1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.mediav2.common.cts;
18 
19 import static android.media.MediaCodecInfo.CodecProfileLevel.*;
20 import static android.media.MediaFormat.PICTURE_TYPE_B;
21 import static android.media.MediaFormat.PICTURE_TYPE_I;
22 import static android.media.MediaFormat.PICTURE_TYPE_P;
23 import static android.media.MediaFormat.PICTURE_TYPE_UNKNOWN;
24 
25 import android.media.MediaCodec;
26 import android.media.MediaFormat;
27 import android.util.Pair;
28 
29 import org.junit.Assert;
30 
31 import java.nio.ByteBuffer;
32 import java.util.ArrayList;
33 import java.util.HashMap;
34 
35 /**
36  * This class contains utility functions that parse compressed bitstream and returns metadata
37  * necessary for validation. This is by no means a thorough parser that is capable of parsing all
38  * syntax elements of a bitstream. This is designed to handle only the requirements of mediav2
39  * test suite.
40  * <p>
41  * Currently this class hosts utils that can,
42  * <ul>
43  *     <li>Return frame type of the access units of avc, hevc, av1.</li>
44  *     <li>Return profile/level information of avc, hevc, av1, vp9, mpeg4, h263, aac</li>
45  * </ul>
46  */
47 public class BitStreamUtils {
getHashMapVal(HashMap<Integer, Integer> obj, int key)48     public static int getHashMapVal(HashMap<Integer, Integer> obj, int key) {
49         Integer val = obj.get(key);
50         return val == null ? -1 : val;
51     }
52 
53     static class ParsableBitArray {
54         protected final byte[] mData;
55         protected final int mOffset;
56         protected final int mLimit;
57         protected int mCurrByteOffset;
58         protected int mCurrBitOffset;
59 
ParsableBitArray(byte[] data, int offset, int limit)60         ParsableBitArray(byte[] data, int offset, int limit) {
61             mData = data;
62             mOffset = offset;
63             mLimit = limit;
64             mCurrByteOffset = offset;
65             mCurrBitOffset = 0;
66         }
67 
readBit()68         public boolean readBit() {
69             if (mCurrByteOffset >= mLimit) {
70                 throw new ArrayIndexOutOfBoundsException(
71                         String.format("Accessing bytes at offset %d, buffer limit %d",
72                                 mCurrByteOffset, mLimit));
73             }
74             boolean returnValue = (mData[mCurrByteOffset] & (0x80 >> mCurrBitOffset)) != 0;
75             if (++mCurrBitOffset == 8) {
76                 mCurrBitOffset = 0;
77                 mCurrByteOffset++;
78             }
79             return returnValue;
80         }
81 
readBits(int numBits)82         public int readBits(int numBits) {
83             if (numBits > 32) {
84                 throw new IllegalArgumentException("readBits Exception: maximum storage space of "
85                         + "return value of readBits : 32, less than bits to read : " + numBits);
86             }
87             int value = 0;
88             for (int i = 0; i < numBits; i++) {
89                 value <<= 1;
90                 value |= (readBit() ? 1 : 0);
91             }
92             return value;
93         }
94 
readBitsLong(int numBits)95         public long readBitsLong(int numBits) {
96             if (numBits > 64) {
97                 throw new IllegalArgumentException("readBitsLong Exception: maximum storage space "
98                         + "of return value of readBits : 64, less than bits to read : " + numBits);
99             }
100             long value = 0;
101             for (int i = 0; i < numBits; i++) {
102                 value <<= 1;
103                 value |= (readBit() ? 1 : 0);
104             }
105             return value;
106         }
107     }
108 
109     static class NalParsableBitArray extends ParsableBitArray {
NalParsableBitArray(byte[] data, int offset, int limit)110         NalParsableBitArray(byte[] data, int offset, int limit) {
111             super(data, offset, limit);
112         }
113 
114         @Override
readBit()115         public boolean readBit() {
116             // emulation prevention
117             if (mCurrBitOffset == 0 && (mCurrByteOffset - 2 > mOffset)
118                     && mData[mCurrByteOffset] == (byte) 0x03
119                     && mData[mCurrByteOffset - 1] == (byte) 0x00
120                     && mData[mCurrByteOffset - 2] == (byte) 0x00) {
121                 mCurrByteOffset++;
122             }
123             return super.readBit();
124         }
125 
readUEV()126         public int readUEV() {
127             int leadingZeros = 0;
128             while (!readBit()) {
129                 leadingZeros++;
130             }
131             return (1 << leadingZeros) - 1 + (leadingZeros > 0 ? readBits(leadingZeros) : 0);
132         }
133     }
134 
135     static class ObuParsableBitArray extends ParsableBitArray {
ObuParsableBitArray(byte[] data, int offset, int limit)136         ObuParsableBitArray(byte[] data, int offset, int limit) {
137             super(data, offset, limit);
138         }
139 
uvlc()140         public long uvlc() {
141             int leadingZeros = 0;
142             while (true) {
143                 boolean done = readBit();
144                 if (done) {
145                     break;
146                 }
147                 leadingZeros++;
148             }
149             if (leadingZeros >= 32) {
150                 return (1L << 32) - 1;
151             }
152             int value = readBits(leadingZeros);
153             return value + (1L << leadingZeros) - 1;
154         }
155 
leb128()156         public int[] leb128() {
157             int value = 0, bytesRead = 0;
158             for (int count = 0; count < 8; count++) {
159                 int leb128_byte = readBits(8);
160                 value |= (leb128_byte & 0x7f) << (count * 7);
161                 bytesRead++;
162                 if ((leb128_byte & 0x80) == 0) break;
163             }
164             return new int[]{bytesRead, value};
165         }
166     }
167 
168     public abstract static class ParserBase {
169         protected byte[] mData;
170         protected int mOffset;
171         protected int mLimit;
172 
set(byte[] data, int offset, int limit)173         protected void set(byte[] data, int offset, int limit) {
174             mData = data;
175             mOffset = offset;
176             mLimit = limit;
177         }
178 
getFrameType()179         public abstract int getFrameType();
180 
getProfileLevel(boolean isCsd)181         public abstract Pair<Integer, Integer> getProfileLevel(boolean isCsd);
182 
183         // .first = profile, .second = level
plToPair(int profile, int level)184         public Pair<Integer, Integer> plToPair(int profile, int level) {
185             return Pair.create(profile, level);
186         }
187     }
188 
189     static class Mpeg4Parser extends ParserBase {
190         @Override
getFrameType()191         public int getFrameType() {
192             return PICTURE_TYPE_UNKNOWN;
193         }
194 
195         @Override
getProfileLevel(@uppressWarnings"unused") boolean isCsd)196         public Pair<Integer, Integer> getProfileLevel(@SuppressWarnings("unused") boolean isCsd) {
197             ParsableBitArray bitArray = new ParsableBitArray(mData, mOffset, mLimit);
198             Assert.assertEquals(0, bitArray.readBits(8));
199             Assert.assertEquals(0, bitArray.readBits(8));
200             Assert.assertEquals(1, bitArray.readBits(8));
201             Assert.assertEquals(0xb0, bitArray.readBits(8));
202             int profileLevel = bitArray.readBits(8);
203             switch (profileLevel) {
204                 case 0x08: return plToPair(MPEG4ProfileSimple, MPEG4Level0);
205                 case 0x01: return plToPair(MPEG4ProfileSimple, MPEG4Level1);
206                 case 0x02: return plToPair(MPEG4ProfileSimple, MPEG4Level2);
207                 case 0x03: return plToPair(MPEG4ProfileSimple, MPEG4Level3);
208                 case 0xf0: return plToPair(MPEG4ProfileAdvancedSimple, MPEG4Level0);
209                 case 0xf1: return plToPair(MPEG4ProfileAdvancedSimple, MPEG4Level1);
210                 case 0xf2: return plToPair(MPEG4ProfileAdvancedSimple, MPEG4Level2);
211                 case 0xf3: return plToPair(MPEG4ProfileAdvancedSimple, MPEG4Level3);
212                 case 0xf7: return plToPair(MPEG4ProfileAdvancedSimple, MPEG4Level3b);
213                 case 0xf4: return plToPair(MPEG4ProfileAdvancedSimple, MPEG4Level4);
214                 case 0xf5: return plToPair(MPEG4ProfileAdvancedSimple, MPEG4Level5);
215                 default: return null;
216             }
217         }
218     }
219 
220     static class H263Parser extends ParserBase {
221         @Override
getFrameType()222         public int getFrameType() {
223             return PICTURE_TYPE_UNKNOWN;
224         }
225 
226         @Override
getProfileLevel(@uppressWarnings"unused") boolean isCsd)227         public Pair<Integer, Integer> getProfileLevel(@SuppressWarnings("unused") boolean isCsd) {
228             ParsableBitArray bitArray = new ParsableBitArray(mData, mOffset, mLimit);
229             Assert.assertEquals("bad psc", 0x20, bitArray.readBits(22));
230             bitArray.readBits(8); // tr
231             Assert.assertEquals(1, bitArray.readBits(1));
232             Assert.assertEquals(0, bitArray.readBits(1));
233             bitArray.readBits(1);  // split screen
234             bitArray.readBits(1);  // camera indicator
235             bitArray.readBits(1);  // freeze indicator
236             int sourceFormat = bitArray.readBits(3);
237             int picType;
238             int umv = 0, sac = 0, ap = 0, pb = 0;
239             int aic = 0, df = 0, ss = 0, rps = 0, isd = 0, aiv = 0, mq = 0;
240             int rpr = 0, rru = 0;
241             if (sourceFormat == 7) {
242                 int ufep = bitArray.readBits(3);
243                 if (ufep == 1) {
244                     sourceFormat = bitArray.readBits(3);
245                     bitArray.readBits(1); // custom pcf
246                     umv = bitArray.readBits(1);
247                     sac = bitArray.readBits(1);
248                     ap = bitArray.readBits(1);
249                     aic = bitArray.readBits(1);
250                     df = bitArray.readBits(1);
251                     ss = bitArray.readBits(1);
252                     rps = bitArray.readBits(1);
253                     isd = bitArray.readBits(1);
254                     aiv = bitArray.readBits(1);
255                     mq = bitArray.readBits(1);
256                     Assert.assertEquals(1, bitArray.readBits(1));
257                     Assert.assertEquals(0, bitArray.readBits(3));
258                 }
259                 picType = bitArray.readBits(3);
260                 rpr = bitArray.readBits(1);
261                 rru = bitArray.readBits(1);
262                 bitArray.readBits(1);  // rtype
263                 Assert.assertEquals(0, bitArray.readBits(1));  // reserved
264                 Assert.assertEquals(0, bitArray.readBits(1));  // reserved
265                 Assert.assertEquals(1, bitArray.readBits(1));  // start code emulation
266             } else {
267                 picType = bitArray.readBits(1);
268                 umv = bitArray.readBits(1);
269                 sac = bitArray.readBits(1);
270                 ap = bitArray.readBits(1);
271                 pb = bitArray.readBits(1);
272             }
273             int profile = H263ProfileBaseline;
274             if (ap == 1) profile = H263ProfileBackwardCompatible;
275             if (aic == 1 && df == 1 && ss == 1 && mq == 1) profile = H263ProfileISWV2;
276             return plToPair(profile, -1);
277         }
278     }
279 
280     static class AvcParser extends ParserBase {
281         private static final int NO_NAL_UNIT_FOUND = -1;
282         private static final HashMap<Integer, Integer> LEVEL_MAP = new HashMap<>() {
283             {
284                 put(10, AVCLevel1);
285                 put(11, AVCLevel11);
286                 put(12, AVCLevel12);
287                 put(13, AVCLevel13);
288                 put(20, AVCLevel2);
289                 put(21, AVCLevel21);
290                 put(22, AVCLevel22);
291                 put(30, AVCLevel3);
292                 put(31, AVCLevel31);
293                 put(32, AVCLevel32);
294                 put(40, AVCLevel4);
295                 put(41, AVCLevel41);
296                 put(42, AVCLevel42);
297                 put(50, AVCLevel5);
298                 put(51, AVCLevel51);
299                 put(52, AVCLevel52);
300                 put(60, AVCLevel6);
301                 put(61, AVCLevel61);
302                 put(62, AVCLevel62);
303             }
304         };
305 
getNalUnitStartOffset(byte[] dataArray, int start, int limit)306         private int getNalUnitStartOffset(byte[] dataArray, int start, int limit) {
307             for (int pos = start; pos + 3 < limit; pos++) {
308                 if ((pos + 3) < limit && dataArray[pos] == 0 && dataArray[pos + 1] == 0
309                         && dataArray[pos + 2] == 1) {
310                     return pos + 3;
311                 } else if ((pos + 4) < limit && dataArray[pos] == 0 && dataArray[pos + 1] == 0
312                         && dataArray[pos + 2] == 0 && dataArray[pos + 3] == 1) {
313                     return pos + 4;
314                 }
315             }
316             return NO_NAL_UNIT_FOUND;
317         }
318 
getNalUnitType(byte[] dataArray, int nalUnitOffset)319         private static int getNalUnitType(byte[] dataArray, int nalUnitOffset) {
320             return dataArray[nalUnitOffset] & 0x1F;
321         }
322 
323         @Override
getFrameType()324         public int getFrameType() {
325             for (int pos = mOffset; pos < mLimit; ) {
326                 int offset = getNalUnitStartOffset(mData, pos, mLimit);
327                 if (offset == NO_NAL_UNIT_FOUND) return PICTURE_TYPE_UNKNOWN;
328                 int nalUnitType = getNalUnitType(mData, offset);
329                 if (nalUnitType == 1 || nalUnitType == 2 || nalUnitType == 5) {  // coded slice
330                     NalParsableBitArray bitArray = new NalParsableBitArray(mData, offset, mLimit);
331                     Assert.assertEquals(0, bitArray.readBits(1)); // forbidden zero bit
332                     bitArray.readBits(7); // nal_ref_idc + nal_unit_type
333                     bitArray.readUEV(); // first_mb_in_slice
334                     int sliceType = bitArray.readUEV();
335                     if (sliceType % 5 == 0) {
336                         return PICTURE_TYPE_P;
337                     } else if (sliceType % 5 == 1) {
338                         return PICTURE_TYPE_B;
339                     } else if (sliceType % 5 == 2) {
340                         return PICTURE_TYPE_I;
341                     } else {
342                         return PICTURE_TYPE_UNKNOWN;
343                     }
344                 }
345                 pos = offset;
346             }
347             return PICTURE_TYPE_UNKNOWN;
348         }
349 
350         @Override
getProfileLevel(@uppressWarnings"unused") boolean isCsd)351         public Pair<Integer, Integer> getProfileLevel(@SuppressWarnings("unused") boolean isCsd) {
352             for (int pos = mOffset; pos < mLimit; ) {
353                 int offset = getNalUnitStartOffset(mData, pos, mLimit);
354                 if (offset == NO_NAL_UNIT_FOUND) return null;
355                 if (getNalUnitType(mData, offset) == 7) { // seq_parameter_set_rbsp
356                     NalParsableBitArray bitArray = new NalParsableBitArray(mData, offset, mLimit);
357                     Assert.assertEquals(0, bitArray.readBits(1)); // forbidden zero bit
358                     bitArray.readBits(7); // nal_ref_idc + nal_unit_type
359                     int profileIdc = bitArray.readBits(8);
360                     int constraintSet0Flag = bitArray.readBits(1);
361                     int constraintSet1Flag = bitArray.readBits(1);
362                     int constraintSet2Flag = bitArray.readBits(1);
363                     int constraintSet3Flag = bitArray.readBits(1);
364                     int constraintSet4Flag = bitArray.readBits(1);
365                     int constraintSet5Flag = bitArray.readBits(1);
366                     Assert.assertEquals(0, bitArray.readBits(2)); // reserved zero 2 bits
367                     int levelIdc = bitArray.readBits(8);
368 
369                     int profile = -1;
370                     if (constraintSet0Flag == 1 || profileIdc == 66) {
371                         profile = constraintSet1Flag == 1 ? AVCProfileConstrainedBaseline :
372                                 AVCProfileBaseline;
373                     } else if (constraintSet1Flag == 1 || profileIdc == 77) {
374                         profile = AVCProfileMain;
375                     } else if (constraintSet2Flag == 1 || profileIdc == 88) {
376                         profile = AVCProfileExtended;
377                     } else if (profileIdc == 100) {
378                         profile = (constraintSet4Flag == 1 && constraintSet5Flag == 1)
379                                 ? AVCProfileConstrainedHigh : AVCProfileHigh;
380                     } else if (profileIdc == 110) {
381                         profile = AVCProfileHigh10;
382                     } else if (profileIdc == 122) {
383                         profile = AVCProfileHigh422;
384                     } else if (profileIdc == 244) {
385                         profile = AVCProfileHigh444;
386                     }
387 
388                     // In bitstreams conforming to the Baseline, Constrained Baseline, Main, or
389                     // Extended profiles :
390                     // - If level_idc is equal to 11 and constraint_set3_flag is equal to 1, the
391                     // indicated level is level 1b.
392                     // - Otherwise (level_idc is not equal to 11 or constraint_set3_flag is not
393                     // equal to 1), level_idc is equal to a value of ten times the level number
394                     // (of the indicated level) specified in Table A-1.
395                     int level;
396                     if ((levelIdc == 11) && (profile == AVCProfileBaseline
397                             || profile == AVCProfileConstrainedBaseline || profile == AVCProfileMain
398                             || profile == AVCProfileExtended)) {
399                         level = constraintSet3Flag == 1 ? AVCLevel1b : AVCLevel11;
400                     } else if ((levelIdc == 9) && (profile == AVCProfileHigh
401                             || profile == AVCProfileHigh10 || profile == AVCProfileHigh422
402                             || profile == AVCProfileHigh444)) {
403                         // In bitstreams conforming to the High, High 10, High 4:2:2, High 4:4:4
404                         // Predictive, High 10 Intra, High 4:2:2 Intra, High 4:4:4 Intra, or
405                         // CAVLC 4:4:4 Intra profiles,
406                         // - If level_idc is equal to 9, the indicated level is level 1b.
407                         // - Otherwise (level_idc is not equal to 9), level_idc is equal to a
408                         // value of ten times the level number (of the indicated level) specified
409                         // in Table A-1
410                         level = AVCLevel1b;
411                     } else {
412                         level = getHashMapVal(LEVEL_MAP, levelIdc);
413                     }
414                     return plToPair(profile, level);
415                 }
416                 pos = offset;
417             }
418             return null;
419         }
420     }
421 
422     static class HevcParser extends ParserBase {
423         private static final int NO_NAL_UNIT_FOUND = -1;
424         private static final int TRAIL_N = 0;
425         private static final int RASL_R = 9;
426         private static final int BLA_W_LP = 16;
427         private static final int RSV_IRAP_VCL23 = 23;
428         private static final HashMap<Integer, Integer> LEVEL_MAP_MAIN_TIER = new HashMap<>() {
429             {
430                 put(30, HEVCMainTierLevel1);
431                 put(60, HEVCMainTierLevel2);
432                 put(63, HEVCMainTierLevel21);
433                 put(90, HEVCMainTierLevel3);
434                 put(93, HEVCMainTierLevel31);
435                 put(120, HEVCMainTierLevel4);
436                 put(123, HEVCMainTierLevel41);
437                 put(150, HEVCMainTierLevel5);
438                 put(153, HEVCMainTierLevel51);
439                 put(156, HEVCMainTierLevel52);
440                 put(180, HEVCMainTierLevel6);
441                 put(183, HEVCMainTierLevel61);
442                 put(186, HEVCMainTierLevel62);
443             }
444         };
445         private static final HashMap<Integer, Integer> LEVEL_MAP_HIGH_TIER = new HashMap<>() {
446             {
447                 put(120, HEVCHighTierLevel4);
448                 put(123, HEVCHighTierLevel41);
449                 put(150, HEVCHighTierLevel5);
450                 put(153, HEVCHighTierLevel51);
451                 put(156, HEVCHighTierLevel52);
452                 put(180, HEVCHighTierLevel6);
453                 put(183, HEVCHighTierLevel61);
454                 put(186, HEVCHighTierLevel62);
455             }
456         };
457 
getNalUnitStartOffset(byte[] dataArray, int start, int limit)458         private int getNalUnitStartOffset(byte[] dataArray, int start, int limit) {
459             for (int pos = start; pos + 3 < limit; pos++) {
460                 if ((pos + 3) < limit && dataArray[pos] == 0 && dataArray[pos + 1] == 0
461                         && dataArray[pos + 2] == 1) {
462                     return pos + 3;
463                 } else if ((pos + 4) < limit && dataArray[pos] == 0 && dataArray[pos + 1] == 0
464                         && dataArray[pos + 2] == 0 && dataArray[pos + 3] == 1) {
465                     return pos + 4;
466                 }
467             }
468             return NO_NAL_UNIT_FOUND;
469         }
470 
getNalUnitType(byte[] dataArray, int nalUnitOffset)471         private static int getNalUnitType(byte[] dataArray, int nalUnitOffset) {
472             return (dataArray[nalUnitOffset] & 0x7E) >> 1;
473         }
474 
475         @Override
getFrameType()476         public int getFrameType() {
477             for (int pos = mOffset; pos < mLimit; ) {
478                 int offset = getNalUnitStartOffset(mData, pos, mLimit);
479                 if (offset == NO_NAL_UNIT_FOUND) return PICTURE_TYPE_UNKNOWN;
480                 int nalUnitType = getNalUnitType(mData, offset);
481                 if ((nalUnitType >= TRAIL_N && nalUnitType <= RASL_R) || (nalUnitType >= BLA_W_LP
482                         && nalUnitType <= RSV_IRAP_VCL23)) { // codec slice
483                     NalParsableBitArray bitArray = new NalParsableBitArray(mData, offset, mLimit);
484                     bitArray.readBits(16); // nal_unit_header
485 
486                     // Parsing slice_segment_header values from H.265/HEVC Table 7.3.6.1
487                     boolean firstSliceSegmentInPicFlag = bitArray.readBit();
488                     if (!firstSliceSegmentInPicFlag) return PICTURE_TYPE_UNKNOWN;
489                     if (nalUnitType >= BLA_W_LP && nalUnitType <= RSV_IRAP_VCL23) {
490                         bitArray.readBit();  // no_output_of_prior_pics_flag
491                     }
492                     bitArray.readUEV(); // slice_pic_parameter_set_id
493                     // FIXME: Assumes num_extra_slice_header_bits element of PPS data to be 0
494                     int sliceType = bitArray.readUEV();
495                     if (sliceType == 0) {
496                         return PICTURE_TYPE_B;
497                     } else if (sliceType == 1) {
498                         return PICTURE_TYPE_P;
499                     } else if (sliceType == 2) {
500                         return PICTURE_TYPE_I;
501                     } else {
502                         return PICTURE_TYPE_UNKNOWN;
503                     }
504                 }
505                 pos = offset;
506             }
507             return PICTURE_TYPE_UNKNOWN;
508         }
509 
510         @Override
getProfileLevel(@uppressWarnings"unused") boolean isCsd)511         public Pair<Integer, Integer> getProfileLevel(@SuppressWarnings("unused") boolean isCsd) {
512             for (int pos = mOffset; pos < mLimit; ) {
513                 int offset = getNalUnitStartOffset(mData, pos, mLimit);
514                 if (offset == NO_NAL_UNIT_FOUND) return null;
515                 if (getNalUnitType(mData, offset) == 33) { // sps_nut
516                     NalParsableBitArray bitArray = new NalParsableBitArray(mData, offset, mLimit);
517                     bitArray.readBits(16); // nal unit header
518                     bitArray.readBits(4); // sps video parameter set id
519                     bitArray.readBits(3); // sps_max_sub_layers_minus1
520                     bitArray.readBits(1); // sps temporal id nesting flag
521                     // profile_tier_level
522                     bitArray.readBits(2); // generalProfileSpace
523                     int generalTierFlag = bitArray.readBits(1);
524                     int generalProfileIdc = bitArray.readBits(5);
525                     int[] generalProfileCompatibility = new int[32];
526                     for (int j = 0; j < generalProfileCompatibility.length; j++) {
527                         generalProfileCompatibility[j] = bitArray.readBits(1);
528                     }
529                     bitArray.readBits(1); // general progressive source flag
530                     bitArray.readBits(1); // general interlaced source flag
531                     bitArray.readBits(1); // general non packed constraint flag
532                     bitArray.readBits(1); // general frame only constraint flag
533 
534                     // interpretation of next 44 bits is dependent on generalProfileIdc and
535                     // generalProfileCompatibility; but we do not use them in this validation
536                     // process, so we're skipping over them.
537                     bitArray.readBitsLong(44);
538                     int generalLevelIdc = bitArray.readBits(8);
539 
540                     int profile = -1;
541                     if (generalProfileIdc == 1 || generalProfileCompatibility[1] == 1) {
542                         profile = HEVCProfileMain;
543                     } else if (generalProfileIdc == 2 || generalProfileCompatibility[2] == 1) {
544                         profile = HEVCProfileMain10;
545                     } else if (generalProfileIdc == 3 || generalProfileCompatibility[3] == 1) {
546                         profile = HEVCProfileMainStill;
547                     }
548 
549                     return plToPair(profile, getHashMapVal(
550                             generalTierFlag == 0 ? LEVEL_MAP_MAIN_TIER : LEVEL_MAP_HIGH_TIER,
551                             generalLevelIdc));
552                 }
553                 pos = offset;
554             }
555             return null;
556         }
557     }
558 
559     static class Vp9Parser extends ParserBase {
560         private static final HashMap<Integer, Integer> PROFILE_MAP = new HashMap<>() {
561             {
562                 put(0, VP9Profile0);
563                 put(1, VP9Profile1);
564                 put(2, VP9Profile2);
565                 put(3, VP9Profile3);
566             }
567         };
568         private static final HashMap<Integer, Integer> LEVEL_MAP = new HashMap<>() {
569             {
570                 put(10, VP9Level1);
571                 put(11, VP9Level11);
572                 put(20, VP9Level2);
573                 put(21, VP9Level21);
574                 put(30, VP9Level3);
575                 put(31, VP9Level31);
576                 put(40, VP9Level4);
577                 put(41, VP9Level41);
578                 put(50, VP9Level5);
579                 put(51, VP9Level51);
580                 put(60, VP9Level6);
581                 put(61, VP9Level61);
582                 put(62, VP9Level62);
583             }
584         };
585 
getProfileLevelFromCSD()586         private Pair<Integer, Integer> getProfileLevelFromCSD() { // parse vp9 codecprivate
587             int profile = -1, level = -1;
588             for (int pos = mOffset; pos < mLimit; ) {
589                 ParsableBitArray bitArray = new ParsableBitArray(mData, pos + mOffset, mLimit);
590                 int id = bitArray.readBits(8);
591                 int len = bitArray.readBits(8);
592                 pos += 2;
593                 int val = bitArray.readBits(len * 8);
594                 pos += len;
595                 if (id == 1 || id == 2) {
596                     Assert.assertEquals(1, len);
597                     if (id == 1) profile = val;
598                     else level = val;
599                 }
600                 if (profile != -1 && level != -1) break;
601             }
602             return plToPair(getHashMapVal(PROFILE_MAP, profile), getHashMapVal(LEVEL_MAP, level));
603         }
604 
getProfileFromFrameHeader()605         private Pair<Integer, Integer> getProfileFromFrameHeader() { // parse uncompressed header
606             ParsableBitArray bitArray = new ParsableBitArray(mData, mOffset, mLimit);
607             bitArray.readBits(2); // frame marker
608             int profileLBit = bitArray.readBits(1);
609             int profileHBit = bitArray.readBits(1);
610             int profile = profileHBit << 1 + profileLBit;
611             return plToPair(getHashMapVal(PROFILE_MAP, profile), -1);
612         }
613 
614         @Override
getFrameType()615         public int getFrameType() {
616             return PICTURE_TYPE_UNKNOWN;
617         }
618 
619         @Override
getProfileLevel(boolean isCsd)620         public Pair<Integer, Integer> getProfileLevel(boolean isCsd) {
621             return isCsd ? getProfileLevelFromCSD() : getProfileFromFrameHeader();
622         }
623     }
624 
625     static class Av1Parser extends ParserBase {
626         private static final int OBU_SEQUENCE_HEADER = 1;
627         private static final int OBU_FRAME_HEADER = 3;
628         private static final int OBU_FRAME = 6;
629         private static final int OBP_KEY_FRAME = 0;
630         private static final int OBP_INTER_FRAME = 1;
631         private static final int OBP_INTRA_ONLY_FRAME = 2;
632         private static final int OBP_SWITCH_FRAME = 3;
633         private static final int NUM_REF_FRAMES = 8;
634 
635         static class ObuInfo {
636             private int mObuType;
637             private int mTemporalId;
638             private int mSpatialId;
639             private int mHeaderSize;
640             private int mSizeFieldSize;
641             private int mDataSize;
642 
getTotalObuSize()643             int getTotalObuSize() {
644                 return mHeaderSize + mSizeFieldSize + mDataSize;
645             }
646 
getObuDataOffset()647             int getObuDataOffset() {
648                 return mHeaderSize + mSizeFieldSize;
649             }
650         }
651 
652         static class SeqHeaderObu {
653             public int seqProfile;
654             public int reducedStillPictureHeader;
655             public final int[] seqLevelIdx = new int[32];
656             public int timingInfoPresentFlag;
657             public int equalPictureInterval;
658             public int decoderModelInfoPresentFlag;
659             public int bufferDelayLengthMinus1;
660             public int bufferRemovalTimeLengthMinus1;
661             public int framePresentationTimeLengthMinus1;
662             public int initialDisplayDelayPresentFlag;
663             public int operatingPointsCntMinus1;
664             public final int[] operatingPointIdc = new int[32];
665             public final int[] seqTier = new int[32];
666             public final int[] decoderModelPresentForThisOp = new int[32];
667             public int frameIdNumbersPresentFlag;
668             public int deltaFrameIdLengthMinus2;
669             public int additionalFrameIdLengthMinus1;
670             public int seqForceScreenContentTools;
671             public int seqForceIntegerMv;
672             public int orderHintBits;
673             public int enableHighBitDepth;
674         }
675 
676         static class FrameHeaderObu {
677             public int frameType;
678             public int showFrame;
679             public int showExistingFrame;
680             public int errorResilientMode;
681         }
682 
683         private final SeqHeaderObu mSeqHeader = new SeqHeaderObu();
684         private final int[] mRefFrameType = new int[NUM_REF_FRAMES];
685 
686         // obu header size, obu size field, obu size
parseObuHeader(byte[] dataArray, int pos, int limit)687         private ObuInfo parseObuHeader(byte[] dataArray, int pos, int limit) {
688             int obuHeaderSize = 1;
689             ObuInfo obuDetails = new ObuInfo();
690             ObuParsableBitArray bitArray = new ObuParsableBitArray(dataArray, pos, limit);
691             bitArray.readBits(1);  // forbidden bit
692             obuDetails.mObuType = bitArray.readBits(4); // obu type
693             int extensionFlag = bitArray.readBits(1);
694             int hasSizeField = bitArray.readBits(1);
695             Assert.assertEquals(1, hasSizeField);
696             bitArray.readBits(1); // reserved 1bit
697             if (extensionFlag == 1) {
698                 obuDetails.mTemporalId = bitArray.readBits(3);
699                 obuDetails.mSpatialId = bitArray.readBits(2);
700                 bitArray.readBits(3);
701                 obuHeaderSize++;
702             }
703             int[] obuSizeInfo = bitArray.leb128();
704             obuDetails.mHeaderSize = obuHeaderSize;
705             obuDetails.mSizeFieldSize = obuSizeInfo[0];
706             obuDetails.mDataSize = obuSizeInfo[1];
707             return obuDetails;
708         }
709 
parseSequenceHeader(ObuParsableBitArray bitArray)710         private void parseSequenceHeader(ObuParsableBitArray bitArray) {
711             mSeqHeader.seqProfile = bitArray.readBits(3);
712             bitArray.readBits(1); // still picture
713             mSeqHeader.reducedStillPictureHeader = bitArray.readBits(1);
714             if (mSeqHeader.reducedStillPictureHeader == 1) {
715                 mSeqHeader.seqLevelIdx[0] = bitArray.readBits(5);
716             } else {
717                 mSeqHeader.timingInfoPresentFlag = bitArray.readBits(1);
718                 if (mSeqHeader.timingInfoPresentFlag == 1) {
719                     bitArray.readBitsLong(32); // num_units_in_display_tick
720                     bitArray.readBitsLong(32); // time_scale
721                     mSeqHeader.equalPictureInterval = bitArray.readBits(1);
722                     if (mSeqHeader.equalPictureInterval == 1) {
723                         bitArray.uvlc(); // num_ticks_per_picture_minus_1
724                     }
725                     mSeqHeader.decoderModelInfoPresentFlag = bitArray.readBits(1);
726                     if (mSeqHeader.decoderModelInfoPresentFlag == 1) {
727                         mSeqHeader.bufferDelayLengthMinus1 = bitArray.readBits(5);
728                         bitArray.readBitsLong(32); // num_units_in_decoding_tick
729                         mSeqHeader.bufferRemovalTimeLengthMinus1 = bitArray.readBits(5);
730                         mSeqHeader.framePresentationTimeLengthMinus1 = bitArray.readBits(5);
731                     }
732                 } else {
733                     mSeqHeader.decoderModelInfoPresentFlag = 0;
734                 }
735                 mSeqHeader.initialDisplayDelayPresentFlag = bitArray.readBits(1);
736                 mSeqHeader.operatingPointsCntMinus1 = bitArray.readBits(5);
737                 for (int i = 0; i <= mSeqHeader.operatingPointsCntMinus1; i++) {
738                     mSeqHeader.operatingPointIdc[i] = bitArray.readBits(12);
739                     mSeqHeader.seqLevelIdx[i] = bitArray.readBits(5);
740                     if (mSeqHeader.seqLevelIdx[i] > 7) {
741                         mSeqHeader.seqTier[i] = bitArray.readBits(1);
742                     }
743                     if (mSeqHeader.decoderModelInfoPresentFlag == 1) {
744                         mSeqHeader.decoderModelPresentForThisOp[i] = bitArray.readBits(1);
745                         if (mSeqHeader.decoderModelPresentForThisOp[i] == 1) {
746                             int n = mSeqHeader.bufferDelayLengthMinus1 + 1;
747                             bitArray.readBits(n); // decoder_buffer_delay
748                             bitArray.readBits(n); // encoder_buffer_delay
749                             bitArray.readBits(1); // low_delay_mode_flag
750                         }
751                     } else {
752                         mSeqHeader.decoderModelPresentForThisOp[i] = 0;
753                     }
754                     if (mSeqHeader.initialDisplayDelayPresentFlag == 1) {
755                         if (bitArray.readBits(1) == 1) {
756                             bitArray.readBits(4); // initial_display_delay_minus_1
757                         }
758                     }
759                 }
760             }
761             int frameWidthBitsMinus1 = bitArray.readBits(4);
762             int frameHeightBitsMinus1 = bitArray.readBits(4);
763             bitArray.readBits(frameWidthBitsMinus1 + 1); // max_frame_width_minus_1
764             bitArray.readBits(frameHeightBitsMinus1 + 1); // max_frame_height_minus_1
765             if (mSeqHeader.reducedStillPictureHeader == 1) {
766                 mSeqHeader.frameIdNumbersPresentFlag = 0;
767             } else {
768                 mSeqHeader.frameIdNumbersPresentFlag = bitArray.readBits(1);
769             }
770             if (mSeqHeader.frameIdNumbersPresentFlag == 1) {
771                 mSeqHeader.deltaFrameIdLengthMinus2 = bitArray.readBits(4);
772                 mSeqHeader.additionalFrameIdLengthMinus1 = bitArray.readBits(3);
773             }
774             bitArray.readBits(1); // use_128x128_superblock
775             bitArray.readBits(1); // enable_filter_intra
776             bitArray.readBits(1); // enable_intra_edge_filter
777             if (mSeqHeader.reducedStillPictureHeader == 1) {
778                 mSeqHeader.seqForceScreenContentTools = 2;
779                 mSeqHeader.seqForceIntegerMv = 2;
780                 mSeqHeader.orderHintBits = 0;
781             } else {
782                 bitArray.readBits(1); // enable_interintra_compound
783                 bitArray.readBits(1); // enable_masked_compound
784                 bitArray.readBits(1); // enable_warped_motion
785                 bitArray.readBits(1); // enable_dual_filter
786                 int enableOrderHint = bitArray.readBits(1);
787                 if (enableOrderHint == 1) {
788                     bitArray.readBits(1); // enable_jnt_comp
789                     bitArray.readBits(1); // enable_ref_frame_mvs
790                 }
791                 int seqChooseScreenContentTools = bitArray.readBits(1);
792                 if (seqChooseScreenContentTools == 1) {
793                     mSeqHeader.seqForceScreenContentTools = 2;
794                 } else {
795                     mSeqHeader.seqForceScreenContentTools = bitArray.readBits(1);
796                 }
797                 if (mSeqHeader.seqForceScreenContentTools > 0) {
798                     int seqChooseIntegerMv = bitArray.readBits(1);
799                     if (seqChooseIntegerMv == 1) {
800                         mSeqHeader.seqForceIntegerMv = 2;
801                     } else {
802                         mSeqHeader.seqForceIntegerMv = bitArray.readBits(1);
803                     }
804                 } else {
805                     mSeqHeader.seqForceIntegerMv = 2;
806                 }
807                 if (enableOrderHint == 1) {
808                     int orderHintBitsMinus1 = bitArray.readBits(3);
809                     mSeqHeader.orderHintBits = orderHintBitsMinus1 + 1;
810                 } else {
811                     mSeqHeader.orderHintBits = 0;
812                 }
813             }
814             bitArray.readBits(1); // enable super res
815             bitArray.readBits(1); // enable cdef
816             bitArray.readBits(1); // enable restoration
817             mSeqHeader.enableHighBitDepth = bitArray.readBits(1);
818         }
819 
parseFrameHeader(ObuParsableBitArray bitArray, int temporalId, int spatialId)820         private FrameHeaderObu parseFrameHeader(ObuParsableBitArray bitArray, int temporalId,
821                 int spatialId) {
822             FrameHeaderObu frameHeader = new FrameHeaderObu();
823             int idLen = 0;
824             if (mSeqHeader.frameIdNumbersPresentFlag == 1) {
825                 idLen = mSeqHeader.additionalFrameIdLengthMinus1
826                         + mSeqHeader.deltaFrameIdLengthMinus2 + 3;
827             }
828             int allFrames = (1 << NUM_REF_FRAMES) - 1;
829             int refreshFrameFlags = 0;
830             int frameIsIntra;
831             if (mSeqHeader.reducedStillPictureHeader == 1) {
832                 frameHeader.frameType = OBP_KEY_FRAME;
833                 frameIsIntra = 1;
834                 frameHeader.showFrame = 1;
835             } else {
836                 frameHeader.showExistingFrame = bitArray.readBits(1);
837                 if (frameHeader.showExistingFrame == 1) {
838                     int frameToShowMapIdx = bitArray.readBits(3);
839                     if (mSeqHeader.decoderModelInfoPresentFlag == 1
840                             && mSeqHeader.equalPictureInterval == 0) {
841                         int n = mSeqHeader.framePresentationTimeLengthMinus1 + 1;
842                         bitArray.readBits(n); // frame_presentation_time
843                     }
844                     if (mSeqHeader.frameIdNumbersPresentFlag == 1) {
845                         bitArray.readBits(idLen); // display_frame_id
846                     }
847                     frameHeader.frameType = mRefFrameType[frameToShowMapIdx];
848                     if (frameHeader.frameType == OBP_KEY_FRAME) {
849                         refreshFrameFlags = allFrames;
850                     }
851                     return frameHeader;
852                 }
853                 frameHeader.frameType = bitArray.readBits(2);
854                 frameIsIntra = (frameHeader.frameType == OBP_INTRA_ONLY_FRAME
855                         || frameHeader.frameType == OBP_KEY_FRAME) ? 1 : 0;
856                 frameHeader.showFrame = bitArray.readBits(1);
857                 if (frameHeader.showFrame == 1 && mSeqHeader.decoderModelInfoPresentFlag == 1
858                         && mSeqHeader.equalPictureInterval == 0) {
859                     int n = mSeqHeader.framePresentationTimeLengthMinus1 + 1;
860                     bitArray.readBits(n); // frame_presentation_time
861                 }
862                 if (frameHeader.showFrame == 0) {
863                     bitArray.readBits(1); // showable_frame
864                 }
865                 if (frameHeader.frameType == OBP_SWITCH_FRAME || (
866                         frameHeader.frameType == OBP_KEY_FRAME && frameHeader.showFrame == 1)) {
867                     frameHeader.errorResilientMode = 1;
868                 } else {
869                     frameHeader.errorResilientMode = bitArray.readBits(1);
870                 }
871             }
872             bitArray.readBits(1); // disable_cdf_update
873             int allowScreenContentTools;
874             if (mSeqHeader.seqForceScreenContentTools == 2) {
875                 allowScreenContentTools = bitArray.readBits(1);
876             } else {
877                 allowScreenContentTools = mSeqHeader.seqForceScreenContentTools;
878             }
879             if (allowScreenContentTools == 1 && mSeqHeader.seqForceIntegerMv == 2) {
880                 bitArray.readBits(1); // force_integer_mv
881             }
882             if (mSeqHeader.frameIdNumbersPresentFlag == 1) {
883                 bitArray.readBits(idLen); // current_frame_id
884             }
885             if (frameHeader.frameType != OBP_SWITCH_FRAME
886                     && mSeqHeader.reducedStillPictureHeader == 0) {
887                 bitArray.readBits(1); // frame_size_override_flag
888             }
889             bitArray.readBits(mSeqHeader.orderHintBits); // order_hint
890             if (frameIsIntra != 1 && frameHeader.errorResilientMode == 0) {
891                 bitArray.readBits(3); // primary_ref_frame
892             }
893 
894             if (mSeqHeader.decoderModelInfoPresentFlag == 1) {
895                 int bufferRemovalTimePresentFlag = bitArray.readBits(1);
896                 if (bufferRemovalTimePresentFlag == 1) {
897                     for (int i = 0; i <= mSeqHeader.operatingPointsCntMinus1; i++) {
898                         if (mSeqHeader.decoderModelPresentForThisOp[i] == 1) {
899                             int opPtIdc = mSeqHeader.operatingPointIdc[i];
900                             boolean inTemporalLayer = ((opPtIdc >> temporalId) & 1) == 1;
901                             boolean inSpatialLayer = ((opPtIdc >> (spatialId + 8)) & 1) == 1;
902                             if (opPtIdc == 0 || (inTemporalLayer && inSpatialLayer)) {
903                                 int n = mSeqHeader.bufferRemovalTimeLengthMinus1 + 1;
904                                 bitArray.readBits(n); // buffer_removal_time
905                             }
906                         }
907                     }
908                 }
909             }
910 
911             if (frameHeader.frameType == OBP_SWITCH_FRAME || (frameHeader.frameType == OBP_KEY_FRAME
912                     && frameHeader.showFrame == 1)) {
913                 refreshFrameFlags = allFrames;
914             } else {
915                 refreshFrameFlags = bitArray.readBits(8);
916             }
917 
918             for (int i = 0; i < 8; i++) {
919                 if ((refreshFrameFlags >> i & 1) == 1) {
920                     mRefFrameType[i] = frameHeader.frameType;
921                 }
922             }
923             return frameHeader;
924         }
925 
926         // parse av1 codec configuration record
getProfileLevelFromCSD()927         private Pair<Integer, Integer> getProfileLevelFromCSD() {
928             int profile = -1;
929             ParsableBitArray bitArray = new ParsableBitArray(mData, mOffset, mLimit);
930             Assert.assertEquals(1, bitArray.readBits(1));  // marker
931             Assert.assertEquals(1, bitArray.readBits(7));  // version
932             int seqProfile = bitArray.readBits(3);
933             int seqLevelIdx0 = bitArray.readBits(5);
934             bitArray.readBits(1);  // seqTier0
935             int highBitDepth = bitArray.readBits(1);
936             bitArray.readBits(1);  // is input 12 bit;
937             if (seqProfile == 0) {
938                 profile = highBitDepth == 0 ? AV1ProfileMain8 : AV1ProfileMain10;
939             }
940 
941             int level = AV1Level2 << seqLevelIdx0;
942             return plToPair(profile, level);
943         }
944 
945         // parse av1 sequence header
getProfileLevelFromSeqHeader()946         private Pair<Integer, Integer> getProfileLevelFromSeqHeader() {
947             for (int pos = mOffset; pos < mLimit; ) {
948                 ObuInfo obuDetails = parseObuHeader(mData, pos, mLimit);
949                 ObuParsableBitArray bitArray =
950                         new ObuParsableBitArray(mData, pos + obuDetails.getObuDataOffset(),
951                                 pos + obuDetails.getTotalObuSize());
952                 if (obuDetails.mObuType == OBU_SEQUENCE_HEADER) {
953                     int profile = -1;
954                     parseSequenceHeader(bitArray);
955                     if (mSeqHeader.seqProfile == 0) {
956                         profile = mSeqHeader.enableHighBitDepth == 0 ? AV1ProfileMain8 :
957                                 AV1ProfileMain10;
958                     }
959 
960                     int level = AV1Level2 << mSeqHeader.seqLevelIdx[0];
961                     return plToPair(profile, level);
962                 }
963                 pos += obuDetails.getTotalObuSize();
964             }
965             return null;
966         }
967 
968         @Override
getFrameType()969         public int getFrameType() {
970             ArrayList<FrameHeaderObu> headers = new ArrayList<>();
971             for (int pos = mOffset; pos < mLimit; ) {
972                 ObuInfo obuDetails = parseObuHeader(mData, pos, mLimit);
973                 ObuParsableBitArray bitArray =
974                         new ObuParsableBitArray(mData, pos + obuDetails.getObuDataOffset(),
975                                 pos + obuDetails.getTotalObuSize());
976                 if (obuDetails.mObuType == OBU_SEQUENCE_HEADER) {
977                     parseSequenceHeader(bitArray);
978                 } else if (obuDetails.mObuType == OBU_FRAME_HEADER
979                         || obuDetails.mObuType == OBU_FRAME) {
980                     FrameHeaderObu frameHeader = parseFrameHeader(bitArray, obuDetails.mTemporalId,
981                             obuDetails.mSpatialId);
982                     headers.add(frameHeader);
983                 }
984                 pos += obuDetails.getTotalObuSize();
985             }
986             for (FrameHeaderObu frameHeader : headers) {
987                 if (frameHeader.showFrame == 1 || frameHeader.showExistingFrame == 1) {
988                     if (frameHeader.frameType == OBP_KEY_FRAME
989                             || frameHeader.frameType == OBP_INTRA_ONLY_FRAME) {
990                         return PICTURE_TYPE_I;
991                     } else if (frameHeader.frameType == OBP_INTER_FRAME) {
992                         return PICTURE_TYPE_P;
993                     }
994                     return PICTURE_TYPE_UNKNOWN;
995                 }
996             }
997             return PICTURE_TYPE_UNKNOWN;
998         }
999 
1000         @Override
getProfileLevel(boolean isCsd)1001         public Pair<Integer, Integer> getProfileLevel(boolean isCsd) {
1002             return isCsd ? getProfileLevelFromCSD() : getProfileLevelFromSeqHeader();
1003         }
1004     }
1005 
1006     static class AacParser extends ParserBase {
1007         @Override
getFrameType()1008         public int getFrameType() {
1009             return PICTURE_TYPE_UNKNOWN;
1010         }
1011 
1012         @Override
getProfileLevel(@uppressWarnings"unused") boolean isCsd)1013         public Pair<Integer, Integer> getProfileLevel(@SuppressWarnings("unused") boolean isCsd) {
1014             // parse AudioSpecificConfig() of ISO 14496 Part 3
1015             ParsableBitArray bitArray = new ParsableBitArray(mData, mOffset, mLimit);
1016             int audioObjectType = bitArray.readBits(5);
1017             if (audioObjectType == 31) {
1018                 audioObjectType = 32 + bitArray.readBits(6); // audio object type ext
1019             }
1020             return plToPair(audioObjectType, -1);
1021         }
1022     }
1023 
getParserObject(String mediaType)1024     public static ParserBase getParserObject(String mediaType) {
1025         switch (mediaType) {
1026             case MediaFormat.MIMETYPE_VIDEO_MPEG4:
1027                 return new Mpeg4Parser();
1028             case MediaFormat.MIMETYPE_VIDEO_H263:
1029                 return new H263Parser();
1030             case MediaFormat.MIMETYPE_VIDEO_AVC:
1031                 return new AvcParser();
1032             case MediaFormat.MIMETYPE_VIDEO_HEVC:
1033                 return new HevcParser();
1034             case MediaFormat.MIMETYPE_VIDEO_AV1:
1035                 return new Av1Parser();
1036             case MediaFormat.MIMETYPE_VIDEO_VP9:
1037                 return new Vp9Parser();
1038             case MediaFormat.MIMETYPE_AUDIO_AAC:
1039                 return new AacParser();
1040         }
1041         return null;
1042     }
1043 
getFrameTypeFromBitStream(ByteBuffer buf, MediaCodec.BufferInfo info, ParserBase o)1044     public static int getFrameTypeFromBitStream(ByteBuffer buf, MediaCodec.BufferInfo info,
1045             ParserBase o) {
1046         if (o == null) return PICTURE_TYPE_UNKNOWN;
1047         byte[] dataArray = new byte[info.size];
1048         buf.position(info.offset);
1049         buf.get(dataArray);
1050         o.set(dataArray, 0, info.size);
1051         return o.getFrameType();
1052     }
1053 
getProfileLevelFromBitStream(ByteBuffer buf, MediaCodec.BufferInfo info, ParserBase o)1054     public static Pair<Integer, Integer> getProfileLevelFromBitStream(ByteBuffer buf,
1055             MediaCodec.BufferInfo info, ParserBase o) {
1056         if (o == null) return null;
1057         byte[] dataArray = new byte[info.size];
1058         buf.position(info.offset);
1059         buf.get(dataArray);
1060         o.set(dataArray, 0, info.size);
1061         return o.getProfileLevel((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0);
1062     }
1063 }
1064