/*
 * Copyright (C) 2011 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.
 */
#include "utils/Log.h"
#include "M4OSA_Types.h"
#include "M4OSA_Debug.h"

#include "M4VD_EXTERNAL_Interface.h"
#include "M4VD_Tools.h"
#include "M4_VideoEditingCommon.h"
#include "OMX_Video.h"
/**
 ************************************************************************
 * @file   M4VD_EXTERNAL_BitstreamParser.c
 * @brief
 * @note   This file implements external Bitstream parser
 ************************************************************************
 */

typedef struct {
    M4OSA_UInt8 code;
    M4OSA_Int32 profile;
    M4OSA_Int32 level;
} codeProfileLevel;

static codeProfileLevel mpeg4ProfileLevelTable[] = {
    {0x01, OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1},
    {0x02, OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level2},
    {0x03, OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level3},
    {0x04, OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level4a},
    {0x05, OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level5},
    {0x08, OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0},
    {0x11, OMX_VIDEO_MPEG4ProfileSimpleScalable,OMX_VIDEO_MPEG4Level1},
    {0x12, OMX_VIDEO_MPEG4ProfileSimpleScalable,OMX_VIDEO_MPEG4Level2},
    {0x21, OMX_VIDEO_MPEG4ProfileCore, OMX_VIDEO_MPEG4Level1},
    {0x22, OMX_VIDEO_MPEG4ProfileCore, OMX_VIDEO_MPEG4Level2},
    {0x32, OMX_VIDEO_MPEG4ProfileMain, OMX_VIDEO_MPEG4Level2},
    {0x33, OMX_VIDEO_MPEG4ProfileMain, OMX_VIDEO_MPEG4Level3},
    {0x34, OMX_VIDEO_MPEG4ProfileMain, OMX_VIDEO_MPEG4Level4},
    {0x42, OMX_VIDEO_MPEG4ProfileNbit, OMX_VIDEO_MPEG4Level2},
    {0x51, OMX_VIDEO_MPEG4ProfileScalableTexture, OMX_VIDEO_MPEG4Level1},
    {0x61, OMX_VIDEO_MPEG4ProfileSimpleFace, OMX_VIDEO_MPEG4Level1},
    {0x62, OMX_VIDEO_MPEG4ProfileSimpleFace, OMX_VIDEO_MPEG4Level2},
    {0x71, OMX_VIDEO_MPEG4ProfileBasicAnimated, OMX_VIDEO_MPEG4Level1},
    {0x72, OMX_VIDEO_MPEG4ProfileBasicAnimated, OMX_VIDEO_MPEG4Level2},
    {0x81, OMX_VIDEO_MPEG4ProfileHybrid, OMX_VIDEO_MPEG4Level1},
    {0x82, OMX_VIDEO_MPEG4ProfileHybrid, OMX_VIDEO_MPEG4Level2},
    {0x91, OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level1},
    {0x92, OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level2},
    {0x93, OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level3},
    {0x94, OMX_VIDEO_MPEG4ProfileAdvancedRealTime, OMX_VIDEO_MPEG4Level4},
    {0xa1, OMX_VIDEO_MPEG4ProfileCoreScalable, OMX_VIDEO_MPEG4Level1},
    {0xa2, OMX_VIDEO_MPEG4ProfileCoreScalable, OMX_VIDEO_MPEG4Level2},
    {0xa3, OMX_VIDEO_MPEG4ProfileCoreScalable, OMX_VIDEO_MPEG4Level3},
    {0xb1, OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level1},
    {0xb2, OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level2},
    {0xb3, OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level3},
    {0xb4, OMX_VIDEO_MPEG4ProfileAdvancedCoding, OMX_VIDEO_MPEG4Level4},
    {0xc1, OMX_VIDEO_MPEG4ProfileAdvancedCore, OMX_VIDEO_MPEG4Level1},
    {0xc2, OMX_VIDEO_MPEG4ProfileAdvancedCore, OMX_VIDEO_MPEG4Level2},
    {0xd1, OMX_VIDEO_MPEG4ProfileAdvancedScalable, OMX_VIDEO_MPEG4Level1},
    {0xd2, OMX_VIDEO_MPEG4ProfileAdvancedScalable, OMX_VIDEO_MPEG4Level2},
    {0xd3, OMX_VIDEO_MPEG4ProfileAdvancedScalable, OMX_VIDEO_MPEG4Level3},
    {0xf0, OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level0},
    {0xf1, OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level1},
    {0xf2, OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level2},
    {0xf3, OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level3},
    {0xf4, OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level4},
    {0xf5, OMX_VIDEO_MPEG4ProfileAdvancedSimple, OMX_VIDEO_MPEG4Level5}
};

