[x265] [PATCH] Add Aom film grain characteristics as SEI message to the bitstream
Anusuya Kumarasamy
anusuya.kumarasamy at multicorewareinc.com
Fri Sep 27 10:05:46 UTC 2024
>From acb4ab5a4f14b7a88ccdf3bdc4b01ddf68fcec29 Mon Sep 17 00:00:00 2001
From: Hazarath Kumar M <hazarathkumar at multicorewareinc.com>
Date: Wed, 25 Sep 2024 14:35:27 +0530
Subject: [PATCH 4/5] Add Aom film grain characteristics as SEI message to
the
bitstream
---
doc/reST/cli.rst | 4 +
source/common/param.cpp | 7 ++
source/encoder/encoder.cpp | 11 +++
source/encoder/encoder.h | 2 +
source/encoder/frameencoder.cpp | 92 ++++++++++++++++++++++
source/encoder/frameencoder.h | 31 ++++++++
source/encoder/sei.h | 131 ++++++++++++++++++++++++++++++++
source/x265.h | 3 +
source/x265cli.cpp | 1 +
source/x265cli.h | 1 +
10 files changed, 283 insertions(+)
diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst
index 95cb37f20..a4907f7d2 100755
--- a/doc/reST/cli.rst
+++ b/doc/reST/cli.rst
@@ -2702,6 +2702,10 @@ Bitstream options
Refers to the film grain model characteristics for signal enhancement
information transmission.
+.. option:: --aom-film-grain <filename>
+
+ Refers to the AOM film grain model characteristics
+
**CLI_ONLY**
DCT Approximations
diff --git a/source/common/param.cpp b/source/common/param.cpp
index d08bb604e..ceef42589 100755
--- a/source/common/param.cpp
+++ b/source/common/param.cpp
@@ -402,6 +402,7 @@ void x265_param_default(x265_param* param)
#endif
/* Film grain characteristics model filename */
param->filmGrain = NULL;
+ param->aomFilmGrain = NULL;
param->bEnableSBRC = 0;
/* Multi-View Encoding*/
@@ -1455,6 +1456,7 @@ int x265_param_parse(x265_param* p, const char* name,
const char* value)
OPT("eos") p->bEnableEndOfSequence = atobool(value);
/* Film grain characterstics model filename */
OPT("film-grain") p->filmGrain = (char* )value;
+ OPT("aom-film-grain") p->aomFilmGrain = (char*)value;
OPT("mcstf") p->bEnableTemporalFilter = atobool(value);
OPT("sbrc") p->bEnableSBRC = atobool(value);
#if ENABLE_ALPHA
@@ -2403,6 +2405,8 @@ char *x265_param2string(x265_param* p, int padx, int
pady)
BOOL(p->bliveVBV2pass, "vbv-live-multi-pass");
if (p->filmGrain)
s += sprintf(s, " film-grain=%s", p->filmGrain); // Film grain
characteristics model filename
+ if (p->aomFilmGrain)
+ s += sprintf(s, " aom-film-grain=%s", p->aomFilmGrain);
BOOL(p->bEnableTemporalFilter, "mcstf");
#if ENABLE_ALPHA
BOOL(p->bEnableAlpha, "alpha");
@@ -2956,6 +2960,9 @@ void x265_copy_params(x265_param* dst, x265_param*
src)
/* Film grain */
if (src->filmGrain)
dst->filmGrain = src->filmGrain;
+ /* Aom Film grain*/
+ if (src->aomFilmGrain)
+ dst->aomFilmGrain = src->aomFilmGrain;
dst->bEnableSBRC = src->bEnableSBRC;
}
diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp
index 13b98e986..c78413bfb 100644
--- a/source/encoder/encoder.cpp
+++ b/source/encoder/encoder.cpp
@@ -142,6 +142,7 @@ Encoder::Encoder()
m_analysisFileIn = NULL;
m_analysisFileOut = NULL;
m_filmGrainIn = NULL;
+ m_aomFilmGrainIn = NULL;
m_naluFile = NULL;
m_offsetEmergency = NULL;
m_iFrameNum = 0;
@@ -533,6 +534,14 @@ void Encoder::create()
x265_log_file(NULL, X265_LOG_ERROR, "Failed to open film grain
characteristics binary file %s\n", m_param->filmGrain);
}
}
+ if (m_param->aomFilmGrain)
+ {
+ m_aomFilmGrainIn = x265_fopen(m_param->aomFilmGrain, "rb");
+ if (!m_aomFilmGrainIn)
+ {
+ x265_log_file(NULL, X265_LOG_ERROR, "Failed to open Aom film
grain characteristics binary file %s\n", m_param->aomFilmGrain);
+ }
+ }
m_bZeroLatency = !m_param->bframes && !m_param->lookaheadDepth &&
m_param->frameNumThreads == 1 && m_param->maxSlices == 1;
m_aborted |= parseLambdaFile(m_param);
@@ -973,6 +982,8 @@ void Encoder::destroy()
fclose(m_naluFile);
if (m_filmGrainIn)
x265_fclose(m_filmGrainIn);
+ if (m_aomFilmGrainIn)
+ x265_fclose(m_aomFilmGrainIn);
#ifdef SVT_HEVC
X265_FREE(m_svtAppData);
diff --git a/source/encoder/encoder.h b/source/encoder/encoder.h
index e5020c1dc..4b72f8bf9 100644
--- a/source/encoder/encoder.h
+++ b/source/encoder/encoder.h
@@ -285,6 +285,8 @@ public:
ThreadSafeInteger* zoneWriteCount;
/* Film grain model file */
FILE* m_filmGrainIn;
+ /* Aom film grain model file*/
+ FILE* m_aomFilmGrainIn;
OrigPicBuffer* m_origPicBuffer;
Encoder();
diff --git a/source/encoder/frameencoder.cpp
b/source/encoder/frameencoder.cpp
index deb478a0f..e21dbfa85 100644
--- a/source/encoder/frameencoder.cpp
+++ b/source/encoder/frameencoder.cpp
@@ -872,6 +872,14 @@ void FrameEncoder::compressFrame(int layer)
readModel(&m_filmGrain, this->m_top->m_filmGrainIn);
m_filmGrain.writeSEImessages(m_bs, *slice->m_sps,
NAL_UNIT_PREFIX_SEI, m_nalList, m_param->bSingleSeiNal, layer);
}
+ /* Write Aom film grain characteristics if present */
+ if (this->m_top->m_aomFilmGrainIn)
+ {
+ AomFilmGrainCharacteristics m_aomFilmGrain;
+ /* Read the Film grain model file */
+ readAomModel(&m_aomFilmGrain, this->m_top->m_aomFilmGrainIn);
+ m_aomFilmGrain.writeSEImessages(m_bs, *slice->m_sps,
NAL_UNIT_PREFIX_SEI, m_nalList, m_param->bSingleSeiNal);
+ }
/* Write user SEI */
for (int i = 0; i < m_frame[layer]->m_userSEI.numPayloads; i++)
{
@@ -2335,6 +2343,90 @@ void
FrameEncoder::readModel(FilmGrainCharacteristics* m_filmGrain, FILE* filmgr
}
}
}
+
+void FrameEncoder::readAomModel(AomFilmGrainCharacteristics*
m_aomFilmGrain, FILE* Aomfilmgrain)
+{
+ char const* errorMessage = "Error reading Aom FilmGrain
characteristics\n";
+ AomFilmGrain m_afg;
+ x265_fread((char*)&m_aomFilmGrain->m_apply_grain, sizeof(int32_t), 1,
Aomfilmgrain, errorMessage);
+ x265_fread((char*)&m_aomFilmGrain->m_grain_seed, sizeof(uint16_t), 1,
Aomfilmgrain, errorMessage);
+ x265_fread((char*)&m_aomFilmGrain->m_update_grain, sizeof(int32_t), 1,
Aomfilmgrain, errorMessage);
+ x265_fread((char*)&m_aomFilmGrain->m_num_y_points, sizeof(int32_t), 1,
Aomfilmgrain, errorMessage);
+ if (m_aomFilmGrain->m_num_y_points)
+ {
+ 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);
+ }
+ }
+ }
+ x265_fread((char*)&m_aomFilmGrain->m_num_cb_points, sizeof(int32_t),
1, Aomfilmgrain, errorMessage);
+ if (m_aomFilmGrain->m_num_cb_points)
+ {
+ 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);
+ }
+ }
+ }
+ x265_fread((char*)&m_aomFilmGrain->m_num_cr_points, sizeof(int32_t),
1, Aomfilmgrain, errorMessage);
+ if (m_aomFilmGrain->m_num_cr_points)
+ {
+ 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);
+ }
+ }
+ }
+ x265_fread((char*)&m_aomFilmGrain->m_scaling_shift, sizeof(int32_t),
1, Aomfilmgrain, errorMessage);
+ x265_fread((char*)&m_aomFilmGrain->m_ar_coeff_lag, sizeof(int32_t), 1,
Aomfilmgrain, errorMessage);
+ if (m_aomFilmGrain->m_num_y_points)
+ {
+
+ for (int i = 0; i < 24; i++)
+ {
+ x265_fread((char*)&m_aomFilmGrain->m_ar_coeffs_y[i],
sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ }
+ }
+ if (m_aomFilmGrain->m_num_cb_points ||
m_afg.m_chroma_scaling_from_luma)
+ {
+ for (int i = 0; i < 25; i++)
+ {
+ x265_fread((char*)&m_aomFilmGrain->m_ar_coeffs_cb[i],
sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ }
+ }
+ if (m_aomFilmGrain->m_num_cr_points ||
m_afg.m_chroma_scaling_from_luma)
+ {
+
+ for (int i = 0; i < 25; i++)
+ {
+ x265_fread((char*)&m_aomFilmGrain->m_ar_coeffs_cr[i],
sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ }
+ }
+ x265_fread((char*)&m_aomFilmGrain->m_ar_coeff_shift, sizeof(int32_t),
1, Aomfilmgrain, errorMessage);
+ x265_fread((char*)&m_aomFilmGrain->m_grain_scale_shift,
sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ if (m_aomFilmGrain->m_num_cb_points)
+ {
+ x265_fread((char*)&m_aomFilmGrain->m_cb_mult, sizeof(int32_t), 1,
Aomfilmgrain, errorMessage);
+ x265_fread((char*)&m_aomFilmGrain->m_cb_luma_mult,
sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ x265_fread((char*)&m_aomFilmGrain->m_cb_offset, sizeof(int32_t),
1, Aomfilmgrain, errorMessage);
+ }
+ if (m_aomFilmGrain->m_num_cr_points)
+ {
+ x265_fread((char*)&m_aomFilmGrain->m_cr_mult, sizeof(int32_t), 1,
Aomfilmgrain, errorMessage);
+ x265_fread((char*)&m_aomFilmGrain->m_cr_luma_mult,
sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+ x265_fread((char*)&m_aomFilmGrain->m_cr_offset, sizeof(int32_t),
1, Aomfilmgrain, errorMessage);
+ }
+ x265_fread((char*)&m_aomFilmGrain->m_overlap_flag, sizeof(int32_t), 1,
Aomfilmgrain, errorMessage);
+ x265_fread((char*)&m_aomFilmGrain->m_clip_to_restricted_range,
sizeof(int32_t), 1, Aomfilmgrain, errorMessage);
+}
+
#if ENABLE_LIBVMAF
void FrameEncoder::vmafFrameLevelScore()
{
diff --git a/source/encoder/frameencoder.h b/source/encoder/frameencoder.h
index ebc6e57c5..21d05c2f2 100644
--- a/source/encoder/frameencoder.h
+++ b/source/encoder/frameencoder.h
@@ -142,6 +142,36 @@ struct FGPresent
bool m_presentFlag[3];
};
+struct AomFilmGrain
+{
+ int32_t m_apply_grain;
+ int32_t m_update_grain;
+ int32_t m_scaling_points_y[14][2];
+ int32_t m_num_y_points;
+ int32_t m_scaling_points_cb[10][2];
+ int32_t m_num_cb_points;
+ int32_t m_scaling_points_cr[10][2];
+ int32_t m_num_cr_points;
+ int32_t m_scaling_shift;
+ int32_t m_ar_coeff_lag;
+ int32_t m_ar_coeffs_y[24];
+ int32_t m_ar_coeffs_cb[25];
+ int32_t m_ar_coeffs_cr[25];
+ int32_t m_ar_coeff_shift;
+ int32_t m_cb_mult;
+ int32_t m_cb_luma_mult;
+ int32_t m_cb_offset;
+ int32_t m_cr_mult;
+ int32_t m_cr_luma_mult;
+ int32_t m_cr_offset;
+ int32_t m_overlap_flag;
+ int32_t m_clip_to_restricted_range;
+ int32_t m_bitDepth;
+ int32_t m_chroma_scaling_from_luma;
+ int32_t m_grain_scale_shift;
+ uint16_t m_grain_seed;
+};
+
// Manages the wave-front processing of a single encoding frame
class FrameEncoder : public WaveFront, public Thread
{
@@ -287,6 +317,7 @@ protected:
void computeAvgTrainingData(int layer);
void collectDynDataRow(CUData& ctu, FrameStats* rowStats);
void readModel(FilmGrainCharacteristics* m_filmGrain, FILE* filmgrain);
+ void readAomModel(AomFilmGrainCharacteristics* m_aomFilmGrain, FILE*
Aomfilmgrain);
};
}
diff --git a/source/encoder/sei.h b/source/encoder/sei.h
index e357a1bf5..1fa4dc69b 100644
--- a/source/encoder/sei.h
+++ b/source/encoder/sei.h
@@ -168,6 +168,137 @@ class FilmGrainCharacteristics : public SEI
}
};
+class AomFilmGrainCharacteristics : public SEI {
+
+public:
+
+ AomFilmGrainCharacteristics()
+ {
+ m_payloadType = USER_DATA_REGISTERED_ITU_T_T35;
+ m_payloadSize = 0;
+ }
+
+ int32_t m_apply_grain;
+ int32_t m_update_grain;
+ int32_t m_scaling_points_y[14][2];
+ int32_t m_num_y_points;
+ int32_t m_scaling_points_cb[10][2];
+ int32_t m_num_cb_points;
+ int32_t m_scaling_points_cr[10][2];
+ int32_t m_num_cr_points;
+ int32_t m_scaling_shift;
+ int32_t m_ar_coeff_lag;
+ int32_t m_ar_coeffs_y[24];
+ int32_t m_ar_coeffs_cb[25];
+ int32_t m_ar_coeffs_cr[25];
+ int32_t m_ar_coeff_shift;
+ int32_t m_cb_mult;
+ int32_t m_cb_luma_mult;
+ int32_t m_cb_offset;
+ int32_t m_cr_mult;
+ int32_t m_cr_luma_mult;
+ int32_t m_cr_offset;
+ int32_t m_overlap_flag;
+ int32_t m_clip_to_restricted_range;
+ int32_t m_bitDepth;
+ int32_t m_chroma_scaling_from_luma;
+ int32_t m_grain_scale_shift;
+ uint16_t m_grain_seed;
+
+ void writeSEI(const SPS&)
+ {
+ WRITE_CODE(0x26, 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(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)
+ {
+ for (int i = 0; i < m_num_y_points; i++)
+ {
+ for (int j = 0; j < 2; j++)
+ {
+ WRITE_CODE(m_scaling_points_y[i][j], 8,
"scaling_points_y[i][j]");
+ }
+ }
+ }
+ 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_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]");
+ }
+ }
+ }
+ WRITE_CODE(m_scaling_shift - 8, 2, "scaling_shift");
+ WRITE_CODE(m_ar_coeff_lag, 2, "ar_coeff_lag");
+ if (m_num_y_points)
+ {
+ for (int i = 0; i < 24; i++)
+ {
+ WRITE_CODE(m_ar_coeffs_y[i] + 128, 8, "ar_coeff_y[i]");
+ }
+ }
+ if (m_num_cb_points || m_chroma_scaling_from_luma)
+ {
+ for (int i = 0; i < 25; i++)
+ {
+ WRITE_CODE(m_ar_coeffs_cb[i] + 128, 8, "ar_coeff_cb[i]");
+ }
+ }
+ if (m_num_cr_points || m_chroma_scaling_from_luma)
+ {
+ for (int i = 0; i < 25; i++)
+ {
+ WRITE_CODE(m_ar_coeffs_cr[i] + 128, 8, "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)
+ {
+ 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)
+ {
+ WRITE_CODE(m_cr_mult, 8, "cr_mult");
+ WRITE_CODE(m_cr_luma_mult, 8, "cr_luma_mult");
+ WRITE_CODE(m_cr_offset, 9, "cr_offset");
+ }
+ WRITE_FLAG(m_overlap_flag, "overlap_flag");
+ WRITE_FLAG(m_clip_to_restricted_range, "clip_to_restricted_range");
+ 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");
+ }
+ }
+ }
+};
+
static const uint32_t ISO_IEC_11578_LEN = 16;
class SEIuserDataUnregistered : public SEI
diff --git a/source/x265.h b/source/x265.h
index 532d01b22..54e699317 100644
--- a/source/x265.h
+++ b/source/x265.h
@@ -2307,6 +2307,9 @@ typedef struct x265_param
/* Film Grain Characteristic file */
char* filmGrain;
+ /* Aom Film Grain Characteristic file */
+ char* aomFilmGrain;
+
/*Motion compensated temporal filter*/
int bEnableTemporalFilter;
double temporalFilterStrength;
diff --git a/source/x265cli.cpp b/source/x265cli.cpp
index ca7d9c973..b9ce96f19 100755
--- a/source/x265cli.cpp
+++ b/source/x265cli.cpp
@@ -408,6 +408,7 @@ namespace X265_NS {
H1(" 4 - encoder abort\n");
H0("\nSEI Message Options\n");
H0(" --film-grain <filename> File containing Film
Grain Characteristics to be written as a SEI Message\n");
+ H0(" --aom-film-grain <filename> File containing Aom Film
Grain Characteristics to be written as a SEI Message\n");
#undef OPT
#undef H0
diff --git a/source/x265cli.h b/source/x265cli.h
index 2ec48352d..3df0fa7a6 100644
--- a/source/x265cli.h
+++ b/source/x265cli.h
@@ -395,6 +395,7 @@ static const struct option long_options[] =
{ "max-vbv-fullness", required_argument, NULL, 0 },
{ "scenecut-qp-config", required_argument, NULL, 0 },
{ "film-grain", required_argument, NULL, 0 },
+ { "aom-film-grain", required_argument, NULL, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
--
2.36.0.windows.1
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20240927/d4aa2516/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0004-Add-Aom-film-grain-characteristics-as-SEI-message-to.patch
Type: application/octet-stream
Size: 17735 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20240927/d4aa2516/attachment-0001.obj>
More information about the x265-devel
mailing list