[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 ¶m, 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 ¶m, VPS& vps)
if (levels[i].levelEnum >= Level::LEVEL5 && param.maxCUSize < 32)
{
x265_log(¶m, 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(¶m, X265_LOG_INFO, "NONE profile, Level-NONE
(Main tier)\n");
@@ -186,7 +196,7 @@ void determineLevel(const x265_param ¶m, VPS& vps)
if (numPocTotalCurr > 10)
{
x265_log(¶m, 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(¶m, X265_LOG_INFO, "NONE profile, Level-NONE
(Main tier)\n");
@@ -221,10 +231,10 @@ void determineLevel(const x265_param ¶m, 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