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.
623 lines
21 KiB
623 lines
21 KiB
/*
|
|
* 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
|
|
h264bsdInit
|
|
h264bsdDecode
|
|
h264bsdShutdown
|
|
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
/*------------------------------------------------------------------------------
|
|
1. Include headers
|
|
------------------------------------------------------------------------------*/
|
|
#include "h264bsd_decoder.h"
|
|
#include "h264bsd_nal_unit.h"
|
|
#include "h264bsd_byte_stream.h"
|
|
#include "h264bsd_seq_param_set.h"
|
|
#include "h264bsd_pic_param_set.h"
|
|
#include "h264bsd_slice_header.h"
|
|
#include "h264bsd_slice_data.h"
|
|
#include "h264bsd_neighbour.h"
|
|
#include "h264bsd_util.h"
|
|
#include "h264bsd_dpb.h"
|
|
#include "h264bsd_deblocking.h"
|
|
#include "h264bsd_conceal.h"
|
|
#include "h264bsd_storage.h"
|
|
|
|
/*------------------------------------------------------------------------------
|
|
2. External compiler flags
|
|
--------------------------------------------------------------------------------
|
|
|
|
--------------------------------------------------------------------------------
|
|
3. Module defines
|
|
------------------------------------------------------------------------------*/
|
|
|
|
/*------------------------------------------------------------------------------
|
|
4. Local function prototypes
|
|
------------------------------------------------------------------------------*/
|
|
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Function name: h264bsdInit
|
|
|
|
Functional description:
|
|
Initialize the decoder.
|
|
|
|
Inputs:
|
|
noOutputReordering flag to indicate the decoder that it does not
|
|
have to perform reordering of display images.
|
|
|
|
Outputs:
|
|
pStorage pointer to initialized storage structure
|
|
|
|
Returns:
|
|
none
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
u32 h264bsdInit(storage_t *pStorage, u32 noOutputReordering)
|
|
{
|
|
|
|
/* Variables */
|
|
u32 size;
|
|
/* Code */
|
|
|
|
h264bsdInitStorage(pStorage);
|
|
|
|
/* allocate mbLayer to be next multiple of 64 to enable use of
|
|
* specific NEON optimized "memset" for clearing the structure */
|
|
size = (sizeof(macroblockLayer_t) + 63) & ~0x3F;
|
|
|
|
pStorage->mbLayer = (macroblockLayer_t*)malloc(size);
|
|
if (!pStorage->mbLayer)
|
|
return HANTRO_NOK;
|
|
|
|
if (noOutputReordering)
|
|
pStorage->noReordering = HANTRO_TRUE;
|
|
|
|
return HANTRO_OK;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Function: h264bsdDecodeInternal
|
|
|
|
Functional description:
|
|
Decode a NAL unit. This function calls other modules to perform
|
|
tasks like
|
|
* extract and decode NAL unit from the byte stream
|
|
* decode parameter sets
|
|
* decode slice header and slice data
|
|
* conceal errors in the picture
|
|
* perform deblocking filtering
|
|
|
|
This function contains top level control logic of the decoder.
|
|
|
|
Inputs:
|
|
pStorage pointer to storage data structure
|
|
byteStrm pointer to stream buffer given by application
|
|
len length of the buffer in bytes
|
|
|
|
Outputs:
|
|
readBytes number of bytes read from the stream is stored
|
|
here
|
|
|
|
Returns:
|
|
H264BSD_RDY decoding finished, nothing special
|
|
H264BSD_PIC_RDY decoding of a picture finished
|
|
H264BSD_HDRS_RDY param sets activated, information like
|
|
picture dimensions etc can be read
|
|
H264BSD_ERROR error in decoding
|
|
H264BSD_PARAM_SET_ERROR serious error in decoding, failed to
|
|
activate param sets
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
u32 h264bsdDecodeInternal(storage_t *pStorage, u8 *byteStrm, u32 len,
|
|
u32 *readBytes)
|
|
{
|
|
|
|
/* Variables */
|
|
|
|
u32 tmp, ppsId, spsId;
|
|
i32 picOrderCnt;
|
|
nalUnit_t nalUnit;
|
|
seqParamSet_t seqParamSet;
|
|
picParamSet_t picParamSet;
|
|
strmData_t strm;
|
|
u32 accessUnitBoundaryFlag = HANTRO_FALSE;
|
|
u32 picReady = HANTRO_FALSE;
|
|
|
|
/* if previous buffer was not finished and same pointer given -> skip NAL
|
|
* unit extraction */
|
|
if (pStorage->prevBufNotFinished && byteStrm == pStorage->prevBufPointer)
|
|
{
|
|
strm = pStorage->strm[0];
|
|
strm.pStrmCurrPos = strm.pStrmBuffStart;
|
|
strm.strmBuffReadBits = strm.bitPosInWord = 0;
|
|
*readBytes = pStorage->prevBytesConsumed;
|
|
}
|
|
else
|
|
{
|
|
tmp = h264bsdExtractNalUnit(byteStrm, len, &strm, readBytes);
|
|
if (tmp != HANTRO_OK)
|
|
{
|
|
EPRINT("BYTE_STREAM");
|
|
return(H264BSD_ERROR);
|
|
}
|
|
/* store stream */
|
|
pStorage->strm[0] = strm;
|
|
pStorage->prevBytesConsumed = *readBytes;
|
|
pStorage->prevBufPointer = byteStrm;
|
|
}
|
|
pStorage->prevBufNotFinished = HANTRO_FALSE;
|
|
|
|
tmp = h264bsdDecodeNalUnit(&strm, &nalUnit);
|
|
if (tmp != HANTRO_OK)
|
|
{
|
|
EPRINT("NAL_UNIT");
|
|
return(H264BSD_ERROR);
|
|
}
|
|
|
|
/* Discard unspecified, reserved, SPS extension and auxiliary picture slices */
|
|
if(nalUnit.nalUnitType == 0 || nalUnit.nalUnitType >= 13)
|
|
{
|
|
DEBUG(("DISCARDED NAL (UNSPECIFIED, REGISTERED, SPS ext or AUX slice)\n"));
|
|
return(H264BSD_RDY);
|
|
}
|
|
|
|
tmp = h264bsdCheckAccessUnitBoundary(
|
|
&strm,
|
|
&nalUnit,
|
|
pStorage,
|
|
&accessUnitBoundaryFlag);
|
|
if (tmp != HANTRO_OK)
|
|
{
|
|
EPRINT("ACCESS UNIT BOUNDARY CHECK");
|
|
if (tmp == PARAM_SET_ERROR)
|
|
return(H264BSD_PARAM_SET_ERROR);
|
|
else
|
|
return(H264BSD_ERROR);
|
|
}
|
|
|
|
if ( accessUnitBoundaryFlag )
|
|
{
|
|
DEBUG(("Access unit boundary\n"));
|
|
/* conceal if picture started and param sets activated */
|
|
if (pStorage->picStarted && pStorage->activeSps != NULL)
|
|
{
|
|
DEBUG(("CONCEALING..."));
|
|
|
|
/* return error if second phase of
|
|
* initialization is not completed */
|
|
if (pStorage->pendingActivation)
|
|
{
|
|
EPRINT("Pending activation not completed");
|
|
return (H264BSD_ERROR);
|
|
}
|
|
|
|
if (!pStorage->validSliceInAccessUnit)
|
|
{
|
|
pStorage->currImage->data =
|
|
h264bsdAllocateDpbImage(pStorage->dpb);
|
|
h264bsdInitRefPicList(pStorage->dpb);
|
|
tmp = h264bsdConceal(pStorage, pStorage->currImage, P_SLICE);
|
|
}
|
|
else
|
|
tmp = h264bsdConceal(pStorage, pStorage->currImage,
|
|
pStorage->sliceHeader->sliceType);
|
|
|
|
picReady = HANTRO_TRUE;
|
|
|
|
/* current NAL unit should be decoded on next activation -> set
|
|
* readBytes to 0 */
|
|
*readBytes = 0;
|
|
pStorage->prevBufNotFinished = HANTRO_TRUE;
|
|
DEBUG(("...DONE\n"));
|
|
}
|
|
else
|
|
{
|
|
pStorage->validSliceInAccessUnit = HANTRO_FALSE;
|
|
}
|
|
pStorage->skipRedundantSlices = HANTRO_FALSE;
|
|
}
|
|
|
|
if (!picReady)
|
|
{
|
|
switch (nalUnit.nalUnitType)
|
|
{
|
|
case NAL_SEQ_PARAM_SET:
|
|
DEBUG(("SEQ PARAM SET\n"));
|
|
tmp = h264bsdDecodeSeqParamSet(&strm, &seqParamSet);
|
|
if (tmp != HANTRO_OK)
|
|
{
|
|
EPRINT("SEQ_PARAM_SET");
|
|
FREE(seqParamSet.offsetForRefFrame);
|
|
FREE(seqParamSet.vuiParameters);
|
|
return(H264BSD_ERROR);
|
|
}
|
|
tmp = h264bsdStoreSeqParamSet(pStorage, &seqParamSet);
|
|
break;
|
|
|
|
case NAL_PIC_PARAM_SET:
|
|
DEBUG(("PIC PARAM SET\n"));
|
|
tmp = h264bsdDecodePicParamSet(&strm, &picParamSet);
|
|
if (tmp != HANTRO_OK)
|
|
{
|
|
EPRINT("PIC_PARAM_SET");
|
|
FREE(picParamSet.runLength);
|
|
FREE(picParamSet.topLeft);
|
|
FREE(picParamSet.bottomRight);
|
|
FREE(picParamSet.sliceGroupId);
|
|
return(H264BSD_ERROR);
|
|
}
|
|
tmp = h264bsdStorePicParamSet(pStorage, &picParamSet);
|
|
break;
|
|
|
|
case NAL_CODED_SLICE_IDR:
|
|
DEBUG(("IDR "));
|
|
/* fall through */
|
|
case NAL_CODED_SLICE:
|
|
DEBUG(("SLICE HEADER\n"));
|
|
|
|
/* picture successfully finished and still decoding same old
|
|
* access unit -> no need to decode redundant slices */
|
|
if (pStorage->skipRedundantSlices)
|
|
return(H264BSD_RDY);
|
|
|
|
pStorage->picStarted = HANTRO_TRUE;
|
|
|
|
if (h264bsdIsStartOfPicture(pStorage))
|
|
{
|
|
pStorage->numConcealedMbs = 0;
|
|
pStorage->currentPicId = 0;
|
|
|
|
tmp = h264bsdCheckPpsId(&strm, &ppsId);
|
|
ASSERT(tmp == HANTRO_OK);
|
|
/* store old activeSpsId and return headers ready
|
|
* indication if activeSps changes */
|
|
spsId = pStorage->activeSpsId;
|
|
tmp = h264bsdActivateParamSets(pStorage, ppsId,
|
|
IS_IDR_NAL_UNIT(&nalUnit) ?
|
|
HANTRO_TRUE : HANTRO_FALSE);
|
|
if (tmp != HANTRO_OK)
|
|
{
|
|
EPRINT("Param set activation");
|
|
pStorage->activePpsId = MAX_NUM_PIC_PARAM_SETS;
|
|
pStorage->activePps = NULL;
|
|
pStorage->activeSpsId = MAX_NUM_SEQ_PARAM_SETS;
|
|
pStorage->activeSps = NULL;
|
|
pStorage->pendingActivation = HANTRO_FALSE;
|
|
|
|
if(tmp == MEMORY_ALLOCATION_ERROR)
|
|
{
|
|
return H264BSD_MEMALLOC_ERROR;
|
|
}
|
|
else
|
|
return(H264BSD_PARAM_SET_ERROR);
|
|
}
|
|
|
|
if (spsId != pStorage->activeSpsId)
|
|
{
|
|
seqParamSet_t *oldSPS = NULL;
|
|
seqParamSet_t *newSPS = pStorage->activeSps;
|
|
u32 noOutputOfPriorPicsFlag = 1;
|
|
|
|
if(pStorage->oldSpsId < MAX_NUM_SEQ_PARAM_SETS)
|
|
{
|
|
oldSPS = pStorage->sps[pStorage->oldSpsId];
|
|
}
|
|
|
|
*readBytes = 0;
|
|
pStorage->prevBufNotFinished = HANTRO_TRUE;
|
|
|
|
|
|
if(nalUnit.nalUnitType == NAL_CODED_SLICE_IDR)
|
|
{
|
|
tmp =
|
|
h264bsdCheckPriorPicsFlag(&noOutputOfPriorPicsFlag,
|
|
&strm, newSPS,
|
|
pStorage->activePps,
|
|
nalUnit.nalUnitType);
|
|
}
|
|
else
|
|
{
|
|
tmp = HANTRO_NOK;
|
|
}
|
|
|
|
if((tmp != HANTRO_OK) ||
|
|
(noOutputOfPriorPicsFlag != 0) ||
|
|
(pStorage->dpb->noReordering) ||
|
|
(oldSPS == NULL) ||
|
|
(oldSPS->picWidthInMbs != newSPS->picWidthInMbs) ||
|
|
(oldSPS->picHeightInMbs != newSPS->picHeightInMbs) ||
|
|
(oldSPS->maxDpbSize != newSPS->maxDpbSize))
|
|
{
|
|
pStorage->dpb->flushed = 0;
|
|
}
|
|
else
|
|
{
|
|
h264bsdFlushDpb(pStorage->dpb);
|
|
}
|
|
|
|
pStorage->oldSpsId = pStorage->activeSpsId;
|
|
|
|
return(H264BSD_HDRS_RDY);
|
|
}
|
|
}
|
|
|
|
/* return error if second phase of
|
|
* initialization is not completed */
|
|
if (pStorage->pendingActivation)
|
|
{
|
|
EPRINT("Pending activation not completed");
|
|
return (H264BSD_ERROR);
|
|
}
|
|
tmp = h264bsdDecodeSliceHeader(&strm, pStorage->sliceHeader + 1,
|
|
pStorage->activeSps, pStorage->activePps, &nalUnit);
|
|
if (tmp != HANTRO_OK)
|
|
{
|
|
EPRINT("SLICE_HEADER");
|
|
return(H264BSD_ERROR);
|
|
}
|
|
if (h264bsdIsStartOfPicture(pStorage))
|
|
{
|
|
if (!IS_IDR_NAL_UNIT(&nalUnit))
|
|
{
|
|
tmp = h264bsdCheckGapsInFrameNum(pStorage->dpb,
|
|
pStorage->sliceHeader[1].frameNum,
|
|
nalUnit.nalRefIdc != 0 ?
|
|
HANTRO_TRUE : HANTRO_FALSE,
|
|
pStorage->activeSps->
|
|
gapsInFrameNumValueAllowedFlag);
|
|
if (tmp != HANTRO_OK)
|
|
{
|
|
EPRINT("Gaps in frame num");
|
|
return(H264BSD_ERROR);
|
|
}
|
|
}
|
|
pStorage->currImage->data =
|
|
h264bsdAllocateDpbImage(pStorage->dpb);
|
|
}
|
|
|
|
/* store slice header to storage if successfully decoded */
|
|
pStorage->sliceHeader[0] = pStorage->sliceHeader[1];
|
|
pStorage->validSliceInAccessUnit = HANTRO_TRUE;
|
|
pStorage->prevNalUnit[0] = nalUnit;
|
|
|
|
h264bsdComputeSliceGroupMap(pStorage,
|
|
pStorage->sliceHeader->sliceGroupChangeCycle);
|
|
|
|
h264bsdInitRefPicList(pStorage->dpb);
|
|
tmp = h264bsdReorderRefPicList(pStorage->dpb,
|
|
&pStorage->sliceHeader->refPicListReordering,
|
|
pStorage->sliceHeader->frameNum,
|
|
pStorage->sliceHeader->numRefIdxL0Active);
|
|
if (tmp != HANTRO_OK)
|
|
{
|
|
EPRINT("Reordering");
|
|
return(H264BSD_ERROR);
|
|
}
|
|
|
|
DEBUG(("SLICE DATA, FIRST %d\n",
|
|
pStorage->sliceHeader->firstMbInSlice));
|
|
tmp = h264bsdDecodeSliceData(&strm, pStorage,
|
|
pStorage->currImage, pStorage->sliceHeader);
|
|
if (tmp != HANTRO_OK)
|
|
{
|
|
EPRINT("SLICE_DATA");
|
|
h264bsdMarkSliceCorrupted(pStorage,
|
|
pStorage->sliceHeader->firstMbInSlice);
|
|
return(H264BSD_ERROR);
|
|
}
|
|
|
|
if (h264bsdIsEndOfPicture(pStorage))
|
|
{
|
|
picReady = HANTRO_TRUE;
|
|
pStorage->skipRedundantSlices = HANTRO_TRUE;
|
|
}
|
|
break;
|
|
|
|
case NAL_SEI:
|
|
DEBUG(("SEI MESSAGE, NOT DECODED"));
|
|
break;
|
|
|
|
default:
|
|
DEBUG(("NOT IMPLEMENTED YET %d\n",nalUnit.nalUnitType));
|
|
}
|
|
}
|
|
|
|
if (picReady)
|
|
{
|
|
h264bsdFilterPicture(pStorage->currImage, pStorage->mb);
|
|
|
|
h264bsdResetStorage(pStorage);
|
|
|
|
picOrderCnt = h264bsdDecodePicOrderCnt(pStorage->poc,
|
|
pStorage->activeSps, pStorage->sliceHeader, pStorage->prevNalUnit);
|
|
|
|
if (pStorage->validSliceInAccessUnit)
|
|
{
|
|
if (pStorage->prevNalUnit->nalRefIdc)
|
|
{
|
|
tmp = h264bsdMarkDecRefPic(pStorage->dpb,
|
|
&pStorage->sliceHeader->decRefPicMarking,
|
|
pStorage->currImage, pStorage->sliceHeader->frameNum,
|
|
picOrderCnt,
|
|
IS_IDR_NAL_UNIT(pStorage->prevNalUnit) ?
|
|
HANTRO_TRUE : HANTRO_FALSE,
|
|
pStorage->currentPicId, pStorage->numConcealedMbs);
|
|
}
|
|
/* non-reference picture, just store for possible display
|
|
* reordering */
|
|
else
|
|
{
|
|
tmp = h264bsdMarkDecRefPic(pStorage->dpb, NULL,
|
|
pStorage->currImage, pStorage->sliceHeader->frameNum,
|
|
picOrderCnt,
|
|
IS_IDR_NAL_UNIT(pStorage->prevNalUnit) ?
|
|
HANTRO_TRUE : HANTRO_FALSE,
|
|
pStorage->currentPicId, pStorage->numConcealedMbs);
|
|
}
|
|
}
|
|
|
|
pStorage->picStarted = HANTRO_FALSE;
|
|
pStorage->validSliceInAccessUnit = HANTRO_FALSE;
|
|
|
|
return(H264BSD_PIC_RDY);
|
|
}
|
|
else
|
|
return(H264BSD_RDY);
|
|
|
|
}
|
|
|
|
u32 h264bsdDecode(storage_t *pStorage, u8 *byteStrm, u32 len, u8 **picture, u32 *width, u32 *height) {
|
|
u32 bytesRead = 0;
|
|
u32 retCode = 3;
|
|
u32 readBytes = 0;
|
|
|
|
do {
|
|
len -= readBytes;
|
|
byteStrm += readBytes;
|
|
retCode = h264bsdDecodeInternal(pStorage, byteStrm, len, &readBytes);
|
|
} while (retCode == 0 || retCode == 2);
|
|
|
|
if (retCode == H264BSD_PIC_RDY) {
|
|
*width = (pStorage->activeSps->picWidthInMbs)*16;
|
|
*height = (pStorage->activeSps->picHeightInMbs)*16;
|
|
*picture = h264bsdDpbOutputPicture(pStorage->dpb)->data;
|
|
}
|
|
|
|
return retCode;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Function: h264bsdShutdown
|
|
|
|
Functional description:
|
|
Shutdown a decoder instance. Function frees all the memories
|
|
allocated for the decoder instance.
|
|
|
|
Inputs:
|
|
pStorage pointer to storage data structure
|
|
|
|
Returns:
|
|
none
|
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
void h264bsdShutdown(storage_t *pStorage)
|
|
{
|
|
|
|
/* Variables */
|
|
|
|
u32 i;
|
|
|
|
/* Code */
|
|
|
|
ASSERT(pStorage);
|
|
|
|
for (i = 0; i < MAX_NUM_SEQ_PARAM_SETS; i++)
|
|
{
|
|
if (pStorage->sps[i])
|
|
{
|
|
FREE(pStorage->sps[i]->offsetForRefFrame);
|
|
FREE(pStorage->sps[i]->vuiParameters);
|
|
FREE(pStorage->sps[i]);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < MAX_NUM_PIC_PARAM_SETS; i++)
|
|
{
|
|
if (pStorage->pps[i])
|
|
{
|
|
FREE(pStorage->pps[i]->runLength);
|
|
FREE(pStorage->pps[i]->topLeft);
|
|
FREE(pStorage->pps[i]->bottomRight);
|
|
FREE(pStorage->pps[i]->sliceGroupId);
|
|
FREE(pStorage->pps[i]);
|
|
}
|
|
}
|
|
|
|
FREE(pStorage->mbLayer);
|
|
FREE(pStorage->mb);
|
|
FREE(pStorage->sliceGroupMap);
|
|
|
|
if(pStorage->conversionBuffer != NULL) FREE(pStorage->conversionBuffer);
|
|
|
|
h264bsdFreeDpb(pStorage->dpb);
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Function name: h264bsdAlloc
|
|
|
|
Functional description:
|
|
Allocate storage for a decoder
|
|
|
|
Inputs:
|
|
none
|
|
|
|
Outputs:
|
|
none
|
|
|
|
Returns:
|
|
pStorage pointer to uninitialized storage structure
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
storage_t* h264bsdAlloc()
|
|
{
|
|
return (storage_t*)malloc(sizeof(storage_t));
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
|
|
Function name: h264bsdFree
|
|
|
|
Functional description:
|
|
Free storage for a decoder
|
|
|
|
Inputs:
|
|
pStorage pointer to storage structure
|
|
|
|
Outputs:
|
|
none
|
|
|
|
Returns:
|
|
none
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
void h264bsdFree(storage_t *pStorage)
|
|
{
|
|
free(pStorage);
|
|
}
|
|
|