changeset 12578:f27e4c589564

API: New API to reconfigure zones
author Aruna Matheswaran <aruna@multicorewareinc.com>
date Thu, 17 Oct 2019 12:04:07 +0530
parents 971180b100f8
children 96fb4962ccb5
files doc/reST/api.rst source/CMakeLists.txt source/common/param.cpp source/encoder/api.cpp source/encoder/dpb.h source/encoder/encoder.cpp source/encoder/encoder.h source/encoder/ratecontrol.cpp source/encoder/slicetype.cpp source/x265.h
diffstat 10 files changed, 160 insertions(+-), 75 deletions(-) [+]
line wrap: on
line diff
--- a/doc/reST/api.rst	Tue Oct 22 20:14:37 2019 +0530
+++ b/doc/reST/api.rst	Thu Oct 17 12:04:07 2019 +0530
@@ -191,7 +191,15 @@ changes made to the parameters for auto-
 	 *      switched out of; using reconfig to switch between ultrafast and other
 	 *      presets is not recommended without a more fine-grained breakdown of
 	 *      parameters to take this into account. */
-	int x265_encoder_reconfig(x265_encoder *, x265_param *);
+    int x265_encoder_reconfig(x265_encoder *, x265_param *);
+
+**x265_encoder_reconfig_zone()** Used to reconfigure rate-contol settings of zones mid-encode::
+
+    /* x265_encoder_reconfig_zone:
+     *      Properties of the zone will be copied to encoder's param and will be used only to
+     *      influence rate-control decisions of the zone.
+     *      returns 0 on successful copy and negative on failure.*/
+    int x265_encoder_reconfig(x265_encoder *, x265_param *);
 
 **x265_get_slicetype_poc_and_scenecut()** may be used to fetch slice type, poc and scene cut information mid-encode::
 
--- a/source/CMakeLists.txt	Tue Oct 22 20:14:37 2019 +0530
+++ b/source/CMakeLists.txt	Thu Oct 17 12:04:07 2019 +0530
@@ -29,7 +29,7 @@ option(NATIVE_BUILD "Target the build CP
 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 180)
+set(X265_BUILD 181)
 configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
                "${PROJECT_BINARY_DIR}/x265.def")
 configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
