diff -r 000000000000 -r 951a5db380a0 videoeditorengine/avcedit/src/dpb.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/videoeditorengine/avcedit/src/dpb.cpp Fri Jan 29 14:08:33 2010 +0200 @@ -0,0 +1,574 @@ +/* +* Copyright (c) 2010 Ixonos Plc. +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - Initial contribution +* +* Contributors: +* Ixonos Plc +* +* Description: +* +*/ + + +#include +#include "globals.h" +#include "framebuffer.h" +#include "dpb.h" + + + +/* + * + * dpbOpen: + * + * Parameters: + * + * Function: + * Allocate DPB. + * + * Returns: + * Pointer to dpb or NULL + * + */ +dpb_s *dpbOpen() +{ + dpb_s *dpb; + + dpb = (dpb_s *)User::Alloc(sizeof(dpb_s)); + + if (dpb != NULL) + memset(dpb, 0, sizeof(dpb_s)); + + return dpb; +} + + +/* + * + * dpbClose: + * + * Parameters: + * dpb DPB object + * + * Function: + * Deinitialize DPB. + * + * Returns: + * - + * + */ +void dpbClose(dpb_s *dpb) +{ + int i; + + for (i = 0; i < DPB_MAX_SIZE; i++) + frmCloseRef(dpb->buffers[i]); + + User::Free(dpb); +} + + +/* + * + * dpbSetSize: + * + * Parameters: + * dpb DPB object + * dpbSize New DPB size + * + * Function: + * Set DPB size in frames. + * + * Returns: + * - + * + */ +void dpbSetSize(dpb_s *dpb, int dpbSize) +{ + int i; + + /* If new DPB size is smaller than old, close any unneeded frame buffers */ + for (i = dpbSize; i < dpb->size; i++) { + frmCloseRef(dpb->buffers[i]); + dpb->buffers[i] = NULL; + } + + dpb->size = min(dpbSize, DPB_MAX_SIZE); +} + + +/* + * + * dpbGetNextOutputPic: + * + * Parameters: + * dpb DPB object + * dpbHasIDRorMMCO5 Set upon return if IDR picture or picture with + * MMCO5 command is found in DPB + * + * Function: + * Find next frame to output (frame with the lowest POC). + * Search is started from the last active frame in dpb and is + * stopped if all frames have been checked or IDR picture or + * picture with MMCO5 is found. + * + * Returns: + * Framebuffer with the lowest POC or 0 if DPB is empty + * + */ +frmBuf_s *dpbGetNextOutputPic(dpb_s *dpb, int *dpbHasIDRorMMCO5) +{ + frmBuf_s * tmpFrm; + int i; + + tmpFrm = 0; + + /* Find first output pic in decoding order */ + for (i = dpb->fullness-1; i >= 0; i--) { + if (dpb->buffers[i]->forOutput) { + tmpFrm = dpb->buffers[i]; + break; + } + } + + *dpbHasIDRorMMCO5 = 0; + + /* Find picture with lowest poc. Stop search if IDR or MMCO5 is found */ + for (; i >= 0; i--) { + if (dpb->buffers[i]->isIDR || dpb->buffers[i]->hasMMCO5) { + *dpbHasIDRorMMCO5 = 1; + break; + } + if (dpb->buffers[i]->forOutput && dpb->buffers[i]->poc < tmpFrm->poc) + tmpFrm = dpb->buffers[i]; + } + + return tmpFrm; +} + + +/* + * + * dpbStorePicture: + * + * Parameters: + * dpb DPB object + * currPic Current picture + * outputQueue Output queue + * + * Function: + * - Remove unused frames (non-reference, non-output frames) from the DPB. + * - If there is room in the DPB, put picture to DPB. + * - If there is no room in DPB, put pictures to output queue + * until frame is available. + * + * Returns: + * The number of pictures in output queue or negative value for error. + * + */ +int dpbStorePicture(dpb_s *dpb, frmBuf_s *currPic, frmBuf_s *outputQueue[]) +{ + frmBuf_s *tmpRemList[DPB_MAX_SIZE]; + frmBuf_s *tmpFrm; + int numFrm, numRemFrm; + int i; + int freeBufferFound; + int numOutput; + int dpbHasIDRorMMCO5; + + /* + * If the current picture is a reference picture and DPB is already full of + * reference pictures, we cannot insert current picture to DPB. Therefore, + * we force one reference picture out of DPB to make space for current + * picture. This situation can only happen with corrupted bitstreams. + */ + if (currPic->refType != FRM_NON_REF_PIC && + (dpb->numShortTermPics+dpb->numLongTermPics) == dpb->size) + { + if (dpb->numLongTermPics == dpb->size) + dpb->buffers[dpb->fullness-1]->refType = FRM_NON_REF_PIC; + else + dpbMarkLowestShortTermPicAsNonRef(dpb); + } + + /* + * Remove unused frames from dpb + */ + + numFrm = 0; + numRemFrm = 0; + for (i = 0; i < dpb->fullness; i++) { + if (dpb->buffers[i]->refType != FRM_NON_REF_PIC || dpb->buffers[i]->forOutput) { + dpb->buffers[numFrm] = dpb->buffers[i]; + numFrm++; + } + else { + /* Put unsused pics to temporary list */ + tmpRemList[numRemFrm] = dpb->buffers[i]; + numRemFrm++; + } + } + + /* Copy unused pics after active pics */ + for (i = 0; i < numRemFrm; i++) + dpb->buffers[numFrm+i] = tmpRemList[i]; + + dpb->fullness = numFrm; + + + /* + * Try to store current pic to dpb. If there is no room in dpb, we have to + * output some pictures to make room. + */ + + /* Case 1: if current pic is unused, it won't be stored in dpb */ + if (currPic->refType == FRM_NON_REF_PIC && !currPic->forOutput) { + return 0; + } + + /* Case 2: if there is space left in dpb, store current pic */ + if (dpb->fullness < dpb->size) { + + tmpFrm = dpb->buffers[dpb->fullness]; /* Unused frame */ + + tmpFrm = frmMakeRefFrame(currPic, tmpFrm); + if (tmpFrm == NULL) + return DPB_ERR_MEM_ALLOC; + + /* Move frames one position toward end of the list */ + for (i = dpb->fullness; i > 0; i--) + dpb->buffers[i] = dpb->buffers[i-1]; + + /* Always insert new frame to the beginning of the list */ + dpb->buffers[0] = tmpFrm; + dpb->fullness++; + + if (currPic->refType == FRM_SHORT_TERM_PIC) + dpb->numShortTermPics++; + else if (currPic->refType == FRM_LONG_TERM_PIC) + dpb->numLongTermPics++; + + /* Current picture is marked unused */ + currPic->forOutput = 0; + currPic->refType = FRM_NON_REF_PIC; + + /* No pictures in ouput queue */ + return 0; + } + + /* Case 3: output pictures with bumping process until there is space in dpb or + * current pic is non-reference and has lowest poc */ + freeBufferFound = 0; + numOutput = 0; + while (!freeBufferFound) { + + /* Next picture to output is a picture having smallest POC in DPB */ + tmpFrm = dpbGetNextOutputPic(dpb, &dpbHasIDRorMMCO5); + + /* Current picture is output if it is non-reference picture having */ + /* smaller POC than any of the pictures in DPB */ + if (currPic->refType == FRM_NON_REF_PIC && + (tmpFrm == 0 || (!dpbHasIDRorMMCO5 && currPic->poc < tmpFrm->poc))) + { + /* Output current picture */ + currPic->forOutput = 0; + outputQueue[numOutput] = currPic; + numOutput++; + freeBufferFound = 1; + } + else { + /* Output picture that we got from DPB */ + tmpFrm->forOutput = 0; + outputQueue[numOutput] = tmpFrm; + numOutput++; + if (tmpFrm->refType == FRM_NON_REF_PIC) + freeBufferFound = 1; + } + } + + return numOutput; +} + + +/* + * + * dpbUpdatePicNums: + * + * Parameters: + * dpb DPB object + * frameNum Current picture frame number + * maxFrameNum Maximum frame number + * + * Function: + * Compute picture numbers for all pictures in DPB. + * + * Returns: + * - + * + */ +void dpbUpdatePicNums(dpb_s *dpb, int32 frameNum, int32 maxFrameNum) +{ + int i; + frmBuf_s **refPicList; + + refPicList = dpb->buffers; + + for (i = 0; i < dpb->fullness; i++) { + if (refPicList[i]->refType == FRM_SHORT_TERM_PIC) { + /* Short term pictures */ + if (refPicList[i]->frameNum > frameNum) + refPicList[i]->picNum = refPicList[i]->frameNum - maxFrameNum; + else + refPicList[i]->picNum = refPicList[i]->frameNum; + } + else if (refPicList[i]->refType == FRM_LONG_TERM_PIC) + /* Long term pictures */ + refPicList[i]->longTermPicNum = refPicList[i]->longTermFrmIdx; + } +} + + +/* + * + * dpbMarkAllPicsAsNonRef: + * + * Parameters: + * dpb DPB object + * + * Function: + * Mark all picrures as non-reference pictures. + * + * Returns: + * - + * + */ +void dpbMarkAllPicsAsNonRef(dpb_s *dpb) +{ + int i; + + /* Mark all pictures as not used for reference */ + for (i = 0; i < dpb->fullness; i++) + dpb->buffers[i]->refType = FRM_NON_REF_PIC; + + dpb->numShortTermPics = 0; + dpb->numLongTermPics = 0; +} + + +/* + * + * dpbMarkLowestShortTermPicAsNonRef: + * + * Parameters: + * dpb DPB object + * + * Function: + * Mark short-term picture having lowest picture number as + * non-reference pictures. + * + * Returns: + * - + * + */ +void dpbMarkLowestShortTermPicAsNonRef(dpb_s *dpb) +{ + int picIdx; + int i; + + /* Find short term pic with lowest picNum */ + picIdx = -1; + for (i = dpb->fullness-1; i >= 0; i--) { + if (dpb->buffers[i]->refType == FRM_SHORT_TERM_PIC && + (picIdx < 0 || dpb->buffers[i]->picNum < dpb->buffers[picIdx]->picNum)) + picIdx = i; + } + + /* Mark short term pic with lowest picNum as not reference picture */ + if (picIdx >= 0) { + dpb->buffers[picIdx]->refType = FRM_NON_REF_PIC; + dpb->numShortTermPics--; + } +} + + +/* + * + * dpbMarkShortTermPicAsNonRef: + * + * Parameters: + * dpb DPB object + * picNum Picture number + * + * Function: + * Mark short-term picture having picture number picNum as + * non-reference picture. + * + * Returns: + * DPB_OK or DPB_ERR_PICTURE_NOT_FOUND + * + */ +int dpbMarkShortTermPicAsNonRef(dpb_s *dpb, int32 picNum) +{ + int i; + + for (i = 0; i < dpb->fullness; i++) { + if (dpb->buffers[i]->refType == FRM_SHORT_TERM_PIC && + dpb->buffers[i]->picNum == picNum) + { + dpb->buffers[i]->refType = FRM_NON_REF_PIC; + dpb->numShortTermPics--; + return DPB_OK; + } + } + + return DPB_ERR_PICTURE_NOT_FOUND; +} + + +/* + * + * dpbMarkLongTermPicAsNonRef: + * + * Parameters: + * dpb DPB object + * longTermPicNum Long-term picture number + * + * Function: + * Mark long-term picture having long-term picture number longTermPicNum + * as non-reference picture. + * + * Returns: + * DPB_OK or DPB_ERR_PICTURE_NOT_FOUND + * + */ +int dpbMarkLongTermPicAsNonRef(dpb_s *dpb, int longTermPicNum) +{ + int i; + + for (i = 0; i < dpb->fullness; i++) { + if (dpb->buffers[i]->refType == FRM_LONG_TERM_PIC && + dpb->buffers[i]->longTermPicNum == longTermPicNum) + { + dpb->buffers[i]->refType = FRM_NON_REF_PIC; + dpb->numLongTermPics--; + return DPB_OK; + } + } + + return DPB_ERR_PICTURE_NOT_FOUND; +} + + +/* + * + * dpbVerifyLongTermFrmIdx: + * + * Parameters: + * dpb DPB object + * longTermFrmIdx Long-term frame index + * + * Function: + * If there is a long-term picture having long term frame index + * longTermFrmIdx, mark that picture as non-reference picture. + * + * Returns: + * - + * + */ +void dpbVerifyLongTermFrmIdx(dpb_s *dpb, int longTermFrmIdx) +{ + int i; + + /* Check if longTermFrmIdx is already in use */ + for (i = 0; i < dpb->fullness; i++) { + if (dpb->buffers[i]->refType == FRM_LONG_TERM_PIC && + dpb->buffers[i]->longTermFrmIdx == longTermFrmIdx) + { + dpb->buffers[i]->refType = FRM_NON_REF_PIC; + dpb->numLongTermPics--; + break; + } + } +} + + +/* + * + * dpbMarkShortTermPicAsLongTerm: + * + * Parameters: + * dpb DPB object + * picNum Picture number + * longTermFrmIdx Long-term frame index + * + * Function: + * Mark short-term picture having picture number picNum as long-term + * picture having long-term frame index longTermFrmIdx. + * + * Returns: + * DPB_OK or DPB_ERR_PICTURE_NOT_FOUND + * + */ +int dpbMarkShortTermPicAsLongTerm(dpb_s *dpb, int32 picNum, int longTermFrmIdx) +{ + int i; + + /* To avoid duplicate of longTermFrmIdx */ + dpbVerifyLongTermFrmIdx(dpb, longTermFrmIdx); + + /* Mark pic with picNum as long term and assign longTermFrmIdx to it */ + for (i = 0; i < dpb->fullness; i++) { + if (dpb->buffers[i]->refType == FRM_SHORT_TERM_PIC && + dpb->buffers[i]->picNum == picNum) + { + dpb->buffers[i]->refType = FRM_LONG_TERM_PIC; + dpb->buffers[i]->longTermFrmIdx = longTermFrmIdx; + dpb->numShortTermPics--; + dpb->numLongTermPics++; + return DPB_OK; + } + } + + return DPB_ERR_PICTURE_NOT_FOUND; +} + + +/* + * + * dpbSetMaxLongTermFrameIdx: + * + * Parameters: + * dpb DPB object + * maxLongTermFrmIdxPlus1 Maximum long-term frame index plus 1 + * + * Function: + * Set maximum long-term frame index. All long-term pictures having + * bigger long-term frame index than maxLongTermFrmIdxPlus1-1 are + * marked as non-reference pictures. + * + * Returns: + * - + * + */ +void dpbSetMaxLongTermFrameIdx(dpb_s *dpb, int maxLongTermFrmIdxPlus1) +{ + int i; + + for (i = 0; i < dpb->fullness; i++) { + if (dpb->buffers[i]->refType == FRM_LONG_TERM_PIC && + dpb->buffers[i]->longTermFrmIdx > maxLongTermFrmIdxPlus1-1) + { + dpb->buffers[i]->refType = FRM_NON_REF_PIC; + dpb->numLongTermPics--; + } + } + + dpb->maxLongTermFrameIdx = maxLongTermFrmIdxPlus1 - 1; +}