[x265] [PATCH Alpha 08/10] Add support for alpha in HLS

Anusuya Kumarasamy anusuya.kumarasamy at multicorewareinc.com
Mon Aug 5 11:09:18 UTC 2024


>From 3c8cc9c76566a87f01cc6dc7c649afa5ddf540a1 Mon Sep 17 00:00:00 2001
From: AnusuyaKumarasamy <anusuya.kumarasamy at multicorewareinc.com>
Date: Wed, 3 Jul 2024 10:07:03 +0530
Subject: [PATCH] Add support for alpha in HLS

---
 source/common/slice.h           |  21 +++-
 source/encoder/api.cpp          |   6 +-
 source/encoder/encoder.cpp      |  81 +++++++++++--
 source/encoder/entropy.cpp      | 194 +++++++++++++++++++++++++++-----
 source/encoder/entropy.h        |  12 +-
 source/encoder/frameencoder.cpp |   4 +-
 source/encoder/level.cpp        |  40 ++++---
 source/encoder/ratecontrol.cpp  |   2 +-
 source/encoder/sei.h            |  35 ++++++
 source/x265.h                   |   3 +
 10 files changed, 330 insertions(+), 68 deletions(-)

diff --git a/source/common/slice.h b/source/common/slice.h
index 83f4c488f..c85cf0972 100644
--- a/source/common/slice.h
+++ b/source/common/slice.h
@@ -73,7 +73,9 @@ namespace Profile {
         MAIN10 = 2,
         MAINSTILLPICTURE = 3,
         MAINREXT = 4,
-        HIGHTHROUGHPUTREXT = 5
+        HIGHTHROUGHPUTREXT = 5,
+        SCALABLEMAIN = 7,
+        SCALABLEMAIN10 = 8
     };
 }

