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