[x265] [PATCH] API Support to enable VBV end feature

Yaswanth Sastry yaswanth.sastry at multicorewareinc.com
Wed Sep 18 07:33:04 UTC 2024


>From b9de94104762177e25ad233ea6f6c89854621cef Mon Sep 17 00:00:00 2001
From: yaswanthsastry <yaswanth.sastry at multicorewareinc.com>
Date: Mon, 9 Sep 2024 14:57:14 +0530
Subject: [PATCH] API Support to enable VBV end feature

Added support for enabling the VBV-end feature in x265 when the total frame
count is unknown, using the x265_configure_vbv_end API.
---
 source/CMakeLists.txt          |  2 +-
 source/common/frame.h          |  2 ++
 source/common/param.cpp        |  2 --
 source/encoder/api.cpp         | 11 ++++++++++-
 source/encoder/encoder.cpp     |  1 +
 source/encoder/ratecontrol.cpp | 22 +++++++++++++++-------
 source/encoder/ratecontrol.h   |  2 ++
 source/x265.h                  |  9 +++++++++
 8 files changed, 40 insertions(+), 11 deletions(-)

diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index 1f5b9ca3c..f9a7f69ff 100755
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -31,7 +31,7 @@ option(NATIVE_BUILD "Target the build CPU" OFF)
 option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF)
 mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)
 # X265_BUILD must be incremented each time the public API is changed
-set(X265_BUILD 212)
+set(X265_BUILD 213)
 configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
                "${PROJECT_BINARY_DIR}/x265.def")
 configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
diff --git a/source/common/frame.h b/source/common/frame.h
index 4fa90ef54..1f0a892b5 100644
--- a/source/common/frame.h
+++ b/source/common/frame.h
@@ -148,6 +148,8 @@ public:
     Frame*                 m_prevMCSTF;
     int*                   m_isSubSampled;

+    /*Vbv-End-Flag*/
+    int vbvEndFlag;
     /* aq-mode 4 : Gaussian, edge and theta frames for edge information */
     pixel*                 m_edgePic;
     pixel*                 m_gaussianPic;
diff --git a/source/common/param.cpp b/source/common/param.cpp
index aad31b515..7700e94cf 100755
--- a/source/common/param.cpp
+++ b/source/common/param.cpp
@@ -1819,8 +1819,6 @@ int x265_check_params(x265_param* param)
         "Valid final VBV buffer emptiness must be a fraction 0 - 1, or
size in kbits");
     CHECK(param->vbvEndFrameAdjust < 0,
         "Valid vbv-end-fr-adj must be a fraction 0 - 1");
