/*--------------------------------------------------------------------------
Copyright (c) 2010 - 2013, The Linux Foundation. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of  The Linux Foundation nor
      the names of its contributors may be used to endorse or promote
      products derived from this software without specific prior written
      permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------*/
/*========================================================================

                      O p e n M M
         V i d e o   U t i l i t i e s

*//** @file VideoUtils.cpp
  This module contains utilities and helper routines.

@par EXTERNALIZED FUNCTIONS

@par INITIALIZATION AND SEQUENCING REQUIREMENTS
  (none)

*//*====================================================================== */

/* =======================================================================

                     INCLUDE FILES FOR MODULE

========================================================================== */
#include "h264_utils.h"
#include "extra_data_handler.h"
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/time.h>
#ifdef _ANDROID_
#include <cutils/properties.h>
extern "C" {
#include<utils/Log.h>
}

#endif

/* =======================================================================

   DEFINITIONS AND DECLARATIONS FOR MODULE

   This section contains definitions for constants, macros, types, variables
   and other items needed by this module.

   ========================================================================== */


#define MAX_SUPPORTED_LEVEL 32

    RbspParser::RbspParser (const uint8 *_begin, const uint8 *_end)
: begin (_begin), end(_end), pos (- 1), bit (0),
    cursor (0xFFFFFF), advanceNeeded (true)
{
}

// Destructor
/*lint -e{1540}  Pointer member neither freed nor zeroed by destructor
 * No problem
 */
RbspParser::~RbspParser () {}

// Return next RBSP byte as a word
uint32 RbspParser::next ()
{
    if (advanceNeeded) advance ();
    //return static_cast<uint32> (*pos);
    return static_cast<uint32> (begin[pos]);
}

// Advance RBSP decoder to next byte
void RbspParser::advance ()
{
    ++pos;
    //if (pos >= stop)
    if (begin + pos == end) {
        /*lint -e{730}  Boolean argument to function
         * I don't see a problem here
         */
        //throw false;
        ALOGV("H264Parser-->NEED TO THROW THE EXCEPTION...");
    }
    cursor <<= 8;
    //cursor |= static_cast<uint32> (*pos);
    cursor |= static_cast<uint32> (begin[pos]);
    if ((cursor & 0xFFFFFF) == 0x000003) {
        advance ();
    }
    advanceNeeded = false;
}

// Decode unsigned integer
uint32 RbspParser::u (uint32 n)
{
    uint32 i, s, x = 0;
    for (i = 0; i < n; i += s) {
        s = static_cast<uint32>STD_MIN(static_cast<int>(8 - bit),
                static_cast<int>(n - i));
        x <<= s;

        x |= ((next () >> ((8 - static_cast<uint32>(bit)) - s)) &
                ((1 << s) - 1));

        bit = (bit + s) % 8;
        if (!bit) {
            advanceNeeded = true;
        }
    }
    return x;
}

// Decode unsigned integer Exp-Golomb-coded syntax element
uint32 RbspParser::ue ()
{
    int leadingZeroBits = -1;
    for (uint32 b = 0; !b; ++leadingZeroBits) {
        b = u (1);
    }
    return ((1 << leadingZeroBits) - 1) +
        u (static_cast<uint32>(leadingZeroBits));
}

// Decode signed integer Exp-Golomb-coded syntax element
int32 RbspParser::se ()
{
    const uint32 x = ue ();
    if (!x) return 0;
    else if (x & 1) return static_cast<int32> ((x >> 1) + 1);
    else return - static_cast<int32> (x >> 1);
}

void H264_Utils::allocate_rbsp_buffer(uint32 inputBufferSize)
{
    m_rbspBytes = (byte *) calloc(1,inputBufferSize);
    m_prv_nalu.nal_ref_idc = 0;
    m_prv_nalu.nalu_type = NALU_TYPE_UNSPECIFIED;
}

H264_Utils::H264_Utils(): m_height(0),
    m_width(0),
    m_rbspBytes(NULL),
    m_au_data (false)
{
    initialize_frame_checking_environment();
}

H264_Utils::~H264_Utils()
{
    /*  if(m_pbits)
        {
        delete(m_pbits);
        m_pbits = NULL;
        }
     */
    if (m_rbspBytes) {
        free(m_rbspBytes);
        m_rbspBytes = NULL;
    }
}

/***********************************************************************/
/*
FUNCTION:
H264_Utils::initialize_frame_checking_environment

DESCRIPTION:
Extract RBSP data from a NAL

INPUT/OUTPUT PARAMETERS:
None

RETURN VALUE:
boolean

SIDE EFFECTS:
None.
 */
/***********************************************************************/
void H264_Utils::initialize_frame_checking_environment()
{
    m_forceToStichNextNAL = false;
    m_au_data = false;
    m_prv_nalu.nal_ref_idc = 0;
    m_prv_nalu.nalu_type = NALU_TYPE_UNSPECIFIED;
}

/***********************************************************************/
/*
FUNCTION:
H264_Utils::extract_rbsp

DESCRIPTION:
Extract RBSP data from a NAL

INPUT/OUTPUT PARAMETERS:
<In>
buffer : buffer containing start code or nal length + NAL units
buffer_length : the length of the NAL buffer
start_code : If true, start code is detected,
otherwise size nal length is detected
size_of_nal_length_field: size of nal length field

<Out>
rbsp_bistream : extracted RBSP bistream
rbsp_length : the length of the RBSP bitstream
nal_unit : decoded NAL header information

RETURN VALUE:
boolean

SIDE EFFECTS:
None.
 */
/***********************************************************************/

boolean H264_Utils::extract_rbsp(OMX_IN   OMX_U8  *buffer,
        OMX_IN   OMX_U32 buffer_length,
        OMX_IN   OMX_U32 size_of_nal_length_field,
        OMX_OUT  OMX_U8  *rbsp_bistream,
        OMX_OUT  OMX_U32 *rbsp_length,
        OMX_OUT  NALU    *nal_unit)
{
    byte coef1, coef2, coef3;
    uint32 pos = 0;
    uint32 nal_len = buffer_length;
    uint32 sizeofNalLengthField = 0;
    uint32 zero_count;
    boolean eRet = true;
    boolean start_code = (size_of_nal_length_field==0)?true:false;

    if (start_code) {
        // Search start_code_prefix_one_3bytes (0x000001)
        coef2 = buffer[pos++];
        coef3 = buffer[pos++];
        do {
            if (pos >= buffer_length) {
                ALOGE("ERROR: In %s() - line %d", __func__, __LINE__);
                return false;
            }

            coef1 = coef2;
            coef2 = coef3;
            coef3 = buffer[pos++];
        } while (coef1 || coef2 || coef3 != 1);
    } else if (size_of_nal_length_field) {
        /* This is the case to play multiple NAL units inside each access unit*/
        /* Extract the NAL length depending on sizeOfNALength field */
        sizeofNalLengthField = size_of_nal_length_field;
        nal_len = 0;
        while (size_of_nal_length_field--) {
            nal_len |= buffer[pos++]<<(size_of_nal_length_field<<3);
        }
        if (nal_len >= buffer_length) {
            ALOGE("ERROR: In %s() - line %d", __func__, __LINE__);
            return false;
        }
    }

    if (nal_len > buffer_length) {
        ALOGE("ERROR: In %s() - line %d", __func__, __LINE__);
        return false;
    }
    if (pos + 1 > (nal_len + sizeofNalLengthField)) {
        ALOGE("ERROR: In %s() - line %d", __func__, __LINE__);
        return false;
    }
    if ((nal_unit->forbidden_zero_bit = (buffer[pos] & 0x80)) != 0) {
        ALOGE("ERROR: In %s() - line %d", __func__, __LINE__);
    }
    nal_unit->nal_ref_idc   = (buffer[pos] & 0x60) >> 5;
    nal_unit->nalu_type = buffer[pos++] & 0x1f;
    ALOGV("@#@# Pos = %x NalType = %x buflen = %d",
            pos-1, nal_unit->nalu_type, buffer_length);
    *rbsp_length = 0;


    if ( nal_unit->nalu_type == NALU_TYPE_EOSEQ ||
            nal_unit->nalu_type == NALU_TYPE_EOSTREAM)
        return (nal_len + sizeofNalLengthField);

    zero_count = 0;
    while (pos < (nal_len+sizeofNalLengthField)) {  //similar to for in p-42
        if ( zero_count == 2 ) {
            if ( buffer[pos] == 0x03 ) {
                pos ++;
                zero_count = 0;
                continue;
            }
            if ( buffer[pos] <= 0x01 ) {
                if ( start_code ) {
                    *rbsp_length -= 2;
                    pos -= 2;
                    return pos;
                }
            }
            zero_count = 0;
        }
        zero_count ++;
        if ( buffer[pos] != 0 )
            zero_count = 0;

        rbsp_bistream[(*rbsp_length)++] = buffer[pos++];
    }

    return eRet;
}