M4OSA_UInt32 M4VD_EXTERNAL_GetBitsFromMemory(M4VS_Bitstream_ctxt* parsingCtxt,
     M4OSA_UInt32 nb_bits)
{
        return(M4VD_Tools_GetBitsFromMemory(parsingCtxt,nb_bits));
}

M4OSA_ERR M4VD_EXTERNAL_WriteBitsToMemory(M4OSA_UInt32 bitsToWrite,
                                                 M4OSA_MemAddr32 dest_bits,
                                                 M4OSA_UInt8 offset, M4OSA_UInt8 nb_bits)
{
        return (M4VD_Tools_WriteBitsToMemory( bitsToWrite,dest_bits,
                                                offset,  nb_bits));
}

M4OSA_ERR M4DECODER_EXTERNAL_ParseVideoDSI(M4OSA_UInt8* pVol, M4OSA_Int32 aVolSize,
                                             M4DECODER_MPEG4_DecoderConfigInfo* pDci,
                                             M4DECODER_VideoSize* pVideoSize)
{
    M4VS_Bitstream_ctxt parsingCtxt;
    M4OSA_UInt32 code, j;
    M4OSA_MemAddr8 start;
    M4OSA_UInt8 i;
    M4OSA_UInt32 time_incr_length;
    M4OSA_UInt8 vol_verid=0, b_hierarchy_type;

    /* Parsing variables */
    M4OSA_UInt8 video_object_layer_shape = 0;
    M4OSA_UInt8 sprite_enable = 0;
    M4OSA_UInt8 reduced_resolution_vop_enable = 0;
    M4OSA_UInt8 scalability = 0;
    M4OSA_UInt8 enhancement_type = 0;
    M4OSA_UInt8 complexity_estimation_disable = 0;
    M4OSA_UInt8 interlaced = 0;
    M4OSA_UInt8 sprite_warping_points = 0;
    M4OSA_UInt8 sprite_brightness_change = 0;
    M4OSA_UInt8 quant_precision = 0;

    /* Fill the structure with default parameters */
    pVideoSize->m_uiWidth              = 0;
    pVideoSize->m_uiHeight             = 0;

    pDci->uiTimeScale          = 0;
    pDci->uiProfile            = 0;
    pDci->uiUseOfResynchMarker = 0;
    pDci->bDataPartition       = M4OSA_FALSE;
    pDci->bUseOfRVLC           = M4OSA_FALSE;

    /* Reset the bitstream context */
    parsingCtxt.stream_byte = 0;
    parsingCtxt.stream_index = 8;
    parsingCtxt.in = (M4OSA_Int8 *)pVol;

    start = (M4OSA_Int8 *)pVol;

    /* Start parsing */
    while (parsingCtxt.in - start < aVolSize)
    {
        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 8);
        if (code == 0)
        {
            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 8);
            if (code == 0)
            {
                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 8);
                if (code == 1)
                {
                    /* start code found */
                    code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 8);

                    /* ----- 0x20..0x2F : video_object_layer_start_code ----- */

                    if ((code > 0x1F) && (code < 0x30))
                    {
                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                 1);/* random accessible vol */
                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                 8);/* video object type indication */
                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                 1);/* is object layer identifier */
                        if (code == 1)
                        {
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                     4); /* video object layer verid */
                            vol_verid = (M4OSA_UInt8)code;
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                     3); /* video object layer priority */
                        }
                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                 4);/* aspect ratio */
                        if (code == 15)
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                     16); /* par_width and par_height (8+8) */
                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                 1);/* vol control parameters */
                        if (code == 1)
                        {
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                     3);/* chroma format + low delay (3+1) */
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                     1);/* vbv parameters */
                            if (code == 1)
                            {
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         32);/* first and latter half bitrate + 2 marker bits
                                            (15 + 1 + 15 + 1) */
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         31);/* first and latter half vbv buffer size + first
                                          half vbv occupancy + marker bits (15+1+3+11+1)*/
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         16);/* first half vbv occupancy + marker bits (15+1)*/
                            }
                        }
                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                 2); /* video object layer shape */
                        /* Need to save it for vop parsing */
                        video_object_layer_shape = (M4OSA_UInt8)code;

                        if (code != 0) return 0; /* only rectangular case supported */

                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                 1); /* Marker bit */
                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                 16); /* VOP time increment resolution */
                        pDci->uiTimeScale = code;

                        /* Computes time increment length */
                        j    = code - 1;
                        for (i = 0; (i < 32) && (j != 0); j >>=1)
                        {
                            i++;
                        }
                        time_incr_length = (i == 0) ? 1 : i;

                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                 1);/* Marker bit */
                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                 1);/* Fixed VOP rate */
                        if (code == 1)
                        {
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                     time_incr_length);/* Fixed VOP time increment */
                        }

                        if(video_object_layer_shape != 1) /* 1 = Binary */
                        {
                            if(video_object_layer_shape == 0) /* 0 = rectangular */
                            {
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         1);/* Marker bit */
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         13);/* Width */
                                pVideoSize->m_uiWidth = code;
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         1);/* Marker bit */
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         13);/* Height */
                                pVideoSize->m_uiHeight = code;
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         1);/* Marker bit */
                            }
                        }

                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                 1);/* interlaced */
                        interlaced = (M4OSA_UInt8)code;
                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                 1);/* OBMC disable */

                        if(vol_verid == 1)
                        {
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                     1);/* sprite enable */
                            sprite_enable = (M4OSA_UInt8)code;
                        }
                        else
                        {
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                     2);/* sprite enable */
                            sprite_enable = (M4OSA_UInt8)code;
                        }
                        if ((sprite_enable == 1) || (sprite_enable == 2))
                        /* Sprite static = 1 and Sprite GMC = 2 */
                        {
                            if (sprite_enable != 2)
                            {

                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         13);/* sprite width */
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         1);/* Marker bit */
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         13);/* sprite height */
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         1);/* Marker bit */
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         13);/* sprite l coordinate */
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         1);/* Marker bit */
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         13);/* sprite top coordinate */
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         1);/* Marker bit */
                            }

                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                     6);/* sprite warping points */
                            sprite_warping_points = (M4OSA_UInt8)code;
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                     2);/* sprite warping accuracy */
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                     1);/* sprite brightness change */
                            sprite_brightness_change = (M4OSA_UInt8)code;
                            if (sprite_enable != 2)
                            {
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                             1);/* low latency sprite enable */
                            }
                        }
                        if ((vol_verid != 1) && (video_object_layer_shape != 0))
                        {
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         1);/* sadct disable */
                        }

                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 1); /* not 8 bits */
                        if (code)
                        {
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                     4);/* quant precision */
                            quant_precision = (M4OSA_UInt8)code;
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         4);/* bits per pixel */
                        }

                        /* greyscale not supported */
                        if(video_object_layer_shape == 3)
                        {
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                     3); /* nogray quant update + composition method +
                                            linear composition */
                        }

                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                     1);/* quant type */
                        if (code)
                        {
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         1);/* load intra quant mat */
                            if (code)
                            {
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 8);/* */
                                 i    = 1;
                                while (i < 64)
                                {
                                    code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 8);
                                    if (code == 0)
                                        break;
                                    i++;
                                }
                            }

                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                         1);/* load non intra quant mat */
                            if (code)
                            {
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 8);/* */
                                 i    = 1;
                                while (i < 64)
                                {
                                    code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 8);
                                    if (code == 0)
                                        break;
                                    i++;
                                }
                            }
                        }

                        if (vol_verid != 1)
                        {
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                     1);/* quarter sample */
                        }

                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                     1);/* complexity estimation disable */
                        complexity_estimation_disable = (M4OSA_UInt8)code;
                        if (!code)
                        {
                            //return M4ERR_NOT_IMPLEMENTED;
                        }

                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                     1);/* resync marker disable */
                        pDci->uiUseOfResynchMarker = (code) ? 0 : 1;

                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt,
                                     1);/* data partitionned */
                        pDci->bDataPartition = (code) ? M4OSA_TRUE : M4OSA_FALSE;
                        if (code)
                        {
                            /* reversible VLC */
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 1);
                            pDci->bUseOfRVLC = (code) ? M4OSA_TRUE : M4OSA_FALSE;
                        }

                        if (vol_verid != 1)
                        {
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 1);/* newpred */
                            if (code)
                            {
                                //return M4ERR_PARAMETER;
                            }
                            /* reduced resolution vop enable */
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 1);
                            reduced_resolution_vop_enable = (M4OSA_UInt8)code;
                        }

                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 1);/* scalability */
                        scalability = (M4OSA_UInt8)code;
                        if (code)
                        {
                            /* hierarchy type */
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 1);
                            b_hierarchy_type = (M4OSA_UInt8)code;
                            /* ref layer id */
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 4);
                            /* ref sampling direct */
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 1);
                            /* hor sampling factor N */
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 5);
                            /* hor sampling factor M */
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 5);
                            /* vert sampling factor N */
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 5);
                            /* vert sampling factor M */
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 5);
                            /* enhancement type */
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 1);
                            enhancement_type = (M4OSA_UInt8)code;
                            if ((!b_hierarchy_type) && (video_object_layer_shape == 1))
                            {
                                /* use ref shape */
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 1);
                                /* use ref texture */
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 1);
                                /* shape hor sampling factor N */
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 5);
                                /* shape hor sampling factor M */
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 5);
                                /* shape vert sampling factor N */
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 5);
                                /* shape vert sampling factor M */
                                code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 5);
                            }
                        }
                        break;
                    }

                    /* ----- 0xB0 : visual_object_sequence_start_code ----- */

                    else if(code == 0xB0)
                    {
                        /* profile_and_level_indication */
                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 8);
                        pDci->uiProfile = (M4OSA_UInt8)code;
                    }

                    /* ----- 0xB5 : visual_object_start_code ----- */

                    else if(code == 0xB5)
                    {
                        /* is object layer identifier */
                        code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 1);
                        if (code == 1)
                        {
                             /* visual object verid */
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 4);
                            vol_verid = (M4OSA_UInt8)code;
                             /* visual object layer priority */
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 3);
                        }
                        else
                        {
                             /* Realign on byte */
                            code = M4VD_EXTERNAL_GetBitsFromMemory(&parsingCtxt, 7);
                            vol_verid = 1;
                        }
                    }

                    /* ----- end ----- */
                }
                else
                {
                    if ((code >> 2) == 0x20)
                    {
                        /* H263 ...-> wrong*/
                        break;
                    }
                }
            }
        }
    }

    return M4NO_ERROR;
}

