[x265] [PATCH] Update the support to signal AOM fgm params
Logaprakash Ramajayam
logaprakash.ramajayam at multicorewareinc.com
Fri Nov 21 08:49:35 UTC 2025
>From a006e30f630a84b36fd11c9364d0e01c01ddedfd Mon Sep 17 00:00:00 2001
From: AnusuyaKumarasamy <anusuya.kumarasamy at multicorewareinc.com>
Date: Fri, 14 Nov 2025 14:20:42 +0530
Subject: [PATCH] Update the support to signal AOM fgm params
This patch fixes the decode of bitstream with AOM FGM SEI in ffmpeg
---
source/encoder/frameencoder.cpp | 98 +++++++++++++++++-
source/encoder/sei.h | 170 ++++++++++++++++++++++++--------
2 files changed, 225 insertions(+), 43 deletions(-)
diff --git a/source/encoder/frameencoder.cpp b/source/encoder/frameencoder.cpp
index 74ef45eae..517d5f662 100644
--- a/source/encoder/frameencoder.cpp
+++ b/source/encoder/frameencoder.cpp
@@ -2324,88 +2324,182 @@ void FrameEncoder::readModel(FilmGrainCharacteristics* m_filmGrain, FILE* filmgr
}
}
+void compute_film_grain_resolution(int width, int height,
+ int& apply_units_resolution_log2,
+ int& apply_horz_resolution,
+ int& apply_vert_resolution) {
+ const int max_log2 = 15;
+
+ for (int log2 = max_log2; log2 >= 0; --log2) {
+ int unit = 1 << log2;
+
+ if (width % unit == 0 && height % unit == 0) {
+ apply_units_resolution_log2 = log2;
+ apply_horz_resolution = width / unit;
+ apply_vert_resolution = height / unit;
+ return;
+ }
+ }
+
+ apply_units_resolution_log2 = 0;
+ apply_horz_resolution = width;
+ apply_vert_resolution = height;
+}
+
void FrameEncoder::readAomModel(AomFilmGrainCharacteristics* m_aomFilmGrain, FILE* Aomfilmgrain)
{
char const* errorMessage = "Error reading Aom FilmGrain characteristics\n";
AomFilmGrain m_afg;
m_afg.m_chroma_scaling_from_luma = 0;
+ int bitCount = 0;
+ bitCount += 4; // payload_less_than_4byte_flag(1) + film_grain_param_set_idx(3)
x265_fread((char*)&m_aomFilmGrain->m_apply_grain, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount++;
x265_fread((char*)&m_aomFilmGrain->m_grain_seed, sizeof(uint16_t), 1, Aomfilmgrain, errorMessage);
+ bitCount+=16;
x265_fread((char*)&m_aomFilmGrain->m_update_grain, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount++;
x265_fread((char*)&m_aomFilmGrain->m_num_y_points, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount+=4;
+
if (m_aomFilmGrain->m_num_y_points)
{
+ m_aomFilmGrain->point_y_value_increment_bits = 8;
+ bitCount += 3;
+ m_aomFilmGrain->point_y_scaling_bits = 8;
+ bitCount += 2;
for (int i = 0; i < m_aomFilmGrain->m_num_y_points; i++)
{
for (int j = 0; j < 2; j++)
{
x265_fread((char*)&m_aomFilmGrain->m_scaling_points_y[i][j], sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount+=8;
}
}
}
x265_fread((char*)&m_aomFilmGrain->m_num_cb_points, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount+=4;
if (m_aomFilmGrain->m_num_cb_points)
{
+ m_aomFilmGrain->point_cb_value_increment_bits = 8;
+ bitCount += 3;
+ m_aomFilmGrain->point_cb_scaling_bits = 8;
+ bitCount += 2;
+ m_aomFilmGrain->cb_scaling_offset = 0;
+ bitCount += 8;
for (int i = 0; i < m_aomFilmGrain->m_num_cb_points; i++)
{
for (int j = 0; j < 2; j++)
{
x265_fread((char*)&m_aomFilmGrain->m_scaling_points_cb[i][j], sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount+=8;
}
}
}
x265_fread((char*)&m_aomFilmGrain->m_num_cr_points, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount+=4;
if (m_aomFilmGrain->m_num_cr_points)
{
+ m_aomFilmGrain->point_cr_value_increment_bits = 8;
+ bitCount += 3;
+ m_aomFilmGrain->point_cr_scaling_bits = 8;
+ bitCount += 2;
+ m_aomFilmGrain->cr_scaling_offset = 0;
+ bitCount += 8;
for (int i = 0; i < m_aomFilmGrain->m_num_cr_points; i++)
{
for (int j = 0; j < 2; j++)
{
x265_fread((char*)&m_aomFilmGrain->m_scaling_points_cr[i][j], sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount+=8;
}
}
}
x265_fread((char*)&m_aomFilmGrain->m_scaling_shift, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount+=2;
x265_fread((char*)&m_aomFilmGrain->m_ar_coeff_lag, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount+=2;
if (m_aomFilmGrain->m_num_y_points)
{
-
+ bitCount += 2;
for (int i = 0; i < 24; i++)
{
x265_fread((char*)&m_aomFilmGrain->m_ar_coeffs_y[i], sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount+=8;
}
}
if (m_aomFilmGrain->m_num_cb_points || m_afg.m_chroma_scaling_from_luma)
{
+ bitCount += 2;
for (int i = 0; i < 25; i++)
{
x265_fread((char*)&m_aomFilmGrain->m_ar_coeffs_cb[i], sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount+=8;
}
}
if (m_aomFilmGrain->m_num_cr_points || m_afg.m_chroma_scaling_from_luma)
{
-
+ bitCount += 2;
for (int i = 0; i < 25; i++)
{
x265_fread((char*)&m_aomFilmGrain->m_ar_coeffs_cr[i], sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount+=8;
}
}
x265_fread((char*)&m_aomFilmGrain->m_ar_coeff_shift, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount+=2;
x265_fread((char*)&m_aomFilmGrain->m_grain_scale_shift, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount+=2;
if (m_aomFilmGrain->m_num_cb_points)
{
x265_fread((char*)&m_aomFilmGrain->m_cb_mult, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount += 8;
x265_fread((char*)&m_aomFilmGrain->m_cb_luma_mult, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount += 8;
x265_fread((char*)&m_aomFilmGrain->m_cb_offset, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount += 9;
}
if (m_aomFilmGrain->m_num_cr_points)
{
x265_fread((char*)&m_aomFilmGrain->m_cr_mult, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount += 8;
x265_fread((char*)&m_aomFilmGrain->m_cr_luma_mult, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount += 8;
x265_fread((char*)&m_aomFilmGrain->m_cr_offset, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount += 9;
}
x265_fread((char*)&m_aomFilmGrain->m_overlap_flag, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount++;
x265_fread((char*)&m_aomFilmGrain->m_clip_to_restricted_range, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ bitCount++;
+
+ m_aomFilmGrain->luma_only_flag = m_aomFilmGrain->m_num_cb_points == 0 && m_aomFilmGrain->m_num_cr_points == 0;
+ bitCount++;
+ m_aomFilmGrain->subsamplingX = CHROMA_H_SHIFT(m_param->internalCsp);
+ m_aomFilmGrain->subsamplingY = CHROMA_V_SHIFT(m_param->internalCsp);
+ if (!m_aomFilmGrain->luma_only_flag)
+ bitCount += 2; // subsampling_x(1) + subsampling_y(1)
+ compute_film_grain_resolution(m_param->sourceWidth, m_param->sourceHeight, m_aomFilmGrain->units_resolution_log2,
+ m_aomFilmGrain->horz_resolution, m_aomFilmGrain->vert_resolution);
+ bitCount += 28; // apply_units_resolution_log2(4) + apply_horz_resolution(12) + apply_vert_resolution(12)
+ m_aomFilmGrain->predict_scaling_flag = 0;
+ bitCount++;
+ m_aomFilmGrain->predict_y_scaling_flag = 0;
+ m_aomFilmGrain->predict_cb_scaling_flag = 0;
+ m_aomFilmGrain->predict_cr_scaling_flag = 0;
+ m_aomFilmGrain->m_bitDepth = m_param->internalBitDepth;
+ bitCount++; // videosingnaltypepresentflag
+ if (m_frame[0]->m_encData->m_slice->m_sps->vuiParameters.videoSignalTypePresentFlag) bitCount += 4; // bit_depth_minus8(3) + cicp_info_present_flag(1)
+ if (m_frame[0]->m_encData->m_slice->m_sps->vuiParameters.colourDescriptionPresentFlag) bitCount += 25; // colourPrimaries(8) + transferCharacteristics(8) + matrixCoefficients(8)+ videoFullRangeFlag(1)
+ if (!m_aomFilmGrain->luma_only_flag) {
+ m_aomFilmGrain->m_chroma_scaling_from_luma = 0;
+ bitCount++;
+ }
+
+ m_aomFilmGrain->payload_size = (bitCount + 8 - 1) / 8;
+ m_aomFilmGrain->payload_bits = m_aomFilmGrain->payload_size < 4 ? 2 : 8;
+ bitCount += m_aomFilmGrain->payload_bits;
+ m_aomFilmGrain->payload_size = (bitCount + 8 - 1) / 8;
}
#if ENABLE_LIBVMAF
diff --git a/source/encoder/sei.h b/source/encoder/sei.h
index 3ed957058..b7aaaee20 100644
--- a/source/encoder/sei.h
+++ b/source/encoder/sei.h
@@ -204,83 +204,171 @@ public:
int32_t m_chroma_scaling_from_luma;
int32_t m_grain_scale_shift;
uint16_t m_grain_seed;
+ bool subsamplingX;
+ bool subsamplingY;
+ bool predict_scaling_flag;
+ bool predict_y_scaling_flag;
+ bool predict_cb_scaling_flag;
+ bool predict_cr_scaling_flag;
+ int units_resolution_log2;
+ int horz_resolution;
+ int vert_resolution;
+ bool luma_only_flag;
+ int point_y_value_increment_bits;
+ int point_y_scaling_bits;
+ int point_cb_value_increment_bits;
+ int point_cb_scaling_bits;
+ int point_cr_value_increment_bits;
+ int point_cr_scaling_bits;
+ int cb_scaling_offset;
+ int cr_scaling_offset;
+ int payload_size;
+ int payload_bits;
- void writeSEI(const SPS&)
+ void writeSEI(const SPS& sps)
{
- WRITE_CODE(0x26, 8, "country_code");
+ WRITE_CODE(0xB5, 8, "country_code");
WRITE_CODE(0x5890, 16, "provider_code");
- WRITE_CODE(0x0001, 16, "provider_oriented_code");
- WRITE_FLAG(m_apply_grain, "afgs1_enable_flag");
- WRITE_CODE(m_grain_seed, 16, "grain_seed");
+ WRITE_CODE(0x0001, 8, "provider_oriented_code");
+ WRITE_FLAG(1, "afgs1_enable_flag");
+ WRITE_CODE(0, 4, "reserved_4bits");
+ WRITE_CODE(0, 3, "num_film_grain_sets_minus1");
+ WRITE_FLAG(payload_size < 4 ? 1 : 0, "payload_less_than_4byte_flag");
+ WRITE_CODE(payload_size, payload_bits, "payload_size");
+
WRITE_CODE(0, 3, "film_grain_param_set_idx");
- WRITE_CODE(m_update_grain, 1, "update_grain");
- WRITE_CODE(m_num_y_points, 4, "num_y_points");
- if (m_num_y_points)
+ WRITE_FLAG(m_apply_grain, "apply_grain_flag");
+ WRITE_CODE(m_grain_seed, 16, "grain_seed");
+ WRITE_FLAG(1, "update_grain_flag");
+ WRITE_CODE(units_resolution_log2, 4, "apply_units_resolution_log2");
+ WRITE_CODE(horz_resolution, 12, "apply_horz_resolution");
+ WRITE_CODE(vert_resolution, 12, "apply_vert_resolution");
+ WRITE_FLAG(luma_only_flag, "luma_only_flag");
+ if (!luma_only_flag) {
+ WRITE_FLAG(subsamplingX, "subsampling_x");
+ WRITE_FLAG(subsamplingY, "subsampling_y");
+ }
+ WRITE_FLAG(sps.vuiParameters.videoSignalTypePresentFlag, "video_signal_characteristics_flag");
+ if (sps.vuiParameters.videoSignalTypePresentFlag)
{
- for (int i = 0; i < m_num_y_points; i++)
+ WRITE_CODE(m_bitDepth - 8, 3, "bit_depth_minus8");
+ WRITE_FLAG(sps.vuiParameters.colourDescriptionPresentFlag, "cicp_info_present_flag");
+ if (sps.vuiParameters.colourDescriptionPresentFlag)
{
- for (int j = 0; j < 2; j++)
- {
- WRITE_CODE(m_scaling_points_y[i][j], 8, "scaling_points_y[i][j]");
- }
+ WRITE_CODE(sps.vuiParameters.colourPrimaries, 8, "colour_primaries");
+ WRITE_CODE(sps.vuiParameters.transferCharacteristics, 8, "transfer_characteristics");
+ WRITE_CODE(sps.vuiParameters.matrixCoefficients, 8, "matrix_coefficients");
+ WRITE_FLAG(sps.vuiParameters.videoFullRangeFlag, "video_full_range_flag");
}
}
- WRITE_FLAG(m_num_cb_points == 0 && m_num_cr_points == 0, "luma_only_flag");
- WRITE_FLAG(0, "chroma_scaling_from_luma");
- WRITE_CODE(m_num_cb_points, 4, "num_cb_points");
- if (m_num_cb_points)
- {
- for (int i = 0; i < m_num_cb_points; i++)
- {
- for (int j = 0; j < 2; j++)
- {
- WRITE_CODE(m_scaling_points_cb[i][j], 8, "scaling_points_cb[i][j]");
- }
+ WRITE_FLAG(predict_scaling_flag, "predict_scaling_flag");
+ if (predict_scaling_flag) {
+ WRITE_FLAG(predict_y_scaling_flag, "predict_y_scaling_flag");
+ }
+
+ WRITE_CODE(m_num_y_points, 4, "num_y_points");
+ if (m_num_y_points) {
+ WRITE_CODE(point_y_value_increment_bits - 1, 3, "point_y_value_increment_bits_minus1");
+ int bitsIncr = point_y_value_increment_bits;
+ WRITE_CODE(point_y_scaling_bits - 5, 2, "point_y_scaling_bits_minus5");
+ int bitsScal = point_y_scaling_bits;
+ for (int i = 0; i < m_num_y_points; i++) {
+ if (i)
+ WRITE_CODE(m_scaling_points_y[i][0] - m_scaling_points_y[i - 1][0], bitsIncr, "point_y_value_increment[i]");
+ else
+ WRITE_CODE(m_scaling_points_y[i][0], bitsIncr, "point_y_value_increment[i]");
+ WRITE_CODE(m_scaling_points_y[i][1], bitsScal, "point_y_scaling[i]");
}
}
- WRITE_CODE(m_num_cr_points, 4, "num_cr_points");
- if (m_num_cr_points)
- {
- for (int i = 0; i < m_num_cr_points; i++)
- {
- for (int j = 0; j < 2; j++)
- {
- WRITE_CODE(m_scaling_points_cr[i][j], 8, "scaling_points_cr[i][j]");
+
+ if (!luma_only_flag)
+ WRITE_FLAG(m_chroma_scaling_from_luma, "chroma_scaling_from_luma");
+
+ if (luma_only_flag || m_chroma_scaling_from_luma) {
+ m_num_cb_points = 0;
+ m_num_cr_points = 0;
+ }
+ else {
+ if (predict_scaling_flag)
+ WRITE_FLAG(predict_cb_scaling_flag, "predict_cb_scaling_flag");
+
+ WRITE_CODE(m_num_cb_points, 4, "num_cb_points");
+ if (m_num_cb_points) {
+ WRITE_CODE(point_cb_value_increment_bits - 1, 3, "point_cb_value_increment_bits_minus1");
+ int bitsIncr = point_cb_value_increment_bits;
+ WRITE_CODE(point_cb_scaling_bits - 5, 2, "point_cb_scaling_bits_minus5");
+ int bitsScal = point_cb_scaling_bits;
+ WRITE_CODE(cb_scaling_offset, 8, "cb_scaling_offset");
+
+ for (int i = 0; i < m_num_cb_points; i++) {
+ if (i)
+ WRITE_CODE(m_scaling_points_cb[i][0] - m_scaling_points_cb[i - 1][0], bitsIncr, "point_cb_value_increment[i]");
+ else
+ WRITE_CODE(m_scaling_points_cb[i][0], bitsIncr, "point_cb_value_increment[i]");
+ WRITE_CODE(m_scaling_points_cb[i][1], bitsScal, "point_cb_scaling[i]");
+ }
+ }
+
+ if (predict_scaling_flag)
+ WRITE_FLAG(predict_cr_scaling_flag, "predict_cr_scaling_flag");
+
+ WRITE_CODE(m_num_cr_points, 4, "num_cr_points");
+ if (m_num_cr_points) {
+ WRITE_CODE(point_cr_value_increment_bits - 1, 3, "point_cr_value_increment_bits_minus1");
+ int bitsIncr = point_cr_value_increment_bits;
+ WRITE_CODE(point_cr_scaling_bits - 5, 2, "point_cr_scaling_bits_minus5");
+ int bitsScal = point_cr_scaling_bits;
+ WRITE_CODE(cr_scaling_offset, 8, "cr_scaling_offset");
+
+ for (int i = 0; i < m_num_cr_points; i++) {
+ if (i)
+ WRITE_CODE(m_scaling_points_cr[i][0] - m_scaling_points_cr[i - 1][0], bitsIncr, "point_cr_value_increment[i]");
+ else
+ WRITE_CODE(m_scaling_points_cr[i][0], bitsIncr, "point_cr_value_increment[i]");
+ WRITE_CODE(m_scaling_points_cr[i][1], bitsScal, "point_cr_scaling[i]");
}
}
}
- WRITE_CODE(m_scaling_shift - 8, 2, "scaling_shift");
+
+ WRITE_CODE(m_scaling_shift - 8, 2, "grain_scaling_minus8");
WRITE_CODE(m_ar_coeff_lag, 2, "ar_coeff_lag");
- if (m_num_y_points)
+ int bits_per_ar_coef = 8;
+ if (m_num_y_points || predict_y_scaling_flag)
{
+ WRITE_CODE(bits_per_ar_coef - 5, 2, "bits_per_ar_coeff_y_minus5");
+
for (int i = 0; i < 24; i++)
{
- WRITE_CODE(m_ar_coeffs_y[i] + 128, 8, "ar_coeff_y[i]");
+ WRITE_CODE(m_ar_coeffs_y[i] + (1 << (bits_per_ar_coef - 1)), bits_per_ar_coef, "ar_coeff_y[i]");
}
}
- if (m_num_cb_points || m_chroma_scaling_from_luma)
+ if (m_num_cb_points || m_chroma_scaling_from_luma || predict_cb_scaling_flag)
{
+ WRITE_CODE(bits_per_ar_coef - 5, 2, "bits_per_ar_coeff_cb_minus5");
+
for (int i = 0; i < 25; i++)
{
- WRITE_CODE(m_ar_coeffs_cb[i] + 128, 8, "ar_coeff_cb[i]");
+ WRITE_CODE(m_ar_coeffs_cb[i] + (1 << (bits_per_ar_coef - 1)), bits_per_ar_coef, "ar_coeff_cb[i]");
}
}
- if (m_num_cr_points || m_chroma_scaling_from_luma)
+ if (m_num_cr_points || m_chroma_scaling_from_luma || predict_cr_scaling_flag)
{
+ WRITE_CODE(bits_per_ar_coef - 5, 2, "bits_per_ar_coeff_cr_minus5");
+
for (int i = 0; i < 25; i++)
{
- WRITE_CODE(m_ar_coeffs_cr[i] + 128, 8, "ar_coeff_cr[i]");
+ WRITE_CODE(m_ar_coeffs_cr[i] + (1 << (bits_per_ar_coef - 1)), bits_per_ar_coef, "ar_coeff_cr[i]");
}
}
WRITE_CODE(m_ar_coeff_shift - 6, 2, "ar_coeff_shift");
WRITE_CODE(m_grain_scale_shift, 2, "grain_scale_shift");
- if (m_num_cb_points)
+ if (m_num_cb_points && !predict_cb_scaling_flag)
{
WRITE_CODE(m_cb_mult, 8, "cb_mult");
WRITE_CODE(m_cb_luma_mult, 8, "cb_luma_mult");
WRITE_CODE(m_cb_offset, 9, "cb_offset");
}
- if (m_num_cr_points)
+ if (m_num_cr_points && !predict_cr_scaling_flag)
{
WRITE_CODE(m_cr_mult, 8, "cr_mult");
WRITE_CODE(m_cr_luma_mult, 8, "cr_luma_mult");
--
2.45.2
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20251121/1d11f8dc/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Update-the-support-to-signal-AOM-fgm-params.patch
Type: application/octet-stream
Size: 18857 bytes
Desc: 0001-Update-the-support-to-signal-AOM-fgm-params.patch
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20251121/1d11f8dc/attachment-0001.obj>
More information about the x265-devel
mailing list