videoeditorengine/avcedit/src/dpb.cpp
changeset 0 951a5db380a0
--- /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 <string.h>
+#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;
+}