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