Newer
Older

Karsten Suehring
committed
/* The copyright in this software is being made available under the BSD
* License, included below. This software may be subject to other third party
* and contributor rights, including patent rights, and no such rights are
* granted under this license.
*
* Copyright (c) 2010-2025, ITU/ISO/IEC

Karsten Suehring
committed
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
* 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 the ITU/ISO/IEC 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 AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
*/
/**
\file SEIread.cpp
\brief reading funtionality for SEI messages
*/
#include "CommonLib/CommonDef.h"
#include "CommonLib/BitStream.h"
#include "CommonLib/SEI.h"
#include "CommonLib/Slice.h"
#include "VLCReader.h"
#include "SEIread.h"
#include "CommonLib/Picture.h"
#include "CommonLib/dtrace_next.h"
#include <iomanip>
//! \ingroup DecoderLib
//! \{
void SEIReader::sei_read_scode(std::ostream *pOS, uint32_t length, int& code, const char *pSymbolName)
{
if (pOS)
{
(*pOS) << " " << std::setw(55) << pSymbolName << ": " << code << "\n";
}
}
void SEIReader::sei_read_code(std::ostream *pOS, uint32_t length, uint32_t &ruiCode, const char *pSymbolName)

Karsten Suehring
committed
{

Karsten Suehring
committed
if (pOS)
{
(*pOS) << " " << std::setw(55) << pSymbolName << ": " << ruiCode << "\n";
}
}
void SEIReader::sei_read_uvlc(std::ostream *pOS, uint32_t& ruiCode, const char *pSymbolName)
{

Karsten Suehring
committed
if (pOS)
{
(*pOS) << " " << std::setw(55) << pSymbolName << ": " << ruiCode << "\n";
}
}
void SEIReader::sei_read_svlc(std::ostream *pOS, int& ruiCode, const char *pSymbolName)
{

Karsten Suehring
committed
if (pOS)
{
(*pOS) << " " << std::setw(55) << pSymbolName << ": " << ruiCode << "\n";
}
}
void SEIReader::sei_read_flag(std::ostream *pOS, uint32_t& ruiCode, const char *pSymbolName)
{

Karsten Suehring
committed
if (pOS)
{
(*pOS) << " " << std::setw(55) << pSymbolName << ": " << (ruiCode?1:0) << "\n";
}
}
void SEIReader::sei_read_string(std::ostream* os, std::string& code, const char* symbolName)
{
if (os)
{
(*os) << " " << std::setw(55) << symbolName << ": " << code << "\n";
}
}

Karsten Suehring
committed
static inline void output_sei_message_header(SEI &sei, std::ostream *pDecodedMessageOutputStream, uint32_t payloadSize)
{
if (pDecodedMessageOutputStream)
{
std::string seiMessageHdr(SEI::getSEIMessageString(sei.payloadType())); seiMessageHdr+=" SEI message";
(*pDecodedMessageOutputStream) << std::setfill('-') << std::setw((int) seiMessageHdr.size()) << "-"
<< std::setfill(' ') << "\n"
<< seiMessageHdr << " (" << payloadSize << " bytes)"
<< "\n";

Karsten Suehring
committed
}
}
/**
* unmarshal a single SEI message from bitstream bs
*/

Karsten Suehring
committed
// note: for independent parsing no parameter set should not be required here
SEIMessages::iterator SEIReader::parseSEImessage(InputBitstream* bs, SEIMessages& seis, const NalUnitType nalUnitType, const uint32_t nuh_layer_id, const uint32_t temporalId, const VPS *vps, const SPS *sps, HRD &hrd, std::ostream *pDecodedMessageOutputStream)

