/*
* 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 "bitbuffer.h"
#include "vld.h"
#include "macroblock.h"
#include "parameterset.h"
#include "framebuffer.h"
#include "dpb.h"
#include "slice.h"
#include "sequence.h"
#define MIN_ALPHA_BETA_OFFSET -6
#define MAX_ALPHA_BETA_OFFSET 6
/*
* AVC syntax functions as specified in specification
*/
/*
* Static functions
*/
static int getRefPicListReorderingCmds(slice_s *slice, unsigned int numRefFrames,
bitbuffer_s *bitbuf);
static int getDecRefPicMarkingCmds(slice_s *slice, unsigned int numRefFrames,
bitbuffer_s *bitbuf);
static int refPicListReordering(slice_s *slice, dpb_s *dpb,
frmBuf_s *refPicList[], int numRefPicActive,
sliceRefPicListReorderCmd_s reorderCmdList[]);
/*
* AVC syntax functions as specified in specification
*/
/* Return fixed length code */
static int u_n(bitbuffer_s *bitbuf, int len, unsigned int *val)
{
*val = vldGetFLC(bitbuf, len);
if (bibGetStatus(bitbuf) < 0)
return SLICE_ERROR;
return SLICE_OK;
}
/* Return unsigned UVLC code */
static int ue_v(bitbuffer_s *bitbuf, unsigned int *val, unsigned int maxVal)
{
*val = vldGetUVLC(bitbuf);
if (bibGetStatus(bitbuf) < 0)
return SLICE_ERROR;
if (*val > maxVal)
return SLICE_ERR_ILLEGAL_VALUE;
return SLICE_OK;
}
/* Return signed UVLC code */
static int se_v(bitbuffer_s *bitbuf, int *val, int minVal, int maxVal)
{
*val = vldGetSignedUVLC(bitbuf);
if (bibGetStatus(bitbuf) < 0)
return SLICE_ERROR;
if (*val < minVal || *val > maxVal)
return SLICE_ERR_ILLEGAL_VALUE;
return SLICE_OK;
}
/* Return long signed UVLC code */
static int se_v_long(bitbuffer_s *bitbuf, int32 *val)
{
*val = vldGetSignedUVLClong(bitbuf);
if (bibGetStatus(bitbuf) < 0)
return SLICE_ERROR;
return SLICE_OK;
}
/*
*
* sliceOpen:
*
* Parameters:
*
* Function:
* Allocate and initialize a slice.
*
* Returns:
* Pointer to slice
*
*/
slice_s *sliceOpen()
{
slice_s *slice;
slice = (slice_s *)User::Alloc(sizeof(slice_s));
if (slice != NULL)
memset(slice, 0, sizeof(slice_s));
return slice;
}
/*
*
* sliceClose:
*
* Parameters:
* slice Slice object
*
* Function:
* Deallocate slice
*
* Returns:
* Nothing
*
*/
void sliceClose(slice_s *slice)
{
User::Free(slice);
}
/*
* getRefPicListReorderingCmds:
*
* Parameters:
* slice Slice object
* bitbuf Bitbuffer object
* numRefFrames Number of reference frames in used
*
* Function:
* Parse and store the ref pic reordering commands
*
* Return:
* The number of bits being parsed
*/
static int getRefPicListReorderingCmds(slice_s *slice, unsigned int numRefFrames,
bitbuffer_s *bitbuf)
{
int i;
unsigned int reordering_of_pic_nums_idc;
int retCode;
if (!IS_SLICE_I(slice->slice_type)) {
if ((retCode = u_n(bitbuf, 1, &slice->ref_pic_list_reordering_flag0)) < 0)
return retCode;
if (slice->ref_pic_list_reordering_flag0) {
i = 0;
do {
/* Get command */
if ((retCode = ue_v(bitbuf, &reordering_of_pic_nums_idc, 3)) < 0)
return retCode;
slice->reorderCmdList[i].reordering_of_pic_nums_idc = reordering_of_pic_nums_idc;
/* Get command parameters */
if (reordering_of_pic_nums_idc == 0 || reordering_of_pic_nums_idc == 1) {
unsigned int maxDiff = slice->maxFrameNum/2-1;
if (reordering_of_pic_nums_idc == 1)
maxDiff = maxDiff - 1;
if ((retCode = ue_v(bitbuf, &slice->reorderCmdList[i].abs_diff_pic_num_minus1, maxDiff)) < 0)
return retCode;
}
else if (reordering_of_pic_nums_idc == 2) {
/* longTermPicNum be in the range of 0 to num_ref_frames, inclusive. */
if ((retCode = ue_v(bitbuf, &slice->reorderCmdList[i].long_term_pic_num, numRefFrames)) < 0)
return retCode;
}
i++;
} while (reordering_of_pic_nums_idc != 3 && i < MAX_NUM_OF_REORDER_CMDS);
}
}
return SLICE_OK;
}
/*
* getDecRefPicMarkingCmds:
*
* Parameters:
* slice Slice object
* bitbuf Bitbuffer object
* numRefFrames Number of reference frames in used
*
* Function:
* Parse and store the MMCO commands
*
* Return:
* The number of bits being parsed
*/
static int getDecRefPicMarkingCmds(slice_s *slice, unsigned int numRefFrames,
bitbuffer_s *bitbuf)
{
int i;
unsigned int mmco;
int retCode;
/* MMCO commands can exist only in slice header of a reference picture */
if (slice->nalRefIdc != 0) {
if (slice->isIDR) {
if ((retCode = u_n(bitbuf, 1, &slice->no_output_of_prior_pics_flag)) < 0)
return retCode;
if ((retCode = u_n(bitbuf, 1, &slice->long_term_reference_flag)) < 0)
return retCode;
}
else {
if ((retCode = u_n(bitbuf, 1, &slice->adaptive_ref_pic_marking_mode_flag)) < 0)
return retCode;
if (slice->adaptive_ref_pic_marking_mode_flag) {
i = 0;
do {
/* Get MMCO command */
if ((retCode = ue_v(bitbuf, &mmco, 6)) < 0)
return retCode;
slice->mmcoCmdList[i].memory_management_control_operation = mmco;
/* Get command parameter (if any) */
if (mmco == 1 || mmco == 3) {
if ((retCode = ue_v(bitbuf, &slice->mmcoCmdList[i].difference_of_pic_nums_minus1, 65535)) < 0)
return retCode;
}
if (mmco == 2) {
if ((retCode = ue_v(bitbuf, &slice->mmcoCmdList[i].long_term_pic_num, numRefFrames)) < 0)
return retCode;
}
if (mmco == 3 || mmco == 6) {
if ((retCode = ue_v(bitbuf, &slice->mmcoCmdList[i].long_term_frame_idx, numRefFrames)) < 0)
return retCode;
}
if (mmco == 4) {
if ((retCode = ue_v(bitbuf, &slice->mmcoCmdList[i].max_long_term_frame_idx_plus1, numRefFrames)) < 0)
return retCode;
}
if (mmco == 5) {
slice->picHasMMCO5 = 1;
}
i++;
} while (mmco != 0 && i < MAX_NUM_OF_MMCO_OPS);
}
}
}
else
slice->adaptive_ref_pic_marking_mode_flag = 0;
return 1;
}
/*
* sliceInitRefPicList:
*
* Parameters:
* dpb DPB buffer
* refPicList Reference picture list (output)
*
* Fucntion:
* Initialize reference picture list.
*
* Return:
* Number of reference frames in the list
*/
int sliceInitRefPicList(dpb_s *dpb, frmBuf_s *refPicList[])
{
int numRef, numShort;
frmBuf_s *refTmp;
int i, j;
/*
* Select the reference pictures from the DPB
*/
j = 0;
/* Put short term pictures first in the list */
for (i = 0; i < dpb->fullness; i++) {
if (dpb->buffers[i]->refType == FRM_SHORT_TERM_PIC)
refPicList[j++] = dpb->buffers[i];
}
numShort = j;
/* Put long term pictures after the short term pictures */
for (i = 0; i < dpb->fullness; i++) {
if (dpb->buffers[i]->refType == FRM_LONG_TERM_PIC)
refPicList[j++] = dpb->buffers[i];
}
numRef = j;
/* numLong = numRef - numShort; */
/*
* Initialisation process for reference picture lists
*/
/* Sort short term pictures in the order of descending picNum */
for (i = 0; i < numShort; i++) {
for (j = i+1; j < numShort; j++) {
if (refPicList[i]->picNum < refPicList[j]->picNum) {
/* exchange refPicList[i] and refPicList[j] */
refTmp = refPicList[i];
refPicList[i] = refPicList[j];
refPicList[j] = refTmp;
}
}
}
/* Sort long term pictures in the order of ascending longTermPicNum */
for (i = numShort; i < numRef; i++) {
for (j = i+1; j < numRef; j++) {
if (refPicList[i]->longTermPicNum > refPicList[j]->longTermPicNum) {
/* exchange refPicList[i] and refPicList[j] */
refTmp = refPicList[i];
refPicList[i] = refPicList[j];
refPicList[j] = refTmp;
}
}
}
return numRef;
}
/*
* sliceFixRefPicList:
*
* Parameters:
* dpb DPB buffer
* refPicList Reference picture list (output)
* numRefPicActive Number of active reference frames
* numExistingRefFrames Number of reference frames in refPicList
*
* Fucntion:
* If numExistingRefFrames < numRefPicActive, try to fill up the
* reference frame list
*
* Return:
* 0 for no pictures exist in reference frame list
* 1 for pictures exist in reference frame list
*/
int sliceFixRefPicList(dpb_s *dpb, frmBuf_s *refPicList[],
int numRefPicActive, int numExistingRefFrames,
int width, int height)
{
int i;
if (numExistingRefFrames == 0) {
/* Try to find any picture in DPB, even non-reference frame */
for (i = 0; i < dpb->size; i++) {
if (dpb->buffers[i] != NULL && dpb->buffers[i]->width == width && dpb->buffers[i]->height == height)
break;
}
if (i < dpb->size) {
refPicList[0] = dpb->buffers[i];
numExistingRefFrames = 1;
}
else
return 0;
}
/* Duplicate last extry of the reference frame list so that list becomes full */
for (i = numExistingRefFrames; i < numRefPicActive; i++)
refPicList[i] = refPicList[numExistingRefFrames-1];
return 1;
}
/*
* refPicListReordering:
*
* Parameters:
* slice Current slice object
* dpb DPB buffer
* refPicList Reference picture list (modified by this function)
* numRefPicActive Number of active reference frames
* reorderCmdList Reordering command list
*
* Fucntion:
* Reorder the reference picture list for current slice
*
* Return:
* SLICE_OK for no error and negative value for error
*/
static int refPicListReordering(slice_s *slice, dpb_s *dpb,
frmBuf_s *refPicList[], int numRefPicActive,
sliceRefPicListReorderCmd_s reorderCmdList[])
{
int i;
int reordering_of_pic_nums_idc, longTermPicNum;
int32 absDiffPicNum;
int refIdx;
int32 currPicNum, picNumPred, picNumNoWrap;
int32 maxPicNum, picNum;
int cmdNum;
int cIdx, nIdx;
/*
* 3. Reordering process for reference picture list
*/
maxPicNum = slice->maxFrameNum; /* for frame coding only */
currPicNum = slice->frame_num;
picNumPred = currPicNum;
refIdx = 0;
cmdNum = 0;
do {
reordering_of_pic_nums_idc = reorderCmdList[cmdNum].reordering_of_pic_nums_idc;
if (reordering_of_pic_nums_idc == 0 || reordering_of_pic_nums_idc == 1) {
/*
* reorder short-term ref pic -subclause 8.2.4.3.1
*/
absDiffPicNum = reorderCmdList[cmdNum].abs_diff_pic_num_minus1 + 1;
/* Derive picNumNoWrap */
if (reordering_of_pic_nums_idc == 0) {
if (picNumPred - absDiffPicNum < 0)
picNumNoWrap = picNumPred - absDiffPicNum + maxPicNum;
else
picNumNoWrap = picNumPred - absDiffPicNum;
}
else { /* reordering_of_pic_nums_idc == 1 */
if (picNumPred + absDiffPicNum >= maxPicNum)
picNumNoWrap = picNumPred + absDiffPicNum - maxPicNum;
else
picNumNoWrap = picNumPred + absDiffPicNum;
}
/* Derive picNum */
if (picNumNoWrap > currPicNum)
picNum = picNumNoWrap - maxPicNum;
else
picNum = picNumNoWrap;
/* Find short term picture with picture number picNum */
for (i = 0; i < dpb->fullness; i++) {
if (!dpb->buffers[i]->nonExisting &&
dpb->buffers[i]->refType == FRM_SHORT_TERM_PIC &&
dpb->buffers[i]->picNum == picNum)
break;
}
/* If picNum was not found */
if (i == dpb->fullness) {
PRINT((_L("The short term ref pic(%d) is not found!\n"), picNum));
return SLICE_ERR_ILLEGAL_VALUE;
}
/* Shift remaining pictures later in the list */
for (cIdx = numRefPicActive; cIdx > refIdx; cIdx--)
refPicList[cIdx] = refPicList[cIdx - 1];
/* Place picture with number picNum into the index position refIdx */
refPicList[refIdx++] = dpb->buffers[i];
/* Remove duplicate of the inserted picture */
nIdx = refIdx;
for (cIdx = refIdx; cIdx <= numRefPicActive; cIdx++)
if (refPicList[cIdx]->refType == FRM_LONG_TERM_PIC || refPicList[cIdx]->picNum != picNum)
refPicList[nIdx++] = refPicList[cIdx];
picNumPred = picNumNoWrap;
}
else if (reordering_of_pic_nums_idc == 2) {
/*
* reorder long-term ref pic -subclause 8.2.4.3.2
*/
/* Get long-term picture number */
longTermPicNum = reorderCmdList[cmdNum].long_term_pic_num;
/* Find long-term picture with picture number longTermPicNum */
for (i = 0; i < dpb->fullness; i++)
if (dpb->buffers[i]->refType == FRM_LONG_TERM_PIC &&
dpb->buffers[i]->longTermPicNum == longTermPicNum)
break;
if (i == dpb->fullness) {
// something wrong !
PRINT((_L("The long term ref pic(%d) is not found!\n"), longTermPicNum));
return SLICE_ERR_ILLEGAL_VALUE;
}
/* Shift remaining pictures later in the list */
for (cIdx = numRefPicActive; cIdx > refIdx; cIdx--)
refPicList[cIdx] = refPicList[cIdx - 1];
/* Place picture with number longTermPicNum into the index position refIdx */
refPicList[refIdx++] = dpb->buffers[i];
/* Remove duplicate of the inserted picture */
nIdx = refIdx;
for (cIdx = refIdx; cIdx <= numRefPicActive; cIdx++)
if (refPicList[cIdx]->refType == FRM_SHORT_TERM_PIC ||
refPicList[cIdx]->longTermPicNum != longTermPicNum)
{
refPicList[nIdx++] = refPicList[cIdx];
}
}
cmdNum++;
} while (reordering_of_pic_nums_idc != 3 && cmdNum < MAX_NUM_OF_REORDER_CMDS);
refPicList[numRefPicActive] = 0;
return SLICE_OK;
}
// sliceParseMacroblocks
// Parses the macroblocks one by one in the input slice.
TInt sliceParseMacroblocks(slice_s *slice, frmBuf_s *recoBuf, dpb_s *dpb,
pic_parameter_set_s *pps,
mbAttributes_s *mbData, TInt sliceID,
bitbuffer_s *bitbuf,
TBool aBitShiftInSlice)
{
frmBuf_s *refPicList0[DPB_MAX_SIZE+1];
macroblock_s mb;
TInt numRefFrames;
TInt numExistingRefFrames;
// TInt refFramesExist;
TInt mbIdxY;
TInt mbIdxX;
TInt mbksPerLine;
TInt mbksPerCol;
TInt picSizeInMbs;
TInt currMbAddr;
TInt sliceGroupNum;
void *stream;
TInt retCode;
// Choose number of reference frames and build reference picture list
numRefFrames = 0;
// refFramesExist = 0;
if (!IS_SLICE_I(slice->slice_type))
{
if (slice->num_ref_idx_active_override_flag)
numRefFrames = slice->num_ref_idx_l0_active_minus1 + 1;
else
numRefFrames = pps->num_ref_idx_l0_active_minus1 + 1;
numExistingRefFrames = sliceInitRefPicList(dpb, refPicList0);
if (numExistingRefFrames < numRefFrames)
{
// refFramesExist = sliceFixRefPicList(dpb, refPicList0, numRefFrames, numExistingRefFrames,
// recoBuf->width, recoBuf->height);
}
else
// refFramesExist = 1;
if (slice->ref_pic_list_reordering_flag0 && numExistingRefFrames > 0)
{
retCode = refPicListReordering(slice, dpb, refPicList0, numRefFrames, slice->reorderCmdList);
if (retCode < 0)
return retCode;
}
}
mbksPerLine = recoBuf->width/MBK_SIZE;
mbksPerCol = recoBuf->height/MBK_SIZE;
picSizeInMbs = mbksPerLine*mbksPerCol;
currMbAddr = slice->first_mb_in_slice;
sliceGroupNum = sliceID & 0xF;
mbIdxY = currMbAddr / mbksPerLine;
mbIdxX = currMbAddr - mbIdxY*mbksPerLine;
mbkSetInitialQP(&mb, slice->qp, pps->chroma_qp_index_offset);
stream = bitbuf;
// Loop until all macroblocks in current slice have been decoded
// If there has been a bitshift in the slice, we must go through
// the macroblocks to see if any PCM coded MB are used.
if(aBitShiftInSlice)
{
do
{
// Store slice ID for current macroblock
mbData->sliceMap[currMbAddr] = sliceID;
// Store loopfilter mode
mbData->filterModeTab[currMbAddr] = (int8) slice->disable_deblocking_filter_idc;
mbData->alphaOffset[currMbAddr] = (int8) (slice->slice_alpha_c0_offset_div2*2);
mbData->betaOffset[currMbAddr] = (int8) (slice->slice_beta_offset_div2*2);
retCode = mbkParse(&mb, numRefFrames,
mbData, recoBuf->width,
slice->slice_type, pps->constrained_intra_pred_flag,
pps->chroma_qp_index_offset,
mbIdxX, mbIdxY, stream, slice->bitOffset);
if (retCode == MBK_PCM_FOUND)
{
// We can stop parsing this slice
// Check later if this is the case also if we have slices in more than one NAL (is it even possible?)!!!
return SLICE_OK;
}
if (retCode < 0)
return SLICE_ERROR;
// If end of slice data has been reached and there are no
// skipped macroblocks left, stop decoding slice.
if (!bibMoreRbspData(bitbuf) && mb.numSkipped <= 0)
break;
// Find next mb address in the current slice group
do
{
// Next mb address
currMbAddr++;
// If end of frame was reached, stop search
if (currMbAddr == picSizeInMbs)
break;
// Update mb location
mbIdxX++;
if (mbIdxX == mbksPerLine)
{
mbIdxX = 0;
mbIdxY++;
}
} while ((mbData->sliceMap[currMbAddr] & 0xF) != sliceGroupNum);
// If end of frame was reached, stop decoding slice
} while (currMbAddr < picSizeInMbs);
}
return SLICE_OK;
}
// EncodeUnsignedNBits
// Encodes the input aValue to the bit buffer with aLength bits.
void EncodeUnsignedNBits(bitbuffer_s *aBitBuffer, TUint aValue, TUint aLength)
{
TUint tempValue;
TInt i;
TUint8 byteValue;
if(aBitBuffer->bitpos == 0)
{
// Get the next byte
aBitBuffer->currentBits = aBitBuffer->data[aBitBuffer->bytePos];
aBitBuffer->bytePos++;
aBitBuffer->bitpos = 8;
}
// Write aValue bit by bit to the bit buffer
for (i=aLength-1; i>=0; i--)
{
// Get the ith bit from aValue
tempValue = (aValue & (1 << i)) >> i;
// Zero out the bitpos bit
byteValue = aBitBuffer->data[aBitBuffer->bytePos-1] & ~(1<<(aBitBuffer->bitpos-1));
byteValue |= tempValue << (aBitBuffer->bitpos-1);
aBitBuffer->data[aBitBuffer->bytePos-1] = byteValue;
aBitBuffer->bitpos--;
if(aBitBuffer->bitpos == 0)
{
// Get the next byte
aBitBuffer->currentBits = aBitBuffer->data[aBitBuffer->bytePos];
aBitBuffer->bytePos++;
aBitBuffer->bitpos = 8;
}
}
// Make sure the bit buffer currentBits is up-to-date
aBitBuffer->currentBits = aBitBuffer->data[aBitBuffer->bytePos-1];
}
// ParseSliceHeader
// Parses the input slice header. PPS Id, frame numbering and POC LSB are modified if required.
TInt ParseSliceHeader(slice_s *slice, seq_parameter_set_s *spsList[],
pic_parameter_set_s *ppsList[], bitbuffer_s *bitbuf,
TUint* aFrameNumber, TUint aFrameFromEncoder)
{
seq_parameter_set_s *sps;
pic_parameter_set_s *pps;
TUint picSizeInMapUnits;
TUint temp, temp2;
TInt sliceQp, len1;
TInt retCode;
TInt shiftedBits = 0;
slice->picHasMMCO5 = 0;
// Initialize the bit offset to zero
slice->bitOffset = 0;
// First macroblock in slice
if ((retCode = ue_v(bitbuf, &slice->first_mb_in_slice, 65535)) < 0)
return retCode;
// Slice type
if ((retCode = ue_v(bitbuf, &slice->slice_type, SLICE_MAX)) < 0)
return retCode;
// PPS id
if ((retCode = ue_v(bitbuf, &slice->pic_parameter_set_id, PS_MAX_NUM_OF_PPS-1)) < 0)
return retCode;
pps = ppsList[slice->pic_parameter_set_id];
if (pps == NULL)
{
PRINT((_L("Error: referring to non-existing PPS.\n")));
return SLICE_ERR_NON_EXISTING_PPS;
}
syncBitBufferBitpos(bitbuf);
// If the index has been changed the new index must be coded instead of
// the old one to the slice header
if (pps->indexChanged)
{
// We have to encode the new PPS Id to the bitbuffer
TUint oldPPSId = slice->pic_parameter_set_id;
TUint newPPSId;
if ( aFrameFromEncoder )
newPPSId = pps->encPPSId;
else
newPPSId = pps->origPPSId;
TUint trailingBits = GetNumTrailingBits(bitbuf);
TInt diff = 0;
TUint oldIdLength = ReturnUnsignedExpGolombCodeLength(oldPPSId);
TUint newIdLength = ReturnUnsignedExpGolombCodeLength(newPPSId);
// Signal that the slice data has been modified
slice->sliceDataModified = 1;
// Get the new pps
pps = ppsList[newPPSId];
if(trailingBits > 8)
{
trailingBits = 8;
}
if ( oldIdLength == newIdLength )
{
// Just encode the new Id on top of the old Id
bitbuf->bitpos += oldIdLength;
if(bitbuf->bitpos > 8)
{
// Go to the right byte and bit position
bitbuf->bytePos -= bitbuf->bitpos / 8;
bitbuf->bitpos = bitbuf->bitpos % 8;
}
EncodeUnsignedExpGolombCode(bitbuf, newPPSId);
}
else if ( oldIdLength < newIdLength )
{
diff = newIdLength - oldIdLength;
// Positive bit offset indicates bit-wise shift to right
slice->bitOffset = (diff % 8);
ShiftBufferRight(bitbuf, diff, trailingBits, oldIdLength);
// After shifting, encode the new value to the bit buffer
EncodeUnsignedExpGolombCode(bitbuf, newPPSId);
}
else
{
// New id's length is smaller than old id's length
diff = oldIdLength - newIdLength;
// Negative bit offset indicates bit-wise shift to left
slice->bitOffset = -(diff % 8);
ShiftBufferLeft(bitbuf, diff, oldIdLength);
// After shifting, encode the new value to the bit buffer
EncodeUnsignedExpGolombCode(bitbuf, newPPSId);
}
shiftedBits = diff;
}
sps = spsList[pps->seq_parameter_set_id];
if (sps == NULL)
{
PRINT((_L("Error: referring to non-existing SPS.\n")));
return SLICE_ERR_NON_EXISTING_SPS;
}
picSizeInMapUnits = (sps->pic_width_in_mbs_minus1+1) * (sps->pic_height_in_map_units_minus1+1);
if (slice->first_mb_in_slice >= picSizeInMapUnits)
return SLICE_ERR_ILLEGAL_VALUE;
// Maximum frame number
slice->maxFrameNum = (TUint)1 << (sps->log2_max_frame_num_minus4+4);
// IDR type NAL unit shall have frame number as zero
if ( slice->nalType == NAL_TYPE_CODED_SLICE_IDR )
{
// Reset frame number for an IDR slice
*aFrameNumber = 0;
}
else if ( *aFrameNumber == (slice->maxFrameNum - 1 ) )
{
// Reset frame number if maximum frame number has been reached
*aFrameNumber = 0;
}
else if( !slice->first_mb_in_slice )
{
(*aFrameNumber)++; // Increment frame number only if this is the first mb in slice
}
if (sps->maxFrameNumChanged)
{
// Frame number field size
TUint oldFrameNum;
TUint newFrameNum = sps->log2_max_frame_num_minus4+4;
if ( aFrameFromEncoder )
oldFrameNum = sps->encMaxFrameNum+4;
else
oldFrameNum = sps->origMaxFrameNum+4;
TUint trailingBits = GetNumTrailingBits(bitbuf);
TInt diff = 0;
// Signal that the slice data has been modified
slice->sliceDataModified = 1;
if(trailingBits > 8)
{
trailingBits = 8;
}
// If the size of the frame number field has changed then shift bits in the buffer
if ( oldFrameNum < newFrameNum )
{
diff = newFrameNum - oldFrameNum;
// Positive bit offset indicates bit-wise shift to right
slice->bitOffset += (diff % 8);
ShiftBufferRight(bitbuf, diff, trailingBits, 0);
}
else if ( oldFrameNum > newFrameNum )
{
// New id's length is smaller than old id's length
diff = oldFrameNum - newFrameNum;
// Negative bit offset indicates bit-wise shift to left
slice->bitOffset -= (diff % 8);
ShiftBufferLeft(bitbuf, diff, 0);
}
shiftedBits += diff;
}
// Encode the new frame number here
EncodeUnsignedNBits(bitbuf, *aFrameNumber, sps->log2_max_frame_num_minus4+4);
slice->frame_num = *aFrameNumber;
// IDR picture
if (slice->isIDR)
{
if ((retCode = ue_v(bitbuf, &slice->idr_pic_id, 65535)) < 0)
return retCode;
}
syncBitBufferBitpos(bitbuf);
// POC parameters
if (sps->pic_order_cnt_type == 0)
{
if (sps->maxPOCNumChanged)
{
// POC lsb number
TUint oldPOCNum;
TUint newPOCNum = sps->log2_max_pic_order_cnt_lsb_minus4+4;
if ( aFrameFromEncoder )
oldPOCNum = sps->encMaxPOCNum+4;
else
oldPOCNum = sps->origMaxPOCNum+4;
TUint trailingBits = GetNumTrailingBits(bitbuf);
TInt diff = 0;
// Signal that the slice data has been modified
slice->sliceDataModified = 1;
if (trailingBits > 8)
{
trailingBits = 8;
}
// If the size of the POC lsb field has changed then shift bits in the buffer
if ( oldPOCNum < newPOCNum )
{
diff = newPOCNum - oldPOCNum;
// Positive bit offset indicates bit-wise shift to right
slice->bitOffset += (diff % 8);
ShiftBufferRight(bitbuf, diff, trailingBits, 0);
}
else if ( oldPOCNum > newPOCNum )
{
// New id's length is smaller than old id's length
diff = oldPOCNum - newPOCNum;
// Negative bit offset indicates bit-wise shift to left
slice->bitOffset -= (diff % 8);
ShiftBufferLeft(bitbuf, diff, 0);
}
shiftedBits += diff;
}
// For now encode the POC as the frame number
EncodeUnsignedNBits(bitbuf, *aFrameNumber, sps->log2_max_pic_order_cnt_lsb_minus4+4);
slice->delta_pic_order_cnt_bottom = 0;
if (pps->pic_order_present_flag)
{ // && !field_pic_flag
if ((retCode = se_v_long(bitbuf, &slice->delta_pic_order_cnt_bottom)) < 0)
return retCode;
}
}
else if (sps->pic_order_cnt_type == 1)
{
slice->delta_pic_order_cnt_0 = 0;
slice->delta_pic_order_cnt_1 = 0;
// Read delta_pic_order_cnt[ 0 ] and delta_pic_order_cnt[ 1 ]
if (!sps->delta_pic_order_always_zero_flag)
{
// delta_pic_order_cnt[ 0 ]
if ((retCode = se_v_long(bitbuf, &slice->delta_pic_order_cnt_0)) < 0)
return retCode;
if (pps->pic_order_present_flag)
{ // delta_pic_order_cnt[ 1 ]
if ((retCode = se_v_long(bitbuf, &slice->delta_pic_order_cnt_1)) < 0)
return retCode;
}
}
}
// If we don't have to do any bit shifting (left or right) with the slice header,
// we can just stop parsing the header and return.
if (shiftedBits == 0)
{
return SLICE_STOP_PARSING;
}
// Redundant picture count
if (pps->redundant_pic_cnt_present_flag)
{
if ((retCode = ue_v(bitbuf, &slice->redundant_pic_cnt, 127)) < 0)
return retCode;
}
else
slice->redundant_pic_cnt = 0;
// Reference picture management
if (IS_SLICE_P(slice->slice_type))
{
if ((retCode = u_n(bitbuf, 1, &slice->num_ref_idx_active_override_flag)) < 0)
return retCode;
if (slice->num_ref_idx_active_override_flag)
{
if ((retCode = ue_v(bitbuf, &slice->num_ref_idx_l0_active_minus1, DPB_MAX_SIZE-1)) < 0)
return retCode;
}
}
// Reordering the reference picture list
retCode = getRefPicListReorderingCmds(slice, sps->num_ref_frames, bitbuf);
if (retCode < 0)
return retCode;
// Read the MMCO commands, but not do the operations until all the slices in current picture are decoded
if (slice->nalRefIdc)
{
retCode = getDecRefPicMarkingCmds(slice, sps->num_ref_frames, bitbuf);
if (retCode < 0)
return retCode;
}
// Slice quant
if ((retCode = se_v(bitbuf, &slice->slice_qp_delta, -MAX_QP, MAX_QP)) < 0)
return retCode;
sliceQp = pps->pic_init_qp_minus26 + 26 + slice->slice_qp_delta;
if (sliceQp < MIN_QP || sliceQp > MAX_QP)
{
PRINT((_L("Error: illegal slice quant.\n")));
return SLICE_ERR_ILLEGAL_VALUE;
}
slice->qp = sliceQp;
// Deblocking filter
slice->disable_deblocking_filter_idc = 0;
slice->slice_alpha_c0_offset_div2 = 0;
slice->slice_beta_offset_div2 = 0;
if (pps->deblocking_filter_parameters_present_flag == 1)
{
if ((retCode = ue_v(bitbuf, &slice->disable_deblocking_filter_idc, 2)) < 0)
return retCode;
if (slice->disable_deblocking_filter_idc != 1)
{
if ((retCode = se_v(bitbuf, &slice->slice_alpha_c0_offset_div2, MIN_ALPHA_BETA_OFFSET, MAX_ALPHA_BETA_OFFSET)) < 0)
return retCode;
if ((retCode = se_v(bitbuf, &slice->slice_beta_offset_div2, MIN_ALPHA_BETA_OFFSET, MAX_ALPHA_BETA_OFFSET)) < 0)
return retCode;
}
}
// Read slice_group_change_cycle
if (pps->num_slice_groups_minus1 > 0 && pps->slice_group_map_type >= 3 &&
pps->slice_group_map_type <= 5)
{
// len = Ceil( Log2( PicSizeInMapUnits / SliceGroupChangeRate + 1 ) )
// PicSizeInMapUnits / SliceGroupChangeRate
temp = picSizeInMapUnits / (pps->slice_group_change_rate_minus1+1);
// Calculate Log2
temp2 = (temp + 1) >> 1;
for (len1 = 0; len1 < 16 && temp2 != 0; len1++)
temp2 >>= 1;
// Calculate Ceil
if ( (((unsigned)1) << len1) < (temp + 1) )
len1++;
if ((retCode = u_n(bitbuf, len1, &slice->slice_group_change_cycle)) < 0)
return retCode;
// Ceil( PicSizeInMapUnits/SliceGroupChangeRate )
if (temp * (pps->slice_group_change_rate_minus1+1) != picSizeInMapUnits)
temp++;
// The value of slice_group_change_cycle shall be in the range of
// 0 to Ceil( PicSizeInMapUnits/SliceGroupChangeRate ), inclusive.
if (slice->slice_group_change_cycle > temp)
return SLICE_ERR_ILLEGAL_VALUE;
}
return SLICE_OK;
}