/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mangui.hls.demux { import flash.utils.ByteArray; /* inspired from https://github.com/aizvorski/h264bitstream/blob/master/h264_stream.c#L241-L342 */ public class SPSInfo { public var width : int; public var height : int; public function SPSInfo(sps : ByteArray) { var profile_idc : int; sps.position++; profile_idc = sps.readUnsignedByte(); var eg : ExpGolomb = new ExpGolomb(sps); // constraint_set[0-5]_flag, u(1), reserved_zero_2bits u(2), level_idc u(8) eg.readBits(16); // skip seq_parameter_set_id eg.readUE(); if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 144) { var chroma_format_idc : int = eg.readUE(); if (3 === chroma_format_idc) { // separate_colour_plane_flag eg.readBits(1); } // bit_depth_luma_minus8 eg.readUE(); // bit_depth_chroma_minus8 eg.readUE(); // qpprime_y_zero_transform_bypass_flag eg.readBits(1); // seq_scaling_matrix_present_flag var seq_scaling_matrix_present_flag : Boolean = eg.readBoolean(); if (seq_scaling_matrix_present_flag) { var imax : int = (chroma_format_idc != 3) ? 8 : 12; for (var i : int = 0; i < imax; ++i) { // seq_scaling_list_present_flag[ i ] if (eg.readBoolean()) { if (i < 6) { scaling_list(16, eg); } else { scaling_list(64, eg); } } } } } // log2_max_frame_num_minus4 eg.readUE(); var pic_order_cnt_type : int = eg.readUE(); if ( 0 === pic_order_cnt_type ) { // log2_max_pic_order_cnt_lsb_minus4 eg.readUE(); } else if ( 1 === pic_order_cnt_type ) { // delta_pic_order_always_zero_flag eg.readBits(1); // offset_for_non_ref_pic eg.readUE(); // offset_for_top_to_bottom_field eg.readUE(); var num_ref_frames_in_pic_order_cnt_cycle : int = eg.readUE(); for (i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; ++i) { // offset_for_ref_frame[ i ] eg.readUE(); } } // max_num_ref_frames eg.readUE(); // gaps_in_frame_num_value_allowed_flag eg.readBits(1); var pic_width_in_mbs_minus1 : int = eg.readUE(); var pic_height_in_map_units_minus1 : int = eg.readUE(); var frame_mbs_only_flag : int = eg.readBits(1); if (0 === frame_mbs_only_flag) { // mb_adaptive_frame_field_flag eg.readBits(1); } // direct_8x8_inference_flag eg.readBits(1); var frame_cropping_flag : int = eg.readBits(1); if (frame_cropping_flag) { var frame_crop_left_offset : int = eg.readUE(); var frame_crop_right_offset : int = eg.readUE(); var frame_crop_top_offset : int = eg.readUE(); var frame_crop_bottom_offset : int = eg.readUE(); } width = ((pic_width_in_mbs_minus1 + 1) * 16) - frame_crop_left_offset * 2 - frame_crop_right_offset * 2; height = ((2 - frame_mbs_only_flag) * (pic_height_in_map_units_minus1 + 1) * 16) - (frame_crop_top_offset * 2) - (frame_crop_bottom_offset * 2); } private static function scaling_list(sizeOfScalingList : int, eg : ExpGolomb) : void { var lastScale : int = 8; var nextScale : int = 8; var delta_scale : int; for (var j : int = 0; j < sizeOfScalingList; ++j) { if (nextScale != 0) { delta_scale = eg.readSE(); nextScale = (lastScale + delta_scale + 256) % 256; } lastScale = (nextScale == 0) ? lastScale : nextScale; } } } }