u32 h264bsdDecode(storage_t *pStorage, u8 *byteStrm, u32 len, u32 picId, u32 *readBytes) { /* Variables */ u32 tmp, ppsId, spsId; i32 picOrderCnt; nalUnit_t nalUnit; seqParamSet_t seqParamSet; picParamSet_t picParamSet; strmData_t strm; u32 accessUnitBoundaryFlag = HANTRO_FALSE; u32 picReady = HANTRO_FALSE; /* Code */ /*ASSERT(pStorage); ASSERT(byteStrm); ASSERT(len); ASSERT(readBytes);*/ /* if previous buffer was not finished and same pointer given -> skip NAL * unit extraction */ if (pStorage->prevBufNotFinished && byteStrm == pStorage->prevBufPointer) { strm = pStorage->strm[0]; strm.pStrmCurrPos = strm.pStrmBuffStart; strm.strmBuffReadBits = strm.bitPosInWord = 0; *readBytes = pStorage->prevBytesConsumed; } else { tmp = h264bsdExtractNalUnit(byteStrm, len, &strm, readBytes); if (tmp != HANTRO_OK) { EPRINT("BYTE_STREAM"); return(H264BSD_ERROR); } /* store stream */ pStorage->strm[0] = strm; pStorage->prevBytesConsumed = *readBytes; pStorage->prevBufPointer = byteStrm; } pStorage->prevBufNotFinished = HANTRO_FALSE; tmp = h264bsdDecodeNalUnit(&strm, &nalUnit); if (tmp != HANTRO_OK) { EPRINT("NAL_UNIT"); return(H264BSD_ERROR); } #ifndef SINGLE_SLICE /* Discard unspecified, reserved, SPS extension and auxiliary picture slices */ if(nalUnit.nalUnitType == 0 || nalUnit.nalUnitType >= 13) { DEBUG(("DISCARDED NAL (UNSPECIFIED, REGISTERED, SPS ext or AUX slice)\n")); return(H264BSD_RDY); } tmp = h264bsdCheckAccessUnitBoundary( &strm, &nalUnit, pStorage, &accessUnitBoundaryFlag); if (tmp != HANTRO_OK) { EPRINT("ACCESS UNIT BOUNDARY CHECK"); if (tmp == PARAM_SET_ERROR) return(H264BSD_PARAM_SET_ERROR); else return(H264BSD_ERROR); } if ( accessUnitBoundaryFlag ) { DEBUG(("Access unit boundary\n")); /* conceal if picture started and param sets activated */ if (pStorage->picStarted && pStorage->activeSps != NULL) { DEBUG(("CONCEALING...")); /* return error if second phase of * initialization is not completed */ if (pStorage->pendingActivation) { EPRINT("Pending activation not completed"); return (H264BSD_ERROR); } if (!pStorage->validSliceInAccessUnit) { pStorage->currImage->data = h264bsdAllocateDpbImage(pStorage->dpb); h264bsdInitRefPicList(pStorage->dpb); tmp = h264bsdConceal(pStorage, pStorage->currImage, P_SLICE); } else tmp = h264bsdConceal(pStorage, pStorage->currImage, pStorage->sliceHeader->sliceType); picReady = HANTRO_TRUE; /* current NAL unit should be decoded on next activation -> set * readBytes to 0 */ *readBytes = 0; pStorage->prevBufNotFinished = HANTRO_TRUE; DEBUG(("...DONE\n")); } else { pStorage->validSliceInAccessUnit = HANTRO_FALSE; } pStorage->skipRedundantSlices = HANTRO_FALSE; } #endif if (!picReady) { switch (nalUnit.nalUnitType) { case NAL_SEQ_PARAM_SET: DEBUG(("SEQ PARAM SET\n")); tmp = h264bsdDecodeSeqParamSet(&strm, &seqParamSet); if (tmp != HANTRO_OK) { EPRINT("SEQ_PARAM_SET"); FREE(seqParamSet.offsetForRefFrame); FREE(seqParamSet.vuiParameters); return(H264BSD_ERROR); } tmp = h264bsdStoreSeqParamSet(pStorage, &seqParamSet); break; case NAL_PIC_PARAM_SET: DEBUG(("PIC PARAM SET\n")); tmp = h264bsdDecodePicParamSet(&strm, &picParamSet); if (tmp != HANTRO_OK) { EPRINT("PIC_PARAM_SET"); FREE(picParamSet.runLength); FREE(picParamSet.topLeft); FREE(picParamSet.bottomRight); FREE(picParamSet.sliceGroupId); return(H264BSD_ERROR); } tmp = h264bsdStorePicParamSet(pStorage, &picParamSet); break; case NAL_CODED_SLICE_IDR: DEBUG(("IDR ")); /* fall through */ case NAL_CODED_SLICE: DEBUG(("SLICE HEADER\n")); /* picture successfully finished and still decoding same old * access unit -> no need to decode redundant slices */ if (pStorage->skipRedundantSlices) return(H264BSD_RDY); pStorage->picStarted = HANTRO_TRUE; if (h264bsdIsStartOfPicture(pStorage)) { pStorage->numConcealedMbs = 0; pStorage->currentPicId = picId; tmp = h264bsdCheckPpsId(&strm, &ppsId); ASSERT(tmp == HANTRO_OK); /* store old activeSpsId and return headers ready * indication if activeSps changes */ spsId = pStorage->activeSpsId; tmp = h264bsdActivateParamSets(pStorage, ppsId, IS_IDR_NAL_UNIT(&nalUnit) ? HANTRO_TRUE : HANTRO_FALSE); if (tmp != HANTRO_OK) { EPRINT("Param set activation"); pStorage->activePpsId = MAX_NUM_PIC_PARAM_SETS; pStorage->activePps = NULL; pStorage->activeSpsId = MAX_NUM_SEQ_PARAM_SETS; pStorage->activeSps = NULL; pStorage->pendingActivation = HANTRO_FALSE; if(tmp == MEMORY_ALLOCATION_ERROR) { return H264BSD_MEMALLOC_ERROR; } else return(H264BSD_PARAM_SET_ERROR); } if (spsId != pStorage->activeSpsId) { seqParamSet_t *oldSPS = NULL; seqParamSet_t *newSPS = pStorage->activeSps; u32 noOutputOfPriorPicsFlag = 1; if(pStorage->oldSpsId < MAX_NUM_SEQ_PARAM_SETS) { oldSPS = pStorage->sps[pStorage->oldSpsId]; } *readBytes = 0; pStorage->prevBufNotFinished = HANTRO_TRUE; if(nalUnit.nalUnitType == NAL_CODED_SLICE_IDR) { tmp = h264bsdCheckPriorPicsFlag(&noOutputOfPriorPicsFlag, &strm, newSPS, pStorage->activePps, nalUnit.nalUnitType); } else { tmp = HANTRO_NOK; } if((tmp != HANTRO_OK) || (noOutputOfPriorPicsFlag != 0) || (pStorage->dpb->noReordering) || (oldSPS == NULL) || (oldSPS->picWidthInMbs != newSPS->picWidthInMbs) || (oldSPS->picHeightInMbs != newSPS->picHeightInMbs) || (oldSPS->maxDpbSize != newSPS->maxDpbSize)) { pStorage->dpb->flushed = 0; } else { h264bsdFlushDpb(pStorage->dpb); } pStorage->oldSpsId = pStorage->activeSpsId; return(H264BSD_HDRS_RDY); } } /* return error if second phase of * initialization is not completed */ if (pStorage->pendingActivation) { EPRINT("Pending activation not completed"); return (H264BSD_ERROR); } tmp = h264bsdDecodeSliceHeader(&strm, pStorage->sliceHeader + 1, pStorage->activeSps, pStorage->activePps, &nalUnit); if (tmp != HANTRO_OK) { EPRINT("SLICE_HEADER"); return(H264BSD_ERROR); } if (h264bsdIsStartOfPicture(pStorage)) { if (!IS_IDR_NAL_UNIT(&nalUnit)) { tmp = h264bsdCheckGapsInFrameNum(pStorage->dpb, pStorage->sliceHeader[1].frameNum, nalUnit.nalRefIdc != 0 ? HANTRO_TRUE : HANTRO_FALSE, pStorage->activeSps-> gapsInFrameNumValueAllowedFlag); if (tmp != HANTRO_OK) { EPRINT("Gaps in frame num"); return(H264BSD_ERROR); } } pStorage->currImage->data = h264bsdAllocateDpbImage(pStorage->dpb); } /* store slice header to storage if successfully decoded */ pStorage->sliceHeader[0] = pStorage->sliceHeader[1]; pStorage->validSliceInAccessUnit = HANTRO_TRUE; pStorage->prevNalUnit[0] = nalUnit; h264bsdComputeSliceGroupMap(pStorage, pStorage->sliceHeader->sliceGroupChangeCycle); h264bsdInitRefPicList(pStorage->dpb); tmp = h264bsdReorderRefPicList(pStorage->dpb, &pStorage->sliceHeader->refPicListReordering, pStorage->sliceHeader->frameNum, pStorage->sliceHeader->numRefIdxL0Active); if (tmp != HANTRO_OK) { EPRINT("Reordering"); return(H264BSD_ERROR); } DEBUG(("SLICE DATA, FIRST %d\n", pStorage->sliceHeader->firstMbInSlice)); tmp = h264bsdDecodeSliceData(&strm, pStorage, pStorage->currImage, pStorage->sliceHeader); // in single slice mode every slice is a ready picture #ifndef SINGLE_SLICE if (tmp != HANTRO_OK) { EPRINT("SLICE_DATA"); h264bsdMarkSliceCorrupted(pStorage, pStorage->sliceHeader->firstMbInSlice); return(H264BSD_ERROR); }; if (h264bsdIsEndOfPicture(pStorage)) { #endif picReady = HANTRO_TRUE; #ifndef SINGLE_SLICE pStorage->skipRedundantSlices = HANTRO_TRUE; }; #endif break; case NAL_SEI: DEBUG(("SEI MESSAGE, NOT DECODED")); break; default: DEBUG(("NOT IMPLEMENTED YET %d\n",nalUnit.nalUnitType)); } } if (picReady) { h264bsdFilterPicture(pStorage->currImage, pStorage->mb); #ifdef EMIT_IMAGE_ASAP /*if (gLastSlice == 1){ h264bsdWriteSliceMbData( pStorage->currImage, pStorage->sliceHeader->firstMbInSlice, (pStorage->currImage->width * pStorage->currImage->height) - 1, sliceData ); }else{*/ h264bsdWriteSliceMbData( pStorage->currImage, pStorage->sliceHeader->firstMbInSlice, pStorage->sliceHeader->firstMbInSlice + pStorage->slice->numDecodedMbs - 1, sliceData ); //}; //sliceData[18] = pStorage->sliceHeader->firstMbInSlice; //sliceData[19] = pStorage->sliceHeader->firstMbInSlice + pStorage->slice->numDecodedMbs - 1; extern_emit_image( pStorage->currImage->data, pStorage->currImage->width * 16, pStorage->currImage->height * 16, sliceData ); #endif h264bsdResetStorage(pStorage); picOrderCnt = h264bsdDecodePicOrderCnt(pStorage->poc, pStorage->activeSps, pStorage->sliceHeader, pStorage->prevNalUnit); if (pStorage->validSliceInAccessUnit) { if (pStorage->prevNalUnit->nalRefIdc) { tmp = h264bsdMarkDecRefPic(pStorage->dpb, &pStorage->sliceHeader->decRefPicMarking, pStorage->currImage, pStorage->sliceHeader->frameNum, picOrderCnt, IS_IDR_NAL_UNIT(pStorage->prevNalUnit) ? HANTRO_TRUE : HANTRO_FALSE, pStorage->currentPicId, pStorage->numConcealedMbs); } /* non-reference picture, just store for possible display * reordering */ else { tmp = h264bsdMarkDecRefPic(pStorage->dpb, NULL, pStorage->currImage, pStorage->sliceHeader->frameNum, picOrderCnt, IS_IDR_NAL_UNIT(pStorage->prevNalUnit) ? HANTRO_TRUE : HANTRO_FALSE, pStorage->currentPicId, pStorage->numConcealedMbs); } } pStorage->picStarted = HANTRO_FALSE; pStorage->validSliceInAccessUnit = HANTRO_FALSE; return(H264BSD_PIC_RDY); } else return(H264BSD_RDY); }
u32 h264bsdDecodeSliceHeader(strmData_t *pStrmData, sliceHeader_t *pSliceHeader, seqParamSet_t *pSeqParamSet, picParamSet_t *pPicParamSet, nalUnit_t *pNalUnit) { /* Variables */ u32 tmp, i, value; i32 itmp; u32 picSizeInMbs; /* Code */ ASSERT(pStrmData); ASSERT(pSliceHeader); ASSERT(pSeqParamSet); ASSERT(pPicParamSet); ASSERT( pNalUnit->nalUnitType == NAL_CODED_SLICE || pNalUnit->nalUnitType == NAL_CODED_SLICE_IDR ); H264SwDecMemset(pSliceHeader, 0, sizeof(sliceHeader_t)); picSizeInMbs = pSeqParamSet->picWidthInMbs * pSeqParamSet->picHeightInMbs; tmp = h264bsdDecodeExpGolombUnsigned(pStrmData, &value); if (tmp != HANTRO_OK) return(tmp); pSliceHeader->firstMbInSlice = value; if (value >= picSizeInMbs) { EPRINT("first_mb_in_slice"); return(HANTRO_NOK); } tmp = h264bsdDecodeExpGolombUnsigned(pStrmData, &value); if (tmp != HANTRO_OK) return(tmp); pSliceHeader->sliceType = value; /* slice type has to be either I or P slice. P slice is not allowed when * current NAL unit is an IDR NAL unit or num_ref_frames is 0 */ if ( !IS_I_SLICE(pSliceHeader->sliceType) && ( !IS_P_SLICE(pSliceHeader->sliceType) || IS_IDR_NAL_UNIT(pNalUnit) || !pSeqParamSet->numRefFrames ) ) { EPRINT("slice_type"); return(HANTRO_NOK); } tmp = h264bsdDecodeExpGolombUnsigned(pStrmData, &value); if (tmp != HANTRO_OK) return(tmp); pSliceHeader->picParameterSetId = value; if (pSliceHeader->picParameterSetId != pPicParamSet->picParameterSetId) { EPRINT("pic_parameter_set_id"); return(HANTRO_NOK); } /* log2(maxFrameNum) -> num bits to represent frame_num */ i = 0; while (pSeqParamSet->maxFrameNum >> i) i++; i--; tmp = h264bsdGetBits(pStrmData, i); if (tmp == END_OF_STREAM) return(HANTRO_NOK); if (IS_IDR_NAL_UNIT(pNalUnit) && tmp != 0) { EPRINT("frame_num"); return(HANTRO_NOK); } pSliceHeader->frameNum = tmp; if (IS_IDR_NAL_UNIT(pNalUnit)) { tmp = h264bsdDecodeExpGolombUnsigned(pStrmData, &value); if (tmp != HANTRO_OK) return(tmp); pSliceHeader->idrPicId = value; if (value > 65535) { EPRINT("idr_pic_id"); return(HANTRO_NOK); } } if (pSeqParamSet->picOrderCntType == 0) { /* log2(maxPicOrderCntLsb) -> num bits to represent pic_order_cnt_lsb */ i = 0; while (pSeqParamSet->maxPicOrderCntLsb >> i) i++; i--; tmp = h264bsdGetBits(pStrmData, i); if (tmp == END_OF_STREAM) return(HANTRO_NOK); pSliceHeader->picOrderCntLsb = tmp; if (pPicParamSet->picOrderPresentFlag) { tmp = h264bsdDecodeExpGolombSigned(pStrmData, &itmp); if (tmp != HANTRO_OK) return(tmp); pSliceHeader->deltaPicOrderCntBottom = itmp; } /* check that picOrderCnt for IDR picture will be zero. See * DecodePicOrderCnt function to understand the logic here */ if ( IS_IDR_NAL_UNIT(pNalUnit) && ( (pSliceHeader->picOrderCntLsb > pSeqParamSet->maxPicOrderCntLsb/2) || MIN((i32)pSliceHeader->picOrderCntLsb, (i32)pSliceHeader->picOrderCntLsb + pSliceHeader->deltaPicOrderCntBottom) != 0 ) ) { return(HANTRO_NOK); } }
/*------------------------------------------------------------------------------ Function: h264bsdDecodeVlc Functional description: Decode a NAL unit until a slice header. This function calls other modules to perform tasks like * extract and decode NAL unit from the byte stream * decode parameter sets * decode slice header and slice data * conceal errors in the picture * perform deblocking filtering This function contains top level control logic of the decoder. Inputs: pStorage pointer to storage data structure byteStrm pointer to stream buffer given by application len length of the buffer in bytes picId identifier for a picture, assigned by the application Outputs: readBytes number of bytes read from the stream is stored here Returns: H264BSD_RDY decoding finished, nothing special H264BSD_PIC_RDY decoding of a picture finished H264BSD_HDRS_RDY param sets activated, information like picture dimensions etc can be read H264BSD_ERROR error in decoding H264BSD_PARAM_SET_ERROR serius error in decoding, failed to activate param sets ------------------------------------------------------------------------------*/ u32 h264bsdDecode(decContainer_t * pDecCont, const u8 * byteStrm, u32 len, u32 picId, u32 * readBytes) { /* Variables */ u32 tmp, ppsId, spsId; u32 accessUnitBoundaryFlag = HANTRO_FALSE; u32 picReady = HANTRO_FALSE; storage_t *pStorage; nalUnit_t nalUnit; seqParamSet_t seqParamSet; picParamSet_t picParamSet; strmData_t strm; u32 ret = 0; DEBUG_PRINT(("h264bsdDecode\n")); /* Code */ ASSERT(pDecCont); ASSERT(byteStrm); ASSERT(len); ASSERT(readBytes); pStorage = &pDecCont->storage; ASSERT(pStorage); DEBUG_PRINT(("Valid slice in access unit %d\n", pStorage->validSliceInAccessUnit)); if(pDecCont->rlcMode) { pStorage->strm[0].removeEmul3Byte = 1; strm.removeEmul3Byte = 1; } else { pStorage->strm[0].removeEmul3Byte = 0; strm.removeEmul3Byte = 0; } /* if previous buffer was not finished and same pointer given -> skip NAL * unit extraction */ if(pStorage->prevBufNotFinished && byteStrm == pStorage->prevBufPointer) { strm = pStorage->strm[0]; strm.pStrmCurrPos = strm.pStrmBuffStart; strm.strmBuffReadBits = strm.bitPosInWord = 0; *readBytes = pStorage->prevBytesConsumed; } else { tmp = h264bsdExtractNalUnit(byteStrm, len, &strm, readBytes, pDecCont->rlcMode); if(tmp != HANTRO_OK) { ERROR_PRINT("BYTE_STREAM"); return (H264BSD_ERROR); } /* store stream */ pStorage->strm[0] = strm; pStorage->prevBytesConsumed = *readBytes; pStorage->prevBufPointer = byteStrm; } pStorage->prevBufNotFinished = HANTRO_FALSE; tmp = h264bsdDecodeNalUnit(&strm, &nalUnit); if(tmp != HANTRO_OK) { ret = H264BSD_ERROR; goto NEXT_NAL; } /* Discard unspecified, reserved, SPS extension and auxiliary picture slices */ if(nalUnit.nalUnitType == 0 || (nalUnit.nalUnitType >= 13 && (pStorage->mvc == 0 || (nalUnit.nalUnitType != 14 && nalUnit.nalUnitType != 15 && nalUnit.nalUnitType != 20)))) { DEBUG_PRINT(("DISCARDED NAL (UNSPECIFIED, REGISTERED, SPS ext or AUX slice)\n")); ret = H264BSD_RDY; goto NEXT_NAL; } if(pDecCont->skipNonReference && nalUnit.nalRefIdc == 0 ) { DEBUG_PRINT(("DISCARDED NAL (NON-REFERENCE PICTURE)\n")); ret = H264BSD_NONREF_PIC_SKIPPED; goto NEXT_NAL; } if(!pStorage->checkedAub) { pStorage->aub->prevModFrameNum = pStorage->aub->prevFrameNum & ~pDecCont->frameNumMask; tmp = h264bsdCheckAccessUnitBoundary(&strm, &nalUnit, pStorage, &accessUnitBoundaryFlag); if(tmp != HANTRO_OK) { ERROR_PRINT("ACCESS UNIT BOUNDARY CHECK"); if(tmp == PARAM_SET_ERROR) ret = (H264BSD_PARAM_SET_ERROR); else ret = (H264BSD_ERROR); goto NEXT_NAL; } } else { pStorage->checkedAub = 0; } if(accessUnitBoundaryFlag) { DEBUG_PRINT(("Access unit boundary, NAL TYPE %d\n", nalUnit.nalUnitType)); /* conceal if picture started and param sets activated */ if(pStorage->picStarted && pStorage->activeSps != NULL) { if(pDecCont->rlcMode) /* Error conceal in RLC mode */ { DecAsicBuffers_t *pAsicBuff = pDecCont->asicBuff; ASSERT(pAsicBuff); ASSERT(pAsicBuff->mbCtrl.virtualAddress); DEBUG_PRINT(("CONCEALING...")); if(!pStorage->validSliceInAccessUnit) { DEBUG_PRINT(("!validSliceunit\n")); pStorage->currImage->data = h264bsdAllocateDpbImage(pStorage->dpb); h264bsdInitRefPicList(pStorage->dpb); h264bsdConceal(pStorage, pAsicBuff, P_SLICE); } else { DEBUG_PRINT(("validSliceunit\n")); h264bsdConceal(pStorage, pAsicBuff, pStorage->sliceHeader->sliceType); } picReady = HANTRO_TRUE; /* current NAL unit should be decoded on next activation -> set * readBytes to 0 */ *readBytes = 0; pStorage->prevBufNotFinished = HANTRO_TRUE; DEBUG_PRINT(("...DONE\n")); } else /* VLC mode */ { DEBUG_PRINT(("New access unit and previous not finished\n")); DEBUG_PRINT(("PICTURE FREEZE CONCEAL...\n")); if(!pStorage->validSliceInAccessUnit) { DEBUG_PRINT(("!validSliceunit\n")); if (!pStorage->view && !pStorage->secondField) { pStorage->currImage->data = h264bsdAllocateDpbImage(pStorage->dpb); pStorage->sliceHeader->fieldPicFlag = 0; } else if (pStorage->view) { pStorage->validSliceInAccessUnit = 1; if (!pStorage->baseOppositeFieldPic) { pStorage->currImage->data = h264bsdAllocateDpbImage(pStorage->dpb); } else { pStorage->baseOppositeFieldPic = 0; pStorage->currImage->data = pStorage->dpb->currentOut->data; } pStorage->sliceHeader = pStorage->sliceHeaders[0]; } h264bsdInitRefPicList(pStorage->dpb); } pStorage->skipRedundantSlices = HANTRO_FALSE; /* current NAL unit should be decoded on next activation -> set * readBytes to 0 */ *readBytes = 0; pStorage->prevBufNotFinished = HANTRO_TRUE; DEBUG_PRINT(("...DONE\n")); return (H264BSD_NEW_ACCESS_UNIT); } } else { DEBUG_PRINT(("vali slice false\n")); pStorage->validSliceInAccessUnit = HANTRO_FALSE; } pStorage->skipRedundantSlices = HANTRO_FALSE; } if(!picReady) { DEBUG_PRINT(("nal unit type: %d\n", nalUnit.nalUnitType)); switch (nalUnit.nalUnitType) { case NAL_SEQ_PARAM_SET: case NAL_SUBSET_SEQ_PARAM_SET: DEBUG_PRINT(("SEQ PARAM SET\n")); tmp = h264bsdDecodeSeqParamSet(&strm, &seqParamSet, nalUnit.nalUnitType == NAL_SEQ_PARAM_SET ? 0 : 1); if(tmp != HANTRO_OK) { ERROR_PRINT("SEQ_PARAM_SET decoding"); FREE(seqParamSet.offsetForRefFrame); FREE(seqParamSet.vuiParameters); ret = H264BSD_ERROR; } else { tmp = h264bsdStoreSeqParamSet(pStorage, &seqParamSet); if(tmp != HANTRO_OK) { ERROR_PRINT("SEQ_PARAM_SET allocation"); ret = H264BSD_ERROR; } if (nalUnit.nalUnitType == NAL_SUBSET_SEQ_PARAM_SET) { pStorage->viewId[0] = seqParamSet.mvc.viewId[0]; pStorage->viewId[1] = seqParamSet.mvc.viewId[1]; } } ret = H264BSD_RDY; goto NEXT_NAL; case NAL_PIC_PARAM_SET: DEBUG_PRINT(("PIC PARAM SET\n")); tmp = h264bsdDecodePicParamSet(&strm, &picParamSet); if(tmp != HANTRO_OK) { ERROR_PRINT("PIC_PARAM_SET decoding"); FREE(picParamSet.runLength); FREE(picParamSet.topLeft); FREE(picParamSet.bottomRight); FREE(picParamSet.sliceGroupId); ret = H264BSD_ERROR; } else { tmp = h264bsdStorePicParamSet(pStorage, &picParamSet); if(tmp != HANTRO_OK) { ERROR_PRINT("PIC_PARAM_SET allocation"); ret = H264BSD_ERROR; } } ret = H264BSD_RDY; goto NEXT_NAL; case NAL_CODED_SLICE_IDR: DEBUG_PRINT(("IDR ")); /* fall through */ case NAL_CODED_SLICE: case NAL_CODED_SLICE_EXT: DEBUG_PRINT(("decode slice header\n")); if (nalUnit.nalUnitType == NAL_CODED_SLICE_EXT) { /* base not yet initialized -> skip */ if (pStorage->activeViewSps[0] == NULL) goto NEXT_NAL; pStorage->view = 1; /* view_id not equal to view_id of the 1. non-base view or * base view picture missing -> skip */ if (nalUnit.viewId != pStorage->viewId[pStorage->view] || (pStorage->numViews && pStorage->nextView == 0)) { goto NEXT_NAL; } } else pStorage->view = 0; /* base view detected, but stereo expected -> go back and freeze * previous stereo view picture */ if (pStorage->view == 0 && pStorage->numViews && pStorage->nextView != 0 && pStorage->activeViewSps[0]) { *readBytes = 0; pStorage->prevBufNotFinished = HANTRO_TRUE; pStorage->view = 1; pStorage->dpb = pStorage->dpbs[pStorage->view]; pStorage->validSliceInAccessUnit = 1; if (!pStorage->baseOppositeFieldPic) { pStorage->currImage->data = h264bsdAllocateDpbImage(pStorage->dpb); } else { pStorage->baseOppositeFieldPic = 0; pStorage->currImage->data = pStorage->dpb->currentOut->data; } h264bsdInitRefPicList(pStorage->dpb); return (H264BSD_NEW_ACCESS_UNIT); } /* picture successfully finished and still decoding same old * access unit -> no need to decode redundant slices */ if(pStorage->skipRedundantSlices) { DEBUG_PRINT(("skipping redundant slice\n")); ret = H264BSD_RDY; goto NEXT_NAL; } pStorage->picStarted = HANTRO_TRUE; if(h264bsdIsStartOfPicture(pStorage)) { pStorage->numConcealedMbs = 0; pStorage->currentPicId = picId; tmp = h264bsdCheckPpsId(&strm, &ppsId); ASSERT(tmp == HANTRO_OK); /* store old activeSpsId and return headers ready * indication if activeSps changes */ spsId = pStorage->activeViewSpsId[pStorage->view]; tmp = h264bsdActivateParamSets(pStorage, ppsId, IS_IDR_NAL_UNIT(&nalUnit) ? HANTRO_TRUE : HANTRO_FALSE); if(tmp != HANTRO_OK || pStorage->activeSps == NULL || pStorage->activePps == NULL) { ERROR_PRINT("Param set activation"); ret = H264BSD_PARAM_SET_ERROR; if (pStorage->view && pStorage->activeSps == NULL) pStorage->numViews = 0; goto NEXT_NAL; } if(spsId != pStorage->activeSpsId) { seqParamSet_t *oldSPS = NULL; seqParamSet_t *newSPS = pStorage->activeSps; u32 noOutputOfPriorPicsFlag = 1; if(pStorage->oldSpsId < MAX_NUM_SEQ_PARAM_SETS) { oldSPS = pStorage->sps[pStorage->oldSpsId]; } *readBytes = 0; pStorage->prevBufNotFinished = HANTRO_TRUE; if(IS_IDR_NAL_UNIT(&nalUnit)) { tmp = h264bsdCheckPriorPicsFlag(&noOutputOfPriorPicsFlag, &strm, newSPS, pStorage->activePps, NAL_CODED_SLICE_IDR); /*nalUnit.nalUnitType);*/ } else { tmp = HANTRO_NOK; } if((tmp != HANTRO_OK) || (noOutputOfPriorPicsFlag != 0) || (pStorage->dpb->noReordering) || (oldSPS == NULL) || (oldSPS->picWidthInMbs != newSPS->picWidthInMbs) || (oldSPS->picHeightInMbs != newSPS->picHeightInMbs) || (oldSPS->maxDpbSize != newSPS->maxDpbSize)) { pStorage->dpb->flushed = 0; } else { h264bsdFlushDpb(pStorage->dpb); } pStorage->oldSpsId = pStorage->activeSpsId; pStorage->picStarted = HANTRO_FALSE; return (H264BSD_HDRS_RDY); } if(pStorage->activePps->numSliceGroups != 1 && !pDecCont->rlcMode) { pDecCont->reallocate = 1; pDecCont->tryVlc = 0; pStorage->picStarted = HANTRO_FALSE; *readBytes = 0; return (H264BSD_FMO); } if(pStorage->activePps->numSliceGroups == 1 && pDecCont->rlcMode && !pStorage->asoDetected) { if(pDecCont->forceRlcMode) pDecCont->tryVlc = 0; else { DEBUG_PRINT(("h264bsdDecode: no FMO/ASO detected, switch to VLC\n")); pDecCont->tryVlc = 1; /* we have removed emulation prevevention 3B from stream, * cannot go to VLC for this frame; but try the * next one */ /* pDecCont->rlcMode = 0; */ } } } tmp = h264bsdDecodeSliceHeader(&strm, pStorage->sliceHeader + 1, pStorage->activeSps, pStorage->activePps, &nalUnit); if(tmp != HANTRO_OK) { ERROR_PRINT("SLICE_HEADER"); ret = H264BSD_ERROR; goto NEXT_NAL; } if(h264bsdIsStartOfPicture(pStorage)) { /* stereo view picture, non-matching field pic flag or bottom * field flag -> freeze previous stereo view frame of field * (frame/field and top/bottom info from base view) */ if (pStorage->view && ((pStorage->sliceHeader[1].fieldPicFlag != pStorage->sliceHeaders[0][1].fieldPicFlag) || (pStorage->sliceHeader[1].bottomFieldFlag != pStorage->sliceHeaders[0][1].bottomFieldFlag))) { pStorage->validSliceInAccessUnit = 1; pStorage->sliceHeader = pStorage->sliceHeaders[0]; if (!pStorage->baseOppositeFieldPic) { pStorage->currImage->data = h264bsdAllocateDpbImage(pStorage->dpb); } else { pStorage->currImage->data = pStorage->dpb->currentOut->data; } h264bsdInitRefPicList(pStorage->dpb); return (H264BSD_NEW_ACCESS_UNIT); } tmp = pStorage->secondField; if(pStorage->view ? pStorage->baseOppositeFieldPic : (pStorage->baseOppositeFieldPic = h264bsdIsOppositeFieldPic(pStorage->sliceHeader + 1, pStorage->sliceHeader + 0, &pStorage->secondField, pStorage->dpb->prevRefFrameNum, pStorage->aub->newPicture))) { /* TODO: make sure that currentOut->status[field] is * EMPTY */ if(pStorage->dpb->delayedOut != 0) { /* we delayed the output while waiting for second field */ pStorage->dpb->outBuf[pStorage->dpb->delayedId].fieldPicture = 0; /* mark both fields available */ DEBUG_PRINT(("Second field coming...\n")); } pStorage->currImage->data = pStorage->dpb->currentOut->data; } else { if(pStorage->dpb->delayedOut != 0 || /* missing field and PP running */ ((pStorage->numViews == 0 ? tmp : (pStorage->sliceHeader->fieldPicFlag && pStorage->view == 0)) && pDecCont->pp.decPpIf.ppStatus == DECPP_PIC_NOT_FINISHED)) { pStorage->secondField = 0; DEBUG_PRINT(("Second field missing...Output delayed stuff\n")); *readBytes = 0; pStorage->prevBufNotFinished = HANTRO_TRUE; pStorage->dpb->delayedOut = 0; pStorage->checkedAub = 1; return (H264BSD_UNPAIRED_FIELD); } if(!IS_IDR_NAL_UNIT(&nalUnit) && !pDecCont->modeChange && !pDecCont->gapsCheckedForThis) { DEBUG_PRINT(("Check gaps in frame num; mode change %d\n", pDecCont->modeChange)); tmp = h264bsdCheckGapsInFrameNum(pStorage->dpb, pStorage-> sliceHeader[1]. frameNum, nalUnit.nalRefIdc != 0 ? HANTRO_TRUE : HANTRO_FALSE, pStorage->activeSps-> gapsInFrameNumValueAllowedFlag); pDecCont->gapsCheckedForThis = HANTRO_TRUE; if(tmp != HANTRO_OK) { pDecCont->gapsCheckedForThis = HANTRO_FALSE; ERROR_PRINT("Gaps in frame num"); ret = H264BSD_ERROR; goto NEXT_NAL; } } pStorage->currImage->data = h264bsdAllocateDpbImage(pStorage->dpb); #ifdef SET_EMPTY_PICTURE_DATA /* USE THIS ONLY FOR DEBUGGING PURPOSES */ { i32 bgd = SET_EMPTY_PICTURE_DATA; DWLmemset(pStorage->currImage->data->virtualAddress, bgd, pStorage->currImage->data->size); } #endif } } else { if(!pDecCont->rlcMode && pStorage->sliceHeader[1].redundantPicCnt != 0) { ret = H264BSD_RDY; goto NEXT_NAL; } } DEBUG_PRINT(("vali slice TRUE\n")); /* store slice header to storage if successfully decoded */ pStorage->sliceHeader[0] = pStorage->sliceHeader[1]; pStorage->validSliceInAccessUnit = HANTRO_TRUE; pStorage->prevNalUnit[0] = nalUnit; if(IS_B_SLICE(pStorage->sliceHeader[1].sliceType)) { if((pDecCont->h264ProfileSupport == H264_BASELINE_PROFILE) || (pDecCont->rlcMode != 0)) { ERROR_PRINT("B_SLICE not allowed in baseline decoder"); ret = H264BSD_ERROR; goto NEXT_NAL; } if(pDecCont->asicBuff->enableDmvAndPoc == 0) { DEBUG_PRINT(("B_SLICE in baseline stream!!! DMV and POC writing were not enabled!")); DEBUG_PRINT(("B_SLICE decoding will not be accurate for a while!")); /* enable DMV and POC writing */ pDecCont->asicBuff->enableDmvAndPoc = 1; } } /* For VLC mode, end SW decode here */ if(!pDecCont->rlcMode) { DEBUG_PRINT(("\tVLC mode! Skip slice data decoding\n")); if(pDecCont->is8190 == 0) { h264bsdInitRefPicList(pStorage->dpb); } SetPicNums(pStorage->dpb, pStorage->sliceHeader->frameNum); return (H264BSD_PIC_RDY); } /* TODO pitäskö siirtää pelkästään rlc moodille, note that * SetPicNums called only inside h264bsdReorderRefPicList() */ h264bsdInitRefPicList(pStorage->dpb); tmp = h264bsdReorderRefPicList(pStorage->dpb, &pStorage->sliceHeader-> refPicListReordering, pStorage->sliceHeader->frameNum, pStorage->sliceHeader-> numRefIdxL0Active); if(tmp != HANTRO_OK) { ERROR_PRINT("h264bsdReorderRefPicList failed\n"); ret = H264BSD_ERROR; goto NEXT_NAL; } h264bsdComputeSliceGroupMap(pStorage, pStorage->sliceHeader-> sliceGroupChangeCycle); tmp = h264bsdDecodeSliceData(pDecCont, &strm, pStorage->sliceHeader); if(tmp != HANTRO_OK) { h264bsdMarkSliceCorrupted(pStorage, pStorage->sliceHeader-> firstMbInSlice); return (H264BSD_ERROR); } if(h264bsdIsEndOfPicture(pStorage)) { picReady = HANTRO_TRUE; DEBUG_PRINT(("Skip redundant RLC\n")); pStorage->skipRedundantSlices = HANTRO_TRUE; } break; case NAL_SEI: DEBUG_PRINT(("SEI MESSAGE, NOT DECODED\n")); ret = H264BSD_RDY; goto NEXT_NAL; case NAL_END_OF_SEQUENCE: DEBUG_PRINT(("END_OF_SEQUENCE, NOT DECODED\n")); ret = H264BSD_RDY; goto NEXT_NAL; case NAL_END_OF_STREAM: DEBUG_PRINT(("END_OF_STREAM, NOT DECODED\n")); ret = H264BSD_RDY; goto NEXT_NAL; case NAL_PREFIX: pStorage->view = 0; pStorage->nonInterViewRef = nalUnit.interViewFlag == 0; /* set flag to indicate that this is probably mvc stream, affects * base layer param set activation */ pStorage->mvcStream = pStorage->mvc; goto NEXT_NAL; default: DEBUG_PRINT(("NOT IMPLEMENTED YET %d\n", nalUnit.nalUnitType)); ret = H264BSD_RDY; goto NEXT_NAL; } } if(picReady) { return (H264BSD_PIC_RDY); } else return (H264BSD_RDY); NEXT_NAL: if(!pDecCont->rlcMode) { const u8 *next = h264bsdFindNextStartCode(strm.pStrmBuffStart, strm.strmBuffSize); if(next != NULL) { *readBytes = (u32) (next - byteStrm); pStorage->prevBytesConsumed = *readBytes; } } return ret; }
i32 h264bsdDecodePicOrderCnt(pocStorage_t *poc, seqParamSet_t *sps, sliceHeader_t *pSliceHeader, nalUnit_t *pNalUnit) { /* Variables */ u32 i; i32 picOrderCnt; u32 frameNumOffset, absFrameNum, picOrderCntCycleCnt; u32 frameNumInPicOrderCntCycle; i32 expectedDeltaPicOrderCntCycle; u32 containsMmco5; /* Code */ ASSERT(poc); ASSERT(sps); ASSERT(pSliceHeader); ASSERT(pNalUnit); ASSERT(sps->picOrderCntType <= 2); #if 0 /* JanSa: I don't think this is necessary, don't see any reason to * increment prevFrameNum one by one instead of one big increment. * However, standard specifies that this should be done -> if someone * figures out any case when the outcome would be different for step by * step increment, this part of the code should be enabled */ /* if there was a gap in frame numbering and picOrderCntType is 1 or 2 -> * "compute" pic order counts for non-existing frames. These are not * actually computed, but process needs to be done to update the * prevFrameNum and prevFrameNumOffset */ if ( sps->picOrderCntType > 0 && pSliceHeader->frameNum != poc->prevFrameNum && pSliceHeader->frameNum != ((poc->prevFrameNum + 1) % sps->maxFrameNum)) { /* use variable i for unUsedShortTermFrameNum */ i = (poc->prevFrameNum + 1) % sps->maxFrameNum; do { if (poc->prevFrameNum > i) frameNumOffset = poc->prevFrameNumOffset + sps->maxFrameNum; else frameNumOffset = poc->prevFrameNumOffset; poc->prevFrameNumOffset = frameNumOffset; poc->prevFrameNum = i; i = (i + 1) % sps->maxFrameNum; } while (i != pSliceHeader->frameNum); } #endif /* check if current slice includes mmco equal to 5 */ containsMmco5 = HANTRO_FALSE; if (pSliceHeader->decRefPicMarking.adaptiveRefPicMarkingModeFlag) { i = 0; while (pSliceHeader->decRefPicMarking.operation[i]. memoryManagementControlOperation) { if (pSliceHeader->decRefPicMarking.operation[i]. memoryManagementControlOperation == 5) { containsMmco5 = HANTRO_TRUE; break; } i++; } } switch (sps->picOrderCntType) { case 0: /* set prevPicOrderCnt values for IDR frame */ if (IS_IDR_NAL_UNIT(pNalUnit)) { poc->prevPicOrderCntMsb = 0; poc->prevPicOrderCntLsb = 0; } /* compute picOrderCntMsb (stored in picOrderCnt variable) */ if ( (pSliceHeader->picOrderCntLsb < poc->prevPicOrderCntLsb) && ((poc->prevPicOrderCntLsb - pSliceHeader->picOrderCntLsb) >= sps->maxPicOrderCntLsb/2) ) { picOrderCnt = poc->prevPicOrderCntMsb + (i32)sps->maxPicOrderCntLsb; } else if ((pSliceHeader->picOrderCntLsb > poc->prevPicOrderCntLsb) && ((pSliceHeader->picOrderCntLsb - poc->prevPicOrderCntLsb) > sps->maxPicOrderCntLsb/2) ) { picOrderCnt = poc->prevPicOrderCntMsb - (i32)sps->maxPicOrderCntLsb; } else picOrderCnt = poc->prevPicOrderCntMsb; /* standard specifies that prevPicOrderCntMsb is from previous * rererence frame -> replace old value only if current frame is * rererence frame */ if (pNalUnit->nalRefIdc) poc->prevPicOrderCntMsb = picOrderCnt; /* compute top field order cnt (stored in picOrderCnt) */ picOrderCnt += (i32)pSliceHeader->picOrderCntLsb; /* if delta for bottom field is negative -> bottom will be the * minimum pic order count */ if (pSliceHeader->deltaPicOrderCntBottom < 0) picOrderCnt += pSliceHeader->deltaPicOrderCntBottom; /* standard specifies that prevPicOrderCntLsb is from previous * rererence frame -> replace old value only if current frame is * rererence frame */ if (pNalUnit->nalRefIdc) { /* if current frame contains mmco5 -> modify values to be * stored */ if (containsMmco5) { poc->prevPicOrderCntMsb = 0; /* prevPicOrderCntLsb should be the top field picOrderCnt * if previous frame included mmco5. Top field picOrderCnt * for frames containing mmco5 is obtained by subtracting * the picOrderCnt from original top field order count -> * value is zero if top field was the minimum, i.e. delta * for bottom was positive, otherwise value is * -deltaPicOrderCntBottom */ if (pSliceHeader->deltaPicOrderCntBottom < 0) poc->prevPicOrderCntLsb = (u32)(-pSliceHeader->deltaPicOrderCntBottom); else poc->prevPicOrderCntLsb = 0; picOrderCnt = 0; } else { poc->prevPicOrderCntLsb = pSliceHeader->picOrderCntLsb; } } break; case 1: /* step 1 (in the description in the standard) */ if (IS_IDR_NAL_UNIT(pNalUnit)) frameNumOffset = 0; else if (poc->prevFrameNum > pSliceHeader->frameNum) frameNumOffset = poc->prevFrameNumOffset + sps->maxFrameNum; else frameNumOffset = poc->prevFrameNumOffset; /* step 2 */ if (sps->numRefFramesInPicOrderCntCycle) absFrameNum = frameNumOffset + pSliceHeader->frameNum; else absFrameNum = 0; if (pNalUnit->nalRefIdc == 0 && absFrameNum > 0) absFrameNum -= 1; /* step 3 */ if (absFrameNum > 0) { picOrderCntCycleCnt = (absFrameNum - 1)/sps->numRefFramesInPicOrderCntCycle; frameNumInPicOrderCntCycle = (absFrameNum - 1)%sps->numRefFramesInPicOrderCntCycle; } /* step 4 */ expectedDeltaPicOrderCntCycle = 0; for (i = 0; i < sps->numRefFramesInPicOrderCntCycle; i++) expectedDeltaPicOrderCntCycle += sps->offsetForRefFrame[i]; /* step 5 (picOrderCnt used to store expectedPicOrderCnt) */ /*lint -esym(644,picOrderCntCycleCnt) always initialized */ /*lint -esym(644,frameNumInPicOrderCntCycle) always initialized */ if (absFrameNum > 0) { picOrderCnt = (i32)picOrderCntCycleCnt * expectedDeltaPicOrderCntCycle; for (i = 0; i <= frameNumInPicOrderCntCycle; i++) picOrderCnt += sps->offsetForRefFrame[i]; } else picOrderCnt = 0; if (pNalUnit->nalRefIdc == 0) picOrderCnt += sps->offsetForNonRefPic; /* step 6 (picOrderCnt is top field order cnt if delta for bottom * is positive, otherwise it is bottom field order cnt) */ picOrderCnt += pSliceHeader->deltaPicOrderCnt[0]; if ( (sps->offsetForTopToBottomField + pSliceHeader->deltaPicOrderCnt[1]) < 0 ) { picOrderCnt += sps->offsetForTopToBottomField + pSliceHeader->deltaPicOrderCnt[1]; } /* if current picture contains mmco5 -> set prevFrameNumOffset and * prevFrameNum to 0 for computation of picOrderCnt of next * frame, otherwise store frameNum and frameNumOffset to poc * structure */ if (!containsMmco5) { poc->prevFrameNumOffset = frameNumOffset; poc->prevFrameNum = pSliceHeader->frameNum; } else { poc->prevFrameNumOffset = 0; poc->prevFrameNum = 0; picOrderCnt = 0; } break; default: /* case 2 */ /* derive frameNumOffset */ if (IS_IDR_NAL_UNIT(pNalUnit)) frameNumOffset = 0; else if (poc->prevFrameNum > pSliceHeader->frameNum) frameNumOffset = poc->prevFrameNumOffset + sps->maxFrameNum; else frameNumOffset = poc->prevFrameNumOffset; /* derive picOrderCnt (type 2 has same value for top and bottom * field order cnts) */ if (IS_IDR_NAL_UNIT(pNalUnit)) picOrderCnt = 0; else if (pNalUnit->nalRefIdc == 0) picOrderCnt = 2 * (i32)(frameNumOffset + pSliceHeader->frameNum) - 1; else picOrderCnt = 2 * (i32)(frameNumOffset + pSliceHeader->frameNum); /* if current picture contains mmco5 -> set prevFrameNumOffset and * prevFrameNum to 0 for computation of picOrderCnt of next * frame, otherwise store frameNum and frameNumOffset to poc * structure */ if (!containsMmco5) { poc->prevFrameNumOffset = frameNumOffset; poc->prevFrameNum = pSliceHeader->frameNum; } else { poc->prevFrameNumOffset = 0; poc->prevFrameNum = 0; picOrderCnt = 0; } break; } /*lint -esym(644,picOrderCnt) always initialized */ return(picOrderCnt); }