in src/mkvgen/src/SpsParser.c [204:386]
STATUS parseH264SpsGetResolution(PBYTE pSps, UINT32 spsSize, PUINT16 pWidth, PUINT16 pHeight)
{
STATUS retStatus = STATUS_SUCCESS;
UINT32 frameCropLeftOffset = 0, frameCropRightOffset = 0, frameCropTopOffset = 0, frameCropBottomOffset = 0, picWidthInMbsMinus1 = 0,
frameMbsOnlyFlag = 0, picHeightInMapUnitsMinus1 = 0, profileIdc = 0, sizeOfScalingList = 0, lastScale = 8, nextScale = 8,
picOrderCntType = 0, numRefFramesInPicOrderCntCycle = 0, deltaScale = 0, chromaFormatIdc = 1, separateColourPlaneFlag = 0;
UINT32 i, j, read;
INT32 readInt, width, height, pixelWidth, pixelHeight, subWidthC, subHeightC, arrayWidth, cropUnitX, cropUnitY;
BitReader bitReader;
CHK(pSps != NULL && pWidth != NULL && pHeight != NULL, STATUS_NULL_ARG);
CHK(spsSize != 0, STATUS_INVALID_ARG_LEN);
// Create a bit reader on top of the SPS
CHK_STATUS(bitReaderReset(&bitReader, pSps, spsSize * 8));
// Read the SPS Nalu
CHK_STATUS(bitReaderReadBits(&bitReader, 8, &read));
CHK(((read & 0x80) == 0) && ((read & 0x60) != 0) && ((read & 0x1f) == SPS_NALU_TYPE), STATUS_MKV_INVALID_H264_H265_SPS_NALU);
// Get the profile
CHK_STATUS(bitReaderReadBits(&bitReader, 8, &profileIdc));
// Skip the constraint set flags 0 - 5, the reserved 2 zero bits
// 8 bits level_idc and after that read the exp golomb for seq_parameter_set_id
CHK_STATUS(bitReaderReadBits(&bitReader, 6 + 2 + 8, &read));
// Read exp golomb for seq_parameter_set_id
CHK_STATUS(bitReaderReadExpGolomb(&bitReader, &read));
if (profileIdc == 100 || profileIdc == 110 || profileIdc == 122 || profileIdc == 244 || profileIdc == 44 || profileIdc == 83 ||
profileIdc == 86 || profileIdc == 118 || profileIdc == 128 || profileIdc == 138) {
// Read chroma_format_idc
CHK_STATUS(bitReaderReadExpGolomb(&bitReader, &chromaFormatIdc));
if (chromaFormatIdc == 3) {
// Read residual_colour_transform_flag
CHK_STATUS(bitReaderReadBit(&bitReader, &separateColourPlaneFlag));
}
// Read bit_depth_luma_minus8
CHK_STATUS(bitReaderReadExpGolomb(&bitReader, &read));
// Read bit_depth_chroma_minus8
CHK_STATUS(bitReaderReadExpGolomb(&bitReader, &read));
// Read qpprime_y_zero_transform_bypass_flag
CHK_STATUS(bitReaderReadBit(&bitReader, &read));
// Read seq_scaling_matrix_present_flag
CHK_STATUS(bitReaderReadBit(&bitReader, &read));
if (read != 0) {
for (i = 0; i < 8; i++) {
// Read seq_scaling_list_present_flag
CHK_STATUS(bitReaderReadBit(&bitReader, &read));
if (read != 0) {
sizeOfScalingList = (i < 6) ? 16 : 64;
for (j = 0; j < sizeOfScalingList; j++) {
if (nextScale != 0) {
// Read delta scale
CHK_STATUS(bitReaderReadExpGolomb(&bitReader, &deltaScale));
nextScale = (lastScale + deltaScale + 256) % 256;
}
lastScale = (nextScale == 0) ? lastScale : nextScale;
}
}
}
}
}
// Read log2_max_frame_num_minus4
CHK_STATUS(bitReaderReadExpGolomb(&bitReader, &read));
// Read pic_order_cnt_type
CHK_STATUS(bitReaderReadExpGolomb(&bitReader, &picOrderCntType));
if (picOrderCntType == 0) {
// Read log2_max_pic_order_cnt_lsb_minus4
CHK_STATUS(bitReaderReadExpGolomb(&bitReader, &read));
} else if (picOrderCntType == 1) {
// Read delta_pic_order_always_zero_flag
CHK_STATUS(bitReaderReadBit(&bitReader, &read));
// Read offset_for_non_ref_pic
CHK_STATUS(bitReaderReadExpGolombSe(&bitReader, &readInt));
// Read offset_for_top_to_bottom_field
CHK_STATUS(bitReaderReadExpGolombSe(&bitReader, &readInt));
// Read bit_depth_luma_minus8
CHK_STATUS(bitReaderReadExpGolomb(&bitReader, &numRefFramesInPicOrderCntCycle));
for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
// Read offset_for_ref_frame
CHK_STATUS(bitReaderReadExpGolombSe(&bitReader, &readInt));
}
}
// Read max_num_ref_frames
CHK_STATUS(bitReaderReadExpGolomb(&bitReader, &read));
// Read gaps_in_frame_num_value_allowed_flag
CHK_STATUS(bitReaderReadBit(&bitReader, &read));
// Read pic_width_in_mbs_minus1
CHK_STATUS(bitReaderReadExpGolomb(&bitReader, &picWidthInMbsMinus1));
// Read pic_height_in_map_units_minus1
CHK_STATUS(bitReaderReadExpGolomb(&bitReader, &picHeightInMapUnitsMinus1));
// Read frame_mbs_only_flag
CHK_STATUS(bitReaderReadBit(&bitReader, &frameMbsOnlyFlag));
if (frameMbsOnlyFlag == 0) {
// Read mb_adaptive_frame_field_flag
CHK_STATUS(bitReaderReadBit(&bitReader, &read));
}
// Read direct_8x8_inference_flag
CHK_STATUS(bitReaderReadBit(&bitReader, &read));
// Read frame_cropping_flag
CHK_STATUS(bitReaderReadBit(&bitReader, &read));
if (read != 0) {
// Read frame_crop_left_offset
CHK_STATUS(bitReaderReadExpGolomb(&bitReader, &frameCropLeftOffset));
// Read frame_crop_right_offset
CHK_STATUS(bitReaderReadExpGolomb(&bitReader, &frameCropRightOffset));
// Read frame_crop_top_offset
CHK_STATUS(bitReaderReadExpGolomb(&bitReader, &frameCropTopOffset));
// Read frame_crop_bottom_offset
CHK_STATUS(bitReaderReadExpGolomb(&bitReader, &frameCropBottomOffset));
}
// Read vui_parameters_present_flag
CHK_STATUS(bitReaderReadBit(&bitReader, &read));
// Proper width and height extraction is defined in part in
// 7.3.2.1.1 for SPS syntax: https://www.itu.int/rec/T-REC-H.264-201304-S/en
arrayWidth = frameMbsOnlyFlag != 0 ? 1 : 2;
pixelWidth = (picWidthInMbsMinus1 + 1) * 16;
pixelHeight = (picHeightInMapUnitsMinus1 + 1) * 16 * arrayWidth;
switch (chromaFormatIdc) {
case 1:
subWidthC = 2;
subHeightC = 2;
break;
case 2:
subWidthC = 2;
subHeightC = 1;
break;
default:
subWidthC = 1;
subHeightC = 1;
}
cropUnitX = subWidthC;
cropUnitY = subHeightC * arrayWidth;
width = pixelWidth - frameCropLeftOffset * cropUnitX - frameCropRightOffset * cropUnitX;
height = pixelHeight - frameCropTopOffset * cropUnitY - frameCropBottomOffset * cropUnitY;
CHK(width >= 0 && width <= MAX_UINT16, STATUS_MKV_INVALID_H264_H265_SPS_WIDTH);
CHK(height >= 0 && height <= MAX_UINT16, STATUS_MKV_INVALID_H264_H265_SPS_HEIGHT);
*pWidth = (UINT16) width;
*pHeight = (UINT16) height;
CleanUp:
return retStatus;
}