Skip to content
Snippets Groups Projects
Commit 45a7b5aa authored by Philippe de Lagrange's avatar Philippe de Lagrange
Browse files
VFGS-1.0, same code as https://github.com/InterDigitalInc/VersatileFilmGrain (v1.0), but changed license, file headers.
parent 52c54646
No related branches found
Tags VFGS-1.0
No related merge requests found
Showing with 2524 additions and 71 deletions
# minimum required cmake version
cmake_minimum_required( VERSION 3.5 FATAL_ERROR )
# project name
project( vfgs )
set( EXE_NAME vfgs )
# get source files
file( GLOB SRC_FILES "${CMAKE_SOURCE_DIR}/src/*.c" )
# use ccache
find_program( CCACHE_FOUND ccache )
if( CCACHE_FOUND )
message( STATUS "ccache found. using it." )
set_property( GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache )
set_property( GLOBAL PROPERTY RULE_LAUNCH_LINK ccache )
endif()
# set default CMAKE_BUILD_TYPE to Release if not set
if( NOT CMAKE_BUILD_TYPE )
set( CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE )
endif()
if( CMAKE_SYSTEM_NAME STREQUAL "Linux" )
if( CMAKE_CXX_COMPILER_ID STREQUAL "GNU" )
set( USE_ADDRESS_SANITIZER OFF CACHE BOOL "Compiles with -sanitize=address and links to libasan" )
endif()
endif()
if( CMAKE_COMPILER_IS_GNUCC )
set( BUILD_STATIC OFF CACHE BOOL "Build static executables" )
endif()
include_directories(${CMAKE_SOURCE_DIR}/src)
# Enable warnings for some generators and toolsets.
if( MSVC )
# CMake 3.11.0 introduces support for generator expression COMPILE_LANGUAGE.
# MSVC generator does not support the generator expression COMPILE_LANGUAGE yet.
#string( APPEND CMAKE_CXX_FLAGS " warnings-as-errors /wd4996" )
string( APPEND CMAKE_C_FLAGS " /WX /wd4996" )
else()
add_compile_options( "-Werror" )
endif()
# enable sse4.1 build for all source files for gcc and clang
if( UNIX OR MINGW )
add_compile_options( "-msse4.1" )
endif()
# enable parallel build for Visual Studio
if( MSVC )
add_compile_options( "/MP" )
add_compile_options( "/EHsc" )
endif()
add_executable( ${EXE_NAME} ${SRC_FILES})
COPYING 0 → 100644
The copyright in this software is being made available under the BSD
License, included below. This software may be subject to other third party
and contributor rights, including patent rights, and no such rights are
granted under this license.
Copyright (c) 2023, ITU/ISO/IEC
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the ITU/ISO/IEC nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
# VFGS
# VFGS - Versatile film grain synthesis
Software model of hardware-friendly film grain synthesis, supporting FGC SEI message.
This software implements a film grain synthesis method that supports both frequency-filtering and auto-regressive modes of the FGC SEI message, while reducing hardware implementation costs compared to SMPTE RDD-5 by doing a sample-based local adaptation, rather than based on a local 8x8 average (which requires line buffers).
## Getting started
The intent is to provide a "one for all" solution, using a single hardware module while supporting different grain models.
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
Details of design considerations regarding film grain synthesis can be found in [JVET-AC2020](https://jvet-experts.org/doc_end_user/current_document.php?id=12577) (committee draft of ISO 23007-2 technical report), section 8.
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
This software is designed as a model for hardware designers; it uses the C language, and is organized in separate layers:
* the hardware layer (in vfgs_hw.c), which runs a the process for the full picture, based on grain patterns memory, local adaptation LUTs, and a few other parameters. This is the piece that is potentially implemented in hardware.
* the firmware layer (in vfgs_fw.c), that converts input model parameters (e.g. FGC SEI) to hardware configuration. This part can be easily modified to adapt to other grain metadata formats, to generate grain patterns in a different way, etc.
* the outer layer, made of the main program and YUV I/O routines.
## Add your files
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
```
cd existing_repo
git remote add origin https://vcgit.hhi.fraunhofer.de/jvet-ahg-fgt/vfgs.git
git branch -M main
git push -uf origin main
```
## Integrate with your tools
- [ ] [Set up project integrations](https://vcgit.hhi.fraunhofer.de/jvet-ahg-fgt/vfgs/-/settings/integrations)
## Collaborate with your team
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
## Test and Deploy
Use the built-in continuous integration in GitLab.
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
***
# Editing this README
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template.
## Usage
## Suggestions for a good README
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
This programs takes an input YUV video and a configuration file, and generates an output YUV video.
## Name
Choose a self-explaining name for your project.
The configuration file reflects the contents of an FGC SEI message, and follows the same syntax as in the [VTM](https://vcgit.hhi.fraunhofer.de/jvet/VVCSoftware_VTM). Test configuration files can be found in the cfg/ subfolder. A default configuration is used if none is provided.
## Description
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
An SEI text dump as output by the VTM or HM can also be ingested instead of a configuration file, an example of which is also found in the cfg/ subfolder. Only the first FGC SEI found in the dump is retained.
## Badges
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
When the `--gain` option is used, new valid grain parameters are computed internally before further processing.
## Visuals
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
Full help is provided when typing `vfgs --help`, with default option values indicated in angle brackets [ ]:
## Installation
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
```bash
Usage: vfgs [options] <input.yuv> <output.yuv>
## Usage
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
-w,--width <value> Picture width [1920]
-h,--height <value> Picture height [1080]
-b,--bitdepth <value> Input bit depth [10]
--outdepth <value> Output bit depth (<= input depth) [same as input]
-f,--format <value> Chroma format (420/422/444) [420]
-n,--frames <value> Number of frames to process (0=all) [0]
-s,--seek <value> Picture start index within input file [0]
-c,--cfg <filename> Read film grain configuration file
-g,--gain <value> Apply a global scale (in percent) to grain strength
--help Display this page
````
## Support
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
## Compilation
## Roadmap
If you have ideas for releases in the future, it is a good idea to list them in the README.
Compilation is performed either using `cmake` or typing `gcc src/*.c -o vfgs.exe -mavx2` (adapt -mXXX to your machine)
## Contributing
State if you are open to contributions and what your requirements are for accepting them.
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
## Authors and acknowledgment
Show your appreciation to those who have contributed to the project.
Please use fork and merge requests. Examples of welcome contributions:
- SIMD and GPU acceleration (HW layer)
- HDL code / HW design (HW layer)
- Further improved FGC SEI message support (FW layer)
## License
For open source projects, say how it is licensed.
## Project status
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
The usual ISO/ITU BSD 3-clause-clear license is applicable. See the [COPYING](COPYING) file.
#======== Film grain characteristics SEI message =====================
SEIFGCEnabled : 1
SEIFGCCancelFlag : 0 # placeholder (not implemented)
SEIFGCPersistenceFlag : 0 # placeholder (not implemented)
SEIFGCModelID : 0 # 0: frequency filtering; 1: auto-regression
SEIFGCSepColourDescPresentFlag : 0 # placeholder (if not 0, need to specify separate colour description (not implemented))
SEIFGCBlendingModeID : 0 # placeholder - value ignored, always 0 (0: additive; 1: multipliciative)
SEIFGCLog2ScaleFactor : 5
SEIFGCCompModelPresentComp0 : 1 # if not 0, need to specify model for comp 0
SEIFGCCompModelPresentComp1 : 1 # if not 0, need to specify model for comp 1
SEIFGCCompModelPresentComp2 : 1 # if not 0, need to specify model for comp 2
SEIFGCNumIntensityIntervalMinus1Comp0 : 7 # Number of intensity intervals for comp 0
SEIFGCNumIntensityIntervalMinus1Comp1 : 7 # Number of intensity intervals for comp 1
SEIFGCNumIntensityIntervalMinus1Comp2 : 7 # Number of intensity intervals for comp 2
SEIFGCNumModelValuesMinus1Comp0 : 1 # Number of model values for comp 0
SEIFGCNumModelValuesMinus1Comp1 : 0 # Number of model values for comp 1
SEIFGCNumModelValuesMinus1Comp2 : 0 # Number of model values for comp 2
SEIFGCIntensityIntervalLowerBoundComp0 : 0 40 60 80 100 120 140 160 # Lower bound of intensity interval for comp 0
SEIFGCIntensityIntervalLowerBoundComp1 : 0 64 96 112 128 144 160 192 # Lower bound of intensity interval for comp 1
SEIFGCIntensityIntervalLowerBoundComp2 : 0 64 96 112 128 144 160 192 # Lower bound of intensity interval for comp 2
SEIFGCIntensityIntervalUpperBoundComp0 : 39 59 79 99 119 139 159 255 # Upper bound of intensity interval for comp 0
SEIFGCIntensityIntervalUpperBoundComp1 : 63 95 111 127 143 159 191 255 # Upper bound of intensity interval for comp 1
SEIFGCIntensityIntervalUpperBoundComp2 : 63 95 111 127 143 159 191 255 # Upper bound of intensity interval for comp 2
SEIFGCCompModelValuesComp0 : 100 7 100 8 100 9 110 10 120 11 135 12 145 13 180 14 # model values for each intensity interval for comp 0
SEIFGCCompModelValuesComp1 : 128 96 64 64 64 64 96 128 # model values for each intensity interval for comp 1
SEIFGCCompModelValuesComp2 : 128 96 64 64 64 64 96 128 # model values for each intensity interval for comp 2
\ No newline at end of file
#======== Film grain characteristics SEI message =====================
SEIFGCEnabled : 1
SEIFGCCancelFlag : 0 # for SMPTE-RDD5: the value must be 0
SEIFGCPersistenceFlag : 0 # for SMPTE-RDD5: the value must be 0
SEIFGCModelID : 1 # for SMPTE-RDD5: the value must be 0 (0: frequency filtering; 1: auto-regression; 2-3 are reserved)
SEIFGCSepColourDescPresentFlag : 0 # for SMPTE-RDD5: the value must be 0 (if not 0, need to specify separate colour description (not implemented in current encoder cmd line))
SEIFGCBlendingModeID : 0 # for SMPTE-RDD5: the value must be 0 (0: additive; 1: multiplicative)
SEIFGCLog2ScaleFactor : 5
SEIFGCCompModelPresentComp0 : 1 # if not 0, need to specify model for comp 0 (not implemented in current encoder cmd line)
SEIFGCCompModelPresentComp1 : 0 # if not 0, need to specify model for comp 1 (not implemented in current encoder cmd line)
SEIFGCCompModelPresentComp2 : 0 # if not 0, need to specify model for comp 2 (not implemented in current encoder cmd line)
SEIFGCNumIntensityIntervalMinus1Comp0 : 0 # Number of intensity intervals for comp 0
SEIFGCNumIntensityIntervalMinus1Comp1 : 0 # Number of intensity intervals for comp 1
SEIFGCNumIntensityIntervalMinus1Comp2 : 0 # Number of intensity intervals for comp 2
SEIFGCNumModelValuesMinus1Comp0 : 5 # Number of model values for comp 0
SEIFGCNumModelValuesMinus1Comp1 : 1 # Number of model values for comp 1
SEIFGCNumModelValuesMinus1Comp2 : 1 # Number of model values for comp 2
SEIFGCIntensityIntervalLowerBoundComp0 : 0 #0 40 60 80 100 120 140 160
SEIFGCIntensityIntervalLowerBoundComp1 : 0
SEIFGCIntensityIntervalLowerBoundComp2 : 0
SEIFGCIntensityIntervalUpperBoundComp0 : 255 #39 59 79 99 119 139 159 255
SEIFGCIntensityIntervalUpperBoundComp1 : 255
SEIFGCIntensityIntervalUpperBoundComp2 : 255
SEIFGCCompModelValuesComp0 : 100 11 0 -8 32 -7 # [90 0 -60 256 -55]/256
SEIFGCCompModelValuesComp1 : 64 90
SEIFGCCompModelValuesComp2 : 64 90
\ No newline at end of file
--------------------------------------
Film grain characteristics SEI message (28 bytes)
fg_characteristics_cancel_flag: 0
fg_model_id: 0
fg_separate_colour_description_present_flag: 0
fg_blending_mode_id: 0
fg_log2_scale_factor: 2
fg_comp_model_present_flag[c]: 1
fg_comp_model_present_flag[c]: 0
fg_comp_model_present_flag[c]: 0
fg_num_intensity_intervals_minus1[c]: 5
fg_num_model_values_minus1[c]: 1
fg_intensity_interval_lower_bound[c][i]: 15
fg_intensity_interval_upper_bound[c][i]: 27
fg_comp_model_value[c][i]: 4
fg_comp_model_value[c][i]: 7
fg_intensity_interval_lower_bound[c][i]: 28
fg_intensity_interval_upper_bound[c][i]: 52
fg_comp_model_value[c][i]: 9
fg_comp_model_value[c][i]: 7
fg_intensity_interval_lower_bound[c][i]: 53
fg_intensity_interval_upper_bound[c][i]: 86
fg_comp_model_value[c][i]: 12
fg_comp_model_value[c][i]: 7
fg_intensity_interval_lower_bound[c][i]: 87
fg_intensity_interval_upper_bound[c][i]: 132
fg_comp_model_value[c][i]: 16
fg_comp_model_value[c][i]: 7
fg_intensity_interval_lower_bound[c][i]: 133
fg_intensity_interval_upper_bound[c][i]: 139
fg_comp_model_value[c][i]: 12
fg_comp_model_value[c][i]: 7
fg_intensity_interval_lower_bound[c][i]: 140
fg_intensity_interval_upper_bound[c][i]: 146
fg_comp_model_value[c][i]: 8
fg_comp_model_value[c][i]: 7
fg_characteristics_persistence_flag: 1
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: dcd51a8924d9c45748bdf4cdc36ee0101069e44a0537fa9264002c5516560e84ce524903d2a12e311906d62c3a017531
--------------------------------------
Film grain characteristics SEI message (31 bytes)
fg_characteristics_cancel_flag: 0
fg_model_id: 0
fg_separate_colour_description_present_flag: 0
fg_blending_mode_id: 0
fg_log2_scale_factor: 2
fg_comp_model_present_flag[c]: 1
fg_comp_model_present_flag[c]: 0
fg_comp_model_present_flag[c]: 0
fg_num_intensity_intervals_minus1[c]: 6
fg_num_model_values_minus1[c]: 1
fg_intensity_interval_lower_bound[c][i]: 15
fg_intensity_interval_upper_bound[c][i]: 22
fg_comp_model_value[c][i]: 4
fg_comp_model_value[c][i]: 7
fg_intensity_interval_lower_bound[c][i]: 23
fg_intensity_interval_upper_bound[c][i]: 39
fg_comp_model_value[c][i]: 8
fg_comp_model_value[c][i]: 7
fg_intensity_interval_lower_bound[c][i]: 40
fg_intensity_interval_upper_bound[c][i]: 78
fg_comp_model_value[c][i]: 11
fg_comp_model_value[c][i]: 7
fg_intensity_interval_lower_bound[c][i]: 79
fg_intensity_interval_upper_bound[c][i]: 124
fg_comp_model_value[c][i]: 15
fg_comp_model_value[c][i]: 7
fg_intensity_interval_lower_bound[c][i]: 125
fg_intensity_interval_upper_bound[c][i]: 129
fg_comp_model_value[c][i]: 11
fg_comp_model_value[c][i]: 7
fg_intensity_interval_lower_bound[c][i]: 130
fg_intensity_interval_upper_bound[c][i]: 138
fg_comp_model_value[c][i]: 8
fg_comp_model_value[c][i]: 7
fg_intensity_interval_lower_bound[c][i]: 139
fg_intensity_interval_upper_bound[c][i]: 146
fg_comp_model_value[c][i]: 4
fg_comp_model_value[c][i]: 7
fg_characteristics_persistence_flag: 1
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: 3f6b2d8831ee8340769f58eb790f8213d4eb32c7cc085fa0ed88648e99f4c0726b28372990eaef157c93be291bf0ad8e
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: 7f4a6d46766e93a40a01653b76e32326b880f75e46d1f7b11168a53393b7a7bbbb484c5425b03205a218ed3f9a8965a3
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: 2f45cf1f108112d499eb5548e2ef4fc491c64a00319dee2eed81cba66c06edbbf0dec61377a7ba07630bbe3130c3ed4e
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: d391e20ee27e761f28f42566c6556e5fbe1f39ac873b276f2745f420196553a0dd99c48c35b808ebff4fe54353fc7e8c
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: 007697ded7d1fa9df0bf213cb2004efa6cd55799c7068ddffd16076f919f142f821e55e06e859f01b363643638584346
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: 460a927e84fdd5646a9e5892a2245da51e7437de8caceb409f1da5844ce6c7388ee5a4b0c44c2c03b3bdf3b321f514ee
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: 56fbc457dcd62b94a82e77d0b01c66fd0148fed28be8d26e2be1a81d66383007c2775abf4f4b773f407fc20d1d7b39e6
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: 81565d8fd123c8f67cbc9632e893e1e92329cce34f859290e878e1b6ec1a4e47b6ee75dd1576ba0422e0de40fd02f96f
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: bd8f797dfe001e56090f99fb356b37477b5acabe7d38fd5bf7146ffc9b4aa5a4adf9ccaed0c00f38c5d89efd0fb8044d
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: 216b357de7a7ecf31777c6c271e835a818d536cb05a66e81bc7fe6500e36804a727b4a21ac50e52338baa46abdb540ed
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: c4590252c9e054e41c4571df4f0f03e5d076dd92df0ad952a648e836d296a1309186f5f39405087aa6654c858c97dbbc
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: 3bde5d368bb7083fe8e3a1d40180da84a047b1a24795c3d62fa4b447a9fc8a73f8b5a5aedba9f7d81680065cea26da98
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: bf0bd1bd5506955cc45a0378fa552634ad0918874fd9510d4c13827e76ab7d8bca289b87b2d751ea313b03ce3d357940
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: af35daaf38233f18718b17703e31595a79c3b9d09ebf7a8e0e60c80531cd04905e825d42e4cbeee46ee1c374cb1c5980
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: 482b622f1ba3ac946717ffe8550cf74925d0b59f3eac5e9d4b41e6f3a59c19c9394222e7cfff6b3dbf8fc1963850a981
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: decc545e8851b8c6ffc966ca5224e5f0827d4b8ffd18c6a6c5594b1e6a1069e9a6882d0c7c81a0c66e2b4f4f8eb1813d
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: 2d9f6a8a61d7330e9c8b6ad76af5882fb63516511af66d8d616b31efb1a6b56571f5444504b6506b83d71edde8715a5b
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: 963067c5f8b16c77a575e302a1a5fa829b38c5784855705b1cdce78732af258b17732084be12369ed076901866120fd9
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: b40b806a3cfa4b77adb2f411d99652bd9df098b8c6cfdc7b0b7c3e86dff7de0e61380140d8311d5df648f480a33430b3
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: cc8b51c52f7a5b3a90b12edb69cbc4406775bbb5dfca84fd109003b336829dd77e35a7bc9e7a8aea86a855aa45b4cfcb
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: f555413e5d0fce776545ec32d4b370469df1fa83b285cf3c6b871817e2b70664405304948c287b7c09b59619b48ef983
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: 99cdfaf659cf84e97c13d206ebbbd2dcf3b77d8a01a03741b678c488fffffdd700735b37644aad11086ffffeb979efa1
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: 11ed2a5168d8135d3627f50d9809ca6dcf7bf44b7f194adae40643ec6ba10ab62ab10076359766ee2739c36173dda7f4
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: 76dc7d87788ca3515c5efa1e89905d5f1bfce23eb3f32579b6e30bcb08200d32a6638ac97be2c4d09147712c5b3e3406
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: ba10eee0a0b4a428235b160327fa6163e04f9a823a997ac72b2989f0aeaa388fd8a5f71f205f09da649045fda6c080f4
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: db2ed5d6d023179d3eb8703bd63a74b144ef350092b1711236a00531cd734cae6c150cdbb2ee17b373b36268bf4ebf28
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: 398f965c9adfbe5aa3f371dcdd4c3b40486962f4f33d3fa37d37aef58eb2cb3e9c6bb78a6caea1269549c17d52257f6e
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: cbdaaa57ff6217531681665f09d3da487bdf8b26c0a4b1d49bd9737eaadac7d39c481afdc4288bfad54844521b2fd1d2
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: c0e7b0e95cfb7dbb223c4d917631a1a0ec785e20092d2ee2d980f8d62a14d606b5a0644052daf5b8ecc65368d96caeb3
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: 97f91646a53811ea9d9a014f45511528b8bb32798004e3aff1d6f1fc8e9d4f58ece0a015e154e60798a6f9ce5f6efdad
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: a30966571f598dbc6127c69a78943af27e492747d4d30688ca224804458ae71c0fa3cf5ab41e018f33dcf2ba0216a020
--------------------------------
Decoded picture hash SEI message (50 bytes)
dph_sei_hash_type: 0
dph_sei_single_component_flag: 0
dph_sei_reserved_zero_7bits: 0
picture_md5: 163da8a9966113a091a23733fa46113e25996808a36294ecceb07267fd4c1567c352fd66be6eb8b313c92f749571ef87
#======== Film grain characteristics SEI message =====================
SEIFGCEnabled : 1
SEIFGCCancelFlag : 0
SEIFGCPersistenceFlag : 0
SEIFGCModelID : 0 # 0: frequency filtering; 1: auto-regression; 2-3 are reserved
SEIFGCSepColourDescPresentFlag : 0 # if not 0, need to specify separate colour description (not implemented in current encoder cmd line)
SEIFGCBlendingModeID : 0 # 0: additive; 1: multipliciative
SEIFGCLog2ScaleFactor : 2
SEIFGCCompModelPresentComp0 : 1 # if not 0, need to specify model for comp 0 (not implemented in current encoder cmd line)
SEIFGCCompModelPresentComp1 : 0 # if not 0, need to specify model for comp 1 (not implemented in current encoder cmd line)
SEIFGCCompModelPresentComp2 : 0 # if not 0, need to specify model for comp 2 (not implemented in current encoder cmd line)
SEIFGCNumIntensityIntervalMinus1Comp0 : 0
SEIFGCNumIntensityIntervalMinus1Comp1 : 2
SEIFGCNumIntensityIntervalMinus1Comp2 : 3
SEIFGCNumModelValuesMinus1Comp0 : 2
SEIFGCNumModelValuesMinus1Comp1 : 0
SEIFGCNumModelValuesMinus1Comp2 : 0
SEIFGCIntensityIntervalLowerBoundComp0 : 20
SEIFGCIntensityIntervalLowerBoundComp1 : 10 110 210
SEIFGCIntensityIntervalLowerBoundComp2 : 10 60 110 210
SEIFGCIntensityIntervalUpperBoundComp0 : 230
SEIFGCIntensityIntervalUpperBoundComp1 : 100 200 250
SEIFGCIntensityIntervalUpperBoundComp2 : 50 100 200 250
SEIFGCCompModelValuesComp0 : 168 2 2
SEIFGCCompModelValuesComp1 : 100 2 2 120 12 12 140 14 14
SEIFGCCompModelValuesComp2 : 200 4 4 250 6 6 300 11 11 350 13 13
\ No newline at end of file
#======== Film grain characteristics SEI message =====================
SEIFGCEnabled : 1
SEIFGCCancelFlag : 0
SEIFGCPersistenceFlag : 0
SEIFGCModelID : 0 # 0: frequency filtering; 1: auto-regression; 2-3 are reserved
SEIFGCSepColourDescPresentFlag : 0 # if not 0, need to specify separate colour description (not implemented in current encoder cmd line)
SEIFGCBlendingModeID : 0 # 0: additive; 1: multipliciative
SEIFGCLog2ScaleFactor : 2
SEIFGCCompModelPresentComp0 : 1 # if not 0, need to specify model for comp 0 (not implemented in current encoder cmd line)
SEIFGCCompModelPresentComp1 : 0 # if not 0, need to specify model for comp 1 (not implemented in current encoder cmd line)
SEIFGCCompModelPresentComp2 : 0 # if not 0, need to specify model for comp 2 (not implemented in current encoder cmd line)
SEIFGCNumIntensityIntervalMinus1Comp0 : 0
SEIFGCNumIntensityIntervalMinus1Comp1 : 2
SEIFGCNumIntensityIntervalMinus1Comp2 : 3
SEIFGCNumModelValuesMinus1Comp0 : 2
SEIFGCNumModelValuesMinus1Comp1 : 0
SEIFGCNumModelValuesMinus1Comp2 : 0
SEIFGCIntensityIntervalLowerBoundComp0 : 20
SEIFGCIntensityIntervalLowerBoundComp1 : 10 110 210
SEIFGCIntensityIntervalLowerBoundComp2 : 10 60 110 210
SEIFGCIntensityIntervalUpperBoundComp0 : 230
SEIFGCIntensityIntervalUpperBoundComp1 : 100 200 250
SEIFGCIntensityIntervalUpperBoundComp2 : 50 100 200 250
SEIFGCCompModelValuesComp0 : 168 8 8
SEIFGCCompModelValuesComp1 : 100 2 2 120 12 12 140 14 14
SEIFGCCompModelValuesComp2 : 200 4 4 250 6 6 300 11 11 350 13 13
\ No newline at end of file
#======== Film grain characteristics SEI message =====================
SEIFGCEnabled : 1
SEIFGCCancelFlag : 0
SEIFGCPersistenceFlag : 0
SEIFGCModelID : 0 # 0: frequency filtering; 1: auto-regression; 2-3 are reserved
SEIFGCSepColourDescPresentFlag : 0 # if not 0, need to specify separate colour description (not implemented in current encoder cmd line)
SEIFGCBlendingModeID : 0 # 0: additive; 1: multipliciative
SEIFGCLog2ScaleFactor : 2
SEIFGCCompModelPresentComp0 : 1 # if not 0, need to specify model for comp 0 (not implemented in current encoder cmd line)
SEIFGCCompModelPresentComp1 : 0 # if not 0, need to specify model for comp 1 (not implemented in current encoder cmd line)
SEIFGCCompModelPresentComp2 : 0 # if not 0, need to specify model for comp 2 (not implemented in current encoder cmd line)
SEIFGCNumIntensityIntervalMinus1Comp0 : 0
SEIFGCNumIntensityIntervalMinus1Comp1 : 2
SEIFGCNumIntensityIntervalMinus1Comp2 : 3
SEIFGCNumModelValuesMinus1Comp0 : 2
SEIFGCNumModelValuesMinus1Comp1 : 0
SEIFGCNumModelValuesMinus1Comp2 : 0
SEIFGCIntensityIntervalLowerBoundComp0 : 20
SEIFGCIntensityIntervalLowerBoundComp1 : 10 110 210
SEIFGCIntensityIntervalLowerBoundComp2 : 10 60 110 210
SEIFGCIntensityIntervalUpperBoundComp0 : 230
SEIFGCIntensityIntervalUpperBoundComp1 : 100 200 250
SEIFGCIntensityIntervalUpperBoundComp2 : 50 100 200 250
SEIFGCCompModelValuesComp0 : 168 14 14
SEIFGCCompModelValuesComp1 : 100 2 2 120 12 12 140 14 14
SEIFGCCompModelValuesComp2 : 200 4 4 250 6 6 300 11 11 350 13 13
\ No newline at end of file
#======== Film grain characteristics SEI message =====================
SEIFGCEnabled : 1
SEIFGCCancelFlag : 0
SEIFGCPersistenceFlag : 0
SEIFGCModelID : 0 # 0: frequency filtering; 1: auto-regression; 2-3 are reserved
SEIFGCSepColourDescPresentFlag : 0 # if not 0, need to specify separate colour description (not implemented in current encoder cmd line)
SEIFGCBlendingModeID : 0 # 0: additive; 1: multipliciative
SEIFGCLog2ScaleFactor : 4
SEIFGCCompModelPresentComp0 : 1 # if not 0, need to specify model for comp 0 (not implemented in current encoder cmd line)
SEIFGCCompModelPresentComp1 : 0 # if not 0, need to specify model for comp 1 (not implemented in current encoder cmd line)
SEIFGCCompModelPresentComp2 : 0 # if not 0, need to specify model for comp 2 (not implemented in current encoder cmd line)
SEIFGCNumIntensityIntervalMinus1Comp0 : 3
SEIFGCNumIntensityIntervalMinus1Comp1 : 2
SEIFGCNumIntensityIntervalMinus1Comp2 : 3
SEIFGCNumModelValuesMinus1Comp0 : 2
SEIFGCNumModelValuesMinus1Comp1 : 0
SEIFGCNumModelValuesMinus1Comp2 : 0
SEIFGCIntensityIntervalLowerBoundComp0 : 20 60 100 140
SEIFGCIntensityIntervalLowerBoundComp1 : 10 110 210
SEIFGCIntensityIntervalLowerBoundComp2 : 10 60 110 210
SEIFGCIntensityIntervalUpperBoundComp0 : 59 99 130 179
SEIFGCIntensityIntervalUpperBoundComp1 : 100 200 250
SEIFGCIntensityIntervalUpperBoundComp2 : 50 100 200 250
SEIFGCCompModelValuesComp0 : 16 7 7 64 7 7 112 7 7 168 7 7
SEIFGCCompModelValuesComp1 : 100 2 2 120 12 12 140 14 14
SEIFGCCompModelValuesComp2 : 200 4 4 250 6 6 300 11 11 350 13 13
\ No newline at end of file
#======== Film grain characteristics SEI message =====================
SEIFGCEnabled : 1
SEIFGCCancelFlag : 0
SEIFGCPersistenceFlag : 0
SEIFGCModelID : 0 # 0: frequency filtering; 1: auto-regression; 2-3 are reserved
SEIFGCSepColourDescPresentFlag : 0 # if not 0, need to specify separate colour description (not implemented in current encoder cmd line)
SEIFGCBlendingModeID : 0 # 0: additive; 1: multipliciative
SEIFGCLog2ScaleFactor : 4
SEIFGCCompModelPresentComp0 : 1 # if not 0, need to specify model for comp 0 (not implemented in current encoder cmd line)
SEIFGCCompModelPresentComp1 : 1 # if not 0, need to specify model for comp 1 (not implemented in current encoder cmd line)
SEIFGCCompModelPresentComp2 : 1 # if not 0, need to specify model for comp 2 (not implemented in current encoder cmd line)
SEIFGCNumIntensityIntervalMinus1Comp0 : 1
SEIFGCNumIntensityIntervalMinus1Comp1 : 2
SEIFGCNumIntensityIntervalMinus1Comp2 : 3
SEIFGCNumModelValuesMinus1Comp0 : 0
SEIFGCNumModelValuesMinus1Comp1 : 2
SEIFGCNumModelValuesMinus1Comp2 : 2
SEIFGCIntensityIntervalLowerBoundComp0 : 10 110
SEIFGCIntensityIntervalLowerBoundComp1 : 10 110 210
SEIFGCIntensityIntervalLowerBoundComp2 : 10 60 110 210
SEIFGCIntensityIntervalUpperBoundComp0 : 100 250
SEIFGCIntensityIntervalUpperBoundComp1 : 100 200 250
SEIFGCIntensityIntervalUpperBoundComp2 : 50 100 200 250
SEIFGCCompModelValuesComp0 : 100 150
SEIFGCCompModelValuesComp1 : 100 2 2 120 12 12 140 14 14
SEIFGCCompModelValuesComp2 : 200 4 4 250 6 6 300 11 11 350 13 13
\ No newline at end of file
#======== Film grain characteristics SEI message =====================
SEIFGCEnabled : 1
SEIFGCCancelFlag : 0
SEIFGCPersistenceFlag : 0
SEIFGCModelID : 0 # 0: frequency filtering; 1: auto-regression; 2-3 are reserved
SEIFGCSepColourDescPresentFlag : 0 # if not 0, need to specify separate colour description (not implemented in current encoder cmd line)
SEIFGCBlendingModeID : 0 # 0: additive; 1: multipliciative
SEIFGCLog2ScaleFactor : 3
SEIFGCCompModelPresentComp0 : 1 # if not 0, need to specify model for comp 0 (not implemented in current encoder cmd line)
SEIFGCCompModelPresentComp1 : 1 # if not 0, need to specify model for comp 1 (not implemented in current encoder cmd line)
SEIFGCCompModelPresentComp2 : 1 # if not 0, need to specify model for comp 2 (not implemented in current encoder cmd line)
SEIFGCNumIntensityIntervalMinus1Comp0 : 1
SEIFGCNumIntensityIntervalMinus1Comp1 : 2
SEIFGCNumIntensityIntervalMinus1Comp2 : 3
SEIFGCNumModelValuesMinus1Comp0 : 2
SEIFGCNumModelValuesMinus1Comp1 : 2
SEIFGCNumModelValuesMinus1Comp2 : 1
SEIFGCIntensityIntervalLowerBoundComp0 : 10 110
SEIFGCIntensityIntervalLowerBoundComp1 : 10 110 210
SEIFGCIntensityIntervalLowerBoundComp2 : 10 60 110 210
SEIFGCIntensityIntervalUpperBoundComp0 : 100 250
SEIFGCIntensityIntervalUpperBoundComp1 : 100 200 250
SEIFGCIntensityIntervalUpperBoundComp2 : 50 100 200 250
SEIFGCCompModelValuesComp0 : 50 8 8 75 8 8
SEIFGCCompModelValuesComp1 : 50 2 2 60 12 12 70 14 14
SEIFGCCompModelValuesComp2 : 100 4 125 6 150 11 175 13
\ No newline at end of file
#======== Film grain characteristics SEI message =====================
SEIFGCEnabled : 1
SEIFGCCancelFlag : 0
SEIFGCPersistenceFlag : 0
SEIFGCModelID : 0
SEIFGCSepColourDescPresentFlag : 0
SEIFGCBlendingModeID : 0
SEIFGCLog2ScaleFactor : 6
SEIFGCCompModelPresentComp0 : 1
SEIFGCCompModelPresentComp1 : 1
SEIFGCCompModelPresentComp2 : 1
SEIFGCNumIntensityIntervalMinus1Comp0 : 1
SEIFGCNumIntensityIntervalMinus1Comp1 : 2
SEIFGCNumIntensityIntervalMinus1Comp2 : 3
SEIFGCNumModelValuesMinus1Comp0 : 0
SEIFGCNumModelValuesMinus1Comp1 : 2
SEIFGCNumModelValuesMinus1Comp2 : 2
SEIFGCIntensityIntervalLowerBoundComp0 : 10 110
SEIFGCIntensityIntervalLowerBoundComp1 : 10 110 210
SEIFGCIntensityIntervalLowerBoundComp2 : 10 60 110 210
SEIFGCIntensityIntervalUpperBoundComp0 : 100 250
SEIFGCIntensityIntervalUpperBoundComp1 : 100 200 250
SEIFGCIntensityIntervalUpperBoundComp2 : 50 100 200 250
SEIFGCCompModelValuesComp0 : 100 150
SEIFGCCompModelValuesComp1 : 100 2 2 120 12 12 140 14 14
SEIFGCCompModelValuesComp2 : 160 4 4 200 6 6 240 11 11 250 13 13
\ No newline at end of file
This diff is collapsed.
/* The copyright in this software is being made available under the BSD
* License, included below. This software may be subject to other third party
* and contributor rights, including patent rights, and no such rights are
* granted under this license.
*
* Copyright (c) 2023, ITU/ISO/IEC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _VFGS_FW_H_
#define _VFGS_FW_H_
#ifndef int32
#define int32 signed int
#define uint32 unsigned int
#define int16 signed short
#define uint16 unsigned short
#define int8 signed char
#define uint8 unsigned char
#endif
#define SEI_MAX_MODEL_VALUES 6
typedef struct fgs_sei_s {
uint8 model_id;
uint8 log2_scale_factor;
uint8 comp_model_present_flag[3];
uint16 num_intensity_intervals[3];
uint8 num_model_values[3];
uint8 intensity_interval_lower_bound[3][256];
uint8 intensity_interval_upper_bound[3][256];
int16 comp_model_value[3][256][SEI_MAX_MODEL_VALUES];
} fgs_sei;
void vfgs_init_sei(fgs_sei* cfg);
#endif // _VFGS_FW_H_
/* The copyright in this software is being made available under the BSD
* License, included below. This software may be subject to other third party
* and contributor rights, including patent rights, and no such rights are
* granted under this license.
*
* Copyright (c) 2023, ITU/ISO/IEC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "vfgs_hw.h"
#include <string.h> // memcpy
#include <assert.h>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define round(a,s) (((a)+(1<<((s)-1)))>>(s))
#define PATTERN_INTERPOLATION 0
// Note: declarations optimized for code readability; e.g. pattern storage in
// actual hardware implementation would differ significantly
static int8 pattern[2][VFGS_MAX_PATTERNS+1][64][64] = {0, }; // +1 to simplify interpolation code
static uint8 sLUT[3][256] = {0, };
static uint8 pLUT[3][256] = {0, };
static uint32 rnd = 0xdeadbeef;
static uint32 rnd_up = 0xdeadbeef;
static uint32 line_rnd = 0xdeadbeef;
static uint32 line_rnd_up = 0xdeadbeef;
static uint8 scale_shift = 5+6;
static uint8 bs = 0; // bitshift = bitdepth - 8
static uint8 Y_min = 0;
static uint8 Y_max = 255;
static uint8 C_min = 0;
static uint8 C_max = 255;
static int csubx = 2;
static int csuby = 2;
// Processing pipeline (needs only 2 registers for each color actually, for horizontal deblocking)
static int16 grain[3][32]; // 9 bit needed because of overlap (has norm > 1)
static uint8 scale[3][32];
/** Pseudo-random number generator */
static uint32 prng(uint32 x)
{
uint32 s = ((x << 30) ^ (x << 2)) & 0x80000000;
x = s | (x >> 1);
return x;
}
/** Derive Y x/y offsets from (random) number
*
* Bit fields are designed to minimize overlaps across color channels, to
* decorrelate them as much as possible.
*
* 10-bit for 12 or 13 bins makes a reasonably uniform distribution (1.2%
* probability error).
*
* If 8-bit is requested to further simplify the multiplier, at the cost of less
* uniform probability, the following bitfields can be considered:
*
* Y: sign = rnd[31], x = (rnd[7:0]*13 >> 8)*4, y = (rnd[21:14]*12 >> 8)*4
* U: sign = rnd[0], x = (rnd[17:10]*13 >> 8)*2, y = (rnd[31:24]*12 >> 8)*2
* V: sign = rnd[13], x = (rnd[27:20]*13 >> 8)*2, y = (rnd[11:4]*12 >> 8)*2
*
* Note: to fully support cross-component correlation within patterns, we would
* need to align luma/chroma offsets.
*/
static void get_offset_y(uint32 val, int *s, uint8 *x, uint8 *y)
{
uint32 bf; // bit field
*s = ((val >> 31) & 1) ? -1 : 1;
bf = (val >> 0) & 0x3ff;
*x = ((bf * 13) >> 10) * 4; // 13 = 8 + 4 + 1 (two adders)
bf = (val >> 14) & 0x3ff;
*y = ((bf * 12) >> 10) * 4; // 12 = 8 + 4 (one adder)
// Note: could shift 9 and * 2, to make a multiple of 2 and make use of all
// pattern samples (when using overlap).
}
static void get_offset_u(uint32 val, int *s, uint8 *x, uint8 *y)
{
uint32 bf; // bit field
*s = ((val >> 2) & 1) ? -1 : 1;
bf = (val >> 10) & 0x3ff;
*x = ((bf * 13) >> 10) * (4/csubx);
bf = ((val >> 24) & 0x0ff) | ((val << 8) & 0x300);
*y = ((bf * 12) >> 10) * (4/csuby);
}
static void get_offset_v(uint32 val, int *s, uint8 *x, uint8 *y)
{
uint32 bf; // bit field
*s = ((val >> 15) & 1) ? -1 : 1;
bf = (val >> 20) & 0x3ff;
*x = ((bf * 13) >> 10) * (4/csubx);
bf = (val >> 4) & 0x3ff;
*y = ((bf * 12) >> 10) * (4/csuby);
}
static void add_grain_block(void* I, int c, int x, int y, int width)
{
uint8 *I8 = (uint8*)I;
uint16 *I16 = (uint16*)I;
int s, s_up; // random sign flip (current + upper row)
uint8 ox, oy; // random offset (current)
uint8 ox_up, oy_up; // random offset (upper row)
uint8 oc1, oc2; // overlapping coefficients
uint8 pi; // pattern index integer part
int i, j;
int P; // Pattern sample (from current pattern index)
#if PATTERN_INTERPOLATION
int Pn; // Next-pattern sample (from pattern index+1)
uint8 pf; // pattern index fractional part
#endif
uint8 intensity;
int flush = 0;
int subx = c ? csubx : 1;
int suby = c ? csuby : 1;
uint8 I_min = c ? C_min : Y_min;
uint8 I_max = c ? C_max : Y_max;
if ((y & 1) && suby > 1)
return;
assert(!(x & 15));
assert(width > 128);
assert(bs == 0 || bs == 2);
assert(scale_shift + bs >= 8 && scale_shift + bs <= 13);
// TODO: assert subx, suby, Y/C min/max, max pLUT values, etc
j = y & 0xf;
if (y > 15 && j == 0) // first line of overlap
{
oc1 = (suby > 1) ? 20 : 12; // current
oc2 = (suby > 1) ? 20 : 24; // upper
}
else if (y > 15 && j == 1) // second line of overlap
{
oc1 = 24;
oc2 = 12;
}
else
{
oc1 = oc2 = 0;
}
// Derive block offsets + sign
if (c==0)
get_offset_y(rnd, &s, &ox, &oy);
else if (c==1)
get_offset_u(rnd, &s, &ox, &oy);
else
get_offset_v(rnd, &s, &ox, &oy);
oy += j/suby;
// Same for upper block (overlap)
if (c==0)
get_offset_y(rnd_up, &s_up, &ox_up, &oy_up);
else if (c==1)
get_offset_u(rnd_up, &s_up, &ox_up, &oy_up);
else
get_offset_v(rnd_up, &s_up, &ox_up, &oy_up);
oy_up += (16 + j)/suby;
// Make grain pattern
for (i=0; i<16/subx; i++)
{
intensity = bs ? I16[x/subx+i] >> bs : I8[x/subx+i];
pi = pLUT[c][intensity] >> 4; // pattern index (integer part)
#if PATTERN_INTERPOLATION
pf = pLUT[c][intensity] & 15; // fractional part (interpolate with next) -- could restrict to less bits (e.g. 2)
#endif
// Pattern
P = pattern[c?1:0][pi ][oy][ox + i] * s; // We could consider just XORing the sign bit
#if PATTERN_INTERPOLATION
Pn = pattern[c?1:0][pi+1][oy][ox + i] * s; // But there are equivalent hw tricks, e.g. storing values as sign + amplitude instead of two's complement
#endif
if (oc1) // overlap
{
P = round(P * oc1 + pattern[c?1:0][pi ][oy_up][ox_up + i] * oc2 * s_up, 5);
#if PATTERN_INTERPOLATION
Pn = round(Pn * oc1 + pattern[c?1:0][pi+1][oy_up][ox_up + i] * oc2 * s_up, 5);
#endif
}
#if PATTERN_INTERPOLATION
// Pattern interpolation: P is current, Pn is next, pf is interpolation coefficient
grain[c][16/subx+i] = round(P * (16-pf) + Pn * pf, 4);
#else
grain[c][16/subx+i] = P;
#endif
// Scale sign already integrated above because of overlap
scale[c][16/subx+i] = sLUT[c][intensity];
}
// Scale & output
do
{
if (x > 0)
{
int32 g;
int16 l1, l0, r0, r1;
if (!flush)
{
// Horizontal deblock (across previous block)
l1 = grain[c][16/subx -2];
l0 = grain[c][16/subx -1];
r0 = grain[c][16/subx +0];
r1 = grain[c][16/subx +1];
grain[c][16/subx -1] = round(l1 + 3*l0 + r0, 2);
grain[c][16/subx +0] = round(l0 + 3*r0 + r1, 2);
}
for (i=0; i<16/subx; i++)
{
// Output previous block (or flush current)
g = round(scale[c][i] * (int16)grain[c][i], scale_shift);
if (bs)
I16[(x-16)/subx+i] = max(I_min<<bs, min(I_max<<bs, I16[(x-16)/subx+i] + g));
else
I8[(x-16)/subx+i] = max(I_min, min(I_max, I8[(x-16)/subx+i] + g));
}
}
// Shift pipeline
for (i=0; i<16/subx && !flush; i++)
{
grain[c][i] = grain[c][i+16/subx];
scale[c][i] = scale[c][i+16/subx];
}
if (x + 16 >= width)
{
flush ++;
x += 16;
}
} while (flush == 1);
}
/* Public interface ***********************************************************/
void vfgs_add_grain_line(void* Y, void* U, void* V, int y, int width)
{
// Generate / backup / restore per-line random seeds (needed to make multi-line blocks)
if (y && (y & 0x0f) == 0)
{
// new line of blocks --> backup + copy current to upper
line_rnd_up = line_rnd;
line_rnd = rnd;
}
rnd_up = line_rnd_up;
rnd = line_rnd;
// Process line
for (int x=0; x<width; x+=16)
{
// Process pixels for each color component
add_grain_block(Y, 0, x, y, width);
add_grain_block(U, 1, x, y, width);
add_grain_block(V, 2, x, y, width);
// Crank random generator
rnd = prng(rnd);
rnd_up = prng(rnd_up); // upper block (overlapping)
}
}
void vfgs_set_luma_pattern(int index, int8* P)
{
assert(index >= 0 && index < 8);
memcpy(pattern[0][index], P, 64*64);
}
void vfgs_set_chroma_pattern(int index, int8 *P)
{
assert(index >= 0 && index < 8);
for (int i=0; i<64/csuby; i++)
memcpy(pattern[1][index][i], P + (64/csuby)*i, 64/csubx);
}
void vfgs_set_scale_lut(int c, uint8 lut[])
{
assert(c>=0 && c<3);
memcpy(sLUT[c], lut, 256);
}
void vfgs_set_pattern_lut(int c, uint8 lut[])
{
assert(c>=0 && c<3);
memcpy(pLUT[c], lut, 256);
}
void vfgs_set_seed(uint32 seed)
{
rnd = rnd_up = line_rnd = line_rnd_up = seed;
}
void vfgs_set_scale_shift(int shift)
{
assert(shift >= 2 && shift < 8);
scale_shift = shift + 6 - bs;
}
void vfgs_set_depth(int depth)
{
assert(depth==8 || depth==10);
if (bs==0 && depth>8)
scale_shift -= 2;
if (bs==2 && depth==8)
scale_shift += 2;
bs = depth - 8;
}
void vfgs_set_chroma_subsampling(int subx, int suby)
{
assert(subx==1 || subx==2);
assert(suby==1 || suby==2);
csubx = subx;
csuby = suby;
}
/* The copyright in this software is being made available under the BSD
* License, included below. This software may be subject to other third party
* and contributor rights, including patent rights, and no such rights are
* granted under this license.
*
* Copyright (c) 2023, ITU/ISO/IEC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _VFGS_HW_H_
#define _VFGS_HW_H_
#ifndef int32
#define int32 signed int
#define uint32 unsigned int
#define int16 signed short
#define uint16 unsigned short
#define int8 signed char
#define uint8 unsigned char
#endif
#define VFGS_MAX_PATTERNS 8
void vfgs_set_luma_pattern(int index, int8* P);
void vfgs_set_chroma_pattern(int index, int8 *P);
void vfgs_set_scale_lut(int c, uint8 lut[]);
void vfgs_set_pattern_lut(int c, uint8 lut[]);
void vfgs_set_seed(uint32 seed);
void vfgs_set_scale_shift(int shift);
void vfgs_set_depth(int depth);
void vfgs_set_chroma_subsampling(int subx, int suby);
void vfgs_add_grain_line(void* Y, void* U, void* V, int y, int width);
#endif // _VFGS_HW_H_
/* The copyright in this software is being made available under the BSD
* License, included below. This software may be subject to other third party
* and contributor rights, including patent rights, and no such rights are
* granted under this license.
*
* Copyright (c) 2023, ITU/ISO/IEC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "vfgs_fw.h"
#include "vfgs_hw.h"
#include "yuv.h"
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#ifdef _MSC_VER
#define strcasecmp _stricmp
#else
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#endif
#define DEFAULT_FREQ 8
#define CHECK(cond, ...) { if (!(cond)) { fprintf(stderr, "Error: "); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); return 1; } }
// Program parameters
static FILE* fsrc = NULL;
static FILE* fdst = NULL;
static int width = 1920;
static int height = 1080;
static int depth = 10;
static int odepth = 0;
static int frames = 0;
static int seek = 0;
static int format = YUV_420;
static fgs_sei sei = {
.model_id = 0,
.log2_scale_factor = 5,
.comp_model_present_flag = { 1, 1, 1 },
.num_intensity_intervals = { 8, 8, 8 },
.num_model_values = { 3, 3, 3 },
.intensity_interval_lower_bound = {
{ 0, 40, 60, 80, 100, 120, 140, 160 },
{ 0, 64, 96, 112, 128, 144, 160, 192 },
{ 0, 64, 96, 112, 128, 144, 160, 192 }
},
.intensity_interval_upper_bound = {
{ 39, 59, 79, 99, 119, 139, 159, 255 },
{ 63, 95, 111, 127, 143, 159, 191, 255 },
{ 63, 95, 111, 127, 143, 159, 191, 255 }
},
.comp_model_value = {
// luma (scale / h / v)
{
{ 100, 7, 7 },
{ 100, 8, 8 },
{ 100, 9, 9 },
{ 110, 10, 10 },
{ 120, 11, 11 },
{ 135, 12, 12 },
{ 145, 13, 13 },
{ 180, 14, 14 },
},
// Cb
{
{ 128, 8, 8 },
{ 96, 8, 8 },
{ 64, 8, 8 },
{ 64, 8, 8 },
{ 64, 8, 8 },
{ 64, 8, 8 },
{ 96, 8, 8 },
{ 128, 8, 8 },
},
// Cr
{
{ 128, 8, 8 },
{ 96, 8, 8 },
{ 64, 8, 8 },
{ 64, 8, 8 },
{ 64, 8, 8 },
{ 64, 8, 8 },
{ 96, 8, 8 },
{ 128, 8, 8 },
},
}
};
static int read_array_u8(uint8* x, char* s)
{
while (isdigit(*s))
{
*x++ = atoi(s);
while (isdigit(*s))
s++;
while (isblank(*s))
s++;
}
return 0;
}
/** Fill model array with default values when unspecified */
static void fill_model_array(int16 *x, int n, int model_id)
{
x += n;
if (n<2) { *x++ = model_id ? 0 : DEFAULT_FREQ; } // H high cutoff / 1st AR coef (left & top)
if (n<3) { x[0] = model_id ? 0 : x[-1]; x++; } // V high cutoff / x-comp corr
if (n<4) { *x++ = 0; } // H low cutoff / 2nd AR coef (top-left, top-right)
if (n<5) { *x++ = model_id; } // H low cutoff / aspect ratio
if (n<6) { *x++ = 0; } // x-comp corr / 3rd AR coef (left-left, top-top)
}
static int read_model_array(int16 *x, char* s, int n, int model_id)
{
int i;
// Note: frequency cutoffs are included bounds (<=)
while (isdigit(*s) || *s=='-' || *s=='+')
{
for (i=0; i<n; i++)
{
*x++ = atoi(s);
while (isdigit(*s) || *s=='-' || *s=='+')
s++;
while (isblank(*s))
s++;
}
fill_model_array(x-n, n, model_id);
x += SEI_MAX_MODEL_VALUES-n;
}
return 0;
}
static int read_format(const char* s)
{
if (!strcasecmp(s, "444")) return YUV_444;
else if (!strcasecmp(s, "422")) return YUV_422;
else return YUV_420;
}
static const char* format_str(int format)
{
if (format == YUV_420) return "420";
else if (format == YUV_422) return "422";
else if (format == YUV_444) return "444";
else return "???";
}
static int adjust_chroma_cfg()
{
if (sei.model_id == 0)
{
// Conversion of component model values for 4:2:2 and 4:2:0 chroma formats
for (int c=1; c<3; c++)
if (sei.comp_model_present_flag[c])
for (int k=0; k<sei.num_intensity_intervals[c]; k++)
{
if (format < YUV_444)
sei.comp_model_value[c][k][1] = max(2, min(14, sei.comp_model_value[c][k][1] << 1)); // Horizontal frequency
if (format < YUV_422)
sei.comp_model_value[c][k][2] = max(2, min(14, sei.comp_model_value[c][k][2] << 1)); // Vertical frequency
if (format == YUV_420)
sei.comp_model_value[c][k][0] >>= 1;
else if (format == YUV_422)
sei.comp_model_value[c][k][0] = (sei.comp_model_value[c][k][0] * 181 + 128) >> 8;
}
}
return 0;
}
static int check_cfg()
{
// Unsupported features
CHECK(format == YUV_420 || (!sei.comp_model_present_flag[1] && !sei.comp_model_present_flag[2]), "color grain currently not supported on yuv422 and yuv444 formats");
CHECK(sei.model_id==0 || (!sei.comp_model_present_flag[1] && !sei.comp_model_present_flag[2]), "color grain currently not supported in SEI.AR mode");
// Sanity checks
CHECK(sei.model_id <= 1, "SEIFGCModelId shall be 0 or 1");
for (int c = 0; c < 3; c++)
{
if (sei.comp_model_present_flag[c])
{
int rng = (1 << depth);
CHECK(sei.num_model_values[c] >= 1 && sei.num_model_values[c] <= 6, "SEIFGCNumModelValuesMinus1Comp%d out of 0..5 range", c);
for (int i = 0; i < sei.num_intensity_intervals[c]; i++)
{
CHECK(sei.intensity_interval_lower_bound[c][i] <= sei.intensity_interval_upper_bound[c][i], "inconsistent interval %d for component %d: upper bound should be larger or equal than lower bound", i, c);
CHECK(sei.comp_model_value[c][i][0] < rng, "scaling factor for component %d and interval %d is too large", c, i);
if (sei.model_id == 0) // Frequency-filtering mode
{
CHECK(sei.comp_model_value[c][i][1] >= 2 && sei.comp_model_value[c][i][1] <= 14, "horizontal cutoff frequency for component %d and interval %d out of 2..14 range", c, i);
CHECK(sei.comp_model_value[c][i][1] >= 2 && sei.comp_model_value[c][i][2] <= 14, "vertical cutoff frequency for component %d and interval %d out of 2..14 range", c, i);
}
else // Auto-regressive
{
CHECK(sei.comp_model_value[c][i][1] >= -rng/2 && sei.comp_model_value[c][i][1] < rng/2, "first AR coefficient for component %d and interval %d is out of range", c, i);
CHECK(sei.comp_model_value[c][i][3] >= -rng/2 && sei.comp_model_value[c][i][3] < rng/2, "second AR coefficient for component %d and interval %d is out of range", c, i);
CHECK(sei.comp_model_value[c][i][5] >= -rng/2 && sei.comp_model_value[c][i][5] < rng/2, "third AR coefficient for component %d and interval %d is out of range", c, i);
}
}
}
}
return 0;
}
static int read_cfg(const char* filename)
{
FILE* cfg;
char line[1024];
char *s, *v, *e;
int c=0, i=0, j=0;
cfg = fopen(filename, "rt");
if (!cfg)
{
printf("Can not open file %s\n\n", filename);
return 1;
}
while (fgets(line, sizeof(line), cfg))
{
if (line[0] == '#') // remove comments (special case for 1st character)
continue;
s = strtok(line, "#"); // remove comments
while (isblank(*s)) // skip leading whitespace
s++;
s = strtok(s, ":"); // get "name"
v = strtok(NULL, ":"); // get "value"
if (v == NULL)
continue;
while (isblank(*v)) // skip leading whitespace of "value"
v++;
for (e=s; !isblank(*e) && *e; e++) // trim trailing whitespace of "name"
;
*e = '\0';
// SEI
if (!strcasecmp(s, "SEIFGCModelId")) { sei.model_id = atoi(v); }
else if (!strcasecmp(s, "SEIFGCLog2ScaleFactor")) { sei.log2_scale_factor = atoi(v); }
else if (!strcasecmp(s, "SEIFGCCompModelPresentComp0")) { sei.comp_model_present_flag[0] = atoi(v); }
else if (!strcasecmp(s, "SEIFGCCompModelPresentComp1")) { sei.comp_model_present_flag[1] = atoi(v); }
else if (!strcasecmp(s, "SEIFGCCompModelPresentComp2")) { sei.comp_model_present_flag[2] = atoi(v); }
else if (!strcasecmp(s, "SEIFGCNumIntensityIntervalMinus1Comp0")) { sei.num_intensity_intervals[0] = atoi(v) + 1; }
else if (!strcasecmp(s, "SEIFGCNumIntensityIntervalMinus1Comp1")) { sei.num_intensity_intervals[1] = atoi(v) + 1; }
else if (!strcasecmp(s, "SEIFGCNumIntensityIntervalMinus1Comp2")) { sei.num_intensity_intervals[2] = atoi(v) + 1; }
else if (!strcasecmp(s, "SEIFGCNumModelValuesMinus1Comp0")) { sei.num_model_values[0] = atoi(v) + 1; }
else if (!strcasecmp(s, "SEIFGCNumModelValuesMinus1Comp1")) { sei.num_model_values[1] = atoi(v) + 1; }
else if (!strcasecmp(s, "SEIFGCNumModelValuesMinus1Comp2")) { sei.num_model_values[2] = atoi(v) + 1; }
else if (!strcasecmp(s, "SEIFGCIntensityIntervalLowerBoundComp0")) { read_array_u8(sei.intensity_interval_lower_bound[0], v); }
else if (!strcasecmp(s, "SEIFGCIntensityIntervalLowerBoundComp1")) { read_array_u8(sei.intensity_interval_lower_bound[1], v); }
else if (!strcasecmp(s, "SEIFGCIntensityIntervalLowerBoundComp2")) { read_array_u8(sei.intensity_interval_lower_bound[2], v); }
else if (!strcasecmp(s, "SEIFGCIntensityIntervalUpperBoundComp0")) { read_array_u8(sei.intensity_interval_upper_bound[0], v); }
else if (!strcasecmp(s, "SEIFGCIntensityIntervalUpperBoundComp1")) { read_array_u8(sei.intensity_interval_upper_bound[1], v); }
else if (!strcasecmp(s, "SEIFGCIntensityIntervalUpperBoundComp2")) { read_array_u8(sei.intensity_interval_upper_bound[2], v); }
else if (!strcasecmp(s, "SEIFGCCompModelValuesComp0")) { read_model_array(sei.comp_model_value[0][0], v, sei.num_model_values[0], sei.model_id); }
else if (!strcasecmp(s, "SEIFGCCompModelValuesComp1")) { read_model_array(sei.comp_model_value[1][0], v, sei.num_model_values[1], sei.model_id); }
else if (!strcasecmp(s, "SEIFGCCompModelValuesComp2")) { read_model_array(sei.comp_model_value[2][0], v, sei.num_model_values[2], sei.model_id); }
// SEI, dump style
else if (!strcasecmp(s, "fg_model_id")) { sei.model_id = atoi(v); }
else if (!strcasecmp(s, "fg_log2_scale_factor")) { sei.log2_scale_factor = atoi(v); }
else if (!strcasecmp(s, "fg_comp_model_present_flag[c]")) { sei.comp_model_present_flag[c] = atoi(v); c = (c<2) ? c+1 : 0; }
else if (!strcasecmp(s, "fg_num_intensity_intervals_minus1[c]")) { sei.num_intensity_intervals[c] = atoi(v) + 1; }
else if (!strcasecmp(s, "fg_num_model_values_minus1[c]")) { sei.num_model_values[c] = atoi(v) + 1; }
else if (!strcasecmp(s, "fg_intensity_interval_lower_bound[c][i]")) { sei.intensity_interval_lower_bound[c][i] = atoi(v); }
else if (!strcasecmp(s, "fg_intensity_interval_upper_bound[c][i]")) { sei.intensity_interval_upper_bound[c][i] = atoi(v); }
else if (!strcasecmp(s, "fg_comp_model_value[c][i]"))
{
sei.comp_model_value[c][i][j++] = atoi(v);
if (j == sei.num_model_values[c])
{
fill_model_array(sei.comp_model_value[c][i], sei.num_model_values[c], sei.model_id);
i ++; // next intensity interval
j = 0;
if (i == sei.num_intensity_intervals[c])
{
c ++; // next color component
i = 0;
}
}
}
else if (!strcasecmp(s, "fg_characteristics_persistence_flag")) { break; /* stop at the end of the first FGS SEI */ }
}
return 0;
}
static void apply_gain(unsigned gain)
{
if (gain==100)
return;
for(;gain>100; gain/=2)
sei.log2_scale_factor --;
for(;gain && gain<50; gain*=2)
sei.log2_scale_factor ++;
for (int c=0; c<3; c++)
for (int i=0; sei.comp_model_present_flag[c] && i<sei.num_intensity_intervals[c]; i++)
sei.comp_model_value[c][i][0] = (int16)((int)sei.comp_model_value[c][i][0] * gain / 100);
}
static int help(const char* name)
{
printf("Usage: %s [options] <input.yuv> <output.yuv>\n\n", name);
printf(" -w,--width <value> Picture width [%d]\n", width);
printf(" -h,--height <value> Picture height [%d]\n", height);
printf(" -b,--bitdepth <value> Input bit depth [%d]\n", depth);
printf(" --outdepth <value> Output bit depth (<= input depth) [same as input]\n");
printf(" -f,--format <value> Chroma format (420/422/444) [%s]\n", format_str(format));
printf(" -n,--frames <value> Number of frames to process (0=all) [%d]\n", frames);
printf(" -s,--seek <value> Picture start index within input file [%d]\n", seek);
printf(" -c,--cfg <filename> Read film grain configuration file\n");
printf(" -g,--gain <value> Apply a global scale (in percent) to grain strength\n");
printf(" --help Display this page\n\n");
return 0;
}
static void vfgs_add_grain(yuv* frame)
{
uint8 *Y = frame->Y;
uint8 *U = frame->U;
uint8 *V = frame->V;
assert(depth == frame->depth);
for (int y=0; y<frame->height; y++)
{
vfgs_add_grain_line(Y, U, V, y, frame->width);
Y += frame->stride * (depth > 8 ? 2 : 1);
if ((y & 1) || (frame->height == frame->cheight))
{
U += frame->cstride * (depth > 8 ? 2 : 1);
V += frame->cstride * (depth > 8 ? 2 : 1);
}
}
}
int main(int argc, const char **argv)
{
int i;
int err=0;
yuv frame, oframe;
unsigned gain = 100;
// Parse parameters
for (i=1; i<argc && !err; i++)
{
const char* param = argv[i];
if (!strcasecmp(param, "-w") || !strcasecmp(param, "--width")) { if (i+1 < argc) width = atoi(argv[++i]); else err = 1; }
else if (!strcasecmp(param, "-h") || !strcasecmp(param, "--height")) { if (i+1 < argc) height = atoi(argv[++i]); else err = 1; }
else if (!strcasecmp(param, "-b") || !strcasecmp(param, "--bitdepth")) { if (i+1 < argc) depth = atoi(argv[++i]); else err = 1; }
else if ( !strcasecmp(param, "--outdepth")) { if (i+1 < argc) odepth = atoi(argv[++i]); else err = 1; }
else if (!strcasecmp(param, "-f") || !strcasecmp(param, "--format")) { if (i+1 < argc) format = read_format(argv[++i]); else err = 1; }
else if (!strcasecmp(param, "-n") || !strcasecmp(param, "--frames")) { if (i+1 < argc) frames = atoi(argv[++i]); else err = 1; }
else if (!strcasecmp(param, "-s") || !strcasecmp(param, "--seek")) { if (i+1 < argc) seek = atoi(argv[++i]); else err = 1; }
else if (!strcasecmp(param, "-c") || !strcasecmp(param, "--cfg")) { if (i+1 < argc) err = read_cfg(argv[++i]); else err = 1; }
else if (!strcasecmp(param, "-g") || !strcasecmp(param, "--gain")) { if (i+1 < argc) gain = atoi(argv[++i]); else err = 1; }
else if (!strcasecmp(param, "-h") || !strcasecmp(param, "--help")) { help(argv[0]); return 1; }
else if (param[0]!='-')
{
if (!fsrc)
{
fsrc = fopen(param, "rb");
if (!fsrc)
{
printf("Can not open file %s\n\n", param);
err = 1;
}
}
else if (!fdst)
{
fdst = fopen(param, "wb");
if (!fdst)
{
printf("Can not create file %s\n\n", param);
err = 1;
}
}
}
else
{
printf("Unknown parameter %s\n", param);
err = 1;
}
}
if (!fsrc || !fdst || err)
{
help(argv[0]);
return 1;
}
if (check_cfg())
{
return 1;
}
odepth = odepth ? odepth : depth;
assert(depth==8 || depth==10);
assert((odepth==8 || odepth==10) && (odepth <= depth));
assert(width>=128);
assert(height>=128);
vfgs_set_depth(depth);
vfgs_set_chroma_subsampling((format < YUV_444)?2:1, (format < YUV_422)?2:1);
adjust_chroma_cfg();
apply_gain(gain);
vfgs_init_sei(&sei);
yuv_alloc(width, height, depth, format, &frame);
if (odepth < depth)
yuv_alloc(width, height, odepth, format, &oframe);
else
oframe = frame;
yuv_skip(&frame, seek, fsrc);
// Process frames
for (int n = 0; ((frames == 0) || (n < frames)) && !ferror(fsrc); n++)
{
yuv_read(&frame, fsrc);
if (feof(fsrc))
break;
//yuv_pad(&frame);
vfgs_add_grain(&frame);
if (odepth < depth)
yuv_to_8bit(&oframe, &frame);
yuv_write(&oframe, fdst);
}
yuv_free(&frame);
if (odepth < depth)
yuv_free(&oframe);
return 0;
}
src/yuv.c 0 → 100644
/* The copyright in this software is being made available under the BSD
* License, included below. This software may be subject to other third party
* and contributor rights, including patent rights, and no such rights are
* granted under this license.
*
* Copyright (c) 2023, ITU/ISO/IEC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "yuv.h"
#include <stdint.h>
#include <assert.h>
#ifdef _MSC_VER
#include <malloc.h>
#define fseeko _fseeki64
#else
#include <mm_malloc.h>
#endif
#define ALIGN_SIZE 16 // width & height padded to that
#define ALIGN_MEM 64 // start addr + stride should be a multiple of that
#define uint16 unsigned short
#define uint8 unsigned char
int yuv_alloc(int width, int height, int depth, int format, yuv* frame)
{
int size;
int sz = (depth == 8) ? 1 : 2;
int height2, cheight2;
int subx = (format > YUV_422) ? 1 : 2;
int suby = (format > YUV_420) ? 1 : 2;
frame->depth = depth;
frame->width = width;
frame->stride = (width & (ALIGN_MEM-1)) ? (width + ALIGN_MEM) & ~(ALIGN_MEM-1) : width;
frame->height = height;
height2 = (height & (ALIGN_SIZE-1)) ? (height + ALIGN_SIZE) & ~(ALIGN_SIZE-1) : height;
size = frame->stride * height2 * sz;
width = width / subx;
frame->cwidth = width;
frame->cstride = (width & (ALIGN_MEM-1)) ? (width + ALIGN_MEM) & ~(ALIGN_MEM-1) : width;
height = height / suby;
frame->cheight = height;
cheight2 = (height & (ALIGN_SIZE/suby-1)) ? (height + ALIGN_SIZE/suby) & ~(ALIGN_SIZE/suby-1) : height;
size += frame->cstride * cheight2 * 2 * sz;
frame->Y = _mm_malloc(size, ALIGN_MEM*sz);
frame->U = (uint8*) frame->Y + frame->stride * height2 * sz;
frame->V = (uint8*) frame->U + frame->cstride * cheight2 * sz;
return !frame->Y;
}
void yuv_free(yuv* frame)
{
_mm_free(frame->Y);
frame->Y = NULL;
frame->U = NULL;
frame->V = NULL;
}
int yuv_skip(yuv* frame, int n, FILE* file)
{
int size;
int sz = (frame->depth == 8) ? 1 : 2;
size = frame->width * frame->height * sz;
size += frame->cwidth * frame->cheight * 2 * sz;
return fseeko(file, (long long)size * n, SEEK_CUR);
}
static void yuv_pad_comp(void* buffer, int width, int height, int stride, int walign, int halign, int depth)
{
uint8* buf8 = (uint8* )buffer;
uint16* buf16 = (uint16*)buffer;
int width2 = (width & (walign-1)) ? (width + walign) & ~(walign-1) : width;
int height2 = (height & (halign-1)) ? (height + halign) & ~(halign-1) : height;
int i, k;
assert(walign==ALIGN_SIZE || walign==ALIGN_SIZE/2 || halign==ALIGN_SIZE || halign==ALIGN_SIZE/2);
assert(((intptr_t)buffer & ((depth == 8) ? ALIGN_MEM-1 : 2*ALIGN_MEM-1)) == 0);
assert((stride & (ALIGN_MEM-1)) == 0);
if (depth==8)
{
for (i=0; i<height; i++)
{
for (k=width; k<width2; k++)
buf8[k] = buf8[width-1];
buf8 += stride;
}
for (;i<height2; i++)
{
for (k=0; k<stride; k++)
buf8[k] = buf8[k-stride];
buf8 += stride;
}
}
else
{
for (i=0; i<height; i++)
{
for (k=width; k<width2; k++)
buf16[k] = buf16[width-1];
buf16 += stride;
}
for (;i<height2; i++)
{
for (k=0; k<stride; k++)
buf16[k] = buf16[k-stride];
buf16 += stride;
}
}
}
void yuv_pad(yuv* frame)
{
int subx = (frame->width == frame->cwidth) ? 1 : 2;
int suby = (frame->height == frame->cheight) ? 1 : 2;
yuv_pad_comp(frame->Y, frame->width, frame->height, frame->stride, ALIGN_SIZE, ALIGN_SIZE, frame->depth);
yuv_pad_comp(frame->U, frame->cwidth, frame->cheight, frame->cstride, ALIGN_SIZE/subx, ALIGN_SIZE/suby, frame->depth);
yuv_pad_comp(frame->V, frame->cwidth, frame->cheight, frame->cstride, ALIGN_SIZE/subx, ALIGN_SIZE/suby, frame->depth);
}
static int yuv_read_comp(void* buffer, FILE* file, int width, int height, int stride, int depth)
{
uint8* buf8 = buffer;
int sz = (depth == 8) ? 1 : 2;
int nread = 0;
int err = 0;
int i;
for (i=0; i<height && !err; i++)
{
nread = (int)fread(buf8, sz, width, file);
buf8 += stride*sz;
err = (nread != width);
}
return err;
}
int yuv_read(yuv* frame, FILE* file)
{
int err = 0;
err |= yuv_read_comp(frame->Y, file, frame->width, frame->height, frame->stride, frame->depth);
err |= yuv_read_comp(frame->U, file, frame->cwidth, frame->cheight, frame->cstride, frame->depth);
err |= yuv_read_comp(frame->V, file, frame->cwidth, frame->cheight, frame->cstride, frame->depth);
return err;
}
static int yuv_write_comp(void* buffer, FILE* file, int width, int height, int stride, int depth)
{
uint8* buf8 = buffer;
int sz = (depth == 8) ? 1 : 2;
int nwrite = 0;
int err = 0;
int i;
for (i=0; i<height && !err; i++)
{
nwrite = (int)fwrite(buf8, sz, width, file);
buf8 += stride*sz;
err = (nwrite != width);
}
return err;
}
int yuv_write(yuv* frame, FILE* file)
{
int err = 0;
err |= yuv_write_comp(frame->Y, file, frame->width, frame->height, frame->stride, frame->depth);
err |= yuv_write_comp(frame->U, file, frame->cwidth, frame->cheight, frame->cstride, frame->depth);
err |= yuv_write_comp(frame->V, file, frame->cwidth, frame->cheight, frame->cstride, frame->depth);
return err;
}
void yuv_to_8bit(yuv* dst, const yuv* src)
{
uint8* buf8;
uint16* buf16;
int i, j;
assert(dst->depth == 8 && src->depth == 10);
assert(dst->width == src->width && dst->height == src->height);
assert(dst->cwidth == src->cwidth && dst->cheight == src->cheight);
buf16 = src->Y;
buf8 = dst->Y;
for (j=0; j<src->height; j++)
{
for (i=0; i<src->width; i++)
buf8[i] = (uint8)((buf16[i] + 2) >> 2);
buf16 += src->stride;
buf8 += dst->stride;
}
buf16 = src->U;
buf8 = dst->U;
for (j=0; j<src->cheight; j++)
{
for (i=0; i<src->cwidth; i++)
buf8[i] = (uint8)((buf16[i] + 2) >> 2);
buf16 += src->cstride;
buf8 += dst->cstride;
}
buf16 = src->V;
buf8 = dst->V;
for (j=0; j<src->cheight; j++)
{
for (i=0; i<src->cwidth; i++)
buf8[i] = (uint8)((buf16[i] + 2) >> 2);
buf16 += src->cstride;
buf8 += dst->cstride;
}
}
/* The copyright in this software is being made available under the BSD
* License, included below. This software may be subject to other third party
* and contributor rights, including patent rights, and no such rights are
* granted under this license.
*
* Copyright (c) 2023, ITU/ISO/IEC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _YUV_H_
#define _YUV_H_
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#define YUV_420 0
#define YUV_422 1
#define YUV_444 2
typedef struct yuv_s {
void* Y;
void* U;
void* V;
unsigned short width;
unsigned short height;
unsigned short stride;
unsigned short cwidth;
unsigned short cheight;
unsigned short cstride;
unsigned depth;
} yuv;
int yuv_alloc(int width, int height, int depth, int format, yuv* frame);
void yuv_free(yuv* frame);
void yuv_pad(yuv* frame);
int yuv_skip(yuv* frame, int n, FILE* file);
int yuv_read(yuv* frame, FILE* file);
int yuv_write(yuv* frame, FILE* file);
void yuv_to_8bit(yuv* dst, const yuv* src);
#endif // _YUV_H_
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment