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