Forked from
jvet / VVCSoftware_VTM
7312 commits behind the upstream repository.
-
Karsten Suehring authoredKarsten Suehring authored
SEIEncoder.cpp 31.00 KiB
/* 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-2019, ITU/ISO/IEC
* 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.
*/
#include "CommonLib/CommonDef.h"
#include "CommonLib/SEI.h"
#include "EncGOP.h"
#include "EncLib.h"
uint32_t calcMD5(const CPelUnitBuf& pic, PictureHash &digest, const BitDepths &bitDepths);
uint32_t calcCRC(const CPelUnitBuf& pic, PictureHash &digest, const BitDepths &bitDepths);
uint32_t calcChecksum(const CPelUnitBuf& pic, PictureHash &digest, const BitDepths &bitDepths);
std::string hashToString(const PictureHash &digest, int numChar);
//! \ingroup EncoderLib
//! \{
#if HEVC_VPS
void SEIEncoder::initSEIActiveParameterSets (SEIActiveParameterSets *seiActiveParameterSets, const VPS *vps, const SPS *sps)
#else
void SEIEncoder::initSEIActiveParameterSets (SEIActiveParameterSets *seiActiveParameterSets, const SPS *sps)
#endif
{
CHECK(!(m_isInitialized), "Unspecified error");
CHECK(!(seiActiveParameterSets!=NULL), "Unspecified error");
#if HEVC_VPS
CHECK(!(vps!=NULL), "Unspecified error");
#endif
CHECK(!(sps!=NULL), "Unspecified error");
#if HEVC_VPS
seiActiveParameterSets->activeVPSId = vps->getVPSId();
#endif
seiActiveParameterSets->m_selfContainedCvsFlag = false;
seiActiveParameterSets->m_noParameterSetUpdateFlag = false;
seiActiveParameterSets->numSpsIdsMinus1 = 0;
seiActiveParameterSets->activeSeqParameterSetId.resize(seiActiveParameterSets->numSpsIdsMinus1 + 1);
seiActiveParameterSets->activeSeqParameterSetId[0] = sps->getSPSId();
}
void SEIEncoder::initSEIFramePacking(SEIFramePacking *seiFramePacking, int currPicNum)
{
CHECK(!(m_isInitialized), "Unspecified error");
CHECK(!(seiFramePacking!=NULL), "Unspecified error");
seiFramePacking->m_arrangementId = m_pcCfg->getFramePackingArrangementSEIId();
seiFramePacking->m_arrangementCancelFlag = 0;
seiFramePacking->m_arrangementType = m_pcCfg->getFramePackingArrangementSEIType();
CHECK(!((seiFramePacking->m_arrangementType > 2) && (seiFramePacking->m_arrangementType < 6) ), "Unspecified error");
seiFramePacking->m_quincunxSamplingFlag = m_pcCfg->getFramePackingArrangementSEIQuincunx();
seiFramePacking->m_contentInterpretationType = m_pcCfg->getFramePackingArrangementSEIInterpretation();
seiFramePacking->m_spatialFlippingFlag = 0;
seiFramePacking->m_frame0FlippedFlag = 0;
seiFramePacking->m_fieldViewsFlag = (seiFramePacking->m_arrangementType == 2);
seiFramePacking->m_currentFrameIsFrame0Flag = ((seiFramePacking->m_arrangementType == 5) && (currPicNum&1) );
seiFramePacking->m_frame0SelfContainedFlag = 0;
seiFramePacking->m_frame1SelfContainedFlag = 0;
seiFramePacking->m_frame0GridPositionX = 0;
seiFramePacking->m_frame0GridPositionY = 0;
seiFramePacking->m_frame1GridPositionX = 0;
seiFramePacking->m_frame1GridPositionY = 0;
seiFramePacking->m_arrangementReservedByte = 0;
seiFramePacking->m_arrangementPersistenceFlag = true;
seiFramePacking->m_upsampledAspectRatio = 0;
}
void SEIEncoder::initSEISegmentedRectFramePacking(SEISegmentedRectFramePacking *seiSegmentedRectFramePacking)
{
CHECK(!(m_isInitialized), "Unspecified error");
CHECK(!(seiSegmentedRectFramePacking!=NULL), "Unspecified error");
seiSegmentedRectFramePacking->m_arrangementCancelFlag = m_pcCfg->getSegmentedRectFramePackingArrangementSEICancel();
seiSegmentedRectFramePacking->m_contentInterpretationType = m_pcCfg->getSegmentedRectFramePackingArrangementSEIType();
seiSegmentedRectFramePacking->m_arrangementPersistenceFlag = m_pcCfg->getSegmentedRectFramePackingArrangementSEIPersistence();
}
void SEIEncoder::initSEIDisplayOrientation(SEIDisplayOrientation* seiDisplayOrientation)
{
CHECK(!(m_isInitialized), "Unspecified error");
CHECK(!(seiDisplayOrientation!=NULL), "Unspecified error");
seiDisplayOrientation->cancelFlag = false;
seiDisplayOrientation->horFlip = false;
seiDisplayOrientation->verFlip = false;
seiDisplayOrientation->anticlockwiseRotation = m_pcCfg->getDisplayOrientationSEIAngle();
}
void SEIEncoder::initSEIToneMappingInfo(SEIToneMappingInfo *seiToneMappingInfo)
{
CHECK(!(m_isInitialized), "Unspecified error");
CHECK(!(seiToneMappingInfo!=NULL), "Unspecified error");
seiToneMappingInfo->m_toneMapId = m_pcCfg->getTMISEIToneMapId();
seiToneMappingInfo->m_toneMapCancelFlag = m_pcCfg->getTMISEIToneMapCancelFlag();
seiToneMappingInfo->m_toneMapPersistenceFlag = m_pcCfg->getTMISEIToneMapPersistenceFlag();
seiToneMappingInfo->m_codedDataBitDepth = m_pcCfg->getTMISEICodedDataBitDepth();
CHECK(!(seiToneMappingInfo->m_codedDataBitDepth >= 8 && seiToneMappingInfo->m_codedDataBitDepth <= 14), "Unspecified error");
seiToneMappingInfo->m_targetBitDepth = m_pcCfg->getTMISEITargetBitDepth();
CHECK(!(seiToneMappingInfo->m_targetBitDepth >= 1 && seiToneMappingInfo->m_targetBitDepth <= 17), "Unspecified error");
seiToneMappingInfo->m_modelId = m_pcCfg->getTMISEIModelID();
CHECK(!(seiToneMappingInfo->m_modelId >=0 &&seiToneMappingInfo->m_modelId<=4), "Unspecified error");
switch( seiToneMappingInfo->m_modelId)
{
case 0:
{
seiToneMappingInfo->m_minValue = m_pcCfg->getTMISEIMinValue();
seiToneMappingInfo->m_maxValue = m_pcCfg->getTMISEIMaxValue();
break;
}
case 1:
{
seiToneMappingInfo->m_sigmoidMidpoint = m_pcCfg->getTMISEISigmoidMidpoint();
seiToneMappingInfo->m_sigmoidWidth = m_pcCfg->getTMISEISigmoidWidth();
break;
}
case 2:
{
uint32_t num = 1u<<(seiToneMappingInfo->m_targetBitDepth);
seiToneMappingInfo->m_startOfCodedInterval.resize(num);
int* ptmp = m_pcCfg->getTMISEIStartOfCodedInterva();
if(ptmp)
{
for(int i=0; i<num;i++)
{
seiToneMappingInfo->m_startOfCodedInterval[i] = ptmp[i];
}
}
break;
}
case 3:
{
seiToneMappingInfo->m_numPivots = m_pcCfg->getTMISEINumPivots();
seiToneMappingInfo->m_codedPivotValue.resize(seiToneMappingInfo->m_numPivots);
seiToneMappingInfo->m_targetPivotValue.resize(seiToneMappingInfo->m_numPivots);
int* ptmpcoded = m_pcCfg->getTMISEICodedPivotValue();
int* ptmptarget = m_pcCfg->getTMISEITargetPivotValue();
if(ptmpcoded&&ptmptarget)
{
for(int i=0; i<(seiToneMappingInfo->m_numPivots);i++)
{
seiToneMappingInfo->m_codedPivotValue[i]=ptmpcoded[i];
seiToneMappingInfo->m_targetPivotValue[i]=ptmptarget[i];
}
}
break;
}
case 4:
{
seiToneMappingInfo->m_cameraIsoSpeedIdc = m_pcCfg->getTMISEICameraIsoSpeedIdc();
seiToneMappingInfo->m_cameraIsoSpeedValue = m_pcCfg->getTMISEICameraIsoSpeedValue();
CHECK(!( seiToneMappingInfo->m_cameraIsoSpeedValue !=0 ), "Unspecified error");
seiToneMappingInfo->m_exposureIndexIdc = m_pcCfg->getTMISEIExposurIndexIdc();
seiToneMappingInfo->m_exposureIndexValue = m_pcCfg->getTMISEIExposurIndexValue();
CHECK(!( seiToneMappingInfo->m_exposureIndexValue !=0 ), "Unspecified error");
seiToneMappingInfo->m_exposureCompensationValueSignFlag = m_pcCfg->getTMISEIExposureCompensationValueSignFlag();
seiToneMappingInfo->m_exposureCompensationValueNumerator = m_pcCfg->getTMISEIExposureCompensationValueNumerator();
seiToneMappingInfo->m_exposureCompensationValueDenomIdc = m_pcCfg->getTMISEIExposureCompensationValueDenomIdc();
seiToneMappingInfo->m_refScreenLuminanceWhite = m_pcCfg->getTMISEIRefScreenLuminanceWhite();
seiToneMappingInfo->m_extendedRangeWhiteLevel = m_pcCfg->getTMISEIExtendedRangeWhiteLevel();
CHECK(!( seiToneMappingInfo->m_extendedRangeWhiteLevel >= 100 ), "Unspecified error");
seiToneMappingInfo->m_nominalBlackLevelLumaCodeValue = m_pcCfg->getTMISEINominalBlackLevelLumaCodeValue();
seiToneMappingInfo->m_nominalWhiteLevelLumaCodeValue = m_pcCfg->getTMISEINominalWhiteLevelLumaCodeValue();
CHECK(!( seiToneMappingInfo->m_nominalWhiteLevelLumaCodeValue > seiToneMappingInfo->m_nominalBlackLevelLumaCodeValue ), "Unspecified error");
seiToneMappingInfo->m_extendedWhiteLevelLumaCodeValue = m_pcCfg->getTMISEIExtendedWhiteLevelLumaCodeValue();
CHECK(!( seiToneMappingInfo->m_extendedWhiteLevelLumaCodeValue >= seiToneMappingInfo->m_nominalWhiteLevelLumaCodeValue ), "Unspecified error");
break;
}
default:
{
CHECK(!(!"Undefined SEIToneMapModelId"), "Unspecified error");
break;
}
}
}
void SEIEncoder::initSEISOPDescription(SEISOPDescription *sopDescriptionSEI, Slice *slice, int picInGOP, int lastIdr, int currGOPSize)
{
CHECK(!(m_isInitialized), "Unspecified error");
CHECK(!(sopDescriptionSEI != NULL), "Unspecified error");
CHECK(!(slice != NULL), "Unspecified error");
int sopCurrPOC = slice->getPOC();
sopDescriptionSEI->m_sopSeqParameterSetId = slice->getSPS()->getSPSId();
int i = 0;
int prevEntryId = picInGOP;
for (int j = picInGOP; j < currGOPSize; j++)
{
int deltaPOC = m_pcCfg->getGOPEntry(j).m_POC - m_pcCfg->getGOPEntry(prevEntryId).m_POC;
if ((sopCurrPOC + deltaPOC) < m_pcCfg->getFramesToBeEncoded())
{
sopCurrPOC += deltaPOC;
sopDescriptionSEI->m_sopDescVclNaluType[i] = m_pcEncGOP->getNalUnitType(sopCurrPOC, lastIdr, slice->getPic()->fieldPic);
sopDescriptionSEI->m_sopDescTemporalId[i] = m_pcCfg->getGOPEntry(j).m_temporalId;
sopDescriptionSEI->m_sopDescStRpsIdx[i] = m_pcEncLib->getReferencePictureSetIdxForSOP(sopCurrPOC, j);
sopDescriptionSEI->m_sopDescPocDelta[i] = deltaPOC;
prevEntryId = j;
i++;
}
}
sopDescriptionSEI->m_numPicsInSopMinus1 = i - 1;
}
void SEIEncoder::initSEIBufferingPeriod(SEIBufferingPeriod *bufferingPeriodSEI, Slice *slice)
{
CHECK(!(m_isInitialized), "Unspecified error");
CHECK(!(bufferingPeriodSEI != NULL), "Unspecified error");
CHECK(!(slice != NULL), "Unspecified error");
uint32_t uiInitialCpbRemovalDelay = (90000/2); // 0.5 sec
bufferingPeriodSEI->m_initialCpbRemovalDelay [0][0] = uiInitialCpbRemovalDelay;
bufferingPeriodSEI->m_initialCpbRemovalDelayOffset[0][0] = uiInitialCpbRemovalDelay;
bufferingPeriodSEI->m_initialCpbRemovalDelay [0][1] = uiInitialCpbRemovalDelay;
bufferingPeriodSEI->m_initialCpbRemovalDelayOffset[0][1] = uiInitialCpbRemovalDelay;
double dTmp = (double)slice->getSPS()->getVuiParameters()->getTimingInfo()->getNumUnitsInTick() / (double)slice->getSPS()->getVuiParameters()->getTimingInfo()->getTimeScale();
uint32_t uiTmp = (uint32_t)( dTmp * 90000.0 );
uiInitialCpbRemovalDelay -= uiTmp;
uiInitialCpbRemovalDelay -= uiTmp / ( slice->getSPS()->getVuiParameters()->getHrdParameters()->getTickDivisorMinus2() + 2 );
bufferingPeriodSEI->m_initialAltCpbRemovalDelay [0][0] = uiInitialCpbRemovalDelay;
bufferingPeriodSEI->m_initialAltCpbRemovalDelayOffset[0][0] = uiInitialCpbRemovalDelay;
bufferingPeriodSEI->m_initialAltCpbRemovalDelay [0][1] = uiInitialCpbRemovalDelay;
bufferingPeriodSEI->m_initialAltCpbRemovalDelayOffset[0][1] = uiInitialCpbRemovalDelay;
bufferingPeriodSEI->m_rapCpbParamsPresentFlag = 0;
//for the concatenation, it can be set to one during splicing.
bufferingPeriodSEI->m_concatenationFlag = 0;
//since the temporal layer HRD is not ready, we assumed it is fixed
bufferingPeriodSEI->m_auCpbRemovalDelayDelta = 1;
bufferingPeriodSEI->m_cpbDelayOffset = 0;
bufferingPeriodSEI->m_dpbDelayOffset = 0;
}
//! initialize scalable nesting SEI message.
//! Note: The SEI message structures input into this function will become part of the scalable nesting SEI and will be
//! automatically freed, when the nesting SEI is disposed.
void SEIEncoder::initSEIScalableNesting(SEIScalableNesting *scalableNestingSEI, SEIMessages &nestedSEIs)
{
CHECK(!(m_isInitialized), "Unspecified error");
CHECK(!(scalableNestingSEI != NULL), "Unspecified error");
scalableNestingSEI->m_bitStreamSubsetFlag = 1; // If the nested SEI messages are picture buffering SEI messages, picture timing SEI messages or sub-picture timing SEI messages, bitstream_subset_flag shall be equal to 1
scalableNestingSEI->m_nestingOpFlag = 0;
scalableNestingSEI->m_nestingNumOpsMinus1 = 0; //nesting_num_ops_minus1
scalableNestingSEI->m_allLayersFlag = 0;
scalableNestingSEI->m_nestingNoOpMaxTemporalIdPlus1 = 6 + 1; //nesting_no_op_max_temporal_id_plus1
scalableNestingSEI->m_nestingNumLayersMinus1 = 1 - 1; //nesting_num_layers_minus1
scalableNestingSEI->m_nestingLayerId[0] = 0;
scalableNestingSEI->m_nestedSEIs.clear();
for (SEIMessages::iterator it=nestedSEIs.begin(); it!=nestedSEIs.end(); it++)
{
scalableNestingSEI->m_nestedSEIs.push_back((*it));
}
}
void SEIEncoder::initSEIRecoveryPoint(SEIRecoveryPoint *recoveryPointSEI, Slice *slice)
{
CHECK(!(m_isInitialized), "Unspecified error");
CHECK(!(recoveryPointSEI != NULL), "Unspecified error");
CHECK(!(slice != NULL), "Unspecified error");
recoveryPointSEI->m_recoveryPocCnt = 0;
recoveryPointSEI->m_exactMatchingFlag = ( slice->getPOC() == 0 ) ? (true) : (false);
recoveryPointSEI->m_brokenLinkFlag = false;
}
//! calculate hashes for entire reconstructed picture
void SEIEncoder::initDecodedPictureHashSEI(SEIDecodedPictureHash *decodedPictureHashSEI, PelUnitBuf& pic, std::string &rHashString, const BitDepths &bitDepths)
{
CHECK(!(m_isInitialized), "Unspecified error");
CHECK(!(decodedPictureHashSEI!=NULL), "Unspecified error");
decodedPictureHashSEI->method = m_pcCfg->getDecodedPictureHashSEIType();
switch (m_pcCfg->getDecodedPictureHashSEIType())
{
case HASHTYPE_MD5:
{
uint32_t numChar=calcMD5(pic, decodedPictureHashSEI->m_pictureHash, bitDepths);
rHashString = hashToString(decodedPictureHashSEI->m_pictureHash, numChar);
}
break;
case HASHTYPE_CRC:
{
uint32_t numChar=calcCRC(pic, decodedPictureHashSEI->m_pictureHash, bitDepths);
rHashString = hashToString(decodedPictureHashSEI->m_pictureHash, numChar);
}
break;
case HASHTYPE_CHECKSUM:
default:
{
uint32_t numChar=calcChecksum(pic, decodedPictureHashSEI->m_pictureHash, bitDepths);
rHashString = hashToString(decodedPictureHashSEI->m_pictureHash, numChar);
}
break;
}
}
void SEIEncoder::initTemporalLevel0IndexSEI(SEITemporalLevel0Index *temporalLevel0IndexSEI, Slice *slice)
{
CHECK(!(m_isInitialized), "Unspecified error");
CHECK(!(temporalLevel0IndexSEI!=NULL), "Unspecified error");
CHECK(!(slice!=NULL), "Unspecified error");
if (slice->getRapPicFlag())
{
m_tl0Idx = 0;
m_rapIdx = (m_rapIdx + 1) & 0xFF;
}
else
{
m_tl0Idx = (m_tl0Idx + (slice->getTLayer() ? 0 : 1)) & 0xFF;
}
temporalLevel0IndexSEI->tl0Idx = m_tl0Idx;
temporalLevel0IndexSEI->rapIdx = m_rapIdx;
}
#if HEVC_TILES_WPP
void SEIEncoder::initSEITempMotionConstrainedTileSets (SEITempMotionConstrainedTileSets *sei, const PPS *pps)
{
CHECK(!(m_isInitialized), "Unspecified error");
CHECK(!(sei!=NULL), "Unspecified error");
CHECK(!(pps!=NULL), "Unspecified error");
if(pps->getTilesEnabledFlag())
{
sei->m_mc_all_tiles_exact_sample_value_match_flag = false;
sei->m_each_tile_one_tile_set_flag = false;
sei->m_limited_tile_set_display_flag = false;
sei->setNumberOfTileSets((pps->getNumTileColumnsMinus1() + 1) * (pps->getNumTileRowsMinus1() + 1));
for(int i=0; i < sei->getNumberOfTileSets(); i++)
{
sei->tileSetData(i).m_mcts_id = i; //depends the application;
sei->tileSetData(i).setNumberOfTileRects(1);
for(int j=0; j<sei->tileSetData(i).getNumberOfTileRects(); j++)
{
sei->tileSetData(i).topLeftTileIndex(j) = i+j;
sei->tileSetData(i).bottomRightTileIndex(j) = i+j;
}
sei->tileSetData(i).m_exact_sample_value_match_flag = false;
sei->tileSetData(i).m_mcts_tier_level_idc_present_flag = false;
}
}
else
{
CHECK(!(!"Tile is not enabled"), "Unspecified error");
}
}
#endif
void SEIEncoder::initSEIKneeFunctionInfo(SEIKneeFunctionInfo *seiKneeFunctionInfo)
{
CHECK(!(m_isInitialized), "Unspecified error");
CHECK(!(seiKneeFunctionInfo!=NULL), "Unspecified error");
seiKneeFunctionInfo->m_kneeId = m_pcCfg->getKneeSEIId();
seiKneeFunctionInfo->m_kneeCancelFlag = m_pcCfg->getKneeSEICancelFlag();
if ( !seiKneeFunctionInfo->m_kneeCancelFlag )
{
seiKneeFunctionInfo->m_kneePersistenceFlag = m_pcCfg->getKneeSEIPersistenceFlag();
seiKneeFunctionInfo->m_kneeInputDrange = m_pcCfg->getKneeSEIInputDrange();
seiKneeFunctionInfo->m_kneeInputDispLuminance = m_pcCfg->getKneeSEIInputDispLuminance();
seiKneeFunctionInfo->m_kneeOutputDrange = m_pcCfg->getKneeSEIOutputDrange();
seiKneeFunctionInfo->m_kneeOutputDispLuminance = m_pcCfg->getKneeSEIOutputDispLuminance();
seiKneeFunctionInfo->m_kneeNumKneePointsMinus1 = m_pcCfg->getKneeSEINumKneePointsMinus1();
int* piInputKneePoint = m_pcCfg->getKneeSEIInputKneePoint();
int* piOutputKneePoint = m_pcCfg->getKneeSEIOutputKneePoint();
if(piInputKneePoint&&piOutputKneePoint)
{
seiKneeFunctionInfo->m_kneeInputKneePoint.resize(seiKneeFunctionInfo->m_kneeNumKneePointsMinus1+1);
seiKneeFunctionInfo->m_kneeOutputKneePoint.resize(seiKneeFunctionInfo->m_kneeNumKneePointsMinus1+1);
for(int i=0; i<=seiKneeFunctionInfo->m_kneeNumKneePointsMinus1; i++)
{
seiKneeFunctionInfo->m_kneeInputKneePoint[i] = piInputKneePoint[i];
seiKneeFunctionInfo->m_kneeOutputKneePoint[i] = piOutputKneePoint[i];
}
}
}
}
template <typename T>
static void readTokenValue(T &returnedValue, /// value returned
bool &failed, /// used and updated
std::istream &is, /// stream to read token from
const char *pToken) /// token string
{
returnedValue=T();
if (failed)
{
return;
}
int c;
// Ignore any whitespace
while ((c=is.get())!=EOF && isspace(c));
// test for comment mark
while (c=='#')
{
// Ignore to the end of the line
while ((c=is.get())!=EOF && (c!=10 && c!=13));
// Ignore any white space at the start of the next line
while ((c=is.get())!=EOF && isspace(c));
}
// test first character of token
failed=(c!=pToken[0]);
// test remaining characters of token
int pos;
for(pos=1;!failed && pToken[pos]!=0 && is.get()==pToken[pos]; pos++);
failed|=(pToken[pos]!=0);
// Ignore any whitespace before the ':'
while (!failed && (c=is.get())!=EOF && isspace(c));
failed|=(c!=':');
// Now read the value associated with the token:
if (!failed)
{
is >> returnedValue;
failed=!is.good();
if (!failed)
{
c=is.get();
failed=(c!=EOF && !isspace(c));
}
}
if (failed)
{
std::cerr << "Unable to read token '" << pToken << "'\n";
}
}
template <typename T>
static void readTokenValueAndValidate(T &returnedValue, /// value returned
bool &failed, /// used and updated
std::istream &is, /// stream to read token from
const char *pToken, /// token string
const T &minInclusive, /// minimum value allowed, inclusive
const T &maxInclusive) /// maximum value allowed, inclusive
{
readTokenValue(returnedValue, failed, is, pToken);
if (!failed)
{
if (returnedValue<minInclusive || returnedValue>maxInclusive)
{
failed=true;
std::cerr << "Value for token " << pToken << " must be in the range " << minInclusive << " to " << maxInclusive << " (inclusive); value read: " << returnedValue << std::endl;
}
}
}
// bool version does not have maximum and minimum values.
static void readTokenValueAndValidate(bool &returnedValue, /// value returned
bool &failed, /// used and updated
std::istream &is, /// stream to read token from
const char *pToken) /// token string
{
readTokenValue(returnedValue, failed, is, pToken);
}
bool SEIEncoder::initSEIColourRemappingInfo(SEIColourRemappingInfo* seiColourRemappingInfo, int currPOC) // returns true on success, false on failure.
{
CHECK(!(m_isInitialized), "Unspecified error");
CHECK(!(seiColourRemappingInfo!=NULL), "Unspecified error");
// reading external Colour Remapping Information SEI message parameters from file
if( !m_pcCfg->getColourRemapInfoSEIFileRoot().empty())
{
bool failed=false;
// building the CRI file name with poc num in prefix "_poc.txt"
std::string colourRemapSEIFileWithPoc(m_pcCfg->getColourRemapInfoSEIFileRoot());
{
std::stringstream suffix;
suffix << "_" << currPOC << ".txt";
colourRemapSEIFileWithPoc+=suffix.str();
}
std::ifstream fic(colourRemapSEIFileWithPoc.c_str());
if (!fic.good() || !fic.is_open())
{
std::cerr << "No Colour Remapping Information SEI parameters file " << colourRemapSEIFileWithPoc << " for POC " << currPOC << std::endl;
return false;
}
// TODO: identify and remove duplication with decoder parsing through abstraction.
readTokenValueAndValidate(seiColourRemappingInfo->m_colourRemapId, failed, fic, "colour_remap_id", uint32_t(0), uint32_t(0x7fffffff) );
readTokenValueAndValidate(seiColourRemappingInfo->m_colourRemapCancelFlag, failed, fic, "colour_remap_cancel_flag" );
if( !seiColourRemappingInfo->m_colourRemapCancelFlag )
{
readTokenValueAndValidate(seiColourRemappingInfo->m_colourRemapPersistenceFlag, failed, fic, "colour_remap_persistence_flag" );
readTokenValueAndValidate(seiColourRemappingInfo->m_colourRemapVideoSignalInfoPresentFlag, failed, fic, "colour_remap_video_signal_info_present_flag");
if( seiColourRemappingInfo->m_colourRemapVideoSignalInfoPresentFlag )
{
readTokenValueAndValidate(seiColourRemappingInfo->m_colourRemapFullRangeFlag, failed, fic, "colour_remap_full_range_flag" );
readTokenValueAndValidate(seiColourRemappingInfo->m_colourRemapPrimaries, failed, fic, "colour_remap_primaries", int(0), int(255) );
readTokenValueAndValidate(seiColourRemappingInfo->m_colourRemapTransferFunction, failed, fic, "colour_remap_transfer_function", int(0), int(255) );
readTokenValueAndValidate(seiColourRemappingInfo->m_colourRemapMatrixCoefficients, failed, fic, "colour_remap_matrix_coefficients", int(0), int(255) );
}
readTokenValueAndValidate(seiColourRemappingInfo->m_colourRemapInputBitDepth, failed, fic, "colour_remap_input_bit_depth", int(8), int(16) );
readTokenValueAndValidate(seiColourRemappingInfo->m_colourRemapBitDepth, failed, fic, "colour_remap_bit_depth", int(8), int(16) );
const int maximumInputValue = (1 << (((seiColourRemappingInfo->m_colourRemapInputBitDepth + 7) >> 3) << 3)) - 1;
const int maximumRemappedValue = (1 << (((seiColourRemappingInfo->m_colourRemapBitDepth + 7) >> 3) << 3)) - 1;
for( int c=0 ; c<3 ; c++ )
{
readTokenValueAndValidate(seiColourRemappingInfo->m_preLutNumValMinus1[c], failed, fic, "pre_lut_num_val_minus1[c]", int(0), int(32) );
if( seiColourRemappingInfo->m_preLutNumValMinus1[c]>0 )
{
seiColourRemappingInfo->m_preLut[c].resize(seiColourRemappingInfo->m_preLutNumValMinus1[c]+1);
for( int i=0 ; i<=seiColourRemappingInfo->m_preLutNumValMinus1[c] ; i++ )
{
readTokenValueAndValidate(seiColourRemappingInfo->m_preLut[c][i].codedValue, failed, fic, "pre_lut_coded_value[c][i]", int(0), maximumInputValue );
readTokenValueAndValidate(seiColourRemappingInfo->m_preLut[c][i].targetValue, failed, fic, "pre_lut_target_value[c][i]", int(0), maximumRemappedValue );
}
}
}
readTokenValueAndValidate(seiColourRemappingInfo->m_colourRemapMatrixPresentFlag, failed, fic, "colour_remap_matrix_present_flag" );
if( seiColourRemappingInfo->m_colourRemapMatrixPresentFlag )
{
readTokenValueAndValidate(seiColourRemappingInfo->m_log2MatrixDenom, failed, fic, "log2_matrix_denom", int(0), int(15) );
for( int c=0 ; c<3 ; c++ )
{
for( int i=0 ; i<3 ; i++ )
{
readTokenValueAndValidate(seiColourRemappingInfo->m_colourRemapCoeffs[c][i], failed, fic, "colour_remap_coeffs[c][i]", -32768, 32767 );
}
}
}
for( int c=0 ; c<3 ; c++ )
{
readTokenValueAndValidate(seiColourRemappingInfo->m_postLutNumValMinus1[c], failed, fic, "post_lut_num_val_minus1[c]", int(0), int(32) );
if( seiColourRemappingInfo->m_postLutNumValMinus1[c]>0 )
{
seiColourRemappingInfo->m_postLut[c].resize(seiColourRemappingInfo->m_postLutNumValMinus1[c]+1);
for( int i=0 ; i<=seiColourRemappingInfo->m_postLutNumValMinus1[c] ; i++ )
{
readTokenValueAndValidate(seiColourRemappingInfo->m_postLut[c][i].codedValue, failed, fic, "post_lut_coded_value[c][i]", int(0), maximumRemappedValue );
readTokenValueAndValidate(seiColourRemappingInfo->m_postLut[c][i].targetValue, failed, fic, "post_lut_target_value[c][i]", int(0), maximumRemappedValue );
}
}
}
}
if( failed )
{
EXIT( "Error while reading Colour Remapping Information SEI parameters file '" << colourRemapSEIFileWithPoc << "'" );
}
}
return true;
}
void SEIEncoder::initSEIChromaResamplingFilterHint(SEIChromaResamplingFilterHint *seiChromaResamplingFilterHint, int iHorFilterIndex, int iVerFilterIndex)
{
CHECK(!(m_isInitialized), "Unspecified error");
CHECK(!(seiChromaResamplingFilterHint!=NULL), "Unspecified error");
seiChromaResamplingFilterHint->m_verChromaFilterIdc = iVerFilterIndex;
seiChromaResamplingFilterHint->m_horChromaFilterIdc = iHorFilterIndex;
seiChromaResamplingFilterHint->m_verFilteringFieldProcessingFlag = 1;
seiChromaResamplingFilterHint->m_targetFormatIdc = 3;
seiChromaResamplingFilterHint->m_perfectReconstructionFlag = false;
// this creates some example filter values, if explicit filter definition is selected
if (seiChromaResamplingFilterHint->m_verChromaFilterIdc == 1)
{
const int numVerticalFilters = 3;
const int verTapLengthMinus1[] = {5,3,3};
seiChromaResamplingFilterHint->m_verFilterCoeff.resize(numVerticalFilters);
for(int i = 0; i < numVerticalFilters; i ++)
{
seiChromaResamplingFilterHint->m_verFilterCoeff[i].resize(verTapLengthMinus1[i]+1);
}
// Note: C++11 -> seiChromaResamplingFilterHint->m_verFilterCoeff[0] = {-3,13,31,23,3,-3};
seiChromaResamplingFilterHint->m_verFilterCoeff[0][0] = -3;
seiChromaResamplingFilterHint->m_verFilterCoeff[0][1] = 13;
seiChromaResamplingFilterHint->m_verFilterCoeff[0][2] = 31;
seiChromaResamplingFilterHint->m_verFilterCoeff[0][3] = 23;
seiChromaResamplingFilterHint->m_verFilterCoeff[0][4] = 3;
seiChromaResamplingFilterHint->m_verFilterCoeff[0][5] = -3;
seiChromaResamplingFilterHint->m_verFilterCoeff[1][0] = -1;
seiChromaResamplingFilterHint->m_verFilterCoeff[1][1] = 25;
seiChromaResamplingFilterHint->m_verFilterCoeff[1][2] = 247;
seiChromaResamplingFilterHint->m_verFilterCoeff[1][3] = -15;
seiChromaResamplingFilterHint->m_verFilterCoeff[2][0] = -20;
seiChromaResamplingFilterHint->m_verFilterCoeff[2][1] = 186;
seiChromaResamplingFilterHint->m_verFilterCoeff[2][2] = 100;
seiChromaResamplingFilterHint->m_verFilterCoeff[2][3] = -10;
}
else
{
seiChromaResamplingFilterHint->m_verFilterCoeff.resize(0);
}
if (seiChromaResamplingFilterHint->m_horChromaFilterIdc == 1)
{
int const numHorizontalFilters = 1;
const int horTapLengthMinus1[] = {3};
seiChromaResamplingFilterHint->m_horFilterCoeff.resize(numHorizontalFilters);
for(int i = 0; i < numHorizontalFilters; i ++)
{
seiChromaResamplingFilterHint->m_horFilterCoeff[i].resize(horTapLengthMinus1[i]+1);
}
seiChromaResamplingFilterHint->m_horFilterCoeff[0][0] = 1;
seiChromaResamplingFilterHint->m_horFilterCoeff[0][1] = 6;
seiChromaResamplingFilterHint->m_horFilterCoeff[0][2] = 1;
}
else
{
seiChromaResamplingFilterHint->m_horFilterCoeff.resize(0);
}
}
void SEIEncoder::initSEITimeCode(SEITimeCode *seiTimeCode)
{
CHECK(!(m_isInitialized), "Unspecified error");
CHECK(!(seiTimeCode!=NULL), "Unspecified error");
// Set data as per command line options
seiTimeCode->numClockTs = m_pcCfg->getNumberOfTimesets();
for(int i = 0; i < seiTimeCode->numClockTs; i++)
{
seiTimeCode->timeSetArray[i] = m_pcCfg->getTimeSet(i);
}
}
#if U0033_ALTERNATIVE_TRANSFER_CHARACTERISTICS_SEI
void SEIEncoder::initSEIAlternativeTransferCharacteristics(SEIAlternativeTransferCharacteristics *seiAltTransCharacteristics)
{
CHECK(!(m_isInitialized), "Unspecified error");
CHECK(!(seiAltTransCharacteristics!=NULL), "Unspecified error");
// Set SEI message parameters read from command line options
seiAltTransCharacteristics->m_preferredTransferCharacteristics = m_pcCfg->getSEIPreferredTransferCharacteristics();
}
#endif
void SEIEncoder::initSEIGreenMetadataInfo(SEIGreenMetadataInfo *seiGreenMetadataInfo, uint32_t u)
{
CHECK(!(m_isInitialized), "Unspecified error");
CHECK(!(seiGreenMetadataInfo!=NULL), "Unspecified error");
seiGreenMetadataInfo->m_greenMetadataType = m_pcCfg->getSEIGreenMetadataType();
seiGreenMetadataInfo->m_xsdMetricType = m_pcCfg->getSEIXSDMetricType();
seiGreenMetadataInfo->m_xsdMetricValue = u;
}
//! \}