<div dir="ltr">Pushed to master branch</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Mar 4, 2022 at 1:46 PM Keshav E <<a href="mailto:keshav@multicorewareinc.com">keshav@multicorewareinc.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">Observed a warning in the patch sent in the previous email. Resolved the warning and reattaching the patch here.<div>From 0ba89aaa409d09f94348536edf7cede8f3f7f7e7 Mon Sep 17 00:00:00 2001<br>From: Keshav E <<a href="mailto:keshav@multicorewareinc.com" target="_blank">keshav@multicorewareinc.com</a>><br>Date: Fri, 4 Mar 2022 12:36:14 +0530<br>Subject: [PATCH] Add film grain characteristics as a SEI message to the<br> bitstream<br><br>---<br> doc/reST/cli.rst                 |  6 ++<br> source/CMakeLists.txt            |  2 +-<br> source/common/common.h           |  9 +++<br> source/common/param.cpp          |  9 +++<br> source/encoder/encoder.cpp       | 12 ++++<br> source/encoder/encoder.h         |  2 +<br> source/encoder/frameencoder.cpp  | 57 ++++++++++++++++++-<br> source/encoder/frameencoder.h    | 29 ++++++++++<br> source/encoder/sei.h             | 95 ++++++++++++++++++++++++++++++++<br> source/test/regression-tests.txt |  4 ++<br> source/test/smoke-tests.txt      |  4 ++<br> source/x265.h                    |  3 +<br> source/x265cli.cpp               |  3 +<br> source/x265cli.h                 |  1 +<br> 14 files changed, 234 insertions(+), 2 deletions(-)<br><br>diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst<br>index 1491b63fe..1640c1f8e 100755<br>--- a/doc/reST/cli.rst<br>+++ b/doc/reST/cli.rst<br>@@ -2659,6 +2659,12 @@ Bitstream options<br>     Emit SEI messages in a single NAL unit instead of multiple NALs. Default disabled.<br>   When HRD SEI is enabled the HM decoder will throw a warning.<br> <br>+.. option:: --film-grain <filename><br>+<br>+    Refers to the film grain model characteristics for signal enhancement information transmission<br>+<br>+    **CLI_ONLY**<br>+<br> DCT Approximations<br> =================<br> <br>diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt<br>index 60031df63..13e4750de 100755<br>--- a/source/CMakeLists.txt<br>+++ b/source/CMakeLists.txt<br>@@ -29,7 +29,7 @@ option(NATIVE_BUILD "Target the build CPU" OFF)<br> option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF)<br> mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)<br> # X265_BUILD must be incremented each time the public API is changed<br>-set(X265_BUILD 203)<br>+set(X265_BUILD 204)<br> configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265.def.in" target="_blank">x265.def.in</a>"<br>                "${PROJECT_BINARY_DIR}/x265.def")<br> configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265_config.h.in" target="_blank">x265_config.h.in</a>"<br>diff --git a/source/common/common.h b/source/common/common.h<br>index 8c06cd79e..a245c7dae 100644<br>--- a/source/common/common.h<br>+++ b/source/common/common.h<br>@@ -340,6 +340,7 @@ typedef int16_t  coeff_t;      // transform coefficient<br> #define FILLER_OVERHEAD (NAL_TYPE_OVERHEAD + START_CODE_OVERHEAD + 1)<br> <br> #define MAX_NUM_DYN_REFINE          (NUM_CU_DEPTH * X265_REFINE_INTER_LEVELS)<br>+#define X265_BYTE 8<br> <br> namespace X265_NS {<br> <br>@@ -434,6 +435,14 @@ int      x265_rename(const char* oldName, const char* newName);<br> #define  x265_unlink(fileName) unlink(fileName)<br> #define  x265_rename(oldName, newName) rename(oldName, newName)<br> #endif<br>+/* Close a file */<br>+#define  x265_fclose(file) if (file != NULL) fclose(file); file=NULL;<br>+#define x265_fread(val, size, readSize, fileOffset,errorMessage)\<br>+    if (fread(val, size, readSize, fileOffset) != readSize)\<br>+    {\<br>+        x265_log(NULL, X265_LOG_ERROR, errorMessage); \<br>+        return; \<br>+    }<br> int      x265_exp2fix8(double x);<br> <br> double   x265_ssim2dB(double ssim);<br>diff --git a/source/common/param.cpp b/source/common/param.cpp<br>index f72305372..ed6973d9c 100755<br>--- a/source/common/param.cpp<br>+++ b/source/common/param.cpp<br>@@ -384,6 +384,8 @@ void x265_param_default(x265_param* param)<br>     param->svtHevcParam = svtParam;<br>     svt_param_default(param);<br> #endif<br>+    /* Film grain characteristics model filename */<br>+    param->filmGrain = NULL;<br> }<br> <br> int x265_param_default_preset(x265_param* param, const char* preset, const char* tune)<br>@@ -1460,6 +1462,8 @@ int x265_param_parse(x265_param* p, const char* name, const char* value)<br>         OPT("video-signal-type-preset") p->videoSignalTypePreset = strdup(value);<br>         OPT("eob") p->bEnableEndOfBitstream = atobool(value);<br>         OPT("eos") p->bEnableEndOfSequence = atobool(value);<br>+        /* Film grain characterstics model filename */<br>+        OPT("film-grain") p->filmGrain = (char* )value;<br>         else<br>             return X265_PARAM_BAD_NAME;<br>     }<br>@@ -2353,6 +2357,8 @@ char *x265_param2string(x265_param* p, int padx, int pady)<br>     s += sprintf(s, "conformance-window-offsets right=%d bottom=%d", p->confWinRightOffset, p->confWinBottomOffset);<br>     s += sprintf(s, " decoder-max-rate=%d", p->decoderVbvMaxRate);<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> #undef BOOL<br>     return buf;<br> }<br>@@ -2726,6 +2732,9 @@ void x265_copy_params(x265_param* dst, x265_param* src)<br> #ifdef SVT_HEVC<br>     memcpy(dst->svtHevcParam, src->svtHevcParam, sizeof(EB_H265_ENC_CONFIGURATION));<br> #endif<br>+    /* Film grain */<br>+    if (src->filmGrain)<br>+        dst->filmGrain = src->filmGrain;<br> }<br> <br> #ifdef SVT_HEVC<br>diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp<br>index 5d0c9a050..f33a6d053 100644<br>--- a/source/encoder/encoder.cpp<br>+++ b/source/encoder/encoder.cpp<br>@@ -142,6 +142,7 @@ Encoder::Encoder()<br>     m_threadPool = NULL;<br>     m_analysisFileIn = NULL;<br>     m_analysisFileOut = NULL;<br>+    m_filmGrainIn = NULL;<br>     m_naluFile = NULL;<br>     m_offsetEmergency = NULL;<br>     m_iFrameNum = 0;<br>@@ -551,6 +552,15 @@ void Encoder::create()<br>             }<br>         }<br>     }<br>+    if (m_param->filmGrain)<br>+    {<br>+        m_filmGrainIn = x265_fopen(m_param->filmGrain, "rb");<br>+        if (!m_filmGrainIn)<br>+        {<br>+            x265_log_file(NULL, X265_LOG_ERROR, "Failed to open film grain characteristics binary file %s\n", m_param->filmGrain);<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> <br>@@ -996,6 +1006,8 @@ void Encoder::destroy()<br>      }<br>     if (m_naluFile)<br>         fclose(m_naluFile);<br>+    if (m_filmGrainIn)<br>+        x265_fclose(m_filmGrainIn);<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 2ee5bdaee..cfbb55fe0 100644<br>--- a/source/encoder/encoder.h<br>+++ b/source/encoder/encoder.h<br>@@ -295,6 +295,8 @@ public:<br> <br>     ThreadSafeInteger* zoneReadCount;<br>     ThreadSafeInteger* zoneWriteCount;<br>+    /* Film grain model file */<br>+    FILE* m_filmGrainIn;<br> <br>     Encoder();<br>     ~Encoder()<br>diff --git a/source/encoder/frameencoder.cpp b/source/encoder/frameencoder.cpp<br>index 1b3875a25..9dc9242f6 100644<br>--- a/source/encoder/frameencoder.cpp<br>+++ b/source/encoder/frameencoder.cpp<br>@@ -762,7 +762,14 @@ void FrameEncoder::compressFrame()<br>         m_seiAlternativeTC.m_preferredTransferCharacteristics = m_param->preferredTransferCharacteristics;<br>         m_seiAlternativeTC.writeSEImessages(m_bs, *slice->m_sps, NAL_UNIT_PREFIX_SEI, m_nalList, m_param->bSingleSeiNal);<br>     }<br>-<br>+    /* Write Film grain characteristics if present */<br>+    if (this->m_top->m_filmGrainIn)<br>+    {<br>+        FilmGrainCharacteristics m_filmGrain;<br>+        /* Read the Film grain model file */<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);<br>+    }<br>     /* Write user SEI */<br>     for (int i = 0; i < m_frame->m_userSEI.numPayloads; i++)<br>     {<br>@@ -2133,6 +2140,54 @@ void FrameEncoder::noiseReductionUpdate()<br>         m_nr->nrOffsetDenoise[cat][0] = 0;<br>     }<br> }<br>+<br>+void FrameEncoder::readModel(FilmGrainCharacteristics* m_filmGrain, FILE* filmgrain)<br>+{<br>+    char const* errorMessage = "Error reading FilmGrain characteristics\n";<br>+    FilmGrain m_fg;<br>+    x265_fread((char* )&m_fg, sizeof(bool) * 3 + sizeof(uint8_t), 1, filmgrain, errorMessage);<br>+    m_filmGrain->m_filmGrainCharacteristicsCancelFlag = m_fg.m_filmGrainCharacteristicsCancelFlag;<br>+    m_filmGrain->m_filmGrainCharacteristicsPersistenceFlag = m_fg.m_filmGrainCharacteristicsPersistenceFlag;<br>+    m_filmGrain->m_filmGrainModelId = m_fg.m_filmGrainModelId;<br>+    m_filmGrain->m_separateColourDescriptionPresentFlag = m_fg.m_separateColourDescriptionPresentFlag;<br>+    if (m_filmGrain->m_separateColourDescriptionPresentFlag)<br>+    {<br>+        ColourDescription m_clr;<br>+        x265_fread((char* )&m_clr, sizeof(bool) + sizeof(uint8_t) * 5, 1, filmgrain, errorMessage);<br>+        m_filmGrain->m_filmGrainBitDepthLumaMinus8 = m_clr.m_filmGrainBitDepthLumaMinus8;<br>+        m_filmGrain->m_filmGrainBitDepthChromaMinus8 = m_clr.m_filmGrainBitDepthChromaMinus8;<br>+        m_filmGrain->m_filmGrainFullRangeFlag = m_clr.m_filmGrainFullRangeFlag;<br>+        m_filmGrain->m_filmGrainColourPrimaries = m_clr.m_filmGrainColourPrimaries;<br>+        m_filmGrain->m_filmGrainTransferCharacteristics = m_clr.m_filmGrainTransferCharacteristics;<br>+        m_filmGrain->m_filmGrainMatrixCoeffs = m_clr.m_filmGrainMatrixCoeffs;<br>+    }<br>+    FGPresent m_present;<br>+    x265_fread((char* )&m_present, sizeof(bool) * 3 + sizeof(uint8_t) * 2, 1, filmgrain, errorMessage);<br>+    m_filmGrain->m_blendingModeId = m_present.m_blendingModeId;<br>+    m_filmGrain->m_log2ScaleFactor = m_present.m_log2ScaleFactor;<br>+    m_filmGrain->m_compModel[0].bPresentFlag = m_present.m_presentFlag[0];<br>+    m_filmGrain->m_compModel[1].bPresentFlag = m_present.m_presentFlag[1];<br>+    m_filmGrain->m_compModel[2].bPresentFlag = m_present.m_presentFlag[2];<br>+    for (int i = 0; i < MAX_NUM_COMPONENT; i++)<br>+    {<br>+        if (m_filmGrain->m_compModel[i].bPresentFlag)<br>+        {<br>+            x265_fread((char* )(&m_filmGrain->m_compModel[i].m_filmGrainNumIntensityIntervalMinus1), sizeof(uint8_t), 1, filmgrain, errorMessage);<br>+            x265_fread((char* )(&m_filmGrain->m_compModel[i].numModelValues), sizeof(uint8_t), 1, filmgrain, errorMessage);<br>+            m_filmGrain->m_compModel[i].intensityValues = (FilmGrainCharacteristics::CompModelIntensityValues* ) malloc(sizeof(FilmGrainCharacteristics::CompModelIntensityValues) * (m_filmGrain->m_compModel[i].m_filmGrainNumIntensityIntervalMinus1+1)) ;<br>+            for (int j = 0; j <= m_filmGrain->m_compModel[i].m_filmGrainNumIntensityIntervalMinus1; j++)<br>+            {<br>+                x265_fread((char* )(&m_filmGrain->m_compModel[i].intensityValues[j].intensityIntervalLowerBound), sizeof(uint8_t), 1, filmgrain, errorMessage);<br>+                x265_fread((char* )(&m_filmGrain->m_compModel[i].intensityValues[j].intensityIntervalUpperBound), sizeof(uint8_t), 1, filmgrain, errorMessage);<br>+                m_filmGrain->m_compModel[i].intensityValues[j].compModelValue = (int* ) malloc(sizeof(int) * (m_filmGrain->m_compModel[i].numModelValues));<br>+                for (int k = 0; k < m_filmGrain->m_compModel[i].numModelValues; k++)<br>+                {<br>+                    x265_fread((char* )(&m_filmGrain->m_compModel[i].intensityValues[j].compModelValue[k]), sizeof(int), 1, filmgrain, errorMessage);<br>+                }<br>+            }<br>+        }<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 f4cfc624d..5d972cb26 100644<br>--- a/source/encoder/frameencoder.h<br>+++ b/source/encoder/frameencoder.h<br>@@ -113,6 +113,34 @@ struct CTURow<br>     }<br> };<br> <br>+/*Film grain characteristics*/<br>+struct FilmGrain<br>+{<br>+    bool    m_filmGrainCharacteristicsCancelFlag;<br>+    bool    m_filmGrainCharacteristicsPersistenceFlag;<br>+    bool    m_separateColourDescriptionPresentFlag;<br>+    uint8_t m_filmGrainModelId;<br>+    uint8_t m_blendingModeId;<br>+    uint8_t m_log2ScaleFactor;<br>+};<br>+<br>+struct ColourDescription<br>+{<br>+    bool        m_filmGrainFullRangeFlag;<br>+    uint8_t     m_filmGrainBitDepthLumaMinus8;<br>+    uint8_t     m_filmGrainBitDepthChromaMinus8;<br>+    uint8_t     m_filmGrainColourPrimaries;<br>+    uint8_t     m_filmGrainTransferCharacteristics;<br>+    uint8_t     m_filmGrainMatrixCoeffs;<br>+};<br>+<br>+struct FGPresent<br>+{<br>+    uint8_t     m_blendingModeId;<br>+    uint8_t     m_log2ScaleFactor;<br>+    bool        m_presentFlag[3];<br>+};<br>+<br> // Manages the wave-front processing of a single encoding frame<br> class FrameEncoder : public WaveFront, public Thread<br> {<br>@@ -250,6 +278,7 @@ protected:<br>     void collectDynDataFrame();<br>     void computeAvgTrainingData();<br>     void collectDynDataRow(CUData& ctu, FrameStats* rowStats);    <br>+    void readModel(FilmGrainCharacteristics* m_filmGrain, FILE* filmgrain);<br> };<br> }<br> <br>diff --git a/source/encoder/sei.h b/source/encoder/sei.h<br>index 61d39edd9..03e210639 100644<br>--- a/source/encoder/sei.h<br>+++ b/source/encoder/sei.h<br>@@ -73,6 +73,101 @@ public:<br>     }<br> };<br> <br>+/* Film grain characteristics */<br>+class FilmGrainCharacteristics : public SEI<br>+{<br>+  public:<br>+<br>+    FilmGrainCharacteristics()<br>+    {<br>+        m_payloadType = FILM_GRAIN_CHARACTERISTICS;<br>+        m_payloadSize = 0;<br>+    }<br>+<br>+    struct CompModelIntensityValues<br>+    {<br>+        uint8_t intensityIntervalLowerBound;<br>+        uint8_t intensityIntervalUpperBound;<br>+        int*    compModelValue;<br>+    };<br>+<br>+    struct CompModel<br>+    {<br>+        bool    bPresentFlag;<br>+        uint8_t numModelValues;<br>+        uint8_t m_filmGrainNumIntensityIntervalMinus1;<br>+        CompModelIntensityValues* intensityValues;<br>+    };<br>+<br>+    CompModel   m_compModel[MAX_NUM_COMPONENT];<br>+    bool        m_filmGrainCharacteristicsPersistenceFlag;<br>+    bool        m_filmGrainCharacteristicsCancelFlag;<br>+    bool        m_separateColourDescriptionPresentFlag;<br>+    bool        m_filmGrainFullRangeFlag;<br>+    uint8_t     m_filmGrainModelId;<br>+    uint8_t     m_blendingModeId;<br>+    uint8_t     m_log2ScaleFactor;<br>+    uint8_t     m_filmGrainBitDepthLumaMinus8;<br>+    uint8_t     m_filmGrainBitDepthChromaMinus8;<br>+    uint8_t     m_filmGrainColourPrimaries;<br>+    uint8_t     m_filmGrainTransferCharacteristics;<br>+    uint8_t     m_filmGrainMatrixCoeffs;<br>+<br>+    void writeSEI(const SPS&)<br>+    {<br>+        WRITE_FLAG(m_filmGrainCharacteristicsCancelFlag, "film_grain_characteristics_cancel_flag");<br>+<br>+        if (!m_filmGrainCharacteristicsCancelFlag)<br>+        {<br>+            WRITE_CODE(m_filmGrainModelId, 2, "film_grain_model_id");<br>+            WRITE_FLAG(m_separateColourDescriptionPresentFlag, "separate_colour_description_present_flag");<br>+            if (m_separateColourDescriptionPresentFlag)<br>+            {<br>+                WRITE_CODE(m_filmGrainBitDepthLumaMinus8, 3, "film_grain_bit_depth_luma_minus8");<br>+                WRITE_CODE(m_filmGrainBitDepthChromaMinus8, 3, "film_grain_bit_depth_chroma_minus8");<br>+                WRITE_FLAG(m_filmGrainFullRangeFlag, "film_grain_full_range_flag");<br>+                WRITE_CODE(m_filmGrainColourPrimaries, X265_BYTE, "film_grain_colour_primaries");<br>+                WRITE_CODE(m_filmGrainTransferCharacteristics, X265_BYTE, "film_grain_transfer_characteristics");<br>+                WRITE_CODE(m_filmGrainMatrixCoeffs, X265_BYTE, "film_grain_matrix_coeffs");<br>+            }<br>+            WRITE_CODE(m_blendingModeId, 2, "blending_mode_id");<br>+            WRITE_CODE(m_log2ScaleFactor, 4, "log2_scale_factor");<br>+            for (uint8_t c = 0; c < 3; c++)<br>+            {<br>+                WRITE_FLAG(m_compModel[c].bPresentFlag && m_compModel[c].m_filmGrainNumIntensityIntervalMinus1 + 1 > 0 && m_compModel[c].numModelValues > 0, "comp_model_present_flag[c]");<br>+            }<br>+            for (uint8_t c = 0; c < 3; c++)<br>+            {<br>+                if (m_compModel[c].bPresentFlag && m_compModel[c].m_filmGrainNumIntensityIntervalMinus1 + 1 > 0 && m_compModel[c].numModelValues > 0)<br>+                {<br>+                    assert(m_compModel[c].m_filmGrainNumIntensityIntervalMinus1 + 1 <= 256);<br>+                    assert(m_compModel[c].numModelValues <= X265_BYTE);<br>+                    WRITE_CODE(m_compModel[c].m_filmGrainNumIntensityIntervalMinus1 , X265_BYTE, "num_intensity_intervals_minus1[c]");<br>+                    WRITE_CODE(m_compModel[c].numModelValues - 1, 3, "num_model_values_minus1[c]");<br>+                    for (uint8_t interval = 0; interval < m_compModel[c].m_filmGrainNumIntensityIntervalMinus1 + 1; interval++)<br>+                    {<br>+                        WRITE_CODE(m_compModel[c].intensityValues[interval].intensityIntervalLowerBound, X265_BYTE, "intensity_interval_lower_bound[c][i]");<br>+                        WRITE_CODE(m_compModel[c].intensityValues[interval].intensityIntervalUpperBound, X265_BYTE, "intensity_interval_upper_bound[c][i]");<br>+                        for (uint8_t j = 0; j < m_compModel[c].numModelValues; j++)<br>+                        {<br>+                            WRITE_SVLC(m_compModel[c].intensityValues[interval].compModelValue[j],"comp_model_value[c][i]");<br>+                        }<br>+                    }<br>+                }<br>+            }<br>+            WRITE_FLAG(m_filmGrainCharacteristicsPersistenceFlag, "film_grain_characteristics_persistence_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>+<br> static const uint32_t ISO_IEC_11578_LEN = 16;<br> <br> class SEIuserDataUnregistered : public SEI<br>diff --git a/source/test/regression-tests.txt b/source/test/regression-tests.txt<br>index 26d43b28a..10a4449e7 100644<br>--- a/source/test/regression-tests.txt<br>+++ b/source/test/regression-tests.txt<br>@@ -195,4 +195,8 @@ CrowdRun_1920x1080_50_10bit_422.yuv,--no-cutree --analysis-save x265_analysis.da<br> #segment encoding<br> BasketballDrive_1920x1080_50.y4m, --preset ultrafast --no-open-gop --chunk-start 100 --chunk-end 200<br> <br>+#Test FG SEI message addition<br>+#OldTownCross_1920x1080_50_10bit_422.yuv,--preset slower --tune grain --film-grain "OldTownCross_1920x1080_50_10bit_422.bin"<br>+#RaceHorses_416x240_30_10bit.yuv,--preset ultrafast --signhide --colormatrix bt709 --film-grain "RaceHorses_416x240_30_10bit.bin"<br>+<br> # vim: tw=200<br>diff --git a/source/test/smoke-tests.txt b/source/test/smoke-tests.txt<br>index 041b97e76..a88a225b4 100644<br>--- a/source/test/smoke-tests.txt<br>+++ b/source/test/smoke-tests.txt<br>@@ -23,3 +23,7 @@ CrowdRun_1920x1080_50_10bit_444.yuv,--preset=superfast --bitrate 7000 --sao --li<br> # Main12 intraCost overflow bug test<br> 720p50_parkrun_ter.y4m,--preset medium<br> 720p50_parkrun_ter.y4m,--preset=fast --hevc-aq --no-cutree<br>+# Test FG SEI message addition<br>+# CrowdRun_1920x1080_50_10bit_444.yuv,--preset=ultrafast --weightp --keyint -1 --film-grain "CrowdRun_1920x1080_50_10bit_444.bin"<br>+# DucksAndLegs_1920x1080_60_10bit_422.yuv,--preset=veryfast --min-cu 16 --film-grain "DucksAndLegs_1920x1080_60_10bit_422.bin"<br>+# NebutaFestival_2560x1600_60_10bit_crop.yuv,--preset=superfast --bitrate 10000 --sao --limit-sao --cll --max-cll "1000,400" --film-grain "NebutaFestival_2560x1600_60_10bit_crop.bin"<br>diff --git a/source/x265.h b/source/x265.h<br>index bf945498f..5d242d653 100644<br>--- a/source/x265.h<br>+++ b/source/x265.h<br>@@ -1989,6 +1989,9 @@ typedef struct x265_param<br>     /* Flag to turn on/off traditional scenecut detection in histogram based scenecut detection.<br>      * When false, only spatial properties are used for scenecut detection. Default true */<br>     int      bEnableTradScdInHscd;<br>+<br>+    /* Film Grain Characteristic file */<br>+    char* filmGrain;<br> } x265_param;<br> <br> /* x265_param_alloc:<br>diff --git a/source/x265cli.cpp b/source/x265cli.cpp<br>index bfb6293f3..3a03de579 100755<br>--- a/source/x265cli.cpp<br>+++ b/source/x265cli.cpp<br>@@ -391,6 +391,9 @@ namespace X265_NS {<br>         H1("    2 - unable to open encoder\n");<br>         H1("    3 - unable to generate stream headers\n");<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>+<br> #undef OPT<br> #undef H0<br> #undef H1<br>diff --git a/source/x265cli.h b/source/x265cli.h<br>index 8fcf37b8a..7072f7616 100644<br>--- a/source/x265cli.h<br>+++ b/source/x265cli.h<br>@@ -380,6 +380,7 @@ static const struct option long_options[] =<br>     { "abr-ladder", required_argument, NULL, 0 },<br>     { "min-vbv-fullness", required_argument, NULL, 0 },<br>     { "max-vbv-fullness", required_argument, NULL, 0 },<br>+    { "film-grain", required_argument, NULL, 0 },<br>     { 0, 0, 0, 0 },<br>     { 0, 0, 0, 0 },<br>     { 0, 0, 0, 0 },<br>-- <br>2.20.1.windows.1<br><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Mar 4, 2022 at 11:09 AM Srikanth Kurapati <<a href="mailto:srikanth.kurapati@multicorewareinc.com" target="_blank">srikanth.kurapati@multicorewareinc.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">This patch looks good to be pushed.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Mar 4, 2022 at 10:32 AM Keshav E <<a href="mailto:keshav@multicorewareinc.com" target="_blank">keshav@multicorewareinc.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">From 10084990ea36a8d29432996b81fe6de427daaf69 Mon Sep 17 00:00:00 2001<br>From: Keshav E <<a href="mailto:keshav@multicorewareinc.com" target="_blank">keshav@multicorewareinc.com</a>><br>Date: Thu, 3 Mar 2022 14:30:57 +0530<br>Subject: [PATCH] Add film grain characteristics as a SEI message to the<br> bitstream<br><br>---<br> doc/reST/cli.rst                 |  6 ++<br> source/CMakeLists.txt            |  2 +-<br> source/common/common.h           |  9 +++<br> source/common/param.cpp          |  9 +++<br> source/encoder/encoder.cpp       | 12 ++++<br> source/encoder/encoder.h         |  2 +<br> source/encoder/frameencoder.cpp  | 57 ++++++++++++++++++-<br> source/encoder/frameencoder.h    | 29 ++++++++++<br> source/encoder/sei.h             | 95 ++++++++++++++++++++++++++++++++<br> source/test/regression-tests.txt |  4 ++<br> source/test/smoke-tests.txt      |  4 ++<br> source/x265.h                    |  3 +<br> source/x265cli.cpp               |  3 +<br> source/x265cli.h                 |  1 +<br> 14 files changed, 234 insertions(+), 2 deletions(-)<br><br>diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst<br>index 1491b63fe..1640c1f8e 100755<br>--- a/doc/reST/cli.rst<br>+++ b/doc/reST/cli.rst<br>@@ -2659,6 +2659,12 @@ Bitstream options<br>       Emit SEI messages in a single NAL unit instead of multiple NALs. Default disabled.<br>   When HRD SEI is enabled the HM decoder will throw a warning.<br> <br>+.. option:: --film-grain <filename><br>+<br>+    Refers to the film grain model characteristics for signal enhancement information transmission<br>+<br>+    **CLI_ONLY**<br>+<br> DCT Approximations<br> =================<br> <br>diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt<br>index 60031df63..13e4750de 100755<br>--- a/source/CMakeLists.txt<br>+++ b/source/CMakeLists.txt<br>@@ -29,7 +29,7 @@ option(NATIVE_BUILD "Target the build CPU" OFF)<br> option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF)<br> mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)<br> # X265_BUILD must be incremented each time the public API is changed<br>-set(X265_BUILD 203)<br>+set(X265_BUILD 204)<br> configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265.def.in" target="_blank">x265.def.in</a>"<br>                "${PROJECT_BINARY_DIR}/x265.def")<br> configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265_config.h.in" target="_blank">x265_config.h.in</a>"<br>diff --git a/source/common/common.h b/source/common/common.h<br>index 8c06cd79e..a245c7dae 100644<br>--- a/source/common/common.h<br>+++ b/source/common/common.h<br>@@ -340,6 +340,7 @@ typedef int16_t  coeff_t;      // transform coefficient<br> #define FILLER_OVERHEAD (NAL_TYPE_OVERHEAD + START_CODE_OVERHEAD + 1)<br> <br> #define MAX_NUM_DYN_REFINE          (NUM_CU_DEPTH * X265_REFINE_INTER_LEVELS)<br>+#define X265_BYTE 8<br> <br> namespace X265_NS {<br> <br>@@ -434,6 +435,14 @@ int      x265_rename(const char* oldName, const char* newName);<br> #define  x265_unlink(fileName) unlink(fileName)<br> #define  x265_rename(oldName, newName) rename(oldName, newName)<br> #endif<br>+/* Close a file */<br>+#define  x265_fclose(file) if (file != NULL) fclose(file); file=NULL;<br>+#define x265_fread(val, size, readSize, fileOffset,errorMessage)\<br>+    if (fread(val, size, readSize, fileOffset) != readSize)\<br>+    {\<br>+        x265_log(NULL, X265_LOG_ERROR, errorMessage); \<br>+        return; \<br>+    }<br> int      x265_exp2fix8(double x);<br> <br> double   x265_ssim2dB(double ssim);<br>diff --git a/source/common/param.cpp b/source/common/param.cpp<br>index f72305372..ed6973d9c 100755<br>--- a/source/common/param.cpp<br>+++ b/source/common/param.cpp<br>@@ -384,6 +384,8 @@ void x265_param_default(x265_param* param)<br>     param->svtHevcParam = svtParam;<br>     svt_param_default(param);<br> #endif<br>+    /* Film grain characteristics model filename */<br>+    param->filmGrain = NULL;<br> }<br> <br> int x265_param_default_preset(x265_param* param, const char* preset, const char* tune)<br>@@ -1460,6 +1462,8 @@ int x265_param_parse(x265_param* p, const char* name, const char* value)<br>         OPT("video-signal-type-preset") p->videoSignalTypePreset = strdup(value);<br>         OPT("eob") p->bEnableEndOfBitstream = atobool(value);<br>         OPT("eos") p->bEnableEndOfSequence = atobool(value);<br>+        /* Film grain characterstics model filename */<br>+        OPT("film-grain") p->filmGrain = (char* )value;<br>         else<br>             return X265_PARAM_BAD_NAME;<br>     }<br>@@ -2353,6 +2357,8 @@ char *x265_param2string(x265_param* p, int padx, int pady)<br>     s += sprintf(s, "conformance-window-offsets right=%d bottom=%d", p->confWinRightOffset, p->confWinBottomOffset);<br>     s += sprintf(s, " decoder-max-rate=%d", p->decoderVbvMaxRate);<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> #undef BOOL<br>     return buf;<br> }<br>@@ -2726,6 +2732,9 @@ void x265_copy_params(x265_param* dst, x265_param* src)<br> #ifdef SVT_HEVC<br>     memcpy(dst->svtHevcParam, src->svtHevcParam, sizeof(EB_H265_ENC_CONFIGURATION));<br> #endif<br>+    /* Film grain */<br>+    if (src->filmGrain)<br>+        dst->filmGrain = src->filmGrain;<br> }<br> <br> #ifdef SVT_HEVC<br>diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp<br>index 5d0c9a050..f33a6d053 100644<br>--- a/source/encoder/encoder.cpp<br>+++ b/source/encoder/encoder.cpp<br>@@ -142,6 +142,7 @@ Encoder::Encoder()<br>     m_threadPool = NULL;<br>     m_analysisFileIn = NULL;<br>     m_analysisFileOut = NULL;<br>+    m_filmGrainIn = NULL;<br>     m_naluFile = NULL;<br>     m_offsetEmergency = NULL;<br>     m_iFrameNum = 0;<br>@@ -551,6 +552,15 @@ void Encoder::create()<br>             }<br>         }<br>     }<br>+    if (m_param->filmGrain)<br>+    {<br>+        m_filmGrainIn = x265_fopen(m_param->filmGrain, "rb");<br>+        if (!m_filmGrainIn)<br>+        {<br>+            x265_log_file(NULL, X265_LOG_ERROR, "Failed to open film grain characteristics binary file %s\n", m_param->filmGrain);<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> <br>@@ -996,6 +1006,8 @@ void Encoder::destroy()<br>      }<br>     if (m_naluFile)<br>         fclose(m_naluFile);<br>+    if (m_filmGrainIn)<br>+        x265_fclose(m_filmGrainIn);<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 2ee5bdaee..cfbb55fe0 100644<br>--- a/source/encoder/encoder.h<br>+++ b/source/encoder/encoder.h<br>@@ -295,6 +295,8 @@ public:<br> <br>     ThreadSafeInteger* zoneReadCount;<br>     ThreadSafeInteger* zoneWriteCount;<br>+    /* Film grain model file */<br>+    FILE* m_filmGrainIn;<br> <br>     Encoder();<br>     ~Encoder()<br>diff --git a/source/encoder/frameencoder.cpp b/source/encoder/frameencoder.cpp<br>index 1b3875a25..44415d079 100644<br>--- a/source/encoder/frameencoder.cpp<br>+++ b/source/encoder/frameencoder.cpp<br>@@ -762,7 +762,14 @@ void FrameEncoder::compressFrame()<br>         m_seiAlternativeTC.m_preferredTransferCharacteristics = m_param->preferredTransferCharacteristics;<br>         m_seiAlternativeTC.writeSEImessages(m_bs, *slice->m_sps, NAL_UNIT_PREFIX_SEI, m_nalList, m_param->bSingleSeiNal);<br>     }<br>-<br>+    /* Write Film grain characteristics if present */<br>+    if (this->m_top->m_filmGrainIn)<br>+    {<br>+        FilmGrainCharacteristics m_filmGrain;<br>+        /* Read the Film grain model file */<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);<br>+    }<br>     /* Write user SEI */<br>     for (int i = 0; i < m_frame->m_userSEI.numPayloads; i++)<br>     {<br>@@ -2133,6 +2140,54 @@ void FrameEncoder::noiseReductionUpdate()<br>         m_nr->nrOffsetDenoise[cat][0] = 0;<br>     }<br> }<br>+<br>+void FrameEncoder::readModel(FilmGrainCharacteristics* m_filmGrain, FILE* filmgrain)<br>+{<br>+    char* errorMessage = "Error reading FilmGrain characteristics\n";<br>+    FilmGrain m_fg;<br>+    x265_fread((char* )&m_fg, sizeof(bool) * 3 + sizeof(uint8_t), 1, filmgrain, errorMessage);<br>+    m_filmGrain->m_filmGrainCharacteristicsCancelFlag = m_fg.m_filmGrainCharacteristicsCancelFlag;<br>+    m_filmGrain->m_filmGrainCharacteristicsPersistenceFlag = m_fg.m_filmGrainCharacteristicsPersistenceFlag;<br>+    m_filmGrain->m_filmGrainModelId = m_fg.m_filmGrainModelId;<br>+    m_filmGrain->m_separateColourDescriptionPresentFlag = m_fg.m_separateColourDescriptionPresentFlag;<br>+    if (m_filmGrain->m_separateColourDescriptionPresentFlag)<br>+    {<br>+        ColourDescription m_clr;<br>+        x265_fread((char* )&m_clr, sizeof(bool) + sizeof(uint8_t) * 5, 1, filmgrain, errorMessage);<br>+        m_filmGrain->m_filmGrainBitDepthLumaMinus8 = m_clr.m_filmGrainBitDepthLumaMinus8;<br>+        m_filmGrain->m_filmGrainBitDepthChromaMinus8 = m_clr.m_filmGrainBitDepthChromaMinus8;<br>+        m_filmGrain->m_filmGrainFullRangeFlag = m_clr.m_filmGrainFullRangeFlag;<br>+        m_filmGrain->m_filmGrainColourPrimaries = m_clr.m_filmGrainColourPrimaries;<br>+        m_filmGrain->m_filmGrainTransferCharacteristics = m_clr.m_filmGrainTransferCharacteristics;<br>+        m_filmGrain->m_filmGrainMatrixCoeffs = m_clr.m_filmGrainMatrixCoeffs;<br>+    }<br>+    FGPresent m_present;<br>+    x265_fread((char* )&m_present, sizeof(bool) * 3 + sizeof(uint8_t) * 2, 1, filmgrain, errorMessage);<br>+    m_filmGrain->m_blendingModeId = m_present.m_blendingModeId;<br>+    m_filmGrain->m_log2ScaleFactor = m_present.m_log2ScaleFactor;<br>+    m_filmGrain->m_compModel[0].bPresentFlag = m_present.m_presentFlag[0];<br>+    m_filmGrain->m_compModel[1].bPresentFlag = m_present.m_presentFlag[1];<br>+    m_filmGrain->m_compModel[2].bPresentFlag = m_present.m_presentFlag[2];<br>+    for (int i = 0; i < MAX_NUM_COMPONENT; i++)<br>+    {<br>+        if (m_filmGrain->m_compModel[i].bPresentFlag)<br>+        {<br>+            x265_fread((char* )(&m_filmGrain->m_compModel[i].m_filmGrainNumIntensityIntervalMinus1), sizeof(uint8_t), 1, filmgrain, errorMessage);<br>+            x265_fread((char* )(&m_filmGrain->m_compModel[i].numModelValues), sizeof(uint8_t), 1, filmgrain, errorMessage);<br>+            m_filmGrain->m_compModel[i].intensityValues = (FilmGrainCharacteristics::CompModelIntensityValues* ) malloc(sizeof(FilmGrainCharacteristics::CompModelIntensityValues) * (m_filmGrain->m_compModel[i].m_filmGrainNumIntensityIntervalMinus1+1)) ;<br>+            for (int j = 0; j <= m_filmGrain->m_compModel[i].m_filmGrainNumIntensityIntervalMinus1; j++)<br>+            {<br>+                x265_fread((char* )(&m_filmGrain->m_compModel[i].intensityValues[j].intensityIntervalLowerBound), sizeof(uint8_t), 1, filmgrain, errorMessage);<br>+                x265_fread((char* )(&m_filmGrain->m_compModel[i].intensityValues[j].intensityIntervalUpperBound), sizeof(uint8_t), 1, filmgrain, errorMessage);<br>+                m_filmGrain->m_compModel[i].intensityValues[j].compModelValue = (int* ) malloc(sizeof(int) * (m_filmGrain->m_compModel[i].numModelValues));<br>+                for (int k = 0; k < m_filmGrain->m_compModel[i].numModelValues; k++)<br>+                {<br>+                    x265_fread((char* )(&m_filmGrain->m_compModel[i].intensityValues[j].compModelValue[k]), sizeof(int), 1, filmgrain, errorMessage);<br>+                }<br>+            }<br>+        }<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 f4cfc624d..5d972cb26 100644<br>--- a/source/encoder/frameencoder.h<br>+++ b/source/encoder/frameencoder.h<br>@@ -113,6 +113,34 @@ struct CTURow<br>     }<br> };<br> <br>+/*Film grain characteristics*/<br>+struct FilmGrain<br>+{<br>+    bool    m_filmGrainCharacteristicsCancelFlag;<br>+    bool    m_filmGrainCharacteristicsPersistenceFlag;<br>+    bool    m_separateColourDescriptionPresentFlag;<br>+    uint8_t m_filmGrainModelId;<br>+    uint8_t m_blendingModeId;<br>+    uint8_t m_log2ScaleFactor;<br>+};<br>+<br>+struct ColourDescription<br>+{<br>+    bool        m_filmGrainFullRangeFlag;<br>+    uint8_t     m_filmGrainBitDepthLumaMinus8;<br>+    uint8_t     m_filmGrainBitDepthChromaMinus8;<br>+    uint8_t     m_filmGrainColourPrimaries;<br>+    uint8_t     m_filmGrainTransferCharacteristics;<br>+    uint8_t     m_filmGrainMatrixCoeffs;<br>+};<br>+<br>+struct FGPresent<br>+{<br>+    uint8_t     m_blendingModeId;<br>+    uint8_t     m_log2ScaleFactor;<br>+    bool        m_presentFlag[3];<br>+};<br>+<br> // Manages the wave-front processing of a single encoding frame<br> class FrameEncoder : public WaveFront, public Thread<br> {<br>@@ -250,6 +278,7 @@ protected:<br>     void collectDynDataFrame();<br>     void computeAvgTrainingData();<br>     void collectDynDataRow(CUData& ctu, FrameStats* rowStats);    <br>+    void readModel(FilmGrainCharacteristics* m_filmGrain, FILE* filmgrain);<br> };<br> }<br> <br>diff --git a/source/encoder/sei.h b/source/encoder/sei.h<br>index 61d39edd9..03e210639 100644<br>--- a/source/encoder/sei.h<br>+++ b/source/encoder/sei.h<br>@@ -73,6 +73,101 @@ public:<br>     }<br> };<br> <br>+/* Film grain characteristics */<br>+class FilmGrainCharacteristics : public SEI<br>+{<br>+  public:<br>+<br>+    FilmGrainCharacteristics()<br>+    {<br>+        m_payloadType = FILM_GRAIN_CHARACTERISTICS;<br>+        m_payloadSize = 0;<br>+    }<br>+<br>+    struct CompModelIntensityValues<br>+    {<br>+        uint8_t intensityIntervalLowerBound;<br>+        uint8_t intensityIntervalUpperBound;<br>+        int*    compModelValue;<br>+    };<br>+<br>+    struct CompModel<br>+    {<br>+        bool    bPresentFlag;<br>+        uint8_t numModelValues;<br>+        uint8_t m_filmGrainNumIntensityIntervalMinus1;<br>+        CompModelIntensityValues* intensityValues;<br>+    };<br>+<br>+    CompModel   m_compModel[MAX_NUM_COMPONENT];<br>+    bool        m_filmGrainCharacteristicsPersistenceFlag;<br>+    bool        m_filmGrainCharacteristicsCancelFlag;<br>+    bool        m_separateColourDescriptionPresentFlag;<br>+    bool        m_filmGrainFullRangeFlag;<br>+    uint8_t     m_filmGrainModelId;<br>+    uint8_t     m_blendingModeId;<br>+    uint8_t     m_log2ScaleFactor;<br>+    uint8_t     m_filmGrainBitDepthLumaMinus8;<br>+    uint8_t     m_filmGrainBitDepthChromaMinus8;<br>+    uint8_t     m_filmGrainColourPrimaries;<br>+    uint8_t     m_filmGrainTransferCharacteristics;<br>+    uint8_t     m_filmGrainMatrixCoeffs;<br>+<br>+    void writeSEI(const SPS&)<br>+    {<br>+        WRITE_FLAG(m_filmGrainCharacteristicsCancelFlag, "film_grain_characteristics_cancel_flag");<br>+<br>+        if (!m_filmGrainCharacteristicsCancelFlag)<br>+        {<br>+            WRITE_CODE(m_filmGrainModelId, 2, "film_grain_model_id");<br>+            WRITE_FLAG(m_separateColourDescriptionPresentFlag, "separate_colour_description_present_flag");<br>+            if (m_separateColourDescriptionPresentFlag)<br>+            {<br>+                WRITE_CODE(m_filmGrainBitDepthLumaMinus8, 3, "film_grain_bit_depth_luma_minus8");<br>+                WRITE_CODE(m_filmGrainBitDepthChromaMinus8, 3, "film_grain_bit_depth_chroma_minus8");<br>+                WRITE_FLAG(m_filmGrainFullRangeFlag, "film_grain_full_range_flag");<br>+                WRITE_CODE(m_filmGrainColourPrimaries, X265_BYTE, "film_grain_colour_primaries");<br>+                WRITE_CODE(m_filmGrainTransferCharacteristics, X265_BYTE, "film_grain_transfer_characteristics");<br>+                WRITE_CODE(m_filmGrainMatrixCoeffs, X265_BYTE, "film_grain_matrix_coeffs");<br>+            }<br>+            WRITE_CODE(m_blendingModeId, 2, "blending_mode_id");<br>+            WRITE_CODE(m_log2ScaleFactor, 4, "log2_scale_factor");<br>+            for (uint8_t c = 0; c < 3; c++)<br>+            {<br>+                WRITE_FLAG(m_compModel[c].bPresentFlag && m_compModel[c].m_filmGrainNumIntensityIntervalMinus1 + 1 > 0 && m_compModel[c].numModelValues > 0, "comp_model_present_flag[c]");<br>+            }<br>+            for (uint8_t c = 0; c < 3; c++)<br>+            {<br>+                if (m_compModel[c].bPresentFlag && m_compModel[c].m_filmGrainNumIntensityIntervalMinus1 + 1 > 0 && m_compModel[c].numModelValues > 0)<br>+                {<br>+                    assert(m_compModel[c].m_filmGrainNumIntensityIntervalMinus1 + 1 <= 256);<br>+                    assert(m_compModel[c].numModelValues <= X265_BYTE);<br>+                    WRITE_CODE(m_compModel[c].m_filmGrainNumIntensityIntervalMinus1 , X265_BYTE, "num_intensity_intervals_minus1[c]");<br>+                    WRITE_CODE(m_compModel[c].numModelValues - 1, 3, "num_model_values_minus1[c]");<br>+                    for (uint8_t interval = 0; interval < m_compModel[c].m_filmGrainNumIntensityIntervalMinus1 + 1; interval++)<br>+                    {<br>+                        WRITE_CODE(m_compModel[c].intensityValues[interval].intensityIntervalLowerBound, X265_BYTE, "intensity_interval_lower_bound[c][i]");<br>+                        WRITE_CODE(m_compModel[c].intensityValues[interval].intensityIntervalUpperBound, X265_BYTE, "intensity_interval_upper_bound[c][i]");<br>+                        for (uint8_t j = 0; j < m_compModel[c].numModelValues; j++)<br>+                        {<br>+                            WRITE_SVLC(m_compModel[c].intensityValues[interval].compModelValue[j],"comp_model_value[c][i]");<br>+                        }<br>+                    }<br>+                }<br>+            }<br>+            WRITE_FLAG(m_filmGrainCharacteristicsPersistenceFlag, "film_grain_characteristics_persistence_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>+<br> static const uint32_t ISO_IEC_11578_LEN = 16;<br> <br> class SEIuserDataUnregistered : public SEI<br>diff --git a/source/test/regression-tests.txt b/source/test/regression-tests.txt<br>index 26d43b28a..10a4449e7 100644<br>--- a/source/test/regression-tests.txt<br>+++ b/source/test/regression-tests.txt<br>@@ -195,4 +195,8 @@ CrowdRun_1920x1080_50_10bit_422.yuv,--no-cutree --analysis-save x265_analysis.da<br> #segment encoding<br> BasketballDrive_1920x1080_50.y4m, --preset ultrafast --no-open-gop --chunk-start 100 --chunk-end 200<br> <br>+#Test FG SEI message addition<br>+#OldTownCross_1920x1080_50_10bit_422.yuv,--preset slower --tune grain --film-grain "OldTownCross_1920x1080_50_10bit_422.bin"<br>+#RaceHorses_416x240_30_10bit.yuv,--preset ultrafast --signhide --colormatrix bt709 --film-grain "RaceHorses_416x240_30_10bit.bin"<br>+<br> # vim: tw=200<br>diff --git a/source/test/smoke-tests.txt b/source/test/smoke-tests.txt<br>index 041b97e76..a88a225b4 100644<br>--- a/source/test/smoke-tests.txt<br>+++ b/source/test/smoke-tests.txt<br>@@ -23,3 +23,7 @@ CrowdRun_1920x1080_50_10bit_444.yuv,--preset=superfast --bitrate 7000 --sao --li<br> # Main12 intraCost overflow bug test<br> 720p50_parkrun_ter.y4m,--preset medium<br> 720p50_parkrun_ter.y4m,--preset=fast --hevc-aq --no-cutree<br>+# Test FG SEI message addition<br>+# CrowdRun_1920x1080_50_10bit_444.yuv,--preset=ultrafast --weightp --keyint -1 --film-grain "CrowdRun_1920x1080_50_10bit_444.bin"<br>+# DucksAndLegs_1920x1080_60_10bit_422.yuv,--preset=veryfast --min-cu 16 --film-grain "DucksAndLegs_1920x1080_60_10bit_422.bin"<br>+# NebutaFestival_2560x1600_60_10bit_crop.yuv,--preset=superfast --bitrate 10000 --sao --limit-sao --cll --max-cll "1000,400" --film-grain "NebutaFestival_2560x1600_60_10bit_crop.bin"<br>diff --git a/source/x265.h b/source/x265.h<br>index bf945498f..5d242d653 100644<br>--- a/source/x265.h<br>+++ b/source/x265.h<br>@@ -1989,6 +1989,9 @@ typedef struct x265_param<br>     /* Flag to turn on/off traditional scenecut detection in histogram based scenecut detection.<br>      * When false, only spatial properties are used for scenecut detection. Default true */<br>     int      bEnableTradScdInHscd;<br>+<br>+    /* Film Grain Characteristic file */<br>+    char* filmGrain;<br> } x265_param;<br> <br> /* x265_param_alloc:<br>diff --git a/source/x265cli.cpp b/source/x265cli.cpp<br>index bfb6293f3..3a03de579 100755<br>--- a/source/x265cli.cpp<br>+++ b/source/x265cli.cpp<br>@@ -391,6 +391,9 @@ namespace X265_NS {<br>         H1("    2 - unable to open encoder\n");<br>         H1("    3 - unable to generate stream headers\n");<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>+<br> #undef OPT<br> #undef H0<br> #undef H1<br>diff --git a/source/x265cli.h b/source/x265cli.h<br>index 8fcf37b8a..7072f7616 100644<br>--- a/source/x265cli.h<br>+++ b/source/x265cli.h<br>@@ -380,6 +380,7 @@ static const struct option long_options[] =<br>     { "abr-ladder", required_argument, NULL, 0 },<br>     { "min-vbv-fullness", required_argument, NULL, 0 },<br>     { "max-vbv-fullness", required_argument, NULL, 0 },<br>+    { "film-grain", required_argument, NULL, 0 },<br>     { 0, 0, 0, 0 },<br>     { 0, 0, 0, 0 },<br>     { 0, 0, 0, 0 },<br>-- <br>2.20.1.windows.1<br><br></div>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org" target="_blank">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr"><div dir="ltr"><b style="background-color:rgb(255,255,255)"><font color="#0b5394">With Regards,</font></b><div><b style="background-color:rgb(255,255,255)"><font color="#0b5394">Srikanth Kurapati.</font></b></div></div></div>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org" target="_blank">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</blockquote></div>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org" target="_blank">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</blockquote></div>