Karsten Suehring
committed
{
SEIMessages seiListInCurNalu;

Karsten Suehring
committed
setBitstream(bs);
CHECK(m_pcBitstream->getNumBitsUntilByteAligned(), "Bitstream not aligned");
SEIMessages::iterator newSEI = seis.end();

Karsten Suehring
committed
do
{
const bool seiMessageRead = xReadSEImessage(seis, nalUnitType, nuh_layer_id, temporalId, vps, sps, hrd, pDecodedMessageOutputStream);
if (seiMessageRead)
{
seiListInCurNalu.push_back(seis.back());
if (newSEI == seis.end())
{
newSEI = --seis.end();
}

Karsten Suehring
committed
/* SEI messages are an integer number of bytes, something has failed
* in the parsing if bitstream not byte-aligned */
CHECK(m_pcBitstream->getNumBitsUntilByteAligned(), "Bitstream not aligned");
}
while (m_pcBitstream->getNumBitsLeft() > 8);
const SEIMessages fillerData = getSeisByType(seiListInCurNalu, SEI::PayloadType::FILLER_PAYLOAD);
CHECK(fillerData.size() > 0 && fillerData.size() != seiListInCurNalu.size(), "When an SEI NAL unit contains an SEI message with payloadType equal to filler payload, the SEI NAL unit shall not contain any other SEI message with payloadType not equal to filler payload");
const SEIMessages pictureTiming = getSeisByType(seiListInCurNalu, SEI::PayloadType::PICTURE_TIMING);
CHECK(hrd.getGeneralHrdParameters().getGeneralSamePicTimingInAllOlsFlag() && pictureTiming.size() > 0 && pictureTiming.size() != seiListInCurNalu.size(),

Karsten Suehring
committed
"When general_same_pic_timing_in_all_ols_flag is equal to 1 [...], and when an SEI NAL unit contains a non-scalable-nested SEI message with "
"payloadType equal to 1 (PT), the SEI NAL unit shall not contain any other SEI message with payloadType not equal 1.");

Karsten Suehring
committed
xReadRbspTrailingBits();

Karsten Suehring
committed
}
void SEIReader::parseAndExtractSEIScalableNesting(InputBitstream *bs, const NalUnitType nalUnitType,
const uint32_t nuh_layer_id, const VPS *vps, const SPS *sps, HRD &hrd,
uint32_t payloadSize, std::vector<SeiPayload> *seiList)
xParseSEIScalableNesting(sn, nalUnitType, nuh_layer_id, payloadSize, vps, sps, m_nestedHrd, nullptr, seiList);
int payloadBitsRemaining = getBitstream()->getNumBitsLeft();
if (payloadBitsRemaining) /* more_data_in_payload() */
{
for (; payloadBitsRemaining > 9; payloadBitsRemaining--)
{
uint32_t reservedPayloadExtensionData;
sei_read_code(nullptr, 1, reservedPayloadExtensionData, "reserved_payload_extension_data");
}
/* 2 */
int finalBits = getBitstream()->peekBits(payloadBitsRemaining);
int finalPayloadBits = 0;
for (int mask = 0xff; finalBits & (mask >> finalPayloadBits); finalPayloadBits++)
{
continue;
}
/* 3 */
for (; payloadBitsRemaining > 9 - finalPayloadBits; payloadBitsRemaining--)
{
uint32_t reservedPayloadExtensionData;
sei_read_flag ( 0, reservedPayloadExtensionData, "reserved_payload_extension_data");
}
uint32_t dummy;
sei_read_flag( 0, dummy, "payload_bit_equal_to_one"); payloadBitsRemaining--;
while (payloadBitsRemaining)
{
sei_read_flag( 0, dummy, "payload_bit_equal_to_zero"); payloadBitsRemaining--;
}
}
}
void SEIReader::getSEIDecodingUnitInfoDuiIdx(InputBitstream* bs, const uint32_t nuhLayerId, HRD& hrd,
uint32_t payloadSize, int& duiIdx)
const SEIBufferingPeriod* bp = hrd.getBufferingPeriodSEI();
InputBitstream bsTmp(*bs);
setBitstream(&bsTmp);
SEIDecodingUnitInfo dui;
xParseSEIDecodingUnitInfo(dui, payloadSize, *bp, nuhLayerId, nullptr);
duiIdx = dui.decodingUnitIdx;
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
bool SEIReader::xCheckNnpfcSeiMsg(uint32_t seiId, bool baseFlag, const std::vector<int> nnpfcValueList)
{
if (baseFlag)
{
//Check if this is a new filter or a repetition of an existing base flag
for (auto val : nnpfcValueList)
{
if (val == seiId)
{
//The filter is a repetition.
return false;
}
}
}
else
{
bool filterHasPresent = false;
for(auto val : nnpfcValueList)
{
if (val == seiId)
{
filterHasPresent = true;
break;
}
}
CHECK(!filterHasPresent, "Cannot have update filter without base filter already present!")
}
return true;
}
bool SEIReader::xCheckNnpfcUpdatePresentSeiMsg(uint32_t seiId, const std::vector<int> nnpfcValueList)
{
int count = 0;
for (auto val : nnpfcValueList)
{
if (val == seiId)
{
count++;
if (count == 2)
return true;
}
}
return false;
}
bool SEIReader::xReadSEImessage(SEIMessages& seis, const NalUnitType nalUnitType, const uint32_t nuh_layer_id, const uint32_t temporalId, const VPS *vps, const SPS *sps, HRD &hrd, std::ostream *pDecodedMessageOutputStream)

