Java tutorial
//package com.java2s; /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import android.annotation.SuppressLint; import android.media.MediaCodecInfo.CodecProfileLevel; import android.util.Pair; public class Main { private static final byte[] NAL_START_CODE = new byte[] { 0, 0, 0, 1 }; private static final int SPS_NAL_UNIT_TYPE = 7; /** * Parses an SPS NAL unit. * * @param spsNalUnit The NAL unit. * @return A pair consisting of AVC profile and level constants, as defined in * {@link android.media.MediaCodecInfo.CodecProfileLevel}. Null if the input data was not an SPS NAL unit. */ public static Pair<Integer, Integer> parseSpsNalUnit(byte[] spsNalUnit) { // SPS NAL unit: // - Start prefix (4 bytes) // - Forbidden zero bit (1 bit) // - NAL ref idx (2 bits) // - NAL unit type (5 bits) // - Profile idc (8 bits) // - Constraint bits (3 bits) // - Reserved bits (5 bits) // - Level idx (8 bits) if (isNalStartCode(spsNalUnit, 0) && spsNalUnit.length == 8 && (spsNalUnit[5] & 0x1F) == SPS_NAL_UNIT_TYPE) { return Pair.create(parseAvcProfile(spsNalUnit), parseAvcLevel(spsNalUnit)); } return null; } /** * Tests whether there exists a NAL start code at a given index. * * @param data The data. * @param index The index to test. * @return Whether there exists a start code that begins at {@code index}. */ private static boolean isNalStartCode(byte[] data, int index) { if (data.length - index <= NAL_START_CODE.length) { return false; } for (int j = 0; j < NAL_START_CODE.length; j++) { if (data[index + j] != NAL_START_CODE[j]) { return false; } } return true; } @SuppressLint("InlinedApi") private static int parseAvcProfile(byte[] data) { int profileIdc = data[6] & 0xFF; switch (profileIdc) { case 0x42: return CodecProfileLevel.AVCProfileBaseline; case 0x4d: return CodecProfileLevel.AVCProfileMain; case 0x58: return CodecProfileLevel.AVCProfileExtended; case 0x64: return CodecProfileLevel.AVCProfileHigh; case 0x6e: return CodecProfileLevel.AVCProfileHigh10; case 0x7a: return CodecProfileLevel.AVCProfileHigh422; case 0xf4: return CodecProfileLevel.AVCProfileHigh444; default: return 0; } } @SuppressLint("InlinedApi") private static int parseAvcLevel(byte[] data) { int levelIdc = data[8] & 0xFF; switch (levelIdc) { case 9: return CodecProfileLevel.AVCLevel1b; case 10: return CodecProfileLevel.AVCLevel1; case 11: return CodecProfileLevel.AVCLevel11; case 12: return CodecProfileLevel.AVCLevel12; case 13: return CodecProfileLevel.AVCLevel13; case 20: return CodecProfileLevel.AVCLevel2; case 21: return CodecProfileLevel.AVCLevel21; case 22: return CodecProfileLevel.AVCLevel22; case 30: return CodecProfileLevel.AVCLevel3; case 31: return CodecProfileLevel.AVCLevel31; case 32: return CodecProfileLevel.AVCLevel32; case 40: return CodecProfileLevel.AVCLevel4; case 41: return CodecProfileLevel.AVCLevel41; case 42: return CodecProfileLevel.AVCLevel42; case 50: return CodecProfileLevel.AVCLevel5; case 51: return CodecProfileLevel.AVCLevel51; default: return 0; } } }