[x265] [PATCH] Add API to read CTU Information

vignesh at multicorewareinc.com vignesh at multicorewareinc.com
Tue May 9 14:27:05 CEST 2017


# HG changeset patch
# User Santhoshini Sekar
# Date 1493009037 -19800
#      Mon Apr 24 10:13:57 2017 +0530
# Node ID 6a9eb27b2b0d1a716911bf19136ceb653a51270b
# Parent  7ecd263f6d43966df308d53029a67cfda03bb185
Add API to read CTU Information

diff -r 7ecd263f6d43 -r 6a9eb27b2b0d doc/reST/api.rst
--- a/doc/reST/api.rst	Tue May 09 12:43:04 2017 +0530
+++ b/doc/reST/api.rst	Mon Apr 24 10:13:57 2017 +0530
@@ -192,6 +192,12 @@
 	 *      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 *);
+**x265_encoder_ctu_info**
+       /* x265_encoder_ctu_info:
+        *    Copy CTU information such as ctu address and ctu partition structure of all
+        *    CTUs in each frame. The function is invoked only if "--ctu-info" is enabled and
+        *    the encoder will wait for this copy to complete if enabled.
+        */
 
 Pictures
 ========
diff -r 7ecd263f6d43 -r 6a9eb27b2b0d doc/reST/cli.rst
--- a/doc/reST/cli.rst	Tue May 09 12:43:04 2017 +0530
+++ b/doc/reST/cli.rst	Mon Apr 24 10:13:57 2017 +0530
@@ -1221,7 +1221,16 @@
 	intra cost of a frame used in scenecut detection. For example, a value of 5 indicates,
 	if the inter cost of a frame is greater than or equal to 95 percent of the intra cost of the frame,
 	then detect this frame as scenecut. Values between 5 and 15 are recommended. Default 5.	
-	
+
+.. option:: --ctu-info <0, 1, 2, 4, 6>
+
+   This value enables receiving CTU information asynchronously and determine reaction to the CTU information. Default 0.
+   1: force the partitions if CTU information is present.
+   2: functionality of (1) and reduce qp if CTU information has changed.
+   4: functionality of (1) and force Inter modes when CTU Information has changed, merge/skip otherwise.
+   This option should be enabled only when planning to invoke the API function x265_encoder_ctu_info to copy ctu-info asynchronously. 
+   If enabled without calling the API function, the encoder will wait indefinitely.
+
 .. option:: --intra-refresh
 
 	Enables Periodic Intra Refresh(PIR) instead of keyframe insertion.
diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/CMakeLists.txt
--- a/source/CMakeLists.txt	Tue May 09 12:43:04 2017 +0530
+++ b/source/CMakeLists.txt	Mon Apr 24 10:13:57 2017 +0530
@@ -29,7 +29,7 @@
 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 116)
+set(X265_BUILD 117)
 configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
                "${PROJECT_BINARY_DIR}/x265.def")
 configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/common/frame.cpp
--- a/source/common/frame.cpp	Tue May 09 12:43:04 2017 +0530
+++ b/source/common/frame.cpp	Mon Apr 24 10:13:57 2017 +0530
@@ -48,6 +48,8 @@
     m_rcData = NULL;
     m_encodeStartTime = 0;
     m_reconfigureRc = false;
+    m_ctuInfo = NULL;
+    m_prevCtuInfoChange = NULL;
 }
 
 bool Frame::create(x265_param *param, float* quantOffsets)
@@ -166,6 +168,23 @@
         delete[] m_userSEI.payloads;
     }
 
+    if (m_ctuInfo)
+    {
+        uint32_t widthInCU = (m_param->sourceWidth + g_maxCUSize - 1) >> g_maxLog2CUSize;
+        uint32_t heightInCU = (m_param->sourceHeight + g_maxCUSize - 1) >> g_maxLog2CUSize;
+        uint32_t numCUsInFrame = widthInCU * heightInCU;
+        for (uint32_t i = 0; i < numCUsInFrame; i++)
+        {
+            X265_FREE((*m_ctuInfo + i)->ctuInfo);
+            (*m_ctuInfo + i)->ctuInfo = NULL;
+        }
+        X265_FREE(*m_ctuInfo);
+        *m_ctuInfo = NULL;
+        X265_FREE(m_ctuInfo);
+        m_ctuInfo = NULL;
+        X265_FREE(m_prevCtuInfoChange);
+        m_prevCtuInfoChange = NULL;
+    }
     m_lowres.destroy();
     X265_FREE(m_rcData);
 }
diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/common/frame.h
--- a/source/common/frame.h	Tue May 09 12:43:04 2017 +0530
+++ b/source/common/frame.h	Mon Apr 24 10:13:57 2017 +0530
@@ -108,6 +108,9 @@
     x265_analysis_2Pass    m_analysis2Pass;
     RcStats*               m_rcData;
 
+    x265_ctu_info_t**      m_ctuInfo;
+    Event                  m_copied;
+    int*                   m_prevCtuInfoChange;
     int64_t                m_encodeStartTime;
     Frame();
 
diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/common/param.cpp
--- a/source/common/param.cpp	Tue May 09 12:43:04 2017 +0530
+++ b/source/common/param.cpp	Mon Apr 24 10:13:57 2017 +0530
@@ -275,6 +275,7 @@
 
     param->toneMapFile = NULL;
     param->bDhdr10opt = 0;
+    param->bCTUInfo = 0;
 }
 
 int x265_param_default_preset(x265_param* param, const char* preset, const char* tune)
@@ -954,6 +955,7 @@
         OPT("limit-sao") p->bLimitSAO = atobool(value);
         OPT("dhdr10-info") p->toneMapFile = strdup(value);
         OPT("dhdr10-opt") p->bDhdr10opt = atobool(value);
+        OPT("ctu-info") p->bCTUInfo = atoi(value);
         else
             return X265_PARAM_BAD_NAME;
     }
@@ -1294,6 +1296,8 @@
         "qpmin exceeds supported range (0 to 69)");
     CHECK(param->log2MaxPocLsb < 4 || param->log2MaxPocLsb > 16,
         "Supported range for log2MaxPocLsb is 4 to 16");
+    CHECK(param->bCTUInfo < 0 || (param->bCTUInfo != 0 && param->bCTUInfo != 1 && param->bCTUInfo != 2 && param->bCTUInfo != 4 && param->bCTUInfo != 6) || param->bCTUInfo > 6,
+        "Supported values for bCTUInfo are 0, 1, 2, 4, 6");
 #if !X86_64
     CHECK(param->searchMethod == X265_SEA && (param->sourceWidth > 840 || param->sourceHeight > 480),
         "SEA motion search does not support resolutions greater than 480p in 32 bit build");
@@ -1457,6 +1461,7 @@
     TOOLOPT(param->bEnableStrongIntraSmoothing, "strong-intra-smoothing");
     TOOLVAL(param->lookaheadSlices, "lslices=%d");
     TOOLVAL(param->lookaheadThreads, "lthreads=%d")
+    TOOLVAL(param->bCTUInfo, "ctu-info=%d");
     if (param->maxSlices > 1)
         TOOLVAL(param->maxSlices, "slices=%d");
     if (param->bEnableLoopFilter)
@@ -1670,6 +1675,7 @@
     BOOL(p->bDhdr10opt, "dhdr10-opt");
     s += sprintf(s, " refine-level=%d", p->analysisRefineLevel);
     BOOL(p->bLimitSAO, "limit-sao");
+    s += sprintf(s, " ctu-info=%d", p->bCTUInfo);
 #undef BOOL
     return buf;
 }
diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/encoder/api.cpp
--- a/source/encoder/api.cpp	Tue May 09 12:43:04 2017 +0530
+++ b/source/encoder/api.cpp	Mon Apr 24 10:13:57 2017 +0530
@@ -295,6 +295,14 @@
     encoder->m_bQueuedIntraRefresh = 1;
     return 0;
 }
+int x265_encoder_ctu_info(x265_encoder *enc, int poc, x265_ctu_info_t** ctu)
+{
+    if (!ctu || !enc)
+        return -1;
+    Encoder* encoder = static_cast<Encoder*>(enc);
+    encoder->copyCtuInfo(ctu, poc);
+    return 0;
+}
 
 void x265_cleanup(void)
 {
@@ -372,6 +380,7 @@
 
     sizeof(x265_frame_stats),
     &x265_encoder_intra_refresh,
+    &x265_encoder_ctu_info,
 };
 
 typedef const x265_api* (*api_get_func)(int bitDepth);
diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/encoder/dpb.cpp
--- a/source/encoder/dpb.cpp	Tue May 09 12:43:04 2017 +0530
+++ b/source/encoder/dpb.cpp	Mon Apr 24 10:13:57 2017 +0530
@@ -105,6 +105,23 @@
                 }
             }
 
