changeset 12671:ac951f9fef8a

Add support for RADL pictures at IDR scenecuts
author Pooja Venkatesan <pooja@multicorewareinc.com>
date Mon, 29 Jun 2020 14:43:31 +0530
parents 4996092aa8ab
children 70447252bdf8
files doc/reST/cli.rst source/common/lowres.cpp source/common/lowres.h source/encoder/encoder.cpp source/encoder/encoder.h source/encoder/slicetype.cpp
diffstat 6 files changed, 28 insertions(+-), 7 deletions(-) [+]
line wrap: on
line diff
--- a/doc/reST/cli.rst	Mon Jun 29 14:43:24 2020 +0530
+++ b/doc/reST/cli.rst	Mon Jun 29 14:43:31 2020 +0530
@@ -1475,7 +1475,10 @@ Slice decision options
 	
 .. option:: --radl <integer>
 	
-	Number of RADL pictures allowed infront of IDR. Requires fixed keyframe interval.
+	Number of RADL pictures allowed infront of IDR. Requires closed gop interval.
+	If enabled for fixed keyframe interval, inserts RADL at every IDR.
+	If enabled for closed gop interval, in case of :option:`--hist-scenecut` inserts RADL at every hard scenecut
+	whereas for the :option:`--scenecut`, inserts RADL at every scenecut.
 	Recommended value is 2-3. Default 0 (disabled).
 	
 	**Range of values: Between 0 and `--bframes`
