shithub: h264bsd

ref: 947024fb1ce0ab5b51a4464184969c6c06b4c966
dir: /src/h264bsd_decoder.c/

View raw version
/*
 * 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
          h264bsdCurrentImage
          h264bsdNextOutputPicture
          h264bsdPicWidth
          h264bsdPicHeight
          h264bsdFlushBuffer
          h264bsdCheckValidParamSets
          h264bsdVideoRange
          h264bsdMatrixCoefficients
          h264bsdCroppingParams

------------------------------------------------------------------------------*/

/*------------------------------------------------------------------------------
    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 */

    ASSERT(pStorage);

    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;

    pStorage->rgbConversionBuffer = NULL;
    pStorage->rgbConversionBufferLength = 0;

    return HANTRO_OK;
}

/*------------------------------------------------------------------------------

    Function: h264bsdDecode

        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
            picId           identifier for a picture, assigned by the
                            application

        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 serius error in decoding, failed to
                                    activate param sets

------------------------------------------------------------------------------*/

u32 h264bsdDecode(storage_t *pStorage, u8 *byteStrm, u32 len, u32 picId,
    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;

/* Code */

    ASSERT(pStorage);
    ASSERT(byteStrm);
    ASSERT(len);
    ASSERT(readBytes);

    /* 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    = picId;

                    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);

}

/*------------------------------------------------------------------------------

    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);

    h264bsdFreeDpb(pStorage->dpb);

}

/*------------------------------------------------------------------------------

    Function: h264bsdNextOutputPicture

        Functional description:
            Get next output picture in display order.

        Inputs:
            pStorage    pointer to storage data structure

        Outputs:
            picId       identifier of the picture will be stored here
            isIdrPic    IDR flag of the picture will be stored here
            numErrMbs   number of concealed macroblocks in the picture
                        will be stored here

        Returns:
            pointer to the picture data
            NULL if no pictures available for display

------------------------------------------------------------------------------*/

u8* h264bsdNextOutputPicture(storage_t *pStorage, u32 *picId, u32 *isIdrPic,
    u32 *numErrMbs)
{

/* Variables */

    dpbOutPicture_t *pOut;

/* Code */

    ASSERT(pStorage);

    pOut = h264bsdDpbOutputPicture(pStorage->dpb);
    
    if (pOut != NULL)
    {
        *picId = pOut->picId;
        *isIdrPic = pOut->isIdr;
        *numErrMbs = pOut->numErrMbs;
        return (pOut->data);
    }
    else
        return(NULL);

}


/*------------------------------------------------------------------------------

    Function: h264bsdNextOutputPictureARGB

        Functional description:
            Get next output picture in display order, converted from YUV to ARGB.
            Freeing the resulting buffer is the callers responsibility.

        Inputs:
            pStorage    pointer to storage data structure

        Outputs:
            picId       identifier of the picture will be stored here
            isIdrPic    IDR flag of the picture will be stored here
            numErrMbs   number of concealed macroblocks in the picture
                        will be stored here
            length      The length of the resulting buffer

        Returns:
            pointer to the picture data
            NULL if no pictures available for display

------------------------------------------------------------------------------*/
u8* h264bsdNextOutputPictureARGB(storage_t *pStorage, u32 *picId, u32 *isIdrPic, u32 *numErrMbs, u32 *length)
{
    /* Variables */

    dpbOutPicture_t *pOut;
    u8              *data;
    /* Code */

    ASSERT(pStorage);

    pOut = h264bsdDpbOutputPicture(pStorage->dpb);
    
    if (pOut != NULL)
    {
        *picId = pOut->picId;
        *isIdrPic = pOut->isIdr;
        *numErrMbs = pOut->numErrMbs;

        data = yuv2rgb(pStorage, pOut->data);

        *length = pStorage->rgbConversionBufferLength;
        return data;
    }
    else
        return(NULL);
}

/*------------------------------------------------------------------------------

    Function: h264bsdPicWidth

        Functional description:
            Get width of the picture in macroblocks

        Inputs:
            pStorage    pointer to storage data structure

        Outputs:
            none

        Returns:
            picture width
            0 if parameters sets not yet activated

------------------------------------------------------------------------------*/

u32 h264bsdPicWidth(storage_t *pStorage)
{

/* Variables */

/* Code */

    ASSERT(pStorage);

    if (pStorage->activeSps)
        return(pStorage->activeSps->picWidthInMbs);
    else
        return(0);

}

/*------------------------------------------------------------------------------

    Function: h264bsdPicHeight

        Functional description:
            Get height of the picture in macroblocks

        Inputs:
            pStorage    pointer to storage data structure

        Outputs:
            none

        Returns:
            picture width
            0 if parameters sets not yet activated

------------------------------------------------------------------------------*/

u32 h264bsdPicHeight(storage_t *pStorage)
{

/* Variables */

/* Code */

    ASSERT(pStorage);

    if (pStorage->activeSps)
        return(pStorage->activeSps->picHeightInMbs);
    else
        return(0);

}

/*------------------------------------------------------------------------------

    Function: h264bsdFlushBuffer

        Functional description:
            Flush the decoded picture buffer, see dpb.c for details

        Inputs:
            pStorage    pointer to storage data structure

------------------------------------------------------------------------------*/

void h264bsdFlushBuffer(storage_t *pStorage)
{

/* Variables */

/* Code */

    ASSERT(pStorage);

    h264bsdFlushDpb(pStorage->dpb);

}

/*------------------------------------------------------------------------------

    Function: h264bsdCheckValidParamSets

        Functional description:
            Check if any valid parameter set combinations (SPS/PPS) exists.

        Inputs:
            pStorage    pointer to storage structure

        Returns:
            1       at least one valid SPS/PPS combination found
            0       no valid param set combinations found


------------------------------------------------------------------------------*/

u32 h264bsdCheckValidParamSets(storage_t *pStorage)
{

/* Variables */

/* Code */

    ASSERT(pStorage);

    return(h264bsdValidParamSets(pStorage) == HANTRO_OK ? 1 : 0);

}

/*------------------------------------------------------------------------------

    Function: h264bsdVideoRange

        Functional description:
            Get value of video_full_range_flag received in the VUI data.

        Inputs:
            pStorage    pointer to storage structure

        Returns:
            1   video_full_range_flag received and value is 1
            0   otherwise

------------------------------------------------------------------------------*/

u32 h264bsdVideoRange(storage_t *pStorage)
{

/* Variables */

/* Code */

    ASSERT(pStorage);

    if (pStorage->activeSps && pStorage->activeSps->vuiParametersPresentFlag &&
        pStorage->activeSps->vuiParameters &&
        pStorage->activeSps->vuiParameters->videoSignalTypePresentFlag &&
        pStorage->activeSps->vuiParameters->videoFullRangeFlag)
        return(1);
    else /* default value of video_full_range_flag is 0 */
        return(0);

}

/*------------------------------------------------------------------------------

    Function: h264bsdMatrixCoefficients

        Functional description:
            Get value of matrix_coefficients received in the VUI data

        Inputs:
            pStorage    pointer to storage structure

        Outputs:
            value of matrix_coefficients if received
            2   otherwise (this is the default value)

------------------------------------------------------------------------------*/

u32 h264bsdMatrixCoefficients(storage_t *pStorage)
{

/* Variables */

/* Code */

    ASSERT(pStorage);

    if (pStorage->activeSps && pStorage->activeSps->vuiParametersPresentFlag &&
        pStorage->activeSps->vuiParameters &&
        pStorage->activeSps->vuiParameters->videoSignalTypePresentFlag &&
        pStorage->activeSps->vuiParameters->colourDescriptionPresentFlag)
        return(pStorage->activeSps->vuiParameters->matrixCoefficients);
    else /* default unspecified */
        return(2);

}

/*------------------------------------------------------------------------------

    Function: hh264bsdCroppingParams

        Functional description:
            Get cropping parameters of the active SPS

        Inputs:
            pStorage    pointer to storage structure

        Outputs:
            croppingFlag    flag indicating if cropping params present is
                            stored here
            leftOffset      cropping left offset in pixels is stored here
            width           width of the image after cropping is stored here
            topOffset       cropping top offset in pixels is stored here
            height          height of the image after cropping is stored here

        Returns:
            none

------------------------------------------------------------------------------*/

void h264bsdCroppingParams(storage_t *pStorage, u32 *croppingFlag,
    u32 *leftOffset, u32 *width, u32 *topOffset, u32 *height)
{

/* Variables */

/* Code */

    ASSERT(pStorage);

    if (pStorage->activeSps && pStorage->activeSps->frameCroppingFlag)
    {
        *croppingFlag = 1;
        *leftOffset = 2 * pStorage->activeSps->frameCropLeftOffset;
        *width = 16 * pStorage->activeSps->picWidthInMbs -
                 2 * (pStorage->activeSps->frameCropLeftOffset +
                      pStorage->activeSps->frameCropRightOffset);
        *topOffset = 2 * pStorage->activeSps->frameCropTopOffset;
        *height = 16 * pStorage->activeSps->picHeightInMbs -
                  2 * (pStorage->activeSps->frameCropTopOffset +
                       pStorage->activeSps->frameCropBottomOffset);
    }
    else
    {
        *croppingFlag = 0;
        *leftOffset = 0;
        *width = 0;
        *topOffset = 0;
        *height = 0;
    }

}

/*------------------------------------------------------------------------------

    Function: h264bsdSampleAspectRatio

        Functional description:
            Get aspect ratio received in the VUI data

        Inputs:
            pStorage    pointer to storage structure

        Outputs:
            sarWidth    sample aspect ratio height
            sarHeight   sample aspect ratio width

------------------------------------------------------------------------------*/

void h264bsdSampleAspectRatio(storage_t *pStorage, u32 *sarWidth, u32 *sarHeight)
{

/* Variables */
    u32 w = 1;
    u32 h = 1;
/* Code */

    ASSERT(pStorage);


    if (pStorage->activeSps &&
        pStorage->activeSps->vuiParametersPresentFlag &&
        pStorage->activeSps->vuiParameters &&
        pStorage->activeSps->vuiParameters->aspectRatioPresentFlag )
    {
        switch (pStorage->activeSps->vuiParameters->aspectRatioIdc)
        {
            case ASPECT_RATIO_UNSPECIFIED:  w =   0; h =  0; break;
            case ASPECT_RATIO_1_1:          w =   1; h =  1; break;
            case ASPECT_RATIO_12_11:        w =  12; h = 11; break;
            case ASPECT_RATIO_10_11:        w =  10; h = 11; break;
            case ASPECT_RATIO_16_11:        w =  16; h = 11; break;
            case ASPECT_RATIO_40_33:        w =  40; h = 33; break;
            case ASPECT_RATIO_24_11:        w =  24; h = 11; break;
            case ASPECT_RATIO_20_11:        w =  20; h = 11; break;
            case ASPECT_RATIO_32_11:        w =  32; h = 11; break;
            case ASPECT_RATIO_80_33:        w =  80; h = 33; break;
            case ASPECT_RATIO_18_11:        w =  18; h = 11; break;
            case ASPECT_RATIO_15_11:        w =  15; h = 11; break;
            case ASPECT_RATIO_64_33:        w =  64; h = 33; break;
            case ASPECT_RATIO_160_99:       w = 160; h = 99; break;
            case ASPECT_RATIO_EXTENDED_SAR:
                w = pStorage->activeSps->vuiParameters->sarWidth;
                h = pStorage->activeSps->vuiParameters->sarHeight;
                if ((w == 0) || (h == 0))
                    w = h = 0;
                break;
            default:
                w = 0;
                h = 0;
                break;
        }
    }

    /* set aspect ratio*/
    *sarWidth = w;
    *sarHeight = h;

}

/*------------------------------------------------------------------------------

    Function: h264bsdProfile

        Functional description:
            Get profile information from active SPS

        Inputs:
            pStorage    pointer to storage structure

        Outputs:
            profile   current profile

------------------------------------------------------------------------------*/
u32 h264bsdProfile(storage_t *pStorage)
{
    if (pStorage->activeSps)
        return pStorage->activeSps->profileIdc;
    else
        return 0;
}

/*------------------------------------------------------------------------------

    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);
}

void yuvtorgb(int Y, int U, int V, u8 *rgb)
{
    int r, g, b, c, d, e;
    
    c = Y - 16;
    d = U - 128;
    e = V - 128;
    r = 1.164383 * c                   + 1.596027 * e ;
    g = 1.164383 * c - (0.391762 * d) - (0.812968 * e);
    b = 1.164383 * c +  2.017232 * d                  ;
   
    rgb[0] = 0xff;
    rgb[1] = CLIP1(r);
    rgb[2] = CLIP1(g);
    rgb[3] = CLIP1(b);
}


u8* yuv2rgb(storage_t *pStorage, u8* yuvBytes)
{
    int x;    
    int i,j;

    u8* y = yuvBytes;
    u8* u = 0;
    u8* v = 0;
    u8* out = 0;
    
    int w = h264bsdPicWidth(pStorage) * 16;
    int W = w*4;
    int w_2 = w/2;
    int h = h264bsdPicHeight(pStorage) * 16;

    int rgbLength = w*h*4;

    int uoffset = w*h;
    int voffset = w*h+((w*h)>>2);
    int luma = 0;
    
    u = yuvBytes+uoffset;
    v = yuvBytes+voffset;

    if (pStorage->rgbConversionBuffer != NULL && pStorage->rgbConversionBufferLength != rgbLength)
    {
        FREE(pStorage->rgbConversionBuffer);
        pStorage->rgbConversionBufferLength = 0;
    }

    if (pStorage->rgbConversionBuffer == NULL)
    {
        pStorage->rgbConversionBuffer = (u8*)malloc(rgbLength);
        if (pStorage->rgbConversionBuffer == NULL)
            return NULL;
        pStorage->rgbConversionBufferLength = rgbLength;
    }

    out = pStorage->rgbConversionBuffer;
    
    for(; h -= 2;){
        for(j = w_2; j--; ) {
            int u,v,y1,y2;
            
            y2 = yuvBytes[luma + w];
            y1 = yuvBytes[luma++];

            u = yuvBytes[uoffset++];
            v = yuvBytes[voffset++];

            yuvtorgb(y1, u, v, out);    
            yuvtorgb(y2, u, v, (out+W));
           
            out += 4;

            y2 = yuvBytes[luma + w];
            y1 = yuvBytes[luma++];

            yuvtorgb(y1, u, v, out);    
            yuvtorgb(y2, u, v, (out+W));

            out += 4;
        }

        luma += w;
        out += W;
    }
   
    return pStorage->rgbConversionBuffer;
}