diff --git a/.github/workflows/build-aarch64-emu-libretro.yml b/.github/workflows/build-aarch64-emu-libretro.yml index 3b5aa2ad362..fccbcf18356 100644 --- a/.github/workflows/build-aarch64-emu-libretro.yml +++ b/.github/workflows/build-aarch64-emu-libretro.yml @@ -130,9 +130,14 @@ jobs: uses: actions/upload-artifact@v7 with: name: output.logs (${{ inputs.DEVICE }}-aarch64-emu-libretro) + include-hidden-files: true path: | output.log ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/.threads/logs/ + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/config.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/meson-logs/meson-log.txt + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/CMakeFiles/CMakeError.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/config.summary - name: Clean ccache run: | diff --git a/.github/workflows/build-aarch64-emu-standalone.yml b/.github/workflows/build-aarch64-emu-standalone.yml index 9333da7f556..7366eca2718 100644 --- a/.github/workflows/build-aarch64-emu-standalone.yml +++ b/.github/workflows/build-aarch64-emu-standalone.yml @@ -159,9 +159,14 @@ jobs: uses: actions/upload-artifact@v7 with: name: output.logs (${{ inputs.DEVICE }}-aarch64-emu-standalone) + include-hidden-files: true path: | output.log ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/.threads/logs/ + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/config.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/meson-logs/meson-log.txt + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/CMakeFiles/CMakeError.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/config.summary - name: Clean ccache run: | diff --git a/.github/workflows/build-aarch64-image.yml b/.github/workflows/build-aarch64-image.yml index 0de779790ab..bc31744efd2 100644 --- a/.github/workflows/build-aarch64-image.yml +++ b/.github/workflows/build-aarch64-image.yml @@ -118,9 +118,14 @@ jobs: uses: actions/upload-artifact@v7 with: name: output.logs (${{ inputs.DEVICE }}-aarch64-image) + include-hidden-files: true path: | output.log ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/.threads/logs/ + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/config.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/meson-logs/meson-log.txt + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/CMakeFiles/CMakeError.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/config.summary - name: Get date run: echo "DATE=$(date +'%Y%m%d')" >> $GITHUB_ENV diff --git a/.github/workflows/build-aarch64-mame-lr.yml b/.github/workflows/build-aarch64-mame-lr.yml index deecb709e0b..cb035b9fa98 100644 --- a/.github/workflows/build-aarch64-mame-lr.yml +++ b/.github/workflows/build-aarch64-mame-lr.yml @@ -78,9 +78,14 @@ jobs: uses: actions/upload-artifact@v7 with: name: output.logs (${{ inputs.DEVICE }}-aarch64-mame-lr) + include-hidden-files: true path: | output.log ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/.threads/logs/ + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/config.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/meson-logs/meson-log.txt + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/CMakeFiles/CMakeError.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/config.summary - name: Clean ccache run: | diff --git a/.github/workflows/build-aarch64-qt6.yml b/.github/workflows/build-aarch64-qt6.yml index 689bca0a49a..7565a442f6b 100644 --- a/.github/workflows/build-aarch64-qt6.yml +++ b/.github/workflows/build-aarch64-qt6.yml @@ -84,9 +84,14 @@ jobs: uses: actions/upload-artifact@v7 with: name: output.logs (${{ inputs.DEVICE }}-aarch64-qt6) + include-hidden-files: true path: | output.log ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/.threads/logs/ + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/config.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/meson-logs/meson-log.txt + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/CMakeFiles/CMakeError.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/config.summary - name: Clean ccache run: | diff --git a/.github/workflows/build-aarch64-rust.yml b/.github/workflows/build-aarch64-rust.yml index 10b6098f6f1..b3ed702203c 100644 --- a/.github/workflows/build-aarch64-rust.yml +++ b/.github/workflows/build-aarch64-rust.yml @@ -63,9 +63,14 @@ jobs: uses: actions/upload-artifact@v7 with: name: output.logs-${{ inputs.DEVICE }}-aarch64-rust + include-hidden-files: true path: | output.log ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/.threads/logs/ + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/config.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/meson-logs/meson-log.txt + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/CMakeFiles/CMakeError.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/config.summary - name: Print space run: df -h diff --git a/.github/workflows/build-aarch64-toolchain.yml b/.github/workflows/build-aarch64-toolchain.yml index 797c4a6ebb9..529c749ddde 100644 --- a/.github/workflows/build-aarch64-toolchain.yml +++ b/.github/workflows/build-aarch64-toolchain.yml @@ -65,9 +65,14 @@ jobs: uses: actions/upload-artifact@v7 with: name: output.logs (${{ inputs.DEVICE }}-aarch64-toolchain) + include-hidden-files: true path: | output.log ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/.threads/logs/ + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/config.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/meson-logs/meson-log.txt + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/CMakeFiles/CMakeError.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/config.summary - name: Build llvm:target if: ${{ inputs.DEVICE == 'SM8250' || inputs.DEVICE == 'SM8550' || inputs.DEVICE == 'SM8650' || inputs.DEVICE == 'SM8750' }} diff --git a/.github/workflows/build-aarch64.yml b/.github/workflows/build-aarch64.yml index 647a62b68dd..0192c2c95db 100644 --- a/.github/workflows/build-aarch64.yml +++ b/.github/workflows/build-aarch64.yml @@ -76,9 +76,14 @@ jobs: uses: actions/upload-artifact@v7 with: name: output.logs-${{ inputs.DEVICE }}-aarch64 + include-hidden-files: true path: | output.log ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/.threads/logs/ + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/config.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/meson-logs/meson-log.txt + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/CMakeFiles/CMakeError.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/config.summary - name: Get date run: echo "DATE=$(date +'%Y%m%d')" >> $GITHUB_ENV @@ -111,9 +116,14 @@ jobs: uses: actions/upload-artifact@v7 with: name: output.logs-${{ inputs.DEVICE }}-modules + include-hidden-files: true path: | output.log ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/.threads/logs/ + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/config.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/meson-logs/meson-log.txt + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/CMakeFiles/CMakeError.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.aarch64/build/**/config.summary - name: Clean ccache run: | diff --git a/.github/workflows/build-arm.yml b/.github/workflows/build-arm.yml index 0388394a0ce..d2ada016b70 100644 --- a/.github/workflows/build-arm.yml +++ b/.github/workflows/build-arm.yml @@ -62,9 +62,14 @@ jobs: uses: actions/upload-artifact@v7 with: name: output.logs (${{ inputs.DEVICE }}-arm) + include-hidden-files: true path: | output.log ./build.ROCKNIX-${{ inputs.DEVICE }}.arm/.threads/logs/ + ./build.ROCKNIX-${{ inputs.DEVICE }}.arm/build/**/config.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.arm/build/**/meson-logs/meson-log.txt + ./build.ROCKNIX-${{ inputs.DEVICE }}.arm/build/**/CMakeFiles/CMakeError.log + ./build.ROCKNIX-${{ inputs.DEVICE }}.arm/build/**/config.summary - name: Clean ccache run: | diff --git a/Dockerfile b/Dockerfile index a041070176a..c5d58cbeea5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,6 +32,9 @@ RUN apt-get update \ RUN if [ "$(uname -m)" = "aarch64" ]; then \ apt-get install -y libc6-amd64-cross qemu-user-binfmt --no-install-recommends; \ + mkdir -p /lib64; \ + ln -sf /usr/x86_64-linux-gnu/lib/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2; \ + ln -sfn /usr/x86_64-linux-gnu/lib /usr/lib/x86_64-linux-gnu; \ fi RUN rm -rf /var/lib/apt/lists/* diff --git a/config/optimize b/config/optimize index bcb4095f853..d9769fa7819 100644 --- a/config/optimize +++ b/config/optimize @@ -9,7 +9,19 @@ TARGET_LIBDIR="$SYSROOT_PREFIX/lib $SYSROOT_PREFIX/usr/lib" TARGET_INCDIR="$SYSROOT_PREFIX/include $SYSROOT_PREFIX/usr/include" HOST_CPPFLAGS="" -HOST_CFLAGS="-march=x86-64 -mtune=generic -O2 -DNDEBUG -Wall -pipe -I$TOOLCHAIN/include" +# baseline -march per build machine so host builds are portable across CPUs +case "$(uname -m)" in + x86_64) + HOST_ARCH_FLAGS="-march=x86-64 -mtune=generic" + ;; + aarch64|arm64) + HOST_ARCH_FLAGS="-march=armv8-a" + ;; + *) + HOST_ARCH_FLAGS="" + ;; +esac +HOST_CFLAGS="$HOST_ARCH_FLAGS -O2 -DNDEBUG -Wall -pipe -I$TOOLCHAIN/include" HOST_CXXFLAGS="$HOST_CFLAGS" HOST_LDFLAGS="-Wl,-rpath,$TOOLCHAIN/lib -L$TOOLCHAIN/lib" HOST_INCDIR="$TOOLCHAIN/include /usr/include" diff --git a/distributions/ROCKNIX/options b/distributions/ROCKNIX/options index 5ce69d6e26a..1908bdf271c 100644 --- a/distributions/ROCKNIX/options +++ b/distributions/ROCKNIX/options @@ -4,6 +4,12 @@ # GOLD (Google Linker) support GOLD_SUPPORT="yes" +# MOLD (Modern Linker) support, and use it as the default target linker +# (packages opt out via PKG_BUILD_FLAGS: glibc pins +bfd, box86/box64 +# need -mold for -Ttext-segment) + MOLD_SUPPORT="yes" + DEFAULT_LINKER="mold" + # HARDENING (security relevant linker and compiler flags) support HARDENING_SUPPORT="no" @@ -182,8 +188,16 @@ # btop tool (yes / no) BTOP_TOOL="yes" -# Distribution Specific source location - DISTRO_MIRROR="https://github.com/ROCKNIX/distribution-sources/releases/download/sources-v2" +# Distribution Specific source location. Space separated list, tried in order +# after the upstream URL. +# +# The second entry is TEMPORARY, DROP BEFORE MERGE: the org mirror predates the +# versions this branch bumped to, so an upstream hiccup on any of them is a hard +# CI failure - invisible-mirror.net rate limits ncurses, gnupg.org 403s and +# freedesktop.org 418s. The fork release carries the affected tarballs. +# See https://github.com/sunshineinabox/distribution/releases/tag/sources + DISTRO_MIRROR="https://github.com/ROCKNIX/distribution-sources/releases/download/sources-v2 \ + https://github.com/sunshineinabox/distribution/releases/download/sources" DISTRO_SRC="https://sources.libreelec.tv/$DISTRO_VERSION" # Default size of system partition, in MB, eg. 512 diff --git a/projects/ROCKNIX/devices/RK3326/packages/u-boot-legacy/package.mk b/projects/ROCKNIX/devices/RK3326/packages/u-boot-legacy/package.mk index 06bd64f11e0..23ac2fd59a1 100644 --- a/projects/ROCKNIX/devices/RK3326/packages/u-boot-legacy/package.mk +++ b/projects/ROCKNIX/devices/RK3326/packages/u-boot-legacy/package.mk @@ -20,6 +20,10 @@ if [ -n "${UBOOT_FIRMWARE}" ]; then fi pre_make_target() { + # Same gcc 16 -Wunused-but-set-variable vs -Werror problem as the RK3588 + # tree: cmd/gpt.c carries the same dead accumulator. Vendor code. + export KCFLAGS="-Wno-error=unused-but-set-variable" + PKG_UBOOT_CONFIG="rocknix_rk3326_defconfig" PKG_RKBIN="$(get_build_dir rkbin)" PKG_MINILOADER="${PKG_RKBIN}/bin/rk33/rk3326_miniloader_v1.40.bin" diff --git a/projects/ROCKNIX/devices/RK3588/packages/u-boot/package.mk b/projects/ROCKNIX/devices/RK3588/packages/u-boot/package.mk index dea923740a3..296c3deba9c 100644 --- a/projects/ROCKNIX/devices/RK3588/packages/u-boot/package.mk +++ b/projects/ROCKNIX/devices/RK3588/packages/u-boot/package.mk @@ -19,6 +19,12 @@ if [ -n "${UBOOT_FIRMWARE}" ]; then fi pre_make_target() { + # gcc 16 promotes -Wunused-but-set-variable and this vendor tree builds + # -Werror. The hits are dead locals in cmd/ (gpt.c, then nvedit.c), which + # are cosmetic, and each one costs a full build to find. Turn the class + # off rather than carry a patch per file for a tree we do not own. + export KCFLAGS="-Wno-error=unused-but-set-variable" + PKG_UBOOT_CONFIG="orangepi_5_defconfig" PKG_RKBIN="$(get_build_dir rkbin)" PKG_MINILOADER="spl/u-boot-spl.bin" diff --git a/projects/ROCKNIX/packages/apps/mako-osd/patches/000-disable-placeholder-text.patch b/projects/ROCKNIX/packages/apps/mako-osd/patches/000-disable-placeholder-text.patch index f1497c23416..8379eb024fc 100644 --- a/projects/ROCKNIX/packages/apps/mako-osd/patches/000-disable-placeholder-text.patch +++ b/projects/ROCKNIX/packages/apps/mako-osd/patches/000-disable-placeholder-text.patch @@ -1,22 +1,74 @@ -diff --git a/render.c b/render.c -index 8fed6d8..b157323 100644 ---- a/render.c -+++ b/render.c -@@ -438,7 +438,7 @@ void render(struct mako_surface *surface, struct pool_buffer *buffer, int scale, - ++visible_count; +--- a/render.c 2026-08-09 23:04:49 ++++ b/render.c 2026-08-09 23:04:49 +@@ -355,17 +355,14 @@ + cairo_restore(cairo); + + size_t visible_count = 0; +- size_t hidden_count = 0; + int total_height = 0; + int max_width = 0; + int pending_bottom_margin = 0; + struct mako_notification *notif; +- size_t total_notifications = 0; + wl_list_for_each(notif, &state->notifications, link) { + if (notif->surface != surface) { + continue; } - } +- ++total_notifications; + + // Immediately before rendering we need to re-match all of the criteria + // so that matches against the anchor and output work even if the +@@ -390,7 +387,6 @@ + + if (style->max_visible >= 0 && + visible_count >= (size_t)style->max_visible) { +- ++hidden_count; + continue; + } + +@@ -435,45 +431,7 @@ + // group are rendered based on criteria, a group is considered a + // single entity for this purpose. + ++visible_count; +- } +- } +- +- if (hidden_count > 0) { +- struct mako_notification *hidden_notif = create_notification(state); +- hidden_notif->surface = surface; +- hidden_notif->hidden = true; +- apply_each_criteria(&state->config.criteria, hidden_notif); +- +- struct mako_style *style = &hidden_notif->style; - -+/* - if (hidden_count > 0) { - struct mako_notification *hidden_notif = create_notification(state); - hidden_notif->surface = surface; -@@ -478,7 +478,7 @@ void render(struct mako_surface *surface, struct pool_buffer *buffer, int scale, +- if (style->margin.top > pending_bottom_margin) { +- total_height += style->margin.top; +- } else { +- total_height += pending_bottom_margin; +- } +- +- struct mako_hidden_format_data data = { +- .hidden = hidden_count, +- .count = total_notifications, +- }; +- +- size_t text_ln = +- format_text(style->format, NULL, format_hidden_text, &data); +- char *text = malloc(text_ln + 1); +- if (text == NULL) { +- fprintf(stderr, "allocation failed"); +- return; } - destroy_notification(hidden_notif); - } - -+*/ +- format_text(style->format, text, format_hidden_text, &data); +- +- int hidden_height = render_notification( +- cairo, state, surface, style, text, NULL, total_height, scale, NULL, 0); +- free(text); +- +- total_height += hidden_height; +- pending_bottom_margin = style->margin.bottom; +- destroy_notification(hidden_notif); + } + *rendered_width = max_width; - *rendered_height = total_height; - } diff --git a/projects/ROCKNIX/packages/audio/alsa-lib/package.mk b/projects/ROCKNIX/packages/audio/alsa-lib/package.mk index 7649fd03eeb..00a3cf4a081 100644 --- a/projects/ROCKNIX/packages/audio/alsa-lib/package.mk +++ b/projects/ROCKNIX/packages/audio/alsa-lib/package.mk @@ -3,9 +3,10 @@ # Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv) PKG_NAME="alsa-lib" -PKG_VERSION="1.2.14" -PKG_LICENSE="GPL" -PKG_SITE="http://www.alsa-project.org/" +PKG_VERSION="1.2.16.1" +PKG_SHA256="f740db7f488255944ffd4428416ee3390a96742856916433df468c281436480e" +PKG_LICENSE="LGPL-2.1-or-later" +PKG_SITE="https://www.alsa-project.org/" PKG_URL="https://www.alsa-project.org/files/pub/lib/alsa-lib-${PKG_VERSION}.tar.bz2" PKG_DEPENDS_TARGET="toolchain alsa-ucm-conf alsa-topology-conf" PKG_LONGDESC="ALSA (Advanced Linux Sound Architecture) is the next generation Linux Sound API." diff --git a/projects/ROCKNIX/packages/audio/alsa-lib/patches/001-silence-underruns.patch b/projects/ROCKNIX/packages/audio/alsa-lib/patches/001-silence-underruns.patch index bf4253550c2..47e635ae522 100644 --- a/projects/ROCKNIX/packages/audio/alsa-lib/patches/001-silence-underruns.patch +++ b/projects/ROCKNIX/packages/audio/alsa-lib/patches/001-silence-underruns.patch @@ -1,14 +1,20 @@ -diff -rupN alsa-lib-1.2.8.orig/src/pcm/pcm.c alsa-lib-1.2.8/src/pcm/pcm.c ---- alsa-lib-1.2.8.orig/src/pcm/pcm.c 2023-02-08 15:16:54.463152310 -0500 -+++ alsa-lib-1.2.8/src/pcm/pcm.c 2023-02-08 15:17:08.347091741 -0500 -@@ -8566,8 +8566,8 @@ int snd_pcm_recover(snd_pcm_t *pcm, int - s = "underrun"; - else - s = "overrun"; -- if (!silent) -- SNDERR("%s occurred", s); -+ //if (!silent) -+ // SNDERR("%s occurred", s); - err = snd_pcm_prepare(pcm); - if (err < 0) { - SNDERR("cannot recovery from %s, prepare failed: %s", s, snd_strerror(err)); +Subject: [PATCH] pcm: log a recovered xrun at debug priority + +snd_pcm_recover() prepares the stream and returns success, so the xrun +is handled rather than fatal. Reporting it at error priority floods the +journal on handhelds and cannot be filtered: snd_lib_log_filter() raises +any level below SND_LOG_ERROR back up to it. At debug priority the +message is off by default and still reachable with LIBASOUND_DEBUG. + +diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c +--- a/src/pcm/pcm.c ++++ b/src/pcm/pcm.c +@@ -8784,7 +8784,7 @@ + else + s = "overrun"; + if (!silent) +- snd_error(PCM, "%s occurred", s); ++ snd_debug(PCM, "%s occurred", s); + err = snd_pcm_prepare(pcm); + if (err < 0) { + snd_error(PCM, "cannot recovery from %s, prepare failed: %s", s, snd_strerror(err)); diff --git a/projects/ROCKNIX/packages/audio/alsa-lib/patches/SM8250/0001-Enabled-extended-namehints-in-alsa.conf.patch b/projects/ROCKNIX/packages/audio/alsa-lib/patches/SM8250/0001-Enabled-extended-namehints-in-alsa.conf.patch index aeba6d016f8..c54b4c4d5db 100644 --- a/projects/ROCKNIX/packages/audio/alsa-lib/patches/SM8250/0001-Enabled-extended-namehints-in-alsa.conf.patch +++ b/projects/ROCKNIX/packages/audio/alsa-lib/patches/SM8250/0001-Enabled-extended-namehints-in-alsa.conf.patch @@ -1,17 +1,9 @@ -From 80965d8afd3241017b7dde8dcbd56ab2fd879973 Mon Sep 17 00:00:00 2001 -From: Elimar Riesebieter -Date: Wed, 11 Jan 2017 16:16:14 +0100 Subject: [PATCH] Enabled extended namehints in alsa.conf ---- - src/conf/alsa.conf | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -Index: alsa-lib/src/conf/alsa.conf -=================================================================== ---- alsa-lib.orig/src/conf/alsa.conf -+++ alsa-lib/src/conf/alsa.conf -@@ -53,11 +53,11 @@ cards.@hooks [ +diff --git a/src/conf/alsa.conf b/src/conf/alsa.conf +--- a/src/conf/alsa.conf ++++ b/src/conf/alsa.conf +@@ -96,11 +96,11 @@ # # show all name hints also for definitions without hint {} section diff --git a/projects/ROCKNIX/packages/audio/alsa-lib/patches/SM8550/0001-Enabled-extended-namehints-in-alsa.conf.patch b/projects/ROCKNIX/packages/audio/alsa-lib/patches/SM8550/0001-Enabled-extended-namehints-in-alsa.conf.patch index aeba6d016f8..c54b4c4d5db 100644 --- a/projects/ROCKNIX/packages/audio/alsa-lib/patches/SM8550/0001-Enabled-extended-namehints-in-alsa.conf.patch +++ b/projects/ROCKNIX/packages/audio/alsa-lib/patches/SM8550/0001-Enabled-extended-namehints-in-alsa.conf.patch @@ -1,17 +1,9 @@ -From 80965d8afd3241017b7dde8dcbd56ab2fd879973 Mon Sep 17 00:00:00 2001 -From: Elimar Riesebieter -Date: Wed, 11 Jan 2017 16:16:14 +0100 Subject: [PATCH] Enabled extended namehints in alsa.conf ---- - src/conf/alsa.conf | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -Index: alsa-lib/src/conf/alsa.conf -=================================================================== ---- alsa-lib.orig/src/conf/alsa.conf -+++ alsa-lib/src/conf/alsa.conf -@@ -53,11 +53,11 @@ cards.@hooks [ +diff --git a/src/conf/alsa.conf b/src/conf/alsa.conf +--- a/src/conf/alsa.conf ++++ b/src/conf/alsa.conf +@@ -96,11 +96,11 @@ # # show all name hints also for definitions without hint {} section diff --git a/projects/ROCKNIX/packages/audio/alsa-lib/patches/alsa-lib-asound.conf_configdir.patch b/projects/ROCKNIX/packages/audio/alsa-lib/patches/alsa-lib-asound.conf_configdir.patch index efe2f1ae7c7..ccbd671ed22 100644 --- a/projects/ROCKNIX/packages/audio/alsa-lib/patches/alsa-lib-asound.conf_configdir.patch +++ b/projects/ROCKNIX/packages/audio/alsa-lib/patches/alsa-lib-asound.conf_configdir.patch @@ -1,8 +1,12 @@ +Subject: [PATCH] conf: add /run and /storage as config locations + +/storage is the writable data partition, /run is where generated +configuration lands. Replaces ~/.asoundrc, which has no meaning here. + diff --git a/src/conf/alsa.conf b/src/conf/alsa.conf -index a04173a0..1f13fd84 100644 --- a/src/conf/alsa.conf +++ b/src/conf/alsa.conf -@@ -11,7 +11,8 @@ +@@ -12,7 +12,8 @@ "/usr/etc/alsa/conf.d" "/etc/alsa/conf.d" "/etc/asound.conf|||/usr/etc/asound.conf" diff --git a/projects/ROCKNIX/packages/audio/alsa-ucm-conf/package.mk b/projects/ROCKNIX/packages/audio/alsa-ucm-conf/package.mk index 8f571a1dcc3..9cce24799e1 100644 --- a/projects/ROCKNIX/packages/audio/alsa-ucm-conf/package.mk +++ b/projects/ROCKNIX/packages/audio/alsa-ucm-conf/package.mk @@ -2,9 +2,10 @@ # Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv) PKG_NAME="alsa-ucm-conf" -PKG_VERSION="1.2.13" -PKG_LICENSE="BSD-3c" -PKG_SITE="http://www.alsa-project.org/" +PKG_VERSION="1.2.16.1" +PKG_SHA256="cf3d1c07e089a83c4ece2c20f05dd6a8aab7fcd108768c38811386880575492b" +PKG_LICENSE="BSD-3-Clause" +PKG_SITE="https://www.alsa-project.org/" PKG_URL="https://www.alsa-project.org/files/pub/lib/alsa-ucm-conf-${PKG_VERSION}.tar.bz2" PKG_LONGDESC="ALSA Use Case Manager configuration (and topologies)" PKG_TOOLCHAIN="manual" diff --git a/projects/ROCKNIX/packages/audio/alsa-ucm-conf/patches/H700/0002_Add-Allwinner-H616-configuration.patch b/projects/ROCKNIX/packages/audio/alsa-ucm-conf/patches/H700/0002_Add-Allwinner-H616-configuration.patch deleted file mode 100644 index f6b824464ee..00000000000 --- a/projects/ROCKNIX/packages/audio/alsa-ucm-conf/patches/H700/0002_Add-Allwinner-H616-configuration.patch +++ /dev/null @@ -1,85 +0,0 @@ -From eccc3536e12a86434ced1529fcad5bbbb280ffeb Mon Sep 17 00:00:00 2001 -From: Ryan Walklin -Date: Sat, 21 Dec 2024 23:01:14 +1300 -Subject: [PATCH] sun4i-codec: add routing for headphones and internal speaker - -The sun4i-codec kernel driver covers a large number of Allwinner SoCs. -The H616 codec has a single line-out route, which is used in concert -with a Toshiba mux chip to send audio to either an internal speaker or -headphone jack on a number of Anbernic handheld gaming devices. - -Add a UCM configuration to allow enabling/disabling the speaker amp -depending on whether headphones are in use or not. - -Signed-off-by: Ryan Walklin ---- - ucm2/Allwinner/sun4i-h616/HiFi.conf | 35 +++++++++++++++++++ - ucm2/conf.d/sun4i-codec/h616-audio-codec.conf | 8 +++++ - 2 files changed, 43 insertions(+) - create mode 100644 ucm2/Allwinner/sun4i-h616/HiFi.conf - create mode 100644 ucm2/conf.d/sun4i-codec/h616-audio-codec.conf - -diff --git a/ucm2/Allwinner/sun4i-h616/HiFi.conf b/ucm2/Allwinner/sun4i-h616/HiFi.conf -new file mode 100644 -index 00000000..2cb9a31f ---- /dev/null -+++ b/ucm2/Allwinner/sun4i-h616/HiFi.conf -@@ -0,0 +1,40 @@ -+SectionDevice."Speaker" { -+ Comment "Internal Speaker" -+ -+ EnableSequence [ -+ cset "name='DAC Playback Volume' 63" -+ cset "name='Speaker Switch' on" -+ ] -+ -+ Value { -+ PlaybackMixerElem "Line Out" -+ PlaybackPCM "hw:${CardId},0" -+ } -+ -+ DisableSequence [ -+ cset "name='Speaker Switch' off" -+ ] -+ -+ ConflictingDevice [ -+ "Headphones" -+ ] -+} -+ -+ -+SectionDevice."Headphones" { -+ Comment "Headphones" -+ -+ EnableSequence [ -+ cset "name='DAC Playback Volume' 63" -+ ] -+ -+ Value { -+ PlaybackMixerElem "Line Out" -+ PlaybackPCM "hw:${CardId},0" -+ JackControl "Headphone Jack" -+ } -+ -+ ConflictingDevice [ -+ "Speaker" -+ ] -+} -diff --git a/ucm2/conf.d/sun4i-codec/h616-audio-codec.conf b/ucm2/conf.d/sun4i-codec/h616-audio-codec.conf -new file mode 100644 -index 00000000..240f41ab ---- /dev/null -+++ b/ucm2/conf.d/sun4i-codec/h616-audio-codec.conf -@@ -0,0 +1,12 @@ -+# UCM for Allwinner H616 Codec -+ -+Syntax 3 -+ -+SectionUseCase."HiFi" { -+ File "/Allwinner/sun4i-h616/HiFi.conf" -+ Comment "Play HiFi quality Music" -+} -+ -+FixedBootSequence [ -+ cset "name='DAC Playback Switch' on" -+] diff --git a/projects/ROCKNIX/packages/audio/alsa-ucm-conf/patches/H700/0002_sun4i-h616-restore-DAC-gain-and-boot-switch.patch b/projects/ROCKNIX/packages/audio/alsa-ucm-conf/patches/H700/0002_sun4i-h616-restore-DAC-gain-and-boot-switch.patch new file mode 100644 index 00000000000..c6d7978aba9 --- /dev/null +++ b/projects/ROCKNIX/packages/audio/alsa-ucm-conf/patches/H700/0002_sun4i-h616-restore-DAC-gain-and-boot-switch.patch @@ -0,0 +1,41 @@ +Subject: [PATCH] sun4i-h616: set DAC gain and enable the DAC at boot + +1.2.16 carries the H616 routing upstream, but without the two settings +the Anbernic handhelds need. sun4i-codec comes up with DAC Playback +Switch off and the digital gain at its reset value, so both outputs are +silent until they are set; the switch goes in FixedBootSequence because +it must survive a verb change. + +diff --git a/ucm2/Allwinner/sun4i-h616/HiFi.conf b/ucm2/Allwinner/sun4i-h616/HiFi.conf +--- a/ucm2/Allwinner/sun4i-h616/HiFi.conf ++++ b/ucm2/Allwinner/sun4i-h616/HiFi.conf +@@ -2,6 +2,7 @@ + Comment "Internal Speaker" + + EnableSequence [ ++ cset "name='DAC Playback Volume' 63" + cset "name='Speaker Switch' on" + ] + +@@ -23,6 +24,10 @@ + SectionDevice."Headphones" { + Comment "Headphones" + ++ EnableSequence [ ++ cset "name='DAC Playback Volume' 63" ++ ] ++ + Value { + PlaybackMixerElem "Line Out" + PlaybackPCM "hw:${CardId},0" +diff --git a/ucm2/Allwinner/sun4i-h616/h616-audio-codec.conf b/ucm2/Allwinner/sun4i-h616/h616-audio-codec.conf +--- a/ucm2/Allwinner/sun4i-h616/h616-audio-codec.conf ++++ b/ucm2/Allwinner/sun4i-h616/h616-audio-codec.conf +@@ -6,3 +6,7 @@ + File "/Allwinner/sun4i-h616/HiFi.conf" + Comment "Play HiFi quality Music" + } ++ ++FixedBootSequence [ ++ cset "name='DAC Playback Switch' on" ++] diff --git a/projects/ROCKNIX/packages/audio/alsa-utils/package.mk b/projects/ROCKNIX/packages/audio/alsa-utils/package.mk index e576cff4306..9458eea8c22 100644 --- a/projects/ROCKNIX/packages/audio/alsa-utils/package.mk +++ b/projects/ROCKNIX/packages/audio/alsa-utils/package.mk @@ -4,9 +4,10 @@ # Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS) PKG_NAME="alsa-utils" -PKG_VERSION="1.2.14" -PKG_LICENSE="GPL" -PKG_SITE="http://www.alsa-project.org/" +PKG_VERSION="1.2.16" +PKG_SHA256="092399d5e8749a1d5e188e393157521cec4b75693b60ebb79bbce728cff2232c" +PKG_LICENSE="GPL-2.0-or-later" +PKG_SITE="https://www.alsa-project.org/" PKG_URL="https://www.alsa-project.org/files/pub/utils/alsa-utils-${PKG_VERSION}.tar.bz2" PKG_DEPENDS_TARGET="toolchain alsa-lib ncurses systemd alsa-ucm-conf" PKG_LONGDESC="This package includes the utilities for ALSA, like alsamixer, aplay, arecord, alsactl, iecset and speaker-test." diff --git a/projects/ROCKNIX/packages/audio/libfreeaptx/package.mk b/projects/ROCKNIX/packages/audio/libfreeaptx/package.mk deleted file mode 100644 index 73664fc8e6f..00000000000 --- a/projects/ROCKNIX/packages/audio/libfreeaptx/package.mk +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Copyright (C) 2024-present ROCKNIX (https://github.com/ROCKNIX) - -. ${ROOT}/packages/audio/libfreeaptx/package.mk - -PKG_SHA256="5ab5ebddf3f2eb7ce47a505b87460b00fc1ede99c70010796d3575ab31ea80bf" diff --git a/projects/ROCKNIX/packages/audio/libsndfile/package.mk b/projects/ROCKNIX/packages/audio/libsndfile/package.mk index 4fd0f4aeae3..50451a63eb4 100644 --- a/projects/ROCKNIX/packages/audio/libsndfile/package.mk +++ b/projects/ROCKNIX/packages/audio/libsndfile/package.mk @@ -5,6 +5,7 @@ PKG_NAME="libsndfile" PKG_VERSION="e486f20" +PKG_SHA256="1227bc78df8eece089e6b984ba7c32e74e210f146d2bac1b76bd218baaf35ce5" PKG_LICENSE="LGPL-2.1-or-later" PKG_SITE="https://libsndfile.github.io/libsndfile/" PKG_URL="https://github.com/libsndfile/libsndfile/archive/${PKG_VERSION}.tar.gz" diff --git a/projects/ROCKNIX/packages/audio/opus/package.mk b/projects/ROCKNIX/packages/audio/opus/package.mk deleted file mode 100644 index d59ed4da6ab..00000000000 --- a/projects/ROCKNIX/packages/audio/opus/package.mk +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Copyright (C) 2024-present ROCKNIX (https://github.com/ROCKNIX) - -. ${ROOT}/packages/audio/opus/package.mk - -PKG_VERSION="1.5.2" -PKG_SHA256="65c1d2f78b9f2fb20082c38cbe47c951ad5839345876e46941612ee87f9a7ce1" -PKG_URL="https://ftp.osuosl.org/pub/xiph/releases/opus/${PKG_NAME}-${PKG_VERSION}.tar.gz" diff --git a/projects/ROCKNIX/packages/audio/pipewire/config/pipewire-pulse-dbus.conf b/projects/ROCKNIX/packages/audio/pipewire/config/pipewire-pulse-dbus.conf new file mode 100644 index 00000000000..99f86b22a20 --- /dev/null +++ b/projects/ROCKNIX/packages/audio/pipewire/config/pipewire-pulse-dbus.conf @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/projects/ROCKNIX/packages/audio/pipewire/package.mk b/projects/ROCKNIX/packages/audio/pipewire/package.mk index b272aa09677..046f6ba2eb0 100644 --- a/projects/ROCKNIX/packages/audio/pipewire/package.mk +++ b/projects/ROCKNIX/packages/audio/pipewire/package.mk @@ -2,11 +2,12 @@ # Copyright (C) 2021-present Team LibreELEC (https://libreelec.tv) PKG_NAME="pipewire" -PKG_VERSION="1.2.6" -PKG_LICENSE="LGPL" +PKG_VERSION="1.6.8" +PKG_SHA256="8181172a1d95131f6af8bbc0b98f90b2a33349b042b84c3ce57dd5d11348cc58" +PKG_LICENSE="MIT" PKG_SITE="https://pipewire.org" PKG_URL="https://github.com/PipeWire/pipewire/archive/${PKG_VERSION}.tar.gz" -PKG_DEPENDS_TARGET="toolchain libpthread-stubs dbus ncurses alsa-lib pulseaudio systemd libsndfile libusb" +PKG_DEPENDS_TARGET="toolchain libpthread-stubs dbus glib ncurses alsa-lib pulseaudio systemd libsndfile libusb" PKG_LONGDESC="PipeWire is a server and user space API to deal with multimedia pipeline" PKG_PATCH_DIRS+=" ${DEVICE}" @@ -27,9 +28,9 @@ fi if [ "${VULKAN_SUPPORT}" = "yes" ]; then PKG_DEPENDS_TARGET+=" vulkan-loader vulkan-headers" - PKG_PIPEWIRE_VULKAN+="-Dvulkan=enabled \ - -Dx11=disabled \ - -Dx11-xfixes=disabled" + PKG_PIPEWIRE_VULKAN="-Dvulkan=enabled" +else + PKG_PIPEWIRE_VULKAN="-Dvulkan=disabled" fi PKG_MESON_OPTS_TARGET="-Ddocs=disabled \ @@ -39,7 +40,7 @@ PKG_MESON_OPTS_TARGET="-Ddocs=disabled \ -Dinstalled_tests=disabled \ -Dgstreamer=disabled \ -Dgstreamer-device-provider=disabled \ - -Dsystemd=enabled \ + -Dlibsystemd=enabled \ -Dsystemd-system-service=enabled \ -Dsystemd-user-service=disabled \ -Dpipewire-alsa=enabled \ @@ -65,6 +66,8 @@ PKG_MESON_OPTS_TARGET="-Ddocs=disabled \ -Dvideotestsrc=disabled \ -Dvolume=enabled \ ${PKG_PIPEWIRE_VULKAN} \ + -Dx11=disabled \ + -Dx11-xfixes=disabled \ -Dpw-cat=enabled \ -Dudev=enabled \ -Dudevrulesdir=/usr/lib/udev/rules.d \ @@ -81,11 +84,64 @@ PKG_MESON_OPTS_TARGET="-Ddocs=disabled \ -Dlibcanberra=disabled \ -Dlegacy-rtkit=false" +# Latency floors. The devices below cannot keep up with the stock 32-frame +# quantum, so they were carrying near-identical copies of the same two +# patches against upstream's shipped configuration; both files support +# drop-ins, which is where per-device policy belongs. +case ${DEVICE} in + SM6115|SM8550|SM8650|SM8750) + PKG_PIPEWIRE_QUANTUM="960" + PKG_PIPEWIRE_PULSE_QUANTUM="960" + ;; + SM8250) + PKG_PIPEWIRE_PULSE_QUANTUM="1024" + # was a patch setting rt.prio in the module-rt args; module-rt defaults + # rt.prio to RTPRIO_CLIENT, so the build option reaches the same place. + PKG_MESON_OPTS_TARGET+=" -Drtprio-client=99" + ;; +esac + pre_configure_target() { export TARGET_CFLAGS="${TARGET_CFLAGS} -Wno-error=float-conversion" export TARGET_LDFLAGS="${TARGET_LDFLAGS} -lncursesw -ltinfow" } +post_makeinstall_target() { + # 1.6 started installing pipewire-pulse.service and pipewire-pulse.socket. + # scripts/install copies system.d/ first and then untars the package on top, + # so upstream's units would win and pipewire-pulse would come up as the + # pipewire user with no XDG_RUNTIME_DIR or HOME. Install ours from here, + # where they are part of the package and cannot be overwritten. + cp ${PKG_DIR}/system.d/pipewire-pulse.service ${PKG_DIR}/system.d/pipewire-pulse.socket \ + ${INSTALL}/usr/lib/systemd/system + + # pipewire-pulse (root, system bus) may own the PulseAudio discovery name + mkdir -p ${INSTALL}/usr/share/dbus-1/system.d + cp ${PKG_DIR}/config/pipewire-pulse-dbus.conf ${INSTALL}/usr/share/dbus-1/system.d + + # Latency floors, per device. Drop-ins are merged key by key onto the + # shipped configuration, so only the values we care about are named. + if [ -n "${PKG_PIPEWIRE_QUANTUM}" ]; then + mkdir -p ${INSTALL}/usr/share/pipewire/pipewire.conf.d + cat >${INSTALL}/usr/share/pipewire/pipewire.conf.d/50-rocknix-latency.conf <${INSTALL}/usr/share/pipewire/pipewire-pulse.conf.d/50-rocknix-latency.conf <; unpinned, they roll with the channel on every build and + # header drift breaks the generated thunks (nixos-unstable 2026-08-05) + export NIX_PATH="nixpkgs=https://github.com/NixOS/nixpkgs/archive/ee67c8504dafc87ba63e862d76558384d10e1e8c.tar.gz" mkdir -p "${PKG_BUILD}/.${TARGET_NAME}" cd "${PKG_BUILD}/.${TARGET_NAME}" @@ -86,6 +90,18 @@ make_target() { ;; esac + # thunkgen host-parse system headers. --sysroot instead of -isystem so the + # guest parse's own --sysroot (appended later, last one wins) overrides it; + # libstdc++ passed explicitly since it is not discoverable under a sysroot. + local cxxdir + cxxdir=$(ls -d "${TOOLCHAIN}/${TARGET_NAME}/include/c++/"* | sort -V | tail -n1) + # --target pins the host parse to the device triple: on an aarch64 build + # host clang's default target already matches, but on an x86_64 build host + # the host parse otherwise reads the aarch64 sysroot as x86_64 - SVE types + # in bits/math-vector.h are unknown and every host_layout is generated with + # the wrong ABI, which the .inl compiles then reject. + export THUNKGEN_EXTRA_FLAGS="--target=${TARGET_NAME} --sysroot ${SYSROOT_PREFIX} -isystem ${cxxdir} -isystem ${cxxdir}/${TARGET_NAME}" + local -a tgt_opts=( -G Ninja -S "${PKG_BUILD}" @@ -107,6 +123,10 @@ make_target() { -DTUNE_CPU="${TUNE_CPU}" ) cmake "${tgt_opts[@]}" + # aarch64 build host: x86_64 thunk descriptor needs the cross prefix, not bare clang + if [ "$(uname -m)" = "aarch64" ]; then + sed -i 's#/bin/clang)#/bin/x86_64-unknown-linux-gnu-clang)#; s#/bin/clang++)#/bin/x86_64-unknown-linux-gnu-clang++)#' "${PKG_BUILD}/Data/nix/LibraryForwarding/shell.nix" + fi bash "${PKG_BUILD}/Data/nix/cmake_enable_libfwd.sh" ninja } diff --git a/projects/ROCKNIX/packages/compat/fex-emu/patches/0003-hostlibs-use-sysroot-deps.patch b/projects/ROCKNIX/packages/compat/fex-emu/patches/0003-hostlibs-use-sysroot-deps.patch index 97278b01a64..e514a38854e 100644 --- a/projects/ROCKNIX/packages/compat/fex-emu/patches/0003-hostlibs-use-sysroot-deps.patch +++ b/projects/ROCKNIX/packages/compat/fex-emu/patches/0003-hostlibs-use-sysroot-deps.patch @@ -1,56 +1,81 @@ +From: ROCKNIX +Subject: [PATCH] ThunkLibs: keep foreign-arch sysroot out of interface parses + +thunkgen parses each interface twice: once for the host ABI and once +for the guest (x86) ABI via --sysroot . Include directories +attached to the *-deps targets reach BOTH parses, and -isystem always +outranks the sysroot's standard directories. On sysrooted cross builds +pkg-config returns the sysroot-prefixed form of /usr/include, which the +existing REMOVE_ITEM guard cannot catch, so the x86 guest parses read +the host architecture's glibc. Two symptom classes on aarch64 hosts: +bits/math-vector.h SVE typedefs are unparseable under an x86 target, +and bits/wordsize.h hardcodes __WORDSIZE 64, which under -m32 collapses +uint64_t to 32 bits and corrupts every generated guest layout that +contains one (Vulkan non-dispatchable handles, VkDeviceSize, ...). + +Extend the guard in both helper copies (HostLibs and GuestLibs, keyed +on CMAKE_SYSROOT and on pkg-config's own sysroot) and re-add only the +arch-neutral API subdirectories (drm, wayland) on the host side. The +standard library reaches the host parse via THUNKGEN_EXTRA_FLAGS +"--sysroot ..." from the build recipe instead; the guest parse's later +--sysroot overrides it, so each parse sees its own arch's headers. + diff --git a/ThunkLibs/HostLibs/CMakeLists.txt b/ThunkLibs/HostLibs/CMakeLists.txt -index a526c72ff..346eb71d4 100644 --- a/ThunkLibs/HostLibs/CMakeLists.txt +++ b/ThunkLibs/HostLibs/CMakeLists.txt -@@ -127,6 +127,7 @@ foreach(GUEST_BITNESS IN LISTS BITNESS_LIST) - - generate(libasound ${CMAKE_CURRENT_SOURCE_DIR}/../libasound/libasound_interface.cpp ${GUEST_BITNESS}) - target_include_directories_from_pkgconfig(libasound-${GUEST_BITNESS}-deps alsa) -+ target_include_directories(libasound-${GUEST_BITNESS}-deps INTERFACE ${CMAKE_SYSROOT}/usr/include) - add_host_lib(asound ${GUEST_BITNESS}) - - # disabled for now, headers are platform specific -@@ -137,6 +138,11 @@ foreach(GUEST_BITNESS IN LISTS BITNESS_LIST) +@@ -13,6 +13,14 @@ + pkg_check_modules(PKG QUIET ${pkg}) + if (PKG_FOUND) + list(REMOVE_ITEM PKG_INCLUDE_DIRS /usr/include) ++ # Same rule for sysrooted cross builds: the guest parse must get the ++ # standard library from its own --sysroot, not the host architecture's ++ if (CMAKE_SYSROOT) ++ list(REMOVE_ITEM PKG_INCLUDE_DIRS ${CMAKE_SYSROOT}/usr/include) ++ endif() ++ if (DEFINED ENV{PKG_CONFIG_SYSROOT_DIR}) ++ list(REMOVE_ITEM PKG_INCLUDE_DIRS "$ENV{PKG_CONFIG_SYSROOT_DIR}/usr/include") ++ endif() + target_include_directories(${target} INTERFACE ${PKG_INCLUDE_DIRS}) + elseif (ARGN) + target_include_directories(${target} INTERFACE ${ARGN}) +@@ -137,6 +145,12 @@ generate(libdrm ${CMAKE_CURRENT_SOURCE_DIR}/../libdrm/libdrm_interface.cpp ${GUEST_BITNESS}) target_include_directories_from_pkgconfig(libdrm-${GUEST_BITNESS}-deps libdrm /usr/include/drm /usr/include/libdrm) -+ target_include_directories(libdrm-${GUEST_BITNESS}-deps INTERFACE -+ ${CMAKE_SYSROOT}/usr/include -+ ${CMAKE_SYSROOT}/usr/include/drm -+ ${CMAKE_SYSROOT}/usr/include/libdrm -+ ) ++ if (CMAKE_SYSROOT) ++ target_include_directories(libdrm-${GUEST_BITNESS}-deps INTERFACE ++ ${CMAKE_SYSROOT}/usr/include/drm ++ ${CMAKE_SYSROOT}/usr/include/libdrm ++ ) ++ endif() add_host_lib(drm ${GUEST_BITNESS}) endforeach() -@@ -148,21 +154,30 @@ foreach(GUEST_BITNESS IN LISTS BITNESS_LIST) - endif() - - generate(libvulkan ${CMAKE_CURRENT_SOURCE_DIR}/../libvulkan/libvulkan_interface.cpp ${GUEST_BITNESS}) -- target_include_directories(libvulkan-${GUEST_BITNESS}-deps INTERFACE ${FEX_PROJECT_SOURCE_DIR}/External/Vulkan-Headers/include/) -+ target_include_directories(libvulkan-${GUEST_BITNESS}-deps INTERFACE -+ ${FEX_PROJECT_SOURCE_DIR}/External/Vulkan-Headers/include/ -+ ${CMAKE_SYSROOT}/usr/include -+ ) - target_include_directories_from_pkgconfig(libvulkan-${GUEST_BITNESS}-deps "xcb;x11;xrandr;xrender") - add_host_lib(vulkan ${GUEST_BITNESS}) - +@@ -155,6 +169,9 @@ generate(libwayland-client ${CMAKE_CURRENT_SOURCE_DIR}/../libwayland-client/libwayland-client_interface.cpp ${GUEST_BITNESS}) add_host_lib(wayland-client ${GUEST_BITNESS}) target_include_directories_from_pkgconfig(libwayland-client-${GUEST_BITNESS}-deps wayland-client /usr/include/wayland) -+ target_include_directories(libwayland-client-${GUEST_BITNESS}-deps INTERFACE -+ ${CMAKE_SYSROOT}/usr/include -+ ${CMAKE_SYSROOT}/usr/include/wayland -+ ) ++ if (CMAKE_SYSROOT) ++ target_include_directories(libwayland-client-${GUEST_BITNESS}-deps INTERFACE ${CMAKE_SYSROOT}/usr/include/wayland) ++ endif() generate(libEGL ${CMAKE_CURRENT_SOURCE_DIR}/../libEGL/libEGL_interface.cpp ${GUEST_BITNESS}) target_include_directories_from_pkgconfig(libEGL-${GUEST_BITNESS}-deps egl) -+ target_include_directories(libEGL-${GUEST_BITNESS}-deps INTERFACE ${CMAKE_SYSROOT}/usr/include) - add_host_lib(EGL ${GUEST_BITNESS}) - - generate(libGL ${CMAKE_CURRENT_SOURCE_DIR}/../libGL/libGL_interface.cpp ${GUEST_BITNESS}) - target_include_directories_from_pkgconfig(libGL-${GUEST_BITNESS}-deps gl) - target_include_directories_from_pkgconfig(libGL-${GUEST_BITNESS}-deps "xcb;x11;xrandr;xrender") -+ target_include_directories(libGL-${GUEST_BITNESS}-deps INTERFACE ${CMAKE_SYSROOT}/usr/include) - add_host_lib(GL ${GUEST_BITNESS}) - - find_package(OpenGL REQUIRED) +diff --git a/ThunkLibs/GuestLibs/CMakeLists.txt b/ThunkLibs/GuestLibs/CMakeLists.txt +--- a/ThunkLibs/GuestLibs/CMakeLists.txt ++++ b/ThunkLibs/GuestLibs/CMakeLists.txt +@@ -12,6 +12,14 @@ + pkg_check_modules(PKG QUIET ${pkg}) + if (PKG_FOUND) + list(REMOVE_ITEM PKG_INCLUDE_DIRS /usr/include) ++ # Same rule for sysrooted cross builds: the guest parse must get the ++ # standard library from its own --sysroot, not the host architecture's ++ if (CMAKE_SYSROOT) ++ list(REMOVE_ITEM PKG_INCLUDE_DIRS ${CMAKE_SYSROOT}/usr/include) ++ endif() ++ if (DEFINED ENV{PKG_CONFIG_SYSROOT_DIR}) ++ list(REMOVE_ITEM PKG_INCLUDE_DIRS "$ENV{PKG_CONFIG_SYSROOT_DIR}/usr/include") ++ endif() + target_include_directories(${target} INTERFACE ${PKG_INCLUDE_DIRS}) + elseif (ARGN) + target_include_directories(${target} INTERFACE ${ARGN}) diff --git a/projects/ROCKNIX/packages/compat/fex-emu/patches/0005-host-thunks-aarch64-char-signed-char.patch b/projects/ROCKNIX/packages/compat/fex-emu/patches/0005-host-thunks-aarch64-char-signed-char.patch deleted file mode 100644 index a1f02bfea6e..00000000000 --- a/projects/ROCKNIX/packages/compat/fex-emu/patches/0005-host-thunks-aarch64-char-signed-char.patch +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/ThunkLibs/include/common/Host.h b/ThunkLibs/include/common/Host.h ---- a/ThunkLibs/include/common/Host.h -+++ b/ThunkLibs/include/common/Host.h -@@ -446,8 +446,22 @@ struct host_to_guest_convertible { - operator guest_layout() const requires (std::is_same_v) - { - return (guest_layout)reinterpret_cast&>(*this); - } - -+ operator guest_layout() const requires (std::is_same_v) -+ { -+ guest_layout ret; -+ ret.data = reinterpret_cast(from.data); -+ return ret; -+ } -+ -+ operator guest_layout() const requires (std::is_same_v) -+ { -+ guest_layout ret; -+ ret.data = reinterpret_cast(from.data); -+ return ret; -+ } -+ - // Make guest_layout of "wchar_t" and "uint32_t" interoperable - operator guest_layout() const requires (std::is_same_v) - { diff --git a/projects/ROCKNIX/packages/compat/lib32/package.mk b/projects/ROCKNIX/packages/compat/lib32/package.mk index e7deea64e72..2cf47b28d30 100644 --- a/projects/ROCKNIX/packages/compat/lib32/package.mk +++ b/projects/ROCKNIX/packages/compat/lib32/package.mk @@ -19,7 +19,7 @@ makeinstall_target() { esac cd ${PKG_BUILD} - LIBROOT="${ROOT}/build.${DISTRO}-${DEVICE}.${LIBARCH}/image/system/" + LIBROOT="${BUILD_ROOT}/build.${DISTRO}-${DEVICE}.${LIBARCH}/image/system/" mkdir -p ${INSTALL}/usr/lib32 rsync -al ${LIBROOT}/usr/lib/* ${INSTALL}/usr/lib32 >/dev/null 2>&1 rsync -al ${LIBROOT}/usr/lib32/* ${INSTALL}/usr/lib32 >/dev/null 2>&1 diff --git a/projects/ROCKNIX/packages/compress/libzip/package.mk b/projects/ROCKNIX/packages/compress/libzip/package.mk index 7fe44ce691b..a59fd6be084 100644 --- a/projects/ROCKNIX/packages/compress/libzip/package.mk +++ b/projects/ROCKNIX/packages/compress/libzip/package.mk @@ -3,9 +3,10 @@ # Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv) PKG_NAME="libzip" -PKG_VERSION="1.11.1" +PKG_VERSION="1.11.4" +PKG_SHA256="8a247f57d1e3e6f6d11413b12a6f28a9d388de110adc0ec608d893180ed7097b" PKG_LICENSE="GPL" PKG_SITE="https://libzip.org/download" -PKG_URL="${PKG_SITE}/${PKG_NAME}-${PKG_VERSION}.tar.xz" +PKG_URL="https://libzip.org/download/${PKG_NAME}-${PKG_VERSION}.tar.xz" PKG_DEPENDS_TARGET="toolchain zlib gnutls openssl" PKG_LONGDESC="A C library for reading, creating, and modifying zip archives." diff --git a/projects/ROCKNIX/packages/compress/xz/package.mk b/projects/ROCKNIX/packages/compress/xz/package.mk index f156fe0f747..92c418d581f 100644 --- a/projects/ROCKNIX/packages/compress/xz/package.mk +++ b/projects/ROCKNIX/packages/compress/xz/package.mk @@ -4,8 +4,8 @@ # Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS) PKG_NAME="xz" -PKG_VERSION="5.8.1" -PKG_SHA256="0b54f79df85912504de0b14aec7971e3f964491af1812d83447005807513cd9e" +PKG_VERSION="5.8.3" +PKG_SHA256="fff1ffcf2b0da84d308a14de513a1aa23d4e9aa3464d17e64b9714bfdd0bbfb6" PKG_LICENSE="GPL" PKG_SITE="https://tukaani.org/xz/" PKG_URL="https://github.com/tukaani-project/xz/releases/download/v${PKG_VERSION}/${PKG_NAME}-${PKG_VERSION}.tar.xz" diff --git a/projects/ROCKNIX/packages/debug/strace/package.mk b/projects/ROCKNIX/packages/debug/strace/package.mk deleted file mode 100644 index e6a57bef007..00000000000 --- a/projects/ROCKNIX/packages/debug/strace/package.mk +++ /dev/null @@ -1,30 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv) - -PKG_NAME="strace" -PKG_LICENSE="BSD" -PKG_SITE="https://strace.io/" -PKG_DEPENDS_TARGET="toolchain" -PKG_LONGDESC="strace is a diagnostic, debugging and instructional userspace utility" -PKG_TOOLCHAIN="autotools" -PKG_BUILD_FLAGS="-cfg-libs" - -case "${DEVICE}" in - SM8650|SM8750|SM8550|SM8250|H700) - PKG_VERSION="6.19" - PKG_SHA256="e076c851eec0972486ec842164fdc54547f9d17abd3d1449de8b120f5d299143" - ;; - RK3399|S922X|RK3566|SM6115) - PKG_VERSION="6.18" - PKG_SHA256="0ad5dcba973a69e779650ef1cb335b12ee60716fc7326609895bd33e6d2a7325" - ;; - *) - PKG_VERSION="6.17" - PKG_SHA256="0a7c7bedc7efc076f3242a0310af2ae63c292a36dd4236f079e88a93e98cb9c0" - ;; -esac -PKG_URL="https://strace.io/files/${PKG_VERSION}/strace-${PKG_VERSION}.tar.xz" - -if [ "${TARGET_ARCH}" = x86_64 -o "${TARGET_ARCH}" = "aarch64" ]; then - PKG_CONFIGURE_OPTS_TARGET="--enable-mpers=no" -fi diff --git a/projects/ROCKNIX/packages/debug/strace/patches/strace-0001-autoreconf.patch b/projects/ROCKNIX/packages/debug/strace/patches/strace-0001-autoreconf.patch deleted file mode 100644 index 41dd01be4b3..00000000000 --- a/projects/ROCKNIX/packages/debug/strace/patches/strace-0001-autoreconf.patch +++ /dev/null @@ -1,17 +0,0 @@ -diff --git a/configure.ac b/configure.ac -index 4e7bc2a89..3b762c94c 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -11,11 +11,7 @@ - # SPDX-License-Identifier: LGPL-2.1-or-later - - AC_PREREQ(2.57) --AC_INIT([strace], -- st_esyscmd_s([./build-aux/git-version-gen .tarball-version]), -- [strace-devel@lists.strace.io], -- [strace], -- [https://strace.io]) -+AC_INIT([strace],[5.11]) - m4_define([copyright_year], st_esyscmd_s([./build-aux/copyright-year-gen .year])) - m4_define([manpage_date], st_esyscmd_s([./build-aux/file-date-gen doc/strace.1.in])) - AC_COPYRIGHT([Copyright (c) 1999-]copyright_year[ The strace developers.]) diff --git a/projects/ROCKNIX/packages/debug/strace/patches/strace-0002-fix-autoconf-archive.patch b/projects/ROCKNIX/packages/debug/strace/patches/strace-0002-fix-autoconf-archive.patch deleted file mode 100644 index 4e0927da661..00000000000 --- a/projects/ROCKNIX/packages/debug/strace/patches/strace-0002-fix-autoconf-archive.patch +++ /dev/null @@ -1,39 +0,0 @@ -From ba71a5f3778df1bb19ba593f6a5550c01f5349ad Mon Sep 17 00:00:00 2001 -From: MilhouseVH -Date: Tue, 28 Jan 2020 03:17:14 +0000 -Subject: [PATCH] fix API change since autoconf-archive-2019.01.06 - ---- - Makefile.am | 2 +- - Makefile.in | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/Makefile.am b/Makefile.am -index 723460f2e..a6a0f5f9c 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -408,7 +408,7 @@ strace_LDADD += $(libiberty_LIBS) - endif - endif - --@CODE_COVERAGE_RULES@ -+include $(top_srcdir)/aminclude_static.am - CODE_COVERAGE_BRANCH_COVERAGE = 1 - CODE_COVERAGE_GENHTML_OPTIONS = $(CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT) \ - --prefix $(shell cd $(abs_top_srcdir)/.. && pwd || echo .) -diff --git a/Makefile.in b/Makefile.in -index b0ec9f686..9b4b93d8b 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -10351,7 +10351,7 @@ $(top_srcdir)/xlat/xfs_dqblk_flags.h: $(top_srcdir)/xlat/xfs_dqblk_flags.in $(to - $(top_srcdir)/xlat/xfs_quota_flags.h: $(top_srcdir)/xlat/xfs_quota_flags.in $(top_srcdir)/xlat/gen.sh - $(AM_V_GEN)$(top_srcdir)/xlat/gen.sh $< $@ - --@CODE_COVERAGE_RULES@ -+include $(top_srcdir)/aminclude_static.am - - .PHONY: check-valgrind-local - check-valgrind-local: --- -2.7.4 - diff --git a/projects/ROCKNIX/packages/devel/boost/package.mk b/projects/ROCKNIX/packages/devel/boost/package.mk index 8a6c26a17bc..b3d1c9b27c2 100644 --- a/projects/ROCKNIX/packages/devel/boost/package.mk +++ b/projects/ROCKNIX/packages/devel/boost/package.mk @@ -4,9 +4,10 @@ # Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS) PKG_NAME="boost" -PKG_VERSION="1.86.0" -PKG_LICENSE="OSS" -PKG_SITE="http://www.boost.org/" +PKG_VERSION="1.91.0" +PKG_SHA256="de5e6b0e4913395c6bdfa90537febd9028ea4c0735d2cdb0cd9b45d5f51264f5" +PKG_LICENSE="BSL-1.0" +PKG_SITE="https://www.boost.org/" PKG_URL="https://archives.boost.io/release/${PKG_VERSION}/source/${PKG_NAME}_${PKG_VERSION//./_}.tar.bz2" PKG_DEPENDS_HOST="toolchain:host" PKG_DEPENDS_TARGET="toolchain boost:host Python3 zlib bzip2" @@ -60,7 +61,6 @@ makeinstall_target() { --with-random \ --with-regex -sICU_PATH="${SYSROOT_PREFIX}/usr" \ --with-serialization \ - --with-system \ --with-thread \ --with-nowide \ --with-context \ diff --git a/projects/ROCKNIX/packages/devel/glibc/package.mk b/projects/ROCKNIX/packages/devel/glibc/package.mk index 7a345275ecd..7424d8884ba 100644 --- a/projects/ROCKNIX/packages/devel/glibc/package.mk +++ b/projects/ROCKNIX/packages/devel/glibc/package.mk @@ -3,15 +3,19 @@ # Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv) PKG_NAME="glibc" -PKG_VERSION="2.41" -PKG_LICENSE="GPL" +PKG_VERSION="2.44" +PKG_SHA256="37f600f2bef3c5e8300147059568b2a2e40a7ad6ccc65ce942556d49429cc667" +PKG_LICENSE="LGPL-2.1-or-later" PKG_SITE="https://www.gnu.org/software/libc/" PKG_URL="https://ftp.gnu.org/pub/gnu/glibc/${PKG_NAME}-${PKG_VERSION}.tar.xz" +# ROCKNIX: pigz:host added PKG_DEPENDS_TARGET="ccache:host autotools:host linux:host gcc:bootstrap pigz:host Python3:host" PKG_DEPENDS_INIT="glibc" PKG_LONGDESC="The Glibc package contains the main C library." +# ROCKNIX: force bfd, no gold PKG_BUILD_FLAGS="+bfd -gold" +# ROCKNIX: lowest kernel across supported devices (RK3588 runs a 6.1 BSP) case "${DEVICE}" in RK3588) OPT_ENABLE_KERNEL=6.1.0 @@ -21,12 +25,6 @@ case "${DEVICE}" in ;; esac -case ${TARGET_ARCH} in - arm|aarch64) - PKG_PATCH_DIRS="widevine-arm" - ;; -esac - PKG_CONFIGURE_OPTS_TARGET="BASH_SHELL=/bin/sh \ ac_cv_path_PERL=no \ ac_cv_prog_MAKEINFO= \ @@ -48,6 +46,9 @@ PKG_CONFIGURE_OPTS_TARGET="BASH_SHELL=/bin/sh \ --disable-nscd \ --disable-timezone-tools" +# ROCKNIX: new-compiler warning churn must not break the build +PKG_CONFIGURE_OPTS_TARGET+=" --disable-werror" + if build_with_debug; then PKG_CONFIGURE_OPTS_TARGET+=" --enable-debug" else @@ -59,7 +60,10 @@ post_unpack() { } pre_configure_target() { -# Filter out some problematic *FLAGS + # Filter out some problematic *FLAGS + # ROCKNIX: build glibc at -O3 + export CFLAGS=$(echo ${CFLAGS} | sed -e "s|-ffast-math||g") + export CFLAGS=$(echo ${CFLAGS} | sed -e "s|-Ofast|-O3|g") export CFLAGS=$(echo ${CFLAGS} | sed -e "s|-O.|-O3|g") export CFLAGS=$(echo ${CFLAGS} | sed -e "s|-Wunused-but-set-variable||g") @@ -69,6 +73,8 @@ pre_configure_target() { export CFLAGS=$(echo ${CFLAGS} | sed -e "s|${PROJECT_CFLAGS}||g") fi + export LDFLAGS=$(echo ${LDFLAGS} | sed -e "s|-ffast-math||g") + export LDFLAGS=$(echo ${LDFLAGS} | sed -e "s|-Ofast|-O3|g") export LDFLAGS=$(echo ${LDFLAGS} | sed -e "s|-O.|-O3|g") export LDFLAGS=$(echo ${LDFLAGS} | sed -e "s|-Wl,--as-needed||") @@ -107,12 +113,14 @@ post_makeinstall_target() { cp -a ${INSTALL}/usr/share/i18n/locales ${INSTALL}/.noinstall mv ${INSTALL}/usr/share/i18n/charmaps ${INSTALL}/.noinstall + # ROCKNIX: keep all glibc programs (no GLIBC_INCLUDE_BIN cleanup) + safe_remove ${INSTALL}/usr/lib/audit safe_remove ${INSTALL}/usr/lib/glibc safe_remove ${INSTALL}/usr/lib/*.o safe_remove ${INSTALL}/var -# add UTF-8 charmap + # add UTF-8 charmap mkdir -p ${INSTALL}/usr/share/i18n/charmaps cp -PR ${INSTALL}/.noinstall/charmaps/UTF-8.gz ${INSTALL}/usr/share/i18n/charmaps @@ -123,11 +131,12 @@ post_makeinstall_target() { cp -PR ${PKG_BUILD}/localedata/locales/POSIX ${INSTALL}/usr/share/i18n/locales fi -# create default configs + # create default configs mkdir -p ${INSTALL}/etc cp ${PKG_DIR}/config/nsswitch-target.conf ${INSTALL}/etc/nsswitch.conf cp ${PKG_DIR}/config/host.conf ${INSTALL}/etc cp ${PKG_DIR}/config/gai.conf ${INSTALL}/etc + # ROCKNIX: writable ld.so.cache location cp ${PKG_DIR}/config/ld.so.conf ${INSTALL}/etc } @@ -152,7 +161,7 @@ makeinstall_init() { } post_makeinstall_init() { -# create default configs + # create default configs mkdir -p ${INSTALL}/etc cp ${PKG_DIR}/config/nsswitch-init.conf ${INSTALL}/etc/nsswitch.conf } diff --git a/projects/ROCKNIX/packages/devel/glibc/patches/0001-Makerules-install-the-ABI-lib-names-header-from-the-.patch b/projects/ROCKNIX/packages/devel/glibc/patches/0001-Makerules-install-the-ABI-lib-names-header-from-the-.patch new file mode 100644 index 00000000000..e5dd7fb5593 --- /dev/null +++ b/projects/ROCKNIX/packages/devel/glibc/patches/0001-Makerules-install-the-ABI-lib-names-header-from-the-.patch @@ -0,0 +1,47 @@ +From 8b24036663eb5c8a644ca76ba8193afadc8100a7 Mon Sep 17 00:00:00 2001 +From: Rudi Heitbaum +Date: Mon, 27 Jul 2026 10:30:00 +1000 +Subject: [PATCH] Makerules: install the ABI lib-names header from the top + level only + +For multi-ABI configurations Makerules adds + + install-others-nosubdir: $(inst_includedir)/$(lib-names-h-abi) + +in every directory, but the $(inst_includedir)/%.h install rules are +defined only where $(headers) is non-empty. csu defines no headers, so +in csu the prerequisite has no rule and only succeeds if the file has +already been installed by the top level, which does have $(headers). + +Removing the top-level .NOTPARALLEL dropped that ordering: with +'make install -jN' the csu sub-make can run before the top-level +install-others-nosubdir and then fails with + + make[3]: *** No rule to make target + '.../usr/include/gnu/lib-names-hard.h', needed by + 'install-others-nosubdir'. Stop. + +Restrict the dependency to the top level, where the rules to install the +header always exist. Observed installing an armv7 hard-float build; all +multi-ABI targets (arm, aarch64, x86) are affected. +--- + Makerules | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/Makerules b/Makerules +index 6bef57e..e3666d3 100644 +--- a/Makerules ++++ b/Makerules +@@ -302,7 +302,9 @@ lib-names-h-abi = gnu/lib-names-$(default-abi).h + lib-names-stmp-abi = gnu/lib-names-$(default-abi).stmp + before-compile += $(common-objpfx)$(lib-names-h-abi) + common-generated += gnu/lib-names.h ++ifndef subdir + install-others-nosubdir: $(inst_includedir)/$(lib-names-h-abi) ++endif + $(common-objpfx)gnu/lib-names.h: + $(make-target-directory) + { \ +-- +2.47.1 + diff --git a/projects/ROCKNIX/packages/devel/glibc/patches/0002-Fix-gen-as-const-headers-races-with-the-parallel-sub.patch b/projects/ROCKNIX/packages/devel/glibc/patches/0002-Fix-gen-as-const-headers-races-with-the-parallel-sub.patch new file mode 100644 index 00000000000..de0d1cbc9e4 --- /dev/null +++ b/projects/ROCKNIX/packages/devel/glibc/patches/0002-Fix-gen-as-const-headers-races-with-the-parallel-sub.patch @@ -0,0 +1,135 @@ +From 5d1e923ed79185668ac62d19fc37e7e23a3642b6 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Thu, 6 Aug 2026 14:07:55 -0300 +Subject: [PATCH] Fix gen-as-const-headers races with the parallel subdir + recursion (BZ 34438) + +The parallel subdirectory recursion (commit 7cac99621e96) only orders +csu (and mach/hurd on Hurd) before the parallel fan-out plus the edges +the Depend files request. A header generated from gen-as-const-headers +is only ordered before the compilations of the subdirectory that +adds the .sym (through before-compile), so a header consumed by a +different subdirectory may not exist yet when its consumer is +compiled. + +That is the case for : it is generated when +building misc, while its only consumer, ____longjmp_chk.S (x86_64 and +sh), is built in debug. The serial recursion always ran misc before +debug in the sorted order, hiding the missing dependency. + +Move the generate the header to 'debug' instead. + +The same class of problem exists on Hurd: jmp_buf-ssp.h that is used +by ____longjmp_chk.S in debug, and signal-defines.h that is sued +by debug and setjmp. + +Deterministically reproduced with 'make debug/subdir_lib' from a clean +build tree (which orders only csu before debug), and verified with +builds for x86_64-linux-gnu, sh4-linux-gnu, i686-gnu, and x86_64-gnu. +Reviewed-by: Sam James + +(cherry picked from commit 60c9ed0e6b9cce07e85ee56fc39b9afe36919e45) +--- + Makerules | 12 +++++++++++- + sysdeps/mach/hurd/x86/Makefile | 6 +----- + sysdeps/unix/sysv/linux/sh/Makefile | 4 +++- + sysdeps/unix/sysv/linux/x86_64/Makefile | 4 +++- + sysdeps/x86/Makefile | 10 ++++++++-- + 5 files changed, 26 insertions(+), 10 deletions(-) + +diff --git a/Makerules b/Makerules +index 6bef57ec..cef30974 100644 +--- a/Makerules ++++ b/Makerules +@@ -259,7 +259,17 @@ endif # gen-py-const-headers + ifdef gen-as-const-headers + # Generating headers for assembly constants. + # We need this defined early to get into before-compile before +-# it's used in sysd-rules, below. ++# it's used in sysd-rules, below. The gen-as-const-headers is evaluated ++# per subdirectory, so the before-compile dependency below only orders ++# the generated header before the compiles of the subdirectory whose ++# Makefile adds the .sym directive. ++# The parallel subdirectory recursion does not order sibling subdirectories, ++# so a .sym must be added in the subdirectory that compiles its consumers, ++# or in csu (which runs before the parallel) when it has consumers in ++# several subdirectories. ++# It must not add the same .sym in several subdirectories though: their ++# concurrent sub-makes would race generating the header through the fixed ++# temporary files below. + # Define GEN_AS_CONST_HEADERS to avoid circular dependency [BZ #22792]. + # NB: is generated from tcb-offsets.sym to define + # offsets and sizes of types in and maybe which +diff --git a/sysdeps/mach/hurd/x86/Makefile b/sysdeps/mach/hurd/x86/Makefile +index 97e3287c..1d94f3a1 100644 +--- a/sysdeps/mach/hurd/x86/Makefile ++++ b/sysdeps/mach/hurd/x86/Makefile +@@ -3,11 +3,7 @@ sysdep_routines += ioperm + sysdep_headers += sys/io.h + endif + +-ifeq ($(subdir),debug) +-gen-as-const-headers += signal-defines.sym +-endif +- +-ifeq ($(subdir),setjmp) ++ifeq ($(subdir),csu) + gen-as-const-headers += signal-defines.sym + endif + +diff --git a/sysdeps/unix/sysv/linux/sh/Makefile b/sysdeps/unix/sysv/linux/sh/Makefile +index dd3b382a..8c4cb738 100644 +--- a/sysdeps/unix/sysv/linux/sh/Makefile ++++ b/sysdeps/unix/sysv/linux/sh/Makefile +@@ -6,7 +6,9 @@ ifeq ($(subdir),stdlib) + gen-as-const-headers += ucontext_i.sym + endif + +-ifeq ($(subdir),misc) ++# is only used by ____longjmp_chk.S, which is ++# built in the debug subdirectory. ++ifeq ($(subdir),debug) + gen-as-const-headers += sigaltstack-offsets.sym + endif + +diff --git a/sysdeps/unix/sysv/linux/x86_64/Makefile b/sysdeps/unix/sysv/linux/x86_64/Makefile +index 69383828..528fd951 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/Makefile ++++ b/sysdeps/unix/sysv/linux/x86_64/Makefile +@@ -10,7 +10,9 @@ ifeq ($(subdir),csu) + gen-as-const-headers += ucontext_i.sym + endif + +-ifeq ($(subdir),misc) ++# is only used by ____longjmp_chk.S, which is ++# built in the debug subdirectory. ++ifeq ($(subdir),debug) + gen-as-const-headers += sigaltstack-offsets.sym + endif + +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index 232e388d..b4434deb 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -1,5 +1,12 @@ + ifeq ($(subdir),csu) +-gen-as-const-headers += cpu-features-offsets.sym features-offsets.sym ++# is used by the setjmp/longjmp implementations in the ++# setjmp subdirectory and also by ____longjmp_chk.S in the debug ++# subdirectory. ++gen-as-const-headers += \ ++ cpu-features-offsets.sym \ ++ features-offsets.sym \ ++ jmp_buf-ssp.sym \ ++ # gen-as-const-headers + endif + + ifeq ($(subdir),elf) +@@ -171,7 +178,6 @@ tests += \ + endif # $(subdir) == math + + ifeq ($(subdir),setjmp) +-gen-as-const-headers += jmp_buf-ssp.sym + sysdep_routines += __longjmp_cancel + endif + diff --git a/projects/ROCKNIX/packages/devel/glibc/patches/0003-Makefile-Order-the-top-level-stamp-files-before-the-.patch b/projects/ROCKNIX/packages/devel/glibc/patches/0003-Makefile-Order-the-top-level-stamp-files-before-the-.patch new file mode 100644 index 00000000000..787bf7912a8 --- /dev/null +++ b/projects/ROCKNIX/packages/devel/glibc/patches/0003-Makefile-Order-the-top-level-stamp-files-before-the-.patch @@ -0,0 +1,45 @@ +From f34027b27fefbc94aab04bff613ba5c24fb909b1 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Thu, 6 Aug 2026 14:07:59 -0300 +Subject: [PATCH] Makefile: Order the top-level stamp files before the + subdirectory fan-out + +The archive rules in Makerules list every stamp file as a prerequisite, +including the top level's own, and the elf sub-make evaluates them to +build libc_pic.a for the librtld.map link. A sub-make can only create +the stamp files of its own directory, so when the top-level ones do not +exist yet it fails with: + + make[2]: *** No rule to make target '.../stamp.os', needed by + '.../libc_pic.a'. Stop. + +The serial recursion created them before the subdirectories through the +prerequisite order of subdir_lib; the parallel recursion (commit +7cac99621e96) does not. Add them as prerequisites of the object-building +per-subdirectory targets. +Reviewed-by: Sam James + +(cherry picked from commit 25c42d04c45fc5fdb1481a7f968782791b21fd3e) +--- + Makefile | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/Makefile b/Makefile +index b9fac6f47c..d559c42873 100644 +--- a/Makefile ++++ b/Makefile +@@ -575,6 +575,14 @@ $(foreach t,$(+elf_last_subdir_targets),$(eval \ + elf/$(t): $(addsuffix /$(t),$(filter-out elf,$(subdirs))))) + endif + ++# The archive rules in Makerules list every stamp file as a ++# prerequisite of libc_pic.a, which the elf sub-make evaluates for the ++# librtld.map link, but a sub-make can only create its own directory's ++# stamps. Create the top-level ones before the fan-out. ++$(foreach t,$(+elf_last_subdir_targets),$(eval \ ++ $(addsuffix /$(t),$(subdirs)): \ ++ $(foreach o,$(object-suffixes-for-libc),$(common-objpfx)stamp$(o)))) ++ + # Pass barriers: a subdirectory 'others' build links programs against + # the libraries, so the 'lib' pass (including the top-level libc.so + # link) must have completed. diff --git a/projects/ROCKNIX/packages/devel/glibc/patches/0004-Makerules-Make-the-.dt-to-.d-conversion-safe-against.patch b/projects/ROCKNIX/packages/devel/glibc/patches/0004-Makerules-Make-the-.dt-to-.d-conversion-safe-against.patch new file mode 100644 index 00000000000..c1616146dc2 --- /dev/null +++ b/projects/ROCKNIX/packages/devel/glibc/patches/0004-Makerules-Make-the-.dt-to-.d-conversion-safe-against.patch @@ -0,0 +1,64 @@ +From fc3641194619c7c327ef398c88c07b3069878ed3 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Thu, 6 Aug 2026 14:07:58 -0300 +Subject: [PATCH] Makerules: Make the .dt to .d conversion safe against + concurrent sub-makes + +The %.d: %.dt rule seds its input into a fixed temporary name, renames +it into place and removes the input. Two makes converting the same +file trip over each other: + + mv: cannot stat '.../test-double-libmvec-sincos-avx512f.o.T': No such file or directory + sed: can't read .../test-float-libmvec-acosf-avx512f.o.dt: No such file or directory + +That happens because the elf rtld-Rules recursion runs a sub-make over +every $(rtld-subdirs) directory, which converts that directory's .dt +files, and the parallel subdirectory recursion (commit 7cac99621e96) +runs it concurrently with those subdirectories' own sub-makes. + +Add the PID of the shell to the temporary name and claim the input with +a rename: only the run that wins converts and installs the target. +Reviewed-by: Sam James + +(cherry picked from commit ba8c8801be7674cc12406914184516a811ac22a8) +--- + Makerules | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/Makerules b/Makerules +index 5f65f3ab9e..be51154bae 100644 +--- a/Makerules ++++ b/Makerules +@@ -755,10 +755,20 @@ all-dt-files := $(foreach o,$(object-suffixes-for-libc),$(+depfiles:.d=$o.dt)) + $(wildcard $(all-dt-files:.dt=.d)) + + # This is a funny rule in that it removes its input file. ++# ++# More than one make can convert the .dt files of a single object ++# directory: the elf rtld-Rules recursion runs a sub-make over every ++# $(rtld-subdirs) directory, concurrently with that directory's own ++# sub-make under the parallel subdir recursion. Add the PID of the ++# shell to the temporary name and claim the input with a rename: only ++# the run that wins converts and installs the target. + %.d: %.dt +- @sed $(sed-remove-objpfx) $< > $(@:.d=.T) && \ +- mv -f $(@:.d=.T) $@ && \ +- rm -f $< ++ @dt=$(@:.d=.T)$$$$; \ ++ if mv -f $< $$dt 2>/dev/null; then \ ++ sed $(sed-remove-objpfx) $$dt > $$dt.new && \ ++ mv -f $$dt.new $@ && \ ++ rm -f $$dt; \ ++ fi + + # Avoid the .h.d files for any .sym files whose .h files don't exist yet. + # They will be generated when they're needed, and trying too early won't work. +@@ -1423,7 +1433,7 @@ endef + # Also remove the dependencies and generated source files. + common-clean: common-mostlyclean + -rm -f $(addprefix $(objpfx),$(generated)) +- -rm -f $(objpfx)*.d $(objpfx)*.dt ++ -rm -f $(objpfx)*.d $(objpfx)*.dt $(objpfx)*.T[0-9]* + -rm -fr $(addprefix $(objpfx),$(generated-dirs)) + -rm -f $(addprefix $(common-objpfx),$(common-generated)) + -rm -f $(gen-as-const-headers:%.sym=$(common-objpfx)%.h) diff --git a/projects/ROCKNIX/packages/devel/glibc/patches/0005-arm-Order-the-rtld-link-after-libgcc-stubs.a.patch b/projects/ROCKNIX/packages/devel/glibc/patches/0005-arm-Order-the-rtld-link-after-libgcc-stubs.a.patch new file mode 100644 index 00000000000..c0983ac1e47 --- /dev/null +++ b/projects/ROCKNIX/packages/devel/glibc/patches/0005-arm-Order-the-rtld-link-after-libgcc-stubs.a.patch @@ -0,0 +1,44 @@ +From 10e3ce8a57e134c13dd28772de68542b0e3d4e86 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Thu, 6 Aug 2026 14:08:00 -0300 +Subject: [PATCH] arm: Order the rtld link after libgcc-stubs.a + +The librtld.map and librtld.os link recipes use $(gnulib), which on arm +contains libgcc-stubs.a through gnulib-arch. But the archive is only a +prerequisite of lib-noranlib so the rtld link can run before the archive +exists: + + ld.bfd: cannot find .../elf/libgcc-stubs.a: No such file or directory + +The race seems to predates the parallel subdirectory recursion, which +only made it observable. + +Add the order-only dependency in sysdeps/arm/Makefile rather than in +elf/Makefile. Theprerequisite lists expand when the rule is parsed, +and gnulib-arch is only defined once Makerules includes the sysdeps +makefiles. + +Verified with a build for arm-linux-gnueabihf. +Reviewed-by: Sam James + +(cherry picked from commit a33ceb6e96dc8de8d36de1b1f3ec06ceb524d012) +--- + sysdeps/arm/Makefile | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/sysdeps/arm/Makefile b/sysdeps/arm/Makefile +index 0bb1b6e05b..9042315492 100644 +--- a/sysdeps/arm/Makefile ++++ b/sysdeps/arm/Makefile +@@ -10,6 +10,11 @@ shared-only-routines += aeabi_unwind_cpp_pr1 + $(objpfx)libgcc-stubs.a: $(objpfx)aeabi_unwind_cpp_pr1.os + $(build-extra-lib) + ++# The rtld link recipes in elf/Makefile use $(gnulib), which here ++# includes libgcc-stubs.a, but they cannot name it as a prerequisite: ++# gnulib-arch is only defined once this file is included from Makerules. ++$(objpfx)librtld.map $(objpfx)librtld.os: | $(objpfx)libgcc-stubs.a ++ + lib-noranlib: $(objpfx)libgcc-stubs.a + + ifeq ($(build-shared),yes) diff --git a/projects/ROCKNIX/packages/devel/glibc/patches/aarch64/001-guard-off-vector-types.patch b/projects/ROCKNIX/packages/devel/glibc/patches/aarch64/001-guard-off-vector-types.patch deleted file mode 100644 index 84cc9c44ea7..00000000000 --- a/projects/ROCKNIX/packages/devel/glibc/patches/aarch64/001-guard-off-vector-types.patch +++ /dev/null @@ -1,95 +0,0 @@ -[RFC PATCH] arm64/math-vec.h: guard off the vector types with CPP constants - -Simon Chopin simon.chopin@canonical.com -Wed Sep 27 14:18:39 GMT 2023 -Previous message (by thread): [RFC PATCH] pthread_create: Name stacks in /proc//maps -Next message (by thread): [RFC PATCH] arm64/math-vec.h: guard off the vector types with CPP constants -Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] -When implementing a C parser, it's apparently common to use GCC as -preprocessor. However, those programs don't necessarily define the SIMD -intrinsic types exposed by GCC, resulting in failed compilations. - -This patch adds a way for those users to bypass entirely the vector -types, as they usually aren't interested in libmvec anyway. They can -just add -D__ARM_VEC_MATH_DISABLED=1 to the CPP_FLAGS they pass on to -GCC. - -Fixes: BZ #25422 - -Signed-off-by: Simon Chopin ---- - sysdeps/aarch64/fpu/bits/math-vector.h | 32 ++++++++++++++------------ - 1 file changed, 17 insertions(+), 15 deletions(-) - -diff --git a/sysdeps/aarch64/fpu/bits/math-vector.h b/sysdeps/aarch64/fpu/bits/math-vector.h -index 7c200599c1..c739e6bc5d 100644 ---- a/sysdeps/aarch64/fpu/bits/math-vector.h -+++ b/sysdeps/aarch64/fpu/bits/math-vector.h -@@ -25,29 +25,30 @@ - /* Get default empty definitions for simd declarations. */ - #include - --#if __GNUC_PREREQ(9, 0) --# define __ADVSIMD_VEC_MATH_SUPPORTED -+#if defined __ARM_ARCH_8A && !defined __ARM_VEC_MATH_DISABLED -+# if __GNUC_PREREQ(9, 0) -+# define __ADVSIMD_VEC_MATH_SUPPORTED - typedef __Float32x4_t __f32x4_t; - typedef __Float64x2_t __f64x2_t; --#elif __glibc_clang_prereq(8, 0) --# define __ADVSIMD_VEC_MATH_SUPPORTED -+# elif __glibc_clang_prereq(8, 0) -+# define __ADVSIMD_VEC_MATH_SUPPORTED - typedef __attribute__ ((__neon_vector_type__ (4))) float __f32x4_t; - typedef __attribute__ ((__neon_vector_type__ (2))) double __f64x2_t; --#endif -+# endif - --#if __GNUC_PREREQ(10, 0) || __glibc_clang_prereq(11, 0) --# define __SVE_VEC_MATH_SUPPORTED -+# if __GNUC_PREREQ(10, 0) || __glibc_clang_prereq(11, 0) -+# define __SVE_VEC_MATH_SUPPORTED - typedef __SVFloat32_t __sv_f32_t; - typedef __SVFloat64_t __sv_f64_t; - typedef __SVBool_t __sv_bool_t; --#endif -+# endif - - /* If vector types and vector PCS are unsupported in the working - compiler, no choice but to omit vector math declarations. */ - --#ifdef __ADVSIMD_VEC_MATH_SUPPORTED -+# ifdef __ADVSIMD_VEC_MATH_SUPPORTED - --# define __vpcs __attribute__ ((__aarch64_vector_pcs__)) -+# define __vpcs __attribute__ ((__aarch64_vector_pcs__)) - - __vpcs __f32x4_t _ZGVnN4v_cosf (__f32x4_t); - __vpcs __f32x4_t _ZGVnN4v_expf (__f32x4_t); -@@ -59,10 +60,10 @@ __vpcs __f64x2_t _ZGVnN2v_exp (__f64x2_t); - __vpcs __f64x2_t _ZGVnN2v_log (__f64x2_t); - __vpcs __f64x2_t _ZGVnN2v_sin (__f64x2_t); - --# undef __ADVSIMD_VEC_MATH_SUPPORTED --#endif /* __ADVSIMD_VEC_MATH_SUPPORTED */ -+# undef __ADVSIMD_VEC_MATH_SUPPORTED -+# endif /* __ADVSIMD_VEC_MATH_SUPPORTED */ - --#ifdef __SVE_VEC_MATH_SUPPORTED -+# ifdef __SVE_VEC_MATH_SUPPORTED - - __sv_f32_t _ZGVsMxv_cosf (__sv_f32_t, __sv_bool_t); - __sv_f32_t _ZGVsMxv_expf (__sv_f32_t, __sv_bool_t); -@@ -74,5 +75,6 @@ __sv_f64_t _ZGVsMxv_exp (__sv_f64_t, __sv_bool_t); - __sv_f64_t _ZGVsMxv_log (__sv_f64_t, __sv_bool_t); - __sv_f64_t _ZGVsMxv_sin (__sv_f64_t, __sv_bool_t); - --# undef __SVE_VEC_MATH_SUPPORTED --#endif /* __SVE_VEC_MATH_SUPPORTED */ -+# undef __SVE_VEC_MATH_SUPPORTED -+# endif /* __SVE_VEC_MATH_SUPPORTED */ -+#endif /* _ARM_ARCH_8A && !__ARM_VEC_MATH_DISABLED */ - -base-commit: 64b1a44183a3094672ed304532bedb9acc707554 --- -2.40.1 diff --git a/projects/ROCKNIX/packages/devel/glibc/patches/glibc-0002-Linux--Only-define-OPEN_TREE_.patch b/projects/ROCKNIX/packages/devel/glibc/patches/glibc-0002-Linux--Only-define-OPEN_TREE_.patch deleted file mode 100644 index 36ae724365f..00000000000 --- a/projects/ROCKNIX/packages/devel/glibc/patches/glibc-0002-Linux--Only-define-OPEN_TREE_.patch +++ /dev/null @@ -1,42 +0,0 @@ -From d12b017cddfeb9fe9920ba054ae3dfcb8e9238b8 Mon Sep 17 00:00:00 2001 -From: Florian Weimer -Date: Wed, 4 Mar 2026 18:32:36 +0100 -Subject: [PATCH 1/1] Linux: Only define OPEN_TREE_* macros in if - undefined (bug 33921) - -There is a conditional inclusion of earlier in the file. -If that defines the macros, do not redefine them. This addresses build -problems as the token sequence used by the UAPI macro definitions -changes between Linux versions. - -Reviewed-by: Adhemerval Zanella ---- - sysdeps/unix/sysv/linux/sys/mount.h | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/sysdeps/unix/sysv/linux/sys/mount.h b/sysdeps/unix/sysv/linux/sys/mount.h -index 5e496caf2f..0c5ebed33a 100644 ---- a/sysdeps/unix/sysv/linux/sys/mount.h -+++ b/sysdeps/unix/sysv/linux/sys/mount.h -@@ -265,8 +265,16 @@ - #define FSOPEN_CLOEXEC 0x00000001 - - /* open_tree flags. */ --#define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */ --#define OPEN_TREE_CLOEXEC O_CLOEXEC /* Close the file on execve() */ -+#ifndef OPEN_TREE_CLONE -+# define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */ -+#endif -+#ifndef O_CLOEXEC -+# include -+# define O_CLOEXEC __O_CLOEXEC -+#endif -+#ifndef OPEN_TREE_CLOEXEC -+# define OPEN_TREE_CLOEXEC O_CLOEXEC /* Close the file on execve() */ -+#endif - - - __BEGIN_DECLS - --- -2.43.7 diff --git a/projects/ROCKNIX/packages/devel/glibc/patches/glibc-fix-dns-with-broken-routers.patch b/projects/ROCKNIX/packages/devel/glibc/patches/glibc-fix-dns-with-broken-routers.patch index d2ac6708530..c76bf2292f1 100644 --- a/projects/ROCKNIX/packages/devel/glibc/patches/glibc-fix-dns-with-broken-routers.patch +++ b/projects/ROCKNIX/packages/devel/glibc/patches/glibc-fix-dns-with-broken-routers.patch @@ -95,13 +95,13 @@ Date: Tue Oct 1 12:09:07 2013 +0300 res, &status, &no_data)) != 0) --- a/sysdeps/unix/sysv/linux/check_pf.c +++ b/sysdeps/unix/sysv/linux/check_pf.c -@@ -224,7 +224,8 @@ make_request (int fd, pid_t pid) - } - else +@@ -212,7 +212,8 @@ { -- if (!IN6_IS_ADDR_LOOPBACK (address)) -+ if (!IN6_IS_ADDR_LOOPBACK (address) && -+ !IN6_IS_ADDR_LINKLOCAL (address)) + struct in6_addr in6addr; + memcpy (&in6addr, address, sizeof (in6addr)); +- if (!IN6_IS_ADDR_LOOPBACK (&in6addr)) ++ if (!IN6_IS_ADDR_LOOPBACK (&in6addr) && ++ !IN6_IS_ADDR_LINKLOCAL (&in6addr)) seen_ipv6 = true; } } diff --git a/projects/ROCKNIX/packages/devel/json-glib/package.mk b/projects/ROCKNIX/packages/devel/json-glib/package.mk index 698d5bbebc5..776b720e353 100644 --- a/projects/ROCKNIX/packages/devel/json-glib/package.mk +++ b/projects/ROCKNIX/packages/devel/json-glib/package.mk @@ -1,15 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 -# Copyright (C) 2021-present Team LibreELEC (https://libreelec.tv) +# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv) -PKG_NAME="json-glib" -PKG_VERSION="1.10.0" -PKG_LICENSE="LGPL-2.1" -PKG_SITE="https://github.com/GNOME/json-glib" -PKG_URL="https://github.com/GNOME/json-glib/archive/${PKG_VERSION}.tar.gz" -PKG_DEPENDS_TARGET="toolchain glib glib:host" -PKG_LONGDESC="JSON-GLib implements a full suite of JSON-related tools using GLib and GObject." +. ${ROOT}/packages/devel/json-glib/package.mk -PKG_MESON_OPTS_TARGET="-Dintrospection=disabled \ - -Dgtk_doc=disabled \ - -Dman=false \ - -Dtests=false" +# json-glib's introspection needs the host glib tooling +PKG_DEPENDS_TARGET="${PKG_DEPENDS_TARGET} glib:host" diff --git a/projects/ROCKNIX/packages/devel/libfmt/package.mk b/projects/ROCKNIX/packages/devel/libfmt/package.mk deleted file mode 100644 index 335ea4334c5..00000000000 --- a/projects/ROCKNIX/packages/devel/libfmt/package.mk +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Copyright (C) 2024-present ROCKNIX (https://github.com/ROCKNIX) - -. ${ROOT}/packages/devel/libfmt/package.mk - -case ${DEVICE} in - SM8250|SM8550|SM8650|SM8750|AMD64) - ;; - *) - PKG_VERSION="9.1.0" - PKG_SHA256="" - PKG_URL="https://github.com/fmtlib/fmt/archive/${PKG_VERSION}.tar.gz" - ;; -esac diff --git a/projects/ROCKNIX/packages/devel/libpthread-stubs/package.mk b/projects/ROCKNIX/packages/devel/libpthread-stubs/package.mk index 61575af7462..2fe8b9cd1ed 100644 --- a/projects/ROCKNIX/packages/devel/libpthread-stubs/package.mk +++ b/projects/ROCKNIX/packages/devel/libpthread-stubs/package.mk @@ -3,6 +3,7 @@ PKG_NAME="libpthread-stubs" PKG_VERSION="0.5" +PKG_SHA256="593196cc746173d1e25cb54a93a87fd749952df68699aab7e02c085530e87747" PKG_LICENSE="OSS" PKG_SITE="http://xcb.freedesktop.org/" PKG_URL="http://xcb.freedesktop.org/dist/${PKG_NAME}-${PKG_VERSION}.tar.gz" diff --git a/projects/ROCKNIX/packages/devel/ncurses/package.mk b/projects/ROCKNIX/packages/devel/ncurses/package.mk index 4024b292586..b03afd1e8b5 100644 --- a/projects/ROCKNIX/packages/devel/ncurses/package.mk +++ b/projects/ROCKNIX/packages/devel/ncurses/package.mk @@ -4,8 +4,8 @@ # Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS) PKG_NAME="ncurses" -PKG_VERSION="6.5" -PKG_SHA256="136d91bc269a9a5785e5f9e980bc76ab57428f604ce3e5a5a90cebc767971cc6" +PKG_VERSION="6.6" +PKG_SHA256="355b4cbbed880b0381a04c46617b7656e362585d52e9cf84a67e2009b749ff11" PKG_LICENSE="MIT" PKG_SITE="http://www.gnu.org/software/ncurses/" PKG_URL="http://invisible-mirror.net/archives/ncurses/ncurses-${PKG_VERSION}.tar.gz" diff --git a/projects/ROCKNIX/packages/devel/ncurses/patches/ncurses-001-terminfo-xterm.patch b/projects/ROCKNIX/packages/devel/ncurses/patches/0001-terminfo-xterm.patch similarity index 59% rename from projects/ROCKNIX/packages/devel/ncurses/patches/ncurses-001-terminfo-xterm.patch rename to projects/ROCKNIX/packages/devel/ncurses/patches/0001-terminfo-xterm.patch index f90b8d73a75..036e7dd2c6d 100644 --- a/projects/ROCKNIX/packages/devel/ncurses/patches/ncurses-001-terminfo-xterm.patch +++ b/projects/ROCKNIX/packages/devel/ncurses/patches/0001-terminfo-xterm.patch @@ -1,9 +1,15 @@ +From 99d8ca22f1aebb6f61d2cbc6a9df9e09b8f8801d Mon Sep 17 00:00:00 2001 +From: mglae +Date: Thu, 27 Dec 2018 15:53:05 +0100 +Subject: [PATCH] terminfo xterm Remove recent xterm terminfo features to be compatible with other emulations ---- a/misc/terminfo.src 2021-03-20 22:45:39.000000000 +0100 -+++ b/misc/terminfo.src 2021-06-01 23:53:10.335516419 +0200 -@@ -4946,9 +4946,9 @@ xterm-xfree86|xterm terminal emulator (X +--- +diff --git a/misc/terminfo.src b/misc/terminfo.src +--- a/misc/terminfo.src ++++ b/misc/terminfo.src +@@ -5072,9 +5072,9 @@ xterm-xfree86|xterm terminal emulator (X xterm+nofkeys|building block for xterm fkey-variants, npc, diff --git a/projects/ROCKNIX/packages/devel/ncurses/patches/0002-alloc-fallbacks.patch b/projects/ROCKNIX/packages/devel/ncurses/patches/0002-alloc-fallbacks.patch new file mode 100644 index 00000000000..7ff40a51d55 --- /dev/null +++ b/projects/ROCKNIX/packages/devel/ncurses/patches/0002-alloc-fallbacks.patch @@ -0,0 +1,20 @@ +From 99d8ca22f1aebb6f61d2cbc6a9df9e09b8f8801d Mon Sep 17 00:00:00 2001 +From: mglae +Date: Thu, 27 Dec 2018 15:53:05 +0100 +Subject: [PATCH] alloc fallbacks + +Fix freeing not allocated fallback entries by allocating a copy. + +--- +diff --git a/ncurses/tinfo/tinfo_driver.c b/ncurses/tinfo/tinfo_driver.c +--- a/ncurses/tinfo/tinfo_driver.c ++++ b/ncurses/tinfo/tinfo_driver.c +@@ -181,6 +181,8 @@ drv_CanHandle(TERMINAL_CONTROL_BLOCK * T + if (status != TGETENT_YES) { + const TERMTYPE2 *fallback = _nc_fallback2(tname); + ++ if (fallback) ++ fallback = _nc_copy_entry(fallback); + if (fallback) { + T(("found fallback entry")); + TerminalType(termp) = *fallback; diff --git a/projects/ROCKNIX/packages/devel/ncurses/patches/0003-fix-configure-pkgconfig.patch b/projects/ROCKNIX/packages/devel/ncurses/patches/0003-fix-configure-pkgconfig.patch new file mode 100644 index 00000000000..90077cbf425 --- /dev/null +++ b/projects/ROCKNIX/packages/devel/ncurses/patches/0003-fix-configure-pkgconfig.patch @@ -0,0 +1,20 @@ +From 4fa3e0ef444f1cf57b9b86e7d840694c5ef43f4d Mon Sep 17 00:00:00 2001 +From: mglae +Date: Sat, 04 Dec 2021 15:27:26 +0100 +Subject: [PATCH] fix configure pkgconfig + +Fix configure option --with-pkg-config-libdir is broken for cross compilation + +--- +diff --git a/configure b/configure +--- a/configure ++++ b/configure +@@ -4591,7 +4591,7 @@ echo $ECHO_N "checking for first directo + cf_pkg_config_path=none + for cf_config in $cf_search_path + do +- if test -d "$cf_config" ++ if test -n "$cf_config" + then + cf_pkg_config_path=$cf_config + break diff --git a/projects/ROCKNIX/packages/devel/ncurses/patches/ncurses-003-fix_hints.patch b/projects/ROCKNIX/packages/devel/ncurses/patches/0004-fix-scroll-hints-with-hashmap-disabled.patch similarity index 100% rename from projects/ROCKNIX/packages/devel/ncurses/patches/ncurses-003-fix_hints.patch rename to projects/ROCKNIX/packages/devel/ncurses/patches/0004-fix-scroll-hints-with-hashmap-disabled.patch diff --git a/projects/ROCKNIX/packages/devel/ncurses/patches/ncurses-002-alloc-fallbacks.patch b/projects/ROCKNIX/packages/devel/ncurses/patches/ncurses-002-alloc-fallbacks.patch deleted file mode 100644 index eaf093adb5f..00000000000 --- a/projects/ROCKNIX/packages/devel/ncurses/patches/ncurses-002-alloc-fallbacks.patch +++ /dev/null @@ -1,13 +0,0 @@ -Fix freeing not allocated fallback entries by allocating a copy. - ---- a/ncurses/tinfo/tinfo_driver.c 2018-11-24 23:17:03.000000000 +0100 -+++ b/ncurses/tinfo/tinfo_driver.c 2018-12-29 10:27:19.000000000 +0100 -@@ -180,6 +180,8 @@ drv_CanHandle(TERMINAL_CONTROL_BLOCK * T - if (status != TGETENT_YES) { - const TERMTYPE2 *fallback = _nc_fallback2(tname); - -+ if (fallback) -+ fallback = _nc_copy_entry(fallback); - if (fallback) { - T(("found fallback entry")); - TerminalType(termp) = *fallback; diff --git a/projects/ROCKNIX/packages/devel/ncurses/patches/ncurses-004-fix_configure_pkgconfig.patch b/projects/ROCKNIX/packages/devel/ncurses/patches/ncurses-004-fix_configure_pkgconfig.patch deleted file mode 100644 index 9328063900a..00000000000 --- a/projects/ROCKNIX/packages/devel/ncurses/patches/ncurses-004-fix_configure_pkgconfig.patch +++ /dev/null @@ -1,13 +0,0 @@ -Fix configure option --with-pkg-config-libdir is broken for cross compilation - ---- a/configure 2021-10-17 17:12:23.000000000 +0200 -+++ b/configure 2021-11-26 00:27:00.224815736 +0100 -@@ -4255,7 +4255,7 @@ echo $ECHO_N "checking for first directo - cf_pkg_config_path=none - for cf_config in $cf_search_path - do -- if test -d "$cf_config" -+ if test -n "$cf_config" - then - cf_pkg_config_path=$cf_config - break diff --git a/projects/ROCKNIX/packages/devel/patchelf/package.mk b/projects/ROCKNIX/packages/devel/patchelf/package.mk index 5205689e11a..28b9cf6b804 100644 --- a/projects/ROCKNIX/packages/devel/patchelf/package.mk +++ b/projects/ROCKNIX/packages/devel/patchelf/package.mk @@ -1,14 +1,13 @@ -# SPDX-License-Identifier: GPL-2.0-only -# Copyright (C) 2023-present Team LibreELEC (https://libreelec.tv) +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2024-present ROCKNIX (https://github.com/ROCKNIX) -PKG_NAME="patchelf" -PKG_VERSION="0.18.0" -PKG_SHA256="1952b2a782ba576279c211ee942e341748fdb44997f704dd53def46cd055470b" -PKG_LICENSE="GPL-3.0-or-later" -PKG_SITE="https://github.com/NixOS/patchelf" -PKG_URL="https://github.com/NixOS/patchelf/releases/download/${PKG_VERSION}/patchelf-${PKG_VERSION}.tar.bz2" -PKG_DEPENDS_HOST="autotools:host" +. ${ROOT}/packages/devel/patchelf/package.mk + +# Core declares no PKG_DEPENDS_TARGET, so nothing orders the target build +# after the cross toolchain. Nothing depends on patchelf:target either - +# every reference in the tree is patchelf:host, and the target build exists +# only because patchelf ships in the image - so there is no dependency edge +# to sequence it. On a fresh tree it gets scheduled before gcc is built and +# dies with "C compiler cannot create executables". Name the toolchain the +# way every other target package does. PKG_DEPENDS_TARGET="toolchain" -PKG_LONGDESC="A small utility to modify the dynamic linker and RPATH of ELF executables" -PKG_TOOLCHAIN="autotools" -PKG_BUILD_FLAGS="-cfg-libs:host" diff --git a/projects/ROCKNIX/packages/devel/readline/package.mk b/projects/ROCKNIX/packages/devel/readline/package.mk index 367454ad146..0f8f357cdb9 100644 --- a/projects/ROCKNIX/packages/devel/readline/package.mk +++ b/projects/ROCKNIX/packages/devel/readline/package.mk @@ -3,7 +3,13 @@ . ${ROOT}/packages/devel/readline/package.mk +# --with-curses only picks the termcap interface; nothing links a termcap +# library into libreadline.so, which is left with tgetent/tputs/tgoto +# undefined. bfd and gold tolerate that, mold does not. Name the library +# explicitly: "=yes" resolves to -ltinfo, which exists here only as a static +# archive, and the symbols live in libtinfow regardless. PKG_CONFIGURE_OPTS_TARGET="bash_cv_wcwidth_broken=no \ --enable-shared \ --disable-static \ - --with-curses" + --with-curses \ + --with-shared-termcap-library=-ltinfow" diff --git a/projects/ROCKNIX/packages/devel/shared-mime-info/package.mk b/projects/ROCKNIX/packages/devel/shared-mime-info/package.mk index d0abba6de27..a22ea5cb4b7 100644 --- a/projects/ROCKNIX/packages/devel/shared-mime-info/package.mk +++ b/projects/ROCKNIX/packages/devel/shared-mime-info/package.mk @@ -2,7 +2,8 @@ # Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv) PKG_NAME="shared-mime-info" -PKG_VERSION="2.4" +PKG_VERSION="2.5.1" +PKG_SHA256="b75b420da9b0be9a3d99b1bee6ed87957b56ab54583ac1a97fbd0dc98ddddb25" PKG_LICENSE="GPL-2.0-only" PKG_SITE="https://freedesktop.org/wiki/Software/shared-mime-info/" PKG_URL="https://gitlab.freedesktop.org/xdg/${PKG_NAME}/-/archive/${PKG_VERSION}/${PKG_NAME}-${PKG_VERSION}.tar.bz2" @@ -18,8 +19,14 @@ configure_package() { fi } -PKG_MESON_OPTS_HOST="-Dupdate-mimedb=false" -PKG_MESON_OPTS_TARGET="-Dupdate-mimedb=false" +# build-spec needs xmlto, which we do not ship, and the spec document +# and tests are of no use in the image +PKG_MESON_OPTS_COMMON="-Dupdate-mimedb=false \ + -Dbuild-spec=false \ + -Dbuild-tests=false" + +PKG_MESON_OPTS_HOST="${PKG_MESON_OPTS_COMMON}" +PKG_MESON_OPTS_TARGET="${PKG_MESON_OPTS_COMMON}" post_makeinstall_target() { mkdir -p ${SYSROOT_PREFIX}/usr/lib/pkgconfig diff --git a/projects/ROCKNIX/packages/devel/swig/package.mk b/projects/ROCKNIX/packages/devel/swig/package.mk index 829c79652d1..05be791fde0 100644 --- a/projects/ROCKNIX/packages/devel/swig/package.mk +++ b/projects/ROCKNIX/packages/devel/swig/package.mk @@ -1,45 +1,15 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (C) 2009-2016 Stephan Raue (stephan@openelec.tv) +# SPDX-License-Identifier: GPL-2.0 # Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv) -PKG_NAME="swig" +. ${ROOT}/packages/devel/swig/package.mk + +# Held at 4.1.1: swig 4.5 dropped the Python 2 compatibility macros from +# its generated preamble, and u-boot's libfdt.i still calls PyInt_AsLong, +# so binman fails to import _libfdt.so. That file is generated during the +# u-boot build rather than shipped, so there is nothing to patch. swig is +# host codegen only - being current buys us nothing. Drop this once +# u-boot's pylibfdt stops using the Python 2 API. PKG_VERSION="4.1.1" PKG_SHA256="2af08aced8fcd65cdb5cc62426768914bedc735b1c250325203716f78e39ac9b" -PKG_LICENSE="GPL" -PKG_SITE="http://www.swig.org" -PKG_URL="${SOURCEFORGE_SRC}/swig/${PKG_NAME}-${PKG_VERSION}.tar.gz" -PKG_DEPENDS_HOST="ccache:host" -PKG_LONGDESC="SWIG is a software development tool that connects programs written in C and C++ with a variety of high-level programming languages." -PKG_TOOLCHAIN="configure" - -PKG_CONFIGURE_OPTS_HOST="--program-suffix=4.0 \ - --with-pcre-prefix=${TOOLCHAIN} \ - --with-boost=no \ - --without-pcre \ - --without-x \ - --without-tcl \ - --without-python \ - --without-python3 \ - --without-perl5 \ - --without-octave \ - --without-java \ - --without-gcj \ - --without-android \ - --without-guile \ - --without-mzscheme \ - --without-ruby \ - --without-php \ - --without-ocaml \ - --without-pike \ - --without-chicken \ - --without-csharp \ - --without-lua \ - --without-allegrocl \ - --without-clisp \ - --without-r \ - --without-go \ - --without-d" - -post_makeinstall_host() { - ln -sf swig4.0 ${TOOLCHAIN}/bin/swig -} +# core expanded PKG_URL against its own version when this was sourced +PKG_URL="https://downloads.sourceforge.net/project/swig/swig/swig-${PKG_VERSION}/${PKG_NAME}-${PKG_VERSION}.tar.gz" diff --git a/projects/ROCKNIX/packages/emulators/libretro/beetle-psx-lr/patches/beetle-psx-lr-0001-fix-build-with-std-c++20.patch b/projects/ROCKNIX/packages/emulators/libretro/beetle-psx-lr/patches/beetle-psx-lr-0001-fix-build-with-std-c++20.patch new file mode 100644 index 00000000000..c318fadad28 --- /dev/null +++ b/projects/ROCKNIX/packages/emulators/libretro/beetle-psx-lr/patches/beetle-psx-lr-0001-fix-build-with-std-c++20.patch @@ -0,0 +1,35 @@ +From: LibretroAdmin +Subject: [PATCH] Fixed build with -std=c++20 (#936) + +Backport of upstream 2b8fbd60a3: designate the kernel/user memory +mirror entries of lightrec_map so the initializer list is uniformly +designated; gcc 16 rejects mixed designated/positional initializers. + +--- a/mednafen/psx/cpu.cpp ++++ b/mednafen/psx/cpu.cpp +@@ -3689,21 +3689,21 @@ struct lightrec_mem_map PS_CPU::lightrec_map[] = { + }, + + /* Mirrors of the kernel/user memory */ +- { ++ [PSX_MAP_MIRROR1] = { + .pc = 0x00200000, + .length = 0x200000, + .address = NULL, + .ops = NULL, + .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM], + }, +- { ++ [PSX_MAP_MIRROR2] = { + .pc = 0x00400000, + .length = 0x200000, + .address = NULL, + .ops = NULL, + .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM], + }, +- { ++ [PSX_MAP_MIRROR3] = { + .pc = 0x00600000, + .length = 0x200000, + .address = NULL, + diff --git a/projects/ROCKNIX/packages/emulators/libretro/desmume-lr/package.mk b/projects/ROCKNIX/packages/emulators/libretro/desmume-lr/package.mk index cffcc60ce5a..d37e6d06b43 100644 --- a/projects/ROCKNIX/packages/emulators/libretro/desmume-lr/package.mk +++ b/projects/ROCKNIX/packages/emulators/libretro/desmume-lr/package.mk @@ -43,7 +43,7 @@ makeinstall_target() { mkdir -p ${INSTALL}/usr/lib/libretro if [ "${ARCH}" = "aarch64" ] then - cp -vP ${ROOT}/build.${DISTRO}-${DEVICE}.arm/install_pkg/desmume-*/usr/lib/libretro/desmume_libretro.so ${INSTALL}/usr/lib/libretro/ + cp -vP ${BUILD_ROOT}/build.${DISTRO}-${DEVICE}.arm/install_pkg/desmume-*/usr/lib/libretro/desmume_libretro.so ${INSTALL}/usr/lib/libretro/ else cp desmume_libretro.so ${INSTALL}/usr/lib/libretro/ fi diff --git a/projects/ROCKNIX/packages/emulators/libretro/gpsp-lr/package.mk b/projects/ROCKNIX/packages/emulators/libretro/gpsp-lr/package.mk index 548c34a0814..a7f329750de 100644 --- a/projects/ROCKNIX/packages/emulators/libretro/gpsp-lr/package.mk +++ b/projects/ROCKNIX/packages/emulators/libretro/gpsp-lr/package.mk @@ -46,7 +46,7 @@ makeinstall_target() { mkdir -p ${INSTALL}/usr/lib/libretro if [ "${ARCH}" = "aarch64" ] then - cp -vP ${ROOT}/build.${DISTRO}-${DEVICE}.arm/install_pkg/gpsp-*/usr/lib/libretro/gpsp_libretro.so ${INSTALL}/usr/lib/libretro/ + cp -vP ${BUILD_ROOT}/build.${DISTRO}-${DEVICE}.arm/install_pkg/gpsp-*/usr/lib/libretro/gpsp_libretro.so ${INSTALL}/usr/lib/libretro/ else cp ${PKG_BUILD}/gpsp_libretro.so ${INSTALL}/usr/lib/libretro/ fi diff --git a/projects/ROCKNIX/packages/emulators/libretro/pcsx_rearmed-lr/package.mk b/projects/ROCKNIX/packages/emulators/libretro/pcsx_rearmed-lr/package.mk index 0ff8bdec570..430c65a9c4e 100644 --- a/projects/ROCKNIX/packages/emulators/libretro/pcsx_rearmed-lr/package.mk +++ b/projects/ROCKNIX/packages/emulators/libretro/pcsx_rearmed-lr/package.mk @@ -29,7 +29,7 @@ makeinstall_target32() { aarch64) if [ "${ENABLE_32BIT}" == "true" ] then - cp -vP ${ROOT}/build.${DISTRO}-${DEVICE}.arm/install_pkg/${PKG_NAME}-*/usr/lib/libretro/${1}_libretro.so ${INSTALL}/usr/lib/libretro/${1}32_libretro.so + cp -vP ${BUILD_ROOT}/build.${DISTRO}-${DEVICE}.arm/install_pkg/${PKG_NAME}-*/usr/lib/libretro/${1}_libretro.so ${INSTALL}/usr/lib/libretro/${1}32_libretro.so fi ;; esac diff --git a/projects/ROCKNIX/packages/emulators/libretro/retroarch/package.mk b/projects/ROCKNIX/packages/emulators/libretro/retroarch/package.mk index 94d1bf07d49..9eb2cc0213d 100644 --- a/projects/ROCKNIX/packages/emulators/libretro/retroarch/package.mk +++ b/projects/ROCKNIX/packages/emulators/libretro/retroarch/package.mk @@ -114,10 +114,10 @@ makeinstall_target() { case ${ARCH} in aarch64) - if [ -f ${ROOT}/build.${DISTRO}-${DEVICE}.arm/install_pkg/retroarch-*/usr/bin/retroarch ]; then - cp -vP ${ROOT}/build.${DISTRO}-${DEVICE}.arm/install_pkg/retroarch-*/usr/bin/retroarch ${INSTALL}/usr/bin/retroarch32 + if [ -f ${BUILD_ROOT}/build.${DISTRO}-${DEVICE}.arm/install_pkg/retroarch-*/usr/bin/retroarch ]; then + cp -vP ${BUILD_ROOT}/build.${DISTRO}-${DEVICE}.arm/install_pkg/retroarch-*/usr/bin/retroarch ${INSTALL}/usr/bin/retroarch32 mkdir -p ${INSTALL}/usr/share/retroarch/filters/32bit/ - cp -rvP ${ROOT}/build.${DISTRO}-${DEVICE}.arm/install_pkg/retroarch-*/usr/share/retroarch/filters/64bit/* ${INSTALL}/usr/share/retroarch/filters/32bit/ + cp -rvP ${BUILD_ROOT}/build.${DISTRO}-${DEVICE}.arm/install_pkg/retroarch-*/usr/share/retroarch/filters/64bit/* ${INSTALL}/usr/share/retroarch/filters/32bit/ fi ;; esac diff --git a/projects/ROCKNIX/packages/emulators/libretro/retroarch/patches/retroarch-0100-ffmpeg9-lavc63.patch b/projects/ROCKNIX/packages/emulators/libretro/retroarch/patches/retroarch-0100-ffmpeg9-lavc63.patch new file mode 100644 index 00000000000..e525c0d9dd0 --- /dev/null +++ b/projects/ROCKNIX/packages/emulators/libretro/retroarch/patches/retroarch-0100-ffmpeg9-lavc63.patch @@ -0,0 +1,206 @@ +From f5b422d5a81f0b4d263e2f52c8419ea9ce7467f6 Mon Sep 17 00:00:00 2001 +From: LibretroAdmin +Subject: [PATCH] ffmpeg: support FFmpeg 9 (lavc 63), version-gated back to + existing floor + +MSYS2 updated mingw-w64-ffmpeg to 9.0, which removes the deprecated +AVCodec.sample_fmts / AVCodec.supported_samplerates arrays and breaks +the MSYS2 CI build in record_ffmpeg.c. + +record_ffmpeg: add accessors that use avcodec_get_supported_config() +where available (lavc >= 61.13.100, FFmpeg 7.1+) and fall back to the +legacy AVCodec struct members on older versions. NULL now means +unrestricted instead of being dereferenced, hardening both paths. + +camera/ffmpeg: version-gate const-ness of the AVInputFormat/AVCodec +pointers; lavf 59 (FFmpeg 5.0) made that API const-correct, lavf 58 +(FFmpeg 4.x, the driver's minimum) warns on const pointers. + +Verified: compile matrix with production flags against FFmpeg 3.4.13, +4.4.5, 5.1.6, 6.1.2, 7.1.1, 8.1.2 and 9.0 all clean; full configure + +make against FFmpeg 9.0 builds and links; resolver logic runtime-tested +under ASan/UBSan against FFmpeg 9.0 (new path) and 6.1.2 (legacy path) +with identical results and no sanitizer findings. +--- + camera/drivers/ffmpeg.c | 17 +++++++- + record/drivers/record_ffmpeg.c | 71 +++++++++++++++++++++++++++++----- + 2 files changed, 76 insertions(+), 12 deletions(-) + +diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c +index 2c0e68adade4..f12f55690465 100644 +--- a/camera/drivers/ffmpeg.c ++++ b/camera/drivers/ffmpeg.c +@@ -58,13 +58,26 @@ extern "C" { + #define FFMPEG_CAMERA_DEFAULT_BACKEND "lavfi" + #endif + ++/* lavf 59 (FFmpeg 5.0) made the demuxer/codec discovery API const-correct: ++ * av_find_input_format() returns const AVInputFormat*, avformat_open_input() ++ * accepts one, and av_find_best_stream() takes const AVCodec**. Older ++ * versions use mutable pointers throughout, so a single const-qualified ++ * declaration cannot satisfy both. */ ++#if LIBAVFORMAT_VERSION_MAJOR >= 59 ++typedef const AVInputFormat ffmpeg_camera_input_format_t; ++typedef const AVCodec ffmpeg_camera_codec_t; ++#else ++typedef AVInputFormat ffmpeg_camera_input_format_t; ++typedef AVCodec ffmpeg_camera_codec_t; ++#endif ++ + typedef struct ffmpeg_camera + { + sthread_t *poll_thread; + AVFormatContext *format_context; + AVCodecContext *decoder_context; +- const AVCodec *decoder; +- const AVInputFormat *input_format; /* owned by ffmpeg, don't free it */ ++ ffmpeg_camera_codec_t *decoder; /* owned by ffmpeg, don't free it */ ++ ffmpeg_camera_input_format_t *input_format; /* owned by ffmpeg, don't free it */ + AVDictionary *options; + AVPacket *packet; + AVFrame *camera_frame; +diff --git a/record/drivers/record_ffmpeg.c b/record/drivers/record_ffmpeg.c +index fc801af0b34e..5f72f2b87241 100644 +--- a/record/drivers/record_ffmpeg.c ++++ b/record/drivers/record_ffmpeg.c +@@ -79,6 +79,15 @@ extern "C" { + #define FFMPEG8 (LIBAVCODEC_VERSION_MAJOR >= 62) + #endif + ++/* avcodec_get_supported_config() was added in lavc 61.13.100 (FFmpeg 7.1) ++ * and the AVCodec.sample_fmts / AVCodec.supported_samplerates arrays it ++ * replaces were deprecated at the same time, then removed entirely in ++ * lavc 63 (FFmpeg 9). Use the new API as soon as it is available so a ++ * single codepath covers FFmpeg 7.1 through 9+, and keep the old struct ++ * members for FFmpeg 7.0 and older. */ ++#define HAVE_AVCODEC_GET_SUPPORTED_CONFIG \ ++ (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100)) ++ + #ifndef AV_INPUT_BUFFER_MIN_SIZE + #define AV_INPUT_BUFFER_MIN_SIZE 16384 + #endif +@@ -216,11 +225,48 @@ typedef struct ffmpeg + + AVFormatContext *ctx; + ++/* Returns the encoder's list of supported sample formats, terminated by ++ * AV_SAMPLE_FMT_NONE, or NULL if the encoder does not restrict sample ++ * formats (or the list could not be queried). */ ++static const enum AVSampleFormat *ffmpeg_codec_sample_formats( ++ const AVCodec *codec) ++{ ++#if HAVE_AVCODEC_GET_SUPPORTED_CONFIG ++ const void *fmts = NULL; ++ if (avcodec_get_supported_config(NULL, codec, ++ AV_CODEC_CONFIG_SAMPLE_FORMAT, 0, &fmts, NULL) < 0) ++ return NULL; ++ return (const enum AVSampleFormat*)fmts; ++#else ++ return codec->sample_fmts; ++#endif ++} ++ ++/* Returns the encoder's list of supported sample rates, terminated by 0, ++ * or NULL if the encoder does not restrict sample rates (or the list ++ * could not be queried). */ ++static const int *ffmpeg_codec_supported_samplerates(const AVCodec *codec) ++{ ++#if HAVE_AVCODEC_GET_SUPPORTED_CONFIG ++ const void *rates = NULL; ++ if (avcodec_get_supported_config(NULL, codec, ++ AV_CODEC_CONFIG_SAMPLE_RATE, 0, &rates, NULL) < 0) ++ return NULL; ++ return (const int*)rates; ++#else ++ return codec->supported_samplerates; ++#endif ++} ++ + static bool ffmpeg_codec_has_sample_format(enum AVSampleFormat fmt, + const enum AVSampleFormat *fmts) + { + unsigned i; + ++ /* A NULL list means the encoder does not restrict sample formats. */ ++ if (!fmts) ++ return true; ++ + for (i = 0; fmts[i] != AV_SAMPLE_FMT_NONE; i++) + if (fmt == fmts[i]) + return true; +@@ -230,30 +276,32 @@ static bool ffmpeg_codec_has_sample_format(enum AVSampleFormat fmt, + static void ffmpeg_audio_resolve_format(struct ff_audio_info *audio, + const AVCodec *codec) + { ++ const enum AVSampleFormat *sample_fmts = ffmpeg_codec_sample_formats(codec); ++ + audio->codec->sample_fmt = AV_SAMPLE_FMT_NONE; + +- if (ffmpeg_codec_has_sample_format(AV_SAMPLE_FMT_FLTP, codec->sample_fmts)) ++ if (ffmpeg_codec_has_sample_format(AV_SAMPLE_FMT_FLTP, sample_fmts)) + { + audio->codec->sample_fmt = AV_SAMPLE_FMT_FLTP; + audio->use_float = true; + audio->is_planar = true; + RARCH_LOG("[FFmpeg] Using sample format FLTP.\n"); + } +- else if (ffmpeg_codec_has_sample_format(AV_SAMPLE_FMT_FLT, codec->sample_fmts)) ++ else if (ffmpeg_codec_has_sample_format(AV_SAMPLE_FMT_FLT, sample_fmts)) + { + audio->codec->sample_fmt = AV_SAMPLE_FMT_FLT; + audio->use_float = true; + audio->is_planar = false; + RARCH_LOG("[FFmpeg] Using sample format FLT.\n"); + } +- else if (ffmpeg_codec_has_sample_format(AV_SAMPLE_FMT_S16P, codec->sample_fmts)) ++ else if (ffmpeg_codec_has_sample_format(AV_SAMPLE_FMT_S16P, sample_fmts)) + { + audio->codec->sample_fmt = AV_SAMPLE_FMT_S16P; + audio->use_float = false; + audio->is_planar = true; + RARCH_LOG("[FFmpeg] Using sample format S16P.\n"); + } +- else if (ffmpeg_codec_has_sample_format(AV_SAMPLE_FMT_S16, codec->sample_fmts)) ++ else if (ffmpeg_codec_has_sample_format(AV_SAMPLE_FMT_S16, sample_fmts)) + { + audio->codec->sample_fmt = AV_SAMPLE_FMT_S16; + audio->use_float = false; +@@ -268,21 +316,24 @@ static void ffmpeg_audio_resolve_sample_rate(ffmpeg_t *handle, + { + struct ff_config_param *params = &handle->config; + struct record_params *param = &handle->params; ++ const int *supported_samplerates = ffmpeg_codec_supported_samplerates(codec); + +- /* We'll have to force resampling to some supported sampling rate. */ +- if (codec->supported_samplerates && !params->sample_rate) ++ /* We'll have to force resampling to some supported sampling rate. ++ * A NULL list means the encoder accepts any sample rate, in which ++ * case the input rate is kept as-is. */ ++ if (supported_samplerates && !params->sample_rate) + { + unsigned i; + int input_rate = (int)param->samplerate; + + /* Favor closest sampling rate, but always prefer ratio > 1.0. */ +- int best_rate = codec->supported_samplerates[0]; ++ int best_rate = supported_samplerates[0]; + int best_diff = best_rate - input_rate; + +- for (i = 1; codec->supported_samplerates[i]; i++) ++ for (i = 1; supported_samplerates[i]; i++) + { + bool better_rate = false; +- int diff = codec->supported_samplerates[i] - input_rate; ++ int diff = supported_samplerates[i] - input_rate; + + if (best_diff < 0) + better_rate = (diff > best_diff); +@@ -291,7 +342,7 @@ static void ffmpeg_audio_resolve_sample_rate(ffmpeg_t *handle, + + if (better_rate) + { +- best_rate = codec->supported_samplerates[i]; ++ best_rate = supported_samplerates[i]; + best_diff = diff; + } + } diff --git a/projects/ROCKNIX/packages/emulators/libretro/uae4arm/patches/uae4arm-0001-fix-std-numbers-ambiguity.patch b/projects/ROCKNIX/packages/emulators/libretro/uae4arm/patches/uae4arm-0001-fix-std-numbers-ambiguity.patch new file mode 100644 index 00000000000..57d5f5dcdf6 --- /dev/null +++ b/projects/ROCKNIX/packages/emulators/libretro/uae4arm/patches/uae4arm-0001-fix-std-numbers-ambiguity.patch @@ -0,0 +1,29 @@ +From: Chips-fr upstream +Subject: [PATCH] Fix ambiguous numbers symbol conflict with std::numbers (GCC 16) + +Backport of upstream 4c7e3a86e2: libstdc++ 16 exposes the C++20 +std::numbers namespace via , which combined with using +namespace std makes the file-static numbers array ambiguous. +Rename it to td_numbers. + +--- a/src/statusline.cpp ++++ b/src/statusline.cpp +@@ -32,7 +32,7 @@ extern SDL_Surface *prSDLScreen; + * Some code to put status information on the screen. + */ + +-static const char *numbers = { /* ugly 0123456789CHD%+-PNK */ ++static const char *td_numbers = { /* ugly 0123456789CHD%+-PNK */ + "+++++++--++++-+++++++++++++++++-++++++++++++++++++++++++++++++++++++++++++++-++++++-++++----++---+--------------+++++++++++++++++++++" + "+xxxxx+--+xx+-+xxxxx++xxxxx++x+-+x++xxxxx++xxxxx++xxxxx++xxxxx++xxxxx++xxxx+-+x++x+-+xxx++-+xx+-+x---+----------+xxxxx++x+++x++x++x++" + "+x+++x+--++x+-+++++x++++++x++x+++x++x++++++x++++++++++x++x+++x++x+++x++x++++-+x++x+-+x++x+--+x++x+--+x+----+++--+x---x++xx++x++x+x+++" +@@ -53,7 +53,7 @@ static void write_tdnumber (uae_u8 *buf, int x, int y, int num, uae_u32 c1, uae_ + int j; + const char *numptr; + +- numptr = numbers + num * TD_NUM_WIDTH + NUMBERS_NUM * TD_NUM_WIDTH * y; ++ numptr = td_numbers + num * TD_NUM_WIDTH + NUMBERS_NUM * TD_NUM_WIDTH * y; + for (j = 0; j < TD_NUM_WIDTH; j++) { + if (*numptr == 'x') + putpixel (buf, x + j, c1); + diff --git a/projects/ROCKNIX/packages/emulators/standalone/armsx2-sa/patches/armsx2-0100-ffmpeg9-lavc63.patch b/projects/ROCKNIX/packages/emulators/standalone/armsx2-sa/patches/armsx2-0100-ffmpeg9-lavc63.patch new file mode 100644 index 00000000000..10449c04353 --- /dev/null +++ b/projects/ROCKNIX/packages/emulators/standalone/armsx2-sa/patches/armsx2-0100-ffmpeg9-lavc63.patch @@ -0,0 +1,124 @@ +Subject: [PATCH] GSCapture: query codec formats via avcodec_get_supported_config + +AVCodec.pix_fmts and .sample_fmts were deprecated in lavc 61.13.100 and +removed in lavc 63 (FFmpeg 9), so GSCapture.cpp does not compile. Query +them through avcodec_get_supported_config() instead, resolved from the +same dynamically loaded avcodec as the rest of the file, and keep the old +struct members for FFmpeg 7.0 and older. + +Not fixed upstream in either ARMSX2 or PCSX2 as of this writing. + +diff --git a/pcsx2/GS/GSCapture.cpp b/pcsx2/GS/GSCapture.cpp +--- a/pcsx2/GS/GSCapture.cpp ++++ b/pcsx2/GS/GSCapture.cpp +@@ -67,6 +67,7 @@ + X(avcodec_receive_packet) \ + X(avcodec_parameters_from_context) \ + X(avcodec_get_hw_config) \ ++ X(avcodec_get_supported_config) \ + X(av_codec_iterate) \ + X(av_packet_alloc) \ + X(av_packet_free) \ +@@ -230,6 +231,37 @@ + VISIT_SWRESAMPLE_IMPORTS(DECLARE_IMPORT); + #undef DECLARE_IMPORT + ++// AVCodec.pix_fmts and AVCodec.sample_fmts were deprecated in lavc 61.13.100 ++// (FFmpeg 7.1) in favour of avcodec_get_supported_config(), and removed in ++// lavc 63 (FFmpeg 9). Query through the new call, which is resolved from the ++// same dynamically loaded avcodec as everything else here. ++#define HAVE_AVCODEC_GET_SUPPORTED_CONFIG \ ++ (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100)) ++ ++static const AVPixelFormat* GetCodecPixelFormats(const AVCodec* codec) ++{ ++#if HAVE_AVCODEC_GET_SUPPORTED_CONFIG ++ const void* fmts = nullptr; ++ if (wrap_avcodec_get_supported_config(nullptr, codec, AV_CODEC_CONFIG_PIX_FORMAT, 0, &fmts, nullptr) < 0) ++ return nullptr; ++ return static_cast(fmts); ++#else ++ return codec->pix_fmts; ++#endif ++} ++ ++static const AVSampleFormat* GetCodecSampleFormats(const AVCodec* codec) ++{ ++#if HAVE_AVCODEC_GET_SUPPORTED_CONFIG ++ const void* fmts = nullptr; ++ if (wrap_avcodec_get_supported_config(nullptr, codec, AV_CODEC_CONFIG_SAMPLE_FORMAT, 0, &fmts, nullptr) < 0) ++ return nullptr; ++ return static_cast(fmts); ++#else ++ return codec->sample_fmts; ++#endif ++} ++ + // We could refcount this, but really, may as well just load it and pay the cost once. + // Not like we need to save a few megabytes of memory... + #ifndef USE_LINKED_FFMPEG +@@ -454,14 +486,15 @@ + // Default to NV12 if not overridden by the user + const AVPixelFormat preferred_sw_pix_fmt = GSConfig.VideoCaptureFormat.empty() ? AV_PIX_FMT_NV12 : static_cast(std::stoi(GSConfig.VideoCaptureFormat)); + AVPixelFormat sw_pix_fmt = preferred_sw_pix_fmt; +- if (vcodec->pix_fmts) ++ const AVPixelFormat* vcodec_pix_fmts = GetCodecPixelFormats(vcodec); ++ if (vcodec_pix_fmts) + { +- sw_pix_fmt = vcodec->pix_fmts[0]; +- for (u32 i = 0; vcodec->pix_fmts[i] != AV_PIX_FMT_NONE; i++) ++ sw_pix_fmt = vcodec_pix_fmts[0]; ++ for (u32 i = 0; vcodec_pix_fmts[i] != AV_PIX_FMT_NONE; i++) + { +- if (vcodec->pix_fmts[i] == preferred_sw_pix_fmt) ++ if (vcodec_pix_fmts[i] == preferred_sw_pix_fmt) + { +- sw_pix_fmt = vcodec->pix_fmts[i]; ++ sw_pix_fmt = vcodec_pix_fmts[i]; + break; + } + } +@@ -686,7 +719,8 @@ + #endif + + bool supports_format = false; +- for (const AVSampleFormat* p = acodec->sample_fmts; *p != AV_SAMPLE_FMT_NONE; p++) ++ const AVSampleFormat* acodec_sample_fmts = GetCodecSampleFormats(acodec); ++ for (const AVSampleFormat* p = acodec_sample_fmts; p && *p != AV_SAMPLE_FMT_NONE; p++) + { + if (*p == s_audio_codec_context->sample_fmt) + { +@@ -694,10 +728,10 @@ + break; + } + } +- if (!supports_format) ++ if (!supports_format && acodec_sample_fmts) + { + Console.WriteLn(fmt::format("Audio codec '{}' does not support float samples, using default.", acodec->name)); +- s_audio_codec_context->sample_fmt = acodec->sample_fmts[0]; ++ s_audio_codec_context->sample_fmt = acodec_sample_fmts[0]; + s_swr_context = wrap_swr_alloc(); + if (!s_swr_context) + { +@@ -1533,15 +1567,16 @@ + } + + // rawvideo doesn't have a list of formats. +- if (v_codec->pix_fmts == nullptr) ++ const AVPixelFormat* v_codec_pix_fmts = GetCodecPixelFormats(v_codec); ++ if (v_codec_pix_fmts == nullptr) + { +- Console.Error("(GetVideoFormatList) v_codec->pix_fmts is null."); ++ Console.Error("(GetVideoFormatList) codec pixel format list is null."); + return ret; + } + +- for (int i = 0; v_codec->pix_fmts[i] != AVPixelFormat::AV_PIX_FMT_NONE; i++) ++ for (int i = 0; v_codec_pix_fmts[i] != AVPixelFormat::AV_PIX_FMT_NONE; i++) + { +- ret.emplace_back(v_codec->pix_fmts[i], wrap_av_get_pix_fmt_name(v_codec->pix_fmts[i])); ++ ret.emplace_back(v_codec_pix_fmts[i], wrap_av_get_pix_fmt_name(v_codec_pix_fmts[i])); + } + + return ret; diff --git a/projects/ROCKNIX/packages/emulators/standalone/daedalusx64-sa/package.mk b/projects/ROCKNIX/packages/emulators/standalone/daedalusx64-sa/package.mk index 606d58ef8b9..cc48fdffc98 100644 --- a/projects/ROCKNIX/packages/emulators/standalone/daedalusx64-sa/package.mk +++ b/projects/ROCKNIX/packages/emulators/standalone/daedalusx64-sa/package.mk @@ -29,7 +29,7 @@ pre_configure_target() { makeinstall_target() { if [ "${ARCH}" = "aarch64" ]; then mkdir -p ${INSTALL}/usr - cp -r ${ROOT}/build.${DISTRO}-${DEVICE}.arm/install_pkg/daedalusx64-sa-${PKG_VERSION}/usr/* ${INSTALL}/usr/ + cp -r ${BUILD_ROOT}/build.${DISTRO}-${DEVICE}.arm/install_pkg/daedalusx64-sa-${PKG_VERSION}/usr/* ${INSTALL}/usr/ chmod +x ${INSTALL}/usr/bin/* else mkdir -p ${INSTALL}/usr/bin diff --git a/projects/ROCKNIX/packages/emulators/standalone/dolphin-sa/package.mk b/projects/ROCKNIX/packages/emulators/standalone/dolphin-sa/package.mk index c2c979503d8..8bdc4a47b78 100644 --- a/projects/ROCKNIX/packages/emulators/standalone/dolphin-sa/package.mk +++ b/projects/ROCKNIX/packages/emulators/standalone/dolphin-sa/package.mk @@ -59,11 +59,17 @@ post_unpack() { } pre_configure_target() { - PKG_CMAKE_OPTS_TARGET+=" -DCMAKE_BUILD_TYPE=Release \ + # The vendored mbedtls defaults MBEDTLS_FATAL_WARNINGS to ON, and that is + # the only thing adding -Werror anywhere in this tree. gcc 16 then stops + # on a dead local in its bignum.c. Warnings-as-errors is for mbedtls' own + # CI, not for a consumer building a pinned copy of it. + PKG_CMAKE_OPTS_TARGET+=" -DMBEDTLS_FATAL_WARNINGS=OFF \ + -DCMAKE_BUILD_TYPE=Release \ -DDISTRIBUTOR="ROCKNIX" \ -DENABLE_NOGUI=ON \ -DENABLE_EVDEV=ON \ -DENABLE_SDL=ON \ + -DSDL_PIPEWIRE=OFF \ -DUSE_DISCORD_PRESENCE=OFF \ -DBUILD_SHARED_LIBS=OFF \ -DLINUX_LOCAL_DEV=OFF \ diff --git a/projects/ROCKNIX/packages/emulators/standalone/gopher64-sa/package.mk b/projects/ROCKNIX/packages/emulators/standalone/gopher64-sa/package.mk index 561a94d4450..d87ac1cfcc3 100644 --- a/projects/ROCKNIX/packages/emulators/standalone/gopher64-sa/package.mk +++ b/projects/ROCKNIX/packages/emulators/standalone/gopher64-sa/package.mk @@ -40,6 +40,13 @@ make_target() { " export SKIA_BINARIES_URL="https://github.com/rust-skia/skia-binaries/releases/download/0.90.0/skia-binaries-da4579b39b75fa2187c5-aarch64-unknown-linux-gnu-gl-pdf-textlayout-vulkan.tar.gz" + # rustc 1.95 destabilised custom target JSON specs (rust-lang/rust#150151): + # loading one now needs -Zunstable-options, and -Z needs a nightly or + # bootstrapped compiler. Our TARGET_NAME is a custom triple, so this is + # unavoidable - the kernel does the same for its own custom targets. + export RUSTC_BOOTSTRAP=1 + export RUSTFLAGS="${RUSTFLAGS} -Zunstable-options" + cargo build \ --target ${TARGET_NAME} \ --no-default-features \ diff --git a/projects/ROCKNIX/packages/emulators/standalone/touchhle-sa/package.mk b/projects/ROCKNIX/packages/emulators/standalone/touchhle-sa/package.mk index 0a21a6d542f..640aadebda6 100644 --- a/projects/ROCKNIX/packages/emulators/standalone/touchhle-sa/package.mk +++ b/projects/ROCKNIX/packages/emulators/standalone/touchhle-sa/package.mk @@ -6,28 +6,28 @@ PKG_LICENSE="MPLv2" PKG_VERSION="3c5850585ba55615b17a58c58331b6d6f52d4a9d" PKG_SITE="https://github.com/touchHLE/touchHLE" PKG_URL="${PKG_SITE}.git" -PKG_DEPENDS_TARGET="toolchain cargo:host cargo rust SDL2 sndio libsamplerate" +PKG_DEPENDS_TARGET="toolchain cargo:host cargo rust SDL2 openal-soft sndio libsamplerate" PKG_LONGDESC="touchHLE: high-level emulator for iPhone OS apps" PKG_TOOLCHAIN="manual" -post_unpack() { - cd ${PKG_BUILD}/vendor/openal-soft - sed -i 's/false,/AL_FALSE_ENUM,/g' alc/backends/sdl2.c 2>/dev/null || true - sed -i 's/enum CompatFlags : uint8_t/enum CompatFlags/g' alc/alu.h - sed -i 's/enum class UhjQualityType : uint8_t/enum UhjQualityType/g' core/uhjfilter.h - # Disable JACK backend (avoids needing jack/jack.h in sysroot) - sed -i '/build.define("ALSOFT_EXAMPLES", "OFF");/a\ build.define("ALSOFT_BACKEND_JACK", "OFF");' ${PKG_BUILD}/src/audio/openal_soft_wrapper/build.rs -} - make_target() { unset CMAKE export RUSTFLAGS="-C link-arg=-lasound" export CMAKE_POLICY_VERSION_MINIMUM="3.5" export CFLAGS="${CFLAGS} -std=gnu11" - export CMAKE_ARGS="${CMAKE_ARGS} -DALSOFT_BACKEND_JACK=OFF" + # rustc 1.95 destabilised custom target JSON specs (rust-lang/rust#150151): + # loading one now needs -Zunstable-options, and -Z needs a nightly or + # bootstrapped compiler. Our TARGET_NAME is a custom triple, so this is + # unavoidable - the kernel does the same for its own custom targets. + export RUSTC_BOOTSTRAP=1 + export RUSTFLAGS="${RUSTFLAGS} -Zunstable-options" + # touchHLE defaults to the "static" feature, which bundles its own SDL2 and + # openal-soft. The vendored SDL2 predates pipewire 1.6 and no longer builds, + # and we already ship both libraries, so link the system ones instead. cargo build \ + --no-default-features \ --target ${TARGET_NAME} \ --release } diff --git a/projects/ROCKNIX/packages/emulators/standalone/vita3k-sa/patches/vita3k-sa-0001-mem-add-missing-cstdint-include.patch b/projects/ROCKNIX/packages/emulators/standalone/vita3k-sa/patches/vita3k-sa-0001-mem-add-missing-cstdint-include.patch new file mode 100644 index 00000000000..264560f05b5 --- /dev/null +++ b/projects/ROCKNIX/packages/emulators/standalone/vita3k-sa/patches/vita3k-sa-0001-mem-add-missing-cstdint-include.patch @@ -0,0 +1,18 @@ +From: Vita3K upstream +Subject: [PATCH] mem: Add missing include for latest GCC/Clang (#3915) + +Backport of upstream 9f955b8f0e: atomic.h uses uint16_t/uint32_t/ +uint64_t without including ; libstdc++ 16 no longer provides +it transitively. + +--- a/vita3k/mem/include/mem/atomic.h ++++ b/vita3k/mem/include/mem/atomic.h +@@ -17,6 +17,7 @@ + + #pragma once + ++#include + #include + + #ifdef _MSC_VER + diff --git a/projects/ROCKNIX/packages/emulators/standalone/yabasanshiro-sa/patches/06-boost-drop-removed-system-component.patch b/projects/ROCKNIX/packages/emulators/standalone/yabasanshiro-sa/patches/06-boost-drop-removed-system-component.patch new file mode 100644 index 00000000000..9f7d8d69ff8 --- /dev/null +++ b/projects/ROCKNIX/packages/emulators/standalone/yabasanshiro-sa/patches/06-boost-drop-removed-system-component.patch @@ -0,0 +1,15 @@ +Boost.System has been header-only since 1.69 and 1.91 dropped the compiled +stub along with its CMake config, so requesting it as a component fails the +configure. The remaining components pull in the headers. + +--- a/yabause/src/retro_arena/CMakeLists.txt ++++ b/yabause/src/retro_arena/CMakeLists.txt +@@ -10,7 +10,7 @@ + find_package(OpenGLES) + find_package(PkgConfig REQUIRED) + +-find_package(Boost REQUIRED COMPONENTS system filesystem date_time locale) ++find_package(Boost REQUIRED COMPONENTS filesystem date_time locale) + + if (NOT OPENGLES2_FOUND) + return() diff --git a/projects/ROCKNIX/packages/emulators/standalone/yabasanshiro-sa/patches/07-scsp-fix-linux-timed-wait.patch b/projects/ROCKNIX/packages/emulators/standalone/yabasanshiro-sa/patches/07-scsp-fix-linux-timed-wait.patch new file mode 100644 index 00000000000..60893558d48 --- /dev/null +++ b/projects/ROCKNIX/packages/emulators/standalone/yabasanshiro-sa/patches/07-scsp-fix-linux-timed-wait.patch @@ -0,0 +1,41 @@ +The ARCH_IS_LINUX sound thread built its wait deadline with time(), which +takes a time_t and so leaves tv_nsec uninitialised, then handed +pthread_cond_timedwait the result of ctime() - a char* into a static +buffer - where a struct timespec was expected. The deadline was therefore +read out of ASCII text and the wait returned EINVAL immediately, skipping +the 68k and SCSP stepping that the rtn == 0 branch guards. The ANDROID +branch a few lines up already does this correctly. + +Also normalise tv_nsec, pthread_cond_timedwait requires it below one +second and adding sleeptime can carry past that. + +--- a/yabause/src/scsp.c ++++ b/yabause/src/scsp.c +@@ -151,6 +151,7 @@ + #include "sys/resource.h" + #include + #include ++#include + pthread_cond_t sync_cnd = PTHREAD_COND_INITIALIZER; + pthread_mutex_t sync_mutex = PTHREAD_MUTEX_INITIALIZER; + #endif +@@ -5672,14 +5673,14 @@ + } + pthread_mutex_unlock(&sync_mutex); + #elif defined(ARCH_IS_LINUX) +- time(&tm); +- long n = tm.tv_nsec; ++ clock_gettime(CLOCK_REALTIME, &tm); + tm.tv_nsec += sleeptime; +- if( n > tm.tv_nsec){ +- tm.tv_sec += 1; ++ if (tm.tv_nsec >= 1000000000L) { ++ tm.tv_sec += tm.tv_nsec / 1000000000L; ++ tm.tv_nsec %= 1000000000L; + } + pthread_mutex_lock(&sync_mutex); +- int rtn = pthread_cond_timedwait(&sync_cnd,&sync_mutex,ctime(&tm)); ++ int rtn = pthread_cond_timedwait(&sync_cnd,&sync_mutex,&tm); + if(rtn == 0){ + for (i = 0; i < samplecnt; i += step) { + MM68KExec(step); diff --git a/projects/ROCKNIX/packages/graphics/SDL2/package.mk b/projects/ROCKNIX/packages/graphics/SDL2/package.mk index 6c9bd5847b1..a8587e1d801 100644 --- a/projects/ROCKNIX/packages/graphics/SDL2/package.mk +++ b/projects/ROCKNIX/packages/graphics/SDL2/package.mk @@ -7,7 +7,7 @@ PKG_VERSION="2.32.10" PKG_LICENSE="GPL" PKG_SITE="https://www.libsdl.org/" PKG_URL="https://www.libsdl.org/release/SDL2-${PKG_VERSION}.tar.gz" -PKG_DEPENDS_TARGET="toolchain alsa-lib systemd dbus pulseaudio libdrm SDL2:host libX11:host" +PKG_DEPENDS_TARGET="toolchain alsa-lib systemd dbus pulseaudio libdrm SDL2:host" PKG_LONGDESC="Simple DirectMedia Layer is a cross-platform development library designed to provide low level access to audio, keyboard, mouse, joystick, and graphics hardware." PKG_DEPENDS_HOST="toolchain:host distutilscross:host" diff --git a/projects/ROCKNIX/packages/graphics/cairo/package.mk b/projects/ROCKNIX/packages/graphics/cairo/package.mk index 32f4462de03..574e9df30ef 100644 --- a/projects/ROCKNIX/packages/graphics/cairo/package.mk +++ b/projects/ROCKNIX/packages/graphics/cairo/package.mk @@ -3,11 +3,11 @@ # Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv) PKG_NAME="cairo" -PKG_VERSION="1.17.8" -PKG_SHA256="5b10c8892d1b58d70d3f0ba5b47863a061262fa56b9dc7944161f8c8b783bc64" +PKG_VERSION="1.18.4" +PKG_SHA256="445ed8208a6e4823de1226a74ca319d3600e83f6369f99b14265006599c32ccb" PKG_LICENSE="LGPL" PKG_SITE="https://cairographics.org/" -PKG_URL="https://cairographics.org/snapshots/${PKG_NAME}-${PKG_VERSION}.tar.xz" +PKG_URL="https://cairographics.org/releases/${PKG_NAME}-${PKG_VERSION}.tar.xz" PKG_DEPENDS_TARGET="toolchain zlib freetype fontconfig glib libpng pixman" PKG_LONGDESC="Cairo is a vector graphics library with cross-device output support." @@ -36,7 +36,6 @@ pre_configure_target() { -Dquartz=disabled \ -Dtee=disabled \ -Dtests=disabled \ - -Dxml=disabled \ -Dzlib=enabled \ -Dgtk2-utils=disabled \ -Dglib=enabled \ @@ -56,5 +55,4 @@ pre_configure_target() { -Dxlib-xcb=disabled" ;; esac - sed -i "s~'ipc_rmid_deferred_release', 'auto'~'ipc_rmid_deferred_release', 'true'~g" ${PKG_BUILD}/meson.build } diff --git a/projects/ROCKNIX/packages/graphics/gdk-pixbuf/package.mk b/projects/ROCKNIX/packages/graphics/gdk-pixbuf/package.mk index eade5b1f4a7..01da7c06cc5 100644 --- a/projects/ROCKNIX/packages/graphics/gdk-pixbuf/package.mk +++ b/projects/ROCKNIX/packages/graphics/gdk-pixbuf/package.mk @@ -3,11 +3,11 @@ # Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv) PKG_NAME="gdk-pixbuf" -PKG_VERSION="2.42.10" -PKG_SHA256="ee9b6c75d13ba096907a2e3c6b27b61bcd17f5c7ebeab5a5b439d2f2e39fe44b" +PKG_VERSION="2.44.7" +PKG_SHA256="172f80e3626ec31520a970400f1a3694e04718f6c2cd2885f75250fb5a6995a4" PKG_LICENSE="OSS" PKG_SITE="http://www.gtk.org/" -PKG_URL="https://www.mirrorservice.org/sites/ftp.gnome.org//pub/GNOME/sources/gdk-pixbuf/${PKG_VERSION:0:4}/gdk-pixbuf-${PKG_VERSION}.tar.xz" +PKG_URL="https://ftp.gnome.org/pub/gnome/sources/gdk-pixbuf/${PKG_VERSION:0:4}/gdk-pixbuf-${PKG_VERSION}.tar.xz" PKG_DEPENDS_TARGET="toolchain glib libjpeg-turbo libpng jasper shared-mime-info tiff zlib" PKG_DEPENDS_CONFIG="shared-mime-info" PKG_LONGDESC="GdkPixbuf is a a GNOME library for image loading and manipulation." @@ -20,8 +20,8 @@ configure_package() { pre_configure_target() { PKG_MESON_OPTS_TARGET="--wrap-mode=nodownload \ - -Dgtk_doc=false \ - -Ddocs=false \ + -Ddocumentation=false \ + -Dglycin=disabled \ -Dintrospection=disabled \ -Dman=false \ -Drelocatable=false \ diff --git a/projects/ROCKNIX/packages/graphics/glew/package.mk b/projects/ROCKNIX/packages/graphics/glew/package.mk index 946187e5c50..a680ef92e7e 100644 --- a/projects/ROCKNIX/packages/graphics/glew/package.mk +++ b/projects/ROCKNIX/packages/graphics/glew/package.mk @@ -2,10 +2,11 @@ # Copyright (C) 2022-present JELOS (https://github.com/JustEnoughLinuxOS) PKG_NAME="glew" -PKG_VERSION="2.2.0" +PKG_VERSION="2.3.1" +PKG_SHA256="b64790f94b926acd7e8f84c5d6000a86cb43967bd1e688b03089079799c9e889" PKG_LICENSE="BSD" PKG_SITE="http://glew.sourceforge.net/" -PKG_URL="${SOURCEFORGE_SRC}/glew/glew/${PKG_VERSION}/${PKG_NAME}-${PKG_VERSION}.tgz" +PKG_URL="https://downloads.sourceforge.net/project/glew/glew/${PKG_VERSION}/${PKG_NAME}-${PKG_VERSION}.tgz" PKG_DEPENDS_TARGET="toolchain" PKG_LONGDESC="GLEW - The OpenGL Extension Wrangler Library" PKG_TOOLCHAIN="cmake" diff --git a/projects/ROCKNIX/packages/graphics/glslang/package.mk b/projects/ROCKNIX/packages/graphics/glslang/package.mk index 1fdbe83a12b..5ed04cff7e3 100755 --- a/projects/ROCKNIX/packages/graphics/glslang/package.mk +++ b/projects/ROCKNIX/packages/graphics/glslang/package.mk @@ -2,49 +2,8 @@ # Copyright (C) 2021-present Frank Hartung (supervisedthinking (@) gmail.com) # Copyright (C) 2021-present Team LibreELEC (https://libreelec.tv) -PKG_NAME="glslang" -# The SPIRV-Tools & SPIRV-Headers pkg_version/s need to match the compatible (known_good) glslang pkg_version. -# https://raw.githubusercontent.com/KhronosGroup/glslang/${PKG_VERSION}/known_good.json -# When updating glslang pkg_version please update to the known_good spirv-tools & spirv-headers pkg_version/s. -PKG_VERSION="15.1.0" -PKG_LICENSE="Apache-2.0" -PKG_SITE="https://github.com/KhronosGroup/glslang" -PKG_URL="https://github.com/KhronosGroup/glslang/archive/${PKG_VERSION}.tar.gz" -PKG_DEPENDS_HOST="toolchain:host Python3:host" -PKG_DEPENDS_TARGET="toolchain Python3" -PKG_LONGDESC="Khronos-reference front end for GLSL/ESSL, partial front end for HLSL, and a SPIR-V generator." -PKG_DEPENDS_UNPACK="spirv-headers spirv-tools" +. ${ROOT}/packages/graphics/vulkan/glslang/package.mk -PKG_CMAKE_OPTS_COMMON="-DBUILD_EXTERNAL=ON \ - -DENABLE_SPVREMAPPER=OFF \ - -DENABLE_GLSLANG_JS=OFF \ - -DENABLE_RTTI=OFF \ - -DENABLE_EXCEPTIONS=OFF \ - -DENABLE_OPT=ON \ - -DENABLE_PCH=ON \ - -DGLSLANG_TESTS=OFF \ - -Wno-dev" - -post_unpack() { - # Enables SPIR-V optimzer capability needed for ENABLE_OPT CMake build option - mkdir -p ${PKG_BUILD}/External/spirv-tools - tar --strip-components=1 \ - -xf "${SOURCES}/spirv-tools/spirv-tools-$(get_pkg_version spirv-tools).tar.gz" \ - -C "${PKG_BUILD}/External/spirv-tools" - mkdir -p ${PKG_BUILD}/External/spirv-tools/external/spirv-headers - tar --strip-components=1 \ - -xf "${SOURCES}/spirv-headers/spirv-headers-$(get_pkg_version spirv-headers).tar.gz" \ - -C "${PKG_BUILD}/External/spirv-tools/external/spirv-headers" -} - -pre_configure_host() { - PKG_CMAKE_OPTS_HOST+="${PKG_CMAKE_OPTS_COMMON} \ - -DBUILD_SHARED_LIBS=OFF" - -} - -pre_configure_target() { - PKG_CMAKE_OPTS_TARGET+="${PKG_CMAKE_OPTS_COMMON} \ - -DBUILD_SHARED_LIBS=ON \ - -DENABLE_GLSLANG_BINARIES=OFF" -} +# the SPIR-V remapper is not used by anything we ship. Appending after the +# source works because the configure hooks expand this when they run. +PKG_CMAKE_OPTS_COMMON+=" -DENABLE_SPVREMAPPER=OFF" diff --git a/projects/ROCKNIX/packages/graphics/libdrm/package.mk b/projects/ROCKNIX/packages/graphics/libdrm/package.mk index 1ea529959f2..81674eeb084 100644 --- a/projects/ROCKNIX/packages/graphics/libdrm/package.mk +++ b/projects/ROCKNIX/packages/graphics/libdrm/package.mk @@ -1,21 +1,20 @@ - # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2009-2016 Stephan Raue (stephan@openelec.tv) # Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv) PKG_NAME="libdrm" -PKG_VERSION="2.4.128" -PKG_LICENSE="GPL" -PKG_SITE="http://dri.freedesktop.org" -PKG_URL="http://dri.freedesktop.org/libdrm/libdrm-${PKG_VERSION}.tar.xz" -PKG_DEPENDS_HOST="toolchain libpciaccess libdisplay-info" -PKG_DEPENDS_TARGET="toolchain libpciaccess libdisplay-info" +PKG_VERSION="2.4.134" +PKG_SHA256="ac5e74d157830eb8bee44c6a6bf3ad49774ef0dd2a72bdad74a8f20308b52a95" +PKG_LICENSE="MIT" +PKG_SITE="https://dri.freedesktop.org" +PKG_URL="https://dri.freedesktop.org/libdrm/libdrm-${PKG_VERSION}.tar.xz" +PKG_DEPENDS_HOST="toolchain:host" +PKG_DEPENDS_TARGET="toolchain libpciaccess" PKG_LONGDESC="The userspace interface library to kernel DRM services." -PKG_TOOLCHAIN="meson" get_graphicdrivers -PKG_MESON_OPTS_TARGET="-Dnouveau=disabled \ +PKG_MESON_OPTS_COMMON="-Dnouveau=disabled \ -Domap=disabled \ -Dexynos=disabled \ -Dtegra=disabled \ @@ -23,18 +22,38 @@ PKG_MESON_OPTS_TARGET="-Dnouveau=disabled \ -Dman-pages=disabled \ -Dvalgrind=disabled \ -Dfreedreno-kgsl=false \ - -Dinstall-test-programs=false \ -Dudev=false" -listcontains "${GRAPHIC_DRIVERS}" "(iris|i915|i965)" && +PKG_MESON_OPTS_HOST="${PKG_MESON_OPTS_COMMON} \ + -Damdgpu=disabled \ + -Detnaviv=disabled \ + -Dfreedreno=disabled \ + -Dintel=disabled \ + -Dradeon=disabled \ + -Dvc4=disabled \ + -Dvmwgfx=disabled \ + -Dtests=false \ + -Dinstall-test-programs=false" + +PKG_MESON_OPTS_TARGET="${PKG_MESON_OPTS_COMMON} \ + -Dtests=true \ + -Dinstall-test-programs=true" + +listcontains "${GRAPHIC_DRIVERS}" "(crocus|i915|iris)" && PKG_MESON_OPTS_TARGET+=" -Dintel=enabled" || PKG_MESON_OPTS_TARGET+=" -Dintel=disabled" -listcontains "${GRAPHIC_DRIVERS}" "(r200|r300|r600|radeonsi)" && +listcontains "${GRAPHIC_DRIVERS}" "(r300|r600|radeonsi)" && PKG_MESON_OPTS_TARGET+=" -Dradeon=enabled" || PKG_MESON_OPTS_TARGET+=" -Dradeon=disabled" listcontains "${GRAPHIC_DRIVERS}" "radeonsi" && PKG_MESON_OPTS_TARGET+=" -Damdgpu=enabled" || PKG_MESON_OPTS_TARGET+=" -Damdgpu=disabled" +listcontains "${GRAPHIC_DRIVERS}" "vmware" && + PKG_MESON_OPTS_TARGET+=" -Dvmwgfx=enabled" || PKG_MESON_OPTS_TARGET+=" -Dvmwgfx=disabled" + +listcontains "${GRAPHIC_DRIVERS}" "vc4" && + PKG_MESON_OPTS_TARGET+=" -Dvc4=enabled" || PKG_MESON_OPTS_TARGET+=" -Dvc4=disabled" + listcontains "${GRAPHIC_DRIVERS}" "freedreno" && PKG_MESON_OPTS_TARGET+=" -Dfreedreno=enabled" || PKG_MESON_OPTS_TARGET+=" -Dfreedreno=disabled" @@ -42,11 +61,24 @@ listcontains "${GRAPHIC_DRIVERS}" "etnaviv" && PKG_MESON_OPTS_TARGET+=" -Detnaviv=enabled" || PKG_MESON_OPTS_TARGET+=" -Detnaviv=disabled" post_makeinstall_target() { + # Remove all test programs installed by install-test-programs=true except modetest + PKG_LIBDRM_LIST="drmdevice modeprint proptest vbltest" + for PKG_LIBDRM_TEST in ${PKG_LIBDRM_LIST}; do + safe_remove ${INSTALL}/usr/bin/${PKG_LIBDRM_TEST} + done + + if listcontains "${GRAPHIC_DRIVERS}" "radeonsi"; then + safe_remove ${INSTALL}/usr/bin/amdgpu_stress + fi + + # modetest is kept, we use it for display bring-up mkdir -p ${INSTALL}/usr/bin cp -a ${PKG_BUILD}/.${TARGET_NAME}/tests/modetest/modetest ${INSTALL}/usr/bin/ - for header in xf86drm.h xf86drmMode.h - do - sed -i "s###g" ${SYSROOT_PREFIX}/usr/include/${header} - sed -i "s##g" ${SYSROOT_PREFIX}/usr/include/${header} - done + + # the installed headers include , which only resolves for consumers + # that add /usr/include/drm to their search path + for header in xf86drm.h xf86drmMode.h; do + sed -i "s###g" ${SYSROOT_PREFIX}/usr/include/${header} + sed -i "s##g" ${SYSROOT_PREFIX}/usr/include/${header} + done } diff --git a/projects/ROCKNIX/packages/graphics/libglvnd/package.mk b/projects/ROCKNIX/packages/graphics/libglvnd/package.mk index e9624786706..ba3bd0148df 100644 --- a/projects/ROCKNIX/packages/graphics/libglvnd/package.mk +++ b/projects/ROCKNIX/packages/graphics/libglvnd/package.mk @@ -3,6 +3,7 @@ PKG_NAME="libglvnd" PKG_VERSION="1.7.0" +PKG_SHA256="073e7292788d4d3eeb45ea6c7bdcce9bfdb3b3eef8d7dbd47f2f30dce046ef98" PKG_LICENSE="GPL" PKG_SITE="https://github.com/NVIDIA/libglvnd" PKG_URL="https://github.com/NVIDIA/libglvnd/archive/v${PKG_VERSION}.tar.gz" diff --git a/projects/ROCKNIX/packages/graphics/libpng/package.mk b/projects/ROCKNIX/packages/graphics/libpng/package.mk index 192822987a5..b3401178483 100644 --- a/projects/ROCKNIX/packages/graphics/libpng/package.mk +++ b/projects/ROCKNIX/packages/graphics/libpng/package.mk @@ -2,10 +2,11 @@ # Copyright (C) 2009-2016 Stephan Raue (stephan@openelec.tv) PKG_NAME="libpng" -PKG_VERSION="1.6.40" +PKG_VERSION="1.6.58" +PKG_SHA256="28eb403f51f0f7405249132cecfe82ea5c0ef97f1b32c5a65828814ae0d34775" PKG_LICENSE="LibPNG2" PKG_SITE="http://www.libpng.org/" -PKG_URL="${SOURCEFORGE_SRC}/libpng/${PKG_NAME}-${PKG_VERSION}.tar.xz" +PKG_URL="https://downloads.sourceforge.net/project/libpng/libpng16/${PKG_VERSION}/${PKG_NAME}-${PKG_VERSION}.tar.xz" PKG_DEPENDS_HOST="zlib:host" PKG_DEPENDS_TARGET="toolchain zlib" PKG_LONGDESC="An extensible file format for the lossless, portable, well-compressed storage of raster images." diff --git a/projects/ROCKNIX/packages/graphics/librashader/package.mk b/projects/ROCKNIX/packages/graphics/librashader/package.mk index f182ce30e9c..ac061d371ad 100644 --- a/projects/ROCKNIX/packages/graphics/librashader/package.mk +++ b/projects/ROCKNIX/packages/graphics/librashader/package.mk @@ -13,6 +13,13 @@ PKG_TOOLCHAIN="manual" make_target() { unset CMAKE + # rustc 1.95 destabilised custom target JSON specs (rust-lang/rust#150151): + # loading one now needs -Zunstable-options, and -Z needs a nightly or + # bootstrapped compiler. Our TARGET_NAME is a custom triple, so this is + # unavoidable - the kernel does the same for its own custom targets. + export RUSTC_BOOTSTRAP=1 + export RUSTFLAGS="${RUSTFLAGS} -Zunstable-options" + cargo build \ --target ${TARGET_NAME} \ --features stable \ diff --git a/projects/ROCKNIX/packages/graphics/mesa-demos/package.mk b/projects/ROCKNIX/packages/graphics/mesa-demos/package.mk index dd4871838f2..ea517d4d604 100644 --- a/projects/ROCKNIX/packages/graphics/mesa-demos/package.mk +++ b/projects/ROCKNIX/packages/graphics/mesa-demos/package.mk @@ -3,6 +3,7 @@ PKG_NAME="mesa-demos" PKG_VERSION="9.0.0" +PKG_SHA256="3046a3d26a7b051af7ebdd257a5f23bfeb160cad6ed952329cdff1e9f1ed496b" PKG_LICENSE="OSS" PKG_SITE="https://www.mesa3d.org/" PKG_URL="https://archive.mesa3d.org/demos/${PKG_NAME}-${PKG_VERSION}.tar.xz" diff --git a/projects/ROCKNIX/packages/graphics/mesa/package.mk b/projects/ROCKNIX/packages/graphics/mesa/package.mk index 23cc53d86cb..37d63a70f15 100644 --- a/projects/ROCKNIX/packages/graphics/mesa/package.mk +++ b/projects/ROCKNIX/packages/graphics/mesa/package.mk @@ -11,9 +11,12 @@ PKG_DEPENDS_HOST="toolchain:host llvm:host libclc:host spirv-tools:host libdrm:h PKG_DEPENDS_TARGET="toolchain expat libdrm Mako:host pyyaml:host" PKG_LONGDESC="Mesa is a 3-D graphics library with an API." PKG_TOOLCHAIN="meson" +PKG_BUILD_FLAGS="+speed" PKG_PATCH_DIRS+=" ${DEVICE}" PKG_VERSION="26.1.6" -PKG_URL="https://gitlab.freedesktop.org/mesa/mesa/-/archive/mesa-${PKG_VERSION}/mesa-mesa-${PKG_VERSION}.tar.gz" +PKG_SHA256="5296b88a0f1e012e2cb9ada150a2bbadf728ca81e5a4fb2ab43c83a4d2158606" +# release tarball, as LibreELEC core uses, rather than a git snapshot +PKG_URL="https://mesa.freedesktop.org/archive/mesa-${PKG_VERSION}.tar.xz" if listcontains "${GRAPHIC_DRIVERS}" "panfrost" || \ listcontains "${GRAPHIC_DRIVERS}" "freedreno"; then diff --git a/projects/ROCKNIX/packages/graphics/qt6/package.mk b/projects/ROCKNIX/packages/graphics/qt6/package.mk index 1605c6801d9..44da0ad46a4 100644 --- a/projects/ROCKNIX/packages/graphics/qt6/package.mk +++ b/projects/ROCKNIX/packages/graphics/qt6/package.mk @@ -79,8 +79,10 @@ pre_configure_host() { -DQT_BUILD_TESTS=OFF \ -DQT_USE_CCACHE=ON \ -DQT_GENERATE_SBOM=OFF \ + -DQT_ALLOW_SYMLINK_IN_PATHS=ON \ -DQT_FEATURE_icu=OFF \ -DQT_FEATURE_wayland=ON \ + -DINPUT_opengl=no \ -DBUILD_WITH_PCH=OFF" } @@ -118,6 +120,7 @@ pre_configure_target(){ -DQT_USE_CCACHE=ON \ -DQT_FEATURE_xcb=ON \ -DQT_GENERATE_SBOM=OFF \ + -DQT_ALLOW_SYMLINK_IN_PATHS=ON \ -DBUILD_WITH_PCH=OFF" } diff --git a/projects/ROCKNIX/packages/graphics/spirv-headers/package.mk b/projects/ROCKNIX/packages/graphics/spirv-headers/package.mk deleted file mode 100644 index 43b925291b0..00000000000 --- a/projects/ROCKNIX/packages/graphics/spirv-headers/package.mk +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Copyright (C) 2021-present Frank Hartung (supervisedthinking (@) gmail.com) -# Copyright (C) 2021-present Team LibreELEC (https://libreelec.tv) - -PKG_NAME="spirv-headers" -# The SPIRV-Headers pkg_version needs to match the compatible (known_good) glslang pkg_version. -# https://raw.githubusercontent.com/KhronosGroup/glslang/${PKG_VERSION}/known_good.json -# When updating glslang pkg_version please update to the known_good spirv-headers pkg_version. -PKG_VERSION="3f17b2af6784bfa2c5aa5dbb8e0e74a607dd8b3b" -PKG_LICENSE="Apache-2.0" -PKG_SITE="https://github.com/KhronosGroup/SPIRV-headers" -PKG_URL="https://github.com/KhronosGroup/SPIRV-headers/archive/${PKG_VERSION}.tar.gz" -PKG_DEPENDS_HOST="" -PKG_LONGDESC="SPIRV-Headers" -PKG_TOOLCHAIN="manual" diff --git a/projects/ROCKNIX/packages/graphics/spirv-tools/package.mk b/projects/ROCKNIX/packages/graphics/spirv-tools/package.mk index 69886d786bc..7ef81c7f0c3 100644 --- a/projects/ROCKNIX/packages/graphics/spirv-tools/package.mk +++ b/projects/ROCKNIX/packages/graphics/spirv-tools/package.mk @@ -2,27 +2,10 @@ # Copyright (C) 2021-present Frank Hartung (supervisedthinking (@) gmail.com) # Copyright (C) 2021-present Team LibreELEC (https://libreelec.tv) -PKG_NAME="spirv-tools" -# The SPIRV-Tools pkg_version needs to match the compatible (known_good) glslang pkg_version. -# https://raw.githubusercontent.com/KhronosGroup/glslang/${PKG_VERSION}/known_good.json -# When updating glslang pkg_version please update to the known_good spirv-tools pkg_version. -PKG_VERSION="4d2f0b40bfe290dea6c6904dafdf7fd8328ba346" -PKG_LICENSE="Apache-2.0" -PKG_SITE="https://github.com/KhronosGroup/SPIRV-Tools" -PKG_URL="https://github.com/KhronosGroup/SPIRV-Tools/archive/${PKG_VERSION}.tar.gz" -PKG_DEPENDS_HOST="toolchain:host" -PKG_DEPENDS_TARGET="toolchain" -PKG_DEPENDS_UNPACK="spirv-headers" -PKG_LONGDESC="The SPIR-V Tools project provides an API and commands for processing SPIR-V modules." +. ${ROOT}/packages/graphics/spirv-tools/package.mk -PKG_CMAKE_OPTS_HOST="-DSPIRV_SKIP_TESTS=ON" +# core builds the target side static and with the tools; we want the shared +# library only PKG_CMAKE_OPTS_TARGET="-DSPIRV_SKIP_TESTS=ON \ -DSPIRV_SKIP_EXECUTABLES=ON \ -DBUILD_SHARED_LIBS=ON" - -post_unpack() { - mkdir -p ${PKG_BUILD}/external/spirv-headers - tar --strip-components=1 \ - -xf "${SOURCES}/spirv-headers/spirv-headers-$(get_pkg_version spirv-headers).tar.gz" \ - -C "${PKG_BUILD}/external/spirv-headers" -} diff --git a/projects/ROCKNIX/packages/graphics/vulkan-wsi-layer/patches/0001-drop-obsolete-STDC_VERSION-workaround.patch b/projects/ROCKNIX/packages/graphics/vulkan-wsi-layer/patches/0001-drop-obsolete-STDC_VERSION-workaround.patch new file mode 100644 index 00000000000..7c6a4507606 --- /dev/null +++ b/projects/ROCKNIX/packages/graphics/vulkan-wsi-layer/patches/0001-drop-obsolete-STDC_VERSION-workaround.patch @@ -0,0 +1,71 @@ +From: ROCKNIX +Subject: [PATCH] wayland: drop the obsolete __STDC_VERSION__ workaround + +These headers define __STDC_VERSION__ to 0 when it is absent, which it +always is in C++, to satisfy wayland headers that once tested it +unguarded. wayland does not do that any more - wayland-util.h now +writes defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L - so +the define changes nothing, while gcc 16 rejects defining the macro at +all and the project builds with -Werror. + +--- a/wsi/wayland/surface.hpp 2026-08-11 05:10:32.128136079 +0000 ++++ b/wsi/wayland/surface.hpp 2026-08-11 05:10:32.140233918 +0000 +@@ -28,9 +28,6 @@ + + #pragma once + +-#ifndef __STDC_VERSION__ +-#define __STDC_VERSION__ 0 +-#endif + #include + + #include "wsi/surface.hpp" +--- a/wsi/wayland/swapchain.hpp 2026-08-11 05:10:32.128884288 +0000 ++++ b/wsi/wayland/swapchain.hpp 2026-08-11 05:10:32.155345175 +0000 +@@ -31,9 +31,6 @@ + #include + } + +-#ifndef __STDC_VERSION__ +-#define __STDC_VERSION__ 0 +-#endif + #include + #include + #include "surface.hpp" +--- a/wsi/wayland/wl_helpers.hpp 2026-08-11 05:10:32.129567372 +0000 ++++ b/wsi/wayland/wl_helpers.hpp 2026-08-11 05:10:32.171071266 +0000 +@@ -26,9 +26,6 @@ + + #include + +-#ifndef __STDC_VERSION__ +-#define __STDC_VERSION__ 0 +-#endif + #include + + #include "util/custom_allocator.hpp" +--- a/wsi/wayland/wl_object_owner.hpp 2026-08-11 05:10:32.130163497 +0000 ++++ b/wsi/wayland/wl_object_owner.hpp 2026-08-11 05:10:32.183574938 +0000 +@@ -24,9 +24,6 @@ + + #pragma once + +-#ifndef __STDC_VERSION__ +-#define __STDC_VERSION__ 0 +-#endif + #include + #include + #include +--- a/wsi/wayland/surface_properties.cpp ++++ b/wsi/wayland/surface_properties.cpp +@@ -25,10 +25,6 @@ + + #define VK_USE_PLATFORM_WAYLAND_KHR 1 + +-#ifndef __STDC_VERSION__ +-#define __STDC_VERSION__ 0 +-#endif +- + #include + #include + diff --git a/projects/ROCKNIX/packages/graphics/vulkan/vulkan-headers/package.mk b/projects/ROCKNIX/packages/graphics/vulkan/vulkan-headers/package.mk index 91ea2f6d8e0..fc3823f993d 100755 --- a/projects/ROCKNIX/packages/graphics/vulkan/vulkan-headers/package.mk +++ b/projects/ROCKNIX/packages/graphics/vulkan/vulkan-headers/package.mk @@ -3,7 +3,8 @@ # Copyright (C) 2021-present Team LibreELEC (https://libreelec.tv) PKG_NAME="vulkan-headers" -PKG_VERSION="1.4.347" +PKG_VERSION="1.4.359" +PKG_SHA256="f655ccd3098d1d999c42dfcf3c7491c6e36fb02c886efece2d2470f7a3b57752" PKG_LICENSE="Apache-2.0" PKG_SITE="https://github.com/KhronosGroup/Vulkan-Headers" PKG_URL="https://github.com/KhronosGroup/Vulkan-Headers/archive/v${PKG_VERSION}.tar.gz" diff --git a/projects/ROCKNIX/packages/graphics/vulkan/vulkan-loader/package.mk b/projects/ROCKNIX/packages/graphics/vulkan/vulkan-loader/package.mk index 8c64770b4e4..0af553204c1 100755 --- a/projects/ROCKNIX/packages/graphics/vulkan/vulkan-loader/package.mk +++ b/projects/ROCKNIX/packages/graphics/vulkan/vulkan-loader/package.mk @@ -3,12 +3,14 @@ # Copyright (C) 2021-present Team LibreELEC (https://libreelec.tv) PKG_NAME="vulkan-loader" -PKG_VERSION="1.4.347" +PKG_VERSION="1.4.359" +PKG_SHA256="c40f7d49496f1561a9a7147da783cff34bfdc8d242dd4134e05bff59d1b7bf79" PKG_LICENSE="Apache-2.0" PKG_SITE="https://github.com/KhronosGroup/Vulkan-Loader" PKG_URL="https://github.com/KhronosGroup/Vulkan-Loader/archive/v${PKG_VERSION}.tar.gz" PKG_DEPENDS_TARGET="toolchain Python3:host vulkan-headers libxcb libX11 libXrandr wayland" PKG_LONGDESC="Vulkan Installable Client Driver (ICD) Loader." +PKG_BUILD_FLAGS="+lto +speed" pre_configure_target() { PKG_CMAKE_OPTS_TARGET="-DBUILD_TESTS=OFF \ diff --git a/projects/ROCKNIX/packages/graphics/vulkan/vulkan-tools/package.mk b/projects/ROCKNIX/packages/graphics/vulkan/vulkan-tools/package.mk index 83bf58e517d..dfa3de0bef9 100755 --- a/projects/ROCKNIX/packages/graphics/vulkan/vulkan-tools/package.mk +++ b/projects/ROCKNIX/packages/graphics/vulkan/vulkan-tools/package.mk @@ -3,7 +3,8 @@ # Copyright (C) 2021-present Team LibreELEC (https://libreelec.tv) PKG_NAME="vulkan-tools" -PKG_VERSION="1.4.347" +PKG_VERSION="1.4.359" +PKG_SHA256="64b7e72d8838348be97f2f04b2757469ac828676376dbbd671165a0bb21194a5" PKG_LICENSE="Apache-2.0" PKG_SITE="https://github.com/KhronosGroup/Vulkan-Tools" PKG_URL="https://github.com/KhronosGroup/Vulkan-tools/archive/v${PKG_VERSION}.tar.gz" diff --git a/projects/ROCKNIX/packages/graphics/waffle/package.mk b/projects/ROCKNIX/packages/graphics/waffle/package.mk index 6ae11962c77..98d1b3fb976 100644 --- a/projects/ROCKNIX/packages/graphics/waffle/package.mk +++ b/projects/ROCKNIX/packages/graphics/waffle/package.mk @@ -2,7 +2,7 @@ # Copyright (C) 2024-present ROCKNIX (https://rocknix.org) PKG_NAME="waffle" PKG_LICENSE="BSD" -PKG_VERSION="5f1f48287e806544d745e9a8f5aed47234c61292" +PKG_VERSION="3b20e4d7bccc5471fe54db21e1b75022fa47d7d8" PKG_SITE="https://waffle.freedesktop.org/" PKG_URL="https://gitlab.freedesktop.org/mesa/waffle/-/archive/${PKG_VERSION}.tar.gz" PKG_DEPENDS_TARGET="toolchain wayland mesa Python3" @@ -15,3 +15,14 @@ PKG_MESON_OPTS_TARGET+=" -Dwayland=enabled \ -Dsurfaceless_egl=enabled \ -Dglx=enabled \ -Dbuild-examples=false" + +pre_configure_target() { + # waffle is the only meson package we build that uses import('cmake'). + # That module wants the cmake root, which meson finds by running + # "cmake --system-information". setup_toolchain exports CMAKE as a whole + # command line for the cmake toolchain - binary plus -DCMAKE_TOOLCHAIN_FILE + # and -DCMAKE_INSTALL_PREFIX - and meson reads $CMAKE as the program, so + # the probe fails with "unable to determine cmake root". Drop it and let + # meson find the bare binary on PATH. + unset CMAKE +} diff --git a/projects/ROCKNIX/packages/graphics/wxwidgets/package.mk b/projects/ROCKNIX/packages/graphics/wxwidgets/package.mk index ccbdc50200f..5e4999d2440 100644 --- a/projects/ROCKNIX/packages/graphics/wxwidgets/package.mk +++ b/projects/ROCKNIX/packages/graphics/wxwidgets/package.mk @@ -11,4 +11,7 @@ PKG_LONGDESC="wxWidgets is a free and open source cross-platform C++ framework f pre_configure_target(){ PKG_CMAKE_OPTS_TARGET+=" -DCMAKE_SYSROOT=${SYSROOT_PREFIX} -DCMAKE_POLICY_VERSION_MINIMUM=3.5" + # wxSound is unused; without this wx links SDL3 from the sysroot and its + # exported targets then clash with SDL2 consumers (cemu: SDL_VERSION mix) + PKG_CMAKE_OPTS_TARGET+=" -DwxUSE_LIBSDL=OFF" } diff --git a/projects/ROCKNIX/packages/lang/gcc/package.mk b/projects/ROCKNIX/packages/lang/gcc/package.mk index 3cf2a7a685d..d808f102d20 100644 --- a/projects/ROCKNIX/packages/lang/gcc/package.mk +++ b/projects/ROCKNIX/packages/lang/gcc/package.mk @@ -3,85 +3,16 @@ . ${ROOT}/packages/lang/gcc/package.mk -PKG_VERSION="15.2.0" -PKG_SHA256="438fd996826b0c82485a29da03a72d71d6e3541a83ec702df4271f6fe025d24e" -PKG_URL="https://ftpmirror.gnu.org/gcc/${PKG_NAME}-${PKG_VERSION}/${PKG_NAME}-${PKG_VERSION}.tar.xz" +# ROCKNIX: ship libatomic on aarch64 too (core enables arm/riscv64 only) +if [ "${TARGET_ARCH}" = "aarch64" ]; then + OPTS_LIBATOMIC="--enable-libatomic" + PKG_CONFIGURE_OPTS_HOST="${PKG_CONFIGURE_OPTS_HOST/--disable-libatomic/--enable-libatomic}" +fi -case ${TARGET_ARCH} in - arm|aarch64) - OPTS_LIBATOMIC="--enable-libatomic" - ;; - *) - OPTS_LIBATOMIC="--disable-libatomic" - ;; -esac +# ROCKNIX: build libgomp (core disables it) and ship it with the target libs +PKG_CONFIGURE_OPTS_HOST="${PKG_CONFIGURE_OPTS_HOST/--disable-libgomp/--enable-libgomp}" -GCC_COMMON_CONFIGURE_OPTS="--target=${TARGET_NAME} \ - --with-sysroot=${SYSROOT_PREFIX} \ - --with-gmp=${TOOLCHAIN} \ - --with-mpfr=${TOOLCHAIN} \ - --with-mpc=${TOOLCHAIN} \ - --with-zstd=${TOOLCHAIN} \ - --with-gnu-as \ - --with-gnu-ld \ - --enable-plugin \ - --enable-lto \ - --enable-gold \ - --enable-ld=default \ - --with-linker-hash-style=gnu \ - --disable-multilib \ - --disable-nls \ - --enable-checking=release \ - --without-ppl \ - --without-cloog \ - --disable-libada \ - --disable-libmudflap \ - --disable-libitm \ - --disable-libquadmath \ - --enable-libgomp \ - --disable-libmpx \ - --disable-libssp \ - --disable-static \ - --enable-shared \ - --disable-werror \ - --enable-__cxa_atexit" - -PKG_CONFIGURE_OPTS_BOOTSTRAP="${GCC_COMMON_CONFIGURE_OPTS} \ - --enable-cloog-backend=isl \ - --disable-decimal-float \ - --disable-gcov \ - --enable-languages=c \ - --disable-libatomic \ - --disable-libgomp \ - --disable-libsanitizer \ - --disable-shared \ - --disable-threads \ - --without-headers \ - --with-newlib \ - ${TARGET_ARCH_GCC_OPTS}" - -PKG_CONFIGURE_OPTS_HOST="${GCC_COMMON_CONFIGURE_OPTS} \ - --enable-languages=c,c++ \ - ${OPTS_LIBATOMIC} \ - --enable-decimal-float \ - --enable-tls \ - --enable-shared \ - --disable-static \ - --enable-long-long \ - --enable-threads=posix \ - --disable-libstdcxx-pch \ - --enable-libstdcxx-time \ - --enable-clocale=gnu \ - ${TARGET_ARCH_GCC_OPTS}" - -makeinstall_target() { +post_makeinstall_target() { mkdir -p ${INSTALL}/usr/lib - cp -P ${PKG_BUILD}/.${HOST_NAME}/${TARGET_NAME}/libgcc/libgcc_s.so* ${INSTALL}/usr/lib - cp -P ${PKG_BUILD}/.${HOST_NAME}/${TARGET_NAME}/libstdc++-v3/src/.libs/libstdc++.so* ${INSTALL}/usr/lib cp -P ${PKG_BUILD}/.${HOST_NAME}/${TARGET_NAME}/libgomp/.libs/*.so* ${INSTALL}/usr/lib - cp -P ${PKG_BUILD}/.${HOST_NAME}/${TARGET_NAME}/libsanitizer/asan/.libs/*.so* ${INSTALL}/usr/lib - cp -P ${PKG_BUILD}/.${HOST_NAME}/${TARGET_NAME}/libsanitizer/ubsan/.libs/*.so* ${INSTALL}/usr/lib - if [ "${OPTS_LIBATOMIC}" = "--enable-libatomic" ]; then - cp -P ${PKG_BUILD}/.${HOST_NAME}/${TARGET_NAME}/libatomic/.libs/libatomic.so* ${INSTALL}/usr/lib - fi } diff --git a/projects/ROCKNIX/packages/lang/go/package.mk b/projects/ROCKNIX/packages/lang/go/package.mk index d8dc9fc9c61..4f21540f82a 100644 --- a/projects/ROCKNIX/packages/lang/go/package.mk +++ b/projects/ROCKNIX/packages/lang/go/package.mk @@ -3,8 +3,9 @@ # Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv) PKG_NAME="go" -PKG_VERSION="1.21.4" -PKG_LICENSE="BSD" +PKG_VERSION="1.25.12" +PKG_SHA256="82be4a550152a4d735fe9ea1610da2883e9b5a732aa74591e881e83e8502b3e3" +PKG_LICENSE="BSD-3-Clause" PKG_SITE="https://golang.org" PKG_URL="https://github.com/golang/go/archive/${PKG_NAME}${PKG_VERSION}.tar.gz" PKG_DEPENDS_HOST="toolchain" diff --git a/projects/ROCKNIX/packages/lang/go/patches/go-0001-add-ca-cert-location.patch b/projects/ROCKNIX/packages/lang/go/patches/go-0001-add-ca-cert-location.patch index d8cff9ffd12..2c3ddf58cdd 100644 --- a/projects/ROCKNIX/packages/lang/go/patches/go-0001-add-ca-cert-location.patch +++ b/projects/ROCKNIX/packages/lang/go/patches/go-0001-add-ca-cert-location.patch @@ -1,10 +1,16 @@ +Subject: [PATCH] x509: look for certificates in /etc/ssl + +ROCKNIX keeps its CA bundle at /etc/ssl, which is not one of the +directories Go scans. + diff --git a/src/crypto/x509/root_linux.go b/src/crypto/x509/root_linux.go -index ad6ce5cae7..763c686fed 100644 --- a/src/crypto/x509/root_linux.go +++ b/src/crypto/x509/root_linux.go -@@ -20,4 +20,5 @@ var certDirectories = []string{ - "/etc/ssl/certs", // SLES10/SLES11, https://golang.org/issue/12139 - "/etc/pki/tls/certs", // Fedora/RHEL - "/system/etc/security/cacerts", // Android -+ "/etc/ssl", // ROCKNIX +@@ -20,6 +20,7 @@ + var certDirectories = []string{ + "/etc/ssl/certs", // SLES10/SLES11, https://golang.org/issue/12139 + "/etc/pki/tls/certs", // Fedora/RHEL ++ "/etc/ssl", // ROCKNIX } + + func init() { diff --git a/projects/ROCKNIX/packages/lang/lua54/package.mk b/projects/ROCKNIX/packages/lang/lua54/package.mk index 57b29424939..b16c5c5d025 100644 --- a/projects/ROCKNIX/packages/lang/lua54/package.mk +++ b/projects/ROCKNIX/packages/lang/lua54/package.mk @@ -2,7 +2,8 @@ # Copyright (C) 2022-present Team LibreELEC (https://libreelec.tv) PKG_NAME="lua54" -PKG_VERSION="5.4.6" +PKG_VERSION="5.4.8" +PKG_SHA256="4f18ddae154e793e46eeab727c59ef1c0c0c2b744e7b94219710d76f530629ae" PKG_LICENSE="MIT" PKG_SITE="https://www.lua.org" PKG_URL="http://www.lua.org/ftp/lua-${PKG_VERSION}.tar.gz" diff --git a/projects/ROCKNIX/packages/lang/luajit/package.mk b/projects/ROCKNIX/packages/lang/luajit/package.mk index a4821efb28e..47fc9935f63 100644 --- a/projects/ROCKNIX/packages/lang/luajit/package.mk +++ b/projects/ROCKNIX/packages/lang/luajit/package.mk @@ -32,7 +32,13 @@ makeinstall_host() { makeinstall_target() { cd .${TARGET_NAME} - unset CFLAGS + # This builds host tools (minilua, buildvm) alongside the target library, + # and folds a bare CFLAGS/LDFLAGS into both - see LDOPTIONS and ASOPTIONS + # in src/Makefile. Target link flags are fatal to the host compiler: + # ld.mold is installed cross-prefixed, so host gcc reading -fuse-ld=mold + # fails with "collect2: cannot find 'ld'". Pass the prefixed pairs only. + local target_ldflags="${LDFLAGS}" + unset CFLAGS LDFLAGS [ "${ARCH}" = "arm" ] && BIT="-m32" make PREFIX="/usr" \ CC="${CC} -fPIC" \ @@ -40,10 +46,10 @@ makeinstall_target() { TARGET_AR="${AR} rcus" \ TARGET_STRIP=true \ TARGET_CFLAGS="${TARGET_CFLAGS}" \ - TARGET_LDFLAGS="${LDFLAGS}" \ + TARGET_LDFLAGS="${target_ldflags}" \ HOST_CC="${HOST_CC} ${BIT}" \ - HOST_CFLAGS="${CFLAGS}" \ - HOST_LDFLAGS="${LDFLAGS}" \ + HOST_CFLAGS="${HOST_CFLAGS}" \ + HOST_LDFLAGS="${HOST_LDFLAGS}" \ XCFLAGS= \ ${JITARCH} \ amalg diff --git a/projects/ROCKNIX/packages/lang/nasm/package.mk b/projects/ROCKNIX/packages/lang/nasm/package.mk index b698b773db5..0289f2148ca 100644 --- a/projects/ROCKNIX/packages/lang/nasm/package.mk +++ b/projects/ROCKNIX/packages/lang/nasm/package.mk @@ -1,16 +1,12 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (C) 2009-2016 Stephan Raue (stephan@openelec.tv) -# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv) +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2024-present ROCKNIX (https://github.com/ROCKNIX) -PKG_NAME="nasm" -PKG_VERSION="2.16.01" -PKG_SHA256="c77745f4802375efeee2ec5c0ad6b7f037ea9c87c92b149a9637ff099f162558" -PKG_LICENSE="BSD" -PKG_SITE="https://www.nasm.us/" -PKG_URL="https://gstreamer.freedesktop.org/src/mirror/nasm-${PKG_VERSION}.tar.xz" -PKG_DEPENDS_HOST="ccache:host" -PKG_LONGDESC="The Netwide Assembler, NASM, is an 80x86 and x86-64 assembler designed for portability and modularity." +. ${ROOT}/packages/lang/nasm/package.mk -pre_configure_host() { - HOST_CONFIGURE_OPTS=$(echo ${HOST_CONFIGURE_OPTS} | sed -e "s|--disable-static||" -e "s|--enable-shared||") -} +# Core scopes nasm to x86_64 targets, and scripts/build silently skips any +# package whose PKG_ARCH excludes the target arch - so on aarch64 devices +# nasm:host never reaches the toolchain, and libvpx:host, which assembles +# x86_64 host code on every target arch, dies at configure with +# "nasm: not found". The old shadow carried no PKG_ARCH at all; that absence +# was operative, and deleting it as cruft broke every emu-standalone leg. +PKG_ARCH="any" diff --git a/projects/ROCKNIX/packages/lang/nasm/patches/nasm-0001-Make--handle-warning-files-while-building-in-a-directory.patch b/projects/ROCKNIX/packages/lang/nasm/patches/nasm-0001-Make--handle-warning-files-while-building-in-a-directory.patch deleted file mode 100644 index b8c97e93d90..00000000000 --- a/projects/ROCKNIX/packages/lang/nasm/patches/nasm-0001-Make--handle-warning-files-while-building-in-a-directory.patch +++ /dev/null @@ -1,231 +0,0 @@ -From 7e80d6b834cd792dbbd7a99fbff98e46cdd5789f Mon Sep 17 00:00:00 2001 -From: "H. Peter Anvin" -Date: Tue, 17 Jan 2023 13:05:55 -0800 -Subject: [PATCH] Make: handle warning files while building in a directory - -The dependency on the warning files breaks when we are building in a -directory *and* the files already exist from being shipped with the -distribution tarballs. The make VPATH simply isn't sophisticated -enough to deal with it, so let the C compiler handle it by #including -the generated file from a dummy C file. - -Reported-by: Rudi Heitbaum -Signed-off-by: H. Peter Anvin ---- - Makefile.in | 38 ++++++++++++++++++++------------------ - Mkfiles/msvc.mak | 14 +++++++------- - Mkfiles/openwcom.mak | 14 +++++++------- - doc/Makefile.in | 2 +- - 6 files changed, 37 insertions(+), 34 deletions(-) - -diff --git a/Makefile.in b/Makefile.in -index 148fcb50..95268fd2 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -37,8 +37,10 @@ AR = @AR@ - RANLIB = @RANLIB@ - STRIP = @STRIP@ - -+tools = $(top_srcdir)/tools -+ - PERL = perl --PERLFLAGS = -I$(srcdir)/perllib -I$(srcdir) -+PERLFLAGS = -I$(top_srcdir)/perllib -I$(srcdir) - RUNPERL = $(PERL) $(PERLFLAGS) - - PYTHON3 = python3 -@@ -65,8 +67,8 @@ LN_S = @LN_S@ - FIND = find - - # Binary suffixes --O = @OBJEXT@ --X = @EXEEXT@ -+O = @OBJEXT@ -+X = @EXEEXT@ - A = @LIBEXT@ - - # Debug stuff -@@ -194,14 +196,14 @@ PERLREQ = config/unconfig.h \ - x86/iflag.c x86/iflaggen.h \ - macros/macros.c \ - asm/pptok.ph asm/directbl.c asm/directiv.h \ -- asm/warnings.c include/warnings.h doc/warnings.src \ -+ $(WARNFILES) \ - misc/nasmtok.el \ - version.h version.mac version.mak nsis/version.nsh - - INSDEP = x86/insns.dat x86/insns.pl x86/insns-iflags.ph x86/iflags.ph - - config/unconfig.h: config/config.h.in -- $(RUNPERL) $(srcdir)/tools/unconfig.pl \ -+ $(RUNPERL) $(tools)/unconfig.pl \ - '$(srcdir)' config/config.h.in config/unconfig.h - - x86/iflag.c: $(INSDEP) -@@ -273,7 +275,7 @@ x86/regs.h: x86/regs.dat x86/regs.pl - # reasonable, but doesn't update the time stamp if the files aren't - # changed, to avoid rebuilding everything every time. Track the actual - # dependency by the empty file asm/warnings.time. --WARNFILES = asm/warnings.c include/warnings.h doc/warnings.src -+WARNFILES = asm/warnings_c.h include/warnings.h doc/warnings.src - - warnings: - $(RM_F) $(WARNFILES) $(WARNFILES:=.time) -@@ -283,11 +285,11 @@ asm/warnings.time: $(ALLOBJ_NW:.$(O)=.c) - : > asm/warnings.time - $(MAKE) $(WARNFILES:=.time) - --asm/warnings.c.time: asm/warnings.pl asm/warnings.time -- $(RUNPERL) $(srcdir)/asm/warnings.pl c asm/warnings.c $(srcdir) -- : > asm/warnings.c.time -+asm/warnings_c.h.time: asm/warnings.pl asm/warnings.time -+ $(RUNPERL) $(srcdir)/asm/warnings.pl c asm/warnings_c.h $(srcdir) -+ : > asm/warnings_c.h.time - --asm/warnings.c: asm/warnings.c.time -+asm/warnings_c.h: asm/warnings_c.h.time - @: Side effect - - include/warnings.h.time: asm/warnings.pl asm/warnings.time -@@ -506,8 +508,8 @@ EXTERNAL_DEPENDENCIES = 1 - # the dependency information will remain external, so it doesn't - # pollute the git logs. - # --Makefile.dep: $(PERLREQ) tools/mkdep.pl config.status -- $(RUNPERL) tools/mkdep.pl -M Makefile.in -- $(DEPDIRS) -+Makefile.dep: $(PERLREQ) $(tools)/mkdep.pl config.status -+ $(RUNPERL) $(tools)/mkdep.pl -M Makefile.in -- $(DEPDIRS) - - dep: Makefile.dep - -@@ -517,9 +519,9 @@ dep: Makefile.dep - # be invoked manually or via "make dist". It should be run before - # creating release archives. - # --alldeps: $(PERLREQ) tools/syncfiles.pl tools/mkdep.pl -- $(RUNPERL) tools/syncfiles.pl Makefile.in Mkfiles/*.mak -- $(RUNPERL) tools/mkdep.pl -i -M Makefile.in Mkfiles/*.mak -- \ -+alldeps: $(PERLREQ) $(tools)/syncfiles.pl $(tools)/mkdep.pl -+ $(RUNPERL) $(tools)/syncfiles.pl Makefile.in Mkfiles/*.mak -+ $(RUNPERL) $(tools)/mkdep.pl -i -M Makefile.in Mkfiles/*.mak -- \ - $(DEPDIRS) - $(RM_F) *.dep - if [ -f config.status ]; then \ -@@ -528,9 +530,9 @@ alldeps: $(PERLREQ) tools/syncfiles.pl tools/mkdep.pl - - # Strip internal dependency information from all Makefiles; this makes - # the output good for git checkin --cleandeps: $(PERLREQ) tools/syncfiles.pl tools/mkdep.pl -- $(RUNPERL) tools/syncfiles.pl Makefile.in Mkfiles/*.mak -- $(RUNPERL) tools/mkdep.pl -e -M Makefile.in Mkfiles/*.mak -- \ -+cleandeps: $(PERLREQ) $(tools)/syncfiles.pl $(tools)/mkdep.pl -+ $(RUNPERL) $(tools)/syncfiles.pl Makefile.in Mkfiles/*.mak -+ $(RUNPERL) $(tools)/mkdep.pl -e -M Makefile.in Mkfiles/*.mak -- \ - $(DEPDIRS) - $(RM_F) *.dep - if [ -f config.status ]; then \ -diff --git a/Mkfiles/msvc.mak b/Mkfiles/msvc.mak -index cf71fffc..da71c5c6 100644 ---- a/Mkfiles/msvc.mak -+++ b/Mkfiles/msvc.mak -@@ -153,14 +153,14 @@ PERLREQ = config\unconfig.h \ - x86\iflag.c x86\iflaggen.h \ - macros\macros.c \ - asm\pptok.ph asm\directbl.c asm\directiv.h \ -- asm\warnings.c include\warnings.h doc\warnings.src \ -+ $(WARNFILES) \ - misc\nasmtok.el \ - version.h version.mac version.mak nsis\version.nsh - - INSDEP = x86\insns.dat x86\insns.pl x86\insns-iflags.ph x86\iflags.ph - - config\unconfig.h: config\config.h.in -- $(RUNPERL) $(srcdir)\tools\unconfig.pl \ -+ $(RUNPERL) $(tools)\unconfig.pl \ - '$(srcdir)' config\config.h.in config\unconfig.h - - x86\iflag.c: $(INSDEP) -@@ -232,7 +232,7 @@ x86\regs.h: x86\regs.dat x86\regs.pl - # reasonable, but doesn't update the time stamp if the files aren't - # changed, to avoid rebuilding everything every time. Track the actual - # dependency by the empty file asm\warnings.time. --WARNFILES = asm\warnings.c include\warnings.h doc\warnings.src -+WARNFILES = asm\warnings_c.h include\warnings.h doc\warnings.src - - warnings: - $(RM_F) $(WARNFILES) $(WARNFILES:=.time) -@@ -242,11 +242,11 @@ asm\warnings.time: $(ALLOBJ_NW:.$(O)=.c) - : > asm\warnings.time - $(MAKE) $(WARNFILES:=.time) - --asm\warnings.c.time: asm\warnings.pl asm\warnings.time -- $(RUNPERL) $(srcdir)\asm\warnings.pl c asm\warnings.c $(srcdir) -- : > asm\warnings.c.time -+asm\warnings_c.h.time: asm\warnings.pl asm\warnings.time -+ $(RUNPERL) $(srcdir)\asm\warnings.pl c asm\warnings_c.h $(srcdir) -+ : > asm\warnings_c.h.time - --asm\warnings.c: asm\warnings.c.time -+asm\warnings_c.h: asm\warnings_c.h.time - @: Side effect - - include\warnings.h.time: asm\warnings.pl asm\warnings.time -diff --git a/Mkfiles/openwcom.mak b/Mkfiles/openwcom.mak -index 5394d85d..605f9afe 100644 ---- a/Mkfiles/openwcom.mak -+++ b/Mkfiles/openwcom.mak -@@ -166,14 +166,14 @@ PERLREQ = config\unconfig.h & - x86\iflag.c x86\iflaggen.h & - macros\macros.c & - asm\pptok.ph asm\directbl.c asm\directiv.h & -- asm\warnings.c include\warnings.h doc\warnings.src & -+ $(WARNFILES) & - misc\nasmtok.el & - version.h version.mac version.mak nsis\version.nsh - - INSDEP = x86\insns.dat x86\insns.pl x86\insns-iflags.ph x86\iflags.ph - - config\unconfig.h: config\config.h.in -- $(RUNPERL) $(srcdir)\tools\unconfig.pl & -+ $(RUNPERL) $(tools)\unconfig.pl & - '$(srcdir)' config\config.h.in config\unconfig.h - - x86\iflag.c: $(INSDEP) -@@ -245,7 +245,7 @@ x86\regs.h: x86\regs.dat x86\regs.pl - # reasonable, but doesn't update the time stamp if the files aren't - # changed, to avoid rebuilding everything every time. Track the actual - # dependency by the empty file asm\warnings.time. --WARNFILES = asm\warnings.c include\warnings.h doc\warnings.src -+WARNFILES = asm\warnings_c.h include\warnings.h doc\warnings.src - - warnings: - $(RM_F) $(WARNFILES) $(WARNFILES:=.time) -@@ -255,11 +255,11 @@ asm\warnings.time: $(ALLOBJ_NW:.$(O)=.c) - : > asm\warnings.time - $(MAKE) $(WARNFILES:=.time) - --asm\warnings.c.time: asm\warnings.pl asm\warnings.time -- $(RUNPERL) $(srcdir)\asm\warnings.pl c asm\warnings.c $(srcdir) -- : > asm\warnings.c.time -+asm\warnings_c.h.time: asm\warnings.pl asm\warnings.time -+ $(RUNPERL) $(srcdir)\asm\warnings.pl c asm\warnings_c.h $(srcdir) -+ : > asm\warnings_c.h.time - --asm\warnings.c: asm\warnings.c.time -+asm\warnings_c.h: asm\warnings_c.h.time - @: Side effect - - include\warnings.h.time: asm\warnings.pl asm\warnings.time -diff --git a/doc/Makefile.in b/doc/Makefile.in -index e92437a0..1c8393c5 100644 ---- a/doc/Makefile.in -+++ b/doc/Makefile.in -@@ -20,7 +20,7 @@ INSTALL = @INSTALL@ - INSTALL_PROGRAM = @INSTALL_PROGRAM@ - INSTALL_DATA = @INSTALL_DATA@ - --PERL = perl -I$(srcdir) -+PERL = perl -I$(top_srcdir)/perllib -I$(srcdir) - - PDFOPT = @PDFOPT@ - diff --git a/projects/ROCKNIX/packages/linux-firmware/iwlwifi-firmware/package.mk b/projects/ROCKNIX/packages/linux-firmware/iwlwifi-firmware/package.mk index ed1f790ec33..d9dbc131eba 100644 --- a/projects/ROCKNIX/packages/linux-firmware/iwlwifi-firmware/package.mk +++ b/projects/ROCKNIX/packages/linux-firmware/iwlwifi-firmware/package.mk @@ -1,5 +1,6 @@ PKG_NAME="iwlwifi-firmware" PKG_VERSION="6faef0d76cff4f2f6082b6a22245341fcb4f469e" +PKG_SHA256="7e4bc0763358f85e308ea0b4a46f08e84ae4e480c7665d5112fbee34200b5623" PKG_LICENSE="Apache" PKG_SITE="https://github.com/armbian/firmware" PKG_URL="${PKG_SITE}/archive/${PKG_VERSION}.tar.gz" diff --git a/projects/ROCKNIX/packages/linux/package.mk b/projects/ROCKNIX/packages/linux/package.mk index 0502019f299..3e24a709328 100644 --- a/projects/ROCKNIX/packages/linux/package.mk +++ b/projects/ROCKNIX/packages/linux/package.mk @@ -365,8 +365,10 @@ make_target() { NO_LIBPFM4=1 \ NO_LIBBABELTRACE=1 \ NO_CAPSTONE=1 \ + NO_RUST=1 \ CROSS_COMPILE="${TARGET_PREFIX}" \ JOBS="${CONCURRENCY_MAKE_LEVEL}" \ + EXTRA_CFLAGS="-g -O2 -Wno-error=discarded-qualifiers" \ make ${PERF_BUILD_ARGS} mkdir -p ${INSTALL}/usr/bin cp perf ${INSTALL}/usr/bin diff --git a/projects/ROCKNIX/packages/multimedia/ffmpeg/package.mk b/projects/ROCKNIX/packages/multimedia/ffmpeg/package.mk index aaf495c8c26..592dd2c6d15 100644 --- a/projects/ROCKNIX/packages/multimedia/ffmpeg/package.mk +++ b/projects/ROCKNIX/packages/multimedia/ffmpeg/package.mk @@ -3,18 +3,16 @@ # Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv) PKG_NAME="ffmpeg" -PKG_LICENSE="LGPLv2.1+" +PKG_LICENSE="LGPL-3.0-or-later" PKG_SITE="https://ffmpeg.org" PKG_DEPENDS_TARGET="toolchain zlib bzip2 openssl speex" PKG_LONGDESC="FFmpeg is a complete, cross-platform solution to record, convert and stream audio and video." -PKG_VERSION="7.1.1" -PKG_SHA256="733984395e0dbbe5c046abda2dc49a5544e7e0e1e2366bba849222ae9e3a03b1" +PKG_VERSION="9.0" +PKG_SHA256="7f607a00dd0d28a729d5a4811205812eef01cf6ef6155025febb6f36a9062d52" PKG_URL="http://ffmpeg.org/releases/ffmpeg-${PKG_VERSION}.tar.xz" PKG_PATCH_DIRS="libreelec" -PKG_PATCH_DIRS+=" v4l2-request v4l2-drmprime" - post_unpack() { # Fix FFmpeg version if [ "${DEVICE}" = "S922X" ]; then @@ -29,19 +27,26 @@ get_graphicdrivers PKG_FFMPEG_HWACCEL="--enable-hwaccels" +# RK3588's kernel has no mainline rkvdec or hantro, so V4L2 has nothing to +# talk to there; every other RK runs mainline V4L2 stateless. case ${DEVICE} in RK3588*) V4L2_SUPPORT=no ;; + RK3326*|RK3399*) + PKG_PATCH_DIRS+=" v4l2-request vf-deinterlace-v4l2m2m" + ;; + RK*) + PKG_PATCH_DIRS+=" v4l2-request detlev vf-deinterlace-v4l2m2m" + ;; *) - case ${DEVICE} in - RK*) - PKG_PATCH_DIRS+=" vf-deinterlace-v4l2m2m" - ;; - esac + PKG_PATCH_DIRS+=" v4l2-request" ;; esac +# libudev and v4l2-request are not ffmpeg options, the v4l2-request patch +# series adds them to configure. RK3588 decodes through rkmpp and does not +# carry that series, so naming them there fails the configure outright. if [ "${V4L2_SUPPORT}" = "yes" ]; then PKG_DEPENDS_TARGET+=" libdrm" PKG_NEED_UNPACK+=" $(get_pkg_directory libdrm)" @@ -60,11 +65,14 @@ if [ "${V4L2_SUPPORT}" = "yes" ]; then PKG_DEPENDS_TARGET+=" systemd" PKG_NEED_UNPACK+=" $(get_pkg_directory systemd)" PKG_FFMPEG_V4L2+=" --enable-libudev --enable-v4l2-request" - else + elif listcontains "${PKG_PATCH_DIRS}" "v4l2-request"; then PKG_FFMPEG_V4L2+=" --disable-libudev --disable-v4l2-request" fi else - PKG_FFMPEG_V4L2="--disable-v4l2_m2m --disable-libudev --disable-v4l2-request" + PKG_FFMPEG_V4L2="--disable-v4l2_m2m" + if listcontains "${PKG_PATCH_DIRS}" "v4l2-request"; then + PKG_FFMPEG_V4L2+=" --disable-libudev --disable-v4l2-request" + fi fi if [ "${VAAPI_SUPPORT}" = "yes" ]; then @@ -105,12 +113,6 @@ if [ "${TARGET_ARCH}" = "x86_64" ]; then PKG_DEPENDS_TARGET+=" nasm:host" fi -case ${DEVICE} in - RK*) - PKG_DEPENDS_TARGET+=" rkmpp" - ;; -esac - if target_has_feature "(neon|sse)"; then PKG_DEPENDS_TARGET+=" dav1d" PKG_NEED_UNPACK+=" $(get_pkg_directory dav1d)" @@ -164,7 +166,6 @@ configure_target() { --enable-avcodec \ --enable-avformat \ --enable-swscale \ - --enable-postproc \ --enable-avfilter \ --disable-devices \ --enable-pthreads \ diff --git a/projects/ROCKNIX/packages/multimedia/ffmpeg/patches/detlev/0001-wip-hevc-Add-support-for-sps-st-rps-control.patch b/projects/ROCKNIX/packages/multimedia/ffmpeg/patches/detlev/0001-wip-hevc-Add-support-for-sps-st-rps-control.patch new file mode 100644 index 00000000000..0019e0f7479 --- /dev/null +++ b/projects/ROCKNIX/packages/multimedia/ffmpeg/patches/detlev/0001-wip-hevc-Add-support-for-sps-st-rps-control.patch @@ -0,0 +1,196 @@ +From 22a798e9733c38dab6f76e717fa3c5fd2773f27a Mon Sep 17 00:00:00 2001 +From: Detlev Casanova +Date: Wed, 9 Jul 2025 15:29:34 -0400 +Subject: [PATCH] wip: hevc: Add support for sps_st_rps control + +Signed-off-by: Detlev Casanova +--- + libavcodec/hevc/ps.c | 17 ++++++---- + libavcodec/hevc/ps.h | 4 ++- + libavcodec/v4l2_request_hevc.c | 60 +++++++++++++++++++++++++++++++++- + 3 files changed, 73 insertions(+), 8 deletions(-) + +diff --git a/libavcodec/hevc/ps.c b/libavcodec/hevc/ps.c +index f18b88489b4..7c56852fe72 100644 +--- a/libavcodec/hevc/ps.c ++++ b/libavcodec/hevc/ps.c +@@ -103,6 +103,7 @@ int ff_hevc_decode_short_term_rps(GetBitContext *gb, AVCodecContext *avctx, + if (rps->rps_predict) { + const ShortTermRPS *rps_ridx; + uint8_t used[32] = { 0 }; ++ uint8_t use_delta[32] = { 0 }; + int delta_rps; + + if (is_slice_header) { +@@ -128,13 +129,13 @@ int ff_hevc_decode_short_term_rps(GetBitContext *gb, AVCodecContext *avctx, + } + delta_rps = (1 - (rps->delta_rps_sign << 1)) * rps->abs_delta_rps; + for (i = 0; i <= rps_ridx->num_delta_pocs; i++) { +- used[k] = get_bits1(gb); ++ used[i] = get_bits1(gb); + +- rps->use_delta = 0; +- if (!used[k]) +- rps->use_delta = get_bits1(gb); ++ use_delta[i] = 1; ++ if (!used[i]) ++ use_delta[i] = get_bits1(gb); + +- if (used[k] || rps->use_delta) { ++ if (used[i] || use_delta[i]) { + if (i < rps_ridx->num_delta_pocs) + delta_poc = delta_rps + rps_ridx->delta_poc[i]; + else +@@ -186,8 +187,10 @@ int ff_hevc_decode_short_term_rps(GetBitContext *gb, AVCodecContext *avctx, + } + } + +- for (unsigned i = 0; i < FF_ARRAY_ELEMS(used); i++) ++ for (unsigned i = 0; i < FF_ARRAY_ELEMS(used); i++) { + rps->used |= (uint32_t)used[i] << i; ++ rps->use_delta |= (uint32_t)use_delta[i] << i; ++ } + } else { + unsigned int nb_positive_pics; + +@@ -215,6 +218,7 @@ int ff_hevc_decode_short_term_rps(GetBitContext *gb, AVCodecContext *avctx, + prev -= delta_poc; + rps->delta_poc[i] = prev; + rps->used |= get_bits1(gb) * (1 << i); ++ rps->delta_poc_s0[i] = delta_poc; + } + prev = 0; + for (i = 0; i < nb_positive_pics; i++) { +@@ -228,6 +232,7 @@ int ff_hevc_decode_short_term_rps(GetBitContext *gb, AVCodecContext *avctx, + prev += delta_poc; + rps->delta_poc[rps->num_negative_pics + i] = prev; + rps->used |= get_bits1(gb) * (1 << (rps->num_negative_pics + i)); ++ rps->delta_poc_s1[i] = delta_poc; + } + } + } +diff --git a/libavcodec/hevc/ps.h b/libavcodec/hevc/ps.h +index 6f5b1f87554..373bd9555fb 100644 +--- a/libavcodec/hevc/ps.h ++++ b/libavcodec/hevc/ps.h +@@ -74,7 +74,10 @@ typedef struct HEVCHdrParams { + + typedef struct ShortTermRPS { + int32_t delta_poc[32]; ++ uint16_t delta_poc_s0[16]; ++ uint16_t delta_poc_s1[16]; + uint32_t used; ++ uint32_t use_delta; + + uint8_t delta_idx; + uint8_t num_negative_pics; +@@ -85,7 +88,6 @@ typedef struct ShortTermRPS { + unsigned delta_rps_sign:1; + + unsigned rps_predict:1; +- unsigned use_delta:1; + } ShortTermRPS; + + typedef struct HEVCWindow { +diff --git a/libavcodec/v4l2_request_hevc.c b/libavcodec/v4l2_request_hevc.c +index 761e448a18c..ec6dc57c537 100644 +--- a/libavcodec/v4l2_request_hevc.c ++++ b/libavcodec/v4l2_request_hevc.c +@@ -25,7 +25,8 @@ + #include "internal.h" + #include "v4l2_request.h" + +-#define V4L2_HEVC_CONTROLS_MAX 6 ++#define V4L2_HEVC_CONTROLS_MAX 7 ++#define MAX_EXT_SPS_RPS 65 + + typedef struct V4L2RequestContextHEVC { + V4L2RequestContext base; +@@ -44,6 +45,8 @@ typedef struct V4L2RequestControlsHEVC { + struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix; + struct v4l2_ctrl_hevc_slice_params slice_params; + struct v4l2_ctrl_hevc_slice_params *frame_slice_params; ++ struct v4l2_ctrl_hevc_ext_sps_st_rps ext_sps_st_rps[MAX_EXT_SPS_RPS]; ++ struct v4l2_ctrl_hevc_ext_sps_lt_rps ext_sps_lt_rps[MAX_EXT_SPS_RPS]; + unsigned int allocated_slice_params; + unsigned int num_slice_params; + uint32_t *entry_point_offsets; +@@ -360,6 +363,48 @@ static void fill_sps(struct v4l2_ctrl_hevc_sps *ctrl, const HEVCContext *h) + ctrl->flags |= V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED; + } + ++static void fill_ext_sps_st_rps (struct v4l2_ctrl_hevc_ext_sps_st_rps *ctrl, const HEVCContext *h) ++{ ++ const HEVCPPS *pps = h->pps; ++ const HEVCSPS *sps = pps->sps; ++ int i; ++ ++ for (i = 0; i < sps->nb_st_rps; i++) { ++ ctrl[i].flags |= ++ sps->st_rps[i].rps_predict ? ++ V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED : 0, ++ ctrl[i].delta_idx_minus1 = ++ sps->st_rps[i].delta_idx - 1; ++ ctrl[i].delta_rps_sign = ++ sps->st_rps[i].delta_rps_sign; ++ ctrl[i].abs_delta_rps_minus1 = ++ sps->st_rps[i].abs_delta_rps - 1; ++ ctrl[i].num_negative_pics = ++ sps->st_rps[i].num_negative_pics; ++ ctrl[i].num_positive_pics = ++ sps->st_rps[i].num_delta_pocs - sps->st_rps[i].num_negative_pics; ++ ++ ctrl[i].used_by_curr_pic = sps->st_rps[i].used; ++ ctrl[i].use_delta_flag = sps->st_rps[i].use_delta; ++ ++ for (int j = 0; j < 16; j++) { ++ ctrl[i].delta_poc_s0_minus1[j] = sps->st_rps[i].delta_poc_s0[j] - 1; ++ ctrl[i].delta_poc_s1_minus1[j] = sps->st_rps[i].delta_poc_s1[j] - 1; ++ } ++ } ++/* ++ for (i = 0; i < sps->num_long_term_ref_pics_sps; i++) { ++ ext_sps_rps_set = &g_array_index (self->ext_sps_rps, ++ struct v4l2_ctrl_hevc_ext_sps_rps, i); ++ ++ ctrl[i]->lt_ref_pic_poc_lsb_sps = sps->lt_ref_pic_poc_lsb_sps[i]; ++ ctrl[i]->flags |= sps->used_by_curr_pic_lt_sps_flag[i] ? ++ V4L2_HEVC_EXT_SPS_RPS_FLAG_USED_LT : 0; ++ } ++*/ ++} ++ ++ + static int v4l2_request_hevc_start_frame(AVCodecContext *avctx, + av_unused const uint8_t *buffer, + av_unused uint32_t size) +@@ -377,6 +422,8 @@ static int v4l2_request_hevc_start_frame(AVCodecContext *avctx, + return ret; + + fill_sps(&controls->sps, h); ++ if (controls->sps.num_short_term_ref_pic_sets) ++ fill_ext_sps_st_rps(controls->ext_sps_st_rps, h); + fill_decode_params(&controls->decode_params, h); + + if (ctx->has_scaling_matrix) { +@@ -527,6 +574,17 @@ static int v4l2_request_hevc_queue_decode(AVCodecContext *avctx, bool last_slice + .size = sizeof(controls->decode_params), + }; + ++ if (controls->sps.num_short_term_ref_pic_sets) { ++ printf("%lu, %d\n", sizeof(*controls->ext_sps_st_rps), controls->sps.num_short_term_ref_pic_sets); ++ control[count++] = (struct v4l2_ext_control) { ++ .id = V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS, ++ .ptr = controls->ext_sps_st_rps, ++ .size = sizeof(*controls->ext_sps_st_rps) * ++ controls->sps.num_short_term_ref_pic_sets, ++ }; ++ } ++ // TODO: Add long term ++ + if (ctx->has_scaling_matrix) { + control[count++] = (struct v4l2_ext_control) { + .id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX, +-- +GitLab + diff --git a/projects/ROCKNIX/packages/multimedia/ffmpeg/patches/libreelec/ffmpeg-001-libreelec.patch b/projects/ROCKNIX/packages/multimedia/ffmpeg/patches/libreelec/0001-libreelec.patch similarity index 76% rename from projects/ROCKNIX/packages/multimedia/ffmpeg/patches/libreelec/ffmpeg-001-libreelec.patch rename to projects/ROCKNIX/packages/multimedia/ffmpeg/patches/libreelec/0001-libreelec.patch index ba2c73b8a98..aa88e493b2f 100644 --- a/projects/ROCKNIX/packages/multimedia/ffmpeg/patches/libreelec/ffmpeg-001-libreelec.patch +++ b/projects/ROCKNIX/packages/multimedia/ffmpeg/patches/libreelec/0001-libreelec.patch @@ -1,4 +1,4 @@ -From f3b90efacf67fb8e8ed07654a6c3f1bd807002a3 Mon Sep 17 00:00:00 2001 +From 342b6ab899e9c66286239c0717ea67183af505df Mon Sep 17 00:00:00 2001 From: Lukas Rusak Date: Wed, 10 Apr 2019 13:39:21 -0700 Subject: [PATCH 1/2] libavcodec/libdav1d: add libdav1d_get_format method to @@ -18,10 +18,10 @@ decoding is properly activated. 1 file changed, 11 insertions(+) diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c -index 546b42e9c622..378231485900 100644 +index b41b741c0d55..614713ff0b93 100644 --- a/libavcodec/libdav1d.c +++ b/libavcodec/libdav1d.c -@@ -69,6 +69,16 @@ static const enum AVPixelFormat pix_fmt_rgb[3] = { +@@ -67,6 +67,16 @@ static const enum AVPixelFormat pix_fmt_rgb[3] = { AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, }; @@ -38,7 +38,7 @@ index 546b42e9c622..378231485900 100644 static void libdav1d_log_callback(void *opaque, const char *fmt, va_list vl) { AVCodecContext *c = opaque; -@@ -424,6 +434,7 @@ static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame) +@@ -410,6 +420,7 @@ static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame) if (res < 0) goto fail; @@ -47,7 +47,7 @@ index 546b42e9c622..378231485900 100644 frame->height = p->p.h; if (c->width != p->p.w || c->height != p->p.h) { -From 74d85efbbd5c9e92e7967d0a0200c41d8ce8a88e Mon Sep 17 00:00:00 2001 +From b8edcb3683570867864a3d26253c4e48be51baab Mon Sep 17 00:00:00 2001 From: chewitt Date: Sun, 11 Aug 2019 07:08:19 +0000 Subject: [PATCH 2/2] add long-term yuv2rgb logging patch @@ -57,17 +57,17 @@ Subject: [PATCH 2/2] add long-term yuv2rgb logging patch 1 file changed, 4 deletions(-) diff --git a/libswscale/yuv2rgb.c b/libswscale/yuv2rgb.c -index 52fe2093e7b1..b04934071542 100644 +index a430a110db74..d7a1a6a9be1f 100644 --- a/libswscale/yuv2rgb.c +++ b/libswscale/yuv2rgb.c -@@ -573,10 +573,6 @@ SwsFunc ff_yuv2rgb_get_func_ptr(SwsContext *c) +@@ -575,10 +575,6 @@ SwsFunc ff_yuv2rgb_get_func_ptr(SwsInternal *c) if (t) return t; - av_log(c, AV_LOG_WARNING, - "No accelerated colorspace conversion found from %s to %s.\n", -- av_get_pix_fmt_name(c->srcFormat), av_get_pix_fmt_name(c->dstFormat)); +- av_get_pix_fmt_name(c->opts.src_format), av_get_pix_fmt_name(c->opts.dst_format)); - - if (c->srcFormat == AV_PIX_FMT_YUV422P) { - switch (c->dstFormat) { + if (c->opts.src_format == AV_PIX_FMT_YUV422P) { + switch (c->opts.dst_format) { case AV_PIX_FMT_BGR48BE: diff --git a/projects/ROCKNIX/packages/multimedia/ffmpeg/patches/v4l2-drmprime/ffmpeg-001-v4l2-drmprime.patch b/projects/ROCKNIX/packages/multimedia/ffmpeg/patches/v4l2-drmprime/ffmpeg-001-v4l2-drmprime.patch deleted file mode 100644 index 4a2f18f4800..00000000000 --- a/projects/ROCKNIX/packages/multimedia/ffmpeg/patches/v4l2-drmprime/ffmpeg-001-v4l2-drmprime.patch +++ /dev/null @@ -1,814 +0,0 @@ -From cf29d984c17f56df0e41f33fb28fe72160cc7869 Mon Sep 17 00:00:00 2001 -From: Lukas Rusak -Date: Tue, 24 Apr 2018 23:00:23 -0700 -Subject: [PATCH 1/8] libavcodec: v4l2m2m: output AVDRMFrameDescriptor - -This allows for a zero-copy output by exporting the v4l2 buffer then wrapping that buffer -in the AVDRMFrameDescriptor like it is done in rkmpp. - -This has been in use for quite some time with great success on many platforms including: - - Amlogic S905 - - Raspberry Pi - - i.MX6 - - Dragonboard 410c - -This was developed in conjunction with Kodi to allow handling the zero-copy buffer rendering. -A simply utility for testing is also available here: https://github.com/BayLibre/ffmpeg-drm - -todo: - - allow selecting pixel format output from decoder - - allow configuring amount of output and capture buffers - -V2: - - allow selecting AV_PIX_FMT_DRM_PRIME - -V3: - - use get_format to select AV_PIX_FMT_DRM_PRIME - - use hw_configs - - add handling of AV_PIX_FMT_YUV420P format (for raspberry pi) - - add handling of AV_PIX_FMT_YUYV422 format (for i.MX6 coda decoder) - -V4: - - rebased on 4.2.2 - -V5: - - rebased on 4.3 ---- - libavcodec/v4l2_buffers.c | 155 ++++++++++++++++++++++++++++++++++++-- - libavcodec/v4l2_buffers.h | 4 + - libavcodec/v4l2_context.c | 40 +++++++++- - libavcodec/v4l2_m2m.h | 3 + - libavcodec/v4l2_m2m_dec.c | 23 ++++++ - 5 files changed, 213 insertions(+), 12 deletions(-) - -diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c -index 23474ee143..0013f54caa 100644 ---- a/libavcodec/v4l2_buffers.c -+++ b/libavcodec/v4l2_buffers.c -@@ -21,6 +21,7 @@ - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -+#include - #include - #include - #include -@@ -28,6 +29,7 @@ - #include - #include - #include "libavcodec/avcodec.h" -+#include "libavutil/hwcontext.h" - #include "libavutil/pixdesc.h" - #include "refstruct.h" - #include "v4l2_context.h" -@@ -210,7 +212,79 @@ static enum AVColorTransferCharacteristic v4l2_get_color_trc(V4L2Buffer *buf) - return AVCOL_TRC_UNSPECIFIED; - } - --static void v4l2_free_buffer(void *opaque, uint8_t *unused) -+static uint8_t * v4l2_get_drm_frame(V4L2Buffer *avbuf) -+{ -+ 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 (avbuf->context->av_pix_fmt) { -+ case AV_PIX_FMT_YUYV422: -+ -+ layer->format = DRM_FORMAT_YUYV; -+ layer->nb_planes = 1; -+ -+ break; -+ -+ case AV_PIX_FMT_NV12: -+ case AV_PIX_FMT_NV21: -+ -+ layer->format = avbuf->context->av_pix_fmt == AV_PIX_FMT_NV12 ? -+ DRM_FORMAT_NV12 : 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 * -+ avbuf->context->format.fmt.pix.height; -+ layer->planes[1].pitch = avbuf->plane_info[0].bytesperline; -+ break; -+ -+ case AV_PIX_FMT_YUV420P: -+ -+ layer->format = 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 * -+ avbuf->context->format.fmt.pix.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 * -+ avbuf->context->format.fmt.pix.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; -+} -+ -+static void v4l2_free_buffer(void *opaque, uint8_t *data) - { - V4L2Buffer* avbuf = opaque; - V4L2m2mContext *s = buf_to_m2mctx(avbuf); -@@ -234,6 +308,36 @@ static void v4l2_free_buffer(void *opaque, uint8_t *unused) - } - } - -+static int v4l2_buffer_export_drm(V4L2Buffer* avbuf) -+{ -+ struct v4l2_exportbuffer expbuf; -+ int i, ret; -+ -+ for (i = 0; i < avbuf->num_planes; i++) { -+ memset(&expbuf, 0, sizeof(expbuf)); -+ -+ expbuf.index = avbuf->buf.index; -+ expbuf.type = avbuf->buf.type; -+ expbuf.plane = i; -+ -+ ret = ioctl(buf_to_m2mctx(avbuf)->fd, VIDIOC_EXPBUF, &expbuf); -+ if (ret < 0) -+ return AVERROR(errno); -+ -+ if (V4L2_TYPE_IS_MULTIPLANAR(avbuf->buf.type)) { -+ /* drm frame */ -+ avbuf->drm_frame.objects[i].size = avbuf->buf.m.planes[i].length; -+ avbuf->drm_frame.objects[i].fd = expbuf.fd; -+ } else { -+ /* drm frame */ -+ avbuf->drm_frame.objects[0].size = avbuf->buf.length; -+ avbuf->drm_frame.objects[0].fd = expbuf.fd; -+ } -+ } -+ -+ return 0; -+} -+ - static int v4l2_buf_increase_ref(V4L2Buffer *in) - { - V4L2m2mContext *s = buf_to_m2mctx(in); -@@ -252,6 +356,24 @@ static int v4l2_buf_increase_ref(V4L2Buffer *in) - return 0; - } - -+static int v4l2_buf_to_bufref_drm(V4L2Buffer *in, AVBufferRef **buf) -+{ -+ int ret; -+ -+ *buf = av_buffer_create((uint8_t *) &in->drm_frame, -+ sizeof(in->drm_frame), -+ v4l2_free_buffer, -+ in, AV_BUFFER_FLAG_READONLY); -+ if (!*buf) -+ return AVERROR(ENOMEM); -+ -+ ret = v4l2_buf_increase_ref(in); -+ if (ret) -+ av_buffer_unref(buf); -+ -+ return ret; -+} -+ - static int v4l2_buf_to_bufref(V4L2Buffer *in, int plane, AVBufferRef **buf) - { - int ret; -@@ -301,13 +423,24 @@ static int v4l2_buffer_buf_to_swframe(AVFrame *frame, V4L2Buffer *avbuf) - - 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 (buf_to_m2mctx(avbuf)->output_drm) { -+ /* 1. get references to the actual data */ -+ ret = v4l2_buf_to_bufref_drm(avbuf, &frame->buf[0]); - if (ret) - return ret; - -- frame->linesize[i] = avbuf->plane_info[i].bytesperline; -- frame->data[i] = frame->buf[i]->data; -+ frame->data[0] = (uint8_t *) v4l2_get_drm_frame(avbuf); -+ frame->format = AV_PIX_FMT_DRM_PRIME; -+ } else { -+ /* 1. get references to the actual data */ -+ for (i = 0; i < avbuf->num_planes; i++) { -+ ret = v4l2_buf_to_bufref(avbuf, i, &frame->buf[i]); -+ if (ret) -+ return ret; -+ -+ frame->linesize[i] = avbuf->plane_info[i].bytesperline; -+ frame->data[i] = frame->buf[i]->data; -+ } - } - - /* fixup special cases */ -@@ -542,9 +675,6 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index) - - 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; -@@ -554,6 +684,15 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index) - avbuf->buf.length = avbuf->planes[0].length; - } - -+ if (V4L2_TYPE_IS_OUTPUT(ctx->type)) -+ return 0; -+ -+ if (buf_to_m2mctx(avbuf)->output_drm) { -+ ret = v4l2_buffer_export_drm(avbuf); -+ if (ret) -+ return ret; -+ } -+ - return ff_v4l2_buffer_enqueue(avbuf); - } - -diff --git a/libavcodec/v4l2_buffers.h b/libavcodec/v4l2_buffers.h -index e35b161309..b83f22152c 100644 ---- a/libavcodec/v4l2_buffers.h -+++ b/libavcodec/v4l2_buffers.h -@@ -29,6 +29,7 @@ - #include - - #include "libavutil/frame.h" -+#include "libavutil/hwcontext_drm.h" - #include "packet.h" - - enum V4L2Buffer_status { -@@ -44,6 +45,9 @@ typedef struct V4L2Buffer { - /* each buffer needs to have a reference to its context */ - struct V4L2Context *context; - -+ /* DRM descriptor */ -+ AVDRMFrameDescriptor drm_frame; -+ - /* This object is refcounted per-plane, so we need to keep track - * of how many context-refs we are holding. - * This pointer is a RefStruct reference. */ -diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c -index be1df3785b..4673d025c5 100644 ---- a/libavcodec/v4l2_context.c -+++ b/libavcodec/v4l2_context.c -@@ -446,22 +446,54 @@ static int v4l2_release_buffers(V4L2Context* ctx) - struct v4l2_requestbuffers req = { - .memory = V4L2_MEMORY_MMAP, - .type = ctx->type, -- .count = 0, /* 0 -> unmaps buffers from the driver */ -+ .count = 0, /* 0 -> unmap all buffers from the driver */ - }; -- int i, j; -+ int ret, i, j; - - for (i = 0; i < ctx->num_buffers; i++) { - V4L2Buffer *buffer = &ctx->buffers[i]; - - for (j = 0; j < buffer->num_planes; j++) { - struct V4L2Plane_info *p = &buffer->plane_info[j]; -+ -+ if (V4L2_TYPE_IS_OUTPUT(ctx->type)) { -+ /* output buffers are not EXPORTED */ -+ goto unmap; -+ } -+ -+ if (ctx_to_m2mctx(ctx)->output_drm) { -+ /* use the DRM frame to close */ -+ if (buffer->drm_frame.objects[j].fd >= 0) { -+ if (close(buffer->drm_frame.objects[j].fd) < 0) { -+ av_log(logger(ctx), AV_LOG_ERROR, "%s close drm fd " -+ "[buffer=%2d, plane=%d, fd=%2d] - %s \n", -+ ctx->name, i, j, buffer->drm_frame.objects[j].fd, -+ av_err2str(AVERROR(errno))); -+ } -+ } -+ } -+unmap: - if (p->mm_addr && p->length) - if (munmap(p->mm_addr, p->length) < 0) -- av_log(logger(ctx), AV_LOG_ERROR, "%s unmap plane (%s))\n", ctx->name, av_err2str(AVERROR(errno))); -+ av_log(logger(ctx), AV_LOG_ERROR, "%s unmap plane (%s))\n", -+ ctx->name, av_err2str(AVERROR(errno))); - } - } - -- return ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_REQBUFS, &req); -+ ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_REQBUFS, &req); -+ if (ret < 0) { -+ av_log(logger(ctx), AV_LOG_ERROR, "release all %s buffers (%s)\n", -+ ctx->name, av_err2str(AVERROR(errno))); -+ -+ if (ctx_to_m2mctx(ctx)->output_drm) -+ av_log(logger(ctx), AV_LOG_ERROR, -+ "Make sure the DRM client releases all FB/GEM objects before closing the codec (ie):\n" -+ "for all buffers: \n" -+ " 1. drmModeRmFB(..)\n" -+ " 2. drmIoctl(.., DRM_IOCTL_GEM_CLOSE,... )\n"); -+ } -+ -+ return ret; - } - - static inline int v4l2_try_raw_format(V4L2Context* ctx, enum AVPixelFormat pixfmt) -diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h -index 4ba33dc335..76ddbf1a26 100644 ---- a/libavcodec/v4l2_m2m.h -+++ b/libavcodec/v4l2_m2m.h -@@ -66,6 +66,9 @@ typedef struct V4L2m2mContext { - - /* reference back to V4L2m2mPriv */ - void *priv; -+ -+ /* generate DRM frames */ -+ int output_drm; - } V4L2m2mContext; - - typedef struct V4L2m2mPriv { -diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c -index aa2d759e1e..b8dc4eb81f 100644 ---- a/libavcodec/v4l2_m2m_dec.c -+++ b/libavcodec/v4l2_m2m_dec.c -@@ -23,6 +23,9 @@ - - #include - #include -+ -+#include "libavutil/hwcontext.h" -+#include "libavutil/hwcontext_drm.h" - #include "libavutil/pixfmt.h" - #include "libavutil/pixdesc.h" - #include "libavutil/opt.h" -@@ -30,6 +33,9 @@ - #include "codec_internal.h" - #include "libavcodec/decode.h" - -+#include "libavcodec/hwaccels.h" -+#include "libavcodec/internal.h" -+ - #include "v4l2_context.h" - #include "v4l2_m2m.h" - #include "v4l2_fmt.h" -@@ -205,6 +211,15 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx) - capture->av_codec_id = AV_CODEC_ID_RAWVIDEO; - capture->av_pix_fmt = avctx->pix_fmt; - -+ /* the client requests the codec to generate DRM frames: -+ * - data[0] will therefore point to the returned AVDRMFrameDescriptor -+ * check the ff_v4l2_buffer_to_avframe conversion function. -+ * - the DRM frame format is passed in the DRM frame descriptor layer. -+ * check the v4l2_get_drm_frame function. -+ */ -+ if (ff_get_format(avctx, avctx->codec->pix_fmts) == AV_PIX_FMT_DRM_PRIME) -+ s->output_drm = 1; -+ - s->avctx = avctx; - ret = ff_v4l2_m2m_codec_init(priv); - if (ret) { -@@ -230,6 +245,11 @@ static const AVOption options[] = { - { NULL}, - }; - -+static const AVCodecHWConfigInternal *v4l2_m2m_hw_configs[] = { -+ HW_CONFIG_INTERNAL(DRM_PRIME), -+ NULL -+}; -+ - #define M2MDEC_CLASS(NAME) \ - static const AVClass v4l2_m2m_ ## NAME ## _dec_class = { \ - .class_name = #NAME "_v4l2m2m_decoder", \ -@@ -255,6 +275,9 @@ static const AVOption options[] = { - .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | \ - FF_CODEC_CAP_INIT_CLEANUP, \ - .p.wrapper_name = "v4l2m2m", \ -+ .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \ -+ AV_PIX_FMT_NONE}, \ -+ .hw_configs = v4l2_m2m_hw_configs, \ - } - - M2MDEC(h264, "H.264", AV_CODEC_ID_H264, "h264_mp4toannexb"); - -From b1c53282fe4a9357f5a74feebd5a4c01954930b3 Mon Sep 17 00:00:00 2001 -From: Lukas Rusak -Date: Thu, 16 Aug 2018 21:09:40 -0700 -Subject: [PATCH 2/8] libavcodec: v4l2m2m: depends on libdrm - ---- - configure | 1 + - libavcodec/v4l2_buffers.c | 2 +- - 2 files changed, 2 insertions(+), 1 deletion(-) - -diff --git a/configure b/configure -index d77a55b653..9db1921b99 100755 ---- a/configure -+++ b/configure -@@ -3746,6 +3746,7 @@ 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" - vfwcap_indev_deps="vfw32 vfwcap_defines" -diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c -index 0013f54caa..9069520556 100644 ---- a/libavcodec/v4l2_buffers.c -+++ b/libavcodec/v4l2_buffers.c -@@ -21,7 +21,7 @@ - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - --#include -+#include - #include - #include - #include - -From 659318a5f802b42be23eb95cebb01cfd46cfac21 Mon Sep 17 00:00:00 2001 -From: Lukas Rusak -Date: Thu, 16 Aug 2018 21:10:13 -0700 -Subject: [PATCH 3/8] libavcodec: v4l2m2m: set format_modifier to - DRM_FORMAT_MOD_LINEAR - ---- - libavcodec/v4l2_buffers.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c -index 9069520556..066bf5b8c3 100644 ---- a/libavcodec/v4l2_buffers.c -+++ b/libavcodec/v4l2_buffers.c -@@ -328,10 +328,12 @@ static int v4l2_buffer_export_drm(V4L2Buffer* avbuf) - /* drm frame */ - avbuf->drm_frame.objects[i].size = avbuf->buf.m.planes[i].length; - avbuf->drm_frame.objects[i].fd = expbuf.fd; -+ avbuf->drm_frame.objects[i].format_modifier = DRM_FORMAT_MOD_LINEAR; - } else { - /* drm frame */ - avbuf->drm_frame.objects[0].size = avbuf->buf.length; - avbuf->drm_frame.objects[0].fd = expbuf.fd; -+ avbuf->drm_frame.objects[0].format_modifier = DRM_FORMAT_MOD_LINEAR; - } - } - - -From f84379aca3bff34205648e85e0c79fd544a20e39 Mon Sep 17 00:00:00 2001 -From: Lukas Rusak -Date: Thu, 16 Aug 2018 21:10:53 -0700 -Subject: [PATCH 4/8] libavcodec: v4l2m2m: only mmap the buffer when it is - output type and drm prime is used - ---- - libavcodec/v4l2_buffers.c | 20 ++++++++++++++------ - 1 file changed, 14 insertions(+), 6 deletions(-) - -diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c -index 066bf5b8c3..3a65ced497 100644 ---- a/libavcodec/v4l2_buffers.c -+++ b/libavcodec/v4l2_buffers.c -@@ -661,14 +661,22 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index) - - 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) { -+ 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) { -+ 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) - -From 6c02dc58f69365fd1f3c5502b481e0fae6987ff7 Mon Sep 17 00:00:00 2001 -From: Lukas Rusak -Date: Thu, 16 Aug 2018 21:11:38 -0700 -Subject: [PATCH 5/8] libavcodec: v4l2m2m: allow using software pixel formats - ---- - libavcodec/v4l2_m2m_dec.c | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c -index b8dc4eb81f..28b29c4522 100644 ---- a/libavcodec/v4l2_m2m_dec.c -+++ b/libavcodec/v4l2_m2m_dec.c -@@ -217,8 +217,16 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx) - * - the DRM frame format is passed in the DRM frame descriptor layer. - * check the v4l2_get_drm_frame function. - */ -- if (ff_get_format(avctx, avctx->codec->pix_fmts) == AV_PIX_FMT_DRM_PRIME) -+ switch (ff_get_format(avctx, avctx->codec->pix_fmts)) { -+ case AV_PIX_FMT_DRM_PRIME: - s->output_drm = 1; -+ break; -+ case AV_PIX_FMT_NONE: -+ return 0; -+ break; -+ default: -+ break; -+ } - - s->avctx = avctx; - ret = ff_v4l2_m2m_codec_init(priv); -@@ -276,6 +284,7 @@ static const AVCodecHWConfigInternal *v4l2_m2m_hw_configs[] = { - FF_CODEC_CAP_INIT_CLEANUP, \ - .p.wrapper_name = "v4l2m2m", \ - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \ -+ AV_PIX_FMT_NV12, \ - AV_PIX_FMT_NONE}, \ - .hw_configs = v4l2_m2m_hw_configs, \ - } - -From 45cab2ebdbd00ce6eb683dd838956049e7fe9a3f Mon Sep 17 00:00:00 2001 -From: Lukas Rusak -Date: Mon, 24 Sep 2018 13:39:31 -0700 -Subject: [PATCH 6/8] libavcodec: v4l2m2m: implement hwcontext - ---- - libavcodec/v4l2_buffers.c | 22 ++++++++++++++++++++++ - libavcodec/v4l2_context.h | 2 ++ - libavcodec/v4l2_m2m.h | 2 ++ - libavcodec/v4l2_m2m_dec.c | 11 +++++++++++ - 4 files changed, 37 insertions(+) - -diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c -index 3a65ced497..7285705857 100644 ---- a/libavcodec/v4l2_buffers.c -+++ b/libavcodec/v4l2_buffers.c -@@ -433,6 +433,7 @@ static int v4l2_buffer_buf_to_swframe(AVFrame *frame, V4L2Buffer *avbuf) - - frame->data[0] = (uint8_t *) v4l2_get_drm_frame(avbuf); - frame->format = AV_PIX_FMT_DRM_PRIME; -+ frame->hw_frames_ctx = av_buffer_ref(avbuf->context->frames_ref); - } else { - /* 1. get references to the actual data */ - for (i = 0; i < avbuf->num_planes; i++) { -@@ -634,6 +635,27 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index) - avbuf->buf.type = ctx->type; - avbuf->buf.index = index; - -+ if (buf_to_m2mctx(avbuf)->output_drm) { -+ AVHWFramesContext *hwframes; -+ -+ av_buffer_unref(&ctx->frames_ref); -+ -+ ctx->frames_ref = av_hwframe_ctx_alloc(buf_to_m2mctx(avbuf)->device_ref); -+ if (!ctx->frames_ref) { -+ ret = AVERROR(ENOMEM); -+ return ret; -+ } -+ -+ 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; -+ ret = av_hwframe_ctx_init(ctx->frames_ref); -+ if (ret < 0) -+ return ret; -+ } -+ - if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) { - avbuf->buf.length = VIDEO_MAX_PLANES; - avbuf->buf.m.planes = avbuf->planes; -diff --git a/libavcodec/v4l2_context.h b/libavcodec/v4l2_context.h -index 6f7460c89a..02fbb6eec3 100644 ---- a/libavcodec/v4l2_context.h -+++ b/libavcodec/v4l2_context.h -@@ -93,6 +93,8 @@ typedef struct V4L2Context { - */ - int done; - -+ AVBufferRef *frames_ref; -+ - } V4L2Context; - - /** -diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h -index 76ddbf1a26..47dfe0905f 100644 ---- a/libavcodec/v4l2_m2m.h -+++ b/libavcodec/v4l2_m2m.h -@@ -67,6 +67,8 @@ typedef struct V4L2m2mContext { - /* reference back to V4L2m2mPriv */ - void *priv; - -+ AVBufferRef *device_ref; -+ - /* generate DRM frames */ - int output_drm; - } V4L2m2mContext; -diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c -index 28b29c4522..a5dc926232 100644 ---- a/libavcodec/v4l2_m2m_dec.c -+++ b/libavcodec/v4l2_m2m_dec.c -@@ -35,6 +35,7 @@ - - #include "libavcodec/hwaccels.h" - #include "libavcodec/internal.h" -+#include "libavcodec/hwconfig.h" - - #include "v4l2_context.h" - #include "v4l2_m2m.h" -@@ -228,6 +229,16 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx) - break; - } - -+ s->device_ref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_DRM); -+ if (!s->device_ref) { -+ ret = AVERROR(ENOMEM); -+ return ret; -+ } -+ -+ 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) { - -From 221ed816ded7c3a2b265a7c3e8c06e320ba791fb Mon Sep 17 00:00:00 2001 -From: Lukas Rusak -Date: Wed, 6 May 2020 11:12:58 -0700 -Subject: [PATCH 7/8] libavcodec: v4l2m2m: add option to specify pixel format - used by the decoder - ---- - libavcodec/v4l2_context.c | 9 +++++++++ - libavcodec/v4l2_m2m.h | 2 ++ - libavcodec/v4l2_m2m_dec.c | 1 + - 3 files changed, 12 insertions(+) - -diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c -index 4673d025c5..1f1fd6d982 100644 ---- a/libavcodec/v4l2_context.c -+++ b/libavcodec/v4l2_context.c -@@ -522,6 +522,8 @@ static inline int v4l2_try_raw_format(V4L2Context* ctx, enum AVPixelFormat pixfm - - static int v4l2_get_raw_format(V4L2Context* ctx, enum AVPixelFormat *p) - { -+ V4L2m2mContext* s = ctx_to_m2mctx(ctx); -+ V4L2m2mPriv *priv = s->avctx->priv_data; - enum AVPixelFormat pixfmt = ctx->av_pix_fmt; - struct v4l2_fmtdesc fdesc; - int ret; -@@ -540,6 +542,13 @@ static int v4l2_get_raw_format(V4L2Context* ctx, enum AVPixelFormat *p) - 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++; -+ continue; -+ } -+ } -+ - pixfmt = ff_v4l2_format_v4l2_to_avfmt(fdesc.pixelformat, AV_CODEC_ID_RAWVIDEO); - ret = v4l2_try_raw_format(ctx, pixfmt); - if (ret){ -diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h -index 47dfe0905f..7b020e2373 100644 ---- a/libavcodec/v4l2_m2m.h -+++ b/libavcodec/v4l2_m2m.h -@@ -30,6 +30,7 @@ - #include - - #include "libavcodec/avcodec.h" -+#include "libavutil/pixfmt.h" - #include "v4l2_context.h" - - #define container_of(ptr, type, member) ({ \ -@@ -80,6 +81,7 @@ typedef struct V4L2m2mPriv { - - int num_output_buffers; - int num_capture_buffers; -+ enum AVPixelFormat pix_fmt; - } V4L2m2mPriv; - - /** -diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c -index a5dc926232..a8f707ba4e 100644 ---- a/libavcodec/v4l2_m2m_dec.c -+++ b/libavcodec/v4l2_m2m_dec.c -@@ -261,6 +261,7 @@ static const AVOption options[] = { - V4L_M2M_DEFAULT_OPTS, - { "num_capture_buffers", "Number of buffers in the capture context", - OFFSET(num_capture_buffers), AV_OPT_TYPE_INT, {.i64 = 20}, 2, INT_MAX, FLAGS }, -+ { "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}, - }; - - -From 0e747a21c508567cd6ea615dba1a0dd85d38c076 Mon Sep 17 00:00:00 2001 -From: Lukas Rusak -Date: Mon, 24 Sep 2018 13:39:56 -0700 -Subject: [PATCH 8/8] libavcodec: v4l2m2m: implement flush - ---- - libavcodec/v4l2_m2m_dec.c | 36 ++++++++++++++++++++++++++++++++++++ - 1 file changed, 36 insertions(+) - -diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c -index a8f707ba4e..5f992f0e7f 100644 ---- a/libavcodec/v4l2_m2m_dec.c -+++ b/libavcodec/v4l2_m2m_dec.c -@@ -254,6 +254,41 @@ static av_cold int v4l2_decode_close(AVCodecContext *avctx) - return ff_v4l2_m2m_codec_end(avctx->priv_data); - } - -+static void v4l2_decode_flush(AVCodecContext *avctx) -+{ -+ V4L2m2mPriv *priv = avctx->priv_data; -+ V4L2m2mContext* s = priv->context; -+ V4L2Context* output = &s->output; -+ V4L2Context* capture = &s->capture; -+ int ret, i; -+ -+ struct v4l2_decoder_cmd cmd = { -+ .cmd = V4L2_DEC_CMD_START, -+ .flags = 0, -+ }; -+ -+ 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); -+ -+ ret = ff_v4l2_context_set_status(output, VIDIOC_STREAMON); -+ if (ret < 0) -+ av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMON %s error: %d\n", output->name, ret); -+ -+ for (i = 0; i < output->num_buffers; i++) { -+ if (output->buffers[i].status == V4L2BUF_IN_DRIVER) -+ output->buffers[i].status = V4L2BUF_AVAILABLE; -+ } -+ -+ 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); -+ -+ s->draining = 0; -+ output->done = 0; -+ capture->done = 0; -+} -+ - #define OFFSET(x) offsetof(V4L2m2mPriv, x) - #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM - -@@ -290,6 +325,7 @@ static const AVCodecHWConfigInternal *v4l2_m2m_hw_configs[] = { - .init = v4l2_decode_init, \ - FF_CODEC_RECEIVE_FRAME_CB(v4l2_receive_frame), \ - .close = v4l2_decode_close, \ -+ .flush = v4l2_decode_flush, \ - .bsfs = bsf_name, \ - .p.capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \ - .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | \ diff --git a/projects/ROCKNIX/packages/multimedia/ffmpeg/patches/v4l2-request/ffmpeg-001-v4l2-request.patch b/projects/ROCKNIX/packages/multimedia/ffmpeg/patches/v4l2-request/0001-v4l2-request.patch similarity index 57% rename from projects/ROCKNIX/packages/multimedia/ffmpeg/patches/v4l2-request/ffmpeg-001-v4l2-request.patch rename to projects/ROCKNIX/packages/multimedia/ffmpeg/patches/v4l2-request/0001-v4l2-request.patch index 663d4edcd41..e549fb5e8d5 100644 --- a/projects/ROCKNIX/packages/multimedia/ffmpeg/patches/v4l2-request/ffmpeg-001-v4l2-request.patch +++ b/projects/ROCKNIX/packages/multimedia/ffmpeg/patches/v4l2-request/0001-v4l2-request.patch @@ -1,35 +1,44 @@ -From b32bc2026a32f1dea2688b619f1547781da6bdaa Mon Sep 17 00:00:00 2001 +From 900fa8e6625a0134432a1dccf87633b499af5fb1 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Tue, 6 Aug 2024 09:06:00 +0000 -Subject: [PATCH 01/11] avutil/hwcontext: Add hwdevice type for V4L2 Request +Subject: [PATCH 01/13] avutil/hwcontext: Add hwdevice type for V4L2 Request API -Add a hwdevice type for V4L2 Request API with transfer_data_from support -for AV_PIX_FMT_DRM_PRIME, based on AV_HWDEVICE_TYPE_DRM. +Add a hwdevice type for use with V4L2 Request API stateless decoding. -AVV4L2RequestDeviceContext.media_fd can be set by the application or a -media device path can be supplied when hwdevice is created. When none -is supplied it default to -1 and hwaccel will auto-detect a media device -with a capable video device. +AVV4L2RequestFramesContext is expected to be filled with a V4L2 coded +pixel format and optional codec-specific extended controls before an +AVHWFramesContext is initialized. + +Once initialized AVV4L2RequestFramesContextInternal describe the opened +V4L2 stateless decoder session, with details about media/video file +descriptors, formats of CAPTURE/OUTPUT queues and buffer pools for +creating CAPTURE/OUTPUT buffers. + +AVHWFramesContext.pool defaults to create frame descriptors around a +CAPTURE buffer, and frames are returned with AVFrame.data[0] pointing +to a AVDRMFrameDescriptor and AVFrame.data[1] the CAPTURE buffer index. Signed-off-by: Jonas Karlman --- - configure | 7 + - libavutil/Makefile | 3 + - libavutil/hwcontext.c | 4 + - libavutil/hwcontext.h | 1 + - libavutil/hwcontext_internal.h | 1 + - libavutil/hwcontext_v4l2request.c | 261 ++++++++++++++++++++++++++++++ - libavutil/hwcontext_v4l2request.h | 41 +++++ - 7 files changed, 318 insertions(+) + configure | 8 + + libavutil/Makefile | 4 + + libavutil/hwcontext.c | 4 + + libavutil/hwcontext.h | 1 + + libavutil/hwcontext_internal.h | 1 + + libavutil/hwcontext_v4l2request.c | 617 +++++++++++++++++++++ + libavutil/hwcontext_v4l2request.h | 70 +++ + libavutil/hwcontext_v4l2request_internal.h | 67 +++ + 8 files changed, 772 insertions(+) create mode 100644 libavutil/hwcontext_v4l2request.c create mode 100644 libavutil/hwcontext_v4l2request.h + create mode 100644 libavutil/hwcontext_v4l2request_internal.h diff --git a/configure b/configure -index d77a55b653..b8f82f0fbf 100755 +index 17596942749a..7d851aa13d29 100755 --- a/configure +++ b/configure -@@ -359,6 +359,7 @@ External library support: +@@ -368,6 +368,7 @@ External library support: --enable-omx-rpi enable OpenMAX IL code for Raspberry Pi [no] --enable-rkmpp enable Rockchip Media Process Platform code [no] --disable-v4l2-m2m disable V4L2 mem2mem code [autodetect] @@ -37,7 +46,7 @@ index d77a55b653..b8f82f0fbf 100755 --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] -@@ -2025,6 +2026,7 @@ HWACCEL_LIBRARY_LIST=" +@@ -2162,6 +2163,7 @@ HWACCEL_LIBRARY_LIST=" mmal omx opencl @@ -45,15 +54,16 @@ index d77a55b653..b8f82f0fbf 100755 " DOCUMENT_LIST=" -@@ -3146,6 +3148,7 @@ dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode ole32 user32" +@@ -3341,6 +3343,8 @@ dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode ole32 user32" ffnvcodec_deps_any="libdl LoadLibrary" - mediacodec_deps="android mediandk" + mediacodec_deps="android mediandk pthreads" nvdec_deps="ffnvcodec" -+v4l2_request_deps="linux_media_h v4l2_timeval_to_ns" ++v4l2_request_deps="linux_media_h v4l2_timeval_to_ns libdrm" ++v4l2_request_suggest="libdrm" vaapi_x11_deps="xlib_x11" videotoolbox_hwaccel_deps="videotoolbox pthreads" videotoolbox_hwaccel_extralibs="-framework QuartzCore" -@@ -7197,6 +7200,10 @@ if enabled v4l2_m2m; then +@@ -7588,6 +7592,10 @@ if enabled v4l2_m2m; then check_cc vp9_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_VP9;" fi @@ -65,48 +75,49 @@ index d77a55b653..b8f82f0fbf 100755 test_code cc sys/videoio.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_sanitized struct_v4l2_frmivalenum_discrete diff --git a/libavutil/Makefile b/libavutil/Makefile -index 6e6fa8d800..1ce46157dd 100644 +index c5241895ff59..fa161b9bc58f 100644 --- a/libavutil/Makefile +++ b/libavutil/Makefile -@@ -48,6 +48,7 @@ HEADERS = adler32.h \ - hwcontext_qsv.h \ +@@ -52,6 +52,7 @@ HEADERS = adler32.h \ hwcontext_mediacodec.h \ hwcontext_opencl.h \ + hwcontext_oh.h \ + hwcontext_v4l2request.h \ hwcontext_vaapi.h \ hwcontext_videotoolbox.h \ hwcontext_vdpau.h \ -@@ -201,6 +202,7 @@ OBJS-$(CONFIG_MACOS_KPERF) += macos_kperf.o - OBJS-$(CONFIG_MEDIACODEC) += hwcontext_mediacodec.o +@@ -214,6 +215,7 @@ OBJS-$(CONFIG_MEDIACODEC) += hwcontext_mediacodec.o + OBJS-$(CONFIG_OHCODEC) += hwcontext_oh.o OBJS-$(CONFIG_OPENCL) += hwcontext_opencl.o OBJS-$(CONFIG_QSV) += hwcontext_qsv.o +OBJS-$(CONFIG_V4L2_REQUEST) += hwcontext_v4l2request.o OBJS-$(CONFIG_VAAPI) += hwcontext_vaapi.o OBJS-$(CONFIG_VIDEOTOOLBOX) += hwcontext_videotoolbox.o OBJS-$(CONFIG_VDPAU) += hwcontext_vdpau.o -@@ -222,6 +224,7 @@ SKIPHEADERS-$(CONFIG_D3D12VA) += hwcontext_d3d12va.h - SKIPHEADERS-$(CONFIG_DXVA2) += hwcontext_dxva2.h +@@ -245,6 +247,8 @@ SKIPHEADERS-$(CONFIG_AMF) += hwcontext_amf.h \ + hwcontext_amf_internal.h SKIPHEADERS-$(CONFIG_QSV) += hwcontext_qsv.h SKIPHEADERS-$(CONFIG_OPENCL) += hwcontext_opencl.h -+SKIPHEADERS-$(CONFIG_V4L2_REQUEST) += hwcontext_v4l2request.h ++SKIPHEADERS-$(CONFIG_V4L2_REQUEST) += hwcontext_v4l2request.h \ ++ hwcontext_v4l2request_internal.h SKIPHEADERS-$(CONFIG_VAAPI) += hwcontext_vaapi.h SKIPHEADERS-$(CONFIG_VIDEOTOOLBOX) += hwcontext_videotoolbox.h SKIPHEADERS-$(CONFIG_VDPAU) += hwcontext_vdpau.h diff --git a/libavutil/hwcontext.c b/libavutil/hwcontext.c -index fa99a0d8a4..7fae9381da 100644 +index 83bd7457e8e6..7f93d90c8e0f 100644 --- a/libavutil/hwcontext.c +++ b/libavutil/hwcontext.c -@@ -65,6 +65,9 @@ static const HWContextType * const hw_table[] = { +@@ -71,6 +71,9 @@ static const HWContextType * const hw_table[] = { #endif - #if CONFIG_VULKAN - &ff_hwcontext_type_vulkan, + #if CONFIG_OHCODEC + &ff_hwcontext_type_oh, +#endif +#if CONFIG_V4L2_REQUEST + &ff_hwcontext_type_v4l2request, #endif NULL, }; -@@ -77,6 +80,7 @@ static const char *const hw_type_names[] = { +@@ -83,6 +86,7 @@ static const char *const hw_type_names[] = { [AV_HWDEVICE_TYPE_D3D12VA] = "d3d12va", [AV_HWDEVICE_TYPE_OPENCL] = "opencl", [AV_HWDEVICE_TYPE_QSV] = "qsv", @@ -115,19 +126,19 @@ index fa99a0d8a4..7fae9381da 100644 [AV_HWDEVICE_TYPE_VDPAU] = "vdpau", [AV_HWDEVICE_TYPE_VIDEOTOOLBOX] = "videotoolbox", diff --git a/libavutil/hwcontext.h b/libavutil/hwcontext.h -index bac30debae..8cf50ddbd0 100644 +index 29374cf0a7e3..88e47cc7f517 100644 --- a/libavutil/hwcontext.h +++ b/libavutil/hwcontext.h -@@ -38,6 +38,7 @@ enum AVHWDeviceType { - AV_HWDEVICE_TYPE_MEDIACODEC, - AV_HWDEVICE_TYPE_VULKAN, - AV_HWDEVICE_TYPE_D3D12VA, +@@ -41,6 +41,7 @@ enum AVHWDeviceType { + AV_HWDEVICE_TYPE_AMF, + /* OpenHarmony Codec device */ + AV_HWDEVICE_TYPE_OHCODEC, + AV_HWDEVICE_TYPE_V4L2REQUEST, }; /** diff --git a/libavutil/hwcontext_internal.h b/libavutil/hwcontext_internal.h -index e32b786238..fd0cf29c6e 100644 +index dcfdc2016a30..94e4da16c0c5 100644 --- a/libavutil/hwcontext_internal.h +++ b/libavutil/hwcontext_internal.h @@ -158,6 +158,7 @@ extern const HWContextType ff_hwcontext_type_drm; @@ -140,10 +151,10 @@ index e32b786238..fd0cf29c6e 100644 extern const HWContextType ff_hwcontext_type_videotoolbox; diff --git a/libavutil/hwcontext_v4l2request.c b/libavutil/hwcontext_v4l2request.c new file mode 100644 -index 0000000000..833fbf9f40 +index 000000000000..3d92b633675b --- /dev/null +++ b/libavutil/hwcontext_v4l2request.c -@@ -0,0 +1,261 @@ +@@ -0,0 +1,617 @@ +/* + * This file is part of FFmpeg. + * @@ -171,69 +182,392 @@ index 0000000000..833fbf9f40 +#include +#include + ++#include ++ +#include "avassert.h" +#include "hwcontext_drm.h" +#include "hwcontext_internal.h" -+#include "hwcontext_v4l2request.h" ++#include "hwcontext_v4l2request_internal.h" +#include "mem.h" + -+static void v4l2request_device_free(AVHWDeviceContext *hwdev) ++typedef struct V4L2RequestDeviceContext { ++} V4L2RequestDeviceContext; ++ ++typedef struct V4L2RequestFramesContext { ++ AVV4L2RequestFramesContext p; ++ AVV4L2RequestFramesContextInternal internal; ++} V4L2RequestFramesContext; ++ ++typedef struct V4L2RequestFrameDescriptor { ++ AVDRMFrameDescriptor base; ++ AVBufferRef *ref; ++ uint32_t index; ++ int fd[AV_DRM_MAX_PLANES]; ++} V4L2RequestFrameDescriptor; ++ ++static const struct { ++ uint32_t pixelformat; ++ enum AVPixelFormat sw_format; ++ uint32_t drm_format; ++ uint64_t format_modifier; ++ uint32_t bit_depth; ++} v4l2request_capture_pixelformats[] = { ++ { V4L2_PIX_FMT_NV12, AV_PIX_FMT_NV12, DRM_FORMAT_NV12, DRM_FORMAT_MOD_LINEAR, 8 }, ++#if defined(V4L2_PIX_FMT_NV12_32L32) ++ { V4L2_PIX_FMT_NV12_32L32, AV_PIX_FMT_YUV420P, DRM_FORMAT_NV12, DRM_FORMAT_MOD_ALLWINNER_TILED, 8 }, ++#endif ++#if defined(V4L2_PIX_FMT_NV15) && defined(DRM_FORMAT_NV15) ++ { V4L2_PIX_FMT_NV15, AV_PIX_FMT_YUV420P10, DRM_FORMAT_NV15, DRM_FORMAT_MOD_LINEAR, 10 }, ++#endif ++ { V4L2_PIX_FMT_NV16, AV_PIX_FMT_NV16, DRM_FORMAT_NV16, DRM_FORMAT_MOD_LINEAR, 8 }, ++#if defined(V4L2_PIX_FMT_NV20) && defined(DRM_FORMAT_NV20) ++ { V4L2_PIX_FMT_NV20, AV_PIX_FMT_YUV422P10, DRM_FORMAT_NV20, DRM_FORMAT_MOD_LINEAR, 10 }, ++#endif ++#if defined(V4L2_PIX_FMT_P010) && defined(DRM_FORMAT_P010) ++ { V4L2_PIX_FMT_P010, AV_PIX_FMT_P010, DRM_FORMAT_P010, DRM_FORMAT_MOD_LINEAR, 10 }, ++#endif ++#if defined(V4L2_PIX_FMT_NV12MT_COL128) && defined(V4L2_PIX_FMT_NV12MT_10_COL128) ++ { V4L2_PIX_FMT_NV12MT_COL128, AV_PIX_FMT_YUV420P, DRM_FORMAT_NV12, DRM_FORMAT_MOD_BROADCOM_SAND128, 8 }, ++#if defined(DRM_FORMAT_P030) ++ { V4L2_PIX_FMT_NV12MT_10_COL128, AV_PIX_FMT_YUV420P10, DRM_FORMAT_P030, DRM_FORMAT_MOD_BROADCOM_SAND128, 10 }, ++#endif ++#endif ++}; ++ ++static int v4l2request_set_drm_descriptor(AVDRMFrameDescriptor *desc, ++ struct v4l2_format *format) +{ -+ AVV4L2RequestDeviceContext *hwctx = hwdev->hwctx; ++ AVDRMLayerDescriptor *layer = &desc->layers[0]; ++ uint32_t pixelformat = V4L2_TYPE_IS_MULTIPLANAR(format->type) ? ++ format->fmt.pix_mp.pixelformat : ++ format->fmt.pix.pixelformat; ++ uint64_t format_modifier; ++ ++ layer->format = 0; ++ for (int i = 0; i < FF_ARRAY_ELEMS(v4l2request_capture_pixelformats); i++) { ++ if (pixelformat == v4l2request_capture_pixelformats[i].pixelformat) { ++ layer->format = v4l2request_capture_pixelformats[i].drm_format; ++ format_modifier = v4l2request_capture_pixelformats[i].format_modifier; ++ break; ++ } ++ } ++ if (!layer->format) ++ return AVERROR(ENOENT); ++ ++ for (int i = 0; i < desc->nb_objects; i++) { ++ desc->objects[i].format_modifier = format_modifier; ++ desc->objects[i].size = V4L2_TYPE_IS_MULTIPLANAR(format->type) ? ++ format->fmt.pix_mp.plane_fmt[i].sizeimage : ++ format->fmt.pix.sizeimage; ++ } ++ ++ desc->nb_layers = 1; ++ layer->nb_planes = 2; ++ ++ layer->planes[0].object_index = 0; ++ layer->planes[0].offset = 0; ++ layer->planes[0].pitch = V4L2_TYPE_IS_MULTIPLANAR(format->type) ? ++ format->fmt.pix_mp.plane_fmt[0].bytesperline : ++ format->fmt.pix.bytesperline; + -+ if (hwctx->media_fd >= 0) { -+ close(hwctx->media_fd); -+ hwctx->media_fd = -1; ++ layer->planes[1].object_index = 0; ++ layer->planes[1].offset = layer->planes[0].pitch * ++ (V4L2_TYPE_IS_MULTIPLANAR(format->type) ? ++ format->fmt.pix_mp.height : ++ format->fmt.pix.height); ++ layer->planes[1].pitch = layer->planes[0].pitch; ++ ++#if defined(V4L2_PIX_FMT_NV12MT_COL128) && defined(V4L2_PIX_FMT_NV12MT_10_COL128) ++ // Raspberry Pi formats need special handling ++ if (pixelformat == V4L2_PIX_FMT_NV12MT_COL128 || ++ pixelformat == V4L2_PIX_FMT_NV12MT_10_COL128) { ++ layer->planes[1].object_index = 1; ++ layer->planes[1].offset = 0; ++ layer->planes[0].pitch = (V4L2_TYPE_IS_MULTIPLANAR(format->type) ? ++ format->fmt.pix_mp.height : ++ format->fmt.pix.height); ++ layer->planes[1].pitch = layer->planes[0].pitch / 2; + } ++#endif ++ ++ return 0; ++} ++ ++static void v4l2request_device_uninit(AVHWDeviceContext *hwdev) ++{ +} + +static int v4l2request_device_create(AVHWDeviceContext *hwdev, const char *device, + AVDictionary *opts, int flags) +{ -+ AVV4L2RequestDeviceContext *hwctx = hwdev->hwctx; ++ return 0; ++} ++ ++static int v4l2request_open_decoder(AVHWFramesContext *hwfc) ++{ ++ AVV4L2RequestFramesContext *fctx = hwfc->hwctx; + -+ hwctx->media_fd = -1; -+ hwdev->free = v4l2request_device_free; ++ // Ensure codec pixelformat is set ++ if (!fctx->pixelformat) ++ return AVERROR(EINVAL); + -+ // Use auto-detect -+ if (!device || !device[0]) -+ return 0; ++ // TODO: locate a decoder supporting the requested pixelformat + -+ hwctx->media_fd = open(device, O_RDWR); -+ if (hwctx->media_fd < 0) -+ return AVERROR(errno); ++ return AVERROR(ENOSYS); ++} + -+ return 0; ++static AVBufferRef *v4l2request_v4l2_buffer_alloc(AVHWFramesContext *hwfc, ++ struct v4l2_format *format) ++{ ++ AVV4L2RequestFramesContext *fctx = hwfc->hwctx; ++ AVV4L2RequestFramesContextInternal *fctxi = fctx->internal; ++ struct v4l2_create_buffers buffers = { ++ .count = 1, ++ .memory = V4L2_MEMORY_MMAP, ++ .format = *format, ++ }; ++ struct v4l2_buffer *buffer; ++ uint8_t num_planes; ++ AVBufferRef *ref; ++ ++ num_planes = V4L2_TYPE_IS_MULTIPLANAR(format->type) ? ++ format->fmt.pix_mp.num_planes : 0; ++ ++ ref = av_buffer_allocz(sizeof(struct v4l2_buffer) + ++ (sizeof(struct v4l2_plane) * num_planes)); ++ if (!ref) ++ return NULL; ++ ++ buffer = (struct v4l2_buffer *)ref->data; ++ buffer->type = format->type; ++ ++ if (num_planes) { ++ buffer->length = num_planes; ++ buffer->m.planes = (struct v4l2_plane *)(buffer + 1); ++ } ++ ++ // Create the buffer ++ if (ioctl(fctxi->video_fd, VIDIOC_CREATE_BUFS, &buffers) < 0) { ++ av_log(hwfc, AV_LOG_ERROR, "Failed to create buffer of type %d: %s (%d)\n", ++ buffer->type, strerror(errno), errno); ++ goto fail; ++ } ++ ++ buffer->memory = buffers.memory; ++ buffer->index = buffers.index; ++ ++ // Query more details of the created buffer ++ if (ioctl(fctxi->video_fd, VIDIOC_QUERYBUF, buffer) < 0) { ++ av_log(hwfc, AV_LOG_ERROR, "Failed to query buffer %d of type %d: %s (%d)\n", ++ buffer->index, buffer->type, strerror(errno), errno); ++ goto fail; ++ } ++ ++ return ref; ++ ++fail: ++ av_buffer_unref(&ref); ++ return NULL; +} + -+static int v4l2request_device_init(AVHWDeviceContext *hwdev) ++static AVBufferRef *v4l2request_capture_buffer_alloc(void *opaque, size_t size) +{ -+ AVV4L2RequestDeviceContext *hwctx = hwdev->hwctx; -+ struct media_device_info device_info; ++ AVHWFramesContext *hwfc = opaque; ++ AVV4L2RequestFramesContext *fctx = hwfc->hwctx; ++ AVV4L2RequestFramesContextInternal *fctxi = fctx->internal; + -+ // Use auto-detect -+ if (hwctx->media_fd < 0) -+ return 0; ++ return v4l2request_v4l2_buffer_alloc(hwfc, &fctxi->capture.format); ++} + -+ if (ioctl(hwctx->media_fd, MEDIA_IOC_DEVICE_INFO, &device_info) < 0) -+ return AVERROR(errno); ++static AVBufferRef *v4l2request_output_buffer_alloc(void *opaque, size_t size) ++{ ++ AVHWFramesContext *hwfc = opaque; ++ AVV4L2RequestFramesContext *fctx = hwfc->hwctx; ++ AVV4L2RequestFramesContextInternal *fctxi = fctx->internal; ++ ++ return v4l2request_v4l2_buffer_alloc(hwfc, &fctxi->output.format); ++} ++ ++static void v4l2request_frame_free(void *opaque, uint8_t *data) ++{ ++ V4L2RequestFrameDescriptor *desc = (V4L2RequestFrameDescriptor *)data; ++ ++ // Close the exported CAPTURE buffer memory planes ++ for (int i = 0; i < FF_ARRAY_ELEMS(desc->fd); i++) { ++ if (desc->fd[i] >= 0) { ++ close(desc->fd[i]); ++ desc->fd[i] = -1; ++ } ++ } ++ ++ // Return the CAPTURE buffer to the frames context CAPTURE pool ++ av_buffer_unref(&desc->ref); ++ ++ av_free(data); ++} ++ ++static AVBufferRef *v4l2request_frame_alloc(void *opaque, size_t size) ++{ ++ AVHWFramesContext *hwfc = opaque; ++ AVV4L2RequestFramesContext *fctx = hwfc->hwctx; ++ AVV4L2RequestFramesContextInternal *fctxi = fctx->internal; ++ struct v4l2_format *format = &fctxi->capture.format; ++ V4L2RequestFrameDescriptor *desc; ++ struct v4l2_buffer *buffer; ++ AVBufferRef *ref; ++ uint8_t *data; ++ ++ data = av_mallocz(size); ++ if (!data) ++ return NULL; ++ ++ ref = av_buffer_create(data, size, v4l2request_frame_free, ++ hwfc, AV_BUFFER_FLAG_READONLY); ++ if (!ref) { ++ av_free(data); ++ return NULL; ++ } ++ ++ // Set initial default values ++ desc = (V4L2RequestFrameDescriptor *)data; ++ for (int i = 0; i < FF_ARRAY_ELEMS(desc->fd); i++) ++ desc->fd[i] = -1; ++ ++ // Get a CAPTURE buffer from frames context CAPTURE pool ++ desc->ref = av_buffer_pool_get(fctxi->capture.pool); ++ if (!desc->ref) ++ goto fail; ++ ++ buffer = (struct v4l2_buffer *)desc->ref->data; ++ desc->index = buffer->index; ++ ++ // Export CAPTURE buffer memory planes ++ desc->base.nb_objects = V4L2_TYPE_IS_MULTIPLANAR(format->type) ? ++ format->fmt.pix_mp.num_planes : 1; ++ av_assert0(desc->base.nb_objects <= AV_DRM_MAX_PLANES); ++ for (int i = 0; i < desc->base.nb_objects; i++) { ++ struct v4l2_exportbuffer exportbuffer = { ++ .type = buffer->type, ++ .index = buffer->index, ++ .plane = i, ++ .flags = O_RDONLY, ++ }; ++ if (ioctl(fctxi->video_fd, VIDIOC_EXPBUF, &exportbuffer) < 0) { ++ av_log(hwfc, AV_LOG_ERROR, "Failed to export memory plane %d (%d): %s (%d)\n", ++ i, buffer->index, strerror(errno), errno); ++ goto fail; ++ } ++ desc->base.objects[i].fd = desc->fd[i] = exportbuffer.fd; ++ } ++ ++ // Set AVDRMFrameDescriptor based on CAPTURE buffer format ++ if (v4l2request_set_drm_descriptor(&desc->base, format) < 0) ++ goto fail; ++ ++ return ref; ++ ++fail: ++ av_buffer_unref(&ref); ++ return NULL; ++} ++ ++static int v4l2request_frames_init(AVHWFramesContext *hwfc) ++{ ++ V4L2RequestFramesContext *hwctx = hwfc->hwctx; ++ AVV4L2RequestFramesContextInternal *fctxi; ++ uint32_t pixelformat; ++ int ret; ++ ++ // Set initial default values ++ fctxi = &hwctx->internal; ++ hwctx->p.internal = fctxi; ++ fctxi->media_fd = -1; ++ fctxi->video_fd = -1; ++ ++ // Locate and open a capable video decoder device ++ ret = v4l2request_open_decoder(hwfc); ++ if (ret < 0) ++ return ret; ++ ++ // Reset init controls after video device is opened ++ hwctx->p.init_controls = NULL; ++ hwctx->p.nb_init_controls = 0; ++ ++ // Update frames context with CAPTURE format details ++ if (V4L2_TYPE_IS_MULTIPLANAR(fctxi->capture.format.type)) { ++ hwfc->width = fctxi->capture.format.fmt.pix_mp.width; ++ hwfc->height = fctxi->capture.format.fmt.pix_mp.height; ++ pixelformat = fctxi->capture.format.fmt.pix_mp.pixelformat; ++ } else { ++ hwfc->width = fctxi->capture.format.fmt.pix.width; ++ hwfc->height = fctxi->capture.format.fmt.pix.height; ++ pixelformat = fctxi->capture.format.fmt.pix.pixelformat; ++ } ++ ++ hwfc->sw_format = AV_PIX_FMT_NONE; ++ for (int i = 0; i < FF_ARRAY_ELEMS(v4l2request_capture_pixelformats); i++) { ++ if (pixelformat == v4l2request_capture_pixelformats[i].pixelformat) { ++ hwctx->p.bit_depth = v4l2request_capture_pixelformats[i].bit_depth; ++ hwfc->sw_format = v4l2request_capture_pixelformats[i].sw_format; ++ break; ++ } ++ } ++ ++ // Initialize buffer pool for CAPTURE buffers ++ fctxi->capture.pool = av_buffer_pool_init2(sizeof(struct v4l2_buffer), hwfc, ++ v4l2request_capture_buffer_alloc, NULL); ++ if (!fctxi->capture.pool) ++ return AVERROR(ENOMEM); ++ ++ // Initialize buffer pool for OUTPUT buffers ++ fctxi->output.pool = av_buffer_pool_init2(sizeof(struct v4l2_buffer), hwfc, ++ v4l2request_output_buffer_alloc, NULL); ++ if (!fctxi->output.pool) ++ return AVERROR(ENOMEM); ++ ++ // Initialize buffer pool for frame descriptors ++ ffhwframesctx(hwfc)->pool_internal = ++ av_buffer_pool_init2(sizeof(V4L2RequestFrameDescriptor), hwfc, ++ v4l2request_frame_alloc, NULL); ++ if (!ffhwframesctx(hwfc)->pool_internal) ++ return AVERROR(ENOMEM); + -+ av_log(hwdev, AV_LOG_VERBOSE, "Using V4L2 media driver %s (%u.%u.%u)\n", -+ device_info.driver, -+ device_info.driver_version >> 16, -+ (device_info.driver_version >> 8) & 0xff, -+ device_info.driver_version & 0xff); ++ av_log(hwfc, AV_LOG_VERBOSE, "Using CAPTURE buffer format %s (%dx%d)\n", ++ av_fourcc2str(pixelformat), hwfc->width, hwfc->height); + + return 0; +} + ++static void v4l2request_frames_uninit(AVHWFramesContext *hwfc) ++{ ++ AVV4L2RequestFramesContext *fctx = hwfc->hwctx; ++ AVV4L2RequestFramesContextInternal *fctxi = fctx->internal; ++ ++ av_buffer_pool_uninit(&fctxi->capture.pool); ++ av_buffer_pool_uninit(&fctxi->output.pool); ++ ++ if (fctxi->video_fd >= 0) { ++ close(fctxi->video_fd); ++ fctxi->video_fd = -1; ++ } ++ ++ if (fctxi->media_fd) { ++ close(fctxi->media_fd); ++ fctxi->media_fd = -1; ++ } ++} ++ +static int v4l2request_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame) +{ ++ V4L2RequestFrameDescriptor *desc; ++ + frame->buf[0] = av_buffer_pool_get(hwfc->pool); + if (!frame->buf[0]) + return AVERROR(ENOMEM); + -+ frame->data[0] = (uint8_t *)frame->buf[0]->data; ++ desc = (V4L2RequestFrameDescriptor *)frame->buf[0]->data; ++ frame->data[0] = (uint8_t *)&desc->base; ++ frame->data[1] = (uint8_t *)(uintptr_t)desc->index; + + frame->format = AV_PIX_FMT_DRM_PRIME; + frame->width = hwfc->width; @@ -242,18 +576,18 @@ index 0000000000..833fbf9f40 + return 0; +} + -+typedef struct DRMMapping { ++typedef struct V4L2RequestMapping { + // Address and length of each mmap()ed region. + int nb_regions; + int object[AV_DRM_MAX_PLANES]; + void *address[AV_DRM_MAX_PLANES]; + size_t length[AV_DRM_MAX_PLANES]; -+} DRMMapping; ++} V4L2RequestMapping; + +static void v4l2request_unmap_frame(AVHWFramesContext *hwfc, + HWMapDescriptor *hwmap) +{ -+ DRMMapping *map = hwmap->priv; ++ V4L2RequestMapping *map = hwmap->priv; + + for (int i = 0; i < map->nb_regions; i++) { + struct dma_buf_sync sync = { @@ -273,7 +607,7 @@ index 0000000000..833fbf9f40 + struct dma_buf_sync sync = { + .flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ, + }; -+ DRMMapping *map; ++ V4L2RequestMapping *map; + int ret, i, p, plane; + void *addr; + @@ -283,12 +617,12 @@ index 0000000000..833fbf9f40 + + av_assert0(desc->nb_objects <= AV_DRM_MAX_PLANES); + for (i = 0; i < desc->nb_objects; i++) { -+ addr = mmap(NULL, desc->objects[i].size, AV_HWFRAME_MAP_READ, MAP_SHARED, ++ addr = mmap(NULL, desc->objects[i].size, PROT_READ, MAP_SHARED, + desc->objects[i].fd, 0); + if (addr == MAP_FAILED) { ++ ret = AVERROR(errno); + av_log(hwfc, AV_LOG_ERROR, "Failed to map DRM object %d to memory: %s (%d)\n", + desc->objects[i].fd, strerror(errno), errno); -+ ret = AVERROR(errno); + goto fail; + } + @@ -340,19 +674,24 @@ index 0000000000..833fbf9f40 + enum AVHWFrameTransferDirection dir, + enum AVPixelFormat **formats) +{ -+ enum AVPixelFormat *pix_fmts; ++ enum AVPixelFormat *fmts; + + if (dir == AV_HWFRAME_TRANSFER_DIRECTION_TO) + return AVERROR(ENOSYS); + -+ pix_fmts = av_malloc_array(2, sizeof(*pix_fmts)); -+ if (!pix_fmts) ++ fmts = av_malloc_array(2, sizeof(*fmts)); ++ if (!fmts) + return AVERROR(ENOMEM); + -+ pix_fmts[0] = hwfc->sw_format; -+ pix_fmts[1] = AV_PIX_FMT_NONE; ++ fmts[0] = hwfc->sw_format; ++ fmts[1] = AV_PIX_FMT_NONE; + -+ *formats = pix_fmts; ++ if (hwfc->sw_format == AV_PIX_FMT_YUV420P || ++ hwfc->sw_format == AV_PIX_FMT_YUV420P10 || ++ hwfc->sw_format == AV_PIX_FMT_YUV422P10) ++ fmts[0] = AV_PIX_FMT_NONE; ++ ++ *formats = fmts; + return 0; +} + @@ -387,18 +726,46 @@ index 0000000000..833fbf9f40 + return ret; +} + ++static int v4l2request_map_from(AVHWFramesContext *hwfc, AVFrame *dst, ++ const AVFrame *src, int flags) ++{ ++ int ret; ++ ++ if (!(flags & AV_HWFRAME_MAP_READ)) ++ return AVERROR(ENOSYS); ++ ++ if (hwfc->sw_format == AV_PIX_FMT_NONE || ++ hwfc->sw_format == AV_PIX_FMT_YUV420P || ++ hwfc->sw_format == AV_PIX_FMT_YUV420P10 || ++ hwfc->sw_format == AV_PIX_FMT_YUV422P10) ++ return AVERROR(ENOSYS); ++ else if (dst->format == AV_PIX_FMT_NONE) ++ dst->format = hwfc->sw_format; ++ else if (hwfc->sw_format != dst->format) ++ return AVERROR(ENOSYS); ++ ++ ret = v4l2request_map_frame(hwfc, dst, src); ++ if (ret) ++ return ret; ++ ++ return av_frame_copy_props(dst, src); ++} ++ +const HWContextType ff_hwcontext_type_v4l2request = { + .type = AV_HWDEVICE_TYPE_V4L2REQUEST, + .name = "V4L2 Request API", + -+ .device_hwctx_size = sizeof(AVV4L2RequestDeviceContext), ++ .device_hwctx_size = sizeof(V4L2RequestDeviceContext), + .device_create = v4l2request_device_create, -+ .device_init = v4l2request_device_init, ++ .device_uninit = v4l2request_device_uninit, + ++ .frames_hwctx_size = sizeof(V4L2RequestFramesContext), ++ .frames_init = v4l2request_frames_init, ++ .frames_uninit = v4l2request_frames_uninit, + .frames_get_buffer = v4l2request_get_buffer, -+ + .transfer_get_formats = v4l2request_transfer_get_formats, + .transfer_data_from = v4l2request_transfer_data_from, ++ .map_from = v4l2request_map_from, + + .pix_fmts = (const enum AVPixelFormat[]) { + AV_PIX_FMT_DRM_PRIME, @@ -407,10 +774,10 @@ index 0000000000..833fbf9f40 +}; diff --git a/libavutil/hwcontext_v4l2request.h b/libavutil/hwcontext_v4l2request.h new file mode 100644 -index 0000000000..0fe42f97b4 +index 000000000000..ec6beadd6495 --- /dev/null +++ b/libavutil/hwcontext_v4l2request.h -@@ -0,0 +1,41 @@ +@@ -0,0 +1,70 @@ +/* + * This file is part of FFmpeg. + * @@ -432,100 +799,61 @@ index 0000000000..0fe42f97b4 +#ifndef AVUTIL_HWCONTEXT_V4L2REQUEST_H +#define AVUTIL_HWCONTEXT_V4L2REQUEST_H + ++#include ++#include ++ +/** + * @file + * An API-specific header for AV_HWDEVICE_TYPE_V4L2REQUEST. + */ + ++typedef struct AVV4L2RequestFramesContextInternal AVV4L2RequestFramesContextInternal; ++ +/** -+ * V4L2 Request API device details. ++ * V4L2 Request API frames context. + * -+ * Allocated as AVHWDeviceContext.hwctx ++ * This struct is allocated as AVHWFramesContext.hwctx + */ -+typedef struct AVV4L2RequestDeviceContext { ++typedef struct AVV4L2RequestFramesContext { ++ /** ++ * Internal context for the initialized V4L2 stateless decoder/encoder session. ++ */ ++ AVV4L2RequestFramesContextInternal *internal; ++ + /** -+ * File descriptor of media device. ++ * V4L2_PIX_FMT_* coded pixel format to set on the OUTPUT queue (decoders) ++ * or the CAPTURE queue (encoders) during initialization. + * -+ * Defaults to -1 for auto-detect. ++ * This field must be set by caller before av_hwframe_ctx_init() is called. + */ -+ int media_fd; -+} AVV4L2RequestDeviceContext; ++ uint32_t pixelformat; ++ ++ /** ++ * Optional bit depth of the frame pixel format, e.g. 8 or 10. ++ * ++ * This field should be set by caller before av_hwframe_ctx_init() is called, ++ * the field will be updated to match the selected frame pixel format after ++ * successful initialization. ++ */ ++ uint32_t bit_depth; ++ ++ /** ++ * Optional codec-specific extended controls to be set during initialization. ++ * ++ * These fields should be set by caller before av_hwframe_ctx_init() is called, ++ * fields are reset to NULL and 0 after successful initialization. ++ */ ++ struct v4l2_ext_control *init_controls; ++ int nb_init_controls; ++} AVV4L2RequestFramesContext; + +#endif /* AVUTIL_HWCONTEXT_V4L2REQUEST_H */ - -From 8b12b1ca49f86dee00a68d819990a2d63150ac1a Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Tue, 6 Aug 2024 09:06:01 +0000 -Subject: [PATCH 02/11] avcodec: Add common V4L2 Request API code - -Add common helpers for supporting V4L2 Request API hwaccels. - -Basic flow for initialization follow the kernel Memory-to-memory -Stateless Video Decoder Interface > Initialization [1]. - -In init video devices is probed and when a capable device is found it is -initialized for decoding. Codec specific CONTROLs may be set to assist -kernel driver. A supported CAPTURE format is selected. A hw frame ctx is -created and CAPTURE buffers is allocated. OUTPUT buffers and request -objects for a circular queue is also allocated. - -In frame_params a buffer pool is created and configured to allocate -CAPTURE buffers. - -In flush all queued OUTPUT and CAPTURE buffers is dequeued. - -In uninit any pending request is flushed, also video and media device is -closed. The media device is not closed when ownership of the media_fd -has been transfered to the hwdevice. - -[1] https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-stateless-decoder.html#initialization - -Co-developed-by: Jernej Skrabec -Signed-off-by: Jernej Skrabec -Co-developed-by: Alex Bee -Signed-off-by: Alex Bee -Signed-off-by: Jonas Karlman ---- - MAINTAINERS | 1 + - libavcodec/Makefile | 1 + - libavcodec/v4l2_request.c | 441 +++++++++++++++++++++++++++++ - libavcodec/v4l2_request.h | 84 ++++++ - libavcodec/v4l2_request_internal.h | 42 +++ - 5 files changed, 569 insertions(+) - create mode 100644 libavcodec/v4l2_request.c - create mode 100644 libavcodec/v4l2_request.h - create mode 100644 libavcodec/v4l2_request_internal.h - -diff --git a/MAINTAINERS b/MAINTAINERS -index 76651d5ff8..391acfbe16 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -278,6 +278,7 @@ Hardware acceleration: - d3d11va* Steve Lhomme - d3d12va_encode* Tong Wu - mediacodec* Matthieu Bouron, Aman Gupta, Zhao Zhili -+ v4l2_request* Jonas Karlman (CC jonas@kwiboo.se) - vaapi* Haihao Xiang - vaapi_encode* Mark Thompson, Haihao Xiang - vdpau* Philip Langdale, Carl Eugen Hoyos -diff --git a/libavcodec/Makefile b/libavcodec/Makefile -index a4fcce3b42..af60923827 100644 ---- a/libavcodec/Makefile -+++ b/libavcodec/Makefile -@@ -176,6 +176,7 @@ OBJS-$(CONFIG_VP3DSP) += vp3dsp.o - OBJS-$(CONFIG_VP56DSP) += vp56dsp.o - OBJS-$(CONFIG_VP8DSP) += vp8dsp.o - OBJS-$(CONFIG_V4L2_M2M) += v4l2_m2m.o v4l2_context.o v4l2_buffers.o v4l2_fmt.o -+OBJS-$(CONFIG_V4L2_REQUEST) += v4l2_request.o - OBJS-$(CONFIG_WMA_FREQS) += wma_freqs.o - OBJS-$(CONFIG_WMV2DSP) += wmv2dsp.o - -diff --git a/libavcodec/v4l2_request.c b/libavcodec/v4l2_request.c +diff --git a/libavutil/hwcontext_v4l2request_internal.h b/libavutil/hwcontext_v4l2request_internal.h new file mode 100644 -index 0000000000..436c8de4a4 +index 000000000000..20436b2b2d69 --- /dev/null -+++ b/libavcodec/v4l2_request.c -@@ -0,0 +1,441 @@ ++++ b/libavutil/hwcontext_v4l2request_internal.h +@@ -0,0 +1,67 @@ +/* + * This file is part of FFmpeg. + * @@ -544,435 +872,742 @@ index 0000000000..436c8de4a4 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + -+#include "config.h" ++#ifndef AVUTIL_HWCONTEXT_V4L2REQUEST_INTERNAL_H ++#define AVUTIL_HWCONTEXT_V4L2REQUEST_INTERNAL_H + -+#include -+#include -+#include -+#include ++#include "buffer.h" ++#include "hwcontext_v4l2request.h" + -+#include "libavutil/hwcontext_v4l2request.h" -+#include "libavutil/mem.h" -+#include "decode.h" -+#include "v4l2_request_internal.h" ++/** ++ * @file ++ * FFmpeg internal API-specific header for AV_HWDEVICE_TYPE_V4L2REQUEST. ++ */ + -+static const AVClass v4l2_request_context_class = { -+ .class_name = "V4L2RequestContext", -+ .item_name = av_default_item_name, -+ .version = LIBAVUTIL_VERSION_INT, -+}; ++/** ++ * Internal context for the initialized V4L2 stateless decoder/encoder session. ++ */ ++struct AVV4L2RequestFramesContextInternal { ++ /** ++ * Media device file descriptor of the initialized session. ++ */ ++ int media_fd; + -+int ff_v4l2_request_query_control(AVCodecContext *avctx, -+ struct v4l2_query_ext_ctrl *control) -+{ -+ V4L2RequestContext *ctx = v4l2_request_context(avctx); ++ /** ++ * Video device file descriptor of the initialized session. ++ */ ++ int video_fd; + -+ if (ioctl(ctx->video_fd, VIDIOC_QUERY_EXT_CTRL, control) < 0) { -+ // Skip error logging when driver does not support control id (EINVAL) -+ if (errno != EINVAL) { -+ av_log(ctx, AV_LOG_ERROR, "Failed to query control %u: %s (%d)\n", -+ control->id, strerror(errno), errno); -+ } -+ return AVERROR(errno); -+ } ++ /** ++ * Details of the initialized CAPTURE and OUTPUT queues. ++ */ ++ struct { ++ /** ++ * V4L2 buffer format. ++ */ ++ struct v4l2_format format; + -+ return 0; -+} ++ /** ++ * V4L2 buffer capabilities flags. ++ */ ++ uint32_t capabilities; ++ ++ /** ++ * Buffer pool of allocated V4L2 buffers. ++ * ++ * AVBufferRef.data points to a struct v4l2_buffer for the created buffer. ++ */ ++ AVBufferPool *pool; ++ } capture, output; ++}; + -+int ff_v4l2_request_query_control_default_value(AVCodecContext *avctx, -+ uint32_t id) -+{ -+ struct v4l2_query_ext_ctrl control = { -+ .id = id, -+ }; -+ int ret; ++#endif /* AVUTIL_HWCONTEXT_V4L2REQUEST_INTERNAL_H */ + +From 2d317790a8e86fe5451c48d28f4925f3372591e3 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Tue, 6 Aug 2024 09:06:02 +0000 +Subject: [PATCH 02/13] avutil/hwcontext_v4l2request: Probe for a capable media + and video device + +Probe all media devices and its linked video devices to locate a video +device that support stateless decoding of the specific codec using the +V4L2 Request API. + +A video device is deemed capable when all tests pass, e.g. kernel +drivers support the coded pixel format and the frame size is supported. + +Basic flow for initialization follows the kernel Memory-to-memory +Stateless Video Decoder Interface > Initialization [1]. + +[1] https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-stateless-decoder.html#initialization + +Co-developed-by: Jernej Skrabec +Signed-off-by: Jernej Skrabec +Co-developed-by: Alex Bee +Signed-off-by: Alex Bee +Signed-off-by: Jonas Karlman +--- + configure | 9 +- + libavutil/hwcontext_v4l2request.c | 513 +++++++++++++++++++++++++++++- + 2 files changed, 517 insertions(+), 5 deletions(-) + +diff --git a/configure b/configure +index 7d851aa13d29..d6dbe3734ead 100755 +--- a/configure ++++ b/configure +@@ -2098,6 +2098,7 @@ EXTERNAL_LIBRARY_LIST=" + libtorch + libtwolame + libuavs3d ++ libudev + libv4l2 + libvmaf + libvorbis +@@ -3343,8 +3344,8 @@ dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode ole32 user32" + ffnvcodec_deps_any="libdl LoadLibrary" + mediacodec_deps="android mediandk pthreads" + nvdec_deps="ffnvcodec" +-v4l2_request_deps="linux_media_h v4l2_timeval_to_ns libdrm" +-v4l2_request_suggest="libdrm" ++v4l2_request_deps="linux_media_h v4l2_timeval_to_ns libdrm libudev" ++v4l2_request_suggest="libdrm libudev" + vaapi_x11_deps="xlib_x11" + videotoolbox_hwaccel_deps="videotoolbox pthreads" + videotoolbox_hwaccel_extralibs="-framework QuartzCore" +@@ -4313,7 +4314,7 @@ shader_compression_suggest="zlib" + + avcodec_extralibs="pthreads_extralibs iconv_extralibs dxva2_extralibs liblcevc_dec_extralibs lcms2_extralibs" + avfilter_extralibs="pthreads_extralibs" +-avutil_extralibs="d3d11va_extralibs d3d12va_extralibs mediacodec_extralibs nanosleep_extralibs pthreads_extralibs vaapi_drm_extralibs vaapi_x11_extralibs vaapi_win32_extralibs vdpau_x11_extralibs" ++avutil_extralibs="d3d11va_extralibs d3d12va_extralibs mediacodec_extralibs nanosleep_extralibs pthreads_extralibs v4l2_request_extralibs vaapi_drm_extralibs vaapi_x11_extralibs vaapi_win32_extralibs vdpau_x11_extralibs" + + # programs + ffmpeg_deps="avcodec avfilter avformat threads" +@@ -7594,6 +7595,8 @@ fi + + if enabled v4l2_request; then + check_func_headers "linux/media.h linux/videodev2.h" v4l2_timeval_to_ns ++ check_pkg_config libudev libudev libudev.h udev_new ++ v4l2_request_extralibs="$libudev_extralibs" + fi + + check_headers sys/videoio.h +diff --git a/libavutil/hwcontext_v4l2request.c b/libavutil/hwcontext_v4l2request.c +index 3d92b633675b..f99eea6eaeb8 100644 +--- a/libavutil/hwcontext_v4l2request.c ++++ b/libavutil/hwcontext_v4l2request.c +@@ -26,6 +26,7 @@ + #include + + #include ++#include + + #include "avassert.h" + #include "hwcontext_drm.h" +@@ -33,7 +34,16 @@ + #include "hwcontext_v4l2request_internal.h" + #include "mem.h" + ++typedef struct V4L2RequestVideoDecoder { ++ dev_t media_dev; ++ dev_t video_dev; ++ uint32_t *pixelformats; ++ int nb_pixelformats; ++} V4L2RequestVideoDecoder; ++ + typedef struct V4L2RequestDeviceContext { ++ V4L2RequestVideoDecoder *decoders; ++ int nb_decoders; + } V4L2RequestDeviceContext; + + typedef struct V4L2RequestFramesContext { +@@ -138,25 +148,524 @@ static int v4l2request_set_drm_descriptor(AVDRMFrameDescriptor *desc, + + static void v4l2request_device_uninit(AVHWDeviceContext *hwdev) + { ++ V4L2RequestDeviceContext *hwctx = hwdev->hwctx; + -+ ret = ff_v4l2_request_query_control(avctx, &control); -+ if (ret < 0) -+ return ret; ++ av_freep(&hwctx->decoders); ++ hwctx->nb_decoders = 0; + } + + static int v4l2request_device_create(AVHWDeviceContext *hwdev, const char *device, + AVDictionary *opts, int flags) + { ++ V4L2RequestDeviceContext *hwctx = hwdev->hwctx; + -+ return control.default_value; -+} ++ hwctx->decoders = NULL; ++ hwctx->nb_decoders = 0; ++ ++ // TODO: enumerate V4L2 Request API capable video decoders ++ // and fill hwctx->decoders and hwctx->nb_decoders, ++ // limit to decoders for the media 'device' when specified + -+int ff_v4l2_request_set_request_controls(V4L2RequestContext *ctx, int request_fd, -+ struct v4l2_ext_control *control, int count) + return 0; + } + ++static int v4l2request_set_format(AVHWFramesContext *hwfc, ++ enum v4l2_buf_type type, ++ uint32_t pixelformat, ++ uint32_t buffersize) +{ -+ struct v4l2_ext_controls controls = { -+ .controls = control, -+ .count = count, -+ .request_fd = request_fd, -+ .which = (request_fd >= 0) ? V4L2_CTRL_WHICH_REQUEST_VAL : 0, ++ AVV4L2RequestFramesContext *fctx = hwfc->hwctx; ++ AVV4L2RequestFramesContextInternal *fctxi = fctx->internal; ++ struct v4l2_format format = { ++ .type = type, + }; + -+ if (!control || !count) -+ return 0; ++ if (V4L2_TYPE_IS_MULTIPLANAR(type)) { ++ format.fmt.pix_mp.width = hwfc->width; ++ format.fmt.pix_mp.height = hwfc->height; ++ format.fmt.pix_mp.pixelformat = pixelformat; ++ format.fmt.pix_mp.plane_fmt[0].sizeimage = buffersize; ++ format.fmt.pix_mp.num_planes = 1; ++ } else { ++ format.fmt.pix.width = hwfc->width; ++ format.fmt.pix.height = hwfc->height; ++ format.fmt.pix.pixelformat = pixelformat; ++ format.fmt.pix.sizeimage = buffersize; ++ } + -+ if (ioctl(ctx->video_fd, VIDIOC_S_EXT_CTRLS, &controls) < 0) ++ if (ioctl(fctxi->video_fd, VIDIOC_S_FMT, &format) < 0) + return AVERROR(errno); + + return 0; +} + -+int ff_v4l2_request_set_controls(AVCodecContext *avctx, -+ struct v4l2_ext_control *control, int count) -+{ -+ V4L2RequestContext *ctx = v4l2_request_context(avctx); -+ int ret; -+ -+ ret = ff_v4l2_request_set_request_controls(ctx, -1, control, count); -+ if (ret < 0) { -+ av_log(ctx, AV_LOG_ERROR, "Failed to set %d control(s): %s (%d)\n", -+ count, strerror(errno), errno); -+ } -+ -+ return ret; -+} -+ -+static int v4l2_request_buffer_alloc(V4L2RequestContext *ctx, -+ V4L2RequestBuffer *buf, -+ enum v4l2_buf_type type) ++static int v4l2request_select_capture_format(AVHWFramesContext *hwfc) +{ -+ struct v4l2_plane planes[1] = {}; -+ struct v4l2_create_buffers buffers = { -+ .count = 1, -+ .memory = V4L2_MEMORY_MMAP, -+ .format.type = type, ++ AVV4L2RequestFramesContext *fctx = hwfc->hwctx; ++ AVV4L2RequestFramesContextInternal *fctxi = fctx->internal; ++ enum v4l2_buf_type type = fctxi->capture.format.type; ++ uint32_t pixelformat, fallback = 0; ++ struct v4l2_format format = { ++ .type = type, ++ }; ++ struct v4l2_fmtdesc fmtdesc = { ++ .index = 0, ++ .type = type, + }; + -+ // Get format details for the buffer to be created -+ if (ioctl(ctx->video_fd, VIDIOC_G_FMT, &buffers.format) < 0) { -+ av_log(ctx, AV_LOG_ERROR, "Failed to get format of type %d: %s (%d)\n", -+ type, strerror(errno), errno); ++ // Get the driver preferred (or default) format ++ if (ioctl(fctxi->video_fd, VIDIOC_G_FMT, &format) < 0) + return AVERROR(errno); -+ } + -+ // Create the buffer -+ if (ioctl(ctx->video_fd, VIDIOC_CREATE_BUFS, &buffers) < 0) { -+ av_log(ctx, AV_LOG_ERROR, "Failed to create buffer of type %d: %s (%d)\n", -+ type, strerror(errno), errno); -+ return AVERROR(errno); -+ } ++ pixelformat = V4L2_TYPE_IS_MULTIPLANAR(type) ? ++ format.fmt.pix_mp.pixelformat : ++ format.fmt.pix.pixelformat; + -+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) { -+ buf->width = buffers.format.fmt.pix_mp.width; -+ buf->height = buffers.format.fmt.pix_mp.height; -+ buf->size = buffers.format.fmt.pix_mp.plane_fmt[0].sizeimage; -+ buf->buffer.length = 1; -+ buf->buffer.m.planes = planes; -+ } else { -+ buf->width = buffers.format.fmt.pix.width; -+ buf->height = buffers.format.fmt.pix.height; -+ buf->size = buffers.format.fmt.pix.sizeimage; ++ // Try to use the driver preferred format when it is a known format ++ for (int i = 0; i < FF_ARRAY_ELEMS(v4l2request_capture_pixelformats); i++) { ++ if (pixelformat == v4l2request_capture_pixelformats[i].pixelformat && ++ (fctx->bit_depth == v4l2request_capture_pixelformats[i].bit_depth || ++ !fctx->bit_depth)) ++ return v4l2request_set_format(hwfc, type, pixelformat, 0); + } + -+ buf->index = buffers.index; -+ buf->capabilities = buffers.capabilities; -+ buf->used = 0; -+ -+ buf->buffer.type = type; -+ buf->buffer.memory = V4L2_MEMORY_MMAP; -+ buf->buffer.index = buf->index; ++ // Next try to use the first known format with matching bit depth ++ while (ioctl(fctxi->video_fd, VIDIOC_ENUM_FMT, &fmtdesc) >= 0) { ++ for (int i = 0; i < FF_ARRAY_ELEMS(v4l2request_capture_pixelformats); i++) { ++ if (fmtdesc.pixelformat == v4l2request_capture_pixelformats[i].pixelformat) { ++ if (fctx->bit_depth == v4l2request_capture_pixelformats[i].bit_depth || ++ !fctx->bit_depth) ++ return v4l2request_set_format(hwfc, type, fmtdesc.pixelformat, 0); ++ else if (!fallback) ++ fallback = fmtdesc.pixelformat; ++ } ++ } + -+ // Query more details of the created buffer -+ if (ioctl(ctx->video_fd, VIDIOC_QUERYBUF, &buf->buffer) < 0) { -+ av_log(ctx, AV_LOG_ERROR, "Failed to query buffer %d of type %d: %s (%d)\n", -+ buf->index, type, strerror(errno), errno); -+ return AVERROR(errno); ++ fmtdesc.index++; + } + -+ // Output buffers is mapped and capture buffers is exported -+ if (V4L2_TYPE_IS_OUTPUT(type)) { -+ off_t offset = V4L2_TYPE_IS_MULTIPLANAR(type) ? -+ buf->buffer.m.planes[0].m.mem_offset : -+ buf->buffer.m.offset; -+ void *addr = mmap(NULL, buf->size, PROT_READ | PROT_WRITE, MAP_SHARED, -+ ctx->video_fd, offset); -+ if (addr == MAP_FAILED) { -+ av_log(ctx, AV_LOG_ERROR, "Failed to map output buffer %d: %s (%d)\n", -+ buf->index, strerror(errno), errno); -+ return AVERROR(errno); -+ } ++ // Fallback to use the first known format ++ if (fallback) ++ return v4l2request_set_format(hwfc, type, fallback, 0); + -+ // Raw bitstream data is appended to output buffers -+ buf->addr = (uint8_t *)addr; -+ } else { -+ struct v4l2_exportbuffer exportbuffer = { -+ .type = type, -+ .index = buf->index, -+ .flags = O_RDONLY, -+ }; ++ return AVERROR(errno); ++} + -+ if (ioctl(ctx->video_fd, VIDIOC_EXPBUF, &exportbuffer) < 0) { -+ av_log(ctx, AV_LOG_ERROR, "Failed to export capture buffer %d: %s (%d)\n", -+ buf->index, strerror(errno), errno); -+ return AVERROR(errno); -+ } ++static int v4l2request_try_framesize(AVHWFramesContext *hwfc, ++ uint32_t pixelformat) ++{ ++ AVV4L2RequestFramesContext *fctx = hwfc->hwctx; ++ AVV4L2RequestFramesContextInternal *fctxi = fctx->internal; ++ struct v4l2_frmsizeenum frmsize = { ++ .index = 0, ++ .pixel_format = pixelformat, ++ }; + -+ // Used in the AVDRMFrameDescriptor for decoded frames -+ buf->fd = exportbuffer.fd; ++ // Enumerate and check if frame size is supported ++ while (ioctl(fctxi->video_fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) >= 0) { ++ if (frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE && ++ hwfc->width == frmsize.discrete.width && ++ hwfc->height == frmsize.discrete.height) { ++ return 0; ++ } else if ((frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE || ++ frmsize.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) && ++ hwfc->width >= frmsize.stepwise.min_width && ++ hwfc->height >= frmsize.stepwise.min_height && ++ hwfc->width <= frmsize.stepwise.max_width && ++ hwfc->height <= frmsize.stepwise.max_height) { ++ return 0; ++ } + -+ /* -+ * Use buffer index as base for V4L2 frame reference. -+ * This works because a capture buffer is closely tied to a AVFrame -+ * and FFmpeg handle all frame reference tracking for us. -+ */ -+ buf->buffer.timestamp.tv_usec = buf->index + 1; ++ frmsize.index++; + } + -+ return 0; ++ return AVERROR(errno); +} + -+static void v4l2_request_buffer_free(V4L2RequestBuffer *buf) ++static int v4l2request_try_format(AVHWFramesContext *hwfc, ++ enum v4l2_buf_type type, ++ uint32_t pixelformat) +{ -+ // Unmap output buffers -+ if (buf->addr) { -+ munmap(buf->addr, buf->size); -+ buf->addr = NULL; -+ } ++ AVV4L2RequestFramesContext *fctx = hwfc->hwctx; ++ AVV4L2RequestFramesContextInternal *fctxi = fctx->internal; ++ struct v4l2_fmtdesc fmtdesc = { ++ .index = 0, ++ .type = type, ++ }; ++ ++ // Enumerate and check if format is supported ++ while (ioctl(fctxi->video_fd, VIDIOC_ENUM_FMT, &fmtdesc) >= 0) { ++ if (fmtdesc.pixelformat == pixelformat) ++ return 0; + -+ // Close exported capture buffers or requests for output buffers -+ if (buf->fd >= 0) { -+ close(buf->fd); -+ buf->fd = -1; ++ fmtdesc.index++; + } ++ ++ return AVERROR(errno); +} + -+static void v4l2_request_frame_free(void *opaque, uint8_t *data) ++static int v4l2request_set_controls(AVHWFramesContext *hwfc, ++ struct v4l2_ext_control *control, int count) +{ -+ V4L2RequestFrameDescriptor *desc = (V4L2RequestFrameDescriptor *)data; ++ AVV4L2RequestFramesContext *fctx = hwfc->hwctx; ++ AVV4L2RequestFramesContextInternal *fctxi = fctx->internal; ++ struct v4l2_ext_controls controls = { ++ .controls = control, ++ .count = count, ++ }; + -+ v4l2_request_buffer_free(&desc->capture); ++ if (!control || !count) ++ return 0; + -+ av_free(data); ++ if (ioctl(fctxi->video_fd, VIDIOC_S_EXT_CTRLS, &controls) < 0) ++ return AVERROR(errno); ++ ++ return 0; +} + -+static AVBufferRef *v4l2_request_frame_alloc(void *opaque, size_t size) ++static int v4l2request_probe_video_device(AVHWFramesContext *hwfc, ++ const char *path, ++ uint32_t pixelformat, ++ uint32_t buffersize) +{ -+ V4L2RequestContext *ctx = opaque; -+ V4L2RequestFrameDescriptor *desc; -+ AVBufferRef *ref; -+ uint8_t *data; ++ AVV4L2RequestFramesContext *fctx = hwfc->hwctx; ++ AVV4L2RequestFramesContextInternal *fctxi = fctx->internal; ++ struct v4l2_capability capability; ++ struct v4l2_create_buffers buffers; ++ unsigned int capabilities; ++ int ret; + -+ data = av_mallocz(size); -+ if (!data) -+ return NULL; ++ /* ++ * Open video device in non-blocking mode to support decoding using ++ * multiple queued requests, required for e.g. multi stage decoding. ++ */ ++ fctxi->video_fd = open(path, O_RDWR | O_NONBLOCK); ++ if (fctxi->video_fd < 0) { ++ ret = AVERROR(errno); ++ av_log(hwfc, AV_LOG_ERROR, "Failed to open video device %s: %s (%d)\n", ++ path, strerror(errno), errno); ++ return ret; ++ } + -+ ref = av_buffer_create(data, size, v4l2_request_frame_free, ctx, 0); -+ if (!ref) { -+ av_free(data); -+ return NULL; ++ // Query capabilities of the video device ++ if (ioctl(fctxi->video_fd, VIDIOC_QUERYCAP, &capability) < 0) { ++ ret = AVERROR(errno); ++ av_log(hwfc, AV_LOG_ERROR, "Failed to query capabilities of %s: %s (%d)\n", ++ path, strerror(errno), errno); ++ goto fail; + } + -+ desc = (V4L2RequestFrameDescriptor *)data; -+ desc->capture.fd = -1; ++ // Use device capabilities of the opened device when supported ++ capabilities = (capability.capabilities & V4L2_CAP_DEVICE_CAPS) ? ++ capability.device_caps : capability.capabilities; + -+ // Create a V4L2 capture buffer for this AVFrame -+ if (v4l2_request_buffer_alloc(ctx, &desc->capture, ctx->format.type) < 0) { -+ av_buffer_unref(&ref); -+ return NULL; ++ // Ensure streaming is supported on the video device ++ if ((capabilities & V4L2_CAP_STREAMING) != V4L2_CAP_STREAMING) { ++ ret = AVERROR(EINVAL); ++ av_log(hwfc, AV_LOG_VERBOSE, "Device %s is missing streaming capability\n", path); ++ goto fail; + } + -+ // TODO: Set AVDRMFrameDescriptor of this AVFrame -+ -+ return ref; -+} ++ // Ensure multi- or single-planar API can be used ++ if ((capabilities & V4L2_CAP_VIDEO_M2M_MPLANE) == V4L2_CAP_VIDEO_M2M_MPLANE) { ++ fctxi->output.format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; ++ fctxi->capture.format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; ++ } else if ((capabilities & V4L2_CAP_VIDEO_M2M) == V4L2_CAP_VIDEO_M2M) { ++ fctxi->output.format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ fctxi->capture.format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ } else { ++ ret = AVERROR(EINVAL); ++ av_log(hwfc, AV_LOG_VERBOSE, "Device %s is missing mem2mem capability\n", path); ++ goto fail; ++ } + -+static void v4l2_request_hwframe_ctx_free(AVHWFramesContext *hwfc) -+{ -+ av_buffer_pool_uninit(&hwfc->pool); -+} ++ // Query OUTPUT buffer capabilities ++ buffers = (struct v4l2_create_buffers) { ++ .count = 0, ++ .memory = V4L2_MEMORY_MMAP, ++ .format.type = fctxi->output.format.type, ++ }; ++ if (ioctl(fctxi->video_fd, VIDIOC_CREATE_BUFS, &buffers) < 0) { ++ ret = AVERROR(errno); ++ av_log(hwfc, AV_LOG_ERROR, ++ "Failed to query OUTPUT buffer capabilities of %s: %s (%d)\n", ++ path, strerror(errno), errno); ++ goto fail; ++ } ++ fctxi->output.capabilities = buffers.capabilities; + -+int ff_v4l2_request_frame_params(AVCodecContext *avctx, -+ AVBufferRef *hw_frames_ctx) -+{ -+ V4L2RequestContext *ctx = v4l2_request_context(avctx); -+ AVHWFramesContext *hwfc = (AVHWFramesContext *)hw_frames_ctx->data; -+ -+ hwfc->format = AV_PIX_FMT_DRM_PRIME; -+ // TODO: Set sw_format based on capture buffer format -+ hwfc->sw_format = AV_PIX_FMT_NONE; -+ -+ if (V4L2_TYPE_IS_MULTIPLANAR(ctx->format.type)) { -+ hwfc->width = ctx->format.fmt.pix_mp.width; -+ hwfc->height = ctx->format.fmt.pix_mp.height; -+ } else { -+ hwfc->width = ctx->format.fmt.pix.width; -+ hwfc->height = ctx->format.fmt.pix.height; ++ // Ensure requests can be used ++ if ((buffers.capabilities & V4L2_BUF_CAP_SUPPORTS_REQUESTS) != ++ V4L2_BUF_CAP_SUPPORTS_REQUESTS) { ++ ret = AVERROR(EINVAL); ++ av_log(hwfc, AV_LOG_VERBOSE, "Device %s is missing support for requests\n", path); ++ goto fail; + } + -+ hwfc->pool = av_buffer_pool_init2(sizeof(V4L2RequestFrameDescriptor), ctx, -+ v4l2_request_frame_alloc, NULL); -+ if (!hwfc->pool) -+ return AVERROR(ENOMEM); -+ -+ hwfc->free = v4l2_request_hwframe_ctx_free; -+ -+ hwfc->initial_pool_size = 1; -+ -+ switch (avctx->codec_id) { -+ case AV_CODEC_ID_VP9: -+ hwfc->initial_pool_size += 8; -+ break; -+ case AV_CODEC_ID_VP8: -+ hwfc->initial_pool_size += 3; -+ break; -+ default: -+ hwfc->initial_pool_size += 2; ++ // Ensure the codec pixelformat can be used ++ ret = v4l2request_try_format(hwfc, fctxi->output.format.type, pixelformat); ++ if (ret < 0) { ++ av_log(hwfc, AV_LOG_VERBOSE, "Device %s is missing support for pixelformat %s\n", ++ path, av_fourcc2str(pixelformat)); ++ goto fail; + } + -+ return 0; -+} -+ -+int ff_v4l2_request_uninit(AVCodecContext *avctx) -+{ -+ V4L2RequestContext *ctx = v4l2_request_context(avctx); -+ -+ if (ctx->video_fd >= 0) { -+ // TODO: Flush and wait on all pending requests ++ // Ensure frame size is supported, when driver support ENUM_FRAMESIZES ++ ret = v4l2request_try_framesize(hwfc, pixelformat); ++ if (ret < 0 && ret != AVERROR(ENOTTY)) { ++ av_log(hwfc, AV_LOG_VERBOSE, ++ "Device %s is missing support for frame size %dx%d of pixelformat %s\n", ++ path, hwfc->width, hwfc->height, av_fourcc2str(pixelformat)); ++ goto fail; ++ } + -+ // Stop output queue -+ if (ioctl(ctx->video_fd, VIDIOC_STREAMOFF, &ctx->output_type) < 0) { -+ av_log(ctx, AV_LOG_WARNING, "Failed to stop output streaming: %s (%d)\n", -+ strerror(errno), errno); -+ } ++ // Set the codec pixelformat and OUTPUT buffersize to be used ++ ret = v4l2request_set_format(hwfc, fctxi->output.format.type, pixelformat, buffersize); ++ if (ret < 0) { ++ av_log(hwfc, AV_LOG_ERROR, ++ "Failed to set OUTPUT pixelformat %s of %s: %s (%d)\n", ++ av_fourcc2str(pixelformat), path, strerror(errno), errno); ++ goto fail; ++ } + -+ // Stop capture queue -+ if (ioctl(ctx->video_fd, VIDIOC_STREAMOFF, &ctx->format.type) < 0) { -+ av_log(ctx, AV_LOG_WARNING, "Failed to stop capture streaming: %s (%d)\n", -+ strerror(errno), errno); -+ } ++ // Get format details for OUTPUT buffers ++ if (ioctl(fctxi->video_fd, VIDIOC_G_FMT, &fctxi->output.format) < 0) { ++ ret = AVERROR(errno); ++ av_log(hwfc, AV_LOG_ERROR, "Failed to get OUTPUT format: %s (%d)\n", ++ strerror(errno), errno); ++ goto fail; ++ } + -+ // Release output buffers -+ for (int i = 0; i < FF_ARRAY_ELEMS(ctx->output); i++) { -+ v4l2_request_buffer_free(&ctx->output[i]); -+ } ++ /* ++ * Set any codec specific controls that can help assist the driver ++ * make a decision on what CAPTURE buffer format can be used. ++ */ ++ ret = v4l2request_set_controls(hwfc, fctx->init_controls, fctx->nb_init_controls); ++ if (ret < 0) { ++ av_log(hwfc, AV_LOG_VERBOSE, ++ "Failed to set %d control(s): %s (%d)\n", ++ fctx->nb_init_controls, strerror(errno), errno); ++ goto fail; ++ } + -+ // Close video device file descriptor -+ close(ctx->video_fd); -+ ctx->video_fd = -1; ++ // Select a supported CAPTURE buffer format ++ ret = v4l2request_select_capture_format(hwfc); ++ if (ret < 0) { ++ av_log(hwfc, AV_LOG_VERBOSE, ++ "Failed to select a CAPTURE format %s of %s: %s (%d)\n", ++ av_fourcc2str(pixelformat), path, strerror(errno), errno); ++ goto fail; + } + -+ // Ownership of media device file descriptor may belong to hwdevice -+ if (ctx->device_ref) { -+ av_buffer_unref(&ctx->device_ref); -+ ctx->media_fd = -1; -+ } else if (ctx->media_fd >= 0) { -+ close(ctx->media_fd); -+ ctx->media_fd = -1; ++ // Query CAPTURE buffer capabilities ++ buffers = (struct v4l2_create_buffers) { ++ .count = 0, ++ .memory = V4L2_MEMORY_MMAP, ++ .format.type = fctxi->capture.format.type, ++ }; ++ if (ioctl(fctxi->video_fd, VIDIOC_CREATE_BUFS, &buffers) < 0) { ++ ret = AVERROR(errno); ++ av_log(hwfc, AV_LOG_ERROR, ++ "Failed to query CAPTURE buffer capabilities of %s: %s (%d)\n", ++ path, strerror(errno), errno); ++ goto fail; + } ++ fctxi->capture.capabilities = buffers.capabilities; + -+ ff_mutex_destroy(&ctx->mutex); ++ // Get format details for CAPTURE buffers ++ if (ioctl(fctxi->video_fd, VIDIOC_G_FMT, &fctxi->capture.format) < 0) { ++ ret = AVERROR(errno); ++ av_log(hwfc, AV_LOG_ERROR, "Failed to get CAPTURE format: %s (%d)\n", ++ strerror(errno), errno); ++ goto fail; ++ } + ++ // All tests passed, video device should be capable + return 0; ++ ++fail: ++ if (fctxi->video_fd >= 0) { ++ close(fctxi->video_fd); ++ fctxi->video_fd = -1; ++ } ++ return ret; +} + -+static int v4l2_request_init_context(AVCodecContext *avctx) ++static int v4l2request_probe_video_devices(AVHWFramesContext *hwfc, ++ struct udev *udev, ++ uint32_t pixelformat, ++ uint32_t buffersize) +{ -+ V4L2RequestContext *ctx = v4l2_request_context(avctx); ++ AVV4L2RequestFramesContext *fctx = hwfc->hwctx; ++ AVV4L2RequestFramesContextInternal *fctxi = fctx->internal; ++ struct media_device_info device_info; ++ struct media_v2_topology topology = {0}; ++ struct media_v2_interface *interfaces; ++ struct udev_device *device; ++ const char *path; ++ dev_t devnum; + int ret; + -+ // Initialize context state -+ ff_mutex_init(&ctx->mutex, NULL); -+ for (int i = 0; i < FF_ARRAY_ELEMS(ctx->output); i++) { -+ ctx->output[i].index = i; -+ ctx->output[i].fd = -1; -+ } -+ atomic_init(&ctx->next_output, 0); -+ atomic_init(&ctx->queued_output, 0); -+ atomic_init(&ctx->queued_request, 0); -+ atomic_init(&ctx->queued_capture, 0); ++ if (ioctl(fctxi->media_fd, MEDIA_IOC_DEVICE_INFO, &device_info) < 0) ++ return AVERROR(errno); + -+ // Get format details for capture buffers -+ if (ioctl(ctx->video_fd, VIDIOC_G_FMT, &ctx->format) < 0) { -+ av_log(ctx, AV_LOG_ERROR, "Failed to get capture format: %s (%d)\n", ++ if (ioctl(fctxi->media_fd, MEDIA_IOC_G_TOPOLOGY, &topology) < 0) { ++ ret = AVERROR(errno); ++ av_log(hwfc, AV_LOG_ERROR, "Failed to get media topology: %s (%d)\n", + strerror(errno), errno); ++ return ret; ++ } ++ ++ if (!topology.num_interfaces) ++ return AVERROR(ENOENT); ++ ++ interfaces = av_calloc(topology.num_interfaces, sizeof(struct media_v2_interface)); ++ if (!interfaces) ++ return AVERROR(ENOMEM); ++ ++ topology.ptr_interfaces = (__u64)(uintptr_t)interfaces; ++ if (ioctl(fctxi->media_fd, MEDIA_IOC_G_TOPOLOGY, &topology) < 0) { + ret = AVERROR(errno); ++ av_log(hwfc, AV_LOG_ERROR, "Failed to get media topology: %s (%d)\n", ++ strerror(errno), errno); + goto fail; + } + -+ // Create frame context and allocate initial capture buffers -+ ret = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_V4L2REQUEST); -+ if (ret < 0) -+ goto fail; ++ ret = AVERROR(ENOENT); ++ for (int i = 0; i < topology.num_interfaces; i++) { ++ if (interfaces[i].intf_type != MEDIA_INTF_T_V4L_VIDEO) ++ continue; + -+ // Allocate output buffers for circular queue -+ for (int i = 0; i < FF_ARRAY_ELEMS(ctx->output); i++) { -+ ret = v4l2_request_buffer_alloc(ctx, &ctx->output[i], ctx->output_type); -+ if (ret < 0) -+ goto fail; -+ } ++ devnum = makedev(interfaces[i].devnode.major, interfaces[i].devnode.minor); ++ device = udev_device_new_from_devnum(udev, 'c', devnum); ++ if (!device) ++ continue; + -+ // Allocate requests for circular queue -+ for (int i = 0; i < FF_ARRAY_ELEMS(ctx->output); i++) { -+ if (ioctl(ctx->media_fd, MEDIA_IOC_REQUEST_ALLOC, &ctx->output[i].fd) < 0) { -+ av_log(ctx, AV_LOG_ERROR, "Failed to allocate request %d: %s (%d)\n", -+ i, strerror(errno), errno); -+ ret = AVERROR(errno); -+ goto fail; ++ path = udev_device_get_devnode(device); ++ if (path) ++ ret = v4l2request_probe_video_device(hwfc, path, pixelformat, buffersize); ++ udev_device_unref(device); ++ ++ // Stop when we have found a capable video device ++ if (!ret) { ++ av_log(hwfc, AV_LOG_INFO, ++ "Using V4L2 media driver %s (%u.%u.%u) for %s\n", ++ device_info.driver, ++ device_info.driver_version >> 16, ++ (device_info.driver_version >> 8) & 0xff, ++ device_info.driver_version & 0xff, ++ av_fourcc2str(pixelformat)); ++ break; + } + } + -+ // Start output queue -+ if (ioctl(ctx->video_fd, VIDIOC_STREAMON, &ctx->output_type) < 0) { -+ av_log(ctx, AV_LOG_ERROR, "Failed to start output streaming: %s (%d)\n", -+ strerror(errno), errno); -+ ret = AVERROR(errno); -+ goto fail; -+ } ++fail: ++ av_free(interfaces); ++ return ret; ++} + -+ // Start capture queue -+ if (ioctl(ctx->video_fd, VIDIOC_STREAMON, &ctx->format.type) < 0) { -+ av_log(ctx, AV_LOG_ERROR, "Failed to start capture streaming: %s (%d)\n", -+ strerror(errno), errno); ++static int v4l2request_probe_media_device(AVHWFramesContext *hwfc, ++ struct udev_device *device, ++ uint32_t pixelformat, ++ uint32_t buffersize) ++{ ++ AVV4L2RequestFramesContext *fctx = hwfc->hwctx; ++ AVV4L2RequestFramesContextInternal *fctxi = fctx->internal; ++ const char *path; ++ int ret; ++ ++ path = udev_device_get_devnode(device); ++ if (!path) ++ return AVERROR(ENODEV); ++ ++ // Open enumerated media device ++ fctxi->media_fd = open(path, O_RDWR); ++ if (fctxi->media_fd < 0) { + ret = AVERROR(errno); -+ goto fail; ++ av_log(hwfc, AV_LOG_ERROR, "Failed to open media device %s: %s (%d)\n", ++ path, strerror(errno), errno); ++ return ret; + } + -+ return 0; ++ // Probe video devices of current media device ++ ret = v4l2request_probe_video_devices(hwfc, udev_device_get_udev(device), ++ pixelformat, buffersize); ++ ++ // Cleanup when no capable video device was found ++ if (ret < 0) { ++ close(fctxi->media_fd); ++ fctxi->media_fd = -1; ++ } + -+fail: -+ ff_v4l2_request_uninit(avctx); + return ret; +} + -+int ff_v4l2_request_init(AVCodecContext *avctx, -+ uint32_t pixelformat, uint32_t buffersize, -+ struct v4l2_ext_control *control, int count) ++static int v4l2request_probe_media_devices(AVHWFramesContext *hwfc, ++ struct udev *udev, ++ uint32_t pixelformat, ++ uint32_t buffersize) +{ -+ V4L2RequestContext *ctx = v4l2_request_context(avctx); -+ AVV4L2RequestDeviceContext *hwctx = NULL; ++ struct udev_enumerate *enumerate; ++ struct udev_list_entry *devices; ++ struct udev_list_entry *entry; ++ struct udev_device *device; ++ int ret; + -+ // Set initial default values -+ ctx->av_class = &v4l2_request_context_class; -+ ctx->media_fd = -1; -+ ctx->video_fd = -1; -+ -+ // Try to use media device file descriptor opened and owned by hwdevice -+ if (avctx->hw_device_ctx) { -+ AVHWDeviceContext *device_ctx = (AVHWDeviceContext *)avctx->hw_device_ctx->data; -+ if (device_ctx->type == AV_HWDEVICE_TYPE_V4L2REQUEST && device_ctx->hwctx) { -+ hwctx = device_ctx->hwctx; -+ ctx->media_fd = hwctx->media_fd; -+ } -+ } ++ enumerate = udev_enumerate_new(udev); ++ if (!enumerate) ++ return AVERROR(ENOMEM); ++ ++ udev_enumerate_add_match_subsystem(enumerate, "media"); ++ udev_enumerate_scan_devices(enumerate); ++ devices = udev_enumerate_get_list_entry(enumerate); ++ ++ ret = AVERROR(ENOENT); ++ udev_list_entry_foreach(entry, devices) { ++ const char *path = udev_list_entry_get_name(entry); ++ if (!path) ++ continue; ++ ++ device = udev_device_new_from_syspath(udev, path); ++ if (!device) ++ continue; + -+ // TODO: Probe for a capable media and video device ++ // Probe media device for a capable video device ++ ret = v4l2request_probe_media_device(hwfc, device, pixelformat, buffersize); ++ udev_device_unref(device); + -+ // Transfer (or return) ownership of media device file descriptor to hwdevice -+ if (hwctx) { -+ hwctx->media_fd = ctx->media_fd; -+ ctx->device_ref = av_buffer_ref(avctx->hw_device_ctx); ++ // Stop when we have found a capable media and video device ++ if (!ret) ++ break; + } + -+ // Create buffers and finalize init -+ return v4l2_request_init_context(avctx); ++ udev_enumerate_unref(enumerate); ++ return ret; +} -diff --git a/libavcodec/v4l2_request.h b/libavcodec/v4l2_request.h ++ + static int v4l2request_open_decoder(AVHWFramesContext *hwfc) + { + AVV4L2RequestFramesContext *fctx = hwfc->hwctx; ++ uint32_t buffersize; ++ struct udev *udev; ++ int ret; + + // Ensure codec pixelformat is set + if (!fctx->pixelformat) + return AVERROR(EINVAL); + +- // TODO: locate a decoder supporting the requested pixelformat ++ // FIXME: locate a decoder using hwdevice context decoders ++ ++ udev = udev_new(); ++ if (!udev) ++ return AVERROR(ENOMEM); ++ ++ buffersize = FFMAX(hwfc->width * hwfc->height * 3 / 2, 256 * 1024); ++ ++ // Probe all media devices (auto-detection) ++ ret = v4l2request_probe_media_devices(hwfc, udev, fctx->pixelformat, buffersize); + +- return AVERROR(ENOSYS); ++ udev_unref(udev); ++ return ret; + } + + static AVBufferRef *v4l2request_v4l2_buffer_alloc(AVHWFramesContext *hwfc, + +From 9a5d025a873145afc16fea3078ae3410d2291280 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Tue, 6 Aug 2024 09:06:01 +0000 +Subject: [PATCH 03/13] avcodec: Add common V4L2 Request API code + +Add initial helpers for supporting V4L2 Request API hwaccels. + +Basic flow for initialization follows the kernel Memory-to-memory +Stateless Video Decoder Interface > Initialization [1]. + +In init a hw frame ctx is created and initialized to start a new V4L2 +video decoding session, initial CAPTURE buffers is pre-allocated, +OUTPUT buffers and request objects are allocated for a circular queue. + +In frame_params the codec pixel format and optional codec-specific +extended controls is configured before the hw frame ctx is initialized. + +In uninit any pending request is flushed before resources are released. + +[1] https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-stateless-decoder.html#initialization + +Co-developed-by: Jernej Skrabec +Signed-off-by: Jernej Skrabec +Co-developed-by: Alex Bee +Signed-off-by: Alex Bee +Signed-off-by: Jonas Karlman +--- + libavcodec/Makefile | 2 + + libavcodec/v4l2_request.c | 249 ++++++++++++++++++++++++++++++++++++++ + libavcodec/v4l2_request.h | 64 ++++++++++ + 3 files changed, 315 insertions(+) + create mode 100644 libavcodec/v4l2_request.c + create mode 100644 libavcodec/v4l2_request.h + +diff --git a/libavcodec/Makefile b/libavcodec/Makefile +index 12a8265025bc..a2212bbf9504 100644 +--- a/libavcodec/Makefile ++++ b/libavcodec/Makefile +@@ -185,6 +185,7 @@ OBJS-$(CONFIG_VIDEODSP) += videodsp.o + OBJS-$(CONFIG_VP3DSP) += vp3dsp.o + OBJS-$(CONFIG_VP8DSP) += vp8dsp.o + OBJS-$(CONFIG_V4L2_M2M) += v4l2_m2m.o v4l2_context.o v4l2_buffers.o v4l2_fmt.o ++OBJS-$(CONFIG_V4L2_REQUEST) += v4l2_request.o + OBJS-$(CONFIG_WMA_FREQS) += wma_freqs.o + OBJS-$(CONFIG_WMV2DSP) += wmv2dsp.o + +@@ -1360,6 +1361,7 @@ SKIPHEADERS-$(CONFIG_VIDEOTOOLBOX) += videotoolbox.h vt_internal.h + SKIPHEADERS-$(CONFIG_VULKAN) += ffv1_vulkan.h prores_vulkan.h vulkan_video.h \ + vulkan_encode.h vulkan_decode.h + SKIPHEADERS-$(CONFIG_V4L2_M2M) += v4l2_buffers.h v4l2_context.h v4l2_m2m.h ++SKIPHEADERS-$(CONFIG_V4L2_REQUEST) += v4l2_request.h + SKIPHEADERS-$(CONFIG_ZLIB) += zlib_wrapper.h + + TESTPROGS = avcodec \ +diff --git a/libavcodec/v4l2_request.c b/libavcodec/v4l2_request.c new file mode 100644 -index 0000000000..621caaf28c +index 000000000000..dfec0e8906a8 --- /dev/null -+++ b/libavcodec/v4l2_request.h -@@ -0,0 +1,84 @@ ++++ b/libavcodec/v4l2_request.c +@@ -0,0 +1,249 @@ +/* + * This file is part of FFmpeg. + * @@ -991,78 +1626,243 @@ index 0000000000..621caaf28c + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + -+#ifndef AVCODEC_V4L2_REQUEST_H -+#define AVCODEC_V4L2_REQUEST_H ++#include "config.h" + -+#include -+#include ++#include ++#include ++#include ++#include + -+#include ++#include "libavutil/hwcontext_v4l2request_internal.h" ++#include "libavutil/mem.h" ++#include "decode.h" ++#include "internal.h" ++#include "v4l2_request.h" + -+#include "libavutil/hwcontext_drm.h" -+#include "libavutil/thread.h" ++static const AVClass v4l2_request_context_class = { ++ .class_name = "V4L2RequestContext", ++ .item_name = av_default_item_name, ++ .version = LIBAVUTIL_VERSION_INT, ++}; + -+typedef struct V4L2RequestBuffer { -+ int index; -+ int fd; -+ uint8_t *addr; -+ uint32_t width; -+ uint32_t height; -+ uint32_t size; -+ uint32_t used; -+ uint32_t capabilities; -+ struct v4l2_buffer buffer; -+} V4L2RequestBuffer; ++static inline V4L2RequestContext *v4l2_request_context(AVCodecContext *avctx) ++{ ++ return (V4L2RequestContext *)avctx->internal->hwaccel_priv_data; ++} + -+typedef struct V4L2RequestContext { -+ const AVClass *av_class; -+ AVBufferRef *device_ref; -+ int media_fd; -+ int video_fd; -+ struct v4l2_format format; -+ enum v4l2_buf_type output_type; -+ AVMutex mutex; -+ V4L2RequestBuffer output[4]; -+ atomic_int_least8_t next_output; -+ atomic_uint_least32_t queued_output; -+ atomic_uint_least32_t queued_request; -+ atomic_uint_least64_t queued_capture; -+ int (*post_probe)(AVCodecContext *avctx); -+} V4L2RequestContext; ++static void v4l2_request_output_buffer_uninit(V4L2RequestOutputBuffer *output) ++{ ++ // Close the request associated with the OUTPUT buffer ++ if (output->request_fd >= 0) { ++ close(output->request_fd); ++ output->request_fd = -1; ++ } + -+typedef struct V4L2RequestPictureContext { -+ V4L2RequestBuffer *output; -+ V4L2RequestBuffer *capture; -+} V4L2RequestPictureContext; ++ // Umap the OUTPUT buffer memory ++ if (output->addr) { ++ munmap(output->addr, output->size); ++ output->addr = NULL; ++ } + -+int ff_v4l2_request_query_control(AVCodecContext *avctx, -+ struct v4l2_query_ext_ctrl *control); ++ // Return the OUTPUT buffer to the frames context OUTPUT pool ++ av_buffer_unref(&output->ref); ++} + -+int ff_v4l2_request_query_control_default_value(AVCodecContext *avctx, -+ uint32_t id); ++static int v4l2_request_output_buffer_init(V4L2RequestContext *ctx, ++ V4L2RequestOutputBuffer *output) ++{ ++ struct v4l2_format *format = &ctx->fctxi->output.format; ++ struct v4l2_buffer *buffer; ++ off_t offset; ++ void *addr; ++ int ret; + -+int ff_v4l2_request_set_request_controls(V4L2RequestContext *ctx, int request_fd, -+ struct v4l2_ext_control *control, int count); ++ // Get an OUTPUT buffer from frames context OUTPUT pool ++ output->ref = av_buffer_pool_get(ctx->fctxi->output.pool); ++ if (!output->ref) ++ return AVERROR(ENOMEM); + -+int ff_v4l2_request_set_controls(AVCodecContext *avctx, -+ struct v4l2_ext_control *control, int count); ++ buffer = (struct v4l2_buffer *)output->ref->data; ++ output->index = buffer->index; ++ output->size = V4L2_TYPE_IS_MULTIPLANAR(format->type) ? ++ format->fmt.pix_mp.plane_fmt[0].sizeimage : ++ format->fmt.pix.sizeimage; ++ output->bytesused = 0; ++ ++ // Map the OUTPUT buffer memory, raw bitstream data is written into it ++ offset = V4L2_TYPE_IS_MULTIPLANAR(buffer->type) ? ++ buffer->m.planes[0].m.mem_offset : ++ buffer->m.offset; ++ addr = mmap(NULL, output->size, PROT_READ | PROT_WRITE, MAP_SHARED, ++ ctx->fctxi->video_fd, offset); ++ if (addr == MAP_FAILED) { ++ ret = AVERROR(errno); ++ av_log(ctx, AV_LOG_ERROR, "Failed to map OUTPUT buffer %d: %s (%d)\n", ++ output->index, strerror(errno), errno); ++ goto fail; ++ } ++ output->addr = addr; ++ ++ // Allocate and associated a request for the OUTPUT buffer ++ if (ioctl(ctx->fctxi->media_fd, MEDIA_IOC_REQUEST_ALLOC, &output->request_fd) < 0) { ++ ret = AVERROR(errno); ++ av_log(ctx, AV_LOG_ERROR, "Failed to allocate request for OUTPUT buffer %d: %s (%d)\n", ++ output->index, strerror(errno), errno); ++ goto fail; ++ } ++ ++ return 0; ++ ++fail: ++ v4l2_request_output_buffer_uninit(output); ++ return ret; ++} + +int ff_v4l2_request_frame_params(AVCodecContext *avctx, -+ AVBufferRef *hw_frames_ctx); ++ AVBufferRef *hw_frames_ctx, ++ uint32_t pixelformat, ++ uint8_t bit_depth) ++{ ++ V4L2RequestContext *ctx = v4l2_request_context(avctx); ++ AVHWFramesContext *hwfc = (AVHWFramesContext *)hw_frames_ctx->data; ++ AVV4L2RequestFramesContext *fctx = hwfc->hwctx; ++ ++ // Set parameters used during frames context initialization ++ fctx->pixelformat = pixelformat; ++ fctx->bit_depth = bit_depth; ++ if (ctx) { ++ fctx->init_controls = ctx->init_controls; ++ fctx->nb_init_controls = ctx->nb_init_controls; ++ } + -+int ff_v4l2_request_uninit(AVCodecContext *avctx); ++ hwfc->format = AV_PIX_FMT_DRM_PRIME; ++ hwfc->sw_format = AV_PIX_FMT_NONE; ++ hwfc->width = avctx->coded_width; ++ hwfc->height = avctx->coded_height; ++ ++ // Pre-allocate CAPTURE buffers to ensure CAPTURE queue can be started ++ hwfc->initial_pool_size = 1; ++ ++ return 0; ++} ++ ++int ff_v4l2_request_uninit(AVCodecContext *avctx) ++{ ++ V4L2RequestContext *ctx = v4l2_request_context(avctx); ++ enum v4l2_buf_type type; ++ ++ if (ctx->fctxi) { ++ // TODO: Flush and wait on all pending requests ++ ++ // Stop streaming on OUTPUT queue ++ type = ctx->fctxi->output.format.type; ++ if (ioctl(ctx->fctxi->video_fd, VIDIOC_STREAMOFF, &type) < 0) ++ av_log(ctx, AV_LOG_WARNING, "Failed to stop OUTPUT streaming: %s (%d)\n", ++ strerror(errno), errno); ++ ++ // Stop streaming on CAPTURE queue ++ type = ctx->fctxi->capture.format.type; ++ if (ioctl(ctx->fctxi->video_fd, VIDIOC_STREAMOFF, &type) < 0) ++ av_log(ctx, AV_LOG_WARNING, "Failed to stop CAPTURE streaming: %s (%d)\n", ++ strerror(errno), errno); ++ ++ // Release OUTPUT buffers and requests ++ for (int i = 0; i < FF_ARRAY_ELEMS(ctx->output); i++) ++ v4l2_request_output_buffer_uninit(&ctx->output[i]); ++ ++ ctx->fctxi = NULL; ++ } ++ ++ av_buffer_unref(&ctx->frames_ref); ++ ff_mutex_destroy(&ctx->mutex); ++ ++ return 0; ++} + +int ff_v4l2_request_init(AVCodecContext *avctx, -+ uint32_t pixelformat, uint32_t buffersize, -+ struct v4l2_ext_control *control, int count); ++ struct v4l2_ext_control *control, int count, ++ int (*post_frames_ctx)(AVCodecContext *avctx)) ++{ ++ V4L2RequestContext *ctx = v4l2_request_context(avctx); ++ AVHWFramesContext *hwfc; ++ AVV4L2RequestFramesContext *fctx; ++ enum v4l2_buf_type type; ++ int ret; + -+#endif /* AVCODEC_V4L2_REQUEST_H */ -diff --git a/libavcodec/v4l2_request_internal.h b/libavcodec/v4l2_request_internal.h ++ // Set initial default values ++ ctx->av_class = &v4l2_request_context_class; ++ ctx->init_controls = control; ++ ctx->nb_init_controls = count; ++ ff_mutex_init(&ctx->mutex, NULL); ++ for (int i = 0; i < FF_ARRAY_ELEMS(ctx->output); i++) { ++ ctx->output[i].index = i; ++ ctx->output[i].request_fd = -1; ++ } ++ ++ // Create frames context and allocate initial CAPTURE buffers ++ ret = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_V4L2REQUEST); ++ if (ret < 0) ++ goto fail; ++ ++ ctx->frames_ref = av_buffer_ref(avctx->hw_frames_ctx); ++ if (!ctx->frames_ref) { ++ ret = AVERROR(ENOMEM); ++ goto fail; ++ } ++ ++ // Get internal hwctx from frames context ++ hwfc = (AVHWFramesContext *)ctx->frames_ref->data; ++ fctx = hwfc->hwctx; ++ ctx->fctxi = fctx->internal; ++ ++ // Reset init controls after successful frames context initialization ++ ctx->init_controls = NULL; ++ ctx->nb_init_controls = 0; ++ ++ // Check codec-specific controls, e.g. profile and level ++ if (post_frames_ctx) { ++ ret = post_frames_ctx(avctx); ++ if (ret < 0) ++ goto fail; ++ } ++ ++ // Allocate OUTPUT buffers and requests for circular queue ++ for (int i = 0; i < FF_ARRAY_ELEMS(ctx->output); i++) { ++ ret = v4l2_request_output_buffer_init(ctx, &ctx->output[i]); ++ if (ret < 0) ++ goto fail; ++ } ++ ++ // Start streaming on OUTPUT queue ++ type = ctx->fctxi->output.format.type; ++ if (ioctl(ctx->fctxi->video_fd, VIDIOC_STREAMON, &type) < 0) { ++ ret = AVERROR(errno); ++ av_log(ctx, AV_LOG_ERROR, "Failed to start OUTPUT streaming: %s (%d)\n", ++ strerror(errno), errno); ++ goto fail; ++ } ++ ++ // Start streaming on CAPTURE queue ++ type = ctx->fctxi->capture.format.type; ++ if (ioctl(ctx->fctxi->video_fd, VIDIOC_STREAMON, &type) < 0) { ++ ret = AVERROR(errno); ++ av_log(ctx, AV_LOG_ERROR, "Failed to start CAPTURE streaming: %s (%d)\n", ++ strerror(errno), errno); ++ goto fail; ++ } ++ ++ return 0; ++ ++fail: ++ ff_v4l2_request_uninit(avctx); ++ return ret; ++} +diff --git a/libavcodec/v4l2_request.h b/libavcodec/v4l2_request.h new file mode 100644 -index 0000000000..554b663ab4 +index 000000000000..d09bbf73441c --- /dev/null -+++ b/libavcodec/v4l2_request_internal.h -@@ -0,0 +1,42 @@ ++++ b/libavcodec/v4l2_request.h +@@ -0,0 +1,64 @@ +/* + * This file is part of FFmpeg. + * @@ -1081,56 +1881,85 @@ index 0000000000..554b663ab4 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + -+#ifndef AVCODEC_V4L2_REQUEST_INTERNAL_H -+#define AVCODEC_V4L2_REQUEST_INTERNAL_H ++#ifndef AVCODEC_V4L2_REQUEST_H ++#define AVCODEC_V4L2_REQUEST_H + -+#include ++#include ++#include ++#include + -+#include "internal.h" -+#include "v4l2_request.h" ++#include "libavutil/buffer.h" ++#include "libavutil/log.h" ++#include "libavutil/thread.h" ++#include "avcodec.h" + -+typedef struct V4L2RequestFrameDescriptor { -+ AVDRMFrameDescriptor base; -+ V4L2RequestBuffer capture; -+} V4L2RequestFrameDescriptor; ++typedef struct AVV4L2RequestFramesContextInternal AVV4L2RequestFramesContextInternal; + -+static inline V4L2RequestContext *v4l2_request_context(AVCodecContext *avctx) -+{ -+ return (V4L2RequestContext *)avctx->internal->hwaccel_priv_data; -+} ++typedef struct V4L2RequestOutputBuffer { ++ AVBufferRef *ref; ++ uint32_t index; ++ int request_fd; ++ uint8_t *addr; ++ uint32_t size; ++ uint32_t bytesused; ++ struct timeval timestamp; ++} V4L2RequestOutputBuffer; + -+static inline V4L2RequestFrameDescriptor *v4l2_request_framedesc(AVFrame *frame) -+{ -+ return (V4L2RequestFrameDescriptor *)frame->data[0]; -+} ++typedef struct V4L2RequestContext { ++ const AVClass *av_class; ++ AVBufferRef *frames_ref; ++ AVV4L2RequestFramesContextInternal *fctxi; ++ AVMutex mutex; ++ V4L2RequestOutputBuffer output[4]; ++ struct v4l2_ext_control *init_controls; ++ int nb_init_controls; ++} V4L2RequestContext; ++ ++int ff_v4l2_request_frame_params(AVCodecContext *avctx, ++ AVBufferRef *hw_frames_ctx, ++ uint32_t pixelformat, ++ uint8_t bit_depth); ++ ++int ff_v4l2_request_uninit(AVCodecContext *avctx); ++ ++int ff_v4l2_request_init(AVCodecContext *avctx, ++ struct v4l2_ext_control *control, int count, ++ int (*post_frames_ctx)(AVCodecContext *avctx)); + -+#endif /* AVCODEC_V4L2_REQUEST_INTERNAL_H */ ++#endif /* AVCODEC_V4L2_REQUEST_H */ -From f2779c95d7416be33aa3b50f1c7f1f33f5b9aad5 Mon Sep 17 00:00:00 2001 +From f227da5a137d45d44d37e1d2be6427e9f7c247b3 Mon Sep 17 00:00:00 2001 From: Jonas Karlman -Date: Tue, 6 Aug 2024 09:06:02 +0000 -Subject: [PATCH 03/11] avcodec/v4l2request: Probe for a capable media and - video device +Date: Tue, 6 Aug 2024 09:06:03 +0000 +Subject: [PATCH 04/13] avcodec/v4l2request: Add common decode support for + hwaccels -Probe all media devices and its linked video devices to locate a video -device that support stateless decoding of the specific codec using the -V4L2 Request API. +Add common support for decoding using the V4L2 Request API. -When AVV4L2RequestDeviceContext.media_fd is a valid file descriptor only -video devices for the opened media device is probed. -E.g. using a -init_hw_device v4l2request:/dev/media1 parameter. +Basic flow for decoding follows the kernel Memory-to-memory Stateless +Video Decoder Interface > Decoding [1]. -A video device is deemed capable when all tests pass, e.g. kernel driver -support the codec, FFmpeg v4l2-request code know about the buffer format -and kernel driver report that the frame size is supported. +A codec hwaccel typically handle decoding as follow: -A codec specific hook, post_probe, is supported to e.g. test for codec -specific limitations, PROFILE and LEVEL controls. +In start_frame next OUTPUT buffer and its related request object is +picked from a circular queue and any codec specific CONTROLs are +prepared. -Basic flow for initialization follow the kernel Memory-to-memory -Stateless Video Decoder Interface > Initialization [1]. +In decode_slice the slice bitstream data is appended to the OUTPUT +buffer. -[1] https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-stateless-decoder.html#initialization +In end_frame a CAPTURE buffer tied to the AVFrame is queued, it will be +used as the decoding target by the driver / hw decoder. The prepared +codec specific CONTROLs are queued as part of the request object. +Finally, the request object is submitted for decoding. + +In post_process the AVFrame is only returned once the CAPTURE buffer +tied to the AVFrame has been made available for dequeuing by the driver. + +For slice based hw decoders only the request for the final slice of the +frame is submitted in end_frame, remaining is submitted in decode_slice. + +[1] https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-stateless-decoder.html#decoding Co-developed-by: Jernej Skrabec Signed-off-by: Jernej Skrabec @@ -1138,860 +1967,647 @@ Co-developed-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Jonas Karlman --- - configure | 4 +- - libavcodec/Makefile | 2 +- - libavcodec/v4l2_request.c | 18 +- - libavcodec/v4l2_request_internal.h | 9 + - libavcodec/v4l2_request_probe.c | 614 +++++++++++++++++++++++++++++ - 5 files changed, 641 insertions(+), 6 deletions(-) - create mode 100644 libavcodec/v4l2_request_probe.c + configure | 3 +- + libavcodec/hwconfig.h | 2 + + libavcodec/v4l2_request.c | 537 +++++++++++++++++++++++++++++++++++++- + libavcodec/v4l2_request.h | 41 +++ + 4 files changed, 581 insertions(+), 2 deletions(-) diff --git a/configure b/configure -index b8f82f0fbf..98a342d109 100755 +index d6dbe3734ead..b50aa0605d6d 100755 --- a/configure +++ b/configure -@@ -1966,6 +1966,7 @@ EXTERNAL_LIBRARY_LIST=" - libtorch - libtwolame - libuavs3d -+ libudev - libv4l2 - libvmaf - libvorbis -@@ -3148,7 +3149,7 @@ dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode ole32 user32" +@@ -3344,7 +3344,7 @@ dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode ole32 user32" ffnvcodec_deps_any="libdl LoadLibrary" - mediacodec_deps="android mediandk" + mediacodec_deps="android mediandk pthreads" nvdec_deps="ffnvcodec" --v4l2_request_deps="linux_media_h v4l2_timeval_to_ns" -+v4l2_request_deps="linux_media_h v4l2_timeval_to_ns libdrm libudev" +-v4l2_request_deps="linux_media_h v4l2_timeval_to_ns libdrm libudev" ++v4l2_request_deps="linux_media_h v4l2_timeval_to_ns v4l2_m2m_hold_capture_buf libdrm libudev" + v4l2_request_suggest="libdrm libudev" vaapi_x11_deps="xlib_x11" videotoolbox_hwaccel_deps="videotoolbox pthreads" - videotoolbox_hwaccel_extralibs="-framework QuartzCore" -@@ -7202,6 +7203,7 @@ fi +@@ -7594,6 +7594,7 @@ if enabled v4l2_m2m; then + fi if enabled v4l2_request; then ++ check_cc v4l2_m2m_hold_capture_buf linux/videodev2.h "int i = V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF" check_func_headers "linux/media.h linux/videodev2.h" v4l2_timeval_to_ns -+ check_pkg_config libudev libudev libudev.h udev_new - fi - - check_headers sys/videoio.h -diff --git a/libavcodec/Makefile b/libavcodec/Makefile -index af60923827..ebd2dc54b9 100644 ---- a/libavcodec/Makefile -+++ b/libavcodec/Makefile -@@ -176,7 +176,7 @@ OBJS-$(CONFIG_VP3DSP) += vp3dsp.o - OBJS-$(CONFIG_VP56DSP) += vp56dsp.o - OBJS-$(CONFIG_VP8DSP) += vp8dsp.o - OBJS-$(CONFIG_V4L2_M2M) += v4l2_m2m.o v4l2_context.o v4l2_buffers.o v4l2_fmt.o --OBJS-$(CONFIG_V4L2_REQUEST) += v4l2_request.o -+OBJS-$(CONFIG_V4L2_REQUEST) += v4l2_request.o v4l2_request_probe.o - OBJS-$(CONFIG_WMA_FREQS) += wma_freqs.o - OBJS-$(CONFIG_WMV2DSP) += wmv2dsp.o + check_pkg_config libudev libudev libudev.h udev_new + v4l2_request_extralibs="$libudev_extralibs" +diff --git a/libavcodec/hwconfig.h b/libavcodec/hwconfig.h +index ee29ca631df0..159064a1f14c 100644 +--- a/libavcodec/hwconfig.h ++++ b/libavcodec/hwconfig.h +@@ -79,6 +79,8 @@ void ff_hwaccel_uninit(AVCodecContext *avctx); + HW_CONFIG_HWACCEL(0, 0, 1, D3D11VA_VLD, NONE, ff_ ## codec ## _d3d11va_hwaccel) + #define HWACCEL_D3D12VA(codec) \ + HW_CONFIG_HWACCEL(1, 1, 0, D3D12, D3D12VA, ff_ ## codec ## _d3d12va_hwaccel) ++#define HWACCEL_V4L2REQUEST(codec) \ ++ HW_CONFIG_HWACCEL(1, 0, 0, DRM_PRIME, V4L2REQUEST, ff_ ## codec ## _v4l2request_hwaccel) + #define HW_CONFIG_ENCODER(device, frames, ad_hoc, format, device_type_) \ + &(const AVCodecHWConfigInternal) { \ diff --git a/libavcodec/v4l2_request.c b/libavcodec/v4l2_request.c -index 436c8de4a4..6f44c5d826 100644 +index dfec0e8906a8..36eec8540295 100644 --- a/libavcodec/v4l2_request.c +++ b/libavcodec/v4l2_request.c -@@ -244,7 +244,11 @@ static AVBufferRef *v4l2_request_frame_alloc(void *opaque, size_t size) - return NULL; - } +@@ -19,6 +19,7 @@ + #include "config.h" -- // TODO: Set AVDRMFrameDescriptor of this AVFrame -+ // Set AVDRMFrameDescriptor of this AVFrame -+ if (ff_v4l2_request_set_drm_descriptor(desc, &ctx->format) < 0) { -+ av_buffer_unref(&ref); -+ return NULL; -+ } + #include ++#include + #include + #include + #include +@@ -29,6 +30,8 @@ + #include "internal.h" + #include "v4l2_request.h" - return ref; ++#define V4L2_PLANES_MAX 2 ++ + static const AVClass v4l2_request_context_class = { + .class_name = "V4L2RequestContext", + .item_name = av_default_item_name, +@@ -40,6 +43,537 @@ static inline V4L2RequestContext *v4l2_request_context(AVCodecContext *avctx) + return (V4L2RequestContext *)avctx->internal->hwaccel_priv_data; } -@@ -261,8 +265,7 @@ int ff_v4l2_request_frame_params(AVCodecContext *avctx, - AVHWFramesContext *hwfc = (AVHWFramesContext *)hw_frames_ctx->data; - - hwfc->format = AV_PIX_FMT_DRM_PRIME; -- // TODO: Set sw_format based on capture buffer format -- hwfc->sw_format = AV_PIX_FMT_NONE; -+ hwfc->sw_format = ff_v4l2_request_get_sw_format(&ctx->format); - if (V4L2_TYPE_IS_MULTIPLANAR(ctx->format.type)) { - hwfc->width = ctx->format.fmt.pix_mp.width; -@@ -413,6 +416,7 @@ int ff_v4l2_request_init(AVCodecContext *avctx, - { - V4L2RequestContext *ctx = v4l2_request_context(avctx); - AVV4L2RequestDeviceContext *hwctx = NULL; -+ int ret; - - // Set initial default values - ctx->av_class = &v4l2_request_context_class; -@@ -428,7 +432,13 @@ int ff_v4l2_request_init(AVCodecContext *avctx, - } - } - -- // TODO: Probe for a capable media and video device -+ // Probe for a capable media and video device for the V4L2 codec pixelformat -+ ret = ff_v4l2_request_probe(avctx, pixelformat, buffersize, control, count); -+ if (ret < 0) { -+ av_log(avctx, AV_LOG_INFO, "No V4L2 video device found for %s\n", -+ av_fourcc2str(pixelformat)); ++static inline uint32_t v4l2_request_frameindex(AVFrame *frame) ++{ ++ return (uint32_t)(uintptr_t)frame->data[1]; ++} ++ ++uint64_t ff_v4l2_request_get_capture_timestamp(AVFrame *frame) ++{ ++ /* ++ * The CAPTURE buffer index is used as a base for V4L2 frame reference. ++ * This works because frames are decoded into a CAPTURE buffer that is ++ * closely tied to an AVFrame. ++ */ ++ struct timeval timestamp = { ++ .tv_sec = 0, ++ .tv_usec = v4l2_request_frameindex(frame) + 1, ++ }; ++ return v4l2_timeval_to_ns(×tamp); ++} ++ ++int ff_v4l2_request_query_control(AVCodecContext *avctx, ++ struct v4l2_query_ext_ctrl *control) ++{ ++ V4L2RequestContext *ctx = v4l2_request_context(avctx); ++ ++ if (ioctl(ctx->fctxi->video_fd, VIDIOC_QUERY_EXT_CTRL, control) < 0) { ++ int ret = AVERROR(errno); ++ // Skip error logging when driver does not support control id (EINVAL) ++ if (errno != EINVAL) ++ av_log(ctx, AV_LOG_ERROR, "Failed to query control %u: %s (%d)\n", ++ control->id, strerror(errno), errno); + return ret; + } - - // Transfer (or return) ownership of media device file descriptor to hwdevice - if (hwctx) { -diff --git a/libavcodec/v4l2_request_internal.h b/libavcodec/v4l2_request_internal.h -index 554b663ab4..a5c3de22ef 100644 ---- a/libavcodec/v4l2_request_internal.h -+++ b/libavcodec/v4l2_request_internal.h -@@ -39,4 +39,13 @@ static inline V4L2RequestFrameDescriptor *v4l2_request_framedesc(AVFrame *frame) - return (V4L2RequestFrameDescriptor *)frame->data[0]; - } - -+enum AVPixelFormat ff_v4l2_request_get_sw_format(struct v4l2_format *format); + -+int ff_v4l2_request_set_drm_descriptor(V4L2RequestFrameDescriptor *framedesc, -+ struct v4l2_format *format); -+ -+int ff_v4l2_request_probe(AVCodecContext *avctx, uint32_t pixelformat, -+ uint32_t buffersize, struct v4l2_ext_control *control, -+ int count); ++ return 0; ++} + - #endif /* AVCODEC_V4L2_REQUEST_INTERNAL_H */ -diff --git a/libavcodec/v4l2_request_probe.c b/libavcodec/v4l2_request_probe.c -new file mode 100644 -index 0000000000..941042ec04 ---- /dev/null -+++ b/libavcodec/v4l2_request_probe.c -@@ -0,0 +1,614 @@ -+/* -+ * 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 -+ */ ++int ff_v4l2_request_query_control_default_value(AVCodecContext *avctx, ++ uint32_t id) ++{ ++ struct v4l2_query_ext_ctrl control = { ++ .id = id, ++ }; ++ int ret; + -+#include "config.h" ++ ret = ff_v4l2_request_query_control(avctx, &control); ++ if (ret < 0) ++ return ret; + -+#include -+#include -+#include -+#include ++ return control.default_value; ++} + -+#include -+#include ++static int v4l2_request_set_controls(V4L2RequestContext *ctx, int request_fd, ++ struct v4l2_ext_control *control, int count) ++{ ++ struct v4l2_ext_controls controls = { ++ .controls = control, ++ .count = count, ++ .request_fd = request_fd, ++ .which = (request_fd >= 0) ? V4L2_CTRL_WHICH_REQUEST_VAL : 0, ++ }; + -+#include "libavutil/hwcontext_v4l2request.h" -+#include "libavutil/mem.h" -+#include "v4l2_request_internal.h" ++ if (!control || !count) ++ return 0; + -+static const struct { -+ uint32_t pixelformat; -+ enum AVPixelFormat sw_format; -+ uint32_t drm_format; -+ uint64_t format_modifier; -+} v4l2_request_capture_pixelformats[] = { -+ { V4L2_PIX_FMT_NV12, AV_PIX_FMT_NV12, DRM_FORMAT_NV12, DRM_FORMAT_MOD_LINEAR }, -+#if defined(V4L2_PIX_FMT_NV12_32L32) -+ { V4L2_PIX_FMT_NV12_32L32, AV_PIX_FMT_NONE, DRM_FORMAT_NV12, DRM_FORMAT_MOD_ALLWINNER_TILED }, -+#endif -+#if defined(V4L2_PIX_FMT_NV15) && defined(DRM_FORMAT_NV15) -+ { V4L2_PIX_FMT_NV15, AV_PIX_FMT_NONE, DRM_FORMAT_NV15, DRM_FORMAT_MOD_LINEAR }, -+#endif -+ { V4L2_PIX_FMT_NV16, AV_PIX_FMT_NV16, DRM_FORMAT_NV16, DRM_FORMAT_MOD_LINEAR }, -+#if defined(V4L2_PIX_FMT_NV20) && defined(DRM_FORMAT_NV20) -+ { V4L2_PIX_FMT_NV20, AV_PIX_FMT_NONE, DRM_FORMAT_NV20, DRM_FORMAT_MOD_LINEAR }, -+#endif -+#if defined(V4L2_PIX_FMT_P010) && defined(DRM_FORMAT_P010) -+ { V4L2_PIX_FMT_P010, AV_PIX_FMT_P010, DRM_FORMAT_P010, DRM_FORMAT_MOD_LINEAR }, -+#endif -+#if defined(V4L2_PIX_FMT_NV12_COL128) && defined(V4L2_PIX_FMT_NV12_10_COL128) -+ { -+ .pixelformat = V4L2_PIX_FMT_NV12_COL128, -+ .sw_format = AV_PIX_FMT_NONE, -+ .drm_format = DRM_FORMAT_NV12, -+ .format_modifier = DRM_FORMAT_MOD_BROADCOM_SAND128, -+ }, -+#if defined(DRM_FORMAT_P030) -+ { -+ .pixelformat = V4L2_PIX_FMT_NV12_10_COL128, -+ .sw_format = AV_PIX_FMT_NONE, -+ .drm_format = DRM_FORMAT_P030, -+ .format_modifier = DRM_FORMAT_MOD_BROADCOM_SAND128, -+ }, -+#endif -+#endif -+#if defined(V4L2_PIX_FMT_YUV420_10_AFBC_16X16_SPLIT) -+ { -+ .pixelformat = V4L2_PIX_FMT_YUV420_10_AFBC_16X16_SPLIT, -+ .sw_format = AV_PIX_FMT_NONE, -+ .drm_format = DRM_FORMAT_YUV420_10BIT, -+ .format_modifier = DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | -+ AFBC_FORMAT_MOD_SPARSE | -+ AFBC_FORMAT_MOD_SPLIT), -+ }, -+#endif -+#if defined(V4L2_PIX_FMT_YUV420_8_AFBC_16X16_SPLIT) -+ { -+ .pixelformat = V4L2_PIX_FMT_YUV420_8_AFBC_16X16_SPLIT, -+ .sw_format = AV_PIX_FMT_NONE, -+ .drm_format = DRM_FORMAT_YUV420_8BIT, -+ .format_modifier = DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | -+ AFBC_FORMAT_MOD_SPARSE | -+ AFBC_FORMAT_MOD_SPLIT), -+ }, -+#endif -+}; ++ if (ioctl(ctx->fctxi->video_fd, VIDIOC_S_EXT_CTRLS, &controls) < 0) ++ return AVERROR(errno); ++ ++ return 0; ++} + -+enum AVPixelFormat ff_v4l2_request_get_sw_format(struct v4l2_format *format) ++int ff_v4l2_request_set_controls(AVCodecContext *avctx, ++ struct v4l2_ext_control *control, int count) +{ -+ uint32_t pixelformat = V4L2_TYPE_IS_MULTIPLANAR(format->type) ? -+ format->fmt.pix_mp.pixelformat : -+ format->fmt.pix.pixelformat; ++ V4L2RequestContext *ctx = v4l2_request_context(avctx); ++ int ret; + -+ for (int i = 0; i < FF_ARRAY_ELEMS(v4l2_request_capture_pixelformats); i++) { -+ if (pixelformat == v4l2_request_capture_pixelformats[i].pixelformat) -+ return v4l2_request_capture_pixelformats[i].sw_format; -+ } ++ ret = v4l2_request_set_controls(ctx, -1, control, count); ++ if (ret < 0) ++ av_log(ctx, AV_LOG_ERROR, "Failed to set %d control(s): %s (%d)\n", ++ count, strerror(errno), errno); + -+ return AV_PIX_FMT_NONE; ++ return ret; +} + -+int ff_v4l2_request_set_drm_descriptor(V4L2RequestFrameDescriptor *framedesc, -+ struct v4l2_format *format) ++static int v4l2_request_queue_buffer(V4L2RequestContext *ctx, ++ struct v4l2_buffer *buffer) +{ -+ AVDRMFrameDescriptor *desc = &framedesc->base; -+ AVDRMLayerDescriptor *layer = &desc->layers[0]; -+ uint32_t pixelformat = V4L2_TYPE_IS_MULTIPLANAR(format->type) ? -+ format->fmt.pix_mp.pixelformat : -+ format->fmt.pix.pixelformat; ++ struct v4l2_plane planes[V4L2_PLANES_MAX] = {}; + -+ // Set drm format and format modifier -+ layer->format = 0; -+ for (int i = 0; i < FF_ARRAY_ELEMS(v4l2_request_capture_pixelformats); i++) { -+ if (pixelformat == v4l2_request_capture_pixelformats[i].pixelformat) { -+ layer->format = v4l2_request_capture_pixelformats[i].drm_format; -+ desc->objects[0].format_modifier = -+ v4l2_request_capture_pixelformats[i].format_modifier; -+ break; -+ } ++ if (V4L2_TYPE_IS_MULTIPLANAR(buffer->type)) { ++ planes[0].bytesused = buffer->bytesused; ++ buffer->bytesused = 0; ++ buffer->length = FF_ARRAY_ELEMS(planes); ++ buffer->m.planes = planes; + } + -+ if (!layer->format) -+ return AVERROR(ENOENT); -+ -+ desc->nb_objects = 1; -+ desc->objects[0].fd = framedesc->capture.fd; -+ desc->objects[0].size = framedesc->capture.size; -+ -+ desc->nb_layers = 1; -+ layer->nb_planes = 1; -+ -+ layer->planes[0].object_index = 0; -+ layer->planes[0].offset = 0; -+ layer->planes[0].pitch = V4L2_TYPE_IS_MULTIPLANAR(format->type) ? -+ format->fmt.pix_mp.plane_fmt[0].bytesperline : -+ format->fmt.pix.bytesperline; -+ -+ // AFBC formats only use 1 plane, remaining use 2 planes -+ if ((desc->objects[0].format_modifier >> 56) != DRM_FORMAT_MOD_VENDOR_ARM) { -+ layer->nb_planes = 2; -+ layer->planes[1].object_index = 0; -+ layer->planes[1].offset = layer->planes[0].pitch * -+ (V4L2_TYPE_IS_MULTIPLANAR(format->type) ? -+ format->fmt.pix_mp.height : -+ format->fmt.pix.height); -+ layer->planes[1].pitch = layer->planes[0].pitch; -+ } ++ // Queue the buffer ++ if (ioctl(ctx->fctxi->video_fd, VIDIOC_QBUF, buffer) < 0) ++ return AVERROR(errno); + -+#if defined(V4L2_PIX_FMT_NV12_COL128) && defined(V4L2_PIX_FMT_NV12_10_COL128) -+ // Raspberry Pi formats need special handling -+ if (pixelformat == V4L2_PIX_FMT_NV12_COL128 || -+ pixelformat == V4L2_PIX_FMT_NV12_10_COL128) { -+ desc->objects[0].format_modifier = -+ DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT(layer->planes[0].pitch); -+ layer->planes[1].offset = 128 * -+ (V4L2_TYPE_IS_MULTIPLANAR(format->type) ? -+ format->fmt.pix_mp.height : -+ format->fmt.pix.height); -+ layer->planes[0].pitch = (V4L2_TYPE_IS_MULTIPLANAR(format->type) ? -+ format->fmt.pix_mp.width : -+ format->fmt.pix.width); -+ if (pixelformat == V4L2_PIX_FMT_NV12_10_COL128) -+ layer->planes[0].pitch *= 2; -+ layer->planes[1].pitch = layer->planes[0].pitch; -+ } -+#endif ++ // Mark the buffer as queued ++ if (V4L2_TYPE_IS_OUTPUT(buffer->type)) ++ ctx->queued_output |= 1 << buffer->index; ++ else ++ ctx->queued_capture |= 1 << buffer->index; + + return 0; +} + -+static int v4l2_request_set_format(AVCodecContext *avctx, -+ enum v4l2_buf_type type, -+ uint32_t pixelformat, -+ uint32_t buffersize) ++static int v4l2_request_queue_capture_buffer(V4L2RequestContext *ctx, ++ uint32_t index) +{ -+ V4L2RequestContext *ctx = v4l2_request_context(avctx); -+ struct v4l2_format format = { -+ .type = type, ++ struct v4l2_buffer buffer = { ++ .index = index, ++ .type = ctx->fctxi->capture.format.type, ++ .memory = V4L2_MEMORY_MMAP, + }; -+ -+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) { -+ format.fmt.pix_mp.width = avctx->coded_width; -+ format.fmt.pix_mp.height = avctx->coded_height; -+ format.fmt.pix_mp.pixelformat = pixelformat; -+ format.fmt.pix_mp.plane_fmt[0].sizeimage = buffersize; -+ format.fmt.pix_mp.num_planes = 1; -+ } else { -+ format.fmt.pix.width = avctx->coded_width; -+ format.fmt.pix.height = avctx->coded_height; -+ format.fmt.pix.pixelformat = pixelformat; -+ format.fmt.pix.sizeimage = buffersize; -+ } -+ -+ if (ioctl(ctx->video_fd, VIDIOC_S_FMT, &format) < 0) -+ return AVERROR(errno); -+ -+ return 0; ++ return v4l2_request_queue_buffer(ctx, &buffer); +} + -+static int v4l2_request_select_capture_format(AVCodecContext *avctx) ++static int v4l2_request_queue_output_buffer(V4L2RequestContext *ctx, ++ V4L2RequestOutputBuffer *output, ++ uint32_t flags) +{ -+ V4L2RequestContext *ctx = v4l2_request_context(avctx); -+ enum v4l2_buf_type type = ctx->format.type; -+ struct v4l2_format format = { -+ .type = type, ++ struct v4l2_buffer buffer = { ++ .index = output->index, ++ .type = ctx->fctxi->output.format.type, ++ .memory = V4L2_MEMORY_MMAP, ++ .timestamp = output->timestamp, ++ .bytesused = output->bytesused, ++ .request_fd = output->request_fd, ++ .flags = V4L2_BUF_FLAG_REQUEST_FD | flags, + }; -+ struct v4l2_fmtdesc fmtdesc = { -+ .index = 0, ++ return v4l2_request_queue_buffer(ctx, &buffer); ++} ++ ++static int v4l2_request_dequeue_buffer(V4L2RequestContext *ctx, ++ enum v4l2_buf_type type) ++{ ++ struct v4l2_plane planes[V4L2_PLANES_MAX] = {}; ++ struct v4l2_buffer buffer = { + .type = type, ++ .memory = V4L2_MEMORY_MMAP, + }; -+ uint32_t pixelformat; -+ -+ // Get the driver preferred (or default) format -+ if (ioctl(ctx->video_fd, VIDIOC_G_FMT, &format) < 0) -+ return AVERROR(errno); -+ -+ pixelformat = V4L2_TYPE_IS_MULTIPLANAR(type) ? -+ format.fmt.pix_mp.pixelformat : -+ format.fmt.pix.pixelformat; + -+ // Use the driver preferred format when it is supported -+ for (int i = 0; i < FF_ARRAY_ELEMS(v4l2_request_capture_pixelformats); i++) { -+ if (pixelformat == v4l2_request_capture_pixelformats[i].pixelformat) -+ return v4l2_request_set_format(avctx, type, pixelformat, 0); ++ if (V4L2_TYPE_IS_MULTIPLANAR(buffer.type)) { ++ buffer.length = FF_ARRAY_ELEMS(planes); ++ buffer.m.planes = planes; + } + -+ // Otherwise, use first format that is supported -+ while (ioctl(ctx->video_fd, VIDIOC_ENUM_FMT, &fmtdesc) >= 0) { -+ for (int i = 0; i < FF_ARRAY_ELEMS(v4l2_request_capture_pixelformats); i++) { -+ if (fmtdesc.pixelformat == v4l2_request_capture_pixelformats[i].pixelformat) -+ return v4l2_request_set_format(avctx, type, fmtdesc.pixelformat, 0); -+ } ++ // Dequeue next completed buffer ++ if (ioctl(ctx->fctxi->video_fd, VIDIOC_DQBUF, &buffer) < 0) ++ return AVERROR(errno); + -+ fmtdesc.index++; -+ } ++ // Mark the buffer as dequeued ++ if (V4L2_TYPE_IS_OUTPUT(buffer.type)) ++ ctx->queued_output &= ~(1 << buffer.index); ++ else ++ ctx->queued_capture &= ~(1 << buffer.index); + -+ return AVERROR(errno); ++ return 0; +} + -+static int v4l2_request_try_framesize(AVCodecContext *avctx, -+ uint32_t pixelformat) ++static inline int v4l2_request_dequeue_completed_buffers(V4L2RequestContext *ctx, ++ enum v4l2_buf_type type) +{ -+ V4L2RequestContext *ctx = v4l2_request_context(avctx); -+ struct v4l2_frmsizeenum frmsize = { -+ .index = 0, -+ .pixel_format = pixelformat, -+ }; -+ -+ // Enumerate and check if frame size is supported -+ while (ioctl(ctx->video_fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) >= 0) { -+ if (frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE && -+ frmsize.discrete.width == avctx->coded_width && -+ frmsize.discrete.height == avctx->coded_height) { -+ return 0; -+ } else if ((frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE || -+ frmsize.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) && -+ avctx->coded_width <= frmsize.stepwise.max_width && -+ avctx->coded_height <= frmsize.stepwise.max_height && -+ avctx->coded_width % frmsize.stepwise.step_width == 0 && -+ avctx->coded_height % frmsize.stepwise.step_height == 0) { -+ return 0; -+ } ++ int ret; + -+ frmsize.index++; -+ } ++ do { ++ ret = v4l2_request_dequeue_buffer(ctx, type); ++ } while (!ret); + -+ return AVERROR(errno); ++ return ret; +} + -+static int v4l2_request_try_format(AVCodecContext *avctx, -+ enum v4l2_buf_type type, -+ uint32_t pixelformat) ++static int v4l2_request_wait_on_capture(V4L2RequestContext *ctx, uint32_t index) +{ -+ V4L2RequestContext *ctx = v4l2_request_context(avctx); -+ struct v4l2_fmtdesc fmtdesc = { -+ .index = 0, -+ .type = type, ++ enum v4l2_buf_type type = ctx->fctxi->capture.format.type; ++ struct pollfd pollfd = { ++ .fd = ctx->fctxi->video_fd, ++ .events = POLLIN, + }; + -+ // Enumerate and check if format is supported -+ while (ioctl(ctx->video_fd, VIDIOC_ENUM_FMT, &fmtdesc) >= 0) { -+ if (fmtdesc.pixelformat == pixelformat) -+ return 0; ++ ff_mutex_lock(&ctx->mutex); + -+ fmtdesc.index++; ++ // Dequeue all completed CAPTURE buffers ++ if (ctx->queued_capture) ++ v4l2_request_dequeue_completed_buffers(ctx, type); ++ ++ // Wait on the specific CAPTURE buffer ++ while (ctx->queued_capture & (1 << index)) { ++ int ret = poll(&pollfd, 1, 2000); ++ if (ret <= 0) ++ goto fail; ++ ++ ret = v4l2_request_dequeue_buffer(ctx, type); ++ if (ret < 0 && ret != AVERROR(EAGAIN)) ++ goto fail; + } + -+ return AVERROR(errno); ++ ff_mutex_unlock(&ctx->mutex); ++ return 0; ++ ++fail: ++ ff_mutex_unlock(&ctx->mutex); ++ av_log(ctx, AV_LOG_ERROR, "Failed waiting on CAPTURE buffer %d\n", index); ++ return AVERROR(EINVAL); +} + -+static int v4l2_request_probe_video_device(const char *path, -+ AVCodecContext *avctx, -+ uint32_t pixelformat, -+ uint32_t buffersize, -+ struct v4l2_ext_control *control, -+ int count) ++static V4L2RequestOutputBuffer *v4l2_request_next_output(V4L2RequestContext *ctx) +{ -+ V4L2RequestContext *ctx = v4l2_request_context(avctx); -+ struct v4l2_capability capability; -+ struct v4l2_create_buffers buffers = { -+ .count = 0, -+ .memory = V4L2_MEMORY_MMAP, ++ enum v4l2_buf_type type = ctx->fctxi->output.format.type; ++ V4L2RequestOutputBuffer *output; ++ struct pollfd pollfd = { ++ .fd = ctx->fctxi->video_fd, ++ .events = POLLOUT, + }; -+ unsigned int capabilities; -+ int ret; ++ uint8_t index; + -+ /* -+ * Open video device in non-blocking mode to support decoding using -+ * multiple queued requests, required for e.g. multi stage decoding. -+ */ -+ ctx->video_fd = open(path, O_RDWR | O_NONBLOCK); -+ if (ctx->video_fd < 0) { -+ av_log(avctx, AV_LOG_ERROR, "Failed to open video device %s: %s (%d)\n", -+ path, strerror(errno), errno); -+ return AVERROR(errno); -+ } ++ ff_mutex_lock(&ctx->mutex); + -+ // Query capabilities of the video device -+ if (ioctl(ctx->video_fd, VIDIOC_QUERYCAP, &capability) < 0) { -+ av_log(avctx, AV_LOG_ERROR, "Failed to query capabilities of %s: %s (%d)\n", -+ path, strerror(errno), errno); -+ ret = AVERROR(errno); -+ goto fail; -+ } ++ // Use next OUTPUT buffer in the circular queue ++ index = ctx->next_output; ++ output = &ctx->output[index]; ++ ctx->next_output = (index + 1) % FF_ARRAY_ELEMS(ctx->output); + -+ // Use device capabilities when needed -+ if (capability.capabilities & V4L2_CAP_DEVICE_CAPS) -+ capabilities = capability.device_caps; -+ else -+ capabilities = capability.capabilities; ++ // Dequeue all completed OUTPUT buffers ++ if (ctx->queued_output) ++ v4l2_request_dequeue_completed_buffers(ctx, type); + -+ // Ensure streaming is supported on the video device -+ if ((capabilities & V4L2_CAP_STREAMING) != V4L2_CAP_STREAMING) { -+ av_log(ctx, AV_LOG_VERBOSE, "Device %s is missing streaming capability\n", path); -+ ret = AVERROR(EINVAL); -+ goto fail; -+ } ++ // Wait on the specific OUTPUT buffer ++ while (ctx->queued_output & (1 << output->index)) { ++ int ret = poll(&pollfd, 1, 2000); ++ if (ret <= 0) ++ goto fail; + -+ // Ensure multi- or single-planar API can be used -+ if ((capabilities & V4L2_CAP_VIDEO_M2M_MPLANE) == V4L2_CAP_VIDEO_M2M_MPLANE) { -+ ctx->output_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; -+ ctx->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; -+ } else if ((capabilities & V4L2_CAP_VIDEO_M2M) == V4L2_CAP_VIDEO_M2M) { -+ ctx->output_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; -+ ctx->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; -+ } else { -+ av_log(ctx, AV_LOG_VERBOSE, "Device %s is missing mem2mem capability\n", path); -+ ret = AVERROR(EINVAL); -+ goto fail; ++ ret = v4l2_request_dequeue_buffer(ctx, type); ++ if (ret < 0 && ret != AVERROR(EAGAIN)) ++ goto fail; + } + -+ // Query output buffer capabilities -+ buffers.format.type = ctx->output_type; -+ if (ioctl(ctx->video_fd, VIDIOC_CREATE_BUFS, &buffers) < 0) { -+ av_log(avctx, AV_LOG_ERROR, -+ "Failed to query output buffer capabilities of %s: %s (%d)\n", -+ path, strerror(errno), errno); -+ ret = AVERROR(errno); -+ goto fail; -+ } ++ ff_mutex_unlock(&ctx->mutex); + -+ // Ensure requests can be used -+ if ((buffers.capabilities & V4L2_BUF_CAP_SUPPORTS_REQUESTS) != -+ V4L2_BUF_CAP_SUPPORTS_REQUESTS) { -+ av_log(ctx, AV_LOG_VERBOSE, "Device %s is missing support for requests\n", path); -+ ret = AVERROR(EINVAL); -+ goto fail; -+ } ++ // Reset bytesused state ++ output->bytesused = 0; + -+ // Ensure the codec pixelformat can be used -+ ret = v4l2_request_try_format(avctx, ctx->output_type, pixelformat); -+ if (ret < 0) { -+ av_log(ctx, AV_LOG_VERBOSE, "Device %s is missing support for pixelformat %s\n", -+ path, av_fourcc2str(pixelformat)); -+ goto fail; -+ } ++ return output; + -+ // Ensure frame size is supported, when driver support ENUM_FRAMESIZES -+ ret = v4l2_request_try_framesize(avctx, pixelformat); -+ if (ret < 0 && ret != AVERROR(ENOTTY)) { -+ av_log(ctx, AV_LOG_VERBOSE, -+ "Device %s is missing support for frame size %dx%d of pixelformat %s\n", -+ path, avctx->coded_width, avctx->coded_height, av_fourcc2str(pixelformat)); -+ goto fail; -+ } ++fail: ++ ff_mutex_unlock(&ctx->mutex); ++ av_log(ctx, AV_LOG_ERROR, "Failed waiting on OUTPUT buffer %d\n", ++ output->index); ++ return NULL; ++} + -+ // Set the codec pixelformat and output buffersize to be used -+ ret = v4l2_request_set_format(avctx, ctx->output_type, pixelformat, buffersize); -+ if (ret < 0) { -+ av_log(avctx, AV_LOG_ERROR, -+ "Failed to set output pixelformat %s of %s: %s (%d)\n", -+ av_fourcc2str(pixelformat), path, strerror(errno), errno); -+ goto fail; -+ } ++static int v4l2_request_wait_on_request(V4L2RequestContext *ctx, ++ V4L2RequestOutputBuffer *output) ++{ ++ struct pollfd pollfd = { ++ .fd = output->request_fd, ++ .events = POLLPRI, ++ }; + -+ /* -+ * Set any codec specific controls that can help assist the driver -+ * make a decision on what capture buffer format can be used. -+ */ -+ ret = ff_v4l2_request_set_controls(avctx, control, count); -+ if (ret < 0) -+ goto fail; ++ // Wait on the specific request to complete ++ while (ctx->queued_request & (1 << output->index)) { ++ int ret = poll(&pollfd, 1, 2000); ++ if (ret <= 0) ++ break; + -+ // Select a capture buffer format known to the hwaccel -+ ret = v4l2_request_select_capture_format(avctx); -+ if (ret < 0) { -+ av_log(avctx, AV_LOG_VERBOSE, -+ "Failed to select a capture format for %s of %s: %s (%d)\n", -+ av_fourcc2str(pixelformat), path, strerror(errno), errno); -+ goto fail; ++ // Mark request as dequeued ++ if (pollfd.revents & (POLLPRI | POLLERR)) { ++ ctx->queued_request &= ~(1 << output->index); ++ break; ++ } + } + -+ // Check codec specific controls, e.g. profile and level -+ if (ctx->post_probe) { -+ ret = ctx->post_probe(avctx); -+ if (ret < 0) -+ goto fail; ++ // Reinit the request object ++ if (ioctl(output->request_fd, MEDIA_REQUEST_IOC_REINIT) < 0) { ++ int ret = AVERROR(errno); ++ av_log(ctx, AV_LOG_ERROR, "Failed to reinit request object %d: %s (%d)\n", ++ output->request_fd, strerror(errno), errno); ++ return ret; + } + -+ // All tests passed, video device should be capable ++ // Ensure request is marked as dequeued ++ ctx->queued_request &= ~(1 << output->index); ++ + return 0; ++} + -+fail: -+ if (ctx->video_fd >= 0) { -+ close(ctx->video_fd); -+ ctx->video_fd = -1; ++int ff_v4l2_request_append_output(AVCodecContext *avctx, ++ V4L2RequestPictureContext *pic, ++ const uint8_t *data, uint32_t size) ++{ ++ V4L2RequestContext *ctx = v4l2_request_context(avctx); ++ ++ // Append data to OUTPUT buffer and ensure there is enough space for padding ++ if (pic->output->bytesused + size + AV_INPUT_BUFFER_PADDING_SIZE <= pic->output->size) { ++ memcpy(pic->output->addr + pic->output->bytesused, data, size); ++ pic->output->bytesused += size; ++ return 0; ++ } else { ++ av_log(ctx, AV_LOG_ERROR, ++ "Failed to append %u bytes data to OUTPUT buffer %d (%u of %u used)\n", ++ size, pic->output->index, pic->output->bytesused, pic->output->size); ++ return AVERROR(ENOMEM); + } -+ return ret; +} + -+static int v4l2_request_probe_video_devices(struct udev *udev, -+ AVCodecContext *avctx, -+ uint32_t pixelformat, -+ uint32_t buffersize, -+ struct v4l2_ext_control *control, -+ int count) ++static int v4l2_request_queue_decode(AVCodecContext *avctx, ++ V4L2RequestPictureContext *pic, ++ struct v4l2_ext_control *control, int count, ++ bool first_slice, bool last_slice) +{ + V4L2RequestContext *ctx = v4l2_request_context(avctx); -+ struct media_device_info device_info; -+ struct media_v2_topology topology = {0}; -+ struct media_v2_interface *interfaces; -+ struct udev_device *device; -+ const char *path; -+ dev_t devnum; ++ uint32_t flags; + int ret; + -+ if (ioctl(ctx->media_fd, MEDIA_IOC_DEVICE_INFO, &device_info) < 0) -+ return AVERROR(errno); -+ -+ if (ioctl(ctx->media_fd, MEDIA_IOC_G_TOPOLOGY, &topology) < 0) { -+ av_log(avctx, AV_LOG_ERROR, "Failed to get media topology: %s (%d)\n", -+ strerror(errno), errno); -+ return AVERROR(errno); ++ if (first_slice) { ++ /* ++ * Wait on dequeue of the target CAPTURE buffer. Otherwise V4L2 decoder ++ * may use a different CAPTURE buffer than hwaccel expects. ++ * ++ * Normally decoding has already completed when a CAPTURE buffer is ++ * reused so this is more or less a no-op, however in some situations ++ * FFmpeg may reuse an AVFrame early, i.e. when no output frame was ++ * produced prior time, and a synchronization is necessary. ++ */ ++ ret = v4l2_request_wait_on_capture(ctx, pic->capture_index); ++ if (ret < 0) ++ return ret; + } + -+ if (!topology.num_interfaces) -+ return AVERROR(ENOENT); ++ ff_mutex_lock(&ctx->mutex); + -+ interfaces = av_calloc(topology.num_interfaces, sizeof(struct media_v2_interface)); -+ if (!interfaces) -+ return AVERROR(ENOMEM); ++ /* ++ * The OUTPUT buffer tied to prior use of current request object can ++ * independently be dequeued before the full decode request has been ++ * completed. This may happen when a decoder use multi stage decoding, ++ * e.g. rpi-hevc-dec. In such case we can start reusing the OUTPUT buffer, ++ * however we must wait on the prior request to fully complete before we ++ * can reuse the request object, and a synchronization is necessary. ++ */ ++ ret = v4l2_request_wait_on_request(ctx, pic->output); ++ if (ret < 0) ++ goto fail; + -+ topology.ptr_interfaces = (__u64)(uintptr_t)interfaces; -+ if (ioctl(ctx->media_fd, MEDIA_IOC_G_TOPOLOGY, &topology) < 0) { -+ av_log(avctx, AV_LOG_ERROR, "Failed to get media topology: %s (%d)\n", -+ strerror(errno), errno); -+ ret = AVERROR(errno); ++ /* ++ * Dequeue any completed OUTPUT buffers, this is strictly not necessary, ++ * however if a synchronization was necessary for the CAPTURE and/or request ++ * there is more than likely one or more OUTPUT buffers that can be dequeued. ++ */ ++ if (ctx->queued_output) ++ v4l2_request_dequeue_completed_buffers(ctx, ctx->fctxi->output.format.type); ++ ++ // Set codec controls for current request ++ ret = v4l2_request_set_controls(ctx, pic->output->request_fd, control, count); ++ if (ret < 0) { ++ av_log(ctx, AV_LOG_ERROR, "Failed to set %d control(s) for request %d: %s (%d)\n", ++ count, pic->output->request_fd, strerror(errno), errno); + goto fail; + } + -+ ret = AVERROR(ENOENT); -+ for (int i = 0; i < topology.num_interfaces; i++) { -+ if (interfaces[i].intf_type != MEDIA_INTF_T_V4L_VIDEO) -+ continue; ++ // Ensure there is zero padding at the end of bitstream data ++ memset(pic->output->addr + pic->output->bytesused, 0, AV_INPUT_BUFFER_PADDING_SIZE); + -+ devnum = makedev(interfaces[i].devnode.major, interfaces[i].devnode.minor); -+ device = udev_device_new_from_devnum(udev, 'c', devnum); -+ if (!device) -+ continue; ++ /* ++ * Use CAPTURE buffer index as base for V4L2 frame reference. ++ * This works because a CAPTURE buffer is closely tied to a AVFrame ++ * and FFmpeg handle all frame reference tracking for us. ++ */ ++ pic->output->timestamp = (struct timeval) { ++ .tv_sec = 0, ++ .tv_usec = pic->capture_index + 1, ++ }; + -+ path = udev_device_get_devnode(device); -+ if (path) -+ ret = v4l2_request_probe_video_device(path, avctx, pixelformat, -+ buffersize, control, count); -+ udev_device_unref(device); ++ /* ++ * Queue the OUTPUT buffer of current request. The CAPTURE buffer may be ++ * hold by the V4L2 decoder unless this is the last slice of a frame. ++ */ ++ flags = last_slice ? 0 : V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF; ++ ret = v4l2_request_queue_output_buffer(ctx, pic->output, flags); ++ if (ret < 0) { ++ av_log(ctx, AV_LOG_ERROR, "Failed to queue OUTPUT buffer %d for request %d: %s (%d)\n", ++ pic->output->index, pic->output->request_fd, strerror(errno), errno); ++ goto fail; ++ } + -+ // Stop when we have found a capable video device -+ if (!ret) { -+ av_log(avctx, AV_LOG_INFO, -+ "Using V4L2 media driver %s (%u.%u.%u) for %s\n", -+ device_info.driver, -+ device_info.driver_version >> 16, -+ (device_info.driver_version >> 8) & 0xff, -+ device_info.driver_version & 0xff, -+ av_fourcc2str(pixelformat)); -+ break; ++ if (first_slice) { ++ /* ++ * Queue the target CAPTURE buffer, hwaccel expect and depend on that ++ * this specific CAPTURE buffer will be used as decode target for ++ * current request, otherwise frames may be output in wrong order or ++ * wrong CAPTURE buffer could get used as a reference frame. ++ */ ++ ret = v4l2_request_queue_capture_buffer(ctx, pic->capture_index); ++ if (ret < 0) { ++ av_log(ctx, AV_LOG_ERROR, "Failed to queue CAPTURE buffer %d for request %d: %s (%d)\n", ++ pic->capture_index, pic->output->request_fd, strerror(errno), errno); ++ goto fail; + } + } + ++ // Queue current request ++ ret = ioctl(pic->output->request_fd, MEDIA_REQUEST_IOC_QUEUE); ++ if (ret < 0) { ++ ret = AVERROR(errno); ++ av_log(ctx, AV_LOG_ERROR, "Failed to queue request object %d: %s (%d)\n", ++ pic->output->request_fd, strerror(errno), errno); ++ goto fail; ++ } ++ ++ // Mark current request as queued ++ ctx->queued_request |= 1 << pic->output->index; ++ ++ ret = 0; +fail: -+ av_free(interfaces); ++ ff_mutex_unlock(&ctx->mutex); + return ret; +} + -+static int v4l2_request_probe_media_device(struct udev_device *device, -+ AVCodecContext *avctx, -+ uint32_t pixelformat, -+ uint32_t buffersize, -+ struct v4l2_ext_control *control, -+ int count) ++int ff_v4l2_request_decode_slice(AVCodecContext *avctx, ++ V4L2RequestPictureContext *pic, ++ struct v4l2_ext_control *control, int count, ++ bool first_slice, bool last_slice) +{ + V4L2RequestContext *ctx = v4l2_request_context(avctx); -+ const char *path; -+ int ret; + -+ path = udev_device_get_devnode(device); -+ if (!path) -+ return AVERROR(ENODEV); ++ /* ++ * Fallback to queue each slice as a full frame when holding CAPTURE ++ * buffers is not supported by the driver. ++ */ ++ if ((ctx->fctxi->output.capabilities & V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF) != ++ V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF) ++ return v4l2_request_queue_decode(avctx, pic, control, count, true, true); + -+ // Open enumerated media device -+ ctx->media_fd = open(path, O_RDWR); -+ if (ctx->media_fd < 0) { -+ av_log(avctx, AV_LOG_ERROR, "Failed to open media device %s: %s (%d)\n", -+ path, strerror(errno), errno); -+ return AVERROR(errno); -+ } ++ return v4l2_request_queue_decode(avctx, pic, control, count, ++ first_slice, last_slice); ++} + -+ // Probe video devices of current media device -+ ret = v4l2_request_probe_video_devices(udev_device_get_udev(device), -+ avctx, pixelformat, -+ buffersize, control, count); ++int ff_v4l2_request_decode_frame(AVCodecContext *avctx, ++ V4L2RequestPictureContext *pic, ++ struct v4l2_ext_control *control, int count) ++{ ++ return v4l2_request_queue_decode(avctx, pic, control, count, true, true); ++} + -+ // Cleanup when no capable video device was found -+ if (ret < 0) { -+ close(ctx->media_fd); -+ ctx->media_fd = -1; -+ } ++static int v4l2_request_post_process(void *logctx, AVFrame *frame) ++{ ++ uint32_t index = v4l2_request_frameindex(frame); ++ FrameDecodeData *fdd = frame->private_ref; ++ V4L2RequestContext *ctx = fdd->hwaccel_priv; + -+ return ret; ++ // Wait on CAPTURE buffer before returning the frame to application ++ return v4l2_request_wait_on_capture(ctx, index); +} + -+static int v4l2_request_probe_media_devices(struct udev *udev, -+ AVCodecContext *avctx, -+ uint32_t pixelformat, -+ uint32_t buffersize, -+ struct v4l2_ext_control *control, -+ int count) ++int ff_v4l2_request_reset_picture(AVCodecContext *avctx, V4L2RequestPictureContext *pic) +{ -+ struct udev_enumerate *enumerate; -+ struct udev_list_entry *devices; -+ struct udev_list_entry *entry; -+ struct udev_device *device; -+ int ret; ++ V4L2RequestContext *ctx = v4l2_request_context(avctx); + -+ enumerate = udev_enumerate_new(udev); -+ if (!enumerate) -+ return AVERROR(ENOMEM); ++ // Get and wait on next OUTPUT buffer from circular queue ++ pic->output = v4l2_request_next_output(ctx); ++ if (!pic->output) ++ return AVERROR(EINVAL); + -+ udev_enumerate_add_match_subsystem(enumerate, "media"); -+ udev_enumerate_scan_devices(enumerate); -+ devices = udev_enumerate_get_list_entry(enumerate); ++ return 0; ++} + -+ ret = AVERROR(ENOENT); -+ udev_list_entry_foreach(entry, devices) { -+ const char *path = udev_list_entry_get_name(entry); -+ if (!path) -+ continue; ++int ff_v4l2_request_start_frame(AVCodecContext *avctx, ++ V4L2RequestPictureContext *pic, ++ AVFrame *frame) ++{ ++ V4L2RequestContext *ctx = v4l2_request_context(avctx); ++ uint32_t index = v4l2_request_frameindex(frame); ++ FrameDecodeData *fdd = frame->private_ref; ++ int ret; + -+ device = udev_device_new_from_syspath(udev, path); -+ if (!device) -+ continue; ++ // Get next OUTPUT buffer from circular queue ++ ret = ff_v4l2_request_reset_picture(avctx, pic); ++ if (ret) ++ return ret; + -+ // Probe media device for a capable video device -+ ret = v4l2_request_probe_media_device(device, avctx, pixelformat, -+ buffersize, control, count); -+ udev_device_unref(device); ++ // Ensure CAPTURE buffer is dequeued before reuse ++ ret = v4l2_request_wait_on_capture(ctx, index); ++ if (ret) ++ return ret; + -+ // Stop when we have found a capable media and video device -+ if (!ret) -+ break; -+ } ++ // Wait on CAPTURE buffer in post_process() before returning to application ++ fdd->hwaccel_priv = ctx; ++ fdd->post_process = v4l2_request_post_process; + -+ udev_enumerate_unref(enumerate); -+ return ret; ++ // CAPTURE buffer used for current frame ++ pic->capture_index = index; ++ ++ return 0; +} + -+int ff_v4l2_request_probe(AVCodecContext *avctx, -+ uint32_t pixelformat, uint32_t buffersize, -+ struct v4l2_ext_control *control, int count) ++void ff_v4l2_request_flush(AVCodecContext *avctx) +{ + V4L2RequestContext *ctx = v4l2_request_context(avctx); -+ struct udev *udev; -+ int ret; ++ enum v4l2_buf_type type = ctx->fctxi->output.format.type; ++ struct pollfd pollfd = { ++ .fd = ctx->fctxi->video_fd, ++ .events = POLLOUT, ++ }; + -+ udev = udev_new(); -+ if (!udev) -+ return AVERROR(ENOMEM); ++ ff_mutex_lock(&ctx->mutex); + -+ if (ctx->media_fd >= 0) { -+ // Probe video devices of current media device -+ ret = v4l2_request_probe_video_devices(udev, avctx, pixelformat, -+ buffersize, control, count); -+ } else { -+ // Probe all media devices (auto-detect) -+ ret = v4l2_request_probe_media_devices(udev, avctx, pixelformat, -+ buffersize, control, count); ++ // Dequeue all completed OUTPUT buffers ++ if (ctx->queued_output) ++ v4l2_request_dequeue_completed_buffers(ctx, type); ++ ++ // Wait on any remaining OUTPUT buffer ++ while (ctx->queued_output) { ++ int ret = poll(&pollfd, 1, 2000); ++ if (ret <= 0) ++ break; ++ ++ ret = v4l2_request_dequeue_buffer(ctx, type); ++ if (ret < 0 && ret != AVERROR(EAGAIN)) ++ break; + } + -+ udev_unref(udev); -+ return ret; ++ // Dequeue all completed CAPTURE buffers ++ if (ctx->queued_capture) ++ v4l2_request_dequeue_completed_buffers(ctx, ctx->fctxi->capture.format.type); ++ ++ ff_mutex_unlock(&ctx->mutex); +} - -From 917168b391fa76cff0b7b74050bd90fa60e07b8c Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Tue, 6 Aug 2024 09:06:03 +0000 -Subject: [PATCH 04/11] avcodec/v4l2request: Add common decode support for - hwaccels - -Add common support for decoding using the V4L2 Request API. - -Basic flow for decoding follow the kernel Memory-to-memory Stateless -Video Decoder Interface > Decoding [1]. - -A codec hwaccel typically handle decoding as follow: - -In start_frame next OUTPUT buffer and its related request object is -picked from a circular queue and any codec specific CONTROLs is prepared. - -In decode_slice the slice bitstream data is appended to the OUTPUT -buffer. - -In end_frame a CAPTURE buffer tied to the AVFrame is queued, it will be -used as the decoding target by the driver / hw decoder. The prepared -codec specific CONTROLs get queued as part of the request object. -Finally the request object is submitted for decoding. - -For slice based hw decoders only the request for the final slice of the -frame is submitted in end_frame, remaining is submitted in decode_slice. - -[1] https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-stateless-decoder.html#decoding - -Co-developed-by: Jernej Skrabec -Signed-off-by: Jernej Skrabec -Co-developed-by: Alex Bee -Signed-off-by: Alex Bee -Signed-off-by: Jonas Karlman ---- - configure | 3 +- - libavcodec/Makefile | 2 +- - libavcodec/hwconfig.h | 2 + - libavcodec/v4l2_request.c | 3 +- - libavcodec/v4l2_request.h | 23 ++ - libavcodec/v4l2_request_decode.c | 459 +++++++++++++++++++++++++++++++ - 6 files changed, 489 insertions(+), 3 deletions(-) - create mode 100644 libavcodec/v4l2_request_decode.c - -diff --git a/configure b/configure -index 98a342d109..b74da32e8b 100755 ---- a/configure -+++ b/configure -@@ -3149,7 +3149,7 @@ dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode ole32 user32" - ffnvcodec_deps_any="libdl LoadLibrary" - mediacodec_deps="android mediandk" - nvdec_deps="ffnvcodec" --v4l2_request_deps="linux_media_h v4l2_timeval_to_ns libdrm libudev" -+v4l2_request_deps="linux_media_h v4l2_timeval_to_ns v4l2_m2m_hold_capture_buf libdrm libudev" - vaapi_x11_deps="xlib_x11" - videotoolbox_hwaccel_deps="videotoolbox pthreads" - videotoolbox_hwaccel_extralibs="-framework QuartzCore" -@@ -7202,6 +7202,7 @@ if enabled v4l2_m2m; then - fi - - if enabled v4l2_request; then -+ check_cc v4l2_m2m_hold_capture_buf linux/videodev2.h "int i = V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF" - check_func_headers "linux/media.h linux/videodev2.h" v4l2_timeval_to_ns - check_pkg_config libudev libudev libudev.h udev_new - fi -diff --git a/libavcodec/Makefile b/libavcodec/Makefile -index ebd2dc54b9..6f2229b1b6 100644 ---- a/libavcodec/Makefile -+++ b/libavcodec/Makefile -@@ -176,7 +176,7 @@ OBJS-$(CONFIG_VP3DSP) += vp3dsp.o - OBJS-$(CONFIG_VP56DSP) += vp56dsp.o - OBJS-$(CONFIG_VP8DSP) += vp8dsp.o - OBJS-$(CONFIG_V4L2_M2M) += v4l2_m2m.o v4l2_context.o v4l2_buffers.o v4l2_fmt.o --OBJS-$(CONFIG_V4L2_REQUEST) += v4l2_request.o v4l2_request_probe.o -+OBJS-$(CONFIG_V4L2_REQUEST) += v4l2_request.o v4l2_request_probe.o v4l2_request_decode.o - OBJS-$(CONFIG_WMA_FREQS) += wma_freqs.o - OBJS-$(CONFIG_WMV2DSP) += wmv2dsp.o - -diff --git a/libavcodec/hwconfig.h b/libavcodec/hwconfig.h -index ee29ca631d..159064a1f1 100644 ---- a/libavcodec/hwconfig.h -+++ b/libavcodec/hwconfig.h -@@ -79,6 +79,8 @@ void ff_hwaccel_uninit(AVCodecContext *avctx); - HW_CONFIG_HWACCEL(0, 0, 1, D3D11VA_VLD, NONE, ff_ ## codec ## _d3d11va_hwaccel) - #define HWACCEL_D3D12VA(codec) \ - HW_CONFIG_HWACCEL(1, 1, 0, D3D12, D3D12VA, ff_ ## codec ## _d3d12va_hwaccel) -+#define HWACCEL_V4L2REQUEST(codec) \ -+ HW_CONFIG_HWACCEL(1, 0, 0, DRM_PRIME, V4L2REQUEST, ff_ ## codec ## _v4l2request_hwaccel) - - #define HW_CONFIG_ENCODER(device, frames, ad_hoc, format, device_type_) \ - &(const AVCodecHWConfigInternal) { \ -diff --git a/libavcodec/v4l2_request.c b/libavcodec/v4l2_request.c -index 6f44c5d826..aae719ead6 100644 ---- a/libavcodec/v4l2_request.c -+++ b/libavcodec/v4l2_request.c -@@ -303,7 +303,8 @@ int ff_v4l2_request_uninit(AVCodecContext *avctx) - V4L2RequestContext *ctx = v4l2_request_context(avctx); ++ + static void v4l2_request_output_buffer_uninit(V4L2RequestOutputBuffer *output) + { + // Close the request associated with the OUTPUT buffer +@@ -142,7 +676,8 @@ int ff_v4l2_request_uninit(AVCodecContext *avctx) + enum v4l2_buf_type type; - if (ctx->video_fd >= 0) { + if (ctx->fctxi) { - // TODO: Flush and wait on all pending requests + // Flush and wait on all pending requests + ff_v4l2_request_flush(avctx); - // Stop output queue - if (ioctl(ctx->video_fd, VIDIOC_STREAMOFF, &ctx->output_type) < 0) { + // Stop streaming on OUTPUT queue + type = ctx->fctxi->output.format.type; diff --git a/libavcodec/v4l2_request.h b/libavcodec/v4l2_request.h -index 621caaf28c..62248feb48 100644 +index d09bbf73441c..53759f20bb10 100644 --- a/libavcodec/v4l2_request.h +++ b/libavcodec/v4l2_request.h -@@ -81,4 +81,27 @@ int ff_v4l2_request_init(AVCodecContext *avctx, - uint32_t pixelformat, uint32_t buffersize, - struct v4l2_ext_control *control, int count); +@@ -46,10 +46,51 @@ typedef struct V4L2RequestContext { + AVV4L2RequestFramesContextInternal *fctxi; + AVMutex mutex; + V4L2RequestOutputBuffer output[4]; ++ uint8_t next_output; ++ uint32_t queued_output; ++ uint32_t queued_request; ++ uint64_t queued_capture; + struct v4l2_ext_control *init_controls; + int nb_init_controls; + } V4L2RequestContext; ++typedef struct V4L2RequestPictureContext { ++ V4L2RequestOutputBuffer *output; ++ uint32_t capture_index; ++} V4L2RequestPictureContext; ++ +uint64_t ff_v4l2_request_get_capture_timestamp(AVFrame *frame); + ++int ff_v4l2_request_query_control(AVCodecContext *avctx, ++ struct v4l2_query_ext_ctrl *control); ++ ++int ff_v4l2_request_query_control_default_value(AVCodecContext *avctx, ++ uint32_t id); ++ ++int ff_v4l2_request_set_controls(AVCodecContext *avctx, ++ struct v4l2_ext_control *control, int count); ++ +int ff_v4l2_request_append_output(AVCodecContext *avctx, + V4L2RequestPictureContext *pic, + const uint8_t *data, uint32_t size); @@ -2013,13 +2629,132 @@ index 621caaf28c..62248feb48 100644 + +void ff_v4l2_request_flush(AVCodecContext *avctx); + - #endif /* AVCODEC_V4L2_REQUEST_H */ -diff --git a/libavcodec/v4l2_request_decode.c b/libavcodec/v4l2_request_decode.c + int ff_v4l2_request_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx, + uint32_t pixelformat, + +From 51a441640119ef3359a38dae67290a96ed77e6a0 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Tue, 6 Aug 2024 09:06:04 +0000 +Subject: [PATCH 05/13] avcodec: Add V4L2 Request API mpeg2 hwaccel + +Add a V4L2 Request API hwaccel for MPEG2. + +Support for MPEG2 is enabled when Linux kernel headers declare the +control id V4L2_CID_STATELESS_MPEG2_SEQUENCE, added in v5.14. + +This also change v4l2_request hwaccel to use autodetect in configure. + +Signed-off-by: Jonas Karlman +--- + configure | 7 +- + libavcodec/Makefile | 1 + + libavcodec/hwaccels.h | 1 + + libavcodec/mpeg12dec.c | 6 ++ + libavcodec/v4l2_request_mpeg2.c | 184 ++++++++++++++++++++++++++++++++ + 5 files changed, 197 insertions(+), 2 deletions(-) + create mode 100644 libavcodec/v4l2_request_mpeg2.c + +diff --git a/configure b/configure +index b50aa0605d6d..3b00bcfc0d65 100755 +--- a/configure ++++ b/configure +@@ -368,7 +368,7 @@ External library support: + --enable-omx-rpi enable OpenMAX IL code for Raspberry Pi [no] + --enable-rkmpp enable Rockchip Media Process Platform code [no] + --disable-v4l2-m2m disable V4L2 mem2mem code [autodetect] +- --enable-v4l2-request enable V4L2 Request API code [no] ++ --disable-v4l2-request disable V4L2 Request API code [autodetect] + --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] +@@ -2143,6 +2143,7 @@ HWACCEL_AUTODETECT_LIBRARY_LIST=" + videotoolbox + vulkan + v4l2_m2m ++ v4l2_request + " + + # catchall list of things that require external libs to link +@@ -2164,7 +2165,6 @@ HWACCEL_LIBRARY_LIST=" + mmal + omx + opencl +- v4l2_request + " + + DOCUMENT_LIST=" +@@ -3434,6 +3434,8 @@ mpeg2_dxva2_hwaccel_deps="dxva2" + mpeg2_dxva2_hwaccel_select="mpeg2video_decoder" + mpeg2_nvdec_hwaccel_deps="nvdec" + mpeg2_nvdec_hwaccel_select="mpeg2video_decoder" ++mpeg2_v4l2request_hwaccel_deps="v4l2_request mpeg2_v4l2_request" ++mpeg2_v4l2request_hwaccel_select="mpeg2video_decoder" + mpeg2_vaapi_hwaccel_deps="vaapi" + mpeg2_vaapi_hwaccel_select="mpeg2video_decoder" + mpeg2_vdpau_hwaccel_deps="vdpau" +@@ -7594,6 +7596,7 @@ if enabled v4l2_m2m; then + fi + + if enabled v4l2_request; then ++ check_cc mpeg2_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_MPEG2_SEQUENCE" + check_cc v4l2_m2m_hold_capture_buf linux/videodev2.h "int i = V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF" + check_func_headers "linux/media.h linux/videodev2.h" v4l2_timeval_to_ns + check_pkg_config libudev libudev libudev.h udev_new +diff --git a/libavcodec/Makefile b/libavcodec/Makefile +index a2212bbf9504..29cc4d64db02 100644 +--- a/libavcodec/Makefile ++++ b/libavcodec/Makefile +@@ -1086,6 +1086,7 @@ OBJS-$(CONFIG_MPEG2_DXVA2_HWACCEL) += dxva2_mpeg2.o + OBJS-$(CONFIG_MPEG2_D3D12VA_HWACCEL) += dxva2_mpeg2.o d3d12va_mpeg2.o + OBJS-$(CONFIG_MPEG2_NVDEC_HWACCEL) += nvdec_mpeg12.o + OBJS-$(CONFIG_MPEG2_QSV_HWACCEL) += qsvdec.o ++OBJS-$(CONFIG_MPEG2_V4L2REQUEST_HWACCEL) += v4l2_request_mpeg2.o + OBJS-$(CONFIG_MPEG2_VAAPI_HWACCEL) += vaapi_mpeg2.o + OBJS-$(CONFIG_MPEG2_VDPAU_HWACCEL) += vdpau_mpeg12.o + OBJS-$(CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o +diff --git a/libavcodec/hwaccels.h b/libavcodec/hwaccels.h +index 3de191288a59..8893064ce786 100644 +--- a/libavcodec/hwaccels.h ++++ b/libavcodec/hwaccels.h +@@ -60,6 +60,7 @@ extern const struct FFHWAccel ff_mpeg2_d3d11va2_hwaccel; + extern const struct FFHWAccel ff_mpeg2_d3d12va_hwaccel; + extern const struct FFHWAccel ff_mpeg2_dxva2_hwaccel; + extern const struct FFHWAccel ff_mpeg2_nvdec_hwaccel; ++extern const struct FFHWAccel ff_mpeg2_v4l2request_hwaccel; + extern const struct FFHWAccel ff_mpeg2_vaapi_hwaccel; + extern const struct FFHWAccel ff_mpeg2_vdpau_hwaccel; + extern const struct FFHWAccel ff_mpeg2_videotoolbox_hwaccel; +diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c +index 4c83bcfa90e3..c65e9e3b86a8 100644 +--- a/libavcodec/mpeg12dec.c ++++ b/libavcodec/mpeg12dec.c +@@ -821,6 +821,9 @@ static const enum AVPixelFormat mpeg2_hwaccel_pixfmt_list_420[] = { + #endif + #if CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL + AV_PIX_FMT_VIDEOTOOLBOX, ++#endif ++#if CONFIG_MPEG2_V4L2REQUEST_HWACCEL ++ AV_PIX_FMT_DRM_PRIME, + #endif + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_NONE +@@ -2736,6 +2739,9 @@ const FFCodec ff_mpeg2video_decoder = { + #endif + #if CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL + HWACCEL_VIDEOTOOLBOX(mpeg2), ++#endif ++#if CONFIG_MPEG2_V4L2REQUEST_HWACCEL ++ HWACCEL_V4L2REQUEST(mpeg2), + #endif + NULL + }, +diff --git a/libavcodec/v4l2_request_mpeg2.c b/libavcodec/v4l2_request_mpeg2.c new file mode 100644 -index 0000000000..8e7e241e36 +index 000000000000..5d89b7168e6f --- /dev/null -+++ b/libavcodec/v4l2_request_decode.c -@@ -0,0 +1,459 @@ ++++ b/libavcodec/v4l2_request_mpeg2.c +@@ -0,0 +1,184 @@ +/* + * This file is part of FFmpeg. + * @@ -2040,728 +2775,153 @@ index 0000000000..8e7e241e36 + +#include "config.h" + -+#include -+#include -+ -+#include "decode.h" -+#include "v4l2_request_internal.h" -+ -+#define INPUT_BUFFER_PADDING_SIZE (AV_INPUT_BUFFER_PADDING_SIZE * 4) ++#include "hwaccel_internal.h" ++#include "hwconfig.h" ++#include "mathops.h" ++#include "mpegvideo.h" ++#include "v4l2_request.h" + -+uint64_t ff_v4l2_request_get_capture_timestamp(AVFrame *frame) -+{ -+ V4L2RequestFrameDescriptor *desc = v4l2_request_framedesc(frame); -+ -+ /* -+ * The capture buffer index is used as a base for V4L2 frame reference. -+ * This works because frames are decoded into a capture buffer that is -+ * closely tied to an AVFrame. -+ */ -+ return desc ? v4l2_timeval_to_ns(&desc->capture.buffer.timestamp) : 0; -+} -+ -+static int v4l2_request_queue_buffer(V4L2RequestContext *ctx, int request_fd, -+ V4L2RequestBuffer *buf, uint32_t flags) -+{ -+ struct v4l2_plane planes[1] = {}; -+ struct v4l2_buffer buffer = { -+ .index = buf->index, -+ .type = buf->buffer.type, -+ .memory = buf->buffer.memory, -+ .timestamp = buf->buffer.timestamp, -+ .bytesused = buf->used, -+ .request_fd = request_fd, -+ .flags = ((request_fd >= 0) ? V4L2_BUF_FLAG_REQUEST_FD : 0) | flags, -+ }; -+ -+ if (V4L2_TYPE_IS_MULTIPLANAR(buffer.type)) { -+ planes[0].bytesused = buf->used; -+ buffer.bytesused = 0; -+ buffer.length = 1; -+ buffer.m.planes = planes; -+ } -+ -+ // Queue the buffer -+ if (ioctl(ctx->video_fd, VIDIOC_QBUF, &buffer) < 0) -+ return AVERROR(errno); -+ -+ // Mark the buffer as queued -+ if (V4L2_TYPE_IS_OUTPUT(buffer.type)) -+ atomic_fetch_or(&ctx->queued_output, 1 << buffer.index); -+ else -+ atomic_fetch_or(&ctx->queued_capture, 1 << buffer.index); -+ -+ return 0; -+} -+ -+static int v4l2_request_dequeue_buffer(V4L2RequestContext *ctx, -+ enum v4l2_buf_type type) -+{ -+ struct v4l2_plane planes[1] = {}; -+ struct v4l2_buffer buffer = { -+ .type = type, -+ .memory = V4L2_MEMORY_MMAP, -+ }; -+ -+ if (V4L2_TYPE_IS_MULTIPLANAR(buffer.type)) { -+ buffer.length = 1; -+ buffer.m.planes = planes; -+ } -+ -+ // Dequeue next completed buffer -+ if (ioctl(ctx->video_fd, VIDIOC_DQBUF, &buffer) < 0) -+ return AVERROR(errno); -+ -+ // Mark the buffer as dequeued -+ if (V4L2_TYPE_IS_OUTPUT(buffer.type)) -+ atomic_fetch_and(&ctx->queued_output, ~(1 << buffer.index)); -+ else -+ atomic_fetch_and(&ctx->queued_capture, ~(1 << buffer.index)); -+ -+ return 0; -+} ++typedef struct V4L2RequestControlsMPEG2 { ++ V4L2RequestPictureContext pic; ++ struct v4l2_ctrl_mpeg2_sequence sequence; ++ struct v4l2_ctrl_mpeg2_picture picture; ++ struct v4l2_ctrl_mpeg2_quantisation quantisation; ++} V4L2RequestControlsMPEG2; + -+static inline int v4l2_request_dequeue_completed_buffers(V4L2RequestContext *ctx, -+ enum v4l2_buf_type type) ++static int v4l2_request_mpeg2_start_frame(AVCodecContext *avctx, ++ av_unused const AVBufferRef *buf_ref, ++ av_unused const uint8_t *buffer, ++ av_unused uint32_t size) +{ ++ const MpegEncContext *s = avctx->priv_data; ++ V4L2RequestControlsMPEG2 *controls = s->cur_pic.ptr->hwaccel_picture_private; + int ret; + -+ do { -+ ret = v4l2_request_dequeue_buffer(ctx, type); -+ } while (!ret); ++ ret = ff_v4l2_request_start_frame(avctx, &controls->pic, s->cur_pic.ptr->f); ++ if (ret) ++ return ret; + -+ return ret; -+} ++ controls->sequence = (struct v4l2_ctrl_mpeg2_sequence) { ++ /* ISO/IEC 13818-2, ITU-T Rec. H.262: Sequence header */ ++ .horizontal_size = s->width, ++ .vertical_size = s->height, ++ .vbv_buffer_size = controls->pic.output->size, + -+static int v4l2_request_wait_on_capture(V4L2RequestContext *ctx, -+ V4L2RequestBuffer *capture) -+{ -+ struct pollfd pollfd = { -+ .fd = ctx->video_fd, -+ .events = POLLIN, ++ /* ISO/IEC 13818-2, ITU-T Rec. H.262: Sequence extension */ ++ .profile_and_level_indication = 0, ++ .chroma_format = s->chroma_format, + }; + -+ ff_mutex_lock(&ctx->mutex); -+ -+ // Dequeue all completed capture buffers -+ if (atomic_load(&ctx->queued_capture)) -+ v4l2_request_dequeue_completed_buffers(ctx, ctx->format.type); -+ -+ // Wait on the specific capture buffer, when needed -+ while (atomic_load(&ctx->queued_capture) & (1 << capture->index)) { -+ int ret = poll(&pollfd, 1, 2000); -+ if (ret <= 0) -+ goto fail; -+ -+ ret = v4l2_request_dequeue_buffer(ctx, ctx->format.type); -+ if (ret < 0 && ret != AVERROR(EAGAIN)) -+ goto fail; -+ } -+ -+ ff_mutex_unlock(&ctx->mutex); -+ return 0; ++ if (s->progressive_sequence) ++ controls->sequence.flags |= V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE; + -+fail: -+ ff_mutex_unlock(&ctx->mutex); -+ av_log(ctx, AV_LOG_ERROR, "Failed waiting on capture buffer %d\n", -+ capture->index); -+ return AVERROR(EINVAL); -+} ++ controls->picture = (struct v4l2_ctrl_mpeg2_picture) { ++ /* ISO/IEC 13818-2, ITU-T Rec. H.262: Picture header */ ++ .picture_coding_type = s->pict_type, + -+static V4L2RequestBuffer *v4l2_request_next_output(V4L2RequestContext *ctx) -+{ -+ int index; -+ V4L2RequestBuffer *output; -+ struct pollfd pollfd = { -+ .fd = ctx->video_fd, -+ .events = POLLOUT, ++ /* ISO/IEC 13818-2, ITU-T Rec. H.262: Picture coding extension */ ++ .f_code[0][0] = s->mpeg_f_code[0][0], ++ .f_code[0][1] = s->mpeg_f_code[0][1], ++ .f_code[1][0] = s->mpeg_f_code[1][0], ++ .f_code[1][1] = s->mpeg_f_code[1][1], ++ .picture_structure = s->picture_structure, ++ .intra_dc_precision = s->intra_dc_precision, + }; + -+ ff_mutex_lock(&ctx->mutex); -+ -+ // Use next output buffer in the circular queue -+ index = atomic_load(&ctx->next_output); -+ output = &ctx->output[index]; -+ atomic_store(&ctx->next_output, (index + 1) % FF_ARRAY_ELEMS(ctx->output)); -+ -+ // Dequeue all completed output buffers -+ if (atomic_load(&ctx->queued_output)) -+ v4l2_request_dequeue_completed_buffers(ctx, ctx->output_type); -+ -+ // Wait on the specific output buffer, when needed -+ while (atomic_load(&ctx->queued_output) & (1 << output->index)) { -+ int ret = poll(&pollfd, 1, 2000); -+ if (ret <= 0) -+ goto fail; ++ if (s->top_field_first) ++ controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST; + -+ ret = v4l2_request_dequeue_buffer(ctx, ctx->output_type); -+ if (ret < 0 && ret != AVERROR(EAGAIN)) -+ goto fail; -+ } ++ if (s->frame_pred_frame_dct) ++ controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT; + -+ ff_mutex_unlock(&ctx->mutex); ++ if (s->concealment_motion_vectors) ++ controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV; + -+ // Reset used state -+ output->used = 0; ++ if (s->intra_vlc_format) ++ controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_INTRA_VLC; + -+ return output; ++ if (s->q_scale_type) ++ controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE; + -+fail: -+ ff_mutex_unlock(&ctx->mutex); -+ av_log(ctx, AV_LOG_ERROR, "Failed waiting on output buffer %d\n", -+ output->index); -+ return NULL; -+} ++ if (s->alternate_scan) ++ controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_ALT_SCAN; + -+static int v4l2_request_wait_on_request(V4L2RequestContext *ctx, -+ V4L2RequestBuffer *output) -+{ -+ struct pollfd pollfd = { -+ .fd = output->fd, -+ .events = POLLPRI, -+ }; ++ if (s->repeat_first_field) ++ controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_REPEAT_FIRST; + -+ // Wait on the specific request to complete, when needed -+ while (atomic_load(&ctx->queued_request) & (1 << output->index)) { -+ int ret = poll(&pollfd, 1, 2000); -+ if (ret <= 0) -+ break; ++ if (s->progressive_frame) ++ controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_PROGRESSIVE; + -+ // Mark request as dequeued -+ if (pollfd.revents & (POLLPRI | POLLERR)) { -+ atomic_fetch_and(&ctx->queued_request, ~(1 << output->index)); -+ break; -+ } ++ switch (s->pict_type) { ++ case AV_PICTURE_TYPE_B: ++ if (s->next_pic.ptr) ++ controls->picture.backward_ref_ts = ++ ff_v4l2_request_get_capture_timestamp(s->next_pic.ptr->f); ++ // fall-through ++ case AV_PICTURE_TYPE_P: ++ if (s->last_pic.ptr) ++ controls->picture.forward_ref_ts = ++ ff_v4l2_request_get_capture_timestamp(s->last_pic.ptr->f); + } + -+ // Reinit the request object -+ if (ioctl(output->fd, MEDIA_REQUEST_IOC_REINIT, NULL) < 0) { -+ av_log(ctx, AV_LOG_ERROR, "Failed to reinit request object %d: %s (%d)\n", -+ output->fd, strerror(errno), errno); -+ return AVERROR(errno); ++ for (int i = 0; i < 64; i++) { ++ int n = s->idsp.idct_permutation[ff_zigzag_direct[i]]; ++ controls->quantisation.intra_quantiser_matrix[i] = s->intra_matrix[n]; ++ controls->quantisation.non_intra_quantiser_matrix[i] = s->inter_matrix[n]; ++ controls->quantisation.chroma_intra_quantiser_matrix[i] = s->chroma_intra_matrix[n]; ++ controls->quantisation.chroma_non_intra_quantiser_matrix[i] = s->chroma_inter_matrix[n]; + } + -+ // Ensure request is marked as dequeued -+ atomic_fetch_and(&ctx->queued_request, ~(1 << output->index)); -+ + return 0; +} + -+int ff_v4l2_request_append_output(AVCodecContext *avctx, -+ V4L2RequestPictureContext *pic, -+ const uint8_t *data, uint32_t size) ++static int v4l2_request_mpeg2_decode_slice(AVCodecContext *avctx, ++ const uint8_t *buffer, uint32_t size) +{ -+ V4L2RequestContext *ctx = v4l2_request_context(avctx); ++ const MpegEncContext *s = avctx->priv_data; ++ V4L2RequestControlsMPEG2 *controls = s->cur_pic.ptr->hwaccel_picture_private; + -+ // Append data to output buffer and ensure there is enough space for padding -+ if (pic->output->used + size + INPUT_BUFFER_PADDING_SIZE <= pic->output->size) { -+ memcpy(pic->output->addr + pic->output->used, data, size); -+ pic->output->used += size; -+ return 0; -+ } else { -+ av_log(ctx, AV_LOG_ERROR, -+ "Failed to append %u bytes data to output buffer %d (%u of %u used)\n", -+ size, pic->output->index, pic->output->used, pic->output->size); -+ return AVERROR(ENOMEM); -+ } ++ return ff_v4l2_request_append_output(avctx, &controls->pic, buffer, size); +} + -+static int v4l2_request_queue_decode(AVCodecContext *avctx, -+ V4L2RequestPictureContext *pic, -+ struct v4l2_ext_control *control, int count, -+ bool first_slice, bool last_slice) ++static int v4l2_request_mpeg2_end_frame(AVCodecContext *avctx) +{ -+ V4L2RequestContext *ctx = v4l2_request_context(avctx); -+ uint32_t flags; -+ int ret; -+ -+ if (first_slice) { -+ /* -+ * Wait on dequeue of the target capture buffer, when needed. Otherwise -+ * V4L2 decoder may use a different capture buffer than hwaccel expects. -+ * -+ * Normally decoding has already completed when a capture buffer is -+ * reused so this is more or less a no-op, however in some situations -+ * FFmpeg may reuse an AVFrame early, i.e. when no output frame was -+ * produced prior time, and a syncronization is necessary. -+ */ -+ ret = v4l2_request_wait_on_capture(ctx, pic->capture); -+ if (ret < 0) -+ return ret; -+ } -+ -+ ff_mutex_lock(&ctx->mutex); -+ -+ /* -+ * The output buffer tied to prior use of current request object can -+ * independently be dequeued before the full decode request has been -+ * completed. This may happen when a decoder use multi stage decoding, -+ * e.g. rpivid. In such case we can start reusing the output buffer, -+ * however we must wait on the prior request to fully complete before we -+ * can reuse the request object, and a syncronization is necessary. -+ */ -+ ret = v4l2_request_wait_on_request(ctx, pic->output); -+ if (ret < 0) -+ goto fail; ++ const MpegEncContext *s = avctx->priv_data; ++ V4L2RequestControlsMPEG2 *controls = s->cur_pic.ptr->hwaccel_picture_private; + -+ /* -+ * Dequeue any completed output buffers, this is strictly not necessary, -+ * however if a syncronization was necessary for the capture and/or request -+ * there is more than likely one or more output buffers that can be dequeued. -+ */ -+ if (atomic_load(&ctx->queued_output)) -+ v4l2_request_dequeue_completed_buffers(ctx, ctx->output_type); ++ struct v4l2_ext_control control[] = { ++ { ++ .id = V4L2_CID_STATELESS_MPEG2_SEQUENCE, ++ .ptr = &controls->sequence, ++ .size = sizeof(controls->sequence), ++ }, ++ { ++ .id = V4L2_CID_STATELESS_MPEG2_PICTURE, ++ .ptr = &controls->picture, ++ .size = sizeof(controls->picture), ++ }, ++ { ++ .id = V4L2_CID_STATELESS_MPEG2_QUANTISATION, ++ .ptr = &controls->quantisation, ++ .size = sizeof(controls->quantisation), ++ }, ++ }; + -+ // Set codec controls for current request -+ ret = ff_v4l2_request_set_request_controls(ctx, pic->output->fd, control, count); -+ if (ret < 0) { -+ av_log(ctx, AV_LOG_ERROR, "Failed to set %d control(s) for request %d: %s (%d)\n", -+ count, pic->output->fd, strerror(errno), errno); -+ goto fail; -+ } ++ return ff_v4l2_request_decode_frame(avctx, &controls->pic, ++ control, FF_ARRAY_ELEMS(control)); ++} + -+ // Ensure there is zero padding at the end of bitstream data -+ memset(pic->output->addr + pic->output->used, 0, INPUT_BUFFER_PADDING_SIZE); ++static int v4l2_request_mpeg2_init(AVCodecContext *avctx) ++{ ++ return ff_v4l2_request_init(avctx, NULL, 0, NULL); ++} + -+ // Use timestamp of the capture buffer for V4L2 frame reference -+ pic->output->buffer.timestamp = pic->capture->buffer.timestamp; -+ -+ /* -+ * Queue the output buffer of current request. The capture buffer may be -+ * hold by the V4L2 decoder unless this is the last slice of a frame. -+ */ -+ flags = last_slice ? 0 : V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF; -+ ret = v4l2_request_queue_buffer(ctx, pic->output->fd, pic->output, flags); -+ if (ret < 0) { -+ av_log(ctx, AV_LOG_ERROR, "Failed to queue output buffer %d for request %d: %s (%d)\n", -+ pic->output->index, pic->output->fd, strerror(errno), errno); -+ ret = AVERROR(errno); -+ goto fail; -+ } -+ -+ if (first_slice) { -+ /* -+ * Queue the target capture buffer, hwaccel expect and depend on that -+ * this specific capture buffer will be used as decode target for -+ * current request, otherwise frames may be output in wrong order or -+ * wrong capture buffer could get used as a reference frame. -+ */ -+ ret = v4l2_request_queue_buffer(ctx, -1, pic->capture, 0); -+ if (ret < 0) { -+ av_log(ctx, AV_LOG_ERROR, "Failed to queue capture buffer %d for request %d: %s (%d)\n", -+ pic->capture->index, pic->output->fd, strerror(errno), errno); -+ ret = AVERROR(errno); -+ goto fail; -+ } -+ } -+ -+ // Queue current request -+ ret = ioctl(pic->output->fd, MEDIA_REQUEST_IOC_QUEUE, NULL); -+ if (ret < 0) { -+ av_log(ctx, AV_LOG_ERROR, "Failed to queue request object %d: %s (%d)\n", -+ pic->output->fd, strerror(errno), errno); -+ ret = AVERROR(errno); -+ goto fail; -+ } -+ -+ // Mark current request as queued -+ atomic_fetch_or(&ctx->queued_request, 1 << pic->output->index); -+ -+ ret = 0; -+fail: -+ ff_mutex_unlock(&ctx->mutex); -+ return ret; -+} -+ -+int ff_v4l2_request_decode_slice(AVCodecContext *avctx, -+ V4L2RequestPictureContext *pic, -+ struct v4l2_ext_control *control, int count, -+ bool first_slice, bool last_slice) -+{ -+ /* -+ * Fallback to queue each slice as a full frame when holding capture -+ * buffers is not supported by the driver. -+ */ -+ if ((pic->output->capabilities & V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF) != -+ V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF) -+ return v4l2_request_queue_decode(avctx, pic, control, count, true, true); -+ -+ return v4l2_request_queue_decode(avctx, pic, control, count, -+ first_slice, last_slice); -+} -+ -+int ff_v4l2_request_decode_frame(AVCodecContext *avctx, -+ V4L2RequestPictureContext *pic, -+ struct v4l2_ext_control *control, int count) -+{ -+ return v4l2_request_queue_decode(avctx, pic, control, count, true, true); -+} -+ -+static int v4l2_request_post_process(void *logctx, AVFrame *frame) -+{ -+ V4L2RequestFrameDescriptor *desc = v4l2_request_framedesc(frame); -+ FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; -+ V4L2RequestContext *ctx = fdd->hwaccel_priv; -+ -+ // Wait on capture buffer before returning the frame to application -+ return v4l2_request_wait_on_capture(ctx, &desc->capture); -+} -+ -+int ff_v4l2_request_reset_picture(AVCodecContext *avctx, V4L2RequestPictureContext *pic) -+{ -+ V4L2RequestContext *ctx = v4l2_request_context(avctx); -+ -+ // Get and wait on next output buffer from circular queue -+ pic->output = v4l2_request_next_output(ctx); -+ if (!pic->output) -+ return AVERROR(EINVAL); -+ -+ return 0; -+} -+ -+int ff_v4l2_request_start_frame(AVCodecContext *avctx, -+ V4L2RequestPictureContext *pic, -+ AVFrame *frame) -+{ -+ V4L2RequestContext *ctx = v4l2_request_context(avctx); -+ V4L2RequestFrameDescriptor *desc = v4l2_request_framedesc(frame); -+ FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; -+ int ret; -+ -+ // Get next output buffer from circular queue -+ ret = ff_v4l2_request_reset_picture(avctx, pic); -+ if (ret) -+ return ret; -+ -+ // Ensure capture buffer is dequeued before reuse -+ ret = v4l2_request_wait_on_capture(ctx, &desc->capture); -+ if (ret) -+ return ret; -+ -+ // Wait on capture buffer in post_process() before returning to application -+ fdd->hwaccel_priv = ctx; -+ fdd->post_process = v4l2_request_post_process; -+ -+ // Capture buffer used for current frame -+ pic->capture = &desc->capture; -+ -+ return 0; -+} -+ -+void ff_v4l2_request_flush(AVCodecContext *avctx) -+{ -+ V4L2RequestContext *ctx = v4l2_request_context(avctx); -+ struct pollfd pollfd = { -+ .fd = ctx->video_fd, -+ .events = POLLOUT, -+ }; -+ -+ ff_mutex_lock(&ctx->mutex); -+ -+ // Dequeue all completed output buffers -+ if (atomic_load(&ctx->queued_output)) -+ v4l2_request_dequeue_completed_buffers(ctx, ctx->output_type); -+ -+ // Wait on any remaining output buffer -+ while (atomic_load(&ctx->queued_output)) { -+ int ret = poll(&pollfd, 1, 2000); -+ if (ret <= 0) -+ break; -+ -+ ret = v4l2_request_dequeue_buffer(ctx, ctx->output_type); -+ if (ret < 0 && ret != AVERROR(EAGAIN)) -+ break; -+ } -+ -+ // Dequeue all completed capture buffers -+ if (atomic_load(&ctx->queued_capture)) -+ v4l2_request_dequeue_completed_buffers(ctx, ctx->format.type); -+ -+ ff_mutex_unlock(&ctx->mutex); -+} - -From 66cb225496620a953033096eb1013692be9cb931 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Tue, 6 Aug 2024 09:06:04 +0000 -Subject: [PATCH 05/11] avcodec: Add V4L2 Request API mpeg2 hwaccel - -Add a V4L2 Request API hwaccel for MPEG2. - -Support for MPEG2 is enabled when Linux kernel headers declare the -control id V4L2_CID_STATELESS_MPEG2_SEQUENCE, added in v5.14. - -This also change v4l2_request hwaccel to use autodetect in configure. - -Signed-off-by: Jonas Karlman ---- - configure | 7 +- - libavcodec/Makefile | 1 + - libavcodec/hwaccels.h | 1 + - libavcodec/mpeg12dec.c | 6 ++ - libavcodec/v4l2_request_mpeg2.c | 176 ++++++++++++++++++++++++++++++++ - 5 files changed, 189 insertions(+), 2 deletions(-) - create mode 100644 libavcodec/v4l2_request_mpeg2.c - -diff --git a/configure b/configure -index b74da32e8b..cbf0ee0ced 100755 ---- a/configure -+++ b/configure -@@ -359,7 +359,7 @@ External library support: - --enable-omx-rpi enable OpenMAX IL code for Raspberry Pi [no] - --enable-rkmpp enable Rockchip Media Process Platform code [no] - --disable-v4l2-m2m disable V4L2 mem2mem code [autodetect] -- --enable-v4l2-request enable V4L2 Request API code [no] -+ --disable-v4l2-request disable V4L2 Request API code [autodetect] - --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] -@@ -2006,6 +2006,7 @@ HWACCEL_AUTODETECT_LIBRARY_LIST=" - videotoolbox - vulkan - v4l2_m2m -+ v4l2_request - " - - # catchall list of things that require external libs to link -@@ -2027,7 +2028,6 @@ HWACCEL_LIBRARY_LIST=" - mmal - omx - opencl -- v4l2_request - " - - DOCUMENT_LIST=" -@@ -3232,6 +3232,8 @@ mpeg2_dxva2_hwaccel_deps="dxva2" - mpeg2_dxva2_hwaccel_select="mpeg2video_decoder" - mpeg2_nvdec_hwaccel_deps="nvdec" - mpeg2_nvdec_hwaccel_select="mpeg2video_decoder" -+mpeg2_v4l2request_hwaccel_deps="v4l2_request mpeg2_v4l2_request" -+mpeg2_v4l2request_hwaccel_select="mpeg2video_decoder" - mpeg2_vaapi_hwaccel_deps="vaapi" - mpeg2_vaapi_hwaccel_select="mpeg2video_decoder" - mpeg2_vdpau_hwaccel_deps="vdpau" -@@ -7202,6 +7204,7 @@ if enabled v4l2_m2m; then - fi - - if enabled v4l2_request; then -+ check_cc mpeg2_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_MPEG2_SEQUENCE" - check_cc v4l2_m2m_hold_capture_buf linux/videodev2.h "int i = V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF" - check_func_headers "linux/media.h linux/videodev2.h" v4l2_timeval_to_ns - check_pkg_config libudev libudev libudev.h udev_new -diff --git a/libavcodec/Makefile b/libavcodec/Makefile -index 6f2229b1b6..2c69b747b1 100644 ---- a/libavcodec/Makefile -+++ b/libavcodec/Makefile -@@ -1039,6 +1039,7 @@ OBJS-$(CONFIG_MPEG2_DXVA2_HWACCEL) += dxva2_mpeg2.o - OBJS-$(CONFIG_MPEG2_D3D12VA_HWACCEL) += dxva2_mpeg2.o d3d12va_mpeg2.o - OBJS-$(CONFIG_MPEG2_NVDEC_HWACCEL) += nvdec_mpeg12.o - OBJS-$(CONFIG_MPEG2_QSV_HWACCEL) += qsvdec.o -+OBJS-$(CONFIG_MPEG2_V4L2REQUEST_HWACCEL) += v4l2_request_mpeg2.o - OBJS-$(CONFIG_MPEG2_VAAPI_HWACCEL) += vaapi_mpeg2.o - OBJS-$(CONFIG_MPEG2_VDPAU_HWACCEL) += vdpau_mpeg12.o - OBJS-$(CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o -diff --git a/libavcodec/hwaccels.h b/libavcodec/hwaccels.h -index 5171e4c7d7..0cba7c71be 100644 ---- a/libavcodec/hwaccels.h -+++ b/libavcodec/hwaccels.h -@@ -57,6 +57,7 @@ extern const struct FFHWAccel ff_mpeg2_d3d11va2_hwaccel; - extern const struct FFHWAccel ff_mpeg2_d3d12va_hwaccel; - extern const struct FFHWAccel ff_mpeg2_dxva2_hwaccel; - extern const struct FFHWAccel ff_mpeg2_nvdec_hwaccel; -+extern const struct FFHWAccel ff_mpeg2_v4l2request_hwaccel; - extern const struct FFHWAccel ff_mpeg2_vaapi_hwaccel; - extern const struct FFHWAccel ff_mpeg2_vdpau_hwaccel; - extern const struct FFHWAccel ff_mpeg2_videotoolbox_hwaccel; -diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c -index 4f784611de..af8ffa5976 100644 ---- a/libavcodec/mpeg12dec.c -+++ b/libavcodec/mpeg12dec.c -@@ -839,6 +839,9 @@ static const enum AVPixelFormat mpeg2_hwaccel_pixfmt_list_420[] = { - #endif - #if CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL - AV_PIX_FMT_VIDEOTOOLBOX, -+#endif -+#if CONFIG_MPEG2_V4L2REQUEST_HWACCEL -+ AV_PIX_FMT_DRM_PRIME, - #endif - AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE -@@ -2681,6 +2684,9 @@ const FFCodec ff_mpeg2video_decoder = { - #endif - #if CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL - HWACCEL_VIDEOTOOLBOX(mpeg2), -+#endif -+#if CONFIG_MPEG2_V4L2REQUEST_HWACCEL -+ HWACCEL_V4L2REQUEST(mpeg2), - #endif - NULL - }, -diff --git a/libavcodec/v4l2_request_mpeg2.c b/libavcodec/v4l2_request_mpeg2.c -new file mode 100644 -index 0000000000..998c91355a ---- /dev/null -+++ b/libavcodec/v4l2_request_mpeg2.c -@@ -0,0 +1,176 @@ -+/* -+ * 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 "config.h" -+ -+#include "hwaccel_internal.h" -+#include "hwconfig.h" -+#include "mpegvideo.h" -+#include "v4l2_request.h" -+ -+typedef struct V4L2RequestControlsMPEG2 { -+ V4L2RequestPictureContext pic; -+ struct v4l2_ctrl_mpeg2_sequence sequence; -+ struct v4l2_ctrl_mpeg2_picture picture; -+ struct v4l2_ctrl_mpeg2_quantisation quantisation; -+} V4L2RequestControlsMPEG2; -+ -+static int v4l2_request_mpeg2_start_frame(AVCodecContext *avctx, -+ av_unused const uint8_t *buffer, -+ av_unused uint32_t size) -+{ -+ const MpegEncContext *s = avctx->priv_data; -+ V4L2RequestControlsMPEG2 *controls = s->cur_pic.ptr->hwaccel_picture_private; -+ int ret; -+ -+ ret = ff_v4l2_request_start_frame(avctx, &controls->pic, s->cur_pic.ptr->f); -+ if (ret) -+ return ret; -+ -+ controls->sequence = (struct v4l2_ctrl_mpeg2_sequence) { -+ /* ISO/IEC 13818-2, ITU-T Rec. H.262: Sequence header */ -+ .horizontal_size = s->width, -+ .vertical_size = s->height, -+ .vbv_buffer_size = controls->pic.output->size, -+ -+ /* ISO/IEC 13818-2, ITU-T Rec. H.262: Sequence extension */ -+ .profile_and_level_indication = 0, -+ .chroma_format = s->chroma_format, -+ }; -+ -+ if (s->progressive_sequence) -+ controls->sequence.flags |= V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE; -+ -+ controls->picture = (struct v4l2_ctrl_mpeg2_picture) { -+ /* ISO/IEC 13818-2, ITU-T Rec. H.262: Picture header */ -+ .picture_coding_type = s->pict_type, -+ -+ /* ISO/IEC 13818-2, ITU-T Rec. H.262: Picture coding extension */ -+ .f_code[0][0] = s->mpeg_f_code[0][0], -+ .f_code[0][1] = s->mpeg_f_code[0][1], -+ .f_code[1][0] = s->mpeg_f_code[1][0], -+ .f_code[1][1] = s->mpeg_f_code[1][1], -+ .picture_structure = s->picture_structure, -+ .intra_dc_precision = s->intra_dc_precision, -+ }; -+ -+ if (s->top_field_first) -+ controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST; -+ -+ if (s->frame_pred_frame_dct) -+ controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT; -+ -+ if (s->concealment_motion_vectors) -+ controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV; -+ -+ if (s->intra_vlc_format) -+ controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_INTRA_VLC; -+ -+ if (s->q_scale_type) -+ controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE; -+ -+ if (s->alternate_scan) -+ controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_ALT_SCAN; -+ -+ if (s->repeat_first_field) -+ controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_REPEAT_FIRST; -+ -+ if (s->progressive_frame) -+ controls->picture.flags |= V4L2_MPEG2_PIC_FLAG_PROGRESSIVE; -+ -+ switch (s->pict_type) { -+ case AV_PICTURE_TYPE_B: -+ if (s->next_pic.ptr) -+ controls->picture.backward_ref_ts = -+ ff_v4l2_request_get_capture_timestamp(s->next_pic.ptr->f); -+ // fall-through -+ case AV_PICTURE_TYPE_P: -+ if (s->last_pic.ptr) -+ controls->picture.forward_ref_ts = -+ ff_v4l2_request_get_capture_timestamp(s->last_pic.ptr->f); -+ } -+ -+ for (int i = 0; i < 64; i++) { -+ int n = s->idsp.idct_permutation[ff_zigzag_direct[i]]; -+ controls->quantisation.intra_quantiser_matrix[i] = s->intra_matrix[n]; -+ controls->quantisation.non_intra_quantiser_matrix[i] = s->inter_matrix[n]; -+ controls->quantisation.chroma_intra_quantiser_matrix[i] = s->chroma_intra_matrix[n]; -+ controls->quantisation.chroma_non_intra_quantiser_matrix[i] = s->chroma_inter_matrix[n]; -+ } -+ -+ return 0; -+} -+ -+static int v4l2_request_mpeg2_decode_slice(AVCodecContext *avctx, -+ const uint8_t *buffer, uint32_t size) -+{ -+ const MpegEncContext *s = avctx->priv_data; -+ V4L2RequestControlsMPEG2 *controls = s->cur_pic.ptr->hwaccel_picture_private; -+ -+ return ff_v4l2_request_append_output(avctx, &controls->pic, buffer, size); -+} -+ -+static int v4l2_request_mpeg2_end_frame(AVCodecContext *avctx) -+{ -+ const MpegEncContext *s = avctx->priv_data; -+ V4L2RequestControlsMPEG2 *controls = s->cur_pic.ptr->hwaccel_picture_private; -+ -+ struct v4l2_ext_control control[] = { -+ { -+ .id = V4L2_CID_STATELESS_MPEG2_SEQUENCE, -+ .ptr = &controls->sequence, -+ .size = sizeof(controls->sequence), -+ }, -+ { -+ .id = V4L2_CID_STATELESS_MPEG2_PICTURE, -+ .ptr = &controls->picture, -+ .size = sizeof(controls->picture), -+ }, -+ { -+ .id = V4L2_CID_STATELESS_MPEG2_QUANTISATION, -+ .ptr = &controls->quantisation, -+ .size = sizeof(controls->quantisation), -+ }, -+ }; -+ -+ return ff_v4l2_request_decode_frame(avctx, &controls->pic, -+ control, FF_ARRAY_ELEMS(control)); -+} -+ -+static int v4l2_request_mpeg2_init(AVCodecContext *avctx) -+{ -+ return ff_v4l2_request_init(avctx, V4L2_PIX_FMT_MPEG2_SLICE, -+ 1024 * 1024, -+ NULL, 0); -+} ++static int v4l2_request_mpeg2_frame_params(AVCodecContext *avctx, ++ AVBufferRef *hw_frames_ctx) ++{ ++ return ff_v4l2_request_frame_params(avctx, hw_frames_ctx, ++ V4L2_PIX_FMT_MPEG2_SLICE, 8); ++} + +const FFHWAccel ff_mpeg2_v4l2request_hwaccel = { + .p.name = "mpeg2_v4l2request", @@ -2776,13 +2936,14 @@ index 0000000000..998c91355a + .init = v4l2_request_mpeg2_init, + .uninit = ff_v4l2_request_uninit, + .priv_data_size = sizeof(V4L2RequestContext), -+ .frame_params = ff_v4l2_request_frame_params, ++ .frame_params = v4l2_request_mpeg2_frame_params, ++ .caps_internal = HWACCEL_CAP_ASYNC_SAFE, +}; -From bccaf9b66ca4e1180c0d42bc95daf540e1e2ffb7 Mon Sep 17 00:00:00 2001 +From 55d176a32f6e55543261889e172270df833ce19b Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 6 Aug 2024 09:06:05 +0000 -Subject: [PATCH 06/11] avcodec/h264dec: add ref_pic_marking and pic_order_cnt +Subject: [PATCH 06/13] avcodec/h264dec: add ref_pic_marking and pic_order_cnt bit_size to slice context The V4L2_CID_STATELESS_H264_DECODE_PARAMS control require following: @@ -2806,10 +2967,10 @@ Signed-off-by: Jonas Karlman 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c -index a66b75ca80..58a48f3fbe 100644 +index 0ce8e46c72b4..7ab26d423139 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c -@@ -1690,7 +1690,7 @@ static int h264_slice_header_parse(const H264Context *h, H264SliceContext *sl, +@@ -1701,7 +1701,7 @@ static int h264_slice_header_parse(const H264Context *h, H264SliceContext *sl, unsigned int slice_type, tmp, i; int field_pic_flag, bottom_field_flag; int first_slice = sl == h->slice_ctx && !h->current_slice; @@ -2818,7 +2979,7 @@ index a66b75ca80..58a48f3fbe 100644 if (first_slice) av_assert0(!h->setup_finished); -@@ -1781,6 +1781,7 @@ static int h264_slice_header_parse(const H264Context *h, H264SliceContext *sl, +@@ -1792,6 +1792,7 @@ static int h264_slice_header_parse(const H264Context *h, H264SliceContext *sl, sl->poc_lsb = 0; sl->delta_poc_bottom = 0; @@ -2826,7 +2987,7 @@ index a66b75ca80..58a48f3fbe 100644 if (sps->poc_type == 0) { sl->poc_lsb = get_bits(&sl->gb, sps->log2_max_poc_lsb); -@@ -1795,6 +1796,7 @@ static int h264_slice_header_parse(const H264Context *h, H264SliceContext *sl, +@@ -1806,6 +1807,7 @@ static int h264_slice_header_parse(const H264Context *h, H264SliceContext *sl, if (pps->pic_order_present == 1 && picture_structure == PICT_FRAME) sl->delta_poc[1] = get_se_golomb(&sl->gb); } @@ -2834,7 +2995,7 @@ index a66b75ca80..58a48f3fbe 100644 sl->redundant_pic_count = 0; if (pps->redundant_pic_cnt_present) -@@ -1834,9 +1836,11 @@ static int h264_slice_header_parse(const H264Context *h, H264SliceContext *sl, +@@ -1845,9 +1847,11 @@ static int h264_slice_header_parse(const H264Context *h, H264SliceContext *sl, sl->explicit_ref_marking = 0; if (nal->ref_idc) { @@ -2847,10 +3008,10 @@ index a66b75ca80..58a48f3fbe 100644 if (sl->slice_type_nos != AV_PICTURE_TYPE_I && pps->cabac) { diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h -index ccd7583bf4..71cbb0e0cc 100644 +index 74fd09dfaacd..33d788627f38 100644 --- a/libavcodec/h264dec.h +++ b/libavcodec/h264dec.h -@@ -324,6 +324,7 @@ typedef struct H264SliceContext { +@@ -322,6 +322,7 @@ typedef struct H264SliceContext { MMCO mmco[H264_MAX_MMCO_COUNT]; int nb_mmco; int explicit_ref_marking; @@ -2858,7 +3019,7 @@ index ccd7583bf4..71cbb0e0cc 100644 int frame_num; int idr_pic_id; -@@ -332,6 +333,7 @@ typedef struct H264SliceContext { +@@ -330,6 +331,7 @@ typedef struct H264SliceContext { int delta_poc[2]; int curr_pic_num; int max_pic_num; @@ -2867,10 +3028,10 @@ index ccd7583bf4..71cbb0e0cc 100644 /** -From e7674a31a7bc8b37a8ba4be0fc59074333a95b2d Mon Sep 17 00:00:00 2001 +From 84bb22c3eba4b8ed70322f65882dd52cdeec31ed Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Tue, 6 Aug 2024 09:06:06 +0000 -Subject: [PATCH 07/11] avcodec: Add V4L2 Request API h264 hwaccel +Subject: [PATCH 07/13] avcodec: Add V4L2 Request API h264 hwaccel Add a V4L2 Request API hwaccel for H.264, supporting both slice and frame decoding modes. @@ -2887,15 +3048,15 @@ Signed-off-by: Jonas Karlman libavcodec/h264_slice.c | 7 + libavcodec/h264dec.c | 3 + libavcodec/hwaccels.h | 1 + - libavcodec/v4l2_request_h264.c | 522 +++++++++++++++++++++++++++++++++ - 6 files changed, 537 insertions(+) + libavcodec/v4l2_request_h264.c | 532 +++++++++++++++++++++++++++++++++ + 6 files changed, 547 insertions(+) create mode 100644 libavcodec/v4l2_request_h264.c diff --git a/configure b/configure -index cbf0ee0ced..6866a61153 100755 +index 3b00bcfc0d65..0bfd84358d3e 100755 --- a/configure +++ b/configure -@@ -3186,6 +3186,8 @@ h264_dxva2_hwaccel_deps="dxva2" +@@ -3388,6 +3388,8 @@ h264_dxva2_hwaccel_deps="dxva2" h264_dxva2_hwaccel_select="h264_decoder" h264_nvdec_hwaccel_deps="nvdec" h264_nvdec_hwaccel_select="h264_decoder" @@ -2904,7 +3065,7 @@ index cbf0ee0ced..6866a61153 100755 h264_vaapi_hwaccel_deps="vaapi" h264_vaapi_hwaccel_select="h264_decoder" h264_vdpau_hwaccel_deps="vdpau" -@@ -7204,6 +7206,7 @@ if enabled v4l2_m2m; then +@@ -7596,6 +7598,7 @@ if enabled v4l2_m2m; then fi if enabled v4l2_request; then @@ -2913,10 +3074,10 @@ index cbf0ee0ced..6866a61153 100755 check_cc v4l2_m2m_hold_capture_buf linux/videodev2.h "int i = V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF" check_func_headers "linux/media.h linux/videodev2.h" v4l2_timeval_to_ns diff --git a/libavcodec/Makefile b/libavcodec/Makefile -index 2c69b747b1..00bc1cf8f2 100644 +index 29cc4d64db02..7b5653df8854 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile -@@ -1017,6 +1017,7 @@ OBJS-$(CONFIG_H264_DXVA2_HWACCEL) += dxva2_h264.o +@@ -1064,6 +1064,7 @@ OBJS-$(CONFIG_H264_DXVA2_HWACCEL) += dxva2_h264.o OBJS-$(CONFIG_H264_D3D12VA_HWACCEL) += dxva2_h264.o d3d12va_h264.o OBJS-$(CONFIG_H264_NVDEC_HWACCEL) += nvdec_h264.o OBJS-$(CONFIG_H264_QSV_HWACCEL) += qsvdec.o @@ -2925,10 +3086,10 @@ index 2c69b747b1..00bc1cf8f2 100644 OBJS-$(CONFIG_H264_VDPAU_HWACCEL) += vdpau_h264.o OBJS-$(CONFIG_H264_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c -index 58a48f3fbe..259a2c307a 100644 +index 7ab26d423139..97fab7085c72 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c -@@ -781,6 +781,7 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) +@@ -789,6 +789,7 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) (CONFIG_H264_D3D11VA_HWACCEL * 2) + \ CONFIG_H264_D3D12VA_HWACCEL + \ CONFIG_H264_NVDEC_HWACCEL + \ @@ -2936,17 +3097,17 @@ index 58a48f3fbe..259a2c307a 100644 CONFIG_H264_VAAPI_HWACCEL + \ CONFIG_H264_VIDEOTOOLBOX_HWACCEL + \ CONFIG_H264_VDPAU_HWACCEL + \ -@@ -806,6 +807,9 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) +@@ -817,6 +818,9 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) #endif - #if CONFIG_H264_VULKAN_HWACCEL - *fmt++ = AV_PIX_FMT_VULKAN; + #if CONFIG_H264_NVDEC_HWACCEL + *fmt++ = AV_PIX_FMT_CUDA; +#endif +#if CONFIG_H264_V4L2REQUEST_HWACCEL + *fmt++ = AV_PIX_FMT_DRM_PRIME; #endif if (CHROMA444(h)) { if (h->avctx->colorspace == AVCOL_SPC_RGB) { -@@ -862,6 +866,9 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) +@@ -873,6 +877,9 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) #if CONFIG_H264_VIDEOTOOLBOX_HWACCEL if (h->avctx->colorspace != AVCOL_SPC_RGB) *fmt++ = AV_PIX_FMT_VIDEOTOOLBOX; @@ -2957,10 +3118,10 @@ index 58a48f3fbe..259a2c307a 100644 if (CHROMA444(h)) { if (h->avctx->colorspace == AVCOL_SPC_RGB) diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c -index 0154fe17b6..a5e89ebddd 100644 +index 809a93838643..6c4ce97f63f9 100644 --- a/libavcodec/h264dec.c +++ b/libavcodec/h264dec.c -@@ -1160,6 +1160,9 @@ const FFCodec ff_h264_decoder = { +@@ -1144,6 +1144,9 @@ const FFCodec ff_h264_decoder = { #endif #if CONFIG_H264_VULKAN_HWACCEL HWACCEL_VULKAN(h264), @@ -2971,10 +3132,10 @@ index 0154fe17b6..a5e89ebddd 100644 NULL }, diff --git a/libavcodec/hwaccels.h b/libavcodec/hwaccels.h -index 0cba7c71be..024e021d73 100644 +index 8893064ce786..052153465feb 100644 --- a/libavcodec/hwaccels.h +++ b/libavcodec/hwaccels.h -@@ -34,6 +34,7 @@ extern const struct FFHWAccel ff_h264_d3d11va2_hwaccel; +@@ -37,6 +37,7 @@ extern const struct FFHWAccel ff_h264_d3d11va2_hwaccel; extern const struct FFHWAccel ff_h264_d3d12va_hwaccel; extern const struct FFHWAccel ff_h264_dxva2_hwaccel; extern const struct FFHWAccel ff_h264_nvdec_hwaccel; @@ -2984,10 +3145,10 @@ index 0cba7c71be..024e021d73 100644 extern const struct FFHWAccel ff_h264_videotoolbox_hwaccel; diff --git a/libavcodec/v4l2_request_h264.c b/libavcodec/v4l2_request_h264.c new file mode 100644 -index 0000000000..5affe309ac +index 000000000000..5abf631090ac --- /dev/null +++ b/libavcodec/v4l2_request_h264.c -@@ -0,0 +1,522 @@ +@@ -0,0 +1,532 @@ +/* + * This file is part of FFmpeg. + * @@ -3217,6 +3378,7 @@ index 0000000000..5affe309ac +} + +static int v4l2_request_h264_start_frame(AVCodecContext *avctx, ++ av_unused const AVBufferRef *buf_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) +{ @@ -3437,7 +3599,7 @@ index 0000000000..5affe309ac + return v4l2_request_h264_queue_decode(avctx, true); +} + -+static int v4l2_request_h264_post_probe(AVCodecContext *avctx) ++static int v4l2_request_h264_post_frames_ctx(AVCodecContext *avctx) +{ + V4L2RequestContextH264 *ctx = avctx->internal->hwaccel_priv_data; + @@ -3475,7 +3637,6 @@ index 0000000000..5affe309ac + +static int v4l2_request_h264_init(AVCodecContext *avctx) +{ -+ V4L2RequestContextH264 *ctx = avctx->internal->hwaccel_priv_data; + const H264Context *h = avctx->priv_data; + struct v4l2_ctrl_h264_sps sps; + @@ -3489,10 +3650,19 @@ index 0000000000..5affe309ac + + fill_sps(&sps, h); + -+ ctx->base.post_probe = v4l2_request_h264_post_probe; -+ return ff_v4l2_request_init(avctx, V4L2_PIX_FMT_H264_SLICE, -+ 4 * 1024 * 1024, -+ control, FF_ARRAY_ELEMS(control)); ++ return ff_v4l2_request_init(avctx, control, FF_ARRAY_ELEMS(control), ++ v4l2_request_h264_post_frames_ctx); ++} ++ ++static int v4l2_request_h264_frame_params(AVCodecContext *avctx, ++ AVBufferRef *hw_frames_ctx) ++{ ++ const H264Context *h = avctx->priv_data; ++ const SPS *sps = h ? h->ps.sps : NULL; ++ uint8_t bit_depth = sps ? sps->bit_depth_luma : 0; ++ ++ return ff_v4l2_request_frame_params(avctx, hw_frames_ctx, ++ V4L2_PIX_FMT_H264_SLICE, bit_depth); +} + +const FFHWAccel ff_h264_v4l2request_hwaccel = { @@ -3508,13 +3678,14 @@ index 0000000000..5affe309ac + .init = v4l2_request_h264_init, + .uninit = ff_v4l2_request_uninit, + .priv_data_size = sizeof(V4L2RequestContextH264), -+ .frame_params = ff_v4l2_request_frame_params, ++ .frame_params = v4l2_request_h264_frame_params, ++ .caps_internal = HWACCEL_CAP_ASYNC_SAFE, +}; -From 0b3c85ab94619e449026145a9795f2013732977c Mon Sep 17 00:00:00 2001 +From adab6e2bb9472e9e8f9716569d54aeede50c1aa3 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Tue, 6 Aug 2024 09:06:07 +0000 -Subject: [PATCH 08/11] avcodec: Add V4L2 Request API hevc hwaccel +Subject: [PATCH 08/13] avcodec: Add V4L2 Request API hevc hwaccel Add a V4L2 Request API hwaccel for HEVC, supporting both slice and frame decoding modes. @@ -3534,15 +3705,15 @@ Signed-off-by: Jonas Karlman libavcodec/Makefile | 1 + libavcodec/hevc/hevcdec.c | 10 + libavcodec/hwaccels.h | 1 + - libavcodec/v4l2_request_hevc.c | 745 +++++++++++++++++++++++++++++++++ - 5 files changed, 762 insertions(+) + libavcodec/v4l2_request_hevc.c | 752 +++++++++++++++++++++++++++++++++ + 5 files changed, 769 insertions(+) create mode 100644 libavcodec/v4l2_request_hevc.c diff --git a/configure b/configure -index 6866a61153..7a2901d960 100755 +index 0bfd84358d3e..f86e5a3597ef 100755 --- a/configure +++ b/configure -@@ -2491,6 +2491,7 @@ TYPES_LIST=" +@@ -2645,6 +2645,7 @@ TYPES_LIST=" struct_sockaddr_sa_len struct_sockaddr_storage struct_stat_st_mtim_tv_nsec @@ -3550,7 +3721,7 @@ index 6866a61153..7a2901d960 100755 struct_v4l2_frmivalenum_discrete struct_mfxConfigInterface " -@@ -3206,6 +3207,8 @@ hevc_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_HEVC" +@@ -3408,6 +3409,8 @@ hevc_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_HEVC" hevc_dxva2_hwaccel_select="hevc_decoder" hevc_nvdec_hwaccel_deps="nvdec" hevc_nvdec_hwaccel_select="hevc_decoder" @@ -3559,7 +3730,7 @@ index 6866a61153..7a2901d960 100755 hevc_vaapi_hwaccel_deps="vaapi VAPictureParameterBufferHEVC" hevc_vaapi_hwaccel_select="hevc_decoder" hevc_vdpau_hwaccel_deps="vdpau VdpPictureInfoHEVC" -@@ -7207,10 +7210,12 @@ fi +@@ -7599,10 +7602,12 @@ fi if enabled v4l2_request; then check_cc h264_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_H264_DECODE_MODE" @@ -3569,14 +3740,14 @@ index 6866a61153..7a2901d960 100755 check_func_headers "linux/media.h linux/videodev2.h" v4l2_timeval_to_ns check_pkg_config libudev libudev libudev.h udev_new + check_struct linux/videodev2.h "struct v4l2_ctrl_hevc_decode_params" num_delta_pocs_of_ref_rps_idx + v4l2_request_extralibs="$libudev_extralibs" fi - check_headers sys/videoio.h diff --git a/libavcodec/Makefile b/libavcodec/Makefile -index 00bc1cf8f2..fa78523b76 100644 +index 7b5653df8854..1605237f14c9 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile -@@ -1027,6 +1027,7 @@ OBJS-$(CONFIG_HEVC_DXVA2_HWACCEL) += dxva2_hevc.o +@@ -1074,6 +1074,7 @@ OBJS-$(CONFIG_HEVC_DXVA2_HWACCEL) += dxva2_hevc.o OBJS-$(CONFIG_HEVC_D3D12VA_HWACCEL) += dxva2_hevc.o d3d12va_hevc.o OBJS-$(CONFIG_HEVC_NVDEC_HWACCEL) += nvdec_hevc.o OBJS-$(CONFIG_HEVC_QSV_HWACCEL) += qsvdec.o @@ -3585,10 +3756,10 @@ index 00bc1cf8f2..fa78523b76 100644 OBJS-$(CONFIG_HEVC_VDPAU_HWACCEL) += vdpau_hevc.o h265_profile_level.o OBJS-$(CONFIG_HEVC_VULKAN_HWACCEL) += vulkan_decode.o vulkan_hevc.o diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c -index 0dc24f82f8..4b14a931a2 100644 +index ae5f0fe69d89..647251e6f024 100644 --- a/libavcodec/hevc/hevcdec.c +++ b/libavcodec/hevc/hevcdec.c -@@ -527,6 +527,7 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) +@@ -580,6 +580,7 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) CONFIG_HEVC_D3D11VA_HWACCEL * 2 + \ CONFIG_HEVC_D3D12VA_HWACCEL + \ CONFIG_HEVC_NVDEC_HWACCEL + \ @@ -3596,7 +3767,7 @@ index 0dc24f82f8..4b14a931a2 100644 CONFIG_HEVC_VAAPI_HWACCEL + \ CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL + \ CONFIG_HEVC_VDPAU_HWACCEL + \ -@@ -561,6 +562,9 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) +@@ -618,6 +619,9 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) #endif #if CONFIG_HEVC_VULKAN_HWACCEL *fmt++ = AV_PIX_FMT_VULKAN; @@ -3606,7 +3777,7 @@ index 0dc24f82f8..4b14a931a2 100644 #endif break; case AV_PIX_FMT_YUV420P10: -@@ -588,6 +592,9 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) +@@ -645,6 +649,9 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) #endif #if CONFIG_HEVC_NVDEC_HWACCEL *fmt++ = AV_PIX_FMT_CUDA; @@ -3616,7 +3787,7 @@ index 0dc24f82f8..4b14a931a2 100644 #endif break; case AV_PIX_FMT_YUV444P: -@@ -4107,6 +4114,9 @@ const FFCodec ff_hevc_decoder = { +@@ -4280,6 +4287,9 @@ const FFCodec ff_hevc_decoder = { #endif #if CONFIG_HEVC_VULKAN_HWACCEL HWACCEL_VULKAN(hevc), @@ -3627,10 +3798,10 @@ index 0dc24f82f8..4b14a931a2 100644 NULL }, diff --git a/libavcodec/hwaccels.h b/libavcodec/hwaccels.h -index 024e021d73..ad145fc07c 100644 +index 052153465feb..f4bad689130e 100644 --- a/libavcodec/hwaccels.h +++ b/libavcodec/hwaccels.h -@@ -44,6 +44,7 @@ extern const struct FFHWAccel ff_hevc_d3d11va2_hwaccel; +@@ -47,6 +47,7 @@ extern const struct FFHWAccel ff_hevc_d3d11va2_hwaccel; extern const struct FFHWAccel ff_hevc_d3d12va_hwaccel; extern const struct FFHWAccel ff_hevc_dxva2_hwaccel; extern const struct FFHWAccel ff_hevc_nvdec_hwaccel; @@ -3640,10 +3811,10 @@ index 024e021d73..ad145fc07c 100644 extern const struct FFHWAccel ff_hevc_videotoolbox_hwaccel; diff --git a/libavcodec/v4l2_request_hevc.c b/libavcodec/v4l2_request_hevc.c new file mode 100644 -index 0000000000..9fabe468b7 +index 000000000000..26cba2c75f43 --- /dev/null +++ b/libavcodec/v4l2_request_hevc.c -@@ -0,0 +1,745 @@ +@@ -0,0 +1,752 @@ +/* + * This file is part of FFmpeg. + * @@ -3822,7 +3993,8 @@ index 0000000000..9fabe468b7 +} + +static int fill_slice_params(V4L2RequestControlsHEVC *controls, int slice, -+ bool max_entry_point_offsets, const HEVCContext *h) ++ uint32_t size, bool max_entry_point_offsets, ++ const HEVCContext *h) +{ + struct v4l2_ctrl_hevc_slice_params *slice_params = &controls->frame_slice_params[slice]; + struct v4l2_ctrl_hevc_decode_params *decode_params = &controls->decode_params; @@ -3831,8 +4003,8 @@ index 0000000000..9fabe468b7 + int i, offsets; + + *slice_params = (struct v4l2_ctrl_hevc_slice_params) { -+ .bit_size = 0, -+ .data_byte_offset = controls->pic.output->used + sh->data_offset, ++ .bit_size = (size - sh->data_offset) * 8, ++ .data_byte_offset = controls->pic.output->bytesused + sh->data_offset, + .num_entry_point_offsets = sh->num_entry_point_offsets, + + /* ISO/IEC 23008-2, ITU-T Rec. H.265: NAL unit header */ @@ -3999,469 +4171,820 @@ index 0000000000..9fabe468b7 + if (sps->long_term_ref_pics_present) + ctrl->flags |= V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT; + -+ if (sps->temporal_mvp_enabled) -+ ctrl->flags |= V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED; ++ if (sps->temporal_mvp_enabled) ++ ctrl->flags |= V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED; ++ ++ if (sps->strong_intra_smoothing_enabled) ++ ctrl->flags |= V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED; ++} ++ ++static int v4l2_request_hevc_start_frame(AVCodecContext *avctx, ++ av_unused const AVBufferRef *buf_ref, ++ av_unused const uint8_t *buffer, ++ av_unused uint32_t size) ++{ ++ const HEVCContext *h = avctx->priv_data; ++ const HEVCPPS *pps = h->pps; ++ const HEVCSPS *sps = pps->sps; ++ V4L2RequestContextHEVC *ctx = avctx->internal->hwaccel_priv_data; ++ V4L2RequestControlsHEVC *controls = h->cur_frame->hwaccel_picture_private; ++ const SliceHeader *sh = &h->sh; ++ int ret; ++ ++ ret = ff_v4l2_request_start_frame(avctx, &controls->pic, h->cur_frame->f); ++ if (ret) ++ return ret; ++ ++ fill_sps(&controls->sps, h); ++ fill_decode_params(&controls->decode_params, h); ++ ++ if (ctx->has_scaling_matrix) { ++ const ScalingList *sl = pps->scaling_list_data_present_flag ? ++ &pps->scaling_list : ++ sps->scaling_list_enabled ? ++ &sps->scaling_list : NULL; ++ if (sl) { ++ for (int i = 0; i < 6; i++) { ++ for (int j = 0; j < 16; j++) ++ controls->scaling_matrix.scaling_list_4x4[i][j] = sl->sl[0][i][j]; ++ for (int j = 0; j < 64; j++) { ++ controls->scaling_matrix.scaling_list_8x8[i][j] = sl->sl[1][i][j]; ++ controls->scaling_matrix.scaling_list_16x16[i][j] = sl->sl[2][i][j]; ++ if (i < 2) ++ controls->scaling_matrix.scaling_list_32x32[i][j] = sl->sl[3][i * 3][j]; ++ } ++ controls->scaling_matrix.scaling_list_dc_coef_16x16[i] = sl->sl_dc[0][i]; ++ if (i < 2) ++ controls->scaling_matrix.scaling_list_dc_coef_32x32[i] = sl->sl_dc[1][i * 3]; ++ } ++ } ++ } ++ ++ /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture parameter set */ ++ controls->pps = (struct v4l2_ctrl_hevc_pps) { ++ .pic_parameter_set_id = sh->pps_id, ++ .num_extra_slice_header_bits = pps->num_extra_slice_header_bits, ++ .num_ref_idx_l0_default_active_minus1 = pps->num_ref_idx_l0_default_active - 1, ++ .num_ref_idx_l1_default_active_minus1 = pps->num_ref_idx_l1_default_active - 1, ++ .init_qp_minus26 = pps->pic_init_qp_minus26, ++ .diff_cu_qp_delta_depth = pps->diff_cu_qp_delta_depth, ++ .pps_cb_qp_offset = pps->cb_qp_offset, ++ .pps_cr_qp_offset = pps->cr_qp_offset, ++ .pps_beta_offset_div2 = pps->beta_offset / 2, ++ .pps_tc_offset_div2 = pps->tc_offset / 2, ++ .log2_parallel_merge_level_minus2 = pps->log2_parallel_merge_level - 2, ++ }; ++ ++ if (pps->dependent_slice_segments_enabled_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED; ++ ++ if (pps->output_flag_present_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT; ++ ++ if (pps->sign_data_hiding_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED; ++ ++ if (pps->cabac_init_present_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT; ++ ++ if (pps->constrained_intra_pred_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED; ++ ++ if (pps->transform_skip_enabled_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED; ++ ++ if (pps->cu_qp_delta_enabled_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED; ++ ++ if (pps->pic_slice_level_chroma_qp_offsets_present_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT; ++ ++ if (pps->weighted_pred_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED; ++ ++ if (pps->weighted_bipred_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED; ++ ++ if (pps->transquant_bypass_enable_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED; ++ ++ if (pps->tiles_enabled_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_TILES_ENABLED; ++ ++ if (pps->entropy_coding_sync_enabled_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED; ++ ++ if (pps->loop_filter_across_tiles_enabled_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED; ++ ++ if (pps->seq_loop_filter_across_slices_enabled_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED; ++ ++ if (pps->deblocking_filter_override_enabled_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED; ++ ++ if (pps->disable_dbf) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER; ++ ++ if (pps->lists_modification_present_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT; ++ ++ if (pps->slice_header_extension_present_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT; ++ ++ if (pps->deblocking_filter_control_present_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT; ++ ++ if (pps->uniform_spacing_flag) ++ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING; ++ ++ if (pps->tiles_enabled_flag) { ++ controls->pps.num_tile_columns_minus1 = pps->num_tile_columns - 1; ++ controls->pps.num_tile_rows_minus1 = pps->num_tile_rows - 1; ++ ++ for (int i = 0; i < pps->num_tile_columns; i++) ++ controls->pps.column_width_minus1[i] = pps->column_width[i] - 1; ++ ++ for (int i = 0; i < pps->num_tile_rows; i++) ++ controls->pps.row_height_minus1[i] = pps->row_height[i] - 1; ++ } ++ ++ controls->first_slice = true; ++ controls->frame_slice_params = &controls->slice_params; ++ controls->allocated_slice_params = 0; ++ controls->num_slice_params = 0; ++ controls->allocated_entry_point_offsets = 0; ++ controls->num_entry_point_offsets = 0; ++ ++ return 0; ++} ++ ++static int v4l2_request_hevc_queue_decode(AVCodecContext *avctx, bool last_slice) ++{ ++ const HEVCContext *h = avctx->priv_data; ++ V4L2RequestContextHEVC *ctx = avctx->internal->hwaccel_priv_data; ++ V4L2RequestControlsHEVC *controls = h->cur_frame->hwaccel_picture_private; ++ int count = 0; ++ ++ struct v4l2_ext_control control[V4L2_HEVC_CONTROLS_MAX] = {}; ++ ++ control[count++] = (struct v4l2_ext_control) { ++ .id = V4L2_CID_STATELESS_HEVC_SPS, ++ .ptr = &controls->sps, ++ .size = sizeof(controls->sps), ++ }; ++ ++ control[count++] = (struct v4l2_ext_control) { ++ .id = V4L2_CID_STATELESS_HEVC_PPS, ++ .ptr = &controls->pps, ++ .size = sizeof(controls->pps), ++ }; ++ ++ control[count++] = (struct v4l2_ext_control) { ++ .id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS, ++ .ptr = &controls->decode_params, ++ .size = sizeof(controls->decode_params), ++ }; ++ ++ if (ctx->has_scaling_matrix) { ++ control[count++] = (struct v4l2_ext_control) { ++ .id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX, ++ .ptr = &controls->scaling_matrix, ++ .size = sizeof(controls->scaling_matrix), ++ }; ++ } ++ ++ if (ctx->max_slice_params && controls->num_slice_params) { ++ control[count++] = (struct v4l2_ext_control) { ++ .id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS, ++ .ptr = controls->frame_slice_params, ++ .size = sizeof(*controls->frame_slice_params) * ++ FFMIN(controls->num_slice_params, ctx->max_slice_params), ++ }; ++ } ++ ++ if (ctx->max_entry_point_offsets && controls->num_entry_point_offsets) { ++ control[count++] = (struct v4l2_ext_control) { ++ .id = V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS, ++ .ptr = controls->entry_point_offsets, ++ .size = sizeof(*controls->entry_point_offsets) * ++ FFMIN(controls->num_entry_point_offsets, ++ ctx->max_entry_point_offsets), ++ }; ++ } ++ ++ if (ctx->decode_mode == V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED) ++ return ff_v4l2_request_decode_slice(avctx, &controls->pic, control, count, ++ controls->first_slice, last_slice); + -+ if (sps->strong_intra_smoothing_enabled) -+ ctrl->flags |= V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED; ++ return ff_v4l2_request_decode_frame(avctx, &controls->pic, control, count); +} + -+static int v4l2_request_hevc_start_frame(AVCodecContext *avctx, -+ av_unused const uint8_t *buffer, -+ av_unused uint32_t size) ++static int v4l2_request_hevc_decode_slice(AVCodecContext *avctx, ++ const uint8_t *buffer, uint32_t size) +{ + const HEVCContext *h = avctx->priv_data; -+ const HEVCPPS *pps = h->pps; -+ const HEVCSPS *sps = pps->sps; + V4L2RequestContextHEVC *ctx = avctx->internal->hwaccel_priv_data; + V4L2RequestControlsHEVC *controls = h->cur_frame->hwaccel_picture_private; + const SliceHeader *sh = &h->sh; -+ int ret; ++ int ret, slice = controls->num_slice_params; + -+ ret = ff_v4l2_request_start_frame(avctx, &controls->pic, h->cur_frame->f); -+ if (ret) -+ return ret; ++ if (ctx->decode_mode == V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED && ++ (slice >= ctx->max_slice_params || (ctx->max_entry_point_offsets && ++ (controls->num_entry_point_offsets + sh->num_entry_point_offsets > ctx->max_entry_point_offsets)))) { ++ ret = v4l2_request_hevc_queue_decode(avctx, false); ++ if (ret) ++ return ret; + -+ fill_sps(&controls->sps, h); -+ fill_decode_params(&controls->decode_params, h); ++ ff_v4l2_request_reset_picture(avctx, &controls->pic); ++ slice = controls->num_slice_params = 0; ++ controls->num_entry_point_offsets = 0; ++ controls->first_slice = false; ++ } + -+ if (ctx->has_scaling_matrix) { -+ const ScalingList *sl = pps->scaling_list_data_present_flag ? -+ &pps->scaling_list : -+ sps->scaling_list_enabled ? -+ &sps->scaling_list : NULL; -+ if (sl) { -+ for (int i = 0; i < 6; i++) { -+ for (int j = 0; j < 16; j++) -+ controls->scaling_matrix.scaling_list_4x4[i][j] = sl->sl[0][i][j]; -+ for (int j = 0; j < 64; j++) { -+ controls->scaling_matrix.scaling_list_8x8[i][j] = sl->sl[1][i][j]; -+ controls->scaling_matrix.scaling_list_16x16[i][j] = sl->sl[2][i][j]; -+ if (i < 2) -+ controls->scaling_matrix.scaling_list_32x32[i][j] = sl->sl[3][i * 3][j]; -+ } -+ controls->scaling_matrix.scaling_list_dc_coef_16x16[i] = sl->sl_dc[0][i]; -+ if (i < 2) -+ controls->scaling_matrix.scaling_list_dc_coef_32x32[i] = sl->sl_dc[1][i * 3]; -+ } ++ if (ctx->start_code == V4L2_STATELESS_HEVC_START_CODE_ANNEX_B) { ++ ret = ff_v4l2_request_append_output(avctx, &controls->pic, ++ nalu_slice_start_code, 3); ++ if (ret) ++ return ret; ++ } ++ ++ if (ctx->max_slice_params) { ++ if (slice && controls->allocated_slice_params < slice + 1) { ++ void *slice_params = controls->allocated_slice_params == 0 ? NULL : controls->frame_slice_params; ++ int slices = controls->allocated_slice_params == 0 ? 8 : controls->allocated_slice_params * 2; ++ slice_params = av_realloc_array(slice_params, slices, sizeof(*controls->frame_slice_params)); ++ if (!slice_params) ++ return AVERROR(ENOMEM); ++ if (controls->allocated_slice_params == 0) ++ memcpy(slice_params, controls->frame_slice_params, sizeof(*controls->frame_slice_params)); ++ controls->frame_slice_params = slice_params; ++ controls->allocated_slice_params = slices; + } ++ ++ ret = fill_slice_params(controls, slice, size, ++ !!ctx->max_entry_point_offsets, h); ++ if (ret) ++ return ret; + } + -+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture parameter set */ -+ controls->pps = (struct v4l2_ctrl_hevc_pps) { -+ .pic_parameter_set_id = sh->pps_id, -+ .num_extra_slice_header_bits = pps->num_extra_slice_header_bits, -+ .num_ref_idx_l0_default_active_minus1 = pps->num_ref_idx_l0_default_active - 1, -+ .num_ref_idx_l1_default_active_minus1 = pps->num_ref_idx_l1_default_active - 1, -+ .init_qp_minus26 = pps->pic_init_qp_minus26, -+ .diff_cu_qp_delta_depth = pps->diff_cu_qp_delta_depth, -+ .pps_cb_qp_offset = pps->cb_qp_offset, -+ .pps_cr_qp_offset = pps->cr_qp_offset, -+ .pps_beta_offset_div2 = pps->beta_offset / 2, -+ .pps_tc_offset_div2 = pps->tc_offset / 2, -+ .log2_parallel_merge_level_minus2 = pps->log2_parallel_merge_level - 2, -+ }; ++ ret = ff_v4l2_request_append_output(avctx, &controls->pic, buffer, size); ++ if (ret) ++ return ret; + -+ if (pps->dependent_slice_segments_enabled_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED; ++ controls->num_slice_params++; ++ return 0; ++} + -+ if (pps->output_flag_present_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT; ++static int v4l2_request_hevc_end_frame(AVCodecContext *avctx) ++{ ++ return v4l2_request_hevc_queue_decode(avctx, true); ++} + -+ if (pps->sign_data_hiding_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED; ++static void v4l2_request_hevc_free_frame_priv(AVRefStructOpaque hwctx, void *data) ++{ ++ V4L2RequestControlsHEVC *controls = data; + -+ if (pps->cabac_init_present_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT; ++ if (controls->allocated_slice_params) ++ av_freep(&controls->frame_slice_params); + -+ if (pps->constrained_intra_pred_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED; ++ av_freep(&controls->entry_point_offsets); ++} + -+ if (pps->transform_skip_enabled_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED; ++static int v4l2_request_hevc_post_frames_ctx(AVCodecContext *avctx) ++{ ++ V4L2RequestContextHEVC *ctx = avctx->internal->hwaccel_priv_data; ++ int ret; + -+ if (pps->cu_qp_delta_enabled_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED; ++ struct v4l2_ext_control control[] = { ++ { .id = V4L2_CID_STATELESS_HEVC_DECODE_MODE, }, ++ { .id = V4L2_CID_STATELESS_HEVC_START_CODE, }, ++ }; ++ struct v4l2_query_ext_ctrl scaling_matrix = { ++ .id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX, ++ }; ++ struct v4l2_query_ext_ctrl entry_point_offsets = { ++ .id = V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS, ++ }; ++ struct v4l2_query_ext_ctrl slice_params = { ++ .id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS, ++ }; + -+ if (pps->pic_slice_level_chroma_qp_offsets_present_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT; ++ ctx->decode_mode = ff_v4l2_request_query_control_default_value(avctx, ++ V4L2_CID_STATELESS_HEVC_DECODE_MODE); ++ if (ctx->decode_mode != V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED && ++ ctx->decode_mode != V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED) { ++ av_log(ctx, AV_LOG_VERBOSE, "Unsupported decode mode: %d\n", ++ ctx->decode_mode); ++ return AVERROR(EINVAL); ++ } + -+ if (pps->weighted_pred_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED; ++ ctx->start_code = ff_v4l2_request_query_control_default_value(avctx, ++ V4L2_CID_STATELESS_HEVC_START_CODE); ++ if (ctx->start_code != V4L2_STATELESS_HEVC_START_CODE_NONE && ++ ctx->start_code != V4L2_STATELESS_HEVC_START_CODE_ANNEX_B) { ++ av_log(ctx, AV_LOG_VERBOSE, "Unsupported start code: %d\n", ++ ctx->start_code); ++ return AVERROR(EINVAL); ++ } + -+ if (pps->weighted_bipred_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED; ++ // TODO: check V4L2_CID_MPEG_VIDEO_HEVC_PROFILE control ++ // TODO: check V4L2_CID_MPEG_VIDEO_HEVC_LEVEL control + -+ if (pps->transquant_bypass_enable_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED; ++ ret = ff_v4l2_request_query_control(avctx, &scaling_matrix); ++ if (!ret) ++ ctx->has_scaling_matrix = true; ++ else ++ ctx->has_scaling_matrix = false; + -+ if (pps->tiles_enabled_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_TILES_ENABLED; ++ ret = ff_v4l2_request_query_control(avctx, &entry_point_offsets); ++ if (!ret) ++ ctx->max_entry_point_offsets = FFMAX(entry_point_offsets.dims[0], 1); ++ else ++ ctx->max_entry_point_offsets = 0; + -+ if (pps->entropy_coding_sync_enabled_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED; ++ ret = ff_v4l2_request_query_control(avctx, &slice_params); ++ if (!ret) ++ ctx->max_slice_params = FFMAX(slice_params.dims[0], 1); ++ else ++ ctx->max_slice_params = 0; + -+ if (pps->loop_filter_across_tiles_enabled_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED; ++ av_log(ctx, AV_LOG_VERBOSE, "%s-based decoder with SLICE_PARAMS=%u, " ++ "ENTRY_POINT_OFFSETS=%u and SCALING_MATRIX=%d controls\n", ++ ctx->decode_mode == V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED ? "slice" : "frame", ++ ctx->max_slice_params, ctx->max_entry_point_offsets, ctx->has_scaling_matrix); + -+ if (pps->seq_loop_filter_across_slices_enabled_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED; ++ control[0].value = ctx->decode_mode; ++ control[1].value = ctx->start_code; + -+ if (pps->deblocking_filter_override_enabled_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED; ++ return ff_v4l2_request_set_controls(avctx, control, FF_ARRAY_ELEMS(control)); ++} + -+ if (pps->disable_dbf) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER; ++static int v4l2_request_hevc_init(AVCodecContext *avctx) ++{ ++ const HEVCContext *h = avctx->priv_data; ++ struct v4l2_ctrl_hevc_sps sps; + -+ if (pps->lists_modification_present_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT; ++ struct v4l2_ext_control control[] = { ++ { ++ .id = V4L2_CID_STATELESS_HEVC_SPS, ++ .ptr = &sps, ++ .size = sizeof(sps), ++ }, ++ }; + -+ if (pps->slice_header_extension_present_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT; ++ fill_sps(&sps, h); ++ ++ return ff_v4l2_request_init(avctx, control, FF_ARRAY_ELEMS(control), ++ v4l2_request_hevc_post_frames_ctx); ++} ++ ++static int v4l2_request_hevc_frame_params(AVCodecContext *avctx, ++ AVBufferRef *hw_frames_ctx) ++{ ++ const HEVCContext *h = avctx->priv_data; ++ const HEVCSPS *sps = h && h->pps ? h->pps->sps : NULL; ++ uint8_t bit_depth = sps ? sps->bit_depth : 0; ++ ++ return ff_v4l2_request_frame_params(avctx, hw_frames_ctx, ++ V4L2_PIX_FMT_HEVC_SLICE, bit_depth); ++} ++ ++const FFHWAccel ff_hevc_v4l2request_hwaccel = { ++ .p.name = "hevc_v4l2request", ++ .p.type = AVMEDIA_TYPE_VIDEO, ++ .p.id = AV_CODEC_ID_HEVC, ++ .p.pix_fmt = AV_PIX_FMT_DRM_PRIME, ++ .start_frame = v4l2_request_hevc_start_frame, ++ .decode_slice = v4l2_request_hevc_decode_slice, ++ .end_frame = v4l2_request_hevc_end_frame, ++ .flush = ff_v4l2_request_flush, ++ .free_frame_priv = v4l2_request_hevc_free_frame_priv, ++ .frame_priv_data_size = sizeof(V4L2RequestControlsHEVC), ++ .init = v4l2_request_hevc_init, ++ .uninit = ff_v4l2_request_uninit, ++ .priv_data_size = sizeof(V4L2RequestContextHEVC), ++ .frame_params = v4l2_request_hevc_frame_params, ++ .caps_internal = HWACCEL_CAP_ASYNC_SAFE, ++}; + +From 6724bfac7fd7c8b3fa31233983ac6979d0c3954d Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Wed, 22 May 2019 14:46:58 +0200 +Subject: [PATCH 09/13] avcodec: Add V4L2 Request API vp8 hwaccel + +Add a V4L2 Request API hwaccel for VP8. + +Support for VP8 is enabled when Linux kernel headers declare the +control id V4L2_CID_STATELESS_VP8_FRAME, added in v5.13. + +Co-developed-by: Ezequiel Garcia +Signed-off-by: Ezequiel Garcia +Signed-off-by: Boris Brezillon +Co-developed-by: Jonas Karlman +Signed-off-by: Jonas Karlman +--- + configure | 3 + + libavcodec/Makefile | 1 + + libavcodec/hwaccels.h | 1 + + libavcodec/v4l2_request_vp8.c | 242 ++++++++++++++++++++++++++++++++++ + libavcodec/vp8.c | 6 + + 5 files changed, 253 insertions(+) + create mode 100644 libavcodec/v4l2_request_vp8.c + +diff --git a/configure b/configure +index f86e5a3597ef..3546fffa5233 100755 +--- a/configure ++++ b/configure +@@ -3477,6 +3477,8 @@ vc1_vdpau_hwaccel_deps="vdpau" + vc1_vdpau_hwaccel_select="vc1_decoder" + vp8_nvdec_hwaccel_deps="nvdec" + vp8_nvdec_hwaccel_select="vp8_decoder" ++vp8_v4l2request_hwaccel_deps="v4l2_request vp8_v4l2_request" ++vp8_v4l2request_hwaccel_select="vp8_decoder" + vp8_vaapi_hwaccel_deps="vaapi" + vp8_vaapi_hwaccel_select="vp8_decoder" + vp9_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_VP9" +@@ -7605,6 +7607,7 @@ if enabled v4l2_request; then + check_cc hevc_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_HEVC_SPS" + check_cc mpeg2_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_MPEG2_SEQUENCE" + check_cc v4l2_m2m_hold_capture_buf linux/videodev2.h "int i = V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF" ++ check_cc vp8_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_VP8_FRAME" + check_func_headers "linux/media.h linux/videodev2.h" v4l2_timeval_to_ns + check_pkg_config libudev libudev libudev.h udev_new + check_struct linux/videodev2.h "struct v4l2_ctrl_hevc_decode_params" num_delta_pocs_of_ref_rps_idx +diff --git a/libavcodec/Makefile b/libavcodec/Makefile +index 1605237f14c9..5eee5e92a264 100644 +--- a/libavcodec/Makefile ++++ b/libavcodec/Makefile +@@ -1104,6 +1104,7 @@ OBJS-$(CONFIG_VC1_QSV_HWACCEL) += qsvdec.o + OBJS-$(CONFIG_VC1_VAAPI_HWACCEL) += vaapi_vc1.o + OBJS-$(CONFIG_VC1_VDPAU_HWACCEL) += vdpau_vc1.o + OBJS-$(CONFIG_VP8_NVDEC_HWACCEL) += nvdec_vp8.o ++OBJS-$(CONFIG_VP8_V4L2REQUEST_HWACCEL) += v4l2_request_vp8.o + OBJS-$(CONFIG_VP8_VAAPI_HWACCEL) += vaapi_vp8.o + OBJS-$(CONFIG_VP9_D3D11VA_HWACCEL) += dxva2_vp9.o + OBJS-$(CONFIG_VP9_DXVA2_HWACCEL) += dxva2_vp9.o +diff --git a/libavcodec/hwaccels.h b/libavcodec/hwaccels.h +index f4bad689130e..e60ec2a49878 100644 +--- a/libavcodec/hwaccels.h ++++ b/libavcodec/hwaccels.h +@@ -81,6 +81,7 @@ extern const struct FFHWAccel ff_vc1_nvdec_hwaccel; + extern const struct FFHWAccel ff_vc1_vaapi_hwaccel; + extern const struct FFHWAccel ff_vc1_vdpau_hwaccel; + extern const struct FFHWAccel ff_vp8_nvdec_hwaccel; ++extern const struct FFHWAccel ff_vp8_v4l2request_hwaccel; + extern const struct FFHWAccel ff_vp8_vaapi_hwaccel; + extern const struct FFHWAccel ff_vp9_d3d11va_hwaccel; + extern const struct FFHWAccel ff_vp9_d3d11va2_hwaccel; +diff --git a/libavcodec/v4l2_request_vp8.c b/libavcodec/v4l2_request_vp8.c +new file mode 100644 +index 000000000000..3fb23951dff1 +--- /dev/null ++++ b/libavcodec/v4l2_request_vp8.c +@@ -0,0 +1,242 @@ ++/* ++ * 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 ++ */ + -+ if (pps->deblocking_filter_control_present_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT; ++#include "config.h" + -+ if (pps->uniform_spacing_flag) -+ controls->pps.flags |= V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING; ++#include "hwaccel_internal.h" ++#include "hwconfig.h" ++#include "v4l2_request.h" ++#include "vp8.h" + -+ if (pps->tiles_enabled_flag) { -+ controls->pps.num_tile_columns_minus1 = pps->num_tile_columns - 1; -+ controls->pps.num_tile_rows_minus1 = pps->num_tile_rows - 1; ++typedef struct V4L2RequestControlsVP8 { ++ V4L2RequestPictureContext pic; ++ struct v4l2_ctrl_vp8_frame frame; ++} V4L2RequestControlsVP8; + -+ for (int i = 0; i < pps->num_tile_columns; i++) -+ controls->pps.column_width_minus1[i] = pps->column_width[i] - 1; ++static int v4l2_request_vp8_start_frame(AVCodecContext *avctx, ++ av_unused const AVBufferRef *buf_ref, ++ const uint8_t *buffer, ++ av_unused uint32_t size) ++{ ++ const VP8Context *s = avctx->priv_data; ++ V4L2RequestControlsVP8 *controls = s->framep[VP8_FRAME_CURRENT]->hwaccel_picture_private; ++ struct v4l2_ctrl_vp8_frame *ctrl = &controls->frame; ++ unsigned int header_size = 3 + 7 * s->keyframe; ++ const uint8_t *data = buffer + header_size; ++ int ret, i, j, k; + -+ for (int i = 0; i < pps->num_tile_rows; i++) -+ controls->pps.row_height_minus1[i] = pps->row_height[i] - 1; -+ } ++ ret = ff_v4l2_request_start_frame(avctx, &controls->pic, ++ s->framep[VP8_FRAME_CURRENT]->tf.f); ++ if (ret) ++ return ret; + -+ controls->first_slice = true; -+ controls->frame_slice_params = &controls->slice_params; -+ controls->allocated_slice_params = 0; -+ controls->num_slice_params = 0; -+ controls->allocated_entry_point_offsets = 0; -+ controls->num_entry_point_offsets = 0; ++ *ctrl = (struct v4l2_ctrl_vp8_frame) { ++ .lf = { ++ .sharpness_level = s->filter.sharpness, ++ .level = s->filter.level, ++ }, + -+ return 0; -+} ++ .quant = { ++ .y_ac_qi = s->quant.yac_qi, ++ .y_dc_delta = s->quant.ydc_delta, ++ .y2_dc_delta = s->quant.y2dc_delta, ++ .y2_ac_delta = s->quant.y2ac_delta, ++ .uv_dc_delta = s->quant.uvdc_delta, ++ .uv_ac_delta = s->quant.uvac_delta, ++ }, + -+static int v4l2_request_hevc_queue_decode(AVCodecContext *avctx, bool last_slice) -+{ -+ const HEVCContext *h = avctx->priv_data; -+ V4L2RequestContextHEVC *ctx = avctx->internal->hwaccel_priv_data; -+ V4L2RequestControlsHEVC *controls = h->cur_frame->hwaccel_picture_private; -+ int count = 0; ++ .coder_state = { ++ .range = s->coder_state_at_header_end.range, ++ .value = s->coder_state_at_header_end.value, ++ .bit_count = s->coder_state_at_header_end.bit_count, ++ }, + -+ struct v4l2_ext_control control[V4L2_HEVC_CONTROLS_MAX] = {}; ++ .width = avctx->width, ++ .height = avctx->height, + -+ control[count++] = (struct v4l2_ext_control) { -+ .id = V4L2_CID_STATELESS_HEVC_SPS, -+ .ptr = &controls->sps, -+ .size = sizeof(controls->sps), -+ }; ++ .horizontal_scale = 0, /* scale not supported by FFmpeg */ ++ .vertical_scale = 0, /* scale not supported by FFmpeg */ + -+ control[count++] = (struct v4l2_ext_control) { -+ .id = V4L2_CID_STATELESS_HEVC_PPS, -+ .ptr = &controls->pps, -+ .size = sizeof(controls->pps), -+ }; ++ .version = s->profile & 0x3, ++ .prob_skip_false = s->prob->mbskip, ++ .prob_intra = s->prob->intra, ++ .prob_last = s->prob->last, ++ .prob_gf = s->prob->golden, ++ .num_dct_parts = s->num_coeff_partitions, + -+ control[count++] = (struct v4l2_ext_control) { -+ .id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS, -+ .ptr = &controls->decode_params, -+ .size = sizeof(controls->decode_params), ++ .first_part_size = s->header_partition_size, ++ .first_part_header_bits = (8 * (s->coder_state_at_header_end.input - data) - ++ s->coder_state_at_header_end.bit_count - 8), + }; + -+ if (ctx->has_scaling_matrix) { -+ control[count++] = (struct v4l2_ext_control) { -+ .id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX, -+ .ptr = &controls->scaling_matrix, -+ .size = sizeof(controls->scaling_matrix), -+ }; -+ } -+ -+ if (ctx->max_slice_params && controls->num_slice_params) { -+ control[count++] = (struct v4l2_ext_control) { -+ .id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS, -+ .ptr = controls->frame_slice_params, -+ .size = sizeof(*controls->frame_slice_params) * -+ FFMIN(controls->num_slice_params, ctx->max_slice_params), -+ }; -+ } -+ -+ if (ctx->max_entry_point_offsets && controls->num_entry_point_offsets) { -+ control[count++] = (struct v4l2_ext_control) { -+ .id = V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS, -+ .ptr = controls->entry_point_offsets, -+ .size = sizeof(*controls->entry_point_offsets) * -+ FFMIN(controls->num_entry_point_offsets, -+ ctx->max_entry_point_offsets), -+ }; ++ for (i = 0; i < 4; i++) { ++ ctrl->segment.quant_update[i] = s->segmentation.base_quant[i]; ++ ctrl->segment.lf_update[i] = s->segmentation.filter_level[i]; + } + -+ if (ctx->decode_mode == V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED) -+ return ff_v4l2_request_decode_slice(avctx, &controls->pic, control, count, -+ controls->first_slice, last_slice); -+ -+ return ff_v4l2_request_decode_frame(avctx, &controls->pic, control, count); -+} -+ -+static int v4l2_request_hevc_decode_slice(AVCodecContext *avctx, -+ const uint8_t *buffer, uint32_t size) -+{ -+ const HEVCContext *h = avctx->priv_data; -+ V4L2RequestContextHEVC *ctx = avctx->internal->hwaccel_priv_data; -+ V4L2RequestControlsHEVC *controls = h->cur_frame->hwaccel_picture_private; -+ const SliceHeader *sh = &h->sh; -+ int ret, slice = controls->num_slice_params; -+ uint32_t extra_size = 0; ++ for (i = 0; i < 3; i++) ++ ctrl->segment.segment_probs[i] = s->prob->segmentid[i]; + -+ if (ctx->decode_mode == V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED && -+ (slice >= ctx->max_slice_params || (ctx->max_entry_point_offsets && -+ (controls->num_entry_point_offsets + sh->num_entry_point_offsets > ctx->max_entry_point_offsets)))) { -+ ret = v4l2_request_hevc_queue_decode(avctx, false); -+ if (ret) -+ return ret; ++ if (s->segmentation.enabled) ++ ctrl->segment.flags |= V4L2_VP8_SEGMENT_FLAG_ENABLED; + -+ ff_v4l2_request_reset_picture(avctx, &controls->pic); -+ slice = controls->num_slice_params = 0; -+ controls->num_entry_point_offsets = 0; -+ controls->first_slice = false; -+ } ++ if (s->segmentation.update_map) ++ ctrl->segment.flags |= V4L2_VP8_SEGMENT_FLAG_UPDATE_MAP; + -+ if (ctx->start_code == V4L2_STATELESS_HEVC_START_CODE_ANNEX_B) { -+ ret = ff_v4l2_request_append_output(avctx, &controls->pic, -+ nalu_slice_start_code, 3); -+ if (ret) -+ return ret; -+ extra_size = 3; -+ } ++ if (s->segmentation.update_feature_data) ++ ctrl->segment.flags |= V4L2_VP8_SEGMENT_FLAG_UPDATE_FEATURE_DATA; + -+ if (ctx->max_slice_params) { -+ if (slice && controls->allocated_slice_params < slice + 1) { -+ void *slice_params = controls->allocated_slice_params == 0 ? NULL : controls->frame_slice_params; -+ int slices = controls->allocated_slice_params == 0 ? 8 : controls->allocated_slice_params * 2; -+ slice_params = av_realloc_array(slice_params, slices, sizeof(*controls->frame_slice_params)); -+ if (!slice_params) -+ return AVERROR(ENOMEM); -+ if (controls->allocated_slice_params == 0) -+ memcpy(slice_params, controls->frame_slice_params, sizeof(*controls->frame_slice_params)); -+ controls->frame_slice_params = slice_params; -+ controls->allocated_slice_params = slices; -+ } ++ if (!s->segmentation.absolute_vals) ++ ctrl->segment.flags |= V4L2_VP8_SEGMENT_FLAG_DELTA_VALUE_MODE; + -+ ret = fill_slice_params(controls, slice, !!ctx->max_entry_point_offsets, h); -+ if (ret) -+ return ret; ++ for (i = 0; i < 4; i++) { ++ ctrl->lf.ref_frm_delta[i] = s->lf_delta.ref[i]; ++ ctrl->lf.mb_mode_delta[i] = s->lf_delta.mode[i + MODE_I4x4]; + } + -+ ret = ff_v4l2_request_append_output(avctx, &controls->pic, buffer, size); -+ if (ret) -+ return ret; ++ if (s->lf_delta.enabled) ++ ctrl->lf.flags |= V4L2_VP8_LF_ADJ_ENABLE; + -+ if (ctx->max_slice_params) -+ controls->frame_slice_params[slice].bit_size = (size + extra_size) * 8; ++ if (s->lf_delta.update) ++ ctrl->lf.flags |= V4L2_VP8_LF_DELTA_UPDATE; + -+ controls->num_slice_params++; -+ return 0; -+} ++ if (s->filter.simple) ++ ctrl->lf.flags |= V4L2_VP8_LF_FILTER_TYPE_SIMPLE; + -+static int v4l2_request_hevc_end_frame(AVCodecContext *avctx) -+{ -+ return v4l2_request_hevc_queue_decode(avctx, true); -+} ++ if (s->keyframe) { ++ static const uint8_t keyframe_y_mode_probs[4] = { ++ 145, 156, 163, 128 ++ }; ++ static const uint8_t keyframe_uv_mode_probs[3] = { ++ 142, 114, 183 ++ }; + -+static void v4l2_request_hevc_free_frame_priv(FFRefStructOpaque hwctx, void *data) -+{ -+ V4L2RequestControlsHEVC *controls = data; ++ memcpy(ctrl->entropy.y_mode_probs, keyframe_y_mode_probs, 4); ++ memcpy(ctrl->entropy.uv_mode_probs, keyframe_uv_mode_probs, 3); ++ } else { ++ for (i = 0; i < 4; i++) ++ ctrl->entropy.y_mode_probs[i] = s->prob->pred16x16[i]; ++ for (i = 0; i < 3; i++) ++ ctrl->entropy.uv_mode_probs[i] = s->prob->pred8x8c[i]; ++ } ++ for (i = 0; i < 2; i++) ++ for (j = 0; j < 19; j++) ++ ctrl->entropy.mv_probs[i][j] = s->prob->mvc[i][j]; + -+ if (controls->allocated_slice_params) -+ av_freep(&controls->frame_slice_params); ++ for (i = 0; i < 4; i++) { ++ for (j = 0; j < 8; j++) { ++ static const int coeff_bands_inverse[8] = { ++ 0, 1, 2, 3, 5, 6, 4, 15 ++ }; ++ int coeff_pos = coeff_bands_inverse[j]; + -+ av_freep(&controls->entry_point_offsets); -+} ++ for (k = 0; k < 3; k++) { ++ memcpy(ctrl->entropy.coeff_probs[i][j][k], ++ s->prob->token[i][coeff_pos][k], 11); ++ } ++ } ++ } + -+static int v4l2_request_hevc_post_probe(AVCodecContext *avctx) -+{ -+ V4L2RequestContextHEVC *ctx = avctx->internal->hwaccel_priv_data; -+ int ret; ++ for (i = 0; i < 8; i++) ++ ctrl->dct_part_sizes[i] = s->coeff_partition_size[i]; + -+ struct v4l2_ext_control control[] = { -+ { .id = V4L2_CID_STATELESS_HEVC_DECODE_MODE, }, -+ { .id = V4L2_CID_STATELESS_HEVC_START_CODE, }, -+ }; -+ struct v4l2_query_ext_ctrl scaling_matrix = { -+ .id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX, -+ }; -+ struct v4l2_query_ext_ctrl entry_point_offsets = { -+ .id = V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS, -+ }; -+ struct v4l2_query_ext_ctrl slice_params = { -+ .id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS, -+ }; ++ if (s->framep[VP8_FRAME_PREVIOUS]) ++ ctrl->last_frame_ts = ++ ff_v4l2_request_get_capture_timestamp(s->framep[VP8_FRAME_PREVIOUS]->tf.f); ++ if (s->framep[VP8_FRAME_GOLDEN]) ++ ctrl->golden_frame_ts = ++ ff_v4l2_request_get_capture_timestamp(s->framep[VP8_FRAME_GOLDEN]->tf.f); ++ if (s->framep[VP8_FRAME_ALTREF]) ++ ctrl->alt_frame_ts = ++ ff_v4l2_request_get_capture_timestamp(s->framep[VP8_FRAME_ALTREF]->tf.f); + -+ ctx->decode_mode = ff_v4l2_request_query_control_default_value(avctx, -+ V4L2_CID_STATELESS_HEVC_DECODE_MODE); -+ if (ctx->decode_mode != V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED && -+ ctx->decode_mode != V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED) { -+ av_log(ctx, AV_LOG_VERBOSE, "Unsupported decode mode: %d\n", -+ ctx->decode_mode); -+ return AVERROR(EINVAL); -+ } ++ if (s->keyframe) ++ ctrl->flags |= V4L2_VP8_FRAME_FLAG_KEY_FRAME; + -+ ctx->start_code = ff_v4l2_request_query_control_default_value(avctx, -+ V4L2_CID_STATELESS_HEVC_START_CODE); -+ if (ctx->start_code != V4L2_STATELESS_HEVC_START_CODE_NONE && -+ ctx->start_code != V4L2_STATELESS_HEVC_START_CODE_ANNEX_B) { -+ av_log(ctx, AV_LOG_VERBOSE, "Unsupported start code: %d\n", -+ ctx->start_code); -+ return AVERROR(EINVAL); -+ } ++ if (s->profile & 0x4) ++ ctrl->flags |= V4L2_VP8_FRAME_FLAG_EXPERIMENTAL; + -+ // TODO: check V4L2_CID_MPEG_VIDEO_HEVC_PROFILE control -+ // TODO: check V4L2_CID_MPEG_VIDEO_HEVC_LEVEL control ++ if (!s->invisible) ++ ctrl->flags |= V4L2_VP8_FRAME_FLAG_SHOW_FRAME; + -+ ret = ff_v4l2_request_query_control(avctx, &scaling_matrix); -+ if (!ret) -+ ctx->has_scaling_matrix = true; -+ else -+ ctx->has_scaling_matrix = false; ++ if (s->mbskip_enabled) ++ ctrl->flags |= V4L2_VP8_FRAME_FLAG_MB_NO_SKIP_COEFF; + -+ ret = ff_v4l2_request_query_control(avctx, &entry_point_offsets); -+ if (!ret) -+ ctx->max_entry_point_offsets = FFMAX(entry_point_offsets.dims[0], 1); -+ else -+ ctx->max_entry_point_offsets = 0; ++ if (s->sign_bias[VP8_FRAME_GOLDEN]) ++ ctrl->flags |= V4L2_VP8_FRAME_FLAG_SIGN_BIAS_GOLDEN; + -+ ret = ff_v4l2_request_query_control(avctx, &slice_params); -+ if (!ret) -+ ctx->max_slice_params = FFMAX(slice_params.dims[0], 1); -+ else -+ ctx->max_slice_params = 0; ++ if (s->sign_bias[VP8_FRAME_ALTREF]) ++ ctrl->flags |= V4L2_VP8_FRAME_FLAG_SIGN_BIAS_ALT; + -+ av_log(ctx, AV_LOG_VERBOSE, "%s-based decoder with SLICE_PARAMS=%u, " -+ "ENTRY_POINT_OFFSETS=%u and SCALING_MATRIX=%d controls\n", -+ ctx->decode_mode == V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED ? "slice" : "frame", -+ ctx->max_slice_params, ctx->max_entry_point_offsets, ctx->has_scaling_matrix); ++ return 0; ++} + -+ control[0].value = ctx->decode_mode; -+ control[1].value = ctx->start_code; ++static int v4l2_request_vp8_decode_slice(AVCodecContext *avctx, ++ const uint8_t *buffer, uint32_t size) ++{ ++ const VP8Context *s = avctx->priv_data; ++ V4L2RequestControlsVP8 *controls = s->framep[VP8_FRAME_CURRENT]->hwaccel_picture_private; + -+ return ff_v4l2_request_set_controls(avctx, control, FF_ARRAY_ELEMS(control)); ++ return ff_v4l2_request_append_output(avctx, &controls->pic, buffer, size); +} + -+static int v4l2_request_hevc_init(AVCodecContext *avctx) ++static int v4l2_request_vp8_end_frame(AVCodecContext *avctx) +{ -+ V4L2RequestContextHEVC *ctx = avctx->internal->hwaccel_priv_data; -+ const HEVCContext *h = avctx->priv_data; -+ struct v4l2_ctrl_hevc_sps sps; ++ const VP8Context *s = avctx->priv_data; ++ V4L2RequestControlsVP8 *controls = s->framep[VP8_FRAME_CURRENT]->hwaccel_picture_private; + + struct v4l2_ext_control control[] = { + { -+ .id = V4L2_CID_STATELESS_HEVC_SPS, -+ .ptr = &sps, -+ .size = sizeof(sps), ++ .id = V4L2_CID_STATELESS_VP8_FRAME, ++ .ptr = &controls->frame, ++ .size = sizeof(controls->frame), + }, + }; + -+ fill_sps(&sps, h); ++ return ff_v4l2_request_decode_frame(avctx, &controls->pic, ++ control, FF_ARRAY_ELEMS(control)); ++} + -+ ctx->base.post_probe = v4l2_request_hevc_post_probe; -+ return ff_v4l2_request_init(avctx, V4L2_PIX_FMT_HEVC_SLICE, -+ 4 * 1024 * 1024, -+ control, FF_ARRAY_ELEMS(control)); ++static int v4l2_request_vp8_init(AVCodecContext *avctx) ++{ ++ return ff_v4l2_request_init(avctx, NULL, 0, NULL); +} + -+const FFHWAccel ff_hevc_v4l2request_hwaccel = { -+ .p.name = "hevc_v4l2request", ++static int v4l2_request_vp8_frame_params(AVCodecContext *avctx, ++ AVBufferRef *hw_frames_ctx) ++{ ++ return ff_v4l2_request_frame_params(avctx, hw_frames_ctx, ++ V4L2_PIX_FMT_VP8_FRAME, 8); ++} ++ ++const FFHWAccel ff_vp8_v4l2request_hwaccel = { ++ .p.name = "vp8_v4l2request", + .p.type = AVMEDIA_TYPE_VIDEO, -+ .p.id = AV_CODEC_ID_HEVC, ++ .p.id = AV_CODEC_ID_VP8, + .p.pix_fmt = AV_PIX_FMT_DRM_PRIME, -+ .start_frame = v4l2_request_hevc_start_frame, -+ .decode_slice = v4l2_request_hevc_decode_slice, -+ .end_frame = v4l2_request_hevc_end_frame, ++ .start_frame = v4l2_request_vp8_start_frame, ++ .decode_slice = v4l2_request_vp8_decode_slice, ++ .end_frame = v4l2_request_vp8_end_frame, + .flush = ff_v4l2_request_flush, -+ .free_frame_priv = v4l2_request_hevc_free_frame_priv, -+ .frame_priv_data_size = sizeof(V4L2RequestControlsHEVC), -+ .init = v4l2_request_hevc_init, ++ .frame_priv_data_size = sizeof(V4L2RequestControlsVP8), ++ .init = v4l2_request_vp8_init, + .uninit = ff_v4l2_request_uninit, -+ .priv_data_size = sizeof(V4L2RequestContextHEVC), -+ .frame_params = ff_v4l2_request_frame_params, ++ .priv_data_size = sizeof(V4L2RequestContext), ++ .frame_params = v4l2_request_vp8_frame_params, ++ .caps_internal = HWACCEL_CAP_ASYNC_SAFE, +}; +diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c +index 9010e19e6b74..8a1e3425cac8 100644 +--- a/libavcodec/vp8.c ++++ b/libavcodec/vp8.c +@@ -184,6 +184,9 @@ static enum AVPixelFormat get_pixel_format(VP8Context *s) + #endif + #if CONFIG_VP8_NVDEC_HWACCEL + AV_PIX_FMT_CUDA, ++#endif ++#if CONFIG_VP8_V4L2REQUEST_HWACCEL ++ AV_PIX_FMT_DRM_PRIME, + #endif + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_NONE, +@@ -2975,6 +2978,9 @@ const FFCodec ff_vp8_decoder = { + #endif + #if CONFIG_VP8_NVDEC_HWACCEL + HWACCEL_NVDEC(vp8), ++#endif ++#if CONFIG_VP8_V4L2REQUEST_HWACCEL ++ HWACCEL_V4L2REQUEST(vp8), + #endif + NULL + }, -From 63716a8632a02eb3c9d7715a5dd0bf99d4296d48 Mon Sep 17 00:00:00 2001 +From 523f6c9fa1a3b5acbc70d841ba0e8444f5d2400b Mon Sep 17 00:00:00 2001 From: Boris Brezillon -Date: Wed, 22 May 2019 14:46:58 +0200 -Subject: [PATCH 09/11] avcodec: Add V4L2 Request API vp8 hwaccel +Date: Tue, 9 Dec 2025 20:30:05 +0100 +Subject: [PATCH 10/13] avcodec: Add V4L2 Request API vp9 hwaccel -Add a V4L2 Request API hwaccel for VP8. +Add a V4L2 Request API hwaccel for VP9. + +Support for VP9 is enabled when Linux kernel headers declare the +control id V4L2_CID_STATELESS_VP9_FRAME, added in v5.17. -Co-developed-by: Ezequiel Garcia -Signed-off-by: Ezequiel Garcia Signed-off-by: Boris Brezillon +Co-developed-by: Jernej Skrabec +Signed-off-by: Jernej Skrabec Co-developed-by: Jonas Karlman Signed-off-by: Jonas Karlman --- configure | 3 + libavcodec/Makefile | 1 + libavcodec/hwaccels.h | 1 + - libavcodec/v4l2_request_vp8.c | 235 ++++++++++++++++++++++++++++++++++ - libavcodec/vp8.c | 6 + - 5 files changed, 246 insertions(+) - create mode 100644 libavcodec/v4l2_request_vp8.c + libavcodec/v4l2_request_vp9.c | 530 ++++++++++++++++++++++++++++++++++ + libavcodec/vp9.c | 7 + + 5 files changed, 542 insertions(+) + create mode 100644 libavcodec/v4l2_request_vp9.c diff --git a/configure b/configure -index 7a2901d960..3b1288eb98 100755 +index 3546fffa5233..06e86082c05e 100755 --- a/configure +++ b/configure -@@ -3271,6 +3271,8 @@ vc1_vdpau_hwaccel_deps="vdpau" - vc1_vdpau_hwaccel_select="vc1_decoder" - vp8_nvdec_hwaccel_deps="nvdec" - vp8_nvdec_hwaccel_select="vp8_decoder" -+vp8_v4l2request_hwaccel_deps="v4l2_request vp8_v4l2_request" -+vp8_v4l2request_hwaccel_select="vp8_decoder" - vp8_vaapi_hwaccel_deps="vaapi" - vp8_vaapi_hwaccel_select="vp8_decoder" - vp9_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_VP9" -@@ -7213,6 +7215,7 @@ if enabled v4l2_request; then - check_cc hevc_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_HEVC_SPS" +@@ -3491,6 +3491,8 @@ vp9_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_VP9" + vp9_dxva2_hwaccel_select="vp9_decoder" + vp9_nvdec_hwaccel_deps="nvdec" + vp9_nvdec_hwaccel_select="vp9_decoder" ++vp9_v4l2request_hwaccel_deps="v4l2_request vp9_v4l2_request" ++vp9_v4l2request_hwaccel_select="vp9_decoder" + vp9_vaapi_hwaccel_deps="vaapi VADecPictureParameterBufferVP9_bit_depth" + vp9_vaapi_hwaccel_select="vp9_decoder" + vp9_vdpau_hwaccel_deps="vdpau VdpPictureInfoVP9" +@@ -7608,6 +7610,7 @@ if enabled v4l2_request; then check_cc mpeg2_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_MPEG2_SEQUENCE" check_cc v4l2_m2m_hold_capture_buf linux/videodev2.h "int i = V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF" -+ check_cc vp8_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_VP8_FRAME" + check_cc vp8_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_VP8_FRAME" ++ check_cc vp9_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_VP9_FRAME" check_func_headers "linux/media.h linux/videodev2.h" v4l2_timeval_to_ns check_pkg_config libudev libudev libudev.h udev_new check_struct linux/videodev2.h "struct v4l2_ctrl_hevc_decode_params" num_delta_pocs_of_ref_rps_idx diff --git a/libavcodec/Makefile b/libavcodec/Makefile -index fa78523b76..3fa9822594 100644 +index 5eee5e92a264..5f977bed12f4 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile -@@ -1057,6 +1057,7 @@ OBJS-$(CONFIG_VC1_QSV_HWACCEL) += qsvdec.o - OBJS-$(CONFIG_VC1_VAAPI_HWACCEL) += vaapi_vc1.o - OBJS-$(CONFIG_VC1_VDPAU_HWACCEL) += vdpau_vc1.o - OBJS-$(CONFIG_VP8_NVDEC_HWACCEL) += nvdec_vp8.o -+OBJS-$(CONFIG_VP8_V4L2REQUEST_HWACCEL) += v4l2_request_vp8.o - OBJS-$(CONFIG_VP8_VAAPI_HWACCEL) += vaapi_vp8.o - OBJS-$(CONFIG_VP9_D3D11VA_HWACCEL) += dxva2_vp9.o +@@ -1110,6 +1110,7 @@ OBJS-$(CONFIG_VP9_D3D11VA_HWACCEL) += dxva2_vp9.o OBJS-$(CONFIG_VP9_DXVA2_HWACCEL) += dxva2_vp9.o + OBJS-$(CONFIG_VP9_D3D12VA_HWACCEL) += dxva2_vp9.o d3d12va_vp9.o + OBJS-$(CONFIG_VP9_NVDEC_HWACCEL) += nvdec_vp9.o ++OBJS-$(CONFIG_VP9_V4L2REQUEST_HWACCEL) += v4l2_request_vp9.o + OBJS-$(CONFIG_VP9_VAAPI_HWACCEL) += vaapi_vp9.o + OBJS-$(CONFIG_VP9_VDPAU_HWACCEL) += vdpau_vp9.o + OBJS-$(CONFIG_VP9_VIDEOTOOLBOX_HWACCEL) += videotoolbox_vp9.o diff --git a/libavcodec/hwaccels.h b/libavcodec/hwaccels.h -index ad145fc07c..cb2cdb3893 100644 +index e60ec2a49878..ca47a3c90605 100644 --- a/libavcodec/hwaccels.h +++ b/libavcodec/hwaccels.h -@@ -76,6 +76,7 @@ extern const struct FFHWAccel ff_vc1_nvdec_hwaccel; - extern const struct FFHWAccel ff_vc1_vaapi_hwaccel; - extern const struct FFHWAccel ff_vc1_vdpau_hwaccel; - extern const struct FFHWAccel ff_vp8_nvdec_hwaccel; -+extern const struct FFHWAccel ff_vp8_v4l2request_hwaccel; - extern const struct FFHWAccel ff_vp8_vaapi_hwaccel; - extern const struct FFHWAccel ff_vp9_d3d11va_hwaccel; - extern const struct FFHWAccel ff_vp9_d3d11va2_hwaccel; -diff --git a/libavcodec/v4l2_request_vp8.c b/libavcodec/v4l2_request_vp8.c +@@ -88,6 +88,7 @@ extern const struct FFHWAccel ff_vp9_d3d11va2_hwaccel; + extern const struct FFHWAccel ff_vp9_d3d12va_hwaccel; + extern const struct FFHWAccel ff_vp9_dxva2_hwaccel; + extern const struct FFHWAccel ff_vp9_nvdec_hwaccel; ++extern const struct FFHWAccel ff_vp9_v4l2request_hwaccel; + extern const struct FFHWAccel ff_vp9_vaapi_hwaccel; + extern const struct FFHWAccel ff_vp9_vdpau_hwaccel; + extern const struct FFHWAccel ff_vp9_videotoolbox_hwaccel; +diff --git a/libavcodec/v4l2_request_vp9.c b/libavcodec/v4l2_request_vp9.c new file mode 100644 -index 0000000000..551b6dc75f +index 000000000000..e93937daf227 --- /dev/null -+++ b/libavcodec/v4l2_request_vp8.c -@@ -0,0 +1,235 @@ ++++ b/libavcodec/v4l2_request_vp9.c +@@ -0,0 +1,530 @@ +/* + * This file is part of FFmpeg. + * @@ -4484,318 +5007,660 @@ index 0000000000..551b6dc75f + +#include "hwaccel_internal.h" +#include "hwconfig.h" ++#include "internal.h" +#include "v4l2_request.h" -+#include "vp8.h" ++#include "vp89_rac.h" ++#include "vp9dec.h" ++ ++#define V4L2_VP9_CONTROLS_MAX 2 ++ ++typedef struct V4L2RequestContextVP9 { ++ V4L2RequestContext base; ++ bool has_compressed_hdr; ++} V4L2RequestContextVP9; + -+typedef struct V4L2RequestControlsVP8 { ++typedef struct V4L2RequestControlsVP9 { + V4L2RequestPictureContext pic; -+ struct v4l2_ctrl_vp8_frame frame; -+} V4L2RequestControlsVP8; ++ struct v4l2_ctrl_vp9_frame frame; ++ struct v4l2_ctrl_vp9_compressed_hdr compressed_hdr; ++} V4L2RequestControlsVP9; + -+static int v4l2_request_vp8_start_frame(AVCodecContext *avctx, -+ const uint8_t *buffer, -+ av_unused uint32_t size) ++// differential forward probability updates ++static int read_prob_delta(VPXRangeCoder *c) +{ -+ const VP8Context *s = avctx->priv_data; -+ V4L2RequestControlsVP8 *controls = s->framep[VP8_FRAME_CURRENT]->hwaccel_picture_private; -+ struct v4l2_ctrl_vp8_frame *ctrl = &controls->frame; -+ unsigned int header_size = 3 + 7 * s->keyframe; -+ const uint8_t *data = buffer + header_size; -+ int ret, i, j, k; ++ static const uint8_t inv_map_table[255] = { ++ 7, 20, 33, 46, 59, 72, 85, 98, 111, 124, 137, 150, 163, 176, ++ 189, 202, 215, 228, 241, 254, 1, 2, 3, 4, 5, 6, 8, 9, ++ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, ++ 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, ++ 40, 41, 42, 43, 44, 45, 47, 48, 49, 50, 51, 52, 53, 54, ++ 55, 56, 57, 58, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, ++ 70, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, ++ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 99, 100, ++ 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 112, 113, 114, 115, ++ 116, 117, 118, 119, 120, 121, 122, 123, 125, 126, 127, 128, 129, 130, ++ 131, 132, 133, 134, 135, 136, 138, 139, 140, 141, 142, 143, 144, 145, ++ 146, 147, 148, 149, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, ++ 161, 162, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, ++ 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 190, 191, ++ 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 203, 204, 205, 206, ++ 207, 208, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219, 220, 221, ++ 222, 223, 224, 225, 226, 227, 229, 230, 231, 232, 233, 234, 235, 236, ++ 237, 238, 239, 240, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, ++ 252, 253, 253, ++ }; ++ int d; ++ ++ /* This code is trying to do a differential probability update. For a ++ * current probability A in the range [1, 255], the difference to a new ++ * probability of any value can be expressed differentially as 1-A, 255-A ++ * where some part of this (absolute range) exists both in positive as ++ * well as the negative part, whereas another part only exists in one ++ * half. We're trying to code this shared part differentially, i.e. ++ * times two where the value of the lowest bit specifies the sign, and ++ * the single part is then coded on top of this. This absolute difference ++ * then again has a value of [0, 254], but a bigger value in this range ++ * indicates that we're further away from the original value A, so we ++ * can code this as a VLC code, since higher values are increasingly ++ * unlikely. The first 20 values in inv_map_table[] allow 'cheap, rough' ++ * updates vs. the 'fine, exact' updates further down the range, which ++ * adds one extra dimension to this differential update model. */ ++ ++ if (!vp89_rac_get(c)) { ++ d = vp89_rac_get_uint(c, 4) + 0; ++ } else if (!vp89_rac_get(c)) { ++ d = vp89_rac_get_uint(c, 4) + 16; ++ } else if (!vp89_rac_get(c)) { ++ d = vp89_rac_get_uint(c, 5) + 32; ++ } else { ++ d = vp89_rac_get_uint(c, 7); ++ if (d >= 65) ++ d = (d << 1) - 65 + vp89_rac_get(c); ++ d += 64; ++ av_assert2(d < FF_ARRAY_ELEMS(inv_map_table)); ++ } + -+ ret = ff_v4l2_request_start_frame(avctx, &controls->pic, -+ s->framep[VP8_FRAME_CURRENT]->tf.f); -+ if (ret) -+ return ret; ++ return inv_map_table[d]; ++} + -+ *ctrl = (struct v4l2_ctrl_vp8_frame) { ++static void fill_compressed_hdr(struct v4l2_ctrl_vp9_compressed_hdr *ctrl, ++ const uint8_t *buffer, uint32_t size, ++ AVCodecContext *avctx) ++{ ++ const VP9Context *s = avctx->priv_data; ++ enum CompPredMode comppredmode; ++ int ret, i, j, k, l, m, n; ++ VPXRangeCoder c; ++ ++ ret = ff_vpx_init_range_decoder(&c, buffer + s->s.h.uncompressed_header_size, ++ s->s.h.compressed_header_size); ++ if (ret < 0) ++ return; ++ ++ if (vpx_rac_get_prob_branchy(&c, 128)) // marker bit ++ return; ++ ++ // txfm updates ++ if (s->s.h.lossless) { ++ ctrl->tx_mode = V4L2_VP9_TX_MODE_ONLY_4X4; ++ } else { ++ ctrl->tx_mode = vp89_rac_get_uint(&c, 2); ++ if (ctrl->tx_mode == V4L2_VP9_TX_MODE_ALLOW_32X32) ++ ctrl->tx_mode += vp89_rac_get(&c); ++ ++ if (ctrl->tx_mode == V4L2_VP9_TX_MODE_SELECT) { ++ for (i = 0; i < 2; i++) ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->tx8[i][0] = read_prob_delta(&c); ++ for (i = 0; i < 2; i++) ++ for (j = 0; j < 2; j++) ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->tx16[i][j] = read_prob_delta(&c); ++ for (i = 0; i < 2; i++) ++ for (j = 0; j < 3; j++) ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->tx32[i][j] = read_prob_delta(&c); ++ } ++ } ++ ++ // coef updates ++ for (i = 0; i < 4; i++) { ++ if (vp89_rac_get(&c)) { ++ for (j = 0; j < 2; j++) ++ for (k = 0; k < 2; k++) ++ for (l = 0; l < 6; l++) ++ for (m = 0; m < 6; m++) { ++ if (m >= 3 && l == 0) // dc only has 3 pt ++ break; ++ for (n = 0; n < 3; n++) ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->coef[i][j][k][l][m][n] = ++ read_prob_delta(&c); ++ } ++ } ++ if (ctrl->tx_mode == i) ++ break; ++ } ++ ++ // mode updates ++ for (i = 0; i < 3; i++) ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->skip[i] = read_prob_delta(&c); ++ if (!s->s.h.keyframe && !s->s.h.intraonly) { ++ for (i = 0; i < 7; i++) ++ for (j = 0; j < 3; j++) ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->inter_mode[i][j] = read_prob_delta(&c); ++ ++ if (s->s.h.filtermode == FILTER_SWITCHABLE) ++ for (i = 0; i < 4; i++) ++ for (j = 0; j < 2; j++) ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->interp_filter[i][j] = read_prob_delta(&c); ++ ++ for (i = 0; i < 4; i++) ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->is_inter[i] = read_prob_delta(&c); ++ ++ if (s->s.h.allowcompinter) { ++ comppredmode = vp89_rac_get(&c); ++ if (comppredmode) ++ comppredmode += vp89_rac_get(&c); ++ if (comppredmode == PRED_SWITCHABLE) ++ for (i = 0; i < 5; i++) ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->comp_mode[i] = read_prob_delta(&c); ++ } else { ++ comppredmode = PRED_SINGLEREF; ++ } ++ ++ if (comppredmode != PRED_COMPREF) { ++ for (i = 0; i < 5; i++) { ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->single_ref[i][0] = read_prob_delta(&c); ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->single_ref[i][1] = read_prob_delta(&c); ++ } ++ } ++ ++ if (comppredmode != PRED_SINGLEREF) { ++ for (i = 0; i < 5; i++) ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->comp_ref[i] = read_prob_delta(&c); ++ } ++ ++ for (i = 0; i < 4; i++) ++ for (j = 0; j < 9; j++) ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->y_mode[i][j] = read_prob_delta(&c); ++ ++ for (i = 0; i < 4; i++) ++ for (j = 0; j < 4; j++) ++ for (k = 0; k < 3; k++) ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->partition[(i * 4) + j][k] = read_prob_delta(&c); ++ ++ // mv fields ++ for (i = 0; i < 3; i++) ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->mv.joint[i] = (vp89_rac_get_uint(&c, 7) << 1) | 1; ++ ++ for (i = 0; i < 2; i++) { ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->mv.sign[i] = (vp89_rac_get_uint(&c, 7) << 1) | 1; ++ ++ for (j = 0; j < 10; j++) ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->mv.classes[i][j] = (vp89_rac_get_uint(&c, 7) << 1) | 1; ++ ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->mv.class0_bit[i] = (vp89_rac_get_uint(&c, 7) << 1) | 1; ++ ++ for (j = 0; j < 10; j++) ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->mv.bits[i][j] = (vp89_rac_get_uint(&c, 7) << 1) | 1; ++ } ++ ++ for (i = 0; i < 2; i++) { ++ for (j = 0; j < 2; j++) ++ for (k = 0; k < 3; k++) ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->mv.class0_fr[i][j][k] = ++ (vp89_rac_get_uint(&c, 7) << 1) | 1; ++ ++ for (j = 0; j < 3; j++) ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->mv.fr[i][j] = (vp89_rac_get_uint(&c, 7) << 1) | 1; ++ } ++ ++ if (s->s.h.highprecisionmvs) { ++ for (i = 0; i < 2; i++) { ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->mv.class0_hp[i] = (vp89_rac_get_uint(&c, 7) << 1) | 1; ++ ++ if (vpx_rac_get_prob_branchy(&c, 252)) ++ ctrl->mv.hp[i] = (vp89_rac_get_uint(&c, 7) << 1) | 1; ++ } ++ } ++ } ++ ++ memcpy(ctrl->uv_mode, s->prob.p.uv_mode, sizeof(ctrl->uv_mode)); ++} ++ ++static void fill_frame(struct v4l2_ctrl_vp9_frame *ctrl, AVCodecContext *avctx) ++{ ++ const VP9Context *s = avctx->priv_data; ++ AVFrame *ref; ++ int i; ++ ++ *ctrl = (struct v4l2_ctrl_vp9_frame) { + .lf = { -+ .sharpness_level = s->filter.sharpness, -+ .level = s->filter.level, ++ .level = s->s.h.filter.level, ++ .sharpness = s->s.h.filter.sharpness, + }, + + .quant = { -+ .y_ac_qi = s->quant.yac_qi, -+ .y_dc_delta = s->quant.ydc_delta, -+ .y2_dc_delta = s->quant.y2dc_delta, -+ .y2_ac_delta = s->quant.y2ac_delta, -+ .uv_dc_delta = s->quant.uvdc_delta, -+ .uv_ac_delta = s->quant.uvac_delta, ++ .base_q_idx = s->s.h.yac_qi, ++ .delta_q_y_dc = s->s.h.ydc_qdelta, ++ .delta_q_uv_dc = s->s.h.uvdc_qdelta, ++ .delta_q_uv_ac = s->s.h.uvac_qdelta, + }, + -+ .coder_state = { -+ .range = s->coder_state_at_header_end.range, -+ .value = s->coder_state_at_header_end.value, -+ .bit_count = s->coder_state_at_header_end.bit_count, -+ }, ++ .compressed_header_size = s->s.h.compressed_header_size, ++ .uncompressed_header_size = s->s.h.uncompressed_header_size, ++ .frame_width_minus_1 = avctx->width - 1, ++ .frame_height_minus_1 = avctx->height - 1, ++ .render_width_minus_1 = s->w - 1, ++ .render_height_minus_1 = s->h - 1, ++ .reset_frame_context = s->s.h.resetctx > 0 ? s->s.h.resetctx - 1 : 0, ++ .frame_context_idx = s->s.h.framectxid, ++ .profile = s->s.h.profile, ++ .bit_depth = s->s.h.bpp, ++ .interpolation_filter = s->s.h.filtermode ^ (s->s.h.filtermode <= 1), ++ .tile_cols_log2 = s->s.h.tiling.log2_tile_cols, ++ .tile_rows_log2 = s->s.h.tiling.log2_tile_rows, ++ .reference_mode = s->s.h.comppredmode, ++ }; + -+ .width = avctx->width, -+ .height = avctx->height, ++ for (i = 0; i < 4; i++) ++ ctrl->lf.ref_deltas[i] = s->s.h.lf_delta.ref[i]; + -+ .horizontal_scale = 0, /* scale not supported by FFmpeg */ -+ .vertical_scale = 0, /* scale not supported by FFmpeg */ ++ for (i = 0; i < 2; i++) ++ ctrl->lf.mode_deltas[i] = s->s.h.lf_delta.mode[i]; + -+ .version = s->profile & 0x3, -+ .prob_skip_false = s->prob->mbskip, -+ .prob_intra = s->prob->intra, -+ .prob_last = s->prob->last, -+ .prob_gf = s->prob->golden, -+ .num_dct_parts = s->num_coeff_partitions, ++ if (s->s.h.lf_delta.enabled) ++ ctrl->lf.flags |= V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED; + -+ .first_part_size = s->header_partition_size, -+ .first_part_header_bits = (8 * (s->coder_state_at_header_end.input - data) - -+ s->coder_state_at_header_end.bit_count - 8), -+ }; ++ if (s->s.h.lf_delta.updated) ++ ctrl->lf.flags |= V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE; + -+ for (i = 0; i < 4; i++) { -+ ctrl->segment.quant_update[i] = s->segmentation.base_quant[i]; -+ ctrl->segment.lf_update[i] = s->segmentation.filter_level[i]; ++ for (i = 0; i < 8; i++) { ++ if (s->s.h.segmentation.feat[i].q_enabled) { ++ ctrl->seg.feature_data[i][V4L2_VP9_SEG_LVL_ALT_Q] = ++ s->s.h.segmentation.feat[i].q_val; ++ ctrl->seg.feature_enabled[i] |= 1 << V4L2_VP9_SEG_LVL_ALT_Q; ++ } ++ ++ if (s->s.h.segmentation.feat[i].lf_enabled) { ++ ctrl->seg.feature_data[i][V4L2_VP9_SEG_LVL_ALT_L] = ++ s->s.h.segmentation.feat[i].lf_val; ++ ctrl->seg.feature_enabled[i] |= 1 << V4L2_VP9_SEG_LVL_ALT_L; ++ } ++ ++ if (s->s.h.segmentation.feat[i].ref_enabled) { ++ ctrl->seg.feature_data[i][V4L2_VP9_SEG_LVL_REF_FRAME] = ++ s->s.h.segmentation.feat[i].ref_val; ++ ctrl->seg.feature_enabled[i] |= 1 << V4L2_VP9_SEG_LVL_REF_FRAME; ++ } ++ ++ if (s->s.h.segmentation.feat[i].skip_enabled) ++ ctrl->seg.feature_enabled[i] |= 1 << V4L2_VP9_SEG_LVL_SKIP; + } + -+ for (i = 0; i < 3; i++) -+ ctrl->segment.segment_probs[i] = s->prob->segmentid[i]; ++ for (i = 0; i < 7; i++) ++ ctrl->seg.tree_probs[i] = s->s.h.segmentation.prob[i]; + -+ if (s->segmentation.enabled) -+ ctrl->segment.flags |= V4L2_VP8_SEGMENT_FLAG_ENABLED; ++ if (s->s.h.segmentation.temporal) { ++ for (i = 0; i < 3; i++) ++ ctrl->seg.pred_probs[i] = s->s.h.segmentation.pred_prob[i]; ++ } else { ++ memset(ctrl->seg.pred_probs, 255, sizeof(ctrl->seg.pred_probs)); ++ } + -+ if (s->segmentation.update_map) -+ ctrl->segment.flags |= V4L2_VP8_SEGMENT_FLAG_UPDATE_MAP; ++ if (s->s.h.segmentation.enabled) ++ ctrl->seg.flags |= V4L2_VP9_SEGMENTATION_FLAG_ENABLED; + -+ if (s->segmentation.update_feature_data) -+ ctrl->segment.flags |= V4L2_VP8_SEGMENT_FLAG_UPDATE_FEATURE_DATA; ++ if (s->s.h.segmentation.update_map) ++ ctrl->seg.flags |= V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP; + -+ if (!s->segmentation.absolute_vals) -+ ctrl->segment.flags |= V4L2_VP8_SEGMENT_FLAG_DELTA_VALUE_MODE; ++ if (s->s.h.segmentation.temporal) ++ ctrl->seg.flags |= V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE; + -+ for (i = 0; i < 4; i++) { -+ ctrl->lf.ref_frm_delta[i] = s->lf_delta.ref[i]; -+ ctrl->lf.mb_mode_delta[i] = s->lf_delta.mode[i + MODE_I4x4]; -+ } ++ if (s->frame_header->segmentation_update_data) ++ ctrl->seg.flags |= V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA; + -+ if (s->lf_delta.enabled) -+ ctrl->lf.flags |= V4L2_VP8_LF_ADJ_ENABLE; ++ if (s->s.h.segmentation.absolute_vals) ++ ctrl->seg.flags |= V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE; + -+ if (s->lf_delta.update) -+ ctrl->lf.flags |= V4L2_VP8_LF_DELTA_UPDATE; ++ if (s->s.h.keyframe) ++ ctrl->flags |= V4L2_VP9_FRAME_FLAG_KEY_FRAME; + -+ if (s->filter.simple) -+ ctrl->lf.flags |= V4L2_VP8_LF_FILTER_TYPE_SIMPLE; ++ if (!s->s.h.invisible) ++ ctrl->flags |= V4L2_VP9_FRAME_FLAG_SHOW_FRAME; + -+ if (s->keyframe) { -+ static const uint8_t keyframe_y_mode_probs[4] = { -+ 145, 156, 163, 128 -+ }; -+ static const uint8_t keyframe_uv_mode_probs[3] = { -+ 142, 114, 183 -+ }; ++ if (s->s.h.errorres) ++ ctrl->flags |= V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT; + -+ memcpy(ctrl->entropy.y_mode_probs, keyframe_y_mode_probs, 4); -+ memcpy(ctrl->entropy.uv_mode_probs, keyframe_uv_mode_probs, 3); -+ } else { -+ for (i = 0; i < 4; i++) -+ ctrl->entropy.y_mode_probs[i] = s->prob->pred16x16[i]; -+ for (i = 0; i < 3; i++) -+ ctrl->entropy.uv_mode_probs[i] = s->prob->pred8x8c[i]; -+ } -+ for (i = 0; i < 2; i++) -+ for (j = 0; j < 19; j++) -+ ctrl->entropy.mv_probs[i][j] = s->prob->mvc[i][j]; ++ if (s->s.h.intraonly) ++ ctrl->flags |= V4L2_VP9_FRAME_FLAG_INTRA_ONLY; + -+ for (i = 0; i < 4; i++) { -+ for (j = 0; j < 8; j++) { -+ static const int coeff_bands_inverse[8] = { -+ 0, 1, 2, 3, 5, 6, 4, 15 -+ }; -+ int coeff_pos = coeff_bands_inverse[j]; ++ if (!s->s.h.keyframe && s->s.h.highprecisionmvs) ++ ctrl->flags |= V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV; + -+ for (k = 0; k < 3; k++) { -+ memcpy(ctrl->entropy.coeff_probs[i][j][k], -+ s->prob->token[i][coeff_pos][k], 11); -+ } -+ } -+ } ++ if (s->s.h.refreshctx) ++ ctrl->flags |= V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX; + -+ for (i = 0; i < 8; i++) -+ ctrl->dct_part_sizes[i] = s->coeff_partition_size[i]; ++ if (s->s.h.parallelmode) ++ ctrl->flags |= V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE; + -+ if (s->framep[VP8_FRAME_PREVIOUS]) -+ ctrl->last_frame_ts = -+ ff_v4l2_request_get_capture_timestamp(s->framep[VP8_FRAME_PREVIOUS]->tf.f); -+ if (s->framep[VP8_FRAME_GOLDEN]) -+ ctrl->golden_frame_ts = -+ ff_v4l2_request_get_capture_timestamp(s->framep[VP8_FRAME_GOLDEN]->tf.f); -+ if (s->framep[VP8_FRAME_ALTREF]) -+ ctrl->alt_frame_ts = -+ ff_v4l2_request_get_capture_timestamp(s->framep[VP8_FRAME_ALTREF]->tf.f); ++ if (s->ss_h) ++ ctrl->flags |= V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING; + -+ if (s->keyframe) -+ ctrl->flags |= V4L2_VP8_FRAME_FLAG_KEY_FRAME; ++ if (s->ss_v) ++ ctrl->flags |= V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING; + -+ if (s->profile & 0x4) -+ ctrl->flags |= V4L2_VP8_FRAME_FLAG_EXPERIMENTAL; ++ if (avctx->color_range == AVCOL_RANGE_JPEG) ++ ctrl->flags |= V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING; + -+ if (!s->invisible) -+ ctrl->flags |= V4L2_VP8_FRAME_FLAG_SHOW_FRAME; ++ ref = s->s.refs[s->s.h.refidx[0]].f; ++ if (ref && ref->private_ref) ++ ctrl->last_frame_ts = ff_v4l2_request_get_capture_timestamp(ref); + -+ if (s->mbskip_enabled) -+ ctrl->flags |= V4L2_VP8_FRAME_FLAG_MB_NO_SKIP_COEFF; ++ ref = s->s.refs[s->s.h.refidx[1]].f; ++ if (ref && ref->private_ref) ++ ctrl->golden_frame_ts = ff_v4l2_request_get_capture_timestamp(ref); + -+ if (s->sign_bias[VP8_FRAME_GOLDEN]) -+ ctrl->flags |= V4L2_VP8_FRAME_FLAG_SIGN_BIAS_GOLDEN; ++ ref = s->s.refs[s->s.h.refidx[2]].f; ++ if (ref && ref->private_ref) ++ ctrl->alt_frame_ts = ff_v4l2_request_get_capture_timestamp(ref); ++ ++ if (s->s.h.signbias[0]) ++ ctrl->ref_frame_sign_bias |= V4L2_VP9_SIGN_BIAS_LAST; ++ ++ if (s->s.h.signbias[1]) ++ ctrl->ref_frame_sign_bias |= V4L2_VP9_SIGN_BIAS_GOLDEN; ++ ++ if (s->s.h.signbias[2]) ++ ctrl->ref_frame_sign_bias |= V4L2_VP9_SIGN_BIAS_ALT; ++} ++ ++static int v4l2_request_vp9_start_frame(AVCodecContext *avctx, ++ av_unused const AVBufferRef *buf_ref, ++ const uint8_t *buffer, ++ uint32_t size) ++{ ++ const VP9SharedContext *h = avctx->priv_data; ++ const VP9Frame *f = &h->frames[CUR_FRAME]; ++ V4L2RequestContextVP9 *ctx = avctx->internal->hwaccel_priv_data; ++ V4L2RequestControlsVP9 *controls = f->hwaccel_picture_private; ++ int ret; ++ ++ ret = ff_v4l2_request_start_frame(avctx, &controls->pic, f->tf.f); ++ if (ret) ++ return ret; ++ ++ fill_frame(&controls->frame, avctx); ++ ++ if (ctx->has_compressed_hdr) ++ fill_compressed_hdr(&controls->compressed_hdr, buffer, size, avctx); ++ ++ return 0; ++} ++ ++static int v4l2_request_vp9_decode_slice(AVCodecContext *avctx, ++ const uint8_t *buffer, uint32_t size) ++{ ++ const VP9SharedContext *h = avctx->priv_data; ++ V4L2RequestControlsVP9 *controls = h->frames[CUR_FRAME].hwaccel_picture_private; ++ ++ return ff_v4l2_request_append_output(avctx, &controls->pic, buffer, size); ++} ++ ++static int v4l2_request_vp9_end_frame(AVCodecContext *avctx) ++{ ++ const VP9SharedContext *h = avctx->priv_data; ++ V4L2RequestContextVP9 *ctx = avctx->internal->hwaccel_priv_data; ++ V4L2RequestControlsVP9 *controls = h->frames[CUR_FRAME].hwaccel_picture_private; ++ int count = 0; ++ ++ struct v4l2_ext_control control[V4L2_VP9_CONTROLS_MAX] = {}; + -+ if (s->sign_bias[VP8_FRAME_ALTREF]) -+ ctrl->flags |= V4L2_VP8_FRAME_FLAG_SIGN_BIAS_ALT; ++ control[count++] = (struct v4l2_ext_control) { ++ .id = V4L2_CID_STATELESS_VP9_FRAME, ++ .ptr = &controls->frame, ++ .size = sizeof(controls->frame), ++ }; + -+ return 0; ++ if (ctx->has_compressed_hdr) { ++ control[count++] = (struct v4l2_ext_control) { ++ .id = V4L2_CID_STATELESS_VP9_COMPRESSED_HDR, ++ .ptr = &controls->compressed_hdr, ++ .size = sizeof(controls->compressed_hdr), ++ }; ++ } ++ ++ return ff_v4l2_request_decode_frame(avctx, &controls->pic, control, count); +} + -+static int v4l2_request_vp8_decode_slice(AVCodecContext *avctx, -+ const uint8_t *buffer, uint32_t size) ++static int v4l2_request_vp9_post_frames_ctx(AVCodecContext *avctx) +{ -+ const VP8Context *s = avctx->priv_data; -+ V4L2RequestControlsVP8 *controls = s->framep[VP8_FRAME_CURRENT]->hwaccel_picture_private; ++ V4L2RequestContextVP9 *ctx = avctx->internal->hwaccel_priv_data; + -+ return ff_v4l2_request_append_output(avctx, &controls->pic, buffer, size); ++ struct v4l2_query_ext_ctrl compressed_hdr = { ++ .id = V4L2_CID_STATELESS_VP9_COMPRESSED_HDR, ++ }; ++ ++ // TODO: check V4L2_CID_MPEG_VIDEO_VP9_PROFILE ++ // TODO: check V4L2_CID_MPEG_VIDEO_VP9_LEVEL ++ ++ if (!ff_v4l2_request_query_control(avctx, &compressed_hdr)) ++ ctx->has_compressed_hdr = true; ++ else ++ ctx->has_compressed_hdr = false; ++ ++ return 0; +} + -+static int v4l2_request_vp8_end_frame(AVCodecContext *avctx) ++static int v4l2_request_vp9_init(AVCodecContext *avctx) +{ -+ const VP8Context *s = avctx->priv_data; -+ V4L2RequestControlsVP8 *controls = s->framep[VP8_FRAME_CURRENT]->hwaccel_picture_private; ++ struct v4l2_ctrl_vp9_frame frame; + + struct v4l2_ext_control control[] = { + { -+ .id = V4L2_CID_STATELESS_VP8_FRAME, -+ .ptr = &controls->frame, -+ .size = sizeof(controls->frame), ++ .id = V4L2_CID_STATELESS_VP9_FRAME, ++ .ptr = &frame, ++ .size = sizeof(frame), + }, + }; + -+ return ff_v4l2_request_decode_frame(avctx, &controls->pic, -+ control, FF_ARRAY_ELEMS(control)); ++ fill_frame(&frame, avctx); ++ ++ return ff_v4l2_request_init(avctx, control, FF_ARRAY_ELEMS(control), ++ v4l2_request_vp9_post_frames_ctx); +} + -+static int v4l2_request_vp8_init(AVCodecContext *avctx) ++static int v4l2_request_vp9_frame_params(AVCodecContext *avctx, ++ AVBufferRef *hw_frames_ctx) +{ -+ return ff_v4l2_request_init(avctx, V4L2_PIX_FMT_VP8_FRAME, -+ 2 * 1024 * 1024, -+ NULL, 0); ++ const VP9Context *s = avctx->priv_data; ++ uint8_t bit_depth = s ? s->s.h.bpp : 0; ++ ++ return ff_v4l2_request_frame_params(avctx, hw_frames_ctx, ++ V4L2_PIX_FMT_VP9_FRAME, bit_depth); +} + -+const FFHWAccel ff_vp8_v4l2request_hwaccel = { -+ .p.name = "vp8_v4l2request", ++const FFHWAccel ff_vp9_v4l2request_hwaccel = { ++ .p.name = "vp9_v4l2request", + .p.type = AVMEDIA_TYPE_VIDEO, -+ .p.id = AV_CODEC_ID_VP8, ++ .p.id = AV_CODEC_ID_VP9, + .p.pix_fmt = AV_PIX_FMT_DRM_PRIME, -+ .start_frame = v4l2_request_vp8_start_frame, -+ .decode_slice = v4l2_request_vp8_decode_slice, -+ .end_frame = v4l2_request_vp8_end_frame, ++ .start_frame = v4l2_request_vp9_start_frame, ++ .decode_slice = v4l2_request_vp9_decode_slice, ++ .end_frame = v4l2_request_vp9_end_frame, + .flush = ff_v4l2_request_flush, -+ .frame_priv_data_size = sizeof(V4L2RequestControlsVP8), -+ .init = v4l2_request_vp8_init, ++ .frame_priv_data_size = sizeof(V4L2RequestControlsVP9), ++ .init = v4l2_request_vp9_init, + .uninit = ff_v4l2_request_uninit, -+ .priv_data_size = sizeof(V4L2RequestContext), -+ .frame_params = ff_v4l2_request_frame_params, ++ .priv_data_size = sizeof(V4L2RequestContextVP9), ++ .frame_params = v4l2_request_vp9_frame_params, ++ .caps_internal = HWACCEL_CAP_ASYNC_SAFE, +}; -diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c -index d6df018655..04b16cc2e3 100644 ---- a/libavcodec/vp8.c -+++ b/libavcodec/vp8.c -@@ -184,6 +184,9 @@ static enum AVPixelFormat get_pixel_format(VP8Context *s) +diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c +index 1f34197a283e..fd2c1c43a064 100644 +--- a/libavcodec/vp9.c ++++ b/libavcodec/vp9.c +@@ -168,6 +168,7 @@ static int update_size(AVCodecContext *avctx, int w, int h) + CONFIG_VP9_D3D11VA_HWACCEL * 2 + \ + CONFIG_VP9_D3D12VA_HWACCEL + \ + CONFIG_VP9_NVDEC_HWACCEL + \ ++ CONFIG_VP9_V4L2REQUEST_HWACCEL + \ + CONFIG_VP9_VAAPI_HWACCEL + \ + CONFIG_VP9_VDPAU_HWACCEL + \ + CONFIG_VP9_VIDEOTOOLBOX_HWACCEL + \ +@@ -213,6 +214,9 @@ static int update_size(AVCodecContext *avctx, int w, int h) #endif - #if CONFIG_VP8_NVDEC_HWACCEL - AV_PIX_FMT_CUDA, + #if CONFIG_VP9_VULKAN_HWACCEL + *fmtp++ = AV_PIX_FMT_VULKAN; +#endif -+#if CONFIG_VP8_V4L2REQUEST_HWACCEL -+ AV_PIX_FMT_DRM_PRIME, ++#if CONFIG_VP9_V4L2REQUEST_HWACCEL ++ *fmtp++ = AV_PIX_FMT_DRM_PRIME; #endif - AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE, -@@ -2980,6 +2983,9 @@ const FFCodec ff_vp8_decoder = { + break; + case AV_PIX_FMT_YUV420P12: +@@ -1959,6 +1963,9 @@ const FFCodec ff_vp9_decoder = { #endif - #if CONFIG_VP8_NVDEC_HWACCEL - HWACCEL_NVDEC(vp8), + #if CONFIG_VP9_VULKAN_HWACCEL + HWACCEL_VULKAN(vp9), +#endif -+#if CONFIG_VP8_V4L2REQUEST_HWACCEL -+ HWACCEL_V4L2REQUEST(vp8), ++#if CONFIG_VP9_V4L2REQUEST_HWACCEL ++ HWACCEL_V4L2REQUEST(vp9), #endif NULL }, -From 96c22879bbbfcbd57cd73a165ab6b1fb49663481 Mon Sep 17 00:00:00 2001 -From: Boris Brezillon -Date: Thu, 12 Dec 2019 16:13:55 +0100 -Subject: [PATCH 10/11] avcodec: Add V4L2 Request API vp9 hwaccel +From 6b67aa32fc3b9cad3e2487875e058ba726e0513d Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 6 Jul 2024 08:41:30 +0000 +Subject: [PATCH 11/13] avcodec: Add V4L2 Request API av1 hwaccel -FIXME: split patch +Add a V4L2 Request API hwaccel for AV1. + +Support for AV1 is enabled when Linux kernel headers declare the +control id V4L2_CID_STATELESS_AV1_FRAME, added in v6.5. -Signed-off-by: Boris Brezillon -Co-developed-by: Jernej Skrabec -Signed-off-by: Jernej Skrabec -Co-developed-by: Jonas Karlman Signed-off-by: Jonas Karlman --- configure | 3 + libavcodec/Makefile | 1 + + libavcodec/av1dec.c | 10 + libavcodec/hwaccels.h | 1 + - libavcodec/v4l2_request_vp9.c | 288 ++++++++++++++++++++++++++++++++++ - libavcodec/vp9.c | 187 +++++++++++++++------- - libavcodec/vp9dec.h | 4 + - libavcodec/vp9shared.h | 1 + - 7 files changed, 431 insertions(+), 54 deletions(-) - create mode 100644 libavcodec/v4l2_request_vp9.c + libavcodec/v4l2_request_av1.c | 636 ++++++++++++++++++++++++++++++++++ + 5 files changed, 651 insertions(+) + create mode 100644 libavcodec/v4l2_request_av1.c diff --git a/configure b/configure -index 3b1288eb98..2904b67ef7 100755 +index 06e86082c05e..3d4009f3480d 100755 --- a/configure +++ b/configure -@@ -3285,6 +3285,8 @@ vp9_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_VP9" - vp9_dxva2_hwaccel_select="vp9_decoder" - vp9_nvdec_hwaccel_deps="nvdec" - vp9_nvdec_hwaccel_select="vp9_decoder" -+vp9_v4l2request_hwaccel_deps="v4l2_request vp9_v4l2_request" -+vp9_v4l2request_hwaccel_select="vp9_decoder" - vp9_vaapi_hwaccel_deps="vaapi VADecPictureParameterBufferVP9_bit_depth" - vp9_vaapi_hwaccel_select="vp9_decoder" - vp9_vdpau_hwaccel_deps="vdpau VdpPictureInfoVP9" -@@ -7216,6 +7218,7 @@ if enabled v4l2_request; then +@@ -3363,6 +3363,8 @@ av1_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_AV1" + av1_dxva2_hwaccel_select="av1_decoder" + av1_nvdec_hwaccel_deps="nvdec CUVIDAV1PICPARAMS" + av1_nvdec_hwaccel_select="av1_decoder" ++av1_v4l2request_hwaccel_deps="v4l2_request av1_v4l2_request" ++av1_v4l2request_hwaccel_select="av1_decoder" + av1_vaapi_hwaccel_deps="vaapi VADecPictureParameterBufferAV1_bit_depth_idx" + av1_vaapi_hwaccel_select="av1_decoder" + av1_vdpau_hwaccel_deps="vdpau VdpPictureInfoAV1" +@@ -7605,6 +7607,7 @@ if enabled v4l2_m2m; then + fi + + if enabled v4l2_request; then ++ check_cc av1_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_AV1_SEQUENCE" + check_cc h264_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_H264_DECODE_MODE" + check_cc hevc_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_HEVC_SPS" check_cc mpeg2_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_MPEG2_SEQUENCE" - check_cc v4l2_m2m_hold_capture_buf linux/videodev2.h "int i = V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF" - check_cc vp8_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_VP8_FRAME" -+ check_cc vp9_v4l2_request linux/videodev2.h "int i = V4L2_CID_STATELESS_VP9_FRAME" - check_func_headers "linux/media.h linux/videodev2.h" v4l2_timeval_to_ns - check_pkg_config libudev libudev libudev.h udev_new - check_struct linux/videodev2.h "struct v4l2_ctrl_hevc_decode_params" num_delta_pocs_of_ref_rps_idx diff --git a/libavcodec/Makefile b/libavcodec/Makefile -index 3fa9822594..95c77d7bec 100644 +index 5f977bed12f4..c6735d32a511 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile -@@ -1063,6 +1063,7 @@ OBJS-$(CONFIG_VP9_D3D11VA_HWACCEL) += dxva2_vp9.o - OBJS-$(CONFIG_VP9_DXVA2_HWACCEL) += dxva2_vp9.o - OBJS-$(CONFIG_VP9_D3D12VA_HWACCEL) += dxva2_vp9.o d3d12va_vp9.o - OBJS-$(CONFIG_VP9_NVDEC_HWACCEL) += nvdec_vp9.o -+OBJS-$(CONFIG_VP9_V4L2REQUEST_HWACCEL) += v4l2_request_vp9.o - OBJS-$(CONFIG_VP9_VAAPI_HWACCEL) += vaapi_vp9.o - OBJS-$(CONFIG_VP9_VDPAU_HWACCEL) += vdpau_vp9.o - OBJS-$(CONFIG_VP9_VIDEOTOOLBOX_HWACCEL) += videotoolbox_vp9.o +@@ -1051,6 +1051,7 @@ OBJS-$(CONFIG_AV1_D3D11VA_HWACCEL) += dxva2_av1.o + OBJS-$(CONFIG_AV1_DXVA2_HWACCEL) += dxva2_av1.o + OBJS-$(CONFIG_AV1_D3D12VA_HWACCEL) += dxva2_av1.o d3d12va_av1.o + OBJS-$(CONFIG_AV1_NVDEC_HWACCEL) += nvdec_av1.o ++OBJS-$(CONFIG_AV1_V4L2REQUEST_HWACCEL) += v4l2_request_av1.o + OBJS-$(CONFIG_AV1_VAAPI_HWACCEL) += vaapi_av1.o + OBJS-$(CONFIG_AV1_VDPAU_HWACCEL) += vdpau_av1.o + OBJS-$(CONFIG_AV1_VIDEOTOOLBOX_HWACCEL) += videotoolbox_av1.o +diff --git a/libavcodec/av1dec.c b/libavcodec/av1dec.c +index ba8442077a9e..dd89bf857bc5 100644 +--- a/libavcodec/av1dec.c ++++ b/libavcodec/av1dec.c +@@ -542,6 +542,7 @@ static int get_pixel_format(AVCodecContext *avctx) + CONFIG_AV1_D3D11VA_HWACCEL * 2 + \ + CONFIG_AV1_D3D12VA_HWACCEL + \ + CONFIG_AV1_NVDEC_HWACCEL + \ ++ CONFIG_AV1_V4L2REQUEST_HWACCEL + \ + CONFIG_AV1_VAAPI_HWACCEL + \ + CONFIG_AV1_VDPAU_HWACCEL + \ + CONFIG_AV1_VIDEOTOOLBOX_HWACCEL + \ +@@ -577,6 +578,9 @@ static int get_pixel_format(AVCodecContext *avctx) + #endif + #if CONFIG_AV1_VULKAN_HWACCEL + *fmtp++ = AV_PIX_FMT_VULKAN; ++#endif ++#if CONFIG_AV1_V4L2REQUEST_HWACCEL ++ *fmtp++ = AV_PIX_FMT_DRM_PRIME; + #endif + break; + case AV_PIX_FMT_YUV420P10: +@@ -604,6 +608,9 @@ static int get_pixel_format(AVCodecContext *avctx) + #endif + #if CONFIG_AV1_VULKAN_HWACCEL + *fmtp++ = AV_PIX_FMT_VULKAN; ++#endif ++#if CONFIG_AV1_V4L2REQUEST_HWACCEL ++ *fmtp++ = AV_PIX_FMT_DRM_PRIME; + #endif + break; + case AV_PIX_FMT_YUV420P12: +@@ -1630,6 +1637,9 @@ const FFCodec ff_av1_decoder = { + #if CONFIG_AV1_VULKAN_HWACCEL + HWACCEL_VULKAN(av1), + #endif ++#if CONFIG_AV1_V4L2REQUEST_HWACCEL ++ HWACCEL_V4L2REQUEST(av1), ++#endif + + NULL + }, diff --git a/libavcodec/hwaccels.h b/libavcodec/hwaccels.h -index cb2cdb3893..8571cc7e8b 100644 +index ca47a3c90605..7b6f67330a3c 100644 --- a/libavcodec/hwaccels.h +++ b/libavcodec/hwaccels.h -@@ -83,6 +83,7 @@ extern const struct FFHWAccel ff_vp9_d3d11va2_hwaccel; - extern const struct FFHWAccel ff_vp9_d3d12va_hwaccel; - extern const struct FFHWAccel ff_vp9_dxva2_hwaccel; - extern const struct FFHWAccel ff_vp9_nvdec_hwaccel; -+extern const struct FFHWAccel ff_vp9_v4l2request_hwaccel; - extern const struct FFHWAccel ff_vp9_vaapi_hwaccel; - extern const struct FFHWAccel ff_vp9_vdpau_hwaccel; - extern const struct FFHWAccel ff_vp9_videotoolbox_hwaccel; -diff --git a/libavcodec/v4l2_request_vp9.c b/libavcodec/v4l2_request_vp9.c +@@ -24,6 +24,7 @@ extern const struct FFHWAccel ff_av1_d3d11va2_hwaccel; + extern const struct FFHWAccel ff_av1_d3d12va_hwaccel; + extern const struct FFHWAccel ff_av1_dxva2_hwaccel; + extern const struct FFHWAccel ff_av1_nvdec_hwaccel; ++extern const struct FFHWAccel ff_av1_v4l2request_hwaccel; + extern const struct FFHWAccel ff_av1_vaapi_hwaccel; + extern const struct FFHWAccel ff_av1_vdpau_hwaccel; + extern const struct FFHWAccel ff_av1_videotoolbox_hwaccel; +diff --git a/libavcodec/v4l2_request_av1.c b/libavcodec/v4l2_request_av1.c new file mode 100644 -index 0000000000..41ea4e37f5 +index 000000000000..4eabdbf31b95 --- /dev/null -+++ b/libavcodec/v4l2_request_vp9.c -@@ -0,0 +1,288 @@ ++++ b/libavcodec/v4l2_request_av1.c +@@ -0,0 +1,636 @@ +/* + * This file is part of FFmpeg. + * @@ -4816,671 +5681,758 @@ index 0000000000..41ea4e37f5 + +#include "config.h" + ++#include "libavutil/mem.h" +#include "hwaccel_internal.h" +#include "hwconfig.h" ++#include "av1dec.h" ++#include "internal.h" +#include "v4l2_request.h" -+#include "vp9dec.h" + -+typedef struct V4L2RequestControlsVP9 { ++#define V4L2_AV1_CONTROLS_MAX 4 ++ ++typedef struct V4L2RequestContextAV1 { ++ V4L2RequestContext base; ++ bool has_film_grain; ++} V4L2RequestContextAV1; ++ ++typedef struct V4L2RequestControlsAV1 { + V4L2RequestPictureContext pic; -+ struct v4l2_ctrl_vp9_frame frame; -+ struct v4l2_ctrl_vp9_compressed_hdr chp; -+} V4L2RequestControlsVP9; ++ struct v4l2_ctrl_av1_sequence sequence; ++ struct v4l2_ctrl_av1_frame frame; ++ struct v4l2_ctrl_av1_film_grain film_grain; ++ struct v4l2_ctrl_av1_tile_group_entry tile_group_entry; ++ struct v4l2_ctrl_av1_tile_group_entry *tile_group_entries; ++ unsigned int allocated_tile_group_entries; ++ unsigned int num_tile_group_entries; ++} V4L2RequestControlsAV1; ++ ++static int get_bit_depth_from_seq(const AV1RawSequenceHeader *seq) ++{ ++ if (seq->seq_profile == AV_PROFILE_AV1_PROFESSIONAL && ++ seq->color_config.high_bitdepth) ++ return seq->color_config.twelve_bit ? 12 : 10; ++ else ++ return seq->color_config.high_bitdepth ? 10 : 8; ++} + -+static void v4l2_request_vp9_set_frame_ctx(AVCodecContext *avctx) ++static void fill_sequence(struct v4l2_ctrl_av1_sequence *ctrl, ++ const AV1DecContext *s) +{ -+ VP9Context *s = avctx->priv_data; -+ const VP9Frame *f = &s->s.frames[CUR_FRAME]; -+ V4L2RequestControlsVP9 *controls = f->hwaccel_picture_private; -+ struct v4l2_ctrl_vp9_compressed_hdr *chp = &controls->chp; -+ -+ memset(chp, 0, sizeof(&chp)); -+ -+ chp->tx_mode = s->s.h.txfmmode; -+ memcpy(chp->tx8, s->prob_raw.p.tx8p, sizeof(s->prob_raw.p.tx8p)); -+ memcpy(chp->tx16, s->prob_raw.p.tx16p, sizeof(s->prob_raw.p.tx16p)); -+ memcpy(chp->tx32, s->prob_raw.p.tx32p, sizeof(s->prob_raw.p.tx32p)); -+ for (unsigned i = 0; i < 4; i++) { -+ for (unsigned j = 0; j < 2; j++) { -+ for (unsigned k = 0; k < 2; k++) { -+ for (unsigned l = 0; l < 6; l++) { -+ for (unsigned m = 0; m < 6; m++) { -+ memcpy(chp->coef[i][j][k][l][m], s->prob_raw.coef[i][j][k][l][m], sizeof(chp->coef[0][0][0][0][0])); -+ } -+ } ++ const AV1RawSequenceHeader *seq = s->raw_seq; ++ ++ *ctrl = (struct v4l2_ctrl_av1_sequence) { ++ .seq_profile = seq->seq_profile, ++ .order_hint_bits = seq->enable_order_hint ? ++ seq->order_hint_bits_minus_1 + 1 : 0, ++ .bit_depth = get_bit_depth_from_seq(seq), ++ .max_frame_width_minus_1 = seq->max_frame_width_minus_1, ++ .max_frame_height_minus_1 = seq->max_frame_height_minus_1, ++ }; ++ ++ if (seq->still_picture) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_STILL_PICTURE; ++ ++ if (seq->use_128x128_superblock) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK; ++ ++ if (seq->enable_filter_intra) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_FILTER_INTRA; ++ ++ if (seq->enable_intra_edge_filter) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTRA_EDGE_FILTER; ++ ++ if (seq->enable_interintra_compound) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTERINTRA_COMPOUND; ++ ++ if (seq->enable_masked_compound) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_MASKED_COMPOUND; ++ ++ if (seq->enable_warped_motion) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_WARPED_MOTION; ++ ++ if (seq->enable_dual_filter) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_DUAL_FILTER; ++ ++ if (seq->enable_order_hint) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_ORDER_HINT; ++ ++ if (seq->enable_jnt_comp) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_JNT_COMP; ++ ++ if (seq->enable_ref_frame_mvs) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_REF_FRAME_MVS; ++ ++ if (seq->enable_superres) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_SUPERRES; ++ ++ if (seq->enable_cdef) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_CDEF; ++ ++ if (seq->enable_restoration) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_ENABLE_RESTORATION; ++ ++ if (seq->color_config.mono_chrome) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_MONO_CHROME; ++ ++ if (seq->color_config.color_range) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_COLOR_RANGE; ++ ++ if (seq->color_config.subsampling_x) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_X; ++ ++ if (seq->color_config.subsampling_y) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_Y; ++ ++ if (seq->film_grain_params_present) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_FILM_GRAIN_PARAMS_PRESENT; ++ ++ if (seq->color_config.separate_uv_delta_q) ++ ctrl->flags |= V4L2_AV1_SEQUENCE_FLAG_SEPARATE_UV_DELTA_Q; ++} ++ ++static void fill_frame(struct v4l2_ctrl_av1_frame *ctrl, const AV1DecContext *s) ++{ ++ const AV1RawFrameHeader *frame_header = s->raw_frame_header; ++ const CodedBitstreamAV1Context *cbctx = s->cbc->priv_data; ++ uint8_t remap_lr_type[4] = { ++ V4L2_AV1_FRAME_RESTORE_NONE, ++ V4L2_AV1_FRAME_RESTORE_SWITCHABLE, ++ V4L2_AV1_FRAME_RESTORE_WIENER, ++ V4L2_AV1_FRAME_RESTORE_SGRPROJ, ++ }; ++ int i, j; ++ ++ *ctrl = (struct v4l2_ctrl_av1_frame) { ++ .tile_info = { ++ .context_update_tile_id = frame_header->context_update_tile_id, ++ .tile_cols = frame_header->tile_cols, ++ .tile_rows = frame_header->tile_rows, ++ .tile_size_bytes = frame_header->tile_cols_log2 > 0 || ++ frame_header->tile_rows_log2 > 0 ? ++ frame_header->tile_size_bytes_minus1 + 1 : 0, ++ }, ++ ++ .quantization = { ++ .base_q_idx = frame_header->base_q_idx, ++ .delta_q_y_dc = frame_header->delta_q_y_dc, ++ .delta_q_u_dc = frame_header->delta_q_u_dc, ++ .delta_q_u_ac = frame_header->delta_q_u_ac, ++ .delta_q_v_dc = frame_header->delta_q_v_dc, ++ .delta_q_v_ac = frame_header->delta_q_v_ac, ++ .qm_y = frame_header->qm_y, ++ .qm_u = frame_header->qm_u, ++ .qm_v = frame_header->qm_v, ++ .delta_q_res = frame_header->delta_q_res, ++ }, ++ ++ .loop_filter = { ++ .level[0] = frame_header->loop_filter_level[0], ++ .level[1] = frame_header->loop_filter_level[1], ++ .level[2] = frame_header->loop_filter_level[2], ++ .level[3] = frame_header->loop_filter_level[3], ++ .sharpness = frame_header->loop_filter_sharpness, ++ .mode_deltas[0] = frame_header->loop_filter_mode_deltas[0], ++ .mode_deltas[1] = frame_header->loop_filter_mode_deltas[1], ++ .delta_lf_res = frame_header->delta_lf_res, ++ }, ++ ++ .cdef = { ++ .damping_minus_3 = frame_header->cdef_damping_minus_3, ++ .bits = frame_header->cdef_bits, ++ }, ++ ++ .loop_restoration = { ++ .lr_unit_shift = frame_header->lr_unit_shift, ++ .lr_uv_shift = frame_header->lr_uv_shift, ++ }, ++ ++ .superres_denom = frame_header->use_superres ? ++ frame_header->coded_denom + AV1_SUPERRES_DENOM_MIN : ++ AV1_SUPERRES_NUM, ++ .skip_mode_frame[0] = frame_header->skip_mode_present ? ++ s->cur_frame.skip_mode_frame_idx[0] : 0, ++ .skip_mode_frame[1] = frame_header->skip_mode_present ? ++ s->cur_frame.skip_mode_frame_idx[1] : 0, ++ .primary_ref_frame = frame_header->primary_ref_frame, ++ .frame_type = frame_header->frame_type, ++ .order_hint = frame_header->order_hint, ++ .upscaled_width = cbctx->upscaled_width, ++ .interpolation_filter = frame_header->interpolation_filter, ++ .tx_mode = frame_header->tx_mode, ++ .frame_width_minus_1 = cbctx->frame_width - 1, ++ .frame_height_minus_1 = cbctx->frame_height - 1, ++ .render_width_minus_1 = cbctx->render_width - 1, ++ .render_height_minus_1 = cbctx->render_height - 1, ++ .current_frame_id = frame_header->current_frame_id, ++ .refresh_frame_flags = frame_header->refresh_frame_flags, ++ }; ++ ++ if (frame_header->segmentation_enabled) ++ ctrl->segmentation.flags |= V4L2_AV1_SEGMENTATION_FLAG_ENABLED; ++ ++ if (frame_header->segmentation_update_map) ++ ctrl->segmentation.flags |= V4L2_AV1_SEGMENTATION_FLAG_UPDATE_MAP; ++ ++ if (frame_header->segmentation_temporal_update) ++ ctrl->segmentation.flags |= V4L2_AV1_SEGMENTATION_FLAG_TEMPORAL_UPDATE; ++ ++ if (frame_header->segmentation_update_data) ++ ctrl->segmentation.flags |= V4L2_AV1_SEGMENTATION_FLAG_UPDATE_DATA; ++ ++ for (i = 0; i < AV1_MAX_SEGMENTS; i++) { ++ for (j = 0; j < AV1_SEG_LVL_MAX; j++) { ++ if (frame_header->feature_enabled[i][j]) { ++ ctrl->segmentation.feature_enabled[i] |= V4L2_AV1_SEGMENT_FEATURE_ENABLED(j); ++ ctrl->segmentation.last_active_seg_id = i; ++ if (j >= AV1_SEG_LVL_REF_FRAME) ++ ctrl->segmentation.flags |= V4L2_AV1_SEGMENTATION_FLAG_SEG_ID_PRE_SKIP; + } ++ ctrl->segmentation.feature_data[i][j] = frame_header->feature_value[i][j]; + } + } -+ memcpy(chp->skip, s->prob_raw.p.skip, sizeof(s->prob_raw.p.skip)); -+ memcpy(chp->inter_mode, s->prob_raw.p.mv_mode, sizeof(s->prob_raw.p.mv_mode)); -+ memcpy(chp->interp_filter, s->prob_raw.p.filter, sizeof(s->prob_raw.p.filter)); -+ memcpy(chp->is_inter, s->prob_raw.p.intra, sizeof(s->prob_raw.p.intra)); -+ memcpy(chp->comp_mode, s->prob_raw.p.comp, sizeof(s->prob_raw.p.comp)); -+ memcpy(chp->single_ref, s->prob_raw.p.single_ref, sizeof(s->prob_raw.p.single_ref)); -+ memcpy(chp->comp_ref, s->prob_raw.p.comp_ref, sizeof(s->prob_raw.p.comp_ref)); -+ memcpy(chp->y_mode, s->prob_raw.p.y_mode, sizeof(s->prob_raw.p.y_mode)); -+ for (unsigned i = 0; i < 10; i++) -+ memcpy(chp->uv_mode[i], s->prob.p.uv_mode[i], sizeof(s->prob.p.uv_mode[0])); -+ for (unsigned i = 0; i < 4; i++) -+ memcpy(chp->partition[i * 4], s->prob_raw.p.partition[i], sizeof(s->prob_raw.p.partition[0])); -+ memcpy(chp->mv.joint, s->prob_raw.p.mv_joint, sizeof(s->prob_raw.p.mv_joint)); -+ for (unsigned i = 0; i < 2; i++) { -+ chp->mv.sign[i] = s->prob_raw.p.mv_comp[i].sign; -+ memcpy(chp->mv.classes[i], s->prob_raw.p.mv_comp[i].classes, sizeof(s->prob_raw.p.mv_comp[0].classes)); -+ chp->mv.class0_bit[i] = s->prob_raw.p.mv_comp[i].class0; -+ memcpy(chp->mv.bits[i], s->prob_raw.p.mv_comp[i].bits, sizeof(s->prob_raw.p.mv_comp[0].bits)); -+ memcpy(chp->mv.class0_fr[i], s->prob_raw.p.mv_comp[i].class0_fp, sizeof(s->prob_raw.p.mv_comp[0].class0_fp)); -+ memcpy(chp->mv.fr[i], s->prob_raw.p.mv_comp[i].fp, sizeof(s->prob_raw.p.mv_comp[0].fp)); -+ chp->mv.class0_hp[i] = s->prob_raw.p.mv_comp[i].class0_hp; -+ chp->mv.hp[i] = s->prob_raw.p.mv_comp[i].hp; ++ ++ if (frame_header->uniform_tile_spacing_flag) ++ ctrl->tile_info.flags |= V4L2_AV1_TILE_INFO_FLAG_UNIFORM_TILE_SPACING; ++ ++ for (i = 0; i < frame_header->tile_cols; i++) { ++ ctrl->tile_info.mi_col_starts[i] = frame_header->tile_start_col_sb[i]; ++ ctrl->tile_info.width_in_sbs_minus_1[i] = frame_header->width_in_sbs_minus_1[i]; + } -+} ++ ctrl->tile_info.mi_col_starts[i] = 2 * ((cbctx->frame_width + 7) >> 3); + -+static void fill_frame(struct v4l2_ctrl_vp9_frame *dec_params, AVCodecContext *avctx) -+{ -+ const VP9Context *s = avctx->priv_data; -+ AVFrame *ref; ++ for (i = 0; i < frame_header->tile_rows; i++) { ++ ctrl->tile_info.mi_row_starts[i] = frame_header->tile_start_row_sb[i]; ++ ctrl->tile_info.height_in_sbs_minus_1[i] = frame_header->height_in_sbs_minus_1[i]; ++ } ++ ctrl->tile_info.mi_row_starts[i] = 2 * ((cbctx->frame_height + 7) >> 3); + -+ memset(dec_params, 0, sizeof(*dec_params)); ++ if (frame_header->diff_uv_delta) ++ ctrl->quantization.flags |= V4L2_AV1_QUANTIZATION_FLAG_DIFF_UV_DELTA; + -+ if (s->s.h.keyframe) -+ dec_params->flags |= V4L2_VP9_FRAME_FLAG_KEY_FRAME; -+ if (!s->s.h.invisible) -+ dec_params->flags |= V4L2_VP9_FRAME_FLAG_SHOW_FRAME; -+ if (s->s.h.errorres) -+ dec_params->flags |= V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT; -+ if (s->s.h.intraonly) -+ dec_params->flags |= V4L2_VP9_FRAME_FLAG_INTRA_ONLY; -+ if (!s->s.h.keyframe && s->s.h.highprecisionmvs) -+ dec_params->flags |= V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV; -+ if (s->s.h.refreshctx) -+ dec_params->flags |= V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX; -+ if (s->s.h.parallelmode) -+ dec_params->flags |= V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE; -+ if (s->ss_h) -+ dec_params->flags |= V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING; -+ if (s->ss_v) -+ dec_params->flags |= V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING; -+ if (avctx->color_range == AVCOL_RANGE_JPEG) -+ dec_params->flags |= V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING; -+ -+ dec_params->compressed_header_size = s->s.h.compressed_header_size; -+ dec_params->uncompressed_header_size = s->s.h.uncompressed_header_size; -+ dec_params->profile = s->s.h.profile; -+ dec_params->reset_frame_context = s->s.h.resetctx > 0 ? s->s.h.resetctx - 1 : 0; -+ dec_params->frame_context_idx = s->s.h.framectxid; -+ dec_params->bit_depth = s->s.h.bpp; -+ -+ dec_params->interpolation_filter = s->s.h.filtermode ^ (s->s.h.filtermode <= 1); -+ dec_params->tile_cols_log2 = s->s.h.tiling.log2_tile_cols; -+ dec_params->tile_rows_log2 = s->s.h.tiling.log2_tile_rows; -+ dec_params->reference_mode = s->s.h.comppredmode; -+ dec_params->frame_width_minus_1 = s->w - 1; -+ dec_params->frame_height_minus_1 = s->h - 1; -+ //dec_params->render_width_minus_1 = avctx->width - 1; -+ //dec_params->render_height_minus_1 = avctx->height - 1; ++ if (frame_header->using_qmatrix) ++ ctrl->quantization.flags |= V4L2_AV1_QUANTIZATION_FLAG_USING_QMATRIX; ++ ++ if (frame_header->delta_q_present) ++ ctrl->quantization.flags |= V4L2_AV1_QUANTIZATION_FLAG_DELTA_Q_PRESENT; ++ ++ if (frame_header->loop_filter_delta_enabled) ++ ctrl->loop_filter.flags |= V4L2_AV1_LOOP_FILTER_FLAG_DELTA_ENABLED; ++ ++ if (frame_header->loop_filter_delta_update) ++ ctrl->loop_filter.flags |= V4L2_AV1_LOOP_FILTER_FLAG_DELTA_UPDATE; ++ ++ if (frame_header->delta_lf_present) ++ ctrl->loop_filter.flags |= V4L2_AV1_LOOP_FILTER_FLAG_DELTA_LF_PRESENT; ++ ++ if (frame_header->delta_lf_multi) ++ ctrl->loop_filter.flags |= V4L2_AV1_LOOP_FILTER_FLAG_DELTA_LF_MULTI; ++ ++ for (i = 0; i < AV1_NUM_REF_FRAMES; i++) { ++ ctrl->loop_filter.ref_deltas[i] = frame_header->loop_filter_ref_deltas[i]; ++ } ++ ++ for (i = 0; i < cbctx->num_planes; i++) { ++ ctrl->loop_restoration.frame_restoration_type[i] = ++ remap_lr_type[frame_header->lr_type[i]]; ++ if (frame_header->lr_type[i] != AV1_RESTORE_NONE) { ++ ctrl->loop_restoration.flags |= V4L2_AV1_LOOP_RESTORATION_FLAG_USES_LR; ++ if (i > 0) ++ ctrl->loop_restoration.flags |= V4L2_AV1_LOOP_RESTORATION_FLAG_USES_CHROMA_LR; ++ } ++ } ++ if (ctrl->loop_restoration.flags & V4L2_AV1_LOOP_RESTORATION_FLAG_USES_LR) { ++ ctrl->loop_restoration.loop_restoration_size[0] = ++ 1 << (6 + frame_header->lr_unit_shift); ++ ctrl->loop_restoration.loop_restoration_size[1] = ++ 1 << (6 + frame_header->lr_unit_shift - frame_header->lr_uv_shift); ++ ctrl->loop_restoration.loop_restoration_size[2] = ++ 1 << (6 + frame_header->lr_unit_shift - frame_header->lr_uv_shift); ++ } ++ ++ for (i = 0; i < AV1_TOTAL_REFS_PER_FRAME; i++) { ++ ctrl->global_motion.type[i] = s->cur_frame.gm_type[i]; ++ for (j = 0; j < 6; ++j) { ++ ctrl->global_motion.params[i][j] = s->cur_frame.gm_params[i][j]; ++ if (s->cur_frame.gm_invalid[i]) ++ ctrl->global_motion.invalid |= V4L2_AV1_GLOBAL_MOTION_IS_INVALID(i); ++ } ++ ++ if (frame_header->is_global[i]) ++ ctrl->global_motion.flags[i] |= V4L2_AV1_GLOBAL_MOTION_FLAG_IS_GLOBAL; ++ ++ if (frame_header->is_rot_zoom[i]) ++ ctrl->global_motion.flags[i] |= V4L2_AV1_GLOBAL_MOTION_FLAG_IS_ROT_ZOOM; ++ ++ if (frame_header->is_translation[i]) ++ ctrl->global_motion.flags[i] |= V4L2_AV1_GLOBAL_MOTION_FLAG_IS_TRANSLATION; ++ } ++ ++ for (i = 0; i < AV1_TOTAL_REFS_PER_FRAME; i++) { ++ AVFrame *ref = s->ref[i].f; ++ ++ ctrl->order_hints[i] = s->cur_frame.order_hints[i]; ++ if (ref) ++ ctrl->reference_frame_ts[i] = ff_v4l2_request_get_capture_timestamp(ref); ++ if (i < AV1_REFS_PER_FRAME) ++ ctrl->ref_frame_idx[i] = frame_header->ref_frame_idx[i]; ++ } ++ ++ for (i = 0; i < (1 << frame_header->cdef_bits); i++) { ++ ctrl->cdef.y_pri_strength[i] = frame_header->cdef_y_pri_strength[i]; ++ ctrl->cdef.y_sec_strength[i] = frame_header->cdef_y_sec_strength[i]; ++ ctrl->cdef.uv_pri_strength[i] = frame_header->cdef_uv_pri_strength[i]; ++ ctrl->cdef.uv_sec_strength[i] = frame_header->cdef_uv_sec_strength[i]; ++ } ++ ++ if (frame_header->show_frame) ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_SHOW_FRAME; ++ ++ if (frame_header->showable_frame) ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_SHOWABLE_FRAME; ++ ++ if (frame_header->error_resilient_mode) ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_ERROR_RESILIENT_MODE; ++ ++ if (frame_header->disable_cdf_update) ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_DISABLE_CDF_UPDATE; ++ ++ if (frame_header->allow_screen_content_tools) ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_ALLOW_SCREEN_CONTENT_TOOLS; ++ ++ if (s->cur_frame.force_integer_mv) ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_FORCE_INTEGER_MV; ++ ++ if (frame_header->allow_intrabc) ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_ALLOW_INTRABC; ++ ++ if (frame_header->use_superres) ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_USE_SUPERRES; ++ ++ if (frame_header->allow_high_precision_mv) ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_ALLOW_HIGH_PRECISION_MV; ++ ++ if (frame_header->is_motion_mode_switchable) ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_IS_MOTION_MODE_SWITCHABLE; ++ ++ if (frame_header->use_ref_frame_mvs) ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_USE_REF_FRAME_MVS; ++ ++ if (frame_header->disable_frame_end_update_cdf) ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_DISABLE_FRAME_END_UPDATE_CDF; ++ ++ if (frame_header->allow_warped_motion) ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_ALLOW_WARPED_MOTION; ++ ++ if (frame_header->reference_select) ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_REFERENCE_SELECT; ++ ++ if (frame_header->reduced_tx_set) ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_REDUCED_TX_SET; ++ ++ if (frame_header->skip_mode_present) { ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_SKIP_MODE_ALLOWED; // FIXME ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_SKIP_MODE_PRESENT; ++ } ++ ++ if (frame_header->frame_size_override_flag) ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_FRAME_SIZE_OVERRIDE; ++ ++ if (frame_header->buffer_removal_time_present_flag) { ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_BUFFER_REMOVAL_TIME_PRESENT; ++ for (i = 0; i < AV1_MAX_OPERATING_POINTS; i++) ++ ctrl->buffer_removal_time[i] = frame_header->buffer_removal_time[i]; ++ } + -+ ref = s->s.refs[s->s.h.refidx[0]].f; -+ if (ref && ref->buf[0]) -+ dec_params->last_frame_ts = ff_v4l2_request_get_capture_timestamp(ref); -+ ref = s->s.refs[s->s.h.refidx[1]].f; -+ if (ref && ref->buf[0]) -+ dec_params->golden_frame_ts = ff_v4l2_request_get_capture_timestamp(ref); -+ ref = s->s.refs[s->s.h.refidx[2]].f; -+ if (ref && ref->buf[0]) -+ dec_params->alt_frame_ts = ff_v4l2_request_get_capture_timestamp(ref); ++ if (frame_header->frame_refs_short_signaling) ++ ctrl->flags |= V4L2_AV1_FRAME_FLAG_FRAME_REFS_SHORT_SIGNALING; ++} + -+ if (s->s.h.signbias[0]) -+ dec_params->ref_frame_sign_bias |= V4L2_VP9_SIGN_BIAS_LAST; -+ if (s->s.h.signbias[1]) -+ dec_params->ref_frame_sign_bias |= V4L2_VP9_SIGN_BIAS_GOLDEN; -+ if (s->s.h.signbias[2]) -+ dec_params->ref_frame_sign_bias |= V4L2_VP9_SIGN_BIAS_ALT; ++static void fill_film_grain(struct v4l2_ctrl_av1_film_grain *ctrl, ++ const AV1DecContext *s) ++{ ++ const AV1RawFilmGrainParams *film_grain = &s->cur_frame.film_grain; ++ int i; ++ ++ *ctrl = (struct v4l2_ctrl_av1_film_grain) { ++ .cr_mult = film_grain->cr_mult, ++ .grain_seed = film_grain->grain_seed, ++ .film_grain_params_ref_idx = film_grain->film_grain_params_ref_idx, ++ .num_y_points = film_grain->num_y_points, ++ .num_cb_points = film_grain->num_cb_points, ++ .num_cr_points = film_grain->num_cr_points, ++ .grain_scaling_minus_8 = film_grain->grain_scaling_minus_8, ++ .ar_coeff_lag = film_grain->ar_coeff_lag, ++ .ar_coeff_shift_minus_6 = film_grain->ar_coeff_shift_minus_6, ++ .grain_scale_shift = film_grain->grain_scale_shift, ++ .cb_mult = film_grain->cb_mult, ++ .cb_luma_mult = film_grain->cb_luma_mult, ++ .cr_luma_mult = film_grain->cr_luma_mult, ++ .cb_offset = film_grain->cb_offset, ++ .cr_offset = film_grain->cr_offset, ++ }; + -+ if (s->s.h.lf_delta.enabled) -+ dec_params->lf.flags |= V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED; -+ if (s->s.h.lf_delta.updated) -+ dec_params->lf.flags |= V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE; ++ if (film_grain->apply_grain) ++ ctrl->flags |= V4L2_AV1_FILM_GRAIN_FLAG_APPLY_GRAIN; + -+ dec_params->lf.level = s->s.h.filter.level; -+ dec_params->lf.sharpness = s->s.h.filter.sharpness; -+ for (unsigned i = 0; i < 4; i++) -+ dec_params->lf.ref_deltas[i] = s->s.h.lf_delta.ref[i]; -+ for (unsigned i = 0; i < 2; i++) -+ dec_params->lf.mode_deltas[i] = s->s.h.lf_delta.mode[i]; ++ if (film_grain->update_grain) ++ ctrl->flags |= V4L2_AV1_FILM_GRAIN_FLAG_UPDATE_GRAIN; + -+ dec_params->quant.base_q_idx = s->s.h.yac_qi; -+ dec_params->quant.delta_q_y_dc = s->s.h.ydc_qdelta; -+ dec_params->quant.delta_q_uv_dc = s->s.h.uvdc_qdelta; -+ dec_params->quant.delta_q_uv_ac = s->s.h.uvac_qdelta; ++ if (film_grain->chroma_scaling_from_luma) ++ ctrl->flags |= V4L2_AV1_FILM_GRAIN_FLAG_CHROMA_SCALING_FROM_LUMA; + -+ if (s->s.h.segmentation.enabled) -+ dec_params->seg.flags |= V4L2_VP9_SEGMENTATION_FLAG_ENABLED; -+ if (s->s.h.segmentation.update_map) -+ dec_params->seg.flags |= V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP; -+ if (s->s.h.segmentation.temporal) -+ dec_params->seg.flags |= V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE; -+ if (s->s.h.segmentation.update_data) -+ dec_params->seg.flags |= V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA; -+ if (s->s.h.segmentation.absolute_vals) -+ dec_params->seg.flags |= V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE; ++ if (film_grain->overlap_flag) ++ ctrl->flags |= V4L2_AV1_FILM_GRAIN_FLAG_OVERLAP; + -+ for (unsigned i = 0; i < 7; i++) -+ dec_params->seg.tree_probs[i] = s->s.h.segmentation.prob[i]; ++ if (film_grain->clip_to_restricted_range) ++ ctrl->flags |= V4L2_AV1_FILM_GRAIN_FLAG_CLIP_TO_RESTRICTED_RANGE; + -+ if (s->s.h.segmentation.temporal) { -+ for (unsigned i = 0; i < 3; i++) -+ dec_params->seg.pred_probs[i] = s->s.h.segmentation.pred_prob[i]; -+ } else { -+ memset(dec_params->seg.pred_probs, 255, sizeof(dec_params->seg.pred_probs)); ++ if (!film_grain->apply_grain) ++ return; ++ ++ for (i = 0; i < film_grain->num_y_points; i++) { ++ ctrl->point_y_value[i] = film_grain->point_y_value[i]; ++ ctrl->point_y_scaling[i] = film_grain->point_y_scaling[i]; + } + -+ for (unsigned i = 0; i < 8; i++) { -+ if (s->s.h.segmentation.feat[i].q_enabled) { -+ dec_params->seg.feature_enabled[i] |= 1 << V4L2_VP9_SEG_LVL_ALT_Q; -+ dec_params->seg.feature_data[i][V4L2_VP9_SEG_LVL_ALT_Q] = s->s.h.segmentation.feat[i].q_val; -+ } ++ for (i = 0; i < film_grain->num_cb_points; i++) { ++ ctrl->point_cb_value[i] = film_grain->point_cb_value[i]; ++ ctrl->point_cb_scaling[i] = film_grain->point_cb_scaling[i]; ++ } + -+ if (s->s.h.segmentation.feat[i].lf_enabled) { -+ dec_params->seg.feature_enabled[i] |= 1 << V4L2_VP9_SEG_LVL_ALT_L; -+ dec_params->seg.feature_data[i][V4L2_VP9_SEG_LVL_ALT_L] = s->s.h.segmentation.feat[i].lf_val; -+ } ++ for (i = 0; i < film_grain->num_cr_points; i++) { ++ ctrl->point_cr_value[i] = film_grain->point_cr_value[i]; ++ ctrl->point_cr_scaling[i] = film_grain->point_cr_scaling[i]; ++ } + -+ if (s->s.h.segmentation.feat[i].ref_enabled) { -+ dec_params->seg.feature_enabled[i] |= 1 << V4L2_VP9_SEG_LVL_REF_FRAME; -+ dec_params->seg.feature_data[i][V4L2_VP9_SEG_LVL_REF_FRAME] = s->s.h.segmentation.feat[i].ref_val; -+ } ++ for (i = 0; i < 24; i++) { ++ ctrl->ar_coeffs_y_plus_128[i] = film_grain->ar_coeffs_y_plus_128[i]; ++ } + -+ if (s->s.h.segmentation.feat[i].skip_enabled) -+ dec_params->seg.feature_enabled[i] |= 1 << V4L2_VP9_SEG_LVL_SKIP; ++ for (i = 0; i < 25; i++) { ++ ctrl->ar_coeffs_cb_plus_128[i] = film_grain->ar_coeffs_cb_plus_128[i]; ++ ctrl->ar_coeffs_cr_plus_128[i] = film_grain->ar_coeffs_cr_plus_128[i]; + } +} + -+static int v4l2_request_vp9_start_frame(AVCodecContext *avctx, ++static int v4l2_request_av1_start_frame(AVCodecContext *avctx, ++ av_unused const AVBufferRef *buf_ref, + av_unused const uint8_t *buffer, + av_unused uint32_t size) +{ -+ const VP9SharedContext *h = avctx->priv_data; -+ const VP9Frame *f = &h->frames[CUR_FRAME]; -+ V4L2RequestControlsVP9 *controls = f->hwaccel_picture_private; ++ const AV1DecContext *s = avctx->priv_data; ++ V4L2RequestContextAV1 *ctx = avctx->internal->hwaccel_priv_data; ++ V4L2RequestControlsAV1 *controls = s->cur_frame.hwaccel_picture_private; + int ret; + -+ ret = ff_v4l2_request_start_frame(avctx, &controls->pic, f->tf.f); ++ ret = ff_v4l2_request_start_frame(avctx, &controls->pic, s->cur_frame.f); + if (ret) + return ret; + -+ v4l2_request_vp9_set_frame_ctx(avctx); ++ fill_sequence(&controls->sequence, s); ++ fill_frame(&controls->frame, s); + -+ fill_frame(&controls->frame, avctx); ++ if (ctx->has_film_grain) ++ fill_film_grain(&controls->film_grain, s); ++ ++ controls->tile_group_entries = &controls->tile_group_entry; ++ controls->allocated_tile_group_entries = 0; ++ controls->num_tile_group_entries = 0; + + return 0; +} + -+static int v4l2_request_vp9_decode_slice(AVCodecContext *avctx, ++static int v4l2_request_av1_decode_slice(AVCodecContext *avctx, + const uint8_t *buffer, uint32_t size) +{ -+ const VP9SharedContext *h = avctx->priv_data; -+ V4L2RequestControlsVP9 *controls = h->frames[CUR_FRAME].hwaccel_picture_private; ++ const AV1DecContext *s = avctx->priv_data; ++ const AV1RawFrameHeader *fh = s->raw_frame_header; ++ V4L2RequestControlsAV1 *controls = s->cur_frame.hwaccel_picture_private; ++ ++ controls->num_tile_group_entries = fh->tile_cols * fh->tile_rows; ++ if (controls->num_tile_group_entries > V4L2_AV1_MAX_TILE_COUNT) ++ return AVERROR(EINVAL); ++ ++ if (controls->num_tile_group_entries > 1 && ++ controls->num_tile_group_entries > controls->allocated_tile_group_entries) { ++ struct v4l2_ctrl_av1_tile_group_entry *tile_group_entries; ++ ++ tile_group_entries = av_realloc_array(controls->allocated_tile_group_entries ? ++ controls->tile_group_entries : NULL, ++ controls->num_tile_group_entries, ++ sizeof(*controls->tile_group_entries)); ++ if (!tile_group_entries) ++ return AVERROR(ENOMEM); ++ ++ if (!controls->allocated_tile_group_entries) ++ memcpy(tile_group_entries, controls->tile_group_entries, ++ sizeof(*controls->tile_group_entries)); ++ ++ controls->tile_group_entries = tile_group_entries; ++ controls->allocated_tile_group_entries = controls->num_tile_group_entries; ++ } ++ ++ for (int i = 0; i < controls->num_tile_group_entries; i++) { ++ controls->tile_group_entries[i] = (struct v4l2_ctrl_av1_tile_group_entry) { ++ .tile_offset = controls->pic.output->bytesused + ++ s->tile_group_info[i].tile_offset, ++ .tile_size = s->tile_group_info[i].tile_size, ++ .tile_row = s->tile_group_info[i].tile_row, ++ .tile_col = s->tile_group_info[i].tile_column, ++ }; ++ } + + return ff_v4l2_request_append_output(avctx, &controls->pic, buffer, size); +} + -+static int v4l2_request_vp9_end_frame(AVCodecContext *avctx) ++static int v4l2_request_av1_end_frame(AVCodecContext *avctx) +{ -+ const VP9SharedContext *h = avctx->priv_data; -+ V4L2RequestControlsVP9 *controls = h->frames[CUR_FRAME].hwaccel_picture_private; ++ const AV1DecContext *s = avctx->priv_data; ++ V4L2RequestContextAV1 *ctx = avctx->internal->hwaccel_priv_data; ++ V4L2RequestControlsAV1 *controls = s->cur_frame.hwaccel_picture_private; ++ int count = 0; + -+ struct v4l2_ext_control control[] = { -+ { -+ .id = V4L2_CID_STATELESS_VP9_FRAME, -+ .ptr = &controls->frame, -+ .size = sizeof(controls->frame), -+ }, -+ { -+ .id = V4L2_CID_STATELESS_VP9_COMPRESSED_HDR, -+ .ptr = &controls->chp, -+ .size = sizeof(controls->chp), -+ }, ++ struct v4l2_ext_control control[V4L2_AV1_CONTROLS_MAX] = {}; ++ ++ control[count++] = (struct v4l2_ext_control) { ++ .id = V4L2_CID_STATELESS_AV1_SEQUENCE, ++ .ptr = &controls->sequence, ++ .size = sizeof(controls->sequence), + }; + -+ return ff_v4l2_request_decode_frame(avctx, &controls->pic, -+ control, FF_ARRAY_ELEMS(control)); ++ control[count++] = (struct v4l2_ext_control) { ++ .id = V4L2_CID_STATELESS_AV1_FRAME, ++ .ptr = &controls->frame, ++ .size = sizeof(controls->frame), ++ }; ++ ++ control[count++] = (struct v4l2_ext_control) { ++ .id = V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY, ++ .ptr = controls->tile_group_entries, ++ .size = sizeof(*controls->tile_group_entries) * ++ FFMAX(controls->num_tile_group_entries, 1), ++ }; ++ ++ if (ctx->has_film_grain) { ++ control[count++] = (struct v4l2_ext_control) { ++ .id = V4L2_CID_STATELESS_AV1_FILM_GRAIN, ++ .ptr = &controls->film_grain, ++ .size = sizeof(controls->film_grain), ++ }; ++ } ++ ++ return ff_v4l2_request_decode_frame(avctx, &controls->pic, control, count); +} + -+static int v4l2_request_vp9_init(AVCodecContext *avctx) ++static void v4l2_request_av1_free_frame_priv(AVRefStructOpaque hwctx, void *data) +{ -+ struct v4l2_ctrl_vp9_frame frame; ++ V4L2RequestControlsAV1 *controls = data; ++ ++ if (controls->allocated_tile_group_entries) ++ av_freep(&controls->tile_group_entries); ++} ++ ++static int v4l2_request_av1_post_frames_ctx(AVCodecContext *avctx) ++{ ++ V4L2RequestContextAV1 *ctx = avctx->internal->hwaccel_priv_data; ++ ++ struct v4l2_query_ext_ctrl film_grain = { ++ .id = V4L2_CID_STATELESS_AV1_FILM_GRAIN, ++ }; ++ ++ // TODO: check V4L2_CID_MPEG_VIDEO_AV1_PROFILE ++ // TODO: check V4L2_CID_MPEG_VIDEO_AV1_LEVEL ++ ++ if (!ff_v4l2_request_query_control(avctx, &film_grain)) ++ ctx->has_film_grain = true; ++ else ++ ctx->has_film_grain = false; ++ ++ return 0; ++} ++ ++static int v4l2_request_av1_init(AVCodecContext *avctx) ++{ ++ const AV1DecContext *s = avctx->priv_data; ++ struct v4l2_ctrl_av1_sequence sequence; + + struct v4l2_ext_control control[] = { + { -+ .id = V4L2_CID_STATELESS_VP9_FRAME, -+ .ptr = &frame, -+ .size = sizeof(frame), ++ .id = V4L2_CID_STATELESS_AV1_SEQUENCE, ++ .ptr = &sequence, ++ .size = sizeof(sequence), + }, + }; + -+ fill_frame(&frame, avctx); ++ fill_sequence(&sequence, s); + -+ // TODO: check V4L2_CID_MPEG_VIDEO_VP9_PROFILE -+ // TODO: check V4L2_CID_MPEG_VIDEO_VP9_LEVEL ++ return ff_v4l2_request_init(avctx, control, FF_ARRAY_ELEMS(control), ++ v4l2_request_av1_post_frames_ctx); ++} ++ ++static int v4l2_request_av1_frame_params(AVCodecContext *avctx, ++ AVBufferRef *hw_frames_ctx) ++{ ++ const AV1DecContext *s = avctx->priv_data; ++ const AV1RawSequenceHeader *seq = s ? s->raw_seq : NULL; ++ uint8_t bit_depth = seq ? get_bit_depth_from_seq(seq) : 0; + -+ return ff_v4l2_request_init(avctx, V4L2_PIX_FMT_VP9_FRAME, -+ 3 * 1024 * 1024, -+ control, FF_ARRAY_ELEMS(control)); ++ return ff_v4l2_request_frame_params(avctx, hw_frames_ctx, ++ V4L2_PIX_FMT_AV1_FRAME, bit_depth); +} + -+const FFHWAccel ff_vp9_v4l2request_hwaccel = { -+ .p.name = "vp9_v4l2request", ++const FFHWAccel ff_av1_v4l2request_hwaccel = { ++ .p.name = "av1_v4l2request", + .p.type = AVMEDIA_TYPE_VIDEO, -+ .p.id = AV_CODEC_ID_VP9, ++ .p.id = AV_CODEC_ID_AV1, + .p.pix_fmt = AV_PIX_FMT_DRM_PRIME, -+ .start_frame = v4l2_request_vp9_start_frame, -+ .decode_slice = v4l2_request_vp9_decode_slice, -+ .end_frame = v4l2_request_vp9_end_frame, ++ .start_frame = v4l2_request_av1_start_frame, ++ .decode_slice = v4l2_request_av1_decode_slice, ++ .end_frame = v4l2_request_av1_end_frame, + .flush = ff_v4l2_request_flush, -+ .frame_priv_data_size = sizeof(V4L2RequestControlsVP9), -+ .init = v4l2_request_vp9_init, ++ .free_frame_priv = v4l2_request_av1_free_frame_priv, ++ .frame_priv_data_size = sizeof(V4L2RequestControlsAV1), ++ .init = v4l2_request_av1_init, + .uninit = ff_v4l2_request_uninit, -+ .priv_data_size = sizeof(V4L2RequestContext), -+ .frame_params = ff_v4l2_request_frame_params, ++ .priv_data_size = sizeof(V4L2RequestContextAV1), ++ .frame_params = v4l2_request_av1_frame_params, ++ .caps_internal = HWACCEL_CAP_ASYNC_SAFE, +}; -diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c -index 8ede2e2eb3..17b611bfdd 100644 ---- a/libavcodec/vp9.c -+++ b/libavcodec/vp9.c -@@ -163,6 +163,7 @@ static int update_size(AVCodecContext *avctx, int w, int h) - CONFIG_VP9_D3D11VA_HWACCEL * 2 + \ - CONFIG_VP9_D3D12VA_HWACCEL + \ - CONFIG_VP9_NVDEC_HWACCEL + \ -+ CONFIG_VP9_V4L2REQUEST_HWACCEL + \ - CONFIG_VP9_VAAPI_HWACCEL + \ - CONFIG_VP9_VDPAU_HWACCEL + \ - CONFIG_VP9_VIDEOTOOLBOX_HWACCEL) -@@ -202,6 +203,9 @@ static int update_size(AVCodecContext *avctx, int w, int h) + +From 6d218019f1d8294ab17648358a3259082d9b64a4 Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Sun, 14 Dec 2025 01:12:06 +0000 +Subject: [PATCH 12/13] avutil/hwcontext_v4l2request: Add support for + AFBC_16X16_SPLIT pix fmts + +Add support for YUV420_8_AFBC_16X16_SPLIT and YUV420_10_AFBC_16X16_SPLIT +used by Cedrus decoder. + +Signed-off-by: Jernej Skrabec +Signed-off-by: Jonas Karlman +--- + libavutil/hwcontext_v4l2request.c | 40 +++++++++++++++++++++++++------ + 1 file changed, 33 insertions(+), 7 deletions(-) + +diff --git a/libavutil/hwcontext_v4l2request.c b/libavutil/hwcontext_v4l2request.c +index f99eea6eaeb8..59abb94b148c 100644 +--- a/libavutil/hwcontext_v4l2request.c ++++ b/libavutil/hwcontext_v4l2request.c +@@ -85,6 +85,28 @@ static const struct { + { V4L2_PIX_FMT_NV12MT_10_COL128, AV_PIX_FMT_YUV420P10, DRM_FORMAT_P030, DRM_FORMAT_MOD_BROADCOM_SAND128, 10 }, #endif - #if CONFIG_VP9_VIDEOTOOLBOX_HWACCEL - *fmtp++ = AV_PIX_FMT_VIDEOTOOLBOX; -+#endif -+#if CONFIG_VP9_V4L2REQUEST_HWACCEL -+ *fmtp++ = AV_PIX_FMT_DRM_PRIME; #endif - break; - case AV_PIX_FMT_YUV420P12: -@@ -375,7 +379,7 @@ static av_always_inline int inv_recenter_nonneg(int v, int m) - } - - // differential forward probability updates --static int update_prob(VPXRangeCoder *c, int p) -+static int read_prob_delta(VPXRangeCoder *c) - { - static const uint8_t inv_map_table[255] = { - 7, 20, 33, 46, 59, 72, 85, 98, 111, 124, 137, 150, 163, 176, -@@ -429,8 +433,13 @@ static int update_prob(VPXRangeCoder *c, int p) - av_assert2(d < FF_ARRAY_ELEMS(inv_map_table)); - } - -- return p <= 128 ? 1 + inv_recenter_nonneg(inv_map_table[d], p - 1) : -- 255 - inv_recenter_nonneg(inv_map_table[d], 255 - p); -+ return inv_map_table[d]; -+} -+ -+static int update_prob(int p, int d) -+{ -+ return p <= 128 ? 1 + inv_recenter_nonneg(d, p - 1) : -+ 255 - inv_recenter_nonneg(d, 255 - p); - } - - static int read_colorspace_details(AVCodecContext *avctx) -@@ -697,7 +706,8 @@ static int decode_frame_header(AVCodecContext *avctx, - get_bits(&s->gb, 8) : 255; - } - -- if (get_bits1(&s->gb)) { -+ s->s.h.segmentation.update_data = get_bits1(&s->gb); -+ if (s->s.h.segmentation.update_data) { - s->s.h.segmentation.absolute_vals = get_bits1(&s->gb); - for (i = 0; i < 8; i++) { - if ((s->s.h.segmentation.feat[i].q_enabled = get_bits1(&s->gb))) -@@ -903,6 +913,8 @@ static int decode_frame_header(AVCodecContext *avctx, - * as explicit copies if the fw update is missing (and skip the copy upon - * fw update)? */ - s->prob.p = s->prob_ctx[c].p; -+ memset(&s->prob_raw.p, 0, sizeof(s->prob_raw.p)); -+ memset(&s->prob_raw.coef, 0, sizeof(s->prob_raw.coef)); - - // txfm updates - if (s->s.h.lossless) { -@@ -914,18 +926,25 @@ static int decode_frame_header(AVCodecContext *avctx, ++#if defined(V4L2_PIX_FMT_YUV420_8_AFBC_16X16_SPLIT) ++ { ++ .pixelformat = V4L2_PIX_FMT_YUV420_8_AFBC_16X16_SPLIT, ++ .sw_format = AV_PIX_FMT_YUV420P, ++ .drm_format = DRM_FORMAT_YUV420_8BIT, ++ .format_modifier = DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | ++ AFBC_FORMAT_MOD_SPARSE | ++ AFBC_FORMAT_MOD_SPLIT), ++ .bit_depth = 8, ++ }, ++#endif ++#if defined(V4L2_PIX_FMT_YUV420_10_AFBC_16X16_SPLIT) ++ { ++ .pixelformat = V4L2_PIX_FMT_YUV420_10_AFBC_16X16_SPLIT, ++ .sw_format = AV_PIX_FMT_YUV420P10, ++ .drm_format = DRM_FORMAT_YUV420_10BIT, ++ .format_modifier = DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | ++ AFBC_FORMAT_MOD_SPARSE | ++ AFBC_FORMAT_MOD_SPLIT), ++ .bit_depth = 10, ++ }, ++#endif + }; - if (s->s.h.txfmmode == TX_SWITCHABLE) { - for (i = 0; i < 2; i++) -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -- s->prob.p.tx8p[i] = update_prob(&s->c, s->prob.p.tx8p[i]); -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.tx8p[i] = read_prob_delta(&s->c); -+ s->prob.p.tx8p[i] = update_prob(s->prob.p.tx8p[i], -+ s->prob_raw.p.tx8p[i]); -+ } - for (i = 0; i < 2; i++) - for (j = 0; j < 2; j++) -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -- s->prob.p.tx16p[i][j] = -- update_prob(&s->c, s->prob.p.tx16p[i][j]); -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.tx16p[i][j] = read_prob_delta(&s->c); -+ s->prob.p.tx16p[i][j] = update_prob(s->prob.p.tx16p[i][j], -+ s->prob_raw.p.tx16p[i][j]); -+ } - for (i = 0; i < 2; i++) - for (j = 0; j < 3; j++) -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -- s->prob.p.tx32p[i][j] = -- update_prob(&s->c, s->prob.p.tx32p[i][j]); -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.tx32p[i][j] = read_prob_delta(&s->c); -+ s->prob.p.tx32p[i][j] = update_prob(s->prob.p.tx32p[i][j], -+ s->prob_raw.p.tx32p[i][j]); -+ } - } + static int v4l2request_set_drm_descriptor(AVDRMFrameDescriptor *desc, +@@ -115,7 +137,7 @@ static int v4l2request_set_drm_descriptor(AVDRMFrameDescriptor *desc, } -@@ -937,15 +956,18 @@ static int decode_frame_header(AVCodecContext *avctx, - for (k = 0; k < 2; k++) - for (l = 0; l < 6; l++) - for (m = 0; m < 6; m++) { -+ uint8_t *pd = s->prob_raw.coef[i][j][k][l][m]; - uint8_t *p = s->prob.coef[i][j][k][l][m]; - uint8_t *r = ref[j][k][l][m]; - if (m >= 3 && l == 0) // dc only has 3 pt - break; - for (n = 0; n < 3; n++) { -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -- p[n] = update_prob(&s->c, r[n]); -- else -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ pd[n] = read_prob_delta(&s->c); -+ p[n] = update_prob(r[n], pd[n]); -+ } else { - p[n] = r[n]; -+ } - } - memcpy(&p[3], ff_vp9_model_pareto8[p[2]], 8); - } -@@ -968,25 +990,37 @@ static int decode_frame_header(AVCodecContext *avctx, - - // mode updates - for (i = 0; i < 3; i++) -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -- s->prob.p.skip[i] = update_prob(&s->c, s->prob.p.skip[i]); -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.skip[i] = read_prob_delta(&s->c); -+ s->prob.p.skip[i] = update_prob(s->prob.p.skip[i], -+ s->prob_raw.p.skip[i]); -+ } - if (!s->s.h.keyframe && !s->s.h.intraonly) { - for (i = 0; i < 7; i++) - for (j = 0; j < 3; j++) -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.mv_mode[i][j] = read_prob_delta(&s->c); - s->prob.p.mv_mode[i][j] = -- update_prob(&s->c, s->prob.p.mv_mode[i][j]); -+ update_prob(s->prob.p.mv_mode[i][j], -+ s->prob_raw.p.mv_mode[i][j]); -+ } - - if (s->s.h.filtermode == FILTER_SWITCHABLE) - for (i = 0; i < 4; i++) - for (j = 0; j < 2; j++) -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.filter[i][j] = read_prob_delta(&s->c); - s->prob.p.filter[i][j] = -- update_prob(&s->c, s->prob.p.filter[i][j]); -+ update_prob(s->prob.p.filter[i][j], -+ s->prob_raw.p.filter[i][j]); -+ } - - for (i = 0; i < 4; i++) -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -- s->prob.p.intra[i] = update_prob(&s->c, s->prob.p.intra[i]); -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.intra[i] = read_prob_delta(&s->c); -+ s->prob.p.intra[i] = update_prob(s->prob.p.intra[i], -+ s->prob_raw.p.intra[i]); -+ } - - if (s->s.h.allowcompinter) { - s->s.h.comppredmode = vp89_rac_get(&s->c); -@@ -994,92 +1028,134 @@ static int decode_frame_header(AVCodecContext *avctx, - s->s.h.comppredmode += vp89_rac_get(&s->c); - if (s->s.h.comppredmode == PRED_SWITCHABLE) - for (i = 0; i < 5; i++) -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.comp[i] = read_prob_delta(&s->c); - s->prob.p.comp[i] = -- update_prob(&s->c, s->prob.p.comp[i]); -+ update_prob(s->prob.p.comp[i], s->prob_raw.p.comp[i]); -+ } - } else { - s->s.h.comppredmode = PRED_SINGLEREF; - } - - if (s->s.h.comppredmode != PRED_COMPREF) { - for (i = 0; i < 5; i++) { -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.single_ref[i][0] = read_prob_delta(&s->c); - s->prob.p.single_ref[i][0] = -- update_prob(&s->c, s->prob.p.single_ref[i][0]); -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -+ update_prob(s->prob.p.single_ref[i][0], -+ s->prob_raw.p.single_ref[i][0]); -+ } -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.single_ref[i][1] = read_prob_delta(&s->c); - s->prob.p.single_ref[i][1] = -- update_prob(&s->c, s->prob.p.single_ref[i][1]); -+ update_prob(s->prob.p.single_ref[i][1], -+ s->prob_raw.p.single_ref[i][1]); -+ } - } - } - - if (s->s.h.comppredmode != PRED_SINGLEREF) { - for (i = 0; i < 5; i++) -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.comp_ref[i] = read_prob_delta(&s->c); - s->prob.p.comp_ref[i] = -- update_prob(&s->c, s->prob.p.comp_ref[i]); -+ update_prob(s->prob.p.comp_ref[i], -+ s->prob_raw.p.comp_ref[i]); -+ } - } - - for (i = 0; i < 4; i++) - for (j = 0; j < 9; j++) -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.y_mode[i][j] = read_prob_delta(&s->c); - s->prob.p.y_mode[i][j] = -- update_prob(&s->c, s->prob.p.y_mode[i][j]); -+ update_prob(s->prob.p.y_mode[i][j], -+ s->prob_raw.p.y_mode[i][j]); -+ } - - for (i = 0; i < 4; i++) - for (j = 0; j < 4; j++) - for (k = 0; k < 3; k++) -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.partition[i][j][k] = read_prob_delta(&s->c); - s->prob.p.partition[3 - i][j][k] = -- update_prob(&s->c, -- s->prob.p.partition[3 - i][j][k]); -+ update_prob(s->prob.p.partition[3 - i][j][k], -+ s->prob_raw.p.partition[i][j][k]); -+ } - - // mv fields don't use the update_prob subexp model for some reason - for (i = 0; i < 3; i++) -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -- s->prob.p.mv_joint[i] = (vp89_rac_get_uint(&s->c, 7) << 1) | 1; -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.mv_joint[i] = (vp89_rac_get_uint(&s->c, 7) << 1) | 1; -+ s->prob.p.mv_joint[i] = s->prob_raw.p.mv_joint[i]; -+ } - - for (i = 0; i < 2; i++) { -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -- s->prob.p.mv_comp[i].sign = -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.mv_comp[i].sign = - (vp89_rac_get_uint(&s->c, 7) << 1) | 1; -+ s->prob.p.mv_comp[i].sign = -+ s->prob_raw.p.mv_comp[i].sign; -+ } - - for (j = 0; j < 10; j++) -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -- s->prob.p.mv_comp[i].classes[j] = -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.mv_comp[i].classes[j] = - (vp89_rac_get_uint(&s->c, 7) << 1) | 1; -+ s->prob.p.mv_comp[i].classes[j] = -+ s->prob_raw.p.mv_comp[i].classes[j]; -+ } - -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -- s->prob.p.mv_comp[i].class0 = -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.mv_comp[i].class0 = - (vp89_rac_get_uint(&s->c, 7) << 1) | 1; -+ s->prob.p.mv_comp[i].class0 = -+ s->prob_raw.p.mv_comp[i].class0; -+ } - - for (j = 0; j < 10; j++) -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -- s->prob.p.mv_comp[i].bits[j] = -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.mv_comp[i].bits[j] = - (vp89_rac_get_uint(&s->c, 7) << 1) | 1; -+ s->prob.p.mv_comp[i].bits[j] = -+ s->prob_raw.p.mv_comp[i].bits[j]; -+ } - } - - for (i = 0; i < 2; i++) { - for (j = 0; j < 2; j++) - for (k = 0; k < 3; k++) -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -- s->prob.p.mv_comp[i].class0_fp[j][k] = -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.mv_comp[i].class0_fp[j][k] = - (vp89_rac_get_uint(&s->c, 7) << 1) | 1; -+ s->prob.p.mv_comp[i].class0_fp[j][k] = -+ s->prob_raw.p.mv_comp[i].class0_fp[j][k]; -+ } - - for (j = 0; j < 3; j++) -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -- s->prob.p.mv_comp[i].fp[j] = -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.mv_comp[i].fp[j] = - (vp89_rac_get_uint(&s->c, 7) << 1) | 1; -+ s->prob.p.mv_comp[i].fp[j] = -+ s->prob_raw.p.mv_comp[i].fp[j]; -+ } - } + desc->nb_layers = 1; +- layer->nb_planes = 2; ++ layer->nb_planes = 1; - if (s->s.h.highprecisionmvs) { - for (i = 0; i < 2; i++) { -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -- s->prob.p.mv_comp[i].class0_hp = -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.mv_comp[i].class0_hp = - (vp89_rac_get_uint(&s->c, 7) << 1) | 1; -+ s->prob.p.mv_comp[i].class0_hp = -+ s->prob_raw.p.mv_comp[i].class0_hp; -+ } + layer->planes[0].object_index = 0; + layer->planes[0].offset = 0; +@@ -123,12 +145,16 @@ static int v4l2request_set_drm_descriptor(AVDRMFrameDescriptor *desc, + format->fmt.pix_mp.plane_fmt[0].bytesperline : + format->fmt.pix.bytesperline; -- if (vpx_rac_get_prob_branchy(&s->c, 252)) -- s->prob.p.mv_comp[i].hp = -+ if (vpx_rac_get_prob_branchy(&s->c, 252)) { -+ s->prob_raw.p.mv_comp[i].hp = - (vp89_rac_get_uint(&s->c, 7) << 1) | 1; -+ s->prob.p.mv_comp[i].hp = -+ s->prob_raw.p.mv_comp[i].hp; -+ } - } - } - } -@@ -1870,6 +1946,9 @@ const FFCodec ff_vp9_decoder = { - #endif - #if CONFIG_VP9_VIDEOTOOLBOX_HWACCEL - HWACCEL_VIDEOTOOLBOX(vp9), -+#endif -+#if CONFIG_VP9_V4L2REQUEST_HWACCEL -+ HWACCEL_V4L2REQUEST(vp9), - #endif - NULL - }, -diff --git a/libavcodec/vp9dec.h b/libavcodec/vp9dec.h -index 81dc801052..99df1cb730 100644 ---- a/libavcodec/vp9dec.h -+++ b/libavcodec/vp9dec.h -@@ -134,6 +134,10 @@ typedef struct VP9Context { - ProbContext p; - uint8_t coef[4][2][2][6][6][11]; - } prob; -+ struct { -+ ProbContext p; -+ uint8_t coef[4][2][2][6][6][11]; -+ } prob_raw; +- layer->planes[1].object_index = 0; +- layer->planes[1].offset = layer->planes[0].pitch * +- (V4L2_TYPE_IS_MULTIPLANAR(format->type) ? +- format->fmt.pix_mp.height : +- format->fmt.pix.height); +- layer->planes[1].pitch = layer->planes[0].pitch; ++ // AFBC formats only use 1 plane, remaining use 2 planes ++ if ((desc->objects[0].format_modifier >> 56) != DRM_FORMAT_MOD_VENDOR_ARM) { ++ layer->nb_planes = 2; ++ layer->planes[1].object_index = 0; ++ layer->planes[1].offset = layer->planes[0].pitch * ++ (V4L2_TYPE_IS_MULTIPLANAR(format->type) ? ++ format->fmt.pix_mp.height : ++ format->fmt.pix.height); ++ layer->planes[1].pitch = layer->planes[0].pitch; ++ } - // contextual (above) cache - uint8_t *above_partition_ctx; -diff --git a/libavcodec/vp9shared.h b/libavcodec/vp9shared.h -index 8a450c26a6..37e389e9e1 100644 ---- a/libavcodec/vp9shared.h -+++ b/libavcodec/vp9shared.h -@@ -136,6 +136,7 @@ typedef struct VP9BitstreamHeader { - uint8_t temporal; - uint8_t absolute_vals; - uint8_t update_map; -+ uint8_t update_data; - uint8_t prob[7]; - uint8_t pred_prob[3]; - struct { + #if defined(V4L2_PIX_FMT_NV12MT_COL128) && defined(V4L2_PIX_FMT_NV12MT_10_COL128) + // Raspberry Pi formats need special handling -From 904a85173fab816bb3c30652300efa93f2333657 Mon Sep 17 00:00:00 2001 -From: Alex Bee -Date: Sun, 15 Dec 2024 01:16:13 +0100 -Subject: [PATCH 11/11] HACK: avcodec: Don't check VIDIOC_ENUM_FRAMESIZES - step_width / step_height +From b57fbbe50c9b2656fad86a1a7eeabfd2b2a50935 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 14 Dec 2025 01:14:17 +0000 +Subject: [PATCH 13/13] avutil/hwcontext_v4l2request: Add support for + BROADCOM_SAND128 pix fmts -Currently required, since hantro and rkvdec drivers expose wrong values. +Add support for NV12_COL128 and NV12_10_COL128 used by downstream +Raspberry Pi HEVC decoder. -Signed-off-by: Alex Bee +Signed-off-by: Jonas Karlman --- - libavcodec/v4l2_request_probe.c | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) + libavutil/hwcontext_v4l2request.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) -diff --git a/libavcodec/v4l2_request_probe.c b/libavcodec/v4l2_request_probe.c -index 941042ec04..b3b1af3744 100644 ---- a/libavcodec/v4l2_request_probe.c -+++ b/libavcodec/v4l2_request_probe.c -@@ -258,9 +258,7 @@ static int v4l2_request_try_framesize(AVCodecContext *avctx, - } else if ((frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE || - frmsize.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) && - avctx->coded_width <= frmsize.stepwise.max_width && -- avctx->coded_height <= frmsize.stepwise.max_height && -- avctx->coded_width % frmsize.stepwise.step_width == 0 && -- avctx->coded_height % frmsize.stepwise.step_height == 0) { -+ avctx->coded_height <= frmsize.stepwise.max_height) { - return 0; - } +diff --git a/libavutil/hwcontext_v4l2request.c b/libavutil/hwcontext_v4l2request.c +index 59abb94b148c..b6633d9081bc 100644 +--- a/libavutil/hwcontext_v4l2request.c ++++ b/libavutil/hwcontext_v4l2request.c +@@ -107,6 +107,12 @@ static const struct { + .bit_depth = 10, + }, + #endif ++#if defined(V4L2_PIX_FMT_NV12_COL128) && defined(V4L2_PIX_FMT_NV12_10_COL128) ++ { V4L2_PIX_FMT_NV12_COL128, AV_PIX_FMT_YUV420P, DRM_FORMAT_NV12, DRM_FORMAT_MOD_BROADCOM_SAND128, 8 }, ++#if defined(DRM_FORMAT_P030) ++ { V4L2_PIX_FMT_NV12_10_COL128, AV_PIX_FMT_YUV420P10, DRM_FORMAT_P030, DRM_FORMAT_MOD_BROADCOM_SAND128, 10 }, ++#endif ++#endif + }; + + static int v4l2request_set_drm_descriptor(AVDRMFrameDescriptor *desc, +@@ -169,6 +175,25 @@ static int v4l2request_set_drm_descriptor(AVDRMFrameDescriptor *desc, + } + #endif + ++#if defined(V4L2_PIX_FMT_NV12_COL128) && defined(V4L2_PIX_FMT_NV12_10_COL128) ++ // Raspberry Pi formats need special handling ++ if (pixelformat == V4L2_PIX_FMT_NV12_COL128 || ++ pixelformat == V4L2_PIX_FMT_NV12_10_COL128) { ++ desc->objects[0].format_modifier = ++ DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT(layer->planes[0].pitch); ++ layer->planes[1].offset = 128 * ++ (V4L2_TYPE_IS_MULTIPLANAR(format->type) ? ++ format->fmt.pix_mp.height : ++ format->fmt.pix.height); ++ layer->planes[0].pitch = (V4L2_TYPE_IS_MULTIPLANAR(format->type) ? ++ format->fmt.pix_mp.width : ++ format->fmt.pix.width); ++ if (pixelformat == V4L2_PIX_FMT_NV12_10_COL128) ++ layer->planes[0].pitch *= 2; ++ layer->planes[1].pitch = layer->planes[0].pitch; ++ } ++#endif ++ + return 0; + } diff --git a/projects/ROCKNIX/packages/multimedia/ffmpeg/patches/vf-deinterlace-v4l2m2m/ffmpeg-001-vf-deinterlace-v4l2m2m.patch b/projects/ROCKNIX/packages/multimedia/ffmpeg/patches/vf-deinterlace-v4l2m2m/0001-vf-deinterlace-v4l2m2m.patch similarity index 95% rename from projects/ROCKNIX/packages/multimedia/ffmpeg/patches/vf-deinterlace-v4l2m2m/ffmpeg-001-vf-deinterlace-v4l2m2m.patch rename to projects/ROCKNIX/packages/multimedia/ffmpeg/patches/vf-deinterlace-v4l2m2m/0001-vf-deinterlace-v4l2m2m.patch index 0720cc34913..35d819672d6 100644 --- a/projects/ROCKNIX/packages/multimedia/ffmpeg/patches/vf-deinterlace-v4l2m2m/ffmpeg-001-vf-deinterlace-v4l2m2m.patch +++ b/projects/ROCKNIX/packages/multimedia/ffmpeg/patches/vf-deinterlace-v4l2m2m/0001-vf-deinterlace-v4l2m2m.patch @@ -1,4 +1,4 @@ -From accf519d251f366afbbbffb67ebac3553a3c7cbb Mon Sep 17 00:00:00 2001 +From 69dd718a8b4b00cefbc108589895650f35bbc13b Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Tue, 3 Dec 2019 21:01:18 +0100 Subject: [PATCH] Add V4L2 m2m deinterlace filter @@ -7,16 +7,16 @@ Signed-off-by: Alex Bee --- libavfilter/Makefile | 1 + libavfilter/allfilters.c | 1 + - libavfilter/vf_deinterlace_v4l2m2m.c | 1011 ++++++++++++++++++++++++++ - 3 files changed, 1013 insertions(+) + libavfilter/vf_deinterlace_v4l2m2m.c | 1015 ++++++++++++++++++++++++++ + 3 files changed, 1017 insertions(+) create mode 100644 libavfilter/vf_deinterlace_v4l2m2m.c diff --git a/libavfilter/Makefile b/libavfilter/Makefile -index 91487afb21..84adb9ba46 100644 +index a530cfae29be..155ea9127f1c 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile -@@ -272,6 +272,7 @@ OBJS-$(CONFIG_DEFLATE_FILTER) += vf_neighbor.o - OBJS-$(CONFIG_DEFLICKER_FILTER) += vf_deflicker.o +@@ -279,6 +279,7 @@ OBJS-$(CONFIG_DEFLICKER_FILTER) += vf_deflicker.o + OBJS-$(CONFIG_DEINTERLACE_D3D12_FILTER) += vf_deinterlace_d3d12.o OBJS-$(CONFIG_DEINTERLACE_QSV_FILTER) += vf_vpp_qsv.o OBJS-$(CONFIG_DEINTERLACE_VAAPI_FILTER) += vf_deinterlace_vaapi.o vaapi_vpp.o +OBJS-$(CONFIG_DEINTERLACE_V4L2M2M_FILTER) += vf_deinterlace_v4l2m2m.o @@ -24,23 +24,23 @@ index 91487afb21..84adb9ba46 100644 OBJS-$(CONFIG_DELOGO_FILTER) += vf_delogo.o OBJS-$(CONFIG_DENOISE_VAAPI_FILTER) += vf_misc_vaapi.o vaapi_vpp.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c -index 9819f0f95b..c6d93340e6 100644 +index e26859e15914..e037f8ab647f 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c -@@ -248,6 +248,7 @@ extern const AVFilter ff_vf_dedot; - extern const AVFilter ff_vf_deflate; - extern const AVFilter ff_vf_deflicker; - extern const AVFilter ff_vf_deinterlace_qsv; -+extern const AVFilter ff_vf_deinterlace_v4l2m2m; - extern const AVFilter ff_vf_deinterlace_vaapi; - extern const AVFilter ff_vf_dejudder; - extern const AVFilter ff_vf_delogo; +@@ -253,6 +253,7 @@ extern const FFFilter ff_vf_deflate; + extern const FFFilter ff_vf_deflicker; + extern const FFFilter ff_vf_deinterlace_qsv; + extern const FFFilter ff_vf_deinterlace_d3d12; ++extern const FFFilter ff_vf_deinterlace_v4l2m2m; + extern const FFFilter ff_vf_deinterlace_vaapi; + extern const FFFilter ff_vf_dejudder; + extern const FFFilter ff_vf_delogo; diff --git a/libavfilter/vf_deinterlace_v4l2m2m.c b/libavfilter/vf_deinterlace_v4l2m2m.c new file mode 100644 -index 0000000000..bf163279ce +index 000000000000..ef015bb76453 --- /dev/null +++ b/libavfilter/vf_deinterlace_v4l2m2m.c -@@ -0,0 +1,1011 @@ +@@ -0,0 +1,1015 @@ +/* + * This file is part of FFmpeg. + * @@ -664,11 +664,15 @@ index 0000000000..bf163279ce + if (!buf) + return AVERROR(ENOMEM); + -+ if (V4L2_TYPE_IS_MULTIPLANAR(buf->buffer.type)) -+ for (i = 0; i < drm_desc->nb_objects; i++) ++ 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.planes[i].bytesused = buf->plane_info[i].length; ++ } ++ } else { + buf->buffer.m.fd = drm_desc->objects[0].fd; ++ buf->buffer.bytesused = buf->plane_info[0].length; ++ } + + return deint_v4l2m2m_enqueue_buffer(buf); +} @@ -1041,14 +1045,14 @@ index 0000000000..bf163279ce + }, +}; + -+AVFilter ff_vf_deinterlace_v4l2m2m = { -+ .name = "deinterlace_v4l2m2m", -+ .description = NULL_IF_CONFIG_SMALL("V4L2 M2M deinterlacer"), ++const FFFilter ff_vf_deinterlace_v4l2m2m = { ++ .p.name = "deinterlace_v4l2m2m", ++ .p.description = NULL_IF_CONFIG_SMALL("V4L2 M2M deinterlacer"), ++ .p.priv_class = &deinterlace_v4l2m2m_class, + .priv_size = sizeof(DeintV4L2M2MContext), + .init = &deint_v4l2m2m_init, + .uninit = &deint_v4l2m2m_uninit, + FILTER_QUERY_FUNC(&deint_v4l2m2m_query_formats), + FILTER_INPUTS(deint_v4l2m2m_inputs), + FILTER_OUTPUTS(deint_v4l2m2m_outputs), -+ .priv_class = &deinterlace_v4l2m2m_class, +}; diff --git a/projects/ROCKNIX/packages/multimedia/gstreamer/gst-libav/patches/0001-gst-libav-Fix-build-failure-with-FFmpeg-9.0.patch b/projects/ROCKNIX/packages/multimedia/gstreamer/gst-libav/patches/0001-gst-libav-Fix-build-failure-with-FFmpeg-9.0.patch new file mode 100644 index 00000000000..3104ce52caf --- /dev/null +++ b/projects/ROCKNIX/packages/multimedia/gstreamer/gst-libav/patches/0001-gst-libav-Fix-build-failure-with-FFmpeg-9.0.patch @@ -0,0 +1,59 @@ +From be9bdb67f4fc868977f1f74e95b6ebe19ef792ec Mon Sep 17 00:00:00 2001 +Subject: [PATCH] gst-libav: Fix build failure with FFmpeg 9.0 + +Backport of gstreamer!12217. AV_CODEC_ID_V308/V408/V410 are gone in +FFmpeg 9.0 (lavc 63), so guard them the way upstream already guards +AV_CODEC_ID_AYUV for lavc 61. + +Upstream: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/12217 + +diff --git a/ext/libav/gstavviddec.c b/ext/libav/gstavviddec.c +--- a/ext/libav/gstavviddec.c ++++ b/ext/libav/gstavviddec.c +@@ -2997,12 +2997,15 @@ + } + + /* no quasi codecs, please */ +- if (in_plugin->id == AV_CODEC_ID_RAWVIDEO || +- in_plugin->id == AV_CODEC_ID_V210 || +- in_plugin->id == AV_CODEC_ID_V210X || +- in_plugin->id == AV_CODEC_ID_V308 || +- in_plugin->id == AV_CODEC_ID_V408 || +- in_plugin->id == AV_CODEC_ID_V410 || in_plugin->id == AV_CODEC_ID_R210 ++ if (in_plugin->id == AV_CODEC_ID_RAWVIDEO ++ || in_plugin->id == AV_CODEC_ID_V210 ++ || in_plugin->id == AV_CODEC_ID_V210X ++ || in_plugin->id == AV_CODEC_ID_R210 ++#if LIBAVCODEC_VERSION_MAJOR < 63 ++ || in_plugin->id == AV_CODEC_ID_V308 ++ || in_plugin->id == AV_CODEC_ID_V408 ++ || in_plugin->id == AV_CODEC_ID_V410 ++#endif + #if LIBAVCODEC_VERSION_MAJOR < 61 + || in_plugin->id == AV_CODEC_ID_AYUV + #endif +diff --git a/ext/libav/gstavvidenc.c b/ext/libav/gstavvidenc.c +--- a/ext/libav/gstavvidenc.c ++++ b/ext/libav/gstavvidenc.c +@@ -1030,12 +1030,15 @@ + } + + /* no quasi codecs, please */ +- if (in_plugin->id == AV_CODEC_ID_RAWVIDEO || +- in_plugin->id == AV_CODEC_ID_V210 || +- in_plugin->id == AV_CODEC_ID_V210X || +- in_plugin->id == AV_CODEC_ID_V308 || +- in_plugin->id == AV_CODEC_ID_V408 || +- in_plugin->id == AV_CODEC_ID_V410 || in_plugin->id == AV_CODEC_ID_R210 ++ if (in_plugin->id == AV_CODEC_ID_RAWVIDEO ++ || in_plugin->id == AV_CODEC_ID_V210 ++ || in_plugin->id == AV_CODEC_ID_V210X ++ || in_plugin->id == AV_CODEC_ID_R210 ++#if LIBAVCODEC_VERSION_MAJOR < 63 ++ || in_plugin->id == AV_CODEC_ID_V308 ++ || in_plugin->id == AV_CODEC_ID_V408 ++ || in_plugin->id == AV_CODEC_ID_V410 ++#endif + #if LIBAVCODEC_VERSION_MAJOR < 61 + || in_plugin->id == AV_CODEC_ID_AYUV + #endif diff --git a/projects/ROCKNIX/packages/multimedia/libvpx/package.mk b/projects/ROCKNIX/packages/multimedia/libvpx/package.mk index e878e850540..947d4488d4d 100644 --- a/projects/ROCKNIX/packages/multimedia/libvpx/package.mk +++ b/projects/ROCKNIX/packages/multimedia/libvpx/package.mk @@ -3,10 +3,11 @@ # Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS) PKG_NAME="libvpx" -PKG_VERSION="df655cf4fb6c2a23b964544acd015cc715752830" # 1.13.1 -PKG_LICENSE="BSD" +PKG_VERSION="1.16.0" +PKG_SHA256="7a479a3c66b9f5d5542a4c6a1b7d3768a983b1e5c14c60a9396edc9b649e015c" +PKG_LICENSE="BSD-3-Clause" PKG_SITE="https://github.com/webmproject/libvpx" -PKG_URL="${PKG_SITE}/archive/${PKG_VERSION}.tar.gz" +PKG_URL="${PKG_SITE}/archive/v${PKG_VERSION}.tar.gz" PKG_DEPENDS_HOST="toolchain nasm:host" PKG_DEPENDS_TARGET="toolchain" PKG_LONGDESC="WebM VP8/VP9 Codec" @@ -76,5 +77,9 @@ configure_target() { } post_makeinstall_target() { - ln -sf libvpx.so.8.0.1 ${INSTALL}/usr/lib/libvpx.so.6 + # Steam expects the old libvpx.so.6 name; resolve the library this version + # actually installed instead of hardcoding a filename the soname bump removed + local vpx_lib=$(basename "$(readlink -f "${INSTALL}/usr/lib/libvpx.so")") + [ -f "${INSTALL}/usr/lib/${vpx_lib}" ] || die "libvpx: no installed library to point libvpx.so.6 at" + ln -sfv "${vpx_lib}" "${INSTALL}/usr/lib/libvpx.so.6" } diff --git a/projects/ROCKNIX/packages/multimedia/mpv/package.mk b/projects/ROCKNIX/packages/multimedia/mpv/package.mk index 4b47ff00082..c48fb74db2a 100644 --- a/projects/ROCKNIX/packages/multimedia/mpv/package.mk +++ b/projects/ROCKNIX/packages/multimedia/mpv/package.mk @@ -27,11 +27,15 @@ else PKG_MESON_OPTS_TARGET+=" -Dwayland=disabled" fi -PKG_MESON_OPTS_TARGET+=" -Dsdl2-gamepad=enabled" # Vulkan has issues on S922X so disable [ "${DEVICE}" == "S922X" ] && PKG_MESON_OPTS_TARGET+=" -Dvulkan=disabled" +# 0.41 dropped the -Dsdl2 umbrella and now autodetects SDL2 with +# required:false, gating the three features on it. Name them so a missing +# SDL2 is an error rather than three silently absent outputs. +PKG_MESON_OPTS_TARGET+=" -Dsdl2-audio=enabled -Dsdl2-video=enabled -Dsdl2-gamepad=enabled" + post_makeinstall_target() { cp ${PKG_DIR}/scripts/* ${INSTALL}/usr/bin chmod 0755 ${INSTALL}/usr/bin/* 2>/dev/null ||: diff --git a/projects/ROCKNIX/packages/network/avahi/package.mk b/projects/ROCKNIX/packages/network/avahi/package.mk index 84071f66b67..ca29e02fb0d 100644 --- a/projects/ROCKNIX/packages/network/avahi/package.mk +++ b/projects/ROCKNIX/packages/network/avahi/package.mk @@ -4,6 +4,7 @@ PKG_NAME="avahi" PKG_VERSION="0.8" +PKG_SHA256="c15e750ef7c6df595fb5f2ce10cac0fee2353649600e6919ad08ae8871e4945f" PKG_LICENSE="GPL" PKG_SITE="http://avahi.org/" PKG_URL="https://github.com/lathiat/avahi/archive/v${PKG_VERSION}.tar.gz" @@ -55,7 +56,11 @@ PKG_CONFIGURE_OPTS_TARGET="py_cv_mod_gtk_=yes \ --disable-nls" pre_configure_target() { - NOCONFIGURE=1 ./autogen.sh + # run from the source dir explicitly: after an interrupted first build, + # autogen has already produced ./configure, so the retry enters the + # configure-toolchain flow whose cwd is the (empty) build subdir - a bare + # ./autogen.sh can then never be found and the tree cannot recover + (cd "${PKG_BUILD}" && NOCONFIGURE=1 ./autogen.sh) } post_configure_target() { diff --git a/projects/ROCKNIX/packages/network/bluez/package.mk b/projects/ROCKNIX/packages/network/bluez/package.mk index 23be1a8aab1..6a5c278f084 100644 --- a/projects/ROCKNIX/packages/network/bluez/package.mk +++ b/projects/ROCKNIX/packages/network/bluez/package.mk @@ -3,8 +3,9 @@ # Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv) PKG_NAME="bluez" -PKG_VERSION="5.83" -PKG_LICENSE="GPL" +PKG_VERSION="5.87" +PKG_SHA256="26bdcf2cebd7310c6f598850606b037ef0c515fe6608ebc54d22c50c4c32b35f" +PKG_LICENSE="GPL-2.0-or-later" PKG_SITE="http://www.bluez.org/" PKG_URL="https://www.kernel.org/pub/linux/bluetooth/${PKG_NAME}-${PKG_VERSION}.tar.xz" PKG_DEPENDS_TARGET="toolchain dbus glib readline systemd json-c alsa-lib ncurses" @@ -34,7 +35,6 @@ PKG_CONFIGURE_OPTS_TARGET="--disable-dependency-tracking \ --disable-manpages \ --disable-experimental \ --enable-sixaxis \ - --enable-sap \ --enable-a2dp \ --enable-avrcp \ --enable-btpclient \ diff --git a/projects/ROCKNIX/packages/network/bluez/patches/bluez-01_add-obexd-policy.patch b/projects/ROCKNIX/packages/network/bluez/patches/0001-add-obexd-policy.patch similarity index 83% rename from projects/ROCKNIX/packages/network/bluez/patches/bluez-01_add-obexd-policy.patch rename to projects/ROCKNIX/packages/network/bluez/patches/0001-add-obexd-policy.patch index 6fd94b998e8..113eecc442f 100644 --- a/projects/ROCKNIX/packages/network/bluez/patches/bluez-01_add-obexd-policy.patch +++ b/projects/ROCKNIX/packages/network/bluez/patches/0001-add-obexd-policy.patch @@ -1,5 +1,10 @@ +From 2d7faa8b220b825f95d4e5f17e0948e1daaa0874 Mon Sep 17 00:00:00 2001 +From: Stefan Saraev +Date: Tue, 06 Aug 2013 12:37:04 +0300 +Subject: [PATCH] add obexd policy + diff --git a/src/bluetooth.conf b/src/bluetooth.conf -index 8a1e258..31b7542 100644 +index b6c6149..7b48aa9 100644 --- a/src/bluetooth.conf +++ b/src/bluetooth.conf @@ -21,10 +21,24 @@ @@ -27,3 +32,6 @@ index 8a1e258..31b7542 100644 +-- +2.53.0 + diff --git a/projects/ROCKNIX/packages/network/bluez/patches/bluez-03_storagedir.patch b/projects/ROCKNIX/packages/network/bluez/patches/0002-storagedir.patch similarity index 54% rename from projects/ROCKNIX/packages/network/bluez/patches/bluez-03_storagedir.patch rename to projects/ROCKNIX/packages/network/bluez/patches/0002-storagedir.patch index 6bad3b146ff..fa229a5c999 100644 --- a/projects/ROCKNIX/packages/network/bluez/patches/bluez-03_storagedir.patch +++ b/projects/ROCKNIX/packages/network/bluez/patches/0002-storagedir.patch @@ -1,9 +1,15 @@ -diff -Naur bluez-5.7/configure.ac bluez-5.7.patch/configure.ac ---- bluez-5.7/configure.ac 2013-06-26 18:17:07.000000000 +0200 -+++ bluez-5.7.patch/configure.ac 2013-07-12 20:21:17.000000000 +0200 -@@ -238,10 +238,13 @@ - prefix="${ac_default_prefix}" +From 541b9953dd44fbb3d46be38d7243f3c812863d2a Mon Sep 17 00:00:00 2001 +From: Stephan Raue +Date: Fri, 12 Jul 2013 20:37:41 +0200 +Subject: [PATCH] storagedir + +diff --git a/configure.ac b/configure.ac +index b011e9b..07304c6 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -480,10 +480,13 @@ else fi + AC_SUBST(PKGLIBEXECDIR, "${pkglibexecdir}") -if (test "$localstatedir" = '${prefix}/var'); then - storagedir="${prefix}/var/lib/bluetooth" @@ -19,3 +25,6 @@ diff -Naur bluez-5.7/configure.ac bluez-5.7.patch/configure.ac fi AC_DEFINE_UNQUOTED(STORAGEDIR, "${storagedir}", [Directory for the storage files]) +-- +2.53.0 + diff --git a/projects/ROCKNIX/packages/network/bluez/patches/bluez-11_sixaxis-fix-PID-navigation-controller.patch b/projects/ROCKNIX/packages/network/bluez/patches/0005-sixaxis-fix-PID-navigation-controller.patch similarity index 88% rename from projects/ROCKNIX/packages/network/bluez/patches/bluez-11_sixaxis-fix-PID-navigation-controller.patch rename to projects/ROCKNIX/packages/network/bluez/patches/0005-sixaxis-fix-PID-navigation-controller.patch index d3de493f2e9..b96253f8e6b 100644 --- a/projects/ROCKNIX/packages/network/bluez/patches/bluez-11_sixaxis-fix-PID-navigation-controller.patch +++ b/projects/ROCKNIX/packages/network/bluez/patches/0005-sixaxis-fix-PID-navigation-controller.patch @@ -14,10 +14,10 @@ Navigation Controller is using PID 0x042f over USB but PID 0x0268 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/sixaxis.c b/plugins/sixaxis.c -index 939fed7..f6baea7 100644 +index a04a76d..3e2890e 100644 --- a/plugins/sixaxis.c +++ b/plugins/sixaxis.c -@@ -354,7 +354,13 @@ static bool setup_device(int fd, const char *sysfs_path, +@@ -363,7 +363,13 @@ static bool setup_device(int fd, const char *sysfs_path, info("sixaxis: setting up new device"); btd_device_device_set_name(device, cp->name); @@ -33,7 +33,7 @@ index 939fed7..f6baea7 100644 closure = g_new0(struct authentication_closure, 1); diff --git a/profiles/input/sixaxis.h b/profiles/input/sixaxis.h -index 8e6f3cc..321a918 100644 +index 44e43b4..de8ec33 100644 --- a/profiles/input/sixaxis.h +++ b/profiles/input/sixaxis.h @@ -25,6 +25,7 @@ struct cable_pairing { @@ -44,7 +44,7 @@ index 8e6f3cc..321a918 100644 CablePairingType type; }; -@@ -54,6 +55,7 @@ get_pairing(uint16_t vid, uint16_t pid) +@@ -54,6 +55,7 @@ get_pairing(uint16_t vid, uint16_t pid, const char *name) .vid = 0x054c, .pid = 0x042f, .version = 0x0000, @@ -53,5 +53,5 @@ index 8e6f3cc..321a918 100644 }, { -- -2.7.4 +2.53.0 diff --git a/projects/ROCKNIX/packages/network/bluez/patches/bluez-12-fix-obexd-after-5_73.patch b/projects/ROCKNIX/packages/network/bluez/patches/0006-fix-obexd-after-5-73.patch similarity index 66% rename from projects/ROCKNIX/packages/network/bluez/patches/bluez-12-fix-obexd-after-5_73.patch rename to projects/ROCKNIX/packages/network/bluez/patches/0006-fix-obexd-after-5-73.patch index 4023c97bd5d..fa145daf861 100644 --- a/projects/ROCKNIX/packages/network/bluez/patches/bluez-12-fix-obexd-after-5_73.patch +++ b/projects/ROCKNIX/packages/network/bluez/patches/0006-fix-obexd-after-5-73.patch @@ -1,5 +1,10 @@ +From 4bc9f3e35b959b641577e1dd182f52e28bc7c87b Mon Sep 17 00:00:00 2001 +From: Rudi Heitbaum +Date: Sat, 09 Mar 2024 08:05:30 +0000 +Subject: [PATCH] fix obexd after 5 73 + diff --git a/Makefile.obexd b/Makefile.obexd -index b7e9f2d33..9a9e9a0a0 100644 +index 7ad74e128..666463b7c 100644 --- a/Makefile.obexd +++ b/Makefile.obexd @@ -1,6 +1,4 @@ @@ -9,7 +14,7 @@ index b7e9f2d33..9a9e9a0a0 100644 if SYSTEMD systemduserunit_DATA += obexd/src/obex.service -@@ -40,6 +38,8 @@ obexd_builtin_sources += obexd/plugins/opp.c +@@ -41,6 +39,8 @@ obexd_builtin_sources += obexd/plugins/opp.c obexd_builtin_modules += ftp obexd_builtin_sources += obexd/plugins/ftp.c obexd/plugins/ftp.h @@ -18,7 +23,7 @@ index b7e9f2d33..9a9e9a0a0 100644 obexd_builtin_modules += irmc obexd_builtin_sources += obexd/plugins/irmc.c -@@ -56,6 +56,8 @@ obexd_builtin_sources += obexd/plugins/mas.c obexd/src/map_ap.h \ +@@ -57,6 +57,8 @@ obexd_builtin_sources += obexd/plugins/mas.c obexd/src/map_ap.h \ obexd/plugins/messages.h \ obexd/plugins/messages-dummy.c @@ -27,7 +32,7 @@ index b7e9f2d33..9a9e9a0a0 100644 obexd_builtin_modules += mns obexd_builtin_sources += obexd/client/mns.c obexd/src/map_ap.h \ obexd/client/map-event.h -@@ -107,11 +109,6 @@ obexd_src_obexd_CPPFLAGS = $(AM_CPPFLAGS) $(GLIB_CFLAGS) $(DBUS_CFLAGS) \ +@@ -108,11 +110,6 @@ obexd_src_obexd_CPPFLAGS = $(AM_CPPFLAGS) $(GLIB_CFLAGS) $(DBUS_CFLAGS) \ -D_FILE_OFFSET_BITS=64 \ -I$(builddir)/obexd/src @@ -39,3 +44,6 @@ index b7e9f2d33..9a9e9a0a0 100644 if OBEX if SYSTEMD obexd_src_obexd_CPPFLAGS += -DSYSTEMD +-- +2.53.0 + diff --git a/projects/ROCKNIX/packages/network/connman/package.mk b/projects/ROCKNIX/packages/network/connman/package.mk index def3453f58a..0315d800dce 100644 --- a/projects/ROCKNIX/packages/network/connman/package.mk +++ b/projects/ROCKNIX/packages/network/connman/package.mk @@ -4,8 +4,9 @@ # Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS) PKG_NAME="connman" -PKG_VERSION="1.43" # 1.43 -PKG_LICENSE="GPL" +PKG_VERSION="2.0" +PKG_SHA256="e0f879af3dfe6c1e4ec1cc31d71af34ee01ed87892be6c596ee42990a17bac53" +PKG_LICENSE="GPL-2.0-or-later" PKG_SITE="http://www.connman.net" PKG_URL="https://git.kernel.org/pub/scm/network/connman/connman.git/snapshot/connman-${PKG_VERSION}.tar.gz" PKG_DEPENDS_TARGET="toolchain glib ncurses readline dbus iptables" @@ -46,6 +47,18 @@ PKG_CONFIGURE_OPTS_TARGET="--srcdir=.. \ --with-systemdunitdir=/usr/lib/systemd/system \ --disable-silent-rules" +post_configure_target() { + # 2.0 links through libtool, which bakes the build host's sysroot into + # RUNPATH; connmand shipped with an absolute /build/... path without this. + libtool_remove_rpath libtool +} + +post_unpack() { + # 2.0 added AC_CONFIG_AUX_DIR(build-aux); the git snapshot omits the + # directory, and there is no shipped configure, so autoreconf needs it. + mkdir -p ${PKG_BUILD}/build-aux +} + if [ "$WIREGUARD_SUPPORT" = "yes" ]; then PKG_CONFIGURE_OPTS_TARGET+=" --enable-wireguard=builtin" else diff --git a/projects/ROCKNIX/packages/network/connman/patches/0001-do-not-cleanup-routes.patch b/projects/ROCKNIX/packages/network/connman/patches/0001-do-not-cleanup-routes.patch new file mode 100644 index 00000000000..57c74ce14f7 --- /dev/null +++ b/projects/ROCKNIX/packages/network/connman/patches/0001-do-not-cleanup-routes.patch @@ -0,0 +1,18 @@ +From 01bf6480e8a0a13089f41ed28a9055295066baa0 Mon Sep 17 00:00:00 2001 +From: Stefan Saraev +Date: Fri, 09 Jan 2015 21:25:29 +0200 +Subject: [PATCH] do not cleanup routes + +diff --git a/src/device.c b/src/device.c +index 0fda950..eb09e53 100644 +--- a/src/device.c ++++ b/src/device.c +@@ -1501,8 +1501,6 @@ int __connman_device_init(const char *de + if (nodevice) + nodevice_filter = g_strsplit(nodevice, ",", -1); + +- cleanup_devices(); +- + return 0; + } + diff --git a/projects/ROCKNIX/packages/network/connman/patches/connman-05_link-against-ncurses.patch b/projects/ROCKNIX/packages/network/connman/patches/0003-link-against-ncurses.patch similarity index 70% rename from projects/ROCKNIX/packages/network/connman/patches/connman-05_link-against-ncurses.patch rename to projects/ROCKNIX/packages/network/connman/patches/0003-link-against-ncurses.patch index 1cdf631b03f..c16b6a8afb3 100644 --- a/projects/ROCKNIX/packages/network/connman/patches/connman-05_link-against-ncurses.patch +++ b/projects/ROCKNIX/packages/network/connman/patches/0003-link-against-ncurses.patch @@ -11,15 +11,15 @@ diff --git a/Makefile.am b/Makefile.am index 41efc1f..d1d3ddc 100644 --- a/Makefile.am +++ b/Makefile.am -@@ -252,7 +252,7 @@ client_connmanctl_SOURCES = client/dbus_helpers.h client/dbus_helpers.c \ +@@ -313,7 +313,7 @@ client_connmanctl_SOURCES = client/dbus_ client/main.c client_connmanctl_LDADD = gdbus/libgdbus-internal.la @DBUS_LIBS@ @GLIB_LIBS@ \ - -lreadline -ldl -+ -lreadline -lncurses -ltinfo -ldl ++ -lreadline -lncurses -ldl endif - noinst_PROGRAMS += unit/test-pbkdf2-sha1 unit/test-prf-sha1 unit/test-ippool + noinst_PROGRAMS += unit/test-ippool -- 1.7.10.4 diff --git a/projects/ROCKNIX/packages/network/connman/patches/connman-01-do-not-cleanup-routes.patch b/projects/ROCKNIX/packages/network/connman/patches/connman-01-do-not-cleanup-routes.patch deleted file mode 100644 index 9409458294c..00000000000 --- a/projects/ROCKNIX/packages/network/connman/patches/connman-01-do-not-cleanup-routes.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/src/device.c b/src/device.c -index 0fda950..eb09e53 100644 ---- a/src/device.c -+++ b/src/device.c -@@ -1247,8 +1247,6 @@ int __connman_device_init(const char *device, const char *nodevice) - if (nodevice != NULL) - nodevice_filter = g_strsplit(nodevice, ",", -1); - -- cleanup_devices(); -- - return 0; - } - diff --git a/projects/ROCKNIX/packages/network/iwd/package.mk b/projects/ROCKNIX/packages/network/iwd/package.mk index 45b68c132ad..1be259d70b2 100644 --- a/projects/ROCKNIX/packages/network/iwd/package.mk +++ b/projects/ROCKNIX/packages/network/iwd/package.mk @@ -3,8 +3,8 @@ . ${ROOT}/packages/network/iwd/package.mk -PKG_VERSION="3.10" -PKG_SHA256="0cd7dc9b32b9d6809a4a5e5d063b5c5fd279f5ad3a0bf03d7799da66df5cad45" +PKG_VERSION="3.12" +PKG_SHA256="d89a5e45c7180170e19be828f9e944a768c593758094fc57a358d0e7c4cb1a49" pre_configure_target() { export LIBS="-lncurses -ltinfo" diff --git a/projects/ROCKNIX/packages/network/libpcap/package.mk b/projects/ROCKNIX/packages/network/libpcap/package.mk index 85c4c69e5f7..85db1e8fb20 100644 --- a/projects/ROCKNIX/packages/network/libpcap/package.mk +++ b/projects/ROCKNIX/packages/network/libpcap/package.mk @@ -2,10 +2,11 @@ # Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv) PKG_NAME="libpcap" -PKG_VERSION="1.10.4" +PKG_VERSION="1.10.6" +PKG_SHA256="872dd11337fe1ab02ad9d4fee047c9da244d695c6ddf34e2ebb733efd4ed8aa9" PKG_LICENSE="GPL" PKG_SITE="http://www.tcpdump.org/" -PKG_URL="http://www.tcpdump.org/release/libpcap-${PKG_VERSION}.tar.gz" +PKG_URL="https://www.tcpdump.org/release/libpcap-${PKG_VERSION}.tar.gz" PKG_DEPENDS_TARGET="toolchain" PKG_LONGDESC="A portable framework for low-level network monitoring." # use configure, not cmake. review cmake in future release. diff --git a/projects/ROCKNIX/packages/network/nfs-utils/package.mk b/projects/ROCKNIX/packages/network/nfs-utils/package.mk deleted file mode 100644 index eb8dc5d0aa6..00000000000 --- a/projects/ROCKNIX/packages/network/nfs-utils/package.mk +++ /dev/null @@ -1,31 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (C) 2024-present Team LibreELEC (https://libreelec.tv) - -PKG_NAME="nfs-utils" -PKG_VERSION="2.6.4" -PKG_SHA256="01b3b0fb9c7d0bbabf5114c736542030748c788ec2fd9734744201e9b0a1119d" -PKG_LICENSE="GPL-2.0-or-later" -PKG_SITE="http://www.linux-nfs.org/" -PKG_URL="https://www.kernel.org/pub/linux/utils/nfs-utils/${PKG_VERSION}/nfs-utils-${PKG_VERSION}.tar.xz" -PKG_DEPENDS_TARGET="toolchain keyutils libevent libtirpc rpcbind sqlite util-linux" -PKG_LONGDESC="Linux NFS userland utility package" - -PKG_CONFIGURE_OPTS_TARGET="--disable-gss \ - --disable-nfsv41 \ - --disable-nfsdcld \ - --disable-nfsrahead \ - --disable-nfsdcltrack \ - --disable-ldap" - -pre_configure_target() { - cd ${PKG_BUILD} - rm -rf .${TARGET_NAME} -} - -makeinstall_target() { - mkdir -p "${INSTALL}/usr/sbin/" - cp -PR utils/mount/mount.nfs "${INSTALL}/usr/sbin/" - ln -s mount.nfs "${INSTALL}/usr/sbin/mount.nfs4" - ln -s mount.nfs "${INSTALL}/usr/sbin/umount.nfs" - ln -s mount.nfs "${INSTALL}/usr/sbin/umount.nfs4" -} diff --git a/projects/ROCKNIX/packages/network/openssh/package.mk b/projects/ROCKNIX/packages/network/openssh/package.mk index 84399e7ae39..44ed66d4774 100644 --- a/projects/ROCKNIX/packages/network/openssh/package.mk +++ b/projects/ROCKNIX/packages/network/openssh/package.mk @@ -3,14 +3,15 @@ # Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv) PKG_NAME="openssh" -PKG_VERSION="9.8p1" -PKG_LICENSE="OSS" +PKG_VERSION="10.4p1" +PKG_SHA256="ef6026dd2aea8d56059638d5d3262902c892ceba9f88395835e0d06d3fb63238" +PKG_LICENSE="BSD-2-Clause AND ISC" PKG_SITE="https://www.openssh.com/" PKG_URL="https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/${PKG_NAME}-${PKG_VERSION}.tar.gz" PKG_DEPENDS_TARGET="toolchain openssl zlib" PKG_LONGDESC="An open re-implementation of the SSH package." PKG_TOOLCHAIN="autotools" -PKG_BUILD_FLAGS="+lto" +PKG_BUILD_FLAGS="+lto -cfg-libs" PKG_CONFIGURE_OPTS_TARGET="ac_cv_header_rpc_types_h=no \ --sysconfdir=/etc/ssh \ @@ -23,7 +24,7 @@ PKG_CONFIGURE_OPTS_TARGET="ac_cv_header_rpc_types_h=no \ --disable-wtmp \ --disable-wtmpx \ --without-rpath \ - --with-ssl-engine \ + --without-ssl-engine \ --with-privsep-user=nobody \ --disable-pututline \ --disable-pututxline \ diff --git a/projects/ROCKNIX/packages/network/openssh/patches/openssh-8.9p1-keydir.patch b/projects/ROCKNIX/packages/network/openssh/patches/0001-keydir.patch similarity index 75% rename from projects/ROCKNIX/packages/network/openssh/patches/openssh-8.9p1-keydir.patch rename to projects/ROCKNIX/packages/network/openssh/patches/0001-keydir.patch index 58502295339..9ccdd7de7a1 100644 --- a/projects/ROCKNIX/packages/network/openssh/patches/openssh-8.9p1-keydir.patch +++ b/projects/ROCKNIX/packages/network/openssh/patches/0001-keydir.patch @@ -1,7 +1,13 @@ -diff -u a/configure.ac b/configure.ac ---- a/configure.ac 2018-10-16 20:01:20.000000000 -0400 -+++ b/configure.ac 2018-12-06 04:08:42.718993760 -0500 -@@ -5185,6 +5185,19 @@ +From 3df253529b24a73a50367890d32d17135419450a Mon Sep 17 00:00:00 2001 +From: Stephan Raue +Date: Sun, 03 Aug 2014 15:23:00 +0200 +Subject: [PATCH] keydir + +diff --git a/configure.ac b/configure.ac +index a4d544c..b7119fd 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -5507,6 +5507,19 @@ AC_ARG_WITH([superuser-path], ) @@ -21,7 +27,7 @@ diff -u a/configure.ac b/configure.ac AC_MSG_CHECKING([if we need to convert IPv4 in IPv6-mapped addresses]) IPV4_IN6_HACK_MSG="no" AC_ARG_WITH(4in6, -@@ -5565,6 +5578,7 @@ +@@ -5908,6 +5921,7 @@ G=`eval echo ${piddir}` ; G=`eval echo ${G}` H=`eval echo ${PRIVSEP_PATH}` ; H=`eval echo ${H}` I=`eval echo ${user_path}` ; I=`eval echo ${I}` J=`eval echo ${superuser_path}` ; J=`eval echo ${J}` @@ -29,7 +35,7 @@ diff -u a/configure.ac b/configure.ac echo "" echo "OpenSSH has been configured with the following options:" -@@ -5588,6 +5602,9 @@ +@@ -5931,6 +5945,9 @@ fi if test ! -z "$superuser_path" ; then echo " sshd superuser user PATH: $J" fi @@ -39,14 +45,14 @@ diff -u a/configure.ac b/configure.ac echo " Manpage format: $MANTYPE" echo " PAM support: $PAM_MSG" echo " OSF SIA support: $SIA_MSG" -Common subdirectories: a/contrib and b/contrib -diff -u a/Makefile.in b/Makefile.in ---- a/Makefile.in 2018-10-16 20:01:20.000000000 -0400 -+++ b/Makefile.in 2018-12-06 04:00:04.301968236 -0500 -@@ -32,8 +32,10 @@ - STRIP_OPT=@STRIP_OPT@ - TEST_SHELL=@TEST_SHELL@ +diff --git a/Makefile.in b/Makefile.in +index da59bcc..100496d 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -34,8 +34,10 @@ TEST_SHELL=@TEST_SHELL@ BUILDDIR=@abs_top_builddir@ + SK_STANDALONE=@SK_STANDALONE@ + COMPATINCLUDES="$(BUILDDIR)/@COMPATINCLUDES@" +KEYDIR=@KEYDIR@ PATHS= -DSSHDIR=\"$(sysconfdir)\" \ @@ -54,27 +60,25 @@ diff -u a/Makefile.in b/Makefile.in -D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" \ -D_PATH_SSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" \ -D_PATH_SFTP_SERVER=\"$(SFTP_SERVER)\" \ -@@ -168,11 +170,11 @@ +@@ -186,10 +188,10 @@ PATHSUBS = \ -e 's|/etc/ssh/sshd_config|$(sysconfdir)/sshd_config|g' \ -e 's|/usr/libexec|$(libexecdir)|g' \ -e 's|/etc/shosts.equiv|$(sysconfdir)/shosts.equiv|g' \ - -e 's|/etc/ssh/ssh_host_key|$(sysconfdir)/ssh_host_key|g' \ - -e 's|/etc/ssh/ssh_host_ecdsa_key|$(sysconfdir)/ssh_host_ecdsa_key|g' \ -- -e 's|/etc/ssh/ssh_host_dsa_key|$(sysconfdir)/ssh_host_dsa_key|g' \ - -e 's|/etc/ssh/ssh_host_rsa_key|$(sysconfdir)/ssh_host_rsa_key|g' \ - -e 's|/etc/ssh/ssh_host_ed25519_key|$(sysconfdir)/ssh_host_ed25519_key|g' \ + -e 's|/etc/ssh/ssh_host_key|$(KEYDIR)/ssh_host_key|g' \ + -e 's|/etc/ssh/ssh_host_ecdsa_key|$(KEYDIR)/ssh_host_ecdsa_key|g' \ -+ -e 's|/etc/ssh/ssh_host_dsa_key|$(KEYDIR)/ssh_host_dsa_key|g' \ + -e 's|/etc/ssh/ssh_host_rsa_key|$(KEYDIR)/ssh_host_rsa_key|g' \ + -e 's|/etc/ssh/ssh_host_ed25519_key|$(KEYDIR)/ssh_host_ed25519_key|g' \ -e 's|/var/run/sshd.pid|$(piddir)/sshd.pid|g' \ -e 's|/etc/moduli|$(sysconfdir)/moduli|g' \ -e 's|/etc/ssh/moduli|$(sysconfdir)/moduli|g' \ -Common subdirectories: a/openbsd-compat and b/openbsd-compat -diff -u a/pathnames.h b/pathnames.h ---- a/pathnames.h 2018-10-16 20:01:20.000000000 -0400 -+++ b/pathnames.h 2018-12-06 04:15:01.286012398 -0500 +diff --git a/pathnames.h b/pathnames.h +index 2f0b9f4..c6fee12 100644 +--- a/pathnames.h ++++ b/pathnames.h @@ -18,6 +18,10 @@ #define SSHDIR ETCDIR "/ssh" #endif @@ -98,22 +102,23 @@ diff -u a/pathnames.h b/pathnames.h /* * Of these, ssh_host_key must be readable only by root, whereas ssh_config -@@ -36,12 +40,12 @@ +@@ -36,11 +40,11 @@ */ #define _PATH_SERVER_CONFIG_FILE SSHDIR "/sshd_config" #define _PATH_HOST_CONFIG_FILE SSHDIR "/ssh_config" --#define _PATH_HOST_DSA_KEY_FILE SSHDIR "/ssh_host_dsa_key" -#define _PATH_HOST_ECDSA_KEY_FILE SSHDIR "/ssh_host_ecdsa_key" --#define _PATH_HOST_ED25519_KEY_FILE SSHDIR "/ssh_host_ed25519_key" --#define _PATH_HOST_XMSS_KEY_FILE SSHDIR "/ssh_host_xmss_key" -#define _PATH_HOST_RSA_KEY_FILE SSHDIR "/ssh_host_rsa_key" +-#define _PATH_HOST_ED25519_KEY_FILE SSHDIR "/ssh_host_ed25519_key" +-#define _PATH_HOST_MLDSA44_ED25519_KEY_FILE SSHDIR "/ssh_host_mldsa44_ed25519_key" -#define _PATH_DH_MODULI SSHDIR "/moduli" -+#define _PATH_HOST_DSA_KEY_FILE KEYDIR "/ssh_host_dsa_key" +#define _PATH_HOST_ECDSA_KEY_FILE KEYDIR "/ssh_host_ecdsa_key" -+#define _PATH_HOST_ED25519_KEY_FILE KEYDIR "/ssh_host_ed25519_key" -+#define _PATH_HOST_XMSS_KEY_FILE KEYDIR "/ssh_host_xmss_key" +#define _PATH_HOST_RSA_KEY_FILE KEYDIR "/ssh_host_rsa_key" ++#define _PATH_HOST_ED25519_KEY_FILE KEYDIR "/ssh_host_ed25519_key" ++#define _PATH_HOST_MLDSA44_ED25519_KEY_FILE KEYDIR "/ssh_host_mldsa44_ed25519_key" +#define _PATH_DH_MODULI KEYDIR "/moduli" #ifndef _PATH_SSH_PROGRAM #define _PATH_SSH_PROGRAM "/usr/bin/ssh" +-- +2.53.0 + diff --git a/projects/ROCKNIX/packages/network/openssh/patches/openssh-silence-missing-identity-error.patch b/projects/ROCKNIX/packages/network/openssh/patches/0002-silence-missing-identity-error.patch similarity index 57% rename from projects/ROCKNIX/packages/network/openssh/patches/openssh-silence-missing-identity-error.patch rename to projects/ROCKNIX/packages/network/openssh/patches/0002-silence-missing-identity-error.patch index e7b01daf6ae..43a4ec1cfd7 100644 --- a/projects/ROCKNIX/packages/network/openssh/patches/openssh-silence-missing-identity-error.patch +++ b/projects/ROCKNIX/packages/network/openssh/patches/0002-silence-missing-identity-error.patch @@ -1,8 +1,13 @@ +From 60d8f2245761d64546eeb2eb3f44fe89984cf08d Mon Sep 17 00:00:00 2001 +From: Stefan Saraev +Date: Sun, 24 Mar 2013 15:06:00 +0200 +Subject: [PATCH] silence missing identity error + diff --git a/sshconnect2.c b/sshconnect2.c -index d6af0b9..22c0aa6 100644 +index d1555ee..25cc9e5 100644 --- a/sshconnect2.c +++ b/sshconnect2.c -@@ -1524,9 +1524,7 @@ +@@ -1535,9 +1535,7 @@ load_identity_file(Identity *id) struct stat st; if (stat(id->filename, &st) == -1) { @@ -13,3 +18,6 @@ index d6af0b9..22c0aa6 100644 return NULL; } snprintf(prompt, sizeof prompt, +-- +2.53.0 + diff --git a/projects/ROCKNIX/packages/network/openssh/patches/openssh-source-etc-environment.patch b/projects/ROCKNIX/packages/network/openssh/patches/0003-source-etc-environment.patch similarity index 75% rename from projects/ROCKNIX/packages/network/openssh/patches/openssh-source-etc-environment.patch rename to projects/ROCKNIX/packages/network/openssh/patches/0003-source-etc-environment.patch index b23ee72b8e6..ff868e916ae 100644 --- a/projects/ROCKNIX/packages/network/openssh/patches/openssh-source-etc-environment.patch +++ b/projects/ROCKNIX/packages/network/openssh/patches/0003-source-etc-environment.patch @@ -8,10 +8,10 @@ Subject: [PATCH] openssh: source /etc/environment 1 file changed, 2 deletions(-) diff --git a/session.c b/session.c -index ac06b08..0a1c59a 100644 +index fc9c9d6..0d612b1 100644 --- a/session.c +++ b/session.c -@@ -1080,7 +1080,6 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell) +@@ -1036,7 +1036,6 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell) child_set_env(&env, &envsize, "KRB5CCNAME", cp); } @@ -19,14 +19,14 @@ index ac06b08..0a1c59a 100644 { char *cp; -@@ -1089,7 +1088,6 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell) +@@ -1045,7 +1044,6 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell) read_environment_file(&env, &envsize, "/etc/environment", - options.permit_user_env_whitelist); + options.permit_user_env_allowlist); } -#endif #ifdef KRB5 if (s->authctxt->krb5_ccname) child_set_env(&env, &envsize, "KRB5CCNAME", -- -2.7.4 +2.53.0 diff --git a/projects/ROCKNIX/packages/network/samba/config/smb.conf b/projects/ROCKNIX/packages/network/samba/config/smb.conf index f4c1e8ed750..f90699ae87f 100644 --- a/projects/ROCKNIX/packages/network/samba/config/smb.conf +++ b/projects/ROCKNIX/packages/network/samba/config/smb.conf @@ -22,7 +22,6 @@ passdb backend = smbpasswd smb passwd file = /storage/.cache/samba/smbpasswd smb encrypt = disabled - fruit:model = Xserve # samba share options map to guest = Bad User diff --git a/projects/ROCKNIX/packages/network/samba/package.mk b/projects/ROCKNIX/packages/network/samba/package.mk index 3d49a62ec93..743ad97d546 100644 --- a/projects/ROCKNIX/packages/network/samba/package.mk +++ b/projects/ROCKNIX/packages/network/samba/package.mk @@ -3,7 +3,8 @@ # Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv) PKG_NAME="samba" -PKG_VERSION="4.21.0" +PKG_VERSION="4.24.5" +PKG_SHA256="6d5d7ee82f5ce9da4135086c9b184e47a58b4b023565f58abbb1f8c8a922306b" PKG_LICENSE="GPLv3+" PKG_SITE="https://www.samba.org" PKG_URL="https://download.samba.org/pub/samba/stable/${PKG_NAME}-${PKG_VERSION}.tar.gz" @@ -86,8 +87,6 @@ pre_configure_target() { cd ${PKG_BUILD} rm -rf .${TARGET_NAME} -# work around link issues - export LDFLAGS="${LDFLAGS} -lreadline -lncursesw" # support 64-bit offsets and seeks on 32-bit platforms if [ "${TARGET_ARCH}" = "arm" ]; then diff --git a/projects/ROCKNIX/packages/network/samba/patches/samba-200-4.11-fix-ASN1-bso14164.patch b/projects/ROCKNIX/packages/network/samba/patches/0200-4.11-fix-ASN1-bso14164.patch similarity index 93% rename from projects/ROCKNIX/packages/network/samba/patches/samba-200-4.11-fix-ASN1-bso14164.patch rename to projects/ROCKNIX/packages/network/samba/patches/0200-4.11-fix-ASN1-bso14164.patch index 195528f2244..9669cac92e3 100644 --- a/projects/ROCKNIX/packages/network/samba/patches/samba-200-4.11-fix-ASN1-bso14164.patch +++ b/projects/ROCKNIX/packages/network/samba/patches/0200-4.11-fix-ASN1-bso14164.patch @@ -40,10 +40,10 @@ diff --git a/wscript_configure_embedded_heimdal b/wscript_configure_embedded_hei index 8c55ae2..4fdae80 100644 --- a/wscript_configure_embedded_heimdal +++ b/wscript_configure_embedded_heimdal -@@ -13,3 +13,14 @@ - # when this will be available also in - # system libraries... - conf.define('HAVE_CLIENT_GSS_C_CHANNEL_BOUND_FLAG', 1) +@@ -16,3 +16,14 @@ conf.define('HAVE_CLIENT_GSS_C_CHANNEL_B + + conf.define('HAVE_KRB5_INIT_CREDS_STEP', 1) + conf.define('HAVE_GSS_KEY_VALUE_SET_DESC', 1) + +def check_system_heimdal_binary(name): + if conf.LIB_MAY_BE_BUNDLED(name): @@ -57,3 +57,4 @@ index 8c55ae2..4fdae80 100644 +check_system_heimdal_binary("asn1_compile") -- 2.20.1 + diff --git a/projects/ROCKNIX/packages/network/samba/patches/samba-950-no-man.patch b/projects/ROCKNIX/packages/network/samba/patches/0950-no-man.patch similarity index 89% rename from projects/ROCKNIX/packages/network/samba/patches/samba-950-no-man.patch rename to projects/ROCKNIX/packages/network/samba/patches/0950-no-man.patch index 79f0c560cf8..659d4240335 100644 --- a/projects/ROCKNIX/packages/network/samba/patches/samba-950-no-man.patch +++ b/projects/ROCKNIX/packages/network/samba/patches/0950-no-man.patch @@ -12,7 +12,7 @@ diff --git a/buildtools/wafsamba/wafsamba.py b/buildtools/wafsamba/wafsamba.py index a077026..2a897d0 100644 --- a/buildtools/wafsamba/wafsamba.py +++ b/buildtools/wafsamba/wafsamba.py -@@ -328,11 +328,6 @@ def SAMBA_LIBRARY(bld, libname, source, +@@ -415,11 +415,6 @@ def SAMBA_LIBRARY(bld, libname, source, else: bld.PKG_CONFIG_FILES(pc_files, vnum=vnum) @@ -24,7 +24,7 @@ index a077026..2a897d0 100644 Build.BuildContext.SAMBA_LIBRARY = SAMBA_LIBRARY -@@ -437,9 +432,6 @@ def SAMBA_BINARY(bld, binname, source, +@@ -547,9 +542,6 @@ def SAMBA_BINARY(bld, binname, source, samba_ldflags = pie_ldflags ) diff --git a/projects/ROCKNIX/packages/network/samba/patches/samba-951-no-man-4.16.patch b/projects/ROCKNIX/packages/network/samba/patches/0951-no-man-4.16.patch similarity index 73% rename from projects/ROCKNIX/packages/network/samba/patches/samba-951-no-man-4.16.patch rename to projects/ROCKNIX/packages/network/samba/patches/0951-no-man-4.16.patch index 0a20aef158e..3225f7caf29 100644 --- a/projects/ROCKNIX/packages/network/samba/patches/samba-951-no-man-4.16.patch +++ b/projects/ROCKNIX/packages/network/samba/patches/0951-no-man-4.16.patch @@ -1,7 +1,12 @@ +From 08de0299286cb7fe04b191917482135090b6915f Mon Sep 17 00:00:00 2001 +From: heitbaum <6086324+heitbaum@users.noreply.github.com> +Date: Sat, 05 Dec 2020 07:58:54 +0000 +Subject: [PATCH] no man 4.16 + diff --git a/docs-xml/wscript_build b/docs-xml/wscript_build ---- a/docs-xml/wscript_build 2020-12-05 09:01:19.652459634 +0000 -+++ b/docs-xml/wscript_build 2020-12-05 09:10:10.639446971 +0000 -@@ -175,32 +175,3 @@ +--- a/docs-xml/wscript_build ++++ b/docs-xml/wscript_build +@@ -180,35 +180,3 @@ bld.SAMBA_GENERATOR(path_entities, target=path_entities, rule=generate_path_entity_file, dep_vars=bld.dynconfig_varnames()) @@ -28,6 +33,9 @@ diff --git a/docs-xml/wscript_build b/docs-xml/wscript_build - if conf.env.build_winexe == True: - bld.SAMBAMANPAGES(winexe_manpages) - +- if bld.CONFIG_SET('HAVE_EVHTTP_NEW') and bld.CONFIG_SET('WITH_PROFILE'): +- bld.SAMBAMANPAGES(prometheus_manpages) +- - if bld.CONFIG_SET('ENABLE_SELFTEST'): - bld.SAMBAMANPAGES('manpages/vfstest.1') - diff --git a/projects/ROCKNIX/packages/network/samba/system.d/nmbd.service b/projects/ROCKNIX/packages/network/samba/system.d/nmbd.service index a2dc1b35a20..881a8a1dc8e 100644 --- a/projects/ROCKNIX/packages/network/samba/system.d/nmbd.service +++ b/projects/ROCKNIX/packages/network/samba/system.d/nmbd.service @@ -1,7 +1,7 @@ [Unit] Description=Samba NMB Daemon -Wants=network-online.target samba-config.service -After=network-online.target samba-config.service +Wants=network-online.target +After=network-online.target ConditionPathExists=!/storage/.cache/services/samba.disabled ConditionPathExists=/run/samba/smb.conf diff --git a/projects/ROCKNIX/packages/network/syncthing/package.mk b/projects/ROCKNIX/packages/network/syncthing/package.mk index 7b2de731f85..a9fca007271 100644 --- a/projects/ROCKNIX/packages/network/syncthing/package.mk +++ b/projects/ROCKNIX/packages/network/syncthing/package.mk @@ -3,8 +3,9 @@ # Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS) PKG_NAME="syncthing" -PKG_VERSION="2.0.13" -PKG_LICENSE="MPLv2" +PKG_VERSION="2.1.3" +PKG_SHA256="f34bc1b3219e02ac1eca0b1446f582af8fe13f789da5f8c679ba9cac0396bf81" +PKG_LICENSE="MPL-2.0" PKG_SITE="https://syncthing.net/" PKG_URL="https://github.com/syncthing/syncthing/releases/download/v${PKG_VERSION}/syncthing-source-v${PKG_VERSION}.tar.gz" PKG_DEPENDS_TARGET="toolchain go:host" diff --git a/projects/ROCKNIX/packages/network/tailscale/package.mk b/projects/ROCKNIX/packages/network/tailscale/package.mk index c4507ce697b..2ec1467e6db 100644 --- a/projects/ROCKNIX/packages/network/tailscale/package.mk +++ b/projects/ROCKNIX/packages/network/tailscale/package.mk @@ -3,7 +3,7 @@ # Copyright (C) 2022-present fewtarius (https://github.com/fewtarius) PKG_NAME="tailscale" -PKG_VERSION="1.98.8" +PKG_VERSION="1.102.2" PKG_SITE="https://tailscale.com/" PKG_DEPENDS_TARGET="toolchain wireguard-tools" PKG_LONGDESC="Zero config VPN. Installs on any device in minutes, manages firewall rules for you, and works from anywhere." @@ -12,11 +12,11 @@ PKG_TOOLCHAIN="manual" case ${TARGET_ARCH} in aarch64) TS_ARCH="_arm64" - PKG_SHA256="53eb3ce89d062fd34e393d24a6c8ec08c769fede8eb77fe9c6e347ad4ae00f84" + PKG_SHA256="2b64e9ade7e73034b5ec9e9bcd537f5ddd14ae3abb435e57e929e7486ae42660" ;; x86_64) TS_ARCH="_amd64" - PKG_SHA256="3a55b5900dd7e11e09b6c74d1e46d223d549dfbefbdc1f044a8ab7bdbafb933c" + PKG_SHA256="ad2cde12f8de95f7b93a1e0401e652291c603d42b9d60a33fb1741eb38ab04d8" ;; esac diff --git a/projects/ROCKNIX/packages/rust/cargo-snapshot/package.mk b/projects/ROCKNIX/packages/rust/cargo-snapshot/package.mk deleted file mode 100755 index bf03a9b6c67..00000000000 --- a/projects/ROCKNIX/packages/rust/cargo-snapshot/package.mk +++ /dev/null @@ -1,25 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv) - -PKG_NAME="cargo-snapshot" -PKG_VERSION="$(get_pkg_version rust)" -PKG_LICENSE="MIT" -PKG_SITE="https://www.rust-lang.org" -PKG_LONGDESC="cargo bootstrap package" -PKG_TOOLCHAIN="manual" - -case "${MACHINE_HARDWARE_NAME}" in - "aarch64") - PKG_SHA256="69a99d7f0af6d9a86c89c1f991953e924d9910eb06847524e3833063338e3923" - PKG_URL="https://static.rust-lang.org/dist/cargo-${PKG_VERSION}-${MACHINE_HARDWARE_NAME}-unknown-linux-gnu.tar.xz" - ;; - "arm") - PKG_SHA256="05e425da9e2dccedf88df280347cbfef4538969fc330cc752987e590de00a825" - PKG_URL="https://static.rust-lang.org/dist/cargo-${PKG_VERSION}-${MACHINE_HARDWARE_NAME}-unknown-linux-gnueabihf.tar.xz" - ;; - "x86_64") - PKG_SHA256="03595624775204f80ff3a67986f69c8918e4cd311877ced635108888013a1e39" - PKG_URL="https://static.rust-lang.org/dist/cargo-${PKG_VERSION}-${MACHINE_HARDWARE_NAME}-unknown-linux-gnu.tar.xz" - ;; -esac -PKG_SOURCE_NAME="cargo-snapshot_${PKG_VERSION}_${ARCH}.tar.xz" diff --git a/projects/ROCKNIX/packages/rust/cargo/package.mk b/projects/ROCKNIX/packages/rust/cargo/package.mk deleted file mode 100755 index 1cabd949fad..00000000000 --- a/projects/ROCKNIX/packages/rust/cargo/package.mk +++ /dev/null @@ -1,32 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv) - -PKG_NAME="cargo" -PKG_VERSION="$(get_pkg_version rust)" -PKG_LICENSE="MIT" -PKG_SITE="https://www.rust-lang.org" -PKG_DEPENDS_HOST="openssl:host rust:host" -PKG_DEPENDS_UNPACK="cargo-snapshot rust" -PKG_LONGDESC="Cargo is the Rust package manager" -PKG_TOOLCHAIN="manual" - -pre_configure_host() { - "$(get_build_dir cargo-snapshot)/install.sh" --prefix="${PKG_BUILD}/cargo-snapshot" --disable-ldconfig -} - -configure_host() { - cd ${PKG_BUILD} -} - -make_host() { - cd ${PKG_BUILD} - - export RUSTC_BOOTSTRAP="1" - - ./cargo-snapshot/bin/cargo build -v --target ${RUST_HOST} --release --manifest-path="$(get_build_dir rust)/src/tools/cargo/Cargo.toml" -} - -makeinstall_host() { - mkdir -p ${TOOLCHAIN}/bin - cp -a ${PKG_BUILD}/.${RUST_HOST}/target/${RUST_HOST}/release/cargo ${TOOLCHAIN}/bin/ -} diff --git a/projects/ROCKNIX/packages/rust/cbindgen/package.mk b/projects/ROCKNIX/packages/rust/cbindgen/package.mk deleted file mode 100755 index 1a8a6646568..00000000000 --- a/projects/ROCKNIX/packages/rust/cbindgen/package.mk +++ /dev/null @@ -1,27 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (C) 2025-present Team LibreELEC (https://libreelec.tv) - -PKG_NAME="cbindgen" -PKG_VERSION="0.29.2" -PKG_SHA256="c7d4d610482390c70e471a5682de714967e187ed2f92f2237c317a484a8c7e3a" -PKG_LICENSE="MPL-2.0" -PKG_SITE="https://github.com/mozilla/bindgen" -PKG_URL="https://github.com/mozilla/cbindgen/archive/v${PKG_VERSION}.tar.gz" -PKG_DEPENDS_HOST="cargo:host" -PKG_LONGDESC="A project for generating C bindings from Rust code" -PKG_TOOLCHAIN="manual" - -configure_host() { - cd ${PKG_BUILD} -} - -make_host() { - cd ${PKG_BUILD} - - cargo build -v --target ${RUST_HOST} --release -} - -makeinstall_host() { - mkdir -p ${TOOLCHAIN}/bin - cp -a ${PKG_BUILD}/.${RUST_HOST}/target/${RUST_HOST}/release/cbindgen ${TOOLCHAIN}/bin/ -} diff --git a/projects/ROCKNIX/packages/rust/rust-std-snapshot/package.mk b/projects/ROCKNIX/packages/rust/rust-std-snapshot/package.mk deleted file mode 100755 index e5a365c643c..00000000000 --- a/projects/ROCKNIX/packages/rust/rust-std-snapshot/package.mk +++ /dev/null @@ -1,25 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv) - -PKG_NAME="rust-std-snapshot" -PKG_VERSION="$(get_pkg_version rust)" -PKG_LICENSE="MIT" -PKG_SITE="https://www.rust-lang.org" -PKG_LONGDESC="rust std library bootstrap package" -PKG_TOOLCHAIN="manual" - -case "${MACHINE_HARDWARE_NAME}" in - "aarch64") - PKG_SHA256="2be613d5525a4ce8b7e2a1a55beeb64198314507be0d2da5aea4fd166cdde21f" - PKG_URL="https://static.rust-lang.org/dist/rust-std-${PKG_VERSION}-${MACHINE_HARDWARE_NAME}-unknown-linux-gnu.tar.xz" - ;; - "arm") - PKG_SHA256="386964a6b9e85aef7b93a0b5c682339ec5628947c29076b7459c934fbf8fcfda" - PKG_URL="https://static.rust-lang.org/dist/rust-std-${PKG_VERSION}-${MACHINE_HARDWARE_NAME}-unknown-linux-gnueabihf.tar.xz" - ;; - "x86_64") - PKG_SHA256="74109ee2c19098f1d7122087dd338a8f643203b3ce678c9d58169db733e17a03" - PKG_URL="https://static.rust-lang.org/dist/rust-std-${PKG_VERSION}-${MACHINE_HARDWARE_NAME}-unknown-linux-gnu.tar.xz" - ;; -esac -PKG_SOURCE_NAME="rust-std-snapshot_${PKG_VERSION}_${ARCH}.tar.xz" diff --git a/projects/ROCKNIX/packages/rust/rust/package.mk b/projects/ROCKNIX/packages/rust/rust/package.mk index 548ed3f6297..b7181c6f9ab 100755 --- a/projects/ROCKNIX/packages/rust/rust/package.mk +++ b/projects/ROCKNIX/packages/rust/rust/package.mk @@ -1,10 +1,10 @@ -# SPDX-License-Identifier: GPL-2.0 +# SPDX-License-Identifier: GPL-2.0-only # Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv) PKG_NAME="rust" -PKG_VERSION="1.94.1" -PKG_SHA256="4c142a625f12e3cdf716c68ae19f4f60d98ad1482627b08579b15838e95ad514" -PKG_LICENSE="MIT" +PKG_VERSION="1.97.1" +PKG_SHA256="622c2b429c53cbfdc0dd3a51d03554e91cd63ebec1912c1f5709640cdfef1a9d" +PKG_LICENSE="MIT OR Apache-2.0" PKG_SITE="https://www.rust-lang.org" PKG_URL="https://static.rust-lang.org/dist/rustc-${PKG_VERSION}-src.tar.gz" PKG_DEPENDS_HOST="toolchain llvm:host" @@ -19,13 +19,14 @@ pre_configure_host() { } configure_host() { - + # rust has no built-in *-rocknix-* targets, so supply them as custom + # target specs mkdir -p ${PKG_BUILD}/targets case "${TARGET_ARCH}" in "arm") # the arm target is special because we specify the subarch. ie armv8a - cp -a ${PKG_DIR}/targets/arm-libreelec-linux-gnueabihf.json ${PKG_BUILD}/targets/${TARGET_NAME}.json + cp -a ${PKG_DIR}/targets/arm-rocknix-linux-gnueabihf.json ${PKG_BUILD}/targets/${TARGET_NAME}.json ;; "aarch64" | "x86_64") cp -a ${PKG_DIR}/targets/${TARGET_NAME}.json ${PKG_BUILD}/targets/${TARGET_NAME}.json @@ -33,7 +34,7 @@ configure_host() { esac cat >${PKG_BUILD}/config.toml < +Date: Sat, 18 Apr 2009 22:06:12 +0200 +Subject: [PATCH] halt no init + +diff --git a/init/halt.c b/init/halt.c +--- a/init/halt.c ++++ b/init/halt.c +@@ -206,7 +206,7 @@ int halt_main(int argc UNUSED_PARAM, cha + + /* Perform action. */ + rc = 1; +- if (!(flags & 4)) { /* no -f */ ++ if (ENABLE_INIT && !(flags & 4)) { /* no -f */ + //TODO: I tend to think that signalling linuxrc is wrong + // pity original author didn't comment on it... + if (ENABLE_LINUXRC) { diff --git a/projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-02_silence-crond-startup-logging.patch b/projects/ROCKNIX/packages/sysutils/busybox/patches/0002-silence-crond-startup-logging.patch similarity index 63% rename from projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-02_silence-crond-startup-logging.patch rename to projects/ROCKNIX/packages/sysutils/busybox/patches/0002-silence-crond-startup-logging.patch index 30105bdb185..1f04f83de76 100644 --- a/projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-02_silence-crond-startup-logging.patch +++ b/projects/ROCKNIX/packages/sysutils/busybox/patches/0002-silence-crond-startup-logging.patch @@ -7,14 +7,14 @@ Subject: [PATCH] silence crond startup logging miscutils/crond.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) -diff -Naur busybox-1.23.0/miscutils/crond.c busybox-1.23.0.patch/miscutils/crond.c ---- busybox-1.23.0/miscutils/crond.c 2014-10-04 22:35:59.000000000 +0200 -+++ busybox-1.23.0.patch/miscutils/crond.c 2014-12-26 23:07:53.386118290 +0100 -@@ -1054,7 +1054,6 @@ +diff --git a/miscutils/crond.c b/miscutils/crond.c +--- a/miscutils/crond.c ++++ b/miscutils/crond.c +@@ -1068,7 +1068,6 @@ int crond_main(int argc UNUSED_PARAM, ch /* Useful on Android where DEFAULT_SHELL /bin/sh may not exist */ G.default_shell = xstrdup(get_shell_name()); - + - log8("crond (busybox "BB_VER") started, log level %d", G.log_level); rescan_crontab_dir(); - write_pidfile(CONFIG_PID_FILE_PATH "/crond.pid"); + write_pidfile_std_path_and_ext("crond"); #if ENABLE_FEATURE_CROND_SPECIAL_TIMES diff --git a/projects/ROCKNIX/packages/sysutils/busybox/patches/0003-make-unicode-printable.patch b/projects/ROCKNIX/packages/sysutils/busybox/patches/0003-make-unicode-printable.patch new file mode 100644 index 00000000000..9b5d2b9cac6 --- /dev/null +++ b/projects/ROCKNIX/packages/sysutils/busybox/patches/0003-make-unicode-printable.patch @@ -0,0 +1,33 @@ +From 52d8c5f2f80c0a571f07c2d1540c340a4741d1ea Mon Sep 17 00:00:00 2001 +From: Stefan Saraev +Date: Mon, 19 May 2014 23:52:07 +0300 +Subject: [PATCH] make unicode printable + +# +# stolen from OpenWRT +# +# https://dev.openwrt.org/attachment/ticket/7993/701-make_unicode_printable.patch +# + +--- +diff --git a/libbb/printable_string.c b/libbb/printable_string.c +--- a/libbb/printable_string.c ++++ b/libbb/printable_string.c +@@ -28,8 +28,6 @@ const char* FAST_FUNC printable_string2( + } + if (c < ' ') + break; +- if (c >= 0x7f) +- break; + s++; + } + +@@ -42,7 +40,7 @@ const char* FAST_FUNC printable_string2( + unsigned char c = *d; + if (c == '\0') + break; +- if (c < ' ' || c >= 0x7f) ++ if (c < ' ') + *d = '?'; + d++; + } diff --git a/projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-04-revert-dd-fsync-change.patch b/projects/ROCKNIX/packages/sysutils/busybox/patches/0004-revert-dd-fsync-change.patch similarity index 87% rename from projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-04-revert-dd-fsync-change.patch rename to projects/ROCKNIX/packages/sysutils/busybox/patches/0004-revert-dd-fsync-change.patch index e5dabec86a4..1c063cbbf0f 100644 --- a/projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-04-revert-dd-fsync-change.patch +++ b/projects/ROCKNIX/packages/sysutils/busybox/patches/0004-revert-dd-fsync-change.patch @@ -13,7 +13,7 @@ diff --git a/coreutils/dd.c b/coreutils/dd.c index d302f35..bf0c4ab 100644 --- a/coreutils/dd.c +++ b/coreutils/dd.c -@@ -531,11 +531,11 @@ int dd_main(int argc UNUSED_PARAM, char **argv) +@@ -643,11 +643,11 @@ int dd_main(int argc UNUSED_PARAM, char if (write_and_stats(ibuf, n, obs, outfile)) goto out_status; } @@ -28,7 +28,7 @@ index d302f35..bf0c4ab 100644 + } } - if (ENABLE_FEATURE_DD_IBS_OBS && oc) { + #if ENABLE_FEATURE_DD_IBS_OBS -- 2.7.4 diff --git a/projects/ROCKNIX/packages/sysutils/busybox/patches/0005-update-shadow-or-passwd-not-both.patch b/projects/ROCKNIX/packages/sysutils/busybox/patches/0005-update-shadow-or-passwd-not-both.patch new file mode 100644 index 00000000000..de510b596d0 --- /dev/null +++ b/projects/ROCKNIX/packages/sysutils/busybox/patches/0005-update-shadow-or-passwd-not-both.patch @@ -0,0 +1,17 @@ +From 712ce0b82e49bd55b55b3e5a5db6bc642390d7a1 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak +Date: Mon, 11 Sep 2017 20:19:21 -0700 +Subject: [PATCH] update shadow or passwd not both + +diff --git a/loginutils/passwd.c b/loginutils/passwd.c +--- a/loginutils/passwd.c ++++ b/loginutils/passwd.c +@@ -218,7 +218,7 @@ int passwd_main(int argc UNUSED_PARAM, c + if (rc > 0) + /* password in /etc/shadow was updated */ + newp = (char*) "x"; +- if (rc >= 0) ++ if (rc == 0) + /* 0 = /etc/shadow missing (not an error), >0 = passwd changed in /etc/shadow */ + #endif + { diff --git a/projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-06-prevent-root-weak-passwd.patch b/projects/ROCKNIX/packages/sysutils/busybox/patches/0006-prevent-root-weak-passwd.patch similarity index 58% rename from projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-06-prevent-root-weak-passwd.patch rename to projects/ROCKNIX/packages/sysutils/busybox/patches/0006-prevent-root-weak-passwd.patch index a8e5c706cff..736cd2d883a 100644 --- a/projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-06-prevent-root-weak-passwd.patch +++ b/projects/ROCKNIX/packages/sysutils/busybox/patches/0006-prevent-root-weak-passwd.patch @@ -1,8 +1,13 @@ +From 628ce14af45efee04e2cc2be702cd03d284418f2 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Fri, 08 Dec 2017 06:53:41 +0000 +Subject: [PATCH] prevent root weak passwd + diff --git a/loginutils/passwd.c b/loginutils/passwd.c index 6c643d3..df8859d 100644 --- a/loginutils/passwd.c +++ b/loginutils/passwd.c -@@ -69,7 +69,6 @@ static char* new_password(const struct passwd *pw, uid_t myuid, const char *algo +@@ -69,7 +69,6 @@ static char* new_password(const struct p goto err_ret; if (ENABLE_FEATURE_PASSWD_WEAK_CHECK && obscure(orig, newp, pw) /* NB: passing NULL orig is ok */ diff --git a/projects/ROCKNIX/packages/sysutils/busybox/patches/0010-add-MS_BIND-when-remounting-a-bind-mount.patch b/projects/ROCKNIX/packages/sysutils/busybox/patches/0010-add-MS_BIND-when-remounting-a-bind-mount.patch new file mode 100644 index 00000000000..c74a10ec814 --- /dev/null +++ b/projects/ROCKNIX/packages/sysutils/busybox/patches/0010-add-MS_BIND-when-remounting-a-bind-mount.patch @@ -0,0 +1,73 @@ +From 5624e803c89ee79afe7c6fd0ef9929110505a800 Mon Sep 17 00:00:00 2001 +Subject: [PATCH] mount: add MS_BIND when remounting a bind mount + +Remounting a bind mount without MS_BIND makes it visible as an ordinary +mount. A bind mount is only identifiable from /proc/self/mountinfo, where +its root field names a subdirectory rather than "/", so walk that and +take the last matching entry in case several sources are stacked on one +mount point. + +Original by Peter Vicman ; rebased for 1.38 and +the line leak in the read loop fixed. + +diff --git a/util-linux/mount.c b/util-linux/mount.c +--- a/util-linux/mount.c ++++ b/util-linux/mount.c +@@ -1917,7 +1917,46 @@ + } + + #endif // !ENABLE_FEATURE_MOUNT_NFS ++ ++// Check mount point in /proc/self/mountinfo and identify bind mount ++// return 1 for bind mount, 0 for normal mount ++static int check_bind_mount(struct mntent *mp) ++{ ++ int mnt_dir_len; ++ char *p; ++ FILE *fp; ++ char *line; ++ int ret = 0; + ++ // https://www.kernel.org/doc/Documentation/filesystems/proc.txt ++ // 21 20 179:20 /rocknix_flash /flash ro,noatime shared:2 - ext4 /dev/data rw ++ // 20 22 179:1 / /flash ro,noatime shared:2 - vfat /dev/mmcblk1p1 ro ++ ++ fp = fopen("/proc/self/mountinfo", "r"); ++ if (fp == NULL) ++ return ret; ++ ++ // remove trailing slash ++ mnt_dir_len = strlen(mp->mnt_dir); ++ if (mnt_dir_len > 1 && mp->mnt_dir[mnt_dir_len - 1] == '/') { ++ mnt_dir_len--; ++ mp->mnt_dir[mnt_dir_len] = '\0'; ++ } ++ ++ while ((line = xmalloc_fgetline(fp)) != NULL) { ++ // find mount point ++ p = strstr(line, mp->mnt_dir); ++ if (p != NULL) { ++ // a bind mount names a subdirectory as its root, not just "/" ++ ret = (strncmp(p - 2, "/ ", 2) != 0); // last entry wins ++ } ++ free(line); ++ } ++ ++ fclose(fp); ++ return ret; ++} ++ + // Find "...,NAME=NUM,..." in the option string, remove "NAME=NUM" option + // and return NUM. + // Return 0 if not found. +@@ -2152,6 +2191,10 @@ + } else if (S_ISDIR(st.st_mode) && !mp->mnt_type) + vfsflags |= MS_BIND; + } ++ ++ // add explicit MS_BIND if remounting a bind mount ++ if ((vfsflags & MS_REMOUNT) && check_bind_mount(mp)) ++ vfsflags |= MS_BIND; + + // If we know the fstype (or don't need to), jump straight + // to the actual mount. diff --git a/projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-00_halt_no_init.patch b/projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-00_halt_no_init.patch deleted file mode 100644 index ce454f4c07b..00000000000 --- a/projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-00_halt_no_init.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Naur busybox-1.13.2/init/halt.c busybox-1.13.2a/init/halt.c ---- busybox-1.13.2/init/halt.c 2008-11-09 18:28:19.000000000 +0100 -+++ busybox-1.13.2a/init/halt.c 2009-02-01 16:38:37.000000000 +0100 -@@ -79,7 +79,7 @@ - - /* Perform action. */ - rc = 1; -- if (!(flags & 4)) { /* no -f */ -+ if (ENABLE_INIT && !(flags & 4)) { /* no -f */ - //TODO: I tend to think that signalling linuxrc is wrong - // pity original author didn't comment on it... - if (ENABLE_FEATURE_INITRD) { diff --git a/projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-03-make_unicode_printable.patch b/projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-03-make_unicode_printable.patch deleted file mode 100644 index ec7354f6d41..00000000000 --- a/projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-03-make_unicode_printable.patch +++ /dev/null @@ -1,26 +0,0 @@ -# -# stolen from OpenWRT -# -# https://dev.openwrt.org/attachment/ticket/7993/701-make_unicode_printable.patch -# - ---- a/libbb/printable_string.c 2013-01-13 20:06:04.210089516 +0800 -+++ b/libbb/printable_string.c 2013-01-13 20:00:27.917211167 +0800 -@@ -31,8 +31,6 @@ - } - if (c < ' ') - break; -- if (c >= 0x7f) -- break; - s++; - } - -@@ -45,7 +43,7 @@ - unsigned char c = *d; - if (c == '\0') - break; -- if (c < ' ' || c >= 0x7f) -+ if (c < ' ') - *d = '?'; - d++; - } diff --git a/projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-05-update-shadow-or-passwd-not-both.patch b/projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-05-update-shadow-or-passwd-not-both.patch deleted file mode 100644 index b2698c9808c..00000000000 --- a/projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-05-update-shadow-or-passwd-not-both.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Naur a/loginutils/passwd.c b/loginutils/passwd.c ---- a/loginutils/passwd.c 2017-07-06 08:14:57.000000000 -0700 -+++ b/loginutils/passwd.c 2017-09-11 17:06:07.572805135 -0700 -@@ -220,7 +220,7 @@ - if (rc > 0) - /* password in /etc/shadow was updated */ - newp = (char*) "x"; -- if (rc >= 0) -+ if (rc == 0) - /* 0 = /etc/shadow missing (not an error), >0 = passwd changed in /etc/shadow */ - #endif - { diff --git a/projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-10-add-MS_BIND-option-when-remouting-bind-mount.patch b/projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-10-add-MS_BIND-option-when-remouting-bind-mount.patch deleted file mode 100644 index 2fc43171662..00000000000 --- a/projects/ROCKNIX/packages/sysutils/busybox/patches/busybox-10-add-MS_BIND-option-when-remouting-bind-mount.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 5624e803c89ee79afe7c6fd0ef9929110505a800 Mon Sep 17 00:00:00 2001 -From: Peter Vicman -Date: Fri, 20 Sep 2019 18:58:30 +0200 -Subject: [PATCH] add MS_BIND option when remouting bind mount - -when remounting bind mount add explicit MS_BIND to parameters -to "hide" bind mount from user's view - -bind mount is only visible from /proc/self/mountinfo that's -why we traverse the lines and using last entry in case -multiple sources are mount over same mount point - -Signed-off-by: Peter Vicman ---- - util-linux/mount.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 48 insertions(+) - -diff --git a/util-linux/mount.c b/util-linux/mount.c -index 84c85c0..bc3fbda 100644 ---- a/util-linux/mount.c -+++ b/util-linux/mount.c -@@ -1887,6 +1887,50 @@ static int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts) - - #endif // !ENABLE_FEATURE_MOUNT_NFS - -+// Check mount point in /proc/self/mountinfo and identify bind mount -+// return 1 for bind mount, 0 for normal mount -+static int check_bind_mount(struct mntent *mp) -+{ -+int mnt_dir_len; -+char *p; -+FILE *fp; -+char *line = NULL; -+int ret = 0; -+ -+ // https://www.kernel.org/doc/Documentation/filesystems/proc.txt -+ // 21 20 179:20 /coreelec_flash /flash ro,noatime shared:2 - ext4 /dev/data rw,resgid=1065,data=ordered -+ // 20 22 179:1 / /flash ro,noatime shared:2 - vfat /dev/mmcblk1p1 ro,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro -+ -+ fp = fopen("/proc/self/mountinfo", "r"); -+ if (fp == NULL) -+ return ret; -+ -+ // remove trailing slash -+ mnt_dir_len = strlen(mp->mnt_dir); -+ if (mnt_dir_len > 1 && mp->mnt_dir[mnt_dir_len - 1] == '/') { -+ mnt_dir_len--; -+ mp->mnt_dir[mnt_dir_len] = '\0'; -+ } -+ -+ while ((line = xmalloc_fgetline(fp)) != NULL) { -+ // find mount point -+ p = strstr(line, mp->mnt_dir); -+ if (p == NULL) -+ continue; -+ -+ // bind mount has folder for root and not just "/" -+ ret = 0; // always use result from last entry -+ if (strncmp(p - 2, "/ ", 2) != 0) -+ ret = 1; -+ } -+ -+ if (line != NULL) -+ free(line); -+ -+ fclose(fp); -+ return ret; -+} -+ - // Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem - // type detection. Returns 0 for success, nonzero for failure. - // NB: mp->xxx fields may be trashed on exit -@@ -2058,6 +2102,10 @@ static int singlemount(struct mntent *mp, int ignore_busy) - vfsflags |= MS_BIND; - } - -+ // add explicit MS_BIND if remounting bind mount -+ if ((vfsflags & MS_REMOUNT) && (check_bind_mount(mp) == 1)) -+ vfsflags |= MS_BIND; -+ - // If we know the fstype (or don't need to), jump straight - // to the actual mount. - if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) { --- -2.7.4 - diff --git a/projects/ROCKNIX/packages/sysutils/busybox/profile.d/098-busybox b/projects/ROCKNIX/packages/sysutils/busybox/profile.d/098-busybox index 7de01127874..e9e82c9aafd 100644 --- a/projects/ROCKNIX/packages/sysutils/busybox/profile.d/098-busybox +++ b/projects/ROCKNIX/packages/sysutils/busybox/profile.d/098-busybox @@ -6,7 +6,7 @@ export HOME="/storage" export PATH="/usr/bin:/usr/sbin" -export HOSTNAME=`cat /etc/hostname` +export HOSTNAME=`cat /proc/sys/kernel/hostname` export PS1='\[\e[1m\]\h:\[\e[1m\]\w \[\e[0m\]\$\[\e[0m\] ' # Redirect requests for sudo to nowhere. diff --git a/projects/ROCKNIX/packages/sysutils/file/package.mk b/projects/ROCKNIX/packages/sysutils/file/package.mk index 25ea7f80341..630b94f1985 100644 --- a/projects/ROCKNIX/packages/sysutils/file/package.mk +++ b/projects/ROCKNIX/packages/sysutils/file/package.mk @@ -3,10 +3,11 @@ # Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS) PKG_NAME="file" -PKG_VERSION="c5eb6d6" +PKG_VERSION="5.48" +PKG_SHA256="ed14656883b23a364b4057c05595d93252da9bc473d30106519519d0da141283" PKG_LICENSE="BSD" PKG_SITE="http://www.darwinsys.com/file/" -PKG_URL="https://github.com/file/file/archive/${PKG_VERSION}.tar.gz" +PKG_URL="http://ftp.astron.com/pub/file/file-${PKG_VERSION}.tar.gz" PKG_DEPENDS_HOST="ccache:host autotools:host" PKG_DEPENDS_TARGET="toolchain file:host zlib" PKG_LONGDESC="The file utility is used to determine the types of various files." diff --git a/projects/ROCKNIX/packages/sysutils/i2c-tools/package.mk b/projects/ROCKNIX/packages/sysutils/i2c-tools/package.mk index 15ab0b800de..204b15db5a6 100644 --- a/projects/ROCKNIX/packages/sysutils/i2c-tools/package.mk +++ b/projects/ROCKNIX/packages/sysutils/i2c-tools/package.mk @@ -2,9 +2,9 @@ # Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv) PKG_NAME="i2c-tools" -PKG_VERSION="4.3" -PKG_SHA256="1f899e43603184fac32f34d72498fc737952dbc9c97a8dd9467fadfdf4600cf9" -PKG_LICENSE="GPL" +PKG_VERSION="4.4" +PKG_SHA256="8b15f0a880ab87280c40cfd7235cfff28134bf14d5646c07518b1ff6642a2473" +PKG_LICENSE="GPL-2.0-or-later" PKG_SITE="https://i2c.wiki.kernel.org/index.php/I2C_Tools" PKG_URL="https://www.kernel.org/pub/software/utils/i2c-tools/${PKG_NAME}-${PKG_VERSION}.tar.xz" PKG_DEPENDS_TARGET="toolchain Python3 distutilscross:host" diff --git a/projects/ROCKNIX/packages/sysutils/i2c-tools/patches/pyinstalldir.patch b/projects/ROCKNIX/packages/sysutils/i2c-tools/patches/pyinstalldir.patch index 07ee55d27f0..e6843d0ff84 100644 --- a/projects/ROCKNIX/packages/sysutils/i2c-tools/patches/pyinstalldir.patch +++ b/projects/ROCKNIX/packages/sysutils/i2c-tools/patches/pyinstalldir.patch @@ -1,12 +1,18 @@ -diff -ur a/py-smbus/Module.mk b/py-smbus/Module.mk ---- a/py-smbus/Module.mk 2014-02-20 09:37:15.711233000 +0100 -+++ b/py-smbus/Module.mk 2019-12-14 08:20:51.730946457 +0100 +Subject: [PATCH] py-smbus: honour DESTDIR when installing + +4.4 added --prefix="$(PREFIX)" to the distutils install, but we invoke +make with DESTDIR set and PREFIX=/usr, so without DESTDIR the module +lands in the host's /usr instead of the staging tree. + +diff --git a/py-smbus/Module.mk b/py-smbus/Module.mk +--- a/py-smbus/Module.mk ++++ b/py-smbus/Module.mk @@ -22,7 +22,7 @@ rm -rf py-smbus/build install-python: -- $(DISTUTILS) install -+ $(DISTUTILS) install --prefix=$(DESTDIR)$(PREFIX) +- $(DISTUTILS) install --prefix="$(PREFIX)" ++ $(DISTUTILS) install --prefix="$(DESTDIR)$(PREFIX)" all: all-python diff --git a/projects/ROCKNIX/packages/sysutils/squashfs-tools/package.mk b/projects/ROCKNIX/packages/sysutils/squashfs-tools/package.mk index 753827560e4..c71069318ba 100644 --- a/projects/ROCKNIX/packages/sysutils/squashfs-tools/package.mk +++ b/projects/ROCKNIX/packages/sysutils/squashfs-tools/package.mk @@ -2,8 +2,8 @@ # Copyright (C) 2026 ROCKNIX (https://github.com/ROCKNIX) PKG_NAME="squashfs-tools" -PKG_VERSION="4.7" -PKG_SHA256="f1605ef720aa0b23939a49ef4491f6e734333ccc4bda4324d330da647e105328" +PKG_VERSION="4.7.5" +PKG_SHA256="547b7b7f4d2e44bf91b6fc554664850c69563701deab9fd9cd7e21f694c88ea6" PKG_LICENSE="GPL" PKG_SITE="https://github.com/plougher/squashfs-tools" PKG_URL="https://github.com/plougher/squashfs-tools/releases/download/${PKG_VERSION}/${PKG_NAME}-${PKG_VERSION}.tar.gz" diff --git a/projects/ROCKNIX/packages/sysutils/systemd/package.mk b/projects/ROCKNIX/packages/sysutils/systemd/package.mk index c2a4247e332..84a35dcf886 100644 --- a/projects/ROCKNIX/packages/sysutils/systemd/package.mk +++ b/projects/ROCKNIX/packages/sysutils/systemd/package.mk @@ -3,18 +3,18 @@ # Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv) PKG_NAME="systemd" -PKG_VERSION="255.8" -PKG_LICENSE="LGPL2.1+" +PKG_VERSION="261.2" +PKG_SHA256="ed1059ff964f5df35b6056434cc17cc83f86dc913f10489948a0b19b6081c5ec" +PKG_LICENSE="LGPL-2.1-or-later" PKG_SITE="http://www.freedesktop.org/wiki/Software/systemd" -PKG_URL="https://github.com/systemd/systemd-stable/archive/v${PKG_VERSION}.tar.gz" +PKG_URL="https://github.com/systemd/systemd/archive/v${PKG_VERSION}.tar.gz" PKG_DEPENDS_TARGET="toolchain libcap kmod util-linux libidn2 Python3:host Jinja2:host pcre2 zstd libgcrypt openssl" PKG_LONGDESC="A system and session manager for Linux, compatible with SysV and LSB init scripts." +PKG_BUILD_FLAGS="+lto" PKG_MESON_OPTS_TARGET="--libdir=/usr/lib \ - -Drootprefix=/usr \ - -Dsplit-usr=false \ + -Dfallback-hostname=ROCKNIX \ -Dsplit-bin=true \ - -Ddefault-hierarchy=hybrid \ -Dtty-gid=5 \ -Dtests=false \ -Dseccomp=false \ @@ -31,9 +31,7 @@ PKG_MESON_OPTS_TARGET="--libdir=/usr/lib \ -Dmicrohttpd=false \ -Dlibcryptsetup=false \ -Dlibcurl=false \ - -Dlibidn=false \ -Dlibidn2=true \ - -Dlibiptc=false \ -Dqrencode=false \ -Dgcrypt=true \ -Dgnutls=false \ @@ -93,6 +91,7 @@ PKG_MESON_OPTS_TARGET="--libdir=/usr/lib \ -Dlink-udev-shared=true \ -Dlink-systemctl-shared=true \ -Dlink-networkd-shared=false \ + -Djournal-storage-default=auto \ -Dbashcompletiondir=no \ -Dzshcompletiondir=no \ -Dkmod-path=/usr/bin/kmod \ @@ -117,7 +116,6 @@ pre_configure_target() { post_makeinstall_target() { # remove unneeded stuff - safe_remove ${INSTALL}/etc/init.d safe_remove ${INSTALL}/etc/systemd/system safe_remove ${INSTALL}/etc/xdg safe_remove ${INSTALL}/etc/X11 @@ -136,7 +134,6 @@ post_makeinstall_target() { safe_remove ${INSTALL}/usr/lib/udev/rules.d/73-seat-late.rules # remove getty units, we dont want a console - safe_remove ${INSTALL}/usr/lib/systemd/system/autovt@.service safe_remove ${INSTALL}/usr/lib/systemd/system/console-getty.service safe_remove ${INSTALL}/usr/lib/systemd/system/container-getty@.service safe_remove ${INSTALL}/usr/lib/systemd/system/getty.target @@ -157,6 +154,11 @@ post_makeinstall_target() { # adjust systemd-hwdb-update (we have read-only /etc). sed '/^ConditionNeedsUpdate=.*$/d' -i ${INSTALL}/usr/lib/systemd/system/systemd-hwdb-update.service + # remove systemd-creds, we do not use the credentials/provisioning stack + safe_remove ${INSTALL}/usr/bin/systemd-creds + safe_remove ${INSTALL}/usr/lib/tmpfiles.d/credstore.conf + safe_remove ${INSTALL}/usr/lib/tmpfiles.d/provision.conf + # remove nspawn safe_remove ${INSTALL}/usr/bin/systemd-nspawn safe_remove ${INSTALL}/usr/lib/systemd/system/systemd-nspawn@.service diff --git a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0001-move-etc-systemd-system-to-storage-.config-system.d.patch b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0001-move-etc-systemd-system-to-storage-.config-system.d.patch index 9a2d176ad78..ed54be49219 100644 --- a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0001-move-etc-systemd-system-to-storage-.config-system.d.patch +++ b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0001-move-etc-systemd-system-to-storage-.config-system.d.patch @@ -1,17 +1,22 @@ -commit 43aba5ffffc6d35ed97db035c5818c76652b06de -Author: Matthias Reichl -Date: Mon Sep 28 23:55:13 2020 +0200 - - move /etc/systemd/system to /storage/.config/system.d +From 43aba5ffffc6d35ed97db035c5818c76652b06de Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Mon, 28 Sep 2020 23:55:13 +0200 +Subject: [PATCH] move /etc/systemd/system to /storage/.config/system.d +--- diff --git a/meson.build b/meson.build -index dbbddb68e2..4592cd1094 100644 -@@ -255,7 +255,7 @@ - conf.set_quoted('SYSTEMD_UPDATE_HELPER_PATH', libexecdir / 'systemd-update-helper') - conf.set_quoted('SYSTEMD_USERWORK_PATH', libexecdir / 'systemd-userwork') +index e9c64b098e..e810e6c3a7 100644 +--- a/meson.build ++++ b/meson.build +@@ -298,7 +298,7 @@ conf.set_quoted('SYSTEMD_USERWORK_PATH', libexecdir / 'syst + conf.set_quoted('SYSTEMD_MOUNTWORK_PATH', libexecdir / 'systemd-mountwork') + conf.set_quoted('SYSTEMD_NSRESOURCEWORK_PATH', libexecdir / 'systemd-nsresourcework') conf.set_quoted('SYSTEMD_VERITYSETUP_PATH', libexecdir / 'systemd-veritysetup') -conf.set_quoted('SYSTEM_CONFIG_UNIT_DIR', pkgsysconfdir / 'system') +conf.set_quoted('SYSTEM_CONFIG_UNIT_DIR', '/storage/.config/system.d') conf.set_quoted('SYSTEM_DATA_UNIT_DIR', systemunitdir) conf.set_quoted('SYSTEM_ENV_GENERATOR_DIR', systemenvgeneratordir) conf.set_quoted('SYSTEM_GENERATOR_DIR', systemgeneratordir) +-- +2.53.0 + diff --git a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0002-move-hwdb.bin-to-run.patch b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0002-move-hwdb.bin-to-run.patch index ac11b21fd33..f4128b76834 100644 --- a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0002-move-hwdb.bin-to-run.patch +++ b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0002-move-hwdb.bin-to-run.patch @@ -10,28 +10,27 @@ Subject: [PATCH] move hwdb.bin to /run 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libsystemd/sd-hwdb/hwdb-internal.h b/src/libsystemd/sd-hwdb/hwdb-internal.h -index 5302679a62..4afdd6e306 100644 +index 72b2f777c8..2d8e2fbb16 100644 --- a/src/libsystemd/sd-hwdb/hwdb-internal.h +++ b/src/libsystemd/sd-hwdb/hwdb-internal.h -@@ -84,7 +84,7 @@ struct trie_value_entry2_f { +@@ -83,6 +83,6 @@ struct trie_value_entry2_f { - #define hwdb_bin_paths \ + #define HWDB_BIN_PATHS \ "/etc/systemd/hwdb/hwdb.bin\0" \ - "/etc/udev/hwdb.bin\0" \ + "/run/hwdb.bin\0" \ "/usr/lib/systemd/hwdb/hwdb.bin\0" \ - _CONF_PATHS_SPLIT_USR_NULSTR("systemd/hwdb/hwdb.bin") \ UDEVLIBEXECDIR "/hwdb.bin\0" diff --git a/src/shared/hwdb-util.c b/src/shared/hwdb-util.c -index 12621b7f89..552b1dc008 100644 +index f6415694e1..6a37caeb39 100644 --- a/src/shared/hwdb-util.c +++ b/src/shared/hwdb-util.c -@@ -587,7 +587,7 @@ int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool co - * source. If true, then hwdb.bin will be created without the information. systemd-hwdb command - * should set the argument false, and 'udevadm hwdb' command should set it true. */ +@@ -599,7 +599,7 @@ int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool co + path_simplify(root_abs); + } -- hwdb_bin = path_join(root, hwdb_bin_dir ?: "/etc/udev", "hwdb.bin"); -+ hwdb_bin = path_join(root, hwdb_bin_dir ?: "/run", "hwdb.bin"); +- hwdb_bin = path_join(root_abs, hwdb_bin_dir ?: "/etc/udev", "hwdb.bin"); ++ hwdb_bin = path_join(root_abs, hwdb_bin_dir ?: "/run", "hwdb.bin"); if (!hwdb_bin) return -ENOMEM; @@ -49,5 +48,5 @@ index 4ba36d1fc6..4848ae9661 100644 DefaultDependencies=no -- -2.34.1 +2.53.0 diff --git a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0004-dont-show-machineid-error-on-first-boot.patch b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0004-dont-show-machineid-error-on-first-boot.patch index 63bcaf32694..38302715ee8 100644 --- a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0004-dont-show-machineid-error-on-first-boot.patch +++ b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0004-dont-show-machineid-error-on-first-boot.patch @@ -1,11 +1,11 @@ --- a/src/shared/machine-id-setup.c +++ b/src/shared/machine-id-setup.c -@@ -129,7 +129,7 @@ - "2) /etc/machine-id exists and is empty.\n" - "3) /etc/machine-id is missing and /etc is writable.\n"); - else -- return log_error_errno(errno, "Cannot open %s: %m", etc_machine_id); -+ return 0; +@@ -168,7 +168,7 @@ + etc_machine_id, + etc); + +- return log_error_errno(errno, "Cannot create '%s': %m", etc_machine_id); ++ return 0; } - writable = false; + log_debug("Successfully opened new '%s' file.", etc_machine_id); diff --git a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0005-dont-provision-nonexistant-dirs.patch b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0005-dont-provision-nonexistant-dirs.patch deleted file mode 100644 index 5b608ff2ef3..00000000000 --- a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0005-dont-provision-nonexistant-dirs.patch +++ /dev/null @@ -1,22 +0,0 @@ ---- a/tmpfiles.d/provision.conf -+++ b/tmpfiles.d/provision.conf -@@ -15,8 +15,3 @@ - - # Provision a /etc/hosts file from credentials. - f^ /etc/hosts - - - - network.hosts -- --# Provision SSH key for root --d- /root :0700 root :root - --d- /root/.ssh :0700 root :root - --f^ /root/.ssh/authorized_keys :0600 root :root - ssh.authorized_keys.root ---- a/tmpfiles.d/credstore.conf -+++ b/tmpfiles.d/credstore.conf -@@ -6,8 +6,3 @@ - # (at your option) any later version. - - # See tmpfiles.d(5) for details -- --d /etc/credstore 0700 root root --d /etc/credstore.encrypted 0700 root root --z /run/credstore 0700 root root --z /run/credstore.encrypted 0700 root root diff --git a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0200-persist-persistent-timer-stamps.patch b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0200-persist-persistent-timer-stamps.patch index d7990a0dc53..c9164699022 100644 --- a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0200-persist-persistent-timer-stamps.patch +++ b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0200-persist-persistent-timer-stamps.patch @@ -8,15 +8,15 @@ Subject: [PATCH] timers: use a persistent filesystem for persistent timers 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/timer.c b/src/core/timer.c -index 03935ee..bfd5c02 100644 +index 510d8e1..41f41dd 100644 --- a/src/core/timer.c +++ b/src/core/timer.c -@@ -144,11 +144,11 @@ static int timer_setup_persistent(Timer *t) { +@@ -139,11 +139,11 @@ static int timer_setup_persistent(Timer *t) { if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) { -- r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers", UNIT_DEPENDENCY_FILE); -+ r = unit_require_mounts_for(UNIT(t), "/storage/.cache/systemd/timers", UNIT_DEPENDENCY_FILE); +- r = unit_add_mounts_for(UNIT(t), "/var/lib/systemd/timers", UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES); ++ r = unit_add_mounts_for(UNIT(t), "/storage/.cache/systemd/timers", UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES); if (r < 0) return r; @@ -26,5 +26,5 @@ index 03935ee..bfd5c02 100644 const char *e; -- -2.14.1 +2.53.0 diff --git a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0300-config-env-unhide-cursor.patch b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0300-config-env-unhide-cursor.patch index 17da76545a1..34a11d3e6b5 100644 --- a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0300-config-env-unhide-cursor.patch +++ b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0300-config-env-unhide-cursor.patch @@ -11,8 +11,8 @@ diff --git a/units/debug-shell.service.in b/units/debug-shell.service.in index 1127e68..4c3e971 100644 --- a/units/debug-shell.service.in +++ b/units/debug-shell.service.in -@@ -15,8 +15,8 @@ IgnoreOnIsolate=yes - ConditionPathExists={{DEBUGTTY}} +@@ -16,8 +16,8 @@ ConditionPathExists={{DEBUGTTY}} + After=systemd-vconsole-setup.service [Service] -Environment=TERM=linux diff --git a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0400-hide-useless-shutdown-log-message.patch b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0400-hide-useless-shutdown-log-message.patch index ab5b238cfc9..a1006121f6b 100644 --- a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0400-hide-useless-shutdown-log-message.patch +++ b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0400-hide-useless-shutdown-log-message.patch @@ -1,18 +1,16 @@ -diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c -index b709078a..76ad0715 100644 --- a/src/shutdown/shutdown.c +++ b/src/shutdown/shutdown.c -@@ -409,7 +409,7 @@ int main(int argc, char *argv[]) { +@@ -444,7 +444,7 @@ LOG_TARGET_KMSG)) bump_sysctl_printk_log_level(LOG_WARNING); - init_watchdog(); + /* init_watchdog(); */ - /* Lock us into memory */ - (void) mlockall(MCL_CURRENT|MCL_FUTURE); -@@ -443,7 +443,7 @@ int main(int argc, char *argv[]) { - for (;;) { + /* Lock us into memory. If the first mlockall call fails, don't attempt it again. */ + if (safe_mlockall(MCL_FUTURE|MCL_ONFAULT) >= 0) +@@ -479,7 +479,7 @@ + for (bool last_try = false;;) { bool changed = false; - (void) watchdog_ping(); @@ -20,16 +18,16 @@ index b709078a..76ad0715 100644 /* Let's trim the cgroup tree on each iteration so that we leave an empty cgroup tree around, * so that container managers get a nice notify event when we are down */ -@@ -547,7 +547,7 @@ int main(int argc, char *argv[]) { - - /* We're done with the watchdog. Note that the watchdog is explicitly not stopped here. It remains - * active to guard against any issues during the rest of the shutdown sequence. */ +@@ -586,7 +586,7 @@ + * explicitly close the device with disarm=false here, before releasing the rest of the watchdog + * data. */ + watchdog_close(/* disarm= */ false); - watchdog_free_device(); + /* watchdog_free_device(); */ - arguments[0] = NULL; /* Filled in by execute_directories(), when needed */ - arguments[1] = arg_verb; -@@ -573,13 +573,13 @@ int main(int argc, char *argv[]) { + const char *arguments[] = { + NULL, /* Filled in by execute_directories(), when needed */ +@@ -622,13 +622,13 @@ log_error_errno(r, "Failed to switch root to \"/run/initramfs\": %m"); } @@ -45,11 +43,9 @@ index b709078a..76ad0715 100644 /* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need * to be sync'ed explicitly in advance. So let's do this here, but not needlessly slow down -diff --git a/src/shutdown/umount.c b/src/shutdown/umount.c -index 1a9b99d7..b5621515 100644 --- a/src/shutdown/umount.c +++ b/src/shutdown/umount.c -@@ -331,7 +331,7 @@ static int umount_with_timeout(MountPoint *m, bool last_try) { +@@ -343,7 +343,7 @@ UMOUNT_NOFOLLOW | /* Don't follow symlinks: this should never happen unless our mount list was wrong */ (m->umount_lazily ? MNT_DETACH : MNT_FORCE))); if (r < 0) { @@ -58,11 +54,9 @@ index 1a9b99d7..b5621515 100644 if (r == -EBUSY && last_try) log_umount_blockers(m->path); -diff --git a/src/volatile-root/volatile-root.c b/src/volatile-root/volatile-root.c -index 27be7bdf..f24587e7 100644 --- a/src/volatile-root/volatile-root.c +++ b/src/volatile-root/volatile-root.c -@@ -50,7 +50,7 @@ static int make_volatile(const char *path) { +@@ -53,7 +53,7 @@ r = umount_recursive(path, 0); if (r < 0) { @@ -71,15 +65,16 @@ index 27be7bdf..f24587e7 100644 goto finish_umount; } ---- systemd.orig/src/core/job.c 2026-07-28 17:07:56.388732069 +0000 -+++ systemd/src/core/job.c 2026-07-28 17:58:17.659644182 +0000 -@@ -734,6 +734,10 @@ static void job_emit_done_message(Unit * +--- a/src/core/job.c ++++ b/src/core/job.c +@@ -763,6 +763,10 @@ assert(t >= 0); assert(t < _JOB_TYPE_MAX); - -+ /* Suppress console/journal status message for failed unmount jobs on mount units. */ + ++ /* Suppress the console/journal status message for failed unmount jobs on mount units. */ + if (t == JOB_STOP && result == JOB_FAILED && u->type == UNIT_MOUNT) + return; + if (!unit_log_level_test(u, job_done_messages[result].log_level)) return; + diff --git a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0500-Add-working-directory-storage-for-debug-shell.patch b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0500-Add-working-directory-storage-for-debug-shell.patch index e64752d74ef..786d4dbefbd 100644 --- a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0500-Add-working-directory-storage-for-debug-shell.patch +++ b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0500-Add-working-directory-storage-for-debug-shell.patch @@ -1,23 +1,10 @@ -From c38a2fc53e5ebb3fc4637a168408591003aad0fb Mon Sep 17 00:00:00 2001 -From: Portisch -Date: Mon, 30 Sep 2019 12:20:00 +0200 -Subject: [PATCH] Add working directory '/storage' for debug-shell - ---- - units/debug-shell.service.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/units/debug-shell.service.in b/units/debug-shell.service.in -index 9f3868e106..d5f93f18a6 100644 --- a/units/debug-shell.service.in +++ b/units/debug-shell.service.in -@@ -16,6 +16,7 @@ IgnoreOnIsolate=yes - ConditionPathExists=@DEBUGTTY@ - +@@ -16,6 +16,7 @@ + After=systemd-vconsole-setup.service + [Service] +WorkingDirectory=/storage Environment=ENV=/etc/profile ExecStart=/bin/sh -c 'echo -en "\033[?25h"; exec /bin/sh' Restart=always --- -2.17.1 diff --git a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0600-timedated-use-run-rocknix-localtime.patch b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0600-timedated-use-run-rocknix-localtime.patch index 3f826f5e276..157bdc659fc 100644 --- a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0600-timedated-use-run-rocknix-localtime.patch +++ b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0600-timedated-use-run-rocknix-localtime.patch @@ -1,6 +1,6 @@ --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c -@@ -290,34 +290,47 @@ +@@ -282,6 +282,7 @@ static int context_write_data_timezone(Context *c) { _cleanup_free_ char *p = NULL; const char *source; @@ -8,39 +8,27 @@ assert(c); -- /* No timezone is very similar to UTC. Hence in either of these cases link the UTC file in. Except if -- * it isn't installed, in which case we remove the symlink altogether. Since glibc defaults to an -- * internal version of UTC in that case behaviour is mostly equivalent. We still prefer creating the -- * symlink though, since things are more self explanatory then. */ - - if (isempty(c->zone) || streq(c->zone, "UTC")) { +@@ -294,7 +295,7 @@ if (access("/usr/share/zoneinfo/UTC", F_OK) < 0) { -- if (unlink("/etc/localtime") < 0 && errno != ENOENT) +- if (unlink(etc_localtime()) < 0 && errno != ENOENT) + if (unlink("/var/run/localtime") < 0 && errno != ENOENT) return -errno; return 0; - } - -- source = "../usr/share/zoneinfo/UTC"; -+ source = "/usr/share/zoneinfo/UTC"; - } else { -- p = path_join("../usr/share/zoneinfo", c->zone); -+ p = path_join("/usr/share/zoneinfo", c->zone); - if (!p) - return -ENOMEM; - +@@ -309,8 +310,24 @@ source = p; } -- return symlink_atomic(source, "/etc/localtime"); -+ r = symlink_atomic(source, "/var/run/localtime"); +- return symlinkat_atomic_full(source, AT_FDCWD, etc_localtime(), +- !secure_getenv("SYSTEMD_ETC_LOCALTIME")); ++ r = symlinkat_atomic_full(source, AT_FDCWD, "/var/run/localtime", ++ !secure_getenv("SYSTEMD_ETC_LOCALTIME")); + if (r < 0) + return r; + -+ /* Persist timezone across reboots via /storage/.cache/timezone */ ++ /* Persist the timezone across reboots, /var/run does not survive one. */ + if (!isempty(c->zone)) { + _cleanup_free_ char *tz_line = NULL; + @@ -55,4 +43,4 @@ + return 0; } - static int context_write_data_local_rtc(Context *c) { + static const char* etc_adjtime(void) { diff --git a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0601-get-timezone-follow-indirect-symlinks.patch b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0601-get-timezone-follow-indirect-symlinks.patch index e08377ed780..c2af45ae144 100644 --- a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0601-get-timezone-follow-indirect-symlinks.patch +++ b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-0601-get-timezone-follow-indirect-symlinks.patch @@ -1,23 +1,27 @@ --- a/src/basic/time-util.c +++ b/src/basic/time-util.c -@@ -1626,8 +1626,18 @@ int get_timezone(char **ret) { - return r; /* returns EINVAL if not a symlink */ +@@ -1692,8 +1692,22 @@ + return r; /* Return EINVAL if not a symlink */ - e = PATH_STARTSWITH_SET(t, "/usr/share/zoneinfo/", "../usr/share/zoneinfo/"); + const char *e = PATH_STARTSWITH_SET(t, "/usr/share/zoneinfo/", "../usr/share/zoneinfo/"); - if (!e) - return -EINVAL; + if (!e) { ++ /* Our /etc/localtime points at a symlink under /var/run, so resolve the ++ * whole chain before giving up. */ + char resolved[PATH_MAX + 1]; -+ if (realpath("/etc/localtime", resolved)) { ++ ++ if (realpath(etc_localtime(), resolved)) { + free(t); + t = strdup(resolved); + if (!t) + return -ENOMEM; ++ + e = PATH_STARTSWITH_SET(t, "/usr/share/zoneinfo/", "../usr/share/zoneinfo/"); + } + if (!e) + return -EINVAL; + } - if (!timezone_is_valid(e, LOG_DEBUG)) return -EINVAL; + diff --git a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-errno-list-filter-out-EFSBADCRC-and-EFSCORRUPTED.patch b/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-errno-list-filter-out-EFSBADCRC-and-EFSCORRUPTED.patch deleted file mode 100644 index cc5acfa5d7d..00000000000 --- a/projects/ROCKNIX/packages/sysutils/systemd/patches/systemd-errno-list-filter-out-EFSBADCRC-and-EFSCORRUPTED.patch +++ /dev/null @@ -1,34 +0,0 @@ -From fb146f6d2c5118410fd19907651fd8f7310bf69e Mon Sep 17 00:00:00 2001 -From: Yu Watanabe -Date: Tue, 24 Feb 2026 20:19:45 +0900 -Subject: [PATCH] errno-list: filter out EFSBADCRC and EFSCORRUPTED - -These are introduced in kernel v7.0. - -Upstream-Status: Backport [https://github.com/systemd/systemd/commit/3cfb16998808a6ec8012a6120d0a82f0e1a0c8bb] -Signed-off-by: Martin Jansa ---- - src/basic/generate-errno-list.sh | 10 +++++++--- - 1 file changed, 7 insertions(+), 3 deletions(-) - -diff --git a/src/basic/generate-errno-list.sh b/src/basic/generate-errno-list.sh -index f756b2e020..491fa1b6e3 100755 ---- a/src/basic/generate-errno-list.sh -+++ b/src/basic/generate-errno-list.sh -@@ -3,9 +3,13 @@ - set -eu - set -o pipefail - --# In kernel's arch/parisc/include/uapi/asm/errno.h, ECANCELLED and EREFUSED are defined as aliases of --# ECANCELED and ECONNREFUSED, respectively. Let's drop them. -+# In kernel's arch/parisc/include/uapi/asm/errno.h, The following aliases are defined: -+# ECANCELLED → ECANCELED -+# EREFUSED → ECONNREFUSED -+# EFSBADCRC → EBADMSG -+# EFSCORRUPTED → EUCLEAN -+# Let's drop them. - - ${1:?} -dM -include errno.h - = 258 sets up StateDirectory= with symlink-refusing +# semantics (openat2 RESOLVE_NO_SYMLINKS), so the unit dies at step +# STATE_DIRECTORY with ELOOP ('Too many levels of symbolic links') - +# observed on SM8250/SM8550 under 261.2. The rfkill binary itself +# hardcodes /var/lib/systemd/rfkill/ and follows the symlink fine, so +# drop the manager-side StateDirectory handling entirely. +[Service] +StateDirectory= diff --git a/projects/ROCKNIX/packages/sysutils/util-linux/package.mk b/projects/ROCKNIX/packages/sysutils/util-linux/package.mk index 4b7ea70fff7..cc7a88c53e8 100644 --- a/projects/ROCKNIX/packages/sysutils/util-linux/package.mk +++ b/projects/ROCKNIX/packages/sysutils/util-linux/package.mk @@ -4,8 +4,9 @@ # Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS) PKG_NAME="util-linux" -PKG_VERSION="2.39.2" -PKG_LICENSE="GPL" +PKG_VERSION="2.42.2" +PKG_SHA256="03a05d3adf9602ef128f2da05b84b3205ce60c351e5737c0370f74000679ce8a" +PKG_LICENSE="GPL-2.0-or-later" PKG_URL="https://www.kernel.org/pub/linux/utils/util-linux/v$(get_pkg_version_maj_min)/${PKG_NAME}-${PKG_VERSION}.tar.xz" PKG_DEPENDS_HOST="ccache:host autoconf:host automake:host intltool:host libtool:host pkg-config:host" PKG_DEPENDS_TARGET="toolchain" diff --git a/projects/ROCKNIX/packages/sysutils/util-linux/patches/util-linux-01-fix-pkgconf.patch b/projects/ROCKNIX/packages/sysutils/util-linux/patches/0001-fix-pkgconf.patch similarity index 92% rename from projects/ROCKNIX/packages/sysutils/util-linux/patches/util-linux-01-fix-pkgconf.patch rename to projects/ROCKNIX/packages/sysutils/util-linux/patches/0001-fix-pkgconf.patch index 7515acbc7ff..528238436c0 100644 --- a/projects/ROCKNIX/packages/sysutils/util-linux/patches/util-linux-01-fix-pkgconf.patch +++ b/projects/ROCKNIX/packages/sysutils/util-linux/patches/0001-fix-pkgconf.patch @@ -11,7 +11,6 @@ Subject: [PATCH] fix pkgconf 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/libblkid/blkid.pc.in b/libblkid/blkid.pc.in -index 40ec8a9..056ae64 100644 --- a/libblkid/blkid.pc.in +++ b/libblkid/blkid.pc.in @@ -1,7 +1,7 @@ @@ -26,10 +25,11 @@ index 40ec8a9..056ae64 100644 Name: blkid Description: Block device id library diff --git a/libmount/mount.pc.in b/libmount/mount.pc.in -index 2c32797..c8112c6 100644 --- a/libmount/mount.pc.in +++ b/libmount/mount.pc.in -@@ -1,7 +1,7 @@ +@@ -10,9 +10,9 @@ + # (at your option) any later version. + # prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@usrlib_execdir@ @@ -41,7 +41,6 @@ index 2c32797..c8112c6 100644 Name: mount Description: mount library diff --git a/libsmartcols/smartcols.pc.in b/libsmartcols/smartcols.pc.in -index 0b16739..8f474ef 100644 --- a/libsmartcols/smartcols.pc.in +++ b/libsmartcols/smartcols.pc.in @@ -1,7 +1,7 @@ @@ -56,7 +55,6 @@ index 0b16739..8f474ef 100644 Name: smartcols Description: table or tree library diff --git a/libuuid/uuid.pc.in b/libuuid/uuid.pc.in -index 875de19..ef1009e 100644 --- a/libuuid/uuid.pc.in +++ b/libuuid/uuid.pc.in @@ -1,7 +1,7 @@ @@ -70,6 +68,3 @@ index 875de19..ef1009e 100644 Name: uuid Description: Universally unique id library --- -1.7.2.5 - diff --git a/projects/ROCKNIX/packages/sysutils/util-linux/patches/util-linux-02-enable-blkdiscard.patch b/projects/ROCKNIX/packages/sysutils/util-linux/patches/0002-enable-blkdiscard.patch similarity index 63% rename from projects/ROCKNIX/packages/sysutils/util-linux/patches/util-linux-02-enable-blkdiscard.patch rename to projects/ROCKNIX/packages/sysutils/util-linux/patches/0002-enable-blkdiscard.patch index f7820b15ea0..7a1d1ed3a22 100644 --- a/projects/ROCKNIX/packages/sysutils/util-linux/patches/util-linux-02-enable-blkdiscard.patch +++ b/projects/ROCKNIX/packages/sysutils/util-linux/patches/0002-enable-blkdiscard.patch @@ -1,9 +1,18 @@ ---- util-linux-2.39.2/configure.ac.orig 2024-11-23 11:15:21.120872078 +0000 -+++ util-linux-2.39.2/configure.ac 2024-11-23 11:17:32.011211100 +0000 -@@ -1737,6 +1737,14 @@ +Subject: [PATCH] build: make blkdiscard configurable + +blkdiscard is only wired up as UL_BUILD_INIT(...,[check]), so with +--disable-all-programs there is no way to ask for it and +--enable-blkdiscard is an unrecognized option. Give it an AC_ARG_ENABLE +like the other tools. Still not present upstream in 2.42.2. + +diff --git a/configure.ac b/configure.ac +--- a/configure.ac ++++ b/configure.ac +@@ -1843,6 +1843,14 @@ + UL_REQUIRES_LINUX([fstrim]) UL_REQUIRES_BUILD([fstrim], [libmount]) AM_CONDITIONAL([BUILD_FSTRIM], [test "x$build_fstrim" = xyes]) - ++ +AC_ARG_ENABLE([blkdiscard], + AS_HELP_STRING([--disable-blkdiscard], [do not build blkdiscard(8)]), + [], [UL_DEFAULT_ENABLE([blkdiscard], [check])] @@ -11,11 +20,10 @@ +UL_BUILD_INIT([blkdiscard]) +UL_REQUIRES_LINUX([blkdiscard]) +AM_CONDITIONAL([BUILD_BLKDISCARD], [test "x$build_blkdiscard" = xyes]) -+ + AC_ARG_ENABLE([swapon], - AS_HELP_STRING([--disable-swapon], [do not build swapon(8) and swapoff(8)]), -@@ -2075,10 +2083,6 @@ +@@ -2235,10 +2243,6 @@ UL_REQUIRES_LINUX([fsfreeze]) AM_CONDITIONAL([BUILD_FSFREEZE], [test "x$build_fsfreeze" = xyes]) diff --git a/projects/ROCKNIX/packages/textproc/icu/package.mk b/projects/ROCKNIX/packages/textproc/icu/package.mk index 84ff375a9f9..38a697ad2da 100644 --- a/projects/ROCKNIX/packages/textproc/icu/package.mk +++ b/projects/ROCKNIX/packages/textproc/icu/package.mk @@ -2,10 +2,11 @@ # Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv) PKG_NAME="icu" -PKG_VERSION="74.1" +PKG_VERSION="78.3" +PKG_SHA256="3a2e7a47604ba702f345878308e6fefeca612ee895cf4a5f222e7955fabfe0c0" PKG_LICENSE="Custom" PKG_SITE="http://www.icu-project.org" -PKG_URL="https://github.com/unicode-org/icu/releases/download/release-${PKG_VERSION//./-}/icu4c-${PKG_VERSION//./_}-src.tgz" +PKG_URL="https://github.com/unicode-org/icu/releases/download/release-${PKG_VERSION}/icu4c-${PKG_VERSION}-sources.tgz" PKG_DEPENDS_HOST="toolchain:host" PKG_DEPENDS_TARGET="toolchain icu:host" PKG_LONGDESC="International Components for Unicode library." diff --git a/projects/ROCKNIX/packages/tools/at-spi2-core/package.mk b/projects/ROCKNIX/packages/tools/at-spi2-core/package.mk index 2f0935f1473..282af0e4ecf 100644 --- a/projects/ROCKNIX/packages/tools/at-spi2-core/package.mk +++ b/projects/ROCKNIX/packages/tools/at-spi2-core/package.mk @@ -3,8 +3,8 @@ # Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv) PKG_NAME="at-spi2-core" -PKG_VERSION="2.45.1" -PKG_SHA256="ba95f346e93108fbb3462c62437081d582154db279b4052dedc52a706828b192" +PKG_VERSION="2.61.1" +PKG_SHA256="0f88d443b8e3a4f7c701c4f6625032a989b8a0244cb2bdb3d3bd9872f00506f4" PKG_LICENSE="OSS" PKG_SITE="http://www.gnome.org/" PKG_URL="https://download.gnome.org/sources/at-spi2-core/${PKG_VERSION:0:4}/at-spi2-core-${PKG_VERSION}.tar.xz" @@ -12,7 +12,7 @@ PKG_DEPENDS_TARGET="toolchain atk dbus glib libXtst libXext libXi" PKG_LONGDESC="Protocol definitions and daemon for D-Bus at-spi." PKG_MESON_OPTS_TARGET="-Ddocs=false \ - -Dintrospection=no \ + -Dintrospection=disabled \ -Ddbus_daemon=/usr/bin/dbus-daemon" pre_configure_target() { diff --git a/projects/ROCKNIX/packages/tools/atf/package.mk b/projects/ROCKNIX/packages/tools/atf/package.mk index 070a32b64de..247d36b760c 100644 --- a/projects/ROCKNIX/packages/tools/atf/package.mk +++ b/projects/ROCKNIX/packages/tools/atf/package.mk @@ -15,14 +15,18 @@ PKG_PATCH_DIRS+="${DEVICE}" case ${DEVICE} in H700) PKG_VERSION="2.12.0" + PKG_SHA256="d95aaf292792c98035910d7e6c64ebfb297c897fef510415db1612f6d39f9223" ;; *) PKG_VERSION="2.10.0" - PKG_SHA256="696b8e53923aac4474532da7dd681f0bd044b329732facd65aeabea3e61adca9" + PKG_SHA256="6b1d5e89c311c5e7eaeb062713953311464c0378ab3e4ebc7ede72a746964bb1" ;; esac -PKG_URL="https://github.com/ARM-software/arm-trusted-firmware/archive/v${PKG_VERSION}.tar.gz" +# Same project as ARM-software/arm-trusted-firmware and byte-identical +# in content; use the org LibreELEC core does. The archives differ only +# in their top-level directory name, hence the different checksums. +PKG_URL="https://github.com/TrustedFirmware-A/trusted-firmware-a/archive/v${PKG_VERSION}.tar.gz" [ -n "${KERNEL_TOOLCHAIN}" ] && PKG_DEPENDS_TARGET+=" gcc-${KERNEL_TOOLCHAIN}:host" diff --git a/projects/ROCKNIX/packages/tools/grub/package.mk b/projects/ROCKNIX/packages/tools/grub/package.mk index 0f78b06f7b6..159cd2ccc65 100644 --- a/projects/ROCKNIX/packages/tools/grub/package.mk +++ b/projects/ROCKNIX/packages/tools/grub/package.mk @@ -2,12 +2,18 @@ # Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv) PKG_NAME="grub" -PKG_VERSION="2.14-rc1" +PKG_VERSION="2.14" +PKG_SHA256="6dcd64c4c5163870dd4cd89d460d1aa8f59b150e721a1e2b493f88433bc79ca9" PKG_LICENSE="GPLv3" PKG_SITE="https://www.gnu.org/software/grub/index.html" -PKG_URL="http://git.savannah.gnu.org/cgit/grub.git/snapshot/${PKG_NAME}-${PKG_VERSION}.tar.gz" -PKG_DEPENDS_HOST="toolchain:host" -PKG_DEPENDS_TARGET="toolchain flex freetype:host gettext:host grub:host" +# grub development moved off Savannah, whose cgit snapshots are gone. The +# tag carries the project prefix, so the ref is grub-${PKG_VERSION}; the +# archive's own top directory is stripped by scripts/extract. +PKG_URL="https://gitlab.freedesktop.org/gnu-grub/grub/-/archive/${PKG_NAME}-${PKG_VERSION}/${PKG_NAME}-${PKG_VERSION}.tar.gz" +# 2.14 configure.ac m4_fatal()s without AX_CHECK_LINK_FLAG, so ./bootstrap +# needs autoconf-archive; 2.14-rc1 did not. Both phases bootstrap. +PKG_DEPENDS_HOST="toolchain:host autoconf-archive:host" +PKG_DEPENDS_TARGET="toolchain flex freetype:host gettext:host grub:host autoconf-archive:host" PKG_DEPENDS_UNPACK="gnulib" PKG_LONGDESC="GRUB is a Multiboot boot loader." PKG_TOOLCHAIN="configure" @@ -22,6 +28,10 @@ pre_configure_host() { unset LDFLAGS unset CPP + # autoconf-archive installs its macros into the sysroot, which is not on + # aclocal's default search path, so bootstrap cannot see AX_CHECK_LINK_FLAG. + export ACLOCAL_PATH="${SYSROOT_PREFIX}/usr/share/aclocal" + cd ${PKG_BUILD} # keep grub synced with gnulib ./bootstrap --gnulib-srcdir=$(get_build_dir gnulib) --copy --no-git --no-bootstrap-sync --skip-po @@ -45,6 +55,10 @@ pre_configure_target() { unset LDFLAGS unset CPP + # autoconf-archive installs its macros into the sysroot, which is not on + # aclocal's default search path, so bootstrap cannot see AX_CHECK_LINK_FLAG. + export ACLOCAL_PATH="${SYSROOT_PREFIX}/usr/share/aclocal" + cd ${PKG_BUILD} # keep grub synced with gnulib ./bootstrap --gnulib-srcdir=$(get_build_dir gnulib) --copy --no-git --no-bootstrap-sync --skip-po @@ -61,10 +75,15 @@ pre_configure_target() { } make_target() { + # glibc 2.44 makes strchr and friends C23 const-generic, so given a + # "const char *" they now return "const char *". util/resolve.c assigns + # that to a plain "char *" and grub builds -Werror. The result is only + # tested for NULL there, so losing the qualifier changes nothing, and + # upstream still carries the same line. make CC=${CC} \ AR=${AR} \ RANLIB=${RANLIB} \ - CFLAGS="-I${SYSROOT_PREFIX}/usr/include -fomit-frame-pointer -D_FILE_OFFSET_BITS=64" \ + CFLAGS="-I${SYSROOT_PREFIX}/usr/include -fomit-frame-pointer -D_FILE_OFFSET_BITS=64 -Wno-error=discarded-qualifiers" \ LDFLAGS="-L${SYSROOT_PREFIX}/usr/lib" } diff --git a/projects/ROCKNIX/packages/tools/miniupnpc/package.mk b/projects/ROCKNIX/packages/tools/miniupnpc/package.mk deleted file mode 100644 index 50d667340d9..00000000000 --- a/projects/ROCKNIX/packages/tools/miniupnpc/package.mk +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv) - -PKG_NAME="miniupnpc" -PKG_VERSION="2.3.3" -PKG_SHA256="d52a0afa614ad6c088cc9ddff1ae7d29c8c595ac5fdd321170a05f41e634bd1a" -PKG_LICENSE="BSD" -PKG_SITE="http://miniupnp.free.fr" -PKG_URL="http://miniupnp.free.fr/files/${PKG_NAME}-${PKG_VERSION}.tar.gz" -PKG_DEPENDS_TARGET="toolchain" -PKG_LONGDESC="The MiniUPnP project offers software which supports the UPnP Internet Gateway Device (IGD) specifications" - -PKG_CMAKE_OPTS_TARGET="-DUPNPC_BUILD_SHARED=OFF -DUPNPC_BUILD_STATIC=ON" diff --git a/projects/ROCKNIX/packages/tools/qemu/package.mk b/projects/ROCKNIX/packages/tools/qemu/package.mk deleted file mode 100644 index 1e72a7c0edb..00000000000 --- a/projects/ROCKNIX/packages/tools/qemu/package.mk +++ /dev/null @@ -1,52 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv) - -PKG_NAME="qemu" -PKG_VERSION="10.0.2" -PKG_SHA256="ef786f2398cb5184600f69aef4d5d691efd44576a3cff4126d38d4c6fec87759" -PKG_LICENSE="GPL" -PKG_SITE="https://www.qemu.org" -PKG_URL="https://download.qemu.org/qemu-${PKG_VERSION}.tar.xz" -PKG_DEPENDS_HOST="toolchain:host glib:host pixman:host Python3:host zlib:host" -PKG_LONGDESC="QEMU is a generic and open source machine emulator and virtualizer." -PKG_TOOLCHAIN="configure" - -pre_configure_host() { - - HOST_CONFIGURE_OPTS="\ - --bindir=${TOOLCHAIN}/bin \ - --extra-cflags=-I${TOOLCHAIN}/include \ - --extra-ldflags=-L${TOOLCHAIN}/lib \ - --libexecdir=${TOOLCHAIN}/lib \ - --localstatedir=${TOOLCHAIN}/var \ - --prefix=${TOOLCHAIN} \ - --sbindir=${TOOLCHAIN}/sbin \ - --sysconfdir=${TOOLCHAIN}/etc \ - --enable-tools \ - --enable-malloc=system \ - --disable-attr \ - --disable-auth-pam \ - --disable-install-blobs \ - --disable-capstone \ - --disable-curl \ - --disable-debug-info \ - --disable-debug-mutex \ - --disable-debug-tcg \ - --disable-docs \ - --disable-gcrypt \ - --disable-gnutls \ - --disable-system \ - --disable-vnc \ - --disable-werror \ - --disable-xkbcommon \ - --disable-zstd \ - --target-list=${TARGET_ARCH}-linux-user" - - export DONT_BUILD_LEGACY_PYC=1 -} - -makeinstall_host() { - mkdir -p ${TOOLCHAIN}/bin - cp ${PKG_BUILD}/.${HOST_NAME}/qemu-img ${TOOLCHAIN}/bin - cp ${PKG_BUILD}/.${HOST_NAME}/qemu-${TARGET_ARCH} ${TOOLCHAIN}/bin -} diff --git a/projects/ROCKNIX/packages/tools/socat/package.mk b/projects/ROCKNIX/packages/tools/socat/package.mk index d87c1bffbe1..1b3465f39a3 100644 --- a/projects/ROCKNIX/packages/tools/socat/package.mk +++ b/projects/ROCKNIX/packages/tools/socat/package.mk @@ -3,7 +3,8 @@ # Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS) PKG_NAME="socat" -PKG_VERSION="1.7.4.4" +PKG_VERSION="1.8.1.3" +PKG_SHA256="25bc6476292b2e614220989c77b0b6fca87bb2525d9747b31a6639b1fb602418" PKG_LICENSE="GPLv2+" PKG_SITE="http://www.dest-unreach.org/socat/download" PKG_URL="${PKG_SITE}/${PKG_NAME}-${PKG_VERSION}.tar.bz2" @@ -15,3 +16,9 @@ PKG_CONFIGURE_OPTS_TARGET+=" --disable-libwrap \ --disable-readline \ --enable-termios" + +pre_makeinstall_target() { + # 1.8 installs helper scripts that ship in the source tree; we build out + # of tree, so make install looks for them in the build directory + cp -f ${PKG_BUILD}/*.sh ${PKG_BUILD}/.${TARGET_NAME}/ 2>/dev/null || true +} diff --git a/projects/ROCKNIX/packages/wayland/compositor/sway/package.mk b/projects/ROCKNIX/packages/wayland/compositor/sway/package.mk index 6514964a727..ccffcb363dd 100644 --- a/projects/ROCKNIX/packages/wayland/compositor/sway/package.mk +++ b/projects/ROCKNIX/packages/wayland/compositor/sway/package.mk @@ -9,16 +9,26 @@ PKG_LONGDESC="i3-compatible Wayland compositor" PKG_TOOLCHAIN="meson" PKG_PATCH_DIRS+="${DEVICE}" +# the sway version has to match the wlroots ABI the device gets, so this +# case must mirror the one in the wlroots package case ${DEVICE} in RK3588) + # wlroots 0.17.4-rk PKG_VERSION="1.9" PKG_URL="https://github.com/swaywm/sway/archive/${PKG_VERSION}.zip" ;; - *) + RK3326|RK3566|RK3576|S922X) + # wlroots 0.19.3-rk, the libmali fork PKG_VERSION="1.11" PKG_SHA256="0e37a55b7c3379230e97e1ad982542b75016a0c7d6676198604e557f9b373dae" PKG_URL="https://github.com/swaywm/sway/releases/download/${PKG_VERSION}/sway-${PKG_VERSION}.tar.gz" ;; + *) + # pairs with stock wlroots 0.20.x + PKG_VERSION="1.12" + PKG_SHA256="a7b1becc217433c11c6284d36bcea0687b87b77b0ed26a384565292ec321f2b1" + PKG_URL="https://github.com/swaywm/sway/releases/download/${PKG_VERSION}/sway-${PKG_VERSION}.tar.gz" + ;; esac # to enable xwayland package: https://gitlab.freedesktop.org/xorg/lib/libxcb-wm/-/tree/master/icccm?ref_type=heads diff --git a/projects/ROCKNIX/packages/wayland/compositor/sway/patches/1.9/0001-ipc-handle-the-sticky-drag-lock-state.patch b/projects/ROCKNIX/packages/wayland/compositor/sway/patches/1.9/0001-ipc-handle-the-sticky-drag-lock-state.patch new file mode 100644 index 00000000000..72fa221c0a0 --- /dev/null +++ b/projects/ROCKNIX/packages/wayland/compositor/sway/patches/1.9/0001-ipc-handle-the-sticky-drag-lock-state.patch @@ -0,0 +1,41 @@ +From: ROCKNIX +Subject: [PATCH] ipc: handle the sticky drag-lock state + +libinput grew LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY and sway builds +-Werror, so RK3588's arm leg stops here: + + sway/ipc-json.c:910:17: error: enumeration value + 'LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY' not handled in switch + +Only this branch is affected. RK3588 is the one device still on sway +1.9, to stay in step with its wlroots 0.17.4-rk; every other device is +on 1.11 or 1.12, which already carry the case. + +Same string upstream uses. Unlike the equivalent wlroots gap this is +not a behavioural bug - drag_lock is initialised to "unknown", so the +unhandled value already fell through safely and only the -Werror stops +the build - so this is purely about reporting the right state over IPC. + +Upstream guards the case with HAVE_LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_ +STICKY from its meson feature detection. That guard exists for building +against older libinput, which cannot happen here: the tree has one +libinput and it is the one that defines the value. Adding the meson +probe for a single pinned device fork would be more moving parts than +the problem needs. + +ipc-json.c is the only file affected. 1.9 has twelve libinput switches +and this is the one gap - the CLICKFINGER_MAP values 1.11 adds live in +a switch 1.9 does not have. + +--- a/sway/ipc-json.c ++++ b/sway/ipc-json.c +@@ -914,6 +914,9 @@ + case LIBINPUT_CONFIG_DRAG_LOCK_DISABLED: + drag_lock = "disabled"; + break; ++ case LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY: ++ drag_lock = "enabled_sticky"; ++ break; + } + json_object_object_add(object, "tap_drag_lock", + json_object_new_string(drag_lock)); diff --git a/projects/ROCKNIX/packages/wayland/lib/fcft/package.mk b/projects/ROCKNIX/packages/wayland/lib/fcft/package.mk index cde98a58e7a..f2382c91ad8 100644 --- a/projects/ROCKNIX/packages/wayland/lib/fcft/package.mk +++ b/projects/ROCKNIX/packages/wayland/lib/fcft/package.mk @@ -1,20 +1,11 @@ # SPDX-License-Identifier: GPL-2.0 # Copyright (C) 2021-present Team LibreELEC (https://libreelec.tv) -PKG_NAME="fcft" -PKG_VERSION="3.1.9" -PKG_LICENSE="MIT" -PKG_SITE="https://codeberg.org/dnkl/fcft" -PKG_URL="https://codeberg.org/dnkl/fcft/archive/${PKG_VERSION}.tar.gz" -PKG_DEPENDS_TARGET="toolchain pixman fontconfig freetype tllist" -PKG_LONGDESC="A simple library for font loading and glyph rasterization using FontConfig, FreeType and pixman." +. ${ROOT}/packages/wayland/lib/fcft/package.mk -PKG_MESON_OPTS_TARGET="-Ddocs=disabled \ - -Dgrapheme-shaping=disabled \ - -Drun-shaping=disabled \ - -Dtest-text-shaping=false \ - -Dexamples=false" - -pre_configure_target() { -export TARGET_CFLAGS="${TARGET_CFLAGS} -Wno-error=maybe-uninitialized" -} +# Codeberg regenerated its cached archive for this tag, so the checksum +# LibreELEC recorded no longer matches what upstream serves; LE builds +# still pass because their own mirror holds the original bytes and ours +# does not. Content verified as upstream 3.3.3. Drop this once the +# tarball is on the ROCKNIX sources mirror. +PKG_SHA256="b0c0f4a599f43723736c8565b8b84337c4195077f07f1bb8bb3252bb13a2306a" diff --git a/projects/ROCKNIX/packages/wayland/lib/seatd/package.mk b/projects/ROCKNIX/packages/wayland/lib/seatd/package.mk index b7198600363..8e79881c6f0 100644 --- a/projects/ROCKNIX/packages/wayland/lib/seatd/package.mk +++ b/projects/ROCKNIX/packages/wayland/lib/seatd/package.mk @@ -2,10 +2,11 @@ # Copyright (C) 2021-present Team LibreELEC (https://libreelec.tv) PKG_NAME="seatd" -PKG_VERSION="0.9.0" +PKG_VERSION="0.9.3" +PKG_SHA256="302564d54d8e28191fadfd734f2675ecb0c9e0615a58011b89ef15dfa4dbaa96" PKG_LICENSE="MIT" PKG_SITE="https://git.sr.ht/~kennylevinsen/seatd" -PKG_URL="https://github.com/kennylevinsen/seatd/archive/refs/tags/${PKG_VERSION}.tar.gz" +PKG_URL="https://git.sr.ht/~kennylevinsen/seatd/archive/${PKG_VERSION}.tar.gz" PKG_DEPENDS_TARGET="toolchain systemd" PKG_LONGDESC="A minimal seat management daemon, and a universal seat management library." diff --git a/projects/ROCKNIX/packages/wayland/lib/tllist/package.mk b/projects/ROCKNIX/packages/wayland/lib/tllist/package.mk deleted file mode 100644 index 8405d6c0a44..00000000000 --- a/projects/ROCKNIX/packages/wayland/lib/tllist/package.mk +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Copyright (C) 2021-present Team LibreELEC (https://libreelec.tv) - -PKG_NAME="tllist" -PKG_VERSION="1.1.0" -PKG_SHA256="0e7b7094a02550dd80b7243bcffc3671550b0f1d8ba625e4dff52517827d5d23" -PKG_LICENSE="MIT" -PKG_SITE="https://codeberg.org/dnkl/tllist" -PKG_URL="https://codeberg.org/dnkl/tllist/archive/${PKG_VERSION}.tar.gz" -PKG_DEPENDS_TARGET="toolchain" -PKG_LONGDESC="A C header file only implementation of a typed linked list." diff --git a/projects/ROCKNIX/packages/wayland/lib/wlroots/package.mk b/projects/ROCKNIX/packages/wayland/lib/wlroots/package.mk index 016c1dc648e..3a127f058d4 100644 --- a/projects/ROCKNIX/packages/wayland/lib/wlroots/package.mk +++ b/projects/ROCKNIX/packages/wayland/lib/wlroots/package.mk @@ -4,7 +4,7 @@ PKG_NAME="wlroots" PKG_LICENSE="MIT" PKG_SITE="https://gitlab.freedesktop.org/wlroots/wlroots/" -PKG_DEPENDS_TARGET="toolchain libinput libxkbcommon pixman libdrm wayland wayland-protocols seatd xwayland hwdata:host libxcb xcb-util-wm" +PKG_DEPENDS_TARGET="toolchain libinput libxkbcommon pixman libdrm wayland wayland-protocols seatd xwayland hwdata:host libxcb xcb-util-wm libdisplay-info" PKG_LONGDESC="A modular Wayland compositor library" PKG_TOOLCHAIN="meson" @@ -22,8 +22,9 @@ case ${DEVICE} in PKG_URL="https://github.com/rocknix/rockchip-wlroots/archive/refs/tags/${PKG_VERSION}.tar.gz" ;; *) - PKG_VERSION="0.19.3" - PKG_SHA256="a6ff89b64ea15e424d1b0db4a22145fccf5ec2ff2e7b8af0fa35e2ac8975986f" + # stock upstream, matching the version LibreELEC core carries + PKG_VERSION="0.20.2" + PKG_SHA256="972c7ac44b17828f4702bfae7cd8347346a3fb5b2c1076cfa2c3fcedac5ec343" PKG_URL="${PKG_SITE}/-/archive/${PKG_VERSION}/wlroots-${PKG_VERSION}.tar.gz" ;; esac diff --git a/projects/ROCKNIX/packages/wayland/lib/wlroots/patches/0.17.4-rk/0001-libinput-ignore-unhandled-switch-types.patch b/projects/ROCKNIX/packages/wayland/lib/wlroots/patches/0.17.4-rk/0001-libinput-ignore-unhandled-switch-types.patch new file mode 100644 index 00000000000..37cdcaaea38 --- /dev/null +++ b/projects/ROCKNIX/packages/wayland/lib/wlroots/patches/0.17.4-rk/0001-libinput-ignore-unhandled-switch-types.patch @@ -0,0 +1,40 @@ +From: ROCKNIX +Subject: [PATCH] backend/libinput: ignore unhandled switch types + +libinput grew LIBINPUT_SWITCH_KEYPAD_SLIDE, which this wlroots is too +old to know about, so -Werror=switch stops the build: + + backend/libinput/switch.c:34:9: error: enumeration value + 'LIBINPUT_SWITCH_KEYPAD_SLIDE' not handled in switch + +Silencing the warning would be wrong. wlr_event is zero initialised by +its designated initialiser and WLR_SWITCH_TYPE_LID is 0, so an +unhandled type currently falls out of the switch and gets emitted to +the compositor as a lid event. + +Take the same route as wlroots 0.19/0.20, which return early with a +debug log rather than guessing. Those versions do it by feature test in +switch_type_from_libinput(); this branch has no such helper, so the +default label goes on the switch itself and needs no libinput version +check to compile against either libinput. + +--- a/backend/libinput/switch.c ++++ b/backend/libinput/switch.c +@@ -1,6 +1,7 @@ + #include + #include + #include ++#include + #include "backend/libinput.h" + + const struct wlr_switch_impl libinput_switch_impl = { +@@ -38,6 +39,9 @@ + case LIBINPUT_SWITCH_TABLET_MODE: + wlr_event.switch_type = WLR_SWITCH_TYPE_TABLET_MODE; + break; ++ default: ++ wlr_log(WLR_DEBUG, "Unhandled libinput switch type"); ++ return; + } + switch (libinput_event_switch_get_switch_state(sevent)) { + case LIBINPUT_SWITCH_STATE_OFF: diff --git a/projects/ROCKNIX/packages/wayland/libinput/package.mk b/projects/ROCKNIX/packages/wayland/libinput/package.mk deleted file mode 100644 index 06f6c3c7654..00000000000 --- a/projects/ROCKNIX/packages/wayland/libinput/package.mk +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (C) 2009-2016 Stephan Raue (stephan@openelec.tv) -# Copyright (C) 2017-present Team LibreELEC (https://libreelec.tv) - -PKG_NAME="libinput" -PKG_VERSION="1.26.2" -PKG_LICENSE="GPL" -PKG_SITE="https://www.freedesktop.org/wiki/Software/libinput/" -PKG_URL="https://gitlab.freedesktop.org/libinput/libinput/-/archive/${PKG_VERSION}/${PKG_NAME}-${PKG_VERSION}.tar.bz2" -PKG_DEPENDS_TARGET="toolchain systemd libevdev mtdev" -PKG_LONGDESC="libinput is a library to handle input devices in Wayland compositors and to provide a generic X.Org input driver." - -PKG_MESON_OPTS_TARGET="-Dlibwacom=false \ - -Ddebug-gui=false \ - -Dtests=false \ - -Ddocumentation=false" diff --git a/projects/ROCKNIX/packages/wayland/libxkbcommon/package.mk b/projects/ROCKNIX/packages/wayland/libxkbcommon/package.mk index c7b97634fa4..6f33ca89c52 100644 --- a/projects/ROCKNIX/packages/wayland/libxkbcommon/package.mk +++ b/projects/ROCKNIX/packages/wayland/libxkbcommon/package.mk @@ -1,26 +1,18 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (C) 2009-2016 Stephan Raue (stephan@openelec.tv) -# Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv) +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv) -PKG_NAME="libxkbcommon" -PKG_VERSION="1.6.0" -PKG_LICENSE="MIT" -PKG_SITE="https://xkbcommon.org" -PKG_URL="https://xkbcommon.org/download/${PKG_NAME}-${PKG_VERSION}.tar.xz" -PKG_DEPENDS_TARGET="toolchain xkeyboard-config libxml2 libXau libxcb" -PKG_LONGDESC="xkbcommon is a library to handle keyboard descriptions." +. ${ROOT}/packages/wayland/libxkbcommon/package.mk -PKG_MESON_OPTS_TARGET="-Denable-docs=false" - -if [ "${DISPLAYSERVER}" = "x11" ]; then - PKG_MESON_OPTS_TARGET+=" -Denable-x11=true \ - -Denable-wayland=false" -elif [ "${DISPLAYSERVER}" = "wl" ]; then - PKG_DEPENDS_TARGET+=" wayland wayland-protocols" - PKG_MESON_OPTS_TARGET+=" -Denable-x11=true \ - -Denable-wayland=true \ - -Dxkb-config-root=/usr/share/X11/xkb" -else - PKG_MESON_OPTS_TARGET+=" -Denable-x11=false \ - -Denable-wayland=false" +# core turns X11 support off under wayland; we keep it for XWayland clients, +# and point xkb at the location xkeyboard-config installs to +if [ "${DISPLAYSERVER}" = "wl" ]; then + PKG_DEPENDS_TARGET+=" libXau libxcb" + PKG_MESON_OPTS_TARGET="${PKG_MESON_OPTS_TARGET/-Denable-x11=false/-Denable-x11=true}" + PKG_MESON_OPTS_TARGET+=" -Dxkb-config-root=/usr/share/X11/xkb" fi + +pre_configure_target() { + if [ "${DISPLAYSERVER}" = "x11" -o "${DISPLAYSERVER}" = "wl" ]; then + TARGET_LDFLAGS="${LDFLAGS} -lXau -lxcb" + fi +} diff --git a/projects/ROCKNIX/packages/wayland/mtdev/package.mk b/projects/ROCKNIX/packages/wayland/mtdev/package.mk deleted file mode 100644 index 10ac8039b0d..00000000000 --- a/projects/ROCKNIX/packages/wayland/mtdev/package.mk +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (C) 2009-2016 Stephan Raue (stephan@openelec.tv) - -PKG_NAME="mtdev" -PKG_VERSION="1.1.6" -PKG_SHA256="15d7b28da8ac71d8bc8c9287c2045fd174267bc740bec10cfda332dc1204e0e0" -PKG_LICENSE="MIT" -PKG_SITE="http://bitmath.org" -PKG_URL="http://sources.buildroot.net/mtdev/${PKG_NAME}-${PKG_VERSION}.tar.bz2" -PKG_DEPENDS_TARGET="toolchain" -PKG_LONGDESC="The mtdev is a stand-alone library which transforms all variants of kernel MT events to the slotted type B protocol." -PKG_BUILD_FLAGS="+pic" - -PKG_CONFIGURE_OPTS_TARGET="--enable-static --disable-shared" diff --git a/projects/ROCKNIX/packages/wayland/util/bemenu/package.mk b/projects/ROCKNIX/packages/wayland/util/bemenu/package.mk index 6c4bb070521..8e7cd3b3304 100644 --- a/projects/ROCKNIX/packages/wayland/util/bemenu/package.mk +++ b/projects/ROCKNIX/packages/wayland/util/bemenu/package.mk @@ -2,8 +2,8 @@ # Copyright (C) 2021-present Team LibreELEC (https://libreelec.tv) PKG_NAME="bemenu" -PKG_VERSION="0.6.15" -PKG_SHA256="abad9656b194ac511fd87d3d3ab4b155957fc4e402e76082c7fbefa6e84dad75" +PKG_VERSION="0.6.23" +PKG_SHA256="0e7878c3bf57e0e362efe89c59deddd33819cd62b980be7e0b7bb4da45478e44" PKG_LICENSE="MIT" PKG_SITE="https://github.com/Cloudef/bemenu" PKG_URL="https://github.com/Cloudef/bemenu/archive/${PKG_VERSION}.tar.gz" diff --git a/projects/ROCKNIX/packages/wayland/util/foot/package.mk b/projects/ROCKNIX/packages/wayland/util/foot/package.mk index 45071661d2a..ee9af994dc5 100644 --- a/projects/ROCKNIX/packages/wayland/util/foot/package.mk +++ b/projects/ROCKNIX/packages/wayland/util/foot/package.mk @@ -1,34 +1,14 @@ # SPDX-License-Identifier: GPL-2.0 # Copyright (C) 2021-present Team LibreELEC (https://libreelec.tv) -PKG_NAME="foot" -PKG_VERSION="1.19.0" -PKG_LICENSE="MIT" -PKG_SITE="https://codeberg.org/dnkl/foot/" -PKG_URL="https://codeberg.org/dnkl/foot/archive/${PKG_VERSION}.tar.gz" -PKG_DEPENDS_TARGET="toolchain ncurses wayland wayland-protocols pixman fontconfig libxkbcommon fcft" -PKG_LONGDESC="A fast, lightweight and minimalistic Wayland terminal emulator" - -PKG_MESON_OPTS_TARGET="-Ddocs=disabled \ - -Dthemes=false \ - -Dime=false \ - -Dgrapheme-clustering=auto \ - -Dterminfo=disabled \ - -Ddefault-terminfo=xterm" - -pre_configure_target() { - export TARGET_CFLAGS=$(echo "${TARGET_CFLAGS} -Wno-error=switch") -} - -post_makeinstall_target(){ - # clean up - safe_remove ${INSTALL}/usr/share/* - - # install scripts - mkdir -p ${INSTALL}/usr/bin - cp ${PKG_DIR}/scripts/foot.sh ${INSTALL}/usr/bin - - # install config - mkdir -p ${INSTALL}/usr/share/foot - cp ${PKG_DIR}/config/foot.ini ${INSTALL}/usr/share/foot -} +# This shadow exists only for the checksum override below. It must keep +# scripts/ and config/, because PKG_DIR resolves here rather than merging +# with core, and the inherited install step copies from PKG_DIR; both are +# cosmetic duplicates of core's. The whole directory goes when the +# override does. +. ${ROOT}/packages/wayland/util/foot/package.mk + +# See the fcft shadow: codeberg regenerated its cached archive for this +# tag, so LibreELEC's recorded checksum no longer matches upstream. +# Content verified as upstream 1.27.0. +PKG_SHA256="f5917cad2d7b723b99873e53d78fd10ea202923d189aed5086591fc53b70b7e3" diff --git a/projects/ROCKNIX/packages/wayland/util/swaybg/package.mk b/projects/ROCKNIX/packages/wayland/util/swaybg/package.mk deleted file mode 100644 index 0d2d620a120..00000000000 --- a/projects/ROCKNIX/packages/wayland/util/swaybg/package.mk +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Copyright (C) 2021-present Team LibreELEC (https://libreelec.tv) - -PKG_NAME="swaybg" -PKG_VERSION="1.2.1" -PKG_SHA256="45c4a1a3b83c86ddc321a6136402b708f195a022d0ccee4641b23d14c3a3c25e" -PKG_LICENSE="MIT" -PKG_SITE="https://swaywm.org/" -PKG_URL="https://github.com/swaywm/swaybg/archive/v${PKG_VERSION}.tar.gz" -PKG_DEPENDS_TARGET="toolchain wayland wayland-protocols cairo pango gdk-pixbuf" -PKG_LONGDESC="Wallpaper tool for Wayland compositors" - -PKG_MESON_OPTS_TARGET="-Dgdk-pixbuf=enabled \ - -Dman-pages=disabled" - -pre_configure_target() { - # swaybg does not build without -Wno flags as all warnings being treated as errors - export TARGET_CFLAGS=$(echo "${TARGET_CFLAGS} -Wno-maybe-uninitialized") -} diff --git a/projects/ROCKNIX/packages/wayland/util/wlr-randr/package.mk b/projects/ROCKNIX/packages/wayland/util/wlr-randr/package.mk index 72915434431..f080c75b8b8 100644 --- a/projects/ROCKNIX/packages/wayland/util/wlr-randr/package.mk +++ b/projects/ROCKNIX/packages/wayland/util/wlr-randr/package.mk @@ -1,11 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -# Copyright (C) 2021-present Team LibreELEC (https://libreelec.tv) +# Copyright (C) 2024-present ROCKNIX (https://github.com/ROCKNIX) -PKG_NAME="wlr-randr" -PKG_VERSION="0.4.1" -PKG_SHA256="8af085aeed3132f7442a05bafeadfd0ea30e9a4818af1a91e161f7d560f2cd93" -PKG_LICENSE="MIT" -PKG_SITE="https://git.sr.ht/~emersion/wlr-randr" -PKG_URL="https://git.sr.ht/~emersion/wlr-randr/archive/v${PKG_VERSION}.tar.gz" -PKG_DEPENDS_TARGET="toolchain wayland" -PKG_LONGDESC="Utility to manage outputs of a Wayland compositor." +. ${ROOT}/packages/wayland/util/wlr-randr/package.mk diff --git a/projects/ROCKNIX/packages/wayland/wayland-protocols/package.mk b/projects/ROCKNIX/packages/wayland/wayland-protocols/package.mk index 5aa81733895..a502b5d4f63 100644 --- a/projects/ROCKNIX/packages/wayland/wayland-protocols/package.mk +++ b/projects/ROCKNIX/packages/wayland/wayland-protocols/package.mk @@ -1,17 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 # Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv) -PKG_NAME="wayland-protocols" -PKG_VERSION="1.44" -PKG_LICENSE="OSS" -PKG_SITE="https://wayland.freedesktop.org/" -PKG_URL="https://gitlab.freedesktop.org/wayland/${PKG_NAME}/-/releases/${PKG_VERSION}/downloads/${PKG_NAME}-${PKG_VERSION}.tar.xz" -PKG_DEPENDS_TARGET="toolchain wayland:host" -PKG_DEPENDS_HOST="toolchain:host wayland:host" -PKG_LONGDESC="Specifications of extended Wayland protocols" - -PKG_MESON_OPTS_TARGET="-Dtests=false" +. ${ROOT}/packages/wayland/wayland-protocols/package.mk -post_makeinstall_target() { - safe_remove ${INSTALL} -} +# we build this for the host as well +PKG_DEPENDS_HOST="toolchain:host wayland:host" diff --git a/projects/ROCKNIX/packages/wayland/wayland-protocols/patches/0001-build-add-Cflags-to-pkg-config-when-headers-are-inst.patch b/projects/ROCKNIX/packages/wayland/wayland-protocols/patches/0001-build-add-Cflags-to-pkg-config-when-headers-are-inst.patch new file mode 100644 index 00000000000..03ea5b1a349 --- /dev/null +++ b/projects/ROCKNIX/packages/wayland/wayland-protocols/patches/0001-build-add-Cflags-to-pkg-config-when-headers-are-inst.patch @@ -0,0 +1,48 @@ +From 82c7293fa8a6b32d1b38559238fdeda233025892 Mon Sep 17 00:00:00 2001 +From: Rudi Heitbaum +Date: Wed, 27 May 2026 13:42:20 +0000 +Subject: [PATCH] build: add Cflags to pkg-config when headers are installed + +When wayland-scanner >= 1.22.90 is available, wayland-protocols generates +and installs enum headers under ${includedir}/wayland-protocols/. However +the pkg-config file omits Cflags, leaving consumers unable to locate these +headers without manually patching the .pc file. + +Add extra_cflags to pkgconfig.generate() conditioned on the same +wayland-scanner version guard used for header generation, so that +Cflags: -I${includedir} is emitted only when the headers are actually +installed. + +Fixes build failures in wlroots 0.20+ which includes these headers +directly via . + +Signed-off-by: Rudi Heitbaum +--- + meson.build | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/meson.build b/meson.build +index 25d42ce..14bab63 100644 +--- a/meson.build ++++ b/meson.build +@@ -189,15 +189,13 @@ pkgconfig.generate( + filebase: 'wayland-protocols', + name: 'Wayland Protocols', + description: 'Wayland protocol files', +- dataonly: true, ++ dataonly: include_dirs.length() == 0, ++ extra_cflags: include_dirs.length() > 0 ? ['-I${includedir}'] : [], + variables: { +- 'prefix': get_option('prefix'), +- 'includedir': '${prefix}/@0@'.format(get_option('includedir')), + 'datarootdir': '${prefix}/@0@'.format(get_option('datadir')), + 'pkgdatadir': '${pc_sysrootdir}${datarootdir}/wayland-protocols' + }, + uninstalled_variables: { +- 'includedir': meson.current_build_dir() / 'include', + 'pkgdatadir': meson.project_source_root(), + }, + ) +-- +2.53.0 + diff --git a/projects/ROCKNIX/packages/wayland/wayland/package.mk b/projects/ROCKNIX/packages/wayland/wayland/package.mk index e43c8d60fce..d925c6ac14e 100644 --- a/projects/ROCKNIX/packages/wayland/wayland/package.mk +++ b/projects/ROCKNIX/packages/wayland/wayland/package.mk @@ -1,35 +1,11 @@ # SPDX-License-Identifier: GPL-2.0 # Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv) -PKG_NAME="wayland" -PKG_VERSION="1.23.1" -PKG_LICENSE="OSS" -PKG_SITE="https://wayland.freedesktop.org/" -PKG_URL="https://gitlab.freedesktop.org/wayland/wayland/-/releases/${PKG_VERSION}/downloads/${PKG_NAME}-${PKG_VERSION}.tar.xz" -PKG_DEPENDS_HOST="libffi:host expat:host libxml2:host meson:host" -PKG_DEPENDS_TARGET="toolchain wayland:host libffi expat libxml2" -PKG_LONGDESC="a display server protocol" +. ${ROOT}/packages/wayland/wayland/package.mk +# core builds only the scanner for the host; we need libwayland there too PKG_MESON_OPTS_HOST="-Dlibraries=true \ -Dscanner=true \ -Dtests=false \ -Ddocumentation=false \ -Ddtd_validation=false" - -PKG_MESON_OPTS_TARGET="-Dlibraries=true \ - -Dscanner=false \ - -Dtests=false \ - -Ddocumentation=false \ - -Ddtd_validation=false" - -pre_configure_target() { - # wayland does not build with NDEBUG (requires assert for tests) - export TARGET_CFLAGS=$(echo ${TARGET_CFLAGS} | sed -e "s|-DNDEBUG||g") -} - -post_makeinstall_host() { - cp ${TOOLCHAIN}/lib/pkgconfig/wayland-scanner.pc ${SYSROOT_PREFIX}/usr/lib/pkgconfig/ - # Needed for vulkan tools >= 1.3.299 - mkdir -p ${TOOLCHAIN}/${TARGET_NAME}/sysroot/usr/share/wayland - cp ${PKG_BUILD}/protocol/wayland.xml ${TOOLCHAIN}/${TARGET_NAME}/sysroot/usr/share/wayland/wayland.xml -} diff --git a/projects/ROCKNIX/packages/wayland/wayland/patches/00-fix-wayland-scanner-pkgconfig.patch b/projects/ROCKNIX/packages/wayland/wayland/patches/00-fix-wayland-scanner-pkgconfig.patch index 90d40ba7869..70d46e97e9d 100644 --- a/projects/ROCKNIX/packages/wayland/wayland/patches/00-fix-wayland-scanner-pkgconfig.patch +++ b/projects/ROCKNIX/packages/wayland/wayland/patches/00-fix-wayland-scanner-pkgconfig.patch @@ -1,13 +1,19 @@ +From: ROCKNIX +Subject: [PATCH] meson: keep pkgdatadir free of pc_sysrootdir + +pkg-config already prefixes ${pc_sysrootdir} itself when it is set, so +having it inside pkgdatadir too yields the sysroot path twice and the +protocol directory cannot be found when cross compiling. + diff --git a/src/meson.build b/src/meson.build -index 5d04334..59af71a 100644 --- a/src/meson.build +++ b/src/meson.build -@@ -65,7 +65,7 @@ if get_option('scanner') +@@ -65,7 +65,7 @@ version: meson.project_version(), variables: [ 'datarootdir=' + join_paths('${prefix}', get_option('datadir')), - 'pkgdatadir=' + join_paths('${pc_sysrootdir}${datarootdir}', meson.project_name()), + 'pkgdatadir=' + join_paths('${datarootdir}', meson.project_name()), - 'bindir=' + join_paths('${prefix}', get_option('bindir')), 'wayland_scanner=${bindir}/wayland-scanner' ], + filebase: 'wayland-scanner' diff --git a/projects/ROCKNIX/patches/gcc/0004-vect-pass-the-SLP-node-when-costing-emulated-vectors.patch b/projects/ROCKNIX/patches/gcc/0004-vect-pass-the-SLP-node-when-costing-emulated-vectors.patch new file mode 100644 index 00000000000..5d5e538ec7f --- /dev/null +++ b/projects/ROCKNIX/patches/gcc/0004-vect-pass-the-SLP-node-when-costing-emulated-vectors.patch @@ -0,0 +1,57 @@ +From: ROCKNIX +Subject: [PATCH] vect: pass the SLP node when costing emulated vector ops + +vectorizable_operation still hands stmt_info to record_stmt_cost on the +emulated-vector path, so node arrives NULL at the target cost hook. On +aarch64 that is fatal: + + during GIMPLE pass: vect + kernel/module/procfs.c:74:12: internal compiler error: Segmentation fault + 0x119b424 info_for_reduction(_loop_vec_info*, _slp_tree*) + 0x12c1920 aarch64_vector_costs::count_ops(...) + 0x11f186e vect_slp_analyze_operations(vec_info*) + +count_ops enters its reduction block on stmt_info alone - + + if (stmt_info + && (kind == scalar_stmt || kind == vector_stmt || kind == vec_to_scalar) + && vect_is_reduction (stmt_info)) + +using the stmt_vec_info overload of vect_is_reduction - then passes node +to aarch64_force_single_cycle, which dereferences it in +info_for_reduction as node->cycle_info.id. Nothing on that path checks +node, and the sibling call to aarch64_in_loop_reduction_latency only +touches node inside "if (sve_costs)", so with +nosve it returns +harmlessly and execution reaches the deref. + +Both call sites here are scalar_stmt on a PLUS_EXPR/MINUS_EXPR/ +NEGATE_EXPR switch, which is precisely a reduction accumulator, and the +block is guarded by using_emulated_vectors_p - reached when the target +has no native vectors for the mode, as with the kernel's +-mgeneral-regs-only. The neighbouring vect_model_simple_cost call four +lines up already passes slp_node, and slp_node is a parameter of the +enclosing function, so these two are simply stragglers of the SLP-only +migration. + +Same shape as upstream 3bc63918cec9 ("A few missing SLP node passings to +vector costing"), which fixed the identical mistake in +vectorizable_reduction, vectorizable_live_operation, vectorizable_bswap +and vectorizable_store. Prefer that over a null check in the aarch64 +backend: guarding there would silently cost the reduction as if +force_single_cycle were false rather than restore the information the +cost model asked for. + +--- a/gcc/tree-vect-stmts.cc ++++ b/gcc/tree-vect-stmts.cc +@@ -6872,9 +6872,9 @@ + if (n != 0) + { + /* We also need to materialize two large constants. */ +- record_stmt_cost (cost_vec, 2, scalar_stmt, stmt_info, ++ record_stmt_cost (cost_vec, 2, scalar_stmt, slp_node, + 0, vect_prologue); +- record_stmt_cost (cost_vec, n, scalar_stmt, stmt_info, ++ record_stmt_cost (cost_vec, n, scalar_stmt, slp_node, + 0, vect_body); + } + } diff --git a/projects/ROCKNIX/patches/gcc/libsanitizer-Fix_up_build_against_latest_kernel_headers.patch b/projects/ROCKNIX/patches/gcc/libsanitizer-Fix_up_build_against_latest_kernel_headers.patch deleted file mode 100644 index ec0c3516f11..00000000000 --- a/projects/ROCKNIX/patches/gcc/libsanitizer-Fix_up_build_against_latest_kernel_headers.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 259d5c6ef7ca0b7fb07acf97538fa7ba590c8e8b Mon Sep 17 00:00:00 2001 -From: Jakub Jelinek -Date: Wed, 29 Apr 2026 11:14:03 +0200 -Subject: [PATCH] libsanitizer: Fix up build against latest kernel headers - -The Linux kernel recently removed the linux/scc.h header, so gcc (both -16.1-rc2 and trunk) fails to build e.g. on Fedora rawhide now. - -The following patch cherry picks a recent upstream fix for this, the macros -defined in that header haven't been really used since 2013-ish. - -2026-04-29 Jakub Jelinek - - * sanitizer_common/sanitizer_platform_limits_posix.cpp: Cherry picked - from LLVM commit 3dc4fd6dd41100f051a63642f449b16324389c96. - -Reviewed-by: Richard Biener ---- - .../sanitizer_platform_limits_posix.cpp | 21 ++++++++----------- - 1 file changed, 9 insertions(+), 12 deletions(-) - -diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp -index 5872e3396f053..47eb1dc326772 100644 ---- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp -+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp -@@ -152,16 +152,15 @@ typedef struct user_fpregs elf_fpregset_t; - #if defined(__mips64) - # include - #endif --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -+# include -+# include -+# include -+# include -+# include -+# include -+# include -+# include -+# include - #endif // SANITIZER_ANDROID - - #include -@@ -534,8 +533,6 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); - unsigned struct_kbsentry_sz = sizeof(struct kbsentry); - unsigned struct_mtconfiginfo_sz = sizeof(struct mtconfiginfo); - unsigned struct_nr_parms_struct_sz = sizeof(struct nr_parms_struct); -- unsigned struct_scc_modem_sz = sizeof(struct scc_modem); -- unsigned struct_scc_stat_sz = sizeof(struct scc_stat); - unsigned struct_serial_multiport_struct_sz - = sizeof(struct serial_multiport_struct); - unsigned struct_serial_struct_sz = sizeof(struct serial_struct); diff --git a/projects/ROCKNIX/patches/gst-plugins-base/gst-plugins-base-0001-fix-gstvideopool-circular-include.patch b/projects/ROCKNIX/patches/gst-plugins-base/gst-plugins-base-0001-fix-gstvideopool-circular-include.patch new file mode 100644 index 00000000000..5c7656e5131 --- /dev/null +++ b/projects/ROCKNIX/patches/gst-plugins-base/gst-plugins-base-0001-fix-gstvideopool-circular-include.patch @@ -0,0 +1,62 @@ +Subject: video: fix circular include in gstvideopool.h vs gstvideodmabufpool.h + +gstvideodmabufpool.h (new in 1.28, included from the video.h aggregate) +needs the complete GstVideoBufferPool declarations, but gstvideopool.h +included the aggregate before making them: a TU that includes +gstvideopool.h directly re-enters it through the aggregate, hits the +include guard, and fails with unknown/incomplete type errors. Declare +the bufferpool types before the aggregate include (only the prelude is +needed for GST_VIDEO_API) and move the GstVideoAlignment config helpers +after it. Not yet fixed upstream; to be submitted as a GStreamer MR. + +--- a/gst-libs/gst/video/gstvideopool.h ++++ b/gst-libs/gst/video/gstvideopool.h +@@ -22,7 +22,11 @@ + + #include + +-#include ++/* Only the prelude here: this header must complete its own declarations ++ * before pulling in the video.h aggregate, because gstvideodmabufpool.h ++ * (included from the aggregate) derives from GstVideoBufferPool and its ++ * nested include of this header is a no-op once the guard is set. */ ++#include + + G_BEGIN_DECLS + +@@ -45,14 +49,6 @@ + */ + #define GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT "GstBufferPoolOptionVideoAlignment" + +-/* setting a bufferpool config */ +- +-GST_VIDEO_API +-void gst_buffer_pool_config_set_video_alignment (GstStructure *config, const GstVideoAlignment *align); +- +-GST_VIDEO_API +-gboolean gst_buffer_pool_config_get_video_alignment (const GstStructure *config, GstVideoAlignment *align); +- + /* video bufferpool */ + typedef struct _GstVideoBufferPool GstVideoBufferPool; + typedef struct _GstVideoBufferPoolClass GstVideoBufferPoolClass; +@@ -85,4 +81,20 @@ + + G_END_DECLS + ++/* The aggregate is included here to stay transitively available and to ++ * provide GstVideoAlignment for the config helpers below. */ ++#include ++ ++G_BEGIN_DECLS ++ ++/* setting a bufferpool config */ ++ ++GST_VIDEO_API ++void gst_buffer_pool_config_set_video_alignment (GstStructure *config, const GstVideoAlignment *align); ++ ++GST_VIDEO_API ++gboolean gst_buffer_pool_config_get_video_alignment (const GstStructure *config, GstVideoAlignment *align); ++ ++G_END_DECLS ++ + #endif /* __GST_VIDEO_POOL_H__ */ diff --git a/projects/ROCKNIX/patches/opus/0001-celt-vroundf-vcvtaq-is-aarch64-only.patch b/projects/ROCKNIX/patches/opus/0001-celt-vroundf-vcvtaq-is-aarch64-only.patch new file mode 100644 index 00000000000..6f96124b993 --- /dev/null +++ b/projects/ROCKNIX/patches/opus/0001-celt-vroundf-vcvtaq-is-aarch64-only.patch @@ -0,0 +1,35 @@ +From: ROCKNIX +Subject: [PATCH] celt: vroundf's vcvtaq path is aarch64 only + +Building 32-bit ARM with -march=armv8-a fails: + + celt/arm/mathops_arm.h:41:12: error: implicit declaration of function + 'vcvtaq_s32_f32'; did you mean 'vcvtq_s32_f32'? + error: incompatible types when returning type 'int' but 'int32x4_t' + was expected + +vroundf picks vcvtaq_s32_f32 when __ARM_ARCH >= 8, but that intrinsic +is AArch64 only. gcc 16.2.0's AArch32 arm_neon.h does not declare it at +any -mfpu level - neon, neon-fp-armv8 and crypto-neon-fp-armv8 all +fail - while the AArch64 header does. The architecture version is +simply the wrong thing to test. + +It goes unnoticed on ARMv7 builds because __ARM_ARCH is 7 there, and on +AArch64 because the first arm of the condition already matches. It only +bites a 32-bit build targeting ARMv8, which is what ROCKNIX uses for +its compat leg. + +Test __aarch64__ alone and let everything else take the existing +rounding fallback, which is what ARMv7 has always used. + +--- a/celt/arm/mathops_arm.h ++++ b/celt/arm/mathops_arm.h +@@ -37,7 +37,7 @@ + + static inline int32x4_t vroundf(float32x4_t x) + { +-# if defined(__aarch64__) || (defined(__ARM_ARCH) && __ARM_ARCH >= 8) ++# if defined(__aarch64__) + return vcvtaq_s32_f32(x); + # else + uint32x4_t sign = vandq_u32(vreinterpretq_u32_f32(x), vdupq_n_u32(0x80000000)); diff --git a/scripts/build b/scripts/build index a815a0a9eb2..6fe1b8a30e7 100755 --- a/scripts/build +++ b/scripts/build @@ -299,6 +299,15 @@ record_timestamp BUILD_CONFIGURE pkg_call_exists_opt pre_configure && pkg_call pkg_call_exists_opt pre_configure_${TARGET} && pkg_call +# A configure killed partway leaves a meson build directory that exists but +# has no build.dat/build.ninja; meson then refuses it as "already configured" +# while being unable to read it, and the package can never configure again. +# The state is entirely regenerable, so start that one over. +if [ -d "meson-private" ] && { [ ! -f "meson-private/build.dat" ] || [ ! -f "build.ninja" ]; }; then + build_msg "CLR_WARNING" "MESON" "discarding a partially configured build directory" + rm -rf meson-private meson-info meson-logs build.ninja .ninja_deps .ninja_log +fi + if pkg_call_exists configure_${TARGET}; then pkg_call else @@ -469,6 +478,14 @@ if [ ! -d "${SYSROOT_PREFIX}${BUILD_OPTS_TARGET_LIBDIR}" ]; then ln -s lib "${SYSROOT_PREFIX}${BUILD_OPTS_TARGET_LIBDIR}" fi +# The shared sysroot needs the same bridge. Leaving it to arrive with +# whichever package merges first means a package configured against +# ${BUILD_OPTS_TARGET_LIBDIR} can be built before anything creates it, and it +# then fails to find headers that are present under lib. +if [ -n "${BUILD_OPTS_TARGET_LIBDIR}" -a ! -e "${PKG_ORIG_SYSROOT_PREFIX}${BUILD_OPTS_TARGET_LIBDIR}" ]; then + ln -sfn lib "${PKG_ORIG_SYSROOT_PREFIX}${BUILD_OPTS_TARGET_LIBDIR}" 2>/dev/null || true +fi + record_timestamp BUILD_MAKEINSTALL # make install diff --git a/scripts/get_archive b/scripts/get_archive index a70be616d2a..412f06191d9 100755 --- a/scripts/get_archive +++ b/scripts/get_archive @@ -20,7 +20,6 @@ build_msg "CLR_GET" "GET" "${1} (archive)" "indent" pkg_lock_status "GETPKG" "${PKG_NAME}" "unpack" "downloading package..." -PACKAGE_MIRROR="${DISTRO_MIRROR}/${PKG_SOURCE_NAME}" [ "${VERBOSE}" != "yes" ] && WGET_OPT=-q WGET_CMD="wget --secure-protocol=TLSv1_2 --output-file=- --timeout=30 --tries=3 --passive-ftp --no-check-certificate -c ${WGET_OPT} --progress=bar:force --retry-connrefused --waitretry=5 --retry-on-http-error=429,500,502,503,504 --show-progress -O ${PACKAGE}" @@ -29,11 +28,14 @@ unset LD_LIBRARY_PATH rm -f "${STAMP_URL}" "${STAMP_SHA}" +# DISTRO_MIRROR is a list, so a distro can keep its own cache alongside the +# shared one. Each is tried in turn after the upstream URL, which matters +# when upstream is gone entirely - savannah stopped generating the cgit +# snapshot configtools fetches, so only a mirror can supply it. PKG_URLS="${PKG_URL}" -if [ -n "${PACKAGE_MIRROR}" ] -then - PKG_URLS="${PKG_URL} ${PACKAGE_MIRROR}" -fi +for mirror in ${DISTRO_MIRROR}; do + PKG_URLS+=" ${mirror}/${PKG_SOURCE_NAME}" +done NBWGET=10 while [ ${NBWGET} -gt 0 ]; do diff --git a/scripts/get_env b/scripts/get_env index 8489793c07e..b384e164b45 100755 --- a/scripts/get_env +++ b/scripts/get_env @@ -1,5 +1,18 @@ #!/usr/bin/env bash -for var in $(compgen -e); do +for var in $(compgen -e); do [[ "$var" == PATH ]] && continue + # A host TMPDIR does not exist inside the container. macOS sets one by + # default, so mktemp fails and init_package_cache dies before it can + # build the package caches - which is why builds have needed to be run + # as "env -u TMPDIR make docker-...". Drop it and let the container use + # its own /tmp. + [[ "$var" == TMPDIR ]] && continue + # The build system keeps its derived state in the underscore namespace and + # only recomputes it when unset: init_package_cache regenerates the package + # caches when _CACHE_PACKAGE_* are empty, and set_debug_depends runs when + # _DEBUG_DEPENDS_LIST is unset - tested with +x, so an empty-but-set value + # also suppresses it. Carrying those in from the host pins them for the + # whole run, and adding or removing a package then silently has no effect. + [[ "$var" == _* ]] && continue echo "$var=${!var}" done