├── .github ├── dependabot.yml └── workflows │ ├── build-debian-packages.yml │ ├── build-on-Windows.yml │ ├── build-on-linux.yml │ └── build-on-macOS.yml ├── .gitignore ├── .gitmodules ├── .idea ├── cavif.iml ├── inspectionProfiles │ └── Project_Default.xml ├── misc.xml └── modules.xml ├── CHANGELOG.md ├── CMakeLists.txt ├── LICENSE ├── README.md ├── debian ├── .gitignore ├── README.Debian ├── README.source ├── cavif-docs.docs ├── changelog ├── compat ├── control ├── copyright ├── manpage.1.ex ├── manpage.sgml.ex ├── manpage.xml.ex ├── menu.ex ├── rules ├── source │ └── format └── watch.ex ├── doc └── ja_JP │ ├── README.md │ └── usage.md ├── patches ├── libaom.patch └── zlib.patch ├── scripts ├── apply-patches.sh ├── build-debian-package.sh ├── build-deps.sh ├── reset-submodules.sh └── test-debian-package.sh ├── src ├── AVIFBuilder.cpp ├── AVIFBuilder.hpp ├── Config.cpp ├── Config.hpp ├── ext │ ├── ExternalPartitionModel.hpp │ ├── ExternalPartitionModelFactoryContainer.cpp │ ├── ExternalPartitionModelFactoryContainer.hpp │ └── models │ │ ├── NonSplitPartitionModel.cpp │ │ └── NonSplitPartitionModel.hpp ├── img │ ├── Conversion.hpp │ └── png │ │ ├── Reader.cpp │ │ └── Reader.hpp └── main.cpp └── test └── NopTest.cpp /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gitsubmodule" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | time: "02:00" 8 | timezone: "Asia/Tokyo" 9 | reviewers: 10 | - "ledyba-z" 11 | - package-ecosystem: "github-actions" 12 | directory: "/" 13 | schedule: 14 | interval: "weekly" 15 | time: "02:00" 16 | timezone: Asia/Tokyo 17 | reviewers: 18 | - "ledyba-z" 19 | -------------------------------------------------------------------------------- /.github/workflows/build-debian-packages.yml: -------------------------------------------------------------------------------- 1 | name: Build debian packages 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - dependabot/** 7 | tags: 8 | - v* 9 | pull_request: 10 | branches: 11 | - master 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | strategy: 17 | matrix: 18 | codename: [bionic, focal] 19 | steps: 20 | - uses: actions/checkout@v3 21 | with: 22 | submodules: 'recursive' 23 | fetch-depth: 0 24 | - name: Build debian package 25 | uses: link-u/execute-on-separated-ubuntu@master 26 | with: 27 | script: scripts/build-debian-package.sh 28 | on: ${{ matrix.codename }} 29 | - name: Upload result 30 | uses: actions/upload-artifact@v3 31 | with: 32 | name: ${{ matrix.codename }} 33 | path: | 34 | **/*.ddeb 35 | **/*.deb 36 | - name: Inspect disk usage 37 | shell: bash 38 | run: du -sh . 39 | 40 | test: 41 | needs: build 42 | runs-on: ubuntu-latest 43 | strategy: 44 | matrix: 45 | codename: [bionic, focal] 46 | steps: 47 | - uses: actions/checkout@v3 48 | - name: Download artifact 49 | uses: actions/download-artifact@v3 50 | with: 51 | name: ${{ matrix.codename }} 52 | path: artifact 53 | - name: Check debian package 54 | uses: link-u/execute-on-separated-ubuntu@master 55 | with: 56 | script: scripts/test-debian-package.sh 57 | on: ${{ matrix.codename }} 58 | 59 | release: 60 | if: startsWith(github.ref, 'refs/tags/v') 61 | needs: test 62 | runs-on: ubuntu-latest 63 | steps: 64 | - name: Create release 65 | id: create_release 66 | uses: actions/create-release@v1.1.4 67 | env: 68 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 69 | with: 70 | tag_name: ${{ github.ref }} 71 | release_name: Release ${{ github.ref }} 72 | commitish: ${{ github.sha }} 73 | draft: true 74 | prerelease: true 75 | outputs: 76 | upload_url: ${{ steps.create_release.outputs.upload_url }} 77 | 78 | upload: 79 | needs: release 80 | runs-on: ubuntu-latest 81 | strategy: 82 | matrix: 83 | codename: [bionic, focal] 84 | steps: 85 | - name: Download artifact 86 | uses: actions/download-artifact@v3 87 | with: 88 | name: ${{ matrix.codename }} 89 | path: ${{ matrix.codename }} 90 | - name: Create a zip 91 | shell: bash 92 | run: zip ${{ matrix.codename }}.zip ${{ matrix.codename }}/* 93 | - name: Upload release asset 94 | uses: actions/upload-release-asset@v1.0.2 95 | env: 96 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 97 | with: 98 | upload_url: ${{ needs.release.outputs.upload_url }} 99 | asset_path: ${{ matrix.codename }}.zip 100 | asset_name: ${{ matrix.codename }}.zip 101 | asset_content_type: application/zip 102 | 103 | deploy: 104 | needs: upload 105 | runs-on: ubuntu-latest 106 | strategy: 107 | matrix: 108 | codename: [bionic, focal] 109 | steps: 110 | - name: Download artifact 111 | uses: actions/download-artifact@v3 112 | with: 113 | name: ${{ matrix.codename }} 114 | path: ${{ matrix.codename }} 115 | - name: Listup files 116 | shell: bash 117 | run: find . 118 | - name: Deploy 119 | shell: bash 120 | run: | 121 | printenv DEPLOY_SCRIPT | base64 -d > deploy.sh 122 | bash deploy.sh upload "${{ matrix.codename }}" "avif" "${{ matrix.codename }}" 123 | env: 124 | DEPLOY_SCRIPT: ${{ secrets.YOROZU_DEPLOY_SCRIPT }} 125 | 126 | sign: 127 | needs: deploy 128 | runs-on: ubuntu-latest 129 | steps: 130 | - name: Sign 131 | shell: bash 132 | run: | 133 | printenv DEPLOY_SCRIPT | base64 -d > deploy.sh 134 | bash deploy.sh sign 135 | env: 136 | DEPLOY_SCRIPT: ${{ secrets.YOROZU_DEPLOY_SCRIPT }} 137 | -------------------------------------------------------------------------------- /.github/workflows/build-on-Windows.yml: -------------------------------------------------------------------------------- 1 | name: Build on Windows 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - dependabot/** 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | build: 13 | runs-on: windows-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | with: 17 | submodules: 'recursive' 18 | fetch-depth: 0 19 | - uses: msys2/setup-msys2@v2 20 | with: 21 | msystem: MINGW64 22 | path-type: strict 23 | - name: Install dependencies 24 | shell: msys2 {0} 25 | run: | 26 | set +eux 27 | export HOME=${{ github.workspace }} 28 | pacman -S --noconfirm \ 29 | git \ 30 | patch \ 31 | \ 32 | base-devel \ 33 | mingw-w64-x86_64-toolchain \ 34 | \ 35 | mingw-w64-x86_64-cmake \ 36 | mingw-w64-x86_64-nasm \ 37 | mingw-w64-x86_64-yasm \ 38 | mingw-w64-x86_64-meson \ 39 | mingw-w64-x86_64-ninja 40 | - name: build dependencies 41 | shell: msys2 {0} 42 | run: | 43 | set +eux 44 | export HOME=${{ github.workspace }} 45 | bash scripts/reset-submodules.sh 46 | bash scripts/apply-patches.sh 47 | bash scripts/build-deps.sh 48 | - name: configure 49 | shell: msys2 {0} 50 | run: | 51 | set +eux 52 | export HOME=${{ github.workspace }} 53 | cmake -S . -B build -G Ninja '-DCMAKE_CXX_FLAGS=-static' 54 | - name: make 55 | shell: msys2 {0} 56 | run: | 57 | set +eux 58 | export HOME=${{ github.workspace }} 59 | cd build 60 | ninja -v 61 | strip cavif.exe 62 | - name: Upload result 63 | uses: actions/upload-artifact@v3 64 | with: 65 | name: cavif-win64 66 | path: build/cavif.exe 67 | -------------------------------------------------------------------------------- /.github/workflows/build-on-linux.yml: -------------------------------------------------------------------------------- 1 | name: Build on Linux 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - dependabot/** 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | build: 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | matrix: 16 | os: [ubuntu-18.04, ubuntu-20.04] 17 | steps: 18 | - uses: actions/checkout@v3 19 | with: 20 | submodules: 'recursive' 21 | fetch-depth: 0 22 | - name: Install dependencies 23 | shell: bash 24 | run: | 25 | # Workaround: gcc >= 8.0 is required. 26 | case $(lsb_release -cs) in 27 | bionic) 28 | sudo apt install -y --no-install-recommends \ 29 | gcc-8 g++-8 yasm nasm python3-venv python3-pip python3-setuptools ;; 30 | *) 31 | sudo apt install -y --no-install-recommends \ 32 | gcc g++ yasm nasm python3-venv python3-pip python3-setuptools ;; 33 | esac 34 | sudo apt install -y gcc-8 g++-8 yasm python3-venv python3-pip python3-setuptools 35 | python3 -m venv venv 36 | source venv/bin/activate 37 | pip3 install wheel 38 | pip3 install meson 39 | pip3 install ninja 40 | - name: configure 41 | shell: bash 42 | run: | 43 | source venv/bin/activate 44 | # Workaround: gcc >= 8.0 is required. 45 | case $(lsb_release -cs) in 46 | bionic) 47 | export CC=gcc-8 48 | export CXX=g++-8 49 | ;; 50 | *) ;; 51 | esac 52 | bash scripts/reset-submodules.sh 53 | bash scripts/apply-patches.sh 54 | bash scripts/build-deps.sh 55 | cmake -S . -B build -G Ninja 56 | - name: Build 57 | shell: bash 58 | run: | 59 | source venv/bin/activate 60 | env --chdir build ninja 61 | -------------------------------------------------------------------------------- /.github/workflows/build-on-macOS.yml: -------------------------------------------------------------------------------- 1 | name: Build on macOS 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - dependabot/** 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | build: 13 | runs-on: macos-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | with: 17 | submodules: 'recursive' 18 | fetch-depth: 0 19 | - name: Install dependencies 20 | shell: bash 21 | run: | 22 | python3 -m venv venv 23 | source venv/bin/activate 24 | pip3 install wheel 25 | pip3 install meson 26 | pip3 install ninja 27 | brew install yasm nasm 28 | - name: configure 29 | shell: bash 30 | run: | 31 | export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)" 32 | source venv/bin/activate 33 | bash scripts/reset-submodules.sh 34 | bash scripts/apply-patches.sh 35 | bash scripts/build-deps.sh 36 | cmake -S . -B build -G 'Ninja' 37 | - name: make 38 | shell: bash 39 | run: | 40 | export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)" 41 | source venv/bin/activate 42 | (cd build && ninja) 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### 2 | *.bmp 3 | *.png 4 | *.avif 5 | *.csv 6 | /perf.data 7 | /perf.data.old 8 | /build/ 9 | /*.deb 10 | /*.ddeb 11 | 12 | ### C++ template 13 | # Compiled Object files 14 | *.slo 15 | *.lo 16 | *.o 17 | *.obj 18 | 19 | # Precompiled Headers 20 | *.gch 21 | *.pch 22 | 23 | # Compiled Dynamic libraries 24 | *.so 25 | *.dylib 26 | *.dll 27 | 28 | # Fortran module files 29 | *.mod 30 | 31 | # Compiled Static libraries 32 | *.lai 33 | *.la 34 | *.a 35 | *.lib 36 | 37 | # Executables 38 | *.exe 39 | *.out 40 | *.app 41 | 42 | # 43 | /cmake-build-*/ 44 | 45 | ### JetBrains template 46 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 47 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 48 | 49 | # User-specific stuff: 50 | .idea/workspace.xml 51 | .idea/tasks.xml 52 | .idea/dictionaries 53 | .idea/vcs.xml 54 | .idea/jsLibraryMappings.xml 55 | 56 | # Sensitive or high-churn files: 57 | .idea/dataSources.ids 58 | .idea/dataSources.xml 59 | .idea/dataSources.local.xml 60 | .idea/sqlDataSources.xml 61 | .idea/dynamic.xml 62 | .idea/uiDesigner.xml 63 | 64 | # Gradle: 65 | .idea/gradle.xml 66 | .idea/libraries 67 | 68 | # Mongo Explorer plugin: 69 | .idea/mongoSettings.xml 70 | 71 | ## File-based project format: 72 | *.iws 73 | 74 | ## Plugin-specific files: 75 | 76 | # IntelliJ 77 | /out/ 78 | 79 | # mpeltonen/sbt-idea plugin 80 | .idea_modules/ 81 | 82 | # JIRA plugin 83 | atlassian-ide-plugin.xml 84 | 85 | # Crashlytics plugin (for Android Studio and IntelliJ) 86 | com_crashlytics_export_strings.xml 87 | crashlytics.properties 88 | crashlytics-build.properties 89 | fabric.properties 90 | 91 | # 92 | /_deps/ 93 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/clipp"] 2 | path = external/clipp 3 | url = https://github.com/muellan/clipp 4 | [submodule "external/libaom"] 5 | path = external/libaom 6 | url = https://aomedia.googlesource.com/aom 7 | ignore = dirty 8 | [submodule "external/libpng"] 9 | path = external/libpng 10 | url = https://git.code.sf.net/p/libpng/code 11 | [submodule "external/libavif-container"] 12 | path = external/libavif-container 13 | url = https://github.com/link-u/libavif-container 14 | [submodule "external/zlib"] 15 | path = external/zlib 16 | url = https://github.com/madler/zlib 17 | ignore = dirty 18 | [submodule "external/vmaf"] 19 | path = external/vmaf 20 | url = https://github.com/Netflix/vmaf 21 | -------------------------------------------------------------------------------- /.idea/cavif.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ## [0.4.0] 10 | 11 | ### Added 12 | 13 | - New parameters for `--horizontal-scale-mode` and `--vertical-scale-mode` are introduced. 14 | - `1/4` 15 | - `3/4` 16 | - `1/8` 17 | - `--cpu-used 9` is introduced. 18 | - `--(enable|disable)-rect-tx` is introduced. Enabled by default. 19 | - `--(enable|disable)-diagonal-intra` is introduced. Enabled by default. 20 | - `--content-type (default|screen|film)` is introduced. 21 | - `default`: regular video content(default) 22 | - `screen`: Screen capture content 23 | - `film`: Film content 24 | - `--(enable|disable)-tx-size-search` is introduced. Enabled by default. 25 | - `--delta-q-strength (int)` is introduced. Takes 0 to 1000. Default is `100`. 26 | - `--(enable|disble)-loop-filter` is introduced. Enabled by default. 27 | 28 | ### Changed 29 | - libaom is upgraded to v3.3.0 30 | - libvmaf is upgrade to [441ab02a6b9df77a716f9bc1772340acd36e201b](https://github.com/Netflix/vmaf/tree/441ab02a6b9df77a716f9bc1772340acd36e201b). 31 | - [Remove URL from header to make image sizes smaller](https://github.com/link-u/cavif/pull/56). 32 | - Default values of `--color-primaries`, `--transfer-characteristics` and `--matrix-coefficients` are now "empty". 33 | - If those flags are not set and input PNG file does not contain a `sRGB` chunk, these settings are used: 34 | - `--color-primaries 1` (sRGB/sYCC) 35 | - `--transfer-characteristics 13` (sRGB/sYCC) 36 | - `--matrix-coefficients 5` (sYCC) 37 | - All of `--color-primaries`, `--transfer-characteristics` and `--matrix-coefficients` nor none of them must be set. 38 | - `--enable-full-color-range` is now default, as mentioned in [ISO/IEC 23000-22:2019/Amd 2:2021](https://www.iso.org/standard/81634.html). 39 | - [Use SingleItemTypeReferenceBox instead of SingleItemTypeReferenceBoxLarge](https://github.com/link-u/cavif/commit/e271be5eddf1259d7a34315ece967a5e95766f49) to make images smaller. 40 | 41 | ### Fixed 42 | 43 | - Now we can build cavif for mac OS and debian package. 44 | - `--crop-size` and `--crop-offset` are now validated according to [ISO/IEC 23000-22:2019/Amd 2:2021](https://www.iso.org/standard/81634.html): 45 | - crop size must be integers. 46 | - the leftmost pixel must be positioned in even line if pixel format is `yuv420` or `yuv422`. 47 | - the topmost pixel must be positioned in even line if pixel format is `yuv420`. 48 | - [Fix HEIF compatibility](https://github.com/link-u/cavif/commit/2232b3f23646e18607cf6636a967720a6e0ec2d7). 49 | 50 | ### Removed 51 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(cavif LANGUAGES CXX) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 6 | set(ENABLE_DOCS OFF) 7 | 8 | if (WIN32) 9 | # https://stackoverflow.com/questions/47690822/possible-to-force-cmake-msvc-to-use-utf-8-encoding-for-source-files-without-a-bo 10 | add_compile_options("$<$:/utf-8>") 11 | add_compile_options("$<$:/utf-8>") 12 | 13 | # https://stackoverflow.com/a/60410369 14 | set(ENV{PKG_CONFIG_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/_deps/lib/pkgconfig\;$ENV{PKG_CONFIG_PATH}") 15 | else(WIN32) 16 | set(ENV{PKG_CONFIG_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/_deps/lib/pkgconfig:$ENV{PKG_CONFIG_PATH}") 17 | endif(WIN32) 18 | 19 | # pkg-config path for dependencies 20 | include_directories("${CMAKE_CURRENT_SOURCE_DIR}/_deps/include") 21 | link_directories("${CMAKE_CURRENT_SOURCE_DIR}/_deps/lib") 22 | ############################################################################### 23 | add_subdirectory(external/libavif-container EXCLUDE_FROM_ALL) 24 | ############################################################################### 25 | # zlib 26 | set(ASM686L OFF CACHE BOOL "Enable building i686 assembly implementation" FORCE) 27 | set(ASM686 OFF CACHE BOOL "Enable building amd64 assembly implementation" FORCE) 28 | enable_language(ASM) # FIXME(ledyba-z): This line is required to generate ninja scripts. 29 | add_subdirectory(external/zlib EXCLUDE_FROM_ALL) 30 | set(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/zlib" "${CMAKE_CURRENT_BINARY_DIR}/external/zlib") 31 | set(ZLIB_ROOT "${CMAKE_BINARY_DIR}/zlib") 32 | set(ZLIB_DIR "${CMAKE_BINARY_DIR}/zlib") 33 | ############################################################################### 34 | # libpng 35 | set(SKIP_INSTALL_ALL ON CACHE BOOL "Please see external/libpng/CMakeLists.txt for detail" FORCE) 36 | 37 | set(PNG_BUILD_ZLIB ON CACHE BOOL "Custom zlib Location, else find_package is used" FORCE) 38 | set(PNG_SHARED OFF CACHE BOOL "Build shared lib" FORCE) 39 | set(PNG_STATIC ON CACHE BOOL "Build static lib" FORCE) 40 | set(PNG_TESTS OFF CACHE BOOL "Build libpng tests" FORCE) 41 | add_subdirectory(external/libpng EXCLUDE_FROM_ALL) 42 | #FIXME(ledyba-z): Workaround to include "pnglibconf.h" 43 | target_include_directories(png_static PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/external/libpng") 44 | # zlib 45 | target_link_directories(png_static PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/external/zlib") 46 | target_include_directories(png_static PRIVATE external/zlib "${CMAKE_CURRENT_BINARY_DIR}/external/zlib") 47 | target_link_libraries(png_static zlibstatic) 48 | add_dependencies(png_static zlibstatic) 49 | ############################################################################### 50 | # libaom 51 | set(ENABLE_TESTS OFF CACHE BOOL "" FORCE) 52 | set(ENABLE_EXAMPLES OFF CACHE BOOL "" FORCE) 53 | set(ENABLE_TOOLS OFF CACHE BOOL "" FORCE) 54 | # See: external/libaom/build/cmake/aom_config_defaults.cmake 55 | set(CONFIG_TUNE_VMAF 1 CACHE INTERNAL "Enable encoding tuning for VMAF." FORCE) 56 | set(CONFIG_NN_V2 1 CACHE INTERNAL "Fully-connected neural nets ver.2." FORCE) 57 | # FIXME(ledyba-z): They can be useful, but they create csv files in current dir. 58 | # It may cause some problem when encoding multiple images at parallel. 59 | #set(CONFIG_COLLECT_PARTITION_STATS 1 CACHE INTERNAL "AV1 experiment: Collect partition timing stats. Can be 1 or 2." FORCE) 60 | #set(CONFIG_PARTITION_SEARCH_ORDER 1 CACHE INTERNAL "AV1 experiment: Use alternative partition search order." FORCE) 61 | # FIXME(ledyba-z): CONFIG_DIST_8X8 conflicts with CONFIG_MULTITHREAD. 62 | # --- aom_configure: Detected CPU: x86_64 63 | # CMake Warning at external/libaom/build/cmake/util.cmake:57 (message): 64 | # --- Disabled CONFIG_DIST_8X8, incompatible with CONFIG_MULTITHREAD. 65 | # 66 | set(CONFIG_AV1_DECODER 0 CACHE STRING "Enable AV1 decoder." FORCE) 67 | add_subdirectory(external/libaom EXCLUDE_FROM_ALL) 68 | ############################################################################### 69 | 70 | add_executable(cavif 71 | src/main.cpp 72 | 73 | src/img/Conversion.hpp 74 | src/img/png/Reader.cpp 75 | src/img/png/Reader.hpp 76 | 77 | src/Config.cpp 78 | src/Config.hpp 79 | 80 | src/AVIFBuilder.cpp 81 | src/AVIFBuilder.hpp 82 | 83 | src/ext/ExternalPartitionModelFactoryContainer.cpp 84 | src/ext/ExternalPartitionModelFactoryContainer.hpp 85 | src/ext/ExternalPartitionModel.hpp 86 | 87 | src/ext/models/NonSplitPartitionModel.cpp 88 | src/ext/models/NonSplitPartitionModel.hpp 89 | ) 90 | 91 | # https://cmake.org/cmake/help/latest/manual/cmake-compile-features.7.html#requiring-language-standards 92 | # https://stackoverflow.com/questions/45688522/how-to-enable-c17-in-cmake 93 | target_compile_features(cavif PRIVATE cxx_std_17) 94 | # https://cmake.org/cmake/help/latest/prop_tgt/CXX_STANDARD.html 95 | set_property(TARGET cavif PROPERTY CXX_STANDARD 17) 96 | set_property(TARGET cavif PROPERTY CXX_STANDARD_REQUIRED ON) 97 | 98 | if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 99 | set_property(TARGET cavif PROPERTY CXX_FLAGS_DEBUG "-g3 -O0 -fno-omit-frame-pointer") 100 | endif() 101 | 102 | target_link_libraries(cavif PRIVATE aom) 103 | target_link_libraries(cavif PRIVATE png_static) 104 | target_link_libraries(cavif PRIVATE fmt::fmt) 105 | target_link_libraries(cavif PRIVATE libavif-container) 106 | target_include_directories(cavif PRIVATE external/libaom) 107 | target_include_directories(cavif PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/external/libaom") 108 | target_include_directories(cavif PRIVATE external/libavif-container/src) 109 | target_include_directories(cavif PRIVATE "${CMAKE_BINARY_DIR}/include") 110 | 111 | target_include_directories(cavif PRIVATE external/libpng) 112 | target_link_libraries(cavif PRIVATE png_static) 113 | target_link_libraries(cavif PRIVATE ${ZLIB_LDFLAGS} ${ZLIB_LIBRARIES}) 114 | if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 115 | # FIXME(ledyba-z): workaround for gcc-8 116 | target_link_libraries(cavif PRIVATE stdc++fs) 117 | endif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 118 | 119 | ############################################################################### 120 | 121 | install(TARGETS cavif 122 | RUNTIME DESTINATION bin 123 | ) 124 | 125 | install(DIRECTORY external/vmaf/model 126 | DESTINATION share/cavif 127 | ) 128 | 129 | ############################################################################### 130 | ## Testing 131 | ############################################################################### 132 | enable_testing() 133 | include(GoogleTest) 134 | add_subdirectory(external/libavif-container/external/gtest EXCLUDE_FROM_ALL) 135 | 136 | add_executable(cavif-tests 137 | test/NopTest.cpp 138 | ) 139 | target_link_libraries(cavif-tests PRIVATE gtest) 140 | target_link_libraries(cavif-tests PRIVATE gtest_main) 141 | target_include_directories(cavif-tests PRIVATE external/gtest/googletest/include) 142 | 143 | target_compile_features(cavif-tests PRIVATE cxx_std_17) 144 | set_property(TARGET cavif-tests PROPERTY CXX_STANDARD 17) 145 | set_property(TARGET cavif-tests PROPERTY CXX_STANDARD_REQUIRED ON) 146 | set_property(TARGET cavif-tests PROPERTY CXX_FLAGS_DEBUG "-g3 -O0 -fno-omit-frame-pointer") 147 | 148 | gtest_add_tests( 149 | TARGET cavif-tests 150 | #TEST_SUFFIX .noArgs 151 | TEST_LIST ALL_TESTS 152 | ) 153 | set_tests_properties(${ALL_TESTS} PROPERTIES TIMEOUT 10) 154 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019-present, Link-U Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cavif 2 | 3 | **Sorry, this repository is no longer maintained due to the retirement of the main maintainer. After some time, this repository will be archived.** 4 | 5 | **Ther source is currently maitained on avif-community by the maintaier. It's not a official community of AVIF codec. We take no resposibility the name of the community.** 6 | 7 | **This repository will be removed after 2023-01-31 to resolve the confusing situation.** 8 | 9 | | | Status | 10 | |--|---| 11 | | Linux | [![Build on Linux](https://github.com/link-u/cavif/workflows/Build%20on%20Linux/badge.svg) ](https://github.com/link-u/cavif/actions?query=workflow%3A%22Build+on+Linux%22) | 12 | | Linux(.deb) | [![Build debian packages](https://github.com/link-u/cavif/workflows/Build%20debian%20packages/badge.svg)](https://github.com/link-u/cavif/actions?query=workflow%3A%22Build+debian+packages%22) | 13 | | macOS | [![Build on macOS](https://github.com/link-u/cavif/workflows/Build%20on%20macOS/badge.svg)](https://github.com/link-u/cavif/actions?query=workflow%3A%22Build+on+macOS%22) | 14 | | Windows | [![Build on Windows](https://github.com/link-u/cavif/workflows/Build%20on%20Windows/badge.svg)](https://github.com/link-u/cavif/actions?query=workflow%3A%22Build+on+Windows%22) | 15 | 16 | ## Description (en) 17 | 18 | avif encoder, using [libaom](https://aomedia.googlesource.com/aom/) directly. 19 | 20 | [avif (AV1 Image File Format)](https://aomediacodec.github.io/av1-avif/) is a still picture format uses a keyframe of [AV1](https://aomediacodec.github.io/av1-spec/av1-spec.pdf). 21 | 22 | The most significant mission of this project is "**Make it enable to tune libaom's all encoding options to optimize quality/size ratio as nice as possible human beings can**". 23 | 24 | ## Description (ja) 25 | 26 | [AVIF(AV1 Image File Format)]((https://aomediacodec.github.io/av1-avif/))は、動画フォーマットである[AV1](https://aomediacodec.github.io/av1-spec/av1-spec.pdf)のキーフレームを流用して圧縮する静止画フォーマットです。 27 | 28 | cavifは、ラッパーを介さず [libaom](https://aomedia.googlesource.com/aom/) を直接叩くavifのエンコーディング・コマンドです。このプロジェクトの唯一にして最大の使命は、 **libaomの静止画に関する全エンコードオプションを仔細に操作できるようにして、現生人類が現時点で達成可能な最高の圧縮効率を実現する手段を提供すること** です。 29 | 30 | [日本語の詳しいドキュメントはこちら](./doc/ja_JP/README.md)。 31 | 32 | # How to build 33 | 34 | ## Pre-requirements 35 | 36 | ### cmake >= 3.13 37 | 38 | If your system cmake is lower than 3.13, please install the latest version: 39 | 40 | To install: 41 | 42 | - Ubuntu/Debian 43 | - See https://apt.kitware.com/ 44 | - Windows 45 | - [Download | CMake](https://cmake.org/download/) 46 | - [mingw-w64-cmake - MSYS2 Packages](https://packages.msys2.org/base/mingw-w64-cmake) 47 | - mac OS 48 | - `brew install cmake` 49 | 50 | ### latest version of meson and ninja 51 | 52 | meson and ninja are required to build libvmaf. 53 | 54 | Please see: https://mesonbuild.com/Quick-guide.html 55 | 56 | Or another method: You can use python's venv to install. [See our CI about details](https://github.com/link-u/cavif/blob/master/.github/workflows/build-on-linux.yml). 57 | 58 | ## Build steps 59 | 60 | ```bash 61 | # cloning this repository with dependencies. 62 | git clone --recurse-submodules --recursive https://github.com/link-u/cavif 63 | 64 | cd cavif 65 | 66 | # Apply workarounds 67 | bash scripts/apply-patches.sh 68 | 69 | # Build dependencies not managed by CMake. 70 | bash scripts/build-deps.sh 71 | 72 | # Make build directory 73 | mkdir build && cd build 74 | 75 | # If your system gcc is 8.0 or higher: 76 | cmake -G 'Ninja' .. 77 | 78 | # If not, please install gcc-8 (or higher) and tell them to CMake. 79 | CXX=g++-8 CC=gcc-8 cmake -G 'Ninja' .. 80 | 81 | # build and get cavif binary! 82 | ninja 83 | ``` 84 | 85 | # Usage 86 | 87 | ## basic usage 88 | 89 | ```bash 90 | cavif -i -o 91 | ``` 92 | 93 | Example avif files are available in [AOMediaCodec/av1-avif](https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles) or [link-u/avif-sample-images](https://github.com/link-u/avif-sample-images). 94 | 95 | (Currently, detailed documentation is only in [Japanese](./doc/ja_JP/README.md)) 96 | 97 | ## basic usage (alpha) 98 | 99 | You have to encode alpha plane separately(Of course, it's to achieve best image quality!). 100 | 101 | ```bash 102 | cavif -i -o --encode-target alpha --monochrome 103 | cavif -i -o --encode-target image --attach-alpha 104 | ``` 105 | 106 | ## SYNOPSIS 107 | 108 | ``` 109 | [2022/03/26 11:57:21 INFO ] cavif 110 | [2022/03/26 11:57:21 INFO ] libaom ver: 3.3.0 111 | [2022/03/26 11:57:21 INFO ] libpng ver:1.6.38.git 112 | SYNOPSIS 113 | cavif -i -o [--attach-alpha ] [--attach-depth 114 | ] [--encode-target [image|alpha]] [--show-result] [--rotation 115 | [0|90|180|270]] [--mirror [vertical|horizontal]] [--crop-size ] 116 | [--crop-offset ] [--full-still-picture-header] 117 | [--color-primaries (|bt709|sRGB|sYCC|unspecified|bt470m|bt470bg|bt601|ntsc|smpte240m|generic-film|bt2020|bt2100|smpte428|xyz|smpte431|smpte432|22)] 119 | [--transfer-characteristics (|bt709|unspecified|bt470m|bt470bg|bt601|ntsc|smpte240m|linear|log100|log100sqrt10|iec61966|bt1361|sRGB|sYCC|bt2020|bt2020-10bit|bt2020-12bit|smpte2084|bt2100pq|smpte428|bt2100hlg|arib-b67)] 121 | [--matrix-coefficients (|bt709|sRGB|unspecified|us-fcc|bt470bg|sYCC|bt601|ntsc|smpte240m|bt2020)] 123 | [--horizontal-scale-mode [1/1|1/2|3/5|4/5|1/4|3/4|1/8]] [--vertical-scale-mode 124 | [1/1|1/2|3/5|4/5|1/4|3/4|1/8]] [--resize-mode [none|fixed|random]] 125 | [--resize-denominator_ <[8-16], default=8>] [--superres-mode 126 | [none|fixed|random|qthresh|auto]] [--superres-denominator_ <[8-16], default=8>] 127 | [--superres-qthresh <[0-63], default=63 (Do not apply superres filter)>] 128 | [--render-width <>] [--render-height <>] [--profile 129 | <0=base(default), 1=high, 2=professional>] [--pix-fmt [yuv420|yuv422|yuv444]] 130 | [--bit-depth [8|10|12]] [--disable-full-color-range] [--enable-full-color-range] 131 | [--encoder-usage [good|realtime]] [--threads ] [--enable-row-mt] [--disable-row-mt] [--cpu-used <0-9, default=1. 133 | Higher means slower encoding and better quality>] [--rate-control [cbr|q|cq]] 134 | [--bit-rate ] [--crf <0-63(default=10)>] [--qmin 135 | <0-63(default=0)>] [--qmax <0-63(default=63)>] [--adaptive-quantization 136 | [none|variance|complexity|cyclic]] [--enable-adaptive-quantization-b] 137 | [--disable-adaptive-quantization-b] [--delta-q [none|objective|perceptual]] 138 | [--delta-q-strength] [--enable-chroma-delta-q] [--disable-chroma-delta-q] 139 | [--enable-loop-filter] [--disable-loop-filter] [--enable-delta-lf] 140 | [--disable-delta-lf] [--use-qm] [--qm-min <0-15 (default: 5)>] [--qm-max <0-15 141 | (default: 9)>] [--qm-min-y <0-15 (default: 10)>] [--qm-min-u <0-15 (default: 11)>] 142 | [--qm-min-v <0-15 (default: 12)>] [--tune 143 | [ssim|psnr|vmaf-with-preprocessing|vmaf-without-preprocessing|vmaf-max-gain|vmaf-neg-max-gain]] 144 | [--content-type [default|screen|film]] [--vmaf-model-path <>] 145 | [--lossless] [--monochrome] [--sharpness <0-7>] [--disable-cdef] [--enable-cdef] 146 | [--disable-loop-restoration] [--enable-loop-restoration] [--superblock-size 147 | [dynamic|128|64]] [--tile-rows <0-6>] [--tile-columns <0-6>] 148 | [--keyframe-temporal-filter [disable|without-overlay|with-overlay]] 149 | [--enable-rect-partitions] [--disable-rect-partitions] [--enable-ab-partitions] 150 | [--disable-ab-partitions] [--disable-1to4-partitions] [--enable-1to4-partitions] 151 | [--enable-intra-edge-filter] [--disable-intra-edge-filter] [--min-partition-size 152 | [4|8|16|32|64|128]] [--max-partition-size [4|8|16|32|64|128]] [--enable-tx64] 153 | [--disable-tx64] [--enable-flip-idtx] [--disable-flip-idtx] [--enable-rect-tx] 154 | [--disable-rect-tx] [--use-dct-only] [--use-default-tx-only] [--use-reduced-tx-set] 155 | [--enable-filter-intra] [--disable-filter-intra] [--enable-smooth-intra] 156 | [--disable-smooth-intra] [--enable-paeth-intra] [--disable-paeth-intra] 157 | [--enable-chroma-from-luma] [--disable-chroma-from-luma] [--enable-superres] 158 | [--disable-superres] [--enable-palette] [--disable-palette] [--enable-intrabc] 159 | [--disable-intrabc] [--enable-angle-delta] [--disable-angle-delta] 160 | [--enable-diagonal-intra] [--disable-diagonal-intra] [--enable-directional-intra] 161 | [--disable-directional-intra] [--enable-tx-size-search] [--disable-tx-size-search] 162 | 163 | cavif -h 164 | 165 | OPTIONS 166 | -i, --input Filename to input 167 | -o, --output 168 | Filename to output 169 | 170 | --attach-alpha 171 | Attach alpha plane 172 | 173 | --attach-depth 174 | Attach depth plane 175 | 176 | --encode-target 177 | Encode target 178 | 179 | image Encode image planes (default) 180 | alpha Encode an alpha plane 181 | --show-result 182 | Show encoding result 183 | 184 | --rotation Set rotation meta data(irot). Counter-clockwise. 185 | --mirror Set mirror meta data(imir). 186 | --crop-size Set crop size. 187 | --crop-offset 188 | Set crop offset. 189 | 190 | --full-still-picture-header 191 | Force to output full picture header 192 | 193 | --color-primaries 194 | Set color primaries information value. 195 | 196 | 197 | See https://www.itu.int/rec/T-REC-H.273-201612-I/en 198 | 199 | bt709 Rec. ITU-R BT.709-6 200 | sRGB IEC 61966-2-1 sRGB or sYCC 201 | sYCC IEC 61966-2-1 sRGB or sYCC 202 | unspecified Image characteristics are unknown or are determined by the application. 203 | bt470m Rec. ITU-R BT.470-6 System M (historical) 204 | bt470bg Rec. ITU-R BT.470-6 System B, G (historical) 205 | bt601 Rec. ITU-R BT.601-7 625 206 | ntsc Rec. ITU-R BT.1700-0 NTSC 207 | smpte240m SMPTE ST 240 (1999) 208 | generic-film 209 | Generic film (colour filters using Illuminant C) 210 | 211 | bt2020 Rec. ITU-R BT.2020-2 212 | bt2100 Rec. ITU-R BT.2100-0 213 | smpte428 SMPTE ST 428-1 214 | xyz (CIE 1931 XYZ as in ISO 11664-1) 215 | smpte431 SMPTE RP 431-2 (2011) 216 | smpte432 SMPTE EG 432-1 (2010) 217 | 22 No corresponding industry specification identified 218 | --transfer-characteristics 219 | Set transfer characteristics information value. 220 | 221 | 222 | See https://www.itu.int/rec/T-REC-H.273-201612-I/en 223 | 224 | bt709 Rec. ITU-R BT.709-6 225 | unspecified Image characteristics are unknown or are determined by the application. 226 | bt470m Rec. ITU-R BT.470-6 System M (historical) 227 | bt470bg Rec. ITU-R BT.470-6 System B, G (historical) 228 | bt601 Rec. ITU-R BT.1700-0 NTSC 229 | ntsc Rec. ITU-R BT.1700-0 NTSC 230 | smpte240m SMPTE 240M (1999) (historical) 231 | linear Linear transfer characteristics 232 | log100 Logarithmic transfer characteristic (100:1 range) 233 | log100sqrt10 234 | Logarithmic transfer characteristic (100 * Sqrt( 10 ) : 1 range) 235 | 236 | iec61966 IEC 61966-2-4 237 | bt1361 Rec. ITU-R BT.1361-0 extended colour gamut system (historical) 238 | sRGB IEC 61966-2-1 sRGB or sYCC 239 | sYCC IEC 61966-2-1 sRGB or sYCC 240 | bt2020 Rec. ITU-R BT.2020-2 (10-bit system) 241 | bt2020-10bit 242 | Rec. ITU-R BT.2020-2 (10-bit system) 243 | 244 | bt2020-12bit 245 | Rec. ITU-R BT.2020-2 (12-bit system) 246 | 247 | smpte2084 SMPTE ST 2084 for 10-, 12-, 14- and 16-bit systems 248 | bt2100pq Rec. ITU-R BT.2100-0 perceptual quantization (PQ) system 249 | smpte428 SMPTE ST 428-1 250 | bt2100hlg Rec. ITU-R BT.2100-0 hybrid log-gamma (HLG) system 251 | arib-b67 ARIB STD-B67 252 | --matrix-coefficients 253 | Set matrix coefficients information value. 254 | 255 | 256 | See https://www.itu.int/rec/T-REC-H.273-201612-I/en 257 | 258 | bt709 Rec. ITU-R BT.709-6 (default) 259 | sRGB IEC 61966-2-1 sRGB or sYCC (default) 260 | unspecified Image characteristics are unknown or are determined by the application 261 | us-fcc United States Federal Communications Commission (2003) 262 | bt470bg Rec. ITU-R BT.470-6 System B, G (historical) 263 | sYCC IEC 61966-2-1 sRGB or sYCC 264 | bt601 Rec. ITU-R BT.601-7 625 265 | ntsc Rec. ITU-R BT.1700-0 NTSC 266 | smpte240m SMPTE 240M 267 | bt2020 Rec. ITU-R BT.2020-2 (non-constant luminance) 268 | --horizontal-scale-mode 269 | Set horizontal scale mode 270 | 271 | 1/1 Do not scale (default) 272 | 1/2 Scale to 1/2 273 | 3/5 Scale to 3/5 274 | 4/5 Scale to 4/5 275 | 1/4 Scale to 1/4 276 | 3/4 Scale to 3/4 277 | 1/8 Scale to 1/8 278 | --vertical-scale-mode 279 | Set vertical scale mode 280 | 281 | 1/1 Do not scale (default) 282 | 1/2 Scale to 1/2 283 | 3/5 Scale to 3/5 284 | 4/5 Scale to 4/5 285 | 1/4 Scale to 1/4 286 | 3/4 Scale to 3/4 287 | 1/8 Scale to 1/8 288 | --resize-mode 289 | Set resize mode 290 | 291 | none Do not resize 292 | fixed Resize image using a denominator_ given by `--resize-denominator_` arg 293 | random Resize image randomly! 294 | --resize-denominator_ 295 | Set resize denominator_. 296 | 297 | --superres-mode 298 | Set superres mode 299 | 300 | none Do not use superres mode 301 | fixed Apply superres filter to image using a denominator_ given by 302 | `--superres-denominator_` arg 303 | 304 | random Apply superres filter to image with a random denominator_! 305 | qthresh Apply or do not apply superres filter to image based on the q index 306 | auto Apply or do not apply superres filter to image automatically 307 | --superres-denominator_ 308 | Set superres resize denominator_. 309 | 310 | --superres-qthresh 311 | Set q level threshold for superres. 312 | 313 | --render-width 314 | Set render width explicitly 315 | 316 | --render-height 317 | Set render height explicitly 318 | 319 | --profile AV1 Profile(0=base, 1=high, 2=professional) 320 | --pix-fmt Pixel format of output image 321 | yuv420 YUV420 format (default) 322 | yuv422 YUV422 format 323 | yuv444 YUV444 format (recommended for lossless images) 324 | --bit-depth Bit depth of output image 325 | 8 8bits per color, 24bits per pixel (default) 326 | 10 10bits per color, 30bits per pixel 327 | 12 12bits per color, 36bits per pixel 328 | --disable-full-color-range 329 | Use limited YUV color range (default) 330 | 331 | --enable-full-color-range 332 | Use full YUV color range 333 | 334 | --encoder-usage 335 | Encoder usage 336 | 337 | good Good Quality mode (default) 338 | realtime Real time encoding mode 339 | --enable-row-mt 340 | Enable row based multi-threading of encoder 341 | 342 | --disable-row-mt 343 | Disable row based multi-threading of encoder (default) 344 | 345 | --cpu-used Quality/Speed ratio modifier 346 | --rate-control 347 | Rate control method 348 | 349 | cbr Constant Bit Rate mode. Please also set `--bit-rate` arg. 350 | q Constant Quality (default) 351 | cq Constrained Quality 352 | --bit-rate Bit rate of output image. 353 | --crf CQ Level in CQ rate control mode 354 | --qmin Minimum (Best Quality) Quantizer 355 | --qmax Maximum (Worst Quality) Quantizer 356 | --adaptive-quantization 357 | Set adaptive-quantization mode 358 | 359 | none none(default) 360 | variance variance based 361 | complexity complexity based 362 | cyclic Cyclic refresh 363 | --enable-adaptive-quantization-b 364 | use adaptive quantize_b 365 | 366 | --disable-adaptive-quantization-b 367 | use traditional adaptive quantization (default) 368 | 369 | --delta-q a mode of delta q mode feature, that allows modulating q per superblock 370 | none disable deltaQ 371 | objective Use modulation to maximize objective quality 372 | perceptual Use modulation to maximize perceptual quality 373 | --delta-q-strength 374 | strength of deltaQ [0..1000] (default = 100) 375 | 376 | --enable-chroma-delta-q 377 | enable delta quantization in chroma 378 | 379 | --disable-chroma-delta-q 380 | disable delta quantization in chroma 381 | 382 | --enable-loop-filter 383 | enable loop filter (default) 384 | 385 | --disable-loop-filter 386 | disable loop filter 387 | 388 | --enable-delta-lf 389 | enable delta loop filter 390 | 391 | --disable-delta-lf 392 | disable delta loop filter (default) 393 | 394 | --use-qm Use QMatrix 395 | --qm-min Min quant matrix flatness 396 | --qm-max Max quant matrix flatness 397 | --qm-min-y Min quant matrix flatness for Y 398 | --qm-min-u Min quant matrix flatness for U 399 | --qm-min-v Min quant matrix flatness for V 400 | --tune Quality metric to tune 401 | ssim SSIM(structural similarity) 402 | psnr PSNR(peak signal-to-noise ratio) 403 | vmaf-with-preprocessing 404 | vmaf-with-preprocessing 405 | 406 | vmaf-without-preprocessing 407 | vmaf-without-preprocessing 408 | 409 | vmaf-max-gain 410 | vmaf-max-gain 411 | 412 | vmaf-neg-max-gain 413 | vmaf-neg-max-gain 414 | 415 | --content-type 416 | Content type 417 | 418 | default Regular video content (default) 419 | screen Screen capture content 420 | film Film content 421 | --vmaf-model-path 422 | VMAF model file path to tuning image quality 423 | 424 | --lossless Enable lossless encoding 425 | --monochrome 426 | Encode to monochrome image 427 | 428 | --sharpness Sharpening output 429 | --disable-cdef 430 | Disable Constrained Directional Enhancement Filter (default) 431 | 432 | --enable-cdef 433 | Enable Constrained Directional Enhancement Filter 434 | 435 | --disable-loop-restoration 436 | Disable Loop Restoration Filter (default) 437 | 438 | --enable-loop-restoration 439 | Enable Loop Restoration Filter 440 | 441 | --superblock-size 442 | Superblock size. 443 | 444 | dynamic encoder determines the size automatically. 445 | 128 use 128x128 superblock. 446 | 64 use 64x64 superblock. 447 | --tile-rows Number of tile rows 448 | --tile-columns 449 | Number of tile columns 450 | 451 | --keyframe-temporal-filter 452 | Enable temporal filtering on key frame 453 | 454 | --enable-rect-partitions 455 | enable rectangular partitions (default) 456 | 457 | --disable-rect-partitions 458 | disable rectangular partitions 459 | 460 | --enable-ab-partitions 461 | enable ab partitions (default) 462 | 463 | --disable-ab-partitions 464 | disable ab partitions 465 | 466 | --disable-1to4-partitions 467 | enable 1to4 partitions (default) 468 | 469 | --enable-1to4-partitions 470 | disable 1to4 partitions 471 | 472 | --enable-intra-edge-filter 473 | enable intra edge filter (default) 474 | 475 | --disable-intra-edge-filter 476 | disable intra edge filter 477 | 478 | --min-partition-size 479 | min partition size 480 | 481 | --max-partition-size 482 | max partition size 483 | 484 | --enable-tx64 485 | enable 64-length transforms (default) 486 | 487 | --disable-tx64 488 | disable 64-length transforms 489 | 490 | --enable-flip-idtx 491 | enable flip and identity transforms (default) 492 | 493 | --disable-flip-idtx 494 | disable flip and identity transforms 495 | 496 | --enable-rect-tx 497 | enable rectangular transforms (default) 498 | 499 | --disable-rect-tx 500 | disable rectangular transforms 501 | 502 | --use-dct-only 503 | Use DCT tx onlyq 504 | 505 | --use-default-tx-only 506 | use default tx type only 507 | 508 | --use-reduced-tx-set 509 | use reduced tx set, transforms w/o flip (4) + Identity (1). 510 | 511 | --enable-filter-intra 512 | enable (default) 513 | 514 | --disable-filter-intra 515 | disable 516 | 517 | --enable-smooth-intra 518 | enable (default) 519 | 520 | --disable-smooth-intra 521 | disable 522 | 523 | --enable-paeth-intra 524 | enable (default) 525 | 526 | --disable-paeth-intra 527 | disable 528 | 529 | --enable-chroma-from-luma 530 | enable (default) 531 | 532 | --disable-chroma-from-luma 533 | disable 534 | 535 | --enable-superres 536 | enable frame superresolution (default) 537 | 538 | --disable-superres 539 | disable frame superresolution 540 | 541 | --enable-palette 542 | enable palette mode 543 | 544 | --disable-palette 545 | disable palette mode (default) 546 | 547 | --enable-intrabc 548 | enable intra block copy mode (default) 549 | 550 | --disable-intrabc 551 | disable intra block copy mode 552 | 553 | --enable-angle-delta 554 | enable intra angle delta (default) 555 | 556 | --disable-angle-delta 557 | disable intra angle delta 558 | 559 | --enable-diagonal-intra 560 | enable usage of D45 to D203 intra modes (default) 561 | 562 | --disable-diagonal-intra 563 | disable usage of D45 to D203 intra modes 564 | 565 | --enable-directional-intra 566 | turn on directional intra mode (default) 567 | 568 | --disable-directional-intra 569 | turn off directional intra mode 570 | 571 | --enable-tx-size-search 572 | turn on transform size search (default). Transforms always have the largest 573 | possible size 574 | 575 | --disable-tx-size-search 576 | turn off transform size search. Search for the best transform size for each 577 | block 578 | 579 | -h, --help Show help and exit. 580 | ``` 581 | 582 | ## TODO 583 | 584 | - Thumbnail 585 | - Improve default configs 586 | - Add more and more command-line flags. 587 | 588 | # Related repositories 589 | 590 | - [link-u/davif](https://github.com/link-u/davif) - avif decoder, using dav1d directly. 591 | - [link-u/libavif-container](https://github.com/link-u/libavif-container) - a library to parse avif container. 592 | - [link-u/avif-sample-images](https://github.com/link-u/avif-sample-images) - sample images from us. 593 | -------------------------------------------------------------------------------- /debian/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .debhelper 3 | files 4 | *.debhelper 5 | *.deb 6 | *.dsc 7 | *.build 8 | *.buildinfo 9 | *.changes 10 | *.tar.gz 11 | *.log 12 | *.substvars 13 | 14 | */ 15 | !source/ 16 | debhelper-build-stamp 17 | -------------------------------------------------------------------------------- /debian/README.Debian: -------------------------------------------------------------------------------- 1 | cavif for Debian 2 | --------------- 3 | 4 | 5 | 6 | -- Ryo Hirafuji Sat, 25 Jan 2020 20:03:30 +0900 7 | -------------------------------------------------------------------------------- /debian/README.source: -------------------------------------------------------------------------------- 1 | cavif for Debian 2 | --------------- 3 | 4 | 6 | 7 | 8 | 9 | -- Ryo Hirafuji Sat, 25 Jan 2020 20:03:30 +0900 10 | 11 | -------------------------------------------------------------------------------- /debian/cavif-docs.docs: -------------------------------------------------------------------------------- 1 | README.source 2 | README.Debian 3 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | cavif (0.1.0) unstable; urgency=medium 2 | 3 | * Please see https://github.com/link-u/cavif/releases for more information! 4 | 5 | -- Ryo Hirafuji Sat, 27 Jan 2020 12:45:30 +0900 6 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 10 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: cavif 2 | Section: unknown 3 | Priority: optional 4 | Maintainer: Ryo Hirafuji 5 | Build-Depends: debhelper (>= 10), cmake (>= 3.21), pkg-config, gcc-9, g++-9, libc6-dev, libstdc++-9-dev, yasm, nasm 6 | Standards-Version: 4.1.2 7 | Homepage: https://github.com/link-u/cavif 8 | Vcs-Git: https://github.com/link-u/cavif.git 9 | Vcs-Browser: https://github.com/link-u/cavif 10 | 11 | Package: cavif 12 | Architecture: any 13 | Depends: ${shlibs:Depends}, ${misc:Depends} 14 | Description: avif encoder, using libaom directly. 15 | The most significant mission of this project is 16 | "Make it enable to tune libaom's all encoding options to optimize 17 | quality/size ratio as nice as possible human beings can". 18 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: cavif 3 | Source: https://github.com/link-u/cavif 4 | 5 | Files: * 6 | Copyright: 2019-present, Ryo Hirafuji at Link-U Inc. 7 | License: MIT 8 | The MIT License (MIT) 9 | 10 | Copyright (c) 2019-present, Link-U Inc. 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining a copy 13 | of this software and associated documentation files (the "Software"), to deal 14 | in the Software without restriction, including without limitation the rights 15 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | copies of the Software, and to permit persons to whom the Software is 17 | furnished to do so, subject to the following conditions: 18 | 19 | The above copyright notice and this permission notice shall be included in 20 | all copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | THE SOFTWARE. 29 | -------------------------------------------------------------------------------- /debian/manpage.1.ex: -------------------------------------------------------------------------------- 1 | .\" Hey, EMACS: -*- nroff -*- 2 | .\" (C) Copyright 2020 Ryo Hirafuji , 3 | .\" 4 | .\" First parameter, NAME, should be all caps 5 | .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection 6 | .\" other parameters are allowed: see man(7), man(1) 7 | .TH Cavif SECTION "January 25 2020" 8 | .\" Please adjust this date whenever revising the manpage. 9 | .\" 10 | .\" Some roff macros, for reference: 11 | .\" .nh disable hyphenation 12 | .\" .hy enable hyphenation 13 | .\" .ad l left justify 14 | .\" .ad b justify to both left and right margins 15 | .\" .nf disable filling 16 | .\" .fi enable filling 17 | .\" .br insert line break 18 | .\" .sp insert n+1 empty lines 19 | .\" for manpage-specific macros, see man(7) 20 | .SH NAME 21 | cavif \- program to do something 22 | .SH SYNOPSIS 23 | .B cavif 24 | .RI [ options ] " files" ... 25 | .br 26 | .B bar 27 | .RI [ options ] " files" ... 28 | .SH DESCRIPTION 29 | This manual page documents briefly the 30 | .B cavif 31 | and 32 | .B bar 33 | commands. 34 | .PP 35 | .\" TeX users may be more comfortable with the \fB\fP and 36 | .\" \fI\fP escape sequences to invode bold face and italics, 37 | .\" respectively. 38 | \fBcavif\fP is a program that... 39 | .SH OPTIONS 40 | These programs follow the usual GNU command line syntax, with long 41 | options starting with two dashes (`-'). 42 | A summary of options is included below. 43 | For a complete description, see the Info files. 44 | .TP 45 | .B \-h, \-\-help 46 | Show summary of options. 47 | .TP 48 | .B \-v, \-\-version 49 | Show version of program. 50 | .SH SEE ALSO 51 | .BR bar (1), 52 | .BR baz (1). 53 | .br 54 | The programs are documented fully by 55 | .IR "The Rise and Fall of a Fooish Bar" , 56 | available via the Info system. 57 | -------------------------------------------------------------------------------- /debian/manpage.sgml.ex: -------------------------------------------------------------------------------- 1 | manpage.1'. You may view 5 | the manual page with: `docbook-to-man manpage.sgml | nroff -man | 6 | less'. A typical entry in a Makefile or Makefile.am is: 7 | 8 | manpage.1: manpage.sgml 9 | docbook-to-man $< > $@ 10 | 11 | 12 | The docbook-to-man binary is found in the docbook-to-man package. 13 | Please remember that if you create the nroff version in one of the 14 | debian/rules file targets (such as build), you will need to include 15 | docbook-to-man in your Build-Depends control field. 16 | 17 | --> 18 | 19 | 20 | FIRSTNAME"> 21 | SURNAME"> 22 | 23 | January 25 2020"> 24 | 26 | SECTION"> 27 | ryo.hirafuji@link-u.co.jp"> 28 | 29 | Cavif"> 30 | 31 | 32 | Debian"> 33 | GNU"> 34 | GPL"> 35 | ]> 36 | 37 | 38 | 39 |
40 | &dhemail; 41 |
42 | 43 | &dhfirstname; 44 | &dhsurname; 45 | 46 | 47 | 2003 48 | &dhusername; 49 | 50 | &dhdate; 51 |
52 | 53 | &dhucpackage; 54 | 55 | &dhsection; 56 | 57 | 58 | &dhpackage; 59 | 60 | program to do something 61 | 62 | 63 | 64 | &dhpackage; 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | DESCRIPTION 73 | 74 | This manual page documents briefly the 75 | &dhpackage; and bar 76 | commands. 77 | 78 | This manual page was written for the &debian; distribution 79 | because the original program does not have a manual page. 80 | Instead, it has documentation in the &gnu; 81 | Info format; see below. 82 | 83 | &dhpackage; is a program that... 84 | 85 | 86 | 87 | OPTIONS 88 | 89 | These programs follow the usual &gnu; command line syntax, 90 | with long options starting with two dashes (`-'). A summary of 91 | options is included below. For a complete description, see the 92 | Info files. 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | Show summary of options. 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | Show version of program. 109 | 110 | 111 | 112 | 113 | 114 | SEE ALSO 115 | 116 | bar (1), baz (1). 117 | 118 | The programs are documented fully by The Rise and 119 | Fall of a Fooish Bar available via the 120 | Info system. 121 | 122 | 123 | AUTHOR 124 | 125 | This manual page was written by &dhusername; &dhemail; for 126 | the &debian; system (and may be used by others). Permission is 127 | granted to copy, distribute and/or modify this document under 128 | the terms of the &gnu; General Public License, Version 2 any 129 | later version published by the Free Software Foundation. 130 | 131 | 132 | On Debian systems, the complete text of the GNU General Public 133 | License can be found in /usr/share/common-licenses/GPL. 134 | 135 | 136 | 137 |
138 | 139 | 155 | -------------------------------------------------------------------------------- /debian/manpage.xml.ex: -------------------------------------------------------------------------------- 1 | 2 | .
will be generated. You may view the 15 | manual page with: nroff -man .
| less'. A typical entry 16 | in a Makefile or Makefile.am is: 17 | 18 | DB2MAN = /usr/share/sgml/docbook/stylesheet/xsl/docbook-xsl/manpages/docbook.xsl 19 | XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0" 20 | 21 | manpage.1: manpage.xml 22 | $(XP) $(DB2MAN) $< 23 | 24 | The xsltproc binary is found in the xsltproc package. The XSL files are in 25 | docbook-xsl. A description of the parameters you can use can be found in the 26 | docbook-xsl-doc-* packages. Please remember that if you create the nroff 27 | version in one of the debian/rules file targets (such as build), you will need 28 | to include xsltproc and docbook-xsl in your Build-Depends control field. 29 | Alternatively use the xmlto command/package. That will also automatically 30 | pull in xsltproc and docbook-xsl. 31 | 32 | Notes for using docbook2x: docbook2x-man does not automatically create the 33 | AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as 34 | ... . 35 | 36 | To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections 37 | read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be 38 | found in the docbook-xsl-doc-html package. 39 | 40 | Validation can be done using: `xmllint -''-noout -''-valid manpage.xml` 41 | 42 | General documentation about man-pages and man-page-formatting: 43 | man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/ 44 | 45 | --> 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 56 | 57 | 59 | 60 | 61 | 62 | ]> 63 | 64 | 65 | 66 | &dhtitle; 67 | &dhpackage; 68 | 69 | 70 | &dhfirstname; 71 | &dhsurname; 72 | Wrote this manpage for the Debian system. 73 |
74 | &dhemail; 75 |
76 |
77 |
78 | 79 | 2007 80 | &dhusername; 81 | 82 | 83 | This manual page was written for the Debian system 84 | (and may be used by others). 85 | Permission is granted to copy, distribute and/or modify this 86 | document under the terms of the GNU General Public License, 87 | Version 2 or (at your option) any later version published by 88 | the Free Software Foundation. 89 | On Debian systems, the complete text of the GNU General Public 90 | License can be found in 91 | /usr/share/common-licenses/GPL. 92 | 93 |
94 | 95 | &dhucpackage; 96 | &dhsection; 97 | 98 | 99 | &dhpackage; 100 | program to do something 101 | 102 | 103 | 104 | &dhpackage; 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | this 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | this 122 | that 123 | 124 | 125 | 126 | 127 | &dhpackage; 128 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | DESCRIPTION 148 | This manual page documents briefly the 149 | &dhpackage; and bar 150 | commands. 151 | This manual page was written for the Debian distribution 152 | because the original program does not have a manual page. 153 | Instead, it has documentation in the GNU 154 | info 155 | 1 156 | format; see below. 157 | &dhpackage; is a program that... 158 | 159 | 160 | OPTIONS 161 | The program follows the usual GNU command line syntax, 162 | with long options starting with two dashes (`-'). A summary of 163 | options is included below. For a complete description, see the 164 | 165 | info 166 | 1 167 | files. 168 | 169 | 172 | 173 | 174 | 175 | 176 | Does this and that. 177 | 178 | 179 | 180 | 181 | 182 | 183 | Show summary of options. 184 | 185 | 186 | 187 | 188 | 189 | 190 | Show version of program. 191 | 192 | 193 | 194 | 195 | 196 | FILES 197 | 198 | 199 | /etc/foo.conf 200 | 201 | The system-wide configuration file to control the 202 | behaviour of &dhpackage;. See 203 | 204 | foo.conf 205 | 5 206 | for further details. 207 | 208 | 209 | 210 | ${HOME}/.foo.conf 211 | 212 | The per-user configuration file to control the 213 | behaviour of &dhpackage;. See 214 | 215 | foo.conf 216 | 5 217 | for further details. 218 | 219 | 220 | 221 | 222 | 223 | ENVIRONMENT 224 | 225 | 226 | FOO_CONF 227 | 228 | If used, the defined file is used as configuration 229 | file (see also ). 230 | 231 | 232 | 233 | 234 | 235 | DIAGNOSTICS 236 | The following diagnostics may be issued 237 | on stderr: 238 | 239 | 240 | Bad configuration file. Exiting. 241 | 242 | The configuration file seems to contain a broken configuration 243 | line. Use the option, to get more info. 244 | 245 | 246 | 247 | 248 | &dhpackage; provides some return codes, that can 249 | be used in scripts: 250 | 251 | Code 252 | Diagnostic 253 | 254 | 0 255 | Program exited successfully. 256 | 257 | 258 | 1 259 | The configuration file seems to be broken. 260 | 261 | 262 | 263 | 264 | 265 | BUGS 266 | The program is currently limited to only work 267 | with the foobar library. 268 | The upstreams BTS can be found 269 | at . 270 | 271 | 272 | SEE ALSO 273 | 274 | 275 | bar 276 | 1 277 | , 278 | baz 279 | 1 280 | , 281 | foo.conf 282 | 5 283 | 284 | The programs are documented fully by The Rise and 285 | Fall of a Fooish Bar available via the 286 | info 287 | 1 288 | system. 289 | 290 |
291 | 292 | -------------------------------------------------------------------------------- /debian/menu.ex: -------------------------------------------------------------------------------- 1 | ?package(cavif):needs="X11|text|vc|wm" section="Applications/see-menu-manual"\ 2 | title="cavif" command="/usr/bin/cavif" 3 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # See debhelper(7) (uncomment to enable) 3 | # output every command that modifies files on the build system. 4 | export DH_VERBOSE = 1 5 | 6 | 7 | # see FEATURE AREAS in dpkg-buildflags(1) 8 | #export DEB_BUILD_MAINT_OPTIONS = hardening=+all 9 | 10 | # see ENVIRONMENT in dpkg-buildflags(1) 11 | # package maintainers to append CFLAGS 12 | #export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic 13 | # package maintainers to append LDFLAGS 14 | #export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed 15 | 16 | 17 | %: 18 | dh $@ --builddirectory=build 19 | 20 | 21 | # dh_make generated override targets 22 | # This is example for Cmake (See https://bugs.debian.org/641051 ) 23 | #override_dh_auto_configure: 24 | # dh_auto_configure -- # -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) 25 | override_dh_auto_configure: 26 | dh_auto_configure -- 27 | override_dh_builddeb: 28 | dh_builddeb --destdir=. 29 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /debian/watch.ex: -------------------------------------------------------------------------------- 1 | # Example watch control file for uscan 2 | # Rename this file to "watch" and then you can run the "uscan" command 3 | # to check for upstream updates and more. 4 | # See uscan(1) for format 5 | 6 | # Compulsory line, this is a version 4 file 7 | version=4 8 | 9 | # PGP signature mangle, so foo.tar.gz has foo.tar.gz.sig 10 | #opts="pgpsigurlmangle=s%$%.sig%" 11 | 12 | # HTTP site (basic) 13 | #http://example.com/downloads.html \ 14 | # files/cavif-([\d\.]+)\.tar\.gz debian uupdate 15 | 16 | # Uncomment to examine an FTP server 17 | #ftp://ftp.example.com/pub/cavif-(.*)\.tar\.gz debian uupdate 18 | 19 | # SourceForge hosted projects 20 | # http://sf.net/cavif/ cavif-(.*)\.tar\.gz debian uupdate 21 | 22 | # GitHub hosted projects 23 | #opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%-$1.tar.gz%" \ 24 | # https://github.com//cavif/tags \ 25 | # (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian uupdate 26 | 27 | # PyPI 28 | # https://pypi.debian.net/cavif/cavif-(.+)\.(?:zip|tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz))) 29 | 30 | # Direct Git 31 | # opts="mode=git" http://git.example.com/cavif.git \ 32 | # refs/tags/v([\d\.]+) debian uupdate 33 | 34 | 35 | 36 | 37 | # Uncomment to find new files on GooglePages 38 | # http://example.googlepages.com/foo.html cavif-(.*)\.tar\.gz 39 | -------------------------------------------------------------------------------- /doc/ja_JP/README.md: -------------------------------------------------------------------------------- 1 | # cavif ドキュメント 2 | 3 | - [コマンドラインオプション](usage.md) 4 | 5 | ## 参考になるかもしれないリンク集 6 | 7 | - AV1/AVIF 8 | - [AV1 Bitstream & Decoding Process Specification - av1-spec.pdf](https://aomediacodec.github.io/av1-spec/av1-spec.pdf) 9 | - [AV1 Image File Format (AVIF)](http://web.archive.org/web/20181109113447/https://people.xiph.org/~negge/AVIF2018.pdf) 10 | - [Into the Depths: 11 | The Technical Details Behind AV1](http://web.archive.org/web/20201112022823/https://mile-high.video/files/mhv2018/pdf/day1/1_02_Egge.pdf) 12 | - [AV1リアルタイムハードウェアエンコーダを開発しました - dwango on GitHub](https://dwango.github.io/articles/av1hwencoder/) 13 | - 画像/動画処理一般 14 | - [画像符号化](http://www7b.biglobe.ne.jp/~yizawa/InfSys1/advanced/image_cod/index.htm) 15 | - [信号処理論第二](http://hil.t.u-tokyo.ac.jp/~kameoka/sp2/) 16 | - [講座:基礎からの画像符号化[全12回]](https://www.ite.or.jp/contents/tech_guide/tech_guide201301_201306.pdf) 17 | - [画像符号化事始め 前半](http://www.pcsj-imps.org/archive/2013tutorial.pdf) 18 | - 各種テクニックを実際に適用してみた画像があって面白い 19 | 20 | ## サンプルファイル 21 | 22 | - [AOMediaCodec/av1-avif](https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles) 23 | - [link-u/avif-sample-images](https://github.com/link-u/avif-sample-images) 24 | -------------------------------------------------------------------------------- /doc/ja_JP/usage.md: -------------------------------------------------------------------------------- 1 | # コマンドラインオプションの説明 2 | 3 | 選択肢から選ぶものは、断りがない限り一番最初がデフォルト。 4 | 5 | ## 入出力 6 | 7 | ### 入力 8 | 9 | - `-i input.png`(必須) 10 | - 対応フォーマット 11 | - 1/2/4/8bit Gray 12 | - 8/16bit RGB 13 | - alpha channel対応(alpha channelをエンコードするには、次の`--encode-target alpha`を指定する) 14 | 15 | ### 出力 16 | 17 | - `-o output.avif`(必須) 18 | 19 | ### エンコードターゲット 20 | 21 | - `--encode-target [image|alpha]` 22 | 23 | 入力されるpngのうちの、imageとalphaのどちらを利用してエンコードするかを指定する。次のオプションとセットで使う。 24 | 25 | なお、`--encode-target alpha`を指定するときは、入力されるPNGにalphaチャンネルが無いとエラーになる。 26 | 27 | ### Alpha/Depth画像の付与 28 | 29 | - `--attach-alpha ` 30 | - `--attach-depth ` 31 | 32 | alphaチャンネルやdepthチャンネルの画像を付与する。なお、depth/alphaとも、モノクロ画像でなければならない。入力の拡張子がavifな事からわかるように、alpha付き/depth付きのAVIF画像を生成するには、2回ないし3回に分けてエンコードする必要がある。 33 | 34 | 画像の解像度やbit深度、色域(`full-range` or `limited-range`)は、現状の規格上は本体の画像とは異なっていても構わない事になっているが、libavifなどではサポートする予定はなさそう([Issue](https://github.com/AOMediaCodec/libavif/issues/86))。 35 | 36 | #### 例:alpha付きのAVIF画像を作る 37 | 38 | ```bash 39 | cavif -i -o --encode-target alpha --monochrome 40 | cavif -i -o --encode-target image --attach-alpha 41 | ``` 42 | 43 | なお、`--attach-alpha`される画像は``からエンコードしたものでなくてもよい。 44 | 45 | #### 例:depthもalphaも追加する 46 | 47 | ```bash 48 | cavif -i -o --encode-target alpha --monochrome 49 | cavif -i -o --encode-target image --monochrome 50 | cavif -i -o --encode-target image --attach-alpha --attach-depth 51 | ``` 52 | 53 | depth画像もモノクロでなければならないことに注意。 54 | 55 | ### エンコード結果の表示 56 | 57 | - `--show-result` 58 | - 初期値:表示しない 59 | 60 | デコードした結果を表示する。ただし、現状デコーダ側へ渡される設定(OBUシーケンスヘッダ)の内容しか表示できない。 61 | 62 | 例: 63 | 64 | ``` 65 | % cavif -i hato.png -o hato.avif --show-result 66 | [2020/01/29 02:33:26 INFO ] cavif 67 | [2020/01/29 02:33:26 INFO ] libaom ver: 1.0.0-errata1-avif 68 | [2020/01/29 02:33:27 INFO ] Encoding: hato.png -> hato.avif 69 | [2020/01/29 02:35:15 INFO ] Encoding done: hato.png -> hato.avif 70 | [2020/01/29 02:35:15 INFO ] 71 | [2020/01/29 02:35:15 INFO ] - OBU Sequence Header: 72 | [2020/01/29 02:35:15 INFO ] - AV1 Profile: 0 73 | [2020/01/29 02:35:15 INFO ] - Still picture: Yes 74 | [2020/01/29 02:35:15 INFO ] - Reduced still picture header: Yes 75 | [2020/01/29 02:35:15 INFO ] - Sequence Level Index at OperatingPoint[0]: 12 76 | [2020/01/29 02:35:15 INFO ] - Max frame width: 3082 77 | [2020/01/29 02:35:15 INFO ] - Max frame height: 2048 78 | [2020/01/29 02:35:15 INFO ] - Use 128x128 superblock: Yes 79 | [2020/01/29 02:35:15 INFO ] - FilterIntra enabled: Yes 80 | [2020/01/29 02:35:15 INFO ] - IntraEdgeFilter enabled: Yes 81 | [2020/01/29 02:35:15 INFO ] - Superres enabled: No 82 | [2020/01/29 02:35:15 INFO ] - CDEF enabled: No 83 | [2020/01/29 02:35:15 INFO ] - Loop Restoration enabled: No 84 | [2020/01/29 02:35:15 INFO ] - Film Grain Params Present: No 85 | [2020/01/29 02:35:15 INFO ] - Color Info: 86 | [2020/01/29 02:35:15 INFO ] - High bit-depth: No 87 | [2020/01/29 02:35:15 INFO ] - Twelve bit: No 88 | [2020/01/29 02:35:15 INFO ] - Monochrome: No 89 | [2020/01/29 02:35:15 INFO ] - Color primaries: 90 | [2020/01/29 02:35:15 INFO ] - Transfer characteristics: 91 | [2020/01/29 02:35:15 INFO ] - Matrix coefficients: 92 | [2020/01/29 02:35:15 INFO ] - Color range: Limited 93 | [2020/01/29 02:35:15 INFO ] - Sub sampling X: 1 94 | [2020/01/29 02:35:15 INFO ] - Sub sampling Y: 1 95 | [2020/01/29 02:35:15 INFO ] - Chroma sample position: 0 96 | [2020/01/29 02:35:15 INFO ] - Separate UV Delta Q: No 97 | ``` 98 | 99 | ## メタデータ 100 | 101 | ### 切り抜き・回転・反転 102 | 103 | 適用される順番は「切り抜き→回転→反転」 104 | 105 | #### 切り抜き 106 | 107 | - `--crop-size widthN/widthD,heightN/heightD` 108 | - 初期値:なし。切り抜かない 109 | - `--crop-offset horizOffN/horizOffD,vertOffN/vertOffD` 110 | - 初期値:中心から切り抜く 111 | 112 | 表示時に切り抜くサイズとオフセットを分数(`N/D`)で指定する。`N/1`の時(整数)の時だけ、`N`と省略可能。 113 | 114 | デフォルトでは指定されたサイズで中心から切り抜き、offsetが指定されたら、その分移動したところから切り抜く。 115 | 116 | 例: 117 | 118 | - `--crop-size 1000/3,1000/7`(333.3x142.9で中心から切り抜く) 119 | - `--crop-size 300,320`(300x320で中心から切り抜く) 120 | 121 | #### 回転 122 | 123 | - `--rotation [0, 90, 180, 270]` 124 | - 初期値:回転しない 125 | 126 | 表示時に回転する。反時計回り。 127 | 128 | #### 反転 129 | 130 | - `--mirror [vertical, horizontal]` 131 | - 初期値:反転しない 132 | 133 | 表示時に反転する。 134 | 135 | ## AV1 シーケンシャルヘッダ 136 | 137 | ### 静止画用の削減されたヘッダを出力せず、動画用のフルのヘッダを出力する 138 | 139 | - `--full-still-picture-header` 140 | - 指定しないとき: 141 | `still_pisture=1`かつ`reduced_still_picture_header=1`の静止画専用ヘッダを出力する 142 | 143 | このオプションを指定すると、動画用のヘッダを出力する。静止画専用のヘッダにくらべて、3バイトぐらい長くなる。 144 | 145 | ## リサイズ・スケール・超解像フィルタ 146 | 147 | ### resize 148 | 149 | 縮小された画像を出力する。デコーダ側は小さいサイズの画像を受け取る。cavifの場合、正直元のpngを縮小すればいいのでは感はないではない。 150 | 151 | - `--resize-mode [none|fixed|random]` 152 | - デフォルト: `none`(リサイズしない) 153 | - `fixed`:リサイズする倍率を指定する。 154 | - `random`: ランダムにリサイズする。たぶん、動画用。 155 | 156 | リサイズするモードを指定する。`fixed`で倍率を指定するには、次の`--resize-mode`を用いる。 157 | 158 | - `--resize-denominator [8-16]` 159 | - デフォルト:`8`(等倍にスケールする) 160 | 161 | `--resize-mode fixed`で指定する倍率の分母を指定する。分子は`8`で固定。つまり、`[0.5-1.0]`倍を9段階で指定できる。 162 | 163 | 注意: 164 | 165 | - `--full-still-picture-header`を指定したときだけ(なぜか)有効になる。 166 | - Frame Superresolutionと組み合わせると、パラメータの組み合わせによってはvalidationで落ちる時がある。 167 | 168 | ### scale 169 | 170 | - `--horizontal-scale-mode [1/1, 4/5, 3/5, 1/2]` 171 | - `--vertical-scale-mode [1/1, 4/5, 3/5, 1/2]` 172 | 173 | `--resize-mode`とは別の方法でリサイズする。デコーダ側は、元の画像からその分だけ縮小された画像を受け取る。 174 | 175 | `--resize-mode`との違いは動画のエンコード中にフレームごとに変更可能なことであるが、cavifの場合はあんまりうれしくない。 176 | 177 | 注意: 178 | 179 | - `--full-still-picture-header`を指定しないと、基本的にassertion errorで落ちる。 180 | - 落ちないようにも出来るのだが、さらに追加でオプションを2つ指定しないといけないので実装してない。 181 | - Frame Super-resolutionと組み合わせると、パラメータの組み合わせによってはvalidationで落ちる時がある。 182 | 183 | ### Frame super-resolution 184 | 185 | エンコーダ側で縮小して、デコーダ側で超解像する機能。デコーダは、元の画像と同じサイズの画像を受け取る。 186 | 187 | - `--enable-superres`(初期値) 188 | - `--disable-superres` 189 | 190 | 超解像フィルタを使うのを許すかどうかを決定する。ここでdisableにすると、次以降のパラメータは一切無視される(はず)。 191 | 192 | - `--superres-mode [none|fixed|random|qthresh|auto]` 193 | - デフォルト: `none`(超解像しない) 194 | - `fixed`:リサイズする倍率を指定する。 195 | - `random`: ランダムにリサイズする。たぶん、動画用。 196 | - `qthresh`: qパラメータに応じて拡大(縮小)倍率を決定する。 197 | - `auto`: 自動で決定する。アルゴリズムは不明(調べてない)。 198 | 199 | 超解像フィルタのモードを指定する。`fixed`と`qthresh`で使うパラメータを指定するためのオプションは次を参照。 200 | 201 | - `--superres-denominator [8-16]` 202 | - デフォルト:`8`(等倍にスケールする) 203 | 204 | `--superres-mode fixed`で指定する倍率の分母を指定する。分子は`8`で固定。つまり、`[0.5-1.0]`倍を9段階で指定できる。 205 | 206 | - `--superres-qthresh [0-63]` 207 | - デフォルト:0(しきい値を設定しない) 208 | 209 | `--superres-mode qthresh`を指定した時の、q値のしきい値を設定する。q値がこの値を下回った時にだけsuperresフィルタが有効になる。その時の倍率はq値によってエンコーダが自動で決定する(アルゴリズムはよくわからん)。 210 | 211 | 注意: 212 | 213 | - `--resize-mode`や`--scale-mode`と組み合わせた時に、パラメータの組み合わせによってはvalidationで落ちる時がある。 214 | 215 | ### Render width / Render height 216 | 217 | 表示するときの解像度を指定できる。ただし、デコーダ側はオリジナルと同じ大きさの画像を受け取り、画像に付属するメタデータにこの解像度が書き込まれる(だけ)。`davif`はあくまでpngに書き戻すためのツールであって表示するためのツールではないので、この値は無視している。 218 | 219 | - `--render-width ` 220 | - デフォルト: `0`(指定しない) 221 | - `--render-height ` 222 | - デフォルト: `0`(指定しない) 223 | 224 | 両方指定しないと有効にならない。 225 | 226 | ## プロファイル 227 | 228 | ### AV1 シーケンス・プロファイル 229 | 230 | - `--profile (0=base, 1=high, 2=professional)` 231 | - デフォルト:`0(base profile)` 232 | 233 | AV1のプロファイルを指定する。[プロファイルごとに使えるピクセルフォーマットとbit depthが異なる](https://aomediacodec.github.io/av1-spec/#sequence-header-obu-semantics)。 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 |
seq_profileBit depthMonochrome supportChroma subsampling
08 or 10YesYUV 4:2:0
18 or 10NoYUV 4:4:4
28 or 10YesYUV 4:2:2
212YesYUV 4:2:0, YUV 4:2:2, YUV 4:4:4
271 | 272 | ### ピクセルフォーマット 273 | 274 | - `--pix-fmt [yuv420, yuv422, yuv444]` 275 | - 初期値:`yuv420` 276 | 277 | 出力される画像のピクセルフォーマット。 278 | 279 | 使えるビット深度とピクセルフォーマットとプロファイルの組み合わせに制限があるので注意。カラー画像をモノクロにするときも、それぞれのLumaの間引き方で結果が変わるので注意。 280 | 281 | ### ビット深度 282 | 283 | - `--bit-depth [8, 10, 12]` 284 | - 初期値:`8bit` 285 | 286 | 出力される画像のビット深度。 287 | 288 | 使えるビット深度とピクセルフォーマットとプロファイルの組み合わせに制限があるので注意。 289 | 290 | ## カラーマネジメント 291 | 292 | ### 色域 293 | 294 | - `--enable-full-color-range`(初期値) 295 | - `--disable-full-color-range` 296 | 297 | 例えば通常の8bitのYUVのフォーマットでは、Yの値として16-235、UとVの値として16-240しか使わないが、このフラグをenableにすると0-255のすべてを使うようになる。10/12ビットでも同様。デフォルトではfalse。 298 | 299 | 計算方法の詳細については、[H.273](https://www.itu.int/rec/T-REC-H.273-201612-I/en)を参照してほしい。 300 | 301 | ### Color Primaries 302 | 303 | ``` 304 | --color-primaries 305 | [| 306 | bt709|sRGB|sYCC|unspecified|bt470m| 307 | bt470bg|bt601|ntsc|smpte240m| 308 | generic-film|bt2020|bt2100|xyz| 309 | smpte428|smpte431|smpte432|ebu3213] 310 | ``` 311 | 312 | - デフォルト値:`bt709` 313 | 314 | それぞれの色空間において、R,G,Bの原色とWhiteが[CIE-XYZ色空間](https://ja.wikipedia.org/wiki/CIE_1931_%E8%89%B2%E7%A9%BA%E9%96%93)のどこに対応するかを定める。それぞれの名前の他、H.273で定義されている定数をそのまま指定することもできる。 315 | 316 | 詳細については、[H.273](https://www.itu.int/rec/T-REC-H.273-201612-I/en)を参照してほしい。 317 | 318 | ### Transfer Characteristics 319 | 320 | ``` 321 | --transfer-characteristics 322 | [| 323 | bt709|unspecified|bt470m| 324 | bt470bg|bt601|ntsc|smpte240m| 325 | linear|log100|log100sqrt10| 326 | iec61966|bt1361|sRGB| 327 | bt2020|bt2020-10bit|bt2020-12bit| 328 | smpte2084|bt2100pq|smpte428|bt2100hlg|arib-b67] 329 | ``` 330 | 331 | - デフォルト値:`bt709` 332 | 333 | いわゆる「[ガンマ補正](https://ja.wikipedia.org/wiki/%E3%82%AC%E3%83%B3%E3%83%9E%E5%80%A4)」の方法を定める。それぞれの名前の他、H.273で定義されている定数をそのまま指定することもできる。 334 | 335 | 詳細については、[H.273](https://www.itu.int/rec/T-REC-H.273-201612-I/en)を参照してほしい。 336 | 337 | ### Matrix Coefficients 338 | 339 | ``` 340 | --matrix-coefficients 341 | [|bt709|sRGB|sYCC| 342 | unspecified|us-fcc|bt470bg|bt601|ntsc|smpte240m|bt2020] 343 | ``` 344 | 345 | - デフォルト値:`bt709` 346 | 347 | RGBからYUVに変換する行列の係数を指定する。それぞれの名前の他、H.273で定義されている定数をそのまま指定することもできる。 348 | 349 | 詳細については、[H.273](https://www.itu.int/rec/T-REC-H.273-201612-I/en)を参照してほしい。 350 | 351 | ## 速度と品質のトレードオフ 352 | 353 | ### エンコーダの用途 354 | 355 | - `--encoder-usage [good, realtime]` 356 | - 初期値:good(品質優先) 357 | 358 | エンコーダのモードを指定する。`good`の方が遅いが画質はよく、`realtime`の方が速いが画質はおざなり。 359 | 360 | ### 利用スレッド数 361 | 362 | - `--threads ` 363 | - 初期値:論理コア数(`nproc`コマンドで確認可能) 364 | 365 | 変換時に使うスレッド数を指定する。ただし実際にマルチスレッドされている気配がない。 366 | 367 | ### row based multi-threading of encoder 368 | 369 | - `--row-mt` 370 | - 初期値:なし(`row-mt`しない) 371 | 372 | 行単位でマルチスレッドでエンコードしてくれるようになるらしい。これを使うと`--threads`の意味が出てくるのかもしれない。ただし、画質に対して何かしらの影響があるかもしれない。 373 | 374 | ### cpu-used 375 | 376 | - `--cpu-used [0-8]` 377 | - 初期値:`1` 378 | 379 | 小さくすればするほど、CPUを犠牲にして画質を上げようとする。 380 | 381 | ## ビットレート制御 382 | 383 | ### チューニング・メトリクス 384 | 385 | - `--tune [ssim|psnr|vmaf-with-preprocessing|vmaf-without-preprocessing|vmaf-max-gain]` 386 | - 初期値:`ssim` ([Structural Similarity](https://www.cns.nyu.edu/pub/lcv/wang03-preprint.pdf)) 387 | 388 | エンコーダが画質を最適するためにパラメータをチューニングするときに、どの指標をつかって画質を評価するか指定する。 389 | 390 | [PSNRとSSIMは有名なので省略](https://dftalk.jp/?p=18111)。 391 | 392 | `vmaf-with-preprocessing`,`vmaf-without-preprocessing`, `vmaf-max-gain`は、Netflixの開発した客観指標、[VMAF](https://github.com/Netflix/vmaf)を使ってtuningする。それぞれの違いは調査してない。 393 | 394 | なお、VMAFを使った指標は、`vmaf-without-preprocessing`以外はassertion errorで落ちてしまう。さらに、一応動く`vmaf-with-preprocessing`も、DebugビルドだとSIGFPEを起こしてクラッシュしてしまうので(Releaseビルドだと不正確な計算でも動いてしまうようだ)、あまり信頼できないかもしれない。 395 | 396 | - `--vmaf-model-path (default: /usr/share/cavif/model/vmaf_v0.6.1.pkl)` 397 | 398 | VMAFはSVMを使って実装されている。その学習済みモデルのパスを指定する。Debian packageで入れた場合`/usr/share/cavif/model/`以下(ソース上では[external/vmaf/model](https://github.com/Netflix/vmaf/tree/master/model)以下)に他のモデルもあるが、現状互換性はなく、`vmaf_v0.6.1.pkl`か`vmaf_4k_v0.6.1.pkl`しか実際には使えない。 399 | 400 | ### レートコントロール・アルゴリズム 401 | 402 | - `--rate-control [q, cq]` 403 | - 初期値:`q` 404 | 405 | 出力される画像のファイルサイズの制御方法を指定する。 406 | 407 | - q: 品質を固定 408 | - cq: 品質を守りつつ、次で指定するbit rate限界まで品質を上げる(ただし努力目標?)。 409 | 410 | ### CQ Level 411 | 412 | - `--crf [0-63]` 413 | - 初期値:`32` 414 | 415 | qとcqで守らせたい品質を指定する。値が低いほど画質はよい。 416 | 417 | ### ビットレート 418 | 419 | - `--bit-rate ` 420 | - 初期値:`256 [kilo-bits per second]` 421 | 422 | `--rate-control cq`で守らせるビットレート。1秒の動画という扱いにしているので、出力されるファイルはここで指定した`kilo-bits`を上回らない…はずだが、努力目標っぽい。 423 | 424 | ### qmax, qmin 425 | 426 | - `--qmax [0-63] (Maximum (Worst Quality) Quantizer)` 427 | - 初期値: `63` 428 | - `--qmin [0-63] (Minimum (Best Quality) Quantizer)` 429 | - 初期値: `0` 430 | 431 | `--rate control[q, cq]`や`--crf [0-63]`で品質を固定した上で、さらに利用するq level(量子化レベル)の上限と下限を指定できる。ソースを読んだ限り、たぶんcrfよりさらにキツく上限と下限を制御するようになるんだと思うけれど、よくわからない。 432 | 433 | ### adaptive quantization 434 | 435 | - `--adaptive-quantization [none, variance, complexity, cyclic]` 436 | - 初期値:`none` 437 | 438 | フレーム内で適応的に量子化パラメータを変える機能。デフォルトでnone。主観画質を上げるのに役立つらしい。 439 | 440 | - `--disable-adaptive-quantization-b`(初期値) 441 | - `--enable-adaptive-quantization-b` 442 | 443 | さらにその進化版もあるらしい。違いはわからない。追加で`enable`にすることで有効になる。 444 | 445 | ### delta q / delta lf 446 | 447 | - `--delta-q [none, objective, perceptual]` 448 | - 初期値:`none` 449 | 450 | スーパーブロックごとにqの値を変えることができる。デフォルトは`none`。`objective`にすると客観指標がよくなり、`perceptual`にすると主観的によくなるらしい。 451 | 452 | #### Chroma Delta Q 453 | 454 | - `--disable-chroma-delta-q`(初期値) 455 | - `--enable-chroma-delta-q` 456 | 457 | chromaでも有効にするかどうか 458 | 459 | #### Delta LF 460 | 461 | - `--disable-delta-lf`(初期値) 462 | - `--enable-delta-lf` 463 | 464 | Delta Qが有効になっているとDelta LoopFilterというのも有効にできる。 465 | 466 | ### quantisation matrices(qm) and quant matrix flatness 467 | 468 | - `--use-qm` 469 | - 初期値:無効。通常の`q`パラメータを使ったクオリティ制御を行う。 470 | - `--qm-min [0-15] (default: 5)` 471 | - `--qm-max [0-15] (default: 9)` 472 | - `--qm-min-y [0-15] (default: 10)` 473 | - `--qm-min-u [0-15] (default: 11)` 474 | - `--qm-min-v [0-15] (default: 12)` 475 | 476 | 上記のqとは別にQMatricesというのを使って品質を変えることも出来るらしい。qとは逆に、上がれば上がるほど品質が良いらしい。 477 | デフォルトではoffで、`--use-qm`を指定して有効にした時だけ、他のオプションが意味を持つ。 478 | 479 | ### ロスレスモード 480 | 481 | - `--lossless` 482 | - 初期値:無効。lossyな圧縮をする 483 | 484 | このフラグをつけると、ロスレスモードでエンコードする。アルファチャンネルをエンコードするときはこのほうがよいかもしれない。 485 | 486 | なお、`--enable-full-color-range`を指定せずlimited rangeのYUVで変換する場合、RGBからYUVに変換する時点で情報が落ちる(変換が単射でない)ので完全に`lossless`にはならないので注意。 487 | 488 | ## Pre process 489 | 490 | ### モノクロ画像 491 | 492 | - `--monochrome` 493 | - 初期値:無効。色のある画像を出力する 494 | 495 | モノクロで出力する。エンコーダが色差信号を無視する(モノクロにする)だけなので、入力画像はモノクロでなくてもよい。 496 | 497 | ### Sharpness 498 | 499 | - `--sharpness [0-7]` 500 | - 初期値: `0`(たぶん、sharpにしない) 501 | 502 | たぶん、上げれば上げるほどシャープになる。ただしおすすめは0とのこと。 503 | 504 | ## Post process 505 | 506 | ### CDEF 507 | 508 | - `--disable-cdef`(初期値) 509 | - `--enable-cdef` 510 | 511 | 主観画質を上げるためのポストプロセス・フィルタである[CDEF](https://arxiv.org/abs/1602.05975)を有効にするかどうか決める。デコード時に適用され、無視できないぐらい重い。 512 | 513 | ### Loop Restoration Filter 514 | 515 | - `--disable-loop-restoration`(初期値) 516 | - `--enable-loop-restoration` 517 | 518 | [失われてしまった高周波数領域を復活させるためのフィルタとのこと](https://www.spiedigitallibrary.org/conference-proceedings-of-spie/11137/1113718/AV1-In-loop-super-resolution-framework/10.1117/12.2534538.short?SSO=1)。 519 | 520 | dav1dで試した限り結構負荷が高いので切ってもいいかもと思い、cavifではデフォルトでdisable。 521 | 522 | ## Coding parameter 523 | 524 | ### スーパーブロックサイズ 525 | 526 | - `--superblock-size [dynamic, 128, 64]` 527 | - デフォルト:`dynamic` 528 | 529 | AV1では、画像をまずすべて同じ大きさのスーパーブロックに分割してから、その後それぞれのスーパーブロックを再帰的に分割して符号化していく。その大本のスーパーブロックのサイズを指定する。 530 | 531 | デフォルトの`dynamic`を指定すると、短辺が480ピクセル以上の時`128x128`、それ以下のときは`64x64`のスーパーブロックで分割する。 532 | 533 | ### タイル分割 534 | 535 | - `--tile-rows [0-6]`, `--tile-columns [0-6]` 536 | - 初期値:両方とも`0` 537 | 538 | 画像をそれぞれ `pow(2, )`, `pow(2, )`個の画像に分割して独立してエンコード・デコードする。 539 | 540 | デフォルトではどちらも`0`で、分割せず1枚の画像として扱う。 541 | 542 | ### disable-(rect, ab, 1to4)-partitions 543 | 544 | - `--disable-rect-partitions`(初期値:`disable`にしない) 545 | - `--disable-ab-partitions`(初期値:`disable`にしない) 546 | - `--disable-1to4-partitions`(初期値:`disable`にしない) 547 | 548 | ブロック分割する時にそれぞれの分割を無効にする。 549 | 550 | rect/ab/1to4については次のAAを見よ: 551 | 552 | ``` 553 | // Partition types. R: Recursive 554 | // 555 | // NONE HORZ VERT SPLIT 556 | // +-------+ +-------+ +---+---+ +---+---+ 557 | // | | | | | | | | R | R | 558 | // | | +-------+ | | | +---+---+ 559 | // | | | | | | | | R | R | 560 | // +-------+ +-------+ +---+---+ +---+---+ 561 | // 562 | // HORZ_A HORZ_B VERT_A VERT_B 563 | // +---+---+ +-------+ +---+---+ +---+---+ 564 | // | | | | | | | | | | | 565 | // +---+---+ +---+---+ +---+ | | +---+ 566 | // | | | | | | | | | | | 567 | // +-------+ +---+---+ +---+---+ +---+---+ 568 | // 569 | // HORZ_4 VERT_4 570 | // +-----+ +-+-+-+ 571 | // +-----+ | | | | 572 | // +-----+ | | | | 573 | // +-----+ +-+-+-+ 574 | ``` 575 | 576 | ### max/min partition size 577 | 578 | - `--min-partition-size [4|8|16|32|64|128]` 579 | - 初期値:`4` 580 | - `--max-partition-size [4|8|16|32|64|128]` 581 | - 初期値:`128` 582 | 583 | 上のパーティションの最小・最大サイズを指定する。デフォルトで最小は4、最大は128。 584 | 585 | ## Intra Edge filtering 586 | 587 | - `--enable-intra-edge-filter`(初期値) 588 | - `--disable-intra-edge-filter` 589 | 590 | 画像がスーパーブロックの定数倍でない限り、端っこにあまりの部分が出る。それらに対して掛けるフィルタを有効にするか否か。 591 | 592 | デフォルトではenable。 593 | 594 | ### TX64 595 | 596 | - `--enable-tx64`(初期値) 597 | - `--disable-tx64` 598 | 599 | 64ピクセルのタイルでのTransformを許可するかしないか設定する。デフォルトではenable。 600 | 601 | 許可しない場合、64ピクセル以下のブロックになるまで必ず分割が走る。 602 | 603 | ### Flip IDTX 604 | 605 | - `--enable-flip-idtx`(初期値) 606 | - `--disable-flip-idtx` 607 | 608 | AV1ではDCT以外にも[ADST](https://groups.google.com/a/webmproject.org/forum/#!topic/webm-discuss/JDxb0Qfzx7U)と呼ばれる上下左右非対称な基底を使った変換を行う事もあるし、そもそも変換を行わないこともある(IDTX; Identity TX)。 609 | 610 | disableにすると、左右非対称な変換と恒等変換を無効にする。デフォルトはもちろん`enable`。 611 | 612 | ``` 613 | * This will enable or disable usage of flip and identity transform 614 | * types in any direction. The default value is 1. Including: 615 | * FLIPADST_DCT, DCT_FLIPADST, FLIPADST_FLIPADST, ADST_FLIPADST, 616 | * FLIPADST_ADST, IDTX, V_DCT, H_DCT, V_ADST, H_ADST, V_FLIPADST, 617 | * H_FLIPADST 618 | ``` 619 | 620 | 同様に、`--use-dct-only` を指定するとDCTしか行わなくなる(初期値:`dct`以外も使う)。 621 | 622 | `--use-default-tx-only` を指定すると、現在の予測モードから定まる「デフォルトのTX」以外は使わなくなる(`intra_mode_to_tx_type()`)。指定しない時(デフォルト)は`default-tx`以外も使う。 623 | 624 | `--use-reduced-tx-set` を指定すると、16種類ある変換中、 `transforms w/o flip (4) + Identity (1)` の5種類しか使わなくなる(`av1_get_ext_tx_set_type()`)。指定しない時はこの5種類以外も使う。 625 | 626 | ### キーフレーム・フィルタリング 627 | 628 | - `--disable-keyfram-temporal-filtering`(初期値) 629 | - `--enable-keyframe-temporal-filtering` 630 | 631 | フレーム同士の相関を見たりするフィルタをキーフレームにも掛けるかどうかを指定する。libaomではデフォルトでonになっているが、cavifでは静止画がターゲットなのでデフォルトでoffにしている。品質に問題があったらenableに戻してください。 632 | 633 | ### Intraフレーム各種 634 | 635 | イントラフレームのフィルタリングを有効にするかどうか。たぶんoffにすると画質は下がる。ただ、デコーダ側で何かしらの処理は走ってたので、offにするとそのかわりデコードが速くなるかもしれない。 636 | 637 | #### フィルタ 638 | 639 | 画質を上げるための各種フィルタ。 640 | 641 | - Filter Intra 642 | - `--enable-filter-intra`(初期値) 643 | - `--disable-filter-intra` 644 | - Smooth Intra 645 | - `--enable-smooth-intra`(初期値) 646 | - `--disable-smooth-intra` 647 | 648 | #### 予測器 649 | 650 | あるピクセル(複数でありうる)から他のピクセルの値を予測する。予測が当たる場合、圧縮率がよくなる。 651 | 652 | ##### [Paeth Intra](https://ieeexplore.ieee.org/document/8667544) 653 | 654 | - `--enable-paeth-intra`(初期値) 655 | - `--disable-paeth-intra` 656 | 657 | ##### Angle Delta 658 | 659 | - `--enable-angle-delta`(初期値) 660 | - `--disable-angle-delta` 661 | 662 | ##### CfL (Chroma prediction from Luma) 663 | 664 | - `--enable-chroma-from-luma`(初期値) 665 | - `--disable-chroma-from-luma` 666 | 667 | Luma信号からChroma信号を予測する。 668 | 669 | 曰く「[どちゃくそ重いからHEVCではstrongly rejectedされたけど、現実的な範囲のものができたからAV1では有効にするぜ](https://arxiv.org/abs/1711.03951)」。デフォルトでon。 670 | 671 | モノクロ画像ではどちらを指定しても関係ないかもしれないが、ゼロの値を使って「無」から何かを予測している可能性はあり、offにするとモノクロでもデコードが速くなる可能性は無いではない。 672 | 673 | #### パレットモード 674 | 675 | - `--disable-palette`(初期値) 676 | - `--enable-palette` 677 | 678 | 有効にすると、8色しか使えないらしい。 679 | 680 | 現状では実際に有効にするには、さらに次の条件が守られていることが必要: 681 | 682 | 683 | - Superblockサイズが64でないと動かない([av1_allow_palette](https://aomedia.googlesource.com/aom/+/refs/tags/v1.0.0-errata1-avif/av1/common/blockd.h#1113)) 684 | - 元画像の色数をカウントしてて、1ライン中で使われている色の数が4色以下のラインが十分にないと動かない([set_screen_content_options](https://aomedia.googlesource.com/aom/+/refs/tags/v1.0.0-errata1-avif/av1/encoder/encoder.c#3857)) 685 | - 「1ラインで4色」は実験的に仮で決めてる値っぽい 686 | - GIMPで8色にしたらだいたい守られている条件 687 | 688 | #### [Intra Block Copy](https://www.semanticscholar.org/paper/Intra-Block-Copy-in-HEVC-Screen-Content-Coding-Xu-Liu/5b8ef0e83b1e839a3ef62ab9821334247878444d/figure/0) 689 | 690 | - `--enable-intrabc`(初期値) 691 | - `--disable-intrabc` 692 | 693 | 同じ内容の領域があったらコピーするモードらしい。4コマ漫画で上のコマと下のコマでセリフ以外コピーしてる時とかは役に立つかもしれない。 694 | -------------------------------------------------------------------------------- /patches/libaom.patch: -------------------------------------------------------------------------------- 1 | diff --git a/CMakeLists.txt b/CMakeLists.txt 2 | index bf290bacf..5ca74d10b 100644 3 | --- a/CMakeLists.txt 4 | +++ b/CMakeLists.txt 5 | @@ -616,7 +616,7 @@ if(CONFIG_AV1_ENCODER) 6 | target_link_libraries(aom PRIVATE ${VMAF_LDFLAGS} ${VMAF_LIBRARIES}) 7 | else() 8 | target_link_libraries(aom 9 | - PRIVATE ${VMAF_LDFLAGS} ${VMAF_LIBRARIES} -static) 10 | + PRIVATE ${VMAF_LDFLAGS} ${VMAF_LIBRARIES}) 11 | endif() 12 | target_include_directories(aom PRIVATE ${VMAF_INCLUDE_DIRS}) 13 | if(VMAF_CFLAGS) 14 | -------------------------------------------------------------------------------- /patches/zlib.patch: -------------------------------------------------------------------------------- 1 | diff --git a/CMakeLists.txt b/CMakeLists.txt 2 | index 0fe939d..e6363b7 100644 3 | --- a/CMakeLists.txt 4 | +++ b/CMakeLists.txt 5 | @@ -230,20 +230,20 @@ endif() 6 | # Example binaries 7 | #============================================================================ 8 | 9 | -add_executable(example test/example.c) 10 | -target_link_libraries(example zlib) 11 | -add_test(example example) 12 | - 13 | -add_executable(minigzip test/minigzip.c) 14 | -target_link_libraries(minigzip zlib) 15 | - 16 | -if(HAVE_OFF64_T) 17 | - add_executable(example64 test/example.c) 18 | - target_link_libraries(example64 zlib) 19 | - set_target_properties(example64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") 20 | - add_test(example64 example64) 21 | - 22 | - add_executable(minigzip64 test/minigzip.c) 23 | - target_link_libraries(minigzip64 zlib) 24 | - set_target_properties(minigzip64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") 25 | -endif() 26 | +#add_executable(example test/example.c) 27 | +#target_link_libraries(example zlib) 28 | +#add_test(example example) 29 | +# 30 | +#add_executable(minigzip test/minigzip.c) 31 | +#target_link_libraries(minigzip zlib) 32 | +# 33 | +#if(HAVE_OFF64_T) 34 | +# add_executable(example64 test/example.c) 35 | +# target_link_libraries(example64 zlib) 36 | +# set_target_properties(example64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") 37 | +# add_test(example64 example64) 38 | +# 39 | +# add_executable(minigzip64 test/minigzip.c) 40 | +# target_link_libraries(minigzip64 zlib) 41 | +# set_target_properties(minigzip64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") 42 | +#endif() 43 | -------------------------------------------------------------------------------- /scripts/apply-patches.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eux 2 | 3 | function readlink_f() { 4 | local src='import os,sys;print(os.path.realpath(sys.argv[1]))' 5 | python3 -c "${src}" "$1" || python -c "${src}" "$1" 6 | } 7 | 8 | ROOT_DIR="$(cd "$(readlink_f "$(dirname "$0")")" && cd .. && pwd)" 9 | cd "${ROOT_DIR}" || exit 1 10 | 11 | set -eux 12 | set -o pipefail 13 | 14 | # libaom 15 | (cd external/libaom; patch -p1 --forward < ../../patches/libaom.patch || true) 16 | (cd external/zlib; patch -p1 --forward < ../../patches/zlib.patch || true) 17 | -------------------------------------------------------------------------------- /scripts/build-debian-package.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eux 2 | 3 | function readlink_f() { 4 | local src='import os,sys;print(os.path.realpath(sys.argv[1]))' 5 | python3 -c "${src}" "$1" || python -c "${src}" "$1" 6 | } 7 | 8 | ROOT_DIR="$(cd "$(readlink_f "$(dirname "$0")")" && cd .. && pwd)" 9 | cd "${ROOT_DIR}" || exit 1 10 | 11 | set -eux 12 | set -o pipefail 13 | 14 | # To avoid limitation: 15 | # https://git-scm.com/docs/git-config/2.35.2#Documentation/git-config.txt-safedirectory 16 | chown "$(id -g):$(id -u)" . -R 17 | 18 | # Generate changelog 19 | git_describe="$(git describe --tags)" 20 | VERSION=${git_describe:1}.$(TZ=JST-9 date +%Y%m%d)+$(lsb_release -cs) 21 | DATE=$(LC_ALL=C TZ=JST-9 date '+%a, %d %b %Y %H:%M:%S %z') 22 | 23 | cat < "${ROOT_DIR}/debian/changelog" 24 | cavif (${VERSION}) unstable; urgency=medium 25 | 26 | * This is automated build. 27 | * Please see https://github.com/link-u/cavif/releases for more information! 28 | 29 | -- Ryo Hirafuji ${DATE} 30 | EOF 31 | 32 | # Add Kitware APT repository to install the latest cmake. 33 | # https://apt.kitware.com/ 34 | apt-get update 35 | apt-get install -y --no-install-recommends wget ca-certificates 36 | wget -O - 'https://apt.kitware.com/kitware-archive.sh' | sh 37 | apt-get update 38 | # It fails if kitware's apt repository is broken. 39 | apt-get install -y --no-install-recommends cmake 40 | 41 | # Workaround: gcc >= 8.0 is required. 42 | case $(lsb_release -cs) in 43 | bionic) 44 | export CC=gcc-8 45 | export CXX=g++-8 46 | sed -i -r "s/gcc-9/gcc-8/g" "${ROOT_DIR}/debian/control" 47 | sed -i -r "s/g\+\+-9/g++-8/g" "${ROOT_DIR}/debian/control" 48 | sed -i -r "s/libstdc\+\+-9-dev/libstdc++-8-dev/g" "${ROOT_DIR}/debian/control" 49 | ;; 50 | *) ;; 51 | esac 52 | 53 | # Workaround: meson has been upgraded so fast, we use the latest versions. 54 | apt-get install -y --no-install-recommends python3-venv python3-pip python3-setuptools 55 | python3 -m venv venv 56 | source venv/bin/activate 57 | pip3 install wheel 58 | pip3 install meson ninja 59 | 60 | # Install deps to build. 61 | #dpkg-checkbuilddeps "${ROOT_DIR}/debian/control" 62 | mk-build-deps --install --remove \ 63 | --tool='apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes' \ 64 | "${ROOT_DIR}/debian/control" 65 | 66 | bash scripts/reset-submodules.sh 67 | bash scripts/apply-patches.sh 68 | bash scripts/build-deps.sh 69 | 70 | fakeroot debian/rules clean 71 | fakeroot debian/rules build 72 | fakeroot debian/rules binary 73 | # workaround. external/libpng will be dirty after making debian packages. 74 | env --chdir=external/libpng git reset --hard 75 | -------------------------------------------------------------------------------- /scripts/build-deps.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eux 2 | 3 | function readlink_f() { 4 | local src='import os,sys;print(os.path.realpath(sys.argv[1]))' 5 | python3 -c "${src}" "$1" || python -c "${src}" "$1" 6 | } 7 | 8 | ROOT_DIR="$(cd "$(readlink_f "$(dirname "$0")")" && cd .. && pwd)" 9 | cd "${ROOT_DIR}" || exit 1 10 | 11 | set -eux 12 | set -o pipefail 13 | 14 | DEPS_DIR="$(readlink_f "${ROOT_DIR}/_deps")" 15 | 16 | rm -Rf "${DEPS_DIR}" 17 | mkdir -p "${DEPS_DIR}" 18 | 19 | # libvmaf 20 | bash -eux < 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "AVIFBuilder.hpp" 22 | #include "Config.hpp" 23 | 24 | namespace { 25 | 26 | enum AVIFProfile : uint8_t { 27 | Baseline = 0, 28 | Advanced = 1, 29 | Unspecified = 255, 30 | }; 31 | 32 | AVIFProfile calcProfile(AVIFBuilder::Frame& frame) { 33 | // https://aomediacodec.github.io/av1-avif/#baseline-profile 34 | // The AV1 profile shall be the Main Profile and the level shall be 5.1 or lower. 35 | if(frame.sequenceHeader().seqProfile == 0) { 36 | bool baseProfile = true; 37 | for(auto const& operatingPoint : frame.sequenceHeader().operatingPoints) { 38 | baseProfile &= operatingPoint.seqLevelIdx <= 13; 39 | } 40 | if (baseProfile) { 41 | return Baseline; 42 | } 43 | } 44 | // https://aomediacodec.github.io/av1-avif/#advanced-profile 45 | // 6.4. AVIF Advanced Profile 46 | // The AV1 profile shall be the High Profile and the level shall be 6.0 or lower. 47 | if(frame.sequenceHeader().seqProfile == 1) { 48 | bool advancedProfile = true; 49 | for(auto const& operatingPoint : frame.sequenceHeader().operatingPoints) { 50 | advancedProfile &= operatingPoint.seqLevelIdx <= 16; 51 | } 52 | if (advancedProfile) { 53 | return Advanced; 54 | } 55 | } 56 | return Unspecified; 57 | } 58 | 59 | 60 | } 61 | 62 | AVIFBuilder::Frame AVIFBuilder::Frame::load(avif::util::Logger& log, std::string const& path) { 63 | std::variant, std::string> file = avif::util::readFile(path); 64 | if(std::holds_alternative(file)) { 65 | log.fatal(std::get(file)); 66 | } 67 | std::shared_ptr const result = avif::Parser(log, std::get>(file)).parse(); 68 | if(!result->ok()) { 69 | log.fatal(result->error()); 70 | } 71 | avif::FileBox const& fileBox = result->fileBox(); 72 | std::optional primaryItemID{}; 73 | if(fileBox.metaBox.primaryItemBox.has_value()) { 74 | primaryItemID = fileBox.metaBox.primaryItemBox.value().itemID; 75 | } 76 | namespace query = avif::util::query; 77 | avif::img::ColorProfile colorProfile; 78 | std::optional colr = query::findProperty(fileBox, primaryItemID); 79 | if(colr.has_value()) { 80 | auto profile = colr.value().profile; 81 | if(std::holds_alternative(profile)) { 82 | colorProfile.iccProfile = avif::img::ICCProfile(std::get(profile).payload); 83 | } else if(std::holds_alternative(profile)) { 84 | colorProfile.iccProfile = avif::img::ICCProfile(std::get(profile).payload); 85 | } else if(std::holds_alternative(profile)) { 86 | colorProfile.cicp = std::get(profile); 87 | } 88 | } 89 | 90 | std::optional av1Config = query::findProperty(fileBox, primaryItemID); 91 | if(!av1Config.has_value()) { 92 | log.fatal("AV1 config not found: {}", path); 93 | } 94 | std::vector configOBUs = av1Config.value().av1Config.configOBUs; 95 | std::shared_ptr av1result = avif::av1::Parser(log, configOBUs).parse(); 96 | if(!av1result->ok()) { 97 | log.fatal(av1result->error()); 98 | } 99 | std::pair region = query::findItemRegion(fileBox, primaryItemID); 100 | auto beg = std::begin(result->buffer()); 101 | std::vector mdat = std::vector(std::next(beg, region.first), std::next(beg, region.second)); 102 | namespace av1query = avif::av1::util::query; 103 | std::optional seq = av1query::find(av1result->packets()); 104 | if(!seq.has_value()) { 105 | log.fatal("Sequence header not found."); 106 | } 107 | return AVIFBuilder::Frame(colorProfile, std::move(seq.value()), std::move(configOBUs), std::move(mdat)); 108 | } 109 | 110 | AVIFBuilder::AVIFBuilder(avif::util::Logger& log, Config& config, uint32_t const width, uint32_t const height) 111 | :log_(log) 112 | ,config_(config) 113 | ,width_(width) 114 | ,height_(height) 115 | { 116 | } 117 | 118 | avif::FileBox AVIFBuilder::buildFileBox() { 119 | if(!this->frame_.has_value()){ 120 | throw std::runtime_error("No primary frame."); 121 | } 122 | Frame& frame = this->frame_.value(); 123 | using namespace avif; 124 | FileBox& fileBox = this->fileBox_; 125 | { 126 | // Fill FileTypeBox. 127 | FileTypeBox& fileTypeBox = fileBox.fileTypeBox; 128 | fileTypeBox.majorBrand = "avif"; 129 | fileTypeBox.minorVersion = 0; 130 | fileTypeBox.compatibleBrands.emplace_back("avif"); 131 | // ISO/IEC 23000-22:2019/Amd. 2:2021(E) 132 | // The FileTypeBox should contain, in the compatible_brands list, the 'mif1' brand 133 | fileTypeBox.compatibleBrands.emplace_back("mif1"); 134 | // https://aomediacodec.github.io/av1-avif/#profiles-constraints 135 | fileTypeBox.compatibleBrands.emplace_back("miaf"); 136 | AVIFProfile profile = calcProfile(frame); 137 | if(this->alpha_.has_value()) { 138 | AVIFProfile alphaProfile = calcProfile(this->alpha_.value()); 139 | if(alphaProfile != profile) { 140 | profile = Unspecified; 141 | } 142 | } 143 | if(this->depth_.has_value()) { 144 | AVIFProfile depthProfile = calcProfile(this->depth_.value()); 145 | if(depthProfile != profile) { 146 | profile = Unspecified; 147 | } 148 | } 149 | // Set a maximum compatible profile. 150 | if(profile == Baseline) { 151 | fileTypeBox.compatibleBrands.emplace_back("MA1B"); 152 | }else if(profile == Advanced) { 153 | fileTypeBox.compatibleBrands.emplace_back("MA1A"); 154 | } 155 | } 156 | { 157 | // Fill metabox 158 | MetaBox& metaBox = this->fileBox_.metaBox; 159 | metaBox.setFullBoxHeader(0, 0); 160 | { // fill HandlerBox 161 | HandlerBox& handlerBox = metaBox.handlerBox; 162 | handlerBox.setFullBoxHeader(0u, 0u); 163 | handlerBox.name = "cavif"; 164 | handlerBox.handler = "pict"; 165 | } 166 | } 167 | this->fillFrameInfo(1, frame); 168 | uint16_t nextID = 2; 169 | if(this->alpha_.has_value()) { 170 | this->fillFrameInfo(nextID, alpha_.value(), avif::kAlphaAuxType()); 171 | this->linkAuxImages(nextID, 1); 172 | ++nextID; 173 | } 174 | if(this->depth_.has_value()) { 175 | this->fillFrameInfo(nextID, depth_.value(), avif::kDepthAuxType()); 176 | this->linkAuxImages(nextID, 1); 177 | ++nextID; 178 | } 179 | return this->fileBox_; 180 | } 181 | 182 | void AVIFBuilder::linkAuxImages(uint16_t const from, uint16_t const to) { 183 | using namespace avif; 184 | if(!this->fileBox_.metaBox.itemReferenceBox.has_value()) { 185 | ItemReferenceBox box{ 186 | .references = std::vector{}, 187 | }; 188 | box.setFullBoxHeader(1, 0); 189 | this->fileBox_.metaBox.itemReferenceBox = box; 190 | } 191 | auto& refs = std::get>(this->fileBox_.metaBox.itemReferenceBox.value().references); 192 | for(auto& ref : refs) { 193 | if(ref.fromItemID == from) { 194 | for(auto const& oldTo : ref.toItemIDs) { 195 | if(oldTo == to) { 196 | return; 197 | } 198 | } 199 | ref.toItemIDs.emplace_back(to); 200 | return; 201 | } 202 | } 203 | auto box = SingleItemTypeReferenceBox { 204 | .fromItemID = from, 205 | .toItemIDs = {to}, 206 | }; 207 | box.hdr.type = avif::util::str2uint("auxl"); 208 | refs.emplace_back(box); 209 | } 210 | 211 | std::vector AVIFBuilder::build() { 212 | avif::FileBox fileBox = this->buildFileBox(); 213 | { // pass1: calc positions 214 | avif::util::StreamWriter pass1; 215 | avif::Writer(log_, pass1).write(fileBox); 216 | } 217 | for (size_t i = 0; i < fileBox.metaBox.itemLocationBox.items.size(); ++i) { 218 | size_t const offset = fileBox.mediaDataBoxes.at(i).offset; 219 | fileBox.metaBox.itemLocationBox.items.at(i).baseOffset = offset; 220 | } 221 | avif::util::StreamWriter out; 222 | avif::Writer(log_, out).write(fileBox); 223 | std::vector data = out.buffer(); 224 | auto beg = std::begin(data); 225 | std::size_t mdatIdx = 0; 226 | if(frame_.has_value()) { 227 | Frame& frame = frame_.value(); 228 | std::copy(std::begin(frame.data()), std::end(frame.data()), std::next(beg, fileBox.mediaDataBoxes.at(mdatIdx).offset)); 229 | ++mdatIdx; 230 | } 231 | if(alpha_.has_value()){ 232 | Frame& frame = alpha_.value(); 233 | std::copy(std::begin(frame.data()), std::end(frame.data()), std::next(beg, fileBox.mediaDataBoxes.at(mdatIdx).offset)); 234 | ++mdatIdx; 235 | } 236 | if(depth_.has_value()){ 237 | Frame& frame = depth_.value(); 238 | std::copy(std::begin(frame.data()), std::end(frame.data()), std::next(beg, fileBox.mediaDataBoxes.at(mdatIdx).offset)); 239 | ++mdatIdx; 240 | } 241 | return data; 242 | } 243 | 244 | void AVIFBuilder::fillFrameInfo(uint16_t const itemID, AVIFBuilder::Frame const& frame, std::optional const& auxType) { 245 | using namespace avif; 246 | MetaBox& metaBox = this->fileBox_.metaBox; 247 | { // fill ItemInfoBox 248 | ItemInfoBox& itemInfoBox = metaBox.itemInfoBox; 249 | itemInfoBox.setFullBoxHeader(1, 0); 250 | { 251 | ItemInfoEntry entry{}; 252 | entry.setFullBoxHeader(2, 0); 253 | entry.itemID = itemID; 254 | entry.itemType = "av01"; 255 | entry.itemProtectionIndex = 0; 256 | entry.itemName = "Image"; 257 | itemInfoBox.itemInfos.emplace_back(entry); 258 | } 259 | } 260 | { // fill ItemLocationBox with dummy data. 261 | ItemLocationBox& locationBox = metaBox.itemLocationBox; 262 | locationBox.setFullBoxHeader(0, 0); 263 | locationBox.offsetSize = 0; 264 | locationBox.lengthSize = 4; 265 | locationBox.baseOffsetSize = 4; 266 | locationBox.items.emplace_back(ItemLocationBox::Item { 267 | .itemID = itemID, 268 | .dataReferenceIndex = 0, 269 | .baseOffset = 0,// TODO: fill it after. 270 | .extents = {{ 271 | ItemLocationBox::Item::Extent { 272 | .extentOffset = 0, 273 | .extentLength = frame.data().size(), 274 | } 275 | }}, 276 | }); 277 | } 278 | if(!auxType.has_value()) { // Primary Image! 279 | PrimaryItemBox pitm{}; 280 | pitm.itemID = itemID; 281 | metaBox.primaryItemBox = pitm; 282 | } 283 | { // fill ItemPropertiesBox 284 | ItemPropertiesBox& propertiesBox = metaBox.itemPropertiesBox; 285 | // Just only one ItemPropertyAssociation box to comply with HEIF requirements. 286 | // See: https://github.com/link-u/avif-sample-images/issues/4 287 | // HEIF (ISO 23008-12:2017) 9.3.1 288 | // There shall be at most one ItemPropertyAssociation box 289 | // with a given pair of values of version and flags. 290 | ItemPropertyAssociation& assoc = 291 | propertiesBox.associations.empty() 292 | ? propertiesBox.associations.emplace_back(ItemPropertyAssociation{}) 293 | : propertiesBox.associations[0]; 294 | ItemPropertyAssociation::Item item{}; 295 | item.itemID = itemID; 296 | { 297 | // FIXME(ledyba-z): Is it really correct? 298 | // https://aomediacodec.github.io/av1-isobmff/#av1sampleentry-semantics 299 | propertiesBox.propertyContainers.properties.emplace_back(PixelAspectRatioBox { 300 | .hSpacing = 1, 301 | .vSpacing = 1, 302 | }); 303 | item.entries.emplace_back(ItemPropertyAssociation::Item::Entry { 304 | .essential = false, 305 | .propertyIndex = static_cast(propertiesBox.propertyContainers.properties.size()), 306 | }); 307 | } 308 | if(config_.cropSize.has_value() && config_.cropOffset.has_value()) { 309 | CleanApertureBox clap{}; 310 | { 311 | auto const w = config_.cropSize.value().first.reduce(); 312 | auto const h = config_.cropSize.value().second.reduce(); 313 | clap.cleanApertureWidthN = w.numerator(); 314 | clap.cleanApertureWidthD = w.denominator(); 315 | clap.cleanApertureHeightN = h.numerator(); 316 | clap.cleanApertureHeightD = h.denominator(); 317 | } 318 | { 319 | auto const h = config_.cropOffset.value().first.reduce(); 320 | auto const v = config_.cropOffset.value().second.reduce(); 321 | clap.horizOffN = h.numerator(); 322 | clap.horizOffD = h.denominator(); 323 | clap.vertOffN = v.numerator(); 324 | clap.vertOffD = v.denominator(); 325 | } 326 | propertiesBox.propertyContainers.properties.emplace_back(clap); 327 | item.entries.emplace_back(ItemPropertyAssociation::Item::Entry { 328 | .essential = true, 329 | .propertyIndex = static_cast(propertiesBox.propertyContainers.properties.size()), 330 | }); 331 | } 332 | if(config_.rotation.has_value()) { 333 | propertiesBox.propertyContainers.properties.emplace_back( ImageRotationBox { 334 | .angle = config_.rotation.value(), 335 | }); 336 | item.entries.emplace_back(ItemPropertyAssociation::Item::Entry { 337 | .essential = true, 338 | .propertyIndex = static_cast(propertiesBox.propertyContainers.properties.size()), 339 | }); 340 | } 341 | if(config_.mirrorAxis.has_value()) { 342 | propertiesBox.propertyContainers.properties.emplace_back(ImageMirrorBox { 343 | .axis = config_.mirrorAxis.value(), 344 | }); 345 | item.entries.emplace_back(ItemPropertyAssociation::Item::Entry { 346 | .essential = true, 347 | .propertyIndex = static_cast(propertiesBox.propertyContainers.properties.size()), 348 | }); 349 | } 350 | { 351 | propertiesBox.propertyContainers.properties.emplace_back(ImageSpatialExtentsProperty { 352 | .imageWidth = width_, 353 | .imageHeight = height_, 354 | }); 355 | item.entries.emplace_back(ItemPropertyAssociation::Item::Entry { 356 | .essential = false, 357 | .propertyIndex = static_cast(propertiesBox.propertyContainers.properties.size()), 358 | }); 359 | } 360 | { 361 | uint8_t bpp = 8; 362 | if(frame.sequenceHeader().colorConfig.highBitdepth) { 363 | bpp = 10; 364 | if(frame.sequenceHeader().colorConfig.twelveBit) { 365 | bpp = 12; 366 | } 367 | } 368 | if(frame.sequenceHeader().colorConfig.monochrome) { 369 | propertiesBox.propertyContainers.properties.emplace_back(PixelInformationProperty { 370 | .bitsPerChannel = {bpp}, 371 | }); 372 | } else { 373 | propertiesBox.propertyContainers.properties.emplace_back(PixelInformationProperty { 374 | .bitsPerChannel = {bpp, bpp, bpp}, 375 | }); 376 | } 377 | item.entries.emplace_back(ItemPropertyAssociation::Item::Entry { 378 | .essential = true, 379 | .propertyIndex = static_cast(propertiesBox.propertyContainers.properties.size()), 380 | }); 381 | } 382 | if (frame.colorProfile().iccProfile.has_value()) { 383 | auto const& icc = frame.colorProfile().iccProfile.value(); 384 | propertiesBox.propertyContainers.properties.emplace_back(ColourInformationBox { 385 | .profile = ColourInformationBox::UnrestrictedICC { 386 | .payload = icc.payload(), 387 | } 388 | }); 389 | item.entries.emplace_back(ItemPropertyAssociation::Item::Entry { 390 | .essential = false, 391 | .propertyIndex = static_cast(propertiesBox.propertyContainers.properties.size()), 392 | }); 393 | } 394 | if (frame.colorProfile().cicp.has_value()) { 395 | auto const& cicp = frame.colorProfile().cicp.value(); 396 | propertiesBox.propertyContainers.properties.emplace_back(ColourInformationBox { 397 | .profile = cicp 398 | }); 399 | item.entries.emplace_back(ItemPropertyAssociation::Item::Entry { 400 | .essential = false, 401 | .propertyIndex = static_cast(propertiesBox.propertyContainers.properties.size()), 402 | }); 403 | } 404 | { 405 | propertiesBox.propertyContainers.properties.emplace_back(AV1CodecConfigurationRecordBox { 406 | .av1Config = AV1CodecConfigurationRecord { 407 | .marker = true, 408 | .version = 1, 409 | .seqProfile = frame.sequenceHeader().seqProfile, 410 | .seqLevelIdx0 = frame.sequenceHeader().operatingPoints.at(0).seqLevelIdx, 411 | .seqTier0 = frame.sequenceHeader().operatingPoints.at(0).seqTier, 412 | .highBitDepth = frame.sequenceHeader().colorConfig.highBitdepth, 413 | .twelveBit = frame.sequenceHeader().colorConfig.twelveBit, 414 | .monochrome = frame.sequenceHeader().colorConfig.monochrome, 415 | .chromaSubsamplingX = frame.sequenceHeader().colorConfig.subsamplingX, 416 | .chromaSubsamplingY = frame.sequenceHeader().colorConfig.subsamplingY, 417 | .chromaSamplePosition = frame.sequenceHeader().colorConfig.chromaSamplePosition.has_value() ? 418 | frame.sequenceHeader().colorConfig.chromaSamplePosition.value() : 419 | static_cast(0) /* CSP_UNKNOWN: 6.4.2. Color config semantics */, 420 | .configOBUs = frame.configOBU(), 421 | }, 422 | }); 423 | item.entries.emplace_back(ItemPropertyAssociation::Item::Entry { 424 | .essential = true, 425 | .propertyIndex = static_cast(propertiesBox.propertyContainers.properties.size()), 426 | }); 427 | } 428 | if(auxType.has_value()) { 429 | propertiesBox.propertyContainers.properties.emplace_back(AuxiliaryTypeProperty { 430 | .auxType = auxType.value(), 431 | }); 432 | item.entries.emplace_back(ItemPropertyAssociation::Item::Entry { 433 | .essential = true, 434 | .propertyIndex = static_cast(propertiesBox.propertyContainers.properties.size()), 435 | }); 436 | } 437 | assoc.items.emplace_back(item); 438 | } 439 | this->fileBox_.mediaDataBoxes.push_back(MediaDataBox { 440 | .offset = 0, // TODO: fill it later. 441 | .size = frame.data().size(), 442 | }); 443 | } 444 | 445 | 446 | AVIFBuilder& AVIFBuilder::setPrimaryFrame(AVIFBuilder::Frame&& frame) { 447 | this->frame_ = std::move(frame); 448 | return *this; 449 | } 450 | 451 | AVIFBuilder& AVIFBuilder::setAlphaFrame(AVIFBuilder::Frame&& frame) { 452 | this->alpha_ = std::move(frame); 453 | return *this; 454 | } 455 | 456 | AVIFBuilder& AVIFBuilder::setDepthFrame(AVIFBuilder::Frame&& frame) { 457 | this->depth_ = std::move(frame); 458 | return *this; 459 | } 460 | -------------------------------------------------------------------------------- /src/AVIFBuilder.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by psi on 2020/01/07. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class Config; 13 | class AVIFBuilder final { 14 | public: 15 | class Frame final { 16 | private: 17 | avif::img::ColorProfile colorProfile_; 18 | avif::av1::SequenceHeader sequenceHeader_; 19 | std::vector configOBU_; 20 | std::vector data_; 21 | public: 22 | Frame() = delete; 23 | explicit Frame(avif::img::ColorProfile colorProfile, avif::av1::SequenceHeader sequenceHeader, std::vector configOBU, std::vector data) 24 | :colorProfile_(std::move(colorProfile)) 25 | ,sequenceHeader_(std::move(sequenceHeader)) 26 | ,configOBU_(std::move(configOBU)) 27 | ,data_(std::move(data)) 28 | { 29 | } 30 | static Frame load(avif::util::Logger& log, std::string const& path); 31 | public: 32 | [[ nodiscard ]] avif::img::ColorProfile const& colorProfile() const { return this->colorProfile_; } 33 | [[ nodiscard ]] avif::av1::SequenceHeader const& sequenceHeader() const { return this->sequenceHeader_; } 34 | [[ nodiscard ]] std::vector const& configOBU() const { return this->configOBU_; } 35 | [[ nodiscard ]] std::vector const& data() const { return this->data_; } 36 | }; 37 | 38 | private: 39 | avif::util::Logger& log_; 40 | Config const& config_; 41 | uint32_t const width_; 42 | uint32_t const height_; 43 | std::optional frame_{}; 44 | std::optional alpha_{}; 45 | std::optional depth_{}; 46 | avif::FileBox fileBox_{}; 47 | 48 | public: 49 | AVIFBuilder() = delete; 50 | explicit AVIFBuilder(avif::util::Logger& log, Config& config, uint32_t width, uint32_t height); 51 | ~AVIFBuilder() noexcept = default; 52 | AVIFBuilder& operator=(AVIFBuilder const&) = delete; 53 | AVIFBuilder& operator=(AVIFBuilder&&) = delete; 54 | AVIFBuilder(AVIFBuilder const&) = delete; 55 | AVIFBuilder(AVIFBuilder&&) = delete; 56 | 57 | public: 58 | AVIFBuilder& setPrimaryFrame(Frame&& frame); 59 | AVIFBuilder& setAlphaFrame(Frame&& frame); 60 | AVIFBuilder& setDepthFrame(Frame&& frame); 61 | [[ nodiscard ]] std::vector build(); 62 | 63 | private: 64 | [[ nodiscard ]] avif::FileBox buildFileBox(); 65 | void linkAuxImages(uint16_t from, uint16_t to); 66 | void fillFrameInfo(uint16_t itemID, AVIFBuilder::Frame const& frame, std::optional const& auxType = {}); 67 | }; 68 | -------------------------------------------------------------------------------- /src/Config.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by psi on 2020/01/14. 3 | // 4 | 5 | #include 6 | 7 | #include "Config.hpp" 8 | 9 | #include "ext/ExternalPartitionModelFactoryContainer.hpp" 10 | #include "ext/ExternalPartitionModel.hpp" 11 | #include "ext/models/NonSplitPartitionModel.hpp" 12 | 13 | namespace { 14 | 15 | // FIXME(ledyba-z): remove this function when the C++20 comes. 16 | bool endsWith(std::string const& target, std::string const& suffix) { 17 | if(target.size() < suffix.size()) { 18 | return false; 19 | } 20 | return target.substr(target.size()-suffix.size()) == suffix; 21 | } 22 | 23 | std::string basename(std::string const& path) { 24 | auto const pos = path.find_last_of('/'); 25 | if(pos == std::string::npos) { 26 | return path; 27 | } 28 | return path.substr(pos+1); 29 | } 30 | 31 | std::string trim(std::string str) { 32 | str.erase(std::find_if(str.rbegin(), str.rend(), [](int ch) { 33 | return !std::isspace(ch); 34 | }).base(), str.end()); 35 | str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](int ch) { 36 | return !std::isspace(ch); 37 | })); 38 | return str; 39 | } 40 | 41 | avif::math::Fraction parseFraction(std::string const& str) { 42 | auto const pos = str.find('/'); 43 | if(pos == std::string::npos) { 44 | return avif::math::Fraction(std::stoi(trim(str)), 1); 45 | } else { 46 | std::string const first = trim(str.substr(0, pos)); 47 | std::string const second = trim(str.substr(pos + 1)); 48 | int const n = std::stoi(first); 49 | int const d = std::stoi(second); 50 | if(d == 0) { 51 | throw std::invalid_argument("denominator_ can't be 0."); 52 | } 53 | return avif::math::Fraction(static_cast(n), static_cast(d)).reduce(); 54 | } 55 | } 56 | 57 | std::pair parseFractionPair(std::string const& str) { 58 | auto pos = str.find(','); 59 | if(pos == std::string::npos) { 60 | throw std::invalid_argument(R"(Invalid fraction pair. Example: "30/4, 100/7", "100, 100/2" or "100, 100")"); 61 | } 62 | std::string const first = trim(str.substr(0, pos)); 63 | std::string const second = trim(str.substr(pos + 1)); 64 | return std::make_pair(parseFraction(first), parseFraction(second)); 65 | } 66 | 67 | template 68 | std::optional parseEnumFromInt(std::string const& str) { 69 | return std::make_optional(static_cast(std::stoi(str))); 70 | } 71 | 72 | } 73 | 74 | Config::Config(int argc, char** argv) 75 | :commandName(basename(std::string(argv[0]))) 76 | ,argc(argc) 77 | ,argv(argv) 78 | ,commandLineFlags(createCommandLineFlags()) 79 | { 80 | } 81 | 82 | void Config::usage() { 83 | std::cerr << make_man_page(commandLineFlags, commandName); 84 | std::cerr << std::flush; 85 | } 86 | 87 | bool Config::parse() { 88 | return !clipp::parse(argc, argv, commandLineFlags).any_error(); 89 | } 90 | 91 | clipp::group Config::createCommandLineFlags() { 92 | using namespace clipp; 93 | auto& aom = this->codec; 94 | 95 | // Support flags. 96 | auto support = ( 97 | option("-h", "--help").doc("Show help and exit.").set(showHelp, true) 98 | ); 99 | 100 | // input/output 101 | group io = ( 102 | required("-i", "--input").doc("Filename to input") & value("input.png", input), 103 | required("-o", "--output").doc("Filename to output") & value("output.avif", output), 104 | option("--attach-alpha").doc("Attach alpha plane") & value("input-alpha.avif").call([&](std::string const& str){ alphaInput = str; }), 105 | option("--attach-depth").doc("Attach depth plane") & value("input-depth.avif").call([&](std::string const& str){ depthInput = str; }), 106 | option("--encode-target").doc("Encode target") & (parameter("image").set(encodeTarget, EncodeTarget::Image).doc("Encode image planes (default)") | parameter("alpha").set(encodeTarget, EncodeTarget::Alpha).doc("Encode an alpha plane")), 107 | option("--show-result").doc("Show encoding result").set(showResult, true) 108 | ); 109 | 110 | // meta 111 | group meta = ( 112 | option("--rotation").doc("Set rotation meta data(irot). Counter-clockwise.") & (parameter("0").set(rotation, std::make_optional(avif::ImageRotationBox::Rotation::Rot0)) | parameter("90").set(rotation, std::make_optional(avif::ImageRotationBox::Rotation::Rot90)) | parameter("180").set(rotation, std::make_optional(avif::ImageRotationBox::Rotation::Rot180)) | parameter("270").set(rotation, std::make_optional(avif::ImageRotationBox::Rotation::Rot270))), 113 | option("--mirror").doc("Set mirror meta data(imir).") & (parameter("vertical").set(mirrorAxis, std::make_optional(avif::ImageMirrorBox::Axis::Vertical)) | parameter("horizontal").set(mirrorAxis, std::make_optional(avif::ImageMirrorBox::Axis::Horizontal))), 114 | option("--crop-size").doc("Set crop size.") & value("width,height").call([&](std::string const& str){ cropSize = parseFractionPair(str); }), 115 | option("--crop-offset").doc("Set crop offset.") & value("horizontalOffset,verticalOffset").call([&](std::string const& str){ cropOffset = parseFractionPair(str); }) 116 | ); 117 | // av1 sequence header 118 | auto av1 = ( 119 | // av1 sequence header 120 | option("--full-still-picture-header").doc("Force to output full picture header").set(aom.full_still_picture_hdr, 1u) 121 | ); 122 | 123 | // colors 124 | group color = ( 125 | option("--color-primaries").doc("Set color primaries information value.") & ( 126 | /* 0 = For future use by ITU-T | ISO/IEC */ 127 | integer("Value defined in H.273").call([&](std::string const& str){ colorPrimaries = parseEnumFromInt(str); }).doc("See https://www.itu.int/rec/T-REC-H.273-201612-I/en") | 128 | parameter("bt709").set(colorPrimaries, std::make_optional(static_cast(1u))).doc("Rec. ITU-R BT.709-6") | 129 | parameter("sRGB").set(colorPrimaries, std::make_optional(static_cast(1u))).doc("IEC 61966-2-1 sRGB or sYCC") | 130 | parameter("sYCC").set(colorPrimaries, std::make_optional(static_cast(1u))).doc("IEC 61966-2-1 sRGB or sYCC") | 131 | parameter("unspecified").set(colorPrimaries, std::make_optional(static_cast(2u))).doc("Image characteristics are unknown or are determined by the application.") | 132 | /* 3 = For future use by ITU-T | ISO/IEC */ 133 | parameter("bt470m").set(colorPrimaries, std::make_optional(static_cast(4u))).doc("Rec. ITU-R BT.470-6 System M (historical)") | 134 | parameter("bt470bg").set(colorPrimaries, std::make_optional(static_cast(5u))).doc("Rec. ITU-R BT.470-6 System B, G (historical)") | 135 | parameter("bt601").set(colorPrimaries, std::make_optional(static_cast(5u))).doc("Rec. ITU-R BT.601-7 625") | 136 | parameter("ntsc").set(colorPrimaries, std::make_optional(static_cast(6u))).doc("Rec. ITU-R BT.1700-0 NTSC") | 137 | parameter("smpte240m").set(colorPrimaries, std::make_optional(static_cast(7u))).doc("SMPTE ST 240 (1999)") | 138 | parameter("generic-film").set(colorPrimaries, std::make_optional(static_cast(8u))).doc("Generic film (colour filters using Illuminant C)") | 139 | parameter("bt2020").set(colorPrimaries, std::make_optional(static_cast(9u))).doc("Rec. ITU-R BT.2020-2") | 140 | parameter("bt2100").set(colorPrimaries, std::make_optional(static_cast(9u))).doc("Rec. ITU-R BT.2100-0") | 141 | parameter("smpte428").set(colorPrimaries, std::make_optional(static_cast(10u))).doc("SMPTE ST 428-1") | 142 | parameter("xyz").set(colorPrimaries, std::make_optional(static_cast(10u))).doc("(CIE 1931 XYZ as in ISO 11664-1)") | 143 | parameter("smpte431").set(colorPrimaries, std::make_optional(static_cast(11u))).doc("SMPTE RP 431-2 (2011)") | 144 | parameter("smpte432").set(colorPrimaries, std::make_optional(static_cast(12u))).doc("SMPTE EG 432-1 (2010)") | 145 | parameter("22").set(colorPrimaries, std::make_optional(static_cast(22u))).doc("No corresponding industry specification identified") 146 | ), 147 | option("--transfer-characteristics").doc("Set transfer characteristics information value.") & ( 148 | integer("Value defined in H.273").call([&](std::string const& str){ transferCharacteristics = parseEnumFromInt(str); }).doc("See https://www.itu.int/rec/T-REC-H.273-201612-I/en") | 149 | parameter("bt709").set(transferCharacteristics, std::make_optional(static_cast(1u))).doc("Rec. ITU-R BT.709-6") | 150 | parameter("unspecified").set(transferCharacteristics, std::make_optional(static_cast(2u))).doc("Image characteristics are unknown or are determined by the application.") | 151 | /* 3 = For future use by ITU-T | ISO/IEC */ 152 | parameter("bt470m").set(transferCharacteristics, std::make_optional(static_cast(4u))).doc("Rec. ITU-R BT.470-6 System M (historical)") | 153 | parameter("bt470bg").set(transferCharacteristics, std::make_optional(static_cast(5u))).doc("Rec. ITU-R BT.470-6 System B, G (historical)") | 154 | parameter("bt601").set(transferCharacteristics, std::make_optional(static_cast(6u))).doc("Rec. ITU-R BT.1700-0 NTSC") | 155 | parameter("ntsc").set(transferCharacteristics, std::make_optional(static_cast(6u))).doc("Rec. ITU-R BT.1700-0 NTSC") | 156 | parameter("smpte240m").set(transferCharacteristics, std::make_optional(static_cast(7u))).doc("SMPTE 240M (1999) (historical)") | 157 | parameter("linear").set(transferCharacteristics, std::make_optional(static_cast(8u))).doc("Linear transfer characteristics") | 158 | parameter("log100").set(transferCharacteristics, std::make_optional(static_cast(9u))).doc("Logarithmic transfer characteristic (100:1 range)") | 159 | parameter("log100sqrt10").set(transferCharacteristics, std::make_optional(static_cast(10u))).doc("Logarithmic transfer characteristic (100 * Sqrt( 10 ) : 1 range)") | 160 | parameter("iec61966").set(transferCharacteristics, std::make_optional(static_cast(11u))).doc("IEC 61966-2-4") | 161 | parameter("bt1361").set(transferCharacteristics, std::make_optional(static_cast(12u))).doc("Rec. ITU-R BT.1361-0 extended colour gamut system (historical)") | 162 | parameter("sRGB").set(transferCharacteristics, std::make_optional(static_cast(13u))).doc("IEC 61966-2-1 sRGB or sYCC") | 163 | parameter("sYCC").set(transferCharacteristics, std::make_optional(static_cast(13u))).doc("IEC 61966-2-1 sRGB or sYCC") | 164 | parameter("bt2020").set(transferCharacteristics, std::make_optional(static_cast(14u))).doc("Rec. ITU-R BT.2020-2 (10-bit system)") | 165 | parameter("bt2020-10bit").set(transferCharacteristics, std::make_optional(static_cast(14u))).doc("Rec. ITU-R BT.2020-2 (10-bit system)") | 166 | parameter("bt2020-12bit").set(transferCharacteristics, std::make_optional(static_cast(15u))).doc("Rec. ITU-R BT.2020-2 (12-bit system)") | 167 | parameter("smpte2084").set(transferCharacteristics, std::make_optional(static_cast(16u))).doc("SMPTE ST 2084 for 10-, 12-, 14- and 16-bit systems") | 168 | parameter("bt2100pq").set(transferCharacteristics, std::make_optional(static_cast(16u))).doc("Rec. ITU-R BT.2100-0 perceptual quantization (PQ) system") | 169 | parameter("smpte428").set(transferCharacteristics, std::make_optional(static_cast(17u))).doc("SMPTE ST 428-1") | 170 | parameter("bt2100hlg").set(transferCharacteristics, std::make_optional(static_cast(18u))).doc("Rec. ITU-R BT.2100-0 hybrid log-gamma (HLG) system") | 171 | parameter("arib-b67").set(transferCharacteristics, std::make_optional(static_cast(18u))).doc("ARIB STD-B67") 172 | ), 173 | option("--matrix-coefficients").doc("Set matrix coefficients information value.") & ( 174 | integer("Value defined in H.273").call([&](std::string const& str){ matrixCoefficients = parseEnumFromInt(str); }).doc("See https://www.itu.int/rec/T-REC-H.273-201612-I/en") | 175 | parameter("bt709").set(matrixCoefficients, std::make_optional(static_cast(1u))).doc("Rec. ITU-R BT.709-6 (default)") | 176 | parameter("sRGB").set(matrixCoefficients, std::make_optional(static_cast(1u))).doc("IEC 61966-2-1 sRGB or sYCC (default)") | 177 | parameter("unspecified").set(matrixCoefficients, std::make_optional(static_cast(2u))).doc("Image characteristics are unknown or are determined by the application") | 178 | /* 3 = For future use by ITU-T | ISO/IEC */ 179 | parameter("us-fcc").set(matrixCoefficients, std::make_optional(static_cast(4u))).doc("United States Federal Communications Commission (2003)") | 180 | parameter("bt470bg").set(matrixCoefficients, std::make_optional(static_cast(4u))).doc("Rec. ITU-R BT.470-6 System B, G (historical)") | 181 | parameter("sYCC").set(matrixCoefficients, std::make_optional(static_cast(5u))).doc("IEC 61966-2-1 sRGB or sYCC") | 182 | parameter("bt601").set(matrixCoefficients, std::make_optional(static_cast(5u))).doc("Rec. ITU-R BT.601-7 625") | 183 | parameter("ntsc").set(matrixCoefficients, std::make_optional(static_cast(6u))).doc("Rec. ITU-R BT.1700-0 NTSC") | 184 | parameter("smpte240m").set(matrixCoefficients, std::make_optional(static_cast(7u))).doc("SMPTE 240M") | 185 | parameter("bt2020").set(matrixCoefficients, std::make_optional(static_cast(9u))).doc("Rec. ITU-R BT.2020-2 (non-constant luminance)") 186 | ) 187 | ); 188 | 189 | auto scales = ( 190 | option("--horizontal-scale-mode").doc("Set horizontal scale mode") & (parameter("1/1").set(scaleMode.h_scaling_mode, AOME_NORMAL).doc("Do not scale (default)") | parameter("1/2").set(scaleMode.h_scaling_mode, AOME_ONETWO).doc("Scale to 1/2") | parameter("3/5").set(scaleMode.h_scaling_mode, AOME_THREEFIVE).doc("Scale to 3/5") | parameter("4/5").set(scaleMode.h_scaling_mode, AOME_FOURFIVE).doc("Scale to 4/5") | parameter("1/4").set(scaleMode.h_scaling_mode, AOME_ONEFOUR).doc("Scale to 1/4") | parameter("3/4").set(scaleMode.h_scaling_mode, AOME_THREEFOUR).doc("Scale to 3/4") | parameter("1/8").set(scaleMode.h_scaling_mode, AOME_ONEEIGHT).doc("Scale to 1/8")), 191 | option("--vertical-scale-mode").doc("Set vertical scale mode") & (parameter("1/1").set(scaleMode.v_scaling_mode, AOME_NORMAL).doc("Do not scale (default)") | parameter("1/2").set(scaleMode.v_scaling_mode, AOME_ONETWO).doc("Scale to 1/2") | parameter("3/5").set(scaleMode.v_scaling_mode, AOME_THREEFIVE).doc("Scale to 3/5") | parameter("4/5").set(scaleMode.v_scaling_mode, AOME_FOURFIVE).doc("Scale to 4/5") | parameter("1/4").set(scaleMode.v_scaling_mode, AOME_ONEFOUR).doc("Scale to 1/4") | parameter("3/4").set(scaleMode.v_scaling_mode, AOME_THREEFOUR).doc("Scale to 3/4") | parameter("1/8").set(scaleMode.v_scaling_mode, AOME_ONEEIGHT).doc("Scale to 1/8")), 192 | option("--resize-mode").doc("Set resize mode") & (parameter("none").set(codec.rc_resize_mode, (unsigned int)(RESIZE_NONE)).doc("Do not resize") | parameter("fixed").set(codec.rc_resize_mode, (unsigned int)(RESIZE_FIXED)).doc("Resize image using a denominator_ given by `--resize-denominator_` arg") | parameter("random").set(codec.rc_resize_mode, (unsigned int)(RESIZE_RANDOM)).doc("Resize image randomly!")), 193 | option("--resize-denominator_").doc("Set resize denominator_.") & (integer("[8-16], default=8", codec.rc_resize_kf_denominator)), 194 | option("--superres-mode").doc("Set superres mode") & (parameter("none").set(codec.rc_superres_mode, AOM_SUPERRES_NONE).doc("Do not use superres mode") | parameter("fixed").set(codec.rc_superres_mode, AOM_SUPERRES_FIXED).doc("Apply superres filter to image using a denominator_ given by `--superres-denominator_` arg") | parameter("random").set(codec.rc_superres_mode, AOM_SUPERRES_RANDOM).doc("Apply superres filter to image with a random denominator_!") | parameter("qthresh").set(codec.rc_superres_mode, AOM_SUPERRES_QTHRESH).doc("Apply or do not apply superres filter to image based on the q index") | parameter("auto").set(codec.rc_superres_mode, AOM_SUPERRES_AUTO).doc("Apply or do not apply superres filter to image automatically")), 195 | option("--superres-denominator_").doc("Set superres resize denominator_.") & (integer("[8-16], default=8", codec.rc_superres_kf_denominator)), 196 | option("--superres-qthresh").doc("Set q level threshold for superres.") & (integer("[0-63], default=63 (Do not apply superres filter)", codec.rc_superres_kf_qthresh)), 197 | option("--render-width").doc("Set render width explicitly") & (integer("", renderWidth)), 198 | option("--render-height").doc("Set render height explicitly") & (integer("", renderHeight)) 199 | ); 200 | 201 | // profile and pixel formats 202 | group pixelAndColor = ( 203 | option("--profile").doc("AV1 Profile(0=base, 1=high, 2=professional)") & integer("0=base(default), 1=high, 2=professional", aom.g_profile), 204 | option("--pix-fmt").doc("Pixel format of output image") & (parameter("yuv420").set(pixFmt, AOM_IMG_FMT_I420).doc("YUV420 format (default)") | parameter("yuv422").set(pixFmt, AOM_IMG_FMT_I422).doc("YUV422 format") | parameter("yuv444").set(pixFmt, AOM_IMG_FMT_I444).doc("YUV444 format (recommended for lossless images)")), 205 | option("--bit-depth").doc("Bit depth of output image") & (parameter("8").set(aom.g_bit_depth, AOM_BITS_8).doc("8bits per color, 24bits per pixel (default)") | parameter("10").set(aom.g_bit_depth, AOM_BITS_10).doc("10bits per color, 30bits per pixel") | parameter("12").set(aom.g_bit_depth, AOM_BITS_12).doc("12bits per color, 36bits per pixel")), 206 | option("--disable-full-color-range").doc("Use limited YUV color range").set(fullColorRange, false), 207 | option("--enable-full-color-range").doc("Use full YUV color range (default)").set(fullColorRange, true) 208 | ); 209 | 210 | // trade-offs between speed and quality. 211 | group multiThreading = ( 212 | option("--encoder-usage").doc("Encoder usage") & (parameter("good").set(aom.g_usage, static_cast(AOM_USAGE_GOOD_QUALITY)).doc("Good Quality mode (default)") | parameter("realtime").set(aom.g_usage, static_cast(AOM_USAGE_REALTIME)).doc("Real time encoding mode")), 213 | option("--threads") & integer("Num of threads to use (default=num of logical cores)", aom.g_threads), 214 | option("--enable-row-mt").doc("Enable row based multi-threading of encoder").set(rowMT, true), 215 | option("--disable-row-mt").doc("Disable row based multi-threading of encoder (default)").set(rowMT, false), 216 | option("--cpu-used").doc("Quality/Speed ratio modifier") & integer("0-9, default=1. Higher means slower encoding and better quality", cpuUsed) 217 | ); 218 | 219 | // rate-control 220 | group rateControl= ( 221 | option("--rate-control").doc("Rate control method") & (parameter("cbr").set(aom.rc_end_usage, AOM_CBR).doc("Constant Bit Rate mode. Please also set `--bit-rate` arg.") | parameter("q").set(aom.rc_end_usage, AOM_Q).doc("Constant Quality (default)") | parameter("cq").set(aom.rc_end_usage, AOM_CQ).doc("Constrained Quality")), 222 | option("--bit-rate").doc("Bit rate of output image.") & integer("kilo-bits per frame(default=0)", aom.rc_target_bitrate), 223 | option("--crf").doc("CQ Level in CQ rate control mode") & integer("0-63(default=10)", crf), 224 | option("--qmin").doc("Minimum (Best Quality) Quantizer") & integer("0-63(default=0)", codec.rc_min_quantizer), 225 | option("--qmax").doc("Maximum (Worst Quality) Quantizer") & integer("0-63(default=63)", codec.rc_max_quantizer), 226 | option("--adaptive-quantization").doc("Set adaptive-quantization mode") & (parameter("none").doc("none(default)").set(adaptiveQuantizationMode, int(NO_AQ)) | parameter("variance").doc("variance based").set(adaptiveQuantizationMode, int(VARIANCE_AQ)) | parameter("complexity").doc("complexity based").set(adaptiveQuantizationMode, int(VARIANCE_AQ)) | parameter("cyclic").doc("Cyclic refresh").set(adaptiveQuantizationMode, int(CYCLIC_REFRESH_AQ))), 227 | option("--enable-adaptive-quantization-b").doc("use adaptive quantize_b").set(enableAdaptiveQuantizationB, true), 228 | option("--disable-adaptive-quantization-b").doc("use traditional adaptive quantization (default)").set(enableAdaptiveQuantizationB, false), 229 | option("--delta-q").doc("a mode of delta q mode feature, that allows modulating q per superblock") & (parameter("none").doc("disable deltaQ").set(deltaQMode, int(NO_DELTA_Q)) | parameter("objective").doc("Use modulation to maximize objective quality").set(deltaQMode, int(DELTA_Q_OBJECTIVE)) | parameter("perceptual").doc("Use modulation to maximize perceptual quality").set(deltaQMode, int(DELTA_Q_PERCEPTUAL))), 230 | option("--delta-q-strength").doc("strength of deltaQ [0..1000] (default = 100)").set(deltaQStrength), 231 | option("--enable-chroma-delta-q").doc("enable delta quantization in chroma").set(enableChromaDeltaQ, true), 232 | option("--disable-chroma-delta-q").doc("disable delta quantization in chroma").set(enableChromaDeltaQ, false), 233 | option("--enable-loop-filter").doc("enable loop filter (default)").set(enableLoopFilter, true), 234 | option("--disable-loop-filter").doc("disable loop filter").set(enableLoopFilter, false), 235 | option("--enable-delta-lf").doc("enable delta loop filter").set(enableDeltaLoopFilter, true), 236 | option("--disable-delta-lf").doc("disable delta loop filter (default)").set(enableDeltaLoopFilter, false), 237 | option("--use-qm").doc("Use QMatrix").set(useQM, true), 238 | option("--qm-min").doc("Min quant matrix flatness") & integer("0-15 (default: 5)", qmMin), 239 | option("--qm-max").doc("Max quant matrix flatness") & integer("0-15 (default: 9)", qmMax), 240 | option("--qm-min-y").doc("Min quant matrix flatness for Y") & integer("0-15 (default: 10)", qmMinY), 241 | option("--qm-min-u").doc("Min quant matrix flatness for U") & integer("0-15 (default: 11)", qmMinU), 242 | option("--qm-min-v").doc("Min quant matrix flatness for V") & integer("0-15 (default: 12)", qmMinV), 243 | // TODO(ledyba-z): Support butteraugli. Don't forget to set CONFIG_TUNE_BUTTERAUGLI in CMakeLists.txt 244 | option("--tune").doc("Quality metric to tune") & (parameter("ssim").doc("SSIM(structural similarity)").set(tune, AOM_TUNE_SSIM) | parameter("psnr").doc("PSNR(peak signal-to-noise ratio)").set(tune, AOM_TUNE_PSNR) | parameter("vmaf-with-preprocessing").doc("vmaf-with-preprocessing").set(tune, AOM_TUNE_VMAF_WITH_PREPROCESSING) | parameter("vmaf-without-preprocessing").doc("vmaf-without-preprocessing").set(tune, AOM_TUNE_VMAF_WITHOUT_PREPROCESSING) | parameter("vmaf-max-gain").doc("vmaf-max-gain").set(tune, AOM_TUNE_VMAF_MAX_GAIN) | parameter("vmaf-neg-max-gain").doc("vmaf-neg-max-gain").set(tune, AOM_TUNE_VMAF_NEG_MAX_GAIN) /* | parameter("butteraugli").doc("google's butteraugli algorithm (github.com/google/butteraugli)").set(tune, AOM_TUNE_BUTTERAUGLI)*/), 245 | option("--content-type").doc("Content type") & (parameter("default").doc("Regular video content (default)").set(contentType, AOM_CONTENT_DEFAULT) | parameter("screen").doc("Screen capture content").set(contentType, AOM_CONTENT_SCREEN) | parameter("film").doc("Film content").set(contentType, AOM_CONTENT_FILM)), 246 | option("--vmaf-model-path").doc("VMAF model file path to tuning image quality") & value("", vmafModelPath), 247 | option("--lossless").doc("Enable lossless encoding").set(lossless, true) 248 | ); 249 | 250 | // pre-process 251 | group preProcess = ( 252 | option("--monochrome").doc("Encode to monochrome image").set(codec.monochrome, 1u), 253 | option("--sharpness").doc("Sharpening output") & integer("0-7", sharpness) 254 | ); 255 | 256 | // post-process 257 | group postProcess = ( 258 | option("--disable-cdef").doc("Disable Constrained Directional Enhancement Filter (default)").set(enableCDEF, false), 259 | option("--enable-cdef").doc("Enable Constrained Directional Enhancement Filter").set(enableCDEF, true), 260 | option("--disable-loop-restoration").doc("Disable Loop Restoration Filter (default)").set(enableRestoration, false), 261 | option("--enable-loop-restoration").doc("Enable Loop Restoration Filter").set(enableRestoration, true) 262 | ); 263 | 264 | // coding parameter 265 | group codingParameters = ( 266 | option("--superblock-size").doc("Superblock size.") & (parameter("dynamic").doc("encoder determines the size automatically.").set(superblockSize, AOM_SUPERBLOCK_SIZE_DYNAMIC) | parameter("128").doc("use 128x128 superblock.").set(superblockSize, AOM_SUPERBLOCK_SIZE_128X128) | parameter("64").doc("use 64x64 superblock.").set(superblockSize, AOM_SUPERBLOCK_SIZE_64X64)), 267 | option("--tile-rows").doc("Number of tile rows") & integer("0-6", tileRows), 268 | option("--tile-columns").doc("Number of tile columns") & integer("0-6", tileColumns), 269 | option("--keyframe-temporal-filter").doc("Enable temporal filtering on key frame") & (parameter("disable").set(keyframeTemporalFilter, 0) | parameter("without-overlay").set(keyframeTemporalFilter, 1) | parameter("with-overlay").set(keyframeTemporalFilter, 2)), 270 | option("--enable-rect-partitions").doc("enable rectangular partitions (default)").set(enableRectPartition, true), 271 | option("--disable-rect-partitions").doc("disable rectangular partitions").set(enableRectPartition, false), 272 | option("--enable-ab-partitions").doc("enable ab partitions (default)").set(enableABPartition, true), 273 | option("--disable-ab-partitions").doc("disable ab partitions").set(enableABPartition, false), 274 | option("--disable-1to4-partitions").doc("enable 1to4 partitions (default)").set(enable1to4Partition, true), 275 | option("--enable-1to4-partitions").doc("disable 1to4 partitions").set(enable1to4Partition, false), 276 | option("--enable-intra-edge-filter").doc("enable intra edge filter (default)").set(enableIntraEdgeFilter, true), 277 | option("--disable-intra-edge-filter").doc("disable intra edge filter").set(enableIntraEdgeFilter, false), 278 | option("--min-partition-size").doc("min partition size") & (parameter("4").set(minPartitionSize, 4) | parameter("8").set(minPartitionSize, 8) | parameter("16").set(minPartitionSize, 16) | parameter("32").set(minPartitionSize, 32) | parameter("64").set(minPartitionSize, 64) | parameter("128").set(minPartitionSize, 128)), 279 | option("--max-partition-size").doc("max partition size") & (parameter("4").set(maxPartitionSize, 4) | parameter("8").set(maxPartitionSize, 8) | parameter("16").set(maxPartitionSize, 16) | parameter("32").set(maxPartitionSize, 32) | parameter("64").set(maxPartitionSize, 64) | parameter("128").set(maxPartitionSize, 128)), 280 | option("--enable-tx64").doc("enable 64-length transforms (default)").set(enableTX64, true), 281 | option("--disable-tx64").doc("disable 64-length transforms").set(enableTX64, false), 282 | option("--enable-flip-idtx").doc("enable flip and identity transforms (default)").set(enableFlipIDTX, true), 283 | option("--disable-flip-idtx").doc("disable flip and identity transforms").set(enableFlipIDTX, false), 284 | option("--enable-rect-tx").doc("enable rectangular transforms (default)").set(enableRectTX, true), 285 | option("--disable-rect-tx").doc("disable rectangular transforms").set(enableRectTX, false), 286 | option("--use-dct-only").doc("Use DCT tx onlyq").set(useDCTOnly, true), 287 | option("--use-default-tx-only").doc("use default tx type only").set(useDefaultTXOnly, true), 288 | option("--use-reduced-tx-set").doc("use reduced tx set, transforms w/o flip (4) + Identity (1).").set(useReducedTXSet, true), 289 | option("--enable-filter-intra").doc("enable (default)").set(enableFilterIntra, true), 290 | option("--disable-filter-intra").doc("disable ").set(enableFilterIntra, false), 291 | option("--enable-smooth-intra").doc("enable (default)").set(enableSmoothIntra, true), 292 | option("--disable-smooth-intra").doc("disable ").set(enableSmoothIntra, false), 293 | option("--enable-paeth-intra").doc("enable (default)").set(enablePaethIntra, true), 294 | option("--disable-paeth-intra").doc("disable ").set(enablePaethIntra, false), 295 | option("--enable-chroma-from-luma").doc("enable (default)").set(enableChromaFromLuma, true), 296 | option("--disable-chroma-from-luma").doc("disable ").set(enableChromaFromLuma, false), 297 | option("--enable-superres").doc("enable frame superresolution (default)").set(enableSuperres, true), 298 | option("--disable-superres").doc("disable frame superresolution").set(enableSuperres, false), 299 | option("--enable-palette").doc("enable palette mode").set(enablePalette, true), 300 | option("--disable-palette").doc("disable palette mode (default)").set(enablePalette, false), 301 | option("--enable-intrabc").doc("enable intra block copy mode (default)").set(enableIntraBC, true), 302 | option("--disable-intrabc").doc("disable intra block copy mode").set(enableIntraBC, false), 303 | option("--enable-angle-delta").doc("enable intra angle delta (default)").set(enableAngleDelta, true), 304 | option("--disable-angle-delta").doc("disable intra angle delta").set(enableAngleDelta, false), 305 | option("--enable-diagonal-intra").doc("enable usage of D45 to D203 intra modes (default)").set(enableDiagonalIntra, true), 306 | option("--disable-diagonal-intra").doc("disable usage of D45 to D203 intra modes").set(enableDiagonalIntra, false), 307 | option("--enable-directional-intra").doc("turn on directional intra mode (default)").set(enableDiagonalIntra, true), 308 | option("--disable-directional-intra").doc("turn off directional intra mode").set(enableDiagonalIntra, false), 309 | option("--enable-tx-size-search").doc("turn on transform size search (default). Transforms always have the largest possible size").set(enableTxSizeSearch, true), 310 | option("--disable-tx-size-search").doc("turn off transform size search. Search for the best transform size for each block").set(enableTxSizeSearch, false) 311 | ); 312 | 313 | //auto partitioning = ( 314 | //); 315 | 316 | return (io, meta, av1, color, scales, pixelAndColor, multiThreading, rateControl, preProcess, postProcess, codingParameters) | support; 317 | } 318 | 319 | void Config::validateBeforeLoad() const { 320 | if(input == output) { 321 | throw std::invalid_argument("Input and output can't be the same file!"); 322 | } 323 | if(!endsWith(input, ".png")) { 324 | throw std::invalid_argument("please give png file for input"); 325 | } 326 | if(!endsWith(output, ".avif")) { 327 | throw std::invalid_argument("please give avif file for output"); 328 | } 329 | if( 330 | (colorPrimaries.has_value() || transferCharacteristics.has_value() || matrixCoefficients.has_value()) && 331 | !(colorPrimaries.has_value() && transferCharacteristics.has_value() && matrixCoefficients.has_value()) 332 | ) { 333 | throw std::invalid_argument("All of (or none of) --color-primaries, --transfer-characteristics and --matrix-coefficients should be set."); 334 | } 335 | if( 336 | (cropSize.has_value() || cropOffset.has_value()) && 337 | !(cropSize.has_value() && cropOffset.has_value()) 338 | ) { 339 | throw std::invalid_argument("both crop-size and crop-offset must be set."); 340 | } 341 | 342 | } 343 | 344 | void Config::validateAfterLoad(const uint32_t width, const uint32_t height) const { 345 | /* 346 | ISO/IEC 23000-22:2019/Amd. 2:2021(E) 347 | 348 | 7.3.6.7 349 | Replace the text with the following: 350 | The clean aperture (cropping) property may be associated with any image and shall be supported by 351 | the MIAF reader. The clean aperture property is restricted according to the chroma sampling format of 352 | the input image (4:4:4, 4:2:2:, 4:2:0, or 4:0:0) as follows: 353 | — cleanApertureWidth and cleanApertureHeight shall be integers; 354 | — The leftmost pixel and the topmost line of the clean aperture as defined in ISO/IEC 14496-12:2020, 355 | Section 12.1.4.1 shall be integers; 356 | — If chroma is subsampled horizontally (i.e., 4:2:2 and 4:2:0), the leftmost pixel of the clean aperture 357 | shall be even numbers; 358 | — If chroma is subsampled vertically (i.e., 4:2:0), the topmost line of the clean aperture shall be even 359 | numbers. 360 | */ 361 | if(cropSize.has_value() && cropOffset.has_value()) { 362 | using avif::math::Fraction; 363 | auto const [cropWidth, cropHeight] = this->cropSize.value(); 364 | auto const [offX, offY] = this->cropOffset.value(); 365 | if (!(cropWidth.isInteger() && cropHeight.isInteger())) { 366 | throw std::invalid_argument("crop size must be integers."); 367 | } 368 | // ISO/IEC 14496-12:2015(E) 369 | // p.157 370 | auto const left = 371 | Fraction(static_cast(width - 1),2).reduce() 372 | .add(offX) 373 | .minus(cropWidth.minus(Fraction(1,1)).div(2)); 374 | auto const top = 375 | Fraction(static_cast(height - 1),2).reduce() 376 | .add(offY) 377 | .minus(cropHeight.minus(Fraction(1,1)).div(2)); 378 | if(!left.isInteger()) { 379 | throw std::invalid_argument("The leftmost pixel must be an integer."); 380 | } 381 | if(!top.isInteger()) { 382 | throw std::invalid_argument("The topmost pixel must be an integer."); 383 | } 384 | if(pixFmt == AOM_IMG_FMT_I420 || pixFmt == AOM_IMG_FMT_I422) { 385 | if(left.numerator() % 2 != 0) { 386 | throw std::invalid_argument("The leftmost pixel must be an even."); 387 | } 388 | } 389 | if(pixFmt == AOM_IMG_FMT_I420) { 390 | if(top.numerator() % 2 != 0) { 391 | throw std::invalid_argument("The topmost pixel must be an even."); 392 | } 393 | } 394 | } 395 | } 396 | 397 | std::optional Config::calcColorProfile() const { 398 | avif::img::ColorProfile profile; 399 | profile.cicp = std::make_optional(); 400 | if(colorPrimaries.has_value() && transferCharacteristics.has_value() && matrixCoefficients.has_value()) { 401 | profile.cicp->colourPrimaries = static_cast(colorPrimaries.value()); 402 | profile.cicp->transferCharacteristics = static_cast(transferCharacteristics.value()); 403 | profile.cicp->colourPrimaries = static_cast(colorPrimaries.value()); 404 | } 405 | profile.cicp->fullRangeFlag = fullColorRange; 406 | return profile; 407 | } 408 | 409 | void Config::modify(aom_codec_ctx_t* aom, avif::img::ColorProfile const& colorProfile) { 410 | // MEMO(ledyba-z): These qp offset parameters are only used in video. 411 | //codec.use_fixed_qp_offsets = 1; 412 | //codec.fixed_qp_offsets[0] = 0; 413 | 414 | #define set(param, expr) \ 415 | if(aom_codec_control(aom, param, (expr)) != AOM_CODEC_OK) { \ 416 | throw std::invalid_argument(std::string("Failed to set [" #param "] : ") + aom_codec_error_detail(aom)); \ 417 | } 418 | 419 | (void)AOME_USE_REFERENCE; // It's for movies.(Anyway, it's not used in current libaom) 420 | 421 | //FIXME: not implemented yet at libaom. 422 | // It can be useful for manga images. 423 | //aom_codec_control(codec, AOME_SET_ROI_MAP, ...); 424 | (void)AOME_SET_ROI_MAP; 425 | 426 | (void)AOME_SET_ACTIVEMAP; // FIXME(ledyba-z): Not used currently. 427 | if(!(scaleMode.h_scaling_mode == AOME_NORMAL && scaleMode.v_scaling_mode == AOME_NORMAL)) { 428 | set(AOME_SET_SCALEMODE, &scaleMode); 429 | } 430 | (void)AOME_SET_SPATIAL_LAYER_ID; // for adaptive video decoding (such as for Netflix or Youtube). 431 | set(AOME_SET_CPUUSED, cpuUsed); 432 | set(AOME_SET_SHARPNESS, sharpness); 433 | (void)AOME_SET_ENABLEAUTOALTREF; // is used only in 2nd pass(thus, it's for video). 434 | (void)AOME_SET_ENABLEAUTOBWDREF; // is for video (bwd-pred frames). 435 | (void)AOME_SET_STATIC_THRESHOLD; // TODO: Not used. I don't know it's for key-frame or not. 436 | (void)AOME_SET_ARNR_MAXFRAMES; // is for video. 437 | (void)AOME_SET_ARNR_STRENGTH; // is for video. 438 | set(AOME_SET_TUNING, tune); 439 | set(AOME_SET_CQ_LEVEL, crf); 440 | // It always can be 0(unlimited) for AVIF. 441 | set(AOME_SET_MAX_INTRA_BITRATE_PCT, 0); 442 | (void)AOME_SET_NUMBER_SPATIAL_LAYERS; // for video 443 | (void)AV1E_SET_MAX_INTER_BITRATE_PCT; // for video 444 | (void)AV1E_SET_GF_CBR_BOOST_PCT; // for video.(I don't know what Golden Frame actually means) 445 | set(AV1E_SET_LOSSLESS, lossless ? 1 : 0); 446 | set(AV1E_SET_ROW_MT, rowMT ? 1 : 0); 447 | set(AV1E_SET_TILE_ROWS, tileRows); 448 | set(AV1E_SET_TILE_COLUMNS, tileColumns); 449 | (void)AV1E_SET_ENABLE_TPL_MODEL; // is for video. 450 | set(AV1E_SET_ENABLE_KEYFRAME_FILTERING, keyframeTemporalFilter); 451 | (void)AV1E_SET_FRAME_PARALLEL_DECODING; // is for video. we have just one frame. Finally, we just encode. 452 | (void)AV1E_SET_ERROR_RESILIENT_MODE; // is for video. 453 | (void)AV1E_SET_S_FRAME_MODE; // is for video. 454 | set(AV1E_SET_AQ_MODE, adaptiveQuantizationMode); 455 | (void)AV1E_SET_FRAME_PERIODIC_BOOST; // is for video. 456 | 457 | //FIXME(ledyba-z): it can be set, but not used. 458 | // To check, `grep -R 'oxcf->noise_sensitivity' external/libaom/av1` 459 | // (updated at 2021/11: it is used, but guarded by OUTPUT_YUV_DENOISED, which is not documented yet. 460 | // set(AV1E_SET_NOISE_SENSITIVITY, 0); 461 | 462 | set(AV1E_SET_TUNE_CONTENT, contentType); 463 | 464 | (void)AV1E_SET_CDF_UPDATE_MODE; // is for video. 465 | 466 | set(AV1E_SET_COLOR_PRIMARIES, colorProfile.cicp->colourPrimaries); 467 | set(AV1E_SET_TRANSFER_CHARACTERISTICS, colorProfile.cicp->transferCharacteristics); 468 | set(AV1E_SET_MATRIX_COEFFICIENTS, colorProfile.cicp->matrixCoefficients); 469 | 470 | // FIXME(ledyba-z): It's not used. see libavif-container to see our choice. 471 | (void)AV1E_SET_CHROMA_SAMPLE_POSITION; 472 | 473 | (void)AV1E_SET_MIN_GF_INTERVAL; // for video 474 | set(AV1E_SET_COLOR_RANGE, colorProfile.cicp->fullRangeFlag ? 1 : 0); 475 | (void)AV1E_SET_RENDER_SIZE; // should be the same as the output size. It's default. 476 | if(renderWidth > 0 && renderHeight > 0) { 477 | int renderSize[2] = {renderWidth, renderHeight}; 478 | set(AV1E_SET_RENDER_SIZE, renderSize); 479 | } 480 | (void)AV1E_SET_TARGET_SEQ_LEVEL_IDX; // for video. 481 | (void)AV1E_GET_SEQ_LEVEL_IDX; // for video. 482 | set(AV1E_SET_SUPERBLOCK_SIZE, superblockSize); 483 | (void)AOME_SET_ENABLEAUTOBWDREF; // is for video. 484 | 485 | set(AV1E_SET_ENABLE_CDEF, enableCDEF ? 1 : 0); 486 | set(AV1E_SET_ENABLE_RESTORATION, enableRestoration ? 1 : 0); 487 | 488 | // we are working on images. 489 | set(AV1E_SET_FORCE_VIDEO_MODE, 0); 490 | 491 | (void)AV1E_SET_ENABLE_OBMC; // is for video, motion prediction. 492 | // OBMC means "Overlapped Block Motion Compensation" 493 | // https://jmvalin.ca/papers/AV1_tools.pdf 494 | 495 | (void)AV1E_SET_DISABLE_TRELLIS_QUANT; // is for video(motion estimation). 496 | // https://en.wikipedia.org/wiki/Trellis_quantization 497 | 498 | if(useQM) { 499 | set(AV1E_SET_ENABLE_QM, 1); 500 | set(AV1E_SET_QM_MIN, qmMin); 501 | set(AV1E_SET_QM_MAX, qmMax); 502 | set(AV1E_SET_QM_Y, qmMinY); 503 | set(AV1E_SET_QM_U, qmMinU); 504 | set(AV1E_SET_QM_V, qmMinV); 505 | } 506 | 507 | set(AV1E_SET_NUM_TG, (1u << static_cast(tileRows)) + (1u << static_cast(tileColumns))); 508 | 509 | (void)AV1E_SET_MTU; // is not needed to set, because AV1E_SET_NUM_TG is already set. 510 | set(AV1E_SET_ENABLE_RECT_PARTITIONS, enableRectPartition ? 1 : 0); 511 | set(AV1E_SET_ENABLE_AB_PARTITIONS, enableABPartition ? 1 : 0); 512 | set(AV1E_SET_ENABLE_1TO4_PARTITIONS, enable1to4Partition ? 1 : 0); 513 | set(AV1E_SET_MIN_PARTITION_SIZE, minPartitionSize); 514 | set(AV1E_SET_MAX_PARTITION_SIZE, maxPartitionSize); 515 | set(AV1E_SET_ENABLE_INTRA_EDGE_FILTER, enableIntraEdgeFilter ? 1 : 0); 516 | (void)AV1E_SET_ENABLE_ORDER_HINT; // is for video 517 | set(AV1E_SET_ENABLE_TX64, enableTX64 ? 1 : 0); 518 | set(AV1E_SET_ENABLE_FLIP_IDTX, enableFlipIDTX ? 1 : 0); 519 | set(AV1E_SET_ENABLE_RECT_TX, enableRectTX ? 1 : 0); 520 | (void)AV1E_SET_ENABLE_DIST_WTD_COMP; // is for video 521 | (void)AV1E_SET_ENABLE_REF_FRAME_MVS; // is for video 522 | (void)AV1E_SET_ALLOW_REF_FRAME_MVS; // is for video 523 | set(AV1E_SET_ENABLE_DUAL_FILTER, 0); 524 | set(AV1E_SET_ENABLE_CHROMA_DELTAQ, enableChromaDeltaQ ? 1 : 0); 525 | (void)AV1E_SET_ENABLE_MASKED_COMP; // is for video 526 | (void)AV1E_SET_ENABLE_ONESIDED_COMP; // is for video 527 | (void)AV1E_SET_ENABLE_INTERINTRA_COMP; // is for video 528 | (void)AV1E_SET_ENABLE_SMOOTH_INTERINTRA; // is for video 529 | (void)AV1E_SET_ENABLE_DIFF_WTD_COMP; // is for video 530 | (void)AV1E_SET_ENABLE_INTERINTER_WEDGE; // is for video 531 | (void)AV1E_SET_ENABLE_GLOBAL_MOTION; // is for video 532 | set(AV1E_SET_ENABLE_GLOBAL_MOTION, 0); // we are working on images. 533 | set(AV1E_SET_ENABLE_WARPED_MOTION, 0); // we are working on images. 534 | set(AV1E_SET_ALLOW_WARPED_MOTION, 0); // we are working on images. 535 | set(AV1E_SET_ENABLE_FILTER_INTRA, enableFilterIntra ? 1 : 0); 536 | set(AV1E_SET_ENABLE_SMOOTH_INTRA, enableSmoothIntra ? 1 : 0); 537 | set(AV1E_SET_ENABLE_PAETH_INTRA, enablePaethIntra ? 1 : 0); 538 | set(AV1E_SET_ENABLE_CFL_INTRA, enableChromaFromLuma ? 1 : 0); 539 | set(AV1E_SET_ENABLE_SUPERRES, enableSuperres ? 1 : 0); 540 | (void)AV1E_SET_ENABLE_OVERLAY; // is for video. 541 | set(AV1E_SET_ENABLE_PALETTE, enablePalette ? 1 : 0); 542 | set(AV1E_SET_ENABLE_INTRABC, enableIntraBC ? 1 : 0); 543 | set(AV1E_SET_DELTAQ_MODE, deltaQMode); 544 | set(AV1E_SET_DELTALF_MODE, enableDeltaLoopFilter ? 1 : 0); 545 | (void)AV1E_SET_SINGLE_TILE_DECODING; // We are working on encoding. 546 | (void)AV1E_ENABLE_MOTION_VECTOR_UNIT_TEST; // is for video. 547 | (void)AV1E_SET_TIMING_INFO_TYPE; // is for video. 548 | (void)AV1E_SET_FILM_GRAIN_TEST_VECTOR; // is for testing 549 | (void)AV1E_SET_FILM_GRAIN_TABLE; // can be supported, but it is mainly for video. 550 | (void)AV1E_SET_DENOISE_NOISE_LEVEL; // can be supported, but it is mainly for video. 551 | (void)AV1E_SET_DENOISE_BLOCK_SIZE; // can be supported, but it is mainly for video. 552 | set(AV1E_SET_REDUCED_TX_TYPE_SET, useReducedTXSet ? 1 : 0); 553 | set(AV1E_SET_INTRA_DCT_ONLY, useDCTOnly ? 1 : 0); 554 | set(AV1E_SET_INTRA_DEFAULT_TX_ONLY, useDefaultTXOnly ? 1 : 0); 555 | set(AV1E_SET_QUANT_B_ADAPT, enableAdaptiveQuantizationB ? 1 : 0); 556 | (void)AV1E_SET_GF_MAX_PYRAMID_HEIGHT; // is for video. 557 | (void)AV1E_SET_MAX_REFERENCE_FRAMES; // is for video. 558 | (void)AV1E_SET_REDUCED_REFERENCE_SET; // is for video. 559 | (void)AV1E_SET_COEFF_COST_UPD_FREQ; // may be for video, because it mentions tile decoding. 560 | (void)AV1E_SET_MODE_COST_UPD_FREQ; // may be for video, because it mentions tile decoding. 561 | (void)AV1E_SET_MV_COST_UPD_FREQ; // may be for video, because it mentions tile decoding. 562 | (void)AV1E_SET_TIER_MASK; // for video, because still picture always has 1 control point. 563 | (void)AV1E_SET_MIN_CR; // is for video. My GDB says that. 564 | (void)AV1E_SET_SVC_LAYER_ID; // is for video. 565 | (void)AV1E_SET_SVC_PARAMS; // is for video. 566 | (void)AV1E_SET_SVC_REF_FRAME_CONFIG; // is for video. 567 | if(!vmafModelPath.empty()) { 568 | set(AV1E_SET_VMAF_MODEL_PATH, vmafModelPath.c_str()); 569 | } 570 | (void)AV1E_ENABLE_EXT_TILE_DEBUG;// is for debugging. 571 | (void)AV1E_ENABLE_SB_MULTIPASS_UNIT_TEST;// is for unit test. 572 | (void)AV1E_SET_GF_MIN_PYRAMID_HEIGHT; // is for video. 573 | 574 | (void)AV1E_SET_VBR_CORPUS_COMPLEXITY_LAP; // is for video. 575 | (void)AV1E_GET_BASELINE_GF_INTERVAL; // is for video. 576 | 577 | (void)AV1E_SET_ENABLE_DNL_DENOISING; // can be supported, but it is mainly for video (used in two pass mode). 578 | 579 | set(AV1E_SET_ENABLE_DIAGONAL_INTRA, enableDiagonalIntra ? 1 : 0); 580 | 581 | (void)AV1E_SET_DV_COST_UPD_FREQ; // is for intrabc motion vectors, for video. 582 | 583 | (void)AV1E_SET_PARTITION_INFO_PATH; // TODO(ledyba-z): It seems it's not recorded for keyframes. Read more papers! 584 | 585 | if (false) { // FIXME(ledyba-z): Can be configured, but not invoked at all. Read more papers! 586 | ExternalPartitionModelFactoryContainer container(std::make_unique()); 587 | auto bridge = container.makeBridge(); 588 | set(AV1E_SET_EXTERNAL_PARTITION, &bridge); 589 | } 590 | 591 | set(AV1E_SET_ENABLE_DIRECTIONAL_INTRA, enableDirectionalIntra ? 1 : 0); 592 | set(AV1E_SET_ENABLE_TX_SIZE_SEARCH, enableTxSizeSearch ? 1 : 0); 593 | 594 | (void)AV1E_SET_SVC_REF_FRAME_COMP_PRED; // is for video. 595 | 596 | set(AV1E_SET_DELTAQ_STRENGTH, deltaQStrength); 597 | set(AV1E_SET_LOOPFILTER_CONTROL, enableLoopFilter ? LOOPFILTER_ALL : LOOPFILTER_NONE); 598 | 599 | #undef set 600 | } 601 | -------------------------------------------------------------------------------- /src/Config.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by psi on 2020/01/14. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "../external/clipp/include/clipp.h" 19 | 20 | class Config final { 21 | public: 22 | std::string commandName{}; 23 | bool showHelp = false; 24 | public: 25 | std::string input{}; 26 | std::optional alphaInput{}; 27 | std::optional depthInput{}; 28 | std::string output{}; 29 | enum EncodeTarget { 30 | Image, 31 | Alpha 32 | }; 33 | EncodeTarget encodeTarget = EncodeTarget::Image; 34 | bool showResult = false; 35 | public: 36 | // meta 37 | std::optional rotation{}; 38 | std::optional mirrorAxis{}; 39 | std::optional> cropSize{}; 40 | std::optional> cropOffset{}; 41 | // color 42 | std::optional colorPrimaries = {}; 43 | std::optional transferCharacteristics = {}; 44 | std::optional matrixCoefficients = {}; 45 | // encoding 46 | aom_codec_enc_cfg codec = {}; 47 | aom_scaling_mode_t scaleMode = { 48 | .h_scaling_mode = AOME_NORMAL, 49 | .v_scaling_mode = AOME_NORMAL, 50 | }; 51 | int renderWidth = 0; 52 | int renderHeight = 0; 53 | aom_img_fmt_t pixFmt = AOM_IMG_FMT_I420; 54 | int crf = 10; 55 | int deltaQMode = 0; 56 | int deltaQStrength = 100; 57 | bool enableChromaDeltaQ = false; 58 | bool enableLoopFilter = true; 59 | bool enableDeltaLoopFilter = false; 60 | bool useQM = false; 61 | int qmMin = DEFAULT_QM_FIRST; 62 | int qmMax = DEFAULT_QM_LAST; 63 | int qmMinY = DEFAULT_QM_Y; 64 | int qmMinU = DEFAULT_QM_U; 65 | int qmMinV = DEFAULT_QM_V; 66 | bool enableRectPartition = true; 67 | bool enableABPartition = true; 68 | bool enable1to4Partition = true; 69 | int minPartitionSize = 4; 70 | int maxPartitionSize = 128; 71 | bool rowMT = false; 72 | int cpuUsed = 1; 73 | int sharpness = 0; 74 | int tileRows = 0; 75 | int tileColumns = 0; 76 | int keyframeTemporalFilter = 0; 77 | bool enableIntraEdgeFilter = true; 78 | bool enableTX64 = true; 79 | bool enableFlipIDTX = true; 80 | bool enableRectTX = true; 81 | bool useDCTOnly = false; 82 | bool useDefaultTXOnly = false; 83 | bool useReducedTXSet = false; 84 | int adaptiveQuantizationMode = NO_AQ; 85 | aom_tune_content contentType = AOM_CONTENT_DEFAULT; 86 | bool enableAdaptiveQuantizationB = false; 87 | bool enableFilterIntra = true; 88 | bool enableSmoothIntra = true; 89 | bool enablePaethIntra = true; 90 | bool enableChromaFromLuma = true; 91 | bool enableSuperres = true; 92 | bool enablePalette = false; 93 | bool enableIntraBC = true; 94 | bool enableAngleDelta = true; 95 | bool enableDiagonalIntra = true; 96 | bool enableDirectionalIntra = true; 97 | bool enableTxSizeSearch = true; 98 | bool lossless = false; 99 | bool enableCDEF = false; 100 | bool enableRestoration = false; 101 | bool fullColorRange = true; 102 | aom_superblock_size_t superblockSize = AOM_SUPERBLOCK_SIZE_DYNAMIC; 103 | aom_tune_metric tune = AOM_TUNE_SSIM; 104 | std::string vmafModelPath = "/usr/share/cavif/model/vmaf_v0.6.1.pkl"; 105 | public: 106 | Config() = delete; 107 | Config(Config&&) noexcept = default; 108 | Config(Config const&) = default; 109 | Config& operator=(Config&&) noexcept = default; 110 | Config& operator=(Config const&) = default; 111 | Config(int argc, char** argv); 112 | 113 | private: 114 | int argc{}; 115 | char** argv{}; 116 | clipp::group commandLineFlags{}; 117 | clipp::group createCommandLineFlags(); 118 | public: 119 | void usage(); 120 | bool parse(); 121 | void validateBeforeLoad() const; 122 | void validateAfterLoad(uint32_t width, uint32_t height) const; 123 | void modify(aom_codec_ctx_t* aom, avif::img::ColorProfile const& colorProfile); 124 | 125 | public: 126 | [[nodiscard]] std::optional calcColorProfile() const; 127 | }; 128 | -------------------------------------------------------------------------------- /src/ext/ExternalPartitionModel.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by psi on 2021/12/04. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | class ExternalPartitionModel { 11 | public: 12 | virtual ~ExternalPartitionModel() noexcept = default; 13 | public: 14 | virtual void sendFeatures(aom_partition_features_t const* features) = 0; 15 | virtual void getDecision(aom_partition_decision_t *decision) = 0; 16 | virtual void sendPartitionStats(aom_partition_stats_t const* stats) = 0; 17 | }; 18 | 19 | class ExternalPartitionModelFactory { 20 | public: 21 | virtual ~ExternalPartitionModelFactory() noexcept = default; 22 | public: 23 | virtual ExternalPartitionModel* create(aom_ext_part_config_t const* part_config) = 0; 24 | virtual aom_ext_part_decision_mode_t decisionMode() = 0; 25 | }; 26 | -------------------------------------------------------------------------------- /src/ext/ExternalPartitionModelFactoryContainer.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by psi on 2021/12/04. 3 | // 4 | 5 | #include "ExternalPartitionModelFactoryContainer.hpp" 6 | #include "ExternalPartitionModel.hpp" 7 | 8 | ExternalPartitionModelFactoryContainer::ExternalPartitionModelFactoryContainer(std::unique_ptr factory) 9 | :factory_(std::move(factory)) 10 | { 11 | } 12 | 13 | aom_ext_part_funcs_t ExternalPartitionModelFactoryContainer::makeBridge() { 14 | aom_ext_part_funcs_t bridge; 15 | bridge.create_model = ExternalPartitionModelFactoryContainer::create_model_; 16 | bridge.delete_model = ExternalPartitionModelFactoryContainer::delete_model_; 17 | bridge.send_features = ExternalPartitionModelFactoryContainer::send_features_; 18 | bridge.get_partition_decision = ExternalPartitionModelFactoryContainer::get_partition_decision_; 19 | bridge.send_partition_stats = ExternalPartitionModelFactoryContainer::send_partition_stats_; 20 | bridge.decision_mode = this->factory_->decisionMode(); 21 | bridge.priv = reinterpret_cast(this); 22 | return bridge; 23 | } 24 | 25 | aom_ext_part_status_t ExternalPartitionModelFactoryContainer::create_model_( 26 | void *priv, 27 | const aom_ext_part_config_t *part_config, 28 | aom_ext_part_model_t *ext_part_model 29 | ) { 30 | auto self = reinterpret_cast(priv); 31 | *ext_part_model = reinterpret_cast(self->factory_->create(part_config)); 32 | return AOM_EXT_PART_OK; 33 | } 34 | 35 | aom_ext_part_status_t ExternalPartitionModelFactoryContainer::delete_model_( 36 | aom_ext_part_model_t ext_part_model) 37 | { 38 | auto model = reinterpret_cast(ext_part_model); 39 | delete model; 40 | return AOM_EXT_PART_OK; 41 | } 42 | 43 | aom_ext_part_status_t ExternalPartitionModelFactoryContainer::send_features_( 44 | aom_ext_part_model_t ext_part_model, 45 | const aom_partition_features_t *part_features 46 | ) { 47 | auto model = reinterpret_cast(ext_part_model); 48 | model->sendFeatures(part_features); 49 | return AOM_EXT_PART_OK; 50 | } 51 | 52 | aom_ext_part_status_t ExternalPartitionModelFactoryContainer::get_partition_decision_( 53 | aom_ext_part_model_t ext_part_model, 54 | aom_partition_decision_t *ext_part_decision) 55 | { 56 | auto model = reinterpret_cast(ext_part_model); 57 | model->getDecision(ext_part_decision); 58 | return AOM_EXT_PART_OK; 59 | } 60 | 61 | aom_ext_part_status_t ExternalPartitionModelFactoryContainer::send_partition_stats_( 62 | aom_ext_part_model_t ext_part_model, 63 | const aom_partition_stats_t *ext_part_stats 64 | ) { 65 | auto model = reinterpret_cast(ext_part_model); 66 | model->sendPartitionStats(ext_part_stats); 67 | return AOM_EXT_PART_OK; 68 | } 69 | -------------------------------------------------------------------------------- /src/ext/ExternalPartitionModelFactoryContainer.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by psi on 2021/12/04. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | class ExternalPartitionModel; 11 | class ExternalPartitionModelFactory; 12 | 13 | class ExternalPartitionModelFactoryContainer final { 14 | public: 15 | explicit ExternalPartitionModelFactoryContainer(std::unique_ptr factory); 16 | ExternalPartitionModelFactoryContainer() = default; 17 | ExternalPartitionModelFactoryContainer(ExternalPartitionModelFactoryContainer&&) noexcept = default; 18 | ExternalPartitionModelFactoryContainer(ExternalPartitionModelFactoryContainer const&) = delete; 19 | ExternalPartitionModelFactoryContainer& operator=(ExternalPartitionModelFactoryContainer&&) = default; 20 | ExternalPartitionModelFactoryContainer& operator=(ExternalPartitionModelFactoryContainer const&) = delete; 21 | ~ExternalPartitionModelFactoryContainer() noexcept = default; 22 | 23 | public: 24 | aom_ext_part_funcs_t makeBridge(); 25 | private: 26 | std::unique_ptr factory_; 27 | private: 28 | static aom_ext_part_status_t create_model_( 29 | void *priv, const aom_ext_part_config_t *part_config, 30 | aom_ext_part_model_t *ext_part_model); 31 | static aom_ext_part_status_t delete_model_(aom_ext_part_model_t ext_part_model); 32 | 33 | static aom_ext_part_status_t send_features_( 34 | aom_ext_part_model_t ext_part_model, 35 | const aom_partition_features_t *part_features); 36 | 37 | static aom_ext_part_status_t get_partition_decision_( 38 | aom_ext_part_model_t ext_part_model, 39 | aom_partition_decision_t *ext_part_decision); 40 | 41 | static aom_ext_part_status_t send_partition_stats_( 42 | aom_ext_part_model_t ext_part_model, 43 | const aom_partition_stats_t *ext_part_stats); 44 | }; 45 | -------------------------------------------------------------------------------- /src/ext/models/NonSplitPartitionModel.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by psi on 2021/12/11. 3 | // 4 | 5 | #include 6 | #include "NonSplitPartitionModel.hpp" 7 | 8 | NonSplitPartitionModelFactory::~NonSplitPartitionModelFactory() noexcept = default; 9 | 10 | ExternalPartitionModel* NonSplitPartitionModelFactory::create(aom_ext_part_config_t const* part_config) { 11 | return new NonSplitPartitionModel(part_config); 12 | } 13 | 14 | aom_ext_part_decision_mode_t NonSplitPartitionModelFactory::decisionMode() { 15 | return AOM_EXT_PART_WHOLE_TREE; 16 | } 17 | 18 | /* 19 | * NonSplitPartitionModel 20 | */ 21 | 22 | NonSplitPartitionModel::NonSplitPartitionModel(aom_ext_part_config_t const* part_config) 23 | :partitionConfig_(*part_config) 24 | { 25 | } 26 | 27 | NonSplitPartitionModel::~NonSplitPartitionModel() noexcept = default; 28 | 29 | void NonSplitPartitionModel::sendFeatures(aom_partition_features_t const* features) { 30 | // ignore. 31 | } 32 | 33 | void NonSplitPartitionModel::getDecision(aom_partition_decision_t* dst) { 34 | aom_partition_decision_t decision = {}; 35 | decision.is_final_decision = true; 36 | *dst = decision; 37 | } 38 | 39 | void NonSplitPartitionModel::sendPartitionStats(aom_partition_stats_t const* stats) { 40 | // ignore. 41 | } 42 | -------------------------------------------------------------------------------- /src/ext/models/NonSplitPartitionModel.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by psi on 2021/12/11. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "../ExternalPartitionModel.hpp" 8 | 9 | class NonSplitPartitionModel final : public ExternalPartitionModel{ 10 | private: 11 | aom_ext_part_config_t const partitionConfig_; 12 | public: 13 | NonSplitPartitionModel(aom_ext_part_config_t const* part_config); 14 | public: 15 | ~NonSplitPartitionModel() noexcept override; 16 | 17 | void sendFeatures(aom_partition_features_t const* features) override; 18 | 19 | void getDecision(aom_partition_decision_t* decision) override; 20 | 21 | void sendPartitionStats(aom_partition_stats_t const* stats) override; 22 | }; 23 | 24 | class NonSplitPartitionModelFactory final: public ExternalPartitionModelFactory { 25 | public: 26 | ~NonSplitPartitionModelFactory() noexcept override; 27 | ExternalPartitionModel* create(aom_ext_part_config_t const* part_config) override; 28 | aom_ext_part_decision_mode_t decisionMode() override; 29 | }; 30 | -------------------------------------------------------------------------------- /src/img/Conversion.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by psi on 2020/01/18. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using MatrixCoefficients = avif::img::color::MatrixCoefficients; 14 | 15 | namespace detail { 16 | 17 | template 18 | void convertImage(avif::img::Image& src, aom_image& dst) { 19 | if(dst.monochrome) { 20 | avif::img::FromRGB::toI400( 21 | src, 22 | dst.planes[0], dst.stride[0]); 23 | } else { 24 | switch (dst.fmt) { 25 | case AOM_IMG_FMT_I420: 26 | case AOM_IMG_FMT_I42016: 27 | avif::img::FromRGB::toI420( 28 | src, 29 | dst.planes[0], dst.stride[0], 30 | dst.planes[1], dst.stride[1], 31 | dst.planes[2], dst.stride[2]); 32 | break; 33 | case AOM_IMG_FMT_I422: 34 | case AOM_IMG_FMT_I42216: 35 | avif::img::FromRGB::toI422( 36 | src, 37 | dst.planes[0], dst.stride[0], 38 | dst.planes[1], dst.stride[1], 39 | dst.planes[2], dst.stride[2]); 40 | break; 41 | case AOM_IMG_FMT_I444: 42 | case AOM_IMG_FMT_I44416: 43 | avif::img::FromRGB::toI444( 44 | src, 45 | dst.planes[0], dst.stride[0], 46 | dst.planes[1], dst.stride[1], 47 | dst.planes[2], dst.stride[2]); 48 | break; 49 | default: 50 | throw std::invalid_argument(fmt::format("Unsupported image format: {:08x}", dst.fmt)); 51 | } 52 | } 53 | } 54 | 55 | template 56 | void convertImage(avif::img::Image& src, aom_image& dst) { 57 | if(dst.range == AOM_CR_FULL_RANGE) { 58 | convertImage(src, dst); 59 | } else { 60 | convertImage(src, dst); 61 | } 62 | } 63 | 64 | template 65 | void convertImage(avif::img::Image& src, aom_image& dst) { 66 | if(src.isMonochrome()) { 67 | convertImage(src, dst); 68 | } else { 69 | convertImage(src, dst); 70 | } 71 | } 72 | 73 | template 74 | void convertAlpha(avif::img::Image& src, aom_image& dst) { 75 | if (dst.monochrome) { 76 | avif::img::FromAlpha::toI400( 77 | src, 78 | dst.planes[0], dst.stride[0]); 79 | } else { 80 | throw std::invalid_argument("Alpha image should be monochrome. Please add --monochrome option."); 81 | } 82 | } 83 | 84 | template 85 | void convertAlpha(avif::img::Image& src, aom_image& dst) { 86 | if(dst.range == AOM_CR_FULL_RANGE) { 87 | convertAlpha(src, dst); 88 | } else { 89 | convertAlpha(src, dst); 90 | } 91 | } 92 | 93 | } 94 | 95 | template 96 | void convert(avif::img::Image& src, aom_image& dst) { 97 | switch (target) { 98 | case Config::EncodeTarget::Image: 99 | detail::convertImage(src, dst); 100 | break; 101 | case Config::EncodeTarget::Alpha: 102 | detail::convertAlpha(src, dst); 103 | break; 104 | default: 105 | throw std::invalid_argument(fmt::format("Unsupported EncodeTarget: {}", target)); 106 | } 107 | } 108 | 109 | template 110 | void convert(avif::img::Image& src, aom_image& dst) { 111 | switch (dst.bit_depth) { 112 | case 8: 113 | convert(src, dst); 114 | break; 115 | case 10: 116 | convert(src, dst); 117 | break; 118 | case 12: 119 | convert(src, dst); 120 | break; 121 | default: 122 | throw std::invalid_argument(fmt::format("Unsupported YUV bit-depth: {}", dst.bit_depth)); 123 | } 124 | } 125 | 126 | template 127 | void convert(Config& config, avif::img::Image& src, aom_image& dst) { 128 | switch (config.encodeTarget) { 129 | case Config::EncodeTarget::Image: 130 | convert(src, dst); 131 | break; 132 | case Config::EncodeTarget::Alpha: 133 | convert(src, dst); 134 | break; 135 | default: 136 | assert(false && "[BUG] Unknown encoder target."); 137 | } 138 | } 139 | 140 | template 141 | void convert(Config& config, avif::img::Image& src, aom_image& dst) { 142 | aom_img_fmt_t const pixFmt = 143 | config.codec.g_bit_depth == 8 ? 144 | config.pixFmt : 145 | static_cast(config.pixFmt | static_cast(AOM_IMG_FMT_HIGHBITDEPTH)); 146 | aom_img_alloc(&dst, pixFmt, src.width(), src.height(), 1); 147 | avif::ColourInformationBox::CICP const cicp = src.colorProfile().cicp.value_or(avif::ColourInformationBox::CICP()); 148 | dst.range = cicp.fullRangeFlag ? AOM_CR_FULL_RANGE : AOM_CR_STUDIO_RANGE; 149 | dst.monochrome = config.codec.monochrome ? 1 : 0; 150 | dst.bit_depth = config.codec.g_bit_depth; 151 | 152 | switch (static_cast(src.colorProfile().cicp.value_or(avif::ColourInformationBox::CICP()).matrixCoefficients)) { 153 | case MatrixCoefficients::MC_IDENTITY: { 154 | using ConvereterType = avif::img::color::ColorConverter; 155 | convert(config, src, dst); 156 | break; 157 | } 158 | case MatrixCoefficients::MC_BT_709: { 159 | using ConvereterType = avif::img::color::ColorConverter; 160 | convert(config, src, dst); 161 | break; 162 | } 163 | case MatrixCoefficients::MC_UNSPECIFIED: { 164 | using ConvereterType = avif::img::color::ColorConverter; 165 | convert(config, src, dst); 166 | break; 167 | } 168 | case MatrixCoefficients::MC_RESERVED_3: { 169 | using ConvereterType = avif::img::color::ColorConverter; 170 | convert(config, src, dst); 171 | break; 172 | } 173 | case MatrixCoefficients::MC_FCC: { 174 | using ConvereterType = avif::img::color::ColorConverter; 175 | convert(config, src, dst); 176 | break; 177 | } 178 | case MatrixCoefficients::MC_BT_470_B_G: { 179 | using ConvereterType = avif::img::color::ColorConverter; 180 | convert(config, src, dst); 181 | break; 182 | } 183 | case MatrixCoefficients::MC_NSTC: { 184 | using ConvereterType = avif::img::color::ColorConverter; 185 | convert(config, src, dst); 186 | break; 187 | } 188 | case MatrixCoefficients::MC_SMPTE_240: { 189 | using ConvereterType = avif::img::color::ColorConverter; 190 | convert(config, src, dst); 191 | break; 192 | } 193 | case MatrixCoefficients::MC_SMPTE_YCGCO: { 194 | using ConvereterType = avif::img::color::ColorConverter; 195 | convert(config, src, dst); 196 | break; 197 | } 198 | case MatrixCoefficients::MC_BT_2020_NCL: { 199 | using ConvereterType = avif::img::color::ColorConverter; 200 | convert(config, src, dst); 201 | break; 202 | } 203 | case MatrixCoefficients::MC_BT_2020_CL:{ 204 | using ConvereterType = avif::img::color::ColorConverter; 205 | convert(config, src, dst); 206 | break; 207 | } 208 | case MatrixCoefficients::MC_SMPTE_2085:{ 209 | using ConvereterType = avif::img::color::ColorConverter; 210 | convert(config, src, dst); 211 | break; 212 | } 213 | case MatrixCoefficients::MC_CHROMAT_NCL:{ 214 | using ConvereterType = avif::img::color::ColorConverter; 215 | convert(config, src, dst); 216 | break; 217 | } 218 | case MatrixCoefficients::MC_CHROMAT_CL:{ 219 | using ConvereterType = avif::img::color::ColorConverter; 220 | convert(config, src, dst); 221 | break; 222 | } 223 | case MatrixCoefficients::MC_BT_2100_ICTCP: { 224 | using ConvereterType = avif::img::color::ColorConverter; 225 | convert(config, src, dst); 226 | break; 227 | } 228 | default: 229 | assert(false && "Unknown matrix coefficients"); 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/img/png/Reader.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by psi on 2020/01/05. 3 | // 4 | 5 | #include "Reader.hpp" 6 | #include 7 | #include 8 | #include 9 | 10 | namespace img::png { 11 | 12 | Reader::Reader(avif::util::FileLogger& log, FILE* const file, png_structp png, png_infop info) 13 | :log_(log) 14 | ,file_(file) 15 | ,png_(png) 16 | ,info_(info) 17 | { 18 | } 19 | 20 | char const* Reader::version() { 21 | return PNG_LIBPNG_VER_STRING; 22 | } 23 | 24 | Reader Reader::create(avif::util::FileLogger& log, std::string const& filename) { 25 | // See http://www.libpng.org/pub/png/libpng-manual.txt 26 | FILE* const file = fopen(filename.c_str(), "rb"); 27 | if(!file) { 28 | throw std::filesystem::filesystem_error("failed to open", filename, std::make_error_code(static_cast(errno))); 29 | } 30 | 31 | { // Check header 32 | uint8_t header[8] = {}; 33 | if (fread(header, 1, 8, file) != 8) { 34 | throw std::filesystem::filesystem_error("failed to read header", filename, std::make_error_code(static_cast(errno))); 35 | } 36 | if (png_sig_cmp(header, 0, 8)) { 37 | throw std::runtime_error(fmt::format("{} is not a valid PNG file.", filename)); 38 | } 39 | } 40 | 41 | // Create reader and retrieve info 42 | png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); 43 | if(!png) { 44 | throw std::runtime_error("failed to create png reader"); 45 | } 46 | 47 | png_infop info = png_create_info_struct(png); 48 | if(!info) { 49 | throw std::runtime_error("failed to create png info structure"); 50 | } 51 | 52 | png_init_io(png, file); 53 | png_set_sig_bytes(png, 8); 54 | 55 | return Reader(log, file, png, info); 56 | } 57 | 58 | Reader::~Reader() noexcept { 59 | // Clean up reader 60 | png_destroy_read_struct(&png_, &info_, nullptr); 61 | // Close file 62 | fclose(file_); 63 | } 64 | 65 | Reader::Result Reader::read() { 66 | png_read_info(png_, info_); 67 | 68 | uint32_t const width = png_get_image_width(png_, info_); 69 | uint32_t const height = png_get_image_height(png_, info_); 70 | png_byte const colorType = png_get_color_type(png_, info_); 71 | png_byte const bitDepth = png_get_bit_depth(png_, info_); 72 | 73 | if(colorType == PNG_COLOR_TYPE_PALETTE) { 74 | png_set_palette_to_rgb(png_); 75 | } 76 | 77 | // PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth. 78 | // http://www.libpng.org/pub/png/libpng-manual.txt 79 | if(colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) { 80 | png_set_expand_gray_1_2_4_to_8(png_); 81 | } 82 | 83 | if(PNG_INFO_tRNS == png_get_valid(png_, info_, PNG_INFO_tRNS)) { 84 | png_set_tRNS_to_alpha(png_); 85 | } 86 | 87 | if(bitDepth == 16) { 88 | png_set_swap(png_); 89 | } 90 | 91 | Reader::Result result = {}; 92 | 93 | if (PNG_INFO_sRGB == png_get_valid(png_, info_, PNG_INFO_sRGB)) { 94 | int intent = {}; 95 | if(PNG_INFO_sRGB == png_get_sRGB(png_, info_, &intent)) { 96 | // indicate sRGB 97 | result.sRGB = std::monostate(); 98 | } 99 | } 100 | 101 | if (PNG_INFO_iCCP == png_get_valid(png_, info_, PNG_INFO_iCCP)) { 102 | png_charp name = {}; 103 | int compression_type = {}; 104 | png_bytep profdata = {}; 105 | png_uint_32 profLen = {}; 106 | if(PNG_INFO_iCCP == png_get_iCCP(png_, info_, &name, &compression_type, &profdata, &profLen)) { 107 | result.iccProfile = std::vector(profdata, profdata + profLen); 108 | } 109 | } 110 | 111 | if (PNG_INFO_cHRM == png_get_valid(png_, info_, PNG_INFO_cHRM)) { 112 | ColorPrimaries colorPrimaries = {}; 113 | if (PNG_INFO_cHRM == png_get_cHRM_fixed( 114 | png_, 115 | info_, 116 | &colorPrimaries.whiteX, 117 | &colorPrimaries.whiteY, 118 | &colorPrimaries.redX, 119 | &colorPrimaries.redY, 120 | &colorPrimaries.greenX, 121 | &colorPrimaries.greenY, 122 | &colorPrimaries.blueX, 123 | &colorPrimaries.blueY)) { 124 | result.colorPrimaries = colorPrimaries; 125 | } 126 | } 127 | 128 | if (PNG_INFO_gAMA == png_get_valid(png_, info_, PNG_INFO_gAMA)) { 129 | png_fixed_point gamma = {}; 130 | if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_, info_, &gamma)) { 131 | result.gamma = gamma; 132 | } 133 | } 134 | 135 | avif::img::PixelOrder pixelOrder = {}; 136 | switch(colorType) { 137 | case PNG_COLOR_TYPE_GRAY: 138 | pixelOrder = avif::img::PixelOrder::Mono; 139 | break; 140 | case PNG_COLOR_TYPE_RGB: 141 | case PNG_COLOR_TYPE_PALETTE: 142 | pixelOrder = avif::img::PixelOrder::RGB; 143 | break; 144 | case PNG_COLOR_TYPE_GRAY_ALPHA: 145 | pixelOrder = avif::img::PixelOrder::MonoA; 146 | break; 147 | case PNG_COLOR_TYPE_RGB_ALPHA: 148 | pixelOrder = avif::img::PixelOrder::RGBA; 149 | break; 150 | default: 151 | throw std::logic_error(fmt::format("Unknown color type: {}", colorType)); 152 | } 153 | size_t const bytesPerPixel = avif::img::calcNumComponents(pixelOrder) * (bitDepth / 8); 154 | png_read_update_info(png_, info_); 155 | std::vector data; 156 | data.resize(bytesPerPixel * width * height); 157 | std::vector rows; 158 | rows.resize(height); 159 | for(uint32_t y = 0; y < height; y++) { 160 | rows.at(y) = std::next(data.data(), y * bytesPerPixel * width); 161 | } 162 | png_read_image(png_, rows.data()); 163 | 164 | if(bitDepth == 16) { 165 | result.image = avif::img::Image<16>(avif::img::ColorProfile{}, pixelOrder, width, height, width * bytesPerPixel, std::move(data)); 166 | } else { 167 | result.image = avif::img::Image<8>(avif::img::ColorProfile{}, pixelOrder, width, height, width * bytesPerPixel, std::move(data)); 168 | } 169 | return result; 170 | } 171 | 172 | } 173 | -------------------------------------------------------------------------------- /src/img/png/Reader.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by psi on 2020/01/05. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace img::png { 15 | 16 | struct ColorPrimaries final { 17 | png_fixed_point whiteX; 18 | png_fixed_point whiteY; 19 | png_fixed_point redX; 20 | png_fixed_point redY; 21 | png_fixed_point greenX; 22 | png_fixed_point greenY; 23 | png_fixed_point blueX; 24 | png_fixed_point blueY; 25 | }; 26 | 27 | class Reader final { 28 | public: 29 | struct Result final { 30 | std::variant, avif::img::Image<16>> image; 31 | std::optional sRGB; 32 | std::optional colorPrimaries; 33 | std::optional gamma; 34 | std::optional> iccProfile; 35 | }; 36 | private: 37 | avif::util::FileLogger& log_; 38 | FILE* const file_; 39 | png_structp png_; 40 | png_infop info_; 41 | public: 42 | Reader() = delete; 43 | Reader(Reader const&) = delete; 44 | Reader(Reader&&) = delete; 45 | Reader& operator=(Reader const&) = delete; 46 | Reader& operator=(Reader&&) = delete; 47 | ~Reader() noexcept; 48 | 49 | public: 50 | static char const* version(); 51 | static Reader create(avif::util::FileLogger& log, std::string const& filename); 52 | Result read(); 53 | 54 | private: 55 | explicit Reader(avif::util::FileLogger& log, FILE* file, png_structp png, png_infop info); 56 | }; 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "Config.hpp" 14 | #include "AVIFBuilder.hpp" 15 | #include "img/png/Reader.hpp" 16 | #include "img/Conversion.hpp" 17 | 18 | namespace { 19 | 20 | size_t encode(avif::util::Logger& log, aom_codec_ctx_t& codec, aom_image* img, std::vector>& packets) { 21 | aom_codec_cx_pkt_t const* pkt; 22 | aom_codec_iter_t iter = nullptr; 23 | aom_codec_err_t const res = aom_codec_encode(&codec, img, 0, 1, img ? AOM_EFLAG_FORCE_KF : 0); 24 | if (res != AOM_CODEC_OK) { 25 | if(img) { 26 | log.fatal("failed to encode a frame: {}", aom_codec_error_detail(&codec)); 27 | } else { 28 | log.fatal("failed to flush encoder: {}", aom_codec_error_detail(&codec)); 29 | } 30 | return 0; 31 | } 32 | size_t numPackets = 0; 33 | while ((pkt = aom_codec_get_cx_data(&codec, &iter)) != nullptr) { 34 | if (pkt->kind == AOM_CODEC_CX_FRAME_PKT) { 35 | auto& frame = pkt->data.frame; 36 | auto const beg = reinterpret_cast(frame.buf); 37 | packets.emplace_back(std::vector(beg, beg + frame.sz)); 38 | ++numPackets; 39 | } 40 | } 41 | return numPackets; 42 | } 43 | 44 | avif::img::ColorProfile mergeColorProfile(avif::util::FileLogger& log, Config const& config, img::png::Reader::Result const& loadResult) { 45 | avif::img::ColorProfile mergedColorProfile{ 46 | .cicp = avif::ColourInformationBox::CICP(), 47 | }; 48 | std::optional configProfile = config.calcColorProfile(); 49 | 50 | if(loadResult.iccProfile.has_value()) { 51 | mergedColorProfile.iccProfile = avif::img::ICCProfile(loadResult.iccProfile.value()); 52 | } 53 | if(loadResult.colorPrimaries.has_value()) { 54 | auto const& colorPrimaries = loadResult.colorPrimaries.value(); 55 | // TODO(ledyba-z): Support. 56 | log.warn("cHRM chunk in PNG is not supported yet. white=({}, {}) red=({},{}) green=({},{}) blue=({},{})", 57 | static_cast(colorPrimaries.whiteX) / 100000.0f, 58 | static_cast(colorPrimaries.whiteY) / 100000.0f, 59 | static_cast(colorPrimaries.redX) / 100000.0f, 60 | static_cast(colorPrimaries.redY) / 100000.0f, 61 | static_cast(colorPrimaries.greenX) / 100000.0f, 62 | static_cast(colorPrimaries.greenY) / 100000.0f, 63 | static_cast(colorPrimaries.blueX) / 100000.0f, 64 | static_cast(colorPrimaries.blueY) / 100000.0f); 65 | } 66 | if(loadResult.gamma.has_value()) { 67 | // TODO(ledyba-z): Support. 68 | log.warn("gAMA chunk in PNG is not supported yet. gamma = {}", 69 | static_cast(loadResult.gamma.value()) / 100000.0f); 70 | } 71 | if(loadResult.sRGB.has_value()) { 72 | auto cicp = avif::ColourInformationBox::CICP(); // default value indicates sRGB. 73 | cicp.fullRangeFlag = config.fullColorRange; 74 | mergedColorProfile.cicp = cicp; 75 | } 76 | if(configProfile.has_value()) { 77 | if(configProfile.value().cicp.has_value()) { 78 | log.info("CICP information will be overridden by flags"); 79 | mergedColorProfile.cicp = configProfile.value().cicp; 80 | } 81 | if(configProfile.value().iccProfile.has_value()) { 82 | log.info("ICC profile will be overridden by flags"); 83 | mergedColorProfile.iccProfile = configProfile.value().iccProfile; 84 | } 85 | } 86 | return mergedColorProfile; 87 | } 88 | 89 | } 90 | 91 | namespace internal{ 92 | int main(int argc, char** argv); 93 | void printSequenceHeader(avif::util::Logger& log, avif::av1::SequenceHeader& seq); 94 | } 95 | 96 | int main(int argc, char** argv) { 97 | try { 98 | return internal::main(argc, argv); 99 | } catch (std::exception& err) { 100 | fprintf(stderr, "%s\n", err.what()); 101 | fflush(stderr); 102 | return -1; 103 | } 104 | } 105 | 106 | int internal::main(int argc, char** argv) { 107 | avif::util::FileLogger log(stdout, stderr, avif::util::Logger::Level::DEBUG); 108 | log.info("cavif"); 109 | log.info("libaom ver: {}", aom_codec_version_str()); 110 | log.info("libpng ver: {}", img::png::Reader::version()); 111 | 112 | aom_codec_iface_t* av1codec = aom_codec_av1_cx(); 113 | if(!av1codec) { 114 | log.fatal("failed to get AV1 encoder."); 115 | } 116 | 117 | Config config(argc, argv); 118 | aom_codec_enc_config_default(av1codec, &config.codec, AOM_USAGE_GOOD_QUALITY); 119 | // Set our default. 120 | config.codec.rc_end_usage = AOM_Q; 121 | config.codec.rc_target_bitrate = 0; 122 | config.codec.g_threads = std::thread::hardware_concurrency(); 123 | if(!config.parse()) { 124 | log.error("Failed to parse arguments!"); 125 | config.usage(); 126 | return -1; 127 | } 128 | if(config.showHelp) { 129 | config.usage(); 130 | return 0; 131 | } 132 | try { 133 | config.validateBeforeLoad(); 134 | } catch (std::exception const& e) { 135 | log.error("Arguments validation failed:"); 136 | log.error("{}", e.what()); 137 | return -2; 138 | } 139 | 140 | // decoding input image 141 | img::png::Reader::Result loadResult = img::png::Reader::create(log, config.input).read(); 142 | aom_image_t img; 143 | 144 | auto colorProfile = mergeColorProfile(log, config, loadResult); 145 | if(std::holds_alternative>(loadResult.image)) { 146 | auto src = std::get>(loadResult.image); 147 | src.colorProfile() = colorProfile; 148 | convert<8>(config, src, img); 149 | } else { 150 | auto src = std::get>(loadResult.image); 151 | src.colorProfile() = colorProfile; 152 | convert<16>(config, src, img); 153 | } 154 | 155 | uint32_t const width = aom_img_plane_width(&img, AOM_PLANE_Y); 156 | uint32_t const height = aom_img_plane_height(&img, AOM_PLANE_Y); 157 | 158 | try { 159 | config.validateAfterLoad(width, height); 160 | } catch (std::exception const& e) { 161 | log.error("Arguments validation failed:"); 162 | log.error("{}", e.what()); 163 | return -2; 164 | } 165 | 166 | // initialize encoder 167 | config.codec.g_w = width; 168 | config.codec.g_h = height; 169 | // Generate just one frame. 170 | config.codec.g_limit = 1; 171 | config.codec.g_pass = AOM_RC_ONE_PASS; 172 | // FIXME(ledyba-z): Encoder produces wrong images when g_input_bit_depth != g_bit_depth. Bug? 173 | config.codec.g_input_bit_depth = config.codec.g_bit_depth; 174 | // FIXME(ledyba-z): If kf_max_dist = 1, it crashes. Bug? 175 | // > A value of 0 implies all frames will be keyframes. 176 | // However, when it is set to 0, assertion always fails: 177 | // cavif/external/libaom/av1/encoder/gop_structure.c:92: 178 | // construct_multi_layer_gf_structure: Assertion `gf_interval >= 1' failed. 179 | config.codec.kf_max_dist = 1; 180 | // One frame takes 1 second. 181 | config.codec.g_timebase.den = 1; 182 | config.codec.g_timebase.num = 1; 183 | 184 | aom_codec_ctx_t codec{}; 185 | 186 | aom_codec_flags_t flags = 0; 187 | if(config.codec.g_bit_depth > 8) { 188 | flags = AOM_CODEC_USE_HIGHBITDEPTH; 189 | } 190 | if(AOM_CODEC_OK != aom_codec_enc_init(&codec, av1codec, &config.codec, flags)) { 191 | log.fatal("Failed to initialize encoder: {}", aom_codec_error_detail(&codec)); 192 | } 193 | 194 | config.modify(&codec, colorProfile); 195 | 196 | std::vector> packets; 197 | { 198 | log.info("Encoding: {} -> {}", config.input, config.output); 199 | auto start = std::chrono::steady_clock::now(); 200 | encode(log, codec, &img, packets); 201 | while(encode(log, codec, nullptr, packets) > 0); //flushing 202 | auto finish = std::chrono::steady_clock::now(); 203 | log.info(" Encoded: {} -> {} in {:.2f} [sec]", config.input, config.output, std::chrono::duration_cast(finish-start).count() / 1000.0f); 204 | } 205 | aom_img_free(&img); 206 | 207 | if (aom_codec_destroy(&codec) != AOM_CODEC_OK) { 208 | log.error("Failed to destroy codec: {}", aom_codec_error_detail(&codec)); 209 | return -1; 210 | } 211 | 212 | if(packets.empty()) { 213 | log.error("no packets to out."); 214 | return -1; 215 | } 216 | { 217 | AVIFBuilder builder(log, config, width, height); 218 | std::shared_ptr result = avif::av1::Parser(log, packets[0]).parse(); 219 | if (!result->ok()) { 220 | log.error(result->error()); 221 | return -1; 222 | } 223 | std::optional seq{}; 224 | std::vector configOBUs; 225 | std::vector mdat; 226 | for(avif::av1::Parser::Result::Packet const& packet : result->packets()) { 227 | switch (packet.type()) { 228 | case avif::av1::Header::Type::TemporalDelimiter: 229 | case avif::av1::Header::Type::Padding: 230 | case avif::av1::Header::Type::Reserved: 231 | break; 232 | case avif::av1::Header::Type::SequenceHeader: 233 | seq = std::get(packet.content()); 234 | configOBUs.insert(std::end(configOBUs), std::next(std::begin(result->buffer()), packet.beg()), std::next(result->buffer().begin(), packet.end())); 235 | mdat.insert(std::end(mdat), std::next(std::begin(result->buffer()), packet.beg()), std::next(std::begin(result->buffer()), packet.end())); 236 | break; 237 | case avif::av1::Header::Type::Frame: 238 | default: { 239 | mdat.insert(std::end(mdat), std::next(std::begin(result->buffer()), packet.beg()), std::next(std::begin(result->buffer()), packet.end())); 240 | break; 241 | } 242 | } 243 | } 244 | if (!seq.has_value()) { 245 | throw std::logic_error("No sequence header OBU."); 246 | } 247 | builder.setPrimaryFrame(AVIFBuilder::Frame(colorProfile, seq.value(), std::move(configOBUs), std::move(mdat))); 248 | if(config.alphaInput.has_value()) { 249 | log.info("Attaching {} as Alpha plane.", config.alphaInput.value()); 250 | builder.setAlphaFrame(AVIFBuilder::Frame::load(log, config.alphaInput.value())); 251 | } 252 | if(config.depthInput.has_value()) { 253 | log.info("Attaching {} as Depth plane.", config.depthInput.value()); 254 | builder.setDepthFrame(AVIFBuilder::Frame::load(log, config.depthInput.value())); 255 | } 256 | std::vector data = builder.build(); 257 | std::optional writeResult = avif::util::writeFile(config.output, data); 258 | if (writeResult.has_value()) { 259 | log.error(writeResult.value()); 260 | return -1; 261 | } 262 | if (config.showResult) { 263 | printSequenceHeader(log, seq.value()); 264 | } 265 | } 266 | return 0; 267 | } 268 | 269 | void internal::printSequenceHeader(avif::util::Logger& log, avif::av1::SequenceHeader& seq) { 270 | log.info(""); 271 | log.info(" - OBU Sequence Header:"); 272 | log.info(" - AV1 Profile: {}", seq.seqProfile); 273 | log.info(" - Still picture: {}", seq.stillPicture ? "Yes" : "No"); 274 | log.info(" - Reduced still picture header: {}", seq.reducedStillPictureHeader ? "Yes" : "No"); 275 | log.info(" - Sequence Level Index at OperatingPoint[0]: {}", seq.operatingPoints.at(0).seqLevelIdx); 276 | log.info(" - Max frame width: {}", seq.maxFrameWidth); 277 | log.info(" - Max frame height: {}", seq.maxFrameHeight); 278 | log.info(" - Use 128x128 superblock: {}", seq.use128x128Superblock ? "Yes" : "No"); 279 | log.info(" - FilterIntra enabled: {}", seq.enableFilterIntra ? "Yes" : "No"); 280 | log.info(" - IntraEdgeFilter enabled: {}", seq.enableIntraEdgeFilter ? "Yes" : "No"); 281 | /* 282 | log.info(" - InterIntraCompound enabled: {}", seq.enableInterintraCompound ? "Yes" : "No"); 283 | log.info(" - Masked Compound enabled: {}", seq.enableMaskedCompound ? "Yes" : "No"); 284 | log.info(" - WarpedMotion enabled: {}", seq.enableWarpedMotion ? "Yes" : "No"); 285 | log.info(" - DualFilter enabled: {}", seq.enableDualFilter ? "Yes" : "No"); 286 | log.info(" - OrderHint enabled: {}", seq.enableOrderHint ? "Yes" : "No"); 287 | log.info(" - JNTComp enabled: {}", seq.enableJNTComp ? "Yes" : "No"); 288 | log.info(" - RefFrameMVS enabled: {}", seq.enableRefFrameMVS ? "Yes" : "No"); 289 | */ 290 | log.info(" - Superres enabled: {}", seq.enableSuperres ? "Yes" : "No"); 291 | log.info(" - CDEF enabled: {}", seq.enableCDEF ? "Yes" : "No"); 292 | log.info(" - Loop Restoration enabled: {}", seq.enableRestoration ? "Yes" : "No"); 293 | log.info(" - Film Grain Params Present: {}", seq.filmGrainParamsPresent ? "Yes" : "No"); 294 | log.info(" - Color Info:"); 295 | log.info(" - High bit-depth: {}", seq.colorConfig.highBitdepth ? "Yes" : "No"); 296 | log.info(" - Twelve bit: {}", seq.colorConfig.twelveBit ? "Yes" : "No"); 297 | log.info(" - Monochrome: {}", seq.colorConfig.monochrome ? "Yes" : "No"); 298 | log.info(" - Color primaries: {}", seq.colorConfig.colorPrimaries.has_value() ? std::to_string(static_cast(seq.colorConfig.colorPrimaries.value())) : ""); 299 | log.info(" - Transfer characteristics: {}", seq.colorConfig.transferCharacteristics.has_value() ? std::to_string(static_cast(seq.colorConfig.transferCharacteristics.value())) : ""); 300 | log.info(" - Matrix coefficients: {}", seq.colorConfig.matrixCoefficients.has_value() ? std::to_string(static_cast(seq.colorConfig.matrixCoefficients.value())) : ""); 301 | log.info(" - Color range: {}", seq.colorConfig.colorRange ? "Full Ranged" : "Limited"); 302 | log.info(" - Sub sampling X: {}", seq.colorConfig.subsamplingX); 303 | log.info(" - Sub sampling Y: {}", seq.colorConfig.subsamplingX); 304 | log.info(" - Chroma sample position: {}", seq.colorConfig.chromaSamplePosition.has_value() ? std::to_string(static_cast(seq.colorConfig.chromaSamplePosition.value())) : ""); 305 | log.info(" - Separate UV Delta Q: {}", seq.colorConfig.separateUVDeltaQ ? "Yes" : "No"); 306 | } 307 | -------------------------------------------------------------------------------- /test/NopTest.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by psi on 2022/03/27. 3 | // 4 | 5 | #include 6 | 7 | TEST(NopTest, TruthOfThisUniverse) { 8 | ASSERT_EQ(42, 42); 9 | } 10 | --------------------------------------------------------------------------------