| /*-------------------------------------------------------------------------- |
| Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora 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 "omx_vdec.h" |
| #include <string.h> |
| #include <stdlib.h> |
| |
| /* ======================================================================= |
| |
| DEFINITIONS AND DECLARATIONS FOR MODULE |
| |
| This section contains definitions for constants, macros, types, variables |
| and other items needed by this module. |
| |
| ========================================================================== */ |
| |
| #define SIZE_NAL_FIELD_MAX 4 |
| #define BASELINE_PROFILE 66 |
| #define MAIN_PROFILE 77 |
| #define HIGH_PROFILE 100 |
| |
| #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; |
| DEBUG_PRINT_LOW("H264Parser-->NEED TO THROW THE EXCEPTION...\n"); |
| } |
| 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; |
| |
| DEBUG_PRINT_LOW("extract_rbsp\n"); |
| |
| if(start_code) { |
| // Search start_code_prefix_one_3bytes (0x000001) |
| coef2 = buffer[pos++]; |
| coef3 = buffer[pos++]; |
| do { |
| if(pos >= buffer_length) |
| { |
| DEBUG_PRINT_ERROR("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) |
| { |
| DEBUG_PRINT_ERROR("ERROR: In %s() - line %d", __func__, __LINE__); |
| return false; |
| } |
| } |
| |
| if (nal_len > buffer_length) |
| { |
| DEBUG_PRINT_ERROR("ERROR: In %s() - line %d", __func__, __LINE__); |
| return false; |
| } |
| if(pos + 1 > (nal_len + sizeofNalLengthField)) |
| { |
| DEBUG_PRINT_ERROR("ERROR: In %s() - line %d", __func__, __LINE__); |
| return false; |
| } |
| if (nal_unit->forbidden_zero_bit = (buffer[pos] & 0x80)) |
| { |
| DEBUG_PRINT_ERROR("ERROR: In %s() - line %d", __func__, __LINE__); |
| } |
| nal_unit->nal_ref_idc = (buffer[pos] & 0x60) >> 5; |
| nal_unit->nalu_type = buffer[pos++] & 0x1f; |
| DEBUG_PRINT_LOW("\n@#@# 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_IN OMX_U8 *buffer, |
| OMX_IN OMX_U32 buffer_length, |
| OMX_IN OMX_U32 size_of_nal_length_field, |
| OMX_OUT OMX_BOOL &isNewFrame) |
| { |
| NALU nal_unit; |
| uint16 first_mb_in_slice = 0; |
| uint32 numBytesInRBSP = 0; |
| bool eRet = true; |
| |
| DEBUG_PRINT_LOW("get_h264_nal_type %p nal_length %d nal_length_field %d\n", |
| 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) ) |
| { |
| DEBUG_PRINT_ERROR("ERROR: In %s() - extract_rbsp() failed", __func__); |
| isNewFrame = OMX_FALSE; |
| eRet = false; |
| } |
| else |
| { |
| switch (nal_unit.nalu_type) |
| { |
| case NALU_TYPE_IDR: |
| case NALU_TYPE_NON_IDR: |
| { |
| DEBUG_PRINT_LOW("\n Found a AU Boundary %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)) ) ) |
| { |
| //DEBUG_PRINT_LOW("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: |
| case NALU_TYPE_UNSPECIFIED: |
| case NALU_TYPE_EOSEQ: |
| case NALU_TYPE_EOSTREAM: |
| { |
| DEBUG_PRINT_LOW("\n Non AU boundary NAL %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: |
| default: |
| { |
| isNewFrame = OMX_FALSE; |
| // Do not update m_forceToStichNextNAL |
| break; |
| } |
| } // end of switch |
| } // end of if |
| m_prv_nalu = nal_unit; |
| DEBUG_PRINT_LOW("get_h264_nal_type - newFrame value %d\n",isNewFrame); |
| return eRet; |
| } |