/*===========================================================================
FUNCTION:
H264_Utils::iSNewFrame

DESCRIPTION:
Returns true if NAL parsing successfull otherwise false.

INPUT/OUTPUT PARAMETERS:
<In>
buffer : buffer containing start code or nal length + NAL units
buffer_length : the length of the NAL buffer
start_code : If true, start code is detected,
otherwise size nal length is detected
size_of_nal_length_field: size of nal length field
<out>
isNewFrame: true if the NAL belongs to a differenet frame
false if the NAL belongs to a current frame

RETURN VALUE:
boolean  true, if nal parsing is successful
false, if the nal parsing has errors

SIDE EFFECTS:
None.
===========================================================================*/
bool H264_Utils::isNewFrame(OMX_BUFFERHEADERTYPE *p_buf_hdr,
        OMX_IN OMX_U32 size_of_nal_length_field,
        OMX_OUT OMX_BOOL &isNewFrame)
{
    NALU nal_unit;
    uint16 first_mb_in_slice = 0;
    OMX_IN OMX_U32 numBytesInRBSP = 0;
    OMX_IN OMX_U8 *buffer = p_buf_hdr->pBuffer;
    OMX_IN OMX_U32 buffer_length = p_buf_hdr->nFilledLen;
    bool eRet = true;

    ALOGV("isNewFrame: buffer %p buffer_length %d "
            "size_of_nal_length_field %d", buffer, buffer_length,
            size_of_nal_length_field);

    if ( false == extract_rbsp(buffer, buffer_length, size_of_nal_length_field,
                m_rbspBytes, &numBytesInRBSP, &nal_unit) ) {
        ALOGE("ERROR: In %s() - extract_rbsp() failed", __func__);
        isNewFrame = OMX_FALSE;
        eRet = false;
    } else {
        nalu_type = nal_unit.nalu_type;
        switch (nal_unit.nalu_type) {
            case NALU_TYPE_IDR:
            case NALU_TYPE_NON_IDR: {
                            ALOGV("AU Boundary with NAL type %d ",nal_unit.nalu_type);
                            if (m_forceToStichNextNAL) {
                                isNewFrame = OMX_FALSE;
                            } else {
                                RbspParser rbsp_parser(m_rbspBytes, (m_rbspBytes+numBytesInRBSP));
                                first_mb_in_slice = rbsp_parser.ue();

                                if ((!first_mb_in_slice) || /*(slice.prv_frame_num != slice.frame_num ) ||*/
                                        ( (m_prv_nalu.nal_ref_idc != nal_unit.nal_ref_idc) && ( nal_unit.nal_ref_idc * m_prv_nalu.nal_ref_idc == 0 ) ) ||
                                        /*( ((m_prv_nalu.nalu_type == NALU_TYPE_IDR) && (nal_unit.nalu_type == NALU_TYPE_IDR)) && (slice.idr_pic_id != slice.prv_idr_pic_id) ) || */
                                        ( (m_prv_nalu.nalu_type != nal_unit.nalu_type ) && ((m_prv_nalu.nalu_type == NALU_TYPE_IDR) || (nal_unit.nalu_type == NALU_TYPE_IDR)) ) ) {
                                    //ALOGV("Found a New Frame due to NALU_TYPE_IDR/NALU_TYPE_NON_IDR");
                                    isNewFrame = OMX_TRUE;
                                } else {
                                    isNewFrame = OMX_FALSE;
                                }
                            }
                            m_au_data = true;
                            m_forceToStichNextNAL = false;
                            break;
                        }
            case NALU_TYPE_SPS:
            case NALU_TYPE_PPS:
            case NALU_TYPE_SEI: {
                            ALOGV("Non-AU boundary with NAL type %d", nal_unit.nalu_type);
                            if (m_au_data) {
                                isNewFrame = OMX_TRUE;
                                m_au_data = false;
                            } else {
                                isNewFrame =  OMX_FALSE;
                            }

                            m_forceToStichNextNAL = true;
                            break;
                        }
            case NALU_TYPE_ACCESS_DELIM:
            case NALU_TYPE_UNSPECIFIED:
            case NALU_TYPE_EOSEQ:
            case NALU_TYPE_EOSTREAM:
            default: {
                     isNewFrame =  OMX_FALSE;
                     // Do not update m_forceToStichNextNAL
                     break;
                 }
        } // end of switch
    } // end of if
    m_prv_nalu = nal_unit;
    ALOGV("get_h264_nal_type - newFrame value %d",isNewFrame);
    return eRet;
}

void perf_metrics::start()
{
    if (!active) {
        start_time = get_act_time();
        active = true;
    }
}

void perf_metrics::stop()
{
    OMX_U64 stop_time = get_act_time();
    if (active) {
        proc_time += (stop_time - start_time);
        active = false;
    }
}

void perf_metrics::end(OMX_U32 units_cntr)
{
    stop();
    ALOGV("--> Processing time : [%.2f] Sec", (float)proc_time / 1e6);
    if (units_cntr) {
        ALOGV("--> Avrg proc time  : [%.2f] mSec", proc_time / (float)(units_cntr * 1e3));
    }
}

void perf_metrics::reset()
{
    start_time = 0;
    proc_time = 0;
    active = false;
}

OMX_U64 perf_metrics::get_act_time()
{
    struct timeval act_time = {0, 0};
    gettimeofday(&act_time, NULL);
    return (act_time.tv_usec + act_time.tv_sec * 1e6);
}

OMX_U64 perf_metrics::processing_time_us()
{
    return proc_time;
}

h264_stream_parser::h264_stream_parser()
{
    reset();
#ifdef PANSCAN_HDLR
    panscan_hdl = new panscan_handler();
    if (!panscan_hdl) {
        ALOGE("ERROR: Panscan hdl was not allocated!");
    } else if (!panscan_hdl->initialize(10)) {
        ALOGE("ERROR: Allocating memory for panscan!");
        delete panscan_hdl;
        panscan_hdl = NULL;
    }
#else
    memset(&panscan_param, 0, sizeof(panscan_param));
    panscan_param.rect_id = NO_PAN_SCAN_BIT;
#endif
}

h264_stream_parser::~h264_stream_parser()
{
#ifdef PANSCAN_HDLR
    if (panscan_hdl) {
        delete panscan_hdl;
        panscan_hdl = NULL;
    }
#endif
}

