blob: b4ff9ccc4b1955b492af02ffc1df1121fcd05024 [file] [log] [blame]
/*--------------------------------------------------------------------------
Copyright (c) 2009, 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 H264_Utils.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>
#ifdef _ANDROID_
#include "cutils/properties.h"
#endif
#include "qtv_msg.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;
QTV_MSG_PRIO(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"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 *) malloc(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_default_profile_chk(true), m_default_level_chk(true)
{
#ifdef _ANDROID_
char property_value[PROPERTY_VALUE_MAX] = {0};
if(0 != property_get("persist.omxvideo.profilecheck", property_value, NULL))
{
if(!strcmp(property_value, "false"))
{
m_default_profile_chk = false;
}
}
else
{
QTV_MSG_PRIO(QTVDIAG_GENERAL, QTVDIAG_PRIO_ERROR, "H264_Utils:: Constr failed in \
getting value for the Android property [persist.omxvideo.profilecheck]");
}
if(0 != property_get("persist.omxvideo.levelcheck", property_value, NULL))
{
if(!strcmp(property_value, "false"))
{
m_default_level_chk = false;
}
}
else
{
QTV_MSG_PRIO(QTVDIAG_GENERAL, QTVDIAG_PRIO_ERROR, "H264_Utils:: Constr failed in \
getting value for the Android property [persist.omxvideo.levelcheck]");
}
#endif
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;
}
/***********************************************************************/
/*
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;
QTV_MSG_PRIO(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED, "extract_rbsp\n");
if (start_code) {
// Search start_code_prefix_one_3bytes (0x000001)
coef2 = buffer[pos++];
coef3 = buffer[pos++];
do {
if (pos >= buffer_length) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_HIGH,
"Error at extract rbsp line %d",
__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) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_ERROR,
"Error at extract rbsp line %d",
__LINE__);
return false;
}
}
if (nal_len > buffer_length) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_ERROR,
"Error at extract rbsp line %d", __LINE__);
return false;
}
if (pos + 1 > (nal_len + sizeofNalLengthField)) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_ERROR,
"Error at extract rbsp line %d", __LINE__);
return false;
}
if (nal_unit->forbidden_zero_bit = (buffer[pos] & 0x80)) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_ERROR,
"Error at extract rbsp line %d", __LINE__);
}
nal_unit->nal_ref_idc = (buffer[pos] & 0x60) >> 5;
nal_unit->nalu_type = buffer[pos++] & 0x1f;
*rbsp_length = 0;
if (nal_unit->nalu_type == NALU_TYPE_EOSEQ ||
nal_unit->nalu_type == NALU_TYPE_EOSTREAM)
return eRet;
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;
break;
}
}
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,
bool & isUpdateTimestamp)
{
NALU nal_unit;
uint16 first_mb_in_slice = 0;
uint32 numBytesInRBSP = 0;
bool eRet = true;
isUpdateTimestamp = false;
QTV_MSG_PRIO3(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"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)) {
QTV_MSG_PRIO(QTVDIAG_GENERAL, QTVDIAG_PRIO_ERROR,
"get_h264_nal_type - ERROR at extract_rbsp\n");
isNewFrame = OMX_FALSE;
eRet = false;
} else {
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"Nalu type: %d",nal_unit.nalu_type);
switch (nal_unit.nalu_type) {
case NALU_TYPE_IDR:
case NALU_TYPE_NON_IDR:
{
RbspParser rbsp_parser(m_rbspBytes,
(m_rbspBytes +
numBytesInRBSP));
first_mb_in_slice = rbsp_parser.ue();
if (m_forceToStichNextNAL) {
isNewFrame = OMX_FALSE;
if(!first_mb_in_slice){
isUpdateTimestamp = true;
}
} else {
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)))) {
isNewFrame = OMX_TRUE;
} else {
isNewFrame = OMX_FALSE;
}
}
m_forceToStichNextNAL = false;
break;
}
default:
{
isNewFrame =
(m_forceToStichNextNAL ? OMX_FALSE :
OMX_TRUE);
m_forceToStichNextNAL = true;
break;
}
} // end of switch
} // end of if
m_prv_nalu = nal_unit;
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"get_h264_nal_type - newFrame value %d\n", isNewFrame);
return eRet;
}
/**************************************************************************
** This function parses an H.264 Annex B formatted bitstream, returning the
** next frame in the format required by MP4 (specified in ISO/IEC 14496-15,
** section 5.2.3, "AVC Sample Structure Definition"), and recovering any
** header (sequence and picture parameter set NALUs) information, formatting
** it as a header block suitable for writing to video format services.
**
** IN const uint8 *encodedBytes
** This points to the H.264 Annex B formatted video bitstream, starting
** with the next frame for which to locate frame boundaries.
**
** IN uint32 totalBytes
** This is the total number of bytes left in the H.264 video bitstream,
** from the given starting position.
**
** INOUT H264StreamInfo &streamInfo
** This structure contains state information about the stream as it has
** been so far parsed.
**
** OUT vector<uint8> &frame
** The properly MP4 formatted H.264 frame will be stored here.
**
** OUT uint32 &bytesConsumed
** This is set to the total number of bytes parsed from the bitstream.
**
** OUT uint32 &nalSize
** The true size of the NAL (without padding zeroes)
**
** OUT bool &keyFrame
** Indicator whether this is an I-frame
**
** IN bool stripSeiAud
** If set, any SEI or AU delimiter NALUs are stripped out.
*************************************************************************/
bool H264_Utils::parseHeader(uint8 * encodedBytes,
uint32 totalBytes,
uint32 sizeOfNALLengthField,
unsigned &height,
unsigned &width,
bool & bInterlace,
unsigned &cropx,
unsigned &cropy,
unsigned &cropdx, unsigned &cropdy)
{
bool keyFrame = FALSE;
bool stripSeiAud = FALSE;
bool nalSize = FALSE;
uint64 bytesConsumed = 0;
uint8 frame[64];
struct H264ParamNalu temp = { 0 };
// Scan NALUs until a frame boundary is detected. If this is the first
// frame, scan a second time to find the end of the frame. Otherwise, the
// first boundary found is the end of the current frame. While scanning,
// collect any sequence/parameter set NALUs for use in constructing the
// stream header.
bool inFrame = true;
bool inNalu = false;
bool vclNaluFound = false;
uint8 naluType = 0;
uint32 naluStart = 0, naluSize = 0;
uint32 prevVclFrameNum = 0, vclFrameNum = 0;
bool prevVclFieldPicFlag = false, vclFieldPicFlag = false;
bool prevVclBottomFieldFlag = false, vclBottomFieldFlag = false;
uint8 prevVclNalRefIdc = 0, vclNalRefIdc = 0;
uint32 prevVclPicOrderCntLsb = 0, vclPicOrderCntLsb = 0;
int32 prevVclDeltaPicOrderCntBottom = 0, vclDeltaPicOrderCntBottom = 0;
int32 prevVclDeltaPicOrderCnt0 = 0, vclDeltaPicOrderCnt0 = 0;
int32 prevVclDeltaPicOrderCnt1 = 0, vclDeltaPicOrderCnt1 = 0;
uint8 vclNaluType = 0;
uint32 vclPicOrderCntType = 0;
uint64 pos;
uint64 posNalDetected = 0xFFFFFFFF;
uint32 cursor = 0xFFFFFFFF;
unsigned int profile_id = 0, level_id = 0;
H264ParamNalu *seq = NULL, *pic = NULL;
// used to determin possible infinite loop condition
int loopCnt = 0;
for (pos = 0;; ++pos) {
// return early, found possible infinite loop
if (loopCnt > 100000)
return 0;
// Scan ahead next byte.
cursor <<= 8;
cursor |= static_cast < uint32 > (encodedBytes[pos]);
if (sizeOfNALLengthField != 0) {
inNalu = true;
naluStart = sizeOfNALLengthField;
}
// If in NALU, scan forward until an end of NALU condition is
// detected.
if (inNalu) {
if (sizeOfNALLengthField == 0) {
// Detect end of NALU condition.
if (((cursor & 0xFFFFFF) == 0x000000)
|| ((cursor & 0xFFFFFF) == 0x000001)
|| (pos >= totalBytes)) {
inNalu = false;
if (pos < totalBytes) {
pos -= 3;
}
naluSize =
static_cast < uint32 >
((static_cast < uint32 >
(pos) - naluStart) + 1);
QTV_MSG_PRIO3(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->1.nalusize=%x pos=%x naluStart=%x\n",
naluSize, pos, naluStart);
} else {
++loopCnt;
continue;
}
}
// Determine NALU type.
naluType = (encodedBytes[naluStart] & 0x1F);
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"H264Parser-->2.naluType=%x....\n",
naluType);
if (naluType == 5)
keyFrame = true;
// For NALUs in the frame having a slice header, parse additional
// fields.
bool isVclNalu = false;
if ((naluType == 1) || (naluType == 2)
|| (naluType == 5)) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"H264Parser-->3.naluType=%x....\n",
naluType);
// Parse additional fields.
RbspParser rbsp(&encodedBytes[naluStart + 1],
&encodedBytes[naluStart +
naluSize]);
vclNaluType = naluType;
vclNalRefIdc =
((encodedBytes[naluStart] >> 5) & 0x03);
(void)rbsp.ue();
(void)rbsp.ue();
const uint32 picSetID = rbsp.ue();
pic = this->pic.find(picSetID);
QTV_MSG_PRIO2(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"H264Parser-->4.sizeof %x %x\n",
this->pic.size(),
this->seq.size());
if (!pic) {
if (this->pic.empty()) {
// Found VCL NALU before needed picture parameter set
// -- assume that we started parsing mid-frame, and
// discard the rest of the frame we're in.
inFrame = false;
//frame.clear ();
QTV_MSG_PRIO(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->5.pic empty........\n");
} else {
QTV_MSG_PRIO(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->6.FAILURE to parse..break frm here");
break;
}
}
if (pic) {
QTV_MSG_PRIO2(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->7.sizeof %x %x\n",
this->pic.size(),
this->seq.size());
seq = this->seq.find(pic->seqSetID);
if (!seq) {
if (this->seq.empty()) {
QTV_MSG_PRIO
(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->8.seq empty........\n");
// Found VCL NALU before needed sequence parameter
// set -- assume that we started parsing
// mid-frame, and discard the rest of the frame
// we're in.
inFrame = false;
//frame.clear ();
} else {
QTV_MSG_PRIO
(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->9.FAILURE to parse...break");
break;
}
}
}
QTV_MSG_PRIO2(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"H264Parser-->10.sizeof %x %x\n",
this->pic.size(),
this->seq.size());
if (pic && seq) {
QTV_MSG_PRIO2(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->11.pic and seq[%x][%x]........\n",
pic, seq);
isVclNalu = true;
vclFrameNum =
rbsp.u(seq->log2MaxFrameNumMinus4 +
4);
if (!seq->frameMbsOnlyFlag) {
vclFieldPicFlag =
(rbsp.u(1) == 1);
if (vclFieldPicFlag) {
vclBottomFieldFlag =
(rbsp.u(1) == 1);
}
} else {
vclFieldPicFlag = false;
vclBottomFieldFlag = false;
}
if (vclNaluType == 5) {
(void)rbsp.ue();
}
vclPicOrderCntType =
seq->picOrderCntType;
if (seq->picOrderCntType == 0) {
vclPicOrderCntLsb = rbsp.u
(seq->
log2MaxPicOrderCntLsbMinus4
+ 4);
if (pic->picOrderPresentFlag
&& !vclFieldPicFlag) {
vclDeltaPicOrderCntBottom
= rbsp.se();
} else {
vclDeltaPicOrderCntBottom
= 0;
}
} else {
vclPicOrderCntLsb = 0;
vclDeltaPicOrderCntBottom = 0;
}
if ((seq->picOrderCntType == 1)
&& !seq->
deltaPicOrderAlwaysZeroFlag) {
vclDeltaPicOrderCnt0 =
rbsp.se();
if (pic->picOrderPresentFlag
&& !vclFieldPicFlag) {
vclDeltaPicOrderCnt1 =
rbsp.se();
} else {
vclDeltaPicOrderCnt1 =
0;
}
} else {
vclDeltaPicOrderCnt0 = 0;
vclDeltaPicOrderCnt1 = 0;
}
}
}
//////////////////////////////////////////////////////////////////
// Perform frame boundary detection.
//////////////////////////////////////////////////////////////////
// The end of the bitstream is always a boundary.
bool boundary = (pos >= totalBytes);
// The first of these NALU types always mark a boundary, but skip
// any that occur before the first VCL NALU in a new frame.
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"H264Parser-->12.naluType[%x].....\n",
naluType);
if ((((naluType >= 6) && (naluType <= 9))
|| ((naluType >= 13) && (naluType <= 18)))
&& (vclNaluFound || !inFrame)) {
boundary = true;
}
// If a VCL NALU is found, compare with the last VCL NALU to
// determine if they belong to different frames.
else if (vclNaluFound && isVclNalu) {
// Clause 7.4.1.2.4 -- detect first VCL NALU through
// parsing of portions of the NALU header and slice
// header.
/*lint -e{731} Boolean argument to equal/not equal
* It's ok
*/
if ((prevVclFrameNum != vclFrameNum)
|| (prevVclFieldPicFlag != vclFieldPicFlag)
|| (prevVclBottomFieldFlag !=
vclBottomFieldFlag)
|| ((prevVclNalRefIdc != vclNalRefIdc)
&& ((prevVclNalRefIdc == 0)
|| (vclNalRefIdc == 0)))
|| ((vclPicOrderCntType == 0)
&&
((prevVclPicOrderCntLsb !=
vclPicOrderCntLsb)
|| (prevVclDeltaPicOrderCntBottom !=
vclDeltaPicOrderCntBottom)))
|| ((vclPicOrderCntType == 1)
&& ((prevVclDeltaPicOrderCnt0
!= vclDeltaPicOrderCnt0)
|| (prevVclDeltaPicOrderCnt1
!= vclDeltaPicOrderCnt1)))) {
boundary = true;
}
}
// If a frame boundary is reached and we were in the frame in
// which at least one VCL NALU was found, we are done processing
// this frame. Remember to back up to NALU start code to make
// sure it is available for when the next frame is parsed.
if (boundary && inFrame && vclNaluFound) {
pos = static_cast < uint64 > (naluStart - 3);
QTV_MSG_PRIO(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"H264Parser-->13.Break \n");
break;
}
inFrame = (inFrame || boundary);
// Process sequence and parameter set NALUs specially.
if ((naluType == 7) || (naluType == 8)) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"H264Parser-->14.naluType[%x].....\n",
naluType);
QTV_MSG_PRIO2(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"H264Parser-->15.sizeof %x %x\n",
this->pic.size(),
this->seq.size());
H264ParamNaluSet & naluSet =
((naluType == 7) ? this->seq : this->pic);
// Parse parameter set ID and other stream information.
H264ParamNalu newParam;
RbspParser rbsp(&encodedBytes[naluStart + 1],
&encodedBytes[naluStart +
naluSize]);
uint32 id;
if (naluType == 7) {
unsigned int tmp;
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->16.naluType[%x].....\n",
naluType);
profile_id = rbsp.u(8);
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->33.prfoile[%d].....\n",
profile_id);
tmp = rbsp.u(8);
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->33.prfoilebytes[%x].....\n",
tmp);
level_id = rbsp.u(8);
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->33.level[%d].....\n",
level_id);
id = newParam.seqSetID = rbsp.ue();
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->33.seqID[%d].....\n",
id);
if (profile_id == 100) {
//Chroma_format_idc
tmp = rbsp.ue();
if (tmp == 3) {
//residual_colour_transform_flag
(void)rbsp.u(1);
}
//bit_depth_luma_minus8
(void)rbsp.ue();
//bit_depth_chroma_minus8
(void)rbsp.ue();
//qpprime_y_zero_transform_bypass_flag
(void)rbsp.u(1);
// seq_scaling_matrix_present_flag
tmp = rbsp.u(1);
if (tmp) {
unsigned int tmp1, t;
//seq_scaling_list_present_flag
for (t = 0; t < 6; t++) {
tmp1 =
rbsp.u(1);
if (tmp1) {
unsigned
int
last_scale
=
8,
next_scale
=
8,
delta_scale;
for (int
j =
0;
j <
16;
j++)
{
if (next_scale) {
delta_scale
=
rbsp.
se
();
next_scale
=
(last_scale
+
delta_scale
+
256)
%
256;
}
last_scale
=
next_scale
?
next_scale
:
last_scale;
}
}
}
for (t = 0; t < 2; t++) {
tmp1 =
rbsp.u(1);
if (tmp1) {
unsigned
int
last_scale
=
8,
next_scale
=
8,
delta_scale;
for (int
j =
0;
j <
64;
j++)
{
if (next_scale) {
delta_scale
=
rbsp.
se
();
next_scale
=
(last_scale
+
delta_scale
+
256)
%
256;
}
last_scale
=
next_scale
?
next_scale
:
last_scale;
}
}
}
}
}
newParam.log2MaxFrameNumMinus4 =
rbsp.ue();
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->33.log2MaxFrameNumMinu[%d].....\n",
newParam.
log2MaxFrameNumMinus4);
newParam.picOrderCntType = rbsp.ue();
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->33.picOrderCntType[%d].....\n",
newParam.picOrderCntType);
if (newParam.picOrderCntType == 0) {
newParam.
log2MaxPicOrderCntLsbMinus4
= rbsp.ue();
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->33.log2MaxPicOrderCntLsbMinus4 [%d].....\n",
newParam.
log2MaxPicOrderCntLsbMinus4);
} else if (newParam.picOrderCntType ==
1) {
newParam.
deltaPicOrderAlwaysZeroFlag
= (rbsp.u(1) == 1);
(void)rbsp.se();
(void)rbsp.se();
const uint32
numRefFramesInPicOrderCntCycle
= rbsp.ue();
for (uint32 i = 0;
i <
numRefFramesInPicOrderCntCycle;
++i) {
(void)rbsp.se();
}
}
tmp = rbsp.ue();
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->33.numrefFrames[%d].....\n",
tmp);
tmp = rbsp.u(1);
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->33.gapsflag[%x].....\n",
tmp);
newParam.picWidthInMbsMinus1 =
rbsp.ue();
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->33.picWidthInMbsMinus1[%d].....\n",
newParam.
picWidthInMbsMinus1);
newParam.picHeightInMapUnitsMinus1 =
rbsp.ue();
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->33.gapsflag[%d].....\n",
newParam.
picHeightInMapUnitsMinus1);
newParam.frameMbsOnlyFlag =
(rbsp.u(1) == 1);
if (!newParam.frameMbsOnlyFlag)
(void)rbsp.u(1);
(void)rbsp.u(1);
tmp = rbsp.u(1);
newParam.crop_left = 0;
newParam.crop_right = 0;
newParam.crop_top = 0;
newParam.crop_bot = 0;
if (tmp) {
newParam.crop_left = rbsp.ue();
newParam.crop_right = rbsp.ue();
newParam.crop_top = rbsp.ue();
newParam.crop_bot = rbsp.ue();
}
QTV_MSG_PRIO4(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser--->34 crop left %d, right %d, top %d, bot %d\n",
newParam.crop_left,
newParam.crop_right,
newParam.crop_top,
newParam.crop_bot);
} else {
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->17.naluType[%x].....\n",
naluType);
id = newParam.picSetID = rbsp.ue();
newParam.seqSetID = rbsp.ue();
(void)rbsp.u(1);
newParam.picOrderPresentFlag =
(rbsp.u(1) == 1);
}
// We currently don't support updating existing parameter
// sets.
//const H264ParamNaluSet::const_iterator it = naluSet.find (id);
H264ParamNalu *it = naluSet.find(id);
if (it) {
const uint32 tempSize = static_cast < uint32 > (it->nalu); // ???
if ((naluSize != tempSize)
|| (0 !=
memcmp(&encodedBytes[naluStart],
&it->nalu,
static_cast <
int >(naluSize)))) {
QTV_MSG_PRIO(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->18.H264 stream contains two or \
more parameter set NALUs having the \
same ID -- this requires either a \
separate parameter set ES or \
multiple sample description atoms, \
neither of which is currently \
supported!");
break;
}
}
// Otherwise, add NALU to appropriate NALU set.
else {
H264ParamNalu *newParamInSet =
naluSet.find(id);
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->19.newParamInset[%x]\n",
newParamInSet);
if (!newParamInSet) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->20.newParamInset[%x]\n",
newParamInSet);
newParamInSet = &temp;
memcpy(newParamInSet, &newParam,
sizeof(struct
H264ParamNalu));
}
QTV_MSG_PRIO4(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->21.encodebytes=%x naluStart=%x\n",
encodedBytes, naluStart,
naluSize, newParamInSet);
QTV_MSG_PRIO2(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->22.naluSize=%x newparaminset=%p\n",
naluSize, newParamInSet);
QTV_MSG_PRIO4(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->23.-->0x%x 0x%x 0x%x 0x%x\n",
(encodedBytes +
naluStart),
(encodedBytes +
naluStart + 1),
(encodedBytes +
naluStart + 2),
(encodedBytes +
naluStart + 3));
memcpy(&newParamInSet->nalu,
(encodedBytes + naluStart),
sizeof(newParamInSet->nalu));
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_MED,
"H264Parser-->24.nalu=0x%x \n",
newParamInSet->nalu);
naluSet.insert(id, newParamInSet);
}
}
// Otherwise, if we are inside the frame, convert the NALU
// and append it to the frame output, if its type is acceptable.
else if (inFrame && (naluType != 0) && (naluType < 12)
&& (!stripSeiAud || (naluType != 9)
&& (naluType != 6))) {
uint8 sizeBuffer[4];
sizeBuffer[0] =
static_cast < uint8 > (naluSize >> 24);
sizeBuffer[1] =
static_cast < uint8 >
((naluSize >> 16) & 0xFF);
sizeBuffer[2] =
static_cast < uint8 >
((naluSize >> 8) & 0xFF);
sizeBuffer[3] =
static_cast < uint8 > (naluSize & 0xFF);
/*lint -e{1025, 1703, 119, 64, 534}
* These are known lint issues
*/
//frame.insert (frame.end (), sizeBuffer,
// sizeBuffer + sizeof (sizeBuffer));
/*lint -e{1025, 1703, 119, 64, 534, 632}
* These are known lint issues
*/
//frame.insert (frame.end (), encodedBytes + naluStart,
// encodedBytes + naluStart + naluSize);
}
// If NALU was a VCL, save VCL NALU parameters
// for use in frame boundary detection.
if (isVclNalu) {
QTV_MSG_PRIO(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"H264Parser-->25.isvclnalu check passed\n");
vclNaluFound = true;
prevVclFrameNum = vclFrameNum;
prevVclFieldPicFlag = vclFieldPicFlag;
prevVclNalRefIdc = vclNalRefIdc;
prevVclBottomFieldFlag = vclBottomFieldFlag;
prevVclPicOrderCntLsb = vclPicOrderCntLsb;
prevVclDeltaPicOrderCntBottom =
vclDeltaPicOrderCntBottom;
prevVclDeltaPicOrderCnt0 = vclDeltaPicOrderCnt0;
prevVclDeltaPicOrderCnt1 = vclDeltaPicOrderCnt1;
}
}
// If not currently in a NALU, detect next NALU start code.
if ((cursor & 0xFFFFFF) == 0x000001) {
QTV_MSG_PRIO(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"H264Parser-->26..here\n");
inNalu = true;
naluStart = static_cast < uint32 > (pos + 1);
if (0xFFFFFFFF == posNalDetected)
posNalDetected = pos - 2;
} else if (pos >= totalBytes) {
QTV_MSG_PRIO2(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"H264Parser-->27.pos[%x] totalBytes[%x]\n",
pos, totalBytes);
break;
}
}
uint64 tmpPos = 0;
// find the first non-zero byte
if (pos > 0) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"H264Parser-->28.last loop[%x]\n", pos);
tmpPos = pos - 1;
while (tmpPos != 0 && encodedBytes[tmpPos] == 0)
--tmpPos;
// add 1 to get the beginning of the start code
++tmpPos;
}
QTV_MSG_PRIO3(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"H264Parser-->29.tmppos=%ld bytesConsumed=%x %x\n",
tmpPos, bytesConsumed, posNalDetected);
bytesConsumed = tmpPos;
nalSize = static_cast < uint32 > (bytesConsumed - posNalDetected);
// Fill in the height and width
QTV_MSG_PRIO2(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"H264Parser-->30.seq[%x] pic[%x]\n", this->seq.size(),
this->pic.size());
if (this->seq.size()) {
m_height =
(unsigned)(16 *
(2 -
(this->seq.begin()->frameMbsOnlyFlag)) *
(this->seq.begin()->picHeightInMapUnitsMinus1 +
1));
m_width =
(unsigned)(16 *
(this->seq.begin()->picWidthInMbsMinus1 + 1));
if ((m_height % 16) != 0) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"\n Height %d is not a multiple of 16",
m_height);
m_height = (m_height / 16 + 1) * 16;
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"\n Height adjusted to %d \n", m_height);
}
if ((m_width % 16) != 0) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"\n Width %d is not a multiple of 16",
m_width);
m_width = (m_width / 16 + 1) * 16;
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"\n Width adjusted to %d \n", m_width);
}
height = m_height;
width = m_width;
bInterlace = (!this->seq.begin()->frameMbsOnlyFlag);
cropx = this->seq.begin()->crop_left << 1;
cropy = this->seq.begin()->crop_top << 1;
cropdx =
width -
((this->seq.begin()->crop_left +
this->seq.begin()->crop_right) << 1);
cropdy =
height -
((this->seq.begin()->crop_top +
this->seq.begin()->crop_bot) << 1);
QTV_MSG_PRIO2(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"H264Parser-->31.cropdy [%x] cropdx[%x]\n",
cropdy, cropdx);
QTV_MSG_PRIO2(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"H264Parser-->31.Height [%x] Width[%x]\n", height,
width);
}
this->seq.eraseall();
this->pic.eraseall();
return validate_profile_and_level(profile_id, level_id);;
}
/* ======================================================================
FUNCTION
H264_Utils::parse_first_h264_input_buffer
DESCRIPTION
parse first h264 input buffer
PARAMETERS
OMX_IN OMX_BUFFERHEADERTYPE* buffer.
RETURN VALUE
true if success
false otherwise
========================================================================== */
OMX_U32 H264_Utils::parse_first_h264_input_buffer(OMX_IN OMX_BUFFERHEADERTYPE *
buffer,
OMX_U32
size_of_nal_length_field)
{
OMX_U32 c1, c2, c3, curr_ptr = 0;
OMX_U32 i, j, aSize[4], size = 0;
OMX_U32 header_len = 0;
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"H264 clip, NAL length field %d\n",
size_of_nal_length_field);
if (buffer == NULL) {
QTV_MSG_PRIO(QTVDIAG_GENERAL, QTVDIAG_PRIO_ERROR,
"Error - buffer is NULL\n");
}
if (size_of_nal_length_field == 0) {
/* Start code with a lot of 0x00 before 0x00 0x00 0x01
Need to move pBuffer to the first 0x00 0x00 0x00 0x01 */
c1 = 1;
c2 = buffer->pBuffer[curr_ptr++];
c3 = buffer->pBuffer[curr_ptr++];
do {
if (curr_ptr >= buffer->nFilledLen) {
QTV_MSG_PRIO(QTVDIAG_GENERAL,
QTVDIAG_PRIO_ERROR,
"ERROR: parse_first_h264_input_buffer - Couldn't find the first 2 NAL (SPS and PPS)\n");
return 0;
}
c1 = c2;
c2 = c3;
c3 = buffer->pBuffer[curr_ptr++];
} while (c1 || c2 || c3 == 0);
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"curr_ptr = %d\n", curr_ptr);
if (curr_ptr > 4) {
// There are unnecessary 0x00
QTV_MSG_PRIO(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"Remove unnecessary 0x00 at SPS\n");
memmove(buffer->pBuffer, &buffer->pBuffer[curr_ptr - 4],
buffer->nFilledLen - curr_ptr - 4);
}
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"dat clip, NAL length field %d\n",
size_of_nal_length_field);
QTV_MSG_PRIO(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"Start code SPS 0x00 00 00 01\n");
curr_ptr = 4;
/* Start code 00 00 01 */
for (OMX_U8 i = 0; i < 2; i++) {
c1 = 1;
c2 = buffer->pBuffer[curr_ptr++];
c3 = buffer->pBuffer[curr_ptr++];
do {
if (curr_ptr >= buffer->nFilledLen) {
QTV_MSG_PRIO(QTVDIAG_GENERAL,
QTVDIAG_PRIO_ERROR,
"ERROR: parse_first_h264_input_buffer - Couldn't find the first 2 NAL (SPS and PPS)\n");
break;
}
c1 = c2;
c2 = c3;
c3 = buffer->pBuffer[curr_ptr++];
} while (c1 || c2 || c3 != 1);
}
header_len = curr_ptr - 4;
} else {
/* NAL length clip */
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"NAL length clip, NAL length field %d\n",
size_of_nal_length_field);
/* SPS size */
for (i = 0; i < SIZE_NAL_FIELD_MAX - size_of_nal_length_field;
i++) {
aSize[SIZE_NAL_FIELD_MAX - 1 - i] = 0;
}
for (j = 0; i < SIZE_NAL_FIELD_MAX; i++, j++) {
aSize[SIZE_NAL_FIELD_MAX - 1 - i] = buffer->pBuffer[j];
}
size = (uint32) (*((uint32 *) (aSize)));
header_len = size + size_of_nal_length_field;
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"OMX - SPS length %d\n", header_len);
/* PPS size */
for (i = 0; i < SIZE_NAL_FIELD_MAX - size_of_nal_length_field;
i++) {
aSize[SIZE_NAL_FIELD_MAX - 1 - i] = 0;
}
for (j = header_len; i < SIZE_NAL_FIELD_MAX; i++, j++) {
aSize[SIZE_NAL_FIELD_MAX - 1 - i] = buffer->pBuffer[j];
}
size = (uint32) (*((uint32 *) (aSize)));
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"OMX - PPS size %d\n", size);
header_len += size + size_of_nal_length_field;
}
return header_len;
}
OMX_U32 H264_Utils::check_header(OMX_IN OMX_BUFFERHEADERTYPE * buffer,
OMX_U32 sizeofNAL, bool & isPartial,
OMX_U32 headerState)
{
byte coef1, coef2, coef3;
uint32 pos = 0;
uint32 nal_len = 0, nal_len2 = 0;
uint32 sizeofNalLengthField = 0;
uint32 zero_count;
OMX_U32 eRet = -1;
OMX_U8 *nal1_ptr = NULL, *nal2_ptr = NULL;
isPartial = true;
QTV_MSG_PRIO(QTVDIAG_GENERAL, QTVDIAG_PRIO_LOW,
"H264_Utils::check_header ");
if (!sizeofNAL) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_HIGH,
"check_header: start code %d",
buffer->nFilledLen);
// Search start_code_prefix_one_3bytes (0x000001)
coef2 = buffer->pBuffer[pos++];
coef3 = buffer->pBuffer[pos++];
do {
if (pos >= buffer->nFilledLen) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_ERROR,
"Error at extract rbsp line %d",
__LINE__);
return eRet;
}
coef1 = coef2;
coef2 = coef3;
coef3 = buffer->pBuffer[pos++];
} while (coef1 || coef2 || coef3 != 1);
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_HIGH,
"check_header: start code got fisrt NAL %d", pos);
nal1_ptr = (OMX_U8 *) & buffer->pBuffer[pos];
// Search start_code_prefix_one_3bytes (0x000001)
if (pos + 2 < buffer->nFilledLen) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_HIGH,
"check_header: start code looking for second NAL %d",
pos);
isPartial = false;
coef2 = buffer->pBuffer[pos++];
coef3 = buffer->pBuffer[pos++];
do {
if (pos >= buffer->nFilledLen) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_HIGH,
"Error at extract rbsp line %d",
__LINE__);
isPartial = true;
break;
}
coef1 = coef2;
coef2 = coef3;
coef3 = buffer->pBuffer[pos++];
} while (coef1 || coef2 || coef3 != 1);
}
if (!isPartial) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_ERROR,
"check_header: start code two nals in one buffer %d",
pos);
nal2_ptr = (OMX_U8 *) & buffer->pBuffer[pos];
if (((nal1_ptr[0] & 0x1f) == NALU_TYPE_SPS)
&& ((nal2_ptr[0] & 0x1f) == NALU_TYPE_PPS)) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_ERROR,
"check_header: start code two nals in one buffer SPS+PPS %d",
pos);
eRet = 0;
} else if (((nal1_ptr[0] & 0x1f) == NALU_TYPE_SPS) && (buffer->nFilledLen < 512)) {
eRet = 0;
}
} else {
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_HIGH,
"check_header: start code partial nal in one buffer %d",
pos);
if (headerState == 0
&& ((nal1_ptr[0] & 0x1f) == NALU_TYPE_SPS)) {
eRet = 0;
} else if (((nal1_ptr[0] & 0x1f) == NALU_TYPE_PPS)) {
eRet = 0;
} else
eRet = -1;
}
} else {
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_ERROR,
"check_header: size nal %d", sizeofNAL);
/* This is the case to play multiple NAL units inside each access unit */
/* Extract the NAL length depending on sizeOfNALength field */
sizeofNalLengthField = sizeofNAL;
nal_len = 0;
while (sizeofNAL--) {
nal_len |= buffer->pBuffer[pos++] << (sizeofNAL << 3);
}
if (nal_len >= buffer->nFilledLen) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_ERROR,
"Error at extract rbsp line %d",
__LINE__);
return eRet;
}
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_ERROR,
"check_header: size nal got fist NAL %d",
nal_len);
nal1_ptr = (OMX_U8 *) & buffer->pBuffer[pos];
if ((nal_len + sizeofNalLengthField) < buffer->nFilledLen) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_ERROR,
"check_header: getting second NAL %d",
buffer->nFilledLen);
isPartial = false;
pos += nal_len;
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_ERROR,
"check_header: getting second NAL position %d",
pos);
sizeofNAL = sizeofNalLengthField;
nal_len2 = 0;
while (sizeofNAL--) {
nal_len2 |=
buffer->pBuffer[pos++] << (sizeofNAL << 3);
}
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_ERROR,
"check_header: getting second NAL %d",
nal_len2);
if (nal_len + nal_len2 + 2 * sizeofNalLengthField >
buffer->nFilledLen) {
QTV_MSG_PRIO1(QTVDIAG_GENERAL,
QTVDIAG_PRIO_ERROR,
"Error at extract rbsp line %d",
__LINE__);
return eRet;
}
QTV_MSG_PRIO1(QTVDIAG_GENERAL, QTVDIAG_PRIO_ERROR,
"check_header: size nal got second NAL %d",
nal_len);
nal2_ptr = (OMX_U8 *) & buffer->pBuffer[pos];
}
if (!isPartial) {
QTV_MSG_PRIO(QTVDIAG_GENERAL, QTVDIAG_PRIO_ERROR,
"check_header: size nal partial nal ");
if (((nal1_ptr[0] & 0x1f) == NALU_TYPE_SPS)
&& ((nal2_ptr[0] & 0x1f) == NALU_TYPE_PPS)) {
eRet = 0;
}
} else {
QTV_MSG_PRIO(QTVDIAG_GENERAL, QTVDIAG_PRIO_ERROR,
"check_header: size nal full header");
if (headerState == 0
&& ((nal1_ptr[0] & 0x1f) == NALU_TYPE_SPS)) {
eRet = 0;
} else if (((nal1_ptr[0] & 0x1f) == NALU_TYPE_PPS)) {
eRet = 0;
} else
eRet = -1;
}
}
return eRet;
}
/*===========================================================================
FUNCTION:
validate_profile_and_level
DESCRIPTION:
This function validate the profile and level that is supported.
INPUT/OUTPUT PARAMETERS:
uint32 profile
uint32 level
RETURN VALUE:
false it it's not supported
true otherwise
SIDE EFFECTS:
None.
===========================================================================*/
bool H264_Utils::validate_profile_and_level(uint32 profile, uint32 level)
{
QTV_MSG_PRIO2(QTVDIAG_GENERAL, QTVDIAG_PRIO_MED,
"H264 profile %d, level %d\n", profile, level);
if ((m_default_profile_chk &&
profile != BASELINE_PROFILE &&
profile != MAIN_PROFILE &&
profile != HIGH_PROFILE) || (m_default_level_chk && level > MAX_SUPPORTED_LEVEL)
) {
return false;
}
return true;
}