[x265] [PATCH] Add film grain characteristics as a SEI message to the bitstream

Mahesh Pittala mahesh at multicorewareinc.com
Sat Mar 5 09:59:03 UTC 2022


Pushed to master branch

On Fri, Mar 4, 2022 at 1:46 PM Keshav E <keshav at multicorewareinc.com> wrote:

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


More information about the x265-devel mailing list