+            if (curFrame->m_ctuInfo != NULL)
+            {
+                uint32_t widthInCU = (curFrame->m_param->sourceWidth + g_maxCUSize - 1) >> g_maxLog2CUSize;
+                uint32_t heightInCU = (curFrame->m_param->sourceHeight + g_maxCUSize - 1) >> g_maxLog2CUSize;
+                uint32_t numCUsInFrame = widthInCU * heightInCU;
+                for (uint32_t i = 0; i < numCUsInFrame; i++)
+                {
+                    X265_FREE((*curFrame->m_ctuInfo + i)->ctuInfo);
+                    (*curFrame->m_ctuInfo + i)->ctuInfo = NULL;
+                }
+                X265_FREE(*curFrame->m_ctuInfo);
+                *(curFrame->m_ctuInfo) = NULL;
+                X265_FREE(curFrame->m_ctuInfo);
+                curFrame->m_ctuInfo = NULL;
+                X265_FREE(curFrame->m_prevCtuInfoChange);
+                curFrame->m_prevCtuInfoChange = NULL;
+            }
             curFrame->m_encData = NULL;
             curFrame->m_reconPic = NULL;
         }
diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp	Tue May 09 12:43:04 2017 +0530
+++ b/source/encoder/encoder.cpp	Mon Apr 24 10:13:57 2017 +0530
@@ -1157,6 +1157,120 @@
     return x265_check_params(encParam);
 }
 