--- a/source/common/lowres.cpp	Mon Jun 29 14:43:24 2020 +0530
+++ b/source/common/lowres.cpp	Mon Jun 29 14:43:31 2020 +0530
@@ -269,6 +269,7 @@ void Lowres::init(PicYuv *origPic, int p
     interPCostPercDiff = 0.0;
     intraCostPercDiff = 0.0;
     m_bIsMaxThres = false;
+    m_bIsHardScenecut = false;
 
     if (qpAqOffset && invQscaleFactor)
         memset(costEstAq, -1, sizeof(costEstAq));
--- a/source/common/lowres.h	Mon Jun 29 14:43:24 2020 +0530
+++ b/source/common/lowres.h	Mon Jun 29 14:43:31 2020 +0530
@@ -238,6 +238,7 @@ struct Lowres : public ReferencePlanes
     bool   m_bIsMaxThres;
     double interPCostPercDiff;
     double intraCostPercDiff;
+    bool   m_bIsHardScenecut;
 
     bool create(x265_param* param, PicYuv *origPic, uint32_t qgSize);
     void destroy();
--- a/source/encoder/encoder.cpp	Mon Jun 29 14:43:24 2020 +0530
+++ b/source/encoder/encoder.cpp	Mon Jun 29 14:43:31 2020 +0530
@@ -1528,7 +1528,7 @@ double Encoder::normalizeRange(int32_t v
     return (double)(value - minValue) * (rangeEnd - rangeStart) / (maxValue - minValue) + rangeStart;
 }
 
-void Encoder::findSceneCuts(x265_picture *pic, bool& bDup, double maxUVSad, double edgeSad, bool& isMaxThres)
+void Encoder::findSceneCuts(x265_picture *pic, bool& bDup, double maxUVSad, double edgeSad, bool& isMaxThres, bool& isHardSC)
 {
     double minEdgeT = m_edgeHistThreshold * MIN_EDGE_FACTOR;
     double minChromaT = minEdgeT * SCENECUT_CHROMA_FACTOR;
@@ -1556,12 +1556,15 @@ void Encoder::findSceneCuts(x265_picture
         {
             pic->frameData.bScenecut = true;
             isMaxThres = true;
+            isHardSC = true;
         }
         else if (edgeSad > m_scaledEdgeThreshold || maxUVSad >= m_scaledChromaThreshold
                  || (edgeSad > m_edgeHistThreshold && maxUVSad >= m_chromaHistThreshold))
         {
             pic->frameData.bScenecut = true;
             bDup = false;
+            if (edgeSad > m_scaledEdgeThreshold || maxUVSad >= m_scaledChromaThreshold)
+                isHardSC = true;
         }
     }
 }
@@ -1595,6 +1598,7 @@ int Encoder::encode(const x265_picture* 
     bool bdropFrame = false;
     bool dropflag = false;
     bool isMaxThres = false;
+    bool isHardSC = false;
 
     if (m_exportedPic)
     {
@@ -1621,7 +1625,7 @@ int Encoder::encode(const x265_picture* 
             {
                 double maxUVSad = 0.0, edgeSad = 0.0;
                 computeHistogramSAD(&maxUVSad, &edgeSad, pic_in->poc);
-                findSceneCuts(pic, bdropFrame, maxUVSad, edgeSad, isMaxThres);
+                findSceneCuts(pic, bdropFrame, maxUVSad, edgeSad, isMaxThres, isHardSC);
             }
         }
 
@@ -1801,6 +1805,8 @@ int Encoder::encode(const x265_picture* 
         {
             inFrame->m_lowres.bScenecut = (inputPic->frameData.bScenecut == 1) ? true : false;
             inFrame->m_lowres.m_bIsMaxThres = isMaxThres;
+            if (m_param->radl && m_param->keyframeMax != m_param->keyframeMin)
+                inFrame->m_lowres.m_bIsHardScenecut = isHardSC;
         }
         if (m_param->bHistBasedSceneCut && m_param->analysisSave)
         {
@@ -4218,10 +4224,10 @@ void Encoder::configure(x265_param *p)
     p->unitSizeDepth = p->maxLog2CUSize - LOG2_UNIT_SIZE;
     p->num4x4Partitions = (1U << (p->unitSizeDepth << 1));
 
-    if (p->radl && (p->keyframeMax != p->keyframeMin))
+    if (p->radl && p->bOpenGOP)
     {
         p->radl = 0;
-        x265_log(p, X265_LOG_WARNING, "Radl requires fixed gop-length (keyint == min-keyint). Disabling radl.\n");
+        x265_log(p, X265_LOG_WARNING, "Radl requires closed gop structure. Disabling radl.\n");
     }
 
     if ((p->chunkStart || p->chunkEnd) && p->bOpenGOP && m_param->bResetZoneConfig)
--- a/source/encoder/encoder.h	Mon Jun 29 14:43:24 2020 +0530
+++ b/source/encoder/encoder.h	Mon Jun 29 14:43:31 2020 +0530
@@ -376,7 +376,7 @@ public:
     bool computeHistograms(x265_picture *pic);
     void computeHistogramSAD(double *maxUVNormalizedSAD, double *edgeNormalizedSAD, int curPoc);
     double normalizeRange(int32_t value, int32_t minValue, int32_t maxValue, double rangeStart, double rangeEnd);
-    void findSceneCuts(x265_picture *pic, bool& bDup, double m_maxUVSADVal, double m_edgeSADVal, bool& isMaxThres);
+    void findSceneCuts(x265_picture *pic, bool& bDup, double m_maxUVSADVal, double m_edgeSADVal, bool& isMaxThres, bool& isHardSC);
 
     void initRefIdx();
     void analyseRefIdx(int *numRefIdx);
--- a/source/encoder/slicetype.cpp	Mon Jun 29 14:43:24 2020 +0530
+++ b/source/encoder/slicetype.cpp	Mon Jun 29 14:43:31 2020 +0530
@@ -1520,6 +1520,7 @@ void Lookahead::slicetypeDecide()
     int bframes, brefs;
     if (!m_param->analysisLoad || m_param->bAnalysisType == HEVC_INFO)
     {
+        bool isClosedGopRadl = m_param->radl && (m_param->keyframeMax != m_param->keyframeMin);
         for (bframes = 0, brefs = 0;; bframes++)
         {
             Lowres& frm = list[bframes]->m_lowres;
@@ -1579,6 +1580,15 @@ void Lookahead::slicetypeDecide()
                 else
                     frm.sliceType = X265_TYPE_IDR;
             }
+            if (frm.sliceType == X265_TYPE_IDR && frm.bScenecut && isClosedGopRadl)
+            {
+                if (!m_param->bHistBasedSceneCut || (m_param->bHistBasedSceneCut && frm.m_bIsHardScenecut))
+                {
+                    for (int i = bframes; i < bframes + m_param->radl; i++)
+                        list[i]->m_lowres.sliceType = X265_TYPE_B;
+                    list[(bframes + m_param->radl)]->m_lowres.sliceType = X265_TYPE_IDR;
+                }
+            }
             if (frm.sliceType == X265_TYPE_IDR)
             {
                 /* Closed GOP */
@@ -2147,7 +2157,7 @@ void Lookahead::slicetypeAnalyse(Lowres 
         }
 
         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 bForceRADL = zoneRadl || (m_param->radl && (m_param->keyframeMax == m_param->keyframeMin));
         bool bLastMiniGop = (framecnt >= m_param->bframes + 1) ? false : true;
         int radl = m_param->radl ? m_param->radl : zoneRadl;
         int preRADL = m_lastKeyframe + m_param->keyframeMax - radl - 1; /*Frame preceeding RADL in POC order*/