M4OSA_ERR getAVCProfileAndLevel(M4OSA_UInt8* pDSI, M4OSA_Int32 DSISize,
                      M4OSA_Int32 *pProfile, M4OSA_Int32 *pLevel) {

    M4OSA_UInt16 index = 28; /* the 29th byte is SPS start */
    M4OSA_Bool constraintSet3;

    if ((pProfile == M4OSA_NULL) || (pLevel == M4OSA_NULL)) {
        return M4ERR_PARAMETER;
    }

    if ((DSISize <= index) || (pDSI == M4OSA_NULL)) {
        LOGE("getAVCProfileAndLevel: DSI is invalid");
        *pProfile = M4VIDEOEDITING_VIDEO_UNKNOWN_PROFILE;
        *pLevel = M4VIDEOEDITING_VIDEO_UNKNOWN_LEVEL;
        return M4ERR_PARAMETER;
    }

    constraintSet3 = (pDSI[index+2] & 0x10);
    LOGV("getAVCProfileAndLevel profile_byte %d, level_byte: %d constrain3flag",
          pDSI[index+1], pDSI[index+3], constraintSet3);

    switch (pDSI[index+1]) {
        case 66:
            *pProfile = OMX_VIDEO_AVCProfileBaseline;
            break;
        case 77:
            *pProfile = OMX_VIDEO_AVCProfileMain;
            break;
        case 88:
            *pProfile = OMX_VIDEO_AVCProfileExtended;
            break;
        case 100:
            *pProfile = OMX_VIDEO_AVCProfileHigh;
            break;
        case 110:
            *pProfile = OMX_VIDEO_AVCProfileHigh10;
            break;
        case 122:
            *pProfile = OMX_VIDEO_AVCProfileHigh422;
            break;
        case 244:
            *pProfile = OMX_VIDEO_AVCProfileHigh444;
            break;
        default:
            *pProfile = M4VIDEOEDITING_VIDEO_UNKNOWN_PROFILE;
    }

    switch (pDSI[index+3]) {
        case 10:
            *pLevel = OMX_VIDEO_AVCLevel1;
            break;
        case 11:
            if (constraintSet3)
                *pLevel = OMX_VIDEO_AVCLevel1b;
            else
                *pLevel = OMX_VIDEO_AVCLevel11;
            break;
        case 12:
            *pLevel = OMX_VIDEO_AVCLevel12;
            break;
        case 13:
            *pLevel = OMX_VIDEO_AVCLevel13;
            break;
        case 20:
            *pLevel = OMX_VIDEO_AVCLevel2;
            break;
        case 21:
            *pLevel = OMX_VIDEO_AVCLevel21;
            break;
        case 22:
            *pLevel = OMX_VIDEO_AVCLevel22;
            break;
        case 30:
            *pLevel = OMX_VIDEO_AVCLevel3;
            break;
        case 31:
            *pLevel = OMX_VIDEO_AVCLevel31;
            break;
        case 32:
            *pLevel = OMX_VIDEO_AVCLevel32;
            break;
        case 40:
            *pLevel = OMX_VIDEO_AVCLevel4;
            break;
        case 41:
            *pLevel = OMX_VIDEO_AVCLevel41;
            break;
        case 42:
            *pLevel = OMX_VIDEO_AVCLevel42;
            break;
        case 50:
            *pLevel = OMX_VIDEO_AVCLevel5;
            break;
        case 51:
            *pLevel = OMX_VIDEO_AVCLevel51;
            break;
        default:
            *pLevel = M4VIDEOEDITING_VIDEO_UNKNOWN_LEVEL;
    }
    LOGV("getAVCProfileAndLevel profile %ld level %ld", *pProfile, *pLevel);
    return M4NO_ERROR;
}

