[x265] [PATCH SCC 02/09] Add profiletier, sps, pps MainScc profile support for scc extension

Anusuya Kumarasamy anusuya.kumarasamy at multicorewareinc.com
Wed Aug 7 17:19:51 UTC 2024


>From 85c51ad5a99db52001e254296ae64335074e47a5 Mon Sep 17 00:00:00 2001
From: AnusuyaKumarasamy <anusuya.kumarasamy at multicorewareinc.com>
Date: Thu, 18 Jul 2024 20:37:58 +0530
Subject: [PATCH 2/9] Add profiletier, sps, pps MainScc profile support for
scc
 extension

---
 source/common/slice.h      |  5 ++-
 source/encoder/encoder.cpp |  8 ++++
 source/encoder/entropy.cpp | 48 +++++++++++++++++---
 source/encoder/level.cpp   | 92 +++++++++++++++++++++++++++++++++++---
 source/x265.h              |  6 +++
 5 files changed, 147 insertions(+), 12 deletions(-)

diff --git a/source/common/slice.h b/source/common/slice.h
index 0d6807952..add5948f8 100644
--- a/source/common/slice.h
+++ b/source/common/slice.h
@@ -76,7 +76,8 @@ namespace Profile {
         HIGHTHROUGHPUTREXT = 5,
         MULTIVIEWMAIN = 6,
         SCALABLEMAIN = 7,
-        SCALABLEMAIN10 = 8
+        SCALABLEMAIN10 = 8,
+        MAINSCC = 9
     };
 }

@@ -324,6 +325,8 @@ struct PPS

     bool     pps_extension_flag;
     int      maxViews;
+
+    int      profileIdc;
 };

 struct WeightParam
diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp
index ff8f53883..095009200 100644
--- a/source/encoder/encoder.cpp
+++ b/source/encoder/encoder.cpp
@@ -3656,6 +3656,8 @@ void Encoder::initSPS(SPS *sps)
     }
 #endif

+    sps->sps_extension_flag = m_param->bEnableSCC ? true : false;
+
 }

 void Encoder::initPPS(PPS *pps)
@@ -3710,6 +3712,12 @@ void Encoder::initPPS(PPS *pps)
         pps->maxViews = m_param->numViews;
     }
 #endif
+
+    if (m_param->bEnableSCC)
+    {
+        pps->profileIdc = Profile::MAINSCC;
+        pps->pps_extension_flag = true;
+    }
 }

 void Encoder::configureZone(x265_param *p, x265_param *zone)