void h264_stream_parser::reset()
{
    curr_32_bit = 0;
    bits_read = 0;
    zero_cntr = 0;
    emulation_code_skip_cntr = 0;
    emulation_sc_enabled = true;
    bitstream = NULL;
    bitstream_bytes = 0;
    memset(&vui_param, 0, sizeof(vui_param));
    vui_param.fixed_fps_prev_ts = LLONG_MAX;
    memset(&sei_buf_period, 0, sizeof(sei_buf_period));
    memset(&sei_pic_timing, 0, sizeof(sei_pic_timing));
    memset(&frame_packing_arrangement,0,sizeof(frame_packing_arrangement));
    frame_packing_arrangement.cancel_flag = 1;
    mbaff_flag = 0;
}

void h264_stream_parser::init_bitstream(OMX_U8* data, OMX_U32 size)
{
    bitstream = data;
    bitstream_bytes = size;
    curr_32_bit = 0;
    bits_read = 0;
    zero_cntr = 0;
    emulation_code_skip_cntr = 0;
}

void h264_stream_parser::parse_vui(bool vui_in_extradata)
{
    OMX_U32 value = 0;
    ALOGV("parse_vui: IN");
    if (vui_in_extradata)
        while (!extract_bits(1) && more_bits()); // Discard VUI enable flag
    if (!more_bits())
        return;

    vui_param.aspect_ratio_info_present_flag = extract_bits(1); //aspect_ratio_info_present_flag
    if (vui_param.aspect_ratio_info_present_flag) {
        ALOGV("Aspect Ratio Info present!");
        aspect_ratio_info();
    }

    if (extract_bits(1)) //overscan_info_present_flag
        extract_bits(1); //overscan_appropriate_flag
    if (extract_bits(1)) { //video_signal_type_present_flag
        extract_bits(3); //video_format
        extract_bits(1); //video_full_range_flag
        if (extract_bits(1)) { //colour_description_present_flag
            extract_bits(8); //colour_primaries
            extract_bits(8); //transfer_characteristics
            extract_bits(8); //matrix_coefficients
        }
    }
    if (extract_bits(1)) { //chroma_location_info_present_flag
        uev(); //chroma_sample_loc_type_top_field
        uev(); //chroma_sample_loc_type_bottom_field
    }
    vui_param.timing_info_present_flag = extract_bits(1);
    if (vui_param.timing_info_present_flag) {
        vui_param.num_units_in_tick = extract_bits(32);
        vui_param.time_scale = extract_bits(32);
        vui_param.fixed_frame_rate_flag = extract_bits(1);
        ALOGV("Timing info present in VUI!");
        ALOGV("  num units in tick  : %u", vui_param.num_units_in_tick);
        ALOGV("  time scale         : %u", vui_param.time_scale);
        ALOGV("  fixed frame rate   : %u", vui_param.fixed_frame_rate_flag);
    }
    vui_param.nal_hrd_parameters_present_flag = extract_bits(1);
    if (vui_param.nal_hrd_parameters_present_flag) {
        ALOGV("nal hrd params present!");
        hrd_parameters(&vui_param.nal_hrd_parameters);
    }
    vui_param.vcl_hrd_parameters_present_flag = extract_bits(1);
    if (vui_param.vcl_hrd_parameters_present_flag) {
        ALOGV("vcl hrd params present!");
        hrd_parameters(&vui_param.vcl_hrd_parameters);
    }
    if (vui_param.nal_hrd_parameters_present_flag ||
            vui_param.vcl_hrd_parameters_present_flag)
        vui_param.low_delay_hrd_flag = extract_bits(1);
    vui_param.pic_struct_present_flag = extract_bits(1);
    ALOGV("pic_struct_present_flag : %u", vui_param.pic_struct_present_flag);
    if (extract_bits(1)) { //bitstream_restriction_flag
        extract_bits(1); //motion_vectors_over_pic_boundaries_flag
        uev(); //max_bytes_per_pic_denom
        uev(); //max_bits_per_mb_denom
        uev(); //log2_max_mv_length_vertical
        uev(); //log2_max_mv_length_horizontal
        uev(); //num_reorder_frames
        uev(); //max_dec_frame_buffering
    }
    ALOGV("parse_vui: OUT");
}

void h264_stream_parser::aspect_ratio_info()
{
    ALOGV("aspect_ratio_info: IN");
    OMX_U32  aspect_ratio_idc = 0;
    OMX_U32  aspect_ratio_x = 0;
    OMX_U32  aspect_ratio_y = 0;
    aspect_ratio_idc = extract_bits(8); //aspect_ratio_idc
    switch (aspect_ratio_idc) {
        case 1:
            aspect_ratio_x = 1;
            aspect_ratio_y = 1;
            break;
        case 2:
            aspect_ratio_x = 12;
            aspect_ratio_y = 11;
            break;
        case 3:
            aspect_ratio_x = 10;
            aspect_ratio_y = 11;
            break;
        case 4:
            aspect_ratio_x = 16;
            aspect_ratio_y = 11;
            break;
        case 5:
            aspect_ratio_x = 40;
            aspect_ratio_y = 33;
            break;
        case 6:
            aspect_ratio_x = 24;
            aspect_ratio_y = 11;
            break;
        case 7:
            aspect_ratio_x = 20;
            aspect_ratio_y = 11;
            break;
        case 8:
            aspect_ratio_x = 32;
            aspect_ratio_y = 11;
            break;
        case 9:
            aspect_ratio_x = 80;
            aspect_ratio_y = 33;
            break;
        case 10:
            aspect_ratio_x = 18;
            aspect_ratio_y = 11;
            break;
        case 11:
            aspect_ratio_x = 15;
            aspect_ratio_y = 11;
            break;
        case 12:
            aspect_ratio_x = 64;
            aspect_ratio_y = 33;
            break;
        case 13:
            aspect_ratio_x = 160;
            aspect_ratio_y = 99;
            break;
        case 14:
            aspect_ratio_x = 4;
            aspect_ratio_y = 3;
            break;
        case 15:
            aspect_ratio_x = 3;
            aspect_ratio_y = 2;
            break;
        case 16:
            aspect_ratio_x = 2;
            aspect_ratio_y = 1;
            break;
        case 255:
            aspect_ratio_x = extract_bits(16); //sar_width
            aspect_ratio_y = extract_bits(16); //sar_height
            break;
        default:
            ALOGV("-->aspect_ratio_idc: Reserved Value ");
            break;
    }
    ALOGV("-->aspect_ratio_idc        : %u", aspect_ratio_idc);
    ALOGV("-->aspect_ratio_x          : %u", aspect_ratio_x);
    ALOGV("-->aspect_ratio_y          : %u", aspect_ratio_y);
    vui_param.aspect_ratio_info.aspect_ratio_idc = aspect_ratio_idc;
    vui_param.aspect_ratio_info.aspect_ratio_x = aspect_ratio_x;
    vui_param.aspect_ratio_info.aspect_ratio_y = aspect_ratio_y;
    ALOGV("aspect_ratio_info: OUT");
}

