Vendor dav1d 1.5.3

This commit is contained in:
Basilisk-Dev 2026-05-11 09:31:45 -04:00 committed by wuggy
commit ee30135ecc
390 changed files with 325535 additions and 0 deletions

View file

@ -0,0 +1,5 @@
This directory contains dav1d 1.5.3 from VideoLAN:
https://code.videolan.org/videolan/dav1d/-/tags/1.5.3
Upstream source is stored in src/. Mozilla-specific build configuration lives
in moz.build, config/, and moz/.

View file

@ -0,0 +1,85 @@
/* Mozilla build configuration for bundled dav1d. */
#ifndef MOZ_DAV1D_CONFIG_H
#define MOZ_DAV1D_CONFIG_H
#if defined(__x86_64__) || defined(_M_X64)
# define ARCH_X86 1
# define ARCH_X86_64 1
# define ARCH_X86_32 0
#elif defined(__i386__) || defined(_M_IX86)
# define ARCH_X86 1
# define ARCH_X86_64 0
# define ARCH_X86_32 1
#else
# define ARCH_X86 0
# define ARCH_X86_64 0
# define ARCH_X86_32 0
#endif
#if defined(__aarch64__) || defined(_M_ARM64)
# define ARCH_AARCH64 1
#else
# define ARCH_AARCH64 0
#endif
#if defined(__arm__) || defined(_M_ARM)
# define ARCH_ARM 1
#else
# define ARCH_ARM 0
#endif
#if defined(__loongarch64)
# define ARCH_LOONGARCH 1
# define ARCH_LOONGARCH64 1
#else
# define ARCH_LOONGARCH 0
# define ARCH_LOONGARCH64 0
#endif
#if defined(__powerpc64__) && defined(_LITTLE_ENDIAN)
# define ARCH_PPC64LE 1
#else
# define ARCH_PPC64LE 0
#endif
#if defined(__riscv)
# define ARCH_RISCV 1
#else
# define ARCH_RISCV 0
#endif
#if defined(IS_BIG_ENDIAN) || defined(__BIG_ENDIAN__)
# define ENDIANNESS_BIG 1
#else
# define ENDIANNESS_BIG 0
#endif
#define CONFIG_8BPC 1
#define CONFIG_16BPC 1
#define CONFIG_LOG 0
#define CONFIG_MACOS_KPERF 0
#define HAVE_ASM 0
#define TRIM_DSP_FUNCTIONS 0
#define HAVE_ALIGNED_ALLOC 0
#define HAVE_DLSYM 0
#define HAVE_ELF_AUX_INFO 0
#define HAVE_GETAUXVAL 0
#define HAVE_MEMALIGN 0
#define HAVE_POSIX_MEMALIGN 0
#define HAVE_PTHREAD_GETAFFINITY_NP 0
#define HAVE_PTHREAD_NP_H 0
#define HAVE_PTHREAD_SETNAME_NP 0
#define HAVE_PTHREAD_SET_NAME_NP 0
#ifdef _WIN32
# define HAVE_IO_H 1
# define HAVE_SYS_TYPES_H 1
# define HAVE_UNISTD_H 0
#else
# define HAVE_IO_H 0
# define HAVE_SYS_TYPES_H 1
# define HAVE_UNISTD_H 1
#endif
#endif /* MOZ_DAV1D_CONFIG_H */

View file

@ -0,0 +1 @@
#define DAV1D_VERSION "1.5.3"

109
media/libdav1d/moz.build Normal file
View file

@ -0,0 +1,109 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
with Files('*'):
BUG_COMPONENT = ('Core', 'Audio/Video')
common_sources = [
'/media/libdav1d/src/src/cdf.c',
'/media/libdav1d/src/src/cpu.c',
'/media/libdav1d/src/src/ctx.c',
'/media/libdav1d/src/src/data.c',
'/media/libdav1d/src/src/decode.c',
'/media/libdav1d/src/src/dequant_tables.c',
'/media/libdav1d/src/src/getbits.c',
'/media/libdav1d/src/src/intra_edge.c',
'/media/libdav1d/src/src/itx_1d.c',
'/media/libdav1d/src/src/lf_mask.c',
'/media/libdav1d/src/src/lib.c',
'/media/libdav1d/src/src/log.c',
'/media/libdav1d/src/src/mem.c',
'/media/libdav1d/src/src/msac.c',
'/media/libdav1d/src/src/obu.c',
'/media/libdav1d/src/src/pal.c',
'/media/libdav1d/src/src/picture.c',
'/media/libdav1d/src/src/qm.c',
'/media/libdav1d/src/src/ref.c',
'/media/libdav1d/src/src/refmvs.c',
'/media/libdav1d/src/src/scan.c',
'/media/libdav1d/src/src/tables.c',
'/media/libdav1d/src/src/thread_task.c',
'/media/libdav1d/src/src/warpmv.c',
'/media/libdav1d/src/src/wedge.c',
]
bitdepth_sources = [
'/media/libdav1d/moz/cdef_16bpc.c',
'/media/libdav1d/moz/cdef_8bpc.c',
'/media/libdav1d/moz/cdef_apply_16bpc.c',
'/media/libdav1d/moz/cdef_apply_8bpc.c',
'/media/libdav1d/moz/fg_apply_16bpc.c',
'/media/libdav1d/moz/fg_apply_8bpc.c',
'/media/libdav1d/moz/filmgrain_16bpc.c',
'/media/libdav1d/moz/filmgrain_8bpc.c',
'/media/libdav1d/moz/ipred_16bpc.c',
'/media/libdav1d/moz/ipred_8bpc.c',
'/media/libdav1d/moz/ipred_prepare_16bpc.c',
'/media/libdav1d/moz/ipred_prepare_8bpc.c',
'/media/libdav1d/moz/itx_16bpc.c',
'/media/libdav1d/moz/itx_8bpc.c',
'/media/libdav1d/moz/lf_apply_16bpc.c',
'/media/libdav1d/moz/lf_apply_8bpc.c',
'/media/libdav1d/moz/loopfilter_16bpc.c',
'/media/libdav1d/moz/loopfilter_8bpc.c',
'/media/libdav1d/moz/looprestoration_16bpc.c',
'/media/libdav1d/moz/looprestoration_8bpc.c',
'/media/libdav1d/moz/lr_apply_16bpc.c',
'/media/libdav1d/moz/lr_apply_8bpc.c',
'/media/libdav1d/moz/mc_16bpc.c',
'/media/libdav1d/moz/mc_8bpc.c',
'/media/libdav1d/moz/recon_16bpc.c',
'/media/libdav1d/moz/recon_8bpc.c',
]
SOURCES += common_sources
SOURCES += bitdepth_sources
if CONFIG['OS_TARGET'] == 'WINNT':
SOURCES += [
'/media/libdav1d/src/src/win32/thread.c',
]
else:
DEFINES['_GNU_SOURCE'] = True
EXPORTS.dav1d += [
'/media/libdav1d/src/include/dav1d/common.h',
'/media/libdav1d/src/include/dav1d/data.h',
'/media/libdav1d/src/include/dav1d/dav1d.h',
'/media/libdav1d/src/include/dav1d/headers.h',
'/media/libdav1d/src/include/dav1d/picture.h',
'/media/libdav1d/src/include/dav1d/version.h',
]
LOCAL_INCLUDES += [
'/media/libdav1d/config',
'/media/libdav1d/src',
'/media/libdav1d/src/include',
'/media/libdav1d/src/include/dav1d',
]
FINAL_LIBRARY = 'gkmedias'
# We allow warnings for third-party code that can be updated from upstream.
ALLOW_COMPILER_WARNINGS = True
if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
CFLAGS += [
'-Wno-missing-field-initializers',
'-Wno-sign-compare',
'-Wno-unused-function',
'-Wno-unused-parameter',
]
if CONFIG['CLANG_CXX'] or CONFIG['CLANG_CL']:
CFLAGS += [
'-Wno-shorten-64-to-32',
'-Wno-unreachable-code',
]

View file

@ -0,0 +1,2 @@
#define BITDEPTH 16
#include "../src/src/cdef_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 8
#include "../src/src/cdef_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 16
#include "../src/src/cdef_apply_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 8
#include "../src/src/cdef_apply_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 16
#include "../src/src/fg_apply_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 8
#include "../src/src/fg_apply_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 16
#include "../src/src/filmgrain_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 8
#include "../src/src/filmgrain_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 16
#include "../src/src/ipred_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 8
#include "../src/src/ipred_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 16
#include "../src/src/ipred_prepare_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 8
#include "../src/src/ipred_prepare_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 16
#include "../src/src/itx_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 8
#include "../src/src/itx_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 16
#include "../src/src/lf_apply_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 8
#include "../src/src/lf_apply_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 16
#include "../src/src/loopfilter_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 8
#include "../src/src/loopfilter_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 16
#include "../src/src/looprestoration_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 8
#include "../src/src/looprestoration_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 16
#include "../src/src/lr_apply_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 8
#include "../src/src/lr_apply_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 16
#include "../src/src/mc_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 8
#include "../src/src/mc_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 16
#include "../src/src/recon_tmpl.c"

View file

@ -0,0 +1,2 @@
#define BITDEPTH 8
#include "../src/src/recon_tmpl.c"

10
media/libdav1d/src/.gitignore vendored Normal file
View file

@ -0,0 +1,10 @@
/build*
/Session.vim
[._]*.swp
*~
tags
.DS_Store
/tests/argon
/tests/dav1d-test-data
*.snap
/tools/output/xxhash.h

View file

@ -0,0 +1,930 @@
stages:
- style
- build
- test
.debian-amd64-common:
image: registry.videolan.org/dav1d-debian-unstable:20250207200301
stage: build
tags:
- docker
- amd64
.debian-amd64-minimum:
image: registry.videolan.org/dav1d-debian-minimum:20250207200301
stage: build
tags:
- docker
- amd64
.debian-llvm-mingw-common:
image: registry.videolan.org/vlc-debian-llvm-msvcrt:20250305204125
stage: build
tags:
- docker
- amd64
.debian-aarch64-common:
image: registry.videolan.org/dav1d-debian-bookworm-aarch64:20250215002814
stage: build
tags:
- docker
- aarch64
.debian-armv7-common:
image: registry.videolan.org/dav1d-debian-bookworm-armv7:20250215014239
stage: build
tags:
- docker
- armv7
.debian-ppc64le-common:
image: registry.videolan.org/dav1d-debian-unstable-ppc64le:20250215003029
stage: build
tags:
- docker
- ppc64le
.android-common:
image: registry.videolan.org/vlc-debian-android:20241118101328
stage: build
tags:
- docker
- amd64
.debian-wasm-emscripten-common:
image: registry.videolan.org/vlc-debian-wasm-emscripten:20250207201514
stage: build
tags:
- docker
- amd64
style-check:
extends: .debian-amd64-common
stage: style
script:
- git grep -I -n -P "\t|\r| $" -- . ':(exclude)*/compat/*' && echo "Trailing whitespace" && exit 1
- git grep -I -n -i -e 'david' --and --not -e 'copyright' -- . ':(exclude)THANKS.md' ':(exclude).gitlab-ci.yml' && echo "Misspelled dav1d" && exit 1
- git grep -I -l -z "" -- . ':(exclude)*/compat/*' | while IFS= read -r -d '' i; do
if [ -n "$(tail -c 1 "$i")" ]; then
echo "No newline at end of $i";
exit 1;
fi;
done
- rg '[\u061c\u2000-\u200f\u2028-\u202f\u205f-\u206f]' ./ && echo "Invisible Unicode characters" && exit 1
- git remote rm upstream 2> /dev/null || true
- git remote add upstream https://code.videolan.org/videolan/dav1d.git
- git fetch -q upstream master
- for i in $(git rev-list HEAD ^upstream/master); do
echo "Checking commit message of $i";
msg="$(git log --format=%B -n 1 $i)";
if [ -n "$(echo "$msg" | awk "NR==2")" ]; then
echo "Malformed commit message in $i, second line must be empty";
exit 1;
fi;
if echo "$msg" | head -1 | grep -q '\.$'; then
echo "Malformed commit message in $i, trailing period in subject line";
exit 1;
fi;
done
x86inc-check:
extends: .debian-amd64-common
stage: style
script:
- git remote rm x86inc 2> /dev/null || true
- git remote add x86inc https://code.videolan.org/videolan/x86inc.asm.git
- git fetch -q x86inc master
- git diff --exit-code x86inc/master:x86inc.asm src/ext/x86/x86inc.asm
allow_failure: true
build-debian:
extends: .debian-amd64-common
tags:
- docker
- avx2
- amd64
script:
- meson setup build --buildtype release
-Dtrim_dsp=false
--werror
- ninja -C build
- cd build && meson test -v
artifacts:
paths:
- build/
expire_in: 1 day
build-debian-static:
extends: .debian-amd64-common
script:
- meson setup build --buildtype release
--default-library static
--werror
- ninja -C build
- cd build && meson test -v
- nm -A -g src/libdav1d.a | grep " [ABCDGRST] " | (! grep -v " _*dav1d_")
build-debian-illegal-instructions:
extends: .debian-amd64-common
tags:
- docker
- avx2
- amd64
script:
- meson setup build --buildtype debug
- ninja -C build
- cd build
- exit_code=0
- time meson test -v --suite checkasm --wrapper 'qemu-x86_64 -cpu Conroe' || exit_code=$((exit_code + $?))
- time meson test -v --suite checkasm --wrapper 'qemu-x86_64 -cpu Penryn' || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
build-debian32:
extends: .debian-amd64-common
script:
- meson setup build --buildtype release
-Dtrim_dsp=false
--werror
--cross-file package/crossfiles/i686-linux32.meson
- ninja -C build
- cd build && meson test -v
artifacts:
paths:
- build/
expire_in: 1 day
build-debian-examples:
extends: .debian-amd64-common
script:
- meson setup build --buildtype release
--werror
-Denable_examples=true
- ninja -C build
build-debian-no-tools:
extends: .debian-amd64-common
script:
- meson setup build --buildtype release
--werror
-Denable_tools=false
- ninja -C build
build-debian-bitdepth:
extends: .debian-amd64-common
script:
- meson setup build --buildtype release
--werror
-Dbitdepths=$DEPTH
- ninja -C build
parallel:
matrix:
- DEPTH: [8, 16]
build-debian-avx:
extends: .debian-amd64-common
tags:
- docker
- avx2
- amd64
variables:
CFLAGS: '-mavx'
script:
- meson setup build --buildtype debugoptimized
--werror
- ninja -C build
- cd build
- time meson test -v --suite checkasm
build-debian-minimum:
extends: .debian-amd64-minimum
script:
- meson setup build --buildtype release
--werror
-Dtrim_dsp=false
- ninja -C build
- cd build && meson test -v
build-debian-avx512:
extends: .debian-amd64-common
tags:
- docker
- amd64-avx512
variables:
CFLAGS: '-mavx'
script:
- meson setup build --buildtype debugoptimized
--werror
- ninja -C build
- cd build
- time meson test -v --suite checkasm
build-debian-clang:
extends: .debian-amd64-common
variables:
CC: clang
CC_LD: mold
script:
- meson setup build --buildtype release
--werror
-Dtrim_dsp=false
- ninja -C build
- cd build && meson test -v
build-win:
extends: .debian-amd64-common
script:
- wineserver -p && wine wineboot
- meson setup build --buildtype release
--werror
--libdir lib
--prefix "$(pwd)/build/dav1d_install"
--cross-file package/crossfiles/${CROSSFILE}.meson
-Ddefault_library=both
-Dtrim_dsp=false
- ninja -C build
- ninja -C build install
- cd build && meson test -v
- ${CROSSFILE}-nm -A -g src/libdav1d.a | grep " [ABCDGRST] " | (! grep -E -v " \.| _*dav1d_")
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
paths:
- build/dav1d_install/
expire_in: 1 week
parallel:
matrix:
- CROSSFILE: [i686-w64-mingw32, x86_64-w64-mingw32]
build-win32-unaligned-stack:
extends: .debian-llvm-mingw-common
script:
- wineserver -p && wine wineboot
- meson setup build --buildtype release
--werror
--cross-file package/crossfiles/i686-w64-mingw32.meson
-Dstack_alignment=4
-Dtrim_dsp=false
- ninja -C build
- cd build && meson test -v
build-win-arm:
extends: .debian-llvm-mingw-common
script:
- meson setup build --buildtype release
--werror
--libdir lib
--prefix "$(pwd)/build/dav1d_install"
--cross-file package/crossfiles/${CROSSFILE}.meson
-Ddefault_library=both
-Dtrim_dsp=false
- ninja -C build
- ninja -C build install
- ${CROSSFILE}-nm -A -g build/src/libdav1d.a | grep " [ABCDGRST] " | (! grep -E -v " \.| _*dav1d_")
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
paths:
- build/dav1d_install/
expire_in: 1 week
parallel:
matrix:
- CROSSFILE: [armv7-w64-mingw32, aarch64-w64-mingw32]
.build-android-common:
extends: .android-common
script:
- meson setup build --buildtype release
--werror
--libdir lib
--prefix "$(pwd)/build/dav1d_install"
--cross-file $CROSSFILE
-Ddefault_library=both
-Dtrim_dsp=false
- ninja -C build
- ninja -C build install
build-android-armv7:
extends: .build-android-common
variables:
CROSSFILE: package/crossfiles/arm-android.meson
rules:
- if: '$CI_COMMIT_BRANCH'
build-android-aarch64:
extends: .build-android-common
variables:
CROSSFILE: package/crossfiles/aarch64-android.meson
rules:
- if: '$CI_COMMIT_BRANCH'
build-android-armv7-release:
extends: build-android-armv7
rules:
- if: '$CI_COMMIT_TAG && $CI_PROJECT_PATH == "videolan/dav1d"'
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
paths:
- build/dav1d_install/
expire_in: 1 week
build-android-aarch64-release:
extends: build-android-aarch64
rules:
- if: '$CI_COMMIT_TAG && $CI_PROJECT_PATH == "videolan/dav1d"'
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
paths:
- build/dav1d_install/
expire_in: 1 week
build-debian-aarch64:
extends: .debian-aarch64-common
script:
- meson setup build --buildtype debugoptimized
--werror
- ninja -C build
- cd build && meson test -v
build-debian-aarch64-clang-5:
extends: .debian-aarch64-common
variables:
CC: clang-5.0
CFLAGS: '-integrated-as'
script:
- meson setup build --buildtype release
- ninja -C build
- cd build && meson test -v
build-debian-aarch64-clang-18:
extends: .debian-amd64-common
variables:
QEMU_LD_PREFIX: /usr/aarch64-linux-gnu/
script:
- meson setup build --buildtype release
-Dtrim_dsp=false
--werror
--cross-file package/crossfiles/aarch64-linux-clang.meson
- ninja -C build
- cd build && meson test -v
build-macos:
stage: build
tags:
- amd64
- macos
script:
- meson setup build --buildtype release
-Ddefault_library=both
-Dtrim_dsp=false
--werror
- ninja -C build
- cd build && meson test -v
build-debian-werror:
extends: .debian-aarch64-common
variables:
CC: clang
script:
- meson setup build --buildtype debug
--werror
- ninja -C build
build-debian-armv7:
extends: .debian-armv7-common
script:
- linux32 meson setup build --buildtype debugoptimized
--werror
- ninja -C build
- cd build && meson test -v
build-debian-armv7-clang-5:
extends: .debian-armv7-common
variables:
CC: clang-5.0
CFLAGS: '-integrated-as'
script:
- linux32 meson setup build --buildtype release
- ninja -C build
- cd build && meson test -v
build-debian-ppc64le:
extends: .debian-ppc64le-common
variables:
CC: gcc-13
script:
- meson setup build --buildtype release
-Dtrim_dsp=false
--werror
- ninja -C build
- cd build && meson test -v
build-debian-wasm:
extends: .debian-wasm-emscripten-common
script:
- source $EMSCRIPTEN_SDK/emsdk_env.sh
- meson setup build --buildtype release
--werror
--default-library static
--cross-file package/crossfiles/${CROSSFILE}.meson
- ninja -C build
- cd build && meson test -v
parallel:
matrix:
- CROSSFILE: [wasm32, wasm64]
build-debian-riscv64:
extends: .debian-amd64-common
variables:
QEMU_CPU: rv64,v=true,vext_spec=v1.0,vlen=256,elen=64
QEMU_LD_PREFIX: /usr/riscv64-linux-gnu/
script:
- meson setup build --buildtype release
-Dtrim_dsp=false
--werror
--cross-file package/crossfiles/${CROSSFILE}.meson
- ninja -C build
- cd build && meson test -v
parallel:
matrix:
- CROSSFILE: [riscv64-linux, riscv64-linux-clang]
build-debian-loongarch64:
extends: .debian-amd64-common
variables:
QEMU_CPU: max-loongarch-cpu
QEMU_LD_PREFIX: /opt/cross-tools/target/
script:
- meson setup build --buildtype release
-Dtrim_dsp=false
--werror
--cross-file package/crossfiles/loongarch64-linux.meson
- ninja -C build
- cd build && meson test -v
.test-common:
stage: test
cache:
key: testdata.git-20190215
paths:
- cache/dav1d-test-data.git/
before_script:
- test -d cache || mkdir cache
- test -d cache/dav1d-test-data.git && GIT_DIR=cache/dav1d-test-data.git git fetch --refmap=refs/heads/master:refs/heads/master origin master
- test -d cache/dav1d-test-data.git || git clone --bare https://code.videolan.org/videolan/dav1d-test-data.git cache/dav1d-test-data.git
- git clone cache/dav1d-test-data.git tests/dav1d-test-data
- git -C tests/dav1d-test-data describe --always --long
dependencies: []
artifacts:
when: always
reports:
junit: build/meson-logs/testlog.junit.xml
.test-asm-common:
extends:
- .debian-amd64-common
- .test-common
tags:
- docker
- amd64
- avx2
script:
- meson configure build -Dtestdata_tests=true
- ninja -C build
- cd build
- exit_code=0
- time meson test -q --suite testdata --test-args "--cpumask 0" || exit_code=$((exit_code + $?))
- time meson test -q --suite testdata --test-args "--cpumask sse2" || exit_code=$((exit_code + $?))
- time meson test -q --suite testdata --test-args "--cpumask ssse3" || exit_code=$((exit_code + $?))
- time meson test -q --suite testdata --test-args "--cpumask sse41" || exit_code=$((exit_code + $?))
- time meson test -q --suite testdata --test-args "--cpumask avx2" || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
.test-argon:
stage: test
cache:
key: argon-20230512
paths:
- cache/argon/
variables:
ARGON_URL: https://streams.videolan.org/argon/argon.tar.zst
before_script:
- test -d cache/argon || mkdir -p cache/argon
- test -f cache/argon/argon.tar.zst ||
(cd cache/argon && curl --remote-name "${ARGON_URL}" --remote-name "${ARGON_URL}.sha512sum" &&
sha512sum --check argon.tar.zst.sha512sum )
- tar -xf cache/argon/argon.tar.zst -C tests
dependencies: []
allow_failure: true
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
test-debian:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-debian"]
script:
- meson setup build --buildtype release
-Dtestdata_tests=true
-Denable_seek_stress=true
-Dlogging=false
-Db_coverage=true
-Dtrim_dsp=false
- ninja -C build
- cd build && time meson test -v
- ninja coverage-html
- mv meson-logs/coveragereport ../coverage
- ninja coverage-xml
- grep -Eo 'line-rate="[^"]+"' meson-logs/coverage.xml | head -n 1 |
grep -Eo '[0-9.]+' | awk '{ print "coverage:", $1 * 100 } '
- time meson test -v --suite testdata_seek-stress --test-args "--threads 2 --framedelay 1"
- time meson test -v --suite testdata_seek-stress --test-args "--threads 2 --framedelay 2"
- time meson test -v --suite testdata --test-args "--threads=1 --negstride"
coverage: '/^coverage: (\d+.\d+)$/'
artifacts:
expose_as: 'Coverage HTML report'
paths:
- coverage/
reports:
coverage_report:
coverage_format: cobertura
path: build/meson-logs/coverage.xml
test-debian-asm:
extends:
- .test-asm-common
needs: ["build-debian"]
dependencies: ["build-debian"]
test-debian32-asm:
extends:
- .test-asm-common
needs: ["build-debian32"]
dependencies: ["build-debian32"]
test-debian-avx512:
extends:
- .debian-amd64-common
- .test-common
tags:
- docker
- amd64-avx512
variables:
CFLAGS: '-mavx'
needs: ["build-debian-avx512"]
script:
- meson setup build --buildtype release
-Dtestdata_tests=true
-Dtrim_dsp=false
- ninja -C build
- cd build && time meson test --suite testdata --test-args "--cpumask avx512icl"
- time meson test --suite testdata --test-args "--threads 2 --framedelay 2 --cpumask avx512icl"
test-debian-unaligned-stack:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-debian"]
tags:
- docker
- avx2
- amd64
script:
- meson setup build --buildtype release
-Dtestdata_tests=true
-Denable_seek_stress=true
-Dlogging=false
-Dstack_alignment=16
-Dtrim_dsp=false
- ninja -C build
- cd build && time meson test -v
test-debian-asan:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-debian"]
variables:
ASAN_OPTIONS: 'detect_leaks=0'
script:
- meson setup build --buildtype debugoptimized
-Dtestdata_tests=true
-Dlogging=false
-Db_sanitize=address
- ninja -C build
- cd build
- exit_code=0
- time meson test -v --setup=sanitizer --suite checkasm || exit_code=$((exit_code + $?))
- time meson test -v --setup=sanitizer --suite testdata --test-args "--cpumask 0" || exit_code=$((exit_code + $?))
- time meson test -v --setup=sanitizer --suite testdata --test-args "--cpumask 0xff" || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
test-debian-msan:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-debian"]
variables:
MSAN_OPTIONS: 'exitcode=1'
CC: clang
script:
- meson setup build --buildtype debugoptimized
-Dtestdata_tests=true
-Denable_seek_stress=true
-Dlogging=false
-Db_sanitize=memory
-Db_lundef=false
-Denable_asm=false
- ninja -C build
- cd build
- exit_code=0
- time meson test -v --setup=sanitizer || exit_code=$((exit_code + $?))
- time meson test -v --setup=sanitizer --suite testdata --test-args "--frametimes /dev/null" || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
test-debian-ubsan:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-debian"]
variables:
UBSAN_OPTIONS: 'print_stacktrace=1:halt_on_error=1'
CC: clang
script:
- meson setup build --buildtype debugoptimized
-Dtestdata_tests=true
-Denable_seek_stress=true
-Dlogging=false
-Db_sanitize=undefined
-Db_lundef=false
-Denable_asm=false
- ninja -C build
- cd build && time meson test -v --setup=sanitizer
test-debian-tsan:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-debian"]
variables:
TSAN_OPTIONS: 'halt_on_error=1'
CC: clang
script:
- meson setup build --buildtype debugoptimized
-Dtestdata_tests=true
-Denable_seek_stress=true
-Dlogging=false
-Db_sanitize=thread
-Db_lundef=false
- ninja -C build
- cd build
- exit_code=0
- time meson test -v --setup=sanitizer --suite testdata --test-args "--threads 2 --framedelay 1" || exit_code=$((exit_code + $?))
- time meson test -v --setup=sanitizer --suite testdata --test-args "--threads 2 --framedelay 2" || exit_code=$((exit_code + $?))
- time meson test -v --setup=sanitizer --suite testdata --test-args "--threads 2 --framedelay 2 --negstride" || exit_code=$((exit_code + $?))
- time meson test -v --setup=sanitizer --suite testdata_seek-stress --test-args "--threads 2 --framedelay 1" || exit_code=$((exit_code + $?))
- time meson test -v --setup=sanitizer --suite testdata_seek-stress --test-args "--threads 2 --framedelay 2" || exit_code=$((exit_code + $?))
- time meson test -v --setup=sanitizer --suite oss-fuzz-asan --suite oss-fuzz-msan --suite oss-fuzz-ubsan || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
test-win64:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-win: [x86_64-w64-mingw32]"]
tags:
- docker
- avx2
- amd64
script:
- wineserver -p && wine wineboot
- meson setup build --buildtype release
-Dtestdata_tests=true
-Dlogging=false
-Dtrim_dsp=false
--cross-file package/crossfiles/x86_64-w64-mingw32.meson
- ninja -C build
- cd build && time meson test -v
test-debian-aarch64:
extends:
- .debian-aarch64-common
- .test-common
needs: ["build-debian-aarch64"]
script:
- meson setup build --buildtype release
-Dtestdata_tests=true
-Dlogging=false
-Dtrim_dsp=false
- ninja -C build
- cd build && time meson test -v
test-debian-ppc64le:
extends:
- .debian-ppc64le-common
- .test-common
variables:
CC: gcc-13
needs: ["build-debian-ppc64le"]
script:
- meson setup build --buildtype release
-Dtestdata_tests=true
-Dlogging=false
-Dtrim_dsp=false
- ninja -C build
- cd build && time meson test -v
test-debian-riscv64:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-debian-riscv64"]
script:
- meson setup build --buildtype release
-Dtestdata_tests=true
-Dlogging=false
-Dtrim_dsp=false
--cross-file package/crossfiles/riscv64-linux.meson
- ninja -C build
- cd build && time meson test -v --timeout-multiplier 10
variables:
QEMU_LD_PREFIX: /usr/riscv64-linux-gnu/
parallel:
matrix:
- QEMU_CPU: [ "rv64,v=true,vext_spec=v1.0,vlen=128,elen=64",
"rv64,v=true,vext_spec=v1.0,vlen=256,elen=64",
"rv64,v=true,vext_spec=v1.0,vlen=512,elen=64",
"rv64,v=true,vext_spec=v1.0,vlen=1024,elen=64" ]
test-debian-aarch64-qemu:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-debian-aarch64"]
script:
- meson setup build --buildtype release
-Dtestdata_tests=true
-Dlogging=false
-Dtrim_dsp=false
--cross-file package/crossfiles/aarch64-linux.meson
- ninja -C build
- cd build && time meson test -v --timeout-multiplier 10
variables:
QEMU_LD_PREFIX: /usr/aarch64-linux-gnu/
parallel:
matrix:
# sve-default-vector-length sets the max vector length in bytes;
# the default is 64, allowing up to 512 bit vectors. Testing 1024
# and 2048 bit vectors requires raising this limit. The sve<n>
# option sets the active vector length in bits.
- QEMU_CPU: [ "max,sve-default-vector-length=256,sve128=on",
"max,sve-default-vector-length=256,sve256=on",
"max,sve-default-vector-length=256,sve512=on",
"max,sve-default-vector-length=256,sve1024=on",
"max,sve-default-vector-length=256,sve2048=on" ]
test-debian-armv7-clang-5:
extends:
- .debian-armv7-common
- .test-common
needs: ["build-debian-armv7-clang-5"]
variables:
CC: clang-5.0
CFLAGS: '-integrated-as'
script:
- linux32 meson setup build --buildtype release
-Dtestdata_tests=true
-Dlogging=false
-Dtrim_dsp=false
- ninja -C build
- cd build && time meson test -v
test-debian-loongarch64:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-debian-loongarch64"]
variables:
QEMU_CPU: max-loongarch-cpu
QEMU_LD_PREFIX: /opt/cross-tools/target/
script:
- meson setup build --buildtype release
-Dtestdata_tests=true
-Dlogging=false
-Dtrim_dsp=false
--cross-file package/crossfiles/loongarch64-linux.meson
- ninja -C build
- cd build && time meson test -v --timeout-multiplier 10
.test-argon-script: &test-argon-script
- meson setup build --buildtype release
-Dlogging=false
-Dtrim_dsp=false
- cd build && ninja
- exit_code=0
test-debian-argon:
extends:
- .debian-amd64-common
- .test-argon
needs: ["build-debian"]
tags:
- docker
- amd64
- avx2
script:
- *test-argon-script
- ../tests/dav1d_argon.bash -t 1 -c 0 || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 2 -c sse2 -g 0 || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 3 -c ssse3 || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 4 -c sse41 || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 5 -c avx2 || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
test-debian32-argon:
extends:
- .debian-amd64-common
- .test-argon
needs: ["build-debian32"]
script:
- meson setup build --buildtype release
-Dlogging=false
-Dtrim_dsp=false
--cross-file package/crossfiles/i686-linux32.meson
- cd build && ninja
- exit_code=0
- ../tests/dav1d_argon.bash -t 2 -c sse2 || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 2 -c ssse3 || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 2 -c sse41 -g 0 || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
test-debian-argon-avx512:
extends:
- .debian-amd64-common
- .test-argon
needs: ["build-debian-avx512"]
tags:
- docker
- amd64-avx512
script:
- *test-argon-script
- ../tests/dav1d_argon.bash -t 2 -c avx512icl || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
test-debian-armv7-argon:
extends:
- .debian-armv7-common
- .test-argon
needs: ["build-debian-armv7"]
script:
- *test-argon-script
- ../tests/dav1d_argon.bash -t 3 -c 0 || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 2 -c neon || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 1 -c neon -g 0 || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
test-debian-aarch64-argon:
extends:
- .debian-aarch64-common
- .test-argon
needs: ["build-debian-aarch64"]
tags:
- docker
- aarch64
- dotprod
script:
- *test-argon-script
- ../tests/dav1d_argon.bash -t 2 -c 0 || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 3 -c neon || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 1 -c neon -g 0 || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 4 -c dotprod || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
.pages-common:
extends: .debian-amd64-common
script:
- meson setup build --buildtype release
--werror
-Denable_docs=true
- ninja -C build doc/html
- mv build/doc/html public
artifacts:
paths:
- public
build-pages:
extends: .pages-common
rules:
- if: '$CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH'
pages:
extends: .pages-common
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
changes:
- include/dav1d/*
- doc/meson.build
- doc/Doxyfile.in.in

View file

@ -0,0 +1,56 @@
# dav1d contribution guide
## CoC
The [VideoLAN Code of Conduct](https://wiki.videolan.org/CoC) applies fully to this project.
## ToDo
The todo list can be found [on the wiki](https://code.videolan.org/videolan/dav1d/wikis/task-list).
## Codebase language
The codebase is developed with the following assumptions:
For the library:
- C language with C99 version, without the VLA or the Complex (*\_\_STDC_NO_COMPLEX__*) features, and without compiler extensions. Anonymous structures and unions are the only allowed compiler extensions for internal code.
- x86 asm in .asm files, using the NASM syntax,
- arm/arm64 in .S files, using the GAS syntax limited to subset llvm 5.0's internal assembler supports,
- no C++ is allowed, whatever the version.
For the tools and utils:
- C *(see above for restrictions)*
- Rust
- C++ is only allowed for the MFT.
If you want to use *Threads* or *Atomic* features, please conform to the **C11**/**POSIX** semantic and use a wrapper for older compilers/platforms *(like done in VLC)*.
Please use modern standard POSIX functions *(strscpy, asprintf, tdestroy)*, and provide a compatibility fallback *(like done in VLC)*.
We will make reasonable efforts for compilers that are a bit older, but we won't support gcc 3 or MSVC 2012.
## Authorship
Please provide a correct authorship for your commit logs, with a name and a valid email.
We will reject anonymous contributions for now. As an exception, known pseudonyms from the multimedia community are accepted.
This project is respecting **Copyright** and **Droit d'auteur**. There is no copyright attribution or CLA.
## Commit logs
Please read [How to Write a Git Commit Message](https://chris.beams.io/posts/git-commit/).
## Submit requests (WIP)
- Code,
- [Compile](https://xkcd.com/303/),
- Check your [code style](https://code.videolan.org/videolan/dav1d/wikis/Coding-style),
- Test,
- Try,
- Submit patches through merge requests,
- Check that this passes the CI.
## Patent license
You need to read, understand, and agree to the [AV1 patents license](doc/PATENTS), before committing.

View file

@ -0,0 +1,23 @@
Copyright © 2018-2025, VideoLAN and dav1d authors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

460
media/libdav1d/src/NEWS Normal file
View file

@ -0,0 +1,460 @@
Changes for 1.5.3 'Sonic':
--------------------------
1.5.3 is a minor release of dav1d, focused on RISC-V and maintenance:
- Misc small optimizations
- RISC-V assembly optimizations for ipred, emu_edge and w_mask,
and VLEN 512 for blend functions
- Fix issue with ivf files with 0 frames in tools
Changes for 1.5.2 'Sonic':
--------------------------
1.5.2 is a minor release of dav1d, focused on maintenance:
- minor speed improvement in recon
- improvements on loongarch symboles visibility and asm
- mark C globals with small code model
- reduce the code size of the frame header parsing (OBU)
- minor fixes on tools and CI
- fix compilation with nasm 3.00
Changes for 1.5.1 'Sonic':
--------------------------
1.5.1 is a minor release of dav1d, focusing on optimizations and stack reduction:
- Rewrite of the looprestoration (SGR, wiener) to reduce stack usage
- Rewrite of {put,prep}_scaled functions
Now, the required stack space for dav1d should be: 62 KB on x86_64 and
58KB on arm and aarch64.
- Improvements on the SSSE3 SGR
- Improvements on ARM32/ARM64 looprestoration optimizations
- RISC-V: blend optimizations for high bitdepth
- Power9: blend optimizations for 8bpc
- Port RISC-V to POSIX/non-Linux OS
- AArch64: Add Neon implementation of load_tmvs
- Fix a rare, but possible deadlock, in flush()
Changes for 1.5.0 'Sonic':
--------------------------
1.5.0 is a major release of dav1d, that:
- WARNING: we removed some of the SSE2 optimizations, so if you care about
systems without SSSE3, you should be careful when updating!
- Add Arm OpenBSD run-time CPU feature
- Optimize index offset calculations for decode_coefs
- picture: copy HDR10+ and T35 metadata only to visible frames
- SSSE3 new optimizations for 6-tap (8bit and hbd)
- AArch64/SVE: Add HBD subpel filters using 128-bit SVE2
- AArch64: Add USMMLA Implementation for 6-tap H/HV
- AArch64: Optimize Armv8.0 NEON for HBD horizontal filters and 6-tap filters
- Power9: Optimized ITX till 16x4.
- Loongarch: numerous optimizations
- RISC-V optimizations for pal, cdef_filter, ipred, mc_blend, mc_bdir, itx
- Allow playing videos in full-screen mode in dav1dplay
Changes for 1.4.3 'Road Runner':
--------------------------------
1.4.3 is a small release focused on security issues
- AArch64: Fix potential out of bounds access in DotProd H/HV filters
- cli: Prevent buffer over-read
Changes for 1.4.2 'Road Runner':
--------------------------------
1.4.2 is a small release of dav1d, improving notably ARM, AVX-512 and PowerPC
- AVX2 optimizations for 8-tap and new variants for 6-tap
- AVX-512 optimizations for 8-tap and new variants for 6-tap
- Improve entropy decoding on ARM64
- New ARM64 optimizations for convolutions based on DotProd extension
- New ARM64 optimizations for convolutions based on i8mm extension
- New ARM64 optimizations for subpel and prep filters for i8mm
- Misc improvements on existing ARM64 optimizations, notably for put/prep
- New PowerPC9 optimizations for loopfilter
- Support for macOS kperf API for benchmarking
Changes for 1.4.1 'Road Runner':
--------------------------------
1.4.1 is a small release of dav1d, improving notably ARM and RISC-V speed
- Optimizations for 6tap filters for NEON (ARM)
- More RISC-V optimizations for itx (4x8, 8x4, 4x16, 16x4, 8x16, 16x8)
- Reduction of binary size on ARM64, ARM32 and RISC-V
- Fix out-of-bounds read in 8bpc SSE2/SSSE3 wiener_filter
- Msac optimizations
Changes for 1.4.0 'Road Runner':
--------------------------------
1.4.0 is a medium release of dav1d, focusing on new architecture support and optimizations
- AVX-512 optimizations for z1, z2, z3 in 8bit and high-bitdepth
- New architecture supported: loongarch
- Loongarch optimizations for 8bit
- New architecture supported: RISC-V
- RISC-V optimizations for itx
- Misc improvements in threading and in reducing binary size
- Fix potential integer overflow with extremely large frame sizes (CVE-2024-1580)
Changes for 1.3.0 'Tundra Peregrine Falcon (Calidus)':
------------------------------------------------------
1.3.0 is a medium release of dav1d, focus on new APIs and memory usage reduction.
- Reduce memory usage in numerous places
- ABI break in Dav1dSequenceHeader, Dav1dFrameHeader, Dav1dContentLightLevel structures
- new API function to check the API version: dav1d_version_api()
- Rewrite of the SGR functions for ARM64 to be faster
- NEON implemetation of save_tmvs for ARM32 and ARM64
- x86 palette DSP for pal_idx_finish function
Changes for 1.2.1 'Arctic Peregrine Falcon':
--------------------------------------------
1.2.1 is a small release of dav1d, adding more SIMD and fixes
- Fix a threading race on task_thread.init_done
- NEON z2 8bpc and high bit-depth optimizations
- SSSE3 z2 high bit-depth optimziations
- Fix a desynced luma/chroma planes issue with Film Grain
- Reduce memory consumption
- Improve dav1d_parse_sequence_header() speed
- OBU: Improve header parsing and fix potential overflows
- OBU: Improve ITU-T T.35 parsing speed
- Misc buildsystems, CI and headers fixes
Changes for 1.2.0 'Arctic Peregrine Falcon':
--------------------------------------------
1.2.0 is a small release of dav1d, adding more SIMD and fixes
- Improvements on attachments of props and T.35 entries on output pictures
- NEON z1/z3 high bit-depth optimizations and improvements for 8bpc
- SSSE3 z2/z3 8bpc and SSSE3 z1/z3 high bit-depth optimziations
- refmvs.save_tmvs optimizations in SSSE3/AVX2/AVX-512
- AVX-512 optimizations for high bit-depth itx (16x64, 32x64, 64x16, 64x32, 64x64)
- AVX2 optimizations for 12bpc for 16x32, 32x16, 32x32 itx
Changes for 1.1.0 'Arctic Peregrine Falcon':
--------------------------------------------
1.1.0 is an important release of dav1d, fixing numerous bugs, and adding SIMD
- New function dav1d_get_frame_delay to query the decoder frame delay
- Numerous fixes for strict conformity to the specs and samples
- NEON and AVX-512 misc fixes and improvements
- Partial AVX2 12bpc transform implementations
- AVX-512 high bit-depth cdef_filter, loopfilter, itx
- NEON z1/z3 optimization for 8bpc
- SSSE3 z1 optimization for 8bpc
"From VideoLAN with love"
Changes for 1.0.0 'Peregrine Falcon':
-------------------------------------
1.0.0 is a major release of dav1d, adding important features and bug fixes.
It notably changes, in an important way, the way threading works, by adding
an automatic thread management.
It also adds support for AVX-512 acceleration, and adds speedups to existing x86
code (from SSE2 to AVX2).
1.0.0 adds new grain API to ease acceleration on the GPU, and adds an API call
to get information of which frame failed to decode, in error cases.
Finally, 1.0.0 fixes numerous small bugs that were reported since the beginning
of the project to have a proper release.
.''.
.''. . *''* :_\/_: .
:_\/_: _\(/_ .:.*_\/_* : /\ : .'.:.'.
.''.: /\ : ./)\ ':'* /\ * : '..'. -=:o:=-
:_\/_:'.:::. ' *''* * '.\'/.' _\(/_'.':'.'
: /\ : ::::: *_\/_* -= o =- /)\ ' *
'..' ':::' * /\ * .'/.\'. '
* *..* :
* :
* 1.0.0
Changes for 0.9.2 'Golden Eagle':
---------------------------------
0.9.2 is a small update of dav1d on the 0.9.x branch:
- x86: SSE4 optimizations of inverse transforms for 10bit for all sizes
- x86: mc.resize optimizations with AVX2/SSSE3 for 10/12b
- x86: SSSE3 optimizations for cdef_filter in 10/12b and mc_w_mask_422/444 in 8b
- ARM NEON optimizations for FilmGrain Gen_grain functions
- Optimizations for splat_mv in SSE2/AVX2 and NEON
- x86: SGR improvements for SSSE3 CPUs
- x86: AVX2 optimizations for cfl_ac
Changes for 0.9.1 'Golden Eagle':
---------------------------------
0.9.1 is a middle-size revision of dav1d, adding notably 10b acceleration for SSSE3:
- 10/12b SSSE3 optimizations for mc (avg, w_avg, mask, w_mask, emu_edge),
prep/put_bilin, prep/put_8tap, ipred (dc/h/v, paeth, smooth, pal, filter), wiener,
sgr (10b), warp8x8, deblock, film_grain, cfl_ac/pred for 32bit and 64bit x86 processors
- Film grain NEON for fguv 10/12b, fgy/fguv 8b and fgy/fguv 10/12 arm32
- Fixes for filmgrain on ARM
- itx 10bit optimizations for 4x4/x8/x16, 8x4/x8/x16 for SSE4
- Misc improvements on SSE2, SSE4
Changes for 0.9.0 'Golden Eagle':
---------------------------------
0.9.0 is a major version of dav1d, adding notably 10b acceleration on x64.
Details:
- x86 (64bit) AVX2 implementation of most 10b/12b functions, which should provide
a large boost for high-bitdepth decoding on modern x86 computers and servers.
- ARM64 neon implementation of FilmGrain (4:2:0/4:2:2/4:4:4 8bit)
- New API to signal events happening during the decoding process
Changes for 0.8.2 'Eurasian Hobby':
-----------------------------------
0.8.2 is a middle-size update of the 0.8.0 branch:
- ARM32 optimizations for ipred and itx in 10/12bits,
completing the 10b/12b work on ARM64 and ARM32
- Give the post-filters their own threads
- ARM64: rewrite the wiener functions
- Speed up coefficient decoding, 0.5%-3% global decoding gain
- x86 optimizations for CDEF_filter and wiener in 10/12bit
- x86: rewrite the SGR AVX2 asm
- x86: improve msac speed on SSE2+ machines
- ARM32: improve speed of ipred and warp
- ARM64: improve speed of ipred, cdef_dir, cdef_filter, warp_motion and itx16
- ARM32/64: improve speed of looprestoration
- Add seeking, pausing to the player
- Update the player for rendering of 10b/12b
- Misc speed improvements and fixes on all platforms
- Add a xxh3 muxer in the dav1d application
Changes for 0.8.1 'Eurasian Hobby':
-----------------------------------
0.8.1 is a minor update on 0.8.0:
- Keep references to buffers valid after dav1d_close(). Fixes a regression
caused by the picture buffer pool added in 0.8.0.
- ARM32 optimizations for 10bit bitdepth for SGR
- ARM32 optimizations for 16bit bitdepth for blend/w_masl/emu_edge
- ARM64 optimizations for 10bit bitdepth for SGR
- x86 optimizations for wiener in SSE2/SSSE3/AVX2
Changes for 0.8.0 'Eurasian Hobby':
-----------------------------------
0.8.0 is a major update for dav1d:
- Improve the performance by using a picture buffer pool;
The improvements can reach 10% on some cases on Windows.
- Support for Apple ARM Silicon
- ARM32 optimizations for 8bit bitdepth for ipred paeth, smooth, cfl
- ARM32 optimizations for 10/12/16bit bitdepth for mc_avg/mask/w_avg,
put/prep 8tap/bilin, wiener and CDEF filters
- ARM64 optimizations for cfl_ac 444 for all bitdepths
- x86 optimizations for MC 8-tap, mc_scaled in AVX2
- x86 optimizations for CDEF in SSE and {put/prep}_{8tap/bilin} in SSSE3
Changes for 0.7.1 'Frigatebird':
------------------------------
0.7.1 is a minor update on 0.7.0:
- ARM32 NEON optimizations for itxfm, which can give up to 28% speedup, and MSAC
- SSE2 optimizations for prep_bilin and prep_8tap
- AVX2 optimizations for MC scaled
- Fix a clamping issue in motion vector projection
- Fix an issue on some specific Haswell CPU on ipred_z AVX2 functions
- Improvements on the dav1dplay utility player to support resizing
Changes for 0.7.0 'Frigatebird':
------------------------------
0.7.0 is a major release for dav1d:
- Faster refmv implementation gaining up to 12% speed while -25% of RAM (Single Thread)
- 10b/12b ARM64 optimizations are mostly complete:
- ipred (paeth, smooth, dc, pal, filter, cfl)
- itxfm (only 10b)
- AVX2/SSSE3 for non-4:2:0 film grain and for mc.resize
- AVX2 for cfl4:4:4
- AVX-512 CDEF filter
- ARM64 8b improvements for cfl_ac and itxfm
- ARM64 implementation for emu_edge in 8b/10b/12b
- ARM32 implementation for emu_edge in 8b
- Improvements on the dav1dplay utility player to support 10 bit,
non-4:2:0 pixel formats and film grain on the GPU
Changes for 0.6.0 'Gyrfalcon':
------------------------------
0.6.0 is a major release for dav1d:
- New ARM64 optimizations for the 10/12bit depth:
- mc_avg, mc_w_avg, mc_mask
- mc_put/mc_prep 8tap/bilin
- mc_warp_8x8
- mc_w_mask
- mc_blend
- wiener
- SGR
- loopfilter
- cdef
- New AVX-512 optimizations for prep_bilin, prep_8tap, cdef_filter, mc_avg/w_avg/mask
- New SSSE3 optimizations for film grain
- New AVX2 optimizations for msac_adapt16
- Fix rare mismatches against the reference decoder, notably because of clipping
- Improvements on ARM64 on msac, cdef, mc_blend_v and looprestoration optimizations
- Improvements on AVX2 optimizations for cdef_filter
- Improvements in the C version for itxfm, cdef_filter
Changes for 0.5.2 'Asiatic Cheetah':
------------------------------------
0.5.2 is a small release improving speed for ARM32 and adding minor features:
- ARM32 optimizations for loopfilter, ipred_dc|h|v
- Add section-5 raw OBU demuxer
- Improve the speed by reducing the L2 cache collisions
- Fix minor issues
Changes for 0.5.1 'Asiatic Cheetah':
------------------------------------
0.5.1 is a small release improving speeds and fixing minor issues
compared to 0.5.0:
- SSE2 optimizations for CDEF, wiener and warp_affine
- NEON optimizations for SGR on ARM32
- Fix mismatch issue in x86 asm in inverse identity transforms
- Fix build issue in ARM64 assembly if debug info was enabled
- Add a workaround for Xcode 11 -fstack-check bug
Changes for 0.5.0 'Asiatic Cheetah':
------------------------------------
0.5.0 is a medium release fixing regressions and minor issues,
and improving speed significantly:
- Export ITU T.35 metadata
- Speed improvements on blend_ on ARM
- Speed improvements on decode_coef and MSAC
- NEON optimizations for blend*, w_mask_, ipred functions for ARM64
- NEON optimizations for CDEF and warp on ARM32
- SSE2 optimizations for MSAC hi_tok decoding
- SSSE3 optimizations for deblocking loopfilters and warp_affine
- AVX2 optimizations for film grain and ipred_z2
- SSE4 optimizations for warp_affine
- VSX optimizations for wiener
- Fix inverse transform overflows in x86 and NEON asm
- Fix integer overflows with large frames
- Improve film grain generation to match reference code
- Improve compatibility with older binutils for ARM
- More advanced Player example in tools
Changes for 0.4.0 'Cheetah':
----------------------------
- Fix playback with unknown OBUs
- Add an option to limit the maximum frame size
- SSE2 and ARM64 optimizations for MSAC
- Improve speed on 32bits systems
- Optimization in obmc blend
- Reduce RAM usage significantly
- The initial PPC SIMD code, cdef_filter
- NEON optimizations for blend functions on ARM
- NEON optimizations for w_mask functions on ARM
- NEON optimizations for inverse transforms on ARM64
- VSX optimizations for CDEF filter
- Improve handling of malloc failures
- Simple Player example in tools
Changes for 0.3.1 'Sailfish':
------------------------------
- Fix a buffer overflow in frame-threading mode on SSSE3 CPUs
- Reduce binary size, notably on Windows
- SSSE3 optimizations for ipred_filter
- ARM optimizations for MSAC
Changes for 0.3.0 'Sailfish':
------------------------------
This is the final release for the numerous speed improvements of 0.3.0-rc.
It mostly:
- Fixes an annoying crash on SSSE3 that happened in the itx functions
Changes for 0.2.2 (0.3.0-rc) 'Antelope':
-----------------------------
- Large improvement on MSAC decoding with SSE, bringing 4-6% speed increase
The impact is important on SSSE3, SSE4 and AVX2 cpus
- SSSE3 optimizations for all blocks size in itx
- SSSE3 optimizations for ipred_paeth and ipred_cfl (420, 422 and 444)
- Speed improvements on CDEF for SSE4 CPUs
- NEON optimizations for SGR and loop filter
- Minor crashes, improvements and build changes
Changes for 0.2.1 'Antelope':
----------------------------
- SSSE3 optimization for cdef_dir
- AVX2 improvements of the existing CDEF optimizations
- NEON improvements of the existing CDEF and wiener optimizations
- Clarification about the numbering/versionning scheme
Changes for 0.2.0 'Antelope':
----------------------------
- ARM64 and ARM optimizations using NEON instructions
- SSSE3 optimizations for both 32 and 64bits
- More AVX2 assembly, reaching almost completion
- Fix installation of includes
- Rewrite inverse transforms to avoid overflows
- Snap packaging for Linux
- Updated API (ABI and API break)
- Fixes for un-decodable samples
Changes for 0.1.0 'Gazelle':
----------------------------
Initial release of dav1d, the fast and small AV1 decoder.
- Support for all features of the AV1 bitstream
- Support for all bitdepth, 8, 10 and 12bits
- Support for all chroma subsamplings 4:2:0, 4:2:2, 4:4:4 *and* grayscale
- Full acceleration for AVX2 64bits processors, making it the fastest decoder
- Partial acceleration for SSSE3 processors
- Partial acceleration for NEON processors

View file

@ -0,0 +1,168 @@
![dav1d logo](doc/dav1d_logo.png)
# dav1d
**dav1d** is an **AV1** cross-platform **d**ecoder, open-source, and focused on speed and correctness.
It is now battle-tested and production-ready and can be used everywhere.
The canonical repository URL for this repo is https://code.videolan.org/videolan/dav1d
This project was partially funded by the *Alliance for Open Media*/**AOM**.
## Goal and Features
The goal of this project is to provide a decoder for **most platforms**, and achieve the **highest speed** possible to overcome the temporary lack of AV1 hardware decoder.
It supports all features from AV1, including all subsampling and bit-depth parameters.
In the future, this project will host simple tools or simple wrappings *(like, for example, an MFT transform)*.
## License
**dav1d** is released under a very liberal license, a contrario from the other VideoLAN projects, so that it can be embedded anywhere, including non-open-source software; or even drivers, to allow the creation of hybrid decoders.
The reasoning behind this decision is the same as for libvorbis, see [RMS on vorbis](https://lwn.net/2001/0301/a/rms-ov-license.php3).
# Roadmap
The plan is the following:
### Reached
1. Complete C implementation of the decoder,
2. Provide a usable API,
3. Port to most platforms,
4. Make it fast on desktop, by writing asm for AVX2 chips.
5. Make it fast on mobile, by writing asm for ARMv8 chips,
6. Make it fast on older desktop, by writing asm for SSSE3+ chips,
7. Make high bit-depth fast on mobile, by writing asm for ARMv8 chips.
8. Make it fast on older mobile, by writing asm for ARMv7 chips,
9. Make high bit-depth fast on older mobile, by writing asm for ARMv7 chips,
10. Make high bit-depth fast on desktop, by writing asm for AVX2 chips,
11. Make high bit-depth fast on older desktop, by writing asm for SSSE3+ chips,
12. Improve threading.
### On-going
13. Improve C code base with [various tweaks](https://code.videolan.org/videolan/dav1d/wikis/task-list),
14. Accelerate for less common architectures, like PPC, SSE2, RISC-V or AVX-512.
### After
15. Use more GPU decoding, when possible.
# Contribute
Currently, we are looking for help from:
- C developers,
- asm developers,
- platform-specific developers,
- GPGPU developers,
- testers.
Our contributions guidelines are quite strict. We want to build a coherent codebase to simplify maintenance and achieve the highest possible speed.
Notably, the codebase is in pure C and asm.
We are on IRC, on the **#dav1d** channel on [*Libera.chat*](http://libera.chat/). If you do not have an IRC Client at hand, use [IRC Web Interface](https://web.libera.chat/#dav1d).
See the [contributions document](CONTRIBUTING.md).
## CLA
There is no CLA.
People will keep their copyright and their authorship rights, while adhering to the BSD 2-clause license.
VideoLAN will only have the collective work rights.
## CoC
The [VideoLAN Code of Conduct](https://wiki.videolan.org/CoC) applies to this project.
# Compile
## General compilation steps
1. Install [Meson](https://mesonbuild.com/) (0.49 or higher), [Ninja](https://ninja-build.org/), and, for x86\* targets, [nasm](https://nasm.us/) (2.14 or higher)
2. Run `mkdir build && cd build` to create a build directory and enter it
3. Run `meson setup ..` to configure meson, add `--default-library=static` if static linking is desired
4. Run `ninja` to compile
Following are modification of step 3 and 4, for specific purpose.
## Cross-Compilation for 32- or 64-bit Windows, 32-bit Linux
If you're on a linux build machine trying to compile .exe for a Windows target/host machine, configure meson like this
```
meson setup .. --cross-file=../package/crossfiles/x86_64-w64-mingw32.meson
```
or, for 32-bit:
```
meson setup .. --cross-file=../package/crossfiles/i686-w64-mingw32.meson
```
`mingw-w64` is a pre-requisite and should be installed on your linux machine via your preferred method or package manager. Note the binary name formats may differ between distributions. Verify the names, and use `alias` if certain binaries cannot be found.
For 32-bit linux, run
```
meson setup .. --cross-file=../package/crossfiles/i686-linux32.meson
```
## Build documentation
1. Make sure [doxygen](https://www.doxygen.nl/) and [graphviz](https://www.graphviz.org/) are installed.
2. Run `meson setup .. -Denable_docs=true` to configure meson to generate docs from the build directory.
3. Run `ninja doc/html` to build the docs
The result can be found in `build/doc/html/`. An online version built from master can be found [here](https://videolan.videolan.me/dav1d/).
# Run tests
1. In the root directory, run `git clone https://code.videolan.org/videolan/dav1d-test-data.git tests/dav1d-test-data` to fetch the test data repository
2. During meson configuration, specify `-Dtestdata_tests=true`
3. Run `meson test -v` after compiling
## Decoder conformance tests (optional but encouraged)
1. Download the argon conformance bitstreams from https://streams.videolan.org/argon/
2. Extract into dav1d directory by running `tar -xvf argon.tar.zst`
3. Execute tests with `tests/dav1d_argon.bash -d build/tools/dav1d -a argon`
4. Expected outcome is `2763 files successfully verified in XXmYYs (dav1d 1.x.y-zz-gHHHHHHH filmgrain=1 cpumask=-1)`
# Support
This project is partially funded by the *Alliance for Open Media*/**AOM** and is supported by TwoOrioles and VideoLabs.
These companies can provide support and integration help, should you need it.
# FAQ
## Why do you not improve libaom rather than starting a new project?
- We believe that libaom is a very good library. It was however developed for research purposes during AV1 design.
We think that an implementation written from scratch can achieve faster decoding, in the same way that *ffvp9* was faster than *libvpx*.
## Is dav1d a recursive acronym?
- Yes.
## Can I help?
- Yes. See the [contributions document](CONTRIBUTING.md).
## I am not a developer. Can I help?
- Yes. We need testers, bug reporters and documentation writers.
## What about the AV1 patent license?
- This project is an implementation of a decoder. It gives you no special rights on the AV1 patents.
Please read the [AV1 patent license](doc/PATENTS) that applies to the AV1 specification and codec.
## Will you care about <my_arch>? <my_os>?
- We do, but we don't have either the time or the knowledge. Therefore, patches and contributions welcome.

View file

@ -0,0 +1,35 @@
# The dav1d project and VideoLAN association would like to thank
## AOM
The Alliance for Open Media (AOM) for partially funding this project.
## Companies
* Two Orioles LLC, for important coding effort
* VideoLabs SAS
## Projects
* VideoLAN
* FFmpeg
* libplacebo
## Individual
And all the dav1d Authors (git shortlog -sn), including:
Henrik Gramner, Martin Storsjö, Ronald S. Bultje, Janne Grunau, James Almer,
Victorien Le Couviour--Tuffet, Matthias Dressel, Nathan E. Egge,
Jean-Baptiste Kempf, Marvin Scholz, Luc Trudeau, Niklas Haas,
Hugo Beauzée-Luyssen, Konstantin Pavlov, David Michael Barr, Steve Lhomme,
yuanhecai, Luca Barbato, Wan-Teh Chang, Kyle Siefring, B Krishnan Iyer,
Francois Cartegnie, Liwei Wang, David Conrad, Derek Buitenhuis, Jan Beich,
Michael Bradshaw, Raphaël Zumer, Xuefeng Jiang, Arpad Panyik, Christophe Gisquet,
Justin Bull, Boyuan Xiao, Dale Curtis, Emmanuel Gil Peyrot, Raphael Zumer,
Rupert Swarbrick, Thierry Foucu, Thomas Daede, jinbo, André Kempe, Colin Lee,
Jonathan Wright, Lynne, Michail Alvanos, Nico Weber, Salome Thirot, SmilingWolf,
Tristan Laurent, Tristan Matthews, Vittorio Giovara, Yannis Guyon,
Andrey Semashev, Anisse Astier, Anton Mitrofanov, Charlie Hayden, Dmitriy Sychov,
Ewout ter Hoeven, Fred Barbier, Hao Chen, Jean-Yves Avenard, Joe Drago,
Mark Shuttleworth, Matthieu Bouron, Mehdi Sabwat, Nicolas Frattaroli,
Pablo Stebler, Rostislav Pehlivanov, Sebastian Dröge, Shiz, Steinar Midtskogen,
Sylvain BERTRAND, Sylvestre Ledru, Timo Gurr, Vibhoothi,
Vignesh Venkatasubramanian, Xavier Claessens, Xu Guangxin, kossh1 and skal.

View file

@ -0,0 +1,23 @@
PROJECT_NAME = dav1d
PROJECT_NUMBER = \@VCS_TAG\@
PROJECT_BRIEF = dav1d is an AV1 decoder
OUTPUT_DIRECTORY = @DOXYGEN_OUTPUT@
STRIP_FROM_PATH = @DOXYGEN_STRIP@
OUTPUT_LANGUAGE = English
TAB_SIZE = 4
EXTRACT_ALL = YES
OPTIMIZE_OUTPUT_FOR_C = YES
DOXYFILE_ENCODING = UTF-8
TYPEDEF_HIDES_STRUCT = YES
HAVE_DOT = YES
QUIET = YES
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_AS_ERROR = FAIL_ON_WARNINGS
INPUT = @DOXYGEN_INPUT@
FILE_PATTERNS = *.h
GENERATE_HTML = YES
GENERATE_LATEX = NO

View file

@ -0,0 +1,108 @@
Alliance for Open Media Patent License 1.0
1. License Terms.
1.1. Patent License. Subject to the terms and conditions of this License, each
Licensor, on behalf of itself and successors in interest and assigns,
grants Licensee a non-sublicensable, perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as expressly stated in this
License) patent license to its Necessary Claims to make, use, sell, offer
for sale, import or distribute any Implementation.
1.2. Conditions.
1.2.1. Availability. As a condition to the grant of rights to Licensee to make,
sell, offer for sale, import or distribute an Implementation under
Section 1.1, Licensee must make its Necessary Claims available under
this License, and must reproduce this License with any Implementation
as follows:
a. For distribution in source code, by including this License in the
root directory of the source code with its Implementation.
b. For distribution in any other form (including binary, object form,
and/or hardware description code (e.g., HDL, RTL, Gate Level Netlist,
GDSII, etc.)), by including this License in the documentation, legal
notices, and/or other written materials provided with the
Implementation.
1.2.2. Additional Conditions. This license is directly from Licensor to
Licensee. Licensee acknowledges as a condition of benefiting from it
that no rights from Licensor are received from suppliers, distributors,
or otherwise in connection with this License.
1.3. Defensive Termination. If any Licensee, its Affiliates, or its agents
initiates patent litigation or files, maintains, or voluntarily
participates in a lawsuit against another entity or any person asserting
that any Implementation infringes Necessary Claims, any patent licenses
granted under this License directly to the Licensee are immediately
terminated as of the date of the initiation of action unless 1) that suit
was in response to a corresponding suit regarding an Implementation first
brought against an initiating entity, or 2) that suit was brought to
enforce the terms of this License (including intervention in a third-party
action by a Licensee).
1.4. Disclaimers. The Reference Implementation and Specification are provided
"AS IS" and without warranty. The entire risk as to implementing or
otherwise using the Reference Implementation or Specification is assumed
by the implementer and user. Licensor expressly disclaims any warranties
(express, implied, or otherwise), including implied warranties of
merchantability, non-infringement, fitness for a particular purpose, or
title, related to the material. IN NO EVENT WILL LICENSOR BE LIABLE TO
ANY OTHER PARTY FOR LOST PROFITS OR ANY FORM OF INDIRECT, SPECIAL,
INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER FROM ANY CAUSES OF
ACTION OF ANY KIND WITH RESPECT TO THIS LICENSE, WHETHER BASED ON BREACH
OF CONTRACT, TORT (INCLUDING NEGLIGENCE), OR OTHERWISE, AND WHETHER OR
NOT THE OTHER PARTRY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2. Definitions.
2.1. Affiliate. “Affiliate” means an entity that directly or indirectly
Controls, is Controlled by, or is under common Control of that party.
2.2. Control. “Control” means direct or indirect control of more than 50% of
the voting power to elect directors of that corporation, or for any other
entity, the power to direct management of such entity.
2.3. Decoder. "Decoder" means any decoder that conforms fully with all
non-optional portions of the Specification.
2.4. Encoder. "Encoder" means any encoder that produces a bitstream that can
be decoded by a Decoder only to the extent it produces such a bitstream.
2.5. Final Deliverable. “Final Deliverable” means the final version of a
deliverable approved by the Alliance for Open Media as a Final
Deliverable.
2.6. Implementation. "Implementation" means any implementation, including the
Reference Implementation, that is an Encoder and/or a Decoder. An
Implementation also includes components of an Implementation only to the
extent they are used as part of an Implementation.
2.7. License. “License” means this license.
2.8. Licensee. “Licensee” means any person or entity who exercises patent
rights granted under this License.
2.9. Licensor. "Licensor" means (i) any Licensee that makes, sells, offers
for sale, imports or distributes any Implementation, or (ii) a person
or entity that has a licensing obligation to the Implementation as a
result of its membership and/or participation in the Alliance for Open
Media working group that developed the Specification.
2.10. Necessary Claims. "Necessary Claims" means all claims of patents or
patent applications, (a) that currently or at any time in the future,
are owned or controlled by the Licensor, and (b) (i) would be an
Essential Claim as defined by the W3C Policy as of February 5, 2004
(https://www.w3.org/Consortium/Patent-Policy-20040205/#def-essential)
as if the Specification was a W3C Recommendation; or (ii) are infringed
by the Reference Implementation.
2.11. Reference Implementation. “Reference Implementation” means an Encoder
and/or Decoder released by the Alliance for Open Media as a Final
Deliverable.
2.12. Specification. “Specification” means the specification designated by
the Alliance for Open Media as a Final Deliverable for which this
License was issued.

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.3 KiB

View file

@ -0,0 +1,51 @@
# Copyright © 2018-2022, VideoLAN and dav1d authors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if not get_option('enable_docs')
subdir_done()
endif
doxygen = find_program('doxygen')
dot = find_program('dot')
conf_data = configuration_data()
conf_data.set('DOXYGEN_INPUT', dav1d_src_root / 'include/dav1d')
conf_data.set('DOXYGEN_STRIP', dav1d_src_root / 'include')
conf_data.set('DOXYGEN_OUTPUT', meson.current_build_dir())
doxyfile = configure_file(input: 'Doxyfile.in.in',
output: 'Doxyfile.in',
configuration: conf_data)
doxyfile_rev_target = vcs_tag(command: [
'git', '--git-dir', dav1d_git_dir, 'describe', '--long', '--always'
],
input: doxyfile,
output: 'Doxyfile'
)
custom_target('doc',
build_by_default: false,
command: [doxygen, doxyfile_rev_target],
output: ['html']
)

View file

@ -0,0 +1,792 @@
/*
* Copyright © 2019, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "vcs_version.h"
#include <getopt.h>
#include <stdbool.h>
#include <SDL.h>
#include "dav1d/dav1d.h"
#include "common/attributes.h"
#include "tools/input/input.h"
#include "dp_fifo.h"
#include "dp_renderer.h"
#define FRAME_OFFSET_TO_PTS(foff) \
(uint64_t)(((foff) * rd_ctx->spf) * 1000000000.0 + .5)
#define TS_TO_PTS(ts) \
(uint64_t)(((ts) * rd_ctx->timebase) * 1000000000.0 + .5)
// Selected renderer callbacks and cookie
static const Dav1dPlayRenderInfo *renderer_info = { NULL };
/**
* Render context structure
* This structure contains informations necessary
* to be shared between the decoder and the renderer
* threads.
*/
typedef struct render_context
{
Dav1dPlaySettings settings;
Dav1dSettings lib_settings;
// Renderer private data (passed to callbacks)
void *rd_priv;
// Lock to protect access to the context structure
SDL_mutex *lock;
// Timestamp of last displayed frame (in timebase unit)
int64_t last_ts;
// Timestamp of last decoded frame (in timebase unit)
int64_t current_ts;
// Ticks when last frame was received
uint32_t last_ticks;
// PTS time base
double timebase;
// Seconds per frame
double spf;
// Number of frames
uint32_t total;
// Fifo
Dav1dPlayPtrFifo *fifo;
// Custom SDL2 event types
uint32_t event_types;
// User pause state
uint8_t user_paused;
// Internal pause state
uint8_t paused;
// Start of internal pause state
uint32_t pause_start;
// Duration of internal pause state
uint32_t pause_time;
// Seek accumulator
int seek;
// Indicates if termination of the decoder thread was requested
uint8_t dec_should_terminate;
} Dav1dPlayRenderContext;
static void dp_settings_print_usage(const char *const app,
const char *const reason, ...)
{
if (reason) {
va_list args;
va_start(args, reason);
vfprintf(stderr, reason, args);
va_end(args);
fprintf(stderr, "\n\n");
}
fprintf(stderr, "Usage: %s [options]\n\n", app);
fprintf(stderr, "Supported options:\n"
" --input/-i $file: input file\n"
" --untimed/-u: ignore PTS, render as fast as possible\n"
" --threads $num: number of threads (default: 0)\n"
" --framedelay $num: maximum frame delay, capped at $threads (default: 0);\n"
" set to 1 for low-latency decoding\n"
" --highquality: enable high quality rendering\n"
" --zerocopy/-z: enable zero copy upload path\n"
" --gpugrain/-g: enable GPU grain synthesis\n"
" --fullscreen/-f: enable full screen mode\n"
" --version/-v: print version and exit\n"
" --renderer/-r: select renderer backend (default: auto)\n");
exit(1);
}
static unsigned parse_unsigned(const char *const optarg, const int option,
const char *const app)
{
char *end;
const unsigned res = (unsigned) strtoul(optarg, &end, 0);
if (*end || end == optarg)
dp_settings_print_usage(app, "Invalid argument \"%s\" for option %s; should be an integer",
optarg, option);
return res;
}
static void dp_rd_ctx_parse_args(Dav1dPlayRenderContext *rd_ctx,
const int argc, char *const *const argv)
{
int o;
Dav1dPlaySettings *settings = &rd_ctx->settings;
Dav1dSettings *lib_settings = &rd_ctx->lib_settings;
// Short options
static const char short_opts[] = "i:vuzgfr:";
enum {
ARG_THREADS = 256,
ARG_FRAME_DELAY,
ARG_HIGH_QUALITY,
};
// Long options
static const struct option long_opts[] = {
{ "input", 1, NULL, 'i' },
{ "version", 0, NULL, 'v' },
{ "untimed", 0, NULL, 'u' },
{ "threads", 1, NULL, ARG_THREADS },
{ "framedelay", 1, NULL, ARG_FRAME_DELAY },
{ "highquality", 0, NULL, ARG_HIGH_QUALITY },
{ "zerocopy", 0, NULL, 'z' },
{ "gpugrain", 0, NULL, 'g' },
{ "fullscreen", 0, NULL, 'f'},
{ "renderer", 0, NULL, 'r'},
{ NULL, 0, NULL, 0 },
};
while ((o = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
switch (o) {
case 'i':
settings->inputfile = optarg;
break;
case 'v':
fprintf(stderr, "%s\n", dav1d_version());
exit(0);
case 'u':
settings->untimed = true;
break;
case ARG_HIGH_QUALITY:
settings->highquality = true;
break;
case 'z':
settings->zerocopy = true;
break;
case 'g':
settings->gpugrain = true;
break;
case 'f':
settings->fullscreen = true;
break;
case 'r':
settings->renderer_name = optarg;
break;
case ARG_THREADS:
lib_settings->n_threads =
parse_unsigned(optarg, ARG_THREADS, argv[0]);
break;
case ARG_FRAME_DELAY:
lib_settings->max_frame_delay =
parse_unsigned(optarg, ARG_FRAME_DELAY, argv[0]);
break;
default:
dp_settings_print_usage(argv[0], NULL);
}
}
if (optind < argc)
dp_settings_print_usage(argv[0],
"Extra/unused arguments found, e.g. '%s'\n", argv[optind]);
if (!settings->inputfile)
dp_settings_print_usage(argv[0], "Input file (-i/--input) is required");
if (settings->renderer_name && strcmp(settings->renderer_name, "auto") == 0)
settings->renderer_name = NULL;
}
/**
* Destroy a Dav1dPlayRenderContext
*/
static void dp_rd_ctx_destroy(Dav1dPlayRenderContext *rd_ctx)
{
assert(rd_ctx != NULL);
renderer_info->destroy_renderer(rd_ctx->rd_priv);
dp_fifo_destroy(rd_ctx->fifo);
SDL_DestroyMutex(rd_ctx->lock);
free(rd_ctx);
}
/**
* Create a Dav1dPlayRenderContext
*
* \note The Dav1dPlayRenderContext must be destroyed
* again by using dp_rd_ctx_destroy.
*/
static Dav1dPlayRenderContext *dp_rd_ctx_create(int argc, char **argv)
{
Dav1dPlayRenderContext *rd_ctx;
// Alloc
rd_ctx = calloc(1, sizeof(Dav1dPlayRenderContext));
if (rd_ctx == NULL) {
return NULL;
}
// Parse and validate arguments
dav1d_default_settings(&rd_ctx->lib_settings);
memset(&rd_ctx->settings, 0, sizeof(rd_ctx->settings));
dp_rd_ctx_parse_args(rd_ctx, argc, argv);
// Init SDL2 library
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) {
fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError());
goto fail;
}
// Register a custom event to notify our SDL main thread
// about new frames
rd_ctx->event_types = SDL_RegisterEvents(3);
if (rd_ctx->event_types == UINT32_MAX) {
fprintf(stderr, "Failure to create custom SDL event types!\n");
goto fail;
}
rd_ctx->fifo = dp_fifo_create(5);
if (rd_ctx->fifo == NULL) {
fprintf(stderr, "Failed to create FIFO for output pictures!\n");
goto fail;
}
rd_ctx->lock = SDL_CreateMutex();
if (rd_ctx->lock == NULL) {
fprintf(stderr, "SDL_CreateMutex failed: %s\n", SDL_GetError());
goto fail;
}
// Select renderer
renderer_info = dp_get_renderer(rd_ctx->settings.renderer_name);
if (renderer_info == NULL) {
printf("No suitable renderer matching %s found.\n",
(rd_ctx->settings.renderer_name) ? rd_ctx->settings.renderer_name : "auto");
} else {
printf("Using %s renderer\n", renderer_info->name);
}
rd_ctx->rd_priv = (renderer_info) ? renderer_info->create_renderer(&rd_ctx->settings) : NULL;
if (rd_ctx->rd_priv == NULL) {
goto fail;
}
return rd_ctx;
fail:
if (rd_ctx->lock)
SDL_DestroyMutex(rd_ctx->lock);
if (rd_ctx->fifo)
dp_fifo_destroy(rd_ctx->fifo);
free(rd_ctx);
SDL_Quit();
return NULL;
}
/**
* Notify about new event
*/
static void dp_rd_ctx_post_event(Dav1dPlayRenderContext *rd_ctx, uint32_t type)
{
SDL_Event event;
SDL_zero(event);
event.type = type;
SDL_PushEvent(&event);
}
/**
* Update the decoder context with a new dav1d picture
*
* Once the decoder decoded a new picture, this call can be used
* to update the internal texture of the render context with the
* new picture.
*/
static void dp_rd_ctx_update_with_dav1d_picture(Dav1dPlayRenderContext *rd_ctx,
Dav1dPicture *dav1d_pic)
{
rd_ctx->current_ts = dav1d_pic->m.timestamp;
renderer_info->update_frame(rd_ctx->rd_priv, dav1d_pic, &rd_ctx->settings);
}
/**
* Toggle pause state
*/
static void dp_rd_ctx_toggle_pause(Dav1dPlayRenderContext *rd_ctx)
{
SDL_LockMutex(rd_ctx->lock);
rd_ctx->user_paused = !rd_ctx->user_paused;
if (rd_ctx->seek)
goto out;
rd_ctx->paused = rd_ctx->user_paused;
uint32_t now = SDL_GetTicks();
if (rd_ctx->paused)
rd_ctx->pause_start = now;
else {
rd_ctx->pause_time += now - rd_ctx->pause_start;
rd_ctx->pause_start = 0;
rd_ctx->last_ticks = now;
}
out:
SDL_UnlockMutex(rd_ctx->lock);
}
/**
* Query pause state
*/
static int dp_rd_ctx_is_paused(Dav1dPlayRenderContext *rd_ctx)
{
int ret;
SDL_LockMutex(rd_ctx->lock);
ret = rd_ctx->paused;
SDL_UnlockMutex(rd_ctx->lock);
return ret;
}
/**
* Request seeking, in seconds
*/
static void dp_rd_ctx_seek(Dav1dPlayRenderContext *rd_ctx, int sec)
{
SDL_LockMutex(rd_ctx->lock);
rd_ctx->seek += sec;
if (!rd_ctx->paused)
rd_ctx->pause_start = SDL_GetTicks();
rd_ctx->paused = 1;
SDL_UnlockMutex(rd_ctx->lock);
}
static int decode_frame(Dav1dPicture **p, Dav1dContext *c,
Dav1dData *data, DemuxerContext *in_ctx);
static inline void destroy_pic(void *a);
/**
* Seek the stream, if requested
*/
static int dp_rd_ctx_handle_seek(Dav1dPlayRenderContext *rd_ctx,
DemuxerContext *in_ctx,
Dav1dContext *c, Dav1dData *data)
{
int res = 0;
SDL_LockMutex(rd_ctx->lock);
if (!rd_ctx->seek)
goto out;
int64_t seek = rd_ctx->seek * 1000000000ULL;
uint64_t pts = TS_TO_PTS(rd_ctx->current_ts);
pts = ((int64_t)pts > -seek) ? pts + seek : 0;
int end = pts >= FRAME_OFFSET_TO_PTS(rd_ctx->total);
if (end)
pts = FRAME_OFFSET_TO_PTS(rd_ctx->total - 1);
uint64_t target_pts = pts;
dav1d_flush(c);
uint64_t shift = FRAME_OFFSET_TO_PTS(5);
while (1) {
if (shift > pts)
shift = pts;
if ((res = input_seek(in_ctx, pts - shift)))
goto out;
Dav1dSequenceHeader seq;
uint64_t cur_pts;
do {
if ((res = input_read(in_ctx, data)))
break;
cur_pts = TS_TO_PTS(data->m.timestamp);
res = dav1d_parse_sequence_header(&seq, data->data, data->sz);
} while (res && cur_pts < pts);
if (!res && cur_pts <= pts)
break;
if (shift > pts)
shift = pts;
pts -= shift;
}
if (!res) {
pts = TS_TO_PTS(data->m.timestamp);
while (pts < target_pts) {
Dav1dPicture *p;
if ((res = decode_frame(&p, c, data, in_ctx)))
break;
if (p) {
pts = TS_TO_PTS(p->m.timestamp);
if (pts < target_pts)
destroy_pic(p);
else {
dp_fifo_push(rd_ctx->fifo, p);
uint32_t type = rd_ctx->event_types + DAV1D_EVENT_SEEK_FRAME;
dp_rd_ctx_post_event(rd_ctx, type);
}
}
}
if (!res) {
rd_ctx->last_ts = data->m.timestamp - rd_ctx->spf / rd_ctx->timebase;
rd_ctx->current_ts = data->m.timestamp;
}
}
out:
rd_ctx->paused = rd_ctx->user_paused;
if (!rd_ctx->paused && rd_ctx->seek) {
uint32_t now = SDL_GetTicks();
rd_ctx->pause_time += now - rd_ctx->pause_start;
rd_ctx->pause_start = 0;
rd_ctx->last_ticks = now;
}
rd_ctx->seek = 0;
SDL_UnlockMutex(rd_ctx->lock);
if (res)
fprintf(stderr, "Error seeking, aborting\n");
return res;
}
/**
* Terminate decoder thread (async)
*/
static void dp_rd_ctx_request_shutdown(Dav1dPlayRenderContext *rd_ctx)
{
SDL_LockMutex(rd_ctx->lock);
rd_ctx->dec_should_terminate = 1;
SDL_UnlockMutex(rd_ctx->lock);
}
/**
* Query state of decoder shutdown request
*/
static int dp_rd_ctx_should_terminate(Dav1dPlayRenderContext *rd_ctx)
{
int ret = 0;
SDL_LockMutex(rd_ctx->lock);
ret = rd_ctx->dec_should_terminate;
SDL_UnlockMutex(rd_ctx->lock);
return ret;
}
/**
* Render the currently available texture
*
* Renders the currently available texture, if any.
*/
static void dp_rd_ctx_render(Dav1dPlayRenderContext *rd_ctx)
{
SDL_LockMutex(rd_ctx->lock);
// Calculate time since last frame was received
uint32_t ticks_now = SDL_GetTicks();
uint32_t ticks_diff = (rd_ctx->last_ticks != 0) ? ticks_now - rd_ctx->last_ticks : 0;
// Calculate when to display the frame
int64_t ts_diff = rd_ctx->current_ts - rd_ctx->last_ts;
int32_t pts_diff = (ts_diff * rd_ctx->timebase) * 1000.0 + .5;
int32_t wait_time = pts_diff - ticks_diff;
// In untimed mode, simply don't wait
if (rd_ctx->settings.untimed)
wait_time = 0;
// This way of timing the playback is not accurate, as there is no guarantee
// that SDL_Delay will wait for exactly the requested amount of time so in a
// accurate player this would need to be done in a better way.
if (wait_time > 0) {
SDL_Delay(wait_time);
} else if (wait_time < -10 && !rd_ctx->paused) { // Do not warn for minor time drifts
fprintf(stderr, "Frame displayed %f seconds too late\n", wait_time / 1000.0);
}
renderer_info->render(rd_ctx->rd_priv, &rd_ctx->settings);
rd_ctx->last_ts = rd_ctx->current_ts;
rd_ctx->last_ticks = SDL_GetTicks();
SDL_UnlockMutex(rd_ctx->lock);
}
static int decode_frame(Dav1dPicture **p, Dav1dContext *c,
Dav1dData *data, DemuxerContext *in_ctx)
{
int res;
// Send data packets we got from the demuxer to dav1d
if ((res = dav1d_send_data(c, data)) < 0) {
// On EAGAIN, dav1d can not consume more data and
// dav1d_get_picture needs to be called first, which
// will happen below, so just keep going in that case
// and do not error out.
if (res != DAV1D_ERR(EAGAIN)) {
dav1d_data_unref(data);
goto err;
}
}
*p = calloc(1, sizeof(**p));
// Try to get a decoded frame
if ((res = dav1d_get_picture(c, *p)) < 0) {
// In all error cases, even EAGAIN, p needs to be freed as
// it is never added to the queue and would leak.
free(*p);
*p = NULL;
// On EAGAIN, it means dav1d has not enough data to decode
// therefore this is not a decoding error but just means
// we need to feed it more data, which happens in the next
// run of the decoder loop.
if (res != DAV1D_ERR(EAGAIN))
goto err;
}
return data->sz == 0 ? input_read(in_ctx, data) : 0;
err:
fprintf(stderr, "Error decoding frame: %s\n",
strerror(-res));
return res;
}
static inline void destroy_pic(void *a)
{
Dav1dPicture *p = (Dav1dPicture *)a;
dav1d_picture_unref(p);
free(p);
}
/* Decoder thread "main" function */
static int decoder_thread_main(void *cookie)
{
Dav1dPlayRenderContext *rd_ctx = cookie;
Dav1dPicture *p;
Dav1dContext *c = NULL;
Dav1dData data;
DemuxerContext *in_ctx = NULL;
int res = 0;
unsigned total, timebase[2], fps[2];
Dav1dPlaySettings settings = rd_ctx->settings;
if ((res = input_open(&in_ctx, "ivf",
settings.inputfile,
fps, &total, timebase)) < 0)
{
fprintf(stderr, "Failed to open demuxer\n");
res = 1;
goto cleanup;
}
rd_ctx->timebase = (double)timebase[1] / timebase[0];
rd_ctx->spf = (double)fps[1] / fps[0];
rd_ctx->total = total;
if ((res = dav1d_open(&c, &rd_ctx->lib_settings))) {
fprintf(stderr, "Failed opening dav1d decoder\n");
res = 1;
goto cleanup;
}
if ((res = input_read(in_ctx, &data)) < 0) {
fprintf(stderr, "Failed demuxing input\n");
res = 1;
goto cleanup;
}
// Decoder loop
while (1) {
if (dp_rd_ctx_should_terminate(rd_ctx) ||
(res = dp_rd_ctx_handle_seek(rd_ctx, in_ctx, c, &data)) ||
(res = decode_frame(&p, c, &data, in_ctx)))
{
break;
}
else if (p) {
// Queue frame
SDL_LockMutex(rd_ctx->lock);
int seek = rd_ctx->seek;
SDL_UnlockMutex(rd_ctx->lock);
if (!seek) {
dp_fifo_push(rd_ctx->fifo, p);
uint32_t type = rd_ctx->event_types + DAV1D_EVENT_NEW_FRAME;
dp_rd_ctx_post_event(rd_ctx, type);
}
}
}
// Release remaining data
if (data.sz > 0)
dav1d_data_unref(&data);
// Do not drain in case an error occured and caused us to leave the
// decoding loop early.
if (res < 0)
goto cleanup;
// Drain decoder
// When there is no more data to feed to the decoder, for example
// because the file ended, we still need to request pictures, as
// even though we do not have more data, there can be frames decoded
// from data we sent before. So we need to call dav1d_get_picture until
// we get an EAGAIN error.
do {
if (dp_rd_ctx_should_terminate(rd_ctx))
break;
p = calloc(1, sizeof(*p));
res = dav1d_get_picture(c, p);
if (res < 0) {
free(p);
if (res != DAV1D_ERR(EAGAIN)) {
fprintf(stderr, "Error decoding frame: %s\n",
strerror(-res));
break;
}
} else {
// Queue frame
dp_fifo_push(rd_ctx->fifo, p);
uint32_t type = rd_ctx->event_types + DAV1D_EVENT_NEW_FRAME;
dp_rd_ctx_post_event(rd_ctx, type);
}
} while (res != DAV1D_ERR(EAGAIN));
cleanup:
dp_rd_ctx_post_event(rd_ctx, rd_ctx->event_types + DAV1D_EVENT_DEC_QUIT);
if (in_ctx)
input_close(in_ctx);
if (c)
dav1d_close(&c);
return (res != DAV1D_ERR(EAGAIN) && res < 0);
}
int main(int argc, char **argv)
{
SDL_Thread *decoder_thread;
// Check for version mismatch between library and tool
const char *version = dav1d_version();
if (strcmp(version, DAV1D_VERSION)) {
fprintf(stderr, "Version mismatch (library: %s, executable: %s)\n",
version, DAV1D_VERSION);
return 1;
}
// Create render context
Dav1dPlayRenderContext *rd_ctx = dp_rd_ctx_create(argc, argv);
if (rd_ctx == NULL) {
fprintf(stderr, "Failed creating render context\n");
return 5;
}
if (rd_ctx->settings.zerocopy) {
if (renderer_info->alloc_pic) {
rd_ctx->lib_settings.allocator = (Dav1dPicAllocator) {
.cookie = rd_ctx->rd_priv,
.alloc_picture_callback = renderer_info->alloc_pic,
.release_picture_callback = renderer_info->release_pic,
};
} else {
fprintf(stderr, "--zerocopy unsupported by selected renderer\n");
}
}
if (rd_ctx->settings.gpugrain) {
if (renderer_info->supports_gpu_grain) {
rd_ctx->lib_settings.apply_grain = 0;
} else {
fprintf(stderr, "--gpugrain unsupported by selected renderer\n");
}
}
// Start decoder thread
decoder_thread = SDL_CreateThread(decoder_thread_main, "Decoder thread", rd_ctx);
// Main loop
#define NUM_MAX_EVENTS 8
SDL_Event events[NUM_MAX_EVENTS];
int num_frame_events = 0;
uint32_t start_time = 0, n_out = 0;
while (1) {
int num_events = 0;
SDL_WaitEvent(NULL);
while (num_events < NUM_MAX_EVENTS && SDL_PollEvent(&events[num_events++]))
break;
for (int i = 0; i < num_events; ++i) {
SDL_Event *e = &events[i];
if (e->type == SDL_QUIT) {
dp_rd_ctx_request_shutdown(rd_ctx);
dp_fifo_flush(rd_ctx->fifo, destroy_pic);
goto out;
} else if (e->type == SDL_WINDOWEVENT) {
if (e->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
// TODO: Handle window resizes
} else if(e->window.event == SDL_WINDOWEVENT_EXPOSED) {
dp_rd_ctx_render(rd_ctx);
}
} else if (e->type == SDL_KEYDOWN) {
SDL_KeyboardEvent *kbde = (SDL_KeyboardEvent *)e;
if (kbde->keysym.sym == SDLK_SPACE) {
dp_rd_ctx_toggle_pause(rd_ctx);
} else if (kbde->keysym.sym == SDLK_ESCAPE) {
dp_rd_ctx_request_shutdown(rd_ctx);
dp_fifo_flush(rd_ctx->fifo, destroy_pic);
goto out;
} else if (kbde->keysym.sym == SDLK_LEFT ||
kbde->keysym.sym == SDLK_RIGHT)
{
if (kbde->keysym.sym == SDLK_LEFT)
dp_rd_ctx_seek(rd_ctx, -5);
else if (kbde->keysym.sym == SDLK_RIGHT)
dp_rd_ctx_seek(rd_ctx, +5);
dp_fifo_flush(rd_ctx->fifo, destroy_pic);
SDL_FlushEvent(rd_ctx->event_types + DAV1D_EVENT_NEW_FRAME);
num_frame_events = 0;
}
} else if (e->type == rd_ctx->event_types + DAV1D_EVENT_NEW_FRAME) {
num_frame_events++;
// Store current ticks for stats calculation
if (start_time == 0)
start_time = SDL_GetTicks();
} else if (e->type == rd_ctx->event_types + DAV1D_EVENT_SEEK_FRAME) {
// Dequeue frame and update the render context with it
Dav1dPicture *p = dp_fifo_shift(rd_ctx->fifo);
// Do not update textures during termination
if (!dp_rd_ctx_should_terminate(rd_ctx)) {
dp_rd_ctx_update_with_dav1d_picture(rd_ctx, p);
n_out++;
}
destroy_pic(p);
} else if (e->type == rd_ctx->event_types + DAV1D_EVENT_DEC_QUIT) {
goto out;
}
}
if (num_frame_events && !dp_rd_ctx_is_paused(rd_ctx)) {
// Dequeue frame and update the render context with it
Dav1dPicture *p = dp_fifo_shift(rd_ctx->fifo);
// Do not update textures during termination
if (!dp_rd_ctx_should_terminate(rd_ctx)) {
dp_rd_ctx_update_with_dav1d_picture(rd_ctx, p);
dp_rd_ctx_render(rd_ctx);
n_out++;
}
destroy_pic(p);
num_frame_events--;
}
}
out:;
// Print stats
uint32_t time_ms = SDL_GetTicks() - start_time - rd_ctx->pause_time;
printf("Decoded %u frames in %d seconds, avg %.02f fps\n",
n_out, time_ms / 1000, n_out/ (time_ms / 1000.0));
int decoder_ret = 0;
SDL_WaitThread(decoder_thread, &decoder_ret);
dp_rd_ctx_destroy(rd_ctx);
SDL_Quit();
return decoder_ret;
}

View file

@ -0,0 +1,147 @@
/*
* Copyright © 2019, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <SDL.h>
#include <assert.h>
#include "dp_fifo.h"
// FIFO structure
struct dp_fifo
{
SDL_mutex *lock;
SDL_cond *cond_change;
size_t capacity;
size_t count;
void **entries;
int push_wait;
int flush;
};
Dav1dPlayPtrFifo *dp_fifo_create(size_t capacity)
{
Dav1dPlayPtrFifo *fifo;
assert(capacity > 0);
if (capacity <= 0)
return NULL;
fifo = malloc(sizeof(*fifo));
if (fifo == NULL)
return NULL;
fifo->capacity = capacity;
fifo->count = 0;
fifo->push_wait = 0;
fifo->flush = 0;
fifo->lock = SDL_CreateMutex();
if (fifo->lock == NULL) {
free(fifo);
return NULL;
}
fifo->cond_change = SDL_CreateCond();
if (fifo->cond_change == NULL) {
SDL_DestroyMutex(fifo->lock);
free(fifo);
return NULL;
}
fifo->entries = calloc(capacity, sizeof(void*));
if (fifo->entries == NULL) {
dp_fifo_destroy(fifo);
return NULL;
}
return fifo;
}
// Destroy FIFO
void dp_fifo_destroy(Dav1dPlayPtrFifo *fifo)
{
assert(fifo->count == 0);
SDL_DestroyMutex(fifo->lock);
SDL_DestroyCond(fifo->cond_change);
free(fifo->entries);
free(fifo);
}
// Push to FIFO
void dp_fifo_push(Dav1dPlayPtrFifo *fifo, void *element)
{
SDL_LockMutex(fifo->lock);
while (fifo->count == fifo->capacity) {
fifo->push_wait = 1;
SDL_CondWait(fifo->cond_change, fifo->lock);
fifo->push_wait = 0;
if (fifo->flush) {
SDL_CondSignal(fifo->cond_change);
SDL_UnlockMutex(fifo->lock);
return;
}
}
fifo->entries[fifo->count++] = element;
if (fifo->count == 1)
SDL_CondSignal(fifo->cond_change);
SDL_UnlockMutex(fifo->lock);
}
// Helper that shifts the FIFO array
static void *dp_fifo_array_shift(void **arr, size_t len)
{
void *shifted_element = arr[0];
for (size_t i = 1; i < len; ++i)
arr[i-1] = arr[i];
return shifted_element;
}
// Get item from FIFO
void *dp_fifo_shift(Dav1dPlayPtrFifo *fifo)
{
SDL_LockMutex(fifo->lock);
while (fifo->count == 0)
SDL_CondWait(fifo->cond_change, fifo->lock);
void *res = dp_fifo_array_shift(fifo->entries, fifo->count--);
if (fifo->count == fifo->capacity - 1)
SDL_CondSignal(fifo->cond_change);
SDL_UnlockMutex(fifo->lock);
return res;
}
void dp_fifo_flush(Dav1dPlayPtrFifo *fifo, void (*destroy_elem)(void *))
{
SDL_LockMutex(fifo->lock);
fifo->flush = 1;
if (fifo->push_wait) {
SDL_CondSignal(fifo->cond_change);
SDL_CondWait(fifo->cond_change, fifo->lock);
}
while (fifo->count)
destroy_elem(fifo->entries[--fifo->count]);
fifo->flush = 0;
SDL_UnlockMutex(fifo->lock);
}

View file

@ -0,0 +1,63 @@
/*
* Copyright © 2019, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Dav1dPlay FIFO helper
*/
typedef struct dp_fifo Dav1dPlayPtrFifo;
/* Create a FIFO
*
* Creates a FIFO with the given capacity.
* If the capacity is reached, new inserts into the FIFO
* will block until enough space is available again.
*/
Dav1dPlayPtrFifo *dp_fifo_create(size_t capacity);
/* Destroy a FIFO
*
* The FIFO must be empty before it is destroyed!
*/
void dp_fifo_destroy(Dav1dPlayPtrFifo *fifo);
/* Shift FIFO
*
* Return the first item from the FIFO, thereby removing it from
* the FIFO and making room for new entries.
*/
void *dp_fifo_shift(Dav1dPlayPtrFifo *fifo);
/* Push to FIFO
*
* Add an item to the end of the FIFO.
* If the FIFO is full, this call will block until there is again enough
* space in the FIFO, so calling this from the "consumer" thread if no
* other thread will call dp_fifo_shift will lead to a deadlock.
*/
void dp_fifo_push(Dav1dPlayPtrFifo *fifo, void *element);
void dp_fifo_flush(Dav1dPlayPtrFifo *fifo, void (*destroy_elem)(void *));

View file

@ -0,0 +1,149 @@
/*
* Copyright © 2020, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <inttypes.h>
#include <string.h>
#include "dav1d/dav1d.h"
#include <SDL.h>
#if HAVE_PLACEBO
# include <libplacebo/config.h>
#endif
// Check libplacebo Vulkan rendering
#if HAVE_VULKAN && defined(SDL_VIDEO_VULKAN)
# if defined(PL_HAVE_VULKAN) && PL_HAVE_VULKAN
# define HAVE_RENDERER_PLACEBO 1
# define HAVE_PLACEBO_VULKAN 1
# endif
#endif
// Check libplacebo OpenGL rendering
#if defined(PL_HAVE_OPENGL) && PL_HAVE_OPENGL
# define HAVE_RENDERER_PLACEBO 1
# define HAVE_PLACEBO_OPENGL 1
#endif
#ifndef HAVE_RENDERER_PLACEBO
#define HAVE_RENDERER_PLACEBO 0
#endif
#ifndef HAVE_PLACEBO_VULKAN
#define HAVE_PLACEBO_VULKAN 0
#endif
#ifndef HAVE_PLACEBO_OPENGL
#define HAVE_PLACEBO_OPENGL 0
#endif
/**
* Settings structure
* Hold all settings available for the player,
* this is usually filled by parsing arguments
* from the console.
*/
typedef struct {
const char *inputfile;
const char *renderer_name;
int highquality;
int untimed;
int zerocopy;
int gpugrain;
int fullscreen;
} Dav1dPlaySettings;
#define WINDOW_WIDTH 910
#define WINDOW_HEIGHT 512
enum {
DAV1D_EVENT_NEW_FRAME,
DAV1D_EVENT_SEEK_FRAME,
DAV1D_EVENT_DEC_QUIT
};
/**
* Renderer info
*/
typedef struct rdr_info
{
// Renderer name
const char *name;
// Cookie passed to the renderer implementation callbacks
void *cookie;
// Callback to create the renderer
void* (*create_renderer)(const Dav1dPlaySettings *settings);
// Callback to destroy the renderer
void (*destroy_renderer)(void *cookie);
// Callback to the render function that renders a prevously sent frame
void (*render)(void *cookie, const Dav1dPlaySettings *settings);
// Callback to the send frame function, _may_ also unref dav1d_pic!
int (*update_frame)(void *cookie, Dav1dPicture *dav1d_pic,
const Dav1dPlaySettings *settings);
// Callback for alloc/release pictures (optional)
int (*alloc_pic)(Dav1dPicture *pic, void *cookie);
void (*release_pic)(Dav1dPicture *pic, void *cookie);
// Whether or not this renderer can apply on-GPU film grain synthesis
int supports_gpu_grain;
} Dav1dPlayRenderInfo;
extern const Dav1dPlayRenderInfo rdr_placebo_vk;
extern const Dav1dPlayRenderInfo rdr_placebo_gl;
extern const Dav1dPlayRenderInfo rdr_sdl;
// Available renderes ordered by priority
static const Dav1dPlayRenderInfo* const dp_renderers[] = {
&rdr_placebo_vk,
&rdr_placebo_gl,
&rdr_sdl,
};
static inline const Dav1dPlayRenderInfo *dp_get_renderer(const char *name)
{
for (size_t i = 0; i < (sizeof(dp_renderers)/sizeof(*dp_renderers)); ++i)
{
if (dp_renderers[i]->name == NULL)
continue;
if (name == NULL || strcmp(name, dp_renderers[i]->name) == 0) {
return dp_renderers[i];
}
}
return NULL;
}
static inline SDL_Window *dp_create_sdl_window(int window_flags)
{
SDL_Window *win;
window_flags |= SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI;
win = SDL_CreateWindow("Dav1dPlay", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
WINDOW_WIDTH, WINDOW_HEIGHT, window_flags);
if (!win)
return NULL;
SDL_SetWindowResizable(win, SDL_TRUE);
return win;
}

View file

@ -0,0 +1,437 @@
/*
* Copyright © 2020, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "dp_renderer.h"
#if HAVE_RENDERER_PLACEBO
#include <assert.h>
#include <libplacebo/renderer.h>
#include <libplacebo/utils/dav1d.h>
#if HAVE_PLACEBO_VULKAN
# include <libplacebo/vulkan.h>
# include <SDL_vulkan.h>
#endif
#if HAVE_PLACEBO_OPENGL
# include <libplacebo/opengl.h>
# include <SDL_opengl.h>
#endif
/**
* Renderer context for libplacebo
*/
typedef struct renderer_priv_ctx
{
// SDL window
SDL_Window *win;
// Placebo log
pl_log log;
// Placebo renderer
pl_renderer renderer;
#if HAVE_PLACEBO_VULKAN
// Placebo Vulkan handle
pl_vulkan vk;
// Placebo Vulkan instance
pl_vk_inst vk_inst;
// Vulkan surface
VkSurfaceKHR surf;
#endif
#if HAVE_PLACEBO_OPENGL
// Placebo OpenGL handle
pl_opengl gl;
// SDL OpenGL context
SDL_GLContext gl_context;
#endif
// Placebo GPU
pl_gpu gpu;
// Placebo swapchain
pl_swapchain swapchain;
// Lock protecting access to the texture
SDL_mutex *lock;
// Image to render, and planes backing them
struct pl_frame image;
pl_tex plane_tex[3];
} Dav1dPlayRendererPrivateContext;
static Dav1dPlayRendererPrivateContext*
placebo_renderer_create_common(const Dav1dPlaySettings *settings, int window_flags)
{
if (settings->fullscreen)
window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
// Create Window
SDL_Window *sdlwin = dp_create_sdl_window(window_flags | SDL_WINDOW_RESIZABLE);
if (sdlwin == NULL) {
fprintf(stderr, "Creating SDL window failed: %s\n", SDL_GetError());
return NULL;
}
SDL_ShowCursor(0);
// Alloc
Dav1dPlayRendererPrivateContext *const rd_priv_ctx =
calloc(1, sizeof(Dav1dPlayRendererPrivateContext));
if (rd_priv_ctx == NULL) {
fprintf(stderr, "Out of memory!\n");
return NULL;
}
rd_priv_ctx->win = sdlwin;
// Init libplacebo
rd_priv_ctx->log = pl_log_create(PL_API_VER, pl_log_params(
.log_cb = pl_log_color,
#ifndef NDEBUG
.log_level = PL_LOG_DEBUG,
#else
.log_level = PL_LOG_WARN,
#endif
));
if (rd_priv_ctx->log == NULL) {
fprintf(stderr, "pl_log_create failed!\n");
free(rd_priv_ctx);
return NULL;
}
// Create Mutex
rd_priv_ctx->lock = SDL_CreateMutex();
if (rd_priv_ctx->lock == NULL) {
fprintf(stderr, "SDL_CreateMutex failed: %s\n", SDL_GetError());
pl_log_destroy(&rd_priv_ctx->log);
free(rd_priv_ctx);
return NULL;
}
return rd_priv_ctx;
}
#if HAVE_PLACEBO_OPENGL
static void *placebo_renderer_create_gl(const Dav1dPlaySettings *settings)
{
SDL_Window *sdlwin = NULL;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
// Common init
Dav1dPlayRendererPrivateContext *rd_priv_ctx =
placebo_renderer_create_common(settings, SDL_WINDOW_OPENGL);
if (rd_priv_ctx == NULL)
return NULL;
sdlwin = rd_priv_ctx->win;
rd_priv_ctx->gl_context = SDL_GL_CreateContext(sdlwin);
if (!rd_priv_ctx->gl_context) {
fprintf(stderr, "Failed creating opengl context: %s\n", SDL_GetError());
exit(2);
}
SDL_GL_MakeCurrent(sdlwin, rd_priv_ctx->gl_context);
rd_priv_ctx->gl = pl_opengl_create(rd_priv_ctx->log, pl_opengl_params(
.allow_software = true,
#ifndef NDEBUG
.debug = true,
#endif
));
if (!rd_priv_ctx->gl) {
fprintf(stderr, "Failed creating opengl device!\n");
exit(2);
}
rd_priv_ctx->swapchain = pl_opengl_create_swapchain(rd_priv_ctx->gl,
pl_opengl_swapchain_params(
.swap_buffers = (void (*)(void *)) SDL_GL_SwapWindow,
.priv = sdlwin,
));
if (!rd_priv_ctx->swapchain) {
fprintf(stderr, "Failed creating opengl swapchain!\n");
exit(2);
}
int w = WINDOW_WIDTH, h = WINDOW_HEIGHT;
SDL_GL_GetDrawableSize(sdlwin, &w, &h);
if (!pl_swapchain_resize(rd_priv_ctx->swapchain, &w, &h)) {
fprintf(stderr, "Failed resizing vulkan swapchain!\n");
exit(2);
}
rd_priv_ctx->gpu = rd_priv_ctx->gl->gpu;
if (w != WINDOW_WIDTH || h != WINDOW_HEIGHT)
printf("Note: window dimensions differ (got %dx%d)\n", w, h);
return rd_priv_ctx;
}
#endif
#if HAVE_PLACEBO_VULKAN
static void *placebo_renderer_create_vk(const Dav1dPlaySettings *settings)
{
SDL_Window *sdlwin = NULL;
// Common init
Dav1dPlayRendererPrivateContext *rd_priv_ctx =
placebo_renderer_create_common(settings, SDL_WINDOW_VULKAN);
if (rd_priv_ctx == NULL)
return NULL;
sdlwin = rd_priv_ctx->win;
// Init Vulkan
unsigned num = 0;
if (!SDL_Vulkan_GetInstanceExtensions(sdlwin, &num, NULL)) {
fprintf(stderr, "Failed enumerating Vulkan extensions: %s\n", SDL_GetError());
exit(1);
}
const char **extensions = malloc(num * sizeof(const char *));
assert(extensions);
SDL_bool ok = SDL_Vulkan_GetInstanceExtensions(sdlwin, &num, extensions);
if (!ok) {
fprintf(stderr, "Failed getting Vk instance extensions\n");
exit(1);
}
if (num > 0) {
printf("Requesting %d additional Vulkan extensions:\n", num);
for (unsigned i = 0; i < num; i++)
printf(" %s\n", extensions[i]);
}
rd_priv_ctx->vk_inst = pl_vk_inst_create(rd_priv_ctx->log, pl_vk_inst_params(
.extensions = extensions,
.num_extensions = num,
));
if (!rd_priv_ctx->vk_inst) {
fprintf(stderr, "Failed creating Vulkan instance!\n");
exit(1);
}
free(extensions);
if (!SDL_Vulkan_CreateSurface(sdlwin, rd_priv_ctx->vk_inst->instance, &rd_priv_ctx->surf)) {
fprintf(stderr, "Failed creating vulkan surface: %s\n", SDL_GetError());
exit(1);
}
rd_priv_ctx->vk = pl_vulkan_create(rd_priv_ctx->log, pl_vulkan_params(
.instance = rd_priv_ctx->vk_inst->instance,
.surface = rd_priv_ctx->surf,
.allow_software = true,
));
if (!rd_priv_ctx->vk) {
fprintf(stderr, "Failed creating vulkan device!\n");
exit(2);
}
// Create swapchain
rd_priv_ctx->swapchain = pl_vulkan_create_swapchain(rd_priv_ctx->vk,
pl_vulkan_swapchain_params(
.surface = rd_priv_ctx->surf,
.present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR,
));
if (!rd_priv_ctx->swapchain) {
fprintf(stderr, "Failed creating vulkan swapchain!\n");
exit(2);
}
int w = WINDOW_WIDTH, h = WINDOW_HEIGHT;
if (!pl_swapchain_resize(rd_priv_ctx->swapchain, &w, &h)) {
fprintf(stderr, "Failed resizing vulkan swapchain!\n");
exit(2);
}
rd_priv_ctx->gpu = rd_priv_ctx->vk->gpu;
if (w != WINDOW_WIDTH || h != WINDOW_HEIGHT)
printf("Note: window dimensions differ (got %dx%d)\n", w, h);
return rd_priv_ctx;
}
#endif
static void placebo_renderer_destroy(void *cookie)
{
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
assert(rd_priv_ctx != NULL);
pl_renderer_destroy(&(rd_priv_ctx->renderer));
pl_swapchain_destroy(&(rd_priv_ctx->swapchain));
for (int i = 0; i < 3; i++)
pl_tex_destroy(rd_priv_ctx->gpu, &(rd_priv_ctx->plane_tex[i]));
#if HAVE_PLACEBO_VULKAN
if (rd_priv_ctx->vk) {
pl_vulkan_destroy(&(rd_priv_ctx->vk));
vkDestroySurfaceKHR(rd_priv_ctx->vk_inst->instance, rd_priv_ctx->surf, NULL);
pl_vk_inst_destroy(&(rd_priv_ctx->vk_inst));
}
#endif
#if HAVE_PLACEBO_OPENGL
if (rd_priv_ctx->gl)
pl_opengl_destroy(&(rd_priv_ctx->gl));
if (rd_priv_ctx->gl_context)
SDL_GL_DeleteContext(rd_priv_ctx->gl_context);
#endif
SDL_DestroyWindow(rd_priv_ctx->win);
pl_log_destroy(&rd_priv_ctx->log);
}
static void placebo_render(void *cookie, const Dav1dPlaySettings *settings)
{
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
assert(rd_priv_ctx != NULL);
SDL_LockMutex(rd_priv_ctx->lock);
if (!rd_priv_ctx->image.num_planes) {
SDL_UnlockMutex(rd_priv_ctx->lock);
return;
}
// Prepare rendering
if (rd_priv_ctx->renderer == NULL) {
rd_priv_ctx->renderer = pl_renderer_create(rd_priv_ctx->log, rd_priv_ctx->gpu);
}
struct pl_swapchain_frame frame;
bool ok = pl_swapchain_start_frame(rd_priv_ctx->swapchain, &frame);
if (!ok) {
SDL_UnlockMutex(rd_priv_ctx->lock);
return;
}
struct pl_frame target;
pl_frame_from_swapchain(&target, &frame);
pl_rect2df_aspect_copy(&target.crop, &rd_priv_ctx->image.crop, 0.0);
if (pl_frame_is_cropped(&target))
pl_tex_clear(rd_priv_ctx->gpu, frame.fbo, (float[4]){ 0.0 });
if (!pl_render_image(rd_priv_ctx->renderer, &rd_priv_ctx->image, &target,
settings->highquality ? &pl_render_default_params
: &pl_render_fast_params))
{
fprintf(stderr, "Failed rendering frame!\n");
pl_tex_clear(rd_priv_ctx->gpu, frame.fbo, (float[4]){ 1.0 });
}
ok = pl_swapchain_submit_frame(rd_priv_ctx->swapchain);
if (!ok) {
fprintf(stderr, "Failed submitting frame!\n");
SDL_UnlockMutex(rd_priv_ctx->lock);
return;
}
pl_swapchain_swap_buffers(rd_priv_ctx->swapchain);
SDL_UnlockMutex(rd_priv_ctx->lock);
}
static int placebo_upload_image(void *cookie, Dav1dPicture *dav1d_pic,
const Dav1dPlaySettings *settings)
{
Dav1dPlayRendererPrivateContext *p = cookie;
assert(p != NULL);
int ret = 0;
if (!dav1d_pic)
return ret;
SDL_LockMutex(p->lock);
if (!pl_upload_dav1dpicture(p->gpu, &p->image, p->plane_tex, pl_dav1d_upload_params(
.picture = dav1d_pic,
.film_grain = settings->gpugrain,
.gpu_allocated = settings->zerocopy,
.asynchronous = true,
)))
{
fprintf(stderr, "Failed uploading planes!\n");
p->image = (struct pl_frame) {0};
ret = -1;
}
SDL_UnlockMutex(p->lock);
return ret;
}
static int placebo_alloc_pic(Dav1dPicture *const pic, void *cookie)
{
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
assert(rd_priv_ctx != NULL);
SDL_LockMutex(rd_priv_ctx->lock);
int ret = pl_allocate_dav1dpicture(pic, (void *) rd_priv_ctx->gpu);
SDL_UnlockMutex(rd_priv_ctx->lock);
return ret;
}
static void placebo_release_pic(Dav1dPicture *pic, void *cookie)
{
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
assert(rd_priv_ctx != NULL);
SDL_LockMutex(rd_priv_ctx->lock);
pl_release_dav1dpicture(pic, (void *) rd_priv_ctx->gpu);
SDL_UnlockMutex(rd_priv_ctx->lock);
}
#if HAVE_PLACEBO_VULKAN
const Dav1dPlayRenderInfo rdr_placebo_vk = {
.name = "placebo-vk",
.create_renderer = placebo_renderer_create_vk,
.destroy_renderer = placebo_renderer_destroy,
.render = placebo_render,
.update_frame = placebo_upload_image,
.alloc_pic = placebo_alloc_pic,
.release_pic = placebo_release_pic,
.supports_gpu_grain = 1,
};
#else
const Dav1dPlayRenderInfo rdr_placebo_vk = { NULL };
#endif
#if HAVE_PLACEBO_OPENGL
const Dav1dPlayRenderInfo rdr_placebo_gl = {
.name = "placebo-gl",
.create_renderer = placebo_renderer_create_gl,
.destroy_renderer = placebo_renderer_destroy,
.render = placebo_render,
.update_frame = placebo_upload_image,
.supports_gpu_grain = 1,
};
#else
const Dav1dPlayRenderInfo rdr_placebo_gl = { NULL };
#endif
#else
const Dav1dPlayRenderInfo rdr_placebo_vk = { NULL };
const Dav1dPlayRenderInfo rdr_placebo_gl = { NULL };
#endif

View file

@ -0,0 +1,175 @@
/*
* Copyright © 2020, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "dp_renderer.h"
#include <assert.h>
/**
* Renderer context for SDL
*/
typedef struct renderer_priv_ctx
{
// SDL window
SDL_Window *win;
// SDL renderer
SDL_Renderer *renderer;
// Lock protecting access to the texture
SDL_mutex *lock;
// Texture to render
SDL_Texture *tex;
} Dav1dPlayRendererPrivateContext;
static void *sdl_renderer_create(const Dav1dPlaySettings *settings)
{
int window_flags = 0;
if (settings->fullscreen)
window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
SDL_Window *win = dp_create_sdl_window(window_flags);
if (win == NULL) {
fprintf(stderr, "Creating SDL window failed: %s\n", SDL_GetError());
return NULL;
}
SDL_ShowCursor(0);
// Alloc
Dav1dPlayRendererPrivateContext *rd_priv_ctx = malloc(sizeof(Dav1dPlayRendererPrivateContext));
if (rd_priv_ctx == NULL) {
fprintf(stderr, "Out of memory!\n");
return NULL;
}
rd_priv_ctx->win = win;
// Create renderer
rd_priv_ctx->renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
// Set scale quality
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
// Create Mutex
rd_priv_ctx->lock = SDL_CreateMutex();
if (rd_priv_ctx->lock == NULL) {
fprintf(stderr, "SDL_CreateMutex failed: %s\n", SDL_GetError());
free(rd_priv_ctx);
return NULL;
}
rd_priv_ctx->tex = NULL;
return rd_priv_ctx;
}
static void sdl_renderer_destroy(void *cookie)
{
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
assert(rd_priv_ctx != NULL);
SDL_DestroyTexture(rd_priv_ctx->tex);
SDL_DestroyRenderer(rd_priv_ctx->renderer);
SDL_DestroyWindow(rd_priv_ctx->win);
SDL_DestroyMutex(rd_priv_ctx->lock);
free(rd_priv_ctx);
}
static void sdl_render(void *cookie, const Dav1dPlaySettings *settings)
{
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
assert(rd_priv_ctx != NULL);
SDL_LockMutex(rd_priv_ctx->lock);
if (rd_priv_ctx->tex == NULL) {
SDL_UnlockMutex(rd_priv_ctx->lock);
return;
}
// Display the frame
SDL_RenderClear(rd_priv_ctx->renderer);
SDL_RenderCopy(rd_priv_ctx->renderer, rd_priv_ctx->tex, NULL, NULL);
SDL_RenderPresent(rd_priv_ctx->renderer);
SDL_UnlockMutex(rd_priv_ctx->lock);
}
static int sdl_update_texture(void *cookie, Dav1dPicture *dav1d_pic,
const Dav1dPlaySettings *settings)
{
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
assert(rd_priv_ctx != NULL);
SDL_LockMutex(rd_priv_ctx->lock);
if (dav1d_pic == NULL) {
rd_priv_ctx->tex = NULL;
SDL_UnlockMutex(rd_priv_ctx->lock);
return 0;
}
int width = dav1d_pic->p.w;
int height = dav1d_pic->p.h;
int tex_w = width;
int tex_h = height;
enum Dav1dPixelLayout dav1d_layout = dav1d_pic->p.layout;
if (DAV1D_PIXEL_LAYOUT_I420 != dav1d_layout || dav1d_pic->p.bpc != 8) {
fprintf(stderr, "Unsupported pixel format, only 8bit 420 supported so far.\n");
exit(50);
}
SDL_Texture *texture = rd_priv_ctx->tex;
if (texture != NULL) {
SDL_QueryTexture(texture, NULL, NULL, &tex_w, &tex_h);
if (tex_w != width || tex_h != height) {
SDL_DestroyTexture(texture);
texture = NULL;
}
}
if (texture == NULL) {
texture = SDL_CreateTexture(rd_priv_ctx->renderer, SDL_PIXELFORMAT_IYUV,
SDL_TEXTUREACCESS_STREAMING, width, height);
SDL_RenderSetLogicalSize(rd_priv_ctx->renderer, width, height);
}
SDL_UpdateYUVTexture(texture, NULL,
dav1d_pic->data[0], (int)dav1d_pic->stride[0], // Y
dav1d_pic->data[1], (int)dav1d_pic->stride[1], // U
dav1d_pic->data[2], (int)dav1d_pic->stride[1] // V
);
rd_priv_ctx->tex = texture;
SDL_UnlockMutex(rd_priv_ctx->lock);
return 0;
}
const Dav1dPlayRenderInfo rdr_sdl = {
.name = "sdl",
.create_renderer = sdl_renderer_create,
.destroy_renderer = sdl_renderer_destroy,
.render = sdl_render,
.update_frame = sdl_update_texture
};

View file

@ -0,0 +1,78 @@
# Copyright © 2018, VideoLAN and dav1d authors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Build definition for the dav1d examples
#
# Leave subdir if examples are disabled
if not get_option('enable_examples')
subdir_done()
endif
# dav1d player sources
dav1dplay_sources = files(
'dav1dplay.c',
'dp_fifo.c',
'dp_renderer_placebo.c',
'dp_renderer_sdl.c',
)
sdl2_dependency = dependency('sdl2', version: '>= 2.0.1', required: true)
if sdl2_dependency.found()
dav1dplay_deps = [sdl2_dependency, libm_dependency]
dav1dplay_cflags = []
placebo_dependency = dependency('libplacebo', version: '>= 4.160.0', required: false)
have_vulkan = false
have_placebo = placebo_dependency.found()
if have_placebo
dav1dplay_deps += placebo_dependency
# If libplacebo is found, we might be able to use Vulkan
# with it, in which case we need the Vulkan library too.
vulkan_dependency = dependency('vulkan', required: false)
if vulkan_dependency.found()
dav1dplay_deps += vulkan_dependency
have_vulkan = true
endif
endif
dav1dplay_cflags += '-DHAVE_PLACEBO=' + (have_placebo ? '1' : '0')
dav1dplay_cflags += '-DHAVE_VULKAN=' + (have_vulkan ? '1' : '0')
dav1dplay = executable('dav1dplay',
dav1dplay_sources,
rev_target,
link_with : [libdav1d, dav1d_input_objs],
include_directories : [dav1d_inc_dirs],
dependencies : [getopt_dependency, dav1dplay_deps],
install : true,
c_args : dav1dplay_cflags,
)
endif

View file

@ -0,0 +1,4 @@
exclude = .*/tests/.*
exclude = .*/tools/.*
exclude = .*/include/common/dump.h
gcov-ignore-parse-errors = negative_hits.warn

View file

@ -0,0 +1,213 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DAV1D_COMMON_ATTRIBUTES_H
#define DAV1D_COMMON_ATTRIBUTES_H
#include "config.h"
#include <stddef.h>
#include <assert.h>
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
#ifndef __has_feature
#define __has_feature(x) 0
#endif
#ifdef __GNUC__
#define ATTR_ALIAS __attribute__((may_alias))
#if defined(__MINGW32__) && !defined(__clang__)
#define ATTR_FORMAT_PRINTF(fmt, attr) __attribute__((__format__(__gnu_printf__, fmt, attr)))
#else
#define ATTR_FORMAT_PRINTF(fmt, attr) __attribute__((__format__(__printf__, fmt, attr)))
#endif
#define COLD __attribute__((cold))
#else
#define ATTR_ALIAS
#define ATTR_FORMAT_PRINTF(fmt, attr)
#define COLD
#endif
#if ARCH_X86_64
/* x86-64 needs 32- and 64-byte alignment for AVX2 and AVX-512. */
#define ALIGN_64_VAL 64
#define ALIGN_32_VAL 32
#define ALIGN_16_VAL 16
#elif ARCH_AARCH64 || ARCH_ARM || ARCH_LOONGARCH || ARCH_PPC64LE || ARCH_X86_32
/* ARM doesn't benefit from anything more than 16-byte alignment. */
#define ALIGN_64_VAL 16
#define ALIGN_32_VAL 16
#define ALIGN_16_VAL 16
#else
/* No need for extra alignment on platforms without assembly. */
#define ALIGN_64_VAL 8
#define ALIGN_32_VAL 8
#define ALIGN_16_VAL 8
#endif
/*
* API for variables, struct members (ALIGN()) like:
* uint8_t var[1][2][3][4]
* becomes:
* ALIGN(uint8_t var[1][2][3][4], alignment).
*/
#ifdef _MSC_VER
#define ALIGN(ll, a) \
__declspec(align(a)) ll
#else
#define ALIGN(line, align) \
line __attribute__((aligned(align)))
#endif
/*
* API for stack alignment (ALIGN_STK_$align()) of variables like:
* uint8_t var[1][2][3][4]
* becomes:
* ALIGN_STK_$align(uint8_t, var, 1, [2][3][4])
*/
#define ALIGN_STK_64(type, var, sz1d, sznd) \
ALIGN(type var[sz1d]sznd, ALIGN_64_VAL)
#define ALIGN_STK_32(type, var, sz1d, sznd) \
ALIGN(type var[sz1d]sznd, ALIGN_32_VAL)
#define ALIGN_STK_16(type, var, sz1d, sznd) \
ALIGN(type var[sz1d]sznd, ALIGN_16_VAL)
/*
* Forbid inlining of a function:
* static NOINLINE void func() {}
*/
#ifdef _MSC_VER
#define NOINLINE __declspec(noinline)
#elif __has_attribute(noclone)
#define NOINLINE __attribute__((noinline, noclone))
#else
#define NOINLINE __attribute__((noinline))
#endif
#ifdef _MSC_VER
#define ALWAYS_INLINE __forceinline
#else
#define ALWAYS_INLINE __attribute__((always_inline)) inline
#endif
#if (defined(__ELF__) || defined(__MACH__) || (defined(_WIN32) && defined(__clang__))) && __has_attribute(visibility)
#define EXTERN extern __attribute__((visibility("hidden")))
#else
#define EXTERN extern
#endif
#if ARCH_X86_64 && __has_attribute(model)
#define ATTR_MCMODEL_SMALL __attribute__((model("small")))
#else
#define ATTR_MCMODEL_SMALL
#endif
#ifdef __clang__
#define NO_SANITIZE(x) __attribute__((no_sanitize(x)))
#else
#define NO_SANITIZE(x)
#endif
#if defined(NDEBUG) && (defined(__GNUC__) || defined(__clang__))
#undef assert
#define assert(x) do { if (!(x)) __builtin_unreachable(); } while (0)
#elif defined(NDEBUG) && defined(_MSC_VER)
#undef assert
#define assert __assume
#endif
#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)
# define dav1d_uninit(x) x=x
#else
# define dav1d_uninit(x) x
#endif
#if defined(_MSC_VER) && !defined(__clang__)
#include <intrin.h>
static inline int ctz(const unsigned int mask) {
unsigned long idx;
_BitScanForward(&idx, mask);
return idx;
}
static inline int clz(const unsigned int mask) {
unsigned long leading_zero = 0;
_BitScanReverse(&leading_zero, mask);
return (31 - leading_zero);
}
#ifdef _WIN64
static inline int clzll(const unsigned long long mask) {
unsigned long leading_zero = 0;
_BitScanReverse64(&leading_zero, mask);
return (63 - leading_zero);
}
#else /* _WIN64 */
static inline int clzll(const unsigned long long mask) {
if (mask >> 32)
return clz((unsigned)(mask >> 32));
else
return clz((unsigned)mask) + 32;
}
#endif /* _WIN64 */
#else /* !_MSC_VER */
static inline int ctz(const unsigned int mask) {
return __builtin_ctz(mask);
}
static inline int clz(const unsigned int mask) {
return __builtin_clz(mask);
}
static inline int clzll(const unsigned long long mask) {
return __builtin_clzll(mask);
}
#endif /* !_MSC_VER */
#ifndef static_assert
#define CHECK_OFFSET(type, field, name) \
struct check_##type##_##field { int x[(name == offsetof(type, field)) ? 1 : -1]; }
#define CHECK_SIZE(type, size) \
struct check_##type##_size { int x[(size == sizeof(type)) ? 1 : -1]; }
#else
#define CHECK_OFFSET(type, field, name) \
static_assert(name == offsetof(type, field), #field)
#define CHECK_SIZE(type, size) \
static_assert(size == sizeof(type), #type)
#endif
#ifdef _MSC_VER
#define PACKED(...) __pragma(pack(push, 1)) __VA_ARGS__ __pragma(pack(pop))
#else
#define PACKED(...) __VA_ARGS__ __attribute__((__packed__))
#endif
#endif /* DAV1D_COMMON_ATTRIBUTES_H */

View file

@ -0,0 +1,93 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DAV1D_COMMON_BITDEPTH_H
#define DAV1D_COMMON_BITDEPTH_H
#include <stdint.h>
#include <string.h>
#include "common/attributes.h"
#if !defined(BITDEPTH)
typedef uint8_t pixel; /* can't be void due to pointer-to-array usage */
typedef void coef;
#define HIGHBD_DECL_SUFFIX /* nothing */
#define HIGHBD_CALL_SUFFIX /* nothing */
#define HIGHBD_TAIL_SUFFIX /* nothing */
#elif BITDEPTH == 8
typedef uint8_t pixel;
typedef int16_t coef;
#define PIXEL_TYPE uint8_t
#define COEF_TYPE int16_t
#define pixel_copy memcpy
#define pixel_set memset
#define iclip_pixel iclip_u8
#define PIX_HEX_FMT "%02x"
#define bitfn(x) x##_8bpc
#define BF(x, suffix) x##_8bpc_##suffix
#define PXSTRIDE(x) (x)
#define highbd_only(x)
#define HIGHBD_DECL_SUFFIX /* nothing */
#define HIGHBD_CALL_SUFFIX /* nothing */
#define HIGHBD_TAIL_SUFFIX /* nothing */
#define bitdepth_from_max(x) 8
#define BITDEPTH_MAX 0xff
#elif BITDEPTH == 16
typedef uint16_t pixel;
typedef int32_t coef;
#define PIXEL_TYPE uint16_t
#define COEF_TYPE int32_t
#define pixel_copy(a, b, c) memcpy(a, b, (c) << 1)
static inline void pixel_set(pixel *const dst, const int val, const int num) {
for (int n = 0; n < num; n++)
dst[n] = val;
}
#define PIX_HEX_FMT "%03x"
#define iclip_pixel(x) iclip(x, 0, bitdepth_max)
#define HIGHBD_DECL_SUFFIX , const int bitdepth_max
#define HIGHBD_CALL_SUFFIX , f->bitdepth_max
#define HIGHBD_TAIL_SUFFIX , bitdepth_max
#define bitdepth_from_max(bitdepth_max) (32 - clz(bitdepth_max))
#define BITDEPTH_MAX bitdepth_max
#define bitfn(x) x##_16bpc
#define BF(x, suffix) x##_16bpc_##suffix
static inline ptrdiff_t PXSTRIDE(const ptrdiff_t x) {
assert(!(x & 1));
return x >> 1;
}
#define highbd_only(x) x
#else
#error invalid value for bitdepth
#endif
#define bytefn(x) bitfn(x)
#define bitfn_decls(name, ...) \
name##_8bpc(__VA_ARGS__); \
name##_16bpc(__VA_ARGS__)
#endif /* DAV1D_COMMON_BITDEPTH_H */

View file

@ -0,0 +1,92 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DAV1D_COMMON_DUMP_H
#define DAV1D_COMMON_DUMP_H
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include "common/bitdepth.h"
static inline void append_plane_to_file(const pixel *buf, ptrdiff_t stride,
int w, int h, const char *const file)
{
FILE *const f = fopen(file, "ab");
while (h--) {
fwrite(buf, w * sizeof(pixel), 1, f);
buf += PXSTRIDE(stride);
}
fclose(f);
}
static inline void hex_fdump(FILE *out, const pixel *buf, ptrdiff_t stride,
int w, int h, const char *what)
{
fprintf(out, "%s\n", what);
while (h--) {
int x;
for (x = 0; x < w; x++)
fprintf(out, " " PIX_HEX_FMT, buf[x]);
buf += PXSTRIDE(stride);
fprintf(out, "\n");
}
}
static inline void hex_dump(const pixel *buf, ptrdiff_t stride,
int w, int h, const char *what)
{
hex_fdump(stdout, buf, stride, w, h, what);
}
static inline void coef_dump(const coef *buf, const int w, const int h,
const int len, const char *what)
{
int y;
printf("%s\n", what);
for (y = 0; y < h; y++) {
int x;
for (x = 0; x < w; x++)
printf(" %*d", len, buf[x]);
buf += w;
printf("\n");
}
}
static inline void ac_dump(const int16_t *buf, int w, int h, const char *what)
{
printf("%s\n", what);
while (h--) {
for (int x = 0; x < w; x++)
printf(" %03d", buf[x]);
buf += w;
printf("\n");
}
}
#endif /* DAV1D_COMMON_DUMP_H */

View file

@ -0,0 +1,45 @@
/*
* Copyright © 2021, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DAV1D_COMMON_FRAME_H
#define DAV1D_COMMON_FRAME_H
/*
* Checks whether Dav1dFrameType == INTER || == SWITCH
* Both are defined as odd numbers {1, 3} and therefore have the LSB set.
* See also: AV1 spec 6.8.2
*/
#define IS_INTER_OR_SWITCH(frame_header) \
((frame_header)->frame_type & 1)
/*
* Checks whether Dav1dFrameType == KEY || == INTRA
* See also: AV1 spec 6.8.2
*/
#define IS_KEY_OR_INTRA(frame_header) \
(!IS_INTER_OR_SWITCH(frame_header))
#endif /* DAV1D_COMMON_FRAME_H */

View file

@ -0,0 +1,84 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DAV1D_COMMON_INTOPS_H
#define DAV1D_COMMON_INTOPS_H
#include <stdint.h>
#include "common/attributes.h"
static inline int imax(const int a, const int b) {
return a > b ? a : b;
}
static inline int imin(const int a, const int b) {
return a < b ? a : b;
}
static inline unsigned umax(const unsigned a, const unsigned b) {
return a > b ? a : b;
}
static inline unsigned umin(const unsigned a, const unsigned b) {
return a < b ? a : b;
}
static inline int iclip(const int v, const int min, const int max) {
return v < min ? min : v > max ? max : v;
}
static inline int iclip_u8(const int v) {
return iclip(v, 0, 255);
}
static inline int apply_sign(const int v, const int s) {
return s < 0 ? -v : v;
}
static inline int apply_sign64(const int v, const int64_t s) {
return s < 0 ? -v : v;
}
static inline int ulog2(const unsigned v) {
return 31 ^ clz(v);
}
static inline int u64log2(const uint64_t v) {
return 63 ^ clzll(v);
}
static inline unsigned inv_recenter(const unsigned r, const unsigned v) {
if (v > (r << 1))
return v;
else if ((v & 1) == 0)
return (v >> 1) + r;
else
return r - ((v + 1) >> 1);
}
#endif /* DAV1D_COMMON_INTOPS_H */

View file

@ -0,0 +1,61 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DAV1D_COMMON_VALIDATE_H
#define DAV1D_COMMON_VALIDATE_H
#include <stdio.h>
#include <stdlib.h>
#if defined(NDEBUG)
#define debug_print(...) do {} while (0)
#define debug_abort() do {} while (0)
#else
#define debug_print(...) fprintf(stderr, __VA_ARGS__)
#define debug_abort abort
#endif
#define validate_input_or_ret_with_msg(x, r, ...) \
if (!(x)) { \
debug_print("Input validation check \'%s\' failed in %s!\n", \
#x, __func__); \
debug_print(__VA_ARGS__); \
debug_abort(); \
return r; \
}
#define validate_input_or_ret(x, r) \
if (!(x)) { \
debug_print("Input validation check \'%s\' failed in %s!\n", \
#x, __func__); \
debug_abort(); \
return r; \
}
#define validate_input(x) validate_input_or_ret(x, )
#endif /* DAV1D_COMMON_VALIDATE_H */

View file

@ -0,0 +1,51 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GCCVER_STDATOMIC_H_
#define GCCVER_STDATOMIC_H_
#if !defined(__cplusplus)
typedef int atomic_int;
typedef unsigned int atomic_uint;
#define memory_order_relaxed __ATOMIC_RELAXED
#define memory_order_acquire __ATOMIC_ACQUIRE
#define atomic_init(p_a, v) do { *(p_a) = (v); } while(0)
#define atomic_store(p_a, v) __atomic_store_n(p_a, v, __ATOMIC_SEQ_CST)
#define atomic_load(p_a) __atomic_load_n(p_a, __ATOMIC_SEQ_CST)
#define atomic_load_explicit(p_a, mo) __atomic_load_n(p_a, mo)
#define atomic_fetch_add(p_a, inc) __atomic_fetch_add(p_a, inc, __ATOMIC_SEQ_CST)
#define atomic_fetch_add_explicit(p_a, inc, mo) __atomic_fetch_add(p_a, inc, mo)
#define atomic_fetch_sub(p_a, dec) __atomic_fetch_sub(p_a, dec, __ATOMIC_SEQ_CST)
#define atomic_exchange(p_a, v) __atomic_exchange_n(p_a, v, __ATOMIC_SEQ_CST)
#define atomic_fetch_or(p_a, v) __atomic_fetch_or(p_a, v, __ATOMIC_SEQ_CST)
#define atomic_compare_exchange_strong(p_a, expected, desired) __atomic_compare_exchange_n(p_a, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
#endif /* !defined(__cplusplus) */
#endif /* GCCVER_STDATOMIC_H_ */

View file

@ -0,0 +1,97 @@
#ifndef __GETOPT_H__
/**
* DISCLAIMER
* This file has no copyright assigned and is placed in the Public Domain.
* This file is part of the mingw-w64 runtime package.
*
* The mingw-w64 runtime package and its code is distributed in the hope that it
* will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR
* IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to
* warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#define __GETOPT_H__
/* All the headers include this file. */
#ifdef _WIN32
#include <crtdefs.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
extern int optind; /* index of first non-option in argv */
extern int optopt; /* single option character, as parsed */
extern int opterr; /* flag to enable built-in diagnostics... */
/* (user may set to zero, to suppress) */
extern char *optarg; /* pointer to argument of current option */
extern int getopt(int nargc, char * const *nargv, const char *options);
#ifdef _BSD_SOURCE
/*
* BSD adds the non-standard `optreset' feature, for reinitialisation
* of `getopt' parsing. We support this feature, for applications which
* proclaim their BSD heritage, before including this header; however,
* to maintain portability, developers are advised to avoid it.
*/
# define optreset __mingw_optreset
extern int optreset;
#endif
#ifdef __cplusplus
}
#endif
/*
* POSIX requires the `getopt' API to be specified in `unistd.h';
* thus, `unistd.h' includes this header. However, we do not want
* to expose the `getopt_long' or `getopt_long_only' APIs, when
* included in this manner. Thus, close the standard __GETOPT_H__
* declarations block, and open an additional __GETOPT_LONG_H__
* specific block, only when *not* __UNISTD_H_SOURCED__, in which
* to declare the extended API.
*/
#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
#define __GETOPT_LONG_H__
#ifdef __cplusplus
extern "C" {
#endif
struct option /* specification for a long form option... */
{
const char *name; /* option name, without leading hyphens */
int has_arg; /* does it take an argument? */
int *flag; /* where to save its status, or NULL */
int val; /* its associated status value */
};
enum /* permitted values for its `has_arg' field... */
{
no_argument = 0, /* option never takes an argument */
required_argument, /* option always requires an argument */
optional_argument /* option may take an argument */
};
extern int getopt_long(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx);
extern int getopt_long_only(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx);
/*
* Previous MinGW implementation had...
*/
#ifndef HAVE_DECL_GETOPT
/*
* ...for the long form API only; keep this for compatibility.
*/
# define HAVE_DECL_GETOPT 1
#endif
#ifdef __cplusplus
}
#endif
#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */
#endif /* !defined(__GETOPT_H__) */

View file

@ -0,0 +1,82 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MSCVER_STDATOMIC_H_
#define MSCVER_STDATOMIC_H_
#if !defined(__cplusplus) && defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4067) /* newline for __has_include_next */
#if defined(__clang__) && __has_include_next(<stdatomic.h>)
/* use the clang stdatomic.h with clang-cl*/
# include_next <stdatomic.h>
#else /* ! stdatomic.h */
#include <windows.h>
#include "common/attributes.h"
typedef volatile LONG atomic_int;
typedef volatile ULONG atomic_uint;
typedef enum {
memory_order_relaxed,
memory_order_acquire
} msvc_atomic_memory_order;
#define atomic_init(p_a, v) do { *(p_a) = (v); } while(0)
#define atomic_store(p_a, v) InterlockedExchange((LONG*)p_a, v)
#define atomic_load(p_a) InterlockedCompareExchange((LONG*)p_a, 0, 0)
#define atomic_exchange(p_a, v) InterlockedExchange(p_a, v)
#define atomic_load_explicit(p_a, mo) atomic_load(p_a)
static inline int atomic_compare_exchange_strong_int(LONG *obj, LONG *expected,
LONG desired)
{
LONG orig = *expected;
*expected = InterlockedCompareExchange(obj, desired, orig);
return *expected == orig;
}
#define atomic_compare_exchange_strong(p_a, expected, desired) atomic_compare_exchange_strong_int((LONG *)p_a, (LONG *)expected, (LONG)desired)
/*
* TODO use a special call to increment/decrement
* using InterlockedIncrement/InterlockedDecrement
*/
#define atomic_fetch_add(p_a, inc) InterlockedExchangeAdd(p_a, inc)
#define atomic_fetch_sub(p_a, dec) InterlockedExchangeAdd(p_a, -(dec))
#define atomic_fetch_or(p_a, v) InterlockedOr(p_a, v)
#define atomic_fetch_add_explicit(p_a, inc, mo) atomic_fetch_add(p_a, inc)
#endif /* ! stdatomic.h */
#pragma warning(pop)
#endif /* !defined(__cplusplus) && defined(_MSC_VER) */
#endif /* MSCVER_STDATOMIC_H_ */

View file

@ -0,0 +1,94 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DAV1D_COMMON_H
#define DAV1D_COMMON_H
#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef DAV1D_API
#if defined _WIN32
#if defined DAV1D_BUILDING_DLL
#define DAV1D_API __declspec(dllexport)
#else
#define DAV1D_API
#endif
#else
#if __GNUC__ >= 4
#define DAV1D_API __attribute__ ((visibility ("default")))
#else
#define DAV1D_API
#endif
#endif
#endif
#if EPERM > 0
#define DAV1D_ERR(e) (-(e)) ///< Negate POSIX error code.
#else
#define DAV1D_ERR(e) (e)
#endif
/**
* A reference-counted object wrapper for a user-configurable pointer.
*/
typedef struct Dav1dUserData {
const uint8_t *data; ///< data pointer
struct Dav1dRef *ref; ///< allocation origin
} Dav1dUserData;
/**
* Input packet metadata which are copied from the input data used to
* decode each image into the matching structure of the output image
* returned back to the user. Since these are metadata fields, they
* can be used for other purposes than the documented ones, they will
* still be passed from input data to output picture without being
* used internally.
*/
typedef struct Dav1dDataProps {
int64_t timestamp; ///< container timestamp of input data, INT64_MIN if unknown (default)
int64_t duration; ///< container duration of input data, 0 if unknown (default)
int64_t offset; ///< stream offset of input data, -1 if unknown (default)
size_t size; ///< packet size, default Dav1dData.sz
struct Dav1dUserData user_data; ///< user-configurable data, default NULL members
} Dav1dDataProps;
/**
* Release reference to a Dav1dDataProps.
*/
DAV1D_API void dav1d_data_props_unref(Dav1dDataProps *props);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* DAV1D_COMMON_H */

View file

@ -0,0 +1,117 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DAV1D_DATA_H
#define DAV1D_DATA_H
#include <stddef.h>
#include <stdint.h>
#include "common.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct Dav1dData {
const uint8_t *data; ///< data pointer
size_t sz; ///< data size
struct Dav1dRef *ref; ///< allocation origin
Dav1dDataProps m; ///< user provided metadata passed to the output picture
} Dav1dData;
/**
* Allocate data.
*
* @param data Input context.
* @param sz Size of the data that should be allocated.
*
* @return Pointer to the allocated buffer on success. NULL on error.
*/
DAV1D_API uint8_t * dav1d_data_create(Dav1dData *data, size_t sz);
/**
* Wrap an existing data array.
*
* @param data Input context.
* @param buf The data to be wrapped.
* @param sz Size of the data.
* @param free_callback Function to be called when we release our last
* reference to this data. In this callback, $buf will be
* the $buf argument to this function, and $cookie will
* be the $cookie input argument to this function.
* @param cookie Opaque parameter passed to free_callback().
*
* @return 0 on success. A negative DAV1D_ERR value on error.
*/
DAV1D_API int dav1d_data_wrap(Dav1dData *data, const uint8_t *buf, size_t sz,
void (*free_callback)(const uint8_t *buf, void *cookie),
void *cookie);
/**
* Wrap a user-provided data pointer into a reference counted object.
*
* data->m.user_data field will initialized to wrap the provided $user_data
* pointer.
*
* $free_callback will be called on the same thread that released the last
* reference. If frame threading is used, make sure $free_callback is
* thread-safe.
*
* @param data Input context.
* @param user_data The user data to be wrapped.
* @param free_callback Function to be called when we release our last
* reference to this data. In this callback, $user_data
* will be the $user_data argument to this function, and
* $cookie will be the $cookie input argument to this
* function.
* @param cookie Opaque parameter passed to $free_callback.
*
* @return 0 on success. A negative DAV1D_ERR value on error.
*/
DAV1D_API int dav1d_data_wrap_user_data(Dav1dData *data,
const uint8_t *user_data,
void (*free_callback)(const uint8_t *user_data,
void *cookie),
void *cookie);
/**
* Free the data reference.
*
* The reference count for data->m.user_data will be decremented (if it has been
* initialized with dav1d_data_wrap_user_data). The $data object will be memset
* to 0.
*
* @param data Input context.
*/
DAV1D_API void dav1d_data_unref(Dav1dData *data);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* DAV1D_DATA_H */

View file

@ -0,0 +1,329 @@
/*
* Copyright © 2018-2021, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DAV1D_H
#define DAV1D_H
#include <errno.h>
#include <stdarg.h>
#include "common.h"
#include "picture.h"
#include "data.h"
#include "version.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct Dav1dContext Dav1dContext;
typedef struct Dav1dRef Dav1dRef;
#define DAV1D_MAX_THREADS 256
#define DAV1D_MAX_FRAME_DELAY 256
typedef struct Dav1dLogger {
void *cookie; ///< Custom data to pass to the callback.
/**
* Logger callback. May be NULL to disable logging.
*
* @param cookie Custom pointer passed to all calls.
* @param format The vprintf compatible format string.
* @param ap List of arguments referenced by the format string.
*/
void (*callback)(void *cookie, const char *format, va_list ap);
} Dav1dLogger;
enum Dav1dInloopFilterType {
DAV1D_INLOOPFILTER_NONE = 0,
DAV1D_INLOOPFILTER_DEBLOCK = 1 << 0,
DAV1D_INLOOPFILTER_CDEF = 1 << 1,
DAV1D_INLOOPFILTER_RESTORATION = 1 << 2,
DAV1D_INLOOPFILTER_ALL = DAV1D_INLOOPFILTER_DEBLOCK |
DAV1D_INLOOPFILTER_CDEF |
DAV1D_INLOOPFILTER_RESTORATION,
};
enum Dav1dDecodeFrameType {
DAV1D_DECODEFRAMETYPE_ALL = 0, ///< decode and return all frames
DAV1D_DECODEFRAMETYPE_REFERENCE = 1,///< decode and return frames referenced by other frames only
DAV1D_DECODEFRAMETYPE_INTRA = 2, ///< decode and return intra frames only (includes keyframes)
DAV1D_DECODEFRAMETYPE_KEY = 3, ///< decode and return keyframes only
};
typedef struct Dav1dSettings {
int n_threads; ///< number of threads (0 = number of logical cores in host system, default 0)
int max_frame_delay; ///< Set to 1 for low-latency decoding (0 = ceil(sqrt(n_threads)), default 0)
int apply_grain; ///< whether to apply film grain on output frames (default 1)
int operating_point; ///< select an operating point for scalable AV1 bitstreams (0 - 31, default 0)
int all_layers; ///< output all spatial layers of a scalable AV1 biststream (default 1)
unsigned frame_size_limit; ///< maximum frame size, in pixels (0 = unlimited, default 0)
Dav1dPicAllocator allocator; ///< Picture allocator callback.
Dav1dLogger logger; ///< Logger callback.
int strict_std_compliance; ///< whether to abort decoding on standard compliance violations
///< that don't affect actual bitstream decoding (e.g. inconsistent
///< or invalid metadata, default 0)
int output_invisible_frames; ///< output invisibly coded frames (in coding order) in addition
///< to all visible frames. Because of show-existing-frame, this
///< means some frames may appear twice (once when coded,
///< once when shown, default 0)
enum Dav1dInloopFilterType inloop_filters; ///< postfilters to enable during decoding (default
///< DAV1D_INLOOPFILTER_ALL)
enum Dav1dDecodeFrameType decode_frame_type; ///< frame types to decode (default
///< DAV1D_DECODEFRAMETYPE_ALL)
uint8_t reserved[16]; ///< reserved for future use
} Dav1dSettings;
/**
* Get library version.
*/
DAV1D_API const char *dav1d_version(void);
/**
* Get library API version.
*
* @return A value in the format 0x00XXYYZZ, where XX is the major version,
* YY the minor version, and ZZ the patch version.
* @see DAV1D_API_MAJOR, DAV1D_API_MINOR, DAV1D_API_PATCH
*/
DAV1D_API unsigned dav1d_version_api(void);
/**
* Initialize settings to default values.
*
* @param s Input settings context.
*/
DAV1D_API void dav1d_default_settings(Dav1dSettings *s);
/**
* Allocate and open a decoder instance.
*
* @param c_out The decoder instance to open. *c_out will be set to the
* allocated context.
* @param s Input settings context.
*
* @note The context must be freed using dav1d_close() when decoding is
* finished.
*
* @return 0 on success, or < 0 (a negative DAV1D_ERR code) on error.
*/
DAV1D_API int dav1d_open(Dav1dContext **c_out, const Dav1dSettings *s);
/**
* Parse a Sequence Header OBU from bitstream data.
*
* @param out Output Sequence Header.
* @param buf The data to be parser.
* @param sz Size of the data.
*
* @return
* 0: Success, and out is filled with the parsed Sequence Header
* OBU parameters.
* DAV1D_ERR(ENOENT): No Sequence Header OBUs were found in the buffer.
* Other negative DAV1D_ERR codes: Invalid data in the buffer, invalid passed-in
* arguments, and other errors during parsing.
*
* @note It is safe to feed this function data containing other OBUs than a
* Sequence Header, as they will simply be ignored. If there is more than
* one Sequence Header OBU present, only the last will be returned.
*/
DAV1D_API int dav1d_parse_sequence_header(Dav1dSequenceHeader *out,
const uint8_t *buf, const size_t sz);
/**
* Feed bitstream data to the decoder, in the form of one or multiple AV1
* Open Bitstream Units (OBUs).
*
* @param c Input decoder instance.
* @param in Input bitstream data. On success, ownership of the reference is
* passed to the library.
*
* @return
* 0: Success, and the data was consumed.
* DAV1D_ERR(EAGAIN): The data can't be consumed. dav1d_get_picture() should
* be called to get one or more frames before the function
* can consume new data.
* Other negative DAV1D_ERR codes: Error during decoding or because of invalid
* passed-in arguments. The reference remains
* owned by the caller.
*/
DAV1D_API int dav1d_send_data(Dav1dContext *c, Dav1dData *in);
/**
* Return a decoded picture.
*
* @param c Input decoder instance.
* @param out Output frame. The caller assumes ownership of the returned
* reference.
*
* @return
* 0: Success, and a frame is returned.
* DAV1D_ERR(EAGAIN): Not enough data to output a frame. dav1d_send_data()
* should be called with new input.
* Other negative DAV1D_ERR codes: Error during decoding or because of invalid
* passed-in arguments.
*
* @note To drain buffered frames from the decoder (i.e. on end of stream),
* call this function until it returns DAV1D_ERR(EAGAIN).
*
* @code{.c}
* Dav1dData data = { 0 };
* Dav1dPicture p = { 0 };
* int res;
*
* read_data(&data);
* do {
* res = dav1d_send_data(c, &data);
* // Keep going even if the function can't consume the current data
* packet. It eventually will after one or more frames have been
* returned in this loop.
* if (res < 0 && res != DAV1D_ERR(EAGAIN))
* free_and_abort();
* res = dav1d_get_picture(c, &p);
* if (res < 0) {
* if (res != DAV1D_ERR(EAGAIN))
* free_and_abort();
* } else
* output_and_unref_picture(&p);
* // Stay in the loop as long as there's data to consume.
* } while (data.sz || read_data(&data) == SUCCESS);
*
* // Handle EOS by draining all buffered frames.
* do {
* res = dav1d_get_picture(c, &p);
* if (res < 0) {
* if (res != DAV1D_ERR(EAGAIN))
* free_and_abort();
* } else
* output_and_unref_picture(&p);
* } while (res == 0);
* @endcode
*/
DAV1D_API int dav1d_get_picture(Dav1dContext *c, Dav1dPicture *out);
/**
* Apply film grain to a previously decoded picture. If the picture contains no
* film grain metadata, then this function merely returns a new reference.
*
* @param c Input decoder instance.
* @param out Output frame. The caller assumes ownership of the returned
* reference.
* @param in Input frame. No ownership is transferred.
*
* @return
* 0: Success, and a frame is returned.
* Other negative DAV1D_ERR codes: Error due to lack of memory or because of
* invalid passed-in arguments.
*
* @note If `Dav1dSettings.apply_grain` is true, film grain was already applied
* by `dav1d_get_picture`, and so calling this function leads to double
* application of film grain. Users should only call this when needed.
*/
DAV1D_API int dav1d_apply_grain(Dav1dContext *c, Dav1dPicture *out,
const Dav1dPicture *in);
/**
* Close a decoder instance and free all associated memory.
*
* @param c_out The decoder instance to close. *c_out will be set to NULL.
*/
DAV1D_API void dav1d_close(Dav1dContext **c_out);
/**
* Flush all delayed frames in decoder and clear internal decoder state,
* to be used when seeking.
*
* @param c Input decoder instance.
*
* @note Decoding will start only after a valid sequence header OBU is
* delivered to dav1d_send_data().
*
*/
DAV1D_API void dav1d_flush(Dav1dContext *c);
enum Dav1dEventFlags {
/**
* The last returned picture contains a reference to a new Sequence Header,
* either because it's the start of a new coded sequence, or the decoder was
* flushed before it was generated.
*/
DAV1D_EVENT_FLAG_NEW_SEQUENCE = 1 << 0,
/**
* The last returned picture contains a reference to a Sequence Header with
* new operating parameters information for the current coded sequence.
*/
DAV1D_EVENT_FLAG_NEW_OP_PARAMS_INFO = 1 << 1,
};
/**
* Fetch a combination of DAV1D_EVENT_FLAG_* event flags generated by the decoding
* process.
*
* @param c Input decoder instance.
* @param flags Where to write the flags.
*
* @return 0 on success, or < 0 (a negative DAV1D_ERR code) on error.
*
* @note Calling this function will clear all the event flags currently stored in
* the decoder.
*
*/
DAV1D_API int dav1d_get_event_flags(Dav1dContext *c, enum Dav1dEventFlags *flags);
/**
* Retrieve the user-provided metadata associated with the input data packet
* for the last decoding error reported to the user, i.e. a negative return
* value (not EAGAIN) from dav1d_send_data() or dav1d_get_picture().
*
* @param c Input decoder instance.
* @param out Output Dav1dDataProps. On success, the caller assumes ownership of
* the returned reference.
*
* @return 0 on success, or < 0 (a negative DAV1D_ERR code) on error.
*/
DAV1D_API int dav1d_get_decode_error_data_props(Dav1dContext *c, Dav1dDataProps *out);
/**
* Get the decoder delay, which is the number of internally buffered frames, not
* including reference frames.
* This value is guaranteed to be >= 1 and <= max_frame_delay.
*
* @param s Input settings context.
*
* @return Decoder frame delay on success, or < 0 (a negative DAV1D_ERR code) on
* error.
*
* @note The returned delay is valid only for a Dav1dContext initialized with the
* provided Dav1dSettings.
*/
DAV1D_API int dav1d_get_frame_delay(const Dav1dSettings *s);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* DAV1D_H */

View file

@ -0,0 +1,440 @@
/*
* Copyright © 2018-2020, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DAV1D_HEADERS_H
#define DAV1D_HEADERS_H
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
// Constants from Section 3. "Symbols and abbreviated terms"
#define DAV1D_MAX_CDEF_STRENGTHS 8
#define DAV1D_MAX_OPERATING_POINTS 32
#define DAV1D_MAX_TILE_COLS 64
#define DAV1D_MAX_TILE_ROWS 64
#define DAV1D_MAX_SEGMENTS 8
#define DAV1D_NUM_REF_FRAMES 8
#define DAV1D_PRIMARY_REF_NONE 7
#define DAV1D_REFS_PER_FRAME 7
#define DAV1D_TOTAL_REFS_PER_FRAME (DAV1D_REFS_PER_FRAME + 1)
enum Dav1dObuType {
DAV1D_OBU_SEQ_HDR = 1,
DAV1D_OBU_TD = 2,
DAV1D_OBU_FRAME_HDR = 3,
DAV1D_OBU_TILE_GRP = 4,
DAV1D_OBU_METADATA = 5,
DAV1D_OBU_FRAME = 6,
DAV1D_OBU_REDUNDANT_FRAME_HDR = 7,
DAV1D_OBU_PADDING = 15,
};
enum Dav1dTxfmMode {
DAV1D_TX_4X4_ONLY,
DAV1D_TX_LARGEST,
DAV1D_TX_SWITCHABLE,
DAV1D_N_TX_MODES,
};
enum Dav1dFilterMode {
DAV1D_FILTER_8TAP_REGULAR,
DAV1D_FILTER_8TAP_SMOOTH,
DAV1D_FILTER_8TAP_SHARP,
DAV1D_N_SWITCHABLE_FILTERS,
DAV1D_FILTER_BILINEAR = DAV1D_N_SWITCHABLE_FILTERS,
DAV1D_N_FILTERS,
DAV1D_FILTER_SWITCHABLE = DAV1D_N_FILTERS,
};
enum Dav1dAdaptiveBoolean {
DAV1D_OFF = 0,
DAV1D_ON = 1,
DAV1D_ADAPTIVE = 2,
};
enum Dav1dRestorationType {
DAV1D_RESTORATION_NONE,
DAV1D_RESTORATION_SWITCHABLE,
DAV1D_RESTORATION_WIENER,
DAV1D_RESTORATION_SGRPROJ,
};
enum Dav1dWarpedMotionType {
DAV1D_WM_TYPE_IDENTITY,
DAV1D_WM_TYPE_TRANSLATION,
DAV1D_WM_TYPE_ROT_ZOOM,
DAV1D_WM_TYPE_AFFINE,
};
typedef struct Dav1dWarpedMotionParams {
enum Dav1dWarpedMotionType type;
int32_t matrix[6];
union {
struct {
int16_t alpha, beta, gamma, delta;
} p;
int16_t abcd[4];
} u;
} Dav1dWarpedMotionParams;
enum Dav1dPixelLayout {
DAV1D_PIXEL_LAYOUT_I400, ///< monochrome
DAV1D_PIXEL_LAYOUT_I420, ///< 4:2:0 planar
DAV1D_PIXEL_LAYOUT_I422, ///< 4:2:2 planar
DAV1D_PIXEL_LAYOUT_I444, ///< 4:4:4 planar
};
enum Dav1dFrameType {
DAV1D_FRAME_TYPE_KEY = 0, ///< Key Intra frame
DAV1D_FRAME_TYPE_INTER = 1, ///< Inter frame
DAV1D_FRAME_TYPE_INTRA = 2, ///< Non key Intra frame
DAV1D_FRAME_TYPE_SWITCH = 3, ///< Switch Inter frame
};
enum Dav1dColorPrimaries {
DAV1D_COLOR_PRI_BT709 = 1,
DAV1D_COLOR_PRI_UNKNOWN = 2,
DAV1D_COLOR_PRI_BT470M = 4,
DAV1D_COLOR_PRI_BT470BG = 5,
DAV1D_COLOR_PRI_BT601 = 6,
DAV1D_COLOR_PRI_SMPTE240 = 7,
DAV1D_COLOR_PRI_FILM = 8,
DAV1D_COLOR_PRI_BT2020 = 9,
DAV1D_COLOR_PRI_XYZ = 10,
DAV1D_COLOR_PRI_SMPTE431 = 11,
DAV1D_COLOR_PRI_SMPTE432 = 12,
DAV1D_COLOR_PRI_EBU3213 = 22,
DAV1D_COLOR_PRI_RESERVED = 255,
};
enum Dav1dTransferCharacteristics {
DAV1D_TRC_BT709 = 1,
DAV1D_TRC_UNKNOWN = 2,
DAV1D_TRC_BT470M = 4,
DAV1D_TRC_BT470BG = 5,
DAV1D_TRC_BT601 = 6,
DAV1D_TRC_SMPTE240 = 7,
DAV1D_TRC_LINEAR = 8,
DAV1D_TRC_LOG100 = 9, ///< logarithmic (100:1 range)
DAV1D_TRC_LOG100_SQRT10 = 10, ///< lograithmic (100*sqrt(10):1 range)
DAV1D_TRC_IEC61966 = 11,
DAV1D_TRC_BT1361 = 12,
DAV1D_TRC_SRGB = 13,
DAV1D_TRC_BT2020_10BIT = 14,
DAV1D_TRC_BT2020_12BIT = 15,
DAV1D_TRC_SMPTE2084 = 16, ///< PQ
DAV1D_TRC_SMPTE428 = 17,
DAV1D_TRC_HLG = 18, ///< hybrid log/gamma (BT.2100 / ARIB STD-B67)
DAV1D_TRC_RESERVED = 255,
};
enum Dav1dMatrixCoefficients {
DAV1D_MC_IDENTITY = 0,
DAV1D_MC_BT709 = 1,
DAV1D_MC_UNKNOWN = 2,
DAV1D_MC_FCC = 4,
DAV1D_MC_BT470BG = 5,
DAV1D_MC_BT601 = 6,
DAV1D_MC_SMPTE240 = 7,
DAV1D_MC_SMPTE_YCGCO = 8,
DAV1D_MC_BT2020_NCL = 9,
DAV1D_MC_BT2020_CL = 10,
DAV1D_MC_SMPTE2085 = 11,
DAV1D_MC_CHROMAT_NCL = 12, ///< Chromaticity-derived
DAV1D_MC_CHROMAT_CL = 13,
DAV1D_MC_ICTCP = 14,
DAV1D_MC_RESERVED = 255,
};
enum Dav1dChromaSamplePosition {
DAV1D_CHR_UNKNOWN = 0,
DAV1D_CHR_VERTICAL = 1, ///< Horizontally co-located with luma(0, 0)
///< sample, between two vertical samples
DAV1D_CHR_COLOCATED = 2, ///< Co-located with luma(0, 0) sample
};
typedef struct Dav1dContentLightLevel {
uint16_t max_content_light_level;
uint16_t max_frame_average_light_level;
} Dav1dContentLightLevel;
typedef struct Dav1dMasteringDisplay {
uint16_t primaries[3][2]; ///< 0.16 fixed point
uint16_t white_point[2]; ///< 0.16 fixed point
uint32_t max_luminance; ///< 24.8 fixed point
uint32_t min_luminance; ///< 18.14 fixed point
} Dav1dMasteringDisplay;
typedef struct Dav1dITUTT35 {
uint8_t country_code;
uint8_t country_code_extension_byte;
size_t payload_size;
uint8_t *payload;
} Dav1dITUTT35;
typedef struct Dav1dSequenceHeader {
/**
* Stream profile, 0 for 8-10 bits/component 4:2:0 or monochrome;
* 1 for 8-10 bits/component 4:4:4; 2 for 4:2:2 at any bits/component,
* or 12 bits/component at any chroma subsampling.
*/
uint8_t profile;
/**
* Maximum dimensions for this stream. In non-scalable streams, these
* are often the actual dimensions of the stream, although that is not
* a normative requirement.
*/
int max_width, max_height;
enum Dav1dPixelLayout layout; ///< format of the picture
enum Dav1dColorPrimaries pri; ///< color primaries (av1)
enum Dav1dTransferCharacteristics trc; ///< transfer characteristics (av1)
enum Dav1dMatrixCoefficients mtrx; ///< matrix coefficients (av1)
enum Dav1dChromaSamplePosition chr; ///< chroma sample position (av1)
/**
* 0, 1 and 2 mean 8, 10 or 12 bits/component, respectively. This is not
* exactly the same as 'hbd' from the spec; the spec's hbd distinguishes
* between 8 (0) and 10-12 (1) bits/component, and another element
* (twelve_bit) to distinguish between 10 and 12 bits/component. To get
* the spec's hbd, use !!our_hbd, and to get twelve_bit, use hbd == 2.
*/
uint8_t hbd;
/**
* Pixel data uses JPEG pixel range ([0,255] for 8bits) instead of
* MPEG pixel range ([16,235] for 8bits luma, [16,240] for 8bits chroma).
*/
uint8_t color_range;
uint8_t num_operating_points;
struct Dav1dSequenceHeaderOperatingPoint {
uint8_t major_level, minor_level;
uint8_t initial_display_delay;
uint16_t idc;
uint8_t tier;
uint8_t decoder_model_param_present;
uint8_t display_model_param_present;
} operating_points[DAV1D_MAX_OPERATING_POINTS];
uint8_t still_picture;
uint8_t reduced_still_picture_header;
uint8_t timing_info_present;
uint32_t num_units_in_tick;
uint32_t time_scale;
uint8_t equal_picture_interval;
uint32_t num_ticks_per_picture;
uint8_t decoder_model_info_present;
uint8_t encoder_decoder_buffer_delay_length;
uint32_t num_units_in_decoding_tick;
uint8_t buffer_removal_delay_length;
uint8_t frame_presentation_delay_length;
uint8_t display_model_info_present;
uint8_t width_n_bits, height_n_bits;
uint8_t frame_id_numbers_present;
uint8_t delta_frame_id_n_bits;
uint8_t frame_id_n_bits;
uint8_t sb128;
uint8_t filter_intra;
uint8_t intra_edge_filter;
uint8_t inter_intra;
uint8_t masked_compound;
uint8_t warped_motion;
uint8_t dual_filter;
uint8_t order_hint;
uint8_t jnt_comp;
uint8_t ref_frame_mvs;
enum Dav1dAdaptiveBoolean screen_content_tools;
enum Dav1dAdaptiveBoolean force_integer_mv;
uint8_t order_hint_n_bits;
uint8_t super_res;
uint8_t cdef;
uint8_t restoration;
uint8_t ss_hor, ss_ver, monochrome;
uint8_t color_description_present;
uint8_t separate_uv_delta_q;
uint8_t film_grain_present;
// Dav1dSequenceHeaders of the same sequence are required to be
// bit-identical until this offset. See 7.5 "Ordering of OBUs":
// Within a particular coded video sequence, the contents of
// sequence_header_obu must be bit-identical each time the
// sequence header appears except for the contents of
// operating_parameters_info.
struct Dav1dSequenceHeaderOperatingParameterInfo {
uint32_t decoder_buffer_delay;
uint32_t encoder_buffer_delay;
uint8_t low_delay_mode;
} operating_parameter_info[DAV1D_MAX_OPERATING_POINTS];
} Dav1dSequenceHeader;
typedef struct Dav1dSegmentationData {
int16_t delta_q;
int8_t delta_lf_y_v, delta_lf_y_h, delta_lf_u, delta_lf_v;
int8_t ref;
uint8_t skip;
uint8_t globalmv;
} Dav1dSegmentationData;
typedef struct Dav1dSegmentationDataSet {
Dav1dSegmentationData d[DAV1D_MAX_SEGMENTS];
uint8_t preskip;
int8_t last_active_segid;
} Dav1dSegmentationDataSet;
typedef struct Dav1dLoopfilterModeRefDeltas {
int8_t mode_delta[2 /* is_zeromv */];
int8_t ref_delta[DAV1D_TOTAL_REFS_PER_FRAME];
} Dav1dLoopfilterModeRefDeltas;
typedef struct Dav1dFilmGrainData {
unsigned seed;
int num_y_points;
uint8_t y_points[14][2 /* value, scaling */];
int chroma_scaling_from_luma;
int num_uv_points[2];
uint8_t uv_points[2][10][2 /* value, scaling */];
int scaling_shift;
int ar_coeff_lag;
int8_t ar_coeffs_y[24];
int8_t ar_coeffs_uv[2][25 + 3 /* padding for alignment purposes */];
uint64_t ar_coeff_shift;
int grain_scale_shift;
int uv_mult[2];
int uv_luma_mult[2];
int uv_offset[2];
int overlap_flag;
int clip_to_restricted_range;
} Dav1dFilmGrainData;
typedef struct Dav1dFrameHeader {
struct {
Dav1dFilmGrainData data;
uint8_t present, update;
} film_grain; ///< film grain parameters
enum Dav1dFrameType frame_type; ///< type of the picture
int width[2 /* { coded_width, superresolution_upscaled_width } */], height;
uint8_t frame_offset; ///< frame number
uint8_t temporal_id; ///< temporal id of the frame for SVC
uint8_t spatial_id; ///< spatial id of the frame for SVC
uint8_t show_existing_frame;
uint8_t existing_frame_idx;
uint32_t frame_id;
uint32_t frame_presentation_delay;
uint8_t show_frame;
uint8_t showable_frame;
uint8_t error_resilient_mode;
uint8_t disable_cdf_update;
uint8_t allow_screen_content_tools;
uint8_t force_integer_mv;
uint8_t frame_size_override;
uint8_t primary_ref_frame;
uint8_t buffer_removal_time_present;
struct Dav1dFrameHeaderOperatingPoint {
uint32_t buffer_removal_time;
} operating_points[DAV1D_MAX_OPERATING_POINTS];
uint8_t refresh_frame_flags;
int render_width, render_height;
struct {
uint8_t width_scale_denominator;
uint8_t enabled;
} super_res;
uint8_t have_render_size;
uint8_t allow_intrabc;
uint8_t frame_ref_short_signaling;
int8_t refidx[DAV1D_REFS_PER_FRAME];
uint8_t hp;
enum Dav1dFilterMode subpel_filter_mode;
uint8_t switchable_motion_mode;
uint8_t use_ref_frame_mvs;
uint8_t refresh_context;
struct {
uint8_t uniform;
uint8_t n_bytes;
uint8_t min_log2_cols, max_log2_cols, log2_cols, cols;
uint8_t min_log2_rows, max_log2_rows, log2_rows, rows;
uint16_t col_start_sb[DAV1D_MAX_TILE_COLS + 1];
uint16_t row_start_sb[DAV1D_MAX_TILE_ROWS + 1];
uint16_t update;
} tiling;
struct {
uint8_t yac;
int8_t ydc_delta;
int8_t udc_delta, uac_delta, vdc_delta, vac_delta;
uint8_t qm, qm_y, qm_u, qm_v;
} quant;
struct {
uint8_t enabled, update_map, temporal, update_data;
Dav1dSegmentationDataSet seg_data;
uint8_t lossless[DAV1D_MAX_SEGMENTS], qidx[DAV1D_MAX_SEGMENTS];
} segmentation;
struct {
struct {
uint8_t present;
uint8_t res_log2;
} q;
struct {
uint8_t present;
uint8_t res_log2;
uint8_t multi;
} lf;
} delta;
uint8_t all_lossless;
struct {
uint8_t level_y[2 /* dir */];
uint8_t level_u, level_v;
uint8_t mode_ref_delta_enabled;
uint8_t mode_ref_delta_update;
Dav1dLoopfilterModeRefDeltas mode_ref_deltas;
uint8_t sharpness;
} loopfilter;
struct {
uint8_t damping;
uint8_t n_bits;
uint8_t y_strength[DAV1D_MAX_CDEF_STRENGTHS];
uint8_t uv_strength[DAV1D_MAX_CDEF_STRENGTHS];
} cdef;
struct {
enum Dav1dRestorationType type[3 /* plane */];
uint8_t unit_size[2 /* y, uv */];
} restoration;
enum Dav1dTxfmMode txfm_mode;
uint8_t switchable_comp_refs;
uint8_t skip_mode_allowed, skip_mode_enabled;
int8_t skip_mode_refs[2];
uint8_t warp_motion;
uint8_t reduced_txtp_set;
Dav1dWarpedMotionParams gmv[DAV1D_REFS_PER_FRAME];
} Dav1dFrameHeader;
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* DAV1D_HEADERS_H */

View file

@ -0,0 +1,36 @@
# Copyright © 2019, VideoLAN and dav1d authors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
dav1d_api_headers = [
'common.h',
'data.h',
'dav1d.h',
'headers.h',
'picture.h',
'version.h',
]
# install headers
install_headers(dav1d_api_headers,
subdir : 'dav1d')

View file

@ -0,0 +1,157 @@
/*
* Copyright © 2018-2020, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DAV1D_PICTURE_H
#define DAV1D_PICTURE_H
#include <stddef.h>
#include <stdint.h>
#include "common.h"
#include "headers.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Number of bytes to align AND pad picture memory buffers by, so that SIMD
* implementations can over-read by a few bytes, and use aligned read/write
* instructions. */
#define DAV1D_PICTURE_ALIGNMENT 64
typedef struct Dav1dPictureParameters {
int w; ///< width (in pixels)
int h; ///< height (in pixels)
enum Dav1dPixelLayout layout; ///< format of the picture
int bpc; ///< bits per pixel component (8 or 10)
} Dav1dPictureParameters;
typedef struct Dav1dPicture {
Dav1dSequenceHeader *seq_hdr;
Dav1dFrameHeader *frame_hdr;
/**
* Pointers to planar image data (Y is [0], U is [1], V is [2]). The data
* should be bytes (for 8 bpc) or words (for 10 bpc). In case of words
* containing 10 bpc image data, the pixels should be located in the LSB
* bits, so that values range between [0, 1023]; the upper bits should be
* zero'ed out.
*/
void *data[3];
/**
* Number of bytes between 2 lines in data[] for luma [0] or chroma [1].
*/
ptrdiff_t stride[2];
Dav1dPictureParameters p;
Dav1dDataProps m;
/**
* High Dynamic Range Content Light Level metadata applying to this picture,
* as defined in section 5.8.3 and 6.7.3
*/
Dav1dContentLightLevel *content_light;
/**
* High Dynamic Range Mastering Display Color Volume metadata applying to
* this picture, as defined in section 5.8.4 and 6.7.4
*/
Dav1dMasteringDisplay *mastering_display;
/**
* Array of ITU-T T.35 metadata as defined in section 5.8.2 and 6.7.2
*/
Dav1dITUTT35 *itut_t35;
/**
* Number of ITU-T T35 metadata entries in the array
*/
size_t n_itut_t35;
uintptr_t reserved[4]; ///< reserved for future use
struct Dav1dRef *frame_hdr_ref; ///< Dav1dFrameHeader allocation origin
struct Dav1dRef *seq_hdr_ref; ///< Dav1dSequenceHeader allocation origin
struct Dav1dRef *content_light_ref; ///< Dav1dContentLightLevel allocation origin
struct Dav1dRef *mastering_display_ref; ///< Dav1dMasteringDisplay allocation origin
struct Dav1dRef *itut_t35_ref; ///< Dav1dITUTT35 allocation origin
uintptr_t reserved_ref[4]; ///< reserved for future use
struct Dav1dRef *ref; ///< Frame data allocation origin
void *allocator_data; ///< pointer managed by the allocator
} Dav1dPicture;
typedef struct Dav1dPicAllocator {
void *cookie; ///< custom data to pass to the allocator callbacks.
/**
* Allocate the picture buffer based on the Dav1dPictureParameters.
*
* The data[0], data[1] and data[2] must be DAV1D_PICTURE_ALIGNMENT byte
* aligned and with a pixel width/height multiple of 128 pixels. Any
* allocated memory area should also be padded by DAV1D_PICTURE_ALIGNMENT
* bytes.
* data[1] and data[2] must share the same stride[1].
*
* This function will be called on the main thread (the thread which calls
* dav1d_get_picture()).
*
* @param pic The picture to allocate the buffer for. The callback needs to
* fill the picture data[0], data[1], data[2], stride[0] and
* stride[1].
* The allocator can fill the pic allocator_data pointer with
* a custom pointer that will be passed to
* release_picture_callback().
* @param cookie Custom pointer passed to all calls.
*
* @note No fields other than data, stride and allocator_data must be filled
* by this callback.
* @return 0 on success. A negative DAV1D_ERR value on error.
*/
int (*alloc_picture_callback)(Dav1dPicture *pic, void *cookie);
/**
* Release the picture buffer.
*
* If frame threading is used, this function may be called by the main
* thread (the thread which calls dav1d_get_picture()) or any of the frame
* threads and thus must be thread-safe. If frame threading is not used,
* this function will only be called on the main thread.
*
* @param pic The picture that was filled by alloc_picture_callback().
* @param cookie Custom pointer passed to all calls.
*/
void (*release_picture_callback)(Dav1dPicture *pic, void *cookie);
} Dav1dPicAllocator;
/**
* Release reference to a picture.
*/
DAV1D_API void dav1d_picture_unref(Dav1dPicture *p);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* DAV1D_PICTURE_H */

View file

@ -0,0 +1,50 @@
/*
* Copyright © 2019-2024, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DAV1D_VERSION_H
#define DAV1D_VERSION_H
#ifdef __cplusplus
extern "C" {
#endif
#define DAV1D_API_VERSION_MAJOR 7
#define DAV1D_API_VERSION_MINOR 0
#define DAV1D_API_VERSION_PATCH 0
/**
* Extract version components from the value returned by
* dav1d_version_int()
*/
#define DAV1D_API_MAJOR(v) (((v) >> 16) & 0xFF)
#define DAV1D_API_MINOR(v) (((v) >> 8) & 0xFF)
#define DAV1D_API_PATCH(v) (((v) >> 0) & 0xFF)
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* DAV1D_VERSION_H */

View file

@ -0,0 +1,34 @@
# Copyright © 2018, VideoLAN and dav1d authors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Revision file (vcs_version.h) generation
dav1d_git_dir = join_paths(dav1d_src_root, '.git')
rev_target = vcs_tag(command: [
'git', '--git-dir', dav1d_git_dir, 'describe', '--long', '--always'
],
input: 'vcs_version.h.in',
output: 'vcs_version.h'
)
subdir('dav1d')

View file

@ -0,0 +1,2 @@
/* auto-generated, do not edit */
#define DAV1D_VERSION "@VCS_TAG@"

View file

@ -0,0 +1,610 @@
# Copyright © 2018-2024, VideoLAN and dav1d authors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
project('dav1d', ['c'],
version: '1.5.3',
default_options: ['c_std=c99',
'warning_level=2',
'buildtype=release',
'b_ndebug=if-release'],
meson_version: '>= 0.49.0')
dav1d_src_root = meson.current_source_dir()
cc = meson.get_compiler('c')
# Configuratin data for config.h
cdata = configuration_data()
# Configuration data for config.asm
cdata_asm = configuration_data()
# Include directories
dav1d_inc_dirs = include_directories(['.', 'include/dav1d', 'include'])
dav1d_api_version_major = cc.get_define('DAV1D_API_VERSION_MAJOR',
prefix: '#include "dav1d/version.h"',
include_directories: dav1d_inc_dirs).strip()
dav1d_api_version_minor = cc.get_define('DAV1D_API_VERSION_MINOR',
prefix: '#include "dav1d/version.h"',
include_directories: dav1d_inc_dirs).strip()
dav1d_api_version_revision = cc.get_define('DAV1D_API_VERSION_PATCH',
prefix: '#include "dav1d/version.h"',
include_directories: dav1d_inc_dirs).strip()
dav1d_soname_version = '@0@.@1@.@2@'.format(dav1d_api_version_major,
dav1d_api_version_minor,
dav1d_api_version_revision)
#
# Option handling
#
# Bitdepth option
dav1d_bitdepths = get_option('bitdepths')
foreach bitdepth : ['8', '16']
cdata.set10('CONFIG_@0@BPC'.format(bitdepth), dav1d_bitdepths.contains(bitdepth))
endforeach
# ASM option
is_asm_enabled = (get_option('enable_asm') == true and
(host_machine.cpu_family() == 'aarch64' or
host_machine.cpu_family().startswith('arm') or
host_machine.cpu() == 'ppc64le' or
host_machine.cpu_family().startswith('riscv') or
host_machine.cpu_family().startswith('loongarch') or
host_machine.cpu_family() == 'x86' or
(host_machine.cpu_family() == 'x86_64' and cc.get_define('__ILP32__').strip() == '')))
cdata.set10('HAVE_ASM', is_asm_enabled)
if is_asm_enabled and get_option('b_sanitize') == 'memory'
error('asm causes false positive with memory sanitizer. Use \'-Denable_asm=false\'.')
endif
cdata.set10('TRIM_DSP_FUNCTIONS', get_option('trim_dsp') == 'true' or
(get_option('trim_dsp') == 'if-release' and get_option('buildtype') == 'release'))
# Logging option
cdata.set10('CONFIG_LOG', get_option('logging'))
cdata.set10('CONFIG_MACOS_KPERF', get_option('macos_kperf'))
#
# OS/Compiler checks and defines
#
# Arguments in test_args will be used even on feature tests
test_args = []
optional_arguments = []
optional_link_arguments = []
if host_machine.system() in ['linux', 'gnu', 'emscripten']
test_args += '-D_GNU_SOURCE'
add_project_arguments('-D_GNU_SOURCE', language: 'c')
endif
have_clock_gettime = false
have_posix_memalign = false
have_memalign = false
have_aligned_alloc = false
if host_machine.system() == 'windows'
cdata.set('_WIN32_WINNT', '0x0601')
cdata.set('UNICODE', 1) # Define to 1 for Unicode (Wide Chars) APIs
cdata.set('_UNICODE', 1) # Define to 1 for Unicode (Wide Chars) APIs
cdata.set('__USE_MINGW_ANSI_STDIO', 1) # Define to force use of MinGW printf
cdata.set('_CRT_DECLARE_NONSTDC_NAMES', 1) # Define to get off_t from sys/types.h on MSVC
if cc.has_function('fseeko', prefix : '#include <stdio.h>', args : test_args)
cdata.set('_FILE_OFFSET_BITS', 64) # Not set by default by Meson on Windows
else
cdata.set('fseeko', '_fseeki64')
cdata.set('ftello', '_ftelli64')
endif
if host_machine.cpu_family() == 'x86_64'
if cc.get_argument_syntax() != 'msvc'
optional_link_arguments += '-Wl,--dynamicbase,--nxcompat,--tsaware,--high-entropy-va'
endif
elif host_machine.cpu_family() == 'x86' or host_machine.cpu_family() == 'arm'
if cc.get_argument_syntax() == 'msvc'
optional_link_arguments += '/largeaddressaware'
else
optional_link_arguments += '-Wl,--dynamicbase,--nxcompat,--tsaware,--large-address-aware'
endif
endif
# On Windows, we use a compatibility layer to emulate pthread
thread_dependency = []
thread_compat_dep = declare_dependency(sources : files('src/win32/thread.c'))
rt_dependency = []
rc_version_array = meson.project_version().split('.')
winmod = import('windows')
rc_data = configuration_data()
rc_data.set('PROJECT_VERSION_MAJOR', rc_version_array[0])
rc_data.set('PROJECT_VERSION_MINOR', rc_version_array[1])
rc_data.set('PROJECT_VERSION_REVISION', rc_version_array[2])
rc_data.set('API_VERSION_MAJOR', dav1d_api_version_major)
rc_data.set('API_VERSION_MINOR', dav1d_api_version_minor)
rc_data.set('API_VERSION_REVISION', dav1d_api_version_revision)
rc_data.set('COPYRIGHT_YEARS', '2018-2025')
else
thread_dependency = dependency('threads')
thread_compat_dep = []
rt_dependency = []
if cc.has_function('clock_gettime', prefix : '#include <time.h>', args : test_args)
have_clock_gettime = true
elif host_machine.system() not in ['darwin', 'ios', 'tvos']
rt_dependency = cc.find_library('rt', required: false)
if not cc.has_function('clock_gettime', prefix : '#include <time.h>', args : test_args, dependencies : rt_dependency)
error('clock_gettime not found')
endif
have_clock_gettime = true
endif
have_posix_memalign = cc.has_function('posix_memalign', prefix : '#include <stdlib.h>', args : test_args)
have_memalign = cc.has_function('memalign', prefix : '#include <malloc.h>', args : test_args)
have_aligned_alloc = cc.has_function('aligned_alloc', prefix : '#include <stdlib.h>', args : test_args)
endif
cdata.set10('HAVE_CLOCK_GETTIME', have_clock_gettime)
cdata.set10('HAVE_POSIX_MEMALIGN', have_posix_memalign)
cdata.set10('HAVE_MEMALIGN', have_memalign)
cdata.set10('HAVE_ALIGNED_ALLOC', have_aligned_alloc)
# check for fseeko on android. It is not always available if _FILE_OFFSET_BITS is defined to 64
have_fseeko = true
if host_machine.system() == 'android'
if not cc.has_function('fseeko', prefix : '#include <stdio.h>', args : test_args)
if cc.has_function('fseeko', prefix : '#include <stdio.h>', args : test_args + ['-U_FILE_OFFSET_BITS'])
warning('Files larger than 2 gigabytes might not be supported in the dav1d CLI tool.')
add_project_arguments('-U_FILE_OFFSET_BITS', language: 'c')
elif get_option('enable_tools')
error('dav1d CLI tool needs fseeko()')
else
have_fseeko = false
endif
endif
endif
libdl_dependency = []
have_dlsym = false
if host_machine.system() == 'linux'
libdl_dependency = cc.find_library('dl', required : false)
have_dlsym = cc.has_function('dlsym', prefix : '#include <dlfcn.h>', args : test_args, dependencies : libdl_dependency)
endif
cdata.set10('HAVE_DLSYM', have_dlsym)
libm_dependency = cc.find_library('m', required: false)
# Header checks
stdatomic_dependencies = []
if not cc.check_header('stdatomic.h')
if cc.get_id() == 'msvc'
# we have a custom replacement for MSVC
stdatomic_dependencies += declare_dependency(
include_directories : include_directories('include/compat/msvc'),
)
elif cc.compiles('''int main() { int v = 0; return __atomic_fetch_add(&v, 1, __ATOMIC_SEQ_CST); }''',
name : 'GCC-style atomics', args : test_args)
stdatomic_dependencies += declare_dependency(
include_directories : include_directories('include/compat/gcc'),
)
else
error('Atomics not supported')
endif
endif
if host_machine.cpu_family().startswith('wasm')
# enable atomics + bulk-memory features
stdatomic_dependencies += thread_dependency.partial_dependency(compile_args: true)
endif
cdata.set10('HAVE_SYS_TYPES_H', cc.check_header('sys/types.h'))
cdata.set10('HAVE_UNISTD_H', cc.check_header('unistd.h'))
cdata.set10('HAVE_IO_H', cc.check_header('io.h'))
have_pthread_np = cc.check_header('pthread_np.h')
cdata.set10('HAVE_PTHREAD_NP_H', have_pthread_np)
test_args += '-DHAVE_PTHREAD_NP_H=' + (have_pthread_np ? '1' : '0')
# Function checks
if not cc.has_function('getopt_long', prefix : '#include <getopt.h>', args : test_args)
getopt_dependency = declare_dependency(
sources: files('tools/compat/getopt.c'),
include_directories : include_directories('include/compat'),
)
else
getopt_dependency = []
endif
have_getauxval = false
have_elf_aux_info = false
if (host_machine.cpu_family() == 'aarch64' or
host_machine.cpu_family().startswith('arm') or
host_machine.cpu_family().startswith('loongarch') or
host_machine.cpu() == 'ppc64le' or
host_machine.cpu_family().startswith('riscv'))
have_getauxval = cc.has_function('getauxval', prefix : '#include <sys/auxv.h>', args : test_args)
have_elf_aux_info = cc.has_function('elf_aux_info', prefix : '#include <sys/auxv.h>', args : test_args)
endif
cdata.set10('HAVE_GETAUXVAL', have_getauxval)
cdata.set10('HAVE_ELF_AUX_INFO', have_elf_aux_info)
pthread_np_prefix = '''
#include <pthread.h>
#if HAVE_PTHREAD_NP_H
#include <pthread_np.h>
#endif
'''
cdata.set10('HAVE_PTHREAD_GETAFFINITY_NP', cc.has_function('pthread_getaffinity_np', prefix : pthread_np_prefix, args : test_args, dependencies : thread_dependency))
cdata.set10('HAVE_PTHREAD_SETAFFINITY_NP', cc.has_function('pthread_setaffinity_np', prefix : pthread_np_prefix, args : test_args, dependencies : thread_dependency))
cdata.set10('HAVE_PTHREAD_SETNAME_NP', cc.has_function('pthread_setname_np', prefix : pthread_np_prefix, args : test_args, dependencies : thread_dependency))
cdata.set10('HAVE_PTHREAD_SET_NAME_NP', cc.has_function('pthread_set_name_np', prefix : pthread_np_prefix, args : test_args, dependencies : thread_dependency))
cdata.set10('HAVE_C11_GENERIC', cc.compiles('int x = _Generic(0, default: 0);', name: '_Generic', args: test_args))
# Compiler flag tests
if cc.has_argument('-fvisibility=hidden')
add_project_arguments('-fvisibility=hidden', language: 'c')
else
warning('Compiler does not support -fvisibility=hidden, all symbols will be public!')
endif
# Compiler flags that should be set
# But when the compiler does not supports them
# it is not an error and silently tolerated
if cc.get_argument_syntax() != 'msvc'
optional_arguments += [
'-Wundef',
'-Werror=vla',
'-Wno-maybe-uninitialized',
'-Wno-missing-field-initializers',
'-Wno-unused-parameter',
'-Wstrict-prototypes',
'-Werror=missing-prototypes',
'-Wshorten-64-to-32',
]
if host_machine.cpu_family() == 'x86'
optional_arguments += [
'-msse2',
'-mfpmath=sse',
]
endif
else
optional_arguments += [
'-wd4028', # parameter different from declaration
'-wd4090', # broken with arrays of pointers
'-wd4996' # use of POSIX functions
]
endif
if (get_option('buildtype') != 'debug' and get_option('buildtype') != 'plain')
optional_arguments += '-fomit-frame-pointer'
optional_arguments += '-ffast-math'
endif
if (host_machine.system() in ['darwin', 'ios', 'tvos'] and cc.get_id() == 'clang' and
cc.version().startswith('11'))
# Workaround for Xcode 11 -fstack-check bug, see #301
optional_arguments += '-fno-stack-check'
endif
if (host_machine.cpu_family() == 'aarch64' or host_machine.cpu_family().startswith('arm'))
optional_arguments += '-fno-align-functions'
endif
add_project_arguments(cc.get_supported_arguments(optional_arguments), language : 'c')
add_project_link_arguments(cc.get_supported_link_arguments(optional_link_arguments), language : 'c')
# libFuzzer related things
fuzzing_engine = get_option('fuzzing_engine')
if fuzzing_engine == 'libfuzzer'
if not cc.has_argument('-fsanitize=fuzzer')
error('fuzzing_engine libfuzzer requires "-fsanitize=fuzzer"')
endif
fuzzer_args = ['-fsanitize=fuzzer-no-link', '-fsanitize=fuzzer']
add_project_arguments(cc.first_supported_argument(fuzzer_args), language : 'c')
endif
cdata.set10('ENDIANNESS_BIG', host_machine.endian() == 'big')
if host_machine.cpu_family().startswith('x86')
if get_option('stack_alignment') > 0
stack_alignment = get_option('stack_alignment')
elif host_machine.cpu_family() == 'x86_64' or host_machine.system() in ['linux', 'darwin', 'ios', 'tvos']
stack_alignment = 16
else
stack_alignment = 4
endif
cdata_asm.set('STACK_ALIGNMENT', stack_alignment)
endif
#
# ASM specific stuff
#
use_gaspp = false
if (is_asm_enabled and
(host_machine.cpu_family() == 'aarch64' or
host_machine.cpu_family().startswith('arm')) and
cc.get_argument_syntax() == 'msvc' and
(cc.get_id() != 'clang-cl' or meson.version().version_compare('<0.58.0')))
gaspp = find_program('gas-preprocessor.pl')
use_gaspp = true
gaspp_args = [
'-as-type', 'armasm',
'-arch', host_machine.cpu_family(),
'--',
host_machine.cpu_family() == 'aarch64' ? 'armasm64' : 'armasm',
'-nologo',
'-I@0@'.format(dav1d_src_root),
'-I@0@/'.format(meson.current_build_dir()),
]
gaspp_gen = generator(gaspp,
output: '@BASENAME@.obj',
arguments: gaspp_args + [
'@INPUT@',
'-c',
'-o', '@OUTPUT@'
])
endif
cdata.set10('ARCH_AARCH64', host_machine.cpu_family() == 'aarch64' or host_machine.cpu() == 'arm64')
cdata.set10('ARCH_ARM', host_machine.cpu_family().startswith('arm') and host_machine.cpu() != 'arm64')
have_as_func = false
have_as_arch = false
aarch64_extensions = {
'dotprod': 'udot v0.4s, v0.16b, v0.16b',
'i8mm': 'usdot v0.4s, v0.16b, v0.16b',
'sve': 'whilelt p0.s, x0, x1',
'sve2': 'sqrdmulh z0.s, z0.s, z0.s',
}
supported_aarch64_archexts = []
supported_aarch64_instructions = []
if (is_asm_enabled and
(host_machine.cpu_family() == 'aarch64' or
host_machine.cpu_family().startswith('arm')))
as_func_code = '''__asm__ (
".func meson_test"
".endfunc"
);
'''
have_as_func = cc.compiles(as_func_code)
# fedora package build infrastructure uses a gcc specs file to enable
# '-fPIE' by default. The chosen way only adds '-fPIE' to the C compiler
# with integrated preprocessor. It is not added to the standalone
# preprocessor or the preprocessing stage of '.S' files. So we have to
# compile code to check if we have to define PIC for the arm asm to
# avoid absolute relocations when building for example checkasm.
check_pic_code = '''
#if defined(PIC)
#error "PIC already defined"
#elif !(defined(__PIC__) || defined(__pic__))
#error "no pic"
#endif
'''
if cc.compiles(check_pic_code)
cdata.set('PIC', '3')
endif
if host_machine.cpu_family() == 'aarch64'
have_as_arch = cc.compiles('''__asm__ (".arch armv8-a");''')
as_arch_str = ''
if have_as_arch
as_arch_level = 'armv8-a'
# Check what .arch levels are supported. In principle, we only
# want to detect up to armv8.2-a here (binutils requires that
# in order to enable i8mm). However, older Clang versions
# (before Clang 17, and Xcode versions up to and including 15.0)
# didn't support controlling dotprod/i8mm extensions via
# .arch_extension, therefore try to enable a high enough .arch
# level as well, to implicitly make them available via that.
foreach arch : ['armv8.2-a', 'armv8.4-a', 'armv8.6-a']
if cc.compiles('__asm__ (".arch ' + arch + '\\n");')
as_arch_level = arch
endif
endforeach
# Clang versions before 17 also had a bug
# (https://github.com/llvm/llvm-project/issues/32220)
# causing a plain ".arch <level>" to not have any effect unless it
# had an extra "+<feature>" included - but it was activated on the
# next ".arch_extension" directive instead. Check if we can include
# "+crc" as dummy feature to make the .arch directive behave as
# expected and take effect right away.
if cc.compiles('__asm__ (".arch ' + as_arch_level + '+crc\\n");')
as_arch_level = as_arch_level + '+crc'
endif
cdata.set('AS_ARCH_LEVEL', as_arch_level)
as_arch_str = '".arch ' + as_arch_level + '\\n"'
endif
if use_gaspp
python3 = import('python').find_installation()
endif
foreach name, instr : aarch64_extensions
if use_gaspp
f = configure_file(
command: [python3, '-c', 'import sys; print(sys.argv[1])', '@0@'.format(instr)],
output: 'test-@0@.S'.format(name),
capture: true)
r = run_command(gaspp, gaspp_args, f, '-c', '-o', meson.current_build_dir() / 'test-' + name + '.obj', check: false)
message('Checking for gaspp/armasm64 ' + name.to_upper() + ': ' + (r.returncode() == 0 ? 'YES' : 'NO'))
if r.returncode() == 0
supported_aarch64_instructions += name
endif
else
# Test for support for the various extensions. First test if
# the assembler supports the .arch_extension directive for
# enabling/disabling the extension, then separately check whether
# the instructions themselves are supported. Even if .arch_extension
# isn't supported, we may be able to assemble the instructions
# if the .arch level includes support for them.
code = '__asm__ (' + as_arch_str
code += '".arch_extension ' + name + '\\n"'
code += ');'
supports_archext = cc.compiles(code)
code = '__asm__ (' + as_arch_str
if supports_archext
supported_aarch64_archexts += name
code += '".arch_extension ' + name + '\\n"'
endif
code += '"' + instr + '\\n"'
code += ');'
if cc.compiles(code, name: name.to_upper())
supported_aarch64_instructions += name
endif
endif
endforeach
endif
endif
cdata.set10('HAVE_AS_FUNC', have_as_func)
cdata.set10('HAVE_AS_ARCH_DIRECTIVE', have_as_arch)
foreach name, _ : aarch64_extensions
cdata.set10('HAVE_AS_ARCHEXT_' + name.to_upper() + '_DIRECTIVE', name in supported_aarch64_archexts)
cdata.set10('HAVE_' + name.to_upper(), name in supported_aarch64_instructions)
endforeach
cdata.set10('ARCH_X86', host_machine.cpu_family().startswith('x86'))
cdata.set10('ARCH_X86_64', host_machine.cpu_family() == 'x86_64')
cdata.set10('ARCH_X86_32', host_machine.cpu_family() == 'x86')
if host_machine.cpu_family().startswith('x86')
cdata_asm.set('private_prefix', 'dav1d')
cdata_asm.set10('ARCH_X86_64', host_machine.cpu_family() == 'x86_64')
cdata_asm.set10('ARCH_X86_32', host_machine.cpu_family() == 'x86')
cdata_asm.set10('PIC', true)
# Convert SSE asm into (128-bit) AVX when compiler flags are set to use AVX instructions
cdata_asm.set10('FORCE_VEX_ENCODING', cc.get_define('__AVX__').strip() != '')
endif
cdata.set10('ARCH_PPC64LE', host_machine.cpu() == 'ppc64le')
cdata.set10('ARCH_RISCV', host_machine.cpu_family().startswith('riscv'))
cdata.set10('ARCH_RV32', host_machine.cpu_family() == 'riscv32')
cdata.set10('ARCH_RV64', host_machine.cpu_family() == 'riscv64')
cdata.set10('ARCH_LOONGARCH', host_machine.cpu_family().startswith('loongarch'))
cdata.set10('ARCH_LOONGARCH32', host_machine.cpu_family() == 'loongarch32')
cdata.set10('ARCH_LOONGARCH64', host_machine.cpu_family() == 'loongarch64')
# meson's cc.symbols_have_underscore_prefix() is unfortunately unrelieably
# when additional flags like '-fprofile-instr-generate' are passed via CFLAGS
# see following meson issue https://github.com/mesonbuild/meson/issues/5482
if (host_machine.system() in ['darwin', 'ios', 'tvos'] or
(host_machine.system() == 'windows' and host_machine.cpu_family() == 'x86'))
cdata.set10('PREFIX', true)
cdata_asm.set10('PREFIX', true)
endif
if is_asm_enabled and host_machine.cpu_family().startswith('x86')
# NASM compiler support
nasm = find_program('nasm')
# check NASM version
if nasm.found()
nasm_r = run_command(nasm, '-v', check: true)
out = nasm_r.stdout().strip().split()
if out[1].to_lower() == 'version'
if out[2].version_compare('<2.14')
error('nasm 2.14 or later is required, found nasm @0@'.format(out[2]))
endif
else
error('unexpected nasm version string: @0@'.format(nasm_r.stdout()))
endif
endif
# Generate config.asm
config_asm_target = configure_file(output: 'config.asm', output_format: 'nasm', configuration: cdata_asm)
if host_machine.system() == 'windows'
nasm_format = 'win'
elif host_machine.system() in ['darwin', 'ios', 'tvos']
nasm_format = 'macho'
else
nasm_format = 'elf'
endif
if host_machine.cpu_family() == 'x86_64'
nasm_format += '64'
else
nasm_format += '32'
endif
nasm_gen = generator(nasm,
output: '@BASENAME@.obj',
depfile: '@BASENAME@.obj.ndep',
arguments: [
'-f', nasm_format,
'-I', '@0@/src/'.format(dav1d_src_root),
'-I', '@0@/'.format(meson.current_build_dir()),
'-MQ', '@OUTPUT@', '-MF', '@DEPFILE@',
'@EXTRA_ARGS@',
'@INPUT@',
'-o', '@OUTPUT@'
])
endif
if is_asm_enabled and host_machine.cpu_family().startswith('riscv')
as_option_code = '''__asm__ (
".option arch, +v\n"
"vsetivli zero, 0, e8, m1, ta, ma"
);
'''
if not cc.compiles(as_option_code, name : 'RISC-V Vector')
error('Compiler doesn\'t support \'.option arch\' asm directive. Update to binutils>=2.38 or clang>=17 or use \'-Denable_asm=false\'.')
endif
endif
# Generate config.h
config_h_target = configure_file(output: 'config.h', configuration: cdata)
#
# Include subdir meson.build files
# The order is important!
subdir('include')
subdir('doc')
subdir('src')
subdir('tools')
subdir('examples')
subdir('tests')

View file

@ -0,0 +1,75 @@
# General options
option('bitdepths',
type: 'array',
choices: ['8', '16'],
description: 'Enable only specified bitdepths')
option('enable_asm',
type: 'boolean',
value: true,
description: 'Build asm files, if available')
option('enable_tools',
type: 'boolean',
value: true,
description: 'Build dav1d cli tools')
option('enable_examples',
type: 'boolean',
value: false,
description: 'Build dav1d examples')
option('enable_tests',
type: 'boolean',
value: true,
description: 'Build dav1d tests')
option('enable_seek_stress',
type: 'boolean',
value: false,
description: 'Build seek_stress test tool')
option('enable_docs',
type: 'boolean',
value: false,
description: 'Build dav1d documentation')
option('logging',
type: 'boolean',
value: true,
description: 'Print error log messages using the provided callback function')
option('testdata_tests',
type: 'boolean',
value: false,
description: 'Run tests requiring the test data repository')
option('fuzzing_engine',
type: 'combo',
choices : ['none', 'libfuzzer', 'oss-fuzz'],
value: 'none',
description: 'Select the fuzzing engine')
option('fuzzer_ldflags',
type: 'string',
description: 'Extra LDFLAGS used during linking of fuzzing binaries')
option('stack_alignment',
type: 'integer',
value: 0)
option('xxhash_muxer',
type : 'feature',
value : 'auto')
option('trim_dsp',
type: 'combo',
choices: ['true', 'false', 'if-release'],
value: 'if-release',
description: 'Eliminate redundant DSP functions where possible')
option('macos_kperf',
type: 'boolean',
value: false,
description: 'Use the private macOS kperf API for benchmarking')

View file

@ -0,0 +1,15 @@
[binaries]
c = 'aarch64-linux-android21-clang'
cpp = 'aarch64-linux-android21-clang++'
ar = 'llvm-ar'
strip = 'llvm-strip'
pkgconfig = 'pkg-config'
[properties]
needs_exe_wrapper = true
[host_machine]
system = 'android'
cpu_family = 'aarch64'
cpu = 'aarch64'
endian = 'little'

View file

@ -0,0 +1,16 @@
[binaries]
c = 'clang'
cpp = 'clang++'
ar = 'aarch64-linux-gnu-ar'
strip = 'aarch64-linux-gnu-strip'
exe_wrapper = 'qemu-aarch64'
[properties]
c_args = '-target aarch64-linux-gnu'
c_link_args = '-target aarch64-linux-gnu'
[host_machine]
system = 'linux'
cpu_family = 'aarch64'
cpu = 'aarch64'
endian = 'little'

View file

@ -0,0 +1,12 @@
[binaries]
c = 'aarch64-linux-gnu-gcc'
cpp = 'aarch64-linux-gnu-g++'
ar = 'aarch64-linux-gnu-ar'
strip = 'aarch64-linux-gnu-strip'
exe_wrapper = 'qemu-aarch64'
[host_machine]
system = 'linux'
cpu_family = 'aarch64'
cpu = 'aarch64'
endian = 'little'

View file

@ -0,0 +1,16 @@
[binaries]
c = 'aarch64-w64-mingw32-clang'
cpp = 'aarch64-w64-mingw32-clang++'
ar = 'aarch64-w64-mingw32-ar'
strip = 'aarch64-w64-mingw32-strip'
pkgconfig = 'pkg-config'
windres = 'aarch64-w64-mingw32-windres'
[properties]
c_link_args = ['-static-libgcc']
[host_machine]
system = 'windows'
cpu_family = 'aarch64'
cpu = 'aarch64'
endian = 'little'

View file

@ -0,0 +1,15 @@
[binaries]
c = 'armv7a-linux-androideabi21-clang'
cpp = 'armv7a-linux-androideabi21-clang++'
ar = 'llvm-ar'
strip = 'llvm-strip'
pkgconfig = 'pkg-config'
[properties]
needs_exe_wrapper = true
[host_machine]
system = 'android'
cpu_family = 'arm'
cpu = 'arm'
endian = 'little'

View file

@ -0,0 +1,27 @@
[binaries]
c = ['clang', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk']
cpp = ['clang++', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk']
objc = ['clang', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk']
objcpp = ['clang++', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk']
ar = 'ar'
strip = 'strip'
[built-in options]
c_args = ['-miphoneos-version-min=11.0']
cpp_args = ['-miphoneos-version-min=11.0']
c_link_args = ['-miphoneos-version-min=11.0']
cpp_link_args = ['-miphoneos-version-min=11.0']
objc_args = ['-miphoneos-version-min=11.0']
objcpp_args = ['-miphoneos-version-min=11.0']
[properties]
root = '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer'
needs_exe_wrapper = true
[host_machine]
system = 'darwin'
subsystem = 'ios'
kernel = 'xnu'
cpu_family = 'aarch64'
cpu = 'aarch64'
endian = 'little'

View file

@ -0,0 +1,16 @@
[binaries]
c = 'armv7-w64-mingw32-clang'
cpp = 'armv7-w64-mingw32-clang++'
ar = 'armv7-w64-mingw32-ar'
strip = 'armv7-w64-mingw32-strip'
pkgconfig = 'pkg-config'
windres = 'armv7-w64-mingw32-windres'
[properties]
c_link_args = ['-static-libgcc']
[host_machine]
system = 'windows'
cpu_family = 'arm'
cpu = 'armv7'
endian = 'little'

View file

@ -0,0 +1,15 @@
[binaries]
c = 'gcc'
cpp = 'g++'
ar = 'ar'
strip = 'strip'
[properties]
c_link_args = ['-m32', '-Wl,-z,text']
c_args = ['-m32']
[host_machine]
system = 'linux'
cpu_family = 'x86'
cpu = 'i686'
endian = 'little'

View file

@ -0,0 +1,16 @@
[binaries]
c = 'i686-w64-mingw32-gcc'
cpp = 'i686-w64-mingw32-g++'
ar = 'i686-w64-mingw32-ar'
strip = 'i686-w64-mingw32-strip'
windres = 'i686-w64-mingw32-windres'
exe_wrapper = 'wine'
[properties]
c_link_args = ['-static-libgcc']
[host_machine]
system = 'windows'
cpu_family = 'x86'
cpu = 'i686'
endian = 'little'

View file

@ -0,0 +1,13 @@
[binaries]
c = 'loongarch64-unknown-linux-gnu-gcc'
cpp = 'loongarch64-unknown-linux-gnu-c++'
ar = 'loongarch64-unknown-linux-gnu-ar'
strip = 'loongarch64-unknown-linux-gnu-strip'
pkgconfig = 'pkg-config'
exe_wrapper = 'qemu-loongarch64'
[host_machine]
system = 'linux'
cpu_family = 'loongarch64'
cpu = 'loongarch64'
endian = 'little'

View file

@ -0,0 +1,16 @@
[binaries]
c = 'clang'
cpp = 'clang++'
ar = 'riscv64-linux-gnu-ar'
strip = 'riscv64-linux-gnu-strip'
exe_wrapper = 'qemu-riscv64'
[properties]
c_args = '-target riscv64-linux-gnu'
c_link_args = '-target riscv64-linux-gnu'
[host_machine]
system = 'linux'
cpu_family = 'riscv64'
cpu = 'riscv64'
endian = 'little'

View file

@ -0,0 +1,12 @@
[binaries]
c = 'riscv64-linux-gnu-gcc'
cpp = 'riscv64-linux-gnu-g++'
ar = 'riscv64-linux-gnu-ar'
strip = 'riscv64-linux-gnu-strip'
exe_wrapper = 'qemu-riscv64'
[host_machine]
system = 'linux'
cpu_family = 'riscv64'
cpu = 'riscv64'
endian = 'little'

View file

@ -0,0 +1,15 @@
[binaries]
c = 'emcc'
cpp = 'em++'
ar = 'emar'
strip = 'emstrip'
exe_wrapper = 'node'
[properties]
c_link_args = ['-sEXPORT_ALL=1']
[host_machine]
system = 'emscripten'
cpu_family = 'wasm32'
cpu = 'wasm32'
endian = 'little'

View file

@ -0,0 +1,15 @@
[binaries]
c = 'emcc'
cpp = 'em++'
ar = 'emar'
strip = 'emstrip'
exe_wrapper = 'node'
[properties]
c_link_args = ['-sEXPORT_ALL=1']
[host_machine]
system = 'emscripten'
cpu_family = 'wasm64'
cpu = 'wasm64'
endian = 'little'

View file

@ -0,0 +1,15 @@
[binaries]
c = 'i686-linux-android19-clang'
cpp = 'i686-linux-android19-clang++'
ar = 'llvm-ar'
strip = 'llvm-strip'
pkgconfig = 'pkg-config'
[properties]
needs_exe_wrapper = true
[host_machine]
system = 'android'
cpu_family = 'x86'
cpu = 'i686'
endian = 'little'

View file

@ -0,0 +1,15 @@
[binaries]
c = 'x86_64-linux-android21-clang'
cpp = 'x86_64-linux-android21-clang++'
ar = 'llvm-ar'
strip = 'llvm-strip'
pkgconfig = 'pkg-config'
[properties]
needs_exe_wrapper = true
[host_machine]
system = 'android'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'

View file

@ -0,0 +1,27 @@
[binaries]
c = ['clang', '-arch', 'x86_64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk']
cpp = ['clang++', '-arch', 'x86_64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk']
objc = ['clang', '-arch', 'x86_64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk']
objcpp = ['clang++', '-arch', 'x86_64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk']
ar = 'ar'
strip = 'strip'
[built-in options]
c_args = ['-miphoneos-version-min=11.0']
cpp_args = ['-miphoneos-version-min=11.0']
c_link_args = ['-miphoneos-version-min=11.0']
cpp_link_args = ['-miphoneos-version-min=11.0']
objc_args = ['-miphoneos-version-min=11.0']
objcpp_args = ['-miphoneos-version-min=11.0']
[properties]
root = '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer'
needs_exe_wrapper = true
[host_machine]
system = 'darwin'
subsystem = 'ios-simulator'
kernel = 'xnu'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'

View file

@ -0,0 +1,16 @@
[binaries]
c = 'x86_64-w64-mingw32-gcc'
cpp = 'x86_64-w64-mingw32-g++'
ar = 'x86_64-w64-mingw32-ar'
strip = 'x86_64-w64-mingw32-strip'
windres = 'x86_64-w64-mingw32-windres'
exe_wrapper = 'wine'
[properties]
c_link_args = ['-static-libgcc']
[host_machine]
system = 'windows'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'

View file

@ -0,0 +1,24 @@
name: dav1d
base: core18
version: git
version-script: git describe HEAD --always
summary: AV1 decoder from VideoLAN
description: |
A small and fast AV1 decoder from the people who brought you VLC.
grade: stable
confinement: strict # use 'strict' once you have the right plugs and slots
apps:
dav1d:
command: usr/bin/dav1d
plugs: [ 'home' ]
parts:
dav1d:
plugin: meson
source: ../../
build-packages: [ 'nasm' ]
meson-parameters:
- --prefix=/usr
- --buildtype=release

View file

@ -0,0 +1,540 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2019, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "src/arm/asm.S"
#include "util.S"
#include "cdef_tmpl.S"
// n1 = s0/d0
// w1 = d0/q0
// n2 = s4/d2
// w2 = d2/q1
.macro pad_top_bottom s1, s2, w, stride, n1, w1, n2, w2, align, ret
tst r7, #1 // CDEF_HAVE_LEFT
beq 2f
// CDEF_HAVE_LEFT
tst r7, #2 // CDEF_HAVE_RIGHT
beq 1f
// CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
ldrh r12, [\s1, #-2]
vldr \n1, [\s1]
vdup.16 d4, r12
ldrh r12, [\s1, #\w]
vmov.16 d4[1], r12
ldrh r12, [\s2, #-2]
vldr \n2, [\s2]
vmov.16 d4[2], r12
ldrh r12, [\s2, #\w]
vmovl.u8 q0, d0
vmov.16 d4[3], r12
vmovl.u8 q1, d2
vmovl.u8 q2, d4
vstr s8, [r0, #-4]
vst1.16 {\w1}, [r0, :\align]
vstr s9, [r0, #2*\w]
add r0, r0, #2*\stride
vstr s10, [r0, #-4]
vst1.16 {\w2}, [r0, :\align]
vstr s11, [r0, #2*\w]
.if \ret
pop {r4-r8,pc}
.else
add r0, r0, #2*\stride
b 3f
.endif
1:
// CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
ldrh r12, [\s1, #-2]
vldr \n1, [\s1]
vdup.16 d4, r12
ldrh r12, [\s2, #-2]
vldr \n2, [\s2]
vmovl.u8 q0, d0
vmov.16 d4[1], r12
vmovl.u8 q1, d2
vmovl.u8 q2, d4
vstr s8, [r0, #-4]
vst1.16 {\w1}, [r0, :\align]
vstr s12, [r0, #2*\w]
add r0, r0, #2*\stride
vstr s9, [r0, #-4]
vst1.16 {\w2}, [r0, :\align]
vstr s12, [r0, #2*\w]
.if \ret
pop {r4-r8,pc}
.else
add r0, r0, #2*\stride
b 3f
.endif
2:
// !CDEF_HAVE_LEFT
tst r7, #2 // CDEF_HAVE_RIGHT
beq 1f
// !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
vldr \n1, [\s1]
ldrh r12, [\s1, #\w]
vldr \n2, [\s2]
vdup.16 d4, r12
ldrh r12, [\s2, #\w]
vmovl.u8 q0, d0
vmov.16 d4[1], r12
vmovl.u8 q1, d2
vmovl.u8 q2, d4
vstr s12, [r0, #-4]
vst1.16 {\w1}, [r0, :\align]
vstr s8, [r0, #2*\w]
add r0, r0, #2*\stride
vstr s12, [r0, #-4]
vst1.16 {\w2}, [r0, :\align]
vstr s9, [r0, #2*\w]
.if \ret
pop {r4-r8,pc}
.else
add r0, r0, #2*\stride
b 3f
.endif
1:
// !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
vldr \n1, [\s1]
vldr \n2, [\s2]
vmovl.u8 q0, d0
vmovl.u8 q1, d2
vstr s12, [r0, #-4]
vst1.16 {\w1}, [r0, :\align]
vstr s12, [r0, #2*\w]
add r0, r0, #2*\stride
vstr s12, [r0, #-4]
vst1.16 {\w2}, [r0, :\align]
vstr s12, [r0, #2*\w]
.if \ret
pop {r4-r8,pc}
.else
add r0, r0, #2*\stride
.endif
3:
.endm
.macro load_n_incr dst, src, incr, w
.if \w == 4
vld1.32 {\dst\()[0]}, [\src, :32], \incr
.else
vld1.8 {\dst\()}, [\src, :64], \incr
.endif
.endm
// void dav1d_cdef_paddingX_8bpc_neon(uint16_t *tmp, const pixel *src,
// ptrdiff_t src_stride, const pixel (*left)[2],
// const pixel *const top,
// const pixel *const bottom, int h,
// enum CdefEdgeFlags edges);
// n1 = s0/d0
// w1 = d0/q0
// n2 = s4/d2
// w2 = d2/q1
.macro padding_func w, stride, n1, w1, n2, w2, align
function cdef_padding\w\()_8bpc_neon, export=1
push {r4-r8,lr}
ldrd r4, r5, [sp, #24]
ldrd r6, r7, [sp, #32]
cmp r7, #0xf // fully edged
beq cdef_padding\w\()_edged_8bpc_neon
vmov.i16 q3, #0x8000
tst r7, #4 // CDEF_HAVE_TOP
bne 1f
// !CDEF_HAVE_TOP
sub r12, r0, #2*(2*\stride+2)
vmov.i16 q2, #0x8000
vst1.16 {q2,q3}, [r12]!
.if \w == 8
vst1.16 {q2,q3}, [r12]!
.endif
b 3f
1:
// CDEF_HAVE_TOP
add r8, r4, r2
sub r0, r0, #2*(2*\stride)
pad_top_bottom r4, r8, \w, \stride, \n1, \w1, \n2, \w2, \align, 0
// Middle section
3:
tst r7, #1 // CDEF_HAVE_LEFT
beq 2f
// CDEF_HAVE_LEFT
tst r7, #2 // CDEF_HAVE_RIGHT
beq 1f
// CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
0:
vld1.16 {d2[]}, [r3, :16]!
ldrh r12, [r1, #\w]
load_n_incr d0, r1, r2, \w
subs r6, r6, #1
vmov.16 d2[1], r12
vmovl.u8 q0, d0
vmovl.u8 q1, d2
vstr s4, [r0, #-4]
vst1.16 {\w1}, [r0, :\align]
vstr s5, [r0, #2*\w]
add r0, r0, #2*\stride
bgt 0b
b 3f
1:
// CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
vld1.16 {d2[]}, [r3, :16]!
load_n_incr d0, r1, r2, \w
subs r6, r6, #1
vmovl.u8 q0, d0
vmovl.u8 q1, d2
vstr s4, [r0, #-4]
vst1.16 {\w1}, [r0, :\align]
vstr s12, [r0, #2*\w]
add r0, r0, #2*\stride
bgt 1b
b 3f
2:
tst r7, #2 // CDEF_HAVE_RIGHT
beq 1f
// !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
0:
ldrh r12, [r1, #\w]
load_n_incr d0, r1, r2, \w
vdup.16 d2, r12
subs r6, r6, #1
vmovl.u8 q0, d0
vmovl.u8 q1, d2
vstr s12, [r0, #-4]
vst1.16 {\w1}, [r0, :\align]
vstr s4, [r0, #2*\w]
add r0, r0, #2*\stride
bgt 0b
b 3f
1:
// !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
load_n_incr d0, r1, r2, \w
subs r6, r6, #1
vmovl.u8 q0, d0
vstr s12, [r0, #-4]
vst1.16 {\w1}, [r0, :\align]
vstr s12, [r0, #2*\w]
add r0, r0, #2*\stride
bgt 1b
3:
tst r7, #8 // CDEF_HAVE_BOTTOM
bne 1f
// !CDEF_HAVE_BOTTOM
sub r12, r0, #4
vmov.i16 q2, #0x8000
vst1.16 {q2,q3}, [r12]!
.if \w == 8
vst1.16 {q2,q3}, [r12]!
.endif
pop {r4-r8,pc}
1:
// CDEF_HAVE_BOTTOM
add r8, r5, r2
pad_top_bottom r5, r8, \w, \stride, \n1, \w1, \n2, \w2, \align, 1
endfunc
.endm
padding_func 8, 16, d0, q0, d2, q1, 128
padding_func 4, 8, s0, d0, s4, d2, 64
// void cdef_paddingX_edged_8bpc_neon(uint16_t *tmp, const pixel *src,
// ptrdiff_t src_stride, const pixel (*left)[2],
// const pixel *const top,
// const pixel *const bottom, int h,
// enum CdefEdgeFlags edges);
.macro padding_func_edged w, stride, reg, align
function cdef_padding\w\()_edged_8bpc_neon
sub r0, r0, #(2*\stride)
ldrh r12, [r4, #-2]
vldr \reg, [r4]
add r8, r4, r2
strh r12, [r0, #-2]
ldrh r12, [r4, #\w]
vstr \reg, [r0]
strh r12, [r0, #\w]
ldrh r12, [r8, #-2]
vldr \reg, [r8]
strh r12, [r0, #\stride-2]
ldrh r12, [r8, #\w]
vstr \reg, [r0, #\stride]
strh r12, [r0, #\stride+\w]
add r0, r0, #2*\stride
0:
ldrh r12, [r3], #2
vldr \reg, [r1]
str r12, [r0, #-2]
ldrh r12, [r1, #\w]
add r1, r1, r2
subs r6, r6, #1
vstr \reg, [r0]
str r12, [r0, #\w]
add r0, r0, #\stride
bgt 0b
ldrh r12, [r5, #-2]
vldr \reg, [r5]
add r8, r5, r2
strh r12, [r0, #-2]
ldrh r12, [r5, #\w]
vstr \reg, [r0]
strh r12, [r0, #\w]
ldrh r12, [r8, #-2]
vldr \reg, [r8]
strh r12, [r0, #\stride-2]
ldrh r12, [r8, #\w]
vstr \reg, [r0, #\stride]
strh r12, [r0, #\stride+\w]
pop {r4-r8,pc}
endfunc
.endm
padding_func_edged 8, 16, d0, 64
padding_func_edged 4, 8, s0, 32
tables
filter 8, 8
filter 4, 8
find_dir 8
.macro load_px_8 d11, d12, d21, d22, w
.if \w == 8
add r6, r2, r9 // x + off
sub r9, r2, r9 // x - off
vld1.8 {\d11}, [r6] // p0
add r6, r6, #16 // += stride
vld1.8 {\d21}, [r9] // p1
add r9, r9, #16 // += stride
vld1.8 {\d12}, [r6] // p0
vld1.8 {\d22}, [r9] // p1
.else
add r6, r2, r9 // x + off
sub r9, r2, r9 // x - off
vld1.32 {\d11[0]}, [r6] // p0
add r6, r6, #8 // += stride
vld1.32 {\d21[0]}, [r9] // p1
add r9, r9, #8 // += stride
vld1.32 {\d11[1]}, [r6] // p0
add r6, r6, #8 // += stride
vld1.32 {\d21[1]}, [r9] // p1
add r9, r9, #8 // += stride
vld1.32 {\d12[0]}, [r6] // p0
add r6, r6, #8 // += stride
vld1.32 {\d22[0]}, [r9] // p1
add r9, r9, #8 // += stride
vld1.32 {\d12[1]}, [r6] // p0
vld1.32 {\d22[1]}, [r9] // p1
.endif
.endm
.macro handle_pixel_8 s1, s2, thresh_vec, shift, tap, min
.if \min
vmin.u8 q3, q3, \s1
vmax.u8 q4, q4, \s1
vmin.u8 q3, q3, \s2
vmax.u8 q4, q4, \s2
.endif
vabd.u8 q8, q0, \s1 // abs(diff)
vabd.u8 q11, q0, \s2 // abs(diff)
vshl.u8 q9, q8, \shift // abs(diff) >> shift
vshl.u8 q12, q11, \shift // abs(diff) >> shift
vqsub.u8 q9, \thresh_vec, q9 // clip = imax(0, threshold - (abs(diff) >> shift))
vqsub.u8 q12, \thresh_vec, q12// clip = imax(0, threshold - (abs(diff) >> shift))
vcgt.u8 q10, q0, \s1 // px > p0
vcgt.u8 q13, q0, \s2 // px > p1
vmin.u8 q9, q9, q8 // imin(abs(diff), clip)
vmin.u8 q12, q12, q11 // imin(abs(diff), clip)
vneg.s8 q8, q9 // -imin()
vneg.s8 q11, q12 // -imin()
vbsl q10, q8, q9 // constrain() = imax(imin(diff, clip), -clip)
vdup.8 d18, \tap // taps[k]
vbsl q13, q11, q12 // constrain() = imax(imin(diff, clip), -clip)
vmlal.s8 q1, d20, d18 // sum += taps[k] * constrain()
vmlal.s8 q1, d26, d18 // sum += taps[k] * constrain()
vmlal.s8 q2, d21, d18 // sum += taps[k] * constrain()
vmlal.s8 q2, d27, d18 // sum += taps[k] * constrain()
.endm
// void cdef_filterX_edged_neon(pixel *dst, ptrdiff_t dst_stride,
// const uint16_t *tmp, int pri_strength,
// int sec_strength, int dir, int damping,
// int h, size_t edges);
.macro filter_func_8 w, pri, sec, min, suffix
function cdef_filter\w\suffix\()_edged_neon
.if \pri
movrel_local r8, pri_taps
and r9, r3, #1
add r8, r8, r9, lsl #1
.endif
movrel_local r9, directions\w
add r5, r9, r5, lsl #1
vmov.u8 d17, #7
vdup.8 d16, r6 // damping
vmov.8 d8[0], r3
vmov.8 d8[1], r4
vclz.i8 d8, d8 // clz(threshold)
vsub.i8 d8, d17, d8 // ulog2(threshold)
vqsub.u8 d8, d16, d8 // shift = imax(0, damping - ulog2(threshold))
vneg.s8 d8, d8 // -shift
.if \sec
vdup.8 q6, d8[1]
.endif
.if \pri
vdup.8 q5, d8[0]
.endif
1:
.if \w == 8
add r12, r2, #16
vld1.8 {d0}, [r2, :64] // px
vld1.8 {d1}, [r12, :64] // px
.else
add r12, r2, #8
vld1.32 {d0[0]}, [r2, :32] // px
add r9, r2, #2*8
vld1.32 {d0[1]}, [r12, :32] // px
add r12, r12, #2*8
vld1.32 {d1[0]}, [r9, :32] // px
vld1.32 {d1[1]}, [r12, :32] // px
.endif
vmov.u8 q1, #0 // sum
vmov.u8 q2, #0 // sum
.if \min
vmov.u16 q3, q0 // min
vmov.u16 q4, q0 // max
.endif
// Instead of loading sec_taps 2, 1 from memory, just set it
// to 2 initially and decrease for the second round.
// This is also used as loop counter.
mov lr, #2 // sec_taps[0]
2:
.if \pri
ldrsb r9, [r5] // off1
load_px_8 d28, d29, d30, d31, \w
.endif
.if \sec
add r5, r5, #4 // +2*2
ldrsb r9, [r5] // off2
.endif
.if \pri
ldrb r12, [r8] // *pri_taps
vdup.8 q7, r3 // threshold
handle_pixel_8 q14, q15, q7, q5, r12, \min
.endif
.if \sec
load_px_8 d28, d29, d30, d31, \w
add r5, r5, #8 // +2*4
ldrsb r9, [r5] // off3
vdup.8 q7, r4 // threshold
handle_pixel_8 q14, q15, q7, q6, lr, \min
load_px_8 d28, d29, d30, d31, \w
handle_pixel_8 q14, q15, q7, q6, lr, \min
sub r5, r5, #11 // r5 -= 2*(2+4); r5 += 1;
.else
add r5, r5, #1 // r5 += 1
.endif
subs lr, lr, #1 // sec_tap-- (value)
.if \pri
add r8, r8, #1 // pri_taps++ (pointer)
.endif
bne 2b
vshr.s16 q14, q1, #15 // -(sum < 0)
vshr.s16 q15, q2, #15 // -(sum < 0)
vadd.i16 q1, q1, q14 // sum - (sum < 0)
vadd.i16 q2, q2, q15 // sum - (sum < 0)
vrshr.s16 q1, q1, #4 // (8 + sum - (sum < 0)) >> 4
vrshr.s16 q2, q2, #4 // (8 + sum - (sum < 0)) >> 4
vaddw.u8 q1, q1, d0 // px + (8 + sum ...) >> 4
vaddw.u8 q2, q2, d1 // px + (8 + sum ...) >> 4
vqmovun.s16 d0, q1
vqmovun.s16 d1, q2
.if \min
vmin.u8 q0, q0, q4
vmax.u8 q0, q0, q3 // iclip(px + .., min, max)
.endif
.if \w == 8
vst1.8 {d0}, [r0, :64], r1
add r2, r2, #2*16 // tmp += 2*tmp_stride
subs r7, r7, #2 // h -= 2
vst1.8 {d1}, [r0, :64], r1
.else
vst1.32 {d0[0]}, [r0, :32], r1
add r2, r2, #4*8 // tmp += 4*tmp_stride
vst1.32 {d0[1]}, [r0, :32], r1
subs r7, r7, #4 // h -= 4
vst1.32 {d1[0]}, [r0, :32], r1
vst1.32 {d1[1]}, [r0, :32], r1
.endif
// Reset pri_taps and directions back to the original point
sub r5, r5, #2
.if \pri
sub r8, r8, #2
.endif
bgt 1b
vpop {q4-q7}
pop {r4-r9,pc}
endfunc
.endm
.macro filter_8 w
filter_func_8 \w, pri=1, sec=0, min=0, suffix=_pri
filter_func_8 \w, pri=0, sec=1, min=0, suffix=_sec
filter_func_8 \w, pri=1, sec=1, min=1, suffix=_pri_sec
.endm
filter_8 8
filter_8 4

View file

@ -0,0 +1,233 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2020, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "src/arm/asm.S"
#include "util.S"
#include "cdef_tmpl.S"
// r1 = d0/q0
// r2 = d2/q1
.macro pad_top_bot_16 s1, s2, w, stride, r1, r2, align, ret
tst r7, #1 // CDEF_HAVE_LEFT
beq 2f
// CDEF_HAVE_LEFT
tst r7, #2 // CDEF_HAVE_RIGHT
beq 1f
// CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
vldr s8, [\s1, #-4]
vld1.16 {\r1}, [\s1, :\align]
vldr s9, [\s1, #2*\w]
vldr s10, [\s2, #-4]
vld1.16 {\r2}, [\s2, :\align]
vldr s11, [\s2, #2*\w]
vstr s8, [r0, #-4]
vst1.16 {\r1}, [r0, :\align]
vstr s9, [r0, #2*\w]
add r0, r0, #2*\stride
vstr s10, [r0, #-4]
vst1.16 {\r2}, [r0, :\align]
vstr s11, [r0, #2*\w]
.if \ret
pop {r4-r8,pc}
.else
add r0, r0, #2*\stride
b 3f
.endif
1:
// CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
vldr s8, [\s1, #-4]
vld1.16 {\r1}, [\s1, :\align]
vldr s9, [\s2, #-4]
vld1.16 {\r2}, [\s2, :\align]
vstr s8, [r0, #-4]
vst1.16 {\r1}, [r0, :\align]
vstr s12, [r0, #2*\w]
add r0, r0, #2*\stride
vstr s9, [r0, #-4]
vst1.16 {\r2}, [r0, :\align]
vstr s12, [r0, #2*\w]
.if \ret
pop {r4-r8,pc}
.else
add r0, r0, #2*\stride
b 3f
.endif
2:
// !CDEF_HAVE_LEFT
tst r7, #2 // CDEF_HAVE_RIGHT
beq 1f
// !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
vld1.16 {\r1}, [\s1, :\align]
vldr s8, [\s1, #2*\w]
vld1.16 {\r2}, [\s2, :\align]
vldr s9, [\s2, #2*\w]
vstr s12, [r0, #-4]
vst1.16 {\r1}, [r0, :\align]
vstr s8, [r0, #2*\w]
add r0, r0, #2*\stride
vstr s12, [r0, #-4]
vst1.16 {\r2}, [r0, :\align]
vstr s9, [r0, #2*\w]
.if \ret
pop {r4-r8,pc}
.else
add r0, r0, #2*\stride
b 3f
.endif
1:
// !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
vld1.16 {\r1}, [\s1, :\align]
vld1.16 {\r2}, [\s2, :\align]
vstr s12, [r0, #-4]
vst1.16 {\r1}, [r0, :\align]
vstr s12, [r0, #2*\w]
add r0, r0, #2*\stride
vstr s12, [r0, #-4]
vst1.16 {\r2}, [r0, :\align]
vstr s12, [r0, #2*\w]
.if \ret
pop {r4-r8,pc}
.else
add r0, r0, #2*\stride
.endif
3:
.endm
// void dav1d_cdef_paddingX_16bpc_neon(uint16_t *tmp, const pixel *src,
// ptrdiff_t src_stride, const pixel (*left)[2],
// const pixel *const top,
// const pixel *const bottom, int h,
// enum CdefEdgeFlags edges);
// r1 = d0/q0
// r2 = d2/q1
.macro padding_func_16 w, stride, r1, r2, align
function cdef_padding\w\()_16bpc_neon, export=1
push {r4-r8,lr}
ldrd r4, r5, [sp, #24]
ldrd r6, r7, [sp, #32]
vmov.i16 q3, #0x8000
tst r7, #4 // CDEF_HAVE_TOP
bne 1f
// !CDEF_HAVE_TOP
sub r12, r0, #2*(2*\stride+2)
vmov.i16 q2, #0x8000
vst1.16 {q2,q3}, [r12]!
.if \w == 8
vst1.16 {q2,q3}, [r12]!
.endif
b 3f
1:
// CDEF_HAVE_TOP
add r8, r4, r2
sub r0, r0, #2*(2*\stride)
pad_top_bot_16 r4, r8, \w, \stride, \r1, \r2, \align, 0
// Middle section
3:
tst r7, #1 // CDEF_HAVE_LEFT
beq 2f
// CDEF_HAVE_LEFT
tst r7, #2 // CDEF_HAVE_RIGHT
beq 1f
// CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
0:
vld1.32 {d2[]}, [r3, :32]!
vldr s5, [r1, #2*\w]
vld1.16 {\r1}, [r1, :\align], r2
subs r6, r6, #1
vstr s4, [r0, #-4]
vst1.16 {\r1}, [r0, :\align]
vstr s5, [r0, #2*\w]
add r0, r0, #2*\stride
bgt 0b
b 3f
1:
// CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
vld1.32 {d2[]}, [r3, :32]!
vld1.16 {\r1}, [r1, :\align], r2
subs r6, r6, #1
vstr s4, [r0, #-4]
vst1.16 {\r1}, [r0, :\align]
vstr s12, [r0, #2*\w]
add r0, r0, #2*\stride
bgt 1b
b 3f
2:
tst r7, #2 // CDEF_HAVE_RIGHT
beq 1f
// !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
0:
vldr s4, [r1, #2*\w]
vld1.16 {\r1}, [r1, :\align], r2
subs r6, r6, #1
vstr s12, [r0, #-4]
vst1.16 {\r1}, [r0, :\align]
vstr s4, [r0, #2*\w]
add r0, r0, #2*\stride
bgt 0b
b 3f
1:
// !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
vld1.16 {\r1}, [r1, :\align], r2
subs r6, r6, #1
vstr s12, [r0, #-4]
vst1.16 {\r1}, [r0, :\align]
vstr s12, [r0, #2*\w]
add r0, r0, #2*\stride
bgt 1b
3:
tst r7, #8 // CDEF_HAVE_BOTTOM
bne 1f
// !CDEF_HAVE_BOTTOM
sub r12, r0, #4
vmov.i16 q2, #0x8000
vst1.16 {q2,q3}, [r12]!
.if \w == 8
vst1.16 {q2,q3}, [r12]!
.endif
pop {r4-r8,pc}
1:
// CDEF_HAVE_BOTTOM
add r8, r5, r2
pad_top_bot_16 r5, r8, \w, \stride, \r1, \r2, \align, 1
endfunc
.endm
padding_func_16 8, 16, q0, q1, 128
padding_func_16 4, 8, d0, d2, 64
tables
filter 8, 16
filter 4, 16
find_dir 16

View file

@ -0,0 +1,515 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2020, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "src/arm/asm.S"
#include "util.S"
.macro dir_table w, stride
const directions\w
.byte -1 * \stride + 1, -2 * \stride + 2
.byte 0 * \stride + 1, -1 * \stride + 2
.byte 0 * \stride + 1, 0 * \stride + 2
.byte 0 * \stride + 1, 1 * \stride + 2
.byte 1 * \stride + 1, 2 * \stride + 2
.byte 1 * \stride + 0, 2 * \stride + 1
.byte 1 * \stride + 0, 2 * \stride + 0
.byte 1 * \stride + 0, 2 * \stride - 1
// Repeated, to avoid & 7
.byte -1 * \stride + 1, -2 * \stride + 2
.byte 0 * \stride + 1, -1 * \stride + 2
.byte 0 * \stride + 1, 0 * \stride + 2
.byte 0 * \stride + 1, 1 * \stride + 2
.byte 1 * \stride + 1, 2 * \stride + 2
.byte 1 * \stride + 0, 2 * \stride + 1
endconst
.endm
.macro tables
dir_table 8, 16
dir_table 4, 8
const pri_taps
.byte 4, 2, 3, 3
endconst
.endm
.macro load_px d11, d12, d21, d22, w
.if \w == 8
add r6, r2, r9, lsl #1 // x + off
sub r9, r2, r9, lsl #1 // x - off
vld1.16 {\d11,\d12}, [r6] // p0
vld1.16 {\d21,\d22}, [r9] // p1
.else
add r6, r2, r9, lsl #1 // x + off
sub r9, r2, r9, lsl #1 // x - off
vld1.16 {\d11}, [r6] // p0
add r6, r6, #2*8 // += stride
vld1.16 {\d21}, [r9] // p1
add r9, r9, #2*8 // += stride
vld1.16 {\d12}, [r6] // p0
vld1.16 {\d22}, [r9] // p1
.endif
.endm
.macro handle_pixel s1, s2, thresh_vec, shift, tap, min
.if \min
vmin.u16 q2, q2, \s1
vmax.s16 q3, q3, \s1
vmin.u16 q2, q2, \s2
vmax.s16 q3, q3, \s2
.endif
vabd.u16 q8, q0, \s1 // abs(diff)
vabd.u16 q11, q0, \s2 // abs(diff)
vshl.u16 q9, q8, \shift // abs(diff) >> shift
vshl.u16 q12, q11, \shift // abs(diff) >> shift
vqsub.u16 q9, \thresh_vec, q9 // clip = imax(0, threshold - (abs(diff) >> shift))
vqsub.u16 q12, \thresh_vec, q12// clip = imax(0, threshold - (abs(diff) >> shift))
vsub.i16 q10, \s1, q0 // diff = p0 - px
vsub.i16 q13, \s2, q0 // diff = p1 - px
vneg.s16 q8, q9 // -clip
vneg.s16 q11, q12 // -clip
vmin.s16 q10, q10, q9 // imin(diff, clip)
vmin.s16 q13, q13, q12 // imin(diff, clip)
vdup.16 q9, \tap // taps[k]
vmax.s16 q10, q10, q8 // constrain() = imax(imin(diff, clip), -clip)
vmax.s16 q13, q13, q11 // constrain() = imax(imin(diff, clip), -clip)
vmla.i16 q1, q10, q9 // sum += taps[k] * constrain()
vmla.i16 q1, q13, q9 // sum += taps[k] * constrain()
.endm
// void dav1d_cdef_filterX_Ybpc_neon(pixel *dst, ptrdiff_t dst_stride,
// const uint16_t *tmp, int pri_strength,
// int sec_strength, int dir, int damping,
// int h, size_t edges);
.macro filter_func w, bpc, pri, sec, min, suffix
function cdef_filter\w\suffix\()_\bpc\()bpc_neon
.if \bpc == 8
cmp r8, #0xf
beq cdef_filter\w\suffix\()_edged_neon
.endif
.if \pri
.if \bpc == 16
clz r9, r9
sub r9, r9, #24 // -bitdepth_min_8
neg r9, r9 // bitdepth_min_8
.endif
movrel_local r8, pri_taps
.if \bpc == 16
lsr r9, r3, r9 // pri_strength >> bitdepth_min_8
and r9, r9, #1 // (pri_strength >> bitdepth_min_8) & 1
.else
and r9, r3, #1
.endif
add r8, r8, r9, lsl #1
.endif
movrel_local r9, directions\w
add r5, r9, r5, lsl #1
vmov.u16 d17, #15
vdup.16 d16, r6 // damping
.if \pri
vdup.16 q5, r3 // threshold
.endif
.if \sec
vdup.16 q7, r4 // threshold
.endif
vmov.16 d8[0], r3
vmov.16 d8[1], r4
vclz.i16 d8, d8 // clz(threshold)
vsub.i16 d8, d17, d8 // ulog2(threshold)
vqsub.u16 d8, d16, d8 // shift = imax(0, damping - ulog2(threshold))
vneg.s16 d8, d8 // -shift
.if \sec
vdup.16 q6, d8[1]
.endif
.if \pri
vdup.16 q4, d8[0]
.endif
1:
.if \w == 8
vld1.16 {q0}, [r2, :128] // px
.else
add r12, r2, #2*8
vld1.16 {d0}, [r2, :64] // px
vld1.16 {d1}, [r12, :64] // px
.endif
vmov.u16 q1, #0 // sum
.if \min
vmov.u16 q2, q0 // min
vmov.u16 q3, q0 // max
.endif
// Instead of loading sec_taps 2, 1 from memory, just set it
// to 2 initially and decrease for the second round.
// This is also used as loop counter.
mov lr, #2 // sec_taps[0]
2:
.if \pri
ldrsb r9, [r5] // off1
load_px d28, d29, d30, d31, \w
.endif
.if \sec
add r5, r5, #4 // +2*2
ldrsb r9, [r5] // off2
.endif
.if \pri
ldrb r12, [r8] // *pri_taps
handle_pixel q14, q15, q5, q4, r12, \min
.endif
.if \sec
load_px d28, d29, d30, d31, \w
add r5, r5, #8 // +2*4
ldrsb r9, [r5] // off3
handle_pixel q14, q15, q7, q6, lr, \min
load_px d28, d29, d30, d31, \w
handle_pixel q14, q15, q7, q6, lr, \min
sub r5, r5, #11 // r5 -= 2*(2+4); r5 += 1;
.else
add r5, r5, #1 // r5 += 1
.endif
subs lr, lr, #1 // sec_tap-- (value)
.if \pri
add r8, r8, #1 // pri_taps++ (pointer)
.endif
bne 2b
vshr.s16 q14, q1, #15 // -(sum < 0)
vadd.i16 q1, q1, q14 // sum - (sum < 0)
vrshr.s16 q1, q1, #4 // (8 + sum - (sum < 0)) >> 4
vadd.i16 q0, q0, q1 // px + (8 + sum ...) >> 4
.if \min
vmin.s16 q0, q0, q3
vmax.s16 q0, q0, q2 // iclip(px + .., min, max)
.endif
.if \bpc == 8
vmovn.u16 d0, q0
.endif
.if \w == 8
add r2, r2, #2*16 // tmp += tmp_stride
subs r7, r7, #1 // h--
.if \bpc == 8
vst1.8 {d0}, [r0, :64], r1
.else
vst1.16 {q0}, [r0, :128], r1
.endif
.else
.if \bpc == 8
vst1.32 {d0[0]}, [r0, :32], r1
.else
vst1.16 {d0}, [r0, :64], r1
.endif
add r2, r2, #2*16 // tmp += 2*tmp_stride
subs r7, r7, #2 // h -= 2
.if \bpc == 8
vst1.32 {d0[1]}, [r0, :32], r1
.else
vst1.16 {d1}, [r0, :64], r1
.endif
.endif
// Reset pri_taps and directions back to the original point
sub r5, r5, #2
.if \pri
sub r8, r8, #2
.endif
bgt 1b
vpop {q4-q7}
pop {r4-r9,pc}
endfunc
.endm
.macro filter w, bpc
filter_func \w, \bpc, pri=1, sec=0, min=0, suffix=_pri
filter_func \w, \bpc, pri=0, sec=1, min=0, suffix=_sec
filter_func \w, \bpc, pri=1, sec=1, min=1, suffix=_pri_sec
function cdef_filter\w\()_\bpc\()bpc_neon, export=1
push {r4-r9,lr}
vpush {q4-q7}
ldrd r4, r5, [sp, #92]
ldrd r6, r7, [sp, #100]
.if \bpc == 16
ldrd r8, r9, [sp, #108]
.else
ldr r8, [sp, #108]
.endif
cmp r3, #0 // pri_strength
bne 1f
b cdef_filter\w\()_sec_\bpc\()bpc_neon // only sec
1:
cmp r4, #0 // sec_strength
bne 1f
b cdef_filter\w\()_pri_\bpc\()bpc_neon // only pri
1:
b cdef_filter\w\()_pri_sec_\bpc\()bpc_neon // both pri and sec
endfunc
.endm
const div_table, align=4
.short 840, 420, 280, 210, 168, 140, 120, 105
endconst
const alt_fact, align=4
.short 420, 210, 140, 105, 105, 105, 105, 105, 140, 210, 420, 0
endconst
.macro cost_alt dest, s1, s2, s3, s4, s5, s6
vmull.s16 q1, \s1, \s1 // sum_alt[n]*sum_alt[n]
vmull.s16 q2, \s2, \s2
vmull.s16 q3, \s3, \s3
vmull.s16 q5, \s4, \s4 // sum_alt[n]*sum_alt[n]
vmull.s16 q12, \s5, \s5
vmull.s16 q6, \s6, \s6 // q6 overlaps the first \s1-\s2 here
vmul.i32 q1, q1, q13 // sum_alt[n]^2*fact
vmla.i32 q1, q2, q14
vmla.i32 q1, q3, q15
vmul.i32 q5, q5, q13 // sum_alt[n]^2*fact
vmla.i32 q5, q12, q14
vmla.i32 q5, q6, q15
vadd.i32 d2, d2, d3
vadd.i32 d3, d10, d11
vpadd.i32 \dest, d2, d3 // *cost_ptr
.endm
.macro find_best s1, s2, s3
.ifnb \s2
vmov.32 lr, \s2
.endif
cmp r12, r1 // cost[n] > best_cost
itt gt
movgt r0, r3 // best_dir = n
movgt r1, r12 // best_cost = cost[n]
.ifnb \s2
add r3, r3, #1 // n++
cmp lr, r1 // cost[n] > best_cost
vmov.32 r12, \s3
itt gt
movgt r0, r3 // best_dir = n
movgt r1, lr // best_cost = cost[n]
add r3, r3, #1 // n++
.endif
.endm
// int dav1d_cdef_find_dir_Xbpc_neon(const pixel *img, const ptrdiff_t stride,
// unsigned *const var)
.macro find_dir bpc
function cdef_find_dir_\bpc\()bpc_neon, export=1
push {lr}
vpush {q4-q7}
.if \bpc == 16
clz r3, r3 // clz(bitdepth_max)
sub lr, r3, #24 // -bitdepth_min_8
.endif
sub sp, sp, #32 // cost
mov r3, #8
vmov.u16 q1, #0 // q0-q1 sum_diag[0]
vmov.u16 q3, #0 // q2-q3 sum_diag[1]
vmov.u16 q5, #0 // q4-q5 sum_hv[0-1]
vmov.u16 q8, #0 // q6,d16 sum_alt[0]
// q7,d17 sum_alt[1]
vmov.u16 q9, #0 // q9,d22 sum_alt[2]
vmov.u16 q11, #0
vmov.u16 q10, #0 // q10,d23 sum_alt[3]
.irpc i, 01234567
.if \bpc == 8
vld1.8 {d30}, [r0, :64], r1
vmov.u8 d31, #128
vsubl.u8 q15, d30, d31 // img[x] - 128
.else
vld1.16 {q15}, [r0, :128], r1
vdup.16 q14, lr // -bitdepth_min_8
vshl.u16 q15, q15, q14
vmov.u16 q14, #128
vsub.i16 q15, q15, q14 // img[x] - 128
.endif
vmov.u16 q14, #0
.if \i == 0
vmov q0, q15 // sum_diag[0]
.else
vext.8 q12, q14, q15, #(16-2*\i)
vext.8 q13, q15, q14, #(16-2*\i)
vadd.i16 q0, q0, q12 // sum_diag[0]
vadd.i16 q1, q1, q13 // sum_diag[0]
.endif
vrev64.16 q13, q15
vswp d26, d27 // [-x]
.if \i == 0
vmov q2, q13 // sum_diag[1]
.else
vext.8 q12, q14, q13, #(16-2*\i)
vext.8 q13, q13, q14, #(16-2*\i)
vadd.i16 q2, q2, q12 // sum_diag[1]
vadd.i16 q3, q3, q13 // sum_diag[1]
.endif
vpadd.u16 d26, d30, d31 // [(x >> 1)]
vmov.u16 d27, #0
vpadd.u16 d24, d26, d28
vpadd.u16 d24, d24, d28 // [y]
vmov.u16 r12, d24[0]
vadd.i16 q5, q5, q15 // sum_hv[1]
.if \i < 4
vmov.16 d8[\i], r12 // sum_hv[0]
.else
vmov.16 d9[\i-4], r12 // sum_hv[0]
.endif
.if \i == 0
vmov.u16 q6, q13 // sum_alt[0]
.else
vext.8 q12, q14, q13, #(16-2*\i)
vext.8 q14, q13, q14, #(16-2*\i)
vadd.i16 q6, q6, q12 // sum_alt[0]
vadd.i16 d16, d16, d28 // sum_alt[0]
.endif
vrev64.16 d26, d26 // [-(x >> 1)]
vmov.u16 q14, #0
.if \i == 0
vmov q7, q13 // sum_alt[1]
.else
vext.8 q12, q14, q13, #(16-2*\i)
vext.8 q13, q13, q14, #(16-2*\i)
vadd.i16 q7, q7, q12 // sum_alt[1]
vadd.i16 d17, d17, d26 // sum_alt[1]
.endif
.if \i < 6
vext.8 q12, q14, q15, #(16-2*(3-(\i/2)))
vext.8 q13, q15, q14, #(16-2*(3-(\i/2)))
vadd.i16 q9, q9, q12 // sum_alt[2]
vadd.i16 d22, d22, d26 // sum_alt[2]
.else
vadd.i16 q9, q9, q15 // sum_alt[2]
.endif
.if \i == 0
vmov q10, q15 // sum_alt[3]
.elseif \i == 1
vadd.i16 q10, q10, q15 // sum_alt[3]
.else
vext.8 q12, q14, q15, #(16-2*(\i/2))
vext.8 q13, q15, q14, #(16-2*(\i/2))
vadd.i16 q10, q10, q12 // sum_alt[3]
vadd.i16 d23, d23, d26 // sum_alt[3]
.endif
.endr
vmov.u32 q15, #105
vmull.s16 q12, d8, d8 // sum_hv[0]*sum_hv[0]
vmlal.s16 q12, d9, d9
vmull.s16 q13, d10, d10 // sum_hv[1]*sum_hv[1]
vmlal.s16 q13, d11, d11
vadd.s32 d8, d24, d25
vadd.s32 d9, d26, d27
vpadd.s32 d8, d8, d9 // cost[2,6] (s16, s17)
vmul.i32 d8, d8, d30 // cost[2,6] *= 105
vrev64.16 q1, q1
vrev64.16 q3, q3
vext.8 q1, q1, q1, #10 // sum_diag[0][14-n]
vext.8 q3, q3, q3, #10 // sum_diag[1][14-n]
vstr s16, [sp, #2*4] // cost[2]
vstr s17, [sp, #6*4] // cost[6]
movrel_local r12, div_table
vld1.16 {q14}, [r12, :128]
vmull.s16 q5, d0, d0 // sum_diag[0]*sum_diag[0]
vmull.s16 q12, d1, d1
vmlal.s16 q5, d2, d2
vmlal.s16 q12, d3, d3
vmull.s16 q0, d4, d4 // sum_diag[1]*sum_diag[1]
vmull.s16 q1, d5, d5
vmlal.s16 q0, d6, d6
vmlal.s16 q1, d7, d7
vmovl.u16 q13, d28 // div_table
vmovl.u16 q14, d29
vmul.i32 q5, q5, q13 // cost[0]
vmla.i32 q5, q12, q14
vmul.i32 q0, q0, q13 // cost[4]
vmla.i32 q0, q1, q14
vadd.i32 d10, d10, d11
vadd.i32 d0, d0, d1
vpadd.i32 d0, d10, d0 // cost[0,4] = s0,s1
movrel_local r12, alt_fact
vld1.16 {d29, d30, d31}, [r12, :64] // div_table[2*m+1] + 105
vstr s0, [sp, #0*4] // cost[0]
vstr s1, [sp, #4*4] // cost[4]
vmovl.u16 q13, d29 // div_table[2*m+1] + 105
vmovl.u16 q14, d30
vmovl.u16 q15, d31
cost_alt d14, d12, d13, d16, d14, d15, d17 // cost[1], cost[3]
cost_alt d15, d18, d19, d22, d20, d21, d23 // cost[5], cost[7]
vstr s28, [sp, #1*4] // cost[1]
vstr s29, [sp, #3*4] // cost[3]
mov r0, #0 // best_dir
vmov.32 r1, d0[0] // best_cost
mov r3, #1 // n
vstr s30, [sp, #5*4] // cost[5]
vstr s31, [sp, #7*4] // cost[7]
vmov.32 r12, d14[0]
find_best d14[0], d8[0], d14[1]
find_best d14[1], d0[1], d15[0]
find_best d15[0], d8[1], d15[1]
find_best d15[1]
eor r3, r0, #4 // best_dir ^4
ldr r12, [sp, r3, lsl #2]
sub r1, r1, r12 // best_cost - cost[best_dir ^ 4]
lsr r1, r1, #10
str r1, [r2] // *var
add sp, sp, #32
vpop {q4-q7}
pop {pc}
endfunc
.endm

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,868 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2019, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "src/arm/asm.S"
#include "util.S"
.macro loop_filter wd
function lpf_8_wd\wd\()_neon
vabd.u8 d0, d22, d23 // abs(p1 - p0)
vabd.u8 d1, d25, d24 // abs(q1 - q0)
vabd.u8 d2, d23, d24 // abs(p0 - q0)
vabd.u8 d3, d22, d25 // abs(p1 - q1)
.if \wd >= 6
vabd.u8 d4, d21, d22 // abs(p2 - p1)
vabd.u8 d5, d26, d25 // abs(q2 - q1)
.endif
.if \wd >= 8
vabd.u8 d6, d20, d21 // abs(p3 - p2)
vabd.u8 d7, d27, d26 // abs(q3 - q3)
.endif
.if \wd >= 6
vmax.u8 d4, d4, d5
.endif
vqadd.u8 d2, d2, d2 // abs(p0 - q0) * 2
.if \wd >= 8
vmax.u8 d6, d6, d7
.endif
vshr.u8 d3, d3, #1
.if \wd >= 8
vmax.u8 d4, d4, d6
.endif
.if \wd >= 6
vand d4, d4, d14
.endif
vmax.u8 d0, d0, d1 // max(abs(p1 - p0), abs(q1 - q0))
vqadd.u8 d2, d2, d3 // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1
.if \wd >= 6
vmax.u8 d4, d0, d4
vcge.u8 d1, d11, d4 // max(abs(p1 - p0), abs(q1 - q0), abs(), abs(), ...) <= I
.else
vcge.u8 d1, d11, d0 // max(abs(p1 - p0), abs(q1 - q0)) <= I
.endif
vcge.u8 d2, d10, d2 // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1 <= E
vand d1, d1, d2 // fm
vand d1, d1, d13 // fm && wd >= 4
.if \wd >= 6
vand d14, d14, d1 // fm && wd > 4
.endif
.if \wd >= 16
vand d15, d15, d1 // fm && wd == 16
.endif
vmov r10, r11, d1
orrs r10, r10, r11
beq 9f // if (!fm || wd < 4) return;
.if \wd >= 6
vmov.i8 d10, #1
vabd.u8 d2, d21, d23 // abs(p2 - p0)
vabd.u8 d3, d22, d23 // abs(p1 - p0)
vabd.u8 d4, d25, d24 // abs(q1 - q0)
vabd.u8 d5, d26, d24 // abs(q2 - q0)
.if \wd >= 8
vabd.u8 d6, d20, d23 // abs(p3 - p0)
vabd.u8 d7, d27, d24 // abs(q3 - q0)
.endif
vmax.u8 d2, d2, d3
vmax.u8 d4, d4, d5
.if \wd >= 8
vmax.u8 d6, d6, d7
.endif
vmax.u8 d2, d2, d4
.if \wd >= 8
vmax.u8 d2, d2, d6
.endif
.if \wd == 16
vabd.u8 d3, d17, d23 // abs(p6 - p0)
vabd.u8 d4, d18, d23 // abs(p5 - p0)
vabd.u8 d5, d19, d23 // abs(p4 - p0)
.endif
vcge.u8 d2, d10, d2 // flat8in
.if \wd == 16
vabd.u8 d6, d28, d24 // abs(q4 - q0)
vabd.u8 d7, d29, d24 // abs(q5 - q0)
vabd.u8 d8, d30, d24 // abs(q6 - q0)
.endif
vand d14, d2, d14 // flat8in && fm && wd > 4
vbic d1, d1, d14 // fm && wd >= 4 && !flat8in
.if \wd == 16
vmax.u8 d3, d3, d4
vmax.u8 d5, d5, d6
.endif
vmov r10, r11, d1
.if \wd == 16
vmax.u8 d7, d7, d8
vmax.u8 d3, d3, d5
vmax.u8 d3, d3, d7
vcge.u8 d3, d10, d3 // flat8out
.endif
orrs r10, r10, r11
.if \wd == 16
vand d15, d15, d3 // flat8out && fm && wd == 16
vand d15, d15, d14 // flat8out && flat8in && fm && wd == 16
vbic d14, d14, d15 // flat8in && fm && wd >= 4 && !flat8out
.endif
beq 1f // skip wd == 4 case
.endif
vsubl.u8 q1, d22, d25 // p1 - q1
vcgt.u8 d0, d0, d12 // hev
vqmovn.s16 d2, q1
vand d4, d2, d0 // if (hev) iclip_diff(p1 - q1)
vbic d0, d1, d0 // (fm && wd >= 4 && !hev)
vsubl.u8 q1, d24, d23
vmov.i16 q3, #3
vmul.i16 q1, q1, q3
vmov.i8 d6, #4
vaddw.s8 q1, q1, d4
vmov.i8 d7, #3
vqmovn.s16 d2, q1 // f
vqadd.s8 d4, d6, d2 // imin(f + 4, 127)
vqadd.s8 d5, d7, d2 // imin(f + 3, 127)
vshr.s8 d4, d4, #3 // f1
vshr.s8 d5, d5, #3 // f2
vmovl.u8 q1, d23 // p0
vmovl.u8 q3, d24 // q0
vaddw.s8 q1, q1, d5
vsubw.s8 q3, q3, d4
vrshr.s8 d4, d4, #1 // (f1 + 1) >> 1
vqmovun.s16 d2, q1 // out p0
vqmovun.s16 d6, q3 // out q0
vbit d23, d2, d1 // if (fm && wd >= 4)
vmovl.u8 q1, d22 // p1
vbit d24, d6, d1 // if (fm && wd >= 4)
vmovl.u8 q3, d25 // q1
vaddw.s8 q1, q1, d4
vsubw.s8 q3, q3, d4
vqmovun.s16 d2, q1 // out p1
vqmovun.s16 d6, q3 // out q1
vbit d22, d2, d0 // if (fm && wd >= 4 && !hev)
vbit d25, d6, d0 // if (fm && wd >= 4 && !hev)
1:
.if \wd == 6
vmov r10, r11, d14
orrs r10, r10, r11
beq 2f // skip if there's no flat8in
vaddl.u8 q0, d21, d21 // p2 * 2
vaddl.u8 q1, d21, d22 // p2 + p1
vaddl.u8 q2, d22, d23 // p1 + p0
vaddl.u8 q3, d23, d24 // p0 + q0
vadd.i16 q4, q0, q1
vadd.i16 q5, q2, q3
vaddl.u8 q6, d24, d25 // q0 + q1
vadd.i16 q4, q4, q5
vsub.i16 q6, q6, q0
vaddl.u8 q5, d25, d26 // q1 + q2
vrshrn.i16 d0, q4, #3 // out p1
vadd.i16 q4, q4, q6
vsub.i16 q5, q5, q1
vaddl.u8 q6, d26, d26 // q2 + q2
vrshrn.i16 d1, q4, #3 // out p0
vadd.i16 q4, q4, q5
vsub.i16 q6, q6, q2
vrshrn.i16 d2, q4, #3 // out q0
vbit d22, d0, d14 // p1 if (flat8in)
vadd.i16 q4, q4, q6
vbit d23, d1, d14 // p0 if (flat8in)
vrshrn.i16 d3, q4, #3 // out q1
vbit d24, d2, d14 // q0 if (flat8in)
vbit d25, d3, d14 // q1 if (flat8in)
.elseif \wd >= 8
vmov r10, r11, d14
orrs r10, r10, r11
.if \wd == 8
beq 8f // skip if there's no flat8in
.else
beq 2f // skip if there's no flat8in
.endif
vaddl.u8 q0, d20, d21 // p3 + p2
vaddl.u8 q1, d22, d25 // p1 + q1
vaddl.u8 q2, d20, d22 // p3 + p1
vaddl.u8 q3, d23, d26 // p0 + q2
vadd.i16 q4, q0, q0 // 2 * (p3 + p2)
vaddw.u8 q4, q4, d23 // + p0
vaddw.u8 q4, q4, d24 // + q0
vadd.i16 q4, q4, q2 // + p3 + p1
vsub.i16 q1, q1, q0 // p1 + q1 - p3 - p2
vsub.i16 q3, q3, q2 // p0 + q2 - p3 - p1
vrshrn.i16 d10, q4, #3 // out p2
vadd.i16 q4, q4, q1
vaddl.u8 q0, d20, d23 // p3 + p0
vaddl.u8 q1, d24, d27 // q0 + q3
vrshrn.i16 d11, q4, #3 // out p1
vadd.i16 q4, q4, q3
vsub.i16 q1, q1, q0 // q0 + q3 - p3 - p0
vaddl.u8 q2, d21, d24 // p2 + q0
vaddl.u8 q3, d25, d27 // q1 + q3
vrshrn.i16 d12, q4, #3 // out p0
vadd.i16 q4, q4, q1
vsub.i16 q3, q3, q2 // q1 + q3 - p2 - q0
vaddl.u8 q0, d22, d25 // p1 + q1
vaddl.u8 q1, d26, d27 // q2 + q3
vrshrn.i16 d13, q4, #3 // out q0
vadd.i16 q4, q4, q3
vsub.i16 q1, q1, q0 // q2 + q3 - p1 - q1
vrshrn.i16 d0, q4, #3 // out q1
vadd.i16 q4, q4, q1
vbit d21, d10, d14
vbit d22, d11, d14
vbit d23, d12, d14
vrshrn.i16 d1, q4, #3 // out q2
vbit d24, d13, d14
vbit d25, d0, d14
vbit d26, d1, d14
.endif
2:
.if \wd == 16
vmov r10, r11, d15
orrs r10, r10, r11
bne 1f // check if flat8out is needed
vmov r10, r11, d14
orrs r10, r10, r11
beq 8f // if there was no flat8in, just write the inner 4 pixels
b 7f // if flat8in was used, write the inner 6 pixels
1:
vaddl.u8 q1, d17, d17 // p6 + p6
vaddl.u8 q2, d17, d18 // p6 + p5
vaddl.u8 q3, d17, d19 // p6 + p4
vaddl.u8 q4, d17, d20 // p6 + p3
vadd.i16 q6, q1, q2
vadd.i16 q5, q3, q4
vaddl.u8 q3, d17, d21 // p6 + p2
vadd.i16 q6, q6, q5
vaddl.u8 q4, d17, d22 // p6 + p1
vaddl.u8 q5, d18, d23 // p5 + p0
vadd.i16 q3, q3, q4
vaddl.u8 q4, d19, d24 // p4 + q0
vadd.i16 q6, q6, q3
vadd.i16 q5, q5, q4
vaddl.u8 q3, d20, d25 // p3 + q1
vadd.i16 q6, q6, q5
vsub.i16 q3, q3, q1
vaddl.u8 q1, d21, d26 // p2 + q2
vrshrn.i16 d0, q6, #4 // out p5
vadd.i16 q6, q6, q3 // - (p6 + p6) + (p3 + q1)
vsub.i16 q1, q1, q2
vaddl.u8 q2, d22, d27 // p1 + q3
vaddl.u8 q3, d17, d19 // p6 + p4
vrshrn.i16 d1, q6, #4 // out p4
vadd.i16 q6, q6, q1 // - (p6 + p5) + (p2 + q2)
vsub.i16 q2, q2, q3
vaddl.u8 q3, d23, d28 // p0 + q4
vaddl.u8 q4, d17, d20 // p6 + p3
vrshrn.i16 d2, q6, #4 // out p3
vadd.i16 q6, q6, q2 // - (p6 + p4) + (p1 + q3)
vsub.i16 q3, q3, q4
vaddl.u8 q4, d24, d29 // q0 + q5
vaddl.u8 q2, d17, d21 // p6 + p2
vrshrn.i16 d3, q6, #4 // out p2
vadd.i16 q6, q6, q3 // - (p6 + p3) + (p0 + q4)
vsub.i16 q4, q4, q2
vaddl.u8 q3, d25, d30 // q1 + q6
vaddl.u8 q5, d17, d22 // p6 + p1
vrshrn.i16 d4, q6, #4 // out p1
vadd.i16 q6, q6, q4 // - (p6 + p2) + (q0 + q5)
vsub.i16 q3, q3, q5
vaddl.u8 q4, d26, d30 // q2 + q6
vbif d0, d18, d15 // out p5
vaddl.u8 q5, d18, d23 // p5 + p0
vrshrn.i16 d5, q6, #4 // out p0
vadd.i16 q6, q6, q3 // - (p6 + p1) + (q1 + q6)
vsub.i16 q4, q4, q5
vaddl.u8 q5, d27, d30 // q3 + q6
vbif d1, d19, d15 // out p4
vaddl.u8 q9, d19, d24 // p4 + q0
vrshrn.i16 d6, q6, #4 // out q0
vadd.i16 q6, q6, q4 // - (p5 + p0) + (q2 + q6)
vsub.i16 q5, q5, q9
vaddl.u8 q4, d28, d30 // q4 + q6
vbif d2, d20, d15 // out p3
vaddl.u8 q9, d20, d25 // p3 + q1
vrshrn.i16 d7, q6, #4 // out q1
vadd.i16 q6, q6, q5 // - (p4 + q0) + (q3 + q6)
vsub.i16 q9, q4, q9
vaddl.u8 q5, d29, d30 // q5 + q6
vbif d3, d21, d15 // out p2
vaddl.u8 q10, d21, d26 // p2 + q2
vrshrn.i16 d8, q6, #4 // out q2
vadd.i16 q6, q6, q9 // - (p3 + q1) + (q4 + q6)
vsub.i16 q5, q5, q10
vaddl.u8 q9, d30, d30 // q6 + q6
vbif d4, d22, d15 // out p1
vaddl.u8 q10, d22, d27 // p1 + q3
vrshrn.i16 d9, q6, #4 // out q3
vadd.i16 q6, q6, q5 // - (p2 + q2) + (q5 + q6)
vsub.i16 q9, q9, q10
vbif d5, d23, d15 // out p0
vrshrn.i16 d10, q6, #4 // out q4
vadd.i16 q6, q6, q9 // - (p1 + q3) + (q6 + q6)
vrshrn.i16 d11, q6, #4 // out q5
vbif d6, d24, d15 // out q0
vbif d7, d25, d15 // out q1
vbif d8, d26, d15 // out q2
vbif d9, d27, d15 // out q3
vbif d10, d28, d15 // out q4
vbif d11, d29, d15 // out q5
.endif
bx lr
.if \wd == 16
7:
// Return to a shorter epilogue, writing only the inner 6 pixels
bx r8
.endif
.if \wd >= 8
8:
// Return to a shorter epilogue, writing only the inner 4 pixels
bx r9
.endif
9:
// Return directly without writing back any pixels
bx r12
endfunc
.endm
loop_filter 16
loop_filter 8
loop_filter 6
loop_filter 4
.macro lpf_8_wd16
adr r8, 7f + CONFIG_THUMB
adr r9, 8f + CONFIG_THUMB
bl lpf_8_wd16_neon
.endm
.macro lpf_8_wd8
adr r9, 8f + CONFIG_THUMB
bl lpf_8_wd8_neon
.endm
.macro lpf_8_wd6
bl lpf_8_wd6_neon
.endm
.macro lpf_8_wd4
bl lpf_8_wd4_neon
.endm
function lpf_v_4_8_neon
mov r12, lr
sub r10, r0, r1, lsl #1
vld1.8 {d22}, [r10, :64], r1 // p1
vld1.8 {d24}, [r0, :64], r1 // q0
vld1.8 {d23}, [r10, :64], r1 // p0
vld1.8 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
lpf_8_wd4
sub r10, r0, r1, lsl #1
vst1.8 {d22}, [r10, :64], r1 // p1
vst1.8 {d24}, [r0, :64], r1 // q0
vst1.8 {d23}, [r10, :64], r1 // p0
vst1.8 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
bx r12
endfunc
function lpf_h_4_8_neon
mov r12, lr
sub r10, r0, #2
add r0, r10, r1, lsl #2
vld1.32 {d22[0]}, [r10], r1
vld1.32 {d22[1]}, [r0], r1
vld1.32 {d23[0]}, [r10], r1
vld1.32 {d23[1]}, [r0], r1
vld1.32 {d24[0]}, [r10], r1
vld1.32 {d24[1]}, [r0], r1
vld1.32 {d25[0]}, [r10], r1
vld1.32 {d25[1]}, [r0], r1
add r0, r0, #2
transpose_4x8b q11, q12, d22, d23, d24, d25
lpf_8_wd4
sub r10, r0, r1, lsl #3
sub r10, r10, #2
transpose_4x8b q11, q12, d22, d23, d24, d25
add r0, r10, r1, lsl #2
vst1.32 {d22[0]}, [r10], r1
vst1.32 {d22[1]}, [r0], r1
vst1.32 {d23[0]}, [r10], r1
vst1.32 {d23[1]}, [r0], r1
vst1.32 {d24[0]}, [r10], r1
vst1.32 {d24[1]}, [r0], r1
vst1.32 {d25[0]}, [r10], r1
vst1.32 {d25[1]}, [r0], r1
add r0, r0, #2
bx r12
endfunc
function lpf_v_6_8_neon
mov r12, lr
sub r10, r0, r1, lsl #1
sub r10, r10, r1
vld1.8 {d21}, [r10, :64], r1 // p2
vld1.8 {d24}, [r0, :64], r1 // q0
vld1.8 {d22}, [r10, :64], r1 // p1
vld1.8 {d25}, [r0, :64], r1 // q1
vld1.8 {d23}, [r10, :64], r1 // p0
vld1.8 {d26}, [r0, :64], r1 // q2
sub r0, r0, r1, lsl #1
sub r0, r0, r1
lpf_8_wd6
sub r10, r0, r1, lsl #1
vst1.8 {d22}, [r10, :64], r1 // p1
vst1.8 {d24}, [r0, :64], r1 // q0
vst1.8 {d23}, [r10, :64], r1 // p0
vst1.8 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
bx r12
endfunc
function lpf_h_6_8_neon
mov r12, lr
sub r10, r0, #4
add r0, r10, r1, lsl #2
vld1.8 {d20}, [r10], r1
vld1.8 {d24}, [r0], r1
vld1.8 {d21}, [r10], r1
vld1.8 {d25}, [r0], r1
vld1.8 {d22}, [r10], r1
vld1.8 {d26}, [r0], r1
vld1.8 {d23}, [r10], r1
vld1.8 {d27}, [r0], r1
add r0, r0, #4
transpose_8x8b q10, q11, q12, q13, d20, d21, d22, d23, d24, d25, d26, d27
lpf_8_wd6
sub r10, r0, r1, lsl #3
sub r10, r10, #2
transpose_4x8b q11, q12, d22, d23, d24, d25
add r0, r10, r1, lsl #2
vst1.32 {d22[0]}, [r10], r1
vst1.32 {d22[1]}, [r0], r1
vst1.32 {d23[0]}, [r10], r1
vst1.32 {d23[1]}, [r0], r1
vst1.32 {d24[0]}, [r10], r1
vst1.32 {d24[1]}, [r0], r1
vst1.32 {d25[0]}, [r10], r1
vst1.32 {d25[1]}, [r0], r1
add r0, r0, #2
bx r12
endfunc
function lpf_v_8_8_neon
mov r12, lr
sub r10, r0, r1, lsl #2
vld1.8 {d20}, [r10, :64], r1 // p3
vld1.8 {d24}, [r0, :64], r1 // q0
vld1.8 {d21}, [r10, :64], r1 // p2
vld1.8 {d25}, [r0, :64], r1 // q1
vld1.8 {d22}, [r10, :64], r1 // p1
vld1.8 {d26}, [r0, :64], r1 // q2
vld1.8 {d23}, [r10, :64], r1 // p0
vld1.8 {d27}, [r0, :64], r1 // q3
sub r0, r0, r1, lsl #2
lpf_8_wd8
sub r10, r0, r1, lsl #1
sub r10, r10, r1
vst1.8 {d21}, [r10, :64], r1 // p2
vst1.8 {d24}, [r0, :64], r1 // q0
vst1.8 {d22}, [r10, :64], r1 // p1
vst1.8 {d25}, [r0, :64], r1 // q1
vst1.8 {d23}, [r10, :64], r1 // p0
vst1.8 {d26}, [r0, :64], r1 // q2
sub r0, r0, r1, lsl #1
sub r0, r0, r1
bx r12
8:
sub r10, r0, r1, lsl #1
vst1.8 {d22}, [r10, :64], r1 // p1
vst1.8 {d24}, [r0, :64], r1 // q0
vst1.8 {d23}, [r10, :64], r1 // p0
vst1.8 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
bx r12
endfunc
function lpf_h_8_8_neon
mov r12, lr
sub r10, r0, #4
add r0, r10, r1, lsl #2
vld1.8 {d20}, [r10], r1
vld1.8 {d24}, [r0], r1
vld1.8 {d21}, [r10], r1
vld1.8 {d25}, [r0], r1
vld1.8 {d22}, [r10], r1
vld1.8 {d26}, [r0], r1
vld1.8 {d23}, [r10], r1
vld1.8 {d27}, [r0], r1
add r0, r0, #4
transpose_8x8b q10, q11, q12, q13, d20, d21, d22, d23, d24, d25, d26, d27
lpf_8_wd8
sub r10, r0, r1, lsl #3
sub r10, r10, #4
transpose_8x8b q10, q11, q12, q13, d20, d21, d22, d23, d24, d25, d26, d27
add r0, r10, r1, lsl #2
vst1.8 {d20}, [r10], r1
vst1.8 {d24}, [r0], r1
vst1.8 {d21}, [r10], r1
vst1.8 {d25}, [r0], r1
vst1.8 {d22}, [r10], r1
vst1.8 {d26}, [r0], r1
vst1.8 {d23}, [r10], r1
vst1.8 {d27}, [r0], r1
add r0, r0, #4
bx r12
8:
sub r10, r0, r1, lsl #3
sub r10, r10, #2
transpose_4x8b q11, q12, d22, d23, d24, d25
add r0, r10, r1, lsl #2
vst1.32 {d22[0]}, [r10], r1
vst1.32 {d22[1]}, [r0], r1
vst1.32 {d23[0]}, [r10], r1
vst1.32 {d23[1]}, [r0], r1
vst1.32 {d24[0]}, [r10], r1
vst1.32 {d24[1]}, [r0], r1
vst1.32 {d25[0]}, [r10], r1
vst1.32 {d25[1]}, [r0], r1
add r0, r0, #2
bx r12
endfunc
function lpf_v_16_8_neon
mov r12, lr
sub r10, r0, r1, lsl #3
add r10, r10, r1
vld1.8 {d17}, [r10, :64], r1 // p6
vld1.8 {d24}, [r0, :64], r1 // q0
vld1.8 {d18}, [r10, :64], r1 // p5
vld1.8 {d25}, [r0, :64], r1 // q1
vld1.8 {d19}, [r10, :64], r1 // p4
vld1.8 {d26}, [r0, :64], r1 // q2
vld1.8 {d20}, [r10, :64], r1 // p3
vld1.8 {d27}, [r0, :64], r1 // q3
vld1.8 {d21}, [r10, :64], r1 // p2
vld1.8 {d28}, [r0, :64], r1 // q4
vld1.8 {d22}, [r10, :64], r1 // p1
vld1.8 {d29}, [r0, :64], r1 // q5
vld1.8 {d23}, [r10, :64], r1 // p0
vld1.8 {d30}, [r0, :64], r1 // q6
sub r0, r0, r1, lsl #3
add r0, r0, r1
lpf_8_wd16
sub r10, r0, r1, lsl #2
sub r10, r10, r1, lsl #1
vst1.8 {d0}, [r10, :64], r1 // p5
vst1.8 {d6}, [r0, :64], r1 // q0
vst1.8 {d1}, [r10, :64], r1 // p4
vst1.8 {d7}, [r0, :64], r1 // q1
vst1.8 {d2}, [r10, :64], r1 // p3
vst1.8 {d8}, [r0, :64], r1 // q2
vst1.8 {d3}, [r10, :64], r1 // p2
vst1.8 {d9}, [r0, :64], r1 // q3
vst1.8 {d4}, [r10, :64], r1 // p1
vst1.8 {d10}, [r0, :64], r1 // q4
vst1.8 {d5}, [r10, :64], r1 // p0
vst1.8 {d11}, [r0, :64], r1 // q5
sub r0, r0, r1, lsl #2
sub r0, r0, r1, lsl #1
bx r12
7:
sub r10, r0, r1
sub r10, r10, r1, lsl #1
vst1.8 {d21}, [r10, :64], r1 // p2
vst1.8 {d24}, [r0, :64], r1 // q0
vst1.8 {d22}, [r10, :64], r1 // p1
vst1.8 {d25}, [r0, :64], r1 // q1
vst1.8 {d23}, [r10, :64], r1 // p0
vst1.8 {d26}, [r0, :64], r1 // q2
sub r0, r0, r1, lsl #1
sub r0, r0, r1
bx r12
8:
sub r10, r0, r1, lsl #1
vst1.8 {d22}, [r10, :64], r1 // p1
vst1.8 {d24}, [r0, :64], r1 // q0
vst1.8 {d23}, [r10, :64], r1 // p0
vst1.8 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
bx r12
endfunc
function lpf_h_16_8_neon
mov r12, lr
sub r10, r0, #8
vld1.8 {d16}, [r10, :64], r1
vld1.8 {d24}, [r0, :64], r1
vld1.8 {d17}, [r10, :64], r1
vld1.8 {d25}, [r0, :64], r1
vld1.8 {d18}, [r10, :64], r1
vld1.8 {d26}, [r0, :64], r1
vld1.8 {d19}, [r10, :64], r1
vld1.8 {d27}, [r0, :64], r1
vld1.8 {d20}, [r10, :64], r1
vld1.8 {d28}, [r0, :64], r1
vld1.8 {d21}, [r10, :64], r1
vld1.8 {d29}, [r0, :64], r1
vld1.8 {d22}, [r10, :64], r1
vld1.8 {d30}, [r0, :64], r1
vld1.8 {d23}, [r10, :64], r1
vld1.8 {d31}, [r0, :64], r1
transpose_8x8b q8, q9, q10, q11, d16, d17, d18, d19, d20, d21, d22, d23
transpose_8x8b q12, q13, q14, q15, d24, d25, d26, d27, d28, d29, d30, d31
lpf_8_wd16
sub r0, r0, r1, lsl #3
sub r10, r0, #8
transpose_8x8b q8, q0, q1, q2, d16, d17, d0, d1, d2, d3, d4, d5
transpose_8x8b q3, q4, q5, q15, d6, d7, d8, d9, d10, d11, d30, d31
vst1.8 {d16}, [r10, :64], r1
vst1.8 {d6}, [r0, :64], r1
vst1.8 {d17}, [r10, :64], r1
vst1.8 {d7}, [r0, :64], r1
vst1.8 {d0}, [r10, :64], r1
vst1.8 {d8}, [r0, :64], r1
vst1.8 {d1}, [r10, :64], r1
vst1.8 {d9}, [r0, :64], r1
vst1.8 {d2}, [r10, :64], r1
vst1.8 {d10}, [r0, :64], r1
vst1.8 {d3}, [r10, :64], r1
vst1.8 {d11}, [r0, :64], r1
vst1.8 {d4}, [r10, :64], r1
vst1.8 {d30}, [r0, :64], r1
vst1.8 {d5}, [r10, :64], r1
vst1.8 {d31}, [r0, :64], r1
bx r12
7:
sub r10, r0, r1, lsl #3
sub r10, r10, #4
transpose_8x8b q10, q11, q12, q13, d20, d21, d22, d23, d24, d25, d26, d27
add r0, r10, r1, lsl #2
vst1.8 {d20}, [r10], r1
vst1.8 {d24}, [r0], r1
vst1.8 {d21}, [r10], r1
vst1.8 {d25}, [r0], r1
vst1.8 {d22}, [r10], r1
vst1.8 {d26}, [r0], r1
vst1.8 {d23}, [r10], r1
vst1.8 {d27}, [r0], r1
add r0, r0, #4
bx r12
8:
sub r10, r0, r1, lsl #3
sub r10, r10, #2
transpose_4x8b q11, q12, d22, d23, d24, d25
add r0, r10, r1, lsl #2
vst1.32 {d22[0]}, [r10], r1
vst1.32 {d22[1]}, [r0], r1
vst1.32 {d23[0]}, [r10], r1
vst1.32 {d23[1]}, [r0], r1
vst1.32 {d24[0]}, [r10], r1
vst1.32 {d24[1]}, [r0], r1
vst1.32 {d25[0]}, [r10], r1
vst1.32 {d25[1]}, [r0], r1
add r0, r0, #2
bx r12
endfunc
// void dav1d_lpf_v_sb_y_8bpc_neon(pixel *dst, const ptrdiff_t stride,
// const uint32_t *const vmask,
// const uint8_t (*l)[4], ptrdiff_t b4_stride,
// const Av1FilterLUT *lut, const int w)
.macro lpf_func dir, type
function lpf_\dir\()_sb_\type\()_8bpc_neon, export=1
push {r4-r11,lr}
vpush {q4-q7}
ldrd r4, r5, [sp, #100]
ldrd r6, r7, [r2] // vmask[0], vmask[1]
.ifc \type, y
ldr r2, [r2, #8] // vmask[2]
.endif
add r5, r5, #128 // Move to sharp part of lut
.ifc \type, y
orr r7, r7, r2 // vmask[1] |= vmask[2]
.endif
.ifc \dir, v
sub r4, r3, r4, lsl #2
.else
sub r3, r3, #4
lsl r4, r4, #2
.endif
orr r6, r6, r7 // vmask[0] |= vmask[1]
1:
tst r6, #0x03
.ifc \dir, v
vld1.8 {d0}, [r4]!
vld1.8 {d1}, [r3]!
.else
vld2.32 {d0[0], d1[0]}, [r3], r4
vld2.32 {d0[1], d1[1]}, [r3], r4
.endif
beq 7f // if (!(vm & bits)) continue;
vld1.8 {d5[]}, [r5] // sharp[0]
add r5, r5, #8
vmov.i32 d2, #0xff
vdup.32 d13, r6 // vmask[0]
vand d0, d0, d2 // Keep only lowest byte in each 32 bit word
vand d1, d1, d2
vtst.8 d3, d1, d2 // Check for nonzero values in l[0][0]
vmov.i8 d4, #1
vld1.8 {d6[]}, [r5] // sharp[1]
sub r5, r5, #8
vbif d1, d0, d3 // if (!l[0][0]) L = l[offset][0]
vtst.32 d2, d1, d2 // L != 0
vmul.i32 d1, d1, d4 // L
.ifc \type, y
vdup.32 d15, r2 // vmask[2]
.endif
vdup.32 d14, r7 // vmask[1]
vmov r10, r11, d2
orrs r10, r10, r11
beq 7f // if (!L) continue;
vneg.s8 d5, d5 // -sharp[0]
movrel_local r10, word_12
vshr.u8 d12, d1, #4 // H
vld1.32 {d16}, [r10, :64]
vshl.s8 d3, d1, d5 // L >> sharp[0]
.ifc \type, y
vtst.32 d15, d15, d16 // if (vmask[2] & bits)
.endif
vmov.i8 d7, #2
vmin.u8 d3, d3, d6 // imin(L >> sharp[0], sharp[1])
vadd.i8 d0, d1, d7 // L + 2
vmax.u8 d11, d3, d4 // imax(imin(), 1) = limit = I
vadd.u8 d0, d0, d0 // 2*(L + 2)
vtst.32 d14, d14, d16 // if (vmask[1] & bits)
vadd.i8 d10, d0, d11 // 2*(L + 2) + limit = E
vtst.32 d13, d13, d16 // if (vmask[0] & bits)
vand d13, d13, d2 // vmask[0] &= L != 0
.ifc \type, y
tst r2, #0x03
beq 2f
// wd16
bl lpf_\dir\()_16_8_neon
b 8f
2:
.endif
tst r7, #0x03
beq 3f
.ifc \type, y
// wd8
bl lpf_\dir\()_8_8_neon
.else
// wd6
bl lpf_\dir\()_6_8_neon
.endif
b 8f
3:
// wd4
bl lpf_\dir\()_4_8_neon
.ifc \dir, h
b 8f
7:
// For dir h, the functions above increment r0.
// If the whole function is skipped, increment it here instead.
add r0, r0, r1, lsl #3
.else
7:
.endif
8:
lsrs r6, r6, #2 // vmask[0] >>= 2
lsr r7, r7, #2 // vmask[1] >>= 2
.ifc \type, y
lsr r2, r2, #2 // vmask[2] >>= 2
.endif
.ifc \dir, v
add r0, r0, #8
.else
// For dir h, r0 is returned incremented
.endif
bne 1b
vpop {q4-q7}
pop {r4-r11,pc}
endfunc
.endm
lpf_func v, y
lpf_func h, y
lpf_func v, uv
lpf_func h, uv
const word_12, align=4
.word 1, 2
endconst

View file

@ -0,0 +1,859 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2020, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "src/arm/asm.S"
#include "util.S"
.macro loop_filter wd
function lpf_4_wd\wd\()_neon
vabd.u16 d0, d22, d23 // abs(p1 - p0)
vabd.u16 d1, d25, d24 // abs(q1 - q0)
vabd.u16 d2, d23, d24 // abs(p0 - q0)
vabd.u16 d3, d22, d25 // abs(p1 - q1)
.if \wd >= 6
vabd.u16 d4, d21, d22 // abs(p2 - p1)
vabd.u16 d5, d26, d25 // abs(q2 - q1)
.endif
.if \wd >= 8
vabd.u16 d6, d20, d21 // abs(p3 - p2)
vabd.u16 d7, d27, d26 // abs(q3 - q3)
.endif
.if \wd >= 6
vmax.u16 d4, d4, d5
.endif
vqadd.u16 d2, d2, d2 // abs(p0 - q0) * 2
.if \wd >= 8
vmax.u16 d6, d6, d7
.endif
vshr.u16 d3, d3, #1
.if \wd >= 8
vmax.u16 d4, d4, d6
.endif
vmax.u16 d0, d0, d1 // max(abs(p1 - p0), abs(q1 - q0))
vqadd.u16 d2, d2, d3 // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1
.if \wd >= 6
vmax.u16 d4, d0, d4
vcge.u16 d1, d11, d4 // max(abs(p1 - p0), abs(q1 - q0), abs(), abs(), ...) <= I
.else
vcge.u16 d1, d11, d0 // max(abs(p1 - p0), abs(q1 - q0)) <= I
.endif
vcge.u16 d2, d10, d2 // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1 <= E
vand d1, d1, d2 // fm && wd >= 4 (implicit)
.if \wd >= 6
vmov d14, d1 // fm && wd > 4 (implicit)
.endif
.if \wd >= 16
vmov d15, d1 // fm && wd == 16 (implicit)
.endif
vmov r10, r11, d1
orrs r10, r10, r11
beq 9f // if (!fm || wd < 4) return;
.if \wd >= 6
vmov.i16 d10, #1
vabd.u16 d2, d21, d23 // abs(p2 - p0)
vabd.u16 d3, d22, d23 // abs(p1 - p0)
vabd.u16 d4, d25, d24 // abs(q1 - q0)
vabd.u16 d5, d26, d24 // abs(q2 - q0)
vdup.16 d9, r9 // bitdepth_min_8
.if \wd >= 8
vabd.u16 d6, d20, d23 // abs(p3 - p0)
vabd.u16 d7, d27, d24 // abs(q3 - q0)
.endif
vmax.u16 d2, d2, d3
vmax.u16 d4, d4, d5
.if \wd >= 8
vmax.u16 d6, d6, d7
.endif
vmax.u16 d2, d2, d4
vshl.u16 d10, d10, d9 // F = 1 << bitdepth_min_8
.if \wd >= 8
vmax.u16 d2, d2, d6
.endif
.if \wd == 16
vabd.u16 d3, d17, d23 // abs(p6 - p0)
vabd.u16 d4, d18, d23 // abs(p5 - p0)
vabd.u16 d5, d19, d23 // abs(p4 - p0)
.endif
vcge.u16 d2, d10, d2 // flat8in
.if \wd == 16
vabd.u16 d6, d28, d24 // abs(q4 - q0)
vabd.u16 d7, d29, d24 // abs(q5 - q0)
vabd.u16 d8, d30, d24 // abs(q6 - q0)
.endif
vand d14, d2, d14 // flat8in && fm && wd > 4
vbic d1, d1, d14 // fm && wd >= 4 && !flat8in
.if \wd == 16
vmax.u16 d3, d3, d4
vmax.u16 d5, d5, d6
.endif
vmov r10, r11, d1
.if \wd == 16
vmax.u16 d7, d7, d8
vmax.u16 d3, d3, d5
vmax.u16 d3, d3, d7
vcge.u16 d3, d10, d3 // flat8out
.endif
orrs r10, r10, r11
.if \wd == 16
vand d15, d15, d3 // flat8out && fm && wd == 16
vand d15, d15, d14 // flat8out && flat8in && fm && wd == 16
vbic d14, d14, d15 // flat8in && fm && wd >= 4 && !flat8out
.endif
beq 1f // skip wd == 4 case
.endif
vdup.16 d3, r8 // bitdepth_max
vsub.u16 d2, d22, d25 // p1 - q1
vshr.u16 d3, d3, #1 // 128 << bitdepth_min_8 - 1
vcgt.u16 d0, d0, d12 // hev
vmvn d9, d3 // - 128 * (1 << bitdepth_min_8)
vmin.s16 d2, d2, d3 // iclip_diff(p1 - q1)
vmax.s16 d2, d2, d9 // iclip_diff(p1 - q1)
vand d4, d2, d0 // if (hev) iclip_diff(p1 - q1)
vsub.u16 d2, d24, d23
vmov.i16 d6, #3
vbic d0, d1, d0 // (fm && wd >= 4 && !hev)
vmul.i16 d2, d2, d6
vmov.i16 d7, #4
vadd.i16 d2, d2, d4
vmin.s16 d2, d2, d3 // f = iclip_diff()
vmax.s16 d2, d2, d9 // f = iclip_diff()
vqadd.s16 d4, d7, d2 // f + 4
vqadd.s16 d5, d6, d2 // f + 3
vmin.s16 d4, d4, d3 // imin(f + 4, 128 << bitdepth_min_8 - 1)
vmin.s16 d5, d5, d3 // imin(f + 3, 128 << bitdepth_min_8 - 1)
vshr.s16 d4, d4, #3 // f1
vshr.s16 d5, d5, #3 // f2
vmov.i16 d9, #0
vdup.16 d3, r8 // bitdepth_max
vqadd.s16 d2, d23, d5 // p0 + f2
vqsub.s16 d6, d24, d4 // q0 - f1
vrshr.s16 d4, d4, #1 // (f1 + 1) >> 1
vmin.s16 d2, d2, d3 // out p0 = iclip_pixel()
vmin.s16 d6, d6, d3 // out q0 = iclip_pixel()
vmax.s16 d2, d2, d9 // out p0 = iclip_pixel()
vmax.s16 d6, d6, d9 // out q0 = iclip_pixel()
vbit d23, d2, d1 // if (fm && wd >= 4)
vbit d24, d6, d1 // if (fm && wd >= 4)
vqadd.s16 d2, d22, d4 // p1 + f
vqsub.s16 d6, d25, d4 // q1 - f
vmin.s16 d2, d2, d3 // out p1 = iclip_pixel()
vmin.s16 d6, d6, d3 // out q1 = iclip_pixel()
vmax.s16 d2, d2, d9 // out p1 = iclip_pixel()
vmax.s16 d6, d6, d9 // out q1 = iclip_pixel()
vbit d22, d2, d0 // if (fm && wd >= 4 && !hev)
vbit d25, d6, d0 // if (fm && wd >= 4 && !hev)
1:
.if \wd == 6
vmov r10, r11, d14
orrs r10, r10, r11
beq 2f // skip if there's no flat8in
vadd.i16 d0, d21, d21 // p2 * 2
vadd.i16 d2, d21, d22 // p2 + p1
vadd.i16 d4, d22, d23 // p1 + p0
vadd.i16 d6, d23, d24 // p0 + q0
vadd.i16 d8, d0, d2
vadd.i16 d10, d4, d6
vadd.i16 d12, d24, d25 // q0 + q1
vadd.i16 d8, d8, d10
vsub.i16 d12, d12, d0
vadd.i16 d10, d25, d26 // q1 + q2
vrshr.u16 d0, d8, #3 // out p1
vadd.i16 d8, d8, d12
vsub.i16 d10, d10, d2
vadd.i16 d12, d26, d26 // q2 + q2
vrshr.u16 d1, d8, #3 // out p0
vadd.i16 d8, d8, d10
vsub.i16 d12, d12, d4
vrshr.u16 d2, d8, #3 // out q0
vbit d22, d0, d14 // p1 if (flat8in)
vadd.i16 d8, d8, d12
vbit d23, d1, d14 // p0 if (flat8in)
vrshr.u16 d3, d8, #3 // out q1
vbit d24, d2, d14 // q0 if (flat8in)
vbit d25, d3, d14 // q1 if (flat8in)
.elseif \wd >= 8
vmov r10, r11, d14
orrs r10, r10, r11
.if \wd == 8
beq 8f // skip if there's no flat8in
.else
beq 2f // skip if there's no flat8in
.endif
vadd.i16 d0, d20, d21 // p3 + p2
vadd.i16 d2, d22, d25 // p1 + q1
vadd.i16 d4, d20, d22 // p3 + p1
vadd.i16 d6, d23, d26 // p0 + q2
vadd.i16 d8, d0, d0 // 2 * (p3 + p2)
vadd.i16 d9, d23, d24 // p0 + q0
vadd.i16 d8, d8, d4 // + p3 + p1
vsub.i16 d2, d2, d0 // p1 + q1 - p3 - p2
vadd.i16 d8, d8, d9 // + p0 + q0
vsub.i16 d6, d6, d4 // p0 + q2 - p3 - p1
vrshr.u16 d10, d8, #3 // out p2
vadd.i16 d8, d8, d2
vadd.i16 d0, d20, d23 // p3 + p0
vadd.i16 d2, d24, d27 // q0 + q3
vrshr.u16 d11, d8, #3 // out p1
vadd.i16 d8, d8, d6
vsub.i16 d2, d2, d0 // q0 + q3 - p3 - p0
vadd.i16 d4, d21, d24 // p2 + q0
vadd.i16 d6, d25, d27 // q1 + q3
vrshr.u16 d12, d8, #3 // out p0
vadd.i16 d8, d8, d2
vsub.i16 d6, d6, d4 // q1 + q3 - p2 - q0
vadd.i16 d0, d22, d25 // p1 + q1
vadd.i16 d2, d26, d27 // q2 + q3
vrshr.u16 d13, d8, #3 // out q0
vadd.i16 d8, d8, d6
vsub.i16 d2, d2, d0 // q2 + q3 - p1 - q1
vrshr.u16 d0, d8, #3 // out q1
vadd.i16 d8, d8, d2
vbit d21, d10, d14
vbit d22, d11, d14
vbit d23, d12, d14
vrshr.u16 d1, d8, #3 // out q2
vbit d24, d13, d14
vbit d25, d0, d14
vbit d26, d1, d14
.endif
2:
.if \wd == 16
vmov r10, r11, d15
orrs r10, r10, r11
bne 1f // check if flat8out is needed
vmov r10, r11, d14
orrs r10, r10, r11
beq 8f // if there was no flat8in, just write the inner 4 pixels
b 7f // if flat8in was used, write the inner 6 pixels
1:
vadd.i16 d2, d17, d17 // p6 + p6
vadd.i16 d4, d17, d18 // p6 + p5
vadd.i16 d6, d17, d19 // p6 + p4
vadd.i16 d8, d17, d20 // p6 + p3
vadd.i16 d12, d2, d4
vadd.i16 d10, d6, d8
vadd.i16 d6, d17, d21 // p6 + p2
vadd.i16 d12, d12, d10
vadd.i16 d8, d17, d22 // p6 + p1
vadd.i16 d10, d18, d23 // p5 + p0
vadd.i16 d6, d6, d8
vadd.i16 d8, d19, d24 // p4 + q0
vadd.i16 d12, d12, d6
vadd.i16 d10, d10, d8
vadd.i16 d6, d20, d25 // p3 + q1
vadd.i16 d12, d12, d10
vsub.i16 d6, d6, d2
vadd.i16 d2, d21, d26 // p2 + q2
vrshr.u16 d0, d12, #4 // out p5
vadd.i16 d12, d12, d6 // - (p6 + p6) + (p3 + q1)
vsub.i16 d2, d2, d4
vadd.i16 d4, d22, d27 // p1 + q3
vadd.i16 d6, d17, d19 // p6 + p4
vrshr.u16 d1, d12, #4 // out p4
vadd.i16 d12, d12, d2 // - (p6 + p5) + (p2 + q2)
vsub.i16 d4, d4, d6
vadd.i16 d6, d23, d28 // p0 + q4
vadd.i16 d8, d17, d20 // p6 + p3
vrshr.u16 d2, d12, #4 // out p3
vadd.i16 d12, d12, d4 // - (p6 + p4) + (p1 + q3)
vsub.i16 d6, d6, d8
vadd.i16 d8, d24, d29 // q0 + q5
vadd.i16 d4, d17, d21 // p6 + p2
vrshr.u16 d3, d12, #4 // out p2
vadd.i16 d12, d12, d6 // - (p6 + p3) + (p0 + q4)
vsub.i16 d8, d8, d4
vadd.i16 d6, d25, d30 // q1 + q6
vadd.i16 d10, d17, d22 // p6 + p1
vrshr.u16 d4, d12, #4 // out p1
vadd.i16 d12, d12, d8 // - (p6 + p2) + (q0 + q5)
vsub.i16 d6, d6, d10
vadd.i16 d8, d26, d30 // q2 + q6
vbif d0, d18, d15 // out p5
vadd.i16 d10, d18, d23 // p5 + p0
vrshr.u16 d5, d12, #4 // out p0
vadd.i16 d12, d12, d6 // - (p6 + p1) + (q1 + q6)
vsub.i16 d8, d8, d10
vadd.i16 d10, d27, d30 // q3 + q6
vbif d1, d19, d15 // out p4
vadd.i16 d18, d19, d24 // p4 + q0
vrshr.u16 d6, d12, #4 // out q0
vadd.i16 d12, d12, d8 // - (p5 + p0) + (q2 + q6)
vsub.i16 d10, d10, d18
vadd.i16 d8, d28, d30 // q4 + q6
vbif d2, d20, d15 // out p3
vadd.i16 d18, d20, d25 // p3 + q1
vrshr.u16 d7, d12, #4 // out q1
vadd.i16 d12, d12, d10 // - (p4 + q0) + (q3 + q6)
vsub.i16 d18, d8, d18
vadd.i16 d10, d29, d30 // q5 + q6
vbif d3, d21, d15 // out p2
vadd.i16 d20, d21, d26 // p2 + q2
vrshr.u16 d8, d12, #4 // out q2
vadd.i16 d12, d12, d18 // - (p3 + q1) + (q4 + q6)
vsub.i16 d10, d10, d20
vadd.i16 d18, d30, d30 // q6 + q6
vbif d4, d22, d15 // out p1
vadd.i16 d20, d22, d27 // p1 + q3
vrshr.u16 d9, d12, #4 // out q3
vadd.i16 d12, d12, d10 // - (p2 + q2) + (q5 + q6)
vsub.i16 d18, d18, d20
vbif d5, d23, d15 // out p0
vrshr.u16 d10, d12, #4 // out q4
vadd.i16 d12, d12, d18 // - (p1 + q3) + (q6 + q6)
vrshr.u16 d11, d12, #4 // out q5
vbif d6, d24, d15 // out q0
vbif d7, d25, d15 // out q1
vbif d8, d26, d15 // out q2
vbif d9, d27, d15 // out q3
vbif d10, d28, d15 // out q4
vbif d11, d29, d15 // out q5
.endif
bx lr
.if \wd == 16
7:
// Return to a shorter epilogue, writing only the inner 6 pixels
bx r6
.endif
.if \wd >= 8
8:
// Return to a shorter epilogue, writing only the inner 4 pixels
bx r7
.endif
9:
// Return directly without writing back any pixels
bx r12
endfunc
.endm
loop_filter 16
loop_filter 8
loop_filter 6
loop_filter 4
.macro lpf_4_wd16
adr r6, 7f + CONFIG_THUMB
adr r7, 8f + CONFIG_THUMB
bl lpf_4_wd16_neon
.endm
.macro lpf_4_wd8
adr r7, 8f + CONFIG_THUMB
bl lpf_4_wd8_neon
.endm
.macro lpf_4_wd6
bl lpf_4_wd6_neon
.endm
.macro lpf_4_wd4
bl lpf_4_wd4_neon
.endm
function lpf_v_4_4_neon
mov r12, lr
sub r10, r0, r1, lsl #1
vld1.16 {d22}, [r10, :64], r1 // p1
vld1.16 {d24}, [r0, :64], r1 // q0
vld1.16 {d23}, [r10, :64], r1 // p0
vld1.16 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
lpf_4_wd4
sub r10, r0, r1, lsl #1
vst1.16 {d22}, [r10, :64], r1 // p1
vst1.16 {d24}, [r0, :64], r1 // q0
vst1.16 {d23}, [r10, :64], r1 // p0
vst1.16 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
bx r12
endfunc
function lpf_h_4_4_neon
mov r12, lr
sub r10, r0, #4
add r0, r10, r1, lsl #1
vld1.16 {d22}, [r10], r1
vld1.16 {d24}, [r0], r1
vld1.16 {d23}, [r10], r1
vld1.16 {d25}, [r0], r1
add r0, r0, #4
transpose_4x4h q11, q12, d22, d23, d24, d25
lpf_4_wd4
sub r10, r0, r1, lsl #2
sub r10, r10, #4
transpose_4x4h q11, q12, d22, d23, d24, d25
add r0, r10, r1, lsl #1
vst1.16 {d22}, [r10], r1
vst1.16 {d24}, [r0], r1
vst1.16 {d23}, [r10], r1
vst1.16 {d25}, [r0], r1
add r0, r0, #4
bx r12
endfunc
function lpf_v_6_4_neon
mov r12, lr
sub r10, r0, r1, lsl #1
sub r10, r10, r1
vld1.16 {d21}, [r10, :64], r1 // p2
vld1.16 {d24}, [r0, :64], r1 // q0
vld1.16 {d22}, [r10, :64], r1 // p1
vld1.16 {d25}, [r0, :64], r1 // q1
vld1.16 {d23}, [r10, :64], r1 // p0
vld1.16 {d26}, [r0, :64], r1 // q2
sub r0, r0, r1, lsl #1
sub r0, r0, r1
lpf_4_wd6
sub r10, r0, r1, lsl #1
vst1.16 {d22}, [r10, :64], r1 // p1
vst1.16 {d24}, [r0, :64], r1 // q0
vst1.16 {d23}, [r10, :64], r1 // p0
vst1.16 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
bx r12
endfunc
function lpf_h_6_4_neon
mov r12, lr
sub r10, r0, #8
vld1.16 {d20}, [r10, :64], r1
vld1.16 {d24}, [r0, :64], r1
vld1.16 {d21}, [r10, :64], r1
vld1.16 {d25}, [r0, :64], r1
vld1.16 {d22}, [r10, :64], r1
vld1.16 {d26}, [r0, :64], r1
vld1.16 {d23}, [r10, :64], r1
vld1.16 {d27}, [r0, :64], r1
transpose_4x4h q10, q11, d20, d21, d22, d23
transpose_4x4h q12, q13, d24, d25, d26, d27
lpf_4_wd6
sub r0, r0, #4
transpose_4x4h q11, q12, d22, d23, d24, d25
sub r10, r0, r1, lsl #2
sub r0, r0, r1, lsl #1
vst1.16 {d22}, [r10], r1
vst1.16 {d24}, [r0], r1
vst1.16 {d23}, [r10], r1
vst1.16 {d25}, [r0], r1
add r0, r0, #4
bx r12
endfunc
function lpf_v_8_4_neon
mov r12, lr
sub r10, r0, r1, lsl #2
vld1.16 {d20}, [r10, :64], r1 // p3
vld1.16 {d24}, [r0, :64], r1 // q0
vld1.16 {d21}, [r10, :64], r1 // p2
vld1.16 {d25}, [r0, :64], r1 // q1
vld1.16 {d22}, [r10, :64], r1 // p1
vld1.16 {d26}, [r0, :64], r1 // q2
vld1.16 {d23}, [r10, :64], r1 // p0
vld1.16 {d27}, [r0, :64], r1 // q3
sub r0, r0, r1, lsl #2
lpf_4_wd8
sub r10, r0, r1, lsl #1
sub r10, r10, r1
vst1.16 {d21}, [r10, :64], r1 // p2
vst1.16 {d24}, [r0, :64], r1 // q0
vst1.16 {d22}, [r10, :64], r1 // p1
vst1.16 {d25}, [r0, :64], r1 // q1
vst1.16 {d23}, [r10, :64], r1 // p0
vst1.16 {d26}, [r0, :64], r1 // q2
sub r0, r0, r1, lsl #1
sub r0, r0, r1
bx r12
8:
sub r10, r0, r1, lsl #1
vst1.16 {d22}, [r10, :64], r1 // p1
vst1.16 {d24}, [r0, :64], r1 // q0
vst1.16 {d23}, [r10, :64], r1 // p0
vst1.16 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
bx r12
endfunc
function lpf_h_8_4_neon
mov r12, lr
sub r10, r0, #8
vld1.16 {d20}, [r10, :64], r1
vld1.16 {d24}, [r0, :64], r1
vld1.16 {d21}, [r10, :64], r1
vld1.16 {d25}, [r0, :64], r1
vld1.16 {d22}, [r10, :64], r1
vld1.16 {d26}, [r0, :64], r1
vld1.16 {d23}, [r10, :64], r1
vld1.16 {d27}, [r0, :64], r1
transpose_4x4h q10, q11, d20, d21, d22, d23
transpose_4x4h q12, q13, d24, d25, d26, d27
lpf_4_wd8
sub r0, r0, r1, lsl #2
transpose_4x4h q10, q11, d20, d21, d22, d23
transpose_4x4h q12, q13, d24, d25, d26, d27
sub r10, r0, #8
vst1.16 {d20}, [r10, :64], r1
vst1.16 {d24}, [r0, :64], r1
vst1.16 {d21}, [r10, :64], r1
vst1.16 {d25}, [r0, :64], r1
vst1.16 {d22}, [r10, :64], r1
vst1.16 {d26}, [r0, :64], r1
vst1.16 {d23}, [r10, :64], r1
vst1.16 {d27}, [r0, :64], r1
bx r12
8:
sub r0, r0, #4
transpose_4x4h q11, q12, d22, d23, d24, d25
sub r10, r0, r1, lsl #2
sub r0, r0, r1, lsl #1
vst1.16 {d22}, [r10], r1
vst1.16 {d24}, [r0], r1
vst1.16 {d23}, [r10], r1
vst1.16 {d25}, [r0], r1
add r0, r0, #4
bx r12
endfunc
function lpf_v_16_4_neon
mov r12, lr
sub r10, r0, r1, lsl #3
add r10, r10, r1
vld1.16 {d17}, [r10, :64], r1 // p6
vld1.16 {d24}, [r0, :64], r1 // q0
vld1.16 {d18}, [r10, :64], r1 // p5
vld1.16 {d25}, [r0, :64], r1 // q1
vld1.16 {d19}, [r10, :64], r1 // p4
vld1.16 {d26}, [r0, :64], r1 // q2
vld1.16 {d20}, [r10, :64], r1 // p3
vld1.16 {d27}, [r0, :64], r1 // q3
vld1.16 {d21}, [r10, :64], r1 // p2
vld1.16 {d28}, [r0, :64], r1 // q4
vld1.16 {d22}, [r10, :64], r1 // p1
vld1.16 {d29}, [r0, :64], r1 // q5
vld1.16 {d23}, [r10, :64], r1 // p0
vld1.16 {d30}, [r0, :64], r1 // q6
sub r0, r0, r1, lsl #3
add r0, r0, r1
lpf_4_wd16
sub r10, r0, r1, lsl #2
sub r10, r10, r1, lsl #1
vst1.16 {d0}, [r10, :64], r1 // p5
vst1.16 {d6}, [r0, :64], r1 // q0
vst1.16 {d1}, [r10, :64], r1 // p4
vst1.16 {d7}, [r0, :64], r1 // q1
vst1.16 {d2}, [r10, :64], r1 // p3
vst1.16 {d8}, [r0, :64], r1 // q2
vst1.16 {d3}, [r10, :64], r1 // p2
vst1.16 {d9}, [r0, :64], r1 // q3
vst1.16 {d4}, [r10, :64], r1 // p1
vst1.16 {d10}, [r0, :64], r1 // q4
vst1.16 {d5}, [r10, :64], r1 // p0
vst1.16 {d11}, [r0, :64], r1 // q5
sub r0, r0, r1, lsl #2
sub r0, r0, r1, lsl #1
bx r12
7:
sub r10, r0, r1
sub r10, r10, r1, lsl #1
vst1.16 {d21}, [r10, :64], r1 // p2
vst1.16 {d24}, [r0, :64], r1 // q0
vst1.16 {d22}, [r10, :64], r1 // p1
vst1.16 {d25}, [r0, :64], r1 // q1
vst1.16 {d23}, [r10, :64], r1 // p0
vst1.16 {d26}, [r0, :64], r1 // q2
sub r0, r0, r1, lsl #1
sub r0, r0, r1
bx r12
8:
sub r10, r0, r1, lsl #1
vst1.16 {d22}, [r10, :64], r1 // p1
vst1.16 {d24}, [r0, :64], r1 // q0
vst1.16 {d23}, [r10, :64], r1 // p0
vst1.16 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
bx r12
endfunc
function lpf_h_16_4_neon
mov r12, lr
sub r10, r0, #16
sub r0, r0, #8
vld1.16 {d16}, [r10, :64], r1
vld1.16 {d20}, [r0, :64], r1
vld1.16 {d17}, [r10, :64], r1
vld1.16 {d21}, [r0, :64], r1
vld1.16 {d18}, [r10, :64], r1
vld1.16 {d22}, [r0, :64], r1
vld1.16 {d19}, [r10, :64], r1
vld1.16 {d23}, [r0, :64], r1
sub r10, r10, r1, lsl #2
sub r0, r0, r1, lsl #2
add r10, r10, #16
add r0, r0, #16
vld1.16 {d24}, [r10, :64], r1
vld1.16 {d28}, [r0, :64], r1
vld1.16 {d25}, [r10, :64], r1
vld1.16 {d29}, [r0, :64], r1
vld1.16 {d26}, [r10, :64], r1
vld1.16 {d30}, [r0, :64], r1
vld1.16 {d27}, [r10, :64], r1
vld1.16 {d31}, [r0, :64], r1
sub r0, r0, #8
transpose_4x4h q8, q9, d16, d17, d18, d19
transpose_4x4h q10, q11, d20, d21, d22, d23
transpose_4x4h q12, q13, d24, d25, d26, d27
transpose_4x4h q14, q15, d28, d29, d30, d31
lpf_4_wd16
sub r0, r0, r1, lsl #2
transpose_4x4h q8, q0, d16, d17, d0, d1
transpose_4x4h q1, q2, d2, d3, d4, d5
transpose_4x4h q3, q4, d6, d7, d8, d9
transpose_4x4h q5, q15, d10, d11, d30, d31
sub r10, r0, #16
sub r0, r0, #8
vst1.16 {d16}, [r10, :64], r1
vst1.16 {d2}, [r0, :64], r1
vst1.16 {d17}, [r10, :64], r1
vst1.16 {d3}, [r0, :64], r1
vst1.16 {d0}, [r10, :64], r1
vst1.16 {d4}, [r0, :64], r1
vst1.16 {d1}, [r10, :64], r1
vst1.16 {d5}, [r0, :64], r1
sub r10, r10, r1, lsl #2
sub r0, r0, r1, lsl #2
add r10, r10, #16
add r0, r0, #16
vst1.16 {d6}, [r10, :64], r1
vst1.16 {d10}, [r0, :64], r1
vst1.16 {d7}, [r10, :64], r1
vst1.16 {d11}, [r0, :64], r1
vst1.16 {d8}, [r10, :64], r1
vst1.16 {d30}, [r0, :64], r1
vst1.16 {d9}, [r10, :64], r1
vst1.16 {d31}, [r0, :64], r1
sub r0, r0, #8
bx r12
7:
sub r0, r0, r1, lsl #2
transpose_4x4h q10, q11, d20, d21, d22, d23
transpose_4x4h q12, q13, d24, d25, d26, d27
sub r10, r0, #8
vst1.16 {d20}, [r10, :64], r1
vst1.16 {d24}, [r0, :64], r1
vst1.16 {d21}, [r10, :64], r1
vst1.16 {d25}, [r0, :64], r1
vst1.16 {d22}, [r10, :64], r1
vst1.16 {d26}, [r0, :64], r1
vst1.16 {d23}, [r10, :64], r1
vst1.16 {d27}, [r0, :64], r1
bx r12
8:
sub r0, r0, #4
transpose_4x4h q11, q12, d22, d23, d24, d25
sub r10, r0, r1, lsl #2
sub r0, r0, r1, lsl #1
vst1.16 {d22}, [r10], r1
vst1.16 {d24}, [r0], r1
vst1.16 {d23}, [r10], r1
vst1.16 {d25}, [r0], r1
add r0, r0, #4
bx r12
endfunc
// void dav1d_lpf_v_sb_y_16bpc_neon(pixel *dst, const ptrdiff_t stride,
// const uint32_t *const vmask,
// const uint8_t (*l)[4], ptrdiff_t b4_stride,
// const Av1FilterLUT *lut, const int w,
// const int bitdepth_max)
.macro lpf_func dir, type
function lpf_\dir\()_sb_\type\()_16bpc_neon, export=1
push {r4-r11,lr}
vpush {q4-q7}
ldrd r4, r5, [sp, #100]
ldr r8, [sp, #112] // bitdepth_max; the 'w' parameter isn't loaded
sub sp, sp, #8
clz r9, r8
rsb r9, r9, #24 // bitdepth_min_8
ldrd r6, r7, [r2] // vmask[0], vmask[1]
.ifc \type, y
ldr r2, [r2, #8] // vmask[2]
.endif
add r5, r5, #128 // Move to sharp part of lut
.ifc \type, y
orr r7, r7, r2 // vmask[1] |= vmask[2]
.endif
.ifc \dir, v
sub r4, r3, r4, lsl #2
.else
sub r3, r3, #4
lsl r4, r4, #2
.endif
orr r6, r6, r7 // vmask[0] |= vmask[1]
1:
tst r6, #0x01
strd r6, r7, [sp]
.ifc \dir, v
ldrb r10, [r4], #4
ldrb r11, [r3], #4
.else
ldrb r10, [r3]
ldrb r11, [r3, #4]
add r3, r3, r4
.endif
beq 7f // if (!(vm & bits)) continue;
orrs r12, r10, r11
vdup.16 d31, r9 // bitdepth_min_8
beq 7f // if (!(l[0][0] | l[offset][0])) continue;
cmp r11, #0 // Check for nonzero values in l[0][0]
ldrb r6, [r5], #8 // sharp[0]
it eq
moveq r11, r10 // if (!l[0][0]) L = l[offset][0]
ldrb r12, [r5] // sharp[1]
lsr r6, r11, r6 // L >> sharp[0]
sub r5, r5, #8
cmp r12, r6
lsr r10, r11, #4 // H
add r11, r11, #2 // L + 2
it lt
movlt r6, r12 // imin(L >> sharp[0], sharp[1])
add r11, r11, r11 // 2*(L + 2)
cmp r6, #1
lsl r10, r10, r9 // H << bitdepth_min_8
it lt
movlt r6, #1 // imax(imin(), 1) = limit = I
vdup.16 d12, r10 // H << bitdepth_min_8
add r11, r11, r6 // 2*(L + 2) + limit = E
lsl r6, r6, r9 // I << bitdepth_min_8
lsl r11, r11, r9 // E << bitdepth_min_8
vdup.16 d11, r6 // I << bitdepth_min_8
vdup.16 d10, r11 // E << bitdepth_min_8
.ifc \type, y
tst r2, #0x01
beq 2f
// wd16
bl lpf_\dir\()_16_4_neon
b 8f
2:
.endif
tst r7, #0x01
beq 3f
.ifc \type, y
// wd8
bl lpf_\dir\()_8_4_neon
.else
// wd6
bl lpf_\dir\()_6_4_neon
.endif
b 8f
3:
// wd4
bl lpf_\dir\()_4_4_neon
.ifc \dir, h
b 8f
7:
// For dir h, the functions above increment r0.
// If the whole function is skipped, increment it here instead.
add r0, r0, r1, lsl #2
.else
7:
.endif
8:
ldrd r6, r7, [sp]
.ifc \type, y
lsr r2, r2, #1 // vmask[2] >>= 1
.endif
.ifc \dir, v
add r0, r0, #8
.else
// For dir h, r0 is returned incremented
.endif
lsrs r6, r6, #1 // vmask[0] >>= 1
lsr r7, r7, #1 // vmask[1] >>= 1
bne 1b
add sp, sp, #8
vpop {q4-q7}
pop {r4-r11,pc}
endfunc
.endm
lpf_func v, y
lpf_func h, y
lpf_func v, uv
lpf_func h, uv

Some files were not shown because too many files have changed in this diff Show more