--- a/source/common/param.cpp	Tue Oct 22 20:14:37 2019 +0530
+++ b/source/common/param.cpp	Thu Oct 17 12:04:07 2019 +0530
@@ -274,6 +274,8 @@ void x265_param_default(x265_param* para
     param->rc.qpMin = 0;
     param->rc.qpMax = QP_MAX_MAX;
     param->rc.bEnableConstVbv = 0;
+    param->bResetZoneConfig = 1;
+    param->reconfigWindowSize = 0;
 
     /* Video Usability Information (VUI) */
     param->vui.aspectRatioIdc = 0;
@@ -2333,6 +2335,8 @@ void x265_copy_params(x265_param* dst, x
     dst->rc.bEnableSlowFirstPass = src->rc.bEnableSlowFirstPass;
     dst->rc.zoneCount = src->rc.zoneCount;
     dst->rc.zonefileCount = src->rc.zonefileCount;
+    dst->reconfigWindowSize = src->reconfigWindowSize;
+    dst->bResetZoneConfig = src->bResetZoneConfig;
 
     if (src->rc.zonefileCount && src->rc.zones)
     {
--- a/source/encoder/api.cpp	Tue Oct 22 20:14:37 2019 +0530
+++ b/source/encoder/api.cpp	Thu Oct 17 12:04:07 2019 +0530
@@ -100,7 +100,7 @@ x265_encoder *x265_encoder_open(x265_par
     if(param) PARAM_NS::x265_param_default(param);
     if(latestParam) PARAM_NS::x265_param_default(latestParam);
     if(zoneParam) PARAM_NS::x265_param_default(zoneParam);
-
+  
     if (!param || !latestParam || !zoneParam)
         goto fail;
     if (p->rc.zoneCount || p->rc.zonefileCount)
@@ -191,9 +191,20 @@ x265_encoder *x265_encoder_open(x265_par
 
     encoder->create();
 
+    if (!param->bResetZoneConfig)
+    {
+        param->rc.zones = X265_MALLOC(x265_zone, param->rc.zonefileCount);
+        for (int i = 0; i < param->rc.zonefileCount; i++)
+        {
+            param->rc.zones[i].zoneParam = X265_MALLOC(x265_param, 1);
+            memcpy(param->rc.zones[i].zoneParam, param, sizeof(x265_param));
+        }
+    }
+
     memcpy(zoneParam, param, sizeof(x265_param));
     for (int i = 0; i < param->rc.zonefileCount; i++)
     {
+        param->rc.zones[i].startFrame = -1;
         encoder->configureZone(zoneParam, param->rc.zones[i].zoneParam);
     }
 
@@ -362,6 +373,25 @@ int x265_encoder_reconfig(x265_encoder* 
     return ret;
 }
 
+
+int x265_encoder_reconfig_zone(x265_encoder* enc, x265_zone* zone_in)
+{
+    if (!enc || !zone_in)
+        return -1;
+    Encoder* encoder = static_cast<Encoder*>(enc);
+    x265_zone* zone = &(encoder->m_param->rc).zones[encoder->m_zoneIndex];
+    x265_param* zoneParam = zone->zoneParam;
+    
+    int ret = encoder->reconfigureParam(zoneParam, zone_in->zoneParam);
+    if (ret)
+        return -1;
+    memcpy(zone, zone_in, sizeof(x265_zone));
+    
+    encoder->m_zoneIndex++;
+    encoder->m_zoneIndex %= encoder->m_param->rc.zonefileCount;
+    return 0;
+}
+
 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)
@@ -988,6 +1018,7 @@ static const x265_api libapi =
     &x265_encoder_open,
     &x265_encoder_parameters,
     &x265_encoder_reconfig,
+    &x265_encoder_reconfig_zone,
     &x265_encoder_headers,
     &x265_encoder_encode,
     &x265_encoder_get_stats,
--- a/source/encoder/dpb.h	Tue Oct 22 20:14:37 2019 +0530
+++ b/source/encoder/dpb.h	Thu Oct 17 12:04:07 2019 +0530
@@ -52,12 +52,15 @@ public:
         m_lastIDR = 0;
         m_pocCRA = 0;
         m_bhasLeadingPicture = param->radl;
-        for (int i = 0; i < param->rc.zonefileCount; i++)
+        if (param->bResetZoneConfig)
         {
-            if (param->rc.zones[i].zoneParam->radl)
+            for (int i = 0; i < param->rc.zonefileCount ; i++)
             {
-                m_bhasLeadingPicture = param->rc.zones[i].zoneParam->radl;
-                break;
+                if (param->rc.zones[i].zoneParam->radl)
+                {
+                    m_bhasLeadingPicture = param->rc.zones[i].zoneParam->radl;
+                    break;
+                }
             }
         }
         m_bRefreshPending = false;
--- a/source/encoder/encoder.cpp	Tue Oct 22 20:14:37 2019 +0530
+++ b/source/encoder/encoder.cpp	Thu Oct 17 12:04:07 2019 +0530
@@ -134,6 +134,7 @@ Encoder::Encoder()
     m_prevTonemapPayload.payload = NULL;
     m_startPoint = 0;
     m_saveCTUSize = 0;
+    m_zoneIndex = 0;
 }
 inline char *strcatFilename(const char *input, const char *suffix)
 {
@@ -1866,12 +1867,15 @@ int Encoder::encode(const x265_picture* 
                 frameEnc->m_analysisData.poc = frameEnc->m_poc;
                 if (m_param->rc.bStatRead)
                     readAnalysisFile(&frameEnc->m_analysisData, frameEnc->m_poc, frameEnc->m_lowres.sliceType);
-             }
-
-            for (int i = 0; i < m_param->rc.zonefileCount; i++)
+            }
+
+            if (m_param->bResetZoneConfig)
             {
-                if (m_param->rc.zones[i].startFrame == frameEnc->m_poc)
-                    x265_encoder_reconfig(this, m_param->rc.zones[i].zoneParam);
+                for (int i = 0; i < m_param->rc.zonefileCount; i++)
+                {
+                    if (m_param->rc.zones[i].startFrame == frameEnc->m_poc)
+                        x265_encoder_reconfig(this, m_param->rc.zones[i].zoneParam);
+                }
             }
 
             if (frameEnc->m_reconfigureRc && m_reconfigureRc)
@@ -3066,48 +3070,51 @@ void Encoder::initPPS(PPS *pps)
 
 void Encoder::configureZone(x265_param *p, x265_param *zone)
 {
-    p->maxNumReferences = zone->maxNumReferences;
-    p->bEnableFastIntra = zone->bEnableFastIntra;
-    p->bEnableEarlySkip = zone->bEnableEarlySkip;
-    p->bEnableRecursionSkip = zone->bEnableRecursionSkip;
-    p->searchMethod = zone->searchMethod;
-    p->searchRange = zone->searchRange;
-    p->subpelRefine = zone->subpelRefine;
-    p->rdoqLevel = zone->rdoqLevel;
-    p->rdLevel = zone->rdLevel;
-    p->bEnableRectInter = zone->bEnableRectInter;
-    p->maxNumMergeCand = zone->maxNumMergeCand;
-    p->bIntraInBFrames = zone->bIntraInBFrames;
-    if(zone->scalingLists)
-        p->scalingLists = strdup(zone->scalingLists);
-
-    p->rc.aqMode = zone->rc.aqMode;
-    p->rc.aqStrength = zone->rc.aqStrength;
-    p->noiseReductionInter = zone->noiseReductionInter;
-    p->noiseReductionIntra = zone->noiseReductionIntra;
-
-    p->limitModes = zone->limitModes;
-    p->bEnableSplitRdSkip = zone->bEnableSplitRdSkip;
-    p->bCULossless = zone->bCULossless;
-    p->bEnableRdRefine = zone->bEnableRdRefine;
-    p->limitTU = zone->limitTU;
-    p->bEnableTSkipFast = zone->bEnableTSkipFast;
-    p->rdPenalty = zone->rdPenalty;
-    p->dynamicRd = zone->dynamicRd;
-    p->bEnableTransformSkip = zone->bEnableTransformSkip;
-    p->bEnableAMP = zone->bEnableAMP;
-
-    if (m_param->rc.rateControlMode == X265_RC_ABR)
-        p->rc.bitrate = zone->rc.bitrate;
-    if (m_param->rc.rateControlMode == X265_RC_CRF)
-        p->rc.rfConstant = zone->rc.rfConstant;
-    if (m_param->rc.rateControlMode == X265_RC_CQP)
-    {
-        p->rc.qp = zone->rc.qp;
-        p->rc.aqMode = X265_AQ_NONE;
-        p->rc.hevcAq = 0;
-    }
-    p->radl = zone->radl;
+    if (m_param->bResetZoneConfig)
+    {
+        p->maxNumReferences = zone->maxNumReferences;
+        p->bEnableFastIntra = zone->bEnableFastIntra;
+        p->bEnableEarlySkip = zone->bEnableEarlySkip;
+        p->bEnableRecursionSkip = zone->bEnableRecursionSkip;
+        p->searchMethod = zone->searchMethod;
+        p->searchRange = zone->searchRange;
+        p->subpelRefine = zone->subpelRefine;
+        p->rdoqLevel = zone->rdoqLevel;
+        p->rdLevel = zone->rdLevel;
+        p->bEnableRectInter = zone->bEnableRectInter;
+        p->maxNumMergeCand = zone->maxNumMergeCand;
+        p->bIntraInBFrames = zone->bIntraInBFrames;
+        if (zone->scalingLists)
+            p->scalingLists = strdup(zone->scalingLists);
+
+        p->rc.aqMode = zone->rc.aqMode;
+        p->rc.aqStrength = zone->rc.aqStrength;
+        p->noiseReductionInter = zone->noiseReductionInter;
+        p->noiseReductionIntra = zone->noiseReductionIntra;
+
+        p->limitModes = zone->limitModes;
+        p->bEnableSplitRdSkip = zone->bEnableSplitRdSkip;
+        p->bCULossless = zone->bCULossless;
+        p->bEnableRdRefine = zone->bEnableRdRefine;
+        p->limitTU = zone->limitTU;
+        p->bEnableTSkipFast = zone->bEnableTSkipFast;
+        p->rdPenalty = zone->rdPenalty;
+        p->dynamicRd = zone->dynamicRd;
+        p->bEnableTransformSkip = zone->bEnableTransformSkip;
+        p->bEnableAMP = zone->bEnableAMP;
+
+        if (m_param->rc.rateControlMode == X265_RC_ABR)
+            p->rc.bitrate = zone->rc.bitrate;
+        if (m_param->rc.rateControlMode == X265_RC_CRF)
+            p->rc.rfConstant = zone->rc.rfConstant;
+        if (m_param->rc.rateControlMode == X265_RC_CQP)
+        {
+            p->rc.qp = zone->rc.qp;
+            p->rc.aqMode = X265_AQ_NONE;
+            p->rc.hevcAq = 0;
+        }
+        p->radl = zone->radl;
+    }
     memcpy(zone, p, sizeof(x265_param));
 }
 
@@ -3816,6 +3823,12 @@ void Encoder::configure(x265_param *p)
         x265_log(p, X265_LOG_WARNING, "Turning on repeat - headers for zone encoding\n");
     }
 
+    if (!m_param->bResetZoneConfig && (p->keyframeMax != p->keyframeMin))
+        x265_log(p, X265_LOG_WARNING, "External zone reconfiguration requires a fixed GOP size to enable appropriate signaling of HRD info\n");
+
+    if (!m_param->bResetZoneConfig && (p->reconfigWindowSize != (uint64_t)p->keyframeMax))
+        x265_log(p, X265_LOG_WARNING, "Zone size must be multiple of GOP size to enable appropriate signaling of HRD info\n");
+
     if (m_param->bEnableHME)
     {
         if (m_param->sourceHeight < 540)
--- a/source/encoder/encoder.h	Tue Oct 22 20:14:37 2019 +0530
+++ b/source/encoder/encoder.h	Thu Oct 17 12:04:07 2019 +0530
@@ -263,6 +263,8 @@ public:
 
     x265_sei_payload        m_prevTonemapPayload;
 
+    int                     m_zoneIndex;
+
     /* Collect frame level feature data */
     uint64_t*               m_rdCost;
     uint64_t*               m_variance;
--- a/source/encoder/ratecontrol.cpp	Tue Oct 22 20:14:37 2019 +0530
+++ b/source/encoder/ratecontrol.cpp	Thu Oct 17 12:04:07 2019 +0530
@@ -1251,7 +1251,8 @@ int RateControl::rateControlStart(Frame*
         {
             m_param = m_param->rc.zones[i].zoneParam;
             reconfigureRC();
-            init(*m_curSlice->m_sps);
+            if (m_param->bResetZoneConfig)
+                init(*m_curSlice->m_sps);
         }
     }
     if (m_param->rc.bStatRead)
--- a/source/encoder/slicetype.cpp	Tue Oct 22 20:14:37 2019 +0530
+++ b/source/encoder/slicetype.cpp	Thu Oct 17 12:04:07 2019 +0530
@@ -1531,12 +1531,15 @@ void Lookahead::slicetypeDecide()
             if (frm.bIsFadeEnd){
                 frm.sliceType = m_param->bOpenGOP && m_lastKeyframe >= 0 ? X265_TYPE_I : X265_TYPE_IDR;
             }
-            for (int i = 0; i < m_param->rc.zonefileCount; i++)
+            if (m_param->bResetZoneConfig)
             {
-                int curZoneStart = m_param->rc.zones[i].startFrame;
-                curZoneStart += curZoneStart ? m_param->rc.zones[i].zoneParam->radl : 0;
-                if (curZoneStart == frm.frameNum)
-                    frm.sliceType = X265_TYPE_IDR;
+                for (int i = 0; i < m_param->rc.zonefileCount; i++)
+                {
+                    int curZoneStart = m_param->rc.zones[i].startFrame;
+                    curZoneStart += curZoneStart ? m_param->rc.zones[i].zoneParam->radl : 0;
+                    if (curZoneStart == frm.frameNum)
+                        frm.sliceType = X265_TYPE_IDR;
+                }
             }
             if ((frm.sliceType == X265_TYPE_I && frm.frameNum - m_lastKeyframe >= m_param->keyframeMin) || (frm.frameNum == (m_param->chunkStart - 1)) || (frm.frameNum == m_param->chunkEnd))
             {
@@ -1554,16 +1557,19 @@ void Lookahead::slicetypeDecide()
                 m_lastKeyframe = frm.frameNum;
                 frm.bKeyframe = true;
                 int zoneRadl = 0;
-                for (int i = 0; i < m_param->rc.zonefileCount; i++)
+                if (m_param->bResetZoneConfig)
                 {
-                    int zoneStart = m_param->rc.zones[i].startFrame;
-                    zoneStart += zoneStart ? m_param->rc.zones[i].zoneParam->radl : 0;
-                    if (zoneStart == frm.frameNum)
+                    for (int i = 0; i < m_param->rc.zonefileCount; i++)
                     {
-                        zoneRadl = m_param->rc.zones[i].zoneParam->radl;
-                        m_param->radl = 0;
-                        m_param->rc.zones->zoneParam->radl = i < m_param->rc.zonefileCount - 1? m_param->rc.zones[i + 1].zoneParam->radl : 0;
-                        break;
+                        int zoneStart = m_param->rc.zones[i].startFrame;
+                        zoneStart += zoneStart ? m_param->rc.zones[i].zoneParam->radl : 0;
+                        if (zoneStart == frm.frameNum)
+                        {
+                            zoneRadl = m_param->rc.zones[i].zoneParam->radl;
+                            m_param->radl = 0;
+                            m_param->rc.zones->zoneParam->radl = i < m_param->rc.zonefileCount - 1 ? m_param->rc.zones[i + 1].zoneParam->radl : 0;
+                            break;
+                        }
                     }
                 }
                 if (bframes > 0 && !m_param->radl && !zoneRadl)
@@ -1854,13 +1860,16 @@ void Lookahead::slicetypeAnalyse(Lowres 
     }
     frames[framecnt + 1] = NULL;
 
-    for (int i = 0; i < m_param->rc.zonefileCount; i++)
+    if (m_param->bResetZoneConfig)
     {
-        int curZoneStart = m_param->rc.zones[i].startFrame, nextZoneStart = 0;
-        curZoneStart += curZoneStart ? m_param->rc.zones[i].zoneParam->radl : 0;
-        nextZoneStart += (i + 1 < m_param->rc.zonefileCount) ? m_param->rc.zones[i + 1].startFrame + m_param->rc.zones[i + 1].zoneParam->radl : m_param->totalFrames;
-        if (curZoneStart <= frames[0]->frameNum && nextZoneStart > frames[0]->frameNum)
-            m_param->keyframeMax = nextZoneStart - curZoneStart;
+        for (int i = 0; i < m_param->rc.zonefileCount; i++)
+        {
+            int curZoneStart = m_param->rc.zones[i].startFrame, nextZoneStart = 0;
+            curZoneStart += curZoneStart ? m_param->rc.zones[i].zoneParam->radl : 0;
+            nextZoneStart += (i + 1 < m_param->rc.zonefileCount) ? m_param->rc.zones[i + 1].startFrame + m_param->rc.zones[i + 1].zoneParam->radl : m_param->totalFrames;
+            if (curZoneStart <= frames[0]->frameNum && nextZoneStart > frames[0]->frameNum)
+                m_param->keyframeMax = nextZoneStart - curZoneStart;
+        }
     }
     int keylimit = m_param->keyframeMax;
     if (frames[0]->frameNum < m_param->chunkEnd)
@@ -2071,7 +2080,7 @@ void Lookahead::slicetypeAnalyse(Lowres 
             frames[numFrames]->sliceType = X265_TYPE_P;
         }
 
-        int zoneRadl = m_param->rc.zonefileCount ? m_param->rc.zones->zoneParam->radl : 0;
+        int zoneRadl = m_param->rc.zonefileCount && m_param->bResetZoneConfig ? m_param->rc.zones->zoneParam->radl : 0;
         bool bForceRADL = (m_param->radl || zoneRadl) && !m_param->bOpenGOP;
         bool bLastMiniGop = (framecnt >= m_param->bframes + 1) ? false : true;
         int radl = m_param->radl ? m_param->radl : zoneRadl;
--- a/source/x265.h	Tue Oct 22 20:14:37 2019 +0530
+++ b/source/x265.h	Thu Oct 17 12:04:07 2019 +0530
@@ -1819,6 +1819,13 @@ typedef struct x265_param
 
     /*Input sequence bit depth. It can be either 8bit, 10bit or 12bit.*/
     int       sourceBitDepth;
+
+    /*Size of the zone to be reconfigured in frames. Default 0. API only. */
+    uint32_t  reconfigWindowSize;
+
+    /*Flag to indicate if rate-control history has to be reset during zone reconfiguration.
+      Default 1 (Enabled). API only. */
+    int       bResetZoneConfig;
 } x265_param;
 /* x265_param_alloc:
  *  Allocates an x265_param instance. The returned param structure is not
@@ -1995,6 +2002,12 @@ int x265_encoder_encode(x265_encoder *en
  *      parameters to take this into account. */
 int x265_encoder_reconfig(x265_encoder *, x265_param *);
 
+/* x265_encoder_reconfig_zone:
+*       zone settings are copied to the encoder's param.
+*       Properties of the zone will be used only to re-configure rate-control settings
+*       of the zone mid-encode. Returns 0 on success on successful copy, negative on failure.*/
+int x265_encoder_reconfig_zone(x265_encoder *, x265_zone *);
+
 /* x265_encoder_get_stats:
  *       returns encoder statistics */
 void x265_encoder_get_stats(x265_encoder *encoder, x265_stats *, uint32_t statsSizeBytes);
@@ -2123,6 +2136,7 @@ typedef struct x265_api
     x265_encoder* (*encoder_open)(x265_param*);
     void          (*encoder_parameters)(x265_encoder*, x265_param*);
     int           (*encoder_reconfig)(x265_encoder*, x265_param*);
+    int           (*encoder_reconfig_zone)(x265_encoder*, x265_zone*);
     int           (*encoder_headers)(x265_encoder*, x265_nal**, uint32_t*);
     int           (*encoder_encode)(x265_encoder*, x265_nal**, uint32_t*, x265_picture*, x265_picture*);
     void          (*encoder_get_stats)(x265_encoder*, x265_stats*, uint32_t);