/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*------------------------------------------------------------------------------ Table of contents 1. Include headers 2. External compiler flags 3. Module defines 4. Local function prototypes 5. Functions H264SwDecInit H264SwDecGetInfo H264SwDecRelease H264SwDecDecode H264SwDecGetAPIVersion H264SwDecNextPicture ------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------ 1. Include headers ------------------------------------------------------------------------------*/ #include #include #include #include "basetype.h" #include "h264bsd_container.h" #include "H264SwDecApi.h" #include "h264bsd_decoder.h" #include "h264bsd_util.h" #define UNUSED(x) (void)(x) /*------------------------------------------------------------------------------ Version Information ------------------------------------------------------------------------------*/ #define H264SWDEC_MAJOR_VERSION 2 #define H264SWDEC_MINOR_VERSION 3 /*------------------------------------------------------------------------------ 2. External compiler flags -------------------------------------------------------------------------------- H264DEC_TRACE Trace H264 Decoder API function calls. H264DEC_EVALUATION Compile evaluation version, restricts number of frames that can be decoded -------------------------------------------------------------------------------- 3. Module defines ------------------------------------------------------------------------------*/ #ifdef H264DEC_TRACE #include #define DEC_API_TRC(str) H264SwDecTrace(str) #else #define DEC_API_TRC(str) #endif #ifdef H264DEC_EVALUATION #define H264DEC_EVALUATION_LIMIT 500 #endif void H264SwDecTrace(char *string) { UNUSED(string); } void* H264SwDecMalloc(u32 size, u32 num) { if (size > UINT32_MAX / num) { ALOGE("can't allocate %u * %u bytes", size, num); android_errorWriteLog(0x534e4554, "27855419"); return NULL; } return malloc(size * num); } void H264SwDecFree(void *ptr) { free(ptr); } void H264SwDecMemcpy(void *dest, void *src, u32 count) { memcpy(dest, src, count); } void H264SwDecMemset(void *ptr, i32 value, u32 count) { memset(ptr, value, count); } /*------------------------------------------------------------------------------ Function: H264SwDecInit() Functional description: Initialize decoder software. Function reserves memory for the decoder instance and calls h264bsdInit to initialize the instance data. Inputs: noOutputReordering flag to indicate decoder that it doesn't have to try to provide output pictures in display order, saves memory Outputs: decInst pointer to initialized instance is stored here Returns: H264SWDEC_OK successfully initialized the instance H264SWDEC_INITFAIL initialization failed H264SWDEC_PARAM_ERR invalid parameters H264SWDEC_MEM_FAIL memory allocation failed ------------------------------------------------------------------------------*/ H264SwDecRet H264SwDecInit(H264SwDecInst *decInst, u32 noOutputReordering) { u32 rv = 0; decContainer_t *pDecCont; DEC_API_TRC("H264SwDecInit#"); /* check that right shift on negative numbers is performed signed */ /*lint -save -e* following check causes multiple lint messages */ if ( ((-1)>>1) != (-1) ) { DEC_API_TRC("H264SwDecInit# ERROR: Right shift is not signed"); return(H264SWDEC_INITFAIL); } /*lint -restore */ if (decInst == NULL) { DEC_API_TRC("H264SwDecInit# ERROR: decInst == NULL"); return(H264SWDEC_PARAM_ERR); } pDecCont = (decContainer_t *)H264SwDecMalloc(sizeof(decContainer_t), 1); if (pDecCont == NULL) { DEC_API_TRC("H264SwDecInit# ERROR: Memory allocation failed"); return(H264SWDEC_MEMFAIL); } #ifdef H264DEC_TRACE sprintf(pDecCont->str, "H264SwDecInit# decInst %p noOutputReordering %d", (void*)decInst, noOutputReordering); DEC_API_TRC(pDecCont->str); #endif rv = h264bsdInit(&pDecCont->storage, noOutputReordering); if (rv != HANTRO_OK) { H264SwDecRelease(pDecCont); return(H264SWDEC_MEMFAIL); } pDecCont->decStat = INITIALIZED; pDecCont->picNumber = 0; #ifdef H264DEC_TRACE sprintf(pDecCont->str, "H264SwDecInit# OK: return %p", (void*)pDecCont); DEC_API_TRC(pDecCont->str); #endif *decInst = (decContainer_t *)pDecCont; return(H264SWDEC_OK); } /*------------------------------------------------------------------------------ Function: H264SwDecGetInfo() Functional description: This function provides read access to decoder information. This function should not be called before H264SwDecDecode function has indicated that headers are ready. Inputs: decInst decoder instance Outputs: pDecInfo pointer to info struct where data is written Returns: H264SWDEC_OK success H264SWDEC_PARAM_ERR invalid parameters H264SWDEC_HDRS_NOT_RDY information not available yet ------------------------------------------------------------------------------*/ H264SwDecRet H264SwDecGetInfo(H264SwDecInst decInst, H264SwDecInfo *pDecInfo) { storage_t *pStorage; DEC_API_TRC("H264SwDecGetInfo#"); if (decInst == NULL || pDecInfo == NULL) { DEC_API_TRC("H264SwDecGetInfo# ERROR: decInst or pDecInfo is NULL"); return(H264SWDEC_PARAM_ERR); } pStorage = &(((decContainer_t *)decInst)->storage); if (pStorage->activeSps == NULL || pStorage->activePps == NULL) { DEC_API_TRC("H264SwDecGetInfo# ERROR: Headers not decoded yet"); return(H264SWDEC_HDRS_NOT_RDY); } #ifdef H264DEC_TRACE sprintf(((decContainer_t*)decInst)->str, "H264SwDecGetInfo# decInst %p pDecInfo %p", decInst, (void*)pDecInfo); DEC_API_TRC(((decContainer_t*)decInst)->str); #endif /* h264bsdPicWidth and -Height return dimensions in macroblock units, * picWidth and -Height in pixels */ pDecInfo->picWidth = h264bsdPicWidth(pStorage) << 4; pDecInfo->picHeight = h264bsdPicHeight(pStorage) << 4; pDecInfo->videoRange = h264bsdVideoRange(pStorage); pDecInfo->matrixCoefficients = h264bsdMatrixCoefficients(pStorage); h264bsdCroppingParams(pStorage, &pDecInfo->croppingFlag, &pDecInfo->cropParams.cropLeftOffset, &pDecInfo->cropParams.cropOutWidth, &pDecInfo->cropParams.cropTopOffset, &pDecInfo->cropParams.cropOutHeight); /* sample aspect ratio */ h264bsdSampleAspectRatio(pStorage, &pDecInfo->parWidth, &pDecInfo->parHeight); /* profile */ pDecInfo->profile = h264bsdProfile(pStorage); DEC_API_TRC("H264SwDecGetInfo# OK"); return(H264SWDEC_OK); } /*------------------------------------------------------------------------------ Function: H264SwDecRelease() Functional description: Release the decoder instance. Function calls h264bsdShutDown to release instance data and frees the memory allocated for the instance. Inputs: decInst Decoder instance Outputs: none Returns: none ------------------------------------------------------------------------------*/ void H264SwDecRelease(H264SwDecInst decInst) { decContainer_t *pDecCont; DEC_API_TRC("H264SwDecRelease#"); if (decInst == NULL) { DEC_API_TRC("H264SwDecRelease# ERROR: decInst == NULL"); return; } pDecCont = (decContainer_t*)decInst; #ifdef H264DEC_TRACE sprintf(pDecCont->str, "H264SwDecRelease# decInst %p",decInst); DEC_API_TRC(pDecCont->str); #endif h264bsdShutdown(&pDecCont->storage); H264SwDecFree(pDecCont); } /*------------------------------------------------------------------------------ Function: H264SwDecDecode Functional description: Decode stream data. Calls h264bsdDecode to do the actual decoding. Input: decInst decoder instance pInput pointer to input struct Outputs: pOutput pointer to output struct Returns: H264SWDEC_NOT_INITIALIZED decoder instance not initialized yet H264SWDEC_PARAM_ERR invalid parameters H264SWDEC_STRM_PROCESSED stream buffer decoded H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY headers decoded, stream buffer not finished H264SWDEC_PIC_RDY decoding of a picture finished H264SWDEC_PIC_RDY_BUFF_NOT_EMPTY decoding of a picture finished, stream buffer not finished H264SWDEC_STRM_ERR serious error in decoding, no valid parameter sets available to decode picture data H264SWDEC_EVALUATION_LIMIT_EXCEEDED this can only occur when evaluation version is used, max number of frames reached ------------------------------------------------------------------------------*/ H264SwDecRet H264SwDecDecode(H264SwDecInst decInst, H264SwDecInput *pInput, H264SwDecOutput *pOutput) { decContainer_t *pDecCont; u32 strmLen; u32 numReadBytes; u8 *tmpStream; u32 decResult = 0; H264SwDecRet returnValue = H264SWDEC_STRM_PROCESSED; DEC_API_TRC("H264SwDecDecode#"); /* Check that function input parameters are valid */ if (pInput == NULL || pOutput == NULL) { DEC_API_TRC("H264SwDecDecode# ERROR: pInput or pOutput is NULL"); return(H264SWDEC_PARAM_ERR); } if ((pInput->pStream == NULL) || (pInput->dataLen == 0)) { DEC_API_TRC("H264SwDecDecode# ERROR: Invalid input parameters"); return(H264SWDEC_PARAM_ERR); } pDecCont = (decContainer_t *)decInst; /* Check if decoder is in an incorrect mode */ if (decInst == NULL || pDecCont->decStat == UNINITIALIZED) { DEC_API_TRC("H264SwDecDecode# ERROR: Decoder not initialized"); return(H264SWDEC_NOT_INITIALIZED); } #ifdef H264DEC_EVALUATION if (pDecCont->picNumber >= H264DEC_EVALUATION_LIMIT) return(H264SWDEC_EVALUATION_LIMIT_EXCEEDED); #endif #ifdef H264DEC_TRACE sprintf(pDecCont->str, "H264SwDecDecode# decInst %p pInput %p pOutput %p", decInst, (void*)pInput, (void*)pOutput); DEC_API_TRC(pDecCont->str); #endif pOutput->pStrmCurrPos = NULL; numReadBytes = 0; strmLen = pInput->dataLen; tmpStream = pInput->pStream; pDecCont->storage.intraConcealmentFlag = pInput->intraConcealmentMethod; do { /* Return HDRS_RDY after DPB flush caused by new SPS */ if (pDecCont->decStat == NEW_HEADERS) { decResult = H264BSD_HDRS_RDY; pDecCont->decStat = INITIALIZED; } else /* Continue decoding normally */ { decResult = h264bsdDecode(&pDecCont->storage, tmpStream, strmLen, pInput->picId, &numReadBytes); } tmpStream += numReadBytes; /* check if too many bytes are read from stream */ if ( (i32)(strmLen - numReadBytes) >= 0 ) strmLen -= numReadBytes; else strmLen = 0; pOutput->pStrmCurrPos = tmpStream; switch (decResult) { case H264BSD_HDRS_RDY: if(pDecCont->storage.dpb->flushed && pDecCont->storage.dpb->numOut != pDecCont->storage.dpb->outIndex) { /* output first all DPB stored pictures * DPB flush caused by new SPS */ pDecCont->storage.dpb->flushed = 0; pDecCont->decStat = NEW_HEADERS; returnValue = H264SWDEC_PIC_RDY_BUFF_NOT_EMPTY; strmLen = 0; } else { returnValue = H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY; strmLen = 0; } break; case H264BSD_PIC_RDY: pDecCont->picNumber++; if (strmLen == 0) returnValue = H264SWDEC_PIC_RDY; else returnValue = H264SWDEC_PIC_RDY_BUFF_NOT_EMPTY; strmLen = 0; break; case H264BSD_PARAM_SET_ERROR: if ( !h264bsdCheckValidParamSets(&pDecCont->storage) && strmLen == 0 ) { returnValue = H264SWDEC_STRM_ERR; } break; case H264BSD_MEMALLOC_ERROR: { returnValue = H264SWDEC_MEMFAIL; strmLen = 0; } break; default: break; } } while (strmLen); #ifdef H264DEC_TRACE sprintf(pDecCont->str, "H264SwDecDecode# OK: DecResult %d", returnValue); DEC_API_TRC(pDecCont->str); #endif return(returnValue); } /*------------------------------------------------------------------------------ Function: H264SwDecGetAPIVersion Functional description: Return version information of the API Inputs: none Outputs: none Returns: API version ------------------------------------------------------------------------------*/ H264SwDecApiVersion H264SwDecGetAPIVersion() { H264SwDecApiVersion ver; ver.major = H264SWDEC_MAJOR_VERSION; ver.minor = H264SWDEC_MINOR_VERSION; return(ver); } /*------------------------------------------------------------------------------ Function: H264SwDecNextPicture Functional description: Get next picture in display order if any available. Input: decInst decoder instance. flushBuffer force output of all buffered pictures Output: pOutput pointer to output structure Returns: H264SWDEC_OK no pictures available for display H264SWDEC_PIC_RDY picture available for display H264SWDEC_PARAM_ERR invalid parameters ------------------------------------------------------------------------------*/ H264SwDecRet H264SwDecNextPicture(H264SwDecInst decInst, H264SwDecPicture *pOutput, u32 flushBuffer) { decContainer_t *pDecCont; u32 numErrMbs, isIdrPic, picId; u32 *pOutPic; DEC_API_TRC("H264SwDecNextPicture#"); if (decInst == NULL || pOutput == NULL) { DEC_API_TRC("H264SwDecNextPicture# ERROR: decInst or pOutput is NULL"); return(H264SWDEC_PARAM_ERR); } pDecCont = (decContainer_t*)decInst; #ifdef H264DEC_TRACE sprintf(pDecCont->str, "H264SwDecNextPicture# decInst %p pOutput %p %s %d", decInst, (void*)pOutput, "flushBuffer", flushBuffer); DEC_API_TRC(pDecCont->str); #endif if (flushBuffer) h264bsdFlushBuffer(&pDecCont->storage); pOutPic = (u32*)h264bsdNextOutputPicture(&pDecCont->storage, &picId, &isIdrPic, &numErrMbs); if (pOutPic == NULL) { DEC_API_TRC("H264SwDecNextPicture# OK: return H264SWDEC_OK"); return(H264SWDEC_OK); } else { pOutput->pOutputPicture = pOutPic; pOutput->picId = picId; pOutput->isIdrPicture = isIdrPic; pOutput->nbrOfErrMBs = numErrMbs; DEC_API_TRC("H264SwDecNextPicture# OK: return H264SWDEC_PIC_RDY"); return(H264SWDEC_PIC_RDY); } }