diff options
Diffstat (limited to 'media/libstagefright/codecs/on2/h264dec/source/h264bsd_seq_param_set.c')
-rw-r--r-- | media/libstagefright/codecs/on2/h264dec/source/h264bsd_seq_param_set.c | 577 |
1 files changed, 577 insertions, 0 deletions
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_seq_param_set.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_seq_param_set.c new file mode 100644 index 0000000..751051a --- /dev/null +++ b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_seq_param_set.c @@ -0,0 +1,577 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*------------------------------------------------------------------------------ + + Table of contents + + 1. Include headers + 2. External compiler flags + 3. Module defines + 4. Local function prototypes + 5. Functions + h264bsdDecodeSeqParamSet + GetDpbSize + h264bsdCompareSeqParamSets + +------------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------ + 1. Include headers +------------------------------------------------------------------------------*/ + +#include "h264bsd_seq_param_set.h" +#include "h264bsd_util.h" +#include "h264bsd_vlc.h" +#include "h264bsd_vui.h" +#include "h264bsd_cfg.h" + +/*------------------------------------------------------------------------------ + 2. External compiler flags +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- + 3. Module defines +------------------------------------------------------------------------------*/ + +/* enumeration to indicate invalid return value from the GetDpbSize function */ +enum {INVALID_DPB_SIZE = 0x7FFFFFFF}; + +/*------------------------------------------------------------------------------ + 4. Local function prototypes +------------------------------------------------------------------------------*/ + +static u32 GetDpbSize(u32 picSizeInMbs, u32 levelIdc); + +/*------------------------------------------------------------------------------ + + Function name: h264bsdDecodeSeqParamSet + + Functional description: + Decode sequence parameter set information from the stream. + + Function allocates memory for offsetForRefFrame array if + picture order count type is 1 and numRefFramesInPicOrderCntCycle + is greater than zero. + + Inputs: + pStrmData pointer to stream data structure + + Outputs: + pSeqParamSet decoded information is stored here + + Returns: + HANTRO_OK success + HANTRO_NOK failure, invalid information or end of stream + MEMORY_ALLOCATION_ERROR for memory allocation failure + +------------------------------------------------------------------------------*/ + +u32 h264bsdDecodeSeqParamSet(strmData_t *pStrmData, seqParamSet_t *pSeqParamSet) +{ + +/* Variables */ + + u32 tmp, i, value; + +/* Code */ + + ASSERT(pStrmData); + ASSERT(pSeqParamSet); + + H264SwDecMemset(pSeqParamSet, 0, sizeof(seqParamSet_t)); + + /* profile_idc */ + tmp = h264bsdGetBits(pStrmData, 8); + if (tmp == END_OF_STREAM) + return(HANTRO_NOK); + if (tmp != 66) + { + DEBUG(("NOT BASELINE PROFILE %d\n", tmp)); + } + pSeqParamSet->profileIdc = tmp; + + /* constrained_set0_flag */ + tmp = h264bsdGetBits(pStrmData, 1); + /* constrained_set1_flag */ + tmp = h264bsdGetBits(pStrmData, 1); + /* constrained_set2_flag */ + tmp = h264bsdGetBits(pStrmData, 1); + + if (tmp == END_OF_STREAM) + return(HANTRO_NOK); + + /* reserved_zero_5bits, values of these bits shall be ignored */ + tmp = h264bsdGetBits(pStrmData, 5); + if (tmp == END_OF_STREAM) + return(HANTRO_NOK); + + tmp = h264bsdGetBits(pStrmData, 8); + if (tmp == END_OF_STREAM) + return(HANTRO_NOK); + pSeqParamSet->levelIdc = tmp; + + tmp = h264bsdDecodeExpGolombUnsigned(pStrmData, + &pSeqParamSet->seqParameterSetId); + if (tmp != HANTRO_OK) + return(tmp); + if (pSeqParamSet->seqParameterSetId >= MAX_NUM_SEQ_PARAM_SETS) + { + EPRINT("seq_param_set_id"); + return(HANTRO_NOK); + } + + /* log2_max_frame_num_minus4 */ + tmp = h264bsdDecodeExpGolombUnsigned(pStrmData, &value); + if (tmp != HANTRO_OK) + return(tmp); + if (value > 12) + { + EPRINT("log2_max_frame_num_minus4"); + return(HANTRO_NOK); + } + /* maxFrameNum = 2^(log2_max_frame_num_minus4 + 4) */ + pSeqParamSet->maxFrameNum = 1 << (value+4); + + /* valid POC types are 0, 1 and 2 */ + tmp = h264bsdDecodeExpGolombUnsigned(pStrmData, &value); + if (tmp != HANTRO_OK) + return(tmp); + if (value > 2) + { + EPRINT("pic_order_cnt_type"); + return(HANTRO_NOK); + } + pSeqParamSet->picOrderCntType = value; + + if (pSeqParamSet->picOrderCntType == 0) + { + /* log2_max_pic_order_cnt_lsb_minus4 */ + tmp = h264bsdDecodeExpGolombUnsigned(pStrmData, &value); + if (tmp != HANTRO_OK) + return(tmp); + if (value > 12) + { + EPRINT("log2_max_pic_order_cnt_lsb_minus4"); + return(HANTRO_NOK); + } + /* maxPicOrderCntLsb = 2^(log2_max_pic_order_cnt_lsb_minus4 + 4) */ + pSeqParamSet->maxPicOrderCntLsb = 1 << (value+4); + } + else if (pSeqParamSet->picOrderCntType == 1) + { + tmp = h264bsdGetBits(pStrmData, 1); + if (tmp == END_OF_STREAM) + return(HANTRO_NOK); + pSeqParamSet->deltaPicOrderAlwaysZeroFlag = (tmp == 1) ? + HANTRO_TRUE : HANTRO_FALSE; + + tmp = h264bsdDecodeExpGolombSigned(pStrmData, + &pSeqParamSet->offsetForNonRefPic); + if (tmp != HANTRO_OK) + return(tmp); + + tmp = h264bsdDecodeExpGolombSigned(pStrmData, + &pSeqParamSet->offsetForTopToBottomField); + if (tmp != HANTRO_OK) + return(tmp); + + tmp = h264bsdDecodeExpGolombUnsigned(pStrmData, + &pSeqParamSet->numRefFramesInPicOrderCntCycle); + if (tmp != HANTRO_OK) + return(tmp); + if (pSeqParamSet->numRefFramesInPicOrderCntCycle > 255) + { + EPRINT("num_ref_frames_in_pic_order_cnt_cycle"); + return(HANTRO_NOK); + } + + if (pSeqParamSet->numRefFramesInPicOrderCntCycle) + { + /* NOTE: This has to be freed somewhere! */ + ALLOCATE(pSeqParamSet->offsetForRefFrame, + pSeqParamSet->numRefFramesInPicOrderCntCycle, i32); + if (pSeqParamSet->offsetForRefFrame == NULL) + return(MEMORY_ALLOCATION_ERROR); + + for (i = 0; i < pSeqParamSet->numRefFramesInPicOrderCntCycle; i++) + { + tmp = h264bsdDecodeExpGolombSigned(pStrmData, + pSeqParamSet->offsetForRefFrame + i); + if (tmp != HANTRO_OK) + return(tmp); + } + } + else + { + pSeqParamSet->offsetForRefFrame = NULL; + } + } + + tmp = h264bsdDecodeExpGolombUnsigned(pStrmData, + &pSeqParamSet->numRefFrames); + if (tmp != HANTRO_OK) + return(tmp); + if (pSeqParamSet->numRefFrames > MAX_NUM_REF_PICS) + { + EPRINT("num_ref_frames"); + return(HANTRO_NOK); + } + + tmp = h264bsdGetBits(pStrmData, 1); + if (tmp == END_OF_STREAM) + return(HANTRO_NOK); + pSeqParamSet->gapsInFrameNumValueAllowedFlag = (tmp == 1) ? + HANTRO_TRUE : HANTRO_FALSE; + + tmp = h264bsdDecodeExpGolombUnsigned(pStrmData, &value); + if (tmp != HANTRO_OK) + return(tmp); + pSeqParamSet->picWidthInMbs = value + 1; + + tmp = h264bsdDecodeExpGolombUnsigned(pStrmData, &value); + if (tmp != HANTRO_OK) + return(tmp); + pSeqParamSet->picHeightInMbs = value + 1; + + /* frame_mbs_only_flag, shall be 1 for baseline profile */ + tmp = h264bsdGetBits(pStrmData, 1); + if (tmp == END_OF_STREAM) + return(HANTRO_NOK); + if (!tmp) + { + EPRINT("frame_mbs_only_flag"); + return(HANTRO_NOK); + } + + /* direct_8x8_inference_flag */ + tmp = h264bsdGetBits(pStrmData, 1); + if (tmp == END_OF_STREAM) + return(HANTRO_NOK); + + tmp = h264bsdGetBits(pStrmData, 1); + if (tmp == END_OF_STREAM) + return(HANTRO_NOK); + pSeqParamSet->frameCroppingFlag = (tmp == 1) ? HANTRO_TRUE : HANTRO_FALSE; + + if (pSeqParamSet->frameCroppingFlag) + { + tmp = h264bsdDecodeExpGolombUnsigned(pStrmData, + &pSeqParamSet->frameCropLeftOffset); + if (tmp != HANTRO_OK) + return(tmp); + tmp = h264bsdDecodeExpGolombUnsigned(pStrmData, + &pSeqParamSet->frameCropRightOffset); + if (tmp != HANTRO_OK) + return(tmp); + tmp = h264bsdDecodeExpGolombUnsigned(pStrmData, + &pSeqParamSet->frameCropTopOffset); + if (tmp != HANTRO_OK) + return(tmp); + tmp = h264bsdDecodeExpGolombUnsigned(pStrmData, + &pSeqParamSet->frameCropBottomOffset); + if (tmp != HANTRO_OK) + return(tmp); + + /* check that frame cropping params are valid, parameters shall + * specify non-negative area within the original picture */ + if ( ( (i32)pSeqParamSet->frameCropLeftOffset > + ( 8 * (i32)pSeqParamSet->picWidthInMbs - + ((i32)pSeqParamSet->frameCropRightOffset + 1) ) ) || + ( (i32)pSeqParamSet->frameCropTopOffset > + ( 8 * (i32)pSeqParamSet->picHeightInMbs - + ((i32)pSeqParamSet->frameCropBottomOffset + 1) ) ) ) + { + EPRINT("frame_cropping"); + return(HANTRO_NOK); + } + } + + /* check that image dimensions and levelIdc match */ + tmp = pSeqParamSet->picWidthInMbs * pSeqParamSet->picHeightInMbs; + value = GetDpbSize(tmp, pSeqParamSet->levelIdc); + if (value == INVALID_DPB_SIZE || pSeqParamSet->numRefFrames > value) + { + DEBUG(("WARNING! Invalid DPB size based on SPS Level!\n")); + DEBUG(("WARNING! Using num_ref_frames =%d for DPB size!\n", + pSeqParamSet->numRefFrames)); + value = pSeqParamSet->numRefFrames; + } + pSeqParamSet->maxDpbSize = value; + + tmp = h264bsdGetBits(pStrmData, 1); + if (tmp == END_OF_STREAM) + return(HANTRO_NOK); + pSeqParamSet->vuiParametersPresentFlag = (tmp == 1) ? + HANTRO_TRUE : HANTRO_FALSE; + + /* VUI */ + if (pSeqParamSet->vuiParametersPresentFlag) + { + ALLOCATE(pSeqParamSet->vuiParameters, 1, vuiParameters_t); + if (pSeqParamSet->vuiParameters == NULL) + return(MEMORY_ALLOCATION_ERROR); + tmp = h264bsdDecodeVuiParameters(pStrmData, + pSeqParamSet->vuiParameters); + if (tmp != HANTRO_OK) + return(tmp); + /* check numReorderFrames and maxDecFrameBuffering */ + if (pSeqParamSet->vuiParameters->bitstreamRestrictionFlag) + { + if (pSeqParamSet->vuiParameters->numReorderFrames > + pSeqParamSet->vuiParameters->maxDecFrameBuffering || + pSeqParamSet->vuiParameters->maxDecFrameBuffering < + pSeqParamSet->numRefFrames || + pSeqParamSet->vuiParameters->maxDecFrameBuffering > + pSeqParamSet->maxDpbSize) + { + return(HANTRO_NOK); + } + + /* standard says that "the sequence shall not require a DPB with + * size of more than max(1, maxDecFrameBuffering) */ + pSeqParamSet->maxDpbSize = + MAX(1, pSeqParamSet->vuiParameters->maxDecFrameBuffering); + } + } + + tmp = h264bsdRbspTrailingBits(pStrmData); + + /* ignore possible errors in trailing bits of parameters sets */ + return(HANTRO_OK); + +} + +/*------------------------------------------------------------------------------ + + Function: GetDpbSize + + Functional description: + Get size of the DPB in frames. Size is determined based on the + picture size and MaxDPB for the specified level. These determine + how many pictures may fit into to the buffer. However, the size + is also limited to a maximum of 16 frames and therefore function + returns the minimum of the determined size and 16. + + Inputs: + picSizeInMbs number of macroblocks in the picture + levelIdc indicates the level + + Outputs: + none + + Returns: + size of the DPB in frames + INVALID_DPB_SIZE when invalid levelIdc specified or picSizeInMbs + is higher than supported by the level in question + +------------------------------------------------------------------------------*/ + +u32 GetDpbSize(u32 picSizeInMbs, u32 levelIdc) +{ + +/* Variables */ + + u32 tmp; + u32 maxPicSizeInMbs; + +/* Code */ + + ASSERT(picSizeInMbs); + + /* use tmp as the size of the DPB in bytes, computes as 1024 * MaxDPB + * (from table A-1 in Annex A) */ + switch (levelIdc) + { + case 10: + tmp = 152064; + maxPicSizeInMbs = 99; + break; + + case 11: + tmp = 345600; + maxPicSizeInMbs = 396; + break; + + case 12: + tmp = 912384; + maxPicSizeInMbs = 396; + break; + + case 13: + tmp = 912384; + maxPicSizeInMbs = 396; + break; + + case 20: + tmp = 912384; + maxPicSizeInMbs = 396; + break; + + case 21: + tmp = 1824768; + maxPicSizeInMbs = 792; + break; + + case 22: + tmp = 3110400; + maxPicSizeInMbs = 1620; + break; + + case 30: + tmp = 3110400; + maxPicSizeInMbs = 1620; + break; + + case 31: + tmp = 6912000; + maxPicSizeInMbs = 3600; + break; + + case 32: + tmp = 7864320; + maxPicSizeInMbs = 5120; + break; + + case 40: + tmp = 12582912; + maxPicSizeInMbs = 8192; + break; + + case 41: + tmp = 12582912; + maxPicSizeInMbs = 8192; + break; + + case 42: + tmp = 34816*384; + maxPicSizeInMbs = 8704; + break; + + case 50: + /* standard says 42301440 here, but corrigendum "corrects" this to + * 42393600 */ + tmp = 42393600; + maxPicSizeInMbs = 22080; + break; + + case 51: + tmp = 70778880; + maxPicSizeInMbs = 36864; + break; + + default: + return(INVALID_DPB_SIZE); + } + + /* this is not "correct" return value! However, it results in error in + * decoding and this was easiest place to check picture size */ + if (picSizeInMbs > maxPicSizeInMbs) + return(INVALID_DPB_SIZE); + + tmp /= (picSizeInMbs*384); + + return(MIN(tmp, 16)); + +} + +/*------------------------------------------------------------------------------ + + Function name: h264bsdCompareSeqParamSets + + Functional description: + Compare two sequence parameter sets. + + Inputs: + pSps1 pointer to a sequence parameter set + pSps2 pointer to another sequence parameter set + + Outputs: + 0 sequence parameter sets are equal + 1 otherwise + +------------------------------------------------------------------------------*/ + +u32 h264bsdCompareSeqParamSets(seqParamSet_t *pSps1, seqParamSet_t *pSps2) +{ + +/* Variables */ + + u32 i; + +/* Code */ + + ASSERT(pSps1); + ASSERT(pSps2); + + /* first compare parameters whose existence does not depend on other + * parameters and only compare the rest of the params if these are equal */ + if (pSps1->profileIdc == pSps2->profileIdc && + pSps1->levelIdc == pSps2->levelIdc && + pSps1->maxFrameNum == pSps2->maxFrameNum && + pSps1->picOrderCntType == pSps2->picOrderCntType && + pSps1->numRefFrames == pSps2->numRefFrames && + pSps1->gapsInFrameNumValueAllowedFlag == + pSps2->gapsInFrameNumValueAllowedFlag && + pSps1->picWidthInMbs == pSps2->picWidthInMbs && + pSps1->picHeightInMbs == pSps2->picHeightInMbs && + pSps1->frameCroppingFlag == pSps2->frameCroppingFlag && + pSps1->vuiParametersPresentFlag == pSps2->vuiParametersPresentFlag) + { + if (pSps1->picOrderCntType == 0) + { + if (pSps1->maxPicOrderCntLsb != pSps2->maxPicOrderCntLsb) + return 1; + } + else if (pSps1->picOrderCntType == 1) + { + if (pSps1->deltaPicOrderAlwaysZeroFlag != + pSps2->deltaPicOrderAlwaysZeroFlag || + pSps1->offsetForNonRefPic != pSps2->offsetForNonRefPic || + pSps1->offsetForTopToBottomField != + pSps2->offsetForTopToBottomField || + pSps1->numRefFramesInPicOrderCntCycle != + pSps2->numRefFramesInPicOrderCntCycle) + { + return 1; + } + else + { + for (i = 0; i < pSps1->numRefFramesInPicOrderCntCycle; i++) + if (pSps1->offsetForRefFrame[i] != + pSps2->offsetForRefFrame[i]) + { + return 1; + } + } + } + if (pSps1->frameCroppingFlag) + { + if (pSps1->frameCropLeftOffset != pSps2->frameCropLeftOffset || + pSps1->frameCropRightOffset != pSps2->frameCropRightOffset || + pSps1->frameCropTopOffset != pSps2->frameCropTopOffset || + pSps1->frameCropBottomOffset != pSps2->frameCropBottomOffset) + { + return 1; + } + } + + return 0; + } + + return 1; +} + |