diff options
author | Andrew Geissler <geissonator@yahoo.com> | 2023-01-13 17:55:19 +0300 |
---|---|---|
committer | Andrew Geissler <geissonator@yahoo.com> | 2023-01-13 21:05:42 +0300 |
commit | 517393d903089f921915530ffa689a7a1d113420 (patch) | |
tree | 8bac829cbf7fe13f7f1a4d937e1997d923755ed6 /meta-raspberrypi | |
parent | 98ccb1903bfb490dc6075e694664d8f1edef74dd (diff) | |
download | openbmc-517393d903089f921915530ffa689a7a1d113420.tar.xz |
subtree updates Jan-13-2023
meta-openembedded: d04444509a..cd13881611:
Alex Kiernan (10):
mdns: Upgrade 1310.140.1 -> 1790.40.31
mdns: Set MDNS_VERSIONSTR_NODTS
mdns: Upgrade 1790.40.31 -> 1790.60.25
ostree: Upgrade 2022.5 -> 2022.7
ostree: Use systemd_system_unitdir for systemd units
ostree: Switch to fuse3 which is supported in ostree now
ostree: Fix comments for configuration/ptest
ostree: Handle musl's ERANGE mapping
usbguard: Remove pegtl from DEPENDS
usbguard: Upgrade 1.1.1 -> 1.1.2
Alex Stewart (2):
gvfs: stylize DEPENDS
gvfs: obviate the ssh-client requirement for gvfs
Alexander Kanavin (5):
frr: add a patch to correctly check presence of python from pkg-config
lirc: correctly use PYTHONPATH
libportal: move to oe-core
packagegroup-meta-python: drop python3-strict-rfc3339
nftables: fix builds with latest setuptools
Alexander Stein (1):
dool: Add patch to fix rebuild
Archana Polampalli (1):
Nodejs - Upgrade to 16.18.1
Bartosz Golaszewski (3):
python3-kmod: new package
python3-watchdogdev: new package
packagegroup-meta-python: add missing packages
Bruce Ashfield (1):
zfs: update to 2.1.7
Changqing Li (5):
linuxptp: fix do_compile error
keyutils: fix ptest failed since "+++ Can't Determine Endianness"
graphviz: Do not build tcl support for native
redis: 6.2.7 -> 6.2.8
redis: 7.0.5 -> 7.0.7
Chen Pei (2):
suitesparse:fix git branch in SRC_URI
botan: upgrade 2.19.2 -> 2.19.3
Chen Qi (4):
xfce4-verve-plugin: fix do_configure faiure about missing libpcre
networkmanager: fix dhcpcd PACKAGECONFIG
networkmanager: install config files into correct place
networkmanager: fix /etc/resolv.conf handling
Christian Eggers (1):
boost-url: remove recipe
Clément Péron (3):
navigation: bump proj to 9.1.0 library
proj: add a packageconfig to build as a static library
proj: avoid leaking host path in libproj
Devendra Tewari (1):
android-tools: Use echo instead of bbnote
Dmitry Baryshkov (1):
nss: fix cross-compilation error
Erwann Roussy (3):
python3-schedutils: add recipe
python3-linux-procfs: add recipe
tuna: add recipe
Fabio Estevam (2):
remmina: Update to 1.4.28
crucible: Upgrade to 2022.12.06
Geoff Parker (1):
python3-yappi: upgrade 1.3.6 -> 1.4.0, python 3.11 compatible
Gerbrand De Laender (1):
python3-aioserial: new package
Gianfranco Costamagna (2):
vbxguestdrivers: upgrade 7.0.2 -> 7.0.4
boinc-client: Update boinc from 7.18.1 to 7.20.4
Gianluigi Spagnuolo (1):
libbpf: add native and nativesdk BBCLASSEXTEND
Hains van den Bosch (2):
python3-twisted: Add python3-asyncio to RDEPENDS
python3-twisted: Add python3-typing-extensions to RDEPENDS
He Zhe (1):
protobuf: upgrade 3.21.5 -> 3.21.10
Jose Quaresma (1):
lshw: bump to 42fef565
Kai Kang (31):
freeradius: fix multilib systemd service start failure
wxwidgets: 3.1.5 -> 3.2.1
python3-attrdict3: add recipe with version 2.0.2
python3-wxgtk4: 4.1.1 -> 4.2.0
xfce4-settings: 4.16.3 -> 4.16.5
python3-m2crypto: fix CVE-2020-25657 and buildpaths qa issue
fixup! wxwidgets: 3.1.5 -> 3.2.1
postfix: fix multilib conflict of sample-main.cf
python3-wxgtk4: replace deprecated inspect.getargspec
libxfce4ui: 4.16.1 -> 4.18.0
thunar-volman: 4.16.0 -> 4.18.0
xfce4-cpufreq-plugin: 1.2.7 -> 1.2.8
xfce4-wavelan-plugin: 0.6.2 -> 0.6.3
xfce4-cpugraph-plugin: 1.2.6 -> 1.2.7
xfce4-sensors-plugin: 1.4.3 -> 1.4.4
thunar-shares-plugin: Bump GLib minimum required to 2.26
xfce4-dev-tools: 4.16.0 -> 4.18.0
libxfce4util: 4.16.0 -> 4.18.0
exo: 4.16.4 -> 4.18.0
garcon: 4.16.1 -> 4.18.0
xfce4-panel: 4.16.3 -> 4.18.0
thunar: 4.16.9 -> 4.18.0
tumbler: 4.16.0 -> 4.18.0
xfconf: 4.16.0 -> 4.18.0
xfce4-appfinder: 4.16.1 -> 4.18.0
xfce4-settings: 4.16.5 -> 4.18.0
xfce4-power-manager: 4.16.0 -> 4.18.0
xfce4-session: 4.16.0 -> 4.18.0
xfwm4: 4.16.1 -> 4.18.0
xfdesktop: 4.16.0 -> 4.18.0
xorg-lib: set XORG_EXT for recipes
Khem Raj (91):
gnome-text-editor: Add missing libpcre build time depenedency
ettercap: Add missing dependency on libpcre
xcb-util-cursor: Update to 0.1.4
lldpd: Use github release assets for SRC_URI
aufs-util: Fix build with large file support enabled systems
volume-key: Inherit python3targetconfig
proj: Enable apps when building native variant
python3-pyproj: Export PROJ_DIR
satyr: Inherit python3targetconfig
rest: Re-add 0.8.1
gfbgraph: Use rest 0.8.1
audit: Inherit python3targetconfig
opensaf: Check for _FILE_OFFSET_BITS instead of __TIMESIZE
flite: Add missing deps on alsa-lib and chrpath
python3-pystemd: Regenerate .c sources using newer cython
libreport: Inherit python3targetconfig
uw-imap: Disable parallelism
gnome-calendar: Upgrade to 43.1
gnome-photos: Upgrade to 43.0
libgweather: Remove 40.0
waf-samba.bbclass: point PYTHON_CONFIG to target python3-config
amtk: Add missing dep on python3-pygments-native
fontforge: Inherit python3targetconfig
tepl: Add missing dep on python3-pygments-native
alsa-oss: Remove recipe
opencv: Check for commercial_ffmpeg as well to enable ffmpeg
opencv: Fix build with ffmpeg 5.1+
fwts: Upgrade to 22.11.00
minio: Disable on mips
sip: Add recipe for 6.7.5
imapfilter: Upgrade to 2.7.6
perfetto: Do not pass TUNE_CCARGS to native/host compiler
stressapptest: Upgrade to latest tip
mariadb: Upgrade to 10.11.1
surf: Depend on gcr3
fatcat: Enable 64bit off_t
stressapptest: Fix build with largefile support and musl
nspr: Upgrade to 4.35
cryptsetup: Upgrade to 2.6.0
libyui,libyui-ncurses: Upgrade to 4.2.3
inotify-tools: Fix build on musl and lfs64
sdbus-c++-libsystemd: Upgrade to 250.9 systemd release
xfsprogs: Upgrade to 6.0.0
drbd,drbd-utils: Upgrade to 9.2.1 and drbd-utils to 9.22.0
libtraceevent: Add recipe
libtracefs: Add recipe
trace-cmd: Remove use of off64_t and lseek64
xfsdump: Add -D_LARGEFILE64_SOURCE on musl
xfstests: Add -D_LARGEFILE64_SOURCE on musl
mariadb: Alias lseek64/open64/ftruncate64 on musl systems
gperftools: Define off64_t on musl
android-tools: Define lseek64 = lseek on musl
php: Add -D_LARGEFILE64_SOURCE to cflags
spice-gtk: Use libucontext for coroutines on musl
wxwidgets: Fix build with musl
wxwidgets: Fix locale on musl
wxwidgets: Set HAVE_LARGEFILE_SUPPORT
python3-wxgtk4: Do not use GetAssertStackTrace with USE_STACKWALKER disabled
f2fs-tools: Upgrade to 1.15.0
trace-cmd: Pass ldflags to compiler
parole: Define DATADIRNAME
abseil-cpp: Replace off64_t with off_t
vsftpd_3.0.5.bb: Define _LARGEFILE64_SOURCE on musl
mozjs-102: Disable mozilla stackwalk on musl
fatresize: Fix build when 64bit time_t is enabled
boinc-client: Fix build when using 64bit time_t
python3-grpcio: Define -D_LARGEFILE64_SOURCE only for musl
gnome-online-accounts: Fix build race seen on musl systems
imagemagick: Do not set ac_cv_sys_file_offset_bits
spdlog: Do not use LFS64 functions with musl
mongodb: Do not use off64_t on musl
dracut: Do not undefine _FILE_OFFSET_BITS
libcamera: Diable 64bit time_t on glibc targets
v4l-utils: Diable 64bit time_t on glibc targets
opensaf: Fix the check for __fsblkcnt64_t size
libcereal,poco: Link with -latomic on ppc32 as well
sshpass: Use SPDX identified string for GPLv2
nftables: Upgrade to 1.0.6
mycroft: Check for pulseaudio in distro features
trace-cmd: Build libs before building rest
open-vm-tools: Fix build with 64-bit time_t
libtraceevent: Move plugins into package of its own
trace-cmd: Upgrade to 3.1.5
luajit: Update to latest on v2.1 branch
concurrencykit: Update to 0.7.0
concurrencykit: Set correct PLAT value for riscv32
concurrencykit: Fix build on riscv32 and riscv64
sysbench: Enable only on architectures supporting LuaJIT
packagegroup-meta-oe: Ensure sysbench is included in limited arches
hwloc: Update to 2.9.0
fluentbit: Link with libatomic on ppc32
Lei Maohui (1):
polkit: Fix multilib builds
Leon Anavi (9):
python3-watchdog: Upgrade 2.2.0 -> 2.2.1
python3-zeroconf: Upgrade 0.39.4 -> 0.47.1
python3-croniter: Upgrade 1.3.7 -> 1.3.8
python3-coverage: Upgrade 7.0.1 -> 7.0.3
python3-prompt-toolkit: Upgrade 3.0.31 -> 3.0.36
python3-simplejson: Upgrade 3.18.0 -> 3.18.1
python3-termcolor: Upgrade 2.1.1 -> 2.2.0
python3-cantools: Upgrade 37.2.0 -> 38.0.0
python3-marshmallow: Upgrade 3.18.0 -> 3.19.0
Livin Sunny (1):
libwebsockets: add ipv6 in PACKAGECONFIG
Markus Volk (88):
blueman: add RDEPEND on python3-fcntl
hwdata: add patch to use sysroot prefix for pkgdatadir
pipewire: upgrade 0.3.59 -> 0.3.60
spirv-cross: upgrade; fix build
blueman: upgrade 2.34 -> 2.35
pipewire: upgrade 0.3.60 -> 0.3.61
iwd: upgrade 1.30 -> 2.0
libgdata: use gcr3
libgweather: update 4.0.0 -> 4.2.0
gnome-online-accounts: use gcr3
geary: build with gcr3
gnome-keyring: use gcr3
evolution-data-server: update 3.44.2 -> 3.46.1
gnome-settings-daemon: update 42.1 -> 43.0
libnma: update 1.8.38 -> 1.10.4
geocode-glib: build with libsoup-3.0
gjs: update 1.72.2 -> 1.75.1
gnome-shell: update 42.0 -> 43.1
mutter: update 42.0 -> 43.1
polkit: add recipe for v122
mozjs: update 98 -> 102
appstream-glib: update 0.7.18 -> 0.8.2
gthumb: build with libsoup-3
amtk: update 5.3.1 -> 5.6.1
gedit: update 42.2 -> 43.2
evolution-data-server: remove libgdata dependency
tepl: update 6.0.0 -> 6.2.0
perfetto: pass TUNE_CCARGS to use machine tune
gnome-photos: update dependencies
thunar-archive-plugin: update 0.4.0 -> 0.5.0
libadwaita: remove deprecated sassc-native dependency
gnome-shell: remove deprecated sassc-native dependency
spice-gtk: add missing license information
pipewire: update 0.3.61 -> 0.3.62
gdm: update 42.0 -> 43.0
gnome-session: update 42.0 -> 43-0
geoclue: update to latest commit to allow to build with libsoup-3.0
gvfs: fix polkit homedir
editorconfig: add recipe
tracker: update 3.4.1 -> 3.4.2
gvfs: fix dependencies
gnome-calculator: update 42.2 -> 43.0.1
tracker-miners: update 3.4.1 -> 3.4.2
gnome-photos: add missing runtime dependency on tracker-miners
gtksourceview5: update 5.4.2 -> 5.6.1
remmina: build with libsoup-3.0
ostree: replace libsoup-2.4 by curl
gnome-text-editor: update 42.2 -> 43.1
gtk4: remove recipe
libxmlb: allow to build native
pipewire: update 0.3.62 -> 0.3.63
gnome-shell-extensions: update SRC_URI and remove sassc-native dep
grilo: update 0.3.14 -> 0.3.15
libstemmer: move recipe to meta-oe
xdg-desktop-portal: add recipe
bubblewrap: import recipe from meta-security
gnome-software: add recipe
basu: import recipe from meta-wayland
xdg-desktop-portal-wlr: add recipe
appstream: add recipe
flatpak: add recipe
flatpak-xdg-utils: add recipe
flatpak: add runtime dependency on flatpak-xdg-utils
wireplumber: update 0.4.12 -> 0.4.13
wireplumber: build with dbus support by default
xdg-desktop-portal-gnome: add recipe
libcloudproviders: add recipe
evince: update 42.3 -> 43.1
libportal: build libportal-gtk4 and vala support
nautilus: update 42.2 -> 43.1
gnome-desktop: update 42.0 -> 43
file-roller: update 3.42.0 -> 43.0
wireplumber: dont start systemd system service by default
gnome-bluetooth: update 42.4 -> 42.5
gnome-flashback: update 3.44.0 -> 3.46.0
libwnck3: update 40.1 -> 43.0
gnome-panel: update 3.44.0 -> 3.47.1
gnome-terminal: update 3.42.2 -> 3.46.7
dconf-editor: update 3.38.3 -> 43.0
gnome-shell: add missing RDEPENDS
gnome-control-center: update 42.0 -> 43.2
gnome-shell: add runtime dependency on adwaita-icon-theme
xdg-desktop-portal-gtk: add recipe
thunar: add tumbler to RRECOMMENDS
gnome:terminal add missing inherit meson
gnome-disk-utility: update 42.0 -> 43.0
eog: add recipe
libdecor: import recipe
Martin Jansa (3):
nss: fix SRC_URI
geoclue: fix polkit files only with modem-gps PACKAGECONFIG
layer.conf: update LAYERSERIES_COMPAT for mickledore
Mathieu Dubois-Briand (2):
nss: Add missing CVE product
nss: Whitelist CVEs related to libnssdbm
Matthias Klein (1):
paho-mqtt-c: upgrade 1.3.11 -> 1.3.12
Max Krummenacher (1):
opencv: follow changed name license_flags_accepted
Mingli Yu (25):
gnome-calculator: add opengl to REQUIRED_DISTRO_FEATURES
waylandpp: add opengl to REQUIRED_DISTRO_FEATURES
libnma: add opengl to REQUIRED_DISTRO_FEATURES
network-manager-applet: add opengl to REQUIRED_DISTRO_FEATURES
gssdp: check opengl is enabled or not
gtksourceview5: add opengl to REQUIRED_DISTRO_FEATURES
gnome-font-viewer: add opengl to REQUIRED_DISTRO_FEATURES
libxfce4ui: check opengl DISTRO_FEATURES
gnome-desktop: add opengl to REQUIRED_DISTRO_FEATURES
ibus: add opengl related check
nautilus: add opengl to REQUIRED_DISTRO_FEATURES
gnome-bluetooth: add opengl to REQUIRED_DISTRO_FEATURES
evince: add opengl to REQUIRED_DISTRO_FEATURES
gnome-calendar: add opengl to REQUIRED_DISTRO_FEATURES
xf86-video-amdgpu: add opengl to REQUIRED_DISTRO_FEATURES
spice-gtk: add opengl to REQUIRED_DISTRO_FEATURES
grail: add opengl to REQUIRED_DISTRO_FEATURES
frame: add opengl to REQUIRED_DISTRO_FEATURES
geis: add opengl to REQUIRED_DISTRO_FEATURES
evolution-data-server: add opengl to REQUIRED_DISTRO_FEATURES
libgweather4: add opengl to REQUIRED_DISTRO_FEATURES
geary: add opengl to REQUIRED_DISTRO_FEATURES
file-roller: add opengl to REQUIRED_DISTRO_FEATURES
gnome-photos: add opengl to REQUIRED_DISTRO_FEATURES
xdg-desktop-portal-wlr: add opengl to REQUIRED_DISTRO_FEATURES
Naveen Saini (3):
opencl-headers: add native and nativesdk
tcsh: add native nativesdk BBCLASSEXTEND
tbb: upgrade 2021.5.0 -> 2021.7.0
Omkar Patil (1):
ntfs-3g-ntfsprogs: Upgrade 2022.5.17 to 2022.10.3
Ovidiu Panait (1):
multipath-tools: upgrade 0.8.4 -> 0.9.3
Peter Bergin (1):
sysbench: Upgrade 0.4.12 -> 1.0.20
Peter Kjellerstedt (4):
chrony: Make it possible to enable editline support again
chrony: Remove the libcap and nss PACKAGECONFIGs
Revert "lldpd: Use github release assets for SRC_URI"
lldpd: Correct the checksum for the tar ball to match 1.0.16
Preeti Sachan (1):
fluidsynth: update SRC_URI to remove non-existing 2.2.x branch
Roger Knecht (1):
python3-rapidjson: add recipe
Sakib Sajal (1):
minio: fix license information
Samuli Piippo (1):
protobuf: stage protoc binary to sysroot
Tim Orling (4):
libio-pty-perl: upgrade 1.16 -> 1.17; enable ptest
libmozilla-ca-perl: add recipe for 20221114
libio-socket-ssl-perl: upgrade 2.075 -> 2.076
libtest-warnings-perl: move to oe-core
Tomasz Żyjewski (2):
python3-binwalk: add recipe for version 2.3.3
python3-uefi-firmware: add recipe for version 1.9
Wang Mingyu (190):
byacc: upgrade 20220128 -> 20221106
libforms: upgrade 1.2.4 -> 1.2.5pre1
libnftnl: upgrade 1.2.3 -> 1.2.4
mpich: upgrade 4.0.2 -> 4.0.3
python3-u-msgpack-python: upgrade 2.7.1 -> 2.7.2
python3-aiosignal: upgrade 1.2.0 -> 1.3.1
python3-eth-hash: upgrade 0.5.0 -> 0.5.1
python3-frozenlist: upgrade 1.3.1 -> 1.3.3
python3-google-auth: upgrade 2.14.0 -> 2.14.1
python3-greenlet: upgrade 2.0.0 -> 2.0.1
python3-imageio: upgrade 2.22.3 -> 2.22.4
python3-pycocotools: upgrade 2.0.5 -> 2.0.6
babl: upgrade 0.1.96 -> 0.1.98
ctags: upgrade 5.9.20221106.0 -> 5.9.20221113.0
gegl: upgrade 0.4.38 -> 0.4.40
freerdp: upgrade 2.8.1 -> 2.9.0
glibmm-2.68: upgrade 2.72.1 -> 2.74.0
googlebenchmark: upgrade 1.7.0 -> 1.7.1
gnome-backgrounds: upgrade 42.0 -> 43
nano: upgrade 6.4 -> 7.0
networkmanager-openvpn: upgrade 1.10.0 -> 1.10.2
python3-django: upgrade 4.1 -> 4.1.3
python3-flask-migrate: upgrade 3.1.0 -> 4.0.0
python3-eth-utils: upgrade 2.0.0 -> 2.1.0
python3-eventlet: upgrade 0.33.1 -> 0.33.2
python3-googleapis-common-protos: upgrade 1.56.4 -> 1.57.0
python3-google-api-python-client: upgrade 2.65.0 -> 2.66.0
python3-pymongo: upgrade 4.3.2 -> 4.3.3
lldpd: upgrade 1.0.15 -> 1.0.16
audit: upgrade 3.0.8 -> 3.0.9
ccid: upgrade 1.5.0 -> 1.5.1
colord: upgrade 1.4.5 -> 1.4.6
ctags: upgrade 5.9.20221113.0 -> 5.9.20221120.0
flatbuffers: upgrade 22.10.26 -> 22.11.23
libglvnd: upgrade 1.5.0 -> 1.6.0
gensio: upgrade 2.5.2 -> 2.6.1
mg: upgrade 20220614 -> 20221112
nbdkit: upgrade 1.33.2 -> 1.33.3
xfstests: upgrade 2022.10.30 -> 2022.11.06
pcsc-lite: upgrade 1.9.8 -> 1.9.9
python3-matplotlib-inline: upgrade 0.1.2 -> 0.1.6
python3-astroid: upgrade 2.12.12 -> 2.12.13
python3-asyncinotify: upgrade 2.0.5 -> 2.0.8
python3-charset-normalizer: upgrade 3.0.0 -> 3.0.1
python3-dateparser: upgrade 1.1.0 -> 1.1.4
python3-can: upgrade 4.0.0 -> 4.1.0
python3-flask-socketio: upgrade 5.3.1 -> 5.3.2
python3-ipython: upgrade 8.2.0 -> 8.6.0
python3-langtable: upgrade 0.0.60 -> 0.0.61
python3-jedi: upgrade 0.18.1 -> 0.18.2
python3-grpcio-tools: upgrade 1.50.0 -> 1.51.0
python3-grpcio: upgrade 1.50.0 -> 1.51.0
python3-networkx: upgrade 2.8.7 -> 2.8.8
python3-pyatspi: upgrade 2.38.2 -> 2.46.0
python3-pandas: upgrade 1.5.1 -> 1.5.2
python3-pybind11-json: upgrade 0.2.11 -> 0.2.13
python3-pychromecast: upgrade 12.1.4 -> 13.0.1
python3-pycodestyle: upgrade 2.9.1 -> 2.10.0
xterm: upgrade 373 -> 377
smarty: upgrade 4.2.1 -> 4.3.0
spdlog: upgrade 1.10.0 -> 1.11.0
python3-pyperf: upgrade 2.4.1 -> 2.5.0
python3-pyflakes: upgrade 2.5.0 -> 3.0.1
python3-pymisp: upgrade 2.4.157 -> 2.4.165.1
capnproto: upgrade 0.10.2 -> 0.10.3
libass: upgrade 0.16.0 -> 0.17.0
ctags: upgrade 5.9.20221120.0 -> 5.9.20221127.0
libio-socket-ssl-perl: upgrade 2.076 -> 2.077
python3-grpcio-tools: upgrade 1.51.0 -> 1.51.1
python3-asyncinotify: upgrade 2.0.8 -> 3.0.1
python3-grpcio: upgrade 1.51.0 -> 1.51.1
opensc: upgrade 0.22.0 -> 0.23.0
python3-ipython: upgrade 8.6.0 -> 8.7.0
ply: upgrade 2.2.0 -> 2.3.0
python3-apt: upgrade 2.3.0 -> 2.5.0
poppler: upgrade 22.11.0 -> 22.12.0
python3-asttokens: upgrade 2.1.0 -> 2.2.0
python3-cbor2: upgrade 5.4.3 -> 5.4.5
python3-geomet: upgrade 0.3.0 -> 1.0.0
python3-google-api-core: upgrade 2.10.2 -> 2.11.0
python3-google-api-python-client: upgrade 2.66.0 -> 2.68.0
python3-path: upgrade 16.5.0 -> 16.6.0
python3-google-auth: upgrade 2.14.1 -> 2.15.0
zabbix: upgrade 6.2.4 -> 6.2.5
xmlsec1: upgrade 1.2.36 -> 1.2.37
smcroute: upgrade 2.5.5 -> 2.5.6
python3-protobuf: upgrade 4.21.9 -> 4.21.10
python3-traitlets: upgrade 5.5.0 -> 5.6.0
python3-twine: upgrade 4.0.1 -> 4.0.2
python3-web3: upgrade 5.31.1 -> 5.31.2
python3-ujson: upgrade 5.5.0 -> 5.6.0
ctags: upgrade 5.9.20221127.0 -> 5.9.20221204.0
dnsmasq: upgrade 2.87 -> 2.88
flatbuffers: upgrade 22.11.23 -> 22.12.06
nbdkit: upgrade 1.33.3 -> 1.33.4
hwdata: upgrade 0.364 -> 0.365
evolution-data-server: update 3.46.1 -> 3.46.2
xfstests: upgrade 2022.11.06 -> 2022.11.27
python3-protobuf: upgrade 4.21.10 -> 4.21.11
python3-traitlets: upgrade 5.6.0 -> 5.7.0
python3-redis: upgrade 4.3.5 -> 4.4.0
python3-web3: upgrade 5.31.2 -> 5.31.3
python3-asttokens: upgrade 2.2.0 -> 2.2.1
python3-cbor2: upgrade 5.4.5 -> 5.4.6
python3-google-api-python-client: upgrade 2.68.0 -> 2.69.0
python3-gmpy2: upgrade 2.1.2 -> 2.1.3
python3-multidict: upgrade 6.0.2 -> 6.0.3
python3-watchdog: upgrade 2.1.9 -> 2.2.0
python3-pychromecast: upgrade 13.0.1 -> 13.0.2
python3-pymisp: upgrade 2.4.165.1 -> 2.4.166
python3-pytest-xdist: upgrade 3.0.2 -> 3.1.0
python3-yarl: upgrade 1.8.1 -> 1.8.2
zabbix: upgrade 6.2.5 -> 6.2.6
python3-yamlloader: upgrade 1.1.0 -> 1.2.2
tio: upgrade 2.3 -> 2.4
ctags: upgrade 5.9.20221204.0 -> 6.0.20221218.0
dash: upgrade 0.5.11.5 -> 0.5.12
nanopb: upgrade 0.4.6.4 -> 0.4.7
libio-socket-ssl-perl: upgrade 2.077 -> 2.078
libfile-slurper-perl: upgrade 0.013 -> 0.014
protobuf: upgrade 3.21.10 -> 3.21.12
python3-alembic: upgrade 1.8.1 -> 1.9.0
nano: upgrade 7.0 -> 7.1
python3-gmpy2: upgrade 2.1.3 -> 2.1.5
python3-eth-account: upgrade 0.7.0 -> 0.8.0
python3-google-api-python-client: upgrade 2.69.0 -> 2.70.0
python3-protobuf: upgrade 4.21.11 -> 4.21.12
python3-pycares: upgrade 4.2.2 -> 4.3.0
python3-pycurl: upgrade 7.45.1 -> 7.45.2
python3-pychromecast: upgrade 13.0.2 -> 13.0.4
python3-pyproj: upgrade 3.4.0 -> 3.4.1
python3-pydicti: upgrade 1.1.6 -> 1.2.0
python3-sentry-sdk: upgrade 1.11.1 -> 1.12.0
python3-traitlets: upgrade 5.7.0 -> 5.7.1
tio: upgrade 2.4 -> 2.5
python3-sqlalchemy: upgrade 1.4.44 -> 1.4.45
xfsdump: upgrade 3.1.11 -> 3.1.12
python3-isort: upgrade 5.10.1 -> 5.11.3
xfstests: upgrade 2022.11.27 -> 2022.12.11
ctags: upgrade 6.0.20221218.0 -> 6.0.20221225.0
gst-editing-services: upgrade 1.20.4 -> 1.20.5
logcheck: upgrade 1.3.24 -> 1.4.0
memtester: upgrade 4.5.1 -> 4.6.0
libmime-types-perl: upgrade 2.22 -> 2.23
metacity: upgrade 3.46.0 -> 3.46.1
python3-alembic: upgrade 1.9.0 -> 1.9.1
xfstests: upgrade 2022.12.11 -> 2022.12.18
python3-cytoolz: upgrade 0.12.0 -> 0.12.1
python3-asgiref: upgrade 3.5.2 -> 3.6.0
python3-autobahn: upgrade 22.7.1 -> 22.12.1
python3-coverage: upgrade 6.5.0 -> 7.0.1
python3-bitarray: upgrade 2.6.0 -> 2.6.1
python3-imageio: upgrade 2.22.4 -> 2.23.0
python3-isort: upgrade 5.11.3 -> 5.11.4
python3-multidict: upgrade 6.0.3 -> 6.0.4
python3-traitlets: upgrade 5.7.1 -> 5.8.0
python3-pymisp: upgrade 2.4.166 -> 2.4.167
python3-sentry-sdk: upgrade 1.12.0 -> 1.12.1
python3-supervisor: upgrade 4.2.4 -> 4.2.5
wolfssl: upgrade 5.5.3 -> 5.5.4
remmina: upgrade 1.4.28 -> 1.4.29
ser2net: upgrade 4.3.10 -> 4.3.11
tesseract: upgrade 5.2.0 -> 5.3.0
network-manager-applet: upgrade 1.26.0 -> 1.30.0
byacc: upgrade 20221106 -> 20221229
ctags: upgrade 6.0.20221225.0 -> 6.0.20230101.0
flashrom: upgrade 1.2 -> 1.2.1
fontforge: upgrade 20220308 -> 20230101
hunspell: upgrade 1.7.1 -> 1.7.2
libmime-types-perl: upgrade 2.23 -> 2.24
libnet-dns-perl: upgrade 1.35 -> 1.36
tepl: upgrade 6.2.0 -> 6.4.0
tcpdump: upgrade 4.99.1 -> 4.99.2
traceroute: upgrade 2.1.0 -> 2.1.1
openwsman: upgrade 2.7.1 -> 2.7.2
pcsc-tools: upgrade 1.6.0 -> 1.6.1
poppler: upgrade 22.12.0 -> 23.01.0
rsnapshot: upgrade 1.4.4 -> 1.4.5
tree: upgrade 2.0.4 -> 2.1.0
python3-bidict: upgrade 0.22.0 -> 0.22.1
python3-bitarray: upgrade 2.6.1 -> 2.6.2
python3-dateparser: upgrade 1.1.4 -> 1.1.5
python3-lz4: upgrade 4.0.2 -> 4.3.2
python3-mock: upgrade 4.0.3 -> 5.0.0
python3-pillow: upgrade 9.3.0 -> 9.4.0
python3-pydantic: upgrade 1.10.2 -> 1.10.4
python3-pyephem: upgrade 4.1.3 -> 4.1.4
python3-xlsxwriter: upgrade 3.0.3 -> 3.0.5
python3-xxhash: upgrade 3.1.0 -> 3.2.0
dnf-plugins/rpm.py: Fix grammar when RPM_PREFER_ELF_ARCH doesn't exit.
Xiangyu Chen (1):
lldpd: add ptest for lldpd package
Yi Zhao (13):
libpwquality: set correct pam plugin directory
ostree: add runtime dependency bubblewrap for PACKAGECONFIG[selinux]
ostree: fix selinux policy rebuild error on first deployment
frr: upgrade 8.3.1 -> 8.4.1
open-vm-tools: upgrade 12.1.0 -> 12.1.5
libtdb: upgrade 1.4.3 -> 1.4.7
libldb: upgrade 2.3.4 -> 2.6.1
libtalloc: upgrade 2.3.3 -> 2.3.4
libtevent: upgrade 0.10.2 -> 0.13.0
samba upgrade 4.14.14 -> 4.17.4
krb5: upgrade 1.17.2 -> 1.20.1
grubby: update to latest git rev
grubby: drop version 8.40
Zheng Qiu (1):
python3-inotify: add ptest
persianpros (1):
samba: Remove samba related PYTHONHASHSEED patches and use export function
zhengrq.fnst@fujitsu.com (15):
python3-pymodbus: upgrade 3.0.0 -> 3.0.2
python3-pywbemtools: upgrade 1.0.1 -> 1.1.0
python3-stevedore: upgrade 4.1.0 -> 4.1.1
ser2net: upgrade 4.3.9 -> 4.3.10
yelp-tools: upgrade 42.0 -> 42.1
python3-python-vlc: upgrade 3.0.16120 -> 3.0.18121
python3-sqlalchemy: upgrade 1.4.43 -> 1.4.44
python3-zopeinterface: upgrade 5.5.1 -> 5.5.2
python3-simplejson: upgrade 3.17.6 -> 3.18.0
python3-pywbemtools: upgrade 1.0.1 -> 1.1.1
python3-redis: upgrade 4.3.4 -> 4.3.5
python3-texttable: upgrade 1.6.4 -> 1.6.7
python3-sentry-sdk: upgrade 1.9.10 -> 1.11.1
python3-twitter: upgrade 4.10.1 -> 4.12.1
python3-termcolor: upgrade 2.1.0 -> 2.1.1
meta-security: 2aa48e6f4e..f991b20f56:
Alex Kiernan (1):
bubblewrap: Update 0.6.2 -> 0.7.0
Armin Kuster (2):
python3-privacyidea: update to 2.7.4
chipsec: update to 1.9.1
Michael Haener (1):
tpm2-tools: update to 5.3
meta-arm: d5f132b199..5c42f084f7:
Adam Johnston (1):
arm/trusted-services: Fix 'no such file' when building libts
Adrian Herrera (2):
atp: decouple m5readfile from m5ops
atp: move m5readfile to meta-gem5
Adrián Herrera Arcila (5):
atp: fix failing test_readme
gem5: support for EXTRAS
atp: separate recipe for gem5 models
atp: fix machine overrides in recipes
ci: add meta-atp to check-layers
David Bagonyi (1):
meta-arm-toolchain: Drop calls to datastore finalize
Diego Sueiro (2):
arm/classes: Introduce apply_local_src_patches bbclass
arm/trusted-firmware-m: Fix local source patches application
Emekcan (1):
arm/fvp: Upgrade Corstone1000 FVP
Emekcan Aras (6):
arm-bsp/documentation: corstone1000: update the user guide
arm/optee: Move optee-3.18 patches
arm/optee: support optee 3.19
arm-bsp/optee-os: Adds 3.19 bbappend
arm-bsp/optee-os: N1SDP support for optee-os 3.19
arm/qemuarm-secureboot: pin optee-os version
Jon Mason (5):
arm-bsp/trusted-services: rename bbappends with git version
arm/trusted-services: limit the ts compatible machines
arm-bsp/trusted-services: add n1sdp support
arm/trusted-firmware-m: update to 1.6.1
CI: define DEFAULT_TAG and CPU_REQUEST
Khem Raj (1):
gn: Replace lfs64 functions with original counterparts
Mohamed Omar Asaker (5):
arm-bsp/trusted-services: corstone1000: Use the stateless platform service calls
arm-bsp/trusted-firmware-m: Bump TFM to v1.7
arm-bsp/trusted-firmware-m: corstone1000: TFM 1.7
arm-bsp/musca_b1: Edit the platform name
arm-bsp/trusted-firmware-m: Remove TF-M 1.6 recipe
Peter Hoyes (3):
arm/fvp: Backport shlex.join from Python 3.8
arm/fvpboot: Disable timing annotation by default
arm/classes: Ensure patch files are sorted in apply_local_src_patches
Robbie Cao (1):
arm/fvp-base-r-aem: upgrade to version 11.20.15
Ross Burton (17):
CI: revert a meta-clang change which breaks pixman (thus, xserver)
CI: add variables needed for k8s runners
CI: add tags to all jobs
CI: no need to install telnet
CI: fix builds with clang
CI: use the .setup fragment in machine-coverage
arm/fvp-base-a-aem: upgrade to 11.20.15
arm-bsp/edk2-firmware: allow clang builds on juno
ci/get-binary-toolchains: rewrite, slightly
arm-bsp/documentation: update fvp-base documentation to use runfvp
CI: use qemuarm64 for pending-updates report job
meta-atp: remove
meta-gem5: remove
arm/fvp-envelope: name the FVP tarballs for checksums
arm/fvp-envelope: update HOMEPAGE
arm/fvp-base-a-aem: add support for aarch64 binaries
CI: don't pin fvp-base jobs to x86-64
poky: 44bb88cc86..0ce159991d:
Alejandro Hernandez Samaniego (6):
baremetal-image: Avoid overriding qemu variables from IMAGE_CLASSES
rust: Enable building rust from stable, beta and nightly channels
rust: Enable baremetal targets
baremetal-helloworld: Enable x86 and x86-64 ports
baremetal-helloworld: Move from skeleton to recipes-extended matching what rust-hello-world is doing
oe-selftest: Add baremetal toolchain test
Alex Kiernan (20):
rust: Install target.json for target rustc
rust: update 1.65.0 -> 1.66.0
oeqa/runtime/rust: Add basic compile/run test
libstd-rs: Merge .inc into .bb
libstd-rs: Move source directory to library/test
rust-llvm: Merge .inc into .bb
rust-llvm: Update LLVM_VERSION to match embedded version
packagegroup-rust-sdk-target: Add Rust SDK target packagegroup
packagegroup-core-sdk: Add SDK toolchain language selection support
rust: Merge .inc into .bb
rust: Move musl-x86 fix for `__stack_chk_fail_local` to rust-source
cargo: Merge .inc into .bb
cargo: Extend DEBUG_PREFIX_MAP to cover vendor
cargo: Include crossbeam-utils patch
cargo: Drop exclude from world
packagegroup-rust-sdk-target: Add cargo
oeqa/runtime/rust: Add cargo test
classes: image: Set empty weak default IMAGE_LINGUAS
default-distrovars: Include "c" in IMAGE_LINGUAS for glibc
rust: Merge all rustc-source patches into rust-source.inc
Alex Stewart (2):
lsof: add update-alternatives logic
opkg: upgrade to version 0.6.1
Alexander Kanavin (155):
elfutils: update 0.187 -> 0.188
rsync: update 3.2.5 -> 3.2.7
swig: update 4.0.2 -> 4.1.0
tcl: update 8.6.11 -> 8.6.12
quota: update 4.06 -> 4.09
shadow: update 4.12.3 -> 4.13
texinfo: update 6.8 -> 7.0
libhandy: update 1.6.3 -> 1.8.0
xf86-input-mouse: update 1.9.3 -> 1.9.4
flac: update 1.4.0 -> 1.4.2
icu: update 71.1 -> 72-1
libgpg-error: update 1.45 -> 1.46
popt: update 1.18 -> 1.19
vte: update 0.68.0 -> 0.70.1
webkitgtk: update 2.36.7 -> 2.38.2
man-db: update 2.10.2 -> 2.11.1
gawk: update 5.1.1 -> 5.2.1
unfs: update 0.9.22 -> 0.10.0
qemu-helper: depend on unfs3 and pseudo directly
runqemu: do not hardcode the ip address of the nfs server when using tap
selftest/runqemu: reenable the nfs rootfs test
glibc-tests: correctly pull in the actual tests when installing -ptest package
python3: fix tests on x86 (32 bit)
ptest-packagelists.inc: do not run valgrind ptests on 32 bit x86
python3: use the standard shell version of python3-config
python3targetconfig.bbclass: use PYTHONPATH to point to the target config
bitbake: fetch2/wget.py: correctly match versioned directories
devtool/upgrade: correctly handle recipes where S is a subdir of upstream tree
python3-numpy: fix upstream version check
python3-poetry-core: update 1.3.2 -> 1.4.0
tcl: update 8.6.12 -> 8.6.13
libnewt: update 0.52.21 -> 0.52.23
libxdmcp: update 1.1.3 -> 1.1.4
libxpm: update 3.5.13 -> 3.5.14
libxrandr: update 1.5.2 -> 1.5.3
bluez: update 5.65 -> 5.66
libxcrypt: update PV to match SRCREV
python3-dbusmock: update 0.28.4 -> 0.28.6
ruby: merge .inc into .bb
ruby: update 3.1.2 -> 3.1.3
ghostscript: update 9.56.1 -> 10.0.0
tzdata: update 2022d -> 2022g
systemtap: upgrade 4.7 -> 4.8
gnupg: upgrade 2.3.7 -> 2.3.8
ptest-packagelists.inc: correctly assign fast and slow tests
ovmf: update edk2-stable202208 -> edk2-stable202211
llvm: update 15.0.4 -> 15.0.6
tcmode-default.inc: set LLVMVERSION to a major version wildcard
cmake: update 3.24.2 -> 3.25.1
python3-native: further tweak to sysconfig.py to find python includes correctly
libslirp: add recipe to continue slirp support in qemu
qemu: update 7.1.0 -> 7.2.0
systemd: update 251.8 -> 252.4
dpkg: update 1.21.9 -> 1.21.13
python3-installer: update 0.5.1 -> 0.6.0
python3: update 3.11.0 -> 3.11.1
weston: update 11.0.0 -> 11.0.1
xhost: update 1.0.8 -> 1.0.9
xinit: update 1.4.1 -> 1.4.2
xkbcomp: update 1.4.5 -> 1.4.6
xprop: update 1.2.5 -> 1.2.6
xset: update 1.2.4 -> 1.2.5
xvinfo: update 1.1.4 -> 1.1.5
xf86-video-vesa: update 2.5.0 -> 2.6.0
libice: update 1.0.10 -> 1.1.1
libxcomposite: update 0.4.5 -> 0.4.6
libxdamage: update 1.1.5 -> 1.1.6
libxres: update 1.2.1 -> 1.2.2
libxscrnsaver: update 1.2.3 -> 1.2.4
libxv: update 1.0.11 -> 1.0.12
jquery: upgrade 3.6.1 -> 3.6.2
libmodule-build-perl: update 0.4231 -> 0.4232
python3-chardet: upgrade 5.0.0 -> 5.1.0
libarchive: upgrade 3.6.1 -> 3.6.2
stress-ng: upgrade 0.15.00 -> 0.15.01
vulkan: upgrade 1.3.231.1 -> 1.3.236.0
Revert "python3-native: further tweak to sysconfig.py to find python includes correctly"
conf/machine/include: add x86-64-v3 tunes (AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE)
go: update 1.19.3 -> 1.19.4
vulkan-samples: update to latest revision
boost-build-native: update 1.80.0 -> 1.81.0
qemu: disable sporadically failing test-io-channel-command
devtool: process local files only for the main branch
libportal: add from meta-openembedded/meta-gnome
libportal: convert from gtk-doc to gi-docgen
epiphany: update 42.4 -> 43.0
qemux86-64: build for x86-64-v3 (2013 Haswell and later) rather than Core 2 from 2006
valgrind: disable tests that started failing after switching to x86-64-v3 target
glib-2.0: upgrade 2.74.3 -> 2.74.4
jquery: upgrade 3.6.2 -> 3.6.3
nasm: update 2.15.05 -> 2.16.01
ffmpeg: use nasm patched-in debug-prefix-map option to restore reproducibility
gtk+3: update 3.24.35 -> 3.24.36
libva-utils: update 2.16.0 -> 2.17.0
xcb-util: update 0.4.0 -> 0.4.1
gnupg: update 2.3.8 -> 2.4.0
libksba: update 1.6.2 -> 1.6.3
python3-pycryptodomex: upgrade 3.15.0 -> 3.16.0
piglit: upgrade to latest revision
python3-setuptools-scm: upgrade 7.0.5 -> 7.1.0
python3-attrs: upgrade 22.1.0 -> 22.2.0
webkitgtk: upgrade 2.38.2 -> 2.38.3
linux-firmware: upgrade 20221109 -> 20221214
harfbuzz: upgrade 5.3.1 -> 6.0.0
python3-pytz: upgrade 2022.6 -> 2022.7
strace: upgrade 6.0 -> 6.1
python3-pycryptodome: upgrade 3.15.0 -> 3.16.0
meson: upgrade 0.64.0 -> 1.0.0
xwayland: upgrade 22.1.5 -> 22.1.7
python3-pyrsistent: upgrade 0.19.2 -> 0.19.3
file: upgrade 5.43 -> 5.44
python3-subunit: upgrade 1.4.1 -> 1.4.2
python3-zipp: upgrade 3.10.0 -> 3.11.0
python3-cryptography: upgrade 38.0.3 -> 38.0.4
logrotate: upgrade 3.20.1 -> 3.21.0
python3-importlib-metadata: upgrade 5.0.0 -> 5.2.0
python3-numpy: upgrade 1.23.4 -> 1.24.1
xserver-xorg: upgrade 21.1.4 -> 21.1.6
puzzles: upgrade to latest revision
vte: upgrade 0.70.1 -> 0.70.2
libpsl: upgrade 0.21.1 -> 0.21.2
libtest-fatal-perl: upgrade 0.016 -> 0.017
python3-urllib3: upgrade 1.26.12 -> 1.26.13
python3-cryptography-vectors: upgrade 38.0.3 -> 38.0.4
python3-setuptools: upgrade 65.5.1 -> 65.6.3
libsdl2: upgrade 2.26.0 -> 2.26.1
python3-gitdb: upgrade 4.0.9 -> 4.0.10
diffoscope: upgrade 224 -> 230
python3-mako: upgrade 1.2.3 -> 1.2.4
python3-sphinx: upgrade 5.3.0 -> 6.0.0
libsolv: upgrade 0.7.22 -> 0.7.23
ruby: upgrade 3.1.3 -> 3.2.0
python3-lxml: upgrade 4.9.1 -> 4.9.2
python3-git: upgrade 3.1.29 -> 3.1.30
curl: upgrade 7.86.0 -> 7.87.0
kmscube: upgrade to latest revision
gobject-introspection: upgrade 1.72.0 -> 1.74.0
python3-dtschema: upgrade 2022.11 -> 2022.12
bash: upgrade 5.2.9 -> 5.2.15
kexec-tools: upgrade 2.0.25 -> 2.0.26
python3-jsonschema: upgrade 4.17.0 -> 4.17.3
python3-pycairo: upgrade 1.21.0 -> 1.23.0
nghttp2: upgrade 1.50.0 -> 1.51.0
python3-certifi: upgrade 2022.9.24 -> 2022.12.7
python3-hypothesis: upgrade 6.57.1 -> 6.61.0
libsndfile1: upgrade 1.1.0 -> 1.2.0
repo: upgrade 2.29.9 -> 2.31
libpcap: upgrade 1.10.1 -> 1.10.2
python3-jsonschema: depend on rfc3339-validator in all cases
python3-strict-rfc3339: remove the recipe
elfutils: do not error out on deprecated declarations
gcr3: limit version check to 3.x versions without odd-even rule
ncurses: restore version check as it's now again working due to release of 6.4
tiff: update 4.4.0 -> 4.5.0
qemu: fix recent reproducibility issues
Alexey Smirnov (1):
classes: make TOOLCHAIN more permissive for kernel
Anton Antonov (1):
rust: Do not use default compiler flags defined in CC crate
Antonin Godard (2):
busybox: always start do_compile with orig config files
busybox: rm temporary files if do_compile was interrupted
Atanas Bunchev (1):
qemu.rst: slirp port forwarding details
Bruce Ashfield (30):
linux-yocto-dev: bump to v6.0+
linux-yocto/5.19: update to v5.19.16
linux-yocto/5.15: update to v5.15.74
linux-yocto/5.19: update to v5.19.17
linux-yocto/5.15: update to v5.15.76
linux-yocto/5.19: cfg: intel and vesa updates
kern-tools: integrate ZFS speedup patch
linux-yocto-dev: bump to v6.1
kernel-devsrc: fix for v6.1+
lttng-modules: fix build for v6.1+
linux-yocto/5.19: security.cfg: remove configs which have been dropped
linux-yocto/5.15: update to v5.15.78
linux-yocto/5.19: fix CONFIG_CRYPTO_CCM mismatch warnings
linux-yocto/5.15: fix CONFIG_CRYPTO_CCM mismatch warnings
linux-yocto/5.19: fix elfutils run-backtrace-native-core ptest failure
linux-libc-headers: add 6.x fetch location
linux-libc-headers: bump to 6.1
linux-yocto/5.19: fix perf build with clang
linux-yocto/5.15: ltp and squashfs fixes
linux-yocto: introduce v6.1 reference kernel recipes
linux-yocto/5.15: fix perf build with clang
linux-yocto/5.15: libbpf: Fix build warning on ref_ctr_off
linux-yocto/5.15: update to v5.15.84
linux-yocto/6.1: update to v6.1.1
linux-yocto/5.15: powerpc: Fix reschedule bug in KUAP-unlocked user copy
linux-yocto/5.19: powerpc: Fix reschedule bug in KUAP-unlocked user copy
linux-yocto/6.1: update to v6.1.3
linux-yocto/6.1: cfg: remove CONFIG_ARM_CRYPTO
yocto-bsps/5.15: update to v5.15.78
linux-yocto/5.15: update to v5.15.80
Carlos Alberto Lopez Perez (3):
xwayland: libxshmfence is needed when dri3 is enabled
recipes: Enable nativesdk for gperf, unifdef, gi-docgen and its dependencies
mesa-gl: gallium is required when enabling x11
Changqing Li (2):
base.bbclass: Fix way to check ccache path
sqlite3: upgrade 3.40.0 -> 3.40.1
Charlie Johnston (1):
opkg: ensure opkg uses private gpg.conf when applying keys.
Chee Yang Lee (1):
migration-guides: add release-notes for 4.1.1
Chen Qi (10):
kernel.bbclass: make KERNEL_DEBUG_TIMESTAMPS work at rebuild
resolvconf: make it work
dhcpcd: fix to work with systemd
bitbake: command.py: cleanup bb.cache.parse_recipe
psplash: consider the situation of psplash not exist for systemd
bc: extend to nativesdk
rm_work: adjust dependency to make do_rm_work_all depend on do_rm_work
selftest: allow '-R' and '-r' be used together
dhcpcd: backport two patches to fix runtime error
libseccomp: fix typo in DESCRIPTION
Christian Eggers (1):
boost: add url lib
David Bagonyi (1):
u-boot: Fix u-boot signing when building with multiple u-boot configs
Dmitry Baryshkov (2):
linux-firmware: upgrade 20221012 -> 20221109
linux-firmware: add new fw file to ${PN}-qcom-adreno-a530
Enguerrand de Ribaucourt (1):
bitbake-layers: fix a typo
Enrico Jörns (1):
sstatesig: emit more helpful error message when not finding sstate manifest
Enrico Scholz (1):
sstate: show progress bar again
Fabre Sébastien (1):
u-boot: Add /boot in SYSROOT_DIRS
Frank de Brabander (4):
bitbake: README: Improve explanation about running the testsuite
bitbake: bin/utils: Ensure locale en_US.UTF-8 is available on the system
bitbake: process: log odd unlink events with bitbake.sock
bitbake: README: add required python version for bitbake
Harald Seiler (1):
opkg: Set correct info_dir and status_file in opkg.conf
Jagadeesh Krishnanjanappa (1):
qemuboot.bbclass: make sure runqemu boots bundled initramfs kernel image
Jan Kircher (1):
toolchain-scripts: compatibility with unbound variable protection
Javier Tia (1):
poky.conf: Add Fedora 36 as supported distro
Joe Slater (2):
python3: Fix CVE-2022-37460
libarchive: fix CVE-2022-36227
Jose Quaresma (2):
Revert "gstreamer1.0: disable flaky gstbin:test_watch_for_state_change test"
gstreamer1.0: Fix race conditions in gstbin tests
Joshua Watt (4):
qemu-helper-native: Correctly pass program name as argv[0]
bitbake: cooker: Use event to terminate parser threads
bitbake: cooker: Start sync thread a little earlier
bitbake: bitbake: Convert to argparse
Kai Kang (4):
xorg-lib-common.inc: set default value of XORG_EXT
libx11-compose-data: 1.6.8 -> 1.8.3
libx11: 1.8.1 -> 1.8.3
libsm: 1.2.3 > 1.2.4
Kasper Revsbech (1):
bitbake: fetch2/wget: handle username/password in uri
Khem Raj (47):
rsync: Delete pedantic errors re-ordering patch
pseudo: Disable LFS on 32bit arches
libxkbcommon: Extend to build native package
iso-codes: Extend to build native packages
xkeyboard-config: Extend to build native package
bluez5: enable position independent executables flag
rpcsvc-proto: Use autoconf knob to enable largefile support
gptfdisk: Enable largefile support functions
libpcre2: Upgrade to 10.42
erofs-utils: Convert from off64_t to off_t
pseudo: Remove 64bit time_t flags
unfs3: Define off64_t in terms of off_t on musl
acpid: Fix largefile enabled build
efivar: Replace off64_t with off_t
ltp: Fix largefile support
acl: Enable largefile support by default
libpciaccess: Do not use 64bit functions for largefile support
mdadm: Use _FILE_OFFSET_BITS to use largefile support
btrfs-tools: Do not use 64bit functions for largefile support
e2fsprogs: Do not use 64bit functions for largefile support
libbsd: Fix build with largefile support
gpgme: Fix with with largefile support
virglrenderer: Replace lseek64 with lseek
nfs-utils: Replace statfs64 with statfs
alsa-utils: Replace off64_t with off_t
lttng-tools: Fix build with largefile support
strace: Add knob to enable largefile support
numactl: Enable largefile support
qemu: Fix build with largefile support
systemd: Fix 252 release build on musl
rust: Do not use open64 on musl in getrandom crate
rust,libstd-rs: Fix build with latest musl
rust-llvm: Fix build on latest musl
cargo: Do not use open64 on musl anymore
llvm: Do not use lseek64
strace: Replace off64_t with off_t in sync_file_range.c test
vulkan-samples: Do not use LFS64 APIs in spdlog
pulseaudio: Do not use 64bit time_t flags
musl: Update to latest on tip of trunk
rust: Fix build with 64bit time_t
stress-ng: Do not enforce gold linker
time64.inc: Add GLIBC_64BIT_TIME_FLAGS on ppc/x86 as well
time64: Remove leading whitespace from GLIBC_64BIT_TIME_FLAGS
mpg123: Enable largefile support
site/powerpc32-linux: Do not cache statvfs64 across glibc and musl
tiff: Add packageconfig knob for webp
site/common-musl: Set ac_cv_sys_file_offset_bits default to 64
Lee Chee Yang (1):
migration-guides: add release-notes for 4.0.6
Luca Boccassi (2):
systemd: refresh patch to remove fuzz introduced by rebase on v252
systemd: ship pcrphase/measure tools and units in systemd-extra-utils
Luis (1):
rm_work.bbclass: use HOSTTOOLS 'rm' binary exclusively
Marek Vasut (5):
bitbake: fetch2/git: Prevent git fetcher from fetching gitlab repository metadata
package_rpm: Fix Linux 6.1.0 perf 1.0 version mistranslation
systemd: Make importd depend on glib-2.0 again
bitbake: bitbake-user-manual: Document override :append, :prepend, :remove order
bitbake: fetch2/git: Clarify the meaning of namespace
Markus Volk (12):
ell: upgrade 0.53 -> 0.54
libsdl2: update 2.24.2 -> 2.26.0
graphene: import from meta-oe
gtk4: import recipe from meta-gnome
gcr: rename gcr -> gcr3
gcr: add recipe for gcr-4, needed to build with gtk4
epiphany: use gcr3
gtk4: add tracker-miners runtime dependency
python3-dbusmock: allow to build native
gtk4: update 4.8.2 -> 4.8.3
gcr3: update 3.40.0 -> 3.41.1
librsvg: enable vapi build
Marta Rybczynska (2):
efibootmgr: update compilation with musl
cve-update-db-native: avoid incomplete updates
Martin Jansa (4):
libxml2: upgrade test data from 20080827 to 20130923
nativesdk-rpm: export RPM_ETCCONFIGDIR and MAGIC in environment like RPM_CONFIGDIR
nativesdk-rpm: don't create wrappers for WRAPPER_TOOLS
tune-x86-64-v3.inc: set QEMU_EXTRAOPTIONS like other tune-* files
Mathieu Dubois-Briand (1):
dbus: Add missing CVE product name
Michael Halstead (1):
uninative: Upgrade to 3.8.1 to include libgcc
Michael Opdenacker (34):
manuals: add missing references to classes
manuals: fix paragraphs with the "inherit" word
ref-manual/classes.rst: remove reference to sip.bbclass
manuals: simplify .gitignore files
manuals: split dev-manual/common-tasks.rst
dev-manual/sbom.rst: minor corrections
bitbake: bitbake-user-manual: update references to Yocto Project manual
bitbake.conf: remove SERIAL_CONSOLE variable
bitbake: bitbake-user-manual: add reference to bitbake git repository
ref-manual: add references to variables only documented in the BitBake manual
manuals: add reference to yocto-docs git repository to page footer
manuals: add missing references to variables
manuals: add missing SPDX license header to source files
manuals: fix double colons
ref-manual/resources.rst: fix formating
ref-manual: update references to release notes
manual: improve documentation about using external toolchains
ref-manual/images.rst: fix unnumbered list
manuals: define proper numbered lists
manuals: final removal of SERIAL_CONSOLE variable
ref-manual/resources.rst: improve description of mailing lists
ref-manual/system-requirements.rst: update buildtools instructions
manuals: create references to buildtools
documentation/poky.yaml.in: update minimum python version to 3.8
manuals: prepare 4.2 migration notes
bitbake: bitbake-user-manual: double colon fix
bitbake: bitbake-user-manual: remove "OEBasic" signature generator
migration-guides: fix 4.2 migration note issues
toaster-manual: fix description of introduction video
ref-manual/classes.rst: remove .bbclass from section titles
manuals: simplify references to classes
migration-1.6.rst: fix redundant reference
ref-manual/system-requirements.rst: recommend buildtools for not supported distros
.gitignore: ignore files generated by Toaster
Mikko Rapeli (5):
qemurunner.py: support setting slirp host IP address
runqemu: limit slirp host port forwarding to localhost 127.0.0.1
qemurunner.py: use IP address from command line
dev-manual/runtime-testing.rst: fix oeqa runtime test path
runqemu: add QB_SETUP_CMD and QB_CLEANUP_CMD
Mingli Yu (8):
tcl: correct the header location in tcl.pc
python3: make tkinter available when enabled
sudo: add selinux and audit PACKAGECONFIG
iproute2: add selinux PACKAGECONFIG
util-linux: add selinux PACKAGECONFIG
cronie: add selinux PACKAGECONFIG
psmisc: add selinux PACKAGECONFIG
gcr: add opengl to REQUIRED_DISTRO_FEATURES
Narpat Mali (2):
ffmpeg: fix for CVE-2022-3964
ffmpeg: fix for CVE-2022-3965
Ola x Nilsson (4):
kbd: Don't build tests
glibc: Add ppoll fortify symbol for 64 bit time_t
insane: Add QA check for 32 bit time and file offset functions
time64.conf: Include to enable 64 bit time flags
Ovidiu Panait (1):
kernel.bbclass: remove empty module directories to prevent QA issues
Patrick Williams (1):
kernel-fitimage: reduce dependency to the cpio
Pavel Zhukov (1):
oeqa/rpm.py: Increase timeout and add debug output
Peter Kjellerstedt (1):
recipes, classes: Avoid adding extra whitespace to PACKAGESPLITFUNCS
Peter Marko (2):
externalsrc: fix lookup for .gitmodules
oeqa/selftest/externalsrc: add test for srctree_hash_files
Petr Kubizňák (1):
harfbuzz: remove bindir only if it exists
Petr Vorel (1):
iputils: update to 20221126
Polampalli, Archana (1):
libpam: fix CVE-2022-28321
Qiu, Zheng (3):
valgrind: remove most hidden tests for arm64
tiff: Security fix for CVE-2022-3970
vim: upgrade 9.0.0820 -> 9.0.0947
Quentin Schulz (4):
cairo: update patch for CVE-2019-6461 with upstream solution
cairo: fix CVE patches assigned wrong CVE number
docs: kernel-dev: faq: update tip on how to not include kernel in image
docs: migration-guides: migration-4.0: specify variable name change for kernel inclusion in image recipe
Randy MacLeod (1):
valgrind: skip the boost_thread test on arm
Ranjitsinh Rathod (1):
curl: Correct LICENSE from MIT-open-group to curl
Ravula Adhitya Siddartha (2):
linux-yocto/5.15: update genericx86* machines to v5.15.78
linux-yocto/5.19: update genericx86* machines to v5.19.17
Richard Purdie (97):
bitbake: cache/cookerdata: Move recipe parsing functions from cache to databuilder
bitbake: cache: Drop broken/unused code
bitbake: cache: Drop unused function
bitbake: server: Ensure cooker profiling works
bitbake: worker/runqueue: Reduce initial data transfer in workerdata
bitbake: cache: Drop support for not saving the cache file
bitbake: runqueue: Add further debug for sstate reuse issues
bitbake: runqueue: Fix race issues around hash equivalence and sstate reuse
bitbake: data/siggen: Switch to use frozensets and optimize
bitbake: data_smart: Add debugging for overrides stability issue
bitbake: utils: Allow to_boolean to support int values
base: Drop do_package base definition
bitbake: data: Drop obsolete pydoc/path code
bitbake: BBHandler: Remove pointless global variable declarations
bitbake: runqueue: Improve error message for missing multiconfig
bitbake: data_smart: Small cache reuse optimization
bitbake.conf: Simplify CACHE setting
oeqa/selftest/tinfoil: Add test for separate config_data with recipe_parse_file()
qemu: Ensure libpng dependency is deterministic
bitbake: data: Tweak code layout
bitbake: cache/siggen: Simplify passing basehash data into the cache
bitbake: siggen/cache: Optionally allow adding siggen hash data to the bitbake cache
bitbake: parse: Add support for addpylib conf file directive and BB_GLOBAL_PYMODULES
bitbake: cookerdata: Ensure layers use LAYERSERIES_COMPAT fairly
base: Switch to use addpylib directive and BB_GLOBAL_PYMODULES
devtool/friends: Use LAYERSERIES_CORENAMES when generating LAYERSERIES_COMPAT entries
scripts/checklayer: Update to match bitbake changes
yocto-check-layer: Allow OE-Core to be tested
bitbake: main: Add timestamp to server retry messages
bitbake: main/server: Add lockfile debugging upon server retry
poky/poky-tiny: Drop largefile mentions
lib/sstatesig: Drop OEBasic siggen
bitbake: siggen: Drop non-multiconfig aware siggen support
bitbake: build/siggen/runqueue: Drop do_setscene references
bitbake: bitbake: Bump minimum python version requirement to 3.8
sanity: Update minimum python version to 3.8
bitbake: main/process: Add extra sockname debugging
Revert "kernel-fitimage: reduce dependency to the cpio"
bitbake: siggen: Directly store datacaches reference
bitbake: bitbake: siggen/runqueue: Switch to using RECIPE_SIGGEN_INFO feature for signature dumping
bitbake: siggen: Add dummy dataCaches from task context/datastore
bitbake: build/siggen: Rework stamps functions
bitbake: siggen: Clarify which fn is meant
bitbake: ast/data/codeparser: Add dependencies from python module functions
bitbake: codeparser/data: Add vardepsexclude support to module dependency code
bitbake.conf: Add module function vardepsexclude entries
time64: Rename to a .inc file to match the others
bitbake: command: Add ping command
bitbake: cache: Allow compression of the data in SiggenRecipeInfo
bitbake: siggen: Minor code improvement
bitbake: server/process: Add bitbake.sock race handling
oeqa/concurrencytest: Add number of failures to summary output
python3-poetry-core: Fix determinism issue breaking reproducibility
bitbake: cache/siggen: Fix cache issues with signature handling
bitbake: event: builtins fix for 'd' deletion
bitbake: cooker: Ensure cache is cleared for partial resets
bitbake: tinfoil: Ensure CommandExit is handled
bitbake: cache: Drop reciever side counting for SiggenRecipeInfo
bitbake: knotty: Avoid looping with tracebacks
bitbake: event: Add enable/disable heartbeat code
bitbake: cooker/cookerdata: Rework the way the datastores are reset
bitbake: server/process: Improve exception and idle function logging
bitbake: command: Tweak finishAsyncCommand ordering to avoid races
bitbake: cooker: Ensure commands clean up any parser processes
bitbake: server/process: Improve idle loop exit code
bitbake: event: Always use threadlock
bitbake: server/process: Add locking around idle functions accesses
bitbake: server/process: Run idle commands in a separate idle thread
bitbake: knotty: Ping the server/cooker periodically
bitbake: cookerdata: Fix cache/reparsing issue
bitbake: cookerdata: Fix previous commit to use a string, not a generator
bitbake: command: Ensure that failure cases call finishAsyncComand
layer.conf: Update to use mickledore as the layer series name
layer.conf: Mark master as compatible with mickledore
bitbake: lib/bb: Update thread/process locks to use a timeout
package: Move fixup_perms function to bb function library
package: Move get_conffiles/files_from_filevars functions to lib
package: Move pkgdata handling functions to oe.packagedata
package: Move emit_pkgdata to packagedata.py
package: Move package functions to function library
package: Drop unused function and obsolete comment
package: Move mapping_rename_hook to packagedata function library
python3-cython: Use PACKAGESPLITFUNCS instead of PACKAGEBUILDPKGD
package: Drop support for PACKAGEBUILDPKGD function customisation
recipes/classes: Drop prepend/append usage with PACKAGESPLITFUNCS
bitbake: cooker: Rework the parsing results submission
bitbake: cooker: Clean up inotify idle handler
uninative-tarball: Add libgcc
patchelf: Add fix submitted upstream for uninative segfaults
bitbake: cooker/command: Drop async command handler indirection via cooker
bitbake: process/cooker/command: Fix currentAsyncCommand locking/races
uninative: Ensure uninative is enabled in all cases for BuildStarted event
qemux86-64: Reduce tuning to core2-64
bitbake: tinfoil: Don't wait for events indefinitely
bitbake: knotty: Improve shutdown handling
bitbake: cooker: Fix exit handling issues
bitbake: server/process: Move heartbeat to idle thread
Robert Andersson (1):
go-crosssdk: avoid host contamination by GOCACHE
Ross Burton (28):
build-appliance-image: Update to master head revision
lib/buildstats: fix parsing of trees with reduced_proc_pressure directories
combo-layer: remove unused import
combo-layer: dont use bb.utils.rename
combo-layer: add sync-revs command
libxml2: upgrade 2.9.14 -> 2.10.3
libxml2: add more testing
python3-packaging: upgrade to 22.0
python3-hatchling: remove python3-tomli DEPENDS
python3-cryptography: remove python3-tomli RDEPENDS
meson: drop redundant is_debianlike() patch
meson: always use meson subcommands
libepoxy: remove upstreamed patch
gtk+3: upgrade 3.24.34 -> 3.24.35
gtk+3: port to Meson
meson: no need to rebuild on install
at-spi2-core: clean up x11 enabling
at-spi2-core: disable API docs if x11 is disabled
gtk+3: fix reproducible builds
lsof: upgrade 4.96.4 -> 4.96.5
pango: upgrade 1.50.11 -> 1.50.12
python3-hatch-vcs: upgrade 0.2.0 -> 0.3.0
python3-hatchling: upgrade 1.11.1 -> 1.12.1
python3-pathspec: upgrade 0.10.1 -> 0.10.3
rm_work: handle non-existant stamps directory
oeqa/selftest/debuginfod: improve testcase
elfutils: disable deprecation errors in all builds, not just native
curl: don't enable debug builds
Ryan Eatmon (1):
go: Update reproducibility patch to fix panic errors
Sandeep Gundlupet Raju (3):
libdrm: Remove libdrm-kms package
kernel-fitimage: Adjust order of dtb/dtbo files
kernel-fitimage: Allow user to select dtb when multiple dtb exists
Saul Wold (1):
at: Change when files are copied
Sergei Zhmylev (1):
oeqa/qemurunner: implement vmdk images support
Tim Orling (7):
python3-hypothesis: upgrade 6.56.4 -> 6.57.1
at-spi2-core: upgrade 2.44.1 -> 2.46.0
mirrors.bbclass: update CPAN_MIRROR
libtry-tiny-perl: add recipe for 0.31
libtest-fatal-perl: add recipe for 0.016
libtest-warnings-perl: move from meta-perl
liburi-perl: upgrade 5.08 -> 5.17
Trevor Woerner (1):
local.conf.sample: update bbclass locations
Vincent Davis Jr (1):
mesa: enable glvnd support
Wang Mingyu (49):
btrfs-tools: upgrade 6.0 -> 6.0.1
libpipeline: upgrade 1.5.6 -> 1.5.7
btrfs-tools: upgrade 6.0.1 -> 6.0.2
bind: upgrade 9.18.8 -> 9.18.9
ccache: upgrade 4.7.2 -> 4.7.4
dropbear: upgrade 2022.82 -> 2022.83
libinput: upgrade 1.21.0 -> 1.22.0
libxft: upgrade 2.3.6 -> 2.3.7
mpfr: upgrade 4.1.0 -> 4.1.1
glib-2.0: upgrade 2.74.1 -> 2.74.3
libxcrypt-compat: upgrade 4.4.30 -> 4.4.33
patchelf: upgrade 0.16.1 -> 0.17.0
pciutils: upgrade 3.8.0 -> 3.9.0
shaderc: upgrade 2022.3 -> 2022.4
sqlite3: upgrade 3.39.4 -> 3.40.0
stress-ng: upgrade 0.14.06 -> 0.15.00
swig: upgrade 4.1.0 -> 4.1.1
texinfo: upgrade 7.0 -> 7.0.1
usbutils: upgrade 014 -> 015
xz: upgrade 5.2.7 -> 5.2.9
wayland-protocols: upgrade 1.28 -> 1.31
gnu-config: upgrade to latest revision
libfontenc: upgrade 1.1.6 -> 1.1.7
libpcre2: upgrade 10.40 -> 10.41
libpng: upgrade 1.6.38 -> 1.6.39
libxau: upgrade 1.0.10 -> 1.0.11
libxkbfile: upgrade 1.1.1 -> 1.1.2
libxshmfence: upgrade 1.3.1 -> 1.3.2
xrandr: upgrade 1.5.1 -> 1.5.2
boost: upgrade 1.80.0 -> 1.81.0
ell: upgrade 0.54 -> 0.55
git: upgrade 2.38.1 -> 2.39.0
help2man: upgrade 1.49.2 -> 1.49.3
iproute2: upgrade 6.0.0 -> 6.1.0
libmpc: upgrade 1.2.1 -> 1.3.1
makedepend: upgrade 1.0.7 -> 1.0.8
psmisc: upgrade 23.5 -> 23.6
xz: upgrade 5.2.9 -> 5.4.0
gstreamer1.0: upgrade 1.20.4 -> 1.20.5
bind: upgrade 9.18.9 -> 9.18.10
btrfs-tools: upgrade 6.0.2 -> 6.1
librepo: upgrade 1.14.5 -> 1.15.1
libsdl2: upgrade 2.26.1 -> 2.26.2
libva-utils: upgrade 2.17.0 -> 2.17.1
libxkbcommon: upgrade 1.4.1 -> 1.5.0
mpfr: upgrade 4.1.1 -> 4.2.0
dpkg: upgrade 1.21.13 -> 1.21.17
rxvt-unicode: upgrade 9.30 -> 9.31
virglrenderer: upgrade 0.10.3 -> 0.10.4
Xiangyu Chen (3):
grub: backport patches to fix CVE-2022-28736
openssh: remove RRECOMMENDS to rng-tools for sshd package
grub2: backport patch to fix CVE-2022-2601 CVE-2022-3775
Yoann Congal (2):
bitbake: Group and reorder options in bitbake help
bitbake: main: Move --buildfile help at the end of "Execution" group
leimaohui (1):
libpng: Enable NEON for aarch64 to enensure consistency with arm32.
pgowda (1):
binutils: Add patch to fix CVE-2022-4285
张忠山 (1):
bitbake: data_smart: Use regex consistently for override matching
meta-raspberrypi: 93dadf336c..896566aa92:
Carlos Alberto Lopez Perez (1):
weston: disablepackageconfig options that fail to build with userland drivers
Khem Raj (2):
lirc: Drop upstreamed patch
linux-raspberrypi.inc: Weakly assign COMPATIBLE_MACHINE
Martin Jansa (2):
bluez5: update patches to apply on 5.66 version
layer.conf: update LAYERSERIES_COMPAT for mickledore
Vincent Davis Jr (5):
rpidistro-vlc,rpidistro-ffmpeg: update COMPATIBLE_HOST regex
rpidistro-vlc: upgrade 3.0.12 -> 3.0.17
rpi-default-providers: add libav and libpostproc
rpidistro-ffmpeg: upgrade 4.3.2 -> 4.3.4
rpidistro-ffmpeg: remove --enable-v4l2-request flag
Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
Change-Id: Ied8537beedde0f83790e6e3595057db45f408107
Diffstat (limited to 'meta-raspberrypi')
44 files changed, 10957 insertions, 2377 deletions
diff --git a/meta-raspberrypi/conf/layer.conf b/meta-raspberrypi/conf/layer.conf index 992ff18c76..85adf24eef 100644 --- a/meta-raspberrypi/conf/layer.conf +++ b/meta-raspberrypi/conf/layer.conf @@ -9,7 +9,7 @@ BBFILE_COLLECTIONS += "raspberrypi" BBFILE_PATTERN_raspberrypi := "^${LAYERDIR}/" BBFILE_PRIORITY_raspberrypi = "9" -LAYERSERIES_COMPAT_raspberrypi = "kirkstone langdale" +LAYERSERIES_COMPAT_raspberrypi = "mickledore" LAYERDEPENDS_raspberrypi = "core" # Additional license directories. diff --git a/meta-raspberrypi/conf/machine/include/rpi-default-providers.inc b/meta-raspberrypi/conf/machine/include/rpi-default-providers.inc index 67f2bf5662..3f810264b3 100644 --- a/meta-raspberrypi/conf/machine/include/rpi-default-providers.inc +++ b/meta-raspberrypi/conf/machine/include/rpi-default-providers.inc @@ -9,6 +9,8 @@ PREFERRED_PROVIDER_virtual/mesa ?= "${@bb.utils.contains("MACHINE_FEATURES", "vc PREFERRED_PROVIDER_virtual/libgbm ?= "${@bb.utils.contains("MACHINE_FEATURES", "vc4graphics", "mesa", "mesa-gl", d)}" PREFERRED_PROVIDER_vlc ?= "rpidistro-vlc" PREFERRED_PROVIDER_ffmpeg ?= "rpidistro-ffmpeg" +PREFERRED_PROVIDER_libav ?= "rpidistro-ffmpeg" +PREFERRED_PROVIDER_libpostproc ?= "rpidistro-ffmpeg" PREFERRED_PROVIDER_jpeg ?= "jpeg" PREFERRED_PROVIDER_virtual/libomxil ?= "userland" diff --git a/meta-raspberrypi/dynamic-layers/meta-python/recipes-connectivity/lirc/lirc/lirc-gpio-ir-0.10.patch b/meta-raspberrypi/dynamic-layers/meta-python/recipes-connectivity/lirc/lirc/lirc-gpio-ir-0.10.patch deleted file mode 100644 index c0fdd189be..0000000000 --- a/meta-raspberrypi/dynamic-layers/meta-python/recipes-connectivity/lirc/lirc/lirc-gpio-ir-0.10.patch +++ /dev/null @@ -1,175 +0,0 @@ -diff -ruN lirc-0.10.1.orig/lib/config_file.c lirc-0.10.1/lib/config_file.c ---- lirc-0.10.1.orig/lib/config_file.c 2017-09-10 17:52:19.000000000 +0900 -+++ lirc-0.10.1/lib/config_file.c 2019-06-26 00:39:45.734320696 +0900 -@@ -71,7 +71,7 @@ - typedef void* (*array_guest_func)(void* item, void* arg); - - --#define LINE_LEN 1024 -+#define LINE_LEN 4096 - #define MAX_INCLUDES 10 - - const char* whitespace = " \t"; -diff -ruN lirc-0.10.1.orig/lib/ir_remote.h lirc-0.10.1/lib/ir_remote.h ---- lirc-0.10.1.orig/lib/ir_remote.h 2017-09-10 17:52:19.000000000 +0900 -+++ lirc-0.10.1/lib/ir_remote.h 2019-06-26 00:39:45.714321224 +0900 -@@ -110,12 +110,17 @@ - - static inline int is_pulse(lirc_t data) - { -- return data & PULSE_BIT ? 1 : 0; -+ return ((data & LIRC_MODE2_MASK)==LIRC_MODE2_PULSE) ? 1 : 0; - } - - static inline int is_space(lirc_t data) - { -- return !is_pulse(data); -+ return ((data & LIRC_MODE2_MASK)==LIRC_MODE2_SPACE) ? 1 : 0; -+} -+ -+static inline int is_timeout(lirc_t data) -+{ -+ return ((data & LIRC_MODE2_MASK)==LIRC_MODE2_TIMEOUT) ? 1 : 0; - } - - static inline int has_repeat(const struct ir_remote* remote) -diff -ruN lirc-0.10.1.orig/lib/irrecord.c lirc-0.10.1/lib/irrecord.c ---- lirc-0.10.1.orig/lib/irrecord.c 2017-09-10 17:52:19.000000000 +0900 -+++ lirc-0.10.1/lib/irrecord.c 2019-06-26 00:39:45.724320960 +0900 -@@ -1398,9 +1398,16 @@ - state->retval = 0; - return STS_LEN_TIMEOUT; - } -+ if (is_timeout(state->data)) { -+ return STS_LEN_AGAIN; -+ } - state->count++; - if (state->mode == MODE_GET_GAP) { -- state->sum += state->data & PULSE_MASK; -+ if (state->sum != 0 || is_pulse(state->data)) { -+ state->sum += state->data & PULSE_MASK; -+ }else{ -+ return STS_LEN_AGAIN; -+ } - if (state->average == 0 && is_space(state->data)) { - if (state->data > 100000) { - state->sum = 0; -@@ -1472,6 +1479,10 @@ - state->keypresses = lastmaxcount; - return STS_LEN_AGAIN; - } else if (state->mode == MODE_HAVE_GAP) { -+ if (state->count==1 && is_space(state->data)) { -+ state->count = 0; -+ return STS_LEN_AGAIN; -+ } - if (state->count <= MAX_SIGNALS) { - signals[state->count - 1] = state->data & PULSE_MASK; - } else { -@@ -1510,7 +1521,7 @@ - /* such long pulses may appear with - * crappy hardware (receiver? / remote?) - */ -- else { -+ else if(is_pulse(state->data)) { - remote->gap = 0; - return STS_LEN_NO_GAP_FOUND; - } -@@ -1811,22 +1822,24 @@ - - static int raw_data_ok(struct button_state* btn_state) - { -- int r; -+ int r = 0; - int ref; - -- if (!is_space(btn_state->data)) { -+ if (is_pulse(btn_state->data)) { - r = 0; -- } else if (is_const(&remote)) { -- if (remote.gap > btn_state->sum) { -- ref = (remote.gap - btn_state->sum); -- ref *= (100 - remote.eps); -- ref /= 100; -+ } else if (is_space(btn_state->data)) { -+ if (is_const(&remote)) { -+ if (remote.gap > btn_state->sum) { -+ ref = (remote.gap - btn_state->sum); -+ ref *= (100 - remote.eps); -+ ref /= 100; -+ } else { -+ ref = 0; -+ } -+ r = btn_state->data > ref; - } else { -- ref = 0; -+ r = btn_state->data > (remote.gap * (100 - remote.eps)) / 100; - } -- r = btn_state->data > ref; -- } else { -- r = btn_state->data > (remote.gap * (100 - remote.eps)) / 100; - } - return r; - } -@@ -1970,7 +1983,7 @@ - btn_state->data = remote.gap; - } - if (btn_state->count == 0) { -- if (!is_space(btn_state->data) -+ if (is_pulse(btn_state->data) - || btn_state->data < - remote.gap - remote.gap * remote.eps / - 100) { -diff -ruN lirc-0.10.1.orig/lib/lirc/ir_remote.h lirc-0.10.1/lib/lirc/ir_remote.h ---- lirc-0.10.1.orig/lib/lirc/ir_remote.h 2017-09-10 17:52:58.000000000 +0900 -+++ lirc-0.10.1/lib/lirc/ir_remote.h 2019-06-26 00:39:45.724320960 +0900 -@@ -110,12 +110,17 @@ - - static inline int is_pulse(lirc_t data) - { -- return data & PULSE_BIT ? 1 : 0; -+ return ((data & LIRC_MODE2_MASK)==LIRC_MODE2_PULSE) ? 1 : 0; - } - - static inline int is_space(lirc_t data) - { -- return !is_pulse(data); -+ return ((data & LIRC_MODE2_MASK)==LIRC_MODE2_SPACE) ? 1 : 0; -+} -+ -+static inline int is_timeout(lirc_t data) -+{ -+ return ((data & LIRC_MODE2_MASK)==LIRC_MODE2_TIMEOUT) ? 1 : 0; - } - - static inline int has_repeat(const struct ir_remote* remote) -diff -ruN lirc-0.10.1.orig/tools/mode2.cpp lirc-0.10.1/tools/mode2.cpp ---- lirc-0.10.1.orig/tools/mode2.cpp 2017-09-10 17:52:19.000000000 +0900 -+++ lirc-0.10.1/tools/mode2.cpp 2019-06-26 00:45:38.840404976 +0900 -@@ -326,12 +326,24 @@ - void print_mode2_data(unsigned int data) - { - static int bitno = 1; -+ static bool leading_space = true; -+ unsigned int msg = data & LIRC_MODE2_MASK; - - switch (opt_dmode) { - case 0: -- printf("%s %u\n", ( -- data & PULSE_BIT) ? "pulse" : "space", -- (uint32_t)(data & PULSE_MASK)); -+ if (leading_space && msg == LIRC_MODE2_SPACE ) { -+ break; -+ } else { -+ leading_space = false; -+ } -+ if (msg == LIRC_MODE2_PULSE) { -+ printf("pulse %u\n", (__u32)(data & PULSE_MASK)); -+ } else if (msg == LIRC_MODE2_SPACE) { -+ printf("space %u\n", (__u32)(data & PULSE_MASK)); -+ } else if (msg == LIRC_MODE2_TIMEOUT) { -+ printf("timeout %u\n", (__u32)(data & PULSE_MASK)); -+ leading_space = true; -+ } - break; - case 1: { - /* print output like irrecord raw config file data */ diff --git a/meta-raspberrypi/dynamic-layers/meta-python/recipes-connectivity/lirc/lirc_0.10.%.bbappend b/meta-raspberrypi/dynamic-layers/meta-python/recipes-connectivity/lirc/lirc_0.10.%.bbappend index 22f8ce4107..0ccd4f701e 100644 --- a/meta-raspberrypi/dynamic-layers/meta-python/recipes-connectivity/lirc/lirc_0.10.%.bbappend +++ b/meta-raspberrypi/dynamic-layers/meta-python/recipes-connectivity/lirc/lirc_0.10.%.bbappend @@ -1,6 +1,5 @@ FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:" SRC_URI:append:rpi = " \ - file://lirc-gpio-ir-0.10.patch \ file://lircd.service \ " diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0001-configure-fix-linking-on-RISC-V-ISA.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0001-configure-fix-linking-on-RISC-V-ISA.patch index ac96efad84..3be8f1e026 100644 --- a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0001-configure-fix-linking-on-RISC-V-ISA.patch +++ b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0001-configure-fix-linking-on-RISC-V-ISA.patch @@ -2,11 +2,17 @@ From: =?utf-8?q?R=C3=A9mi_Denis-Courmont?= <remi@remlab.net> Date: Sat, 16 Jun 2018 21:31:45 +0300 Subject: configure: fix linking on RISC-V ISA -Upstream-status: Pending +Upstream-Status: Inappropriate + +RPI-Distro repo forks original vlc and applies patches +to enable raspiberry pi support. + --- configure.ac | 1 + 1 file changed, 1 insertion(+) +diff --git a/configure.ac b/configure.ac +index 2037a9e..df26367 100644 --- a/configure.ac +++ b/configure.ac @@ -113,6 +113,7 @@ case "${host_os}" in diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0002-Revert-configure-Require-libmodplug-0.8.9.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0002-Revert-configure-Require-libmodplug-0.8.9.patch index 3dfcf853b0..61807b3e14 100644 --- a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0002-Revert-configure-Require-libmodplug-0.8.9.patch +++ b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0002-Revert-configure-Require-libmodplug-0.8.9.patch @@ -2,13 +2,18 @@ From: Sebastian Ramacher <sramacher@debian.org> Date: Mon, 19 Aug 2019 21:08:26 +0200 Subject: Revert "configure: Require libmodplug >= 0.8.9" -This reverts commit 48f014768dc22ecad23d0e9f53c38805a3aff832. +Upstream-Status: Inappropriate + +RPI-Distro repo forks original vlc and applies patches +to enable raspiberry pi support. -Upstream-status: Pending +This reverts commit 48f014768dc22ecad23d0e9f53c38805a3aff832. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) +diff --git a/configure.ac b/configure.ac +index df26367..b8580ec 100644 --- a/configure.ac +++ b/configure.ac @@ -2207,7 +2207,7 @@ AC_ARG_ENABLE(mod, diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0003-CVE-2022-41325.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0003-CVE-2022-41325.patch new file mode 100644 index 0000000000..41f7109679 --- /dev/null +++ b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0003-CVE-2022-41325.patch @@ -0,0 +1,83 @@ +From 4fcace61801f418786c42487c6b06b693ee87666 Mon Sep 17 00:00:00 2001 +From: Romain Vimont <rom1v@videolabs.io> +Date: Mon, 19 Sep 2022 17:17:01 +0200 +Subject: [PATCH] vnc: fix possible buffer overflow + +Upstream-Status: Inappropriate + +RPI-Distro repo forks original vlc and applies patches +to enable raspiberry pi support. + +Thanks to 0xMitsurugi [1] from Synacktiv [2] for the bug report and fix. + +[1] https://twitter.com/0xMitsurugi +[2] https://www.synacktiv.com/ + +Fixes #27335 + +(cherry picked from commit 5eb783fd44ed6298db3e38f7765f21c42e4405f9) +--- + modules/access/vnc.c | 23 ++++++++++++++++------- + 1 file changed, 16 insertions(+), 7 deletions(-) + +--- a/modules/access/vnc.c ++++ b/modules/access/vnc.c +@@ -33,6 +33,7 @@ + #ifdef HAVE_CONFIG_H + # include "config.h" + #endif ++#include <assert.h> + + #include <vlc_common.h> + #include <vlc_plugin.h> +@@ -115,7 +116,7 @@ + int i_cancel_state; + + rfbClient* p_client; +- int i_framebuffersize; ++ size_t i_framebuffersize; + block_t *p_block; + + float f_fps; +@@ -143,11 +144,16 @@ + p_sys->es = NULL; + } + +- int i_width = p_client->width; +- int i_height = p_client->height; +- int i_depth = p_client->format.bitsPerPixel; ++ assert(!(p_client->width & ~0xffff)); // fits in 16 bits ++ uint16_t i_width = p_client->width; + +- switch( i_depth ) ++ assert(!(p_client->height & ~0xffff)); // fits in 16 bits ++ uint16_t i_height = p_client->height; ++ ++ uint8_t i_bits_per_pixel = p_client->format.bitsPerPixel; ++ assert((i_bits_per_pixel & 0x7) == 0); // multiple of 8 ++ ++ switch( i_bits_per_pixel ) + { + case 8: + i_chroma = VLC_CODEC_RGB8; +@@ -180,7 +186,10 @@ + } + + /* Set up framebuffer */ +- p_sys->i_framebuffersize = i_width * i_height * i_depth / 8; ++ if (mul_overflow(i_width, i_height * (i_bits_per_pixel / 8), &p_sys->i_framebuffersize)) { ++ msg_Err(p_demux, "VNC framebuffersize overflow"); ++ return FALSE; ++ } + + /* Reuse unsent block */ + if ( p_sys->p_block ) +@@ -211,7 +220,7 @@ + fmt.video.i_frame_rate_base = 1000; + fmt.video.i_frame_rate = 1000 * p_sys->f_fps; + +- fmt.video.i_bits_per_pixel = i_depth; ++ fmt.video.i_bits_per_pixel = i_bits_per_pixel; + fmt.video.i_rmask = p_client->format.redMax << p_client->format.redShift; + fmt.video.i_gmask = p_client->format.greenMax << p_client->format.greenShift; + fmt.video.i_bmask = p_client->format.blueMax << p_client->format.blueShift; diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0003-mmal_20.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0004-mmal_20.patch index 6038d0ee39..ab317303d9 100644 --- a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0003-mmal_20.patch +++ b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0004-mmal_20.patch @@ -1,4 +1,7 @@ -Upstream-status: Pending +Upstream-Status: Inappropriate + +RPI-Distro repo forks original vlc and applies patches +to enable raspiberry pi support. --- a/configure.ac +++ b/configure.ac @@ -26,13 +29,13 @@ Upstream-status: Pending fi AM_CONDITIONAL([HAVE_MMAL], [test "${have_mmal}" = "yes"]) +AM_CONDITIONAL([HAVE_MMAL_AVCODEC], [test "${enable_mmal_avcodec}" = "yes"]) - + dnl dnl evas plugin --- a/include/vlc_fourcc.h +++ b/include/vlc_fourcc.h @@ -365,6 +365,11 @@ - + /* Broadcom MMAL opaque buffer type */ #define VLC_CODEC_MMAL_OPAQUE VLC_FOURCC('M','M','A','L') +#define VLC_CODEC_MMAL_ZC_SAND8 VLC_FOURCC('Z','S','D','8') @@ -40,7 +43,7 @@ Upstream-status: Pending +#define VLC_CODEC_MMAL_ZC_SAND30 VLC_FOURCC('Z','S','D','3') +#define VLC_CODEC_MMAL_ZC_I420 VLC_FOURCC('Z','4','2','0') +#define VLC_CODEC_MMAL_ZC_RGB32 VLC_FOURCC('Z','R','G','B') - + /* DXVA2 opaque video surface for use with D3D9 */ #define VLC_CODEC_D3D9_OPAQUE VLC_FOURCC('D','X','A','9') /* 4:2:0 8 bpc */ --- a/modules/hw/mmal/Makefile.am @@ -48,12 +51,12 @@ Upstream-status: Pending @@ -1,23 +1,57 @@ include $(top_srcdir)/modules/common.am mmaldir = $(pluginsdir)/mmal - + -AM_CFLAGS += $(CFLAGS_mmal) -AM_LDFLAGS += -rpath '$(mmaldir)' $(LDFLAGS_mmal) +AM_CFLAGS += -pthread $(CFLAGS_mmal) +AM_LDFLAGS += -pthread -rpath '$(mmaldir)' $(LDFLAGS_mmal) - + -libmmal_vout_plugin_la_SOURCES = vout.c mmal_picture.c mmal_picture.h +libmmal_vout_plugin_la_SOURCES = vout.c mmal_cma.c mmal_picture.c subpic.c\ + mmal_cma.h mmal_picture.h subpic.h transform_ops.h\ @@ -63,7 +66,7 @@ Upstream-status: Pending +libmmal_vout_plugin_la_LDFLAGS = $(AM_LDFLAGS) -lm -lX11 -lXrandr libmmal_vout_plugin_la_LIBADD = $(LIBS_mmal) mmal_LTLIBRARIES = libmmal_vout_plugin.la - + -libmmal_codec_plugin_la_SOURCES = codec.c +libmmal_codec_plugin_la_SOURCES = codec.c mmal_cma.c mmal_picture.c subpic.c\ + mmal_cma.h mmal_picture.h subpic.h transform_ops.h\ @@ -72,7 +75,7 @@ Upstream-status: Pending libmmal_codec_plugin_la_LDFLAGS = $(AM_LDFLAGS) libmmal_codec_plugin_la_LIBADD = $(LIBS_mmal) mmal_LTLIBRARIES += libmmal_codec_plugin.la - + -libmmal_deinterlace_plugin_la_SOURCES = deinterlace.c mmal_picture.c +libmmal_deinterlace_plugin_la_SOURCES = deinterlace.c mmal_picture.c mmal_cma.c\ + mmal_cma.h mmal_picture.h transform_ops.h\ @@ -517,7 +520,7 @@ Upstream-status: Pending @@ -26,267 +26,443 @@ #include "config.h" #endif - + +#include <stdatomic.h> + #include <vlc_common.h> @@ -526,17 +529,17 @@ Upstream-status: Pending #include <vlc_codec.h> +#include <vlc_filter.h> #include <vlc_threads.h> - + -#include <bcm_host.h> #include <interface/mmal/mmal.h> #include <interface/mmal/util/mmal_util.h> #include <interface/mmal/util/mmal_default_components.h> - + +#include <interface/vcsm/user-vcsm.h> + +#include "mmal_cma.h" #include "mmal_picture.h" - + +#include "subpic.h" +#include "blend_rgba_neon.h" + @@ -550,18 +553,18 @@ Upstream-status: Pending #define NUM_EXTRA_BUFFERS 5 +//#define NUM_EXTRA_BUFFERS 10 #define NUM_DECODER_BUFFER_HEADERS 30 - + -#define MIN_NUM_BUFFERS_IN_TRANSIT 2 +#define CONVERTER_BUFFERS 4 // Buffers on the output of the converter + +#define MMAL_SLICE_HEIGHT 16 +#define MMAL_ALIGN_W 32 +#define MMAL_ALIGN_H 16 - + #define MMAL_OPAQUE_NAME "mmal-opaque" #define MMAL_OPAQUE_TEXT N_("Decode frames directly into RPI VideoCore instead of host memory.") #define MMAL_OPAQUE_LONGTEXT N_("Decode frames directly into RPI VideoCore instead of host memory. This option must only be used with the MMAL video output plugin.") - + -static int OpenDecoder(decoder_t *dec); -static void CloseDecoder(decoder_t *dec); - @@ -580,7 +583,7 @@ Upstream-status: Pending +#define MMAL_ISP_NAME "mmal-isp" +#define MMAL_ISP_TEXT N_("Use mmal isp rather than hvs.") +#define MMAL_ISP_LONGTEXT N_("Use mmal isp rather than hvs. This may be faster but has no blend.") - + -struct decoder_sys_t { - bool opaque; +typedef struct decoder_sys_t @@ -593,11 +596,11 @@ Upstream-status: Pending + hw_mmal_port_pool_ref_t *ppr; MMAL_ES_FORMAT_T *output_format; - vlc_sem_t sem; - + + MMAL_STATUS_T err_stream; bool b_top_field_first; bool b_progressive; - + + bool b_flushed; + + vcsm_init_type_t vcsm_init_type; @@ -613,7 +616,7 @@ Upstream-status: Pending atomic_bool started; -}; +} decoder_sys_t; - + -/* Utilities */ -static int change_output_format(decoder_t *dec); -static int send_output_buffer(decoder_t *dec); @@ -627,7 +630,7 @@ Upstream-status: Pending -static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer); -static void input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer); -static void output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer); - + -static int OpenDecoder(decoder_t *dec) -{ - int ret = VLC_SUCCESS; @@ -647,12 +650,12 @@ Upstream-status: Pending + {{MMAL_PARAMETER_SUPPORTED_ENCODINGS, sizeof(((supported_mmal_enc_t *)0)->supported)}, {0}}, \ + -1 \ +} - + - if (dec->fmt_in.i_codec != VLC_CODEC_MPGV && - dec->fmt_in.i_codec != VLC_CODEC_H264) - return VLC_EGENERIC; +static supported_mmal_enc_t supported_decode_in_enc = SUPPORTED_MMAL_ENC_INIT; - + - sys = calloc(1, sizeof(decoder_sys_t)); - if (!sys) { - ret = VLC_ENOMEM; @@ -672,7 +675,7 @@ Upstream-status: Pending - dec->p_sys = sys; + return false; +} - + - sys->opaque = var_InheritBool(dec, MMAL_OPAQUE_NAME); - bcm_host_init(); +static bool set_and_test_enc_supported(supported_mmal_enc_t * const support, MMAL_PORT_T * port, const MMAL_FOURCC_T fcc) @@ -684,7 +687,7 @@ Upstream-status: Pending + else + support->n = (support->supported.header.size - sizeof(support->supported.header)) / + sizeof(support->supported.encodings[0]); - + - status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &sys->component); - if (status != MMAL_SUCCESS) { - msg_Err(dec, "Failed to create MMAL component %s (status=%"PRIx32" %s)", @@ -694,7 +697,7 @@ Upstream-status: Pending - } + return is_enc_supported(support, fcc); +} - + - sys->component->control->userdata = (struct MMAL_PORT_USERDATA_T *)dec; - status = mmal_port_enable(sys->component->control, control_port_cb); - if (status != MMAL_SUCCESS) { @@ -737,7 +740,7 @@ Upstream-status: Pending } + return 0; +} - + - sys->input = sys->component->input[0]; - sys->input->userdata = (struct MMAL_PORT_USERDATA_T *)dec; - if (dec->fmt_in.i_codec == VLC_CODEC_MPGV) @@ -776,7 +779,7 @@ Upstream-status: Pending + } + return 0; +} - + - if (dec->fmt_in.i_codec == VLC_CODEC_H264) { - if (dec->fmt_in.i_extra > 0) { - status = mmal_format_extradata_alloc(sys->input->format, @@ -804,7 +807,7 @@ Upstream-status: Pending } +} +#endif - + - status = mmal_port_format_commit(sys->input); - if (status != MMAL_SUCCESS) { - msg_Err(dec, "Failed to commit format for input port %s (status=%"PRIx32" %s)", @@ -822,7 +825,7 @@ Upstream-status: Pending - sys->input->buffer_size = sys->input->buffer_size_recommended; - sys->input->buffer_num = sys->input->buffer_num_recommended; +} - + - status = mmal_port_enable(sys->input, input_port_cb); - if (status != MMAL_SUCCESS) { - msg_Err(dec, "Failed to enable input port %s (status=%"PRIx32" %s)", @@ -830,7 +833,7 @@ Upstream-status: Pending - ret = VLC_EGENERIC; - goto out; - } - + - sys->output = sys->component->output[0]; - sys->output->userdata = (struct MMAL_PORT_USERDATA_T *)dec; +static void draw_corners(void * pic_buf, size_t pic_stride, unsigned int x, unsigned int y, unsigned int w, unsigned int h) @@ -846,7 +849,7 @@ Upstream-status: Pending + draw_line(pic_buf, pic_stride, x, y + h - 1, len, -(int)pic_stride); +} +#endif - + - if (sys->opaque) { - extra_buffers.hdr.id = MMAL_PARAMETER_EXTRA_BUFFERS; - extra_buffers.hdr.size = sizeof(MMAL_PARAMETER_UINT32_T); @@ -863,7 +866,7 @@ Upstream-status: Pending +{ + static const unsigned int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 0}; + const unsigned int * p = primes; - + - msg_Dbg(dec, "Activate zero-copy for output port"); - MMAL_PARAMETER_BOOLEAN_T zero_copy = { - { MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T) }, @@ -873,7 +876,7 @@ Upstream-status: Pending + if (num == 0 || den == 0) { + return (MMAL_RATIONAL_T){.num = 0, .den = 0}; + } - + - status = mmal_port_parameter_set(sys->output, &zero_copy.hdr); - if (status != MMAL_SUCCESS) { - msg_Err(dec, "Failed to set zero copy on port %s (status=%"PRIx32" %s)", @@ -889,7 +892,7 @@ Upstream-status: Pending } + return (MMAL_RATIONAL_T){.num = num, .den = den}; +} - + - status = mmal_port_enable(sys->output, output_port_cb); - if (status != MMAL_SUCCESS) { - msg_Err(dec, "Failed to enable output port %s (status=%"PRIx32" %s)", @@ -901,7 +904,7 @@ Upstream-status: Pending +static picture_t * alloc_opaque_pic(decoder_t * const dec, MMAL_BUFFER_HEADER_T * const buf) +{ + decoder_sys_t *const dec_sys = dec->p_sys; - + - status = mmal_component_enable(sys->component); - if (status != MMAL_SUCCESS) { - msg_Err(dec, "Failed to enable component %s (status=%"PRIx32" %s)", @@ -919,11 +922,11 @@ Upstream-status: Pending + msg_Err(dec, "%s: Empty buffer", __func__); + goto fail2; } - + - sys->input_pool = mmal_pool_create(sys->input->buffer_num, 0); + if ((pic->context = hw_mmal_gen_context(buf, dec_sys->ppr)) == NULL) + goto fail2; - + - if (sys->opaque) { - dec->fmt_out.i_codec = VLC_CODEC_MMAL_OPAQUE; - dec->fmt_out.video.i_chroma = VLC_CODEC_MMAL_OPAQUE; @@ -961,22 +964,22 @@ Upstream-status: Pending + msg_Err(dec, "MMAL error %"PRIx32" \"%s\"", status, + mmal_status_to_string(status)); } - + - dec->pf_decode = decode; - dec->pf_flush = flush_decoder; + mmal_buffer_header_release(buffer); +} - + - vlc_sem_init(&sys->sem, 0); +static void input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) +{ + block_t * const block = (block_t *)buffer->user_data; - + -out: - if (ret != VLC_SUCCESS) - CloseDecoder(dec); + (void)port; // Unused - + - return ret; +#if TRACE_ALL + msg_Dbg((decoder_t *)port->userdata, "<<< %s: cmd=%d, data=%p, len=%d/%d, pts=%lld", __func__, @@ -989,14 +992,14 @@ Upstream-status: Pending + if (block != NULL) + block_Release(block); } - + -static void CloseDecoder(decoder_t *dec) +static void decoder_output_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { - decoder_sys_t *sys = dec->p_sys; - MMAL_BUFFER_HEADER_T *buffer; + decoder_t * const dec = (decoder_t *)port->userdata; - + - if (!sys) + if (buffer->cmd == 0 && buffer->length != 0) + { @@ -1016,7 +1019,7 @@ Upstream-status: Pending + // Buffer released or attached to pic - do not release again return; + } - + - if (sys->component && sys->component->control->is_enabled) - mmal_port_disable(sys->component->control); + if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED) @@ -1024,7 +1027,7 @@ Upstream-status: Pending + decoder_sys_t * const sys = dec->p_sys; + MMAL_EVENT_FORMAT_CHANGED_T * const fmt = mmal_event_format_changed_get(buffer); + MMAL_ES_FORMAT_T * const format = mmal_format_alloc(); - + - if (sys->input && sys->input->is_enabled) - mmal_port_disable(sys->input); + if (format == NULL) @@ -1033,7 +1036,7 @@ Upstream-status: Pending + { + mmal_format_full_copy(format, fmt->format); + format->encoding = MMAL_ENCODING_OPAQUE; - + - if (sys->output && sys->output->is_enabled) - mmal_port_disable(sys->output); + // If no PAR in the stream - see if we've got one from the demux @@ -1057,17 +1060,17 @@ Upstream-status: Pending + d = 1; + } + } - + - if (sys->component && sys->component->is_enabled) - mmal_component_disable(sys->component); + format->es->video.par = rationalize_sar(n, d); + } - + - if (sys->input_pool) - mmal_pool_destroy(sys->input_pool); + if (sys->output_format != NULL) + mmal_format_free(sys->output_format); - + - if (sys->output_format) - mmal_format_free(sys->output_format); + sys->output_format = format; @@ -1077,7 +1080,7 @@ Upstream-status: Pending + char buf0[5]; + msg_Warn(dec, "Unexpected output cb event: %s", str_fourcc(buf0, buffer->cmd)); + } - + - if (sys->output_pool) - mmal_pool_destroy(sys->output_pool); + // If we get here then we were flushing (cmd == 0 && len == 0) or @@ -1087,13 +1090,13 @@ Upstream-status: Pending + buffer->user_data = NULL; + mmal_buffer_header_release(buffer); +} - + - if (sys->component) - mmal_component_release(sys->component); - + - vlc_sem_destroy(&sys->sem); - free(sys); - + - bcm_host_deinit(); +static void fill_output_port(decoder_t *dec) +{ @@ -1113,7 +1116,7 @@ Upstream-status: Pending + hw_mmal_port_pool_ref_fill(sys->ppr); + return; } - + static int change_output_format(decoder_t *dec) { MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T interlace_type; @@ -1122,7 +1125,7 @@ Upstream-status: Pending MMAL_STATUS_T status; - int pool_size; int ret = 0; - + +#if TRACE_ALL + msg_Dbg(dec, "%s: <<<", __func__); +#endif @@ -1132,7 +1135,7 @@ Upstream-status: Pending status = mmal_port_format_commit(sys->output); @@ -300,7 +476,9 @@ static int change_output_format(decoder_ } - + port_reset: +#if TRACE_ALL msg_Dbg(dec, "%s: Do full port reset", __func__); @@ -1142,7 +1145,7 @@ Upstream-status: Pending msg_Err(dec, "Failed to disable output port (status=%"PRIx32" %s)", @@ -310,6 +488,7 @@ port_reset: } - + mmal_format_full_copy(sys->output->format, sys->output_format); + status = mmal_port_format_commit(sys->output); @@ -1151,7 +1154,7 @@ Upstream-status: Pending @@ -318,18 +497,10 @@ port_reset: goto out; } - + - if (sys->opaque) { - sys->output->buffer_num = NUM_DECODER_BUFFER_HEADERS; - pool_size = NUM_DECODER_BUFFER_HEADERS; @@ -1163,7 +1166,7 @@ Upstream-status: Pending - + sys->output->buffer_num = NUM_DECODER_BUFFER_HEADERS; sys->output->buffer_size = sys->output->buffer_size_recommended; - + - status = mmal_port_enable(sys->output, output_port_cb); + status = mmal_port_enable(sys->output, decoder_output_cb); if (status != MMAL_SUCCESS) { @@ -1171,7 +1174,7 @@ Upstream-status: Pending status, mmal_status_to_string(status)); @@ -338,25 +509,14 @@ port_reset: } - + if (!atomic_load(&sys->started)) { - if (!sys->opaque) { - sys->output_pool = mmal_port_pool_create(sys->output, pool_size, 0); @@ -1179,7 +1182,7 @@ Upstream-status: Pending - } - atomic_store(&sys->started, true); - + /* we need one picture from vout for each buffer header on the output * port */ - dec->i_extra_picture_buffers = pool_size; @@ -1196,7 +1199,7 @@ Upstream-status: Pending msg_Dbg(dec, "Request %d extra pictures", dec->i_extra_picture_buffers); +#endif } - + apply_fmt: @@ -366,8 +526,8 @@ apply_fmt: dec->fmt_out.video.i_y_offset = sys->output->format->es->video.crop.y; @@ -1208,7 +1211,7 @@ Upstream-status: Pending + dec->fmt_out.video.i_sar_den = sys->output_format->es->video.par.den; dec->fmt_out.video.i_frame_rate = sys->output->format->es->video.frame_rate.num; dec->fmt_out.video.i_frame_rate_base = sys->output->format->es->video.frame_rate.den; - + @@ -382,12 +542,19 @@ apply_fmt: sys->b_progressive = (interlace_type.eMode == MMAL_InterlaceProgressive); sys->b_top_field_first = sys->b_progressive ? true : @@ -1220,7 +1223,7 @@ Upstream-status: Pending interlace_type.eMode); +#endif } - + + // Tell the rest of the world we have changed format + vlc_mutex_lock(&sys->pic_lock); + ret = decoder_UpdateVideoFormat(dec); @@ -1232,7 +1235,7 @@ Upstream-status: Pending @@ -395,144 +562,85 @@ out: return ret; } - + -static int send_output_buffer(decoder_t *dec) +static MMAL_STATUS_T +set_extradata_and_commit(decoder_t * const dec, decoder_sys_t * const sys) @@ -1244,7 +1247,7 @@ Upstream-status: Pending MMAL_STATUS_T status; - unsigned buffer_size = 0; - int ret = 0; - + - if (!sys->output->is_enabled) - return VLC_EGENERIC; - @@ -1318,7 +1321,7 @@ Upstream-status: Pending - return ret; + return status; } - + -static void fill_output_port(decoder_t *dec) +static MMAL_STATUS_T decoder_send_extradata(decoder_t * const dec, decoder_sys_t *const sys) { @@ -1341,7 +1344,7 @@ Upstream-status: Pending + buf->length = dec->fmt_in.i_extra; + buf->data = dec->fmt_in.p_extra; + buf->flags = MMAL_BUFFER_HEADER_FLAG_CONFIG; - + - if (sys->output_pool) { - max_buffers_in_transit = __MAX(sys->output_pool->headers_num, - MIN_NUM_BUFFERS_IN_TRANSIT); @@ -1357,7 +1360,7 @@ Upstream-status: Pending + } } - buffers_to_send = max_buffers_in_transit - atomic_load(&sys->output_in_transit); - + - if (buffers_to_send > buffers_available) - buffers_to_send = buffers_available; - @@ -1373,14 +1376,14 @@ Upstream-status: Pending - break; + return MMAL_SUCCESS; } - + static void flush_decoder(decoder_t *dec) { - decoder_sys_t *sys = dec->p_sys; - MMAL_BUFFER_HEADER_T *buffer; - MMAL_STATUS_T status; + decoder_sys_t *const sys = dec->p_sys; - + - msg_Dbg(dec, "Flushing decoder ports..."); - mmal_port_flush(sys->output); - mmal_port_flush(sys->input); @@ -1404,7 +1407,7 @@ Upstream-status: Pending + msg_Dbg(dec, "%s: >>>", __func__); +#endif } - + static int decode(decoder_t *dec, block_t *block) { decoder_sys_t *sys = dec->p_sys; @@ -1414,7 +1417,7 @@ Upstream-status: Pending - uint32_t flags = 0; + uint32_t flags = MMAL_BUFFER_HEADER_FLAG_FRAME_START; MMAL_STATUS_T status; - + +#if TRACE_ALL + msg_Dbg(dec, "<<< %s: %lld/%lld", __func__, block == NULL ? -1LL : block->i_dts, block == NULL ? -1LL : block->i_pts); +#endif @@ -1431,12 +1434,12 @@ Upstream-status: Pending @@ -541,18 +649,50 @@ static int decode(decoder_t *dec, block_ msg_Err(dec, "Failed to change output port format"); } - + - if (!block) - goto out; + if (block == NULL) + return VLCDEC_SUCCESS; - + /* * Check whether full flush is required */ @@ -1453,7 +1456,7 @@ Upstream-status: Pending block_Release(block); return VLCDEC_SUCCESS; } - + + // Reenable stuff if the last thing we did was flush + if (!sys->output->is_enabled && + (status = mmal_port_enable(sys->output, decoder_output_cb)) != MMAL_SUCCESS) @@ -1481,11 +1484,11 @@ Upstream-status: Pending + // reported the size & the output stages have been set up if (atomic_load(&sys->started)) fill_output_port(dec); - + @@ -563,18 +703,21 @@ static int decode(decoder_t *dec, block_ if (block->i_flags & BLOCK_FLAG_CORRUPTED) flags |= MMAL_BUFFER_HEADER_FLAG_CORRUPTED; - + - while (block && block->i_buffer > 0) { - buffer = mmal_queue_timedwait(sys->input_pool->queue, 100); + while (block != NULL) @@ -1506,7 +1509,7 @@ Upstream-status: Pending buffer->dts = block->i_dts; buffer->alloc_size = sys->input->buffer_size; + buffer->user_data = NULL; - + len = block->i_buffer; if (len > buffer->alloc_size) @@ -585,94 +728,1808 @@ static int decode(decoder_t *dec, block_ @@ -1522,7 +1525,7 @@ Upstream-status: Pending block = NULL; } buffer->flags = flags; - + +#if TRACE_ALL + msg_Dbg(dec, "%s: -- Send buffer: cmd=%d, data=%p, size=%d, len=%d, offset=%d, flags=%#x, pts=%lld, dts=%lld", __func__,\ + buffer->cmd, buffer->data, buffer->alloc_size, buffer->length, buffer->offset, @@ -1542,17 +1545,17 @@ Upstream-status: Pending + flags &= ~MMAL_BUFFER_HEADER_FLAG_FRAME_START; } + return VLCDEC_SUCCESS; - + -out: - if (need_flush) - flush_decoder(dec); +fail: + flush_decoder(dec); + return VLCDEC_ECRITICAL; - + - return VLCDEC_SUCCESS; } - + -static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) + +static void CloseDecoder(decoder_t *dec) @@ -1921,7 +1924,7 @@ Upstream-status: Pending +#if TRACE_ALL + msg_Dbg(p_filter, "%s: <<< cmd=%d, data=%p, pic=%p", __func__, buffer->cmd, buffer->data, buffer->user_data); +#endif - + if (buffer->cmd == MMAL_EVENT_ERROR) { - status = *(uint32_t *)buffer->data; - msg_Err(dec, "MMAL error %"PRIx32" \"%s\"", status, @@ -1932,10 +1935,10 @@ Upstream-status: Pending + msg_Err(p_filter, "MMAL error %"PRIx32" \"%s\"", status, mmal_status_to_string(status)); } - + mmal_buffer_header_release(buffer); } - + -static void input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) +static void conv_input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf) { @@ -1967,14 +1970,14 @@ Upstream-status: Pending + vlc_mutex_lock(&sys->lock); + pic_fifo_put(&sys->ret_pics, pic); + vlc_mutex_unlock(&sys->lock); - + - mmal_buffer_header_release(buffer); - if (block) - block_Release(block); - atomic_fetch_sub(&sys->input_in_transit, 1); vlc_sem_post(&sys->sem); } - + -static void output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) +static void conv_output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf) { @@ -2006,7 +2009,7 @@ Upstream-status: Pending - fmt = mmal_event_format_changed_get(buffer); + filter_t * const p_filter = (filter_t *)port->userdata; + filter_sys_t * const sys = p_filter->p_sys; - + - format = mmal_format_alloc(); - mmal_format_full_copy(format, fmt->format); +#if TRACE_ALL @@ -2016,7 +2019,7 @@ Upstream-status: Pending +#endif + if (buf->cmd == 0) { + picture_t * const pic = (picture_t *)buf->user_data; - + - if (sys->opaque) - format->encoding = MMAL_ENCODING_OPAQUE; + if (pic == NULL) { @@ -2713,9 +2716,9 @@ Upstream-status: Pending + if (use_isp || use_resizer) + return VLC_EGENERIC; + } - + - sys->output_format = format; - + - mmal_buffer_header_release(buffer); + if (use_resizer) { + // use resizer overrides use_isp @@ -3858,7 +3861,7 @@ Upstream-status: Pending @@ -26,11 +26,12 @@ #include "config.h" #endif - + -#include <vlc_picture_pool.h> +#include <stdatomic.h> + @@ -3867,31 +3870,31 @@ Upstream-status: Pending #include <vlc_plugin.h> #include <vlc_filter.h> -#include <vlc_atomic.h> - + #include "mmal_picture.h" - + @@ -39,468 +40,814 @@ #include <interface/mmal/util/mmal_util.h> #include <interface/mmal/util/mmal_default_components.h> - + -#define MIN_NUM_BUFFERS_IN_TRANSIT 2 +#define MMAL_DEINTERLACE_NO_QPU "mmal-deinterlace-no-qpu" +#define MMAL_DEINTERLACE_NO_QPU_TEXT N_("Do not use QPUs for advanced HD deinterlacing.") +#define MMAL_DEINTERLACE_NO_QPU_LONGTEXT N_("Do not make use of the QPUs to allow higher quality deinterlacing of HD content.") - + -#define MMAL_DEINTERLACE_QPU "mmal-deinterlace-adv-qpu" -#define MMAL_DEINTERLACE_QPU_TEXT N_("Use QPUs for advanced HD deinterlacing.") -#define MMAL_DEINTERLACE_QPU_LONGTEXT N_("Make use of the QPUs to allow higher quality deinterlacing of HD content.") +#define MMAL_DEINTERLACE_ADV "mmal-deinterlace-adv" +#define MMAL_DEINTERLACE_ADV_TEXT N_("Force advanced deinterlace") +#define MMAL_DEINTERLACE_ADV_LONGTEXT N_("Force advanced deinterlace") - + -static int Open(filter_t *filter); -static void Close(filter_t *filter); +#define MMAL_DEINTERLACE_FAST "mmal-deinterlace-fast" +#define MMAL_DEINTERLACE_FAST_TEXT N_("Force fast deinterlace") +#define MMAL_DEINTERLACE_FAST_LONGTEXT N_("Force fast deinterlace") - + -vlc_module_begin() - set_shortname(N_("MMAL deinterlace")) - set_description(N_("MMAL-based deinterlace filter plugin")) @@ -3915,7 +3918,7 @@ Upstream-status: Pending +#define MMAL_DEINTERLACE_FULL_RATE "mmal-deinterlace-full-rate" +#define MMAL_DEINTERLACE_FULL_RATE_TEXT N_("Full output framerate") +#define MMAL_DEINTERLACE_FULL_RATE_LONGTEXT N_("Full output framerate. 1 output frame for each interlaced field input") - + -struct filter_sys_t { + +typedef struct filter_sys_t @@ -3940,14 +3943,14 @@ Upstream-status: Pending + bool use_passthrough; + unsigned int seq_in; // Seq of next frame to submit (1-15) [Init=1] + unsigned int seq_out; // Seq of last frame received (1-15) [Init=15] - + - MMAL_QUEUE_T *filtered_pictures; - vlc_sem_t sem; + vcsm_init_type_t vcsm_init_type; - + - atomic_bool started; +} filter_sys_t; - + - /* statistics */ - int output_in_transit; - int input_in_transit; @@ -3958,9 +3961,9 @@ Upstream-status: Pending -static void output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer); -static picture_t *deinterlace(filter_t *filter, picture_t *picture); -static void flush(filter_t *filter); - + #define MMAL_COMPONENT_DEFAULT_DEINTERLACE "vc.ril.image_fx" - + -static int Open(filter_t *filter) +#define TRACE_ALL 0 + @@ -3975,7 +3978,7 @@ Upstream-status: Pending - bool use_qpu = var_InheritBool(filter, MMAL_DEINTERLACE_QPU); + filter_sys_t *const filter_sys = p_filter->p_sys; + picture_t * const pic = filter_NewPicture(p_filter); - + - MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imfx_param = { - { MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, sizeof(imfx_param) }, - MMAL_PARAM_IMAGEFX_DEINTERLACE_ADV, @@ -3984,7 +3987,7 @@ Upstream-status: Pending - }; + if (pic == NULL) + goto fail1; - + - int ret = VLC_SUCCESS; - MMAL_STATUS_T status; - filter_sys_t *sys; @@ -3992,28 +3995,28 @@ Upstream-status: Pending + msg_Err(p_filter, "%s: Empty buffer", __func__); + goto fail2; + } - + - msg_Dbg(filter, "Try to open mmal_deinterlace filter. frame_duration: %d, QPU %s!", - frame_duration, use_qpu ? "used" : "unused"); + if ((pic->context = hw_mmal_gen_context(buf, filter_sys->out_ppr)) == NULL) + goto fail2; - + - if (filter->fmt_in.video.i_chroma != VLC_CODEC_MMAL_OPAQUE) - return VLC_EGENERIC; + buf_to_pic_copy_props(pic, buf); - + - if (filter->fmt_out.video.i_chroma != VLC_CODEC_MMAL_OPAQUE) - return VLC_EGENERIC; +#if TRACE_ALL + msg_Dbg(p_filter, "pic: prog=%d, tff=%d, date=%lld", pic->b_progressive, pic->b_top_field_first, (long long)pic->date); +#endif - + - sys = calloc(1, sizeof(filter_sys_t)); - if (!sys) - return VLC_ENOMEM; - filter->p_sys = sys; + return pic; - + - bcm_host_init(); +fail2: + picture_Release(pic); @@ -4021,7 +4024,7 @@ Upstream-status: Pending +// mmal_buffer_header_release(buf); + return NULL; +} - + - status = mmal_component_create(MMAL_COMPONENT_DEFAULT_DEINTERLACE, &sys->component); - if (status != MMAL_SUCCESS) { - msg_Err(filter, "Failed to create MMAL component %s (status=%"PRIx32" %s)", @@ -4040,7 +4043,7 @@ Upstream-status: Pending +#else + VLC_UNUSED(port); +#endif - + - status = mmal_port_parameter_set(sys->component->output[0], &imfx_param.hdr); - if (status != MMAL_SUCCESS) { - msg_Err(filter, "Failed to configure MMAL component %s (status=%"PRIx32" %s)", @@ -4049,7 +4052,7 @@ Upstream-status: Pending - goto out; - } + mmal_buffer_header_release(buffer); - + - sys->component->control->userdata = (struct MMAL_PORT_USERDATA_T *)filter; - status = mmal_port_enable(sys->component->control, control_port_cb); - if (status != MMAL_SUCCESS) { @@ -4080,7 +4083,7 @@ Upstream-status: Pending +#endif + return; } - + - sys->input = sys->component->input[0]; - sys->input->userdata = (struct MMAL_PORT_USERDATA_T *)filter; - if (filter->fmt_in.i_codec == VLC_CODEC_MMAL_OPAQUE) @@ -4096,10 +4099,10 @@ Upstream-status: Pending + mmal_buffer_header_reset(buf); // User data stays intact so release will kill pic + mmal_buffer_header_release(buf); +} - + - es_format_Copy(&filter->fmt_out, &filter->fmt_in); - filter->fmt_out.video.i_frame_rate *= 2; - + - status = mmal_port_format_commit(sys->input); - if (status != MMAL_SUCCESS) { - msg_Err(filter, "Failed to commit format for input port %s (status=%"PRIx32" %s)", @@ -4109,7 +4112,7 @@ Upstream-status: Pending - } - sys->input->buffer_size = sys->input->buffer_size_recommended; - sys->input->buffer_num = sys->input->buffer_num_recommended; - + - if (filter->fmt_in.i_codec == VLC_CODEC_MMAL_OPAQUE) { - MMAL_PARAMETER_BOOLEAN_T zero_copy = { - { MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T) }, @@ -4118,7 +4121,7 @@ Upstream-status: Pending +static MMAL_STATUS_T fill_output_from_q(filter_t * const p_filter, filter_sys_t * const sys, MMAL_QUEUE_T * const q) +{ + MMAL_BUFFER_HEADER_T * out_buf; - + - status = mmal_port_parameter_set(sys->input, &zero_copy.hdr); - if (status != MMAL_SUCCESS) { - msg_Err(filter, "Failed to set zero copy on port %s (status=%"PRIx32" %s)", @@ -4136,7 +4139,7 @@ Upstream-status: Pending } + return MMAL_SUCCESS; +} - + - status = mmal_port_enable(sys->input, input_port_cb); - if (status != MMAL_SUCCESS) { - msg_Err(filter, "Failed to enable input port %s (status=%"PRIx32" %s)", @@ -4149,14 +4152,14 @@ Upstream-status: Pending +static MMAL_BOOL_T out_buffer_pre_release_cb(MMAL_BUFFER_HEADER_T *header, void *userdata) +{ + VLC_UNUSED(userdata); - + - sys->output = sys->component->output[0]; - sys->output->userdata = (struct MMAL_PORT_USERDATA_T *)filter; - mmal_format_full_copy(sys->output->format, sys->input->format); + cma_buf_t * const cb = header->user_data; + header->user_data = NULL; + cma_buf_unref(cb); // Copes fine with NULL - + - status = mmal_port_format_commit(sys->output); - if (status != MMAL_SUCCESS) { - msg_Err(filter, "Failed to commit format for output port %s (status=%"PRIx32" %s)", @@ -4240,7 +4243,7 @@ Upstream-status: Pending + goto fail; + } + mmal_buffer_header_reset(out_buf); - + - sys->output->buffer_num = 3; + // Attach cma_buf to the buffer & ensure it is freed when the buffer is released + // On a good send callback the pic will be extracted to avoid this @@ -4264,7 +4267,7 @@ Upstream-status: Pending + p_pic, out_buf->data, out_buf->user_data, out_buf->flags, + out_buf->length, out_buf->alloc_size, (long long)out_buf->pts); +#endif - + - if (filter->fmt_in.i_codec == VLC_CODEC_MMAL_OPAQUE) { - MMAL_PARAMETER_UINT32_T extra_buffers = { - { MMAL_PARAMETER_EXTRA_BUFFERS, sizeof(MMAL_PARAMETER_UINT32_T) }, @@ -4282,7 +4285,7 @@ Upstream-status: Pending } + out_buf = NULL; + } - + - MMAL_PARAMETER_BOOLEAN_T zero_copy = { - { MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T) }, - 1 @@ -4297,7 +4300,7 @@ Upstream-status: Pending + msg_Err(p_filter, "Pic has not attached buffer"); + goto fail; + } - + - status = mmal_port_parameter_set(sys->output, &zero_copy.hdr); - if (status != MMAL_SUCCESS) { - msg_Err(filter, "Failed to set zero copy on port %s (status=%"PRIx32" %s)", @@ -4317,7 +4320,7 @@ Upstream-status: Pending + goto fail; } } - + - status = mmal_port_enable(sys->output, output_port_cb); - if (status != MMAL_SUCCESS) { - msg_Err(filter, "Failed to enable output port %s (status=%"PRIx32" %s)", @@ -4410,7 +4413,7 @@ Upstream-status: Pending + // Crash on lockup + assert(ret_pics != NULL || seq_delta(sys->seq_in, sys->seq_out) < 5); } - + - status = mmal_component_enable(sys->component); - if (status != MMAL_SUCCESS) { - msg_Err(filter, "Failed to enable component %s (status=%"PRIx32" %s)", @@ -4471,20 +4474,20 @@ Upstream-status: Pending + // Leaving the input disabled is fine - but we want to leave the output enabled + // so we can retrieve buffers that are still bound to pictures } - + - sys->filtered_pictures = mmal_queue_create(); + sys->seq_in = 1; + sys->seq_out = 15; - + - filter->pf_video_filter = deinterlace; - filter->pf_flush = flush; +#if TRACE_ALL + msg_Dbg(p_filter, ">>> %s", __func__); +#endif +} - + - vlc_sem_init(&sys->sem, 0); - + -out: - if (ret != VLC_SUCCESS) - Close(filter); @@ -4493,7 +4496,7 @@ Upstream-status: Pending + // Nothing to do + VLC_UNUSED(p_filter); +} - + - return ret; +static picture_t * pass_deinterlace(filter_t * p_filter, picture_t * p_pic) +{ @@ -4502,7 +4505,7 @@ Upstream-status: Pending + p_pic->b_progressive = true; + return p_pic; } - + -static void Close(filter_t *filter) + +static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) @@ -4511,7 +4514,7 @@ Upstream-status: Pending - MMAL_BUFFER_HEADER_T *buffer; + filter_t *filter = (filter_t *)port->userdata; + MMAL_STATUS_T status; - + - if (!sys) + if (buffer->cmd == MMAL_EVENT_ERROR) { + status = *(uint32_t *)buffer->data; @@ -4533,7 +4536,7 @@ Upstream-status: Pending + + if (sys == NULL) return; - + - if (sys->component && sys->component->control->is_enabled) - mmal_port_disable(sys->component->control); + if (sys->use_passthrough) @@ -4541,19 +4544,19 @@ Upstream-status: Pending + free(sys); + return; + } - + - if (sys->input && sys->input->is_enabled) - mmal_port_disable(sys->input); + di_flush(filter); - + - if (sys->output && sys->output->is_enabled) - mmal_port_disable(sys->output); + if (sys->component && sys->component->control->is_enabled) + mmal_port_disable(sys->component->control); - + if (sys->component && sys->component->is_enabled) mmal_component_disable(sys->component); - + - while ((buffer = mmal_queue_get(sys->filtered_pictures))) { - picture_t *pic = (picture_t *)buffer->user_data; - picture_Release(pic); @@ -4575,22 +4578,22 @@ Upstream-status: Pending + if (sys->out_pool != NULL) + mmal_pool_destroy(sys->out_pool); } - + - if (sys->filtered_pictures) - mmal_queue_destroy(sys->filtered_pictures); + if (sys->out_q != NULL) + mmal_queue_destroy(sys->out_q); - + if (sys->component) mmal_component_release(sys->component); - + - vlc_sem_destroy(&sys->sem); + cma_vcsm_exit(sys->vcsm_init_type); + free(sys); +} + - + - bcm_host_deinit(); +static bool is_fmt_valid_in(const vlc_fourcc_t fmt) +{ @@ -4598,7 +4601,7 @@ Upstream-status: Pending + fmt == VLC_CODEC_MMAL_ZC_I420 || + fmt == VLC_CODEC_MMAL_ZC_SAND8; } - + -static int send_output_buffer(filter_t *filter) +static int OpenMmalDeinterlace(filter_t *filter) { @@ -4619,7 +4622,7 @@ Upstream-status: Pending + if (!is_fmt_valid_in(filter->fmt_in.video.i_chroma) || + filter->fmt_out.video.i_chroma != filter->fmt_in.video.i_chroma) + return VLC_EGENERIC; - + - if (!sys->output->is_enabled) { - ret = VLC_EGENERIC; - goto out; @@ -4665,7 +4668,7 @@ Upstream-status: Pending + msg_Warn(filter, "Deinterlace bypassed due to lack of GPU memory"); + } } - + - picture = filter_NewPicture(filter); - if (!picture) { - msg_Warn(filter, "Failed to get new picture"); @@ -4717,7 +4720,7 @@ Upstream-status: Pending } - picture->format.i_frame_rate = filter->fmt_out.video.i_frame_rate; - picture->format.i_frame_rate_base = filter->fmt_out.video.i_frame_rate_base; - + - buffer = picture->p_sys->buffer; - buffer->user_data = picture; - buffer->cmd = 0; @@ -4727,7 +4730,7 @@ Upstream-status: Pending + MMAL_COMPONENT_DEFAULT_DEINTERLACE, status, mmal_status_to_string(status)); + goto fail; + } - + - mmal_picture_lock(picture); + { + const MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imfx_param = { @@ -4738,7 +4741,7 @@ Upstream-status: Pending + 4, + { 5 /* Frame type: mixed */, frame_duration, sys->half_rate, sys->use_qpu } + }; - + - status = mmal_port_send_buffer(sys->output, buffer); + status = mmal_port_parameter_set(sys->component->output[0], &imfx_param.hdr); + if (status != MMAL_SUCCESS) { @@ -4763,7 +4766,7 @@ Upstream-status: Pending + sys->component->control->name, status, mmal_status_to_string(status)); + goto fail; } - + -out: - return ret; -} @@ -4771,7 +4774,7 @@ Upstream-status: Pending + sys->input->userdata = (struct MMAL_PORT_USERDATA_T *)filter; + sys->input->format->encoding = vlc_to_mmal_video_fourcc(&filter->fmt_in.video); + hw_mmal_vlc_fmt_to_mmal_fmt(sys->input->format, &filter->fmt_in.video); - + -static void fill_output_port(filter_t *filter) -{ - filter_sys_t *sys = filter->p_sys; @@ -4785,7 +4788,7 @@ Upstream-status: Pending + es_format_Copy(&filter->fmt_out, &filter->fmt_in); + if (!sys->half_rate) + filter->fmt_out.video.i_frame_rate *= 2; - + - if (buffers_to_send > buffers_available) - buffers_to_send = buffers_available; + status = mmal_port_format_commit(sys->input); @@ -4797,7 +4800,7 @@ Upstream-status: Pending + sys->input->buffer_size = sys->input->buffer_size_recommended; + sys->input->buffer_num = 30; +// sys->input->buffer_num = sys->input->buffer_num_recommended; - + -#ifndef NDEBUG - msg_Dbg(filter, "Send %d buffers to output port (available: %d, in_transit: %d, buffer_num: %d)", - buffers_to_send, buffers_available, sys->output_in_transit, @@ -4812,7 +4815,7 @@ Upstream-status: Pending + goto fail; } -} - + -static picture_t *deinterlace(filter_t *filter, picture_t *picture) -{ - filter_sys_t *sys = filter->p_sys; @@ -4827,7 +4830,7 @@ Upstream-status: Pending + sys->input->name, status, mmal_status_to_string(status)); + goto fail; + } - + - fill_output_port(filter); + status = mmal_port_enable(sys->input, di_input_port_cb); + if (status != MMAL_SUCCESS) { @@ -4835,12 +4838,12 @@ Upstream-status: Pending + sys->input->name, status, mmal_status_to_string(status)); + goto fail; + } - + - buffer = picture->p_sys->buffer; - buffer->user_data = picture; - buffer->pts = picture->date; - buffer->cmd = 0; - + - if (!picture->p_sys->displayed) { - status = mmal_port_send_buffer(sys->input, buffer); - if (status != MMAL_SUCCESS) { @@ -4881,7 +4884,7 @@ Upstream-status: Pending } - if (out_picture) - out_picture->p_next = NULL; - + - return ret; -} - @@ -4891,7 +4894,7 @@ Upstream-status: Pending - MMAL_BUFFER_HEADER_T *buffer; + sys->output = sys->component->output[0]; + mmal_format_full_copy(sys->output->format, sys->input->format); - + - msg_Dbg(filter, "flush deinterlace filter"); + if (!sys->is_cma) + { @@ -4908,7 +4911,7 @@ Upstream-status: Pending + msg_Err(filter, "Failed to alloc cma buf pool"); + goto fail; + } - + - msg_Dbg(filter, "flush: flush ports (input: %d, output: %d in transit)", - sys->input_in_transit, sys->output_in_transit); - mmal_port_flush(sys->output); @@ -4934,13 +4937,13 @@ Upstream-status: Pending + msg_Err(filter, "Failed to alloc out pool"); + goto fail; + } - + -static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) -{ - filter_t *filter = (filter_t *)port->userdata; - MMAL_STATUS_T status; + port_parameter_set_bool(sys->output, MMAL_PARAMETER_ZERO_COPY, true); - + - if (buffer->cmd == MMAL_EVENT_ERROR) { - status = *(uint32_t *)buffer->data; - msg_Err(filter, "MMAL error %"PRIx32" \"%s\"", status, @@ -4951,12 +4954,12 @@ Upstream-status: Pending + msg_Err(filter, "Output port format commit failed"); + goto fail; + } - + - mmal_buffer_header_release(buffer); -} + sys->output->buffer_num = 30; + sys->output->buffer_size = sys->output->buffer_size_recommended; - + -static void input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) -{ - picture_t *picture = (picture_t *)buffer->user_data; @@ -4970,7 +4973,7 @@ Upstream-status: Pending + goto fail; + } + } - + - if (picture) { - picture_Release(picture); - } else { @@ -4982,7 +4985,7 @@ Upstream-status: Pending + sys->component->name, status, mmal_status_to_string(status)); + goto fail; } - + - atomic_fetch_sub(&sys->input_in_transit, 1); - vlc_sem_post(&sys->sem); + filter->pf_video_filter = deinterlace; @@ -4993,7 +4996,7 @@ Upstream-status: Pending + CloseMmalDeinterlace(filter); + return ret; } - + -static void output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) -{ - filter_t *filter = (filter_t *)port->userdata; @@ -5022,7 +5025,7 @@ Upstream-status: Pending + +vlc_module_end() + - + - if (buffer->cmd == 0) { - if (buffer->length > 0) { - atomic_store(&sys->started, true); @@ -8126,7 +8129,7 @@ Upstream-status: Pending @@ -21,25 +21,1542 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ - + +// We would really like to use vlc_thread.h but the detach thread stuff can't be +// used here :-( +#include <pthread.h> @@ -8148,7 +8151,7 @@ Upstream-status: Pending +#include <interface/mmal/util/mmal_default_components.h> +#include <interface/vmcs_host/vcgencmd.h> +#include <interface/vcsm/user-vcsm.h> - + +#include "mmal_cma.h" #include "mmal_picture.h" +#include "transform_ops.h" @@ -9291,7 +9294,7 @@ Upstream-status: Pending + ent = ent_list_extract_pic_ent(&pc->ents_cur, pic); + +// printf("ent_found: %p\n", ent); - + -int mmal_picture_lock(picture_t *picture) + if (ent == NULL) + { @@ -9523,7 +9526,7 @@ Upstream-status: Pending + case MMAL_ENCODING_RGB16: + pb = 2; + break; - + - int offset = 0; - picture->p[0].p_pixels = buffer->data; - for (int i = 1; i < picture->i_planes; i++) { @@ -9544,14 +9547,14 @@ Upstream-status: Pending +// msg_Err(p_filter, "%s: Unexpected format", __func__); + return VLC_EGENERIC; } - + - pic_sys->displayed = false; + // Fix up SAR if unset + if (pic->format.i_sar_den == 0 || pic->format.i_sar_num == 0) { + pic->format.i_sar_den = mm_fmt->par.den; + pic->format.i_sar_num = mm_fmt->par.num; + } - + + pic->i_planes = planes; + unsigned int offset = 0; + for (unsigned int i = 0; i != planes; ++i) { @@ -9680,17 +9683,17 @@ Upstream-status: Pending @@ -24,19 +24,298 @@ #ifndef VLC_MMAL_MMAL_PICTURE_H_ #define VLC_MMAL_MMAL_PICTURE_H_ - + +#include <stdatomic.h> + #include <vlc_common.h> #include <interface/mmal/mmal.h> - + +#include "mmal_cma.h" + /* Think twice before changing this. Incorrect values cause havoc. */ #define NUM_ACTUAL_OPAQUE_BUFFERS 30 - + -struct picture_sys_t { - vlc_object_t *owner; +#ifndef VLC_TICK_INVALID @@ -9969,18 +9972,18 @@ Upstream-status: Pending +vcsm_init_type_t cma_vcsm_type(void); +const char * cma_vcsm_init_str(const vcsm_init_type_t init_mode); + - + - MMAL_BUFFER_HEADER_T *buffer; - bool displayed; -}; +#define VOUT_DISPLAY_CHANGE_MMAL_BASE 1024 +#define VOUT_DISPLAY_CHANGE_MMAL_HIDE (VOUT_DISPLAY_CHANGE_MMAL_BASE + 0) - + -int mmal_picture_lock(picture_t *picture); +#define MMAL_COMPONENT_DEFAULT_RESIZER "vc.ril.resize" +#define MMAL_COMPONENT_ISP_RESIZER "vc.ril.isp" +#define MMAL_COMPONENT_HVS "vc.ril.hvs" - + #endif --- /dev/null +++ b/modules/hw/mmal/rpi_prof.h @@ -10879,17 +10882,17 @@ Upstream-status: Pending +++ b/modules/hw/mmal/vout.c @@ -27,21 +27,28 @@ #endif - + #include <math.h> +#include <stdatomic.h> - + #include <vlc_common.h> -#include <vlc_atomic.h> #include <vlc_plugin.h> #include <vlc_threads.h> #include <vlc_vout_display.h> +#include <vlc_modules.h> - + -#include "mmal_picture.h" - +#pragma GCC diagnostic push @@ -10907,13 +10910,13 @@ Upstream-status: Pending +#include "transform_ops.h" + +#define TRACE_ALL 0 - + #define MAX_BUFFERS_IN_TRANSIT 1 #define VC_TV_MAX_MODE_IDS 127 @@ -50,10 +57,28 @@ #define MMAL_LAYER_TEXT N_("VideoCore layer where the video is displayed.") #define MMAL_LAYER_LONGTEXT N_("VideoCore layer where the video is displayed. Subpictures are displayed directly above and a black background directly below.") - + -#define MMAL_BLANK_BACKGROUND_NAME "mmal-blank-background" -#define MMAL_BLANK_BACKGROUND_TEXT N_("Blank screen below video.") -#define MMAL_BLANK_BACKGROUND_LONGTEXT N_("Render blank screen below video. " \ @@ -10940,13 +10943,13 @@ Upstream-status: Pending +#define MMAL_VOUT_TRANSPARENT_LONGTEXT N_("Enable layers beneath the video layer."\ +" By default these are disabled."\ +" Having the lower layers enabled can impact video performance") - + #define MMAL_ADJUST_REFRESHRATE_NAME "mmal-adjust-refreshrate" #define MMAL_ADJUST_REFRESHRATE_TEXT N_("Adjust HDMI refresh rate to the video.") @@ -68,332 +93,628 @@ #define PHASE_OFFSET_TARGET ((double)0.25) #define PHASE_CHECK_INTERVAL 100 - + -static int Open(vlc_object_t *); -static void Close(vlc_object_t *); - @@ -10965,7 +10968,7 @@ Upstream-status: Pending - set_callbacks(Open, Close) -vlc_module_end() +#define SUBS_MAX 4 - + -struct dmx_region_t { - struct dmx_region_t *next; - picture_t *picture; @@ -10982,12 +10985,12 @@ Upstream-status: Pending + MMAL_COMPONENT_T *component; + subpic_reg_stash_t sub; +} vout_subpic_t; - + struct vout_display_sys_t { - vlc_cond_t buffer_cond; - vlc_mutex_t buffer_mutex; vlc_mutex_t manage_mutex; - + - plane_t planes[3]; /* Depending on video format up to 3 planes are used */ - picture_t **pictures; /* Actual list of alloced pictures passed into picture_pool */ - picture_pool_t *picture_pool; @@ -10998,11 +11001,11 @@ Upstream-status: Pending MMAL_POOL_T *pool; /* mmal buffer headers, used for pushing pictures to component*/ - struct dmx_region_t *dmx_region; int i_planes; /* Number of actually used planes, 1 for opaque, 3 for i420 */ - + - uint32_t buffer_size; /* size of actual mmal buffers */ int buffers_in_transit; /* number of buffers currently pushed to mmal component */ unsigned num_buffers; /* number of buffers allocated at mmal port */ - + - DISPMANX_DISPLAY_HANDLE_T dmx_handle; - DISPMANX_ELEMENT_HANDLE_T bkg_element; - DISPMANX_RESOURCE_HANDLE_T bkg_resource; @@ -11018,17 +11021,17 @@ Upstream-status: Pending + MMAL_DISPLAYTRANSFORM_T dest_transform; // Dest window coord transform + MMAL_DISPLAYTRANSFORM_T display_transform; // "Native" display transform + MMAL_DISPLAYTRANSFORM_T video_transform; // Combined config+native transform - + - int i_frame_rate_base; /* cached framerate to detect changes for rate adjustment */ - int i_frame_rate; + unsigned int i_frame_rate_base; /* cached framerate to detect changes for rate adjustment */ + unsigned int i_frame_rate; - + int next_phase_check; /* lowpass for phase check frequency */ int phase_offset; /* currently applied offset to presentation time in ns */ int layer; /* the dispman layer (z-index) used for video rendering */ + bool transparent; // Do not disable layers beneath ours - + bool need_configure_display; /* indicates a required display reconfigure to main thread */ bool adjust_refresh_rate; bool native_interlaced; @@ -11037,7 +11040,7 @@ Upstream-status: Pending - bool opaque; /* indicated use of opaque picture format (zerocopy) */ -}; + bool force_config; - + -static const vlc_fourcc_t subpicture_chromas[] = { - VLC_CODEC_RGBA, - 0 @@ -11058,14 +11061,14 @@ Upstream-status: Pending + MMAL_POOL_T * out_pool; + bool pending; + } isp; - + -/* Utility functions */ -static inline uint32_t align(uint32_t x, uint32_t y); -static int configure_display(vout_display_t *vd, const vout_display_cfg_t *cfg, - const video_format_t *fmt); + MMAL_POOL_T * copy_pool; + MMAL_BUFFER_HEADER_T * copy_buf; - + -/* VLC vout display callbacks */ -static picture_pool_t *vd_pool(vout_display_t *vd, unsigned count); -static void vd_prepare(vout_display_t *vd, picture_t *picture, @@ -11081,14 +11084,14 @@ Upstream-status: Pending + // Subpic blend if we have to do it here + vzc_pool_ctl_t * vzc; +}; - + -/* TV service */ -static int query_resolution(vout_display_t *vd, unsigned *width, unsigned *height); -static void tvservice_cb(void *callback_data, uint32_t reason, uint32_t param1, - uint32_t param2); -static void adjust_refresh_rate(vout_display_t *vd, const video_format_t *fmt); -static int set_latency_target(vout_display_t *vd, bool enable); - + -/* DispManX */ -static void display_subpicture(vout_display_t *vd, subpicture_t *subpicture); -static void close_dmx(vout_display_t *vd); @@ -11101,7 +11104,7 @@ Upstream-status: Pending -static void show_background(vout_display_t *vd, bool enable); -static void maintain_phase_sync(vout_display_t *vd); +// ISP setup - + -static int Open(vlc_object_t *object) +static inline bool want_isp(const vout_display_t * const vd) { @@ -11115,14 +11118,14 @@ Upstream-status: Pending - unsigned i; + return (vd->fmt.i_chroma == VLC_CODEC_MMAL_ZC_SAND10); +} - + - if (vout_display_IsWindowed(vd)) - return VLC_EGENERIC; +static inline bool want_copy(const vout_display_t * const vd) +{ + return (vd->fmt.i_chroma == VLC_CODEC_I420 || vd->fmt.i_chroma == VLC_CODEC_I420_10L); +} - + - sys = calloc(1, sizeof(struct vout_display_sys_t)); - if (!sys) - return VLC_ENOMEM; @@ -11133,7 +11136,7 @@ Upstream-status: Pending + VLC_CODEC_I420 : + vd->fmt.i_chroma; +} - + - sys->layer = var_InheritInteger(vd, MMAL_LAYER_NAME); - bcm_host_init(); +static MMAL_FOURCC_T vout_vlc_to_mmal_pic_fourcc(const unsigned int fcc) @@ -11155,14 +11158,14 @@ Upstream-status: Pending + } + return MMAL_ENCODING_I420; +} - + - sys->opaque = vd->fmt.i_chroma == VLC_CODEC_MMAL_OPAQUE; +static void display_set_format(const vout_display_t * const vd, MMAL_ES_FORMAT_T *const es_fmt, const bool is_intermediate) +{ + const unsigned int w = is_intermediate ? vd->fmt.i_visible_width : vd->fmt.i_width ; + const unsigned int h = is_intermediate ? vd->fmt.i_visible_height : vd->fmt.i_height; + MMAL_VIDEO_FORMAT_T * const v_fmt = &es_fmt->es->video; - + - status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &sys->component); - if (status != MMAL_SUCCESS) { - msg_Err(vd, "Failed to create MMAL component %s (status=%"PRIx32" %s)", @@ -11189,7 +11192,7 @@ Upstream-status: Pending + v_fmt->frame_rate.num = vd->fmt.i_frame_rate; + v_fmt->frame_rate.den = vd->fmt.i_frame_rate_base; + v_fmt->color_space = vlc_to_mmal_color_space(vd->fmt.space); - + - sys->component->control->userdata = (struct MMAL_PORT_USERDATA_T *)vd; - status = mmal_port_enable(sys->component->control, control_port_cb); - if (status != MMAL_SUCCESS) { @@ -11241,12 +11244,12 @@ Upstream-status: Pending + status = *(uint32_t *)buffer->data; + msg_Err(vd, "MMAL error %"PRIx32" \"%s\"", status, mmal_status_to_string(status)); } - + - sys->input = sys->component->input[0]; - sys->input->userdata = (struct MMAL_PORT_USERDATA_T *)vd; + mmal_buffer_header_release(buffer); +} - + - if (sys->opaque) { - sys->input->format->encoding = MMAL_ENCODING_OPAQUE; - sys->i_planes = 1; @@ -11276,7 +11279,7 @@ Upstream-status: Pending + // but might not on later flushes as we shut down + vout_display_t * const vd = (vout_display_t *)port->userdata; + struct vout_isp_conf_s *const isp = &vd->sys->isp; - + - status = mmal_port_format_commit(sys->input); - if (status != MMAL_SUCCESS) { - msg_Err(vd, "Failed to commit format for input port %s (status=%"PRIx32" %s)", @@ -11298,7 +11301,7 @@ Upstream-status: Pending + mmal_buffer_header_release(buf); + } +} - + - vout_display_PlacePicture(&place, &vd->source, vd->cfg, false); - display_region.hdr.id = MMAL_PARAMETER_DISPLAYREGION; - display_region.hdr.size = sizeof(MMAL_DISPLAYREGION_T); @@ -11355,7 +11358,7 @@ Upstream-status: Pending + return err; + } } - + - for (i = 0; i < sys->i_planes; ++i) { - sys->planes[i].i_lines = buffer_height; - sys->planes[i].i_pitch = buffer_pitch; @@ -11368,7 +11371,7 @@ Upstream-status: Pending + return err; + } + } - + - if (i > 0) { - sys->planes[i].i_lines /= 2; - sys->planes[i].i_pitch /= 2; @@ -11383,7 +11386,7 @@ Upstream-status: Pending } + return MMAL_SUCCESS; +} - + - vlc_mutex_init(&sys->buffer_mutex); - vlc_cond_init(&sys->buffer_cond); - vlc_mutex_init(&sys->manage_mutex); @@ -11391,7 +11394,7 @@ Upstream-status: Pending +{ + struct vout_isp_conf_s * const isp = &vd_sys->isp; + VLC_UNUSED(vd); - + - vd->pool = vd_pool; - vd->prepare = vd_prepare; - vd->display = vd_display; @@ -11399,10 +11402,10 @@ Upstream-status: Pending - vd->manage = vd_manage; + if (isp->component == NULL) + return; - + - vc_tv_register_callback(tvservice_cb, vd); + isp_flush(isp); - + - if (query_resolution(vd, &sys->display_width, &sys->display_height) >= 0) { - vout_display_SendEventDisplaySize(vd, sys->display_width, sys->display_height); - } else { @@ -11418,28 +11421,28 @@ Upstream-status: Pending + mmal_queue_destroy(isp->out_q); + isp->out_q = NULL; } - + - sys->dmx_handle = vc_dispmanx_display_open(0); - vd->info.subpicture_chromas = subpicture_chromas; + if (isp->out_pool != NULL) { + mmal_port_pool_destroy(isp->output, isp->out_pool); + isp->out_pool = NULL; + } - + - vout_display_DeleteWindow(vd, NULL); + isp->input = NULL; + isp->output = NULL; - + -out: - if (ret != VLC_SUCCESS) - Close(object); + mmal_component_release(isp->component); + isp->component = NULL; - + - return ret; + return; } - + -static void Close(vlc_object_t *object) +// Restuff into output rather than return to pool is we can +static MMAL_BOOL_T isp_out_pool_cb(MMAL_POOL_T *pool, MMAL_BUFFER_HEADER_T *buffer, void *userdata) @@ -11457,13 +11460,13 @@ Upstream-status: Pending + } + return MMAL_TRUE; +} - + - vc_tv_unregister_callback_full(tvservice_cb, vd); +static MMAL_STATUS_T isp_setup(vout_display_t * const vd, vout_display_sys_t * const vd_sys) +{ + struct vout_isp_conf_s * const isp = &vd_sys->isp; + MMAL_STATUS_T err; - + - if (sys->dmx_handle) - close_dmx(vd); + if ((err = mmal_component_create(MMAL_COMPONENT_ISP_RESIZER, &isp->component)) != MMAL_SUCCESS) { @@ -11472,7 +11475,7 @@ Upstream-status: Pending + } + isp->input = isp->component->input[0]; + isp->output = isp->component->output[0]; - + - if (sys->component && sys->component->control->is_enabled) - mmal_port_disable(sys->component->control); + isp->component->control->userdata = (void *)vd; @@ -11480,29 +11483,29 @@ Upstream-status: Pending + msg_Err(vd, "Failed to enable ISP control port"); + goto fail; + } - + - if (sys->input && sys->input->is_enabled) - mmal_port_disable(sys->input); + isp->input->userdata = (void *)vd; + display_set_format(vd, isp->input->format, false); - + - if (sys->component && sys->component->is_enabled) - mmal_component_disable(sys->component); + if ((err = port_parameter_set_bool(isp->input, MMAL_PARAMETER_ZERO_COPY, true)) != MMAL_SUCCESS) + goto fail; - + - if (sys->pool) - mmal_port_pool_destroy(sys->input, sys->pool); + if ((err = mmal_port_format_commit(isp->input)) != MMAL_SUCCESS) { + msg_Err(vd, "Failed to set ISP input format"); + goto fail; + } - + - if (sys->component) - mmal_component_release(sys->component); + isp->input->buffer_size = isp->input->buffer_size_recommended; + isp->input->buffer_num = 30; - + - if (sys->picture_pool) - picture_pool_Release(sys->picture_pool); - else @@ -11516,7 +11519,7 @@ Upstream-status: Pending + msg_Err(vd, "Failed to create input pool"); + goto fail; + } - + - vlc_mutex_destroy(&sys->buffer_mutex); - vlc_cond_destroy(&sys->buffer_cond); - vlc_mutex_destroy(&sys->manage_mutex); @@ -11525,7 +11528,7 @@ Upstream-status: Pending + err = MMAL_ENOMEM; + goto fail; + } - + - if (sys->native_interlaced) { - if (vc_gencmd(response, sizeof(response), "hvs_update_fields 0") < 0 || - response[18] != '0') @@ -11539,7 +11542,7 @@ Upstream-status: Pending + msg_Err(vd, "Failed to set ISP input format"); + goto fail; } - + - free(sys->pictures); - free(sys); + isp->output->buffer_size = isp->output->buffer_size_recommended; @@ -11558,13 +11561,13 @@ Upstream-status: Pending + goto fail; + + return MMAL_SUCCESS; - + - bcm_host_deinit(); +fail: + isp_close(vd, vd_sys); + return err; } - + -static inline uint32_t align(uint32_t x, uint32_t y) { - uint32_t mod = x % y; - if (mod == 0) @@ -11792,7 +11795,7 @@ Upstream-status: Pending + } + return 0; } - + static int configure_display(vout_display_t *vd, const vout_display_cfg_t *cfg, const video_format_t *fmt) { @@ -11801,7 +11804,7 @@ Upstream-status: Pending - MMAL_DISPLAYREGION_T display_region; + vout_display_sys_t * const sys = vd->sys; MMAL_STATUS_T status; - + if (!cfg && !fmt) + { + msg_Err(vd, "%s: Missing cfg & fmt", __func__); @@ -11809,17 +11812,17 @@ Upstream-status: Pending + } + + isp_check(vd, sys); - + if (fmt) { sys->input->format->es->video.par.num = fmt->i_sar_num; @@ -412,30 +733,14 @@ static int configure_display(vout_displa if (!cfg) cfg = vd->cfg; - + - vout_display_PlacePicture(&place, fmt, cfg, false); + sys->video_transform = combine_transform( + vlc_to_mmal_transform(fmt->orientation), sys->display_transform); - + - display_region.hdr.id = MMAL_PARAMETER_DISPLAYREGION; - display_region.hdr.size = sizeof(MMAL_DISPLAYREGION_T); - display_region.fullscreen = MMAL_FALSE; @@ -11843,7 +11846,7 @@ Upstream-status: Pending + if (set_input_region(vd, fmt) != 0) return -EINVAL; - } - + - show_background(vd, var_InheritBool(vd, MMAL_BLANK_BACKGROUND_NAME)); sys->adjust_refresh_rate = var_InheritBool(vd, MMAL_ADJUST_REFRESHRATE_NAME); sys->native_interlaced = var_InheritBool(vd, MMAL_NATIVE_INTERLACED); @@ -11851,7 +11854,7 @@ Upstream-status: Pending @@ -446,204 +751,217 @@ static int configure_display(vout_displa return 0; } - + +static void kill_pool(vout_display_sys_t * const sys) +{ + if (sys->pic_pool != NULL) { @@ -11870,21 +11873,21 @@ Upstream-status: Pending - MMAL_STATUS_T status; - unsigned i; + vout_display_sys_t * const sys = vd->sys; - + - if (sys->picture_pool) { - if (sys->num_buffers < count) - msg_Warn(vd, "Picture pool with %u pictures requested, but we already have one with %u pictures", - count, sys->num_buffers); + msg_Dbg(vd, "%s: fmt:%dx%d,sar:%d/%d; source:%dx%d", __func__, + vd->fmt.i_width, vd->fmt.i_height, vd->fmt.i_sar_num, vd->fmt.i_sar_den, vd->source.i_width, vd->source.i_height); - + - goto out; + if (sys->pic_pool == NULL) { + sys->pic_pool = picture_pool_NewFromFormat(&vd->fmt, count); } + return sys->pic_pool; +} - + - if (sys->opaque) { - if (count <= NUM_ACTUAL_OPAQUE_BUFFERS) - count = NUM_ACTUAL_OPAQUE_BUFFERS; @@ -11896,7 +11899,7 @@ Upstream-status: Pending + return true; + return false; +} - + - MMAL_PARAMETER_BOOLEAN_T zero_copy = { - { MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T) }, - 1 @@ -11906,7 +11909,7 @@ Upstream-status: Pending +{ + vout_display_sys_t * const sys = vd->sys; + MMAL_STATUS_T err; - + - status = mmal_port_parameter_set(sys->input, &zero_copy.hdr); - if (status != MMAL_SUCCESS) { - msg_Err(vd, "Failed to set zero copy on port %s (status=%"PRIx32" %s)", @@ -11930,7 +11933,7 @@ Upstream-status: Pending -#ifndef NDEBUG - msg_Dbg(vd, "Creating picture pool with %u pictures", count); #endif - + - sys->input->buffer_num = count; - status = mmal_port_enable(sys->input, input_port_cb); - if (status != MMAL_SUCCESS) { @@ -11942,7 +11945,7 @@ Upstream-status: Pending + if (subpicture != NULL) { + subpicture_Delete(subpicture); } - + - status = mmal_component_enable(sys->component); - if (status != MMAL_SUCCESS) { - msg_Err(vd, "Failed to enable component %s (status=%"PRIx32" %s)", @@ -12017,11 +12020,11 @@ Upstream-status: Pending + msg_Err(vd, "Replicated buffer get fail"); + goto fail; } - + - sys->pictures[i]->i_planes = sys->i_planes; - memcpy(sys->pictures[i]->p, sys->planes, sys->i_planes * sizeof(plane_t)); - } - + - memset(&picture_pool_cfg, 0, sizeof(picture_pool_configuration_t)); - picture_pool_cfg.picture_count = sys->num_buffers; - picture_pool_cfg.picture = sys->pictures; @@ -12035,7 +12038,7 @@ Upstream-status: Pending + if (mmal_port_format_commit(sys->input) != MMAL_SUCCESS) + msg_Warn(vd, "Input format commit failed"); + } - + - sys->picture_pool = picture_pool_NewExtended(&picture_pool_cfg); - if (!sys->picture_pool) { - msg_Err(vd, "Failed to create picture pool"); @@ -12047,7 +12050,7 @@ Upstream-status: Pending + goto fail; + } } - + -out: - return sys->picture_pool; -} @@ -12123,18 +12126,18 @@ Upstream-status: Pending - } else { - picture_Release(picture); } - + - display_subpicture(vd, subpicture); +fail: + for (unsigned int i = 0; i != SUBS_MAX && sys->subpic_bufs[i] != NULL; ++i) { + mmal_buffer_header_release(sys->subpic_bufs[i]); + sys->subpic_bufs[i] = NULL; + } - + - if (subpicture) - subpicture_Delete(subpicture); + picture_Release(p_pic); - + if (sys->next_phase_check == 0 && sys->adjust_refresh_rate) maintain_phase_sync(vd); sys->next_phase_check = (sys->next_phase_check + 1) % PHASE_CHECK_INTERVAL; @@ -12146,7 +12149,7 @@ Upstream-status: Pending - vlc_mutex_unlock(&sys->buffer_mutex); - } } - + static int vd_control(vout_display_t *vd, int query, va_list args) { - vout_display_sys_t *sys = vd->sys; @@ -12155,7 +12158,7 @@ Upstream-status: Pending + vout_display_sys_t * const sys = vd->sys; int ret = VLC_EGENERIC; + VLC_UNUSED(args); - + switch (query) { - case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: - tmp_cfg = va_arg(args, const vout_display_cfg_t *); @@ -12175,7 +12178,7 @@ Upstream-status: Pending + if (configure_display(vd, vd->cfg, &vd->source) >= 0) ret = VLC_SUCCESS; break; - + - case VOUT_DISPLAY_RESET_PICTURES: - vlc_assert_unreachable(); case VOUT_DISPLAY_CHANGE_ZOOM: @@ -12218,13 +12221,13 @@ Upstream-status: Pending + ret = VLC_SUCCESS; break; + } - + default: msg_Warn(vd, "Unknown control query %d", query); @@ -653,79 +971,207 @@ static int vd_control(vout_display_t *vd return ret; } - + +static void set_display_windows(vout_display_t *const vd, vout_display_sys_t *const sys) +{ + unsigned int width, height; @@ -12245,9 +12248,9 @@ Upstream-status: Pending - vout_display_sys_t *sys = vd->sys; - unsigned width, height; + vout_display_sys_t *const sys = vd->sys; - + vlc_mutex_lock(&sys->manage_mutex); - + if (sys->need_configure_display) { - close_dmx(vd); - sys->dmx_handle = vc_dispmanx_display_open(0); @@ -12261,10 +12264,10 @@ Upstream-status: Pending sys->need_configure_display = false; + set_display_windows(vd, sys); } - + vlc_mutex_unlock(&sys->manage_mutex); } - + -static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) + +static int attach_subpics(vout_display_t * const vd, vout_display_sys_t * const sys, @@ -12273,7 +12276,7 @@ Upstream-status: Pending - vout_display_t *vd = (vout_display_t *)port->userdata; - MMAL_STATUS_T status; + unsigned int n = 0; - + - if (buffer->cmd == MMAL_EVENT_ERROR) { - status = *(uint32_t *)buffer->data; - msg_Err(vd, "MMAL error %"PRIx32" \"%s\"", status, mmal_status_to_string(status)); @@ -12284,7 +12287,7 @@ Upstream-status: Pending + return VLC_ENOMEM; + } } - + - mmal_buffer_header_release(buffer); + // Attempt to import the subpics + for (subpicture_t * spic = subpicture; spic != NULL; spic = spic->p_next) @@ -12330,7 +12333,7 @@ Upstream-status: Pending + } + return VLC_SUCCESS; } - + -static void input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) + +static void vd_prepare(vout_display_t *vd, picture_t *p_pic, @@ -12425,12 +12428,12 @@ Upstream-status: Pending vout_display_sys_t *sys = vd->sys; - picture_t *picture = (picture_t *)buffer->user_data; + picture_sys_t *pic_sys = picture->p_sys; - + - if (picture) - picture_Release(picture); + if (!sys->adjust_refresh_rate || pic_sys->displayed) + return; - + - vlc_mutex_lock(&sys->buffer_mutex); - atomic_fetch_sub(&sys->buffers_in_transit, 1); - vlc_cond_signal(&sys->buffer_cond); @@ -12440,7 +12443,7 @@ Upstream-status: Pending + picture->date += sys->phase_offset; +#endif } - + -static int query_resolution(vout_display_t *vd, unsigned *width, unsigned *height) + +static void vd_control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) @@ -12449,7 +12452,7 @@ Upstream-status: Pending - int ret = 0; + vout_display_t *vd = (vout_display_t *)port->userdata; + MMAL_STATUS_T status; - + - if (vc_tv_get_display_state(&display_state) == 0) { - if (display_state.state & 0xFF) { - *width = display_state.display.hdmi.width; @@ -12468,23 +12471,23 @@ Upstream-status: Pending + status = *(uint32_t *)buffer->data; + msg_Err(vd, "MMAL error %"PRIx32" \"%s\"", status, mmal_status_to_string(status)); } - + - return ret; + mmal_buffer_header_release(buffer); } - + static void tvservice_cb(void *callback_data, uint32_t reason, uint32_t param1, uint32_t param2) @@ -780,9 +1226,9 @@ static void adjust_refresh_rate(vout_dis double best_score, score; int i; - + - vc_tv_get_display_state(&display_state); + vc_tv_get_display_state_id(sys->display_id, &display_state); if(display_state.display.hdmi.mode != HDMI_MODE_OFF) { - num_modes = vc_tv_hdmi_get_supported_modes_new(display_state.display.hdmi.group, + num_modes = vc_tv_hdmi_get_supported_modes_new_id(sys->display_id, display_state.display.hdmi.group, supported_modes, VC_TV_MAX_MODE_IDS, NULL, NULL); - + for (i = 0; i < num_modes; ++i) { @@ -810,7 +1256,7 @@ static void adjust_refresh_rate(vout_dis if((best_id >= 0) && (display_state.display.hdmi.mode != supported_modes[best_id].code)) { @@ -12498,7 +12501,7 @@ Upstream-status: Pending @@ -828,148 +1274,12 @@ static void adjust_refresh_rate(vout_dis } } - + -static void display_subpicture(vout_display_t *vd, subpicture_t *subpicture) -{ - vout_display_sys_t *sys = vd->sys; @@ -12648,7 +12651,7 @@ Upstream-status: Pending @@ -1012,32 +1322,436 @@ static void maintain_phase_sync(vout_dis } } - + -static void show_background(vout_display_t *vd, bool enable) +static void CloseMmalVout(vlc_object_t *object) { @@ -13700,7 +13703,7 @@ Upstream-status: Pending @@ -43,6 +43,8 @@ # include "../android/utils.h" #endif - + +#define REQUIRE_DMA_BUF_IMPORT 1 + typedef struct vlc_gl_sys_t @@ -13709,7 +13712,7 @@ Upstream-status: Pending @@ -355,6 +357,14 @@ static int Open (vlc_object_t *obj, cons goto error; } - + +#if REQUIRE_DMA_BUF_IMPORT + if (!CheckToken(ext, "EGL_EXT_image_dma_buf_import")) + { @@ -13728,7 +13731,7 @@ Upstream-status: Pending p_owner->b_waiting = false; vlc_cond_signal( &p_owner->wait_request ); + vlc_mutex_unlock( &p_owner->lock ); - + /* If the video output is paused or slow, or if the picture pool size was * under-estimated (e.g. greedy video filter, buggy decoder...), the @@ -2005,7 +2006,6 @@ void input_DecoderDelete( decoder_t *p_d @@ -13736,9 +13739,9 @@ Upstream-status: Pending if( p_owner->p_vout != NULL ) vout_Cancel( p_owner->p_vout, true ); - vlc_mutex_unlock( &p_owner->lock ); - + vlc_join( p_owner->thread, NULL ); - + --- a/src/misc/fourcc.c +++ b/src/misc/fourcc.c @@ -755,8 +755,13 @@ static const struct @@ -13762,7 +13765,7 @@ Upstream-status: Pending @@ -365,10 +365,30 @@ void picture_CopyProperties( picture_t * p_dst->b_top_field_first = p_src->b_top_field_first; } - + +static inline bool is_zc_chroma(const vlc_fourcc_t i_chroma) +{ + return i_chroma == VLC_CODEC_MMAL_OPAQUE || @@ -13789,15 +13792,15 @@ Upstream-status: Pending + for( int i = 0; i < p_src->i_planes; i++ ) + plane_CopyPixels( p_dst->p+i, p_src->p+i ); + } - + assert( p_dst->context == NULL ); - + --- a/src/video_output/video_output.c +++ b/src/video_output/video_output.c @@ -964,6 +964,17 @@ static picture_t *ConvertRGB32AndBlend(v return NULL; } - + + +static inline bool is_zc_chroma(const vlc_fourcc_t i_chroma) +{ @@ -13814,7 +13817,7 @@ Upstream-status: Pending vout_thread_sys_t *sys = vout->p; @@ -1098,7 +1109,7 @@ static int ThreadDisplayRenderPicture(vo } - + assert(vout_IsDisplayFiltered(vd) == !sys->display.use_dr); - if (sys->display.use_dr && !is_direct) { + if (sys->display.use_dr && !is_direct && !is_zc_chroma(todisplay->format.i_chroma)) { diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0004-mmal_exit_fix.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0005-mmal_exit_fix.patch index b8ac0a0ba3..d8fc7fbfe2 100644 --- a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0004-mmal_exit_fix.patch +++ b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0005-mmal_exit_fix.patch @@ -1,4 +1,7 @@ -Upstream-status: Pending +Upstream-Status: Inappropriate + +RPI-Distro repo forks original vlc and applies patches +to enable raspiberry pi support. --- a/bin/vlc.c +++ b/bin/vlc.c @@ -12,5 +15,5 @@ Upstream-status: Pending +// signal (SIGINT, SIG_DFL); + _exit(0); } - + /***************************************************************************** diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0006-Use-packageconfig-to-detect-mmal-support.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0006-Use-packageconfig-to-detect-mmal-support.patch deleted file mode 100644 index 3a2ac236c0..0000000000 --- a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0006-Use-packageconfig-to-detect-mmal-support.patch +++ /dev/null @@ -1,56 +0,0 @@ -From: Vincent Davis Jr <vince@underview.tech> -Date: Fri, 07 Jan 2022 07:10:47 PM CST -Subject: [PATCH] Use packageconfig to acquire mmal flags - -Need to use userland graphics libraries package files as it's best to not assume /opt/vc is where -all libs and headers are installed per distro. Also, needed to include $BCMHOST_MMAL_LIBS variable as -AC_CHECK_LIB(bcm_host) fails to find `vc_tv_unregister_callback_full`. Adding $BCMHOST_MMAL_LIBS uses all -libs inside bcm_host,mmal,vcsm,openmaxil .pc files when checking for `vc_tv_unregister_callback_full` -function. - -Upstream-status: Pending - -Signed-off-by: Vincent Davis Jr <vince@underview.tech> -diff --git a/configure.ac b/configure.ac -index bff220510..4d487409d 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -3483,23 +3483,25 @@ AC_ARG_ENABLE(mmal_avcodec, - [Use MMAL enabled avcodec libs (default disable)])) - if test "${enable_mmal}" != "no"; then - VLC_SAVE_FLAGS -- LDFLAGS="${LDFLAGS} -L/opt/vc/lib -lvchostif" -- CPPFLAGS="${CPPFLAGS} -isystem /opt/vc/include -isystem /opt/vc/include/interface/vcos/pthreads -isystem /opt/vc/include/interface/vmcs_host/linux" -- AC_CHECK_HEADERS(interface/mmal/mmal.h, -- [ AC_CHECK_LIB(bcm_host, vc_tv_unregister_callback_full, [ -+ PKG_CHECK_MODULES(BCMHOST_MMAL, [bcm_host mmal vcsm openmaxil egl], [ -+ HAVE_MMAL=yes -+ AC_CHECK_HEADERS(interface/mmal/mmal.h, -+ [ AC_CHECK_LIB(bcm_host $BCMHOST_MMAL_LIBS, vc_tv_unregister_callback_full, [ - have_mmal="yes" -- VLC_ADD_PLUGIN([mmal]) -- VLC_ADD_LDFLAGS([mmal],[ -L/opt/vc/lib ]) -- VLC_ADD_CFLAGS([mmal],[ -isystem /opt/vc/include -isystem /opt/vc/include/interface/vcos/pthreads -isystem /opt/vc/include/interface/vmcs_host/linux ]) -- VLC_ADD_LIBS([mmal],[ -lbcm_host -lmmal -lmmal_core -lmmal_components -lmmal_util -lvchostif -lvchiq_arm -lvcsm ]) ], [ -+ VLC_ADD_PLUGIN([bcm_host mmal vcsm openmaxil egl]) -+ VLC_ADD_CFLAGS([bcm_host mmal vcsm openmaxil egl],[$BCMHOST_MMAL_CFLAGS]) -+ VLC_ADD_LIBS([bcm_host mmal vcsm openmaxil egl],[$BCMHOST_MMAL_LIBS]) ], [ - AS_IF([test "${enable_mmal}" = "yes"], - [ AC_MSG_ERROR([Cannot find bcm library...]) ], - [ AC_MSG_WARN([Cannot find bcm library...]) ]) -- ], -- []) -- ] , [ AS_IF([test "${enable_mmal}" = "yes"], -- [ AC_MSG_ERROR([Cannot find development headers for mmal...]) ], -- [ AC_MSG_WARN([Cannot find development headers for mmal...]) ]) ]) -+ ],[]) -+ ],[ AS_IF([test "${enable_mmal}" = "yes"], -+ [ AC_MSG_ERROR([Cannot find development headers for mmal...]) ], -+ [ AC_MSG_WARN([Cannot find development headers for mmal...]) ]) ]) -+ ],:[ -+ AC_MSG_WARN([${BCMHOST_PKG_ERRORS}: userland graphics not available.]) -+ HAVE_MMAL=no -+ ]) - VLC_RESTORE_FLAGS - fi - AM_CONDITIONAL([HAVE_MMAL], [test "${have_mmal}" = "yes"]) diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0005-mmal_chain.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0006-mmal_chain.patch index abd31df562..99fd03e101 100644 --- a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0005-mmal_chain.patch +++ b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0006-mmal_chain.patch @@ -1,10 +1,13 @@ -Upstream-status: Pending +Upstream-Status: Inappropriate + +RPI-Distro repo forks original vlc and applies patches +to enable raspiberry pi support. --- a/modules/video_chroma/chain.c +++ b/modules/video_chroma/chain.c @@ -280,8 +280,9 @@ static int BuildTransformChain( filter_t return VLC_SUCCESS; - + /* Lets try resize+chroma first, then transform */ - msg_Dbg( p_filter, "Trying to build chroma+resize" ); - EsFormatMergeSize( &fmt_mid, &p_filter->fmt_out, &p_filter->fmt_in ); diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0007-armv6.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0007-armv6.patch new file mode 100644 index 0000000000..64a24268cf --- /dev/null +++ b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0007-armv6.patch @@ -0,0 +1,53 @@ +Upstream-Status: Inappropriate + +RPI-Distro repo forks original vlc and applies patches +to enable raspiberry pi support. + +--- a/modules/hw/mmal/blend_rgba_neon.S ++++ b/modules/hw/mmal/blend_rgba_neon.S +@@ -1,10 +1,10 @@ +- .syntax unified +- .arm +-// .thumb +- .text ++#include "../../arm_neon/asm.S" + .align 16 + .arch armv7-a +- .fpu neon-vfpv4 ++ .syntax unified ++#if HAVE_AS_FPU_DIRECTIVE ++ .fpu neon-vfpv4 ++#endif + + @ blend_rgbx_rgba_neon + +--- a/modules/hw/mmal/codec.c ++++ b/modules/hw/mmal/codec.c +@@ -29,6 +29,7 @@ + #include <stdatomic.h> + + #include <vlc_common.h> ++#include <vlc_cpu.h> + #include <vlc_plugin.h> + #include <vlc_codec.h> + #include <vlc_filter.h> +@@ -2311,6 +2312,9 @@ static int OpenBlendMmal(vlc_object_t *o + filter_t * const p_filter = (filter_t *)object; + const vlc_fourcc_t vfcc_dst = p_filter->fmt_out.video.i_chroma; + ++ if (!vlc_CPU_ARM_NEON()) ++ return VLC_EGENERIC; ++ + if (!hw_mmal_chroma_is_mmal(vfcc_dst) || + !hw_mmal_vzc_subpic_fmt_valid(&p_filter->fmt_in.video)) + { +@@ -2421,6 +2425,9 @@ static int OpenBlendNeon(vlc_object_t *o + MMAL_FOURCC_T mfcc_dst = vlc_to_mmal_video_fourcc(&p_filter->fmt_out.video); + blend_neon_fn * blend_fn = (blend_neon_fn *)0; + ++ if (!vlc_CPU_ARM_NEON()) ++ return VLC_EGENERIC; ++ + // Non-alpha RGB only for dest + if (vfcc_dst != VLC_CODEC_RGB32) + return VLC_EGENERIC; diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0007-use-vorbisidec.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0007-use-vorbisidec.patch deleted file mode 100644 index 18bdc4ddd1..0000000000 --- a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0007-use-vorbisidec.patch +++ /dev/null @@ -1,18 +0,0 @@ -* tremor provides libvorbisidec, use it instead of libvorbisdec - -Upstream-status: Pending - -Signed-off-by: Tim Orling <TicoTimo@gmail.com> - -Index: vlc-2.2.1/modules/codec/Makefile.am -=================================================================== ---- vlc-2.2.1.orig/modules/codec/Makefile.am -+++ vlc-2.2.1/modules/codec/Makefile.am -@@ -234,7 +234,7 @@ codec_LTLIBRARIES += $(LTLIBtheora) - libtremor_plugin_la_SOURCES = codec/vorbis.c - libtremor_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -DMODULE_NAME_IS_tremor - libtremor_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(codecdir)' --libtremor_plugin_la_LIBADD = -lvorbisdec -logg -+libtremor_plugin_la_LIBADD = -lvorbisidec -logg - EXTRA_LTLIBRARIES += libtremor_plugin.la - codec_LTLIBRARIES += $(LTLIBtremor) diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0010-fix-numeric_limits-is-not-a-member-of-std.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0010-fix-numeric_limits-is-not-a-member-of-std.patch deleted file mode 100644 index a13b337fe2..0000000000 --- a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0010-fix-numeric_limits-is-not-a-member-of-std.patch +++ /dev/null @@ -1,35 +0,0 @@ -From: Vincent Davis Jr <vince@underview.tech> -Date: Fri, 07 Jan 2022 07:10:47 PM CST -Subject: [PATCH] Fix numeric limits not a member - -* Fixes bellow compiler issue: - ../../git/modules/demux/adaptive/playlist/SegmentInformation.cpp:397:23: error: 'numeric_limits' is not a member of 'std' - 397 | if(number == std::numeric_limits<uint64_t>::max()) - -Upstream-status: Pending - -Signed-off-by: Vincent Davis Jr <vince@underview.tech> -diff --git a/modules/demux/adaptive/playlist/SegmentInformation.cpp b/modules/demux/adaptive/playlist/SegmentInformation.cpp -index 344e155c7..8eeb05439 100644 ---- a/modules/demux/adaptive/playlist/SegmentInformation.cpp -+++ b/modules/demux/adaptive/playlist/SegmentInformation.cpp -@@ -34,6 +34,7 @@ - - #include <algorithm> - #include <cassert> -+#include <limits> - - using namespace adaptive::playlist; - -diff --git a/modules/demux/hls/playlist/Parser.cpp b/modules/demux/hls/playlist/Parser.cpp -index 67110e4cd..743969922 100644 ---- a/modules/demux/hls/playlist/Parser.cpp -+++ b/modules/demux/hls/playlist/Parser.cpp -@@ -42,6 +42,7 @@ - #include <map> - #include <cctype> - #include <algorithm> -+#include <limits> - - using namespace adaptive; - using namespace adaptive::playlist; diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0008-fix-luaL-checkint.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/2001-fix-luaL-checkint.patch index 96b5d2d246..e8990fca60 100644 --- a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0008-fix-luaL-checkint.patch +++ b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/2001-fix-luaL-checkint.patch @@ -1,7 +1,10 @@ * luaL_checkint and luaL_optint were deprecated in lua 5.3 * replacement functions are luaL_checkinteger and luaL_optinteger -Upstream-status: Pending +Upstream-Status: Inappropriate + +RPI-Distro repo forks original vlc and applies patches to enable +raspiberry pi support. Signed-off-by: Tim Orling <TicoTimo@gmail.com> diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/2002-use-vorbisidec.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/2002-use-vorbisidec.patch new file mode 100644 index 0000000000..bfabf21fa4 --- /dev/null +++ b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/2002-use-vorbisidec.patch @@ -0,0 +1,33 @@ +From d0a7ba506fd302ad195f79f287b5a5a154ac02a3 Mon Sep 17 00:00:00 2001 +From: Vincent Davis Jr <vince@underview.tech> +Date: Sun, 4 Dec 2022 16:09:51 -0600 +Subject: [PATCH] tremor provides libvorbisidec, use it instead of libvorbisdec + +Upstream-Status: Inappropriate + +RPI-Distro repo forks original vlc and applies patches to enable +raspiberry pi support. + +THIS PATCHES HAS BEEN REIMPLEMENTED INORDER TO APPLY PROPERLY. + +Signed-off-by: Tim Orling <TicoTimo@gmail.com> +--- + modules/codec/Makefile.am | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am +index 3dadf1119..8b6189e92 100644 +--- a/modules/codec/Makefile.am ++++ b/modules/codec/Makefile.am +@@ -324,7 +324,7 @@ codec_LTLIBRARIES += $(LTLIBdaala) + libtremor_plugin_la_SOURCES = codec/vorbis.c + libtremor_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -DMODULE_NAME_IS_tremor + libtremor_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(codecdir)' +-libtremor_plugin_la_LIBADD = -lvorbisdec -logg ++libtremor_plugin_la_LIBADD = -lvorbisidec -logg + EXTRA_LTLIBRARIES += libtremor_plugin.la + codec_LTLIBRARIES += $(LTLIBtremor) + +-- +2.38.1 + diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3001-configure.ac-setup-for-OE-usage.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3001-configure.ac-setup-for-OE-usage.patch new file mode 100644 index 0000000000..d676be39bf --- /dev/null +++ b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3001-configure.ac-setup-for-OE-usage.patch @@ -0,0 +1,124 @@ +From ddc2ea76058466b45a1acf37bed0d794cd3112a3 Mon Sep 17 00:00:00 2001 +From: Vincent Davis Jr <vince@underview.tech> +Date: Fri, 9 Dec 2022 19:04:42 -0600 +Subject: [PATCH] configure.ac: setup for OE usage + +Upstream-Status: Inappropriate + +RPI-Distro repo forks original vlc and applies patches to enable +raspiberry pi support. + +Need to use userland graphics libraries package files as it's best +to not assume /opt/vc is where all libs and headers are installed per +distro. Also, needed to include $BCMHOST_MMAL_LIBS variable as +AC_CHECK_LIB(bcm_host) fails to find `vc_tv_unregister_callback_full`. +Adding $BCMHOST_MMAL_LIBS uses all libs inside +bcm_host.pc, mmal.pc, vcsm.pc, openmaxil.pc files when checking +for `vc_tv_unregister_callback_full` function. + +Supposed to change linked version to opengl to GLESv2 + +Ensure correct package config file is used for: +* opencv +* freerdp + +Adds Workaround for modules/codec/omxil/omxil_core.h + multiple definition of `pf_enable_graphic_buffers' + multiple definition of `pf_get_graphic_buffer_usage' + multiple definition of `pf_get_hal_format' + +Signed-off-by: Vincent Davis Jr <vince@underview.tech> +--- + configure.ac | 34 ++++++++++++++++++++++------------ + 1 file changed, 22 insertions(+), 12 deletions(-) + +diff --git a/configure.ac b/configure.ac +index a72dca0b6..5b8585a26 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -95,6 +95,13 @@ AS_IF([test -n "${with_binary_version}"],[ + [Binary specific version]) + ]) + ++# Workaround for modules/codec/omxil/omxil_core.h ++# multiple definition of `pf_enable_graphic_buffers' ++# multiple definition of `pf_get_graphic_buffer_usage' ++# multiple definition of `pf_get_hal_format' ++AC_SUBST([AM_CXXFLAGS], [-fcommon]) ++AC_SUBST([AM_CFLAGS], [-fcommon]) ++ + dnl Prevent clang from accepting unknown flags with a mere warning + AX_APPEND_COMPILE_FLAGS([-Werror=unknown-warning-option -Werror=invalid-command-line-argument], [CFLAGS]) + AX_APPEND_COMPILE_FLAGS([-Werror=unknown-warning-option -Werror=invalid-command-line-argument], [CXXFLAGS]) +@@ -1900,7 +1907,7 @@ PKG_ENABLE_MODULES_VLC([BLURAY], [libbluray], [libbluray >= 0.6.2], (libbluray f + dnl + dnl OpenCV wrapper and example filters + dnl +-PKG_ENABLE_MODULES_VLC([OPENCV], [opencv_example opencv_wrapper], [opencv > 2.0], (OpenCV (computer vision) filter), [auto]) ++PKG_ENABLE_MODULES_VLC([OPENCV], [opencv_example opencv_wrapper], [opencv4 >= 2.0], (OpenCV (computer vision) filter), [auto]) + + + dnl +@@ -2077,7 +2084,7 @@ PKG_ENABLE_MODULES_VLC([VNC], [vnc], [libvncclient >= 0.9.9], (VNC/rfb client su + + dnl RDP/Remote Desktop access module + dnl +-PKG_ENABLE_MODULES_VLC([FREERDP], [rdp], [freerdp >= 1.0.1], (RDP/Remote Desktop client support) ) ++PKG_ENABLE_MODULES_VLC([FREERDP], [rdp], [freerdp2 >= 1.0.1], (RDP/Remote Desktop client support) ) + + dnl + dnl Real RTSP plugin +@@ -3089,14 +3096,14 @@ PKG_CHECK_MODULES([GL], [gl], [ + #ifdef _WIN32 + # include <GL/glew.h> + #endif +-#include <GL/gl.h> ++#include <GLES2/gl2.h> + ]], [ + [int t0 = GL_TEXTURE0;]]) + ], [ + GL_CFLAGS="" + have_gl="yes" + AS_IF([test "${SYS}" != "mingw32"], [ +- GL_LIBS="-lGL" ++ GL_LIBS="-lGLESv2" + ], [ + GL_LIBS="-lopengl32" + ]) +@@ -3483,15 +3490,14 @@ AC_ARG_ENABLE(mmal_avcodec, + [Use MMAL enabled avcodec libs (default disable)])) + if test "${enable_mmal}" != "no"; then + VLC_SAVE_FLAGS +- LDFLAGS="${LDFLAGS} -L/opt/vc/lib -lvchostif" +- CPPFLAGS="${CPPFLAGS} -isystem /opt/vc/include -isystem /opt/vc/include/interface/vcos/pthreads -isystem /opt/vc/include/interface/vmcs_host/linux" +- AC_CHECK_HEADERS(interface/mmal/mmal.h, +- [ AC_CHECK_LIB(bcm_host, vc_tv_unregister_callback_full, [ ++ PKG_CHECK_MODULES(BCMHOST_MMAL, [bcm_host mmal vcsm openmaxil egl], [ ++ HAVE_MMAL=yes ++ AC_CHECK_HEADERS(interface/mmal/mmal.h, ++ [ AC_CHECK_LIB(bcm_host $BCMHOST_MMAL_LIBS, vc_tv_unregister_callback_full, [ + have_mmal="yes" +- VLC_ADD_PLUGIN([mmal]) +- VLC_ADD_LDFLAGS([mmal],[ -L/opt/vc/lib ]) +- VLC_ADD_CFLAGS([mmal],[ -isystem /opt/vc/include -isystem /opt/vc/include/interface/vcos/pthreads -isystem /opt/vc/include/interface/vmcs_host/linux ]) +- VLC_ADD_LIBS([mmal],[ -lbcm_host -lmmal -lmmal_core -lmmal_components -lmmal_util -lvchostif -lvchiq_arm -lvcsm ]) ], [ ++ VLC_ADD_PLUGIN([bcm_host mmal vcsm openmaxil egl]) ++ VLC_ADD_CFLAGS([bcm_host mmal vcsm openmaxil egl],[$BCMHOST_MMAL_CFLAGS]) ++ VLC_ADD_LIBS([bcm_host mmal vcsm openmaxil egl],[$BCMHOST_MMAL_LIBS -lmmal_components]) ], [ + AS_IF([test "${enable_mmal}" = "yes"], + [ AC_MSG_ERROR([Cannot find bcm library...]) ], + [ AC_MSG_WARN([Cannot find bcm library...]) ]) +@@ -3500,6 +3506,10 @@ if test "${enable_mmal}" != "no"; then + ] , [ AS_IF([test "${enable_mmal}" = "yes"], + [ AC_MSG_ERROR([Cannot find development headers for mmal...]) ], + [ AC_MSG_WARN([Cannot find development headers for mmal...]) ]) ]) ++ ],:[ ++ AC_MSG_WARN([${BCMHOST_PKG_ERRORS}: userland graphics not available.]) ++ HAVE_MMAL=NO ++ ]) + VLC_RESTORE_FLAGS + fi + AM_CONDITIONAL([HAVE_MMAL], [test "${have_mmal}" = "yes"]) +-- +2.38.1 + diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0009-fix-EGL-macro-undeclared-and-EGLImageKHR.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3002-fix-EGL-macro-undeclared-and-EGLImageKHR.patch index 9bd6b41469..ab72b4f3c9 100644 --- a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/0009-fix-EGL-macro-undeclared-and-EGLImageKHR.patch +++ b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3002-fix-EGL-macro-undeclared-and-EGLImageKHR.patch @@ -2,11 +2,14 @@ From: Vincent Davis Jr <vince@underview.tech> Date: Fri, 07 Jan 2022 07:01:47 PM CST Subject: [PATCH] Fix EGL macro undeclared and EGLImageKHR +Upstream-Status: Inappropriate + +RPI-Distro repo forks original vlc and applies patches to enable +raspiberry pi support. + * Fixes compiler issues related to EGL macro constant/enum value type not being defined * Updates EGLImage to EGLImageKHR -Upstream-status: Pending - Signed-off-by: Vincent Davis Jr <vince@underview.tech> diff --git a/modules/hw/mmal/converter_mmal.c b/modules/hw/mmal/converter_mmal.c index f31cb81d8..426af668b 100644 diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3003-codec-omxil_core-replace-opt-vc-path-with-usr-lib.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3003-codec-omxil_core-replace-opt-vc-path-with-usr-lib.patch new file mode 100644 index 0000000000..a2dba50b2f --- /dev/null +++ b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3003-codec-omxil_core-replace-opt-vc-path-with-usr-lib.patch @@ -0,0 +1,43 @@ +From 85f6603aca1d174848b42e696a4cff8af57613d6 Mon Sep 17 00:00:00 2001 +From: Vincent Davis Jr <vince@underview.tech> +Date: Thu, 8 Dec 2022 23:38:36 -0600 +Subject: [PATCH] codec: omxil_core replace /opt/vc path with /usr/lib + +Upstream-Status: Inappropriate + +RPI-Distro repo clones original VLC and applies patches to enable +raspiberry pi support. + +Configures omxil_core.c for OE usages as libbcm_host.so +and libopenmaxil.so are located in a different location. + +Signed-off-by: Vincent Davis Jr <vince@underview.tech> +--- + modules/codec/omxil/omxil_core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/modules/codec/omxil/omxil_core.c b/modules/codec/omxil/omxil_core.c +index 5098f517a..5922d9034 100644 +--- a/modules/codec/omxil/omxil_core.c ++++ b/modules/codec/omxil/omxil_core.c +@@ -56,7 +56,7 @@ static const char *ppsz_dll_list[] = + #if defined(USE_IOMX) + "libiomx.so", /* Not used when using IOMX, the lib should already be loaded */ + #elif defined(RPI_OMX) +- "/opt/vc/lib/libopenmaxil.so", /* Broadcom IL core */ ++ "/usr/lib/libopenmaxil.so", /* Broadcom IL core */ + #elif 1 + "libOMX_Core.so", /* TI OMAP IL core */ + "libOmxCore.so", /* Qualcomm IL core */ +@@ -70,7 +70,7 @@ static const char *ppsz_dll_list[] = + #ifdef RPI_OMX + static const char *ppsz_extra_dll_list[] = + { +- "/opt/vc/lib/libbcm_host.so", /* Broadcom host library */ ++ "/usr/lib/libbcm_host.so", /* Broadcom host library */ + 0 + }; + #endif +-- +2.38.1 + diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3004-use-GLESv2-headers-over-GL-headers.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3004-use-GLESv2-headers-over-GL-headers.patch new file mode 100644 index 0000000000..8016ab3795 --- /dev/null +++ b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3004-use-GLESv2-headers-over-GL-headers.patch @@ -0,0 +1,60 @@ +From 377a67af6c3f7c38f6f7ba24f042ba1a6cfd3f24 Mon Sep 17 00:00:00 2001 +From: Vincent Davis Jr <vince@underview.tech> +Date: Fri, 9 Dec 2022 00:21:43 -0600 +Subject: [PATCH] use GLESv2 headers over GL headers + +Upstream-Status: Inappropriate + +RPI-Distro repo forks original vlc and applies patches to enable +raspiberry pi support. + +We utilize GLESv2 during compilation. Patches ensures +we utilize headers for it. + +Signed-off-by: Vincent Davis Jr <vince@underview.tech> +--- + modules/video_output/opengl/converter.h | 12 +++--------- + modules/visualization/glspectrum.c | 4 +++- + 2 files changed, 6 insertions(+), 10 deletions(-) + +diff --git a/modules/video_output/opengl/converter.h b/modules/video_output/opengl/converter.h +index 7000e1f38..a3fe32671 100644 +--- a/modules/video_output/opengl/converter.h ++++ b/modules/video_output/opengl/converter.h +@@ -41,15 +41,9 @@ + # include <OpenGLES/ES2/glext.h> + # endif + #else /* !defined (__APPLE__) */ +-# if defined (USE_OPENGL_ES2) +-# include <GLES2/gl2.h> +-# include <GLES2/gl2ext.h> +-# else +-# ifdef _WIN32 +-# include <GL/glew.h> +-# endif +-# include <GL/gl.h> +-# endif ++#define USE_OPENGL_ES2 ++#include <GLES2/gl2.h> ++#include <GLES2/gl2ext.h> + #endif + + #define VLCGL_PICTURE_MAX 128 +diff --git a/modules/visualization/glspectrum.c b/modules/visualization/glspectrum.c +index 06f8d1bdf..470080b1a 100644 +--- a/modules/visualization/glspectrum.c ++++ b/modules/visualization/glspectrum.c +@@ -37,7 +37,9 @@ + #ifdef __APPLE__ + # include <OpenGL/gl.h> + #else +-# include <GL/gl.h> ++#define USE_OPENGL_ES2 ++#include <GLES2/gl2.h> ++#include <GLES2/gl2ext.h> + #endif + + #include <math.h> +-- +2.38.1 + diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3005-modules-remove-glspectrum-usage.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3005-modules-remove-glspectrum-usage.patch new file mode 100644 index 0000000000..7cf210be27 --- /dev/null +++ b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3005-modules-remove-glspectrum-usage.patch @@ -0,0 +1,149 @@ +From 5f1bb5889d838719e381350b25c00ef3a75d0e02 Mon Sep 17 00:00:00 2001 +From: Vincent Davis Jr <vince@underview.tech> +Date: Fri, 9 Dec 2022 01:07:55 -0600 +Subject: [PATCH] modules: remove glspectrum usage + +Upstream-Status: Inappropriate + +RPI-Distro repo forks original vlc and applies patches to enable +raspiberry pi support. + +The glspectrum modules requries OpenGL +while we only want to utilize GLESv2. + +Signed-off-by: Vincent Davis Jr <vince@underview.tech> +--- + modules/Makefile.in | 24 ------------------------ + modules/visualization/Makefile.am | 10 ---------- + 2 files changed, 34 deletions(-) + +diff --git a/modules/Makefile.in b/modules/Makefile.in +index bde45db53..c9c4342ad 100644 +--- a/modules/Makefile.in ++++ b/modules/Makefile.in +@@ -481,7 +481,6 @@ TESTS = hpack_test$(EXEEXT) hpackenc_test$(EXEEXT) \ + @HAVE_WIN32_FALSE@am__append_247 = $(X_LIBS) $(X_PRE_LIBS) -lX11 + @HAVE_DARWIN_FALSE@@HAVE_WIN32_FALSE@am__append_248 = $(X_LIBS) $(X_PRE_LIBS) -lX11 + @HAVE_EVAS_TRUE@am__append_249 = libevas_plugin.la +-@HAVE_GL_TRUE@am__append_250 = libglspectrum_plugin.la + @ENABLE_SOUT_TRUE@@HAVE_GCRYPT_TRUE@am__append_251 = libaccess_output_livehttp_plugin.la + @ENABLE_SOUT_TRUE@am__append_252 = libaccess_output_shout_plugin.la \ + @ENABLE_SOUT_TRUE@ libaccess_output_srt_plugin.la \ +@@ -2028,13 +2027,7 @@ libgles2_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(libgles2_plugin_la_CFLAGS) $(CFLAGS) \ + $(libgles2_plugin_la_LDFLAGS) $(LDFLAGS) -o $@ +-libglspectrum_plugin_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +-am_libglspectrum_plugin_la_OBJECTS = visualization/glspectrum.lo \ +- visualization/visual/fft.lo visualization/visual/window.lo +-libglspectrum_plugin_la_OBJECTS = \ +- $(am_libglspectrum_plugin_la_OBJECTS) +-@HAVE_GL_TRUE@am_libglspectrum_plugin_la_rpath = -rpath $(visudir) + libglwin32_plugin_la_DEPENDENCIES = libchroma_copy.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_5) + am__objects_23 = \ +@@ -6507,7 +6500,6 @@ am__depfiles_remade = \ + video_splitter/$(DEPDIR)/clone.Plo \ + video_splitter/$(DEPDIR)/libpanoramix_plugin_la-panoramix.Plo \ + video_splitter/$(DEPDIR)/wall.Plo \ +- visualization/$(DEPDIR)/glspectrum.Plo \ + visualization/$(DEPDIR)/libgoom_plugin_la-goom.Plo \ + visualization/$(DEPDIR)/libprojectm_plugin_la-projectm.Plo \ + visualization/$(DEPDIR)/libvsxu_plugin_la-vsxu.Plo \ +@@ -6731,7 +6723,6 @@ SOURCES = $(liba52_plugin_la_SOURCES) $(libaa_plugin_la_SOURCES) \ + $(libglconv_vaapi_x11_plugin_la_SOURCES) \ + $(libglconv_vdpau_plugin_la_SOURCES) \ + $(libgles2_plugin_la_SOURCES) \ +- $(libglspectrum_plugin_la_SOURCES) \ + $(libglwin32_plugin_la_SOURCES) $(libglx_plugin_la_SOURCES) \ + $(libgme_plugin_la_SOURCES) $(libgnutls_plugin_la_SOURCES) \ + $(libgoom_plugin_la_SOURCES) $(libgradfun_plugin_la_SOURCES) \ +@@ -7130,7 +7121,6 @@ DIST_SOURCES = $(liba52_plugin_la_SOURCES) $(libaa_plugin_la_SOURCES) \ + $(libglconv_vaapi_x11_plugin_la_SOURCES) \ + $(libglconv_vdpau_plugin_la_SOURCES) \ + $(libgles2_plugin_la_SOURCES) \ +- $(libglspectrum_plugin_la_SOURCES) \ + $(libglwin32_plugin_la_SOURCES) $(libglx_plugin_la_SOURCES) \ + $(libgme_plugin_la_SOURCES) $(libgnutls_plugin_la_SOURCES) \ + $(libgoom_plugin_la_SOURCES) $(libgradfun_plugin_la_SOURCES) \ +@@ -12696,13 +12686,6 @@ libevent_thread_la_LDFLAGS = -static + visudir = $(pluginsdir)/visualization + visu_LTLIBRARIES = $(am__append_250) $(LTLIBgoom) $(LTLIBprojectm) \ + libvisual_plugin.la $(LTLIBvsxu) +-libglspectrum_plugin_la_SOURCES = \ +- visualization/glspectrum.c \ +- visualization/visual/fft.c visualization/visual/fft.h \ +- visualization/visual/window.c visualization/visual/window.h \ +- visualization/visual/window_presets.h +- +-libglspectrum_plugin_la_LIBADD = $(GL_LIBS) $(LIBM) + libgoom_plugin_la_SOURCES = visualization/goom.c + libgoom_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(GOOM_CFLAGS) + libgoom_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(visudir)' +@@ -15715,8 +15698,6 @@ visualization/$(am__dirstamp): + visualization/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) visualization/$(DEPDIR) + @: > visualization/$(DEPDIR)/$(am__dirstamp) +-visualization/glspectrum.lo: visualization/$(am__dirstamp) \ +- visualization/$(DEPDIR)/$(am__dirstamp) + visualization/visual/$(am__dirstamp): + @$(MKDIR_P) visualization/visual + @: > visualization/visual/$(am__dirstamp) +@@ -15728,8 +15709,6 @@ visualization/visual/fft.lo: visualization/visual/$(am__dirstamp) \ + visualization/visual/window.lo: visualization/visual/$(am__dirstamp) \ + visualization/visual/$(DEPDIR)/$(am__dirstamp) + +-libglspectrum_plugin.la: $(libglspectrum_plugin_la_OBJECTS) $(libglspectrum_plugin_la_DEPENDENCIES) $(EXTRA_libglspectrum_plugin_la_DEPENDENCIES) +- $(AM_V_CCLD)$(LINK) $(am_libglspectrum_plugin_la_rpath) $(libglspectrum_plugin_la_OBJECTS) $(libglspectrum_plugin_la_LIBADD) $(LIBS) + video_output/opengl/libglwin32_plugin_la-vout_helper.lo: \ + video_output/opengl/$(am__dirstamp) \ + video_output/opengl/$(DEPDIR)/$(am__dirstamp) +@@ -21420,7 +21399,6 @@ distclean-compile: + @AMDEP_TRUE@@am__include@ @am__quote@video_splitter/$(DEPDIR)/clone.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@video_splitter/$(DEPDIR)/libpanoramix_plugin_la-panoramix.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@video_splitter/$(DEPDIR)/wall.Plo@am__quote@ # am--include-marker +-@AMDEP_TRUE@@am__include@ @am__quote@visualization/$(DEPDIR)/glspectrum.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@visualization/$(DEPDIR)/libgoom_plugin_la-goom.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@visualization/$(DEPDIR)/libprojectm_plugin_la-projectm.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@visualization/$(DEPDIR)/libvsxu_plugin_la-vsxu.Plo@am__quote@ # am--include-marker +@@ -30324,7 +30302,6 @@ distclean: distclean-recursive + -rm -f video_splitter/$(DEPDIR)/clone.Plo + -rm -f video_splitter/$(DEPDIR)/libpanoramix_plugin_la-panoramix.Plo + -rm -f video_splitter/$(DEPDIR)/wall.Plo +- -rm -f visualization/$(DEPDIR)/glspectrum.Plo + -rm -f visualization/$(DEPDIR)/libgoom_plugin_la-goom.Plo + -rm -f visualization/$(DEPDIR)/libprojectm_plugin_la-projectm.Plo + -rm -f visualization/$(DEPDIR)/libvsxu_plugin_la-vsxu.Plo +@@ -31722,7 +31699,6 @@ maintainer-clean: maintainer-clean-recursive + -rm -f video_splitter/$(DEPDIR)/clone.Plo + -rm -f video_splitter/$(DEPDIR)/libpanoramix_plugin_la-panoramix.Plo + -rm -f video_splitter/$(DEPDIR)/wall.Plo +- -rm -f visualization/$(DEPDIR)/glspectrum.Plo + -rm -f visualization/$(DEPDIR)/libgoom_plugin_la-goom.Plo + -rm -f visualization/$(DEPDIR)/libprojectm_plugin_la-projectm.Plo + -rm -f visualization/$(DEPDIR)/libvsxu_plugin_la-vsxu.Plo +diff --git a/modules/visualization/Makefile.am b/modules/visualization/Makefile.am +index 10619e030..aafc97f87 100644 +--- a/modules/visualization/Makefile.am ++++ b/modules/visualization/Makefile.am +@@ -1,16 +1,6 @@ + visudir = $(pluginsdir)/visualization + visu_LTLIBRARIES = + +-libglspectrum_plugin_la_SOURCES = \ +- visualization/glspectrum.c \ +- visualization/visual/fft.c visualization/visual/fft.h \ +- visualization/visual/window.c visualization/visual/window.h \ +- visualization/visual/window_presets.h +-libglspectrum_plugin_la_LIBADD = $(GL_LIBS) $(LIBM) +-if HAVE_GL +-visu_LTLIBRARIES += libglspectrum_plugin.la +-endif +- + libgoom_plugin_la_SOURCES = visualization/goom.c + libgoom_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(GOOM_CFLAGS) + libgoom_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(visudir)' +-- +2.38.1 + diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3006-codec-omxil_core.h-fix-multiple-definition-of.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3006-codec-omxil_core.h-fix-multiple-definition-of.patch new file mode 100644 index 0000000000..e680c88bca --- /dev/null +++ b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3006-codec-omxil_core.h-fix-multiple-definition-of.patch @@ -0,0 +1,43 @@ +From fd4d233757cc46cd89f68b45ec4b059940dd84ae Mon Sep 17 00:00:00 2001 +From: Vincent Davis Jr <vince@underview.tech> +Date: Fri, 9 Dec 2022 19:58:11 -0600 +Subject: [PATCH] codec: omxil_core.h fix multiple definition of + +Upstream-Status: Inappropriate + +RPI-Distro repo forks original vlc and applies patches +to enable raspiberry pi support. + +Issue occurs during compilation as +* pf_enable_graphic_buffers +* pf_get_graphic_buffer_usage +* pf_get_hal_format + +Apears to be defined multiple times as the omxil_core.h +is included in multiple files. + +Signed-off-by: Vincent Davis Jr <vince@underview.tech> +--- + modules/codec/omxil/omxil_core.h | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/modules/codec/omxil/omxil_core.h b/modules/codec/omxil/omxil_core.h +index ac3db510b..f6e42f5ed 100644 +--- a/modules/codec/omxil/omxil_core.h ++++ b/modules/codec/omxil/omxil_core.h +@@ -34,9 +34,9 @@ extern OMX_ERRORTYPE (*pf_component_enum)(OMX_STRING, OMX_U32, OMX_U32); + extern OMX_ERRORTYPE (*pf_get_roles_of_component)(OMX_STRING, OMX_U32 *, OMX_U8 **); + + /* Extra IOMX android functions. Can be NULL if we don't link with libiomx */ +-OMX_ERRORTYPE (*pf_enable_graphic_buffers)(OMX_HANDLETYPE, OMX_U32, OMX_BOOL); +-OMX_ERRORTYPE (*pf_get_graphic_buffer_usage)(OMX_HANDLETYPE, OMX_U32, OMX_U32*); +-OMX_ERRORTYPE (*pf_get_hal_format) (const char *, int *); ++extern OMX_ERRORTYPE (*pf_enable_graphic_buffers)(OMX_HANDLETYPE, OMX_U32, OMX_BOOL); ++extern OMX_ERRORTYPE (*pf_get_graphic_buffer_usage)(OMX_HANDLETYPE, OMX_U32, OMX_U32*); ++extern OMX_ERRORTYPE (*pf_get_hal_format) (const char *, int *); + + int InitOmxCore(vlc_object_t *p_this); + void DeinitOmxCore(void); +-- +2.38.1 + diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3007-remove-xorg-related-link-libs.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3007-remove-xorg-related-link-libs.patch new file mode 100644 index 0000000000..a0487fa2e4 --- /dev/null +++ b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3007-remove-xorg-related-link-libs.patch @@ -0,0 +1,36 @@ +From 34e4f4dad923095989ccb0ab8efb883c592bdbfd Mon Sep 17 00:00:00 2001 +From: Vincent Davis Jr <vince@underview.tech> +Date: Fri, 9 Dec 2022 20:04:27 -0600 +Subject: [PATCH] remove xorg related link libs + +Upstream-Status: Inappropriate + +RPI-Distro repo forks original vlc and applies patches +to enable raspiberry pi support. + +If x11 isn't defined in DISTRO_FEATURES +required xorg related libs are not included +in recipe-sysroot resulting in compilation +failure. + +Signed-off-by: Vincent Davis Jr <vince@underview.tech> +--- + modules/hw/mmal/Makefile.am | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/modules/hw/mmal/Makefile.am b/modules/hw/mmal/Makefile.am +index 4abe68e2e..86dad2c2d 100644 +--- a/modules/hw/mmal/Makefile.am ++++ b/modules/hw/mmal/Makefile.am +@@ -8,7 +8,7 @@ libmmal_vout_plugin_la_SOURCES = vout.c mmal_cma.c mmal_picture.c subpic.c\ + mmal_cma.h mmal_picture.h subpic.h transform_ops.h\ + mmal_piccpy_neon.S + libmmal_vout_plugin_la_CFLAGS = $(AM_CFLAGS) +-libmmal_vout_plugin_la_LDFLAGS = $(AM_LDFLAGS) -lm -lX11 -lXrandr ++libmmal_vout_plugin_la_LDFLAGS = $(AM_LDFLAGS) -lm + libmmal_vout_plugin_la_LIBADD = $(LIBS_mmal) + mmal_LTLIBRARIES = libmmal_vout_plugin.la + +-- +2.38.1 + diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3008-vo-Makefile.am-exclude-libgl_plugin.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3008-vo-Makefile.am-exclude-libgl_plugin.patch new file mode 100644 index 0000000000..8806c80a60 --- /dev/null +++ b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3008-vo-Makefile.am-exclude-libgl_plugin.patch @@ -0,0 +1,97 @@ +From 28917a258a4173af0abda0eef7faef5cbf95f123 Mon Sep 17 00:00:00 2001 +From: Vincent Davis Jr <vince@underview.tech> +Date: Fri, 9 Dec 2022 21:28:48 -0600 +Subject: [PATCH] vo: Makefile.am exclude libgl_plugin + +Upstream-Status: Inappropriate + +RPI-Distro repo forks original vlc and applies patches +to enable raspiberry pi support. + +In the situation where opengl isn't included in +DISTRO_FEATURES. We need to exclude the opengl +vout plugin from being built. + +Signed-off-by: Vincent Davis Jr <vince@underview.tech> +--- + modules/video_output/Makefile.am | 64 -------------------------------- + 1 file changed, 64 deletions(-) + +diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am +index 78c06cfc4..14a330e68 100644 +--- a/modules/video_output/Makefile.am ++++ b/modules/video_output/Makefile.am +@@ -57,70 +57,6 @@ if HAVE_TVOS + vout_LTLIBRARIES += libvout_ios_plugin.la libglconv_cvpx_plugin.la + endif + +-### OpenGL ### +-libgles2_plugin_la_SOURCES = $(OPENGL_COMMONSOURCES) video_output/opengl/display.c +-libgles2_plugin_la_CFLAGS = $(AM_CFLAGS) $(GLES2_CFLAGS) -DUSE_OPENGL_ES2 $(OPENGL_COMMONCLFAGS) +-libgles2_plugin_la_LIBADD = $(GLES2_LIBS) $(LIBM) $(OPENGL_COMMONLIBS) +-libgles2_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)' +- +-EXTRA_LTLIBRARIES += libgles2_plugin.la +-vout_LTLIBRARIES += $(LTLIBgles2) +- +-libgl_plugin_la_SOURCES = $(OPENGL_COMMONSOURCES) video_output/opengl/display.c +-libgl_plugin_la_CFLAGS = $(AM_CFLAGS) $(GL_CFLAGS) $(OPENGL_COMMONCLFAGS) +-libgl_plugin_la_LIBADD = $(LIBM) $(OPENGL_COMMONLIBS) +-if HAVE_WIN32 +-libgl_plugin_la_CFLAGS += -DHAVE_GL_CORE_SYMBOLS +-libgl_plugin_la_LIBADD += $(GL_LIBS) +-endif +- +-libglconv_vaapi_wl_plugin_la_SOURCES = video_output/opengl/converter_vaapi.c \ +- video_output/opengl/converter.h \ +- hw/vaapi/vlc_vaapi.c hw/vaapi/vlc_vaapi.h +-libglconv_vaapi_wl_plugin_la_CFLAGS = $(AM_CFLAGS) $(GL_CFLAGS) -DHAVE_VA_WL $(LIBVA_WL_CFLAGS) +-libglconv_vaapi_wl_plugin_la_LIBADD = $(LIBVA_LIBS) $(LIBVA_EGL_LIBS) \ +- $(LIBVA_WL_LIBS) +- +-libglconv_vaapi_x11_plugin_la_SOURCES = $(libglconv_vaapi_wl_plugin_la_SOURCES) +-libglconv_vaapi_x11_plugin_la_CFLAGS = $(AM_CFLAGS) -DHAVE_VA_X11 +-libglconv_vaapi_x11_plugin_la_LIBADD = $(LIBVA_LIBS) $(LIBVA_EGL_LIBS) \ +- $(LIBVA_X11_LIBS) $(X_LIBS) $(X_PRE_LIBS) -lX11 +- +-libglconv_vaapi_drm_plugin_la_SOURCES = $(libglconv_vaapi_wl_plugin_la_SOURCES) +-libglconv_vaapi_drm_plugin_la_CFLAGS = $(AM_CFLAGS) -DHAVE_VA_DRM +-libglconv_vaapi_drm_plugin_la_LIBADD = $(LIBVA_LIBS) $(LIBVA_EGL_LIBS) \ +- $(LIBVA_DRM_LIBS) +- +-libglconv_vdpau_plugin_la_SOURCES = video_output/opengl/converter_vdpau.c \ +- video_output/opengl/converter.h hw/vdpau/vlc_vdpau.h +-libglconv_vdpau_plugin_la_CFLAGS = $(AM_CFLAGS) $(VDPAU_CFLAGS) +-libglconv_vdpau_plugin_la_LIBADD = $(LIBDL) libvlc_vdpau.la $(X_LIBS) $(X_PRE_LIBS) -lX11 +- +-if HAVE_GL +-vout_LTLIBRARIES += libgl_plugin.la +-if HAVE_EGL +-if HAVE_VAAPI +-if HAVE_WAYLAND_EGL +-if HAVE_VAAPI_WL +-vout_LTLIBRARIES += libglconv_vaapi_wl_plugin.la +-endif +-endif +-if HAVE_XCB +-if HAVE_VAAPI_X11 +-vout_LTLIBRARIES += libglconv_vaapi_x11_plugin.la +-endif +-endif +-if HAVE_VAAPI_DRM +-vout_LTLIBRARIES += libglconv_vaapi_drm_plugin.la +-endif +-endif +-endif # HAVE_EGL +- +-if HAVE_VDPAU +-vout_LTLIBRARIES += libglconv_vdpau_plugin.la +-endif +-endif # HAVE_GL +- + ### XCB ### + libvlc_xcb_events_la_SOURCES = \ + video_output/xcb/events.c video_output/xcb/events.h +-- +2.38.1 + diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3009-vo-converter_vaapi-Fix-EGL-macro-undeclared.patch b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3009-vo-converter_vaapi-Fix-EGL-macro-undeclared.patch new file mode 100644 index 0000000000..0f28199511 --- /dev/null +++ b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/files/3009-vo-converter_vaapi-Fix-EGL-macro-undeclared.patch @@ -0,0 +1,59 @@ +From 35276c4b02b9114436108e74727d192f1e21f239 Mon Sep 17 00:00:00 2001 +From: Vincent Davis Jr <vince@underview.tech> +Date: Fri, 9 Dec 2022 23:31:33 -0600 +Subject: [PATCH] vo: converter_vaapi Fix EGL macro undeclared + +Upstream-Status: Inappropriate + +RPI-Distro repo forks original vlc and applies patches to enable +raspiberry pi support. + +Fixes compiler issues related to EGL macro constant/enum value type +not being defined + +Signed-off-by: Vincent Davis Jr <vince@underview.tech> +--- + modules/video_output/opengl/converter_vaapi.c | 27 +++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/modules/video_output/opengl/converter_vaapi.c b/modules/video_output/opengl/converter_vaapi.c +index cd842f711..59245fe4c 100644 +--- a/modules/video_output/opengl/converter_vaapi.c ++++ b/modules/video_output/opengl/converter_vaapi.c +@@ -55,6 +55,33 @@ + + #define DRM_FORMAT_MOD_INVALID fourcc_mod_code(NONE, DRM_FORMAT_RESERVED) + ++#define EGL_LINUX_DMA_BUF_EXT 0x3270 ++#define EGL_LINUX_DRM_FOURCC_EXT 0x3271 ++#define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272 ++#define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273 ++#define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274 ++#define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275 ++#define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276 ++#define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277 ++#define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278 ++#define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279 ++#define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A ++#define EGL_YUV_COLOR_SPACE_HINT_EXT 0x327B ++#define EGL_SAMPLE_RANGE_HINT_EXT 0x327C ++#define EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT 0x327D ++#define EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT 0x327E ++#define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443 ++#define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444 ++#define EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT 0x3445 ++#define EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0x3446 ++#define EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT 0x3447 ++#define EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0x3448 ++#define EGL_DMA_BUF_PLANE3_FD_EXT 0x3440 ++#define EGL_DMA_BUF_PLANE3_OFFSET_EXT 0x3441 ++#define EGL_DMA_BUF_PLANE3_PITCH_EXT 0x3442 ++#define EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT 0x3449 ++#define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A ++ + struct priv + { + struct vlc_vaapi_instance *vainst; +-- +2.38.1 + diff --git a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/rpidistro-vlc_3.0.12.bb b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/rpidistro-vlc_3.0.17.bb index b244dde88e..2653b28f90 100644 --- a/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/rpidistro-vlc_3.0.12.bb +++ b/meta-raspberrypi/dynamic-layers/multimedia-layer/recipes-multimedia/rpidistro-vlc/rpidistro-vlc_3.0.17.bb @@ -9,17 +9,25 @@ SRC_URI = "\ git://git@github.com/RPi-Distro/vlc;protocol=https;branch=buster-rpt \ file://0001-configure-fix-linking-on-RISC-V-ISA.patch \ file://0002-Revert-configure-Require-libmodplug-0.8.9.patch \ - file://0003-mmal_20.patch \ - file://0004-mmal_exit_fix.patch \ - file://0005-mmal_chain.patch \ - file://0006-Use-packageconfig-to-detect-mmal-support.patch \ - file://0007-use-vorbisidec.patch \ - file://0008-fix-luaL-checkint.patch \ - file://0009-fix-EGL-macro-undeclared-and-EGLImageKHR.patch \ - file://0010-fix-numeric_limits-is-not-a-member-of-std.patch \ -" - -SRCREV = "f7fd69f12a3b89d03768fa3bd468e8f33cd1dc7c" + file://0003-CVE-2022-41325.patch \ + file://0004-mmal_20.patch \ + file://0005-mmal_exit_fix.patch \ + file://0006-mmal_chain.patch \ + file://0007-armv6.patch \ + file://2001-fix-luaL-checkint.patch \ + file://2002-use-vorbisidec.patch \ + file://3001-configure.ac-setup-for-OE-usage.patch \ + file://3002-fix-EGL-macro-undeclared-and-EGLImageKHR.patch \ + file://3003-codec-omxil_core-replace-opt-vc-path-with-usr-lib.patch \ + file://3004-use-GLESv2-headers-over-GL-headers.patch \ + file://3005-modules-remove-glspectrum-usage.patch \ + file://3006-codec-omxil_core.h-fix-multiple-definition-of.patch \ + ${@bb.utils.contains('DISTRO_FEATURES', 'x11', '', 'file://3007-remove-xorg-related-link-libs.patch', d)} \ + ${@bb.utils.contains('DISTRO_FEATURES', 'opengl', '', 'file://3008-vo-Makefile.am-exclude-libgl_plugin.patch', d)} \ + file://3009-vo-converter_vaapi-Fix-EGL-macro-undeclared.patch \ + " + +SRCREV = "b276eb0d7bc3213363e97dbb681ef7c927be6c73" S = "${WORKDIR}/git" @@ -37,24 +45,29 @@ EXTRA_OECONF = "\ --enable-run-as-root \ --enable-xvideo \ --disable-lua \ - --disable-screen --disable-caca \ + --disable-screen \ + --disable-caca \ --enable-vlm \ --enable-tremor \ - --disable-aa --disable-faad \ + --disable-aa \ + --disable-faad \ --enable-dbus \ --without-contrib \ --without-kde-solid \ --enable-realrtsp \ --disable-libtar \ --enable-avcodec \ -" + --disable-css \ + " PACKAGECONFIG ?= "\ ${@bb.utils.contains('DISTRO_FEATURES', 'x11', 'x11', '', d)} \ ${@bb.utils.contains('MACHINE_FEATURES', 'vc4graphics', '', 'mmal', d)} \ - live555 dv1394 notify fontconfig fluidsynth freetype dvdread png udev \ - x264 alsa harfbuzz jack neon fribidi dvbpsi a52 v4l2 gles2 \ -" + ${@bb.utils.contains('DISTRO_FEATURES', 'opengl', 'gles2', '', d)} \ + ${@bb.utils.contains_any('DISTRO_FEATURES', 'x11', 'notify', '', d)} \ + live555 dv1394 fontconfig fluidsynth freetype png udev \ + x264 alsa harfbuzz jack neon fribidi dvbpsi a52 v4l2 \ + " PACKAGECONFIG[mmal] = "--enable-omxil --enable-omxil-vout --enable-rpi-omxil --enable-mmal --enable-mmal-avcodec,,userland" PACKAGECONFIG[x264] = "--enable-x264,--disable-x264,x264" @@ -65,13 +78,13 @@ PACKAGECONFIG[live555] = "--enable-live555 LIVE555_PREFIX=${STAGING_DIR_HOST}${p PACKAGECONFIG[libass] = "--enable-libass,--disable-libass,libass" PACKAGECONFIG[postproc] = "--enable-postproc,--disable-postproc,libpostproc" PACKAGECONFIG[libva] = "--enable-libva,--disable-libva,libva" -PACKAGECONFIG[opencv] = "--enable-opencv,--disable-opencv,opencv" +#PACKAGECONFIG[opencv] = "--enable-opencv,--disable-opencv,opencv" PACKAGECONFIG[speex] = "--enable-speex,--disable-speex,speex" PACKAGECONFIG[gstreamer] = "--enable-gst-decode,--disable-gst-decode,gstreamer1.0 gstreamer1.0-plugins-base gstreamer1.0-plugins-bad" PACKAGECONFIG[vpx] = "--enable-vpx,--disable-vpx, libvpx" -PACKAGECONFIG[freerdp] = "--enable-freerdp,--disable-freerdp, freerdp" +#PACKAGECONFIG[freerdp] = "--enable-freerdp,--disable-freerdp, freerdp" PACKAGECONFIG[dvbpsi] = "--enable-dvbpsi,--disable-dvbpsi, libdvbpsi" -PACKAGECONFIG[samba] = "--enable-smbclient,--disable-smbclient, samba" +#PACKAGECONFIG[samba] = "--enable-smbclient,--disable-smbclient, samba" PACKAGECONFIG[upnp] = "--enable-upnp,--disable-upnp,libupnp" PACKAGECONFIG[dvdnav] = "--enable-dvdnav,--disable-dvdnav,libdvdnav libdvdcss" PACKAGECONFIG[sftp] = "--enable-sftp,--disable-sftp,libssh2" @@ -84,14 +97,14 @@ PACKAGECONFIG[svgdec] = "--enable-svgdec,--disable-svgdec,librsvg cairo" PACKAGECONFIG[notify] = "--enable-notify,--disable-notify, libnotify gtk+3" PACKAGECONFIG[fontconfig] = "--enable-fontconfig,--disable-fontconfig, fontconfig" PACKAGECONFIG[freetype] = "--enable-freetype,--disable-freetype, freetype" -PACKAGECONFIG[dvdread] = "--enable-dvdread,--disable-dvdread, libdvdread libdvdcss" +#PACKAGECONFIG[dvdread] = "--enable-dvdread,--disable-dvdread, libdvdread libdvdcss" PACKAGECONFIG[vnc] = "--enable-vnc,--disable-vnc, libvncserver" -PACKAGECONFIG[x11] = "--with-x --enable-xcb,--without-x --disable-xcb, xcb-util-keysyms libxpm libxinerama" +PACKAGECONFIG[x11] = "--with-x --enable-xcb,--without-x --disable-xcb, xcb-util-keysyms libxpm libxinerama" PACKAGECONFIG[png] = "--enable-png,--disable-png,libpng" -PACKAGECONFIG[vdpau] = "--enable-vdpau,--disable-vdpau,libvdpau" -PACKAGECONFIG[wayland] = "--enable-wayland,--disable-wayland,wayland wayland-native" +#PACKAGECONFIG[vdpau] = "--enable-vdpau,--disable-vdpau,libvdpau" +#PACKAGECONFIG[wayland] = "--enable-wayland,--disable-wayland,wayland wayland-native" PACKAGECONFIG[gles2] = "--enable-gles2,--disable-gles2,virtual/libgles2" -PACKAGECONFIG[dca] = "--enable-dca,," +#PACKAGECONFIG[dca] = "--enable-dca,--disable-dca,libdca" PACKAGECONFIG[fribidi] = "--enable-fribidi,,fribidi" PACKAGECONFIG[gnutls] = "--enable-gnutls,,gnutls" PACKAGECONFIG[fluidsynth] = "--enable-fluidsynth,,fluidsynth" @@ -105,25 +118,15 @@ PACKAGECONFIG[pulseaudio] = "--enable-pulse,--disable-pulse,pulseaudio" PACKAGECONFIG[sdl-image] = "--enable-sdl-image,,libsdl-image" PACKAGECONFIG[v4l2] = "--enable-v4l2,,v4l-utils" -# Workaround for modules/codec/omxil/omxil_core.h -# multiple definition of `pf_enable_graphic_buffers' -# multiple definition of `pf_get_graphic_buffer_usage' -# multiple definition of `pf_get_hal_format' -TARGET_CFLAGS:append = " -fcommon" -TARGET_CXXFLAGS:append = " -fcommon" +TARGET_CFLAGS:append = " -I${STAGING_INCDIR}/drm" +TARGET_LDFLAGS:append = " ${@bb.utils.contains('DISTRO_FEATURES', 'opengl', '-lGLESv2', '', d)}" # Ensures the --enable-mmal-avcodec flag is available for usage do_configure:prepend() { olddir=`pwd` cd ${S} ./bootstrap - cd $olddir -} - -do_configure:append() { - # https://forums.raspberrypi.com/viewtopic.php?p=1601535 - sed -i "/GLAPI void APIENTRY glShaderSource (/d" ${STAGING_INCDIR}/GL/glext.h - #sed -i -e s:'${top_builddir_slash}libtool':'${top_builddir_slash}'${TARGET_SYS}-libtool:g ${B}/doltlibtool + cd $olddir } # This recipe packages vlc as a library as well, so qt4 dependencies @@ -140,20 +143,20 @@ FILES:${PN} += "\ ${datadir}/vlc \ ${datadir}/icons \ ${datadir}/metainfo/vlc.appdata.xml \ -" + " FILES:${PN}-dbg += "\ ${libdir}/vlc/*/.debug \ ${libdir}/vlc/plugins/*/.debug \ -" + " FILES:${PN}-staticdev += "\ ${libdir}/vlc/plugins/*/*.a \ ${libdir}/vlc/libcompat.a \ -" + " # Only enable it for rpi class of machines COMPATIBLE_HOST = "null" -COMPATIBLE_HOST:rpi = "'(.*)'" +COMPATIBLE_HOST:rpi = "(.*)" INSANE_SKIP:${PN} = "dev-so" diff --git a/meta-raspberrypi/recipes-connectivity/bluez5/bluez5/0001-bcm43xx-Add-bcm43xx-3wire-variant.patch b/meta-raspberrypi/recipes-connectivity/bluez5/bluez5/0001-bcm43xx-Add-bcm43xx-3wire-variant.patch index 3bc02c49e2..1843b038e5 100644 --- a/meta-raspberrypi/recipes-connectivity/bluez5/bluez5/0001-bcm43xx-Add-bcm43xx-3wire-variant.patch +++ b/meta-raspberrypi/recipes-connectivity/bluez5/bluez5/0001-bcm43xx-Add-bcm43xx-3wire-variant.patch @@ -1,17 +1,17 @@ -From b4f2b77472aeb967d3a7595e8a965785c7a37c87 Mon Sep 17 00:00:00 2001 +From 8e8321cd597d3d9d342a8a3533ad10751dde5885 Mon Sep 17 00:00:00 2001 From: Phil Elwell <phil@raspberrypi.org> Date: Tue, 16 Feb 2016 16:40:46 +0000 -Subject: [PATCH 1/4] bcm43xx: Add bcm43xx-3wire variant +Subject: [PATCH] bcm43xx: Add bcm43xx-3wire variant --- tools/hciattach.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/hciattach.c b/tools/hciattach.c -index 59a76a7..5861d33 100644 +index 276a4e56e..7d01d8b74 100644 --- a/tools/hciattach.c +++ b/tools/hciattach.c -@@ -1144,6 +1144,9 @@ struct uart_t uart[] = { +@@ -1078,6 +1078,9 @@ struct uart_t uart[] = { { "bcm43xx", 0x0000, 0x0000, HCI_UART_H4, 115200, 3000000, FLOW_CTL, DISABLE_PM, NULL, bcm43xx, NULL }, @@ -21,6 +21,3 @@ index 59a76a7..5861d33 100644 { "ath3k", 0x0000, 0x0000, HCI_UART_ATH3K, 115200, 115200, FLOW_CTL, DISABLE_PM, NULL, ath3k_ps, ath3k_pm }, --- -1.9.1 - diff --git a/meta-raspberrypi/recipes-connectivity/bluez5/bluez5/0002-bcm43xx-The-UART-speed-must-be-reset-after-the-firmw.patch b/meta-raspberrypi/recipes-connectivity/bluez5/bluez5/0002-bcm43xx-The-UART-speed-must-be-reset-after-the-firmw.patch index 5a0a434a30..1dd89a1e23 100644 --- a/meta-raspberrypi/recipes-connectivity/bluez5/bluez5/0002-bcm43xx-The-UART-speed-must-be-reset-after-the-firmw.patch +++ b/meta-raspberrypi/recipes-connectivity/bluez5/bluez5/0002-bcm43xx-The-UART-speed-must-be-reset-after-the-firmw.patch @@ -1,17 +1,18 @@ -From e145c9621f976063e5c573db1f2053d906f63427 Mon Sep 17 00:00:00 2001 +From 96e5e5eef04c6c4ae83d4d822a536cfa87605ae2 Mon Sep 17 00:00:00 2001 From: Phil Elwell <phil@raspberrypi.org> Date: Tue, 16 Feb 2016 16:39:09 +0000 -Subject: [PATCH 2/4] bcm43xx: The UART speed must be reset after the firmware download +Subject: [PATCH] bcm43xx: The UART speed must be reset after the firmware + download --- tools/hciattach_bcm43xx.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/hciattach_bcm43xx.c b/tools/hciattach_bcm43xx.c -index 81f38cb..0b792e0 100644 +index b89fc1b50..de01a6aea 100644 --- a/tools/hciattach_bcm43xx.c +++ b/tools/hciattach_bcm43xx.c -@@ -366,11 +366,8 @@ int bcm43xx_init(int fd, int def_speed, int speed, struct termios *ti, +@@ -350,11 +350,8 @@ int bcm43xx_init(int fd, int def_speed, int speed, struct termios *ti, return -1; if (bcm43xx_locate_patch(FIRMWARE_DIR, chip_name, fw_path)) { @@ -24,7 +25,7 @@ index 81f38cb..0b792e0 100644 if (bcm43xx_load_firmware(fd, fw_path)) return -1; -@@ -380,6 +377,7 @@ int bcm43xx_init(int fd, int def_speed, int speed, struct termios *ti, +@@ -364,6 +361,7 @@ int bcm43xx_init(int fd, int def_speed, int speed, struct termios *ti, return -1; } @@ -32,6 +33,3 @@ index 81f38cb..0b792e0 100644 if (bcm43xx_reset(fd)) return -1; } --- -1.9.1 - diff --git a/meta-raspberrypi/recipes-connectivity/bluez5/bluez5/0003-Increase-firmware-load-timeout-to-30s.patch b/meta-raspberrypi/recipes-connectivity/bluez5/bluez5/0003-Increase-firmware-load-timeout-to-30s.patch index f9f09ebb09..d1c586c7a7 100644 --- a/meta-raspberrypi/recipes-connectivity/bluez5/bluez5/0003-Increase-firmware-load-timeout-to-30s.patch +++ b/meta-raspberrypi/recipes-connectivity/bluez5/bluez5/0003-Increase-firmware-load-timeout-to-30s.patch @@ -1,17 +1,17 @@ -From d41dc2046dd08d8c95197f677e224506f5b39bdd Mon Sep 17 00:00:00 2001 +From 05c3e145b5aa62e7e759932ea99f94d495b651c3 Mon Sep 17 00:00:00 2001 From: Phil Elwell <phil@raspberrypi.org> Date: Wed, 20 Jan 2016 16:00:37 +0000 -Subject: [PATCH 3/4] Increase firmware load timeout to 30s +Subject: [PATCH] Increase firmware load timeout to 30s --- tools/hciattach.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/hciattach.c b/tools/hciattach.c -index 5861d33..4141796 100644 +index 7d01d8b74..465bb17dd 100644 --- a/tools/hciattach.c +++ b/tools/hciattach.c -@@ -1293,7 +1293,7 @@ int main(int argc, char *argv[]) +@@ -1227,7 +1227,7 @@ int main(int argc, char *argv[]) { struct uart_t *u = NULL; int detach, printpid, raw, opt, i, n, ld, err; @@ -20,6 +20,3 @@ index 5861d33..4141796 100644 int init_speed = 0; int send_break = 0; pid_t pid; --- -1.9.1 - diff --git a/meta-raspberrypi/recipes-connectivity/bluez5/bluez5/0004-Move-the-43xx-firmware-into-lib-firmware.patch b/meta-raspberrypi/recipes-connectivity/bluez5/bluez5/0004-Move-the-43xx-firmware-into-lib-firmware.patch deleted file mode 100644 index dadce354e9..0000000000 --- a/meta-raspberrypi/recipes-connectivity/bluez5/bluez5/0004-Move-the-43xx-firmware-into-lib-firmware.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 76681284b0ea49852041fdb97a35175089a08781 Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.org> -Date: Tue, 23 Feb 2016 17:52:29 +0000 -Subject: [PATCH 4/4] Move the 43xx firmware into /lib/firmware - ---- - tools/hciattach_bcm43xx.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tools/hciattach_bcm43xx.c b/tools/hciattach_bcm43xx.c -index 0b792e0..207f668 100644 ---- a/tools/hciattach_bcm43xx.c -+++ b/tools/hciattach_bcm43xx.c -@@ -43,7 +43,7 @@ - #include "hciattach.h" - - #ifndef FIRMWARE_DIR --#define FIRMWARE_DIR "/etc/firmware" -+#define FIRMWARE_DIR "/lib/firmware" - #endif - - #define FW_EXT ".hcd" --- -1.9.1 - diff --git a/meta-raspberrypi/recipes-connectivity/bluez5/bluez5/0004-Move-the-hciattach-firmware-into-lib-firmware.patch b/meta-raspberrypi/recipes-connectivity/bluez5/bluez5/0004-Move-the-hciattach-firmware-into-lib-firmware.patch new file mode 100644 index 0000000000..dde7b38499 --- /dev/null +++ b/meta-raspberrypi/recipes-connectivity/bluez5/bluez5/0004-Move-the-hciattach-firmware-into-lib-firmware.patch @@ -0,0 +1,29 @@ +From 744f894e42d05b1dee917cc221ed3c1815990459 Mon Sep 17 00:00:00 2001 +From: Phil Elwell <phil@raspberrypi.org> +Date: Tue, 23 Feb 2016 17:52:29 +0000 +Subject: [PATCH] Move the hciattach firmware into /lib/firmware + +* FIRMWARE_DIR is now used by all hciattach firmware (not just bcm43xx) since 5.66 with: + commit d9253248363b995e44c1f5e393ed1c7aa4ec81ce + Author: Marek Vasut <marex@denx.de> + Date: Tue Nov 1 12:53:33 2022 +0100 + Subject: tools: Make hciattach_* firmware path build-time configurable + +Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com> +--- + tools/hciattach.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/hciattach.h b/tools/hciattach.h +index dfa4c1e7a..e88484766 100644 +--- a/tools/hciattach.h ++++ b/tools/hciattach.h +@@ -41,7 +41,7 @@ + #define HCI_UART_VND_DETECT 5 + + #ifndef FIRMWARE_DIR +-#define FIRMWARE_DIR "/etc/firmware" ++#define FIRMWARE_DIR "/lib/firmware" + #endif + + int read_hci_event(int fd, unsigned char *buf, int size); diff --git a/meta-raspberrypi/recipes-connectivity/bluez5/bluez5_%.bbappend b/meta-raspberrypi/recipes-connectivity/bluez5/bluez5_%.bbappend index 09d410350b..c5d905b295 100644 --- a/meta-raspberrypi/recipes-connectivity/bluez5/bluez5_%.bbappend +++ b/meta-raspberrypi/recipes-connectivity/bluez5/bluez5_%.bbappend @@ -4,7 +4,7 @@ SRC_URI:append:rpi = "\ file://0001-bcm43xx-Add-bcm43xx-3wire-variant.patch \ file://0002-bcm43xx-The-UART-speed-must-be-reset-after-the-firmw.patch \ file://0003-Increase-firmware-load-timeout-to-30s.patch \ - file://0004-Move-the-43xx-firmware-into-lib-firmware.patch \ + file://0004-Move-the-hciattach-firmware-into-lib-firmware.patch \ " RDEPENDS:${PN}:append:rpi = " pi-bluetooth" diff --git a/meta-raspberrypi/recipes-graphics/wayland/weston_%.bbappend b/meta-raspberrypi/recipes-graphics/wayland/weston_%.bbappend index 89917f0498..f9ed06a8f2 100644 --- a/meta-raspberrypi/recipes-graphics/wayland/weston_%.bbappend +++ b/meta-raspberrypi/recipes-graphics/wayland/weston_%.bbappend @@ -1,4 +1,4 @@ -PACKAGECONFIG:remove:rpi = "${@bb.utils.contains('MACHINE_FEATURES', 'vc4graphics', 'fbdev', '', d)}" +PACKAGECONFIG:remove:rpi = "${@bb.utils.contains('MACHINE_FEATURES', 'vc4graphics', 'fbdev', 'egl clients', d)}" EXTRA_OECONF:append:rpi = " \ --disable-xwayland-test \ diff --git a/meta-raspberrypi/recipes-kernel/linux/linux-raspberrypi.inc b/meta-raspberrypi/recipes-kernel/linux/linux-raspberrypi.inc index be1883c2bb..4f67d298fd 100644 --- a/meta-raspberrypi/recipes-kernel/linux/linux-raspberrypi.inc +++ b/meta-raspberrypi/recipes-kernel/linux/linux-raspberrypi.inc @@ -3,7 +3,7 @@ SECTION = "kernel" LICENSE = "GPL-2.0-only" LIC_FILES_CHKSUM = "file://COPYING;md5=6bc538ed5bd9a7fc9398086aedcd7e46" -COMPATIBLE_MACHINE = "^rpi$" +COMPATIBLE_MACHINE ?= "^rpi$" PE = "1" PV = "${LINUX_VERSION}+git${SRCPV}" diff --git a/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0001-avcodec-arm-sbcenc-avoid-callee-preserved-vfp-regist.patch b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0001-avcodec-arm-sbcenc-avoid-callee-preserved-vfp-regist.patch index e9c9eb7de7..d9c07dd77e 100644 --- a/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0001-avcodec-arm-sbcenc-avoid-callee-preserved-vfp-regist.patch +++ b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0001-avcodec-arm-sbcenc-avoid-callee-preserved-vfp-regist.patch @@ -2,6 +2,11 @@ From: James Cowgill <jcowgill@debian.org> Date: Sun, 11 Aug 2019 16:50:56 +0100 Subject: avcodec/arm/sbcenc: avoid callee preserved vfp registers +Upstream-Status: Inappropriate + +RPI-Distro repo clones original ffmpeg and applies patches to enable +raspiberry pi support. + When compiling FFmpeg with GCC-9, some very random segfaults were observed in code which had previously called down into the SBC encoder NEON assembly routines. This was caused by these functions clobbering @@ -19,8 +24,6 @@ sets of registers consecutively numbered which hopefully makes the code more easy to follow. Since this commit only reallocates registers, it should have no performance impact. -Upstream-status: Pending - Signed-off-by: James Cowgill <jcowgill@debian.org> --- libavcodec/arm/sbcdsp_neon.S | 220 +++++++++++++++++++++---------------------- @@ -38,7 +41,7 @@ index d83d21d..914abfb 100644 - vld1.16 {d8, d9}, [r2, :128]! + vld1.16 {d16, d17}, [r0, :64]! + vld1.16 {d20, d21}, [r2, :128]! - + - vmull.s16 q0, d4, d8 - vld1.16 {d6, d7}, [r0, :64]! - vmull.s16 q1, d5, d9 @@ -47,7 +50,7 @@ index d83d21d..914abfb 100644 + vld1.16 {d18, d19}, [r0, :64]! + vmull.s16 q1, d17, d21 + vld1.16 {d22, d23}, [r2, :128]! - + - vmlal.s16 q0, d6, d10 - vld1.16 {d4, d5}, [r0, :64]! - vmlal.s16 q1, d7, d11 @@ -56,7 +59,7 @@ index d83d21d..914abfb 100644 + vld1.16 {d16, d17}, [r0, :64]! + vmlal.s16 q1, d19, d23 + vld1.16 {d20, d21}, [r2, :128]! - + - vmlal.s16 q0, d4, d8 - vld1.16 {d6, d7}, [r0, :64]! - vmlal.s16 q1, d5, d9 @@ -65,7 +68,7 @@ index d83d21d..914abfb 100644 + vld1.16 {d18, d19}, [r0, :64]! + vmlal.s16 q1, d17, d21 + vld1.16 {d22, d23}, [r2, :128]! - + - vmlal.s16 q0, d6, d10 - vld1.16 {d4, d5}, [r0, :64]! - vmlal.s16 q1, d7, d11 @@ -74,23 +77,23 @@ index d83d21d..914abfb 100644 + vld1.16 {d16, d17}, [r0, :64]! + vmlal.s16 q1, d19, d23 + vld1.16 {d20, d21}, [r2, :128]! - + - vmlal.s16 q0, d4, d8 - vmlal.s16 q1, d5, d9 + vmlal.s16 q0, d16, d20 + vmlal.s16 q1, d17, d21 - + vpadd.s32 d0, d0, d1 vpadd.s32 d1, d2, d3 - + vrshrn.s32 d0, q0, SBC_PROTO_FIXED_SCALE - + - vld1.16 {d2, d3, d4, d5}, [r2, :128]! + vld1.16 {d16, d17, d18, d19}, [r2, :128]! - + vdup.i32 d1, d0[1] /* TODO: can be eliminated */ vdup.i32 d0, d0[0] /* TODO: can be eliminated */ - + - vmull.s16 q3, d2, d0 - vmull.s16 q4, d3, d0 - vmlal.s16 q3, d4, d1 @@ -99,14 +102,14 @@ index d83d21d..914abfb 100644 + vmull.s16 q11, d17, d0 + vmlal.s16 q10, d18, d1 + vmlal.s16 q11, d19, d1 - + - vpadd.s32 d0, d6, d7 /* TODO: can be eliminated */ - vpadd.s32 d1, d8, d9 /* TODO: can be eliminated */ + vpadd.s32 d0, d20, d21 /* TODO: can be eliminated */ + vpadd.s32 d1, d22, d23 /* TODO: can be eliminated */ - + vst1.32 {d0, d1}, [r1, :128] - + @@ -91,57 +91,57 @@ function ff_sbc_analyze_8_neon, export=1 /* TODO: merge even and odd cases (or even merge all four calls to this * function) in order to have only aligned reads from 'in' array @@ -213,13 +216,13 @@ index d83d21d..914abfb 100644 + vpadd.s32 d1, d26, d27 + vpadd.s32 d2, d28, d29 + vpadd.s32 d3, d30, d31 - + vrshr.s32 q0, q0, SBC_PROTO_FIXED_SCALE vrshr.s32 q1, q1, SBC_PROTO_FIXED_SCALE @@ -153,38 +153,38 @@ function ff_sbc_analyze_8_neon, export=1 vdup.i32 d1, d0[1] /* TODO: can be eliminated */ vdup.i32 d0, d0[0] /* TODO: can be eliminated */ - + - vld1.16 {d4, d5}, [r2, :128]! - vmull.s16 q6, d4, d0 - vld1.16 {d6, d7}, [r2, :128]! @@ -284,5 +287,6 @@ index d83d21d..914abfb 100644 + vpadd.s32 d1, d26, d27 /* TODO: can be eliminated */ + vpadd.s32 d2, d28, d29 /* TODO: can be eliminated */ + vpadd.s32 d3, d30, d31 /* TODO: can be eliminated */ - + vst1.32 {d0, d1, d2, d3}, [r1, :128] + diff --git a/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0002-Fix-build-on-powerpc-and-ppc64.patch b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0002-Fix-build-on-powerpc-and-ppc64.patch index 4d9c1b9f58..f398791679 100644 --- a/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0002-Fix-build-on-powerpc-and-ppc64.patch +++ b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0002-Fix-build-on-powerpc-and-ppc64.patch @@ -2,7 +2,10 @@ From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> Date: Tue, 19 Jan 2021 20:35:29 +0100 Subject: Fix build on powerpc and ppc64 -Upstream-status: Pending +Upstream-Status: Inappropriate + +RPI-Distro repo clones original ffmpeg and applies patches to enable +raspiberry pi support. --- libswscale/ppc/yuv2rgb_altivec.c | 10 ++++++++++ @@ -15,7 +18,7 @@ index 5365452..930ef6b 100644 @@ -283,6 +283,16 @@ static inline void cvtyuvtoRGB(SwsContext *c, vector signed short Y, * ------------------------------------------------------------------------------ */ - + +#if !HAVE_VSX +static inline vector unsigned char vec_xl(signed long long offset, const ubyte *addr) +{ diff --git a/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0003-avcodec-pngenc-remove-monowhite-from-apng-formats.patch b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0003-avcodec-pngenc-remove-monowhite-from-apng-formats.patch index 38f3fd4dab..11e3383aab 100644 --- a/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0003-avcodec-pngenc-remove-monowhite-from-apng-formats.patch +++ b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0003-avcodec-pngenc-remove-monowhite-from-apng-formats.patch @@ -2,13 +2,15 @@ From: Paul B Mahol <onemda@gmail.com> Date: Sun, 14 Feb 2021 17:20:03 +0100 Subject: avcodec/pngenc: remove monowhite from apng formats +Upstream-Status: Inappropriate + +RPI-Distro repo clones original ffmpeg and applies patches to enable +raspiberry pi support. + Monowhite pixel format is not supported, and it does not make sense to add support for it. Fixes #7989 - -Upstream-status: Pending - --- libavcodec/pngenc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0004-ffmpeg-4.3.2-rpi_10.patch b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0004-ffmpeg-4.3.4-rpi_14.patch index 6bab0d05b5..740ac0eab9 100644 --- a/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0004-ffmpeg-4.3.2-rpi_10.patch +++ b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0004-ffmpeg-4.3.4-rpi_14.patch @@ -1,16 +1,27 @@ -Upstream-status: Pending +Upstream-Status: Inappropriate + +RPI-Distro repo clones original ffmpeg and applies patches to enable +raspiberry pi support. --- a/configure +++ b/configure -@@ -274,6 +274,7 @@ External library support: +@@ -207,6 +207,7 @@ External library support: + --disable-bzlib disable bzlib [autodetect] + --disable-coreimage disable Apple CoreImage framework [autodetect] + --enable-chromaprint enable audio fingerprinting with chromaprint [no] ++ --disable-epoxy disable epoxy [autodetect] + --enable-frei0r enable frei0r video filtering [no] + --enable-gcrypt enable gcrypt, needed for rtmp(t)e support + if openssl, librtmp or gmp is not used [no] +@@ -274,6 +275,7 @@ External library support: --enable-libtls enable LibreSSL (via libtls), needed for https support if openssl, gnutls or mbedtls is not used [no] --enable-libtwolame enable MP2 encoding via libtwolame [no] -+ --enable-libudev enable libudev [no] ++ --disable-libudev disable libudev [autodetect] --enable-libv4l2 enable libv4l2/v4l-utils [no] --enable-libvidstab enable video stabilization using vid.stab [no] --enable-libvmaf enable vmaf filter via libvmaf [no] -@@ -336,12 +337,17 @@ External library support: +@@ -336,12 +338,17 @@ External library support: --enable-libmfx enable Intel MediaSDK (AKA Quick Sync Video) code via libmfx [no] --enable-libnpp enable Nvidia Performance Primitives-based code [no] --enable-mmal enable Broadcom Multi-Media Abstraction Layer (Raspberry Pi) via MMAL [no] @@ -28,23 +39,17 @@ Upstream-status: Pending --disable-vaapi disable Video Acceleration API (mainly Unix/Intel) code [autodetect] --disable-vdpau disable Nvidia Video Decode and Presentation API for Unix code [autodetect] --disable-videotoolbox disable VideoToolbox code [autodetect] -@@ -1771,6 +1777,7 @@ EXTERNAL_LIBRARY_LIST=" - libdav1d - libdc1394 - libdrm +@@ -1699,7 +1706,9 @@ EXTERNAL_AUTODETECT_LIBRARY_LIST=" + avfoundation + bzlib + coreimage + epoxy - libflite - libfontconfig - libfreetype -@@ -1807,6 +1814,7 @@ EXTERNAL_LIBRARY_LIST=" - libtesseract - libtheora - libtwolame + iconv + libudev - libv4l2 - libvorbis - libvpx -@@ -1861,7 +1869,10 @@ HWACCEL_LIBRARY_LIST=" + libxcb + libxcb_shm + libxcb_shape +@@ -1861,7 +1870,10 @@ HWACCEL_LIBRARY_LIST=" mmal omx opencl @@ -53,9 +58,9 @@ Upstream-status: Pending + rpi4_8 + rpi4_10 " - + DOCUMENT_LIST=" -@@ -1877,12 +1888,16 @@ FEATURE_LIST=" +@@ -1877,12 +1889,16 @@ FEATURE_LIST=" gray hardcoded_tables omx_rpi @@ -70,17 +75,17 @@ Upstream-status: Pending + vout_drm + vout_egl " - + # this list should be kept in linking order -@@ -1923,6 +1938,7 @@ SUBSYSTEM_LIST=" +@@ -1923,6 +1939,7 @@ SUBSYSTEM_LIST=" pixelutils network rdft + rpi " - + # COMPONENT_LIST needs to come last to ensure correct dependency checking -@@ -2405,9 +2421,11 @@ CONFIG_EXTRA=" +@@ -2405,9 +2422,11 @@ CONFIG_EXTRA=" rangecoder riffdec riffenc @@ -92,7 +97,7 @@ Upstream-status: Pending scene_sad sinewin snappy -@@ -2737,6 +2755,8 @@ hap_decoder_select="snappy texturedsp" +@@ -2737,6 +2756,8 @@ hap_decoder_select="snappy texturedsp" hap_encoder_deps="libsnappy" hap_encoder_select="texturedspenc" hevc_decoder_select="bswapdsp cabac golomb hevcparse videodsp" @@ -101,7 +106,7 @@ Upstream-status: Pending huffyuv_decoder_select="bswapdsp huffyuvdsp llviddsp" huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp llvidencdsp" hymt_decoder_select="huffyuv_decoder" -@@ -2903,6 +2923,7 @@ d3d11va_deps="dxva_h ID3D11VideoDecoder +@@ -2903,6 +2924,7 @@ d3d11va_deps="dxva_h ID3D11VideoDecoder dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode ole32 user32" ffnvcodec_deps_any="libdl LoadLibrary" nvdec_deps="ffnvcodec" @@ -109,7 +114,7 @@ Upstream-status: Pending vaapi_x11_deps="xlib" videotoolbox_hwaccel_deps="videotoolbox pthreads" videotoolbox_hwaccel_extralibs="-framework QuartzCore" -@@ -2934,6 +2955,12 @@ hevc_dxva2_hwaccel_deps="dxva2 DXVA_PicP +@@ -2934,6 +2956,12 @@ hevc_dxva2_hwaccel_deps="dxva2 DXVA_PicP hevc_dxva2_hwaccel_select="hevc_decoder" hevc_nvdec_hwaccel_deps="nvdec" hevc_nvdec_hwaccel_select="hevc_decoder" @@ -122,16 +127,15 @@ Upstream-status: Pending hevc_vaapi_hwaccel_deps="vaapi VAPictureParameterBufferHEVC" hevc_vaapi_hwaccel_select="hevc_decoder" hevc_vdpau_hwaccel_deps="vdpau VdpPictureInfoHEVC" -@@ -3401,8 +3428,14 @@ sndio_indev_deps="sndio" +@@ -3401,8 +3429,13 @@ sndio_indev_deps="sndio" sndio_outdev_deps="sndio" v4l2_indev_deps_any="linux_videodev2_h sys_videoio_h" v4l2_indev_suggest="libv4l2" +v4l2_outdev_deps="libdrm" v4l2_outdev_deps_any="linux_videodev2_h sys_videoio_h" v4l2_outdev_suggest="libv4l2" -+vout_drm_outdev_deps="libdrm vout_drm" -+vout_egl_outdev_deps="xlib" -+vout_egl_outdev_select="epoxy" ++vout_drm_outdev_deps="libdrm" ++vout_egl_outdev_deps="xlib epoxy" +vout_rpi_outdev_deps="rpi" +vout_rpi_outdev_select="sand" vfwcap_indev_deps="vfw32 vfwcap_defines" @@ -145,23 +149,20 @@ Upstream-status: Pending unsharp_opencl_filter_deps="opencl" uspp_filter_deps="gpl avcodec" vaguedenoiser_filter_deps="gpl" -@@ -6299,6 +6333,7 @@ enabled libdav1d && require_pkg - enabled libdavs2 && require_pkg_config libdavs2 "davs2 >= 1.6.0" davs2.h davs2_decoder_open - enabled libdc1394 && require_pkg_config libdc1394 libdc1394-2 dc1394/dc1394.h dc1394_new - enabled libdrm && require_pkg_config libdrm libdrm xf86drm.h drmGetVersion -+enabled epoxy && require_pkg_config epoxy epoxy epoxy/egl.h epoxy_egl_version - enabled libfdk_aac && { check_pkg_config libfdk_aac fdk-aac "fdk-aac/aacenc_lib.h" aacEncOpen || - { require libfdk_aac fdk-aac/aacenc_lib.h aacEncOpen -lfdk-aac && - warn "using libfdk without pkg-config"; } } -@@ -6376,6 +6411,7 @@ enabled libtls && require_pkg - enabled libtwolame && require libtwolame twolame.h twolame_init -ltwolame && - { check_lib libtwolame twolame.h twolame_encode_buffer_float32_interleaved -ltwolame || - die "ERROR: libtwolame must be installed and version must be >= 0.3.10"; } -+enabled libudev && require_pkg_config libudev libudev libudev.h udev_new - enabled libv4l2 && require_pkg_config libv4l2 libv4l2 libv4l2.h v4l2_ioctl - enabled libvidstab && require_pkg_config libvidstab "vidstab >= 0.98" vid.stab/libvidstab.h vsMotionDetectInit - enabled libvmaf && require_pkg_config libvmaf "libvmaf >= 1.3.9" libvmaf.h compute_vmaf -@@ -6430,11 +6466,12 @@ enabled mbedtls && { check_pkg +@@ -6102,6 +6136,12 @@ check_func_headers glob.h glob + enabled xlib && + check_lib xlib "X11/Xlib.h X11/extensions/Xvlib.h" XvGetPortAttribute -lXv -lX11 -lXext + ++enabled libudev && ++ check_pkg_config libudev libudev libudev.h udev_new ++ ++enabled epoxy && ++ check_pkg_config epoxy epoxy epoxy/egl.h epoxy_egl_version ++ + check_headers direct.h + check_headers dirent.h + check_headers dxgidebug.h +@@ -6430,11 +6470,12 @@ enabled mbedtls && { check_pkg check_lib mbedtls mbedtls/ssl.h mbedtls_ssl_init -lmbedtls -lmbedx509 -lmbedcrypto || die "ERROR: mbedTLS not found"; } enabled mediacodec && { enabled jni || die "ERROR: mediacodec requires --enable-jni"; } @@ -176,26 +177,32 @@ Upstream-status: Pending die "ERROR: mmal not found" && check_func_headers interface/mmal/mmal.h "MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS"; } enabled openal && { { for al_extralibs in "${OPENAL_LIBS}" "-lopenal" "-lOpenAL32"; do -@@ -6475,6 +6512,10 @@ enabled rkmpp && { require_p +@@ -6475,8 +6516,16 @@ enabled rkmpp && { require_p { enabled libdrm || die "ERROR: rkmpp requires --enable-libdrm"; } } +enabled v4l2_request && { enabled libdrm || + die "ERROR: v4l2-request requires --enable-libdrm"; } && + { enabled libudev || -+ die "ERROR: v4l2-request requires --enable-libudev"; } ++ die "ERROR: v4l2-request requires libudev"; } enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 42" VSScript.h vsscript_init - - -@@ -6556,6 +6597,8 @@ if enabled v4l2_m2m; then + ++enabled vout_drm && { enabled libdrm || die "ERROR: vout_drm requires --enable-libdrm"; } ++ ++enabled vout_egl && { enabled epoxy || die "ERROR: vout_egl requires epoxy"; } && ++ { enabled xlib || die "ERROR: vout_egl requires xlib"; } + + if enabled gcrypt; then + GCRYPT_CONFIG="${cross_prefix}libgcrypt-config" +@@ -6556,6 +6605,8 @@ if enabled v4l2_m2m; then check_cc vp9_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_VP9;" fi - + +check_func_headers "linux/media.h linux/videodev2.h" v4l2_timeval_to_ns +check_cc hevc_v4l2_request linux/videodev2.h "int i = V4L2_PIX_FMT_HEVC_SLICE;" check_headers sys/videoio.h test_code cc sys/videoio.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_sanitized struct_v4l2_frmivalenum_discrete - + --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -2119,8 +2119,8 @@ static int ifilter_send_frame(InputFilte @@ -208,11 +215,11 @@ Upstream-status: Pending + ifilter->height != av_frame_cropped_height(frame); break; } - + @@ -2131,6 +2131,9 @@ static int ifilter_send_frame(InputFilte (ifilter->hw_frames_ctx && ifilter->hw_frames_ctx->data != frame->hw_frames_ctx->data)) need_reinit = 1; - + + if (no_cvt_hw && fg->graph) + need_reinit = 0; + @@ -221,7 +228,7 @@ Upstream-status: Pending if (ret < 0) @@ -2401,8 +2404,7 @@ static int decode_video(InputStream *ist decoded_frame->top_field_first = ist->top_field_first; - + ist->frames_decoded++; - - if (ist->hwaccel_retrieve_data && decoded_frame->format == ist->hwaccel_pix_fmt) { @@ -229,7 +236,21 @@ Upstream-status: Pending err = ist->hwaccel_retrieve_data(ist->dec_ctx, decoded_frame); if (err < 0) goto fail; -@@ -2820,6 +2822,16 @@ static enum AVPixelFormat get_format(AVC +@@ -2600,7 +2602,12 @@ static int process_input_packet(InputStr + case AVMEDIA_TYPE_VIDEO: + ret = decode_video (ist, repeating ? NULL : &avpkt, &got_output, &duration_pts, !pkt, + &decode_failed); +- if (!repeating || !pkt || got_output) { ++ // Pi: Do not inc dts if no_cvt_hw set ++ // V4L2 H264 decode has long latency and sometimes spits out a long ++ // stream of output without input. In this case incrementing DTS is wrong. ++ // There may be cases where the condition as written is correct so only ++ // "fix" in the cases which cause problems ++ if (!repeating || !pkt || (got_output && !no_cvt_hw)) { + if (pkt && pkt->duration) { + duration_dts = av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q); + } else if(ist->dec_ctx->framerate.num != 0 && ist->dec_ctx->framerate.den != 0) { +@@ -2820,6 +2827,16 @@ static enum AVPixelFormat get_format(AVC } else { const HWAccel *hwaccel = NULL; int i; @@ -246,10 +267,10 @@ Upstream-status: Pending for (i = 0; hwaccels[i].name; i++) { if (hwaccels[i].pix_fmt == *p) { hwaccel = &hwaccels[i]; -@@ -2914,6 +2926,15 @@ static int init_input_stream(int ist_ind +@@ -2914,6 +2931,15 @@ static int init_input_stream(int ist_ind return ret; } - + +#if CONFIG_HEVC_RPI_DECODER + ret = -1; + if (strcmp(codec->name, "hevc_rpi") == 0 && @@ -270,7 +291,7 @@ Upstream-status: Pending HWACCEL_QSV, + HWACCEL_RPI, }; - + typedef struct HWAccel { @@ -590,6 +591,7 @@ extern int video_sync_method; extern float frame_drop_threshold; @@ -283,15 +304,15 @@ Upstream-status: Pending --- a/fftools/ffmpeg_filter.c +++ b/fftools/ffmpeg_filter.c @@ -1186,8 +1186,8 @@ int ifilter_parameters_from_frame(InputF - + ifilter->format = frame->format; - + - ifilter->width = frame->width; - ifilter->height = frame->height; + ifilter->width = av_frame_cropped_width(frame); + ifilter->height = av_frame_cropped_height(frame); ifilter->sample_aspect_ratio = frame->sample_aspect_ratio; - + ifilter->sample_rate = frame->sample_rate; --- a/fftools/ffmpeg_hw.c +++ b/fftools/ffmpeg_hw.c @@ -309,7 +330,7 @@ Upstream-status: Pending @@ -130,6 +130,12 @@ static const char *opt_name_enc_time_bas }\ } - + +#if CONFIG_RPI +static int rpi_init(AVCodecContext *avctx) { + return 0; @@ -376,7 +397,7 @@ Upstream-status: Pending + v4l2_req_devscan.o weak_link.o OBJS-$(CONFIG_WMA_FREQS) += wma_freqs.o OBJS-$(CONFIG_WMV2DSP) += wmv2dsp.o - + @@ -391,6 +396,14 @@ OBJS-$(CONFIG_HEVC_QSV_DECODER) + OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc_ps_enc.o \ hevc_data.o @@ -399,7 +420,7 @@ Upstream-status: Pending +OBJS-$(CONFIG_HEVC_RPI4_8_HWACCEL) += rpivid_hevc.o +OBJS-$(CONFIG_HEVC_RPI4_10_HWACCEL) += rpivid_hevc.o +OBJS-$(CONFIG_HEVC_V4L2REQUEST_HWACCEL) += v4l2_request_hevc.o v4l2_req_decode_q.o\ -+ v4l2_req_hevc_v1.o v4l2_req_hevc_v2.o ++ v4l2_req_hevc_v1.o v4l2_req_hevc_v2.o v4l2_req_hevc_v3.o v4l2_req_hevc_v4.o OBJS-$(CONFIG_HEVC_VAAPI_HWACCEL) += vaapi_hevc.o h265_profile_level.o OBJS-$(CONFIG_HEVC_VDPAU_HWACCEL) += vdpau_hevc.o OBJS-$(CONFIG_MJPEG_NVDEC_HWACCEL) += nvdec_mjpeg.o @@ -435,6 +456,1866 @@ Upstream-status: Pending +$(SUBDIR)rpi_qpu.o: $(SUBDIR)rpi_hevc_transform8.h $(SUBDIR)rpi_hevc_transform10.h +$(SUBDIR)rpi_hevcdec.o $(SUBDIR)rpi_shader_template.o $(SUBDIR)rpi_qpu.o: $(SUBDIR)rpi_hevc_shader.h +endif +--- a/libavcodec/aarch64/Makefile ++++ b/libavcodec/aarch64/Makefile +@@ -44,10 +44,12 @@ NEON-OBJS-$(CONFIG_H264PRED) + NEON-OBJS-$(CONFIG_H264QPEL) += aarch64/h264qpel_neon.o \ + aarch64/hpeldsp_neon.o + NEON-OBJS-$(CONFIG_HPELDSP) += aarch64/hpeldsp_neon.o +-NEON-OBJS-$(CONFIG_IDCTDSP) += aarch64/simple_idct_neon.o ++NEON-OBJS-$(CONFIG_IDCTDSP) += aarch64/idctdsp_neon.o \ ++ aarch64/simple_idct_neon.o + NEON-OBJS-$(CONFIG_MDCT) += aarch64/mdct_neon.o + NEON-OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_neon.o + NEON-OBJS-$(CONFIG_PIXBLOCKDSP) += aarch64/pixblockdsp_neon.o ++NEON-OBJS-$(CONFIG_VC1DSP) += aarch64/vc1dsp_neon.o + NEON-OBJS-$(CONFIG_VP8DSP) += aarch64/vp8dsp_neon.o + + # decoders/encoders +--- a/libavcodec/aarch64/idctdsp_init_aarch64.c ++++ b/libavcodec/aarch64/idctdsp_init_aarch64.c +@@ -27,19 +27,29 @@ + #include "libavcodec/idctdsp.h" + #include "idct.h" + ++void ff_put_pixels_clamped_neon(const int16_t *, uint8_t *, ptrdiff_t); ++void ff_put_signed_pixels_clamped_neon(const int16_t *, uint8_t *, ptrdiff_t); ++void ff_add_pixels_clamped_neon(const int16_t *, uint8_t *, ptrdiff_t); ++ + av_cold void ff_idctdsp_init_aarch64(IDCTDSPContext *c, AVCodecContext *avctx, + unsigned high_bit_depth) + { + int cpu_flags = av_get_cpu_flags(); + +- if (have_neon(cpu_flags) && !avctx->lowres && !high_bit_depth) { +- if (avctx->idct_algo == FF_IDCT_AUTO || +- avctx->idct_algo == FF_IDCT_SIMPLEAUTO || +- avctx->idct_algo == FF_IDCT_SIMPLENEON) { +- c->idct_put = ff_simple_idct_put_neon; +- c->idct_add = ff_simple_idct_add_neon; +- c->idct = ff_simple_idct_neon; +- c->perm_type = FF_IDCT_PERM_PARTTRANS; ++ if (have_neon(cpu_flags)) { ++ if (!avctx->lowres && !high_bit_depth) { ++ if (avctx->idct_algo == FF_IDCT_AUTO || ++ avctx->idct_algo == FF_IDCT_SIMPLEAUTO || ++ avctx->idct_algo == FF_IDCT_SIMPLENEON) { ++ c->idct_put = ff_simple_idct_put_neon; ++ c->idct_add = ff_simple_idct_add_neon; ++ c->idct = ff_simple_idct_neon; ++ c->perm_type = FF_IDCT_PERM_PARTTRANS; ++ } + } ++ ++ c->add_pixels_clamped = ff_add_pixels_clamped_neon; ++ c->put_pixels_clamped = ff_put_pixels_clamped_neon; ++ c->put_signed_pixels_clamped = ff_put_signed_pixels_clamped_neon; + } + } +--- /dev/null ++++ b/libavcodec/aarch64/idctdsp_neon.S +@@ -0,0 +1,130 @@ ++/* ++ * IDCT AArch64 NEON optimisations ++ * ++ * Copyright (c) 2022 Ben Avison <bavison@riscosopen.org> ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#include "libavutil/aarch64/asm.S" ++ ++// Clamp 16-bit signed block coefficients to unsigned 8-bit ++// On entry: ++// x0 -> array of 64x 16-bit coefficients ++// x1 -> 8-bit results ++// x2 = row stride for results, bytes ++function ff_put_pixels_clamped_neon, export=1 ++ ld1 {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], #64 ++ ld1 {v4.16b, v5.16b, v6.16b, v7.16b}, [x0] ++ sqxtun v0.8b, v0.8h ++ sqxtun v1.8b, v1.8h ++ sqxtun v2.8b, v2.8h ++ sqxtun v3.8b, v3.8h ++ sqxtun v4.8b, v4.8h ++ st1 {v0.8b}, [x1], x2 ++ sqxtun v0.8b, v5.8h ++ st1 {v1.8b}, [x1], x2 ++ sqxtun v1.8b, v6.8h ++ st1 {v2.8b}, [x1], x2 ++ sqxtun v2.8b, v7.8h ++ st1 {v3.8b}, [x1], x2 ++ st1 {v4.8b}, [x1], x2 ++ st1 {v0.8b}, [x1], x2 ++ st1 {v1.8b}, [x1], x2 ++ st1 {v2.8b}, [x1] ++ ret ++endfunc ++ ++// Clamp 16-bit signed block coefficients to signed 8-bit (biased by 128) ++// On entry: ++// x0 -> array of 64x 16-bit coefficients ++// x1 -> 8-bit results ++// x2 = row stride for results, bytes ++function ff_put_signed_pixels_clamped_neon, export=1 ++ ld1 {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], #64 ++ movi v4.8b, #128 ++ ld1 {v16.16b, v17.16b, v18.16b, v19.16b}, [x0] ++ sqxtn v0.8b, v0.8h ++ sqxtn v1.8b, v1.8h ++ sqxtn v2.8b, v2.8h ++ sqxtn v3.8b, v3.8h ++ sqxtn v5.8b, v16.8h ++ add v0.8b, v0.8b, v4.8b ++ sqxtn v6.8b, v17.8h ++ add v1.8b, v1.8b, v4.8b ++ sqxtn v7.8b, v18.8h ++ add v2.8b, v2.8b, v4.8b ++ sqxtn v16.8b, v19.8h ++ add v3.8b, v3.8b, v4.8b ++ st1 {v0.8b}, [x1], x2 ++ add v0.8b, v5.8b, v4.8b ++ st1 {v1.8b}, [x1], x2 ++ add v1.8b, v6.8b, v4.8b ++ st1 {v2.8b}, [x1], x2 ++ add v2.8b, v7.8b, v4.8b ++ st1 {v3.8b}, [x1], x2 ++ add v3.8b, v16.8b, v4.8b ++ st1 {v0.8b}, [x1], x2 ++ st1 {v1.8b}, [x1], x2 ++ st1 {v2.8b}, [x1], x2 ++ st1 {v3.8b}, [x1] ++ ret ++endfunc ++ ++// Add 16-bit signed block coefficients to unsigned 8-bit ++// On entry: ++// x0 -> array of 64x 16-bit coefficients ++// x1 -> 8-bit input and results ++// x2 = row stride for 8-bit input and results, bytes ++function ff_add_pixels_clamped_neon, export=1 ++ ld1 {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], #64 ++ mov x3, x1 ++ ld1 {v4.8b}, [x1], x2 ++ ld1 {v5.8b}, [x1], x2 ++ ld1 {v6.8b}, [x1], x2 ++ ld1 {v7.8b}, [x1], x2 ++ ld1 {v16.16b, v17.16b, v18.16b, v19.16b}, [x0] ++ uaddw v0.8h, v0.8h, v4.8b ++ uaddw v1.8h, v1.8h, v5.8b ++ uaddw v2.8h, v2.8h, v6.8b ++ ld1 {v4.8b}, [x1], x2 ++ uaddw v3.8h, v3.8h, v7.8b ++ ld1 {v5.8b}, [x1], x2 ++ sqxtun v0.8b, v0.8h ++ ld1 {v6.8b}, [x1], x2 ++ sqxtun v1.8b, v1.8h ++ ld1 {v7.8b}, [x1] ++ sqxtun v2.8b, v2.8h ++ sqxtun v3.8b, v3.8h ++ uaddw v4.8h, v16.8h, v4.8b ++ st1 {v0.8b}, [x3], x2 ++ uaddw v0.8h, v17.8h, v5.8b ++ st1 {v1.8b}, [x3], x2 ++ uaddw v1.8h, v18.8h, v6.8b ++ st1 {v2.8b}, [x3], x2 ++ uaddw v2.8h, v19.8h, v7.8b ++ sqxtun v4.8b, v4.8h ++ sqxtun v0.8b, v0.8h ++ st1 {v3.8b}, [x3], x2 ++ sqxtun v1.8b, v1.8h ++ sqxtun v2.8b, v2.8h ++ st1 {v4.8b}, [x3], x2 ++ st1 {v0.8b}, [x3], x2 ++ st1 {v1.8b}, [x3], x2 ++ st1 {v2.8b}, [x3] ++ ret ++endfunc +--- a/libavcodec/aarch64/vc1dsp_init_aarch64.c ++++ b/libavcodec/aarch64/vc1dsp_init_aarch64.c +@@ -21,10 +21,28 @@ + #include "libavutil/attributes.h" + #include "libavutil/cpu.h" + #include "libavutil/aarch64/cpu.h" ++#include "libavutil/intreadwrite.h" + #include "libavcodec/vc1dsp.h" + + #include "config.h" + ++void ff_vc1_inv_trans_8x8_neon(int16_t *block); ++void ff_vc1_inv_trans_8x4_neon(uint8_t *dest, ptrdiff_t stride, int16_t *block); ++void ff_vc1_inv_trans_4x8_neon(uint8_t *dest, ptrdiff_t stride, int16_t *block); ++void ff_vc1_inv_trans_4x4_neon(uint8_t *dest, ptrdiff_t stride, int16_t *block); ++ ++void ff_vc1_inv_trans_8x8_dc_neon(uint8_t *dest, ptrdiff_t stride, int16_t *block); ++void ff_vc1_inv_trans_8x4_dc_neon(uint8_t *dest, ptrdiff_t stride, int16_t *block); ++void ff_vc1_inv_trans_4x8_dc_neon(uint8_t *dest, ptrdiff_t stride, int16_t *block); ++void ff_vc1_inv_trans_4x4_dc_neon(uint8_t *dest, ptrdiff_t stride, int16_t *block); ++ ++void ff_vc1_v_loop_filter4_neon(uint8_t *src, ptrdiff_t stride, int pq); ++void ff_vc1_h_loop_filter4_neon(uint8_t *src, ptrdiff_t stride, int pq); ++void ff_vc1_v_loop_filter8_neon(uint8_t *src, ptrdiff_t stride, int pq); ++void ff_vc1_h_loop_filter8_neon(uint8_t *src, ptrdiff_t stride, int pq); ++void ff_vc1_v_loop_filter16_neon(uint8_t *src, ptrdiff_t stride, int pq); ++void ff_vc1_h_loop_filter16_neon(uint8_t *src, ptrdiff_t stride, int pq); ++ + void ff_put_vc1_chroma_mc8_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int h, int x, int y); + void ff_avg_vc1_chroma_mc8_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, +@@ -34,14 +52,90 @@ void ff_put_vc1_chroma_mc4_neon(uint8_t + void ff_avg_vc1_chroma_mc4_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int h, int x, int y); + ++int ff_vc1_unescape_buffer_helper_neon(const uint8_t *src, int size, uint8_t *dst); ++ ++static int vc1_unescape_buffer_neon(const uint8_t *src, int size, uint8_t *dst) ++{ ++ /* Dealing with starting and stopping, and removing escape bytes, are ++ * comparatively less time-sensitive, so are more clearly expressed using ++ * a C wrapper around the assembly inner loop. Note that we assume a ++ * little-endian machine that supports unaligned loads. */ ++ int dsize = 0; ++ while (size >= 4) ++ { ++ int found = 0; ++ while (!found && (((uintptr_t) dst) & 7) && size >= 4) ++ { ++ found = (AV_RL32(src) &~ 0x03000000) == 0x00030000; ++ if (!found) ++ { ++ *dst++ = *src++; ++ --size; ++ ++dsize; ++ } ++ } ++ if (!found) ++ { ++ int skip = size - ff_vc1_unescape_buffer_helper_neon(src, size, dst); ++ dst += skip; ++ src += skip; ++ size -= skip; ++ dsize += skip; ++ while (!found && size >= 4) ++ { ++ found = (AV_RL32(src) &~ 0x03000000) == 0x00030000; ++ if (!found) ++ { ++ *dst++ = *src++; ++ --size; ++ ++dsize; ++ } ++ } ++ } ++ if (found) ++ { ++ *dst++ = *src++; ++ *dst++ = *src++; ++ ++src; ++ size -= 3; ++ dsize += 2; ++ } ++ } ++ while (size > 0) ++ { ++ *dst++ = *src++; ++ --size; ++ ++dsize; ++ } ++ return dsize; ++} ++ + av_cold void ff_vc1dsp_init_aarch64(VC1DSPContext *dsp) + { + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { ++ dsp->vc1_inv_trans_8x8 = ff_vc1_inv_trans_8x8_neon; ++ dsp->vc1_inv_trans_8x4 = ff_vc1_inv_trans_8x4_neon; ++ dsp->vc1_inv_trans_4x8 = ff_vc1_inv_trans_4x8_neon; ++ dsp->vc1_inv_trans_4x4 = ff_vc1_inv_trans_4x4_neon; ++ dsp->vc1_inv_trans_8x8_dc = ff_vc1_inv_trans_8x8_dc_neon; ++ dsp->vc1_inv_trans_8x4_dc = ff_vc1_inv_trans_8x4_dc_neon; ++ dsp->vc1_inv_trans_4x8_dc = ff_vc1_inv_trans_4x8_dc_neon; ++ dsp->vc1_inv_trans_4x4_dc = ff_vc1_inv_trans_4x4_dc_neon; ++ ++ dsp->vc1_v_loop_filter4 = ff_vc1_v_loop_filter4_neon; ++ dsp->vc1_h_loop_filter4 = ff_vc1_h_loop_filter4_neon; ++ dsp->vc1_v_loop_filter8 = ff_vc1_v_loop_filter8_neon; ++ dsp->vc1_h_loop_filter8 = ff_vc1_h_loop_filter8_neon; ++ dsp->vc1_v_loop_filter16 = ff_vc1_v_loop_filter16_neon; ++ dsp->vc1_h_loop_filter16 = ff_vc1_h_loop_filter16_neon; ++ + dsp->put_no_rnd_vc1_chroma_pixels_tab[0] = ff_put_vc1_chroma_mc8_neon; + dsp->avg_no_rnd_vc1_chroma_pixels_tab[0] = ff_avg_vc1_chroma_mc8_neon; + dsp->put_no_rnd_vc1_chroma_pixels_tab[1] = ff_put_vc1_chroma_mc4_neon; + dsp->avg_no_rnd_vc1_chroma_pixels_tab[1] = ff_avg_vc1_chroma_mc4_neon; ++ ++ dsp->vc1_unescape_buffer = vc1_unescape_buffer_neon; + } + } +--- /dev/null ++++ b/libavcodec/aarch64/vc1dsp_neon.S +@@ -0,0 +1,1546 @@ ++/* ++ * VC1 AArch64 NEON optimisations ++ * ++ * Copyright (c) 2022 Ben Avison <bavison@riscosopen.org> ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#include "libavutil/aarch64/asm.S" ++ ++// VC-1 8x8 inverse transform ++// On entry: ++// x0 -> array of 16-bit inverse transform coefficients, in column-major order ++// On exit: ++// array at x0 updated to hold transformed block; also now held in row-major order ++function ff_vc1_inv_trans_8x8_neon, export=1 ++ ld1 {v1.16b, v2.16b}, [x0], #32 ++ ld1 {v3.16b, v4.16b}, [x0], #32 ++ ld1 {v5.16b, v6.16b}, [x0], #32 ++ shl v1.8h, v1.8h, #2 // 8/2 * src[0] ++ sub x1, x0, #3*32 ++ ld1 {v16.16b, v17.16b}, [x0] ++ shl v7.8h, v2.8h, #4 // 16 * src[8] ++ shl v18.8h, v2.8h, #2 // 4 * src[8] ++ shl v19.8h, v4.8h, #4 // 16 * src[24] ++ ldr d0, .Lcoeffs_it8 ++ shl v5.8h, v5.8h, #2 // 8/2 * src[32] ++ shl v20.8h, v6.8h, #4 // 16 * src[40] ++ shl v21.8h, v6.8h, #2 // 4 * src[40] ++ shl v22.8h, v17.8h, #4 // 16 * src[56] ++ ssra v20.8h, v19.8h, #2 // 4 * src[24] + 16 * src[40] ++ mul v23.8h, v3.8h, v0.h[0] // 6/2 * src[16] ++ sub v19.8h, v19.8h, v21.8h // 16 * src[24] - 4 * src[40] ++ ssra v7.8h, v22.8h, #2 // 16 * src[8] + 4 * src[56] ++ sub v18.8h, v22.8h, v18.8h // - 4 * src[8] + 16 * src[56] ++ shl v3.8h, v3.8h, #3 // 16/2 * src[16] ++ mls v20.8h, v2.8h, v0.h[2] // - 15 * src[8] + 4 * src[24] + 16 * src[40] ++ ssra v1.8h, v1.8h, #1 // 12/2 * src[0] ++ ssra v5.8h, v5.8h, #1 // 12/2 * src[32] ++ mla v7.8h, v4.8h, v0.h[2] // 16 * src[8] + 15 * src[24] + 4 * src[56] ++ shl v21.8h, v16.8h, #3 // 16/2 * src[48] ++ mls v19.8h, v2.8h, v0.h[1] // - 9 * src[8] + 16 * src[24] - 4 * src[40] ++ sub v2.8h, v23.8h, v21.8h // t4/2 = 6/2 * src[16] - 16/2 * src[48] ++ mla v18.8h, v4.8h, v0.h[1] // - 4 * src[8] + 9 * src[24] + 16 * src[56] ++ add v4.8h, v1.8h, v5.8h // t1/2 = 12/2 * src[0] + 12/2 * src[32] ++ sub v1.8h, v1.8h, v5.8h // t2/2 = 12/2 * src[0] - 12/2 * src[32] ++ mla v3.8h, v16.8h, v0.h[0] // t3/2 = 16/2 * src[16] + 6/2 * src[48] ++ mla v7.8h, v6.8h, v0.h[1] // t1 = 16 * src[8] + 15 * src[24] + 9 * src[40] + 4 * src[56] ++ add v5.8h, v1.8h, v2.8h // t6/2 = t2/2 + t4/2 ++ sub v16.8h, v1.8h, v2.8h // t7/2 = t2/2 - t4/2 ++ mla v20.8h, v17.8h, v0.h[1] // -t2 = - 15 * src[8] + 4 * src[24] + 16 * src[40] + 9 * src[56] ++ add v21.8h, v1.8h, v2.8h // t6/2 = t2/2 + t4/2 ++ add v22.8h, v4.8h, v3.8h // t5/2 = t1/2 + t3/2 ++ mls v19.8h, v17.8h, v0.h[2] // -t3 = - 9 * src[8] + 16 * src[24] - 4 * src[40] - 15 * src[56] ++ sub v17.8h, v4.8h, v3.8h // t8/2 = t1/2 - t3/2 ++ add v23.8h, v4.8h, v3.8h // t5/2 = t1/2 + t3/2 ++ mls v18.8h, v6.8h, v0.h[2] // -t4 = - 4 * src[8] + 9 * src[24] - 15 * src[40] + 16 * src[56] ++ sub v1.8h, v1.8h, v2.8h // t7/2 = t2/2 - t4/2 ++ sub v2.8h, v4.8h, v3.8h // t8/2 = t1/2 - t3/2 ++ neg v3.8h, v7.8h // -t1 ++ neg v4.8h, v20.8h // +t2 ++ neg v6.8h, v19.8h // +t3 ++ ssra v22.8h, v7.8h, #1 // (t5 + t1) >> 1 ++ ssra v1.8h, v19.8h, #1 // (t7 - t3) >> 1 ++ neg v7.8h, v18.8h // +t4 ++ ssra v5.8h, v4.8h, #1 // (t6 + t2) >> 1 ++ ssra v16.8h, v6.8h, #1 // (t7 + t3) >> 1 ++ ssra v2.8h, v18.8h, #1 // (t8 - t4) >> 1 ++ ssra v17.8h, v7.8h, #1 // (t8 + t4) >> 1 ++ ssra v21.8h, v20.8h, #1 // (t6 - t2) >> 1 ++ ssra v23.8h, v3.8h, #1 // (t5 - t1) >> 1 ++ srshr v3.8h, v22.8h, #2 // (t5 + t1 + 4) >> 3 ++ srshr v4.8h, v5.8h, #2 // (t6 + t2 + 4) >> 3 ++ srshr v5.8h, v16.8h, #2 // (t7 + t3 + 4) >> 3 ++ srshr v6.8h, v17.8h, #2 // (t8 + t4 + 4) >> 3 ++ srshr v2.8h, v2.8h, #2 // (t8 - t4 + 4) >> 3 ++ srshr v1.8h, v1.8h, #2 // (t7 - t3 + 4) >> 3 ++ srshr v7.8h, v21.8h, #2 // (t6 - t2 + 4) >> 3 ++ srshr v16.8h, v23.8h, #2 // (t5 - t1 + 4) >> 3 ++ trn2 v17.8h, v3.8h, v4.8h ++ trn2 v18.8h, v5.8h, v6.8h ++ trn2 v19.8h, v2.8h, v1.8h ++ trn2 v20.8h, v7.8h, v16.8h ++ trn1 v21.4s, v17.4s, v18.4s ++ trn2 v17.4s, v17.4s, v18.4s ++ trn1 v18.4s, v19.4s, v20.4s ++ trn2 v19.4s, v19.4s, v20.4s ++ trn1 v3.8h, v3.8h, v4.8h ++ trn2 v4.2d, v21.2d, v18.2d ++ trn1 v20.2d, v17.2d, v19.2d ++ trn1 v5.8h, v5.8h, v6.8h ++ trn1 v1.8h, v2.8h, v1.8h ++ trn1 v2.8h, v7.8h, v16.8h ++ trn1 v6.2d, v21.2d, v18.2d ++ trn2 v7.2d, v17.2d, v19.2d ++ shl v16.8h, v20.8h, #4 // 16 * src[24] ++ shl v17.8h, v4.8h, #4 // 16 * src[40] ++ trn1 v18.4s, v3.4s, v5.4s ++ trn1 v19.4s, v1.4s, v2.4s ++ shl v21.8h, v7.8h, #4 // 16 * src[56] ++ shl v22.8h, v6.8h, #2 // 4 * src[8] ++ shl v23.8h, v4.8h, #2 // 4 * src[40] ++ trn2 v3.4s, v3.4s, v5.4s ++ trn2 v1.4s, v1.4s, v2.4s ++ shl v2.8h, v6.8h, #4 // 16 * src[8] ++ sub v5.8h, v16.8h, v23.8h // 16 * src[24] - 4 * src[40] ++ ssra v17.8h, v16.8h, #2 // 4 * src[24] + 16 * src[40] ++ sub v16.8h, v21.8h, v22.8h // - 4 * src[8] + 16 * src[56] ++ trn1 v22.2d, v18.2d, v19.2d ++ trn2 v18.2d, v18.2d, v19.2d ++ trn1 v19.2d, v3.2d, v1.2d ++ ssra v2.8h, v21.8h, #2 // 16 * src[8] + 4 * src[56] ++ mls v17.8h, v6.8h, v0.h[2] // - 15 * src[8] + 4 * src[24] + 16 * src[40] ++ shl v21.8h, v22.8h, #2 // 8/2 * src[0] ++ shl v18.8h, v18.8h, #2 // 8/2 * src[32] ++ mls v5.8h, v6.8h, v0.h[1] // - 9 * src[8] + 16 * src[24] - 4 * src[40] ++ shl v6.8h, v19.8h, #3 // 16/2 * src[16] ++ trn2 v1.2d, v3.2d, v1.2d ++ mla v16.8h, v20.8h, v0.h[1] // - 4 * src[8] + 9 * src[24] + 16 * src[56] ++ ssra v21.8h, v21.8h, #1 // 12/2 * src[0] ++ ssra v18.8h, v18.8h, #1 // 12/2 * src[32] ++ mul v3.8h, v19.8h, v0.h[0] // 6/2 * src[16] ++ shl v19.8h, v1.8h, #3 // 16/2 * src[48] ++ mla v2.8h, v20.8h, v0.h[2] // 16 * src[8] + 15 * src[24] + 4 * src[56] ++ add v20.8h, v21.8h, v18.8h // t1/2 = 12/2 * src[0] + 12/2 * src[32] ++ mla v6.8h, v1.8h, v0.h[0] // t3/2 = 16/2 * src[16] + 6/2 * src[48] ++ sub v1.8h, v21.8h, v18.8h // t2/2 = 12/2 * src[0] - 12/2 * src[32] ++ sub v3.8h, v3.8h, v19.8h // t4/2 = 6/2 * src[16] - 16/2 * src[48] ++ mla v17.8h, v7.8h, v0.h[1] // -t2 = - 15 * src[8] + 4 * src[24] + 16 * src[40] + 9 * src[56] ++ mls v5.8h, v7.8h, v0.h[2] // -t3 = - 9 * src[8] + 16 * src[24] - 4 * src[40] - 15 * src[56] ++ add v7.8h, v1.8h, v3.8h // t6/2 = t2/2 + t4/2 ++ add v18.8h, v20.8h, v6.8h // t5/2 = t1/2 + t3/2 ++ mls v16.8h, v4.8h, v0.h[2] // -t4 = - 4 * src[8] + 9 * src[24] - 15 * src[40] + 16 * src[56] ++ sub v19.8h, v1.8h, v3.8h // t7/2 = t2/2 - t4/2 ++ neg v21.8h, v17.8h // +t2 ++ mla v2.8h, v4.8h, v0.h[1] // t1 = 16 * src[8] + 15 * src[24] + 9 * src[40] + 4 * src[56] ++ sub v0.8h, v20.8h, v6.8h // t8/2 = t1/2 - t3/2 ++ neg v4.8h, v5.8h // +t3 ++ sub v22.8h, v1.8h, v3.8h // t7/2 = t2/2 - t4/2 ++ sub v23.8h, v20.8h, v6.8h // t8/2 = t1/2 - t3/2 ++ neg v24.8h, v16.8h // +t4 ++ add v6.8h, v20.8h, v6.8h // t5/2 = t1/2 + t3/2 ++ add v1.8h, v1.8h, v3.8h // t6/2 = t2/2 + t4/2 ++ ssra v7.8h, v21.8h, #1 // (t6 + t2) >> 1 ++ neg v3.8h, v2.8h // -t1 ++ ssra v18.8h, v2.8h, #1 // (t5 + t1) >> 1 ++ ssra v19.8h, v4.8h, #1 // (t7 + t3) >> 1 ++ ssra v0.8h, v24.8h, #1 // (t8 + t4) >> 1 ++ srsra v23.8h, v16.8h, #1 // (t8 - t4 + 1) >> 1 ++ srsra v22.8h, v5.8h, #1 // (t7 - t3 + 1) >> 1 ++ srsra v1.8h, v17.8h, #1 // (t6 - t2 + 1) >> 1 ++ srsra v6.8h, v3.8h, #1 // (t5 - t1 + 1) >> 1 ++ srshr v2.8h, v18.8h, #6 // (t5 + t1 + 64) >> 7 ++ srshr v3.8h, v7.8h, #6 // (t6 + t2 + 64) >> 7 ++ srshr v4.8h, v19.8h, #6 // (t7 + t3 + 64) >> 7 ++ srshr v5.8h, v0.8h, #6 // (t8 + t4 + 64) >> 7 ++ srshr v16.8h, v23.8h, #6 // (t8 - t4 + 65) >> 7 ++ srshr v17.8h, v22.8h, #6 // (t7 - t3 + 65) >> 7 ++ st1 {v2.16b, v3.16b}, [x1], #32 ++ srshr v0.8h, v1.8h, #6 // (t6 - t2 + 65) >> 7 ++ srshr v1.8h, v6.8h, #6 // (t5 - t1 + 65) >> 7 ++ st1 {v4.16b, v5.16b}, [x1], #32 ++ st1 {v16.16b, v17.16b}, [x1], #32 ++ st1 {v0.16b, v1.16b}, [x1] ++ ret ++endfunc ++ ++// VC-1 8x4 inverse transform ++// On entry: ++// x0 -> array of 8-bit samples, in row-major order ++// x1 = row stride for 8-bit sample array ++// x2 -> array of 16-bit inverse transform coefficients, in row-major order ++// On exit: ++// array at x0 updated by saturated addition of (narrowed) transformed block ++function ff_vc1_inv_trans_8x4_neon, export=1 ++ ld1 {v1.8b, v2.8b, v3.8b, v4.8b}, [x2], #32 ++ mov x3, x0 ++ ld1 {v16.8b, v17.8b, v18.8b, v19.8b}, [x2] ++ ldr q0, .Lcoeffs_it8 // includes 4-point coefficients in upper half of vector ++ ld1 {v5.8b}, [x0], x1 ++ trn2 v6.4h, v1.4h, v3.4h ++ trn2 v7.4h, v2.4h, v4.4h ++ trn1 v1.4h, v1.4h, v3.4h ++ trn1 v2.4h, v2.4h, v4.4h ++ trn2 v3.4h, v16.4h, v18.4h ++ trn2 v4.4h, v17.4h, v19.4h ++ trn1 v16.4h, v16.4h, v18.4h ++ trn1 v17.4h, v17.4h, v19.4h ++ ld1 {v18.8b}, [x0], x1 ++ trn1 v19.2s, v6.2s, v3.2s ++ trn2 v3.2s, v6.2s, v3.2s ++ trn1 v6.2s, v7.2s, v4.2s ++ trn2 v4.2s, v7.2s, v4.2s ++ trn1 v7.2s, v1.2s, v16.2s ++ trn1 v20.2s, v2.2s, v17.2s ++ shl v21.4h, v19.4h, #4 // 16 * src[1] ++ trn2 v1.2s, v1.2s, v16.2s ++ shl v16.4h, v3.4h, #4 // 16 * src[3] ++ trn2 v2.2s, v2.2s, v17.2s ++ shl v17.4h, v6.4h, #4 // 16 * src[5] ++ ld1 {v22.8b}, [x0], x1 ++ shl v23.4h, v4.4h, #4 // 16 * src[7] ++ mul v24.4h, v1.4h, v0.h[0] // 6/2 * src[2] ++ ld1 {v25.8b}, [x0] ++ shl v26.4h, v19.4h, #2 // 4 * src[1] ++ shl v27.4h, v6.4h, #2 // 4 * src[5] ++ ssra v21.4h, v23.4h, #2 // 16 * src[1] + 4 * src[7] ++ ssra v17.4h, v16.4h, #2 // 4 * src[3] + 16 * src[5] ++ sub v23.4h, v23.4h, v26.4h // - 4 * src[1] + 16 * src[7] ++ sub v16.4h, v16.4h, v27.4h // 16 * src[3] - 4 * src[5] ++ shl v7.4h, v7.4h, #2 // 8/2 * src[0] ++ shl v20.4h, v20.4h, #2 // 8/2 * src[4] ++ mla v21.4h, v3.4h, v0.h[2] // 16 * src[1] + 15 * src[3] + 4 * src[7] ++ shl v1.4h, v1.4h, #3 // 16/2 * src[2] ++ mls v17.4h, v19.4h, v0.h[2] // - 15 * src[1] + 4 * src[3] + 16 * src[5] ++ ssra v7.4h, v7.4h, #1 // 12/2 * src[0] ++ mls v16.4h, v19.4h, v0.h[1] // - 9 * src[1] + 16 * src[3] - 4 * src[5] ++ ssra v20.4h, v20.4h, #1 // 12/2 * src[4] ++ mla v23.4h, v3.4h, v0.h[1] // - 4 * src[1] + 9 * src[3] + 16 * src[7] ++ shl v3.4h, v2.4h, #3 // 16/2 * src[6] ++ mla v1.4h, v2.4h, v0.h[0] // t3/2 = 16/2 * src[2] + 6/2 * src[6] ++ mla v21.4h, v6.4h, v0.h[1] // t1 = 16 * src[1] + 15 * src[3] + 9 * src[5] + 4 * src[7] ++ mla v17.4h, v4.4h, v0.h[1] // -t2 = - 15 * src[1] + 4 * src[3] + 16 * src[5] + 9 * src[7] ++ sub v2.4h, v24.4h, v3.4h // t4/2 = 6/2 * src[2] - 16/2 * src[6] ++ mls v16.4h, v4.4h, v0.h[2] // -t3 = - 9 * src[1] + 16 * src[3] - 4 * src[5] - 15 * src[7] ++ add v3.4h, v7.4h, v20.4h // t1/2 = 12/2 * src[0] + 12/2 * src[4] ++ mls v23.4h, v6.4h, v0.h[2] // -t4 = - 4 * src[1] + 9 * src[3] - 15 * src[5] + 16 * src[7] ++ sub v4.4h, v7.4h, v20.4h // t2/2 = 12/2 * src[0] - 12/2 * src[4] ++ neg v6.4h, v21.4h // -t1 ++ add v7.4h, v3.4h, v1.4h // t5/2 = t1/2 + t3/2 ++ sub v19.4h, v3.4h, v1.4h // t8/2 = t1/2 - t3/2 ++ add v20.4h, v4.4h, v2.4h // t6/2 = t2/2 + t4/2 ++ sub v24.4h, v4.4h, v2.4h // t7/2 = t2/2 - t4/2 ++ add v26.4h, v3.4h, v1.4h // t5/2 = t1/2 + t3/2 ++ add v27.4h, v4.4h, v2.4h // t6/2 = t2/2 + t4/2 ++ sub v2.4h, v4.4h, v2.4h // t7/2 = t2/2 - t4/2 ++ sub v1.4h, v3.4h, v1.4h // t8/2 = t1/2 - t3/2 ++ neg v3.4h, v17.4h // +t2 ++ neg v4.4h, v16.4h // +t3 ++ neg v28.4h, v23.4h // +t4 ++ ssra v7.4h, v21.4h, #1 // (t5 + t1) >> 1 ++ ssra v1.4h, v23.4h, #1 // (t8 - t4) >> 1 ++ ssra v20.4h, v3.4h, #1 // (t6 + t2) >> 1 ++ ssra v24.4h, v4.4h, #1 // (t7 + t3) >> 1 ++ ssra v19.4h, v28.4h, #1 // (t8 + t4) >> 1 ++ ssra v2.4h, v16.4h, #1 // (t7 - t3) >> 1 ++ ssra v27.4h, v17.4h, #1 // (t6 - t2) >> 1 ++ ssra v26.4h, v6.4h, #1 // (t5 - t1) >> 1 ++ trn1 v1.2d, v7.2d, v1.2d ++ trn1 v2.2d, v20.2d, v2.2d ++ trn1 v3.2d, v24.2d, v27.2d ++ trn1 v4.2d, v19.2d, v26.2d ++ srshr v1.8h, v1.8h, #2 // (t5 + t1 + 4) >> 3, (t8 - t4 + 4) >> 3 ++ srshr v2.8h, v2.8h, #2 // (t6 + t2 + 4) >> 3, (t7 - t3 + 4) >> 3 ++ srshr v3.8h, v3.8h, #2 // (t7 + t3 + 4) >> 3, (t6 - t2 + 4) >> 3 ++ srshr v4.8h, v4.8h, #2 // (t8 + t4 + 4) >> 3, (t5 - t1 + 4) >> 3 ++ trn2 v6.8h, v1.8h, v2.8h ++ trn1 v1.8h, v1.8h, v2.8h ++ trn2 v2.8h, v3.8h, v4.8h ++ trn1 v3.8h, v3.8h, v4.8h ++ trn2 v4.4s, v6.4s, v2.4s ++ trn1 v7.4s, v1.4s, v3.4s ++ trn2 v1.4s, v1.4s, v3.4s ++ mul v3.8h, v4.8h, v0.h[5] // 22/2 * src[24] ++ trn1 v2.4s, v6.4s, v2.4s ++ mul v4.8h, v4.8h, v0.h[4] // 10/2 * src[24] ++ mul v6.8h, v7.8h, v0.h[6] // 17 * src[0] ++ mul v1.8h, v1.8h, v0.h[6] // 17 * src[16] ++ mls v3.8h, v2.8h, v0.h[4] // t4/2 = - 10/2 * src[8] + 22/2 * src[24] ++ mla v4.8h, v2.8h, v0.h[5] // t3/2 = 22/2 * src[8] + 10/2 * src[24] ++ add v0.8h, v6.8h, v1.8h // t1 = 17 * src[0] + 17 * src[16] ++ sub v1.8h, v6.8h, v1.8h // t2 = 17 * src[0] - 17 * src[16] ++ neg v2.8h, v3.8h // -t4/2 ++ neg v6.8h, v4.8h // -t3/2 ++ ssra v4.8h, v0.8h, #1 // (t1 + t3) >> 1 ++ ssra v2.8h, v1.8h, #1 // (t2 - t4) >> 1 ++ ssra v3.8h, v1.8h, #1 // (t2 + t4) >> 1 ++ ssra v6.8h, v0.8h, #1 // (t1 - t3) >> 1 ++ srshr v0.8h, v4.8h, #6 // (t1 + t3 + 64) >> 7 ++ srshr v1.8h, v2.8h, #6 // (t2 - t4 + 64) >> 7 ++ srshr v2.8h, v3.8h, #6 // (t2 + t4 + 64) >> 7 ++ srshr v3.8h, v6.8h, #6 // (t1 - t3 + 64) >> 7 ++ uaddw v0.8h, v0.8h, v5.8b ++ uaddw v1.8h, v1.8h, v18.8b ++ uaddw v2.8h, v2.8h, v22.8b ++ uaddw v3.8h, v3.8h, v25.8b ++ sqxtun v0.8b, v0.8h ++ sqxtun v1.8b, v1.8h ++ sqxtun v2.8b, v2.8h ++ sqxtun v3.8b, v3.8h ++ st1 {v0.8b}, [x3], x1 ++ st1 {v1.8b}, [x3], x1 ++ st1 {v2.8b}, [x3], x1 ++ st1 {v3.8b}, [x3] ++ ret ++endfunc ++ ++// VC-1 4x8 inverse transform ++// On entry: ++// x0 -> array of 8-bit samples, in row-major order ++// x1 = row stride for 8-bit sample array ++// x2 -> array of 16-bit inverse transform coefficients, in row-major order (row stride is 8 coefficients) ++// On exit: ++// array at x0 updated by saturated addition of (narrowed) transformed block ++function ff_vc1_inv_trans_4x8_neon, export=1 ++ mov x3, #16 ++ ldr q0, .Lcoeffs_it8 // includes 4-point coefficients in upper half of vector ++ mov x4, x0 ++ ld1 {v1.d}[0], [x2], x3 // 00 01 02 03 ++ ld1 {v2.d}[0], [x2], x3 // 10 11 12 13 ++ ld1 {v3.d}[0], [x2], x3 // 20 21 22 23 ++ ld1 {v4.d}[0], [x2], x3 // 30 31 32 33 ++ ld1 {v1.d}[1], [x2], x3 // 40 41 42 43 ++ ld1 {v2.d}[1], [x2], x3 // 50 51 52 53 ++ ld1 {v3.d}[1], [x2], x3 // 60 61 62 63 ++ ld1 {v4.d}[1], [x2] // 70 71 72 73 ++ ld1 {v5.s}[0], [x0], x1 ++ ld1 {v6.s}[0], [x0], x1 ++ ld1 {v7.s}[0], [x0], x1 ++ trn2 v16.8h, v1.8h, v2.8h // 01 11 03 13 41 51 43 53 ++ trn1 v1.8h, v1.8h, v2.8h // 00 10 02 12 40 50 42 52 ++ trn2 v2.8h, v3.8h, v4.8h // 21 31 23 33 61 71 63 73 ++ trn1 v3.8h, v3.8h, v4.8h // 20 30 22 32 60 70 62 72 ++ ld1 {v4.s}[0], [x0], x1 ++ trn2 v17.4s, v16.4s, v2.4s // 03 13 23 33 43 53 63 73 ++ trn1 v18.4s, v1.4s, v3.4s // 00 10 20 30 40 50 60 70 ++ trn1 v2.4s, v16.4s, v2.4s // 01 11 21 31 41 51 61 71 ++ mul v16.8h, v17.8h, v0.h[4] // 10/2 * src[3] ++ ld1 {v5.s}[1], [x0], x1 ++ mul v17.8h, v17.8h, v0.h[5] // 22/2 * src[3] ++ ld1 {v6.s}[1], [x0], x1 ++ trn2 v1.4s, v1.4s, v3.4s // 02 12 22 32 42 52 62 72 ++ mul v3.8h, v18.8h, v0.h[6] // 17 * src[0] ++ ld1 {v7.s}[1], [x0], x1 ++ mul v1.8h, v1.8h, v0.h[6] // 17 * src[2] ++ ld1 {v4.s}[1], [x0] ++ mla v16.8h, v2.8h, v0.h[5] // t3/2 = 22/2 * src[1] + 10/2 * src[3] ++ mls v17.8h, v2.8h, v0.h[4] // t4/2 = - 10/2 * src[1] + 22/2 * src[3] ++ add v2.8h, v3.8h, v1.8h // t1 = 17 * src[0] + 17 * src[2] ++ sub v1.8h, v3.8h, v1.8h // t2 = 17 * src[0] - 17 * src[2] ++ neg v3.8h, v16.8h // -t3/2 ++ ssra v16.8h, v2.8h, #1 // (t1 + t3) >> 1 ++ neg v18.8h, v17.8h // -t4/2 ++ ssra v17.8h, v1.8h, #1 // (t2 + t4) >> 1 ++ ssra v3.8h, v2.8h, #1 // (t1 - t3) >> 1 ++ ssra v18.8h, v1.8h, #1 // (t2 - t4) >> 1 ++ srshr v1.8h, v16.8h, #2 // (t1 + t3 + 64) >> 3 ++ srshr v2.8h, v17.8h, #2 // (t2 + t4 + 64) >> 3 ++ srshr v3.8h, v3.8h, #2 // (t1 - t3 + 64) >> 3 ++ srshr v16.8h, v18.8h, #2 // (t2 - t4 + 64) >> 3 ++ trn2 v17.8h, v2.8h, v3.8h // 12 13 32 33 52 53 72 73 ++ trn2 v18.8h, v1.8h, v16.8h // 10 11 30 31 50 51 70 71 ++ trn1 v1.8h, v1.8h, v16.8h // 00 01 20 21 40 41 60 61 ++ trn1 v2.8h, v2.8h, v3.8h // 02 03 22 23 42 43 62 63 ++ trn1 v3.4s, v18.4s, v17.4s // 10 11 12 13 50 51 52 53 ++ trn2 v16.4s, v18.4s, v17.4s // 30 31 32 33 70 71 72 73 ++ trn1 v17.4s, v1.4s, v2.4s // 00 01 02 03 40 41 42 43 ++ mov d18, v3.d[1] // 50 51 52 53 ++ shl v19.4h, v3.4h, #4 // 16 * src[8] ++ mov d20, v16.d[1] // 70 71 72 73 ++ shl v21.4h, v16.4h, #4 // 16 * src[24] ++ mov d22, v17.d[1] // 40 41 42 43 ++ shl v23.4h, v3.4h, #2 // 4 * src[8] ++ shl v24.4h, v18.4h, #4 // 16 * src[40] ++ shl v25.4h, v20.4h, #4 // 16 * src[56] ++ shl v26.4h, v18.4h, #2 // 4 * src[40] ++ trn2 v1.4s, v1.4s, v2.4s // 20 21 22 23 60 61 62 63 ++ ssra v24.4h, v21.4h, #2 // 4 * src[24] + 16 * src[40] ++ sub v2.4h, v25.4h, v23.4h // - 4 * src[8] + 16 * src[56] ++ shl v17.4h, v17.4h, #2 // 8/2 * src[0] ++ sub v21.4h, v21.4h, v26.4h // 16 * src[24] - 4 * src[40] ++ shl v22.4h, v22.4h, #2 // 8/2 * src[32] ++ mov d23, v1.d[1] // 60 61 62 63 ++ ssra v19.4h, v25.4h, #2 // 16 * src[8] + 4 * src[56] ++ mul v25.4h, v1.4h, v0.h[0] // 6/2 * src[16] ++ shl v1.4h, v1.4h, #3 // 16/2 * src[16] ++ mls v24.4h, v3.4h, v0.h[2] // - 15 * src[8] + 4 * src[24] + 16 * src[40] ++ ssra v17.4h, v17.4h, #1 // 12/2 * src[0] ++ mls v21.4h, v3.4h, v0.h[1] // - 9 * src[8] + 16 * src[24] - 4 * src[40] ++ ssra v22.4h, v22.4h, #1 // 12/2 * src[32] ++ mla v2.4h, v16.4h, v0.h[1] // - 4 * src[8] + 9 * src[24] + 16 * src[56] ++ shl v3.4h, v23.4h, #3 // 16/2 * src[48] ++ mla v19.4h, v16.4h, v0.h[2] // 16 * src[8] + 15 * src[24] + 4 * src[56] ++ mla v1.4h, v23.4h, v0.h[0] // t3/2 = 16/2 * src[16] + 6/2 * src[48] ++ mla v24.4h, v20.4h, v0.h[1] // -t2 = - 15 * src[8] + 4 * src[24] + 16 * src[40] + 9 * src[56] ++ add v16.4h, v17.4h, v22.4h // t1/2 = 12/2 * src[0] + 12/2 * src[32] ++ sub v3.4h, v25.4h, v3.4h // t4/2 = 6/2 * src[16] - 16/2 * src[48] ++ sub v17.4h, v17.4h, v22.4h // t2/2 = 12/2 * src[0] - 12/2 * src[32] ++ mls v21.4h, v20.4h, v0.h[2] // -t3 = - 9 * src[8] + 16 * src[24] - 4 * src[40] - 15 * src[56] ++ mla v19.4h, v18.4h, v0.h[1] // t1 = 16 * src[8] + 15 * src[24] + 9 * src[40] + 4 * src[56] ++ add v20.4h, v16.4h, v1.4h // t5/2 = t1/2 + t3/2 ++ mls v2.4h, v18.4h, v0.h[2] // -t4 = - 4 * src[8] + 9 * src[24] - 15 * src[40] + 16 * src[56] ++ sub v0.4h, v16.4h, v1.4h // t8/2 = t1/2 - t3/2 ++ add v18.4h, v17.4h, v3.4h // t6/2 = t2/2 + t4/2 ++ sub v22.4h, v17.4h, v3.4h // t7/2 = t2/2 - t4/2 ++ neg v23.4h, v24.4h // +t2 ++ sub v25.4h, v17.4h, v3.4h // t7/2 = t2/2 - t4/2 ++ add v3.4h, v17.4h, v3.4h // t6/2 = t2/2 + t4/2 ++ neg v17.4h, v21.4h // +t3 ++ sub v26.4h, v16.4h, v1.4h // t8/2 = t1/2 - t3/2 ++ add v1.4h, v16.4h, v1.4h // t5/2 = t1/2 + t3/2 ++ neg v16.4h, v19.4h // -t1 ++ neg v27.4h, v2.4h // +t4 ++ ssra v20.4h, v19.4h, #1 // (t5 + t1) >> 1 ++ srsra v0.4h, v2.4h, #1 // (t8 - t4 + 1) >> 1 ++ ssra v18.4h, v23.4h, #1 // (t6 + t2) >> 1 ++ srsra v22.4h, v21.4h, #1 // (t7 - t3 + 1) >> 1 ++ ssra v25.4h, v17.4h, #1 // (t7 + t3) >> 1 ++ srsra v3.4h, v24.4h, #1 // (t6 - t2 + 1) >> 1 ++ ssra v26.4h, v27.4h, #1 // (t8 + t4) >> 1 ++ srsra v1.4h, v16.4h, #1 // (t5 - t1 + 1) >> 1 ++ trn1 v0.2d, v20.2d, v0.2d ++ trn1 v2.2d, v18.2d, v22.2d ++ trn1 v3.2d, v25.2d, v3.2d ++ trn1 v1.2d, v26.2d, v1.2d ++ srshr v0.8h, v0.8h, #6 // (t5 + t1 + 64) >> 7, (t8 - t4 + 65) >> 7 ++ srshr v2.8h, v2.8h, #6 // (t6 + t2 + 64) >> 7, (t7 - t3 + 65) >> 7 ++ srshr v3.8h, v3.8h, #6 // (t7 + t3 + 64) >> 7, (t6 - t2 + 65) >> 7 ++ srshr v1.8h, v1.8h, #6 // (t8 + t4 + 64) >> 7, (t5 - t1 + 65) >> 7 ++ uaddw v0.8h, v0.8h, v5.8b ++ uaddw v2.8h, v2.8h, v6.8b ++ uaddw v3.8h, v3.8h, v7.8b ++ uaddw v1.8h, v1.8h, v4.8b ++ sqxtun v0.8b, v0.8h ++ sqxtun v2.8b, v2.8h ++ sqxtun v3.8b, v3.8h ++ sqxtun v1.8b, v1.8h ++ st1 {v0.s}[0], [x4], x1 ++ st1 {v2.s}[0], [x4], x1 ++ st1 {v3.s}[0], [x4], x1 ++ st1 {v1.s}[0], [x4], x1 ++ st1 {v0.s}[1], [x4], x1 ++ st1 {v2.s}[1], [x4], x1 ++ st1 {v3.s}[1], [x4], x1 ++ st1 {v1.s}[1], [x4] ++ ret ++endfunc ++ ++// VC-1 4x4 inverse transform ++// On entry: ++// x0 -> array of 8-bit samples, in row-major order ++// x1 = row stride for 8-bit sample array ++// x2 -> array of 16-bit inverse transform coefficients, in row-major order (row stride is 8 coefficients) ++// On exit: ++// array at x0 updated by saturated addition of (narrowed) transformed block ++function ff_vc1_inv_trans_4x4_neon, export=1 ++ mov x3, #16 ++ ldr d0, .Lcoeffs_it4 ++ mov x4, x0 ++ ld1 {v1.d}[0], [x2], x3 // 00 01 02 03 ++ ld1 {v2.d}[0], [x2], x3 // 10 11 12 13 ++ ld1 {v3.d}[0], [x2], x3 // 20 21 22 23 ++ ld1 {v4.d}[0], [x2] // 30 31 32 33 ++ ld1 {v5.s}[0], [x0], x1 ++ ld1 {v5.s}[1], [x0], x1 ++ ld1 {v6.s}[0], [x0], x1 ++ trn2 v7.4h, v1.4h, v2.4h // 01 11 03 13 ++ trn1 v1.4h, v1.4h, v2.4h // 00 10 02 12 ++ ld1 {v6.s}[1], [x0] ++ trn2 v2.4h, v3.4h, v4.4h // 21 31 23 33 ++ trn1 v3.4h, v3.4h, v4.4h // 20 30 22 32 ++ trn2 v4.2s, v7.2s, v2.2s // 03 13 23 33 ++ trn1 v16.2s, v1.2s, v3.2s // 00 10 20 30 ++ trn1 v2.2s, v7.2s, v2.2s // 01 11 21 31 ++ trn2 v1.2s, v1.2s, v3.2s // 02 12 22 32 ++ mul v3.4h, v4.4h, v0.h[0] // 10/2 * src[3] ++ mul v4.4h, v4.4h, v0.h[1] // 22/2 * src[3] ++ mul v7.4h, v16.4h, v0.h[2] // 17 * src[0] ++ mul v1.4h, v1.4h, v0.h[2] // 17 * src[2] ++ mla v3.4h, v2.4h, v0.h[1] // t3/2 = 22/2 * src[1] + 10/2 * src[3] ++ mls v4.4h, v2.4h, v0.h[0] // t4/2 = - 10/2 * src[1] + 22/2 * src[3] ++ add v2.4h, v7.4h, v1.4h // t1 = 17 * src[0] + 17 * src[2] ++ sub v1.4h, v7.4h, v1.4h // t2 = 17 * src[0] - 17 * src[2] ++ neg v7.4h, v3.4h // -t3/2 ++ neg v16.4h, v4.4h // -t4/2 ++ ssra v3.4h, v2.4h, #1 // (t1 + t3) >> 1 ++ ssra v4.4h, v1.4h, #1 // (t2 + t4) >> 1 ++ ssra v16.4h, v1.4h, #1 // (t2 - t4) >> 1 ++ ssra v7.4h, v2.4h, #1 // (t1 - t3) >> 1 ++ srshr v1.4h, v3.4h, #2 // (t1 + t3 + 64) >> 3 ++ srshr v2.4h, v4.4h, #2 // (t2 + t4 + 64) >> 3 ++ srshr v3.4h, v16.4h, #2 // (t2 - t4 + 64) >> 3 ++ srshr v4.4h, v7.4h, #2 // (t1 - t3 + 64) >> 3 ++ trn2 v7.4h, v1.4h, v3.4h // 10 11 30 31 ++ trn1 v1.4h, v1.4h, v3.4h // 00 01 20 21 ++ trn2 v3.4h, v2.4h, v4.4h // 12 13 32 33 ++ trn1 v2.4h, v2.4h, v4.4h // 02 03 22 23 ++ trn2 v4.2s, v7.2s, v3.2s // 30 31 32 33 ++ trn1 v16.2s, v1.2s, v2.2s // 00 01 02 03 ++ trn1 v3.2s, v7.2s, v3.2s // 10 11 12 13 ++ trn2 v1.2s, v1.2s, v2.2s // 20 21 22 23 ++ mul v2.4h, v4.4h, v0.h[1] // 22/2 * src[24] ++ mul v4.4h, v4.4h, v0.h[0] // 10/2 * src[24] ++ mul v7.4h, v16.4h, v0.h[2] // 17 * src[0] ++ mul v1.4h, v1.4h, v0.h[2] // 17 * src[16] ++ mls v2.4h, v3.4h, v0.h[0] // t4/2 = - 10/2 * src[8] + 22/2 * src[24] ++ mla v4.4h, v3.4h, v0.h[1] // t3/2 = 22/2 * src[8] + 10/2 * src[24] ++ add v0.4h, v7.4h, v1.4h // t1 = 17 * src[0] + 17 * src[16] ++ sub v1.4h, v7.4h, v1.4h // t2 = 17 * src[0] - 17 * src[16] ++ neg v3.4h, v2.4h // -t4/2 ++ neg v7.4h, v4.4h // -t3/2 ++ ssra v4.4h, v0.4h, #1 // (t1 + t3) >> 1 ++ ssra v3.4h, v1.4h, #1 // (t2 - t4) >> 1 ++ ssra v2.4h, v1.4h, #1 // (t2 + t4) >> 1 ++ ssra v7.4h, v0.4h, #1 // (t1 - t3) >> 1 ++ trn1 v0.2d, v4.2d, v3.2d ++ trn1 v1.2d, v2.2d, v7.2d ++ srshr v0.8h, v0.8h, #6 // (t1 + t3 + 64) >> 7, (t2 - t4 + 64) >> 7 ++ srshr v1.8h, v1.8h, #6 // (t2 + t4 + 64) >> 7, (t1 - t3 + 64) >> 7 ++ uaddw v0.8h, v0.8h, v5.8b ++ uaddw v1.8h, v1.8h, v6.8b ++ sqxtun v0.8b, v0.8h ++ sqxtun v1.8b, v1.8h ++ st1 {v0.s}[0], [x4], x1 ++ st1 {v0.s}[1], [x4], x1 ++ st1 {v1.s}[0], [x4], x1 ++ st1 {v1.s}[1], [x4] ++ ret ++endfunc ++ ++// VC-1 8x8 inverse transform, DC case ++// On entry: ++// x0 -> array of 8-bit samples, in row-major order ++// x1 = row stride for 8-bit sample array ++// x2 -> 16-bit inverse transform DC coefficient ++// On exit: ++// array at x0 updated by saturated addition of (narrowed) transformed block ++function ff_vc1_inv_trans_8x8_dc_neon, export=1 ++ ldrsh w2, [x2] ++ mov x3, x0 ++ ld1 {v0.8b}, [x0], x1 ++ ld1 {v1.8b}, [x0], x1 ++ ld1 {v2.8b}, [x0], x1 ++ add w2, w2, w2, lsl #1 ++ ld1 {v3.8b}, [x0], x1 ++ ld1 {v4.8b}, [x0], x1 ++ add w2, w2, #1 ++ ld1 {v5.8b}, [x0], x1 ++ asr w2, w2, #1 ++ ld1 {v6.8b}, [x0], x1 ++ add w2, w2, w2, lsl #1 ++ ld1 {v7.8b}, [x0] ++ add w0, w2, #16 ++ asr w0, w0, #5 ++ dup v16.8h, w0 ++ uaddw v0.8h, v16.8h, v0.8b ++ uaddw v1.8h, v16.8h, v1.8b ++ uaddw v2.8h, v16.8h, v2.8b ++ uaddw v3.8h, v16.8h, v3.8b ++ uaddw v4.8h, v16.8h, v4.8b ++ uaddw v5.8h, v16.8h, v5.8b ++ sqxtun v0.8b, v0.8h ++ uaddw v6.8h, v16.8h, v6.8b ++ sqxtun v1.8b, v1.8h ++ uaddw v7.8h, v16.8h, v7.8b ++ sqxtun v2.8b, v2.8h ++ sqxtun v3.8b, v3.8h ++ sqxtun v4.8b, v4.8h ++ st1 {v0.8b}, [x3], x1 ++ sqxtun v0.8b, v5.8h ++ st1 {v1.8b}, [x3], x1 ++ sqxtun v1.8b, v6.8h ++ st1 {v2.8b}, [x3], x1 ++ sqxtun v2.8b, v7.8h ++ st1 {v3.8b}, [x3], x1 ++ st1 {v4.8b}, [x3], x1 ++ st1 {v0.8b}, [x3], x1 ++ st1 {v1.8b}, [x3], x1 ++ st1 {v2.8b}, [x3] ++ ret ++endfunc ++ ++// VC-1 8x4 inverse transform, DC case ++// On entry: ++// x0 -> array of 8-bit samples, in row-major order ++// x1 = row stride for 8-bit sample array ++// x2 -> 16-bit inverse transform DC coefficient ++// On exit: ++// array at x0 updated by saturated addition of (narrowed) transformed block ++function ff_vc1_inv_trans_8x4_dc_neon, export=1 ++ ldrsh w2, [x2] ++ mov x3, x0 ++ ld1 {v0.8b}, [x0], x1 ++ ld1 {v1.8b}, [x0], x1 ++ ld1 {v2.8b}, [x0], x1 ++ add w2, w2, w2, lsl #1 ++ ld1 {v3.8b}, [x0] ++ add w0, w2, #1 ++ asr w0, w0, #1 ++ add w0, w0, w0, lsl #4 ++ add w0, w0, #64 ++ asr w0, w0, #7 ++ dup v4.8h, w0 ++ uaddw v0.8h, v4.8h, v0.8b ++ uaddw v1.8h, v4.8h, v1.8b ++ uaddw v2.8h, v4.8h, v2.8b ++ uaddw v3.8h, v4.8h, v3.8b ++ sqxtun v0.8b, v0.8h ++ sqxtun v1.8b, v1.8h ++ sqxtun v2.8b, v2.8h ++ sqxtun v3.8b, v3.8h ++ st1 {v0.8b}, [x3], x1 ++ st1 {v1.8b}, [x3], x1 ++ st1 {v2.8b}, [x3], x1 ++ st1 {v3.8b}, [x3] ++ ret ++endfunc ++ ++// VC-1 4x8 inverse transform, DC case ++// On entry: ++// x0 -> array of 8-bit samples, in row-major order ++// x1 = row stride for 8-bit sample array ++// x2 -> 16-bit inverse transform DC coefficient ++// On exit: ++// array at x0 updated by saturated addition of (narrowed) transformed block ++function ff_vc1_inv_trans_4x8_dc_neon, export=1 ++ ldrsh w2, [x2] ++ mov x3, x0 ++ ld1 {v0.s}[0], [x0], x1 ++ ld1 {v1.s}[0], [x0], x1 ++ ld1 {v2.s}[0], [x0], x1 ++ add w2, w2, w2, lsl #4 ++ ld1 {v3.s}[0], [x0], x1 ++ add w2, w2, #4 ++ asr w2, w2, #3 ++ add w2, w2, w2, lsl #1 ++ ld1 {v0.s}[1], [x0], x1 ++ add w2, w2, #16 ++ asr w2, w2, #5 ++ dup v4.8h, w2 ++ ld1 {v1.s}[1], [x0], x1 ++ ld1 {v2.s}[1], [x0], x1 ++ ld1 {v3.s}[1], [x0] ++ uaddw v0.8h, v4.8h, v0.8b ++ uaddw v1.8h, v4.8h, v1.8b ++ uaddw v2.8h, v4.8h, v2.8b ++ uaddw v3.8h, v4.8h, v3.8b ++ sqxtun v0.8b, v0.8h ++ sqxtun v1.8b, v1.8h ++ sqxtun v2.8b, v2.8h ++ sqxtun v3.8b, v3.8h ++ st1 {v0.s}[0], [x3], x1 ++ st1 {v1.s}[0], [x3], x1 ++ st1 {v2.s}[0], [x3], x1 ++ st1 {v3.s}[0], [x3], x1 ++ st1 {v0.s}[1], [x3], x1 ++ st1 {v1.s}[1], [x3], x1 ++ st1 {v2.s}[1], [x3], x1 ++ st1 {v3.s}[1], [x3] ++ ret ++endfunc ++ ++// VC-1 4x4 inverse transform, DC case ++// On entry: ++// x0 -> array of 8-bit samples, in row-major order ++// x1 = row stride for 8-bit sample array ++// x2 -> 16-bit inverse transform DC coefficient ++// On exit: ++// array at x0 updated by saturated addition of (narrowed) transformed block ++function ff_vc1_inv_trans_4x4_dc_neon, export=1 ++ ldrsh w2, [x2] ++ mov x3, x0 ++ ld1 {v0.s}[0], [x0], x1 ++ ld1 {v1.s}[0], [x0], x1 ++ ld1 {v0.s}[1], [x0], x1 ++ add w2, w2, w2, lsl #4 ++ ld1 {v1.s}[1], [x0] ++ add w0, w2, #4 ++ asr w0, w0, #3 ++ add w0, w0, w0, lsl #4 ++ add w0, w0, #64 ++ asr w0, w0, #7 ++ dup v2.8h, w0 ++ uaddw v0.8h, v2.8h, v0.8b ++ uaddw v1.8h, v2.8h, v1.8b ++ sqxtun v0.8b, v0.8h ++ sqxtun v1.8b, v1.8h ++ st1 {v0.s}[0], [x3], x1 ++ st1 {v1.s}[0], [x3], x1 ++ st1 {v0.s}[1], [x3], x1 ++ st1 {v1.s}[1], [x3] ++ ret ++endfunc ++ ++.align 5 ++.Lcoeffs_it8: ++.quad 0x000F00090003 ++.Lcoeffs_it4: ++.quad 0x0011000B0005 ++.Lcoeffs: ++.quad 0x00050002 ++ ++// VC-1 in-loop deblocking filter for 4 pixel pairs at boundary of vertically-neighbouring blocks ++// On entry: ++// x0 -> top-left pel of lower block ++// x1 = row stride, bytes ++// w2 = PQUANT bitstream parameter ++function ff_vc1_v_loop_filter4_neon, export=1 ++ sub x3, x0, w1, sxtw #2 ++ ldr d0, .Lcoeffs ++ ld1 {v1.s}[0], [x0], x1 // P5 ++ ld1 {v2.s}[0], [x3], x1 // P1 ++ ld1 {v3.s}[0], [x3], x1 // P2 ++ ld1 {v4.s}[0], [x0], x1 // P6 ++ ld1 {v5.s}[0], [x3], x1 // P3 ++ ld1 {v6.s}[0], [x0], x1 // P7 ++ ld1 {v7.s}[0], [x3] // P4 ++ ld1 {v16.s}[0], [x0] // P8 ++ ushll v17.8h, v1.8b, #1 // 2*P5 ++ dup v18.8h, w2 // pq ++ ushll v2.8h, v2.8b, #1 // 2*P1 ++ uxtl v3.8h, v3.8b // P2 ++ uxtl v4.8h, v4.8b // P6 ++ uxtl v19.8h, v5.8b // P3 ++ mls v2.4h, v3.4h, v0.h[1] // 2*P1-5*P2 ++ uxtl v3.8h, v6.8b // P7 ++ mls v17.4h, v4.4h, v0.h[1] // 2*P5-5*P6 ++ ushll v5.8h, v5.8b, #1 // 2*P3 ++ uxtl v6.8h, v7.8b // P4 ++ mla v17.4h, v3.4h, v0.h[1] // 2*P5-5*P6+5*P7 ++ uxtl v3.8h, v16.8b // P8 ++ mla v2.4h, v19.4h, v0.h[1] // 2*P1-5*P2+5*P3 ++ uxtl v1.8h, v1.8b // P5 ++ mls v5.4h, v6.4h, v0.h[1] // 2*P3-5*P4 ++ mls v17.4h, v3.4h, v0.h[0] // 2*P5-5*P6+5*P7-2*P8 ++ sub v3.4h, v6.4h, v1.4h // P4-P5 ++ mls v2.4h, v6.4h, v0.h[0] // 2*P1-5*P2+5*P3-2*P4 ++ mla v5.4h, v1.4h, v0.h[1] // 2*P3-5*P4+5*P5 ++ mls v5.4h, v4.4h, v0.h[0] // 2*P3-5*P4+5*P5-2*P6 ++ abs v4.4h, v3.4h ++ srshr v7.4h, v17.4h, #3 ++ srshr v2.4h, v2.4h, #3 ++ sshr v4.4h, v4.4h, #1 // clip ++ srshr v5.4h, v5.4h, #3 ++ abs v7.4h, v7.4h // a2 ++ sshr v3.4h, v3.4h, #8 // clip_sign ++ abs v2.4h, v2.4h // a1 ++ cmeq v16.4h, v4.4h, #0 // test clip == 0 ++ abs v17.4h, v5.4h // a0 ++ sshr v5.4h, v5.4h, #8 // a0_sign ++ cmhs v19.4h, v2.4h, v7.4h // test a1 >= a2 ++ cmhs v18.4h, v17.4h, v18.4h // test a0 >= pq ++ sub v3.4h, v3.4h, v5.4h // clip_sign - a0_sign ++ bsl v19.8b, v7.8b, v2.8b // a3 ++ orr v2.8b, v16.8b, v18.8b // test clip == 0 || a0 >= pq ++ uqsub v5.4h, v17.4h, v19.4h // a0 >= a3 ? a0-a3 : 0 (a0 > a3 in all cases where filtering is enabled, so makes more sense to subtract this way round than the opposite and then taking the abs) ++ cmhs v7.4h, v19.4h, v17.4h // test a3 >= a0 ++ mul v0.4h, v5.4h, v0.h[1] // a0 >= a3 ? 5*(a0-a3) : 0 ++ orr v5.8b, v2.8b, v7.8b // test clip == 0 || a0 >= pq || a3 >= a0 ++ mov w0, v5.s[1] // move to gp reg ++ ushr v0.4h, v0.4h, #3 // a0 >= a3 ? (5*(a0-a3))>>3 : 0 ++ cmhs v5.4h, v0.4h, v4.4h ++ tbnz w0, #0, 1f // none of the 4 pixel pairs should be updated if this one is not filtered ++ bsl v5.8b, v4.8b, v0.8b // FFMIN(d, clip) ++ bic v0.8b, v5.8b, v2.8b // set each d to zero if it should not be filtered because clip == 0 || a0 >= pq (a3 > a0 case already zeroed by saturating sub) ++ mls v6.4h, v0.4h, v3.4h // invert d depending on clip_sign & a0_sign, or zero it if they match, and accumulate into P4 ++ mla v1.4h, v0.4h, v3.4h // invert d depending on clip_sign & a0_sign, or zero it if they match, and accumulate into P5 ++ sqxtun v0.8b, v6.8h ++ sqxtun v1.8b, v1.8h ++ st1 {v0.s}[0], [x3], x1 ++ st1 {v1.s}[0], [x3] ++1: ret ++endfunc ++ ++// VC-1 in-loop deblocking filter for 4 pixel pairs at boundary of horizontally-neighbouring blocks ++// On entry: ++// x0 -> top-left pel of right block ++// x1 = row stride, bytes ++// w2 = PQUANT bitstream parameter ++function ff_vc1_h_loop_filter4_neon, export=1 ++ sub x3, x0, #4 // where to start reading ++ ldr d0, .Lcoeffs ++ ld1 {v1.8b}, [x3], x1 ++ sub x0, x0, #1 // where to start writing ++ ld1 {v2.8b}, [x3], x1 ++ ld1 {v3.8b}, [x3], x1 ++ ld1 {v4.8b}, [x3] ++ dup v5.8h, w2 // pq ++ trn1 v6.8b, v1.8b, v2.8b ++ trn2 v1.8b, v1.8b, v2.8b ++ trn1 v2.8b, v3.8b, v4.8b ++ trn2 v3.8b, v3.8b, v4.8b ++ trn1 v4.4h, v6.4h, v2.4h // P1, P5 ++ trn1 v7.4h, v1.4h, v3.4h // P2, P6 ++ trn2 v2.4h, v6.4h, v2.4h // P3, P7 ++ trn2 v1.4h, v1.4h, v3.4h // P4, P8 ++ ushll v3.8h, v4.8b, #1 // 2*P1, 2*P5 ++ uxtl v6.8h, v7.8b // P2, P6 ++ uxtl v7.8h, v2.8b // P3, P7 ++ uxtl v1.8h, v1.8b // P4, P8 ++ mls v3.8h, v6.8h, v0.h[1] // 2*P1-5*P2, 2*P5-5*P6 ++ ushll v2.8h, v2.8b, #1 // 2*P3, 2*P7 ++ uxtl v4.8h, v4.8b // P1, P5 ++ mla v3.8h, v7.8h, v0.h[1] // 2*P1-5*P2+5*P3, 2*P5-5*P6+5*P7 ++ mov d6, v6.d[1] // P6 ++ mls v3.8h, v1.8h, v0.h[0] // 2*P1-5*P2+5*P3-2*P4, 2*P5-5*P6+5*P7-2*P8 ++ mov d4, v4.d[1] // P5 ++ mls v2.4h, v1.4h, v0.h[1] // 2*P3-5*P4 ++ mla v2.4h, v4.4h, v0.h[1] // 2*P3-5*P4+5*P5 ++ sub v7.4h, v1.4h, v4.4h // P4-P5 ++ mls v2.4h, v6.4h, v0.h[0] // 2*P3-5*P4+5*P5-2*P6 ++ srshr v3.8h, v3.8h, #3 ++ abs v6.4h, v7.4h ++ sshr v7.4h, v7.4h, #8 // clip_sign ++ srshr v2.4h, v2.4h, #3 ++ abs v3.8h, v3.8h // a1, a2 ++ sshr v6.4h, v6.4h, #1 // clip ++ mov d16, v3.d[1] // a2 ++ abs v17.4h, v2.4h // a0 ++ cmeq v18.4h, v6.4h, #0 // test clip == 0 ++ sshr v2.4h, v2.4h, #8 // a0_sign ++ cmhs v19.4h, v3.4h, v16.4h // test a1 >= a2 ++ cmhs v5.4h, v17.4h, v5.4h // test a0 >= pq ++ sub v2.4h, v7.4h, v2.4h // clip_sign - a0_sign ++ bsl v19.8b, v16.8b, v3.8b // a3 ++ orr v3.8b, v18.8b, v5.8b // test clip == 0 || a0 >= pq ++ uqsub v5.4h, v17.4h, v19.4h // a0 >= a3 ? a0-a3 : 0 (a0 > a3 in all cases where filtering is enabled, so makes more sense to subtract this way round than the opposite and then taking the abs) ++ cmhs v7.4h, v19.4h, v17.4h // test a3 >= a0 ++ mul v0.4h, v5.4h, v0.h[1] // a0 >= a3 ? 5*(a0-a3) : 0 ++ orr v5.8b, v3.8b, v7.8b // test clip == 0 || a0 >= pq || a3 >= a0 ++ mov w2, v5.s[1] // move to gp reg ++ ushr v0.4h, v0.4h, #3 // a0 >= a3 ? (5*(a0-a3))>>3 : 0 ++ cmhs v5.4h, v0.4h, v6.4h ++ tbnz w2, #0, 1f // none of the 4 pixel pairs should be updated if this one is not filtered ++ bsl v5.8b, v6.8b, v0.8b // FFMIN(d, clip) ++ bic v0.8b, v5.8b, v3.8b // set each d to zero if it should not be filtered because clip == 0 || a0 >= pq (a3 > a0 case already zeroed by saturating sub) ++ mla v4.4h, v0.4h, v2.4h // invert d depending on clip_sign & a0_sign, or zero it if they match, and accumulate into P5 ++ mls v1.4h, v0.4h, v2.4h // invert d depending on clip_sign & a0_sign, or zero it if they match, and accumulate into P4 ++ sqxtun v3.8b, v4.8h ++ sqxtun v2.8b, v1.8h ++ st2 {v2.b, v3.b}[0], [x0], x1 ++ st2 {v2.b, v3.b}[1], [x0], x1 ++ st2 {v2.b, v3.b}[2], [x0], x1 ++ st2 {v2.b, v3.b}[3], [x0] ++1: ret ++endfunc ++ ++// VC-1 in-loop deblocking filter for 8 pixel pairs at boundary of vertically-neighbouring blocks ++// On entry: ++// x0 -> top-left pel of lower block ++// x1 = row stride, bytes ++// w2 = PQUANT bitstream parameter ++function ff_vc1_v_loop_filter8_neon, export=1 ++ sub x3, x0, w1, sxtw #2 ++ ldr d0, .Lcoeffs ++ ld1 {v1.8b}, [x0], x1 // P5 ++ movi v2.2d, #0x0000ffff00000000 ++ ld1 {v3.8b}, [x3], x1 // P1 ++ ld1 {v4.8b}, [x3], x1 // P2 ++ ld1 {v5.8b}, [x0], x1 // P6 ++ ld1 {v6.8b}, [x3], x1 // P3 ++ ld1 {v7.8b}, [x0], x1 // P7 ++ ushll v16.8h, v1.8b, #1 // 2*P5 ++ ushll v3.8h, v3.8b, #1 // 2*P1 ++ ld1 {v17.8b}, [x3] // P4 ++ uxtl v4.8h, v4.8b // P2 ++ ld1 {v18.8b}, [x0] // P8 ++ uxtl v5.8h, v5.8b // P6 ++ dup v19.8h, w2 // pq ++ uxtl v20.8h, v6.8b // P3 ++ mls v3.8h, v4.8h, v0.h[1] // 2*P1-5*P2 ++ uxtl v4.8h, v7.8b // P7 ++ ushll v6.8h, v6.8b, #1 // 2*P3 ++ mls v16.8h, v5.8h, v0.h[1] // 2*P5-5*P6 ++ uxtl v7.8h, v17.8b // P4 ++ uxtl v17.8h, v18.8b // P8 ++ mla v16.8h, v4.8h, v0.h[1] // 2*P5-5*P6+5*P7 ++ uxtl v1.8h, v1.8b // P5 ++ mla v3.8h, v20.8h, v0.h[1] // 2*P1-5*P2+5*P3 ++ sub v4.8h, v7.8h, v1.8h // P4-P5 ++ mls v6.8h, v7.8h, v0.h[1] // 2*P3-5*P4 ++ mls v16.8h, v17.8h, v0.h[0] // 2*P5-5*P6+5*P7-2*P8 ++ abs v17.8h, v4.8h ++ sshr v4.8h, v4.8h, #8 // clip_sign ++ mls v3.8h, v7.8h, v0.h[0] // 2*P1-5*P2+5*P3-2*P4 ++ sshr v17.8h, v17.8h, #1 // clip ++ mla v6.8h, v1.8h, v0.h[1] // 2*P3-5*P4+5*P5 ++ srshr v16.8h, v16.8h, #3 ++ mls v6.8h, v5.8h, v0.h[0] // 2*P3-5*P4+5*P5-2*P6 ++ cmeq v5.8h, v17.8h, #0 // test clip == 0 ++ srshr v3.8h, v3.8h, #3 ++ abs v16.8h, v16.8h // a2 ++ abs v3.8h, v3.8h // a1 ++ srshr v6.8h, v6.8h, #3 ++ cmhs v18.8h, v3.8h, v16.8h // test a1 >= a2 ++ abs v20.8h, v6.8h // a0 ++ sshr v6.8h, v6.8h, #8 // a0_sign ++ bsl v18.16b, v16.16b, v3.16b // a3 ++ cmhs v3.8h, v20.8h, v19.8h // test a0 >= pq ++ sub v4.8h, v4.8h, v6.8h // clip_sign - a0_sign ++ uqsub v6.8h, v20.8h, v18.8h // a0 >= a3 ? a0-a3 : 0 (a0 > a3 in all cases where filtering is enabled, so makes more sense to subtract this way round than the opposite and then taking the abs) ++ cmhs v16.8h, v18.8h, v20.8h // test a3 >= a0 ++ orr v3.16b, v5.16b, v3.16b // test clip == 0 || a0 >= pq ++ mul v0.8h, v6.8h, v0.h[1] // a0 >= a3 ? 5*(a0-a3) : 0 ++ orr v5.16b, v3.16b, v16.16b // test clip == 0 || a0 >= pq || a3 >= a0 ++ cmtst v2.2d, v5.2d, v2.2d // if 2nd of each group of is not filtered, then none of the others in the group should be either ++ mov w0, v5.s[1] // move to gp reg ++ ushr v0.8h, v0.8h, #3 // a0 >= a3 ? (5*(a0-a3))>>3 : 0 ++ mov w2, v5.s[3] ++ orr v2.16b, v3.16b, v2.16b ++ cmhs v3.8h, v0.8h, v17.8h ++ and w0, w0, w2 ++ bsl v3.16b, v17.16b, v0.16b // FFMIN(d, clip) ++ tbnz w0, #0, 1f // none of the 8 pixel pairs should be updated in this case ++ bic v0.16b, v3.16b, v2.16b // set each d to zero if it should not be filtered ++ mls v7.8h, v0.8h, v4.8h // invert d depending on clip_sign & a0_sign, or zero it if they match, and accumulate into P4 ++ mla v1.8h, v0.8h, v4.8h // invert d depending on clip_sign & a0_sign, or zero it if they match, and accumulate into P5 ++ sqxtun v0.8b, v7.8h ++ sqxtun v1.8b, v1.8h ++ st1 {v0.8b}, [x3], x1 ++ st1 {v1.8b}, [x3] ++1: ret ++endfunc ++ ++// VC-1 in-loop deblocking filter for 8 pixel pairs at boundary of horizontally-neighbouring blocks ++// On entry: ++// x0 -> top-left pel of right block ++// x1 = row stride, bytes ++// w2 = PQUANT bitstream parameter ++function ff_vc1_h_loop_filter8_neon, export=1 ++ sub x3, x0, #4 // where to start reading ++ ldr d0, .Lcoeffs ++ ld1 {v1.8b}, [x3], x1 // P1[0], P2[0]... ++ sub x0, x0, #1 // where to start writing ++ ld1 {v2.8b}, [x3], x1 ++ add x4, x0, x1, lsl #2 ++ ld1 {v3.8b}, [x3], x1 ++ ld1 {v4.8b}, [x3], x1 ++ ld1 {v5.8b}, [x3], x1 ++ ld1 {v6.8b}, [x3], x1 ++ ld1 {v7.8b}, [x3], x1 ++ trn1 v16.8b, v1.8b, v2.8b // P1[0], P1[1], P3[0]... ++ ld1 {v17.8b}, [x3] ++ trn2 v1.8b, v1.8b, v2.8b // P2[0], P2[1], P4[0]... ++ trn1 v2.8b, v3.8b, v4.8b // P1[2], P1[3], P3[2]... ++ trn2 v3.8b, v3.8b, v4.8b // P2[2], P2[3], P4[2]... ++ dup v4.8h, w2 // pq ++ trn1 v18.8b, v5.8b, v6.8b // P1[4], P1[5], P3[4]... ++ trn2 v5.8b, v5.8b, v6.8b // P2[4], P2[5], P4[4]... ++ trn1 v6.4h, v16.4h, v2.4h // P1[0], P1[1], P1[2], P1[3], P5[0]... ++ trn1 v19.4h, v1.4h, v3.4h // P2[0], P2[1], P2[2], P2[3], P6[0]... ++ trn1 v20.8b, v7.8b, v17.8b // P1[6], P1[7], P3[6]... ++ trn2 v7.8b, v7.8b, v17.8b // P2[6], P2[7], P4[6]... ++ trn2 v2.4h, v16.4h, v2.4h // P3[0], P3[1], P3[2], P3[3], P7[0]... ++ trn2 v1.4h, v1.4h, v3.4h // P4[0], P4[1], P4[2], P4[3], P8[0]... ++ trn1 v3.4h, v18.4h, v20.4h // P1[4], P1[5], P1[6], P1[7], P5[4]... ++ trn1 v16.4h, v5.4h, v7.4h // P2[4], P2[5], P2[6], P2[7], P6[4]... ++ trn2 v17.4h, v18.4h, v20.4h // P3[4], P3[5], P3[6], P3[7], P7[4]... ++ trn2 v5.4h, v5.4h, v7.4h // P4[4], P4[5], P4[6], P4[7], P8[4]... ++ trn1 v7.2s, v6.2s, v3.2s // P1 ++ trn1 v18.2s, v19.2s, v16.2s // P2 ++ trn2 v3.2s, v6.2s, v3.2s // P5 ++ trn2 v6.2s, v19.2s, v16.2s // P6 ++ trn1 v16.2s, v2.2s, v17.2s // P3 ++ trn2 v2.2s, v2.2s, v17.2s // P7 ++ ushll v7.8h, v7.8b, #1 // 2*P1 ++ trn1 v17.2s, v1.2s, v5.2s // P4 ++ ushll v19.8h, v3.8b, #1 // 2*P5 ++ trn2 v1.2s, v1.2s, v5.2s // P8 ++ uxtl v5.8h, v18.8b // P2 ++ uxtl v6.8h, v6.8b // P6 ++ uxtl v18.8h, v16.8b // P3 ++ mls v7.8h, v5.8h, v0.h[1] // 2*P1-5*P2 ++ uxtl v2.8h, v2.8b // P7 ++ ushll v5.8h, v16.8b, #1 // 2*P3 ++ mls v19.8h, v6.8h, v0.h[1] // 2*P5-5*P6 ++ uxtl v16.8h, v17.8b // P4 ++ uxtl v1.8h, v1.8b // P8 ++ mla v19.8h, v2.8h, v0.h[1] // 2*P5-5*P6+5*P7 ++ uxtl v2.8h, v3.8b // P5 ++ mla v7.8h, v18.8h, v0.h[1] // 2*P1-5*P2+5*P3 ++ sub v3.8h, v16.8h, v2.8h // P4-P5 ++ mls v5.8h, v16.8h, v0.h[1] // 2*P3-5*P4 ++ mls v19.8h, v1.8h, v0.h[0] // 2*P5-5*P6+5*P7-2*P8 ++ abs v1.8h, v3.8h ++ sshr v3.8h, v3.8h, #8 // clip_sign ++ mls v7.8h, v16.8h, v0.h[0] // 2*P1-5*P2+5*P3-2*P4 ++ sshr v1.8h, v1.8h, #1 // clip ++ mla v5.8h, v2.8h, v0.h[1] // 2*P3-5*P4+5*P5 ++ srshr v17.8h, v19.8h, #3 ++ mls v5.8h, v6.8h, v0.h[0] // 2*P3-5*P4+5*P5-2*P6 ++ cmeq v6.8h, v1.8h, #0 // test clip == 0 ++ srshr v7.8h, v7.8h, #3 ++ abs v17.8h, v17.8h // a2 ++ abs v7.8h, v7.8h // a1 ++ srshr v5.8h, v5.8h, #3 ++ cmhs v18.8h, v7.8h, v17.8h // test a1 >= a2 ++ abs v19.8h, v5.8h // a0 ++ sshr v5.8h, v5.8h, #8 // a0_sign ++ bsl v18.16b, v17.16b, v7.16b // a3 ++ cmhs v4.8h, v19.8h, v4.8h // test a0 >= pq ++ sub v3.8h, v3.8h, v5.8h // clip_sign - a0_sign ++ uqsub v5.8h, v19.8h, v18.8h // a0 >= a3 ? a0-a3 : 0 (a0 > a3 in all cases where filtering is enabled, so makes more sense to subtract this way round than the opposite and then taking the abs) ++ cmhs v7.8h, v18.8h, v19.8h // test a3 >= a0 ++ orr v4.16b, v6.16b, v4.16b // test clip == 0 || a0 >= pq ++ mul v0.8h, v5.8h, v0.h[1] // a0 >= a3 ? 5*(a0-a3) : 0 ++ orr v5.16b, v4.16b, v7.16b // test clip == 0 || a0 >= pq || a3 >= a0 ++ mov w2, v5.s[1] // move to gp reg ++ ushr v0.8h, v0.8h, #3 // a0 >= a3 ? (5*(a0-a3))>>3 : 0 ++ mov w3, v5.s[3] ++ cmhs v5.8h, v0.8h, v1.8h ++ and w5, w2, w3 ++ bsl v5.16b, v1.16b, v0.16b // FFMIN(d, clip) ++ tbnz w5, #0, 2f // none of the 8 pixel pairs should be updated in this case ++ bic v0.16b, v5.16b, v4.16b // set each d to zero if it should not be filtered because clip == 0 || a0 >= pq (a3 > a0 case already zeroed by saturating sub) ++ mla v2.8h, v0.8h, v3.8h // invert d depending on clip_sign & a0_sign, or zero it if they match, and accumulate into P5 ++ mls v16.8h, v0.8h, v3.8h // invert d depending on clip_sign & a0_sign, or zero it if they match, and accumulate into P4 ++ sqxtun v1.8b, v2.8h ++ sqxtun v0.8b, v16.8h ++ tbnz w2, #0, 1f // none of the first 4 pixel pairs should be updated if so ++ st2 {v0.b, v1.b}[0], [x0], x1 ++ st2 {v0.b, v1.b}[1], [x0], x1 ++ st2 {v0.b, v1.b}[2], [x0], x1 ++ st2 {v0.b, v1.b}[3], [x0] ++1: tbnz w3, #0, 2f // none of the second 4 pixel pairs should be updated if so ++ st2 {v0.b, v1.b}[4], [x4], x1 ++ st2 {v0.b, v1.b}[5], [x4], x1 ++ st2 {v0.b, v1.b}[6], [x4], x1 ++ st2 {v0.b, v1.b}[7], [x4] ++2: ret ++endfunc ++ ++// VC-1 in-loop deblocking filter for 16 pixel pairs at boundary of vertically-neighbouring blocks ++// On entry: ++// x0 -> top-left pel of lower block ++// x1 = row stride, bytes ++// w2 = PQUANT bitstream parameter ++function ff_vc1_v_loop_filter16_neon, export=1 ++ sub x3, x0, w1, sxtw #2 ++ ldr d0, .Lcoeffs ++ ld1 {v1.16b}, [x0], x1 // P5 ++ movi v2.2d, #0x0000ffff00000000 ++ ld1 {v3.16b}, [x3], x1 // P1 ++ ld1 {v4.16b}, [x3], x1 // P2 ++ ld1 {v5.16b}, [x0], x1 // P6 ++ ld1 {v6.16b}, [x3], x1 // P3 ++ ld1 {v7.16b}, [x0], x1 // P7 ++ ushll v16.8h, v1.8b, #1 // 2*P5[0..7] ++ ushll v17.8h, v3.8b, #1 // 2*P1[0..7] ++ ld1 {v18.16b}, [x3] // P4 ++ uxtl v19.8h, v4.8b // P2[0..7] ++ ld1 {v20.16b}, [x0] // P8 ++ uxtl v21.8h, v5.8b // P6[0..7] ++ dup v22.8h, w2 // pq ++ ushll2 v3.8h, v3.16b, #1 // 2*P1[8..15] ++ mls v17.8h, v19.8h, v0.h[1] // 2*P1[0..7]-5*P2[0..7] ++ ushll2 v19.8h, v1.16b, #1 // 2*P5[8..15] ++ uxtl2 v4.8h, v4.16b // P2[8..15] ++ mls v16.8h, v21.8h, v0.h[1] // 2*P5[0..7]-5*P6[0..7] ++ uxtl2 v5.8h, v5.16b // P6[8..15] ++ uxtl v23.8h, v6.8b // P3[0..7] ++ uxtl v24.8h, v7.8b // P7[0..7] ++ mls v3.8h, v4.8h, v0.h[1] // 2*P1[8..15]-5*P2[8..15] ++ ushll v4.8h, v6.8b, #1 // 2*P3[0..7] ++ uxtl v25.8h, v18.8b // P4[0..7] ++ mls v19.8h, v5.8h, v0.h[1] // 2*P5[8..15]-5*P6[8..15] ++ uxtl2 v26.8h, v6.16b // P3[8..15] ++ mla v17.8h, v23.8h, v0.h[1] // 2*P1[0..7]-5*P2[0..7]+5*P3[0..7] ++ uxtl2 v7.8h, v7.16b // P7[8..15] ++ ushll2 v6.8h, v6.16b, #1 // 2*P3[8..15] ++ mla v16.8h, v24.8h, v0.h[1] // 2*P5[0..7]-5*P6[0..7]+5*P7[0..7] ++ uxtl2 v18.8h, v18.16b // P4[8..15] ++ uxtl v23.8h, v20.8b // P8[0..7] ++ mls v4.8h, v25.8h, v0.h[1] // 2*P3[0..7]-5*P4[0..7] ++ uxtl v24.8h, v1.8b // P5[0..7] ++ uxtl2 v20.8h, v20.16b // P8[8..15] ++ mla v3.8h, v26.8h, v0.h[1] // 2*P1[8..15]-5*P2[8..15]+5*P3[8..15] ++ uxtl2 v1.8h, v1.16b // P5[8..15] ++ sub v26.8h, v25.8h, v24.8h // P4[0..7]-P5[0..7] ++ mla v19.8h, v7.8h, v0.h[1] // 2*P5[8..15]-5*P6[8..15]+5*P7[8..15] ++ sub v7.8h, v18.8h, v1.8h // P4[8..15]-P5[8..15] ++ mls v6.8h, v18.8h, v0.h[1] // 2*P3[8..15]-5*P4[8..15] ++ abs v27.8h, v26.8h ++ sshr v26.8h, v26.8h, #8 // clip_sign[0..7] ++ mls v17.8h, v25.8h, v0.h[0] // 2*P1[0..7]-5*P2[0..7]+5*P3[0..7]-2*P4[0..7] ++ abs v28.8h, v7.8h ++ sshr v27.8h, v27.8h, #1 // clip[0..7] ++ mls v16.8h, v23.8h, v0.h[0] // 2*P5[0..7]-5*P6[0..7]+5*P7[0..7]-2*P8[0..7] ++ sshr v7.8h, v7.8h, #8 // clip_sign[8..15] ++ sshr v23.8h, v28.8h, #1 // clip[8..15] ++ mla v4.8h, v24.8h, v0.h[1] // 2*P3[0..7]-5*P4[0..7]+5*P5[0..7] ++ cmeq v28.8h, v27.8h, #0 // test clip[0..7] == 0 ++ srshr v17.8h, v17.8h, #3 ++ mls v3.8h, v18.8h, v0.h[0] // 2*P1[8..15]-5*P2[8..15]+5*P3[8..15]-2*P4[8..15] ++ cmeq v29.8h, v23.8h, #0 // test clip[8..15] == 0 ++ srshr v16.8h, v16.8h, #3 ++ mls v19.8h, v20.8h, v0.h[0] // 2*P5[8..15]-5*P6[8..15]+5*P7[8..15]-2*P8[8..15] ++ abs v17.8h, v17.8h // a1[0..7] ++ mla v6.8h, v1.8h, v0.h[1] // 2*P3[8..15]-5*P4[8..15]+5*P5[8..15] ++ srshr v3.8h, v3.8h, #3 ++ mls v4.8h, v21.8h, v0.h[0] // 2*P3[0..7]-5*P4[0..7]+5*P5[0..7]-2*P6[0..7] ++ abs v16.8h, v16.8h // a2[0..7] ++ srshr v19.8h, v19.8h, #3 ++ mls v6.8h, v5.8h, v0.h[0] // 2*P3[8..15]-5*P4[8..15]+5*P5[8..15]-2*P6[8..15] ++ cmhs v5.8h, v17.8h, v16.8h // test a1[0..7] >= a2[0..7] ++ abs v3.8h, v3.8h // a1[8..15] ++ srshr v4.8h, v4.8h, #3 ++ abs v19.8h, v19.8h // a2[8..15] ++ bsl v5.16b, v16.16b, v17.16b // a3[0..7] ++ srshr v6.8h, v6.8h, #3 ++ cmhs v16.8h, v3.8h, v19.8h // test a1[8..15] >= a2[8.15] ++ abs v17.8h, v4.8h // a0[0..7] ++ sshr v4.8h, v4.8h, #8 // a0_sign[0..7] ++ bsl v16.16b, v19.16b, v3.16b // a3[8..15] ++ uqsub v3.8h, v17.8h, v5.8h // a0[0..7] >= a3[0..7] ? a0[0..7]-a3[0..7] : 0 (a0 > a3 in all cases where filtering is enabled, so makes more sense to subtract this way round than the opposite and then taking the abs) ++ abs v19.8h, v6.8h // a0[8..15] ++ cmhs v20.8h, v17.8h, v22.8h // test a0[0..7] >= pq ++ cmhs v5.8h, v5.8h, v17.8h // test a3[0..7] >= a0[0..7] ++ sub v4.8h, v26.8h, v4.8h // clip_sign[0..7] - a0_sign[0..7] ++ sshr v6.8h, v6.8h, #8 // a0_sign[8..15] ++ mul v3.8h, v3.8h, v0.h[1] // a0[0..7] >= a3[0..7] ? 5*(a0[0..7]-a3[0..7]) : 0 ++ uqsub v17.8h, v19.8h, v16.8h // a0[8..15] >= a3[8..15] ? a0[8..15]-a3[8..15] : 0 (a0 > a3 in all cases where filtering is enabled, so makes more sense to subtract this way round than the opposite and then taking the abs) ++ orr v20.16b, v28.16b, v20.16b // test clip[0..7] == 0 || a0[0..7] >= pq ++ cmhs v21.8h, v19.8h, v22.8h // test a0[8..15] >= pq ++ cmhs v16.8h, v16.8h, v19.8h // test a3[8..15] >= a0[8..15] ++ mul v0.8h, v17.8h, v0.h[1] // a0[8..15] >= a3[8..15] ? 5*(a0[8..15]-a3[8..15]) : 0 ++ sub v6.8h, v7.8h, v6.8h // clip_sign[8..15] - a0_sign[8..15] ++ orr v5.16b, v20.16b, v5.16b // test clip[0..7] == 0 || a0[0..7] >= pq || a3[0..7] >= a0[0..7] ++ ushr v3.8h, v3.8h, #3 // a0[0..7] >= a3[0..7] ? (5*(a0[0..7]-a3[0..7]))>>3 : 0 ++ orr v7.16b, v29.16b, v21.16b // test clip[8..15] == 0 || a0[8..15] >= pq ++ cmtst v17.2d, v5.2d, v2.2d // if 2nd of each group of is not filtered, then none of the others in the group should be either ++ mov w0, v5.s[1] // move to gp reg ++ cmhs v19.8h, v3.8h, v27.8h ++ ushr v0.8h, v0.8h, #3 // a0[8..15] >= a3[8..15] ? (5*(a0[8..15]-a3[8..15]))>>3 : 0 ++ mov w2, v5.s[3] ++ orr v5.16b, v7.16b, v16.16b // test clip[8..15] == 0 || a0[8..15] >= pq || a3[8..15] >= a0[8..15] ++ orr v16.16b, v20.16b, v17.16b ++ bsl v19.16b, v27.16b, v3.16b // FFMIN(d[0..7], clip[0..7]) ++ cmtst v2.2d, v5.2d, v2.2d ++ cmhs v3.8h, v0.8h, v23.8h ++ mov w4, v5.s[1] ++ mov w5, v5.s[3] ++ and w0, w0, w2 ++ bic v5.16b, v19.16b, v16.16b // set each d[0..7] to zero if it should not be filtered because clip[0..7] == 0 || a0[0..7] >= pq (a3 > a0 case already zeroed by saturating sub) ++ orr v2.16b, v7.16b, v2.16b ++ bsl v3.16b, v23.16b, v0.16b // FFMIN(d[8..15], clip[8..15]) ++ mls v25.8h, v5.8h, v4.8h // invert d[0..7] depending on clip_sign[0..7] & a0_sign[0..7], or zero it if they match, and accumulate into P4[0..7] ++ and w2, w4, w5 ++ bic v0.16b, v3.16b, v2.16b // set each d[8..15] to zero if it should not be filtered because clip[8..15] == 0 || a0[8..15] >= pq (a3 > a0 case already zeroed by saturating sub) ++ mla v24.8h, v5.8h, v4.8h // invert d[0..7] depending on clip_sign[0..7] & a0_sign[0..7], or zero it if they match, and accumulate into P5[0..7] ++ and w0, w0, w2 ++ mls v18.8h, v0.8h, v6.8h // invert d[8..15] depending on clip_sign[8..15] & a0_sign[8..15], or zero it if they match, and accumulate into P4[8..15] ++ sqxtun v2.8b, v25.8h ++ tbnz w0, #0, 1f // none of the 16 pixel pairs should be updated in this case ++ mla v1.8h, v0.8h, v6.8h // invert d[8..15] depending on clip_sign[8..15] & a0_sign[8..15], or zero it if they match, and accumulate into P5[8..15] ++ sqxtun v0.8b, v24.8h ++ sqxtun2 v2.16b, v18.8h ++ sqxtun2 v0.16b, v1.8h ++ st1 {v2.16b}, [x3], x1 ++ st1 {v0.16b}, [x3] ++1: ret ++endfunc ++ ++// VC-1 in-loop deblocking filter for 16 pixel pairs at boundary of horizontally-neighbouring blocks ++// On entry: ++// x0 -> top-left pel of right block ++// x1 = row stride, bytes ++// w2 = PQUANT bitstream parameter ++function ff_vc1_h_loop_filter16_neon, export=1 ++ sub x3, x0, #4 // where to start reading ++ ldr d0, .Lcoeffs ++ ld1 {v1.8b}, [x3], x1 // P1[0], P2[0]... ++ sub x0, x0, #1 // where to start writing ++ ld1 {v2.8b}, [x3], x1 ++ add x4, x0, x1, lsl #3 ++ ld1 {v3.8b}, [x3], x1 ++ add x5, x0, x1, lsl #2 ++ ld1 {v4.8b}, [x3], x1 ++ add x6, x4, x1, lsl #2 ++ ld1 {v5.8b}, [x3], x1 ++ ld1 {v6.8b}, [x3], x1 ++ ld1 {v7.8b}, [x3], x1 ++ trn1 v16.8b, v1.8b, v2.8b // P1[0], P1[1], P3[0]... ++ ld1 {v17.8b}, [x3], x1 ++ trn2 v1.8b, v1.8b, v2.8b // P2[0], P2[1], P4[0]... ++ ld1 {v2.8b}, [x3], x1 ++ trn1 v18.8b, v3.8b, v4.8b // P1[2], P1[3], P3[2]... ++ ld1 {v19.8b}, [x3], x1 ++ trn2 v3.8b, v3.8b, v4.8b // P2[2], P2[3], P4[2]... ++ ld1 {v4.8b}, [x3], x1 ++ trn1 v20.8b, v5.8b, v6.8b // P1[4], P1[5], P3[4]... ++ ld1 {v21.8b}, [x3], x1 ++ trn2 v5.8b, v5.8b, v6.8b // P2[4], P2[5], P4[4]... ++ ld1 {v6.8b}, [x3], x1 ++ trn1 v22.8b, v7.8b, v17.8b // P1[6], P1[7], P3[6]... ++ ld1 {v23.8b}, [x3], x1 ++ trn2 v7.8b, v7.8b, v17.8b // P2[6], P2[7], P4[6]... ++ ld1 {v17.8b}, [x3], x1 ++ trn1 v24.8b, v2.8b, v19.8b // P1[8], P1[9], P3[8]... ++ ld1 {v25.8b}, [x3] ++ trn2 v2.8b, v2.8b, v19.8b // P2[8], P2[9], P4[8]... ++ trn1 v19.4h, v16.4h, v18.4h // P1[0], P1[1], P1[2], P1[3], P5[0]... ++ trn1 v26.8b, v4.8b, v21.8b // P1[10], P1[11], P3[10]... ++ trn2 v4.8b, v4.8b, v21.8b // P2[10], P2[11], P4[10]... ++ trn1 v21.4h, v1.4h, v3.4h // P2[0], P2[1], P2[2], P2[3], P6[0]... ++ trn1 v27.4h, v20.4h, v22.4h // P1[4], P1[5], P1[6], P1[7], P5[4]... ++ trn1 v28.8b, v6.8b, v23.8b // P1[12], P1[13], P3[12]... ++ trn2 v6.8b, v6.8b, v23.8b // P2[12], P2[13], P4[12]... ++ trn1 v23.4h, v5.4h, v7.4h // P2[4], P2[5], P2[6], P2[7], P6[4]... ++ trn1 v29.4h, v24.4h, v26.4h // P1[8], P1[9], P1[10], P1[11], P5[8]... ++ trn1 v30.8b, v17.8b, v25.8b // P1[14], P1[15], P3[14]... ++ trn2 v17.8b, v17.8b, v25.8b // P2[14], P2[15], P4[14]... ++ trn1 v25.4h, v2.4h, v4.4h // P2[8], P2[9], P2[10], P2[11], P6[8]... ++ trn1 v31.2s, v19.2s, v27.2s // P1[0..7] ++ trn2 v19.2s, v19.2s, v27.2s // P5[0..7] ++ trn1 v27.2s, v21.2s, v23.2s // P2[0..7] ++ trn2 v21.2s, v21.2s, v23.2s // P6[0..7] ++ trn1 v23.4h, v28.4h, v30.4h // P1[12], P1[13], P1[14], P1[15], P5[12]... ++ trn2 v16.4h, v16.4h, v18.4h // P3[0], P3[1], P3[2], P3[3], P7[0]... ++ trn1 v18.4h, v6.4h, v17.4h // P2[12], P2[13], P2[14], P2[15], P6[12]... ++ trn2 v20.4h, v20.4h, v22.4h // P3[4], P3[5], P3[6], P3[7], P7[4]... ++ trn2 v22.4h, v24.4h, v26.4h // P3[8], P3[9], P3[10], P3[11], P7[8]... ++ trn1 v24.2s, v29.2s, v23.2s // P1[8..15] ++ trn2 v23.2s, v29.2s, v23.2s // P5[8..15] ++ trn1 v26.2s, v25.2s, v18.2s // P2[8..15] ++ trn2 v18.2s, v25.2s, v18.2s // P6[8..15] ++ trn2 v25.4h, v28.4h, v30.4h // P3[12], P3[13], P3[14], P3[15], P7[12]... ++ trn2 v1.4h, v1.4h, v3.4h // P4[0], P4[1], P4[2], P4[3], P8[0]... ++ trn2 v3.4h, v5.4h, v7.4h // P4[4], P4[5], P4[6], P4[7], P8[4]... ++ trn2 v2.4h, v2.4h, v4.4h // P4[8], P4[9], P4[10], P4[11], P8[8]... ++ trn2 v4.4h, v6.4h, v17.4h // P4[12], P4[13], P4[14], P4[15], P8[12]... ++ ushll v5.8h, v31.8b, #1 // 2*P1[0..7] ++ ushll v6.8h, v19.8b, #1 // 2*P5[0..7] ++ trn1 v7.2s, v16.2s, v20.2s // P3[0..7] ++ uxtl v17.8h, v27.8b // P2[0..7] ++ trn2 v16.2s, v16.2s, v20.2s // P7[0..7] ++ uxtl v20.8h, v21.8b // P6[0..7] ++ trn1 v21.2s, v22.2s, v25.2s // P3[8..15] ++ ushll v24.8h, v24.8b, #1 // 2*P1[8..15] ++ trn2 v22.2s, v22.2s, v25.2s // P7[8..15] ++ ushll v25.8h, v23.8b, #1 // 2*P5[8..15] ++ trn1 v27.2s, v1.2s, v3.2s // P4[0..7] ++ uxtl v26.8h, v26.8b // P2[8..15] ++ mls v5.8h, v17.8h, v0.h[1] // 2*P1[0..7]-5*P2[0..7] ++ uxtl v17.8h, v18.8b // P6[8..15] ++ mls v6.8h, v20.8h, v0.h[1] // 2*P5[0..7]-5*P6[0..7] ++ trn1 v18.2s, v2.2s, v4.2s // P4[8..15] ++ uxtl v28.8h, v7.8b // P3[0..7] ++ mls v24.8h, v26.8h, v0.h[1] // 2*P1[8..15]-5*P2[8..15] ++ uxtl v16.8h, v16.8b // P7[0..7] ++ uxtl v26.8h, v21.8b // P3[8..15] ++ mls v25.8h, v17.8h, v0.h[1] // 2*P5[8..15]-5*P6[8..15] ++ uxtl v22.8h, v22.8b // P7[8..15] ++ ushll v7.8h, v7.8b, #1 // 2*P3[0..7] ++ uxtl v27.8h, v27.8b // P4[0..7] ++ trn2 v1.2s, v1.2s, v3.2s // P8[0..7] ++ ushll v3.8h, v21.8b, #1 // 2*P3[8..15] ++ trn2 v2.2s, v2.2s, v4.2s // P8[8..15] ++ uxtl v4.8h, v18.8b // P4[8..15] ++ mla v5.8h, v28.8h, v0.h[1] // 2*P1[0..7]-5*P2[0..7]+5*P3[0..7] ++ uxtl v1.8h, v1.8b // P8[0..7] ++ mla v6.8h, v16.8h, v0.h[1] // 2*P5[0..7]-5*P6[0..7]+5*P7[0..7] ++ uxtl v2.8h, v2.8b // P8[8..15] ++ uxtl v16.8h, v19.8b // P5[0..7] ++ mla v24.8h, v26.8h, v0.h[1] // 2*P1[8..15]-5*P2[8..15]+5*P3[8..15] ++ uxtl v18.8h, v23.8b // P5[8..15] ++ dup v19.8h, w2 // pq ++ mla v25.8h, v22.8h, v0.h[1] // 2*P5[8..15]-5*P6[8..15]+5*P7[8..15] ++ sub v21.8h, v27.8h, v16.8h // P4[0..7]-P5[0..7] ++ sub v22.8h, v4.8h, v18.8h // P4[8..15]-P5[8..15] ++ mls v7.8h, v27.8h, v0.h[1] // 2*P3[0..7]-5*P4[0..7] ++ abs v23.8h, v21.8h ++ mls v3.8h, v4.8h, v0.h[1] // 2*P3[8..15]-5*P4[8..15] ++ abs v26.8h, v22.8h ++ sshr v21.8h, v21.8h, #8 // clip_sign[0..7] ++ mls v5.8h, v27.8h, v0.h[0] // 2*P1[0..7]-5*P2[0..7]+5*P3[0..7]-2*P4[0..7] ++ sshr v23.8h, v23.8h, #1 // clip[0..7] ++ sshr v26.8h, v26.8h, #1 // clip[8..15] ++ mls v6.8h, v1.8h, v0.h[0] // 2*P5[0..7]-5*P6[0..7]+5*P7[0..7]-2*P8[0..7] ++ sshr v1.8h, v22.8h, #8 // clip_sign[8..15] ++ cmeq v22.8h, v23.8h, #0 // test clip[0..7] == 0 ++ mls v24.8h, v4.8h, v0.h[0] // 2*P1[8..15]-5*P2[8..15]+5*P3[8..15]-2*P4[8..15] ++ cmeq v28.8h, v26.8h, #0 // test clip[8..15] == 0 ++ srshr v5.8h, v5.8h, #3 ++ mls v25.8h, v2.8h, v0.h[0] // 2*P5[8..15]-5*P6[8..15]+5*P7[8..15]-2*P8[8..15] ++ srshr v2.8h, v6.8h, #3 ++ mla v7.8h, v16.8h, v0.h[1] // 2*P3[0..7]-5*P4[0..7]+5*P5[0..7] ++ srshr v6.8h, v24.8h, #3 ++ mla v3.8h, v18.8h, v0.h[1] // 2*P3[8..15]-5*P4[8..15]+5*P5[8..15] ++ abs v5.8h, v5.8h // a1[0..7] ++ srshr v24.8h, v25.8h, #3 ++ mls v3.8h, v17.8h, v0.h[0] // 2*P3[8..15]-5*P4[8..15]+5*P5[8..15]-2*P6[8..15] ++ abs v2.8h, v2.8h // a2[0..7] ++ abs v6.8h, v6.8h // a1[8..15] ++ mls v7.8h, v20.8h, v0.h[0] // 2*P3[0..7]-5*P4[0..7]+5*P5[0..7]-2*P6[0..7] ++ abs v17.8h, v24.8h // a2[8..15] ++ cmhs v20.8h, v5.8h, v2.8h // test a1[0..7] >= a2[0..7] ++ srshr v3.8h, v3.8h, #3 ++ cmhs v24.8h, v6.8h, v17.8h // test a1[8..15] >= a2[8.15] ++ srshr v7.8h, v7.8h, #3 ++ bsl v20.16b, v2.16b, v5.16b // a3[0..7] ++ abs v2.8h, v3.8h // a0[8..15] ++ sshr v3.8h, v3.8h, #8 // a0_sign[8..15] ++ bsl v24.16b, v17.16b, v6.16b // a3[8..15] ++ abs v5.8h, v7.8h // a0[0..7] ++ sshr v6.8h, v7.8h, #8 // a0_sign[0..7] ++ cmhs v7.8h, v2.8h, v19.8h // test a0[8..15] >= pq ++ sub v1.8h, v1.8h, v3.8h // clip_sign[8..15] - a0_sign[8..15] ++ uqsub v3.8h, v2.8h, v24.8h // a0[8..15] >= a3[8..15] ? a0[8..15]-a3[8..15] : 0 (a0 > a3 in all cases where filtering is enabled, so makes more sense to subtract this way round than the opposite and then taking the abs) ++ cmhs v2.8h, v24.8h, v2.8h // test a3[8..15] >= a0[8..15] ++ uqsub v17.8h, v5.8h, v20.8h // a0[0..7] >= a3[0..7] ? a0[0..7]-a3[0..7] : 0 (a0 > a3 in all cases where filtering is enabled, so makes more sense to subtract this way round than the opposite and then taking the abs) ++ cmhs v19.8h, v5.8h, v19.8h // test a0[0..7] >= pq ++ orr v7.16b, v28.16b, v7.16b // test clip[8..15] == 0 || a0[8..15] >= pq ++ sub v6.8h, v21.8h, v6.8h // clip_sign[0..7] - a0_sign[0..7] ++ mul v3.8h, v3.8h, v0.h[1] // a0[8..15] >= a3[8..15] ? 5*(a0[8..15]-a3[8..15]) : 0 ++ cmhs v5.8h, v20.8h, v5.8h // test a3[0..7] >= a0[0..7] ++ orr v19.16b, v22.16b, v19.16b // test clip[0..7] == 0 || a0[0..7] >= pq ++ mul v0.8h, v17.8h, v0.h[1] // a0[0..7] >= a3[0..7] ? 5*(a0[0..7]-a3[0..7]) : 0 ++ orr v2.16b, v7.16b, v2.16b // test clip[8..15] == 0 || a0[8..15] >= pq || a3[8..15] >= a0[8..15] ++ orr v5.16b, v19.16b, v5.16b // test clip[0..7] == 0 || a0[0..7] >= pq || a3[0..7] >= a0[0..7] ++ ushr v3.8h, v3.8h, #3 // a0[8..15] >= a3[8..15] ? (5*(a0[8..15]-a3[8..15]))>>3 : 0 ++ mov w7, v2.s[1] ++ mov w8, v2.s[3] ++ ushr v0.8h, v0.8h, #3 // a0[0..7] >= a3[0..7] ? (5*(a0[0..7]-a3[0..7]))>>3 : 0 ++ mov w2, v5.s[1] // move to gp reg ++ cmhs v2.8h, v3.8h, v26.8h ++ mov w3, v5.s[3] ++ cmhs v5.8h, v0.8h, v23.8h ++ bsl v2.16b, v26.16b, v3.16b // FFMIN(d[8..15], clip[8..15]) ++ and w9, w7, w8 ++ bsl v5.16b, v23.16b, v0.16b // FFMIN(d[0..7], clip[0..7]) ++ and w10, w2, w3 ++ bic v0.16b, v2.16b, v7.16b // set each d[8..15] to zero if it should not be filtered because clip[8..15] == 0 || a0[8..15] >= pq (a3 > a0 case already zeroed by saturating sub) ++ and w9, w10, w9 ++ bic v2.16b, v5.16b, v19.16b // set each d[0..7] to zero if it should not be filtered because clip[0..7] == 0 || a0[0..7] >= pq (a3 > a0 case already zeroed by saturating sub) ++ mls v4.8h, v0.8h, v1.8h // invert d[8..15] depending on clip_sign[8..15] & a0_sign[8..15], or zero it if they match, and accumulate into P4 ++ tbnz w9, #0, 4f // none of the 16 pixel pairs should be updated in this case ++ mls v27.8h, v2.8h, v6.8h // invert d[0..7] depending on clip_sign[0..7] & a0_sign[0..7], or zero it if they match, and accumulate into P4 ++ mla v16.8h, v2.8h, v6.8h // invert d[0..7] depending on clip_sign[0..7] & a0_sign[0..7], or zero it if they match, and accumulate into P5 ++ sqxtun v2.8b, v4.8h ++ mla v18.8h, v0.8h, v1.8h // invert d[8..15] depending on clip_sign[8..15] & a0_sign[8..15], or zero it if they match, and accumulate into P5 ++ sqxtun v0.8b, v27.8h ++ sqxtun v1.8b, v16.8h ++ sqxtun v3.8b, v18.8h ++ tbnz w2, #0, 1f ++ st2 {v0.b, v1.b}[0], [x0], x1 ++ st2 {v0.b, v1.b}[1], [x0], x1 ++ st2 {v0.b, v1.b}[2], [x0], x1 ++ st2 {v0.b, v1.b}[3], [x0] ++1: tbnz w3, #0, 2f ++ st2 {v0.b, v1.b}[4], [x5], x1 ++ st2 {v0.b, v1.b}[5], [x5], x1 ++ st2 {v0.b, v1.b}[6], [x5], x1 ++ st2 {v0.b, v1.b}[7], [x5] ++2: tbnz w7, #0, 3f ++ st2 {v2.b, v3.b}[0], [x4], x1 ++ st2 {v2.b, v3.b}[1], [x4], x1 ++ st2 {v2.b, v3.b}[2], [x4], x1 ++ st2 {v2.b, v3.b}[3], [x4] ++3: tbnz w8, #0, 4f ++ st2 {v2.b, v3.b}[4], [x6], x1 ++ st2 {v2.b, v3.b}[5], [x6], x1 ++ st2 {v2.b, v3.b}[6], [x6], x1 ++ st2 {v2.b, v3.b}[7], [x6] ++4: ret ++endfunc ++ ++// Copy at most the specified number of bytes from source to destination buffer, ++// stopping at a multiple of 32 bytes, none of which are the start of an escape sequence ++// On entry: ++// x0 -> source buffer ++// w1 = max number of bytes to copy ++// x2 -> destination buffer, optimally 8-byte aligned ++// On exit: ++// w0 = number of bytes not copied ++function ff_vc1_unescape_buffer_helper_neon, export=1 ++ // Offset by 80 to screen out cases that are too short for us to handle, ++ // and also make it easy to test for loop termination, or to determine ++ // whether we need an odd number of half-iterations of the loop. ++ subs w1, w1, #80 ++ b.mi 90f ++ ++ // Set up useful constants ++ movi v20.4s, #3, lsl #24 ++ movi v21.4s, #3, lsl #16 ++ ++ tst w1, #32 ++ b.ne 1f ++ ++ ld1 {v0.16b, v1.16b, v2.16b}, [x0], #48 ++ ext v25.16b, v0.16b, v1.16b, #1 ++ ext v26.16b, v0.16b, v1.16b, #2 ++ ext v27.16b, v0.16b, v1.16b, #3 ++ ext v29.16b, v1.16b, v2.16b, #1 ++ ext v30.16b, v1.16b, v2.16b, #2 ++ ext v31.16b, v1.16b, v2.16b, #3 ++ bic v24.16b, v0.16b, v20.16b ++ bic v25.16b, v25.16b, v20.16b ++ bic v26.16b, v26.16b, v20.16b ++ bic v27.16b, v27.16b, v20.16b ++ bic v28.16b, v1.16b, v20.16b ++ bic v29.16b, v29.16b, v20.16b ++ bic v30.16b, v30.16b, v20.16b ++ bic v31.16b, v31.16b, v20.16b ++ eor v24.16b, v24.16b, v21.16b ++ eor v25.16b, v25.16b, v21.16b ++ eor v26.16b, v26.16b, v21.16b ++ eor v27.16b, v27.16b, v21.16b ++ eor v28.16b, v28.16b, v21.16b ++ eor v29.16b, v29.16b, v21.16b ++ eor v30.16b, v30.16b, v21.16b ++ eor v31.16b, v31.16b, v21.16b ++ cmeq v24.4s, v24.4s, #0 ++ cmeq v25.4s, v25.4s, #0 ++ cmeq v26.4s, v26.4s, #0 ++ cmeq v27.4s, v27.4s, #0 ++ add w1, w1, #32 ++ b 3f ++ ++1: ld1 {v3.16b, v4.16b, v5.16b}, [x0], #48 ++ ext v25.16b, v3.16b, v4.16b, #1 ++ ext v26.16b, v3.16b, v4.16b, #2 ++ ext v27.16b, v3.16b, v4.16b, #3 ++ ext v29.16b, v4.16b, v5.16b, #1 ++ ext v30.16b, v4.16b, v5.16b, #2 ++ ext v31.16b, v4.16b, v5.16b, #3 ++ bic v24.16b, v3.16b, v20.16b ++ bic v25.16b, v25.16b, v20.16b ++ bic v26.16b, v26.16b, v20.16b ++ bic v27.16b, v27.16b, v20.16b ++ bic v28.16b, v4.16b, v20.16b ++ bic v29.16b, v29.16b, v20.16b ++ bic v30.16b, v30.16b, v20.16b ++ bic v31.16b, v31.16b, v20.16b ++ eor v24.16b, v24.16b, v21.16b ++ eor v25.16b, v25.16b, v21.16b ++ eor v26.16b, v26.16b, v21.16b ++ eor v27.16b, v27.16b, v21.16b ++ eor v28.16b, v28.16b, v21.16b ++ eor v29.16b, v29.16b, v21.16b ++ eor v30.16b, v30.16b, v21.16b ++ eor v31.16b, v31.16b, v21.16b ++ cmeq v24.4s, v24.4s, #0 ++ cmeq v25.4s, v25.4s, #0 ++ cmeq v26.4s, v26.4s, #0 ++ cmeq v27.4s, v27.4s, #0 ++ // Drop through... ++2: mov v0.16b, v5.16b ++ ld1 {v1.16b, v2.16b}, [x0], #32 ++ cmeq v28.4s, v28.4s, #0 ++ cmeq v29.4s, v29.4s, #0 ++ cmeq v30.4s, v30.4s, #0 ++ cmeq v31.4s, v31.4s, #0 ++ orr v24.16b, v24.16b, v25.16b ++ orr v26.16b, v26.16b, v27.16b ++ orr v28.16b, v28.16b, v29.16b ++ orr v30.16b, v30.16b, v31.16b ++ ext v25.16b, v0.16b, v1.16b, #1 ++ orr v22.16b, v24.16b, v26.16b ++ ext v26.16b, v0.16b, v1.16b, #2 ++ ext v27.16b, v0.16b, v1.16b, #3 ++ ext v29.16b, v1.16b, v2.16b, #1 ++ orr v23.16b, v28.16b, v30.16b ++ ext v30.16b, v1.16b, v2.16b, #2 ++ ext v31.16b, v1.16b, v2.16b, #3 ++ bic v24.16b, v0.16b, v20.16b ++ bic v25.16b, v25.16b, v20.16b ++ bic v26.16b, v26.16b, v20.16b ++ orr v22.16b, v22.16b, v23.16b ++ bic v27.16b, v27.16b, v20.16b ++ bic v28.16b, v1.16b, v20.16b ++ bic v29.16b, v29.16b, v20.16b ++ bic v30.16b, v30.16b, v20.16b ++ bic v31.16b, v31.16b, v20.16b ++ addv s22, v22.4s ++ eor v24.16b, v24.16b, v21.16b ++ eor v25.16b, v25.16b, v21.16b ++ eor v26.16b, v26.16b, v21.16b ++ eor v27.16b, v27.16b, v21.16b ++ eor v28.16b, v28.16b, v21.16b ++ mov w3, v22.s[0] ++ eor v29.16b, v29.16b, v21.16b ++ eor v30.16b, v30.16b, v21.16b ++ eor v31.16b, v31.16b, v21.16b ++ cmeq v24.4s, v24.4s, #0 ++ cmeq v25.4s, v25.4s, #0 ++ cmeq v26.4s, v26.4s, #0 ++ cmeq v27.4s, v27.4s, #0 ++ cbnz w3, 90f ++ st1 {v3.16b, v4.16b}, [x2], #32 ++3: mov v3.16b, v2.16b ++ ld1 {v4.16b, v5.16b}, [x0], #32 ++ cmeq v28.4s, v28.4s, #0 ++ cmeq v29.4s, v29.4s, #0 ++ cmeq v30.4s, v30.4s, #0 ++ cmeq v31.4s, v31.4s, #0 ++ orr v24.16b, v24.16b, v25.16b ++ orr v26.16b, v26.16b, v27.16b ++ orr v28.16b, v28.16b, v29.16b ++ orr v30.16b, v30.16b, v31.16b ++ ext v25.16b, v3.16b, v4.16b, #1 ++ orr v22.16b, v24.16b, v26.16b ++ ext v26.16b, v3.16b, v4.16b, #2 ++ ext v27.16b, v3.16b, v4.16b, #3 ++ ext v29.16b, v4.16b, v5.16b, #1 ++ orr v23.16b, v28.16b, v30.16b ++ ext v30.16b, v4.16b, v5.16b, #2 ++ ext v31.16b, v4.16b, v5.16b, #3 ++ bic v24.16b, v3.16b, v20.16b ++ bic v25.16b, v25.16b, v20.16b ++ bic v26.16b, v26.16b, v20.16b ++ orr v22.16b, v22.16b, v23.16b ++ bic v27.16b, v27.16b, v20.16b ++ bic v28.16b, v4.16b, v20.16b ++ bic v29.16b, v29.16b, v20.16b ++ bic v30.16b, v30.16b, v20.16b ++ bic v31.16b, v31.16b, v20.16b ++ addv s22, v22.4s ++ eor v24.16b, v24.16b, v21.16b ++ eor v25.16b, v25.16b, v21.16b ++ eor v26.16b, v26.16b, v21.16b ++ eor v27.16b, v27.16b, v21.16b ++ eor v28.16b, v28.16b, v21.16b ++ mov w3, v22.s[0] ++ eor v29.16b, v29.16b, v21.16b ++ eor v30.16b, v30.16b, v21.16b ++ eor v31.16b, v31.16b, v21.16b ++ cmeq v24.4s, v24.4s, #0 ++ cmeq v25.4s, v25.4s, #0 ++ cmeq v26.4s, v26.4s, #0 ++ cmeq v27.4s, v27.4s, #0 ++ cbnz w3, 91f ++ st1 {v0.16b, v1.16b}, [x2], #32 ++ subs w1, w1, #64 ++ b.pl 2b ++ ++90: add w0, w1, #80 ++ ret ++ ++91: sub w1, w1, #32 ++ b 90b ++endfunc --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -149,6 +149,7 @@ extern AVCodec ff_hap_decoder; @@ -448,7 +2329,7 @@ Upstream-status: Pending @@ -890,6 +891,41 @@ static enum AVCodecID remap_deprecated_c } } - + +static int codec_supports_format(const AVCodec * const p, const enum AVPixelFormat fmt) +{ + const enum AVPixelFormat *pf = p->pix_fmts; @@ -528,7 +2409,7 @@ Upstream-status: Pending @@ -26,83 +26,209 @@ #include "libavutil/internal.h" #include "libavcodec/cabac.h" - + + #define get_cabac_inline get_cabac_inline_arm static av_always_inline int get_cabac_inline_arm(CABACContext *c, @@ -622,7 +2503,7 @@ Upstream-status: Pending + ); + return bit; +} - + - __asm__ volatile( - "ldrb %[bit] , [%[state]] \n\t" - "add %[r_b] , %[tables] , %[lps_off] \n\t" @@ -719,7 +2600,7 @@ Upstream-status: Pending +#endif + "lsls %[range] , %[low], #16 \n\t" + "bne 1f \n\t" - + - return bit & 1; + "str %[ptr] , [%[c], %[ptr_off]] \n\t" + "rev %[tmp] , %[tmp] \n\t" @@ -803,7 +2684,7 @@ Upstream-status: Pending +} + #endif /* HAVE_ARMV6T2_INLINE */ - + #endif /* AVCODEC_ARM_CABAC_H */ --- /dev/null +++ b/libavcodec/arm/rpi_hevc_cabac.h @@ -15211,6 +17092,883 @@ Upstream-status: Pending + bx lr + +endfunc +--- a/libavcodec/arm/vc1dsp_init_neon.c ++++ b/libavcodec/arm/vc1dsp_init_neon.c +@@ -19,6 +19,7 @@ + #include <stdint.h> + + #include "libavutil/attributes.h" ++#include "libavutil/intreadwrite.h" + #include "libavcodec/vc1dsp.h" + #include "vc1dsp.h" + +@@ -32,6 +33,13 @@ void ff_vc1_inv_trans_4x8_dc_neon(uint8_ + void ff_vc1_inv_trans_8x4_dc_neon(uint8_t *dest, ptrdiff_t stride, int16_t *block); + void ff_vc1_inv_trans_4x4_dc_neon(uint8_t *dest, ptrdiff_t stride, int16_t *block); + ++void ff_vc1_v_loop_filter4_neon(uint8_t *src, int stride, int pq); ++void ff_vc1_h_loop_filter4_neon(uint8_t *src, int stride, int pq); ++void ff_vc1_v_loop_filter8_neon(uint8_t *src, int stride, int pq); ++void ff_vc1_h_loop_filter8_neon(uint8_t *src, int stride, int pq); ++void ff_vc1_v_loop_filter16_neon(uint8_t *src, int stride, int pq); ++void ff_vc1_h_loop_filter16_neon(uint8_t *src, int stride, int pq); ++ + void ff_put_pixels8x8_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int rnd); + +@@ -77,6 +85,64 @@ void ff_put_vc1_chroma_mc4_neon(uint8_t + void ff_avg_vc1_chroma_mc4_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int h, int x, int y); + ++int ff_vc1_unescape_buffer_helper_neon(const uint8_t *src, int size, uint8_t *dst); ++ ++static int vc1_unescape_buffer_neon(const uint8_t *src, int size, uint8_t *dst) ++{ ++ /* Dealing with starting and stopping, and removing escape bytes, are ++ * comparatively less time-sensitive, so are more clearly expressed using ++ * a C wrapper around the assembly inner loop. Note that we assume a ++ * little-endian machine that supports unaligned loads. */ ++ int dsize = 0; ++ while (size >= 4) ++ { ++ int found = 0; ++ while (!found && (((uintptr_t) dst) & 7) && size >= 4) ++ { ++ found = (AV_RL32(src) &~ 0x03000000) == 0x00030000; ++ if (!found) ++ { ++ *dst++ = *src++; ++ --size; ++ ++dsize; ++ } ++ } ++ if (!found) ++ { ++ int skip = size - ff_vc1_unescape_buffer_helper_neon(src, size, dst); ++ dst += skip; ++ src += skip; ++ size -= skip; ++ dsize += skip; ++ while (!found && size >= 4) ++ { ++ found = (AV_RL32(src) &~ 0x03000000) == 0x00030000; ++ if (!found) ++ { ++ *dst++ = *src++; ++ --size; ++ ++dsize; ++ } ++ } ++ } ++ if (found) ++ { ++ *dst++ = *src++; ++ *dst++ = *src++; ++ ++src; ++ size -= 3; ++ dsize += 2; ++ } ++ } ++ while (size > 0) ++ { ++ *dst++ = *src++; ++ --size; ++ ++dsize; ++ } ++ return dsize; ++} ++ + #define FN_ASSIGN(X, Y) \ + dsp->put_vc1_mspel_pixels_tab[0][X+4*Y] = ff_put_vc1_mspel_mc##X##Y##_16_neon; \ + dsp->put_vc1_mspel_pixels_tab[1][X+4*Y] = ff_put_vc1_mspel_mc##X##Y##_neon +@@ -92,6 +158,13 @@ av_cold void ff_vc1dsp_init_neon(VC1DSPC + dsp->vc1_inv_trans_8x4_dc = ff_vc1_inv_trans_8x4_dc_neon; + dsp->vc1_inv_trans_4x4_dc = ff_vc1_inv_trans_4x4_dc_neon; + ++ dsp->vc1_v_loop_filter4 = ff_vc1_v_loop_filter4_neon; ++ dsp->vc1_h_loop_filter4 = ff_vc1_h_loop_filter4_neon; ++ dsp->vc1_v_loop_filter8 = ff_vc1_v_loop_filter8_neon; ++ dsp->vc1_h_loop_filter8 = ff_vc1_h_loop_filter8_neon; ++ dsp->vc1_v_loop_filter16 = ff_vc1_v_loop_filter16_neon; ++ dsp->vc1_h_loop_filter16 = ff_vc1_h_loop_filter16_neon; ++ + dsp->put_vc1_mspel_pixels_tab[1][ 0] = ff_put_pixels8x8_neon; + FN_ASSIGN(1, 0); + FN_ASSIGN(2, 0); +@@ -116,4 +189,6 @@ av_cold void ff_vc1dsp_init_neon(VC1DSPC + dsp->avg_no_rnd_vc1_chroma_pixels_tab[0] = ff_avg_vc1_chroma_mc8_neon; + dsp->put_no_rnd_vc1_chroma_pixels_tab[1] = ff_put_vc1_chroma_mc4_neon; + dsp->avg_no_rnd_vc1_chroma_pixels_tab[1] = ff_avg_vc1_chroma_mc4_neon; ++ ++ dsp->vc1_unescape_buffer = vc1_unescape_buffer_neon; + } +--- a/libavcodec/arm/vc1dsp_neon.S ++++ b/libavcodec/arm/vc1dsp_neon.S +@@ -1161,3 +1161,764 @@ function ff_vc1_inv_trans_4x4_dc_neon, e + vst1.32 {d1[1]}, [r0,:32] + bx lr + endfunc ++ ++@ VC-1 in-loop deblocking filter for 4 pixel pairs at boundary of vertically-neighbouring blocks ++@ On entry: ++@ r0 -> top-left pel of lower block ++@ r1 = row stride, bytes ++@ r2 = PQUANT bitstream parameter ++function ff_vc1_v_loop_filter4_neon, export=1 ++ sub r3, r0, r1, lsl #2 ++ vldr d0, .Lcoeffs ++ vld1.32 {d1[0]}, [r0], r1 @ P5 ++ vld1.32 {d2[0]}, [r3], r1 @ P1 ++ vld1.32 {d3[0]}, [r3], r1 @ P2 ++ vld1.32 {d4[0]}, [r0], r1 @ P6 ++ vld1.32 {d5[0]}, [r3], r1 @ P3 ++ vld1.32 {d6[0]}, [r0], r1 @ P7 ++ vld1.32 {d7[0]}, [r3] @ P4 ++ vld1.32 {d16[0]}, [r0] @ P8 ++ vshll.u8 q9, d1, #1 @ 2*P5 ++ vdup.16 d17, r2 @ pq ++ vshll.u8 q10, d2, #1 @ 2*P1 ++ vmovl.u8 q11, d3 @ P2 ++ vmovl.u8 q1, d4 @ P6 ++ vmovl.u8 q12, d5 @ P3 ++ vmls.i16 d20, d22, d0[1] @ 2*P1-5*P2 ++ vmovl.u8 q11, d6 @ P7 ++ vmls.i16 d18, d2, d0[1] @ 2*P5-5*P6 ++ vshll.u8 q2, d5, #1 @ 2*P3 ++ vmovl.u8 q3, d7 @ P4 ++ vmla.i16 d18, d22, d0[1] @ 2*P5-5*P6+5*P7 ++ vmovl.u8 q11, d16 @ P8 ++ vmla.u16 d20, d24, d0[1] @ 2*P1-5*P2+5*P3 ++ vmovl.u8 q12, d1 @ P5 ++ vmls.u16 d4, d6, d0[1] @ 2*P3-5*P4 ++ vmls.u16 d18, d22, d0[0] @ 2*P5-5*P6+5*P7-2*P8 ++ vsub.i16 d1, d6, d24 @ P4-P5 ++ vmls.i16 d20, d6, d0[0] @ 2*P1-5*P2+5*P3-2*P4 ++ vmla.i16 d4, d24, d0[1] @ 2*P3-5*P4+5*P5 ++ vmls.i16 d4, d2, d0[0] @ 2*P3-5*P4+5*P5-2*P6 ++ vabs.s16 d2, d1 ++ vrshr.s16 d3, d18, #3 ++ vrshr.s16 d5, d20, #3 ++ vshr.s16 d2, d2, #1 @ clip ++ vrshr.s16 d4, d4, #3 ++ vabs.s16 d3, d3 @ a2 ++ vshr.s16 d1, d1, #8 @ clip_sign ++ vabs.s16 d5, d5 @ a1 ++ vceq.i16 d7, d2, #0 @ test clip == 0 ++ vabs.s16 d16, d4 @ a0 ++ vshr.s16 d4, d4, #8 @ a0_sign ++ vcge.s16 d18, d5, d3 @ test a1 >= a2 ++ vcge.s16 d17, d16, d17 @ test a0 >= pq ++ vbsl d18, d3, d5 @ a3 ++ vsub.i16 d1, d1, d4 @ clip_sign - a0_sign ++ vorr d3, d7, d17 @ test clip == 0 || a0 >= pq ++ vqsub.u16 d4, d16, d18 @ a0 >= a3 ? a0-a3 : 0 (a0 > a3 in all cases where filtering is enabled, so makes more sense to subtract this way round than the opposite and then taking the abs) ++ vcge.s16 d5, d18, d16 @ test a3 >= a0 ++ vmul.i16 d0, d4, d0[1] @ a0 >= a3 ? 5*(a0-a3) : 0 ++ vorr d4, d3, d5 @ test clip == 0 || a0 >= pq || a3 >= a0 ++ vmov.32 r0, d4[1] @ move to gp reg ++ vshr.u16 d0, d0, #3 @ a0 >= a3 ? (5*(a0-a3))>>3 : 0 ++ vcge.s16 d4, d0, d2 ++ tst r0, #1 ++ bne 1f @ none of the 4 pixel pairs should be updated if this one is not filtered ++ vbsl d4, d2, d0 @ FFMIN(d, clip) ++ vbic d0, d4, d3 @ set each d to zero if it should not be filtered because clip == 0 || a0 >= pq (a3 > a0 case already zeroed by saturating sub) ++ vmls.i16 d6, d0, d1 @ invert d depending on clip_sign & a0_sign, or zero it if they match, and accumulate into P4 ++ vmla.i16 d24, d0, d1 @ invert d depending on clip_sign & a0_sign, or zero it if they match, and accumulate into P5 ++ vqmovun.s16 d0, q3 ++ vqmovun.s16 d1, q12 ++ vst1.32 {d0[0]}, [r3], r1 ++ vst1.32 {d1[0]}, [r3] ++1: bx lr ++endfunc ++ ++@ VC-1 in-loop deblocking filter for 4 pixel pairs at boundary of horizontally-neighbouring blocks ++@ On entry: ++@ r0 -> top-left pel of right block ++@ r1 = row stride, bytes ++@ r2 = PQUANT bitstream parameter ++function ff_vc1_h_loop_filter4_neon, export=1 ++ sub r3, r0, #4 @ where to start reading ++ vldr d0, .Lcoeffs ++ vld1.32 {d2}, [r3], r1 ++ sub r0, r0, #1 @ where to start writing ++ vld1.32 {d4}, [r3], r1 ++ vld1.32 {d3}, [r3], r1 ++ vld1.32 {d5}, [r3] ++ vdup.16 d1, r2 @ pq ++ vtrn.8 q1, q2 ++ vtrn.16 d2, d3 @ P1, P5, P3, P7 ++ vtrn.16 d4, d5 @ P2, P6, P4, P8 ++ vshll.u8 q3, d2, #1 @ 2*P1, 2*P5 ++ vmovl.u8 q8, d4 @ P2, P6 ++ vmovl.u8 q9, d3 @ P3, P7 ++ vmovl.u8 q2, d5 @ P4, P8 ++ vmls.i16 q3, q8, d0[1] @ 2*P1-5*P2, 2*P5-5*P6 ++ vshll.u8 q10, d3, #1 @ 2*P3, 2*P7 ++ vmovl.u8 q1, d2 @ P1, P5 ++ vmla.i16 q3, q9, d0[1] @ 2*P1-5*P2+5*P3, 2*P5-5*P6+5*P7 ++ vmls.i16 q3, q2, d0[0] @ 2*P1-5*P2+5*P3-2*P4, 2*P5-5*P6+5*P7-2*P8 ++ vmov d2, d3 @ needs to be in an even-numbered vector for when we come to narrow it later ++ vmls.i16 d20, d4, d0[1] @ 2*P3-5*P4 ++ vmla.i16 d20, d3, d0[1] @ 2*P3-5*P4+5*P5 ++ vsub.i16 d3, d4, d2 @ P4-P5 ++ vmls.i16 d20, d17, d0[0] @ 2*P3-5*P4+5*P5-2*P6 ++ vrshr.s16 q3, q3, #3 ++ vabs.s16 d5, d3 ++ vshr.s16 d3, d3, #8 @ clip_sign ++ vrshr.s16 d16, d20, #3 ++ vabs.s16 q3, q3 @ a1, a2 ++ vshr.s16 d5, d5, #1 @ clip ++ vabs.s16 d17, d16 @ a0 ++ vceq.i16 d18, d5, #0 @ test clip == 0 ++ vshr.s16 d16, d16, #8 @ a0_sign ++ vcge.s16 d19, d6, d7 @ test a1 >= a2 ++ vcge.s16 d1, d17, d1 @ test a0 >= pq ++ vsub.i16 d16, d3, d16 @ clip_sign - a0_sign ++ vbsl d19, d7, d6 @ a3 ++ vorr d1, d18, d1 @ test clip == 0 || a0 >= pq ++ vqsub.u16 d3, d17, d19 @ a0 >= a3 ? a0-a3 : 0 (a0 > a3 in all cases where filtering is enabled, so makes more sense to subtract this way round than the opposite and then taking the abs) ++ vcge.s16 d6, d19, d17 @ test a3 >= a0 @ ++ vmul.i16 d0, d3, d0[1] @ a0 >= a3 ? 5*(a0-a3) : 0 ++ vorr d3, d1, d6 @ test clip == 0 || a0 >= pq || a3 >= a0 ++ vmov.32 r2, d3[1] @ move to gp reg ++ vshr.u16 d0, d0, #3 @ a0 >= a3 ? (5*(a0-a3))>>3 : 0 ++ vcge.s16 d3, d0, d5 ++ tst r2, #1 ++ bne 1f @ none of the 4 pixel pairs should be updated if this one is not filtered ++ vbsl d3, d5, d0 @ FFMIN(d, clip) ++ vbic d0, d3, d1 @ set each d to zero if it should not be filtered because clip == 0 || a0 >= pq (a3 > a0 case already zeroed by saturating sub) ++ vmla.i16 d2, d0, d16 @ invert d depending on clip_sign & a0_sign, or zero it if they match, and accumulate into P5 ++ vmls.i16 d4, d0, d16 @ invert d depending on clip_sign & a0_sign, or zero it if they match, and accumulate into P4 ++ vqmovun.s16 d1, q1 ++ vqmovun.s16 d0, q2 ++ vst2.8 {d0[0], d1[0]}, [r0], r1 ++ vst2.8 {d0[1], d1[1]}, [r0], r1 ++ vst2.8 {d0[2], d1[2]}, [r0], r1 ++ vst2.8 {d0[3], d1[3]}, [r0] ++1: bx lr ++endfunc ++ ++@ VC-1 in-loop deblocking filter for 8 pixel pairs at boundary of vertically-neighbouring blocks ++@ On entry: ++@ r0 -> top-left pel of lower block ++@ r1 = row stride, bytes ++@ r2 = PQUANT bitstream parameter ++function ff_vc1_v_loop_filter8_neon, export=1 ++ sub r3, r0, r1, lsl #2 ++ vldr d0, .Lcoeffs ++ vld1.32 {d1}, [r0 :64], r1 @ P5 ++ vld1.32 {d2}, [r3 :64], r1 @ P1 ++ vld1.32 {d3}, [r3 :64], r1 @ P2 ++ vld1.32 {d4}, [r0 :64], r1 @ P6 ++ vld1.32 {d5}, [r3 :64], r1 @ P3 ++ vld1.32 {d6}, [r0 :64], r1 @ P7 ++ vshll.u8 q8, d1, #1 @ 2*P5 ++ vshll.u8 q9, d2, #1 @ 2*P1 ++ vld1.32 {d7}, [r3 :64] @ P4 ++ vmovl.u8 q1, d3 @ P2 ++ vld1.32 {d20}, [r0 :64] @ P8 ++ vmovl.u8 q11, d4 @ P6 ++ vdup.16 q12, r2 @ pq ++ vmovl.u8 q13, d5 @ P3 ++ vmls.i16 q9, q1, d0[1] @ 2*P1-5*P2 ++ vmovl.u8 q1, d6 @ P7 ++ vshll.u8 q2, d5, #1 @ 2*P3 ++ vmls.i16 q8, q11, d0[1] @ 2*P5-5*P6 ++ vmovl.u8 q3, d7 @ P4 ++ vmovl.u8 q10, d20 @ P8 ++ vmla.i16 q8, q1, d0[1] @ 2*P5-5*P6+5*P7 ++ vmovl.u8 q1, d1 @ P5 ++ vmla.i16 q9, q13, d0[1] @ 2*P1-5*P2+5*P3 ++ vsub.i16 q13, q3, q1 @ P4-P5 ++ vmls.i16 q2, q3, d0[1] @ 2*P3-5*P4 ++ vmls.i16 q8, q10, d0[0] @ 2*P5-5*P6+5*P7-2*P8 ++ vabs.s16 q10, q13 ++ vshr.s16 q13, q13, #8 @ clip_sign ++ vmls.i16 q9, q3, d0[0] @ 2*P1-5*P2+5*P3-2*P4 ++ vshr.s16 q10, q10, #1 @ clip ++ vmla.i16 q2, q1, d0[1] @ 2*P3-5*P4+5*P5 ++ vrshr.s16 q8, q8, #3 ++ vmls.i16 q2, q11, d0[0] @ 2*P3-5*P4+5*P5-2*P6 ++ vceq.i16 q11, q10, #0 @ test clip == 0 ++ vrshr.s16 q9, q9, #3 ++ vabs.s16 q8, q8 @ a2 ++ vabs.s16 q9, q9 @ a1 ++ vrshr.s16 q2, q2, #3 ++ vcge.s16 q14, q9, q8 @ test a1 >= a2 ++ vabs.s16 q15, q2 @ a0 ++ vshr.s16 q2, q2, #8 @ a0_sign ++ vbsl q14, q8, q9 @ a3 ++ vcge.s16 q8, q15, q12 @ test a0 >= pq ++ vsub.i16 q2, q13, q2 @ clip_sign - a0_sign ++ vqsub.u16 q9, q15, q14 @ a0 >= a3 ? a0-a3 : 0 (a0 > a3 in all cases where filtering is enabled, so makes more sense to subtract this way round than the opposite and then taking the abs) ++ vcge.s16 q12, q14, q15 @ test a3 >= a0 ++ vorr q8, q11, q8 @ test clip == 0 || a0 >= pq ++ vmul.i16 q0, q9, d0[1] @ a0 >= a3 ? 5*(a0-a3) : 0 ++ vorr q9, q8, q12 @ test clip == 0 || a0 >= pq || a3 >= a0 ++ vshl.i64 q11, q9, #16 ++ vmov.32 r0, d18[1] @ move to gp reg ++ vshr.u16 q0, q0, #3 @ a0 >= a3 ? (5*(a0-a3))>>3 : 0 ++ vmov.32 r2, d19[1] ++ vshr.s64 q9, q11, #48 ++ vcge.s16 q11, q0, q10 ++ vorr q8, q8, q9 ++ and r0, r0, r2 ++ vbsl q11, q10, q0 @ FFMIN(d, clip) ++ tst r0, #1 ++ bne 1f @ none of the 8 pixel pairs should be updated in this case ++ vbic q0, q11, q8 @ set each d to zero if it should not be filtered ++ vmls.i16 q3, q0, q2 @ invert d depending on clip_sign & a0_sign, or zero it if they match, and accumulate into P4 ++ vmla.i16 q1, q0, q2 @ invert d depending on clip_sign & a0_sign, or zero it if they match, and accumulate into P5 ++ vqmovun.s16 d0, q3 ++ vqmovun.s16 d1, q1 ++ vst1.32 {d0}, [r3 :64], r1 ++ vst1.32 {d1}, [r3 :64] ++1: bx lr ++endfunc ++ ++.align 5 ++.Lcoeffs: ++.quad 0x00050002 ++ ++@ VC-1 in-loop deblocking filter for 8 pixel pairs at boundary of horizontally-neighbouring blocks ++@ On entry: ++@ r0 -> top-left pel of right block ++@ r1 = row stride, bytes ++@ r2 = PQUANT bitstream parameter ++function ff_vc1_h_loop_filter8_neon, export=1 ++ push {lr} ++ sub r3, r0, #4 @ where to start reading ++ vldr d0, .Lcoeffs ++ vld1.32 {d2}, [r3], r1 @ P1[0], P2[0]... ++ sub r0, r0, #1 @ where to start writing ++ vld1.32 {d4}, [r3], r1 ++ add r12, r0, r1, lsl #2 ++ vld1.32 {d3}, [r3], r1 ++ vld1.32 {d5}, [r3], r1 ++ vld1.32 {d6}, [r3], r1 ++ vld1.32 {d16}, [r3], r1 ++ vld1.32 {d7}, [r3], r1 ++ vld1.32 {d17}, [r3] ++ vtrn.8 q1, q2 @ P1[0], P1[1], P3[0]... P1[2], P1[3], P3[2]... P2[0], P2[1], P4[0]... P2[2], P2[3], P4[2]... ++ vdup.16 q9, r2 @ pq ++ vtrn.16 d2, d3 @ P1[0], P1[1], P1[2], P1[3], P5[0]... P3[0], P3[1], P3[2], P3[3], P7[0]... ++ vtrn.16 d4, d5 @ P2[0], P2[1], P2[2], P2[3], P6[0]... P4[0], P4[1], P4[2], P4[3], P8[0]... ++ vtrn.8 q3, q8 @ P1[4], P1[5], P3[4]... P1[6], P1[7], P3[6]... P2[4], P2[5], P4[4]... P2[6], P2[7], P4[6]... ++ vtrn.16 d6, d7 @ P1[4], P1[5], P1[6], P1[7], P5[4]... P3[4], P3[5], P3[5], P3[7], P7[4]... ++ vtrn.16 d16, d17 @ P2[4], P2[5], P2[6], P2[7], P6[4]... P4[4], P4[5], P4[6], P4[7], P8[4]... ++ vtrn.32 d2, d6 @ P1, P5 ++ vtrn.32 d4, d16 @ P2, P6 ++ vtrn.32 d3, d7 @ P3, P7 ++ vtrn.32 d5, d17 @ P4, P8 ++ vshll.u8 q10, d2, #1 @ 2*P1 ++ vshll.u8 q11, d6, #1 @ 2*P5 ++ vmovl.u8 q12, d4 @ P2 ++ vmovl.u8 q13, d16 @ P6 ++ vmovl.u8 q14, d3 @ P3 ++ vmls.i16 q10, q12, d0[1] @ 2*P1-5*P2 ++ vmovl.u8 q12, d7 @ P7 ++ vshll.u8 q1, d3, #1 @ 2*P3 ++ vmls.i16 q11, q13, d0[1] @ 2*P5-5*P6 ++ vmovl.u8 q2, d5 @ P4 ++ vmovl.u8 q8, d17 @ P8 ++ vmla.i16 q11, q12, d0[1] @ 2*P5-5*P6+5*P7 ++ vmovl.u8 q3, d6 @ P5 ++ vmla.i16 q10, q14, d0[1] @ 2*P1-5*P2+5*P3 ++ vsub.i16 q12, q2, q3 @ P4-P5 ++ vmls.i16 q1, q2, d0[1] @ 2*P3-5*P4 ++ vmls.i16 q11, q8, d0[0] @ 2*P5-5*P6+5*P7-2*P8 ++ vabs.s16 q8, q12 ++ vshr.s16 q12, q12, #8 @ clip_sign ++ vmls.i16 q10, q2, d0[0] @ 2*P1-5*P2+5*P3-2*P4 ++ vshr.s16 q8, q8, #1 @ clip ++ vmla.i16 q1, q3, d0[1] @ 2*P3-5*P4+5*P5 ++ vrshr.s16 q11, q11, #3 ++ vmls.i16 q1, q13, d0[0] @ 2*P3-5*P4+5*P5-2*P6 ++ vceq.i16 q13, q8, #0 @ test clip == 0 ++ vrshr.s16 q10, q10, #3 ++ vabs.s16 q11, q11 @ a2 ++ vabs.s16 q10, q10 @ a1 ++ vrshr.s16 q1, q1, #3 ++ vcge.s16 q14, q10, q11 @ test a1 >= a2 ++ vabs.s16 q15, q1 @ a0 ++ vshr.s16 q1, q1, #8 @ a0_sign ++ vbsl q14, q11, q10 @ a3 ++ vcge.s16 q9, q15, q9 @ test a0 >= pq ++ vsub.i16 q1, q12, q1 @ clip_sign - a0_sign ++ vqsub.u16 q10, q15, q14 @ a0 >= a3 ? a0-a3 : 0 (a0 > a3 in all cases where filtering is enabled, so makes more sense to subtract this way round than the opposite and then taking the abs) ++ vcge.s16 q11, q14, q15 @ test a3 >= a0 ++ vorr q9, q13, q9 @ test clip == 0 || a0 >= pq ++ vmul.i16 q0, q10, d0[1] @ a0 >= a3 ? 5*(a0-a3) : 0 ++ vorr q10, q9, q11 @ test clip == 0 || a0 >= pq || a3 >= a0 ++ vmov.32 r2, d20[1] @ move to gp reg ++ vshr.u16 q0, q0, #3 @ a0 >= a3 ? (5*(a0-a3))>>3 : 0 ++ vmov.32 r3, d21[1] ++ vcge.s16 q10, q0, q8 ++ and r14, r2, r3 ++ vbsl q10, q8, q0 @ FFMIN(d, clip) ++ tst r14, #1 ++ bne 2f @ none of the 8 pixel pairs should be updated in this case ++ vbic q0, q10, q9 @ set each d to zero if it should not be filtered because clip == 0 || a0 >= pq (a3 > a0 case already zeroed by saturating sub) ++ vmla.i16 q3, q0, q1 @ invert d depending on clip_sign & a0_sign, or zero it if they match, and accumulate into P5 ++ vmls.i16 q2, q0, q1 @ invert d depending on clip_sign & a0_sign, or zero it if they match, and accumulate into P4 ++ vqmovun.s16 d1, q3 ++ vqmovun.s16 d0, q2 ++ tst r2, #1 ++ bne 1f @ none of the first 4 pixel pairs should be updated if so ++ vst2.8 {d0[0], d1[0]}, [r0], r1 ++ vst2.8 {d0[1], d1[1]}, [r0], r1 ++ vst2.8 {d0[2], d1[2]}, [r0], r1 ++ vst2.8 {d0[3], d1[3]}, [r0] ++1: tst r3, #1 ++ bne 2f @ none of the second 4 pixel pairs should be updated if so ++ vst2.8 {d0[4], d1[4]}, [r12], r1 ++ vst2.8 {d0[5], d1[5]}, [r12], r1 ++ vst2.8 {d0[6], d1[6]}, [r12], r1 ++ vst2.8 {d0[7], d1[7]}, [r12] ++2: pop {pc} ++endfunc ++ ++@ VC-1 in-loop deblocking filter for 16 pixel pairs at boundary of vertically-neighbouring blocks ++@ On entry: ++@ r0 -> top-left pel of lower block ++@ r1 = row stride, bytes ++@ r2 = PQUANT bitstream parameter ++function ff_vc1_v_loop_filter16_neon, export=1 ++ vpush {d8-d15} ++ sub r3, r0, r1, lsl #2 ++ vldr d0, .Lcoeffs ++ vld1.64 {q1}, [r0 :128], r1 @ P5 ++ vld1.64 {q2}, [r3 :128], r1 @ P1 ++ vld1.64 {q3}, [r3 :128], r1 @ P2 ++ vld1.64 {q4}, [r0 :128], r1 @ P6 ++ vld1.64 {q5}, [r3 :128], r1 @ P3 ++ vld1.64 {q6}, [r0 :128], r1 @ P7 ++ vshll.u8 q7, d2, #1 @ 2*P5[0..7] ++ vshll.u8 q8, d4, #1 @ 2*P1[0..7] ++ vld1.64 {q9}, [r3 :128] @ P4 ++ vmovl.u8 q10, d6 @ P2[0..7] ++ vld1.64 {q11}, [r0 :128] @ P8 ++ vmovl.u8 q12, d8 @ P6[0..7] ++ vdup.16 q13, r2 @ pq ++ vshll.u8 q2, d5, #1 @ 2*P1[8..15] ++ vmls.i16 q8, q10, d0[1] @ 2*P1[0..7]-5*P2[0..7] ++ vshll.u8 q10, d3, #1 @ 2*P5[8..15] ++ vmovl.u8 q3, d7 @ P2[8..15] ++ vmls.i16 q7, q12, d0[1] @ 2*P5[0..7]-5*P6[0..7] ++ vmovl.u8 q4, d9 @ P6[8..15] ++ vmovl.u8 q14, d10 @ P3[0..7] ++ vmovl.u8 q15, d12 @ P7[0..7] ++ vmls.i16 q2, q3, d0[1] @ 2*P1[8..15]-5*P2[8..15] ++ vshll.u8 q3, d10, #1 @ 2*P3[0..7] ++ vmls.i16 q10, q4, d0[1] @ 2*P5[8..15]-5*P6[8..15] ++ vmovl.u8 q6, d13 @ P7[8..15] ++ vmla.i16 q8, q14, d0[1] @ 2*P1[0..7]-5*P2[0..7]+5*P3[0..7] ++ vmovl.u8 q14, d18 @ P4[0..7] ++ vmovl.u8 q9, d19 @ P4[8..15] ++ vmla.i16 q7, q15, d0[1] @ 2*P5[0..7]-5*P6[0..7]+5*P7[0..7] ++ vmovl.u8 q15, d11 @ P3[8..15] ++ vshll.u8 q5, d11, #1 @ 2*P3[8..15] ++ vmls.i16 q3, q14, d0[1] @ 2*P3[0..7]-5*P4[0..7] ++ vmla.i16 q2, q15, d0[1] @ 2*P1[8..15]-5*P2[8..15]+5*P3[8..15] ++ vmovl.u8 q15, d22 @ P8[0..7] ++ vmovl.u8 q11, d23 @ P8[8..15] ++ vmla.i16 q10, q6, d0[1] @ 2*P5[8..15]-5*P6[8..15]+5*P7[8..15] ++ vmovl.u8 q6, d2 @ P5[0..7] ++ vmovl.u8 q1, d3 @ P5[8..15] ++ vmls.i16 q5, q9, d0[1] @ 2*P3[8..15]-5*P4[8..15] ++ vmls.i16 q8, q14, d0[0] @ 2*P1[0..7]-5*P2[0..7]+5*P3[0..7]-2*P4[0..7] ++ vmls.i16 q7, q15, d0[0] @ 2*P5[0..7]-5*P6[0..7]+5*P7[0..7]-2*P8[0..7] ++ vsub.i16 q15, q14, q6 @ P4[0..7]-P5[0..7] ++ vmla.i16 q3, q6, d0[1] @ 2*P3[0..7]-5*P4[0..7]+5*P5[0..7] ++ vrshr.s16 q8, q8, #3 ++ vmls.i16 q2, q9, d0[0] @ 2*P1[8..15]-5*P2[8..15]+5*P3[8..15]-2*P4[8..15] ++ vrshr.s16 q7, q7, #3 ++ vmls.i16 q10, q11, d0[0] @ 2*P5[8..15]-5*P6[8..15]+5*P7[8..15]-2*P8[8..15] ++ vabs.s16 q11, q15 ++ vabs.s16 q8, q8 @ a1[0..7] ++ vmla.i16 q5, q1, d0[1] @ 2*P3[8..15]-5*P4[8..15]+5*P5[8..15] ++ vshr.s16 q15, q15, #8 @ clip_sign[0..7] ++ vrshr.s16 q2, q2, #3 ++ vmls.i16 q3, q12, d0[0] @ 2*P3[0..7]-5*P4[0..7]+5*P5[0..7]-2*P6[0..7] ++ vabs.s16 q7, q7 @ a2[0..7] ++ vrshr.s16 q10, q10, #3 ++ vsub.i16 q12, q9, q1 @ P4[8..15]-P5[8..15] ++ vshr.s16 q11, q11, #1 @ clip[0..7] ++ vmls.i16 q5, q4, d0[0] @ 2*P3[8..15]-5*P4[8..15]+5*P5[8..15]-2*P6[8..15] ++ vcge.s16 q4, q8, q7 @ test a1[0..7] >= a2[0..7] ++ vabs.s16 q2, q2 @ a1[8..15] ++ vrshr.s16 q3, q3, #3 ++ vabs.s16 q10, q10 @ a2[8..15] ++ vbsl q4, q7, q8 @ a3[0..7] ++ vabs.s16 q7, q12 ++ vshr.s16 q8, q12, #8 @ clip_sign[8..15] ++ vrshr.s16 q5, q5, #3 ++ vcge.s16 q12, q2, q10 @ test a1[8..15] >= a2[8.15] ++ vshr.s16 q7, q7, #1 @ clip[8..15] ++ vbsl q12, q10, q2 @ a3[8..15] ++ vabs.s16 q2, q3 @ a0[0..7] ++ vceq.i16 q10, q11, #0 @ test clip[0..7] == 0 ++ vshr.s16 q3, q3, #8 @ a0_sign[0..7] ++ vsub.i16 q3, q15, q3 @ clip_sign[0..7] - a0_sign[0..7] ++ vcge.s16 q15, q2, q13 @ test a0[0..7] >= pq ++ vorr q10, q10, q15 @ test clip[0..7] == 0 || a0[0..7] >= pq ++ vqsub.u16 q15, q2, q4 @ a0[0..7] >= a3[0..7] ? a0[0..7]-a3[0..7] : 0 (a0 > a3 in all cases where filtering is enabled, so makes more sense to subtract this way round than the opposite and then taking the abs) ++ vcge.s16 q2, q4, q2 @ test a3[0..7] >= a0[0..7] ++ vabs.s16 q4, q5 @ a0[8..15] ++ vshr.s16 q5, q5, #8 @ a0_sign[8..15] ++ vmul.i16 q15, q15, d0[1] @ a0[0..7] >= a3[0..7] ? 5*(a0[0..7]-a3[0..7]) : 0 ++ vcge.s16 q13, q4, q13 @ test a0[8..15] >= pq ++ vorr q2, q10, q2 @ test clip[0..7] == 0 || a0[0..7] >= pq || a3[0..7] >= a0[0..7] ++ vsub.i16 q5, q8, q5 @ clip_sign[8..15] - a0_sign[8..15] ++ vceq.i16 q8, q7, #0 @ test clip[8..15] == 0 ++ vshr.u16 q15, q15, #3 @ a0[0..7] >= a3[0..7] ? (5*(a0[0..7]-a3[0..7]))>>3 : 0 ++ vmov.32 r0, d4[1] @ move to gp reg ++ vorr q8, q8, q13 @ test clip[8..15] == 0 || a0[8..15] >= pq ++ vqsub.u16 q13, q4, q12 @ a0[8..15] >= a3[8..15] ? a0[8..15]-a3[8..15] : 0 (a0 > a3 in all cases where filtering is enabled, so makes more sense to subtract this way round than the opposite and then taking the abs) ++ vmov.32 r2, d5[1] ++ vcge.s16 q4, q12, q4 @ test a3[8..15] >= a0[8..15] ++ vshl.i64 q2, q2, #16 ++ vcge.s16 q12, q15, q11 ++ vmul.i16 q0, q13, d0[1] @ a0[8..15] >= a3[8..15] ? 5*(a0[8..15]-a3[8..15]) : 0 ++ vorr q4, q8, q4 @ test clip[8..15] == 0 || a0[8..15] >= pq || a3[8..15] >= a0[8..15] ++ vshr.s64 q2, q2, #48 ++ and r0, r0, r2 ++ vbsl q12, q11, q15 @ FFMIN(d[0..7], clip[0..7]) ++ vshl.i64 q11, q4, #16 ++ vmov.32 r2, d8[1] ++ vshr.u16 q0, q0, #3 @ a0[8..15] >= a3[8..15] ? (5*(a0[8..15]-a3[8..15]))>>3 : 0 ++ vorr q2, q10, q2 ++ vmov.32 r12, d9[1] ++ vshr.s64 q4, q11, #48 ++ vcge.s16 q10, q0, q7 ++ vbic q2, q12, q2 @ set each d[0..7] to zero if it should not be filtered because clip[0..7] == 0 || a0[0..7] >= pq (a3 > a0 case already zeroed by saturating sub) ++ vorr q4, q8, q4 ++ and r2, r2, r12 ++ vbsl q10, q7, q0 @ FFMIN(d[8..15], clip[8..15]) ++ vmls.i16 q14, q2, q3 @ invert d[0..7] depending on clip_sign[0..7] & a0_sign[0..7], or zero it if they match, and accumulate into P4[0..7] ++ and r0, r0, r2 ++ vbic q0, q10, q4 @ set each d[8..15] to zero if it should not be filtered because clip[8..15] == 0 || a0[8..15] >= pq (a3 > a0 case already zeroed by saturating sub) ++ tst r0, #1 ++ bne 1f @ none of the 16 pixel pairs should be updated in this case ++ vmla.i16 q6, q2, q3 @ invert d[0..7] depending on clip_sign[0..7] & a0_sign[0..7], or zero it if they match, and accumulate into P5[0..7] ++ vmls.i16 q9, q0, q5 @ invert d[8..15] depending on clip_sign[8..15] & a0_sign[8..15], or zero it if they match, and accumulate into P4[8..15] ++ vqmovun.s16 d4, q14 ++ vmla.i16 q1, q0, q5 @ invert d[8..15] depending on clip_sign[8..15] & a0_sign[8..15], or zero it if they match, and accumulate into P5[8..15] ++ vqmovun.s16 d0, q6 ++ vqmovun.s16 d5, q9 ++ vqmovun.s16 d1, q1 ++ vst1.64 {q2}, [r3 :128], r1 ++ vst1.64 {q0}, [r3 :128] ++1: vpop {d8-d15} ++ bx lr ++endfunc ++ ++@ VC-1 in-loop deblocking filter for 16 pixel pairs at boundary of horizontally-neighbouring blocks ++@ On entry: ++@ r0 -> top-left pel of right block ++@ r1 = row stride, bytes ++@ r2 = PQUANT bitstream parameter ++function ff_vc1_h_loop_filter16_neon, export=1 ++ push {r4-r6,lr} ++ vpush {d8-d15} ++ sub r3, r0, #4 @ where to start reading ++ vldr d0, .Lcoeffs ++ vld1.32 {d2}, [r3], r1 @ P1[0], P2[0]... ++ sub r0, r0, #1 @ where to start writing ++ vld1.32 {d3}, [r3], r1 ++ add r4, r0, r1, lsl #2 ++ vld1.32 {d10}, [r3], r1 ++ vld1.32 {d11}, [r3], r1 ++ vld1.32 {d16}, [r3], r1 ++ vld1.32 {d4}, [r3], r1 ++ vld1.32 {d8}, [r3], r1 ++ vtrn.8 d2, d3 @ P1[0], P1[1], P3[0]... P2[0], P2[1], P4[0]... ++ vld1.32 {d14}, [r3], r1 ++ vld1.32 {d5}, [r3], r1 ++ vtrn.8 d10, d11 @ P1[2], P1[3], P3[2]... P2[2], P2[3], P4[2]... ++ vld1.32 {d6}, [r3], r1 ++ vld1.32 {d12}, [r3], r1 ++ vtrn.8 d16, d4 @ P1[4], P1[5], P3[4]... P2[4], P2[5], P4[4]... ++ vld1.32 {d13}, [r3], r1 ++ vtrn.16 d2, d10 @ P1[0], P1[1], P1[2], P1[3], P5[0]... P3[0], P3[1], P3[2], P3[3], P7[0]... ++ vld1.32 {d1}, [r3], r1 ++ vtrn.8 d8, d14 @ P1[6], P1[7], P3[6]... P2[6], P2[7], P4[6]... ++ vld1.32 {d7}, [r3], r1 ++ vtrn.16 d3, d11 @ P2[0], P2[1], P2[2], P2[3], P6[0]... P4[0], P4[1], P4[2], P4[3], P8[0]... ++ vld1.32 {d9}, [r3], r1 ++ vtrn.8 d5, d6 @ P1[8], P1[9], P3[8]... P2[8], P2[9], P4[8]... ++ vld1.32 {d15}, [r3] ++ vtrn.16 d16, d8 @ P1[4], P1[5], P1[6], P1[7], P5[4]... P3[4], P3[5], P3[6], P3[7], P7[4]... ++ vtrn.16 d4, d14 @ P2[4], P2[5], P2[6], P2[7], P6[4]... P4[4], P4[5], P4[6], P4[7], P8[4]... ++ vtrn.8 d12, d13 @ P1[10], P1[11], P3[10]... P2[10], P2[11], P4[10]... ++ vdup.16 q9, r2 @ pq ++ vtrn.8 d1, d7 @ P1[12], P1[13], P3[12]... P2[12], P2[13], P4[12]... ++ vtrn.32 d2, d16 @ P1[0..7], P5[0..7] ++ vtrn.16 d5, d12 @ P1[8], P1[7], P1[10], P1[11], P5[8]... P3[8], P3[9], P3[10], P3[11], P7[8]... ++ vtrn.16 d6, d13 @ P2[8], P2[7], P2[10], P2[11], P6[8]... P4[8], P4[9], P4[10], P4[11], P8[8]... ++ vtrn.8 d9, d15 @ P1[14], P1[15], P3[14]... P2[14], P2[15], P4[14]... ++ vtrn.32 d3, d4 @ P2[0..7], P6[0..7] ++ vshll.u8 q10, d2, #1 @ 2*P1[0..7] ++ vtrn.32 d10, d8 @ P3[0..7], P7[0..7] ++ vshll.u8 q11, d16, #1 @ 2*P5[0..7] ++ vtrn.32 d11, d14 @ P4[0..7], P8[0..7] ++ vtrn.16 d1, d9 @ P1[12], P1[13], P1[14], P1[15], P5[12]... P3[12], P3[13], P3[14], P3[15], P7[12]... ++ vtrn.16 d7, d15 @ P2[12], P2[13], P2[14], P2[15], P6[12]... P4[12], P4[13], P4[14], P4[15], P8[12]... ++ vmovl.u8 q1, d3 @ P2[0..7] ++ vmovl.u8 q12, d4 @ P6[0..7] ++ vtrn.32 d5, d1 @ P1[8..15], P5[8..15] ++ vtrn.32 d6, d7 @ P2[8..15], P6[8..15] ++ vtrn.32 d12, d9 @ P3[8..15], P7[8..15] ++ vtrn.32 d13, d15 @ P4[8..15], P8[8..15] ++ vmls.i16 q10, q1, d0[1] @ 2*P1[0..7]-5*P2[0..7] ++ vmovl.u8 q1, d10 @ P3[0..7] ++ vshll.u8 q2, d5, #1 @ 2*P1[8..15] ++ vshll.u8 q13, d1, #1 @ 2*P5[8..15] ++ vmls.i16 q11, q12, d0[1] @ 2*P5[0..7]-5*P6[0..7] ++ vmovl.u8 q14, d6 @ P2[8..15] ++ vmovl.u8 q3, d7 @ P6[8..15] ++ vmovl.u8 q15, d8 @ P7[0..7] ++ vmla.i16 q10, q1, d0[1] @ 2*P1[0..7]-5*P2[0..7]+5*P3[0..7] ++ vmovl.u8 q1, d12 @ P3[8..15] ++ vmls.i16 q2, q14, d0[1] @ 2*P1[8..15]-5*P2[8..15] ++ vmovl.u8 q4, d9 @ P7[8..15] ++ vshll.u8 q14, d10, #1 @ 2*P3[0..7] ++ vmls.i16 q13, q3, d0[1] @ 2*P5[8..15]-5*P6[8..15] ++ vmovl.u8 q5, d11 @ P4[0..7] ++ vmla.i16 q11, q15, d0[1] @ 2*P5[0..7]-5*P6[0..7]+5*P7[0..7] ++ vshll.u8 q15, d12, #1 @ 2*P3[8..15] ++ vmovl.u8 q6, d13 @ P4[8..15] ++ vmla.i16 q2, q1, d0[1] @ 2*P1[8..15]-5*P2[8..15]+5*P3[8..15] ++ vmovl.u8 q1, d14 @ P8[0..7] ++ vmovl.u8 q7, d15 @ P8[8..15] ++ vmla.i16 q13, q4, d0[1] @ 2*P5[8..15]-5*P6[8..15]+5*P7[8..15] ++ vmovl.u8 q4, d16 @ P5[0..7] ++ vmovl.u8 q8, d1 @ P5[8..15] ++ vmls.i16 q14, q5, d0[1] @ 2*P3[0..7]-5*P4[0..7] ++ vmls.i16 q15, q6, d0[1] @ 2*P3[8..15]-5*P4[8..15] ++ vmls.i16 q10, q5, d0[0] @ 2*P1[0..7]-5*P2[0..7]+5*P3[0..7]-2*P4[0..7] ++ vmls.i16 q11, q1, d0[0] @ 2*P5[0..7]-5*P6[0..7]+5*P7[0..7]-2*P8[0..7] ++ vsub.i16 q1, q5, q4 @ P4[0..7]-P5[0..7] ++ vmls.i16 q2, q6, d0[0] @ 2*P1[8..15]-5*P2[8..15]+5*P3[8..15]-2*P4[8..15] ++ vrshr.s16 q10, q10, #3 ++ vmls.i16 q13, q7, d0[0] @ 2*P5[8..15]-5*P6[8..15]+5*P7[8..15]-2*P8[8..15] ++ vsub.i16 q7, q6, q8 @ P4[8..15]-P5[8..15] ++ vrshr.s16 q11, q11, #3 ++ vmla.s16 q14, q4, d0[1] @ 2*P3[0..7]-5*P4[0..7]+5*P5[0..7] ++ vrshr.s16 q2, q2, #3 ++ vmla.i16 q15, q8, d0[1] @ 2*P3[8..15]-5*P4[8..15]+5*P5[8..15] ++ vabs.s16 q10, q10 @ a1[0..7] ++ vrshr.s16 q13, q13, #3 ++ vmls.i16 q15, q3, d0[0] @ 2*P3[8..15]-5*P4[8..15]+5*P5[8..15]-2*P6[8..15] ++ vabs.s16 q3, q11 @ a2[0..7] ++ vabs.s16 q2, q2 @ a1[8..15] ++ vmls.i16 q14, q12, d0[0] @ 2*P3[0..7]-5*P4[0..7]+5*P5[0..7]-2*P6[0..7] ++ vabs.s16 q11, q1 ++ vabs.s16 q12, q13 @ a2[8..15] ++ vcge.s16 q13, q10, q3 @ test a1[0..7] >= a2[0..7] ++ vshr.s16 q1, q1, #8 @ clip_sign[0..7] ++ vrshr.s16 q15, q15, #3 ++ vshr.s16 q11, q11, #1 @ clip[0..7] ++ vrshr.s16 q14, q14, #3 ++ vbsl q13, q3, q10 @ a3[0..7] ++ vcge.s16 q3, q2, q12 @ test a1[8..15] >= a2[8.15] ++ vabs.s16 q10, q15 @ a0[8..15] ++ vshr.s16 q15, q15, #8 @ a0_sign[8..15] ++ vbsl q3, q12, q2 @ a3[8..15] ++ vabs.s16 q2, q14 @ a0[0..7] ++ vabs.s16 q12, q7 ++ vshr.s16 q7, q7, #8 @ clip_sign[8..15] ++ vshr.s16 q14, q14, #8 @ a0_sign[0..7] ++ vshr.s16 q12, q12, #1 @ clip[8..15] ++ vsub.i16 q7, q7, q15 @ clip_sign[8..15] - a0_sign[8..15] ++ vqsub.u16 q15, q10, q3 @ a0[8..15] >= a3[8..15] ? a0[8..15]-a3[8..15] : 0 (a0 > a3 in all cases where filtering is enabled, so makes more sense to subtract this way round than the opposite and then taking the abs) ++ vcge.s16 q3, q3, q10 @ test a3[8..15] >= a0[8..15] ++ vcge.s16 q10, q10, q9 @ test a0[8..15] >= pq ++ vcge.s16 q9, q2, q9 @ test a0[0..7] >= pq ++ vsub.i16 q1, q1, q14 @ clip_sign[0..7] - a0_sign[0..7] ++ vqsub.u16 q14, q2, q13 @ a0[0..7] >= a3[0..7] ? a0[0..7]-a3[0..7] : 0 (a0 > a3 in all cases where filtering is enabled, so makes more sense to subtract this way round than the opposite and then taking the abs) ++ vcge.s16 q2, q13, q2 @ test a3[0..7] >= a0[0..7] ++ vmul.i16 q13, q15, d0[1] @ a0[8..15] >= a3[8..15] ? 5*(a0[8..15]-a3[8..15]) : 0 ++ vceq.i16 q15, q11, #0 @ test clip[0..7] == 0 ++ vmul.i16 q0, q14, d0[1] @ a0[0..7] >= a3[0..7] ? 5*(a0[0..7]-a3[0..7]) : 0 ++ vorr q9, q15, q9 @ test clip[0..7] == 0 || a0[0..7] >= pq ++ vceq.i16 q14, q12, #0 @ test clip[8..15] == 0 ++ vshr.u16 q13, q13, #3 @ a0[8..15] >= a3[8..15] ? (5*(a0[8..15]-a3[8..15]))>>3 : 0 ++ vorr q2, q9, q2 @ test clip[0..7] == 0 || a0[0..7] >= pq || a3[0..7] >= a0[0..7] ++ vshr.u16 q0, q0, #3 @ a0[0..7] >= a3[0..7] ? (5*(a0[0..7]-a3[0..7]))>>3 : 0 ++ vorr q10, q14, q10 @ test clip[8..15] == 0 || a0[8..15] >= pq ++ vcge.s16 q14, q13, q12 ++ vmov.32 r2, d4[1] @ move to gp reg ++ vorr q3, q10, q3 @ test clip[8..15] == 0 || a0[8..15] >= pq || a3[8..15] >= a0[8..15] ++ vmov.32 r3, d5[1] ++ vcge.s16 q2, q0, q11 ++ vbsl q14, q12, q13 @ FFMIN(d[8..15], clip[8..15]) ++ vbsl q2, q11, q0 @ FFMIN(d[0..7], clip[0..7]) ++ vmov.32 r5, d6[1] ++ vbic q0, q14, q10 @ set each d[8..15] to zero if it should not be filtered because clip[8..15] == 0 || a0[8..15] >= pq (a3 > a0 case already zeroed by saturating sub) ++ vmov.32 r6, d7[1] ++ and r12, r2, r3 ++ vbic q2, q2, q9 @ set each d[0..7] to zero if it should not be filtered because clip[0..7] == 0 || a0[0..7] >= pq (a3 > a0 case already zeroed by saturating sub) ++ vmls.i16 q6, q0, q7 @ invert d[8..15] depending on clip_sign[8..15] & a0_sign[8..15], or zero it if they match, and accumulate into P4 ++ vmls.i16 q5, q2, q1 @ invert d[0..7] depending on clip_sign[0..7] & a0_sign[0..7], or zero it if they match, and accumulate into P4 ++ and r14, r5, r6 ++ vmla.i16 q4, q2, q1 @ invert d[0..7] depending on clip_sign[0..7] & a0_sign[0..7], or zero it if they match, and accumulate into P5 ++ and r12, r12, r14 ++ vqmovun.s16 d4, q6 ++ vmla.i16 q8, q0, q7 @ invert d[8..15] depending on clip_sign[8..15] & a0_sign[8..15], or zero it if they match, and accumulate into P5 ++ tst r12, #1 ++ bne 4f @ none of the 16 pixel pairs should be updated in this case ++ vqmovun.s16 d2, q5 ++ vqmovun.s16 d3, q4 ++ vqmovun.s16 d5, q8 ++ tst r2, #1 ++ bne 1f ++ vst2.8 {d2[0], d3[0]}, [r0], r1 ++ vst2.8 {d2[1], d3[1]}, [r0], r1 ++ vst2.8 {d2[2], d3[2]}, [r0], r1 ++ vst2.8 {d2[3], d3[3]}, [r0] ++1: add r0, r4, r1, lsl #2 ++ tst r3, #1 ++ bne 2f ++ vst2.8 {d2[4], d3[4]}, [r4], r1 ++ vst2.8 {d2[5], d3[5]}, [r4], r1 ++ vst2.8 {d2[6], d3[6]}, [r4], r1 ++ vst2.8 {d2[7], d3[7]}, [r4] ++2: add r4, r0, r1, lsl #2 ++ tst r5, #1 ++ bne 3f ++ vst2.8 {d4[0], d5[0]}, [r0], r1 ++ vst2.8 {d4[1], d5[1]}, [r0], r1 ++ vst2.8 {d4[2], d5[2]}, [r0], r1 ++ vst2.8 {d4[3], d5[3]}, [r0] ++3: tst r6, #1 ++ bne 4f ++ vst2.8 {d4[4], d5[4]}, [r4], r1 ++ vst2.8 {d4[5], d5[5]}, [r4], r1 ++ vst2.8 {d4[6], d5[6]}, [r4], r1 ++ vst2.8 {d4[7], d5[7]}, [r4] ++4: vpop {d8-d15} ++ pop {r4-r6,pc} ++endfunc ++ ++@ Copy at most the specified number of bytes from source to destination buffer, ++@ stopping at a multiple of 16 bytes, none of which are the start of an escape sequence ++@ On entry: ++@ r0 -> source buffer ++@ r1 = max number of bytes to copy ++@ r2 -> destination buffer, optimally 8-byte aligned ++@ On exit: ++@ r0 = number of bytes not copied ++function ff_vc1_unescape_buffer_helper_neon, export=1 ++ @ Offset by 48 to screen out cases that are too short for us to handle, ++ @ and also make it easy to test for loop termination, or to determine ++ @ whether we need an odd number of half-iterations of the loop. ++ subs r1, r1, #48 ++ bmi 90f ++ ++ @ Set up useful constants ++ vmov.i32 q0, #0x3000000 ++ vmov.i32 q1, #0x30000 ++ ++ tst r1, #16 ++ bne 1f ++ ++ vld1.8 {q8, q9}, [r0]! ++ vbic q12, q8, q0 ++ vext.8 q13, q8, q9, #1 ++ vext.8 q14, q8, q9, #2 ++ vext.8 q15, q8, q9, #3 ++ veor q12, q12, q1 ++ vbic q13, q13, q0 ++ vbic q14, q14, q0 ++ vbic q15, q15, q0 ++ vceq.i32 q12, q12, #0 ++ veor q13, q13, q1 ++ veor q14, q14, q1 ++ veor q15, q15, q1 ++ vceq.i32 q13, q13, #0 ++ vceq.i32 q14, q14, #0 ++ vceq.i32 q15, q15, #0 ++ add r1, r1, #16 ++ b 3f ++ ++1: vld1.8 {q10, q11}, [r0]! ++ vbic q12, q10, q0 ++ vext.8 q13, q10, q11, #1 ++ vext.8 q14, q10, q11, #2 ++ vext.8 q15, q10, q11, #3 ++ veor q12, q12, q1 ++ vbic q13, q13, q0 ++ vbic q14, q14, q0 ++ vbic q15, q15, q0 ++ vceq.i32 q12, q12, #0 ++ veor q13, q13, q1 ++ veor q14, q14, q1 ++ veor q15, q15, q1 ++ vceq.i32 q13, q13, #0 ++ vceq.i32 q14, q14, #0 ++ vceq.i32 q15, q15, #0 ++ @ Drop through... ++2: vmov q8, q11 ++ vld1.8 {q9}, [r0]! ++ vorr q13, q12, q13 ++ vorr q15, q14, q15 ++ vbic q12, q8, q0 ++ vorr q3, q13, q15 ++ vext.8 q13, q8, q9, #1 ++ vext.8 q14, q8, q9, #2 ++ vext.8 q15, q8, q9, #3 ++ veor q12, q12, q1 ++ vorr d6, d6, d7 ++ vbic q13, q13, q0 ++ vbic q14, q14, q0 ++ vbic q15, q15, q0 ++ vceq.i32 q12, q12, #0 ++ vmov r3, r12, d6 ++ veor q13, q13, q1 ++ veor q14, q14, q1 ++ veor q15, q15, q1 ++ vceq.i32 q13, q13, #0 ++ vceq.i32 q14, q14, #0 ++ vceq.i32 q15, q15, #0 ++ orrs r3, r3, r12 ++ bne 90f ++ vst1.64 {q10}, [r2]! ++3: vmov q10, q9 ++ vld1.8 {q11}, [r0]! ++ vorr q13, q12, q13 ++ vorr q15, q14, q15 ++ vbic q12, q10, q0 ++ vorr q3, q13, q15 ++ vext.8 q13, q10, q11, #1 ++ vext.8 q14, q10, q11, #2 ++ vext.8 q15, q10, q11, #3 ++ veor q12, q12, q1 ++ vorr d6, d6, d7 ++ vbic q13, q13, q0 ++ vbic q14, q14, q0 ++ vbic q15, q15, q0 ++ vceq.i32 q12, q12, #0 ++ vmov r3, r12, d6 ++ veor q13, q13, q1 ++ veor q14, q14, q1 ++ veor q15, q15, q1 ++ vceq.i32 q13, q13, #0 ++ vceq.i32 q14, q14, #0 ++ vceq.i32 q15, q15, #0 ++ orrs r3, r3, r12 ++ bne 91f ++ vst1.64 {q8}, [r2]! ++ subs r1, r1, #32 ++ bpl 2b ++ ++90: add r0, r1, #48 ++ bx lr ++ ++91: sub r1, r1, #16 ++ b 90b ++endfunc --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -2567,6 +2567,17 @@ typedef struct AVHWAccel { @@ -15229,7 +17987,7 @@ Upstream-status: Pending + */ + void (*abort_frame)(AVCodecContext *avctx); } AVHWAccel; - + /** --- a/libavcodec/cabac.h +++ b/libavcodec/cabac.h @@ -15253,7 +18011,7 @@ Upstream-status: Pending +++ b/libavcodec/codec.h @@ -350,6 +350,17 @@ const AVCodec *av_codec_iterate(void **o AVCodec *avcodec_find_decoder(enum AVCodecID id); - + /** + * Find a registered decoder with a matching codec ID and pix_fmt. + * A decoder will pix_fmt set to NULL will match any fmt. @@ -15761,12 +18519,788 @@ Upstream-status: Pending +}; + +#endif +--- /dev/null ++++ b/libavcodec/hevc-ctrls-v3.h +@@ -0,0 +1,255 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * These are the HEVC state controls for use with stateless HEVC ++ * codec drivers. ++ * ++ * It turns out that these structs are not stable yet and will undergo ++ * more changes. So keep them private until they are stable and ready to ++ * become part of the official public API. ++ */ ++ ++#ifndef _HEVC_CTRLS_H_ ++#define _HEVC_CTRLS_H_ ++ ++#include <linux/videodev2.h> ++ ++/* The pixel format isn't stable at the moment and will likely be renamed. */ ++#define V4L2_PIX_FMT_HEVC_SLICE v4l2_fourcc('S', '2', '6', '5') /* HEVC parsed slices */ ++ ++#define V4L2_CID_MPEG_VIDEO_HEVC_SPS (V4L2_CID_CODEC_BASE + 1008) ++#define V4L2_CID_MPEG_VIDEO_HEVC_PPS (V4L2_CID_CODEC_BASE + 1009) ++#define V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS (V4L2_CID_CODEC_BASE + 1010) ++#define V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX (V4L2_CID_CODEC_BASE + 1011) ++#define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS (V4L2_CID_CODEC_BASE + 1012) ++#define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE (V4L2_CID_CODEC_BASE + 1015) ++#define V4L2_CID_MPEG_VIDEO_HEVC_START_CODE (V4L2_CID_CODEC_BASE + 1016) ++ ++/* enum v4l2_ctrl_type type values */ ++#define V4L2_CTRL_TYPE_HEVC_SPS 0x0120 ++#define V4L2_CTRL_TYPE_HEVC_PPS 0x0121 ++#define V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS 0x0122 ++#define V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX 0x0123 ++#define V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS 0x0124 ++ ++enum v4l2_mpeg_video_hevc_decode_mode { ++ V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED, ++ V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED, ++}; ++ ++enum v4l2_mpeg_video_hevc_start_code { ++ V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE, ++ V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B, ++}; ++ ++#define V4L2_HEVC_SLICE_TYPE_B 0 ++#define V4L2_HEVC_SLICE_TYPE_P 1 ++#define V4L2_HEVC_SLICE_TYPE_I 2 ++ ++#define V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE (1ULL << 0) ++#define V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED (1ULL << 1) ++#define V4L2_HEVC_SPS_FLAG_AMP_ENABLED (1ULL << 2) ++#define V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET (1ULL << 3) ++#define V4L2_HEVC_SPS_FLAG_PCM_ENABLED (1ULL << 4) ++#define V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED (1ULL << 5) ++#define V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT (1ULL << 6) ++#define V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED (1ULL << 7) ++#define V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED (1ULL << 8) ++ ++/* The controls are not stable at the moment and will likely be reworked. */ ++struct v4l2_ctrl_hevc_sps { ++ /* ISO/IEC 23008-2, ITU-T Rec. H.265: Sequence parameter set */ ++ __u16 pic_width_in_luma_samples; ++ __u16 pic_height_in_luma_samples; ++ __u8 bit_depth_luma_minus8; ++ __u8 bit_depth_chroma_minus8; ++ __u8 log2_max_pic_order_cnt_lsb_minus4; ++ __u8 sps_max_dec_pic_buffering_minus1; ++ __u8 sps_max_num_reorder_pics; ++ __u8 sps_max_latency_increase_plus1; ++ __u8 log2_min_luma_coding_block_size_minus3; ++ __u8 log2_diff_max_min_luma_coding_block_size; ++ __u8 log2_min_luma_transform_block_size_minus2; ++ __u8 log2_diff_max_min_luma_transform_block_size; ++ __u8 max_transform_hierarchy_depth_inter; ++ __u8 max_transform_hierarchy_depth_intra; ++ __u8 pcm_sample_bit_depth_luma_minus1; ++ __u8 pcm_sample_bit_depth_chroma_minus1; ++ __u8 log2_min_pcm_luma_coding_block_size_minus3; ++ __u8 log2_diff_max_min_pcm_luma_coding_block_size; ++ __u8 num_short_term_ref_pic_sets; ++ __u8 num_long_term_ref_pics_sps; ++ __u8 chroma_format_idc; ++ __u8 sps_max_sub_layers_minus1; ++ ++ __u64 flags; ++}; ++ ++#define V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED (1ULL << 0) ++#define V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT (1ULL << 1) ++#define V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED (1ULL << 2) ++#define V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT (1ULL << 3) ++#define V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED (1ULL << 4) ++#define V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED (1ULL << 5) ++#define V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED (1ULL << 6) ++#define V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT (1ULL << 7) ++#define V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED (1ULL << 8) ++#define V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED (1ULL << 9) ++#define V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED (1ULL << 10) ++#define V4L2_HEVC_PPS_FLAG_TILES_ENABLED (1ULL << 11) ++#define V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED (1ULL << 12) ++#define V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED (1ULL << 13) ++#define V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED (1ULL << 14) ++#define V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED (1ULL << 15) ++#define V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER (1ULL << 16) ++#define V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT (1ULL << 17) ++#define V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT (1ULL << 18) ++#define V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT (1ULL << 19) ++#define V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING (1ULL << 20) ++ ++struct v4l2_ctrl_hevc_pps { ++ /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture parameter set */ ++ __u8 num_extra_slice_header_bits; ++ __u8 num_ref_idx_l0_default_active_minus1; ++ __u8 num_ref_idx_l1_default_active_minus1; ++ __s8 init_qp_minus26; ++ __u8 diff_cu_qp_delta_depth; ++ __s8 pps_cb_qp_offset; ++ __s8 pps_cr_qp_offset; ++ __u8 num_tile_columns_minus1; ++ __u8 num_tile_rows_minus1; ++ __u8 column_width_minus1[20]; ++ __u8 row_height_minus1[22]; ++ __s8 pps_beta_offset_div2; ++ __s8 pps_tc_offset_div2; ++ __u8 log2_parallel_merge_level_minus2; ++ ++ __u8 padding[4]; ++ __u64 flags; ++}; ++ ++#define V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE 0x01 ++ ++#define V4L2_HEVC_DPB_ENTRIES_NUM_MAX 16 ++ ++struct v4l2_hevc_dpb_entry { ++ __u64 timestamp; ++ __u8 flags; ++ __u8 field_pic; ++ __u16 pic_order_cnt[2]; ++ __u8 padding[2]; ++}; ++ ++struct v4l2_hevc_pred_weight_table { ++ __s8 delta_luma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ __s8 luma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ __s8 delta_chroma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]; ++ __s8 chroma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]; ++ ++ __s8 delta_luma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ __s8 luma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ __s8 delta_chroma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]; ++ __s8 chroma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]; ++ ++ __u8 padding[6]; ++ ++ __u8 luma_log2_weight_denom; ++ __s8 delta_chroma_log2_weight_denom; ++}; ++ ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA (1ULL << 0) ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA (1ULL << 1) ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED (1ULL << 2) ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO (1ULL << 3) ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT (1ULL << 4) ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0 (1ULL << 5) ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_USE_INTEGER_MV (1ULL << 6) ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED (1ULL << 7) ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED (1ULL << 8) ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT (1ULL << 9) ++ ++struct v4l2_ctrl_hevc_slice_params { ++ __u32 bit_size; ++ __u32 data_bit_offset; ++ ++ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ ++ __u32 slice_segment_addr; ++ __u32 num_entry_point_offsets; ++ ++ /* ISO/IEC 23008-2, ITU-T Rec. H.265: NAL unit header */ ++ __u8 nal_unit_type; ++ __u8 nuh_temporal_id_plus1; ++ ++ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ ++ __u8 slice_type; ++ __u8 colour_plane_id; ++ __u16 slice_pic_order_cnt; ++ __u8 num_ref_idx_l0_active_minus1; ++ __u8 num_ref_idx_l1_active_minus1; ++ __u8 collocated_ref_idx; ++ __u8 five_minus_max_num_merge_cand; ++ __s8 slice_qp_delta; ++ __s8 slice_cb_qp_offset; ++ __s8 slice_cr_qp_offset; ++ __s8 slice_act_y_qp_offset; ++ __s8 slice_act_cb_qp_offset; ++ __s8 slice_act_cr_qp_offset; ++ __s8 slice_beta_offset_div2; ++ __s8 slice_tc_offset_div2; ++ ++ /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture timing SEI message */ ++ __u8 pic_struct; ++ ++ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ ++ __u8 ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ __u8 ref_idx_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ ++ __u8 padding[5]; ++ ++ __u32 entry_point_offset_minus1[256]; ++ ++ /* ISO/IEC 23008-2, ITU-T Rec. H.265: Weighted prediction parameter */ ++ struct v4l2_hevc_pred_weight_table pred_weight_table; ++ ++ __u64 flags; ++}; ++ ++#define V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC 0x1 ++#define V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC 0x2 ++#define V4L2_HEVC_DECODE_PARAM_FLAG_NO_OUTPUT_OF_PRIOR 0x4 ++ ++struct v4l2_ctrl_hevc_decode_params { ++ __s32 pic_order_cnt_val; ++ __u8 num_active_dpb_entries; ++ struct v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ __u8 num_poc_st_curr_before; ++ __u8 num_poc_st_curr_after; ++ __u8 num_poc_lt_curr; ++ __u8 poc_st_curr_before[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ __u8 poc_st_curr_after[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ __u8 poc_lt_curr[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ __u64 flags; ++}; ++ ++struct v4l2_ctrl_hevc_scaling_matrix { ++ __u8 scaling_list_4x4[6][16]; ++ __u8 scaling_list_8x8[6][64]; ++ __u8 scaling_list_16x16[6][64]; ++ __u8 scaling_list_32x32[2][64]; ++ __u8 scaling_list_dc_coef_16x16[6]; ++ __u8 scaling_list_dc_coef_32x32[2]; ++}; ++ ++/* MPEG-class control IDs specific to the Hantro driver as defined by V4L2 */ ++#define V4L2_CID_CODEC_HANTRO_BASE (V4L2_CTRL_CLASS_CODEC | 0x1200) ++/* ++ * V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP - ++ * the number of data (in bits) to skip in the ++ * slice segment header. ++ * If non-IDR, the bits to be skipped go from syntax element "pic_output_flag" ++ * to before syntax element "slice_temporal_mvp_enabled_flag". ++ * If IDR, the skipped bits are just "pic_output_flag" ++ * (separate_colour_plane_flag is not supported). ++ */ ++#define V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP (V4L2_CID_CODEC_HANTRO_BASE + 0) ++ ++#endif +--- /dev/null ++++ b/libavcodec/hevc-ctrls-v4.h +@@ -0,0 +1,515 @@ ++/* SPDX-License-Identifier: ((GPL-2.0+ WITH Linux-syscall-note) OR BSD-3-Clause) */ ++/* ++ * Video for Linux Two controls header file ++ * ++ * Copyright (C) 1999-2012 the contributors ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * Alternatively you can redistribute this file under the terms of the ++ * BSD license as stated below: ++ * ++ * 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. ++ * 3. The names of its contributors may not be used to endorse or promote ++ * products derived from this software without specific prior written ++ * permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * 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. ++ * ++ * The contents of this header was split off from videodev2.h. All control ++ * definitions should be added to this header, which is included by ++ * videodev2.h. ++ */ ++ ++#ifndef AVCODEC_HEVC_CTRLS_V4_H ++#define AVCODEC_HEVC_CTRLS_V4_H ++ ++#include <linux/const.h> ++#include <linux/types.h> ++ ++#define V4L2_CID_STATELESS_HEVC_SPS (V4L2_CID_CODEC_STATELESS_BASE + 400) ++#define V4L2_CID_STATELESS_HEVC_PPS (V4L2_CID_CODEC_STATELESS_BASE + 401) ++#define V4L2_CID_STATELESS_HEVC_SLICE_PARAMS (V4L2_CID_CODEC_STATELESS_BASE + 402) ++#define V4L2_CID_STATELESS_HEVC_SCALING_MATRIX (V4L2_CID_CODEC_STATELESS_BASE + 403) ++#define V4L2_CID_STATELESS_HEVC_DECODE_PARAMS (V4L2_CID_CODEC_STATELESS_BASE + 404) ++#define V4L2_CID_STATELESS_HEVC_DECODE_MODE (V4L2_CID_CODEC_STATELESS_BASE + 405) ++#define V4L2_CID_STATELESS_HEVC_START_CODE (V4L2_CID_CODEC_STATELESS_BASE + 406) ++#define V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS (V4L2_CID_CODEC_STATELESS_BASE + 407) ++ ++enum v4l2_stateless_hevc_decode_mode { ++ V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED, ++ V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED, ++}; ++ ++enum v4l2_stateless_hevc_start_code { ++ V4L2_STATELESS_HEVC_START_CODE_NONE, ++ V4L2_STATELESS_HEVC_START_CODE_ANNEX_B, ++}; ++ ++#define V4L2_HEVC_SLICE_TYPE_B 0 ++#define V4L2_HEVC_SLICE_TYPE_P 1 ++#define V4L2_HEVC_SLICE_TYPE_I 2 ++ ++#define V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE (1ULL << 0) ++#define V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED (1ULL << 1) ++#define V4L2_HEVC_SPS_FLAG_AMP_ENABLED (1ULL << 2) ++#define V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET (1ULL << 3) ++#define V4L2_HEVC_SPS_FLAG_PCM_ENABLED (1ULL << 4) ++#define V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED (1ULL << 5) ++#define V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT (1ULL << 6) ++#define V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED (1ULL << 7) ++#define V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED (1ULL << 8) ++ ++/** ++ * struct v4l2_ctrl_hevc_sps - ITU-T Rec. H.265: Sequence parameter set ++ * ++ * @video_parameter_set_id: specifies the value of the ++ * vps_video_parameter_set_id of the active VPS ++ * @seq_parameter_set_id: provides an identifier for the SPS for ++ * reference by other syntax elements ++ * @pic_width_in_luma_samples: specifies the width of each decoded picture ++ * in units of luma samples ++ * @pic_height_in_luma_samples: specifies the height of each decoded picture ++ * in units of luma samples ++ * @bit_depth_luma_minus8: this value plus 8specifies the bit depth of the ++ * samples of the luma array ++ * @bit_depth_chroma_minus8: this value plus 8 specifies the bit depth of the ++ * samples of the chroma arrays ++ * @log2_max_pic_order_cnt_lsb_minus4: this value plus 4 specifies the value of ++ * the variable MaxPicOrderCntLsb ++ * @sps_max_dec_pic_buffering_minus1: this value plus 1 specifies the maximum ++ * required size of the decoded picture ++ * buffer for the codec video sequence ++ * @sps_max_num_reorder_pics: indicates the maximum allowed number of pictures ++ * @sps_max_latency_increase_plus1: not equal to 0 is used to compute the ++ * value of SpsMaxLatencyPictures array ++ * @log2_min_luma_coding_block_size_minus3: plus 3 specifies the minimum ++ * luma coding block size ++ * @log2_diff_max_min_luma_coding_block_size: specifies the difference between ++ * the maximum and minimum luma ++ * coding block size ++ * @log2_min_luma_transform_block_size_minus2: plus 2 specifies the minimum luma ++ * transform block size ++ * @log2_diff_max_min_luma_transform_block_size: specifies the difference between ++ * the maximum and minimum luma ++ * transform block size ++ * @max_transform_hierarchy_depth_inter: specifies the maximum hierarchy ++ * depth for transform units of ++ * coding units coded in inter ++ * prediction mode ++ * @max_transform_hierarchy_depth_intra: specifies the maximum hierarchy ++ * depth for transform units of ++ * coding units coded in intra ++ * prediction mode ++ * @pcm_sample_bit_depth_luma_minus1: this value plus 1 specifies the number of ++ * bits used to represent each of PCM sample ++ * values of the luma component ++ * @pcm_sample_bit_depth_chroma_minus1: this value plus 1 specifies the number ++ * of bits used to represent each of PCM ++ * sample values of the chroma components ++ * @log2_min_pcm_luma_coding_block_size_minus3: this value plus 3 specifies the ++ * minimum size of coding blocks ++ * @log2_diff_max_min_pcm_luma_coding_block_size: specifies the difference between ++ * the maximum and minimum size of ++ * coding blocks ++ * @num_short_term_ref_pic_sets: specifies the number of st_ref_pic_set() ++ * syntax structures included in the SPS ++ * @num_long_term_ref_pics_sps: specifies the number of candidate long-term ++ * reference pictures that are specified in the SPS ++ * @chroma_format_idc: specifies the chroma sampling ++ * @sps_max_sub_layers_minus1: this value plus 1 specifies the maximum number ++ * of temporal sub-layers ++ * @reserved: padding field. Should be zeroed by applications. ++ * @flags: see V4L2_HEVC_SPS_FLAG_{} ++ */ ++struct v4l2_ctrl_hevc_sps { ++ __u8 video_parameter_set_id; ++ __u8 seq_parameter_set_id; ++ __u16 pic_width_in_luma_samples; ++ __u16 pic_height_in_luma_samples; ++ __u8 bit_depth_luma_minus8; ++ __u8 bit_depth_chroma_minus8; ++ __u8 log2_max_pic_order_cnt_lsb_minus4; ++ __u8 sps_max_dec_pic_buffering_minus1; ++ __u8 sps_max_num_reorder_pics; ++ __u8 sps_max_latency_increase_plus1; ++ __u8 log2_min_luma_coding_block_size_minus3; ++ __u8 log2_diff_max_min_luma_coding_block_size; ++ __u8 log2_min_luma_transform_block_size_minus2; ++ __u8 log2_diff_max_min_luma_transform_block_size; ++ __u8 max_transform_hierarchy_depth_inter; ++ __u8 max_transform_hierarchy_depth_intra; ++ __u8 pcm_sample_bit_depth_luma_minus1; ++ __u8 pcm_sample_bit_depth_chroma_minus1; ++ __u8 log2_min_pcm_luma_coding_block_size_minus3; ++ __u8 log2_diff_max_min_pcm_luma_coding_block_size; ++ __u8 num_short_term_ref_pic_sets; ++ __u8 num_long_term_ref_pics_sps; ++ __u8 chroma_format_idc; ++ __u8 sps_max_sub_layers_minus1; ++ ++ __u8 reserved[6]; ++ __u64 flags; ++}; ++ ++#define V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED (1ULL << 0) ++#define V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT (1ULL << 1) ++#define V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED (1ULL << 2) ++#define V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT (1ULL << 3) ++#define V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED (1ULL << 4) ++#define V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED (1ULL << 5) ++#define V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED (1ULL << 6) ++#define V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT (1ULL << 7) ++#define V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED (1ULL << 8) ++#define V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED (1ULL << 9) ++#define V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED (1ULL << 10) ++#define V4L2_HEVC_PPS_FLAG_TILES_ENABLED (1ULL << 11) ++#define V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED (1ULL << 12) ++#define V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED (1ULL << 13) ++#define V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED (1ULL << 14) ++#define V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED (1ULL << 15) ++#define V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER (1ULL << 16) ++#define V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT (1ULL << 17) ++#define V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT (1ULL << 18) ++#define V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT (1ULL << 19) ++#define V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING (1ULL << 20) ++ ++/** ++ * struct v4l2_ctrl_hevc_pps - ITU-T Rec. H.265: Picture parameter set ++ * ++ * @pic_parameter_set_id: identifies the PPS for reference by other ++ * syntax elements ++ * @num_extra_slice_header_bits: specifies the number of extra slice header ++ * bits that are present in the slice header RBSP ++ * for coded pictures referring to the PPS. ++ * @num_ref_idx_l0_default_active_minus1: this value plus 1 specifies the ++ * inferred value of num_ref_idx_l0_active_minus1 ++ * @num_ref_idx_l1_default_active_minus1: this value plus 1 specifies the ++ * inferred value of num_ref_idx_l1_active_minus1 ++ * @init_qp_minus26: this value plus 26 specifies the initial value of SliceQp Y for ++ * each slice referring to the PPS ++ * @diff_cu_qp_delta_depth: specifies the difference between the luma coding ++ * tree block size and the minimum luma coding block ++ * size of coding units that convey cu_qp_delta_abs ++ * and cu_qp_delta_sign_flag ++ * @pps_cb_qp_offset: specify the offsets to the luma quantization parameter Cb ++ * @pps_cr_qp_offset: specify the offsets to the luma quantization parameter Cr ++ * @num_tile_columns_minus1: this value plus 1 specifies the number of tile columns ++ * partitioning the picture ++ * @num_tile_rows_minus1: this value plus 1 specifies the number of tile rows partitioning ++ * the picture ++ * @column_width_minus1: this value plus 1 specifies the width of the each tile column in ++ * units of coding tree blocks ++ * @row_height_minus1: this value plus 1 specifies the height of the each tile row in ++ * units of coding tree blocks ++ * @pps_beta_offset_div2: specify the default deblocking parameter offsets for ++ * beta divided by 2 ++ * @pps_tc_offset_div2: specify the default deblocking parameter offsets for tC ++ * divided by 2 ++ * @log2_parallel_merge_level_minus2: this value plus 2 specifies the value of ++ * the variable Log2ParMrgLevel ++ * @reserved: padding field. Should be zeroed by applications. ++ * @flags: see V4L2_HEVC_PPS_FLAG_{} ++ */ ++struct v4l2_ctrl_hevc_pps { ++ __u8 pic_parameter_set_id; ++ __u8 num_extra_slice_header_bits; ++ __u8 num_ref_idx_l0_default_active_minus1; ++ __u8 num_ref_idx_l1_default_active_minus1; ++ __s8 init_qp_minus26; ++ __u8 diff_cu_qp_delta_depth; ++ __s8 pps_cb_qp_offset; ++ __s8 pps_cr_qp_offset; ++ __u8 num_tile_columns_minus1; ++ __u8 num_tile_rows_minus1; ++ __u8 column_width_minus1[20]; ++ __u8 row_height_minus1[22]; ++ __s8 pps_beta_offset_div2; ++ __s8 pps_tc_offset_div2; ++ __u8 log2_parallel_merge_level_minus2; ++ __u8 reserved; ++ __u64 flags; ++}; ++ ++#define V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE 0x01 ++ ++#define V4L2_HEVC_SEI_PIC_STRUCT_FRAME 0 ++#define V4L2_HEVC_SEI_PIC_STRUCT_TOP_FIELD 1 ++#define V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_FIELD 2 ++#define V4L2_HEVC_SEI_PIC_STRUCT_TOP_BOTTOM 3 ++#define V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_TOP 4 ++#define V4L2_HEVC_SEI_PIC_STRUCT_TOP_BOTTOM_TOP 5 ++#define V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM 6 ++#define V4L2_HEVC_SEI_PIC_STRUCT_FRAME_DOUBLING 7 ++#define V4L2_HEVC_SEI_PIC_STRUCT_FRAME_TRIPLING 8 ++#define V4L2_HEVC_SEI_PIC_STRUCT_TOP_PAIRED_PREVIOUS_BOTTOM 9 ++#define V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_PAIRED_PREVIOUS_TOP 10 ++#define V4L2_HEVC_SEI_PIC_STRUCT_TOP_PAIRED_NEXT_BOTTOM 11 ++#define V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_PAIRED_NEXT_TOP 12 ++ ++#define V4L2_HEVC_DPB_ENTRIES_NUM_MAX 16 ++ ++/** ++ * struct v4l2_hevc_dpb_entry - HEVC decoded picture buffer entry ++ * ++ * @timestamp: timestamp of the V4L2 capture buffer to use as reference. ++ * @flags: long term flag for the reference frame ++ * @field_pic: whether the reference is a field picture or a frame. ++ * @reserved: padding field. Should be zeroed by applications. ++ * @pic_order_cnt_val: the picture order count of the current picture. ++ */ ++struct v4l2_hevc_dpb_entry { ++ __u64 timestamp; ++ __u8 flags; ++ __u8 field_pic; ++ __u16 reserved; ++ __s32 pic_order_cnt_val; ++}; ++ ++/** ++ * struct v4l2_hevc_pred_weight_table - HEVC weighted prediction parameters ++ * ++ * @delta_luma_weight_l0: the difference of the weighting factor applied ++ * to the luma prediction value for list 0 ++ * @luma_offset_l0: the additive offset applied to the luma prediction value ++ * for list 0 ++ * @delta_chroma_weight_l0: the difference of the weighting factor applied ++ * to the chroma prediction values for list 0 ++ * @chroma_offset_l0: the difference of the additive offset applied to ++ * the chroma prediction values for list 0 ++ * @delta_luma_weight_l1: the difference of the weighting factor applied ++ * to the luma prediction value for list 1 ++ * @luma_offset_l1: the additive offset applied to the luma prediction value ++ * for list 1 ++ * @delta_chroma_weight_l1: the difference of the weighting factor applied ++ * to the chroma prediction values for list 1 ++ * @chroma_offset_l1: the difference of the additive offset applied to ++ * the chroma prediction values for list 1 ++ * @luma_log2_weight_denom: the base 2 logarithm of the denominator for ++ * all luma weighting factors ++ * @delta_chroma_log2_weight_denom: the difference of the base 2 logarithm ++ * of the denominator for all chroma ++ * weighting factors ++ */ ++struct v4l2_hevc_pred_weight_table { ++ __s8 delta_luma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ __s8 luma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ __s8 delta_chroma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]; ++ __s8 chroma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]; ++ ++ __s8 delta_luma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ __s8 luma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ __s8 delta_chroma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]; ++ __s8 chroma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]; ++ ++ __u8 luma_log2_weight_denom; ++ __s8 delta_chroma_log2_weight_denom; ++}; ++ ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA (1ULL << 0) ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA (1ULL << 1) ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED (1ULL << 2) ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO (1ULL << 3) ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT (1ULL << 4) ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0 (1ULL << 5) ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_USE_INTEGER_MV (1ULL << 6) ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED (1ULL << 7) ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED (1ULL << 8) ++#define V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT (1ULL << 9) ++ ++/** ++ * struct v4l2_ctrl_hevc_slice_params - HEVC slice parameters ++ * ++ * This control is a dynamically sized 1-dimensional array, ++ * V4L2_CTRL_FLAG_DYNAMIC_ARRAY flag must be set when using it. ++ * ++ * @bit_size: size (in bits) of the current slice data ++ * @data_byte_offset: offset (in bytes) to the video data in the current slice data ++ * @num_entry_point_offsets: specifies the number of entry point offset syntax ++ * elements in the slice header. ++ * @nal_unit_type: specifies the coding type of the slice (B, P or I) ++ * @nuh_temporal_id_plus1: minus 1 specifies a temporal identifier for the NAL unit ++ * @slice_type: see V4L2_HEVC_SLICE_TYPE_{} ++ * @colour_plane_id: specifies the colour plane associated with the current slice ++ * @slice_pic_order_cnt: specifies the picture order count ++ * @num_ref_idx_l0_active_minus1: this value plus 1 specifies the maximum ++ * reference index for reference picture list 0 ++ * that may be used to decode the slice ++ * @num_ref_idx_l1_active_minus1: this value plus 1 specifies the maximum ++ * reference index for reference picture list 1 ++ * that may be used to decode the slice ++ * @collocated_ref_idx: specifies the reference index of the collocated picture used ++ * for temporal motion vector prediction ++ * @five_minus_max_num_merge_cand: specifies the maximum number of merging ++ * motion vector prediction candidates supported in ++ * the slice subtracted from 5 ++ * @slice_qp_delta: specifies the initial value of QpY to be used for the coding ++ * blocks in the slice ++ * @slice_cb_qp_offset: specifies a difference to be added to the value of pps_cb_qp_offset ++ * @slice_cr_qp_offset: specifies a difference to be added to the value of pps_cr_qp_offset ++ * @slice_act_y_qp_offset: screen content extension parameters ++ * @slice_act_cb_qp_offset: screen content extension parameters ++ * @slice_act_cr_qp_offset: screen content extension parameters ++ * @slice_beta_offset_div2: specify the deblocking parameter offsets for beta divided by 2 ++ * @slice_tc_offset_div2: specify the deblocking parameter offsets for tC divided by 2 ++ * @pic_struct: indicates whether a picture should be displayed as a frame or as one or ++ * more fields ++ * @reserved0: padding field. Should be zeroed by applications. ++ * @slice_segment_addr: specifies the address of the first coding tree block in ++ * the slice segment ++ * @ref_idx_l0: the list of L0 reference elements as indices in the DPB ++ * @ref_idx_l1: the list of L1 reference elements as indices in the DPB ++ * @short_term_ref_pic_set_size: specifies the size of short-term reference ++ * pictures set included in the SPS ++ * @long_term_ref_pic_set_size: specifies the size of long-term reference ++ * pictures set include in the SPS ++ * @pred_weight_table: the prediction weight coefficients for inter-picture ++ * prediction ++ * @reserved1: padding field. Should be zeroed by applications. ++ * @flags: see V4L2_HEVC_SLICE_PARAMS_FLAG_{} ++ */ ++struct v4l2_ctrl_hevc_slice_params { ++ __u32 bit_size; ++ __u32 data_byte_offset; ++ __u32 num_entry_point_offsets; ++ ++ /* ISO/IEC 23008-2, ITU-T Rec. H.265: NAL unit header */ ++ __u8 nal_unit_type; ++ __u8 nuh_temporal_id_plus1; ++ ++ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ ++ __u8 slice_type; ++ __u8 colour_plane_id; ++ __s32 slice_pic_order_cnt; ++ __u8 num_ref_idx_l0_active_minus1; ++ __u8 num_ref_idx_l1_active_minus1; ++ __u8 collocated_ref_idx; ++ __u8 five_minus_max_num_merge_cand; ++ __s8 slice_qp_delta; ++ __s8 slice_cb_qp_offset; ++ __s8 slice_cr_qp_offset; ++ __s8 slice_act_y_qp_offset; ++ __s8 slice_act_cb_qp_offset; ++ __s8 slice_act_cr_qp_offset; ++ __s8 slice_beta_offset_div2; ++ __s8 slice_tc_offset_div2; ++ ++ /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture timing SEI message */ ++ __u8 pic_struct; ++ ++ __u8 reserved0[3]; ++ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ ++ __u32 slice_segment_addr; ++ __u8 ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ __u8 ref_idx_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ __u16 short_term_ref_pic_set_size; ++ __u16 long_term_ref_pic_set_size; ++ ++ /* ISO/IEC 23008-2, ITU-T Rec. H.265: Weighted prediction parameter */ ++ struct v4l2_hevc_pred_weight_table pred_weight_table; ++ ++ __u8 reserved1[2]; ++ __u64 flags; ++}; ++ ++#define V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC 0x1 ++#define V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC 0x2 ++#define V4L2_HEVC_DECODE_PARAM_FLAG_NO_OUTPUT_OF_PRIOR 0x4 ++ ++/** ++ * struct v4l2_ctrl_hevc_decode_params - HEVC decode parameters ++ * ++ * @pic_order_cnt_val: picture order count ++ * @short_term_ref_pic_set_size: specifies the size of short-term reference ++ * pictures set included in the SPS of the first slice ++ * @long_term_ref_pic_set_size: specifies the size of long-term reference ++ * pictures set include in the SPS of the first slice ++ * @num_active_dpb_entries: the number of entries in dpb ++ * @num_poc_st_curr_before: the number of reference pictures in the short-term ++ * set that come before the current frame ++ * @num_poc_st_curr_after: the number of reference pictures in the short-term ++ * set that come after the current frame ++ * @num_poc_lt_curr: the number of reference pictures in the long-term set ++ * @poc_st_curr_before: provides the index of the short term before references ++ * in DPB array ++ * @poc_st_curr_after: provides the index of the short term after references ++ * in DPB array ++ * @poc_lt_curr: provides the index of the long term references in DPB array ++ * @reserved: padding field. Should be zeroed by applications. ++ * @dpb: the decoded picture buffer, for meta-data about reference frames ++ * @flags: see V4L2_HEVC_DECODE_PARAM_FLAG_{} ++ */ ++struct v4l2_ctrl_hevc_decode_params { ++ __s32 pic_order_cnt_val; ++ __u16 short_term_ref_pic_set_size; ++ __u16 long_term_ref_pic_set_size; ++ __u8 num_active_dpb_entries; ++ __u8 num_poc_st_curr_before; ++ __u8 num_poc_st_curr_after; ++ __u8 num_poc_lt_curr; ++ __u8 poc_st_curr_before[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ __u8 poc_st_curr_after[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ __u8 poc_lt_curr[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ __u8 reserved[4]; ++ struct v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; ++ __u64 flags; ++}; ++ ++/** ++ * struct v4l2_ctrl_hevc_scaling_matrix - HEVC scaling lists parameters ++ * ++ * @scaling_list_4x4: scaling list is used for the scaling process for ++ * transform coefficients. The values on each scaling ++ * list are expected in raster scan order ++ * @scaling_list_8x8: scaling list is used for the scaling process for ++ * transform coefficients. The values on each scaling ++ * list are expected in raster scan order ++ * @scaling_list_16x16: scaling list is used for the scaling process for ++ * transform coefficients. The values on each scaling ++ * list are expected in raster scan order ++ * @scaling_list_32x32: scaling list is used for the scaling process for ++ * transform coefficients. The values on each scaling ++ * list are expected in raster scan order ++ * @scaling_list_dc_coef_16x16: scaling list is used for the scaling process ++ * for transform coefficients. The values on each ++ * scaling list are expected in raster scan order. ++ * @scaling_list_dc_coef_32x32: scaling list is used for the scaling process ++ * for transform coefficients. The values on each ++ * scaling list are expected in raster scan order. ++ */ ++struct v4l2_ctrl_hevc_scaling_matrix { ++ __u8 scaling_list_4x4[6][16]; ++ __u8 scaling_list_8x8[6][64]; ++ __u8 scaling_list_16x16[6][64]; ++ __u8 scaling_list_32x32[2][64]; ++ __u8 scaling_list_dc_coef_16x16[6]; ++ __u8 scaling_list_dc_coef_32x32[2]; ++}; ++ ++#endif --- a/libavcodec/hevc_parser.c +++ b/libavcodec/hevc_parser.c @@ -98,6 +98,19 @@ static int hevc_parse_slice_header(AVCod avctx->profile = ps->sps->ptl.general_ptl.profile_idc; avctx->level = ps->sps->ptl.general_ptl.level_idc; - + + if (ps->sps->chroma_format_idc == 1) { + avctx->chroma_sample_location = ps->sps->vui.chroma_loc_info_present_flag ? + ps->sps->vui.chroma_sample_loc_type_top_field + 1 : @@ -15783,12 +19317,69 @@ Upstream-status: Pending if (ps->vps->vps_timing_info_present_flag) { num = ps->vps->vps_num_units_in_tick; den = ps->vps->vps_time_scale; +--- a/libavcodec/hevc_refs.c ++++ b/libavcodec/hevc_refs.c +@@ -96,18 +96,22 @@ static HEVCFrame *alloc_frame(HEVCContex + if (!frame->rpl_buf) + goto fail; + +- frame->tab_mvf_buf = av_buffer_pool_get(s->tab_mvf_pool); +- if (!frame->tab_mvf_buf) +- goto fail; +- frame->tab_mvf = (MvField *)frame->tab_mvf_buf->data; ++ if (s->tab_mvf_pool) { ++ frame->tab_mvf_buf = av_buffer_pool_get(s->tab_mvf_pool); ++ if (!frame->tab_mvf_buf) ++ goto fail; ++ frame->tab_mvf = (MvField *)frame->tab_mvf_buf->data; ++ } + +- frame->rpl_tab_buf = av_buffer_pool_get(s->rpl_tab_pool); +- if (!frame->rpl_tab_buf) +- goto fail; +- frame->rpl_tab = (RefPicListTab **)frame->rpl_tab_buf->data; +- frame->ctb_count = s->ps.sps->ctb_width * s->ps.sps->ctb_height; +- for (j = 0; j < frame->ctb_count; j++) +- frame->rpl_tab[j] = (RefPicListTab *)frame->rpl_buf->data; ++ if (s->rpl_tab_pool) { ++ frame->rpl_tab_buf = av_buffer_pool_get(s->rpl_tab_pool); ++ if (!frame->rpl_tab_buf) ++ goto fail; ++ frame->rpl_tab = (RefPicListTab **)frame->rpl_tab_buf->data; ++ frame->ctb_count = s->ps.sps->ctb_width * s->ps.sps->ctb_height; ++ for (j = 0; j < frame->ctb_count; j++) ++ frame->rpl_tab[j] = (RefPicListTab *)frame->rpl_buf->data; ++ } + + frame->frame->top_field_first = s->sei.picture_timing.picture_struct == AV_PICTURE_STRUCTURE_TOP_FIELD; + frame->frame->interlaced_frame = (s->sei.picture_timing.picture_struct == AV_PICTURE_STRUCTURE_TOP_FIELD) || (s->sei.picture_timing.picture_struct == AV_PICTURE_STRUCTURE_BOTTOM_FIELD); +@@ -276,14 +280,17 @@ static int init_slice_rpl(HEVCContext *s + int ctb_count = frame->ctb_count; + int ctb_addr_ts = s->ps.pps->ctb_addr_rs_to_ts[s->sh.slice_segment_addr]; + int i; ++ RefPicListTab * const tab = (RefPicListTab *)frame->rpl_buf->data + s->slice_idx; + + if (s->slice_idx >= frame->rpl_buf->size / sizeof(RefPicListTab)) + return AVERROR_INVALIDDATA; + +- for (i = ctb_addr_ts; i < ctb_count; i++) +- frame->rpl_tab[i] = (RefPicListTab *)frame->rpl_buf->data + s->slice_idx; ++ if (frame->rpl_tab) { ++ for (i = ctb_addr_ts; i < ctb_count; i++) ++ frame->rpl_tab[i] = tab; ++ } + +- frame->refPicList = (RefPicList *)frame->rpl_tab[ctb_addr_ts]; ++ frame->refPicList = tab->refPicList; + + return 0; + } --- a/libavcodec/hevcdec.c +++ b/libavcodec/hevcdec.c @@ -332,6 +332,19 @@ static void export_stream_params(HEVCCon - + ff_set_sar(avctx, sps->vui.sar); - + + if (sps->chroma_format_idc == 1) { + avctx->chroma_sample_location = sps->vui.chroma_loc_info_present_flag ? + sps->vui.chroma_sample_loc_type_top_field + 1 : @@ -15816,7 +19407,7 @@ Upstream-status: Pending + CONFIG_HEVC_RPI4_10_HWACCEL + \ CONFIG_HEVC_VDPAU_HWACCEL) enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts; - + switch (sps->pix_fmt) { case AV_PIX_FMT_YUV420P: case AV_PIX_FMT_YUVJ420P: @@ -15851,7 +19442,43 @@ Upstream-status: Pending break; case AV_PIX_FMT_YUV444P: #if CONFIG_HEVC_VDPAU_HWACCEL -@@ -3230,7 +3258,14 @@ static int hevc_decode_frame(AVCodecCont +@@ -459,6 +487,16 @@ static int set_sps(HEVCContext *s, const + if (!sps) + return 0; + ++ // If hwaccel then we don't need all the s/w decode helper arrays ++ if (s->avctx->hwaccel) { ++ export_stream_params(s, sps); ++ ++ s->avctx->pix_fmt = pix_fmt; ++ s->ps.sps = sps; ++ s->ps.vps = (HEVCVPS*) s->ps.vps_list[s->ps.sps->vps_id]->data; ++ return 0; ++ } ++ + ret = pic_arrays_init(s, sps); + if (ret < 0) + goto fail; +@@ -2809,11 +2847,13 @@ static int hevc_frame_start(HEVCContext + ((s->ps.sps->height >> s->ps.sps->log2_min_cb_size) + 1); + int ret; + +- memset(s->horizontal_bs, 0, s->bs_width * s->bs_height); +- memset(s->vertical_bs, 0, s->bs_width * s->bs_height); +- memset(s->cbf_luma, 0, s->ps.sps->min_tb_width * s->ps.sps->min_tb_height); +- memset(s->is_pcm, 0, (s->ps.sps->min_pu_width + 1) * (s->ps.sps->min_pu_height + 1)); +- memset(s->tab_slice_address, -1, pic_size_in_ctb * sizeof(*s->tab_slice_address)); ++ if (s->horizontal_bs) { ++ memset(s->horizontal_bs, 0, s->bs_width * s->bs_height); ++ memset(s->vertical_bs, 0, s->bs_width * s->bs_height); ++ memset(s->cbf_luma, 0, s->ps.sps->min_tb_width * s->ps.sps->min_tb_height); ++ memset(s->is_pcm, 0, (s->ps.sps->min_pu_width + 1) * (s->ps.sps->min_pu_height + 1)); ++ memset(s->tab_slice_address, -1, pic_size_in_ctb * sizeof(*s->tab_slice_address)); ++ } + + s->is_decoded = 0; + s->first_nal_type = s->nal_unit_type; +@@ -3230,7 +3270,14 @@ static int hevc_decode_frame(AVCodecCont s->ref = NULL; ret = decode_nal_units(s, avpkt->data, avpkt->size); if (ret < 0) @@ -15863,10 +19490,38 @@ Upstream-status: Pending + return ret; + } - + if (avctx->hwaccel) { if (s->ref && (ret = avctx->hwaccel->end_frame(avctx)) < 0) { -@@ -3585,6 +3620,15 @@ AVCodec ff_hevc_decoder = { +@@ -3273,15 +3320,19 @@ static int hevc_ref_frame(HEVCContext *s + if (ret < 0) + return ret; + +- dst->tab_mvf_buf = av_buffer_ref(src->tab_mvf_buf); +- if (!dst->tab_mvf_buf) +- goto fail; +- dst->tab_mvf = src->tab_mvf; ++ if (src->tab_mvf_buf) { ++ dst->tab_mvf_buf = av_buffer_ref(src->tab_mvf_buf); ++ if (!dst->tab_mvf_buf) ++ goto fail; ++ dst->tab_mvf = src->tab_mvf; ++ } + +- dst->rpl_tab_buf = av_buffer_ref(src->rpl_tab_buf); +- if (!dst->rpl_tab_buf) +- goto fail; +- dst->rpl_tab = src->rpl_tab; ++ if (src->rpl_tab_buf) { ++ dst->rpl_tab_buf = av_buffer_ref(src->rpl_tab_buf); ++ if (!dst->rpl_tab_buf) ++ goto fail; ++ dst->rpl_tab = src->rpl_tab; ++ } + + dst->rpl_buf = av_buffer_ref(src->rpl_buf); + if (!dst->rpl_buf) +@@ -3585,6 +3636,15 @@ AVCodec ff_hevc_decoder = { #if CONFIG_HEVC_NVDEC_HWACCEL HWACCEL_NVDEC(hevc), #endif @@ -15897,12 +19552,12 @@ Upstream-status: Pending --- a/libavcodec/hwconfig.h +++ b/libavcodec/hwconfig.h @@ -24,6 +24,7 @@ - - + + #define HWACCEL_CAP_ASYNC_SAFE (1 << 0) +#define HWACCEL_CAP_MT_SAFE (1 << 1) - - + + typedef struct AVCodecHWConfigInternal { @@ -70,6 +71,12 @@ typedef struct AVCodecHWConfigInternal { HW_CONFIG_HWACCEL(1, 1, 0, D3D11, D3D11VA, ff_ ## codec ## _d3d11va2_hwaccel) @@ -15922,7 +19577,7 @@ Upstream-status: Pending @@ -24,6 +24,9 @@ * MMAL Video Decoder */ - + +#pragma GCC diagnostic push +// Many many redundant decls in the header files +#pragma GCC diagnostic ignored "-Wredundant-decls" @@ -15935,12 +19590,12 @@ Upstream-status: Pending #include <interface/mmal/vc/mmal_vc_api.h> +#pragma GCC diagnostic pop #include <stdatomic.h> - + #include "avcodec.h" --- a/libavcodec/pthread_frame.c +++ b/libavcodec/pthread_frame.c @@ -191,7 +191,8 @@ static attribute_align_arg void *frame_w - + /* if the previous thread uses hwaccel then we take the lock to ensure * the threads don't run concurrently */ - if (avctx->hwaccel) { @@ -15950,9 +19605,9 @@ Upstream-status: Pending p->hwaccel_serializing = 1; } @@ -614,7 +615,9 @@ void ff_thread_finish_setup(AVCodecConte - + if (!(avctx->active_thread_type&FF_THREAD_FRAME)) return; - + - if (avctx->hwaccel && !p->hwaccel_serializing) { + if (avctx->hwaccel && + !(avctx->hwaccel->caps_internal & HWACCEL_CAP_MT_SAFE) && @@ -15965,7 +19620,7 @@ Upstream-status: Pending @@ -293,6 +293,12 @@ const PixelFormatTag ff_raw_pix_fmt_tags { AV_PIX_FMT_RGB565LE,MKTAG( 3 , 0 , 0 , 0 ) }, /* flipped RGB565LE */ { AV_PIX_FMT_YUV444P, MKTAG('Y', 'V', '2', '4') }, /* YUV444P, swapped UV */ - + + /* RPI (Might as well define for everything) */ + { AV_PIX_FMT_SAND128, MKTAG('S', 'A', 'N', 'D') }, + { AV_PIX_FMT_RPI4_8, MKTAG('S', 'A', 'N', 'D') }, @@ -15974,13 +19629,13 @@ Upstream-status: Pending + { AV_PIX_FMT_NONE, 0 }, }; - + --- a/libavcodec/rawenc.c +++ b/libavcodec/rawenc.c @@ -24,6 +24,7 @@ * Raw Video Encoder */ - + +#include "config.h" #include "avcodec.h" #include "raw.h" @@ -15993,13 +19648,13 @@ Upstream-status: Pending +#if CONFIG_SAND +#include "libavutil/rpi_sand_fns.h" +#endif - + static av_cold int raw_encode_init(AVCodecContext *avctx) { @@ -49,22 +54,114 @@ FF_ENABLE_DEPRECATION_WARNINGS return 0; } - + +#if CONFIG_SAND +static int raw_sand8_as_yuv420(AVCodecContext *avctx, AVPacket *pkt, + const AVFrame *frame) @@ -16080,7 +19735,7 @@ Upstream-status: Pending - frame->width, frame->height, 1); + int ret; + AVFrame * frame = NULL; - + - if (ret < 0) +#if CONFIG_SAND + if (av_rpi_is_sand_frame(src_frame)) { @@ -16104,7 +19759,7 @@ Upstream-status: Pending + frame->width, frame->height, 1); + if (ret < 0) + goto fail; - + if ((ret = ff_alloc_packet2(avctx, pkt, ret, ret)) < 0) - return ret; + goto fail; @@ -16114,7 +19769,7 @@ Upstream-status: Pending frame->width, frame->height, 1)) < 0) - return ret; + goto fail; - + if(avctx->codec_tag == AV_RL32("yuv2") && ret > 0 && frame->format == AV_PIX_FMT_YUYV422) { @@ -81,8 +178,14 @@ static int raw_encode(AVCodecContext *av @@ -16130,7 +19785,7 @@ Upstream-status: Pending + *got_packet = 0; + return ret; } - + AVCodec ff_rawvideo_encoder = { --- /dev/null +++ b/libavcodec/rpi_hevc_cabac.c @@ -17637,7 +21292,7 @@ Upstream-status: Pending + const xy_off_t * const scan_xy_off = off_xys[scan_idx][log2_trafo_size - 2]; + + int use_vpu; -+#if RPI_COMPRESS_COEFFS ++#if RPI_COMPRESS_COEFFS + int num_nonzero = 0; + int use_compress = 0; + int *coeffs32; @@ -17979,7 +21634,7 @@ Upstream-status: Pending + } + use_compress = 0; + } -+#endif ++#endif + + if (nb_significant_coeff_flag != 0) { + const unsigned int gt1_idx_delta = (c_idx_nz << 2) | @@ -18055,7 +21710,7 @@ Upstream-status: Pending + scale, + i == 0 && xy_off->coeff == 0 ? dc_scale : scale_m, + shift); -+#if RPI_COMPRESS_COEFFS ++#if RPI_COMPRESS_COEFFS + if (use_compress) + coeffs32[num_nonzero++] = (res<<16) + (&blk_coeffs[xy_off->coeff] - coeffs); + else @@ -18247,11 +21902,11 @@ Upstream-status: Pending +#endif + + if (!use_dc) { -+#if RPI_COMPRESS_COEFFS ++#if RPI_COMPRESS_COEFFS + if (use_compress) { + coeffs32[num_nonzero] = 0; + } -+#endif ++#endif + rpi_add_residual(s, lc->jb0, log2_trafo_size, c_idx, x0, y0, coeffs); + } +} @@ -29840,7 +33495,7 @@ Upstream-status: Pending + unsigned int i; + for (i = 0; i != 4; ++i) { + cf->s[i].n = 0; -+#if RPI_COMPRESS_COEFFS ++#if RPI_COMPRESS_COEFFS + cf->s[i].packed = 1; + cf->s[i].packed_n = 0; +#endif @@ -46104,76 +49759,104 @@ Upstream-status: Pending @@ -21,6 +21,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - + +#include <drm_fourcc.h> #include <linux/videodev2.h> #include <sys/ioctl.h> #include <sys/mman.h> -@@ -30,12 +31,14 @@ +@@ -29,57 +30,82 @@ + #include <poll.h> #include "libavcodec/avcodec.h" #include "libavcodec/internal.h" ++#include "libavutil/avassert.h" #include "libavutil/pixdesc.h" +#include "libavutil/hwcontext.h" #include "v4l2_context.h" #include "v4l2_buffers.h" #include "v4l2_m2m.h" +#include "weak_link.h" - + #define USEC_PER_SEC 1000000 -static AVRational v4l2_timebase = { 1, USEC_PER_SEC }; +static const AVRational v4l2_timebase = { 1, USEC_PER_SEC }; - - static inline V4L2m2mContext *buf_to_m2mctx(V4L2Buffer *buf) + +-static inline V4L2m2mContext *buf_to_m2mctx(V4L2Buffer *buf) ++static inline V4L2m2mContext *buf_to_m2mctx(const V4L2Buffer * const buf) { -@@ -52,34 +55,44 @@ static inline AVCodecContext *logger(V4L - static inline AVRational v4l2_get_timebase(V4L2Buffer *avbuf) + return V4L2_TYPE_IS_OUTPUT(buf->context->type) ? + container_of(buf->context, V4L2m2mContext, output) : + container_of(buf->context, V4L2m2mContext, capture); + } + +-static inline AVCodecContext *logger(V4L2Buffer *buf) ++static inline AVCodecContext *logger(const V4L2Buffer * const buf) { - V4L2m2mContext *s = buf_to_m2mctx(avbuf); + return buf_to_m2mctx(buf)->avctx; + } + +-static inline AVRational v4l2_get_timebase(V4L2Buffer *avbuf) ++static inline AVRational v4l2_get_timebase(const V4L2Buffer * const avbuf) + { +- V4L2m2mContext *s = buf_to_m2mctx(avbuf); - - if (s->avctx->pkt_timebase.num) - return s->avctx->pkt_timebase; - return s->avctx->time_base; ++ const V4L2m2mContext *s = buf_to_m2mctx(avbuf); + const AVRational tb = s->avctx->pkt_timebase.num ? + s->avctx->pkt_timebase : + s->avctx->time_base; + return tb.num && tb.den ? tb : v4l2_timebase; } - + -static inline void v4l2_set_pts(V4L2Buffer *out, int64_t pts) -+static inline void v4l2_set_pts(V4L2Buffer *out, int64_t pts, int no_rescale) ++static inline struct timeval tv_from_int(const int64_t t) { - int64_t v4l2_pts; -- ++ return (struct timeval){ ++ .tv_usec = t % USEC_PER_SEC, ++ .tv_sec = t / USEC_PER_SEC ++ }; ++} + - if (pts == AV_NOPTS_VALUE) - pts = 0; -- ++static inline int64_t int_from_tv(const struct timeval t) ++{ ++ return (int64_t)t.tv_sec * USEC_PER_SEC + t.tv_usec; ++} + ++static inline void v4l2_set_pts(V4L2Buffer * const out, const int64_t pts) ++{ /* convert pts to v4l2 timebase */ - v4l2_pts = av_rescale_q(pts, v4l2_get_timebase(out), v4l2_timebase); +- out->buf.timestamp.tv_usec = v4l2_pts % USEC_PER_SEC; +- out->buf.timestamp.tv_sec = v4l2_pts / USEC_PER_SEC; + const int64_t v4l2_pts = -+ no_rescale ? pts : + pts == AV_NOPTS_VALUE ? 0 : + av_rescale_q(pts, v4l2_get_timebase(out), v4l2_timebase); - out->buf.timestamp.tv_usec = v4l2_pts % USEC_PER_SEC; - out->buf.timestamp.tv_sec = v4l2_pts / USEC_PER_SEC; ++ out->buf.timestamp = tv_from_int(v4l2_pts); } - + -static inline int64_t v4l2_get_pts(V4L2Buffer *avbuf) -+static inline int64_t v4l2_get_pts(V4L2Buffer *avbuf, int no_rescale) ++static inline int64_t v4l2_get_pts(const V4L2Buffer * const avbuf) { - int64_t v4l2_pts; - ++ const int64_t v4l2_pts = int_from_tv(avbuf->buf.timestamp); ++ return v4l2_pts != 0 ? v4l2_pts : AV_NOPTS_VALUE; ++#if 0 /* convert pts back to encoder timebase */ - v4l2_pts = (int64_t)avbuf->buf.timestamp.tv_sec * USEC_PER_SEC + -+ const int64_t v4l2_pts = (int64_t)avbuf->buf.timestamp.tv_sec * USEC_PER_SEC + - avbuf->buf.timestamp.tv_usec; - -- return av_rescale_q(v4l2_pts, v4l2_timebase, v4l2_get_timebase(avbuf)); +- avbuf->buf.timestamp.tv_usec; + return -+ no_rescale ? v4l2_pts : ++ avbuf->context->no_pts_rescale ? v4l2_pts : + v4l2_pts == 0 ? AV_NOPTS_VALUE : + av_rescale_q(v4l2_pts, v4l2_timebase, v4l2_get_timebase(avbuf)); ++#endif +} -+ + +- return av_rescale_q(v4l2_pts, v4l2_timebase, v4l2_get_timebase(avbuf)); +static void set_buf_length(V4L2Buffer *out, unsigned int plane, uint32_t bytesused, uint32_t length) +{ + if (V4L2_TYPE_IS_MULTIPLANAR(out->buf.type)) { @@ -46184,12 +49867,15 @@ Upstream-status: Pending + out->buf.length = length; + } } - + static enum AVColorPrimaries v4l2_get_color_primaries(V4L2Buffer *buf) -@@ -116,6 +129,105 @@ static enum AVColorPrimaries v4l2_get_co +@@ -116,49 +142,176 @@ static enum AVColorPrimaries v4l2_get_co return AVCOL_PRI_UNSPECIFIED; } - + +-static enum AVColorRange v4l2_get_color_range(V4L2Buffer *buf) +-{ +- enum v4l2_quantization qt; +static void v4l2_set_color(V4L2Buffer *buf, + const enum AVColorPrimaries avcp, + const enum AVColorSpace avcs, @@ -46230,7 +49916,10 @@ Upstream-status: Pending + default: + break; + } -+ + +- qt = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ? +- buf->context->format.fmt.pix_mp.quantization : +- buf->context->format.fmt.pix.quantization; + switch (avcs) { + case AVCOL_SPC_RGB: + cs = V4L2_COLORSPACE_SRGB; @@ -46260,7 +49949,10 @@ Upstream-status: Pending + default: + break; + } -+ + +- switch (qt) { +- case V4L2_QUANTIZATION_LIM_RANGE: return AVCOL_RANGE_MPEG; +- case V4L2_QUANTIZATION_FULL_RANGE: return AVCOL_RANGE_JPEG; + switch (xfer) { + case AVCOL_TRC_BT709: + xfer = V4L2_XFER_FUNC_709; @@ -46274,10 +49966,11 @@ Upstream-status: Pending + case AVCOL_TRC_SMPTE2084: + xfer = V4L2_XFER_FUNC_SMPTE2084; + break; -+ default: -+ break; -+ } -+ + default: + break; + } + +- return AVCOL_RANGE_UNSPECIFIED; + if (V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type)) { + buf->context->format.fmt.pix_mp.colorspace = cs; + buf->context->format.fmt.pix_mp.ycbcr_enc = ycbcr; @@ -46287,15 +49980,58 @@ Upstream-status: Pending + buf->context->format.fmt.pix.ycbcr_enc = ycbcr; + buf->context->format.fmt.pix.xfer_func = xfer; + } + } + +-static enum AVColorSpace v4l2_get_color_space(V4L2Buffer *buf) ++static inline enum v4l2_quantization ++buf_quantization(const V4L2Buffer * const buf) + { +- enum v4l2_ycbcr_encoding ycbcr; +- enum v4l2_colorspace cs; ++ return V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ? ++ buf->context->format.fmt.pix_mp.quantization : ++ buf->context->format.fmt.pix.quantization; ++} + +- cs = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ? ++static inline enum v4l2_colorspace ++buf_colorspace(const V4L2Buffer * const buf) ++{ ++ return V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ? + buf->context->format.fmt.pix_mp.colorspace : + buf->context->format.fmt.pix.colorspace; ++} + +- ycbcr = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ? ++static inline enum v4l2_ycbcr_encoding ++buf_ycbcr_enc(const V4L2Buffer * const buf) ++{ ++ return V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ? + buf->context->format.fmt.pix_mp.ycbcr_enc: + buf->context->format.fmt.pix.ycbcr_enc; ++} + +- switch(cs) { +- case V4L2_COLORSPACE_SRGB: return AVCOL_SPC_RGB; ++static enum AVColorRange v4l2_get_color_range(V4L2Buffer *buf) ++{ ++ switch (buf_quantization(buf)) { ++ case V4L2_QUANTIZATION_LIM_RANGE: ++ return AVCOL_RANGE_MPEG; ++ case V4L2_QUANTIZATION_FULL_RANGE: ++ return AVCOL_RANGE_JPEG; ++ case V4L2_QUANTIZATION_DEFAULT: ++ // If YUV (which we assume for all video decode) then, from the header ++ // comments, range is limited unless CS is JPEG ++ return buf_colorspace(buf) == V4L2_COLORSPACE_JPEG ? ++ AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; ++ default: ++ break; ++ } ++ ++ return AVCOL_RANGE_UNSPECIFIED; +} + - static enum AVColorRange v4l2_get_color_range(V4L2Buffer *buf) - { - enum v4l2_quantization qt; -@@ -134,6 +246,20 @@ static enum AVColorRange v4l2_get_color_ - return AVCOL_RANGE_UNSPECIFIED; - } - +static void v4l2_set_color_range(V4L2Buffer *buf, const enum AVColorRange avcr) +{ + const enum v4l2_quantization q = @@ -46310,13 +50046,51 @@ Upstream-status: Pending + } +} + - static enum AVColorSpace v4l2_get_color_space(V4L2Buffer *buf) ++static enum AVColorSpace v4l2_get_color_space(V4L2Buffer *buf) ++{ ++ switch (buf_colorspace(buf)) { ++ case V4L2_COLORSPACE_JPEG: // JPEG -> SRGB ++ case V4L2_COLORSPACE_SRGB: ++ return AVCOL_SPC_RGB; + case V4L2_COLORSPACE_REC709: return AVCOL_SPC_BT709; + case V4L2_COLORSPACE_470_SYSTEM_M: return AVCOL_SPC_FCC; + case V4L2_COLORSPACE_470_SYSTEM_BG: return AVCOL_SPC_BT470BG; + case V4L2_COLORSPACE_SMPTE170M: return AVCOL_SPC_SMPTE170M; + case V4L2_COLORSPACE_SMPTE240M: return AVCOL_SPC_SMPTE240M; + case V4L2_COLORSPACE_BT2020: +- if (ycbcr == V4L2_YCBCR_ENC_BT2020_CONST_LUM) +- return AVCOL_SPC_BT2020_CL; +- else +- return AVCOL_SPC_BT2020_NCL; ++ return buf_ycbcr_enc(buf) == V4L2_YCBCR_ENC_BT2020_CONST_LUM ? ++ AVCOL_SPC_BT2020_CL : AVCOL_SPC_BT2020_NCL; + default: + break; + } +@@ -168,17 +321,9 @@ static enum AVColorSpace v4l2_get_color_ + + static enum AVColorTransferCharacteristic v4l2_get_color_trc(V4L2Buffer *buf) { - enum v4l2_ycbcr_encoding ycbcr; -@@ -210,73 +336,165 @@ static enum AVColorTransferCharacteristi +- enum v4l2_ycbcr_encoding ycbcr; ++ const enum v4l2_ycbcr_encoding ycbcr = buf_ycbcr_enc(buf); + enum v4l2_xfer_func xfer; +- enum v4l2_colorspace cs; +- +- cs = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ? +- buf->context->format.fmt.pix_mp.colorspace : +- buf->context->format.fmt.pix.colorspace; +- +- ycbcr = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ? +- buf->context->format.fmt.pix_mp.ycbcr_enc: +- buf->context->format.fmt.pix.ycbcr_enc; ++ const enum v4l2_colorspace cs = buf_colorspace(buf); + + xfer = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ? + buf->context->format.fmt.pix_mp.xfer_func: +@@ -210,73 +355,165 @@ static enum AVColorTransferCharacteristi return AVCOL_TRC_UNSPECIFIED; } - + -static void v4l2_free_buffer(void *opaque, uint8_t *unused) +static int v4l2_buf_is_interlaced(const V4L2Buffer * const buf) { @@ -46327,7 +50101,7 @@ Upstream-status: Pending - atomic_fetch_sub_explicit(&s->refcount, 1, memory_order_acq_rel); + return V4L2_FIELD_IS_INTERLACED(buf->buf.field); +} - + - if (s->reinit) { - if (!atomic_load(&s->refcount)) - sem_post(&s->refsync); @@ -46343,7 +50117,7 @@ Upstream-status: Pending +{ + return buf->buf.field == V4L2_FIELD_INTERLACED_TB; +} - + - av_buffer_unref(&avbuf->context_ref); - } +static void v4l2_set_interlace(V4L2Buffer * const buf, const int is_interlaced, const int is_tff) @@ -46351,14 +50125,14 @@ Upstream-status: Pending + buf->buf.field = !is_interlaced ? V4L2_FIELD_NONE : + is_tff ? V4L2_FIELD_INTERLACED_TB : V4L2_FIELD_INTERLACED_BT; } - + -static int v4l2_buf_increase_ref(V4L2Buffer *in) +static uint8_t * v4l2_get_drm_frame(V4L2Buffer *avbuf) { - V4L2m2mContext *s = buf_to_m2mctx(in); + AVDRMFrameDescriptor *drm_desc = &avbuf->drm_frame; + AVDRMLayerDescriptor *layer; - + - if (in->context_ref) - atomic_fetch_add(&in->context_refcount, 1); - else { @@ -46368,7 +50142,7 @@ Upstream-status: Pending + /* fill the DRM frame descriptor */ + drm_desc->nb_objects = avbuf->num_planes; + drm_desc->nb_layers = 1; - + - in->context_refcount = 1; + layer = &drm_desc->layers[0]; + layer->nb_planes = avbuf->num_planes; @@ -46378,7 +50152,7 @@ Upstream-status: Pending + layer->planes[i].offset = 0; + layer->planes[i].pitch = avbuf->plane_info[i].bytesperline; } - + - in->status = V4L2BUF_RET_USER; - atomic_fetch_add_explicit(&s->refcount, 1, memory_order_relaxed); + switch (avbuf->context->av_pix_fmt) { @@ -46386,7 +50160,7 @@ Upstream-status: Pending + + layer->format = DRM_FORMAT_YUYV; + layer->nb_planes = 1; - + - return 0; + break; + @@ -46435,7 +50209,7 @@ Upstream-status: Pending + + return (uint8_t *) drm_desc; } - + -static int v4l2_buf_to_bufref(V4L2Buffer *in, int plane, AVBufferRef **buf) +static void v4l2_free_bufref(void *opaque, uint8_t *data) { @@ -46443,25 +50217,25 @@ Upstream-status: Pending + AVBufferRef * bufref = (AVBufferRef *)data; + V4L2Buffer *avbuf = (V4L2Buffer *)bufref->data; + struct V4L2Context *ctx = ff_weak_link_lock(&avbuf->context_wl); - + - if (plane >= in->num_planes) - return AVERROR(EINVAL); + if (ctx != NULL) { + // Buffer still attached to context + V4L2m2mContext *s = buf_to_m2mctx(avbuf); - + - /* even though most encoders return 0 in data_offset encoding vp8 does require this value */ - *buf = av_buffer_create((char *)in->plane_info[plane].mm_addr + in->planes[plane].data_offset, - in->plane_info[plane].length, v4l2_free_buffer, in, 0); - if (!*buf) - return AVERROR(ENOMEM); + ff_mutex_lock(&ctx->lock); - + - ret = v4l2_buf_increase_ref(in); - if (ret) - av_buffer_unref(buf); -+ avbuf->status = V4L2BUF_AVAILABLE; - ++ ff_v4l2_buffer_set_avail(avbuf); + - return ret; + if (s->draining && V4L2_TYPE_IS_OUTPUT(ctx->type)) { + av_log(logger(avbuf), AV_LOG_DEBUG, "%s: Buffer avail\n", ctx->name); @@ -46482,8 +50256,9 @@ Upstream-status: Pending + + ff_weak_link_unlock(avbuf->context_wl); + av_buffer_unref(&bufref); -+} -+ + } + +-static int v4l2_bufref_to_buf(V4L2Buffer *out, int plane, const uint8_t* data, int size, int offset, AVBufferRef* bref) +static int v4l2_buffer_export_drm(V4L2Buffer* avbuf) +{ + struct v4l2_exportbuffer expbuf; @@ -46514,20 +50289,19 @@ Upstream-status: Pending + } + + return 0; - } - --static int v4l2_bufref_to_buf(V4L2Buffer *out, int plane, const uint8_t* data, int size, int offset, AVBufferRef* bref) ++} ++ +static int v4l2_bufref_to_buf(V4L2Buffer *out, int plane, const uint8_t* data, int size, int offset) { unsigned int bytesused, length; + int rv = 0; - + if (plane >= out->num_planes) return AVERROR(EINVAL); -@@ -284,32 +502,57 @@ static int v4l2_bufref_to_buf(V4L2Buffer +@@ -284,32 +521,57 @@ static int v4l2_bufref_to_buf(V4L2Buffer length = out->plane_info[plane].length; bytesused = FFMIN(size+offset, length); - + - memcpy((uint8_t*)out->plane_info[plane].mm_addr+offset, data, FFMIN(size, length-offset)); - - if (V4L2_TYPE_IS_MULTIPLANAR(out->buf.type)) { @@ -46540,7 +50314,7 @@ Upstream-status: Pending + size = length - offset; + rv = AVERROR(ENOMEM); } - + - return 0; + memcpy((uint8_t*)out->plane_info[plane].mm_addr+offset, data, size); + @@ -46564,14 +50338,14 @@ Upstream-status: Pending + avbuf->status = V4L2BUF_RET_USER; + return newbuf; } - + static int v4l2_buffer_buf_to_swframe(AVFrame *frame, V4L2Buffer *avbuf) { - int i, ret; + int i; - + frame->format = avbuf->context->av_pix_fmt; - + - for (i = 0; i < avbuf->num_planes; i++) { - ret = v4l2_buf_to_bufref(avbuf, i, &frame->buf[i]); - if (ret) @@ -46579,7 +50353,7 @@ Upstream-status: Pending + frame->buf[0] = wrap_avbuf(avbuf); + if (frame->buf[0] == NULL) + return AVERROR(ENOMEM); - ++ + if (buf_to_m2mctx(avbuf)->output_drm) { + /* 1. get references to the actual data */ + frame->data[0] = (uint8_t *) v4l2_get_drm_frame(avbuf); @@ -46587,7 +50361,7 @@ Upstream-status: Pending + frame->hw_frames_ctx = av_buffer_ref(avbuf->context->frames_ref); + return 0; + } -+ + + + /* 1. get references to the actual data */ + for (i = 0; i < avbuf->num_planes; i++) { @@ -46595,9 +50369,9 @@ Upstream-status: Pending frame->linesize[i] = avbuf->plane_info[i].bytesperline; - frame->data[i] = frame->buf[i]->data; } - + /* fixup special cases */ -@@ -318,17 +561,17 @@ static int v4l2_buffer_buf_to_swframe(AV +@@ -318,17 +580,17 @@ static int v4l2_buffer_buf_to_swframe(AV case AV_PIX_FMT_NV21: if (avbuf->num_planes > 1) break; @@ -46606,7 +50380,7 @@ Upstream-status: Pending + frame->linesize[1] = frame->linesize[0]; + frame->data[1] = frame->data[0] + frame->linesize[0] * ff_v4l2_get_format_height(&avbuf->context->format); break; - + case AV_PIX_FMT_YUV420P: if (avbuf->num_planes > 1) break; @@ -46619,12 +50393,12 @@ Upstream-status: Pending + frame->data[1] = frame->data[0] + frame->linesize[0] * ff_v4l2_get_format_height(&avbuf->context->format); + frame->data[2] = frame->data[1] + frame->linesize[1] * ff_v4l2_get_format_height(&avbuf->context->format) / 2; break; - + default: -@@ -338,68 +581,95 @@ static int v4l2_buffer_buf_to_swframe(AV +@@ -338,68 +600,127 @@ static int v4l2_buffer_buf_to_swframe(AV return 0; } - + +static void cpy_2d(uint8_t * dst, int dst_stride, const uint8_t * src, int src_stride, int w, int h) +{ + if (dst_stride == src_stride && w + 32 >= dst_stride) { @@ -46644,6 +50418,38 @@ Upstream-status: Pending + return i != 0 && !(i == num_planes - 1 && (desc->flags & AV_PIX_FMT_FLAG_ALPHA)); +} + ++static int v4l2_buffer_primeframe_to_buf(const AVFrame *frame, V4L2Buffer *out) ++{ ++ const AVDRMFrameDescriptor *const src = (const AVDRMFrameDescriptor *)frame->data[0]; ++ ++ if (frame->format != AV_PIX_FMT_DRM_PRIME || !src) ++ return AVERROR(EINVAL); ++ ++ av_assert0(out->buf.memory == V4L2_MEMORY_DMABUF); ++ ++ if (V4L2_TYPE_IS_MULTIPLANAR(out->buf.type)) { ++ // Only currently cope with single buffer types ++ if (out->buf.length != 1) ++ return AVERROR_PATCHWELCOME; ++ if (src->nb_objects != 1) ++ return AVERROR(EINVAL); ++ ++ out->planes[0].m.fd = src->objects[0].fd; ++ } ++ else { ++ if (src->nb_objects != 1) ++ return AVERROR(EINVAL); ++ ++ out->buf.m.fd = src->objects[0].fd; ++ } ++ ++ // No need to copy src AVDescriptor and if we did then we may confuse ++ // fd close on free ++ out->ref_buf = av_buffer_ref(frame->buf[0]); ++ ++ return 0; ++} ++ static int v4l2_buffer_swframe_to_buf(const AVFrame *frame, V4L2Buffer *out) { - int i, ret; @@ -46756,7 +50562,7 @@ Upstream-status: Pending + av_log(NULL, AV_LOG_ERROR, "%s: Plane total %u > buffer size %zu\n", __func__, offset, out->plane_info[0].length); + return -1; + } - + - for (i = 0; i < out->num_planes; i++) { - ret = v4l2_bufref_to_buf(out, i, frame->buf[i]->data, frame->buf[i]->size, 0, frame->buf[i]); - if (ret) @@ -46770,42 +50576,60 @@ Upstream-status: Pending - return 0; } - -@@ -411,14 +681,22 @@ static int v4l2_buffer_swframe_to_buf(co - - int ff_v4l2_buffer_avframe_to_buf(const AVFrame *frame, V4L2Buffer *out) + +@@ -409,16 +730,31 @@ static int v4l2_buffer_swframe_to_buf(co + * + ******************************************************************************/ + +-int ff_v4l2_buffer_avframe_to_buf(const AVFrame *frame, V4L2Buffer *out) ++int ff_v4l2_buffer_avframe_to_buf(const AVFrame *frame, V4L2Buffer *out, const int64_t track_ts) { - v4l2_set_pts(out, frame->pts); -+ out->buf.flags = frame->key_frame ? (out->buf.flags & ~V4L2_BUF_FLAG_KEYFRAME) : (out->buf.flags | V4L2_BUF_FLAG_KEYFRAME); +- +- return v4l2_buffer_swframe_to_buf(frame, out); ++ out->buf.flags = frame->key_frame ? ++ (out->buf.flags | V4L2_BUF_FLAG_KEYFRAME) : ++ (out->buf.flags & ~V4L2_BUF_FLAG_KEYFRAME); + // Beware that colour info is held in format rather than the actual + // v4l2 buffer struct so this may not be as useful as you might hope + v4l2_set_color(out, frame->color_primaries, frame->colorspace, frame->color_trc); + v4l2_set_color_range(out, frame->color_range); + // PTS & interlace are buffer vars -+ v4l2_set_pts(out, frame->pts, 0); ++ if (track_ts) ++ out->buf.timestamp = tv_from_int(track_ts); ++ else ++ v4l2_set_pts(out, frame->pts); + v4l2_set_interlace(out, frame->interlaced_frame, frame->top_field_first); - - return v4l2_buffer_swframe_to_buf(frame, out); ++ ++ return frame->format == AV_PIX_FMT_DRM_PRIME ? ++ v4l2_buffer_primeframe_to_buf(frame, out) : ++ v4l2_buffer_swframe_to_buf(frame, out); } - --int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *avbuf) -+int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *avbuf, int no_rescale_pts) + + int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *avbuf) { int ret; + V4L2Context * const ctx = avbuf->context; - + av_frame_unref(frame); - -@@ -433,13 +711,24 @@ int ff_v4l2_buffer_buf_to_avframe(AVFram + +@@ -429,17 +765,32 @@ int ff_v4l2_buffer_buf_to_avframe(AVFram + + /* 2. get frame information */ + frame->key_frame = !!(avbuf->buf.flags & V4L2_BUF_FLAG_KEYFRAME); ++ frame->pict_type = frame->key_frame ? AV_PICTURE_TYPE_I : ++ (avbuf->buf.flags & V4L2_BUF_FLAG_PFRAME) != 0 ? AV_PICTURE_TYPE_P : ++ (avbuf->buf.flags & V4L2_BUF_FLAG_BFRAME) != 0 ? AV_PICTURE_TYPE_B : ++ AV_PICTURE_TYPE_NONE; + frame->color_primaries = v4l2_get_color_primaries(avbuf); frame->colorspace = v4l2_get_color_space(avbuf); frame->color_range = v4l2_get_color_range(avbuf); frame->color_trc = v4l2_get_color_trc(avbuf); -- frame->pts = v4l2_get_pts(avbuf); -+ frame->pts = v4l2_get_pts(avbuf, no_rescale_pts); + frame->pts = v4l2_get_pts(avbuf); frame->pkt_dts = AV_NOPTS_VALUE; + frame->interlaced_frame = v4l2_buf_is_interlaced(avbuf); + frame->top_field_first = v4l2_buf_is_top_first(avbuf); - + /* these values are updated also during re-init in v4l2_process_driver_event */ - frame->height = avbuf->context->height; - frame->width = avbuf->context->width; @@ -46820,18 +50644,17 @@ Upstream-status: Pending + frame->crop_right = ctx->selection.left + ctx->selection.width < frame->width ? + frame->width - (ctx->selection.left + ctx->selection.width) : 0; + frame->crop_bottom = ctx->selection.top + ctx->selection.height < frame->height ? -+ frame->width - (ctx->selection.top + ctx->selection.height) : 0; ++ frame->height - (ctx->selection.top + ctx->selection.height) : 0; + } - + /* 3. report errors upstream */ if (avbuf->buf.flags & V4L2_BUF_FLAG_ERROR) { -@@ -452,15 +741,16 @@ int ff_v4l2_buffer_buf_to_avframe(AVFram - +@@ -452,15 +803,15 @@ int ff_v4l2_buffer_buf_to_avframe(AVFram + int ff_v4l2_buffer_buf_to_avpkt(AVPacket *pkt, V4L2Buffer *avbuf) { - int ret; -+ av_log(logger(avbuf), AV_LOG_INFO, "%s\n", __func__); - +- av_packet_unref(pkt); - ret = v4l2_buf_to_bufref(avbuf, 0, &pkt->buf); - if (ret) @@ -46840,29 +50663,25 @@ Upstream-status: Pending + pkt->buf = wrap_avbuf(avbuf); + if (pkt->buf == NULL) + return AVERROR(ENOMEM); - + pkt->size = V4L2_TYPE_IS_MULTIPLANAR(avbuf->buf.type) ? avbuf->buf.m.planes[0].bytesused : avbuf->buf.bytesused; - pkt->data = pkt->buf->data; + pkt->data = (uint8_t*)avbuf->plane_info[0].mm_addr + avbuf->planes[0].data_offset; - ++ pkt->flags = 0; + if (avbuf->buf.flags & V4L2_BUF_FLAG_KEYFRAME) pkt->flags |= AV_PKT_FLAG_KEY; -@@ -470,36 +760,89 @@ int ff_v4l2_buffer_buf_to_avpkt(AVPacket - pkt->flags |= AV_PKT_FLAG_CORRUPT; - } - -- pkt->dts = pkt->pts = v4l2_get_pts(avbuf); -+ pkt->dts = pkt->pts = v4l2_get_pts(avbuf, 0); - +@@ -475,31 +826,91 @@ int ff_v4l2_buffer_buf_to_avpkt(AVPacket return 0; } - + -int ff_v4l2_buffer_avpkt_to_buf(const AVPacket *pkt, V4L2Buffer *out) -+int ff_v4l2_buffer_avpkt_to_buf_ext(const AVPacket *pkt, V4L2Buffer *out, -+ const void *extdata, size_t extlen, int no_rescale_pts) ++int ff_v4l2_buffer_avpkt_to_buf_ext(const AVPacket * const pkt, V4L2Buffer * const out, ++ const void *extdata, size_t extlen, ++ const int64_t timestamp) { int ret; - + - ret = v4l2_bufref_to_buf(out, 0, pkt->data, pkt->size, 0, pkt->buf); - if (ret) + if (extlen) { @@ -46874,18 +50693,23 @@ Upstream-status: Pending + ret = v4l2_bufref_to_buf(out, 0, pkt->data, pkt->size, extlen); + if (ret && ret != AVERROR(ENOMEM)) return ret; - + - v4l2_set_pts(out, pkt->pts); -+ v4l2_set_pts(out, pkt->pts, no_rescale_pts); - - if (pkt->flags & AV_PKT_FLAG_KEY) - out->flags = V4L2_BUF_FLAG_KEYFRAME; - -- return 0; ++ if (timestamp) ++ out->buf.timestamp = tv_from_int(timestamp); ++ else ++ v4l2_set_pts(out, pkt->pts); ++ ++ out->buf.flags = (pkt->flags & AV_PKT_FLAG_KEY) != 0 ? ++ (out->buf.flags | V4L2_BUF_FLAG_KEYFRAME) : ++ (out->buf.flags & ~V4L2_BUF_FLAG_KEYFRAME); + +- if (pkt->flags & AV_PKT_FLAG_KEY) +- out->flags = V4L2_BUF_FLAG_KEYFRAME; + return ret; - } - --int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index) ++} + +- return 0; +int ff_v4l2_buffer_avpkt_to_buf(const AVPacket *pkt, V4L2Buffer *out) +{ + return ff_v4l2_buffer_avpkt_to_buf_ext(pkt, out, NULL, 0, 0); @@ -46908,23 +50732,27 @@ Upstream-status: Pending + close(avbuf->drm_frame.objects[i].fd); + } + ++ av_buffer_unref(&avbuf->ref_buf); ++ + ff_weak_link_unref(&avbuf->context_wl); + + av_free(avbuf); -+} -+ + } + +-int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index) + -+int ff_v4l2_buffer_initialize(AVBufferRef ** pbufref, int index, V4L2Context *ctx) ++int ff_v4l2_buffer_initialize(AVBufferRef ** pbufref, int index, V4L2Context *ctx, enum v4l2_memory mem) { - V4L2Context *ctx = avbuf->context; int ret, i; + V4L2Buffer * const avbuf = av_mallocz(sizeof(*avbuf)); + AVBufferRef * bufref; -+ + +- avbuf->buf.memory = V4L2_MEMORY_MMAP; + *pbufref = NULL; + if (avbuf == NULL) + return AVERROR(ENOMEM); - ++ + bufref = av_buffer_create((uint8_t*)avbuf, sizeof(*avbuf), v4l2_buffer_buffer_free, NULL, 0); + if (bufref == NULL) { + av_free(avbuf); @@ -46932,10 +50760,10 @@ Upstream-status: Pending + } + + avbuf->context = ctx; - avbuf->buf.memory = V4L2_MEMORY_MMAP; ++ avbuf->buf.memory = mem; avbuf->buf.type = ctx->type; avbuf->buf.index = index; - + + for (i = 0; i != FF_ARRAY_ELEMS(avbuf->drm_frame.objects); ++i) { + avbuf->drm_frame.objects[i].fd = -1; + } @@ -46945,43 +50773,48 @@ Upstream-status: Pending if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) { avbuf->buf.length = VIDEO_MAX_PLANES; avbuf->buf.m.planes = avbuf->planes; -@@ -507,7 +850,7 @@ int ff_v4l2_buffer_initialize(V4L2Buffer - +@@ -507,7 +918,7 @@ int ff_v4l2_buffer_initialize(V4L2Buffer + ret = ioctl(buf_to_m2mctx(avbuf)->fd, VIDIOC_QUERYBUF, &avbuf->buf); if (ret < 0) - return AVERROR(errno); + goto fail; - + if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) { avbuf->num_planes = 0; -@@ -527,25 +870,33 @@ int ff_v4l2_buffer_initialize(V4L2Buffer - +@@ -520,6 +931,8 @@ int ff_v4l2_buffer_initialize(V4L2Buffer + avbuf->num_planes = 1; + + for (i = 0; i < avbuf->num_planes; i++) { ++ const int want_mmap = avbuf->buf.memory == V4L2_MEMORY_MMAP && ++ (V4L2_TYPE_IS_OUTPUT(ctx->type) || !buf_to_m2mctx(avbuf)->output_drm); + + avbuf->plane_info[i].bytesperline = V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? + ctx->format.fmt.pix_mp.plane_fmt[i].bytesperline : +@@ -527,25 +940,29 @@ int ff_v4l2_buffer_initialize(V4L2Buffer + if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) { avbuf->plane_info[i].length = avbuf->buf.m.planes[i].length; - avbuf->plane_info[i].mm_addr = mmap(NULL, avbuf->buf.m.planes[i].length, - PROT_READ | PROT_WRITE, MAP_SHARED, - buf_to_m2mctx(avbuf)->fd, avbuf->buf.m.planes[i].m.mem_offset); + -+ if ((V4L2_TYPE_IS_OUTPUT(ctx->type) && buf_to_m2mctx(avbuf)->output_drm) || -+ !buf_to_m2mctx(avbuf)->output_drm) { ++ if (want_mmap) + avbuf->plane_info[i].mm_addr = mmap(NULL, avbuf->buf.m.planes[i].length, + PROT_READ | PROT_WRITE, MAP_SHARED, + buf_to_m2mctx(avbuf)->fd, avbuf->buf.m.planes[i].m.mem_offset); -+ } } else { avbuf->plane_info[i].length = avbuf->buf.length; - avbuf->plane_info[i].mm_addr = mmap(NULL, avbuf->buf.length, - PROT_READ | PROT_WRITE, MAP_SHARED, - buf_to_m2mctx(avbuf)->fd, avbuf->buf.m.offset); + -+ if ((V4L2_TYPE_IS_OUTPUT(ctx->type) && buf_to_m2mctx(avbuf)->output_drm) || -+ !buf_to_m2mctx(avbuf)->output_drm) { ++ if (want_mmap) + avbuf->plane_info[i].mm_addr = mmap(NULL, avbuf->buf.length, + PROT_READ | PROT_WRITE, MAP_SHARED, + buf_to_m2mctx(avbuf)->fd, avbuf->buf.m.offset); -+ } } - + - if (avbuf->plane_info[i].mm_addr == MAP_FAILED) - return AVERROR(ENOMEM); + if (avbuf->plane_info[i].mm_addr == MAP_FAILED) { @@ -46990,19 +50823,19 @@ Upstream-status: Pending + goto fail; + } } - + avbuf->status = V4L2BUF_AVAILABLE; - + - if (V4L2_TYPE_IS_OUTPUT(ctx->type)) - return 0; - if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) { avbuf->buf.m.planes = avbuf->planes; avbuf->buf.length = avbuf->num_planes; -@@ -555,7 +906,20 @@ int ff_v4l2_buffer_initialize(V4L2Buffer +@@ -555,20 +972,51 @@ int ff_v4l2_buffer_initialize(V4L2Buffer avbuf->buf.length = avbuf->planes[0].length; } - + - return ff_v4l2_buffer_enqueue(avbuf); + if (!V4L2_TYPE_IS_OUTPUT(ctx->type)) { + if (buf_to_m2mctx(avbuf)->output_drm) { @@ -47019,19 +50852,20 @@ Upstream-status: Pending + av_buffer_unref(&bufref); + return ret; } - + int ff_v4l2_buffer_enqueue(V4L2Buffer* avbuf) -@@ -564,9 +928,27 @@ int ff_v4l2_buffer_enqueue(V4L2Buffer* a - - avbuf->buf.flags = avbuf->flags; - + { + int ret; ++ int qc; + +- avbuf->buf.flags = avbuf->flags; + if (avbuf->buf.timestamp.tv_sec || avbuf->buf.timestamp.tv_usec) { + av_log(logger(avbuf), AV_LOG_DEBUG, "--- %s pre VIDIOC_QBUF: index %d, ts=%ld.%06ld count=%d\n", + avbuf->context->name, avbuf->buf.index, + avbuf->buf.timestamp.tv_sec, avbuf->buf.timestamp.tv_usec, + avbuf->context->q_count); + } -+ + ret = ioctl(buf_to_m2mctx(avbuf)->fd, VIDIOC_QBUF, &avbuf->buf); - if (ret < 0) - return AVERROR(errno); @@ -47042,31 +50876,34 @@ Upstream-status: Pending + err, strerror(err)); + return AVERROR(err); + } + ++ // Lock not wanted - if called from buffer free then lock already obtained ++ qc = atomic_fetch_add(&avbuf->context->q_count, 1) + 1; + avbuf->status = V4L2BUF_IN_DRIVER; ++ pthread_cond_broadcast(&avbuf->context->cond); + -+ ++avbuf->context->q_count; + av_log(logger(avbuf), AV_LOG_DEBUG, "--- %s VIDIOC_QBUF: index %d, ts=%ld.%06ld count=%d\n", + avbuf->context->name, avbuf->buf.index, -+ avbuf->buf.timestamp.tv_sec, avbuf->buf.timestamp.tv_usec, -+ avbuf->context->q_count); - - avbuf->status = V4L2BUF_IN_DRIVER; - ++ avbuf->buf.timestamp.tv_sec, avbuf->buf.timestamp.tv_usec, qc); + + return 0; + } --- a/libavcodec/v4l2_buffers.h +++ b/libavcodec/v4l2_buffers.h -@@ -27,25 +27,34 @@ +@@ -27,25 +27,38 @@ #include <stdatomic.h> #include <linux/videodev2.h> - + +#include "libavutil/hwcontext_drm.h" #include "avcodec.h" - + enum V4L2Buffer_status { V4L2BUF_AVAILABLE, V4L2BUF_IN_DRIVER, + V4L2BUF_IN_USE, V4L2BUF_RET_USER, }; - + /** * V4L2Buffer (wrapper for v4l2_buffer management) */ @@ -47083,49 +50920,70 @@ Upstream-status: Pending + */ struct V4L2Context *context; + struct ff_weak_link_client *context_wl; - + - /* This object is refcounted per-plane, so we need to keep track - * of how many context-refs we are holding. */ - AVBufferRef *context_ref; - atomic_uint context_refcount; + /* DRM descriptor */ + AVDRMFrameDescriptor drm_frame; - ++ /* For DRM_PRIME encode - need to keep a ref to the source buffer till we ++ * are done ++ */ ++ AVBufferRef * ref_buf; + /* keep track of the mmap address and mmap length */ struct V4L2Plane_info { -@@ -70,11 +79,12 @@ typedef struct V4L2Buffer { - * - * @param[in] frame The AVFRame to push the information to - * @param[in] buf The V4L2Buffer to get the information from -+ * @param[in] no_rescale_pts If non-zero do not rescale PTS - * - * @returns 0 in case of success, AVERROR(EINVAL) if the number of planes is incorrect, - * AVERROR(ENOMEM) if the AVBufferRef can't be created. - */ --int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *buf); -+int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *buf, int no_rescale_pts); - - /** - * Extracts the data from a V4L2Buffer to an AVPacket -@@ -98,6 +108,9 @@ int ff_v4l2_buffer_buf_to_avpkt(AVPacket +@@ -60,7 +73,6 @@ typedef struct V4L2Buffer { + struct v4l2_buffer buf; + struct v4l2_plane planes[VIDEO_MAX_PLANES]; + +- int flags; + enum V4L2Buffer_status status; + + } V4L2Buffer; +@@ -98,6 +110,10 @@ int ff_v4l2_buffer_buf_to_avpkt(AVPacket */ int ff_v4l2_buffer_avpkt_to_buf(const AVPacket *pkt, V4L2Buffer *out); - -+int ff_v4l2_buffer_avpkt_to_buf_ext(const AVPacket *pkt, V4L2Buffer *out, -+ const void *extdata, size_t extlen, int no_rescale_pts); + ++int ff_v4l2_buffer_avpkt_to_buf_ext(const AVPacket * const pkt, V4L2Buffer * const out, ++ const void *extdata, size_t extlen, ++ const int64_t timestamp); + /** * Extracts the data from an AVFrame to a V4L2Buffer * -@@ -116,7 +129,7 @@ int ff_v4l2_buffer_avframe_to_buf(const +@@ -106,7 +122,7 @@ int ff_v4l2_buffer_avpkt_to_buf(const AV + * + * @returns 0 in case of success, a negative AVERROR code otherwise + */ +-int ff_v4l2_buffer_avframe_to_buf(const AVFrame *frame, V4L2Buffer *out); ++int ff_v4l2_buffer_avframe_to_buf(const AVFrame *frame, V4L2Buffer *out, const int64_t track_ts); + + /** + * Initializes a V4L2Buffer +@@ -116,7 +132,7 @@ int ff_v4l2_buffer_avframe_to_buf(const * * @returns 0 in case of success, a negative AVERROR code otherwise */ -int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index); -+int ff_v4l2_buffer_initialize(AVBufferRef **avbuf, int index, struct V4L2Context *ctx); - ++int ff_v4l2_buffer_initialize(AVBufferRef **avbuf, int index, struct V4L2Context *ctx, enum v4l2_memory mem); + /** * Enqueues a V4L2Buffer +@@ -127,5 +143,12 @@ int ff_v4l2_buffer_initialize(V4L2Buffer + */ + int ff_v4l2_buffer_enqueue(V4L2Buffer* avbuf); + ++static inline void ++ff_v4l2_buffer_set_avail(V4L2Buffer* const avbuf) ++{ ++ avbuf->status = V4L2BUF_AVAILABLE; ++ av_buffer_unref(&avbuf->ref_buf); ++} ++ + + #endif // AVCODEC_V4L2_BUFFERS_H --- a/libavcodec/v4l2_context.c +++ b/libavcodec/v4l2_context.c @@ -27,11 +27,13 @@ @@ -47139,41 +50997,233 @@ Upstream-status: Pending #include "v4l2_fmt.h" #include "v4l2_m2m.h" +#include "weak_link.h" - + struct v4l2_format_update { uint32_t v4l2_fmt; -@@ -53,16 +55,6 @@ static inline AVCodecContext *logger(V4L - return ctx_to_m2mctx(ctx)->avctx; +@@ -41,26 +43,168 @@ struct v4l2_format_update { + int update_avfmt; + }; + +-static inline V4L2m2mContext *ctx_to_m2mctx(V4L2Context *ctx) ++ ++static inline int64_t track_to_pts(AVCodecContext *avctx, unsigned int n) + { +- return V4L2_TYPE_IS_OUTPUT(ctx->type) ? +- container_of(ctx, V4L2m2mContext, output) : +- container_of(ctx, V4L2m2mContext, capture); ++ return (int64_t)n; } - + +-static inline AVCodecContext *logger(V4L2Context *ctx) ++static inline unsigned int pts_to_track(AVCodecContext *avctx, const int64_t pts) + { +- return ctx_to_m2mctx(ctx)->avctx; ++ return (unsigned int)pts; + } + -static inline unsigned int v4l2_get_width(struct v4l2_format *fmt) --{ ++// FFmpeg requires us to propagate a number of vars from the coded pkt into ++// the decoded frame. The only thing that tracks like that in V4L2 stateful ++// is timestamp. PTS maps to timestamp for this decode. FFmpeg makes no ++// guarantees about PTS being unique or specified for every frame so replace ++// the supplied PTS with a simple incrementing number and keep a circular ++// buffer of all the things we want preserved (including the original PTS) ++// indexed by the tracking no. ++static int64_t ++xlat_pts_pkt_in(AVCodecContext *const avctx, xlat_track_t *const x, const AVPacket *const avpkt) + { - return V4L2_TYPE_IS_MULTIPLANAR(fmt->type) ? fmt->fmt.pix_mp.width : fmt->fmt.pix.width; --} -- ++ int64_t track_pts; ++ ++ // Avoid 0 ++ if (++x->track_no == 0) ++ x->track_no = 1; ++ ++ track_pts = track_to_pts(avctx, x->track_no); ++ ++ av_log(avctx, AV_LOG_TRACE, "In pkt PTS=%" PRId64 ", DTS=%" PRId64 ", track=%" PRId64 ", n=%u\n", avpkt->pts, avpkt->dts, track_pts, x->track_no); ++ x->track_els[x->track_no % FF_V4L2_M2M_TRACK_SIZE] = (V4L2m2mTrackEl){ ++ .discard = 0, ++ .pending = 1, ++ .pkt_size = avpkt->size, ++ .pts = avpkt->pts, ++ .dts = avpkt->dts, ++ .reordered_opaque = avctx->reordered_opaque, ++ .pkt_pos = avpkt->pos, ++ .pkt_duration = avpkt->duration, ++ .track_pts = track_pts ++ }; ++ return track_pts; + } + -static inline unsigned int v4l2_get_height(struct v4l2_format *fmt) --{ ++static int64_t ++xlat_pts_frame_in(AVCodecContext *const avctx, xlat_track_t *const x, const AVFrame *const frame) + { - return V4L2_TYPE_IS_MULTIPLANAR(fmt->type) ? fmt->fmt.pix_mp.height : fmt->fmt.pix.height; --} -- ++ int64_t track_pts; ++ ++ // Avoid 0 ++ if (++x->track_no == 0) ++ x->track_no = 1; ++ ++ track_pts = track_to_pts(avctx, x->track_no); ++ ++ av_log(avctx, AV_LOG_TRACE, "In frame PTS=%" PRId64 ", track=%" PRId64 ", n=%u\n", frame->pts, track_pts, x->track_no); ++ x->track_els[x->track_no % FF_V4L2_M2M_TRACK_SIZE] = (V4L2m2mTrackEl){ ++ .discard = 0, ++ .pending = 1, ++ .pkt_size = 0, ++ .pts = frame->pts, ++ .dts = AV_NOPTS_VALUE, ++ .reordered_opaque = frame->reordered_opaque, ++ .pkt_pos = frame->pkt_pos, ++ .pkt_duration = frame->pkt_duration, ++ .track_pts = track_pts ++ }; ++ return track_pts; ++} ++ ++ ++// Returns -1 if we should discard the frame ++static int ++xlat_pts_frame_out(AVCodecContext *const avctx, ++ xlat_track_t * const x, ++ AVFrame *const frame) ++{ ++ unsigned int n = pts_to_track(avctx, frame->pts) % FF_V4L2_M2M_TRACK_SIZE; ++ V4L2m2mTrackEl *const t = x->track_els + n; ++ if (frame->pts == AV_NOPTS_VALUE || frame->pts != t->track_pts) ++ { ++ av_log(avctx, frame->pts == AV_NOPTS_VALUE ? AV_LOG_DEBUG : AV_LOG_WARNING, ++ "Frame tracking failure: pts=%" PRId64 ", track[%d]=%" PRId64 "\n", frame->pts, n, t->track_pts); ++ frame->pts = AV_NOPTS_VALUE; ++ frame->pkt_dts = AV_NOPTS_VALUE; ++ frame->reordered_opaque = x->last_opaque; ++ frame->pkt_pos = -1; ++ frame->pkt_duration = 0; ++ frame->pkt_size = -1; ++ } ++ else if (!t->discard) ++ { ++ frame->pts = t->pending ? t->pts : AV_NOPTS_VALUE; ++ frame->pkt_dts = t->dts; ++ frame->reordered_opaque = t->reordered_opaque; ++ frame->pkt_pos = t->pkt_pos; ++ frame->pkt_duration = t->pkt_duration; ++ frame->pkt_size = t->pkt_size; ++ ++ x->last_opaque = x->track_els[n].reordered_opaque; ++ if (frame->pts != AV_NOPTS_VALUE) ++ x->last_pts = frame->pts; ++ t->pending = 0; ++ } ++ else ++ { ++ av_log(avctx, AV_LOG_DEBUG, "Discard frame (flushed): pts=%" PRId64 ", track[%d]=%" PRId64 "\n", frame->pts, n, t->track_pts); ++ return -1; ++ } ++ ++ av_log(avctx, AV_LOG_TRACE, "Out frame PTS=%" PRId64 "/%"PRId64", DTS=%" PRId64 ", track=%"PRId64", n=%d\n", ++ frame->pts, frame->best_effort_timestamp, frame->pkt_dts, t->track_pts, n); ++ return 0; ++} ++ ++// Returns -1 if we should discard the frame ++static int ++xlat_pts_pkt_out(AVCodecContext *const avctx, ++ xlat_track_t * const x, ++ AVPacket *const pkt) ++{ ++ unsigned int n = pts_to_track(avctx, pkt->pts) % FF_V4L2_M2M_TRACK_SIZE; ++ V4L2m2mTrackEl *const t = x->track_els + n; ++ if (pkt->pts == AV_NOPTS_VALUE || pkt->pts != t->track_pts) ++ { ++ av_log(avctx, pkt->pts == AV_NOPTS_VALUE ? AV_LOG_DEBUG : AV_LOG_WARNING, ++ "Pkt tracking failure: pts=%" PRId64 ", track[%d]=%" PRId64 "\n", pkt->pts, n, t->track_pts); ++ pkt->pts = AV_NOPTS_VALUE; ++ } ++ else if (!t->discard) ++ { ++ pkt->pts = t->pending ? t->pts : AV_NOPTS_VALUE; ++ ++ x->last_opaque = x->track_els[n].reordered_opaque; ++ if (pkt->pts != AV_NOPTS_VALUE) ++ x->last_pts = pkt->pts; ++ t->pending = 0; ++ } ++ else ++ { ++ av_log(avctx, AV_LOG_DEBUG, "Discard packet (flushed): pts=%" PRId64 ", track[%d]=%" PRId64 "\n", pkt->pts, n, t->track_pts); ++ return -1; ++ } ++ ++ // * Would like something much better than this...xlat(offset + out_count)? ++ pkt->dts = pkt->pts; ++ av_log(avctx, AV_LOG_TRACE, "Out pkt PTS=%" PRId64 ", track=%"PRId64", n=%d\n", ++ pkt->pts, t->track_pts, n); ++ return 0; ++} ++ ++ ++static inline V4L2m2mContext *ctx_to_m2mctx(const V4L2Context *ctx) ++{ ++ return V4L2_TYPE_IS_OUTPUT(ctx->type) ? ++ container_of(ctx, V4L2m2mContext, output) : ++ container_of(ctx, V4L2m2mContext, capture); ++} ++ ++static inline AVCodecContext *logger(const V4L2Context *ctx) ++{ ++ return ctx_to_m2mctx(ctx)->avctx; + } + static AVRational v4l2_get_sar(V4L2Context *ctx) +@@ -81,21 +225,29 @@ static AVRational v4l2_get_sar(V4L2Conte + return sar; + } + +-static inline unsigned int v4l2_resolution_changed(V4L2Context *ctx, struct v4l2_format *fmt2) ++static inline int ctx_buffers_alloced(const V4L2Context * const ctx) ++{ ++ return ctx->bufrefs != NULL; ++} ++ ++// Width/Height changed or we don't have an alloc in the first place? ++static int ctx_resolution_changed(const V4L2Context *ctx, const struct v4l2_format *fmt2) { - struct AVRational sar = { 0, 1 }; -@@ -94,8 +86,8 @@ static inline unsigned int v4l2_resoluti +- struct v4l2_format *fmt1 = &ctx->format; +- int ret = V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? +- fmt1->fmt.pix_mp.width != fmt2->fmt.pix_mp.width || +- fmt1->fmt.pix_mp.height != fmt2->fmt.pix_mp.height +- : +- fmt1->fmt.pix.width != fmt2->fmt.pix.width || +- fmt1->fmt.pix.height != fmt2->fmt.pix.height; ++ const struct v4l2_format *fmt1 = &ctx->format; ++ int ret = !ctx_buffers_alloced(ctx) || ++ (V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? ++ fmt1->fmt.pix_mp.width != fmt2->fmt.pix_mp.width || ++ fmt1->fmt.pix_mp.height != fmt2->fmt.pix_mp.height ++ : ++ fmt1->fmt.pix.width != fmt2->fmt.pix.width || ++ fmt1->fmt.pix.height != fmt2->fmt.pix.height); + if (ret) - av_log(logger(ctx), AV_LOG_DEBUG, "%s changed (%dx%d) -> (%dx%d)\n", +- av_log(logger(ctx), AV_LOG_DEBUG, "%s changed (%dx%d) -> (%dx%d)\n", ++ av_log(logger(ctx), AV_LOG_DEBUG, "V4L2 %s changed: alloc=%d (%dx%d) -> (%dx%d)\n", ctx->name, - v4l2_get_width(fmt1), v4l2_get_height(fmt1), - v4l2_get_width(fmt2), v4l2_get_height(fmt2)); ++ ctx_buffers_alloced(ctx), + ff_v4l2_get_format_width(fmt1), ff_v4l2_get_format_height(fmt1), + ff_v4l2_get_format_width(fmt2), ff_v4l2_get_format_height(fmt2)); - + return ret; } -@@ -153,58 +145,67 @@ static inline void v4l2_save_to_context( +@@ -153,90 +305,110 @@ static inline void v4l2_save_to_context( } } - + -/** - * handle resolution change event and end of stream event - * returns 1 if reinit was successful, negative if it failed @@ -47192,7 +51242,7 @@ Upstream-status: Pending + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .target = V4L2_SEL_TGT_COMPOSE + }; - + - ret = ioctl(s->fd, VIDIOC_DQEVENT, &evt); - if (ret < 0) { - av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_DQEVENT\n", ctx->name); @@ -47201,7 +51251,7 @@ Upstream-status: Pending + memset(r, 0, sizeof(*r)); + if (ioctl(s->fd, VIDIOC_G_SELECTION, &selection)) + return AVERROR(errno); - + - if (evt.type == V4L2_EVENT_EOS) { - ctx->done = 1; - return 0; @@ -47209,49 +51259,45 @@ Upstream-status: Pending + *r = selection.r; + return 0; +} - + - if (evt.type != V4L2_EVENT_SOURCE_CHANGE) - return 0; +static int do_source_change(V4L2m2mContext * const s) +{ + AVCodecContext *const avctx = s->avctx; -+ + +- ret = ioctl(s->fd, VIDIOC_G_FMT, &out_fmt); +- if (ret) { +- av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_G_FMT\n", s->output.name); +- return 0; +- } + int ret; + int reinit; -+ int full_reinit; + struct v4l2_format cap_fmt = s->capture.format; -+ struct v4l2_format out_fmt = s->output.format; + -+ s->resize_pending = 0; + s->capture.done = 0; - - ret = ioctl(s->fd, VIDIOC_G_FMT, &out_fmt); - if (ret) { -- av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_G_FMT\n", s->output.name); -+ av_log(avctx, AV_LOG_ERROR, "%s VIDIOC_G_FMT failed\n", s->output.name); - return 0; - } - + ret = ioctl(s->fd, VIDIOC_G_FMT, &cap_fmt); if (ret) { - av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_G_FMT\n", s->capture.name); + av_log(avctx, AV_LOG_ERROR, "%s VIDIOC_G_FMT failed\n", s->capture.name); return 0; } - - full_reinit = v4l2_resolution_changed(&s->output, &out_fmt); - if (full_reinit) { + +- full_reinit = v4l2_resolution_changed(&s->output, &out_fmt); +- if (full_reinit) { - s->output.height = v4l2_get_height(&out_fmt); - s->output.width = v4l2_get_width(&out_fmt); - s->output.sample_aspect_ratio = v4l2_get_sar(&s->output); -+ s->output.height = ff_v4l2_get_format_height(&out_fmt); -+ s->output.width = ff_v4l2_get_format_width(&out_fmt); - } -+ s->output.sample_aspect_ratio = v4l2_get_sar(&s->output); -+ +- } + get_default_selection(&s->capture, &s->capture.selection); - - reinit = v4l2_resolution_changed(&s->capture, &cap_fmt); ++ ++ reinit = ctx_resolution_changed(&s->capture, &cap_fmt); ++ if ((s->quirks & FF_V4L2_QUIRK_REINIT_ALWAYS) != 0) ++ reinit = 1; + +- reinit = v4l2_resolution_changed(&s->capture, &cap_fmt); ++ s->capture.format = cap_fmt; if (reinit) { - s->capture.height = v4l2_get_height(&cap_fmt); - s->capture.width = v4l2_get_width(&cap_fmt); @@ -47259,368 +51305,491 @@ Upstream-status: Pending + s->capture.height = ff_v4l2_get_format_height(&cap_fmt); + s->capture.width = ff_v4l2_get_format_width(&cap_fmt); } + +- if (full_reinit || reinit) +- s->reinit = 1; +- +- if (full_reinit) { +- ret = ff_v4l2_m2m_codec_full_reinit(s); +- if (ret) { +- av_log(logger(ctx), AV_LOG_ERROR, "v4l2_m2m_codec_full_reinit\n"); +- return AVERROR(EINVAL); +- } +- goto reinit_run; ++ // If we don't support selection (or it is bust) and we obviously have HD then kludge ++ if ((s->capture.selection.width == 0 || s->capture.selection.height == 0) && ++ (s->capture.height == 1088 && s->capture.width == 1920)) { ++ s->capture.selection = (struct v4l2_rect){.width = 1920, .height = 1080}; + } + + s->capture.sample_aspect_ratio = v4l2_get_sar(&s->capture); + -+ av_log(avctx, AV_LOG_DEBUG, "Source change: SAR: %d/%d, crop %dx%d @ %d,%d\n", ++ av_log(avctx, AV_LOG_DEBUG, "Source change: SAR: %d/%d, wxh %dx%d crop %dx%d @ %d,%d, reinit=%d\n", + s->capture.sample_aspect_ratio.num, s->capture.sample_aspect_ratio.den, ++ s->capture.width, s->capture.height, + s->capture.selection.width, s->capture.selection.height, -+ s->capture.selection.left, s->capture.selection.top); - - if (full_reinit || reinit) - s->reinit = 1; -@@ -212,34 +213,88 @@ static int v4l2_handle_event(V4L2Context - if (full_reinit) { - ret = ff_v4l2_m2m_codec_full_reinit(s); - if (ret) { -- av_log(logger(ctx), AV_LOG_ERROR, "v4l2_m2m_codec_full_reinit\n"); -+ av_log(avctx, AV_LOG_ERROR, "v4l2_m2m_codec_full_reinit failed\n"); - return AVERROR(EINVAL); - } - goto reinit_run; - } - ++ s->capture.selection.left, s->capture.selection.top, reinit); ++ if (reinit) { - if (s->avctx) +- ret = ff_set_dimensions(s->avctx, s->capture.width, s->capture.height); + if (avctx) - ret = ff_set_dimensions(s->avctx, s->capture.width, s->capture.height); ++ ret = ff_set_dimensions(s->avctx, ++ s->capture.selection.width != 0 ? s->capture.selection.width : s->capture.width, ++ s->capture.selection.height != 0 ? s->capture.selection.height : s->capture.height); if (ret < 0) - av_log(logger(ctx), AV_LOG_WARNING, "update avcodec height and width\n"); + av_log(avctx, AV_LOG_WARNING, "update avcodec height and width failed\n"); - + ret = ff_v4l2_m2m_codec_reinit(s); if (ret) { - av_log(logger(ctx), AV_LOG_ERROR, "v4l2_m2m_codec_reinit\n"); + av_log(avctx, AV_LOG_ERROR, "v4l2_m2m_codec_reinit failed\n"); return AVERROR(EINVAL); } ++ ++ if (s->capture.width > ff_v4l2_get_format_width(&s->capture.format) || ++ s->capture.height > ff_v4l2_get_format_height(&s->capture.format)) { ++ av_log(avctx, AV_LOG_ERROR, "Format post reinit too small: wanted %dx%d > got %dx%d\n", ++ s->capture.width, s->capture.height, ++ ff_v4l2_get_format_width(&s->capture.format), ff_v4l2_get_format_height(&s->capture.format)); ++ return AVERROR(EINVAL); ++ } ++ ++ // Update pixel format - should only actually do something on initial change ++ s->capture.av_pix_fmt = ++ ff_v4l2_format_v4l2_to_avfmt(ff_v4l2_get_format_pixelformat(&s->capture.format), AV_CODEC_ID_RAWVIDEO); ++ if (s->output_drm) { ++ avctx->pix_fmt = AV_PIX_FMT_DRM_PRIME; ++ avctx->sw_pix_fmt = s->capture.av_pix_fmt; ++ } ++ else ++ avctx->pix_fmt = s->capture.av_pix_fmt; ++ goto reinit_run; } - + - /* dummy event received */ - return 0; + /* Buffers are OK so just stream off to ack */ -+ av_log(avctx, AV_LOG_DEBUG, "%s: Parameters only\n", __func__); ++ av_log(avctx, AV_LOG_DEBUG, "%s: Parameters only - restart decode\n", __func__); + + ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF); + if (ret) + av_log(avctx, AV_LOG_ERROR, "capture VIDIOC_STREAMOFF failed\n"); + s->draining = 0; - + /* reinit executed */ reinit_run: + ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMON); return 1; } - -+static int ctx_done(V4L2Context * const ctx) -+{ -+ int rv = 0; -+ V4L2m2mContext * const s = ctx_to_m2mctx(ctx); -+ -+ ctx->done = 1; -+ -+ if (s->resize_pending && !V4L2_TYPE_IS_OUTPUT(ctx->type)) -+ rv = do_source_change(s); -+ -+ return rv; -+} -+ -+/** -+ * handle resolution change event and end of stream event -+ * returns 1 if reinit was successful, negative if it failed -+ * returns 0 if reinit was not executed -+ */ -+static int v4l2_handle_event(V4L2Context *ctx) -+{ -+ V4L2m2mContext * const s = ctx_to_m2mctx(ctx); -+ struct v4l2_event evt = { 0 }; -+ int ret; -+ -+ ret = ioctl(s->fd, VIDIOC_DQEVENT, &evt); -+ if (ret < 0) { -+ av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_DQEVENT\n", ctx->name); -+ return 0; -+ } -+ -+ av_log(logger(ctx), AV_LOG_INFO, "Dq event %d\n", evt.type); -+ -+ if (evt.type == V4L2_EVENT_EOS) { -+// ctx->done = 1; -+ av_log(logger(ctx), AV_LOG_TRACE, "%s VIDIOC_EVENT_EOS\n", ctx->name); -+ return 0; -+ } -+ -+ if (evt.type != V4L2_EVENT_SOURCE_CHANGE) -+ return 0; -+ -+ s->resize_pending = 1; -+ if (!ctx->done) -+ return 0; -+ -+ return do_source_change(s); -+} -+ - static int v4l2_stop_decode(V4L2Context *ctx) - { - struct v4l2_decoder_cmd cmd = { -@@ -280,8 +335,26 @@ static int v4l2_stop_encode(V4L2Context + +@@ -280,171 +452,277 @@ static int v4l2_stop_encode(V4L2Context return 0; } - -+static int count_in_driver(const V4L2Context * const ctx) -+{ -+ int i; -+ int n = 0; + +-static V4L2Buffer* v4l2_dequeue_v4l2buf(V4L2Context *ctx, int timeout) +-{ +- struct v4l2_plane planes[VIDEO_MAX_PLANES]; +- struct v4l2_buffer buf = { 0 }; +- V4L2Buffer *avbuf; +- struct pollfd pfd = { +- .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM, /* default blocking capture */ +- .fd = ctx_to_m2mctx(ctx)->fd, ++// DQ a buffer ++// Amalgamates all the various ways there are of signalling EOS/Event to ++// generate a consistant EPIPE. ++// ++// Sets ctx->flag_last if next dq would produce EPIPE (i.e. stream has stopped) ++// ++// Returns: ++// 0 Success ++// AVERROR(EPIPE) Nothing more to read ++// AVERROR(ENOSPC) No buffers in Q to put result in ++// * AVERROR(..) + -+ if (!ctx->bufrefs) -+ return -1; ++ static int ++dq_buf(V4L2Context * const ctx, V4L2Buffer ** const ppavbuf) ++{ ++ V4L2m2mContext * const m = ctx_to_m2mctx(ctx); ++ AVCodecContext * const avctx = m->avctx; ++ V4L2Buffer * avbuf; ++ const int is_mp = V4L2_TYPE_IS_MULTIPLANAR(ctx->type); + -+ for (i = 0; i < ctx->num_buffers; ++i) { -+ V4L2Buffer *const avbuf = (V4L2Buffer *)ctx->bufrefs[i]->data; -+ if (avbuf->status == V4L2BUF_IN_DRIVER) -+ ++n; -+ } -+ return n; -+} ++ struct v4l2_plane planes[VIDEO_MAX_PLANES] = {{0}}; + - static V4L2Buffer* v4l2_dequeue_v4l2buf(V4L2Context *ctx, int timeout) - { -+ V4L2m2mContext * const s = ctx_to_m2mctx(ctx); -+ const int is_capture = !V4L2_TYPE_IS_OUTPUT(ctx->type); - struct v4l2_plane planes[VIDEO_MAX_PLANES]; - struct v4l2_buffer buf = { 0 }; - V4L2Buffer *avbuf; -@@ -290,50 +363,84 @@ static V4L2Buffer* v4l2_dequeue_v4l2buf( - .fd = ctx_to_m2mctx(ctx)->fd, ++ struct v4l2_buffer buf = { ++ .type = ctx->type, ++ .memory = V4L2_MEMORY_MMAP, }; - int i, ret; -+ int no_rx_means_done = 0; - +- int i, ret; + - if (!V4L2_TYPE_IS_OUTPUT(ctx->type) && ctx->buffers) { -+ if (is_capture && ctx->bufrefs) { - for (i = 0; i < ctx->num_buffers; i++) { +- for (i = 0; i < ctx->num_buffers; i++) { - if (ctx->buffers[i].status == V4L2BUF_IN_DRIVER) -+ avbuf = (V4L2Buffer *)ctx->bufrefs[i]->data; -+ if (avbuf->status == V4L2BUF_IN_DRIVER) - break; - } - if (i == ctx->num_buffers) +- break; +- } +- if (i == ctx->num_buffers) - av_log(logger(ctx), AV_LOG_WARNING, "All capture buffers returned to " -+ av_log(logger(ctx), AV_LOG_WARNING, "All capture buffers (%d) returned to " - "userspace. Increase num_capture_buffers " - "to prevent device deadlock or dropped " +- "userspace. Increase num_capture_buffers " +- "to prevent device deadlock or dropped " - "packets/frames.\n"); -+ "packets/frames.\n", i); - } - -+#if 0 -+ // I think this is true but pointless -+ // we will get some other form of EOF signal -+ - /* if we are draining and there are no more capture buffers queued in the driver we are done */ +- } +- +- /* if we are draining and there are no more capture buffers queued in the driver we are done */ - if (!V4L2_TYPE_IS_OUTPUT(ctx->type) && ctx_to_m2mctx(ctx)->draining) { -+ if (is_capture && ctx_to_m2mctx(ctx)->draining) { - for (i = 0; i < ctx->num_buffers; i++) { - /* capture buffer initialization happens during decode hence - * detection happens at runtime - */ +- for (i = 0; i < ctx->num_buffers; i++) { +- /* capture buffer initialization happens during decode hence +- * detection happens at runtime +- */ - if (!ctx->buffers) -+ if (!ctx->bufrefs) - break; - +- break; +- - if (ctx->buffers[i].status == V4L2BUF_IN_DRIVER) -+ avbuf = (V4L2Buffer *)ctx->bufrefs[i]->data; -+ if (avbuf->status == V4L2BUF_IN_DRIVER) - goto start; - } - ctx->done = 1; - return NULL; - } -+#endif - - start: +- goto start; +- } +- ctx->done = 1; +- return NULL; +- } +- +-start: - if (V4L2_TYPE_IS_OUTPUT(ctx->type)) - pfd.events = POLLOUT | POLLWRNORM; - else { -+ if (is_capture) { - /* no need to listen to requests for more input while draining */ - if (ctx_to_m2mctx(ctx)->draining) - pfd.events = POLLIN | POLLRDNORM | POLLPRI; -+ } else { -+ pfd.events = POLLOUT | POLLWRNORM; - } -+ no_rx_means_done = s->resize_pending && is_capture; - - for (;;) { -- ret = poll(&pfd, 1, timeout); -+ // If we have a resize pending then all buffers should be Qed -+ // With a resize pending we should be in drain but evidence suggests -+ // that not all decoders do this so poll to clear -+ int t2 = no_rx_means_done ? 0 : timeout < 0 ? 3000 : timeout; -+ const int e = pfd.events; +- /* no need to listen to requests for more input while draining */ +- if (ctx_to_m2mctx(ctx)->draining) +- pfd.events = POLLIN | POLLRDNORM | POLLPRI; ++ *ppavbuf = NULL; + -+ ret = poll(&pfd, 1, t2); ++ if (ctx->flag_last) ++ return AVERROR(EPIPE); + - if (ret > 0) - break; ++ if (is_mp) { ++ buf.length = VIDEO_MAX_PLANES; ++ buf.m.planes = planes; + } + +- for (;;) { +- ret = poll(&pfd, 1, timeout); +- if (ret > 0) +- break; - if (errno == EINTR) - continue; +- return NULL; ++ while (ioctl(m->fd, VIDIOC_DQBUF, &buf) != 0) { ++ const int err = errno; ++ av_assert0(AVERROR(err) < 0); ++ if (err != EINTR) { ++ av_log(avctx, AV_LOG_DEBUG, "%s VIDIOC_DQBUF, errno (%s)\n", ++ ctx->name, av_err2str(AVERROR(err))); + -+ if (ret < 0) { -+ int err = errno; -+ if (err == EINTR) -+ continue; -+ av_log(logger(ctx), AV_LOG_ERROR, "=== poll error %d (%s): events=%#x, cap buffers=%d\n", -+ err, strerror(err), -+ e, count_in_driver(ctx)); -+ return NULL; -+ } ++ if (err == EPIPE) ++ ctx->flag_last = 1; + -+ // ret == 0 (timeout) -+ if (no_rx_means_done) { -+ av_log(logger(ctx), AV_LOG_DEBUG, "Ctx done on timeout\n"); -+ ret = ctx_done(ctx); -+ if (ret > 0) -+ goto start; ++ return AVERROR(err); + } -+ if (timeout == -1) -+ av_log(logger(ctx), AV_LOG_ERROR, "=== poll unexpected TIMEOUT: events=%#x, cap buffers=%d\n", e, count_in_driver(ctx));; - return NULL; } - -@@ -343,7 +450,8 @@ start: - no need to raise a warning */ - if (timeout == 0) { - for (i = 0; i < ctx->num_buffers; i++) { ++ atomic_fetch_sub(&ctx->q_count, 1); + +- /* 0. handle errors */ +- if (pfd.revents & POLLERR) { +- /* if we are trying to get free buffers but none have been queued yet +- no need to raise a warning */ +- if (timeout == 0) { +- for (i = 0; i < ctx->num_buffers; i++) { - if (ctx->buffers[i].status != V4L2BUF_AVAILABLE) -+ avbuf = (V4L2Buffer *)ctx->bufrefs[i]->data; -+ if (avbuf->status != V4L2BUF_AVAILABLE) - av_log(logger(ctx), AV_LOG_WARNING, "%s POLLERR\n", ctx->name); - } - } -@@ -361,22 +469,25 @@ start: - ctx->done = 1; - return NULL; +- av_log(logger(ctx), AV_LOG_WARNING, "%s POLLERR\n", ctx->name); +- } ++ avbuf = (V4L2Buffer *)ctx->bufrefs[buf.index]->data; ++ ff_v4l2_buffer_set_avail(avbuf); ++ avbuf->buf = buf; ++ if (is_mp) { ++ memcpy(avbuf->planes, planes, sizeof(planes)); ++ avbuf->buf.m.planes = avbuf->planes; ++ } ++ // Done with any attached buffer ++ av_buffer_unref(&avbuf->ref_buf); ++ ++ if (V4L2_TYPE_IS_CAPTURE(ctx->type)) { ++ // Zero length cap buffer return == EOS ++ if ((is_mp ? buf.m.planes[0].bytesused : buf.bytesused) == 0) { ++ av_log(avctx, AV_LOG_DEBUG, "Buffer empty - reQ\n"); ++ ++ // Must reQ so we don't leak ++ // May not matter if the next thing we do is release all the ++ // buffers but better to be tidy. ++ ff_v4l2_buffer_enqueue(avbuf); ++ ++ ctx->flag_last = 1; ++ return AVERROR(EPIPE); } +- else +- av_log(logger(ctx), AV_LOG_WARNING, "%s POLLERR\n", ctx->name); + +- return NULL; ++#ifdef V4L2_BUF_FLAG_LAST ++ // If flag_last set then this contains data but is the last frame ++ // so remember that but return OK ++ if ((buf.flags & V4L2_BUF_FLAG_LAST) != 0) ++ ctx->flag_last = 1; ++#endif + } + +- /* 1. handle resolution changes */ +- if (pfd.revents & POLLPRI) { +- ret = v4l2_handle_event(ctx); +- if (ret < 0) { +- /* if re-init failed, abort */ +- ctx->done = 1; +- return NULL; +- } - if (ret) { - /* if re-init was successful drop the buffer (if there was one) - * since we had to reconfigure capture (unmap all buffers) - */ - return NULL; -- } -+ if (ret > 0) -+ goto start; ++ *ppavbuf = avbuf; ++ return 0; ++} ++ ++/** ++ * handle resolution change event and end of stream event ++ * Expects to be called after the stream has stopped ++ * ++ * returns 1 if reinit was successful, negative if it failed ++ * returns 0 if reinit was not executed ++ */ ++static int ++get_event(V4L2m2mContext * const m) ++{ ++ AVCodecContext * const avctx = m->avctx; ++ struct v4l2_event evt = { 0 }; ++ ++ while (ioctl(m->fd, VIDIOC_DQEVENT, &evt) != 0) { ++ const int rv = AVERROR(errno); ++ if (rv == AVERROR(EINTR)) ++ continue; ++ if (rv == AVERROR(EAGAIN)) { ++ av_log(avctx, AV_LOG_WARNING, "V4L2 failed to get expected event - assume EOS\n"); ++ return AVERROR_EOF; + } ++ av_log(avctx, AV_LOG_ERROR, "V4L2 VIDIOC_DQEVENT: %s\n", av_err2str(rv)); ++ return rv; } - - /* 2. dequeue the buffer */ - if (pfd.revents & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM)) { - + +- /* 2. dequeue the buffer */ +- if (pfd.revents & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM)) { ++ av_log(avctx, AV_LOG_DEBUG, "Dq event %d\n", evt.type); + - if (!V4L2_TYPE_IS_OUTPUT(ctx->type)) { -+ if (is_capture) { - /* there is a capture buffer ready */ - if (pfd.revents & (POLLIN | POLLRDNORM)) - goto dequeue; - -+ // CAPTURE Q drained -+ if (no_rx_means_done) { -+ if (ctx_done(ctx) > 0) -+ goto start; -+ return NULL; -+ } +- /* there is a capture buffer ready */ +- if (pfd.revents & (POLLIN | POLLRDNORM)) +- goto dequeue; ++ if (evt.type == V4L2_EVENT_EOS) { ++ av_log(avctx, AV_LOG_TRACE, "V4L2 VIDIOC_EVENT_EOS\n"); ++ return AVERROR_EOF; ++ } ++ ++ if (evt.type == V4L2_EVENT_SOURCE_CHANGE) ++ return do_source_change(m); + - /* the driver is ready to accept more input; instead of waiting for the capture - * buffer to complete we return NULL so input can proceed (we are single threaded) - */ -@@ -394,37 +505,58 @@ dequeue: - buf.m.planes = planes; ++ return 0; ++} ++ ++ ++// Get a buffer ++// If output then just gets the buffer in the expected way ++// If capture then runs the capture state m/c to deal with res change etc. ++// If return value == 0 then *ppavbuf != NULL ++ ++static int ++get_qbuf(V4L2Context * const ctx, V4L2Buffer ** const ppavbuf, const int timeout) ++{ ++ V4L2m2mContext * const m = ctx_to_m2mctx(ctx); ++ AVCodecContext * const avctx = m->avctx; ++ const int is_cap = V4L2_TYPE_IS_CAPTURE(ctx->type); ++ ++ const unsigned int poll_cap = (POLLIN | POLLRDNORM); ++ const unsigned int poll_out = (POLLOUT | POLLWRNORM); ++ const unsigned int poll_event = POLLPRI; ++ ++ *ppavbuf = NULL; + +- /* the driver is ready to accept more input; instead of waiting for the capture +- * buffer to complete we return NULL so input can proceed (we are single threaded) +- */ +- if (pfd.revents & (POLLOUT | POLLWRNORM)) +- return NULL; ++ for (;;) { ++ struct pollfd pfd = { ++ .fd = m->fd, ++ // If capture && stream not started then assume we are waiting for the initial event ++ .events = !is_cap ? poll_out : ++ !ff_v4l2_ctx_eos(ctx) && ctx->streamon ? poll_cap : ++ poll_event, ++ }; ++ int ret; ++ ++ if (ctx->done) { ++ av_log(avctx, AV_LOG_TRACE, "V4L2 %s already done\n", ctx->name); ++ return AVERROR_EOF; } - + +-dequeue: +- memset(&buf, 0, sizeof(buf)); +- buf.memory = V4L2_MEMORY_MMAP; +- buf.type = ctx->type; +- if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) { +- memset(planes, 0, sizeof(planes)); +- buf.length = VIDEO_MAX_PLANES; +- buf.m.planes = planes; ++ // If capture && timeout == -1 then also wait for rx buffer free ++ if (is_cap && timeout == -1 && m->output.streamon && !m->draining) ++ pfd.events |= poll_out; ++ ++ // If nothing Qed all we will get is POLLERR - avoid that ++ if ((pfd.events == poll_out && atomic_load(&m->output.q_count) == 0) || ++ (pfd.events == poll_cap && atomic_load(&m->capture.q_count) == 0) || ++ (pfd.events == (poll_cap | poll_out) && atomic_load(&m->capture.q_count) == 0 && atomic_load(&m->output.q_count) == 0)) { ++ av_log(avctx, AV_LOG_TRACE, "V4L2 poll %s empty\n", ctx->name); ++ return AVERROR(ENOSPC); + } + - ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_DQBUF, &buf); - if (ret) { - if (errno != EAGAIN) { - ctx->done = 1; - if (errno != EPIPE) -+ while ((ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_DQBUF, &buf)) == -1) { -+ const int err = errno; -+ if (err == EINTR) -+ continue; -+ if (err != EAGAIN) { -+ // EPIPE on CAPTURE can be used instead of BUF_FLAG_LAST -+ if (err != EPIPE || !is_capture) - av_log(logger(ctx), AV_LOG_DEBUG, "%s VIDIOC_DQBUF, errno (%s)\n", +- av_log(logger(ctx), AV_LOG_DEBUG, "%s VIDIOC_DQBUF, errno (%s)\n", - ctx->name, av_err2str(AVERROR(errno))); -+ ctx->name, av_err2str(AVERROR(err))); -+ if (ctx_done(ctx) > 0) -+ goto start; ++ // Timeout kludged s.t. "forever" eventually gives up & produces logging ++ // If waiting for an event when we have seen a last_frame then we expect ++ // it to be ready already so force a short timeout ++ ret = poll(&pfd, 1, ++ ff_v4l2_ctx_eos(ctx) ? 10 : ++ timeout == -1 ? 3000 : timeout); ++ if (ret < 0) { ++ ret = AVERROR(errno); // Remember errno before logging etc. ++ av_assert0(ret < 0); ++ } ++ ++ av_log(avctx, AV_LOG_TRACE, "V4L2 poll %s ret=%d, timeout=%d, events=%#x, revents=%#x\n", ++ ctx->name, ret, timeout, pfd.events, pfd.revents); ++ ++ if (ret < 0) { ++ if (ret == AVERROR(EINTR)) ++ continue; ++ av_log(avctx, AV_LOG_ERROR, "V4L2 %s poll error %d (%s)\n", ctx->name, AVUNERROR(ret), av_err2str(ret)); ++ return ret; ++ } ++ ++ if (ret == 0) { ++ if (timeout == -1) ++ av_log(avctx, AV_LOG_ERROR, "V4L2 %s poll unexpected timeout: events=%#x\n", ctx->name, pfd.events); ++ if (ff_v4l2_ctx_eos(ctx)) { ++ av_log(avctx, AV_LOG_WARNING, "V4L2 %s poll event timeout\n", ctx->name); ++ ret = get_event(m); ++ if (ret < 0) { ++ ctx->done = 1; ++ return ret; ++ } } - return NULL; +- return NULL; ++ return AVERROR(EAGAIN); } -+ --ctx->q_count; -+ av_log(logger(ctx), AV_LOG_DEBUG, "--- %s VIDIOC_DQBUF OK: index=%d, ts=%ld.%06ld, count=%d, dq=%d\n", -+ ctx->name, buf.index, -+ buf.timestamp.tv_sec, buf.timestamp.tv_usec, -+ ctx->q_count, ++ctx->dq_count); -+ -+ avbuf = (V4L2Buffer *)ctx->bufrefs[buf.index]->data; -+ avbuf->status = V4L2BUF_AVAILABLE; -+ avbuf->buf = buf; -+ if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) { -+ memcpy(avbuf->planes, planes, sizeof(planes)); -+ avbuf->buf.m.planes = avbuf->planes; -+ } - + - if (ctx_to_m2mctx(ctx)->draining && !V4L2_TYPE_IS_OUTPUT(ctx->type)) { -+ if (ctx_to_m2mctx(ctx)->draining && is_capture) { - int bytesused = V4L2_TYPE_IS_MULTIPLANAR(buf.type) ? - buf.m.planes[0].bytesused : buf.bytesused; - if (bytesused == 0) { -- ctx->done = 1; -+ av_log(logger(ctx), AV_LOG_DEBUG, "Buffer empty - reQ\n"); -+ -+ // Must reQ so we don't leak -+ // May not matter if the next thing we do is release all the -+ // buffers but better to be tidy. -+ ff_v4l2_buffer_enqueue(avbuf); +- int bytesused = V4L2_TYPE_IS_MULTIPLANAR(buf.type) ? +- buf.m.planes[0].bytesused : buf.bytesused; +- if (bytesused == 0) { ++ if ((pfd.revents & POLLERR) != 0) { ++ av_log(avctx, AV_LOG_WARNING, "V4L2 %s POLLERR\n", ctx->name); ++ return AVERROR_UNKNOWN; ++ } + -+ if (ctx_done(ctx) > 0) -+ goto start; - return NULL; ++ if ((pfd.revents & poll_event) != 0) { ++ ret = get_event(m); ++ if (ret < 0) { + ctx->done = 1; +- return NULL; ++ return ret; } - #ifdef V4L2_BUF_FLAG_LAST +-#ifdef V4L2_BUF_FLAG_LAST - if (buf.flags & V4L2_BUF_FLAG_LAST) - ctx->done = 1; -+ if (buf.flags & V4L2_BUF_FLAG_LAST) { -+ av_log(logger(ctx), AV_LOG_TRACE, "FLAG_LAST set\n"); -+ avbuf->status = V4L2BUF_IN_USE; // Avoid flushing this buffer -+ ctx_done(ctx); -+ } - #endif +-#endif ++ continue; ++ } ++ ++ if ((pfd.revents & poll_cap) != 0) { ++ ret = dq_buf(ctx, ppavbuf); ++ if (ret == AVERROR(EPIPE)) ++ continue; ++ return ret; } - + - avbuf = &ctx->buffers[buf.index]; - avbuf->status = V4L2BUF_AVAILABLE; - avbuf->buf = buf; - if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) { - memcpy(avbuf->planes, planes, sizeof(planes)); - avbuf->buf.m.planes = avbuf->planes; -- } - return avbuf; ++ if ((pfd.revents & poll_out) != 0) { ++ if (is_cap) ++ return AVERROR(EAGAIN); ++ return dq_buf(ctx, ppavbuf); + } +- return avbuf; ++ ++ av_log(avctx, AV_LOG_ERROR, "V4L2 poll unexpected events=%#x, revents=%#x\n", pfd.events, pfd.revents); ++ return AVERROR_UNKNOWN; } - -@@ -443,8 +575,9 @@ static V4L2Buffer* v4l2_getfree_v4l2buf( ++} + +- return NULL; ++// Clear out flags and timestamps that should should be set by the user ++// Returns the passed avbuf ++static V4L2Buffer * ++clean_v4l2_buffer(V4L2Buffer * const avbuf) ++{ ++ struct v4l2_buffer *const buf = &avbuf->buf; ++ ++ buf->flags = 0; ++ buf->field = V4L2_FIELD_ANY; ++ buf->timestamp = (struct timeval){0}; ++ buf->timecode = (struct v4l2_timecode){0}; ++ buf->sequence = 0; ++ ++ return avbuf; + } + + static V4L2Buffer* v4l2_getfree_v4l2buf(V4L2Context *ctx) + { +- int timeout = 0; /* return when no more buffers to dequeue */ + int i; + + /* get back as many output buffers as possible */ + if (V4L2_TYPE_IS_OUTPUT(ctx->type)) { +- do { +- } while (v4l2_dequeue_v4l2buf(ctx, timeout)); ++ V4L2Buffer * avbuf; ++ do { ++ get_qbuf(ctx, &avbuf, 0); ++ } while (avbuf); } - + for (i = 0; i < ctx->num_buffers; i++) { - if (ctx->buffers[i].status == V4L2BUF_AVAILABLE) - return &ctx->buffers[i]; + V4L2Buffer * const avbuf = (V4L2Buffer *)ctx->bufrefs[i]->data; + if (avbuf->status == V4L2BUF_AVAILABLE) -+ return avbuf; ++ return clean_v4l2_buffer(avbuf); } - + return NULL; -@@ -452,25 +585,45 @@ static V4L2Buffer* v4l2_getfree_v4l2buf( - +@@ -452,25 +730,45 @@ static V4L2Buffer* v4l2_getfree_v4l2buf( + static int v4l2_release_buffers(V4L2Context* ctx) { - struct v4l2_requestbuffers req = { @@ -47632,12 +51801,12 @@ Upstream-status: Pending + int i; + int ret = 0; + const int fd = ctx_to_m2mctx(ctx)->fd; - + - for (i = 0; i < ctx->num_buffers; i++) { - V4L2Buffer *buffer = &ctx->buffers[i]; + // Orphan any buffers in the wild + ff_weak_link_break(&ctx->wl_master); - + - for (j = 0; j < buffer->num_planes; j++) { - struct V4L2Plane_info *p = &buffer->plane_info[j]; - if (p->mm_addr && p->length) @@ -47672,15 +51841,15 @@ Upstream-status: Pending + " 2. drmIoctl(.., DRM_IOCTL_GEM_CLOSE,... )\n"); } } -+ ctx->q_count = 0; - ++ atomic_store(&ctx->q_count, 0); + - return ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_REQBUFS, &req); + return ret; } - + static inline int v4l2_try_raw_format(V4L2Context* ctx, enum AVPixelFormat pixfmt) -@@ -499,6 +652,8 @@ static inline int v4l2_try_raw_format(V4 - +@@ -499,6 +797,8 @@ static inline int v4l2_try_raw_format(V4 + static int v4l2_get_raw_format(V4L2Context* ctx, enum AVPixelFormat *p) { + V4L2m2mContext* s = ctx_to_m2mctx(ctx); @@ -47688,10 +51857,10 @@ Upstream-status: Pending enum AVPixelFormat pixfmt = ctx->av_pix_fmt; struct v4l2_fmtdesc fdesc; int ret; -@@ -517,6 +672,13 @@ static int v4l2_get_raw_format(V4L2Conte +@@ -517,6 +817,13 @@ static int v4l2_get_raw_format(V4L2Conte if (ret) return AVERROR(EINVAL); - + + if (priv->pix_fmt != AV_PIX_FMT_NONE) { + if (fdesc.pixelformat != ff_v4l2_format_avfmt_to_v4l2(priv->pix_fmt)) { + fdesc.index++; @@ -47702,10 +51871,10 @@ Upstream-status: Pending pixfmt = ff_v4l2_format_v4l2_to_avfmt(fdesc.pixelformat, AV_CODEC_ID_RAWVIDEO); ret = v4l2_try_raw_format(ctx, pixfmt); if (ret){ -@@ -569,18 +731,77 @@ static int v4l2_get_coded_format(V4L2Con +@@ -569,30 +876,99 @@ static int v4l2_get_coded_format(V4L2Con * *****************************************************************************/ - + + +static void flush_all_buffers_status(V4L2Context* const ctx) +{ @@ -47717,9 +51886,9 @@ Upstream-status: Pending + for (i = 0; i < ctx->num_buffers; ++i) { + struct V4L2Buffer * const buf = (struct V4L2Buffer *)ctx->bufrefs[i]->data; + if (buf->status == V4L2BUF_IN_DRIVER) -+ buf->status = V4L2BUF_AVAILABLE; ++ ff_v4l2_buffer_set_avail(buf); + } -+ ctx->q_count = 0; ++ atomic_store(&ctx->q_count, 0); +} + +static int stuff_all_buffers(AVCodecContext * avctx, V4L2Context* ctx) @@ -47749,18 +51918,25 @@ Upstream-status: Pending int ff_v4l2_context_set_status(V4L2Context* ctx, uint32_t cmd) { int type = ctx->type; - int ret; +- int ret; ++ int ret = 0; + AVCodecContext * const avctx = logger(ctx); -+ + +- ret = ioctl(ctx_to_m2mctx(ctx)->fd, cmd, &type); +- if (ret < 0) +- return AVERROR(errno); ++ // Avoid doing anything if there is nothing we can do ++ if (cmd == VIDIOC_STREAMOFF && !ctx_buffers_alloced(ctx) && !ctx->streamon) ++ return 0; + +- ctx->streamon = (cmd == VIDIOC_STREAMON); + ff_mutex_lock(&ctx->lock); -+ + +- return 0; + if (cmd == VIDIOC_STREAMON && !V4L2_TYPE_IS_OUTPUT(ctx->type)) + stuff_all_buffers(avctx, ctx); - - ret = ioctl(ctx_to_m2mctx(ctx)->fd, cmd, &type); -- if (ret < 0) -- return AVERROR(errno); -+ if (ret < 0) { ++ ++ if (ioctl(ctx_to_m2mctx(ctx)->fd, cmd, &type) < 0) { + const int err = errno; + av_log(avctx, AV_LOG_ERROR, "%s set status %d (%s) failed: err=%d\n", ctx->name, + cmd, (cmd == VIDIOC_STREAMON) ? "ON" : "OFF", err); @@ -47770,73 +51946,153 @@ Upstream-status: Pending + { + if (cmd == VIDIOC_STREAMOFF) + flush_all_buffers_status(ctx); - -- ctx->streamon = (cmd == VIDIOC_STREAMON); ++ else ++ ctx->first_buf = 1; ++ + ctx->streamon = (cmd == VIDIOC_STREAMON); + av_log(avctx, AV_LOG_DEBUG, "%s set status %d (%s) OK\n", ctx->name, + cmd, (cmd == VIDIOC_STREAMON) ? "ON" : "OFF"); + } - -- return 0; ++ ++ // Both stream off & on effectively clear flag_last ++ ctx->flag_last = 0; ++ + ff_mutex_unlock(&ctx->lock); + + return ret; } - + int ff_v4l2_context_enqueue_frame(V4L2Context* ctx, const AVFrame* frame) -@@ -608,7 +829,8 @@ int ff_v4l2_context_enqueue_frame(V4L2Co + { +- V4L2m2mContext *s = ctx_to_m2mctx(ctx); ++ V4L2m2mContext *const s = ctx_to_m2mctx(ctx); ++ AVCodecContext *const avctx = s->avctx; ++ int64_t track_ts; + V4L2Buffer* avbuf; + int ret; + + if (!frame) { + ret = v4l2_stop_encode(ctx); + if (ret) +- av_log(logger(ctx), AV_LOG_ERROR, "%s stop_encode\n", ctx->name); ++ av_log(avctx, AV_LOG_ERROR, "%s stop_encode\n", ctx->name); + s->draining= 1; + return 0; + } +@@ -601,23 +977,29 @@ int ff_v4l2_context_enqueue_frame(V4L2Co + if (!avbuf) + return AVERROR(ENOMEM); + +- ret = ff_v4l2_buffer_avframe_to_buf(frame, avbuf); ++ track_ts = xlat_pts_frame_in(avctx, &s->xlat, frame); ++ ++ ret = ff_v4l2_buffer_avframe_to_buf(frame, avbuf, track_ts); + if (ret) + return ret; + return ff_v4l2_buffer_enqueue(avbuf); } - + -int ff_v4l2_context_enqueue_packet(V4L2Context* ctx, const AVPacket* pkt) +int ff_v4l2_context_enqueue_packet(V4L2Context* ctx, const AVPacket* pkt, -+ const void * extdata, size_t extlen, int no_rescale_pts) ++ const void * extdata, size_t extlen) { V4L2m2mContext *s = ctx_to_m2mctx(ctx); ++ AVCodecContext *const avctx = s->avctx; V4L2Buffer* avbuf; -@@ -616,8 +838,9 @@ int ff_v4l2_context_enqueue_packet(V4L2C - + int ret; ++ int64_t track_ts; + if (!pkt->size) { ret = v4l2_stop_decode(ctx); + // Log but otherwise ignore stop failure if (ret) - av_log(logger(ctx), AV_LOG_ERROR, "%s stop_decode\n", ctx->name); -+ av_log(logger(ctx), AV_LOG_ERROR, "%s stop_decode failed: err=%d\n", ctx->name, ret); ++ av_log(avctx, AV_LOG_ERROR, "%s stop_decode failed: err=%d\n", ctx->name, ret); s->draining = 1; return 0; } -@@ -626,14 +849,17 @@ int ff_v4l2_context_enqueue_packet(V4L2C +@@ -626,8 +1008,13 @@ int ff_v4l2_context_enqueue_packet(V4L2C if (!avbuf) return AVERROR(EAGAIN); - + - ret = ff_v4l2_buffer_avpkt_to_buf(pkt, avbuf); - if (ret) -+ ret = ff_v4l2_buffer_avpkt_to_buf_ext(pkt, avbuf, extdata, extlen, no_rescale_pts); ++ track_ts = xlat_pts_pkt_in(avctx, &s->xlat, pkt); ++ ++ ret = ff_v4l2_buffer_avpkt_to_buf_ext(pkt, avbuf, extdata, extlen, track_ts); + if (ret == AVERROR(ENOMEM)) + av_log(logger(ctx), AV_LOG_ERROR, "Buffer overflow in %s: pkt->size=%d > buf->length=%d\n", + __func__, pkt->size, avbuf->planes[0].length); + else if (ret) return ret; - + return ff_v4l2_buffer_enqueue(avbuf); - } - --int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* frame, int timeout) -+int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* frame, int timeout, int no_rescale_pts) +@@ -635,42 +1022,36 @@ int ff_v4l2_context_enqueue_packet(V4L2C + + int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* frame, int timeout) { ++ V4L2m2mContext *s = ctx_to_m2mctx(ctx); ++ AVCodecContext *const avctx = s->avctx; V4L2Buffer *avbuf; - -@@ -650,7 +876,7 @@ int ff_v4l2_context_dequeue_frame(V4L2Co - return AVERROR(EAGAIN); - } - ++ int rv; + +- /* +- * timeout=-1 blocks until: +- * 1. decoded frame available +- * 2. an input buffer is ready to be dequeued +- */ +- avbuf = v4l2_dequeue_v4l2buf(ctx, timeout); +- if (!avbuf) { +- if (ctx->done) +- return AVERROR_EOF; +- +- return AVERROR(EAGAIN); +- } ++ do { ++ if ((rv = get_qbuf(ctx, &avbuf, timeout)) != 0) ++ return rv; ++ if ((rv = ff_v4l2_buffer_buf_to_avframe(frame, avbuf)) != 0) ++ return rv; ++ } while (xlat_pts_frame_out(avctx, &s->xlat, frame) != 0); + - return ff_v4l2_buffer_buf_to_avframe(frame, avbuf); -+ return ff_v4l2_buffer_buf_to_avframe(frame, avbuf, no_rescale_pts); ++ return 0; } - + int ff_v4l2_context_dequeue_packet(V4L2Context* ctx, AVPacket* pkt) -@@ -702,78 +928,155 @@ int ff_v4l2_context_get_format(V4L2Conte - + { ++ V4L2m2mContext *s = ctx_to_m2mctx(ctx); ++ AVCodecContext *const avctx = s->avctx; + V4L2Buffer *avbuf; ++ int rv; + +- /* +- * blocks until: +- * 1. encoded packet available +- * 2. an input buffer ready to be dequeued +- */ +- avbuf = v4l2_dequeue_v4l2buf(ctx, -1); +- if (!avbuf) { +- if (ctx->done) +- return AVERROR_EOF; ++ do { ++ if ((rv = get_qbuf(ctx, &avbuf, -1)) != 0) ++ return rv == AVERROR(ENOSPC) ? AVERROR(EAGAIN) : rv; // Caller not currently expecting ENOSPC ++ if ((rv = ff_v4l2_buffer_buf_to_avpkt(pkt, avbuf)) != 0) ++ return rv; ++ } while (xlat_pts_pkt_out(avctx, &s->xlat, pkt) != 0); + +- return AVERROR(EAGAIN); +- } +- +- return ff_v4l2_buffer_buf_to_avpkt(pkt, avbuf); ++ return 0; + } + + int ff_v4l2_context_get_format(V4L2Context* ctx, int probe) +@@ -702,78 +1083,160 @@ int ff_v4l2_context_get_format(V4L2Conte + int ff_v4l2_context_set_format(V4L2Context* ctx) { - return ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_S_FMT, &ctx->format); @@ -47864,29 +52120,30 @@ Upstream-status: Pending + ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_S_FMT, &ctx->format); + return ret; } - + void ff_v4l2_context_release(V4L2Context* ctx) { int ret; - + - if (!ctx->buffers) + if (!ctx->bufrefs) return; - + ret = v4l2_release_buffers(ctx); if (ret) av_log(logger(ctx), AV_LOG_WARNING, "V4L2 failed to unmap the %s buffers\n", ctx->name); - + - av_freep(&ctx->buffers); + av_freep(&ctx->bufrefs); + av_buffer_unref(&ctx->frames_ref); + + ff_mutex_destroy(&ctx->lock); ++ pthread_cond_destroy(&ctx->cond); } - + -int ff_v4l2_context_init(V4L2Context* ctx) + -+static int create_buffers(V4L2Context* const ctx, const unsigned int req_buffers) ++static int create_buffers(V4L2Context* const ctx, const unsigned int req_buffers, const enum v4l2_memory mem) { - V4L2m2mContext *s = ctx_to_m2mctx(ctx); + V4L2m2mContext * const s = ctx_to_m2mctx(ctx); @@ -47897,17 +52154,19 @@ Upstream-status: Pending - av_log(logger(ctx), AV_LOG_ERROR, "type %i not supported\n", ctx->type); - return AVERROR_PATCHWELCOME; - } -- ++ int ret; ++ int i; + - ret = ioctl(s->fd, VIDIOC_G_FMT, &ctx->format); - if (ret) - av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_G_FMT failed\n", ctx->name); -+ int ret; -+ int i; - ++ av_assert0(ctx->bufrefs == NULL); + memset(&req, 0, sizeof(req)); - req.count = ctx->num_buffers; +- req.memory = V4L2_MEMORY_MMAP; + req.count = req_buffers; - req.memory = V4L2_MEMORY_MMAP; ++ req.memory = mem; req.type = ctx->type; - ret = ioctl(s->fd, VIDIOC_REQBUFS, &req); - if (ret < 0) { @@ -47920,7 +52179,7 @@ Upstream-status: Pending + return ret; + } } - + ctx->num_buffers = req.count; - ctx->buffers = av_mallocz(ctx->num_buffers * sizeof(V4L2Buffer)); - if (!ctx->buffers) { @@ -47930,7 +52189,7 @@ Upstream-status: Pending - return AVERROR(ENOMEM); + goto fail_release; } - + - for (i = 0; i < req.count; i++) { - ctx->buffers[i].context = ctx; - ret = ff_v4l2_buffer_initialize(&ctx->buffers[i], i); @@ -47942,14 +52201,14 @@ Upstream-status: Pending + } + + for (i = 0; i < ctx->num_buffers; i++) { -+ ret = ff_v4l2_buffer_initialize(&ctx->bufrefs[i], i, ctx); ++ ret = ff_v4l2_buffer_initialize(&ctx->bufrefs[i], i, ctx, mem); + if (ret) { av_log(logger(ctx), AV_LOG_ERROR, "%s buffer[%d] initialization (%s)\n", ctx->name, i, av_err2str(ret)); - goto error; + goto fail_release; } } - + av_log(logger(ctx), AV_LOG_DEBUG, "%s: %s %02d buffers initialized: %04ux%04u, sizeimage %08u, bytesperline %08u\n", ctx->name, V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? av_fourcc2str(ctx->format.fmt.pix_mp.pixelformat) : av_fourcc2str(ctx->format.fmt.pix.pixelformat), req.count, @@ -47959,9 +52218,9 @@ Upstream-status: Pending + ff_v4l2_get_format_height(&ctx->format), V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? ctx->format.fmt.pix_mp.plane_fmt[0].sizeimage : ctx->format.fmt.pix.sizeimage, V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? ctx->format.fmt.pix_mp.plane_fmt[0].bytesperline : ctx->format.fmt.pix.bytesperline); - + return 0; - + -error: +fail_release: v4l2_release_buffers(ctx); @@ -47976,14 +52235,16 @@ Upstream-status: Pending + + // It is not valid to reinit a context without a previous release + av_assert0(ctx->bufrefs == NULL); -+ + +- av_freep(&ctx->buffers); + if (!v4l2_type_supported(ctx)) { + av_log(logger(ctx), AV_LOG_ERROR, "type %i not supported\n", ctx->type); + return AVERROR_PATCHWELCOME; + } - -- av_freep(&ctx->buffers); ++ + ff_mutex_init(&ctx->lock, NULL); ++ pthread_cond_init(&ctx->cond, NULL); ++ atomic_init(&ctx->q_count, 0); + + if (s->output_drm) { + AVHWFramesContext *hwframes; @@ -47997,8 +52258,8 @@ Upstream-status: Pending + hwframes = (AVHWFramesContext*)ctx->frames_ref->data; + hwframes->format = AV_PIX_FMT_DRM_PRIME; + hwframes->sw_format = ctx->av_pix_fmt; -+ hwframes->width = ctx->width; -+ hwframes->height = ctx->height; ++ hwframes->width = ctx->width != 0 ? ctx->width : s->avctx->width; ++ hwframes->height = ctx->height != 0 ? ctx->height : s->avctx->height; + ret = av_hwframe_ctx_init(ctx->frames_ref); + if (ret < 0) + goto fail_unref_hwframes; @@ -48011,12 +52272,12 @@ Upstream-status: Pending + goto fail_unref_hwframes; + } + -+ ret = create_buffers(ctx, ctx->num_buffers); ++ ret = create_buffers(ctx, ctx->num_buffers, ctx->buf_mem); + if (ret < 0) + goto fail_unref_hwframes; + + return 0; - + +fail_unref_hwframes: + av_buffer_unref(&ctx->frames_ref); +fail_unlock: @@ -48031,14 +52292,14 @@ Upstream-status: Pending #include "libavutil/buffer.h" +#include "libavutil/thread.h" #include "v4l2_buffers.h" - + typedef struct V4L2Context { @@ -70,11 +71,18 @@ typedef struct V4L2Context { */ int width, height; AVRational sample_aspect_ratio; + struct v4l2_rect selection; - + /** - * Indexed array of V4L2Buffers + * If the default size of buffer is less than this then try to @@ -48051,50 +52312,98 @@ Upstream-status: Pending + * Indexed array of pointers to V4L2Buffers + */ + AVBufferRef **bufrefs; - + /** * Readonly after init. -@@ -92,6 +100,12 @@ typedef struct V4L2Context { +@@ -82,16 +90,38 @@ typedef struct V4L2Context { + int num_buffers; + + /** ++ * Buffer memory type V4L2_MEMORY_MMAP or V4L2_MEMORY_DMABUF ++ */ ++ enum v4l2_memory buf_mem; ++ ++ /** + * Whether the stream has been started (VIDIOC_STREAMON has been sent). + */ + int streamon; + ++ /* 1st buffer after stream on */ ++ int first_buf; ++ + /** + * Either no more buffers available or an unrecoverable error was notified + * by the V4L2 kernel driver: once set the context has to be exited. */ int done; - + ++ int flag_last; ++ ++ /** ++ * If NZ then when Qing frame/pkt use this rather than the ++ * "real" PTS ++ */ ++ uint64_t track_ts; ++ + AVBufferRef *frames_ref; -+ int q_count; -+ int dq_count; ++ atomic_int q_count; + struct ff_weak_link_master *wl_master; + + AVMutex lock; ++ pthread_cond_t cond; } V4L2Context; - + /** -@@ -156,9 +170,12 @@ int ff_v4l2_context_dequeue_packet(V4L2C +@@ -156,7 +186,10 @@ int ff_v4l2_context_dequeue_packet(V4L2C * @param[in] ctx The V4L2Context to dequeue from. * @param[inout] f The AVFrame to dequeue to. * @param[in] timeout The timeout for dequeue (-1 to block, 0 to return immediately, or milliseconds) -+ * @param[in] no_rescale_pts (0 rescale pts, 1 use pts as -+ * timestamp directly) + * * @return 0 in case of success, AVERROR(EAGAIN) if no buffer was ready, another negative error in case of error. ++ * AVERROR(ENOSPC) if no buffer availible to put ++ * the frame in */ --int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* f, int timeout); -+int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* f, int timeout, int no_rescale_pts); - - /** - * Enqueues a buffer to a V4L2Context from an AVPacket -@@ -170,7 +187,7 @@ int ff_v4l2_context_dequeue_frame(V4L2Co + int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* f, int timeout); + +@@ -170,7 +203,7 @@ int ff_v4l2_context_dequeue_frame(V4L2Co * @param[in] pkt A pointer to an AVPacket. * @return 0 in case of success, a negative error otherwise. */ -int ff_v4l2_context_enqueue_packet(V4L2Context* ctx, const AVPacket* pkt); -+int ff_v4l2_context_enqueue_packet(V4L2Context* ctx, const AVPacket* pkt, const void * ext_data, size_t ext_size, int no_rescale_pts); - ++int ff_v4l2_context_enqueue_packet(V4L2Context* ctx, const AVPacket* pkt, const void * ext_data, size_t ext_size); + /** * Enqueues a buffer to a V4L2Context from an AVFrame --- a/libavcodec/v4l2_m2m.c +++ b/libavcodec/v4l2_m2m.c -@@ -215,13 +215,7 @@ int ff_v4l2_m2m_codec_reinit(V4L2m2mCont +@@ -36,6 +36,14 @@ + #include "v4l2_fmt.h" + #include "v4l2_m2m.h" + ++static void ++xlat_init(xlat_track_t * const x) ++{ ++ memset(x, 0, sizeof(*x)); ++ x->last_pts = AV_NOPTS_VALUE; ++} ++ ++ + static inline int v4l2_splane_video(struct v4l2_capability *cap) + { + if (cap->capabilities & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT) && +@@ -68,7 +76,9 @@ static int v4l2_prepare_contexts(V4L2m2m + + s->capture.done = s->output.done = 0; + s->capture.name = "capture"; ++ s->capture.buf_mem = V4L2_MEMORY_MMAP; + s->output.name = "output"; ++ s->output.buf_mem = s->input_drm ? V4L2_MEMORY_DMABUF : V4L2_MEMORY_MMAP; + atomic_init(&s->refcount, 0); + sem_init(&s->refsync, 0, 0); + +@@ -215,13 +225,7 @@ int ff_v4l2_m2m_codec_reinit(V4L2m2mCont av_log(log_ctx, AV_LOG_ERROR, "capture VIDIOC_STREAMOFF\n"); - + /* 2. unmap the capture buffers (v4l2 and ffmpeg): - * we must wait for all references to be released before being allowed - * to queue new buffers. @@ -48104,30 +52413,49 @@ Upstream-status: Pending - while(sem_wait(&s->refsync) == -1 && errno == EINTR); - ff_v4l2_context_release(&s->capture); - + /* 3. get the new capture format */ -@@ -328,7 +322,10 @@ static void v4l2_m2m_destroy_context(voi +@@ -240,7 +244,6 @@ int ff_v4l2_m2m_codec_reinit(V4L2m2mCont + + /* 5. complete reinit */ + s->draining = 0; +- s->reinit = 0; + + return 0; + } +@@ -274,7 +277,6 @@ int ff_v4l2_m2m_codec_full_reinit(V4L2m2 + + /* start again now that we know the stream dimensions */ + s->draining = 0; +- s->reinit = 0; + + ret = ff_v4l2_context_get_format(&s->output, 0); + if (ret) { +@@ -328,7 +330,13 @@ static void v4l2_m2m_destroy_context(voi ff_v4l2_context_release(&s->capture); sem_destroy(&s->refsync); - + - close(s->fd); + if (s->fd != -1) + close(s->fd); + ++ av_packet_unref(&s->buf_pkt); ++ av_freep(&s->extdata_data); ++ + av_log(s->avctx, AV_LOG_DEBUG, "V4L2 Context destroyed\n"); - + av_free(s); } -@@ -338,17 +335,34 @@ int ff_v4l2_m2m_codec_end(V4L2m2mPriv *p +@@ -338,17 +346,34 @@ int ff_v4l2_m2m_codec_end(V4L2m2mPriv *p V4L2m2mContext *s = priv->context; int ret; - + - ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF); - if (ret) - av_log(s->avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->output.name); + if (!s) + return 0; - + - ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF); - if (ret) - av_log(s->avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->capture.name); @@ -48145,9 +52473,9 @@ Upstream-status: Pending + if (ret) + av_log(s->avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->capture.name); + } - + ff_v4l2_context_release(&s->output); - + + close(s->fd); + s->fd = -1; + @@ -48157,20 +52485,65 @@ Upstream-status: Pending + s->avctx = NULL; + priv->context = NULL; av_buffer_unref(&priv->context_ref); - + return 0; +@@ -392,28 +417,33 @@ int ff_v4l2_m2m_codec_init(V4L2m2mPriv * + return v4l2_configure_contexts(s); + } + +-int ff_v4l2_m2m_create_context(V4L2m2mPriv *priv, V4L2m2mContext **s) ++int ff_v4l2_m2m_create_context(V4L2m2mPriv *priv, V4L2m2mContext **pps) + { +- *s = av_mallocz(sizeof(V4L2m2mContext)); +- if (!*s) ++ V4L2m2mContext * const s = av_mallocz(sizeof(V4L2m2mContext)); ++ ++ *pps = NULL; ++ if (!s) + return AVERROR(ENOMEM); + +- priv->context_ref = av_buffer_create((uint8_t *) *s, sizeof(V4L2m2mContext), ++ priv->context_ref = av_buffer_create((uint8_t *)s, sizeof(*s), + &v4l2_m2m_destroy_context, NULL, 0); + if (!priv->context_ref) { +- av_freep(s); ++ av_free(s); + return AVERROR(ENOMEM); + } + + /* assign the context */ +- priv->context = *s; +- (*s)->priv = priv; ++ priv->context = s; ++ s->priv = priv; + + /* populate it */ +- priv->context->capture.num_buffers = priv->num_capture_buffers; +- priv->context->output.num_buffers = priv->num_output_buffers; +- priv->context->self_ref = priv->context_ref; +- priv->context->fd = -1; ++ s->capture.num_buffers = priv->num_capture_buffers; ++ s->output.num_buffers = priv->num_output_buffers; ++ s->self_ref = priv->context_ref; ++ s->fd = -1; ++ ++ xlat_init(&s->xlat); + ++ *pps = s; + return 0; + } --- a/libavcodec/v4l2_m2m.h +++ b/libavcodec/v4l2_m2m.h @@ -30,6 +30,7 @@ #include <linux/videodev2.h> - + #include "libavcodec/avcodec.h" +#include "libavutil/pixfmt.h" #include "v4l2_context.h" - + #define container_of(ptr, type, member) ({ \ -@@ -38,7 +39,18 @@ - +@@ -38,7 +39,37 @@ + #define V4L_M2M_DEFAULT_OPTS \ { "num_output_buffers", "Number of buffers in the output context",\ - OFFSET(num_output_buffers), AV_OPT_TYPE_INT, { .i64 = 16 }, 6, INT_MAX, FLAGS } @@ -48179,26 +52552,45 @@ Upstream-status: Pending +#define FF_V4L2_M2M_TRACK_SIZE 128 +typedef struct V4L2m2mTrackEl { + int discard; // If we see this buffer its been flushed, so discard ++ int pending; + int pkt_size; + int64_t pts; ++ int64_t dts; + int64_t reordered_opaque; + int64_t pkt_pos; + int64_t pkt_duration; + int64_t track_pts; +} V4L2m2mTrackEl; - ++ ++typedef struct pts_stats_s ++{ ++ void * logctx; ++ const char * name; // For debug ++ unsigned int last_count; ++ unsigned int last_interval; ++ int64_t last_pts; ++ int64_t guess; ++} pts_stats_t; ++ ++typedef struct xlat_track_s { ++ unsigned int track_no; ++ int64_t last_pts; ++ int64_t last_opaque; ++ V4L2m2mTrackEl track_els[FF_V4L2_M2M_TRACK_SIZE]; ++} xlat_track_t; + typedef struct V4L2m2mContext { char devname[PATH_MAX]; -@@ -53,6 +65,7 @@ typedef struct V4L2m2mContext { +@@ -52,7 +83,6 @@ typedef struct V4L2m2mContext { + AVCodecContext *avctx; sem_t refsync; atomic_uint refcount; - int reinit; -+ int resize_pending; - +- int reinit; + /* null frame/packet received */ int draining; -@@ -63,6 +76,23 @@ typedef struct V4L2m2mContext { - +@@ -63,6 +93,36 @@ typedef struct V4L2m2mContext { + /* reference back to V4L2m2mPriv */ void *priv; + @@ -48207,49 +52599,72 @@ Upstream-status: Pending + /* generate DRM frames */ + int output_drm; + ++ /* input frames are drmprime */ ++ int input_drm; ++ + /* Frame tracking */ -+ int64_t last_pkt_dts; -+ int64_t last_opaque; -+ unsigned int track_no; -+ V4L2m2mTrackEl track_els[FF_V4L2_M2M_TRACK_SIZE]; ++ xlat_track_t xlat; ++ int pending_hw; ++ int pending_n; ++ ++ pts_stats_t pts_stat; + + /* req pkt */ + int req_pkt; + + /* Ext data sent */ + int extdata_sent; ++ /* Ext data sent in packet - overrides ctx */ ++ uint8_t * extdata_data; ++ size_t extdata_size; ++ ++#define FF_V4L2_QUIRK_REINIT_ALWAYS 1 ++#define FF_V4L2_QUIRK_ENUM_FRAMESIZES_BROKEN 2 ++ /* Quirks */ ++ unsigned int quirks; ++ } V4L2m2mContext; - + typedef struct V4L2m2mPriv { -@@ -73,6 +103,7 @@ typedef struct V4L2m2mPriv { - +@@ -73,6 +133,7 @@ typedef struct V4L2m2mPriv { + int num_output_buffers; int num_capture_buffers; + enum AVPixelFormat pix_fmt; } V4L2m2mPriv; - + /** -@@ -126,4 +157,16 @@ int ff_v4l2_m2m_codec_reinit(V4L2m2mCont +@@ -126,4 +187,26 @@ int ff_v4l2_m2m_codec_reinit(V4L2m2mCont */ int ff_v4l2_m2m_codec_full_reinit(V4L2m2mContext *ctx); - + + -+static inline unsigned int ff_v4l2_get_format_width(struct v4l2_format *fmt) ++static inline unsigned int ff_v4l2_get_format_width(const struct v4l2_format * const fmt) +{ + return V4L2_TYPE_IS_MULTIPLANAR(fmt->type) ? fmt->fmt.pix_mp.width : fmt->fmt.pix.width; +} + -+static inline unsigned int ff_v4l2_get_format_height(struct v4l2_format *fmt) ++static inline unsigned int ff_v4l2_get_format_height(const struct v4l2_format * const fmt) +{ + return V4L2_TYPE_IS_MULTIPLANAR(fmt->type) ? fmt->fmt.pix_mp.height : fmt->fmt.pix.height; +} + ++static inline uint32_t ff_v4l2_get_format_pixelformat(const struct v4l2_format * const fmt) ++{ ++ return V4L2_TYPE_IS_MULTIPLANAR(fmt->type) ? fmt->fmt.pix_mp.pixelformat : fmt->fmt.pix.pixelformat; ++} ++ ++static inline int ff_v4l2_ctx_eos(const V4L2Context * const ctx) ++{ ++ return ctx->flag_last; ++} ++ + #endif /* AVCODEC_V4L2_M2M_H */ --- a/libavcodec/v4l2_m2m_dec.c +++ b/libavcodec/v4l2_m2m_dec.c @@ -23,6 +23,10 @@ - + #include <linux/videodev2.h> #include <sys/ioctl.h> + @@ -48259,10 +52674,10 @@ Upstream-status: Pending #include "libavutil/pixfmt.h" #include "libavutil/pixdesc.h" #include "libavutil/opt.h" -@@ -30,26 +34,51 @@ +@@ -30,75 +34,111 @@ #include "libavcodec/decode.h" #include "libavcodec/internal.h" - + +#include "libavcodec/hwaccels.h" +#include "libavcodec/internal.h" +#include "libavcodec/hwconfig.h" @@ -48270,7 +52685,80 @@ Upstream-status: Pending #include "v4l2_context.h" #include "v4l2_m2m.h" #include "v4l2_fmt.h" - + +-static int v4l2_try_start(AVCodecContext *avctx) ++// Pick 64 for max last count - that is >1sec at 60fps ++#define STATS_LAST_COUNT_MAX 64 ++#define STATS_INTERVAL_MAX (1 << 30) ++ ++#ifndef FF_API_BUFFER_SIZE_T ++#define FF_API_BUFFER_SIZE_T 1 ++#endif ++ ++static int64_t pts_stats_guess(const pts_stats_t * const stats) + { +- V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context; +- V4L2Context *const capture = &s->capture; +- V4L2Context *const output = &s->output; +- struct v4l2_selection selection = { 0 }; +- int ret; ++ if (stats->last_pts == AV_NOPTS_VALUE || ++ stats->last_interval == 0 || ++ stats->last_count >= STATS_LAST_COUNT_MAX) ++ return AV_NOPTS_VALUE; ++ return stats->last_pts + (int64_t)(stats->last_count - 1) * (int64_t)stats->last_interval; ++} + +- /* 1. start the output process */ +- if (!output->streamon) { +- ret = ff_v4l2_context_set_status(output, VIDIOC_STREAMON); +- if (ret < 0) { +- av_log(avctx, AV_LOG_DEBUG, "VIDIOC_STREAMON on output context\n"); +- return ret; ++static void pts_stats_add(pts_stats_t * const stats, int64_t pts) ++{ ++ if (pts == AV_NOPTS_VALUE || pts == stats->last_pts) { ++ if (stats->last_count < STATS_LAST_COUNT_MAX) ++ ++stats->last_count; ++ return; ++ } ++ ++ if (stats->last_pts != AV_NOPTS_VALUE) { ++ const int64_t interval = pts - stats->last_pts; ++ ++ if (interval < 0 || interval >= STATS_INTERVAL_MAX || ++ stats->last_count >= STATS_LAST_COUNT_MAX) { ++ if (stats->last_interval != 0) ++ av_log(stats->logctx, AV_LOG_DEBUG, "%s: %s: Bad interval: %" PRId64 "/%d\n", ++ __func__, stats->name, interval, stats->last_count); ++ stats->last_interval = 0; ++ } ++ else { ++ const int64_t frame_time = interval / (int64_t)stats->last_count; ++ ++ if (frame_time != stats->last_interval) ++ av_log(stats->logctx, AV_LOG_DEBUG, "%s: %s: New interval: %u->%" PRId64 "/%d=%" PRId64 "\n", ++ __func__, stats->name, stats->last_interval, interval, stats->last_count, frame_time); ++ stats->last_interval = frame_time; + } + } + +- if (capture->streamon) ++ stats->last_pts = pts; ++ stats->last_count = 1; ++} ++ ++static void pts_stats_init(pts_stats_t * const stats, void * logctx, const char * name) ++{ ++ *stats = (pts_stats_t){ ++ .logctx = logctx, ++ .name = name, ++ .last_count = 1, ++ .last_interval = 0, ++ .last_pts = AV_NOPTS_VALUE ++ }; ++} ++ +static int check_output_streamon(AVCodecContext *const avctx, V4L2m2mContext *const s) +{ + int ret; @@ -48280,81 +52768,43 @@ Upstream-status: Pending + }; + + if (s->output.streamon) -+ return 0; -+ -+ ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMON); -+ if (ret < 0) -+ av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMON on output context\n"); -+ -+ if (!s->capture.streamon || ret < 0) -+ return ret; -+ -+ ret = ioctl(s->fd, VIDIOC_DECODER_CMD, &cmd); -+ if (ret < 0) -+ av_log(avctx, AV_LOG_ERROR, "VIDIOC_DECODER_CMD start error: %d\n", errno); -+ else -+ av_log(avctx, AV_LOG_DEBUG, "VIDIOC_DECODER_CMD start OK\n"); -+ -+ return ret; -+} -+ - static int v4l2_try_start(AVCodecContext *avctx) - { - V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context; - V4L2Context *const capture = &s->capture; -- V4L2Context *const output = &s->output; - struct v4l2_selection selection = { 0 }; - int ret; - - /* 1. start the output process */ -- if (!output->streamon) { -- ret = ff_v4l2_context_set_status(output, VIDIOC_STREAMON); -- if (ret < 0) { -- av_log(avctx, AV_LOG_DEBUG, "VIDIOC_STREAMON on output context\n"); -- return ret; -- } -- } -+ if ((ret = check_output_streamon(avctx, s)) != 0) -+ return ret; - - if (capture->streamon) return 0; -@@ -63,15 +92,29 @@ static int v4l2_try_start(AVCodecContext + +- /* 2. get the capture format */ +- capture->format.type = capture->type; +- ret = ioctl(s->fd, VIDIOC_G_FMT, &capture->format); +- if (ret) { +- av_log(avctx, AV_LOG_WARNING, "VIDIOC_G_FMT ioctl\n"); ++ ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMON); ++ if (ret != 0) { ++ av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMON on output context: %s\n", av_err2str(ret)); + return ret; } - - /* 2.1 update the AVCodecContext */ + +- /* 2.1 update the AVCodecContext */ - avctx->pix_fmt = ff_v4l2_format_v4l2_to_avfmt(capture->format.fmt.pix_mp.pixelformat, AV_CODEC_ID_RAWVIDEO); - capture->av_pix_fmt = avctx->pix_fmt; -+ capture->av_pix_fmt = -+ ff_v4l2_format_v4l2_to_avfmt(capture->format.fmt.pix_mp.pixelformat, AV_CODEC_ID_RAWVIDEO); -+ if (s->output_drm) { -+ avctx->pix_fmt = AV_PIX_FMT_DRM_PRIME; -+ avctx->sw_pix_fmt = capture->av_pix_fmt; -+ } -+ else -+ avctx->pix_fmt = capture->av_pix_fmt; - - /* 3. set the crop parameters */ -+#if 1 -+ selection.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; -+ selection.target = V4L2_SEL_TGT_CROP_DEFAULT; -+ ret = ioctl(s->fd, VIDIOC_G_SELECTION, &selection); -+ av_log(avctx, AV_LOG_INFO, "Post G selection ret=%d, err=%d %dx%d\n", ret, errno, selection.r.width, selection.r.height); -+#else - selection.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - selection.r.height = avctx->coded_height; - selection.r.width = avctx->coded_width; -+ av_log(avctx, AV_LOG_INFO, "Try selection %dx%d\n", avctx->coded_width, avctx->coded_height); - ret = ioctl(s->fd, VIDIOC_S_SELECTION, &selection); +- +- /* 3. set the crop parameters */ +- selection.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +- selection.r.height = avctx->coded_height; +- selection.r.width = avctx->coded_width; +- ret = ioctl(s->fd, VIDIOC_S_SELECTION, &selection); - if (!ret) { -+ av_log(avctx, AV_LOG_INFO, "Post S selection ret=%d, err=%d %dx%d\n", ret, errno, selection.r.width, selection.r.height); -+ if (1) { - ret = ioctl(s->fd, VIDIOC_G_SELECTION, &selection); - if (ret) { - av_log(avctx, AV_LOG_WARNING, "VIDIOC_G_SELECTION ioctl\n"); -@@ -82,15 +125,7 @@ static int v4l2_try_start(AVCodecContext - capture->width = selection.r.width; - } +- ret = ioctl(s->fd, VIDIOC_G_SELECTION, &selection); +- if (ret) { +- av_log(avctx, AV_LOG_WARNING, "VIDIOC_G_SELECTION ioctl\n"); +- } else { +- av_log(avctx, AV_LOG_DEBUG, "crop output %dx%d\n", selection.r.width, selection.r.height); +- /* update the size of the resulting frame */ +- capture->height = selection.r.height; +- capture->width = selection.r.width; +- } ++ // STREAMON should do implicit START so this just for those that don't. ++ // It is optional so don't worry if it fails ++ if (ioctl(s->fd, VIDIOC_DECODER_CMD, &cmd) < 0) { ++ ret = AVERROR(errno); ++ av_log(avctx, AV_LOG_WARNING, "VIDIOC_DECODER_CMD start error: %s\n", av_err2str(ret)); } - - /* 4. init the capture context now that we have the capture format */ @@ -48364,131 +52814,133 @@ Upstream-status: Pending - av_log(avctx, AV_LOG_ERROR, "can't request capture buffers\n"); - return AVERROR(ENOMEM); - } ++ else { ++ av_log(avctx, AV_LOG_TRACE, "VIDIOC_DECODER_CMD start OK\n"); + } ++ return 0; ++} + +- /* 5. start the capture process */ +- ret = ff_v4l2_context_set_status(capture, VIDIOC_STREAMON); +- if (ret) { +- av_log(avctx, AV_LOG_DEBUG, "VIDIOC_STREAMON, on capture context\n"); +- return ret; - } -+#endif - - /* 5. start the capture process */ - ret = ff_v4l2_context_set_status(capture, VIDIOC_STREAMON); -@@ -133,52 +168,312 @@ static int v4l2_prepare_decoder(V4L2m2mC ++static int v4l2_try_start(AVCodecContext *avctx) ++{ ++ V4L2m2mContext * const s = ((V4L2m2mPriv*)avctx->priv_data)->context; ++ int ret; + ++ /* 1. start the output process */ ++ if ((ret = check_output_streamon(avctx, s)) != 0) ++ return ret; return 0; } - + +@@ -133,52 +173,525 @@ static int v4l2_prepare_decoder(V4L2m2mC + return 0; + } + -static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame) -+static inline int64_t track_to_pts(AVCodecContext *avctx, unsigned int n) ++static void ++set_best_effort_pts(AVCodecContext *const avctx, ++ pts_stats_t * const ps, ++ AVFrame *const frame) +{ -+ return (int64_t)n; ++ pts_stats_add(ps, frame->pts); ++ ++#if FF_API_PKT_PTS ++FF_DISABLE_DEPRECATION_WARNINGS ++ frame->pkt_pts = frame->pts; ++FF_ENABLE_DEPRECATION_WARNINGS ++#endif ++ frame->best_effort_timestamp = pts_stats_guess(ps); ++ // If we can't guess from just PTS - try DTS ++ if (frame->best_effort_timestamp == AV_NOPTS_VALUE) ++ frame->best_effort_timestamp = frame->pkt_dts; ++ ++ // We can't emulate what s/w does in a useful manner and using the ++ // "correct" answer seems to just confuse things. ++ frame->pkt_dts = frame->pts; ++ av_log(avctx, AV_LOG_TRACE, "Out PTS=%" PRId64 "/%"PRId64", DTS=%" PRId64 "\n", ++ frame->pts, frame->best_effort_timestamp, frame->pkt_dts); +} + -+static inline unsigned int pts_to_track(AVCodecContext *avctx, const int64_t pts) ++static void ++xlat_flush(xlat_track_t * const x) +{ -+ return (unsigned int)pts; ++ unsigned int i; ++ for (i = 0; i != FF_V4L2_M2M_TRACK_SIZE; ++i) { ++ x->track_els[i].pending = 0; ++ x->track_els[i].discard = 1; ++ } ++ x->last_pts = AV_NOPTS_VALUE; +} + -+// FFmpeg requires us to propagate a number of vars from the coded pkt into -+// the decoded frame. The only thing that tracks like that in V4L2 stateful -+// is timestamp. PTS maps to timestamp for this decode. FFmpeg makes no -+// guarantees about PTS being unique or specified for every frame so replace -+// the supplied PTS with a simple incrementing number and keep a circular -+// buffer of all the things we want preserved (including the original PTS) -+// indexed by the tracking no. -+static void -+xlat_pts_in(AVCodecContext *const avctx, V4L2m2mContext *const s, AVPacket *const avpkt) ++static int ++xlat_pending(const xlat_track_t * const x) +{ -+ int64_t track_pts; ++ unsigned int n = x->track_no % FF_V4L2_M2M_TRACK_SIZE; ++ unsigned int i; ++ int r = 0; ++ int64_t now = AV_NOPTS_VALUE; + -+ // Avoid 0 -+ if (++s->track_no == 0) -+ s->track_no = 1; ++ for (i = 0; i < 32; ++i, n = (n - 1) % FF_V4L2_M2M_TRACK_SIZE) { ++ const V4L2m2mTrackEl * const t = x->track_els + n; + -+ track_pts = track_to_pts(avctx, s->track_no); ++ if (!t->pending) ++ continue; + -+ av_log(avctx, AV_LOG_TRACE, "In PTS=%" PRId64 ", DTS=%" PRId64 ", track=%" PRId64 ", n=%u\n", avpkt->pts, avpkt->dts, track_pts, s->track_no); -+ s->last_pkt_dts = avpkt->dts; -+ s->track_els[s->track_no % FF_V4L2_M2M_TRACK_SIZE] = (V4L2m2mTrackEl){ -+ .discard = 0, -+ .pkt_size = avpkt->size, -+ .pts = avpkt->pts, -+ .reordered_opaque = avctx->reordered_opaque, -+ .pkt_pos = avpkt->pos, -+ .pkt_duration = avpkt->duration, -+ .track_pts = track_pts -+ }; -+ avpkt->pts = track_pts; -+} ++ if (now == AV_NOPTS_VALUE) ++ now = t->dts; + -+// Returns -1 if we should discard the frame -+static int -+xlat_pts_out(AVCodecContext *const avctx, V4L2m2mContext *const s, AVFrame *const frame) -+{ -+ unsigned int n = pts_to_track(avctx, frame->pts) % FF_V4L2_M2M_TRACK_SIZE; -+ const V4L2m2mTrackEl *const t = s->track_els + n; -+ if (frame->pts == AV_NOPTS_VALUE || frame->pts != t->track_pts) -+ { -+ av_log(avctx, AV_LOG_INFO, "Tracking failure: pts=%" PRId64 ", track[%d]=%" PRId64 "\n", frame->pts, n, t->track_pts); -+ frame->pts = AV_NOPTS_VALUE; -+ frame->pkt_dts = s->last_pkt_dts; -+ frame->reordered_opaque = s->last_opaque; -+ frame->pkt_pos = -1; -+ frame->pkt_duration = 0; -+ frame->pkt_size = -1; ++ if (t->pts == AV_NOPTS_VALUE || ++ ((now == AV_NOPTS_VALUE || t->pts <= now) && ++ (x->last_pts == AV_NOPTS_VALUE || t->pts > x->last_pts))) ++ ++r; + } -+ else if (!t->discard) -+ { -+ frame->pts = t->pts; -+ frame->pkt_dts = s->last_pkt_dts; -+ frame->reordered_opaque = t->reordered_opaque; -+ frame->pkt_pos = t->pkt_pos; -+ frame->pkt_duration = t->pkt_duration; -+ frame->pkt_size = t->pkt_size; + -+ s->last_opaque = s->track_els[n].reordered_opaque; -+ s->track_els[n].pts = AV_NOPTS_VALUE; // If we hit this again deny accurate knowledge of PTS -+ } -+ else -+ { -+ av_log(avctx, AV_LOG_DEBUG, "Discard frame (flushed): pts=%" PRId64 ", track[%d]=%" PRId64 "\n", frame->pts, n, t->track_pts); -+ return -1; -+ } ++ // If we never get any ideas about PTS vs DTS allow a lot more buffer ++ if (now == AV_NOPTS_VALUE) ++ r -= 16; + -+#if FF_API_PKT_PTS -+FF_DISABLE_DEPRECATION_WARNINGS -+ frame->pkt_pts = frame->pts; -+FF_ENABLE_DEPRECATION_WARNINGS -+#endif -+ frame->best_effort_timestamp = frame->pts; -+ frame->pkt_dts = frame->pts; // We can't emulate what s/w does in a useful manner? -+ av_log(avctx, AV_LOG_TRACE, "Out PTS=%" PRId64 ", DTS=%" PRId64 "\n", frame->pts, frame->pkt_dts); -+ return 0; ++ return r; +} + +static inline int stream_started(const V4L2m2mContext * const s) { -+ return s->capture.streamon && s->output.streamon; ++ return s->output.streamon; +} + +#define NQ_OK 0 +#define NQ_Q_FULL 1 +#define NQ_SRC_EMPTY 2 -+#define NQ_DRAINING 3 -+#define NQ_DEAD 4 ++#define NQ_NONE 3 ++#define NQ_DRAINING 4 ++#define NQ_DEAD 5 + +#define TRY_DQ(nq_status) ((nq_status) >= NQ_OK && (nq_status) <= NQ_DRAINING) ++#define RETRY_NQ(nq_status) ((nq_status) == NQ_Q_FULL || (nq_status) == NQ_NONE) ++ ++// do_not_get If true then no new packet will be got but status will ++// be set appropriately + +// AVERROR_EOF Flushing an already flushed stream +// -ve Error (all errors except EOF are unexpected) +// NQ_OK (0) OK +// NQ_Q_FULL Dst full (retry if we think V4L2 Q has space now) +// NQ_SRC_EMPTY Src empty (do not retry) ++// NQ_NONE Enqueue not attempted +// NQ_DRAINING At EOS, dQ dest until EOS there too +// NQ_DEAD Not running (do not retry, do not attempt capture dQ) + -+static int try_enqueue_src(AVCodecContext * const avctx, V4L2m2mContext * const s) ++static int try_enqueue_src(AVCodecContext * const avctx, V4L2m2mContext * const s, const int do_not_get) { - V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context; - V4L2Context *const capture = &s->capture; - V4L2Context *const output = &s->output; - AVPacket avpkt = {0}; int ret; - + - if (s->buf_pkt.size) { - avpkt = s->buf_pkt; - memset(&s->buf_pkt, 0, sizeof(AVPacket)); @@ -48498,8 +52950,50 @@ Upstream-status: Pending + // If we don't already have a coded packet - get a new one + // We will already have a coded pkt if the output Q was full last time we + // tried to Q it -+ if (!s->buf_pkt.size) { -+ ret = ff_decode_get_packet(avctx, &s->buf_pkt); ++ if (!s->buf_pkt.size && !do_not_get) { ++ unsigned int i; ++ ++ for (i = 0; i < 256; ++i) { ++ uint8_t * side_data; ++#if FF_API_BUFFER_SIZE_T ++ int side_size; ++#else ++ size_t side_size; ++#endif ++ ret = ff_decode_get_packet(avctx, &s->buf_pkt); ++ if (ret != 0) ++ break; ++ ++ // New extradata is the only side-data we undertand ++ side_data = av_packet_get_side_data(&s->buf_pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size); ++ if (side_data) { ++ av_log(avctx, AV_LOG_DEBUG, "New extradata\n"); ++ av_freep(&s->extdata_data); ++ if ((s->extdata_data = av_malloc(side_size ? side_size : 1)) == NULL) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to alloc %d bytes of extra data\n", (int)side_size); ++ return AVERROR(ENOMEM); ++ } ++ memcpy(s->extdata_data, side_data, side_size); ++ s->extdata_size = side_size; ++ s->extdata_sent = 0; ++ } ++ ++ if (s->buf_pkt.size != 0) ++ break; ++ ++ if (s->buf_pkt.side_data_elems == 0) { ++ av_log(avctx, AV_LOG_WARNING, "Empty pkt from ff_decode_get_packet - treating as EOF\n"); ++ ret = AVERROR_EOF; ++ break; ++ } ++ ++ // Retry a side-data only pkt ++ } ++ // If i >= 256 something has gone wrong ++ if (i >= 256) { ++ av_log(avctx, AV_LOG_ERROR, "Too many side-data only packets\n"); ++ return AVERROR(EIO); ++ } + + if (ret == AVERROR(EAGAIN)) { + if (!stream_started(s)) { @@ -48523,7 +53017,7 @@ Upstream-status: Pending + if (!s->draining) { + // Calling enqueue with an empty pkt starts drain + av_assert0(s->buf_pkt.size == 0); -+ ret = ff_v4l2_context_enqueue_packet(&s->output, &s->buf_pkt, NULL, 0, 1); ++ ret = ff_v4l2_context_enqueue_packet(&s->output, &s->buf_pkt, NULL, 0); + if (ret) { + av_log(avctx, AV_LOG_ERROR, "Failed to start drain: ret=%d\n", ret); + return ret; @@ -48536,22 +53030,37 @@ Upstream-status: Pending + av_log(avctx, AV_LOG_ERROR, "Failed to get coded packet: err=%d\n", ret); return ret; + } -+ -+ xlat_pts_in(avctx, s, &s->buf_pkt); } - + - if (s->draining) - goto dequeue; -+ if ((ret = check_output_streamon(avctx, s)) != 0) -+ return ret; - ++ if (s->draining) { ++ if (s->buf_pkt.size) { ++ av_log(avctx, AV_LOG_WARNING, "Unexpected input whilst draining\n"); ++ av_packet_unref(&s->buf_pkt); ++ } ++ return NQ_DRAINING; ++ } + - ret = ff_v4l2_context_enqueue_packet(output, &avpkt); - if (ret < 0) { - if (ret != AVERROR(EAGAIN)) - return ret; -+ ret = ff_v4l2_context_enqueue_packet(&s->output, &s->buf_pkt, -+ avctx->extradata, s->extdata_sent ? 0 : avctx->extradata_size, -+ 1); ++ if (!s->buf_pkt.size) ++ return NQ_NONE; + +- s->buf_pkt = avpkt; +- /* no input buffers available, continue dequeing */ +- } ++ if ((ret = check_output_streamon(avctx, s)) != 0) ++ return ret; ++ ++ if (s->extdata_sent) ++ ret = ff_v4l2_context_enqueue_packet(&s->output, &s->buf_pkt, NULL, 0); ++ else if (s->extdata_data) ++ ret = ff_v4l2_context_enqueue_packet(&s->output, &s->buf_pkt, s->extdata_data, s->extdata_size); ++ else ++ ret = ff_v4l2_context_enqueue_packet(&s->output, &s->buf_pkt, avctx->extradata, avctx->extradata_size); + + if (ret == AVERROR(EAGAIN)) { + // Out of input buffers - keep packet @@ -48561,19 +53070,19 @@ Upstream-status: Pending + // In all other cases we are done with this packet + av_packet_unref(&s->buf_pkt); + s->extdata_sent = 1; - -- s->buf_pkt = avpkt; -- /* no input buffers available, continue dequeing */ -+ if (ret) { -+ av_log(avctx, AV_LOG_ERROR, "Packet enqueue failure: err=%d\n", ret); -+ return ret; -+ } - } - + - if (avpkt.size) { - ret = v4l2_try_start(avctx); -- if (ret) { + if (ret) { - av_packet_unref(&avpkt); ++ av_log(avctx, AV_LOG_ERROR, "Packet enqueue failure: err=%d\n", ret); ++ return ret; ++ } ++ } + +- /* cant recover */ +- if (ret == AVERROR(ENOMEM)) +- return ret; + // Start if we haven't + { + const int ret2 = v4l2_try_start(avctx); @@ -48582,62 +53091,139 @@ Upstream-status: Pending + ret = (ret2 == AVERROR(ENOMEM)) ? ret2 : NQ_DEAD; + } + } - -- /* cant recover */ -- if (ret == AVERROR(ENOMEM)) -- return ret; ++ + return ret; +} - ++ ++static int qbuf_wait(AVCodecContext * const avctx, V4L2Context * const ctx) ++{ ++ int rv = 0; + - return 0; ++ ff_mutex_lock(&ctx->lock); ++ ++ while (atomic_load(&ctx->q_count) == 0 && ctx->streamon) { ++ if (pthread_cond_wait(&ctx->cond, &ctx->lock) != 0) { ++ rv = AVERROR(errno); ++ av_log(avctx, AV_LOG_ERROR, "Cond wait failure: %s\n", av_err2str(rv)); ++ break; + } + } + +-dequeue: +- if (!s->buf_pkt.size) +- av_packet_unref(&avpkt); +- return ff_v4l2_context_dequeue_frame(capture, frame, -1); ++ ff_mutex_unlock(&ctx->lock); ++ return rv; ++} ++ ++// Number of frames over what xlat_pending returns that we keep *16 ++// This is a min value - if it appears to be too small the threshold should ++// adjust dynamically. ++#define PENDING_HW_MIN (3 * 16) ++// Offset to use when setting dynamically ++// Set to %16 == 15 to avoid the threshold changing immediately as we relax ++#define PENDING_HW_OFFSET (PENDING_HW_MIN - 1) ++// Number of consecutive times we've failed to get a frame when we prefer it ++// before we increase the prefer threshold (5ms * N = max expected decode ++// time) ++#define PENDING_N_THRESHOLD 6 ++ +static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame) +{ + V4L2m2mContext *const s = ((V4L2m2mPriv*)avctx->priv_data)->context; -+ int src_rv; ++ int src_rv = NQ_OK; + int dst_rv = 1; // Non-zero (done), non-negative (error) number ++ unsigned int i = 0; + + do { -+ src_rv = try_enqueue_src(avctx, s); -+ -+ // If we got a frame last time and we have nothing to enqueue then -+ // return now. rv will be AVERROR(EAGAIN) indicating that we want more input ++ const int pending = xlat_pending(&s->xlat); ++ const int prefer_dq = (pending > s->pending_hw / 16); ++ const int last_src_rv = src_rv; ++ ++ // Enqueue another pkt for decode if ++ // (a) We don't have a lot of stuff in the buffer already OR ++ // (b) ... we (think we) do but we've failed to get a frame already OR ++ // (c) We've dequeued a lot of frames without asking for input ++ src_rv = try_enqueue_src(avctx, s, !(!prefer_dq || i != 0 || s->req_pkt > 2)); ++ ++ // If we got a frame last time or we've already tried to get a frame and ++ // we have nothing to enqueue then return now. rv will be AVERROR(EAGAIN) ++ // indicating that we want more input. + // This should mean that once decode starts we enter a stable state where + // we alternately ask for input and produce output -+ if (s->req_pkt && src_rv == NQ_SRC_EMPTY) ++ if ((i != 0 || s->req_pkt) && src_rv == NQ_SRC_EMPTY) + break; + -+ if (src_rv == NQ_Q_FULL && dst_rv == AVERROR(EAGAIN)) { -+ av_log(avctx, AV_LOG_WARNING, "Poll says src Q has space but enqueue fail"); -+ src_rv = NQ_SRC_EMPTY; // If we can't enqueue pretend that there is nothing to enqueue ++ if (src_rv == NQ_Q_FULL && last_src_rv == NQ_Q_FULL) { ++ av_log(avctx, AV_LOG_WARNING, "Poll thinks src Q has space; none found\n"); ++ break; + } + + // Try to get a new frame if + // (a) we haven't already got one AND + // (b) enqueue returned a status indicating that decode should be attempted + if (dst_rv != 0 && TRY_DQ(src_rv)) { -+ do { -+ // Dequeue frame will unref any previous contents of frame -+ // if it returns success so we don't need an explicit unref -+ // when discarding -+ // This returns AVERROR(EAGAIN) if there isn't a frame ready yet -+ // but there is room in the input Q -+ dst_rv = ff_v4l2_context_dequeue_frame(&s->capture, frame, -1, 1); ++ // Pick a timeout depending on state ++ const int t = ++ src_rv == NQ_DRAINING ? 300 : ++ prefer_dq ? 5 : ++ src_rv == NQ_Q_FULL ? -1 : 0; ++ ++ // Dequeue frame will unref any previous contents of frame ++ // if it returns success so we don't need an explicit unref ++ // when discarding ++ // This returns AVERROR(EAGAIN) on timeout or if ++ // there is room in the input Q and timeout == -1 ++ dst_rv = ff_v4l2_context_dequeue_frame(&s->capture, frame, t); ++ ++ // Failure due to no buffer in Q? ++ if (dst_rv == AVERROR(ENOSPC)) { ++ // Wait & retry ++ if ((dst_rv = qbuf_wait(avctx, &s->capture)) == 0) { ++ dst_rv = ff_v4l2_context_dequeue_frame(&s->capture, frame, t); ++ } ++ } + -+ if (dst_rv == AVERROR_EOF && (s->draining || s->capture.done)) -+ av_log(avctx, AV_LOG_DEBUG, "Dequeue EOF: draining=%d, cap.done=%d\n", -+ s->draining, s->capture.done); -+ else if (dst_rv && dst_rv != AVERROR(EAGAIN)) -+ av_log(avctx, AV_LOG_ERROR, "Packet dequeue failure: draining=%d, cap.done=%d, err=%d\n", -+ s->draining, s->capture.done, dst_rv); ++ // Adjust dynamic pending threshold ++ if (dst_rv == 0) { ++ if (--s->pending_hw < PENDING_HW_MIN) ++ s->pending_hw = PENDING_HW_MIN; ++ s->pending_n = 0; + -+ // Go again if we got a frame that we need to discard -+ } while (dst_rv == 0 && xlat_pts_out(avctx, s, frame)); ++ set_best_effort_pts(avctx, &s->pts_stat, frame); ++ } ++ else if (dst_rv == AVERROR(EAGAIN)) { ++ if (prefer_dq && ++s->pending_n > PENDING_N_THRESHOLD) { ++ s->pending_hw = pending * 16 + PENDING_HW_OFFSET; ++ s->pending_n = 0; ++ } ++ } ++ ++ if (dst_rv == AVERROR(EAGAIN) && src_rv == NQ_DRAINING) { ++ av_log(avctx, AV_LOG_WARNING, "Timeout in drain - assume EOF"); ++ dst_rv = AVERROR_EOF; ++ s->capture.done = 1; ++ } ++ else if (dst_rv == AVERROR_EOF && (s->draining || s->capture.done)) ++ av_log(avctx, AV_LOG_DEBUG, "Dequeue EOF: draining=%d, cap.done=%d\n", ++ s->draining, s->capture.done); ++ else if (dst_rv && dst_rv != AVERROR(EAGAIN)) ++ av_log(avctx, AV_LOG_ERROR, "Packet dequeue failure: draining=%d, cap.done=%d, err=%d\n", ++ s->draining, s->capture.done, dst_rv); ++ } ++ ++ ++i; ++ if (i >= 256) { ++ av_log(avctx, AV_LOG_ERROR, "Unexpectedly large retry count: %d\n", i); ++ src_rv = AVERROR(EIO); + } + + // Continue trying to enqueue packets if either + // (a) we succeeded last time OR -+ // (b) enqueue failed due to input Q full AND there is now room -+ } while (src_rv == NQ_OK || (src_rv == NQ_Q_FULL && dst_rv == AVERROR(EAGAIN)) ); ++ // (b) we didn't ret a frame and we can retry the input ++ } while (src_rv == NQ_OK || (dst_rv == AVERROR(EAGAIN) && RETRY_NQ(src_rv))); + + // Ensure that the frame contains nothing if we aren't returning a frame + // (might happen when discarding) @@ -48645,7 +53231,7 @@ Upstream-status: Pending + av_frame_unref(frame); + + // If we got a frame this time ask for a pkt next time -+ s->req_pkt = (dst_rv == 0); ++ s->req_pkt = (dst_rv == 0) ? s->req_pkt + 1 : 0; + +#if 0 + if (dst_rv == 0) @@ -48655,8 +53241,8 @@ Upstream-status: Pending + av_log(avctx, AV_LOG_ERROR, "Streamoff and die?\n"); + ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF); + return -1; - } - } ++ } ++ } +#endif + + return dst_rv == 0 ? 0 : @@ -48687,18 +53273,113 @@ Upstream-status: Pending +} +#endif + ++static int ++check_size(AVCodecContext * const avctx, V4L2m2mContext * const s) ++{ ++ unsigned int i; ++ const uint32_t fcc = ff_v4l2_get_format_pixelformat(&s->capture.format); ++ const uint32_t w = avctx->coded_width; ++ const uint32_t h = avctx->coded_height; ++ ++ if (w == 0 || h == 0 || fcc == 0) { ++ av_log(avctx, AV_LOG_TRACE, "%s: Size %dx%d or fcc %s empty\n", __func__, w, h, av_fourcc2str(fcc)); ++ return 0; ++ } ++ if ((s->quirks & FF_V4L2_QUIRK_ENUM_FRAMESIZES_BROKEN) != 0) { ++ av_log(avctx, AV_LOG_TRACE, "%s: Skipped (quirk): Size %dx%d, fcc %s\n", __func__, w, h, av_fourcc2str(fcc)); ++ return 0; ++ } ++ ++ for (i = 0;; ++i) { ++ struct v4l2_frmsizeenum fs = { ++ .index = i, ++ .pixel_format = fcc, ++ }; ++ ++ while (ioctl(s->fd, VIDIOC_ENUM_FRAMESIZES, &fs) != 0) { ++ const int err = AVERROR(errno); ++ if (err == AVERROR(EINTR)) ++ continue; ++ if (i == 0 && err == AVERROR(ENOTTY)) { ++ av_log(avctx, AV_LOG_DEBUG, "Framesize enum not supported\n"); ++ return 0; ++ } ++ if (err != AVERROR(EINVAL)) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to enum framesizes: %s", av_err2str(err)); ++ return err; ++ } ++ av_log(avctx, AV_LOG_WARNING, "Failed to find Size=%dx%d, fmt=%s in %u frame size enums\n", ++ w, h, av_fourcc2str(fcc), i); ++ return err; ++ } ++ ++ switch (fs.type) { ++ case V4L2_FRMSIZE_TYPE_DISCRETE: ++ av_log(avctx, AV_LOG_TRACE, "%s[%d]: Discrete: %dx%d\n", __func__, i, ++ fs.discrete.width,fs.discrete.height); ++ if (w == fs.discrete.width && h == fs.discrete.height) ++ return 0; ++ break; ++ case V4L2_FRMSIZE_TYPE_STEPWISE: ++ av_log(avctx, AV_LOG_TRACE, "%s[%d]: Stepwise: Min: %dx%d Max: %dx%d, Step: %dx%d\n", __func__, i, ++ fs.stepwise.min_width, fs.stepwise.min_height, ++ fs.stepwise.max_width, fs.stepwise.max_height, ++ fs.stepwise.step_width,fs.stepwise.step_height); ++ if (w >= fs.stepwise.min_width && w <= fs.stepwise.max_width && ++ h >= fs.stepwise.min_height && h <= fs.stepwise.max_height && ++ (w - fs.stepwise.min_width) % fs.stepwise.step_width == 0 && ++ (h - fs.stepwise.min_height) % fs.stepwise.step_height == 0) ++ return 0; ++ break; ++ case V4L2_FRMSIZE_TYPE_CONTINUOUS: ++ av_log(avctx, AV_LOG_TRACE, "%s[%d]: Continuous: Min: %dx%d Max: %dx%d, Step: %dx%d\n", __func__, i, ++ fs.stepwise.min_width, fs.stepwise.min_height, ++ fs.stepwise.max_width, fs.stepwise.max_height, ++ fs.stepwise.step_width,fs.stepwise.step_height); ++ if (w >= fs.stepwise.min_width && w <= fs.stepwise.max_width && ++ h >= fs.stepwise.min_height && h <= fs.stepwise.max_height) ++ return 0; ++ break; ++ default: ++ av_log(avctx, AV_LOG_ERROR, "Unexpected framesize enum: %d", fs.type); ++ return AVERROR(EINVAL); ++ } ++ } ++} ++ ++static int ++get_quirks(AVCodecContext * const avctx, V4L2m2mContext * const s) ++{ ++ struct v4l2_capability cap; ++ ++ memset(&cap, 0, sizeof(cap)); ++ while (ioctl(s->fd, VIDIOC_QUERYCAP, &cap) != 0) { ++ int err = errno; ++ if (err == EINTR) ++ continue; ++ av_log(avctx, AV_LOG_ERROR, "V4L2: Failed to get capabilities: %s\n", strerror(err)); ++ return AVERROR(err); ++ } ++ ++ // Could be made table driven if we have a few more but right now there ++ // seems no point ++ ++ // Meson (amlogic) always gives a resolution changed event after output ++ // streamon and userspace must (re)allocate capture buffers and streamon ++ // capture to clear the event even if the capture buffers were the right ++ // size in the first place. ++ if (strcmp(cap.driver, "meson-vdec") == 0) ++ s->quirks |= FF_V4L2_QUIRK_REINIT_ALWAYS | FF_V4L2_QUIRK_ENUM_FRAMESIZES_BROKEN; ++ ++ av_log(avctx, AV_LOG_DEBUG, "Driver '%s': Quirks=%#x\n", cap.driver, s->quirks); ++ return 0; ++} ++ ++// This heuristic is for H264 but use for everything +static uint32_t max_coded_size(const AVCodecContext * const avctx) +{ + uint32_t wxh = avctx->coded_width * avctx->coded_height; + uint32_t size; - --dequeue: -- if (!s->buf_pkt.size) -- av_packet_unref(&avpkt); -- return ff_v4l2_context_dequeue_frame(capture, frame, -1); -+ // Currently the only thing we try to set our own limits for is H264 -+ if (avctx->codec_id != AV_CODEC_ID_H264) -+ return 0; + + size = wxh * 3 / 2; + // H.264 Annex A table A-1 gives minCR which is either 2 or 4 @@ -48711,27 +53392,53 @@ Upstream-status: Pending + // with small WxH + return size + (1 << 16); } - + static av_cold int v4l2_decode_init(AVCodecContext *avctx) -@@ -186,8 +481,12 @@ static av_cold int v4l2_decode_init(AVCo +@@ -186,12 +699,29 @@ static av_cold int v4l2_decode_init(AVCo V4L2Context *capture, *output; V4L2m2mContext *s; V4L2m2mPriv *priv = avctx->priv_data; + int gf_pix_fmt; int ret; - + + av_log(avctx, AV_LOG_TRACE, "<<< %s\n", __func__); + ++ if (avctx->codec_id == AV_CODEC_ID_H264) { ++ if (avctx->ticks_per_frame == 1) { ++ if(avctx->time_base.den < INT_MAX/2) { ++ avctx->time_base.den *= 2; ++ } else ++ avctx->time_base.num /= 2; ++ } ++ avctx->ticks_per_frame = 2; ++ } ++ + av_log(avctx, AV_LOG_INFO, "level=%d\n", avctx->level); ret = ff_v4l2_m2m_create_context(priv, &s); if (ret < 0) return ret; -@@ -204,17 +503,43 @@ static av_cold int v4l2_decode_init(AVCo - + ++ pts_stats_init(&s->pts_stat, avctx, "decoder"); ++ s->pending_hw = PENDING_HW_MIN; ++ + capture = &s->capture; + output = &s->output; + +@@ -199,34 +729,127 @@ static av_cold int v4l2_decode_init(AVCo + * by the v4l2 driver; this event will trigger a full pipeline reconfig and + * the proper values will be retrieved from the kernel driver. + */ +- output->height = capture->height = avctx->coded_height; +- output->width = capture->width = avctx->coded_width; ++// output->height = capture->height = avctx->coded_height; ++// output->width = capture->width = avctx->coded_width; ++ output->height = capture->height = 0; ++ output->width = capture->width = 0; + output->av_codec_id = avctx->codec_id; output->av_pix_fmt = AV_PIX_FMT_NONE; + output->min_buf_size = max_coded_size(avctx); - + capture->av_codec_id = AV_CODEC_ID_RAWVIDEO; capture->av_pix_fmt = avctx->pix_fmt; + capture->min_buf_size = 0; @@ -48743,15 +53450,21 @@ Upstream-status: Pending + * check the v4l2_get_drm_frame function. + */ + ++ avctx->sw_pix_fmt = avctx->pix_fmt; + gf_pix_fmt = ff_get_format(avctx, avctx->codec->pix_fmts); -+ av_log(avctx, AV_LOG_DEBUG, "avctx requested=%d (%s); get_format requested=%d (%s)\n", -+ avctx->pix_fmt, av_get_pix_fmt_name(avctx->pix_fmt), gf_pix_fmt, av_get_pix_fmt_name(gf_pix_fmt)); ++ av_log(avctx, AV_LOG_DEBUG, "avctx requested=%d (%s) %dx%d; get_format requested=%d (%s)\n", ++ avctx->pix_fmt, av_get_pix_fmt_name(avctx->pix_fmt), ++ avctx->coded_width, avctx->coded_height, ++ gf_pix_fmt, av_get_pix_fmt_name(gf_pix_fmt)); + -+ s->output_drm = 0; + if (gf_pix_fmt == AV_PIX_FMT_DRM_PRIME || avctx->pix_fmt == AV_PIX_FMT_DRM_PRIME) { + avctx->pix_fmt = AV_PIX_FMT_DRM_PRIME; + s->output_drm = 1; + } ++ else { ++ capture->av_pix_fmt = gf_pix_fmt; ++ s->output_drm = 0; ++ } + + s->device_ref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_DRM); + if (!s->device_ref) { @@ -48762,7 +53475,7 @@ Upstream-status: Pending + ret = av_hwdevice_ctx_init(s->device_ref); + if (ret < 0) + return ret; - + s->avctx = avctx; ret = ff_v4l2_m2m_codec_init(priv); if (ret) { @@ -48772,15 +53485,24 @@ Upstream-status: Pending - return ret; } - -@@ -223,10 +548,53 @@ static av_cold int v4l2_decode_init(AVCo - + +- return v4l2_prepare_decoder(s); ++ if ((ret = v4l2_prepare_decoder(s)) < 0) ++ return ret; ++ ++ if ((ret = get_quirks(avctx, s)) != 0) ++ return ret; ++ ++ if ((ret = check_size(avctx, s)) != 0) ++ return ret; ++ ++ return 0; + } + static av_cold int v4l2_decode_close(AVCodecContext *avctx) { - V4L2m2mPriv *priv = avctx->priv_data; - V4L2m2mContext *s = priv->context; -- av_packet_unref(&s->buf_pkt); -- return ff_v4l2_m2m_codec_end(priv); + int rv; + av_log(avctx, AV_LOG_TRACE, "<<< %s\n", __func__); + rv = ff_v4l2_m2m_codec_end(avctx->priv_data); @@ -48802,7 +53524,6 @@ Upstream-status: Pending + V4L2m2mContext * const s = priv->context; + V4L2Context * const output = &s->output; + V4L2Context * const capture = &s->capture; -+ int ret, i; + + av_log(avctx, AV_LOG_TRACE, "<<< %s: streamon=%d\n", __func__, output->streamon); + @@ -48810,14 +53531,23 @@ Upstream-status: Pending + // states like EOS processing so don't try to optimize out (having got it + // wrong once) + -+ ret = ff_v4l2_context_set_status(output, VIDIOC_STREAMOFF); -+ if (ret < 0) -+ av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s error: %d\n", output->name, ret); ++ ff_v4l2_context_set_status(output, VIDIOC_STREAMOFF); ++ ++ // Clear any buffered input packet + av_packet_unref(&s->buf_pkt); +- return ff_v4l2_m2m_codec_end(priv); ++ ++ // Clear a pending EOS ++ if (ff_v4l2_ctx_eos(capture)) { ++ // Arguably we could delay this but this is easy and doesn't require ++ // thought or extra vars ++ ff_v4l2_context_set_status(capture, VIDIOC_STREAMOFF); ++ ff_v4l2_context_set_status(capture, VIDIOC_STREAMON); ++ } + + // V4L2 makes no guarantees about whether decoded frames are flushed or not + // so mark all frames we are tracking to be discarded if they appear -+ for (i = 0; i != FF_V4L2_M2M_TRACK_SIZE; ++i) -+ s->track_els[i].discard = 1; ++ xlat_flush(&s->xlat); + + // resend extradata + s->extdata_sent = 0; @@ -48829,9 +53559,9 @@ Upstream-status: Pending + // Stream on will occur when we actually submit a new frame + av_log(avctx, AV_LOG_TRACE, ">>> %s\n", __func__); } - + #define OFFSET(x) offsetof(V4L2m2mPriv, x) -@@ -235,10 +603,16 @@ static av_cold int v4l2_decode_close(AVC +@@ -235,10 +858,16 @@ static av_cold int v4l2_decode_close(AVC static const AVOption options[] = { V4L_M2M_DEFAULT_OPTS, { "num_capture_buffers", "Number of buffers in the capture context", @@ -48840,7 +53570,7 @@ Upstream-status: Pending + { "pixel_format", "Pixel format to be used by the decoder", OFFSET(pix_fmt), AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_NONE}, AV_PIX_FMT_NONE, AV_PIX_FMT_NB, FLAGS }, { NULL}, }; - + +static const AVCodecHWConfigInternal *v4l2_m2m_hw_configs[] = { + HW_CONFIG_INTERNAL(DRM_PRIME), + NULL @@ -48849,7 +53579,7 @@ Upstream-status: Pending #define M2MDEC_CLASS(NAME) \ static const AVClass v4l2_m2m_ ## NAME ## _dec_class = { \ .class_name = #NAME "_v4l2m2m_decoder", \ -@@ -259,9 +633,15 @@ static const AVOption options[] = { +@@ -259,9 +888,15 @@ static const AVOption options[] = { .init = v4l2_decode_init, \ .receive_frame = v4l2_receive_frame, \ .close = v4l2_decode_close, \ @@ -48865,7 +53595,366 @@ Upstream-status: Pending + .hw_configs = v4l2_m2m_hw_configs, \ .wrapper_name = "v4l2m2m", \ } - + +--- a/libavcodec/v4l2_m2m_enc.c ++++ b/libavcodec/v4l2_m2m_enc.c +@@ -24,6 +24,8 @@ + #include <linux/videodev2.h> + #include <sys/ioctl.h> + #include <search.h> ++#include <drm_fourcc.h> ++ + #include "libavcodec/avcodec.h" + #include "libavcodec/internal.h" + #include "libavutil/pixdesc.h" +@@ -37,6 +39,34 @@ + #define MPEG_CID(x) V4L2_CID_MPEG_VIDEO_##x + #define MPEG_VIDEO(x) V4L2_MPEG_VIDEO_##x + ++// P030 should be defined in drm_fourcc.h and hopefully will be sometime ++// in the future but until then... ++#ifndef DRM_FORMAT_P030 ++#define DRM_FORMAT_P030 fourcc_code('P', '0', '3', '0') ++#endif ++ ++#ifndef DRM_FORMAT_NV15 ++#define DRM_FORMAT_NV15 fourcc_code('N', 'V', '1', '5') ++#endif ++ ++#ifndef DRM_FORMAT_NV20 ++#define DRM_FORMAT_NV20 fourcc_code('N', 'V', '2', '0') ++#endif ++ ++#ifndef V4L2_CID_CODEC_BASE ++#define V4L2_CID_CODEC_BASE V4L2_CID_MPEG_BASE ++#endif ++ ++// V4L2_PIX_FMT_NV12_10_COL128 and V4L2_PIX_FMT_NV12_COL128 should be defined ++// in videodev2.h hopefully will be sometime in the future but until then... ++#ifndef V4L2_PIX_FMT_NV12_10_COL128 ++#define V4L2_PIX_FMT_NV12_10_COL128 v4l2_fourcc('N', 'C', '3', '0') ++#endif ++ ++#ifndef V4L2_PIX_FMT_NV12_COL128 ++#define V4L2_PIX_FMT_NV12_COL128 v4l2_fourcc('N', 'C', '1', '2') /* 12 Y/CbCr 4:2:0 128 pixel wide column */ ++#endif ++ + static inline void v4l2_set_timeperframe(V4L2m2mContext *s, unsigned int num, unsigned int den) + { + struct v4l2_streamparm parm = { 0 }; +@@ -147,15 +177,14 @@ static inline int v4l2_mpeg4_profile_fro + static int v4l2_check_b_frame_support(V4L2m2mContext *s) + { + if (s->avctx->max_b_frames) +- av_log(s->avctx, AV_LOG_WARNING, "Encoder does not support b-frames yet\n"); ++ av_log(s->avctx, AV_LOG_WARNING, "Encoder does not support %d b-frames yet\n", s->avctx->max_b_frames); + +- v4l2_set_ext_ctrl(s, MPEG_CID(B_FRAMES), 0, "number of B-frames", 0); ++ v4l2_set_ext_ctrl(s, MPEG_CID(B_FRAMES), s->avctx->max_b_frames, "number of B-frames", 1); + v4l2_get_ext_ctrl(s, MPEG_CID(B_FRAMES), &s->avctx->max_b_frames, "number of B-frames", 0); + if (s->avctx->max_b_frames == 0) + return 0; + + avpriv_report_missing_feature(s->avctx, "DTS/PTS calculation for V4L2 encoding"); +- + return AVERROR_PATCHWELCOME; + } + +@@ -270,13 +299,184 @@ static int v4l2_prepare_encoder(V4L2m2mC + return 0; + } + ++static int avdrm_to_v4l2(struct v4l2_format * const format, const AVFrame * const frame) ++{ ++ const AVDRMFrameDescriptor *const src = (const AVDRMFrameDescriptor *)frame->data[0]; ++ ++ const uint32_t drm_fmt = src->layers[0].format; ++ // Treat INVALID as LINEAR ++ const uint64_t mod = src->objects[0].format_modifier == DRM_FORMAT_MOD_INVALID ? ++ DRM_FORMAT_MOD_LINEAR : src->objects[0].format_modifier; ++ uint32_t pix_fmt = 0; ++ uint32_t w = 0; ++ uint32_t h = 0; ++ uint32_t bpl = src->layers[0].planes[0].pitch; ++ ++ // We really don't expect multiple layers ++ // All formats that we currently cope with are single object ++ ++ if (src->nb_layers != 1 || src->nb_objects != 1) ++ return AVERROR(EINVAL); ++ ++ switch (drm_fmt) { ++ case DRM_FORMAT_YUV420: ++ if (mod == DRM_FORMAT_MOD_LINEAR) { ++ if (src->layers[0].nb_planes != 3) ++ break; ++ pix_fmt = V4L2_PIX_FMT_YUV420; ++ h = src->layers[0].planes[1].offset / bpl; ++ w = bpl; ++ } ++ break; ++ ++ case DRM_FORMAT_NV12: ++ if (mod == DRM_FORMAT_MOD_LINEAR) { ++ if (src->layers[0].nb_planes != 2) ++ break; ++ pix_fmt = V4L2_PIX_FMT_NV12; ++ h = src->layers[0].planes[1].offset / bpl; ++ w = bpl; ++ } ++ else if (fourcc_mod_broadcom_mod(mod) == DRM_FORMAT_MOD_BROADCOM_SAND128) { ++ if (src->layers[0].nb_planes != 2) ++ break; ++ pix_fmt = V4L2_PIX_FMT_NV12_COL128; ++ w = bpl; ++ h = src->layers[0].planes[1].offset / 128; ++ bpl = fourcc_mod_broadcom_param(mod); ++ } ++ break; ++ ++ case DRM_FORMAT_P030: ++ if (fourcc_mod_broadcom_mod(mod) == DRM_FORMAT_MOD_BROADCOM_SAND128) { ++ if (src->layers[0].nb_planes != 2) ++ break; ++ pix_fmt = V4L2_PIX_FMT_NV12_10_COL128; ++ w = bpl / 2; // Matching lie to how we construct this ++ h = src->layers[0].planes[1].offset / 128; ++ bpl = fourcc_mod_broadcom_param(mod); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (!pix_fmt) ++ return AVERROR(EINVAL); ++ ++ if (V4L2_TYPE_IS_MULTIPLANAR(format->type)) { ++ struct v4l2_pix_format_mplane *const pix = &format->fmt.pix_mp; ++ ++ pix->width = w; ++ pix->height = h; ++ pix->pixelformat = pix_fmt; ++ pix->plane_fmt[0].bytesperline = bpl; ++ pix->num_planes = 1; ++ } ++ else { ++ struct v4l2_pix_format *const pix = &format->fmt.pix; ++ ++ pix->width = w; ++ pix->height = h; ++ pix->pixelformat = pix_fmt; ++ pix->bytesperline = bpl; ++ } ++ ++ return 0; ++} ++ ++// Do we have similar enough formats to be usable? ++static int fmt_eq(const struct v4l2_format * const a, const struct v4l2_format * const b) ++{ ++ if (a->type != b->type) ++ return 0; ++ ++ if (V4L2_TYPE_IS_MULTIPLANAR(a->type)) { ++ const struct v4l2_pix_format_mplane *const pa = &a->fmt.pix_mp; ++ const struct v4l2_pix_format_mplane *const pb = &b->fmt.pix_mp; ++ unsigned int i; ++ if (pa->pixelformat != pb->pixelformat || ++ pa->num_planes != pb->num_planes) ++ return 0; ++ for (i = 0; i != pa->num_planes; ++i) { ++ if (pa->plane_fmt[i].bytesperline != pb->plane_fmt[i].bytesperline) ++ return 0; ++ } ++ } ++ else { ++ const struct v4l2_pix_format *const pa = &a->fmt.pix; ++ const struct v4l2_pix_format *const pb = &b->fmt.pix; ++ if (pa->pixelformat != pb->pixelformat || ++ pa->bytesperline != pb->bytesperline) ++ return 0; ++ } ++ return 1; ++} ++ ++ + static int v4l2_send_frame(AVCodecContext *avctx, const AVFrame *frame) + { + V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context; + V4L2Context *const output = &s->output; + ++ // Signal EOF if needed ++ if (!frame) { ++ return ff_v4l2_context_enqueue_frame(output, frame); ++ } ++ ++ if (s->input_drm && !output->streamon) { ++ int rv; ++ struct v4l2_format req_format = {.type = output->format.type}; ++ ++ // Set format when we first get a buffer ++ if ((rv = avdrm_to_v4l2(&req_format, frame)) != 0) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to get V4L2 format from DRM_PRIME frame\n"); ++ return rv; ++ } ++ ++ ff_v4l2_context_release(output); ++ ++ output->format = req_format; ++ ++ if ((rv = ff_v4l2_context_set_format(output)) != 0) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to set V4L2 format\n"); ++ return rv; ++ } ++ ++ if (!fmt_eq(&req_format, &output->format)) { ++ av_log(avctx, AV_LOG_ERROR, "Format mismatch after setup\n"); ++ return AVERROR(EINVAL); ++ } ++ ++ output->selection.top = frame->crop_top; ++ output->selection.left = frame->crop_left; ++ output->selection.width = av_frame_cropped_width(frame); ++ output->selection.height = av_frame_cropped_height(frame); ++ ++ if ((rv = ff_v4l2_context_init(output)) != 0) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to (re)init context\n"); ++ return rv; ++ } ++ ++ { ++ struct v4l2_selection selection = { ++ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT, ++ .target = V4L2_SEL_TGT_CROP, ++ .r = output->selection ++ }; ++ if (ioctl(s->fd, VIDIOC_S_SELECTION, &selection) != 0) { ++ av_log(avctx, AV_LOG_WARNING, "S_SELECTION (CROP) %dx%d @ %d,%d failed: %s\n", ++ selection.r.width, selection.r.height, selection.r.left, selection.r.top, ++ av_err2str(AVERROR(errno))); ++ } ++ av_log(avctx, AV_LOG_TRACE, "S_SELECTION (CROP) %dx%d @ %d,%d OK\n", ++ selection.r.width, selection.r.height, selection.r.left, selection.r.top); ++ } ++ } ++ + #ifdef V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME +- if (frame && frame->pict_type == AV_PICTURE_TYPE_I) ++ if (frame->pict_type == AV_PICTURE_TYPE_I) + v4l2_set_ext_ctrl(s, MPEG_CID(FORCE_KEY_FRAME), 0, "force key frame", 1); + #endif + +@@ -310,7 +510,70 @@ static int v4l2_receive_packet(AVCodecCo + } + + dequeue: +- return ff_v4l2_context_dequeue_packet(capture, avpkt); ++ if ((ret = ff_v4l2_context_dequeue_packet(capture, avpkt)) != 0) ++ return ret; ++ ++ if (capture->first_buf == 1) { ++ uint8_t * data; ++ const int len = avpkt->size; ++ ++ // 1st buffer after streamon should be SPS/PPS ++ capture->first_buf = 2; ++ ++ // Clear both possible stores so there is no chance of confusion ++ av_freep(&s->extdata_data); ++ s->extdata_size = 0; ++ av_freep(&avctx->extradata); ++ avctx->extradata_size = 0; ++ ++ if ((data = av_malloc(len + AV_INPUT_BUFFER_PADDING_SIZE)) != NULL) ++ memcpy(data, avpkt->data, len); ++ ++ av_packet_unref(avpkt); ++ ++ if (data == NULL) ++ return AVERROR(ENOMEM); ++ ++ // We need to copy the header, but keep local if not global ++ if ((avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) != 0) { ++ avctx->extradata = data; ++ avctx->extradata_size = len; ++ } ++ else { ++ s->extdata_data = data; ++ s->extdata_size = len; ++ } ++ ++ if ((ret = ff_v4l2_context_dequeue_packet(capture, avpkt)) != 0) ++ return ret; ++ } ++ ++ // First frame must be key so mark as such even if encoder forgot ++ if (capture->first_buf == 2) ++ avpkt->flags |= AV_PKT_FLAG_KEY; ++ ++ // Add SPS/PPS to the start of every key frame if non-global headers ++ if ((avpkt->flags & AV_PKT_FLAG_KEY) != 0 && s->extdata_size != 0) { ++ const size_t newlen = s->extdata_size + avpkt->size; ++ AVBufferRef * const buf = av_buffer_alloc(newlen + AV_INPUT_BUFFER_PADDING_SIZE); ++ ++ if (buf == NULL) { ++ av_packet_unref(avpkt); ++ return AVERROR(ENOMEM); ++ } ++ ++ memcpy(buf->data, s->extdata_data, s->extdata_size); ++ memcpy(buf->data + s->extdata_size, avpkt->data, avpkt->size); ++ ++ av_buffer_unref(&avpkt->buf); ++ avpkt->buf = buf; ++ avpkt->data = buf->data; ++ avpkt->size = newlen; ++ } ++ ++// av_log(avctx, AV_LOG_INFO, "%s: PTS out=%"PRId64", size=%d, ret=%d\n", __func__, avpkt->pts, avpkt->size, ret); ++ capture->first_buf = 0; ++ return 0; + } + + static av_cold int v4l2_encode_init(AVCodecContext *avctx) +@@ -322,6 +585,8 @@ static av_cold int v4l2_encode_init(AVCo + uint32_t v4l2_fmt_output; + int ret; + ++ av_log(avctx, AV_LOG_INFO, " <<< %s: fmt=%d/%d\n", __func__, avctx->pix_fmt, avctx->sw_pix_fmt); ++ + ret = ff_v4l2_m2m_create_context(priv, &s); + if (ret < 0) + return ret; +@@ -329,13 +594,17 @@ static av_cold int v4l2_encode_init(AVCo + capture = &s->capture; + output = &s->output; + ++ s->input_drm = (avctx->pix_fmt == AV_PIX_FMT_DRM_PRIME); ++ + /* common settings output/capture */ + output->height = capture->height = avctx->height; + output->width = capture->width = avctx->width; + + /* output context */ + output->av_codec_id = AV_CODEC_ID_RAWVIDEO; +- output->av_pix_fmt = avctx->pix_fmt; ++ output->av_pix_fmt = !s->input_drm ? avctx->pix_fmt : ++ avctx->sw_pix_fmt != AV_PIX_FMT_NONE ? avctx->sw_pix_fmt : ++ AV_PIX_FMT_YUV420P; + + /* capture context */ + capture->av_codec_id = avctx->codec_id; +@@ -354,7 +623,7 @@ static av_cold int v4l2_encode_init(AVCo + v4l2_fmt_output = output->format.fmt.pix.pixelformat; + + pix_fmt_output = ff_v4l2_format_v4l2_to_avfmt(v4l2_fmt_output, AV_CODEC_ID_RAWVIDEO); +- if (pix_fmt_output != avctx->pix_fmt) { ++ if (!s->input_drm && pix_fmt_output != avctx->pix_fmt) { + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt_output); + av_log(avctx, AV_LOG_ERROR, "Encoder requires %s pixel format.\n", desc->name); + return AVERROR(EINVAL); --- /dev/null +++ b/libavcodec/v4l2_req_decode_q.c @@ -0,0 +1,84 @@ @@ -49780,16 +54869,26 @@ Upstream-status: Pending +#include "v4l2_req_hevc_vx.c" + --- /dev/null ++++ b/libavcodec/v4l2_req_hevc_v3.c +@@ -0,0 +1,3 @@ ++#define HEVC_CTRLS_VERSION 3 ++#include "v4l2_req_hevc_vx.c" ++ +--- /dev/null ++++ b/libavcodec/v4l2_req_hevc_v4.c +@@ -0,0 +1,3 @@ ++#define HEVC_CTRLS_VERSION 4 ++#include "v4l2_req_hevc_vx.c" ++ +--- /dev/null +++ b/libavcodec/v4l2_req_hevc_vx.c -@@ -0,0 +1,1188 @@ +@@ -0,0 +1,1365 @@ +// File included by v4l2_req_hevc_v* - not compiled on its own + +#include "decode.h" +#include "hevcdec.h" +#include "hwconfig.h" + -+#include "v4l2_request_hevc.h" -+ +#if HEVC_CTRLS_VERSION == 1 +#include "hevc-ctrls-v1.h" + @@ -49798,10 +54897,39 @@ Upstream-status: Pending + +#elif HEVC_CTRLS_VERSION == 2 +#include "hevc-ctrls-v2.h" ++#elif HEVC_CTRLS_VERSION == 3 ++#include "hevc-ctrls-v3.h" ++#elif HEVC_CTRLS_VERSION == 4 ++#include <linux/v4l2-controls.h> ++#if !defined(V4L2_CID_STATELESS_HEVC_SPS) ++#include "hevc-ctrls-v4.h" ++#endif +#else +#error Unknown HEVC_CTRLS_VERSION +#endif + ++#ifndef V4L2_CID_STATELESS_HEVC_SPS ++#define V4L2_CID_STATELESS_HEVC_SPS V4L2_CID_MPEG_VIDEO_HEVC_SPS ++#define V4L2_CID_STATELESS_HEVC_PPS V4L2_CID_MPEG_VIDEO_HEVC_PPS ++#define V4L2_CID_STATELESS_HEVC_SLICE_PARAMS V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS ++#define V4L2_CID_STATELESS_HEVC_SCALING_MATRIX V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX ++#define V4L2_CID_STATELESS_HEVC_DECODE_PARAMS V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS ++#define V4L2_CID_STATELESS_HEVC_DECODE_MODE V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE ++#define V4L2_CID_STATELESS_HEVC_START_CODE V4L2_CID_MPEG_VIDEO_HEVC_START_CODE ++ ++#define V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED ++#define V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED ++#define V4L2_STATELESS_HEVC_START_CODE_NONE V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE ++#define V4L2_STATELESS_HEVC_START_CODE_ANNEX_B V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B ++#endif ++ ++// Should be in videodev2 but we might not have a good enough one ++#ifndef V4L2_PIX_FMT_HEVC_SLICE ++#define V4L2_PIX_FMT_HEVC_SLICE v4l2_fourcc('S', '2', '6', '5') /* HEVC parsed slices */ ++#endif ++ ++#include "v4l2_request_hevc.h" ++ +#include "libavutil/hwcontext_drm.h" + +#include <semaphore.h> @@ -49837,11 +54965,16 @@ Upstream-status: Pending + struct v4l2_ctrl_hevc_slice_params * slice_params; + struct slice_info * slices; + ++ size_t num_offsets; ++ size_t alloced_offsets; ++ uint32_t *offsets; ++ +} V4L2MediaReqDescriptor; + +struct slice_info { + const uint8_t * ptr; + size_t len; // bytes ++ size_t n_offsets; +}; + +// Handy container for accumulating controls before setting @@ -49929,6 +55062,7 @@ Upstream-status: Pending + } +} + ++#if HEVC_CTRLS_VERSION <= 2 +static int find_frame_rps_type(const HEVCContext *h, uint64_t timestamp) +{ + const HEVCFrame *frame; @@ -49954,6 +55088,7 @@ Upstream-status: Pending + + return 0; +} ++#endif + +static unsigned int +get_ref_pic_index(const HEVCContext *h, const HEVCFrame *frame, @@ -49998,7 +55133,7 @@ Upstream-status: Pending + if (rd->num_slices >= rd->alloced_slices) { + struct v4l2_ctrl_hevc_slice_params * p2; + struct slice_info * s2; -+ size_t n2 = rd->num_slices == 0 ? 8 : rd->num_slices * 2; ++ size_t n2 = rd->alloced_slices == 0 ? 8 : rd->alloced_slices * 2; + + p2 = av_realloc_array(rd->slice_params, n2, sizeof(*p2)); + if (p2 == NULL) @@ -50016,6 +55151,23 @@ Upstream-status: Pending + return 0; +} + ++static int offsets_add(V4L2MediaReqDescriptor *const rd, const size_t n, const unsigned * const offsets) ++{ ++ if (rd->num_offsets + n > rd->alloced_offsets) { ++ size_t n2 = rd->alloced_slices == 0 ? 128 : rd->alloced_slices * 2; ++ void * p2; ++ while (rd->num_offsets + n > n2) ++ n2 *= 2; ++ if ((p2 = av_realloc_array(rd->offsets, n2, sizeof(*rd->offsets))) == NULL) ++ return AVERROR(ENOMEM); ++ rd->offsets = p2; ++ rd->alloced_offsets = n2; ++ } ++ for (size_t i = 0; i != n; ++i) ++ rd->offsets[rd->num_offsets++] = offsets[i] - 1; ++ return 0; ++} ++ +static unsigned int +fill_dpb_entries(const HEVCContext * const h, struct v4l2_hevc_dpb_entry * const entries) +{ @@ -50029,12 +55181,21 @@ Upstream-status: Pending + struct v4l2_hevc_dpb_entry * const entry = entries + n++; + + entry->timestamp = frame_capture_dpb(frame->frame); ++#if HEVC_CTRLS_VERSION <= 2 + entry->rps = find_frame_rps_type(h, entry->timestamp); ++#else ++ entry->flags = (frame->flags & HEVC_FRAME_FLAG_LONG_REF) == 0 ? 0 : ++ V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE; ++#endif + entry->field_pic = frame->frame->interlaced_frame; + ++#if HEVC_CTRLS_VERSION <= 3 + /* TODO: Interleaved: Get the POC for each field. */ + entry->pic_order_cnt[0] = frame->poc; + entry->pic_order_cnt[1] = frame->poc; ++#else ++ entry->pic_order_cnt_val = frame->poc; ++#endif + } + } + return n; @@ -50060,8 +55221,11 @@ Upstream-status: Pending + + *slice_params = (struct v4l2_ctrl_hevc_slice_params) { + .bit_size = bit_size, ++#if HEVC_CTRLS_VERSION <= 3 + .data_bit_offset = bit_offset, -+ ++#else ++ .data_byte_offset = bit_offset / 8 + 1, ++#endif + /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ + .slice_segment_addr = sh->slice_segment_addr, + @@ -50144,6 +55308,7 @@ Upstream-status: Pending + fill_pred_table(h, &slice_params->pred_weight_table); + + slice_params->num_entry_point_offsets = sh->num_entry_point_offsets; ++#if HEVC_CTRLS_VERSION <= 3 + if (slice_params->num_entry_point_offsets > 256) { + slice_params->num_entry_point_offsets = 256; + av_log(NULL, AV_LOG_ERROR, "%s: Currently only 256 entry points are supported, but slice has %d entry points.\n", __func__, sh->num_entry_point_offsets); @@ -50151,6 +55316,7 @@ Upstream-status: Pending + + for (i = 0; i < slice_params->num_entry_point_offsets; i++) + slice_params->entry_point_offset_minus1[i] = sh->entry_point_offset[i] - 1; ++#endif +} + +#if HEVC_CTRLS_VERSION >= 2 @@ -50526,51 +55692,66 @@ Upstream-status: Pending +#if HEVC_CTRLS_VERSION >= 2 + struct v4l2_ctrl_hevc_decode_params * const dec, +#endif -+ struct v4l2_ctrl_hevc_slice_params * const slices, -+ const unsigned int slice_no, -+ const unsigned int slice_count) ++ struct v4l2_ctrl_hevc_slice_params * const slices, const unsigned int slice_count, ++ void * const offsets, const size_t offset_count) +{ + int rv; ++#if HEVC_CTRLS_VERSION >= 2 ++ unsigned int n = 3; ++#else ++ unsigned int n = 2; ++#endif + -+ struct v4l2_ext_control control[] = { ++ struct v4l2_ext_control control[6] = { + { -+ .id = V4L2_CID_MPEG_VIDEO_HEVC_SPS, ++ .id = V4L2_CID_STATELESS_HEVC_SPS, + .ptr = &controls->sps, + .size = sizeof(controls->sps), + }, + { -+ .id = V4L2_CID_MPEG_VIDEO_HEVC_PPS, ++ .id = V4L2_CID_STATELESS_HEVC_PPS, + .ptr = &controls->pps, + .size = sizeof(controls->pps), + }, +#if HEVC_CTRLS_VERSION >= 2 + { -+ .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS, ++ .id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS, + .ptr = dec, + .size = sizeof(*dec), + }, +#endif -+ { -+ .id = V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS, -+ .ptr = slices + slice_no, ++ }; ++ ++ if (slices) ++ control[n++] = (struct v4l2_ext_control) { ++ .id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS, ++ .ptr = slices, + .size = sizeof(*slices) * slice_count, -+ }, -+ // Optional -+ { -+ .id = V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX, ++ }; ++ ++ if (controls->has_scaling) ++ control[n++] = (struct v4l2_ext_control) { ++ .id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX, + .ptr = &controls->scaling_matrix, + .size = sizeof(controls->scaling_matrix), -+ }, -+ }; ++ }; + -+ rv = mediabufs_ctl_set_ext_ctrls(ctx->mbufs, mreq, control, -+ controls->has_scaling ? -+ FF_ARRAY_ELEMS(control) : -+ FF_ARRAY_ELEMS(control) - 1); ++#if HEVC_CTRLS_VERSION >= 4 ++ if (offsets) ++ control[n++] = (struct v4l2_ext_control) { ++ .id = V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS, ++ .ptr = offsets, ++ .size = sizeof(((struct V4L2MediaReqDescriptor *)0)->offsets[0]) * offset_count, ++ }; ++#endif ++ ++ rv = mediabufs_ctl_set_ext_ctrls(ctx->mbufs, mreq, control, n); + + return rv; +} + ++// This only works because we started out from a single coded frame buffer ++// that will remain intact until after end_frame +static int v4l2_request_hevc_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +{ + const HEVCContext * const h = avctx->priv_data; @@ -50579,18 +55760,45 @@ Upstream-status: Pending + int bcount = get_bits_count(&h->HEVClc->gb); + uint32_t boff = (ptr_from_index(buffer, bcount/8 + 1) - (buffer + bcount/8 + 1)) * 8 + bcount; + ++ const unsigned int n = rd->num_slices; ++ const unsigned int block_start = (n / ctx->max_slices) * ctx->max_slices; ++ + int rv; + struct slice_info * si; + ++ // This looks dodgy but we know that FFmpeg has parsed this from a buffer ++ // that contains the entire frame including the start code ++ if (ctx->start_code == V4L2_STATELESS_HEVC_START_CODE_ANNEX_B) { ++ buffer -= 3; ++ size += 3; ++ boff += 24; ++ if (buffer[0] != 0 || buffer[1] != 0 || buffer[2] != 1) { ++ av_log(avctx, AV_LOG_ERROR, "Start code requested but missing %02x:%02x:%02x\n", ++ buffer[0], buffer[1], buffer[2]); ++ } ++ } ++ ++ if (ctx->decode_mode == V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED) { ++ if (rd->slices == NULL) { ++ if ((rd->slices = av_mallocz(sizeof(*rd->slices))) == NULL) ++ return AVERROR(ENOMEM); ++ rd->slices->ptr = buffer; ++ rd->num_slices = 1; ++ } ++ rd->slices->len = buffer - rd->slices->ptr + size; ++ return 0; ++ } ++ + if ((rv = slice_add(rd)) != 0) + return rv; + -+ si = rd->slices + rd->num_slices - 1; ++ si = rd->slices + n; + si->ptr = buffer; + si->len = size; ++ si->n_offsets = rd->num_offsets; + -+ if (ctx->multi_slice && rd->num_slices > 1) { -+ struct slice_info *const si0 = rd->slices; ++ if (n != block_start) { ++ struct slice_info *const si0 = rd->slices + block_start; + const size_t offset = (buffer - si0->ptr); + boff += offset * 8; + size += offset; @@ -50598,12 +55806,15 @@ Upstream-status: Pending + } + +#if HEVC_CTRLS_VERSION >= 2 -+ if (rd->num_slices == 1) ++ if (n == 0) + fill_decode_params(h, &rd->dec); -+ fill_slice_params(h, &rd->dec, rd->slice_params + rd->num_slices - 1, size * 8, boff); ++ fill_slice_params(h, &rd->dec, rd->slice_params + n, size * 8, boff); +#else -+ fill_slice_params(h, rd->slice_params + rd->num_slices - 1, size * 8, boff); ++ fill_slice_params(h, rd->slice_params + n, size * 8, boff); +#endif ++ if (ctx->max_offsets != 0 && ++ (rv = offsets_add(rd, h->sh.num_entry_point_offsets, h->sh.entry_point_offset)) != 0) ++ return rv; + + return 0; +} @@ -50629,10 +55840,13 @@ Upstream-status: Pending +{ + V4L2RequestContextHEVC * const ctx = avctx->internal->hwaccel_priv_data; + ++ const int is_last = (j == rd->num_slices); + struct slice_info *const si = rd->slices + i; + struct media_request * req = NULL; + struct qent_src * src = NULL; + MediaBufsStatus stat; ++ void * offsets = rd->offsets + rd->slices[i].n_offsets; ++ size_t n_offsets = (is_last ? rd->num_offsets : rd->slices[j].n_offsets) - rd->slices[i].n_offsets; + + if ((req = media_request_get(ctx->mpool)) == NULL) { + av_log(avctx, AV_LOG_ERROR, "%s: Failed to alloc media request\n", __func__); @@ -50644,8 +55858,8 @@ Upstream-status: Pending +#if HEVC_CTRLS_VERSION >= 2 + &rd->dec, +#endif -+ rd->slice_params, -+ i, j - i)) { ++ rd->slice_params + i, j - i, ++ offsets, n_offsets)) { + av_log(avctx, AV_LOG_ERROR, "%s: Failed to set req ctls\n", __func__); + goto fail1; + } @@ -50665,13 +55879,9 @@ Upstream-status: Pending + goto fail2; + } + -+#warning ANNEX_B start code -+// if (ctx->start_code == V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B) { -+// } -+ + stat = mediabufs_start_request(ctx->mbufs, &req, &src, + i == 0 ? rd->qe_dst : NULL, -+ j == rd->num_slices); ++ is_last); + + if (stat != MEDIABUFS_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "%s: Failed to start request\n", __func__); @@ -50736,18 +55946,11 @@ Upstream-status: Pending + } + + // Send as slices -+ if (ctx->multi_slice) -+ { -+ if ((rv = send_slice(avctx, rd, &rc, 0, rd->num_slices)) != 0) ++ for (i = 0; i < rd->num_slices; i += ctx->max_slices) { ++ const unsigned int e = FFMIN(rd->num_slices, i + ctx->max_slices); ++ if ((rv = send_slice(avctx, rd, &rc, i, e)) != 0) + goto fail; + } -+ else -+ { -+ for (i = 0; i != rd->num_slices; ++i) { -+ if ((rv = send_slice(avctx, rd, &rc, i, i + 1)) != 0) -+ goto fail; -+ } -+ } + + // Set the drm_prime desriptor + drm_from_format(&rd->drm, mediabufs_dst_fmt(ctx->mbufs)); @@ -50762,6 +55965,12 @@ Upstream-status: Pending + return rv; +} + ++static inline int ++ctrl_valid(const struct v4l2_query_ext_ctrl * const c, const int64_t v) ++{ ++ return v >= c->minimum && v <= c->maximum; ++} ++ +// Initial check & init +static int +probe(AVCodecContext * const avctx, V4L2RequestContextHEVC * const ctx) @@ -50773,17 +55982,19 @@ Upstream-status: Pending + + // Check for var slice array + struct v4l2_query_ext_ctrl qc[] = { -+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS }, -+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_SPS }, -+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_PPS }, -+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX }, ++ { .id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS }, ++ { .id = V4L2_CID_STATELESS_HEVC_DECODE_MODE, }, ++ { .id = V4L2_CID_STATELESS_HEVC_SPS }, ++ { .id = V4L2_CID_STATELESS_HEVC_PPS }, ++ { .id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX }, +#if HEVC_CTRLS_VERSION >= 2 -+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS }, ++ { .id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS }, +#endif + }; + // Order & size must match! + static const size_t ctrl_sizes[] = { + sizeof(struct v4l2_ctrl_hevc_slice_params), ++ sizeof(int32_t), + sizeof(struct v4l2_ctrl_hevc_sps), + sizeof(struct v4l2_ctrl_hevc_pps), + sizeof(struct v4l2_ctrl_hevc_scaling_matrix), @@ -50793,26 +56004,44 @@ Upstream-status: Pending + }; + const unsigned int noof_ctrls = FF_ARRAY_ELEMS(qc); + -+ if (mediabufs_ctl_query_ext_ctrls(ctx->mbufs, qc, noof_ctrls)) { -+ av_log(avctx, AV_LOG_DEBUG, "Probed V%d control missing\n", HEVC_CTRLS_VERSION); ++#if HEVC_CTRLS_VERSION == 2 ++ if (mediabufs_ctl_driver_version(ctx->mbufs) >= MEDIABUFS_DRIVER_VERSION(5, 18, 0)) + return AVERROR(EINVAL); -+ } -+ for (i = 0; i != noof_ctrls; ++i) { -+ if (ctrl_sizes[i] != qc[i].elem_size) { -+ av_log(avctx, AV_LOG_DEBUG, "Probed V%d control %d size mismatch %u != %u\n", -+ HEVC_CTRLS_VERSION, i, ctrl_sizes[i], qc[i].elem_size); ++#elif HEVC_CTRLS_VERSION == 3 ++ if (mediabufs_ctl_driver_version(ctx->mbufs) < MEDIABUFS_DRIVER_VERSION(5, 18, 0)) ++ return AVERROR(EINVAL); ++#endif ++ ++ mediabufs_ctl_query_ext_ctrls(ctx->mbufs, qc, noof_ctrls); ++ i = 0; ++#if HEVC_CTRLS_VERSION >= 4 ++ // Skip slice check if no slice mode ++ if (qc[1].type != 0 && !ctrl_valid(qc + 1, V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED)) ++ i = 1; ++#else ++ // Fail frame mode silently for anything prior to V4 ++ if (qc[1].type == 0 || !ctrl_valid(qc + 1, V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED)) ++ return AVERROR(EINVAL); ++#endif ++ for (; i != noof_ctrls; ++i) { ++ if (qc[i].type == 0) { ++ av_log(avctx, AV_LOG_DEBUG, "Probed V%d control %#x missing\n", HEVC_CTRLS_VERSION, qc[i].id); ++ return AVERROR(EINVAL); ++ } ++ if (ctrl_sizes[i] != (size_t)qc[i].elem_size) { ++ av_log(avctx, AV_LOG_DEBUG, "Probed V%d control %d size mismatch %zu != %zu\n", ++ HEVC_CTRLS_VERSION, i, ctrl_sizes[i], (size_t)qc[i].elem_size); + return AVERROR(EINVAL); + } + } + + fill_sps(&ctrl_sps, sps); + -+ if (mediabufs_set_ext_ctrl(ctx->mbufs, NULL, V4L2_CID_MPEG_VIDEO_HEVC_SPS, &ctrl_sps, sizeof(ctrl_sps))) { ++ if (mediabufs_set_ext_ctrl(ctx->mbufs, NULL, V4L2_CID_STATELESS_HEVC_SPS, &ctrl_sps, sizeof(ctrl_sps))) { + av_log(avctx, AV_LOG_ERROR, "Failed to set initial SPS\n"); + return AVERROR(EINVAL); + } + -+ ctx->multi_slice = (qc[0].flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY) != 0; + return 0; +} + @@ -50823,39 +56052,64 @@ Upstream-status: Pending + int ret; + + struct v4l2_query_ext_ctrl querys[] = { -+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE, }, -+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_START_CODE, }, -+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS, }, ++ { .id = V4L2_CID_STATELESS_HEVC_DECODE_MODE, }, ++ { .id = V4L2_CID_STATELESS_HEVC_START_CODE, }, ++ { .id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS, }, ++#if HEVC_CTRLS_VERSION >= 4 ++ { .id = V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS, }, ++#endif + }; + + struct v4l2_ext_control ctrls[] = { -+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE, }, -+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_START_CODE, }, ++ { .id = V4L2_CID_STATELESS_HEVC_DECODE_MODE, }, ++ { .id = V4L2_CID_STATELESS_HEVC_START_CODE, }, + }; + + mediabufs_ctl_query_ext_ctrls(ctx->mbufs, querys, FF_ARRAY_ELEMS(querys)); + -+ ctx->decode_mode = querys[0].default_value; ++ ctx->max_slices = (!(querys[2].flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY) || ++ querys[2].nr_of_dims != 1 || querys[2].dims[0] == 0) ? ++ 1 : querys[2].dims[0]; ++ av_log(avctx, AV_LOG_DEBUG, "%s: Max slices %d\n", __func__, ctx->max_slices); + -+ if (ctx->decode_mode != V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED && -+ ctx->decode_mode != V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED) { -+ av_log(avctx, AV_LOG_ERROR, "%s: unsupported decode mode, %d\n", __func__, ctx->decode_mode); -+ return AVERROR(EINVAL); -+ } ++#if HEVC_CTRLS_VERSION >= 4 ++ ctx->max_offsets = (querys[3].type == 0 || querys[3].nr_of_dims != 1) ? ++ 0 : querys[3].dims[0]; ++ av_log(avctx, AV_LOG_DEBUG, "%s: Entry point offsets %d\n", __func__, ctx->max_offsets); ++#else ++ ctx->max_offsets = 0; ++#endif + -+ ctx->start_code = querys[1].default_value; -+ if (ctx->start_code != V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE && -+ ctx->start_code != V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B) { -+ av_log(avctx, AV_LOG_ERROR, "%s: unsupported start code, %d\n", __func__, ctx->start_code); ++ if (querys[0].default_value == V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED || ++ querys[0].default_value == V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED) ++ ctx->decode_mode = querys[0].default_value; ++ else if (ctrl_valid(querys + 0, V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED)) ++ ctx->decode_mode = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED; ++ else if (ctrl_valid(querys + 0, V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED)) ++ ctx->decode_mode = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED; ++ else { ++ av_log(avctx, AV_LOG_ERROR, "%s: unsupported decode mode\n", __func__); + return AVERROR(EINVAL); + } + -+ ctx->max_slices = querys[2].elems; -+ if (ctx->max_slices > MAX_SLICES) { -+ av_log(avctx, AV_LOG_ERROR, "%s: unsupported max slices, %d\n", __func__, ctx->max_slices); ++ if (querys[1].default_value == V4L2_STATELESS_HEVC_START_CODE_NONE || ++ querys[1].default_value == V4L2_STATELESS_HEVC_START_CODE_ANNEX_B) ++ ctx->start_code = querys[1].default_value; ++ else if (ctrl_valid(querys + 1, V4L2_STATELESS_HEVC_START_CODE_ANNEX_B)) ++ ctx->start_code = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B; ++ else if (ctrl_valid(querys + 1, V4L2_STATELESS_HEVC_START_CODE_NONE)) ++ ctx->start_code = V4L2_STATELESS_HEVC_START_CODE_NONE; ++ else { ++ av_log(avctx, AV_LOG_ERROR, "%s: unsupported start code\n", __func__); + return AVERROR(EINVAL); + } + ++ // If we are in slice mode & START_CODE_NONE supported then pick that ++ // as it doesn't require the slightly dodgy look backwards in our raw buffer ++ if (ctx->decode_mode == V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED && ++ ctrl_valid(querys + 1, V4L2_STATELESS_HEVC_START_CODE_NONE)) ++ ctx->start_code = V4L2_STATELESS_HEVC_START_CODE_NONE; ++ + ctrls[0].value = ctx->decode_mode; + ctrls[1].value = ctx->start_code; + @@ -50878,6 +56132,7 @@ Upstream-status: Pending + + av_freep(&rd->slices); + av_freep(&rd->slice_params); ++ av_freep(&rd->offsets); + + av_free(rd); +} @@ -50904,6 +56159,7 @@ Upstream-status: Pending + return ref; +} + ++#if 0 +static void v4l2_req_pool_free(void *opaque) +{ + av_log(NULL, AV_LOG_DEBUG, "%s: opaque=%p\n", __func__, opaque); @@ -50915,6 +56171,7 @@ Upstream-status: Pending + + av_buffer_pool_uninit(&hwfc->pool); +} ++#endif + +static int frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx) +{ @@ -50931,7 +56188,7 @@ Upstream-status: Pending + hwfc->width = vfmt->fmt.pix.width; + hwfc->height = vfmt->fmt.pix.height; + } -+ ++#if 0 + hwfc->pool = av_buffer_pool_init2(sizeof(V4L2MediaReqDescriptor), avctx, v4l2_req_frame_alloc, v4l2_req_pool_free); + if (!hwfc->pool) + return AVERROR(ENOMEM); @@ -50950,12 +56207,32 @@ Upstream-status: Pending + default: + hwfc->initial_pool_size += 2; + } -+ ++#endif + av_log(avctx, AV_LOG_DEBUG, "%s: avctx=%p ctx=%p hw_frames_ctx=%p hwfc=%p pool=%p width=%d height=%d initial_pool_size=%d\n", __func__, avctx, ctx, hw_frames_ctx, hwfc, hwfc->pool, hwfc->width, hwfc->height, hwfc->initial_pool_size); + + return 0; +} + ++static int alloc_frame(AVCodecContext * avctx, AVFrame *frame) ++{ ++ int rv; ++ ++ frame->buf[0] = v4l2_req_frame_alloc(avctx, sizeof(V4L2MediaReqDescriptor)); ++ if (!frame->buf[0]) ++ return AVERROR(ENOMEM); ++ ++ frame->data[0] = frame->buf[0]->data; ++ ++ frame->hw_frames_ctx = av_buffer_ref(avctx->hw_frames_ctx); ++ ++ if ((rv = ff_attach_decode_data(frame)) != 0) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to attach decode data to frame\n"); ++ av_frame_unref(frame); ++ return rv; ++ } ++ ++ return 0; ++} + +const v4l2_req_decode_fns V(ff_v4l2_req_hevc) = { + .src_pix_fmt_v4l2 = V4L2_PIX_FMT_HEVC_SLICE, @@ -50968,11 +56245,12 @@ Upstream-status: Pending + .end_frame = v4l2_request_hevc_end_frame, + .abort_frame = v4l2_request_hevc_abort_frame, + .frame_params = frame_params, ++ .alloc_frame = alloc_frame, +}; + --- /dev/null +++ b/libavcodec/v4l2_req_media.c -@@ -0,0 +1,1569 @@ +@@ -0,0 +1,1601 @@ +/* + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com> + * @@ -51388,7 +56666,7 @@ Upstream-status: Pending + free(be_dst); +} + -+static struct qent_dst * qe_dst_new(void) ++static struct qent_dst* qe_dst_new(struct ff_weak_link_master * const wl) +{ + struct qent_dst *const be_dst = malloc(sizeof(*be_dst)); + if (!be_dst) @@ -51396,7 +56674,8 @@ Upstream-status: Pending + *be_dst = (struct qent_dst){ + .base = QENT_BASE_INITIALIZER, + .lock = PTHREAD_MUTEX_INITIALIZER, -+ .cond = PTHREAD_COND_INITIALIZER ++ .cond = PTHREAD_COND_INITIALIZER, ++ .mbc_wl = ff_weak_link_ref(wl) + }; + return be_dst; +} @@ -51568,6 +56847,7 @@ Upstream-status: Pending + int vfd; + bool stream_on; + bool polling; ++ bool dst_fixed; // Dst Q is fixed size + pthread_mutex_t lock; + struct buf_pool * src; + struct buf_pool * dst; @@ -51577,6 +56857,7 @@ Upstream-status: Pending + + struct v4l2_format src_fmt; + struct v4l2_format dst_fmt; ++ struct v4l2_capability capability; +}; + +static int qe_v4l2_queue(struct qent_base *const be, @@ -51747,13 +57028,13 @@ Upstream-status: Pending +{ + if (!be->dh[0] || len > dmabuf_size(be->dh[0])) { + size_t newsize = round_up_size(len); -+ request_log("%s: Overrun %d > %d; trying %d\n", __func__, len, dmabuf_size(be->dh[0]), newsize); ++ request_log("%s: Overrun %zd > %zd; trying %zd\n", __func__, len, dmabuf_size(be->dh[0]), newsize); + if (!dbsc) { + request_log("%s: No dmbabuf_ctrl for realloc\n", __func__); + return -ENOMEM; + } + if ((be->dh[0] = dmabuf_realloc(dbsc, be->dh[0], newsize)) == NULL) { -+ request_log("%s: Realloc %d failed\n", __func__, newsize); ++ request_log("%s: Realloc %zd failed\n", __func__, newsize); + return -ENOMEM; + } + } @@ -52069,10 +57350,13 @@ Upstream-status: Pending + return MEDIABUFS_STATUS_SUCCESS; +} + -+static int create_dst_buf(struct mediabufs_ctl *const mbc) ++// Returns noof buffers created, -ve for error ++static int create_dst_bufs(struct mediabufs_ctl *const mbc, unsigned int n, struct qent_dst * const qes[]) +{ ++ unsigned int i; ++ + struct v4l2_create_buffers cbuf = { -+ .count = 1, ++ .count = n, + .memory = V4L2_MEMORY_DMABUF, + .format = mbc->dst_fmt, + }; @@ -52084,7 +57368,14 @@ Upstream-status: Pending + return -err; + } + } -+ return cbuf.index; ++ ++ if (cbuf.count != n) ++ request_warn(mbc->dc, "%s: Created %d of %d V4L2 buffers requested\n", __func__, cbuf.count, n); ++ ++ for (i = 0; i != cbuf.count; ++i) ++ qes[i]->base.index = cbuf.index + i; ++ ++ return cbuf.count; +} + +struct qent_dst* mediabufs_dst_qent_alloc(struct mediabufs_ctl *const mbc, struct dmabufs_ctl *const dbsc) @@ -52092,27 +57383,29 @@ Upstream-status: Pending + struct qent_dst * be_dst; + + if (mbc == NULL) { -+ be_dst = qe_dst_new(); ++ be_dst = qe_dst_new(NULL); + if (be_dst) + be_dst->base.status = QENT_IMPORT; + return be_dst; + } + -+ be_dst = base_to_dst(queue_tryget_free(mbc->dst)); -+ if (!be_dst) { -+ int index; -+ -+ be_dst = qe_dst_new(); ++ if (mbc->dst_fixed) { ++ be_dst = base_to_dst(queue_get_free(mbc->dst)); + if (!be_dst) + return NULL; ++ } ++ else { ++ be_dst = base_to_dst(queue_tryget_free(mbc->dst)); ++ if (!be_dst) { ++ be_dst = qe_dst_new(mbc->this_wlm); ++ if (!be_dst) ++ return NULL; + -+ if ((be_dst->mbc_wl = ff_weak_link_ref(mbc->this_wlm)) == NULL || -+ (index = create_dst_buf(mbc)) < 0) { -+ qe_dst_free(be_dst); -+ return NULL; ++ if (create_dst_bufs(mbc, 1, &be_dst) != 1) { ++ qe_dst_free(be_dst); ++ return NULL; ++ } + } -+ -+ be_dst->base.index = (uint32_t)index; + } + + if (qe_alloc_from_fmt(&be_dst->base, dbsc, &mbc->dst_fmt)) { @@ -52166,29 +57459,42 @@ Upstream-status: Pending + return status; +} + -+MediaBufsStatus mediabufs_dst_slots_create(struct mediabufs_ctl *const mbc, unsigned int n) ++// ** This is a mess if we get partial alloc but without any way to remove ++// individual V4L2 Q members we are somewhat stuffed ++MediaBufsStatus mediabufs_dst_slots_create(struct mediabufs_ctl *const mbc, const unsigned int n, const bool fixed) +{ -+ // **** request buffers + unsigned int i; ++ int a = 0; ++ unsigned int qc; ++ struct qent_dst * qes[32]; ++ ++ if (n > 32) ++ return MEDIABUFS_ERROR_ALLOCATION_FAILED; + -+ for (i = 0; i != n; ++i) ++ // Create qents first as it is hard to get rid of the V4L2 buffers on error ++ for (qc = 0; qc != n; ++qc) + { -+ int index; -+ struct qent_dst * const be_dst = qe_dst_new(); -+ if (!be_dst) -+ return MEDIABUFS_ERROR_OPERATION_FAILED; ++ if ((qes[qc] = qe_dst_new(mbc->this_wlm)) == NULL) ++ goto fail; ++ } + -+ index = create_dst_buf(mbc); -+ if (index < 0) { -+ qe_dst_free(be_dst); -+ return MEDIABUFS_ERROR_OPERATION_FAILED; -+ } ++ if ((a = create_dst_bufs(mbc, n, qes)) < 0) ++ goto fail; + -+ // Add index to free chain -+ be_dst->base.index = (uint32_t)index; -+ queue_put_free(mbc->dst, &be_dst->base); -+ } ++ for (i = 0; i != a; ++i) ++ queue_put_free(mbc->dst, &qes[i]->base); ++ ++ if (a != n) ++ goto fail; ++ ++ mbc->dst_fixed = fixed; + return MEDIABUFS_STATUS_SUCCESS; ++ ++fail: ++ for (i = (a < 0 ? 0 : a); i != qc; ++i) ++ qe_dst_free(qes[i]); ++ ++ return MEDIABUFS_ERROR_ALLOCATION_FAILED; +} + +struct qent_src *mediabufs_src_qent_get(struct mediabufs_ctl *const mbc) @@ -52446,20 +57752,24 @@ Upstream-status: Pending + mediabufs_ctl_delete(mbc); +} + ++unsigned int mediabufs_ctl_driver_version(struct mediabufs_ctl *const mbc) ++{ ++ return mbc->capability.version; ++} ++ +static int set_capabilities(struct mediabufs_ctl *const mbc) +{ -+ struct v4l2_capability capability = { 0 }; + uint32_t caps; + -+ if (ioctl(mbc->vfd, VIDIOC_QUERYCAP, &capability)) { ++ if (ioctl(mbc->vfd, VIDIOC_QUERYCAP, &mbc->capability)) { + int err = errno; + request_err(mbc->dc, "Failed to get capabilities: %s\n", strerror(err)); + return -err; + } + -+ caps = (capability.capabilities & V4L2_CAP_DEVICE_CAPS) != 0 ? -+ capability.device_caps : -+ capability.capabilities; ++ caps = (mbc->capability.capabilities & V4L2_CAP_DEVICE_CAPS) != 0 ? ++ mbc->capability.device_caps : ++ mbc->capability.capabilities; + + if ((caps & V4L2_CAP_VIDEO_M2M_MPLANE) != 0) { + mbc->src_fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; @@ -52544,7 +57854,7 @@ Upstream-status: Pending + --- /dev/null +++ b/libavcodec/v4l2_req_media.h -@@ -0,0 +1,148 @@ +@@ -0,0 +1,154 @@ +/* +e.h +* @@ -52646,11 +57956,14 @@ Upstream-status: Pending + struct qent_dst *const dst_be, + const bool is_final); +// Get / alloc a dst buffer & associate with a slot -+// * BEWARE * Currently has no alloc limit ++// If the dst pool is empty then behaviour depends on the fixed flag passed to ++// dst_slots_create. Default is !fixed = unlimited alloc +struct qent_dst* mediabufs_dst_qent_alloc(struct mediabufs_ctl *const mbc, + struct dmabufs_ctl *const dbsc); +// Create dst slots without alloc -+MediaBufsStatus mediabufs_dst_slots_create(struct mediabufs_ctl *const mbc, unsigned int n); ++// If fixed true then qent_alloc will only get slots from this pool and will ++// block until a qent has been unrefed ++MediaBufsStatus mediabufs_dst_slots_create(struct mediabufs_ctl *const mbc, const unsigned int n, const bool fixed); + +MediaBufsStatus mediabufs_stream_on(struct mediabufs_ctl *const mbc); +MediaBufsStatus mediabufs_stream_off(struct mediabufs_ctl *const mbc); @@ -52686,6 +57999,9 @@ Upstream-status: Pending + struct dmabufs_ctl * const dbsc, + unsigned int n); + ++#define MEDIABUFS_DRIVER_VERSION(a, b, c) (((a) << 16) | ((b) << 8) | (c)) ++unsigned int mediabufs_ctl_driver_version(struct mediabufs_ctl *const mbc); ++ +struct mediabufs_ctl * mediabufs_ctl_new(void * const dc, + const char *vpath, struct pollqueue *const pq); +void mediabufs_ctl_unref(struct mediabufs_ctl **const pmbc); @@ -52695,7 +58011,7 @@ Upstream-status: Pending +#endif --- /dev/null +++ b/libavcodec/v4l2_req_pollqueue.c -@@ -0,0 +1,363 @@ +@@ -0,0 +1,361 @@ +#include <errno.h> +#include <limits.h> +#include <poll.h> @@ -52885,19 +58201,19 @@ Upstream-status: Pending + unsigned int i; + unsigned int n = 0; + struct polltask *pt; ++ struct polltask *pt_next; + uint64_t now = pollqueue_now(0); + int timeout = -1; + int rv; + -+ for (pt = pq->head; pt; pt = pt->next) { ++ for (pt = pq->head; pt; pt = pt_next) { + int64_t t; + ++ pt_next = pt->next; ++ + if (pt->state == POLLTASK_Q_KILL) { -+ struct polltask * const prev = pt->prev; + pollqueue_rem_task(pq, pt); + sem_post(&pt->kill_sem); -+ if ((pt = prev) == NULL) -+ break; + continue; + } + @@ -52936,8 +58252,8 @@ Upstream-status: Pending + * infinite looping + */ + pq->no_prod = true; -+ for (i = 0, pt = pq->head; i < n; ++i) { -+ struct polltask *const pt_next = pt->next; ++ for (i = 0, pt = pq->head; i < n; ++i, pt = pt_next) { ++ pt_next = pt->next; + + /* Pending? */ + if (a[i].revents || @@ -52961,8 +58277,6 @@ Upstream-status: Pending + if (pt->state == POLLTASK_RUN_KILL) + sem_post(&pt->kill_sem); + } -+ -+ pt = pt_next; + } + pq->no_prod = false; + @@ -53082,12 +58396,13 @@ Upstream-status: Pending +#endif /* POLLQUEUE_H_ */ --- /dev/null +++ b/libavcodec/v4l2_req_utils.h -@@ -0,0 +1,21 @@ +@@ -0,0 +1,22 @@ +#include "libavutil/log.h" + +#define request_log(...) av_log(NULL, AV_LOG_INFO, __VA_ARGS__) + +#define request_err(_ctx, ...) av_log(_ctx, AV_LOG_ERROR, __VA_ARGS__) ++#define request_warn(_ctx, ...) av_log(_ctx, AV_LOG_WARNING, __VA_ARGS__) +#define request_info(_ctx, ...) av_log(_ctx, AV_LOG_INFO, __VA_ARGS__) +#define request_debug(_ctx, ...) av_log(_ctx, AV_LOG_DEBUG, __VA_ARGS__) + @@ -53106,7 +58421,7 @@ Upstream-status: Pending + --- /dev/null +++ b/libavcodec/v4l2_request_hevc.c -@@ -0,0 +1,280 @@ +@@ -0,0 +1,315 @@ +/* + * This file is part of FFmpeg. + * @@ -53194,6 +58509,13 @@ Upstream-status: Pending + return ctx->fns->frame_params(avctx, hw_frames_ctx); +} + ++static int v4l2_req_hevc_alloc_frame(AVCodecContext * avctx, AVFrame *frame) ++{ ++ V4L2RequestContextHEVC * const ctx = avctx->internal->hwaccel_priv_data; ++ return ctx->fns->alloc_frame(avctx, frame); ++} ++ ++ +static int v4l2_request_hevc_uninit(AVCodecContext *avctx) +{ + V4L2RequestContextHEVC * const ctx = avctx->internal->hwaccel_priv_data; @@ -53248,6 +58570,17 @@ Upstream-status: Pending + + av_log(avctx, AV_LOG_DEBUG, "<<< %s\n", __func__); + ++ // Give up immediately if this is something that we have no code to deal with ++ if (h->ps.sps->chroma_format_idc != 1) { ++ av_log(avctx, AV_LOG_WARNING, "chroma_format_idc(%d) != 1: Not implemented\n", h->ps.sps->chroma_format_idc); ++ return AVERROR_PATCHWELCOME; ++ } ++ if (!(h->ps.sps->bit_depth == 10 || h->ps.sps->bit_depth == 8) || ++ h->ps.sps->bit_depth != h->ps.sps->bit_depth_chroma) { ++ av_log(avctx, AV_LOG_WARNING, "Bit depth Y:%d C:%d: Not implemented\n", h->ps.sps->bit_depth, h->ps.sps->bit_depth_chroma); ++ return AVERROR_PATCHWELCOME; ++ } ++ + if ((ret = devscan_build(avctx, &ctx->devscan)) != 0) { + av_log(avctx, AV_LOG_WARNING, "Failed to find any V4L2 devices\n"); + return (AVERROR(-ret)); @@ -53300,7 +58633,15 @@ Upstream-status: Pending + goto fail4; + } + -+ if (V2(ff_v4l2_req_hevc, 2).probe(avctx, ctx) == 0) { ++ if (V2(ff_v4l2_req_hevc, 4).probe(avctx, ctx) == 0) { ++ av_log(avctx, AV_LOG_DEBUG, "HEVC API version 4 probed successfully\n"); ++ ctx->fns = &V2(ff_v4l2_req_hevc, 4); ++ } ++ else if (V2(ff_v4l2_req_hevc, 3).probe(avctx, ctx) == 0) { ++ av_log(avctx, AV_LOG_DEBUG, "HEVC API version 3 probed successfully\n"); ++ ctx->fns = &V2(ff_v4l2_req_hevc, 3); ++ } ++ else if (V2(ff_v4l2_req_hevc, 2).probe(avctx, ctx) == 0) { + av_log(avctx, AV_LOG_DEBUG, "HEVC API version 2 probed successfully\n"); + ctx->fns = &V2(ff_v4l2_req_hevc, 2); + } @@ -53325,9 +58666,18 @@ Upstream-status: Pending + goto fail4; + } + -+ if (mediabufs_dst_slots_create(ctx->mbufs, 1)) { -+ av_log(avctx, AV_LOG_ERROR, "Failed to create destination slots\n"); -+ goto fail4; ++ { ++ unsigned int dst_slots = sps->temporal_layer[sps->max_sub_layers - 1].max_dec_pic_buffering + ++ avctx->thread_count + (avctx->extra_hw_frames > 0 ? avctx->extra_hw_frames : 6); ++ av_log(avctx, AV_LOG_DEBUG, "Slots=%d: Reordering=%d, threads=%d, hw+=%d\n", dst_slots, ++ sps->temporal_layer[sps->max_sub_layers - 1].max_dec_pic_buffering, ++ avctx->thread_count, avctx->extra_hw_frames); ++ ++ // extra_hw_frames is -1 if unset ++ if (mediabufs_dst_slots_create(ctx->mbufs, dst_slots, (avctx->extra_hw_frames > 0))) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to create destination slots\n"); ++ goto fail4; ++ } + } + + if (mediabufs_stream_on(ctx->mbufs)) { @@ -53376,7 +58726,7 @@ Upstream-status: Pending + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_HEVC, + .pix_fmt = AV_PIX_FMT_DRM_PRIME, -+// .alloc_frame = v4l2_request_hevc_alloc_frame, ++ .alloc_frame = v4l2_req_hevc_alloc_frame, + .start_frame = v4l2_req_hevc_start_frame, + .decode_slice = v4l2_req_hevc_decode_slice, + .end_frame = v4l2_req_hevc_end_frame, @@ -53389,7 +58739,7 @@ Upstream-status: Pending +}; --- /dev/null +++ b/libavcodec/v4l2_request_hevc.h -@@ -0,0 +1,100 @@ +@@ -0,0 +1,101 @@ +#ifndef AVCODEC_V4L2_REQUEST_HEVC_H +#define AVCODEC_V4L2_REQUEST_HEVC_H + @@ -53437,8 +58787,6 @@ Upstream-status: Pending +#define V4L2_CTRL_FLAG_DYNAMIC_ARRAY 0x0800 +#endif + -+#define MAX_SLICES 128 -+ +#define VCAT(name, version) name##_v##version +#define V2(n,v) VCAT(n, v) +#define V(n) V2(n, HEVC_CTRLS_VERSION) @@ -53455,10 +58803,10 @@ Upstream-status: Pending + + unsigned int timestamp; // ?? maybe uint64_t + -+ int multi_slice; + int decode_mode; + int start_code; -+ int max_slices; ++ unsigned int max_slices; // 0 => not wanted (frame mode) ++ unsigned int max_offsets; // 0 => not wanted + + req_decode_q decode_q; + @@ -53483,16 +58831,121 @@ Upstream-status: Pending + int (*end_frame)(AVCodecContext *avctx); + void (*abort_frame)(AVCodecContext *avctx); + int (*frame_params)(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx); ++ int (*alloc_frame)(AVCodecContext * avctx, AVFrame *frame); +} v4l2_req_decode_fns; + + +extern const v4l2_req_decode_fns V2(ff_v4l2_req_hevc, 1); +extern const v4l2_req_decode_fns V2(ff_v4l2_req_hevc, 2); ++extern const v4l2_req_decode_fns V2(ff_v4l2_req_hevc, 3); ++extern const v4l2_req_decode_fns V2(ff_v4l2_req_hevc, 4); + +#endif +--- a/libavcodec/vc1dec.c ++++ b/libavcodec/vc1dec.c +@@ -486,7 +486,7 @@ static av_cold int vc1_decode_init(AVCod + size = next - start - 4; + if (size <= 0) + continue; +- buf2_size = vc1_unescape_buffer(start + 4, size, buf2); ++ buf2_size = v->vc1dsp.vc1_unescape_buffer(start + 4, size, buf2); + init_get_bits(&gb, buf2, buf2_size * 8); + switch (AV_RB32(start)) { + case VC1_CODE_SEQHDR: +@@ -689,7 +689,7 @@ static int vc1_decode_frame(AVCodecConte + case VC1_CODE_FRAME: + if (avctx->hwaccel) + buf_start = start; +- buf_size2 = vc1_unescape_buffer(start + 4, size, buf2); ++ buf_size2 = v->vc1dsp.vc1_unescape_buffer(start + 4, size, buf2); + break; + case VC1_CODE_FIELD: { + int buf_size3; +@@ -706,8 +706,8 @@ static int vc1_decode_frame(AVCodecConte + ret = AVERROR(ENOMEM); + goto err; + } +- buf_size3 = vc1_unescape_buffer(start + 4, size, +- slices[n_slices].buf); ++ buf_size3 = v->vc1dsp.vc1_unescape_buffer(start + 4, size, ++ slices[n_slices].buf); + init_get_bits(&slices[n_slices].gb, slices[n_slices].buf, + buf_size3 << 3); + slices[n_slices].mby_start = avctx->coded_height + 31 >> 5; +@@ -718,7 +718,7 @@ static int vc1_decode_frame(AVCodecConte + break; + } + case VC1_CODE_ENTRYPOINT: /* it should be before frame data */ +- buf_size2 = vc1_unescape_buffer(start + 4, size, buf2); ++ buf_size2 = v->vc1dsp.vc1_unescape_buffer(start + 4, size, buf2); + init_get_bits(&s->gb, buf2, buf_size2 * 8); + ff_vc1_decode_entry_point(avctx, v, &s->gb); + break; +@@ -735,8 +735,8 @@ static int vc1_decode_frame(AVCodecConte + ret = AVERROR(ENOMEM); + goto err; + } +- buf_size3 = vc1_unescape_buffer(start + 4, size, +- slices[n_slices].buf); ++ buf_size3 = v->vc1dsp.vc1_unescape_buffer(start + 4, size, ++ slices[n_slices].buf); + init_get_bits(&slices[n_slices].gb, slices[n_slices].buf, + buf_size3 << 3); + slices[n_slices].mby_start = get_bits(&slices[n_slices].gb, 9); +@@ -770,7 +770,7 @@ static int vc1_decode_frame(AVCodecConte + ret = AVERROR(ENOMEM); + goto err; + } +- buf_size3 = vc1_unescape_buffer(divider + 4, buf + buf_size - divider - 4, slices[n_slices].buf); ++ buf_size3 = v->vc1dsp.vc1_unescape_buffer(divider + 4, buf + buf_size - divider - 4, slices[n_slices].buf); + init_get_bits(&slices[n_slices].gb, slices[n_slices].buf, + buf_size3 << 3); + slices[n_slices].mby_start = s->mb_height + 1 >> 1; +@@ -779,9 +779,9 @@ static int vc1_decode_frame(AVCodecConte + n_slices1 = n_slices - 1; + n_slices++; + } +- buf_size2 = vc1_unescape_buffer(buf, divider - buf, buf2); ++ buf_size2 = v->vc1dsp.vc1_unescape_buffer(buf, divider - buf, buf2); + } else { +- buf_size2 = vc1_unescape_buffer(buf, buf_size, buf2); ++ buf_size2 = v->vc1dsp.vc1_unescape_buffer(buf, buf_size, buf2); + } + init_get_bits(&s->gb, buf2, buf_size2*8); + } else +--- a/libavcodec/vc1dsp.c ++++ b/libavcodec/vc1dsp.c +@@ -32,6 +32,7 @@ + #include "rnd_avg.h" + #include "vc1dsp.h" + #include "startcode.h" ++#include "vc1_common.h" + + /* Apply overlap transform to horizontal edge */ + static void vc1_v_overlap_c(uint8_t *src, int stride) +@@ -1028,6 +1029,7 @@ av_cold void ff_vc1dsp_init(VC1DSPContex + #endif /* CONFIG_WMV3IMAGE_DECODER || CONFIG_VC1IMAGE_DECODER */ + + dsp->startcode_find_candidate = ff_startcode_find_candidate_c; ++ dsp->vc1_unescape_buffer = vc1_unescape_buffer; + + if (ARCH_AARCH64) + ff_vc1dsp_init_aarch64(dsp); +--- a/libavcodec/vc1dsp.h ++++ b/libavcodec/vc1dsp.h +@@ -80,6 +80,9 @@ typedef struct VC1DSPContext { + * one or more further zero bytes and a one byte. + */ + int (*startcode_find_candidate)(const uint8_t *buf, int size); ++ ++ /* Copy a buffer, removing startcode emulation escape bytes as we go */ ++ int (*vc1_unescape_buffer)(const uint8_t *src, int size, uint8_t *dst); + } VC1DSPContext; + + void ff_vc1dsp_init(VC1DSPContext* c); --- /dev/null +++ b/libavcodec/weak_link.c -@@ -0,0 +1,100 @@ +@@ -0,0 +1,102 @@ +#include <stdlib.h> +#include <pthread.h> +#include <stdatomic.h> @@ -53549,6 +59002,8 @@ Upstream-status: Pending + +struct ff_weak_link_client* ff_weak_link_ref(struct ff_weak_link_master * w) +{ ++ if (!w) ++ return NULL; + atomic_fetch_add(&w->ref_count, 1); + return (struct ff_weak_link_client*)w; +} @@ -53630,7 +59085,7 @@ Upstream-status: Pending +OBJS-$(CONFIG_VOUT_RPI_OUTDEV) += rpi_vout.o OBJS-$(CONFIG_XCBGRAB_INDEV) += xcbgrab.o OBJS-$(CONFIG_XV_OUTDEV) += xv.o - + --- a/libavdevice/alldevices.c +++ b/libavdevice/alldevices.c @@ -52,6 +52,9 @@ extern AVOutputFormat ff_sndio_muxer; @@ -53642,7 +59097,7 @@ Upstream-status: Pending +extern AVOutputFormat ff_vout_rpi_muxer; extern AVInputFormat ff_xcbgrab_demuxer; extern AVOutputFormat ff_xv_muxer; - + --- /dev/null +++ b/libavdevice/drm_vout.c @@ -0,0 +1,643 @@ @@ -53856,7 +59311,7 @@ Upstream-status: Pending + + while (drmWaitVBlank(de->drm_fd, &vbl)) { + if (errno != EINTR) { -+ av_log(s, AV_LOG_WARNING, "drmWaitVBlank failed: %s\n", ERRSTR); ++// av_log(s, AV_LOG_WARNING, "drmWaitVBlank failed: %s\n", ERRSTR); + break; + } + } @@ -54291,7 +59746,7 @@ Upstream-status: Pending + --- /dev/null +++ b/libavdevice/egl_vout.c -@@ -0,0 +1,825 @@ +@@ -0,0 +1,816 @@ +/* + * Copyright (c) 2020 John Cox for Raspberry Pi Trading + * @@ -54334,16 +59789,8 @@ Upstream-status: Pending +#include <stdatomic.h> +#include <unistd.h> + -+#include "drm_fourcc.h" -+#include <drm.h> -+#include <drm_mode.h> -+#include <xf86drm.h> -+#include <xf86drmMode.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> -+#include <X11/Xlib-xcb.h> -+#include <xcb/xcb.h> -+#include <xcb/dri3.h> + +#include "libavutil/rpi_sand_fns.h" + @@ -54555,8 +60002,7 @@ Upstream-status: Pending + XMapWindow(dpy, win); + + { -+ EGLSurface surf = eglCreateWindowSurface(egl_dpy, config, -+ (void *)(uintptr_t)win, NULL); ++ EGLSurface surf = eglCreateWindowSurface(egl_dpy, config, (EGLNativeWindowType)win, NULL); + if (!surf) { + av_log(s, AV_LOG_ERROR, "Error: eglCreateWindowSurface failed\n"); + return -1; @@ -55656,7 +61102,15 @@ Upstream-status: Pending +}; --- a/libavfilter/Makefile +++ b/libavfilter/Makefile -@@ -434,6 +434,7 @@ OBJS-$(CONFIG_TRANSPOSE_OPENCL_FILTER) +@@ -218,6 +218,7 @@ OBJS-$(CONFIG_DEFLATE_FILTER) + OBJS-$(CONFIG_DEFLICKER_FILTER) += vf_deflicker.o + OBJS-$(CONFIG_DEINTERLACE_QSV_FILTER) += vf_deinterlace_qsv.o + OBJS-$(CONFIG_DEINTERLACE_VAAPI_FILTER) += vf_deinterlace_vaapi.o vaapi_vpp.o ++OBJS-$(CONFIG_DEINTERLACE_V4L2M2M_FILTER) += vf_deinterlace_v4l2m2m.o + OBJS-$(CONFIG_DEJUDDER_FILTER) += vf_dejudder.o + OBJS-$(CONFIG_DELOGO_FILTER) += vf_delogo.o + OBJS-$(CONFIG_DENOISE_VAAPI_FILTER) += vf_misc_vaapi.o vaapi_vpp.o +@@ -434,6 +435,7 @@ OBJS-$(CONFIG_TRANSPOSE_OPENCL_FILTER) OBJS-$(CONFIG_TRANSPOSE_VAAPI_FILTER) += vf_transpose_vaapi.o vaapi_vpp.o OBJS-$(CONFIG_TRIM_FILTER) += trim.o OBJS-$(CONFIG_UNPREMULTIPLY_FILTER) += vf_premultiply.o framesync.o @@ -55666,7 +61120,15 @@ Upstream-status: Pending opencl/unsharp.o --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c -@@ -414,6 +414,7 @@ extern AVFilter ff_vf_transpose_opencl; +@@ -204,6 +204,7 @@ extern AVFilter ff_vf_dedot; + extern AVFilter ff_vf_deflate; + extern AVFilter ff_vf_deflicker; + extern AVFilter ff_vf_deinterlace_qsv; ++extern AVFilter ff_vf_deinterlace_v4l2m2m; + extern AVFilter ff_vf_deinterlace_vaapi; + extern AVFilter ff_vf_dejudder; + extern AVFilter ff_vf_delogo; +@@ -414,6 +415,7 @@ extern AVFilter ff_vf_transpose_opencl; extern AVFilter ff_vf_transpose_vaapi; extern AVFilter ff_vf_trim; extern AVFilter ff_vf_unpremultiply; @@ -55683,13 +61145,13 @@ Upstream-status: Pending +#if CONFIG_UNSAND_FILTER +#include "libavutil/rpi_sand_fns.h" +#endif - + #define FF_INTERNAL_FIELDS 1 #include "framequeue.h" @@ -427,6 +430,19 @@ static int can_merge_formats(AVFilterFor } } - + +#if CONFIG_UNSAND_FILTER +static int has_sand_format(const AVFilterFormats * const ff) +{ @@ -55711,13 +61173,13 @@ Upstream-status: Pending AVFilterLink *link = filter->inputs[j]; int convert_needed = 0; + unsigned int extra_convert_tried = 0; - + if (!link) continue; @@ -514,11 +531,14 @@ static int query_formats(AVFilterGraph * ) #undef MERGE_DISPATCH - + - if (convert_needed) { + while (convert_needed) { AVFilterContext *convert; @@ -55727,7 +61189,7 @@ Upstream-status: Pending + int can_retry = 0; + + convert_needed = 0; - + if (graph->disable_auto_convert) { av_log(log_ctx, AV_LOG_ERROR, @@ -531,19 +551,45 @@ static int query_formats(AVFilterGraph * @@ -55760,7 +61222,7 @@ Upstream-status: Pending + inst_name, "", NULL, + graph)) < 0) + return ret; - + - if ((ret = avfilter_graph_create_filter(&convert, filter, - inst_name, graph->scale_sws_opts, NULL, - graph)) < 0) @@ -55813,7 +61275,7 @@ Upstream-status: Pending --- a/libavfilter/buffersrc.c +++ b/libavfilter/buffersrc.c @@ -210,7 +210,7 @@ static int av_buffersrc_add_frame_intern - + switch (ctx->outputs[0]->type) { case AVMEDIA_TYPE_VIDEO: - CHECK_VIDEO_PARAM_CHANGE(ctx, s, frame->width, frame->height, @@ -55822,6 +61284,1345 @@ Upstream-status: Pending break; case AVMEDIA_TYPE_AUDIO: --- /dev/null ++++ b/libavfilter/vf_deinterlace_v4l2m2m.c +@@ -0,0 +1,1336 @@ ++/* ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/** ++ * @file ++ * deinterlace video filter - V4L2 M2M ++ */ ++ ++#include <drm_fourcc.h> ++ ++#include <linux/videodev2.h> ++ ++#include <dirent.h> ++#include <fcntl.h> ++#include <poll.h> ++#include <stdatomic.h> ++#include <stdio.h> ++#include <string.h> ++#include <sys/ioctl.h> ++#include <sys/mman.h> ++#include <unistd.h> ++ ++#include "libavutil/avassert.h" ++#include "libavutil/avstring.h" ++#include "libavutil/common.h" ++#include "libavutil/hwcontext.h" ++#include "libavutil/hwcontext_drm.h" ++#include "libavutil/internal.h" ++#include "libavutil/mathematics.h" ++#include "libavutil/opt.h" ++#include "libavutil/pixdesc.h" ++#include "libavutil/time.h" ++ ++#define FF_INTERNAL_FIELDS 1 ++#include "framequeue.h" ++#include "filters.h" ++#include "avfilter.h" ++#include "formats.h" ++#include "internal.h" ++#include "video.h" ++ ++typedef struct V4L2Queue V4L2Queue; ++typedef struct DeintV4L2M2MContextShared DeintV4L2M2MContextShared; ++ ++typedef struct V4L2PlaneInfo { ++ int bytesperline; ++ size_t length; ++} V4L2PlaneInfo; ++ ++typedef struct V4L2Buffer { ++ int enqueued; ++ int reenqueue; ++ int fd; ++ struct v4l2_buffer buffer; ++ AVFrame frame; ++ struct v4l2_plane planes[VIDEO_MAX_PLANES]; ++ int num_planes; ++ V4L2PlaneInfo plane_info[VIDEO_MAX_PLANES]; ++ AVDRMFrameDescriptor drm_frame; ++ V4L2Queue *q; ++} V4L2Buffer; ++ ++typedef struct V4L2Queue { ++ struct v4l2_format format; ++ int num_buffers; ++ V4L2Buffer *buffers; ++ DeintV4L2M2MContextShared *ctx; ++} V4L2Queue; ++ ++typedef struct pts_stats_s ++{ ++ void * logctx; ++ const char * name; // For debug ++ unsigned int last_count; ++ unsigned int last_interval; ++ int64_t last_pts; ++} pts_stats_t; ++ ++#define PTS_TRACK_SIZE 32 ++typedef struct pts_track_el_s ++{ ++ uint32_t n; ++ unsigned int interval; ++ AVFrame * props; ++} pts_track_el_t; ++ ++typedef struct pts_track_s ++{ ++ uint32_t n; ++ uint32_t last_n; ++ int got_2; ++ void * logctx; ++ pts_stats_t stats; ++ pts_track_el_t a[PTS_TRACK_SIZE]; ++} pts_track_t; ++ ++typedef struct DeintV4L2M2MContextShared { ++ void * logctx; // For logging - will be NULL when done ++ ++ int fd; ++ int done; ++ int width; ++ int height; ++ int orig_width; ++ int orig_height; ++ atomic_uint refcount; ++ ++ AVBufferRef *hw_frames_ctx; ++ ++ unsigned int field_order; ++ ++ pts_track_t track; ++ ++ V4L2Queue output; ++ V4L2Queue capture; ++} DeintV4L2M2MContextShared; ++ ++typedef struct DeintV4L2M2MContext { ++ const AVClass *class; ++ ++ DeintV4L2M2MContextShared *shared; ++} DeintV4L2M2MContext; ++ ++static unsigned int pts_stats_interval(const pts_stats_t * const stats) ++{ ++ return stats->last_interval; ++} ++ ++// Pick 64 for max last count - that is >1sec at 60fps ++#define STATS_LAST_COUNT_MAX 64 ++#define STATS_INTERVAL_MAX (1 << 30) ++static void pts_stats_add(pts_stats_t * const stats, int64_t pts) ++{ ++ if (pts == AV_NOPTS_VALUE || pts == stats->last_pts) { ++ if (stats->last_count < STATS_LAST_COUNT_MAX) ++ ++stats->last_count; ++ return; ++ } ++ ++ if (stats->last_pts != AV_NOPTS_VALUE) { ++ const int64_t interval = pts - stats->last_pts; ++ ++ if (interval < 0 || interval >= STATS_INTERVAL_MAX || ++ stats->last_count >= STATS_LAST_COUNT_MAX) { ++ if (stats->last_interval != 0) ++ av_log(stats->logctx, AV_LOG_DEBUG, "%s: %s: Bad interval: %" PRId64 "/%d\n", ++ __func__, stats->name, interval, stats->last_count); ++ stats->last_interval = 0; ++ } ++ else { ++ const int64_t frame_time = interval / (int64_t)stats->last_count; ++ ++ if (frame_time != stats->last_interval) ++ av_log(stats->logctx, AV_LOG_DEBUG, "%s: %s: New interval: %u->%" PRId64 "/%d=%" PRId64 "\n", ++ __func__, stats->name, stats->last_interval, interval, stats->last_count, frame_time); ++ stats->last_interval = frame_time; ++ } ++ } ++ ++ stats->last_pts = pts; ++ stats->last_count = 1; ++} ++ ++static void pts_stats_init(pts_stats_t * const stats, void * logctx, const char * name) ++{ ++ *stats = (pts_stats_t){ ++ .logctx = logctx, ++ .name = name, ++ .last_count = 1, ++ .last_interval = 0, ++ .last_pts = AV_NOPTS_VALUE ++ }; ++} ++ ++static inline uint32_t pts_track_next_n(pts_track_t * const trk) ++{ ++ if (++trk->n == 0) ++ trk->n = 1; ++ return trk->n; ++} ++ ++static int pts_track_get_frame(pts_track_t * const trk, const struct timeval tv, AVFrame * const dst) ++{ ++ uint32_t n = (uint32_t)(tv.tv_usec / 2 + tv.tv_sec * 500000); ++ pts_track_el_t * t; ++ ++ // As a first guess assume that n==0 means last frame ++ if (n == 0) { ++ n = trk->last_n; ++ if (n == 0) ++ goto fail; ++ } ++ ++ t = trk->a + (n & (PTS_TRACK_SIZE - 1)); ++ ++ if (t->n != n) { ++ av_log(trk->logctx, AV_LOG_ERROR, "%s: track failure: got %u, expected %u\n", __func__, n, trk->n); ++ goto fail; ++ } ++ ++ // 1st frame is simple - just believe it ++ if (n != trk->last_n) { ++ trk->last_n = n; ++ trk->got_2 = 0; ++ return av_frame_copy_props(dst, t->props); ++ } ++ ++ // Only believe in a single interpolated frame ++ if (trk->got_2) ++ goto fail; ++ trk->got_2 = 1; ++ ++ av_frame_copy_props(dst, t->props); ++ ++ ++ // If we can't guess - don't ++ if (t->interval == 0) { ++ dst->best_effort_timestamp = AV_NOPTS_VALUE; ++ dst->pts = AV_NOPTS_VALUE; ++ dst->pkt_dts = AV_NOPTS_VALUE; ++ } ++ else { ++ if (dst->best_effort_timestamp != AV_NOPTS_VALUE) ++ dst->best_effort_timestamp += t->interval / 2; ++ if (dst->pts != AV_NOPTS_VALUE) ++ dst->pts += t->interval / 2; ++ if (dst->pkt_dts != AV_NOPTS_VALUE) ++ dst->pkt_dts += t->interval / 2; ++ } ++ ++ return 0; ++ ++fail: ++ trk->last_n = 0; ++ trk->got_2 = 0; ++ dst->pts = AV_NOPTS_VALUE; ++ dst->pkt_dts = AV_NOPTS_VALUE; ++ return 0; ++} ++ ++static struct timeval pts_track_add_frame(pts_track_t * const trk, const AVFrame * const src) ++{ ++ const uint32_t n = pts_track_next_n(trk); ++ pts_track_el_t * const t = trk->a + (n & (PTS_TRACK_SIZE - 1)); ++ ++ pts_stats_add(&trk->stats, src->pts); ++ ++ t->n = n; ++ t->interval = pts_stats_interval(&trk->stats); // guess that next interval is the same as the last ++ av_frame_unref(t->props); ++ av_frame_copy_props(t->props, src); ++ ++ // We now know what the previous interval was, rather than having to guess, ++ // so set it. There is a better than decent chance that this is before ++ // we use it. ++ if (t->interval != 0) { ++ pts_track_el_t * const prev_t = trk->a + ((n - 1) & (PTS_TRACK_SIZE - 1)); ++ prev_t->interval = t->interval; ++ } ++ ++ // In case deinterlace interpolates frames use every other usec ++ return (struct timeval){.tv_sec = n / 500000, .tv_usec = (n % 500000) * 2}; ++} ++ ++static void pts_track_uninit(pts_track_t * const trk) ++{ ++ unsigned int i; ++ for (i = 0; i != PTS_TRACK_SIZE; ++i) { ++ trk->a[i].n = 0; ++ av_frame_free(&trk->a[i].props); ++ } ++} ++ ++static int pts_track_init(pts_track_t * const trk, void *logctx) ++{ ++ unsigned int i; ++ trk->n = 1; ++ pts_stats_init(&trk->stats, logctx, "track"); ++ for (i = 0; i != PTS_TRACK_SIZE; ++i) { ++ trk->a[i].n = 0; ++ if ((trk->a[i].props = av_frame_alloc()) == NULL) { ++ pts_track_uninit(trk); ++ return AVERROR(ENOMEM); ++ } ++ } ++ return 0; ++} ++ ++static int deint_v4l2m2m_prepare_context(DeintV4L2M2MContextShared *ctx) ++{ ++ struct v4l2_capability cap; ++ int ret; ++ ++ memset(&cap, 0, sizeof(cap)); ++ ret = ioctl(ctx->fd, VIDIOC_QUERYCAP, &cap); ++ if (ret < 0) ++ return ret; ++ ++ if (!(cap.capabilities & V4L2_CAP_STREAMING)) ++ return AVERROR(EINVAL); ++ ++ if (cap.capabilities & V4L2_CAP_VIDEO_M2M) { ++ ctx->capture.format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ ctx->output.format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ ++ return 0; ++ } ++ ++ if (cap.capabilities & V4L2_CAP_VIDEO_M2M_MPLANE) { ++ ctx->capture.format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; ++ ctx->output.format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; ++ ++ return 0; ++ } ++ ++ return AVERROR(EINVAL); ++} ++ ++static int deint_v4l2m2m_try_format(V4L2Queue *queue) ++{ ++ struct v4l2_format *fmt = &queue->format; ++ DeintV4L2M2MContextShared *ctx = queue->ctx; ++ int ret, field; ++ ++ ret = ioctl(ctx->fd, VIDIOC_G_FMT, fmt); ++ if (ret) ++ av_log(ctx->logctx, AV_LOG_ERROR, "VIDIOC_G_FMT failed: %d\n", ret); ++ ++ if (V4L2_TYPE_IS_OUTPUT(fmt->type)) ++ field = V4L2_FIELD_INTERLACED_TB; ++ else ++ field = V4L2_FIELD_NONE; ++ ++ if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) { ++ fmt->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420; ++ fmt->fmt.pix_mp.field = field; ++ fmt->fmt.pix_mp.width = ctx->width; ++ fmt->fmt.pix_mp.height = ctx->height; ++ } else { ++ fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; ++ fmt->fmt.pix.field = field; ++ fmt->fmt.pix.width = ctx->width; ++ fmt->fmt.pix.height = ctx->height; ++ } ++ ++ av_log(ctx->logctx, AV_LOG_DEBUG, "%s: Trying format for type %d, wxh: %dx%d, fmt: %08x, size %u bpl %u pre\n", __func__, ++ fmt->type, fmt->fmt.pix_mp.width, fmt->fmt.pix_mp.height, ++ fmt->fmt.pix_mp.pixelformat, ++ fmt->fmt.pix_mp.plane_fmt[0].sizeimage, fmt->fmt.pix_mp.plane_fmt[0].bytesperline); ++ ++ ret = ioctl(ctx->fd, VIDIOC_TRY_FMT, fmt); ++ if (ret) ++ return AVERROR(EINVAL); ++ ++ av_log(ctx->logctx, AV_LOG_DEBUG, "%s: Trying format for type %d, wxh: %dx%d, fmt: %08x, size %u bpl %u post\n", __func__, ++ fmt->type, fmt->fmt.pix_mp.width, fmt->fmt.pix_mp.height, ++ fmt->fmt.pix_mp.pixelformat, ++ fmt->fmt.pix_mp.plane_fmt[0].sizeimage, fmt->fmt.pix_mp.plane_fmt[0].bytesperline); ++ ++ if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) { ++ if ((fmt->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_YUV420 && ++ fmt->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV12) || ++ fmt->fmt.pix_mp.field != field) { ++ av_log(ctx->logctx, AV_LOG_DEBUG, "format not supported for type %d\n", fmt->type); ++ ++ return AVERROR(EINVAL); ++ } ++ } else { ++ if ((fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_YUV420 && ++ fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_NV12) || ++ fmt->fmt.pix.field != field) { ++ av_log(ctx->logctx, AV_LOG_DEBUG, "format not supported for type %d\n", fmt->type); ++ ++ return AVERROR(EINVAL); ++ } ++ } ++ ++ return 0; ++} ++ ++static int deint_v4l2m2m_set_format(V4L2Queue *queue, uint32_t pixelformat, uint32_t field, int width, int height, int pitch, int ysize) ++{ ++ struct v4l2_format *fmt = &queue->format; ++ DeintV4L2M2MContextShared *ctx = queue->ctx; ++ int ret; ++ ++ struct v4l2_selection sel = { ++ .type = fmt->type, ++ .target = V4L2_TYPE_IS_OUTPUT(fmt->type) ? V4L2_SEL_TGT_CROP_BOUNDS : V4L2_SEL_TGT_COMPOSE_BOUNDS, ++ }; ++ ++ // This works for most single object 4:2:0 types ++ if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) { ++ fmt->fmt.pix_mp.pixelformat = pixelformat; ++ fmt->fmt.pix_mp.field = field; ++ fmt->fmt.pix_mp.width = width; ++ fmt->fmt.pix_mp.height = ysize / pitch; ++ fmt->fmt.pix_mp.plane_fmt[0].bytesperline = pitch; ++ fmt->fmt.pix_mp.plane_fmt[0].sizeimage = ysize + (ysize >> 1); ++ } else { ++ fmt->fmt.pix.pixelformat = pixelformat; ++ fmt->fmt.pix.field = field; ++ fmt->fmt.pix.width = width; ++ fmt->fmt.pix.height = height; ++ fmt->fmt.pix.sizeimage = 0; ++ fmt->fmt.pix.bytesperline = 0; ++ } ++ ++ ret = ioctl(ctx->fd, VIDIOC_S_FMT, fmt); ++ if (ret) { ++ ret = AVERROR(errno); ++ av_log(ctx->logctx, AV_LOG_ERROR, "VIDIOC_S_FMT failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (pixelformat != fmt->fmt.pix.pixelformat) { ++ av_log(ctx->logctx, AV_LOG_ERROR, "Format not supported: %s; S_FMT returned %s\n", av_fourcc2str(pixelformat), av_fourcc2str(fmt->fmt.pix.pixelformat)); ++ return AVERROR(EINVAL); ++ } ++ ++ ret = ioctl(ctx->fd, VIDIOC_G_SELECTION, &sel); ++ if (ret) { ++ ret = AVERROR(errno); ++ av_log(ctx->logctx, AV_LOG_WARNING, "VIDIOC_G_SELECTION failed: %d\n", ret); ++ } ++ ++ sel.r.width = width; ++ sel.r.height = height; ++ sel.r.left = 0; ++ sel.r.top = 0; ++ sel.target = V4L2_TYPE_IS_OUTPUT(fmt->type) ? V4L2_SEL_TGT_CROP : V4L2_SEL_TGT_COMPOSE, ++ sel.flags = V4L2_SEL_FLAG_LE; ++ ++ ret = ioctl(ctx->fd, VIDIOC_S_SELECTION, &sel); ++ if (ret) { ++ ret = AVERROR(errno); ++ av_log(ctx->logctx, AV_LOG_WARNING, "VIDIOC_S_SELECTION failed: %d\n", ret); ++ } ++ ++ return 0; ++} ++ ++static int deint_v4l2m2m_probe_device(DeintV4L2M2MContextShared *ctx, char *node) ++{ ++ int ret; ++ ++ ctx->fd = open(node, O_RDWR | O_NONBLOCK, 0); ++ if (ctx->fd < 0) ++ return AVERROR(errno); ++ ++ ret = deint_v4l2m2m_prepare_context(ctx); ++ if (ret) ++ goto fail; ++ ++ ret = deint_v4l2m2m_try_format(&ctx->capture); ++ if (ret) ++ goto fail; ++ ++ ret = deint_v4l2m2m_try_format(&ctx->output); ++ if (ret) ++ goto fail; ++ ++ return 0; ++ ++fail: ++ close(ctx->fd); ++ ctx->fd = -1; ++ ++ return ret; ++} ++ ++static int deint_v4l2m2m_find_device(DeintV4L2M2MContextShared *ctx) ++{ ++ int ret = AVERROR(EINVAL); ++ struct dirent *entry; ++ char node[PATH_MAX]; ++ DIR *dirp; ++ ++ dirp = opendir("/dev"); ++ if (!dirp) ++ return AVERROR(errno); ++ ++ for (entry = readdir(dirp); entry; entry = readdir(dirp)) { ++ ++ if (strncmp(entry->d_name, "video", 5)) ++ continue; ++ ++ snprintf(node, sizeof(node), "/dev/%s", entry->d_name); ++ av_log(ctx->logctx, AV_LOG_DEBUG, "probing device %s\n", node); ++ ret = deint_v4l2m2m_probe_device(ctx, node); ++ if (!ret) ++ break; ++ } ++ ++ closedir(dirp); ++ ++ if (ret) { ++ av_log(ctx->logctx, AV_LOG_ERROR, "Could not find a valid device\n"); ++ ctx->fd = -1; ++ ++ return ret; ++ } ++ ++ av_log(ctx->logctx, AV_LOG_INFO, "Using device %s\n", node); ++ ++ return 0; ++} ++ ++static int deint_v4l2m2m_enqueue_buffer(V4L2Buffer *buf) ++{ ++ int ret; ++ ++ ret = ioctl(buf->q->ctx->fd, VIDIOC_QBUF, &buf->buffer); ++ if (ret < 0) ++ return AVERROR(errno); ++ ++ buf->enqueued = 1; ++ ++ return 0; ++} ++ ++static int v4l2_buffer_export_drm(V4L2Buffer* avbuf, const uint32_t pixelformat) ++{ ++ struct v4l2_exportbuffer expbuf; ++ int i, ret; ++ uint64_t mod = DRM_FORMAT_MOD_LINEAR; ++ uint32_t fmt = 0; ++ ++ switch (pixelformat) { ++ case V4L2_PIX_FMT_NV12: ++ fmt = DRM_FORMAT_NV12; ++ break; ++ case V4L2_PIX_FMT_YUV420: ++ fmt = DRM_FORMAT_YUV420; ++ break; ++ default: ++ return AVERROR(EINVAL); ++ } ++ ++ avbuf->drm_frame.layers[0].format = fmt; ++ ++ for (i = 0; i < avbuf->num_planes; i++) { ++ memset(&expbuf, 0, sizeof(expbuf)); ++ ++ expbuf.index = avbuf->buffer.index; ++ expbuf.type = avbuf->buffer.type; ++ expbuf.plane = i; ++ ++ ret = ioctl(avbuf->q->ctx->fd, VIDIOC_EXPBUF, &expbuf); ++ if (ret < 0) ++ return AVERROR(errno); ++ ++ avbuf->fd = expbuf.fd; ++ ++ if (V4L2_TYPE_IS_MULTIPLANAR(avbuf->buffer.type)) { ++ /* drm frame */ ++ avbuf->drm_frame.objects[i].size = avbuf->buffer.m.planes[i].length; ++ avbuf->drm_frame.objects[i].fd = expbuf.fd; ++ avbuf->drm_frame.objects[i].format_modifier = mod; ++ } else { ++ /* drm frame */ ++ avbuf->drm_frame.objects[0].size = avbuf->buffer.length; ++ avbuf->drm_frame.objects[0].fd = expbuf.fd; ++ avbuf->drm_frame.objects[0].format_modifier = mod; ++ } ++ } ++ ++ return 0; ++} ++ ++static int deint_v4l2m2m_allocate_buffers(V4L2Queue *queue) ++{ ++ struct v4l2_format *fmt = &queue->format; ++ DeintV4L2M2MContextShared *ctx = queue->ctx; ++ struct v4l2_requestbuffers req; ++ int ret, i, j, multiplanar; ++ uint32_t memory; ++ ++ memory = V4L2_TYPE_IS_OUTPUT(fmt->type) ? ++ V4L2_MEMORY_DMABUF : V4L2_MEMORY_MMAP; ++ ++ multiplanar = V4L2_TYPE_IS_MULTIPLANAR(fmt->type); ++ ++ memset(&req, 0, sizeof(req)); ++ req.count = queue->num_buffers; ++ req.memory = memory; ++ req.type = fmt->type; ++ ++ ret = ioctl(ctx->fd, VIDIOC_REQBUFS, &req); ++ if (ret < 0) { ++ av_log(ctx->logctx, AV_LOG_ERROR, "VIDIOC_REQBUFS failed: %s\n", strerror(errno)); ++ ++ return AVERROR(errno); ++ } ++ ++ queue->num_buffers = req.count; ++ queue->buffers = av_mallocz(queue->num_buffers * sizeof(V4L2Buffer)); ++ if (!queue->buffers) { ++ av_log(ctx->logctx, AV_LOG_ERROR, "malloc enomem\n"); ++ ++ return AVERROR(ENOMEM); ++ } ++ ++ for (i = 0; i < queue->num_buffers; i++) { ++ V4L2Buffer *buf = &queue->buffers[i]; ++ ++ buf->enqueued = 0; ++ buf->fd = -1; ++ buf->q = queue; ++ ++ buf->buffer.type = fmt->type; ++ buf->buffer.memory = memory; ++ buf->buffer.index = i; ++ ++ if (multiplanar) { ++ buf->buffer.length = VIDEO_MAX_PLANES; ++ buf->buffer.m.planes = buf->planes; ++ } ++ ++ ret = ioctl(ctx->fd, VIDIOC_QUERYBUF, &buf->buffer); ++ if (ret < 0) { ++ ret = AVERROR(errno); ++ ++ goto fail; ++ } ++ ++ if (multiplanar) ++ buf->num_planes = buf->buffer.length; ++ else ++ buf->num_planes = 1; ++ ++ for (j = 0; j < buf->num_planes; j++) { ++ V4L2PlaneInfo *info = &buf->plane_info[j]; ++ ++ if (multiplanar) { ++ info->bytesperline = fmt->fmt.pix_mp.plane_fmt[j].bytesperline; ++ info->length = buf->buffer.m.planes[j].length; ++ } else { ++ info->bytesperline = fmt->fmt.pix.bytesperline; ++ info->length = buf->buffer.length; ++ } ++ } ++ ++ if (!V4L2_TYPE_IS_OUTPUT(fmt->type)) { ++ ret = deint_v4l2m2m_enqueue_buffer(buf); ++ if (ret) ++ goto fail; ++ ++ ret = v4l2_buffer_export_drm(buf, multiplanar ? fmt->fmt.pix_mp.pixelformat : fmt->fmt.pix.pixelformat); ++ if (ret) ++ goto fail; ++ } ++ } ++ ++ return 0; ++ ++fail: ++ for (i = 0; i < queue->num_buffers; i++) ++ if (queue->buffers[i].fd >= 0) ++ close(queue->buffers[i].fd); ++ av_free(queue->buffers); ++ queue->buffers = NULL; ++ ++ return ret; ++} ++ ++static int deint_v4l2m2m_streamon(V4L2Queue *queue) ++{ ++ DeintV4L2M2MContextShared * const ctx = queue->ctx; ++ int type = queue->format.type; ++ int ret; ++ ++ ret = ioctl(ctx->fd, VIDIOC_STREAMON, &type); ++ av_log(ctx->logctx, AV_LOG_DEBUG, "%s: type:%d ret:%d errno:%d\n", __func__, type, ret, AVERROR(errno)); ++ if (ret < 0) ++ return AVERROR(errno); ++ ++ return 0; ++} ++ ++static int deint_v4l2m2m_streamoff(V4L2Queue *queue) ++{ ++ DeintV4L2M2MContextShared * const ctx = queue->ctx; ++ int type = queue->format.type; ++ int ret; ++ ++ ret = ioctl(ctx->fd, VIDIOC_STREAMOFF, &type); ++ av_log(ctx->logctx, AV_LOG_DEBUG, "%s: type:%d ret:%d errno:%d\n", __func__, type, ret, AVERROR(errno)); ++ if (ret < 0) ++ return AVERROR(errno); ++ ++ return 0; ++} ++ ++// timeout in ms ++static V4L2Buffer* deint_v4l2m2m_dequeue_buffer(V4L2Queue *queue, int timeout) ++{ ++ struct v4l2_plane planes[VIDEO_MAX_PLANES]; ++ DeintV4L2M2MContextShared *ctx = queue->ctx; ++ struct v4l2_buffer buf = { 0 }; ++ V4L2Buffer* avbuf = NULL; ++ struct pollfd pfd; ++ short events; ++ int ret; ++ ++ if (V4L2_TYPE_IS_OUTPUT(queue->format.type)) ++ events = POLLOUT | POLLWRNORM; ++ else ++ events = POLLIN | POLLRDNORM; ++ ++ pfd.events = events; ++ pfd.fd = ctx->fd; ++ ++ for (;;) { ++ ret = poll(&pfd, 1, timeout); ++ if (ret > 0) ++ break; ++ if (errno == EINTR) ++ continue; ++ return NULL; ++ } ++ ++ if (pfd.revents & POLLERR) ++ return NULL; ++ ++ if (pfd.revents & events) { ++ memset(&buf, 0, sizeof(buf)); ++ buf.memory = V4L2_MEMORY_MMAP; ++ buf.type = queue->format.type; ++ if (V4L2_TYPE_IS_MULTIPLANAR(queue->format.type)) { ++ memset(planes, 0, sizeof(planes)); ++ buf.length = VIDEO_MAX_PLANES; ++ buf.m.planes = planes; ++ } ++ ++ ret = ioctl(ctx->fd, VIDIOC_DQBUF, &buf); ++ if (ret) { ++ if (errno != EAGAIN) ++ av_log(ctx->logctx, AV_LOG_DEBUG, "VIDIOC_DQBUF, errno (%s)\n", ++ av_err2str(AVERROR(errno))); ++ return NULL; ++ } ++ ++ avbuf = &queue->buffers[buf.index]; ++ avbuf->enqueued = 0; ++ avbuf->buffer = buf; ++ if (V4L2_TYPE_IS_MULTIPLANAR(queue->format.type)) { ++ memcpy(avbuf->planes, planes, sizeof(planes)); ++ avbuf->buffer.m.planes = avbuf->planes; ++ } ++ return avbuf; ++ } ++ ++ return NULL; ++} ++ ++static V4L2Buffer *deint_v4l2m2m_find_free_buf(V4L2Queue *queue) ++{ ++ int i; ++ V4L2Buffer *buf = NULL; ++ ++ for (i = 0; i < queue->num_buffers; i++) ++ if (!queue->buffers[i].enqueued) { ++ buf = &queue->buffers[i]; ++ break; ++ } ++ return buf; ++} ++ ++static void deint_v4l2m2m_unref_queued(V4L2Queue *queue) ++{ ++ int i; ++ V4L2Buffer *buf = NULL; ++ ++ if (!queue || !queue->buffers) ++ return; ++ for (i = 0; i < queue->num_buffers; i++) { ++ buf = &queue->buffers[i]; ++ if (queue->buffers[i].enqueued) ++ av_frame_unref(&buf->frame); ++ } ++} ++ ++static void recycle_q(V4L2Queue * const queue) ++{ ++ V4L2Buffer* avbuf; ++ while (avbuf = deint_v4l2m2m_dequeue_buffer(queue, 0), avbuf) { ++ av_frame_unref(&avbuf->frame); ++ } ++} ++ ++static int count_enqueued(V4L2Queue *queue) ++{ ++ int i; ++ int n = 0; ++ ++ if (queue->buffers == NULL) ++ return 0; ++ ++ for (i = 0; i < queue->num_buffers; i++) ++ if (queue->buffers[i].enqueued) ++ ++n; ++ return n; ++} ++ ++static int deint_v4l2m2m_enqueue_frame(V4L2Queue * const queue, AVFrame * const frame) ++{ ++ DeintV4L2M2MContextShared *const ctx = queue->ctx; ++ AVDRMFrameDescriptor *drm_desc = (AVDRMFrameDescriptor *)frame->data[0]; ++ V4L2Buffer *buf; ++ int i; ++ ++ if (V4L2_TYPE_IS_OUTPUT(queue->format.type)) ++ recycle_q(queue); ++ ++ buf = deint_v4l2m2m_find_free_buf(queue); ++ if (!buf) { ++ av_log(ctx->logctx, AV_LOG_ERROR, "%s: error %d finding free buf\n", __func__, 0); ++ return AVERROR(EAGAIN); ++ } ++ if (V4L2_TYPE_IS_MULTIPLANAR(buf->buffer.type)) ++ for (i = 0; i < drm_desc->nb_objects; i++) ++ buf->buffer.m.planes[i].m.fd = drm_desc->objects[i].fd; ++ else ++ buf->buffer.m.fd = drm_desc->objects[0].fd; ++ ++ buf->buffer.field = !frame->interlaced_frame ? V4L2_FIELD_NONE : ++ frame->top_field_first ? V4L2_FIELD_INTERLACED_TB : ++ V4L2_FIELD_INTERLACED_BT; ++ ++ if (ctx->field_order != buf->buffer.field) { ++ av_log(ctx->logctx, AV_LOG_DEBUG, "%s: Field changed: %d->%d\n", __func__, ctx->field_order, buf->buffer.field); ++ ctx->field_order = buf->buffer.field; ++ } ++ ++ buf->buffer.timestamp = pts_track_add_frame(&ctx->track, frame); ++ ++ buf->drm_frame.objects[0].fd = drm_desc->objects[0].fd; ++ ++ av_frame_move_ref(&buf->frame, frame); ++ ++ return deint_v4l2m2m_enqueue_buffer(buf); ++} ++ ++static void deint_v4l2m2m_destroy_context(DeintV4L2M2MContextShared *ctx) ++{ ++ if (atomic_fetch_sub(&ctx->refcount, 1) == 1) { ++ V4L2Queue *capture = &ctx->capture; ++ V4L2Queue *output = &ctx->output; ++ int i; ++ ++ av_log(NULL, AV_LOG_DEBUG, "%s - destroying context\n", __func__); ++ ++ if (ctx->fd >= 0) { ++ deint_v4l2m2m_streamoff(capture); ++ deint_v4l2m2m_streamoff(output); ++ } ++ ++ if (capture->buffers) ++ for (i = 0; i < capture->num_buffers; i++) { ++ capture->buffers[i].q = NULL; ++ if (capture->buffers[i].fd >= 0) ++ close(capture->buffers[i].fd); ++ } ++ ++ deint_v4l2m2m_unref_queued(output); ++ ++ av_buffer_unref(&ctx->hw_frames_ctx); ++ ++ if (capture->buffers) ++ av_free(capture->buffers); ++ ++ if (output->buffers) ++ av_free(output->buffers); ++ ++ if (ctx->fd >= 0) { ++ close(ctx->fd); ++ ctx->fd = -1; ++ } ++ ++ av_free(ctx); ++ } ++} ++ ++static void v4l2_free_buffer(void *opaque, uint8_t *unused) ++{ ++ V4L2Buffer *buf = opaque; ++ DeintV4L2M2MContextShared *ctx = buf->q->ctx; ++ ++ if (!ctx->done) ++ deint_v4l2m2m_enqueue_buffer(buf); ++ ++ deint_v4l2m2m_destroy_context(ctx); ++} ++ ++static uint8_t * v4l2_get_drm_frame(V4L2Buffer *avbuf, int height) ++{ ++ AVDRMFrameDescriptor *drm_desc = &avbuf->drm_frame; ++ AVDRMLayerDescriptor *layer; ++ ++ /* fill the DRM frame descriptor */ ++ drm_desc->nb_objects = avbuf->num_planes; ++ drm_desc->nb_layers = 1; ++ ++ layer = &drm_desc->layers[0]; ++ layer->nb_planes = avbuf->num_planes; ++ ++ for (int i = 0; i < avbuf->num_planes; i++) { ++ layer->planes[i].object_index = i; ++ layer->planes[i].offset = 0; ++ layer->planes[i].pitch = avbuf->plane_info[i].bytesperline; ++ } ++ ++ switch (layer->format) { ++ case DRM_FORMAT_YUYV: ++ layer->nb_planes = 1; ++ break; ++ ++ case DRM_FORMAT_NV12: ++ case DRM_FORMAT_NV21: ++ if (avbuf->num_planes > 1) ++ break; ++ ++ layer->nb_planes = 2; ++ ++ layer->planes[1].object_index = 0; ++ layer->planes[1].offset = avbuf->plane_info[0].bytesperline * ++ height; ++ layer->planes[1].pitch = avbuf->plane_info[0].bytesperline; ++ break; ++ ++ case DRM_FORMAT_YUV420: ++ if (avbuf->num_planes > 1) ++ break; ++ ++ layer->nb_planes = 3; ++ ++ layer->planes[1].object_index = 0; ++ layer->planes[1].offset = avbuf->plane_info[0].bytesperline * ++ height; ++ layer->planes[1].pitch = avbuf->plane_info[0].bytesperline >> 1; ++ ++ layer->planes[2].object_index = 0; ++ layer->planes[2].offset = layer->planes[1].offset + ++ ((avbuf->plane_info[0].bytesperline * ++ height) >> 2); ++ layer->planes[2].pitch = avbuf->plane_info[0].bytesperline >> 1; ++ break; ++ ++ default: ++ drm_desc->nb_layers = 0; ++ break; ++ } ++ ++ return (uint8_t *) drm_desc; ++} ++ ++// timeout in ms ++static int deint_v4l2m2m_dequeue_frame(V4L2Queue *queue, AVFrame* frame, int timeout) ++{ ++ DeintV4L2M2MContextShared *ctx = queue->ctx; ++ V4L2Buffer* avbuf; ++ ++ av_log(ctx->logctx, AV_LOG_TRACE, "<<< %s\n", __func__); ++ ++ avbuf = deint_v4l2m2m_dequeue_buffer(queue, timeout); ++ if (!avbuf) { ++ av_log(ctx->logctx, AV_LOG_DEBUG, "%s: No buffer to dequeue (timeout=%d)\n", __func__, timeout); ++ return AVERROR(EAGAIN); ++ } ++ ++ // Fill in PTS and anciliary info from src frame ++ // we will want to overwrite some fields as only the pts/dts ++ // fields are updated with new timing in this fn ++ pts_track_get_frame(&ctx->track, avbuf->buffer.timestamp, frame); ++ ++ frame->buf[0] = av_buffer_create((uint8_t *) &avbuf->drm_frame, ++ sizeof(avbuf->drm_frame), v4l2_free_buffer, ++ avbuf, AV_BUFFER_FLAG_READONLY); ++ if (!frame->buf[0]) { ++ av_log(ctx->logctx, AV_LOG_ERROR, "%s: error %d creating buffer\n", __func__, 0); ++ return AVERROR(ENOMEM); ++ } ++ ++ atomic_fetch_add(&ctx->refcount, 1); ++ ++ frame->data[0] = (uint8_t *)v4l2_get_drm_frame(avbuf, ctx->orig_height); ++ frame->format = AV_PIX_FMT_DRM_PRIME; ++ if (ctx->hw_frames_ctx) ++ frame->hw_frames_ctx = av_buffer_ref(ctx->hw_frames_ctx); ++ frame->height = ctx->height; ++ frame->width = ctx->width; ++ ++ // Not interlaced now ++ frame->interlaced_frame = 0; ++ frame->top_field_first = 0; ++ // Pkt duration halved ++ frame->pkt_duration /= 2; ++ ++ if (avbuf->buffer.flags & V4L2_BUF_FLAG_ERROR) { ++ av_log(ctx->logctx, AV_LOG_ERROR, "driver decode error\n"); ++ frame->decode_error_flags |= FF_DECODE_ERROR_INVALID_BITSTREAM; ++ } ++ ++ av_log(ctx->logctx, AV_LOG_TRACE, ">>> %s: PTS=%"PRId64"\n", __func__, frame->pts); ++ return 0; ++} ++ ++static int deint_v4l2m2m_config_props(AVFilterLink *outlink) ++{ ++ AVFilterLink *inlink = outlink->src->inputs[0]; ++ AVFilterContext *avctx = outlink->src; ++ DeintV4L2M2MContext *priv = avctx->priv; ++ DeintV4L2M2MContextShared *ctx = priv->shared; ++ int ret; ++ ++ ctx->height = avctx->inputs[0]->h; ++ ctx->width = avctx->inputs[0]->w; ++ ++ av_log(priv, AV_LOG_DEBUG, "%s: %dx%d\n", __func__, ctx->width, ctx->height); ++ ++ outlink->time_base = inlink->time_base; ++ outlink->w = inlink->w; ++ outlink->h = inlink->h; ++ outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; ++ outlink->format = inlink->format; ++ outlink->frame_rate = (AVRational) {1, 0}; // Deny knowledge of frame rate ++ ++ ret = deint_v4l2m2m_find_device(ctx); ++ if (ret) ++ return ret; ++ ++ if (inlink->hw_frames_ctx) { ++ ctx->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx); ++ if (!ctx->hw_frames_ctx) ++ return AVERROR(ENOMEM); ++ } ++ return 0; ++} ++ ++static int deint_v4l2m2m_query_formats(AVFilterContext *avctx) ++{ ++ static const enum AVPixelFormat pixel_formats[] = { ++ AV_PIX_FMT_DRM_PRIME, ++ AV_PIX_FMT_YUV420P, ++ AV_PIX_FMT_NONE, ++ }; ++ ++ return ff_set_common_formats(avctx, ff_make_format_list(pixel_formats)); ++} ++ ++static uint32_t desc_pixelformat(const AVDRMFrameDescriptor * const drm_desc) ++{ ++ const int is_linear = (drm_desc->objects[0].format_modifier == DRM_FORMAT_MOD_LINEAR || ++ drm_desc->objects[0].format_modifier == DRM_FORMAT_MOD_INVALID); ++ ++ switch (drm_desc->layers[0].format) { ++ case DRM_FORMAT_YUV420: ++ if (is_linear) ++ return drm_desc->nb_objects == 1 ? V4L2_PIX_FMT_YUV420 : 0; ++ break; ++ case DRM_FORMAT_NV12: ++ if (is_linear) ++ return drm_desc->nb_objects == 1 ? V4L2_PIX_FMT_NV12 : 0; ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static int deint_v4l2m2m_filter_frame(AVFilterLink *link, AVFrame *in) ++{ ++ AVFilterContext *avctx = link->dst; ++ DeintV4L2M2MContext *priv = avctx->priv; ++ DeintV4L2M2MContextShared *ctx = priv->shared; ++ V4L2Queue *capture = &ctx->capture; ++ V4L2Queue *output = &ctx->output; ++ int ret; ++ ++ av_log(priv, AV_LOG_DEBUG, "<<< %s: input pts: %"PRId64" (%"PRId64") field :%d interlaced: %d aspect:%d/%d\n", ++ __func__, in->pts, AV_NOPTS_VALUE, in->top_field_first, in->interlaced_frame, in->sample_aspect_ratio.num, in->sample_aspect_ratio.den); ++ av_log(priv, AV_LOG_DEBUG, "--- %s: in status in %d/ot %d; out status in %d/out %d\n", __func__, ++ avctx->inputs[0]->status_in, avctx->inputs[0]->status_out, avctx->outputs[0]->status_in, avctx->outputs[0]->status_out); ++ ++ if (ctx->field_order == V4L2_FIELD_ANY) { ++ const AVDRMFrameDescriptor * const drm_desc = (AVDRMFrameDescriptor *)in->data[0]; ++ const uint32_t pixelformat = desc_pixelformat(drm_desc); ++ ++ if (pixelformat == 0) { ++ av_log(avctx, AV_LOG_ERROR, "Unsupported DRM format %s in %d objects, modifier %#" PRIx64 "\n", ++ av_fourcc2str(drm_desc->layers[0].format), ++ drm_desc->nb_objects, drm_desc->objects[0].format_modifier); ++ return AVERROR(EINVAL); ++ } ++ ++ ctx->orig_width = drm_desc->layers[0].planes[0].pitch; ++ ctx->orig_height = drm_desc->layers[0].planes[1].offset / ctx->orig_width; ++ ++ av_log(priv, AV_LOG_DEBUG, "%s: %dx%d (%td,%td)\n", __func__, ctx->width, ctx->height, ++ drm_desc->layers[0].planes[0].pitch, drm_desc->layers[0].planes[1].offset); ++ ++ ret = deint_v4l2m2m_set_format(output, pixelformat, ctx->field_order, ctx->width, ctx->height, ctx->orig_width, drm_desc->layers[0].planes[1].offset); ++ if (ret) ++ return ret; ++ ++ ret = deint_v4l2m2m_set_format(capture, pixelformat, V4L2_FIELD_NONE, ctx->width, ctx->height, ctx->orig_width, drm_desc->layers[0].planes[1].offset); ++ if (ret) ++ return ret; ++ ++ ret = deint_v4l2m2m_allocate_buffers(capture); ++ if (ret) ++ return ret; ++ ++ ret = deint_v4l2m2m_streamon(capture); ++ if (ret) ++ return ret; ++ ++ ret = deint_v4l2m2m_allocate_buffers(output); ++ if (ret) ++ return ret; ++ ++ ret = deint_v4l2m2m_streamon(output); ++ if (ret) ++ return ret; ++ ++ if (in->top_field_first) ++ ctx->field_order = V4L2_FIELD_INTERLACED_TB; ++ else ++ ctx->field_order = V4L2_FIELD_INTERLACED_BT; ++ ++ } ++ ++ ret = deint_v4l2m2m_enqueue_frame(output, in); ++ ++ av_log(priv, AV_LOG_TRACE, ">>> %s: %s\n", __func__, av_err2str(ret)); ++ return ret; ++} ++ ++static int deint_v4l2m2m_activate(AVFilterContext *avctx) ++{ ++ DeintV4L2M2MContext * const priv = avctx->priv; ++ DeintV4L2M2MContextShared *const s = priv->shared; ++ AVFilterLink * const outlink = avctx->outputs[0]; ++ AVFilterLink * const inlink = avctx->inputs[0]; ++ int n = 0; ++ int cn = 99; ++ int instatus = 0; ++ int64_t inpts = 0; ++ int did_something = 0; ++ ++ av_log(priv, AV_LOG_TRACE, "<<< %s\n", __func__); ++ ++ FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, avctx); ++ ++ ff_inlink_acknowledge_status(inlink, &instatus, &inpts); ++ ++ if (!ff_outlink_frame_wanted(outlink)) { ++ av_log(priv, AV_LOG_TRACE, "%s: Not wanted out\n", __func__); ++ } ++ else if (s->field_order != V4L2_FIELD_ANY) // Can't DQ if no setup! ++ { ++ AVFrame * frame = av_frame_alloc(); ++ int rv; ++ ++again: ++ recycle_q(&s->output); ++ n = count_enqueued(&s->output); ++ ++ if (frame == NULL) { ++ av_log(priv, AV_LOG_ERROR, "%s: error allocating frame\n", __func__); ++ return AVERROR(ENOMEM); ++ } ++ ++ rv = deint_v4l2m2m_dequeue_frame(&s->capture, frame, n > 4 ? 300 : 0); ++ if (rv != 0) { ++ av_frame_free(&frame); ++ if (rv != AVERROR(EAGAIN)) { ++ av_log(priv, AV_LOG_ERROR, ">>> %s: DQ fail: %s\n", __func__, av_err2str(rv)); ++ return rv; ++ } ++ } ++ else { ++ frame->interlaced_frame = 0; ++ // frame is always consumed by filter_frame - even on error despite ++ // a somewhat confusing comment in the header ++ rv = ff_filter_frame(outlink, frame); ++ ++ if (instatus != 0) { ++ av_log(priv, AV_LOG_TRACE, "%s: eof loop\n", __func__); ++ goto again; ++ } ++ ++ av_log(priv, AV_LOG_TRACE, "%s: Filtered: %s\n", __func__, av_err2str(rv)); ++ did_something = 1; ++ } ++ ++ cn = count_enqueued(&s->capture); ++ } ++ ++ if (instatus != 0) { ++ ff_outlink_set_status(outlink, instatus, inpts); ++ av_log(priv, AV_LOG_TRACE, ">>> %s: Status done: %s\n", __func__, av_err2str(instatus)); ++ return 0; ++ } ++ ++ recycle_q(&s->output); ++ n = count_enqueued(&s->output); ++ ++ while (n < 6) { ++ AVFrame * frame; ++ int rv; ++ ++ if ((rv = ff_inlink_consume_frame(inlink, &frame)) < 0) { ++ av_log(priv, AV_LOG_ERROR, "%s: consume in failed: %s\n", __func__, av_err2str(rv)); ++ return rv; ++ } ++ ++ if (frame == NULL) { ++ av_log(priv, AV_LOG_TRACE, "%s: No frame\n", __func__); ++ break; ++ } ++ ++ rv = deint_v4l2m2m_filter_frame(inlink, frame); ++ av_frame_free(&frame); ++ ++ if (rv != 0) ++ return rv; ++ ++ av_log(priv, AV_LOG_TRACE, "%s: Q frame\n", __func__); ++ ++n; ++ } ++ ++ if (n < 6) { ++ ff_inlink_request_frame(inlink); ++ did_something = 1; ++ av_log(priv, AV_LOG_TRACE, "%s: req frame\n", __func__); ++ } ++ ++ if (n > 4 && ff_outlink_frame_wanted(outlink)) { ++ ff_filter_set_ready(avctx, 1); ++ did_something = 1; ++ av_log(priv, AV_LOG_TRACE, "%s: ready\n", __func__); ++ } ++ ++ av_log(priv, AV_LOG_TRACE, ">>> %s: OK (n=%d, cn=%d)\n", __func__, n, cn); ++ return did_something ? 0 : FFERROR_NOT_READY; ++} ++ ++static av_cold int deint_v4l2m2m_init(AVFilterContext *avctx) ++{ ++ DeintV4L2M2MContext * const priv = avctx->priv; ++ DeintV4L2M2MContextShared * const ctx = av_mallocz(sizeof(DeintV4L2M2MContextShared)); ++ ++ if (!ctx) { ++ av_log(priv, AV_LOG_ERROR, "%s: error %d allocating context\n", __func__, 0); ++ return AVERROR(ENOMEM); ++ } ++ priv->shared = ctx; ++ ctx->logctx = priv; ++ ctx->fd = -1; ++ ctx->output.ctx = ctx; ++ ctx->output.num_buffers = 8; ++ ctx->capture.ctx = ctx; ++ ctx->capture.num_buffers = 12; ++ ctx->done = 0; ++ ctx->field_order = V4L2_FIELD_ANY; ++ ++ pts_track_init(&ctx->track, priv); ++ ++ atomic_init(&ctx->refcount, 1); ++ ++ return 0; ++} ++ ++static void deint_v4l2m2m_uninit(AVFilterContext *avctx) ++{ ++ DeintV4L2M2MContext *priv = avctx->priv; ++ DeintV4L2M2MContextShared *ctx = priv->shared; ++ ++ ctx->done = 1; ++ ctx->logctx = NULL; // Log to NULL works, log to missing crashes ++ pts_track_uninit(&ctx->track); ++ deint_v4l2m2m_destroy_context(ctx); ++} ++ ++static const AVOption deinterlace_v4l2m2m_options[] = { ++ { NULL }, ++}; ++ ++AVFILTER_DEFINE_CLASS(deinterlace_v4l2m2m); ++ ++static const AVFilterPad deint_v4l2m2m_inputs[] = { ++ { ++ .name = "default", ++ .type = AVMEDIA_TYPE_VIDEO, ++ }, ++ { NULL } ++}; ++ ++static const AVFilterPad deint_v4l2m2m_outputs[] = { ++ { ++ .name = "default", ++ .type = AVMEDIA_TYPE_VIDEO, ++ .config_props = deint_v4l2m2m_config_props, ++ }, ++ { NULL } ++}; ++ ++AVFilter ff_vf_deinterlace_v4l2m2m = { ++ .name = "deinterlace_v4l2m2m", ++ .description = NULL_IF_CONFIG_SMALL("V4L2 M2M deinterlacer"), ++ .priv_size = sizeof(DeintV4L2M2MContext), ++ .init = &deint_v4l2m2m_init, ++ .uninit = &deint_v4l2m2m_uninit, ++ .query_formats = &deint_v4l2m2m_query_formats, ++ .inputs = deint_v4l2m2m_inputs, ++ .outputs = deint_v4l2m2m_outputs, ++ .priv_class = &deinterlace_v4l2m2m_class, ++ .activate = deint_v4l2m2m_activate, ++}; +--- /dev/null +++ b/libavfilter/vf_unsand.c @@ -0,0 +1,234 @@ +/* @@ -56063,7 +62864,7 @@ Upstream-status: Pending @@ -3051,6 +3051,40 @@ static int has_codec_parameters(AVStream return 1; } - + +#if CONFIG_HEVC_RPI_DECODER && CONFIG_HEVC_DECODER +// This should be quite general purpose but avoid possible conflicts +// by limiting usage to cases wehere we know it works. @@ -56165,10 +62966,10 @@ Upstream-status: Pending sha512.h \ @@ -86,6 +87,7 @@ HEADERS = adler32.h tx.h \ - + HEADERS-$(CONFIG_LZO) += lzo.h +HEADERS-$(CONFIG-RPI) += rpi_sand_fn_pw.h - + ARCH_HEADERS = bswap.h \ intmath.h \ @@ -180,6 +182,7 @@ OBJS-$(CONFIG_LZO) @@ -56184,14 +62985,14 @@ Upstream-status: Pending @@ -1,4 +1,6 @@ OBJS += aarch64/cpu.o \ aarch64/float_dsp_init.o \ - + -NEON-OBJS += aarch64/float_dsp_neon.o +NEON-OBJS += aarch64/float_dsp_neon.o \ + aarch64/rpi_sand_neon.o \ + --- /dev/null +++ b/libavutil/aarch64/rpi_sand_neon.S -@@ -0,0 +1,676 @@ +@@ -0,0 +1,781 @@ +/* +Copyright (c) 2021 Michael Eiler + @@ -56252,7 +63053,7 @@ Upstream-status: Pending + + // this is the value we have to add to the src pointer after reading a complete block + // it will move the address to the start of the next block -+ // w10 = stride2 * stride1 - stride1 ++ // w10 = stride2 * stride1 - stride1 + mov w10, w4 + lsl w10, w10, #7 + sub w10, w10, #128 @@ -56279,7 +63080,7 @@ Upstream-status: Pending + // copy 128 bytes (a full block) into the vector registers v0-v7 and increase the src address by 128 + // fortunately these aren't callee saved ones, meaning we don't need to backup them + ld1 { v0.16b, v1.16b, v2.16b, v3.16b}, [x13], #64 -+ ld1 { v4.16b, v5.16b, v6.16b, v7.16b}, [x13], #64 ++ ld1 { v4.16b, v5.16b, v6.16b, v7.16b}, [x13], #64 + + // write these registers back to the destination vector and increase the dst address by 128 + st1 { v0.16b, v1.16b, v2.16b, v3.16b }, [x0], #64 @@ -56310,13 +63111,13 @@ Upstream-status: Pending + add w5, w5, #1 + b incomplete_block_loop_y8 +incomplete_block_loop_end_y8: -+ -+ -+ // increase the row offset by 128 (stride1) ++ ++ ++ // increase the row offset by 128 (stride1) + add w11, w11, #128 + // increment the row counter + add w12, w12, #1 -+ ++ + // process the next row if we haven't finished yet + cmp w15, w12 + bgt row_loop @@ -56380,7 +63181,7 @@ Upstream-status: Pending + beq no_main_c8 + +block_loop_c8: -+ // load the full block -> 128 bytes, the block contains 64 interleaved U and V values ++ // load the full block -> 128 bytes, the block contains 64 interleaved U and V values + ld2 { v0.16b, v1.16b }, [x13], #32 + ld2 { v2.16b, v3.16b }, [x13], #32 + ld2 { v4.16b, v5.16b }, [x13], #32 @@ -56403,14 +63204,14 @@ Upstream-status: Pending + // increment row counter and move src to the beginning of the next block + add w14, w14, #1 + add x13, x13, x10 -+ ++ + // jump to block_loop_c8 iff the block count is smaller than the number of full blocks + cmp w8, w14 + bgt block_loop_c8 + +no_main_c8: + // handle incomplete block at the end of every row -+ eor w5, w5, w5 // point counter, this might be ++ eor w5, w5, w5 // point counter, this might be +incomplete_block_loop_c8: + cmp w5, w9 + bge incomplete_block_loop_end_c8 @@ -56442,228 +63243,6 @@ Upstream-status: Pending + ret +endfunc + -+//void ff_rpi_sand30_lines_to_planar_y16( -+// uint8_t * dest, // [x0] -+// unsigned int dst_stride, // [w1] -> assumed to be equal to _w -+// const uint8_t * src, // [x2] -+// unsigned int src_stride1, // [w3] -> 128 -+// unsigned int src_stride2, // [w4] -+// unsigned int _x, // [w5] -+// unsigned int y, // [w6] -+// unsigned int _w, // [w7] -+// unsigned int h); // [sp, #0] -+ -+function ff_rpi_sand30_lines_to_planar_y16, export=1 -+ stp x19, x20, [sp, #-48]! -+ stp x21, x22, [sp, #16] -+ stp x23, x24, [sp, #32] -+ -+ // w6 = argument h -+ ldr w6, [sp, #48] -+ -+ // slice_inc = ((stride2 - 1) * stride1) -+ mov w5, w4 -+ sub w5, w5, #1 -+ lsl w5, w5, #7 -+ -+ // total number of bytes per row = (width / 3) * 4 -+ mov w8, w7 -+ mov w9, #3 -+ udiv w8, w8, w9 -+ lsl w8, w8, #2 -+ -+ // number of full 128 byte blocks to be processed -+ mov w9, #96 -+ udiv w9, w7, w9 // = (width * 4) / (3*128) = width/96 -+ -+ // w10 = number of full integers to process (4 bytes) -+ // w11 = remaning zero to two 10bit values still to copy over -+ mov w12, #96 -+ mul w12, w9, w12 -+ sub w12, w7, w12 // width - blocks*96 = remaining points per row -+ mov w11, #3 -+ udiv w10, w12, w11 // full integers to process = w12 / 3 -+ mul w11, w10, w11 // #integers *3 -+ sub w11, w12, w11 // remaining 0-2 points = remaining points - integers*3 -+ -+ // increase w9 by one if w10+w11 is not zero, and decrease the row count by one -+ // this is to efficiently copy incomplete blocks at the end of the rows -+ // the last row is handled explicitly to avoid writing out of bounds -+ add w22, w10, w11 -+ cmp w22, #0 -+ cset w22, ne // 1 iff w10+w11 not zero, 0 otherwise -+ add w9, w9, w22 -+ sub w6, w6, #1 -+ -+ // store the number of bytes in w20 which we copy too much for every row -+ // when the width of the frame is not a multiple of 96 (128bytes storing 96 10bit values) -+ mov w20, #96*2 -+ mul w20, w20, w9 -+ sub w20, w1, w20 -+ -+ mov w23, #0 // flag to check whether the last line had already been processed -+ -+ // bitmask to clear the uppper 6bits of the result values -+ mov x19, #0x03ff03ff03ff03ff -+ dup v22.2d, x19 -+ -+ // row counter = 0 -+ eor w12, w12, w12 -+row_loop_y16: -+ cmp w12, w6 // jump to row_loop_y16_fin if we processed all rows -+ bge row_loop_y16_fin -+ -+ mov x13, x2 // row src -+ eor w14, w14, w14 // full block counter -+block_loop_y16: -+ cmp w14, w9 -+ bge block_loop_y16_fin -+ -+ // load 64 bytes -+ ld1 { v0.4s, v1.4s, v2.4s, v3.4s }, [x13], #64 -+ -+ // process v0 and v1 -+ xtn v16.4h, v0.4s -+ ushr v0.4s, v0.4s, #10 -+ xtn v17.4h, v0.4s -+ ushr v0.4s, v0.4s, #10 -+ xtn v18.4h, v0.4s -+ -+ xtn2 v16.8h, v1.4s -+ and v16.16b, v16.16b, v22.16b -+ ushr v1.4s, v1.4s, #10 -+ xtn2 v17.8h, v1.4s -+ and v17.16b, v17.16b, v22.16b -+ ushr v1.4s, v1.4s, #10 -+ xtn2 v18.8h, v1.4s -+ and v18.16b, v18.16b, v22.16b -+ -+ st3 { v16.8h, v17.8h, v18.8h }, [x0], #48 -+ -+ // process v2 and v3 -+ xtn v23.4h, v2.4s -+ ushr v2.4s, v2.4s, #10 -+ xtn v24.4h, v2.4s -+ ushr v2.4s, v2.4s, #10 -+ xtn v25.4h, v2.4s -+ -+ xtn2 v23.8h, v3.4s -+ and v23.16b, v23.16b, v22.16b -+ ushr v3.4s, v3.4s, #10 -+ xtn2 v24.8h, v3.4s -+ and v24.16b, v24.16b, v22.16b -+ ushr v3.4s, v3.4s, #10 -+ xtn2 v25.8h, v3.4s -+ and v25.16b, v25.16b, v22.16b -+ -+ st3 { v23.8h, v24.8h, v25.8h }, [x0], #48 -+ -+ // load the second half of the block -> 64 bytes into registers v4-v7 -+ ld1 { v4.4s, v5.4s, v6.4s, v7.4s }, [x13], #64 -+ -+ // process v4 and v5 -+ xtn v16.4h, v4.4s -+ ushr v4.4s, v4.4s, #10 -+ xtn v17.4h, v4.4s -+ ushr v4.4s, v4.4s, #10 -+ xtn v18.4h, v4.4s -+ -+ xtn2 v16.8h, v5.4s -+ and v16.16b, v16.16b, v22.16b -+ ushr v5.4s, v5.4s, #10 -+ xtn2 v17.8h, v5.4s -+ and v17.16b, v17.16b, v22.16b -+ ushr v5.4s, v5.4s, #10 -+ xtn2 v18.8h, v5.4s -+ and v18.16b, v18.16b, v22.16b -+ -+ st3 { v16.8h, v17.8h, v18.8h }, [x0], #48 -+ -+ // v6 and v7 -+ xtn v23.4h, v6.4s -+ ushr v6.4s, v6.4s, #10 -+ xtn v24.4h, v6.4s -+ ushr v6.4s, v6.4s, #10 -+ xtn v25.4h, v6.4s -+ -+ xtn2 v23.8h, v7.4s -+ and v23.16b, v23.16b, v22.16b -+ ushr v7.4s, v7.4s, #10 -+ xtn2 v24.8h, v7.4s -+ and v24.16b, v24.16b, v22.16b -+ ushr v7.4s, v7.4s, #10 -+ xtn2 v25.8h, v7.4s -+ and v25.16b, v25.16b, v22.16b -+ -+ st3 { v23.8h, v24.8h, v25.8h }, [x0], #48 -+ -+ add x13, x13, x5 // row src += slice_inc -+ add w14, w14, #1 -+ b block_loop_y16 -+block_loop_y16_fin: -+ -+ -+ -+ -+ add x2, x2, #128 // src += stride1 (start of the next row) -+ add x0, x0, w20, sxtw // subtract the bytes we copied too much from dst -+ add w12, w12, #1 -+ b row_loop_y16 -+row_loop_y16_fin: -+ -+ // check whether we have incomplete blocks at the end of every row -+ // in that case decrease row block count by one -+ // change height back to it's original value (meaning increase it by 1) -+ // and jump back to another iteration of row_loop_y16 -+ -+ cmp w23, #1 -+ beq row_loop_y16_fin2 // don't continue here if we already processed the last row -+ add w6, w6, #1 // increase height to the original value -+ sub w9, w9, w22 // block count - 1 or 0, depending on the remaining bytes count -+ mov w23, #1 -+ b row_loop_y16 -+row_loop_y16_fin2: -+ -+ sub x0, x0, w20, sxtw // with the last row we didn't actually move the dst ptr to far ahead, therefore readd the diference -+ -+ // now we've got to handle the last block in the last row -+ eor w12, w12, w12 // w12 = 0 = counter -+integer_loop_y16: -+ cmp w12, w10 -+ bge integer_loop_y16_fin -+ ldr w14, [x13], #4 -+ and w15, w14, #0x3ff -+ strh w15, [x0], #2 -+ lsr w14, w14, #10 -+ and w15, w14, #0x3ff -+ strh w15, [x0], #2 -+ lsr w14, w14, #10 -+ and w15, w14, #0x3ff -+ strh w15, [x0], #2 -+ add w12, w12, #1 -+ b integer_loop_y16 -+integer_loop_y16_fin: -+ -+final_values_y16: -+ // remaining point count = w11 -+ ldr w14, [x13], #4 -+ cmp w11, #0 -+ beq final_values_y16_fin -+ and w15, w14, #0x3ff -+ strh w15, [x0], #2 -+ cmp w11, #1 -+ beq final_values_y16_fin -+ lsr w14, w14, #10 -+ and w15, w14, #0x3ff -+ strh w15, [x0], #2 -+final_values_y16_fin: -+ -+ ldp x23, x24, [sp, #32] -+ ldp x21, x22, [sp, #16] -+ ldp x19, x20, [sp], #48 -+ ret -+endfunc -+ +//void ff_rpi_sand30_lines_to_planar_c16( +// uint8_t * dst_u, // [x0] +// unsigned int dst_stride_u, // [w1] == _w*2 @@ -56671,7 +63250,7 @@ Upstream-status: Pending +// unsigned int dst_stride_v, // [w3] == _w*2 +// const uint8_t * src, // [x4] +// unsigned int stride1, // [w5] == 128 -+// unsigned int stride2, // [w6] ++// unsigned int stride2, // [w6] +// unsigned int _x, // [w7] == 0 +// unsigned int y, // [sp, #0] == 0 +// unsigned int _w, // [sp, #8] -> w3 @@ -56694,7 +63273,7 @@ Upstream-status: Pending + and v5.16b, v5.16b, v16.16b + and v6.16b, v6.16b, v16.16b + st3 { v4.8h, v5.8h, v6.8h }, [sp], #48 -+ ++ + xtn v4.4h, v2.4s + ushr v2.4s, v2.4s, #10 + xtn v5.4h, v2.4s @@ -56841,7 +63420,7 @@ Upstream-status: Pending + ldr w22, [x4], #4 + str w22, [x0], #2 + lsr w22, w22, #16 -+ str w22, [x2], #2 ++ str w22, [x2], #2 + + add w20, w20, #1 + b rem_pix_c16_loop @@ -56868,9 +63447,336 @@ Upstream-status: Pending +// unsigned int _w, +// unsigned int h); + ++// void ff_rpi_sand30_lines_to_planar_y8( ++// uint8_t * dest, : x0 ++// unsigned int dst_stride, : w1 ++// const uint8_t * src, : x2 ++// unsigned int src_stride1, : w3, always 128 ++// unsigned int src_stride2, : w4 ++// unsigned int _x, : w5 ++// unsigned int y, : w6 ++// unsigned int _w, : w7 ++// unsigned int h); : [sp, #0] ++// ++// Assumes that we are starting on a stripe boundary and that overreading ++// within the stripe is OK. However it does respect the dest size for wri ++ ++function ff_rpi_sand30_lines_to_planar_y16, export=1 ++ lsl w4, w4, #7 ++ sub w4, w4, #64 ++ sub w1, w1, w7, lsl #1 ++ uxtw x6, w6 ++ add x8, x2, x6, lsl #7 ++ ldr w6, [sp, #0] ++ ++10: ++ mov x2, x8 ++ mov w5, w7 ++1: ++ ld1 {v0.4s, v1.4s, v2.4s, v3.4s}, [x2], #64 ++ ld1 {v4.4s, v5.4s, v6.4s, v7.4s}, [x2], x4 ++ ++ subs w5, w5, #96 ++ ++ // v0, v1 ++ ++ shrn v18.4h, v0.4s, #14 ++ xtn v16.4h, v0.4s ++ shrn v17.4h, v0.4s, #10 ++ ++ shrn2 v18.8h, v1.4s, #14 ++ xtn2 v16.8h, v1.4s ++ shrn2 v17.8h, v1.4s, #10 ++ ++ ushr v18.8h, v18.8h, #6 ++ bic v16.8h, #0xfc, lsl #8 ++ bic v17.8h, #0xfc, lsl #8 ++ ++ // v2, v3 ++ ++ shrn v21.4h, v2.4s, #14 ++ xtn v19.4h, v2.4s ++ shrn v20.4h, v2.4s, #10 ++ ++ shrn2 v21.8h, v3.4s, #14 ++ xtn2 v19.8h, v3.4s ++ shrn2 v20.8h, v3.4s, #10 ++ ++ ushr v21.8h, v21.8h, #6 ++ bic v19.8h, #0xfc, lsl #8 ++ bic v20.8h, #0xfc, lsl #8 ++ ++ // v4, v5 ++ ++ shrn v24.4h, v4.4s, #14 ++ xtn v22.4h, v4.4s ++ shrn v23.4h, v4.4s, #10 ++ ++ shrn2 v24.8h, v5.4s, #14 ++ xtn2 v22.8h, v5.4s ++ shrn2 v23.8h, v5.4s, #10 ++ ++ ushr v24.8h, v24.8h, #6 ++ bic v22.8h, #0xfc, lsl #8 ++ bic v23.8h, #0xfc, lsl #8 ++ ++ // v6, v7 ++ ++ shrn v27.4h, v6.4s, #14 ++ xtn v25.4h, v6.4s ++ shrn v26.4h, v6.4s, #10 ++ ++ shrn2 v27.8h, v7.4s, #14 ++ xtn2 v25.8h, v7.4s ++ shrn2 v26.8h, v7.4s, #10 ++ ++ ushr v27.8h, v27.8h, #6 ++ bic v25.8h, #0xfc, lsl #8 ++ bic v26.8h, #0xfc, lsl #8 ++ ++ blt 2f ++ ++ st3 {v16.8h, v17.8h, v18.8h}, [x0], #48 ++ st3 {v19.8h, v20.8h, v21.8h}, [x0], #48 ++ st3 {v22.8h, v23.8h, v24.8h}, [x0], #48 ++ st3 {v25.8h, v26.8h, v27.8h}, [x0], #48 ++ ++ bne 1b ++ ++11: ++ subs w6, w6, #1 ++ add x0, x0, w1, uxtw ++ add x8, x8, #128 ++ bne 10b ++ ++ ret ++ ++// Partial final write ++2: ++ cmp w5, #48-96 ++ blt 1f ++ st3 {v16.8h, v17.8h, v18.8h}, [x0], #48 ++ st3 {v19.8h, v20.8h, v21.8h}, [x0], #48 ++ beq 11b ++ mov v16.16b, v22.16b ++ mov v17.16b, v23.16b ++ sub w5, w5, #48 ++ mov v18.16b, v24.16b ++ mov v19.16b, v25.16b ++ mov v20.16b, v26.16b ++ mov v21.16b, v27.16b ++1: ++ cmp w5, #24-96 ++ blt 1f ++ st3 {v16.8h, v17.8h, v18.8h}, [x0], #48 ++ beq 11b ++ mov v16.16b, v19.16b ++ mov v17.16b, v20.16b ++ sub w5, w5, #24 ++ mov v18.16b, v21.16b ++1: ++ cmp w5, #12-96 ++ blt 1f ++ st3 {v16.4h, v17.4h, v18.4h}, [x0], #24 ++ beq 11b ++ mov v16.2d[0], v16.2d[1] ++ sub w5, w5, #12 ++ mov v17.2d[0], v17.2d[1] ++ mov v18.2d[0], v18.2d[1] ++1: ++ cmp w5, #6-96 ++ blt 1f ++ st3 {v16.h, v17.h, v18.h}[0], [x0], #6 ++ st3 {v16.h, v17.h, v18.h}[1], [x0], #6 ++ beq 11b ++ mov v16.2s[0], v16.2s[1] ++ sub w5, w5, #6 ++ mov v17.2s[0], v17.2s[1] ++ mov v18.2s[0], v18.2s[1] ++1: ++ cmp w5, #3-96 ++ blt 1f ++ st3 {v16.h, v17.h, v18.h}[0], [x0], #6 ++ beq 11b ++ mov v16.4h[0], v16.4h[1] ++ sub w5, w5, #3 ++ mov v17.4h[0], v17.4h[1] ++1: ++ cmp w5, #2-96 ++ blt 1f ++ st2 {v16.h, v17.h}[0], [x0], #4 ++ b 11b ++1: ++ st1 {v16.h}[0], [x0], #2 ++ b 11b ++ ++endfunc ++ ++// void ff_rpi_sand30_lines_to_planar_y8( ++// uint8_t * dest, : x0 ++// unsigned int dst_stride, : w1 ++// const uint8_t * src, : x2 ++// unsigned int src_stride1, : w3, always 128 ++// unsigned int src_stride2, : w4 ++// unsigned int _x, : w5 ++// unsigned int y, : w6 ++// unsigned int _w, : w7 ++// unsigned int h); : [sp, #0] ++// ++// Assumes that we are starting on a stripe boundary and that overreading ++// within the stripe is OK. However it does respect the dest size for wri ++ ++function ff_rpi_sand30_lines_to_planar_y8, export=1 ++ lsl w4, w4, #7 ++ sub w4, w4, #64 ++ sub w1, w1, w7 ++ uxtw x6, w6 ++ add x8, x2, x6, lsl #7 ++ ldr w6, [sp, #0] ++ ++10: ++ mov x2, x8 ++ mov w5, w7 ++1: ++ ld1 {v0.4s, v1.4s, v2.4s, v3.4s}, [x2], #64 ++ ld1 {v4.4s, v5.4s, v6.4s, v7.4s}, [x2], x4 ++ ++ subs w5, w5, #96 ++ ++ // v0, v1 ++ ++ shrn v18.4h, v0.4s, #16 ++ xtn v16.4h, v0.4s ++ shrn v17.4h, v0.4s, #12 ++ ++ shrn2 v18.8h, v1.4s, #16 ++ xtn2 v16.8h, v1.4s ++ shrn2 v17.8h, v1.4s, #12 ++ ++ shrn v18.8b, v18.8h, #6 ++ shrn v16.8b, v16.8h, #2 ++ xtn v17.8b, v17.8h ++ ++ // v2, v3 ++ ++ shrn v21.4h, v2.4s, #16 ++ xtn v19.4h, v2.4s ++ shrn v20.4h, v2.4s, #12 ++ ++ shrn2 v21.8h, v3.4s, #16 ++ xtn2 v19.8h, v3.4s ++ shrn2 v20.8h, v3.4s, #12 ++ ++ shrn2 v18.16b, v21.8h, #6 ++ shrn2 v16.16b, v19.8h, #2 ++ xtn2 v17.16b, v20.8h ++ ++ // v4, v5 ++ ++ shrn v24.4h, v4.4s, #16 ++ xtn v22.4h, v4.4s ++ shrn v23.4h, v4.4s, #12 ++ ++ shrn2 v24.8h, v5.4s, #16 ++ xtn2 v22.8h, v5.4s ++ shrn2 v23.8h, v5.4s, #12 ++ ++ shrn v21.8b, v24.8h, #6 ++ shrn v19.8b, v22.8h, #2 ++ xtn v20.8b, v23.8h ++ ++ // v6, v7 ++ ++ shrn v27.4h, v6.4s, #16 ++ xtn v25.4h, v6.4s ++ shrn v26.4h, v6.4s, #12 ++ ++ shrn2 v27.8h, v7.4s, #16 ++ xtn2 v25.8h, v7.4s ++ shrn2 v26.8h, v7.4s, #12 ++ ++ shrn2 v21.16b, v27.8h, #6 ++ shrn2 v19.16b, v25.8h, #2 ++ xtn2 v20.16b, v26.8h ++ ++ blt 2f ++ ++ st3 {v16.16b, v17.16b, v18.16b}, [x0], #48 ++ st3 {v19.16b, v20.16b, v21.16b}, [x0], #48 ++ ++ bne 1b ++ ++11: ++ subs w6, w6, #1 ++ add x0, x0, w1, uxtw ++ add x8, x8, #128 ++ bne 10b ++ ++ ret ++ ++// Partial final write ++2: ++ cmp w5, #48-96 ++ blt 1f ++ st3 {v16.16b, v17.16b, v18.16b}, [x0], #48 ++ beq 11b ++ mov v16.16b, v22.16b ++ mov v17.16b, v23.16b ++ sub w5, w5, #48 ++ mov v18.16b, v24.16b ++1: ++ cmp w5, #24-96 ++ blt 1f ++ st3 {v16.8b, v17.8b, v18.8b}, [x0], #24 ++ beq 11b ++ mov v16.2d[0], v16.2d[1] ++ sub w5, w5, #24 ++ mov v17.2d[0], v17.2d[1] ++ mov v18.2d[0], v18.2d[1] ++1: ++ cmp w5, #12-96 ++ blt 1f ++ st3 {v16.b, v17.b, v18.b}[0], [x0], #3 ++ st3 {v16.b, v17.b, v18.b}[1], [x0], #3 ++ st3 {v16.b, v17.b, v18.b}[2], [x0], #3 ++ st3 {v16.b, v17.b, v18.b}[3], [x0], #3 ++ beq 11b ++ mov v16.2s[0], v16.2s[1] ++ sub w5, w5, #12 ++ mov v17.2s[0], v17.2s[1] ++ mov v18.2s[0], v18.2s[1] ++1: ++ cmp w5, #6-96 ++ blt 1f ++ st3 {v16.b, v17.b, v18.b}[0], [x0], #3 ++ st3 {v16.b, v17.b, v18.b}[1], [x0], #3 ++ beq 11b ++ mov v16.4h[0], v16.4h[1] ++ sub w5, w5, #6 ++ mov v17.4h[0], v17.4h[1] ++ mov v18.4h[0], v18.4h[1] ++1: ++ cmp w5, #3-96 ++ blt 1f ++ st3 {v16.b, v17.b, v18.b}[0], [x0], #3 ++ beq 11b ++ mov v16.8b[0], v16.8b[1] ++ sub w5, w5, #3 ++ mov v17.8b[0], v17.8b[1] ++1: ++ cmp w5, #2-96 ++ blt 1f ++ st2 {v16.b, v17.b}[0], [x0], #2 ++ b 11b ++1: ++ st1 {v16.b}[0], [x0], #1 ++ b 11b ++ ++endfunc ++ --- /dev/null +++ b/libavutil/aarch64/rpi_sand_neon.h -@@ -0,0 +1,55 @@ +@@ -0,0 +1,59 @@ +/* +Copyright (c) 2021 Michael Eiler + @@ -56922,6 +63828,10 @@ Upstream-status: Pending + uint8_t * dst_v, unsigned int dst_stride_v, const uint8_t * src, unsigned int stride1, + unsigned int stride2, unsigned int _x, unsigned int y, unsigned int _w, unsigned int h); + ++void ff_rpi_sand30_lines_to_planar_y8(uint8_t * dest, unsigned int dst_stride, ++ const uint8_t * src, unsigned int src_stride1, unsigned int src_stride2, ++ unsigned int _x, unsigned int y, unsigned int _w, unsigned int h); ++ +#ifdef __cplusplus +} +#endif @@ -56929,13 +63839,13 @@ Upstream-status: Pending --- a/libavutil/arm/Makefile +++ b/libavutil/arm/Makefile @@ -6,3 +6,4 @@ VFP-OBJS += arm/float_dsp_init_vfp.o - + NEON-OBJS += arm/float_dsp_init_neon.o \ arm/float_dsp_neon.o \ + arm/rpi_sand_neon.o \ --- /dev/null +++ b/libavutil/arm/rpi_sand_neon.S -@@ -0,0 +1,768 @@ +@@ -0,0 +1,925 @@ +/* +Copyright (c) 2018 Raspberry Pi (Trading) Ltd. +All rights reserved. @@ -57298,7 +64208,6 @@ Upstream-status: Pending + ldr r6, [sp, #36] + ldr r7, [sp, #32] @ y + mov r12, #48 -+ vmov.u16 q15, #0x3ff + sub r3, #1 + lsl r3, #7 + sub r1, r1, r6, lsl #1 @@ -57314,37 +64223,33 @@ Upstream-status: Pending + vldm r2!, {q10-q13} + add lr, #64 + -+ vshr.u32 q14, q10, #20 @ Cannot vshrn.u32 #20! ++ vshrn.u32 d4 , q10, #14 @ Cannot vshrn.u32 #20! + ands lr, #127 + vshrn.u32 d2, q10, #10 + vmovn.u32 d0, q10 -+ vmovn.u32 d4, q14 + -+ vshr.u32 q14, q11, #20 ++ vshrn.u32 d5, q11, #14 + it eq + addeq r2, r3 + vshrn.u32 d3, q11, #10 + vmovn.u32 d1, q11 -+ vmovn.u32 d5, q14 + + subs r5, #48 -+ vand q0, q15 -+ vand q1, q15 -+ vand q2, q15 ++ vshr.u16 q2, #6 ++ vbic.u16 q0, #0xfc00 ++ vbic.u16 q1, #0xfc00 + -+ vshr.u32 q14, q12, #20 ++ vshrn.u32 d20, q12, #14 + vshrn.u32 d18, q12, #10 + vmovn.u32 d16, q12 -+ vmovn.u32 d20, q14 + -+ vshr.u32 q14, q13, #20 ++ vshrn.u32 d21, q13, #14 + vshrn.u32 d19, q13, #10 + vmovn.u32 d17, q13 -+ vmovn.u32 d21, q14 + -+ vand q8, q15 -+ vand q9, q15 -+ vand q10, q15 ++ vshr.u16 q10, #6 ++ vbic.u16 q8, #0xfc00 ++ vbic.u16 q9 , #0xfc00 + blt 2f + + vst3.16 {d0, d2, d4}, [r0], r12 @@ -57437,7 +64342,6 @@ Upstream-status: Pending + ldr r7, [sp, #48] + ldr r9, [sp, #52] + mov r12, #48 -+ vmov.u16 q15, #0x3ff + sub r8, #1 + lsl r8, #7 + add r5, r5, r7, lsl #7 @@ -57453,48 +64357,44 @@ Upstream-status: Pending + add lr, #64 + + @ N.B. unpack [0,1,2] -> (reg order) 1, 0, 2 -+ vshr.u32 q14, q0, #20 -+ vshrn.u32 d16, q0, #10 ++ vshrn.u32 d20, q0, #14 + vmovn.u32 d18, q0 ++ vshrn.u32 d0, q0, #10 + ands lr, #127 -+ vmovn.u32 d20, q14 + -+ vshr.u32 q14, q1, #20 -+ vshrn.u32 d17, q1, #10 ++ vshrn.u32 d21, q1, #14 + vmovn.u32 d19, q1 -+ vmovn.u32 d21, q14 ++ vshrn.u32 d1, q1, #10 + -+ vshr.u32 q14, q2, #20 + vshrn.u32 d22, q2, #10 -+ vmovn.u32 d24, q2 -+ vmovn.u32 d26, q14 ++ vmovn.u32 d2, q2 ++ vshrn.u32 d4, q2, #14 + -+ vshr.u32 q14, q3, #20 -+ vshrn.u32 d23, q3, #10 -+ vmovn.u32 d25, q3 + add r10, r0, #24 -+ vmovn.u32 d27, q14 ++ vshrn.u32 d23, q3, #10 ++ vmovn.u32 d3, q3 ++ vshrn.u32 d5, q3, #14 + + it eq + addeq r4, r8 -+ vuzp.16 q8, q11 -+ vuzp.16 q9, q12 -+ vuzp.16 q10, q13 ++ vuzp.16 q0, q11 ++ vuzp.16 q9, q1 ++ vuzp.16 q10, q2 + -+ @ q8 V0, V3,.. -> q0 ++ @ q0 V0, V3,.. + @ q9 U0, U3... + @ q10 U1, U4... + @ q11 U2, U5,.. -+ @ q12 V1, V4,.. -> q1 -+ @ q13 V2, V5,.. -> q2 ++ @ q1 V1, V4, ++ @ q2 V2, V5,.. + + subs r6, #24 -+ vand q11, q15 -+ vand q9, q15 -+ vand q10, q15 -+ vand q0, q8, q15 -+ vand q1, q12, q15 -+ vand q2, q13, q15 ++ vbic.u16 q11, #0xfc00 ++ vbic.u16 q9, #0xfc00 ++ vshr.u16 q10, #6 ++ vshr.u16 q2, #6 ++ vbic.u16 q0, #0xfc00 ++ vbic.u16 q1, #0xfc00 + + blt 2f + @@ -57703,10 +64603,177 @@ Upstream-status: Pending +endfunc + + ++@ void ff_rpi_sand30_lines_to_planar_y8( ++@ uint8_t * dest, // [r0] ++@ unsigned int dst_stride, // [r1] ++@ const uint8_t * src, // [r2] ++@ unsigned int src_stride1, // [r3] Ignored - assumed 128 ++@ unsigned int src_stride2, // [sp, #0] -> r3 ++@ unsigned int _x, // [sp, #4] Ignored - 0 ++@ unsigned int y, // [sp, #8] (r7 in prefix) ++@ unsigned int _w, // [sp, #12] -> r6 (cur r5) ++@ unsigned int h); // [sp, #16] -> r7 ++@ ++@ Assumes that we are starting on a stripe boundary and that overreading ++@ within the stripe is OK. However it does respect the dest size for wri ++ ++function ff_rpi_sand30_lines_to_planar_y8, export=1 ++ push {r4-r8, lr} @ +24 ++ ldr r3, [sp, #24] ++ ldr r6, [sp, #36] ++ ldr r7, [sp, #32] @ y ++ mov r12, #48 ++ lsl r3, #7 ++ sub r1, r1, r6 ++ add r8, r2, r7, lsl #7 ++ ldr r7, [sp, #40] ++ ++10: ++ mov r2, r8 ++ add r4, r0, #24 ++ mov r5, r6 ++1: ++ vldm r2, {q8-q15} ++ ++ subs r5, #96 ++ ++ vmovn.u32 d0, q8 ++ vshrn.u32 d2, q8, #12 ++ vshrn.u32 d4, q8, #16 @ Cannot vshrn.u32 #20! ++ ++ add r2, r3 ++ ++ vmovn.u32 d1, q9 ++ vshrn.u32 d3, q9, #12 ++ vshrn.u32 d5, q9, #16 ++ ++ pld [r2, #0] ++ ++ vshrn.u16 d0, q0, #2 ++ vmovn.u16 d1, q1 ++ vshrn.u16 d2, q2, #6 ++ ++ vmovn.u32 d16, q10 ++ vshrn.u32 d18, q10, #12 ++ vshrn.u32 d20, q10, #16 ++ ++ vmovn.u32 d17, q11 ++ vshrn.u32 d19, q11, #12 ++ vshrn.u32 d21, q11, #16 ++ ++ pld [r2, #64] ++ ++ vshrn.u16 d4, q8, #2 ++ vmovn.u16 d5, q9 ++ vshrn.u16 d6, q10, #6 ++ ++ vmovn.u32 d16, q12 ++ vshrn.u32 d18, q12, #12 ++ vshrn.u32 d20, q12, #16 ++ ++ vmovn.u32 d17, q13 ++ vshrn.u32 d19, q13, #12 ++ vshrn.u32 d21, q13, #16 ++ ++ vshrn.u16 d16, q8, #2 ++ vmovn.u16 d17, q9 ++ vshrn.u16 d18, q10, #6 ++ ++ vmovn.u32 d20, q14 ++ vshrn.u32 d22, q14, #12 ++ vshrn.u32 d24, q14, #16 ++ ++ vmovn.u32 d21, q15 ++ vshrn.u32 d23, q15, #12 ++ vshrn.u32 d25, q15, #16 ++ ++ vshrn.u16 d20, q10, #2 ++ vmovn.u16 d21, q11 ++ vshrn.u16 d22, q12, #6 ++ ++ blt 2f ++ ++ vst3.8 {d0, d1, d2}, [r0], r12 ++ vst3.8 {d4, d5, d6}, [r4], r12 ++ vst3.8 {d16, d17, d18}, [r0], r12 ++ vst3.8 {d20, d21, d22}, [r4], r12 ++ ++ bne 1b ++ ++11: ++ subs r7, #1 ++ add r0, r1 ++ add r8, #128 ++ bne 10b ++ ++ pop {r4-r8, pc} ++ ++@ Partial final write ++2: ++ cmp r5, #48-96 ++ blt 1f ++ vst3.8 {d0, d1, d2}, [r0], r12 ++ vst3.8 {d4, d5, d6}, [r4], r12 ++ beq 11b ++ vmov q0, q8 ++ vmov q2, q10 ++ sub r5, #48 ++ vmov d2, d18 ++ vmov d6, d22 ++1: ++ cmp r5, #24-96 ++ blt 1f ++ vst3.8 {d0, d1, d2}, [r0]! ++ beq 11b ++ vmov q0, q2 ++ sub r5, #24 ++ vmov d2, d6 ++1: ++ cmp r5, #12-96 ++ blt 1f ++ vst3.8 {d0[0], d1[0], d2[0]}, [r0]! ++ vst3.8 {d0[1], d1[1], d2[1]}, [r0]! ++ vst3.8 {d0[2], d1[2], d2[2]}, [r0]! ++ vst3.8 {d0[3], d1[3], d2[3]}, [r0]! ++ beq 11b ++ vmov s0, s1 ++ sub r5, #12 ++ vmov s2, s3 ++ vmov s4, s5 ++1: ++ cmp r5, #6-96 ++ blt 1f ++ vst3.8 {d0[0], d1[0], d2[0]}, [r0]! ++ vst3.8 {d0[1], d1[1], d2[1]}, [r0]! ++ add r0, #12 ++ beq 11b ++ vshr.u32 d0, #16 ++ sub r5, #6 ++ vshr.u32 d1, #16 ++ vshr.u32 d2, #16 ++1: ++ cmp r5, #3-96 ++ blt 1f ++ vst3.8 {d0[0], d1[0], d2[0]}, [r0]! ++ beq 11b ++ sub r5, #3 ++ vshr.u32 d0, #8 ++ vshr.u32 d1, #8 ++1: ++ cmp r5, #2-96 ++ blt 1f ++ vst2.8 {d0[0], d1[0]}, [r0]! ++ b 11b ++1: ++ vst1.8 {d0[0]}, [r0]! ++ b 11b ++ ++endfunc ++ + --- /dev/null +++ b/libavutil/arm/rpi_sand_neon.h -@@ -0,0 +1,99 @@ +@@ -0,0 +1,110 @@ +/* +Copyright (c) 2020 Raspberry Pi (Trading) Ltd. +All rights reserved. @@ -57804,6 +64871,17 @@ Upstream-status: Pending + unsigned int _w, // [sp, #12] -> r6 (cur r5) + unsigned int h); // [sp, #16] -> r7 + ++void ff_rpi_sand30_lines_to_planar_y8( ++ uint8_t * dest, // [r0] ++ unsigned int dst_stride, // [r1] ++ const uint8_t * src, // [r2] ++ unsigned int src_stride1, // [r3] Ignored - assumed 128 ++ unsigned int src_stride2, // [sp, #0] -> r3 ++ unsigned int _x, // [sp, #4] Ignored - 0 ++ unsigned int y, // [sp, #8] (r7 in prefix) ++ unsigned int _w, // [sp, #12] -> r6 (cur r5) ++ unsigned int h); // [sp, #16] -> r7 ++ +#endif // AVUTIL_ARM_SAND_NEON_H + --- a/libavutil/frame.c @@ -57811,7 +64889,7 @@ Upstream-status: Pending @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - + +#include "config.h" + #include "channel_layout.h" @@ -57824,13 +64902,13 @@ Upstream-status: Pending +#if CONFIG_SAND +#include "rpi_sand_fns.h" +#endif - + #if FF_API_FRAME_GET_SET MAKE_ACCESSORS(AVFrame, frame, int64_t, best_effort_timestamp) @@ -902,6 +907,12 @@ int av_frame_apply_cropping(AVFrame *fra (frame->crop_top + frame->crop_bottom) >= frame->height) return AVERROR(ERANGE); - + +#if CONFIG_SAND + // Sand cannot be cropped - do not try + if (av_rpi_is_sand_format(frame->format)) @@ -57845,7 +64923,7 @@ Upstream-status: Pending @@ -968,6 +968,16 @@ int av_frame_apply_cropping(AVFrame *fra */ const char *av_frame_side_data_name(enum AVFrameSideDataType type); - + + +static inline int av_frame_cropped_width(const AVFrame * const frame) +{ @@ -57866,11 +64944,11 @@ Upstream-status: Pending #include <sys/mman.h> #include <unistd.h> +#include <sys/ioctl.h> - + #include <drm.h> +#include <libdrm/drm_fourcc.h> #include <xf86drm.h> - + #include "avassert.h" @@ -28,6 +30,11 @@ #include "hwcontext_drm.h" @@ -57881,13 +64959,13 @@ Upstream-status: Pending +#include <linux/mman.h> +#include <linux/dma-buf.h> +#include <linux/dma-heap.h> - - + + static void drm_device_free(AVHWDeviceContext *hwdev) @@ -43,6 +50,11 @@ static int drm_device_create(AVHWDeviceC AVDRMDeviceContext *hwctx = hwdev->hwctx; drmVersionPtr version; - + + if (device == NULL) { + hwctx->fd = -1; + return 0; @@ -57905,7 +64983,7 @@ Upstream-status: Pending size_t length[AV_DRM_MAX_PLANES]; + int fds[AV_DRM_MAX_PLANES]; } DRMMapping; - + +static int dmasync(const int fd, const unsigned int flags) +{ + struct dma_buf_sync sync = { @@ -57926,19 +65004,19 @@ Upstream-status: Pending { DRMMapping *map = hwmap->priv; int i; - + - for (i = 0; i < map->nb_regions; i++) + for (i = 0; i < map->nb_regions; i++) { munmap(map->address[i], map->length[i]); + dmasync(map->fds[i], DMA_BUF_SYNC_END | map->dmaflags); + } - + av_free(map); } @@ -114,15 +145,28 @@ static int drm_map_frame(AVHWFramesConte if (!map) return AVERROR(ENOMEM); - + + for (i = 0; i < AV_DRM_MAX_PLANES; i++) + map->fds[i] = -1; + @@ -57956,7 +65034,7 @@ Upstream-status: Pending + + if (dst->format == AV_PIX_FMT_NONE) + dst->format = hwfc->sw_format; - + av_assert0(desc->nb_objects <= AV_DRM_MAX_PLANES); for (i = 0; i < desc->nb_objects; i++) { - addr = mmap(NULL, desc->objects[i].size, mmap_prot, MAP_SHARED, @@ -57968,7 +65046,7 @@ Upstream-status: Pending if (addr == MAP_FAILED) { err = AVERROR(errno); @@ -151,6 +195,23 @@ static int drm_map_frame(AVHWFramesConte - + dst->width = src->width; dst->height = src->height; + dst->crop_top = src->crop_top; @@ -57988,12 +65066,12 @@ Upstream-status: Pending + // *** Are we sure src->height is actually what we want ??? + } +#endif - + err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, &drm_unmap_frame, map); @@ -160,7 +221,9 @@ static int drm_map_frame(AVHWFramesConte return 0; - + fail: - for (i = 0; i < desc->nb_objects; i++) { + for (i = 0; i < AV_DRM_MAX_PLANES; i++) { @@ -58002,13 +65080,23 @@ Upstream-status: Pending if (map->address[i]) munmap(map->address[i], map->length[i]); } -@@ -178,7 +241,15 @@ static int drm_transfer_get_formats(AVHW - if (!pix_fmts) +@@ -172,16 +235,29 @@ static int drm_transfer_get_formats(AVHW + enum AVHWFrameTransferDirection dir, + enum AVPixelFormat **formats) + { +- enum AVPixelFormat *pix_fmts; ++ enum AVPixelFormat *p; + +- pix_fmts = av_malloc_array(2, sizeof(*pix_fmts)); +- if (!pix_fmts) ++ p = *formats = av_malloc_array(3, sizeof(*p)); ++ if (!p) return AVERROR(ENOMEM); - + - pix_fmts[0] = ctx->sw_format; +- pix_fmts[1] = AV_PIX_FMT_NONE; + // **** Offer native sand too ???? -+ pix_fmts[0] = ++ *p++ = +#if CONFIG_SAND + ctx->sw_format == AV_PIX_FMT_RPI4_8 || ctx->sw_format == AV_PIX_FMT_SAND128 ? + AV_PIX_FMT_YUV420P : @@ -58016,21 +65104,30 @@ Upstream-status: Pending + AV_PIX_FMT_YUV420P10LE : +#endif + ctx->sw_format; - pix_fmts[1] = AV_PIX_FMT_NONE; - - *formats = pix_fmts; -@@ -197,18 +268,80 @@ static int drm_transfer_data_from(AVHWFr ++ ++#if CONFIG_SAND ++ if (ctx->sw_format == AV_PIX_FMT_RPI4_10 || ++ ctx->sw_format == AV_PIX_FMT_RPI4_8 || ctx->sw_format == AV_PIX_FMT_SAND128) ++ *p++ = AV_PIX_FMT_NV12; ++#endif + +- *formats = pix_fmts; ++ *p = AV_PIX_FMT_NONE; + return 0; + } + +@@ -197,18 +273,63 @@ static int drm_transfer_data_from(AVHWFr map = av_frame_alloc(); if (!map) return AVERROR(ENOMEM); - map->format = dst->format; - + + // Map to default + map->format = AV_PIX_FMT_NONE; err = drm_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ); if (err) goto fail; - + - map->width = dst->width; - map->height = dst->height; +#if 0 @@ -58054,29 +65151,12 @@ Upstream-status: Pending + const unsigned int w = FFMIN(dst->width, map->width); + const unsigned int h = FFMIN(dst->height, map->height); + -+ if (map->format == AV_PIX_FMT_RPI4_8 && dst->format == AV_PIX_FMT_YUV420P) { -+ av_rpi_sand_to_planar_y8(dst->data[0], dst->linesize[0], -+ map->data[0], -+ 128, stride2, -+ 0, 0, w, h); -+ av_rpi_sand_to_planar_c8(dst->data[1], dst->linesize[1], -+ dst->data[2], dst->linesize[2], -+ map->data[1], -+ 128, stride2, -+ 0, 0, w / 2, h / 2); -+ } -+ else if (map->format == AV_PIX_FMT_RPI4_10 && dst->format == AV_PIX_FMT_YUV420P10LE) { -+ av_rpi_sand30_to_planar_y16(dst->data[0], dst->linesize[0], -+ map->data[0], -+ 128, stride2, -+ 0, 0, w, h); -+ av_rpi_sand30_to_planar_c16(dst->data[1], dst->linesize[1], -+ dst->data[2], dst->linesize[2], -+ map->data[1], -+ 128, stride2, -+ 0, 0, w / 2, h / 2); -+ } -+ else ++ map->crop_top = 0; ++ map->crop_bottom = 0; ++ map->crop_left = 0; ++ map->crop_right = 0; ++ ++ if (av_rpi_sand_to_planar_frame(dst, map) != 0) + { + av_log(hwfc, AV_LOG_ERROR, "%s: Incompatible output pixfmt for sand\n", __func__); + err = AVERROR(EINVAL); @@ -58094,30 +65174,30 @@ Upstream-status: Pending + map->height = dst->height; + err = av_frame_copy(dst, map); + } - + - err = av_frame_copy(dst, map); if (err) + { + av_log(hwfc, AV_LOG_ERROR, "%s: Copy fail\n", __func__); goto fail; + } - + err = 0; fail: -@@ -223,7 +356,10 @@ static int drm_transfer_data_to(AVHWFram +@@ -223,7 +344,10 @@ static int drm_transfer_data_to(AVHWFram int err; - + if (src->width > hwfc->width || src->height > hwfc->height) + { + av_log(hwfc, AV_LOG_ERROR, "%s: H/w mismatch: %d/%d, %d/%d\n", __func__, dst->width, hwfc->width, dst->height, hwfc->height); return AVERROR(EINVAL); + } - + map = av_frame_alloc(); if (!map) --- a/libavutil/pixdesc.c +++ b/libavutil/pixdesc.c -@@ -2371,6 +2371,38 @@ static const AVPixFmtDescriptor av_pix_f +@@ -2371,6 +2371,50 @@ static const AVPixFmtDescriptor av_pix_f .name = "vulkan", .flags = AV_PIX_FMT_FLAG_HWACCEL, }, @@ -58140,17 +65220,29 @@ Upstream-status: Pending + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 10, 0, 9, 1 }, /* Y */ -+ { 1, 4, 0, 0, 10, 1, 9, 1 }, /* U */ -+ { 1, 4, 1, 0, 10, 1, 9, 2 }, /* V */ ++ { 1, 4, 0, 0, 10, 3, 9, 1 }, /* U */ ++ { 1, 4, 2, 0, 10, 3, 9, 3 }, /* V */ ++ }, ++ .flags = 0, ++ }, ++ [AV_PIX_FMT_SAND64_16] = { ++ .name = "sand64_16", ++ .nb_components = 3, ++ .log2_chroma_w = 1, ++ .log2_chroma_h = 1, ++ .comp = { ++ { 0, 2, 0, 0, 16, 0, 15, 1 }, /* Y */ ++ { 1, 4, 0, 0, 16, 3, 15, 1 }, /* U */ ++ { 1, 4, 2, 0, 16, 3, 15, 3 }, /* V */ + }, + .flags = 0, + }, + [AV_PIX_FMT_RPI4_8] = { -+ .name = "rpi", ++ .name = "rpi4_8", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_RPI4_10] = { -+ .name = "rpi", ++ .name = "rpi4_10", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, }; @@ -58159,7 +65251,7 @@ Upstream-status: Pending --- a/libavutil/pixfmt.h +++ b/libavutil/pixfmt.h @@ -357,6 +357,12 @@ enum AVPixelFormat { - + AV_PIX_FMT_Y210BE, ///< packed YUV 4:2:2 like YUYV422, 20bpp, data in the high bits, big-endian AV_PIX_FMT_Y210LE, ///< packed YUV 4:2:2 like YUYV422, 20bpp, data in the high bits, little-endian +// RPI - not on ifdef so can be got at by calling progs @@ -58168,7 +65260,7 @@ Upstream-status: Pending + AV_PIX_FMT_SAND64_16, ///< 4:2:0 16-bit 64x*Y stripe, 32x*UV stripe, then next x stripe, mysterious padding + AV_PIX_FMT_RPI4_8, + AV_PIX_FMT_RPI4_10, - + AV_PIX_FMT_NB ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions }; --- /dev/null @@ -58403,7 +65495,7 @@ Upstream-status: Pending + --- /dev/null +++ b/libavutil/rpi_sand_fns.c -@@ -0,0 +1,356 @@ +@@ -0,0 +1,445 @@ +/* +Copyright (c) 2018 Raspberry Pi (Trading) Ltd. +All rights reserved. @@ -58635,6 +65727,75 @@ Upstream-status: Pending + } +} + ++// Fetches a single patch - offscreen fixup not done here ++// w <= stride1 ++// single lose bottom 2 bits truncation ++// _x & _w in pixels, strides in bytes ++void av_rpi_sand30_to_planar_y8(uint8_t * dst, const unsigned int dst_stride, ++ const uint8_t * src, ++ unsigned int stride1, unsigned int stride2, ++ unsigned int _x, unsigned int y, ++ unsigned int _w, unsigned int h) ++{ ++ const unsigned int x0 = (_x / 3) * 4; // Byte offset of the word ++ const unsigned int xskip0 = _x - (x0 >> 2) * 3; ++ const unsigned int x1 = ((_x + _w) / 3) * 4; ++ const unsigned int xrem1 = _x + _w - (x1 >> 2) * 3; ++ const unsigned int mask = stride1 - 1; ++ const uint8_t * p0 = src + (x0 & mask) + y * stride1 + (x0 & ~mask) * stride2; ++ const unsigned int slice_inc = ((stride2 - 1) * stride1) >> 2; // RHS of a stripe to LHS of next in words ++ ++#if HAVE_SAND_ASM ++ if (_x == 0) { ++ ff_rpi_sand30_lines_to_planar_y8(dst, dst_stride, src, stride1, stride2, _x, y, _w, h); ++ return; ++ } ++#endif ++ ++ if (x0 == x1) { ++ // ******************* ++ // Partial single word xfer ++ return; ++ } ++ ++ for (unsigned int i = 0; i != h; ++i, dst += dst_stride, p0 += stride1) ++ { ++ unsigned int x = x0; ++ const uint32_t * p = (const uint32_t *)p0; ++ uint8_t * d = dst; ++ ++ if (xskip0 != 0) { ++ const uint32_t p3 = *p++; ++ ++ if (xskip0 == 1) ++ *d++ = (p3 >> 12) & 0xff; ++ *d++ = (p3 >> 22) & 0xff; ++ ++ if (((x += 4) & mask) == 0) ++ p += slice_inc; ++ } ++ ++ while (x != x1) { ++ const uint32_t p3 = *p++; ++ *d++ = (p3 >> 2) & 0xff; ++ *d++ = (p3 >> 12) & 0xff; ++ *d++ = (p3 >> 22) & 0xff; ++ ++ if (((x += 4) & mask) == 0) ++ p += slice_inc; ++ } ++ ++ if (xrem1 != 0) { ++ const uint32_t p3 = *p; ++ ++ *d++ = (p3 >> 2) & 0xff; ++ if (xrem1 == 2) ++ *d++ = (p3 >> 12) & 0xff; ++ } ++ } ++} ++ ++ + +// w/h in pixels +void av_rpi_sand16_to_sand8(uint8_t * dst, const unsigned int dst_stride1, const unsigned int dst_stride2, @@ -58716,6 +65877,16 @@ Upstream-status: Pending + av_rpi_sand_frame_stride1(src), av_rpi_sand_frame_stride2(src), + x/2, y/2, w/2, h/2); + break; ++ case AV_PIX_FMT_NV12: ++ av_rpi_sand_to_planar_y8(dst->data[0], dst->linesize[0], ++ src->data[0], ++ av_rpi_sand_frame_stride1(src), av_rpi_sand_frame_stride2(src), ++ x, y, w, h); ++ av_rpi_sand_to_planar_y8(dst->data[1], dst->linesize[1], ++ src->data[1], ++ av_rpi_sand_frame_stride1(src), av_rpi_sand_frame_stride2(src), ++ x/2, y/2, w, h/2); ++ break; + default: + return -1; + } @@ -58750,6 +65921,16 @@ Upstream-status: Pending + av_rpi_sand_frame_stride1(src), av_rpi_sand_frame_stride2(src), + x/2, y/2, w/2, h/2); + break; ++ case AV_PIX_FMT_NV12: ++ av_rpi_sand30_to_planar_y8(dst->data[0], dst->linesize[0], ++ src->data[0], ++ av_rpi_sand_frame_stride1(src), av_rpi_sand_frame_stride2(src), ++ x, y, w, h); ++ av_rpi_sand30_to_planar_y8(dst->data[1], dst->linesize[1], ++ src->data[1], ++ av_rpi_sand_frame_stride1(src), av_rpi_sand_frame_stride2(src), ++ x/2, y/2, w, h/2); ++ break; + default: + return -1; + } @@ -58762,7 +65943,7 @@ Upstream-status: Pending +} --- /dev/null +++ b/libavutil/rpi_sand_fns.h -@@ -0,0 +1,183 @@ +@@ -0,0 +1,188 @@ +/* +Copyright (c) 2018 Raspberry Pi (Trading) Ltd. +All rights reserved. @@ -58850,6 +66031,11 @@ Upstream-status: Pending + unsigned int _x, unsigned int y, + unsigned int _w, unsigned int h); + ++void av_rpi_sand30_to_planar_y8(uint8_t * dst, const unsigned int dst_stride, ++ const uint8_t * src, ++ unsigned int stride1, unsigned int stride2, ++ unsigned int _x, unsigned int y, ++ unsigned int _w, unsigned int h); + +// w/h in pixels +void av_rpi_sand16_to_sand8(uint8_t * dst, const unsigned int dst_stride1, const unsigned int dst_stride2, @@ -58948,34 +66134,64 @@ Upstream-status: Pending + --- /dev/null +++ b/pi-util/BUILD.txt -@@ -0,0 +1,29 @@ +@@ -0,0 +1,59 @@ +Building Pi FFmpeg +================== + -+Configuration: -+============= ++Current only building on a Pi is supported. ++This builds ffmpeg the way I've tested it ++ ++Get all dependencies - the current package dependencies are good enough ++ ++$ sudo apt-get build-dep ffmpeg + -+These instructions work for cross compiles from Ubuntu 16.04 & Ubuntu -+18.04. I would expect most other linux environments to work but I haven't -+tried them. ++Configure using the pi-util/conf_native.sh script ++------------------------------------------------- + -+pi-util/conf_pi2.sh ++This sets the normal release options and creates an ouutput dir to build into ++The directory name will depend on system and options but will be under out/ + -+contains suitable options to build the code for Pi2/3. It expects to find -+git clones of ++There are a few choices here ++ --mmal build including the legacy mmal-based decoders and zero-copy code ++ this requires appropriate libraries which currently will exist for ++ armv7 but not arm64 ++ --noshared ++ Build a static image rather than a shared library one. Static is ++ easier for testing as there is no need to worry about library ++ paths being confused and therefore running the wrong code, Shared ++ is what is needed, in most cases, when building for use by other ++ programs. ++ ++So for a static build ++--------------------- ++ ++$ pi-util/conf_native.sh --noshared ++ ++$ make -j8 -C out/<wherever the script said it was building to> ++ ++You can now run ffmpeg directly from where it was built ++ ++For a shared build ++------------------ + -+https://github.com/raspberrypi/tools -+https://github.com/raspberrypi/firmware ++$ pi-util/conf_native.sh + -+in the parent of the FFmpeg directory. I recommend using --depth 1 to avoid a -+lot of history you don't want. ++You will normally want an install target if shared. Note that the script has ++set this up to be generated in out/<builddir>/install, you don't have to worry ++about overwriting your system libs. + -+If you have a copy of qasm.py in ../local/bin then the .qasm sources will be -+rebuilt. Otherwise the prebuilt .c & .h files will be used. -+Likewise ../local/bin/vasmvidcore_std will enable VPU code rebuild ++$ make -j8 -C out/<builddir> install + -+pi-util/conf_p1.sh should configure for Pi1. Beware that as of this time -+H265 QPU acceleration is broken on Pi1 and so it is disabled. ++You can now set LD_LIBRARY_PATH appropriately and run ffmpeg from where it was ++built or install the image on the system - you have to be careful to get rid ++of all other ffmpeg libs or confusion may result. There is a little script ++that wipes all other versions - obviously use with care! ++ ++$ sudo pi-util/clean_usr_libs.sh ++ ++Then simply copying from the install to /usr works ++ ++$ sudo cp -r out/<builddir>/install/* /usr + + --- /dev/null @@ -59137,29 +66353,32 @@ Upstream-status: Pending +
--- /dev/null +++ b/pi-util/clean_usr_libs.sh -@@ -0,0 +1,23 @@ +@@ -0,0 +1,26 @@ +set -e +U=/usr/lib/arm-linux-gnueabihf +rm -f $U/libavcodec.* +rm -f $U/libavdevice.* +rm -f $U/libavfilter.* +rm -f $U/libavformat.* -+rm -f $U/libavresample.* +rm -f $U/libavutil.* ++rm -f $U/libswresample.* ++rm -f $U/libswscale.* +U=/usr/lib/arm-linux-gnueabihf/neon/vfp +rm -f $U/libavcodec.* +rm -f $U/libavdevice.* +rm -f $U/libavfilter.* +rm -f $U/libavformat.* -+rm -f $U/libavresample.* +rm -f $U/libavutil.* ++rm -f $U/libswresample.* ++rm -f $U/libswscale.* +U=/usr/lib/aarch64-linux-gnu +rm -f $U/libavcodec.* +rm -f $U/libavdevice.* +rm -f $U/libavfilter.* +rm -f $U/libavformat.* -+rm -f $U/libavresample.* +rm -f $U/libavutil.* ++rm -f $U/libswresample.* ++rm -f $U/libswscale.* + --- /dev/null +++ b/pi-util/conf_arm64_native.sh @@ -59706,57 +66925,90 @@ Upstream-status: Pending +1,WPP_F_ericsson_MAIN_2,WPP_F_ericsson_MAIN_2.bit,WPP_F_ericsson_MAIN_2_yuv.md5
--- /dev/null +++ b/pi-util/conf_native.sh -@@ -0,0 +1,78 @@ +@@ -0,0 +1,106 @@ +echo "Configure for native build" + +FFSRC=`pwd` -+MC=`uname -m` ++MC=`dpkg --print-architecture` ++BUILDBASE=$FFSRC/out + +#RPI_KEEPS="-save-temps=obj" +RPI_KEEPS="" + -+if [ "$MC" == "aarch64" ]; then ++NOSHARED= ++MMAL= ++ ++while [ "$1" != "" ] ; do ++ case $1 in ++ --noshared) ++ NOSHARED=1 ++ ;; ++ --mmal) ++ MMAL=1 ++ ;; ++ *) ++ echo "Usage $0: [--noshared] [--mmal]" ++ exit 1 ++ ;; ++ esac ++ shift ++done ++ ++ ++MCOPTS= ++RPI_INCLUDES= ++RPI_LIBDIRS= ++RPI_DEFINES= ++RPI_EXTRALIBS= ++ ++if [ "$MC" == "arm64" ]; then + echo "M/C aarch64" + A=aarch64-linux-gnu + B=arm64 -+ MCOPTS= -+ RPI_INCLUDES= -+ RPI_LIBDIRS= -+ RPI_DEFINES= -+ RPI_EXTRALIBS= -+ RPIOPTS="--disable-mmal --enable-sand" -+else ++elif [ "$MC" == "armhf" ]; then + echo "M/C armv7" + A=arm-linux-gnueabihf + B=armv7 + MCOPTS="--arch=armv6t2 --cpu=cortex-a7" ++ RPI_DEFINES=-mfpu=neon-vfpv4 ++else ++ echo Unexpected architecture $MC ++ exit 1 ++fi ++ ++if [ $MMAL ]; then + RPI_OPT_VC=/opt/vc + RPI_INCLUDES="-I$RPI_OPT_VC/include -I$RPI_OPT_VC/include/interface/vcos/pthreads -I$RPI_OPT_VC/include/interface/vmcs_host/linux" + RPI_LIBDIRS="-L$RPI_OPT_VC/lib" -+ RPI_DEFINES="-D__VCCOREVER__=0x4000000 -mfpu=neon-vfpv4" ++ RPI_DEFINES="$RPI_DEFINES -D__VCCOREVER__=0x4000000" + RPI_EXTRALIBS="-Wl,--start-group -lbcm_host -lmmal -lmmal_util -lmmal_core -lvcos -lvcsm -lvchostif -lvchiq_arm -Wl,--end-group" + RPIOPTS="--enable-mmal --enable-rpi" ++else ++ RPIOPTS="--disable-mmal --enable-sand" +fi ++ +C=`lsb_release -sc` +V=`cat RELEASE` + +SHARED_LIBS="--enable-shared" -+if [ "$1" == "--noshared" ]; then ++if [ $NOSHARED ]; then + SHARED_LIBS="--disable-shared" -+ OUT=out/$B-$C-$V-static-rel ++ OUT=$BUILDBASE/$B-$C-$V-static-rel + echo Static libs +else + echo Shared libs -+ OUT=out/$B-$C-$V-shared-rel ++ OUT=$BUILDBASE/$B-$C-$V-shared-rel +fi + -+USR_PREFIX=$FFSRC/$OUT/install ++USR_PREFIX=$OUT/install +LIB_PREFIX=$USR_PREFIX/lib/$A +INC_PREFIX=$USR_PREFIX/include/$A + +echo Destination directory: $OUT -+mkdir -p $FFSRC/$OUT -+cd $FFSRC/$OUT ++mkdir -p $OUT ++# Nothing under here need worry git - including this .gitignore! ++echo "**" > $BUILDBASE/.gitignore ++cd $OUT + +$FFSRC/configure \ + --prefix=$USR_PREFIX\ @@ -59767,10 +67019,8 @@ Upstream-status: Pending + --disable-thumb\ + --enable-v4l2-request\ + --enable-libdrm\ -+ --enable-epoxy\ -+ --enable-libudev\ -+ --enable-vout-drm\ + --enable-vout-egl\ ++ --enable-vout-drm\ + $SHARED_LIBS\ + $RPIOPTS\ + --extra-cflags="-ggdb $RPI_KEEPS $RPI_DEFINES $RPI_INCLUDES"\ @@ -59779,118 +67029,13 @@ Upstream-status: Pending + --extra-libs="$RPI_EXTRALIBS"\ + --extra-version="rpi" + -+# --enable-decoder=hevc_rpi\ -+# --enable-extra-warnings\ -+# --arch=armv71\ -+ -+# gcc option for getting asm listing -+# -Wa,-ahls ---- /dev/null -+++ b/pi-util/conf_pi1.sh -@@ -0,0 +1,39 @@ -+echo "Configure for Pi1" -+ -+RPI_TOOLROOT=`pwd`/../tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf -+RPI_OPT_VC=`pwd`/../firmware/hardfp/opt/vc -+ -+RPI_INCLUDES="-I$RPI_OPT_VC/include -I$RPI_OPT_VC/include/interface/vcos/pthreads -I$RPI_OPT_VC/include/interface/vmcs_host/linux" -+RPI_LIBDIRS="-L$RPI_TOOLROOT/lib -L$RPI_OPT_VC/lib" -+#RPI_KEEPS="-save-temps=obj" -+RPI_KEEPS="" -+ -+SHARED_LIBS="--enable-shared" -+if [ "$1" == "--noshared" ]; then -+ SHARED_LIBS="--disable-shared" -+ echo Static libs -+else -+ echo Shared libs -+fi -+ -+./configure --enable-cross-compile\ -+ --cpu=arm1176jzf-s\ -+ --arch=arm\ -+ --disable-neon\ -+ --target-os=linux\ -+ --disable-stripping\ -+ --enable-mmal\ -+ $SHARED_LIBS\ -+ --extra-cflags="-g $RPI_KEEPS $RPI_INCLUDES"\ -+ --extra-cxxflags="$RPI_INCLUDES"\ -+ --extra-ldflags="$RPI_LIBDIRS -Wl,-rpath=/opt/vc/lib,-rpath-link=$RPI_OPT_VC/lib,-rpath=/lib,-rpath=/usr/lib,-rpath-link=$RPI_TOOLROOT/lib,-rpath-link=$RPI_TOOLROOT/lib"\ -+ --extra-libs="-Wl,--start-group -lbcm_host -lmmal -lmmal_util -lmmal_core -lvcos -lvcsm -lvchostif -lvchiq_arm"\ -+ --cross-prefix=$RPI_TOOLROOT/bin/arm-linux-gnueabihf- -+ -+ -+# --enable-extra-warnings\ -+# --arch=armv71\ -+# --enable-shared\ -+ -+# gcc option for getting asm listing -+# -Wa,-ahls ---- /dev/null -+++ b/pi-util/conf_pi2.sh -@@ -0,0 +1,57 @@ -+echo "Configure for Pi2/3" -+ -+FFSRC=`pwd` -+ -+RPI_TOOLROOT=$FFSRC/../tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf -+RPI_OPT_VC=$FFSRC/../firmware/hardfp/opt/vc -+ -+RPI_INCLUDES="-I$RPI_OPT_VC/include -I$RPI_OPT_VC/include/interface/vcos/pthreads -I$RPI_OPT_VC/include/interface/vmcs_host/linux" -+RPI_LIBDIRS="-L$RPI_TOOLROOT/lib -L$RPI_OPT_VC/lib" -+RPI_DEFINES="-D__VCCOREVER__=0x4000000 -mfpu=neon-vfpv4" -+#RPI_KEEPS="-save-temps=obj" -+RPI_KEEPS="" -+ -+SHARED_LIBS="--enable-shared" -+if [ "$1" == "--noshared" ]; then -+ SHARED_LIBS="--disable-shared" -+ OUT=out/x-armv7-static-rel -+ echo Static libs -+else -+ echo Shared libs -+ OUT=out/x-armv7-shared-rel -+fi -+ -+USR_PREFIX=$FFSRC/$OUT/install -+LIB_PREFIX=$USR_PREFIX/lib/arm-linux-gnueabihf -+INC_PREFIX=$USR_PREFIX/include/arm-linux-gnueabihf -+ -+mkdir -p $FFSRC/$OUT -+cd $FFSRC/$OUT -+ -+$FFSRC/configure --enable-cross-compile\ -+ --prefix=$USR_PREFIX\ -+ --libdir=$LIB_PREFIX\ -+ --incdir=$INC_PREFIX\ -+ --arch=armv6t2\ -+ --cpu=cortex-a7\ -+ --target-os=linux\ -+ --disable-stripping\ -+ --disable-thumb\ -+ --enable-mmal\ -+ --enable-rpi\ -+ $SHARED_LIBS\ -+ --extra-cflags="-ggdb $RPI_KEEPS $RPI_DEFINES $RPI_INCLUDES"\ -+ --extra-cxxflags="$RPI_DEFINES $RPI_INCLUDES"\ -+ --extra-ldflags="$RPI_LIBDIRS -Wl,-rpath=/opt/vc/lib,-rpath-link=$RPI_OPT_VC/lib,-rpath=/lib,-rpath=/usr/lib,-rpath-link=$RPI_TOOLROOT/lib,-rpath-link=$RPI_TOOLROOT/lib"\ -+ --extra-libs="-Wl,--start-group -lbcm_host -lmmal -lmmal_util -lmmal_core -lvcos -lvcsm -lvchostif -lvchiq_arm"\ -+ --cross-prefix=$RPI_TOOLROOT/bin/arm-linux-gnueabihf- -+ -+# --enable-shared\ -+ -+# --enable-decoder=hevc_rpi\ -+# --enable-extra-warnings\ -+# --arch=armv71\ -+# --enable-shared\ + +# gcc option for getting asm listing +# -Wa,-ahls --- /dev/null +++ b/pi-util/ffconf.py @@ -0,0 +1,215 @@ -+#!/usr/bin/env python ++#!/usr/bin/env python3 + +import string +import os @@ -59967,16 +67112,16 @@ Upstream-status: Pending + pass + + if m1 and m2 and m1.group() == m2.group(): -+ print >> flog, "Match: " + m1.group() ++ print("Match: " + m1.group(), file=flog) + rv = 0 + elif not m1: -+ print >> flog, "****** Cannot find m1" ++ print("****** Cannot find m1", file=flog) + rv = 3 + elif not m2: -+ print >> flog, "****** Cannot find m2" ++ print("****** Cannot find m2", file=flog) + rv = 2 + else: -+ print >> flog, "****** Mismatch: " + m1.group() + " != " + m2.group() ++ print("****** Mismatch: " + m1.group() + " != " + m2.group(), file=flog) + rv = 1 + flog.close() + return rv @@ -60022,7 +67167,7 @@ Upstream-status: Pending + exp_test = int(a[0]) + if (exp_test and runtest(a[1], tests)): + name = a[1] -+ print "==== ", name, ++ print ("==== ", name, end="") + sys.stdout.flush() + + rv = testone(os.path.join(test_root, name), name, a[2], a[3], a[4], dectype=dectype, vcodec=vcodec, ffmpeg_exec=ffmpeg_exec) @@ -60033,31 +67178,31 @@ Upstream-status: Pending + + if (rv == 0): + if exp_test == 2: -+ print ": * OK *" ++ print(": * OK *") + unx_success.append(name) + else: -+ print ": ok" ++ print(": ok") + elif exp_test == 2 and rv == 1: -+ print ": fail" ++ print(": fail") + elif exp_test == 3 and rv == 2: + # Call an expected "crash" an abort -+ print ": abort" ++ print(": abort") + else: + unx_failures.append(name) + if rv == 1: -+ print ": * FAIL *" ++ print(": * FAIL *") + elif (rv == 2) : -+ print ": * CRASH *" ++ print(": * CRASH *") + elif (rv == 3) : -+ print ": * MD5 MISSING *" ++ print(": * MD5 MISSING *") + else : -+ print ": * BANG *" ++ print(": * BANG *") + + if unx_failures or unx_success: -+ print "Unexpected Failures:", unx_failures -+ print "Unexpected Success: ", unx_success ++ print("Unexpected Failures:", unx_failures) ++ print("Unexpected Success: ", unx_success) + else: -+ print "All tests normal:", successes, "ok,", failures, "failed" ++ print("All tests normal:", successes, "ok,", failures, "failed") + + +class ConfCSVDialect(csv.Dialect): @@ -60567,3 +67712,630 @@ Upstream-status: Pending + + do_logparse(args.logfile) + +--- a/tests/checkasm/Makefile ++++ b/tests/checkasm/Makefile +@@ -9,8 +9,10 @@ AVCODECOBJS-$(CONFIG_G722DSP) + AVCODECOBJS-$(CONFIG_H264DSP) += h264dsp.o + AVCODECOBJS-$(CONFIG_H264PRED) += h264pred.o + AVCODECOBJS-$(CONFIG_H264QPEL) += h264qpel.o ++AVCODECOBJS-$(CONFIG_IDCTDSP) += idctdsp.o + AVCODECOBJS-$(CONFIG_LLVIDDSP) += llviddsp.o + AVCODECOBJS-$(CONFIG_LLVIDENCDSP) += llviddspenc.o ++AVCODECOBJS-$(CONFIG_VC1DSP) += vc1dsp.o + AVCODECOBJS-$(CONFIG_VP8DSP) += vp8dsp.o + AVCODECOBJS-$(CONFIG_VIDEODSP) += videodsp.o + +--- a/tests/checkasm/checkasm.c ++++ b/tests/checkasm/checkasm.c +@@ -121,6 +121,9 @@ static const struct { + #if CONFIG_HUFFYUV_DECODER + { "huffyuvdsp", checkasm_check_huffyuvdsp }, + #endif ++ #if CONFIG_IDCTDSP ++ { "idctdsp", checkasm_check_idctdsp }, ++ #endif + #if CONFIG_JPEG2000_DECODER + { "jpeg2000dsp", checkasm_check_jpeg2000dsp }, + #endif +@@ -145,6 +148,9 @@ static const struct { + #if CONFIG_V210_ENCODER + { "v210enc", checkasm_check_v210enc }, + #endif ++ #if CONFIG_VC1DSP ++ { "vc1dsp", checkasm_check_vc1dsp }, ++ #endif + #if CONFIG_VP8DSP + { "vp8dsp", checkasm_check_vp8dsp }, + #endif +--- a/tests/checkasm/checkasm.h ++++ b/tests/checkasm/checkasm.h +@@ -60,6 +60,7 @@ void checkasm_check_hevc_add_res(void); + void checkasm_check_hevc_idct(void); + void checkasm_check_hevc_sao(void); + void checkasm_check_huffyuvdsp(void); ++void checkasm_check_idctdsp(void); + void checkasm_check_jpeg2000dsp(void); + void checkasm_check_llviddsp(void); + void checkasm_check_llviddspenc(void); +@@ -73,6 +74,7 @@ void checkasm_check_sw_scale(void); + void checkasm_check_utvideodsp(void); + void checkasm_check_v210dec(void); + void checkasm_check_v210enc(void); ++void checkasm_check_vc1dsp(void); + void checkasm_check_vf_eq(void); + void checkasm_check_vf_gblur(void); + void checkasm_check_vf_hflip(void); +--- /dev/null ++++ b/tests/checkasm/idctdsp.c +@@ -0,0 +1,98 @@ ++/* ++ * Copyright (c) 2022 Ben Avison ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with FFmpeg; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include <string.h> ++ ++#include "checkasm.h" ++ ++#include "libavcodec/idctdsp.h" ++ ++#include "libavutil/common.h" ++#include "libavutil/internal.h" ++#include "libavutil/intreadwrite.h" ++#include "libavutil/mem_internal.h" ++ ++#define IDCTDSP_TEST(func) { #func, offsetof(IDCTDSPContext, func) }, ++ ++typedef struct { ++ const char *name; ++ size_t offset; ++} test; ++ ++#define RANDOMIZE_BUFFER16(name, size) \ ++ do { \ ++ int i; \ ++ for (i = 0; i < size; ++i) { \ ++ uint16_t r = rnd() % 0x201 - 0x100; \ ++ AV_WN16A(name##0 + i, r); \ ++ AV_WN16A(name##1 + i, r); \ ++ } \ ++ } while (0) ++ ++#define RANDOMIZE_BUFFER8(name, size) \ ++ do { \ ++ int i; \ ++ for (i = 0; i < size; ++i) { \ ++ uint8_t r = rnd(); \ ++ name##0[i] = r; \ ++ name##1[i] = r; \ ++ } \ ++ } while (0) ++ ++static void check_add_put_clamped(void) ++{ ++ /* Source buffers are only as big as needed, since any over-read won't affect results */ ++ LOCAL_ALIGNED_16(int16_t, src0, [64]); ++ LOCAL_ALIGNED_16(int16_t, src1, [64]); ++ /* Destination buffers have borders of one row above/below and 8 columns left/right to catch overflows */ ++ LOCAL_ALIGNED_8(uint8_t, dst0, [10 * 24]); ++ LOCAL_ALIGNED_8(uint8_t, dst1, [10 * 24]); ++ ++ AVCodecContext avctx = { 0 }; ++ IDCTDSPContext h; ++ ++ const test tests[] = { ++ IDCTDSP_TEST(add_pixels_clamped) ++ IDCTDSP_TEST(put_pixels_clamped) ++ IDCTDSP_TEST(put_signed_pixels_clamped) ++ }; ++ ++ ff_idctdsp_init(&h, &avctx); ++ ++ for (size_t t = 0; t < FF_ARRAY_ELEMS(tests); ++t) { ++ void (*func)(const int16_t *, uint8_t * ptrdiff_t) = *(void **)((intptr_t) &h + tests[t].offset); ++ if (check_func(func, "idctdsp.%s", tests[t].name)) { ++ declare_func_emms(AV_CPU_FLAG_MMX, void, const int16_t *, uint8_t *, ptrdiff_t); ++ RANDOMIZE_BUFFER16(src, 64); ++ RANDOMIZE_BUFFER8(dst, 10 * 24); ++ call_ref(src0, dst0 + 24 + 8, 24); ++ call_new(src1, dst1 + 24 + 8, 24); ++ if (memcmp(dst0, dst1, 10 * 24)) ++ fail(); ++ bench_new(src1, dst1 + 24 + 8, 24); ++ } ++ } ++} ++ ++void checkasm_check_idctdsp(void) ++{ ++ check_add_put_clamped(); ++ report("idctdsp"); ++} +--- /dev/null ++++ b/tests/checkasm/vc1dsp.c +@@ -0,0 +1,452 @@ ++/* ++ * Copyright (c) 2022 Ben Avison ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with FFmpeg; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include <string.h> ++ ++#include "checkasm.h" ++ ++#include "libavcodec/vc1dsp.h" ++ ++#include "libavutil/common.h" ++#include "libavutil/internal.h" ++#include "libavutil/intreadwrite.h" ++#include "libavutil/mem_internal.h" ++ ++#define VC1DSP_TEST(func) { #func, offsetof(VC1DSPContext, func) }, ++#define VC1DSP_SIZED_TEST(func, width, height) { #func, offsetof(VC1DSPContext, func), width, height }, ++ ++typedef struct { ++ const char *name; ++ size_t offset; ++ int width; ++ int height; ++} test; ++ ++typedef struct matrix { ++ size_t width; ++ size_t height; ++ float d[]; ++} matrix; ++ ++static const matrix T8 = { 8, 8, { ++ 12, 12, 12, 12, 12, 12, 12, 12, ++ 16, 15, 9, 4, -4, -9, -15, -16, ++ 16, 6, -6, -16, -16, -6, 6, 16, ++ 15, -4, -16, -9, 9, 16, 4, -15, ++ 12, -12, -12, 12, 12, -12, -12, 12, ++ 9, -16, 4, 15, -15, -4, 16, -9, ++ 6, -16, 16, -6, -6, 16, -16, 6, ++ 4, -9, 15, -16, 16, -15, 9, -4 ++} }; ++ ++static const matrix T4 = { 4, 4, { ++ 17, 17, 17, 17, ++ 22, 10, -10, -22, ++ 17, -17, -17, 17, ++ 10, -22, 22, -10 ++} }; ++ ++static const matrix T8t = { 8, 8, { ++ 12, 16, 16, 15, 12, 9, 6, 4, ++ 12, 15, 6, -4, -12, -16, -16, -9, ++ 12, 9, -6, -16, -12, 4, 16, 15, ++ 12, 4, -16, -9, 12, 15, -6, -16, ++ 12, -4, -16, 9, 12, -15, -6, 16, ++ 12, -9, -6, 16, -12, -4, 16, -15, ++ 12, -15, 6, 4, -12, 16, -16, 9, ++ 12, -16, 16, -15, 12, -9, 6, -4 ++} }; ++ ++static const matrix T4t = { 4, 4, { ++ 17, 22, 17, 10, ++ 17, 10, -17, -22, ++ 17, -10, -17, 22, ++ 17, -22, 17, -10 ++} }; ++ ++static matrix *new_matrix(size_t width, size_t height) ++{ ++ matrix *out = av_mallocz(sizeof (matrix) + height * width * sizeof (float)); ++ if (out == NULL) { ++ fprintf(stderr, "Memory allocation failure\n"); ++ exit(EXIT_FAILURE); ++ } ++ out->width = width; ++ out->height = height; ++ return out; ++} ++ ++static matrix *multiply(const matrix *a, const matrix *b) ++{ ++ matrix *out; ++ if (a->width != b->height) { ++ fprintf(stderr, "Incompatible multiplication\n"); ++ exit(EXIT_FAILURE); ++ } ++ out = new_matrix(b->width, a->height); ++ for (int j = 0; j < out->height; ++j) ++ for (int i = 0; i < out->width; ++i) { ++ float sum = 0; ++ for (int k = 0; k < a->width; ++k) ++ sum += a->d[j * a->width + k] * b->d[k * b->width + i]; ++ out->d[j * out->width + i] = sum; ++ } ++ return out; ++} ++ ++static void normalise(matrix *a) ++{ ++ for (int j = 0; j < a->height; ++j) ++ for (int i = 0; i < a->width; ++i) { ++ float *p = a->d + j * a->width + i; ++ *p *= 64; ++ if (a->height == 4) ++ *p /= (const unsigned[]) { 289, 292, 289, 292 } [j]; ++ else ++ *p /= (const unsigned[]) { 288, 289, 292, 289, 288, 289, 292, 289 } [j]; ++ if (a->width == 4) ++ *p /= (const unsigned[]) { 289, 292, 289, 292 } [i]; ++ else ++ *p /= (const unsigned[]) { 288, 289, 292, 289, 288, 289, 292, 289 } [i]; ++ } ++} ++ ++static void divide_and_round_nearest(matrix *a, float by) ++{ ++ for (int j = 0; j < a->height; ++j) ++ for (int i = 0; i < a->width; ++i) { ++ float *p = a->d + j * a->width + i; ++ *p = rintf(*p / by); ++ } ++} ++ ++static void tweak(matrix *a) ++{ ++ for (int j = 4; j < a->height; ++j) ++ for (int i = 0; i < a->width; ++i) { ++ float *p = a->d + j * a->width + i; ++ *p += 1; ++ } ++} ++ ++/* The VC-1 spec places restrictions on the values permitted at three ++ * different stages: ++ * - D: the input coefficients in frequency domain ++ * - E: the intermediate coefficients, inverse-transformed only horizontally ++ * - R: the fully inverse-transformed coefficients ++ * ++ * To fully cater for the ranges specified requires various intermediate ++ * values to be held to 17-bit precision; yet these conditions do not appear ++ * to be utilised in real-world streams. At least some assembly ++ * implementations have chosen to restrict these values to 16-bit precision, ++ * to accelerate the decoding of real-world streams at the cost of strict ++ * adherence to the spec. To avoid our test marking these as failures, ++ * reduce our random inputs. ++ */ ++#define ATTENUATION 4 ++ ++static matrix *generate_inverse_quantized_transform_coefficients(size_t width, size_t height) ++{ ++ matrix *raw, *tmp, *D, *E, *R; ++ raw = new_matrix(width, height); ++ for (int i = 0; i < width * height; ++i) ++ raw->d[i] = (int) (rnd() % (1024/ATTENUATION)) - 512/ATTENUATION; ++ tmp = multiply(height == 8 ? &T8 : &T4, raw); ++ D = multiply(tmp, width == 8 ? &T8t : &T4t); ++ normalise(D); ++ divide_and_round_nearest(D, 1); ++ for (int i = 0; i < width * height; ++i) { ++ if (D->d[i] < -2048/ATTENUATION || D->d[i] > 2048/ATTENUATION-1) { ++ /* Rare, so simply try again */ ++ av_free(raw); ++ av_free(tmp); ++ av_free(D); ++ return generate_inverse_quantized_transform_coefficients(width, height); ++ } ++ } ++ E = multiply(D, width == 8 ? &T8 : &T4); ++ divide_and_round_nearest(E, 8); ++ for (int i = 0; i < width * height; ++i) ++ if (E->d[i] < -4096/ATTENUATION || E->d[i] > 4096/ATTENUATION-1) { ++ /* Rare, so simply try again */ ++ av_free(raw); ++ av_free(tmp); ++ av_free(D); ++ av_free(E); ++ return generate_inverse_quantized_transform_coefficients(width, height); ++ } ++ R = multiply(height == 8 ? &T8t : &T4t, E); ++ tweak(R); ++ divide_and_round_nearest(R, 128); ++ for (int i = 0; i < width * height; ++i) ++ if (R->d[i] < -512/ATTENUATION || R->d[i] > 512/ATTENUATION-1) { ++ /* Rare, so simply try again */ ++ av_free(raw); ++ av_free(tmp); ++ av_free(D); ++ av_free(E); ++ av_free(R); ++ return generate_inverse_quantized_transform_coefficients(width, height); ++ } ++ av_free(raw); ++ av_free(tmp); ++ av_free(E); ++ av_free(R); ++ return D; ++} ++ ++#define RANDOMIZE_BUFFER16(name, size) \ ++ do { \ ++ int i; \ ++ for (i = 0; i < size; ++i) { \ ++ uint16_t r = rnd(); \ ++ AV_WN16A(name##0 + i, r); \ ++ AV_WN16A(name##1 + i, r); \ ++ } \ ++ } while (0) ++ ++#define RANDOMIZE_BUFFER8(name, size) \ ++ do { \ ++ int i; \ ++ for (i = 0; i < size; ++i) { \ ++ uint8_t r = rnd(); \ ++ name##0[i] = r; \ ++ name##1[i] = r; \ ++ } \ ++ } while (0) ++ ++#define RANDOMIZE_BUFFER8_MID_WEIGHTED(name, size) \ ++ do { \ ++ uint8_t *p##0 = name##0, *p##1 = name##1; \ ++ int i = (size); \ ++ while (i-- > 0) { \ ++ int x = 0x80 | (rnd() & 0x7F); \ ++ x >>= rnd() % 9; \ ++ if (rnd() & 1) \ ++ x = -x; \ ++ *p##1++ = *p##0++ = 0x80 + x; \ ++ } \ ++ } while (0) ++ ++static void check_inv_trans_inplace(void) ++{ ++ /* Inverse transform input coefficients are stored in a 16-bit buffer ++ * with row stride of 8 coefficients irrespective of transform size. ++ * vc1_inv_trans_8x8 differs from the others in two ways: coefficients ++ * are stored in column-major order, and the outputs are written back ++ * to the input buffer, so we oversize it slightly to catch overruns. */ ++ LOCAL_ALIGNED_16(int16_t, inv_trans_in0, [10 * 8]); ++ LOCAL_ALIGNED_16(int16_t, inv_trans_in1, [10 * 8]); ++ ++ VC1DSPContext h; ++ ++ ff_vc1dsp_init(&h); ++ ++ if (check_func(h.vc1_inv_trans_8x8, "vc1dsp.vc1_inv_trans_8x8")) { ++ matrix *coeffs; ++ declare_func_emms(AV_CPU_FLAG_MMX, void, int16_t *); ++ RANDOMIZE_BUFFER16(inv_trans_in, 10 * 8); ++ coeffs = generate_inverse_quantized_transform_coefficients(8, 8); ++ for (int j = 0; j < 8; ++j) ++ for (int i = 0; i < 8; ++i) { ++ int idx = 8 + i * 8 + j; ++ inv_trans_in1[idx] = inv_trans_in0[idx] = coeffs->d[j * 8 + i]; ++ } ++ call_ref(inv_trans_in0 + 8); ++ call_new(inv_trans_in1 + 8); ++ if (memcmp(inv_trans_in0, inv_trans_in1, 10 * 8 * sizeof (int16_t))) ++ fail(); ++ bench_new(inv_trans_in1 + 8); ++ av_free(coeffs); ++ } ++} ++ ++static void check_inv_trans_adding(void) ++{ ++ /* Inverse transform input coefficients are stored in a 16-bit buffer ++ * with row stride of 8 coefficients irrespective of transform size. */ ++ LOCAL_ALIGNED_16(int16_t, inv_trans_in0, [8 * 8]); ++ LOCAL_ALIGNED_16(int16_t, inv_trans_in1, [8 * 8]); ++ ++ /* For all but vc1_inv_trans_8x8, the inverse transform is narrowed and ++ * added with saturation to an array of unsigned 8-bit values. Oversize ++ * this by 8 samples left and right and one row above and below. */ ++ LOCAL_ALIGNED_8(uint8_t, inv_trans_out0, [10 * 24]); ++ LOCAL_ALIGNED_8(uint8_t, inv_trans_out1, [10 * 24]); ++ ++ VC1DSPContext h; ++ ++ const test tests[] = { ++ VC1DSP_SIZED_TEST(vc1_inv_trans_8x4, 8, 4) ++ VC1DSP_SIZED_TEST(vc1_inv_trans_4x8, 4, 8) ++ VC1DSP_SIZED_TEST(vc1_inv_trans_4x4, 4, 4) ++ VC1DSP_SIZED_TEST(vc1_inv_trans_8x8_dc, 8, 8) ++ VC1DSP_SIZED_TEST(vc1_inv_trans_8x4_dc, 8, 4) ++ VC1DSP_SIZED_TEST(vc1_inv_trans_4x8_dc, 4, 8) ++ VC1DSP_SIZED_TEST(vc1_inv_trans_4x4_dc, 4, 4) ++ }; ++ ++ ff_vc1dsp_init(&h); ++ ++ for (size_t t = 0; t < FF_ARRAY_ELEMS(tests); ++t) { ++ void (*func)(uint8_t *, ptrdiff_t, int16_t *) = *(void **)((intptr_t) &h + tests[t].offset); ++ if (check_func(func, "vc1dsp.%s", tests[t].name)) { ++ matrix *coeffs; ++ declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *, ptrdiff_t, int16_t *); ++ RANDOMIZE_BUFFER16(inv_trans_in, 8 * 8); ++ RANDOMIZE_BUFFER8(inv_trans_out, 10 * 24); ++ coeffs = generate_inverse_quantized_transform_coefficients(tests[t].width, tests[t].height); ++ for (int j = 0; j < tests[t].height; ++j) ++ for (int i = 0; i < tests[t].width; ++i) { ++ int idx = j * 8 + i; ++ inv_trans_in1[idx] = inv_trans_in0[idx] = coeffs->d[j * tests[t].width + i]; ++ } ++ call_ref(inv_trans_out0 + 24 + 8, 24, inv_trans_in0); ++ call_new(inv_trans_out1 + 24 + 8, 24, inv_trans_in1); ++ if (memcmp(inv_trans_out0, inv_trans_out1, 10 * 24)) ++ fail(); ++ bench_new(inv_trans_out1 + 24 + 8, 24, inv_trans_in1 + 8); ++ av_free(coeffs); ++ } ++ } ++} ++ ++static void check_loop_filter(void) ++{ ++ /* Deblocking filter buffers are big enough to hold a 16x16 block, ++ * plus 16 columns left and 4 rows above to hold filter inputs ++ * (depending on whether v or h neighbouring block edge, oversized ++ * horizontally to maintain 16-byte alignment) plus 16 columns and ++ * 4 rows below to catch write overflows */ ++ LOCAL_ALIGNED_16(uint8_t, filter_buf0, [24 * 48]); ++ LOCAL_ALIGNED_16(uint8_t, filter_buf1, [24 * 48]); ++ ++ VC1DSPContext h; ++ ++ const test tests[] = { ++ VC1DSP_TEST(vc1_v_loop_filter4) ++ VC1DSP_TEST(vc1_h_loop_filter4) ++ VC1DSP_TEST(vc1_v_loop_filter8) ++ VC1DSP_TEST(vc1_h_loop_filter8) ++ VC1DSP_TEST(vc1_v_loop_filter16) ++ VC1DSP_TEST(vc1_h_loop_filter16) ++ }; ++ ++ ff_vc1dsp_init(&h); ++ ++ for (size_t t = 0; t < FF_ARRAY_ELEMS(tests); ++t) { ++ void (*func)(uint8_t *, ptrdiff_t, int) = *(void **)((intptr_t) &h + tests[t].offset); ++ declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *, ptrdiff_t, int); ++ if (check_func(func, "vc1dsp.%s", tests[t].name)) { ++ for (int count = 1000; count > 0; --count) { ++ int pq = rnd() % 31 + 1; ++ RANDOMIZE_BUFFER8_MID_WEIGHTED(filter_buf, 24 * 48); ++ call_ref(filter_buf0 + 4 * 48 + 16, 48, pq); ++ call_new(filter_buf1 + 4 * 48 + 16, 48, pq); ++ if (memcmp(filter_buf0, filter_buf1, 24 * 48)) ++ fail(); ++ } ++ } ++ for (int j = 0; j < 24; ++j) ++ for (int i = 0; i < 48; ++i) ++ filter_buf1[j * 48 + i] = 0x60 + 0x40 * (i >= 16 && j >= 4); ++ if (check_func(func, "vc1dsp.%s_bestcase", tests[t].name)) ++ bench_new(filter_buf1 + 4 * 48 + 16, 48, 1); ++ if (check_func(func, "vc1dsp.%s_worstcase", tests[t].name)) ++ bench_new(filter_buf1 + 4 * 48 + 16, 48, 31); ++ } ++} ++ ++#define TEST_UNESCAPE \ ++ do { \ ++ for (int count = 100; count > 0; --count) { \ ++ escaped_offset = rnd() & 7; \ ++ unescaped_offset = rnd() & 7; \ ++ escaped_len = (1u << (rnd() % 8) + 3) - (rnd() & 7); \ ++ RANDOMIZE_BUFFER8(unescaped, UNESCAPE_BUF_SIZE); \ ++ len0 = call_ref(escaped0 + escaped_offset, escaped_len, unescaped0 + unescaped_offset); \ ++ len1 = call_new(escaped1 + escaped_offset, escaped_len, unescaped1 + unescaped_offset); \ ++ if (len0 != len1 || memcmp(unescaped0, unescaped1, UNESCAPE_BUF_SIZE)) \ ++ fail(); \ ++ } \ ++ } while (0) ++ ++static void check_unescape(void) ++{ ++ /* This appears to be a typical length of buffer in use */ ++#define LOG2_UNESCAPE_BUF_SIZE 17 ++#define UNESCAPE_BUF_SIZE (1u<<LOG2_UNESCAPE_BUF_SIZE) ++ LOCAL_ALIGNED_8(uint8_t, escaped0, [UNESCAPE_BUF_SIZE]); ++ LOCAL_ALIGNED_8(uint8_t, escaped1, [UNESCAPE_BUF_SIZE]); ++ LOCAL_ALIGNED_8(uint8_t, unescaped0, [UNESCAPE_BUF_SIZE]); ++ LOCAL_ALIGNED_8(uint8_t, unescaped1, [UNESCAPE_BUF_SIZE]); ++ ++ VC1DSPContext h; ++ ++ ff_vc1dsp_init(&h); ++ ++ if (check_func(h.vc1_unescape_buffer, "vc1dsp.vc1_unescape_buffer")) { ++ int len0, len1, escaped_offset, unescaped_offset, escaped_len; ++ declare_func_emms(AV_CPU_FLAG_MMX, int, const uint8_t *, int, uint8_t *); ++ ++ /* Test data which consists of escapes sequences packed as tightly as possible */ ++ for (int x = 0; x < UNESCAPE_BUF_SIZE; ++x) ++ escaped1[x] = escaped0[x] = 3 * (x % 3 == 0); ++ TEST_UNESCAPE; ++ ++ /* Test random data */ ++ RANDOMIZE_BUFFER8(escaped, UNESCAPE_BUF_SIZE); ++ TEST_UNESCAPE; ++ ++ /* Test data with escape sequences at random intervals */ ++ for (int x = 0; x <= UNESCAPE_BUF_SIZE - 4;) { ++ int gap, gap_msb; ++ escaped1[x+0] = escaped0[x+0] = 0; ++ escaped1[x+1] = escaped0[x+1] = 0; ++ escaped1[x+2] = escaped0[x+2] = 3; ++ escaped1[x+3] = escaped0[x+3] = rnd() & 3; ++ gap_msb = 2u << (rnd() % 8); ++ gap = (rnd() &~ -gap_msb) | gap_msb; ++ x += gap; ++ } ++ TEST_UNESCAPE; ++ ++ /* Test data which is known to contain no escape sequences */ ++ memset(escaped0, 0xFF, UNESCAPE_BUF_SIZE); ++ memset(escaped1, 0xFF, UNESCAPE_BUF_SIZE); ++ TEST_UNESCAPE; ++ ++ /* Benchmark the no-escape-sequences case */ ++ bench_new(escaped1, UNESCAPE_BUF_SIZE, unescaped1); ++ } ++} ++ ++void checkasm_check_vc1dsp(void) ++{ ++ check_inv_trans_inplace(); ++ check_inv_trans_adding(); ++ report("inv_trans"); ++ ++ check_loop_filter(); ++ report("loop_filter"); ++ ++ check_unescape(); ++ report("unescape_buffer"); ++} +--- a/tests/fate/checkasm.mak ++++ b/tests/fate/checkasm.mak +@@ -16,6 +16,7 @@ FATE_CHECKASM = fate-checkasm-aacpsdsp + fate-checkasm-hevc_add_res \ + fate-checkasm-hevc_idct \ + fate-checkasm-hevc_sao \ ++ fate-checkasm-idctdsp \ + fate-checkasm-jpeg2000dsp \ + fate-checkasm-llviddsp \ + fate-checkasm-llviddspenc \ +@@ -27,6 +28,7 @@ FATE_CHECKASM = fate-checkasm-aacpsdsp + fate-checkasm-sw_scale \ + fate-checkasm-v210dec \ + fate-checkasm-v210enc \ ++ fate-checkasm-vc1dsp \ + fate-checkasm-vf_blend \ + fate-checkasm-vf_colorspace \ + fate-checkasm-vf_eq \ diff --git a/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0005-fix_flags.diff b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0005-fix-flags.diff index 1eb10749f1..ab6f139af6 100644 --- a/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0005-fix_flags.diff +++ b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/0005-fix-flags.diff @@ -1,8 +1,11 @@ -Upstream-status: Pending +Upstream-Status: Inappropriate + +RPI-Distro repo clones original ffmpeg and applies patches to enable +raspiberry pi support. --- a/configure +++ b/configure -@@ -6467,11 +6467,9 @@ enabled mbedtls && { check_pkg +@@ -6471,11 +6471,9 @@ enabled mbedtls && { check_pkg die "ERROR: mbedTLS not found"; } enabled mediacodec && { enabled jni || die "ERROR: mediacodec requires --enable-jni"; } ( enabled rpi || diff --git a/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/2001-configure-setup-for-OE-core-usage.patch b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/2001-configure-setup-for-OE-core-usage.patch new file mode 100644 index 0000000000..f1538275d2 --- /dev/null +++ b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/2001-configure-setup-for-OE-core-usage.patch @@ -0,0 +1,82 @@ +From 01e738a8f1414acd0102e432bbc15b4e603fd956 Mon Sep 17 00:00:00 2001 +From: Vincent Davis Jr <vince@underview.tech> +Date: Thu, 8 Dec 2022 10:34:20 -0600 +Subject: [PATCH] configure: setup for OE-core usage + +Upstream-Status: Inappropriate + +RPI-Distro repo clones original ffmpeg and applies patches to enable +raspiberry pi support. + +Add global CFLAGS and LDFLAGS. So, that when +./configure runs test it's able to locate proper +headers and libs in a cross-compile environment. + +Add new check to opengl. None of the above headers +exists and we also should be using GLESv2. + +Update where compiler finds OMX_Core.h + +Only check that sdl2 version greater than 2.0.1 + +Signed-off-by: Vincent Davis Jr <vince@underview.tech> +--- + configure | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/configure b/configure +index 723b81f1..0c7f2654 100755 +--- a/configure ++++ b/configure +@@ -5746,6 +5746,9 @@ enable_weak_pic() { + } + + enabled pic && enable_weak_pic ++# Set CFLAGS and LDFLAGS globally ++add_cflags -I${sysroot}/usr/include/ -I${sysroot}/usr/include/IL -I${sysroot}/usr/include/drm ++add_ldflags -L${sysroot}/usr/lib/ + + test_cc <<EOF || die "Symbol mangling check failed." + int ff_extern; +@@ -6471,8 +6474,7 @@ enabled mbedtls && { check_pkg_config mbedtls mbedtls mbedtls/x509_crt + die "ERROR: mbedTLS not found"; } + enabled mediacodec && { enabled jni || die "ERROR: mediacodec requires --enable-jni"; } + ( enabled rpi || +- enabled mmal ) && { { add_cflags -isystem/opt/vc/include/ -isystem/opt/vc/include/interface/vmcs_host/linux -isystem/opt/vc/include/interface/vcos/pthreads -fgnu89-inline && +- add_ldflags -L/opt/vc/lib/ && ++ enabled mmal ) && { { add_cflags -I${sysroot}/usr/include/interface/vmcs_host/linux -I${sysroot}/usr/include/interface/vcos/pthreads -fgnu89-inline && + check_lib mmal interface/mmal/mmal.h mmal_port_connect -lmmal_core -lmmal_util -lmmal_vc_client -lbcm_host -lvcsm -lvchostif -lvchiq_arm -lvcos; } || + die "ERROR: mmal not found" && + check_func_headers interface/mmal/mmal.h "MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS"; } +@@ -6492,15 +6494,15 @@ enabled opengl && { check_lib opengl GL/glx.h glXGetProcAddress "-lGL + check_lib opengl windows.h wglGetProcAddress "-lopengl32 -lgdi32" || + check_lib opengl OpenGL/gl3.h glGetError "-Wl,-framework,OpenGL" || + check_lib opengl ES2/gl.h glGetError "-isysroot=${sysroot} -Wl,-framework,OpenGLES" || ++ check_lib opengl GLES2/gl2.h glGetError "-lGLESv2" || + die "ERROR: opengl not found." + } +-enabled omx_rpi && { test_code cc OMX_Core.h OMX_IndexConfigBrcmVideoRequestIFrame || ++enabled omx_rpi && { test_code cc IL/OMX_Core.h OMX_IndexConfigBrcmVideoRequestIFrame || + { ! enabled cross_compile && +- add_cflags -isystem/opt/vc/include/IL && +- test_code cc OMX_Core.h OMX_IndexConfigBrcmVideoRequestIFrame; } || ++ test_code cc IL/OMX_Core.h OMX_IndexConfigBrcmVideoRequestIFrame; } || + die "ERROR: OpenMAX IL headers from raspberrypi/firmware not found"; } && + enable omx +-enabled omx && require_headers OMX_Core.h ++enabled omx && require_headers IL/OMX_Core.h + enabled openssl && { check_pkg_config openssl openssl openssl/ssl.h OPENSSL_init_ssl || + check_pkg_config openssl openssl openssl/ssl.h SSL_library_init || + check_lib openssl openssl/ssl.h OPENSSL_init_ssl -lssl -lcrypto || +@@ -6540,7 +6542,7 @@ fi + + if enabled sdl2; then + SDL2_CONFIG="${cross_prefix}sdl2-config" +- test_pkg_config sdl2 "sdl2 >= 2.0.1 sdl2 < 2.1.0" SDL_events.h SDL_PollEvent ++ test_pkg_config sdl2 "sdl2 >= 2.0.1" SDL_events.h SDL_PollEvent + if disabled sdl2 && "${SDL2_CONFIG}" --version > /dev/null 2>&1; then + sdl2_cflags=$("${SDL2_CONFIG}" --cflags) + sdl2_extralibs=$("${SDL2_CONFIG}" --libs) +-- +2.38.1 + diff --git a/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/2002-libavdevice-opengl_enc-update-dynamic-function-loader.patch b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/2002-libavdevice-opengl_enc-update-dynamic-function-loader.patch new file mode 100644 index 0000000000..43a9191885 --- /dev/null +++ b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/2002-libavdevice-opengl_enc-update-dynamic-function-loader.patch @@ -0,0 +1,111 @@ +From be426ad76c3e486f1364dd292cf8e1c633c80e91 Mon Sep 17 00:00:00 2001 +From: Vincent Davis Jr <vince@underview.tech> +Date: Thu, 8 Dec 2022 10:39:47 -0600 +Subject: [PATCH] libavdevice: opengl_enc.c update dynamic function loader + +Upstream-Status: Inappropriate + +RPI-Distro repo clones original ffmpeg and applies patches to enable +raspiberry pi support. + +For meta-raspberrypi ffmpeg builds, when opengl +is enabled do_compile will fail. Reasion is that +glGetProcAddress is undefined in either GLES2/gl2.h +or GLES2/gl2ext.h. + +define SelectedGetProcAddress to SDL_GL_GetProcAddress +if sdl2 is included. If not included, define function +pointers at compile time versus runtime. + +Signed-off-by: Vincent Davis Jr <vince@underview.tech> +--- + libavdevice/opengl_enc.c | 44 ++++++++++++++++++++++++++++++++++++---- + 1 file changed, 40 insertions(+), 4 deletions(-) + +diff --git a/libavdevice/opengl_enc.c b/libavdevice/opengl_enc.c +index 2bdb8da7..eabc1bf8 100644 +--- a/libavdevice/opengl_enc.c ++++ b/libavdevice/opengl_enc.c +@@ -37,12 +37,13 @@ + #include <OpenGL/gl3.h> + #elif HAVE_ES2_GL_H + #include <ES2/gl.h> +-#else +-#include <GL/gl.h> +-#include <GL/glext.h> + #endif + #if HAVE_GLXGETPROCADDRESS + #include <GL/glx.h> ++#else ++#define GL_GLEXT_PROTOTYPES ++#include <GLES2/gl2.h> ++#include <GLES2/gl2ext.h> + #endif + + #if CONFIG_SDL2 +@@ -493,8 +494,14 @@ static int av_cold opengl_load_procedures(OpenGLContext *opengl) + + #if HAVE_GLXGETPROCADDRESS + #define SelectedGetProcAddress glXGetProcAddress ++#define CAN_DYNAMIC_LOAD 1 + #elif HAVE_WGLGETPROCADDRESS + #define SelectedGetProcAddress wglGetProcAddress ++#elif CONFIG_SDL2 ++#define SelectedGetProcAddress SDL_GL_GetProcAddress ++#define CAN_DYNAMIC_LOAD 1 ++#else ++#define CAN_DYNAMIC_LOAD 0 + #endif + + #define LOAD_OPENGL_FUN(name, type) \ +@@ -504,7 +511,8 @@ static int av_cold opengl_load_procedures(OpenGLContext *opengl) + return AVERROR(ENOSYS); \ + } + +-#if CONFIG_SDL2 ++#if CAN_DYNAMIC_LOAD ++#if CONFIG_SDL2 + if (!opengl->no_window) + return opengl_sdl_load_procedures(opengl); + #endif +@@ -534,9 +542,37 @@ static int av_cold opengl_load_procedures(OpenGLContext *opengl) + LOAD_OPENGL_FUN(glGetShaderInfoLog, FF_PFNGLGETSHADERINFOLOGPROC) + LOAD_OPENGL_FUN(glEnableVertexAttribArray, FF_PFNGLENABLEVERTEXATTRIBARRAYPROC) + LOAD_OPENGL_FUN(glVertexAttribPointer, FF_PFNGLVERTEXATTRIBPOINTERPROC) ++#else ++ procs->glActiveTexture = glActiveTexture; ++ procs->glGenBuffers = glGenBuffers; ++ procs->glDeleteBuffers = glDeleteBuffers; ++ procs->glBufferData = glBufferData; ++ procs->glBindBuffer = glBindBuffer; ++ procs->glGetAttribLocation = glGetAttribLocation; ++ procs->glGetUniformLocation = glGetUniformLocation; ++ procs->glUniform1f = glUniform1f; ++ procs->glUniform1i = glUniform1i; ++ procs->glUniformMatrix4fv = glUniformMatrix4fv; ++ procs->glCreateProgram = glCreateProgram; ++ procs->glDeleteProgram = glDeleteProgram; ++ procs->glUseProgram = glUseProgram; ++ procs->glLinkProgram = glLinkProgram; ++ procs->glGetProgramiv = glGetProgramiv; ++ procs->glGetProgramInfoLog = glGetProgramInfoLog; ++ procs->glAttachShader = glAttachShader; ++ procs->glCreateShader = glCreateShader; ++ procs->glDeleteShader = glDeleteShader; ++ procs->glCompileShader = glCompileShader; ++ procs->glShaderSource = glShaderSource; ++ procs->glGetShaderiv = glGetShaderiv; ++ procs->glGetShaderInfoLog = glGetShaderInfoLog; ++ procs->glEnableVertexAttribArray = glEnableVertexAttribArray; ++ procs->glVertexAttribPointer = (FF_PFNGLVERTEXATTRIBPOINTERPROC) glVertexAttribPointer; ++#endif + + return 0; + ++#undef CAN_DYNAMIC_LOAD + #undef SelectedGetProcAddress + #undef LOAD_OPENGL_FUN + } +-- +2.38.1 + diff --git a/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/2003-libavcodec-fix-v4l2_req_devscan.patch b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/2003-libavcodec-fix-v4l2_req_devscan.patch new file mode 100644 index 0000000000..2232c48308 --- /dev/null +++ b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/2003-libavcodec-fix-v4l2_req_devscan.patch @@ -0,0 +1,45 @@ +From 62c2f041890a6e20770350721a0a2138d0b38634 Mon Sep 17 00:00:00 2001 +From: Vincent Davis Jr <vince@underview.tech> +Date: Sat, 3 Dec 2022 23:35:51 -0600 +Subject: [PATCH] libavcodec: fix v4l2_req_devscan.h + +Upstream-Status: Inappropriate + +RPI-Distro repo clones original ffmpeg and applies patches to enable +raspiberry pi support. + +Fixes minor differences between v4l2_req_devscan.c +and v4l2_req_devscan.h after all patches have been +applied. + +Signed-off-by: Vincent Davis Jr <vince@underview.tech> +--- + libavcodec/v4l2_req_devscan.h | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/libavcodec/v4l2_req_devscan.h b/libavcodec/v4l2_req_devscan.h +index 0baef365..cd9c49ac 100644 +--- a/libavcodec/v4l2_req_devscan.h ++++ b/libavcodec/v4l2_req_devscan.h +@@ -1,6 +1,8 @@ + #ifndef _DEVSCAN_H_ + #define _DEVSCAN_H_ + ++#include <stdint.h> ++ + struct devscan; + struct decdev; + enum v4l2_buf_type; +@@ -13,7 +15,8 @@ const char *decdev_video_path(const struct decdev *const dev); + enum v4l2_buf_type decdev_src_type(const struct decdev *const dev); + uint32_t decdev_src_pixelformat(const struct decdev *const dev); + +-const struct decdev *devscan_find(struct devscan *const scan, const uint32_t src_fmt_v4l2); ++const struct decdev *devscan_find(struct devscan *const scan, ++ const uint32_t src_fmt_v4l2); + + int devscan_build(void * const dc, struct devscan **pscan); + void devscan_delete(struct devscan **const pScan); +-- +2.38.1 + diff --git a/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/2004-libavcodec-omx-replace-opt-vc-path-with-usr-lib.patch b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/2004-libavcodec-omx-replace-opt-vc-path-with-usr-lib.patch new file mode 100644 index 0000000000..02c07de2cc --- /dev/null +++ b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/files/2004-libavcodec-omx-replace-opt-vc-path-with-usr-lib.patch @@ -0,0 +1,35 @@ +From 0dfb56e12fa709794525cda1471091f6699905d5 Mon Sep 17 00:00:00 2001 +From: Vincent Davis Jr <vince@underview.tech> +Date: Thu, 8 Dec 2022 10:49:03 -0600 +Subject: [PATCH] libavcodec: omx replace /opt/vc path with /usr/lib + +Upstream-Status: Inappropriate + +RPI-Distro repo clones original ffmpeg and applies patches to enable +raspiberry pi support. + +Configures omx.c for OE usages as libbcm_host.so +and libopenmaxil.so are located in a different +location. + +Signed-off-by: Vincent Davis Jr <vince@underview.tech> +--- + libavcodec/omx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libavcodec/omx.c b/libavcodec/omx.c +index 0a6a3083..8c6e9193 100644 +--- a/libavcodec/omx.c ++++ b/libavcodec/omx.c +@@ -141,7 +141,7 @@ static av_cold OMXContext *omx_init(void *logctx, const char *libname, const cha + { + static const char * const libnames[] = { + #if CONFIG_OMX_RPI +- "/opt/vc/lib/libopenmaxil.so", "/opt/vc/lib/libbcm_host.so", ++ "/usr/lib/libopenmaxil.so", "/usr/lib/libbcm_host.so", + #else + "libOMX_Core.so", NULL, + "libOmxCore.so", NULL, +-- +2.38.1 + diff --git a/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/rpidistro-ffmpeg_4.3.2.bb b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/rpidistro-ffmpeg_4.3.4.bb index bf8d4b824c..30e7c575e3 100644 --- a/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/rpidistro-ffmpeg_4.3.2.bb +++ b/meta-raspberrypi/recipes-multimedia/rpidistro-ffmpeg/rpidistro-ffmpeg_4.3.4.bb @@ -33,23 +33,27 @@ RPROVIDES:${PN} = "${PROVIDES}" DEPENDS = "nasm-native" inherit autotools pkgconfig -PACKAGECONFIG ??= "avdevice avfilter avcodec avformat swresample swscale postproc avresample \ - opengl udev sdl2 ffplay alsa bzlib lzma pic pthreads shared theora zlib \ - libvorbis x264 gpl sand rpi vout-drm vout-egl \ - ${@bb.utils.contains('MACHINE_FEATURES', 'vc4graphics', '', 'mmal', d)} \ +PACKAGECONFIG ??= "avdevice avfilter avcodec avformat swresample swscale postproc avresample ffplay \ + v4l2 drm udev alsa bzlib lzma pic pthreads shared theora zlib libvorbis x264 gpl \ + ${@bb.utils.contains('MACHINE_FEATURES', 'vc4graphics', '', 'mmal rpi sand vout-drm', d)} \ ${@bb.utils.contains('AVAILTUNES', 'mips32r2', 'mips32r2', '', d)} \ - ${@bb.utils.contains('DISTRO_FEATURES', 'x11', 'xv xcb', '', d)}" + ${@bb.utils.contains('DISTRO_FEATURES', 'opengl', 'opengl', '', d)} \ + ${@bb.utils.contains('DISTRO_FEATURES', 'x11', 'xv xcb vout-egl epoxy', '', d)}" SRC_URI = "\ git://git@github.com/RPi-Distro/ffmpeg;protocol=https;branch=pios/bullseye \ file://0001-avcodec-arm-sbcenc-avoid-callee-preserved-vfp-regist.patch \ file://0002-Fix-build-on-powerpc-and-ppc64.patch \ file://0003-avcodec-pngenc-remove-monowhite-from-apng-formats.patch \ - file://0004-ffmpeg-4.3.2-rpi_10.patch \ - file://0005-fix_flags.diff \ -" + file://0004-ffmpeg-4.3.4-rpi_14.patch \ + file://0005-fix-flags.diff \ + file://2001-configure-setup-for-OE-core-usage.patch \ + file://2002-libavdevice-opengl_enc-update-dynamic-function-loader.patch \ + file://2003-libavcodec-fix-v4l2_req_devscan.patch \ + file://2004-libavcodec-omx-replace-opt-vc-path-with-usr-lib.patch \ + " -SRCREV = "ea72093f350f38edcd39c480b331c3219c377642" +SRCREV = "246e1a55a0eca931537d8706acd8b133c07beb05" S = "${WORKDIR}/git" @@ -70,7 +74,7 @@ PACKAGECONFIG[altivec] = "--enable-altivec,--disable-altivec," PACKAGECONFIG[bzlib] = "--enable-bzlib,--disable-bzlib,bzip2" PACKAGECONFIG[fdk-aac] = "--enable-libfdk-aac --enable-nonfree,--disable-libfdk-aac,fdk-aac" PACKAGECONFIG[gpl] = "--enable-gpl,--disable-gpl" -PACKAGECONFIG[opengl] = "--enable-opengl,--disable-opengl,virtual/libgl" +PACKAGECONFIG[opengl] = "--enable-opengl,--disable-opengl,virtual/libgles2" PACKAGECONFIG[gsm] = "--enable-libgsm,--disable-libgsm,libgsm" PACKAGECONFIG[jack] = "--enable-indev=jack,--disable-indev=jack,jack" PACKAGECONFIG[libvorbis] = "--enable-libvorbis,--disable-libvorbis,libvorbis" @@ -90,9 +94,11 @@ PACKAGECONFIG[x264] = "--enable-libx264,--disable-libx264,x264" PACKAGECONFIG[xcb] = "--enable-libxcb,--disable-libxcb,libxcb" PACKAGECONFIG[xv] = "--enable-outdev=xv,--disable-outdev=xv,libxv" PACKAGECONFIG[zlib] = "--enable-zlib,--disable-zlib,zlib" -#PACKAGECONFIG[snappy] = "--enable-libsnappy,--enable-libsnappy,snappy" +PACKAGECONFIG[snappy] = "--enable-libsnappy,--disable-libsnappy,snappy" PACKAGECONFIG[udev] = "--enable-libudev,--disable-libudev,udev" -PACKAGECONFIG[v4l2] = "--enable-libv4l2 --enable-v4l2-request --enable-libdrm,,v4l-utils" +PACKAGECONFIG[drm] = "--enable-libdrm,--disable-libdrm,libdrm" +PACKAGECONFIG[epoxy] = "--enable-epoxy,--disable-epoxy,libepoxy" +PACKAGECONFIG[v4l2] = "--enable-libv4l2 --enable-v4l2-m2m,,v4l-utils" PACKAGECONFIG[mmal] = "--enable-omx --enable-omx-rpi --enable-mmal,,userland" PACKAGECONFIG[sand] = "--enable-sand,," PACKAGECONFIG[rpi] = "--enable-rpi,," @@ -138,11 +144,6 @@ EXTRA_OECONF = " \ " EXTRA_OECONF:append:linux-gnux32 = " --disable-asm" -# Directly specify the include directories the contain headers for -# libdrm -# openmaxil -TARGET_CFLAGS:append = " -I${STAGING_INCDIR}/IL -I${STAGING_INCDIR}/drm" - # gold crashes on x86, another solution is to --disable-asm but thats more hacky # ld.gold: internal error in relocate_section, at ../../gold/i386.cc:3684 LDFLAGS:append:x86 = "${@bb.utils.contains('DISTRO_FEATURES', 'ld-is-gold', ' -fuse-ld=bfd ', '', d)}" @@ -190,5 +191,5 @@ INSANE_SKIP:${MLPREFIX}libpostproc = "textrel" # Only enable it for rpi class of machines COMPATIBLE_HOST = "null" -COMPATIBLE_HOST:rpi = "'(.*)'" +COMPATIBLE_HOST:rpi = "(.*)" |