-    CHECK(!param->totalFrames && param->vbvEndFrameAdjust,
-        "vbv-end-fr-adj cannot be enabled when total number of frames is
unknown");
     CHECK(param->minVbvFullness < 0 && param->minVbvFullness > 100,
         "min-vbv-fullness must be a fraction 0 - 100");
     CHECK(param->maxVbvFullness < 0 && param->maxVbvFullness > 100,
diff --git a/source/encoder/api.cpp b/source/encoder/api.cpp
index 96baf56c9..35c5a9be3 100644
--- a/source/encoder/api.cpp
+++ b/source/encoder/api.cpp
@@ -405,7 +405,14 @@ int x265_encoder_reconfig_zone(x265_encoder* enc,
x265_zone* zone_in)

     return 0;
 }
-
+void x265_configure_vbv_end(x265_encoder* enc, x265_picture* picture,
double totalstreamduration)
+{
+    Encoder* encoder = static_cast<Encoder*>(enc);
+    if ((totalstreamduration > 0) && (picture->poc) >
((encoder->m_param->vbvEndFrameAdjust)*(totalstreamduration)*((double)(encoder->m_param->fpsNum
/ encoder->m_param->fpsDenom))))
+    {
+         picture->vbvEndFlag = 1;
+    }
+}
 int x265_encoder_encode(x265_encoder *enc, x265_nal **pp_nal, uint32_t
*pi_nal, x265_picture *pic_in, x265_picture **pic_out)
 {
     if (!enc)
@@ -1000,6 +1007,7 @@ void x265_picture_init(x265_param *param,
x265_picture *pic)
     pic->rpu.payloadSize = 0;
     pic->rpu.payload = NULL;
     pic->picStruct = 0;
+    pic->vbvEndFlag = 0;

     if ((param->analysisSave || param->analysisLoad) ||
(param->bAnalysisType == AVC_INFO))
     {
@@ -1066,6 +1074,7 @@ static const x265_api libapi =
     &x265_encoder_reconfig,
     &x265_encoder_reconfig_zone,
     &x265_encoder_headers,
+    &x265_configure_vbv_end,
     &x265_encoder_encode,
     &x265_encoder_get_stats,
     &x265_encoder_log,
diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp
index 1a16f039d..76b3d3872 100644
--- a/source/encoder/encoder.cpp
+++ b/source/encoder/encoder.cpp
@@ -1713,6 +1713,7 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
             inFrame[layer]->m_poc = (!layer) ? (++m_pocLast) : m_pocLast;
             inFrame[layer]->m_userData = inputPic[0]->userData;
             inFrame[layer]->m_pts = inputPic[0]->pts;
+              inFrame[layer]->vbvEndFlag = inputPic[layer]->vbvEndFlag;

             if ((m_param->bEnableSceneCutAwareQp & BACKWARD) &&
m_param->rc.bStatRead)
             {
diff --git a/source/encoder/ratecontrol.cpp b/source/encoder/ratecontrol.cpp
index 25cb7318e..e023db12d 100644
--- a/source/encoder/ratecontrol.cpp
+++ b/source/encoder/ratecontrol.cpp
@@ -210,6 +210,7 @@ RateControl::RateControl(x265_param& p, Encoder *top)
     m_isFirstMiniGop = false;
     m_lastScenecut = -1;
     m_lastScenecutAwareIFrame = -1;
+    m_totalFrames = -1;
     if (m_param->rc.rateControlMode == X265_RC_CRF)
     {
         m_param->rc.qp = (int)m_param->rc.rfConstant;
@@ -1458,11 +1459,14 @@ int RateControl::rateControlStart(Frame* curFrame,
RateControlEntry* rce, Encode
         updateVbvPlan(enc);
         rce->bufferFill = m_bufferFill;
         rce->vbvEndAdj = false;
-        if (m_param->vbvBufferEnd && rce->encodeOrder >=
m_param->vbvEndFrameAdjust * m_param->totalFrames)
-        {
-            rce->vbvEndAdj = true;
-            rce->targetFill = 0;
-        }
+         if (m_param->vbvBufferEnd && ((curFrame->vbvEndFlag) ||
((m_param->totalFrames) && (rce->encodeOrder >= (m_param->vbvEndFrameAdjust
* m_param->totalFrames)))))
+         {
+              if (m_totalFrames == -1)
+                   m_totalFrames = curFrame->vbvEndFlag ? (1 /
m_param->vbvEndFrameAdjust) * rce->encodeOrder : m_param->totalFrames;
+              rce->remainingVbvEndFrames = ((m_totalFrames) -
(rce->encodeOrder));
+              rce->vbvEndAdj = true;
+              rce->targetFill = 0;
+         }

         int mincr = enc->m_vps.ptl.minCrForLevel;
         /* Profiles above Main10 don't require maxAU size check, so just
set the maximum to a large value. */
@@ -2584,8 +2588,12 @@ double RateControl::clipQscale(Frame* curFrame,
RateControlEntry* rce, double q)
                 {
                     bool loopBreak = false;
                     double bufferDiff = m_param->vbvBufferEnd -
(m_bufferFill / m_bufferSize);
-                    rce->targetFill = m_bufferFill + m_bufferSize *
(bufferDiff / (m_param->totalFrames - rce->encodeOrder));
-                    if (bufferFillCur < rce->targetFill)
+                        if (rce->remainingVbvEndFrames > 0) {
+                             rce->targetFill = m_bufferFill + m_bufferSize
* (bufferDiff / (double)(rce->remainingVbvEndFrames));
+                        }
+                        else
+                             rce->targetFill = m_bufferFill + m_bufferSize
* bufferDiff;
+                        if (bufferFillCur < rce->targetFill)
                     {
                         q *= 1.01;
                         loopTerminate |= 1;
diff --git a/source/encoder/ratecontrol.h b/source/encoder/ratecontrol.h
index c3dc0406f..7e138c43a 100644
--- a/source/encoder/ratecontrol.h
+++ b/source/encoder/ratecontrol.h
@@ -100,6 +100,7 @@ struct RateControlEntry
     bool    isActive;
     double  amortizeFrames;
     double  amortizeFraction;
+    int  remainingVbvEndFrames;
     /* Required in 2-pass rate control */
     uint64_t expectedBits; /* total expected bits up to the current frame
(current one excluded) */
     double   iCuCount;
@@ -136,6 +137,7 @@ public:
     double*     m_relativeComplexity;
     int         m_zoneBufferIdx;

+    int    m_totalFrames;
     bool   m_isAbr;
     bool   m_isVbv;
     bool   m_isCbr;
diff --git a/source/x265.h b/source/x265.h
index 80d1358cd..d0a80bf0c 100644
--- a/source/x265.h
+++ b/source/x265.h
@@ -408,6 +408,8 @@ typedef struct x265_picture
      * on output */
     int64_t dts;

+    int vbvEndFlag; // New flag for VBV end feature
+
     /* force quantizer for != X265_QP_AUTO */
     /* The value provided on input is returned with the same picture (POC)
on
      * output */
@@ -2495,6 +2497,12 @@ int x265_encoder_headers(x265_encoder *, x265_nal
**pp_nal, uint32_t *pi_nal);
  *      Once flushing has begun, all subsequent calls must pass pic_in as
NULL. */
 int x265_encoder_encode(x265_encoder *encoder, x265_nal **pp_nal, uint32_t
*pi_nal, x265_picture *pic_in, x265_picture **pic_out);

+/*
+x265_configure_vbv_end:
+* Set the Vbvend flag based on the totalstreamduration.
+*/
+void x265_configure_vbv_end(x265_encoder* enc, x265_picture* picture,
double totalstreamduration);
+
 /* x265_encoder_reconfig:
  *      various parameters from x265_param are copied.
  *      this takes effect immediately, on whichever frame is encoded next;
@@ -2647,6 +2655,7 @@ typedef struct x265_api
     int           (*encoder_reconfig)(x265_encoder*, x265_param*);
     int           (*encoder_reconfig_zone)(x265_encoder*, x265_zone*);
     int           (*encoder_headers)(x265_encoder*, x265_nal**, uint32_t*);
+    void          (*configure_vbv_end)(x265_encoder*, x265_picture*,
double );
     int           (*encoder_encode)(x265_encoder*, x265_nal**, uint32_t*,
x265_picture*, x265_picture**);
     void          (*encoder_get_stats)(x265_encoder*, x265_stats*,
uint32_t);
     void          (*encoder_log)(x265_encoder*, int, char**);
-- 
2.37.3.windows.1
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20240918/601dadf0/attachment-0001.htm>


More information about the x265-devel mailing list