Karsten Suehring
committed
{
#if ENABLE_TRACING
xTraceSEIHeader();
#endif
int payloadType = 0;
uint32_t val = 0;
do
{
sei_read_code(nullptr, 8, val, "payload_type");

Karsten Suehring
committed
payloadType += val;
} while (val==0xFF);
uint32_t payloadSize = 0;
do
{
sei_read_code(nullptr, 8, val, "payload_size");

Karsten Suehring
committed
payloadSize += val;
} while (val==0xFF);
#if ENABLE_TRACING
xTraceSEIMessageType((SEI::PayloadType)payloadType);
#endif
/* extract the payload for this single SEI message.
* This allows greater safety in erroneous parsing of an SEI message
* from affecting subsequent messages.
* After parsing the payload, bs needs to be restored as the primary
* bitstream.
*/
InputBitstream *bs = getBitstream();
setBitstream(bs->extractSubstream(payloadSize * 8));

Karsten Suehring
committed
if(nalUnitType == NAL_UNIT_PREFIX_SEI)
{
switch (SEI::PayloadType(payloadType))

Karsten Suehring
committed
{
case SEI::PayloadType::FILLER_PAYLOAD:
sei = new SEIFillerPayload;
xParseSEIFillerPayload((SEIFillerPayload&) *sei, payloadSize, pDecodedMessageOutputStream);
break;
case SEI::PayloadType::USER_DATA_UNREGISTERED:
{
auto udu = new SEIUserDataUnregistered;
xParseSEIuserDataUnregistered(*udu, payloadSize, pDecodedMessageOutputStream);
sei = udu;
break;
}
case SEI::PayloadType::DECODING_UNIT_INFO:
const SEIBufferingPeriod* bp = hrd.getBufferingPeriodSEI();
if (bp == nullptr)
{
msg(WARNING, "Warning: Found Decoding unit information SEI message, but no active buffering period is "
"available. Ignoring.");
}
else
{
sei = new SEIDecodingUnitInfo;
xParseSEIDecodingUnitInfo((SEIDecodingUnitInfo&) *sei, payloadSize, *bp, temporalId,
pDecodedMessageOutputStream);
}
break;
case SEI::PayloadType::BUFFERING_PERIOD:

Karsten Suehring
committed
{
auto bp = new SEIBufferingPeriod;
xParseSEIBufferingPeriod(*bp, payloadSize, pDecodedMessageOutputStream);
hrd.setBufferingPeriodSEI(bp);
sei = bp;
break;
const SEIBufferingPeriod* bp = hrd.getBufferingPeriodSEI();
if (bp == nullptr)
{
msg(WARNING,
"Warning: Found Picture timing SEI message, but no active buffering period is available. Ignoring.");
}
else
{
sei = new SEIPictureTiming;
xParseSEIPictureTiming((SEIPictureTiming&) *sei, payloadSize, temporalId, *bp, pDecodedMessageOutputStream);
hrd.setPictureTimingSEI((SEIPictureTiming*) sei);
}
break;

Karsten Suehring
committed
}
case SEI::PayloadType::SCALABLE_NESTING:
{
auto sn = new SEIScalableNesting;
xParseSEIScalableNesting(*sn, nalUnitType, nuh_layer_id, payloadSize, vps, sps, hrd,
pDecodedMessageOutputStream, nullptr);
sei = sn;
break;
}
case SEI::PayloadType::FRAME_FIELD_INFO:
xParseSEIFrameFieldinfo((SEIFrameFieldInfo &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::DEPENDENT_RAP_INDICATION:
sei = new SEIDependentRAPIndication;
xParseSEIDependentRAPIndication((SEIDependentRAPIndication &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::EXTENDED_DRAP_INDICATION:
xParseSEIExtendedDrapIndication((SEIExtendedDrapIndication &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::FRAME_PACKING:

Karsten Suehring
committed
sei = new SEIFramePacking;
xParseSEIFramePacking((SEIFramePacking &) *sei, payloadSize, pDecodedMessageOutputStream);

Karsten Suehring
committed
break;
case SEI::PayloadType::DISPLAY_ORIENTATION:
xParseSEIDisplayOrientation((SEIDisplayOrientation &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::ANNOTATED_REGIONS:
sei = new SEIAnnotatedRegions;
xParseSEIAnnotatedRegions((SEIAnnotatedRegions &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::OBJECT_MASK_INFO:
sei = new SEIObjectMaskInfos;
xParseSEIObjectMaskInfos((SEIObjectMaskInfos&) *sei, payloadSize, pDecodedMessageOutputStream);
break;
case SEI::PayloadType::PARAMETER_SETS_INCLUSION_INDICATION:
Rickard Sjöberg
committed
sei = new SEIParameterSetsInclusionIndication;
xParseSEIParameterSetsInclusionIndication((SEIParameterSetsInclusionIndication &) *sei, payloadSize,
pDecodedMessageOutputStream);
Rickard Sjöberg
committed
break;
case SEI::PayloadType::MASTERING_DISPLAY_COLOUR_VOLUME:

Karsten Suehring
committed
sei = new SEIMasteringDisplayColourVolume;
xParseSEIMasteringDisplayColourVolume((SEIMasteringDisplayColourVolume &) *sei, payloadSize,
pDecodedMessageOutputStream);

Karsten Suehring
committed
break;
case SEI::PayloadType::ALTERNATIVE_TRANSFER_CHARACTERISTICS:

Karsten Suehring
committed
sei = new SEIAlternativeTransferCharacteristics;
xParseSEIAlternativeTransferCharacteristics((SEIAlternativeTransferCharacteristics &) *sei, payloadSize,
pDecodedMessageOutputStream);

Karsten Suehring
committed
break;
case SEI::PayloadType::EQUIRECTANGULAR_PROJECTION:
sei = new SEIEquirectangularProjection;
xParseSEIEquirectangularProjection((SEIEquirectangularProjection &) *sei, payloadSize,
pDecodedMessageOutputStream);
case SEI::PayloadType::SPHERE_ROTATION:
sei = new SEISphereRotation;
xParseSEISphereRotation((SEISphereRotation &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::OMNI_VIEWPORT:
sei = new SEIOmniViewport;
xParseSEIOmniViewport((SEIOmniViewport &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::REGION_WISE_PACKING:
sei = new SEIRegionWisePacking;
xParseSEIRegionWisePacking((SEIRegionWisePacking &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::GENERALIZED_CUBEMAP_PROJECTION:
sei = new SEIGeneralizedCubemapProjection;
xParseSEIGeneralizedCubemapProjection((SEIGeneralizedCubemapProjection &) *sei, payloadSize,
pDecodedMessageOutputStream);
case SEI::PayloadType::SCALABILITY_DIMENSION_INFO:
sei = new SEIScalabilityDimensionInfo;
xParseSEIScalabilityDimensionInfo((SEIScalabilityDimensionInfo &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::GREEN_METADATA:
xParseSEIGreenMetadataInfo((SEIGreenMetadataInfo &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::MULTIVIEW_ACQUISITION_INFO:
sei = new SEIMultiviewAcquisitionInfo;
xParseSEIMultiviewAcquisitionInfo((SEIMultiviewAcquisitionInfo &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::MULTIVIEW_VIEW_POSITION:
sei = new SEIMultiviewViewPosition;
xParseSEIMultiviewViewPosition((SEIMultiviewViewPosition &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::ALPHA_CHANNEL_INFO:
sei = new SEIAlphaChannelInfo;
xParseSEIAlphaChannelInfo((SEIAlphaChannelInfo &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::DEPTH_REPRESENTATION_INFO:
sei = new SEIDepthRepresentationInfo;
xParseSEIDepthRepresentationInfo((SEIDepthRepresentationInfo &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::SUBPICTURE_LEVEL_INFO:
sei = new SEISubpictureLevelInfo;
xParseSEISubpictureLevelInfo((SEISubpictureLevelInfo&) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::SAMPLE_ASPECT_RATIO_INFO:
sei = new SEISampleAspectRatioInfo;
xParseSEISampleAspectRatioInfo((SEISampleAspectRatioInfo &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::USER_DATA_REGISTERED_ITU_T_T35:
xParseSEIUserDataRegistered((SEIUserDataRegistered &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::FILM_GRAIN_CHARACTERISTICS:
xParseSEIFilmGrainCharacteristics((SEIFilmGrainCharacteristics &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::CONTENT_LIGHT_LEVEL_INFO:
xParseSEIContentLightLevelInfo((SEIContentLightLevelInfo &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::AMBIENT_VIEWING_ENVIRONMENT:
xParseSEIAmbientViewingEnvironment((SEIAmbientViewingEnvironment &) *sei, payloadSize,
pDecodedMessageOutputStream);
case SEI::PayloadType::CONTENT_COLOUR_VOLUME:
xParseSEIContentColourVolume((SEIContentColourVolume &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::COLOUR_TRANSFORM_INFO:
sei = new SEIColourTransformInfo;
xParseSEIColourTransformInfo((SEIColourTransformInfo &) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::SEI_MANIFEST:
xParseSEISEIManifest((SEIManifest&) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::SEI_PREFIX_INDICATION:
sei = new SEIPrefixIndication;
xParseSEISEIPrefixIndication((SEIPrefixIndication&) *sei, payloadSize, pDecodedMessageOutputStream);
case SEI::PayloadType::CONSTRAINED_RASL_ENCODING:
sei = new SEIConstrainedRaslIndication;
xParseSEIConstrainedRaslIndication((SEIConstrainedRaslIndication &) *sei, payloadSize,
pDecodedMessageOutputStream);
case SEI::PayloadType::SHUTTER_INTERVAL_INFO:
Jeeva Raj A
committed
sei = new SEIShutterIntervalInfo;
xParseSEIShutterInterval((SEIShutterIntervalInfo &) *sei, payloadSize, pDecodedMessageOutputStream);
Jeeva Raj A
committed
break;
case SEI::PayloadType::NEURAL_NETWORK_POST_FILTER_CHARACTERISTICS:
sei = new SEINeuralNetworkPostFilterCharacteristics;
xParseSEINNPostFilterCharacteristics((SEINeuralNetworkPostFilterCharacteristics &) *sei, payloadSize, sps,
pDecodedMessageOutputStream);
if (xCheckNnpfcSeiMsg( ((SEINeuralNetworkPostFilterCharacteristics*)sei)->m_id, ((SEINeuralNetworkPostFilterCharacteristics*)sei)->m_baseFlag, nnpfcValues) )
{
nnpfcValues.push_back(((SEINeuralNetworkPostFilterCharacteristics*)sei)->m_id);
}
case SEI::PayloadType::NEURAL_NETWORK_POST_FILTER_ACTIVATION:
sei = new SEINeuralNetworkPostFilterActivation;
xParseSEINNPostFilterActivation((SEINeuralNetworkPostFilterActivation &) *sei, payloadSize,
pDecodedMessageOutputStream);
nnpfcProcessed = false;
CHECK(nnpfcValues.size() == 0, "At leaset one NNPFC SEI message should precede NNPFA")
for(int i=0; i<nnpfcValues.size(); ++i)
{
if(((SEINeuralNetworkPostFilterCharacteristics*)sei)->m_id == nnpfcValues[i])
{
//In the case that the NNPFA activates a non-base filter, only consider it process when we have NNPFC that updates the base filter present
if(((SEINeuralNetworkPostFilterCharacteristics*)sei)->m_baseFlag ||
(!((SEINeuralNetworkPostFilterCharacteristics*)sei)->m_baseFlag && xCheckNnpfcUpdatePresentSeiMsg( ((SEINeuralNetworkPostFilterCharacteristics*)sei)->m_id, nnpfcValues)) )
CHECK(!nnpfcProcessed, "No NNPFC, no NNPFA")
case SEI::PayloadType::PHASE_INDICATION:
sei = new SEIPhaseIndication;
xParseSEIPhaseIndication((SEIPhaseIndication &) *sei, payloadSize, pDecodedMessageOutputStream);
break;
case SEI::PayloadType::SEI_PROCESSING_ORDER:
sei = new SEIProcessingOrderInfo;
xParseSEIProcessingOrder((SEIProcessingOrderInfo&)*sei, nalUnitType, nuh_layer_id, payloadSize, vps, sps, hrd,
pDecodedMessageOutputStream);
case SEI::PayloadType::SEI_PROCESSING_ORDER_NESTING:
sei = new SEIProcessingOrderNesting;
xParseSEIProcessingOrderNesting((SEIProcessingOrderNesting&)*sei, nalUnitType, nuh_layer_id, payloadSize, vps, sps, hrd,
pDecodedMessageOutputStream);
break;

Karsten Suehring
committed
case SEI::PayloadType::TEXT_DESCRIPTION:
sei = new SEITextDescription;
xParseSEITextDescription((SEITextDescription&)*sei, payloadSize, pDecodedMessageOutputStream);
break;
case SEI::PayloadType::POST_FILTER_HINT:
sei = new SEIPostFilterHint;
xParseSEIPostFilterHint((SEIPostFilterHint &) *sei, payloadSize, pDecodedMessageOutputStream);
break;
Hendry
committed
case SEI::PayloadType::ENCODER_OPTIMIZATION_INFO:
sei = new SEIEncoderOptimizationInfo;
xParseSEIEncoderOptimizationInfo((SEIEncoderOptimizationInfo &)*sei, payloadSize, pDecodedMessageOutputStream);
break;
case SEI::PayloadType::SOURCE_PICTURE_TIMING_INFO:
sei = new SEISourcePictureTimingInfo;
xParseSEISourcePictureTimingInfo((SEISourcePictureTimingInfo&) *sei, payloadSize, pDecodedMessageOutputStream);
break;
case SEI::PayloadType::MODALITY_INFORMATION:
sei = new SEIModalityInfo;
xParseSEIModalityInfo((SEIModalityInfo &) *sei, payloadSize, pDecodedMessageOutputStream);
break;
case SEI::PayloadType::DIGITALLY_SIGNED_CONTENT_INITIALIZATION:
sei = new SEIDigitallySignedContentInitialization;
xParseSEIDigitallySignedContentInitialization((SEIDigitallySignedContentInitialization &) *sei, payloadSize, pDecodedMessageOutputStream);
break;
case SEI::PayloadType::DIGITALLY_SIGNED_CONTENT_SELECTION:
sei = new SEIDigitallySignedContentSelection;
xParseSEIDigitallySignedContentSelection((SEIDigitallySignedContentSelection &) *sei, payloadSize, pDecodedMessageOutputStream);
break;

Karsten Suehring
committed
default:
for (uint32_t i = 0; i < payloadSize; i++)
{
uint32_t seiByte;
sei_read_code(nullptr, 8, seiByte, "unknown prefix SEI payload byte");

Karsten Suehring
committed
}
msg(WARNING, "Unknown prefix SEI message (payloadType = %d) was found!\n", payloadType);

Karsten Suehring
committed
if (pDecodedMessageOutputStream)
{
(*pDecodedMessageOutputStream) << "Unknown prefix SEI message (payloadType = " << payloadType
<< ") was found!\n";

Karsten Suehring
committed
}
break;
}
}
else
{
switch (SEI::PayloadType(payloadType))
{
case SEI::PayloadType::USER_DATA_UNREGISTERED:
{
auto udu = new SEIUserDataUnregistered;
xParseSEIuserDataUnregistered(*udu, payloadSize, pDecodedMessageOutputStream);
sei = udu;
break;
}
case SEI::PayloadType::DECODED_PICTURE_HASH:
sei = new SEIDecodedPictureHash;
xParseSEIDecodedPictureHash((SEIDecodedPictureHash &) *sei, payloadSize, pDecodedMessageOutputStream);
break;
case SEI::PayloadType::SCALABLE_NESTING:
{
auto sn = new SEIScalableNesting;
xParseSEIScalableNesting(*sn, nalUnitType, nuh_layer_id, payloadSize, vps, sps, hrd,
pDecodedMessageOutputStream, nullptr);
sei = sn;
break;
}
Antti Hallapuro
committed
case SEI::PayloadType::NEURAL_NETWORK_POST_FILTER_CHARACTERISTICS:
sei = new SEINeuralNetworkPostFilterCharacteristics;
xParseSEINNPostFilterCharacteristics((SEINeuralNetworkPostFilterCharacteristics &) *sei, payloadSize, sps,
pDecodedMessageOutputStream);
if (xCheckNnpfcSeiMsg( ((SEINeuralNetworkPostFilterCharacteristics*)sei)->m_id, ((SEINeuralNetworkPostFilterCharacteristics*)sei)->m_baseFlag, nnpfcValues) )
{
nnpfcValues.push_back(((SEINeuralNetworkPostFilterCharacteristics*)sei)->m_id);
}
break;
case SEI::PayloadType::NEURAL_NETWORK_POST_FILTER_ACTIVATION:
sei = new SEINeuralNetworkPostFilterActivation;
xParseSEINNPostFilterActivation((SEINeuralNetworkPostFilterActivation &) *sei, payloadSize,
pDecodedMessageOutputStream);
nnpfcProcessed = false;
CHECK(nnpfcValues.size() == 0, "At leaset one NNPFC SEI message should precede NNPFA")
for (int i = 0; i < nnpfcValues.size(); ++i)
{
if (((SEINeuralNetworkPostFilterCharacteristics*) sei)->m_id == nnpfcValues[i])
Antti Hallapuro
committed
{
Antti Hallapuro
committed
}
Antti Hallapuro
committed
CHECK(!nnpfcProcessed, "No NNPFC, no NNPFA")
nnpfcProcessed = false;
break;
case SEI::PayloadType::FILLER_PAYLOAD:
sei = new SEIFillerPayload;
xParseSEIFillerPayload((SEIFillerPayload &) *sei, payloadSize, pDecodedMessageOutputStream);
break;
case SEI::PayloadType::SEI_PROCESSING_ORDER_NESTING:
sei = new SEIProcessingOrderNesting;
xParseSEIProcessingOrderNesting((SEIProcessingOrderNesting&)*sei, nalUnitType, nuh_layer_id, payloadSize, vps, sps, hrd,
pDecodedMessageOutputStream);
break;
case SEI::PayloadType::GENERATIVE_FACE_VIDEO:
sei = new SEIGenerativeFaceVideo;
xParseSEIGenerativeFaceVideo((SEIGenerativeFaceVideo &)*sei, payloadSize, pDecodedMessageOutputStream);
break;
case SEI::PayloadType::DIGITALLY_SIGNED_CONTENT_VERIFICATION:
sei = new SEIDigitallySignedContentVerification;
xParseSEIDigitallySignedContentVerification((SEIDigitallySignedContentVerification &) *sei, payloadSize, pDecodedMessageOutputStream);
break;
default:
for (uint32_t i = 0; i < payloadSize; i++)
{
uint32_t seiByte;
sei_read_code(nullptr, 8, seiByte, "unknown suffix SEI payload byte");
}
msg(WARNING, "Unknown suffix SEI message (payloadType = %d) was found!\n", payloadType);
if (pDecodedMessageOutputStream)
{
(*pDecodedMessageOutputStream) << "Unknown suffix SEI message (payloadType = " << payloadType
<< ") was found!\n";
}
break;

Karsten Suehring
committed
}
}

Karsten Suehring
committed
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
{
seis.push_back(sei);
}
/* By definition the underlying bitstream terminates in a byte-aligned manner.
* 1. Extract all bar the last MIN(bitsremaining,nine) bits as reserved_payload_extension_data
* 2. Examine the final 8 bits to determine the payload_bit_equal_to_one marker
* 3. Extract the remainingreserved_payload_extension_data bits.
*
* If there are fewer than 9 bits available, extract them.
*/
int payloadBitsRemaining = getBitstream()->getNumBitsLeft();
if (payloadBitsRemaining) /* more_data_in_payload() */
{
for (; payloadBitsRemaining > 9; payloadBitsRemaining--)
{
uint32_t reservedPayloadExtensionData;
sei_read_code ( pDecodedMessageOutputStream, 1, reservedPayloadExtensionData, "reserved_payload_extension_data");
}
/* 2 */
int finalBits = getBitstream()->peekBits(payloadBitsRemaining);
int finalPayloadBits = 0;
for (int mask = 0xff; finalBits & (mask >> finalPayloadBits); finalPayloadBits++)
{
continue;
}
/* 3 */
for (; payloadBitsRemaining > 9 - finalPayloadBits; payloadBitsRemaining--)
{
uint32_t reservedPayloadExtensionData;
sei_read_flag ( 0, reservedPayloadExtensionData, "reserved_payload_extension_data");
}
uint32_t dummy;
sei_read_flag( 0, dummy, "payload_bit_equal_to_one"); payloadBitsRemaining--;
while (payloadBitsRemaining)
{
sei_read_flag( 0, dummy, "payload_bit_equal_to_zero"); payloadBitsRemaining--;
}
}
/* restore primary bitstream for sei_message */
delete getBitstream();
setBitstream(bs);

Karsten Suehring
committed
}
void SEIReader::xParseSEIFillerPayload(SEIFillerPayload &sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream)
{
output_sei_message_header(sei, pDecodedMessageOutputStream, payloadSize);
CHECK(val != 0xff, "ff_byte shall be a byte having the value 0xFF");

Karsten Suehring
committed
/**
* parse bitstream bs and unpack a user_data_unregistered SEI message
* of payloasSize bytes into sei.
*/
void SEIReader::xParseSEIuserDataUnregistered(SEIUserDataUnregistered& sei, uint32_t payloadSize,
std::ostream* pDecodedMessageOutputStream)

Karsten Suehring
committed
{
CHECK(payloadSize < sei.uuid.size(), "Payload too small");

Karsten Suehring
committed
uint32_t val;
output_sei_message_header(sei, pDecodedMessageOutputStream, payloadSize);
for (uint32_t i = 0; i < sei.uuid.size(); i++)

Karsten Suehring
committed
{
sei_read_code(pDecodedMessageOutputStream, 8, val, "uuid_iso_iec_11578");
sei.uuid[i] = val;

Karsten Suehring
committed
}
sei.data.resize(payloadSize - sei.uuid.size());

Karsten Suehring
committed
for (uint32_t i = 0; i < sei.data.size(); i++)

Karsten Suehring
committed
{
sei_read_code(nullptr, 8, val, "user_data_payload_byte");

Karsten Suehring
committed
}

Karsten Suehring
committed
if (pDecodedMessageOutputStream)
{
(*pDecodedMessageOutputStream) << " User data payload size: " << sei.data.size() << "\n";

Karsten Suehring
committed
}
}
Jeeva Raj A
committed
void SEIReader::xParseSEIShutterInterval(SEIShutterIntervalInfo& sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream)
{
int32_t i;
uint32_t val;
output_sei_message_header(sei, pDecodedMessageOutputStream, payloadSize);
sei_read_code(pDecodedMessageOutputStream, 32, val, "sii_time_scale"); sei.m_siiTimeScale = val;
sei_read_flag(pDecodedMessageOutputStream, val, "fixed_shutter_interval_within_clvs_flag"); sei.m_siiFixedSIwithinCLVS = val;
if (sei.m_siiFixedSIwithinCLVS)
{
sei_read_code(pDecodedMessageOutputStream, 32, val, "sii_num_units_in_shutter_interval"); sei.m_siiNumUnitsInShutterInterval = val;
}
else
{
sei_read_code(pDecodedMessageOutputStream, 3, val, "sii_max_sub_layers_minus1 "); sei.m_siiMaxSubLayersMinus1 = val;
sei.m_siiSubLayerNumUnitsInSI.resize(sei.m_siiMaxSubLayersMinus1 + 1);
for (i = 0; i <= sei.m_siiMaxSubLayersMinus1; i++)
{
sei_read_code(pDecodedMessageOutputStream, 32, val, "sub_layer_num_units_in_shutter_interval[ i ]");
sei.m_siiSubLayerNumUnitsInSI[i] = val;
}
}
}
void SEIReader::xParseSEIProcessingOrder(SEIProcessingOrderInfo& sei, const NalUnitType nalUnitType, const uint32_t nuhLayerId, uint32_t payloadSize, const VPS* vps, const SPS* sps, HRD& hrd, std::ostream* decodedMessageOutputStream)
output_sei_message_header(sei, decodedMessageOutputStream, payloadSize);
sei_read_code(decodedMessageOutputStream, 8, val, "po_sei_id");
sei.m_posId = val;
Antti Hallapuro
committed
sei_read_code(decodedMessageOutputStream, 2, val, "po_for_human_viewing_idc");
sei.m_posForHumanViewingIdc = val;
sei_read_code(decodedMessageOutputStream, 2, val, "po_for_machine_analysis_idc");
sei.m_posForMachineAnalysisIdc = val;
sei_read_code(decodedMessageOutputStream, 4, val, "po_reserved_zero_4bits"); // Decoders shall allow any value of po_reserved_zero_4bits in the range of 0 to 15, inclusive
Antti Hallapuro
committed
sei_read_code(decodedMessageOutputStream, 7, val, "po_sei_num_minus2");
sei.m_posNumMinus2 = val;
sei_read_flag(decodedMessageOutputStream, val, "po_breadth_first_flag");
sei.m_posBreadthFirstFlag = val;
sei.m_posPayloadType.resize(numMaxSeiMessages);
sei.m_posProcessingOrder.resize(numMaxSeiMessages);
sei.m_posNumBitsInPrefix.resize(numMaxSeiMessages);
sei.m_posWrappingFlag.resize(numMaxSeiMessages);
sei.m_posImportanceFlag.resize(numMaxSeiMessages);
Antti Hallapuro
committed
sei.m_posProcessingDegreeFlag.resize(numMaxSeiMessages);
Antti Hallapuro
committed
bool NNPFCFound = false;
bool NNPFAFound = false;
sei_read_flag(decodedMessageOutputStream, val, "po_sei_wrapping_flag[i]");
sei.m_posWrappingFlag[i] = val;
sei_read_flag(decodedMessageOutputStream, val, "po_sei_importance_flag[i]");
sei.m_posImportanceFlag[i] = val;
Antti Hallapuro
committed
sei_read_flag(decodedMessageOutputStream, val, "po_sei_processing_degree_flag[i]");
sei.m_posProcessingDegreeFlag[i] = val;
sei_read_code(decodedMessageOutputStream, 13, val, "po_sei_payload_type[i]");
sei.m_posPayloadType[i] = val;
sei_read_flag(decodedMessageOutputStream, val, "po_sei_prefix_flag[i]");
sei.m_posPrefixFlag[i] = val;
sei_read_code(decodedMessageOutputStream, 8, val, "po_sei_processing_order[i]");
sei.m_posProcessingOrder[i] = val;
CHECK((i > 0) && (sei.m_posProcessingOrder[i] < sei.m_posProcessingOrder[i-1]) , "For i greater than 0, po_sei_processing_order[i] shall be greater than or equal to po_sei_processing_order[i-1]");
Antti Hallapuro
committed
NNPFCFound = NNPFCFound || (sei.m_posPayloadType[i] == (uint16_t)SEI::PayloadType::NEURAL_NETWORK_POST_FILTER_CHARACTERISTICS);
NNPFAFound = NNPFAFound || (sei.m_posPayloadType[i] == (uint16_t)SEI::PayloadType::NEURAL_NETWORK_POST_FILTER_ACTIVATION);
CHECK(!NNPFCFound && NNPFAFound, "NNPFA payload type found before NNPFC payload type in SPO SEI");
CHECK(i<2, "An SEI processing order SEI message shall contain at least two pairs sei_payloadType[i] and sei_processingOrder[i]");
Antti Hallapuro
committed
CHECK(NNPFCFound && !NNPFAFound, "When SPO SEI contains NNPFC payload type it shall also contain NNPFA payload type");
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
for (i = 0; i < numMaxSeiMessages; i++)
{
sei.m_posNumBitsInPrefix[i] = 0;
sei.m_posPrefixByte[i].clear();
if (sei.m_posPrefixFlag[i])
{
sei_read_code(decodedMessageOutputStream, 8, val, "po_num_bits_in_prefix_indication_minus1[i]");
sei.m_posNumBitsInPrefix[i] = (uint16_t)val;
for (uint32_t j = 0; j < sei.m_posNumBitsInPrefix[i]; j += 8)
{
uint32_t numBits = (sei.m_posNumBitsInPrefix[i] - j) < 8 ? (sei.m_posNumBitsInPrefix[i] - j) : 8;
uint32_t prefixByte = 0;
for (uint32_t k = 0; k < numBits; k++)
{
sei_read_code(decodedMessageOutputStream, 1, val, "po_sei_prefix_data_bit[i][j]");
prefixByte = (prefixByte << 1) | val;
}
sei.m_posPrefixByte[i].push_back((uint8_t)prefixByte);
}
while (!isByteAligned())
{
sei_read_code(decodedMessageOutputStream, 1, val, "po_byte_alignment_bit_equal_to_one");
CHECK(val == 0, "po_byte_alignment_bit_equal_to_one has value of zero");
}
}
}
Antti Hallapuro
committed
uint32_t numProcStgs = sei.m_posNumMinus2 + 2;
std::vector<uint32_t> seiTypeIdx;
for (uint32_t j = 0; j < numProcStgs; j++)
{
seiTypeIdx.push_back(j);
}
uint32_t subChainFlag = 0;
uint32_t subChainPrevIdx = 0;
sei.m_posSubChainIdx.resize(numProcStgs);
for (uint32_t j = 0; j < numProcStgs; j++)
{
uint32_t idx = seiTypeIdx[j];
if (sei.m_posImportanceFlag[idx] && sei.m_posProcessingDegreeFlag[idx])
Antti Hallapuro
committed
{
sei.m_posSubChainIdx[j] = 0;
}
else if (!sei.m_posImportanceFlag[idx] && sei.m_posProcessingDegreeFlag[idx])
Antti Hallapuro
committed
{
sei.m_posSubChainIdx[j] = subChainPrevIdx;
subChainFlag = 0;
}
else if (sei.m_posImportanceFlag[idx] && !sei.m_posProcessingDegreeFlag[idx])
Antti Hallapuro
committed
{
if (subChainFlag == 0)
{
subChainPrevIdx++;
}
sei.m_posSubChainIdx[j] = subChainPrevIdx;
subChainFlag = 1;
}
else
{
sei.m_posSubChainIdx[j] = subChainFlag * subChainPrevIdx;
}
}
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
}
void SEIReader::xParseSEIProcessingOrderNesting(SEIProcessingOrderNesting& sei, const NalUnitType nalUnitType, const uint32_t nuhLayerId, uint32_t payloadSize, const VPS* vps, const SPS* sps, HRD& hrd, std::ostream* decodedMessageOutputStream)
{
uint32_t val, ponNumPoIdsMinus1;
sei_read_code(decodedMessageOutputStream, 8, val, "pon_num_po_ids_minus1");
ponNumPoIdsMinus1 = val;
sei.m_ponTargetPoId.clear();
for (int i = 0; i <= ponNumPoIdsMinus1; i++)
{
sei_read_code(decodedMessageOutputStream, 8, val, "pon_target_po_id[i]");
sei.m_ponTargetPoId.push_back((uint8_t)val);
}
sei_read_code(decodedMessageOutputStream, 8, val, "pon_num_seis_minus1");
sei.m_ponNumSeisMinus1 = val;
sei.m_ponProcessingOrder.clear();
for (int i = 0; i <= sei.m_ponNumSeisMinus1; i++)
{
sei_read_code(decodedMessageOutputStream, 8, val, "pon_processing_order[i]");
sei.m_ponProcessingOrder.push_back((uint8_t)val);
CHECK((i > 0) && (sei.m_ponProcessingOrder[i] < sei.m_ponProcessingOrder[i-1]) , "When i is greater than 0, pon_processing_order[i] shall be greater than or equal to pon_processing_order[i-1]");
SEIMessages tmpSEI;
const bool seiMessageRead = xReadSEImessage(tmpSEI, nalUnitType, nuhLayerId, 0, vps, sps, m_nestedHrd, decodedMessageOutputStream);
if (seiMessageRead)
{
sei.m_ponWrapSeiMessages.push_back(tmpSEI.front());
tmpSEI.clear();
}
}

Karsten Suehring
committed
/**
* parse bitstream bs and unpack a decoded picture hash SEI message
* of payloadSize bytes into sei.
*/
void SEIReader::xParseSEIDecodedPictureHash(SEIDecodedPictureHash& sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream)
{
uint32_t bytesRead = 0;
output_sei_message_header(sei, pDecodedMessageOutputStream, payloadSize);
uint32_t val;
Martin Pettersson
committed
sei_read_code( pDecodedMessageOutputStream, 8, val, "dph_sei_hash_type");

Karsten Suehring
committed
sei.method = static_cast<HashType>(val); bytesRead++;
sei_read_code( pDecodedMessageOutputStream, 1, val, "dph_sei_single_component_flag");
sei.singleCompFlag = val;
sei_read_code( pDecodedMessageOutputStream, 7, val, "dph_sei_reserved_zero_7bits");
bytesRead++;
uint32_t expectedSize =
(sei.singleCompFlag ? 1 : 3) * (sei.method == HashType::MD5 ? 16 : (sei.method == HashType::CRC ? 2 : 4));
CHECK ((payloadSize - bytesRead) != expectedSize, "The size of the decoded picture hash does not match the expected size.");

Karsten Suehring
committed
const char *traceString="\0";
switch (sei.method)
{
case HashType::MD5:
traceString = "picture_md5";
break;
case HashType::CRC:
traceString = "picture_crc";
break;
case HashType::CHECKSUM:
traceString = "picture_checksum";
break;
default:
THROW("Unknown hash type");
break;

Karsten Suehring
committed
}
if (pDecodedMessageOutputStream)
{
(*pDecodedMessageOutputStream) << " " << std::setw(55) << traceString << ": " << std::hex << std::setfill('0');
}
sei.m_pictureHash.hash.clear();
for(;bytesRead < payloadSize; bytesRead++)
{

Karsten Suehring
committed
sei.m_pictureHash.hash.push_back((uint8_t)val);
if (pDecodedMessageOutputStream)
{
(*pDecodedMessageOutputStream) << std::setw(2) << val;
}
}
if (pDecodedMessageOutputStream)
{
(*pDecodedMessageOutputStream) << std::dec << std::setfill(' ') << "\n";
}
}
void SEIReader::xParseSEIScalableNesting(SEIScalableNesting& sn, const NalUnitType nalUnitType,
const uint32_t nuhLayerId, uint32_t payloadSize, const VPS* vps,
const SPS* sps, HRD& hrd, std::ostream* decodedMessageOutputStream,
std::vector<SeiPayload>* seiList)