void h264_stream_parser::hrd_parameters(h264_hrd_param *hrd_param)
{
    OMX_U32 idx;
    ALOGV("hrd_parameters: IN");
    hrd_param->cpb_cnt = uev() + 1;
    hrd_param->bit_rate_scale = extract_bits(4);
    hrd_param->cpb_size_scale = extract_bits(4);
    ALOGV("-->cpb_cnt        : %u", hrd_param->cpb_cnt);
    ALOGV("-->bit_rate_scale : %u", hrd_param->bit_rate_scale);
    ALOGV("-->cpb_size_scale : %u", hrd_param->cpb_size_scale);
    if (hrd_param->cpb_cnt > MAX_CPB_COUNT) {
        ALOGV("ERROR: Invalid hrd_param->cpb_cnt [%u]!", hrd_param->cpb_cnt);
        return;
    }
    for (idx = 0; idx < hrd_param->cpb_cnt && more_bits(); idx++) {
        hrd_param->bit_rate_value[idx] = uev() + 1;
        hrd_param->cpb_size_value[idx] = uev() + 1;
        hrd_param->cbr_flag[idx] = extract_bits(1);
        ALOGV("-->bit_rate_value [%d] : %u", idx, hrd_param->bit_rate_value[idx]);
        ALOGV("-->cpb_size_value [%d] : %u", idx, hrd_param->cpb_size_value[idx]);
        ALOGV("-->cbr_flag       [%d] : %u", idx, hrd_param->cbr_flag[idx]);
    }
    hrd_param->initial_cpb_removal_delay_length = extract_bits(5) + 1;
    hrd_param->cpb_removal_delay_length = extract_bits(5) + 1;
    hrd_param->dpb_output_delay_length = extract_bits(5) + 1;
    hrd_param->time_offset_length = extract_bits(5);
    ALOGV("-->initial_cpb_removal_delay_length : %u", hrd_param->initial_cpb_removal_delay_length);
    ALOGV("-->cpb_removal_delay_length         : %u", hrd_param->cpb_removal_delay_length);
    ALOGV("-->dpb_output_delay_length          : %u", hrd_param->dpb_output_delay_length);
    ALOGV("-->time_offset_length               : %u", hrd_param->time_offset_length);
    ALOGV("hrd_parameters: OUT");
}

void h264_stream_parser::parse_sei()
{
    OMX_U32 value = 0, processed_bytes = 0;
    OMX_U8 *sei_msg_start = bitstream;
    OMX_U32 sei_unit_size = bitstream_bytes;
    ALOGV("@@parse_sei: IN sei_unit_size(%u)", sei_unit_size);
    while ((processed_bytes + 2) < sei_unit_size && more_bits()) {
        init_bitstream(sei_msg_start + processed_bytes, sei_unit_size - processed_bytes);
        ALOGV("-->NALU_TYPE_SEI");
        OMX_U32 payload_type = 0, payload_size = 0, aux = 0;
        do {
            value = extract_bits(8);
            payload_type += value;
            processed_bytes++;
        } while (value == 0xFF);
        ALOGV("-->payload_type   : %u", payload_type);
        do {
            value = extract_bits(8);
            payload_size += value;
            processed_bytes++;
        } while (value == 0xFF);
        ALOGV("-->payload_size   : %u", payload_size);
        if (payload_size > 0) {
            switch (payload_type) {
                case BUFFERING_PERIOD:
                    sei_buffering_period();
                    break;
                case PIC_TIMING:
                    sei_picture_timing();
                    break;
                case PAN_SCAN_RECT:
                    sei_pan_scan();
                    break;
                case SEI_PAYLOAD_FRAME_PACKING_ARRANGEMENT:
                    parse_frame_pack();
                    break;
                default:
                    ALOGV("-->SEI payload type [%u] not implemented! size[%u]", payload_type, payload_size);
            }
        }
        processed_bytes += (payload_size + emulation_code_skip_cntr);
        ALOGV("-->SEI processed_bytes[%u]", processed_bytes);
    }
    ALOGV("@@parse_sei: OUT");
}

void h264_stream_parser::sei_buffering_period()
{
    OMX_U32 idx;
    OMX_U32 value = 0;
    h264_hrd_param *hrd_param = NULL;
    ALOGV("@@sei_buffering_period: IN");
    value = uev(); // seq_parameter_set_id
    ALOGV("-->seq_parameter_set_id : %u", value);
    if (value > 31) {
        ALOGV("ERROR: Invalid seq_parameter_set_id [%u]!", value);
        return;
    }
    sei_buf_period.is_valid = false;
    if (vui_param.nal_hrd_parameters_present_flag) {
        hrd_param = &vui_param.nal_hrd_parameters;
        if (hrd_param->cpb_cnt > MAX_CPB_COUNT) {
            ALOGV("ERROR: Invalid hrd_param->cpb_cnt [%u]!", hrd_param->cpb_cnt);
            return;
        }
        for (idx = 0; idx < hrd_param->cpb_cnt ; idx++) {
            sei_buf_period.is_valid = true;
            sei_buf_period.initial_cpb_removal_delay[idx] = extract_bits(hrd_param->initial_cpb_removal_delay_length);
            sei_buf_period.initial_cpb_removal_delay_offset[idx] = extract_bits(hrd_param->initial_cpb_removal_delay_length);
            ALOGV("-->initial_cpb_removal_delay        : %u", sei_buf_period.initial_cpb_removal_delay[idx]);
            ALOGV("-->initial_cpb_removal_delay_offset : %u", sei_buf_period.initial_cpb_removal_delay_offset[idx]);
        }
    }
    if (vui_param.vcl_hrd_parameters_present_flag) {
        hrd_param = &vui_param.vcl_hrd_parameters;
        if (hrd_param->cpb_cnt > MAX_CPB_COUNT) {
            ALOGV("ERROR: Invalid hrd_param->cpb_cnt [%u]!", hrd_param->cpb_cnt);
            return;
        }
        for (idx = 0; idx < hrd_param->cpb_cnt ; idx++) {
            sei_buf_period.is_valid = true;
            sei_buf_period.initial_cpb_removal_delay[idx] = extract_bits(hrd_param->initial_cpb_removal_delay_length);
            sei_buf_period.initial_cpb_removal_delay_offset[idx] = extract_bits(hrd_param->initial_cpb_removal_delay_length);
            ALOGV("-->initial_cpb_removal_delay        : %u", sei_buf_period.initial_cpb_removal_delay[idx]);
            ALOGV("-->initial_cpb_removal_delay_offset : %u", sei_buf_period.initial_cpb_removal_delay_offset[idx]);
        }
    }
    sei_buf_period.au_cntr = 0;
    ALOGV("@@sei_buffering_period: OUT");
}