@@ -106,7 +108,7 @@ namespace Level {

 struct ProfileTierLevel
 {
-    int      profileIdc;
+    int      profileIdc[MAX_SCALABLE_LAYERS];
     int      levelIdc;
     uint32_t minCrForLevel;
     uint32_t maxLumaSrForLevel;
@@ -159,6 +161,21 @@ struct VPS
     uint32_t         numReorderPics[MAX_T_LAYERS];
     uint32_t         maxDecPicBuffering[MAX_T_LAYERS];
     uint32_t         maxLatencyIncrease[MAX_T_LAYERS];
+
+#if ENABLE_ALPHA
+    bool             splitting_flag;
+    int              m_scalabilityMask[MAX_VPS_NUM_SCALABILITY_TYPES];
+    int              scalabilityTypes;
+    uint8_t          m_dimensionIdLen[MAX_VPS_NUM_SCALABILITY_TYPES];
+    uint8_t
 m_dimensionId[MAX_VPS_LAYER_ID_PLUS1][MAX_VPS_NUM_SCALABILITY_TYPES];
+    bool              m_nuhLayerIdPresentFlag;
+    uint8_t          m_layerIdInNuh[MAX_VPS_LAYER_ID_PLUS1];
+    uint8_t          m_layerIdInVps[MAX_VPS_LAYER_ID_PLUS1];
+    int              m_viewIdLen;
+    int              m_numLayers;
+    int              m_vpsNumLayerSetsMinus1;
+    bool             vps_extension_flag;
+#endif
 };

 struct Window
diff --git a/source/encoder/api.cpp b/source/encoder/api.cpp
index 60893f4d1..e21f541d9 100644
--- a/source/encoder/api.cpp
+++ b/source/encoder/api.cpp
@@ -185,7 +185,7 @@ x265_encoder *x265_encoder_open(x265_param *p)
     // will detect and set profile/tier/level in VPS
     determineLevel(*param, encoder->m_vps);

-    if (!param->bAllowNonConformance && encoder->m_vps.ptl.profileIdc ==
Profile::NONE)
+    if (!param->bAllowNonConformance && encoder->m_vps.ptl.profileIdc[0]
== Profile::NONE)
     {
         x265_log(param, X265_LOG_INFO, "non-conformant bitstreams not
allowed (--allow-non-conformance)\n");
         goto fail;
@@ -357,11 +357,11 @@ int x265_encoder_reconfig(x265_encoder* enc,
x265_param* param_in)
             VPS saveVPS;
             memcpy(&saveVPS.ptl, &encoder->m_vps.ptl, sizeof(saveVPS.ptl));
             determineLevel(*encoder->m_latestParam, encoder->m_vps);
-            if (saveVPS.ptl.profileIdc != encoder->m_vps.ptl.profileIdc ||
saveVPS.ptl.levelIdc != encoder->m_vps.ptl.levelIdc
+            if (saveVPS.ptl.profileIdc[0] !=
encoder->m_vps.ptl.profileIdc[0] || saveVPS.ptl.levelIdc !=
encoder->m_vps.ptl.levelIdc
                 || saveVPS.ptl.tierFlag != encoder->m_vps.ptl.tierFlag)
             {
                 x265_log(encoder->m_param, X265_LOG_WARNING,
"Profile/Level/Tier has changed from %d/%d/%s to %d/%d/%s.Cannot
reconfigure rate-control.\n",
-                         saveVPS.ptl.profileIdc, saveVPS.ptl.levelIdc,
saveVPS.ptl.tierFlag ? "High" : "Main", encoder->m_vps.ptl.profileIdc,
+                         saveVPS.ptl.profileIdc[0], saveVPS.ptl.levelIdc,
saveVPS.ptl.tierFlag ? "High" : "Main", encoder->m_vps.ptl.profileIdc[0],
                          encoder->m_vps.ptl.levelIdc,
encoder->m_vps.ptl.tierFlag ? "High" : "Main");
                 x265_copy_params(encoder->m_latestParam, &save);
                 memcpy(&encoder->m_vps.ptl, &saveVPS.ptl,
sizeof(saveVPS.ptl));
diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp
index 4ac71f654..5697ac5e5 100644
--- a/source/encoder/encoder.cpp
+++ b/source/encoder/encoder.cpp
@@ -3277,19 +3277,34 @@ void Encoder::getStreamHeaders(NALList& list,
Entropy& sbacCoder, Bitstream& bs)

     /* headers for start of bitstream */
     bs.resetBits();
-    sbacCoder.codeVPS(m_vps);
+    sbacCoder.codeVPS(m_vps, m_sps);
     bs.writeByteAlignment();
     list.serialize(NAL_UNIT_VPS, bs);

-    bs.resetBits();
-    sbacCoder.codeSPS(m_sps, m_scalingList, m_vps.ptl);
-    bs.writeByteAlignment();
-    list.serialize(NAL_UNIT_SPS, bs);
+    for (int layer = 0; layer < m_param->numScalableLayers; layer++)
+    {
+        bs.resetBits();
+        sbacCoder.codeSPS(m_sps, m_scalingList, m_vps.ptl, layer);
+        bs.writeByteAlignment();
+        list.serialize(NAL_UNIT_SPS, bs, layer);
+    }

-    bs.resetBits();
-    sbacCoder.codePPS(m_pps, (m_param->maxSlices <= 1), m_iPPSQpMinus26);
-    bs.writeByteAlignment();
-    list.serialize(NAL_UNIT_PPS, bs);
+    for (int layer = 0; layer < m_param->numScalableLayers; layer++)
+    {
+        bs.resetBits();
+        sbacCoder.codePPS(m_pps, (m_param->maxSlices <= 1),
m_iPPSQpMinus26, layer);
+        bs.writeByteAlignment();
+        list.serialize(NAL_UNIT_PPS, bs, layer);
+    }
+
+#if ENABLE_ALPHA
+    if (m_param->numScalableLayers > 1)
+    {
+        SEIAlphaChannelInfo m_alpha;
+        m_alpha.alpha_channel_cancel_flag = !m_param->numScalableLayers;
+        m_alpha.writeSEImessages(bs, m_sps, NAL_UNIT_PREFIX_SEI, list,
m_param->bSingleSeiNal);
+    }
+#endif

     if (m_param->bSingleSeiNal)
         bs.resetBits();
@@ -3370,6 +3385,54 @@ void Encoder::initVPS(VPS *vps)
     vps->ptl.interlacedSourceFlag = !!m_param->interlaceMode;
     vps->ptl.nonPackedConstraintFlag = false;
     vps->ptl.frameOnlyConstraintFlag = !m_param->interlaceMode;
+
+#if ENABLE_ALPHA
+    vps->vps_extension_flag = false;
+
+    if (m_param->numScalableLayers > 1)
+    {
+        vps->vps_extension_flag = true;
+        int dimIdLen = 0, auxDimIdLen = 0, maxAuxId = 1, auxId[2] = { 0,1
};
+        vps->splitting_flag = false;
+        memset(vps->m_scalabilityMask, 0, sizeof(vps->m_scalabilityMask));
+        memset(vps->m_layerIdInNuh, 0, sizeof(vps->m_layerIdInNuh));
+        memset(vps->m_layerIdInVps, 0, sizeof(vps->m_layerIdInVps));
+        memset(vps->m_dimensionIdLen, 0, sizeof(vps->m_dimensionIdLen));
+        vps->scalabilityTypes = 0;
+
+        vps->m_scalabilityMask[3] = 1;
+        vps->m_scalabilityMask[2] = 1;
+        for (int i = 0; i < MAX_VPS_NUM_SCALABILITY_TYPES; i++)
+        {
+            vps->scalabilityTypes += vps->m_scalabilityMask[i];
+        }
+
+        while ((1 << dimIdLen) < m_param->numScalableLayers)
+        {
+            dimIdLen++;
+        }
+        vps->m_dimensionIdLen[0] = dimIdLen;
+
+        for (int i = 1; i < m_param->numScalableLayers; i++)
+        {
+            vps->m_layerIdInNuh[i] = i;
+            vps->m_dimensionId[i][0] = i;
+            vps->m_layerIdInVps[vps->m_layerIdInNuh[i]] = i;
+            vps->m_dimensionId[i][1] = auxId[i];
+        }
+
+        while ((1 << auxDimIdLen) < (maxAuxId + 1))
+        {
+            auxDimIdLen++;
+        }
+        vps->m_dimensionIdLen[1] = auxDimIdLen;
+
+        vps->m_nuhLayerIdPresentFlag = 1;
+        vps->m_viewIdLen = 0;
+        vps->m_vpsNumLayerSetsMinus1 = 1;
+        vps->m_numLayers = m_param->numScalableLayers;
+    }
+#endif
 }

 void Encoder::initSPS(SPS *sps)
diff --git a/source/encoder/entropy.cpp b/source/encoder/entropy.cpp
index 18de2789e..cc8c83aea 100644
--- a/source/encoder/entropy.cpp
+++ b/source/encoder/entropy.cpp
@@ -230,11 +230,11 @@ Entropy::Entropy()
     X265_CHECK(sizeof(m_contextState) >= sizeof(m_contextState[0]) *
MAX_OFF_CTX_MOD, "context state table is too small\n");
 }

-void Entropy::codeVPS(const VPS& vps)
+void Entropy::codeVPS(const VPS& vps, const SPS& sps)
 {
     WRITE_CODE(0,       4, "vps_video_parameter_set_id");
     WRITE_CODE(3,       2, "vps_reserved_three_2bits");
-    WRITE_CODE(0,       6, "vps_reserved_zero_6bits");
+    WRITE_CODE(vps.m_numLayers - 1, 6, "vps_reserved_zero_6bits");
     WRITE_CODE(vps.maxTempSubLayers - 1, 3, "vps_max_sub_layers_minus1");
     WRITE_FLAG(vps.maxTempSubLayers == 1,
"vps_temporal_id_nesting_flag");
     WRITE_CODE(0xffff, 16, "vps_reserved_ffff_16bits");
@@ -250,13 +250,137 @@ void Entropy::codeVPS(const VPS& vps)
         WRITE_UVLC(vps.maxLatencyIncrease[i] + 1,
"vps_max_latency_increase_plus1[i]");
     }

+#if ENABLE_ALPHA
+    if (vps.m_numLayers > 1)
+    {
+        WRITE_CODE(vps.m_numLayers - 1, 6,
"vps_max_nuh_reserved_zero_layer_id");
+        WRITE_UVLC(vps.m_vpsNumLayerSetsMinus1, "vps_max_op_sets_minus1");
+        for (int i = 1; i <= vps.m_vpsNumLayerSetsMinus1; i++)
+        {
+            for (int j = 0; j < vps.m_numLayers; j++)
+            {
+                WRITE_FLAG(1, "layer_id_included_flag[opsIdx][i]");
+            }
+        }
+    }
+    else
+    {
+        WRITE_CODE(0, 6, "vps_max_nuh_reserved_zero_layer_id");
+        WRITE_UVLC(0, "vps_max_op_sets_minus1");
+    }
+#else
     WRITE_CODE(0, 6, "vps_max_nuh_reserved_zero_layer_id");
-    WRITE_UVLC(0,    "vps_max_op_sets_minus1");
+    WRITE_UVLC(0, "vps_max_op_sets_minus1");
+#endif
+
     WRITE_FLAG(0,    "vps_timing_info_present_flag"); /* we signal timing
info in SPS-VUI */
-    WRITE_FLAG(0,    "vps_extension_flag");
+
+#if ENABLE_ALPHA
+    WRITE_FLAG(vps.vps_extension_flag, "vps_extension_flag");
+
+    if (vps.vps_extension_flag)
+    {
+        while (m_bitIf->getNumberOfWrittenBits() % X265_BYTE != 0)
+        {
+            WRITE_FLAG(1, "vps_extension_alignment_bit_equal_to_one");
+        }
+
+        WRITE_CODE(vps.ptl.levelIdc, 8, "general_level_idc");
+
+        WRITE_FLAG(vps.splitting_flag, "splitting flag");
+        for (int i = 0; i < MAX_VPS_NUM_SCALABILITY_TYPES; i++)
+        {
+            WRITE_FLAG(vps.m_scalabilityMask[i], "scalability_mask[i]");
+        }
+        for (int i = 0; i < vps.scalabilityTypes - vps.splitting_flag; i++)
+        {
+            WRITE_CODE(vps.m_dimensionIdLen[i] - 1, 3,
"dimension_id_len_minus1[i]");
+        }
+        WRITE_FLAG(vps.m_nuhLayerIdPresentFlag,
"vps_nuh_layer_id_present_flag");
+        for (int i = 1; i < vps.m_numLayers; i++)
+        {
+            if (vps.m_nuhLayerIdPresentFlag)
+                WRITE_CODE(vps.m_layerIdInNuh[i], 6, "layer_id_in_nuh[i]");
+
+            if (!vps.splitting_flag)
+            {
+                for (int j = 0; j < vps.scalabilityTypes; j++)
+                {
+                    uint8_t bits = vps.m_dimensionIdLen[j];
+                    WRITE_CODE(vps.m_dimensionId[i][j], bits,
"dimension_id[i][j]");
+                }
+            }
+        }
+        WRITE_CODE(vps.m_viewIdLen, 4, "view_id_len");
+
+        WRITE_FLAG(0, "direct_dependency_flag[1][0]");
+        WRITE_UVLC(0, "num_add_layer_sets");
+        WRITE_FLAG(0, "vps_sub_layers_max_minus1_present_flag");
+        WRITE_FLAG(0, "max_tid_ref_present_flag");
+        WRITE_FLAG(0, "default_ref_layers_active_flag");
+        WRITE_UVLC(2, "vps_num_profile_tier_level_minus1");
+        WRITE_FLAG(1, "vps_profile_present_flag");
+        codeProfileTier(vps.ptl, vps.maxTempSubLayers, 1);
+
+        WRITE_UVLC(0, "num_add_olss");
+        WRITE_CODE(0, 2, "default_output_layer_idc");
+        WRITE_CODE(1, 2, "profile_tier_level_idx[ i ][ j ]");
+        WRITE_CODE(2, 2, "profile_tier_level_idx[ i ][ j ]");
+
+        WRITE_UVLC(0, "vps_num_rep_formats_minus1");
+
+        WRITE_CODE(sps.picWidthInLumaSamples, 16,
"pic_width_vps_in_luma_samples");
+        WRITE_CODE(sps.picHeightInLumaSamples, 16,
"pic_height_vps_in_luma_samples");
+        WRITE_FLAG(1, "chroma_and_bit_depth_vps_present_flag");
+
+        WRITE_CODE(sps.chromaFormatIdc, 2, "chroma_format_vps_idc");
+
+        if (sps.chromaFormatIdc == X265_CSP_I444)
+            WRITE_FLAG(0, "separate_colour_plane_vps_flag");
+
+        WRITE_CODE(X265_DEPTH - 8, 4, "bit_depth_vps_luma_minus8");
+        WRITE_CODE(X265_DEPTH - 8, 4, "bit_depth_vps_chroma_minus8");
+
+        const Window& conf = sps.conformanceWindow;
+        WRITE_FLAG(conf.bEnabled, "conformance_window_vps_flag");
+        if (conf.bEnabled)
+        {
+            int hShift = CHROMA_H_SHIFT(sps.chromaFormatIdc), vShift =
CHROMA_V_SHIFT(sps.chromaFormatIdc);
+            WRITE_UVLC(conf.leftOffset >> hShift,
"conf_win_vps_left_offset");
+            WRITE_UVLC(conf.rightOffset >> hShift,
"conf_win_vps_right_offset");
+            WRITE_UVLC(conf.topOffset >> vShift,
"conf_win_vps_top_offset");
+            WRITE_UVLC(conf.bottomOffset >> vShift,
"conf_win_vps_bottom_offset");
+        }
+
+        WRITE_FLAG(1, "max_one_active_ref_layer_flag");
+        WRITE_FLAG(0, "vps_poc_lsb_aligned_flag");
+        WRITE_FLAG(1, "poc_lsb_not_present_flag[");
+        WRITE_FLAG(0, "sub_layer_flag_info_present_flag");
+
+        for (int i = 1; i <= 1; i++)
+        {
+            for (int j = 0; j < vps.m_numLayers; j++)
+            {
+                WRITE_UVLC(vps.maxDecPicBuffering[0] - 1,
"vps_max_dec_pic_buffering_minus1[i]");
+            }
+        }
+
+        WRITE_UVLC(vps.numReorderPics[0], "vps_num_reorder_pics[i]");
+        WRITE_UVLC(vps.maxLatencyIncrease[0] + 1,
"vps_max_latency_increase_plus1[i]");
+
+        WRITE_UVLC(0, "direct_dep_type_len_minus2");
+
+        WRITE_FLAG(0, "default_direct_dependency_flag");
+        WRITE_UVLC(0, "vps_non_vui_extension_length");
+        WRITE_FLAG(0, "vps_vui_present_flag");
+        WRITE_FLAG(0, "vps_extension2_flag");
+    }
+#else
+    WRITE_FLAG(0, "vps_extension_flag");
+#endif
 }

-void Entropy::codeSPS(const SPS& sps, const ScalingList& scalingList,
const ProfileTierLevel& ptl)
+void Entropy::codeSPS(const SPS& sps, const ScalingList& scalingList,
const ProfileTierLevel& ptl, int layer)
 {
     WRITE_CODE(0, 4, "sps_video_parameter_set_id");
     WRITE_CODE(sps.maxTempSubLayers - 1, 3, "sps_max_sub_layers_minus1");
@@ -264,7 +388,7 @@ void Entropy::codeSPS(const SPS& sps, const
ScalingList& scalingList, const Prof

     codeProfileTier(ptl, sps.maxTempSubLayers);

-    WRITE_UVLC(0, "sps_seq_parameter_set_id");
+    WRITE_UVLC(layer, "sps_seq_parameter_set_id");
     WRITE_UVLC(sps.chromaFormatIdc, "chroma_format_idc");

     if (sps.chromaFormatIdc == X265_CSP_I444)
@@ -322,15 +446,15 @@ void Entropy::codeSPS(const SPS& sps, const
ScalingList& scalingList, const Prof
     WRITE_FLAG(sps.bUseStrongIntraSmoothing,
"sps_strong_intra_smoothing_enable_flag");

     WRITE_FLAG(1, "vui_parameters_present_flag");
-    codeVUI(sps.vuiParameters, sps.maxTempSubLayers,
sps.bEmitVUITimingInfo, sps.bEmitVUIHRDInfo);
+    codeVUI(sps.vuiParameters, sps.maxTempSubLayers,
sps.bEmitVUITimingInfo, sps.bEmitVUIHRDInfo, layer);

     WRITE_FLAG(0, "sps_extension_flag");
 }

-void Entropy::codePPS( const PPS& pps, bool filerAcross, int
iPPSInitQpMinus26 )
+void Entropy::codePPS( const PPS& pps, bool filerAcross, int
iPPSInitQpMinus26, int layer)
 {
-    WRITE_UVLC(0,                          "pps_pic_parameter_set_id");
-    WRITE_UVLC(0,                          "pps_seq_parameter_set_id");
+    WRITE_UVLC(layer,                          "pps_pic_parameter_set_id");
+    WRITE_UVLC(layer,                          "pps_seq_parameter_set_id");
     WRITE_FLAG(0,
 "dependent_slice_segments_enabled_flag");
     WRITE_FLAG(0,                          "output_flag_present_flag");
     WRITE_CODE(0, 3,                       "num_extra_slice_header_bits");
@@ -377,20 +501,25 @@ void Entropy::codePPS( const PPS& pps, bool
filerAcross, int iPPSInitQpMinus26 )
     WRITE_FLAG(0, "pps_extension_flag");
 }

-void Entropy::codeProfileTier(const ProfileTierLevel& ptl, int
maxTempSubLayers)
+void Entropy::codeProfileTier(const ProfileTierLevel& ptl, int
maxTempSubLayers, int layer)
 {
     WRITE_CODE(0, 2,                "XXX_profile_space[]");
     WRITE_FLAG(ptl.tierFlag,        "XXX_tier_flag[]");
-    WRITE_CODE(ptl.profileIdc, 5,   "XXX_profile_idc[]");
+    WRITE_CODE(ptl.profileIdc[layer], 5,   "XXX_profile_idc[]");
     for (int j = 0; j < 32; j++)
-        WRITE_FLAG(ptl.profileCompatibilityFlag[j],
"XXX_profile_compatibility_flag[][j]");
+    {
+        if (layer)
+            WRITE_FLAG(j == ptl.profileIdc[layer] ? 1 : 0,
"XXX_profile_compatibility_flag[][j]");
+        else
+            WRITE_FLAG(ptl.profileCompatibilityFlag[j],
"XXX_profile_compatibility_flag[][j]");
+    }

     WRITE_FLAG(ptl.progressiveSourceFlag,
"general_progressive_source_flag");
     WRITE_FLAG(ptl.interlacedSourceFlag,
 "general_interlaced_source_flag");
     WRITE_FLAG(ptl.nonPackedConstraintFlag,
"general_non_packed_constraint_flag");
     WRITE_FLAG(ptl.frameOnlyConstraintFlag,
"general_frame_only_constraint_flag");

-    if (ptl.profileIdc == Profile::MAINREXT || ptl.profileIdc ==
Profile::HIGHTHROUGHPUTREXT)
+    if (ptl.profileIdc[layer] == Profile::MAINREXT ||
ptl.profileIdc[layer] == Profile::HIGHTHROUGHPUTREXT ||
ptl.profileIdc[layer] == Profile::SCALABLEMAIN || ptl.profileIdc[layer] ==
Profile::SCALABLEMAIN10)
     {
         uint32_t bitDepthConstraint = ptl.bitDepthConstraint;
         int csp = ptl.chromaFormatConstraint;
@@ -428,7 +557,7 @@ void Entropy::codeProfileTier(const ProfileTierLevel&
ptl, int maxTempSubLayers)
     }
 }

-void Entropy::codeVUI(const VUI& vui, int maxSubTLayers, bool
bEmitVUITimingInfo, bool bEmitVUIHRDInfo)
+void Entropy::codeVUI(const VUI& vui, int maxSubTLayers, bool
bEmitVUITimingInfo, bool bEmitVUIHRDInfo, int layer)
 {
     WRITE_FLAG(vui.aspectRatioInfoPresentFlag,
"aspect_ratio_info_present_flag");
     if (vui.aspectRatioInfoPresentFlag)
@@ -479,23 +608,28 @@ void Entropy::codeVUI(const VUI& vui, int
maxSubTLayers, bool bEmitVUITimingInfo
         WRITE_UVLC(vui.defaultDisplayWindow.bottomOffset,
"def_disp_win_bottom_offset");
     }

-    if (!bEmitVUITimingInfo)
+    if(layer)
         WRITE_FLAG(0, "vui_timing_info_present_flag");
     else
     {
-        WRITE_FLAG(1, "vui_timing_info_present_flag");
-        WRITE_CODE(vui.timingInfo.numUnitsInTick, 32,
"vui_num_units_in_tick");
-        WRITE_CODE(vui.timingInfo.timeScale, 32, "vui_time_scale");
-        WRITE_FLAG(0, "vui_poc_proportional_to_timing_flag");
-    }
+        if (!bEmitVUITimingInfo)
+            WRITE_FLAG(0, "vui_timing_info_present_flag");
+        else
+        {
+            WRITE_FLAG(1, "vui_timing_info_present_flag");
+            WRITE_CODE(vui.timingInfo.numUnitsInTick, 32,
"vui_num_units_in_tick");
+            WRITE_CODE(vui.timingInfo.timeScale, 32, "vui_time_scale");
+            WRITE_FLAG(0, "vui_poc_proportional_to_timing_flag");
+        }

-    if (!bEmitVUIHRDInfo)
-        WRITE_FLAG(0, "vui_hrd_parameters_present_flag");
-    else
-    {
-        WRITE_FLAG(vui.hrdParametersPresentFlag,
"vui_hrd_parameters_present_flag");
-        if (vui.hrdParametersPresentFlag)
-            codeHrdParameters(vui.hrdParameters, maxSubTLayers);
+        if (!bEmitVUIHRDInfo)
+            WRITE_FLAG(0, "vui_hrd_parameters_present_flag");
+        else
+        {
+            WRITE_FLAG(vui.hrdParametersPresentFlag,
"vui_hrd_parameters_present_flag");
+            if (vui.hrdParametersPresentFlag)
+                codeHrdParameters(vui.hrdParameters, maxSubTLayers);
+        }
     }

     WRITE_FLAG(0, "bitstream_restriction_flag");
@@ -590,13 +724,13 @@ void Entropy::codeAUD(const Slice& slice)
     WRITE_CODE(picType, 3, "pic_type");
 }

-void Entropy::codeSliceHeader(const Slice& slice, FrameData& encData,
uint32_t slice_addr, uint32_t slice_addr_bits, int sliceQp)
+void Entropy::codeSliceHeader(const Slice& slice, FrameData& encData,
uint32_t slice_addr, uint32_t slice_addr_bits, int sliceQp, int layer)
 {
     WRITE_FLAG((slice_addr == 0 ? 1 : 0),
"first_slice_segment_in_pic_flag");
     if (slice.getRapPicFlag())
         WRITE_FLAG(0, "no_output_of_prior_pics_flag");

-    WRITE_UVLC(0, "slice_pic_parameter_set_id");
+    WRITE_UVLC(layer, "slice_pic_parameter_set_id");

     /* x265 does not use dependent slices, so always write all this data */
     if (slice_addr)
diff --git a/source/encoder/entropy.h b/source/encoder/entropy.h
index 366b1c077..4271701c7 100644
--- a/source/encoder/entropy.h
+++ b/source/encoder/entropy.h
@@ -141,14 +141,14 @@ public:
     void loadIntraDirModeLuma(const Entropy& src);
     void copyState(const Entropy& other);

-    void codeVPS(const VPS& vps);
-    void codeSPS(const SPS& sps, const ScalingList& scalingList, const
ProfileTierLevel& ptl);
-    void codePPS( const PPS& pps, bool filerAcross, int iPPSInitQpMinus26
);
-    void codeVUI(const VUI& vui, int maxSubTLayers, bool
bEmitVUITimingInfo, bool bEmitVUIHRDInfo);
+    void codeVPS(const VPS& vps, const SPS& sps);
+    void codeSPS(const SPS& sps, const ScalingList& scalingList, const
ProfileTierLevel& ptl, int layer = 0);
+    void codePPS( const PPS& pps, bool filerAcross, int iPPSInitQpMinus26,
int layer = 0);
+    void codeVUI(const VUI& vui, int maxSubTLayers, bool
bEmitVUITimingInfo, bool bEmitVUIHRDInfo, int layer = 0);
     void codeAUD(const Slice& slice);
     void codeHrdParameters(const HRDInfo& hrd, int maxSubTLayers);

-    void codeSliceHeader(const Slice& slice, FrameData& encData, uint32_t
slice_addr, uint32_t slice_addr_bits, int sliceQp);
+    void codeSliceHeader(const Slice& slice, FrameData& encData, uint32_t
slice_addr, uint32_t slice_addr_bits, int sliceQp, int layer = 0);
     void codeSliceHeaderWPPEntryPoints(const uint32_t *substreamSizes,
uint32_t numSubStreams, uint32_t maxOffset);
     void codeShortTermRefPicSet(const RPS& rps, int idx);
     void finishSlice()                 { encodeBinTrm(1); finish();
dynamic_cast<Bitstream*>(m_bitIf)->writeByteAlignment(); }
@@ -234,7 +234,7 @@ private:
     void writeEpExGolomb(uint32_t symbol, uint32_t count);
     void writeCoefRemainExGolomb(uint32_t symbol, const uint32_t
absGoRice);

-    void codeProfileTier(const ProfileTierLevel& ptl, int
maxTempSubLayers);
+    void codeProfileTier(const ProfileTierLevel& ptl, int
maxTempSubLayers, int layer = 0);
     void codeScalingList(const ScalingList&);
     void codeScalingList(const ScalingList& scalingList, uint32_t sizeId,
uint32_t listId);

diff --git a/source/encoder/frameencoder.cpp
b/source/encoder/frameencoder.cpp
index b36094f33..8d72adcf4 100644
--- a/source/encoder/frameencoder.cpp
+++ b/source/encoder/frameencoder.cpp
@@ -1095,7 +1095,7 @@ void FrameEncoder::compressFrame(int layer)
                 ScopedLock refIdxLock(m_top->m_sliceRefIdxLock);
                 m_top->analyseRefIdx(slice->m_numRefIdx);
             }
-            m_entropyCoder.codeSliceHeader(*slice,
*m_frame[layer]->m_encData, sliceAddr, m_sliceAddrBits, slice->m_sliceQp);
+            m_entropyCoder.codeSliceHeader(*slice,
*m_frame[layer]->m_encData, sliceAddr, m_sliceAddrBits, slice->m_sliceQp,
layer);

             // Find rows of current slice
             const uint32_t prevSliceRow = nextSliceRow;
@@ -1122,7 +1122,7 @@ void FrameEncoder::compressFrame(int layer)
             ScopedLock refIdxLock(m_top->m_sliceRefIdxLock);
             m_top->analyseRefIdx(slice->m_numRefIdx);
         }
-        m_entropyCoder.codeSliceHeader(*slice, *m_frame[layer]->m_encData,
0, 0, slice->m_sliceQp);
+        m_entropyCoder.codeSliceHeader(*slice, *m_frame[layer]->m_encData,
0, 0, slice->m_sliceQp, layer);

         // serialize each row, record final lengths in slice header
         uint32_t maxStreamSize =
m_nalList.serializeSubstreams(m_substreamSizes, numSubstreams,
m_outStreams);
diff --git a/source/encoder/level.cpp b/source/encoder/level.cpp
index b224a5d3f..c62c63426 100644
--- a/source/encoder/level.cpp
+++ b/source/encoder/level.cpp
@@ -80,38 +80,48 @@ void determineLevel(const x265_param &param, VPS& vps)
         if (param.internalBitDepth <= 8)
         {
             if (vps.ptl.onePictureOnlyConstraintFlag)
-                vps.ptl.profileIdc = Profile::MAINSTILLPICTURE;
+                vps.ptl.profileIdc[0] = Profile::MAINSTILLPICTURE;
             else if (vps.ptl.intraConstraintFlag)
-                vps.ptl.profileIdc = Profile::MAINREXT; /* Main Intra */
+                vps.ptl.profileIdc[0] = Profile::MAINREXT; /* Main Intra */
             else
-                vps.ptl.profileIdc = Profile::MAIN;
+                vps.ptl.profileIdc[0] = Profile::MAIN;
+
+#if ENABLE_ALPHA
+            if (param.numScalableLayers == 2)
+                vps.ptl.profileIdc[1] = Profile::SCALABLEMAIN;
+#endif
         }
         else if (param.internalBitDepth <= 10)
         {
             /* note there is no 10bit still picture profile */
             if (vps.ptl.intraConstraintFlag)
-                vps.ptl.profileIdc = Profile::MAINREXT; /* Main10 Intra */
+                vps.ptl.profileIdc[0] = Profile::MAINREXT; /* Main10 Intra
*/
             else
-                vps.ptl.profileIdc = Profile::MAIN10;
+                vps.ptl.profileIdc[0] = Profile::MAIN10;
+
+#if ENABLE_ALPHA
+            if (param.numScalableLayers == 2)
+                vps.ptl.profileIdc[1] = Profile::SCALABLEMAIN10;
+#endif
         }
     }
     else
-        vps.ptl.profileIdc = Profile::MAINREXT;
+        vps.ptl.profileIdc[0] = Profile::MAINREXT;

     /* determine which profiles are compatible with this stream */

     memset(vps.ptl.profileCompatibilityFlag, 0,
sizeof(vps.ptl.profileCompatibilityFlag));
-    vps.ptl.profileCompatibilityFlag[vps.ptl.profileIdc] = true;
-    if (vps.ptl.profileIdc == Profile::MAIN10 && param.internalBitDepth ==
8)
+    vps.ptl.profileCompatibilityFlag[vps.ptl.profileIdc[0]] = true;
+    if (vps.ptl.profileIdc[0] == Profile::MAIN10 && param.internalBitDepth
== 8)
         vps.ptl.profileCompatibilityFlag[Profile::MAIN] = true;
-    else if (vps.ptl.profileIdc == Profile::MAIN)
+    else if (vps.ptl.profileIdc[0] == Profile::MAIN)
         vps.ptl.profileCompatibilityFlag[Profile::MAIN10] = true;
-    else if (vps.ptl.profileIdc == Profile::MAINSTILLPICTURE)
+    else if (vps.ptl.profileIdc[0] == Profile::MAINSTILLPICTURE)
     {
         vps.ptl.profileCompatibilityFlag[Profile::MAIN] = true;
         vps.ptl.profileCompatibilityFlag[Profile::MAIN10] = true;
     }
-    else if (vps.ptl.profileIdc == Profile::MAINREXT)
+    else if (vps.ptl.profileIdc[0] == Profile::MAINREXT)
         vps.ptl.profileCompatibilityFlag[Profile::MAINREXT] = true;

     uint32_t lumaSamples = param.sourceWidth * param.sourceHeight;
@@ -174,7 +184,7 @@ void determineLevel(const x265_param &param, VPS& vps)
         if (levels[i].levelEnum >= Level::LEVEL5 && param.maxCUSize < 32)
         {
             x265_log(&param, X265_LOG_WARNING, "level %s detected, but CTU
size 16 is non-compliant\n", levels[i].name);
-            vps.ptl.profileIdc = Profile::NONE;
+            vps.ptl.profileIdc[0] = Profile::NONE;
             vps.ptl.levelIdc = Level::NONE;
             vps.ptl.tierFlag = Level::MAIN;
             x265_log(&param, X265_LOG_INFO, "NONE profile, Level-NONE
(Main tier)\n");
@@ -186,7 +196,7 @@ void determineLevel(const x265_param &param, VPS& vps)
         if (numPocTotalCurr > 10)
         {
             x265_log(&param, X265_LOG_WARNING, "level %s detected, but
NumPocTotalCurr (total references) is non-compliant\n", levels[i].name);
-            vps.ptl.profileIdc = Profile::NONE;
+            vps.ptl.profileIdc[0] = Profile::NONE;
             vps.ptl.levelIdc = Level::NONE;
             vps.ptl.tierFlag = Level::MAIN;
             x265_log(&param, X265_LOG_INFO, "NONE profile, Level-NONE
(Main tier)\n");
@@ -221,10 +231,10 @@ void determineLevel(const x265_param &param, VPS& vps)
     static const char *tiers[]    = { "Main", "High" };

     char profbuf[64];
-    strcpy(profbuf, profiles[vps.ptl.profileIdc]);
+    strcpy(profbuf, profiles[vps.ptl.profileIdc[0]]);

     bool bStillPicture = false;
-    if (vps.ptl.profileIdc == Profile::MAINREXT)
+    if (vps.ptl.profileIdc[0] == Profile::MAINREXT)
     {
         if (vps.ptl.bitDepthConstraint > 12 && vps.ptl.intraConstraintFlag)
         {
diff --git a/source/encoder/ratecontrol.cpp b/source/encoder/ratecontrol.cpp
index 9f2b8d9b3..d46fb9a1e 100644
--- a/source/encoder/ratecontrol.cpp
+++ b/source/encoder/ratecontrol.cpp
@@ -1466,7 +1466,7 @@ int RateControl::rateControlStart(Frame* curFrame,
RateControlEntry* rce, Encode

         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. */
-        if (enc->m_vps.ptl.profileIdc > Profile::MAIN10 ||
enc->m_vps.ptl.levelIdc == Level::NONE)
+        if (enc->m_vps.ptl.profileIdc[0] > Profile::MAIN10 ||
enc->m_vps.ptl.levelIdc == Level::NONE)
             rce->frameSizeMaximum = 1e9;
         else
         {
diff --git a/source/encoder/sei.h b/source/encoder/sei.h
index dd4c2b6b8..d54e85a00 100644
--- a/source/encoder/sei.h
+++ b/source/encoder/sei.h
@@ -189,6 +189,41 @@ public:
     }
 };

+#if ENABLE_ALPHA
+class SEIAlphaChannelInfo : public SEI
+{
+public:
+    SEIAlphaChannelInfo()
+    {
+        m_payloadType = ALPHA_CHANNEL_INFO;
+        m_payloadSize = 0;
+    }
+
+    bool alpha_channel_cancel_flag;
+    void writeSEI(const SPS&)
+    {
+        WRITE_CODE(alpha_channel_cancel_flag, 1,
"alpha_channel_cancel_flag");
+        if (!alpha_channel_cancel_flag)
+        {
+            WRITE_CODE(0, 3, "alpha_channel_use_idc");
+            WRITE_CODE(0, 3, "alpha_channel_bit_depth_minus8");
+            WRITE_CODE(0, 9, "alpha_transparent_value");
+            WRITE_CODE(255, 9, "alpha_opaque_value");
+            WRITE_CODE(0, 1, "alpha_channel_incr_flag");
+            WRITE_CODE(0, 1, "alpha_channel_clip_flag");
+        }
+        if (m_bitIf->getNumberOfWrittenBits() % X265_BYTE != 0)
+        {
+            WRITE_FLAG(1, "payload_bit_equal_to_one");
+            while (m_bitIf->getNumberOfWrittenBits() % X265_BYTE != 0)
+            {
+                WRITE_FLAG(0, "payload_bit_equal_to_zero");
+            }
+        }
+    }
+};
+#endif
+
 class SEIMasteringDisplayColorVolume : public SEI
 {
 public:
diff --git a/source/x265.h b/source/x265.h
index 7c1acfea3..238b1358a 100644
--- a/source/x265.h
+++ b/source/x265.h
@@ -371,6 +371,7 @@ typedef enum
     MASTERING_DISPLAY_INFO               = 137,
     CONTENT_LIGHT_LEVEL_INFO             = 144,
     ALTERNATIVE_TRANSFER_CHARACTERISTICS = 147,
+    ALPHA_CHANNEL_INFO                   = 165,
 } SEIPayloadType;

 typedef struct x265_sei_payload
@@ -625,6 +626,8 @@ typedef enum

 #if ENABLE_ALPHA
 #define MAX_SCALABLE_LAYERS     2
+#define MAX_VPS_NUM_SCALABILITY_TYPES     16
+#define MAX_VPS_LAYER_ID_PLUS1            MAX_SCALABLE_LAYERS
 #else
 #define MAX_SCALABLE_LAYERS     1
 #endif
-- 
2.36.0.windows.1
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20240805/251ceda5/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0008-Add-support-for-alpha-in-HLS.patch
Type: application/octet-stream
Size: 31272 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20240805/251ceda5/attachment-0001.obj>


More information about the x265-devel mailing list