+void Encoder::copyCtuInfo(x265_ctu_info_t** frameCtuInfo, int poc)
+{
+    uint32_t widthInCU = (m_param->sourceWidth + g_maxCUSize - 1) >> g_maxLog2CUSize;
+    uint32_t heightInCU = (m_param->sourceHeight + g_maxCUSize - 1) >> g_maxLog2CUSize;
+    Frame* curFrame;
+    Frame* prevFrame = NULL;
+    int32_t* frameCTU;
+    uint32_t numCUsInFrame = widthInCU * heightInCU;
+    uint32_t maxNum8x8Partitions = 64;
+    bool copied = false;
+    do
+    {
+        curFrame = m_lookahead->m_inputQueue.getPOC(poc);
+        if (!curFrame)
+            curFrame = m_lookahead->m_outputQueue.getPOC(poc);
+
+        if (poc > 0)
+        {
+            prevFrame = m_lookahead->m_inputQueue.getPOC(poc - 1);
+            if (!prevFrame)
+                prevFrame = m_lookahead->m_outputQueue.getPOC(poc - 1);
+            if (!prevFrame)
+            {
+                FrameEncoder* prevEncoder;
+                for (int i = 0; i < m_param->frameNumThreads; i++)
+                {
+                    prevEncoder = m_frameEncoder[i];
+                    prevFrame = prevEncoder->m_frame;
+                    if (prevFrame && (prevEncoder->m_frame->m_poc == poc - 1))
+                    {
+                        prevFrame = prevEncoder->m_frame;
+                        break;
+                    }
+                }
+            }
+        }
+        x265_ctu_info_t* ctuTemp, *prevCtuTemp;
+        if (curFrame)
+        {
+            if (!curFrame->m_ctuInfo)
+                CHECKED_MALLOC(curFrame->m_ctuInfo, x265_ctu_info_t*, 1);
+            CHECKED_MALLOC(*curFrame->m_ctuInfo, x265_ctu_info_t, numCUsInFrame);
+            CHECKED_MALLOC_ZERO(curFrame->m_prevCtuInfoChange, int, numCUsInFrame * maxNum8x8Partitions);
+            for (uint32_t i = 0; i < numCUsInFrame; i++)
+            {
+                ctuTemp = *curFrame->m_ctuInfo + i;
+                CHECKED_MALLOC(frameCTU, int32_t, maxNum8x8Partitions);
+                ctuTemp->ctuInfo = (int32_t*)frameCTU;
+                ctuTemp->ctuAddress = frameCtuInfo[i]->ctuAddress;
+                memcpy(ctuTemp->ctuPartitions, frameCtuInfo[i]->ctuPartitions, sizeof(int32_t) * maxNum8x8Partitions);
+                memcpy(ctuTemp->ctuInfo, frameCtuInfo[i]->ctuInfo, sizeof(int32_t) * maxNum8x8Partitions);
+                if (prevFrame && curFrame->m_poc > 1)
+                {
+                    prevCtuTemp = *prevFrame->m_ctuInfo + i;
+                    for (uint32_t j = 0; j < maxNum8x8Partitions; j++)
+                        curFrame->m_prevCtuInfoChange[i * maxNum8x8Partitions + j] = (*((int32_t *)prevCtuTemp->ctuInfo + j) == 2) ? (poc - 1) : prevFrame->m_prevCtuInfoChange[i * maxNum8x8Partitions + j];
+                }
+            }
+            copied = true;
+            curFrame->m_copied.trigger();
+        }
+        else
+        {
+            FrameEncoder* curEncoder;
+            for (int i = 0; i < m_param->frameNumThreads; i++)
+            {
+                curEncoder = m_frameEncoder[i];
+                curFrame = curEncoder->m_frame;
+                if (curFrame)
+                {
+                    if (poc == curFrame->m_poc)
+                    {
+                        if (!curFrame->m_ctuInfo)
+                            CHECKED_MALLOC(curFrame->m_ctuInfo, x265_ctu_info_t*, 1);
+                        CHECKED_MALLOC(*curFrame->m_ctuInfo, x265_ctu_info_t, numCUsInFrame);
+                        CHECKED_MALLOC_ZERO(curFrame->m_prevCtuInfoChange, int, numCUsInFrame * maxNum8x8Partitions);
+                        for (uint32_t l = 0; l < numCUsInFrame; l++)
+                        {
+                            ctuTemp = *curFrame->m_ctuInfo + l;
+                            CHECKED_MALLOC(frameCTU, int32_t, maxNum8x8Partitions);
+                            ctuTemp->ctuInfo = (int32_t*)frameCTU;
+                            ctuTemp->ctuAddress = frameCtuInfo[l]->ctuAddress;
+                            memcpy(ctuTemp->ctuPartitions, frameCtuInfo[l]->ctuPartitions, sizeof(int32_t) * maxNum8x8Partitions);
+                            memcpy(ctuTemp->ctuInfo, frameCtuInfo[l]->ctuInfo, sizeof(int32_t) * maxNum8x8Partitions);
+                            if (prevFrame && curFrame->m_poc > 1)
+                            {
+                                prevCtuTemp = *prevFrame->m_ctuInfo + l;
+                                for (uint32_t j = 0; j < maxNum8x8Partitions; j++)
+                                    curFrame->m_prevCtuInfoChange[l * maxNum8x8Partitions + j] = (*((int32_t *)prevCtuTemp->ctuInfo + j) == CTU_INFO_CHANGE) ? (poc - 1) : prevFrame->m_prevCtuInfoChange[l * maxNum8x8Partitions + j];
+                            }
+                        }
+                        copied = true;
+                        curFrame->m_copied.trigger();
+                        break;
+                    }
+                }
+            }
+        }
+    } while (!copied);
+    return;
+fail:
+    for (uint32_t i = 0; i < numCUsInFrame; i++)
+    {
+        X265_FREE((*curFrame->m_ctuInfo + i)->ctuInfo);
+        (*curFrame->m_ctuInfo + i)->ctuInfo = NULL;
+    }
+    X265_FREE(*curFrame->m_ctuInfo);
+    *(curFrame->m_ctuInfo) = NULL;
+    X265_FREE(curFrame->m_ctuInfo);
+    curFrame->m_ctuInfo = NULL;
+    X265_FREE(curFrame->m_prevCtuInfoChange);
+    curFrame->m_prevCtuInfoChange = NULL;
+}
+
 void EncStats::addPsnr(double psnrY, double psnrU, double psnrV)
 {
     m_psnrSumY += psnrY;
diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/encoder/encoder.h
--- a/source/encoder/encoder.h	Tue May 09 12:43:04 2017 +0530
+++ b/source/encoder/encoder.h	Mon Apr 24 10:13:57 2017 +0530
@@ -199,6 +199,8 @@
 
     int reconfigureParam(x265_param* encParam, x265_param* param);
 
+    void copyCtuInfo(x265_ctu_info_t** frameCtuInfo, int poc);
+
     void getStreamHeaders(NALList& list, Entropy& sbacCoder, Bitstream& bs);
 
     void fetchStats(x265_stats* stats, size_t statsSizeBytes);
diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/encoder/frameencoder.cpp
--- a/source/encoder/frameencoder.cpp	Tue May 09 12:43:04 2017 +0530
+++ b/source/encoder/frameencoder.cpp	Mon Apr 24 10:13:57 2017 +0530
@@ -295,6 +295,11 @@
 
     while (m_threadActive)
     {
+        if (m_param->bCTUInfo)
+        {
+            while (!m_frame->m_ctuInfo)
+                m_frame->m_copied.wait();
+        }
         compressFrame();
         m_done.trigger(); /* FrameEncoder::getEncodedPicture() blocks for this event */
         m_enable.wait();
diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/x265.h
--- a/source/x265.h	Tue May 09 12:43:04 2017 +0530
+++ b/source/x265.h	Mon Apr 24 10:13:57 2017 +0530
@@ -160,6 +160,20 @@
     x265_cu_stats    cuStats;
     double           totalFrameTime;
 } x265_frame_stats;
+typedef struct x265_ctu_info_t
+{
+    int32_t ctuAddress;
+    int32_t ctuPartitions[64];
+    void*    ctuInfo;
+} x265_ctu_info_t;
+
+typedef enum
+{
+    NO_CTU_INFO = 0,
+    HAS_CTU_INFO = 1,
+    CTU_INFO_CHANGE = 2,
+}CTUInfo;
+
 
 /* Arbitrary User SEI
  * Payload size is in bytes and the payload pointer must be non-NULL. 
@@ -1391,6 +1405,9 @@
     /* Insert tone mapping information only for IDR frames and when the 
      * tone mapping information changes. */
     int       bDhdr10opt;
+
+    /* Determine how x265 react to the content information recieved through the API */
+    int       bCTUInfo;
 } x265_param;
 /* x265_param_alloc:
  *  Allocates an x265_param instance. The returned param structure is not
@@ -1581,6 +1598,12 @@
 
 int x265_encoder_intra_refresh(x265_encoder *);
 
+/* x265_encoder_ctu_info:
+ *    Copy CTU information such as ctu address and ctu partition structure of all
+ *    CTUs in each frame. The function is invoked only if "--ctu-info" is enabled and
+ *    the encoder will wait for this copy to complete if enabled.
+ */
+int x265_encoder_ctu_info(x265_encoder *, int poc, x265_ctu_info_t** ctu);
 /* x265_cleanup:
  *       release library static allocations, reset configured CTU size */
 void x265_cleanup(void);
