819 lines
28 KiB
C++
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
|