You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1586 lines
47 KiB
1586 lines
47 KiB
2 years ago
|
/*
|
||
|
* Copyright (C) 2009 The Android Open Source Project
|
||
|
* Modified for use by h264bsd standalone library
|
||
|
*
|
||
|
* 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);
|
||
|
memset(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);
|
||
|
|
||
|
memset(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;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|