@@ -246,229 +246,29 @@ private static Format parseMediaFormat(
246246 System .arraycopy (sps .nalData , 0 , csdData , vps .nalLength , sps .nalLength );
247247 System .arraycopy (pps .nalData , 0 , csdData , vps .nalLength + sps .nalLength , pps .nalLength );
248248
249- // Parse the SPS NAL unit, as per H.265/HEVC (2014) 7.3.2.2.1.
250- ParsableNalUnitBitArray bitArray = new ParsableNalUnitBitArray (sps .nalData , 0 , sps .nalLength );
251- bitArray .skipBits (40 + 4 ); // NAL header, sps_video_parameter_set_id
252- int maxSubLayersMinus1 = bitArray .readBits (3 );
253- bitArray .skipBit (); // sps_temporal_id_nesting_flag
254- int generalProfileSpace = bitArray .readBits (2 );
255- boolean generalTierFlag = bitArray .readBit ();
256- int generalProfileIdc = bitArray .readBits (5 );
257- int generalProfileCompatibilityFlags = 0 ;
258- for (int i = 0 ; i < 32 ; i ++) {
259- if (bitArray .readBit ()) {
260- generalProfileCompatibilityFlags |= (1 << i );
261- }
262- }
263- int [] constraintBytes = new int [6 ];
264- for (int i = 0 ; i < constraintBytes .length ; ++i ) {
265- constraintBytes [i ] = bitArray .readBits (8 );
266- }
267- int generalLevelIdc = bitArray .readBits (8 );
268- int toSkip = 0 ;
269- for (int i = 0 ; i < maxSubLayersMinus1 ; i ++) {
270- if (bitArray .readBit ()) { // sub_layer_profile_present_flag[i]
271- toSkip += 89 ;
272- }
273- if (bitArray .readBit ()) { // sub_layer_level_present_flag[i]
274- toSkip += 8 ;
275- }
276- }
277- bitArray .skipBits (toSkip );
278- if (maxSubLayersMinus1 > 0 ) {
279- bitArray .skipBits (2 * (8 - maxSubLayersMinus1 ));
280- }
281-
282- bitArray .readUnsignedExpGolombCodedInt (); // sps_seq_parameter_set_id
283- int chromaFormatIdc = bitArray .readUnsignedExpGolombCodedInt ();
284- if (chromaFormatIdc == 3 ) {
285- bitArray .skipBit (); // separate_colour_plane_flag
286- }
287- int picWidthInLumaSamples = bitArray .readUnsignedExpGolombCodedInt ();
288- int picHeightInLumaSamples = bitArray .readUnsignedExpGolombCodedInt ();
289- if (bitArray .readBit ()) { // conformance_window_flag
290- int confWinLeftOffset = bitArray .readUnsignedExpGolombCodedInt ();
291- int confWinRightOffset = bitArray .readUnsignedExpGolombCodedInt ();
292- int confWinTopOffset = bitArray .readUnsignedExpGolombCodedInt ();
293- int confWinBottomOffset = bitArray .readUnsignedExpGolombCodedInt ();
294- // H.265/HEVC (2014) Table 6-1
295- int subWidthC = chromaFormatIdc == 1 || chromaFormatIdc == 2 ? 2 : 1 ;
296- int subHeightC = chromaFormatIdc == 1 ? 2 : 1 ;
297- picWidthInLumaSamples -= subWidthC * (confWinLeftOffset + confWinRightOffset );
298- picHeightInLumaSamples -= subHeightC * (confWinTopOffset + confWinBottomOffset );
299- }
300- bitArray .readUnsignedExpGolombCodedInt (); // bit_depth_luma_minus8
301- bitArray .readUnsignedExpGolombCodedInt (); // bit_depth_chroma_minus8
302- int log2MaxPicOrderCntLsbMinus4 = bitArray .readUnsignedExpGolombCodedInt ();
303- // for (i = sps_sub_layer_ordering_info_present_flag ? 0 : sps_max_sub_layers_minus1; ...)
304- for (int i = bitArray .readBit () ? 0 : maxSubLayersMinus1 ; i <= maxSubLayersMinus1 ; i ++) {
305- bitArray .readUnsignedExpGolombCodedInt (); // sps_max_dec_pic_buffering_minus1[i]
306- bitArray .readUnsignedExpGolombCodedInt (); // sps_max_num_reorder_pics[i]
307- bitArray .readUnsignedExpGolombCodedInt (); // sps_max_latency_increase_plus1[i]
308- }
309- bitArray .readUnsignedExpGolombCodedInt (); // log2_min_luma_coding_block_size_minus3
310- bitArray .readUnsignedExpGolombCodedInt (); // log2_diff_max_min_luma_coding_block_size
311- bitArray .readUnsignedExpGolombCodedInt (); // log2_min_luma_transform_block_size_minus2
312- bitArray .readUnsignedExpGolombCodedInt (); // log2_diff_max_min_luma_transform_block_size
313- bitArray .readUnsignedExpGolombCodedInt (); // max_transform_hierarchy_depth_inter
314- bitArray .readUnsignedExpGolombCodedInt (); // max_transform_hierarchy_depth_intra
315- // if (scaling_list_enabled_flag) { if (sps_scaling_list_data_present_flag) {...}}
316- boolean scalingListEnabled = bitArray .readBit ();
317- if (scalingListEnabled && bitArray .readBit ()) {
318- skipScalingList (bitArray );
319- }
320- bitArray .skipBits (2 ); // amp_enabled_flag (1), sample_adaptive_offset_enabled_flag (1)
321- if (bitArray .readBit ()) { // pcm_enabled_flag
322- // pcm_sample_bit_depth_luma_minus1 (4), pcm_sample_bit_depth_chroma_minus1 (4)
323- bitArray .skipBits (8 );
324- bitArray .readUnsignedExpGolombCodedInt (); // log2_min_pcm_luma_coding_block_size_minus3
325- bitArray .readUnsignedExpGolombCodedInt (); // log2_diff_max_min_pcm_luma_coding_block_size
326- bitArray .skipBit (); // pcm_loop_filter_disabled_flag
327- }
328- // Skips all short term reference picture sets.
329- skipShortTermRefPicSets (bitArray );
330- if (bitArray .readBit ()) { // long_term_ref_pics_present_flag
331- // num_long_term_ref_pics_sps
332- for (int i = 0 ; i < bitArray .readUnsignedExpGolombCodedInt (); i ++) {
333- int ltRefPicPocLsbSpsLength = log2MaxPicOrderCntLsbMinus4 + 4 ;
334- // lt_ref_pic_poc_lsb_sps[i], used_by_curr_pic_lt_sps_flag[i]
335- bitArray .skipBits (ltRefPicPocLsbSpsLength + 1 );
336- }
337- }
338- bitArray .skipBits (2 ); // sps_temporal_mvp_enabled_flag, strong_intra_smoothing_enabled_flag
339- float pixelWidthHeightRatio = 1 ;
340- if (bitArray .readBit ()) { // vui_parameters_present_flag
341- if (bitArray .readBit ()) { // aspect_ratio_info_present_flag
342- int aspectRatioIdc = bitArray .readBits (8 );
343- if (aspectRatioIdc == NalUnitUtil .EXTENDED_SAR ) {
344- int sarWidth = bitArray .readBits (16 );
345- int sarHeight = bitArray .readBits (16 );
346- if (sarWidth != 0 && sarHeight != 0 ) {
347- pixelWidthHeightRatio = (float ) sarWidth / sarHeight ;
348- }
349- } else if (aspectRatioIdc < NalUnitUtil .ASPECT_RATIO_IDC_VALUES .length ) {
350- pixelWidthHeightRatio = NalUnitUtil .ASPECT_RATIO_IDC_VALUES [aspectRatioIdc ];
351- } else {
352- Log .w (TAG , "Unexpected aspect_ratio_idc value: " + aspectRatioIdc );
353- }
354- }
355- if (bitArray .readBit ()) { // overscan_info_present_flag
356- bitArray .skipBit (); // overscan_appropriate_flag
357- }
358- if (bitArray .readBit ()) { // video_signal_type_present_flag
359- bitArray .skipBits (4 ); // video_format, video_full_range_flag
360- if (bitArray .readBit ()) { // colour_description_present_flag
361- // colour_primaries, transfer_characteristics, matrix_coeffs
362- bitArray .skipBits (24 );
363- }
364- }
365- if (bitArray .readBit ()) { // chroma_loc_info_present_flag
366- bitArray .readUnsignedExpGolombCodedInt (); // chroma_sample_loc_type_top_field
367- bitArray .readUnsignedExpGolombCodedInt (); // chroma_sample_loc_type_bottom_field
368- }
369- bitArray .skipBit (); // neutral_chroma_indication_flag
370- if (bitArray .readBit ()) { // field_seq_flag
371- // field_seq_flag equal to 1 indicates that the coded video sequence conveys pictures that
372- // represent fields, which means that frame height is double the picture height.
373- picHeightInLumaSamples *= 2 ;
374- }
375- }
249+ NalUnitUtil .H265SpsData spsData =
250+ NalUnitUtil .parseH265SpsNalUnitPayload (sps .nalData , 40 /8 , sps .nalLength );
376251
377252 String codecs =
378253 CodecSpecificDataUtil .buildHevcCodecString (
379- generalProfileSpace ,
380- generalTierFlag ,
381- generalProfileIdc ,
382- generalProfileCompatibilityFlags ,
383- constraintBytes ,
384- generalLevelIdc );
254+ spsData . generalProfileSpace ,
255+ spsData . generalTierFlag ,
256+ spsData . generalProfileIdc ,
257+ spsData . generalProfileCompatibilityFlags ,
258+ spsData . constraintBytes ,
259+ spsData . generalLevelIdc );
385260
386261 return new Format .Builder ()
387262 .setId (formatId )
388263 .setSampleMimeType (MimeTypes .VIDEO_H265 )
389264 .setCodecs (codecs )
390- .setWidth (picWidthInLumaSamples )
391- .setHeight (picHeightInLumaSamples )
392- .setPixelWidthHeightRatio (pixelWidthHeightRatio )
265+ .setWidth (spsData . width )
266+ .setHeight (spsData . height )
267+ .setPixelWidthHeightRatio (spsData . pixelWidthHeightRatio )
393268 .setInitializationData (Collections .singletonList (csdData ))
394269 .build ();
395270 }
396271
397- /** Skips scaling_list_data(). See H.265/HEVC (2014) 7.3.4. */
398- private static void skipScalingList (ParsableNalUnitBitArray bitArray ) {
399- for (int sizeId = 0 ; sizeId < 4 ; sizeId ++) {
400- for (int matrixId = 0 ; matrixId < 6 ; matrixId += sizeId == 3 ? 3 : 1 ) {
401- if (!bitArray .readBit ()) { // scaling_list_pred_mode_flag[sizeId][matrixId]
402- // scaling_list_pred_matrix_id_delta[sizeId][matrixId]
403- bitArray .readUnsignedExpGolombCodedInt ();
404- } else {
405- int coefNum = min (64 , 1 << (4 + (sizeId << 1 )));
406- if (sizeId > 1 ) {
407- // scaling_list_dc_coef_minus8[sizeId - 2][matrixId]
408- bitArray .readSignedExpGolombCodedInt ();
409- }
410- for (int i = 0 ; i < coefNum ; i ++) {
411- bitArray .readSignedExpGolombCodedInt (); // scaling_list_delta_coef
412- }
413- }
414- }
415- }
416- }
417-
418- /**
419- * Reads the number of short term reference picture sets in a SPS as ue(v), then skips all of
420- * them. See H.265/HEVC (2014) 7.3.7 and 7.4.8.
421- */
422- private static void skipShortTermRefPicSets (ParsableNalUnitBitArray bitArray ) {
423- int numShortTermRefPicSets = bitArray .readUnsignedExpGolombCodedInt ();
424- boolean interRefPicSetPredictionFlag = false ;
425- int numNegativePics ;
426- int numPositivePics ;
427- // As this method applies in a SPS, the only element of NumDeltaPocs accessed is the previous
428- // one, so we just keep track of that rather than storing the whole array.
429- // RefRpsIdx = stRpsIdx - (delta_idx_minus1 + 1) and delta_idx_minus1 is always zero in SPS.
430- int previousNumDeltaPocs = 0 ;
431- for (int stRpsIdx = 0 ; stRpsIdx < numShortTermRefPicSets ; stRpsIdx ++) {
432- if (stRpsIdx != 0 ) {
433- interRefPicSetPredictionFlag = bitArray .readBit ();
434- }
435- if (interRefPicSetPredictionFlag ) {
436- boolean deltaRpsSign = bitArray .readBit (); // delta_rps_sign
437- bitArray .readUnsignedExpGolombCodedInt (); // abs_delta_rps_minus1
438- numNegativePics = 0 ;
439- numPositivePics = 0 ;
440- for (int j = 0 ; j <= previousNumDeltaPocs ; j ++) {
441- if (!bitArray .readBit ()) { // used_by_curr_pic_flag[j]
442- if (!bitArray .readBit ()) { // use_delta_flag[j]
443- continue ; // if not use_delta_flag, skip increase numDeltaPocs
444- }
445- }
446- if (deltaRpsSign ) {
447- // See H.265/HEVC (2014) section 7.4.8 equation 7-61
448- numNegativePics ++;
449- } else {
450- // See H.265/HEVC (2014) section 7.4.8 equation 7-62
451- numPositivePics ++;
452- }
453- }
454-
455- } else {
456- numNegativePics = bitArray .readUnsignedExpGolombCodedInt ();
457- numPositivePics = bitArray .readUnsignedExpGolombCodedInt ();
458- for (int i = 0 ; i < numNegativePics ; i ++) {
459- bitArray .readUnsignedExpGolombCodedInt (); // delta_poc_s0_minus1[i]
460- bitArray .skipBit (); // used_by_curr_pic_s0_flag[i]
461- }
462- for (int i = 0 ; i < numPositivePics ; i ++) {
463- bitArray .readUnsignedExpGolombCodedInt (); // delta_poc_s1_minus1[i]
464- bitArray .skipBit (); // used_by_curr_pic_s1_flag[i]
465- }
466- }
467- // See H.265/HEVC (2014) section 7.4.8 equation 7-71
468- previousNumDeltaPocs = numNegativePics + numPositivePics ;
469- }
470- }
471-
472272 @ EnsuresNonNull ({"output" , "sampleReader" })
473273 private void assertTracksCreated () {
474274 Assertions .checkStateNotNull (output );
0 commit comments