webrtc/modules/rtp_rtcp/source/H264/h264_information.cc

819 lines
28 KiB
C++

/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <string.h>
#include "h264_information.h"
//#define DEBUG_SEI_MESSAGE 1
#ifdef DEBUG_SEI_MESSAGE
#include "bitstream_parser.h"
#include <stdio.h>
#include <math.h>
WebRtc_UWord32 BitRateBPS(WebRtc_UWord16 x )
{
return (x & 0x3fff) * WebRtc_UWord32(pow(10.0f,(2 + (x >> 14))));
}
#endif
namespace webrtc {
H264Information::H264Information(const bool SVC)
: _SVC(SVC)
{
}
H264Information::~H264Information()
{
}
void
H264Information::Reset()
{
_parsedLength = 0;
_remLength = 0;
_length = 0;
_info.numNALUs = 0;
_info.numLayers = 0;
memset(_info.startCodeSize, 0, sizeof(_info.startCodeSize));
memset(_info.payloadSize, 0, sizeof(_info.payloadSize));
memset(_info.NRI, 0, sizeof(_info.NRI));
memset(_info.type, 0, sizeof(_info.type));
memset(_info.accLayerSize, 0, sizeof(_info.accLayerSize));
for (WebRtc_Word32 i = 0; i < KMaxNumberOfNALUs; i++)
{
_info.SVCheader[i].idr = 0;
_info.SVCheader[i].priorityID = 0;
_info.SVCheader[i].interLayerPred = 0;
_info.SVCheader[i].dependencyID = 0;
_info.SVCheader[i].qualityID = 0;
_info.SVCheader[i].temporalID = 0;
_info.SVCheader[i].useRefBasePic = 0;
_info.SVCheader[i].discardable = 0;
_info.SVCheader[i].output = 0;
_info.PACSI[i].X = 0;
_info.PACSI[i].Y = 0;
// _info.PACSI[i].T = 0;
_info.PACSI[i].A = 0;
_info.PACSI[i].P = 0;
_info.PACSI[i].C = 0;
_info.PACSI[i].S = 0;
_info.PACSI[i].E = 0;
_info.PACSI[i].TL0picIDx = 0;
_info.PACSI[i].IDRpicID = 0;
_info.PACSI[i].DONC = 0;
_info.PACSI[i].numSEINALUs = 0;
_info.PACSI[i].NALlength = 5;
}
}
/*******************************************************************************
* WebRtc_Word32 GetInfo(const WebRtc_UWord8* ptrEncodedBuffer,
* const WebRtc_UWord32 length,
* const H264Info*& ptrInfo);
*
* Gets information from an encoded stream.
*
* Input:
* - ptrEncodedBuffer : Pointer to encoded stream.
* - length : Length in bytes of encoded stream.
*
* Output:
* - ptrInfo : Pointer to struct with H.264 info.
*
* Return value:
* - 0 : ok
* - (-1) : Error
*/
WebRtc_Word32
H264Information::GetInfo(const WebRtc_UWord8* ptrEncodedBuffer,
const WebRtc_UWord32 length,
const H264Info*& ptrInfo)
{
if (!ptrEncodedBuffer || length < 4)
{
return -1;
}
if (!HasInfo(length))
{
if (-1 == FindInfo(ptrEncodedBuffer, length))
{
Reset();
return -1;
}
}
ptrInfo = &_info;
return 0;
}
RtpVideoCodecTypes
H264Information::Type()
{
if(_SVC)
{
return RTP_H264_SVCVideo;
}
return RTP_H264Video;
}
/*******************************************************************************
* bool HasInfo(const WebRtc_UWord32 length);
*
* Checks if information has already been stored for this encoded stream.
*
* Input:
* - length : Length in bytes of encoded stream.
*
* Return value:
* - true (false) : Information has (not) been stored.
*/
bool
H264Information::HasInfo(const WebRtc_UWord32 length)
{
if (!_info.numNALUs)
{
return false;
}
// has info, make sure current length matches info length
if (length != _length)
{
Reset();
return false;
}
return true;
}
/*******************************************************************************
* WebRtc_Word32 FindInfo(const WebRtc_UWord8* ptrEncodedBuffer,
* const WebRtc_UWord32 length);
*
* Parses the encoded stream.
*
* Input:
* - ptrEncodedBuffer : Pointer to encoded stream.
* - length : Length in bytes of encoded stream.
*
* Return value:
* - 0 : ok
* - (-1) : Error
*/
WebRtc_Word32
H264Information::FindInfo(const WebRtc_UWord8* ptrEncodedBuffer, const WebRtc_UWord32 length)
{
_ptrData = ptrEncodedBuffer;
_length = length;
_parsedLength = 0;
_remLength = length;
do
{
// Get start code length
if (FindNALUStartCodeSize() == -1)
{
Reset();
return -1;
}
// Get NAL unit payload size
WebRtc_Word32 foundLast = FindNALU();
if (foundLast == -1)
{
Reset();
return -1;
}
// Validate parsed length
if (_parsedLength > _length)
{
Reset();
return -1;
}
// Get NRI
GetNRI();
// Get type
if (FindNALUType() == -1)
{
Reset();
return -1;
}
// Set layer start end bit
SetLayerSEBit(foundLast);
// Last NAL unit found?
if (foundLast == 1)
{
if (_parsedLength != _length)
{
Reset();
return -1;
}
_info.numNALUs++;
return SetLayerLengths();
}
// Next NAL unit
_ptrData += (_info.startCodeSize[_info.numNALUs] + _info.payloadSize[_info.numNALUs]);
_remLength -= (_info.startCodeSize[_info.numNALUs] + _info.payloadSize[_info.numNALUs]);
_info.numNALUs++;
// Validate memory allocation
if (_info.numNALUs >= KMaxNumberOfNALUs)
{
Reset();
return -1;
}
}
while(true);
return 0;
}
/*******************************************************************************
* WebRtc_Word32 FindNALUStartCodeSize();
*
* Finds the start code length of the current NAL unit.
*
* Output:
* - _info.startCodeSize[currentNALU] : Start code length in bytes of NAL unit.
*
* Return value:
* - 0 : ok
* - (-1) : Error
*/
WebRtc_Word32
H264Information::FindNALUStartCodeSize()
{
// NAL unit start code. Ex. {0,0,1} or {0,0,0,1}
for (WebRtc_UWord32 i = 2; i < _remLength; i++)
{
if (_ptrData[i] == 1 && _ptrData[i - 1] == 0 && _ptrData[i - 2] == 0)
{
_info.startCodeSize[_info.numNALUs] = WebRtc_UWord8(i + 1);
return 0;
}
}
return -1;
}
/*******************************************************************************
* WebRtc_Word32 FindNALU();
*
* Finds the length of the current NAL unit.
*
* Output:
* - _info.payloadSize[currentNALU] : Payload length in bytes of NAL unit
* (start code length not included).
* - _parsedLength : Current parsed length in bytes.
*
* Return value:
* - 1 : ok. Last NAL unit found.
* - 0 : ok
* - (-1) : Error
*/
WebRtc_Word32
H264Information::FindNALU()
{
for (WebRtc_UWord32 i = _info.startCodeSize[_info.numNALUs]; i < _remLength - 2; i += 2)
{
if (_ptrData[i] == 0)
{
WebRtc_Word32 size = 0;
if ((_ptrData[i + 1] == 1 && _ptrData[i - 1] == 0) ||
(_ptrData[i + 2] == 1 && _ptrData[i + 1] == 0))
{
// Found a header
// Reduce size by preceding zeroes
while (_ptrData[i - 1] == 0)
{
i--;
}
size = i;
}
if (size > 0)
{
_info.payloadSize[_info.numNALUs] = size - _info.startCodeSize[_info.numNALUs];
_parsedLength += _info.startCodeSize[_info.numNALUs] + _info.payloadSize[_info.numNALUs];
return 0;
}
}
}
// Last NAL unit
_info.payloadSize[_info.numNALUs] = _remLength - _info.startCodeSize[_info.numNALUs];
if (_info.payloadSize[_info.numNALUs] > 0)
{
_parsedLength += _info.startCodeSize[_info.numNALUs] + _info.payloadSize[_info.numNALUs];
return 1;
}
return -1;
}
/*******************************************************************************
* void GetNRI();
*
* Finds the NRI of the current NAL unit.
*
* Output:
* - _info.NRI[currentNALU] : NRI of NAL unit.
*
* Return value:
* - 0 : ok
* - (-1) : Error
*/
void
H264Information::GetNRI()
{
// NAL unit header (1 byte)
// ---------------------------------
// | start code |F|NRI| Type |
// ---------------------------------
// NRI (2 bits) - nal_ref_idc. '00' - the NAL unit is not used to reconstruct reference pictures.
// >00 - the NAL unit is required to reconstruct reference pictures
// in the same layer, or contains a parameter set.
const WebRtc_UWord8 type = _ptrData[_info.startCodeSize[_info.numNALUs]] & 0x1f;
// NALU type of 5, 7 and 8 shoud have NRI to b011
if( type == 5 ||
type == 7 ||
type == 8)
{
_info.NRI[_info.numNALUs] = 0x60;
}else
{
_info.NRI[_info.numNALUs] = _ptrData[_info.startCodeSize[_info.numNALUs]] & 0x60;
}
}
/*******************************************************************************
* WebRtc_Word32 FindNALUType();
*
* Finds the type of the current NAL unit.
*
* Output:
* - _info.type[currentNALU] : Type of NAL unit
*
* Return value:
* - 0 : ok
* - (-1) : Error
*/
WebRtc_Word32
H264Information::FindNALUType()
{
// NAL unit header (1 byte)
// ---------------------------------
// | start code |F|NRI| Type |
// ---------------------------------
_info.type[_info.numNALUs] = _ptrData[_info.startCodeSize[_info.numNALUs]] & 0x1f;
if (_info.type[_info.numNALUs] == 0)
{
return -1;
}
// SVC NAL units, extended header
if (ParseSVCNALUHeader() == -1)
{
return -1;
}
return 0;
}
/*******************************************************************************
* WebRtc_Word32 ParseSVCNALUHeader();
*
* Finds the extended header of the current NAL unit. Included for NAL unit types 14 and 20.
*
* Output:
* - _info.SVCheader[currentNALU] : SVC header of NAL unit.
*
* Return value:
* - 0 : ok
* - (-1) : Error
*/
WebRtc_Word32
H264Information::ParseSVCNALUHeader()
{
if (_info.type[_info.numNALUs] == 5)
{
_info.SVCheader[_info.numNALUs].idr = 1;
}
if (_info.type[_info.numNALUs] == 6)
{
WebRtc_UWord32 seiPayloadSize;
do
{
// SEI message
seiPayloadSize = 0;
WebRtc_UWord32 curByte = _info.startCodeSize[_info.numNALUs] + 1;
const WebRtc_UWord32 seiStartOffset = curByte;
WebRtc_UWord32 seiPayloadType = 0;
while(_ptrData[curByte] == 0xff)
{
seiPayloadType += 255;
curByte++;
}
seiPayloadType += _ptrData[curByte++];
while(_ptrData[curByte] == 0xff)
{
seiPayloadSize += 255;
curByte++;
}
seiPayloadSize += _ptrData[curByte++];
if(_info.payloadSize[_info.numNALUs] < _info.startCodeSize[_info.numNALUs] + seiPayloadSize)
{
// sanity of remaining buffer
// return 0 since no one "need" SEI messages
assert(false);
return 0;
}
if(seiPayloadType == 24)
{
// we add this to NALU 0 to be signaled in the first PACSI packet
_info.PACSI[0].numSEINALUs = 1; // we allways add this to NALU 0 to send it in the first packet
if(_info.PACSI[0].seiMessageLength[0] != seiPayloadSize)
{
_info.PACSI[0].seiMessageLength[0] = seiPayloadSize;
delete [] _info.PACSI[0].seiMessageData[0];
_info.PACSI[0].seiMessageData[0] = new WebRtc_UWord8[seiPayloadSize];
}
memcpy(_info.PACSI[0].seiMessageData[0], _ptrData+seiStartOffset, seiPayloadSize);
_info.PACSI[0].NALlength += seiPayloadSize + 2; // additional 2 is the length
#ifdef DEBUG_SEI_MESSAGE
const WebRtc_UWord8 numberOfLayers = 10;
WebRtc_UWord16 avgBitrate[numberOfLayers]= {0,0,0,0,0,0,0,0,0,0};
WebRtc_UWord16 maxBitrateLayer[numberOfLayers]= {0,0,0,0,0,0,0,0,0,0};
WebRtc_UWord16 maxBitrateLayerRepresentation[numberOfLayers] = {0,0,0,0,0,0,0,0,0,0};
WebRtc_UWord16 maxBitrareCalcWindow[numberOfLayers] = {0,0,0,0,0,0,0,0,0,0};
BitstreamParser parserScalabilityInfo(_ptrData+curByte, seiPayloadSize);
parserScalabilityInfo.Get1Bit(); // not used in futher parsing
const WebRtc_UWord8 priority_layer_info_present = parserScalabilityInfo.Get1Bit();
const WebRtc_UWord8 priority_id_setting_flag = parserScalabilityInfo.Get1Bit();
WebRtc_UWord32 numberOfLayersMinusOne = parserScalabilityInfo.GetUE();
for(WebRtc_UWord32 j = 0; j<= numberOfLayersMinusOne; j++)
{
printf("\nLayer ID:%d \n",parserScalabilityInfo.GetUE());
printf("Priority ID:%d \n", parserScalabilityInfo.Get6Bits());
printf("Discardable:%d \n", parserScalabilityInfo.Get1Bit());
printf("Dependency ID:%d \n", parserScalabilityInfo.Get3Bits());
printf("Quality ID:%d \n", parserScalabilityInfo.Get4Bits());
printf("Temporal ID:%d \n", parserScalabilityInfo.Get3Bits());
const WebRtc_UWord8 sub_pic_layer_flag = parserScalabilityInfo.Get1Bit();
const WebRtc_UWord8 sub_region_layer_flag = parserScalabilityInfo.Get1Bit();
const WebRtc_UWord8 iroi_division_info_present_flag = parserScalabilityInfo.Get1Bit();
const WebRtc_UWord8 profile_level_info_present_flag = parserScalabilityInfo.Get1Bit();
const WebRtc_UWord8 bitrate_info_present_flag = parserScalabilityInfo.Get1Bit();
const WebRtc_UWord8 frm_rate_info_present_flag = parserScalabilityInfo.Get1Bit();
const WebRtc_UWord8 frm_size_info_present_flag = parserScalabilityInfo.Get1Bit();
const WebRtc_UWord8 layer_dependency_info_present_flag = parserScalabilityInfo.Get1Bit();
const WebRtc_UWord8 parameter_sets_info_present_flag = parserScalabilityInfo.Get1Bit();
const WebRtc_UWord8 bitstream_restriction_info_present_flag = parserScalabilityInfo.Get1Bit();
const WebRtc_UWord8 exact_inter_layer_pred_flag = parserScalabilityInfo.Get1Bit(); // not used in futher parsing
if(sub_pic_layer_flag || iroi_division_info_present_flag)
{
parserScalabilityInfo.Get1Bit();
}
const WebRtc_UWord8 layer_conversion_flag = parserScalabilityInfo.Get1Bit();
const WebRtc_UWord8 layer_output_flag = parserScalabilityInfo.Get1Bit(); // not used in futher parsing
if(profile_level_info_present_flag)
{
parserScalabilityInfo.Get24Bits();
}
if(bitrate_info_present_flag)
{
// this is what we want
avgBitrate[j] = parserScalabilityInfo.Get16Bits();
maxBitrateLayer[j] = parserScalabilityInfo.Get16Bits();
maxBitrateLayerRepresentation[j] = parserScalabilityInfo.Get16Bits();
maxBitrareCalcWindow[j] = parserScalabilityInfo.Get16Bits();
printf("\tAvg:%d\n", BitRateBPS(avgBitrate[j]));
printf("\tmaxBitrate:%d\n", BitRateBPS(maxBitrateLayer[j]));
printf("\tmaxBitrate rep:%d\n", BitRateBPS(maxBitrateLayerRepresentation[j]));
printf("\tCalcWindow:%d\n", maxBitrareCalcWindow[j]);
}
if(frm_rate_info_present_flag)
{
printf("\tFrame rate constant:%d\n", parserScalabilityInfo.Get2Bits()); // 0 = not constant, 1 = constant, 2 = maybe...
printf("\tFrame rate avg:%d\n", parserScalabilityInfo.Get16Bits()/256);
}
if(frm_size_info_present_flag || iroi_division_info_present_flag)
{
printf("\tFrame Width:%d\n",(parserScalabilityInfo.GetUE()+1)*16);
printf("\tFrame Height:%d\n",(parserScalabilityInfo.GetUE()+1)*16);
}
if(sub_region_layer_flag)
{
parserScalabilityInfo.GetUE();
if(parserScalabilityInfo.Get1Bit())
{
parserScalabilityInfo.Get16Bits();
parserScalabilityInfo.Get16Bits();
parserScalabilityInfo.Get16Bits();
parserScalabilityInfo.Get16Bits();
}
}
if(sub_pic_layer_flag)
{
parserScalabilityInfo.GetUE();
}
if(iroi_division_info_present_flag)
{
if(parserScalabilityInfo.Get1Bit())
{
parserScalabilityInfo.GetUE();
parserScalabilityInfo.GetUE();
}else
{
const WebRtc_UWord32 numRoisMinusOne = parserScalabilityInfo.GetUE();
for(WebRtc_UWord32 k = 0; k <= numRoisMinusOne; k++)
{
parserScalabilityInfo.GetUE();
parserScalabilityInfo.GetUE();
parserScalabilityInfo.GetUE();
}
}
}
if(layer_dependency_info_present_flag)
{
const WebRtc_UWord32 numDirectlyDependentLayers = parserScalabilityInfo.GetUE();
for(WebRtc_UWord32 k = 0; k < numDirectlyDependentLayers; k++)
{
parserScalabilityInfo.GetUE();
}
} else
{
parserScalabilityInfo.GetUE();
}
if(parameter_sets_info_present_flag)
{
const WebRtc_UWord32 numSeqParameterSetMinusOne = parserScalabilityInfo.GetUE();
for(WebRtc_UWord32 k = 0; k <= numSeqParameterSetMinusOne; k++)
{
parserScalabilityInfo.GetUE();
}
const WebRtc_UWord32 numSubsetSeqParameterSetMinusOne = parserScalabilityInfo.GetUE();
for(WebRtc_UWord32 l = 0; l <= numSubsetSeqParameterSetMinusOne; l++)
{
parserScalabilityInfo.GetUE();
}
const WebRtc_UWord32 numPicParameterSetMinusOne = parserScalabilityInfo.GetUE();
for(WebRtc_UWord32 m = 0; m <= numPicParameterSetMinusOne; m++)
{
parserScalabilityInfo.GetUE();
}
}else
{
parserScalabilityInfo.GetUE();
}
if(bitstream_restriction_info_present_flag)
{
parserScalabilityInfo.Get1Bit();
parserScalabilityInfo.GetUE();
parserScalabilityInfo.GetUE();
parserScalabilityInfo.GetUE();
parserScalabilityInfo.GetUE();
parserScalabilityInfo.GetUE();
parserScalabilityInfo.GetUE();
}
if(layer_conversion_flag)
{
parserScalabilityInfo.GetUE();
for(WebRtc_UWord32 k = 0; k <2;k++)
{
if(parserScalabilityInfo.Get1Bit())
{
parserScalabilityInfo.Get24Bits();
parserScalabilityInfo.Get16Bits();
parserScalabilityInfo.Get16Bits();
}
}
}
}
if(priority_layer_info_present)
{
const WebRtc_UWord32 prNumDidMinusOne = parserScalabilityInfo.GetUE();
for(WebRtc_UWord32 k = 0; k <= prNumDidMinusOne;k++)
{
parserScalabilityInfo.Get3Bits();
const WebRtc_UWord32 prNumMinusOne = parserScalabilityInfo.GetUE();
for(WebRtc_UWord32 l = 0; l <= prNumMinusOne; l++)
{
parserScalabilityInfo.GetUE();
parserScalabilityInfo.Get24Bits();
parserScalabilityInfo.Get16Bits();
parserScalabilityInfo.Get16Bits();
}
}
}
if(priority_id_setting_flag)
{
WebRtc_UWord8 priorityIdSettingUri;
WebRtc_UWord32 priorityIdSettingUriIdx = 0;
do
{
priorityIdSettingUri = parserScalabilityInfo.Get8Bits();
} while (priorityIdSettingUri != 0);
}
#endif
} else
{
// not seiPayloadType 24 ignore
}
//check if we have more SEI in NALU
} while (_info.payloadSize[_info.numNALUs] > _info.startCodeSize[_info.numNALUs] + seiPayloadSize);
}
// Extended NAL unit header (3 bytes).
// +---------------+---------------+---------------+
// |0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |R|I| PRID |N| DID | QID | TID |U|D|O| RR|
// +---------------+---------------+---------------+
// R - Reserved for future extensions (MUST be 1). Receivers SHOULD ignore the value of R.
// I - Is layer representation an IDR layer (1) or not (0).
// PRID - Priority identifier for the NAL unit.
// N - Specifies whether inter-layer prediction may be used for decoding the coded slice (1) or not (0).
// DID - Indicates the inter-layer coding dependency level of a layer representation.
// QID - Indicates the quality level of an MGS layer representation.
// TID - Indicates the temporal level of a layer representation.
// U - Use only reference base pictures during the inter prediction process (1) or not (0).
// D - Discardable flag.
// O - Output_flag. Affects the decoded picture output process as defined in Annex C of [H.264].
// RR - Reserved_three_2bits (MUST be '11'). Receivers SHOULD ignore the value of RR.
if (_info.type[_info.numNALUs] == 14 ||
_info.type[_info.numNALUs] == 20)
{
WebRtc_UWord32 curByte = _info.startCodeSize[_info.numNALUs] + 1;
if (_remLength < curByte + 3)
{
return -1;
}
_info.SVCheader[_info.numNALUs].idr = (_ptrData[curByte] >> 6) & 0x01;
_info.SVCheader[_info.numNALUs].priorityID = (_ptrData[curByte++] & 0x3F);
_info.SVCheader[_info.numNALUs].interLayerPred = (_ptrData[curByte] >> 7) & 0x01;
_info.SVCheader[_info.numNALUs].dependencyID = (_ptrData[curByte] >> 4) & 0x07;
_info.SVCheader[_info.numNALUs].qualityID = (_ptrData[curByte++] & 0x0F);
_info.SVCheader[_info.numNALUs].temporalID = (_ptrData[curByte] >> 5) & 0x07;
_info.SVCheader[_info.numNALUs].useRefBasePic = (_ptrData[curByte] >> 4) & 0x01;
_info.SVCheader[_info.numNALUs].discardable = (_ptrData[curByte] >> 3) & 0x01;
_info.SVCheader[_info.numNALUs].output = (_ptrData[curByte] >> 2) & 0x01;
if (_info.type[_info.numNALUs] == 14)
{
// inform the next NALU
memcpy(&(_info.SVCheader[_info.numNALUs+1]), &(_info.SVCheader[_info.numNALUs]), sizeof(_H264_SVC_NALUHeader));
}
}
return 0;
}
/*******************************************************************************
* void SetLayerSEBit();
*
* Sets start and end bits for the current NAL unit.
*
* Output:
* - _info.PACSI[currentNALU].S : First NAL unit in a layer (S = 1).
* - _info.PACSI[currentNALU].E : Last NAL unit in a layer (E = 1).
*
*/
void
H264Information::SetLayerSEBit(WebRtc_Word32 foundLast)
{
if (_info.numNALUs == 0)
{
// First NAL unit
_info.PACSI[_info.numNALUs].S = 1;
}
if (_info.numNALUs > 0)
{
if (_info.type[_info.numNALUs] != _info.type[_info.numNALUs-1] &&
(_info.type[_info.numNALUs] == 20))
{
// First layer in scalable extension
_info.PACSI[_info.numNALUs].S = 1;
_info.PACSI[_info.numNALUs-1].E = 1;
}
if (_info.type[_info.numNALUs] == 20 && _info.type[_info.numNALUs-1] == 20)
{
if (_info.SVCheader[_info.numNALUs].temporalID != _info.SVCheader[_info.numNALUs-1].temporalID ||
_info.SVCheader[_info.numNALUs].dependencyID != _info.SVCheader[_info.numNALUs-1].dependencyID ||
_info.SVCheader[_info.numNALUs].qualityID != _info.SVCheader[_info.numNALUs-1].qualityID)
{
// New layer in scalable extension
_info.PACSI[_info.numNALUs].S = 1;
_info.PACSI[_info.numNALUs-1].E = 1;
}
}
}
if (foundLast)
{
// Last NAL unit
_info.PACSI[_info.numNALUs].E = 1;
}
}
/*******************************************************************************
* WebRtc_Word32 SetLayerLengths();
*
* Sets the accumulated layer length.
*
* Output:
* - _info.accLayerSize[currentLayer] : Size in bytes of layer: 0 - currentLayer.
*
* Return value:
* - 0 : ok
* - (-1) : Error
*
*/
WebRtc_Word32
H264Information::SetLayerLengths()
{
for (WebRtc_UWord32 curNALU = 0; curNALU < _info.numNALUs; curNALU++)
{
_info.accLayerSize[_info.numLayers] += _info.startCodeSize[curNALU] + _info.payloadSize[curNALU];
if (_info.PACSI[curNALU].E == 1)
{
_info.numLayers++;
if (curNALU == WebRtc_UWord32(_info.numNALUs - 1))
{
break;
}
if (_info.numLayers >= KMaxNumberOfLayers)
{
Reset();
return -1;
}
_info.accLayerSize[_info.numLayers] += _info.accLayerSize[_info.numLayers - 1];
}
}
if (_info.numLayers < 1 && _info.numLayers > KMaxNumberOfLayers)
{
Reset();
return -1;
}
if (_info.accLayerSize[_info.numLayers - 1] != WebRtc_Word32(_length))
{
Reset();
return -1;
}
return 0;
}
} // namespace webrtc