@@ -1629,6 +1652,7 @@
 
     int           sizeof_frame_stats;   /* sizeof(x265_frame_stats) */
     int           (*encoder_intra_refresh)(x265_encoder*);
+    int           (*encoder_ctu_info)(x265_encoder*, int, x265_ctu_info_t**);
     /* add new pointers to the end, or increment X265_MAJOR_VERSION */
 } x265_api;
 
diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/x265cli.h
--- a/source/x265cli.h	Tue May 09 12:43:04 2017 +0530
+++ b/source/x265cli.h	Mon Apr 24 10:13:57 2017 +0530
@@ -122,6 +122,7 @@
     { "scenecut",       required_argument, NULL, 0 },
     { "no-scenecut",          no_argument, NULL, 0 },
     { "scenecut-bias",  required_argument, NULL, 0 },
+    { "ctu-info",       required_argument, NULL, 0 },
     { "intra-refresh",        no_argument, NULL, 0 },
     { "rc-lookahead",   required_argument, NULL, 0 },
     { "lookahead-slices", required_argument, NULL, 0 },
@@ -367,6 +368,11 @@
     H1("   --[no-]tskip-fast             Enable fast intra transform skipping. Default %s\n", OPT(param->bEnableTSkipFast));
     H1("   --nr-intra <integer>          An integer value in range of 0 to 2000, which denotes strength of noise reduction in intra CUs. Default 0\n");
     H1("   --nr-inter <integer>          An integer value in range of 0 to 2000, which denotes strength of noise reduction in inter CUs. Default 0\n");
+    H0("   --ctu-info <integer>          Enable receiving ctu information asynchronously and determine reaction to the CTU information (0, 1, 2, 4, 6) Default 0\n"
+       "                                    - 1: force the partitions if CTU information is present\n"
+       "                                    - 2: functionality of (1) and reduce qp if CTU information has changed\n"
+       "                                    - 4: functionality of (1) and force Inter modes when CTU Information has changed, merge/skip otherwise\n"
+       "                                    Enable this option only when planning to invoke the API function x265_encoder_ctu_info to copy ctu-info asynchronously\n");
     H0("\nCoding tools:\n");
     H0("-w/--[no-]weightp                Enable weighted prediction in P slices. Default %s\n", OPT(param->bEnableWeightedPred));
     H0("   --[no-]weightb                Enable weighted prediction in B slices. Default %s\n", OPT(param->bEnableWeightedBiPred));


More information about the x265-devel mailing list