M4OSA_ERR getH263ProfileAndLevel(M4OSA_UInt8* pDSI, M4OSA_Int32 DSISize,
                      M4OSA_Int32 *pProfile, M4OSA_Int32 *pLevel) {

    M4OSA_UInt16 index = 7; /* the 5th and 6th bytes contain the level and profile */

    if ((pProfile == M4OSA_NULL) || (pLevel == M4OSA_NULL)) {
        LOGE("getH263ProfileAndLevel invalid pointer for pProfile");
        return M4ERR_PARAMETER;
    }

    if ((DSISize < index) || (pDSI == M4OSA_NULL)) {
        LOGE("getH263ProfileAndLevel: DSI is invalid");
        *pProfile = M4VIDEOEDITING_VIDEO_UNKNOWN_PROFILE;
        *pLevel = M4VIDEOEDITING_VIDEO_UNKNOWN_LEVEL;
        return M4ERR_PARAMETER;
    }
    LOGV("getH263ProfileAndLevel profile_byte %d, level_byte",
          pDSI[6], pDSI[5]);
    /* get the H263 level */
    switch (pDSI[5]) {
        case 10:
            *pLevel = OMX_VIDEO_H263Level10;
            break;
        case 20:
            *pLevel = OMX_VIDEO_H263Level20;
            break;
        case 30:
            *pLevel = OMX_VIDEO_H263Level30;
            break;
        case 40:
            *pLevel = OMX_VIDEO_H263Level40;
            break;
        case 45:
            *pLevel = OMX_VIDEO_H263Level45;
            break;
        case 50:
            *pLevel = OMX_VIDEO_H263Level50;
            break;
        case 60:
            *pLevel = OMX_VIDEO_H263Level60;
            break;
        case 70:
            *pLevel = OMX_VIDEO_H263Level70;
            break;
        default:
           *pLevel = M4VIDEOEDITING_VIDEO_UNKNOWN_LEVEL;
    }

    /* get H263 profile */
    switch (pDSI[6]) {
        case 0:
            *pProfile = OMX_VIDEO_H263ProfileBaseline;
            break;
        case 1:
            *pProfile = OMX_VIDEO_H263ProfileH320Coding;
            break;
        case 2:
            *pProfile = OMX_VIDEO_H263ProfileBackwardCompatible;
            break;
        case 3:
            *pProfile = OMX_VIDEO_H263ProfileISWV2;
            break;
        case 4:
            *pProfile = OMX_VIDEO_H263ProfileISWV3;
            break;
        case 5:
            *pProfile = OMX_VIDEO_H263ProfileHighCompression;
            break;
        case 6:
            *pProfile = OMX_VIDEO_H263ProfileInternet;
            break;
        case 7:
            *pProfile = OMX_VIDEO_H263ProfileInterlace;
            break;
        case 8:
            *pProfile = OMX_VIDEO_H263ProfileHighLatency;
            break;
        default:
           *pProfile = M4VIDEOEDITING_VIDEO_UNKNOWN_PROFILE;
    }
    LOGV("getH263ProfileAndLevel profile %ld level %ld", *pProfile, *pLevel);
    return M4NO_ERROR;
}

