blob: 9517d0ae3eb075257a1182d63aedd44cce3428d6 [file] [log] [blame]
/*
* 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
ComparePictures
h264bsdReorderRefPicList
Mmcop1
Mmcop2
Mmcop3
Mmcop4
Mmcop5
Mmcop6
h264bsdMarkDecRefPic
h264bsdGetRefPicData
h264bsdAllocateDpbImage
SlidingWindowRefPicMarking
h264bsdInitDpb
h264bsdResetDpb
h264bsdInitRefPicList
FindDpbPic
SetPicNums
h264bsdCheckGapsInFrameNum
FindSmallestPicOrderCnt
OutputPicture
h264bsdDpbOutputPicture
h264bsdFlushDpb
h264bsdFreeDpb
------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------
1. Include headers
------------------------------------------------------------------------------*/
#include "h264bsd_cfg.h"
#include "h264bsd_dpb.h"
#include "h264bsd_slice_header.h"
#include "h264bsd_image.h"
#include "h264bsd_util.h"
#include "basetype.h"
/*------------------------------------------------------------------------------
2. External compiler flags
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
3. Module defines
------------------------------------------------------------------------------*/
/* macros to determine picture status. Note that IS_SHORT_TERM macro returns
* true also for non-existing pictures because non-existing pictures are
* regarded short term pictures according to H.264 standard */
#define IS_REFERENCE(a) ((a).status)
#define IS_EXISTING(a) ((a).status > NON_EXISTING)
#define IS_SHORT_TERM(a) \
((a).status == NON_EXISTING || (a).status == SHORT_TERM)
#define IS_LONG_TERM(a) ((a).status == LONG_TERM)
/* macro to set a picture unused for reference */
#define SET_UNUSED(a) (a).status = UNUSED;
#define MAX_NUM_REF_IDX_L0_ACTIVE 16
/*------------------------------------------------------------------------------
4. Local function prototypes
------------------------------------------------------------------------------*/
static i32 ComparePictures(const void *ptr1, const void *ptr2);
static u32 Mmcop1(dpbStorage_t *dpb, u32 currPicNum, u32 differenceOfPicNums);
static u32 Mmcop2(dpbStorage_t *dpb, u32 longTermPicNum);
static u32 Mmcop3(dpbStorage_t *dpb, u32 currPicNum, u32 differenceOfPicNums,
u32 longTermFrameIdx);
static u32 Mmcop4(dpbStorage_t *dpb, u32 maxLongTermFrameIdx);
static u32 Mmcop5(dpbStorage_t *dpb);
static u32 Mmcop6(dpbStorage_t *dpb, u32 frameNum, i32 picOrderCnt,
u32 longTermFrameIdx);
static u32 SlidingWindowRefPicMarking(dpbStorage_t *dpb);
static i32 FindDpbPic(dpbStorage_t *dpb, i32 picNum, u32 isShortTerm);
static void SetPicNums(dpbStorage_t *dpb, u32 currFrameNum);
static dpbPicture_t* FindSmallestPicOrderCnt(dpbStorage_t *dpb);
static u32 OutputPicture(dpbStorage_t *dpb);
static void ShellSort(dpbPicture_t *pPic, u32 num);
/*------------------------------------------------------------------------------
Function: ComparePictures
Functional description:
Function to compare dpb pictures, used by the ShellSort() function.
Order of the pictures after sorting shall be as follows:
1) short term reference pictures starting with the largest
picNum
2) long term reference pictures starting with the smallest
longTermPicNum
3) pictures unused for reference but needed for display
4) other pictures
Returns:
-1 pic 1 is greater than pic 2
0 equal from comparison point of view
1 pic 2 is greater then pic 1
------------------------------------------------------------------------------*/
static i32 ComparePictures(const void *ptr1, const void *ptr2)
{
/* Variables */
dpbPicture_t *pic1, *pic2;
/* Code */
ASSERT(ptr1);
ASSERT(ptr2);
pic1 = (dpbPicture_t*)ptr1;
pic2 = (dpbPicture_t*)ptr2;
/* both are non-reference pictures, check if needed for display */
if (!IS_REFERENCE(*pic1) && !IS_REFERENCE(*pic2))
{
if (pic1->toBeDisplayed && !pic2->toBeDisplayed)
return(-1);
else if (!pic1->toBeDisplayed && pic2->toBeDisplayed)
return(1);
else
return(0);
}
/* only pic 1 needed for reference -> greater */
else if (!IS_REFERENCE(*pic2))
return(-1);
/* only pic 2 needed for reference -> greater */
else if (!IS_REFERENCE(*pic1))
return(1);
/* both are short term reference pictures -> check picNum */
else if (IS_SHORT_TERM(*pic1) && IS_SHORT_TERM(*pic2))
{
if (pic1->picNum > pic2->picNum)
return(-1);
else if (pic1->picNum < pic2->picNum)
return(1);
else
return(0);
}
/* only pic 1 is short term -> greater */
else if (IS_SHORT_TERM(*pic1))
return(-1);
/* only pic 2 is short term -> greater */
else if (IS_SHORT_TERM(*pic2))
return(1);
/* both are long term reference pictures -> check picNum (contains the
* longTermPicNum */
else
{
if (pic1->picNum > pic2->picNum)
return(1);
else if (pic1->picNum < pic2->picNum)
return(-1);
else
return(0);
}
}
/*------------------------------------------------------------------------------
Function: h264bsdReorderRefPicList
Functional description:
Function to perform reference picture list reordering based on
reordering commands received in the slice header. See details
of the process in the H.264 standard.
Inputs:
dpb pointer to dpb storage structure
order pointer to reordering commands
currFrameNum current frame number
numRefIdxActive number of active reference indices for current
picture
Outputs:
dpb 'list' field of the structure reordered
Returns:
HANTRO_OK success
HANTRO_NOK if non-existing pictures referred to in the
reordering commands
------------------------------------------------------------------------------*/
u32 h264bsdReorderRefPicList(
dpbStorage_t *dpb,
refPicListReordering_t *order,
u32 currFrameNum,
u32 numRefIdxActive)
{
/* Variables */
u32 i, j, k, picNumPred, refIdx;
i32 picNum, picNumNoWrap, index;
u32 isShortTerm;
/* Code */
ASSERT(order);
ASSERT(currFrameNum <= dpb->maxFrameNum);
ASSERT(numRefIdxActive <= MAX_NUM_REF_IDX_L0_ACTIVE);
/* set dpb picture numbers for sorting */
SetPicNums(dpb, currFrameNum);
if (!order->refPicListReorderingFlagL0)
return(HANTRO_OK);
refIdx = 0;
picNumPred = currFrameNum;
i = 0;
while (order->command[i].reorderingOfPicNumsIdc < 3)
{
/* short term */
if (order->command[i].reorderingOfPicNumsIdc < 2)
{
if (order->command[i].reorderingOfPicNumsIdc == 0)
{
picNumNoWrap =
(i32)picNumPred - (i32)order->command[i].absDiffPicNum;
if (picNumNoWrap < 0)
picNumNoWrap += (i32)dpb->maxFrameNum;
}
else
{
picNumNoWrap =
(i32)(picNumPred + order->command[i].absDiffPicNum);
if (picNumNoWrap >= (i32)dpb->maxFrameNum)
picNumNoWrap -= (i32)dpb->maxFrameNum;
}
picNumPred = (u32)picNumNoWrap;
picNum = picNumNoWrap;
if ((u32)picNumNoWrap > currFrameNum)
picNum -= (i32)dpb->maxFrameNum;
isShortTerm = HANTRO_TRUE;
}
/* long term */
else
{
picNum = (i32)order->command[i].longTermPicNum;
isShortTerm = HANTRO_FALSE;
}
/* find corresponding picture from dpb */
index = FindDpbPic(dpb, picNum, isShortTerm);
if (index < 0 || !IS_EXISTING(dpb->buffer[index]))
return(HANTRO_NOK);
/* shift pictures */
for (j = numRefIdxActive; j > refIdx; j--)
dpb->list[j] = dpb->list[j-1];
/* put picture into the list */
dpb->list[refIdx++] = &dpb->buffer[index];
/* remove later references to the same picture */
for (j = k = refIdx; j <= numRefIdxActive; j++)
if(dpb->list[j] != &dpb->buffer[index])
dpb->list[k++] = dpb->list[j];
i++;
}
return(HANTRO_OK);
}
/*------------------------------------------------------------------------------
Function: Mmcop1
Functional description:
Function to mark a short-term reference picture unused for
reference, memory_management_control_operation equal to 1
Returns:
HANTRO_OK success
HANTRO_NOK failure, picture does not exist in the buffer
------------------------------------------------------------------------------*/
static u32 Mmcop1(dpbStorage_t *dpb, u32 currPicNum, u32 differenceOfPicNums)
{
/* Variables */
i32 index, picNum;
/* Code */
ASSERT(currPicNum < dpb->maxFrameNum);
picNum = (i32)currPicNum - (i32)differenceOfPicNums;
index = FindDpbPic(dpb, picNum, HANTRO_TRUE);
if (index < 0)
return(HANTRO_NOK);
SET_UNUSED(dpb->buffer[index]);
dpb->numRefFrames--;
if (!dpb->buffer[index].toBeDisplayed)
dpb->fullness--;
return(HANTRO_OK);
}
/*------------------------------------------------------------------------------
Function: Mmcop2
Functional description:
Function to mark a long-term reference picture unused for
reference, memory_management_control_operation equal to 2
Returns:
HANTRO_OK success
HANTRO_NOK failure, picture does not exist in the buffer
------------------------------------------------------------------------------*/
static u32 Mmcop2(dpbStorage_t *dpb, u32 longTermPicNum)
{
/* Variables */
i32 index;
/* Code */
index = FindDpbPic(dpb, (i32)longTermPicNum, HANTRO_FALSE);
if (index < 0)
return(HANTRO_NOK);
SET_UNUSED(dpb->buffer[index]);
dpb->numRefFrames--;
if (!dpb->buffer[index].toBeDisplayed)
dpb->fullness--;
return(HANTRO_OK);
}
/*------------------------------------------------------------------------------
Function: Mmcop3
Functional description:
Function to assing a longTermFrameIdx to a short-term reference
frame (i.e. to change it to a long-term reference picture),
memory_management_control_operation equal to 3
Returns:
HANTRO_OK success
HANTRO_NOK failure, short-term picture does not exist in the
buffer or is a non-existing picture, or invalid
longTermFrameIdx given
------------------------------------------------------------------------------*/
static u32 Mmcop3(dpbStorage_t *dpb, u32 currPicNum, u32 differenceOfPicNums,
u32 longTermFrameIdx)
{
/* Variables */
i32 index, picNum;
u32 i;
/* Code */
ASSERT(dpb);
ASSERT(currPicNum < dpb->maxFrameNum);
if ( (dpb->maxLongTermFrameIdx == NO_LONG_TERM_FRAME_INDICES) ||
(longTermFrameIdx > dpb->maxLongTermFrameIdx) )
return(HANTRO_NOK);
/* check if a long term picture with the same longTermFrameIdx already
* exist and remove it if necessary */
for (i = 0; i < dpb->maxRefFrames; i++)
if (IS_LONG_TERM(dpb->buffer[i]) &&
(u32)dpb->buffer[i].picNum == longTermFrameIdx)
{
SET_UNUSED(dpb->buffer[i]);
dpb->numRefFrames--;
if (!dpb->buffer[i].toBeDisplayed)
dpb->fullness--;
break;
}
picNum = (i32)currPicNum - (i32)differenceOfPicNums;
index = FindDpbPic(dpb, picNum, HANTRO_TRUE);
if (index < 0)
return(HANTRO_NOK);
if (!IS_EXISTING(dpb->buffer[index]))
return(HANTRO_NOK);
dpb->buffer[index].status = LONG_TERM;
dpb->buffer[index].picNum = (i32)longTermFrameIdx;
return(HANTRO_OK);
}
/*------------------------------------------------------------------------------
Function: Mmcop4
Functional description:
Function to set maxLongTermFrameIdx,
memory_management_control_operation equal to 4
Returns:
HANTRO_OK success
------------------------------------------------------------------------------*/
static u32 Mmcop4(dpbStorage_t *dpb, u32 maxLongTermFrameIdx)
{
/* Variables */
u32 i;
/* Code */
dpb->maxLongTermFrameIdx = maxLongTermFrameIdx;
for (i = 0; i < dpb->maxRefFrames; i++)
if (IS_LONG_TERM(dpb->buffer[i]) &&
( ((u32)dpb->buffer[i].picNum > maxLongTermFrameIdx) ||
(dpb->maxLongTermFrameIdx == NO_LONG_TERM_FRAME_INDICES) ) )
{
SET_UNUSED(dpb->buffer[i]);
dpb->numRefFrames--;
if (!dpb->buffer[i].toBeDisplayed)
dpb->fullness--;
}
return(HANTRO_OK);
}
/*------------------------------------------------------------------------------
Function: Mmcop5
Functional description:
Function to mark all reference pictures unused for reference and
set maxLongTermFrameIdx to NO_LONG_TERM_FRAME_INDICES,
memory_management_control_operation equal to 5. Function flushes
the buffer and places all pictures that are needed for display into
the output buffer.
Returns:
HANTRO_OK success
------------------------------------------------------------------------------*/
static u32 Mmcop5(dpbStorage_t *dpb)
{
/* Variables */
u32 i;
/* Code */
for (i = 0; i < 16; i++)
{
if (IS_REFERENCE(dpb->buffer[i]))
{
SET_UNUSED(dpb->buffer[i]);
if (!dpb->buffer[i].toBeDisplayed)
dpb->fullness--;
}
}
/* output all pictures */
while (OutputPicture(dpb) == HANTRO_OK)
;
dpb->numRefFrames = 0;
dpb->maxLongTermFrameIdx = NO_LONG_TERM_FRAME_INDICES;
dpb->prevRefFrameNum = 0;
return(HANTRO_OK);
}
/*------------------------------------------------------------------------------
Function: Mmcop6
Functional description:
Function to assign longTermFrameIdx to the current picture,
memory_management_control_operation equal to 6
Returns:
HANTRO_OK success
HANTRO_NOK invalid longTermFrameIdx or no room for current
picture in the buffer
------------------------------------------------------------------------------*/
static u32 Mmcop6(dpbStorage_t *dpb, u32 frameNum, i32 picOrderCnt,
u32 longTermFrameIdx)
{
/* Variables */
u32 i;
/* Code */
ASSERT(frameNum < dpb->maxFrameNum);
if ( (dpb->maxLongTermFrameIdx == NO_LONG_TERM_FRAME_INDICES) ||
(longTermFrameIdx > dpb->maxLongTermFrameIdx) )
return(HANTRO_NOK);
/* check if a long term picture with the same longTermFrameIdx already
* exist and remove it if necessary */
for (i = 0; i < dpb->maxRefFrames; i++)
if (IS_LONG_TERM(dpb->buffer[i]) &&
(u32)dpb->buffer[i].picNum == longTermFrameIdx)
{
SET_UNUSED(dpb->buffer[i]);
dpb->numRefFrames--;
if (!dpb->buffer[i].toBeDisplayed)
dpb->fullness--;
break;
}
if (dpb->numRefFrames < dpb->maxRefFrames)
{
dpb->currentOut->frameNum = frameNum;
dpb->currentOut->picNum = (i32)longTermFrameIdx;
dpb->currentOut->picOrderCnt = picOrderCnt;
dpb->currentOut->status = LONG_TERM;
if (dpb->noReordering)
dpb->currentOut->toBeDisplayed = HANTRO_FALSE;
else
dpb->currentOut->toBeDisplayed = HANTRO_TRUE;
dpb->numRefFrames++;
dpb->fullness++;
return(HANTRO_OK);
}
/* if there is no room, return an error */
else
return(HANTRO_NOK);
}
/*------------------------------------------------------------------------------
Function: h264bsdMarkDecRefPic
Functional description:
Function to perform reference picture marking process. This
function should be called both for reference and non-reference
pictures. Non-reference pictures shall have mark pointer set to
NULL.
Inputs:
dpb pointer to the DPB data structure
mark pointer to reference picture marking commands
image pointer to current picture to be placed in the buffer
frameNum frame number of the current picture
picOrderCnt picture order count for the current picture
isIdr flag to indicate if the current picture is an
IDR picture
currentPicId identifier for the current picture, from the
application, stored along with the picture
numErrMbs number of concealed macroblocks in the current
picture, stored along with the picture
Outputs:
dpb 'buffer' modified, possible output frames placed into
'outBuf'
Returns:
HANTRO_OK success
HANTRO_NOK failure
------------------------------------------------------------------------------*/
u32 h264bsdMarkDecRefPic(
dpbStorage_t *dpb,
decRefPicMarking_t *mark,
image_t *image,
u32 frameNum,
i32 picOrderCnt,
u32 isIdr,
u32 currentPicId,
u32 numErrMbs)
{
/* Variables */
u32 i, status;
u32 markedAsLongTerm;
u32 toBeDisplayed;
/* Code */
ASSERT(dpb);
ASSERT(mark || !isIdr);
ASSERT(!isIdr || (frameNum == 0 && picOrderCnt == 0));
ASSERT(frameNum < dpb->maxFrameNum);
if (image->data != dpb->currentOut->data)
{
EPRINT("TRYING TO MARK NON-ALLOCATED IMAGE");
return(HANTRO_NOK);
}
dpb->lastContainsMmco5 = HANTRO_FALSE;
status = HANTRO_OK;
toBeDisplayed = dpb->noReordering ? HANTRO_FALSE : HANTRO_TRUE;
/* non-reference picture, stored for display reordering purposes */
if (mark == NULL)
{
dpb->currentOut->status = UNUSED;
dpb->currentOut->frameNum = frameNum;
dpb->currentOut->picNum = (i32)frameNum;
dpb->currentOut->picOrderCnt = picOrderCnt;
dpb->currentOut->toBeDisplayed = toBeDisplayed;
if (!dpb->noReordering)
dpb->fullness++;
}
/* IDR picture */
else if (isIdr)
{
/* h264bsdCheckGapsInFrameNum not called for IDR pictures -> have to
* reset numOut and outIndex here */
dpb->numOut = dpb->outIndex = 0;
/* flush the buffer */
Mmcop5(dpb);
/* if noOutputOfPriorPicsFlag was set -> the pictures preceding the
* IDR picture shall not be output -> set output buffer empty */
if (mark->noOutputOfPriorPicsFlag || dpb->noReordering)
{
dpb->numOut = 0;
dpb->outIndex = 0;
}
if (mark->longTermReferenceFlag)
{
dpb->currentOut->status = LONG_TERM;
dpb->maxLongTermFrameIdx = 0;
}
else
{
dpb->currentOut->status = SHORT_TERM;
dpb->maxLongTermFrameIdx = NO_LONG_TERM_FRAME_INDICES;
}
dpb->currentOut->frameNum = 0;
dpb->currentOut->picNum = 0;
dpb->currentOut->picOrderCnt = 0;
dpb->currentOut->toBeDisplayed = toBeDisplayed;
dpb->fullness = 1;
dpb->numRefFrames = 1;
}
/* reference picture */
else
{
markedAsLongTerm = HANTRO_FALSE;
if (mark->adaptiveRefPicMarkingModeFlag)
{
i = 0;
while (mark->operation[i].memoryManagementControlOperation)
{
switch (mark->operation[i].memoryManagementControlOperation)
{
case 1:
status = Mmcop1(
dpb,
frameNum,
mark->operation[i].differenceOfPicNums);
break;
case 2:
status = Mmcop2(dpb, mark->operation[i].longTermPicNum);
break;
case 3:
status = Mmcop3(
dpb,
frameNum,
mark->operation[i].differenceOfPicNums,
mark->operation[i].longTermFrameIdx);
break;
case 4:
status = Mmcop4(
dpb,
mark->operation[i].maxLongTermFrameIdx);
break;
case 5:
status = Mmcop5(dpb);
dpb->lastContainsMmco5 = HANTRO_TRUE;
frameNum = 0;
break;
case 6:
status = Mmcop6(
dpb,
frameNum,
picOrderCnt,
mark->operation[i].longTermFrameIdx);
if (status == HANTRO_OK)
markedAsLongTerm = HANTRO_TRUE;
break;
default: /* invalid memory management control operation */
status = HANTRO_NOK;
break;
}
if (status != HANTRO_OK)
{
break;
}
i++;
}
}
else
{
status = SlidingWindowRefPicMarking(dpb);
}
/* if current picture was not marked as long-term reference by
* memory management control operation 6 -> mark current as short
* term and insert it into dpb (if there is room) */
if (!markedAsLongTerm)
{
if (dpb->numRefFrames < dpb->maxRefFrames)
{
dpb->currentOut->frameNum = frameNum;
dpb->currentOut->picNum = (i32)frameNum;
dpb->currentOut->picOrderCnt = picOrderCnt;
dpb->currentOut->status = SHORT_TERM;
dpb->currentOut->toBeDisplayed = toBeDisplayed;
dpb->fullness++;
dpb->numRefFrames++;
}
/* no room */
else
{
status = HANTRO_NOK;
}
}
}
dpb->currentOut->isIdr = isIdr;
dpb->currentOut->picId = currentPicId;
dpb->currentOut->numErrMbs = numErrMbs;
/* dpb was initialized to not to reorder the pictures -> output current
* picture immediately */
if (dpb->noReordering)
{
ASSERT(dpb->numOut == 0);
ASSERT(dpb->outIndex == 0);
dpb->outBuf[dpb->numOut].data = dpb->currentOut->data;
dpb->outBuf[dpb->numOut].isIdr = dpb->currentOut->isIdr;
dpb->outBuf[dpb->numOut].picId = dpb->currentOut->picId;
dpb->outBuf[dpb->numOut].numErrMbs = dpb->currentOut->numErrMbs;
dpb->numOut++;
}
else
{
/* output pictures if buffer full */
while (dpb->fullness > dpb->dpbSize)
{
i = OutputPicture(dpb);
ASSERT(i == HANTRO_OK);
}
}
/* sort dpb */
ShellSort(dpb->buffer, dpb->dpbSize+1);
return(status);
}
/*------------------------------------------------------------------------------
Function: h264bsdGetRefPicData
Functional description:
Function to get reference picture data from the reference picture
list
Returns:
pointer to desired reference picture data
NULL if invalid index or non-existing picture referred
------------------------------------------------------------------------------*/
u8* h264bsdGetRefPicData(dpbStorage_t *dpb, u32 index)
{
/* Variables */
/* Code */
if(index > 16 || dpb->list[index] == NULL)
return(NULL);
else if(!IS_EXISTING(*dpb->list[index]))
return(NULL);
else
return(dpb->list[index]->data);
}
/*------------------------------------------------------------------------------
Function: h264bsdAllocateDpbImage
Functional description:
function to allocate memory for a image. This function does not
really allocate any memory but reserves one of the buffer
positions for decoding of current picture
Returns:
pointer to memory area for the image
------------------------------------------------------------------------------*/
u8* h264bsdAllocateDpbImage(dpbStorage_t *dpb)
{
/* Variables */
/* Code */
ASSERT( !dpb->buffer[dpb->dpbSize].toBeDisplayed &&
!IS_REFERENCE(dpb->buffer[dpb->dpbSize]) );
ASSERT(dpb->fullness <= dpb->dpbSize);
dpb->currentOut = dpb->buffer + dpb->dpbSize;
return(dpb->currentOut->data);
}
/*------------------------------------------------------------------------------
Function: SlidingWindowRefPicMarking
Functional description:
Function to perform sliding window refence picture marking process.
Outputs:
HANTRO_OK success
HANTRO_NOK failure, no short-term reference frame found that
could be marked unused
------------------------------------------------------------------------------*/
static u32 SlidingWindowRefPicMarking(dpbStorage_t *dpb)
{
/* Variables */
i32 index, picNum;
u32 i;
/* Code */
if (dpb->numRefFrames < dpb->maxRefFrames)
{
return(HANTRO_OK);
}
else
{
index = -1;
picNum = 0;
/* find the oldest short term picture */
for (i = 0; i < dpb->numRefFrames; i++)
if (IS_SHORT_TERM(dpb->buffer[i]))
if (dpb->buffer[i].picNum < picNum || index == -1)
{
index = (i32)i;
picNum = dpb->buffer[i].picNum;
}
if (index >= 0)
{
SET_UNUSED(dpb->buffer[index]);
dpb->numRefFrames--;
if (!dpb->buffer[index].toBeDisplayed)
dpb->fullness--;
return(HANTRO_OK);
}
}
return(HANTRO_NOK);
}
/*------------------------------------------------------------------------------
Function: h264bsdInitDpb
Functional description:
Function to initialize DPB. Reserves memories for the buffer,
reference picture list and output buffer. dpbSize indicates
the maximum DPB size indicated by the levelIdc in the stream.
If noReordering flag is FALSE the DPB stores dpbSize pictures
for display reordering purposes. On the other hand, if the
flag is TRUE the DPB only stores maxRefFrames reference pictures
and outputs all the pictures immediately.
Inputs:
picSizeInMbs picture size in macroblocks
dpbSize size of the DPB (number of pictures)
maxRefFrames max number of reference frames
maxFrameNum max frame number
noReordering flag to indicate that DPB does not have to
prepare to reorder frames for display
Outputs:
dpb pointer to dpb data storage
Returns:
HANTRO_OK success
MEMORY_ALLOCATION_ERROR if memory allocation failed
------------------------------------------------------------------------------*/
u32 h264bsdInitDpb(
dpbStorage_t *dpb,
u32 picSizeInMbs,
u32 dpbSize,
u32 maxRefFrames,
u32 maxFrameNum,
u32 noReordering)
{
/* Variables */
u32 i;
/* Code */
ASSERT(picSizeInMbs);
ASSERT(maxRefFrames <= MAX_NUM_REF_PICS);
ASSERT(maxRefFrames <= dpbSize);
ASSERT(maxFrameNum);
ASSERT(dpbSize);
dpb->maxLongTermFrameIdx = NO_LONG_TERM_FRAME_INDICES;
dpb->maxRefFrames = MAX(maxRefFrames, 1);
if (noReordering)
dpb->dpbSize = dpb->maxRefFrames;
else
dpb->dpbSize = dpbSize;
dpb->maxFrameNum = maxFrameNum;
dpb->noReordering = noReordering;
dpb->fullness = 0;
dpb->numRefFrames = 0;
dpb->prevRefFrameNum = 0;
ALLOCATE(dpb->buffer, MAX_NUM_REF_IDX_L0_ACTIVE + 1, dpbPicture_t);
if (dpb->buffer == NULL)
return(MEMORY_ALLOCATION_ERROR);
H264SwDecMemset(dpb->buffer, 0,
(MAX_NUM_REF_IDX_L0_ACTIVE + 1)*sizeof(dpbPicture_t));
for (i = 0; i < dpb->dpbSize + 1; i++)
{
/* Allocate needed amount of memory, which is:
* image size + 32 + 15, where 32 cames from the fact that in ARM OpenMax
* DL implementation Functions may read beyond the end of an array,
* by a maximum of 32 bytes. And +15 cames for the need to align memory
* to 16-byte boundary */
ALLOCATE(dpb->buffer[i].pAllocatedData, (picSizeInMbs*384 + 32+15), u8);
if (dpb->buffer[i].pAllocatedData == NULL)
return(MEMORY_ALLOCATION_ERROR);
dpb->buffer[i].data = ALIGN(dpb->buffer[i].pAllocatedData, 16);
}
ALLOCATE(dpb->list, MAX_NUM_REF_IDX_L0_ACTIVE + 1, dpbPicture_t*);
ALLOCATE(dpb->outBuf, dpb->dpbSize+1, dpbOutPicture_t);
if (dpb->list == NULL || dpb->outBuf == NULL)
return(MEMORY_ALLOCATION_ERROR);
H264SwDecMemset(dpb->list, 0,
((MAX_NUM_REF_IDX_L0_ACTIVE + 1) * sizeof(dpbPicture_t*)) );
dpb->numOut = dpb->outIndex = 0;
return(HANTRO_OK);
}
/*------------------------------------------------------------------------------
Function: h264bsdResetDpb
Functional description:
Function to reset DPB. This function should be called when an IDR
slice (other than the first) activates new sequence parameter set.
Function calls h264bsdFreeDpb to free old allocated memories and
h264bsdInitDpb to re-initialize the DPB. Same inputs, outputs and
returns as for h264bsdInitDpb.
------------------------------------------------------------------------------*/
u32 h264bsdResetDpb(
dpbStorage_t *dpb,
u32 picSizeInMbs,
u32 dpbSize,
u32 maxRefFrames,
u32 maxFrameNum,
u32 noReordering)
{
/* Code */
ASSERT(picSizeInMbs);
ASSERT(maxRefFrames <= MAX_NUM_REF_PICS);
ASSERT(maxRefFrames <= dpbSize);
ASSERT(maxFrameNum);
ASSERT(dpbSize);
h264bsdFreeDpb(dpb);
return h264bsdInitDpb(dpb, picSizeInMbs, dpbSize, maxRefFrames,
maxFrameNum, noReordering);
}
/*------------------------------------------------------------------------------
Function: h264bsdInitRefPicList
Functional description:
Function to initialize reference picture list. Function just
sets pointers in the list according to pictures in the buffer.
The buffer is assumed to contain pictures sorted according to
what the H.264 standard says about initial reference picture list.
Inputs:
dpb pointer to dpb data structure
Outputs:
dpb 'list' field initialized
Returns:
none
------------------------------------------------------------------------------*/
void h264bsdInitRefPicList(dpbStorage_t *dpb)
{
/* Variables */
u32 i;
/* Code */
for (i = 0; i < dpb->numRefFrames; i++)
dpb->list[i] = &dpb->buffer[i];
}
/*------------------------------------------------------------------------------
Function: FindDpbPic
Functional description:
Function to find a reference picture from the buffer. The picture
to be found is identified by picNum and isShortTerm flag.
Returns:
index of the picture in the buffer
-1 if the specified picture was not found in the buffer
------------------------------------------------------------------------------*/
static i32 FindDpbPic(dpbStorage_t *dpb, i32 picNum, u32 isShortTerm)
{
/* Variables */
u32 i = 0;
u32 found = HANTRO_FALSE;
/* Code */
if (isShortTerm)
{
while (i < dpb->maxRefFrames && !found)
{
if (IS_SHORT_TERM(dpb->buffer[i]) &&
dpb->buffer[i].picNum == picNum)
found = HANTRO_TRUE;
else
i++;
}
}
else
{
ASSERT(picNum >= 0);
while (i < dpb->maxRefFrames && !found)
{
if (IS_LONG_TERM(dpb->buffer[i]) &&
dpb->buffer[i].picNum == picNum)
found = HANTRO_TRUE;
else
i++;
}
}
if (found)
return((i32)i);
else
return(-1);
}
/*------------------------------------------------------------------------------
Function: SetPicNums
Functional description:
Function to set picNum values for short-term pictures in the
buffer. Numbering of pictures is based on frame numbers and as
frame numbers are modulo maxFrameNum -> frame numbers of older
pictures in the buffer may be bigger than the currFrameNum.
picNums will be set so that current frame has the largest picNum
and all the short-term frames in the buffer will get smaller picNum
representing their "distance" from the current frame. This
function kind of maps the modulo arithmetic back to normal.
------------------------------------------------------------------------------*/
static void SetPicNums(dpbStorage_t *dpb, u32 currFrameNum)
{
/* Variables */
u32 i;
i32 frameNumWrap;
/* Code */
ASSERT(dpb);
ASSERT(currFrameNum < dpb->maxFrameNum);
for (i = 0; i < dpb->numRefFrames; i++)
if (IS_SHORT_TERM(dpb->buffer[i]))
{
if (dpb->buffer[i].frameNum > currFrameNum)
frameNumWrap =
(i32)dpb->buffer[i].frameNum - (i32)dpb->maxFrameNum;
else
frameNumWrap = (i32)dpb->buffer[i].frameNum;
dpb->buffer[i].picNum = frameNumWrap;
}
}
/*------------------------------------------------------------------------------
Function: h264bsdCheckGapsInFrameNum
Functional description:
Function to check gaps in frame_num and generate non-existing
(short term) reference pictures if necessary. This function should
be called only for non-IDR pictures.
Inputs:
dpb pointer to dpb data structure
frameNum frame number of the current picture
isRefPic flag to indicate if current picture is a reference or
non-reference picture
gapsAllowed Flag which indicates active SPS stance on whether
to allow gaps
Outputs:
dpb 'buffer' possibly modified by inserting non-existing
pictures with sliding window marking process
Returns:
HANTRO_OK success
HANTRO_NOK error in sliding window reference picture marking or
frameNum equal to previous reference frame used for
a reference picture
------------------------------------------------------------------------------*/
u32 h264bsdCheckGapsInFrameNum(dpbStorage_t *dpb, u32 frameNum, u32 isRefPic,
u32 gapsAllowed)
{
/* Variables */
u32 unUsedShortTermFrameNum;
u8 *tmp;
/* Code */
ASSERT(dpb);
ASSERT(dpb->fullness <= dpb->dpbSize);
ASSERT(frameNum < dpb->maxFrameNum);
dpb->numOut = 0;
dpb->outIndex = 0;
if(!gapsAllowed)
return(HANTRO_OK);
if ( (frameNum != dpb->prevRefFrameNum) &&
(frameNum != ((dpb->prevRefFrameNum + 1) % dpb->maxFrameNum)))
{
unUsedShortTermFrameNum = (dpb->prevRefFrameNum + 1) % dpb->maxFrameNum;
/* store data pointer of last buffer position to be used as next
* "allocated" data pointer if last buffer position after this process
* contains data pointer located in outBuf (buffer placed in the output
* shall not be overwritten by the current picture) */
tmp = dpb->buffer[dpb->dpbSize].data;
do
{
SetPicNums(dpb, unUsedShortTermFrameNum);
if (SlidingWindowRefPicMarking(dpb) != HANTRO_OK)
{
return(HANTRO_NOK);
}
/* output pictures if buffer full */
while (dpb->fullness >= dpb->dpbSize)
{
#ifdef _ASSERT_USED
ASSERT(!dpb->noReordering);
ASSERT(OutputPicture(dpb) == HANTRO_OK);
#else
OutputPicture(dpb);
#endif
}
/* add to end of list */
ASSERT( !dpb->buffer[dpb->dpbSize].toBeDisplayed &&
!IS_REFERENCE(dpb->buffer[dpb->dpbSize]) );
dpb->buffer[dpb->dpbSize].status = NON_EXISTING;
dpb->buffer[dpb->dpbSize].frameNum = unUsedShortTermFrameNum;
dpb->buffer[dpb->dpbSize].picNum = (i32)unUsedShortTermFrameNum;
dpb->buffer[dpb->dpbSize].picOrderCnt = 0;
dpb->buffer[dpb->dpbSize].toBeDisplayed = HANTRO_FALSE;
dpb->fullness++;
dpb->numRefFrames++;
/* sort the buffer */
ShellSort(dpb->buffer, dpb->dpbSize+1);
unUsedShortTermFrameNum = (unUsedShortTermFrameNum + 1) %
dpb->maxFrameNum;
} while (unUsedShortTermFrameNum != frameNum);
/* pictures placed in output buffer -> check that 'data' in
* buffer position dpbSize is not in the output buffer (this will be
* "allocated" by h264bsdAllocateDpbImage). If it is -> exchange data
* pointer with the one stored in the beginning */
if (dpb->numOut)
{
u32 i;
for (i = 0; i < dpb->numOut; i++)
{
if (dpb->outBuf[i].data == dpb->buffer[dpb->dpbSize].data)
{
/* find buffer position containing data pointer stored in
* tmp */
for (i = 0; i < dpb->dpbSize; i++)
{
if (dpb->buffer[i].data == tmp)
{
dpb->buffer[i].data =
dpb->buffer[dpb->dpbSize].data;
dpb->buffer[dpb->dpbSize].data = tmp;
break;
}
}
ASSERT(i < dpb->dpbSize);
break;
}
}
}
}
/* frameNum for reference pictures shall not be the same as for previous
* reference picture, otherwise accesses to pictures in the buffer cannot
* be solved unambiguously */
else if (isRefPic && frameNum == dpb->prevRefFrameNum)
{
return(HANTRO_NOK);
}
/* save current frame_num in prevRefFrameNum. For non-reference frame
* prevFrameNum is set to frame number of last non-existing frame above */
if (isRefPic)
dpb->prevRefFrameNum = frameNum;
else if (frameNum != dpb->prevRefFrameNum)
{
dpb->prevRefFrameNum =
(frameNum + dpb->maxFrameNum - 1) % dpb->maxFrameNum;
}
return(HANTRO_OK);
}
/*------------------------------------------------------------------------------
Function: FindSmallestPicOrderCnt
Functional description:
Function to find picture with smallest picture order count. This
will be the next picture in display order.
Returns:
pointer to the picture, NULL if no pictures to be displayed
------------------------------------------------------------------------------*/
dpbPicture_t* FindSmallestPicOrderCnt(dpbStorage_t *dpb)
{
/* Variables */
u32 i;
i32 picOrderCnt;
dpbPicture_t *tmp;
/* Code */
ASSERT(dpb);
picOrderCnt = 0x7FFFFFFF;
tmp = NULL;
for (i = 0; i <= dpb->dpbSize; i++)
{
if (dpb->buffer[i].toBeDisplayed &&
(dpb->buffer[i].picOrderCnt < picOrderCnt))
{
tmp = dpb->buffer + i;
picOrderCnt = dpb->buffer[i].picOrderCnt;
}
}
return(tmp);
}
/*------------------------------------------------------------------------------
Function: OutputPicture
Functional description:
Function to put next display order picture into the output buffer.
Returns:
HANTRO_OK success
HANTRO_NOK no pictures to display
------------------------------------------------------------------------------*/
u32 OutputPicture(dpbStorage_t *dpb)
{
/* Variables */
dpbPicture_t *tmp;
/* Code */
ASSERT(dpb);
if (dpb->noReordering)
return(HANTRO_NOK);
tmp = FindSmallestPicOrderCnt(dpb);
/* no pictures to be displayed */
if (tmp == NULL)
return(HANTRO_NOK);
dpb->outBuf[dpb->numOut].data = tmp->data;
dpb->outBuf[dpb->numOut].isIdr = tmp->isIdr;
dpb->outBuf[dpb->numOut].picId = tmp->picId;
dpb->outBuf[dpb->numOut].numErrMbs = tmp->numErrMbs;
dpb->numOut++;
tmp->toBeDisplayed = HANTRO_FALSE;
if (!IS_REFERENCE(*tmp))
{
dpb->fullness--;
}
return(HANTRO_OK);
}
/*------------------------------------------------------------------------------
Function: h264bsdDpbOutputPicture
Functional description:
Function to get next display order picture from the output buffer.
Return:
pointer to output picture structure, NULL if no pictures to
display
------------------------------------------------------------------------------*/
dpbOutPicture_t* h264bsdDpbOutputPicture(dpbStorage_t *dpb)
{
/* Variables */
/* Code */
ASSERT(dpb);
if (dpb->outIndex < dpb->numOut)
return(dpb->outBuf + dpb->outIndex++);
else
return(NULL);
}
/*------------------------------------------------------------------------------
Function: h264bsdFlushDpb
Functional description:
Function to flush the DPB. Function puts all pictures needed for
display into the output buffer. This function shall be called in
the end of the stream to obtain pictures buffered for display
re-ordering purposes.
------------------------------------------------------------------------------*/
void h264bsdFlushDpb(dpbStorage_t *dpb)
{
/* don't do anything if buffer not reserved */
if (dpb->buffer)
{
dpb->flushed = 1;
/* output all pictures */
while (OutputPicture(dpb) == HANTRO_OK)
;
}
}
/*------------------------------------------------------------------------------
Function: h264bsdFreeDpb
Functional description:
Function to free memories reserved for the DPB.
------------------------------------------------------------------------------*/
void h264bsdFreeDpb(dpbStorage_t *dpb)
{
/* Variables */
u32 i;
/* Code */
ASSERT(dpb);
if (dpb->buffer)
{
for (i = 0; i < dpb->dpbSize+1; i++)
{
FREE(dpb->buffer[i].pAllocatedData);
}
}
FREE(dpb->buffer);
FREE(dpb->list);
FREE(dpb->outBuf);
}
/*------------------------------------------------------------------------------
Function: ShellSort
Functional description:
Sort pictures in the buffer. Function implements Shell's method,
i.e. diminishing increment sort. See e.g. "Numerical Recipes in C"
for more information.
------------------------------------------------------------------------------*/
static void ShellSort(dpbPicture_t *pPic, u32 num)
{
u32 i, j;
u32 step;
dpbPicture_t tmpPic;
step = 7;
while (step)
{
for (i = step; i < num; i++)
{
tmpPic = pPic[i];
j = i;
while (j >= step && ComparePictures(pPic + j - step, &tmpPic) > 0)
{
pPic[j] = pPic[j-step];
j -= step;
}
pPic[j] = tmpPic;
}
step >>= 1;
}
}