void h264_stream_parser::sei_picture_timing()
{
    ALOGV("@@sei_picture_timing: IN");
    OMX_U32 time_offset_len = 0, cpb_removal_len = 24, dpb_output_len  = 24;
    OMX_U8 cbr_flag = 0;
    sei_pic_timing.is_valid = true;
    if (vui_param.nal_hrd_parameters_present_flag) {
        cpb_removal_len = vui_param.nal_hrd_parameters.cpb_removal_delay_length;
        dpb_output_len = vui_param.nal_hrd_parameters.dpb_output_delay_length;
        time_offset_len = vui_param.nal_hrd_parameters.time_offset_length;
        cbr_flag = vui_param.nal_hrd_parameters.cbr_flag[0];
    } else if (vui_param.vcl_hrd_parameters_present_flag) {
        cpb_removal_len = vui_param.vcl_hrd_parameters.cpb_removal_delay_length;
        dpb_output_len = vui_param.vcl_hrd_parameters.dpb_output_delay_length;
        time_offset_len = vui_param.vcl_hrd_parameters.time_offset_length;
        cbr_flag = vui_param.vcl_hrd_parameters.cbr_flag[0];
    }
    sei_pic_timing.cpb_removal_delay = extract_bits(cpb_removal_len);
    sei_pic_timing.dpb_output_delay = extract_bits(dpb_output_len);
    ALOGV("-->cpb_removal_len : %u", cpb_removal_len);
    ALOGV("-->dpb_output_len  : %u", dpb_output_len);
    ALOGV("-->cpb_removal_delay : %u", sei_pic_timing.cpb_removal_delay);
    ALOGV("-->dpb_output_delay  : %u", sei_pic_timing.dpb_output_delay);
    if (vui_param.pic_struct_present_flag) {
        sei_pic_timing.pic_struct = extract_bits(4);
        sei_pic_timing.num_clock_ts = 0;
        switch (sei_pic_timing.pic_struct) {
            case 0:
            case 1:
            case 2:
                sei_pic_timing.num_clock_ts = 1;
                break;
            case 3:
            case 4:
            case 7:
                sei_pic_timing.num_clock_ts = 2;
                break;
            case 5:
            case 6:
            case 8:
                sei_pic_timing.num_clock_ts = 3;
                break;
            default:
                ALOGE("sei_picture_timing: pic_struct invalid!");
        }
        ALOGV("-->num_clock_ts      : %u", sei_pic_timing.num_clock_ts);
        for (OMX_U32 i = 0; i < sei_pic_timing.num_clock_ts && more_bits(); i++) {
            sei_pic_timing.clock_ts_flag = extract_bits(1);
            if (sei_pic_timing.clock_ts_flag) {
                ALOGV("-->clock_timestamp present!");
                sei_pic_timing.ct_type = extract_bits(2);
                sei_pic_timing.nuit_field_based_flag = extract_bits(1);
                sei_pic_timing.counting_type = extract_bits(5);
                sei_pic_timing.full_timestamp_flag = extract_bits(1);
                sei_pic_timing.discontinuity_flag = extract_bits(1);
                sei_pic_timing.cnt_dropped_flag = extract_bits(1);
                sei_pic_timing.n_frames = extract_bits(8);
                ALOGV("-->f_timestamp_flg   : %u", sei_pic_timing.full_timestamp_flag);
                ALOGV("-->n_frames          : %u", sei_pic_timing.n_frames);
                sei_pic_timing.seconds_value = 0;
                sei_pic_timing.minutes_value = 0;
                sei_pic_timing.hours_value = 0;
                if (sei_pic_timing.full_timestamp_flag) {
                    sei_pic_timing.seconds_value = extract_bits(6);
                    sei_pic_timing.minutes_value = extract_bits(6);
                    sei_pic_timing.hours_value = extract_bits(5);
                } else if (extract_bits(1)) {
                    ALOGV("-->seconds_flag enabled!");
                    sei_pic_timing.seconds_value = extract_bits(6);
                    if (extract_bits(1)) {
                        ALOGV("-->minutes_flag enabled!");
                        sei_pic_timing.minutes_value = extract_bits(6);
                        if (extract_bits(1)) {
                            ALOGV("-->hours_flag enabled!");
                            sei_pic_timing.hours_value = extract_bits(5);
                        }
                    }
                }
                sei_pic_timing.time_offset = 0;
                if (time_offset_len > 0)
                    sei_pic_timing.time_offset = iv(time_offset_len);
                ALOGV("-->seconds_value     : %u", sei_pic_timing.seconds_value);
                ALOGV("-->minutes_value     : %u", sei_pic_timing.minutes_value);
                ALOGV("-->hours_value       : %u", sei_pic_timing.hours_value);
                ALOGV("-->time_offset       : %d", sei_pic_timing.time_offset);
            }
        }
    }
    ALOGV("@@sei_picture_timing: OUT");
}

void h264_stream_parser::sei_pan_scan()
{
#ifdef _ANDROID_
    char property_value[PROPERTY_VALUE_MAX] = {0};
    OMX_S32 enable_panscan_log = 0;
    property_get("vidc.dec.debug.panframedata", property_value, "0");
    enable_panscan_log = atoi(property_value);
#endif
#ifdef PANSCAN_HDLR
    h264_pan_scan *pan_scan_param = panscan_hdl->get_free();
#else
    h264_pan_scan *pan_scan_param = &panscan_param;
#endif

    if (!pan_scan_param) {
        ALOGE("sei_pan_scan: ERROR: Invalid pointer!");
        return;
    }

    pan_scan_param->rect_id = uev();
    if (pan_scan_param->rect_id > 0xFF) {
        ALOGE("sei_pan_scan: ERROR: Invalid rect_id[%u]!", (unsigned int)pan_scan_param->rect_id);
        pan_scan_param->rect_id = NO_PAN_SCAN_BIT;
        return;
    }

    pan_scan_param->rect_cancel_flag = extract_bits(1);

    if (pan_scan_param->rect_cancel_flag)
        pan_scan_param->rect_id = NO_PAN_SCAN_BIT;
    else {
        pan_scan_param->cnt = uev() + 1;
        if (pan_scan_param->cnt > MAX_PAN_SCAN_RECT) {
            ALOGE("sei_pan_scan: ERROR: Invalid num of rect [%u]!", (unsigned int)pan_scan_param->cnt);
            pan_scan_param->rect_id = NO_PAN_SCAN_BIT;
            return;
        }

        for (OMX_U32 i = 0; i < pan_scan_param->cnt; i++) {
            pan_scan_param->rect_left_offset[i] = sev();
            pan_scan_param->rect_right_offset[i] = sev();
            pan_scan_param->rect_top_offset[i] = sev();
            pan_scan_param->rect_bottom_offset[i] = sev();

        }
        pan_scan_param->rect_repetition_period = uev();
#ifdef PANSCAN_HDLR
        if (pan_scan_param->rect_repetition_period > 1)
            // Repetition period is decreased by 2 each time panscan data is used
            pan_scan_param->rect_repetition_period *= 2;
#endif
#ifdef _ANDROID_
        if (enable_panscan_log) {
            print_pan_data(pan_scan_param);
        }
#endif
    }
}

void h264_stream_parser::print_pan_data(h264_pan_scan *pan_scan_param)
{
    ALOGE("@@print_pan_data: IN");

    ALOGE("-->rect_id            : %u", (unsigned int)pan_scan_param->rect_id);
    ALOGE("-->rect_cancel_flag   : %u", pan_scan_param->rect_cancel_flag);

    ALOGE("-->cnt                : %u", (unsigned int)pan_scan_param->cnt);

    for (OMX_U32 i = 0; i < pan_scan_param->cnt; i++) {
        ALOGE("-->rect_left_offset   : %d", (int)pan_scan_param->rect_left_offset[i]);
        ALOGE("-->rect_right_offset  : %d", (int)pan_scan_param->rect_right_offset[i]);
        ALOGE("-->rect_top_offset    : %d", (int)pan_scan_param->rect_top_offset[i]);
        ALOGE("-->rect_bottom_offset : %d", (int)pan_scan_param->rect_bottom_offset[i]);
    }
    ALOGE("-->repetition_period  : %u", (unsigned int)pan_scan_param->rect_repetition_period);

    ALOGE("@@print_pan_data: OUT");
}