M4OSA_ERR getMPEG4ProfileAndLevel(M4OSA_UInt8 profileAndLevel,
                      M4OSA_Int32 *pProfile, M4OSA_Int32 *pLevel) {

    M4OSA_UInt32 i = 0;
    M4OSA_UInt32 length = 0;
    if ((pProfile == M4OSA_NULL) || (pLevel == M4OSA_NULL)) {
        return M4ERR_PARAMETER;
    }
    LOGV("getMPEG4ProfileAndLevel profileAndLevel %d", profileAndLevel);
    length = sizeof(mpeg4ProfileLevelTable) /sizeof(mpeg4ProfileLevelTable[0]);
    *pProfile = M4VIDEOEDITING_VIDEO_UNKNOWN_PROFILE;
    *pLevel = M4VIDEOEDITING_VIDEO_UNKNOWN_LEVEL;
    for (i = 0; i < length; i++) {
        if (mpeg4ProfileLevelTable[i].code == profileAndLevel) {
            *pProfile = mpeg4ProfileLevelTable[i].profile;
            *pLevel = mpeg4ProfileLevelTable[i].level;
            break;
        }
    }
    LOGV("getMPEG4ProfileAndLevel profile %ld level %ld", *pProfile, *pLevel);
    return M4NO_ERROR;
}