[x265] [PATCH] SEI: Insert buffering period and picture timing SEI messages
kavitha at multicorewareinc.com
kavitha at multicorewareinc.com
Tue Jun 3 15:26:43 CEST 2014
# 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.
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.
More information about the x265-devel
mailing list