<div dir="ltr">From 3c8cc9c76566a87f01cc6dc7c649afa5ddf540a1 Mon Sep 17 00:00:00 2001<br>From: AnusuyaKumarasamy <<a href="mailto:anusuya.kumarasamy@multicorewareinc.com">anusuya.kumarasamy@multicorewareinc.com</a>><br>Date: Wed, 3 Jul 2024 10:07:03 +0530<br>Subject: [PATCH] Add support for alpha in HLS<br><br>---<br> source/common/slice.h           |  21 +++-<br> source/encoder/api.cpp          |   6 +-<br> source/encoder/encoder.cpp      |  81 +++++++++++--<br> source/encoder/entropy.cpp      | 194 +++++++++++++++++++++++++++-----<br> source/encoder/entropy.h        |  12 +-<br> source/encoder/frameencoder.cpp |   4 +-<br> source/encoder/level.cpp        |  40 ++++---<br> source/encoder/ratecontrol.cpp  |   2 +-<br> source/encoder/sei.h            |  35 ++++++<br> source/x265.h                   |   3 +<br> 10 files changed, 330 insertions(+), 68 deletions(-)<br><br>diff --git a/source/common/slice.h b/source/common/slice.h<br>index 83f4c488f..c85cf0972 100644<br>--- a/source/common/slice.h<br>+++ b/source/common/slice.h<br>@@ -73,7 +73,9 @@ namespace Profile {<br>         MAIN10 = 2,<br>         MAINSTILLPICTURE = 3,<br>         MAINREXT = 4,<br>-        HIGHTHROUGHPUTREXT = 5<br>+        HIGHTHROUGHPUTREXT = 5,<br>+        SCALABLEMAIN = 7,<br>+        SCALABLEMAIN10 = 8<br>     };<br> }<br> <br>@@ -106,7 +108,7 @@ namespace Level {<br> <br> struct ProfileTierLevel<br> {<br>-    int      profileIdc;<br>+    int      profileIdc[MAX_SCALABLE_LAYERS];<br>     int      levelIdc;<br>     uint32_t minCrForLevel;<br>     uint32_t maxLumaSrForLevel;<br>@@ -159,6 +161,21 @@ struct VPS<br>     uint32_t         numReorderPics[MAX_T_LAYERS];<br>     uint32_t         maxDecPicBuffering[MAX_T_LAYERS];<br>     uint32_t         maxLatencyIncrease[MAX_T_LAYERS];<br>+<br>+#if ENABLE_ALPHA<br>+    bool             splitting_flag;<br>+    int              m_scalabilityMask[MAX_VPS_NUM_SCALABILITY_TYPES];<br>+    int              scalabilityTypes;<br>+    uint8_t          m_dimensionIdLen[MAX_VPS_NUM_SCALABILITY_TYPES];<br>+    uint8_t          m_dimensionId[MAX_VPS_LAYER_ID_PLUS1][MAX_VPS_NUM_SCALABILITY_TYPES];<br>+    bool              m_nuhLayerIdPresentFlag;<br>+    uint8_t          m_layerIdInNuh[MAX_VPS_LAYER_ID_PLUS1];<br>+    uint8_t          m_layerIdInVps[MAX_VPS_LAYER_ID_PLUS1];<br>+    int              m_viewIdLen;<br>+    int              m_numLayers;<br>+    int              m_vpsNumLayerSetsMinus1;<br>+    bool             vps_extension_flag;<br>+#endif<br> };<br> <br> struct Window<br>diff --git a/source/encoder/api.cpp b/source/encoder/api.cpp<br>index 60893f4d1..e21f541d9 100644<br>--- a/source/encoder/api.cpp<br>+++ b/source/encoder/api.cpp<br>@@ -185,7 +185,7 @@ x265_encoder *x265_encoder_open(x265_param *p)<br>     // will detect and set profile/tier/level in VPS<br>     determineLevel(*param, encoder->m_vps);<br> <br>-    if (!param->bAllowNonConformance && encoder->m_vps.ptl.profileIdc == Profile::NONE)<br>+    if (!param->bAllowNonConformance && encoder->m_vps.ptl.profileIdc[0] == Profile::NONE)<br>     {<br>         x265_log(param, X265_LOG_INFO, "non-conformant bitstreams not allowed (--allow-non-conformance)\n");<br>         goto fail;<br>@@ -357,11 +357,11 @@ int x265_encoder_reconfig(x265_encoder* enc, x265_param* param_in)<br>             VPS saveVPS;<br>             memcpy(&saveVPS.ptl, &encoder->m_vps.ptl, sizeof(saveVPS.ptl));<br>             determineLevel(*encoder->m_latestParam, encoder->m_vps);<br>-            if (saveVPS.ptl.profileIdc != encoder->m_vps.ptl.profileIdc || saveVPS.ptl.levelIdc != encoder->m_vps.ptl.levelIdc<br>+            if (saveVPS.ptl.profileIdc[0] != encoder->m_vps.ptl.profileIdc[0] || saveVPS.ptl.levelIdc != encoder->m_vps.ptl.levelIdc<br>                 || saveVPS.ptl.tierFlag != encoder->m_vps.ptl.tierFlag)<br>             {<br>                 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",<br>-                         saveVPS.ptl.profileIdc, saveVPS.ptl.levelIdc, saveVPS.ptl.tierFlag ? "High" : "Main", encoder->m_vps.ptl.profileIdc,<br>+                         saveVPS.ptl.profileIdc[0], saveVPS.ptl.levelIdc, saveVPS.ptl.tierFlag ? "High" : "Main", encoder->m_vps.ptl.profileIdc[0],<br>                          encoder->m_vps.ptl.levelIdc, encoder->m_vps.ptl.tierFlag ? "High" : "Main");<br>                 x265_copy_params(encoder->m_latestParam, &save);<br>                 memcpy(&encoder->m_vps.ptl, &saveVPS.ptl, sizeof(saveVPS.ptl));<br>diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp<br>index 4ac71f654..5697ac5e5 100644<br>--- a/source/encoder/encoder.cpp<br>+++ b/source/encoder/encoder.cpp<br>@@ -3277,19 +3277,34 @@ void Encoder::getStreamHeaders(NALList& list, Entropy& sbacCoder, Bitstream& bs)<br>     <br>     /* headers for start of bitstream */<br>     bs.resetBits();<br>-    sbacCoder.codeVPS(m_vps);<br>+    sbacCoder.codeVPS(m_vps, m_sps);<br>     bs.writeByteAlignment();<br>     list.serialize(NAL_UNIT_VPS, bs);<br> <br>-    bs.resetBits();<br>-    sbacCoder.codeSPS(m_sps, m_scalingList, m_vps.ptl);<br>-    bs.writeByteAlignment();<br>-    list.serialize(NAL_UNIT_SPS, bs);<br>+    for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>+    {<br>+        bs.resetBits();<br>+        sbacCoder.codeSPS(m_sps, m_scalingList, m_vps.ptl, layer);<br>+        bs.writeByteAlignment();<br>+        list.serialize(NAL_UNIT_SPS, bs, layer);<br>+    }<br> <br>-    bs.resetBits();<br>-    sbacCoder.codePPS(m_pps, (m_param->maxSlices <= 1), m_iPPSQpMinus26);<br>-    bs.writeByteAlignment();<br>-    list.serialize(NAL_UNIT_PPS, bs);<br>+    for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>+    {<br>+        bs.resetBits();<br>+        sbacCoder.codePPS(m_pps, (m_param->maxSlices <= 1), m_iPPSQpMinus26, layer);<br>+        bs.writeByteAlignment();<br>+        list.serialize(NAL_UNIT_PPS, bs, layer);<br>+    }<br>+<br>+#if ENABLE_ALPHA<br>+    if (m_param->numScalableLayers > 1)<br>+    {<br>+        SEIAlphaChannelInfo m_alpha;<br>+        m_alpha.alpha_channel_cancel_flag = !m_param->numScalableLayers;<br>+        m_alpha.writeSEImessages(bs, m_sps, NAL_UNIT_PREFIX_SEI, list, m_param->bSingleSeiNal);<br>+    }<br>+#endif<br> <br>     if (m_param->bSingleSeiNal)<br>         bs.resetBits();<br>@@ -3370,6 +3385,54 @@ void Encoder::initVPS(VPS *vps)<br>     vps->ptl.interlacedSourceFlag = !!m_param->interlaceMode;<br>     vps->ptl.nonPackedConstraintFlag = false;<br>     vps->ptl.frameOnlyConstraintFlag = !m_param->interlaceMode;<br>+<br>+#if ENABLE_ALPHA<br>+    vps->vps_extension_flag = false;<br>+<br>+    if (m_param->numScalableLayers > 1)<br>+    {<br>+        vps->vps_extension_flag = true;<br>+        int dimIdLen = 0, auxDimIdLen = 0, maxAuxId = 1, auxId[2] = { 0,1 };<br>+        vps->splitting_flag = false;<br>+        memset(vps->m_scalabilityMask, 0, sizeof(vps->m_scalabilityMask));<br>+        memset(vps->m_layerIdInNuh, 0, sizeof(vps->m_layerIdInNuh));<br>+        memset(vps->m_layerIdInVps, 0, sizeof(vps->m_layerIdInVps));<br>+        memset(vps->m_dimensionIdLen, 0, sizeof(vps->m_dimensionIdLen));<br>+        vps->scalabilityTypes = 0;<br>+<br>+        vps->m_scalabilityMask[3] = 1;<br>+        vps->m_scalabilityMask[2] = 1;<br>+        for (int i = 0; i < MAX_VPS_NUM_SCALABILITY_TYPES; i++)<br>+        {<br>+            vps->scalabilityTypes += vps->m_scalabilityMask[i];<br>+        }<br>+<br>+        while ((1 << dimIdLen) < m_param->numScalableLayers)<br>+        {<br>+            dimIdLen++;<br>+        }<br>+        vps->m_dimensionIdLen[0] = dimIdLen;<br>+<br>+        for (int i = 1; i < m_param->numScalableLayers; i++)<br>+        {<br>+            vps->m_layerIdInNuh[i] = i;<br>+            vps->m_dimensionId[i][0] = i;<br>+            vps->m_layerIdInVps[vps->m_layerIdInNuh[i]] = i;<br>+            vps->m_dimensionId[i][1] = auxId[i];<br>+        }<br>+<br>+        while ((1 << auxDimIdLen) < (maxAuxId + 1))<br>+        {<br>+            auxDimIdLen++;<br>+        }<br>+        vps->m_dimensionIdLen[1] = auxDimIdLen;<br>+<br>+        vps->m_nuhLayerIdPresentFlag = 1;<br>+        vps->m_viewIdLen = 0;<br>+        vps->m_vpsNumLayerSetsMinus1 = 1;<br>+        vps->m_numLayers = m_param->numScalableLayers;<br>+    }<br>+#endif<br> }<br> <br> void Encoder::initSPS(SPS *sps)<br>diff --git a/source/encoder/entropy.cpp b/source/encoder/entropy.cpp<br>index 18de2789e..cc8c83aea 100644<br>--- a/source/encoder/entropy.cpp<br>+++ b/source/encoder/entropy.cpp<br>@@ -230,11 +230,11 @@ Entropy::Entropy()<br>     X265_CHECK(sizeof(m_contextState) >= sizeof(m_contextState[0]) * MAX_OFF_CTX_MOD, "context state table is too small\n");<br> }<br> <br>-void Entropy::codeVPS(const VPS& vps)<br>+void Entropy::codeVPS(const VPS& vps, const SPS& sps)<br> {<br>     WRITE_CODE(0,       4, "vps_video_parameter_set_id");<br>     WRITE_CODE(3,       2, "vps_reserved_three_2bits");<br>-    WRITE_CODE(0,       6, "vps_reserved_zero_6bits");<br>+    WRITE_CODE(vps.m_numLayers - 1, 6, "vps_reserved_zero_6bits");<br>     WRITE_CODE(vps.maxTempSubLayers - 1, 3, "vps_max_sub_layers_minus1");<br>     WRITE_FLAG(vps.maxTempSubLayers == 1,   "vps_temporal_id_nesting_flag");<br>     WRITE_CODE(0xffff, 16, "vps_reserved_ffff_16bits");<br>@@ -250,13 +250,137 @@ void Entropy::codeVPS(const VPS& vps)<br>         WRITE_UVLC(vps.maxLatencyIncrease[i] + 1, "vps_max_latency_increase_plus1[i]");<br>     }<br> <br>+#if ENABLE_ALPHA<br>+    if (vps.m_numLayers > 1)<br>+    {<br>+        WRITE_CODE(vps.m_numLayers - 1, 6, "vps_max_nuh_reserved_zero_layer_id");<br>+        WRITE_UVLC(vps.m_vpsNumLayerSetsMinus1, "vps_max_op_sets_minus1");<br>+        for (int i = 1; i <= vps.m_vpsNumLayerSetsMinus1; i++)<br>+        {<br>+            for (int j = 0; j < vps.m_numLayers; j++)<br>+            {<br>+                WRITE_FLAG(1, "layer_id_included_flag[opsIdx][i]");<br>+            }<br>+        }<br>+    }<br>+    else<br>+    {<br>+        WRITE_CODE(0, 6, "vps_max_nuh_reserved_zero_layer_id");<br>+        WRITE_UVLC(0, "vps_max_op_sets_minus1");<br>+    }<br>+#else<br>     WRITE_CODE(0, 6, "vps_max_nuh_reserved_zero_layer_id");<br>-    WRITE_UVLC(0,    "vps_max_op_sets_minus1");<br>+    WRITE_UVLC(0, "vps_max_op_sets_minus1");<br>+#endif<br>+<br>     WRITE_FLAG(0,    "vps_timing_info_present_flag"); /* we signal timing info in SPS-VUI */<br>-    WRITE_FLAG(0,    "vps_extension_flag");<br>+<br>+#if ENABLE_ALPHA<br>+    WRITE_FLAG(vps.vps_extension_flag, "vps_extension_flag");<br>+<br>+    if (vps.vps_extension_flag)<br>+    {<br>+        while (m_bitIf->getNumberOfWrittenBits() % X265_BYTE != 0)<br>+        {<br>+            WRITE_FLAG(1, "vps_extension_alignment_bit_equal_to_one");<br>+        }<br>+<br>+        WRITE_CODE(vps.ptl.levelIdc, 8, "general_level_idc");<br>+<br>+        WRITE_FLAG(vps.splitting_flag, "splitting flag");<br>+        for (int i = 0; i < MAX_VPS_NUM_SCALABILITY_TYPES; i++)<br>+        {<br>+            WRITE_FLAG(vps.m_scalabilityMask[i], "scalability_mask[i]");<br>+        }<br>+        for (int i = 0; i < vps.scalabilityTypes - vps.splitting_flag; i++)<br>+        {<br>+            WRITE_CODE(vps.m_dimensionIdLen[i] - 1, 3, "dimension_id_len_minus1[i]");<br>+        }<br>+        WRITE_FLAG(vps.m_nuhLayerIdPresentFlag, "vps_nuh_layer_id_present_flag");<br>+        for (int i = 1; i < vps.m_numLayers; i++)<br>+        {<br>+            if (vps.m_nuhLayerIdPresentFlag)<br>+                WRITE_CODE(vps.m_layerIdInNuh[i], 6, "layer_id_in_nuh[i]");<br>+<br>+            if (!vps.splitting_flag)<br>+            {<br>+                for (int j = 0; j < vps.scalabilityTypes; j++)<br>+                {<br>+                    uint8_t bits = vps.m_dimensionIdLen[j];<br>+                    WRITE_CODE(vps.m_dimensionId[i][j], bits, "dimension_id[i][j]");<br>+                }<br>+            }<br>+        }<br>+        WRITE_CODE(vps.m_viewIdLen, 4, "view_id_len");<br>+<br>+        WRITE_FLAG(0, "direct_dependency_flag[1][0]");<br>+        WRITE_UVLC(0, "num_add_layer_sets");<br>+        WRITE_FLAG(0, "vps_sub_layers_max_minus1_present_flag");<br>+        WRITE_FLAG(0, "max_tid_ref_present_flag");<br>+        WRITE_FLAG(0, "default_ref_layers_active_flag");<br>+        WRITE_UVLC(2, "vps_num_profile_tier_level_minus1");<br>+        WRITE_FLAG(1, "vps_profile_present_flag");<br>+        codeProfileTier(vps.ptl, vps.maxTempSubLayers, 1);<br>+<br>+        WRITE_UVLC(0, "num_add_olss");<br>+        WRITE_CODE(0, 2, "default_output_layer_idc");<br>+        WRITE_CODE(1, 2, "profile_tier_level_idx[ i ][ j ]");<br>+        WRITE_CODE(2, 2, "profile_tier_level_idx[ i ][ j ]");<br>+<br>+        WRITE_UVLC(0, "vps_num_rep_formats_minus1");<br>+<br>+        WRITE_CODE(sps.picWidthInLumaSamples, 16, "pic_width_vps_in_luma_samples");<br>+        WRITE_CODE(sps.picHeightInLumaSamples, 16, "pic_height_vps_in_luma_samples");<br>+        WRITE_FLAG(1, "chroma_and_bit_depth_vps_present_flag");<br>+<br>+        WRITE_CODE(sps.chromaFormatIdc, 2, "chroma_format_vps_idc");<br>+<br>+        if (sps.chromaFormatIdc == X265_CSP_I444)<br>+            WRITE_FLAG(0, "separate_colour_plane_vps_flag");<br>+<br>+        WRITE_CODE(X265_DEPTH - 8, 4, "bit_depth_vps_luma_minus8");<br>+        WRITE_CODE(X265_DEPTH - 8, 4, "bit_depth_vps_chroma_minus8");<br>+<br>+        const Window& conf = sps.conformanceWindow;<br>+        WRITE_FLAG(conf.bEnabled, "conformance_window_vps_flag");<br>+        if (conf.bEnabled)<br>+        {<br>+            int hShift = CHROMA_H_SHIFT(sps.chromaFormatIdc), vShift = CHROMA_V_SHIFT(sps.chromaFormatIdc);<br>+            WRITE_UVLC(conf.leftOffset >> hShift, "conf_win_vps_left_offset");<br>+            WRITE_UVLC(conf.rightOffset >> hShift, "conf_win_vps_right_offset");<br>+            WRITE_UVLC(conf.topOffset >> vShift, "conf_win_vps_top_offset");<br>+            WRITE_UVLC(conf.bottomOffset >> vShift, "conf_win_vps_bottom_offset");<br>+        }<br>+<br>+        WRITE_FLAG(1, "max_one_active_ref_layer_flag");<br>+        WRITE_FLAG(0, "vps_poc_lsb_aligned_flag");<br>+        WRITE_FLAG(1, "poc_lsb_not_present_flag[");<br>+        WRITE_FLAG(0, "sub_layer_flag_info_present_flag");<br>+<br>+        for (int i = 1; i <= 1; i++)<br>+        {<br>+            for (int j = 0; j < vps.m_numLayers; j++)<br>+            {<br>+                WRITE_UVLC(vps.maxDecPicBuffering[0] - 1, "vps_max_dec_pic_buffering_minus1[i]");<br>+            }<br>+        }<br>+<br>+        WRITE_UVLC(vps.numReorderPics[0], "vps_num_reorder_pics[i]");<br>+        WRITE_UVLC(vps.maxLatencyIncrease[0] + 1, "vps_max_latency_increase_plus1[i]");<br>+<br>+        WRITE_UVLC(0, "direct_dep_type_len_minus2");<br>+<br>+        WRITE_FLAG(0, "default_direct_dependency_flag");<br>+        WRITE_UVLC(0, "vps_non_vui_extension_length");<br>+        WRITE_FLAG(0, "vps_vui_present_flag");<br>+        WRITE_FLAG(0, "vps_extension2_flag");<br>+    }<br>+#else<br>+    WRITE_FLAG(0, "vps_extension_flag");<br>+#endif<br> }<br> <br>-void Entropy::codeSPS(const SPS& sps, const ScalingList& scalingList, const ProfileTierLevel& ptl)<br>+void Entropy::codeSPS(const SPS& sps, const ScalingList& scalingList, const ProfileTierLevel& ptl, int layer)<br> {<br>     WRITE_CODE(0, 4, "sps_video_parameter_set_id");<br>     WRITE_CODE(sps.maxTempSubLayers - 1, 3, "sps_max_sub_layers_minus1");<br>@@ -264,7 +388,7 @@ void Entropy::codeSPS(const SPS& sps, const ScalingList& scalingList, const Prof<br> <br>     codeProfileTier(ptl, sps.maxTempSubLayers);<br> <br>-    WRITE_UVLC(0, "sps_seq_parameter_set_id");<br>+    WRITE_UVLC(layer, "sps_seq_parameter_set_id");<br>     WRITE_UVLC(sps.chromaFormatIdc, "chroma_format_idc");<br> <br>     if (sps.chromaFormatIdc == X265_CSP_I444)<br>@@ -322,15 +446,15 @@ void Entropy::codeSPS(const SPS& sps, const ScalingList& scalingList, const Prof<br>     WRITE_FLAG(sps.bUseStrongIntraSmoothing, "sps_strong_intra_smoothing_enable_flag");<br> <br>     WRITE_FLAG(1, "vui_parameters_present_flag");<br>-    codeVUI(sps.vuiParameters, sps.maxTempSubLayers, sps.bEmitVUITimingInfo, sps.bEmitVUIHRDInfo);<br>+    codeVUI(sps.vuiParameters, sps.maxTempSubLayers, sps.bEmitVUITimingInfo, sps.bEmitVUIHRDInfo, layer);<br> <br>     WRITE_FLAG(0, "sps_extension_flag");<br> }<br> <br>-void Entropy::codePPS( const PPS& pps, bool filerAcross, int iPPSInitQpMinus26 )<br>+void Entropy::codePPS( const PPS& pps, bool filerAcross, int iPPSInitQpMinus26, int layer)<br> {<br>-    WRITE_UVLC(0,                          "pps_pic_parameter_set_id");<br>-    WRITE_UVLC(0,                          "pps_seq_parameter_set_id");<br>+    WRITE_UVLC(layer,                          "pps_pic_parameter_set_id");<br>+    WRITE_UVLC(layer,                          "pps_seq_parameter_set_id");<br>     WRITE_FLAG(0,                          "dependent_slice_segments_enabled_flag");<br>     WRITE_FLAG(0,                          "output_flag_present_flag");<br>     WRITE_CODE(0, 3,                       "num_extra_slice_header_bits");<br>@@ -377,20 +501,25 @@ void Entropy::codePPS( const PPS& pps, bool filerAcross, int iPPSInitQpMinus26 )<br>     WRITE_FLAG(0, "pps_extension_flag");<br> }<br> <br>-void Entropy::codeProfileTier(const ProfileTierLevel& ptl, int maxTempSubLayers)<br>+void Entropy::codeProfileTier(const ProfileTierLevel& ptl, int maxTempSubLayers, int layer)<br> {<br>     WRITE_CODE(0, 2,                "XXX_profile_space[]");<br>     WRITE_FLAG(ptl.tierFlag,        "XXX_tier_flag[]");<br>-    WRITE_CODE(ptl.profileIdc, 5,   "XXX_profile_idc[]");<br>+    WRITE_CODE(ptl.profileIdc[layer], 5,   "XXX_profile_idc[]");<br>     for (int j = 0; j < 32; j++)<br>-        WRITE_FLAG(ptl.profileCompatibilityFlag[j], "XXX_profile_compatibility_flag[][j]");<br>+    {<br>+        if (layer)<br>+            WRITE_FLAG(j == ptl.profileIdc[layer] ? 1 : 0, "XXX_profile_compatibility_flag[][j]");<br>+        else<br>+            WRITE_FLAG(ptl.profileCompatibilityFlag[j], "XXX_profile_compatibility_flag[][j]");<br>+    }<br> <br>     WRITE_FLAG(ptl.progressiveSourceFlag,   "general_progressive_source_flag");<br>     WRITE_FLAG(ptl.interlacedSourceFlag,    "general_interlaced_source_flag");<br>     WRITE_FLAG(ptl.nonPackedConstraintFlag, "general_non_packed_constraint_flag");<br>     WRITE_FLAG(ptl.frameOnlyConstraintFlag, "general_frame_only_constraint_flag");<br> <br>-    if (ptl.profileIdc == Profile::MAINREXT || ptl.profileIdc == Profile::HIGHTHROUGHPUTREXT)<br>+    if (ptl.profileIdc[layer] == Profile::MAINREXT || ptl.profileIdc[layer] == Profile::HIGHTHROUGHPUTREXT || ptl.profileIdc[layer] == Profile::SCALABLEMAIN || ptl.profileIdc[layer] == Profile::SCALABLEMAIN10)<br>     {<br>         uint32_t bitDepthConstraint = ptl.bitDepthConstraint;<br>         int csp = ptl.chromaFormatConstraint;<br>@@ -428,7 +557,7 @@ void Entropy::codeProfileTier(const ProfileTierLevel& ptl, int maxTempSubLayers)<br>     }<br> }<br> <br>-void Entropy::codeVUI(const VUI& vui, int maxSubTLayers, bool bEmitVUITimingInfo, bool bEmitVUIHRDInfo)<br>+void Entropy::codeVUI(const VUI& vui, int maxSubTLayers, bool bEmitVUITimingInfo, bool bEmitVUIHRDInfo, int layer)<br> {<br>     WRITE_FLAG(vui.aspectRatioInfoPresentFlag, "aspect_ratio_info_present_flag");<br>     if (vui.aspectRatioInfoPresentFlag)<br>@@ -479,23 +608,28 @@ void Entropy::codeVUI(const VUI& vui, int maxSubTLayers, bool bEmitVUITimingInfo<br>         WRITE_UVLC(vui.defaultDisplayWindow.bottomOffset, "def_disp_win_bottom_offset");<br>     }<br> <br>-    if (!bEmitVUITimingInfo)<br>+    if(layer)<br>         WRITE_FLAG(0, "vui_timing_info_present_flag");<br>     else<br>     {<br>-        WRITE_FLAG(1, "vui_timing_info_present_flag");<br>-        WRITE_CODE(vui.timingInfo.numUnitsInTick, 32, "vui_num_units_in_tick");<br>-        WRITE_CODE(vui.timingInfo.timeScale, 32, "vui_time_scale");<br>-        WRITE_FLAG(0, "vui_poc_proportional_to_timing_flag");<br>-    }<br>+        if (!bEmitVUITimingInfo)<br>+            WRITE_FLAG(0, "vui_timing_info_present_flag");<br>+        else<br>+        {<br>+            WRITE_FLAG(1, "vui_timing_info_present_flag");<br>+            WRITE_CODE(vui.timingInfo.numUnitsInTick, 32, "vui_num_units_in_tick");<br>+            WRITE_CODE(vui.timingInfo.timeScale, 32, "vui_time_scale");<br>+            WRITE_FLAG(0, "vui_poc_proportional_to_timing_flag");<br>+        }<br> <br>-    if (!bEmitVUIHRDInfo)<br>-        WRITE_FLAG(0, "vui_hrd_parameters_present_flag");<br>-    else<br>-    {<br>-        WRITE_FLAG(vui.hrdParametersPresentFlag, "vui_hrd_parameters_present_flag");<br>-        if (vui.hrdParametersPresentFlag)<br>-            codeHrdParameters(vui.hrdParameters, maxSubTLayers);<br>+        if (!bEmitVUIHRDInfo)<br>+            WRITE_FLAG(0, "vui_hrd_parameters_present_flag");<br>+        else<br>+        {<br>+            WRITE_FLAG(vui.hrdParametersPresentFlag, "vui_hrd_parameters_present_flag");<br>+            if (vui.hrdParametersPresentFlag)<br>+                codeHrdParameters(vui.hrdParameters, maxSubTLayers);<br>+        }<br>     }<br> <br>     WRITE_FLAG(0, "bitstream_restriction_flag");<br>@@ -590,13 +724,13 @@ void Entropy::codeAUD(const Slice& slice)<br>     WRITE_CODE(picType, 3, "pic_type");<br> }<br> <br>-void Entropy::codeSliceHeader(const Slice& slice, FrameData& encData, uint32_t slice_addr, uint32_t slice_addr_bits, int sliceQp)<br>+void Entropy::codeSliceHeader(const Slice& slice, FrameData& encData, uint32_t slice_addr, uint32_t slice_addr_bits, int sliceQp, int layer)<br> {<br>     WRITE_FLAG((slice_addr == 0 ? 1 : 0), "first_slice_segment_in_pic_flag");<br>     if (slice.getRapPicFlag())<br>         WRITE_FLAG(0, "no_output_of_prior_pics_flag");<br> <br>-    WRITE_UVLC(0, "slice_pic_parameter_set_id");<br>+    WRITE_UVLC(layer, "slice_pic_parameter_set_id");<br> <br>     /* x265 does not use dependent slices, so always write all this data */<br>     if (slice_addr)<br>diff --git a/source/encoder/entropy.h b/source/encoder/entropy.h<br>index 366b1c077..4271701c7 100644<br>--- a/source/encoder/entropy.h<br>+++ b/source/encoder/entropy.h<br>@@ -141,14 +141,14 @@ public:<br>     void loadIntraDirModeLuma(const Entropy& src);<br>     void copyState(const Entropy& other);<br> <br>-    void codeVPS(const VPS& vps);<br>-    void codeSPS(const SPS& sps, const ScalingList& scalingList, const ProfileTierLevel& ptl);<br>-    void codePPS( const PPS& pps, bool filerAcross, int iPPSInitQpMinus26 );<br>-    void codeVUI(const VUI& vui, int maxSubTLayers, bool bEmitVUITimingInfo, bool bEmitVUIHRDInfo);<br>+    void codeVPS(const VPS& vps, const SPS& sps);<br>+    void codeSPS(const SPS& sps, const ScalingList& scalingList, const ProfileTierLevel& ptl, int layer = 0);<br>+    void codePPS( const PPS& pps, bool filerAcross, int iPPSInitQpMinus26, int layer = 0);<br>+    void codeVUI(const VUI& vui, int maxSubTLayers, bool bEmitVUITimingInfo, bool bEmitVUIHRDInfo, int layer = 0);<br>     void codeAUD(const Slice& slice);<br>     void codeHrdParameters(const HRDInfo& hrd, int maxSubTLayers);<br> <br>-    void codeSliceHeader(const Slice& slice, FrameData& encData, uint32_t slice_addr, uint32_t slice_addr_bits, int sliceQp);<br>+    void codeSliceHeader(const Slice& slice, FrameData& encData, uint32_t slice_addr, uint32_t slice_addr_bits, int sliceQp, int layer = 0);<br>     void codeSliceHeaderWPPEntryPoints(const uint32_t *substreamSizes, uint32_t numSubStreams, uint32_t maxOffset);<br>     void codeShortTermRefPicSet(const RPS& rps, int idx);<br>     void finishSlice()                 { encodeBinTrm(1); finish(); dynamic_cast<Bitstream*>(m_bitIf)->writeByteAlignment(); }<br>@@ -234,7 +234,7 @@ private:<br>     void writeEpExGolomb(uint32_t symbol, uint32_t count);<br>     void writeCoefRemainExGolomb(uint32_t symbol, const uint32_t absGoRice);<br> <br>-    void codeProfileTier(const ProfileTierLevel& ptl, int maxTempSubLayers);<br>+    void codeProfileTier(const ProfileTierLevel& ptl, int maxTempSubLayers, int layer = 0);<br>     void codeScalingList(const ScalingList&);<br>     void codeScalingList(const ScalingList& scalingList, uint32_t sizeId, uint32_t listId);<br> <br>diff --git a/source/encoder/frameencoder.cpp b/source/encoder/frameencoder.cpp<br>index b36094f33..8d72adcf4 100644<br>--- a/source/encoder/frameencoder.cpp<br>+++ b/source/encoder/frameencoder.cpp<br>@@ -1095,7 +1095,7 @@ void FrameEncoder::compressFrame(int layer)<br>                 ScopedLock refIdxLock(m_top->m_sliceRefIdxLock);<br>                 m_top->analyseRefIdx(slice->m_numRefIdx);<br>             }<br>-            m_entropyCoder.codeSliceHeader(*slice, *m_frame[layer]->m_encData, sliceAddr, m_sliceAddrBits, slice->m_sliceQp);<br>+            m_entropyCoder.codeSliceHeader(*slice, *m_frame[layer]->m_encData, sliceAddr, m_sliceAddrBits, slice->m_sliceQp, layer);<br> <br>             // Find rows of current slice<br>             const uint32_t prevSliceRow = nextSliceRow;<br>@@ -1122,7 +1122,7 @@ void FrameEncoder::compressFrame(int layer)<br>             ScopedLock refIdxLock(m_top->m_sliceRefIdxLock);<br>             m_top->analyseRefIdx(slice->m_numRefIdx);<br>         }<br>-        m_entropyCoder.codeSliceHeader(*slice, *m_frame[layer]->m_encData, 0, 0, slice->m_sliceQp);<br>+        m_entropyCoder.codeSliceHeader(*slice, *m_frame[layer]->m_encData, 0, 0, slice->m_sliceQp, layer);<br> <br>         // serialize each row, record final lengths in slice header<br>         uint32_t maxStreamSize = m_nalList.serializeSubstreams(m_substreamSizes, numSubstreams, m_outStreams);<br>diff --git a/source/encoder/level.cpp b/source/encoder/level.cpp<br>index b224a5d3f..c62c63426 100644<br>--- a/source/encoder/level.cpp<br>+++ b/source/encoder/level.cpp<br>@@ -80,38 +80,48 @@ void determineLevel(const x265_param &param, VPS& vps)<br>         if (param.internalBitDepth <= 8)<br>         {<br>             if (vps.ptl.onePictureOnlyConstraintFlag)<br>-                vps.ptl.profileIdc = Profile::MAINSTILLPICTURE;<br>+                vps.ptl.profileIdc[0] = Profile::MAINSTILLPICTURE;<br>             else if (vps.ptl.intraConstraintFlag)<br>-                vps.ptl.profileIdc = Profile::MAINREXT; /* Main Intra */<br>+                vps.ptl.profileIdc[0] = Profile::MAINREXT; /* Main Intra */<br>             else <br>-                vps.ptl.profileIdc = Profile::MAIN;<br>+                vps.ptl.profileIdc[0] = Profile::MAIN;<br>+<br>+#if ENABLE_ALPHA<br>+            if (param.numScalableLayers == 2)<br>+                vps.ptl.profileIdc[1] = Profile::SCALABLEMAIN;<br>+#endif<br>         }<br>         else if (param.internalBitDepth <= 10)<br>         {<br>             /* note there is no 10bit still picture profile */<br>             if (vps.ptl.intraConstraintFlag)<br>-                vps.ptl.profileIdc = Profile::MAINREXT; /* Main10 Intra */<br>+                vps.ptl.profileIdc[0] = Profile::MAINREXT; /* Main10 Intra */<br>             else<br>-                vps.ptl.profileIdc = Profile::MAIN10;<br>+                vps.ptl.profileIdc[0] = Profile::MAIN10;<br>+<br>+#if ENABLE_ALPHA<br>+            if (param.numScalableLayers == 2)<br>+                vps.ptl.profileIdc[1] = Profile::SCALABLEMAIN10;<br>+#endif<br>         }<br>     }<br>     else<br>-        vps.ptl.profileIdc = Profile::MAINREXT;<br>+        vps.ptl.profileIdc[0] = Profile::MAINREXT;<br> <br>     /* determine which profiles are compatible with this stream */<br> <br>     memset(vps.ptl.profileCompatibilityFlag, 0, sizeof(vps.ptl.profileCompatibilityFlag));<br>-    vps.ptl.profileCompatibilityFlag[vps.ptl.profileIdc] = true;<br>-    if (vps.ptl.profileIdc == Profile::MAIN10 && param.internalBitDepth == 8)<br>+    vps.ptl.profileCompatibilityFlag[vps.ptl.profileIdc[0]] = true;<br>+    if (vps.ptl.profileIdc[0] == Profile::MAIN10 && param.internalBitDepth == 8)<br>         vps.ptl.profileCompatibilityFlag[Profile::MAIN] = true;<br>-    else if (vps.ptl.profileIdc == Profile::MAIN)<br>+    else if (vps.ptl.profileIdc[0] == Profile::MAIN)<br>         vps.ptl.profileCompatibilityFlag[Profile::MAIN10] = true;<br>-    else if (vps.ptl.profileIdc == Profile::MAINSTILLPICTURE)<br>+    else if (vps.ptl.profileIdc[0] == Profile::MAINSTILLPICTURE)<br>     {<br>         vps.ptl.profileCompatibilityFlag[Profile::MAIN] = true;<br>         vps.ptl.profileCompatibilityFlag[Profile::MAIN10] = true;<br>     }<br>-    else if (vps.ptl.profileIdc == Profile::MAINREXT)<br>+    else if (vps.ptl.profileIdc[0] == Profile::MAINREXT)<br>         vps.ptl.profileCompatibilityFlag[Profile::MAINREXT] = true;<br> <br>     uint32_t lumaSamples = param.sourceWidth * param.sourceHeight;<br>@@ -174,7 +184,7 @@ void determineLevel(const x265_param &param, VPS& vps)<br>         if (levels[i].levelEnum >= Level::LEVEL5 && param.maxCUSize < 32)<br>         {<br>             x265_log(&param, X265_LOG_WARNING, "level %s detected, but CTU size 16 is non-compliant\n", levels[i].name);<br>-            vps.ptl.profileIdc = Profile::NONE;<br>+            vps.ptl.profileIdc[0] = Profile::NONE;<br>             vps.ptl.levelIdc = Level::NONE;<br>             vps.ptl.tierFlag = Level::MAIN;<br>             x265_log(&param, X265_LOG_INFO, "NONE profile, Level-NONE (Main tier)\n");<br>@@ -186,7 +196,7 @@ void determineLevel(const x265_param &param, VPS& vps)<br>         if (numPocTotalCurr > 10)<br>         {<br>             x265_log(&param, X265_LOG_WARNING, "level %s detected, but NumPocTotalCurr (total references) is non-compliant\n", levels[i].name);<br>-            vps.ptl.profileIdc = Profile::NONE;<br>+            vps.ptl.profileIdc[0] = Profile::NONE;<br>             vps.ptl.levelIdc = Level::NONE;<br>             vps.ptl.tierFlag = Level::MAIN;<br>             x265_log(&param, X265_LOG_INFO, "NONE profile, Level-NONE (Main tier)\n");<br>@@ -221,10 +231,10 @@ void determineLevel(const x265_param &param, VPS& vps)<br>     static const char *tiers[]    = { "Main", "High" };<br> <br>     char profbuf[64];<br>-    strcpy(profbuf, profiles[vps.ptl.profileIdc]);<br>+    strcpy(profbuf, profiles[vps.ptl.profileIdc[0]]);<br> <br>     bool bStillPicture = false;<br>-    if (vps.ptl.profileIdc == Profile::MAINREXT)<br>+    if (vps.ptl.profileIdc[0] == Profile::MAINREXT)<br>     {<br>         if (vps.ptl.bitDepthConstraint > 12 && vps.ptl.intraConstraintFlag)<br>         {<br>diff --git a/source/encoder/ratecontrol.cpp b/source/encoder/ratecontrol.cpp<br>index 9f2b8d9b3..d46fb9a1e 100644<br>--- a/source/encoder/ratecontrol.cpp<br>+++ b/source/encoder/ratecontrol.cpp<br>@@ -1466,7 +1466,7 @@ int RateControl::rateControlStart(Frame* curFrame, RateControlEntry* rce, Encode<br> <br>         int mincr = enc->m_vps.ptl.minCrForLevel;<br>         /* Profiles above Main10 don't require maxAU size check, so just set the maximum to a large value. */<br>-        if (enc->m_vps.ptl.profileIdc > Profile::MAIN10 || enc->m_vps.ptl.levelIdc == Level::NONE)<br>+        if (enc->m_vps.ptl.profileIdc[0] > Profile::MAIN10 || enc->m_vps.ptl.levelIdc == Level::NONE)<br>             rce->frameSizeMaximum = 1e9;<br>         else<br>         {<br>diff --git a/source/encoder/sei.h b/source/encoder/sei.h<br>index dd4c2b6b8..d54e85a00 100644<br>--- a/source/encoder/sei.h<br>+++ b/source/encoder/sei.h<br>@@ -189,6 +189,41 @@ public:<br>     }<br> };<br> <br>+#if ENABLE_ALPHA<br>+class SEIAlphaChannelInfo : public SEI<br>+{<br>+public:<br>+    SEIAlphaChannelInfo()<br>+    {<br>+        m_payloadType = ALPHA_CHANNEL_INFO;<br>+        m_payloadSize = 0;<br>+    }<br>+<br>+    bool alpha_channel_cancel_flag;<br>+    void writeSEI(const SPS&)<br>+    {<br>+        WRITE_CODE(alpha_channel_cancel_flag, 1, "alpha_channel_cancel_flag");<br>+        if (!alpha_channel_cancel_flag)<br>+        {<br>+            WRITE_CODE(0, 3, "alpha_channel_use_idc");<br>+            WRITE_CODE(0, 3, "alpha_channel_bit_depth_minus8");<br>+            WRITE_CODE(0, 9, "alpha_transparent_value");<br>+            WRITE_CODE(255, 9, "alpha_opaque_value");<br>+            WRITE_CODE(0, 1, "alpha_channel_incr_flag");<br>+            WRITE_CODE(0, 1, "alpha_channel_clip_flag");<br>+        }<br>+        if (m_bitIf->getNumberOfWrittenBits() % X265_BYTE != 0)<br>+        {<br>+            WRITE_FLAG(1, "payload_bit_equal_to_one");<br>+            while (m_bitIf->getNumberOfWrittenBits() % X265_BYTE != 0)<br>+            {<br>+                WRITE_FLAG(0, "payload_bit_equal_to_zero");<br>+            }<br>+        }<br>+    }<br>+};<br>+#endif<br>+<br> class SEIMasteringDisplayColorVolume : public SEI<br> {<br> public:<br>diff --git a/source/x265.h b/source/x265.h<br>index 7c1acfea3..238b1358a 100644<br>--- a/source/x265.h<br>+++ b/source/x265.h<br>@@ -371,6 +371,7 @@ typedef enum<br>     MASTERING_DISPLAY_INFO               = 137,<br>     CONTENT_LIGHT_LEVEL_INFO             = 144,<br>     ALTERNATIVE_TRANSFER_CHARACTERISTICS = 147,<br>+    ALPHA_CHANNEL_INFO                   = 165,<br> } SEIPayloadType;<br> <br> typedef struct x265_sei_payload<br>@@ -625,6 +626,8 @@ typedef enum<br> <br> #if ENABLE_ALPHA<br> #define MAX_SCALABLE_LAYERS     2<br>+#define MAX_VPS_NUM_SCALABILITY_TYPES     16<br>+#define MAX_VPS_LAYER_ID_PLUS1            MAX_SCALABLE_LAYERS<br> #else<br> #define MAX_SCALABLE_LAYERS     1<br> #endif<br>-- <br>2.36.0.windows.1<br><br></div>