[x265] [PATCH] SEI: Insert buffering period and picture timing SEI messages
Steve Borho
steve at borho.org
Tue Jun 3 17:31:05 CEST 2014
On Tue, Jun 3, 2014 at 8:26 AM, <kavitha at multicorewareinc.com> wrote:
> # HG changeset patch
> # User Kavitha Sampath <kavitha at multicorewareinc.com>
> # Date 1401798795 -19800
> # Tue Jun 03 18:03:15 2014 +0530
> # Node ID f9f553c8bd6aa17a3bb3a5025b99e5ccd748f8e7
> # Parent d78f38b707babf597d55859f620911410a25b19d
> SEI: Insert buffering period and picture timing SEI messages
>
> The buffering period SEI message is inserted for every key frame and the
> picture timing SEI is inserted for every frame. The commit also computes the
> HRD parameters as well as HRD Timing parameters that are calculated using the
> delay components(cpb removal delay and dpb output delay) carried in these
> SEI messages. HRD parameters can be signalled by enabling --hrd.
queued for default, with some follow-on improvements.
m_decodingUnitInfoSEIEnabled and m_sps.setHrdParameters() needs some
further attention. If/when is this SEI necessary, and is that the
right bitrate we are using there (should it be the VBV maxrate)?
> diff -r d78f38b707ba -r f9f553c8bd6a doc/reST/cli.rst
> --- a/doc/reST/cli.rst Tue Jun 03 16:15:32 2014 +0530
> +++ b/doc/reST/cli.rst Tue Jun 03 18:03:15 2014 +0530
> @@ -858,6 +858,13 @@
> to keep the stream headers for you and you want keyframes to be
> random access points. Default disabled
>
> +.. option:: --hrd, --no-hrd
> +
> + Enable the signalling of HRD parameters to the decoder. The HRD
> + parameters are carried by the Buffering Period SEI messages and
> + Picture Timing SEI messages providing timing information to the
> + decoder. Default disabled
> +
> .. option:: --aud, --no-aud
>
> Emit an access unit delimiter NAL at the start of each slice access
> diff -r d78f38b707ba -r f9f553c8bd6a source/CMakeLists.txt
> --- a/source/CMakeLists.txt Tue Jun 03 16:15:32 2014 +0530
> +++ b/source/CMakeLists.txt Tue Jun 03 18:03:15 2014 +0530
> @@ -19,7 +19,7 @@
> include(CheckCXXCompilerFlag)
>
> # X265_BUILD must be incremented each time the public API is changed
> -set(X265_BUILD 21)
> +set(X265_BUILD 22)
> configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
> "${PROJECT_BINARY_DIR}/x265.def")
> configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
> diff -r d78f38b707ba -r f9f553c8bd6a source/Lib/TLibCommon/SEI.h
> --- a/source/Lib/TLibCommon/SEI.h Tue Jun 03 16:15:32 2014 +0530
> +++ b/source/Lib/TLibCommon/SEI.h Tue Jun 03 18:03:15 2014 +0530
> @@ -185,14 +185,7 @@
>
> PayloadType payloadType() const { return PICTURE_TIMING; }
>
> - SEIPictureTiming()
> - : m_picStruct(0)
> - , m_sourceScanType(0)
> - , m_duplicateFlag(false)
> - , m_picDpbOutputDuDelay(0)
> - , m_numNalusInDuMinus1(NULL)
> - , m_duCpbRemovalDelayMinus1(NULL)
> - {}
> + SEIPictureTiming() {}
>
> virtual ~SEIPictureTiming()
> {
> diff -r d78f38b707ba -r f9f553c8bd6a source/Lib/TLibCommon/TComPic.h
> --- a/source/Lib/TLibCommon/TComPic.h Tue Jun 03 16:15:32 2014 +0530
> +++ b/source/Lib/TLibCommon/TComPic.h Tue Jun 03 18:03:15 2014 +0530
> @@ -45,6 +45,7 @@
> #include "lowres.h"
> #include "threading.h"
> #include "md5.h"
> +#include "SEI.h"
>
> namespace x265 {
> // private namespace
> @@ -120,6 +121,8 @@
> double m_avgQpAq; // avg QP as decided by AQ in addition to ratecontrol
> double m_rateFactor; // calculated based on the Frame QP
> int32_t m_forceqp; // Force to use the qp specified in qp file
> + SEIPictureTiming m_sei;
> + HRDTiming m_hrdTiming;
>
> TComPic();
> virtual ~TComPic();
> diff -r d78f38b707ba -r f9f553c8bd6a source/Lib/TLibCommon/TComSlice.h
> --- a/source/Lib/TLibCommon/TComSlice.h Tue Jun 03 16:15:32 2014 +0530
> +++ b/source/Lib/TLibCommon/TComSlice.h Tue Jun 03 18:03:15 2014 +0530
> @@ -460,6 +460,14 @@
> void setNumTicksPocDiffOneMinus1(int x) { m_numTicksPocDiffOneMinus1 = x; }
> };
>
> +struct HRDTiming
> +{
> + double cpbInitialAT;
> + double cpbFinalAT;
> + double dpbOutputTime;
> + double cpbRemovalTime;
> +};
> +
> class TComVPS
> {
> private:
> diff -r d78f38b707ba -r f9f553c8bd6a source/common/param.cpp
> --- a/source/common/param.cpp Tue Jun 03 16:15:32 2014 +0530
> +++ b/source/common/param.cpp Tue Jun 03 18:03:15 2014 +0530
> @@ -623,6 +623,7 @@
> OPT("hash") p->decodedPictureHashSEI = atoi(value);
> OPT("aud") p->bEnableAccessUnitDelimiters = atobool(value);
> OPT("b-pyramid") p->bBPyramid = atobool(value);
> + OPT("hrd") p->bEmitHRDSEI = atobool(value);
> OPT("aq-mode") p->rc.aqMode = atoi(value);
> OPT("aq-strength") p->rc.aqStrength = atof(value);
> OPT("vbv-maxrate") p->rc.vbvMaxBitrate = atoi(value);
> diff -r d78f38b707ba -r f9f553c8bd6a source/encoder/encoder.cpp
> --- a/source/encoder/encoder.cpp Tue Jun 03 16:15:32 2014 +0530
> +++ b/source/encoder/encoder.cpp Tue Jun 03 18:03:15 2014 +0530
> @@ -186,6 +186,7 @@
> }
> }
> }
> + m_rateControl->init(&m_frameEncoder[0].m_sps);
> m_lookahead->init();
> m_encodeStartTime = x265_mdate();
> m_totalFrameThreads = param->frameNumThreads;
> @@ -1123,8 +1124,8 @@
> vui->setFrameFieldInfoPresentFlag(!!param->interlaceMode);
> vui->setFieldSeqFlag(!!param->interlaceMode);
>
> - vui->setHrdParametersPresentFlag(false);
> - vui->getHrdParameters()->setNalHrdParametersPresentFlag(false);
> + vui->setHrdParametersPresentFlag(param->bEmitHRDSEI);
> + vui->getHrdParameters()->setNalHrdParametersPresentFlag(param->bEmitHRDSEI);
> vui->getHrdParameters()->setSubPicHrdParamsPresentFlag(false);
>
> vui->getTimingInfo()->setTimingInfoPresentFlag(true);
> @@ -1426,12 +1427,10 @@
>
> m_nonPackedConstraintFlag = false;
> m_frameOnlyConstraintFlag = false;
> - m_bufferingPeriodSEIEnabled = 0;
> m_displayOrientationSEIAngle = 0;
> m_gradualDecodingRefreshInfoEnabled = 0;
> m_decodingUnitInfoSEIEnabled = 0;
> m_useScalingListId = 0;
> - m_activeParameterSetsSEIEnabled = 0;
> m_minSpatialSegmentationIdc = 0;
> m_neutralChromaIndicationFlag = false;
> m_pocProportionalToTimingFlag = false;
> diff -r d78f38b707ba -r f9f553c8bd6a source/encoder/encoder.h
> --- a/source/encoder/encoder.h Tue Jun 03 16:15:32 2014 +0530
> +++ b/source/encoder/encoder.h Tue Jun 03 18:03:15 2014 +0530
> @@ -82,7 +82,6 @@
> int64_t m_firstPts;
> int64_t m_bframeDelayTime;
> int64_t m_prevReorderedPts[2];
> - int64_t m_encodedFrameNum;
>
> ThreadPool* m_threadPool;
> Lookahead* m_lookahead;
> @@ -157,7 +156,8 @@
> bool m_bPCMFilterDisableFlag;
> bool m_loopFilterAcrossTilesEnabledFlag;
>
> - int m_bufferingPeriodSEIEnabled;
> + int64_t m_encodedFrameNum;
> + int m_lastBPSEI;
> int m_displayOrientationSEIAngle;
> int m_gradualDecodingRefreshInfoEnabled;
> int m_decodingUnitInfoSEIEnabled;
> @@ -168,7 +168,6 @@
>
> bool m_TransquantBypassEnableFlag; ///< transquant_bypass_enable_flag setting in PPS.
> bool m_CUTransquantBypassFlagValue; ///< if transquant_bypass_enable_flag, the fixed value to use for the per-CU cu_transquant_bypass_flag.
> - int m_activeParameterSetsSEIEnabled; ///< enable active parameter set SEI message
>
> bool m_neutralChromaIndicationFlag;
> bool m_pocProportionalToTimingFlag;
> diff -r d78f38b707ba -r f9f553c8bd6a source/encoder/frameencoder.cpp
> --- a/source/encoder/frameencoder.cpp Tue Jun 03 16:15:32 2014 +0530
> +++ b/source/encoder/frameencoder.cpp Tue Jun 03 18:03:15 2014 +0530
> @@ -143,11 +143,17 @@
> {
> m_sps.setHrdParameters(m_cfg->param->fpsNum, m_cfg->param->fpsDenom, 0, m_cfg->param->rc.bitrate, m_cfg->param->bframes > 0);
> }
> - if (m_cfg->m_bufferingPeriodSEIEnabled || m_cfg->m_decodingUnitInfoSEIEnabled)
> + if (m_cfg->param->bEmitHRDSEI || m_cfg->m_decodingUnitInfoSEIEnabled)
> {
> m_sps.getVuiParameters()->setHrdParametersPresentFlag(true);
> }
>
> + // initialize HRD parameters of SPS
> + if (m_cfg->param->bEmitHRDSEI)
> + {
> + top->m_rateControl->initHRD(&m_sps);
> + }
> +
> m_sps.setTMVPFlagsPresent(true);
>
> // set default slice level flag to the same as SPS level flag
> @@ -266,7 +272,7 @@
> nalunits[count]->init(nalu);
> count++;
>
> - if (m_cfg->m_activeParameterSetsSEIEnabled)
> + if (m_cfg->param->bEmitHRDSEI)
> {
> SEIActiveParameterSets sei;
> sei.activeVPSId = m_top->m_vps.getVPSId();
> @@ -275,6 +281,7 @@
> sei.numSpsIdsMinus1 = 0;
> sei.activeSeqParamSetId = m_sps.getSPSId();
>
> + nalu.resetToType(NAL_UNIT_PREFIX_SEI);
> entropyCoder->setBitstream(&nalu.m_bitstream);
> m_seiWriter.writeSEImessage(nalu.m_bitstream, sei, &m_sps);
> writeRBSPTrailingBits(nalu.m_bitstream);
> @@ -404,6 +411,7 @@
> TEncEntropy* entropyCoder = getEntropyCoder(0);
> TComSlice* slice = m_pic->getSlice();
> int chFmt = slice->getSPS()->getChromaFormatIdc();
> + int totalCoded = (int)m_top->m_encodedFrameNum - 1;
>
> m_nalCount = 0;
> entropyCoder->setEntropyCoder(&m_sbacCoder, NULL);
> @@ -526,6 +534,34 @@
>
> if (slice->getPic()->m_lowres.bKeyframe)
> {
> + if (m_cfg->param->bEmitHRDSEI)
> + {
> + OutputNALUnit nalu(NAL_UNIT_PREFIX_SEI);
> + SEIBufferingPeriod* sei_buffering_period = &m_top->m_rateControl->sei;
> + sei_buffering_period->m_bpSeqParameterSetId = m_sps.getSPSId();
> + sei_buffering_period->m_rapCpbParamsPresentFlag = 0;
> +
> + // for the concatenation, it can be set to one during splicing.
> + sei_buffering_period->m_concatenationFlag = 0;
> +
> + // since the temporal layer HRD is not ready, we assumed it is fixed
> + sei_buffering_period->m_auCpbRemovalDelayDelta = 1;
> + sei_buffering_period->m_cpbDelayOffset = 0;
> + sei_buffering_period->m_dpbDelayOffset = 0;
> +
> + // hrdFullness() calculates the initial CPB removal delay and offset
> + m_top->m_rateControl->hrdFullness(sei_buffering_period);
> + m_seiWriter.writeSEImessage(nalu.m_bitstream, *sei_buffering_period, &m_sps);
> + writeRBSPTrailingBits(nalu.m_bitstream);
> + m_nalList[m_nalCount] = X265_MALLOC(NALUnitEBSP, 1);
> + if (m_nalList[m_nalCount])
> + {
> + m_nalList[m_nalCount]->init(nalu);
> + m_nalCount++;
> + }
> +
> + m_top->m_lastBPSEI = totalCoded;
> + }
> if (m_cfg->m_gradualDecodingRefreshInfoEnabled && !slice->getRapPicFlag())
> {
> // Gradual decoding refresh SEI
> @@ -568,24 +604,38 @@
> }
> }
>
> - if (!!m_cfg->param->interlaceMode)
> + if (m_cfg->param->bEmitHRDSEI || !!m_cfg->param->interlaceMode)
> {
> + // Picture Timing SEI
> OutputNALUnit nalu(NAL_UNIT_PREFIX_SEI);
>
> - SEIPictureTiming sei;
> + SEIPictureTiming *sei = &m_pic->m_sei;
> + int poc = slice->getPOC();
> + int cpbDelayLength = slice->getSPS()->getVuiParameters()->getHrdParameters()->getCpbRemovalDelayLengthMinus1() + 1;
> if (m_cfg->param->interlaceMode == 2)
> {
> - sei.m_picStruct = (slice->getPOC() & 1) ? 1 /* top */ : 2 /* bottom */;
> + sei->m_picStruct = (poc & 1) ? 1 /* top */ : 2 /* bottom */;
> + }
> + else if (m_cfg->param->interlaceMode == 1)
> + {
> + sei->m_picStruct = (poc & 1) ? 2 /* bottom */ : 1 /* top */;
> }
> else
> {
> - sei.m_picStruct = (slice->getPOC() & 1) ? 2 /* bottom */ : 1 /* top */;
> + sei->m_picStruct = 0;
> }
> - sei.m_sourceScanType = 0;
> - sei.m_duplicateFlag = 0;
> + sei->m_sourceScanType = 0;
> + sei->m_duplicateFlag = false;
> + sei->m_picDpbOutputDuDelay = 0;
> + sei->m_numNalusInDuMinus1 = NULL;
> + sei->m_duCpbRemovalDelayMinus1 = NULL;
>
> + // The m_aucpbremoval delay specifies how many clock ticks the access unit associated with the picture timing
> + // SEI message has to wait after removal of the access unit with the most recent buffering period SEI message
> + sei->m_auCpbRemovalDelay = X265_MIN(X265_MAX(1, totalCoded - m_top->m_lastBPSEI), (1 << cpbDelayLength));
> + sei->m_picDpbOutputDelay = slice->getSPS()->getNumReorderPics(0) + poc - totalCoded;
> entropyCoder->setBitstream(&nalu.m_bitstream);
> - m_seiWriter.writeSEImessage(nalu.m_bitstream, sei, &m_sps);
> + m_seiWriter.writeSEImessage(nalu.m_bitstream, *sei, &m_sps);
> writeRBSPTrailingBits(nalu.m_bitstream);
> m_nalList[m_nalCount] = X265_MALLOC(NALUnitEBSP, 1);
> if (m_nalList[m_nalCount])
> diff -r d78f38b707ba -r f9f553c8bd6a source/encoder/ratecontrol.cpp
> --- a/source/encoder/ratecontrol.cpp Tue Jun 03 16:15:32 2014 +0530
> +++ b/source/encoder/ratecontrol.cpp Tue Jun 03 18:03:15 2014 +0530
> @@ -27,6 +27,10 @@
> #include "encoder.h"
> #include "slicetype.h"
> #include "ratecontrol.h"
> +#include "TLibCommon/SEI.h"
> +
> +#define BR_SHIFT 6
> +#define CPB_SHIFT 4
>
> using namespace x265;
>
> @@ -34,6 +38,50 @@
> const double RateControl::amortizeFraction = 0.85;
> const int RateControl::amortizeFrames = 75;
>
> +namespace {
> +
> +inline int calcScale(uint32_t x)
> +{
> + static uint8_t lut[16] = {4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0};
> + int y, z = (((x & 0xffff) - 1) >> 27) & 16;
> + x >>= z;
> + z += y = (((x & 0xff) - 1) >> 28) & 8;
> + x >>= y;
> + z += y = (((x & 0xf) - 1) >> 29) & 4;
> + x >>= y;
> + return z + lut[x&0xf];
> +}
> +
> +inline int calcLength(uint32_t x)
> +{
> + static uint8_t lut[16] = {4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
> + int y, z = (((x >> 16) - 1) >> 27) & 16;
> + x >>= z ^ 16;
> + z += y = ((x - 0x100) >> 28) & 8;
> + x >>= y ^ 8;
> + z += y = ((x - 0x10) >> 29) & 4;
> + x >>= y ^ 4;
> + return z + lut[x];
> +}
> +
> +inline void reduceFraction(int* n, int* d)
> +{
> + int a = *n;
> + int b = *d;
> + int c;
> + if (!a || !b)
> + return;
> + c = a % b;
> + while (c)
> + {
> + a = b;
> + b = c;
> + c = a % b;
> + }
> + *n /= b;
> + *d /= b;
> +}
> +} // end anonymous namespace
> /* Compute variance to derive AC energy of each block */
> static inline uint32_t acEnergyVar(TComPic *pic, uint64_t sum_ssd, int shift, int i)
> {
> @@ -287,40 +335,11 @@
> param->rc.vbvMaxBitrate = 0;
> }
>
> - isVbv = param->rc.vbvMaxBitrate > 0 && param->rc.vbvBufferSize > 0;
> - double fps = (double)param->fpsNum / param->fpsDenom;
> - if (isVbv)
> - {
> - /* We don't support changing the ABR bitrate right now,
> - so if the stream starts as CBR, keep it CBR. */
> - if (param->rc.vbvBufferSize < (int)(param->rc.vbvMaxBitrate / fps))
> - {
> - param->rc.vbvBufferSize = (int)(param->rc.vbvMaxBitrate / fps);
> - x265_log(param, X265_LOG_WARNING, "VBV buffer size cannot be smaller than one frame, using %d kbit\n",
> - param->rc.vbvBufferSize);
> - }
> - int vbvBufferSize = param->rc.vbvBufferSize * 1000;
> - int vbvMaxBitrate = param->rc.vbvMaxBitrate * 1000;
> -
> - bufferRate = vbvMaxBitrate / fps;
> - vbvMaxRate = vbvMaxBitrate;
> - bufferSize = vbvBufferSize;
> - singleFrameVbv = bufferRate * 1.1 > bufferSize;
> -
> - if (param->rc.vbvBufferInit > 1.)
> - param->rc.vbvBufferInit = Clip3(0.0, 1.0, param->rc.vbvBufferInit / param->rc.vbvBufferSize);
> - param->rc.vbvBufferInit = Clip3(0.0, 1.0, X265_MAX(param->rc.vbvBufferInit, bufferRate / bufferSize));
> - bufferFillFinal = bufferSize * param->rc.vbvBufferInit;
> - isCbr = param->rc.rateControlMode == X265_RC_ABR
> - && param->rc.vbvMaxBitrate <= param->rc.bitrate;
> - }
> -
> bframes = param->bframes;
> bframeBits = 0;
> leadingNoBSatd = 0;
> ipOffset = 6.0 * X265_LOG2(param->rc.ipFactor);
> pbOffset = 6.0 * X265_LOG2(param->rc.pbFactor);
> - init();
>
> /* Adjust the first frame in order to stabilize the quality level compared to the rest */
> #define ABR_INIT_QP_MIN (24)
> @@ -347,8 +366,41 @@
> lstep = pow(2, param->rc.qpStep / 6.0);
> }
>
> -void RateControl::init()
> +void RateControl::init(TComSPS *sps)
> {
> + isVbv = param->rc.vbvMaxBitrate > 0 && param->rc.vbvBufferSize > 0;
> + double fps = (double)param->fpsNum / param->fpsDenom;
> + if (isVbv)
> + {
> + /* We don't support changing the ABR bitrate right now,
> + so if the stream starts as CBR, keep it CBR. */
> + if (param->rc.vbvBufferSize < (int)(param->rc.vbvMaxBitrate / fps))
> + {
> + param->rc.vbvBufferSize = (int)(param->rc.vbvMaxBitrate / fps);
> + x265_log(param, X265_LOG_WARNING, "VBV buffer size cannot be smaller than one frame, using %d kbit\n",
> + param->rc.vbvBufferSize);
> + }
> + int vbvBufferSize = param->rc.vbvBufferSize * 1000;
> + int vbvMaxBitrate = param->rc.vbvMaxBitrate * 1000;
> +
> + TComHRD* hrd = sps->getVuiParameters()->getHrdParameters();
> + if (hrd->getNalHrdParametersPresentFlag())
> + {
> + vbvBufferSize = (hrd->getCpbSizeValueMinus1(0, 0, 0) + 1) << (hrd->getCpbSizeScale() + CPB_SHIFT);
> + vbvMaxBitrate = (hrd->getBitRateValueMinus1(0, 0, 0) + 1) << (hrd->getBitRateScale() + BR_SHIFT);
> + }
> + bufferRate = vbvMaxBitrate / fps;
> + vbvMaxRate = vbvMaxBitrate;
> + bufferSize = vbvBufferSize;
> + singleFrameVbv = bufferRate * 1.1 > bufferSize;
> +
> + if (param->rc.vbvBufferInit > 1.)
> + param->rc.vbvBufferInit = Clip3(0.0, 1.0, param->rc.vbvBufferInit / param->rc.vbvBufferSize);
> + param->rc.vbvBufferInit = Clip3(0.0, 1.0, X265_MAX(param->rc.vbvBufferInit, bufferRate / bufferSize));
> + bufferFillFinal = bufferSize * param->rc.vbvBufferInit;
> + isCbr = param->rc.rateControlMode == X265_RC_ABR
> + && param->rc.vbvMaxBitrate <= param->rc.bitrate;
> + }
> totalBits = 0;
> framesDone = 0;
> double tuneCplxFactor = 1;
> @@ -373,6 +425,45 @@
> predBfromP = pred[0];
> }
>
> +void RateControl::initHRD(TComSPS *sps)
> +{
> + int vbvBufferSize = param->rc.vbvBufferSize * 1000;
> + int vbvMaxBitrate = param->rc.vbvMaxBitrate * 1000;
> +
> + // Init HRD
> + TComHRD* hrd = sps->getVuiParameters()->getHrdParameters();
> + hrd->setCpbCntMinus1(0, 0);
> + hrd->setLowDelayHrdFlag(0, false);
> + hrd->setFixedPicRateFlag(0, 1);
> + hrd->setPicDurationInTcMinus1(0, 0);
> +
> + // normalize HRD size and rate to the value / scale notation
> + hrd->setBitRateScale(Clip3(0, 15, calcScale(vbvMaxBitrate) - BR_SHIFT));
> + hrd->setBitRateValueMinus1(0, 0, 0, (vbvMaxBitrate >> (hrd->getBitRateScale() + BR_SHIFT)) - 1);
> +
> + hrd->setCpbSizeScale(Clip3(0, 15, calcScale(vbvBufferSize) - CPB_SHIFT));
> + hrd->setCpbSizeValueMinus1(0, 0, 0, (vbvBufferSize >> (hrd->getCpbSizeScale() + CPB_SHIFT)) - 1);
> + int bitRateUnscale = (hrd->getBitRateValueMinus1(0, 0, 0) + 1) << (hrd->getBitRateScale() + BR_SHIFT);
> + int cpbSizeUnscale = (hrd->getCpbSizeValueMinus1(0, 0, 0) + 1) << (hrd->getCpbSizeScale() + CPB_SHIFT);
> +
> + // arbitrary
> + #define MAX_DURATION 0.5
> +
> + TimingInfo *time = sps->getVuiParameters()->getTimingInfo();
> + int maxCpbOutputDelay = (int)(X265_MIN(param->keyframeMax * MAX_DURATION * time->getTimeScale() / time->getNumUnitsInTick(), INT_MAX));
> + int maxDpbOutputDelay = (int)(sps->getMaxDecPicBuffering(0) * MAX_DURATION * time->getTimeScale() / time->getNumUnitsInTick());
> + int maxDelay = (int)(90000.0 * cpbSizeUnscale / bitRateUnscale + 0.5);
> +
> + hrd->setInitialCpbRemovalDelayLengthMinus1(2 + Clip3(4, 22, 32 - calcLength(maxDelay)) - 1);
> + hrd->setCpbRemovalDelayLengthMinus1(Clip3(4, 31, 32 - calcLength(maxCpbOutputDelay)) - 1);
> + hrd->setDpbOutputDelayLengthMinus1(Clip3(4, 31, 32 - calcLength(maxDpbOutputDelay)) - 1);
> +
> + #undef MAX_DURATION
> +
> + vbvBufferSize = cpbSizeUnscale;
> + vbvMaxBitrate = bitRateUnscale;
> +}
> +
> void RateControl::rateControlStart(TComPic* pic, Lookahead *l, RateControlEntry* rce, Encoder* enc)
> {
> curSlice = pic->getSlice();
> @@ -627,7 +718,7 @@
> double underflow = 1.0 + (totalBits - wantedBitsWindow) / abrBuffer;
> if (underflow < 0.9 && !isFrameDone)
> {
> - init();
> + init(NULL);
> shortTermCplxSum = rce->lastSatd / (CLIP_DURATION(frameDuration) / BASE_FRAME_DURATION);
> shortTermCplxCount = 1;
> isAbrReset = true;
> @@ -642,6 +733,26 @@
> }
> }
>
> +void RateControl::hrdFullness(SEIBufferingPeriod *seiBP)
> +{
> + TComVUI* vui = curSlice->getSPS()->getVuiParameters();
> + TComHRD* hrd = vui->getHrdParameters();
> + int num = 90000;
> + int denom = (hrd->getBitRateValueMinus1(0, 0, 0) + 1) << (hrd->getBitRateScale() + BR_SHIFT);
> + reduceFraction(&num, &denom);
> + int64_t cpbState = (int64_t)bufferFillFinal;
> + int64_t cpbSize = (int64_t)((hrd->getCpbSizeValueMinus1(0, 0, 0) + 1) << (hrd->getCpbSizeScale() + CPB_SHIFT));
> +
> + if(cpbState < 0 || cpbState > cpbSize)
> + {
> + x265_log(param, X265_LOG_WARNING, "CPB %s: %.0lf bits in a %.0lf-bit buffer\n",
> + cpbState < 0 ? "underflow" : "overflow", (float)cpbState/denom, (float)cpbSize/denom);
> + }
> +
> + seiBP->m_initialCpbRemovalDelay[0][0] = (uint32_t)(num * cpbState + denom) / denom;
> + seiBP->m_initialCpbRemovalDelayOffset[0][0] = (uint32_t)(num * cpbSize + denom) / denom - seiBP->m_initialCpbRemovalDelay[0][0];
> +}
> +
> void RateControl::updateVbvPlan(Encoder* enc)
> {
> bufferFill = bufferFillFinal;
> @@ -1133,6 +1244,37 @@
> }
> }
> updateVbv(bits, rce);
> +
> + if (param->bEmitHRDSEI)
> + {
> + TComVUI *vui = pic->getSlice()->getSPS()->getVuiParameters();
> + TComHRD *hrd = vui->getHrdParameters();
> + TimingInfo *time = vui->getTimingInfo();
> + if (pic->getSlice()->getPOC() == 0)
> + {
> + // access unit initialises the HRD
> + pic->m_hrdTiming.cpbInitialAT = 0;
> + pic->m_hrdTiming.cpbRemovalTime = nominalRemovalTime = (double)sei.m_initialCpbRemovalDelay[0][0] / 90000;
> + }
> + else
> + {
> + pic->m_hrdTiming.cpbRemovalTime = nominalRemovalTime + (double)pic->m_sei.m_auCpbRemovalDelay * time->getNumUnitsInTick() / time->getTimeScale();
> + double cpbEarliestAT = pic->m_hrdTiming.cpbRemovalTime - (double)sei.m_initialCpbRemovalDelay[0][0] / 90000;
> + if (!pic->m_lowres.bKeyframe)
> + {
> + cpbEarliestAT -= (double)sei.m_initialCpbRemovalDelayOffset[0][0] / 90000;
> + }
> +
> + if (hrd->getCbrFlag(0, 0, 0))
> + pic->m_hrdTiming.cpbInitialAT = prevCpbFinalAT;
> + else
> + pic->m_hrdTiming.cpbInitialAT = X265_MAX(prevCpbFinalAT, cpbEarliestAT);
> + }
> +
> + uint32_t cpbsizeUnscale = (hrd->getCpbSizeValueMinus1(0, 0, 0) + 1) << (hrd->getCpbSizeScale() + CPB_SHIFT);
> + pic->m_hrdTiming.cpbFinalAT = prevCpbFinalAT = pic->m_hrdTiming.cpbInitialAT + bits / cpbsizeUnscale;
> + pic->m_hrdTiming.dpbOutputTime = (double)pic->m_sei.m_picDpbOutputDelay * time->getNumUnitsInTick() / time->getTimeScale() + pic->m_hrdTiming.cpbRemovalTime;
> + }
> }
> rce->isActive = false;
> return 0;
> diff -r d78f38b707ba -r f9f553c8bd6a source/encoder/ratecontrol.h
> --- a/source/encoder/ratecontrol.h Tue Jun 03 16:15:32 2014 +0530
> +++ b/source/encoder/ratecontrol.h Tue Jun 03 18:03:15 2014 +0530
> @@ -26,14 +26,14 @@
> #ifndef X265_RATECONTROL_H
> #define X265_RATECONTROL_H
>
> -#include "TLibCommon/CommonDef.h"
> -
> namespace x265 {
> // encoder namespace
>
> struct Lookahead;
> class Encoder;
> class TComPic;
> +class TComSPS;
> +class SEIBufferingPeriod;
>
> #define BASE_FRAME_DURATION 0.04
>
> @@ -122,6 +122,12 @@
> double lastRceq;
> int framesDone; /* framesDone keeps track of # of frames passed through RateCotrol already */
> double qCompress;
> +
> + /* hrd stuff */
> + SEIBufferingPeriod sei;
> + double nominalRemovalTime;
> + double prevCpbFinalAT;
> +
> RateControl(Encoder * _cfg);
>
> // to be called for each frame to process RateControl and set QP
> @@ -130,6 +136,9 @@
> int rateControlEnd(TComPic* pic, int64_t bits, RateControlEntry* rce);
> int rowDiagonalVbvRateControl(TComPic* pic, uint32_t row, RateControlEntry* rce, double& qpVbv);
>
> + void hrdFullness(SEIBufferingPeriod* sei);
> + void init(TComSPS* sps);
> + void initHRD(TComSPS* sps);
> protected:
>
> static const double amortizeFraction;
> @@ -138,7 +147,6 @@
> int residualFrames;
> int residualCost;
>
> - void init();
> double getQScale(RateControlEntry *rce, double rateFactor);
> double rateEstimateQscale(TComPic* pic, RateControlEntry *rce); // main logic for calculating QP based on ABR
> void accumPQpUpdate();
> diff -r d78f38b707ba -r f9f553c8bd6a source/x265.cpp
> --- a/source/x265.cpp Tue Jun 03 16:15:32 2014 +0530
> +++ b/source/x265.cpp Tue Jun 03 18:03:15 2014 +0530
> @@ -163,6 +163,8 @@
> { "strong-intra-smoothing", no_argument, NULL, 0 },
> { "no-cutree", no_argument, NULL, 0 },
> { "cutree", no_argument, NULL, 0 },
> + { "no-hrd", no_argument, NULL, 0 },
> + { "hrd", no_argument, NULL, 0 },
> { "sar", required_argument, NULL, 0 },
> { "overscan", required_argument, NULL, 0 },
> { "videoformat", required_argument, NULL, 0 },
> @@ -392,6 +394,7 @@
> H0(" --[no-]cutree Enable cutree for Adaptive Quantization. Default %s\n", OPT(param->rc.cuTree));
> H0(" --cbqpoffs <integer> Chroma Cb QP Offset. Default %d\n", param->cbQpOffset);
> H0(" --crqpoffs <integer> Chroma Cr QP Offset. Default %d\n", param->crQpOffset);
> + H0(" --[no-]hrd Enable HRD parameters signalling. Default %s\n", OPT(param->bEmitHRDSEI));
> H0(" --rd <0..6> Level of RD in mode decision 0:least....6:full RDO. Default %d\n", param->rdLevel);
> H0(" --psy-rd <0..2.0> Strength of psycho-visual optimization. Requires slow preset or below. Default %f\n", param->psyRd);
> H0(" --[no-]signhide Hide sign bit of one coeff per TU (rdo). Default %s\n", OPT(param->bEnableSignHiding));
> diff -r d78f38b707ba -r f9f553c8bd6a source/x265.h
> --- a/source/x265.h Tue Jun 03 16:15:32 2014 +0530
> +++ b/source/x265.h Tue Jun 03 18:03:15 2014 +0530
> @@ -410,6 +410,10 @@
> * NAL at the start of every access unit. Default false */
> int bEnableAccessUnitDelimiters;
>
> + /* Enables the buffering period SEI and picture timing SEI to signal the HRD
> + * parameteres. Default is disabled */
> + int bEmitHRDSEI;
> +
> /*== Coding Unit (CU) definitions ==*/
>
> /* Maxiumum CU width and height in pixels. The size must be 64, 32, or 16.
> _______________________________________________
> x265-devel mailing list
> x265-devel at videolan.org
> https://mailman.videolan.org/listinfo/x265-devel
--
Steve Borho
More information about the x265-devel
mailing list