void h264_stream_parser::parse_sps()
{
    OMX_U32 value = 0, scaling_matrix_limit;
    ALOGV("@@parse_sps: IN");
    value = extract_bits(8); //profile_idc
    profile = value;
    extract_bits(8); //constraint flags and reserved bits
    extract_bits(8); //level_idc
    uev(); //sps id
    if (value == 100 || value == 110 || value == 122 || value == 244 ||
            value ==  44 || value ==  83 || value ==  86 || value == 118) {
        if (uev() == 3) { //chroma_format_idc
            extract_bits(1); //separate_colour_plane_flag
            scaling_matrix_limit = 12;
        } else
            scaling_matrix_limit = 12;
        uev(); //bit_depth_luma_minus8
        uev(); //bit_depth_chroma_minus8
        extract_bits(1); //qpprime_y_zero_transform_bypass_flag
        if (extract_bits(1)) { //seq_scaling_matrix_present_flag
            for (unsigned int i = 0; i < scaling_matrix_limit && more_bits(); i++) {
                if (extract_bits(1)) { ////seq_scaling_list_present_flag[ i ]
                    if (i < 6)
                        scaling_list(16);
                    else
                        scaling_list(64);
                }
            }
        }
    }
    uev(); //log2_max_frame_num_minus4
    value = uev(); //pic_order_cnt_type
    if (value == 0)
        uev(); //log2_max_pic_order_cnt_lsb_minus4
    else if (value == 1) {
        extract_bits(1); //delta_pic_order_always_zero_flag
        sev(); //offset_for_non_ref_pic
        sev(); //offset_for_top_to_bottom_field
        value = uev(); // num_ref_frames_in_pic_order_cnt_cycle
        for (unsigned int i = 0; i < value; i++)
            sev(); //offset_for_ref_frame[ i ]
    }
    uev(); //max_num_ref_frames
    extract_bits(1); //gaps_in_frame_num_value_allowed_flag
    value = uev(); //pic_width_in_mbs_minus1
    value = uev(); //pic_height_in_map_units_minus1
    if (!extract_bits(1)) //frame_mbs_only_flag
        mbaff_flag = extract_bits(1); //mb_adaptive_frame_field_flag
    extract_bits(1); //direct_8x8_inference_flag
    if (extract_bits(1)) { //frame_cropping_flag
        uev(); //frame_crop_left_offset
        uev(); //frame_crop_right_offset
        uev(); //frame_crop_top_offset
        uev(); //frame_crop_bottom_offset
    }
    if (extract_bits(1)) //vui_parameters_present_flag
        parse_vui(false);
    ALOGV("@@parse_sps: OUT");
}

void h264_stream_parser::scaling_list(OMX_U32 size_of_scaling_list)
{
    OMX_S32 last_scale = 8, next_scale = 8, delta_scale;
    for (unsigned int j = 0; j < size_of_scaling_list; j++) {
        if (next_scale != 0) {
            delta_scale = sev();
            next_scale = (last_scale + delta_scale + 256) % 256;
        }
        last_scale = (next_scale == 0)? last_scale : next_scale;
    }
}

OMX_U32 h264_stream_parser::extract_bits(OMX_U32 n)
{
    OMX_U32 value = 0;
    if (n > 32) {
        ALOGE("ERROR: extract_bits limit to 32 bits!");
        return value;
    }
    value = curr_32_bit >> (32 - n);
    if (bits_read < n) {
        n -= bits_read;
        read_word();
        value |= (curr_32_bit >> (32 - n));
        if (bits_read < n) {
            ALOGV("ERROR: extract_bits underflow!");
            value >>= (n - bits_read);
            n = bits_read;
        }
    }
    bits_read -= n;
    curr_32_bit <<= n;
    return value;
}

void h264_stream_parser::read_word()
{
    curr_32_bit = 0;
    bits_read = 0;
    while (bitstream_bytes && bits_read < 32) {
        if (*bitstream == EMULATION_PREVENTION_THREE_BYTE &&
                zero_cntr >= 2 && emulation_sc_enabled) {
            ALOGV("EMULATION_PREVENTION_THREE_BYTE: Skip 0x03 byte aligned!");
            emulation_code_skip_cntr++;
        } else {
            curr_32_bit <<= 8;
            curr_32_bit |= *bitstream;
            bits_read += 8;
        }
        if (*bitstream == 0)
            zero_cntr++;
        else
            zero_cntr = 0;
        bitstream++;
        bitstream_bytes--;
    }
    curr_32_bit <<= (32 - bits_read);
}

OMX_U32 h264_stream_parser::uev()
{
    OMX_U32 lead_zero_bits = 0, code_num = 0;
    while (!extract_bits(1) && more_bits())
        lead_zero_bits++;
    code_num = lead_zero_bits == 0 ? 0 :
        (1 << lead_zero_bits) - 1 + extract_bits(lead_zero_bits);
    return code_num;
}

bool h264_stream_parser::more_bits()
{
    return (bitstream_bytes > 0 || bits_read > 0);
}

OMX_S32 h264_stream_parser::sev()
{
    OMX_U32 code_num = uev();
    OMX_S32 ret;
    ret = (code_num + 1) >> 1;
    return ((code_num & 1) ? ret : -ret);
}

OMX_S32 h264_stream_parser::iv(OMX_U32 n_bits)
{
    OMX_U32 code_num = extract_bits(n_bits);
    OMX_S32 ret = (code_num >> (n_bits - 1))? (-1)*(~(code_num & ~(0x1 << (n_bits - 1))) + 1) : code_num;
    return ret;
}

OMX_U32 h264_stream_parser::get_nal_unit_type(OMX_U32 *nal_unit_type)
{
    OMX_U32 value = 0, consumed_bytes = 3;
    *nal_unit_type = NALU_TYPE_UNSPECIFIED;
    ALOGV("-->get_nal_unit_type: IN");
    value = extract_bits(24);
    while (value != 0x00000001 && more_bits()) {
        value <<= 8;
        value |= extract_bits(8);
        consumed_bytes++;
    }
    if (value != 0x00000001) {
        ALOGE("ERROR in get_nal_unit_type: Start code not found!");
    } else {
        if (extract_bits(1)) { // forbidden_zero_bit
            ALOGE("WARNING: forbidden_zero_bit should be zero!");
        }
        value = extract_bits(2);
        ALOGV("-->nal_ref_idc    : %x", value);
        *nal_unit_type = extract_bits(5);
        ALOGV("-->nal_unit_type  : %x", *nal_unit_type);
        consumed_bytes++;
        if (consumed_bytes > 5) {
            ALOGE("-->WARNING: Startcode was found after the first 4 bytes!");
        }
    }
    ALOGV("-->get_nal_unit_type: OUT");
    return consumed_bytes;
}

OMX_U32 h264_stream_parser::get_profile()
{
    return profile;
}

OMX_S64 h264_stream_parser::calculate_buf_period_ts(OMX_S64 timestamp)
{
    OMX_S64 clock_ts = timestamp;
    ALOGV("calculate_ts(): IN");
    if (sei_buf_period.au_cntr == 0)
        clock_ts = sei_buf_period.reference_ts = timestamp;
    else if (sei_pic_timing.is_valid && VALID_TS(sei_buf_period.reference_ts)) {
        clock_ts = sei_buf_period.reference_ts + sei_pic_timing.cpb_removal_delay *
            1e6 * vui_param.num_units_in_tick / vui_param.time_scale;
    }
    sei_buf_period.au_cntr++;
    ALOGV("calculate_ts(): OUT");
    return clock_ts;
}

OMX_S64 h264_stream_parser::calculate_fixed_fps_ts(OMX_S64 timestamp, OMX_U32 DeltaTfiDivisor)
{
    if (VALID_TS(timestamp))
        vui_param.fixed_fps_prev_ts = timestamp;
    else if (VALID_TS(vui_param.fixed_fps_prev_ts))
        vui_param.fixed_fps_prev_ts += DeltaTfiDivisor * 1e6 *
            vui_param.num_units_in_tick / vui_param.time_scale;
    return vui_param.fixed_fps_prev_ts;
}