diff --git a/source/encoder/entropy.cpp b/source/encoder/entropy.cpp
index 0e45b4976..400a7dd8e 100644
--- a/source/encoder/entropy.cpp
+++ b/source/encoder/entropy.cpp
@@ -585,7 +585,7 @@ void Entropy::codeSPS(const SPS& sps, const
ScalingList& scalingList, const Prof
     WRITE_FLAG(sps.sps_extension_flag, "sps_extension_flag");

 #if ENABLE_MULTIVIEW
-    if (sps.sps_extension_flag)
+    if (sps.sps_extension_flag && sps.maxViews > 1)
     {
         WRITE_FLAG(0, "sps_range_extensions_flag");
         WRITE_FLAG(sps.maxViews > 1, "sps_multilayer_extension_flag");
@@ -598,6 +598,18 @@ void Entropy::codeSPS(const SPS& sps, const
ScalingList& scalingList, const Prof
             WRITE_FLAG(1, "inter_view_mv_vert_constraint_flag");
     }
 #endif
+
+    if (ptl.profileIdc[0] == Profile::MAINSCC)
+    {
+        bool sps_extension_flags[NUM_EXTENSION_FLAGS] = { false };
+        sps_extension_flags[SCC_EXT_IDX] = true;
+        for (int i = 0; i < NUM_EXTENSION_FLAGS; i++)
+            WRITE_FLAG(sps_extension_flags[i], "sps_extension_flag");
+        WRITE_FLAG(1, "intra_block_copy_enabled_flag");
+        WRITE_FLAG(0, "palette_mode_enabled_flag");
+        WRITE_CODE(0, 2, "motion_vector_resolution_control_idc");
+        WRITE_FLAG(0, "intra_boundary_filter_disabled_flag");
+    }
 }

 void Entropy::codePPS( const PPS& pps, bool filerAcross, int
iPPSInitQpMinus26, int layer)
@@ -650,7 +662,7 @@ void Entropy::codePPS( const PPS& pps, bool
filerAcross, int iPPSInitQpMinus26,
     WRITE_FLAG(pps.pps_extension_flag, "pps_extension_flag");

 #if ENABLE_MULTIVIEW
-    if (pps.pps_extension_flag)
+    if (pps.pps_extension_flag && pps.maxViews > 1)
     {
         WRITE_FLAG(0, "pps_range_extensions_flag");
         WRITE_FLAG(pps.maxViews > 1, "pps_multilayer_extension_flag");
@@ -666,6 +678,18 @@ void Entropy::codePPS( const PPS& pps, bool
filerAcross, int iPPSInitQpMinus26,
         }
     }
 #endif
+
+
+    if (pps.profileIdc == Profile::MAINSCC)
+    {
+        bool pps_extension_flags[NUM_EXTENSION_FLAGS] = { false };
+        pps_extension_flags[SCC_EXT_IDX] = true;
+        for (int i = 0; i < NUM_EXTENSION_FLAGS; i++)
+            WRITE_FLAG(pps_extension_flags[i], "pps_extension_flag");
+        WRITE_FLAG(1, "curr_pic_as_ref_enabled_pps_flag");
+        WRITE_FLAG(0, "adaptive_colour_trans_flag");
+        WRITE_FLAG(0, "palette_predictor_initializer_flag");
+    }
 }

 void Entropy::codeProfileTier(const ProfileTierLevel& ptl, int
maxTempSubLayers, int layer)
@@ -686,7 +710,7 @@ void Entropy::codeProfileTier(const ProfileTierLevel&
ptl, int maxTempSubLayers,
     WRITE_FLAG(ptl.nonPackedConstraintFlag,
"general_non_packed_constraint_flag");
     WRITE_FLAG(ptl.frameOnlyConstraintFlag,
"general_frame_only_constraint_flag");

-    if (ptl.profileIdc[layer] == Profile::MAINREXT ||
ptl.profileIdc[layer] == Profile::HIGHTHROUGHPUTREXT ||
ptl.profileIdc[layer] == Profile::SCALABLEMAIN || ptl.profileIdc[layer] ==
Profile::SCALABLEMAIN10 || ptl.profileIdc[layer] == Profile::MULTIVIEWMAIN)
+    if (ptl.profileIdc[layer] == Profile::MAINREXT ||
ptl.profileIdc[layer] == Profile::HIGHTHROUGHPUTREXT ||
ptl.profileIdc[layer] == Profile::SCALABLEMAIN || ptl.profileIdc[layer] ==
Profile::SCALABLEMAIN10 || ptl.profileIdc[layer] == Profile::MULTIVIEWMAIN
|| ptl.profileIdc[layer] == Profile::MAINSCC)
     {
         uint32_t bitDepthConstraint = ptl.bitDepthConstraint;
         int csp = ptl.chromaFormatConstraint;
@@ -699,9 +723,19 @@ void Entropy::codeProfileTier(const ProfileTierLevel&
ptl, int maxTempSubLayers,
         WRITE_FLAG(ptl.intraConstraintFlag,
 "general_intra_constraint_flag");

 WRITE_FLAG(ptl.onePictureOnlyConstraintFlag,"general_one_picture_only_constraint_flag");
         WRITE_FLAG(ptl.lowerBitRateConstraintFlag,
"general_lower_bit_rate_constraint_flag");
-        WRITE_CODE(0 , 16, "XXX_reserved_zero_35bits[0..15]");
-        WRITE_CODE(0 , 16, "XXX_reserved_zero_35bits[16..31]");
-        WRITE_CODE(0 ,  3, "XXX_reserved_zero_35bits[32..34]");
+        if (ptl.profileIdc[layer] == Profile::MAINSCC)
+        {
+            WRITE_FLAG(bitDepthConstraint <= 14,
"max_14bit_constraint_flag");
+            WRITE_CODE(0, 16, "reserved_zero_33bits[0..15]");
+            WRITE_CODE(0, 16, "reserved_zero_33bits[16..31]");
+            WRITE_FLAG(0, "reserved_zero_33bits[32]");
+        }
+        else
+        {
+            WRITE_CODE(0, 16, "XXX_reserved_zero_35bits[0..15]");
+            WRITE_CODE(0, 16, "XXX_reserved_zero_35bits[16..31]");
+            WRITE_CODE(0, 3, "XXX_reserved_zero_35bits[32..34]");
+        }
     }
     else
     {
@@ -709,6 +743,8 @@ void Entropy::codeProfileTier(const ProfileTierLevel&
ptl, int maxTempSubLayers,
         WRITE_CODE(0, 16, "XXX_reserved_zero_44bits[16..31]");
         WRITE_CODE(0, 12, "XXX_reserved_zero_44bits[32..43]");
     }
+    if (ptl.profileIdc[layer] == Profile::MAINSCC)
+        WRITE_FLAG(false, "inbld_flag");

     WRITE_CODE(ptl.levelIdc, 8, "general_level_idc");

diff --git a/source/encoder/level.cpp b/source/encoder/level.cpp
index 12803baff..b5af25b4f 100644
--- a/source/encoder/level.cpp
+++ b/source/encoder/level.cpp
@@ -60,6 +60,40 @@ LevelSpec levels[] =
     { MAX_UINT, MAX_UINT, MAX_UINT, MAX_UINT, MAX_UINT, MAX_UINT, 1,
Level::LEVEL8_5, "8.5", 85 },
 };

+enum SCCProfileName
+{
+    NONE = 0,
+    // The following are SCC profiles, which would map to the MAINSCC
profile idc.
+    // The enumeration indicates the bit-depth constraint in the bottom 2
digits
+    //                           the chroma format in the next digit
+    //                           the intra constraint in the next digit
+    //                           If it is a SCC profile there is a '2' for
the next digit.
+    //                           If it is a highthroughput , there is a
'2' for the top digit else '1' for the top digit
+    SCC_MAIN = 121108,
+    SCC_MAIN_10 = 121110,
+    SCC_MAIN_444 = 121308,
+    SCC_MAIN_444_10 = 121310,
+};
+
+static const SCCProfileName validSCCProfileNames[1][4/* bit depth
constraint 8=0, 10=1, 12=2, 14=3*/][4/*chroma format*/] =
+{
+   {
+        { NONE,         SCC_MAIN,      NONE,      SCC_MAIN_444
        }, // 8-bit  intra for 400, 420, 422 and 444
+        { NONE,         SCC_MAIN_10,   NONE,      SCC_MAIN_444_10
         }, // 10-bit intra for 400, 420, 422 and 444
+        { NONE,         NONE,          NONE,      NONE
        }, // 12-bit intra for 400, 420, 422 and 444
+        { NONE,         NONE,          NONE,      NONE
        }  // 16-bit intra for 400, 420, 422 and 444
+    },
+};
+
+static inline int _confirm(x265_param* param, bool bflag, const char*
message)
+{
+    if (!bflag)
+        return 0;
+
+    x265_log(param, X265_LOG_ERROR, "%s\n", message);
+    return 1;
+}
+
 /* determine minimum decoder level required to decode the described video
*/
 void determineLevel(const x265_param &param, VPS& vps)
 {
@@ -79,7 +113,9 @@ void determineLevel(const x265_param &param, VPS& vps)
         /* Probably an HEVC v1 profile, but must check to be sure */
         if (param.internalBitDepth <= 8)
         {
-            if (vps.ptl.onePictureOnlyConstraintFlag)
+            if (param.bEnableSCC)
+                vps.ptl.profileIdc[0] = Profile::MAINSCC;
+            else if (vps.ptl.onePictureOnlyConstraintFlag)
                 vps.ptl.profileIdc[0] = Profile::MAINSTILLPICTURE;
             else if (vps.ptl.intraConstraintFlag)
                 vps.ptl.profileIdc[0] = Profile::MAINREXT; /* Main Intra */
@@ -94,7 +130,9 @@ void determineLevel(const x265_param &param, VPS& vps)
         else if (param.internalBitDepth <= 10)
         {
             /* note there is no 10bit still picture profile */
-            if (vps.ptl.intraConstraintFlag)
+            if (param.bEnableSCC)
+                vps.ptl.profileIdc[0] = Profile::MAINSCC;
+            else if (vps.ptl.intraConstraintFlag)
                 vps.ptl.profileIdc[0] = Profile::MAINREXT; /* Main10 Intra
*/
             else
                 vps.ptl.profileIdc[0] = Profile::MAIN10;
@@ -114,6 +152,11 @@ void determineLevel(const x265_param &param, VPS& vps)
 #endif

     /* determine which profiles are compatible with this stream */
+    if (vps.ptl.profileIdc[0] == Profile::MAINSCC)
+    {
+        vps.ptl.onePictureOnlyConstraintFlag = false;
+        vps.ptl.intraConstraintFlag = param.keyframeMax <= 1 ||
vps.ptl.onePictureOnlyConstraintFlag;
+    }

     memset(vps.ptl.profileCompatibilityFlag, 0,
sizeof(vps.ptl.profileCompatibilityFlag));
     vps.ptl.profileCompatibilityFlag[vps.ptl.profileIdc[0]] = true;
@@ -128,6 +171,8 @@ void determineLevel(const x265_param &param, VPS& vps)
     }
     else if (vps.ptl.profileIdc[0] == Profile::MAINREXT)
         vps.ptl.profileCompatibilityFlag[Profile::MAINREXT] = true;
+    else if (vps.ptl.profileIdc[0] == Profile::MAINSCC)
+        vps.ptl.profileCompatibilityFlag[Profile::MAINSCC] = true;

     uint32_t lumaSamples = param.sourceWidth * param.sourceHeight;
     uint32_t samplesPerSec = (uint32_t)(lumaSamples *
((double)param.fpsNum / param.fpsDenom));
@@ -232,7 +277,23 @@ void determineLevel(const x265_param &param, VPS& vps)
         break;
     }

-    static const char *profiles[] = { "None", "Main", "Main 10", "Main
Still Picture", "RExt" };
+    x265_param m_param = param;
+#define CHECK(expr, msg) check_failed |= _confirm(&m_param, expr, msg)
+    int check_failed = 0; /* abort if there is a fatal configuration
problem */
+
+    if (vps.ptl.profileIdc[0] == Profile::MAINSCC)
+    {
+        CHECK(vps.ptl.lowerBitRateConstraintFlag == false &&
vps.ptl.intraConstraintFlag == false, "The lowerBitRateConstraint flag
cannot be false when intraConstraintFlag is false");
+        CHECK(param.bEnableSCC && !(vps.ptl.profileIdc[0] ==
Profile::MAINSCC), "UseIntraBlockCopy must not be enabled unless the SCC
profile is being used.");
+        CHECK(vps.ptl.intraConstraintFlag, "intra constraint flag must be
0 for SCC profiles");
+        CHECK(vps.ptl.onePictureOnlyConstraintFlag, "one-picture-only
constraint flag shall be 0 for SCC profiles");
+        const uint32_t bitDepthIdx = (vps.ptl.bitDepthConstraint == 8 ? 0
: (vps.ptl.bitDepthConstraint == 10 ? 1 : (vps.ptl.bitDepthConstraint == 12
? 2 : (vps.ptl.bitDepthConstraint == 16 ? 3 : 4))));
+        const uint32_t chromaFormatIdx =
uint32_t(vps.ptl.chromaFormatConstraint);
+        const bool bValidProfile = (bitDepthIdx > 2 || chromaFormatIdx >
3) ? false : (validSCCProfileNames[0][bitDepthIdx][chromaFormatIdx] !=
NONE);
+        CHECK(!bValidProfile, "Invalid intra constraint flag, bit depth
constraint flag and chroma format constraint flag combination for a RExt
profile");
+    }
+
+    static const char* profiles[] = { "None", "Main", "Main 10", "Main
Still Picture", "RExt", "", "", "", "", "Main Scc" };
     static const char *tiers[]    = { "Main", "High" };

     char profbuf[64];
@@ -292,6 +353,25 @@ void determineLevel(const x265_param &param, VPS& vps)
         if (vps.ptl.intraConstraintFlag && !bStillPicture)
             strcat(profbuf, " Intra");
     }
+
+    if (vps.ptl.profileIdc[0] == Profile::MAINSCC)
+    {
+        if (param.internalCsp == X265_CSP_I420)
+        {
+            if (vps.ptl.bitDepthConstraint <= 8)
+                strcpy(profbuf, "Main Scc");
+            else if (vps.ptl.bitDepthConstraint <= 10)
+                strcpy(profbuf, "Main 10 Scc");
+        }
+        else if (param.internalCsp == X265_CSP_I444)
+        {
+            if (vps.ptl.bitDepthConstraint <= 8)
+                strcpy(profbuf, "Main 4:4:4 Scc");
+            else if (vps.ptl.bitDepthConstraint <= 10)
+                strcpy(profbuf, "Main 4:4:4 10 Scc");
+        }
+    }
+
     x265_log(&param, X265_LOG_INFO, "%s profile, Level-%s (%s tier)\n",
              profbuf, levels[i].name, tiers[vps.ptl.tierFlag]);
 }
@@ -535,7 +615,8 @@ int x265_param_apply_profile(x265_param *param, const
char *profile)
     if (!strcmp(profile, "main") || !strcmp(profile, "main-intra") ||
         !strcmp(profile, "main10") || !strcmp(profile, "main10-intra") ||
         !strcmp(profile, "main12") || !strcmp(profile, "main12-intra") ||
-        !strcmp(profile, "mainstillpicture") || !strcmp(profile, "msp"))
+        !strcmp(profile, "mainstillpicture") || !strcmp(profile, "msp") ||
+        !strcmp(profile, "main-scc") || !strcmp(profile, "main10-scc"))
     {
         if (param->internalCsp != X265_CSP_I420)
         {
@@ -558,7 +639,8 @@ int x265_param_apply_profile(x265_param *param, const
char *profile)
              !strcmp(profile, "main444-intra") || !strcmp(profile,
"main444-stillpicture") ||
              !strcmp(profile, "main444-10") || !strcmp(profile,
"main444-10-intra") ||
              !strcmp(profile, "main444-12") || !strcmp(profile,
"main444-12-intra") ||
-             !strcmp(profile, "main444-16-intra") || !strcmp(profile,
"main444-16-stillpicture"))
+             !strcmp(profile, "main444-16-intra") || !strcmp(profile,
"main444-16-stillpicture") ||
+             !strcmp(profile, "main444-scc") || !strcmp(profile,
"main444-10-scc"))
     {
         /* any color space allowed */
     }
diff --git a/source/x265.h b/source/x265.h
index 530ae4d81..abe3f16f0 100644
--- a/source/x265.h
+++ b/source/x265.h
@@ -654,6 +654,10 @@ typedef enum
 #define MAX_LAYERS              1
 #endif

+/* SCC Extension Options */
+#define SCC_EXT_IDX               3
+#define NUM_EXTENSION_FLAGS       8
+
 #define X265_IPRATIO_STRENGTH   1.43

 typedef struct x265_cli_csp
@@ -2365,6 +2369,8 @@ static const char * const x265_profile_names[] = {
     "main444-12", "main444-12-intra",

     "main444-16-intra", "main444-16-stillpicture", /* Not Supported! */
+
+    "main-scc", "main10-scc", "main444-scc", "main444-10-scc", /* Screen
content coding */
     0
 };

-- 
2.36.0.windows.1
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20240807/b6fe8ec5/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0002-Add-profiletier-sps-pps-MainScc-profile-support-for-.patch
Type: application/octet-stream
Size: 15704 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20240807/b6fe8ec5/attachment-0001.obj>


More information about the x265-devel mailing list