• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.annotation.TargetApi;
26 import android.media.MediaCodec;
27 import android.media.MediaFormat;
28 import android.os.Build;
29 import android.util.Pair;
30 
31 import org.junit.Assert;
32 
33 import java.nio.ByteBuffer;
34 import java.util.ArrayList;
35 import java.util.Map;
36 
37 /**
38  * This class contains utility functions that parse compressed bitstream and returns metadata
39  * necessary for validation. This is by no means a thorough parser that is capable of parsing all
40  * syntax elements of a bitstream. This is designed to handle only the requirements of mediav2
41  * test suite.
42  * <p>
43  * Currently this class hosts utils that can,
44  * <ul>
45  *     <li>Return frame type of the access units of avc, hevc, av1.</li>
46  *     <li>Return profile/level information of avc, hevc, av1, vp9, mpeg4, h263, aac</li>
47  * </ul>
48  */
49 public class BitStreamUtils {
getHashMapVal(Map<Integer, Integer> obj, int key)50     private static int getHashMapVal(Map<Integer, Integer> obj, int key) {
51         Integer val = obj.get(key);
52         return val == null ? -1 : val;
53     }
54 
55     static class ParsableBitArray {
56         protected final byte[] mData;
57         protected final int mOffset;
58         protected final int mLimit;
59         protected int mCurrByteOffset;
60         protected int mCurrBitOffset;
61 
ParsableBitArray(byte[] data, int offset, int limit)62         ParsableBitArray(byte[] data, int offset, int limit) {
63             mData = data;
64             mOffset = offset;
65             mLimit = limit;
66             mCurrByteOffset = offset;
67             mCurrBitOffset = 0;
68         }
69 
readBit()70         public boolean readBit() {
71             if (mCurrByteOffset >= mLimit) {
72                 throw new ArrayIndexOutOfBoundsException(
73                         String.format("Accessing bytes at offset %d, buffer limit %d",
74                                 mCurrByteOffset, mLimit));
75             }
76             boolean returnValue = (mData[mCurrByteOffset] & (0x80 >> mCurrBitOffset)) != 0;
77             if (++mCurrBitOffset == 8) {
78                 mCurrBitOffset = 0;
79                 mCurrByteOffset++;
80             }
81             return returnValue;
82         }
83 
readBits(int numBits)84         public int readBits(int numBits) {
85             if (numBits > 32) {
86                 throw new IllegalArgumentException("readBits Exception: maximum storage space of "
87                         + "return value of readBits : 32, less than bits to read : " + numBits);
88             }
89             int value = 0;
90             for (int i = 0; i < numBits; i++) {
91                 value <<= 1;
92                 value |= (readBit() ? 1 : 0);
93             }
94             return value;
95         }
96 
readBitsLong(int numBits)97         public long readBitsLong(int numBits) {
98             if (numBits > 64) {
99                 throw new IllegalArgumentException("readBitsLong Exception: maximum storage space "
100                         + "of return value of readBits : 64, less than bits to read : " + numBits);
101             }
102             long value = 0;
103             for (int i = 0; i < numBits; i++) {
104                 value <<= 1;
105                 value |= (readBit() ? 1 : 0);
106             }
107             return value;
108         }
109     }
110 
111     static class NalParsableBitArray extends ParsableBitArray {
NalParsableBitArray(byte[] data, int offset, int limit)112         NalParsableBitArray(byte[] data, int offset, int limit) {
113             super(data, offset, limit);
114         }
115 
116         @Override
readBit()117         public boolean readBit() {
118             // emulation prevention
119             if (mCurrBitOffset == 0 && (mCurrByteOffset - 2 > mOffset)
120                     && mData[mCurrByteOffset] == (byte) 0x03
121                     && mData[mCurrByteOffset - 1] == (byte) 0x00
122                     && mData[mCurrByteOffset - 2] == (byte) 0x00) {
123                 mCurrByteOffset++;
124             }
125             return super.readBit();
126         }
127 
readUEV()128         public int readUEV() {
129             int leadingZeros = 0;
130             while (!readBit()) {
131                 leadingZeros++;
132             }
133             return (1 << leadingZeros) - 1 + (leadingZeros > 0 ? readBits(leadingZeros) : 0);
134         }
135     }
136 
137     static class ObuParsableBitArray extends ParsableBitArray {
ObuParsableBitArray(byte[] data, int offset, int limit)138         ObuParsableBitArray(byte[] data, int offset, int limit) {
139             super(data, offset, limit);
140         }
141 
uvlc()142         public long uvlc() {
143             int leadingZeros = 0;
144             while (true) {
145                 boolean done = readBit();
146                 if (done) {
147                     break;
148                 }
149                 leadingZeros++;
150             }
151             if (leadingZeros >= 32) {
152                 return (1L << 32) - 1;
153             }
154             int value = readBits(leadingZeros);
155             return value + (1L << leadingZeros) - 1;
156         }
157 
leb128()158         public int[] leb128() {
159             int value = 0, bytesRead = 0;
160             for (int count = 0; count < 8; count++) {
161                 int leb128_byte = readBits(8);
162                 value |= (leb128_byte & 0x7f) << (count * 7);
163                 bytesRead++;
164                 if ((leb128_byte & 0x80) == 0) break;
165             }
166             return new int[]{bytesRead, value};
167         }
168     }
169 
170     public abstract static class ParserBase {
171         protected byte[] mData;
172         protected int mOffset;
173         protected int mLimit;
174 
set(byte[] data, int offset, int limit)175         protected void set(byte[] data, int offset, int limit) {
176             mData = data;
177             mOffset = offset;
178             mLimit = limit;
179         }
180 
getFrameType()181         public abstract int getFrameType();
182 
getProfileLevel(boolean isCsd)183         public abstract Pair<Integer, Integer> getProfileLevel(boolean isCsd);
184 
185         // .first = profile, .second = level
plToPair(int profile, int level)186         public Pair<Integer, Integer> plToPair(int profile, int level) {
187             return Pair.create(profile, level);
188         }
189     }
190 
191     static class Mpeg4Parser extends ParserBase {
192         @Override
getFrameType()193         public int getFrameType() {
194             return PICTURE_TYPE_UNKNOWN;
195         }
196 
197         @Override
getProfileLevel(@uppressWarnings"unused") boolean isCsd)198         public Pair<Integer, Integer> getProfileLevel(@SuppressWarnings("unused") boolean isCsd) {
199             ParsableBitArray bitArray = new ParsableBitArray(mData, mOffset, mLimit);
200             Assert.assertEquals(0, bitArray.readBits(8));
201             Assert.assertEquals(0, bitArray.readBits(8));
202             Assert.assertEquals(1, bitArray.readBits(8));
203             Assert.assertEquals(0xb0, bitArray.readBits(8));
204             int profileLevel = bitArray.readBits(8);
205             switch (profileLevel) {
206                 case 0x08: return plToPair(MPEG4ProfileSimple, MPEG4Level0);
207                 case 0x01: return plToPair(MPEG4ProfileSimple, MPEG4Level1);
208                 case 0x02: return plToPair(MPEG4ProfileSimple, MPEG4Level2);
209                 case 0x03: return plToPair(MPEG4ProfileSimple, MPEG4Level3);
210                 case 0xf0: return plToPair(MPEG4ProfileAdvancedSimple, MPEG4Level0);
211                 case 0xf1: return plToPair(MPEG4ProfileAdvancedSimple, MPEG4Level1);
212                 case 0xf2: return plToPair(MPEG4ProfileAdvancedSimple, MPEG4Level2);
213                 case 0xf3: return plToPair(MPEG4ProfileAdvancedSimple, MPEG4Level3);
214                 case 0xf7: return plToPair(MPEG4ProfileAdvancedSimple, MPEG4Level3b);
215                 case 0xf4: return plToPair(MPEG4ProfileAdvancedSimple, MPEG4Level4);
216                 case 0xf5: return plToPair(MPEG4ProfileAdvancedSimple, MPEG4Level5);
217                 default: return null;
218             }
219         }
220     }
221 
222     static class H263Parser extends ParserBase {
223         @Override
getFrameType()224         public int getFrameType() {
225             return PICTURE_TYPE_UNKNOWN;
226         }
227 
228         @Override
getProfileLevel(@uppressWarnings"unused") boolean isCsd)229         public Pair<Integer, Integer> getProfileLevel(@SuppressWarnings("unused") boolean isCsd) {
230             ParsableBitArray bitArray = new ParsableBitArray(mData, mOffset, mLimit);
231             Assert.assertEquals("bad psc", 0x20, bitArray.readBits(22));
232             bitArray.readBits(8); // tr
233             Assert.assertEquals(1, bitArray.readBits(1));
234             Assert.assertEquals(0, bitArray.readBits(1));
235             bitArray.readBits(1);  // split screen
236             bitArray.readBits(1);  // camera indicator
237             bitArray.readBits(1);  // freeze indicator
238             int sourceFormat = bitArray.readBits(3);
239             int picType;
240             int umv = 0, sac = 0, ap = 0, pb = 0;
241             int aic = 0, df = 0, ss = 0, rps = 0, isd = 0, aiv = 0, mq = 0;
242             int rpr = 0, rru = 0;
243             if (sourceFormat == 7) {
244                 int ufep = bitArray.readBits(3);
245                 if (ufep == 1) {
246                     sourceFormat = bitArray.readBits(3);
247                     bitArray.readBits(1); // custom pcf
248                     umv = bitArray.readBits(1);
249                     sac = bitArray.readBits(1);
250                     ap = bitArray.readBits(1);
251                     aic = bitArray.readBits(1);
252                     df = bitArray.readBits(1);
253                     ss = bitArray.readBits(1);
254                     rps = bitArray.readBits(1);
255                     isd = bitArray.readBits(1);
256                     aiv = bitArray.readBits(1);
257                     mq = bitArray.readBits(1);
258                     Assert.assertEquals(1, bitArray.readBits(1));
259                     Assert.assertEquals(0, bitArray.readBits(3));
260                 }
261                 picType = bitArray.readBits(3);
262                 rpr = bitArray.readBits(1);
263                 rru = bitArray.readBits(1);
264                 bitArray.readBits(1);  // rtype
265                 Assert.assertEquals(0, bitArray.readBits(1));  // reserved
266                 Assert.assertEquals(0, bitArray.readBits(1));  // reserved
267                 Assert.assertEquals(1, bitArray.readBits(1));  // start code emulation
268             } else {
269                 picType = bitArray.readBits(1);
270                 umv = bitArray.readBits(1);
271                 sac = bitArray.readBits(1);
272                 ap = bitArray.readBits(1);
273                 pb = bitArray.readBits(1);
274             }
275             int profile = H263ProfileBaseline;
276             if (ap == 1) profile = H263ProfileBackwardCompatible;
277             if (aic == 1 && df == 1 && ss == 1 && mq == 1) profile = H263ProfileISWV2;
278             return plToPair(profile, -1);
279         }
280     }
281 
282     static class AvcParser extends ParserBase {
283         private static final int NO_NAL_UNIT_FOUND = -1;
284         private static final Map<Integer, Integer> LEVEL_MAP = Map.ofEntries(
285                 Map.entry(10, AVCLevel1),
286                 Map.entry(11, AVCLevel11),
287                 Map.entry(12, AVCLevel12),
288                 Map.entry(13, AVCLevel13),
289                 Map.entry(20, AVCLevel2),
290                 Map.entry(21, AVCLevel21),
291                 Map.entry(22, AVCLevel22),
292                 Map.entry(30, AVCLevel3),
293                 Map.entry(31, AVCLevel31),
294                 Map.entry(32, AVCLevel32),
295                 Map.entry(40, AVCLevel4),
296                 Map.entry(41, AVCLevel41),
297                 Map.entry(42, AVCLevel42),
298                 Map.entry(50, AVCLevel5),
299                 Map.entry(51, AVCLevel51),
300                 Map.entry(52, AVCLevel52),
301                 Map.entry(60, AVCLevel6),
302                 Map.entry(61, AVCLevel61),
303                 Map.entry(62, AVCLevel62)
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 Map<Integer, Integer> LEVEL_MAP_MAIN_TIER = Map.ofEntries(
429                 Map.entry(30, HEVCMainTierLevel1),
430                 Map.entry(60, HEVCMainTierLevel2),
431                 Map.entry(63, HEVCMainTierLevel21),
432                 Map.entry(90, HEVCMainTierLevel3),
433                 Map.entry(93, HEVCMainTierLevel31),
434                 Map.entry(120, HEVCMainTierLevel4),
435                 Map.entry(123, HEVCMainTierLevel41),
436                 Map.entry(150, HEVCMainTierLevel5),
437                 Map.entry(153, HEVCMainTierLevel51),
438                 Map.entry(156, HEVCMainTierLevel52),
439                 Map.entry(180, HEVCMainTierLevel6),
440                 Map.entry(183, HEVCMainTierLevel61),
441                 Map.entry(186, HEVCMainTierLevel62)
442         );
443         private static final Map<Integer, Integer> LEVEL_MAP_HIGH_TIER = Map.ofEntries(
444                 Map.entry(120, HEVCHighTierLevel4),
445                 Map.entry(123, HEVCHighTierLevel41),
446                 Map.entry(150, HEVCHighTierLevel5),
447                 Map.entry(153, HEVCHighTierLevel51),
448                 Map.entry(156, HEVCHighTierLevel52),
449                 Map.entry(180, HEVCHighTierLevel6),
450                 Map.entry(183, HEVCHighTierLevel61),
451                 Map.entry(186, HEVCHighTierLevel62)
452         );
453 
getNalUnitStartOffset(byte[] dataArray, int start, int limit)454         private int getNalUnitStartOffset(byte[] dataArray, int start, int limit) {
455             for (int pos = start; pos + 3 < limit; pos++) {
456                 if ((pos + 3) < limit && dataArray[pos] == 0 && dataArray[pos + 1] == 0
457                         && dataArray[pos + 2] == 1) {
458                     return pos + 3;
459                 } else if ((pos + 4) < limit && dataArray[pos] == 0 && dataArray[pos + 1] == 0
460                         && dataArray[pos + 2] == 0 && dataArray[pos + 3] == 1) {
461                     return pos + 4;
462                 }
463             }
464             return NO_NAL_UNIT_FOUND;
465         }
466 
getNalUnitType(byte[] dataArray, int nalUnitOffset)467         private static int getNalUnitType(byte[] dataArray, int nalUnitOffset) {
468             return (dataArray[nalUnitOffset] & 0x7E) >> 1;
469         }
470 
471         @Override
getFrameType()472         public int getFrameType() {
473             for (int pos = mOffset; pos < mLimit; ) {
474                 int offset = getNalUnitStartOffset(mData, pos, mLimit);
475                 if (offset == NO_NAL_UNIT_FOUND) return PICTURE_TYPE_UNKNOWN;
476                 int nalUnitType = getNalUnitType(mData, offset);
477                 if ((nalUnitType >= TRAIL_N && nalUnitType <= RASL_R) || (nalUnitType >= BLA_W_LP
478                         && nalUnitType <= RSV_IRAP_VCL23)) { // codec slice
479                     NalParsableBitArray bitArray = new NalParsableBitArray(mData, offset, mLimit);
480                     bitArray.readBits(16); // nal_unit_header
481 
482                     // Parsing slice_segment_header values from H.265/HEVC Table 7.3.6.1
483                     boolean firstSliceSegmentInPicFlag = bitArray.readBit();
484                     if (!firstSliceSegmentInPicFlag) return PICTURE_TYPE_UNKNOWN;
485                     if (nalUnitType >= BLA_W_LP && nalUnitType <= RSV_IRAP_VCL23) {
486                         bitArray.readBit();  // no_output_of_prior_pics_flag
487                     }
488                     bitArray.readUEV(); // slice_pic_parameter_set_id
489                     // FIXME: Assumes num_extra_slice_header_bits element of PPS data to be 0
490                     int sliceType = bitArray.readUEV();
491                     if (sliceType == 0) {
492                         return PICTURE_TYPE_B;
493                     } else if (sliceType == 1) {
494                         return PICTURE_TYPE_P;
495                     } else if (sliceType == 2) {
496                         return PICTURE_TYPE_I;
497                     } else {
498                         return PICTURE_TYPE_UNKNOWN;
499                     }
500                 }
501                 pos = offset;
502             }
503             return PICTURE_TYPE_UNKNOWN;
504         }
505 
506         @Override
getProfileLevel(@uppressWarnings"unused") boolean isCsd)507         public Pair<Integer, Integer> getProfileLevel(@SuppressWarnings("unused") boolean isCsd) {
508             for (int pos = mOffset; pos < mLimit; ) {
509                 int offset = getNalUnitStartOffset(mData, pos, mLimit);
510                 if (offset == NO_NAL_UNIT_FOUND) return null;
511                 if (getNalUnitType(mData, offset) == 33) { // sps_nut
512                     NalParsableBitArray bitArray = new NalParsableBitArray(mData, offset, mLimit);
513                     bitArray.readBits(16); // nal unit header
514                     bitArray.readBits(4); // sps video parameter set id
515                     bitArray.readBits(3); // sps_max_sub_layers_minus1
516                     bitArray.readBits(1); // sps temporal id nesting flag
517                     // profile_tier_level
518                     bitArray.readBits(2); // generalProfileSpace
519                     int generalTierFlag = bitArray.readBits(1);
520                     int generalProfileIdc = bitArray.readBits(5);
521                     int[] generalProfileCompatibility = new int[32];
522                     for (int j = 0; j < generalProfileCompatibility.length; j++) {
523                         generalProfileCompatibility[j] = bitArray.readBits(1);
524                     }
525                     bitArray.readBits(1); // general progressive source flag
526                     bitArray.readBits(1); // general interlaced source flag
527                     bitArray.readBits(1); // general non packed constraint flag
528                     bitArray.readBits(1); // general frame only constraint flag
529 
530                     // interpretation of next 44 bits is dependent on generalProfileIdc and
531                     // generalProfileCompatibility; but we do not use them in this validation
532                     // process, so we're skipping over them.
533                     bitArray.readBitsLong(44);
534                     int generalLevelIdc = bitArray.readBits(8);
535 
536                     int profile = -1;
537                     if (generalProfileIdc == 1 || generalProfileCompatibility[1] == 1) {
538                         profile = HEVCProfileMain;
539                     } else if (generalProfileIdc == 2 || generalProfileCompatibility[2] == 1) {
540                         profile = HEVCProfileMain10;
541                     } else if (generalProfileIdc == 3 || generalProfileCompatibility[3] == 1) {
542                         profile = HEVCProfileMainStill;
543                     }
544 
545                     return plToPair(profile, getHashMapVal(
546                             generalTierFlag == 0 ? LEVEL_MAP_MAIN_TIER : LEVEL_MAP_HIGH_TIER,
547                             generalLevelIdc));
548                 }
549                 pos = offset;
550             }
551             return null;
552         }
553     }
554 
555     static class Vp9Parser extends ParserBase {
556         private static final Map<Integer, Integer> PROFILE_MAP = Map.ofEntries(
557                 Map.entry(0, VP9Profile0),
558                 Map.entry(1, VP9Profile1),
559                 Map.entry(2, VP9Profile2),
560                 Map.entry(3, VP9Profile3)
561         );
562         private static final Map<Integer, Integer> LEVEL_MAP = Map.ofEntries(
563                 Map.entry(10, VP9Level1),
564                 Map.entry(11, VP9Level11),
565                 Map.entry(20, VP9Level2),
566                 Map.entry(21, VP9Level21),
567                 Map.entry(30, VP9Level3),
568                 Map.entry(31, VP9Level31),
569                 Map.entry(40, VP9Level4),
570                 Map.entry(41, VP9Level41),
571                 Map.entry(50, VP9Level5),
572                 Map.entry(51, VP9Level51),
573                 Map.entry(60, VP9Level6),
574                 Map.entry(61, VP9Level61),
575                 Map.entry(62, VP9Level62)
576         );
577 
getProfileLevelFromCSD()578         private Pair<Integer, Integer> getProfileLevelFromCSD() { // parse vp9 codecprivate
579             int profile = -1, level = -1;
580             for (int pos = mOffset; pos < mLimit; ) {
581                 ParsableBitArray bitArray = new ParsableBitArray(mData, pos + mOffset, mLimit);
582                 int id = bitArray.readBits(8);
583                 int len = bitArray.readBits(8);
584                 pos += 2;
585                 int val = bitArray.readBits(len * 8);
586                 pos += len;
587                 if (id == 1 || id == 2) {
588                     Assert.assertEquals(1, len);
589                     if (id == 1) profile = val;
590                     else level = val;
591                 }
592                 if (profile != -1 && level != -1) break;
593             }
594             return plToPair(getHashMapVal(PROFILE_MAP, profile), getHashMapVal(LEVEL_MAP, level));
595         }
596 
getProfileFromFrameHeader()597         private Pair<Integer, Integer> getProfileFromFrameHeader() { // parse uncompressed header
598             ParsableBitArray bitArray = new ParsableBitArray(mData, mOffset, mLimit);
599             bitArray.readBits(2); // frame marker
600             int profileLBit = bitArray.readBits(1);
601             int profileHBit = bitArray.readBits(1);
602             int profile = profileHBit << 1 + profileLBit;
603             return plToPair(getHashMapVal(PROFILE_MAP, profile), -1);
604         }
605 
606         @Override
getFrameType()607         public int getFrameType() {
608             return PICTURE_TYPE_UNKNOWN;
609         }
610 
611         @Override
getProfileLevel(boolean isCsd)612         public Pair<Integer, Integer> getProfileLevel(boolean isCsd) {
613             return isCsd ? getProfileLevelFromCSD() : getProfileFromFrameHeader();
614         }
615     }
616 
617     static class Av1Parser extends ParserBase {
618         private static final int OBU_SEQUENCE_HEADER = 1;
619         private static final int OBU_FRAME_HEADER = 3;
620         private static final int OBU_FRAME = 6;
621         private static final int OBP_KEY_FRAME = 0;
622         private static final int OBP_INTER_FRAME = 1;
623         private static final int OBP_INTRA_ONLY_FRAME = 2;
624         private static final int OBP_SWITCH_FRAME = 3;
625         private static final int NUM_REF_FRAMES = 8;
626 
627         static class ObuInfo {
628             private int mObuType;
629             private int mTemporalId;
630             private int mSpatialId;
631             private int mHeaderSize;
632             private int mSizeFieldSize;
633             private int mDataSize;
634 
getTotalObuSize()635             int getTotalObuSize() {
636                 return mHeaderSize + mSizeFieldSize + mDataSize;
637             }
638 
getObuDataOffset()639             int getObuDataOffset() {
640                 return mHeaderSize + mSizeFieldSize;
641             }
642         }
643 
644         static class SeqHeaderObu {
645             public int seqProfile;
646             public int reducedStillPictureHeader;
647             public final int[] seqLevelIdx = new int[32];
648             public int timingInfoPresentFlag;
649             public int equalPictureInterval;
650             public int decoderModelInfoPresentFlag;
651             public int bufferDelayLengthMinus1;
652             public int bufferRemovalTimeLengthMinus1;
653             public int framePresentationTimeLengthMinus1;
654             public int initialDisplayDelayPresentFlag;
655             public int operatingPointsCntMinus1;
656             public final int[] operatingPointIdc = new int[32];
657             public final int[] seqTier = new int[32];
658             public final int[] decoderModelPresentForThisOp = new int[32];
659             public int frameIdNumbersPresentFlag;
660             public int deltaFrameIdLengthMinus2;
661             public int additionalFrameIdLengthMinus1;
662             public int seqForceScreenContentTools;
663             public int seqForceIntegerMv;
664             public int orderHintBits;
665             public int enableHighBitDepth;
666         }
667 
668         static class FrameHeaderObu {
669             public int frameType;
670             public int showFrame;
671             public int showExistingFrame;
672             public int errorResilientMode;
673         }
674 
675         private final SeqHeaderObu mSeqHeader = new SeqHeaderObu();
676         private final int[] mRefFrameType = new int[NUM_REF_FRAMES];
677 
678         // obu header size, obu size field, obu size
parseObuHeader(byte[] dataArray, int pos, int limit)679         private ObuInfo parseObuHeader(byte[] dataArray, int pos, int limit) {
680             int obuHeaderSize = 1;
681             ObuInfo obuDetails = new ObuInfo();
682             ObuParsableBitArray bitArray = new ObuParsableBitArray(dataArray, pos, limit);
683             bitArray.readBits(1);  // forbidden bit
684             obuDetails.mObuType = bitArray.readBits(4); // obu type
685             int extensionFlag = bitArray.readBits(1);
686             int hasSizeField = bitArray.readBits(1);
687             Assert.assertEquals(1, hasSizeField);
688             bitArray.readBits(1); // reserved 1bit
689             if (extensionFlag == 1) {
690                 obuDetails.mTemporalId = bitArray.readBits(3);
691                 obuDetails.mSpatialId = bitArray.readBits(2);
692                 bitArray.readBits(3);
693                 obuHeaderSize++;
694             }
695             int[] obuSizeInfo = bitArray.leb128();
696             obuDetails.mHeaderSize = obuHeaderSize;
697             obuDetails.mSizeFieldSize = obuSizeInfo[0];
698             obuDetails.mDataSize = obuSizeInfo[1];
699             return obuDetails;
700         }
701 
parseSequenceHeader(ObuParsableBitArray bitArray)702         private void parseSequenceHeader(ObuParsableBitArray bitArray) {
703             mSeqHeader.seqProfile = bitArray.readBits(3);
704             bitArray.readBits(1); // still picture
705             mSeqHeader.reducedStillPictureHeader = bitArray.readBits(1);
706             if (mSeqHeader.reducedStillPictureHeader == 1) {
707                 mSeqHeader.seqLevelIdx[0] = bitArray.readBits(5);
708             } else {
709                 mSeqHeader.timingInfoPresentFlag = bitArray.readBits(1);
710                 if (mSeqHeader.timingInfoPresentFlag == 1) {
711                     bitArray.readBitsLong(32); // num_units_in_display_tick
712                     bitArray.readBitsLong(32); // time_scale
713                     mSeqHeader.equalPictureInterval = bitArray.readBits(1);
714                     if (mSeqHeader.equalPictureInterval == 1) {
715                         bitArray.uvlc(); // num_ticks_per_picture_minus_1
716                     }
717                     mSeqHeader.decoderModelInfoPresentFlag = bitArray.readBits(1);
718                     if (mSeqHeader.decoderModelInfoPresentFlag == 1) {
719                         mSeqHeader.bufferDelayLengthMinus1 = bitArray.readBits(5);
720                         bitArray.readBitsLong(32); // num_units_in_decoding_tick
721                         mSeqHeader.bufferRemovalTimeLengthMinus1 = bitArray.readBits(5);
722                         mSeqHeader.framePresentationTimeLengthMinus1 = bitArray.readBits(5);
723                     }
724                 } else {
725                     mSeqHeader.decoderModelInfoPresentFlag = 0;
726                 }
727                 mSeqHeader.initialDisplayDelayPresentFlag = bitArray.readBits(1);
728                 mSeqHeader.operatingPointsCntMinus1 = bitArray.readBits(5);
729                 for (int i = 0; i <= mSeqHeader.operatingPointsCntMinus1; i++) {
730                     mSeqHeader.operatingPointIdc[i] = bitArray.readBits(12);
731                     mSeqHeader.seqLevelIdx[i] = bitArray.readBits(5);
732                     if (mSeqHeader.seqLevelIdx[i] > 7) {
733                         mSeqHeader.seqTier[i] = bitArray.readBits(1);
734                     }
735                     if (mSeqHeader.decoderModelInfoPresentFlag == 1) {
736                         mSeqHeader.decoderModelPresentForThisOp[i] = bitArray.readBits(1);
737                         if (mSeqHeader.decoderModelPresentForThisOp[i] == 1) {
738                             int n = mSeqHeader.bufferDelayLengthMinus1 + 1;
739                             bitArray.readBits(n); // decoder_buffer_delay
740                             bitArray.readBits(n); // encoder_buffer_delay
741                             bitArray.readBits(1); // low_delay_mode_flag
742                         }
743                     } else {
744                         mSeqHeader.decoderModelPresentForThisOp[i] = 0;
745                     }
746                     if (mSeqHeader.initialDisplayDelayPresentFlag == 1) {
747                         if (bitArray.readBits(1) == 1) {
748                             bitArray.readBits(4); // initial_display_delay_minus_1
749                         }
750                     }
751                 }
752             }
753             int frameWidthBitsMinus1 = bitArray.readBits(4);
754             int frameHeightBitsMinus1 = bitArray.readBits(4);
755             bitArray.readBits(frameWidthBitsMinus1 + 1); // max_frame_width_minus_1
756             bitArray.readBits(frameHeightBitsMinus1 + 1); // max_frame_height_minus_1
757             if (mSeqHeader.reducedStillPictureHeader == 1) {
758                 mSeqHeader.frameIdNumbersPresentFlag = 0;
759             } else {
760                 mSeqHeader.frameIdNumbersPresentFlag = bitArray.readBits(1);
761             }
762             if (mSeqHeader.frameIdNumbersPresentFlag == 1) {
763                 mSeqHeader.deltaFrameIdLengthMinus2 = bitArray.readBits(4);
764                 mSeqHeader.additionalFrameIdLengthMinus1 = bitArray.readBits(3);
765             }
766             bitArray.readBits(1); // use_128x128_superblock
767             bitArray.readBits(1); // enable_filter_intra
768             bitArray.readBits(1); // enable_intra_edge_filter
769             if (mSeqHeader.reducedStillPictureHeader == 1) {
770                 mSeqHeader.seqForceScreenContentTools = 2;
771                 mSeqHeader.seqForceIntegerMv = 2;
772                 mSeqHeader.orderHintBits = 0;
773             } else {
774                 bitArray.readBits(1); // enable_interintra_compound
775                 bitArray.readBits(1); // enable_masked_compound
776                 bitArray.readBits(1); // enable_warped_motion
777                 bitArray.readBits(1); // enable_dual_filter
778                 int enableOrderHint = bitArray.readBits(1);
779                 if (enableOrderHint == 1) {
780                     bitArray.readBits(1); // enable_jnt_comp
781                     bitArray.readBits(1); // enable_ref_frame_mvs
782                 }
783                 int seqChooseScreenContentTools = bitArray.readBits(1);
784                 if (seqChooseScreenContentTools == 1) {
785                     mSeqHeader.seqForceScreenContentTools = 2;
786                 } else {
787                     mSeqHeader.seqForceScreenContentTools = bitArray.readBits(1);
788                 }
789                 if (mSeqHeader.seqForceScreenContentTools > 0) {
790                     int seqChooseIntegerMv = bitArray.readBits(1);
791                     if (seqChooseIntegerMv == 1) {
792                         mSeqHeader.seqForceIntegerMv = 2;
793                     } else {
794                         mSeqHeader.seqForceIntegerMv = bitArray.readBits(1);
795                     }
796                 } else {
797                     mSeqHeader.seqForceIntegerMv = 2;
798                 }
799                 if (enableOrderHint == 1) {
800                     int orderHintBitsMinus1 = bitArray.readBits(3);
801                     mSeqHeader.orderHintBits = orderHintBitsMinus1 + 1;
802                 } else {
803                     mSeqHeader.orderHintBits = 0;
804                 }
805             }
806             bitArray.readBits(1); // enable super res
807             bitArray.readBits(1); // enable cdef
808             bitArray.readBits(1); // enable restoration
809             mSeqHeader.enableHighBitDepth = bitArray.readBits(1);
810         }
811 
parseFrameHeader(ObuParsableBitArray bitArray, int temporalId, int spatialId)812         private FrameHeaderObu parseFrameHeader(ObuParsableBitArray bitArray, int temporalId,
813                 int spatialId) {
814             FrameHeaderObu frameHeader = new FrameHeaderObu();
815             int idLen = 0;
816             if (mSeqHeader.frameIdNumbersPresentFlag == 1) {
817                 idLen = mSeqHeader.additionalFrameIdLengthMinus1
818                         + mSeqHeader.deltaFrameIdLengthMinus2 + 3;
819             }
820             int allFrames = (1 << NUM_REF_FRAMES) - 1;
821             int refreshFrameFlags = 0;
822             int frameIsIntra;
823             if (mSeqHeader.reducedStillPictureHeader == 1) {
824                 frameHeader.frameType = OBP_KEY_FRAME;
825                 frameIsIntra = 1;
826                 frameHeader.showFrame = 1;
827             } else {
828                 frameHeader.showExistingFrame = bitArray.readBits(1);
829                 if (frameHeader.showExistingFrame == 1) {
830                     int frameToShowMapIdx = bitArray.readBits(3);
831                     if (mSeqHeader.decoderModelInfoPresentFlag == 1
832                             && mSeqHeader.equalPictureInterval == 0) {
833                         int n = mSeqHeader.framePresentationTimeLengthMinus1 + 1;
834                         bitArray.readBits(n); // frame_presentation_time
835                     }
836                     if (mSeqHeader.frameIdNumbersPresentFlag == 1) {
837                         bitArray.readBits(idLen); // display_frame_id
838                     }
839                     frameHeader.frameType = mRefFrameType[frameToShowMapIdx];
840                     if (frameHeader.frameType == OBP_KEY_FRAME) {
841                         refreshFrameFlags = allFrames;
842                     }
843                     return frameHeader;
844                 }
845                 frameHeader.frameType = bitArray.readBits(2);
846                 frameIsIntra = (frameHeader.frameType == OBP_INTRA_ONLY_FRAME
847                         || frameHeader.frameType == OBP_KEY_FRAME) ? 1 : 0;
848                 frameHeader.showFrame = bitArray.readBits(1);
849                 if (frameHeader.showFrame == 1 && mSeqHeader.decoderModelInfoPresentFlag == 1
850                         && mSeqHeader.equalPictureInterval == 0) {
851                     int n = mSeqHeader.framePresentationTimeLengthMinus1 + 1;
852                     bitArray.readBits(n); // frame_presentation_time
853                 }
854                 if (frameHeader.showFrame == 0) {
855                     bitArray.readBits(1); // showable_frame
856                 }
857                 if (frameHeader.frameType == OBP_SWITCH_FRAME || (
858                         frameHeader.frameType == OBP_KEY_FRAME && frameHeader.showFrame == 1)) {
859                     frameHeader.errorResilientMode = 1;
860                 } else {
861                     frameHeader.errorResilientMode = bitArray.readBits(1);
862                 }
863             }
864             bitArray.readBits(1); // disable_cdf_update
865             int allowScreenContentTools;
866             if (mSeqHeader.seqForceScreenContentTools == 2) {
867                 allowScreenContentTools = bitArray.readBits(1);
868             } else {
869                 allowScreenContentTools = mSeqHeader.seqForceScreenContentTools;
870             }
871             if (allowScreenContentTools == 1 && mSeqHeader.seqForceIntegerMv == 2) {
872                 bitArray.readBits(1); // force_integer_mv
873             }
874             if (mSeqHeader.frameIdNumbersPresentFlag == 1) {
875                 bitArray.readBits(idLen); // current_frame_id
876             }
877             if (frameHeader.frameType != OBP_SWITCH_FRAME
878                     && mSeqHeader.reducedStillPictureHeader == 0) {
879                 bitArray.readBits(1); // frame_size_override_flag
880             }
881             bitArray.readBits(mSeqHeader.orderHintBits); // order_hint
882             if (frameIsIntra != 1 && frameHeader.errorResilientMode == 0) {
883                 bitArray.readBits(3); // primary_ref_frame
884             }
885 
886             if (mSeqHeader.decoderModelInfoPresentFlag == 1) {
887                 int bufferRemovalTimePresentFlag = bitArray.readBits(1);
888                 if (bufferRemovalTimePresentFlag == 1) {
889                     for (int i = 0; i <= mSeqHeader.operatingPointsCntMinus1; i++) {
890                         if (mSeqHeader.decoderModelPresentForThisOp[i] == 1) {
891                             int opPtIdc = mSeqHeader.operatingPointIdc[i];
892                             boolean inTemporalLayer = ((opPtIdc >> temporalId) & 1) == 1;
893                             boolean inSpatialLayer = ((opPtIdc >> (spatialId + 8)) & 1) == 1;
894                             if (opPtIdc == 0 || (inTemporalLayer && inSpatialLayer)) {
895                                 int n = mSeqHeader.bufferRemovalTimeLengthMinus1 + 1;
896                                 bitArray.readBits(n); // buffer_removal_time
897                             }
898                         }
899                     }
900                 }
901             }
902 
903             if (frameHeader.frameType == OBP_SWITCH_FRAME || (frameHeader.frameType == OBP_KEY_FRAME
904                     && frameHeader.showFrame == 1)) {
905                 refreshFrameFlags = allFrames;
906             } else {
907                 refreshFrameFlags = bitArray.readBits(8);
908             }
909 
910             for (int i = 0; i < 8; i++) {
911                 if ((refreshFrameFlags >> i & 1) == 1) {
912                     mRefFrameType[i] = frameHeader.frameType;
913                 }
914             }
915             return frameHeader;
916         }
917 
918         // parse av1 codec configuration record
getProfileLevelFromCSD()919         private Pair<Integer, Integer> getProfileLevelFromCSD() {
920             int profile = -1;
921             ParsableBitArray bitArray = new ParsableBitArray(mData, mOffset, mLimit);
922             Assert.assertEquals(1, bitArray.readBits(1));  // marker
923             Assert.assertEquals(1, bitArray.readBits(7));  // version
924             int seqProfile = bitArray.readBits(3);
925             int seqLevelIdx0 = bitArray.readBits(5);
926             bitArray.readBits(1);  // seqTier0
927             int highBitDepth = bitArray.readBits(1);
928             bitArray.readBits(1);  // is input 12 bit;
929             if (seqProfile == 0) {
930                 profile = highBitDepth == 0 ? AV1ProfileMain8 : AV1ProfileMain10;
931             }
932 
933             int level = AV1Level2 << seqLevelIdx0;
934             return plToPair(profile, level);
935         }
936 
937         // parse av1 sequence header
getProfileLevelFromSeqHeader()938         private Pair<Integer, Integer> getProfileLevelFromSeqHeader() {
939             for (int pos = mOffset; pos < mLimit; ) {
940                 ObuInfo obuDetails = parseObuHeader(mData, pos, mLimit);
941                 ObuParsableBitArray bitArray =
942                         new ObuParsableBitArray(mData, pos + obuDetails.getObuDataOffset(),
943                                 pos + obuDetails.getTotalObuSize());
944                 if (obuDetails.mObuType == OBU_SEQUENCE_HEADER) {
945                     int profile = -1;
946                     parseSequenceHeader(bitArray);
947                     if (mSeqHeader.seqProfile == 0) {
948                         profile = mSeqHeader.enableHighBitDepth == 0 ? AV1ProfileMain8 :
949                                 AV1ProfileMain10;
950                     }
951 
952                     int level = AV1Level2 << mSeqHeader.seqLevelIdx[0];
953                     return plToPair(profile, level);
954                 }
955                 pos += obuDetails.getTotalObuSize();
956             }
957             return null;
958         }
959 
960         @Override
getFrameType()961         public int getFrameType() {
962             ArrayList<FrameHeaderObu> headers = new ArrayList<>();
963             for (int pos = mOffset; pos < mLimit; ) {
964                 ObuInfo obuDetails = parseObuHeader(mData, pos, mLimit);
965                 ObuParsableBitArray bitArray =
966                         new ObuParsableBitArray(mData, pos + obuDetails.getObuDataOffset(),
967                                 pos + obuDetails.getTotalObuSize());
968                 if (obuDetails.mObuType == OBU_SEQUENCE_HEADER) {
969                     parseSequenceHeader(bitArray);
970                 } else if (obuDetails.mObuType == OBU_FRAME_HEADER
971                         || obuDetails.mObuType == OBU_FRAME) {
972                     FrameHeaderObu frameHeader = parseFrameHeader(bitArray, obuDetails.mTemporalId,
973                             obuDetails.mSpatialId);
974                     headers.add(frameHeader);
975                 }
976                 pos += obuDetails.getTotalObuSize();
977             }
978             for (FrameHeaderObu frameHeader : headers) {
979                 if (frameHeader.showFrame == 1 || frameHeader.showExistingFrame == 1) {
980                     if (frameHeader.frameType == OBP_KEY_FRAME
981                             || frameHeader.frameType == OBP_INTRA_ONLY_FRAME) {
982                         return PICTURE_TYPE_I;
983                     } else if (frameHeader.frameType == OBP_INTER_FRAME) {
984                         return PICTURE_TYPE_P;
985                     }
986                     return PICTURE_TYPE_UNKNOWN;
987                 }
988             }
989             return PICTURE_TYPE_UNKNOWN;
990         }
991 
992         @Override
getProfileLevel(boolean isCsd)993         public Pair<Integer, Integer> getProfileLevel(boolean isCsd) {
994             return isCsd ? getProfileLevelFromCSD() : getProfileLevelFromSeqHeader();
995         }
996     }
997 
998     static class AacParser extends ParserBase {
999         @Override
getFrameType()1000         public int getFrameType() {
1001             return PICTURE_TYPE_UNKNOWN;
1002         }
1003 
1004         @Override
getProfileLevel(@uppressWarnings"unused") boolean isCsd)1005         public Pair<Integer, Integer> getProfileLevel(@SuppressWarnings("unused") boolean isCsd) {
1006             // parse AudioSpecificConfig() of ISO 14496 Part 3
1007             ParsableBitArray bitArray = new ParsableBitArray(mData, mOffset, mLimit);
1008             int audioObjectType = bitArray.readBits(5);
1009             if (audioObjectType == 31) {
1010                 audioObjectType = 32 + bitArray.readBits(6); // audio object type ext
1011             }
1012             return plToPair(audioObjectType, -1);
1013         }
1014     }
1015 
1016     static class ApvParser extends ParserBase {
1017         private static final Map<Integer, Integer> PROFILE_MAP = Map.ofEntries(
1018                 Map.entry(33, APVProfile422_10));
1019 
getApvLevel(int level, int band)1020         private int getApvLevel(int level, int band) {
1021             switch (level) {
1022                 case 30:
1023                     switch (band) {
1024                         case 0:
1025                             return APVLevel1Band0;
1026                         case 1:
1027                             return APVLevel1Band1;
1028                         case 2:
1029                             return APVLevel1Band2;
1030                         case 3:
1031                             return APVLevel1Band3;
1032                     }
1033                     break;
1034                 case 33:
1035                     switch (band) {
1036                         case 0:
1037                             return APVLevel11Band0;
1038                         case 1:
1039                             return APVLevel11Band1;
1040                         case 2:
1041                             return APVLevel11Band2;
1042                         case 3:
1043                             return APVLevel11Band3;
1044                     }
1045                     break;
1046                 case 60:
1047                     switch (band) {
1048                         case 0:
1049                             return APVLevel2Band0;
1050                         case 1:
1051                             return APVLevel2Band1;
1052                         case 2:
1053                             return APVLevel2Band2;
1054                         case 3:
1055                             return APVLevel2Band3;
1056                     }
1057                     break;
1058                 case 63:
1059                     switch (band) {
1060                         case 0:
1061                             return APVLevel21Band0;
1062                         case 1:
1063                             return APVLevel21Band1;
1064                         case 2:
1065                             return APVLevel21Band2;
1066                         case 3:
1067                             return APVLevel21Band3;
1068                     }
1069                     break;
1070                 case 90:
1071                     switch (band) {
1072                         case 0:
1073                             return APVLevel3Band0;
1074                         case 1:
1075                             return APVLevel3Band1;
1076                         case 2:
1077                             return APVLevel3Band2;
1078                         case 3:
1079                             return APVLevel3Band3;
1080                     }
1081                     break;
1082                 case 93:
1083                     switch (band) {
1084                         case 0:
1085                             return APVLevel31Band0;
1086                         case 1:
1087                             return APVLevel31Band1;
1088                         case 2:
1089                             return APVLevel31Band2;
1090                         case 3:
1091                             return APVLevel31Band3;
1092                     }
1093                     break;
1094                 case 120:
1095                     switch (band) {
1096                         case 0:
1097                             return APVLevel4Band0;
1098                         case 1:
1099                             return APVLevel4Band1;
1100                         case 2:
1101                             return APVLevel4Band2;
1102                         case 3:
1103                             return APVLevel4Band3;
1104                     }
1105                     break;
1106                 case 123:
1107                     switch (band) {
1108                         case 0:
1109                             return APVLevel41Band0;
1110                         case 1:
1111                             return APVLevel41Band1;
1112                         case 2:
1113                             return APVLevel41Band2;
1114                         case 3:
1115                             return APVLevel41Band3;
1116                     }
1117                     break;
1118                 case 150:
1119                     switch (band) {
1120                         case 0:
1121                             return APVLevel5Band0;
1122                         case 1:
1123                             return APVLevel5Band1;
1124                         case 2:
1125                             return APVLevel5Band2;
1126                         case 3:
1127                             return APVLevel5Band3;
1128                     }
1129                     break;
1130                 case 153:
1131                     switch (band) {
1132                         case 0:
1133                             return APVLevel51Band0;
1134                         case 1:
1135                             return APVLevel51Band1;
1136                         case 2:
1137                             return APVLevel51Band2;
1138                         case 3:
1139                             return APVLevel51Band3;
1140                     }
1141                     break;
1142                 case 180:
1143                     switch (band) {
1144                         case 0:
1145                             return APVLevel6Band0;
1146                         case 1:
1147                             return APVLevel6Band1;
1148                         case 2:
1149                             return APVLevel6Band2;
1150                         case 3:
1151                             return APVLevel6Band3;
1152                     }
1153                     break;
1154                 case 183:
1155                     switch (band) {
1156                         case 0:
1157                             return APVLevel61Band0;
1158                         case 1:
1159                             return APVLevel61Band1;
1160                         case 2:
1161                             return APVLevel61Band2;
1162                         case 3:
1163                             return APVLevel61Band3;
1164                     }
1165                     break;
1166                 case 210:
1167                     switch (band) {
1168                         case 0:
1169                             return APVLevel7Band0;
1170                         case 1:
1171                             return APVLevel7Band1;
1172                         case 2:
1173                             return APVLevel7Band2;
1174                         case 3:
1175                             return APVLevel7Band3;
1176                     }
1177                     break;
1178                 case 213:
1179                     switch (band) {
1180                         case 0:
1181                             return APVLevel71Band0;
1182                         case 1:
1183                             return APVLevel71Band1;
1184                         case 2:
1185                             return APVLevel71Band2;
1186                         case 3:
1187                             return APVLevel71Band3;
1188                     }
1189                     break;
1190             }
1191             return APVLevel71Band3;
1192         }
1193 
1194         @Override
getFrameType()1195         public int getFrameType() {
1196             return PICTURE_TYPE_UNKNOWN;
1197         }
1198 
1199         @Override
getProfileLevel(@uppressWarnings"unused") boolean isCsd)1200         public Pair<Integer, Integer> getProfileLevel(@SuppressWarnings("unused") boolean isCsd) {
1201             ParsableBitArray bitArray = new ParsableBitArray(mData, mOffset, mLimit);
1202             Assert.assertEquals(1, bitArray.readBits(8));  // configuration version
1203             int numConfigEntry = bitArray.readBits(8);
1204 
1205             for (int i = 0; i < numConfigEntry; i++) {
1206                 bitArray.readBits(8); // pbu_type
1207                 int numFrameInfo = bitArray.readBits(8);
1208                 for (int j = 0; j < numFrameInfo; j++) {
1209                     bitArray.readBits(6); // reserved zero bits
1210                     bitArray.readBits(1); // color description present flag
1211                     bitArray.readBits(1); // capture time distance ignored
1212                     int profile = bitArray.readBits(8);
1213                     int level = bitArray.readBits(8);
1214                     int band = bitArray.readBits(8);
1215                     return plToPair(getHashMapVal(PROFILE_MAP, profile), getApvLevel(level, band));
1216                 }
1217             }
1218             return null;
1219         }
1220     }
1221 
getParserObject(String mediaType)1222     public static ParserBase getParserObject(String mediaType) {
1223         switch (mediaType) {
1224             case MediaFormat.MIMETYPE_VIDEO_MPEG4:
1225                 return new Mpeg4Parser();
1226             case MediaFormat.MIMETYPE_VIDEO_H263:
1227                 return new H263Parser();
1228             case MediaFormat.MIMETYPE_VIDEO_AVC:
1229                 return new AvcParser();
1230             case MediaFormat.MIMETYPE_VIDEO_HEVC:
1231                 return new HevcParser();
1232             case MediaFormat.MIMETYPE_VIDEO_AV1:
1233                 return new Av1Parser();
1234             case MediaFormat.MIMETYPE_VIDEO_VP9:
1235                 return new Vp9Parser();
1236             case MediaFormat.MIMETYPE_AUDIO_AAC:
1237                 return new AacParser();
1238             case MediaFormat.MIMETYPE_VIDEO_APV:
1239                 return new ApvParser();
1240         }
1241         return null;
1242     }
1243 
1244     @TargetApi(Build.VERSION_CODES.TIRAMISU)
getFrameTypeFromBitStream(ByteBuffer buf, MediaCodec.BufferInfo info, ParserBase o)1245     public static int getFrameTypeFromBitStream(ByteBuffer buf, MediaCodec.BufferInfo info,
1246             ParserBase o) {
1247         if (o == null) return PICTURE_TYPE_UNKNOWN;
1248         byte[] dataArray = new byte[info.size];
1249         buf.position(info.offset);
1250         buf.get(dataArray);
1251         o.set(dataArray, 0, info.size);
1252         return o.getFrameType();
1253     }
1254 
getProfileLevelFromBitStream(ByteBuffer buf, MediaCodec.BufferInfo info, ParserBase o)1255     public static Pair<Integer, Integer> getProfileLevelFromBitStream(ByteBuffer buf,
1256             MediaCodec.BufferInfo info, ParserBase o) {
1257         if (o == null) return null;
1258         byte[] dataArray = new byte[info.size];
1259         buf.position(info.offset);
1260         buf.get(dataArray);
1261         o.set(dataArray, 0, info.size);
1262         return o.getProfileLevel((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0);
1263     }
1264 }
1265