void h264_stream_parser::parse_frame_pack()
{
#ifdef _ANDROID_
    char property_value[PROPERTY_VALUE_MAX] = {0};
    OMX_S32 enable_framepack_log = 0;

    property_get("vidc.dec.debug.panframedata", property_value, "0");
    enable_framepack_log = atoi(property_value);
#endif
    ALOGV("%s:%d parse_frame_pack", __func__, __LINE__);

    frame_packing_arrangement.id = uev();

    frame_packing_arrangement.cancel_flag = extract_bits(1);
    if (!frame_packing_arrangement.cancel_flag) {
        frame_packing_arrangement.type = extract_bits(7);
        frame_packing_arrangement.quincunx_sampling_flag = extract_bits(1);
        frame_packing_arrangement.content_interpretation_type = extract_bits(6);
        frame_packing_arrangement.spatial_flipping_flag = extract_bits(1);
        frame_packing_arrangement.frame0_flipped_flag = extract_bits(1);
        frame_packing_arrangement.field_views_flag = extract_bits(1);
        frame_packing_arrangement.current_frame_is_frame0_flag = extract_bits(1);
        frame_packing_arrangement.frame0_self_contained_flag = extract_bits(1);
        frame_packing_arrangement.frame1_self_contained_flag = extract_bits(1);

        if (!frame_packing_arrangement.quincunx_sampling_flag &&
                frame_packing_arrangement.type != 5) {
            frame_packing_arrangement.frame0_grid_position_x = extract_bits(4);
            frame_packing_arrangement.frame0_grid_position_y = extract_bits(4);
            frame_packing_arrangement.frame1_grid_position_x = extract_bits(4);
            frame_packing_arrangement.frame1_grid_position_y = extract_bits(4);
        }
        frame_packing_arrangement.reserved_byte = extract_bits(8);
        frame_packing_arrangement.repetition_period = uev();
    }
    frame_packing_arrangement.extension_flag = extract_bits(1);

#ifdef _ANDROID_
    if (enable_framepack_log) {
        print_frame_pack();
    }
#endif
}

void h264_stream_parser::print_frame_pack()
{
    ALOGV("## frame_packing_arrangement.id = %u", frame_packing_arrangement.id);
    ALOGV("## frame_packing_arrangement.cancel_flag = %u",
            frame_packing_arrangement.cancel_flag);
    if (!frame_packing_arrangement.cancel_flag) {
        ALOGV("## frame_packing_arrangement.type = %u",
                frame_packing_arrangement.type);
        ALOGV("## frame_packing_arrangement.quincunx_sampling_flag = %u",
                frame_packing_arrangement.quincunx_sampling_flag);
        ALOGV("## frame_packing_arrangement.content_interpretation_type = %u",
                frame_packing_arrangement.content_interpretation_type);
        ALOGV("## frame_packing_arrangement.spatial_flipping_flag = %u",
                frame_packing_arrangement.spatial_flipping_flag);
        ALOGV("## frame_packing_arrangement.frame0_flipped_flag = %u",
                frame_packing_arrangement.frame0_flipped_flag);
        ALOGV("## frame_packing_arrangement.field_views_flag = %u",
                frame_packing_arrangement.field_views_flag);
        ALOGV("## frame_packing_arrangement.current_frame_is_frame0_flag = %u",
                frame_packing_arrangement.current_frame_is_frame0_flag);
        ALOGV("## frame_packing_arrangement.frame0_self_contained_flag = %u",
                frame_packing_arrangement.frame0_self_contained_flag);
        ALOGV("## frame_packing_arrangement.frame1_self_contained_flag = %u",
                frame_packing_arrangement.frame1_self_contained_flag);
        ALOGV("## frame_packing_arrangement.reserved_byte = %u",
                frame_packing_arrangement.reserved_byte);
        ALOGV("## frame_packing_arrangement.repetition_period = %u",
                frame_packing_arrangement.repetition_period);
        ALOGV("## frame_packing_arrangement.extension_flag = %u",
                frame_packing_arrangement.extension_flag);
    }
}
/* API'S EXPOSED TO OMX COMPONENT */

void h264_stream_parser::get_frame_pack_data(
        OMX_QCOM_FRAME_PACK_ARRANGEMENT *frame_pack)
{
    ALOGV("%s:%d get frame data", __func__, __LINE__);
    memcpy(&frame_pack->id,&frame_packing_arrangement.id,
            FRAME_PACK_SIZE*sizeof(OMX_U32));
    return;
}


bool h264_stream_parser::is_mbaff()
{
    ALOGV("%s:%d MBAFF flag=%d", __func__, __LINE__,mbaff_flag);
    return mbaff_flag;
}

void h264_stream_parser::get_frame_rate(OMX_U32 *frame_rate)
{
    if (vui_param.num_units_in_tick != 0)
        *frame_rate = vui_param.time_scale / (2 * vui_param.num_units_in_tick);
}

void h264_stream_parser::parse_nal(OMX_U8* data_ptr, OMX_U32 data_len, OMX_U32 nal_type, bool enable_emu_sc)
{
    OMX_U32 nal_unit_type = NALU_TYPE_UNSPECIFIED, cons_bytes = 0;
    ALOGV("parse_nal(): IN nal_type(%u)", nal_type);
    if (!data_len)
        return;
    init_bitstream(data_ptr, data_len);
    emulation_sc_enabled = enable_emu_sc;
    if (nal_type != NALU_TYPE_VUI) {
        cons_bytes = get_nal_unit_type(&nal_unit_type);
        if (nal_type != nal_unit_type && nal_type != NALU_TYPE_UNSPECIFIED) {
            ALOGV("Unexpected nal_type(%x) expected(%x)", nal_unit_type, nal_type);
            return;
        }
    }
    switch (nal_type) {
        case NALU_TYPE_SPS:
            if (more_bits())
                parse_sps();
#ifdef PANSCAN_HDLR
            panscan_hdl->get_free();
#endif
            break;
        case NALU_TYPE_SEI:
            init_bitstream(data_ptr + cons_bytes, data_len - cons_bytes);
            parse_sei();
            break;
        case NALU_TYPE_VUI:
            parse_vui(true);
            break;
        default:
            ALOGV("nal_unit_type received : %u", nal_type);
    }
    ALOGV("parse_nal(): OUT");
}

#ifdef PANSCAN_HDLR
void h264_stream_parser::update_panscan_data(OMX_S64 timestamp)
{
    panscan_hdl->update_last(timestamp);
}
#endif

void h264_stream_parser::fill_aspect_ratio_info(OMX_QCOM_ASPECT_RATIO *dest_aspect_ratio)
{
    if (dest_aspect_ratio && vui_param.aspect_ratio_info_present_flag) {
        dest_aspect_ratio->aspectRatioX = vui_param.aspect_ratio_info.aspect_ratio_x;
        dest_aspect_ratio->aspectRatioY = vui_param.aspect_ratio_info.aspect_ratio_y;
    }
}

void h264_stream_parser::fill_pan_scan_data(OMX_QCOM_PANSCAN *dest_pan_scan, OMX_S64 timestamp)
{
#ifdef PANSCAN_HDLR
    h264_pan_scan *pan_scan_param = panscan_hdl->get_populated(timestamp);
#else
    h264_pan_scan *pan_scan_param = &panscan_param;
#endif
    if (pan_scan_param) {
        if (!(pan_scan_param->rect_id & NO_PAN_SCAN_BIT)) {
            PRINT_PANSCAN_PARAM(*pan_scan_param);
            dest_pan_scan->numWindows = pan_scan_param->cnt;
            for (unsigned int i = 0; i < dest_pan_scan->numWindows; i++) {
                dest_pan_scan->window[i].x = pan_scan_param->rect_left_offset[i];
                dest_pan_scan->window[i].y = pan_scan_param->rect_top_offset[i];
                dest_pan_scan->window[i].dx = pan_scan_param->rect_right_offset[i];
                dest_pan_scan->window[i].dy = pan_scan_param->rect_bottom_offset[i];
            }
#ifndef PANSCAN_HDLR
            if (pan_scan_param->rect_repetition_period == 0)
                pan_scan_param->rect_id = NO_PAN_SCAN_BIT;
            else if (pan_scan_param->rect_repetition_period > 1)
                pan_scan_param->rect_repetition_period =
                    (pan_scan_param->rect_repetition_period == 2)? 0 :
                    (pan_scan_param->rect_repetition_period - 1);
#endif
        } else
            pan_scan_param->rect_repetition_period = 0;
    }
}

