[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