blob: c1720c63901420693cea59db2a3108b173e1ed72 [file] [log] [blame]
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* 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.
* -------------------------------------------------------------------
*/
#include "mp4dec_lib.h"
#include "vlc_decode.h"
#include "bitstream.h"
#ifndef INT32_MAX
#define INT32_MAX 0x7fffffff
#endif
#ifndef SIZE_MAX
#define SIZE_MAX ((size_t) -1)
#endif
#define OSCL_DISABLE_WARNING_CONDITIONAL_IS_CONSTANT
#ifdef DEC_INTERNAL_MEMORY_OPT
#define QCIF_MBS 99
#define QCIF_BS (4*QCIF_MBS)
#define QCIF_MB_ROWS 11
extern uint8 IMEM_sliceNo[QCIF_MBS];
extern uint8 IMEM_acPredFlag[QCIF_MBS];
extern uint8 IMEM_headerInfo_Mode[QCIF_MBS];
extern uint8 IMEM_headerInfo_CBP[QCIF_MBS];
extern int IMEM_headerInfo_QPMB[QCIF_MBS];
extern MacroBlock IMEM_mblock;
extern MOT IMEM_motX[QCIF_BS];
extern MOT IMEM_motY[QCIF_BS];
extern BitstreamDecVideo IMEM_BitstreamDecVideo[4];
extern typeDCStore IMEM_predDC[QCIF_MBS];
extern typeDCACStore IMEM_predDCAC_col[QCIF_MB_ROWS+1];
extern VideoDecData IMEM_VideoDecData[1];
extern Vop IMEM_currVop[1];
extern Vop IMEM_prevVop[1];
extern PIXEL IMEM_currVop_yChan[QCIF_MBS*128*3];
extern PIXEL IMEM_prevVop_yChan[QCIF_MBS*128*3];
extern uint8 IMEM_pstprcTypCur[6*QCIF_MBS];
extern uint8 IMEM_pstprcTypPrv[6*QCIF_MBS];
extern Vop IMEM_vopHEADER[2];
extern Vol IMEM_VOL[2];
extern Vop IMEM_vopHeader[2][1];
extern Vol IMEM_vol[2][1];
#endif
/* ======================================================================== */
/* Function : PVInitVideoDecoder() */
/* Date : 04/11/2000, 08/29/2000 */
/* Purpose : Initialization of the MPEG-4 video decoder library. */
/* The return type is Bool instead of PV_STATUS because */
/* we don't want to expose PV_STATUS to (outside) programmers */
/* that use our decoder library SDK. */
/* In/out : */
/* Return : PV_TRUE if successed, PV_FALSE if failed. */
/* Modified : */
/* ======================================================================== */
OSCL_EXPORT_REF Bool PVInitVideoDecoder(VideoDecControls *decCtrl, uint8 *volbuf[],
int32 *volbuf_size, int nLayers, int width, int height, MP4DecodingMode mode)
{
VideoDecData *video = (VideoDecData *) decCtrl->videoDecoderData;
Bool status = PV_TRUE;
int idx;
BitstreamDecVideo *stream;
oscl_memset(decCtrl, 0, sizeof(VideoDecControls)); /* fix a size bug. 03/28/2001 */
decCtrl->nLayers = nLayers;
for (idx = 0; idx < nLayers; idx++)
{
decCtrl->volbuf[idx] = volbuf[idx];
decCtrl->volbuf_size[idx] = volbuf_size[idx];
}
/* memory allocation & initialization */
#ifdef DEC_INTERNAL_MEMORY_OPT
video = IMEM_VideoDecData;
#else
video = (VideoDecData *) oscl_malloc(sizeof(VideoDecData));
#endif
if (video != NULL)
{
oscl_memset(video, 0, sizeof(VideoDecData));
video->memoryUsage = sizeof(VideoDecData);
video->numberOfLayers = nLayers;
#ifdef DEC_INTERNAL_MEMORY_OPT
video->vol = (Vol **) IMEM_VOL;
#else
if ((size_t)nLayers > SIZE_MAX / sizeof(Vol *)) {
status = PV_FALSE;
goto fail;
}
video->vol = (Vol **) oscl_malloc(nLayers * sizeof(Vol *));
#endif
if (video->vol == NULL) status = PV_FALSE;
video->memoryUsage += nLayers * sizeof(Vol *);
/* we need to setup this pointer for the application to */
/* pass it around. */
decCtrl->videoDecoderData = (void *) video;
video->videoDecControls = decCtrl; /* yes. we have a cyclic */
/* references here :) */
/* Allocating Vop space, this has to change when we add */
/* spatial scalability to the decoder */
#ifdef DEC_INTERNAL_MEMORY_OPT
video->currVop = IMEM_currVop;
if (video->currVop == NULL) status = PV_FALSE;
else oscl_memset(video->currVop, 0, sizeof(Vop));
video->prevVop = IMEM_prevVop;
if (video->prevVop == NULL) status = PV_FALSE;
else oscl_memset(video->prevVop, 0, sizeof(Vop));
video->memoryUsage += (sizeof(Vop) * 2);
video->vopHeader = (Vop **) IMEM_vopHEADER;
#else
video->currVop = (Vop *) oscl_malloc(sizeof(Vop));
if (video->currVop == NULL) status = PV_FALSE;
else oscl_memset(video->currVop, 0, sizeof(Vop));
video->prevVop = (Vop *) oscl_malloc(sizeof(Vop));
if (video->prevVop == NULL) status = PV_FALSE;
else oscl_memset(video->prevVop, 0, sizeof(Vop));
video->memoryUsage += (sizeof(Vop) * 2);
if ((size_t)nLayers > SIZE_MAX / sizeof(Vop *)) {
status = PV_FALSE;
goto fail;
}
video->vopHeader = (Vop **) oscl_malloc(sizeof(Vop *) * nLayers);
#endif
if (video->vopHeader == NULL) status = PV_FALSE;
else oscl_memset(video->vopHeader, 0, sizeof(Vop *)*nLayers);
video->memoryUsage += (sizeof(Vop *) * nLayers);
video->initialized = PV_FALSE;
/* Decode the header to get all information to allocate data */
if (status == PV_TRUE)
{
/* initialize decoded frame counter. 04/24/2001 */
video->frame_idx = -1;
for (idx = 0; idx < nLayers; idx++)
{
#ifdef DEC_INTERNAL_MEMORY_OPT
video->vopHeader[idx] = IMEM_vopHeader[idx];
#else
video->vopHeader[idx] = (Vop *) oscl_malloc(sizeof(Vop));
#endif
if (video->vopHeader[idx] == NULL)
{
status = PV_FALSE;
break;
}
else
{
oscl_memset(video->vopHeader[idx], 0, sizeof(Vop));
video->vopHeader[idx]->timeStamp = 0;
video->memoryUsage += (sizeof(Vop));
}
#ifdef DEC_INTERNAL_MEMORY_OPT
video->vol[idx] = IMEM_vol[idx];
video->memoryUsage += sizeof(Vol);
oscl_memset(video->vol[idx], 0, sizeof(Vol));
if (video->vol[idx] == NULL) status = PV_FALSE;
stream = IMEM_BitstreamDecVideo;
#else
video->vol[idx] = (Vol *) oscl_malloc(sizeof(Vol));
if (video->vol[idx] == NULL)
{
status = PV_FALSE;
break;
}
else
{
video->memoryUsage += sizeof(Vol);
oscl_memset(video->vol[idx], 0, sizeof(Vol));
}
stream = (BitstreamDecVideo *) oscl_malloc(sizeof(BitstreamDecVideo));
#endif
video->memoryUsage += sizeof(BitstreamDecVideo);
if (stream == NULL)
{
status = PV_FALSE;
break;
}
else
{
int32 buffer_size;
if ((buffer_size = BitstreamOpen(stream, idx)) < 0)
{
mp4dec_log("InitVideoDecoder(): Can't allocate bitstream buffer.\n");
status = PV_FALSE;
break;
}
video->memoryUsage += buffer_size;
video->vol[idx]->bitstream = stream;
video->vol[idx]->volID = idx;
video->vol[idx]->timeInc_offset = 0; /* 11/12/01 */
video->vlcDecCoeffIntra = &VlcDecTCOEFShortHeader;
video->vlcDecCoeffInter = &VlcDecTCOEFShortHeader;
if (mode == MPEG4_MODE)
{
/* Set up VOL header bitstream for frame-based decoding. 08/30/2000 */
BitstreamReset(stream, decCtrl->volbuf[idx], decCtrl->volbuf_size[idx]);
switch (DecodeVOLHeader(video, idx))
{
case PV_SUCCESS :
if (status == PV_TRUE)
status = PV_TRUE; /* we want to make sure that if first layer is bad, second layer is good return PV_FAIL */
else
status = PV_FALSE;
break;
#ifdef PV_TOLERATE_VOL_ERRORS
case PV_BAD_VOLHEADER:
status = PV_TRUE;
break;
#endif
default :
status = PV_FALSE;
break;
}
}
else
{
video->shortVideoHeader = PV_TRUE;
}
if (video->shortVideoHeader == PV_TRUE)
{
mode = H263_MODE;
/* Set max width and height. In H.263 mode, we use */
/* volbuf_size[0] to pass in width and volbuf_size[1] */
/* to pass in height. 04/23/2001 */
video->prevVop->temporalRef = 0; /* 11/12/01 */
/* Compute some convenience variables: 04/23/2001 */
video->vol[idx]->quantType = 0;
video->vol[idx]->quantPrecision = 5;
video->vol[idx]->errorResDisable = 1;
video->vol[idx]->dataPartitioning = 0;
video->vol[idx]->useReverseVLC = 0;
video->intra_acdcPredDisable = 1;
video->vol[idx]->scalability = 0;
video->displayWidth = width;
video->displayHeight = height;
video->width = (width + 15) & -16;
video->height = (height + 15) & -16;
video->size = (int32)video->width * video->height;
#ifdef PV_ANNEX_IJKT_SUPPORT
video->modified_quant = 0;
video->advanced_INTRA = 0;
video->deblocking = 0;
video->slice_structure = 0;
#endif
}
}
}
}
if (status != PV_FALSE)
{
status = PVAllocVideoData(decCtrl, width, height, nLayers);
video->initialized = PV_TRUE;
}
}
else
{
status = PV_FALSE;
}
fail:
if (status == PV_FALSE) PVCleanUpVideoDecoder(decCtrl);
return status;
}
Bool PVAllocVideoData(VideoDecControls *decCtrl, int width, int height, int nLayers)
{
VideoDecData *video = (VideoDecData *) decCtrl->videoDecoderData;
Bool status = PV_TRUE;
int nTotalMB;
int nMBPerRow;
int32 size;
if (video->shortVideoHeader == PV_TRUE)
{
video->displayWidth = width;
video->displayHeight = height;
video->width = (width + 15) & -16;
video->height = (height + 15) & -16;
video->nMBPerRow =
video->nMBinGOB = video->width / MB_SIZE;
video->nMBPerCol =
video->nGOBinVop = video->height / MB_SIZE;
video->nTotalMB =
video->nMBPerRow * video->nMBPerCol;
}
if (((uint64_t)video->width * video->height) > (uint64_t)INT32_MAX / sizeof(PIXEL)) {
return PV_FALSE;
}
size = (int32)sizeof(PIXEL) * video->width * video->height;
#ifdef PV_MEMORY_POOL
decCtrl->size = size;
#else
#ifdef DEC_INTERNAL_MEMORY_OPT
video->currVop->yChan = IMEM_currVop_yChan; /* Allocate memory for all VOP OKA 3/2/1*/
if (video->currVop->yChan == NULL) status = PV_FALSE;
video->currVop->uChan = video->currVop->yChan + size;
video->currVop->vChan = video->currVop->uChan + (size >> 2);
video->prevVop->yChan = IMEM_prevVop_yChan; /* Allocate memory for all VOP OKA 3/2/1*/
if (video->prevVop->yChan == NULL) status = PV_FALSE;
video->prevVop->uChan = video->prevVop->yChan + size;
video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
#else
if (size > INT32_MAX / 3) {
return PV_FALSE;
}
video->currVop->yChan = (PIXEL *) oscl_malloc(size * 3 / 2); /* Allocate memory for all VOP OKA 3/2/1*/
if (video->currVop->yChan == NULL) status = PV_FALSE;
video->currVop->uChan = video->currVop->yChan + size;
video->currVop->vChan = video->currVop->uChan + (size >> 2);
video->prevVop->yChan = (PIXEL *) oscl_malloc(size * 3 / 2); /* Allocate memory for all VOP OKA 3/2/1*/
if (video->prevVop->yChan == NULL) status = PV_FALSE;
video->prevVop->uChan = video->prevVop->yChan + size;
video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
#endif
video->memoryUsage += (size * 3);
#endif // MEMORY_POOL
/* Note that baseVop, enhcVop is only used to hold enhancement */
/* layer header information. 05/04/2000 */
if (nLayers > 1)
{
video->prevEnhcVop = (Vop *) oscl_malloc(sizeof(Vop));
video->memoryUsage += (sizeof(Vop));
if (video->prevEnhcVop == NULL)
{
status = PV_FALSE;
}
else
{
oscl_memset(video->prevEnhcVop, 0, sizeof(Vop));
#ifndef PV_MEMORY_POOL
if (size > INT32_MAX / 3) {
return PV_FALSE;
}
video->prevEnhcVop->yChan = (PIXEL *) oscl_malloc(size * 3 / 2); /* Allocate memory for all VOP OKA 3/2/1*/
if (video->prevEnhcVop->yChan == NULL) status = PV_FALSE;
video->prevEnhcVop->uChan = video->prevEnhcVop->yChan + size;
video->prevEnhcVop->vChan = video->prevEnhcVop->uChan + (size >> 2);
video->memoryUsage += (3 * size / 2);
#endif
}
}
/* Allocating space for slices, AC prediction flag, and */
/* AC/DC prediction storage */
nTotalMB = video->nTotalMB;
nMBPerRow = video->nMBPerRow;
#ifdef DEC_INTERNAL_MEMORY_OPT
video->sliceNo = (uint8 *)(IMEM_sliceNo);
if (video->sliceNo == NULL) status = PV_FALSE;
video->memoryUsage += nTotalMB;
video->acPredFlag = (uint8 *)(IMEM_acPredFlag);
if (video->acPredFlag == NULL) status = PV_FALSE;
video->memoryUsage += (nTotalMB);
video->predDC = (typeDCStore *)(IMEM_predDC);
if (video->predDC == NULL) status = PV_FALSE;
video->memoryUsage += (nTotalMB * sizeof(typeDCStore));
video->predDCAC_col = (typeDCACStore *)(IMEM_predDCAC_col);
if (video->predDCAC_col == NULL) status = PV_FALSE;
video->memoryUsage += ((nMBPerRow + 1) * sizeof(typeDCACStore));
video->predDCAC_row = video->predDCAC_col + 1;
video->headerInfo.Mode = (uint8 *)(IMEM_headerInfo_Mode);
if (video->headerInfo.Mode == NULL) status = PV_FALSE;
video->memoryUsage += nTotalMB;
video->headerInfo.CBP = (uint8 *)(IMEM_headerInfo_CBP);
if (video->headerInfo.CBP == NULL) status = PV_FALSE;
video->memoryUsage += nTotalMB;
video->QPMB = (int *)(IMEM_headerInfo_QPMB);
if (video->QPMB == NULL) status = PV_FALSE;
video->memoryUsage += (nTotalMB * sizeof(int));
video->mblock = &IMEM_mblock;
if (video->mblock == NULL) status = PV_FALSE;
oscl_memset(video->mblock->block, 0, sizeof(int16)*6*NCOEFF_BLOCK); // Aug 23,2005
video->memoryUsage += sizeof(MacroBlock);
video->motX = (MOT *)(IMEM_motX);
if (video->motX == NULL) status = PV_FALSE;
video->motY = (MOT *)(IMEM_motY);
if (video->motY == NULL) status = PV_FALSE;
video->memoryUsage += (sizeof(MOT) * 8 * nTotalMB);
#else
video->sliceNo = (uint8 *) oscl_malloc(nTotalMB);
if (video->sliceNo == NULL) status = PV_FALSE;
video->memoryUsage += nTotalMB;
video->acPredFlag = (uint8 *) oscl_malloc(nTotalMB * sizeof(uint8));
if (video->acPredFlag == NULL) status = PV_FALSE;
video->memoryUsage += (nTotalMB);
if ((size_t)nTotalMB > SIZE_MAX / sizeof(typeDCStore)) {
return PV_FALSE;
}
video->predDC = (typeDCStore *) oscl_malloc(nTotalMB * sizeof(typeDCStore));
if (video->predDC == NULL) status = PV_FALSE;
video->memoryUsage += (nTotalMB * sizeof(typeDCStore));
if (nMBPerRow > INT32_MAX - 1
|| (size_t)(nMBPerRow + 1) > SIZE_MAX / sizeof(typeDCACStore)) {
return PV_FALSE;
}
video->predDCAC_col = (typeDCACStore *) oscl_malloc((nMBPerRow + 1) * sizeof(typeDCACStore));
if (video->predDCAC_col == NULL) status = PV_FALSE;
video->memoryUsage += ((nMBPerRow + 1) * sizeof(typeDCACStore));
/* element zero will be used for storing vertical (col) AC coefficients */
/* the rest will be used for storing horizontal (row) AC coefficients */
video->predDCAC_row = video->predDCAC_col + 1; /* ACDC */
/* Allocating HeaderInfo structure & Quantizer array */
video->headerInfo.Mode = (uint8 *) oscl_malloc(nTotalMB);
if (video->headerInfo.Mode == NULL) status = PV_FALSE;
video->memoryUsage += nTotalMB;
video->headerInfo.CBP = (uint8 *) oscl_malloc(nTotalMB);
if (video->headerInfo.CBP == NULL) status = PV_FALSE;
video->memoryUsage += nTotalMB;
if ((size_t)nTotalMB > SIZE_MAX / sizeof(int16)) {
return PV_FALSE;
}
video->QPMB = (int16 *) oscl_malloc(nTotalMB * sizeof(int16));
if (video->QPMB == NULL) status = PV_FALSE;
video->memoryUsage += (nTotalMB * sizeof(int));
/* Allocating macroblock space */
video->mblock = (MacroBlock *) oscl_malloc(sizeof(MacroBlock));
if (video->mblock == NULL)
{
status = PV_FALSE;
}
else
{
oscl_memset(video->mblock->block, 0, sizeof(int16)*6*NCOEFF_BLOCK); // Aug 23,2005
video->memoryUsage += sizeof(MacroBlock);
}
/* Allocating motion vector space */
if ((size_t)nTotalMB > SIZE_MAX / (sizeof(MOT) * 4)) {
return PV_FALSE;
}
video->motX = (MOT *) oscl_malloc(sizeof(MOT) * 4 * nTotalMB);
if (video->motX == NULL) status = PV_FALSE;
video->motY = (MOT *) oscl_malloc(sizeof(MOT) * 4 * nTotalMB);
if (video->motY == NULL) status = PV_FALSE;
video->memoryUsage += (sizeof(MOT) * 8 * nTotalMB);
#endif
#ifdef PV_POSTPROC_ON
/* Allocating space for post-processing Mode */
#ifdef DEC_INTERNAL_MEMORY_OPT
video->pstprcTypCur = IMEM_pstprcTypCur;
video->memoryUsage += (nTotalMB * 6);
if (video->pstprcTypCur == NULL)
{
status = PV_FALSE;
}
else
{
oscl_memset(video->pstprcTypCur, 0, 4*nTotalMB + 2*nTotalMB);
}
video->pstprcTypPrv = IMEM_pstprcTypPrv;
video->memoryUsage += (nTotalMB * 6);
if (video->pstprcTypPrv == NULL)
{
status = PV_FALSE;
}
else
{
oscl_memset(video->pstprcTypPrv, 0, nTotalMB*6);
}
#else
if (nTotalMB > INT32_MAX / 6) {
return PV_FALSE;
}
video->pstprcTypCur = (uint8 *) oscl_malloc(nTotalMB * 6);
video->memoryUsage += (nTotalMB * 6);
if (video->pstprcTypCur == NULL)
{
status = PV_FALSE;
}
else
{
oscl_memset(video->pstprcTypCur, 0, 4*nTotalMB + 2*nTotalMB);
}
video->pstprcTypPrv = (uint8 *) oscl_malloc(nTotalMB * 6);
video->memoryUsage += (nTotalMB * 6);
if (video->pstprcTypPrv == NULL)
{
status = PV_FALSE;
}
else
{
oscl_memset(video->pstprcTypPrv, 0, nTotalMB*6);
}
#endif
#endif
/* initialize the decoder library */
video->prevVop->predictionType = I_VOP;
video->prevVop->timeStamp = 0;
#ifndef PV_MEMORY_POOL
oscl_memset(video->prevVop->yChan, 16, sizeof(uint8)*size); /* 10/31/01 */
oscl_memset(video->prevVop->uChan, 128, sizeof(uint8)*size / 2);
oscl_memset(video->currVop->yChan, 0, sizeof(uint8)*size*3 / 2);
if (nLayers > 1)
{
oscl_memset(video->prevEnhcVop->yChan, 0, sizeof(uint8)*size*3 / 2);
video->prevEnhcVop->timeStamp = 0;
}
video->concealFrame = video->prevVop->yChan; /* 07/07/2001 */
decCtrl->outputFrame = video->prevVop->yChan; /* 06/19/2002 */
#endif
/* always start from base layer */
video->currLayer = 0;
return status;
}
/* ======================================================================== */
/* Function : PVResetVideoDecoder() */
/* Date : 01/14/2002 */
/* Purpose : Reset video timestamps */
/* In/out : */
/* Return : PV_TRUE if successed, PV_FALSE if failed. */
/* Modified : */
/* ======================================================================== */
Bool PVResetVideoDecoder(VideoDecControls *decCtrl)
{
VideoDecData *video = (VideoDecData *) decCtrl->videoDecoderData;
int idx;
for (idx = 0; idx < decCtrl->nLayers; idx++)
{
video->vopHeader[idx]->timeStamp = 0;
}
video->prevVop->timeStamp = 0;
if (decCtrl->nLayers > 1)
video->prevEnhcVop->timeStamp = 0;
oscl_memset(video->mblock->block, 0, sizeof(int16)*6*NCOEFF_BLOCK); // Aug 23,2005
return PV_TRUE;
}
/* ======================================================================== */
/* Function : PVCleanUpVideoDecoder() */
/* Date : 04/11/2000, 08/29/2000 */
/* Purpose : Cleanup of the MPEG-4 video decoder library. */
/* In/out : */
/* Return : PV_TRUE if successed, PV_FALSE if failed. */
/* Modified : */
/* ======================================================================== */
OSCL_EXPORT_REF Bool PVCleanUpVideoDecoder(VideoDecControls *decCtrl)
{
int idx;
VideoDecData *video = (VideoDecData *) decCtrl->videoDecoderData;
#ifdef DEC_INTERNAL_MEMORY_OPT
if (video)
{
#ifdef PV_POSTPROC_ON
video->pstprcTypCur = NULL;
video->pstprcTypPrv = NULL;
#endif
video->acPredFlag = NULL;
video->sliceNo = NULL;
video->motX = NULL;
video->motY = NULL;
video->mblock = NULL;
video->QPMB = NULL;
video->predDC = NULL;
video->predDCAC_row = NULL;
video->predDCAC_col = NULL;
video->headerInfo.Mode = NULL;
video->headerInfo.CBP = NULL;
if (video->numberOfLayers > 1)
{
if (video->prevEnhcVop)
{
video->prevEnhcVop->uChan = NULL;
video->prevEnhcVop->vChan = NULL;
if (video->prevEnhcVop->yChan) oscl_free(video->prevEnhcVop->yChan);
oscl_free(video->prevEnhcVop);
}
}
if (video->currVop)
{
video->currVop->uChan = NULL;
video->currVop->vChan = NULL;
if (video->currVop->yChan)
video->currVop->yChan = NULL;
video->currVop = NULL;
}
if (video->prevVop)
{
video->prevVop->uChan = NULL;
video->prevVop->vChan = NULL;
if (video->prevVop->yChan)
video->prevVop->yChan = NULL;
video->prevVop = NULL;
}
if (video->vol)
{
for (idx = 0; idx < video->numberOfLayers; idx++)
{
if (video->vol[idx])
{
BitstreamClose(video->vol[idx]->bitstream);
video->vol[idx]->bitstream = NULL;
video->vol[idx] = NULL;
}
video->vopHeader[idx] = NULL;
}
video->vol = NULL;
video->vopHeader = NULL;
}
video = NULL;
decCtrl->videoDecoderData = NULL;
}
#else
if (video)
{
#ifdef PV_POSTPROC_ON
if (video->pstprcTypCur) oscl_free(video->pstprcTypCur);
if (video->pstprcTypPrv) oscl_free(video->pstprcTypPrv);
#endif
if (video->predDC) oscl_free(video->predDC);
video->predDCAC_row = NULL;
if (video->predDCAC_col) oscl_free(video->predDCAC_col);
if (video->motX) oscl_free(video->motX);
if (video->motY) oscl_free(video->motY);
if (video->mblock) oscl_free(video->mblock);
if (video->QPMB) oscl_free(video->QPMB);
if (video->headerInfo.Mode) oscl_free(video->headerInfo.Mode);
if (video->headerInfo.CBP) oscl_free(video->headerInfo.CBP);
if (video->sliceNo) oscl_free(video->sliceNo);
if (video->acPredFlag) oscl_free(video->acPredFlag);
if (video->numberOfLayers > 1)
{
if (video->prevEnhcVop)
{
video->prevEnhcVop->uChan = NULL;
video->prevEnhcVop->vChan = NULL;
if (video->prevEnhcVop->yChan) oscl_free(video->prevEnhcVop->yChan);
oscl_free(video->prevEnhcVop);
}
}
if (video->currVop)
{
#ifndef PV_MEMORY_POOL
video->currVop->uChan = NULL;
video->currVop->vChan = NULL;
if (video->currVop->yChan)
oscl_free(video->currVop->yChan);
#endif
oscl_free(video->currVop);
}
if (video->prevVop)
{
#ifndef PV_MEMORY_POOL
video->prevVop->uChan = NULL;
video->prevVop->vChan = NULL;
if (video->prevVop->yChan)
oscl_free(video->prevVop->yChan);
#endif
oscl_free(video->prevVop);
}
if (video->vol)
{
for (idx = 0; idx < video->numberOfLayers; idx++)
{
if (video->vol[idx])
{
if (video->vol[idx]->bitstream)
{
BitstreamClose(video->vol[idx]->bitstream);
oscl_free(video->vol[idx]->bitstream);
}
oscl_free(video->vol[idx]);
}
}
oscl_free(video->vol);
}
for (idx = 0; idx < video->numberOfLayers; idx++)
{
if (video->vopHeader[idx]) oscl_free(video->vopHeader[idx]);
}
if (video->vopHeader) oscl_free(video->vopHeader);
oscl_free(video);
decCtrl->videoDecoderData = NULL;
}
#endif
return PV_TRUE;
}
/* ======================================================================== */
/* Function : PVGetVideoDimensions() */
/* Date : 040505 */
/* Purpose : */
/* In/out : */
/* Return : the display_width and display_height of */
/* the frame in the current layer. */
/* Note : This is not a macro or inline function because we do */
/* not want to expose our internal data structure. */
/* Modified : */
/* ======================================================================== */
OSCL_EXPORT_REF void PVGetVideoDimensions(VideoDecControls *decCtrl, int32 *display_width, int32 *display_height)
{
VideoDecData *video = (VideoDecData *)decCtrl->videoDecoderData;
*display_width = video->displayWidth;
*display_height = video->displayHeight;
}
OSCL_EXPORT_REF void PVGetBufferDimensions(VideoDecControls *decCtrl, int32 *width, int32 *height) {
VideoDecData *video = (VideoDecData *)decCtrl->videoDecoderData;
*width = video->width;
*height = video->height;
}
/* ======================================================================== */
/* Function : PVGetVideoTimeStamp() */
/* Date : 04/27/2000, 08/29/2000 */
/* Purpose : */
/* In/out : */
/* Return : current time stamp in millisecond. */
/* Note : */
/* Modified : */
/* ======================================================================== */
uint32 PVGetVideoTimeStamp(VideoDecControls *decCtrl)
{
VideoDecData *video = (VideoDecData *)decCtrl->videoDecoderData;
return video->currTimestamp;
}
/* ======================================================================== */
/* Function : PVSetPostProcType() */
/* Date : 07/07/2000 */
/* Purpose : */
/* In/out : */
/* Return : Set post-processing filter type. */
/* Note : */
/* Modified : . 08/29/2000 changes the name for consistency. */
/* ======================================================================== */
OSCL_EXPORT_REF void PVSetPostProcType(VideoDecControls *decCtrl, int mode)
{
VideoDecData *video = (VideoDecData *)decCtrl->videoDecoderData;
video->postFilterType = mode;
}
/* ======================================================================== */
/* Function : PVGetDecBitrate() */
/* Date : 08/23/2000 */
/* Purpose : */
/* In/out : */
/* Return : This function returns the average bits per second. */
/* Note : */
/* Modified : */
/* ======================================================================== */
int PVGetDecBitrate(VideoDecControls *decCtrl)
{
VideoDecData *video = (VideoDecData *)decCtrl->videoDecoderData;
int idx;
int32 sum = 0;
for (idx = 0; idx < BITRATE_AVERAGE_WINDOW; idx++)
{
sum += video->nBitsPerVop[idx];
}
sum = (sum * video->frameRate) / (10 * BITRATE_AVERAGE_WINDOW);
return (int) sum;
}
/* ======================================================================== */
/* Function : PVGetDecFramerate() */
/* Date : 08/23/2000 */
/* Purpose : */
/* In/out : */
/* Return : This function returns the average frame per 10 second. */
/* Note : The fps can be calculated by PVGetDecFramerate()/10 */
/* Modified : */
/* ======================================================================== */
int PVGetDecFramerate(VideoDecControls *decCtrl)
{
VideoDecData *video = (VideoDecData *)decCtrl->videoDecoderData;
return video->frameRate;
}
/* ======================================================================== */
/* Function : PVGetOutputFrame() */
/* Date : 05/07/2001 */
/* Purpose : */
/* In/out : */
/* Return : This function returns the pointer to the output frame */
/* Note : */
/* Modified : */
/* ======================================================================== */
uint8 *PVGetDecOutputFrame(VideoDecControls *decCtrl)
{
return decCtrl->outputFrame;
}
/* ======================================================================== */
/* Function : PVGetLayerID() */
/* Date : 07/09/2001 */
/* Purpose : */
/* In/out : */
/* Return : This function returns decoded frame layer id (BASE/ENHANCE) */
/* Note : */
/* Modified : */
/* ======================================================================== */
int PVGetLayerID(VideoDecControls *decCtrl)
{
VideoDecData *video = (VideoDecData *)decCtrl->videoDecoderData;
return video->currLayer;
}
/* ======================================================================== */
/* Function : PVGetDecMemoryUsage() */
/* Date : 08/23/2000 */
/* Purpose : */
/* In/out : */
/* Return : This function returns the amount of memory used. */
/* Note : */
/* Modified : */
/* ======================================================================== */
int32 PVGetDecMemoryUsage(VideoDecControls *decCtrl)
{
VideoDecData *video = (VideoDecData *)decCtrl->videoDecoderData;
return video->memoryUsage;
}
/* ======================================================================== */
/* Function : PVGetDecBitstreamMode() */
/* Date : 08/23/2000 */
/* Purpose : */
/* In/out : */
/* Return : This function returns the decoding mode of the baselayer */
/* bitstream. */
/* Note : */
/* Modified : */
/* ======================================================================== */
OSCL_EXPORT_REF MP4DecodingMode PVGetDecBitstreamMode(VideoDecControls *decCtrl)
{
VideoDecData *video = (VideoDecData *)decCtrl->videoDecoderData;
if (video->shortVideoHeader)
{
return H263_MODE;
}
else
{
return MPEG4_MODE;
}
}
/* ======================================================================== */
/* Function : PVExtractVolHeader() */
/* Date : 08/29/2000 */
/* Purpose : */
/* In/out : */
/* Return : Extract vol header of the bitstream from buffer[]. */
/* Note : */
/* Modified : */
/* ======================================================================== */
Bool PVExtractVolHeader(uint8 *video_buffer, uint8 *vol_header, int32 *vol_header_size)
{
int idx = -1;
uint8 start_code_prefix[] = { 0x00, 0x00, 0x01 };
uint8 h263_prefix[] = { 0x00, 0x00, 0x80 };
if (oscl_memcmp(h263_prefix, video_buffer, 3) == 0) /* we have short header stream */
{
oscl_memcpy(vol_header, video_buffer, 32);
*vol_header_size = 32;
return TRUE;
}
else
{
if (oscl_memcmp(start_code_prefix, video_buffer, 3) ||
(video_buffer[3] != 0xb0 && video_buffer[3] >= 0x20)) return FALSE;
do
{
idx++;
while (oscl_memcmp(start_code_prefix, video_buffer + idx, 3))
{
idx++;
if (idx + 3 >= *vol_header_size) goto quit;
}
}
while (video_buffer[idx+3] != 0xb3 && video_buffer[idx+3] != 0xb6);
oscl_memcpy(vol_header, video_buffer, idx);
*vol_header_size = idx;
return TRUE;
}
quit:
oscl_memcpy(vol_header, video_buffer, *vol_header_size);
return FALSE;
}
/* ======================================================================== */
/* Function : PVLocateFrameHeader() */
/* Date : 04/8/2005 */
/* Purpose : */
/* In/out : */
/* Return : Return the offset to the first SC in the buffer */
/* Note : */
/* Modified : */
/* ======================================================================== */
int32 PVLocateFrameHeader(uint8 *ptr, int32 size)
{
int count = 0;
int32 i = size;
if (size < 1)
{
return 0;
}
while (i--)
{
if ((count > 1) && (*ptr == 0x01))
{
i += 2;
break;
}
if (*ptr++)
count = 0;
else
count++;
}
return (size - (i + 1));
}
/* ======================================================================== */
/* Function : PVLocateH263FrameHeader() */
/* Date : 04/8/2005 */
/* Purpose : */
/* In/out : */
/* Return : Return the offset to the first SC in the buffer */
/* Note : */
/* Modified : */
/* ======================================================================== */
int32 PVLocateH263FrameHeader(uint8 *ptr, int32 size)
{
int count = 0;
int32 i = size;
if (size < 1)
{
return 0;
}
while (i--)
{
if ((count > 1) && ((*ptr & 0xFC) == 0x80))
{
i += 2;
break;
}
if (*ptr++)
count = 0;
else
count++;
}
return (size - (i + 1));
}
/* ======================================================================== */
/* Function : PVDecodeVideoFrame() */
/* Date : 08/29/2000 */
/* Purpose : Decode one video frame and return a YUV-12 image. */
/* In/out : */
/* Return : */
/* Note : */
/* Modified : 04/17/2001 removed PV_EOS, PV_END_OF_BUFFER */
/* : 08/22/2002 break up into 2 functions PVDecodeVopHeader and */
/* PVDecodeVopBody */
/* ======================================================================== */
OSCL_EXPORT_REF Bool PVDecodeVideoFrame(VideoDecControls *decCtrl, uint8 *buffer[],
uint32 timestamp[], int32 buffer_size[], uint use_ext_timestamp[], uint8 *currYUV)
{
PV_STATUS status = PV_FAIL;
VopHeaderInfo header_info;
status = (PV_STATUS)PVDecodeVopHeader(decCtrl, buffer, timestamp, buffer_size, &header_info, use_ext_timestamp, currYUV);
if (status != PV_TRUE)
return PV_FALSE;
if (PVDecodeVopBody(decCtrl, buffer_size) != PV_TRUE)
{
return PV_FALSE;
}
return PV_TRUE;
}
/* ======================================================================== */
/* Function : PVDecodeVopHeader() */
/* Date : 08/22/2002 */
/* Purpose : Determine target layer and decode vop header, modified from */
/* original PVDecodeVideoFrame. */
/* In/out : */
/* Return : */
/* Note : */
/* Modified : */
/* ======================================================================== */
Bool PVDecodeVopHeader(VideoDecControls *decCtrl, uint8 *buffer[],
uint32 timestamp[], int32 buffer_size[], VopHeaderInfo *header_info, uint use_ext_timestamp [], uint8 *currYUV)
{
VideoDecData *video = (VideoDecData *) decCtrl->videoDecoderData;
Vol *currVol;
Vop *currVop = video->currVop;
Vop **vopHeader = video->vopHeader;
BitstreamDecVideo *stream;
int target_layer;
#ifdef PV_SUPPORT_TEMPORAL_SCALABILITY
PV_STATUS status = PV_FAIL;
int idx;
int32 display_time;
/* decide which frame to decode next */
if (decCtrl->nLayers > 1)
{
display_time = target_layer = -1;
for (idx = 0; idx < decCtrl->nLayers; idx++)
{
/* do we have data for this layer? */
if (buffer_size[idx] <= 0)
{
timestamp[idx] = -1;
continue;
}
/* did the application provide a timestamp for this vop? */
if (timestamp[idx] < 0)
{
if (vopHeader[idx]->timeStamp < 0)
{
/* decode the timestamp in the bitstream */
video->currLayer = idx;
stream = video->vol[idx]->bitstream;
BitstreamReset(stream, buffer[idx], buffer_size[idx]);
while ((status = DecodeVOPHeader(video, vopHeader[idx], FALSE)) != PV_SUCCESS)
{
/* Try to find a VOP header in the buffer. 08/30/2000. */
if (PVSearchNextM4VFrame(stream) != PV_SUCCESS)
{
/* if we don't have data for enhancement layer, */
/* don't just stop. 09/07/2000. */
buffer_size[idx] = 0;
break;
}
}
if (status == PV_SUCCESS)
{
vopHeader[idx]->timeStamp =
timestamp[idx] = CalcVopDisplayTime(video->vol[idx], vopHeader[idx], video->shortVideoHeader);
if (idx == 0) vopHeader[idx]->refSelectCode = 1;
}
}
else
{
/* We've decoded this vop header in the previous run already. */
timestamp[idx] = vopHeader[idx]->timeStamp;
}
}
/* Use timestamps to select the next VOP to be decoded */
if (timestamp[idx] >= 0 && (display_time < 0 || display_time > timestamp[idx]))
{
display_time = timestamp[idx];
target_layer = idx;
}
else if (display_time == timestamp[idx])
{
/* we have to handle either SNR or spatial scalability here. */
}
}
if (target_layer < 0) return PV_FALSE;
/* set up for decoding the target layer */
video->currLayer = target_layer;
currVol = video->vol[target_layer];
video->bitstream = stream = currVol->bitstream;
/* We need to decode the vop header if external timestamp */
/* is provided. 10/04/2000 */
if (vopHeader[target_layer]->timeStamp < 0)
{
stream = video->vol[target_layer]->bitstream;
BitstreamReset(stream, buffer[target_layer], buffer_size[target_layer]);
while (DecodeVOPHeader(video, vopHeader[target_layer], TRUE) != PV_SUCCESS)
{
/* Try to find a VOP header in the buffer. 08/30/2000. */
if (PVSearchNextM4VFrame(stream) != PV_SUCCESS)
{
/* if we don't have data for enhancement layer, */
/* don't just stop. 09/07/2000. */
buffer_size[target_layer] = 0;
break;
}
}
video->vol[target_layer]->timeInc_offset = vopHeader[target_layer]->timeInc;
video->vol[target_layer]->moduloTimeBase = timestamp[target_layer];
vopHeader[target_layer]->timeStamp = timestamp[target_layer];
if (target_layer == 0) vopHeader[target_layer]->refSelectCode = 1;
}
}
else /* base layer only decoding */
{
#endif
video->currLayer = target_layer = 0;
currVol = video->vol[0];
video->bitstream = stream = currVol->bitstream;
if (buffer_size[0] <= 0) return PV_FALSE;
BitstreamReset(stream, buffer[0], buffer_size[0]);
if (video->shortVideoHeader)
{
while (DecodeShortHeader(video, vopHeader[0]) != PV_SUCCESS)
{
if (PVSearchNextH263Frame(stream) != PV_SUCCESS)
{
/* There is no vop header in the buffer, */
/* clean bitstream buffer. 2/5/2001 */
buffer_size[0] = 0;
if (video->initialized == PV_FALSE)
{
video->displayWidth = video->width = 0;
video->displayHeight = video->height = 0;
}
return PV_FALSE;
}
}
if (use_ext_timestamp[0])
{
/* MTB for H263 is absolute TR */
/* following line is equivalent to round((timestamp[0]*30)/1001); 11/13/2001 */
video->vol[0]->moduloTimeBase = 30 * ((timestamp[0] + 17) / 1001) + (30 * ((timestamp[0] + 17) % 1001) / 1001);
vopHeader[0]->timeStamp = timestamp[0];
}
else
vopHeader[0]->timeStamp = CalcVopDisplayTime(currVol, vopHeader[0], video->shortVideoHeader);
}
else
{
while (DecodeVOPHeader(video, vopHeader[0], FALSE) != PV_SUCCESS)
{
/* Try to find a VOP header in the buffer. 08/30/2000. */
if (PVSearchNextM4VFrame(stream) != PV_SUCCESS)
{
/* There is no vop header in the buffer, */
/* clean bitstream buffer. 2/5/2001 */
buffer_size[0] = 0;
return PV_FALSE;
}
}
if (use_ext_timestamp[0])
{
video->vol[0]->timeInc_offset = vopHeader[0]->timeInc;
video->vol[0]->moduloTimeBase = timestamp[0]; /* 11/12/2001 */
vopHeader[0]->timeStamp = timestamp[0];
}
else
{
vopHeader[0]->timeStamp = CalcVopDisplayTime(currVol, vopHeader[0], video->shortVideoHeader);
}
}
/* set up some base-layer only parameters */
vopHeader[0]->refSelectCode = 1;
#ifdef PV_SUPPORT_TEMPORAL_SCALABILITY
}
#endif
timestamp[target_layer] = video->currTimestamp = vopHeader[target_layer]->timeStamp;
#ifdef PV_MEMORY_POOL
vopHeader[target_layer]->yChan = (PIXEL *)currYUV;
vopHeader[target_layer]->uChan = (PIXEL *)currYUV + decCtrl->size;
vopHeader[target_layer]->vChan = (PIXEL *)(vopHeader[target_layer]->uChan) + (decCtrl->size >> 2);
#else
vopHeader[target_layer]->yChan = currVop->yChan;
vopHeader[target_layer]->uChan = currVop->uChan;
vopHeader[target_layer]->vChan = currVop->vChan;
#endif
oscl_memcpy(currVop, vopHeader[target_layer], sizeof(Vop));
#ifdef PV_SUPPORT_TEMPORAL_SCALABILITY
vopHeader[target_layer]->timeStamp = -1;
#endif
/* put header info into the structure */
header_info->currLayer = target_layer;
header_info->timestamp = video->currTimestamp;
header_info->frameType = (MP4FrameType)currVop->predictionType;
header_info->refSelCode = vopHeader[target_layer]->refSelectCode;
header_info->quantizer = currVop->quantizer;
/***************************************/
return PV_TRUE;
}
/* ======================================================================== */
/* Function : PVDecodeVopBody() */
/* Date : 08/22/2002 */
/* Purpose : Decode vop body after the header is decoded, modified from */
/* original PVDecodeVideoFrame. */
/* In/out : */
/* Return : */
/* Note : */
/* Modified : */
/* ======================================================================== */
Bool PVDecodeVopBody(VideoDecControls *decCtrl, int32 buffer_size[])
{
PV_STATUS status = PV_FAIL;
VideoDecData *video = (VideoDecData *) decCtrl->videoDecoderData;
int target_layer = video->currLayer;
Vol *currVol = video->vol[target_layer];
Vop *currVop = video->currVop;
Vop *prevVop = video->prevVop;
Vop *tempVopPtr;
int bytes_consumed = 0; /* Record how many bits we used in the buffer. 04/24/2001 */
int idx;
if (currVop->vopCoded == 0) /* 07/03/2001 */
{
PV_BitstreamByteAlign(currVol->bitstream);
/* We should always clear up bitstream buffer. 10/10/2000 */
bytes_consumed = (getPointer(currVol->bitstream) + 7) >> 3;
if (bytes_consumed > currVol->bitstream->data_end_pos)
{
bytes_consumed = currVol->bitstream->data_end_pos;
}
if (bytes_consumed < buffer_size[target_layer])
{
/* If we only consume part of the bits in the buffer, take those */
/* out. 04/24/2001 */
/* oscl_memcpy(buffer[target_layer], buffer[target_layer]+bytes_consumed,
(buffer_size[target_layer]-=bytes_consumed)); */
buffer_size[target_layer] -= bytes_consumed;
}
else
{
buffer_size[target_layer] = 0;
}
#ifdef PV_MEMORY_POOL
if (target_layer)
{
if (video->prevEnhcVop->timeStamp > video->prevVop->timeStamp)
{
video->prevVop = video->prevEnhcVop;
}
}
oscl_memcpy(currVop->yChan, video->prevVop->yChan, (decCtrl->size*3) / 2);
video->prevVop = prevVop;
video->concealFrame = currVop->yChan; /* 07/07/2001 */
video->vop_coding_type = currVop->predictionType; /* 07/09/01 */
decCtrl->outputFrame = currVop->yChan;
/* Swap VOP pointers. No enhc. frame oscl_memcpy() anymore! 04/24/2001 */
if (target_layer)
{
tempVopPtr = video->prevEnhcVop;
video->prevEnhcVop = video->currVop;
video->currVop = tempVopPtr;
}
else
{
tempVopPtr = video->prevVop;
video->prevVop = video->currVop;
video->currVop = tempVopPtr;
}
#else
if (target_layer) /* this is necessary to avoid flashback problems 06/21/2002*/
{
video->prevEnhcVop->timeStamp = currVop->timeStamp;
}
else
{
video->prevVop->timeStamp = currVop->timeStamp;
}
#endif
video->vop_coding_type = currVop->predictionType; /* 07/09/01 */
/* the following is necessary to avoid displaying an notCoded I-VOP at the beginning of a session
or after random positioning 07/03/02*/
if (currVop->predictionType == I_VOP)
{
video->vop_coding_type = P_VOP;
}
return PV_TRUE;
}
/* ======================================================= */
/* Decode vop body (if there is no error in the header!) */
/* ======================================================= */
/* first, we need to select a reference frame */
if (decCtrl->nLayers > 1)
{
if (currVop->predictionType == I_VOP)
{
/* do nothing here */
}
else if (currVop->predictionType == P_VOP)
{
switch (currVop->refSelectCode)
{
case 0 : /* most recently decoded enhancement vop */
/* Setup video->prevVop before we call PV_DecodeVop(). 04/24/2001 */
if (video->prevEnhcVop->timeStamp >= video->prevVop->timeStamp)
video->prevVop = video->prevEnhcVop;
break;
case 1 : /* most recently displayed base-layer vop */
if (target_layer)
{
if (video->prevEnhcVop->timeStamp > video->prevVop->timeStamp)
video->prevVop = video->prevEnhcVop;
}
break;
case 2 : /* next base-layer vop in display order */
break;
case 3 : /* temporally coincident base-layer vop (no MV's) */
break;
}
}
else /* we have a B-Vop */
{
mp4dec_log("DecodeVideoFrame(): B-VOP not supported.\n");
}
}
/* This is for the calculation of the frame rate and bitrate. */
idx = ++video->frame_idx % BITRATE_AVERAGE_WINDOW;
/* Calculate bitrate for this layer. 08/23/2000 */
status = PV_DecodeVop(video);
video->nBitsPerVop[idx] = getPointer(currVol->bitstream);
video->prevTimestamp[idx] = currVop->timeStamp;
/* restore video->prevVop after PV_DecodeVop(). 04/24/2001 */
// if (currVop->refSelectCode == 0) video->prevVop = prevVop;
video->prevVop = prevVop;
/* Estimate the frame rate. 08/23/2000 */
video->duration = video->prevTimestamp[idx];
video->duration -= video->prevTimestamp[(++idx)%BITRATE_AVERAGE_WINDOW];
if (video->duration > 0)
{ /* Only update framerate when the timestamp is right */
video->frameRate = (int)(FRAMERATE_SCALE) / video->duration;
}
/* We should always clear up bitstream buffer. 10/10/2000 */
bytes_consumed = (getPointer(currVol->bitstream) + 7) >> 3; /* 11/4/03 */
if (bytes_consumed > currVol->bitstream->data_end_pos)
{
bytes_consumed = currVol->bitstream->data_end_pos;
}
if (bytes_consumed < buffer_size[target_layer])
{
/* If we only consume part of the bits in the buffer, take those */
/* out. 04/24/2001 */
/* oscl_memcpy(buffer[target_layer], buffer[target_layer]+bytes_consumed,
(buffer_size[target_layer]-=bytes_consumed)); */
buffer_size[target_layer] -= bytes_consumed;
}
else
{
buffer_size[target_layer] = 0;
}
switch (status)
{
case PV_FAIL :
return PV_FALSE; /* this will take care of concealment if we lose whole frame */
case PV_END_OF_VOP :
/* we may want to differenciate PV_END_OF_VOP and PV_SUCCESS */
/* in the future. 05/10/2000 */
case PV_SUCCESS :
/* Nohting is wrong :). */
video->concealFrame = video->currVop->yChan; /* 07/07/2001 */
video->vop_coding_type = video->currVop->predictionType; /* 07/09/01 */
decCtrl->outputFrame = video->currVop->yChan;
/* Swap VOP pointers. No enhc. frame oscl_memcpy() anymore! 04/24/2001 */
if (target_layer)
{
tempVopPtr = video->prevEnhcVop;
video->prevEnhcVop = video->currVop;
video->currVop = tempVopPtr;
}
else
{
tempVopPtr = video->prevVop;
video->prevVop = video->currVop;
video->currVop = tempVopPtr;
}
break;
default :
/* This will never happen */
break;
}
return PV_TRUE;
}
#ifdef PV_MEMORY_POOL
OSCL_EXPORT_REF void PVSetReferenceYUV(VideoDecControls *decCtrl, uint8 *YUV)
{
VideoDecData *video = (VideoDecData *)decCtrl->videoDecoderData;
video->prevVop->yChan = (PIXEL *)YUV;
video->prevVop->uChan = (PIXEL *)YUV + video->size;
video->prevVop->vChan = (PIXEL *)video->prevVop->uChan + (decCtrl->size >> 2);
oscl_memset(video->prevVop->yChan, 16, sizeof(uint8)*decCtrl->size); /* 10/31/01 */
oscl_memset(video->prevVop->uChan, 128, sizeof(uint8)*decCtrl->size / 2);
video->concealFrame = video->prevVop->yChan; /* 07/07/2001 */
decCtrl->outputFrame = video->prevVop->yChan; /* 06/19/2002 */
}
#endif
/* ======================================================================== */
/* Function : VideoDecoderErrorDetected() */
/* Date : 06/20/2000 */
/* Purpose : */
/* In/out : */
/* Return : This function will be called everytime an error int the */
/* bitstream is detected. */
/* Note : */
/* Modified : */
/* ======================================================================== */
uint VideoDecoderErrorDetected(VideoDecData *)
{
/* This is only used for trapping bitstream error for debuging */
return 0;
}
#ifdef ENABLE_LOG
#include <stdio.h>
#include <stdarg.h>
/* ======================================================================== */
/* Function : m4vdec_dprintf() */
/* Date : 08/15/2000 */
/* Purpose : This is a function that logs messages in the mpeg4 video */
/* decoder. We can call the standard PacketVideo PVMessage */
/* from inside this function if necessary. */
/* In/out : */
/* Return : */
/* Note : To turn on the logging, LOG_MP4DEC_MESSAGE must be defined */
/* when compiling this file (only this file). */
/* Modified : */
/* ======================================================================== */
void m4vdec_dprintf(char *format, ...)
{
FILE *log_fp;
va_list args;
va_start(args, format);
/* open the log file */
log_fp = fopen("\\mp4dec_log.txt", "a+");
if (log_fp == NULL) return;
/* output the message */
vfprintf(log_fp, format, args);
fclose(log_fp);
va_end(args);
}
#endif
/* ======================================================================== */
/* Function : IsIntraFrame() */
/* Date : 05/29/2000 */
/* Purpose : */
/* In/out : */
/* Return : The most recently decoded frame is an Intra frame. */
/* Note : */
/* Modified : */
/* ======================================================================== */
Bool IsIntraFrame(VideoDecControls *decCtrl)
{
VideoDecData *video = (VideoDecData *)decCtrl->videoDecoderData;
return (video->vop_coding_type == I_VOP);
}
/* ======================================================================== */
/* Function : PVDecPostProcess() */
/* Date : 01/09/2002 */
/* Purpose : PostProcess one video frame and return a YUV-12 image. */
/* In/out : */
/* Return : */
/* Note : */
/* Modified : */
/* ======================================================================== */
void PVDecPostProcess(VideoDecControls *decCtrl, uint8 *outputYUV)
{
uint8 *outputBuffer;
#ifdef PV_POSTPROC_ON
VideoDecData *video = (VideoDecData *) decCtrl->videoDecoderData;
int32 tmpvar;
if (outputYUV)
{
outputBuffer = outputYUV;
}
else
{
if (video->postFilterType)
{
outputBuffer = video->currVop->yChan;
}
else
{
outputBuffer = decCtrl->outputFrame;
}
}
if (video->postFilterType)
{
/* Post-processing, */
PostFilter(video, video->postFilterType, outputBuffer);
}
else
{
if (outputYUV)
{
/* Copy decoded frame to the output buffer. */
tmpvar = (int32)video->width * video->height;
oscl_memcpy(outputBuffer, decCtrl->outputFrame, tmpvar*3 / 2); /* 3/3/01 */
}
}
#else
outputBuffer = decCtrl->outputFrame;
outputYUV;
#endif
decCtrl->outputFrame = outputBuffer;
return;
}
/* ======================================================================== */
/* Function : PVDecSetReference(VideoDecControls *decCtrl, uint8 *refYUV, */
/* int32 timestamp) */
/* Date : 07/22/2003 */
/* Purpose : Get YUV reference frame from external source. */
/* In/out : YUV 4-2-0 frame containing new reference frame in the same */
/* : dimension as original, i.e., doesn't have to be multiple of 16 !!!. */
/* Return : */
/* Note : */
/* Modified : */
/* ======================================================================== */
Bool PVDecSetReference(VideoDecControls *decCtrl, uint8 *refYUV, uint32 timestamp)
{
VideoDecData *video = (VideoDecData *) decCtrl->videoDecoderData;
Vop *prevVop = video->prevVop;
int width = video->width;
uint8 *dstPtr, *orgPtr, *dstPtr2, *orgPtr2;
int32 size = (int32)width * video->height;
/* set new parameters */
prevVop->timeStamp = timestamp;
prevVop->predictionType = I_VOP;
dstPtr = prevVop->yChan;
orgPtr = refYUV;
oscl_memcpy(dstPtr, orgPtr, size);
dstPtr = prevVop->uChan;
dstPtr2 = prevVop->vChan;
orgPtr = refYUV + size;
orgPtr2 = orgPtr + (size >> 2);
oscl_memcpy(dstPtr, orgPtr, (size >> 2));
oscl_memcpy(dstPtr2, orgPtr2, (size >> 2));
video->concealFrame = video->prevVop->yChan;
video->vop_coding_type = I_VOP;
decCtrl->outputFrame = video->prevVop->yChan;
return PV_TRUE;
}
/* ======================================================================== */
/* Function : PVDecSetEnhReference(VideoDecControls *decCtrl, uint8 *refYUV, */
/* int32 timestamp) */
/* Date : 07/23/2003 */
/* Purpose : Get YUV enhance reference frame from external source. */
/* In/out : YUV 4-2-0 frame containing new reference frame in the same */
/* : dimension as original, i.e., doesn't have to be multiple of 16 !!!. */
/* Return : */
/* Note : */
/* Modified : */
/* ======================================================================== */
Bool PVDecSetEnhReference(VideoDecControls *decCtrl, uint8 *refYUV, uint32 timestamp)
{
VideoDecData *video = (VideoDecData *) decCtrl->videoDecoderData;
Vop *prevEnhcVop = video->prevEnhcVop;
uint8 *dstPtr, *orgPtr, *dstPtr2, *orgPtr2;
int32 size = (int32) video->width * video->height;
if (video->numberOfLayers <= 1)
return PV_FALSE;
/* set new parameters */
prevEnhcVop->timeStamp = timestamp;
prevEnhcVop->predictionType = I_VOP;
dstPtr = prevEnhcVop->yChan;
orgPtr = refYUV;
oscl_memcpy(dstPtr, orgPtr, size);
dstPtr = prevEnhcVop->uChan;
dstPtr2 = prevEnhcVop->vChan;
orgPtr = refYUV + size;
orgPtr2 = orgPtr + (size >> 2);
oscl_memcpy(dstPtr, orgPtr, (size >> 2));
oscl_memcpy(dstPtr2, orgPtr2, (size >> 2));
video->concealFrame = video->prevEnhcVop->yChan;
video->vop_coding_type = I_VOP;
decCtrl->outputFrame = video->prevEnhcVop->yChan;
return PV_TRUE;
}
/* ======================================================================== */
/* Function : PVGetVolInfo() */
/* Date : 08/06/2003 */
/* Purpose : Get the vol info(only base-layer). */
/* In/out : */
/* Return : */
/* Note : */
/* Modified : 06/24/2004 */
/* ======================================================================== */
Bool PVGetVolInfo(VideoDecControls *decCtrl, VolInfo *pVolInfo)
{
Vol *currVol;
if (pVolInfo == NULL || decCtrl == NULL || decCtrl->videoDecoderData == NULL ||
((VideoDecData *)decCtrl->videoDecoderData)->vol[0] == NULL) return PV_FALSE;
currVol = ((VideoDecData *)(decCtrl->videoDecoderData))->vol[0];
// get the VOL info
pVolInfo->shortVideoHeader = (int32)((VideoDecData *)(decCtrl->videoDecoderData))->shortVideoHeader;
pVolInfo->dataPartitioning = (int32)currVol->dataPartitioning;
pVolInfo->errorResDisable = (int32)currVol->errorResDisable;
pVolInfo->useReverseVLC = (int32)currVol->useReverseVLC;
pVolInfo->scalability = (int32)currVol->scalability;
pVolInfo->nbitsTimeIncRes = (int32)currVol->nbitsTimeIncRes;
pVolInfo->profile_level_id = (int32)currVol->profile_level_id;
return PV_TRUE;
}