OMX_S64 h264_stream_parser::process_ts_with_sei_vui(OMX_S64 timestamp)
{
    bool clock_ts_flag = false;
    OMX_S64 clock_ts = timestamp;
    OMX_U32 deltaTfiDivisor = 2;
    if (vui_param.timing_info_present_flag) {
        if (vui_param.pic_struct_present_flag) {
            if (sei_pic_timing.clock_ts_flag) {
                clock_ts = ((sei_pic_timing.hours_value * 60 + sei_pic_timing.minutes_value) * 60 + sei_pic_timing.seconds_value) * 1e6 +
                    (sei_pic_timing.n_frames * (vui_param.num_units_in_tick * (1 + sei_pic_timing.nuit_field_based_flag)) + sei_pic_timing.time_offset) *
                    1e6 / vui_param.time_scale;
                ALOGV("-->CLOCK TIMESTAMP   : %lld", clock_ts);
                clock_ts_flag = true;
            }
            if (vui_param.fixed_frame_rate_flag) {
                switch (sei_pic_timing.pic_struct) {
                    case 1:
                    case 2:
                        deltaTfiDivisor = 1;
                        break;
                    case 0:
                    case 3:
                    case 4:
                        deltaTfiDivisor = 2;
                        break;
                    case 5:
                    case 6:
                        deltaTfiDivisor = 3;
                        break;
                    case 7:
                        deltaTfiDivisor = 4;
                        break;
                    case 8:
                        deltaTfiDivisor = 6;
                        break;
                    default:
                        ALOGE("process_ts_with_sei_vui: pic_struct invalid!");
                }
            }
        }
        if (!clock_ts_flag) {
            if (vui_param.fixed_frame_rate_flag)
                clock_ts = calculate_fixed_fps_ts(timestamp, deltaTfiDivisor);
            else if (sei_buf_period.is_valid)
                clock_ts = calculate_buf_period_ts(timestamp);
        }
    } else {
        ALOGV("NO TIMING information present in VUI!");
    }
    sei_pic_timing.is_valid = false; // SEI data is valid only for current frame
    return clock_ts;
}

#ifdef PANSCAN_HDLR

panscan_handler::panscan_handler() : panscan_data(NULL) {}

panscan_handler::~panscan_handler()
{
    if (panscan_data) {
        free(panscan_data);
        panscan_data = NULL;
    }
}

bool panscan_handler::initialize(int num_data)
{
    bool ret = false;
    if (!panscan_data) {
        panscan_data = (PANSCAN_NODE *) malloc (sizeof(PANSCAN_NODE) * num_data);
        if (panscan_data) {
            panscan_free.add_multiple(panscan_data, num_data);
            ret = true;
        }
    } else {
        ALOGE("ERROR: Old panscan memory must be freed to allocate new");
    }
    return ret;
}

h264_pan_scan *panscan_handler::get_free()
{
    h264_pan_scan *data = NULL;
    PANSCAN_NODE *panscan_node = panscan_used.watch_last();
    panscan_node = (!panscan_node || VALID_TS(panscan_node->start_ts))?
        panscan_free.remove_first() :
        panscan_used.remove_last();
    if (panscan_node) {
        panscan_node->start_ts = LLONG_MAX;
        panscan_node->end_ts = LLONG_MAX;
        panscan_node->pan_scan_param.rect_id = NO_PAN_SCAN_BIT;
        panscan_node->active = false;
        panscan_used.add_last(panscan_node);
        data = &panscan_node->pan_scan_param;
    }
    return data;
}

h264_pan_scan *panscan_handler::get_populated(OMX_S64 frame_ts)
{
    h264_pan_scan *data = NULL;
    PANSCAN_NODE *panscan_node = panscan_used.watch_first();
    while (panscan_node && !data) {
        if (VALID_TS(panscan_node->start_ts)) {
            if (panscan_node->active && frame_ts < panscan_node->start_ts)
                panscan_node->start_ts = frame_ts;
            if (frame_ts >= panscan_node->start_ts)
                if (frame_ts < panscan_node->end_ts) {
                    data = &panscan_node->pan_scan_param;
                    panscan_node->active = true;
                } else {
                    panscan_free.add_last(panscan_used.remove_first());
                    panscan_node = panscan_used.watch_first();
                }
                else
                    // Finish search if current timestamp has not reached
                    // start timestamp of first panscan data.
                    panscan_node = NULL;
        } else {
            // Only one panscan data is stored for clips
            // with invalid timestamps in every frame
            data = &panscan_node->pan_scan_param;
            panscan_node->active = true;
        }
    }
    if (data) {
        if (data->rect_repetition_period == 0)
            panscan_free.add_last(panscan_used.remove_first());
        else if (data->rect_repetition_period > 1)
            data->rect_repetition_period -= 2;
    }
    PRINT_PANSCAN_DATA(panscan_node);
    return data;
}

void panscan_handler::update_last(OMX_S64 frame_ts)
{
    PANSCAN_NODE *panscan_node = panscan_used.watch_last();
    if (panscan_node && !VALID_TS(panscan_node->start_ts)) {
        panscan_node->start_ts = frame_ts;
        PRINT_PANSCAN_DATA(panscan_node);
        if (panscan_node->prev) {
            if (frame_ts < panscan_node->prev->end_ts)
                panscan_node->prev->end_ts = frame_ts;
            else if (!VALID_TS(frame_ts))
                panscan_node->prev->pan_scan_param.rect_repetition_period = 0;
            PRINT_PANSCAN_DATA(panscan_node->prev);
        }
    }
}

    template <class NODE_STRUCT>
void omx_dl_list<NODE_STRUCT>::add_multiple(NODE_STRUCT *data_arr, int data_num)
{
    for (int idx = 0; idx < data_num; idx++)
        add_last(&data_arr[idx]);
}

    template <class NODE_STRUCT>
NODE_STRUCT *omx_dl_list<NODE_STRUCT>::remove_first()
{
    NODE_STRUCT *data = head;
    if (head) {
        if (head->next) {
            head = head->next;
            head->prev = NULL;
        } else
            head = tail = NULL;
        data->next = data->prev = NULL;
    }
    return data;
}

    template <class NODE_STRUCT>
NODE_STRUCT *omx_dl_list<NODE_STRUCT>::remove_last()
{
    NODE_STRUCT *data = tail;
    if (tail) {
        if (tail->prev) {
            tail = tail->prev;
            tail->next = NULL;
        } else
            head = tail = NULL;
        data->next = data->prev = NULL;
    }
    return data;
}

    template <class NODE_STRUCT>
void omx_dl_list<NODE_STRUCT>::add_last(NODE_STRUCT* data_ptr)
{
    if (data_ptr) {
        data_ptr->next = NULL;
        data_ptr->prev = tail;
        if (tail) {
            tail->next = data_ptr;
            tail = data_ptr;
        } else
            head = tail = data_ptr;
    }
}

    template <class NODE_STRUCT>
NODE_STRUCT* omx_dl_list<NODE_STRUCT>::watch_first()
{
    return head;
}

    template <class NODE_STRUCT>
NODE_STRUCT* omx_dl_list<NODE_STRUCT>::watch_last()
{
    return tail;
}

#endif