[datatype-dev] CR: Parse H.264 opaque data (fix for 244230)
Eric Hyche ehyche at real.comDescription ------------------------------------------- The MainConcept-based and the QT-based H.264 decoders need to be able to recover the width and height of the encoded stream before having to create a buffer to be decoded into. So we add code in datatype/h264/common to parse the Sequence Parameter Set in the AVCDecoderConfigurationRecord and recover the width and height from there. Then we use this code in the QT-based H.264 decoder. (Changes for the MC-based decoder are sent separately.) Files Modified ------------------------------------------- datatype/h264/codec/decoder_qtsdk/Umakefil datatype/h264/codec/decoder_qtsdk/platform/win/h264qt.cpp datatype/h264/codec/decoder_qtsdk/platform/win/h264qt.h datatype/h264/common/hx_parse_h264.cpp datatype/h264/common/pub/hx_parse_h264.h Branches ------------------------------------------- HEAD, 310Atlas, and 204Cay ======================================= Eric Hyche (ehyche at real.com) Principal Engineer RealNetworks, Inc. -------------- next part -------------- Index: Umakefil =================================================================== RCS file: /cvsroot/datatype/h264/codec/decoder_qtsdk/Umakefil,v retrieving revision 1.1 diff -u -w -u -w -r1.1 Umakefil --- Umakefil 14 Jan 2009 19:13:47 -0000 1.1 +++ Umakefil 25 Jun 2009 19:42:42 -0000 @@ -73,7 +73,8 @@ "common/util[utillib]", "datatype/common/util[dtutillib]", "common/runtime[runtlib]", - "common/log/logutil[logutillib]") + "common/log/logutil[logutillib]", + "datatype/h264/common[h264comlib]") project.ExportFunction("PNCodec_Open", "HX_MOFTAG moftFormatTag,HXCODEC *codecRef", Index: platform/win/h264qt.cpp =================================================================== RCS file: /cvsroot/datatype/h264/codec/decoder_qtsdk/platform/win/h264qt.cpp,v retrieving revision 1.5 diff -u -w -u -w -r1.5 h264qt.cpp --- platform\win\h264qt.cpp 22 May 2009 16:05:12 -0000 1.5 +++ platform\win\h264qt.cpp 25 Jun 2009 19:42:42 -0000 @@ -65,6 +65,7 @@ #include "pckunpck.h" #include "hxpacketflags.h" #include "h264qt.h" +#include "hx_parse_h264.h" #include "ImageCompression.h" // from QuickTime SDK #include "GXMath.h" @@ -443,6 +444,31 @@ // Get the opaque data pointer and the opaque data size BYTE* pOpaqueData = ((BYTE*) pParams->pInMof) + 12; UINT32 ulOpaqueDataSize = pParams->pInMof->cbLength - 12; + // Parse the opaque data + HXAVCDecoderConfigurationRecord record; + HX_RESULT rv = record.Unpack(pOpaqueData, ulOpaqueDataSize); + if (SUCCEEDED(rv)) + { + // Get the width and height + UINT32 ulWidth = 0; + UINT32 ulHeight = 0; + rv = record.GetLumaWidthHeight(&ulWidth, &ulHeight); + if (SUCCEEDED(rv) && !m_ulFrameWidth && !m_ulFrameHeight) + { + // Save the width and height + m_ulFrameWidth = ulWidth; + m_ulFrameHeight = ulHeight; + // QTSDK tends to give us back frames which have + // a width that is a multiple of 16. So if the + // width is not a multiple of 16, then round up + // to the next multiple of 16. + UINT32 ulRem = m_ulFrameWidth % 16; + if (ulRem) + { + m_ulFrameWidth += 16 - ulRem; + } + } + } // The initialization data passed in is the sample description // from the stsd box. In most cases, this is the CONTENTS // of the 'avcC' box as defined in the MPEG-4 AVC spec. @@ -944,8 +970,75 @@ HX_RESULT CHXH264StreamQT::PNStream_GetProperty(ULONG32 ulProp, void* pValue) { - HX_ASSERT(FALSE && "CHXH264StreamQT::PNStream_GetProperty() not implemented."); - return HXR_NOTIMPL; + HXLOGL4(HXLOG_AVCQ, "CHXH264StreamQT[%p]::PNStream_GetProperty(%lu,)", this, ulProp); + HX_RESULT retVal = HXR_INVALID_PARAMETER; + + if (pValue) + { + // Clear the return value + retVal = HXR_OK; + // Switch on property type + switch (ulProp) + { + case SP_OUPUT_QUEUE_STATUS: + { + memcpy(pValue, &m_OutputQueueStatus, sizeof(HX_OQS)); + } + break; + case SP_OUPUT_QUEUE_STATUS2: + { + memcpy(pValue, &m_OutputQueueStatus2, sizeof(HX_OQS2)); + } + break; + case SP_ALLOW_DIFFERENT_OUPUT_SIZES: + { + *((HXBOOL*) pValue) = m_bAllowDifferentOutputSizes; + } + break; + case SP_CPUSCALABILITY: + { + *((HXBOOL*) pValue) = m_bCPUScalability; + } + break; + case SP_POSTFILTER: + { + *((HXBOOL*) pValue) = m_bPostFilter; + } + break; + case SP_TEMPORALINTERP: + { + *((HXBOOL*) pValue) = m_bTemporalInterpolation; + } + break; + case SP_DECODE_B_FRAMES: + { + *((HXBOOL*) pValue) = m_bDecodeBFrames; + } + break; + case SP_FRAME_WIDTH: + { + *((UINT32*) pValue) = m_ulFrameWidth; + } + break; + case SP_FRAME_HEIGHT: + { + *((UINT32*) pValue) = m_ulFrameHeight; + } + break; + case SP_HWMEM_MGT: + { + *((HXBOOL*) pValue) = FALSE; + } + break; + default: + { + retVal = HXR_FAIL; + } + break; + } + } + + return retVal; } #if defined(HW_VIDEO_MEMORY_FRONTEND) Index: hx_parse_h264.cpp =================================================================== RCS file: /cvsroot/datatype/h264/common/hx_parse_h264.cpp,v retrieving revision 1.1 diff -u -w -u -w -r1.1 hx_parse_h264.cpp --- hx_parse_h264.cpp 20 May 2009 13:25:01 -0000 1.1 +++ hx_parse_h264.cpp 25 Jun 2009 19:42:55 -0000 @@ -60,6 +60,353 @@ #include "pckunpck.h" #include "hx_parse_h264.h" +const BYTE g_ucDefault_4x4_Intra[16] = { 6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, 32, 32, 37, 37, 42}; +const BYTE g_ucDefault_4x4_Inter[16] = {10, 14, 14, 20, 20, 20, 24, 24, 24, 24, 27, 27, 27, 30, 30, 34}; +const BYTE g_ucDefault_8x8_Intra[64] = { 6, 10, 10, 13, 11, 13, 16, 16, 16, 16, 18, 18, 18, 18, 18, 23, + 23, 23, 23, 23, 23, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, + 27, 27, 27, 27, 29, 29, 29, 29, 29, 29, 29, 31, 31, 31, 31, 31, + 31, 33, 33, 33, 33, 33, 36, 36, 36, 36, 38, 38, 38, 40, 40, 42}; +const BYTE g_ucDefault_8x8_Inter[64] = { 9, 13, 13, 15, 13, 15, 17, 17, 17, 17, 19, 19, 19, 19, 19, 21, + 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24, 24, + 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27, + 27, 28, 28, 28, 28, 28, 30, 30, 30, 30, 32, 32, 32, 33, 33, 35}; + +HX_RESULT HXAVCSequenceParameterSet::Unpack(BYTE* pBuf, UINT32 ulLen) +{ + HX_RESULT retVal = HXR_INVALID_PARAMETER; + + if (pBuf && ulLen) + { + // Set the return value + retVal = HXR_FAIL; + // Make sure we have enough bytes + if (ulLen >= 3) + { + UINT32 i = 0; + // Unpack the profile_idc + UnpackUINT8Inc(&pBuf, &ulLen, &m_ucProfileIDC); + // Unpack the constaint flags + BYTE ucTmp = 0; + UnpackUINT8Inc(&pBuf, &ulLen, &ucTmp); + m_bConstraintSet0Flag = ((ucTmp & 0x80) ? TRUE : FALSE); + m_bConstraintSet1Flag = ((ucTmp & 0x40) ? TRUE : FALSE); + m_bConstraintSet2Flag = ((ucTmp & 0x20) ? TRUE : FALSE); + m_bConstraintSet3Flag = ((ucTmp & 0x10) ? TRUE : FALSE); + // Unpack the level_idc + UnpackUINT8Inc(&pBuf, &ulLen, &m_ucLevelIDC); + // Set up the Bitstream class + Bitstream bs; + bs.SetBuffer(pBuf, ulLen); + // Parse the seq_parameter_set_id + retVal = ParseExpGolombUnsigned(&bs, &m_ulSeqParameterSetID); + if (SUCCEEDED(retVal)) + { + // Check profile_idc + if (m_ucProfileIDC == 100 || m_ucProfileIDC == 110 || + m_ucProfileIDC == 122 || m_ucProfileIDC == 244 || + m_ucProfileIDC == 44 || m_ucProfileIDC == 83 || + m_ucProfileIDC == 86) + { + // Parse the chroma_format_idc + retVal = ParseExpGolombUnsigned(&bs, &m_ulChromaFormatIDC); + if (SUCCEEDED(retVal)) + { + // If the chroma_format_idc is 3, then we need to get the separate_colour_plane_flag + if (m_ulChromaFormatIDC == 3) + { + retVal = ParseBitstreamHXBOOL(&bs, &m_bSeparateColourPlaneFlag); + } + if (SUCCEEDED(retVal)) + { + // Parse the bit_depth_luma_minus8 + retVal = ParseExpGolombUnsigned(&bs, &m_ulBitDepthLumaMinus8); + if (SUCCEEDED(retVal)) + { + // Parse the bit_depth_chroma_minus8 + retVal = ParseExpGolombUnsigned(&bs, &m_ulBitDepthChromaMinus8); + if (SUCCEEDED(retVal)) + { + // Parse the qpprime_y_zero_transform_bypass_flag + retVal = ParseBitstreamHXBOOL(&bs, &m_bQPPrimeYZeroTransformBypassFlag); + if (SUCCEEDED(retVal)) + { + // Parse the seq_scaling_matrix_present_flag + retVal = ParseBitstreamHXBOOL(&bs, &m_bSeqScalingMatrixPresentFlag); + if (SUCCEEDED(retVal)) + { + // Are scaling matrices present? + if (m_bSeqScalingMatrixPresentFlag) + { + // Compute the number of scaling lists. If the chroma_format_idc is not 3, + // then there are 8. If chroma_format_idc is 3, then there are 12. + UINT32 ulNumLists = (m_ulChromaFormatIDC != 3 ? 8 : 12); + for (i = 0; i < ulNumLists && SUCCEEDED(retVal); i++) + { + // Parse the seq_scaling_list_present_flag[i] + retVal = ParseBitstreamHXBOOL(&bs, &m_bSeqScalingListPresent[i]); + if (SUCCEEDED(retVal)) + { + // Is the i-th scaling list present? + if (m_bSeqScalingListPresent[i]) + { + if (i < 6) + { + // Parse the 4x4 scaling lists + retVal = ParseScalingList(&bs, i, &m_ucScalingList4x4[i][0], 16, + &m_bUseDefaultScalingMatrix4x4Flag[i]); + } + else + { + // Parse the 8x8 scaling lists + retVal = ParseScalingList(&bs, i, &m_ucScalingList8x8[i - 6][0], 64, + &m_bUseDefaultScalingMatrix8x8Flag[i - 6]); + } + } + } + } + } + } + } + } + } + } + } + } + if (SUCCEEDED(retVal)) + { + // Parse the log2_max_frame_num_minus4 + retVal = ParseExpGolombUnsigned(&bs, &m_ulLog2MaxFrameNumMinus4); + if (SUCCEEDED(retVal)) + { + // Parse the pic_order_cnt_type + retVal = ParseExpGolombUnsigned(&bs, &m_ulPicOrderCntType); + if (SUCCEEDED(retVal)) + { + // Switch on pic_order_cnt_type + if (m_ulPicOrderCntType == 0) + { + // Parse the log2_max_pic_order_cnt_lsb_minus4 + retVal = ParseExpGolombUnsigned(&bs, &m_ulLog2MaxPicOrderCntLsbMinus4); + } + else if (m_ulPicOrderCntType == 1) + { + // Parse delta_pic_order_always_zero_flag + retVal = ParseBitstreamHXBOOL(&bs, &m_bDeltaPicOrderAlwaysZeroFlag); + if (SUCCEEDED(retVal)) + { + // Parse offset_for_non_ref_pic + retVal = ParseExpGolombSigned(&bs, &m_lOffsetForNonRefPic); + if (SUCCEEDED(retVal)) + { + // Parse offset_for_top_to_bottom_field + retVal = ParseExpGolombSigned(&bs, &m_lOffsetForTopToBottomField); + if (SUCCEEDED(retVal)) + { + // Parse num_ref_frames_in_pic_order_cnt_cycle + retVal = ParseExpGolombUnsigned(&bs, &m_ulNumRefFramesInPicOrderCntCycle); + if (SUCCEEDED(retVal)) + { + // Make sure m_ulNumRefFramesInPicOrderCntCycle is non-zero + if (m_ulNumRefFramesInPicOrderCntCycle) + { + // Set the return value + retVal = HXR_OUTOFMEMORY; + // Allocate offset_for_frame_ref array + HX_VECTOR_DELETE(m_plOffsetForRefFrame); + m_plOffsetForRefFrame = new INT32 [m_ulNumRefFramesInPicOrderCntCycle]; + if (m_plOffsetForRefFrame) + { + // Clear the return value + retVal = HXR_OK; + // Zero out the array + memset(m_plOffsetForRefFrame, 0, m_ulNumRefFramesInPicOrderCntCycle * sizeof(INT32)); + // Loop through reading each offset + for (i = 0; i < m_ulNumRefFramesInPicOrderCntCycle && SUCCEEDED(retVal); i++) + { + // Read offset_for_ref_frame[i] + retVal = retVal = ParseExpGolombSigned(&bs, &m_plOffsetForRefFrame[i]); + } + } + } + } + } + } + } + } + if (SUCCEEDED(retVal)) + { + // Parse num_ref_frames + retVal = ParseExpGolombUnsigned(&bs, &m_ulNumRefFrames); + if (SUCCEEDED(retVal)) + { + // Parse gaps_in_frame_num_value_allowed_flag + retVal = ParseBitstreamHXBOOL(&bs, &m_bGapsInFrameNumValueAllowedFlag); + if (SUCCEEDED(retVal)) + { + // Parse pic_width_in_mbs_minus1 + retVal = ParseExpGolombUnsigned(&bs, &m_ulPicWidthInMbsMinus1); + if (SUCCEEDED(retVal)) + { + // Parse pic_height_in_map_units_minus1 + retVal = ParseExpGolombUnsigned(&bs, &m_ulPicHeightInMapUnitsMinus1); + if (SUCCEEDED(retVal)) + { + // Parse m_bFrameMbsOnlyFlag + retVal = ParseBitstreamHXBOOL(&bs, &m_bFrameMbsOnlyFlag); + if (SUCCEEDED(retVal)) + { + if (!m_bFrameMbsOnlyFlag) + { + // Parse mb_adaptive_frame_field_flag + retVal = ParseBitstreamHXBOOL(&bs, &m_bMbAdaptiveFrameFieldFlag); + } + if (SUCCEEDED(retVal)) + { + // Parse direct_8x8_inference_flag + retVal = ParseBitstreamHXBOOL(&bs, &m_bDirect8x8InferenceFlag); + if (SUCCEEDED(retVal)) + { + // Parse frame_cropping_flag + retVal = ParseBitstreamHXBOOL(&bs, &m_bFrameCroppingFlag); + if (SUCCEEDED(retVal)) + { + // Is the frame_cropping_flag set? + if (m_bFrameCroppingFlag) + { + // Parse frame_crop_left_offset + retVal = ParseExpGolombUnsigned(&bs, &m_ulFrameCropLeftOffset); + if (SUCCEEDED(retVal)) + { + // Parse frame_crop_right_offset + retVal = ParseExpGolombUnsigned(&bs, &m_ulFrameCropRightOffset); + if (SUCCEEDED(retVal)) + { + // Parse frame_crop_top_offset + retVal = ParseExpGolombUnsigned(&bs, &m_ulFrameCropTopOffset); + if (SUCCEEDED(retVal)) + { + // Parse frame_crop_bottom_offset + retVal = ParseExpGolombUnsigned(&bs, &m_ulFrameCropBottomOffset); + } + } + } + } + else + { + // frame_cropping_flag is not set, so offsets are 0 + m_ulFrameCropLeftOffset = 0; + m_ulFrameCropRightOffset = 0; + m_ulFrameCropTopOffset = 0; + m_ulFrameCropBottomOffset = 0; + } + if (SUCCEEDED(retVal)) + { + // Parse vui_parameters_present_flag + retVal = ParseBitstreamHXBOOL(&bs, &m_bVuiParametersPresentFlag); + if (SUCCEEDED(retVal)) + { + // Is vui_parameters() present? + if (m_bVuiParametersPresentFlag) + { + // We do not currently parse the vui_parameters() + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + + return retVal; +} + +HX_RESULT HXAVCSequenceParameterSet::GetLumaWidthHeight(UINT32* pulWidth, UINT32* pulHeight) +{ + HX_RESULT retVal = HXR_INVALID_PARAMETER; + + if (pulWidth && pulHeight) + { + // Get the ChromaArrayType + UINT32 ulChromaArrayType = (m_bSeparateColourPlaneFlag ? 0 : m_ulChromaFormatIDC); + // Get an integer value for m_bFrameMbsOnlyFlag + UINT32 ulFrameMbsOnlyFlag = (m_bFrameMbsOnlyFlag ? 1 : 0); + // Compute the SubWidthC and SubHeightC values + UINT32 ulSubWidthC = 0; + UINT32 ulSubHeightC = 0; + if (!m_bSeparateColourPlaneFlag) + { + switch (m_ulChromaFormatIDC) + { + case 1: + ulSubWidthC = 2; + ulSubHeightC = 2; + break; + case 2: + ulSubWidthC = 2; + ulSubHeightC = 1; + break; + case 3: + ulSubWidthC = 1; + ulSubHeightC = 1; + break; + } + } + // Compute the crop units + UINT32 ulCropUnitX = 0; + UINT32 ulCropUnitY = 0; + if (ulChromaArrayType == 0) + { + ulCropUnitX = 1; + ulCropUnitY = 2 - ulFrameMbsOnlyFlag; + } + else + { + ulCropUnitX = ulSubWidthC; + ulCropUnitY = ulSubHeightC * (2 - ulFrameMbsOnlyFlag); + } + // Compute the picture width in luma samples + UINT32 ulPicWidthInSamplesLuma = (m_ulPicWidthInMbsMinus1 + 1) * 16; + // Compute frame height in macroblocks + UINT32 ulFrameHeightInMbs = (2 - ulFrameMbsOnlyFlag) * (m_ulPicHeightInMapUnitsMinus1 + 1); + // Compute the coordinates + UINT32 ulFrameLeftLuma = m_ulFrameCropLeftOffset * ulCropUnitX; + UINT32 ulFrameRightLuma = ulPicWidthInSamplesLuma - (ulCropUnitX * m_ulFrameCropRightOffset + 1); + UINT32 ulFrameTopLuma = m_ulFrameCropTopOffset * ulCropUnitY; + UINT32 ulFrameBottomLuma = (16 * ulFrameHeightInMbs) - (ulCropUnitY * m_ulFrameCropBottomOffset + 1); + // Now compute the dimensions + *pulWidth = ((ulFrameLeftLuma <= ulFrameRightLuma) ? (ulFrameRightLuma - ulFrameLeftLuma + 1) : 0); + *pulHeight = ((ulFrameTopLuma <= ulFrameBottomLuma) ? (ulFrameBottomLuma - ulFrameTopLuma + 1) : 0); + // Clear the return value + retVal = HXR_OK; + } + + return retVal; +} + +HX_RESULT HXAVCPictureParameterSet::Unpack(BYTE* pBuf, UINT32 ulLen) +{ + HX_RESULT retVal = HXR_INVALID_PARAMETER; + + if (pBuf && ulLen) + { + // We don't currently parse the picture parameter set + retVal = HXR_OK; + } + + return retVal; +} + HX_RESULT HXAVCDecoderConfigurationRecord::Unpack(BYTE* pBuf, UINT32 ulLen) { return UnpackInc(&pBuf, &ulLen); @@ -96,11 +443,23 @@ retVal = UnpackUINT8Inc(ppBuf, pulLen, &m_ucNumSequenceParameterSets); if (SUCCEEDED(retVal)) { + BYTE i = 0; // The number of sequence parameter sets is only in the lower 5 bits // of this byte, so we need to mask out the upper 3 bits. m_ucNumSequenceParameterSets &= 0x1F; + // Make sure we have at least one SPS + if (m_ucNumSequenceParameterSets) + { + // Set the return value + retVal = HXR_OUTOFMEMORY; + // Allocate an array of HXAVCSequenceParameterSet + HX_VECTOR_DELETE(m_pSPS); + m_pSPS = new HXAVCSequenceParameterSet [m_ucNumSequenceParameterSets]; + if (m_pSPS) + { + // Clear the return value + retVal = HXR_OK; // Skip the sequence parameter sets - BYTE i = 0; for (i = 0; i < m_ucNumSequenceParameterSets && SUCCEEDED(retVal); i++) { // Parse the size of the i-th sequence parameter set @@ -108,18 +467,23 @@ retVal = UnpackUINT16BEInc(ppBuf, pulLen, &usSize); if (SUCCEEDED(retVal)) { - // Compute the number of bytes to skip - UINT32 ulBytesToSkip = usSize; - if (ulBytesToSkip > *pulLen) - { - ulBytesToSkip = *pulLen; - // The length of the i-th sequence parameter set is longer - // than the data provided, so fail. + // Set the return value retVal = HXR_FAIL; + // Make sure we have enough bytes to parse + UINT32 ulSize = usSize; + if (ulSize <= *pulLen) + { + // Unpack the i-th SPS + retVal = m_pSPS[i].Unpack(*ppBuf, ulSize); + if (SUCCEEDED(retVal)) + { + // Skip the i-th SPS + *ppBuf += ulSize; + *pulLen -= ulSize; + } + } + } } - // Skip the i-th sequence parameter set - *ppBuf += ulBytesToSkip; - *pulLen -= ulBytesToSkip; } } if (SUCCEEDED(retVal)) @@ -128,6 +492,18 @@ retVal = UnpackUINT8Inc(ppBuf, pulLen, &m_ucNumPictureParameterSets); if (SUCCEEDED(retVal)) { + // Make sure we have at least one PPS + if (m_ucNumPictureParameterSets) + { + // Set the return value + retVal = HXR_OUTOFMEMORY; + // Allocate an array of PPS + HX_VECTOR_DELETE(m_pPPS); + m_pPPS = new HXAVCPictureParameterSet [m_ucNumPictureParameterSets]; + if (m_pPPS) + { + // Clear the return value + retVal = HXR_OK; // Skip the picture parameter sets for (i = 0; i < m_ucNumPictureParameterSets && SUCCEEDED(retVal); i++) { @@ -136,18 +512,23 @@ retVal = UnpackUINT16BEInc(ppBuf, pulLen, &usSize); if (SUCCEEDED(retVal)) { - // Compute the number of bytes to skip - UINT32 ulBytesToSkip = usSize; - if (ulBytesToSkip > *pulLen) - { - ulBytesToSkip = *pulLen; - // The length of the i-th picture parameter set is longer - // than the data provided, so fail. + // Set the return value retVal = HXR_FAIL; - } + // Make sure we have enough bytes to parse + UINT32 ulSize = usSize; + if (ulSize <= *pulLen) + { + // Parse the i-th PPS + retVal = m_pPPS[i].Unpack(*ppBuf, ulSize); + if (SUCCEEDED(retVal)) + { // Skip the i-th sequence parameter set - *ppBuf += ulBytesToSkip; - *pulLen -= ulBytesToSkip; + *ppBuf += ulSize; + *pulLen -= ulSize; + } + } + } + } } } } @@ -163,6 +544,27 @@ return retVal; } +HX_RESULT HXAVCDecoderConfigurationRecord::GetLumaWidthHeight(UINT32* pulWidth, UINT32* pulHeight) +{ + HX_RESULT retVal = HXR_INVALID_PARAMETER; + + if (pulWidth && pulHeight) + { + // Set the return value + retVal = HXR_UNEXPECTED; + // Make sure we have at least one SPS + if (m_ucNumSequenceParameterSets && m_pSPS) + { + // We assume we only have one SPS + HX_ASSERT(m_ucNumSequenceParameterSets == 1); + // Get the width and height from the first SPS + retVal = m_pSPS[0].GetLumaWidthHeight(pulWidth, pulHeight); + } + } + + return retVal; +} + HX_RESULT ParseNALUnitHeader(BYTE** ppBuf, UINT32* pulLen, UINT32* pulNALRefIDC, HXNALUnitType* peNALUnitType) { HX_RESULT retVal = HXR_INVALID_PARAMETER; @@ -272,6 +674,105 @@ return retVal; } +HX_RESULT ParseBitstreamHXBOOL(Bitstream* pBS, HXBOOL* pbValue) +{ + HX_RESULT retVal = HXR_INVALID_PARAMETER; + + if (pBS && pbValue) + { + // Set the return value + retVal = HXR_FAIL; + // Make sure we have one bit + if (pBS->BitsLeft() >= 1) + { + // Get one bit from the bitstream + UINT32 ulTmp = pBS->GetBits(1); + // Set the out parameter + *pbValue = (ulTmp ? TRUE : FALSE); + // Clear the return value + retVal = HXR_OK; + } + } + + return retVal; +} + +HX_RESULT ParseScalingList(Bitstream* pBS, UINT32 ulIdx, BYTE* pucList, UINT32 ulListSize, HXBOOL* pbUseDefaultMatrix) +{ + HX_RESULT retVal = HXR_INVALID_PARAMETER; + + if (pBS && pucList && ulListSize && pbUseDefaultMatrix) + { + // Clear the return value + retVal = HXR_OK; + // Parse ulListSize scales + INT32 lLastScale = 8; + INT32 lNextScale = 8; + UINT32 j = 0; + for (j = 0; j < ulListSize && SUCCEEDED(retVal); j++) + { + if (lNextScale) + { + // Parse the delta_scale + INT32 lDeltaScale = 0; + retVal = ParseExpGolombSigned(pBS, &lDeltaScale); + if (SUCCEEDED(retVal)) + { + // Update nextScale + lNextScale = (lLastScale + lDeltaScale + 256) % 256; + // Set useDefaultScalingMatrixFlag + *pbUseDefaultMatrix = ((j == 0 && lNextScale == 0) ? TRUE : FALSE); + } + } + if (SUCCEEDED(retVal)) + { + pucList[j] = (BYTE) (lNextScale == 0 ? lLastScale : lNextScale); + lLastScale = pucList[j]; + } + } + if (SUCCEEDED(retVal) && *pbUseDefaultMatrix) + { + // We are supposed to use the default scaling matrix for this index. + // Get the proper default matrix to use. This comes from Table 7-2 + // in ITU-T Rec H.264. + const BYTE* pDefaultMatrix = NULL; + UINT32 ulDefaultMatrixSize = 0; + if (ulIdx <= 2) + { + pDefaultMatrix = g_ucDefault_4x4_Intra; + ulDefaultMatrixSize = 16; + } + else if (ulIdx >= 3 && ulIdx <= 5) + { + pDefaultMatrix = g_ucDefault_4x4_Inter; + ulDefaultMatrixSize = 16; + } + else if (ulIdx >= 6 && ulIdx <= 8) + { + pDefaultMatrix = g_ucDefault_8x8_Intra; + ulDefaultMatrixSize = 64; + } + else if (ulIdx >= 9 && ulIdx <= 11) + { + pDefaultMatrix = g_ucDefault_8x8_Inter; + ulDefaultMatrixSize = 64; + } + // Set the return value + retVal = HXR_FAIL; + // Make sure the default matrix matches our matrix size + if (pDefaultMatrix && ulDefaultMatrixSize && ulDefaultMatrixSize == ulListSize) + { + // Copy the default matrix + memcpy(pucList, pDefaultMatrix, ulDefaultMatrixSize * sizeof(BYTE)); + // Clear the return value + retVal = HXR_OK; + } + } + } + + return retVal; +} + HX_RESULT ParseSliceHeader(BYTE* pBuf, UINT32 ulLen, UINT32* pulFirstMBInSlice, HXSliceType* peSliceType, UINT32* pulPictureParameterSetID) { Index: pub/hx_parse_h264.h =================================================================== RCS file: /cvsroot/datatype/h264/common/pub/hx_parse_h264.h,v retrieving revision 1.1 diff -u -w -u -w -r1.1 hx_parse_h264.h --- pub\hx_parse_h264.h 20 May 2009 13:25:02 -0000 1.1 +++ pub\hx_parse_h264.h 25 Jun 2009 19:42:55 -0000 @@ -109,6 +109,182 @@ HXNumSliceTypes }; +class HXAVCSequenceParameterSet +{ +public: + HXAVCSequenceParameterSet() + : m_ucProfileIDC(0) + , m_bConstraintSet0Flag(FALSE) + , m_bConstraintSet1Flag(FALSE) + , m_bConstraintSet2Flag(FALSE) + , m_bConstraintSet3Flag(FALSE) + , m_ucLevelIDC(0) + , m_ulSeqParameterSetID(0) + , m_ulChromaFormatIDC(0) + , m_bSeparateColourPlaneFlag(FALSE) + , m_ulBitDepthLumaMinus8(0) + , m_ulBitDepthChromaMinus8(0) + , m_bQPPrimeYZeroTransformBypassFlag(FALSE) + , m_bSeqScalingMatrixPresentFlag(FALSE) + , m_ulLog2MaxFrameNumMinus4(0) + , m_ulPicOrderCntType(0) + , m_ulLog2MaxPicOrderCntLsbMinus4(0) + , m_bDeltaPicOrderAlwaysZeroFlag(FALSE) + , m_lOffsetForNonRefPic(0) + , m_lOffsetForTopToBottomField(0) + , m_ulNumRefFramesInPicOrderCntCycle(0) + , m_plOffsetForRefFrame(NULL) + , m_ulNumRefFrames(0) + , m_bGapsInFrameNumValueAllowedFlag(FALSE) + , m_ulPicWidthInMbsMinus1(0) + , m_ulPicHeightInMapUnitsMinus1(0) + , m_bFrameMbsOnlyFlag(FALSE) + , m_bMbAdaptiveFrameFieldFlag(FALSE) + , m_bDirect8x8InferenceFlag(FALSE) + , m_bFrameCroppingFlag(FALSE) + , m_ulFrameCropLeftOffset(0) + , m_ulFrameCropRightOffset(0) + , m_ulFrameCropTopOffset(0) + , m_ulFrameCropBottomOffset(0) + , m_bVuiParametersPresentFlag(FALSE) + { + memset(m_bSeqScalingListPresent, 0, 12 * sizeof(HXBOOL)); + memset(m_ucScalingList4x4, 0, 6 * 16 * sizeof(BYTE)); + memset(m_ucScalingList8x8, 0, 6 * 64 * sizeof(BYTE)); + memset(m_bUseDefaultScalingMatrix4x4Flag, 0, 6 * sizeof(HXBOOL)); + memset(m_bUseDefaultScalingMatrix8x8Flag, 0, 6 * sizeof(HXBOOL)); + }; + + ~HXAVCSequenceParameterSet() + { + HX_VECTOR_DELETE(m_plOffsetForRefFrame); + }; + + HX_RESULT Unpack(BYTE* pBuf, UINT32 ulLen); + HX_RESULT GetLumaWidthHeight(UINT32* pulWidth, UINT32* pulHeight); +private: + BYTE m_ucProfileIDC; + HXBOOL m_bConstraintSet0Flag; + HXBOOL m_bConstraintSet1Flag; + HXBOOL m_bConstraintSet2Flag; + HXBOOL m_bConstraintSet3Flag; + BYTE m_ucLevelIDC; + UINT32 m_ulSeqParameterSetID; + UINT32 m_ulChromaFormatIDC; + HXBOOL m_bSeparateColourPlaneFlag; + UINT32 m_ulBitDepthLumaMinus8; + UINT32 m_ulBitDepthChromaMinus8; + HXBOOL m_bQPPrimeYZeroTransformBypassFlag; + HXBOOL m_bSeqScalingMatrixPresentFlag; + HXBOOL m_bSeqScalingListPresent[12]; + BYTE m_ucScalingList4x4[6][16]; + BYTE m_ucScalingList8x8[6][64]; + HXBOOL m_bUseDefaultScalingMatrix4x4Flag[6]; + HXBOOL m_bUseDefaultScalingMatrix8x8Flag[6]; + UINT32 m_ulLog2MaxFrameNumMinus4; + UINT32 m_ulPicOrderCntType; + UINT32 m_ulLog2MaxPicOrderCntLsbMinus4; + HXBOOL m_bDeltaPicOrderAlwaysZeroFlag; + INT32 m_lOffsetForNonRefPic; + INT32 m_lOffsetForTopToBottomField; + UINT32 m_ulNumRefFramesInPicOrderCntCycle; + INT32* m_plOffsetForRefFrame; + UINT32 m_ulNumRefFrames; + HXBOOL m_bGapsInFrameNumValueAllowedFlag; + UINT32 m_ulPicWidthInMbsMinus1; + UINT32 m_ulPicHeightInMapUnitsMinus1; + HXBOOL m_bFrameMbsOnlyFlag; + HXBOOL m_bMbAdaptiveFrameFieldFlag; + HXBOOL m_bDirect8x8InferenceFlag; + HXBOOL m_bFrameCroppingFlag; + UINT32 m_ulFrameCropLeftOffset; + UINT32 m_ulFrameCropRightOffset; + UINT32 m_ulFrameCropTopOffset; + UINT32 m_ulFrameCropBottomOffset; + HXBOOL m_bVuiParametersPresentFlag; +}; + +class HXAVCPictureParameterSet +{ +public: + HXAVCPictureParameterSet() + : m_ulPicParameterSetID(0) + , m_ulSeqParameterSetID(0) + , m_bEntropyCodingModeFlag(FALSE) + , m_bPicOrderPresentFlag(FALSE) + , m_ulNumSliceGroupsMinus1(0) + , m_ulSliceGroupMapType(0) + , m_pulRunLengthMinus1(NULL) + , m_pulTopLeft(NULL) + , m_pulBottomRight(NULL) + , m_bSliceGroupChangeDirectionFlag(FALSE) + , m_ulSliceGroupChangeRateMinus1(0) + , m_ulPicSizeInMapUnitsMinus1(0) + , m_pulSlideGroupID(NULL) + , m_ulNumRefIdx10ActiveMinus1(0) + , m_ulNumRefIdx11ActiveMinus1(0) + , m_bWeightedPredFlag(FALSE) + , m_ucWeightedBipredIDC(0) + , m_lPicInitQpMinus26(0) + , m_lPicInitQsMinus26(0) + , m_lChromaQpIndexOffset(0) + , m_bDeblockingFilterControlPresentFlag(FALSE) + , m_bConstrainedIntraPredFlag(FALSE) + , m_bRedundantPicCntPresentFlag(FALSE) + , m_bTransform8x8ModeFlag(FALSE) + , m_bPixScalingMatrixPresentFlag(FALSE) + , m_lSecondChromaQpIndexOffset(0) + { + memset(m_bPicScalingListPresentFlag, 0, 12 * sizeof(HXBOOL)); + memset(m_ucScalingList4x4, 0, 6 * 16 * sizeof(BYTE)); + memset(m_ucScalingList8x8, 0, 6 * 64 * sizeof(BYTE)); + memset(m_bUseDefaultScalingMatrix4x4Flag, 0, 6 * sizeof(HXBOOL)); + memset(m_bUseDefaultScalingMatrix8x8Flag, 0, 6 * sizeof(HXBOOL)); + }; + + ~HXAVCPictureParameterSet() + { + HX_VECTOR_DELETE(m_pulRunLengthMinus1); + HX_VECTOR_DELETE(m_pulTopLeft); + HX_VECTOR_DELETE(m_pulBottomRight); + HX_VECTOR_DELETE(m_pulSlideGroupID); + }; + + HX_RESULT Unpack(BYTE* pBuf, UINT32 ulLen); +private: + UINT32 m_ulPicParameterSetID; + UINT32 m_ulSeqParameterSetID; + HXBOOL m_bEntropyCodingModeFlag; + HXBOOL m_bPicOrderPresentFlag; + UINT32 m_ulNumSliceGroupsMinus1; + UINT32 m_ulSliceGroupMapType; + UINT32* m_pulRunLengthMinus1; + UINT32* m_pulTopLeft; + UINT32* m_pulBottomRight; + HXBOOL m_bSliceGroupChangeDirectionFlag; + UINT32 m_ulSliceGroupChangeRateMinus1; + UINT32 m_ulPicSizeInMapUnitsMinus1; + UINT32* m_pulSlideGroupID; + UINT32 m_ulNumRefIdx10ActiveMinus1; + UINT32 m_ulNumRefIdx11ActiveMinus1; + HXBOOL m_bWeightedPredFlag; + BYTE m_ucWeightedBipredIDC; + INT32 m_lPicInitQpMinus26; + INT32 m_lPicInitQsMinus26; + INT32 m_lChromaQpIndexOffset; + HXBOOL m_bDeblockingFilterControlPresentFlag; + HXBOOL m_bConstrainedIntraPredFlag; + HXBOOL m_bRedundantPicCntPresentFlag; + HXBOOL m_bTransform8x8ModeFlag; + HXBOOL m_bPixScalingMatrixPresentFlag; + HXBOOL m_bPicScalingListPresentFlag[12]; + BYTE m_ucScalingList4x4[6][16]; + BYTE m_ucScalingList8x8[6][64]; + HXBOOL m_bUseDefaultScalingMatrix4x4Flag[6]; + HXBOOL m_bUseDefaultScalingMatrix8x8Flag[6]; + INT32 m_lSecondChromaQpIndexOffset; +}; + class HXAVCDecoderConfigurationRecord { public: @@ -120,11 +296,15 @@ , m_ucNumBytesInNALUnitLength(0) , m_ucNumSequenceParameterSets(0) , m_ucNumPictureParameterSets(0) + , m_pSPS(NULL) + , m_pPPS(NULL) { }; ~HXAVCDecoderConfigurationRecord() { + HX_VECTOR_DELETE(m_pSPS); + HX_VECTOR_DELETE(m_pPPS); }; HX_RESULT Unpack(BYTE* pBuf, UINT32 ulLen); @@ -137,6 +317,7 @@ BYTE GetNumBytesInNALUnitLength() const { return m_ucNumBytesInNALUnitLength; } BYTE GetNumSequenceParameterSets() const { return m_ucNumSequenceParameterSets; } BYTE GetNumPictureParameterSets() const { return m_ucNumPictureParameterSets; } + HX_RESULT GetLumaWidthHeight(UINT32* pulWidth, UINT32* pulHeight); private: BYTE m_ucConfigurationVersion; BYTE m_ucAVCProfileIndication; @@ -145,12 +326,16 @@ BYTE m_ucNumBytesInNALUnitLength; BYTE m_ucNumSequenceParameterSets; BYTE m_ucNumPictureParameterSets; + HXAVCSequenceParameterSet* m_pSPS; + HXAVCPictureParameterSet* m_pPPS; }; HX_RESULT ParseNALUnitHeader(BYTE** ppBuf, UINT32* pulLen, UINT32* pulNALRefIDC, HXNALUnitType* peNALUnitType); HX_RESULT ParseExpGolombCode(Bitstream* pBS, UINT32* pulCodeNum); HX_RESULT ParseExpGolombUnsigned(Bitstream* pBS, UINT32* pulValue); HX_RESULT ParseExpGolombSigned(Bitstream* pBS, INT32* plValue); +HX_RESULT ParseBitstreamHXBOOL(Bitstream* pBS, HXBOOL* pbValue); +HX_RESULT ParseScalingList(Bitstream* pBS, UINT32 ulIdx, BYTE* pucList, UINT32 ulListSize, HXBOOL* pbUseDefaultMatrix); HX_RESULT ParseSliceHeader(BYTE* pBuf, UINT32 ulLen, UINT32* pulFirstMBInSlice, HXSliceType* peSliceType, UINT32* pulPictureParameterSetID); // This method parses one or more NAL Units, including the 1/2/4 byte NAL unit length.