diff --git a/.github/workflows/build-main.yaml b/.github/workflows/build-main.yaml
index 73e359cc63..6791ed916f 100644
--- a/.github/workflows/build-main.yaml
+++ b/.github/workflows/build-main.yaml
@@ -101,14 +101,14 @@ jobs:
|**Device/Platform**|**Download Package**|**Documentation**|
|----|----|----|
|**Anbernic RG351P/M, Game Console R33S, ODROID Go Advance, ODROID Go Super, Magicx XU10**|[JELOS-RK3326.aarch64-${{ steps.version.outputs.version }}.img.gz](https://github.com/JustEnoughLinuxOS/distribution/releases/download/${{ steps.version.outputs.version }}/JELOS-RK3326.aarch64-${{ steps.version.outputs.version }}.img.gz)|[documentation](/documentation/PER_DEVICE_DOCUMENTATION/RK3326/)|
- |**Anbernic RG353P/M/V/VS, RG503, Powkiddy RK2023, RGB30, RGB10 Max 3**|[JELOS-RK3566.aarch64-${{ steps.version.outputs.version }}.img.gz](https://github.com/JustEnoughLinuxOS/distribution/releases/download/${{ steps.version.outputs.version }}/JELOS-RK3566.aarch64-${{ steps.version.outputs.version }}.img.gz)|[documentation](/documentation/PER_DEVICE_DOCUMENTATION/RK3566/)|
|**Anbernic RG552**|[JELOS-RK3399.aarch64-${{ steps.version.outputs.version }}.img.gz](https://github.com/JustEnoughLinuxOS/distribution/releases/download/${{ steps.version.outputs.version }}/JELOS-RK3399.aarch64-${{ steps.version.outputs.version }}.img.gz)|[documentation](/documentation/PER_DEVICE_DOCUMENTATION/RK3399/)|
|**Atari VCS, AOKZOE, Ayaneo, Ayn, GPD, and other x86_64 devices**|[JELOS-AMD64.x86_64-${{ steps.version.outputs.version }}.img.gz](https://github.com/JustEnoughLinuxOS/distribution/releases/download/${{ steps.version.outputs.version }}/JELOS-AMD64.x86_64-${{ steps.version.outputs.version }}.img.gz)|[documentation](/documentation/PER_DEVICE_DOCUMENTATION/AMD64/)|
|**Hardkernel ODROID Go Ultra, Powkiddy RGB10 Max 3 Pro**|[JELOS-S922X.aarch64-${{ steps.version.outputs.version }}-Odroid_GOU.img.gz](https://github.com/JustEnoughLinuxOS/distribution/releases/download/${{ steps.version.outputs.version }}/JELOS-S922X.aarch64-${{ steps.version.outputs.version }}-Odroid_GOU.img.gz)|[documentation](/documentation/PER_DEVICE_DOCUMENTATION/S922X/)|
|**Hardkernel ODROID N2/N2+**|[JELOS-S922X.aarch64-${{ steps.version.outputs.version }}-Odroid_N2.img.gz](https://github.com/JustEnoughLinuxOS/distribution/releases/download/${{ steps.version.outputs.version }}/JELOS-S922X.aarch64-${{ steps.version.outputs.version }}-Odroid_N2.img.gz)|[documentation](/documentation/PER_DEVICE_DOCUMENTATION/S922X/)|
|**Hardkernel ODROID N2L**|[JELOS-S922X.aarch64-${{ steps.version.outputs.version }}-Odroid_N2L.img.gz](https://github.com/JustEnoughLinuxOS/distribution/releases/download/${{ steps.version.outputs.version }}/JELOS-S922X.aarch64-${{ steps.version.outputs.version }}-Odroid_N2L.img.gz)|[documentation](/documentation/PER_DEVICE_DOCUMENTATION/S922X/)|
|**Orange Pi 5, and Indiedroid Nova**|[JELOS-RK3588.aarch64-${{ steps.version.outputs.version }}.img.gz](https://github.com/JustEnoughLinuxOS/distribution/releases/download/${{ steps.version.outputs.version }}/JELOS-RK3588.aarch64-${{ steps.version.outputs.version }}.img.gz)|[documentation](/documentation/PER_DEVICE_DOCUMENTATION/RK3588/)|
- |**Powkiddy x55**|[JELOS-RK3566-X55.aarch64-${{ steps.version.outputs.version }}.img.gz](https://github.com/JustEnoughLinuxOS/distribution/releases/download/${{ steps.version.outputs.version }}/JELOS-RK3566-X55.aarch64-${{ steps.version.outputs.version }}.img.gz)|[documentation](/documentation/PER_DEVICE_DOCUMENTATION/RK3566-X55/)|
+
+ > Note: Anbernic RG353P/M/V/VS, RG503, Powkiddy RK2023, RGB30, RGB10 Max 3, and x55 releases are paused at version [20240206](https://github.com/JustEnoughLinuxOS/distribution/releases/tag/20240206) while mainline integration is worked. New releases for these devices will return soon.
## Upgrading
* Download and install the update online via the System Settings menu.
@@ -121,12 +121,12 @@ jobs:
|**Device/Platform**|**Download Package**|
|----|----|
|**Anbernic RG351P/M, Game Console R33S,ODROID Go Advance, ODROID Go Super, Magicx XU10**|[JELOS-RK3326.aarch64-${{ steps.version.outputs.version }}.tar](https://github.com/JustEnoughLinuxOS/distribution/releases/download/${{ steps.version.outputs.version }}/JELOS-RK3326.aarch64-${{ steps.version.outputs.version }}.tar)|
- |**Anbernic RG353P/M/V/VS, RG503, Powkiddy RK2023, RGB30, RGB10 Max 3**|[JELOS-RK3566.aarch64-${{ steps.version.outputs.version }}.tar](https://github.com/JustEnoughLinuxOS/distribution/releases/download/${{ steps.version.outputs.version }}/JELOS-RK3566.aarch64-${{ steps.version.outputs.version }}.tar)|
|**Anbernic RG552**|[JELOS-RK3399.aarch64-${{ steps.version.outputs.version }}.tar](https://github.com/JustEnoughLinuxOS/distribution/releases/download/${{ steps.version.outputs.version }}/JELOS-RK3399.aarch64-${{ steps.version.outputs.version }}.tar)|
|****Atari VCS, AOKZOE, Ayaneo, Ayn, GPD, and other x86_64 devices****|[JELOS-AMD64.x86_64-${{ steps.version.outputs.version }}.tar](https://github.com/JustEnoughLinuxOS/distribution/releases/download/${{ steps.version.outputs.version }}/JELOS-AMD64.x86_64-${{ steps.version.outputs.version }}.tar)|
|**Hardkernel ODROID Go Ultra, N2/N2+/N2L, Powkiddy RGB10 Max 3 Pro**|[JELOS-S922X.aarch64-${{ steps.version.outputs.version }}.tar](https://github.com/JustEnoughLinuxOS/distribution/releases/download/${{ steps.version.outputs.version }}/JELOS-S922X.aarch64-${{ steps.version.outputs.version }}.tar)|
|**Orange Pi 5, and Indiedroid Nova**|[JELOS-RK3588.aarch64-${{ steps.version.outputs.version }}.tar](https://github.com/JustEnoughLinuxOS/distribution/releases/download/${{ steps.version.outputs.version }}/JELOS-RK3588.aarch64-${{ steps.version.outputs.version }}.tar)|
- |**Powkiddy x55**|[JELOS-RK3566-X55.aarch64-${{ steps.version.outputs.version }}.tar](https://github.com/JustEnoughLinuxOS/distribution/releases/download/${{ steps.version.outputs.version }}/JELOS-RK3566-X55.aarch64-${{ steps.version.outputs.version }}.tar)|
+
+ > Note: Anbernic RG353P/M/V/VS, RG503, Powkiddy RK2023, RGB30, RGB10 Max 3, and x55 releases are paused at version [20240206](https://github.com/JustEnoughLinuxOS/distribution/releases/tag/20240206) while mainline integration is worked. New releases for these devices will return soon.
## Documentation
diff --git a/Dockerfile b/Dockerfile
index 44c366a259..d425fbd79e 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -24,8 +24,8 @@ RUN apt-get install -y \
### Cross compiling on ARM
RUN if [ "$(uname -m)" = "aarch64" ]; then apt-get install -y --no-install-recommends qemu-user-binfmt libc6-dev-amd64-cross; fi
-RUN if [ ! -d /lib64 ]; then ln -sf /usr/x86_64-linux-gnu/lib64 /lib64; fi
-RUN if [ ! -d /lib/x86_64-linux-gnu ]; then ln -sf /usr/x86_64-linux-gnu/lib /lib/x86_64-linux-gnu; fi
+RUN if [ ! -d /lib64 ]; then ln -sf /usr/x86_64-jelos-linux-gnu/lib64 /lib64; fi
+RUN if [ ! -d /lib/x86_64-jelos-linux-gnu ]; then ln -sf /usr/x86_64-jelos-linux-gnu/lib /lib/x86_64-jelos-linux-gnu; fi
RUN mkdir -p /work && chown docker /work
diff --git a/Makefile b/Makefile
index 9049d7b32e..3dcc6363bb 100644
--- a/Makefile
+++ b/Makefile
@@ -12,9 +12,6 @@ release:
image:
./scripts/image mkimage
-noobs:
- ./scripts/image noobs
-
clean:
rm -rf $(BUILD_DIRS)
@@ -27,7 +24,7 @@ src-pkg:
docs:
./tools/foreach './scripts/clean emulators && ./scripts/build emulators'
-world: AMD64 RK3588 S922X RK3566 RK3566-X55 RK3326 RK3399
+world: AMD64 RK3588 S922X RK3326 RK3399
AMD64:
unset DEVICE_ROOT
@@ -72,7 +69,6 @@ RK3399:
PROJECT=Rockchip DEVICE=RK3399 ARCH=arm ./scripts/build_distro
PROJECT=Rockchip DEVICE=RK3399 ARCH=aarch64 ./scripts/build_distro
-
update:
PROJECT=PC DEVICE=AMD64 ARCH=x86_64 ./scripts/update_packages
diff --git a/README.md b/README.md
index 708f56a88c..c8e49a965e 100644
--- a/README.md
+++ b/README.md
@@ -101,39 +101,40 @@ JELOS supports a variety of ARM and Intel/AMD based devices.
| Manufacturer | Device | CPU / Architecture | Kernel | GL driver | Interface |
| -- | -- | -- | -- | -- | -- |
-| Anbernic | [RG351P/M](http://jelos.org/devices/anbernic/rg351pmv) | Rockchip RK3326 (ARM) | Mainline Linux | Panfrost | Weston + Emulation Station |
-| Anbernic | [RG351v](http://jelos.org/devices/anbernic/rg351pmv) | Rockchip RK3326 (ARM) | Mainline Linux | Panfrost | Weston + Emulation Station |
-| Anbernic | [RG353P](http://jelos.org/devices/anbernic/rg353pmvvs) | Rockchip RK3566 (ARM) | Rockchip BSP 4.19 | Mali | KMS/DRM + Emulation Station |
-| Anbernic | [RG353M](http://jelos.org/devices/anbernic/rg353pmvvs) | Rockchip RK3566 (ARM) | Rockchip BSP 4.19 | Mali | KMS/DRM + Emulation Station |
-| Anbernic | [RG353V](http://jelos.org/devices/anbernic/rg353pmvvs) | Rockchip RK3566 (ARM) | Rockchip BSP 4.19 | Mali | KMS/DRM + Emulation Station |
-| Anbernic | [RG353VS](http://jelos.org/devices/anbernic/rg353pmvvs) | Rockchip RK3566 (ARM) | Rockchip BSP 4.19 | Mali | KMS/DRM + Emulation Station |
-| Anbernic | [RG503](http://jelos.org/devices/anbernic/rg503) | Rockchip RK3566 (ARM) | Rockchip BSP 4.19 | Mali | KMS/DRM + Emulation Station |
-| Anbernic | [RG552](http://jelos.org/devices/anbernic/rg552) | Rockchip RK3399 (ARM) | Mainline Linux | Panfrost | Weston + Emulation Station |
-| Anbernic | [Win600](http://jelos.org/devices/anbernic/win600) | AMD Athlon Silver 3050e (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
-| AOKZOE | [A1 Pro](http://jelos.org/devices/aokzoe/a1-pro) | AMD 7840u (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
-| Atari | [VCS](http://jelos.org/devices/atari/vcs) | AMD Ryzen R1606G (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
-| AYANEO | [Air / Air Pro](http://jelos.org/devices/ayaneo/air) | Amd Ryzen 5 5560U / AMD Ryzen 7 5825U (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
-| AYANEO | [Air Plus](http://jelos.org/devices/ayaneo/air-plus) | Amd Ryzen 7 6800U / (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
-| AYANEO | [AYANEO 2](http://jelos.org/devices/ayaneo/ayaneo-2) | Amd Ryzen 7 6800U / (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
-| AYANEO | [AYANEO 2S](http://jelos.org/devices/ayaneo/ayaneo-2) | Amd Ryzen 7 7840U / (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
-| Ayn | [Loki Zero](http://jelos.org/devices/ayn/loki-zero) | AMD Athlon Silver 3050e (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
-| Ayn | [Loki Max](http://jelos.org/devices/ayn/loki-max) | Amd Ryzen 7 6800U / (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
-| Game Console | [RG33S](http://jelos.org/gameconsole/r33s) | Rockchip RK3326 (ARM) | Mainline Linux | Panfrost | Weston + Emulation Station |
-| GPD | [Win 4](http://jelos.org/devices/gpd/win4) | Amd Ryzen 7 6800U / (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
-| GPD | [Win Max 2 (2022)](http://jelos.org/devices/gpd/win-max-2) | Amd Ryzen 7 6800U / (x86_64) | Mainline Linux| Radeonsi | Weston + Emulation Station |
-| Hardkernel | [Odroid Go Advance](http://jelos.org/devices/hardkernel/odroid-go-advance) | Rockchip RK3326 (ARM) | Mainline Linux | Panfrost | Weston + Emulation Station |
-| Hardkernel | [Odroid Go Super](http://jelos.org/devices/hardkernel/odroid-go-super) | Rockchip RK3326 (ARM) | Mainline Linux | Panfrost | Weston + Emulation Station |
-| Hardkernel | [Odroid Go Ultra](http://jelos.org/devices/hardkernel/odroid-go-ultra) | Amlogic S922X / Mali G52 M6 (ARMv8-A) | Mainline Linux | Mali | Weston + Emulation Station |
-| Hardkernel | [Odroid N2/N2+/N2L](http://jelos.org/devices/hardkernel/odroid-n2) | Amlogic S922X / Mali G52 M6 (ARMv8-A) | Mainline Linux | Mali | Weston + Emulation Station |
-| Indiedroid | [Nova](http://jelos.org/devices/indiedroid/nova) | Rockchip RK3588S / Mali G610 (ARMv8-A) | Rockchip 5.10 BSP Linux | Panfrost | Weston + Emulation Station |
-| Orange Pi | [Orange Pi 5](http://jelos.org/devices/orange-pi/orange-pi-5) | Rockchip RK3588S / Mali G610 (ARMv8-A) | Rockchip 5.10 BSP Linux | Panfrost | Weston + Emulation Station |
-| Magicx | [XU10](http://jelos.org/devices/magicx/xu10) | Rockchip RK3326 (ARM) | Mainline Linux | Panfrost | Weston + Emulation Station |
-| Powkiddy | [RGB10](http://jelos.org/devices/powkiddy/rgb10) | Rockchip RK3326 (ARM) | Mainline Linux | Panfrost | Weston + Emulation Station |
-| Powkiddy | [RGB10 Max 3](http://jelos.org/devices/powkiddy/rgb10-max-3) | Rockchip RK3566 (ARM) | Rockchip BSP 4.19 | Mali | KMS/DRM + Emulation Station |
-| Powkiddy | [RGB10 Max 3 Pro](http://jelos.org/devices/powkiddy/rgb10-max-3-pro) | Amlogic A311D / Mali G52 M4 (ARMv8-A) | Mainline Linux | Mali | Weston + Emulation Station |
-| Powkiddy | [RGB30](http://jelos.org/devices/powkiddy/rgb30) | Rockchip RK3566 (ARM) | Rockchip BSP 4.19 | Mali | KMS/DRM + Emulation Station |
-| Powkiddy | [RK2023](http://jelos.org/devices/powkiddy/rk2023) | Rockchip RK3566 (ARM) | Rockchip BSP 4.19 | Mali | KMS/DRM + Emulation Station |
-| Powkiddy | [x55](http://jelos.org/devices/powkiddy/x55) | Rockchip RK3566 (ARM) | Rockchip BSP 4.19 | Mali | KMS/DRM + Emulation Station |
+| Anbernic | [RG351P/M](https://jelos.org/devices/anbernic/rg351pmv) | Rockchip RK3326 (ARM) | Mainline Linux | Panfrost | Weston + Emulation Station |
+| Anbernic | [RG351v](https://jelos.org/devices/anbernic/rg351pmv) | Rockchip RK3326 (ARM) | Mainline Linux | Panfrost | Weston + Emulation Station |
+| Anbernic | [RG353P](https://jelos.org/devices/anbernic/rg353pmvvs) | Rockchip RK3566 (ARM) | Rockchip BSP 4.19 | Mali | KMS/DRM + Emulation Station |
+| Anbernic | [RG353M](https://jelos.org/devices/anbernic/rg353pmvvs) | Rockchip RK3566 (ARM) | Rockchip BSP 4.19 | Mali | KMS/DRM + Emulation Station |
+| Anbernic | [RG353V](https://jelos.org/devices/anbernic/rg353pmvvs) | Rockchip RK3566 (ARM) | Rockchip BSP 4.19 | Mali | KMS/DRM + Emulation Station |
+| Anbernic | [RG353VS](https://jelos.org/devices/anbernic/rg353pmvvs) | Rockchip RK3566 (ARM) | Rockchip BSP 4.19 | Mali | KMS/DRM + Emulation Station |
+| Anbernic | [RG503](https://jelos.org/devices/anbernic/rg503) | Rockchip RK3566 (ARM) | Rockchip BSP 4.19 | Mali | KMS/DRM + Emulation Station |
+| Anbernic | [RG552](https://jelos.org/devices/anbernic/rg552) | Rockchip RK3399 (ARM) | Mainline Linux | Panfrost | Weston + Emulation Station |
+| Anbernic | [Win600](https://jelos.org/devices/anbernic/win600) | AMD Athlon Silver 3050e (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
+| AOKZOE | [A1 Pro](https://jelos.org/devices/aokzoe/a1-pro) | AMD 7840u (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
+| Atari | [VCS](https://jelos.org/devices/atari/vcs) | AMD Ryzen R1606G (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
+| AYANEO | [Air / Air Pro](https://jelos.org/devices/ayaneo/air) | Amd Ryzen 5 5560U / AMD Ryzen 7 5825U (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
+| AYANEO | [Air Plus](https://jelos.org/devices/ayaneo/air-plus) | Amd Ryzen 7 6800U / (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
+| AYANEO | [AYANEO 2](https://jelos.org/devices/ayaneo/ayaneo-2) | Amd Ryzen 7 6800U / (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
+| AYANEO | [AYANEO 2S](https://jelos.org/devices/ayaneo/ayaneo-2) | Amd Ryzen 7 7840U / (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
+| Ayn | [Loki Zero](https://jelos.org/devices/ayn/loki-zero) | AMD Athlon Silver 3050e (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
+| Ayn | [Loki Max](https://jelos.org/devices/ayn/loki-max) | Amd Ryzen 7 6800U / (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
+| Game Console | [R33S](https://jelos.org/devices/unbranded/game-console-r33s) | Rockchip RK3326 (ARM) | Mainline Linux | Panfrost | Weston + Emulation Station |
+| Game Console | [R35S, R36S](https://jelos.org/devices/unbranded/game-console-r35s-r36s) | Rockchip RK3326 (ARM) | Mainline Linux | Panfrost | Weston + Emulation Station |
+| GPD | [Win 4](https://jelos.org/devices/gpd/win4) | Amd Ryzen 7 6800U / (x86_64) | Mainline Linux | Radeonsi | Weston + Emulation Station |
+| GPD | [Win Max 2 (2022)](https://jelos.org/devices/gpd/win-max-2) | Amd Ryzen 7 6800U / (x86_64) | Mainline Linux| Radeonsi | Weston + Emulation Station |
+| Hardkernel | [Odroid Go Advance](https://jelos.org/devices/hardkernel/odroid-go-advance) | Rockchip RK3326 (ARM) | Mainline Linux | Panfrost | Weston + Emulation Station |
+| Hardkernel | [Odroid Go Super](https://jelos.org/devices/hardkernel/odroid-go-super) | Rockchip RK3326 (ARM) | Mainline Linux | Panfrost | Weston + Emulation Station |
+| Hardkernel | [Odroid Go Ultra](https://jelos.org/devices/hardkernel/odroid-go-ultra) | Amlogic S922X / Mali G52 M6 (ARMv8-A) | Mainline Linux | Mali | Weston + Emulation Station |
+| Hardkernel | [Odroid N2/N2+/N2L](https://jelos.org/devices/hardkernel/odroid-n2) | Amlogic S922X / Mali G52 M6 (ARMv8-A) | Mainline Linux | Mali | Weston + Emulation Station |
+| Indiedroid | [Nova](https://jelos.org/devices/indiedroid/nova) | Rockchip RK3588S / Mali G610 (ARMv8-A) | Rockchip 5.10 BSP Linux | Panfrost | Weston + Emulation Station |
+| Orange Pi | [Orange Pi 5](https://jelos.org/devices/orange-pi/orange-pi-5) | Rockchip RK3588S / Mali G610 (ARMv8-A) | Rockchip 5.10 BSP Linux | Panfrost | Weston + Emulation Station |
+| Magicx | [XU10](https://jelos.org/devices/magicx/xu10) | Rockchip RK3326 (ARM) | Mainline Linux | Panfrost | Weston + Emulation Station |
+| Powkiddy | [RGB10](https://jelos.org/devices/powkiddy/rgb10) | Rockchip RK3326 (ARM) | Mainline Linux | Panfrost | Weston + Emulation Station |
+| Powkiddy | [RGB10 Max 3](https://jelos.org/devices/powkiddy/rgb10-max-3) | Rockchip RK3566 (ARM) | Rockchip BSP 4.19 | Mali | KMS/DRM + Emulation Station |
+| Powkiddy | [RGB10 Max 3 Pro](https://jelos.org/devices/powkiddy/rgb10-max-3-pro) | Amlogic A311D / Mali G52 M4 (ARMv8-A) | Mainline Linux | Mali | Weston + Emulation Station |
+| Powkiddy | [RGB30](https://jelos.org/devices/powkiddy/rgb30) | Rockchip RK3566 (ARM) | Rockchip BSP 4.19 | Mali | KMS/DRM + Emulation Station |
+| Powkiddy | [RK2023](https://jelos.org/devices/powkiddy/rk2023) | Rockchip RK3566 (ARM) | Rockchip BSP 4.19 | Mali | KMS/DRM + Emulation Station |
+| Powkiddy | [x55](https://jelos.org/devices/powkiddy/x55) | Rockchip RK3566 (ARM) | Rockchip BSP 4.19 | Mali | KMS/DRM + Emulation Station |
> [!NOTE]
> While not technically supported, JELOS is also known to work well on a variety of generic x86_64 devices including gaming PCs, mini PCs, and laptop computers.
diff --git a/config/emulators/psvita.conf b/config/emulators/psvita.conf
index 6017185235..ff5b34d217 100644
--- a/config/emulators/psvita.conf
+++ b/config/emulators/psvita.conf
@@ -3,8 +3,8 @@ SYSTEM_FULLNAME="PlayStation Vita"
SYSTEM_MANUFACTURER="Sony"
SYSTEM_RELEASE="2011"
SYSTEM_HARDWARE="portable"
-SYSTEM_PATH="/usr/config/vita3k/launcher/"
-SYSTEM_EXTENSION=".sh"
+SYSTEM_PATH="/storage/.config/vita3k/launcher/"
+SYSTEM_EXTENSION=".sh .psvita"
SYSTEM_COMMAND="/usr/bin/runemu.sh %ROM% -P%SYSTEM% --core=%CORE% --emulator=%EMULATOR% --controllers=\"%CONTROLLERSCONFIG%\""
SYSTEM_PLATFORM="psvita"
SYSTEM_THEME="psvita"
diff --git a/config/graphic b/config/graphic
index 7773e4c1f9..9ce1aac65a 100644
--- a/config/graphic
+++ b/config/graphic
@@ -34,7 +34,7 @@ get_graphicdrivers() {
V4L2_SUPPORT="no"
if [ "${GRAPHIC_DRIVERS}" = "all" ]; then
- GRAPHIC_DRIVERS="crocus i915 iris r300 r600 radeonsi nvidia nvidia-legacy nvidia-ng vmware virtio vc4"
+ GRAPHIC_DRIVERS="crocus i915 iris r300 r600 radeonsi nvidia nvidia-legacy nvidia-ng virtio"
fi
if listcontains "${GRAPHIC_DRIVERS}" "crocus"; then
@@ -132,24 +132,10 @@ get_graphicdrivers() {
VAAPI_SUPPORT="yes"
fi
- if listcontains "${GRAPHIC_DRIVERS}" "vc4"; then
- GALLIUM_DRIVERS+=" vc4 v3d kmsro"
- VULKAN_DRIVERS_MESA+=" broadcom"
- V4L2_SUPPORT="yes"
- VAAPI_SUPPORT="no"
- VDPAU_SUPPORT="no"
- fi
-
if listcontains "${GRAPHIC_DRIVERS}" "virtio"; then
GALLIUM_DRIVERS+=" virgl"
fi
- if listcontains "${GRAPHIC_DRIVERS}" "vmware"; then
- GALLIUM_DRIVERS+=" svga"
- XORG_DRIVERS+=" vmware"
- COMPOSITE_SUPPORT="yes"
- fi
-
# VDPAU Support depends on X11
if [ ! "${DISPLAYSERVER}" = "x11" ]; then
VDPAU_SUPPORT="no"
diff --git a/config/noobs/os.json b/config/noobs/os.json
deleted file mode 100644
index 2fb08c7f63..0000000000
--- a/config/noobs/os.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "name": "@DISTRONAME@_@PROJECT@",
- "version": "@LIBREELEC_VERSION@",
- "release_date": "@RELEASE_DATE@",
- "kernel": "@KERNEL_VERSION@",
- "description": "@DESCRIPTION@",
- "username": "root",
- "password": "@ROOT_PASSWORD@",
- "supported_hex_revisions": "@NOOBS_HEX@",
- "supported_models": [@NOOBS_SUPPORTED_MODELS@]
-}
diff --git a/config/noobs/partition_setup.sh b/config/noobs/partition_setup.sh
deleted file mode 100755
index 50577f5e6b..0000000000
--- a/config/noobs/partition_setup.sh
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/bin/sh -x
-
-# SPDX-License-Identifier: GPL-2.0-or-later
-# Copyright (C) 2009-2016 Stephan Raue (stephan@openelec.tv)
-
-MOUNTPOINT="/tmp/LibreELEC-System"
-
-md5sumCheck() {
- ( cd $MOUNTPOINT
- echo "checking MD5: $1"
- md5sum -c $1.md5
- if [ "$?" = "1" ]; then
- echo "#######################################################"
- echo "# #"
- echo "# LibreELEC failed md5 check - Installation will quit #"
- echo "# #"
- echo "# Your original download was probably corrupt. #"
- echo "# Please visit libreelec.tv and get another copy #"
- echo "# #"
- echo "#######################################################"
- exit 1
- fi
- rm -rf $1.md5
- )
-}
-
-if [ -z $part1 -o -z $part2 -o -z $id1 -o -z $id2 ]; then
- echo "error: part1, part2, id1 or id2 not specified"
- echo "actual values:"
- echo "part1:" $part1
- echo "part2:" $part2
- echo "id1 :" $id1
- echo "id2 :" $id2
- exit 1
-fi
-
-# create mountpoint
- mkdir -p $MOUNTPOINT
-
-# mount needed partition
- mount $part1 $MOUNTPOINT
-
-# check md5sum
- md5sumCheck kernel.img
- md5sumCheck SYSTEM
-
-# create bootloader configuration
- echo "creating bootloader configuration..."
- echo "boot=$id1 disk=$id2 quiet" > $MOUNTPOINT/cmdline.txt
-
-# cleanup mountpoint
- umount $MOUNTPOINT
- rmdir $MOUNTPOINT
diff --git a/config/noobs/partitions.json b/config/noobs/partitions.json
deleted file mode 100644
index 09b6dad9f6..0000000000
--- a/config/noobs/partitions.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "partitions": [
- {
- "label": "System",
- "filesystem_type": "FAT",
- "partition_size_nominal": @SYSTEM_SIZE@,
- "want_maximised": false,
- "uncompressed_tarball_size": 1024,
- "mkfs_options": ""
- },
- {
- "label": "Storage",
- "filesystem_type": "ext4",
- "partition_size_nominal": 1024,
- "want_maximised": true,
- "uncompressed_tarball_size": 10,
- "mkfs_options": ""
- }
- ]
-}
diff --git a/config/path b/config/path
index 1a057aec0f..ac57af5da2 100644
--- a/config/path
+++ b/config/path
@@ -19,12 +19,9 @@ set -e
fi
[ -z "${HOST_NAME}" ] && export HOST_NAME="$(${LOCAL_CC} -dumpmachine)"
-TARGET_NAME=$TARGET_GCC_ARCH-libreelec-linux-gnu${TARGET_ABI}
+TARGET_NAME=$TARGET_GCC_ARCH-jelos-linux-gnu${TARGET_ABI}
BUILD=${BUILD_ROOT}/${BUILD_BASE}.${DISTRONAME}-${DEVICE:-${PROJECT}}.${TARGET_ARCH}
-if [ "${LIBREELEC_VERSION}" = "devel" ] ; then
- BUILD=${BUILD_ROOT}/${BUILD_BASE}.${DISTRONAME}-${DEVICE:-${PROJECT}}.${TARGET_ARCH}-${OS_VERSION}-${LIBREELEC_VERSION}
-fi
if [ -n "$BUILD_SUFFIX" ]; then
BUILD=$BUILD-$BUILD_SUFFIX
diff --git a/distributions/JELOS/options b/distributions/JELOS/options
index 5f2178c737..404b9af991 100644
--- a/distributions/JELOS/options
+++ b/distributions/JELOS/options
@@ -20,13 +20,13 @@
DESCRIPTION="An Open Source firmware."
# Distribution Home URL
- HOME_URL="https://www.jelos.org"
+ HOME_URL="https://jelos.org"
# Documentation URL
- WIKI_URL="https://www.jelos.org"
+ WIKI_URL="https://jelos.org"
# Where to report bugs
- BUG_REPORT_URL="https://www.jelos.org"
+ BUG_REPORT_URL="https://jelos.org"
# Root password to integrate in the target system
ROOT_PASSWORD="system generated"
@@ -107,7 +107,7 @@
CONTAINER_SUPPORT="${CONTAINER_SUPPORT:-no}"
# Support for debug tools such as strace
- DEBUG_SUPPORT="${DEBUG_SUPPORT:-yes}"
+ DEBUG_PACKAGES="${DEBUG_PACKAGES:-yes}"
# Windowmanager to use (fluxbox / none)
WINDOWMANAGER="none"
diff --git a/documentation/PER_DEVICE_DOCUMENTATION/AMD64/SUPPORTED_EMULATORS_AND_CORES.md b/documentation/PER_DEVICE_DOCUMENTATION/AMD64/SUPPORTED_EMULATORS_AND_CORES.md
index 58979c14dd..038c9d79f2 100644
--- a/documentation/PER_DEVICE_DOCUMENTATION/AMD64/SUPPORTED_EMULATORS_AND_CORES.md
+++ b/documentation/PER_DEVICE_DOCUMENTATION/AMD64/SUPPORTED_EMULATORS_AND_CORES.md
@@ -119,7 +119,7 @@ This document describes all available systems emulators and cores available for
|Sony|PlayStation 2 (ps2)|2000|`ps2`|.iso .mdf .nrg .bin .img .dump .gz .cso .chd|**pcsx2:** pcsx2-sa (default)
**retroarch:** pcsx2
|
|Sony|PlayStation 3 (ps3)|2006|`ps3`|.ps3 .psn|**rpcs3:** rpcs3-sa (default)
|
|Sony|PlayStation Portable (psp)|2004|`psp`|.iso .cso .pbp .chd|**ppsspp:** ppsspp-sa (default)
**retroarch:** ppsspp
|
-|Sony|PlayStation Vita (psvita)|2011|`launcher`|.sh|**vita3k:** vita3k-sa (default)
|
+|Sony|PlayStation Vita (psvita)|2011|`launcher`|.sh .psvita|**vita3k:** vita3k-sa (default)
|
|Sony|PSP Minis (pspminis)|2004|`pspminis`|.iso .cso .pbp|**ppsspp:** ppsspp-sa (default)
**retroarch:** ppsspp
|
|Sun Microsystems|J2ME (j2me)|2002|`j2me`|.jar|**retroarch:** freej2me (default)
|
|Various|CHIP-8 / S-CHIP / XO-CHIP (chip-8)|1978|`chip-8`|.ch8 .sc8 .xo8|**retroarch:** jaxe (default)
|
diff --git a/documentation/PER_DEVICE_DOCUMENTATION/RK3399/SUPPORTED_EMULATORS_AND_CORES.md b/documentation/PER_DEVICE_DOCUMENTATION/RK3399/SUPPORTED_EMULATORS_AND_CORES.md
index c3612ba8c6..e8ea141835 100644
--- a/documentation/PER_DEVICE_DOCUMENTATION/RK3399/SUPPORTED_EMULATORS_AND_CORES.md
+++ b/documentation/PER_DEVICE_DOCUMENTATION/RK3399/SUPPORTED_EMULATORS_AND_CORES.md
@@ -116,6 +116,7 @@ This document describes all available systems emulators and cores available for
|Sony|PlayStation Portable (psp)|2004|`psp`|.iso .cso .pbp .chd|**ppsspp:** ppsspp-sa (default)
|
|Sony|PSP Minis (pspminis)|2004|`pspminis`|.iso .cso .pbp|**ppsspp:** ppsspp-sa (default)
**retroarch:** ppsspp
|
|Sun Microsystems|J2ME (j2me)|2002|`j2me`|.jar|**retroarch:** freej2me (default)
|
+|Various|CHIP-8 / S-CHIP / XO-CHIP (chip-8)|1978|`chip-8`|.ch8 .sc8 .xo8|**retroarch:** jaxe (default)
|
|Various|EasyRPG (easyrpg)|2003|`easyrpg`|.zip .easyrpg .ldb|**retroarch:** easyrpg (default)
|
|Various|OpenBOR (openbor)|2003|`openbor`|.pak|**OpenBOR:** OpenBOR (default)
|
|Various|ScummVM (scummvm)|2001|`games`|.sh .svm .scummvm|**scummvmsa:** scummvm (default)
**retroarch:** scummvm
|
diff --git a/packages/apps/device-switch/package.mk b/packages/apps/device-switch/package.mk
new file mode 100644
index 0000000000..fd8bc3f21c
--- /dev/null
+++ b/packages/apps/device-switch/package.mk
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2024-present JELOS (https://github.com/JustEnoughLinuxOS)
+
+PKG_NAME="device-switch"
+PKG_VERSION=""
+PKG_ARCH="any"
+PKG_LICENSE="mix"
+PKG_DEPENDS_TARGET="toolchain"
+PKG_SITE=""
+PKG_URL=""
+PKG_LONGDESC="Support script for switching device dtbs"
+PKG_TOOLCHAIN="manual"
+
+makeinstall_target() {
+
+ mkdir -p ${INSTALL}/usr/bin
+ cp ${PKG_DIR}/scripts/${DEVICE}/device-switch ${INSTALL}/usr/bin
+ chmod 0755 ${INSTALL}/usr/bin/*
+}
diff --git a/packages/apps/device-switch/scripts/RK3326/device-switch b/packages/apps/device-switch/scripts/RK3326/device-switch
new file mode 100644
index 0000000000..969756ae05
--- /dev/null
+++ b/packages/apps/device-switch/scripts/RK3326/device-switch
@@ -0,0 +1,24 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2024-present JELOS (https://github.com/JustEnoughLinuxOS)
+
+. /etc/profile
+
+mount -o remount,rw /flash
+case $1 in
+ R33S)
+ sed -i '/rk3326-gameconsole-r3/c\ load mmc 1:1 ${dtb_loadaddr} rk3326-gameconsole-r33s.dtb' /flash/boot.ini
+ rm -r /storage/remappings/*
+ ;;
+ R36S)
+ sed -i '/rk3326-gameconsole-r3/c\ load mmc 1:1 ${dtb_loadaddr} rk3326-gameconsole-r36s.dtb' /flash/boot.ini
+ rm -r /storage/remappings/*
+ ;;
+esac
+
+cat </flash/device.name
+$1
+EOF
+
+sync
+reboot
diff --git a/packages/apps/device-switch/scripts/RK3326/device-switch.save b/packages/apps/device-switch/scripts/RK3326/device-switch.save
new file mode 100644
index 0000000000..afb5b818b1
--- /dev/null
+++ b/packages/apps/device-switch/scripts/RK3326/device-switch.save
@@ -0,0 +1,20 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2022-present JELOS (https://github.com/JustEnoughLinuxOS)
+
+. /etc/profile
+
+mount -o remount,rw /flash
+case $1 in
+ R33S)
+ sed -i "s#rk3566-rg353v-linux.dtb#rk3566-rg353p-linux.dtb#g" /flash/extlinux/extlinux.conf
+ ;;
+ R36S)
+ sed -i "s#rk3566-rg353p-linux.dtb#rk3566-rg353v-linux.dtb#g" /flash/extlinux/extlinux.conf
+ ;;
+esac
+
+set_setting system.hostname ${1}
+
+sync
+reboot
diff --git a/packages/apps/jelos-gamepad/package.mk b/packages/apps/jelos-gamepad/package.mk
new file mode 100644
index 0000000000..c928235b91
--- /dev/null
+++ b/packages/apps/jelos-gamepad/package.mk
@@ -0,0 +1,19 @@
+PKG_NAME="jelos-gamepad"
+PKG_VERSION="b1fc0fb69047011d99b54029be500280d33a8027"
+PKG_ARCH="aarch64"
+PKG_LICENSE="GPLv3"
+PKG_SITE="https://github.com/R-ARM/rinputer2"
+PKG_URL="$PKG_SITE.git"
+PKG_DEPENDS_TARGET="toolchain"
+PKG_TOOLCHAIN="make"
+GET_HANDLER_SUPPORT="git"
+
+makeinstall_target() {
+ mkdir -p $INSTALL/usr/bin
+ cp rinputer2 ${INSTALL}/usr/bin/jelos_gamepad
+ chmod 0755 ${INSTALL}/usr/bin/jelos_gamepad
+}
+
+post_install() {
+ enable_service jelos_gamepad.service
+}
diff --git a/packages/apps/jelos-gamepad/patches/000-jelos-gamepad.patch b/packages/apps/jelos-gamepad/patches/000-jelos-gamepad.patch
new file mode 100644
index 0000000000..30f9cea1e9
--- /dev/null
+++ b/packages/apps/jelos-gamepad/patches/000-jelos-gamepad.patch
@@ -0,0 +1,56 @@
+diff -rupN rinputer2.orig/main.c rinputer2/main.c
+--- rinputer2.orig/main.c 2023-11-23 04:47:16.344733862 +0000
++++ rinputer2/main.c 2023-11-23 15:00:20.535535759 +0000
+@@ -240,7 +240,7 @@ int rescan_devices(struct rinputer_devic
+ continue;
+
+ // let's not make a loop
+- if(strncmp("Rinputer", name, 8) == 0)
++ if(strncmp("JELOS Gamepad", name, 8) == 0)
+ continue;
+ // ignore steam-created controllers
+ // they have this name, with a digit at the end
+@@ -316,10 +316,10 @@ int main(void)
+
+ ioctl(outfd, UI_SET_EVBIT, EV_KEY);
+
+- //ioctl(outfd, UI_SET_KEYBIT, BTN_DPAD_UP); // dpad up
+- //ioctl(outfd, UI_SET_KEYBIT, BTN_DPAD_DOWN); // dpad down
+- //ioctl(outfd, UI_SET_KEYBIT, BTN_DPAD_LEFT); // dpad left
+- //ioctl(outfd, UI_SET_KEYBIT, BTN_DPAD_RIGHT); // dpad right
++ ioctl(outfd, UI_SET_KEYBIT, BTN_DPAD_UP); // dpad up
++ ioctl(outfd, UI_SET_KEYBIT, BTN_DPAD_DOWN); // dpad down
++ ioctl(outfd, UI_SET_KEYBIT, BTN_DPAD_LEFT); // dpad left
++ ioctl(outfd, UI_SET_KEYBIT, BTN_DPAD_RIGHT); // dpad right
+
+ ioctl(outfd, UI_SET_KEYBIT, BTN_NORTH); // x
+ ioctl(outfd, UI_SET_KEYBIT, BTN_SOUTH); // b
+@@ -332,6 +332,9 @@ int main(void)
+ ioctl(outfd, UI_SET_KEYBIT, BTN_TR2); // L2
+ ioctl(outfd, UI_SET_KEYBIT, BTN_TL2); // R2
+
++ ioctl(outfd, UI_SET_KEYBIT, BTN_THUMBL); // L3
++ ioctl(outfd, UI_SET_KEYBIT, BTN_THUMBR); // R3
++
+ ioctl(outfd, UI_SET_KEYBIT, BTN_SELECT);
+ ioctl(outfd, UI_SET_KEYBIT, BTN_START);
+
+@@ -350,15 +353,15 @@ int main(void)
+ setup_abs(outfd, ABS_RZ);
+
+ // dpad
+- setup_abs(outfd, ABS_HAT0X);
+- setup_abs(outfd, ABS_HAT0Y);
++ //setup_abs(outfd, ABS_HAT0X);
++ //setup_abs(outfd, ABS_HAT0Y);
+
+ // maybe we should pretend to be xbox gamepad?
+ memset(&usetup, 0, sizeof(usetup));
+ usetup.id.bustype = BUS_USB;
+ usetup.id.vendor = 0x1234;
+ usetup.id.product = 0x5678;
+- strcpy(usetup.name, "Rinputer");
++ strcpy(usetup.name, "JELOS Gamepad");
+
+ ioctl(outfd, UI_DEV_SETUP, &usetup);
+ ioctl(outfd, UI_DEV_CREATE);
diff --git a/packages/apps/jelos-gamepad/system.d/jelos_gamepad.service b/packages/apps/jelos-gamepad/system.d/jelos_gamepad.service
new file mode 100644
index 0000000000..d5b6152cde
--- /dev/null
+++ b/packages/apps/jelos-gamepad/system.d/jelos_gamepad.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=Ragnarok Input Daemon
+
+[Service]
+Type=simple
+ExecStart=/usr/bin/jelos_gamepad
+
+[Install]
+WantedBy=multi-user.target
diff --git a/packages/audio/alsa-lib/package.mk b/packages/audio/alsa-lib/package.mk
index 5e31aa37c5..694f20133d 100644
--- a/packages/audio/alsa-lib/package.mk
+++ b/packages/audio/alsa-lib/package.mk
@@ -7,20 +7,11 @@ PKG_VERSION="1.2.10"
PKG_LICENSE="GPL"
PKG_SITE="http://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-topology-conf"
+PKG_DEPENDS_TARGET="toolchain alsa-ucm-conf alsa-topology-conf"
PKG_LONGDESC="ALSA (Advanced Linux Sound Architecture) is the next generation Linux Sound API."
PKG_TOOLCHAIN="autotools"
PKG_BUILD_FLAGS="+pic"
-case ${DEVICE} in
- RK356*)
- PKG_DEPENDS_TARGET+=""
- ;;
- *)
- PKG_DEPENDS_TARGET+=" alsa-ucm-conf"
- ;;
-esac
-
if build_with_debug; then
PKG_ALSA_DEBUG=--with-debug
else
diff --git a/packages/audio/alsa-utils/package.mk b/packages/audio/alsa-utils/package.mk
index dd1383826a..fed5b128ae 100644
--- a/packages/audio/alsa-utils/package.mk
+++ b/packages/audio/alsa-utils/package.mk
@@ -8,7 +8,7 @@ PKG_VERSION="1.2.10"
PKG_LICENSE="GPL"
PKG_SITE="http://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"
+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."
PKG_TOOLCHAIN="autotools"
@@ -20,10 +20,6 @@ PKG_CONFIGURE_OPTS_TARGET="--disable-alsaconf \
--disable-nls \
--disable-rst2man \
--disable-xmlto"
-if [[ ! "${DEVICE}" =~ RK356 ]]
-then
- PKG_DEPENDS_TARGET+=" alsa-ucm-conf"
-fi
post_makeinstall_target() {
rm -rf ${INSTALL}/lib ${INSTALL}/var
diff --git a/packages/audio/rpi-cirrus-config/modprobe.d/rpi-cirrus.conf b/packages/audio/rpi-cirrus-config/modprobe.d/rpi-cirrus.conf
deleted file mode 100644
index 2b3237d29f..0000000000
--- a/packages/audio/rpi-cirrus-config/modprobe.d/rpi-cirrus.conf
+++ /dev/null
@@ -1 +0,0 @@
-softdep arizona-spi pre: arizona-ldo1
diff --git a/packages/audio/rpi-cirrus-config/package.mk b/packages/audio/rpi-cirrus-config/package.mk
deleted file mode 100644
index f0f6eccae6..0000000000
--- a/packages/audio/rpi-cirrus-config/package.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
-
-PKG_NAME="rpi-cirrus-config"
-PKG_VERSION="0.0.2"
-PKG_SHA256="cc11c47f1f2b6d5e72dcdea828ba57e0dcaf74161f675a4a9f395054f5d82d31"
-PKG_LICENSE="GPL"
-PKG_SITE="https://github.com/HiassofT/rpi-cirrus-config"
-PKG_URL="https://github.com/HiassofT/rpi-cirrus-config/archive/${PKG_VERSION}.tar.gz"
-PKG_DEPENDS_TARGET="alsa-utils"
-PKG_LONGDESC="Config scripts for the Wolfson/Cirrus Logic audio card"
-PKG_TOOLCHAIN="manual"
-
-makeinstall_target() {
- mkdir -p ${INSTALL}/usr/lib/udev
- install -m 0755 ${PKG_DIR}/scripts/rpi-cirrus-config ${INSTALL}/usr/lib/udev/rpi-cirrus-config
-
- mkdir -p ${INSTALL}/usr/share/alsa/cards
- cp alsa/RPiCirrus.conf ${INSTALL}/usr/share/alsa/cards
-
- mkdir -p ${INSTALL}/usr/lib/alsa
- cp mixer-scripts/rpi-cirrus-functions.sh ${INSTALL}/usr/lib/alsa
-
- mkdir -p ${INSTALL}/usr/config
- cp -PR ${PKG_DIR}/config/* ${INSTALL}/usr/config
-}
diff --git a/packages/audio/rpi-cirrus-config/scripts/rpi-cirrus-config b/packages/audio/rpi-cirrus-config/scripts/rpi-cirrus-config
deleted file mode 100755
index d8bda0b07c..0000000000
--- a/packages/audio/rpi-cirrus-config/scripts/rpi-cirrus-config
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/sh
-
-# setup default mixer settings for Cirrus Logic Audio Card
-
-. /etc/profile
-
-if [ -f $HOME/.config/sound.conf ] ; then
- alsactl restore -f $HOME/.config/sound.conf
-else
- if [ -r $HOME/.config/rpi-cirrus-config.sh ] ; then
- progress "Setting up Cirrus Logic Audio Card with user config"
- sh $HOME/.config/rpi-cirrus-config.sh
- else
- progress "Setting up Cirrus Logic Audio Card"
-
- # load helper functions and definitions
- . /usr/lib/alsa/rpi-cirrus-functions.sh
-
- playback_to_spdif
- playback_to_lineout
- playback_to_headset
- mixer 'Noise Gate Switch' off
- fi
-fi
diff --git a/packages/audio/rpi-cirrus-config/udev.d/90-alsa-restore.rules b/packages/audio/rpi-cirrus-config/udev.d/90-alsa-restore.rules
deleted file mode 100644
index 283dc4c8b6..0000000000
--- a/packages/audio/rpi-cirrus-config/udev.d/90-alsa-restore.rules
+++ /dev/null
@@ -1,17 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
-
-# When a sound device is detected, restore the volume settings
-SUBSYSTEM=="sound", KERNEL=="controlC*", NAME="snd/%k", ACTION=="add", GOTO="alsa_restore_go"
-GOTO="alsa_restore_end"
-
-LABEL="alsa_restore_go"
-
-# Separate config-script for RPi-Cirrus card
-DRIVERS=="snd-rpi-cirrus", RUN+="rpi-cirrus-config", GOTO="alsa_restore_end"
-
-# Default config-script for all other cards
-RUN+="soundconfig %k"
-
-LABEL="alsa_restore_end"
-
diff --git a/packages/compress/unzip/package.mk b/packages/compress/unzip/package.mk
index be4f17410d..1fb8258952 100644
--- a/packages/compress/unzip/package.mk
+++ b/packages/compress/unzip/package.mk
@@ -5,8 +5,8 @@ PKG_NAME="unzip"
PKG_VERSION="60"
PKG_SHA256="036d96991646d0449ed0aa952e4fbe21b476ce994abc276e49d30e686708bd37"
PKG_LICENSE="OSS"
-PKG_SITE="http://www.info-zip.org/pub/infozip"
-PKG_URL="http://downloads.sourceforge.net/sourceforge/infozip/${PKG_NAME}${PKG_VERSION}.tar.gz"
+PKG_SITE="http://www.info-zip.org/pub/infozip/"
+PKG_URL="https://sourceforge.net/projects/infozip/files/UnZip%206.x%20(latest)/UnZip%206.0/unzip60.tar.gz"
PKG_DEPENDS_TARGET="toolchain"
PKG_LONGDESC="UnZip is an extraction utility for archives compressed in .zip format."
PKG_TOOLCHAIN="manual"
diff --git a/packages/debug/strace/package.mk b/packages/debug/strace/package.mk
index a09984a29e..baa0d0ec81 100644
--- a/packages/debug/strace/package.mk
+++ b/packages/debug/strace/package.mk
@@ -11,5 +11,5 @@ PKG_LONGDESC="strace is a diagnostic, debugging and instructional userspace util
PKG_TOOLCHAIN="autotools"
if [ "${TARGET_ARCH}" = x86_64 -o "${TARGET_ARCH}" = "aarch64" ]; then
- PKG_CONFIGURE_OPTS_TARGET="--enable-mpers=no"
+ PKG_CONFIGURE_OPTS_TARGET="--enable-mpers=no --enable-bundled"
fi
diff --git a/packages/devel/binutils/patches/binutils-01-warn-for-uses-of-system-directories-when-link.patch b/packages/devel/binutils/patches/binutils-01-warn-for-uses-of-system-directories-when-link.patch
index 1619cef941..7cac3adb7c 100644
--- a/packages/devel/binutils/patches/binutils-01-warn-for-uses-of-system-directories-when-link.patch
+++ b/packages/devel/binutils/patches/binutils-01-warn-for-uses-of-system-directories-when-link.patch
@@ -3,7 +3,7 @@ http://git.yoctoproject.org/cgit.cgi/poky/plain/meta/recipes-devtools/binutils/b
just detect and skip system directories if used by mistake
linker output in case of using /usr/lib path:
-/data/LibreELEC.tv/build.LibreELEC-Generic.x86_64-8.0-devel/toolchain/lib/gcc/x86_64-libreelec-linux-gnu/6.2.0/../../../../x86_64-libreelec-linux-gnu/bin/ld: warning: library search path "/usr/lib" is unsafe for cross-compilation, ignore it
+/data/LibreELEC.tv/build.LibreELEC-Generic.x86_64-8.0-devel/toolchain/lib/gcc/x86_64-jelos-linux-gnu/6.2.0/../../../../x86_64-jelos-linux-gnu/bin/ld: warning: library search path "/usr/lib" is unsafe for cross-compilation, ignore it
From 7ab8e318659eb5d9adc758c78d084a95560b93fd Mon Sep 17 00:00:00 2001
From: Khem Raj
diff --git a/packages/devel/elfutils/package.mk b/packages/devel/elfutils/package.mk
index bbbb2e1174..e2ed942057 100644
--- a/packages/devel/elfutils/package.mk
+++ b/packages/devel/elfutils/package.mk
@@ -14,14 +14,6 @@ PKG_LONGDESC="A collection of utilities to handle ELF objects."
PKG_TOOLCHAIN="autotools"
PKG_BUILD_FLAGS="+pic"
-if [ "${LIBREELEC_VERSION}" = "devel" ]; then
- PKG_PROGRAMS="--enable-programs --program-prefix="
- PKG_PROGRAMS_LIST="readelf"
-else
- PKG_PROGRAMS="--disable-programs"
- PKG_PROGRAMS_LIST=
-fi
-
PKG_CONFIGURE_OPTS_HOST="utrace_cv_cc_biarch=false \
--disable-programs \
--disable-nls \
@@ -32,7 +24,7 @@ PKG_CONFIGURE_OPTS_HOST="utrace_cv_cc_biarch=false \
--without-lzma"
PKG_CONFIGURE_OPTS_TARGET="utrace_cv_cc_biarch=false \
- ${PKG_PROGRAMS} \
+ --disable-programs \
--disable-nls \
--disable-demangler \
--disable-debuginfod \
diff --git a/packages/devel/glibc/package.mk b/packages/devel/glibc/package.mk
index 84b55eb88a..8265f7b7ca 100644
--- a/packages/devel/glibc/package.mk
+++ b/packages/devel/glibc/package.mk
@@ -13,9 +13,6 @@ PKG_LONGDESC="The Glibc package contains the main C library."
PKG_BUILD_FLAGS="+bfd -gold"
case "${DEVICE}" in
- RK356*)
- OPT_ENABLE_KERNEL=4.4.0
- ;;
RK358*)
OPT_ENABLE_KERNEL=5.10.0
;;
diff --git a/packages/devel/gmp/package.mk b/packages/devel/gmp/package.mk
index d5be433231..e2ce1f083a 100644
--- a/packages/devel/gmp/package.mk
+++ b/packages/devel/gmp/package.mk
@@ -6,7 +6,7 @@ PKG_NAME="gmp"
PKG_VERSION="6.3.0"
PKG_LICENSE="LGPLv3+"
PKG_SITE="http://gmplib.org/"
-PKG_URL="https://gmplib.org/download/gmp/${PKG_NAME}-${PKG_VERSION}.tar.xz"
+PKG_URL="https://ftp.gnu.org/gnu/gmp/${PKG_NAME}-${PKG_VERSION}.tar.xz"
PKG_DEPENDS_HOST="ccache:host m4:host"
PKG_DEPENDS_TARGET="toolchain"
PKG_LONGDESC="A library for arbitrary precision arithmetic, operating on signed integers, rational numbers, and floating point numbers."
diff --git a/packages/devel/qt5/package.mk b/packages/devel/qt5/package.mk
index f795e4e35f..7ba9fb84fb 100644
--- a/packages/devel/qt5/package.mk
+++ b/packages/devel/qt5/package.mk
@@ -60,7 +60,7 @@ pre_configure_target() {
PKG_CONFIGURE_OPTS_TARGET="-prefix /usr
-sysroot ${SYSROOT_PREFIX}
-hostprefix ${TOOLCHAIN}
- -device linux-libreelec-g++
+ -device linux-g++
-device-option CROSS_COMPILE=${TARGET_PREFIX}
-fontconfig
-opensource -confirm-license
@@ -160,13 +160,8 @@ configure_target() {
mkdir -p ${PKG_BUILD}/.${TARGET_NAME}
cd ${PKG_BUILD}/.${TARGET_NAME}
- # Avoid eglfs_brcm detection by bcm_host.h
- if [ "${DEVICE}" = "RPi4" -o "${DEVICE}" = "RPi2" ]; then
- sed -e "s#bcm_host.h#bcm_host2.h#" -i ${PKG_BUILD}/qtbase/src/gui/configure.json
- fi
-
# Create mkspecs file
- QMAKE_CONF_DIR="${PKG_BUILD}/qtbase/mkspecs/devices/linux-libreelec-g++"
+ QMAKE_CONF_DIR="${PKG_BUILD}/qtbase/mkspecs/devices/linux-g++"
QMAKE_CONF="${QMAKE_CONF_DIR}/qmake.conf"
mkdir -p ${QMAKE_CONF_DIR}
diff --git a/packages/emulators/libretro/idtech-lr/package.mk b/packages/emulators/libretro/idtech-lr/package.mk
index 325913756a..90ffe9836a 100644
--- a/packages/emulators/libretro/idtech-lr/package.mk
+++ b/packages/emulators/libretro/idtech-lr/package.mk
@@ -3,7 +3,7 @@
PKG_NAME="idtech-lr"
PKG_LICENSE="Apache-2.0"
-PKG_SITE="www.jelos.org"
+PKG_SITE="https://jelos.org"
PKG_LONGDESC="Package for all iD Software game engines."
PKG_TOOLCHAIN="manual"
diff --git a/packages/emulators/standalone/dolphin-sa/config/AMD64/WiiControllerProfiles/hremote.ini b/packages/emulators/standalone/dolphin-sa/config/AMD64/WiiControllerProfiles/hremote.ini
index cbd6a07604..88ebbc2d30 100644
--- a/packages/emulators/standalone/dolphin-sa/config/AMD64/WiiControllerProfiles/hremote.ini
+++ b/packages/emulators/standalone/dolphin-sa/config/AMD64/WiiControllerProfiles/hremote.ini
@@ -12,8 +12,8 @@ Shake/Y = Button 4
Shake/Z = Button 4
D-Pad/Up = Axis 6-
D-Pad/Down = Axis 6+
-D-Pad/Left = Axis 7-
-D-Pad/Right = Axis 7+
+D-Pad/Left = Axis 7+
+D-Pad/Right = Axis 7-
IR/Up = `Axis 4-`
IR/Down = `Axis 4+`
IR/Left = `Axis 3-`
diff --git a/packages/emulators/standalone/dolphin-sa/config/AMD64/WiiControllerProfiles/vremote.ini b/packages/emulators/standalone/dolphin-sa/config/AMD64/WiiControllerProfiles/vremote.ini
index 2880a8a369..6f5adf896b 100644
--- a/packages/emulators/standalone/dolphin-sa/config/AMD64/WiiControllerProfiles/vremote.ini
+++ b/packages/emulators/standalone/dolphin-sa/config/AMD64/WiiControllerProfiles/vremote.ini
@@ -10,10 +10,10 @@ Buttons/Home = Button 8
Shake/X = Button 4
Shake/Y = Button 4
Shake/Z = Button 4
-D-Pad/Up = Axis 7-
-D-Pad/Down = Axis 7+
-D-Pad/Left = Axis 6-
-D-Pad/Right = Axis 6+
+D-Pad/Up = Axis 7+
+D-Pad/Down = Axis 7-
+D-Pad/Left = Axis 6+
+D-Pad/Right = Axis 6-
IR/Up = `Axis 4-`
IR/Down = `Axis 4+`
IR/Left = `Axis 3-`
diff --git a/packages/emulators/standalone/duckstation-sa/config/RK3566/RK3566 b/packages/emulators/standalone/duckstation-sa/config/RK3566/RK3566
new file mode 120000
index 0000000000..9207b5754b
--- /dev/null
+++ b/packages/emulators/standalone/duckstation-sa/config/RK3566/RK3566
@@ -0,0 +1 @@
+RK3566
\ No newline at end of file
diff --git a/packages/emulators/standalone/flycast-sa/package.mk b/packages/emulators/standalone/flycast-sa/package.mk
index 07472663f5..ad6af839a8 100644
--- a/packages/emulators/standalone/flycast-sa/package.mk
+++ b/packages/emulators/standalone/flycast-sa/package.mk
@@ -3,7 +3,7 @@
# Copyright (C) 2022-present JELOS (https://github.com/JustEnoughLinuxOS)
PKG_NAME="flycast-sa"
-PKG_VERSION="c146a92f83ae2cba8df8970e21efc54301b9ade1"
+PKG_VERSION="195f401044fc3a77d6ae0dbd206d446d127b2769"
PKG_LICENSE="GPLv2"
PKG_SITE="https://github.com/flyinghead/flycast"
PKG_URL="${PKG_SITE}.git"
diff --git a/packages/emulators/standalone/retroarch/package.mk b/packages/emulators/standalone/retroarch/package.mk
index 20c5bfc815..0a215f6d65 100644
--- a/packages/emulators/standalone/retroarch/package.mk
+++ b/packages/emulators/standalone/retroarch/package.mk
@@ -37,16 +37,6 @@ case ${PROJECT} in
;;
esac
-case ${DEVICE} in
- RK3566*)
- PKG_DEPENDS_TARGET+=" libgo2"
- PKG_CONFIGURE_OPTS_TARGET+=" --enable-odroidgo2"
- ;;
- *)
- PKG_CONFIGURE_OPTS_TARGET+=" --disable-odroidgo2"
- ;;
-esac
-
case ${ARCH} in
arm)
PKG_CONFIGURE_OPTS_TARGET+=" --enable-neon"
diff --git a/packages/emulators/standalone/retroarch/patches/RK3566-X55/0011-librga.patch b/packages/emulators/standalone/retroarch/patches/RK3566-X55/0011-librga.patch
deleted file mode 100644
index 7f875aea19..0000000000
--- a/packages/emulators/standalone/retroarch/patches/RK3566-X55/0011-librga.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -rupN retroarch.orig/gfx/drivers/oga_gfx.c retroarch/gfx/drivers/oga_gfx.c
---- retroarch.orig/gfx/drivers/oga_gfx.c 2022-02-28 19:40:46.222185295 -0500
-+++ retroarch/gfx/drivers/oga_gfx.c 2022-02-28 19:44:14.187909576 -0500
-@@ -22,7 +22,7 @@
- #include "../../verbosity.h"
- #include
- #include
--#include
-+#include
- #include
- #include
- #include
diff --git a/packages/emulators/standalone/retroarch/patches/RK3566-X55/002-display-tweaks.patch b/packages/emulators/standalone/retroarch/patches/RK3566-X55/002-display-tweaks.patch
deleted file mode 100644
index bc388cce96..0000000000
--- a/packages/emulators/standalone/retroarch/patches/RK3566-X55/002-display-tweaks.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-Correct DRM format on Powkiddy x55, extracted from PowKiddy x55 sources.
-diff --git a/deps/libgo2/src/display.c b/deps/libgo2/src/display.c
-index b91cf0624b..936b677fc4 100644
---- a/deps/libgo2/src/display.c
-+++ b/deps/libgo2/src/display.c
-@@ -550,7 +550,7 @@ static uint32_t go2_rkformat_get(uint32_t drm_fourcc)
-
- case DRM_FORMAT_ARGB8888:
- case DRM_FORMAT_XRGB8888:
-- return RK_FORMAT_BGRA_8888;
-+ return RK_FORMAT_RGBA_8888;
-
- case DRM_FORMAT_RGB565:
- return RK_FORMAT_RGB_565;
-@@ -586,6 +586,7 @@ void go2_surface_blit(go2_surface_t* srcSurface, int srcX, int srcY, int srcWidt
- dst.rect.hstride = dstSurface->height;
- dst.rect.format = go2_rkformat_get(dstSurface->format);
-
-+
- rga_info_t src = { 0 };
- src.fd = go2_surface_prime_fd(srcSurface);
- src.mmuFlag = 1;
-diff --git a/gfx/drivers_context/drm_go2_ctx.c b/gfx/drivers_context/drm_go2_ctx.c
-index b758137703..dbcb992279 100644
---- a/gfx/drivers_context/drm_go2_ctx.c
-+++ b/gfx/drivers_context/drm_go2_ctx.c
-@@ -133,7 +133,7 @@ static void *gfx_ctx_go2_drm_init(void *video_driver)
- }
-
- drm->presenter = go2_presenter_create(drm->display,
-- DRM_FORMAT_RGB565, 0xff000000, true);
-+ DRM_FORMAT_XRGB8888, 0xff000000, true);
-
- return drm;
- }
diff --git a/packages/emulators/standalone/vita3k-sa/package.mk b/packages/emulators/standalone/vita3k-sa/package.mk
index 0fdf101efa..cc2369c1a5 100644
--- a/packages/emulators/standalone/vita3k-sa/package.mk
+++ b/packages/emulators/standalone/vita3k-sa/package.mk
@@ -2,7 +2,7 @@
# Copyright (C) 2022-present JELOS (https://github.com/JustEnoughLinuxOS)
PKG_NAME="vita3k-sa"
-PKG_VERSION="564417b3b6a31296a2a09912c249a0145376e3c8"
+PKG_VERSION="da73a57"
PKG_LICENSE="GPLv2"
PKG_SITE="https://github.com/Vita3K/Vita3K"
PKG_URL="${PKG_SITE}.git"
@@ -33,7 +33,8 @@ pre_configure_target() {
PKG_CMAKE_OPTS_TARGET+=" -DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=OFF \
-DUSE_DISCORD_RICH_PRESENCE=OFF \
- -DUSE_VITA3K_UPDATE=OFF"
+ -DUSE_VITA3K_UPDATE=OFF \
+ -DXXH_X86DISPATCH_ALLOW_AVX=ON"
}
makeinstall_target() {
@@ -46,6 +47,9 @@ makeinstall_target() {
chmod 0755 ${INSTALL}/usr/bin/*
mkdir -p ${INSTALL}/usr/config/vita3k/launcher
- cp ${PKG_DIR}/scripts/start_vita3k.sh ${INSTALL}/usr/config/vita3k/launcher/Start\ Vita3K.sh
- chmod 0755 ${INSTALL}/usr/config/vita3k/launcher/Start\ Vita3K.sh
+ cp ${PKG_DIR}/scripts/start_vita3k.sh ${INSTALL}/usr/config/vita3k/launcher/_Start\ Vita3K.sh
+ cp ${PKG_DIR}/scripts/scan_vita3k.sh ${INSTALL}/usr/config/vita3k/launcher/_Scan\ Vita\ Games.sh
+ chmod 0755 ${INSTALL}/usr/config/vita3k/launcher/*sh
+
+ cp ${PKG_DIR}/sources/vita-gamelist.txt ${INSTALL}/usr/config/vita3k
}
diff --git a/packages/emulators/standalone/vita3k-sa/patches/001-base-path.patch b/packages/emulators/standalone/vita3k-sa/patches/001-base-path.patch
index 1b0777c25d..003bb01ea0 100644
--- a/packages/emulators/standalone/vita3k-sa/patches/001-base-path.patch
+++ b/packages/emulators/standalone/vita3k-sa/patches/001-base-path.patch
@@ -1,15 +1,26 @@
-diff --git a/vita3k/main.cpp b/vita3k/main.cpp
-index 4439ad9b6e..c26b84ff82 100644
---- a/vita3k/main.cpp
-+++ b/vita3k/main.cpp
-@@ -84,8 +84,8 @@ static void run_execv(char *argv[], EmuEnvState &emuenv) {
- int main(int argc, char *argv[]) {
- ZoneScoped; // Tracy - Track main function scope
- Root root_paths;
-- root_paths.set_base_path(string_utils::utf_to_wide(SDL_GetBasePath()));
-- root_paths.set_pref_path(string_utils::utf_to_wide(SDL_GetPrefPath(org_name, app_name)));
-+ root_paths.set_base_path(string_utils::utf_to_wide("/storage/.config/vita3k/"));
-+ root_paths.set_pref_path(string_utils::utf_to_wide("/storage/psvita/vita3k/"));
+diff --git a/vita3k/app/src/app_init.cpp b/vita3k/app/src/app_init.cpp
+index 8536b401..459e21f5 100644
+--- a/vita3k/app/src/app_init.cpp
++++ b/vita3k/app/src/app_init.cpp
+@@ -103,9 +103,7 @@ void update_viewport(EmuEnvState &state) {
+ }
- // Create default preference path for safety
- if (!fs::exists(root_paths.get_pref_path()))
+ void init_paths(Root &root_paths) {
+- auto sdl_base_path = SDL_GetBasePath();
+- auto base_path = fs_utils::utf8_to_path(sdl_base_path);
+- SDL_free(sdl_base_path);
++ auto base_path = fs_utils::utf8_to_path("/storage/.config/vita3k/");
+
+ root_paths.set_base_path(base_path);
+ root_paths.set_static_assets_path(base_path);
+@@ -129,9 +127,7 @@ void init_paths(Root &root_paths) {
+ } else {
+ // SDL_GetPrefPath is deferred as it creates the directory.
+ // When using a portable directory, it is not needed.
+- auto sdl_pref_path = SDL_GetPrefPath(org_name, app_name);
+- auto pref_path = fs_utils::utf8_to_path(sdl_pref_path);
+- SDL_free(sdl_pref_path);
++ auto pref_path = fs_utils::utf8_to_path("/storage/psvita/vita3k/");
+
+ #if defined(__APPLE__)
+ // Store other data in the user-wide path. Otherwise we may end up dumping
diff --git a/packages/emulators/standalone/vita3k-sa/patches/003-drop-xdg-desktop-portals.patch b/packages/emulators/standalone/vita3k-sa/patches/003-drop-xdg-desktop-portals.patch
deleted file mode 100644
index a0effdc0d6..0000000000
--- a/packages/emulators/standalone/vita3k-sa/patches/003-drop-xdg-desktop-portals.patch
+++ /dev/null
@@ -1,596 +0,0 @@
-diff --git a/.gitmodules b/.gitmodules
-index e57fd159..bb5ed956 100644
---- a/.gitmodules
-+++ b/.gitmodules
-@@ -90,9 +90,9 @@
- [submodule "external/tracy"]
- path = external/tracy
- url = https://github.com/wolfpld/tracy.git
--[submodule "external/nativefiledialog-extended"]
-- path = external/nativefiledialog-extended
-- url = https://github.com/btzy/nativefiledialog-extended.git
-+[submodule "external/nativefiledialog-cmake"]
-+ path = external/nativefiledialog-cmake
-+ url = https://github.com/Vita3K/nativefiledialog-cmake
- [submodule "external/cubeb"]
- path = external/cubeb
- url = https://github.com/mozilla/cubeb.git
-diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt
-index d4dcfc94..4cb3e1ee 100644
---- a/external/CMakeLists.txt
-+++ b/external/CMakeLists.txt
-@@ -344,11 +344,20 @@ target_compile_definitions(tracy PUBLIC $<$:TRACY_E
- #
- # target_compile_definitions(tracy PUBLIC TRACY_ENABLE)
-
--# Use XDG desktop portals on Linux
--set(NFD_PORTAL ON)
-+# Create alias to prevent the need of multiple changes in case the target name changes
-+# Batocera - bring back nativefiledialog
-+if(UNIX)
-+ find_package(PkgConfig REQUIRED)
-+ pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
-
--# nativefiledialog-extended
--add_subdirectory(nativefiledialog-extended)
-+ include_directories(${GTK3_INCLUDE_DIRS})
-+ link_directories(${GTK3_LIBRARY_DIRS})
-+
-+ add_definitions(${GTK3_CFLAGS_OTHER})
-+
-+ add_library(nativefiledialog STATIC nativefiledialog-cmake/src/nfd_gtk.c nativefiledialog-cmake/src/nfd_common.c)
-+ target_include_directories(nativefiledialog PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/nativefiledialog-cmake/src/include")
-+ target_link_libraries(nativefiledialog ${GTK3_LIBRARIES})
-+endif()
-+set_property(TARGET nativefiledialog PROPERTY FOLDER externals)
-
--# Create alias to prevent the need of multiple changes in case the target name changes
--add_library(NFDe::NFDe ALIAS nfd)
-diff --git a/vita3k/CMakeLists.txt b/vita3k/CMakeLists.txt
-index e1b27dfd..25d8f88b 100644
---- a/vita3k/CMakeLists.txt
-+++ b/vita3k/CMakeLists.txt
-@@ -105,7 +105,6 @@ add_subdirectory(features)
- add_subdirectory(glutil)
- add_subdirectory(gui)
- add_subdirectory(gxm)
--add_subdirectory(host)
- add_subdirectory(ime)
- add_subdirectory(lang)
- add_subdirectory(net)
-diff --git a/vita3k/dir_doc.cpp b/vita3k/dir_doc.cpp
-index b66bbd98..28d5a6f4 100644
---- a/vita3k/dir_doc.cpp
-+++ b/vita3k/dir_doc.cpp
-@@ -115,12 +115,6 @@
- * @brief Vita's GXM low-level graphics API translation layer
- */
-
--/**
-- * @dir vita3k/host
-- *
-- * @brief Host operating system abstraction layer
-- */
--
- /**
- * @dir vita3k/io
- *
-diff --git a/vita3k/gui/CMakeLists.txt b/vita3k/gui/CMakeLists.txt
-index ef7de553..811ee661 100644
---- a/vita3k/gui/CMakeLists.txt
-+++ b/vita3k/gui/CMakeLists.txt
-@@ -51,5 +51,5 @@ add_library(
-
- target_include_directories(gui PUBLIC include ${CMAKE_SOURCE_DIR}/vita3k)
- target_link_libraries(gui PUBLIC app compat config dialog emuenv https ime imgui glutil lang regmgr np)
--target_link_libraries(gui PRIVATE audio ctrl kernel miniz psvpfsparser pugixml::pugixml stb renderer packages sdl2 touch vkutil host::dialog)
-+target_link_libraries(gui PRIVATE audio ctrl kernel miniz psvpfsparser pugixml::pugixml stb renderer packages sdl2 touch vkutil nativefiledialog)
- target_link_libraries(gui PUBLIC tracy)
-diff --git a/vita3k/gui/src/archive_install_dialog.cpp b/vita3k/gui/src/archive_install_dialog.cpp
-index 67832991..5d724637 100644
---- a/vita3k/gui/src/archive_install_dialog.cpp
-+++ b/vita3k/gui/src/archive_install_dialog.cpp
-@@ -19,7 +19,7 @@
- #include "private.h"
-
- #include
--#include
-+#include
- #include
-
- #include
-@@ -32,7 +33,7 @@ static bool delete_archive_file;
- static std::string state, type, title;
- static std::map> contents_archives;
- static std::vector invalid_archives;
--static std::filesystem::path archive_path = "";
-+static nfdchar_t *archive_path;
- static float global_progress = 0.f;
- static float archives_count = 0.f;
-
-@@ -104,20 +104,12 @@ void draw_archive_install_dialog(GuiState &gui, EmuEnvState &emuenv) {
- gui.file_menu.archive_install_dialog = false;
- } else {
- if (state.empty()) {
-- host::dialog::filesystem::Result result = host::dialog::filesystem::Result::CANCEL;
-- if (type == "file") {
-- // Set file filters for the file picking dialog
-- std::vector file_filters = {
-- { "PlayStation Vita commercial software package (NoNpDrm/FAGDec) / PlayStation Vita homebrew software package", { "zip", "vpk" } },
-- { "PlayStation Vita commercial software package (NoNpDrm/FAGDec)", { "zip" } },
-- { "PlayStation Vita homebrew software package", { "vpk" } },
-- };
-- // Call file picking dialog from the native file browser
-- result = host::dialog::filesystem::open_file(archive_path, file_filters);
-- } else {
-- result = host::dialog::filesystem::pick_folder(archive_path);
-- }
-- if (result == host::dialog::filesystem::Result::SUCCESS) {
-+ nfdresult_t result = NFD_CANCEL;
-+ if (type == "file")
-+ result = NFD_OpenDialog("zip,vpk", nullptr, &archive_path);
-+ else
-+ result = NFD_PickFolder(nullptr, &archive_path);
-+ if (result == NFD_OKAY) {
- state = "install";
- } else
- type.clear();
-@@ -133,7 +127,7 @@ void draw_archive_install_dialog(GuiState &gui, EmuEnvState &emuenv) {
- } else
- invalid_archives.push_back(archive_path);
- };
-- const auto contents_path = fs::path(archive_path.wstring());
-+ const auto contents_path = fs::path(string_utils::utf_to_wide(archive_path));
- if (type == "directory") {
- const auto archives_path = get_path_of_archives(contents_path);
- archives_count = float(archives_path.size());
-@@ -264,7 +258,7 @@ void draw_archive_install_dialog(GuiState &gui, EmuEnvState &emuenv) {
- for (const auto archive : invalid_archives)
- fs::remove(archive);
- }
-- archive_path = "";
-+ archive_path = nullptr;
- gui.file_menu.archive_install_dialog = false;
- delete_archive_file = false;
- contents_archives.clear();
-diff --git a/vita3k/gui/src/firmware_install_dialog.cpp b/vita3k/gui/src/firmware_install_dialog.cpp
-index 1b7208e6..f29150f7 100644
---- a/vita3k/gui/src/firmware_install_dialog.cpp
-+++ b/vita3k/gui/src/firmware_install_dialog.cpp
-@@ -19,18 +19,19 @@
-
- #include
- #include
--#include
- #include
- #include
- #include
-
-+#include
-+
- #include
-
- namespace gui {
-
- std::string fw_version;
- bool delete_pup_file;
--std::filesystem::path pup_path = "";
-+nfdchar_t *pup_path;
-
- static void get_firmware_version(EmuEnvState &emuenv) {
- fs::ifstream versionFile(emuenv.pref_path + L"/PUP_DEC/PUP/version.txt");
-@@ -46,7 +46,7 @@ static void get_firmware_version(EmuEnvState &emuenv) {
- }
-
- void draw_firmware_install_dialog(GuiState &gui, EmuEnvState &emuenv) {
-- host::dialog::filesystem::Result result = host::dialog::filesystem::Result::CANCEL;
-+ nfdresult_t result = NFD_CANCEL;
-
- static std::mutex install_mutex;
- static bool draw_file_dialog = true;
-@@ -62,23 +62,23 @@ void draw_firmware_install_dialog(GuiState &gui, EmuEnvState &emuenv) {
- std::lock_guard lock(install_mutex);
-
- if (draw_file_dialog) {
-- result = host::dialog::filesystem::open_file(pup_path, { { "PlayStation Vita Firmware Package", { "PUP" } } });
-+ result = NFD_OpenDialog("PUP", nullptr, &pup_path);
- draw_file_dialog = false;
- finished_installing = false;
-
-- if (result == host::dialog::filesystem::Result::SUCCESS) {
-+ if (result == NFD_OKAY) {
- std::thread installation([&emuenv]() {
-- install_pup(emuenv.pref_path, pup_path.string(), progress_callback);
-+ install_pup(emuenv.pref_path, pup_path, progress_callback);
- std::lock_guard lock(install_mutex);
- finished_installing = true;
- get_firmware_version(emuenv);
- });
- installation.detach();
-- } else if (result == host::dialog::filesystem::Result::CANCEL) {
-+ } else if (result == NFD_CANCEL) {
- gui.file_menu.firmware_install_dialog = false;
- draw_file_dialog = true;
- } else {
-- LOG_ERROR("Error initializing file dialog: {}", host::dialog::filesystem::get_error());
-+ LOG_ERROR("Error initializing file dialog: {}", NFD_GetError());
- gui.file_menu.firmware_install_dialog = false;
- draw_file_dialog = true;
- }
-@@ -117,7 +118,7 @@ void draw_firmware_install_dialog(GuiState &gui, EmuEnvState &emuenv) {
- ImGui::SetCursorPosX(ImGui::GetWindowWidth() / 2 - 30);
- if (ImGui::Button("OK", BUTTON_SIZE)) {
- if (delete_pup_file) {
-- fs::remove(fs::path(pup_path.wstring()));
-+ fs::remove(fs::path(string_utils::utf_to_wide(pup_path)));
- delete_pup_file = false;
- }
- if (emuenv.cfg.initial_setup)
-diff --git a/vita3k/gui/src/initial_setup.cpp b/vita3k/gui/src/initial_setup.cpp
-index 0bbe3548..e327c6cb 100644
---- a/vita3k/gui/src/initial_setup.cpp
-+++ b/vita3k/gui/src/initial_setup.cpp
-@@ -19,11 +19,12 @@
-
- #include
- #include
--#include
- #include
-
- #include
-
-+#include
-+
- namespace gui {
-
- enum InitialSetup {
-@@ -121,12 +122,12 @@ void draw_initial_setup(GuiState &gui, EmuEnvState &emuenv) {
- ImGui::TextWrapped("%s", emuenv.cfg.pref_path.c_str());
- ImGui::SetCursorPos(!is_default_path ? ImVec2((WINDOW_SIZE.x / 2.f) - BIG_BUTTON_SIZE.x - (20.f * SCALE.x), BIG_BUTTON_POS.y) : BIG_BUTTON_POS);
- if (ImGui::Button("Change Emulator Path", BIG_BUTTON_SIZE)) {
-- std::filesystem::path emulator_path = "";
-- host::dialog::filesystem::Result result = host::dialog::filesystem::pick_folder(emulator_path);
-+ nfdchar_t *emulator_path = nullptr;
-+ nfdresult_t result = NFD_PickFolder(nullptr, &emulator_path);
-
-- if ((result == host::dialog::filesystem::Result::SUCCESS) && (emulator_path.wstring() != emuenv.pref_path)) {
-- emuenv.pref_path = emulator_path.wstring() + L'/';
-- emuenv.cfg.pref_path = emulator_path.string();
-+ if ((result == NFD_OKAY) && (string_utils::utf_to_wide(emulator_path) != emuenv.pref_path)) {
-+ emuenv.pref_path = string_utils::utf_to_wide(emulator_path) + L'/';
-+ emuenv.cfg.pref_path = emulator_path;
- }
- }
- if (!is_default_path) {
-diff --git a/vita3k/gui/src/license_install_dialog.cpp b/vita3k/gui/src/license_install_dialog.cpp
-index beabedb8..7eb910a5 100644
---- a/vita3k/gui/src/license_install_dialog.cpp
-+++ b/vita3k/gui/src/license_install_dialog.cpp
-@@ -17,15 +17,15 @@
-
- #include "private.h"
-
--#include
- #include
- #include
- #include
-+#include
-
- namespace gui {
-
- static std::string state, title, zRIF;
--std::filesystem::path license_path = "";
-+nfdchar_t *license_path;
- static bool delete_license_file;
-
- void draw_license_install_dialog(GuiState &gui, EmuEnvState &emuenv) {
-@@ -67,10 +67,10 @@ void draw_license_install_dialog(GuiState &gui, EmuEnvState &emuenv) {
- if (ImGui::Button(common["cancel"].c_str(), BUTTON_SIZE))
- gui.file_menu.license_install_dialog = false;
- } else if (state == "license") {
-- host::dialog::filesystem::Result result = host::dialog::filesystem::Result::CANCEL;
-- result = host::dialog::filesystem::open_file(license_path, { { "PlayStation Vita software license file", { "bin", "rif" } } });
-- if (result == host::dialog::filesystem::Result::SUCCESS) {
-- if (copy_license(emuenv, fs::path(license_path.wstring())))
-+ nfdresult_t result = NFD_CANCEL;
-+ result = NFD_OpenDialog("bin,rif", nullptr, &license_path);
-+ if (result == NFD_OKAY) {
-+ if (copy_license(emuenv, license_path))
- state = "success";
- else
- state = "fail";
-@@ -105,12 +105,12 @@ void draw_license_install_dialog(GuiState &gui, EmuEnvState &emuenv) {
- ImGui::Spacing();
- ImGui::Separator();
- ImGui::Spacing();
-- if (license_path != "")
-+ if (license_path)
- ImGui::Checkbox(license["delete_bin_rif"].c_str(), &delete_license_file);
- ImGui::SetCursorPos(ImVec2(POS_BUTTON, ImGui::GetWindowSize().y - BUTTON_SIZE.y - (20.f * SCALE.y)));
- if (ImGui::Button(common["ok"].c_str(), BUTTON_SIZE)) {
- if (delete_license_file) {
-- fs::remove(fs::path(license_path.wstring()));
-+ fs::remove(fs::path(string_utils::utf_to_wide(std::string(license_path))));
- delete_license_file = false;
- }
- license_path = nullptr;
-diff --git a/vita3k/gui/src/pkg_install_dialog.cpp b/vita3k/gui/src/pkg_install_dialog.cpp
-index 75c11214..46fcf6f8 100644
---- a/vita3k/gui/src/pkg_install_dialog.cpp
-+++ b/vita3k/gui/src/pkg_install_dialog.cpp
-@@ -18,7 +18,6 @@
- #include "private.h"
-
- #include
--#include
- #include
- #include
- #include
-@@ -25,19 +25,18 @@
- #include
- #include
- #include
--
-+#include
- #include
-
- namespace gui {
-
--static std::filesystem::path pkg_path = "";
--static std::filesystem::path license_path = "";
-+static nfdchar_t *pkg_path, *license_path;
- static std::string state, title, zRIF;
- static bool draw_file_dialog = true;
- static bool delete_pkg_file, delete_license_file;
-
- void draw_pkg_install_dialog(GuiState &gui, EmuEnvState &emuenv) {
-- host::dialog::filesystem::Result result = host::dialog::filesystem::Result::CANCEL;
-+ nfdresult_t result = NFD_CANCEL;
- static std::atomic progress(0);
- static std::mutex install_mutex;
- static const auto progress_callback = [&](float updated_progress) {
-@@ -53,15 +53,15 @@ void draw_pkg_install_dialog(GuiState &gui, EmuEnvState &emuenv) {
- const auto BUTTON_SIZE = ImVec2(160.f * SCALE.x, 45.f * SCALE.y);
-
- if (draw_file_dialog) {
-- result = host::dialog::filesystem::open_file(pkg_path, { { "PlayStation Store Downloaded Package", { "pkg" } } });
-+ result = NFD_OpenDialog("pkg", nullptr, &pkg_path);
- draw_file_dialog = false;
-- if (result == host::dialog::filesystem::Result::SUCCESS)
-+ if (result == NFD_OKAY)
- ImGui::OpenPopup("install");
-- else if (result == host::dialog::filesystem::Result::CANCEL) {
-+ else if (result == NFD_CANCEL) {
- gui.file_menu.pkg_install_dialog = false;
- draw_file_dialog = true;
- } else {
-- LOG_ERROR("Error initializing file dialog: {}", host::dialog::filesystem::get_error());
-+ LOG_ERROR("Error initializing file dialog: {}", NFD_GetError());
- gui.file_menu.pkg_install_dialog = false;
- draw_file_dialog = true;
- }
-@@ -97,9 +96,9 @@ void draw_pkg_install_dialog(GuiState &gui, EmuEnvState &emuenv) {
- draw_file_dialog = true;
- }
- } else if (state == "license") {
-- result = host::dialog::filesystem::open_file(license_path, { { "PlayStation Vita software license file", { "bin", "rif" } } });
-- if (result == host::dialog::filesystem::Result::SUCCESS) {
-- fs::ifstream binfile(license_path.wstring(), std::ios::in | std::ios::binary | std::ios::ate);
-+ result = NFD_OpenDialog("bin,rif", nullptr, &license_path);
-+ if (result == NFD_OKAY) {
-+ fs::ifstream binfile(string_utils::utf_to_wide(std::string(license_path)), std::ios::in | std::ios::binary | std::ios::ate);
- zRIF = rif2zrif(binfile);
- state = "install";
- } else
-@@ -125,7 +125,7 @@ void draw_pkg_install_dialog(GuiState &gui, EmuEnvState &emuenv) {
- state = "install";
- } else if (state == "install") {
- std::thread installation([&emuenv]() {
-- if (install_pkg(pkg_path.string(), emuenv, zRIF, progress_callback)) {
-+ if (install_pkg(std::string(pkg_path), emuenv, zRIF, progress_callback)) {
- std::lock_guard lock(install_mutex);
- state = "success";
- } else {
-@@ -143,17 +142,17 @@ void draw_pkg_install_dialog(GuiState &gui, EmuEnvState &emuenv) {
- ImGui::Separator();
- ImGui::Spacing();
- ImGui::Checkbox(lang["delete_pkg"].c_str(), &delete_pkg_file);
-- if (license_path != "")
-+ if (license_path)
- ImGui::Checkbox(lang["delete_bin_rif"].c_str(), &delete_license_file);
- ImGui::Spacing();
- ImGui::SetCursorPos(ImVec2(POS_BUTTON, ImGui::GetWindowSize().y - BUTTON_SIZE.y - (20.f * SCALE.y)));
- if (ImGui::Button(common["ok"].c_str(), BUTTON_SIZE)) {
- if (delete_pkg_file) {
-- fs::remove(fs::path(pkg_path.wstring()));
-+ fs::remove(fs::path(string_utils::utf_to_wide(std::string(pkg_path))));
- delete_pkg_file = false;
- }
- if (delete_license_file) {
-- fs::remove(fs::path(license_path.wstring()));
-+ fs::remove(fs::path(string_utils::utf_to_wide(std::string(pkg_path))));
- delete_license_file = false;
- }
- if ((emuenv.app_info.app_category.find("gd") != std::string::npos) || (emuenv.app_info.app_category.find("gp") != std::string::npos)) {
-@@ -160,8 +160,8 @@ void draw_pkg_install_dialog(GuiState &gui, EmuEnvState &emuenv) {
- save_apps_cache(gui, emuenv);
- }
- update_notice_info(gui, emuenv, "content");
-- pkg_path = "";
-- license_path = "";
-+ pkg_path = nullptr;
-+ license_path = nullptr;
- gui.file_menu.pkg_install_dialog = false;
- draw_file_dialog = true;
- state.clear();
-@@ -175,7 +175,7 @@ void draw_pkg_install_dialog(GuiState &gui, EmuEnvState &emuenv) {
- ImGui::SetCursorPos(ImVec2(POS_BUTTON, ImGui::GetWindowSize().y - BUTTON_SIZE.y - (20.f * SCALE.y)));
- if (ImGui::Button("OK", BUTTON_SIZE)) {
- gui.file_menu.pkg_install_dialog = false;
-- pkg_path = "";
-+ pkg_path = nullptr;
- draw_file_dialog = true;
- work_path = "";
- state.clear();
-diff --git a/vita3k/gui/src/settings.cpp b/vita3k/gui/src/settings.cpp
-index 72ffabdb..7a6f4265 100644
---- a/vita3k/gui/src/settings.cpp
-+++ b/vita3k/gui/src/settings.cpp
-@@ -20,7 +20,6 @@
- #include
- #include
- #include
--#include
- #include
- #include
- #include
-@@ -29,6 +28,7 @@
- #include
- #include
-
-+#include
- #include
- #include
-
-@@ -581,11 +581,11 @@ void draw_settings(GuiState &gui, EmuEnvState &emuenv) {
- sub_menu.clear();
- }
- } else if (sub_menu == "image") {
-- std::filesystem::path image_path = "";
-- host::dialog::filesystem::Result result = host::dialog::filesystem::open_file(image_path, { { "Image file", { "bmp", "gif", "jpg", "png", "tif" } } });
-+ nfdchar_t *image_path;
-+ nfdresult_t result = NFD_OpenDialog("bmp,gif,jpg,png,tif", nullptr, &image_path);
-
-- if ((result == host::dialog::filesystem::Result::SUCCESS) && init_user_start_background(gui, image_path.string())) {
-- gui.users[emuenv.io.user_id].start_path = image_path.string();
-+ if ((result == NFD_OKAY) && init_user_start_background(gui, image_path)) {
-+ gui.users[emuenv.io.user_id].start_path = image_path;
- gui.users[emuenv.io.user_id].start_type = "image";
- save_user(gui, emuenv, emuenv.io.user_id);
- }
-@@ -641,12 +641,12 @@ void draw_settings(GuiState &gui, EmuEnvState &emuenv) {
- ImGui::NextColumn();
- }
- if (ImGui::Selectable(theme_background.home_screen_backgrounds["add_background"].c_str(), false, ImGuiSelectableFlags_None, SIZE_PACKAGE)) {
-- std::filesystem::path background_path = "";
-- host::dialog::filesystem::Result result = host::dialog::filesystem::open_file(background_path, { { "Image file", { "bmp", "gif", "jpg", "png", "tif" } } });
-+ nfdchar_t *background_path;
-+ nfdresult_t result = NFD_OpenDialog("bmp,gif,jpg,png,tif", nullptr, &background_path);
-
-- if ((result == host::dialog::filesystem::Result::SUCCESS) && (!gui.user_backgrounds.contains(background_path.string()))) {
-- if (init_user_background(gui, emuenv, background_path.string())) {
-- gui.users[emuenv.io.user_id].backgrounds.push_back(background_path.string());
-+ if ((result == NFD_OKAY) && (gui.user_backgrounds.find(background_path) == gui.user_backgrounds.end())) {
-+ if (init_user_background(gui, emuenv, background_path)) {
-+ gui.users[emuenv.io.user_id].backgrounds.push_back(background_path);
- gui.users[emuenv.io.user_id].use_theme_bg = false;
- save_user(gui, emuenv, emuenv.io.user_id);
- }
-diff --git a/vita3k/gui/src/settings_dialog.cpp b/vita3k/gui/src/settings_dialog.cpp
-index 37c05f1c..73dc08c3 100644
---- a/vita3k/gui/src/settings_dialog.cpp
-+++ b/vita3k/gui/src/settings_dialog.cpp
-@@ -21,7 +21,6 @@
- #include
- #include
- #include
--#include
- #include
- #include
- #include
-@@ -43,6 +42,7 @@
- #include
-
- #include
-+#include
- #include
- #include
-
-@@ -105,12 +105,12 @@ static void reset_emulator(GuiState &gui, EmuEnvState &emuenv) {
- }
-
- static void change_emulator_path(GuiState &gui, EmuEnvState &emuenv) {
-- std::filesystem::path emulator_path = "";
-- host::dialog::filesystem::Result result = host::dialog::filesystem::pick_folder(emulator_path);
-+ nfdchar_t *emulator_path = nullptr;
-+ nfdresult_t result = NFD_PickFolder(nullptr, &emulator_path);
-
-- if (result == host::dialog::filesystem::Result::SUCCESS && emulator_path.wstring() != emuenv.pref_path) {
-+ if (result == NFD_OKAY && string_utils::utf_to_wide(emulator_path) != emuenv.pref_path) {
- // Refresh the working paths
-- emuenv.pref_path = emulator_path.wstring() + L'/';
-+ emuenv.pref_path = string_utils::utf_to_wide(emulator_path) + L'/';
-
- // TODO: Move app old to new path
- reset_emulator(gui, emuenv);
-diff --git a/vita3k/gui/src/trophy_collection.cpp b/vita3k/gui/src/trophy_collection.cpp
-index 85854dc3..97193c7d 100644
---- a/vita3k/gui/src/trophy_collection.cpp
-+++ b/vita3k/gui/src/trophy_collection.cpp
-@@ -26,6 +26,7 @@
- #include
- #include
-
-+#include
- #include
- #include
-
-diff --git a/vita3k/gui/src/user_management.cpp b/vita3k/gui/src/user_management.cpp
-index e1d23bfb..f0b8a935 100644
---- a/vita3k/gui/src/user_management.cpp
-+++ b/vita3k/gui/src/user_management.cpp
-@@ -24,13 +24,13 @@
-
- #include
- #include
--#include
- #include
- #include
-
- #include
- #include
-
-+#include
- #include
- #include
-
-@@ -373,11 +373,11 @@ void draw_user_management(GuiState &gui, EmuEnvState &emuenv) {
- const auto CHANGE_AVATAR_BTN_SIZE = ImGui::CalcTextSize(lang["change_avatar"].c_str()).x + (ImGui::GetStyle().FramePadding.x * 2.f);
- ImGui::SetCursorPos(ImVec2(AVATAR_POS.x + (AVATAR_SIZE.x / 2.f) - (CHANGE_AVATAR_BTN_SIZE / 2.f), AVATAR_POS.y + AVATAR_SIZE.y));
- if (ImGui::Button(lang["choose_avatar"].c_str(), CHANGE_AVATAR_BTN_SIZE)) {
-- std::filesystem::path avatar_path = "";
-- host::dialog::filesystem::Result result = host::dialog::filesystem::open_file(avatar_path, { { "Image file", { "bmp", "gif", "jpg", "png", "tif" } } });
-+ nfdchar_t *avatar_path;
-+ nfdresult_t result = NFD_OpenDialog("bmp,gif,jpg,png,tif", nullptr, &avatar_path);
-
-- if ((result == host::dialog::filesystem::Result::SUCCESS) && init_avatar(gui, emuenv, "temp", avatar_path.string()))
-- temp.avatar = avatar_path.string();
-+ if ((result == NFD_OKAY) && init_avatar(gui, emuenv, "temp", avatar_path))
-+ temp.avatar = avatar_path;
- }
- ImGui::SetWindowFontScale(0.8f);
- const auto INPUT_NAME_SIZE = 330.f * SCALE.x;
-diff --git a/vita3k/host/CMakeLists.txt b/vita3k/host/CMakeLists.txt
-deleted file mode 100644
-index f9d89128..00000000
---- a/vita3k/host/CMakeLists.txt
-+++ /dev/null
-@@ -1 +0,0 @@
--add_subdirectory(dialog)
-diff --git a/vita3k/host/dialog/CMakeLists.txt b/vita3k/host/dialog/CMakeLists.txt
-deleted file mode 100644
-index d577a152..00000000
---- a/vita3k/host/dialog/CMakeLists.txt
-+++ /dev/null
-@@ -1,11 +0,0 @@
--add_library(host_dialog STATIC
-- src/filesystem.cpp
--)
--
--# Create alias for more friendly naming and avoid conflicts
--# in global CMake scope
--add_library(host::dialog ALIAS host_dialog)
--
--target_include_directories(host_dialog PUBLIC include)
--
--target_link_libraries(host_dialog PRIVATE NFDe::NFDe)
diff --git a/packages/emulators/standalone/vita3k-sa/patches/004-fix-link-error.patch b/packages/emulators/standalone/vita3k-sa/patches/004-fix-link-error.patch
index ce6d21857f..be1ff84d8c 100644
--- a/packages/emulators/standalone/vita3k-sa/patches/004-fix-link-error.patch
+++ b/packages/emulators/standalone/vita3k-sa/patches/004-fix-link-error.patch
@@ -1,12 +1,15 @@
-diff --git a/vita3k/https/CMakeLists.txt b/vita3k/https/CMakeLists.txt
-index f64456bd..e9555080 100644
---- a/vita3k/https/CMakeLists.txt
-+++ b/vita3k/https/CMakeLists.txt
-@@ -6,5 +6,6 @@ add_library(
- )
-
- target_include_directories(https PUBLIC include)
--target_include_directories(https PRIVATE ${OPENSSL_INCLUDE_DIR})
-+target_include_directories(https PRIVATE crypto ssl)
- target_link_libraries(https PUBLIC util)
-+target_link_libraries(https PRIVATE crypto ssl)
+diff --git a/vita3k/CMakeLists.txt b/vita3k/CMakeLists.txt
+index 04177f04..4adb1e0b 100644
+--- a/vita3k/CMakeLists.txt
++++ b/vita3k/CMakeLists.txt
+@@ -136,10 +136,6 @@ if(USE_DISCORD_RICH_PRESENCE)
+ target_link_libraries(vita3k PRIVATE discord-rpc)
+ endif()
+
+-if(LINUX)
+- target_link_libraries(vita3k PRIVATE -static-libgcc -static-libstdc++)
+-endif()
+-
+ set_target_properties(vita3k PROPERTIES OUTPUT_NAME Vita3K
+ ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
diff --git a/packages/emulators/standalone/vita3k-sa/scripts/scan_vita3k.sh b/packages/emulators/standalone/vita3k-sa/scripts/scan_vita3k.sh
new file mode 100755
index 0000000000..2ce1036c7f
--- /dev/null
+++ b/packages/emulators/standalone/vita3k-sa/scripts/scan_vita3k.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2022-present JELOS (https://github.com/JustEnoughLinuxOS)
+
+. /etc/profile
+
+GAME_PATH="/storage/psvita/vita3k/ux0/app"
+GAME_DATA="/storage/.config/vita3k/vita-gamelist.txt"
+OUTPUT_PATH="/storage/.config/vita3k/launcher"
+
+cd ${GAME_PATH}
+for GAME in PC*
+do
+ FILENAME=$(grep ${GAME} ${GAME_DATA} | sed 's~'${GAME}'\t~~g')
+ if [ ! -e "${OUTPUT_PATH}/${FILENAME}.psvita" ] && \
+ [ -n "${FILENAME}" ]
+ then
+ echo ${GAME} > ${OUTPUT_PATH}/"${FILENAME}.psvita"
+ fi
+done
diff --git a/packages/emulators/standalone/vita3k-sa/scripts/start_vita3k.sh b/packages/emulators/standalone/vita3k-sa/scripts/start_vita3k.sh
old mode 100644
new mode 100755
index 415e268cf6..4e6bf7b9d5
--- a/packages/emulators/standalone/vita3k-sa/scripts/start_vita3k.sh
+++ b/packages/emulators/standalone/vita3k-sa/scripts/start_vita3k.sh
@@ -6,16 +6,26 @@
. /etc/profile
jslisten set "-9 Vita3K"
+OUTPUT_PATH="/storage/.config/vita3k/launcher"
+GAME="${1}"
+
#Check if vita3k folder exists in /storage/.config/vita3k
if [ ! -d "/storage/.config/vita3k" ]; then
mkdir -p "/storage/.config/vita3k"
- cp -r "/usr/config/vita3k" "/storage/.config/"
fi
+#Make sure we sync any changes from /storage/.config so new features will be enabled
+#without overwriting existing settings.
+rsync -ah --update /usr/config/vita3k/* /storage/.config/vita3k 2>/dev/null
+
#Check if vita3k folder exists in /storage/roms/psvita
if [ ! -d "/storage/roms/psvita/vita3k" ]; then
mkdir -p "/storage/roms/psvita/vita3k"
fi
+if [ -n "${GAME}" ]; then
+ OPTIONS="-r $(cat "${GAME}")"
+fi
+
#Start Vita3K
-/usr/bin/Vita3K
+/usr/bin/Vita3K ${OPTIONS}
diff --git a/packages/emulators/standalone/vita3k-sa/sources/vita-gamelist.txt b/packages/emulators/standalone/vita3k-sa/sources/vita-gamelist.txt
new file mode 100644
index 0000000000..4eb1d5bcb5
--- /dev/null
+++ b/packages/emulators/standalone/vita3k-sa/sources/vita-gamelist.txt
@@ -0,0 +1,2055 @@
+PCSE00965 #KILLALLZOMBIES
+PCSG00891 √Letter
+PCSE00963 √Letter
+PCSB01019 √Letter
+PCSE00890 10 Second Ninja X
+PCSB00963 10 Second Ninja X
+PCSE00349 1001 Spikes
+PCSE00634 2013: Infected Wars
+PCSE00972 2064: Read Only Memories
+PCSE01169 36 Fragments of Midnight
+PCSG00590 5-nin no Koi Prince: Himitsu no Keiyaku Kekkon
+PCSE01168 7'scarlet
+PCSH10090 7'scarlet
+PCSG00876 7'scarlet
+PCSE00914 99Vidas
+PCSE01167 99vidas - Demo
+PCSE00726 A Boy and His Blob
+PCSH10075 A Certain Magical Virtual-On
+PCSG00505 A Good Librarian Like a Good Shepherd -Library Party-
+PCSE01095 A Hole New World
+PCSB01095 A Rose in the Twilight
+PCSE01046 A Rose in the Twilight
+PCSB00955 A Virus Named TOM
+PCSE00501 A Virus Named TOM
+PCSE01389 A Winter's Daydream
+PCSE00232 A-men
+PCSB00056 A-men
+PCSE00324 A-men 2
+PCSB00222 A-men 2
+PCSB00154 A-men Demo
+PCSB00898 A.O.T. Wings of Freedom
+PCSB00960 A.W. : Phoenix Festa
+PCSE00871 A.W. : Phoenix Festa
+PCSE00278 Aabs Animals
+PCSG00591 Abunai Koi no Sousashitsu: Eternal Happiness
+PCSB00792 AC® Chronicles
+PCSE00700 AC® Chronicles
+PCSB01101 Accel World vs. Sword Art Online
+PCSE01071 Accel World vs. Sword Art Online
+PCSG01016 Accel World vs. Sword Art Online
+PCSE01356 Access Denied
+PCSE01448 Active Neurons
+PCSB01008 Active Soccer 2 DX
+PCSB00858 Actual Sunlight
+PCSE00695 Actual Sunlight
+PCSE00582 Adventure Time: the Secret of the Nameless Kingdom
+PCSE00905 Adventures of Mana
+PCSB00975 Adventures of Mana
+PCSG90182 Aegis of Earth Demo
+PCSE00844 Aegis of Earth: Protonovus Assault
+PCSG00362 Aegis of Earth: Protonovus Assault
+PCSG01296 Aerial Life
+PCSE00628 AeternoBlade
+PCSG00483 AeternoBlade
+PCSB00732 AeternoBlade Demo
+PCSE00636 AeternoBlade Demo
+PCSB00412 Age of Zombies
+PCSE00362 Age of Zombies
+PCSG01325 Ai Kiss
+PCSG00940 AIR
+PCSE00980 Air Race Speed
+PCSG00461 Airship Q
+PCSG00338 Aiyoku no Eustia: Angel’s Blessing
+PCSG00780 Akai Suna Ochiru Tsuki
+PCSE00927 Akiba's Beat
+PCSB01066 AKIBA'S BEAT
+PCSG00159 AKIBA'S TRIP 2
+PCSH00057 AKIBA'S TRIP 2
+PCSE00428 AKIBA'S TRIP UNDEAD & UNDRESSED
+PCSG90191 ALIA's CARNIVAL! Sacramento Trial
+PCSE00210 Alien Breed
+PCSE00445 Alien Shooter
+PCSB00964 Alone With You
+PCSE00887 Alone With You
+PCSB01457 Alphaset by POWGI
+PCSH10271 Alphaset by POWGI
+PCSE01493 Alphaset by POWGI
+PCSB01187 Alteric
+PCSG01243 Alvastia Chronicles
+PCSG01086 Amaekata wa Kanojo Nari ni.
+PCSG01293 Amamane
+PCSG00638 Amatsumi Sora ni! Kumo no Hatate ni
+PCSG01138 Amenity's Life
+PCSG90299 Amenity's Life -アメニティーズ ライフ- 体験版
+PCSG00403 AMNESIA LATER×CROWD V Edition
+PCSB00740 Amnesia Memories
+PCSG00203 AMNESIA V Edition
+PCSG00276 AMNESIA World
+PCSE00647 Amnesia: Memories
+PCSG00696 Angelique Retour
+PCSE00322 Angry Birds Trilogy
+PCSB00397 Angry Birds™ Star Wars
+PCSE00294 Angry Birds™ Star Wars
+PCSG00342 Anoko wa Ore Kara Hanarenai
+PCSE00472 Another World - 20th Anniversary Edition
+PCSE01147 Antiquia Lost
+PCSG00700 Ao no Kanata Four Rhythm
+PCSG90180 Ao no Kanata no Four Rhythm Trial Version
+PCSG01281 Aoki Tsubasa no Chevalier
+PCSG01283 Aonatsu Line
+PCSG00848 Aqua Kitty - Milk Mine Defender DX
+PCSB00798 Ar nosurge Plus: Ode to an Unborn Star
+PCSE00707 AR Nosurge Plus: Ode to an Unborn Star
+PCSG00751 Arcana Famiglia -La storia della Arcana Famiglia- Ancora
+PCSE00427 Arcana Heart 3 LOVE MAX!!!!!
+PCSG00328 Arcana Heart 3: LOVE MAX!!!!!
+PCSB00050 Army Corps of Hell
+PCSE00006 ARMY CORPS OF HELL
+PCSE01379 Asdivine Dios
+PCSE00968 Asdivine Hearts
+PCSE01335 Asdivine Hearts II
+PCSE01419 Asdivine Menace
+PCSE00007 Asphalt: Injection
+PCSG00116 Assassin's Creed® III Lady Liberty
+PCSB00074 Assassin's Creed® III Liberation
+PCSE00053 Assassin's Creed® III Liberation
+PCSG90030 Assault Army
+PCSG90032 Assault Gunners Trial Version
+PCSG00901 AstralAir no Shiroki Towa: White Eternity
+PCSG90248 AstralAir no Shiroki Towa: White Eternity Trial Version
+PCSE01333 Atari Flashback Classics
+PCSE00584 Atelier Ayesha Plus ~The Alchemist of Dusk~
+PCSB00700 Atelier Ayesha Plus ~The Alchemist of Dusk~
+PCSG00347 Atelier Ayesha Plus: The Alchemist of Dusk
+PCSB00906 Atelier Escha & Logy Plus ~Alchemists of the Dusk Sky~
+PCSG00522 Atelier Escha & Logy Plus: Alchemists of the Dusk Sky
+PCSE00826 Atelier Escha & Logy Plus: Alchemists of the Dusk Sky
+PCSB01087 Atelier Firis ~The Alchemist and the Mysterious Journey~
+PCSE01044 Atelier Firis ~The Alchemist and the Mysterious Journey~
+PCSH10026 Atelier Firis ~The Alchemist and the Mysterious Journey~
+PCSG00929 Atelier Firis: The Alchemist of the Mysterious Journey
+PCSG01116 Atelier Lydie & Suelle: The Alchemists and the Mysterious Paintings
+PCSE00296 Atelier Meruru Plus: The Apprentice of Arland
+PCSB00377 Atelier Meruru Plus: The Apprentice of Arland
+PCSG00171 Atelier Meruru Plus: The Apprentice of Arland
+PCSG01223 Atelier Nelke: The Alchemists and the New Earth
+PCSE00466 Atelier Rorona Plus ~The Alchemist of Arland~
+PCSB00582 Atelier Rorona Plus ~The Alchemist of Arland~
+PCSG00245 Atelier Rorona Plus: The Alchemist of Arland
+PCSE00998 Atelier Shallie Plus - Alchemists of the Dusk Sea
+PCSG00821 Atelier Shallie Plus ~Alchemists of the Dusk Sea~
+PCSB01043 Atelier Shallie Plus ~Alchemists of the Dusk Sea~
+PCSE00892 Atelier Sophie ~The Alchemist of the Mysterious Book~
+PCSB00973 Atelier Sophie ~The Alchemist of the Mysterious Book~
+PCSG00694 Atelier Sophie: The Alchemist of the Mysterious Book
+PCSH00220 Atelier Sophie: The Alchemist of the Mysterious Book
+PCSH00231 Atelier Sophie: The Alchemist of the Mysterious Book
+PCSE00231 Atelier Totori Plus: The Adventurer of Arland
+PCSG00127 Atelier Totori Plus: The Adventurer of Arland
+PCSB00291 Atelier Totori Plus: The Adventurer of Arland
+PCSB00274 Atomic Ninjas
+PCSE00274 Atomic Ninjas
+PCSG00762 Attack on Titan
+PCSE00812 Attack on Titan
+PCSG01102 Attack on Titan 2
+PCSE00780 Attractio
+PCSE01367 Awesome Pea
+PCSE01474 Awesome Pea 2
+PCSB00779 Axiom Verge
+PCSG00666 Ayakashi Gohan: Oomori!
+PCSG01175 Azayaka na Irodori no Naka de, Kimi Rashiku
+PCSE00861 Azkend 2: The World Beneath
+PCSG00711 Baboon!
+PCSE01343 Back in 1995
+PCSE00706 Back to Bed
+PCSB00468 Backgammon Blitz
+PCSB01092 Bad Apple Wars
+PCSE01042 Bad Apple Wars
+PCSB00669 BADLAND: Game of the Year Edition
+PCSG00425 Bakumatsu Rock: Ultra Soul
+PCSB01406 Balthazar's Dream
+PCSG01123 Banbutsu Otome * Dungeons
+PCSG00708 Bara ni Kakusareshi Verite
+PCSG01006 Bard's Gold
+PCSB00911 Baseball Riot
+PCSE00790 Bastion
+PCSB00353 Batman: Arkham Origins Blackgate
+PCSE00444 Battalion Commander
+PCSE01478 Battle Rockets
+PCSG00244 Beast Tamer and Prince
+PCSG00604 Beast Tamer and Prince ~Flower & Snow~
+PCSG00539 Believer!
+PCSE00024 Ben 10™ Galactic Racing
+PCSG01221 Beniiro Tenjou Ayakashi Kitan Futaai
+PCSF00251 Bentley's Hackpack™
+PCSB01085 BERSERK and the Band of the Hawk
+PCSE00377 Best of Arcade Games
+PCSB00648 Best Of Arcade Games (FULL)
+PCSE01495 Big Dipper
+PCSE00091 Big Sky Infinity
+PCSF00351 BigFest™
+PCSG00389 Binary Star
+PCSB01105 Bit Dungeon Plus
+PCSE00302 BIT.TRIP Presents... Runner2: Future Legend of Rhythm Alien
+PCSG90096 Bitter Smile Trial
+PCSG00242 Bitter smile.
+PCSG00468 black butterfly psychedelia
+PCSG00935 BLACK WOLVES SAGA -Weiβ und Schwarz-
+PCSB00420 Blast 'Em Bunnies
+PCSG00180 BLAZBLUE CHRONOPHANTASMA
+PCSG00582 BLAZBLUE CHRONOPHANTASMA EXTEND
+PCSB00042 BlazBlue Continuum Shift Extend
+PCSG00003 BLAZBLUE CONTINUUM SHIFT EXTEND
+PCSE00279 BlazBlue: ChronoPhantasma
+PCSE00677 BlazBlue: Chronophantasma Extend
+PCSE00018 BlazBlue: Continuum Shift EXTEND
+PCSE01457 Blind Men
+PCSB01250 Bloodstained: Curse of the Moon
+PCSE00663 Bloxiq
+PCSG00987 BLUE REFLECTION(幻に舞う少女の剣)
+PCSE00864 Blue-Collar Astronaut
+PCSE01019 Bodycheck
+PCSG01205 Boku to Nurse no Kenshuu Nisshi
+PCSG00797 Boku wa Mori Sekai no Kami Tonaru
+PCSB00741 Bombing Busters
+PCSE01368 Bonds of the Skies
+PCSG00259 BOOLINK
+PCSF00570 Borderlands 2
+PCSE00383 Borderlands 2
+PCSE00604 Boss
+PCSE01349 Bouncy Bullets
+PCSE00641 Breach & Clear
+PCSE00225 BreakQuest: Extra Evolution
+PCSB00265 BreakQuest: Extra Evolution
+PCSE01429 Breeder Homegrown
+PCSE00869 Bridge Constructor
+PCSE00657 Broken Age
+PCSE01517 Brotherhood United
+PCSG00755 BROTHERS CONFLICT Precious Baby
+PCSE01455 Bucket Knight
+PCSG00361 Bullet Girls
+PCSG00568 Bullet Girls 2
+PCSH10099 Bullet Girls Phantasia
+PCSB01110 Bunny Must Die! Chelsea and the 7 devils
+PCSG90261 Bunny Must Die! Chelsea and the 7devils. Trial version
+PCSH10053 BURIED STARS
+PCSE01135 Burly Men At Sea
+PCSE00117 Burn the Rope
+PCSG01197 Cafe Cuillere
+PCSB00213 Call of Duty: Black Ops: Declassified
+PCSG00135 Call of Duty® Black Ops: Declassified
+PCSE00097 Call of Duty® Black Ops: Declassified
+PCSB00232 Call of Duty® Black Ops: Declassified
+PCSG00450 Captain Earth: Mind Labyrinth
+PCSE00946 Castle Invasion: Throne Out
+PCSB00111 CastleStorm
+PCSG01179 Catherine: Full Body
+PCSG90323 Catherine: Full Body Trial Verison
+PCSH00099 CatsBlock Vestival
+PCSB00573 Cel Damage HD
+PCSE00422 Cel Damage HD
+PCSG00409 Chain Chronicle V
+PCSG00497 Chaos Rings I
+PCSG00498 Chaos Rings II
+PCSG00500 Chaos Rings III
+PCSG00457 Chaos Rings III Prequel Trilogy
+PCSG00499 Chaos Rings Ω
+PCSE01022 Chaos;Child
+PCSG00555 Chaos;Child
+PCSB01075 CHAOS;CHILD
+PCSG90169 Chaos;Child Demo
+PCSG00995 Chaos;Child: Love Chuchu!!
+PCSG00411 Chaos;Head Dual
+PCSG00435 Chaos;Head Love Chu*Chu!
+PCSG00434 Chaos;Head Noah
+PCSG01150 Charade Maniacs
+PCSE01031 Chasm
+PCSB01233 Chicken Range
+PCSB00598 Child of Light
+PCSE00480 Child of Light
+PCSG00850 Chou Ezaru wa Akai Hana: Koi wa Tsuki ni Shirube Kareru
+PCSG00644 Chou Jigen Taisen Neptune VS Sega Hard Girls: Yume no Gattai Special
+PCSG00234 Chou Megami Shinkou Noire: Gekishin Black Heart
+PCSG00274 Chou no Doku Hana no Kusari Taishou Tsuyakoi Ibun
+PCSG01066 Chouchou Jiken Rhapsodic
+PCSE00044 Chronovolt
+PCSB00102 Chronovolt
+PCSE01281 Chronus Arc
+PCSG00540 ChuSingura46+1 -忠臣蔵46+1- V
+PCSG00454 Ciel Nosurge: Ushinawareta Hoshi e Sasagu Uta
+PCSG00705 Citizens of Earth
+PCSB00686 Citizens of Earth Demo
+PCSE00562 Citizens of Earth Demo
+PCSG00729 ClaDun Returns: This is Sengoku!
+PCSE00999 ClaDun Returns: This is Sengoku!
+PCSE01017 Cladun Returns: This is Sengoku! Demo
+PCSB01067 Cladun Returns: This is Sengoku! Demo
+PCSG90212 Cladun Returns: This is Sengoku! Trial Version
+PCSG00415 CLANNAD
+PCSA00038 Cliff Diving
+PCSG00469 Clock Zero ~Shuuen no Ichibyou~ ExTime
+PCSG00716 Clover Day's ~Making for Happiness.~
+PCSB00303 Coconut Dodge Revitalised
+PCSE00267 Coconut Dodge Revitalised
+PCSB01099 Code: Realize ~Future Blessings~
+PCSE00763 Code: Realize ~Guardian of Rebirth~
+PCSG01110 Code: Realize ~Silver Miracle~
+PCSG00805 Code: Realize ~The Future of Blessings~
+PCSE01278 Code:Realize ~Wintertide Miracles~
+PCSE01011 Collar x Malice
+PCSB01061 Collar×Malice
+PCSB00768 Color Guardians
+PCSE00612 Color Guardians
+PCSE01423 Color Slayer
+PCSE00123 Colors!
+PCSE00376 CONCEPTION II: Children of the Seven Stars
+PCSB00547 Conception II: Children of the Seven Stars Demo
+PCSE00425 Conception II: Children of the Seven Stars Demo
+PCSG90087 Conception II: Children of the Seven Stars Demo
+PCSG90092 Conception II: Children of the Seven Stars Demo
+PCSE01406 Conga Master Go
+PCSB01445 Contraptions
+PCSB00822 Corpse Party BLOOD DRIVE
+PCSE00708 Corpse Party BLOOD DRIVE
+PCSG00298 Corpse Party: Blood Drive
+PCSB00840 Corridor Z
+PCSE00854 Corridor Z
+PCSE01232 CosmicStarHeroine
+PCSB00734 Cosmophony
+PCSA00116 Counterspy
+PCSG01246 Coven and Labyrinth of Galleria
+PCSE00222 CRACKLE
+PCSG00941 Crank In
+PCSG90290 Crank In Trial Version
+PCSE00291 Crazy Market
+PCSE00916 Criminal Girls 2 Party Favors
+PCSB00984 Criminal Girls 2 Party Favors
+PCSG00681 Criminal Girls 2: Party Favors
+PCSE00516 Criminal Girls: Invite Only
+PCSB00636 Criminal Girls: Invite Only
+PCSE00453 Crimsonland
+PCSG00537 Croixleur Sigma
+PCSE00689 Croixleur Sigma
+PCSG00597 Cross Ange: Rondo of Angels and Dragons tr.
+PCSG00365 CROSS†CHANNEL ~For all people~
+PCSB01331 Crossovers by POWGI
+PCSH10175 Crossovers by POWGI
+PCSE01377 Crossovers by POWGI
+PCSE00806 Crypt of the NecroDancer
+PCSE01464 Crypto by POWGI
+PCSB01432 Crypto by POWGI
+PCSH10240 Crypto by POWGI
+PCSG00169 Cure Mate Club
+PCSE01152 Cursed Castilla (Maldita Castilla EX)
+PCSB01160 Cursed Castilla (Maldita Castilla EX)
+PCSB00853 Curses 'N Chaos
+PCSG01122 D.S.-Dal Segno-
+PCSE01348 Daggerhood
+PCSG00264 Dai-3-Ji Super Robot Taisen Z Jigoku-hen
+PCSG00494 Dai-3-Ji Super Robot Taisen Z Tengoku-hen
+PCSG00372 Daisenryaku Exceed II
+PCSG00779 Daisenryaku Perfect: Senjou no Hasha
+PCSG00504 Daisenryaku: Dai Toua Kouboushi 3
+PCSG00842 Damascus Gear Saikyou Exodus
+PCSE00518 Damascus Gear: Operation Tokyo
+PCSG00292 Damascus Gear: Operation Tokyo
+PCSG90109 Damascus Gear: Operation Tokyo
+PCSG00077 Danball Senki W Release
+PCSG00807 Dance with Devils
+PCSG01152 Dance with Devils My Carol
+PCSG00202 Danganronpa 1&2 Reload
+PCSE00399 Danganronpa 2: Goodbye Despair
+PCSB00514 Danganronpa 2: Goodbye Despair
+PCSE00692 Danganronpa Another Episode: Ultra Despair Girls
+PCSB00788 Danganronpa Another Episode: Ultra Despair Girls
+PCSG00772 Danganronpa Another Episode: Ultra Despair Girls
+PCSE01100 Danganronpa V3: Killing Harmony
+PCSE01105 Danganronpa V3: Killing Harmony Demo
+PCSH10052 Danganronpa V3: Killing Harmony Demo version
+PCSB01130 Danganronpa V3: Killing Harmony Demo version
+PCSE00261 Danganronpa: Trigger Happy Havoc
+PCSB00346 Danganronpa: Trigger Happy Havoc
+PCSG01002 Danjon ni Deai o Motomeru no wa Machigatteiru Darou ka? Infinite Combate
+PCSG01017 Daredemo Shodan ni Nareru Igo Kyoushitsu
+PCSE00792 DARIUSBURST Chronicle Saviours
+PCSE00919 Darkest Dungeon
+PCSG00599 Date-A-Live Twin Edition: Rio Reincarnation
+PCSB00540 Day D Tower Rush
+PCSB00747 Day of the Tentacle Remastered
+PCSE01181 Dead Ahead: Zombie Warfare
+PCSA00151 Dead Nation™
+PCSB00296 DEAD OR ALIVE 5 PLUS
+PCSG00167 DEAD OR ALIVE 5 PLUS
+PCSG00771 Dead Or Alive Xtreme 3 Venus
+PCSH00250 DEAD OR ALIVE Xtreme 3 Venus
+PCSH00281 DEAD OR ALIVE Xtreme 3 Venus Free-to-Play Version
+PCSE00578 Deadman's Cross
+PCSE01279 Death Mark
+PCSE00248 Deathmatch Village
+PCSE00401 Deception IV: Blood Ties
+PCSB00499 Deception IV: Blood Ties
+PCSE00743 Deception IV: The Nightmare Princess
+PCSB00829 Deception IV: The Nightmare Princess
+PCSG00685 DEEMO ~The Last Recital~
+PCSE01041 DEEMO The Last Recital
+PCSE01219 Deep Ones
+PCSB01359 Deep Space Rush
+PCSB01223 Defender's Quest: Valley of the Forgotten DX
+PCSE00889 Delta Strike : First Assault
+PCSE01005 Demetrios - The BIG Cynical Adventure
+PCSE00358 Demon Gaze
+PCSG00043 DEMON GAZE
+PCSG00849 DEMON GAZE 2
+PCSB01150 DEMON GAZE 2
+PCSB01437 Demon's Tier+
+PCSE00639 Dengeki Bunko Fighting Climax
+PCSG00341 Dengeki Bunko: Fighting Climax
+PCSB00763 Dengeki Bunko: Fighting Climax
+PCSG00758 Dengeki Bunko: Fighting Climax Ignition
+PCSE00542 Desert Ashes
+PCSG00959 DESIRE remaster ver.
+PCSF00352 Destiny of Spirits
+PCSA00106 Destiny of Spirits™
+PCSE01249 Devious Dungeon
+PCSB01342 Devious Dungeon 2
+PCSB00953 Dex
+PCSG00272 Diabolik Lovers Limited V Edition
+PCSG00530 Diabolik Lovers: Dark Fate
+PCSG00910 Diabolik Lovers: Lost Eden
+PCSG00826 Diabolik Lovers: Lunatic Parade
+PCSG00476 Diabolik Lovers: More, Blood Limited V Edition
+PCSG00472 Diabolik Lovers: Vandead Carnival
+PCSB00389 Die! Die! Die!
+PCSE00755 Digimon Story Cyber Sleuth
+PCSG00516 Digimon Story: Cyber Sleuth
+PCSH00261 Digimon World: Next Order
+PCSG00792 Digimon World: Next Order
+PCSE00820 Dino Dini's Kick Off
+PCSB00895 Dino Dini's Kick Off
+PCSE00022 Disgaea 3: Absence of Detention
+PCSB00098 Disgaea 3: Absence of Detention
+PCSG00005 Disgaea 3:Return(魔界戦記ディスガイア3 Return)
+PCSE00360 Disgaea 4: A Promise Revisited
+PCSF00309 Disney Epic Mickey : Disney Epic Mickey 2: The Power of Two
+PCSF00308 Disney Epic Mickey 2: The Power of Two
+PCSA00110 Disney's Epic Mickey 2: The Power of Two
+PCSB01165 DISTRAINT: Deluxe Edition
+PCSB00373 Divekick
+PCSE00208 DJMax Technika Tune
+PCSG90047 DJMax Technika Tune Demo
+PCSH00025 DJMax Technika Tune Demo
+PCSC80021 DMM.com
+PCSE00103 Doctor Who: The Eternity Clock
+PCSG00775 Dogimegi Inryoku-Chan: Love & Peace
+PCSG90220 Dogimegi Inryoku-Chan: Love & Peace Trial Version
+PCSA00117 Doki-Doki Universe™
+PCSE00124 Dokuro
+PCSB00215 Dokuro
+PCSB00639 Don't Die, Mr Robot
+PCSE00450 Don't Starve: Giant Edition
+PCSE00327 Doodle Devil
+PCSE00133 Doodle God
+PCSB00556 Doodle Kingdom
+PCSG01100 Doukoku Soshite... Remastered
+PCSB00952 Downwell
+PCSE00873 Downwell
+PCSE00305 Dragon Ball Z: Battle of Z
+PCSB00424 Dragon Ball Z: Battle of Z Demo
+PCSG90095 Dragon Ball Z: Battle of Z Demo
+PCSE00330 Dragon Ball Z: Battle of Z Demo
+PCSE00217 Dragon Fantasy Book 1
+PCSE00299 Dragon Fantasy Book 2
+PCSE00952 Dragon Fantasy: Black Tome of Ice
+PCSE01086 Dragon Fantasy: Volumes of Westeria
+PCSE00447 Dragon Fin Soup
+PCSB00621 Dragon Fin Soup
+PCSG00697 Dragon Quest Builders
+PCSE00912 DRAGON QUEST BUILDERS
+PCSE00934 Dragon Quest Builders Demo
+PCSB00999 Dragon Quest Builders Demo
+PCSG90213 Dragon Quest Builders Demo
+PCSH00270 Dragon Quest Builders Demo
+PCSH00298 Dragon Quest Heroes II
+PCSG90245 Dragon Quest Heroes II Demo
+PCSE01190 Dragon Sinker
+PCSE00019 Dragon's Crown
+PCSG00187 Dragon's Crown
+PCSB00408 Dragon's Crown
+PCSH00050 Dragon's Crown
+PCSG00212 Dragon's Dogma Quest
+PCSE01360 Dragonfly Chronicles
+PCSE01193 Dragooned
+PCSG00420 DRAMAtical Murder re:code
+PCSE00224 Draw Slasher
+PCSG00026 DREAM C CLUB ZERO PORTABLE
+PCSE01365 Dreamwalker
+PCSE00841 Dreii
+PCSB01097 Drive Girls
+PCSE01099 Drive Girls
+PCSE01363 Drowning
+PCSB01404 Duck Souls+
+PCSB00437 Duke Nukem 3D: Megaton Edition
+PCSE00339 Duke Nukem 3D: Megaton Edition
+PCSB01474 Dull Grey
+PCSE00008 Dungeon Hunter: Alliance
+PCSE00944 Dungeon Punks
+PCSE00693 Dungeon Travelers 2
+PCSG00407 Dungeon Travelers 2 : The Royal Library & the Monster Seal
+PCSE00718 Dungeon Travelers 2 Demo
+PCSG90141 Dungeon Travelers 2 Demo
+PCSG00841 Dungeon Travelers 2-2
+PCSG90278 Dungeon Travelers 2-2 Trial Version
+PCSB00824 Dungeon Travelers 2: The Royal Library Demo
+PCSG00482 Durarara!! Relay
+PCSE00332 Dustforce
+PCSB01051 DYING: Reborn
+PCSE00984 Dying:Reborn
+PCSG00860 DYNAMIC CHORD feat.[reve parfait] V edition
+PCSG00915 DYNAMIC CHORD feat.apple-polisher V edition
+PCSG00862 DYNAMIC CHORD feat.KYOHSO V edition
+PCSG00861 DYNAMIC CHORD feat.Liar-S V edition
+PCSG90136 Dynasty Warriors 8 Empires Edit Mode Trial Version
+PCSE00405 Dynasty Warriors 8: Xtreme Legends Complete Edition
+PCSH00058 Dynasty Warriors Gundam Reborn
+PCSE00014 Dynasty Warriors Next
+PCSG00002 Dynasty Warriors Next
+PCSB00108 Dynasty Warriors Next Demo Version
+PCSE00069 Dynasty Warriors Next Demo Version
+PCSG90006 Dynasty Warriors Next Trial Version
+PCSG90018 Dynasty Warriors Next Trial Version
+PCSH00004 Dynasty Warriors Next Trial Version
+PCSE00995 DYNASTY WARRIORS: Godseekers
+PCSH10007 Dynasty Warriors: Godseekers Trial Version
+PCSG90243 Dynasty Warriors: Godseekers Trial Version
+PCSB00084 EA SPORTS FIFA Football Demo
+PCSB00082 EA SPORTS FIFA Football Demo
+PCSB00086 EA SPORTS FIFA Football Demo
+PCSE00059 EA SPORTS FIFA Football Demo
+PCSB00083 EA SPORTS FIFA Football Démo
+PCSE00060 EA SPORTS FIFA Football Démo
+PCSE00055 EA SPORTS FIFA Soccer Demo
+PCSG00039 EA SPORTS™ FIFA Football
+PCSG00432 Earth Defense Force 2: PORTABLE V2
+PCSB00884 Earth Defense Force 2: Invaders from Planet Space
+PCSE00710 Earth Defense Force 2: Invaders from Planet Space
+PCSE00209 Earth Defense Force 2017 Portable
+PCSG00291 EbiKore+ Amagami (エビコレ+ アマガミ)
+PCSA00087 Ecolibrium™
+PCSG00753 Eikoku Tantei Mysteria: The Crown
+PCSG01026 Eiyuu Densetsu: Akatsuki no Kiseki
+PCSG00042 Eiyuu Densetsu: Zero no Kiseki Evolution
+PCSG00316 Eiyuu*Senki
+PCSH00246 Element4l
+PCSB01325 Emerald Shores
+PCSB01443 EMMA: Lost In Memories
+PCSG00963 end sleep
+PCSG90254 End Sleep Trail Version
+PCSB00945 Energy Balance
+PCSE01124 Energy Cycle
+PCSE01192 Energy Invasion
+PCSG01167 Enkan no Memoria: Kakera Tomoshi
+PCSA00140 Entwined™
+PCSG01134 Ephemeral FANTASY ON DARK
+PCSB01431 Epic Word Search Collection
+PCSB01458 Epic Word Search Collection 2
+PCSF00023 Escape Plan
+PCSA00004 Escape Plan™
+PCSE00095 escapeVektor
+PCSE00395 Ethan: Meteor Hunter
+PCSG00817 EVE burst error R
+PCSG01249 EVE rebirth terror
+PCSG01139 Evening Bell of Piofiore
+PCSC00001 Everybody's Golf
+PCSE00941 Exile's End
+PCSG00679 Exist Archive
+PCSB00995 Exist Archive
+PCSE00883 Exist Archive: The Other Side of the Sky
+PCSB01419 Explosive Jake
+PCSG00196 Exstetra
+PCSB00027 F1 2011
+PCSE00002 F1 2011
+PCSA00042 Facebook
+PCSE01051 Factotum90
+PCSG00798 Fairune
+PCSE00955 Fallen Legion
+PCSH00157 Fantasy Hero ~unsigned legacy~
+PCSG00280 FANTASY HERO~unsigned legacy~
+PCSB00333 Farming Simulator
+PCSE00285 Farming Simulator
+PCSE00419 Farming Simulator 14
+PCSH00117 Farming Simulator 14
+PCSB00843 Farming Simulator 16
+PCSE01035 Farming Simulator 18
+PCSE01334 Fast Striker
+PCSB00894 Fat City
+PCSA00156 Fat Princess: Piece of Cake
+PCSF00612 Fat Princess: Piece of Cake
+PCSG00600 Fate/EXTELLA
+PCSG01091 Fate/EXTELLA LINK
+PCSE01254 Fate/EXTELLA LINK
+PCSE00928 Fate/Extella: The Umbral Star
+PCSG00386 Fate/hollow ataraxia
+PCSG00122 Fate/Stay Night [Realta Nua]
+PCSE01282 Fernz Gate
+PCSE00404 Fez
+PCSE00266 Fieldrunners 2
+PCSG00107 FIFA 13 WORLD CLASS SOCCER
+PCSE00263 FIFA 14
+PCSG00201 FIFA 14 WORLD CLASS SOCCER
+PCSG00404 FIFA 15
+PCSE00481 FIFA 15
+PCSE01431 Fifty Words by POWGI
+PCSB01397 Fifty Words by POWGI
+PCSH10211 Fifty Words by POWGI
+PCSE01255 Fill-a-Pix: Phil's Epic Adventure
+PCSB00395 FINAL FANTASY X HD Remaster
+PCSG00219 FINAL FANTASY X HD Remaster
+PCSB00394 Final Fantasy X-2 HD Remaster
+PCSG00220 FINAL FANTASY X-2 HD Remaster
+PCSE00504 Final Horizon
+PCSA00037 Fireworks
+PCSB00656 Flame Over
+PCSE00566 Flame Over
+PCSB00328 Floating Cloud God Saves the Pilgrims in HD!
+PCSG01202 Floral flowlove
+PCSA00114 Flower
+PCSG00459 FLOWERS
+PCSG00739 Flowers Le volume sur ete
+PCSG01187 Flowers Le volume sur hiver
+PCSB00382 Flyhunter Origins
+PCSE00257 Flying Hamster HD
+PCSE00039 Foosball 2012
+PCSB00160 Foosball 2012
+PCSE00797 Forma.8
+PCSE00321 Fort Defense
+PCSB00472 Fort Defense North Menace
+PCSG01131 Fortissimo
+PCSH10065 Fortune Street: Dragon Quest & Final Fantasy 30th Anniversary
+PCSB00522 Foul Play
+PCSA00047 foursquare
+PCSE01437 FoxyLand
+PCSE01438 FoxyLand 2
+PCSE01380 Frane: Dragons' Odyssey
+PCSA00147 Freedom Wars
+PCSC00054 Freedom Wars
+PCSD00087 FREEDOM WARS™
+PCSF00446 FREEDOM WARS™
+PCSG00519 Friend to Lover ~フレラバ~
+PCSA00050 FROBISHER SAYS!™
+PCSE00528 Frozen Synapse Prime
+PCSE00229 Fruit Ninja
+PCSB00273 Fruit Ninja
+PCSG01260 Full Kiss
+PCSB01053 Full Throttle Remastered
+PCSE01261 FullBlast
+PCSE00839 Funk of Titans
+PCSB00421 Furmins
+PCSE00111 Furmins
+PCSG00227 Furuiro Meikyuu Rondo: La Roue de fortune
+PCSG00922 Furuki Yoki Jidai no Boukentan
+PCSB01333 Furwind
+PCSG00569 Fushigi no Chronicle: Furikaerimasen Katsu Madewa
+PCSG01085 Futagoza no Paradox
+PCSE00495 Futuridium EP Deluxe
+PCSG00493 Fuuraiki 3
+PCSG01065 Gakuen Club Himitsu no Nightclub
+PCSG00654 Gakuen K -Wonderful School Days- V Edition
+PCSH00249 Gakusen Toshi Asterisk Festa - Houka Kenran
+PCSG00704 Gal Gunvolt
+PCSE00881 Gal*Gun Double Peace
+PCSG00699 Gal*Gun Double Peace
+PCSB00956 Gal*Gun Double Peace
+PCSG01029 Gal*Gun Double Peace Bilingual
+PCSG01151 GALTIA V Edition
+PCSE01440 Ganbare! Super Strikers
+PCSE00958 GAROU: MARK OF THE WOLVES
+PCSE00981 Geki Yaba Runner
+PCSG00214 Gekijouban Madoka Magicka: The Battle Pentagram
+PCSB00799 Gem Legends
+PCSB00965 GemSmashers 3D
+PCSG00373 Gendai Daisenryaku 2016 ~Chitsujo no Houkai·Haken Kokka Shittsui~
+PCSG00256 GENIMUS
+PCSG00619 Genji Koi Emaki
+PCSG00695 Genkai Tokki: Moero Crystal
+PCSH00301 Genkai Tokki: Moero Crystal
+PCSG00882 Genkai Tokki: Seven Pirates
+PCSG01294 Gensou Rougoku no Kaleidoscope
+PCSB00769 Geometry Wars 3: Dimensions
+PCSB00610 Get Off My Lawn!
+PCSE00421 Get Off My Lawn!
+PCSG00921 Geten no Hana with Yume Akari - Aizouban
+PCSG90098 Getsuei Gakuen -kou-
+PCSG00991 Getsuei no Kusari: Kouran Moratorium
+PCSG00794 Getsuei no Kusari: Sakuran Paranoia
+PCSB01378 Ghoulboy
+PCSE01340 Ghoulboy
+PCSG00419 Ginsei Igo: Next Generation
+PCSG01073 Gintama Rumble
+PCSG00670 Girlfriend (Kari) - Kimi to Sugosu Natsuyasumi
+PCSG00339 Girls und Panzer: Senshado, Kiwamemasu!
+PCSG01277 Gnosia
+PCSG00786 Gochuumon wa Usagi Desu ka??
+PCSG00240 GOD EATER 2
+PCSE00789 GOD EATER 2 RAGE BURST
+PCSG00532 GOD EATER 2 RAGE BURST
+PCSH00133 GOD EATER 2 RAGE BURST
+PCSG00719 GOD EATER RESURRECTION
+PCSH00199 GOD EATER RESURRECTION
+PCSE00801 GOD EATER RESURRECTION
+PCSF00438 God of War® Collection
+PCSA00126 God of War® Collection
+PCSG00831 God Wars: Future Past
+PCSG00367 Goes!
+PCSG00218 Golden Time Vivid Memories
+PCSE00879 Grand Kingdom
+PCSB01372 Grass Cutter
+PCSE00487 Gravity Badgers
+PCSB00525 Gravity Crash Ultra
+PCSC00002 GRAVITY DAZE™
+PCSE01384 Gravity Duck
+PCSB01338 Gravity Duck
+PCSD00035 GRAVITY RUSH
+PCSF00024 GRAVITY RUSH™
+PCSA00011 GRAVITY RUSH™
+PCSF00067 GRAVITY RUSH™ (DEMO)
+PCSB00949 Green Game: Timeswapper
+PCSE00547 Grim Fandango Remastered
+PCSG00206 Grisaia no Kajitsu Le Fruit de la Grisaia
+PCSG00620 Grisaia no kajitsu spinout
+PCSG00421 Grisaia no Meikyuu Le Labyrinthe de la Grisaia
+PCSG01149 Grisaia Phantom Trigger 01 & 02
+PCSG01218 Grisaia Phantom Trigger 03 & 04
+PCSE00033 Guacamelee!
+PCSB00189 Guacamelee!
+PCSB01416 Guard Duty
+PCSG00131 GUILTY GEAR XX ΛCORE PLUS R
+PCSG01013 Gun Gun Pixies
+PCSG00126 Gundam Breaker
+PCSG00412 Gundam Breaker 2
+PCSH00208 Gundam Breaker 3
+PCSH10042 Gundam Breaker 3 BREAK EDITION
+PCSH10041 GUNDAM BREAKER 3 BREAK EDITION
+PCSG00657 Gundam Conquest V
+PCSE01283 GUNDEMONIUMS
+PCSG01289 Gunka o Haita Neko
+PCSE00340 Gunslugs
+PCSB01365 Habroxia
+PCSE01504 Habroxia 2
+PCSG00162 Haiyore! Nyaruko-San
+PCSG00577 Hakuisei Aijou Izonshou
+PCSG01275 Hakuisei Renai Shoukougun Re:Therapy
+PCSE01001 Hakuoki Edo Blossoms
+PCSG00217 Hakuouki Kyouka Roku
+PCSG00605 Hakuouki Reimeiroku
+PCSG00297 Hakuouki SSL: Sweet School Life
+PCSG00930 Hakuouki Yugiroku The Great Banquet of the Members
+PCSG00811 Hakuouki: Shinkai - Hana no Shou
+PCSG00485 Hakuouki's Memoirs Omokagegehana
+PCSE01258 Halloween Forever
+PCSG00855 Hana Oboro ~Sengoku-den Ranki~
+PCSG01024 Hanasaki Work Spring!
+PCSG00576 Hanayaka Nari, Wa ga Ichizoku: Gentou Nostalgie
+PCSG00470 Hanayaka Nari, Wa ga Ichizoku: Modern Nostalgie
+PCSG00451 Hanayamata: Yosakoi Live!
+PCSE00681 Handball 16
+PCSG00992 Harukanaru Toki no Naka de 3 Ultimate
+PCSG00542 Harukanaru Toki no Naka De 6
+PCSG00975 Harukanaru Toki no Naka de 6: Gentou Rondo
+PCSG01157 Harukanaru Toki no Naka de Ultimate
+PCSG01252 Haruoto Alice Gram: Snow Drop
+PCSG00559 Harvest OverRay
+PCSE00653 Hatoful Boyfriend
+PCSE00776 Hatoful Boyfriend: Holiday Star
+PCSG01229 Hatsujou Sprinkle
+PCSE00867 Hatsune Miku Project DIVA X
+PCSE00886 Hatsune Miku Project DIVA X Demo
+PCSE00326 Hatsune Miku: Project DIVA f
+PCSB00419 Hatsune Miku: Project DIVA f
+PCSG00074 Hatsune Miku: Project DIVA f
+PCSB00506 Hatsune Miku: Project DIVA f (DEMO)
+PCSG00205 Hatsune Miku: Project DIVA F 2nd
+PCSB00554 Hatsune Miku: Project DIVA F 2nd
+PCSE00434 Hatsune Miku: Project DIVA F 2nd
+PCSH00115 Hatsune Miku: Project DIVA F 2nd (DEMO)
+PCSG00683 Hatsune Miku: Project Diva X
+PCSB01007 Hatsune Miku: Project DIVA X
+PCSH00239 Hatsune Miku: Project Diva X (DEMO)
+PCSH00176 Hatsune Miku: Project DIVA X (初音未來 -Project DIVA- X)
+PCSB01009 Hatsune Miku: Project DIVA X Demo
+PCSG90214 Hatsune Miku: Project DIVA X Trial (DEMO)
+PCSG00988 Hatsuru Kotonaki Mirai Yori
+PCSG00997 Hatsuyuki Sakura
+PCSA00134 HELLDIVERS™
+PCSE00666 Heroes of Loot
+PCSE01256 Heroes Trials
+PCSG00388 Hideboh: Tap Dance Hero
+PCSG00406 High School DxD: New Fight
+PCSG00517 Higurashi no Naku Koro ni Sui
+PCSG00639 Himawari Pebble in the Sky
+PCSH10186 Himno
+PCSG00688 Himouto! Umaru-chan: Umaru Training Plan
+PCSE00254 HISTORY: Legends of War: Patton
+PCSB00922 Hitman GO: Definitive Edition
+PCSE00846 Hitman GO: Definitive Edition
+PCSG00506 Hitotsu Tobashi Ren’ai V
+PCSB01340 Hoggy2
+PCSA00123 Hohokum
+PCSE00533 Home - A Unique Horror Adventure
+PCSB00687 Home - A Unique Horror Adventure
+PCSG00926 Hoshi ori yume mirai
+PCSA00009 Hot Shots Golf™: World Invitational
+PCSG00200 Hotchkiss
+PCSE00249 Hotline Miami
+PCSB00318 Hotline Miami
+PCSE00402 Hotline Miami 2: Wrong Number
+PCSB00511 Hotline Miami 2: Wrong Number
+PCSB00641 htoL#NiQ -The Firefly Diary-
+PCSE00527 htoL#NiQ -The Firefly Diary-
+PCSE00551 HTR+ Slot Car Simulation
+PCSB00938 HTR+ Slot Car Simulation
+PCSE00996 Hue
+PCSB00246 Hungry Giraffe
+PCSA00007 Hustle Kings
+PCSG00518 Hyakka Ryouran Elixir: Record of Torenia Revival
+PCSG00477 Hyakka Yakou
+PCSE00568 Hyperdevotion Noire Goddess Black Heart
+PCSE00400 Hyperdimension Neptunia PP
+PCSB00515 Hyperdimension Neptunia PP
+PCSG00226 Hyperdimension Neptunia Re;Birth 1
+PCSE00443 Hyperdimension Neptunia Re;Birth 1
+PCSB00626 Hyperdimension Neptunia Re;Birth2
+PCSE00661 Hyperdimension Neptunia Re;Birth3 V GENERATION
+PCSG00486 Hyperdimension Neptunia Re;Birth3: V Century
+PCSG00394 Hyperdimension Neptunia U: Action Unleashed
+PCSB00710 HYPERDIMENSION NEPTUNIA U: Action Unleashed
+PCSE00588 HYPERDIMENSION NEPTUNIA U: Action Unleashed
+PCSG90077 Hyperdimension Neptunia: Producing Perfection Demo
+PCSE01188 I Am The Hero
+PCSG01257 I Am The Hero
+PCSE01358 I and Me
+PCSG00592 I DOLL U -
+PCSG00337 I wanna say that I'm not your brother right now!!
+PCSG00355 IA/VT -COLORFUL-
+PCSE01245 Ice Cream Surfer
+PCSE01177 Iconoclasts
+PCSG00965 id: RebirthSession
+PCSG00865 Idol Death Game TV
+PCSG01094 IDOLiSH7 Twelve Fantasia!
+PCSG00357 If my Heart Had Wings
+PCSG01063 Ikemen Sengoku: Toki o Kakeru Koi - Aratanaru Deai
+PCSG00756 Ikenie to Yuki no Setsuna
+PCSE01418 Illusion of L'Phalcia
+PCSA00113 Imaginstruments
+PCSF00210 Imaginstruments
+PCSG00602 Incognito, Falling in Love ― Snow Moon Flower Love Emaki ―
+PCSE00041 INDOOR SPORTS WORLD
+PCSH00278 Infinita Strada Hana
+PCSG00270 Infinite Stratos 2: Ignition Hearts
+PCSG00584 Infinite Stratos 2: Love and Purge
+PCSB00356 Injustice: Gods Among Us Ultimate Edition
+PCSE00271 Injustice: Gods Among Us Ultimate Edition
+PCSE01237 InkSplosion
+PCSB00157 International Snooker 2012
+PCSA00137 Invizimals: The Alliance
+PCSF00415 Invizimals™ Hidden Challenges
+PCSF00510 Invizimals™: The Resistance
+PCSA00552 Invizimals™: The Resistance
+PCSE00876 iO
+PCSB01029 Iron Sea Defenders
+PCSE01369 Iron Snout
+PCSG01186 IS IT WRONG TO TRY TO PICK UP GIRLS IN A DUNGEON? SHOOTING
+PCSG01000 ISLAND
+PCSB01132 It's Spring Again
+PCSG00932 Itadaki Street: Dragon Quest & Final Fantasy 30th Anniversary
+PCSG01083 Iwaihime Matsuri
+PCSG01297 IxSHE Tell
+PCSG00300 J-Stars Victory VS
+PCSE00595 J-Stars Victory Vs+
+PCSH00136 J-STARS Victory VS+
+PCSB00713 J-STARS Victory VS+
+PCSE01287 Jack N' Jill DX
+PCSB01268 Jack N' Jill DX
+PCSF00250 Jak 3
+PCSA00080 Jak and Daxter Collection
+PCSF00248 Jak and Daxter: The Precursor Legacy
+PCSF00249 Jak II
+PCSB00236 JAZZ Trump's Journey
+PCSE00393 Jet Car Stunts
+PCSB00136 Jet Set Radio
+PCSE00088 Jet Set Radio
+PCSE00213 Jetpack Joyride
+PCSB00244 Jetpack Joyride
+PCSB00664 Jetpack Joyride Deluxe
+PCSE00537 Jetpack Joyride Deluxe
+PCSG00064 Jikkyou Powerful Pro Yakyuu 2012
+PCSG00134 Jikkyou Powerful Pro Yakyuu 2012 Kettei Ban
+PCSG00207 Jikkyou Powerful Pro Yakyuu 2013
+PCSG00416 Jikkyou Powerful Pro Yakyuu 2014
+PCSG00748 Jikkyou Powerful Pro Yakyuu 2016
+PCSG01164 Jikkyou Powerful Pro Yakyuu 2018
+PCSG01045 Jikkyou Powerful Pro Yakyuu Championship 2017
+PCSG01219 Jikkyou Powerful Pro Yakyuu Championship 2018
+PCSG00596 Jinro Game
+PCSE00478 Joe Danger
+PCSE00477 Joe Danger 2: The Movie
+PCSG00390 JUDAS CODE(ジューダス コード)
+PCSE00594 Jungle Rumble: Freedom, Happiness, and Bananas
+PCSB01400 Just a Phrase by POWGI
+PCSH10213 Just a Phrase by POWGI
+PCSE01436 Just a Phrase by POWGI
+PCSB01362 Just Ignore Them
+PCSG00529 Justy x Nasty: Maou Hajime Mashita
+PCSG00635 Jyuzaengi: Engetsu Sangokuden 1+2
+PCSG00381 Kadenz fermata Akkord:fortissimo
+PCSG00501 Kaeru Batake de Tsukamaete
+PCSG00304 Kagero: Darkside Princess
+PCSG00360 Kaihou Shoujo SIN
+PCSG00172 Kajiri Kamui Kagura: Akebono no Hikari
+PCSG01007 Kamaitachi no Yoru: Rinne Saisei
+PCSG00675 Kamen Rider: Battride War Genesis
+PCSG01106 Kamidanomi Shisugite Ore no Mirai ga Yabai.
+PCSG00595 Kamigami no Asobi InFinite
+PCSG00684 KanColle Kai
+PCSG01268 Kannagi no Mori Satsukiame Tsuzuri
+PCSG01182 Kanojo * Step
+PCSG01253 Karigurashi Ren'ai
+PCSG01044 Karumaruka Circle
+PCSG01332 Kawaii Deathu Desu
+PCSG00553 Ken Ga Kimi For V
+PCSG00960 Ken ga Kimi: Momoyo Tsuzuri
+PCSG00829 Kenka Bancho Otome
+PCSG01042 Kenka Bancho Otome : Kanzenmuketsu no My Honey
+PCSG01241 Kenka Bancho Otome 2nd Rumble!!
+PCSE00485 Kick and Fennick
+PCSE00113 KickBeat
+PCSB01354 Kid Tripp
+PCSG00040 Kidou Senshi Gundam Seed: Battle Destiny
+PCSE00473 Kilka Card Gods
+PCSB01477 Killer Dolls United
+PCSG01132 Killers and Strawberries
+PCSD00071 Killzone Mercenary
+PCSC00045 Killzone®: Mercenary
+PCSF00403 Killzone™ Mercenary
+PCSA00107 Killzone™ Mercenary
+PCSF00243 Killzone™ Mercenary
+PCSG01087 Kimi no Hitomi ni Hit Me
+PCSG00913 Kimi o Aogi Otome wa Hime ni
+PCSG01318 Kin-iro Loveriche
+PCSG01124 Kin'iro no Corda 2 ff
+PCSG01212 Kin'iro no Corda 3: AnotherSky feat. Jinnan / Shiseikan / Amane Gakuen
+PCSG01211 Kin'iro no Corda 3: Full Voice Special
+PCSG00774 Kin'iro no Corda 4
+PCSH00275 Kin'iro no Corda 4
+PCSG01245 Kin'iro no Corda: Octave
+PCSE00315 King Oddball
+PCSG00742 Kiss Ato
+PCSG00413 KissBell
+PCSG00478 KLAP!! ~Kind Love And Punish~
+PCSG00970 KLAP!! ~Kind Love And Punish~ Fun Party
+PCSB01409 Knightin'+
+PCSB00929 Knock-knock
+PCSB00169 Knytt Underground
+PCSE00092 Knytt Underground
+PCSE01040 KOI
+PCSG01299 Koisuru Otome to Shugo no Tate: Bara no Seibo
+PCSG00761 Kono Aozora ni Yakusoku o
+PCSG00345 Kono Uta ga Owattara: When This Song is Over
+PCSG00996 Kono Yo no Hate de Koi wo Utau Shoujo YU-NO Original
+PCSG01093 Konosuba - Attack of the Destroyer
+PCSG01265 KonoSuba: Give Education to this Useless Goddess!
+PCSG01028 KonoSuba: Judgment on this Greedy Game!
+PCSG01258 Konosuba: Labyrinth of Hope and the Gathering Adventurers
+PCSG01213 Koshotengai no Hashihime Noma
+PCSG00273 Kud Wafter: Converted Edition
+PCSG00894 Kujiragami no Tearstilla
+PCSE00256 Kung Fu Rabbit
+PCSE01036 Kung Fury: Street Rage
+PCSG01158 Kurenai no Homura Sanada Ninpou Chou
+PCSG00609 Kurogane Kaikijong
+PCSG00641 Kurogane Kaikitan: Ichigoichie
+PCSG90129 Kurogane Kaikitan: Senya Ichiya
+PCSG01288 L'Phalcia no Genei
+PCSE00567 LA-MULANA EX
+PCSE00985 Lara Croft GO
+PCSE00856 Last Wings
+PCSE01085 League of Evil
+PCSH10082 Legend of Heroes: Trails in the Sky 3rd Evolution
+PCSH00178 Legend of Heroes: Trails in the Sky FC Evolution
+PCSE01426 Legend of the Skyfish
+PCSB01392 Legend of the Skyfish
+PCSE00061 LEGO Batman 2: DC Super Heroes
+PCSE00442 Lego Batman 3 Beyond Gotham
+PCSE00057 Lego Harry Potter Years 5-7
+PCSE00587 Lego Jurassic World
+PCSE00237 Lego Legends of Chima Laval’s Journey
+PCSB00764 Lego Marvel's Avengers
+PCSE00384 Lego Ninjago Nindroids
+PCSE00534 Lego Ninjago Shadow Of Ronin
+PCSE00791 Lego Star Wars The Force Awakens
+PCSE00390 Lego The Hobbit
+PCSE00067 Lego The Lord Of The Rings
+PCSB00315 LEGO® MARVEL Super Heroes: Universe in Peril
+PCSE00670 LEGO® MARVEL's Avengers
+PCSA00138 Lemmings™ Touch
+PCSG00405 Lend fleur
+PCSE00216 Let's Fish ! Hooked On
+PCSB00230 Let's Fish! Hooked On
+PCSG00028 Let's Try Bass Fishing FISH ON NEXT
+PCSB00879 Letter Quest Remastered
+PCSB00845 LEVEL 22
+PCSE01010 Lichtspeer
+PCSB01154 Licky The Lucky Lizard Lives Again
+PCSB00336 Limbo
+PCSE00268 Limbo
+PCSE01285 Link-a-Pix Deluxe
+PCSG01319 Link-a-Pix Deluxe
+PCSE01231 Little Adventure on the Prairie
+PCSG00007 Little Busters! Converted Edition (リトルバスターズ! Converted Edition)
+PCSF00017 Little Deviants
+PCSA00010 Little Deviants™
+PCSB01215 Little Red Lie
+PCSE01218 Little Red Lie
+PCSF00021 LittleBigPlanet™ PlayStation®Vita
+PCSA00017 LittleBigPlanet™ PlayStation®Vita
+PCSA00549 LittleBigPlanet™ PlayStation®Vita Marvel Super Hero Edition
+PCSB00494 Llamasoft TxK
+PCSE01187 London Detective Mysteria
+PCSB00361 Lone Survivor
+PCSE00301 Lone Survivor
+PCSF00441 Looney Tunes™ Galactic Sports
+PCSG00008 Lord of Apocalypse
+PCSG90001 Lord Of Apocalypse ロードの誘い
+PCSE00673 Lost Dimension
+PCSG01314 LOVE CLEAR
+PCSG00422 Love Live! School idol paradise Vol.1 Printemps
+PCSG00423 Love Live! School idol paradise Vol.2 BiBi
+PCSG00424 Love Live! School idol paradise Vol.3 lily white
+PCSG01004 Love of Ren'ai Koutei of LOVE!
+PCSG00667 LOVE:QUIZ - Koisuru Shoujo no Final Answer
+PCSG00336 LOVELY QUEST Unlimited
+PCSG00556 LOVELY×CATION 1&2
+PCSH10290 Luckslinger
+PCSG01165 Lucky Dog 1
+PCSE00247 LUFTRAUSERS
+PCSE00009 Lumines Electronic Symphony
+PCSG00444 Luminous Arc Infinity
+PCSE00857 Lumo
+PCSG00475 M3: Sono Kuroki Hagane /// Mission Memento Mori
+PCSE00212 Machinarium
+PCSG00947 Macross Delta: Scramble
+PCSE00084 Madden NFL 13
+PCSG00221 Magical Beat
+PCSE00464 Magical Beat (DEMO)
+PCSE00749 Mahjong Carnival
+PCSG00029 Mahjong Fight Club: Shinsei Zenkoku Taisen Han
+PCSG00368 Mahou Shoujo Taisen Zanbatsu
+PCSG00456 Mahouka Koukou no Rettousei: Out of Order
+PCSG00856 Maison de Maou
+PCSG00852 Maji-Kyun! Renaissance
+PCSG00652 Majin Shoujo - Chronicle 2D ACT (Japan) (En,Ja,Zh) (PSN)
+PCSG00770 Majo Koi Nikki: Dragon x Caravan
+PCSG01284 Making*Lovers
+PCSG00130 MALICIOUS REBIRTH
+PCSA00127 MALICIOUS™ REBIRTH
+PCSE00736 Maliya
+PCSG00340 MANGA-KA-KERU
+PCSG00448 MARGINAL#4 IDOL OF SUPERNOVA
+PCSG01008 MARGINAL#4 ROAD TO GALAXY
+PCSG00662 Maru Goukaku! Takken Shiken - Heisei 27 Nendohan
+PCSG00898 Mary Skelter: Nightmares
+PCSB01059 Mary Skelter: Nightmares
+PCSE01158 Mecho Tales
+PCSE01264 Mecho Wars: Desert Ashes
+PCSH10177 Mecho Wars: Desert Ashes
+PCSB00921 MegaTagmension Blanc Neptune VS Zombies
+PCSG00578 MegaTagmension Blanc + Neptune VS Zombies
+PCSH00236 MegaTagmension Blanc + Neptune VS Zombies (Asia)
+PCSE00832 MegaTagmension Blanc Neptune VS Zombies
+PCSG00398 Meikyuu Cross Blood: Infinity Ultimate
+PCSG00258 MeiQ
+PCSE00918 MeiQ: Labyrinth of Death
+PCSB00990 MeiQ: Labyrinth of Death
+PCSG00606 MeiQ: Labyrinth of Death
+PCSE01428 Mekabolt
+PCSB01348 MEKORAMA
+PCSG01285 MELLKISS
+PCSG00733 Melty Moment
+PCSG00176 Memories Off 6 Complete
+PCSH10133 Memories Off Innocent Fille
+PCSG01264 Memories Off Innocent Fille for Dearest
+PCSB00313 Men's Room Mayhem
+PCSE00252 Men's Room Mayhem
+PCSE00956 Mercenary Kings
+PCSH10097 METAGAL
+PCSE01080 METAGAL
+PCSE00078 Metal Gear Solid 2: Sons of Liberty HD Edition
+PCSG00081 Metal Gear Solid 3 HD Edition
+PCSE00079 Metal Gear Solid 3: Snake Eater HD Edition
+PCSB00118 Metal Gear Solid HD Collection
+PCSG00972 METAL MAX Xeno
+PCSE00665 METAL SLUG 3
+PCSB00772 METAL SLUG 3
+PCSE00406 Metrico
+PCSH10242 Metropolis: Lux Obscura
+PCSE00010 Michael Jackson The Experience HD
+PCSG00198 Midnight Deluxe
+PCSE01194 Midnight Deluxe
+PCSG01193 Mikagami Sumika no Seifuku Katsudou
+PCSC00052 Miku Miku Hockey
+PCSC00081 Miku Miku Hockey 2.0
+PCSB01393 Miles & Kilo
+PCSE01425 Miles & Kilo
+PCSB01414 Milo's Quest
+PCSE01501 Mind Maze
+PCSG00184 MIND≒0
+PCSE00491 Minecraft: Playstation Vita Edition
+PCSG00302 Minecraft: Playstation Vita Edition
+PCSB00560 Minecraft: PlayStation Vita Edition
+PCSG00581 Minna de Spelunker Z
+PCSC00055 Minna to Issho
+PCSB00544 Minutes™
+PCSG00610 Miracle Girls Festival
+PCSH10169 Mixups by POWGI
+PCSB01332 Mixups by POWGI
+PCSE01378 Mixups by POWGI
+PCSA00002 MLB 12 The Show
+PCSA00065 MLB 13: The Show
+PCSA00511 MLB15 THE SHOW
+PCSB00983 Mobile Suit Gundam Extreme Versus Force
+PCSG00579 Mobile Suit Gundam: Battle Fortress
+PCSG00738 Mobile Suit Gundam: Extreme VS Force
+PCSE00915 Mobile Suit Gundam: Extreme VS-Force
+PCSE01414 Mochi Mochi Boy
+PCSA00001 ModNation™ Racers: Road Trip
+PCSF00002 ModNation™ Racers: Road Trip
+PCSG00989 Moe Moe 2-Ji Daisenryaku 3
+PCSG00065 Moe Moe Daisensou Gendai Ban Plus Plus
+PCSG00378 Monobeno -pure smile-
+PCSB00473 Monster Monpiece
+PCSG00148 Monster Monpiece
+PCSF00651 MonsterBag -
+PCSE00838 MOP: Operation Cleanup
+PCSB00106 Mortal Kombat
+PCSE00023 Mortal Kombat
+PCSG00706 Moshi, Kono Sekai ni Kami-sama ga Iru to suru Naraba.
+PCSB00498 MotoGP 14
+PCSB00316 MotoGP™13
+PCSC00014 MOTORSTORM® RC
+PCSF00046 MotorStorm®RC -
+PCSG00247 Motto Nee, Chanto Shouyo! +Plus
+PCSG00854 Moujuu-tachi to Ohime-sama
+PCSB00530 MouseCraft
+PCSE01002 Mr.Pumpkin Adventure
+PCSB00367 Ms. Germinator
+PCSB00182 MUD - FIM Motocross World Championship™
+PCSB00685 Multiplayer.it
+PCSE00240 Muramasa Rebirth
+PCSB00404 Muramasa Rebirth
+PCSA00153 Murasaki Baby
+PCSF00435 Murasaki Baby™
+PCSC00043 Muryou-ban E-Channel NEW Paint Park
+PCSE01479 Mushroom Heroes
+PCSH10037 Musou Stars
+PCSE01184 Musynx
+PCSB00979 Mutant Mudds Super Challenge
+PCSB01234 Muv-Luv
+PCSE01259 Muv-Luv
+PCSG00776 Muv-Luv
+PCSG00777 Muv-Luv Alternative
+PCSG90203 Muv-Luv Alternative Total Eclipse: Teito Moyu
+PCSE00530 MXGP - The Official Motocross Videogame
+PCSB01463 My Aunt is a Witch
+PCSE01386 My Big Sister
+PCSE00982 My Name Is Mayo
+PCSE00459 My Singing Monsters
+PCSB00958 Mystery Chronicle: One Way Heroics
+PCSG01178 NadeRevo! Nadeshiko Revolution
+PCSG00664 Nanairo Reincarnation
+PCSG01185 Natsuiro Kokoro Log
+PCSG00650 Natsumegu
+PCSB00594 NAtURAL DOCtRINE
+PCSE00460 NAtURAL DOCtRINE
+PCSG00030 NAX Music Player
+PCSB01321 Necrosphere
+PCSE01413 Need a packet?
+PCSE00089 Need For Speed™ Most Wanted
+PCSG00106 Need For Speed™ Most Wanted
+PCSB00183 Need For Speed™ Most Wanted
+PCSG00410 Nekketsu Inou Bukatsu: Trigger Kiss
+PCSG01068 Neo Angelique: Tenshi no Namida
+PCSG00877 Neo ATLAS 1469
+PCSB00910 Neon Chrome
+PCSE01398 Neon Junctions
+PCSG00951 Nep-Nep Connect: Chaos Chanpuru
+PCSG00656 Net High
+PCSE00070 Netflix
+PCSE01236 NeuroVoider
+PCSE01137 NeverEnd
+PCSE00847 Neverending Nightmares
+PCSB00940 Neverending Nightmares
+PCSG00903 New Game! -The Challenge Stage!-
+PCSH10101 New Game! -The Challenge Stage!- Chinese Version
+PCSB00109 New Little King's Story
+PCSE00066 New Little King's Story
+PCSG01204 NG
+PCSG80001 niconico
+PCSE00514 Nidhogg
+PCSH00254 Night of Azure / Yoru no Nai Kuni (無夜國度)
+PCSG00986 Night of Azure 2 / Yoru no Nai Kuni 2
+PCSE01149 Night Trap - 25th Anniversary Edition
+PCSE00895 NightCry
+PCSG00557 Nights of Azure / Yoru no Nai Kuni
+PCSB00705 Nihilumbra
+PCSE00620 Nihilumbra
+PCSG00586 Nihilumbra
+PCSG00082 Nikoli no Puzzle V: Akari
+PCSG00095 Nikoli no Puzzle V: Hashi o Kakero
+PCSG00067 Nikoli no Puzzle V: Heyawake
+PCSG00098 Nikoli no Puzzle V: Hitori ni Shitekure
+PCSG00060 Nikoli no Puzzle V: Kakuro
+PCSG00083 Nikoli no Puzzle V: Masyu
+PCSG00097 Nikoli no Puzzle V: Number Link
+PCSG00068 Nikoli no Puzzle V: Nurikabe
+PCSG00096 Nikoli no Puzzle V: Shikaku ni Kire
+PCSG00061 Nikoli no Puzzle V: Slither Link
+PCSG00094 Nikoli no Puzzle V: Yajilin
+PCSG00044 Nikoli no Sudoku V: Shugyoku no 12 Puzzle
+PCSG01014 Nil Admirari's Balance Kuroyuri Enyoutan
+PCSG00766 Nil Admirari's Balance Teito Illusion Kitan
+PCSE00021 Ninja Gaiden Sigma Plus
+PCSB00097 NINJA GAIDEN Σ PLUS
+PCSG00157 NINJA GAIDEN Σ2 PLUS
+PCSB00294 NINJA GAIDEN Σ2 PLUS
+PCSB00903 Ninja Senki DX
+PCSG01099 Ninja Usagimaru: Two Tails of Adventure
+PCSG01111 Ninki Seiyuu no Tsukurikata
+PCSG00397 Nisekoi: Yomeiri!
+PCSA00150 No Heroes Allowed: No Puzzles Either!™
+PCSG00803 Nobunaga no Yabou 201X
+PCSG00374 Nobunaga no Yabou: Souzou
+PCSG00607 Nobunaga no Yabou: Souzou with Power-Up Kit
+PCSG00741 Nobunaga no Yabou: Tenshouki with Power-Up Kit HD Version
+PCSH00291 Nobunaga's Ambition: Souzou Sengoku Risshiden
+PCSH00171 Nobunaga's Ambition: Sphere of Influence with Power-Up Kit
+PCSG01107 Nora to Oujo to Noraneko Heart
+PCSE01496 Norman's Great Illusion
+PCSG00833 NORN9 ACT TUNE
+PCSG00429 NORN9 LAST ERA
+PCSB00847 NORN9 VAR COMMONS
+PCSE00762 NORN9 VAR COMMONS
+PCSE01173 NORTH
+PCSE00686 Nova-111
+PCSE00828 Nuclear Throne
+PCSE00220 Nun Attack
+PCSE01004 Nurse Love Addiction
+PCSB01054 Nurse Love Addiction
+PCSE01318 Nurse Love Syndrome
+PCSG00150 Oboro Muramasa
+PCSG01021 Occultic;Nine
+PCSE01097 Oceanhorn
+PCSB00825 Octodad: Dadliest Catch
+PCSE00623 Octodad: Dadliest Catch
+PCSE00369 Oddworld: Munch's Oddysee HD
+PCSE00899 Odin Sphere Leifthrasir
+PCSH00218 Odin Sphere Leifthrasir
+PCSB00986 Odin Sphere Leifthrasir
+PCSE00341 OlliOlli
+PCSE00479 OlliOlli2: Welcome to Olliwood
+PCSG00550 Omega Labyrinth
+PCSG00939 Omega Labyrinth Z
+PCSH10044 Omega Labyrinth Z
+PCSE00275 OMG HD Zombies!
+PCSB01213 One Eyed Kutkh
+PCSH10094 One More Dungeon
+PCSG00358 ONE PIECE UNLIMITED WORLD R
+PCSB00557 ONE PIECE Unlimited World Red
+PCSH00034 ONE PIECE 海賊無雙2
+PCSG00743 One Piece: Burning Blood
+PCSE00808 One Piece: Burning Blood
+PCSG00142 One Piece: Pirate Warriors 2
+PCSG00544 One Piece: Pirate Warriors 3
+PCSE00638 ONE PIECE: PIRATE WARRIORS 3
+PCSH00205 One Tap Hero
+PCSB01306 One Word by POWGI
+PCSH10167 One Word by POWGI
+PCSE01338 One Word by POWGI
+PCSG00377 Ooedo Blacksmith
+PCSA00118 OPEN ME!™
+PCSE00579 Operation Abyss: New Tokyo Legacy
+PCSG00387 Operation Abyss: New Tokyo Legacy
+PCSE01047 Operation Babel: New Tokyo Legacy
+PCSG00514 Operation Babel: New Tokyo Legacy
+PCSG00289 Ore ni Hatarakette Iwaretemo Otsu HD
+PCSG00623 Ore ni Hatarakette Iwaretemo Tori
+PCSF00536 Oreshika: Tainted Bloodlines
+PCSC00060 Oreshika: Tainted Bloodlines
+PCSA00155 Oreshika™: Tainted Bloodlines
+PCSG00299 Oretachi ni Tsubasa wa Nai
+PCSG01076 Oretachi no Sekai wa Owatteiru
+PCSG00919 Orfleurs: Koufuku no Hanataba
+PCSB00924 Organ Trail Complete Edition
+PCSG00057 orgarhythm
+PCSE00116 Orgarhythm
+PCSG00427 Othello
+PCSG00487 Otoko Yuukaku
+PCSG00942 Otome Riron to Sono Shuuhen: Bon Voyage
+PCSG01105 Ouka Sabaki Zan
+PCSG00254 Oukaranman
+PCSG00769 Ouma ga Toki: Kakuriyo no Enishi
+PCSG90304 Our World is Ended
+PCSG00728 Owari no Seraph: Unmei no Hajimari
+PCSG00967 Owaru sekai to birthday
+PCSG00496 OZMAFIA!! -vivace-
+PCSB01462 Pachi Pachi
+PCSA00059 Paint Park
+PCSF00137 Paint Park
+PCSA00111 Paint Park Plus
+PCSE00489 Panda Run
+PCSG01247 Panic Palette
+PCSE01056 Papers, Please
+PCSB01084 Papers, Please
+PCSE01401 Paradox Soul
+PCSE00821 Paranautical Activity
+PCSG00549 Parfait
+PCSE01082 Peasant Knight
+PCSE01143 Penny-Punching Princess
+PCSB01060 Period Cube ~Shackle of Amadeus~
+PCSG00853 Period Cube ~Shackle of Amadeus~
+PCSE01012 Period Cube ~Shackles of Amadeus~
+PCSG01031 Persona 3 Dancing in Moonlight
+PCSE01274 Persona 3: Dancing in Moonlight
+PCSB00245 Persona 4 Golden
+PCSE00120 Persona 4 Golden
+PCSG00563 Persona 4 Golden
+PCSG00004 Persona 4 Golden
+PCSH00021 Persona 4 The GOLDEN
+PCSE00764 Persona 4: Dancing All Night
+PCSB00867 Persona 4: Dancing All Night
+PCSG00364 Persona 4: Dancing All Night
+PCSG01030 Persona 5: Dancing in Starlight
+PCSE01275 Persona 5: Dancing in Starlight
+PCSB01257 Persona 5: Dancing in Starlight
+PCSG00351 Phantasy Star Nova
+PCSH00143 Phantasy Star Nova
+PCSG90131 Phantasy Star Nova (DEMO)
+PCSG90130 Phantasy Star Nova Battle (DEMO)
+PCSG00141 Phantasy Star Online 2
+PCSF00718 Phineas and Ferb: Day of Doofenshmirtz
+PCSG00139 PhotoKano Kiss
+PCSG01071 Photon3
+PCSE01376 Pic-a-Pix Classic
+PCSE01435 Pic-a-Pix Classic 2
+PCSE01253 Pic-a-Pix Color
+PCSE01422 Pic-a-Pix Color 2
+PCSE01357 Pic-a-Pix Pieces
+PCSE01466 Pic-a-Pix Pieces 2
+PCSE00065 Pinball Arcade
+PCSA00109 Pinball Heroes: Complete
+PCSF00167 Pinball Heroes: Complete
+PCSE00751 Pirate Solitaire
+PCSB00645 Pix The Cat
+PCSE00553 Pix The Cat
+PCSE00874 Pixel Hunter
+PCSG00269 PixelJunk™ Monsters Ultimate HD
+PCSE00307 PixelJunk™ Monsters Ultimate HD
+PCSG00384 PixelJunk™ Shooter Ultimate
+PCSE00064 Plants vs Zombies
+PCSG00931 Plastic Memories
+PCSA00069 PlayStation All-Stars Battle Royale
+PCSC00032 PlayStation® All-Stars Battle Royale
+PCSF00228 PlayStation® Home Arcade
+PCSA00083 PlayStation® Home Arcade
+PCSA00139 PlayStation®Vita Pets
+PCSE00682 Pocket God vs Desert Ashes
+PCSE00558 Pocket RPG
+PCSG00672 POLARA
+PCSE01050 POLARA
+PCSG00509 Possession Magenta
+PCSG00262 Power Pro Stadium
+PCSG00006 Power Smash 4
+PCSE00961 Pox Nora
+PCSG00905 Priministar
+PCSG00491 Prince of Stride
+PCSG00271 Princess Arthur
+PCSG00188 Princess Strike!
+PCSG00031 Pro Yakyuu Spirits 2012
+PCSG00151 Pro Yakyuu Spirits 2013
+PCSG00288 Pro Yakyuu Spirits 2014
+PCSG00541 Pro Yakyuu Spirits 2015
+PCSG01248 Pro Yakyuu Spirits 2019
+PCSG00572 Project Discovery
+PCSE00311 Proteus
+PCSH10091 Psychedelica of the Ashen Hawk
+PCSE01166 Psychedelica of the Ashen Hawk
+PCSE01164 Psychedelica of the black butterfly
+PCSG00815 PsychicEmotion6
+PCSE00904 PSYCHO-PASS MANDATORY HAPPINESS
+PCSB00985 PSYCHO-PASS MANDATORY HAPPINESS
+PCSE00042 Puddle
+PCSC00021 Puls-AR
+PCSE00702 Pumped BMX +
+PCSG00904 Puramai Wars V
+PCSE00389 Putty Squad
+PCSG00224 Puyo Puyo Tetris
+PCSE00108 Puzzle by Nikoli V Slitherlink
+PCSE00101 Puzzle by Nikoli V Sudoku
+PCSG00045 Puzzle by Nikoli V: Sudoku
+PCSE00561 Q*bert Rebooted
+PCSE00143 Quell Memento
+PCSG01037 Rabi Laby: Puzzle Out Stories
+PCSE01111 Rabi-Ribi
+PCSB00643 Race The Sun
+PCSG01209 Radio Hammer Station
+PCSG00958 Raging Loop
+PCSG00025 Ragnarok Odyssey
+PCSE00300 Ragnarok Odyssey ACE
+PCSG00140 Ragnarok Odyssey ACE
+PCSE00273 Rainbow Moon
+PCSE00318 Rainbow Skies
+PCSE01351 Random Heroes: Gold Edition
+PCSF00484 Ratchet & Clank
+PCSF00485 Ratchet & Clank 2
+PCSF00486 Ratchet & Clank 3
+PCSF00482 Ratchet & Clank Trilogy
+PCSA00086 Ratchet & Clank: Full Frontal Assault
+PCSF00191 Ratchet and Clank : QForce
+PCSE00843 Ray Gigant
+PCSB00928 RAYGIGANT
+PCSE00277 Rayman Legends
+PCSE00052 Rayman® Origins
+PCSG00382 RE:VICE[D]
+PCSG00933 Re:Zero - kara Hajimeru Isekai Seikatsu - Death or Kiss
+PCSE00325 Real Boxing™
+PCSA00012 Reality Fighters™
+PCSG00663 Rear Pheles: Red of Another
+PCSG00782 Reco Love: Gold Beach
+PCSG00781 RecoLove: Blue Ocean
+PCSE01434 Red Bow
+PCSG90210 Red Sand Falling Moon Trial Version
+PCSE01471 Reed 2
+PCSE01456 Reed Remastered
+PCSG00795 Refrain no Chika Meikyuu to Majo no Ryodan
+PCSG00426 Ren’ai 0 Kilometer V
+PCSG00718 Renai Revenge
+PCSG00990 RepKiss
+PCSE00608 Resident Evil: Revelations 2
+PCSF00728 Resident Evil: Revelations 2
+PCSA00008 Resistance: Burning Skies
+PCSF00142 Resistance: Burning Skies™
+PCSA00103 RESOGUN
+PCSF00262 RESOGUN™
+PCSE00075 Retro City Rampage
+PCSE00546 Retro City Rampage DX
+PCSE01322 Revenant Dogma
+PCSE01065 Revenant Saga
+PCSE01229 Reverie
+PCSG00414 Rewrite
+PCSG01043 Rewrite Harvest festa!
+PCSE01251 Riddled Corpses EX
+PCSE00001 Ridge Racer
+PCSG00001 RIDGE RACER
+PCSB00048 RIDGE RACER
+PCSG90003 Ridge Racer 2011 E3 Interactive Demo
+PCSE00548 Ring Run Circus
+PCSG00257 RisingStar
+PCSE00850 Risk of Rain
+PCSG00287 Ro-Kyu-Bu! Naisho no Shutter Chance
+PCSG00352 Robotics;Notes Elite
+PCSH00165 Robotics;Notes Elite
+PCSG90115 Robotics;Notes Elite Demo
+PCSE00761 Rocketbirds 2: Evolution
+PCSE00112 Rocketbirds HBC
+PCSB00571 Rogue Legacy
+PCSE00449 Rogue Legacy
+PCSG00616 Rollers of the Realm
+PCSH00308 Romance of the Three Kingdoms XIII: Fame and Strategy
+PCSG00870 Romancing SaGa 2
+PCSE01094 Romancing SaGa 2
+PCSE01337 Romancing SaGa 3
+PCSE01055 Root Double -Before Crime After Days Xtend Edition
+PCSG01238 Root Letter Last Answer
+PCSG90224 Rosé and the Old Castle of Twilight
+PCSE00699 Roundabout
+PCSE00750 Royal Defense
+PCSE00753 Royal Defense Invisible Threat
+PCSG00229 Rozen Maiden -Wechseln sie welt ab-
+PCSG00216 Rui wa Tomo o Yobu
+PCSA00490 Run Sackboy! Run!
+PCSF00562 Run Sackboy! Run!
+PCSE01387 Rush Rover
+PCSB01464 Russian Subway Dogs
+PCSG00503 Ryū ga Gotoku 0 Free app for PlayStation®Vita
+PCSG00275 Ryū ga Gotoku: Ishin! Free app for PlayStation®Vita
+PCSG00732 Ryuuyoku no Melodia: Diva with the Blessed Dragonol
+PCSG00640 SA7 - Silent Ability Seven -
+PCSG00543 Saenai Heroine no Sodatekata: 〜blessing flowers〜
+PCSG00802 SaGa: Scarlet Grace
+PCSG00906 Saka Agari Hurricane Portable
+PCSG90088 Saka-Ban
+PCSG00646 Saki Zenkoku Hen
+PCSG00908 Saki: Zenkoku-hen Plus
+PCSG01231 Sakura Sakura
+PCSG00129 Sakura-Sou no Pet na Kanojo
+PCSB01072 Salt and Sanctuary
+PCSE01023 Salt and Sanctuary
+PCSG00041 Samurai & Dragons
+PCSE01113 SAMURAI SHODOWN V SPECIAL
+PCSG00279 Samurai Warriors 4
+PCSE00503 Samurai Warriors 4
+PCSE00827 SAMURAI WARRIORS 4 Empires
+PCSE00737 SAMURAI WARRIORS 4-Ⅱ
+PCSE00714 Samurai Warriors: Chronicles 3
+PCSH00152 Samurai Warriors: Chronicles 3
+PCSG00211 San Goku Shi 12 Taisenban
+PCSG00210 San Goku Shi 12 with Power-Up Kit
+PCSG00949 San Goku Shi 13 with Power-Up Kit
+PCSG00863 Sangoku Hime 4: Tenka Ryouran - Tenmei no Koi Emaki
+PCSG00183 Sangoku Rensenki: Otome no Heihou!
+PCSG00785 Sangoku Rensenki: Otome no Heihou! Omoide Gaeshi - CS Edition
+PCSG01194 Sanzen Sekai Yuugi: Re Multi Universe Myself
+PCSC00007 Sawari Makuru!
+PCSG00554 Sayonara UmiharaKawase +
+PCSB00782 Sayonara UmiharaKawase +
+PCSG00745 Scared Rider Xechs Rev.
+PCSG01036 Scarlet Fragments ~Omoiiro no Memories~
+PCSE01355 Scintillatron4096
+PCSE01505 ScourgeBringer
+PCSE00642 Scram Kitty DX
+PCSG00793 SD Gundam G Generation Genesis
+PCSH00241 SD GUNDAM G GENERATION GENESIS
+PCSH00242 SD GUNDAM G GENERATION GENESIS
+PCSE01153 Secret of Mana
+PCSB01163 Secret of Mana
+PCSG00168 Sei Madou Monogatari
+PCSG00460 Seiken Densetsu: Rise of Mana (聖剣伝説RISE of MANA)
+PCSG01127 Sen no Hatou, Tsukisome no Kouki
+PCSG01104 Sengo Muramasa DX: Guren no Kettou
+PCSG00132 Sengoku Hime 3: Tenka o Kirisaku Hikari to Kage
+PCSG00232 Sengoku Hime 4: Souha Hyakkei, Hana Mamoru Chikai
+PCSG00466 Sengoku Hime 5: Senkatatsu Haoh no Keifu
+PCSG01034 Sengoku Hime 7: Sen'un Tsuranuku Guren no Ishi
+PCSG00233 Sengoku Musou 2 with Moushouden & Empires HD Version
+PCSG00471 Sengoku Musou Chronicle 3
+PCSG00867 Sengoku Otome: Legend Battle
+PCSG00428 Senjou no Waltz
+PCSB00602 SENRAN KAGURA Bon Appetit! (Hanzo x Crimson Squad)
+PCSB00882 SENRAN KAGURA ESTIVAL VERSUS
+PCSB00601 SENRAN KAGURA SHINOVI VERSUS
+PCSG00133 Senran Kagura: Shinovi Versus
+PCSE01480 Sense - A Cyberpunk Ghost Story
+PCSG01210 Seven Days: Anata to Sugosu Nanokakan
+PCSE00589 Severed
+PCSE01125 Shakedown Hawaii
+PCSE00950 Shantae: Half-Genie Hero
+PCSG90111 She (That Girl) Can't Leave Me Trial Version
+PCSG01177 Shikihime no Niwa
+PCSG00278 Shin Gundam Musou
+PCSG00380 Shin Hayarigami
+PCSG00897 Shin Hayarigami 2
+PCSG00010 Shin Kamaitachi no Yoru 11 Hitome no Suspect
+PCSG00452 Shin Sangoku Musou 7 Empires
+PCSH00052 Shin Sangoku Musou 7 with Moushouden
+PCSG00893 Shin Sangoku Musou Eiketsuden
+PCSG00764 Shin Sangoku Musou Online Z
+PCSG01282 Shinigami to Shoujo
+PCSG00255 ShinobiAshi
+PCSE00015 Shinobido 2: Revenge of Zen
+PCSG00019 Shinobido 2: Revenge of Zen
+PCSH00001 Shinobido 2: Revenge of Zen
+PCSB00049 Shinobido 2: Revenge of Zen
+PCSG00580 Shinsou-ban Mahou-tsukai to Goshujin-sama
+PCSE00845 Shiren the Wanderer: The Tower of Fortune and the Dice of Fate
+PCSG00944 Shiro to Kuro no Alice
+PCSG01192 Shiro to Kuro no Alice -Twilight line-
+PCSG00846 Shirogane x Spirits!
+PCSG00822 Shitsuji ga Aruji o Erabu Toki
+PCSB00743 Shovel Knight
+PCSE00640 Shovel Knight
+PCSE00923 Shu
+PCSE00705 Shütshimi
+PCSG00588 Sid Meier's Civilization Revolution 2+
+PCSG01001 Side Kicks!
+PCSE00011 Silent Hill: Book of Memories
+PCSB00115 Silent Hill: Book of Memories
+PCSG01259 Silverio Trinity: Beyond the Horizon
+PCSG00329 Simple V Series Vol.2: The Tousou Highway Full Boost: Nagoya
+PCSB00161 Sine Mora
+PCSE00090 Sine Mora
+PCSE01240 Sir Eatsalot
+PCSE00773 Siralim
+PCSB00588 Skeleton Rider
+PCSG00583 Skullgirls 2nd Encore
+PCSE00865 Sky Force Anniversary
+PCSE01054 Skylight Freerange
+PCSE00862 Skylight Freerange 2: Gachduine
+PCSC80009 Skype
+PCSG00048 Slotter Mania V: Black Lagoon
+PCSF00338 Sly 1 & 2
+PCSA00098 Sly 3: Honor Among Thieves™
+PCSF00209 Sly Cooper: Thieves in Time
+PCSF00269 Sly Raccoon™
+PCSF00216 Smart as
+PCSG00787 Snow White in the Mirror Realm
+PCSG01254 Soi Kano: Gyutto Dakishimete
+PCSG01070 Song of Heiligenstadt
+PCSE00056 Sonic & All-Stars Racing Transformed
+PCSB00190 Sonic & All-Stars Racing Transformed™
+PCSE00221 Sonic & All-Stars Racing Transformed™ Demo
+PCSE00314 Sorcery Saga: Curse of the Great Curry God
+PCSG90074 Sorcery Saga: Curse of the Great Curry God
+PCSG00296 Soukai Buccaneers!
+PCSC00039 SOUL SACRIFICE
+PCSC00049 SOUL SACRIFICE DELTA
+PCSD00079 SOUL SACRIFICE DELTA™
+PCSA00152 Soul Sacrifice™ Delta
+PCSF00532 Soul Sacrifice™ Delta
+PCSA00003 Sound Shapes
+PCSF00076 Sound Shapes™
+PCSG00993 Sousei no Onmyouji
+PCSE00295 Sparkle
+PCSE01089 Spellspire
+PCSG00145 Spelunker Collection
+PCSE00288 Spelunky
+PCSB00359 Spelunky
+PCSB00789 Spider: Rite of the Shrouded Moon
+PCSE00577 SpongeBob HeroPants
+PCSE00068 Spy Hunter
+PCSG00128 Spy Hunter™
+PCSG00714 Star Ocean Second Evolution
+PCSC00008 STAR STRIKE DELTA
+PCSB00254 Star Wars Pinball
+PCSE01235 Stardew Valley
+PCSB01226 Stardew Valley
+PCSE00029 StarDrone Extreme
+PCSG00917 Starry☆Sky ~Autumn Stories~
+PCSG00510 Starry☆Sky ~Spring Stories~
+PCSG00916 Starry☆Sky ~Summer Stories~
+PCSG00918 Starry☆Sky ~Winter Stories~
+PCSE01277 STAY
+PCSB01254 STAY
+PCSG01237 STAY
+PCSB00690 Stealth Inc 2: A Game of Clones
+PCSE00575 Stealth Inc 2: A Game of Clones
+PCSB00317 Stealth Inc: A Clone in the Dark
+PCSE00280 Stealth Inc: A Clone in the Dark
+PCSG01062 Steam Prison: Nanatsu no Bitoku
+PCSE01391 Steam Tactics
+PCSB00542 SteamWorld Dig
+PCSE00430 SteamWorld Dig
+PCSE01101 SteamWorld Dig 2
+PCSE00583 SteamWorld Heist
+PCSB00693 SteamWorld Heist
+PCSE00644 Steins;Gate
+PCSG00147 STEINS;GATE
+PCSE00949 Steins;Gate 0
+PCSB01012 STEINS;GATE 0
+PCSG00673 STEINS;GATE 0
+PCSG01166 STEINS;GATE ELITE
+PCSG00250 Steins;Gate Senkei Kousoku no Phenogram
+PCSG00146 Steins;Gate: My Darling's Embrace(比翼恋理のだーりん)
+PCSE00290 Stick it to the Man
+PCSE01098 Still Time
+PCSG00736 STORM LOVER 2nd V
+PCSG00735 STORM LOVER V
+PCSB00908 Stranger of Sword City
+PCSE00818 Stranger of Sword City
+PCSG00878 Stranger of Sword City
+PCSG00907 Strawberry Nauts
+PCSE00005 STREET FIGHTER X TEKKEN
+PCSB00144 STREET FIGHTER X TEKKEN
+PCSE00688 Strike Solitaire
+PCSE01514 SturmFront - The Mutant War
+PCSH00006 Sudoku by Nikoli V
+PCSG01250 Suki to Suki to de Sankaku Ren’ai
+PCSG90008 Sumioni Trial Version
+PCSE00062 SUMIONI:DEMON ARTS
+PCSB01013 Summon Night 6: Lost borders
+PCSG00827 Summon Night 6: Lost borders
+PCSH00225 Summon Night 6: Lost borders
+PCSE00951 Summon Night 6: Lost Borders
+PCSE00047 SunFlowers
+PCSE00784 Super Blackout
+PCSE01433 Super Box Land Demake
+PCSG01240 Super Destronaut DX: Intruders Edition
+PCSE01460 Super Destronaut: Land Wars
+PCSB00362 Super Exploding Zoo
+PCSE00734 Super Exploding Zoo
+PCSG00069 Super Hero Generation
+PCSB01193 Super Hydorah
+PCSB01152 Super Life of Pixel
+PCSE01077 Super Life of Pixel
+PCSE00942 Super Magical
+PCSE00769 Super Meat Boy!
+PCSE00017 Super Monkey Ball Banana Splitz
+PCSG00032 Super Monkey Ball Banana Splitz
+PCSB01100 Super Mutant Alien Assault
+PCSE01072 Super Mutant Alien Assault
+PCSG00260 Super Robot Taisen
+PCSG01128 Super Robot Taisen X
+PCSH10001 Super Robot Wars V
+PCSH10089 Super Robot Wars X
+PCSH10088 SUPER ROBOT WARS X
+PCSG00495 Super Robot Wars3 Z Jigoku Hen
+PCSB01271 Super Skull Smash Go! 2 Turbo
+PCSE00802 Super Star Wars
+PCSA00006 Super Stardust Delta
+PCSF00019 Super Stardust™ Delta
+PCSE00698 Super Time Force ULTRA
+PCSE01374 Super Weekend Mode
+PCSE01415 Super Wiloo Demake
+PCSE00717 SUPERBEAT XONiC
+PCSE00898 Superdimension Neptune vs Sega Hard Girls
+PCSB00305 Superfrog HD
+PCSG01207 SuperZangyura
+PCSE00012 Supremacy MMA: Unrestricted
+PCSG00948 Suran digit
+PCSB00439 Surge Deluxe
+PCSE00860 Swap Quest
+PCSB00923 SwapQuest
+PCSG01196 sweet pool
+PCSB00507 Switch Galaxy Ultra
+PCSE00493 Switch Galaxy Ultra
+PCSE00465 Sword Art Online -Hollow Fragment-
+PCSG00868 Sword Art Online : Hollow Realization
+PCSB00618 Sword Art Online Hollow Fragment
+PCSE00740 Sword Art Online Lost Song
+PCSH00134 SWORD ART ONLINE Lost Song
+PCSG00294 Sword Art Online: Hollow Fragment
+PCSB00972 SWORD ART ONLINE: HOLLOW REALIZATION
+PCSE00903 SWORD ART ONLINE: HOLLOW REALIZATION
+PCSB00830 Sword Art Online: Lost Song
+PCSE01484 Swordbreaker The Game
+PCSE01508 Synergia
+PCSE01451 Syrup and the Ultimate Sweet
+PCSF00064 t@g
+PCSF00062 Table Football
+PCSA00064 Table Ice Hockey
+PCSD00047 Table Ice Hockey™
+PCSC00028 Table Play Golf
+PCSB00416 Table Top Racing
+PCSB00912 Tachyon Project
+PCSE00836 Tachyon Project
+PCSE00771 Taco Master
+PCSB00458 Tadeo Jones: The game
+PCSG00945 Taiheiyou no Arashi: Koukoku no Kouhai Koko ni Ari, 1942 Senkan Yamato Hankou no Gouhou
+PCSG00637 Taiheiyou no Arashi: Shijousaidai no Gekisen Normandy Koubousen
+PCSG00551 Taiko no Tatsujin V (太鼓の達人 Vバージョン)
+PCSG00726 Taishou Mebiusline: Vitable
+PCSG00869 Taishou x Alice: All in One
+PCSG01141 Taishou x Alice: Heads & Tails
+PCSE00034 Tales From Space: Mutant Blobs Attack
+PCSB00096 Tales from Space: Mutant Blobs Attack!!!
+PCSE00429 Tales of Hearts R
+PCSG00125 Tales of Hearts R
+PCSB00550 TALES OF HEARTS R
+PCSG00163 Tales of Hearts R: Infinite Evolve
+PCSG00009 Tales Of Innocence R
+PCSE01468 Task Force Kampas
+PCSG01203 Tayutama2 -you're the only one-
+PCSA00099 Tearaway™
+PCSF00476 Tearaway™
+PCSG00547 Teikoku Kaigun Koi Bojou: Meiji Yokosuka Koushinkyoku
+PCSG01064 Teikoku Kaleido: Kakumei no Rondo
+PCSG01180 Tengai ni Mau, Iki na Hana
+PCSG00137 Tenshi Tsuki no Shoujo
+PCSE00317 Terraria
+PCSB00722 Teslagrad
+PCSE00814 Teslagrad
+PCSE01238 TETRA's Escape
+PCSB00642 Tetris® Ultimate
+PCSE00521 Tetris® Ultimate
+PCSE00333 The Amazing Spider-Man
+PCSB00428 The Amazing Spider-Man™
+PCSB00676 The Binding of Isaac: Rebirth
+PCSE00507 The Binding of Isaac: Rebirth
+PCSE00735 THE BIT.TRIP
+PCSE01037 The Caligula Effect
+PCSG00687 The Caligula Effect
+PCSE01112 The Count Lucanor
+PCSE01021 The Deer God
+PCSE01344 The Demon Rush: Legends Corrupt
+PCSE01241 The Dreamlands: Aisling's Quest
+PCSG01095 The Fruit of Grisaia: Side Episode
+PCSE01305 The House in Fata Morgana
+PCSG00677 The IdolM@ster Must Songs - Aka-Ban
+PCSG00678 The IdolM@ster Must Songs - Ao-Ban
+PCSE00441 The Keeper of 4 Elements
+PCSE01224 THE KING OF FIGHTERS '97 GLOBAL MATCH
+PCSG00508 The Labyrinth of Grisaia -LE EDEN DE LA GRISAIA-
+PCSH10113 The Legend of Heroes AO NO KISEKI Evolution
+PCSH10111 The Legend of Heroes ZERO NO KISEKI Evolution
+PCSG00490 The Legend of Heroes: Trails in the Sky the Third Evolution
+PCSG00195 The Legend of Heroes: Trails of Cold Steel
+PCSE00786 THE LEGEND OF HEROES: TRAILS OF COLD STEEL
+PCSB00866 THE LEGEND OF HEROES: TRAILS OF COLD STEEL
+PCSG00354 The Legend of Heroes: Trails of Cold Steel II
+PCSE00896 THE LEGEND OF HEROES: TRAILS OF COLD STEEL II
+PCSG00246 The Legend of Heroes: Trails to Azure Evolution
+PCSG90069 The Legend of Heroes: Zero no Kiseki Evolution Free Version
+PCSE00353 The Lego Movie Videogame
+PCSE01162 The Long Reach
+PCSE00993 The Longest Five Minutes
+PCSE01179 The Lost Child
+PCSF00558 The Muppets Movie Adventures
+PCSG01163 The Princess Guide
+PCSG01235 The Princess, the Stray Cat, and Matters of the Heart 2
+PCSE00775 The Quiet Collection
+PCSE00631 The Sun and Moon
+PCSB00489 The Swapper
+PCSE01388 The Tower of Beatrice
+PCSB01347 The Tower of Beatrice
+PCSE00436 The Treasures of Montezuma 4
+PCSE00027 The Treasures of Montezuma Blitz
+PCSA00158 The Unfinished Swan
+PCSE00316 The Walking Dead
+PCSB00411 The Walking Dead
+PCSE00556 The Walking Dead Season 2
+PCSE00352 The Wolf Among Us
+PCSE00258 Thomas Was Alone
+PCSE00774 Three Fourths Home (Extended Edition)
+PCSE01463 Thunder Paw
+PCSE01416 Thy Sword
+PCSB01396 Tic-Tac-Letters by POWGI
+PCSE01430 Tic-Tac-Letters by POWGI
+PCSH10212 Tic-Tac-Letters by POWGI
+PCSG90164 Time Avengers Demo
+PCSE01186 Time Recoil
+PCSG00062 TIME TRAVELERS
+PCSG00966 Timepiece Ensemble
+PCSE01246 Timespinner
+PCSB00552 Tiny Troopers Joint Ops
+PCSE00388 Titan Attacks!
+PCSE00597 Titan Souls
+PCSG00575 To Heart 2: Dungeon Travelers
+PCSG00330 To Love-Ru Trouble Darkness: Battle Ecstasy
+PCSG00689 To Love-Ru Trouble Darkness: True Princess
+PCSG01089 Toaru Majutsu no Virtual-On
+PCSG01015 Tokeijikake no Ley Line: Kagerou ni Samayou Majo
+PCSG00087 Tokushu Houdoubu
+PCSG01103 Tokyo Clanpool
+PCSG90298 Tokyo Clanpool Trial
+PCSG00615 Tokyo Ghoul: Jail
+PCSG00631 Tokyo Onmyouji: Tengen Jibashi - Rei no Baai - V Edition
+PCSE01150 TOKYO TATTOO GIRLS
+PCSB01161 TOKYO TATTOO GIRLS
+PCSE00924 Tokyo Twilight Ghost Hunters Daybreak: Special Gigs
+PCSG00634 Tokyo Twilight Ghost Hunters: Daybreak Special Gigs
+PCSE00893 Tokyo Xanadu
+PCSG00608 Tokyo Xanadu
+PCSB01062 Tokyo Xanadu
+PCSG01048 TOKYO YAMANOTE BOYS for V MAIN DISC
+PCSG01049 Tokyo Yamanote Boys for V: Fan Disc
+PCSG01135 Tonari ni Kanojo no Iru Shiawase: Two Farce
+PCSG01201 Tonari ni Kanojo no Iru Shiawase: Winter Guest
+PCSF00011 Top Darts
+PCSB00791 Top Trumps Turbo
+PCSG00902 Torikago no Marriage: Hatsukoi no Tsubasa
+PCSA00112 Toro's Friend Network
+PCSE00671 TorqueL
+PCSB00355 Total Recoil
+PCSG00113 Tottemo E Mahjong
+PCSG00593 Touch Battle Sensha SP
+PCSE00016 Touch My Katamari
+PCSB00047 Touch My Katamari
+PCSE01015 TOUHOU DOUBLE FOCUS
+PCSG00977 Touhou Genso Maroku W: The Devil of Decline
+PCSE00990 TOUHOU Genso Wanderer
+PCSG00985 Touhou Genso Wanderer TOD -RELOADED-
+PCSE01104 Touhou Kobuto V: Burst Battle
+PCSG00999 Touhou Koubuto V: Burst Battle
+PCSG00752 Touhou Soujinengi V
+PCSE00940 Toukiden 2
+PCSG00834 Toukiden 2 co-op version
+PCSG00379 Toukiden: Kiwami
+PCSB00574 Toukiden: Kiwami
+PCSE00467 Toukiden: Kiwami
+PCSG00193 Toukiden: The Age of Demons
+PCSE00381 Toukiden: The Age of Demons
+PCSB00918 Towerfall Ascension
+PCSG00488 Trails in the Sky FC Evolution
+PCSG00489 Trails In the Sky SC Evolution
+PCSA00060 Treasure Park
+PCSC80006 Treasure Park
+PCSB00422 Treasures of Montezuma Arena
+PCSG00515 Trillion : God Of Destruction
+PCSB00904 Trillion: God of Destruction
+PCSE00813 Trillion: God of Destruction
+PCSG01023 Tsuihou Senkyo
+PCSG00648 Tsuki ni Yorisou Otome no Sahou: Hidamari no Hibi
+PCSG00152 Tsukiei Academy -kou-
+PCSG01025 Tsukitomo. Tsukiuta 12 Memories
+PCSG01019 Tsumikui: Sen no Noroi, Sen no Inori for V
+PCSE01452 Twin Breaker: A Sacred Symbols Adventure
+PCSE01081 Twin Robots
+PCSE00397 TxK
+PCSE00837 Type:Rider
+PCSC00080 U-NEXT
+PCSG00480 Ukiyo no Roushi
+PCSB00070 ULTIMATE MARVEL VS. CAPCOM 3
+PCSG00011 ULTIMATE MARVEL VS. CAPCOM 3
+PCSE00004 ULTIMATE MARVEL VS. CAPCOM 3
+PCSE01487 Ultracore
+PCSE00414 Ultratron
+PCSG00912 Un:BIRTHDAY SONG: Ai o Utau Shinigami - Another Record
+PCSE00822 Uncanny Valley
+PCSF00220 Uncharted: Fight for Fortune™
+PCSC00005 UNCHARTED: Golden Abyss
+PCSF00001 Uncharted: Golden Abyss™
+PCSF00012 Uncharted: Golden Abyss™
+PCSA00029 Uncharted: Golden Abyss™
+PCSD00001 UNCHARTED: Golden Abyss™
+PCSA00088 Uncharted™ Fight for Fortune
+PCSE01144 Under Night In-Birth Exe:Late(st)
+PCSG00964 UNDER NIGHT IN-BIRTH Exe:Late[st]
+PCSB01157 Undertale
+PCSE01116 Undertale
+PCSG01112 UNDERTALE
+PCSE00840 Unepic
+PCSB00841 Unepic
+PCSF00034 Unit 13
+PCSA00014 Unit 13™
+PCSH10310 UnMetal
+PCSG00633 Uppers
+PCSB00038 Urban Trial Freestyle
+PCSE00051 Urban Trial Freestyle
+PCSG01191 Usotsuki Hime to Moumoku Ouji
+PCSG01046 Usotsuki Shangri-La
+PCSG00199 Uta Kumi 575
+PCSG00651 Uta no * Prince-Sama: Music 3
+PCSG00914 Uta no * Prince-Sama: Repeat LOVE
+PCSG00617 Utawarerumono: Mask of Deception
+PCSG00838 Utawarerumono: Mask of Truth (うたわれるもの 二人の白皇)
+PCSE01409 Utawarerumono: Prelude to the Fallen
+PCSG01011 Utsusemi no Meguri
+PCSE00756 VA-11 HALL-A
+PCSB01166 VA-11 HALL-A
+PCSE01223 VA-11 HALL-A
+PCSG01072 VA-11 HALL-A
+PCSE00244 Valhalla Knights 3
+PCSG00307 Valhalla Knights 3 Gold
+PCSE01003 Valkyria Revolution
+PCSB01011 VALKYRIE DRIVE -BHIKKHUNI-
+PCSE00948 VALKYRIE DRIVE -BHIKKHUNI-
+PCSG00467 Vamwolf Cross†
+PCSG01159 Variable Barricade
+PCSE01314 VASARA Collection
+PCSB01133 Vegas Party
+PCSE00712 Velocibox
+PCSB00302 Velocity Ultra
+PCSE00038 Velocity Ultra
+PCSB00410 Velocity®2X
+PCSE00374 Velocity®2X
+PCSG00531 VENUS PROJECT
+PCSE00621 Vertical Drop Heroes HD
+PCSB00031 Virtua Tennis 4
+PCSE00003 Virtua Tennis 4
+PCSB00205 Virtue's Last Reward
+PCSE00506 Vitamin Z
+PCSG01115 VitaminX Destination
+PCSE00913 Volgarr the Viking
+PCSE00760 Volume
+PCSB00810 VVVVVV
+PCSG01084 Wagamama High Spec (ワガママハイスペック)
+PCSE01266 Waking Violet
+PCSG00768 Walpurgis no Uta
+PCSG00790 Wand of Fortune R
+PCSG00938 Wand of Fortune R2
+PCSE00938 Wanderjahr TryAgainOrWalkAway
+PCSE01248 War Theatre
+PCSE01045 Warlock's Tower
+PCSG01018 Warriors All-Stars
+PCSG00209 Warriors Orochi 2 Ultimate
+PCSB00873 WE ARE DOOMED
+NPXS10007 Welcome Park
+PCSC00047 What Did I Do to Deserve This, My Lord?
+PCSB00727 Whispering Willows
+PCSG00249 White Album 2: Shiawase no Mukougawa
+PCSE01032 Windjammers
+PCSG00194 Winning Post 7 2013
+PCSG00545 Winning Post 8 2015
+PCSG00804 Winning Post 8 2016
+PCSG01174 Winning Post 8 2018
+PCSF00007 WipEout® 2048
+PCSA00015 WipEout® 2048
+PCSD00005 WipEout® 2048
+PCSE01516 Witchcrafty
+PCSE01445 Without Escape
+PCSG00511 Wizardry: Torawareshi Bourei no Machi
+PCSG00512 Wizardry: Torawareshi Tomashii no Meikyuu
+PCSE01432 Wizards of Brandel
+PCSE00519 Woah Dave!
+PCSE01453 Word Maze by POWGI
+PCSH10228 Word Maze by POWGI
+PCSB01418 Word Maze by POWGI
+PCSE01286 Word Search by POWGI
+PCSH10166 Word Search by POWGI
+PCSB01267 Word Search by POWGI
+PCSH10168 Word Sudoku by POWGI
+PCSE01339 Word Sudoku by POWGI
+PCSB01307 Word Sudoku by POWGI
+PCSH10179 Word Wheel by POWGI
+PCSB01367 Word Wheel by POWGI
+PCSE01394 Word Wheel by POWGI
+PCSH10180 Wordsweeper by POWGI
+PCSB01366 Wordsweeper by POWGI
+PCSE01395 Wordsweeper by POWGI
+PCSG01088 World Election
+PCSG01114 World End Syndrome
+PCSG00709 World of Final Fantasy
+PCSE00880 WORLD OF FINAL FANTASY
+PCSG00647 World Trigger Borderless Mission
+PCSG00832 World Trigger: Smash Borders
+PCSB00332 WORMS REVOLUTION EXTREME
+PCSE00286 WORMS REVOLUTION EXTREME
+PCSB00204 WRC 3: FIA World Rally Championship
+PCSB00345 WRC 4 FIA WORLD RALLY CHAMPIONSHIP
+PCSE00667 WRC 5 FIA World Rally Championship
+PCSE01477 Wurroom
+PCSE00346 XBLAZE CODE : EMBRYO
+PCSG00463 XBLAZE LOST : MEMORIES
+PCSG00589 XCOM: Enemy Unknown Plus
+PCSE01481 Xeno Crisis
+PCSE01191 Xenon Valkyrie+
+PCSE00897 Xenoraid
+PCSE00694 Xeodrifter™
+PCSG00215 Yahari Game Demo Ore no Seishun Love-Kome wa Machigatteiru.
+PCSG00895 Yahari Game Demo Ore no Seishun Love-Kome wa Machigatteiru. Zoku
+PCSG00800 Yaken no Rodem
+PCSH00147 Yakuza 0! Companion App
+PCSG01080 Yomawari: Midnight Shadows
+PCSB01144 YOMAWARI: MIDNIGHT SHADOWS
+PCSG01120 Yoshiwara Higanbana Kuon no Chigiri
+PCSG01267 your diary +
+PCSC80010 YouTube
+PCSE01033 Ys Origin
+PCSH10049 Ys Origins
+PCSE01103 Ys VIII -Lacrimosa of DANA-
+PCSH00297 Ys VIII -Lacrimosa of DANA-
+PCSG00105 Ys: Memories of Celceta
+PCSH00181 Ys: Memories of Celceta
+PCSG00567 YU-NO: Konoyo no Hate de Koi o Utau Shoujo
+PCSE01462 Yumeutsutsu Re:After
+PCSG01317 Yumeutsutsu Re:After
+PCSG00393 Yumeutsutsu Re:After
+PCSE01461 Yumeutsutsu Re:Master
+PCSG00653 Yunohana SpRING!
+PCSG00909 Yunohana SpRING! ~Cherising Time~
+PCSG00502 Yuuki Yuuna wa Yuusha de Aru: Jukai no Kioku
+PCSG01075 Yuukyuu no Tierblade: Fragments of Memory
+PCSG00808 Yuukyuu no Tierblade: Lost Chronicle
+PCSG00693 Yuusha Shisu
+PCSB00390 Z-Run
+PCSG90316 Zanki Zero trial version
+PCSG01113 Zanki Zero: Last Beginning
+PCSB00094 Zen Pinball 2
+PCSE00050 Zen Pinball 2
+PCSG00883 Zero Escape: 9 Jikan 9 nin 9 no Tobira Zennin Shibo Dos Double Pack
+PCSE01006 Zero Escape: The Nonary Games
+PCSE00085 Zero Escape: Virtue's Last Reward
+PCSE00781 Zero Escape: Zero Time Dilemma
+PCSE01088 Zero Zero Zero Zero
+PCSE01371 Zeroptian Invasion
+PCSG00880 Zettai Kaikyuu Gakuen: Eden with Roses and Phantasm
+PCSG00611 Zettai Meikyuu: Himitsu no Oyayubi Hime
+PCSE00102 Zombie Tycoon 2 : Brainhov's Revenge
diff --git a/packages/emulators/tools/control-gen/control-gen.cpp b/packages/emulators/tools/control-gen/control-gen.cpp
index 62cfc1b1c0..3c06b15215 100644
--- a/packages/emulators/tools/control-gen/control-gen.cpp
+++ b/packages/emulators/tools/control-gen/control-gen.cpp
@@ -7,7 +7,9 @@
int main()
{
- SDL_Init(SDL_INIT_JOYSTICK);
+
+ SDL_GameControllerAddMappingsFromFile("/storage/.config/SDL-GameControllerDB/gamecontrollerdb.txt");
+ SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
atexit(SDL_Quit);
int num_joysticks = SDL_NumJoysticks();
@@ -18,13 +20,17 @@ int main()
if (js)
{
SDL_JoystickGUID guid = SDL_JoystickGetGUID(js);
+ bool is_controller = SDL_IsGameController(i);
+
char guid_str[1024];
SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str));
- const char* name = SDL_JoystickName(js);
-
- printf("controlfolder=\"/storage/.config/gptokeyb\"\nESUDO=\"sudo\"\nESUDOKILL=\"-sudokill\"\nexport SDL_GAMECONTROLLERCONFIG_FILE=\"$controlfolder/gamecontrollerdb.txt\"\nSDLDBFILE=\"${SDL_GAMECONTROLLERCONFIG_FILE}\"\n[ -z \"${SDLDBFILE}\" ] && SDLDBFILE=\"${controlfolder}/gamecontrollerdb.txt\"\nSDLDBUSERFILE=\"/storage/.config/SDL-GameControllerDB/gamecontrollerdb.txt\"\nget_controls() {\nANALOGSTICKS=\"2\"\nDEVICE=\"%s\"\nparam_device=\"%s\"\n}\nGPTOKEYB=\"$controlfolder/gptokeyb $ESUDOKILL\"",
- guid_str, name);
+ if (is_controller)
+ {
+ const char* name = SDL_JoystickName(js);
+ printf("controlfolder=\"/storage/.config/gptokeyb\"\nESUDO=\"sudo\"\nESUDOKILL=\"-sudokill\"\nexport SDL_GAMECONTROLLERCONFIG_FILE=\"$controlfolder/gamecontrollerdb.txt\"\nSDLDBFILE=\"${SDL_GAMECONTROLLERCONFIG_FILE}\"\n[ -z \"${SDLDBFILE}\" ] && SDLDBFILE=\"${controlfolder}/gamecontrollerdb.txt\"\nSDLDBUSERFILE=\"/storage/.config/SDL-GameControllerDB/gamecontrollerdb.txt\"\nget_controls() {\nANALOGSTICKS=\"2\"\nDEVICE=\"%s\"\nparam_device=\"%s\"\n}\nGPTOKEYB=\"$controlfolder/gptokeyb $ESUDOKILL\"",
+ guid_str, name);
+ }
SDL_JoystickClose(js);
}
}
diff --git a/packages/emulators/tools/gamecontrollerdb/config/gamecontrollerdb.txt b/packages/emulators/tools/gamecontrollerdb/config/gamecontrollerdb.txt
index 3cfab694c9..6a2b268a62 100644
--- a/packages/emulators/tools/gamecontrollerdb/config/gamecontrollerdb.txt
+++ b/packages/emulators/tools/gamecontrollerdb/config/gamecontrollerdb.txt
@@ -6,6 +6,7 @@
1900c3ea010000000100000001010000,odroidgo3_joypad,platform:Linux,x:b2,a:b1,b:b0,y:b3,back:b12,start:b13,dpleft:b10,dpdown:b9,dpright:b11,dpup:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b15,rightstick:b16,leftx:a0,lefty:a1,rightx:a2,righty:a3,
19009b4d4b4800000111000000020000,retrogame_joypad,platform:Linux,x:b2,a:b1,b:b0,y:b3,back:b8,start:b9,dpleft:b15,dpdown:b14,dpright:b16,dpup:b13,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a2,righty:a3,
19009b4d4b4800000111000000010000,retrogame_joypad,platform:Linux,x:b2,a:b1,b:b0,y:b3,back:b8,start:b9,dpleft:b15,dpdown:b14,dpright:b16,dpup:b13,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a2,righty:a3,
+0300fcb7341200007856000000000000,JELOS Gamepad,platform:Linux,x:b2,a:b1,b:b0,y:b3,back:b8,start:b9,dpleft:b15,dpdown:b14,dpright:b16,dpup:b13,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,
19009321b0c300000002000010000000,XU10 Gamepad,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,guide:b16,start:b9,dpleft:b14,dpdown:b13,dpright:b15,dpup:b12,leftshoulder:b4,lefttrigger:b7,rightshoulder:b5,righttrigger:b6,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,
190014b3010000009178000000050000,r33s_joypad,platform:Linux,x:b2,a:b1,b:b0,y:b3,back:b8,start:b9,dpleft:b12,dpdown:b11,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,
1900e5914b4800007711000077010000,RGB20S Gamepad,platform:Linux,x:b2,a:b1,b:b0,y:b3,back:b12,start:b13,dpleft:b10,dpdown:b9,dpright:b11,dpup:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b14,rightstick:b15,leftx:a0,lefty:a1,rightx:a2,righty:a3,
diff --git a/packages/emulators/tools/retroarch-joypads/gamepads/JELOS Gamepad.cfg b/packages/emulators/tools/retroarch-joypads/gamepads/JELOS Gamepad.cfg
new file mode 100644
index 0000000000..5347137952
--- /dev/null
+++ b/packages/emulators/tools/retroarch-joypads/gamepads/JELOS Gamepad.cfg
@@ -0,0 +1,29 @@
+input_driver = "udev"
+input_device = "JELOS Gamepad"
+input_vendor_id = "1234"
+input_product_id = "5648"
+input_b_btn = "0"
+input_y_btn = "3"
+input_select_btn = "8"
+input_start_btn = "9"
+input_up_btn = "13"
+input_down_btn = "14"
+input_left_btn = "15"
+input_right_btn = "16"
+input_a_btn = "1"
+input_x_btn = "2"
+input_l_btn = "4"
+input_r_btn = "5"
+input_l2_btn = "6"
+input_r2_btn = "7"
+input_l3_btn = "11"
+input_r3_btn = "12"
+input_l_x_plus_axis = "+0"
+input_l_x_minus_axis = "-0"
+input_l_y_plus_axis = "+1"
+input_l_y_minus_axis = "-1"
+input_r_x_plus_axis = "+3"
+input_r_x_minus_axis = "-3"
+input_r_y_plus_axis = "+4"
+input_r_y_minus_axis = "-4"
+input_gun_trigger_mbtn = "1"
diff --git a/packages/emulators/tools/virtualgamepad/package.mk b/packages/emulators/tools/virtualgamepad/package.mk
new file mode 100644
index 0000000000..7e19e63471
--- /dev/null
+++ b/packages/emulators/tools/virtualgamepad/package.mk
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
+
+PKG_NAME="virtualgamepad"
+PKG_VERSION="a6e8459"
+PKG_LICENSE="GPLv2"
+PKG_SITE="https://github.com/macromorgan/input-wrapper"
+PKG_URL="${PKG_SITE}.git"
+PKG_DEPENDS_TARGET="toolchain linux"
+PKG_TOOLCHAIN="make"
+
+makeinstall_target() {
+ mkdir -p ${INSTALL}/usr/bin
+ cp wrap ${INSTALL}/usr/bin/virtualgamepad
+ chmod 0755 ${INSTALL}/usr/bin/virtualgamepad
+}
+
+post_install() {
+ enable_service virtualgamepad.service
+}
diff --git a/packages/emulators/tools/virtualgamepad/system.d/virtualgamepad.service b/packages/emulators/tools/virtualgamepad/system.d/virtualgamepad.service
new file mode 100644
index 0000000000..23af44bb57
--- /dev/null
+++ b/packages/emulators/tools/virtualgamepad/system.d/virtualgamepad.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=Virtual Gamepad Driver
+
+[Service]
+Type=simple
+ExecStart=/usr/bin/virtualgamepad
+
+[Install]
+WantedBy=multi-user.target
diff --git a/packages/graphics/libdrm/package.mk b/packages/graphics/libdrm/package.mk
index 88f646f6e8..6eb36e16bb 100644
--- a/packages/graphics/libdrm/package.mk
+++ b/packages/graphics/libdrm/package.mk
@@ -34,12 +34,6 @@ listcontains "${GRAPHIC_DRIVERS}" "(r200|r300|r600|radeonsi)" &&
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"
diff --git a/packages/graphics/mesa/package.mk b/packages/graphics/mesa/package.mk
index 2b1a7b09e6..5c300599c6 100644
--- a/packages/graphics/mesa/package.mk
+++ b/packages/graphics/mesa/package.mk
@@ -10,11 +10,17 @@ PKG_TOOLCHAIN="meson"
PKG_PATCH_DIRS+=" ${DEVICE}"
case ${DEVICE} in
- RK3588*)
- PKG_VERSION="120202c675749c5ef81ae4c8cdc30019b4de08f4"
- PKG_SITE="https://gitlab.com/panfork/mesa"
- PKG_URL="${PKG_SITE}.git"
- PKG_GIT_CLONE_BRANCH="csf"
+ RK3588)
+ PKG_VERSION="120202c675749c5ef81ae4c8cdc30019b4de08f4"
+ PKG_SITE="https://gitlab.com/panfork/mesa"
+ PKG_URL="${PKG_SITE}.git"
+ PKG_GIT_CLONE_BRANCH="csf"
+ ;;
+ RK33*|RK3566) #Using upstream dev for panfrost
+ PKG_VERSION="7adc7678a88edccfbd20af2307e7f50e9ed48e47"
+ PKG_SITE="https://gitlab.freedesktop.org/mesa/mesa"
+ PKG_URL="${PKG_SITE}.git"
+ PKG_PATCH_DIRS+=" panfrost"
;;
*)
PKG_VERSION="24.0.0"
@@ -30,6 +36,7 @@ PKG_MESON_OPTS_TARGET="-Dgallium-drivers=${GALLIUM_DRIVERS// /,} \
-Dgallium-omx=disabled \
-Dgallium-nine=false \
-Dgallium-opencl=disabled \
+ -Dgallium-xa=disabled \
-Dshader-cache=enabled \
-Dshared-glapi=enabled \
-Dopengl=true \
@@ -85,12 +92,6 @@ else
PKG_MESON_OPTS_TARGET+=" -Dgallium-va=disabled"
fi
-if listcontains "${GRAPHIC_DRIVERS}" "vmware"; then
- PKG_MESON_OPTS_TARGET+=" -Dgallium-xa=enabled"
-else
- PKG_MESON_OPTS_TARGET+=" -Dgallium-xa=disabled"
-fi
-
if [ "${OPENGLES_SUPPORT}" = "yes" ]; then
PKG_MESON_OPTS_TARGET+=" -Dgles1=enabled -Dgles2=enabled"
else
diff --git a/packages/graphics/qt6/qt6base/package.mk b/packages/graphics/qt6/qt6base/package.mk
index 95059d3497..7e5b3e1990 100644
--- a/packages/graphics/qt6/qt6base/package.mk
+++ b/packages/graphics/qt6/qt6base/package.mk
@@ -34,7 +34,7 @@ PKG_CMAKE_OPTS_HOST+="
pre_configure_target() {
PKG_CMAKE_OPTS_TARGET+="
-GNinja \
- -DQT_HOST_PATH=${PKG_BUILD}/.x86_64-linux-gnu \
+ -DQT_HOST_PATH=${PKG_BUILD}/.x86_64-jelos-linux-gnu \
-DFEATURE_gui=ON \
-DFEATURE_concurrent=OFF \
-DFEATURE_xml=OFF \
diff --git a/packages/graphics/qt6/qt6tools/package.mk b/packages/graphics/qt6/qt6tools/package.mk
index 7474accab0..34b52fccc5 100644
--- a/packages/graphics/qt6/qt6tools/package.mk
+++ b/packages/graphics/qt6/qt6tools/package.mk
@@ -23,7 +23,7 @@ pre_configure_host() {
pre_configure_target() {
PKG_CMAKE_OPTS_TARGET+=" -GNinja \
- -DQT_HOST_PATH=${PKG_BUILD}/.x86_64-linux-gnu \
+ -DQT_HOST_PATH=${PKG_BUILD}/.x86_64-jelos-linux-gnu \
-DQT_FEATURE_linguist=ON \
-DQT_FEATURE_qdbus=ON \
-DQT_DEBUG_FIND_PACKAGE=ON
diff --git a/packages/graphics/qt6/qt6wayland/package.mk b/packages/graphics/qt6/qt6wayland/package.mk
index fc2178e90b..84a7f9ae7d 100644
--- a/packages/graphics/qt6/qt6wayland/package.mk
+++ b/packages/graphics/qt6/qt6wayland/package.mk
@@ -21,7 +21,7 @@ pre_configure_host() {
pre_configure_target() {
PKG_CMAKE_OPTS_TARGET+=" -GNinja \
- -DQT_HOST_PATH=${PKG_BUILD}/.x86_64-linux-gnu \
+ -DQT_HOST_PATH=${PKG_BUILD}/.x86_64-jelos-linux-gnu \
-DQT_DEBUG_FIND_PACKAGE=ON \
-DBUILD_WITH_PCH=OFF \
-DQT_BUILD_EXAMPLES=OFF \
diff --git a/packages/hardware/quirks/devices/AYANEO AYANEO 2S/sleep.d/post/001-fan b/packages/hardware/quirks/devices/AYANEO AYANEO 2S/sleep.d/post/001-fan
new file mode 100644
index 0000000000..84c1f62856
--- /dev/null
+++ b/packages/hardware/quirks/devices/AYANEO AYANEO 2S/sleep.d/post/001-fan
@@ -0,0 +1,7 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
+
+. /etc/profile
+
+systemctl restart fancontrol
diff --git a/packages/hardware/quirks/platforms/RK3566/sleep.d/post/002-freq b/packages/hardware/quirks/devices/AYANEO AYANEO 2S/sleep.d/post/002-freq
similarity index 67%
rename from packages/hardware/quirks/platforms/RK3566/sleep.d/post/002-freq
rename to packages/hardware/quirks/devices/AYANEO AYANEO 2S/sleep.d/post/002-freq
index d5c06cc41f..b8527a4172 100644
--- a/packages/hardware/quirks/platforms/RK3566/sleep.d/post/002-freq
+++ b/packages/hardware/quirks/devices/AYANEO AYANEO 2S/sleep.d/post/002-freq
@@ -12,12 +12,11 @@ if [ ! -n "${OLD_CPU_FREQ}" ]; then
OLD_CPU_FREQ="schedutil"
fi
-OLD_GPU_FREQ=$(get_setting "sleep.gpugovernor")
-if [ ! -n "${OLD_GPU_FREQ}" ]; then
- OLD_GPU_FREQ="simple_ondemand"
-fi
+OLD_GPU_LEVEL=$(get_setting "sleep.gpulevel")
+if [ ! -n "${OLD_GPU_LEVEL}" ]; then
+ OLD_GPU_LEVEL="balanced"
+fi
# Restore old governors.
set_cpu_gov "${OLD_CPU_FREQ}"
-set_dmc_gov "${OLD_CPU_FREQ}"
-set_gpu_gov "${OLD_GPU_FREQ}"
+gpu_performance_level "${OLD_GPU_LEVEL}"
diff --git a/packages/hardware/quirks/devices/AYANEO AYANEO 2S/sleep.d/pre/001-fan b/packages/hardware/quirks/devices/AYANEO AYANEO 2S/sleep.d/pre/001-fan
new file mode 100644
index 0000000000..df3ee2647b
--- /dev/null
+++ b/packages/hardware/quirks/devices/AYANEO AYANEO 2S/sleep.d/pre/001-fan
@@ -0,0 +1,8 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
+
+. /etc/profile
+
+echo 1 >${DEVICE_PWM_FAN}
+echo 0 >${DEVICE_FAN_INPUT}
diff --git a/packages/hardware/quirks/platforms/RK3566/sleep.d/pre/002-freq b/packages/hardware/quirks/devices/AYANEO AYANEO 2S/sleep.d/pre/002-freq
similarity index 76%
rename from packages/hardware/quirks/platforms/RK3566/sleep.d/pre/002-freq
rename to packages/hardware/quirks/devices/AYANEO AYANEO 2S/sleep.d/pre/002-freq
index 4fbe8c64f0..44f3f67bd0 100644
--- a/packages/hardware/quirks/platforms/RK3566/sleep.d/pre/002-freq
+++ b/packages/hardware/quirks/devices/AYANEO AYANEO 2S/sleep.d/pre/002-freq
@@ -8,12 +8,10 @@
### Get the current cpu and gpu governor, save for when the device wakes from sleep.
CUR_CPU_FREQ="$(cat ${CPU_FREQ}/scaling_governor)"
-CUR_GPU_FREQ="$(cat ${GPU_FREQ}/governor)"
-
+CUR_GPU_LEVEL="$(get_gpu_performance_level)"
set_setting sleep.cpugovernor "${CUR_CPU_FREQ}"
-set_setting sleep.gpugovernor "${CUR_GPU_FREQ}"
+set_setting sleep.gpulevel "${CUR_GPU_LEVEL}"
### Set all governors to powersave
set_cpu_gov powersave
-set_dmc_gov powersave
-set_gpu_gov powersave
+gpu_performance_level low
diff --git a/packages/hardware/quirks/devices/Anbernic RG353P/010-governors b/packages/hardware/quirks/devices/Anbernic RG353P/010-governors
deleted file mode 100755
index e1a4622419..0000000000
--- a/packages/hardware/quirks/devices/Anbernic RG353P/010-governors
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
-
-cat </storage/.config/profile.d/010-governors
-CPU_FREQ=("/sys/devices/system/cpu/cpufreq/policy0")
-GPU_FREQ="/sys/devices/platform/fde60000.gpu/devfreq/fde60000.gpu"
-DMC_FREQ="/sys/devices/platform/dmc/devfreq/dmc"
-EOF
diff --git a/packages/hardware/quirks/devices/Anbernic RG353P/030-suspend_mode b/packages/hardware/quirks/devices/Anbernic RG353P/030-suspend_mode
deleted file mode 100755
index 523d9736bb..0000000000
--- a/packages/hardware/quirks/devices/Anbernic RG353P/030-suspend_mode
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
-
-. /etc/profile.d/001-functions
-
-MYSLEEPMODE=$(get_setting system.suspendmode)
-if [ -z "${MYSLEEPMODE}" ]
-then
- /usr/bin/suspendmode mem
-fi
-
-echo s2idle >/sys/power/mem_sleep
-
diff --git a/packages/hardware/quirks/devices/Anbernic RG353P/050-game_configs b/packages/hardware/quirks/devices/Anbernic RG353P/050-game_configs
deleted file mode 100755
index 50b56be0c0..0000000000
--- a/packages/hardware/quirks/devices/Anbernic RG353P/050-game_configs
+++ /dev/null
@@ -1,14 +0,0 @@
-
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2022-present JELOS (https://github.com/JustEnoughLinuxOS)
-
-. /etc/profile
-
-#Set up gzdoom
-if [ ! -d "/storage/.config/gzdoom/" ]; then
- cp -rf /usr/config/gzdoom /storage/.config/
- sed -i '/Joy10=/c\Joy10=togglemap;
- /Joy9=/c\Joy9=menu_main;
- /vid_defheight=/c\vid_defheight=480;
- /vid_defwidth=/c\vid_defwidth=640' /storage/.config/gzdoom/gzdoom.ini
-fi
diff --git a/packages/hardware/quirks/devices/Anbernic RG353P/info.d/001-panel b/packages/hardware/quirks/devices/Anbernic RG353P/info.d/001-panel
index 16eacd8a5b..da49dae9de 100755
--- a/packages/hardware/quirks/devices/Anbernic RG353P/info.d/001-panel
+++ b/packages/hardware/quirks/devices/Anbernic RG353P/info.d/001-panel
@@ -1,11 +1,11 @@
#!/bin/sh
-ID=$(dmesg | grep "panel id:" | sed "s#^.*panel id: ##g")
+ID=$(dmesg | grep "panel")
case ${ID} in
- "30 52")
- ID="v1 (${ID})"
+ *newvision*)
+ ID="v1"
;;
- "38 21")
- ID="v2 (${ID})"
+ *sitronix*)
+ ID="v2"
;;
*)
ID="Unknown"
@@ -15,4 +15,4 @@ esac
if [ -n "${ID}" ]
then
echo "PANEL VERSION: ${ID}"
-fi
+fi
diff --git a/packages/hardware/quirks/devices/Anbernic RG353V/030-suspend_mode b/packages/hardware/quirks/devices/Anbernic RG353V/030-suspend_mode
deleted file mode 100755
index 523d9736bb..0000000000
--- a/packages/hardware/quirks/devices/Anbernic RG353V/030-suspend_mode
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
-
-. /etc/profile.d/001-functions
-
-MYSLEEPMODE=$(get_setting system.suspendmode)
-if [ -z "${MYSLEEPMODE}" ]
-then
- /usr/bin/suspendmode mem
-fi
-
-echo s2idle >/sys/power/mem_sleep
-
diff --git a/packages/hardware/quirks/devices/Anbernic RG353V/info.d/001-panel b/packages/hardware/quirks/devices/Anbernic RG353V/info.d/001-panel
index e4cf3cb554..da49dae9de 100755
--- a/packages/hardware/quirks/devices/Anbernic RG353V/info.d/001-panel
+++ b/packages/hardware/quirks/devices/Anbernic RG353V/info.d/001-panel
@@ -1,10 +1,10 @@
#!/bin/sh
-ID=$(dmesg | grep "panel id:" | sed "s#^.*panel id: ##g")
+ID=$(dmesg | grep "panel")
case ${ID} in
- "30 52")
+ *newvision*)
ID="v1"
;;
- "38 21")
+ *sitronix*)
ID="v2"
;;
*)
@@ -15,4 +15,4 @@ esac
if [ -n "${ID}" ]
then
echo "PANEL VERSION: ${ID}"
-fi
+fi
diff --git a/packages/hardware/quirks/devices/Anbernic RG353VS b/packages/hardware/quirks/devices/Anbernic RG353VS
new file mode 120000
index 0000000000..13b73acc27
--- /dev/null
+++ b/packages/hardware/quirks/devices/Anbernic RG353VS
@@ -0,0 +1 @@
+Anbernic RG353V
\ No newline at end of file
diff --git a/packages/hardware/quirks/devices/Anbernic RG503/010-governors b/packages/hardware/quirks/devices/Anbernic RG503/010-governors
deleted file mode 100755
index e1a4622419..0000000000
--- a/packages/hardware/quirks/devices/Anbernic RG503/010-governors
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
-
-cat </storage/.config/profile.d/010-governors
-CPU_FREQ=("/sys/devices/system/cpu/cpufreq/policy0")
-GPU_FREQ="/sys/devices/platform/fde60000.gpu/devfreq/fde60000.gpu"
-DMC_FREQ="/sys/devices/platform/dmc/devfreq/dmc"
-EOF
diff --git a/packages/hardware/quirks/devices/Anbernic RG503/030-suspend_mode b/packages/hardware/quirks/devices/Anbernic RG503/030-suspend_mode
deleted file mode 100755
index a7a9cbb02e..0000000000
--- a/packages/hardware/quirks/devices/Anbernic RG503/030-suspend_mode
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
-
-. /etc/profile.d/001-functions
-
-MYSLEEPMODE=$(get_setting system.suspendmode)
-if [ -z "${MYSLEEPMODE}" ]
-then
- /usr/bin/suspendmode mem
-fi
-
-echo s2idle >/sys/power/mem_sleep
-
diff --git a/packages/hardware/quirks/devices/Game Console R33S/001-device_config b/packages/hardware/quirks/devices/Game Console R33S/001-device_config
index e326155a6a..4c9d00e3be 100644
--- a/packages/hardware/quirks/devices/Game Console R33S/001-device_config
+++ b/packages/hardware/quirks/devices/Game Console R33S/001-device_config
@@ -11,4 +11,5 @@ DEVICE_PLAYBACK_PATH_HP="SPK"
DEVICE_BRIGHTNESS="128"
DEVICE_PWR_LED_GPIO="77"
DEVICE_TEMP_SENSOR="/sys/devices/virtual/thermal/thermal_zone0/temp"
+DEVICE_DTB_SWITCH="true"
EOF
diff --git a/packages/hardware/quirks/devices/Game Console R36S/001-device_config b/packages/hardware/quirks/devices/Game Console R36S/001-device_config
new file mode 100644
index 0000000000..4c9d00e3be
--- /dev/null
+++ b/packages/hardware/quirks/devices/Game Console R36S/001-device_config
@@ -0,0 +1,15 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
+
+cat </storage/.config/profile.d/001-device_config
+# Device Features
+DEVICE_VOLUMECTL="true"
+DEVICE_POWER_LED="false"
+DEVICE_PLAYBACK_PATH_SPK="HP"
+DEVICE_PLAYBACK_PATH_HP="SPK"
+DEVICE_BRIGHTNESS="128"
+DEVICE_PWR_LED_GPIO="77"
+DEVICE_TEMP_SENSOR="/sys/devices/virtual/thermal/thermal_zone0/temp"
+DEVICE_DTB_SWITCH="true"
+EOF
diff --git a/packages/hardware/quirks/devices/Game Console R36S/002-disable-led b/packages/hardware/quirks/devices/Game Console R36S/002-disable-led
new file mode 100644
index 0000000000..d917e34827
--- /dev/null
+++ b/packages/hardware/quirks/devices/Game Console R36S/002-disable-led
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
+
+. /etc/profile
+
+# Set export GPIO for Power LED
+if [ ! -d "/sys/class/gpio/gpio${DEVICE_PWR_LED_GPIO}" ]; then
+ echo ${DEVICE_PWR_LED_GPIO} > /sys/class/gpio/export
+fi
+
+#Disable blue led on R33S
+echo out >/sys/class/gpio/gpio${DEVICE_PWR_LED_GPIO}/direction
+echo 1 >/sys/class/gpio/gpio${DEVICE_PWR_LED_GPIO}/value
diff --git a/packages/hardware/quirks/devices/Game Console R36S/050-game-configs b/packages/hardware/quirks/devices/Game Console R36S/050-game-configs
new file mode 100644
index 0000000000..cd90a67759
--- /dev/null
+++ b/packages/hardware/quirks/devices/Game Console R36S/050-game-configs
@@ -0,0 +1,59 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2022-present JELOS (https://github.com/JustEnoughLinuxOS)
+
+. /etc/profile
+
+#Set mupen64-plus-sa config for R36S, can use same profile as OGS
+if [ ! -d "/storage/.config/mupen64plus" ]; then
+ mkdir -p "/storage/.config/mupen64plus/"
+ cp -r /usr/local/share/mupen64plus/mupen64plus.cfg* /storage/.config/mupen64plus/
+fi
+if [ -f "/storage/.config/mupen64plus/mupen64plus.cfg.ogs" ]; then
+ rm /storage/.config/mupen64plus/mupen64plus.cfg
+ mv /storage/.config/mupen64plus/mupen64plus.cfg.ogs /storage/.config/mupen64plus/mupen64plus.cfg
+fi
+
+#Set drastic-sa config for R36S (think it can use the same as RG20S)
+if [ ! -d "/storage/.config/drastic" ]; then
+ mkdir -p "/storage/.config/drastic"
+ cp -r "/usr/config/drastic" "/storage/.config/"
+fi
+if [ -f "/storage/.config/drastic/config/drastic.cfg.rgb20s" ]; then
+ rm /storage/.config/drastic/config/drastic.cfg
+ mv /storage/.config/drastic/config/drastic.cfg.rgb20s /storage/.config/drastic/config/drastic.cfg
+fi
+
+#Map ppsspp controls
+if grep R36S -q "/storage/.config/ppsspp/PSP/SYSTEM/controls.ini"
+then
+ exit 1
+else
+cat </storage/.config/ppsspp/PSP/SYSTEM/controls.ini
+#R36S
+[ControlMapping]
+Up = 10-19
+Down = 10-20
+Left = 10-21
+Right = 10-22
+Circle = 10-189
+Cross = 10-190
+Square = 10-188
+Triangle = 10-191
+Start = 10-197
+Select = 10-196
+L = 10-193
+R = 10-192
+An.Up = 10-4003
+An.Down = 10-4002
+An.Left = 10-4001
+An.Right = 10-4000
+Pause = 10-106
+Save State = 10-4010
+Load State = 10-4008
+RightAn.Up = 10-4007
+RightAn.Down = 10-4006
+RightAn.Left = 10-4005
+RightAn.Right = 10-4004
+EOF
+fi
diff --git a/packages/hardware/quirks/devices/Powkiddy RGB10 Max 3/010-governors b/packages/hardware/quirks/devices/Powkiddy RGB10 Max 3/010-governors
deleted file mode 100755
index e1a4622419..0000000000
--- a/packages/hardware/quirks/devices/Powkiddy RGB10 Max 3/010-governors
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
-
-cat </storage/.config/profile.d/010-governors
-CPU_FREQ=("/sys/devices/system/cpu/cpufreq/policy0")
-GPU_FREQ="/sys/devices/platform/fde60000.gpu/devfreq/fde60000.gpu"
-DMC_FREQ="/sys/devices/platform/dmc/devfreq/dmc"
-EOF
diff --git a/packages/hardware/quirks/devices/Powkiddy RGB10 Max 3/030-suspend_mode b/packages/hardware/quirks/devices/Powkiddy RGB10 Max 3/030-suspend_mode
deleted file mode 100755
index 523d9736bb..0000000000
--- a/packages/hardware/quirks/devices/Powkiddy RGB10 Max 3/030-suspend_mode
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
-
-. /etc/profile.d/001-functions
-
-MYSLEEPMODE=$(get_setting system.suspendmode)
-if [ -z "${MYSLEEPMODE}" ]
-then
- /usr/bin/suspendmode mem
-fi
-
-echo s2idle >/sys/power/mem_sleep
-
diff --git a/packages/hardware/quirks/devices/Powkiddy RGB10 Max 3/050-game_configs b/packages/hardware/quirks/devices/Powkiddy RGB10 Max 3/050-game_configs
deleted file mode 100755
index 8fc2c5134d..0000000000
--- a/packages/hardware/quirks/devices/Powkiddy RGB10 Max 3/050-game_configs
+++ /dev/null
@@ -1,17 +0,0 @@
-
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2022-present JELOS (https://github.com/JustEnoughLinuxOS)
-
-. /etc/profile
-
-#Set up gzdoom
-if [ ! -d "/storage/.config/gzdoom/" ]; then
- cp -rf /usr/config/gzdoom /storage/.config/
- sed -i '/Joy10=/c\Joy10=togglemap;
- /Joy9=/c\Joy9=menu_main;
- /vid_defheight=/c\vid_defheight=480;
- /vid_defwidth=/c\vid_defwidth=640' /storage/.config/gzdoom/gzdoom.ini
-fi
-
-#Set Duckstastion SA to rotate
-sed -i '/^Rotate =/c\Rotate = 1' /storage/.config/duckstation/settings.ini
diff --git a/packages/hardware/quirks/devices/Powkiddy RGB30/010-governors b/packages/hardware/quirks/devices/Powkiddy RGB30/010-governors
deleted file mode 100755
index e1a4622419..0000000000
--- a/packages/hardware/quirks/devices/Powkiddy RGB30/010-governors
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
-
-cat </storage/.config/profile.d/010-governors
-CPU_FREQ=("/sys/devices/system/cpu/cpufreq/policy0")
-GPU_FREQ="/sys/devices/platform/fde60000.gpu/devfreq/fde60000.gpu"
-DMC_FREQ="/sys/devices/platform/dmc/devfreq/dmc"
-EOF
diff --git a/packages/hardware/quirks/devices/Powkiddy RGB30/050-audio_path b/packages/hardware/quirks/devices/Powkiddy RGB30/050-audio_path
deleted file mode 100755
index f5860cdb57..0000000000
--- a/packages/hardware/quirks/devices/Powkiddy RGB30/050-audio_path
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
-
-cat </storage/.config/profile.d/002-audio_path
-DEVICE_PLAYBACK_PATH_SPK="HP"
-DEVICE_PLAYBACK_PATH_HP="SPK"
-DEVICE_PLAYBACK_PATH="Playback Path"
-EOF
diff --git a/packages/hardware/quirks/devices/Powkiddy RGB30/050-game_configs b/packages/hardware/quirks/devices/Powkiddy RGB30/050-game_configs
deleted file mode 100755
index 50b56be0c0..0000000000
--- a/packages/hardware/quirks/devices/Powkiddy RGB30/050-game_configs
+++ /dev/null
@@ -1,14 +0,0 @@
-
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2022-present JELOS (https://github.com/JustEnoughLinuxOS)
-
-. /etc/profile
-
-#Set up gzdoom
-if [ ! -d "/storage/.config/gzdoom/" ]; then
- cp -rf /usr/config/gzdoom /storage/.config/
- sed -i '/Joy10=/c\Joy10=togglemap;
- /Joy9=/c\Joy9=menu_main;
- /vid_defheight=/c\vid_defheight=480;
- /vid_defwidth=/c\vid_defwidth=640' /storage/.config/gzdoom/gzdoom.ini
-fi
diff --git a/packages/hardware/quirks/devices/Powkiddy RK2023/010-governors b/packages/hardware/quirks/devices/Powkiddy RK2023/010-governors
deleted file mode 100755
index e1a4622419..0000000000
--- a/packages/hardware/quirks/devices/Powkiddy RK2023/010-governors
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
-
-cat </storage/.config/profile.d/010-governors
-CPU_FREQ=("/sys/devices/system/cpu/cpufreq/policy0")
-GPU_FREQ="/sys/devices/platform/fde60000.gpu/devfreq/fde60000.gpu"
-DMC_FREQ="/sys/devices/platform/dmc/devfreq/dmc"
-EOF
diff --git a/packages/hardware/quirks/devices/Powkiddy RK2023/030-suspend_mode b/packages/hardware/quirks/devices/Powkiddy RK2023/030-suspend_mode
deleted file mode 100755
index 523d9736bb..0000000000
--- a/packages/hardware/quirks/devices/Powkiddy RK2023/030-suspend_mode
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
-
-. /etc/profile.d/001-functions
-
-MYSLEEPMODE=$(get_setting system.suspendmode)
-if [ -z "${MYSLEEPMODE}" ]
-then
- /usr/bin/suspendmode mem
-fi
-
-echo s2idle >/sys/power/mem_sleep
-
diff --git a/packages/hardware/quirks/devices/Powkiddy RK2023/050-audio_path b/packages/hardware/quirks/devices/Powkiddy RK2023/050-audio_path
deleted file mode 100755
index f5860cdb57..0000000000
--- a/packages/hardware/quirks/devices/Powkiddy RK2023/050-audio_path
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
-
-cat </storage/.config/profile.d/002-audio_path
-DEVICE_PLAYBACK_PATH_SPK="HP"
-DEVICE_PLAYBACK_PATH_HP="SPK"
-DEVICE_PLAYBACK_PATH="Playback Path"
-EOF
diff --git a/packages/hardware/quirks/devices/Powkiddy RK2023/050-game_configs b/packages/hardware/quirks/devices/Powkiddy RK2023/050-game_configs
deleted file mode 100755
index 50b56be0c0..0000000000
--- a/packages/hardware/quirks/devices/Powkiddy RK2023/050-game_configs
+++ /dev/null
@@ -1,14 +0,0 @@
-
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2022-present JELOS (https://github.com/JustEnoughLinuxOS)
-
-. /etc/profile
-
-#Set up gzdoom
-if [ ! -d "/storage/.config/gzdoom/" ]; then
- cp -rf /usr/config/gzdoom /storage/.config/
- sed -i '/Joy10=/c\Joy10=togglemap;
- /Joy9=/c\Joy9=menu_main;
- /vid_defheight=/c\vid_defheight=480;
- /vid_defwidth=/c\vid_defwidth=640' /storage/.config/gzdoom/gzdoom.ini
-fi
diff --git a/packages/hardware/quirks/devices/Powkiddy x55/050-game_configs b/packages/hardware/quirks/devices/Powkiddy x55/050-game_configs
deleted file mode 100755
index 50b56be0c0..0000000000
--- a/packages/hardware/quirks/devices/Powkiddy x55/050-game_configs
+++ /dev/null
@@ -1,14 +0,0 @@
-
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2022-present JELOS (https://github.com/JustEnoughLinuxOS)
-
-. /etc/profile
-
-#Set up gzdoom
-if [ ! -d "/storage/.config/gzdoom/" ]; then
- cp -rf /usr/config/gzdoom /storage/.config/
- sed -i '/Joy10=/c\Joy10=togglemap;
- /Joy9=/c\Joy9=menu_main;
- /vid_defheight=/c\vid_defheight=480;
- /vid_defwidth=/c\vid_defwidth=640' /storage/.config/gzdoom/gzdoom.ini
-fi
diff --git a/packages/hardware/quirks/devices/Powkiddy x55/sleep.d/post/001-audio b/packages/hardware/quirks/devices/Powkiddy x55/sleep.d/post/001-audio
deleted file mode 100644
index bc699e4522..0000000000
--- a/packages/hardware/quirks/devices/Powkiddy x55/sleep.d/post/001-audio
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
-
-# Workaround for no audio on wake from sleep.
-
-. /etc/profile
-
-DEVICE_HEADPHONE_DEV="/sys/devices/platform/rk-headset/extcon/extcon3/state"
-HEADPHONE_STATE=$(awk 'BEGIN {FS="="} /HEADPHONE/ {print $2}' ${DEVICE_HEADPHONE_DEV})
-
-amixer -c 0 set "MUTE" "MUTE"
-
-amixer -c 0 set "Capture MIC Path" "Main Mic"
-amixer -c 0 set "Capture MIC Path" "MIC OFF"
-
-case ${HEADPHONE_STATE} in
- 1)
- amixer -c 0 set "Playback Path" "${DEVICE_PLAYBACK_PATH_SPK}"
- amixer -c 0 set "Playback Path" "${DEVICE_PLAYBACK_PATH_HP}"
- ;;
- 0)
- amixer -c 0 set "Playback Path" "${DEVICE_PLAYBACK_PATH_HP}"
- amixer -c 0 set "Playback Path" "${DEVICE_PLAYBACK_PATH_SPK}"
- ;;
-esac
-
-amixer -c 0 set "MUTE" "UNMUTE"
diff --git a/packages/hardware/quirks/platforms/RK3399/060-game_settings b/packages/hardware/quirks/platforms/RK3399/060-game_settings
index fa5cd7d07b..f718e077d4 100755
--- a/packages/hardware/quirks/platforms/RK3399/060-game_settings
+++ b/packages/hardware/quirks/platforms/RK3399/060-game_settings
@@ -5,7 +5,7 @@
. /etc/profile.d/001-functions
### Set the default performance scaling mode for a few systems.
-for SYSTEM in dreamcast n64 ports psp psx saturn pcfx cdi
+for SYSTEM in dreamcast n64 ports psp psx saturn pcfx cdi ps2 gamecube
do
CPU_SETTING=$(get_setting ${SYSTEM}.cpugovernor)
if [ -z "${CPU_SETTING}" ]
diff --git a/packages/hardware/quirks/platforms/RK3566/001-device_config b/packages/hardware/quirks/platforms/RK3566/001-device_config
index 1647feaab3..b146a74af3 100755
--- a/packages/hardware/quirks/platforms/RK3566/001-device_config
+++ b/packages/hardware/quirks/platforms/RK3566/001-device_config
@@ -1,6 +1,6 @@
#!/bin/bash
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (C) 2021-present Fewtarius (https://github.com/fewtarius)
cat </storage/.config/profile.d/001-device_config
DEVICE_FAKE_JACKSENSE="false"
diff --git a/packages/hardware/quirks/devices/Anbernic RG353V/010-governors b/packages/hardware/quirks/platforms/RK3566/010-governors
similarity index 67%
rename from packages/hardware/quirks/devices/Anbernic RG353V/010-governors
rename to packages/hardware/quirks/platforms/RK3566/010-governors
index 437984c283..64a383e66b 100755
--- a/packages/hardware/quirks/devices/Anbernic RG353V/010-governors
+++ b/packages/hardware/quirks/platforms/RK3566/010-governors
@@ -5,6 +5,5 @@
cat </storage/.config/profile.d/010-governors
# FREQ governors
CPU_FREQ=("/sys/devices/system/cpu/cpufreq/policy0")
-GPU_FREQ="/sys/devices/platform/ff400000.gpu/devfreq/ff400000.gpu"
-DMC_FREQ="/sys/devices/platform/dmc/devfreq/dmc"
+GPU_FREQ="$(find /sys/devices/platform/*gpu/devfreq -name '*.gpu')"
EOF
diff --git a/packages/hardware/quirks/devices/Powkiddy RGB30/030-suspend_mode b/packages/hardware/quirks/platforms/RK3566/030-suspend_mode
similarity index 87%
rename from packages/hardware/quirks/devices/Powkiddy RGB30/030-suspend_mode
rename to packages/hardware/quirks/platforms/RK3566/030-suspend_mode
index 523d9736bb..a5b3d79e5d 100755
--- a/packages/hardware/quirks/devices/Powkiddy RGB30/030-suspend_mode
+++ b/packages/hardware/quirks/platforms/RK3566/030-suspend_mode
@@ -10,5 +10,3 @@ then
/usr/bin/suspendmode mem
fi
-echo s2idle >/sys/power/mem_sleep
-
diff --git a/packages/hardware/quirks/platforms/RK3566/050-audio_path b/packages/hardware/quirks/platforms/RK3566/050-audio_path
index 5feee6024f..f12a3983e0 100755
--- a/packages/hardware/quirks/platforms/RK3566/050-audio_path
+++ b/packages/hardware/quirks/platforms/RK3566/050-audio_path
@@ -1,9 +1,9 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (C) 2021-present Fewtarius (https://github.com/fewtarius)
cat </storage/.config/profile.d/002-audio_path
DEVICE_PLAYBACK_PATH_SPK="SPK"
DEVICE_PLAYBACK_PATH_HP="HP"
-DEVICE_PLAYBACK_PATH="Playback Path"
+DEVICE_PLAYBACK_PATH="Playback Mux"
EOF
diff --git a/packages/hardware/quirks/platforms/RK3566/050-modifiers b/packages/hardware/quirks/platforms/RK3566/050-modifiers
index e135998332..0796f20fb4 100755
--- a/packages/hardware/quirks/platforms/RK3566/050-modifiers
+++ b/packages/hardware/quirks/platforms/RK3566/050-modifiers
@@ -1,10 +1,10 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (C) 2022-present Fewtarius
cat </storage/.config/profile.d/050-modifiers
DEVICE_KEY_VOLUMEDOWN=114
DEVICE_KEY_VOLUMEUP=115
DEVICE_FUNC_KEYA_MODIFIER="BTN_SELECT"
-DEVICE_FUNC_KEYB_MODIFIER="BTN_MODE"
+DEVICE_FUNC_KEYB_MODIFIER="BTN_START"
EOF
diff --git a/packages/hardware/quirks/platforms/RK3566/050-volume b/packages/hardware/quirks/platforms/RK3566/050-volume
new file mode 100755
index 0000000000..df8bd341e4
--- /dev/null
+++ b/packages/hardware/quirks/platforms/RK3566/050-volume
@@ -0,0 +1,8 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
+
+. /storage/.config/profile.d/001-device_config
+
+# RK3566 devices have a master volume attached to card 0 that needs to be set to 100% on startup.
+amixer -c 1 set "Master" "100%"
diff --git a/packages/hardware/quirks/platforms/RK3566/060-game_settings b/packages/hardware/quirks/platforms/RK3566/060-game_settings
index e4193f877d..3e5395a1d9 100755
--- a/packages/hardware/quirks/platforms/RK3566/060-game_settings
+++ b/packages/hardware/quirks/platforms/RK3566/060-game_settings
@@ -1,6 +1,6 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (C) 2023-present Fewtarius (https://github.com/fewtarius)
. /etc/profile.d/001-functions
. /storage/.config/profile.d/010-governors
diff --git a/packages/hardware/quirks/platforms/RK3566/090-ui_service b/packages/hardware/quirks/platforms/RK3566/090-ui_service
index accf1e59db..eeafb89b2b 100755
--- a/packages/hardware/quirks/platforms/RK3566/090-ui_service
+++ b/packages/hardware/quirks/platforms/RK3566/090-ui_service
@@ -1,8 +1,8 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (C) 2022-present Fewtarius
### Set the default device configuration
cat </storage/.config/profile.d/090-ui_service
-UI_SERVICE="emustation.service"
+UI_SERVICE="weston.service"
EOF
diff --git a/packages/hardware/quirks/platforms/RK3588/060-game_settings b/packages/hardware/quirks/platforms/RK3588/060-game_settings
new file mode 100644
index 0000000000..4d0f5b34ac
--- /dev/null
+++ b/packages/hardware/quirks/platforms/RK3588/060-game_settings
@@ -0,0 +1,35 @@
+
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
+
+. /etc/profile.d/001-functions
+
+### Set the default performance scaling mode for a few systems.
+for SYSTEM in dreamcast n64 ports psp saturn ps2 gamecube
+do
+ CPU_SETTING=$(get_setting ${SYSTEM}.cpugovernor)
+ if [ -z "${CPU_SETTING}" ]
+ then
+ set_setting ${SYSTEM}.cpugovernor performance
+ fi
+ GPU_SETTING=$(get_setting ${SYSTEM}.gpuperf)
+ if [ -z "${GPU_SETTING}" ]
+ then
+ set_setting ${SYSTEM}.gpuperf profile_peak
+ fi
+done
+
+for SYSTEM in gb gbc gba snes nes sms gamegear genesis mastersystem sega32x megadrive segacd megacd
+do
+ CPU_SETTING=$(get_setting ${SYSTEM}.cpugovernor)
+ if [ -z ${CPU_SETTING} ]
+ then
+ set_setting ${SYSTEM}.cpugovernor powersave
+ fi
+ GPU_SETTING=$(get_setting ${SYSTEM}.gpuperf)
+ if [ -z ${GPU_SETTING} ]
+ then
+ set_setting ${SYSTEM}.gpuperf low
+ fi
+done
diff --git a/packages/hardware/quirks/profile.d/999-export b/packages/hardware/quirks/profile.d/999-export
index 816e5bafea..326dd49ee9 100755
--- a/packages/hardware/quirks/profile.d/999-export
+++ b/packages/hardware/quirks/profile.d/999-export
@@ -14,6 +14,7 @@ export SLOW_CORES \
DEVICE_BASE_TDP \
DEVICE_BRIGHTNESS \
DEVICE_BATTERY_LED_STATUS \
+ DEVICE_DTB_SWITCH \
DEVICE_FAKE_JACKSENSE \
DEVICE_FUNC_KEYA_MODIFIER \
DEVICE_FUNC_KEYB_MODIFIER \
diff --git a/packages/jelos/autostart/001-wifi b/packages/jelos/autostart/001-wifi
new file mode 100755
index 0000000000..a61b8c0bca
--- /dev/null
+++ b/packages/jelos/autostart/001-wifi
@@ -0,0 +1,2 @@
+echo "mmc3:0001:1" > /sys/bus/sdio/drivers/rtw_8821cs/unbind
+echo "mmc3:0001:1" > /sys/bus/sdio/drivers/rtw_8821cs/bind
\ No newline at end of file
diff --git a/packages/jelos/sources/post-update b/packages/jelos/sources/post-update
index be8bfa8ece..d4933eab70 100644
--- a/packages/jelos/sources/post-update
+++ b/packages/jelos/sources/post-update
@@ -69,77 +69,12 @@ ln -sf /usr/share/locale /storage/.config/emulationstation/locale >>/var/log/con
### Add items below this line that are safe to remove after a period of time.
################################################################################
-### 20231114 - Update hosts.conf
-grep "127.0.0.1" /storage/.config/hosts.conf >/dev/null 2>&1 || cp /usr/config/hosts.conf /storage/.config/
-
-### 20231127 - Migrate games to overlayfs (updated 20231203)
-NULL=$(cat /proc/mounts | grep -v -e "/storage/roms" 2>/dev/null | grep ${1})
-if [ ! "$?" = 0 ]
-then
- umount /storage/roms
-fi
-GAMECOUNT=$(find /storage/roms -type f | wc -l)
-if [ "${GAMECOUNT}" -gt 20 ] && \
- [ ! -e "/storage/.migrated_games" ]
-then
- echo "Migrating games to overlayfs" >>${LOG}
- tocon "Migrate games to new storage model..."
- if [ -d "/storage/games-internal" ]
- then
- echo "Backing up games-internal" >>${LOG}
- mv /storage/games-internal /storage/games-internal.backup
- fi
- mv /storage/roms /storage/games-internal
- mkdir /storage/roms
- touch /storage/.migrated_games
-else
- echo "Game weight too low (${GAMECOUNT}) or content already migrated." >>${LOG}
-fi
-
-### Migration part 2
-if [ ! -e "/storage/.migrated_games2" ]
-then
- for GAMES in /storage/games-internal /storage/games-external
- do
- if [ ! -d "${GAMES}/roms" ]
- then
- mkdir -p "${GAMES}/roms" 2>/dev/null
- fi
- tocon "Migrate games to new storage model..."
- mv "${GAMES}"/* "${GAMES}/roms/"
- done
- touch /storage/.migrated_games2
-fi
-
-### 20231129 - Don't default to performance.
-EPP=$(get_setting system.power.epp)
-if [ -z "${EPP}" ] || \
- [ "${EPP}" = "performance" ]
-then
- EPP="balance_performance"
- set_setting system.power.epp ${EPP}
-fi
-
-### 20231130 - Replace smb.conf for new overlay mechanism.
-cp -f /usr/config/smb.conf /storage/.config
-
-### 20231202 - Remove stale profile bits if they exist.
-for FILE in 001-deviceconfig 99-mixer
-do
- rm -f /storage/.config/profile.d/${FILE} 2>/dev/null
-done
-
-### 20231203 - Disable merged storage by default.
-MERGED_STORAGE=$(get_setting system.merged.storage)
-if [ -z "${MERGED_STORAGE}" ]
-then
- set_setting system.merged.storage 0
-fi
-
-systemctl restart jelos-automount
-
### 20240111 - Add new jslisten hotkey
if [ -e "/storage/.config/jslisten_hotkeys" ]
then
grep BTN_VOLBRIGHT_HOTKEY /storage/.config/jslisten_hotkeys || echo -e "\nBTN_VOLBRIGHT_HOTKEY=999" >>/storage/.config/jslisten_hotkeys
fi
+
+### 20240207 - Update Vita launchers and data.
+rsync -ah --update /usr/config/vita3k/* /storage/.config/vita3k 2>/dev/null
+rm -f "/storage/.config/vita3k/launcher/Start Vita3K.sh"
diff --git a/packages/jelos/sources/scripts/automount b/packages/jelos/sources/scripts/automount
index 22767b92ff..77c6ce3291 100755
--- a/packages/jelos/sources/scripts/automount
+++ b/packages/jelos/sources/scripts/automount
@@ -75,6 +75,26 @@ function start_ms() {
fi
}
+start_overlay() {
+ if [ -e "/storage/.overlay_unsupported" ]
+ then
+ # If we're not using the overlay, bind mount the external storage path
+ # so we don't need to change any configs.
+ grep ${MOUNT_PATH} /proc/mounts >/dev/null 2>&1
+ if [ ! $? = 0 ]
+ then
+ MOUNT_PATH="/storage/games-internal"
+ fi
+ log $0 "Executing bind mount of ${MOUNT_PATH} to ${OVERLAY_PATH}"
+ mount --bind ${MOUNT_PATH} ${OVERLAY_PATH}
+ exit 0
+ else
+ log $0 "Enabling overlay."
+ systemctl enable storage-roms.mount >/dev/null 2>&1
+ systemctl start storage-roms.mount >/dev/null 2>&1
+ fi
+}
+
if [[ ! "${MOUNT_GAMES}" =~ [0-9] ]]
then
set_setting system.automount 1
diff --git a/packages/jelos/sources/scripts/factoryreset b/packages/jelos/sources/scripts/factoryreset
index 0f28cd0a44..3c2e0a2d84 100755
--- a/packages/jelos/sources/scripts/factoryreset
+++ b/packages/jelos/sources/scripts/factoryreset
@@ -21,6 +21,11 @@ case "${1}" in
sync
systemctl reboot
;;
+ "audio")
+ systemctl stop pipewire-pulse pipewire-pulse.socket pipewire pipewire.socket wireplumber
+ rm -rf /storage/.local/state /storage/.config/pulse /storage/asound*
+ systemctl reboot
+ ;;
"ALL")
swapoff -a 2>/dev/null
umount /storage/roms 2>/dev/null ||:
diff --git a/packages/jelos/sources/scripts/usbgadget b/packages/jelos/sources/scripts/usbgadget
index 7dd5d22c09..9bd431f576 100755
--- a/packages/jelos/sources/scripts/usbgadget
+++ b/packages/jelos/sources/scripts/usbgadget
@@ -46,6 +46,7 @@ usb_start() {
echo $VENDOR > gadget/strings/0x409/manufacturer
echo $MACHINE > gadget/strings/0x409/product
+
if [ "${USB_MODE}" = mtp ] ; then
echo 0x1d6b > gadget/idVendor
echo 0x0100 > gadget/idProduct
@@ -55,19 +56,20 @@ usb_start() {
mount mtp -t functionfs /dev/ffs-umtp
/usr/sbin/umtprd &
sleep 1
+ echo "${UDC_NAME}" > gadget/UDC
elif [ "${USB_MODE}" = cdc ] ; then
echo cdc > gadget/configs/c.1/strings/0x409/configuration
echo 0x1d6b > gadget/idVendor
echo 0x104 > gadget/idProduct
ln -s gadget/functions/ecm.usb0 gadget/configs/c.1
+ echo "${UDC_NAME}" > gadget/UDC
ifconfig usb0 $IP up
/usr/sbin/udhcpd -S /storage/.cache/usbgadget/udhcpd.conf
else
exit 0
fi
- echo "${UDC_NAME}" > /sys/kernel/config/usb_gadget/gadget/UDC
echo "USB_MODE=$(cat gadget/configs/c.1/strings/0x409/configuration)" > /storage/.cache/usbgadget/usbgadget.conf
}
diff --git a/packages/kernel/linux-drivers/RTL8188EU/package.mk b/packages/kernel/linux-drivers/RTL8188EU/package.mk
index ef2ef24869..d3c539f977 100644
--- a/packages/kernel/linux-drivers/RTL8188EU/package.mk
+++ b/packages/kernel/linux-drivers/RTL8188EU/package.mk
@@ -3,7 +3,7 @@
# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv)
PKG_NAME="RTL8188EU"
-PKG_VERSION="306f3e62cf7cddf8cee74f70f88a7a7b3af46f56"
+PKG_VERSION="f42fc9c45d2086c415dce70d3018031b54a7beef"
PKG_LICENSE="GPL"
PKG_SITE="https://github.com/lwfinger/rtl8188eu"
PKG_URL="https://github.com/lwfinger/rtl8188eu/archive/${PKG_VERSION}.tar.gz"
diff --git a/packages/kernel/linux-drivers/RTL8812AU/package.mk b/packages/kernel/linux-drivers/RTL8812AU/package.mk
index 3f248dc559..3ed9d0509c 100644
--- a/packages/kernel/linux-drivers/RTL8812AU/package.mk
+++ b/packages/kernel/linux-drivers/RTL8812AU/package.mk
@@ -4,7 +4,7 @@
# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
PKG_NAME="RTL8812AU"
-PKG_VERSION="fe35eddb562bba0d6b3dfaa5991fca0ea22ff915"
+PKG_VERSION="2c4567a67b7aac1d6920af7c0928687553059305"
PKG_LICENSE="GPL"
PKG_SITE="https://github.com/morrownr/8812au-20210629"
PKG_URL="${PKG_SITE}.git"
diff --git a/packages/kernel/linux-drivers/RTL8821AU/package.mk b/packages/kernel/linux-drivers/RTL8821AU/package.mk
index 4da99ae91a..6cdf3dc86d 100644
--- a/packages/kernel/linux-drivers/RTL8821AU/package.mk
+++ b/packages/kernel/linux-drivers/RTL8821AU/package.mk
@@ -4,7 +4,7 @@
# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
PKG_NAME="RTL8821AU"
-PKG_VERSION="cf0f873b795806f755d92e0bac063c26b3b31f12"
+PKG_VERSION="6cd61cfce48218c26b57db4733aa0d3cbf9a2f2c"
PKG_LICENSE="GPL"
PKG_SITE="https://github.com/morrownr/8821au-20210708"
PKG_URL="${PKG_SITE}.git"
diff --git a/packages/kernel/linux-drivers/RTL8821CU/package.mk b/packages/kernel/linux-drivers/RTL8821CU/package.mk
index 12c0a1eec5..13f1e5dbd9 100644
--- a/packages/kernel/linux-drivers/RTL8821CU/package.mk
+++ b/packages/kernel/linux-drivers/RTL8821CU/package.mk
@@ -4,7 +4,7 @@
# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
PKG_NAME="RTL8821CU"
-PKG_VERSION="eb52ece92607394ecc22e96b41671ec3e5b1fa30"
+PKG_VERSION="5b39398e2de146edeb76716420f3288f508bea61"
PKG_LICENSE="GPL"
PKG_SITE="https://github.com/morrownr/8821cu-20210916"
PKG_URL="${PKG_SITE}.git"
diff --git a/packages/kernel/linux-drivers/RTL88x2BU/package.mk b/packages/kernel/linux-drivers/RTL88x2BU/package.mk
index 65bb57416f..d5f8282f40 100644
--- a/packages/kernel/linux-drivers/RTL88x2BU/package.mk
+++ b/packages/kernel/linux-drivers/RTL88x2BU/package.mk
@@ -4,7 +4,7 @@
# Copyright (C) 2023 JELOS (https://github.com/JustEnoughLinuxOS)
PKG_NAME="RTL88x2BU"
-PKG_VERSION="cd2b6cbd9c8fbfebee8a1f28fab8e4434450456c"
+PKG_VERSION="cb741f8b773b76c4eb1858f489b4b141ff586365"
PKG_LICENSE="GPL"
PKG_SITE="https://github.com/morrownr/88x2bu-20210702"
PKG_URL="${PKG_SITE}.git"
diff --git a/packages/kernel/linux-firmware/RTL8723DS-firmware/package.mk b/packages/kernel/linux-firmware/RTL8723DS-firmware/package.mk
index 585976a8f9..3b975ef626 100644
--- a/packages/kernel/linux-firmware/RTL8723DS-firmware/package.mk
+++ b/packages/kernel/linux-firmware/RTL8723DS-firmware/package.mk
@@ -4,7 +4,7 @@
PKG_NAME="RTL8723DS-firmware"
PKG_VERSION=""
PKG_LICENSE="Apache-2.0"
-PKG_SITE="www.jelos.org"
+PKG_SITE="https://jelos.org"
PKG_LONGDESC="Realtek RTL8723DS Linux firmware"
PKG_DEPENDS_TARGET="linux rtk_hciattach"
PKG_TOOLCHAIN="manual"
diff --git a/packages/kernel/linux-firmware/RTL8821CS-firmware/package.mk b/packages/kernel/linux-firmware/RTL8821CS-firmware/package.mk
index 838d310ac0..458f5ea9b9 100644
--- a/packages/kernel/linux-firmware/RTL8821CS-firmware/package.mk
+++ b/packages/kernel/linux-firmware/RTL8821CS-firmware/package.mk
@@ -4,7 +4,7 @@
PKG_NAME="RTL8821CS-firmware"
PKG_VERSION=""
PKG_LICENSE="Apache-2.0"
-PKG_SITE="www.jelos.org"
+PKG_SITE="https://jelos.org"
PKG_LONGDESC="Realtek RTL8821CS Linux firmware"
PKG_DEPENDS_TARGET="linux rtk_hciattach"
PKG_TOOLCHAIN="manual"
diff --git a/packages/kernel/linux-firmware/brcmfmac_sdio-firmware-rpi/package.mk b/packages/kernel/linux-firmware/brcmfmac_sdio-firmware-rpi/package.mk
deleted file mode 100644
index 4d81eb6294..0000000000
--- a/packages/kernel/linux-firmware/brcmfmac_sdio-firmware-rpi/package.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-or-later
-# Copyright (C) 2009-2016 Stephan Raue (stephan@openelec.tv)
-# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv)
-
-PKG_NAME="brcmfmac_sdio-firmware-rpi"
-PKG_VERSION="688531da4bcf802a814d9cb0c8b6d62e3b8a3327"
-PKG_SHA256="51a33d23127300dffd6ac088f372b83ab862053f5e4dc7130676ebaaa824e626"
-PKG_LICENSE="GPL"
-PKG_SITE="https://github.com/LibreELEC/LibreELEC.tv"
-PKG_URL="https://github.com/LibreELEC/${PKG_NAME}/archive/${PKG_VERSION}.tar.gz"
-PKG_DEPENDS_TARGET="toolchain kernel-firmware"
-PKG_LONGDESC="Firmware for brcm bluetooth chips used on RaspberryPi devices."
-PKG_TOOLCHAIN="manual"
-
-makeinstall_target() {
- DESTDIR=${INSTALL}/$(get_kernel_overlay_dir) ./install
-}
-
-post_makeinstall_target() {
- # Install rpi btuart script to bring up Bluetooth
- mkdir -p ${INSTALL}/usr/bin
- cp -P ${PKG_DIR}/scripts/rpi-btuart ${INSTALL}/usr/bin
-}
-
-post_install() {
- enable_service brcmfmac_sdio-firmware.service
-}
diff --git a/packages/kernel/linux-firmware/brcmfmac_sdio-firmware-rpi/scripts/rpi-btuart b/packages/kernel/linux-firmware/brcmfmac_sdio-firmware-rpi/scripts/rpi-btuart
deleted file mode 100755
index b9c6cee09d..0000000000
--- a/packages/kernel/linux-firmware/brcmfmac_sdio-firmware-rpi/scripts/rpi-btuart
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/sh
-
-HCIATTACH=/usr/bin/hciattach
-if grep -q "Pi 4" /proc/device-tree/model; then
- BDADDR=
-else
- SERIAL=$(cat /proc/device-tree/serial-number | cut -c9-)
- B1=${SERIAL:2:2}
- B2=${SERIAL:4:2}
- B3=${SERIAL:6:2}
- BDADDR=$(printf b8:27:eb:%02x:%02x:%02x $((0x$B1 ^ 0xaa)) $((0x$B2 ^ 0xaa)) $((0x$B3 ^ 0xaa)))
-fi
-
-uart0="$(cat /proc/device-tree/aliases/uart0)"
-serial1="$(cat /proc/device-tree/aliases/serial1)"
-
-if [ "$uart0" = "$serial1" ] ; then
- uart0_pins="$(wc -c /proc/device-tree/soc/gpio@7e200000/uart0_pins/brcm\,pins | cut -f 1 -d ' ')"
- if [ "$uart0_pins" = "16" ] ; then
- $HCIATTACH /dev/serial1 bcm43xx 3000000 flow - $BDADDR
- else
- $HCIATTACH /dev/serial1 bcm43xx 921600 noflow - $BDADDR
- fi
-else
- $HCIATTACH /dev/serial1 bcm43xx 460800 noflow - $BDADDR
-fi
diff --git a/packages/kernel/linux-firmware/brcmfmac_sdio-firmware-rpi/system.d/brcmfmac_sdio-firmware.service b/packages/kernel/linux-firmware/brcmfmac_sdio-firmware-rpi/system.d/brcmfmac_sdio-firmware.service
deleted file mode 100644
index 97809c744e..0000000000
--- a/packages/kernel/linux-firmware/brcmfmac_sdio-firmware-rpi/system.d/brcmfmac_sdio-firmware.service
+++ /dev/null
@@ -1,13 +0,0 @@
-[Unit]
-Description=Broadcom sdio firmware update for BCM43430A1
-ConditionFileNotEmpty=/proc/device-tree/soc/gpio@7e200000/bt_pins/brcm,pins
-Requires=dev-serial1.device
-After=dev-serial1.device network.target
-
-[Service]
-Type=simple
-RemainAfterExit=yes
-ExecStart=/usr/bin/rpi-btuart
-
-[Install]
-WantedBy=network.target
diff --git a/packages/kernel/linux-firmware/brcmfmac_sdio-firmware-rpi/udev.d/90-rpi-add-serial.rules b/packages/kernel/linux-firmware/brcmfmac_sdio-firmware-rpi/udev.d/90-rpi-add-serial.rules
deleted file mode 100755
index 334bd37d4b..0000000000
--- a/packages/kernel/linux-firmware/brcmfmac_sdio-firmware-rpi/udev.d/90-rpi-add-serial.rules
+++ /dev/null
@@ -1,21 +0,0 @@
-KERNEL=="ttyAMA[01]", PROGRAM="/bin/sh -c '\
- ALIASES=/proc/device-tree/aliases; \
- if [ $(cat $ALIASES/uart0) = $(cat $ALIASES/serial0) ]; then \
- echo 0;\
- elif [ $(cat $ALIASES/uart0) = $(cat $ALIASES/serial1) ]; then \
- echo 1; \
- else \
- exit 1; \
- fi\
- '", SYMLINK+="serial%c"
-
-KERNEL=="ttyS0", PROGRAM="/bin/sh -c '\
- ALIASES=/proc/device-tree/aliases; \
- if [ $(cat $ALIASES/uart1) = $(cat $ALIASES/serial0) ]; then \
- echo 0; \
- elif [ $(cat $ALIASES/uart1) = $(cat $ALIASES/serial1) ]; then \
- echo 1; \
- else \
- exit 1; \
- fi \
- '", SYMLINK+="serial%c"
diff --git a/packages/kernel/linux-firmware/brcmfmac_sdio-firmware/package.mk b/packages/kernel/linux-firmware/brcmfmac_sdio-firmware/package.mk
index 6f3279598b..0b85537615 100644
--- a/packages/kernel/linux-firmware/brcmfmac_sdio-firmware/package.mk
+++ b/packages/kernel/linux-firmware/brcmfmac_sdio-firmware/package.mk
@@ -6,7 +6,7 @@ PKG_VERSION="c70355f9ec6d015b91a5c3199aa08b433e2f7caf"
PKG_LICENSE="GPL"
PKG_SITE="https://github.com/LibreELEC/brcmfmac_sdio-firmware"
PKG_URL="https://github.com/LibreELEC/brcmfmac_sdio-firmware/archive/${PKG_VERSION}.tar.gz"
-PKG_LONGDESC="Broadcom SDIO firmware used with LibreELEC"
+PKG_LONGDESC="Broadcom SDIO firmware used with JELOS"
PKG_TOOLCHAIN="manual"
post_makeinstall_target() {
diff --git a/packages/kernel/linux-firmware/kernel-firmware/firmwares/any.dat b/packages/kernel/linux-firmware/kernel-firmware/firmwares/any.dat
index 8ad5768aab..d7bae2171e 100644
--- a/packages/kernel/linux-firmware/kernel-firmware/firmwares/any.dat
+++ b/packages/kernel/linux-firmware/kernel-firmware/firmwares/any.dat
@@ -21,3 +21,5 @@ brcm/*
rtl_bt/*
rtlwifi/*
rtw*/*
+
+rtl_nic/*
diff --git a/packages/kernel/linux-firmware/kernel-firmware/package.mk b/packages/kernel/linux-firmware/kernel-firmware/package.mk
index e7f40b7813..ebc338e4b5 100644
--- a/packages/kernel/linux-firmware/kernel-firmware/package.mk
+++ b/packages/kernel/linux-firmware/kernel-firmware/package.mk
@@ -8,6 +8,7 @@ PKG_SITE="https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmwar
PKG_URL="https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/snapshot/linux-firmware-${PKG_VERSION}.tar.gz"
PKG_NEED_UNPACK="${PROJECT_DIR}/${PROJECT}/packages/${PKG_NAME} ${PROJECT_DIR}/${PROJECT}/devices/${DEVICE}/packages/${PKG_NAME}"
PKG_LONGDESC="kernel-firmware: kernel related firmware"
+PKG_DEPENDS_HOST="toolchain"
PKG_TOOLCHAIN="manual"
configure_package() {
@@ -67,14 +68,6 @@ makeinstall_target() {
PKG_KERNEL_CFG_FILE=$(kernel_config_path) || die
- # The following files are RPi specific and installed by brcmfmac_sdio-firmware-rpi instead.
- # They are also not required at all if the kernel is not suitably configured.
- if listcontains "${FIRMWARE}" "brcmfmac_sdio-firmware-rpi" || \
- ! grep -q "^CONFIG_BRCMFMAC_SDIO=y" ${PKG_KERNEL_CFG_FILE}; then
- rm -fr ${FW_TARGET_DIR}/brcm/brcmfmac43430*-sdio.*
- rm -fr ${FW_TARGET_DIR}/brcm/brcmfmac43455*-sdio.*
- fi
-
# brcm pcie firmware is only needed by x86_64
[ "${TARGET_ARCH}" != "x86_64" ] && rm -fr ${FW_TARGET_DIR}/brcm/*-pcie.*
diff --git a/packages/kernel/linux/package.mk b/packages/kernel/linux/package.mk
index 3fdef6a22a..edb340d9e5 100644
--- a/packages/kernel/linux/package.mk
+++ b/packages/kernel/linux/package.mk
@@ -4,7 +4,7 @@
PKG_NAME="linux"
PKG_LICENSE="GPL"
-PKG_VERSION="6.7.3"
+PKG_VERSION="6.7.4"
PKG_URL="https://www.kernel.org/pub/linux/kernel/v6.x/${PKG_NAME}-${PKG_VERSION}.tar.xz"
PKG_SITE="http://www.kernel.org"
PKG_DEPENDS_HOST="ccache:host rdfind:host rsync:host openssl:host"
@@ -19,8 +19,8 @@ PKG_PATCH_DIRS+="${LINUX} ${DEVICE} default"
PKG_KERNEL_CFG_FILE=$(kernel_config_path) || die
if [ -n "${KERNEL_TOOLCHAIN}" ]; then
- PKG_DEPENDS_HOST="${PKG_DEPENDS_HOST} gcc-${KERNEL_TOOLCHAIN}:host"
- PKG_DEPENDS_TARGET="${PKG_DEPENDS_TARGET} gcc-${KERNEL_TOOLCHAIN}:host"
+ PKG_DEPENDS_HOST+=" gcc-${KERNEL_TOOLCHAIN}:host"
+ PKG_DEPENDS_TARGET+=" gcc-${KERNEL_TOOLCHAIN}:host"
HEADERS_ARCH=${TARGET_ARCH}
fi
@@ -30,10 +30,9 @@ if [ "${PKG_BUILD_PERF}" != "no" ] && grep -q ^CONFIG_PERF_EVENTS= ${PKG_KERNEL_
fi
if [[ "${TARGET_ARCH}" =~ i*86|x86_64 ]]; then
- PKG_DEPENDS_TARGET+=" elfutils:host pciutils"
- PKG_DEPENDS_UNPACK+=" intel-ucode kernel-firmware"
+ PKG_DEPENDS_TARGET+=" elfutils:host pciutils intel-ucode kernel-firmware"
elif [ "${TARGET_ARCH}" = "arm" -a "${DEVICE}" = "iMX6" ]; then
- PKG_DEPENDS_UNPACK+=" firmware-imx"
+ PKG_DEPENDS_TARGET+=" firmware-imx"
fi
if [[ "${KERNEL_TARGET}" = uImage* ]]; then
@@ -286,32 +285,6 @@ makeinstall_target() {
cp arch/${TARGET_KERNEL_ARCH}/boot/*dtb.img ${INSTALL}/usr/share/bootloader/ 2>/dev/null || :
[ "${DEVICE}" = "Amlogic-ng" ] && cp arch/${TARGET_KERNEL_ARCH}/boot/dts/amlogic/*.dtb ${INSTALL}/usr/share/bootloader/device_trees 2>/dev/null || :
fi
- elif [ "${BOOTLOADER}" = "bcm2835-bootloader" ]; then
- # RPi firmware will decompress gzipped kernels prior to booting
- if [ "${TARGET_KERNEL_ARCH}" = "arm64" ]; then
- pigz --best --force ${INSTALL}/.image/${KERNEL_TARGET}
- mv ${INSTALL}/.image/${KERNEL_TARGET}.gz ${INSTALL}/.image/${KERNEL_TARGET}
- fi
-
- mkdir -p ${INSTALL}/usr/share/bootloader/overlays
-
- # install platform dtbs, but remove upstream kernel dtbs (i.e. without downstream
- # drivers and decent USB support) as these are not required by LibreELEC
- for dtb in arch/${TARGET_KERNEL_ARCH}/boot/dts/*.dtb arch/${TARGET_KERNEL_ARCH}/boot/dts/*/*.dtb; do
- if [ -f ${dtb} ]; then
- cp -v ${dtb} ${INSTALL}/usr/share/bootloader
- fi
- done
- rm -f ${INSTALL}/usr/share/bootloader/bcm283*.dtb
- # duplicated in overlays below
- safe_remove ${INSTALL}/usr/share/bootloader/overlay_map.dtb
-
- # install overlay dtbs
- for dtb in arch/arm/boot/dts/overlays/*.dtb \
- arch/arm/boot/dts/overlays/*.dtbo; do
- cp ${dtb} ${INSTALL}/usr/share/bootloader/overlays 2>/dev/null || :
- done
- cp -p arch/${TARGET_KERNEL_ARCH}/boot/dts/overlays/README ${INSTALL}/usr/share/bootloader/overlays
fi
makeinstall_host
}
diff --git a/packages/lang/Python3/patches/0029-configure.ac-fixup-CC-print-multiarch-output-for-mus.patch b/packages/lang/Python3/patches/0029-configure.ac-fixup-CC-print-multiarch-output-for-mus.patch
index 5253076d90..f544b9d397 100644
--- a/packages/lang/Python3/patches/0029-configure.ac-fixup-CC-print-multiarch-output-for-mus.patch
+++ b/packages/lang/Python3/patches/0029-configure.ac-fixup-CC-print-multiarch-output-for-mus.patch
@@ -6,17 +6,17 @@ Subject: [PATCH] configure.ac: fixup $CC --print-multiarch output for
GCC commit 6834b83784dcf0364eb820e8 (multiarch support for non-glibc linux
systems), which is part of GCC 8+, changed the multiarch logic to use
-$arch-linux-musl / $arch-linux-uclibc rather than $arch-linux-gnu.
+$arch-linux-musl / $arch-linux-uclibc rather than $arch-jelos-linux-gnu.
This then causes the python3 configure script to error out:
-checking for the platform triplet based on compiler characteristics... powerpc-linux-gnu
+checking for the platform triplet based on compiler characteristics... powerpc-jelos-linux-gnu
configure: error: internal configure error for the platform triplet, please file a bug report
http://autobuild.buildroot.net/results/cb4/cb49c539501342e45cbe5ade82e588fcdf51f05b
As it requires that the --print-multiarch output (if not empty) matches the
-deduced triplet (which always uses -linux-gnu).
+deduced triplet (which always uses -jelos-linux-gnu).
It isn't quite clear why --print-multiarch returns something for a
non-multiarch toolchain on some architectures (E.G. PowerPC), but as a
@@ -41,7 +41,7 @@ index ed03b27fb1..841fd6732c 100644
+ [
+ # GCC 8+ returns $arch-linux-{musl,uclibc} for musl/uClibc based
+ # toolchains confusing python. Fix that up
-+ MULTIARCH=$($CC --print-multiarch 2>/dev/null | sed -E 's/-linux-(musl|uclibc)*$/-linux-gnu/')
++ MULTIARCH=$($CC --print-multiarch 2>/dev/null | sed -E 's/-linux-(musl|uclibc)*$/-jelos-linux-gnu/')
+ ]
)
AC_SUBST([MULTIARCH])
diff --git a/packages/lang/go/patches/go-0001-add-ca-cert-location.patch b/packages/lang/go/patches/go-0001-add-ca-cert-location.patch
index 0ea8d6db6b..fd26bf0b42 100644
--- a/packages/lang/go/patches/go-0001-add-ca-cert-location.patch
+++ b/packages/lang/go/patches/go-0001-add-ca-cert-location.patch
@@ -6,5 +6,5 @@ index ad6ce5cae7..763c686fed 100644
"/etc/ssl/certs", // SLES10/SLES11, https://golang.org/issue/12139
"/etc/pki/tls/certs", // Fedora/RHEL
"/system/etc/security/cacerts", // Android
-+ "/etc/ssl", // LibreELEC
++ "/etc/ssl", // JELOS
}
diff --git a/packages/multimedia/ffmpeg/package.mk b/packages/multimedia/ffmpeg/package.mk
index 218df9a777..adbefe418f 100644
--- a/packages/multimedia/ffmpeg/package.mk
+++ b/packages/multimedia/ffmpeg/package.mk
@@ -10,7 +10,7 @@ PKG_LONGDESC="FFmpeg is a complete, cross-platform solution to record, convert a
PKG_VERSION="6.0"
PKG_URL="http://ffmpeg.org/releases/ffmpeg-${PKG_VERSION}.tar.xz"
-PKG_PATCH_DIRS="kodi libreelec"
+PKG_PATCH_DIRS="jelos"
PKG_PATCH_DIRS+=" v4l2-request v4l2-drmprime"
@@ -133,9 +133,6 @@ pre_configure_target() {
if [ "${FFMPEG_TESTING}" = "yes" ]; then
PKG_FFMPEG_TESTING="--enable-encoder=wrapped_avframe --enable-muxer=null"
- if [ "${PROJECT}" = "RPi" ]; then
- PKG_FFMPEG_TESTING+=" --enable-vout-drm --enable-outdev=vout_drm"
- fi
else
PKG_FFMPEG_TESTING="--disable-programs"
fi
@@ -191,7 +188,6 @@ configure_target() {
${PKG_FFMPEG_V4L2} \
${PKG_FFMPEG_VAAPI} \
${PKG_FFMPEG_VDPAU} \
- ${PKG_FFMPEG_RPI} \
--enable-runtime-cpudetect \
--disable-hardcoded-tables \
--disable-encoders \
diff --git a/packages/multimedia/ffmpeg/patches/libreelec/ffmpeg-001-libreelec.patch b/packages/multimedia/ffmpeg/patches/jelos/ffmpeg-001-jelos.patch
similarity index 100%
rename from packages/multimedia/ffmpeg/patches/libreelec/ffmpeg-001-libreelec.patch
rename to packages/multimedia/ffmpeg/patches/jelos/ffmpeg-001-jelos.patch
diff --git a/packages/multimedia/ffmpeg/patches/rpi/ffmpeg-001-rpi.patch b/packages/multimedia/ffmpeg/patches/rpi/ffmpeg-001-rpi.patch
deleted file mode 100644
index 72cacc605c..0000000000
--- a/packages/multimedia/ffmpeg/patches/rpi/ffmpeg-001-rpi.patch
+++ /dev/null
@@ -1,37792 +0,0 @@
-From 504df93cfe5416b394755e79b7b81ee0119cf09c Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Mon, 26 Apr 2021 12:34:50 +0100
-Subject: [PATCH 001/151] Add pi configs and scripts
-
----
- pi-util/BUILD.txt | 59 ++++++++
- pi-util/NOTES.txt | 69 +++++++++
- pi-util/TESTMESA.txt | 82 +++++++++++
- pi-util/clean_usr_libs.sh | 26 ++++
- pi-util/conf_arm64_native.sh | 45 ++++++
- pi-util/conf_h265.2016.csv | 195 ++++++++++++++++++++++++++
- pi-util/conf_h265.2016_HEVC_v1.csv | 147 ++++++++++++++++++++
- pi-util/conf_h265.csv | 144 +++++++++++++++++++
- pi-util/conf_native.sh | 108 +++++++++++++++
- pi-util/ffconf.py | 215 +++++++++++++++++++++++++++++
- pi-util/ffperf.py | 128 +++++++++++++++++
- pi-util/genpatch.sh | 35 +++++
- pi-util/make_array.py | 23 +++
- pi-util/mkinst.sh | 5 +
- pi-util/patkodi.sh | 9 ++
- pi-util/perfcmp.py | 101 ++++++++++++++
- pi-util/qem.sh | 9 ++
- pi-util/v3dusage.py | 128 +++++++++++++++++
- 18 files changed, 1528 insertions(+)
- create mode 100644 pi-util/BUILD.txt
- create mode 100644 pi-util/NOTES.txt
- create mode 100644 pi-util/TESTMESA.txt
- create mode 100755 pi-util/clean_usr_libs.sh
- create mode 100644 pi-util/conf_arm64_native.sh
- create mode 100644 pi-util/conf_h265.2016.csv
- create mode 100644 pi-util/conf_h265.2016_HEVC_v1.csv
- create mode 100644 pi-util/conf_h265.csv
- create mode 100755 pi-util/conf_native.sh
- create mode 100755 pi-util/ffconf.py
- create mode 100755 pi-util/ffperf.py
- create mode 100755 pi-util/genpatch.sh
- create mode 100755 pi-util/make_array.py
- create mode 100755 pi-util/mkinst.sh
- create mode 100644 pi-util/patkodi.sh
- create mode 100755 pi-util/perfcmp.py
- create mode 100755 pi-util/qem.sh
- create mode 100755 pi-util/v3dusage.py
-
-diff --git a/pi-util/BUILD.txt b/pi-util/BUILD.txt
-new file mode 100644
-index 0000000000..b050971f63
---- /dev/null
-+++ b/pi-util/BUILD.txt
-@@ -0,0 +1,59 @@
-+Building Pi FFmpeg
-+==================
-+
-+Current only building on a Pi is supported.
-+This builds ffmpeg the way I've tested it
-+
-+Get all dependencies - the current package dependencies are good enough
-+
-+$ sudo apt-get build-dep ffmpeg
-+
-+Configure using the pi-util/conf_native.sh script
-+-------------------------------------------------
-+
-+This sets the normal release options and creates an ouutput dir to build into
-+The directory name will depend on system and options but will be under out/
-+
-+There are a few choices here
-+ --mmal build including the legacy mmal-based decoders and zero-copy code
-+ this requires appropriate libraries which currently will exist for
-+ armv7 but not arm64
-+ --noshared
-+ Build a static image rather than a shared library one. Static is
-+ easier for testing as there is no need to worry about library
-+ paths being confused and therefore running the wrong code, Shared
-+ is what is needed, in most cases, when building for use by other
-+ programs.
-+
-+So for a static build
-+---------------------
-+
-+$ pi-util/conf_native.sh --noshared
-+
-+$ make -j8 -C out/
-+
-+You can now run ffmpeg directly from where it was built
-+
-+For a shared build
-+------------------
-+
-+$ pi-util/conf_native.sh
-+
-+You will normally want an install target if shared. Note that the script has
-+set this up to be generated in out//install, you don't have to worry
-+about overwriting your system libs.
-+
-+$ make -j8 -C out/ install
-+
-+You can now set LD_LIBRARY_PATH appropriately and run ffmpeg from where it was
-+built or install the image on the system - you have to be careful to get rid
-+of all other ffmpeg libs or confusion may result. There is a little script
-+that wipes all other versions - obviously use with care!
-+
-+$ sudo pi-util/clean_usr_libs.sh
-+
-+Then simply copying from the install to /usr works
-+
-+$ sudo cp -r out//install/* /usr
-+
-+
-diff --git a/pi-util/NOTES.txt b/pi-util/NOTES.txt
-new file mode 100644
-index 0000000000..fcce72226a
---- /dev/null
-+++ b/pi-util/NOTES.txt
-@@ -0,0 +1,69 @@
-+Notes on the hevc_rpi decoder & associated support code
-+-------------------------------------------------------
-+
-+There are 3 main parts to the existing code:
-+
-+1) The decoder - this is all in libavcodec as rpi_hevc*.
-+
-+2) A few filters to deal with Sand frames and a small patch to
-+automatically select the sand->i420 converter when required.
-+
-+3) A kludge in ffmpeg.c to display the decoded video. This could & should
-+be converted into a proper ffmpeg display module.
-+
-+
-+Decoder
-+-------
-+
-+The decoder is a modified version of the existing ffmpeg hevc decoder.
-+Generally it is ~100% faster than the existing ffmpeg hevc s/w decoder.
-+More complex bitstreams can be up to ~200% faster but particularly easy
-+streams can cut its advantage down to ~50%. This means that a Pi3+ can
-+display nearly all 8-bit 1080p30 streams and with some overclocking it can
-+display most lower bitrate 10-bit 1080p30 streams - this latter case is
-+not helped by the requirement to downsample to 8-bit before display on a
-+Pi.
-+
-+It has had co-processor offload added for inter-pred and large block
-+residual transform. Various parts have had optimized ARM NEON assembler
-+added and the existing ARM asm sections have been profiled and
-+re-optimized for A53. The main C code has been substantially reworked at
-+its lower levels in an attempt to optimize it and minimize memory
-+bandwidth. To some extent code paths that deal with frame types that it
-+doesn't support have been pruned.
-+
-+It outputs frames in Broadcom Sand format. This is a somewhat annoying
-+layout that doesn't fit into ffmpegs standard frame descriptions. It has
-+vertical stripes of 128 horizontal pixels (64 in 10 bit forms) with Y for
-+the stripe followed by interleaved U & V, that is then followed by the Y
-+for the next stripe, etc. The final stripe is always padded to
-+stripe-width. This is used in an attempt to help with cache locality and
-+cut down on the number of dram bank switches. It is annoying to use for
-+inter-pred with conventional processing but the way the Pi QPU (which is
-+used for inter-pred) works means that it has negligible downsides here and
-+the improved memory performance exceeds the overhead of the increased
-+complexity in the rest of the code.
-+
-+Frames must be allocated out of GPU memory (as otherwise they can't be
-+accessed by the co-processors). Utility functions (in rpi_zc.c) have been
-+written to make this easier. As the frames are already in GPU memory they
-+can be displayed by the Pi h/w without any further copying.
-+
-+
-+Known non-features
-+------------------
-+
-+Frame allocation should probably be done in some other way in order to fit
-+into the standard framework better.
-+
-+Sand frames are currently declared as software frames, there is an
-+argument that they should be hardware frames but they aren't really.
-+
-+There must be a better way of auto-selecting the hevc_rpi decoder over the
-+normal s/w hevc decoder, but I became confused by the existing h/w
-+acceleration framework and what I wanted to do didn't seem to fit in
-+neatly.
-+
-+Display should be a proper device rather than a kludge in ffmpeg.c
-+
-+
-diff --git a/pi-util/TESTMESA.txt b/pi-util/TESTMESA.txt
-new file mode 100644
-index 0000000000..92bc13a3df
---- /dev/null
-+++ b/pi-util/TESTMESA.txt
-@@ -0,0 +1,82 @@
-+# Setup & Build instructions for testing Argon30 mesa support (on Pi4)
-+
-+# These assume that the drm_mmal test for Sand8 has been built on this Pi
-+# as build relies on many of the same files
-+
-+# 1st get everything required to build ffmpeg
-+# If sources aren't already enabled on your Pi then enable them
-+sudo su
-+sed "s/#deb-src/deb-src/" /etc/apt/sources.list > /tmp/sources.list
-+sed "s/#deb-src/deb-src/" /etc/apt/sources.list.d/raspi.list > /tmp/raspi.list
-+mv /tmp/sources.list /etc/apt/
-+mv /tmp/raspi.list /etc/apt/sources.list.d/
-+apt update
-+
-+# Get dependancies
-+sudo apt build-dep ffmpeg
-+
-+sudo apt install meson libepoxy-dev libxcb-dri3-dev libxcb1-dev libx11-dev libx11-xcb-dev libdrm-dev
-+
-+# Enable H265 V4L2 request decoder
-+sudo su
-+echo dtoverlay=rpivid-v4l2 >> /boot/config.txt
-+# You may also want to add more CMA if you are going to try 4k videos
-+# Change the dtoverlay=vc4-fkms-v3d line in config.txt to read
-+# dtoverlay=vc4-fkms-v3d,cma-512
-+reboot
-+# Check it has turned up
-+ls -la /dev/video*
-+# This should include video19
-+# crw-rw----+ 1 root video 81, 7 Aug 4 17:25 /dev/video19
-+
-+# Currently on the Pi the linux headers from the debian distro don't match
-+# the kernel that we ship and we need to update them - hopefully this step
-+# will be unneeded in the future
-+sudo apt install git bc bison flex libssl-dev make
-+git clone --depth=1 https://github.com/raspberrypi/linux --branch rpi-5.10.y
-+cd linux
-+KERNEL=kernel7l
-+make bcm2711_defconfig
-+make headers_install
-+sudo cp -r usr/include/linux /usr/include
-+cd ..
-+
-+# Config - this builds a staticly linked ffmpeg which is easier for testing
-+pi-util/conf_native.sh --noshared
-+
-+# Build (this is a bit dull)
-+# If you want to poke the source the libavdevice/egl_vout.c contains the
-+# output code -
-+cd out/armv7-static-rel
-+
-+# Check that you have actually configured V4L2 request
-+grep HEVC_V4L2REQUEST config.h
-+# You are hoping for
-+# #define CONFIG_HEVC_V4L2REQUEST_HWACCEL 1
-+# if you get 0 then the config has failed
-+
-+make -j6
-+
-+# Grab test streams
-+wget http://www.jell.yfish.us/media/jellyfish-3-mbps-hd-h264.mkv
-+wget http://www.jell.yfish.us/media/jellyfish-3-mbps-hd-hevc.mkv
-+wget http://www.jell.yfish.us/media/jellyfish-3-mbps-hd-hevc-10bit.mkv
-+
-+# Test i420 output (works currently)
-+./ffmpeg -no_cvt_hw -vcodec h264_v4l2m2m -i jellyfish-3-mbps-hd-h264.mkv -f vout_egl -
-+
-+# Test Sand8 output - doesn't currently work but should once you have
-+# Sand8 working in drm_mmal. I can't guarantee that this will work as
-+# I can't test this path with a known working format, but the debug looks
-+# good. If this doesn't work & drm_mmal does with sand8 then come back to me
-+# The "show_all 1" forces vout to display every frame otherwise it drops any
-+# frame that would cause it to block
-+./ffmpeg -no_cvt_hw -hwaccel drm -vcodec hevc -i jellyfish-3-mbps-hd-hevc.mkv -show_all 1 -f vout_egl -
-+
-+# Test Sand30 - doesn't currently work
-+# (Beware that when FFmpeg errors out it often leaves your teminal window
-+# in a state where you need to reset it)
-+./ffmpeg -no_cvt_hw -hwaccel drm -vcodec hevc -i jellyfish-3-mbps-hd-hevc-10bit.mkv -f vout_egl -
-+
-+
-+
-diff --git a/pi-util/clean_usr_libs.sh b/pi-util/clean_usr_libs.sh
-new file mode 100755
-index 0000000000..b3b2d5509d
---- /dev/null
-+++ b/pi-util/clean_usr_libs.sh
-@@ -0,0 +1,26 @@
-+set -e
-+U=/usr/lib/arm-linux-gnueabihf
-+rm -f $U/libavcodec.*
-+rm -f $U/libavdevice.*
-+rm -f $U/libavfilter.*
-+rm -f $U/libavformat.*
-+rm -f $U/libavutil.*
-+rm -f $U/libswresample.*
-+rm -f $U/libswscale.*
-+U=/usr/lib/arm-linux-gnueabihf/neon/vfp
-+rm -f $U/libavcodec.*
-+rm -f $U/libavdevice.*
-+rm -f $U/libavfilter.*
-+rm -f $U/libavformat.*
-+rm -f $U/libavutil.*
-+rm -f $U/libswresample.*
-+rm -f $U/libswscale.*
-+U=/usr/lib/aarch64-linux-gnu
-+rm -f $U/libavcodec.*
-+rm -f $U/libavdevice.*
-+rm -f $U/libavfilter.*
-+rm -f $U/libavformat.*
-+rm -f $U/libavutil.*
-+rm -f $U/libswresample.*
-+rm -f $U/libswscale.*
-+
-diff --git a/pi-util/conf_arm64_native.sh b/pi-util/conf_arm64_native.sh
-new file mode 100644
-index 0000000000..9e3bbfa190
---- /dev/null
-+++ b/pi-util/conf_arm64_native.sh
-@@ -0,0 +1,45 @@
-+echo "Configure for ARM64 native build"
-+
-+#RPI_KEEPS="-save-temps=obj"
-+
-+SHARED_LIBS="--enable-shared"
-+if [ "$1" == "--noshared" ]; then
-+ SHARED_LIBS="--disable-shared"
-+ echo Static libs
-+ OUT=out/arm64-static-rel
-+else
-+ echo Shared libs
-+ OUT=out/arm64-shared-rel
-+fi
-+
-+mkdir -p $OUT
-+cd $OUT
-+
-+A=aarch64-linux-gnu
-+USR_PREFIX=`pwd`/install
-+LIB_PREFIX=$USR_PREFIX/lib/$A
-+INC_PREFIX=$USR_PREFIX/include/$A
-+
-+../../configure \
-+ --prefix=$USR_PREFIX\
-+ --libdir=$LIB_PREFIX\
-+ --incdir=$INC_PREFIX\
-+ --disable-stripping\
-+ --disable-thumb\
-+ --disable-mmal\
-+ --enable-sand\
-+ --enable-v4l2-request\
-+ --enable-libdrm\
-+ --enable-epoxy\
-+ --enable-libudev\
-+ --enable-vout-drm\
-+ --enable-vout-egl\
-+ $SHARED_LIBS\
-+ --extra-cflags="-ggdb"
-+
-+# --enable-decoder=hevc_rpi\
-+# --enable-extra-warnings\
-+# --arch=armv71\
-+
-+# gcc option for getting asm listing
-+# -Wa,-ahls
-diff --git a/pi-util/conf_h265.2016.csv b/pi-util/conf_h265.2016.csv
-new file mode 100644
-index 0000000000..4efd5d1c67
---- /dev/null
-+++ b/pi-util/conf_h265.2016.csv
-@@ -0,0 +1,195 @@
-+1,HEVC_v1/AMP_A_Samsung_7,AMP_A_Samsung_7.bin,AMP_A_Samsung_7.md5,8
-+1,HEVC_v1/AMP_B_Samsung_7,AMP_B_Samsung_7.bin,AMP_B_Samsung_7.md5,8
-+1,HEVC_v1/AMP_D_Hisilicon_3,AMP_D_Hisilicon.bit,AMP_D_Hisilicon_3.yuv.md5,8
-+1,HEVC_v1/AMP_E_Hisilicon_3,AMP_E_Hisilicon.bit,AMP_E_Hisilicon_3.yuv.md5,8
-+1,HEVC_v1/AMP_F_Hisilicon_3,AMP_F_Hisilicon_3.bit,AMP_F_Hisilicon_3.yuv.md5,8
-+1,HEVC_v1/AMVP_A_MTK_4,AMVP_A_MTK_4.bit,AMVP_A_MTK_4.md5,8
-+1,HEVC_v1/AMVP_B_MTK_4,AMVP_B_MTK_4.bit,AMVP_B_MTK_4.md5,8
-+1,HEVC_v1/AMVP_C_Samsung_7,AMVP_C_Samsung_7.bin,AMVP_C_Samsung_7.md5,8
-+1,HEVC_v1/BUMPING_A_ericsson_1,BUMPING_A_ericsson_1.bit,BUMPING_A_ericsson_1.md5,8
-+1,HEVC_v1/CAINIT_A_SHARP_4,CAINIT_A_SHARP_4.bit,CAINIT_A_SHARP_4.md5,8
-+1,HEVC_v1/CAINIT_B_SHARP_4,CAINIT_B_SHARP_4.bit,CAINIT_B_SHARP_4.md5,8
-+1,HEVC_v1/CAINIT_C_SHARP_3,CAINIT_C_SHARP_3.bit,CAINIT_C_SHARP_3.md5,8
-+1,HEVC_v1/CAINIT_D_SHARP_3,CAINIT_D_SHARP_3.bit,CAINIT_D_SHARP_3.md5,8
-+1,HEVC_v1/CAINIT_E_SHARP_3,CAINIT_E_SHARP_3.bit,CAINIT_E_SHARP_3.md5,8
-+1,HEVC_v1/CAINIT_F_SHARP_3,CAINIT_F_SHARP_3.bit,CAINIT_F_SHARP_3.md5,8
-+1,HEVC_v1/CAINIT_G_SHARP_3,CAINIT_G_SHARP_3.bit,CAINIT_G_SHARP_3.md5,8
-+1,HEVC_v1/CAINIT_H_SHARP_3,CAINIT_H_SHARP_3.bit,CAINIT_H_SHARP_3.md5,8
-+1,HEVC_v1/CIP_A_Panasonic_3,CIP_A_Panasonic_3.bit,CIP_A_Panasonic_3_yuv.md5,8
-+1,HEVC_v1/cip_B_NEC_3,cip_B_NEC_3.bit,cip_B_NEC_3.md5,8
-+1,HEVC_v1/CIP_C_Panasonic_2,CIP_C_Panasonic_2.bit,CIP_C_Panasonic_2_yuv.md5,8
-+1,HEVC_v1/CONFWIN_A_Sony_1,CONFWIN_A_Sony_1.bit,CONFWIN_A_Sony_1.md5,8
-+1,HEVC_v1/DBLK_A_MAIN10_VIXS_4,DBLK_A_MAIN10_VIXS_4.bit,DBLK_A_MAIN10_VIXS_4.md5,10
-+1,HEVC_v1/DBLK_A_SONY_3,DBLK_A_SONY_3.bit,DBLK_A_SONY_3.bit.yuv.md5,8
-+1,HEVC_v1/DBLK_B_SONY_3,DBLK_B_SONY_3.bit,DBLK_B_SONY_3.bit.yuv.md5,8
-+1,HEVC_v1/DBLK_C_SONY_3,DBLK_C_SONY_3.bit,DBLK_C_SONY_3.bit.yuv.md5,8
-+1,HEVC_v1/DBLK_D_VIXS_2,DBLK_D_VIXS_2.bit,DBLK_D_VIXS_2_yuv.md5,8
-+1,HEVC_v1/DBLK_E_VIXS_2,DBLK_E_VIXS_2.bit,DBLK_E_VIXS_2_yuv.md5,8
-+1,HEVC_v1/DBLK_F_VIXS_2,DBLK_F_VIXS_2.bit,DBLK_F_VIXS_2_yuv.md5,8
-+1,HEVC_v1/DBLK_G_VIXS_2,DBLK_G_VIXS_2.bit,DBLK_G_VIXS_2_yuv.md5,8
-+1,HEVC_v1/DELTAQP_A_BRCM_4,DELTAQP_A_BRCM_4.bit,DELTAQP_A_BRCM_4_yuv.md5,8
-+1,HEVC_v1/DELTAQP_B_SONY_3,DELTAQP_B_SONY_3.bit,DELTAQP_B_SONY_3.bit.yuv.md5,8
-+1,HEVC_v1/DELTAQP_C_SONY_3,DELTAQP_C_SONY_3.bit,DELTAQP_C_SONY_3.bit.yuv.md5,8
-+1,HEVC_v1/DSLICE_A_HHI_5,DSLICE_A_HHI_5.bin,DSLICE_A_HHI_5.md5,8
-+1,HEVC_v1/DSLICE_B_HHI_5,DSLICE_B_HHI_5.bin,DSLICE_B_HHI_5.md5,8
-+1,HEVC_v1/DSLICE_C_HHI_5,DSLICE_C_HHI_5.bin,DSLICE_C_HHI_5.md5,8
-+1,HEVC_v1/ENTP_A_QUALCOMM_1,ENTP_A_Qualcomm_1.bit,ENTP_A_Qualcomm_1.md5,8
-+1,HEVC_v1/ENTP_B_Qualcomm_1,ENTP_B_Qualcomm_1.bit,ENTP_B_Qualcomm_1.md5,8
-+1,HEVC_v1/ENTP_C_Qualcomm_1,ENTP_C_Qualcomm_1.bit,ENTP_C_Qualcomm_1.md5,8
-+1,HEVC_v1/EXT_A_ericsson_4,EXT_A_ericsson_4.bit,EXT_A_ericsson_4.md5,8
-+1,HEVC_v1/FILLER_A_Sony_1,FILLER_A_Sony_1.bit,FILLER_A_Sony_1.md5,8
-+1,HEVC_v1/HRD_A_Fujitsu_3,HRD_A_Fujitsu_3.bin,HRD_A_Fujitsu_3.md5,8
-+1,HEVC_v1/INITQP_A_Sony_1,INITQP_A_Sony_1.bit,INITQP_A_Sony_1.md5,8
-+1,HEVC_v1/INITQP_B_Main10_Sony_1,INITQP_B_Main10_Sony_1.bit,INITQP_B_Main10_Sony_1.md5,10
-+1,HEVC_v1/ipcm_A_NEC_3,ipcm_A_NEC_3.bit,ipcm_A_NEC_3.md5,8
-+1,HEVC_v1/ipcm_B_NEC_3,ipcm_B_NEC_3.bit,ipcm_B_NEC_3.md5,8
-+1,HEVC_v1/ipcm_C_NEC_3,ipcm_C_NEC_3.bit,ipcm_C_NEC_3.md5,8
-+1,HEVC_v1/ipcm_D_NEC_3,ipcm_D_NEC_3.bit,ipcm_D_NEC_3.md5,8
-+1,HEVC_v1/ipcm_E_NEC_2,ipcm_E_NEC_2.bit,ipcm_E_NEC_2.md5,8
-+1,HEVC_v1/IPRED_A_docomo_2,IPRED_A_docomo_2.bit,IPRED_A_docomo_2.md5,8
-+1,HEVC_v1/IPRED_B_Nokia_3,IPRED_B_Nokia_3.bit,IPRED_B_Nokia_3_yuv.md5,8
-+1,HEVC_v1/IPRED_C_Mitsubishi_3,IPRED_C_Mitsubishi_3.bit,IPRED_C_Mitsubishi_3_yuv.md5,8
-+1,HEVC_v1/LS_A_Orange_2,LS_A_Orange_2.bit,LS_A_Orange_2_yuv.md5,8
-+1,HEVC_v1/LS_B_Orange_4,LS_B_Orange_4.bit,LS_B_Orange_4_yuv.md5,8
-+1,HEVC_v1/LTRPSPS_A_Qualcomm_1,LTRPSPS_A_Qualcomm_1.bit,LTRPSPS_A_Qualcomm_1.md5,8
-+1,HEVC_v1/MAXBINS_A_TI_5,MAXBINS_A_TI_5.bit,MAXBINS_A_TI_5_yuv.md5,8
-+1,HEVC_v1/MAXBINS_B_TI_5,MAXBINS_B_TI_5.bit,MAXBINS_B_TI_5_yuv.md5,8
-+1,HEVC_v1/MAXBINS_C_TI_5,MAXBINS_C_TI_5.bit,MAXBINS_C_TI_5_yuv.md5,8
-+1,HEVC_v1/MERGE_A_TI_3,MERGE_A_TI_3.bit,MERGE_A_TI_3.md5,8
-+1,HEVC_v1/MERGE_B_TI_3,MERGE_B_TI_3.bit,MERGE_B_TI_3.md5,8
-+1,HEVC_v1/MERGE_C_TI_3,MERGE_C_TI_3.bit,MERGE_C_TI_3.md5,8
-+1,HEVC_v1/MERGE_D_TI_3,MERGE_D_TI_3.bit,MERGE_D_TI_3.md5,8
-+1,HEVC_v1/MERGE_E_TI_3,MERGE_E_TI_3.bit,MERGE_E_TI_3.md5,8
-+1,HEVC_v1/MERGE_F_MTK_4,MERGE_F_MTK_4.bit,MERGE_F_MTK_4.md5,8
-+1,HEVC_v1/MERGE_G_HHI_4,MERGE_G_HHI_4.bit,MERGE_G_HHI_4.md5,8
-+1,HEVC_v1/MVCLIP_A_qualcomm_3,MVCLIP_A_qualcomm_3.bit,MVCLIP_A_qualcomm_3.yuv.md5,8
-+1,HEVC_v1/MVDL1ZERO_A_docomo_4,MVDL1ZERO_A_docomo_4.bit,MVDL1ZERO_A_docomo_4.md5,8
-+1,HEVC_v1/MVEDGE_A_qualcomm_3,MVEDGE_A_qualcomm_3.bit,MVEDGE_A_qualcomm_3.yuv.md5,8
-+1,HEVC_v1/NoOutPrior_A_Qualcomm_1,NoOutPrior_A_Qualcomm_1.bit,NoOutPrior_A_Qualcomm_1.md5,8
-+1,HEVC_v1/NoOutPrior_B_Qualcomm_1,NoOutPrior_B_Qualcomm_1.bit,NoOutPrior_B_Qualcomm_1.md5,8
-+1,HEVC_v1/NUT_A_ericsson_5,NUT_A_ericsson_5.bit,NUT_A_ericsson_5.md5,8
-+1,HEVC_v1/OPFLAG_A_Qualcomm_1,OPFLAG_A_Qualcomm_1.bit,OPFLAG_A_Qualcomm_1.md5,8
-+1,HEVC_v1/OPFLAG_B_Qualcomm_1,OPFLAG_B_Qualcomm_1.bit,OPFLAG_B_Qualcomm_1.md5,8
-+1,HEVC_v1/OPFLAG_C_Qualcomm_1,OPFLAG_C_Qualcomm_1.bit,OPFLAG_C_Qualcomm_1.md5,8
-+1,HEVC_v1/PICSIZE_A_Bossen_1,PICSIZE_A_Bossen_1.bin,PICSIZE_A_Bossen_1.md5,8
-+1,HEVC_v1/PICSIZE_B_Bossen_1,PICSIZE_B_Bossen_1.bin,PICSIZE_B_Bossen_1.md5,8
-+1,HEVC_v1/PICSIZE_C_Bossen_1,PICSIZE_C_Bossen_1.bin,PICSIZE_C_Bossen_1.md5,8
-+1,HEVC_v1/PICSIZE_D_Bossen_1,PICSIZE_D_Bossen_1.bin,PICSIZE_D_Bossen_1.md5,8
-+1,HEVC_v1/PMERGE_A_TI_3,PMERGE_A_TI_3.bit,PMERGE_A_TI_3.md5,8
-+1,HEVC_v1/PMERGE_B_TI_3,PMERGE_B_TI_3.bit,PMERGE_B_TI_3.md5,8
-+1,HEVC_v1/PMERGE_C_TI_3,PMERGE_C_TI_3.bit,PMERGE_C_TI_3.md5,8
-+1,HEVC_v1/PMERGE_D_TI_3,PMERGE_D_TI_3.bit,PMERGE_D_TI_3.md5,8
-+1,HEVC_v1/PMERGE_E_TI_3,PMERGE_E_TI_3.bit,PMERGE_E_TI_3.md5,8
-+1,HEVC_v1/POC_A_Bossen_3,POC_A_Bossen_3.bin,POC_A_Bossen_3.md5,8
-+1,HEVC_v1/PPS_A_qualcomm_7,PPS_A_qualcomm_7.bit,PPS_A_qualcomm_7.yuv.md5,8
-+1,HEVC_v1/PS_B_VIDYO_3,PS_B_VIDYO_3.bit,PS_B_VIDYO_3_yuv.md5,8
-+1,HEVC_v1/RAP_A_docomo_6,RAP_A_docomo_6.bit,RAP_A_docomo_6.md5,8
-+1,HEVC_v1/RAP_B_Bossen_2,RAP_B_Bossen_2.bit,RAP_B_Bossen_2.md5,8
-+1,HEVC_v1/RPLM_A_qualcomm_4,RPLM_A_qualcomm_4.bit,RPLM_A_qualcomm_4.yuv.md5,8
-+1,HEVC_v1/RPLM_B_qualcomm_4,RPLM_B_qualcomm_4.bit,RPLM_B_qualcomm_4.yuv.md5,8
-+1,HEVC_v1/RPS_A_docomo_5,RPS_A_docomo_5.bit,RPS_A_docomo_5.md5,8
-+1,HEVC_v1/RPS_B_qualcomm_5,RPS_B_qualcomm_5.bit,RPS_B_qualcomm_5.yuv.md5,8
-+1,HEVC_v1/RPS_C_ericsson_5,RPS_C_ericsson_5.bit,RPS_C_ericsson_5.md5,8
-+1,HEVC_v1/RPS_D_ericsson_6,RPS_D_ericsson_6.bit,RPS_D_ericsson_6.md5,8
-+1,HEVC_v1/RPS_E_qualcomm_5,RPS_E_qualcomm_5.bit,RPS_E_qualcomm_5.yuv.md5,8
-+1,HEVC_v1/RPS_F_docomo_2,RPS_F_docomo_2.bit,RPS_F_docomo_2.md5,8
-+1,HEVC_v1/RQT_A_HHI_4,RQT_A_HHI_4.bit,RQT_A_HHI_4.md5,8
-+1,HEVC_v1/RQT_B_HHI_4,RQT_B_HHI_4.bit,RQT_B_HHI_4.md5,8
-+1,HEVC_v1/RQT_C_HHI_4,RQT_C_HHI_4.bit,RQT_C_HHI_4.md5,8
-+1,HEVC_v1/RQT_D_HHI_4,RQT_D_HHI_4.bit,RQT_D_HHI_4.md5,8
-+1,HEVC_v1/RQT_E_HHI_4,RQT_E_HHI_4.bit,RQT_E_HHI_4.md5,8
-+1,HEVC_v1/RQT_F_HHI_4,RQT_F_HHI_4.bit,RQT_F_HHI_4.md5,8
-+1,HEVC_v1/RQT_G_HHI_4,RQT_G_HHI_4.bit,RQT_G_HHI_4.md5,8
-+1,HEVC_v1/SAO_A_MediaTek_4,SAO_A_MediaTek_4.bit,SAO_A_MediaTek_4.md5,8
-+1,HEVC_v1/SAO_B_MediaTek_5,SAO_B_MediaTek_5.bit,SAO_B_MediaTek_5.md5,8
-+1,HEVC_v1/SAO_C_Samsung_5,SAO_C_Samsung_5.bin,SAO_C_Samsung_5.md5,8
-+1,HEVC_v1/SAO_D_Samsung_5,SAO_D_Samsung_5.bin,SAO_D_Samsung_5.md5,8
-+1,HEVC_v1/SAO_E_Canon_4,SAO_E_Canon_4.bit,SAO_E_Canon_4.md5,8
-+1,HEVC_v1/SAO_F_Canon_3,SAO_F_Canon_3.bit,SAO_F_Canon_3.md5,8
-+1,HEVC_v1/SAO_G_Canon_3,SAO_G_Canon_3.bit,SAO_G_Canon_3.md5,8
-+1,HEVC_v1/SAO_H_Parabola_1,SAO_H_Parabola_1.bit,SAO_H_Parabola_1.md5,8
-+1,HEVC_v1/SAODBLK_A_MainConcept_4,SAODBLK_A_MainConcept_4.bin,SAODBLK_A_MainConcept_4_md5.txt,8
-+1,HEVC_v1/SAODBLK_B_MainConcept_4,SAODBLK_B_MainConcept_4.bin,SAODBLK_B_MainConcept_4_md5.txt,8
-+1,HEVC_v1/SDH_A_Orange_4,SDH_A_Orange_4.bit,SDH_A_Orange_4_yuv.md5,8
-+1,HEVC_v1/SLICES_A_Rovi_3,SLICES_A_Rovi_3.bin,SLICES_A_Rovi_3.md5,8
-+1,HEVC_v1/SLIST_A_Sony_5,SLIST_A_Sony_5.bin,SLIST_A_Sony_5_yuv.md5,8
-+1,HEVC_v1/SLIST_B_Sony_9,SLIST_B_Sony_9.bin,SLIST_B_Sony_9_yuv.md5,8
-+1,HEVC_v1/SLIST_C_Sony_4,SLIST_C_Sony_4.bin,SLIST_C_Sony_4_yuv.md5,8
-+1,HEVC_v1/SLIST_D_Sony_9,str.bin,SLIST_D_Sony_9_yuv.md5,8
-+1,HEVC_v1/SLPPLP_A_VIDYO_2,SLPPLP_A_VIDYO_2.bit,SLPPLP_A_VIDYO_2_yuv.md5,8
-+1,HEVC_v1/STRUCT_A_Samsung_7,STRUCT_A_Samsung_7.bin,STRUCT_A_Samsung_7.md5,8
-+1,HEVC_v1/STRUCT_B_Samsung_7,STRUCT_B_Samsung_7.bin,STRUCT_B_Samsung_7.md5,8
-+1,HEVC_v1/TILES_A_Cisco_2,TILES_A_Cisco_2.bin,TILES_A_Cisco_2_yuv.md5,8
-+1,HEVC_v1/TILES_B_Cisco_1,TILES_B_Cisco_1.bin,TILES_B_Cisco_1_yuv.md5,8
-+1,HEVC_v1/TMVP_A_MS_3,TMVP_A_MS_3.bit,TMVP_A_MS_3.yuv.md5,8
-+1,HEVC_v1/TSCL_A_VIDYO_5,TSCL_A_VIDYO_5.bit,TSCL_A_VIDYO_5_yuv.md5,8
-+1,HEVC_v1/TSCL_B_VIDYO_4,TSCL_B_VIDYO_4.bit,TSCL_B_VIDYO_4_yuv.md5,8
-+1,HEVC_v1/TSKIP_A_MS_3,TSKIP_A_MS_3.bit,TSKIP_A_MS_3.yuv.md5,8
-+3,HEVC_v1/TSUNEQBD_A_MAIN10_Technicolor_2,TSUNEQBD_A_MAIN10_Technicolor_2.bit,TSUNEQBD_A_MAIN10_Technicolor_2_yuv.md5, # unequal bit depth,10
-+1,HEVC_v1/TUSIZE_A_Samsung_1,TUSIZE_A_Samsung_1.bin,TUSIZE_A_Samsung_1.md5,8
-+1,HEVC_v1/VPSID_A_VIDYO_2,VPSID_A_VIDYO_2.bit,VPSID_A_VIDYO_2_yuv.md5,8
-+3,HEVC_v1/VPSSPSPPS_A_MainConcept_1,VPSSPSPPS_A_MainConcept_1.bin,VPSSPSPPS_A_MainConcept_1_md5.txt, # ???,8
-+1,HEVC_v1/WP_A_MAIN10_Toshiba_3,WP_A_MAIN10_Toshiba_3.bit,WP_A_MAIN10_Toshiba_3_yuv.md5,10
-+1,HEVC_v1/WP_A_Toshiba_3,WP_A_Toshiba_3.bit,WP_A_Toshiba_3_yuv.md5,8
-+1,HEVC_v1/WP_B_Toshiba_3,WP_B_Toshiba_3.bit,WP_B_Toshiba_3_yuv.md5,8
-+1,HEVC_v1/WP_MAIN10_B_Toshiba_3,WP_MAIN10_B_Toshiba_3.bit,WP_MAIN10_B_Toshiba_3_yuv.md5,10
-+1,HEVC_v1/WPP_A_ericsson_MAIN10_2,WPP_A_ericsson_MAIN10_2.bit,WPP_A_ericsson_MAIN10_yuv.md5,10
-+1,HEVC_v1/WPP_A_ericsson_MAIN_2,WPP_A_ericsson_MAIN_2.bit,WPP_A_ericsson_MAIN_2_yuv.md5,8
-+1,HEVC_v1/WPP_B_ericsson_MAIN10_2,WPP_B_ericsson_MAIN10_2.bit,WPP_B_ericsson_MAIN10_yuv.md5,10
-+1,HEVC_v1/WPP_B_ericsson_MAIN_2,WPP_B_ericsson_MAIN_2.bit,WPP_B_ericsson_MAIN_2_yuv.md5,8
-+1,HEVC_v1/WPP_C_ericsson_MAIN10_2,WPP_C_ericsson_MAIN10_2.bit,WPP_C_ericsson_MAIN10_yuv.md5,10
-+1,HEVC_v1/WPP_C_ericsson_MAIN_2,WPP_C_ericsson_MAIN_2.bit,WPP_C_ericsson_MAIN_2_yuv.md5,8
-+1,HEVC_v1/WPP_D_ericsson_MAIN10_2,WPP_D_ericsson_MAIN10_2.bit,WPP_D_ericsson_MAIN10_yuv.md5,10
-+1,HEVC_v1/WPP_D_ericsson_MAIN_2,WPP_D_ericsson_MAIN_2.bit,WPP_D_ericsson_MAIN_2_yuv.md5,8
-+1,HEVC_v1/WPP_E_ericsson_MAIN10_2,WPP_E_ericsson_MAIN10_2.bit,WPP_E_ericsson_MAIN10_yuv.md5,10
-+1,HEVC_v1/WPP_E_ericsson_MAIN_2,WPP_E_ericsson_MAIN_2.bit,WPP_E_ericsson_MAIN_2_yuv.md5,8
-+1,HEVC_v1/WPP_F_ericsson_MAIN10_2,WPP_F_ericsson_MAIN10_2.bit,WPP_F_ericsson_MAIN10_yuv.md5,10
-+1,HEVC_v1/WPP_F_ericsson_MAIN_2,WPP_F_ericsson_MAIN_2.bit,WPP_F_ericsson_MAIN_2_yuv.md5,8
-+1,RExt/ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_2,ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_2.bit,ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_yuv_2.md5,0
-+0,RExt/Bitdepth_A_RExt_Sony_1,Bitdepth_A_RExt_Sony_1.bin,md5sum.txt,8
-+0,RExt/Bitdepth_B_RExt_Sony_1,Bitdepth_B_RExt_Sony_1.bin,md5sum.txt,8
-+0,RExt/CCP_10bit_RExt_QCOM,CCP_10bit_RExt_QCOM.bin,CCP_10bit_RExt_QCOM_md5sum.txt,10
-+0,RExt/CCP_12bit_RExt_QCOM,CCP_12bit_RExt_QCOM.bin,CCP_12bit_RExt_QCOM_md5sum.txt,8
-+0,RExt/CCP_8bit_RExt_QCOM,CCP_8bit_RExt_QCOM.bin,CCP_8bit_RExt_QCOM_md5sum.txt,8
-+1,RExt/ExplicitRdpcm_A_BBC_1,ExplicitRdpcm_A_BBC_1.bit,md5sum.txt,0
-+0,RExt/ExplicitRdpcm_B_BBC_2,ExplicitRdpcm_B_BBC_1.bit,md5sum.txt,8
-+0,RExt/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_10BIT_RExt_Sony_1,EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_10BIT_RExt_Sony_1.bit,EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_10BIT_RExt_Sony_1.md5,10
-+0,RExt/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_12BIT_RExt_Sony_1,EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_12BIT_RExt_Sony_1.bit,EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_12BIT_RExt_Sony_1.md5,8
-+0,RExt/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_16BIT_RExt_Sony_1,EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_16BIT_RExt_Sony_1.bit,EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_16BIT_RExt_Sony_1.md5,8
-+0,RExt/EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_8BIT_RExt_Sony_1,EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_8BIT_RExt_Sony_1.bit,EXTPREC_HIGHTHROUGHPUT_444_16_INTRA_8BIT_RExt_Sony_1.md5,8
-+0,RExt/EXTPREC_MAIN_444_16_INTRA_10BIT_RExt_Sony_1,EXTPREC_MAIN_444_16_INTRA_10BIT_RExt_Sony_1.bit,EXTPREC_MAIN_444_16_INTRA_10BIT_RExt_Sony_1.md5,10
-+0,RExt/EXTPREC_MAIN_444_16_INTRA_12BIT_RExt_Sony_1,EXTPREC_MAIN_444_16_INTRA_12BIT_RExt_Sony_1.bit,EXTPREC_MAIN_444_16_INTRA_12BIT_RExt_Sony_1.md5,8
-+0,RExt/EXTPREC_MAIN_444_16_INTRA_16BIT_RExt_Sony_1,EXTPREC_MAIN_444_16_INTRA_16BIT_RExt_Sony_1.bit,EXTPREC_MAIN_444_16_INTRA_16BIT_RExt_Sony_1.md5,8
-+0,RExt/EXTPREC_MAIN_444_16_INTRA_8BIT_RExt_Sony_1,EXTPREC_MAIN_444_16_INTRA_8BIT_RExt_Sony_1.bit,EXTPREC_MAIN_444_16_INTRA_8BIT_RExt_Sony_1.md5,8
-+1,RExt/GENERAL_10b_420_RExt_Sony_1,GENERAL_10b_420_RExt_Sony_1.bit,GENERAL_10b_420_RExt_Sony_1.md5,10
-+1,RExt/GENERAL_10b_422_RExt_Sony_1,GENERAL_10b_422_RExt_Sony_1.bit,GENERAL_10b_422_RExt_Sony_1.md5,0
-+1,RExt/GENERAL_10b_444_RExt_Sony_2,GENERAL_10b_444_RExt_Sony_2.bit,GENERAL_10b_444_RExt_Sony_2.md5,0
-+1,RExt/GENERAL_12b_400_RExt_Sony_1,GENERAL_12b_400_RExt_Sony_1.bit,GENERAL_12b_400_RExt_Sony_1.md5,0
-+1,RExt/GENERAL_12b_420_RExt_Sony_1,GENERAL_12b_420_RExt_Sony_1.bit,GENERAL_12b_420_RExt_Sony_1.md5,0
-+1,RExt/GENERAL_12b_422_RExt_Sony_1,GENERAL_12b_422_RExt_Sony_1.bit,GENERAL_12b_422_RExt_Sony_1.md5,0
-+1,RExt/GENERAL_12b_444_RExt_Sony_2,GENERAL_12b_444_RExt_Sony_2.bit,GENERAL_12b_444_RExt_Sony_2.md5,0
-+0,RExt/GENERAL_16b_400_RExt_Sony_1,GENERAL_16b_400_RExt_Sony_1.bit,GENERAL_16b_400_RExt_Sony_1.md5,0
-+0,RExt/GENERAL_16b_444_highThroughput_RExt_Sony_2,GENERAL_16b_444_highThroughput_RExt_Sony_2.bit,GENERAL_16b_444_highThroughput_RExt_Sony_2.md5,8
-+0,RExt/GENERAL_16b_444_RExt_Sony_2,GENERAL_16b_444_RExt_Sony_2.bit,GENERAL_16b_444_RExt_Sony_2.md5,8
-+1,RExt/GENERAL_8b_400_RExt_Sony_1,GENERAL_8b_400_RExt_Sony_1.bit,GENERAL_8b_400_RExt_Sony_1.md5,0
-+1,RExt/GENERAL_8b_420_RExt_Sony_1,GENERAL_8b_420_RExt_Sony_1.bit,GENERAL_8b_420_RExt_Sony_1.md5,8
-+1,RExt/GENERAL_8b_444_RExt_Sony_2,GENERAL_8b_444_RExt_Sony_2.bit,GENERAL_8b_444_RExt_Sony_2.md5,0
-+1,RExt/IPCM_A_RExt_NEC_2,IPCM_A_RExt_NEC_2.bit,IPCM_A_RExt_NEC_2_yuv.md5,0
-+1,RExt/IPCM_B_RExt_NEC,IPCM_B_RExt_NEC.bit,IPCM_B_RExt_NEC_yuv.md5,0
-+1,RExt/Main_422_10_A_RExt_Sony_2,Main_422_10_A_RExt_Sony_2.bin,md5sum.txt,0
-+1,RExt/Main_422_10_B_RExt_Sony_2,Main_422_10_B_RExt_Sony_2.bin,md5sum.txt,0
-+1,RExt/PERSIST_RPARAM_A_RExt_Sony_3,PERSIST_RPARAM_A_RExt_Sony_3.bit,PERSIST_RPARAM_A_RExt_Sony_3.md5,0
-+1,RExt/QMATRIX_A_RExt_Sony_1,QMATRIX_A_RExt_Sony_1.bit,QMATRIX_A_RExt_Sony_1.md5,0
-+0,RExt/SAO_A_RExt_MediaTek_1,SAO_A_RExt_MediaTek_1.bit,SAO_A_RExt_MediaTek_1.md5, # Runs out of memory - could be fixed,8
-+0,RExt/TSCTX_10bit_I_RExt_SHARP_1,TSCTX_10bit_I_RExt_SHARP_1.bin,TSCTX_10bit_I_RExt_SHARP_1.md5,10
-+0,RExt/TSCTX_10bit_RExt_SHARP_1,TSCTX_10bit_RExt_SHARP_1.bin,TSCTX_10bit_RExt_SHARP_1.md5,10
-+0,RExt/TSCTX_12bit_I_RExt_SHARP_1,TSCTX_12bit_I_RExt_SHARP_1.bin,TSCTX_12bit_I_RExt_SHARP_1.md5,8
-+0,RExt/TSCTX_12bit_RExt_SHARP_1,TSCTX_12bit_RExt_SHARP_1.bin,TSCTX_12bit_RExt_SHARP_1.md5,8
-+0,RExt/TSCTX_8bit_I_RExt_SHARP_1,TSCTX_8bit_I_RExt_SHARP_1.bin,TSCTX_8bit_I_RExt_SHARP_1.md5,8
-+0,RExt/TSCTX_8bit_RExt_SHARP_1,TSCTX_8bit_RExt_SHARP_1.bin,TSCTX_8bit_RExt_SHARP_1.md5,8
-+0,RExt/WAVETILES_RExt_Sony_2,WAVETILES_RExt_Sony_2.bit,WAVETILES_RExt_Sony_2.md5,8
-+1,local/sao_cu16_mobile_344x280,sao_cu16_mobile_344x280.265,sao_cu16_mobile_344x280.md5,8
-+1,local/dblk_cu16_mobile_344x280,dblk_cu16_mobile_344x280.265,dblk_cu16_mobile_344x280.md5,8
-+1,local/dblksao_cu16_mobile_344x280,dblksao_cu16_mobile_344x280.265,dblksao_cu16_mobile_344x280.md5,8
-+1,local/dblk_pu32_horses_832x448,dblk_pu32_horses_832x448.265,dblk_pu32_horses_832x448.md5,8
-+1,local/intra_pred_21_laps,intra_pred_21_laps.265,intra_pred_21_laps.md5,8
-diff --git a/pi-util/conf_h265.2016_HEVC_v1.csv b/pi-util/conf_h265.2016_HEVC_v1.csv
-new file mode 100644
-index 0000000000..6082641271
---- /dev/null
-+++ b/pi-util/conf_h265.2016_HEVC_v1.csv
-@@ -0,0 +1,147 @@
-+1,AMP_A_Samsung_7,AMP_A_Samsung_7.bin,AMP_A_Samsung_7.md5
-+1,AMP_B_Samsung_7,AMP_B_Samsung_7.bin,AMP_B_Samsung_7.md5
-+1,AMP_D_Hisilicon_3,AMP_D_Hisilicon.bit,AMP_D_Hisilicon_3.yuv.md5
-+1,AMP_E_Hisilicon_3,AMP_E_Hisilicon.bit,AMP_E_Hisilicon_3.yuv.md5
-+1,AMP_F_Hisilicon_3,AMP_F_Hisilicon_3.bit,AMP_F_Hisilicon_3.yuv.md5
-+1,AMVP_A_MTK_4,AMVP_A_MTK_4.bit,AMVP_A_MTK_4.md5
-+1,AMVP_B_MTK_4,AMVP_B_MTK_4.bit,AMVP_B_MTK_4.md5
-+1,AMVP_C_Samsung_7,AMVP_C_Samsung_7.bin,AMVP_C_Samsung_7.md5
-+1,BUMPING_A_ericsson_1,BUMPING_A_ericsson_1.bit,BUMPING_A_ericsson_1.md5
-+1,CAINIT_A_SHARP_4,CAINIT_A_SHARP_4.bit,CAINIT_A_SHARP_4.md5
-+1,CAINIT_B_SHARP_4,CAINIT_B_SHARP_4.bit,CAINIT_B_SHARP_4.md5
-+1,CAINIT_C_SHARP_3,CAINIT_C_SHARP_3.bit,CAINIT_C_SHARP_3.md5
-+1,CAINIT_D_SHARP_3,CAINIT_D_SHARP_3.bit,CAINIT_D_SHARP_3.md5
-+1,CAINIT_E_SHARP_3,CAINIT_E_SHARP_3.bit,CAINIT_E_SHARP_3.md5
-+1,CAINIT_F_SHARP_3,CAINIT_F_SHARP_3.bit,CAINIT_F_SHARP_3.md5
-+1,CAINIT_G_SHARP_3,CAINIT_G_SHARP_3.bit,CAINIT_G_SHARP_3.md5
-+1,CAINIT_H_SHARP_3,CAINIT_H_SHARP_3.bit,CAINIT_H_SHARP_3.md5
-+1,CIP_A_Panasonic_3,CIP_A_Panasonic_3.bit,CIP_A_Panasonic_3_yuv.md5
-+1,cip_B_NEC_3,cip_B_NEC_3.bit,cip_B_NEC_3.md5
-+1,CIP_C_Panasonic_2,CIP_C_Panasonic_2.bit,CIP_C_Panasonic_2_yuv.md5
-+1,CONFWIN_A_Sony_1,CONFWIN_A_Sony_1.bit,CONFWIN_A_Sony_1.md5
-+1,DBLK_A_MAIN10_VIXS_4,DBLK_A_MAIN10_VIXS_4.bit,DBLK_A_MAIN10_VIXS_4.md5
-+1,DBLK_A_SONY_3,DBLK_A_SONY_3.bit,DBLK_A_SONY_3.bit.yuv.md5
-+1,DBLK_B_SONY_3,DBLK_B_SONY_3.bit,DBLK_B_SONY_3.bit.yuv.md5
-+1,DBLK_C_SONY_3,DBLK_C_SONY_3.bit,DBLK_C_SONY_3.bit.yuv.md5
-+1,DBLK_D_VIXS_2,DBLK_D_VIXS_2.bit,DBLK_D_VIXS_2_yuv.md5
-+1,DBLK_E_VIXS_2,DBLK_E_VIXS_2.bit,DBLK_E_VIXS_2_yuv.md5
-+1,DBLK_F_VIXS_2,DBLK_F_VIXS_2.bit,DBLK_F_VIXS_2_yuv.md5
-+1,DBLK_G_VIXS_2,DBLK_G_VIXS_2.bit,DBLK_G_VIXS_2_yuv.md5
-+1,DELTAQP_A_BRCM_4,DELTAQP_A_BRCM_4.bit,DELTAQP_A_BRCM_4_yuv.md5
-+1,DELTAQP_B_SONY_3,DELTAQP_B_SONY_3.bit,DELTAQP_B_SONY_3.bit.yuv.md5
-+1,DELTAQP_C_SONY_3,DELTAQP_C_SONY_3.bit,DELTAQP_C_SONY_3.bit.yuv.md5
-+1,DSLICE_A_HHI_5,DSLICE_A_HHI_5.bin,DSLICE_A_HHI_5.md5
-+1,DSLICE_B_HHI_5,DSLICE_B_HHI_5.bin,DSLICE_B_HHI_5.md5
-+1,DSLICE_C_HHI_5,DSLICE_C_HHI_5.bin,DSLICE_C_HHI_5.md5
-+1,ENTP_A_QUALCOMM_1,ENTP_A_Qualcomm_1.bit,ENTP_A_Qualcomm_1.md5
-+1,ENTP_B_Qualcomm_1,ENTP_B_Qualcomm_1.bit,ENTP_B_Qualcomm_1.md5
-+1,ENTP_C_Qualcomm_1,ENTP_C_Qualcomm_1.bit,ENTP_C_Qualcomm_1.md5
-+1,EXT_A_ericsson_4,EXT_A_ericsson_4.bit,EXT_A_ericsson_4.md5
-+1,FILLER_A_Sony_1,FILLER_A_Sony_1.bit,FILLER_A_Sony_1.md5
-+1,HRD_A_Fujitsu_3,HRD_A_Fujitsu_3.bin,HRD_A_Fujitsu_3.md5
-+1,INITQP_A_Sony_1,INITQP_A_Sony_1.bit,INITQP_A_Sony_1.md5
-+1,INITQP_B_Main10_Sony_1,INITQP_B_Main10_Sony_1.bit,INITQP_B_Main10_Sony_1.md5
-+1,ipcm_A_NEC_3,ipcm_A_NEC_3.bit,ipcm_A_NEC_3.md5
-+1,ipcm_B_NEC_3,ipcm_B_NEC_3.bit,ipcm_B_NEC_3.md5
-+1,ipcm_C_NEC_3,ipcm_C_NEC_3.bit,ipcm_C_NEC_3.md5
-+1,ipcm_D_NEC_3,ipcm_D_NEC_3.bit,ipcm_D_NEC_3.md5
-+1,ipcm_E_NEC_2,ipcm_E_NEC_2.bit,ipcm_E_NEC_2.md5
-+1,IPRED_A_docomo_2,IPRED_A_docomo_2.bit,IPRED_A_docomo_2.md5
-+1,IPRED_B_Nokia_3,IPRED_B_Nokia_3.bit,IPRED_B_Nokia_3_yuv.md5
-+1,IPRED_C_Mitsubishi_3,IPRED_C_Mitsubishi_3.bit,IPRED_C_Mitsubishi_3_yuv.md5
-+1,LS_A_Orange_2,LS_A_Orange_2.bit,LS_A_Orange_2_yuv.md5
-+1,LS_B_Orange_4,LS_B_Orange_4.bit,LS_B_Orange_4_yuv.md5
-+1,LTRPSPS_A_Qualcomm_1,LTRPSPS_A_Qualcomm_1.bit,LTRPSPS_A_Qualcomm_1.md5
-+1,MAXBINS_A_TI_5,MAXBINS_A_TI_5.bit,MAXBINS_A_TI_5_yuv.md5
-+1,MAXBINS_B_TI_5,MAXBINS_B_TI_5.bit,MAXBINS_B_TI_5_yuv.md5
-+1,MAXBINS_C_TI_5,MAXBINS_C_TI_5.bit,MAXBINS_C_TI_5_yuv.md5
-+1,MERGE_A_TI_3,MERGE_A_TI_3.bit,MERGE_A_TI_3.md5
-+1,MERGE_B_TI_3,MERGE_B_TI_3.bit,MERGE_B_TI_3.md5
-+1,MERGE_C_TI_3,MERGE_C_TI_3.bit,MERGE_C_TI_3.md5
-+1,MERGE_D_TI_3,MERGE_D_TI_3.bit,MERGE_D_TI_3.md5
-+1,MERGE_E_TI_3,MERGE_E_TI_3.bit,MERGE_E_TI_3.md5
-+1,MERGE_F_MTK_4,MERGE_F_MTK_4.bit,MERGE_F_MTK_4.md5
-+1,MERGE_G_HHI_4,MERGE_G_HHI_4.bit,MERGE_G_HHI_4.md5
-+1,MVCLIP_A_qualcomm_3,MVCLIP_A_qualcomm_3.bit,MVCLIP_A_qualcomm_3.yuv.md5
-+1,MVDL1ZERO_A_docomo_4,MVDL1ZERO_A_docomo_4.bit,MVDL1ZERO_A_docomo_4.md5
-+1,MVEDGE_A_qualcomm_3,MVEDGE_A_qualcomm_3.bit,MVEDGE_A_qualcomm_3.yuv.md5
-+1,NoOutPrior_A_Qualcomm_1,NoOutPrior_A_Qualcomm_1.bit,NoOutPrior_A_Qualcomm_1.md5
-+1,NoOutPrior_B_Qualcomm_1,NoOutPrior_B_Qualcomm_1.bit,NoOutPrior_B_Qualcomm_1.md5
-+1,NUT_A_ericsson_5,NUT_A_ericsson_5.bit,NUT_A_ericsson_5.md5
-+1,OPFLAG_A_Qualcomm_1,OPFLAG_A_Qualcomm_1.bit,OPFLAG_A_Qualcomm_1.md5
-+1,OPFLAG_B_Qualcomm_1,OPFLAG_B_Qualcomm_1.bit,OPFLAG_B_Qualcomm_1.md5
-+1,OPFLAG_C_Qualcomm_1,OPFLAG_C_Qualcomm_1.bit,OPFLAG_C_Qualcomm_1.md5
-+1,PICSIZE_A_Bossen_1,PICSIZE_A_Bossen_1.bin,PICSIZE_A_Bossen_1.md5
-+1,PICSIZE_B_Bossen_1,PICSIZE_B_Bossen_1.bin,PICSIZE_B_Bossen_1.md5
-+1,PICSIZE_C_Bossen_1,PICSIZE_C_Bossen_1.bin,PICSIZE_C_Bossen_1.md5
-+1,PICSIZE_D_Bossen_1,PICSIZE_D_Bossen_1.bin,PICSIZE_D_Bossen_1.md5
-+1,PMERGE_A_TI_3,PMERGE_A_TI_3.bit,PMERGE_A_TI_3.md5
-+1,PMERGE_B_TI_3,PMERGE_B_TI_3.bit,PMERGE_B_TI_3.md5
-+1,PMERGE_C_TI_3,PMERGE_C_TI_3.bit,PMERGE_C_TI_3.md5
-+1,PMERGE_D_TI_3,PMERGE_D_TI_3.bit,PMERGE_D_TI_3.md5
-+1,PMERGE_E_TI_3,PMERGE_E_TI_3.bit,PMERGE_E_TI_3.md5
-+1,POC_A_Bossen_3,POC_A_Bossen_3.bin,POC_A_Bossen_3.md5
-+1,PPS_A_qualcomm_7,PPS_A_qualcomm_7.bit,PPS_A_qualcomm_7.yuv.md5
-+1,PS_B_VIDYO_3,PS_B_VIDYO_3.bit,PS_B_VIDYO_3_yuv.md5
-+1,RAP_A_docomo_6,RAP_A_docomo_6.bit,RAP_A_docomo_6.md5
-+1,RAP_B_Bossen_2,RAP_B_Bossen_2.bit,RAP_B_Bossen_2.md5
-+1,RPLM_A_qualcomm_4,RPLM_A_qualcomm_4.bit,RPLM_A_qualcomm_4.yuv.md5
-+1,RPLM_B_qualcomm_4,RPLM_B_qualcomm_4.bit,RPLM_B_qualcomm_4.yuv.md5
-+1,RPS_A_docomo_5,RPS_A_docomo_5.bit,RPS_A_docomo_5.md5
-+1,RPS_B_qualcomm_5,RPS_B_qualcomm_5.bit,RPS_B_qualcomm_5.yuv.md5
-+1,RPS_C_ericsson_5,RPS_C_ericsson_5.bit,RPS_C_ericsson_5.md5
-+1,RPS_D_ericsson_6,RPS_D_ericsson_6.bit,RPS_D_ericsson_6.md5
-+1,RPS_E_qualcomm_5,RPS_E_qualcomm_5.bit,RPS_E_qualcomm_5.yuv.md5
-+1,RPS_F_docomo_2,RPS_F_docomo_2.bit,RPS_F_docomo_2.md5
-+1,RQT_A_HHI_4,RQT_A_HHI_4.bit,RQT_A_HHI_4.md5
-+1,RQT_B_HHI_4,RQT_B_HHI_4.bit,RQT_B_HHI_4.md5
-+1,RQT_C_HHI_4,RQT_C_HHI_4.bit,RQT_C_HHI_4.md5
-+1,RQT_D_HHI_4,RQT_D_HHI_4.bit,RQT_D_HHI_4.md5
-+1,RQT_E_HHI_4,RQT_E_HHI_4.bit,RQT_E_HHI_4.md5
-+1,RQT_F_HHI_4,RQT_F_HHI_4.bit,RQT_F_HHI_4.md5
-+1,RQT_G_HHI_4,RQT_G_HHI_4.bit,RQT_G_HHI_4.md5
-+1,SAO_A_MediaTek_4,SAO_A_MediaTek_4.bit,SAO_A_MediaTek_4.md5
-+1,SAO_B_MediaTek_5,SAO_B_MediaTek_5.bit,SAO_B_MediaTek_5.md5
-+1,SAO_C_Samsung_5,SAO_C_Samsung_5.bin,SAO_C_Samsung_5.md5
-+1,SAO_D_Samsung_5,SAO_D_Samsung_5.bin,SAO_D_Samsung_5.md5
-+1,SAO_E_Canon_4,SAO_E_Canon_4.bit,SAO_E_Canon_4.md5
-+1,SAO_F_Canon_3,SAO_F_Canon_3.bit,SAO_F_Canon_3.md5
-+1,SAO_G_Canon_3,SAO_G_Canon_3.bit,SAO_G_Canon_3.md5
-+1,SAO_H_Parabola_1,SAO_H_Parabola_1.bit,SAO_H_Parabola_1.md5
-+2,SAODBLK_A_MainConcept_4,SAODBLK_A_MainConcept_4.bin,SAODBLK_A_MainConcept_4_md5.txt
-+2,SAODBLK_B_MainConcept_4,SAODBLK_B_MainConcept_4.bin,SAODBLK_B_MainConcept_4_md5.txt
-+1,SDH_A_Orange_4,SDH_A_Orange_4.bit,SDH_A_Orange_4_yuv.md5
-+1,SLICES_A_Rovi_3,SLICES_A_Rovi_3.bin,SLICES_A_Rovi_3.md5
-+1,SLIST_A_Sony_5,SLIST_A_Sony_5.bin,SLIST_A_Sony_5_yuv.md5
-+1,SLIST_B_Sony_9,SLIST_B_Sony_9.bin,SLIST_B_Sony_9_yuv.md5
-+1,SLIST_C_Sony_4,SLIST_C_Sony_4.bin,SLIST_C_Sony_4_yuv.md5
-+1,SLIST_D_Sony_9,str.bin,SLIST_D_Sony_9_yuv.md5
-+1,SLPPLP_A_VIDYO_2,SLPPLP_A_VIDYO_2.bit,SLPPLP_A_VIDYO_2_yuv.md5
-+1,STRUCT_A_Samsung_7,STRUCT_A_Samsung_7.bin,STRUCT_A_Samsung_7.md5
-+1,STRUCT_B_Samsung_7,STRUCT_B_Samsung_7.bin,STRUCT_B_Samsung_7.md5
-+1,TILES_A_Cisco_2,TILES_A_Cisco_2.bin,TILES_A_Cisco_2_yuv.md5
-+1,TILES_B_Cisco_1,TILES_B_Cisco_1.bin,TILES_B_Cisco_1_yuv.md5
-+1,TMVP_A_MS_3,TMVP_A_MS_3.bit,TMVP_A_MS_3.yuv.md5
-+1,TSCL_A_VIDYO_5,TSCL_A_VIDYO_5.bit,TSCL_A_VIDYO_5_yuv.md5
-+1,TSCL_B_VIDYO_4,TSCL_B_VIDYO_4.bit,TSCL_B_VIDYO_4_yuv.md5
-+1,TSKIP_A_MS_3,TSKIP_A_MS_3.bit,TSKIP_A_MS_3.yuv.md5
-+3,TSUNEQBD_A_MAIN10_Technicolor_2,TSUNEQBD_A_MAIN10_Technicolor_2.bit,TSUNEQBD_A_MAIN10_Technicolor_2_yuv.md5, # unequal bit depth
-+1,TUSIZE_A_Samsung_1,TUSIZE_A_Samsung_1.bin,TUSIZE_A_Samsung_1.md5
-+1,VPSID_A_VIDYO_2,VPSID_A_VIDYO_2.bit,VPSID_A_VIDYO_2_yuv.md5
-+3,VPSSPSPPS_A_MainConcept_1,VPSSPSPPS_A_MainConcept_1.bin,VPSSPSPPS_A_MainConcept_1_md5.txt, # ???
-+1,WP_A_MAIN10_Toshiba_3,WP_A_MAIN10_Toshiba_3.bit,WP_A_MAIN10_Toshiba_3_yuv.md5
-+1,WP_A_Toshiba_3,WP_A_Toshiba_3.bit,WP_A_Toshiba_3_yuv.md5
-+1,WP_B_Toshiba_3,WP_B_Toshiba_3.bit,WP_B_Toshiba_3_yuv.md5
-+1,WP_MAIN10_B_Toshiba_3,WP_MAIN10_B_Toshiba_3.bit,WP_MAIN10_B_Toshiba_3_yuv.md5
-+1,WPP_A_ericsson_MAIN10_2,WPP_A_ericsson_MAIN10_2.bit,WPP_A_ericsson_MAIN10_yuv.md5
-+1,WPP_A_ericsson_MAIN_2,WPP_A_ericsson_MAIN_2.bit,WPP_A_ericsson_MAIN_2_yuv.md5
-+1,WPP_B_ericsson_MAIN10_2,WPP_B_ericsson_MAIN10_2.bit,WPP_B_ericsson_MAIN10_yuv.md5
-+1,WPP_B_ericsson_MAIN_2,WPP_B_ericsson_MAIN_2.bit,WPP_B_ericsson_MAIN_2_yuv.md5
-+1,WPP_C_ericsson_MAIN10_2,WPP_C_ericsson_MAIN10_2.bit,WPP_C_ericsson_MAIN10_yuv.md5
-+1,WPP_C_ericsson_MAIN_2,WPP_C_ericsson_MAIN_2.bit,WPP_C_ericsson_MAIN_2_yuv.md5
-+1,WPP_D_ericsson_MAIN10_2,WPP_D_ericsson_MAIN10_2.bit,WPP_D_ericsson_MAIN10_yuv.md5
-+1,WPP_D_ericsson_MAIN_2,WPP_D_ericsson_MAIN_2.bit,WPP_D_ericsson_MAIN_2_yuv.md5
-+1,WPP_E_ericsson_MAIN10_2,WPP_E_ericsson_MAIN10_2.bit,WPP_E_ericsson_MAIN10_yuv.md5
-+1,WPP_E_ericsson_MAIN_2,WPP_E_ericsson_MAIN_2.bit,WPP_E_ericsson_MAIN_2_yuv.md5
-+1,WPP_F_ericsson_MAIN10_2,WPP_F_ericsson_MAIN10_2.bit,WPP_F_ericsson_MAIN10_yuv.md5
-+1,WPP_F_ericsson_MAIN_2,WPP_F_ericsson_MAIN_2.bit,WPP_F_ericsson_MAIN_2_yuv.md5
-diff --git a/pi-util/conf_h265.csv b/pi-util/conf_h265.csv
-new file mode 100644
-index 0000000000..fc14f2a3c2
---- /dev/null
-+++ b/pi-util/conf_h265.csv
-@@ -0,0 +1,144 @@
-+1,ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_1,ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_1.bit,ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_1.md5
-+1,AMP_A_Samsung_6,AMP_A_Samsung_6.bin,AMP_A_Samsung_6.md5
-+1,AMP_B_Samsung_6,AMP_B_Samsung_6.bin,AMP_B_Samsung_6.md5
-+1,AMP_D_Hisilicon_3,AMP_D_Hisilicon.bit,AMP_D_Hisilicon_3.yuv.md5
-+1,AMP_E_Hisilicon_3,AMP_E_Hisilicon.bit,AMP_E_Hisilicon_3.yuv.md5
-+1,AMP_F_Hisilicon_3,AMP_F_Hisilicon_3.bit,AMP_F_Hisilicon_3.yuv.md5
-+1,AMVP_A_MTK_4,AMVP_A_MTK_4.bit,AMVP_A_MTK_4.md5
-+1,AMVP_B_MTK_4,AMVP_B_MTK_4.bit,AMVP_B_MTK_4.md5
-+1,AMVP_C_Samsung_6,AMVP_C_Samsung_6.bin,AMVP_C_Samsung_6.md5
-+1,BUMPING_A_ericsson_1,BUMPING_A_ericsson_1.bit,BUMPING_A_ericsson_1.md5
-+1,CAINIT_A_SHARP_4,CAINIT_A_SHARP_4.bit,CAINIT_A_SHARP_4.md5
-+1,CAINIT_B_SHARP_4,CAINIT_B_SHARP_4.bit,CAINIT_B_SHARP_4.md5
-+1,CAINIT_C_SHARP_3,CAINIT_C_SHARP_3.bit,CAINIT_C_SHARP_3.md5
-+1,CAINIT_D_SHARP_3,CAINIT_D_SHARP_3.bit,CAINIT_D_SHARP_3.md5
-+1,CAINIT_E_SHARP_3,CAINIT_E_SHARP_3.bit,CAINIT_E_SHARP_3.md5
-+1,CAINIT_F_SHARP_3,CAINIT_F_SHARP_3.bit,CAINIT_F_SHARP_3.md5
-+1,CAINIT_G_SHARP_3,CAINIT_G_SHARP_3.bit,CAINIT_G_SHARP_3.md5
-+1,CAINIT_H_SHARP_3,CAINIT_H_SHARP_3.bit,CAINIT_H_SHARP_3.md5
-+1,CIP_A_Panasonic_3,CIP_A_Panasonic_3.bit,CIP_A_Panasonic_3_yuv.md5
-+1,cip_B_NEC_3,cip_B_NEC_3.bit,cip_B_NEC_3.md5
-+1,CIP_C_Panasonic_2,CIP_C_Panasonic_2.bit,CIP_C_Panasonic_2_yuv.md5
-+1,CONFWIN_A_Sony_1,CONFWIN_A_Sony_1.bit,CONFWIN_A_Sony_1.md5
-+1,DBLK_A_MAIN10_VIXS_3,DBLK_A_MAIN10_VIXS_3.bit,DBLK_A_MAIN10_VIXS_3.md5
-+1,DBLK_A_SONY_3,DBLK_A_SONY_3.bit,DBLK_A_SONY_3.bit.yuv.md5
-+1,DBLK_B_SONY_3,DBLK_B_SONY_3.bit,DBLK_B_SONY_3.bit.yuv.md5
-+1,DBLK_C_SONY_3,DBLK_C_SONY_3.bit,DBLK_C_SONY_3.bit.yuv.md5
-+1,DBLK_D_VIXS_2,DBLK_D_VIXS_2.bit,DBLK_D_VIXS_2_yuv.md5
-+1,DBLK_E_VIXS_2,DBLK_E_VIXS_2.bit,DBLK_E_VIXS_2_yuv.md5
-+1,DBLK_F_VIXS_2,DBLK_F_VIXS_2.bit,DBLK_F_VIXS_2_yuv.md5
-+1,DBLK_G_VIXS_2,DBLK_G_VIXS_2.bit,DBLK_G_VIXS_2_yuv.md5
-+1,DELTAQP_A_BRCM_4,DELTAQP_A_BRCM_4.bit,DELTAQP_A_BRCM_4_yuv.md5
-+1,DELTAQP_B_SONY_3,DELTAQP_B_SONY_3.bit,DELTAQP_B_SONY_3.bit.yuv.md5
-+1,DELTAQP_C_SONY_3,DELTAQP_C_SONY_3.bit,DELTAQP_C_SONY_3.bit.yuv.md5
-+1,DSLICE_A_HHI_5,DSLICE_A_HHI_5.bin,DSLICE_A_HHI_5.md5
-+1,DSLICE_B_HHI_5,DSLICE_B_HHI_5.bin,DSLICE_B_HHI_5.md5
-+1,DSLICE_C_HHI_5,DSLICE_C_HHI_5.bin,DSLICE_C_HHI_5.md5
-+1,ENTP_A_QUALCOMM_1,ENTP_A_Qualcomm_1.bit,ENTP_A_Qualcomm_1.md5
-+1,ENTP_B_Qualcomm_1,ENTP_B_Qualcomm_1.bit,ENTP_B_Qualcomm_1.md5
-+1,ENTP_C_Qualcomm_1,ENTP_C_Qualcomm_1.bit,ENTP_C_Qualcomm_1.md5
-+1,EXT_A_ericsson_4,EXT_A_ericsson_4.bit,EXT_A_ericsson_4.md5
-+1,FILLER_A_Sony_1,FILLER_A_Sony_1.bit,FILLER_A_Sony_1.md5
-+1,HRD_A_Fujitsu_3,HRD_A_Fujitsu_3.bin,HRD_A_Fujitsu_3.md5
-+1,INITQP_A_Sony_1,INITQP_A_Sony_1.bit,INITQP_A_Sony_1.md5
-+1,INITQP_B_Main10_Sony_1,INITQP_B_Main10_Sony_1.bit,INITQP_B_Main10_Sony_1.md5
-+1,ipcm_A_NEC_3,ipcm_A_NEC_3.bit,ipcm_A_NEC_3.md5
-+1,ipcm_B_NEC_3,ipcm_B_NEC_3.bit,ipcm_B_NEC_3.md5
-+1,ipcm_C_NEC_3,ipcm_C_NEC_3.bit,ipcm_C_NEC_3.md5
-+1,ipcm_D_NEC_3,ipcm_D_NEC_3.bit,ipcm_D_NEC_3.md5
-+1,ipcm_E_NEC_2,ipcm_E_NEC_2.bit,ipcm_E_NEC_2.md5
-+1,IPRED_A_docomo_2,IPRED_A_docomo_2.bit,IPRED_A_docomo_2.md5
-+1,IPRED_B_Nokia_3,IPRED_B_Nokia_3.bit,IPRED_B_Nokia_3_yuv.md5
-+1,IPRED_C_Mitsubishi_3,IPRED_C_Mitsubishi_3.bit,IPRED_C_Mitsubishi_3_yuv.md5
-+1,LS_A_Orange_2,LS_A_Orange_2.bit,LS_A_Orange_2_yuv.md5
-+1,LS_B_Orange_4,LS_B_Orange_4.bit,LS_B_Orange_4_yuv.md5
-+1,LTRPSPS_A_Qualcomm_1,LTRPSPS_A_Qualcomm_1.bit,LTRPSPS_A_Qualcomm_1.md5
-+1,MAXBINS_A_TI_4,MAXBINS_A_TI_4.bit,MAXBINS_A_TI_4.md5
-+1,MAXBINS_B_TI_4,MAXBINS_B_TI_4.bit,MAXBINS_B_TI_4.md5
-+1,MAXBINS_C_TI_4,MAXBINS_C_TI_4.bit,MAXBINS_C_TI_4.md5
-+1,MERGE_A_TI_3,MERGE_A_TI_3.bit,MERGE_A_TI_3.md5
-+1,MERGE_B_TI_3,MERGE_B_TI_3.bit,MERGE_B_TI_3.md5
-+1,MERGE_C_TI_3,MERGE_C_TI_3.bit,MERGE_C_TI_3.md5
-+1,MERGE_D_TI_3,MERGE_D_TI_3.bit,MERGE_D_TI_3.md5
-+1,MERGE_E_TI_3,MERGE_E_TI_3.bit,MERGE_E_TI_3.md5
-+1,MERGE_F_MTK_4,MERGE_F_MTK_4.bit,MERGE_F_MTK_4.md5
-+1,MERGE_G_HHI_4,MERGE_G_HHI_4.bit,MERGE_G_HHI_4.md5
-+1,MVCLIP_A_qualcomm_3,MVCLIP_A_qualcomm_3.bit,MVCLIP_A_qualcomm_3.yuv.md5
-+1,MVDL1ZERO_A_docomo_4,MVDL1ZERO_A_docomo_4.bit,MVDL1ZERO_A_docomo_4.md5
-+1,MVEDGE_A_qualcomm_3,MVEDGE_A_qualcomm_3.bit,MVEDGE_A_qualcomm_3.yuv.md5
-+1,NoOutPrior_A_Qualcomm_1,NoOutPrior_A_Qualcomm_1.bit,NoOutPrior_A_Qualcomm_1.md5
-+1,NoOutPrior_B_Qualcomm_1,NoOutPrior_B_Qualcomm_1.bit,NoOutPrior_B_Qualcomm_1.md5
-+1,NUT_A_ericsson_5,NUT_A_ericsson_5.bit,NUT_A_ericsson_5.md5
-+1,OPFLAG_A_Qualcomm_1,OPFLAG_A_Qualcomm_1.bit,OPFLAG_A_Qualcomm_1.md5
-+1,OPFLAG_B_Qualcomm_1,OPFLAG_B_Qualcomm_1.bit,OPFLAG_B_Qualcomm_1.md5
-+1,OPFLAG_C_Qualcomm_1,OPFLAG_C_Qualcomm_1.bit,OPFLAG_C_Qualcomm_1.md5
-+1,PICSIZE_A_Bossen_1,PICSIZE_A_Bossen_1.bin,PICSIZE_A_Bossen_1.md5
-+1,PICSIZE_B_Bossen_1,PICSIZE_B_Bossen_1.bin,PICSIZE_B_Bossen_1.md5
-+1,PICSIZE_C_Bossen_1,PICSIZE_C_Bossen_1.bin,PICSIZE_C_Bossen_1.md5
-+1,PICSIZE_D_Bossen_1,PICSIZE_D_Bossen_1.bin,PICSIZE_D_Bossen_1.md5
-+1,PMERGE_A_TI_3,PMERGE_A_TI_3.bit,PMERGE_A_TI_3.md5
-+1,PMERGE_B_TI_3,PMERGE_B_TI_3.bit,PMERGE_B_TI_3.md5
-+1,PMERGE_C_TI_3,PMERGE_C_TI_3.bit,PMERGE_C_TI_3.md5
-+1,PMERGE_D_TI_3,PMERGE_D_TI_3.bit,PMERGE_D_TI_3.md5
-+1,PMERGE_E_TI_3,PMERGE_E_TI_3.bit,PMERGE_E_TI_3.md5
-+1,POC_A_Bossen_3,POC_A_Bossen_3.bin,POC_A_Bossen_3.md5
-+1,PPS_A_qualcomm_7,PPS_A_qualcomm_7.bit,PPS_A_qualcomm_7.yuv.md5
-+1,PS_B_VIDYO_3,PS_B_VIDYO_3.bit,PS_B_VIDYO_3_yuv.md5
-+1,RAP_A_docomo_6,RAP_A_docomo_6.bit,RAP_A_docomo_6.md5
-+1,RAP_B_Bossen_2,RAP_B_Bossen_2.bit,RAP_B_Bossen_2.md5
-+1,RPLM_A_qualcomm_4,RPLM_A_qualcomm_4.bit,RPLM_A_qualcomm_4.yuv.md5
-+1,RPLM_B_qualcomm_4,RPLM_B_qualcomm_4.bit,RPLM_B_qualcomm_4.yuv.md5
-+1,RPS_A_docomo_5,RPS_A_docomo_5.bit,RPS_A_docomo_5.md5
-+1,RPS_B_qualcomm_5,RPS_B_qualcomm_5.bit,RPS_B_qualcomm_5.yuv.md5
-+1,RPS_C_ericsson_5,RPS_C_ericsson_5.bit,RPS_C_ericsson_5.md5
-+1,RPS_D_ericsson_6,RPS_D_ericsson_6.bit,RPS_D_ericsson_6.md5
-+1,RPS_E_qualcomm_5,RPS_E_qualcomm_5.bit,RPS_E_qualcomm_5.yuv.md5
-+1,RPS_F_docomo_2,RPS_F_docomo_2.bit,RPS_F_docomo_2.md5
-+1,RQT_A_HHI_4,RQT_A_HHI_4.bit,RQT_A_HHI_4.md5
-+1,RQT_B_HHI_4,RQT_B_HHI_4.bit,RQT_B_HHI_4.md5
-+1,RQT_C_HHI_4,RQT_C_HHI_4.bit,RQT_C_HHI_4.md5
-+1,RQT_D_HHI_4,RQT_D_HHI_4.bit,RQT_D_HHI_4.md5
-+1,RQT_E_HHI_4,RQT_E_HHI_4.bit,RQT_E_HHI_4.md5
-+1,RQT_F_HHI_4,RQT_F_HHI_4.bit,RQT_F_HHI_4.md5
-+1,RQT_G_HHI_4,RQT_G_HHI_4.bit,RQT_G_HHI_4.md5
-+1,SAO_A_MediaTek_4,SAO_A_MediaTek_4.bit,SAO_A_MediaTek_4.md5
-+1,SAO_B_MediaTek_5,SAO_B_MediaTek_5.bit,SAO_B_MediaTek_5.md5
-+1,SAO_C_Samsung_5,SAO_C_Samsung_5.bin,SAO_C_Samsung_5.md5
-+1,SAO_D_Samsung_5,SAO_D_Samsung_5.bin,SAO_D_Samsung_5.md5
-+1,SAO_E_Canon_4,SAO_E_Canon_4.bit,SAO_E_Canon_4.md5
-+1,SAO_F_Canon_3,SAO_F_Canon_3.bit,SAO_F_Canon_3.md5
-+1,SAO_G_Canon_3,SAO_G_Canon_3.bit,SAO_G_Canon_3.md5
-+1,SDH_A_Orange_4,SDH_A_Orange_4.bit,SDH_A_Orange_4_yuv.md5
-+1,SLICES_A_Rovi_3,SLICES_A_Rovi_3.bin,SLICES_A_Rovi_3.md5
-+1,SLIST_A_Sony_4,str.bin,SLIST_A_Sony_4_yuv.md5
-+1,SLIST_B_Sony_8,str.bin,SLIST_B_Sony_8_yuv.md5
-+1,SLIST_C_Sony_3,str.bin,SLIST_C_Sony_3_yuv.md5
-+1,SLIST_D_Sony_9,str.bin,SLIST_D_Sony_9_yuv.md5
-+1,SLPPLP_A_VIDYO_2,SLPPLP_A_VIDYO_2.bit,SLPPLP_A_VIDYO_2_yuv.md5
-+1,STRUCT_A_Samsung_6,STRUCT_A_Samsung_6.bin,STRUCT_A_Samsung_6.md5
-+1,STRUCT_B_Samsung_6,STRUCT_B_Samsung_6.bin,STRUCT_B_Samsung_6.md5
-+1,TILES_A_Cisco_2,TILES_A_Cisco_2.bin,TILES_A_Cisco_2_yuv.md5
-+1,TILES_B_Cisco_1,TILES_B_Cisco_1.bin,TILES_B_Cisco_1_yuv.md5
-+1,TMVP_A_MS_3,TMVP_A_MS_3.bit,TMVP_A_MS_3.yuv.md5
-+1,TSCL_A_VIDYO_5,TSCL_A_VIDYO_5.bit,TSCL_A_VIDYO_5_yuv.md5
-+1,TSCL_B_VIDYO_4,TSCL_B_VIDYO_4.bit,TSCL_B_VIDYO_4_yuv.md5
-+1,TSKIP_A_MS_3,TSKIP_A_MS_3.bit,TSKIP_A_MS_3.yuv.md5
-+0,TSUNEQBD_A_MAIN10_Technicolor_2,TSUNEQBD_A_MAIN10_Technicolor_2.bit,TSUNEQBD_A_MAIN10_Technicolor_2_yuv.md5, # Y/C bit depth unmatched
-+1,TUSIZE_A_Samsung_1,TUSIZE_A_Samsung_1.bin,TUSIZE_A_Samsung_1.md5
-+1,VPSID_A_VIDYO_2,VPSID_A_VIDYO_2.bit,VPSID_A_VIDYO_2_yuv.md5
-+1,WP_A_MAIN10_Toshiba_3,WP_A_MAIN10_Toshiba_3.bit,WP_A_MAIN10_Toshiba_3_yuv.md5
-+1,WP_A_Toshiba_3,WP_A_Toshiba_3.bit,WP_A_Toshiba_3_yuv.md5
-+1,WP_B_Toshiba_3,WP_B_Toshiba_3.bit,WP_B_Toshiba_3_yuv.md5
-+1,WP_MAIN10_B_Toshiba_3,WP_MAIN10_B_Toshiba_3.bit,WP_MAIN10_B_Toshiba_3_yuv.md5
-+1,WPP_A_ericsson_MAIN10_2,WPP_A_ericsson_MAIN10_2.bit,WPP_A_ericsson_MAIN10_yuv.md5
-+1,WPP_A_ericsson_MAIN_2,WPP_A_ericsson_MAIN_2.bit,WPP_A_ericsson_MAIN_2_yuv.md5
-+1,WPP_B_ericsson_MAIN10_2,WPP_B_ericsson_MAIN10_2.bit,WPP_B_ericsson_MAIN10_yuv.md5
-+1,WPP_B_ericsson_MAIN_2,WPP_B_ericsson_MAIN_2.bit,WPP_B_ericsson_MAIN_2_yuv.md5
-+1,WPP_C_ericsson_MAIN10_2,WPP_C_ericsson_MAIN10_2.bit,WPP_C_ericsson_MAIN10_yuv.md5
-+1,WPP_C_ericsson_MAIN_2,WPP_C_ericsson_MAIN_2.bit,WPP_C_ericsson_MAIN_2_yuv.md5
-+1,WPP_D_ericsson_MAIN10_2,WPP_D_ericsson_MAIN10_2.bit,WPP_D_ericsson_MAIN10_yuv.md5
-+1,WPP_D_ericsson_MAIN_2,WPP_D_ericsson_MAIN_2.bit,WPP_D_ericsson_MAIN_2_yuv.md5
-+1,WPP_E_ericsson_MAIN10_2,WPP_E_ericsson_MAIN10_2.bit,WPP_E_ericsson_MAIN10_yuv.md5
-+1,WPP_E_ericsson_MAIN_2,WPP_E_ericsson_MAIN_2.bit,WPP_E_ericsson_MAIN_2_yuv.md5
-+1,WPP_F_ericsson_MAIN10_2,WPP_F_ericsson_MAIN10_2.bit,WPP_F_ericsson_MAIN10_yuv.md5
-+1,WPP_F_ericsson_MAIN_2,WPP_F_ericsson_MAIN_2.bit,WPP_F_ericsson_MAIN_2_yuv.md5
-diff --git a/pi-util/conf_native.sh b/pi-util/conf_native.sh
-new file mode 100755
-index 0000000000..65576846e8
---- /dev/null
-+++ b/pi-util/conf_native.sh
-@@ -0,0 +1,108 @@
-+echo "Configure for native build"
-+
-+FFSRC=`pwd`
-+MC=`dpkg --print-architecture`
-+BUILDBASE=$FFSRC/out
-+
-+#RPI_KEEPS="-save-temps=obj"
-+RPI_KEEPS=""
-+
-+NOSHARED=
-+MMAL=
-+
-+while [ "$1" != "" ] ; do
-+ case $1 in
-+ --noshared)
-+ NOSHARED=1
-+ ;;
-+ --mmal)
-+ MMAL=1
-+ ;;
-+ *)
-+ echo "Usage $0: [--noshared] [--mmal]"
-+ exit 1
-+ ;;
-+ esac
-+ shift
-+done
-+
-+
-+MCOPTS=
-+RPI_INCLUDES=
-+RPI_LIBDIRS=
-+RPI_DEFINES=
-+RPI_EXTRALIBS=
-+
-+if [ "$MC" == "arm64" ]; then
-+ echo "M/C aarch64"
-+ A=aarch64-linux-gnu
-+ B=arm64
-+elif [ "$MC" == "armhf" ]; then
-+ echo "M/C armv7"
-+ A=arm-linux-gnueabihf
-+ B=armv7
-+ MCOPTS="--arch=armv6t2 --cpu=cortex-a7"
-+ RPI_DEFINES=-mfpu=neon-vfpv4
-+else
-+ echo Unexpected architecture $MC
-+ exit 1
-+fi
-+
-+if [ $MMAL ]; then
-+ RPI_OPT_VC=/opt/vc
-+ RPI_INCLUDES="-I$RPI_OPT_VC/include -I$RPI_OPT_VC/include/interface/vcos/pthreads -I$RPI_OPT_VC/include/interface/vmcs_host/linux"
-+ RPI_LIBDIRS="-L$RPI_OPT_VC/lib"
-+ RPI_DEFINES="$RPI_DEFINES -D__VCCOREVER__=0x4000000"
-+ RPI_EXTRALIBS="-Wl,--start-group -lbcm_host -lmmal -lmmal_util -lmmal_core -lvcos -lvcsm -lvchostif -lvchiq_arm -Wl,--end-group"
-+ RPIOPTS="--enable-mmal --enable-rpi"
-+else
-+ RPIOPTS="--disable-mmal --enable-sand"
-+fi
-+
-+C=`lsb_release -sc`
-+V=`cat RELEASE`
-+
-+SHARED_LIBS="--enable-shared"
-+if [ $NOSHARED ]; then
-+ SHARED_LIBS="--disable-shared"
-+ OUT=$BUILDBASE/$B-$C-$V-static-rel
-+ echo Static libs
-+else
-+ echo Shared libs
-+ OUT=$BUILDBASE/$B-$C-$V-shared-rel
-+fi
-+
-+USR_PREFIX=$OUT/install
-+LIB_PREFIX=$USR_PREFIX/lib/$A
-+INC_PREFIX=$USR_PREFIX/include/$A
-+
-+echo Destination directory: $OUT
-+mkdir -p $OUT
-+# Nothing under here need worry git - including this .gitignore!
-+echo "**" > $BUILDBASE/.gitignore
-+cd $OUT
-+
-+$FFSRC/configure \
-+ --prefix=$USR_PREFIX\
-+ --libdir=$LIB_PREFIX\
-+ --incdir=$INC_PREFIX\
-+ $MCOPTS\
-+ --disable-stripping\
-+ --disable-thumb\
-+ --enable-v4l2-request\
-+ --enable-libdrm\
-+ --enable-epoxy\
-+ --enable-libudev\
-+ --enable-vout-egl\
-+ --enable-vout-drm\
-+ $SHARED_LIBS\
-+ $RPIOPTS\
-+ --extra-cflags="-ggdb $RPI_KEEPS $RPI_DEFINES $RPI_INCLUDES"\
-+ --extra-cxxflags="$RPI_DEFINES $RPI_INCLUDES"\
-+ --extra-ldflags="$RPI_LIBDIRS"\
-+ --extra-libs="$RPI_EXTRALIBS"\
-+ --extra-version="rpi"
-+
-+
-+# gcc option for getting asm listing
-+# -Wa,-ahls
-diff --git a/pi-util/ffconf.py b/pi-util/ffconf.py
-new file mode 100755
-index 0000000000..657568014e
---- /dev/null
-+++ b/pi-util/ffconf.py
-@@ -0,0 +1,215 @@
-+#!/usr/bin/env python3
-+
-+import string
-+import os
-+import subprocess
-+import re
-+import argparse
-+import sys
-+import csv
-+from stat import *
-+
-+CODEC_HEVC_RPI = 1
-+HWACCEL_RPI = 2
-+HWACCEL_DRM = 3
-+HWACCEL_VAAPI = 4
-+
-+def testone(fileroot, srcname, es_file, md5_file, pix, dectype, vcodec, ffmpeg_exec):
-+ hwaccel = ""
-+ if dectype == HWACCEL_RPI:
-+ hwaccel = "rpi"
-+ elif dectype == HWACCEL_DRM:
-+ hwaccel = "drm"
-+ elif dectype == HWACCEL_VAAPI:
-+ hwaccel = "vaapi"
-+
-+ pix_fmt = []
-+ if pix == "8":
-+ pix_fmt = ["-pix_fmt", "yuv420p"]
-+ elif pix == "10":
-+ pix_fmt = ["-pix_fmt", "yuv420p10le"]
-+ elif pix == "12":
-+ pix_fmt = ["-pix_fmt", "yuv420p12le"]
-+
-+ tmp_root = "/tmp"
-+
-+ names = srcname.split('/')
-+ while len(names) > 1:
-+ tmp_root = os.path.join(tmp_root, names[0])
-+ del names[0]
-+ name = names[0]
-+
-+ if not os.path.exists(tmp_root):
-+ os.makedirs(tmp_root)
-+
-+ dec_file = os.path.join(tmp_root, name + ".dec.md5")
-+ try:
-+ os.remove(dec_file)
-+ except:
-+ pass
-+
-+ flog = open(os.path.join(tmp_root, name + ".log"), "wt")
-+
-+ ffargs = [ffmpeg_exec, "-flags", "unaligned", "-hwaccel", hwaccel, "-vcodec", "hevc", "-i", os.path.join(fileroot, es_file)] + pix_fmt + ["-f", "md5", dec_file]
-+
-+ # Unaligned needed for cropping conformance
-+ if hwaccel:
-+ rstr = subprocess.call(ffargs, stdout=flog, stderr=subprocess.STDOUT)
-+ else:
-+ rstr = subprocess.call(
-+ [ffmpeg_exec, "-flags", "unaligned", "-vcodec", vcodec, "-i", os.path.join(fileroot, es_file), "-f", "md5", dec_file],
-+ stdout=flog, stderr=subprocess.STDOUT)
-+
-+ try:
-+ m1 = None
-+ m2 = None
-+ with open(os.path.join(fileroot, md5_file)) as f:
-+ for line in f:
-+ m1 = re.search("[0-9a-f]{32}", line.lower())
-+ if m1:
-+ break
-+
-+ with open(dec_file) as f:
-+ m2 = re.search("[0-9a-f]{32}", f.readline())
-+ except:
-+ pass
-+
-+ if m1 and m2 and m1.group() == m2.group():
-+ print("Match: " + m1.group(), file=flog)
-+ rv = 0
-+ elif not m1:
-+ print("****** Cannot find m1", file=flog)
-+ rv = 3
-+ elif not m2:
-+ print("****** Cannot find m2", file=flog)
-+ rv = 2
-+ else:
-+ print("****** Mismatch: " + m1.group() + " != " + m2.group(), file=flog)
-+ rv = 1
-+ flog.close()
-+ return rv
-+
-+def scandir(root):
-+ aconf = []
-+ ents = os.listdir(root)
-+ ents.sort(key=str.lower)
-+ for name in ents:
-+ test_path = os.path.join(root, name)
-+ if S_ISDIR(os.stat(test_path).st_mode):
-+ files = os.listdir(test_path)
-+ es_file = "?"
-+ md5_file = "?"
-+ for f in files:
-+ (base, ext) = os.path.splitext(f)
-+ if base[0] == '.':
-+ pass
-+ elif ext == ".bit" or ext == ".bin":
-+ es_file = f
-+ elif ext == ".md5" or (ext == ".txt" and (base[-4:] == "_md5" or base[-6:] == "md5sum")):
-+ if md5_file == "?":
-+ md5_file = f
-+ elif base[-3:] == "yuv":
-+ md5_file = f
-+ aconf.append((1, name, es_file, md5_file))
-+ return aconf
-+
-+def runtest(name, tests):
-+ if not tests:
-+ return True
-+ for t in tests:
-+ if name[0:len(t)] == t or name.find("/" + t) != -1:
-+ return True
-+ return False
-+
-+def doconf(csva, tests, test_root, vcodec, dectype, ffmpeg_exec):
-+ unx_failures = []
-+ unx_success = []
-+ failures = 0
-+ successes = 0
-+ for a in csva:
-+ exp_test = int(a[0])
-+ if (exp_test and runtest(a[1], tests)):
-+ name = a[1]
-+ print ("==== ", name, end="")
-+ sys.stdout.flush()
-+
-+ rv = testone(os.path.join(test_root, name), name, a[2], a[3], a[4], dectype=dectype, vcodec=vcodec, ffmpeg_exec=ffmpeg_exec)
-+ if (rv == 0):
-+ successes += 1
-+ else:
-+ failures += 1
-+
-+ if (rv == 0):
-+ if exp_test == 2:
-+ print(": * OK *")
-+ unx_success.append(name)
-+ else:
-+ print(": ok")
-+ elif exp_test == 2 and rv == 1:
-+ print(": fail")
-+ elif exp_test == 3 and rv == 2:
-+ # Call an expected "crash" an abort
-+ print(": abort")
-+ else:
-+ unx_failures.append(name)
-+ if rv == 1:
-+ print(": * FAIL *")
-+ elif (rv == 2) :
-+ print(": * CRASH *")
-+ elif (rv == 3) :
-+ print(": * MD5 MISSING *")
-+ else :
-+ print(": * BANG *")
-+
-+ if unx_failures or unx_success:
-+ print("Unexpected Failures:", unx_failures)
-+ print("Unexpected Success: ", unx_success)
-+ else:
-+ print("All tests normal:", successes, "ok,", failures, "failed")
-+
-+
-+class ConfCSVDialect(csv.Dialect):
-+ delimiter = ','
-+ doublequote = True
-+ lineterminator = '\n'
-+ quotechar='"'
-+ quoting = csv.QUOTE_MINIMAL
-+ skipinitialspace = True
-+ strict = True
-+
-+if __name__ == '__main__':
-+
-+ argp = argparse.ArgumentParser(description="FFmpeg h265 conformance tester")
-+ argp.add_argument("tests", nargs='*')
-+ argp.add_argument("--pi4", action='store_true', help="Force pi4 cmd line")
-+ argp.add_argument("--drm", action='store_true', help="Force v4l2 drm cmd line")
-+ argp.add_argument("--vaapi", action='store_true', help="Force vaapi cmd line")
-+ argp.add_argument("--test_root", default="/opt/conform/h265.2016", help="Root dir for test")
-+ argp.add_argument("--csvgen", action='store_true', help="Generate CSV file for dir")
-+ argp.add_argument("--csv", default="pi-util/conf_h265.2016.csv", help="CSV filename")
-+ argp.add_argument("--vcodec", default="hevc_rpi", help="vcodec name to use")
-+ argp.add_argument("--ffmpeg", default="./ffmpeg", help="ffmpeg exec name")
-+ args = argp.parse_args()
-+
-+ if args.csvgen:
-+ csv.writer(sys.stdout).writerows(scandir(args.test_root))
-+ exit(0)
-+
-+ with open(args.csv, 'rt') as csvfile:
-+ csva = [a for a in csv.reader(csvfile, ConfCSVDialect())]
-+
-+ dectype = CODEC_HEVC_RPI
-+ if os.path.exists("/dev/rpivid-hevcmem"):
-+ dectype = HWACCEL_RPI
-+ if args.drm or os.path.exists("/sys/module/rpivid_hevc"):
-+ dectype = HWACCEL_DRM
-+
-+ if args.pi4:
-+ dectype = HWACCEL_RPI
-+ elif args.drm:
-+ dectype = HWACCEL_DRM
-+ elif args.vaapi:
-+ dectype = HWACCEL_VAAPI
-+
-+ doconf(csva, args.tests, args.test_root, args.vcodec, dectype, args.ffmpeg)
-+
-diff --git a/pi-util/ffperf.py b/pi-util/ffperf.py
-new file mode 100755
-index 0000000000..65c5224cd8
---- /dev/null
-+++ b/pi-util/ffperf.py
-@@ -0,0 +1,128 @@
-+#!/usr/bin/env python3
-+
-+import time
-+import string
-+import os
-+import tempfile
-+import subprocess
-+import re
-+import argparse
-+import sys
-+import csv
-+from stat import *
-+
-+class tstats:
-+ close_threshold = 0.01
-+
-+ def __init__(self, stats_dict=None):
-+ if stats_dict != None:
-+ self.name = stats_dict["name"]
-+ self.elapsed = float(stats_dict["elapsed"])
-+ self.user = float(stats_dict["user"])
-+ self.sys = float(stats_dict["sys"])
-+
-+ def times_str(self):
-+ ctime = self.sys + self.user
-+ return "time=%6.2f, cpu=%6.2f (%4.2f%%)" % (self.elapsed, ctime, (ctime * 100.0) / self.elapsed)
-+
-+ def dict(self):
-+ return {"name":self.name, "elapsed":self.elapsed, "user":self.user, "sys":self.sys}
-+
-+ def is_close(self, other):
-+ return abs(self.elapsed - other.elapsed) / self.elapsed < self.close_threshold
-+
-+ def __lt__(self, other):
-+ return self.elapsed < other.elapsed
-+ def __gt__(self, other):
-+ return self.elapsed > other.elapsed
-+
-+ def time_file(name, prefix, ffmpeg="./ffmpeg"):
-+ stats = tstats()
-+ stats.name = name
-+ start_time = time.clock_gettime(time.CLOCK_MONOTONIC);
-+ cproc = subprocess.Popen([ffmpeg, "-no_cvt_hw",
-+ "-vcodec", "hevc_rpi",
-+ "-t", "30", "-i", prefix + name,
-+ "-f", "vout_rpi", os.devnull], bufsize=-1, stdout=flog, stderr=flog);
-+ pinfo = os.wait4(cproc.pid, 0)
-+ end_time = time.clock_gettime(time.CLOCK_MONOTONIC);
-+ stats.elapsed = end_time - start_time
-+ stats.user = pinfo[2].ru_utime
-+ stats.sys = pinfo[2].ru_stime
-+ return stats
-+
-+
-+def common_prefix(s1, s2):
-+ for i in range(min(len(s1),len(s2))):
-+ if s1[i] != s2[i]:
-+ return s1[:i]
-+ return s1[:i+1]
-+
-+def main():
-+ global flog
-+
-+ argp = argparse.ArgumentParser(description="FFmpeg performance tester", epilog="""
-+To blank the screen before starting use "xdg-screensaver activate"
-+(For some reason this doesn't seem to work from within python).
-+""")
-+
-+ argp.add_argument("streams", nargs='*')
-+ argp.add_argument("--csv_out", default="ffperf_out.csv", help="CSV output filename")
-+ argp.add_argument("--csv_in", help="CSV input filename")
-+ argp.add_argument("--prefix", help="Filename prefix (include terminal '/' if a directory).")
-+ argp.add_argument("--repeat", default=3, type=int, help="Run repeat count")
-+ argp.add_argument("--ffmpeg", default="./ffmpeg", help="FFmpeg executable")
-+
-+ args = argp.parse_args()
-+
-+ csv_out = csv.DictWriter(open(args.csv_out, 'w', newline=''), ["name", "elapsed", "user", "sys"])
-+ csv_out.writeheader()
-+
-+ stats_in = {}
-+ if args.csv_in != None:
-+ with open(args.csv_in, 'r', newline='') as f_in:
-+ stats_in = {x["name"]:tstats(x) for x in csv.DictReader(f_in)}
-+
-+ flog = open(os.path.join(tempfile.gettempdir(), "ffperf.log"), "wt")
-+
-+ streams = args.streams
-+ if not streams:
-+ if not stats_in:
-+ print ("No source streams specified")
-+ return 1
-+ prefix = "" if args.prefix == None else args.prefix
-+ streams = [k for k in stats_in]
-+ elif args.prefix != None:
-+ prefix = args.prefix
-+ else:
-+ prefix = streams[0]
-+ for f in streams[1:]:
-+ prefix = common_prefix(prefix, f)
-+ pp = prefix.rpartition(os.sep)
-+ prefix = pp[0] + pp[1]
-+ streams = [s[len(prefix):] for s in streams]
-+
-+ for f in sorted(streams, key=lambda x : "~" * x.count(os.sep) + x.lower()):
-+ print ("====", f)
-+
-+ t0 = tstats({"name":f, "elapsed":999, "user":999, "sys":999})
-+ for i in range(args.repeat):
-+ t = tstats.time_file(f, prefix, args.ffmpeg)
-+ print ("...", t.times_str())
-+ if t0 > t:
-+ t0 = t
-+
-+ if t0.name in stats_in:
-+ pstat = stats_in[t0.name]
-+ print("---" if pstat.is_close(t0) else "<<<" if t0 < pstat else ">>>", pstat.times_str())
-+
-+ csv_out.writerow(t0.dict())
-+
-+ print ()
-+
-+ return 0
-+
-+
-+if __name__ == '__main__':
-+ exit(main())
-+
-diff --git a/pi-util/genpatch.sh b/pi-util/genpatch.sh
-new file mode 100755
-index 0000000000..0948a68a7a
---- /dev/null
-+++ b/pi-util/genpatch.sh
-@@ -0,0 +1,35 @@
-+set -e
-+
-+NOPATCH=
-+if [ "$1" == "--notag" ]; then
-+ shift
-+ NOPATCH=1
-+fi
-+
-+if [ "$1" == "" ]; then
-+ echo Usage: $0 [--notag] \
-+ echo e.g.: $0 mmal_4
-+ exit 1
-+fi
-+
-+VERSION=`cat RELEASE`
-+if [ "$VERSION" == "" ]; then
-+ echo Can\'t find version RELEASE
-+ exit 1
-+fi
-+
-+PATCHFILE=../ffmpeg-$VERSION-$1.patch
-+
-+if [ $NOPATCH ]; then
-+ echo Not tagged
-+else
-+ # Only continue if we are all comitted
-+ git diff --name-status --exit-code
-+
-+ PATCHTAG=pi/$VERSION/$1
-+ echo Tagging: $PATCHTAG
-+
-+ git tag $PATCHTAG
-+fi
-+echo Generating patch: $PATCHFILE
-+git diff n$VERSION -- > $PATCHFILE
-diff --git a/pi-util/make_array.py b/pi-util/make_array.py
-new file mode 100755
-index 0000000000..67b22d2d51
---- /dev/null
-+++ b/pi-util/make_array.py
-@@ -0,0 +1,23 @@
-+#!/usr/bin/env python
-+
-+# Usage
-+# make_array file.bin
-+# Produces file.h with array of bytes.
-+#
-+import sys
-+for file in sys.argv[1:]:
-+ prefix,suffix = file.split('.')
-+ assert suffix=='bin'
-+ name=prefix.split('/')[-1]
-+ print 'Converting',file
-+ with open(prefix+'.h','wb') as out:
-+ print >>out, 'static const unsigned char',name,'[] = {'
-+ with open(file,'rb') as fd:
-+ i = 0
-+ for byte in fd.read():
-+ print >>out, '0x%02x, ' % ord(byte),
-+ i = i + 1
-+ if i % 8 == 0:
-+ print >>out, ' // %04x' % (i - 8)
-+ print >>out,'};'
-+
-diff --git a/pi-util/mkinst.sh b/pi-util/mkinst.sh
-new file mode 100755
-index 0000000000..271a39e846
---- /dev/null
-+++ b/pi-util/mkinst.sh
-@@ -0,0 +1,5 @@
-+set -e
-+
-+make install
-+
-+cp -r install/* ../vlc/sysroot/raspian_stretch_pi1-sysroot/usr
-diff --git a/pi-util/patkodi.sh b/pi-util/patkodi.sh
-new file mode 100644
-index 0000000000..dcd05a606e
---- /dev/null
-+++ b/pi-util/patkodi.sh
-@@ -0,0 +1,9 @@
-+set -e
-+KODIBASE=/home/jc/rpi/kodi/xbmc
-+JOBS=-j20
-+make $JOBS
-+git diff xbmc/release/4.3-kodi > $KODIBASE/tools/depends/target/ffmpeg/pfcd_hevc_optimisations.patch
-+make -C $KODIBASE/tools/depends/target/ffmpeg $JOBS
-+make -C $KODIBASE/build install
-+
-+
-diff --git a/pi-util/perfcmp.py b/pi-util/perfcmp.py
-new file mode 100755
-index 0000000000..e44cfa0c3c
---- /dev/null
-+++ b/pi-util/perfcmp.py
-@@ -0,0 +1,101 @@
-+#!/usr/bin/env python3
-+
-+import time
-+import string
-+import os
-+import tempfile
-+import subprocess
-+import re
-+import argparse
-+import sys
-+import csv
-+from stat import *
-+
-+class tstats:
-+ close_threshold = 0.01
-+
-+ def __init__(self, stats_dict=None):
-+ if stats_dict != None:
-+ self.name = stats_dict["name"]
-+ self.elapsed = float(stats_dict["elapsed"])
-+ self.user = float(stats_dict["user"])
-+ self.sys = float(stats_dict["sys"])
-+
-+ def times_str(self):
-+ ctime = self.sys + self.user
-+ return "time=%6.2f, cpu=%6.2f (%4.2f%%)" % (self.elapsed, ctime, (ctime * 100.0) / self.elapsed)
-+
-+ def dict(self):
-+ return {"name":self.name, "elapsed":self.elapsed, "user":self.user, "sys":self.sys}
-+
-+ def is_close(self, other):
-+ return abs(self.elapsed - other.elapsed) / self.elapsed < self.close_threshold
-+
-+ def __lt__(self, other):
-+ return self.elapsed < other.elapsed
-+ def __gt__(self, other):
-+ return self.elapsed > other.elapsed
-+
-+ def time_file(name, prefix):
-+ stats = tstats()
-+ stats.name = name
-+ start_time = time.clock_gettime(time.CLOCK_MONOTONIC);
-+ cproc = subprocess.Popen(["./ffmpeg", "-t", "30", "-i", prefix + name,
-+ "-f", "null", os.devnull], bufsize=-1, stdout=flog, stderr=flog);
-+ pinfo = os.wait4(cproc.pid, 0)
-+ end_time = time.clock_gettime(time.CLOCK_MONOTONIC);
-+ stats.elapsed = end_time - start_time
-+ stats.user = pinfo[2].ru_utime
-+ stats.sys = pinfo[2].ru_stime
-+ return stats
-+
-+
-+def common_prefix(s1, s2):
-+ for i in range(min(len(s1),len(s2))):
-+ if s1[i] != s2[i]:
-+ return s1[:i]
-+ return s1[:i+1]
-+
-+def main():
-+ argp = argparse.ArgumentParser(description="FFmpeg performance compare")
-+
-+ argp.add_argument("stream0", help="CSV to compare")
-+ argp.add_argument("stream1", nargs='?', default="ffperf_out.csv", help="CSV to compare")
-+
-+ args = argp.parse_args()
-+
-+ with open(args.stream0, 'r', newline='') as f_in:
-+ stats0 = {x["name"]:tstats(x) for x in csv.DictReader(f_in)}
-+ with open(args.stream1, 'r', newline='') as f_in:
-+ stats1 = {x["name"]:tstats(x) for x in csv.DictReader(f_in)}
-+
-+ print (args.stream0, "<<-->>", args.stream1)
-+ print ()
-+
-+ for f in sorted(stats0.keys() | stats1.keys(), key=lambda x : "~" * x.count(os.sep) + x.lower()):
-+ if not (f in stats0) :
-+ print (" XX :", f)
-+ continue
-+ if not (f in stats1) :
-+ print (" XX :", f)
-+ continue
-+
-+ s0 = stats0[f]
-+ s1 = stats1[f]
-+
-+ pcent = ((s0.elapsed - s1.elapsed) / s0.elapsed) * 100.0
-+ thresh = 0.3
-+ tc = 6
-+
-+ nchar = min(tc - 1, int(abs(pcent) / thresh))
-+ cc = " -- " if nchar == 0 else "<" * nchar + " " * (tc - nchar) if pcent < 0 else " " * (tc - nchar) + ">" * nchar
-+
-+ print ("%6.2f %s%6.2f (%+5.2f) : %s" %
-+ (s0.elapsed, cc, s1.elapsed, pcent, f))
-+
-+ return 0
-+
-+
-+if __name__ == '__main__':
-+ exit(main())
-+
-diff --git a/pi-util/qem.sh b/pi-util/qem.sh
-new file mode 100755
-index 0000000000..a4dbb6eacd
---- /dev/null
-+++ b/pi-util/qem.sh
-@@ -0,0 +1,9 @@
-+TARGET_DIR=../src/eupton_vc4dev_2012a/software/vc4/DEV/applications/tutorials/user_shader_example_tex
-+QASM=python\ ../local/bin/qasm.py
-+SRC_FILE=libavcodec/rpi_hevc_shader.qasm
-+DST_BASE=shader
-+
-+cp libavcodec/rpi_hevc_shader_cmd.h $TARGET_DIR
-+$QASM -mc_c:$DST_BASE,$DST_BASE,$DST_BASE $SRC_FILE > $TARGET_DIR/$DST_BASE.c
-+$QASM -mc_h:$DST_BASE,$DST_BASE,$DST_BASE $SRC_FILE > $TARGET_DIR/$DST_BASE.h
-+
-diff --git a/pi-util/v3dusage.py b/pi-util/v3dusage.py
-new file mode 100755
-index 0000000000..5935a11ca5
---- /dev/null
-+++ b/pi-util/v3dusage.py
-@@ -0,0 +1,128 @@
-+#!/usr/bin/env python
-+
-+import sys
-+import argparse
-+import re
-+
-+def do_logparse(logname):
-+
-+ rmatch = re.compile(r'^([0-9]+\.[0-9]{3}): (done )?((vpu0)|(vpu1)|(qpu1)) ([A-Z_]+) cb:([0-9a-f]+) ')
-+ rqcycle = re.compile(r'^([0-9]+\.[0-9]{3}): v3d: QPU Total clock cycles for all QPUs doing vertex/coordinate shading +([0-9]+)$')
-+ rqtscycle = re.compile(r'^([0-9]+\.[0-9]{3}): v3d: QPU Total clock cycles for all QPUs stalled waiting for TMUs +([0-9]+)$')
-+ rl2hits = re.compile(r'^([0-9]+\.[0-9]{3}): v3d: L2C Total Level 2 cache ([a-z]+) +([0-9]+)$')
-+
-+ ttotal = {'idle':0.0}
-+ tstart = {}
-+ qctotal = {}
-+ qtstotal = {}
-+ l2hits = {}
-+ l2total = {}
-+ time0 = None
-+ idle_start = None
-+ qpu_op_no = 0
-+ op_count = 0
-+
-+ with open(logname, "rt") as infile:
-+ for line in infile:
-+ match = rmatch.match(line)
-+ if match:
-+# print match.group(1), ":", match.group(2), ":", match.group(3), ":", match.group(7), ":"
-+ time = float(match.group(1))
-+ unit = match.group(3)
-+ opstart = not match.group(2)
-+ optype = match.group(7)
-+ hascb = match.group(8) != "0"
-+
-+ if unit == 'qpu1':
-+ unit = unit + "." + str(qpu_op_no)
-+ if not opstart:
-+ if hascb or optype == 'EXECUTE_SYNC':
-+ qpu_op_no = 0
-+ else:
-+ qpu_op_no += 1
-+
-+ # Ignore sync type
-+ if optype == 'EXECUTE_SYNC':
-+ continue
-+
-+ if not time0:
-+ time0 = time
-+
-+ if opstart:
-+ tstart[unit] = time;
-+ elif unit in tstart:
-+ op_count += 1
-+ if not unit in ttotal:
-+ ttotal[unit] = 0.0
-+ ttotal[unit] += time - tstart[unit]
-+ del tstart[unit]
-+
-+ if not idle_start and not tstart:
-+ idle_start = time
-+ elif idle_start and tstart:
-+ ttotal['idle'] += time - idle_start
-+ idle_start = None
-+
-+ match = rqcycle.match(line)
-+ if match:
-+ unit = "qpu1." + str(qpu_op_no)
-+ if not unit in qctotal:
-+ qctotal[unit] = 0
-+ qctotal[unit] += int(match.group(2))
-+
-+ match = rqtscycle.match(line)
-+ if match:
-+ unit = "qpu1." + str(qpu_op_no)
-+ if not unit in qtstotal:
-+ qtstotal[unit] = 0
-+ qtstotal[unit] += int(match.group(2))
-+
-+ match = rl2hits.match(line)
-+ if match:
-+ unit = "qpu1." + str(qpu_op_no)
-+ if not unit in l2total:
-+ l2total[unit] = 0
-+ l2hits[unit] = 0
-+ l2total[unit] += int(match.group(3))
-+ if match.group(2) == "hits":
-+ l2hits[unit] += int(match.group(3))
-+
-+
-+ if not time0:
-+ print "No v3d profile records found"
-+ else:
-+ tlogged = time - time0
-+
-+ print "Logged time:", tlogged, " Op count:", op_count
-+ for unit in sorted(ttotal):
-+ print b'%6s: %10.3f %7.3f%%' % (unit, ttotal[unit], ttotal[unit] * 100.0 / tlogged)
-+ print
-+ for unit in sorted(qctotal):
-+ if not unit in qtstotal:
-+ qtstotal[unit] = 0;
-+ print b'%6s: Qcycles: %10d, TMU stall: %10d (%7.3f%%)' % (unit, qctotal[unit], qtstotal[unit], (qtstotal[unit] * 100.0)/qctotal[unit])
-+ if unit in l2total:
-+ print b' L2Total: %10d, hits: %10d (%7.3f%%)' % (l2total[unit], l2hits[unit], (l2hits[unit] * 100.0)/l2total[unit])
-+
-+
-+
-+if __name__ == '__main__':
-+ argp = argparse.ArgumentParser(
-+ formatter_class=argparse.RawDescriptionHelpFormatter,
-+ description="QPU/VPU perf summary from VC logging",
-+ epilog = """
-+Will also summarise TMU stalls if logging requests set in qpu noflush param
-+in the profiled code.
-+
-+Example use:
-+ vcgencmd set_logging level=0xc0
-+
-+ sudo vcdbg log msg >& t.log
-+ v3dusage.py t.log
-+""")
-+
-+ argp.add_argument("logfile")
-+ args = argp.parse_args()
-+
-+ do_logparse(args.logfile)
-+
-
-From f3eaadb27a5bc6db07d33ce0814d796e8cee623e Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Tue, 27 Apr 2021 11:27:39 +0100
-Subject: [PATCH 002/151] Add sand pix fmts & conversion fns
-
----
- configure | 3 +
- libavutil/Makefile | 3 +
- libavutil/arm/Makefile | 1 +
- libavutil/arm/rpi_sand_neon.S | 768 ++++++++++++++++++++++++++++++++++
- libavutil/arm/rpi_sand_neon.h | 99 +++++
- libavutil/pixdesc.c | 44 ++
- libavutil/pixfmt.h | 6 +
- libavutil/rpi_sand_fn_pw.h | 227 ++++++++++
- libavutil/rpi_sand_fns.c | 353 ++++++++++++++++
- libavutil/rpi_sand_fns.h | 183 ++++++++
- 10 files changed, 1687 insertions(+)
- create mode 100644 libavutil/arm/rpi_sand_neon.S
- create mode 100644 libavutil/arm/rpi_sand_neon.h
- create mode 100644 libavutil/rpi_sand_fn_pw.h
- create mode 100644 libavutil/rpi_sand_fns.c
- create mode 100644 libavutil/rpi_sand_fns.h
-
-diff --git a/configure b/configure
-index b6616f00b6..27112ced58 100755
---- a/configure
-+++ b/configure
-@@ -344,6 +344,7 @@ External library support:
- --enable-libvpl enable Intel oneVPL code via libvpl if libmfx is not used [no]
- --enable-libnpp enable Nvidia Performance Primitives-based code [no]
- --enable-mmal enable Broadcom Multi-Media Abstraction Layer (Raspberry Pi) via MMAL [no]
-+ --enable-sand enable sand video formats [rpi]
- --disable-nvdec disable Nvidia video decoding acceleration (via hwaccel) [autodetect]
- --disable-nvenc disable Nvidia video encoding code [autodetect]
- --enable-omx enable OpenMAX IL code [no]
-@@ -1930,6 +1931,7 @@ FEATURE_LIST="
- omx_rpi
- runtime_cpudetect
- safe_bitstream_reader
-+ sand
- shared
- small
- static
-@@ -2495,6 +2497,7 @@ CONFIG_EXTRA="
- rtpdec
- rtpenc_chain
- rv34dsp
-+ sand
- scene_sad
- sinewin
- snappy
-diff --git a/libavutil/Makefile b/libavutil/Makefile
-index dc9012f9a8..e33f5db099 100644
---- a/libavutil/Makefile
-+++ b/libavutil/Makefile
-@@ -73,6 +73,7 @@ HEADERS = adler32.h \
- rational.h \
- replaygain.h \
- ripemd.h \
-+ rpi_sand_fns.h \
- samplefmt.h \
- sha.h \
- sha512.h \
-@@ -192,6 +193,7 @@ OBJS-$(CONFIG_MACOS_KPERF) += macos_kperf.o
- OBJS-$(CONFIG_MEDIACODEC) += hwcontext_mediacodec.o
- OBJS-$(CONFIG_OPENCL) += hwcontext_opencl.o
- OBJS-$(CONFIG_QSV) += hwcontext_qsv.o
-+OBJS-$(CONFIG_SAND) += rpi_sand_fns.o
- OBJS-$(CONFIG_VAAPI) += hwcontext_vaapi.o
- OBJS-$(CONFIG_VIDEOTOOLBOX) += hwcontext_videotoolbox.o
- OBJS-$(CONFIG_VDPAU) += hwcontext_vdpau.o
-@@ -212,6 +214,7 @@ SKIPHEADERS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.h
- SKIPHEADERS-$(CONFIG_DXVA2) += hwcontext_dxva2.h
- SKIPHEADERS-$(CONFIG_QSV) += hwcontext_qsv.h
- SKIPHEADERS-$(CONFIG_OPENCL) += hwcontext_opencl.h
-+SKIPHEADERS-$(CONFIG-RPI) += rpi_sand_fn_pw.h
- SKIPHEADERS-$(CONFIG_VAAPI) += hwcontext_vaapi.h
- SKIPHEADERS-$(CONFIG_VIDEOTOOLBOX) += hwcontext_videotoolbox.h
- SKIPHEADERS-$(CONFIG_VDPAU) += hwcontext_vdpau.h
-diff --git a/libavutil/arm/Makefile b/libavutil/arm/Makefile
-index 5da44b0542..b74b7c4e2f 100644
---- a/libavutil/arm/Makefile
-+++ b/libavutil/arm/Makefile
-@@ -6,3 +6,4 @@ VFP-OBJS += arm/float_dsp_init_vfp.o \
-
- NEON-OBJS += arm/float_dsp_init_neon.o \
- arm/float_dsp_neon.o \
-+ arm/rpi_sand_neon.o \
-diff --git a/libavutil/arm/rpi_sand_neon.S b/libavutil/arm/rpi_sand_neon.S
-new file mode 100644
-index 0000000000..80890fe985
---- /dev/null
-+++ b/libavutil/arm/rpi_sand_neon.S
-@@ -0,0 +1,768 @@
-+/*
-+Copyright (c) 2018 Raspberry Pi (Trading) Ltd.
-+All rights reserved.
-+
-+Redistribution and use in source and binary forms, with or without
-+modification, are permitted provided that the following conditions are met:
-+ * Redistributions of source code must retain the above copyright
-+ notice, this list of conditions and the following disclaimer.
-+ * Redistributions in binary form must reproduce the above copyright
-+ notice, this list of conditions and the following disclaimer in the
-+ documentation and/or other materials provided with the distribution.
-+ * Neither the name of the copyright holder nor the
-+ names of its contributors may be used to endorse or promote products
-+ derived from this software without specific prior written permission.
-+
-+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
-+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+
-+Authors: John Cox
-+*/
-+
-+#include "libavutil/arm/asm.S"
-+
-+
-+@ General notes:
-+@ Having done some timing on this in sand8->y8 (Pi4)
-+@ vst1 (680fps) is a bit faster than vstm (660fps)
-+@ vldm (680fps) is noticably faster than vld1 (480fps)
-+@ (or it might be that a mix is what is required)
-+@
-+@ At least on a Pi4 it is no more expensive to have a single auto-inc register
-+@ for dest address than it is to have 2 used alternately (On Pi3 Ben asserted
-+@ the latter was better)
-+@
-+@ vstm will bus error on unaligned access (so will vldm), vst1 is safe unless
-+@ the memory is uncached.
-+@ As these are Sand -> planar we can assume that src is going to be aligned but
-+@ it is possible that dest isn't (converting to .yuv or other packed format).
-+@ Luckily vst1 is faster than vstm :-) so all is well
-+@ vst1 has alignment requirements of el size so maybe splitting vst1.32 into 4
-+@ .8 stores would let us do non-word aligned stores into uncached but it
-+@ probably isn't worth it.
-+
-+
-+
-+
-+@ void ff_rpi_sand128b_stripe_to_8_10(
-+@ uint8_t * dest, // [r0]
-+@ const uint8_t * src1, // [r1]
-+@ const uint8_t * src2, // [r2]
-+@ unsigned int lines); // [r3]
-+
-+.macro stripe2_to_8, bit_depth
-+ vpush {q4-q7}
-+1:
-+ vldm r1!, {q0-q7}
-+ subs r3, #1
-+ vldm r2!, {q8-q15}
-+ vqrshrn.u16 d0, q0, #\bit_depth - 8
-+ vqrshrn.u16 d1, q1, #\bit_depth - 8
-+ vqrshrn.u16 d2, q2, #\bit_depth - 8
-+ vqrshrn.u16 d3, q3, #\bit_depth - 8
-+ vqrshrn.u16 d4, q4, #\bit_depth - 8
-+ vqrshrn.u16 d5, q5, #\bit_depth - 8
-+ vqrshrn.u16 d6, q6, #\bit_depth - 8
-+ vqrshrn.u16 d7, q7, #\bit_depth - 8
-+ vqrshrn.u16 d8, q8, #\bit_depth - 8
-+ vqrshrn.u16 d9, q9, #\bit_depth - 8
-+ vqrshrn.u16 d10, q10, #\bit_depth - 8
-+ vqrshrn.u16 d11, q11, #\bit_depth - 8
-+ vqrshrn.u16 d12, q12, #\bit_depth - 8
-+ vqrshrn.u16 d13, q13, #\bit_depth - 8
-+ vqrshrn.u16 d14, q14, #\bit_depth - 8
-+ vqrshrn.u16 d15, q15, #\bit_depth - 8
-+ vstm r0!, {q0-q7}
-+ bne 1b
-+ vpop {q4-q7}
-+ bx lr
-+.endm
-+
-+function ff_rpi_sand128b_stripe_to_8_10, export=1
-+ stripe2_to_8 10
-+endfunc
-+
-+@ void ff_rpi_sand8_lines_to_planar_y8(
-+@ uint8_t * dest, // [r0]
-+@ unsigned int dst_stride, // [r1]
-+@ const uint8_t * src, // [r2]
-+@ unsigned int src_stride1, // [r3] Ignored - assumed 128
-+@ unsigned int src_stride2, // [sp, #0] -> r3
-+@ unsigned int _x, // [sp, #4] Ignored - 0
-+@ unsigned int y, // [sp, #8] (r7 in prefix)
-+@ unsigned int _w, // [sp, #12] -> r6 (cur r5)
-+@ unsigned int h); // [sp, #16] -> r7
-+@
-+@ Assumes that we are starting on a stripe boundary and that overreading
-+@ within the stripe is OK. However it does respect the dest size for writing
-+
-+function ff_rpi_sand8_lines_to_planar_y8, export=1
-+ push {r4-r8, lr} @ +24 L
-+ ldr r3, [sp, #24]
-+ ldr r6, [sp, #36]
-+ ldr r7, [sp, #32] @ y
-+ lsl r3, #7
-+ sub r1, r6
-+ add r8, r2, r7, lsl #7
-+ ldr r7, [sp, #40]
-+
-+10:
-+ mov r2, r8
-+ add r4, r0, #24
-+ mov r5, r6
-+ mov lr, #0
-+1:
-+ vldm r2, {q8-q15}
-+ add r2, r3
-+ subs r5, #128
-+ blt 2f
-+ vst1.8 {d16, d17, d18, d19}, [r0]!
-+ vst1.8 {d20, d21, d22, d23}, [r0]!
-+ vst1.8 {d24, d25, d26, d27}, [r0]!
-+ vst1.8 {d28, d29, d30, d31}, [r0]!
-+ bne 1b
-+11:
-+ subs r7, #1
-+ add r0, r1
-+ add r8, #128
-+ bne 10b
-+
-+ pop {r4-r8, pc}
-+
-+@ Partial final write
-+2:
-+ cmp r5, #64-128
-+ blt 1f
-+ vst1.8 {d16, d17, d18, d19}, [r0]!
-+ vst1.8 {d20, d21, d22, d23}, [r0]!
-+ beq 11b
-+ vmov q8, q12
-+ vmov q9, q13
-+ sub r5, #64
-+ vmov q10, q14
-+ vmov q11, q15
-+1:
-+ cmp r5, #32-128
-+ blt 1f
-+ vst1.8 {d16, d17, d18, d19}, [r0]!
-+ beq 11b
-+ vmov q8, q10
-+ sub r5, #32
-+ vmov q9, q11
-+1:
-+ cmp r5, #16-128
-+ blt 1f
-+ vst1.8 {d16, d17}, [r0]!
-+ beq 11b
-+ sub r5, #16
-+ vmov q8, q9
-+1:
-+ cmp r5, #8-128
-+ blt 1f
-+ vst1.8 {d16}, [r0]!
-+ beq 11b
-+ sub r5, #8
-+ vmov d16, d17
-+1:
-+ cmp r5, #4-128
-+ blt 1f
-+ vst1.32 {d16[0]}, [r0]!
-+ beq 11b
-+ sub r5, #4
-+ vshr.u64 d16, #32
-+1:
-+ cmp r5, #2-128
-+ blt 1f
-+ vst1.16 {d16[0]}, [r0]!
-+ beq 11b
-+ vst1.8 {d16[2]}, [r0]!
-+ b 11b
-+1:
-+ vst1.8 {d16[0]}, [r0]!
-+ b 11b
-+endfunc
-+
-+@ void ff_rpi_sand8_lines_to_planar_c8(
-+@ uint8_t * dst_u, // [r0]
-+@ unsigned int dst_stride_u, // [r1]
-+@ uint8_t * dst_v, // [r2]
-+@ unsigned int dst_stride_v, // [r3]
-+@ const uint8_t * src, // [sp, #0] -> r4, r5
-+@ unsigned int stride1, // [sp, #4] 128
-+@ unsigned int stride2, // [sp, #8] -> r8
-+@ unsigned int _x, // [sp, #12] 0
-+@ unsigned int y, // [sp, #16] (r7 in prefix)
-+@ unsigned int _w, // [sp, #20] -> r12, r6
-+@ unsigned int h); // [sp, #24] -> r7
-+@
-+@ Assumes that we are starting on a stripe boundary and that overreading
-+@ within the stripe is OK. However it does respect the dest size for writing
-+
-+function ff_rpi_sand8_lines_to_planar_c8, export=1
-+ push {r4-r8, lr} @ +24
-+
-+ ldr r5, [sp, #24]
-+ ldr r8, [sp, #32]
-+ ldr r7, [sp, #40]
-+ ldr r6, [sp, #44]
-+ lsl r8, #7
-+ add r5, r5, r7, lsl #7
-+ sub r1, r1, r6
-+ sub r3, r3, r6
-+ ldr r7, [sp, #48]
-+ vpush {q4-q7}
-+
-+10:
-+ mov r4, r5
-+ mov r12, r6
-+1:
-+ subs r12, #64
-+ vldm r4, {q0-q7}
-+ add r4, r8
-+ it gt
-+ vldmgt r4, {q8-q15}
-+ add r4, r8
-+
-+ vuzp.8 q0, q1
-+ vuzp.8 q2, q3
-+ vuzp.8 q4, q5
-+ vuzp.8 q6, q7
-+
-+ vuzp.8 q8, q9
-+ vuzp.8 q10, q11
-+ vuzp.8 q12, q13
-+ vuzp.8 q14, q15
-+ subs r12, #64
-+
-+ @ Rearrange regs so we can use vst1 with 4 regs
-+ vswp q1, q2
-+ vswp q5, q6
-+ vswp q9, q10
-+ vswp q13, q14
-+ blt 2f
-+
-+ vst1.8 {d0, d1, d2, d3 }, [r0]!
-+ vst1.8 {d8, d9, d10, d11}, [r0]!
-+ vst1.8 {d16, d17, d18, d19}, [r0]!
-+ vst1.8 {d24, d25, d26, d27}, [r0]!
-+
-+ vst1.8 {d4, d5, d6, d7 }, [r2]!
-+ vst1.8 {d12, d13, d14, d15}, [r2]!
-+ vst1.8 {d20, d21, d22, d23}, [r2]!
-+ vst1.8 {d28, d29, d30, d31}, [r2]!
-+ bne 1b
-+11:
-+ subs r7, #1
-+ add r5, #128
-+ add r0, r1
-+ add r2, r3
-+ bne 10b
-+ vpop {q4-q7}
-+ pop {r4-r8,pc}
-+
-+2:
-+ cmp r12, #64-128
-+ blt 1f
-+ vst1.8 {d0, d1, d2, d3 }, [r0]!
-+ vst1.8 {d8, d9, d10, d11}, [r0]!
-+ vst1.8 {d4, d5, d6, d7 }, [r2]!
-+ vst1.8 {d12, d13, d14, d15}, [r2]!
-+ beq 11b
-+ sub r12, #64
-+ vmov q0, q8
-+ vmov q1, q9
-+ vmov q2, q10
-+ vmov q3, q11
-+ vmov q4, q12
-+ vmov q5, q13
-+ vmov q6, q14
-+ vmov q7, q15
-+1:
-+ cmp r12, #32-128
-+ blt 1f
-+ vst1.8 {d0, d1, d2, d3 }, [r0]!
-+ vst1.8 {d4, d5, d6, d7 }, [r2]!
-+ beq 11b
-+ sub r12, #32
-+ vmov q0, q4
-+ vmov q1, q5
-+ vmov q2, q6
-+ vmov q3, q7
-+1:
-+ cmp r12, #16-128
-+ blt 1f
-+ vst1.8 {d0, d1 }, [r0]!
-+ vst1.8 {d4, d5 }, [r2]!
-+ beq 11b
-+ sub r12, #16
-+ vmov q0, q1
-+ vmov q2, q3
-+1:
-+ cmp r12, #8-128
-+ blt 1f
-+ vst1.8 {d0}, [r0]!
-+ vst1.8 {d4}, [r2]!
-+ beq 11b
-+ sub r12, #8
-+ vmov d0, d1
-+ vmov d4, d5
-+1:
-+ cmp r12, #4-128
-+ blt 1f
-+ vst1.32 {d0[0]}, [r0]!
-+ vst1.32 {d4[0]}, [r2]!
-+ beq 11b
-+ sub r12, #4
-+ vmov s0, s1
-+ vmov s8, s9
-+1:
-+ cmp r12, #2-128
-+ blt 1f
-+ vst1.16 {d0[0]}, [r0]!
-+ vst1.16 {d4[0]}, [r2]!
-+ beq 11b
-+ vst1.8 {d0[2]}, [r0]!
-+ vst1.8 {d4[2]}, [r2]!
-+ b 11b
-+1:
-+ vst1.8 {d0[0]}, [r0]!
-+ vst1.8 {d4[0]}, [r2]!
-+ b 11b
-+endfunc
-+
-+
-+
-+@ void ff_rpi_sand30_lines_to_planar_y16(
-+@ uint8_t * dest, // [r0]
-+@ unsigned int dst_stride, // [r1]
-+@ const uint8_t * src, // [r2]
-+@ unsigned int src_stride1, // [r3] Ignored - assumed 128
-+@ unsigned int src_stride2, // [sp, #0] -> r3
-+@ unsigned int _x, // [sp, #4] Ignored - 0
-+@ unsigned int y, // [sp, #8] (r7 in prefix)
-+@ unsigned int _w, // [sp, #12] -> r6 (cur r5)
-+@ unsigned int h); // [sp, #16] -> r7
-+@
-+@ Assumes that we are starting on a stripe boundary and that overreading
-+@ within the stripe is OK. However it does respect the dest size for writing
-+
-+function ff_rpi_sand30_lines_to_planar_y16, export=1
-+ push {r4-r8, lr} @ +24
-+ ldr r3, [sp, #24]
-+ ldr r6, [sp, #36]
-+ ldr r7, [sp, #32] @ y
-+ mov r12, #48
-+ vmov.u16 q15, #0x3ff
-+ sub r3, #1
-+ lsl r3, #7
-+ sub r1, r1, r6, lsl #1
-+ add r8, r2, r7, lsl #7
-+ ldr r7, [sp, #40]
-+
-+10:
-+ mov r2, r8
-+ add r4, r0, #24
-+ mov r5, r6
-+ mov lr, #0
-+1:
-+ vldm r2!, {q10-q13}
-+ add lr, #64
-+
-+ vshr.u32 q14, q10, #20 @ Cannot vshrn.u32 #20!
-+ ands lr, #127
-+ vshrn.u32 d2, q10, #10
-+ vmovn.u32 d0, q10
-+ vmovn.u32 d4, q14
-+
-+ vshr.u32 q14, q11, #20
-+ it eq
-+ addeq r2, r3
-+ vshrn.u32 d3, q11, #10
-+ vmovn.u32 d1, q11
-+ vmovn.u32 d5, q14
-+
-+ subs r5, #48
-+ vand q0, q15
-+ vand q1, q15
-+ vand q2, q15
-+
-+ vshr.u32 q14, q12, #20
-+ vshrn.u32 d18, q12, #10
-+ vmovn.u32 d16, q12
-+ vmovn.u32 d20, q14
-+
-+ vshr.u32 q14, q13, #20
-+ vshrn.u32 d19, q13, #10
-+ vmovn.u32 d17, q13
-+ vmovn.u32 d21, q14
-+
-+ vand q8, q15
-+ vand q9, q15
-+ vand q10, q15
-+ blt 2f
-+
-+ vst3.16 {d0, d2, d4}, [r0], r12
-+ vst3.16 {d1, d3, d5}, [r4], r12
-+ vst3.16 {d16, d18, d20}, [r0], r12
-+ vst3.16 {d17, d19, d21}, [r4], r12
-+
-+ bne 1b
-+
-+11:
-+ subs r7, #1
-+ add r0, r1
-+ add r8, #128
-+ bne 10b
-+
-+ pop {r4-r8, pc}
-+
-+@ Partial final write
-+2:
-+ cmp r5, #24-48
-+ blt 1f
-+ vst3.16 {d0, d2, d4}, [r0], r12
-+ vst3.16 {d1, d3, d5}, [r4]
-+ beq 11b
-+ vmov q0, q8
-+ sub r5, #24
-+ vmov q1, q9
-+ vmov q2, q10
-+1:
-+ cmp r5, #12-48
-+ blt 1f
-+ vst3.16 {d0, d2, d4}, [r0]!
-+ beq 11b
-+ vmov d0, d1
-+ sub r5, #12
-+ vmov d2, d3
-+ vmov d4, d5
-+1:
-+ cmp r5, #6-48
-+ add r4, r0, #6 @ avoid [r0]! on sequential instructions
-+ blt 1f
-+ vst3.16 {d0[0], d2[0], d4[0]}, [r0]
-+ vst3.16 {d0[1], d2[1], d4[1]}, [r4]
-+ add r0, #12
-+ beq 11b
-+ vmov s0, s1
-+ sub r5, #6
-+ vmov s4, s5
-+ vmov s8, s9
-+1:
-+ cmp r5, #3-48
-+ blt 1f
-+ vst3.16 {d0[0], d2[0], d4[0]}, [r0]!
-+ beq 11b
-+ sub r5, #3
-+ vshr.u32 d0, #16
-+ vshr.u32 d2, #16
-+1:
-+ cmp r5, #2-48
-+ blt 1f
-+ vst2.16 {d0[0], d2[0]}, [r0]!
-+ b 11b
-+1:
-+ vst1.16 {d0[0]}, [r0]!
-+ b 11b
-+
-+endfunc
-+
-+
-+@ void ff_rpi_sand30_lines_to_planar_c16(
-+@ uint8_t * dst_u, // [r0]
-+@ unsigned int dst_stride_u, // [r1]
-+@ uint8_t * dst_v, // [r2]
-+@ unsigned int dst_stride_v, // [r3]
-+@ const uint8_t * src, // [sp, #0] -> r4, r5
-+@ unsigned int stride1, // [sp, #4] 128
-+@ unsigned int stride2, // [sp, #8] -> r8
-+@ unsigned int _x, // [sp, #12] 0
-+@ unsigned int y, // [sp, #16] (r7 in prefix)
-+@ unsigned int _w, // [sp, #20] -> r6, r9
-+@ unsigned int h); // [sp, #24] -> r7
-+@
-+@ Assumes that we are starting on a stripe boundary and that overreading
-+@ within the stripe is OK. However it does respect the dest size for writing
-+
-+function ff_rpi_sand30_lines_to_planar_c16, export=1
-+ push {r4-r10, lr} @ +32
-+ ldr r5, [sp, #32]
-+ ldr r8, [sp, #40]
-+ ldr r7, [sp, #48]
-+ ldr r9, [sp, #52]
-+ mov r12, #48
-+ vmov.u16 q15, #0x3ff
-+ sub r8, #1
-+ lsl r8, #7
-+ add r5, r5, r7, lsl #7
-+ sub r1, r1, r9, lsl #1
-+ sub r3, r3, r9, lsl #1
-+ ldr r7, [sp, #56]
-+10:
-+ mov lr, #0
-+ mov r4, r5
-+ mov r6, r9
-+1:
-+ vldm r4!, {q0-q3}
-+ add lr, #64
-+
-+ @ N.B. unpack [0,1,2] -> (reg order) 1, 0, 2
-+ vshr.u32 q14, q0, #20
-+ vshrn.u32 d16, q0, #10
-+ vmovn.u32 d18, q0
-+ ands lr, #127
-+ vmovn.u32 d20, q14
-+
-+ vshr.u32 q14, q1, #20
-+ vshrn.u32 d17, q1, #10
-+ vmovn.u32 d19, q1
-+ vmovn.u32 d21, q14
-+
-+ vshr.u32 q14, q2, #20
-+ vshrn.u32 d22, q2, #10
-+ vmovn.u32 d24, q2
-+ vmovn.u32 d26, q14
-+
-+ vshr.u32 q14, q3, #20
-+ vshrn.u32 d23, q3, #10
-+ vmovn.u32 d25, q3
-+ add r10, r0, #24
-+ vmovn.u32 d27, q14
-+
-+ it eq
-+ addeq r4, r8
-+ vuzp.16 q8, q11
-+ vuzp.16 q9, q12
-+ vuzp.16 q10, q13
-+
-+ @ q8 V0, V3,.. -> q0
-+ @ q9 U0, U3...
-+ @ q10 U1, U4...
-+ @ q11 U2, U5,..
-+ @ q12 V1, V4,.. -> q1
-+ @ q13 V2, V5,.. -> q2
-+
-+ subs r6, #24
-+ vand q11, q15
-+ vand q9, q15
-+ vand q10, q15
-+ vand q0, q8, q15
-+ vand q1, q12, q15
-+ vand q2, q13, q15
-+
-+ blt 2f
-+
-+ vst3.16 {d18, d20, d22}, [r0], r12
-+ vst3.16 {d19, d21, d23}, [r10]
-+ add r10, r2, #24
-+ vst3.16 {d0, d2, d4}, [r2], r12
-+ vst3.16 {d1, d3, d5}, [r10]
-+
-+ bne 1b
-+
-+11:
-+ subs r7, #1
-+ add r5, #128
-+ add r0, r1
-+ add r2, r3
-+ bne 10b
-+
-+ pop {r4-r10, pc}
-+
-+@ Partial final write
-+2:
-+ cmp r6, #-12
-+ blt 1f
-+ vst3.16 {d18, d20, d22}, [r0]!
-+ vst3.16 {d0, d2, d4}, [r2]!
-+ beq 11b
-+ vmov d18, d19
-+ vmov d20, d21
-+ vmov d22, d23
-+ sub r6, #12
-+ vmov d0, d1
-+ vmov d2, d3
-+ vmov d4, d5
-+1:
-+ cmp r6, #-18
-+ @ Rezip here as it makes the remaining tail handling easier
-+ vzip.16 d0, d18
-+ vzip.16 d2, d20
-+ vzip.16 d4, d22
-+ blt 1f
-+ vst3.16 {d0[1], d2[1], d4[1]}, [r0]!
-+ vst3.16 {d0[0], d2[0], d4[0]}, [r2]!
-+ vst3.16 {d0[3], d2[3], d4[3]}, [r0]!
-+ vst3.16 {d0[2], d2[2], d4[2]}, [r2]!
-+ beq 11b
-+ vmov d0, d18
-+ vmov d2, d20
-+ sub r6, #6
-+ vmov d4, d22
-+1:
-+ cmp r6, #-21
-+ blt 1f
-+ vst3.16 {d0[1], d2[1], d4[1]}, [r0]!
-+ vst3.16 {d0[0], d2[0], d4[0]}, [r2]!
-+ beq 11b
-+ vmov s4, s5
-+ sub r6, #3
-+ vmov s0, s1
-+1:
-+ cmp r6, #-22
-+ blt 1f
-+ vst2.16 {d0[1], d2[1]}, [r0]!
-+ vst2.16 {d0[0], d2[0]}, [r2]!
-+ b 11b
-+1:
-+ vst1.16 {d0[1]}, [r0]!
-+ vst1.16 {d0[0]}, [r2]!
-+ b 11b
-+
-+endfunc
-+
-+@ void ff_rpi_sand30_lines_to_planar_p010(
-+@ uint8_t * dest, // [r0]
-+@ unsigned int dst_stride, // [r1]
-+@ const uint8_t * src, // [r2]
-+@ unsigned int src_stride1, // [r3] Ignored - assumed 128
-+@ unsigned int src_stride2, // [sp, #0] -> r3
-+@ unsigned int _x, // [sp, #4] Ignored - 0
-+@ unsigned int y, // [sp, #8] (r7 in prefix)
-+@ unsigned int _w, // [sp, #12] -> r6 (cur r5)
-+@ unsigned int h); // [sp, #16] -> r7
-+@
-+@ Assumes that we are starting on a stripe boundary and that overreading
-+@ within the stripe is OK. However it does respect the dest size for writing
-+
-+function ff_rpi_sand30_lines_to_planar_p010, export=1
-+ push {r4-r8, lr} @ +24
-+ ldr r3, [sp, #24]
-+ ldr r6, [sp, #36]
-+ ldr r7, [sp, #32] @ y
-+ mov r12, #48
-+ vmov.u16 q15, #0xffc0
-+ sub r3, #1
-+ lsl r3, #7
-+ sub r1, r1, r6, lsl #1
-+ add r8, r2, r7, lsl #7
-+ ldr r7, [sp, #40]
-+
-+10:
-+ mov r2, r8
-+ add r4, r0, #24
-+ mov r5, r6
-+ mov lr, #0
-+1:
-+ vldm r2!, {q10-q13}
-+ add lr, #64
-+
-+ vshl.u32 q14, q10, #6
-+ ands lr, #127
-+ vshrn.u32 d4, q10, #14
-+ vshrn.u32 d2, q10, #4
-+ vmovn.u32 d0, q14
-+
-+ vshl.u32 q14, q11, #6
-+ it eq
-+ addeq r2, r3
-+ vshrn.u32 d5, q11, #14
-+ vshrn.u32 d3, q11, #4
-+ vmovn.u32 d1, q14
-+
-+ subs r5, #48
-+ vand q2, q15
-+ vand q1, q15
-+ vand q0, q15
-+
-+ vshl.u32 q14, q12, #6
-+ vshrn.u32 d20, q12, #14
-+ vshrn.u32 d18, q12, #4
-+ vmovn.u32 d16, q14
-+
-+ vshl.u32 q14, q13, #6
-+ vshrn.u32 d21, q13, #14
-+ vshrn.u32 d19, q13, #4
-+ vmovn.u32 d17, q14
-+
-+ vand q10, q15
-+ vand q9, q15
-+ vand q8, q15
-+ blt 2f
-+
-+ vst3.16 {d0, d2, d4}, [r0], r12
-+ vst3.16 {d1, d3, d5}, [r4], r12
-+ vst3.16 {d16, d18, d20}, [r0], r12
-+ vst3.16 {d17, d19, d21}, [r4], r12
-+
-+ bne 1b
-+
-+11:
-+ subs r7, #1
-+ add r0, r1
-+ add r8, #128
-+ bne 10b
-+
-+ pop {r4-r8, pc}
-+
-+@ Partial final write
-+2:
-+ cmp r5, #24-48
-+ blt 1f
-+ vst3.16 {d0, d2, d4}, [r0], r12
-+ vst3.16 {d1, d3, d5}, [r4]
-+ beq 11b
-+ vmov q0, q8
-+ sub r5, #24
-+ vmov q1, q9
-+ vmov q2, q10
-+1:
-+ cmp r5, #12-48
-+ blt 1f
-+ vst3.16 {d0, d2, d4}, [r0]!
-+ beq 11b
-+ vmov d0, d1
-+ sub r5, #12
-+ vmov d2, d3
-+ vmov d4, d5
-+1:
-+ cmp r5, #6-48
-+ add r4, r0, #6 @ avoid [r0]! on sequential instructions
-+ blt 1f
-+ vst3.16 {d0[0], d2[0], d4[0]}, [r0]
-+ vst3.16 {d0[1], d2[1], d4[1]}, [r4]
-+ add r0, #12
-+ beq 11b
-+ vmov s0, s1
-+ sub r5, #6
-+ vmov s4, s5
-+ vmov s8, s9
-+1:
-+ cmp r5, #3-48
-+ blt 1f
-+ vst3.16 {d0[0], d2[0], d4[0]}, [r0]!
-+ beq 11b
-+ sub r5, #3
-+ vshr.u32 d0, #16
-+ vshr.u32 d2, #16
-+1:
-+ cmp r5, #2-48
-+ blt 1f
-+ vst2.16 {d0[0], d2[0]}, [r0]!
-+ b 11b
-+1:
-+ vst1.16 {d0[0]}, [r0]!
-+ b 11b
-+
-+endfunc
-+
-+
-+
-diff --git a/libavutil/arm/rpi_sand_neon.h b/libavutil/arm/rpi_sand_neon.h
-new file mode 100644
-index 0000000000..447f367bea
---- /dev/null
-+++ b/libavutil/arm/rpi_sand_neon.h
-@@ -0,0 +1,99 @@
-+/*
-+Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
-+All rights reserved.
-+
-+Redistribution and use in source and binary forms, with or without
-+modification, are permitted provided that the following conditions are met:
-+ * Redistributions of source code must retain the above copyright
-+ notice, this list of conditions and the following disclaimer.
-+ * Redistributions in binary form must reproduce the above copyright
-+ notice, this list of conditions and the following disclaimer in the
-+ documentation and/or other materials provided with the distribution.
-+ * Neither the name of the copyright holder nor the
-+ names of its contributors may be used to endorse or promote products
-+ derived from this software without specific prior written permission.
-+
-+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
-+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+
-+Authors: John Cox
-+*/
-+
-+#ifndef AVUTIL_ARM_SAND_NEON_H
-+#define AVUTIL_ARM_SAND_NEON_H
-+
-+void ff_rpi_sand128b_stripe_to_8_10(
-+ uint8_t * dest, // [r0]
-+ const uint8_t * src1, // [r1]
-+ const uint8_t * src2, // [r2]
-+ unsigned int lines); // [r3]
-+
-+void ff_rpi_sand8_lines_to_planar_y8(
-+ uint8_t * dest, // [r0]
-+ unsigned int dst_stride, // [r1]
-+ const uint8_t * src, // [r2]
-+ unsigned int src_stride1, // [r3] Ignored - assumed 128
-+ unsigned int src_stride2, // [sp, #0] -> r3
-+ unsigned int _x, // [sp, #4] Ignored - 0
-+ unsigned int y, // [sp, #8] (r7 in prefix)
-+ unsigned int _w, // [sp, #12] -> r6 (cur r5)
-+ unsigned int h); // [sp, #16] -> r7
-+
-+void ff_rpi_sand8_lines_to_planar_c8(
-+ uint8_t * dst_u, // [r0]
-+ unsigned int dst_stride_u, // [r1]
-+ uint8_t * dst_v, // [r2]
-+ unsigned int dst_stride_v, // [r3]
-+ const uint8_t * src, // [sp, #0] -> r4, r5
-+ unsigned int stride1, // [sp, #4] 128
-+ unsigned int stride2, // [sp, #8] -> r8
-+ unsigned int _x, // [sp, #12] 0
-+ unsigned int y, // [sp, #16] (r7 in prefix)
-+ unsigned int _w, // [sp, #20] -> r12, r6
-+ unsigned int h); // [sp, #24] -> r7
-+
-+void ff_rpi_sand30_lines_to_planar_y16(
-+ uint8_t * dest, // [r0]
-+ unsigned int dst_stride, // [r1]
-+ const uint8_t * src, // [r2]
-+ unsigned int src_stride1, // [r3] Ignored - assumed 128
-+ unsigned int src_stride2, // [sp, #0] -> r3
-+ unsigned int _x, // [sp, #4] Ignored - 0
-+ unsigned int y, // [sp, #8] (r7 in prefix)
-+ unsigned int _w, // [sp, #12] -> r6 (cur r5)
-+ unsigned int h); // [sp, #16] -> r7
-+
-+void ff_rpi_sand30_lines_to_planar_c16(
-+ uint8_t * dst_u, // [r0]
-+ unsigned int dst_stride_u, // [r1]
-+ uint8_t * dst_v, // [r2]
-+ unsigned int dst_stride_v, // [r3]
-+ const uint8_t * src, // [sp, #0] -> r4, r5
-+ unsigned int stride1, // [sp, #4] 128
-+ unsigned int stride2, // [sp, #8] -> r8
-+ unsigned int _x, // [sp, #12] 0
-+ unsigned int y, // [sp, #16] (r7 in prefix)
-+ unsigned int _w, // [sp, #20] -> r6, r9
-+ unsigned int h); // [sp, #24] -> r7
-+
-+void ff_rpi_sand30_lines_to_planar_p010(
-+ uint8_t * dest, // [r0]
-+ unsigned int dst_stride, // [r1]
-+ const uint8_t * src, // [r2]
-+ unsigned int src_stride1, // [r3] Ignored - assumed 128
-+ unsigned int src_stride2, // [sp, #0] -> r3
-+ unsigned int _x, // [sp, #4] Ignored - 0
-+ unsigned int y, // [sp, #8] (r7 in prefix)
-+ unsigned int _w, // [sp, #12] -> r6 (cur r5)
-+ unsigned int h); // [sp, #16] -> r7
-+
-+#endif // AVUTIL_ARM_SAND_NEON_H
-+
-diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c
-index 62a2ae08d9..cb73521ea7 100644
---- a/libavutil/pixdesc.c
-+++ b/libavutil/pixdesc.c
-@@ -2717,6 +2717,50 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
- .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_FLOAT |
- AV_PIX_FMT_FLAG_ALPHA,
- },
-+ [AV_PIX_FMT_SAND128] = {
-+ .name = "sand128",
-+ .nb_components = 3,
-+ .log2_chroma_w = 1,
-+ .log2_chroma_h = 1,
-+ .comp = {
-+ { 0, 1, 0, 0, 8 }, /* Y */
-+ { 1, 2, 0, 0, 8 }, /* U */
-+ { 1, 2, 1, 0, 8 }, /* V */
-+ },
-+ .flags = 0,
-+ },
-+ [AV_PIX_FMT_SAND64_10] = {
-+ .name = "sand64_10",
-+ .nb_components = 3,
-+ .log2_chroma_w = 1,
-+ .log2_chroma_h = 1,
-+ .comp = {
-+ { 0, 2, 0, 0, 10 }, /* Y */
-+ { 1, 4, 0, 0, 10 }, /* U */
-+ { 1, 4, 2, 0, 10 }, /* V */
-+ },
-+ .flags = 0,
-+ },
-+ [AV_PIX_FMT_SAND64_16] = {
-+ .name = "sand64_16",
-+ .nb_components = 3,
-+ .log2_chroma_w = 1,
-+ .log2_chroma_h = 1,
-+ .comp = {
-+ { 0, 2, 0, 0, 16 }, /* Y */
-+ { 1, 4, 0, 0, 16 }, /* U */
-+ { 1, 4, 2, 0, 16 }, /* V */
-+ },
-+ .flags = 0,
-+ },
-+ [AV_PIX_FMT_RPI4_8] = {
-+ .name = "rpi4_8",
-+ .flags = AV_PIX_FMT_FLAG_HWACCEL,
-+ },
-+ [AV_PIX_FMT_RPI4_10] = {
-+ .name = "rpi4_10",
-+ .flags = AV_PIX_FMT_FLAG_HWACCEL,
-+ },
- };
-
- static const char * const color_range_names[] = {
-diff --git a/libavutil/pixfmt.h b/libavutil/pixfmt.h
-index 37c2c79e01..22f70007c3 100644
---- a/libavutil/pixfmt.h
-+++ b/libavutil/pixfmt.h
-@@ -377,6 +377,12 @@ enum AVPixelFormat {
-
- AV_PIX_FMT_Y210BE, ///< packed YUV 4:2:2 like YUYV422, 20bpp, data in the high bits, big-endian
- AV_PIX_FMT_Y210LE, ///< packed YUV 4:2:2 like YUYV422, 20bpp, data in the high bits, little-endian
-+// RPI - not on ifdef so can be got at by calling progs
-+ AV_PIX_FMT_SAND128, ///< 4:2:0 8-bit 128x*Y stripe, 64x*UV stripe, then next x stripe, mysterious padding
-+ AV_PIX_FMT_SAND64_10, ///< 4:2:0 10-bit 64x*Y stripe, 32x*UV stripe, then next x stripe, mysterious padding
-+ AV_PIX_FMT_SAND64_16, ///< 4:2:0 16-bit 64x*Y stripe, 32x*UV stripe, then next x stripe, mysterious padding
-+ AV_PIX_FMT_RPI4_8,
-+ AV_PIX_FMT_RPI4_10,
-
- AV_PIX_FMT_X2RGB10LE, ///< packed RGB 10:10:10, 30bpp, (msb)2X 10R 10G 10B(lsb), little-endian, X=unused/undefined
- AV_PIX_FMT_X2RGB10BE, ///< packed RGB 10:10:10, 30bpp, (msb)2X 10R 10G 10B(lsb), big-endian, X=unused/undefined
-diff --git a/libavutil/rpi_sand_fn_pw.h b/libavutil/rpi_sand_fn_pw.h
-new file mode 100644
-index 0000000000..0324f6826d
---- /dev/null
-+++ b/libavutil/rpi_sand_fn_pw.h
-@@ -0,0 +1,227 @@
-+/*
-+Copyright (c) 2018 Raspberry Pi (Trading) Ltd.
-+All rights reserved.
-+
-+Redistribution and use in source and binary forms, with or without
-+modification, are permitted provided that the following conditions are met:
-+ * Redistributions of source code must retain the above copyright
-+ notice, this list of conditions and the following disclaimer.
-+ * Redistributions in binary form must reproduce the above copyright
-+ notice, this list of conditions and the following disclaimer in the
-+ documentation and/or other materials provided with the distribution.
-+ * Neither the name of the copyright holder nor the
-+ names of its contributors may be used to endorse or promote products
-+ derived from this software without specific prior written permission.
-+
-+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
-+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+
-+Authors: John Cox
-+*/
-+
-+// * Included twice from rpi_sand_fn with different PW
-+
-+#define STRCAT(x,y) x##y
-+
-+#if PW == 1
-+#define pixel uint8_t
-+#define FUNC(f) STRCAT(f, 8)
-+#elif PW == 2
-+#define pixel uint16_t
-+#define FUNC(f) STRCAT(f, 16)
-+#else
-+#error Unexpected PW
-+#endif
-+
-+// Fetches a single patch - offscreen fixup not done here
-+// w <= stride1
-+// unclipped
-+void FUNC(av_rpi_sand_to_planar_y)(uint8_t * dst, const unsigned int dst_stride,
-+ const uint8_t * src,
-+ unsigned int stride1, unsigned int stride2,
-+ unsigned int _x, unsigned int y,
-+ unsigned int _w, unsigned int h)
-+{
-+ const unsigned int x = _x;
-+ const unsigned int w = _w;
-+ const unsigned int mask = stride1 - 1;
-+
-+#if PW == 1 && (HAVE_SAND_ASM || HAVE_SAND_ASM64)
-+ if (_x == 0) {
-+ ff_rpi_sand8_lines_to_planar_y8(dst, dst_stride,
-+ src, stride1, stride2, _x, y, _w, h);
-+ return;
-+ }
-+#endif
-+
-+ if ((x & ~mask) == ((x + w) & ~mask)) {
-+ // All in one sand stripe
-+ const uint8_t * p = src + (x & mask) + y * stride1 + (x & ~mask) * stride2;
-+ for (unsigned int i = 0; i != h; ++i, dst += dst_stride, p += stride1) {
-+ memcpy(dst, p, w);
-+ }
-+ }
-+ else
-+ {
-+ // Two+ stripe
-+ const unsigned int sstride = stride1 * stride2;
-+ const uint8_t * p1 = src + (x & mask) + y * stride1 + (x & ~mask) * stride2;
-+ const uint8_t * p2 = p1 + sstride - (x & mask);
-+ const unsigned int w1 = stride1 - (x & mask);
-+ const unsigned int w3 = (x + w) & mask;
-+ const unsigned int w2 = w - (w1 + w3);
-+
-+ for (unsigned int i = 0; i != h; ++i, dst += dst_stride, p1 += stride1, p2 += stride1) {
-+ unsigned int j;
-+ const uint8_t * p = p2;
-+ uint8_t * d = dst;
-+ memcpy(d, p1, w1);
-+ d += w1;
-+ for (j = 0; j < w2; j += stride1, d += stride1, p += sstride) {
-+ memcpy(d, p, stride1);
-+ }
-+ memcpy(d, p, w3);
-+ }
-+ }
-+}
-+
-+// x & w in bytes but not of interleave (i.e. offset = x*2 for U&V)
-+
-+void FUNC(av_rpi_sand_to_planar_c)(uint8_t * dst_u, const unsigned int dst_stride_u,
-+ uint8_t * dst_v, const unsigned int dst_stride_v,
-+ const uint8_t * src,
-+ unsigned int stride1, unsigned int stride2,
-+ unsigned int _x, unsigned int y,
-+ unsigned int _w, unsigned int h)
-+{
-+ const unsigned int x = _x * 2;
-+ const unsigned int w = _w * 2;
-+ const unsigned int mask = stride1 - 1;
-+
-+#if PW == 1 && (HAVE_SAND_ASM || HAVE_SAND_ASM64)
-+ if (_x == 0) {
-+ ff_rpi_sand8_lines_to_planar_c8(dst_u, dst_stride_u, dst_v, dst_stride_v,
-+ src, stride1, stride2, _x, y, _w, h);
-+ return;
-+ }
-+#endif
-+
-+ if ((x & ~mask) == ((x + w) & ~mask)) {
-+ // All in one sand stripe
-+ const uint8_t * p1 = src + (x & mask) + y * stride1 + (x & ~mask) * stride2;
-+ for (unsigned int i = 0; i != h; ++i, dst_u += dst_stride_u, dst_v += dst_stride_v, p1 += stride1) {
-+ pixel * du = (pixel *)dst_u;
-+ pixel * dv = (pixel *)dst_v;
-+ const pixel * p = (const pixel *)p1;
-+ for (unsigned int k = 0; k < w; k += 2 * PW) {
-+ *du++ = *p++;
-+ *dv++ = *p++;
-+ }
-+ }
-+ }
-+ else
-+ {
-+ // Two+ stripe
-+ const unsigned int sstride = stride1 * stride2;
-+ const unsigned int sstride_p = (sstride - stride1) / PW;
-+
-+ const uint8_t * p1 = src + (x & mask) + y * stride1 + (x & ~mask) * stride2;
-+ const uint8_t * p2 = p1 + sstride - (x & mask);
-+ const unsigned int w1 = stride1 - (x & mask);
-+ const unsigned int w3 = (x + w) & mask;
-+ const unsigned int w2 = w - (w1 + w3);
-+
-+ for (unsigned int i = 0; i != h; ++i, dst_u += dst_stride_u, dst_v += dst_stride_v, p1 += stride1, p2 += stride1) {
-+ unsigned int j;
-+ const pixel * p = (const pixel *)p1;
-+ pixel * du = (pixel *)dst_u;
-+ pixel * dv = (pixel *)dst_v;
-+ for (unsigned int k = 0; k < w1; k += 2 * PW) {
-+ *du++ = *p++;
-+ *dv++ = *p++;
-+ }
-+ for (j = 0, p = (const pixel *)p2; j < w2; j += stride1, p += sstride_p) {
-+ for (unsigned int k = 0; k < stride1; k += 2 * PW) {
-+ *du++ = *p++;
-+ *dv++ = *p++;
-+ }
-+ }
-+ for (unsigned int k = 0; k < w3; k += 2 * PW) {
-+ *du++ = *p++;
-+ *dv++ = *p++;
-+ }
-+ }
-+ }
-+}
-+
-+void FUNC(av_rpi_planar_to_sand_c)(uint8_t * dst_c,
-+ unsigned int stride1, unsigned int stride2,
-+ const uint8_t * src_u, const unsigned int src_stride_u,
-+ const uint8_t * src_v, const unsigned int src_stride_v,
-+ unsigned int _x, unsigned int y,
-+ unsigned int _w, unsigned int h)
-+{
-+ const unsigned int x = _x * 2;
-+ const unsigned int w = _w * 2;
-+ const unsigned int mask = stride1 - 1;
-+ if ((x & ~mask) == ((x + w) & ~mask)) {
-+ // All in one sand stripe
-+ uint8_t * p1 = dst_c + (x & mask) + y * stride1 + (x & ~mask) * stride2;
-+ for (unsigned int i = 0; i != h; ++i, src_u += src_stride_u, src_v += src_stride_v, p1 += stride1) {
-+ const pixel * su = (const pixel *)src_u;
-+ const pixel * sv = (const pixel *)src_v;
-+ pixel * p = (pixel *)p1;
-+ for (unsigned int k = 0; k < w; k += 2 * PW) {
-+ *p++ = *su++;
-+ *p++ = *sv++;
-+ }
-+ }
-+ }
-+ else
-+ {
-+ // Two+ stripe
-+ const unsigned int sstride = stride1 * stride2;
-+ const unsigned int sstride_p = (sstride - stride1) / PW;
-+
-+ const uint8_t * p1 = dst_c + (x & mask) + y * stride1 + (x & ~mask) * stride2;
-+ const uint8_t * p2 = p1 + sstride - (x & mask);
-+ const unsigned int w1 = stride1 - (x & mask);
-+ const unsigned int w3 = (x + w) & mask;
-+ const unsigned int w2 = w - (w1 + w3);
-+
-+ for (unsigned int i = 0; i != h; ++i, src_u += src_stride_u, src_v += src_stride_v, p1 += stride1, p2 += stride1) {
-+ unsigned int j;
-+ const pixel * su = (const pixel *)src_u;
-+ const pixel * sv = (const pixel *)src_v;
-+ pixel * p = (pixel *)p1;
-+ for (unsigned int k = 0; k < w1; k += 2 * PW) {
-+ *p++ = *su++;
-+ *p++ = *sv++;
-+ }
-+ for (j = 0, p = (pixel *)p2; j < w2; j += stride1, p += sstride_p) {
-+ for (unsigned int k = 0; k < stride1; k += 2 * PW) {
-+ *p++ = *su++;
-+ *p++ = *sv++;
-+ }
-+ }
-+ for (unsigned int k = 0; k < w3; k += 2 * PW) {
-+ *p++ = *su++;
-+ *p++ = *sv++;
-+ }
-+ }
-+ }
-+}
-+
-+
-+#undef pixel
-+#undef STRCAT
-+#undef FUNC
-+
-diff --git a/libavutil/rpi_sand_fns.c b/libavutil/rpi_sand_fns.c
-new file mode 100644
-index 0000000000..ed0261b02f
---- /dev/null
-+++ b/libavutil/rpi_sand_fns.c
-@@ -0,0 +1,353 @@
-+/*
-+Copyright (c) 2018 Raspberry Pi (Trading) Ltd.
-+All rights reserved.
-+
-+Redistribution and use in source and binary forms, with or without
-+modification, are permitted provided that the following conditions are met:
-+ * Redistributions of source code must retain the above copyright
-+ notice, this list of conditions and the following disclaimer.
-+ * Redistributions in binary form must reproduce the above copyright
-+ notice, this list of conditions and the following disclaimer in the
-+ documentation and/or other materials provided with the distribution.
-+ * Neither the name of the copyright holder nor the
-+ names of its contributors may be used to endorse or promote products
-+ derived from this software without specific prior written permission.
-+
-+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
-+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+
-+Authors: John Cox
-+*/
-+
-+#include "config.h"
-+#include
-+#include
-+#include "rpi_sand_fns.h"
-+#include "avassert.h"
-+#include "frame.h"
-+
-+#if ARCH_ARM && HAVE_NEON
-+#include "arm/rpi_sand_neon.h"
-+#define HAVE_SAND_ASM 1
-+#else
-+#define HAVE_SAND_ASM 0
-+#endif
-+
-+#define PW 1
-+#include "rpi_sand_fn_pw.h"
-+#undef PW
-+
-+#define PW 2
-+#include "rpi_sand_fn_pw.h"
-+#undef PW
-+
-+#if 1
-+// Simple round
-+static void cpy16_to_8(uint8_t * dst, const uint8_t * _src, unsigned int n, const unsigned int shr)
-+{
-+ const unsigned int rnd = (1 << shr) >> 1;
-+ const uint16_t * src = (const uint16_t *)_src;
-+
-+ for (; n != 0; --n) {
-+ *dst++ = (*src++ + rnd) >> shr;
-+ }
-+}
-+#else
-+// Dithered variation
-+static void cpy16_to_8(uint8_t * dst, const uint8_t * _src, unsigned int n, const unsigned int shr)
-+{
-+ unsigned int rnd = (1 << shr) >> 1;
-+ const unsigned int mask = ((1 << shr) - 1);
-+ const uint16_t * src = (const uint16_t *)_src;
-+
-+ for (; n != 0; --n) {
-+ rnd = *src++ + (rnd & mask);
-+ *dst++ = rnd >> shr;
-+ }
-+}
-+#endif
-+
-+// Fetches a single patch - offscreen fixup not done here
-+// w <= stride1
-+// unclipped
-+// _x & _w in pixels, strides in bytes
-+void av_rpi_sand30_to_planar_y16(uint8_t * dst, const unsigned int dst_stride,
-+ const uint8_t * src,
-+ unsigned int stride1, unsigned int stride2,
-+ unsigned int _x, unsigned int y,
-+ unsigned int _w, unsigned int h)
-+{
-+ const unsigned int x0 = (_x / 3) * 4; // Byte offset of the word
-+ const unsigned int xskip0 = _x - (x0 >> 2) * 3;
-+ const unsigned int x1 = ((_x + _w) / 3) * 4;
-+ const unsigned int xrem1 = _x + _w - (x1 >> 2) * 3;
-+ const unsigned int mask = stride1 - 1;
-+ const uint8_t * p0 = src + (x0 & mask) + y * stride1 + (x0 & ~mask) * stride2;
-+ const unsigned int slice_inc = ((stride2 - 1) * stride1) >> 2; // RHS of a stripe to LHS of next in words
-+
-+#if HAVE_SAND_ASM
-+ if (_x == 0) {
-+ ff_rpi_sand30_lines_to_planar_y16(dst, dst_stride, src, stride1, stride2, _x, y, _w, h);
-+ return;
-+ }
-+#endif
-+
-+ if (x0 == x1) {
-+ // *******************
-+ // Partial single word xfer
-+ return;
-+ }
-+
-+ for (unsigned int i = 0; i != h; ++i, dst += dst_stride, p0 += stride1)
-+ {
-+ unsigned int x = x0;
-+ const uint32_t * p = (const uint32_t *)p0;
-+ uint16_t * d = (uint16_t *)dst;
-+
-+ if (xskip0 != 0) {
-+ const uint32_t p3 = *p++;
-+
-+ if (xskip0 == 1)
-+ *d++ = (p3 >> 10) & 0x3ff;
-+ *d++ = (p3 >> 20) & 0x3ff;
-+
-+ if (((x += 4) & mask) == 0)
-+ p += slice_inc;
-+ }
-+
-+ while (x != x1) {
-+ const uint32_t p3 = *p++;
-+ *d++ = p3 & 0x3ff;
-+ *d++ = (p3 >> 10) & 0x3ff;
-+ *d++ = (p3 >> 20) & 0x3ff;
-+
-+ if (((x += 4) & mask) == 0)
-+ p += slice_inc;
-+ }
-+
-+ if (xrem1 != 0) {
-+ const uint32_t p3 = *p;
-+
-+ *d++ = p3 & 0x3ff;
-+ if (xrem1 == 2)
-+ *d++ = (p3 >> 10) & 0x3ff;
-+ }
-+ }
-+}
-+
-+
-+void av_rpi_sand30_to_planar_c16(uint8_t * dst_u, const unsigned int dst_stride_u,
-+ uint8_t * dst_v, const unsigned int dst_stride_v,
-+ const uint8_t * src,
-+ unsigned int stride1, unsigned int stride2,
-+ unsigned int _x, unsigned int y,
-+ unsigned int _w, unsigned int h)
-+{
-+ const unsigned int x0 = (_x / 3) * 8; // Byte offset of the word
-+ const unsigned int xskip0 = _x - (x0 >> 3) * 3;
-+ const unsigned int x1 = ((_x + _w) / 3) * 8;
-+ const unsigned int xrem1 = _x + _w - (x1 >> 3) * 3;
-+ const unsigned int mask = stride1 - 1;
-+ const uint8_t * p0 = src + (x0 & mask) + y * stride1 + (x0 & ~mask) * stride2;
-+ const unsigned int slice_inc = ((stride2 - 1) * stride1) >> 2; // RHS of a stripe to LHS of next in words
-+
-+#if HAVE_SAND_ASM
-+ if (_x == 0) {
-+ ff_rpi_sand30_lines_to_planar_c16(dst_u, dst_stride_u, dst_v, dst_stride_v,
-+ src, stride1, stride2, _x, y, _w, h);
-+ return;
-+ }
-+#endif
-+
-+ if (x0 == x1) {
-+ // *******************
-+ // Partial single word xfer
-+ return;
-+ }
-+
-+ for (unsigned int i = 0; i != h; ++i, dst_u += dst_stride_u, dst_v += dst_stride_v, p0 += stride1)
-+ {
-+ unsigned int x = x0;
-+ const uint32_t * p = (const uint32_t *)p0;
-+ uint16_t * du = (uint16_t *)dst_u;
-+ uint16_t * dv = (uint16_t *)dst_v;
-+
-+ if (xskip0 != 0) {
-+ const uint32_t p3a = *p++;
-+ const uint32_t p3b = *p++;
-+
-+ if (xskip0 == 1)
-+ {
-+ *du++ = (p3a >> 20) & 0x3ff;
-+ *dv++ = (p3b >> 0) & 0x3ff;
-+ }
-+ *du++ = (p3b >> 10) & 0x3ff;
-+ *dv++ = (p3b >> 20) & 0x3ff;
-+
-+ if (((x += 8) & mask) == 0)
-+ p += slice_inc;
-+ }
-+
-+ while (x != x1) {
-+ const uint32_t p3a = *p++;
-+ const uint32_t p3b = *p++;
-+
-+ *du++ = p3a & 0x3ff;
-+ *dv++ = (p3a >> 10) & 0x3ff;
-+ *du++ = (p3a >> 20) & 0x3ff;
-+ *dv++ = p3b & 0x3ff;
-+ *du++ = (p3b >> 10) & 0x3ff;
-+ *dv++ = (p3b >> 20) & 0x3ff;
-+
-+ if (((x += 8) & mask) == 0)
-+ p += slice_inc;
-+ }
-+
-+ if (xrem1 != 0) {
-+ const uint32_t p3a = *p++;
-+ const uint32_t p3b = *p++;
-+
-+ *du++ = p3a & 0x3ff;
-+ *dv++ = (p3a >> 10) & 0x3ff;
-+ if (xrem1 == 2)
-+ {
-+ *du++ = (p3a >> 20) & 0x3ff;
-+ *dv++ = p3b & 0x3ff;
-+ }
-+ }
-+ }
-+}
-+
-+
-+// w/h in pixels
-+void av_rpi_sand16_to_sand8(uint8_t * dst, const unsigned int dst_stride1, const unsigned int dst_stride2,
-+ const uint8_t * src, const unsigned int src_stride1, const unsigned int src_stride2,
-+ unsigned int w, unsigned int h, const unsigned int shr)
-+{
-+ const unsigned int n = dst_stride1 / 2;
-+ unsigned int j;
-+
-+ // This is true for our current layouts
-+ av_assert0(dst_stride1 == src_stride1);
-+
-+ // As we have the same stride1 for src & dest and src is wider than dest
-+ // then if we loop on src we can always write contiguously to dest
-+ // We make no effort to copy an exact width - round up to nearest src stripe
-+ // as we will always have storage in dest for that
-+
-+#if ARCH_ARM && HAVE_NEON
-+ if (shr == 3 && src_stride1 == 128) {
-+ for (j = 0; j + n < w; j += dst_stride1) {
-+ uint8_t * d = dst + j * dst_stride2;
-+ const uint8_t * s1 = src + j * 2 * src_stride2;
-+ const uint8_t * s2 = s1 + src_stride1 * src_stride2;
-+
-+ ff_rpi_sand128b_stripe_to_8_10(d, s1, s2, h);
-+ }
-+ }
-+ else
-+#endif
-+ {
-+ for (j = 0; j + n < w; j += dst_stride1) {
-+ uint8_t * d = dst + j * dst_stride2;
-+ const uint8_t * s1 = src + j * 2 * src_stride2;
-+ const uint8_t * s2 = s1 + src_stride1 * src_stride2;
-+
-+ for (unsigned int i = 0; i != h; ++i, s1 += src_stride1, s2 += src_stride1, d += dst_stride1) {
-+ cpy16_to_8(d, s1, n, shr);
-+ cpy16_to_8(d + n, s2, n, shr);
-+ }
-+ }
-+ }
-+
-+ // Fix up a trailing dest half stripe
-+ if (j < w) {
-+ uint8_t * d = dst + j * dst_stride2;
-+ const uint8_t * s1 = src + j * 2 * src_stride2;
-+
-+ for (unsigned int i = 0; i != h; ++i, s1 += src_stride1, d += dst_stride1) {
-+ cpy16_to_8(d, s1, n, shr);
-+ }
-+ }
-+}
-+
-+int av_rpi_sand_to_planar_frame(AVFrame * const dst, const AVFrame * const src)
-+{
-+ const int w = av_frame_cropped_width(src);
-+ const int h = av_frame_cropped_height(src);
-+ const int x = src->crop_left;
-+ const int y = src->crop_top;
-+
-+ // We will crop as part of the conversion
-+ dst->crop_top = 0;
-+ dst->crop_left = 0;
-+ dst->crop_bottom = 0;
-+ dst->crop_right = 0;
-+
-+ switch (src->format){
-+ case AV_PIX_FMT_SAND128:
-+ case AV_PIX_FMT_RPI4_8:
-+ switch (dst->format){
-+ case AV_PIX_FMT_YUV420P:
-+ av_rpi_sand_to_planar_y8(dst->data[0], dst->linesize[0],
-+ src->data[0],
-+ av_rpi_sand_frame_stride1(src), av_rpi_sand_frame_stride2(src),
-+ x, y, w, h);
-+ av_rpi_sand_to_planar_c8(dst->data[1], dst->linesize[1],
-+ dst->data[2], dst->linesize[2],
-+ src->data[1],
-+ av_rpi_sand_frame_stride1(src), av_rpi_sand_frame_stride2(src),
-+ x/2, y/2, w/2, h/2);
-+ break;
-+ default:
-+ return -1;
-+ }
-+ break;
-+ case AV_PIX_FMT_SAND64_10:
-+ switch (dst->format){
-+ case AV_PIX_FMT_YUV420P10:
-+ av_rpi_sand_to_planar_y16(dst->data[0], dst->linesize[0],
-+ src->data[0],
-+ av_rpi_sand_frame_stride1(src), av_rpi_sand_frame_stride2(src),
-+ x*2, y, w*2, h);
-+ av_rpi_sand_to_planar_c16(dst->data[1], dst->linesize[1],
-+ dst->data[2], dst->linesize[2],
-+ src->data[1],
-+ av_rpi_sand_frame_stride1(src), av_rpi_sand_frame_stride2(src),
-+ x, y/2, w, h/2);
-+ break;
-+ default:
-+ return -1;
-+ }
-+ break;
-+ case AV_PIX_FMT_RPI4_10:
-+ switch (dst->format){
-+ case AV_PIX_FMT_YUV420P10:
-+ av_rpi_sand30_to_planar_y16(dst->data[0], dst->linesize[0],
-+ src->data[0],
-+ av_rpi_sand_frame_stride1(src), av_rpi_sand_frame_stride2(src),
-+ x, y, w, h);
-+ av_rpi_sand30_to_planar_c16(dst->data[1], dst->linesize[1],
-+ dst->data[2], dst->linesize[2],
-+ src->data[1],
-+ av_rpi_sand_frame_stride1(src), av_rpi_sand_frame_stride2(src),
-+ x/2, y/2, w/2, h/2);
-+ break;
-+ default:
-+ return -1;
-+ }
-+ break;
-+ default:
-+ return -1;
-+ }
-+
-+ return av_frame_copy_props(dst, src);
-+}
-diff --git a/libavutil/rpi_sand_fns.h b/libavutil/rpi_sand_fns.h
-new file mode 100644
-index 0000000000..634b55e800
---- /dev/null
-+++ b/libavutil/rpi_sand_fns.h
-@@ -0,0 +1,183 @@
-+/*
-+Copyright (c) 2018 Raspberry Pi (Trading) Ltd.
-+All rights reserved.
-+
-+Redistribution and use in source and binary forms, with or without
-+modification, are permitted provided that the following conditions are met:
-+ * Redistributions of source code must retain the above copyright
-+ notice, this list of conditions and the following disclaimer.
-+ * Redistributions in binary form must reproduce the above copyright
-+ notice, this list of conditions and the following disclaimer in the
-+ documentation and/or other materials provided with the distribution.
-+ * Neither the name of the copyright holder nor the
-+ names of its contributors may be used to endorse or promote products
-+ derived from this software without specific prior written permission.
-+
-+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
-+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+
-+Authors: John Cox
-+*/
-+
-+#ifndef AVUTIL_RPI_SAND_FNS
-+#define AVUTIL_RPI_SAND_FNS
-+
-+#include "libavutil/frame.h"
-+
-+// For all these fns _x & _w are measured as coord * PW
-+// For the C fns coords are in chroma pels (so luma / 2)
-+// Strides are in bytes
-+
-+void av_rpi_sand_to_planar_y8(uint8_t * dst, const unsigned int dst_stride,
-+ const uint8_t * src,
-+ unsigned int stride1, unsigned int stride2,
-+ unsigned int _x, unsigned int y,
-+ unsigned int _w, unsigned int h);
-+void av_rpi_sand_to_planar_y16(uint8_t * dst, const unsigned int dst_stride,
-+ const uint8_t * src,
-+ unsigned int stride1, unsigned int stride2,
-+ unsigned int _x, unsigned int y,
-+ unsigned int _w, unsigned int h);
-+
-+void av_rpi_sand_to_planar_c8(uint8_t * dst_u, const unsigned int dst_stride_u,
-+ uint8_t * dst_v, const unsigned int dst_stride_v,
-+ const uint8_t * src,
-+ unsigned int stride1, unsigned int stride2,
-+ unsigned int _x, unsigned int y,
-+ unsigned int _w, unsigned int h);
-+void av_rpi_sand_to_planar_c16(uint8_t * dst_u, const unsigned int dst_stride_u,
-+ uint8_t * dst_v, const unsigned int dst_stride_v,
-+ const uint8_t * src,
-+ unsigned int stride1, unsigned int stride2,
-+ unsigned int _x, unsigned int y,
-+ unsigned int _w, unsigned int h);
-+
-+void av_rpi_planar_to_sand_c8(uint8_t * dst_c,
-+ unsigned int stride1, unsigned int stride2,
-+ const uint8_t * src_u, const unsigned int src_stride_u,
-+ const uint8_t * src_v, const unsigned int src_stride_v,
-+ unsigned int _x, unsigned int y,
-+ unsigned int _w, unsigned int h);
-+void av_rpi_planar_to_sand_c16(uint8_t * dst_c,
-+ unsigned int stride1, unsigned int stride2,
-+ const uint8_t * src_u, const unsigned int src_stride_u,
-+ const uint8_t * src_v, const unsigned int src_stride_v,
-+ unsigned int _x, unsigned int y,
-+ unsigned int _w, unsigned int h);
-+
-+void av_rpi_sand30_to_planar_y16(uint8_t * dst, const unsigned int dst_stride,
-+ const uint8_t * src,
-+ unsigned int stride1, unsigned int stride2,
-+ unsigned int _x, unsigned int y,
-+ unsigned int _w, unsigned int h);
-+void av_rpi_sand30_to_planar_c16(uint8_t * dst_u, const unsigned int dst_stride_u,
-+ uint8_t * dst_v, const unsigned int dst_stride_v,
-+ const uint8_t * src,
-+ unsigned int stride1, unsigned int stride2,
-+ unsigned int _x, unsigned int y,
-+ unsigned int _w, unsigned int h);
-+
-+
-+// w/h in pixels
-+void av_rpi_sand16_to_sand8(uint8_t * dst, const unsigned int dst_stride1, const unsigned int dst_stride2,
-+ const uint8_t * src, const unsigned int src_stride1, const unsigned int src_stride2,
-+ unsigned int w, unsigned int h, const unsigned int shr);
-+
-+
-+// dst must contain required pixel format & allocated data buffers
-+// Cropping on the src buffer will be honoured and dst crop will be set to zero
-+int av_rpi_sand_to_planar_frame(AVFrame * const dst, const AVFrame * const src);
-+
-+
-+static inline unsigned int av_rpi_sand_frame_stride1(const AVFrame * const frame)
-+{
-+#ifdef RPI_ZC_SAND128_ONLY
-+ // If we are sure we only only support 128 byte sand formats replace the
-+ // var with a constant which should allow for better optimisation
-+ return 128;
-+#else
-+ return frame->linesize[0];
-+#endif
-+}
-+
-+static inline unsigned int av_rpi_sand_frame_stride2(const AVFrame * const frame)
-+{
-+ return frame->linesize[3];
-+}
-+
-+
-+static inline int av_rpi_is_sand_format(const int format)
-+{
-+ return (format >= AV_PIX_FMT_SAND128 && format <= AV_PIX_FMT_RPI4_10);
-+}
-+
-+static inline int av_rpi_is_sand_frame(const AVFrame * const frame)
-+{
-+ return av_rpi_is_sand_format(frame->format);
-+}
-+
-+static inline int av_rpi_is_sand8_frame(const AVFrame * const frame)
-+{
-+ return (frame->format == AV_PIX_FMT_SAND128 || frame->format == AV_PIX_FMT_RPI4_8);
-+}
-+
-+static inline int av_rpi_is_sand16_frame(const AVFrame * const frame)
-+{
-+ return (frame->format >= AV_PIX_FMT_SAND64_10 && frame->format <= AV_PIX_FMT_SAND64_16);
-+}
-+
-+static inline int av_rpi_is_sand30_frame(const AVFrame * const frame)
-+{
-+ return (frame->format == AV_PIX_FMT_RPI4_10);
-+}
-+
-+static inline int av_rpi_sand_frame_xshl(const AVFrame * const frame)
-+{
-+ return av_rpi_is_sand8_frame(frame) ? 0 : 1;
-+}
-+
-+// If x is measured in bytes (not pixels) then this works for sand64_16 as
-+// well as sand128 - but in the general case we work that out
-+
-+static inline unsigned int av_rpi_sand_frame_off_y(const AVFrame * const frame, const unsigned int x_y, const unsigned int y)
-+{
-+ const unsigned int stride1 = av_rpi_sand_frame_stride1(frame);
-+ const unsigned int stride2 = av_rpi_sand_frame_stride2(frame);
-+ const unsigned int x = x_y << av_rpi_sand_frame_xshl(frame);
-+ const unsigned int x1 = x & (stride1 - 1);
-+ const unsigned int x2 = x ^ x1;
-+
-+ return x1 + stride1 * y + stride2 * x2;
-+}
-+
-+static inline unsigned int av_rpi_sand_frame_off_c(const AVFrame * const frame, const unsigned int x_c, const unsigned int y_c)
-+{
-+ const unsigned int stride1 = av_rpi_sand_frame_stride1(frame);
-+ const unsigned int stride2 = av_rpi_sand_frame_stride2(frame);
-+ const unsigned int x = x_c << (av_rpi_sand_frame_xshl(frame) + 1);
-+ const unsigned int x1 = x & (stride1 - 1);
-+ const unsigned int x2 = x ^ x1;
-+
-+ return x1 + stride1 * y_c + stride2 * x2;
-+}
-+
-+static inline uint8_t * av_rpi_sand_frame_pos_y(const AVFrame * const frame, const unsigned int x, const unsigned int y)
-+{
-+ return frame->data[0] + av_rpi_sand_frame_off_y(frame, x, y);
-+}
-+
-+static inline uint8_t * av_rpi_sand_frame_pos_c(const AVFrame * const frame, const unsigned int x, const unsigned int y)
-+{
-+ return frame->data[1] + av_rpi_sand_frame_off_c(frame, x, y);
-+}
-+
-+#endif
-+
-
-From 89b8d6ac2a886749d4594656083753e682de05a7 Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Tue, 27 Apr 2021 11:36:47 +0100
-Subject: [PATCH 003/151] Add aarch64 asm sand conv functions
-
-Many thanks to eiler.mike@gmail.com (Michael Eiler) for these
-optimizations
----
- libavutil/aarch64/Makefile | 2 +
- libavutil/aarch64/rpi_sand_neon.S | 676 ++++++++++++++++++++++++++++++
- libavutil/aarch64/rpi_sand_neon.h | 55 +++
- libavutil/rpi_sand_fn_pw.h | 4 +-
- libavutil/rpi_sand_fns.c | 3 +
- 5 files changed, 738 insertions(+), 2 deletions(-)
- create mode 100644 libavutil/aarch64/rpi_sand_neon.S
- create mode 100644 libavutil/aarch64/rpi_sand_neon.h
-
-diff --git a/libavutil/aarch64/Makefile b/libavutil/aarch64/Makefile
-index eba0151337..1b44beab39 100644
---- a/libavutil/aarch64/Makefile
-+++ b/libavutil/aarch64/Makefile
-@@ -4,3 +4,5 @@ OBJS += aarch64/cpu.o \
-
- NEON-OBJS += aarch64/float_dsp_neon.o \
- aarch64/tx_float_neon.o \
-+ aarch64/rpi_sand_neon.o \
-+
-diff --git a/libavutil/aarch64/rpi_sand_neon.S b/libavutil/aarch64/rpi_sand_neon.S
-new file mode 100644
-index 0000000000..cdcf71ee67
---- /dev/null
-+++ b/libavutil/aarch64/rpi_sand_neon.S
-@@ -0,0 +1,676 @@
-+/*
-+Copyright (c) 2021 Michael Eiler
-+
-+Redistribution and use in source and binary forms, with or without
-+modification, are permitted provided that the following conditions are met:
-+ * Redistributions of source code must retain the above copyright
-+ notice, this list of conditions and the following disclaimer.
-+ * Redistributions in binary form must reproduce the above copyright
-+ notice, this list of conditions and the following disclaimer in the
-+ documentation and/or other materials provided with the distribution.
-+ * Neither the name of the copyright holder nor the
-+ names of its contributors may be used to endorse or promote products
-+ derived from this software without specific prior written permission.
-+
-+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
-+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+
-+Authors: Michael Eiler
-+*/
-+
-+#include "asm.S"
-+
-+// void ff_rpi_sand8_lines_to_planar_y8(
-+// uint8_t * dest, : x0
-+// unsigned int dst_stride, : w1
-+// const uint8_t * src, : x2
-+// unsigned int src_stride1, : w3, always 128
-+// unsigned int src_stride2, : w4
-+// unsigned int _x, : w5
-+// unsigned int y, : w6
-+// unsigned int _w, : w7
-+// unsigned int h); : [sp, #0]
-+
-+function ff_rpi_sand8_lines_to_planar_y8, export=1
-+ // w15 contains the number of rows we need to process
-+ ldr w15, [sp, #0]
-+
-+ // w8 will contain the number of blocks per row
-+ // w8 = floor(_w/stride1)
-+ // stride1 is assumed to always be 128
-+ mov w8, w1
-+ lsr w8, w8, #7
-+
-+ // in case the width of the image is not a multiple of 128, there will
-+ // be an incomplete block at the end of every row
-+ // w9 contains the number of pixels stored within this block
-+ // w9 = _w - w8 * 128
-+ lsl w9, w8, #7
-+ sub w9, w7, w9
-+
-+ // this is the value we have to add to the src pointer after reading a complete block
-+ // it will move the address to the start of the next block
-+ // w10 = stride2 * stride1 - stride1
-+ mov w10, w4
-+ lsl w10, w10, #7
-+ sub w10, w10, #128
-+
-+ // w11 is the row offset, meaning the start offset of the first block of every collumn
-+ // this will be increased with stride1 within every iteration of the row_loop
-+ eor w11, w11, w11
-+
-+ // w12 = 0, processed row count
-+ eor w12, w12, w12
-+row_loop:
-+ // start of the first block within the current row
-+ // x13 = row offset + src
-+ mov x13, x2
-+ add x13, x13, x11
-+
-+ // w14 = 0, processed block count
-+ eor w14, w14, w14
-+
-+ cmp w8, #0
-+ beq no_main_y8
-+
-+block_loop:
-+ // copy 128 bytes (a full block) into the vector registers v0-v7 and increase the src address by 128
-+ // fortunately these aren't callee saved ones, meaning we don't need to backup them
-+ ld1 { v0.16b, v1.16b, v2.16b, v3.16b}, [x13], #64
-+ ld1 { v4.16b, v5.16b, v6.16b, v7.16b}, [x13], #64
-+
-+ // write these registers back to the destination vector and increase the dst address by 128
-+ st1 { v0.16b, v1.16b, v2.16b, v3.16b }, [x0], #64
-+ st1 { v4.16b, v5.16b, v6.16b, v7.16b }, [x0], #64
-+
-+ // move the source register to the beginning of the next block (x13 = src + block offset)
-+ add x13, x13, x10
-+ // increase the block counter
-+ add w14, w14, #1
-+
-+ // continue with the block_loop if we haven't copied all full blocks yet
-+ cmp w8, w14
-+ bgt block_loop
-+
-+ // handle the last block at the end of each row
-+ // at most 127 byte values copied from src to dst
-+no_main_y8:
-+ eor w5, w5, w5 // i = 0
-+incomplete_block_loop_y8:
-+ cmp w5, w9
-+ bge incomplete_block_loop_end_y8
-+
-+ ldrb w6, [x13]
-+ strb w6, [x0]
-+ add x13, x13, #1
-+ add x0, x0, #1
-+
-+ add w5, w5, #1
-+ b incomplete_block_loop_y8
-+incomplete_block_loop_end_y8:
-+
-+
-+ // increase the row offset by 128 (stride1)
-+ add w11, w11, #128
-+ // increment the row counter
-+ add w12, w12, #1
-+
-+ // process the next row if we haven't finished yet
-+ cmp w15, w12
-+ bgt row_loop
-+
-+ ret
-+endfunc
-+
-+
-+
-+// void ff_rpi_sand8_lines_to_planar_c8(
-+// uint8_t * dst_u, : x0
-+// unsigned int dst_stride_u, : w1 == width
-+// uint8_t * dst_v, : x2
-+// unsigned int dst_stride_v, : w3 == width
-+// const uint8_t * src, : x4
-+// unsigned int stride1, : w5 == 128
-+// unsigned int stride2, : w6
-+// unsigned int _x, : w7
-+// unsigned int y, : [sp, #0]
-+// unsigned int _w, : [sp, #8]
-+// unsigned int h); : [sp, #16]
-+
-+function ff_rpi_sand8_lines_to_planar_c8, export=1
-+ // w7 = width
-+ ldr w7, [sp, #8]
-+
-+ // w15 contains the number of rows we need to process
-+ // counts down
-+ ldr w15, [sp, #16]
-+
-+ // number of full blocks, w8 = _w / (stride1 >> 1) == _w / 64 == _w >> 6
-+ mov w8, w7
-+ lsr w8, w8, #6
-+
-+ // number of pixels in block at the end of every row
-+ // w9 = _w - (w8 * 64)
-+ lsl w9, w8, #6
-+ sub w9, w7, w9
-+
-+ // Skip at the end of the line to account for stride
-+ sub w12, w1, w7
-+
-+ // address delta to the beginning of the next block
-+ // w10 = (stride2 * stride1 - stride1) = stride2 * 128 - 128
-+ lsl w10, w6, #7
-+ sub w10, w10, #128
-+
-+ // w11 = row address start offset = 0
-+ eor w11, w11, w11
-+
-+row_loop_c8:
-+ // start of the first block within the current row
-+ // x13 = row offset + src
-+ mov x13, x4
-+ add x13, x13, x11
-+
-+ // w14 = 0, processed block count
-+ eor w14, w14, w14
-+
-+ cmp w8, #0
-+ beq no_main_c8
-+
-+block_loop_c8:
-+ // load the full block -> 128 bytes, the block contains 64 interleaved U and V values
-+ ld2 { v0.16b, v1.16b }, [x13], #32
-+ ld2 { v2.16b, v3.16b }, [x13], #32
-+ ld2 { v4.16b, v5.16b }, [x13], #32
-+ ld2 { v6.16b, v7.16b }, [x13], #32
-+
-+ // swap register so that we can write them out with a single instruction
-+ mov v16.16b, v1.16b
-+ mov v17.16b, v3.16b
-+ mov v18.16b, v5.16b
-+ mov v1.16b, v2.16b
-+ mov v2.16b, v4.16b
-+ mov v3.16b, v6.16b
-+ mov v4.16b, v16.16b
-+ mov v5.16b, v17.16b
-+ mov v6.16b, v18.16b
-+
-+ st1 { v0.16b, v1.16b, v2.16b, v3.16b }, [x0], #64
-+ st1 { v4.16b, v5.16b, v6.16b, v7.16b }, [x2], #64
-+
-+ // increment row counter and move src to the beginning of the next block
-+ add w14, w14, #1
-+ add x13, x13, x10
-+
-+ // jump to block_loop_c8 iff the block count is smaller than the number of full blocks
-+ cmp w8, w14
-+ bgt block_loop_c8
-+
-+no_main_c8:
-+ // handle incomplete block at the end of every row
-+ eor w5, w5, w5 // point counter, this might be
-+incomplete_block_loop_c8:
-+ cmp w5, w9
-+ bge incomplete_block_loop_end_c8
-+
-+ ldrb w1, [x13]
-+ strb w1, [x0]
-+ add x13, x13, #1
-+
-+ ldrb w1, [x13]
-+ strb w1, [x2]
-+ add x13, x13, #1
-+
-+ add x0, x0, #1
-+ add x2, x2, #1
-+
-+ add w5, w5, #1
-+ b incomplete_block_loop_c8
-+incomplete_block_loop_end_c8:
-+
-+ // increase row_offset by stride1
-+ add w11, w11, #128
-+ add x0, x0, w12, sxtw
-+ add x2, x2, w12, sxtw
-+
-+ // jump to row_Loop_c8 iff the row count is small than the height
-+ subs w15, w15, #1
-+ bgt row_loop_c8
-+
-+ ret
-+endfunc
-+
-+//void ff_rpi_sand30_lines_to_planar_y16(
-+// uint8_t * dest, // [x0]
-+// unsigned int dst_stride, // [w1] -> assumed to be equal to _w
-+// const uint8_t * src, // [x2]
-+// unsigned int src_stride1, // [w3] -> 128
-+// unsigned int src_stride2, // [w4]
-+// unsigned int _x, // [w5]
-+// unsigned int y, // [w6]
-+// unsigned int _w, // [w7]
-+// unsigned int h); // [sp, #0]
-+
-+function ff_rpi_sand30_lines_to_planar_y16, export=1
-+ stp x19, x20, [sp, #-48]!
-+ stp x21, x22, [sp, #16]
-+ stp x23, x24, [sp, #32]
-+
-+ // w6 = argument h
-+ ldr w6, [sp, #48]
-+
-+ // slice_inc = ((stride2 - 1) * stride1)
-+ mov w5, w4
-+ sub w5, w5, #1
-+ lsl w5, w5, #7
-+
-+ // total number of bytes per row = (width / 3) * 4
-+ mov w8, w7
-+ mov w9, #3
-+ udiv w8, w8, w9
-+ lsl w8, w8, #2
-+
-+ // number of full 128 byte blocks to be processed
-+ mov w9, #96
-+ udiv w9, w7, w9 // = (width * 4) / (3*128) = width/96
-+
-+ // w10 = number of full integers to process (4 bytes)
-+ // w11 = remaning zero to two 10bit values still to copy over
-+ mov w12, #96
-+ mul w12, w9, w12
-+ sub w12, w7, w12 // width - blocks*96 = remaining points per row
-+ mov w11, #3
-+ udiv w10, w12, w11 // full integers to process = w12 / 3
-+ mul w11, w10, w11 // #integers *3
-+ sub w11, w12, w11 // remaining 0-2 points = remaining points - integers*3
-+
-+ // increase w9 by one if w10+w11 is not zero, and decrease the row count by one
-+ // this is to efficiently copy incomplete blocks at the end of the rows
-+ // the last row is handled explicitly to avoid writing out of bounds
-+ add w22, w10, w11
-+ cmp w22, #0
-+ cset w22, ne // 1 iff w10+w11 not zero, 0 otherwise
-+ add w9, w9, w22
-+ sub w6, w6, #1
-+
-+ // store the number of bytes in w20 which we copy too much for every row
-+ // when the width of the frame is not a multiple of 96 (128bytes storing 96 10bit values)
-+ mov w20, #96*2
-+ mul w20, w20, w9
-+ sub w20, w1, w20
-+
-+ mov w23, #0 // flag to check whether the last line had already been processed
-+
-+ // bitmask to clear the uppper 6bits of the result values
-+ mov x19, #0x03ff03ff03ff03ff
-+ dup v22.2d, x19
-+
-+ // row counter = 0
-+ eor w12, w12, w12
-+row_loop_y16:
-+ cmp w12, w6 // jump to row_loop_y16_fin if we processed all rows
-+ bge row_loop_y16_fin
-+
-+ mov x13, x2 // row src
-+ eor w14, w14, w14 // full block counter
-+block_loop_y16:
-+ cmp w14, w9
-+ bge block_loop_y16_fin
-+
-+ // load 64 bytes
-+ ld1 { v0.4s, v1.4s, v2.4s, v3.4s }, [x13], #64
-+
-+ // process v0 and v1
-+ xtn v16.4h, v0.4s
-+ ushr v0.4s, v0.4s, #10
-+ xtn v17.4h, v0.4s
-+ ushr v0.4s, v0.4s, #10
-+ xtn v18.4h, v0.4s
-+
-+ xtn2 v16.8h, v1.4s
-+ and v16.16b, v16.16b, v22.16b
-+ ushr v1.4s, v1.4s, #10
-+ xtn2 v17.8h, v1.4s
-+ and v17.16b, v17.16b, v22.16b
-+ ushr v1.4s, v1.4s, #10
-+ xtn2 v18.8h, v1.4s
-+ and v18.16b, v18.16b, v22.16b
-+
-+ st3 { v16.8h, v17.8h, v18.8h }, [x0], #48
-+
-+ // process v2 and v3
-+ xtn v23.4h, v2.4s
-+ ushr v2.4s, v2.4s, #10
-+ xtn v24.4h, v2.4s
-+ ushr v2.4s, v2.4s, #10
-+ xtn v25.4h, v2.4s
-+
-+ xtn2 v23.8h, v3.4s
-+ and v23.16b, v23.16b, v22.16b
-+ ushr v3.4s, v3.4s, #10
-+ xtn2 v24.8h, v3.4s
-+ and v24.16b, v24.16b, v22.16b
-+ ushr v3.4s, v3.4s, #10
-+ xtn2 v25.8h, v3.4s
-+ and v25.16b, v25.16b, v22.16b
-+
-+ st3 { v23.8h, v24.8h, v25.8h }, [x0], #48
-+
-+ // load the second half of the block -> 64 bytes into registers v4-v7
-+ ld1 { v4.4s, v5.4s, v6.4s, v7.4s }, [x13], #64
-+
-+ // process v4 and v5
-+ xtn v16.4h, v4.4s
-+ ushr v4.4s, v4.4s, #10
-+ xtn v17.4h, v4.4s
-+ ushr v4.4s, v4.4s, #10
-+ xtn v18.4h, v4.4s
-+
-+ xtn2 v16.8h, v5.4s
-+ and v16.16b, v16.16b, v22.16b
-+ ushr v5.4s, v5.4s, #10
-+ xtn2 v17.8h, v5.4s
-+ and v17.16b, v17.16b, v22.16b
-+ ushr v5.4s, v5.4s, #10
-+ xtn2 v18.8h, v5.4s
-+ and v18.16b, v18.16b, v22.16b
-+
-+ st3 { v16.8h, v17.8h, v18.8h }, [x0], #48
-+
-+ // v6 and v7
-+ xtn v23.4h, v6.4s
-+ ushr v6.4s, v6.4s, #10
-+ xtn v24.4h, v6.4s
-+ ushr v6.4s, v6.4s, #10
-+ xtn v25.4h, v6.4s
-+
-+ xtn2 v23.8h, v7.4s
-+ and v23.16b, v23.16b, v22.16b
-+ ushr v7.4s, v7.4s, #10
-+ xtn2 v24.8h, v7.4s
-+ and v24.16b, v24.16b, v22.16b
-+ ushr v7.4s, v7.4s, #10
-+ xtn2 v25.8h, v7.4s
-+ and v25.16b, v25.16b, v22.16b
-+
-+ st3 { v23.8h, v24.8h, v25.8h }, [x0], #48
-+
-+ add x13, x13, x5 // row src += slice_inc
-+ add w14, w14, #1
-+ b block_loop_y16
-+block_loop_y16_fin:
-+
-+
-+
-+
-+ add x2, x2, #128 // src += stride1 (start of the next row)
-+ add x0, x0, w20, sxtw // subtract the bytes we copied too much from dst
-+ add w12, w12, #1
-+ b row_loop_y16
-+row_loop_y16_fin:
-+
-+ // check whether we have incomplete blocks at the end of every row
-+ // in that case decrease row block count by one
-+ // change height back to it's original value (meaning increase it by 1)
-+ // and jump back to another iteration of row_loop_y16
-+
-+ cmp w23, #1
-+ beq row_loop_y16_fin2 // don't continue here if we already processed the last row
-+ add w6, w6, #1 // increase height to the original value
-+ sub w9, w9, w22 // block count - 1 or 0, depending on the remaining bytes count
-+ mov w23, #1
-+ b row_loop_y16
-+row_loop_y16_fin2:
-+
-+ sub x0, x0, w20, sxtw // with the last row we didn't actually move the dst ptr to far ahead, therefore readd the diference
-+
-+ // now we've got to handle the last block in the last row
-+ eor w12, w12, w12 // w12 = 0 = counter
-+integer_loop_y16:
-+ cmp w12, w10
-+ bge integer_loop_y16_fin
-+ ldr w14, [x13], #4
-+ and w15, w14, #0x3ff
-+ strh w15, [x0], #2
-+ lsr w14, w14, #10
-+ and w15, w14, #0x3ff
-+ strh w15, [x0], #2
-+ lsr w14, w14, #10
-+ and w15, w14, #0x3ff
-+ strh w15, [x0], #2
-+ add w12, w12, #1
-+ b integer_loop_y16
-+integer_loop_y16_fin:
-+
-+final_values_y16:
-+ // remaining point count = w11
-+ ldr w14, [x13], #4
-+ cmp w11, #0
-+ beq final_values_y16_fin
-+ and w15, w14, #0x3ff
-+ strh w15, [x0], #2
-+ cmp w11, #1
-+ beq final_values_y16_fin
-+ lsr w14, w14, #10
-+ and w15, w14, #0x3ff
-+ strh w15, [x0], #2
-+final_values_y16_fin:
-+
-+ ldp x23, x24, [sp, #32]
-+ ldp x21, x22, [sp, #16]
-+ ldp x19, x20, [sp], #48
-+ ret
-+endfunc
-+
-+//void ff_rpi_sand30_lines_to_planar_c16(
-+// uint8_t * dst_u, // [x0]
-+// unsigned int dst_stride_u, // [w1] == _w*2
-+// uint8_t * dst_v, // [x2]
-+// unsigned int dst_stride_v, // [w3] == _w*2
-+// const uint8_t * src, // [x4]
-+// unsigned int stride1, // [w5] == 128
-+// unsigned int stride2, // [w6]
-+// unsigned int _x, // [w7] == 0
-+// unsigned int y, // [sp, #0] == 0
-+// unsigned int _w, // [sp, #8] -> w3
-+// unsigned int h); // [sp, #16] -> w7
-+
-+.macro rpi_sand30_lines_to_planar_c16_block_half
-+ ld1 { v0.4s, v1.4s, v2.4s, v3.4s }, [x13], #64
-+
-+ xtn v4.4h, v0.4s
-+ ushr v0.4s, v0.4s, #10
-+ xtn v5.4h, v0.4s
-+ ushr v0.4s, v0.4s, #10
-+ xtn v6.4h, v0.4s
-+ xtn2 v4.8h, v1.4s
-+ ushr v1.4s, v1.4s, #10
-+ xtn2 v5.8h, v1.4s
-+ ushr v1.4s, v1.4s, #10
-+ xtn2 v6.8h, v1.4s
-+ and v4.16b, v4.16b, v16.16b
-+ and v5.16b, v5.16b, v16.16b
-+ and v6.16b, v6.16b, v16.16b
-+ st3 { v4.8h, v5.8h, v6.8h }, [sp], #48
-+
-+ xtn v4.4h, v2.4s
-+ ushr v2.4s, v2.4s, #10
-+ xtn v5.4h, v2.4s
-+ ushr v2.4s, v2.4s, #10
-+ xtn v6.4h, v2.4s
-+ xtn2 v4.8h, v3.4s
-+ ushr v3.4s, v3.4s, #10
-+ xtn2 v5.8h, v3.4s
-+ ushr v3.4s, v3.4s, #10
-+ xtn2 v6.8h, v3.4s
-+ and v4.16b, v4.16b, v16.16b
-+ and v5.16b, v5.16b, v16.16b
-+ and v6.16b, v6.16b, v16.16b
-+ st3 { v4.8h, v5.8h, v6.8h }, [sp]
-+ sub sp, sp, #48
-+.endm
-+
-+function ff_rpi_sand30_lines_to_planar_c16, export=1
-+ stp x19, x20, [sp, #-48]!
-+ stp x21, x22, [sp, #16]
-+ stp x23, x24, [sp, #32]
-+
-+ ldr w3, [sp, #48+8] // w3 = width
-+ ldr w7, [sp, #48+16] // w7 = height
-+
-+ // reserve space on the stack for intermediate results
-+ sub sp, sp, #256
-+
-+ // number of 128byte blocks per row, w8 = width / 48
-+ mov w9, #48
-+ udiv w8, w3, w9
-+
-+ // remaining pixels (rem_pix) per row, w9 = width - w8 * 48
-+ mul w9, w8, w9
-+ sub w9, w3, w9
-+
-+ // row offset, the beginning of the next row to process
-+ eor w10, w10, w10
-+
-+ // offset to the beginning of the next block, w11 = stride2 * 128 - 128
-+ lsl w11, w6, #7
-+ sub w11, w11, #128
-+
-+ // decrease the height by one and in case of remaining pixels increase the block count by one
-+ sub w7, w7, #1
-+ cmp w9, #0
-+ cset w19, ne // w19 == 1 iff reamining pixels != 0
-+ add w8, w8, w19
-+
-+ // bytes we have to move dst back by at the end of every row
-+ mov w21, #48*2
-+ mul w21, w21, w8
-+ sub w21, w1, w21
-+
-+ mov w20, #0 // w20 = flag, last row processed
-+
-+ mov x12, #0x03ff03ff03ff03ff
-+ dup v16.2d, x12
-+
-+ // iterate through rows, row counter = w12 = 0
-+ eor w12, w12, w12
-+row_loop_c16:
-+ cmp w12, w7
-+ bge row_loop_c16_fin
-+
-+ // address of row data = src + row_offset
-+ mov x13, x4
-+ add x13, x13, x10
-+
-+ eor w14, w14, w14
-+block_loop_c16:
-+ cmp w14, w8
-+ bge block_loop_c16_fin
-+
-+ rpi_sand30_lines_to_planar_c16_block_half
-+
-+ ld2 { v0.8h, v1.8h }, [sp], #32
-+ ld2 { v2.8h, v3.8h }, [sp], #32
-+ ld2 { v4.8h, v5.8h }, [sp]
-+ sub sp, sp, #64
-+
-+ st1 { v0.8h }, [x0], #16
-+ st1 { v2.8h }, [x0], #16
-+ st1 { v4.8h }, [x0], #16
-+ st1 { v1.8h }, [x2], #16
-+ st1 { v3.8h }, [x2], #16
-+ st1 { v5.8h }, [x2], #16
-+
-+ rpi_sand30_lines_to_planar_c16_block_half
-+
-+ ld2 { v0.8h, v1.8h }, [sp], #32
-+ ld2 { v2.8h, v3.8h }, [sp], #32
-+ ld2 { v4.8h, v5.8h }, [sp]
-+ sub sp, sp, #64
-+
-+ st1 { v0.8h }, [x0], #16
-+ st1 { v2.8h }, [x0], #16
-+ st1 { v4.8h }, [x0], #16
-+ st1 { v1.8h }, [x2], #16
-+ st1 { v3.8h }, [x2], #16
-+ st1 { v5.8h }, [x2], #16
-+
-+ add x13, x13, x11 // offset to next block
-+ add w14, w14, #1
-+ b block_loop_c16
-+block_loop_c16_fin:
-+
-+ add w10, w10, #128
-+ add w12, w12, #1
-+ add x0, x0, w21, sxtw // move dst pointers back by x21
-+ add x2, x2, w21, sxtw
-+ b row_loop_c16
-+row_loop_c16_fin:
-+
-+ cmp w20, #1
-+ beq row_loop_c16_fin2
-+ mov w20, #1
-+ sub w8, w8, w19 // decrease block count by w19
-+ add w7, w7, #1 // increase height
-+ b row_loop_c16
-+
-+row_loop_c16_fin2:
-+ sub x0, x0, w21, sxtw // readd x21 in case of the last row
-+ sub x2, x2, w21, sxtw // so that we can write out the few remaining pixels
-+
-+ // last incomplete block to be finished
-+ // read operations are fine, stride2 is more than large enough even if rem_pix is 0
-+ rpi_sand30_lines_to_planar_c16_block_half
-+ ld2 { v0.8h, v1.8h }, [sp], #32
-+ ld2 { v2.8h, v3.8h }, [sp], #32
-+ ld2 { v4.8h, v5.8h }, [sp], #32
-+ rpi_sand30_lines_to_planar_c16_block_half
-+ ld2 { v0.8h, v1.8h }, [sp], #32
-+ ld2 { v2.8h, v3.8h }, [sp], #32
-+ ld2 { v4.8h, v5.8h }, [sp]
-+ sub sp, sp, #160
-+
-+ mov x4, sp
-+ eor w20, w20, w20
-+rem_pix_c16_loop:
-+ cmp w20, w9
-+ bge rem_pix_c16_fin
-+
-+ ldr w22, [x4], #4
-+ str w22, [x0], #2
-+ lsr w22, w22, #16
-+ str w22, [x2], #2
-+
-+ add w20, w20, #1
-+ b rem_pix_c16_loop
-+rem_pix_c16_fin:
-+
-+ add sp, sp, #256
-+
-+ ldp x23, x24, [sp, #32]
-+ ldp x21, x22, [sp, #16]
-+ ldp x19, x20, [sp], #48
-+ ret
-+endfunc
-+
-+
-+
-+//void ff_rpi_sand30_lines_to_planar_p010(
-+// uint8_t * dest,
-+// unsigned int dst_stride,
-+// const uint8_t * src,
-+// unsigned int src_stride1,
-+// unsigned int src_stride2,
-+// unsigned int _x,
-+// unsigned int y,
-+// unsigned int _w,
-+// unsigned int h);
-+
-diff --git a/libavutil/aarch64/rpi_sand_neon.h b/libavutil/aarch64/rpi_sand_neon.h
-new file mode 100644
-index 0000000000..b3aa481ea4
---- /dev/null
-+++ b/libavutil/aarch64/rpi_sand_neon.h
-@@ -0,0 +1,55 @@
-+/*
-+Copyright (c) 2021 Michael Eiler
-+
-+Redistribution and use in source and binary forms, with or without
-+modification, are permitted provided that the following conditions are met:
-+ * Redistributions of source code must retain the above copyright
-+ notice, this list of conditions and the following disclaimer.
-+ * Redistributions in binary form must reproduce the above copyright
-+ notice, this list of conditions and the following disclaimer in the
-+ documentation and/or other materials provided with the distribution.
-+ * Neither the name of the copyright holder nor the
-+ names of its contributors may be used to endorse or promote products
-+ derived from this software without specific prior written permission.
-+
-+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
-+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+
-+Authors: Michael Eiler
-+*/
-+
-+#pragma once
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+void ff_rpi_sand8_lines_to_planar_y8(uint8_t * dest, unsigned int dst_stride,
-+ const uint8_t * src, unsigned int src_stride1, unsigned int src_stride2,
-+ unsigned int _x, unsigned int y, unsigned int _w, unsigned int h);
-+
-+void ff_rpi_sand8_lines_to_planar_c8(uint8_t * dst_u, unsigned int dst_stride_u,
-+ uint8_t * dst_v, unsigned int dst_stride_v, const uint8_t * src,
-+ unsigned int stride1, unsigned int stride2, unsigned int _x, unsigned int y,
-+ unsigned int _w, unsigned int h);
-+
-+void ff_rpi_sand30_lines_to_planar_y16(uint8_t * dest, unsigned int dst_stride,
-+ const uint8_t * src, unsigned int src_stride1, unsigned int src_stride2,
-+ unsigned int _x, unsigned int y, unsigned int _w, unsigned int h);
-+
-+void ff_rpi_sand30_lines_to_planar_c16(uint8_t * dst_u, unsigned int dst_stride_u,
-+ uint8_t * dst_v, unsigned int dst_stride_v, const uint8_t * src, unsigned int stride1,
-+ unsigned int stride2, unsigned int _x, unsigned int y, unsigned int _w, unsigned int h);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-diff --git a/libavutil/rpi_sand_fn_pw.h b/libavutil/rpi_sand_fn_pw.h
-index 0324f6826d..0d5d203dc3 100644
---- a/libavutil/rpi_sand_fn_pw.h
-+++ b/libavutil/rpi_sand_fn_pw.h
-@@ -54,7 +54,7 @@ void FUNC(av_rpi_sand_to_planar_y)(uint8_t * dst, const unsigned int dst_stride,
- const unsigned int w = _w;
- const unsigned int mask = stride1 - 1;
-
--#if PW == 1 && (HAVE_SAND_ASM || HAVE_SAND_ASM64)
-+#if PW == 1 && HAVE_SAND_ASM
- if (_x == 0) {
- ff_rpi_sand8_lines_to_planar_y8(dst, dst_stride,
- src, stride1, stride2, _x, y, _w, h);
-@@ -106,7 +106,7 @@ void FUNC(av_rpi_sand_to_planar_c)(uint8_t * dst_u, const unsigned int dst_strid
- const unsigned int w = _w * 2;
- const unsigned int mask = stride1 - 1;
-
--#if PW == 1 && (HAVE_SAND_ASM || HAVE_SAND_ASM64)
-+#if PW == 1 && HAVE_SAND_ASM
- if (_x == 0) {
- ff_rpi_sand8_lines_to_planar_c8(dst_u, dst_stride_u, dst_v, dst_stride_v,
- src, stride1, stride2, _x, y, _w, h);
-diff --git a/libavutil/rpi_sand_fns.c b/libavutil/rpi_sand_fns.c
-index ed0261b02f..1f543e9357 100644
---- a/libavutil/rpi_sand_fns.c
-+++ b/libavutil/rpi_sand_fns.c
-@@ -37,6 +37,9 @@ Authors: John Cox
- #if ARCH_ARM && HAVE_NEON
- #include "arm/rpi_sand_neon.h"
- #define HAVE_SAND_ASM 1
-+#elif ARCH_AARCH64 && HAVE_NEON
-+#include "aarch64/rpi_sand_neon.h"
-+#define HAVE_SAND_ASM 1
- #else
- #define HAVE_SAND_ASM 0
- #endif
-
-From 247025a42ae09d6c9c5d4128a5e4b288b7b3047c Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Tue, 27 Apr 2021 11:56:02 +0100
-Subject: [PATCH 004/151] Add raw encoding for sand
-
----
- libavcodec/raw.c | 6 +++
- libavcodec/rawenc.c | 92 ++++++++++++++++++++++++++++++++++++++++++++-
- 2 files changed, 96 insertions(+), 2 deletions(-)
-
-diff --git a/libavcodec/raw.c b/libavcodec/raw.c
-index 1e5b48d1e0..1e689f9ee0 100644
---- a/libavcodec/raw.c
-+++ b/libavcodec/raw.c
-@@ -295,6 +295,12 @@ static const PixelFormatTag raw_pix_fmt_tags[] = {
- { AV_PIX_FMT_RGB565LE,MKTAG( 3 , 0 , 0 , 0 ) }, /* flipped RGB565LE */
- { AV_PIX_FMT_YUV444P, MKTAG('Y', 'V', '2', '4') }, /* YUV444P, swapped UV */
-
-+ /* RPI (Might as well define for everything) */
-+ { AV_PIX_FMT_SAND128, MKTAG('S', 'A', 'N', 'D') },
-+ { AV_PIX_FMT_RPI4_8, MKTAG('S', 'A', 'N', 'D') },
-+ { AV_PIX_FMT_SAND64_10, MKTAG('S', 'N', 'D', 'A') },
-+ { AV_PIX_FMT_RPI4_10, MKTAG('S', 'N', 'D', 'B') },
-+
- { AV_PIX_FMT_NONE, 0 },
- };
-
-diff --git a/libavcodec/rawenc.c b/libavcodec/rawenc.c
-index 8c577006d9..594a77c42a 100644
---- a/libavcodec/rawenc.c
-+++ b/libavcodec/rawenc.c
-@@ -24,6 +24,7 @@
- * Raw Video Encoder
- */
-
-+#include "config.h"
- #include "avcodec.h"
- #include "codec_internal.h"
- #include "encode.h"
-@@ -33,6 +34,10 @@
- #include "libavutil/intreadwrite.h"
- #include "libavutil/imgutils.h"
- #include "libavutil/internal.h"
-+#include "libavutil/avassert.h"
-+#if CONFIG_SAND
-+#include "libavutil/rpi_sand_fns.h"
-+#endif
-
- static av_cold int raw_encode_init(AVCodecContext *avctx)
- {
-@@ -46,12 +51,95 @@ static av_cold int raw_encode_init(AVCodecContext *avctx)
- return 0;
- }
-
-+#if CONFIG_SAND
-+static int raw_sand8_as_yuv420(AVCodecContext *avctx, AVPacket *pkt,
-+ const AVFrame *frame)
-+{
-+ const int width = av_frame_cropped_width(frame);
-+ const int height = av_frame_cropped_height(frame);
-+ const int x0 = frame->crop_left;
-+ const int y0 = frame->crop_top;
-+ const int size = width * height * 3 / 2;
-+ uint8_t * dst;
-+ int ret;
-+
-+ if ((ret = ff_get_encode_buffer(avctx, pkt, size, 0)) < 0)
-+ return ret;
-+
-+ dst = pkt->data;
-+
-+ av_rpi_sand_to_planar_y8(dst, width, frame->data[0], frame->linesize[0], frame->linesize[3], x0, y0, width, height);
-+ dst += width * height;
-+ av_rpi_sand_to_planar_c8(dst, width / 2, dst + width * height / 4, width / 2,
-+ frame->data[1], frame->linesize[1], av_rpi_sand_frame_stride2(frame), x0 / 2, y0 / 2, width / 2, height / 2);
-+ return 0;
-+}
-+
-+static int raw_sand16_as_yuv420(AVCodecContext *avctx, AVPacket *pkt,
-+ const AVFrame *frame)
-+{
-+ const int width = av_frame_cropped_width(frame);
-+ const int height = av_frame_cropped_height(frame);
-+ const int x0 = frame->crop_left;
-+ const int y0 = frame->crop_top;
-+ const int size = width * height * 3;
-+ uint8_t * dst;
-+ int ret;
-+
-+ if ((ret = ff_get_encode_buffer(avctx, pkt, size, 0)) < 0)
-+ return ret;
-+
-+ dst = pkt->data;
-+
-+ av_rpi_sand_to_planar_y16(dst, width * 2, frame->data[0], frame->linesize[0], frame->linesize[3], x0 * 2, y0, width * 2, height);
-+ dst += width * height * 2;
-+ av_rpi_sand_to_planar_c16(dst, width, dst + width * height / 2, width,
-+ frame->data[1], frame->linesize[1], av_rpi_sand_frame_stride2(frame), x0, y0 / 2, width, height / 2);
-+ return 0;
-+}
-+
-+static int raw_sand30_as_yuv420(AVCodecContext *avctx, AVPacket *pkt,
-+ const AVFrame *frame)
-+{
-+ const int width = av_frame_cropped_width(frame);
-+ const int height = av_frame_cropped_height(frame);
-+ const int x0 = frame->crop_left;
-+ const int y0 = frame->crop_top;
-+ const int size = width * height * 3;
-+ uint8_t * dst;
-+ int ret;
-+
-+ if ((ret = ff_get_encode_buffer(avctx, pkt, size, 0)) < 0)
-+ return ret;
-+
-+ dst = pkt->data;
-+
-+ av_rpi_sand30_to_planar_y16(dst, width * 2, frame->data[0], frame->linesize[0], frame->linesize[3], x0, y0, width, height);
-+ dst += width * height * 2;
-+ av_rpi_sand30_to_planar_c16(dst, width, dst + width * height / 2, width,
-+ frame->data[1], frame->linesize[1], av_rpi_sand_frame_stride2(frame), x0/2, y0 / 2, width/2, height / 2);
-+ return 0;
-+}
-+#endif
-+
-+
- static int raw_encode(AVCodecContext *avctx, AVPacket *pkt,
- const AVFrame *frame, int *got_packet)
- {
-- int ret = av_image_get_buffer_size(frame->format,
-- frame->width, frame->height, 1);
-+ int ret;
-
-+#if CONFIG_SAND
-+ if (av_rpi_is_sand_frame(frame)) {
-+ ret = av_rpi_is_sand8_frame(frame) ? raw_sand8_as_yuv420(avctx, pkt, frame) :
-+ av_rpi_is_sand16_frame(frame) ? raw_sand16_as_yuv420(avctx, pkt, frame) :
-+ av_rpi_is_sand30_frame(frame) ? raw_sand30_as_yuv420(avctx, pkt, frame) : -1;
-+ *got_packet = (ret == 0);
-+ return ret;
-+ }
-+#endif
-+
-+ ret = av_image_get_buffer_size(frame->format,
-+ frame->width, frame->height, 1);
- if (ret < 0)
- return ret;
-
-
-From ac6961f424b56563dc793b6bc002a8c04cb1bc36 Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Tue, 27 Apr 2021 12:02:09 +0100
-Subject: [PATCH 005/151] Deal with the lack of trivial sand cropping
-
----
- fftools/ffmpeg.c | 4 ++--
- fftools/ffmpeg_filter.c | 4 ++--
- libavutil/frame.c | 11 +++++++++++
- libavutil/frame.h | 10 ++++++++++
- 4 files changed, 25 insertions(+), 4 deletions(-)
-
-diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
-index d721a5e721..15e084f0b2 100644
---- a/fftools/ffmpeg.c
-+++ b/fftools/ffmpeg.c
-@@ -1993,8 +1993,8 @@ static int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame, int keep_ref
- av_channel_layout_compare(&ifilter->ch_layout, &frame->ch_layout);
- break;
- case AVMEDIA_TYPE_VIDEO:
-- need_reinit |= ifilter->width != frame->width ||
-- ifilter->height != frame->height;
-+ need_reinit |= ifilter->width != av_frame_cropped_width(frame) ||
-+ ifilter->height != av_frame_cropped_height(frame);
- break;
- }
-
-diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
-index 1f5bbf6c4d..f888307762 100644
---- a/fftools/ffmpeg_filter.c
-+++ b/fftools/ffmpeg_filter.c
-@@ -1281,8 +1281,8 @@ int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame)
-
- ifilter->format = frame->format;
-
-- ifilter->width = frame->width;
-- ifilter->height = frame->height;
-+ ifilter->width = av_frame_cropped_width(frame);
-+ ifilter->height = av_frame_cropped_height(frame);
- ifilter->sample_aspect_ratio = frame->sample_aspect_ratio;
-
- ifilter->sample_rate = frame->sample_rate;
-diff --git a/libavutil/frame.c b/libavutil/frame.c
-index 9545477acc..48621e4098 100644
---- a/libavutil/frame.c
-+++ b/libavutil/frame.c
-@@ -16,6 +16,8 @@
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-+#include "config.h"
-+
- #include "channel_layout.h"
- #include "avassert.h"
- #include "buffer.h"
-@@ -27,6 +29,9 @@
- #include "mem.h"
- #include "samplefmt.h"
- #include "hwcontext.h"
-+#if CONFIG_SAND
-+#include "rpi_sand_fns.h"
-+#endif
-
- #if FF_API_OLD_CHANNEL_LAYOUT
- #define CHECK_CHANNELS_CONSISTENCY(frame) \
-@@ -874,6 +879,12 @@ int av_frame_apply_cropping(AVFrame *frame, int flags)
- (frame->crop_top + frame->crop_bottom) >= frame->height)
- return AVERROR(ERANGE);
-
-+#if CONFIG_SAND
-+ // Sand cannot be cropped - do not try
-+ if (av_rpi_is_sand_format(frame->format))
-+ return 0;
-+#endif
-+
- desc = av_pix_fmt_desc_get(frame->format);
- if (!desc)
- return AVERROR_BUG;
-diff --git a/libavutil/frame.h b/libavutil/frame.h
-index 2580269549..3a9d323325 100644
---- a/libavutil/frame.h
-+++ b/libavutil/frame.h
-@@ -957,6 +957,16 @@ int av_frame_apply_cropping(AVFrame *frame, int flags);
- */
- const char *av_frame_side_data_name(enum AVFrameSideDataType type);
-
-+
-+static inline int av_frame_cropped_width(const AVFrame * const frame)
-+{
-+ return frame->width - (frame->crop_left + frame->crop_right);
-+}
-+static inline int av_frame_cropped_height(const AVFrame * const frame)
-+{
-+ return frame->height - (frame->crop_top + frame->crop_bottom);
-+}
-+
- /**
- * @}
- */
-
-From 9a08431f7790507b0374d9585dfc736000c1bd42 Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Tue, 27 Apr 2021 12:31:16 +0100
-Subject: [PATCH 006/151] Add an unsand filter
-
----
- configure | 1 +
- libavfilter/Makefile | 1 +
- libavfilter/allfilters.c | 1 +
- libavfilter/buffersrc.c | 2 +-
- libavfilter/vf_unsand.c | 228 +++++++++++++++++++++++++++++++++++++++
- 5 files changed, 232 insertions(+), 1 deletion(-)
- create mode 100644 libavfilter/vf_unsand.c
-
-diff --git a/configure b/configure
-index 27112ced58..7712482bd5 100755
---- a/configure
-+++ b/configure
-@@ -3754,6 +3754,7 @@ tonemap_opencl_filter_deps="opencl const_nan"
- transpose_opencl_filter_deps="opencl"
- transpose_vaapi_filter_deps="vaapi VAProcPipelineCaps_rotation_flags"
- transpose_vulkan_filter_deps="vulkan spirv_compiler"
-+unsand_filter_select="sand"
- unsharp_opencl_filter_deps="opencl"
- uspp_filter_deps="gpl avcodec"
- vaguedenoiser_filter_deps="gpl"
-diff --git a/libavfilter/Makefile b/libavfilter/Makefile
-index b3d3d981dd..c14fc995a0 100644
---- a/libavfilter/Makefile
-+++ b/libavfilter/Makefile
-@@ -518,6 +518,7 @@ OBJS-$(CONFIG_TRANSPOSE_VAAPI_FILTER) += vf_transpose_vaapi.o vaapi_vpp.o
- OBJS-$(CONFIG_TRANSPOSE_VULKAN_FILTER) += vf_transpose_vulkan.o vulkan.o vulkan_filter.o
- OBJS-$(CONFIG_TRIM_FILTER) += trim.o
- OBJS-$(CONFIG_UNPREMULTIPLY_FILTER) += vf_premultiply.o framesync.o
-+OBJS-$(CONFIG_UNSAND_FILTER) += vf_unsand.o
- OBJS-$(CONFIG_UNSHARP_FILTER) += vf_unsharp.o
- OBJS-$(CONFIG_UNSHARP_OPENCL_FILTER) += vf_unsharp_opencl.o opencl.o \
- opencl/unsharp.o
-diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
-index d7db46c2af..b990a00152 100644
---- a/libavfilter/allfilters.c
-+++ b/libavfilter/allfilters.c
-@@ -490,6 +490,7 @@ extern const AVFilter ff_vf_trim;
- extern const AVFilter ff_vf_unpremultiply;
- extern const AVFilter ff_vf_unsharp;
- extern const AVFilter ff_vf_unsharp_opencl;
-+extern const AVFilter ff_vf_unsand;
- extern const AVFilter ff_vf_untile;
- extern const AVFilter ff_vf_uspp;
- extern const AVFilter ff_vf_v360;
-diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c
-index ba17450b93..0dbe5d2335 100644
---- a/libavfilter/buffersrc.c
-+++ b/libavfilter/buffersrc.c
-@@ -201,7 +201,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
-
- switch (ctx->outputs[0]->type) {
- case AVMEDIA_TYPE_VIDEO:
-- CHECK_VIDEO_PARAM_CHANGE(ctx, s, frame->width, frame->height,
-+ CHECK_VIDEO_PARAM_CHANGE(ctx, s, av_frame_cropped_width(frame), av_frame_cropped_height(frame),
- frame->format, frame->pts);
- break;
- case AVMEDIA_TYPE_AUDIO:
-diff --git a/libavfilter/vf_unsand.c b/libavfilter/vf_unsand.c
-new file mode 100644
-index 0000000000..7100f2fc9b
---- /dev/null
-+++ b/libavfilter/vf_unsand.c
-@@ -0,0 +1,228 @@
-+/*
-+ * Copyright (c) 2007 Bobby Bingham
-+ *
-+ * This file is part of FFmpeg.
-+ *
-+ * FFmpeg is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * FFmpeg is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with FFmpeg; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+/**
-+ * @file
-+ * format and noformat video filters
-+ */
-+
-+#include
-+
-+#include "libavutil/internal.h"
-+#include "libavutil/mem.h"
-+#include "libavutil/pixdesc.h"
-+#include "libavutil/opt.h"
-+#include "libavutil/rpi_sand_fns.h"
-+
-+#include "avfilter.h"
-+#include "formats.h"
-+#include "internal.h"
-+#include "video.h"
-+
-+typedef struct UnsandContext {
-+ const AVClass *class;
-+} UnsandContext;
-+
-+static av_cold void uninit(AVFilterContext *ctx)
-+{
-+// UnsandContext *s = ctx->priv;
-+}
-+
-+static av_cold int init(AVFilterContext *ctx)
-+{
-+// UnsandContext *s = ctx->priv;
-+
-+ return 0;
-+}
-+
-+
-+static int filter_frame(AVFilterLink *link, AVFrame *in)
-+{
-+ AVFilterLink * const outlink = link->dst->outputs[0];
-+ AVFrame *out = NULL;
-+ int rv = 0;
-+
-+ if (outlink->format == in->format) {
-+ // If nothing to do then do nothing
-+ out = in;
-+ }
-+ else
-+ {
-+ if ((out = ff_get_video_buffer(outlink, av_frame_cropped_width(in), av_frame_cropped_height(in))) == NULL)
-+ {
-+ rv = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+ if (av_rpi_sand_to_planar_frame(out, in) != 0)
-+ {
-+ rv = -1;
-+ goto fail;
-+ }
-+
-+ av_frame_free(&in);
-+ }
-+
-+ return ff_filter_frame(outlink, out);
-+
-+fail:
-+ av_frame_free(&out);
-+ av_frame_free(&in);
-+ return rv;
-+}
-+
-+#if 0
-+static void dump_fmts(const AVFilterFormats * fmts)
-+{
-+ int i;
-+ if (fmts== NULL) {
-+ printf("NULL\n");
-+ return;
-+ }
-+ for (i = 0; i < fmts->nb_formats; ++i) {
-+ printf(" %d", fmts->formats[i]);
-+ }
-+ printf("\n");
-+}
-+#endif
-+
-+static int query_formats(AVFilterContext *ctx)
-+{
-+// UnsandContext *s = ctx->priv;
-+ int ret;
-+
-+ // If we aren't connected at both ends then just do nothing
-+ if (ctx->inputs[0] == NULL || ctx->outputs[0] == NULL)
-+ return 0;
-+
-+ // Our output formats depend on our input formats and we can't/don't
-+ // want to convert between bit depths so we need to wait for the source
-+ // to have an opinion before we do
-+ if (ctx->inputs[0]->incfg.formats == NULL)
-+ return AVERROR(EAGAIN);
-+
-+ // Accept anything
-+ if (ctx->inputs[0]->outcfg.formats == NULL &&
-+ (ret = ff_formats_ref(ctx->inputs[0]->incfg.formats, &ctx->inputs[0]->outcfg.formats)) < 0)
-+ return ret;
-+
-+ // Filter out sand formats
-+
-+ // Generate a container if we don't already have one
-+ if (ctx->outputs[0]->incfg.formats == NULL)
-+ {
-+ // Somewhat rubbish way of ensuring we have a good structure
-+ const static enum AVPixelFormat out_fmts[] = {AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE};
-+ AVFilterFormats *formats = ff_make_format_list(out_fmts);
-+
-+ if (formats == NULL)
-+ return AVERROR(ENOMEM);
-+ if ((ret = ff_formats_ref(formats, &ctx->outputs[0]->incfg.formats)) < 0)
-+ return ret;
-+ }
-+
-+ // Replace old format list with new filtered list derived from what our
-+ // input says it can do
-+ {
-+ const AVFilterFormats * const src_ff = ctx->inputs[0]->outcfg.formats;
-+ AVFilterFormats * const dst_ff = ctx->outputs[0]->incfg.formats;
-+ enum AVPixelFormat *dst_fmts = av_malloc(sizeof(enum AVPixelFormat) * src_ff->nb_formats);
-+ int i;
-+ int n = 0;
-+ int seen_420p = 0;
-+ int seen_420p10 = 0;
-+
-+ for (i = 0; i < src_ff->nb_formats; ++i) {
-+ const enum AVPixelFormat f = src_ff->formats[i];
-+
-+ switch (f){
-+ case AV_PIX_FMT_YUV420P:
-+ case AV_PIX_FMT_SAND128:
-+ case AV_PIX_FMT_RPI4_8:
-+ if (!seen_420p) {
-+ seen_420p = 1;
-+ dst_fmts[n++] = AV_PIX_FMT_YUV420P;
-+ }
-+ break;
-+ case AV_PIX_FMT_SAND64_10:
-+ case AV_PIX_FMT_YUV420P10:
-+ case AV_PIX_FMT_RPI4_10:
-+ if (!seen_420p10) {
-+ seen_420p10 = 1;
-+ dst_fmts[n++] = AV_PIX_FMT_YUV420P10;
-+ }
-+ break;
-+ default:
-+ dst_fmts[n++] = f;
-+ break;
-+ }
-+ }
-+
-+ av_freep(&dst_ff->formats);
-+ dst_ff->formats = dst_fmts;
-+ dst_ff->nb_formats = n;
-+ }
-+
-+// printf("Unsand: %s calc: ", __func__);
-+// dump_fmts(ctx->outputs[0]->incfg.formats);
-+
-+ return 0;
-+}
-+
-+
-+#define OFFSET(x) offsetof(UnsandContext, x)
-+static const AVOption unsand_options[] = {
-+ { NULL }
-+};
-+
-+
-+AVFILTER_DEFINE_CLASS(unsand);
-+
-+static const AVFilterPad avfilter_vf_unsand_inputs[] = {
-+ {
-+ .name = "default",
-+ .type = AVMEDIA_TYPE_VIDEO,
-+ .filter_frame = filter_frame,
-+ },
-+ { NULL }
-+};
-+
-+static const AVFilterPad avfilter_vf_unsand_outputs[] = {
-+ {
-+ .name = "default",
-+ .type = AVMEDIA_TYPE_VIDEO
-+ },
-+};
-+
-+AVFilter ff_vf_unsand = {
-+ .name = "unsand",
-+ .description = NULL_IF_CONFIG_SMALL("Convert sand pix fmt to yuv"),
-+
-+ .init = init,
-+ .uninit = uninit,
-+
-+ FILTER_QUERY_FUNC(query_formats),
-+
-+ .priv_size = sizeof(UnsandContext),
-+ .priv_class = &unsand_class,
-+
-+ FILTER_INPUTS(avfilter_vf_unsand_inputs),
-+ FILTER_OUTPUTS(avfilter_vf_unsand_outputs),
-+};
-+
-
-From 6e61007b19544c573f1c2a4c6060d3d24b8d500e Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Tue, 27 Apr 2021 12:37:07 +0100
-Subject: [PATCH 007/151] Reduce mmal compile warnings
-
----
- libavcodec/mmaldec.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/libavcodec/mmaldec.c b/libavcodec/mmaldec.c
-index 3092f58510..6f41b41ac4 100644
---- a/libavcodec/mmaldec.c
-+++ b/libavcodec/mmaldec.c
-@@ -24,6 +24,9 @@
- * MMAL Video Decoder
- */
-
-+#pragma GCC diagnostic push
-+// Many many redundant decls in the header files
-+#pragma GCC diagnostic ignored "-Wredundant-decls"
- #include
- #include
- #include
-@@ -31,6 +34,7 @@
- #include
- #include
- #include
-+#pragma GCC diagnostic pop
- #include
-
- #include "avcodec.h"
-
-From 01aff455665e8f889330519096912ad0005add3c Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Tue, 27 Apr 2021 17:56:16 +0100
-Subject: [PATCH 008/151] Add chroma location to hevc parse
-
----
- libavcodec/hevc_parser.c | 13 +++++++++++++
- libavcodec/hevcdec.c | 13 +++++++++++++
- 2 files changed, 26 insertions(+)
-
-diff --git a/libavcodec/hevc_parser.c b/libavcodec/hevc_parser.c
-index 59f9a0ff3e..4ae7222e8b 100644
---- a/libavcodec/hevc_parser.c
-+++ b/libavcodec/hevc_parser.c
-@@ -97,6 +97,19 @@ static int hevc_parse_slice_header(AVCodecParserContext *s, H2645NAL *nal,
- avctx->profile = ps->sps->ptl.general_ptl.profile_idc;
- avctx->level = ps->sps->ptl.general_ptl.level_idc;
-
-+ if (ps->sps->chroma_format_idc == 1) {
-+ avctx->chroma_sample_location = ps->sps->vui.common.chroma_loc_info_present_flag ?
-+ ps->sps->vui.common.chroma_sample_loc_type_top_field + 1 :
-+ AVCHROMA_LOC_LEFT;
-+ }
-+ else if (ps->sps->chroma_format_idc == 2 ||
-+ ps->sps->chroma_format_idc == 3) {
-+ avctx->chroma_sample_location = AVCHROMA_LOC_TOPLEFT;;
-+ }
-+ else {
-+ avctx->chroma_sample_location = AVCHROMA_LOC_UNSPECIFIED;
-+ }
-+
- if (ps->vps->vps_timing_info_present_flag) {
- num = ps->vps->vps_num_units_in_tick;
- den = ps->vps->vps_time_scale;
-diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
-index 567e8d81d4..b6cfea64d3 100644
---- a/libavcodec/hevcdec.c
-+++ b/libavcodec/hevcdec.c
-@@ -347,6 +347,19 @@ static void export_stream_params(HEVCContext *s, const HEVCSPS *sps)
- else
- avctx->color_range = AVCOL_RANGE_MPEG;
-
-+ if (sps->chroma_format_idc == 1) {
-+ avctx->chroma_sample_location = sps->vui.common.chroma_loc_info_present_flag ?
-+ sps->vui.common.chroma_sample_loc_type_top_field + 1 :
-+ AVCHROMA_LOC_LEFT;
-+ }
-+ else if (sps->chroma_format_idc == 2 ||
-+ sps->chroma_format_idc == 3) {
-+ avctx->chroma_sample_location = AVCHROMA_LOC_TOPLEFT;;
-+ }
-+ else {
-+ avctx->chroma_sample_location = AVCHROMA_LOC_UNSPECIFIED;
-+ }
-+
- if (sps->vui.common.colour_description_present_flag) {
- avctx->color_primaries = sps->vui.common.colour_primaries;
- avctx->color_trc = sps->vui.common.transfer_characteristics;
-
-From c80aad5d2fb373f7564e4257b1272f2decb06dd0 Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Mon, 26 Sep 2022 18:20:50 +0100
-Subject: [PATCH 009/151] hwaccel: Add .abort_frame & use in hevcdec
-
----
- libavcodec/avcodec.h | 11 +++++++++++
- libavcodec/hevcdec.c | 7 ++++++-
- 2 files changed, 17 insertions(+), 1 deletion(-)
-
-diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
-index 39881a1d2b..32bc78e2be 100644
---- a/libavcodec/avcodec.h
-+++ b/libavcodec/avcodec.h
-@@ -2221,6 +2221,17 @@ typedef struct AVHWAccel {
- * that avctx->hwaccel_priv_data is invalid.
- */
- int (*frame_params)(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx);
-+
-+ /**
-+ * Called if parsing fails
-+ *
-+ * An error has occured, end_frame will not be called
-+ * start_frame & decode_slice may or may not have been called
-+ * Optional
-+ *
-+ * @param avctx the codec context
-+ */
-+ void (*abort_frame)(AVCodecContext *avctx);
- } AVHWAccel;
-
- /**
-diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
-index b6cfea64d3..8a0246fa21 100644
---- a/libavcodec/hevcdec.c
-+++ b/libavcodec/hevcdec.c
-@@ -3375,8 +3375,13 @@ static int hevc_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
-
- s->ref = NULL;
- ret = decode_nal_units(s, avpkt->data, avpkt->size);
-- if (ret < 0)
-+ if (ret < 0) {
-+ // Ensure that hwaccel knows this frame is over
-+ if (s->avctx->hwaccel && s->avctx->hwaccel->abort_frame)
-+ s->avctx->hwaccel->abort_frame(s->avctx);
-+
- return ret;
-+ }
-
- if (avctx->hwaccel) {
- if (s->ref && (ret = avctx->hwaccel->end_frame(avctx)) < 0) {
-
-From 317722fd652d9a1c1700319c80fc71acf68ddde6 Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Mon, 26 Sep 2022 18:26:17 +0100
-Subject: [PATCH 010/151] hwaccel: Add CAP_MT_SAFE for accels that can use
- multi-thread
-
----
- libavcodec/hwconfig.h | 1 +
- libavcodec/pthread_frame.c | 7 +++++--
- 2 files changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/libavcodec/hwconfig.h b/libavcodec/hwconfig.h
-index 721424912c..c43ad55245 100644
---- a/libavcodec/hwconfig.h
-+++ b/libavcodec/hwconfig.h
-@@ -24,6 +24,7 @@
-
-
- #define HWACCEL_CAP_ASYNC_SAFE (1 << 0)
-+#define HWACCEL_CAP_MT_SAFE (1 << 1)
-
-
- typedef struct AVCodecHWConfigInternal {
-diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
-index d9d5afaa82..2cc89a41f5 100644
---- a/libavcodec/pthread_frame.c
-+++ b/libavcodec/pthread_frame.c
-@@ -204,7 +204,8 @@ static attribute_align_arg void *frame_worker_thread(void *arg)
-
- /* if the previous thread uses hwaccel then we take the lock to ensure
- * the threads don't run concurrently */
-- if (avctx->hwaccel) {
-+ if (avctx->hwaccel &&
-+ !(avctx->hwaccel->caps_internal & HWACCEL_CAP_MT_SAFE)) {
- pthread_mutex_lock(&p->parent->hwaccel_mutex);
- p->hwaccel_serializing = 1;
- }
-@@ -590,7 +591,9 @@ void ff_thread_finish_setup(AVCodecContext *avctx) {
-
- if (!(avctx->active_thread_type&FF_THREAD_FRAME)) return;
-
-- if (avctx->hwaccel && !p->hwaccel_serializing) {
-+ if (avctx->hwaccel &&
-+ !(avctx->hwaccel->caps_internal & HWACCEL_CAP_MT_SAFE) &&
-+ !p->hwaccel_serializing) {
- pthread_mutex_lock(&p->parent->hwaccel_mutex);
- p->hwaccel_serializing = 1;
- }
-
-From 9005b263450e154a5ec5258fda17d5998fe7896b Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Tue, 27 Apr 2021 17:59:08 +0100
-Subject: [PATCH 011/151] Weak link utils
-
----
- libavcodec/weak_link.c | 102 +++++++++++++++++++++++++++++++++++++++++
- libavcodec/weak_link.h | 23 ++++++++++
- 2 files changed, 125 insertions(+)
- create mode 100644 libavcodec/weak_link.c
- create mode 100644 libavcodec/weak_link.h
-
-diff --git a/libavcodec/weak_link.c b/libavcodec/weak_link.c
-new file mode 100644
-index 0000000000..f234a985b9
---- /dev/null
-+++ b/libavcodec/weak_link.c
-@@ -0,0 +1,102 @@
-+#include
-+#include
-+#include
-+#include "weak_link.h"
-+
-+struct ff_weak_link_master {
-+ atomic_int ref_count; /* 0 is single ref for easier atomics */
-+ pthread_rwlock_t lock;
-+ void * ptr;
-+};
-+
-+static inline struct ff_weak_link_master * weak_link_x(struct ff_weak_link_client * c)
-+{
-+ return (struct ff_weak_link_master *)c;
-+}
-+
-+struct ff_weak_link_master * ff_weak_link_new(void * p)
-+{
-+ struct ff_weak_link_master * w = malloc(sizeof(*w));
-+ if (!w)
-+ return NULL;
-+ w->ptr = p;
-+ if (pthread_rwlock_init(&w->lock, NULL)) {
-+ free(w);
-+ return NULL;
-+ }
-+ return w;
-+}
-+
-+static void weak_link_do_unref(struct ff_weak_link_master * const w)
-+{
-+ int n = atomic_fetch_sub(&w->ref_count, 1);
-+ if (n)
-+ return;
-+
-+ pthread_rwlock_destroy(&w->lock);
-+ free(w);
-+}
-+
-+// Unref & break link
-+void ff_weak_link_break(struct ff_weak_link_master ** ppLink)
-+{
-+ struct ff_weak_link_master * const w = *ppLink;
-+ if (!w)
-+ return;
-+
-+ *ppLink = NULL;
-+ pthread_rwlock_wrlock(&w->lock);
-+ w->ptr = NULL;
-+ pthread_rwlock_unlock(&w->lock);
-+
-+ weak_link_do_unref(w);
-+}
-+
-+struct ff_weak_link_client* ff_weak_link_ref(struct ff_weak_link_master * w)
-+{
-+ if (!w)
-+ return NULL;
-+ atomic_fetch_add(&w->ref_count, 1);
-+ return (struct ff_weak_link_client*)w;
-+}
-+
-+void ff_weak_link_unref(struct ff_weak_link_client ** ppLink)
-+{
-+ struct ff_weak_link_master * const w = weak_link_x(*ppLink);
-+ if (!w)
-+ return;
-+
-+ *ppLink = NULL;
-+ weak_link_do_unref(w);
-+}
-+
-+void * ff_weak_link_lock(struct ff_weak_link_client ** ppLink)
-+{
-+ struct ff_weak_link_master * const w = weak_link_x(*ppLink);
-+
-+ if (!w)
-+ return NULL;
-+
-+ if (pthread_rwlock_rdlock(&w->lock))
-+ goto broken;
-+
-+ if (w->ptr)
-+ return w->ptr;
-+
-+ pthread_rwlock_unlock(&w->lock);
-+
-+broken:
-+ *ppLink = NULL;
-+ weak_link_do_unref(w);
-+ return NULL;
-+}
-+
-+// Ignores a NULL c (so can be on the return path of both broken & live links)
-+void ff_weak_link_unlock(struct ff_weak_link_client * c)
-+{
-+ struct ff_weak_link_master * const w = weak_link_x(c);
-+ if (w)
-+ pthread_rwlock_unlock(&w->lock);
-+}
-+
-+
-diff --git a/libavcodec/weak_link.h b/libavcodec/weak_link.h
-new file mode 100644
-index 0000000000..415b6a27a0
---- /dev/null
-+++ b/libavcodec/weak_link.h
-@@ -0,0 +1,23 @@
-+struct ff_weak_link_master;
-+struct ff_weak_link_client;
-+
-+struct ff_weak_link_master * ff_weak_link_new(void * p);
-+void ff_weak_link_break(struct ff_weak_link_master ** ppLink);
-+
-+struct ff_weak_link_client* ff_weak_link_ref(struct ff_weak_link_master * w);
-+void ff_weak_link_unref(struct ff_weak_link_client ** ppLink);
-+
-+// Returns NULL if link broken - in this case it will also zap
-+// *ppLink and unref the weak_link.
-+// Returns NULL if *ppLink is NULL (so a link once broken stays broken)
-+//
-+// The above does mean that there is a race if this is called simultainiously
-+// by two threads using the same weak_link_client (so don't do that)
-+void * ff_weak_link_lock(struct ff_weak_link_client ** ppLink);
-+void ff_weak_link_unlock(struct ff_weak_link_client * c);
-+
-+
-+
-+
-+
-+
-
-From 824be1710ca96d97c86836fdac0e7dcd28a4b92e Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Tue, 27 Apr 2021 19:23:26 +0100
-Subject: [PATCH 012/151] Add v4l2_req V4L2 request H265 drm_prime decode
-
-Has the abiliy to switch between kernel API versions at runtime. This
-could be removed later once teher is no chance of usage on an old
-kernel.
----
- configure | 14 +
- libavcodec/Makefile | 4 +
- libavcodec/hevc-ctrls-v1.h | 229 +++++
- libavcodec/hevc-ctrls-v2.h | 257 +++++
- libavcodec/hevcdec.c | 10 +
- libavcodec/hwaccels.h | 1 +
- libavcodec/hwconfig.h | 2 +
- libavcodec/v4l2_req_decode_q.c | 84 ++
- libavcodec/v4l2_req_decode_q.h | 25 +
- libavcodec/v4l2_req_devscan.c | 449 +++++++++
- libavcodec/v4l2_req_devscan.h | 23 +
- libavcodec/v4l2_req_dmabufs.c | 266 ++++++
- libavcodec/v4l2_req_dmabufs.h | 40 +
- libavcodec/v4l2_req_hevc_v1.c | 3 +
- libavcodec/v4l2_req_hevc_v2.c | 3 +
- libavcodec/v4l2_req_hevc_vx.c | 1213 +++++++++++++++++++++++
- libavcodec/v4l2_req_media.c | 1596 +++++++++++++++++++++++++++++++
- libavcodec/v4l2_req_media.h | 151 +++
- libavcodec/v4l2_req_pollqueue.c | 361 +++++++
- libavcodec/v4l2_req_pollqueue.h | 18 +
- libavcodec/v4l2_req_utils.h | 27 +
- libavcodec/v4l2_request_hevc.c | 297 ++++++
- libavcodec/v4l2_request_hevc.h | 102 ++
- 23 files changed, 5175 insertions(+)
- create mode 100644 libavcodec/hevc-ctrls-v1.h
- create mode 100644 libavcodec/hevc-ctrls-v2.h
- create mode 100644 libavcodec/v4l2_req_decode_q.c
- create mode 100644 libavcodec/v4l2_req_decode_q.h
- create mode 100644 libavcodec/v4l2_req_devscan.c
- create mode 100644 libavcodec/v4l2_req_devscan.h
- create mode 100644 libavcodec/v4l2_req_dmabufs.c
- create mode 100644 libavcodec/v4l2_req_dmabufs.h
- create mode 100644 libavcodec/v4l2_req_hevc_v1.c
- create mode 100644 libavcodec/v4l2_req_hevc_v2.c
- create mode 100644 libavcodec/v4l2_req_hevc_vx.c
- create mode 100644 libavcodec/v4l2_req_media.c
- create mode 100644 libavcodec/v4l2_req_media.h
- create mode 100644 libavcodec/v4l2_req_pollqueue.c
- create mode 100644 libavcodec/v4l2_req_pollqueue.h
- create mode 100644 libavcodec/v4l2_req_utils.h
- create mode 100644 libavcodec/v4l2_request_hevc.c
- create mode 100644 libavcodec/v4l2_request_hevc.h
-
-diff --git a/configure b/configure
-index 7712482bd5..199aa2b3d5 100755
---- a/configure
-+++ b/configure
-@@ -281,6 +281,7 @@ External library support:
- if openssl, gnutls or mbedtls is not used [no]
- --enable-libtwolame enable MP2 encoding via libtwolame [no]
- --enable-libuavs3d enable AVS3 decoding via libuavs3d [no]
-+ --enable-libudev enable libudev [no]
- --enable-libv4l2 enable libv4l2/v4l-utils [no]
- --enable-libvidstab enable video stabilization using vid.stab [no]
- --enable-libvmaf enable vmaf filter via libvmaf [no]
-@@ -351,6 +352,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-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]
-@@ -1858,6 +1860,7 @@ EXTERNAL_LIBRARY_LIST="
- libtheora
- libtwolame
- libuavs3d
-+ libudev
- libv4l2
- libvmaf
- libvorbis
-@@ -1914,6 +1917,7 @@ HWACCEL_LIBRARY_LIST="
- mmal
- omx
- opencl
-+ v4l2_request
- "
-
- DOCUMENT_LIST="
-@@ -3002,6 +3006,7 @@ d3d11va_deps="dxva_h ID3D11VideoDecoder ID3D11VideoContext"
- dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode ole32 user32"
- ffnvcodec_deps_any="libdl LoadLibrary"
- nvdec_deps="ffnvcodec"
-+v4l2_request_deps="linux_videodev2_h linux_media_h v4l2_timeval_to_ns libdrm libudev"
- vaapi_x11_deps="xlib_x11"
- videotoolbox_hwaccel_deps="videotoolbox pthreads"
- videotoolbox_hwaccel_extralibs="-framework QuartzCore"
-@@ -3045,6 +3050,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"
-+hevc_v4l2request_hwaccel_deps="v4l2_request"
-+hevc_v4l2request_hwaccel_select="hevc_decoder"
- hevc_vaapi_hwaccel_deps="vaapi VAPictureParameterBufferHEVC"
- hevc_vaapi_hwaccel_select="hevc_decoder"
- hevc_vdpau_hwaccel_deps="vdpau VdpPictureInfoHEVC"
-@@ -6696,6 +6703,7 @@ enabled libtwolame && require libtwolame twolame.h twolame_init -ltwolame
- { check_lib libtwolame twolame.h twolame_encode_buffer_float32_interleaved -ltwolame ||
- die "ERROR: libtwolame must be installed and version must be >= 0.3.10"; }
- enabled libuavs3d && require_pkg_config libuavs3d "uavs3d >= 1.1.41" uavs3d.h uavs3d_decode
-+enabled libudev && require_pkg_config libudev libudev libudev.h udev_new
- enabled libv4l2 && require_pkg_config libv4l2 libv4l2 libv4l2.h v4l2_ioctl
- enabled libvidstab && require_pkg_config libvidstab "vidstab >= 0.98" vid.stab/libvidstab.h vsMotionDetectInit
- enabled libvmaf && require_pkg_config libvmaf "libvmaf >= 2.0.0" libvmaf.h vmaf_init
-@@ -6798,6 +6806,10 @@ enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/r
- { enabled libdrm ||
- die "ERROR: rkmpp requires --enable-libdrm"; }
- }
-+enabled v4l2_request && { enabled libdrm ||
-+ die "ERROR: v4l2-request requires --enable-libdrm"; } &&
-+ { enabled libudev ||
-+ die "ERROR: v4l2-request requires --enable-libudev"; }
- enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 42" VSScript.h vsscript_init
-
-
-@@ -6880,6 +6892,8 @@ if enabled v4l2_m2m; then
- check_cc vp9_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_VP9;"
- fi
-
-+check_func_headers "linux/media.h linux/videodev2.h" v4l2_timeval_to_ns
-+check_cc hevc_v4l2_request linux/videodev2.h "int i = V4L2_PIX_FMT_HEVC_SLICE;"
- check_headers sys/videoio.h
- test_code cc sys/videoio.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_sanitized struct_v4l2_frmivalenum_discrete
-
-diff --git a/libavcodec/Makefile b/libavcodec/Makefile
-index 389253f5d0..2d440b5648 100644
---- a/libavcodec/Makefile
-+++ b/libavcodec/Makefile
-@@ -170,6 +170,8 @@ 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_req_media.o v4l2_req_pollqueue.o v4l2_req_dmabufs.o\
-+ v4l2_req_devscan.o weak_link.o
- OBJS-$(CONFIG_WMA_FREQS) += wma_freqs.o
- OBJS-$(CONFIG_WMV2DSP) += wmv2dsp.o
-
-@@ -996,6 +998,8 @@ OBJS-$(CONFIG_HEVC_D3D11VA_HWACCEL) += dxva2_hevc.o
- OBJS-$(CONFIG_HEVC_DXVA2_HWACCEL) += dxva2_hevc.o
- OBJS-$(CONFIG_HEVC_NVDEC_HWACCEL) += nvdec_hevc.o
- OBJS-$(CONFIG_HEVC_QSV_HWACCEL) += qsvdec.o
-+OBJS-$(CONFIG_HEVC_V4L2REQUEST_HWACCEL) += v4l2_request_hevc.o v4l2_req_decode_q.o\
-+ v4l2_req_hevc_v1.o v4l2_req_hevc_v2.o
- OBJS-$(CONFIG_HEVC_VAAPI_HWACCEL) += vaapi_hevc.o h265_profile_level.o
- OBJS-$(CONFIG_HEVC_VDPAU_HWACCEL) += vdpau_hevc.o h265_profile_level.o
- OBJS-$(CONFIG_MJPEG_NVDEC_HWACCEL) += nvdec_mjpeg.o
-diff --git a/libavcodec/hevc-ctrls-v1.h b/libavcodec/hevc-ctrls-v1.h
-new file mode 100644
-index 0000000000..72cbba0953
---- /dev/null
-+++ b/libavcodec/hevc-ctrls-v1.h
-@@ -0,0 +1,229 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * These are the HEVC state controls for use with stateless HEVC
-+ * codec drivers.
-+ *
-+ * It turns out that these structs are not stable yet and will undergo
-+ * more changes. So keep them private until they are stable and ready to
-+ * become part of the official public API.
-+ */
-+
-+#ifndef _HEVC_CTRLS_H_
-+#define _HEVC_CTRLS_H_
-+
-+#include
-+
-+/* The pixel format isn't stable at the moment and will likely be renamed. */
-+#define V4L2_PIX_FMT_HEVC_SLICE v4l2_fourcc('S', '2', '6', '5') /* HEVC parsed slices */
-+
-+#define V4L2_CID_MPEG_VIDEO_HEVC_SPS (V4L2_CID_MPEG_BASE + 1008)
-+#define V4L2_CID_MPEG_VIDEO_HEVC_PPS (V4L2_CID_MPEG_BASE + 1009)
-+#define V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS (V4L2_CID_MPEG_BASE + 1010)
-+#define V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX (V4L2_CID_MPEG_BASE + 1011)
-+#define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE (V4L2_CID_MPEG_BASE + 1015)
-+#define V4L2_CID_MPEG_VIDEO_HEVC_START_CODE (V4L2_CID_MPEG_BASE + 1016)
-+
-+/* enum v4l2_ctrl_type type values */
-+#define V4L2_CTRL_TYPE_HEVC_SPS 0x0120
-+#define V4L2_CTRL_TYPE_HEVC_PPS 0x0121
-+#define V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS 0x0122
-+#define V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX 0x0123
-+
-+enum v4l2_mpeg_video_hevc_decode_mode {
-+ V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED,
-+ V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED,
-+};
-+
-+enum v4l2_mpeg_video_hevc_start_code {
-+ V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE,
-+ V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B,
-+};
-+
-+#define V4L2_HEVC_SLICE_TYPE_B 0
-+#define V4L2_HEVC_SLICE_TYPE_P 1
-+#define V4L2_HEVC_SLICE_TYPE_I 2
-+
-+#define V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE (1ULL << 0)
-+#define V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED (1ULL << 1)
-+#define V4L2_HEVC_SPS_FLAG_AMP_ENABLED (1ULL << 2)
-+#define V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET (1ULL << 3)
-+#define V4L2_HEVC_SPS_FLAG_PCM_ENABLED (1ULL << 4)
-+#define V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED (1ULL << 5)
-+#define V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT (1ULL << 6)
-+#define V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED (1ULL << 7)
-+#define V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED (1ULL << 8)
-+
-+/* The controls are not stable at the moment and will likely be reworked. */
-+struct v4l2_ctrl_hevc_sps {
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: Sequence parameter set */
-+ __u16 pic_width_in_luma_samples;
-+ __u16 pic_height_in_luma_samples;
-+ __u8 bit_depth_luma_minus8;
-+ __u8 bit_depth_chroma_minus8;
-+ __u8 log2_max_pic_order_cnt_lsb_minus4;
-+ __u8 sps_max_dec_pic_buffering_minus1;
-+ __u8 sps_max_num_reorder_pics;
-+ __u8 sps_max_latency_increase_plus1;
-+ __u8 log2_min_luma_coding_block_size_minus3;
-+ __u8 log2_diff_max_min_luma_coding_block_size;
-+ __u8 log2_min_luma_transform_block_size_minus2;
-+ __u8 log2_diff_max_min_luma_transform_block_size;
-+ __u8 max_transform_hierarchy_depth_inter;
-+ __u8 max_transform_hierarchy_depth_intra;
-+ __u8 pcm_sample_bit_depth_luma_minus1;
-+ __u8 pcm_sample_bit_depth_chroma_minus1;
-+ __u8 log2_min_pcm_luma_coding_block_size_minus3;
-+ __u8 log2_diff_max_min_pcm_luma_coding_block_size;
-+ __u8 num_short_term_ref_pic_sets;
-+ __u8 num_long_term_ref_pics_sps;
-+ __u8 chroma_format_idc;
-+ __u8 sps_max_sub_layers_minus1;
-+
-+ __u64 flags;
-+};
-+
-+#define V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT (1ULL << 0)
-+#define V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT (1ULL << 1)
-+#define V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED (1ULL << 2)
-+#define V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT (1ULL << 3)
-+#define V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED (1ULL << 4)
-+#define V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED (1ULL << 5)
-+#define V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED (1ULL << 6)
-+#define V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT (1ULL << 7)
-+#define V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED (1ULL << 8)
-+#define V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED (1ULL << 9)
-+#define V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED (1ULL << 10)
-+#define V4L2_HEVC_PPS_FLAG_TILES_ENABLED (1ULL << 11)
-+#define V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED (1ULL << 12)
-+#define V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED (1ULL << 13)
-+#define V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED (1ULL << 14)
-+#define V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED (1ULL << 15)
-+#define V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER (1ULL << 16)
-+#define V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT (1ULL << 17)
-+#define V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT (1ULL << 18)
-+
-+struct v4l2_ctrl_hevc_pps {
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture parameter set */
-+ __u8 num_extra_slice_header_bits;
-+ __s8 init_qp_minus26;
-+ __u8 diff_cu_qp_delta_depth;
-+ __s8 pps_cb_qp_offset;
-+ __s8 pps_cr_qp_offset;
-+ __u8 num_tile_columns_minus1;
-+ __u8 num_tile_rows_minus1;
-+ __u8 column_width_minus1[20];
-+ __u8 row_height_minus1[22];
-+ __s8 pps_beta_offset_div2;
-+ __s8 pps_tc_offset_div2;
-+ __u8 log2_parallel_merge_level_minus2;
-+
-+ __u8 padding[4];
-+ __u64 flags;
-+};
-+
-+#define V4L2_HEVC_DPB_ENTRY_RPS_ST_CURR_BEFORE 0x01
-+#define V4L2_HEVC_DPB_ENTRY_RPS_ST_CURR_AFTER 0x02
-+#define V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR 0x03
-+
-+#define V4L2_HEVC_DPB_ENTRIES_NUM_MAX 16
-+
-+struct v4l2_hevc_dpb_entry {
-+ __u64 timestamp;
-+ __u8 rps;
-+ __u8 field_pic;
-+ __u16 pic_order_cnt[2];
-+ __u8 padding[2];
-+};
-+
-+struct v4l2_hevc_pred_weight_table {
-+ __s8 delta_luma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-+ __s8 luma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-+ __s8 delta_chroma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2];
-+ __s8 chroma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2];
-+
-+ __s8 delta_luma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-+ __s8 luma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-+ __s8 delta_chroma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2];
-+ __s8 chroma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2];
-+
-+ __u8 padding[6];
-+
-+ __u8 luma_log2_weight_denom;
-+ __s8 delta_chroma_log2_weight_denom;
-+};
-+
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA (1ULL << 0)
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA (1ULL << 1)
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED (1ULL << 2)
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO (1ULL << 3)
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT (1ULL << 4)
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0 (1ULL << 5)
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_USE_INTEGER_MV (1ULL << 6)
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED (1ULL << 7)
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED (1ULL << 8)
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT (1ULL << 9)
-+
-+struct v4l2_ctrl_hevc_slice_params {
-+ __u32 bit_size;
-+ __u32 data_bit_offset;
-+
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
-+ __u32 slice_segment_addr;
-+ __u32 num_entry_point_offsets;
-+
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: NAL unit header */
-+ __u8 nal_unit_type;
-+ __u8 nuh_temporal_id_plus1;
-+
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
-+ __u8 slice_type;
-+ __u8 colour_plane_id;
-+ __u16 slice_pic_order_cnt;
-+ __u8 num_ref_idx_l0_active_minus1;
-+ __u8 num_ref_idx_l1_active_minus1;
-+ __u8 collocated_ref_idx;
-+ __u8 five_minus_max_num_merge_cand;
-+ __s8 slice_qp_delta;
-+ __s8 slice_cb_qp_offset;
-+ __s8 slice_cr_qp_offset;
-+ __s8 slice_act_y_qp_offset;
-+ __s8 slice_act_cb_qp_offset;
-+ __s8 slice_act_cr_qp_offset;
-+ __s8 slice_beta_offset_div2;
-+ __s8 slice_tc_offset_div2;
-+
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture timing SEI message */
-+ __u8 pic_struct;
-+
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
-+ __u8 num_active_dpb_entries;
-+ __u8 ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-+ __u8 ref_idx_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-+
-+ __u8 num_rps_poc_st_curr_before;
-+ __u8 num_rps_poc_st_curr_after;
-+ __u8 num_rps_poc_lt_curr;
-+
-+ __u8 padding;
-+
-+ __u32 entry_point_offset_minus1[256];
-+
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
-+ struct v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-+
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: Weighted prediction parameter */
-+ struct v4l2_hevc_pred_weight_table pred_weight_table;
-+
-+ __u64 flags;
-+};
-+
-+struct v4l2_ctrl_hevc_scaling_matrix {
-+ __u8 scaling_list_4x4[6][16];
-+ __u8 scaling_list_8x8[6][64];
-+ __u8 scaling_list_16x16[6][64];
-+ __u8 scaling_list_32x32[2][64];
-+ __u8 scaling_list_dc_coef_16x16[6];
-+ __u8 scaling_list_dc_coef_32x32[2];
-+};
-+
-+#endif
-diff --git a/libavcodec/hevc-ctrls-v2.h b/libavcodec/hevc-ctrls-v2.h
-new file mode 100644
-index 0000000000..7cbbbf055f
---- /dev/null
-+++ b/libavcodec/hevc-ctrls-v2.h
-@@ -0,0 +1,257 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * These are the HEVC state controls for use with stateless HEVC
-+ * codec drivers.
-+ *
-+ * It turns out that these structs are not stable yet and will undergo
-+ * more changes. So keep them private until they are stable and ready to
-+ * become part of the official public API.
-+ */
-+
-+#ifndef _HEVC_CTRLS_H_
-+#define _HEVC_CTRLS_H_
-+
-+#include
-+
-+/* The pixel format isn't stable at the moment and will likely be renamed. */
-+#define V4L2_PIX_FMT_HEVC_SLICE v4l2_fourcc('S', '2', '6', '5') /* HEVC parsed slices */
-+
-+#define V4L2_CID_MPEG_VIDEO_HEVC_SPS (V4L2_CID_CODEC_BASE + 1008)
-+#define V4L2_CID_MPEG_VIDEO_HEVC_PPS (V4L2_CID_CODEC_BASE + 1009)
-+#define V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS (V4L2_CID_CODEC_BASE + 1010)
-+#define V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX (V4L2_CID_CODEC_BASE + 1011)
-+#define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS (V4L2_CID_CODEC_BASE + 1012)
-+#define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE (V4L2_CID_CODEC_BASE + 1015)
-+#define V4L2_CID_MPEG_VIDEO_HEVC_START_CODE (V4L2_CID_CODEC_BASE + 1016)
-+
-+/* enum v4l2_ctrl_type type values */
-+#define V4L2_CTRL_TYPE_HEVC_SPS 0x0120
-+#define V4L2_CTRL_TYPE_HEVC_PPS 0x0121
-+#define V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS 0x0122
-+#define V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX 0x0123
-+#define V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS 0x0124
-+
-+enum v4l2_mpeg_video_hevc_decode_mode {
-+ V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED,
-+ V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED,
-+};
-+
-+enum v4l2_mpeg_video_hevc_start_code {
-+ V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE,
-+ V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B,
-+};
-+
-+#define V4L2_HEVC_SLICE_TYPE_B 0
-+#define V4L2_HEVC_SLICE_TYPE_P 1
-+#define V4L2_HEVC_SLICE_TYPE_I 2
-+
-+#define V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE (1ULL << 0)
-+#define V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED (1ULL << 1)
-+#define V4L2_HEVC_SPS_FLAG_AMP_ENABLED (1ULL << 2)
-+#define V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET (1ULL << 3)
-+#define V4L2_HEVC_SPS_FLAG_PCM_ENABLED (1ULL << 4)
-+#define V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED (1ULL << 5)
-+#define V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT (1ULL << 6)
-+#define V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED (1ULL << 7)
-+#define V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED (1ULL << 8)
-+
-+/* The controls are not stable at the moment and will likely be reworked. */
-+struct v4l2_ctrl_hevc_sps {
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: Sequence parameter set */
-+ __u16 pic_width_in_luma_samples;
-+ __u16 pic_height_in_luma_samples;
-+ __u8 bit_depth_luma_minus8;
-+ __u8 bit_depth_chroma_minus8;
-+ __u8 log2_max_pic_order_cnt_lsb_minus4;
-+ __u8 sps_max_dec_pic_buffering_minus1;
-+ __u8 sps_max_num_reorder_pics;
-+ __u8 sps_max_latency_increase_plus1;
-+ __u8 log2_min_luma_coding_block_size_minus3;
-+ __u8 log2_diff_max_min_luma_coding_block_size;
-+ __u8 log2_min_luma_transform_block_size_minus2;
-+ __u8 log2_diff_max_min_luma_transform_block_size;
-+ __u8 max_transform_hierarchy_depth_inter;
-+ __u8 max_transform_hierarchy_depth_intra;
-+ __u8 pcm_sample_bit_depth_luma_minus1;
-+ __u8 pcm_sample_bit_depth_chroma_minus1;
-+ __u8 log2_min_pcm_luma_coding_block_size_minus3;
-+ __u8 log2_diff_max_min_pcm_luma_coding_block_size;
-+ __u8 num_short_term_ref_pic_sets;
-+ __u8 num_long_term_ref_pics_sps;
-+ __u8 chroma_format_idc;
-+ __u8 sps_max_sub_layers_minus1;
-+
-+ __u64 flags;
-+};
-+
-+#define V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED (1ULL << 0)
-+#define V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT (1ULL << 1)
-+#define V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED (1ULL << 2)
-+#define V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT (1ULL << 3)
-+#define V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED (1ULL << 4)
-+#define V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED (1ULL << 5)
-+#define V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED (1ULL << 6)
-+#define V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT (1ULL << 7)
-+#define V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED (1ULL << 8)
-+#define V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED (1ULL << 9)
-+#define V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED (1ULL << 10)
-+#define V4L2_HEVC_PPS_FLAG_TILES_ENABLED (1ULL << 11)
-+#define V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED (1ULL << 12)
-+#define V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED (1ULL << 13)
-+#define V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED (1ULL << 14)
-+#define V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED (1ULL << 15)
-+#define V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER (1ULL << 16)
-+#define V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT (1ULL << 17)
-+#define V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT (1ULL << 18)
-+#define V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT (1ULL << 19)
-+#define V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING (1ULL << 20)
-+
-+struct v4l2_ctrl_hevc_pps {
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture parameter set */
-+ __u8 num_extra_slice_header_bits;
-+ __u8 num_ref_idx_l0_default_active_minus1;
-+ __u8 num_ref_idx_l1_default_active_minus1;
-+ __s8 init_qp_minus26;
-+ __u8 diff_cu_qp_delta_depth;
-+ __s8 pps_cb_qp_offset;
-+ __s8 pps_cr_qp_offset;
-+ __u8 num_tile_columns_minus1;
-+ __u8 num_tile_rows_minus1;
-+ __u8 column_width_minus1[20];
-+ __u8 row_height_minus1[22];
-+ __s8 pps_beta_offset_div2;
-+ __s8 pps_tc_offset_div2;
-+ __u8 log2_parallel_merge_level_minus2;
-+
-+ __u8 padding[4];
-+ __u64 flags;
-+};
-+
-+#define V4L2_HEVC_DPB_ENTRY_RPS_ST_CURR_BEFORE 0x01
-+#define V4L2_HEVC_DPB_ENTRY_RPS_ST_CURR_AFTER 0x02
-+#define V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR 0x03
-+
-+#define V4L2_HEVC_DPB_ENTRIES_NUM_MAX 16
-+
-+struct v4l2_hevc_dpb_entry {
-+ __u64 timestamp;
-+ __u8 rps;
-+ __u8 field_pic;
-+ __u16 pic_order_cnt[2];
-+ __u8 padding[2];
-+};
-+
-+struct v4l2_hevc_pred_weight_table {
-+ __s8 delta_luma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-+ __s8 luma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-+ __s8 delta_chroma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2];
-+ __s8 chroma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2];
-+
-+ __s8 delta_luma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-+ __s8 luma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-+ __s8 delta_chroma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2];
-+ __s8 chroma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2];
-+
-+ __u8 padding[6];
-+
-+ __u8 luma_log2_weight_denom;
-+ __s8 delta_chroma_log2_weight_denom;
-+};
-+
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA (1ULL << 0)
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA (1ULL << 1)
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED (1ULL << 2)
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO (1ULL << 3)
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT (1ULL << 4)
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0 (1ULL << 5)
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_USE_INTEGER_MV (1ULL << 6)
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED (1ULL << 7)
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED (1ULL << 8)
-+#define V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT (1ULL << 9)
-+
-+struct v4l2_ctrl_hevc_slice_params {
-+ __u32 bit_size;
-+ __u32 data_bit_offset;
-+
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
-+ __u32 slice_segment_addr;
-+ __u32 num_entry_point_offsets;
-+
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: NAL unit header */
-+ __u8 nal_unit_type;
-+ __u8 nuh_temporal_id_plus1;
-+
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
-+ __u8 slice_type;
-+ __u8 colour_plane_id;
-+ __u16 slice_pic_order_cnt;
-+ __u8 num_ref_idx_l0_active_minus1;
-+ __u8 num_ref_idx_l1_active_minus1;
-+ __u8 collocated_ref_idx;
-+ __u8 five_minus_max_num_merge_cand;
-+ __s8 slice_qp_delta;
-+ __s8 slice_cb_qp_offset;
-+ __s8 slice_cr_qp_offset;
-+ __s8 slice_act_y_qp_offset;
-+ __s8 slice_act_cb_qp_offset;
-+ __s8 slice_act_cr_qp_offset;
-+ __s8 slice_beta_offset_div2;
-+ __s8 slice_tc_offset_div2;
-+
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture timing SEI message */
-+ __u8 pic_struct;
-+
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
-+ __u8 ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-+ __u8 ref_idx_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-+
-+ __u8 padding[5];
-+
-+ __u32 entry_point_offset_minus1[256];
-+
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: Weighted prediction parameter */
-+ struct v4l2_hevc_pred_weight_table pred_weight_table;
-+
-+ __u64 flags;
-+};
-+
-+#define V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC 0x1
-+#define V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC 0x2
-+#define V4L2_HEVC_DECODE_PARAM_FLAG_NO_OUTPUT_OF_PRIOR 0x4
-+
-+struct v4l2_ctrl_hevc_decode_params {
-+ __s32 pic_order_cnt_val;
-+ __u8 num_active_dpb_entries;
-+ struct v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-+ __u8 num_poc_st_curr_before;
-+ __u8 num_poc_st_curr_after;
-+ __u8 num_poc_lt_curr;
-+ __u8 poc_st_curr_before[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-+ __u8 poc_st_curr_after[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-+ __u8 poc_lt_curr[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-+ __u64 flags;
-+};
-+
-+/* MPEG-class control IDs specific to the Hantro driver as defined by V4L2 */
-+#define V4L2_CID_CODEC_HANTRO_BASE (V4L2_CTRL_CLASS_CODEC | 0x1200)
-+/*
-+ * V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP -
-+ * the number of data (in bits) to skip in the
-+ * slice segment header.
-+ * If non-IDR, the bits to be skipped go from syntax element "pic_output_flag"
-+ * to before syntax element "slice_temporal_mvp_enabled_flag".
-+ * If IDR, the skipped bits are just "pic_output_flag"
-+ * (separate_colour_plane_flag is not supported).
-+ */
-+#define V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP (V4L2_CID_CODEC_HANTRO_BASE + 0)
-+
-+struct v4l2_ctrl_hevc_scaling_matrix {
-+ __u8 scaling_list_4x4[6][16];
-+ __u8 scaling_list_8x8[6][64];
-+ __u8 scaling_list_16x16[6][64];
-+ __u8 scaling_list_32x32[2][64];
-+ __u8 scaling_list_dc_coef_16x16[6];
-+ __u8 scaling_list_dc_coef_32x32[2];
-+};
-+
-+#endif
-diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
-index 8a0246fa21..2867cb2e16 100644
---- a/libavcodec/hevcdec.c
-+++ b/libavcodec/hevcdec.c
-@@ -416,6 +416,7 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
- #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + \
- CONFIG_HEVC_D3D11VA_HWACCEL * 2 + \
- CONFIG_HEVC_NVDEC_HWACCEL + \
-+ CONFIG_HEVC_V4L2REQUEST_HWACCEL + \
- CONFIG_HEVC_VAAPI_HWACCEL + \
- CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL + \
- CONFIG_HEVC_VDPAU_HWACCEL)
-@@ -442,6 +443,9 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
- #endif
- #if CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL
- *fmt++ = AV_PIX_FMT_VIDEOTOOLBOX;
-+#endif
-+#if CONFIG_HEVC_V4L2REQUEST_HWACCEL
-+ *fmt++ = AV_PIX_FMT_DRM_PRIME;
- #endif
- break;
- case AV_PIX_FMT_YUV420P10:
-@@ -463,6 +467,9 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
- #endif
- #if CONFIG_HEVC_NVDEC_HWACCEL
- *fmt++ = AV_PIX_FMT_CUDA;
-+#endif
-+#if CONFIG_HEVC_V4L2REQUEST_HWACCEL
-+ *fmt++ = AV_PIX_FMT_DRM_PRIME;
- #endif
- break;
- case AV_PIX_FMT_YUV444P:
-@@ -3749,6 +3756,9 @@ const FFCodec ff_hevc_decoder = {
- #if CONFIG_HEVC_NVDEC_HWACCEL
- HWACCEL_NVDEC(hevc),
- #endif
-+#if CONFIG_HEVC_V4L2REQUEST_HWACCEL
-+ HWACCEL_V4L2REQUEST(hevc),
-+#endif
- #if CONFIG_HEVC_VAAPI_HWACCEL
- HWACCEL_VAAPI(hevc),
- #endif
-diff --git a/libavcodec/hwaccels.h b/libavcodec/hwaccels.h
-index aca55831f3..f32d1c4ec4 100644
---- a/libavcodec/hwaccels.h
-+++ b/libavcodec/hwaccels.h
-@@ -40,6 +40,7 @@ extern const AVHWAccel ff_hevc_d3d11va_hwaccel;
- extern const AVHWAccel ff_hevc_d3d11va2_hwaccel;
- extern const AVHWAccel ff_hevc_dxva2_hwaccel;
- extern const AVHWAccel ff_hevc_nvdec_hwaccel;
-+extern const AVHWAccel ff_hevc_v4l2request_hwaccel;
- extern const AVHWAccel ff_hevc_vaapi_hwaccel;
- extern const AVHWAccel ff_hevc_vdpau_hwaccel;
- extern const AVHWAccel ff_hevc_videotoolbox_hwaccel;
-diff --git a/libavcodec/hwconfig.h b/libavcodec/hwconfig.h
-index c43ad55245..b8aa383071 100644
---- a/libavcodec/hwconfig.h
-+++ b/libavcodec/hwconfig.h
-@@ -71,6 +71,8 @@ typedef struct AVCodecHWConfigInternal {
- HW_CONFIG_HWACCEL(1, 1, 0, D3D11, D3D11VA, ff_ ## codec ## _d3d11va2_hwaccel)
- #define HWACCEL_NVDEC(codec) \
- HW_CONFIG_HWACCEL(1, 1, 0, CUDA, CUDA, ff_ ## codec ## _nvdec_hwaccel)
-+#define HWACCEL_V4L2REQUEST(codec) \
-+ HW_CONFIG_HWACCEL(1, 0, 0, DRM_PRIME, DRM, ff_ ## codec ## _v4l2request_hwaccel)
- #define HWACCEL_VAAPI(codec) \
- HW_CONFIG_HWACCEL(1, 1, 1, VAAPI, VAAPI, ff_ ## codec ## _vaapi_hwaccel)
- #define HWACCEL_VDPAU(codec) \
-diff --git a/libavcodec/v4l2_req_decode_q.c b/libavcodec/v4l2_req_decode_q.c
-new file mode 100644
-index 0000000000..5b3fb958fa
---- /dev/null
-+++ b/libavcodec/v4l2_req_decode_q.c
-@@ -0,0 +1,84 @@
-+#include
-+#include
-+#include
-+
-+#include "v4l2_req_decode_q.h"
-+
-+int decode_q_in_q(const req_decode_ent * const d)
-+{
-+ return d->in_q;
-+}
-+
-+void decode_q_add(req_decode_q * const q, req_decode_ent * const d)
-+{
-+ pthread_mutex_lock(&q->q_lock);
-+ if (!q->head) {
-+ q->head = d;
-+ q->tail = d;
-+ d->prev = NULL;
-+ }
-+ else {
-+ q->tail->next = d;
-+ d->prev = q->tail;
-+ q->tail = d;
-+ }
-+ d->next = NULL;
-+ d->in_q = 1;
-+ pthread_mutex_unlock(&q->q_lock);
-+}
-+
-+// Remove entry from Q - if head wake-up anything that was waiting
-+void decode_q_remove(req_decode_q * const q, req_decode_ent * const d)
-+{
-+ int try_signal = 0;
-+
-+ if (!d->in_q)
-+ return;
-+
-+ pthread_mutex_lock(&q->q_lock);
-+ if (d->prev)
-+ d->prev->next = d->next;
-+ else {
-+ try_signal = 1; // Only need to signal if we were head
-+ q->head = d->next;
-+ }
-+
-+ if (d->next)
-+ d->next->prev = d->prev;
-+ else
-+ q->tail = d->prev;
-+
-+ // Not strictly needed but makes debug easier
-+ d->next = NULL;
-+ d->prev = NULL;
-+ d->in_q = 0;
-+ pthread_mutex_unlock(&q->q_lock);
-+
-+ if (try_signal)
-+ pthread_cond_broadcast(&q->q_cond);
-+}
-+
-+void decode_q_wait(req_decode_q * const q, req_decode_ent * const d)
-+{
-+ pthread_mutex_lock(&q->q_lock);
-+
-+ while (q->head != d)
-+ pthread_cond_wait(&q->q_cond, &q->q_lock);
-+
-+ pthread_mutex_unlock(&q->q_lock);
-+}
-+
-+void decode_q_uninit(req_decode_q * const q)
-+{
-+ pthread_mutex_destroy(&q->q_lock);
-+ pthread_cond_destroy(&q->q_cond);
-+}
-+
-+void decode_q_init(req_decode_q * const q)
-+{
-+ memset(q, 0, sizeof(*q));
-+ pthread_mutex_init(&q->q_lock, NULL);
-+ pthread_cond_init(&q->q_cond, NULL);
-+}
-+
-+
-diff --git a/libavcodec/v4l2_req_decode_q.h b/libavcodec/v4l2_req_decode_q.h
-new file mode 100644
-index 0000000000..af7bbe1de4
---- /dev/null
-+++ b/libavcodec/v4l2_req_decode_q.h
-@@ -0,0 +1,25 @@
-+#ifndef AVCODEC_V4L2_REQ_DECODE_Q_H
-+#define AVCODEC_V4L2_REQ_DECODE_Q_H
-+
-+typedef struct req_decode_ent {
-+ struct req_decode_ent * next;
-+ struct req_decode_ent * prev;
-+ int in_q;
-+} req_decode_ent;
-+
-+typedef struct req_decode_q {
-+ pthread_mutex_t q_lock;
-+ pthread_cond_t q_cond;
-+ req_decode_ent * head;
-+ req_decode_ent * tail;
-+} req_decode_q;
-+
-+int decode_q_in_q(const req_decode_ent * const d);
-+void decode_q_add(req_decode_q * const q, req_decode_ent * const d);
-+void decode_q_remove(req_decode_q * const q, req_decode_ent * const d);
-+void decode_q_wait(req_decode_q * const q, req_decode_ent * const d);
-+void decode_q_uninit(req_decode_q * const q);
-+void decode_q_init(req_decode_q * const q);
-+
-+#endif
-+
-diff --git a/libavcodec/v4l2_req_devscan.c b/libavcodec/v4l2_req_devscan.c
-new file mode 100644
-index 0000000000..cfa94d55c4
---- /dev/null
-+++ b/libavcodec/v4l2_req_devscan.c
-@@ -0,0 +1,449 @@
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+
-+#include
-+#include
-+
-+#include
-+#include
-+
-+#include "v4l2_req_devscan.h"
-+#include "v4l2_req_utils.h"
-+
-+struct decdev {
-+ enum v4l2_buf_type src_type;
-+ uint32_t src_fmt_v4l2;
-+ const char * vname;
-+ const char * mname;
-+};
-+
-+struct devscan {
-+ struct decdev env;
-+ unsigned int dev_size;
-+ unsigned int dev_count;
-+ struct decdev *devs;
-+};
-+
-+static int video_src_pixfmt_supported(uint32_t fmt)
-+{
-+ return 1;
-+}
-+
-+static void v4l2_setup_format(struct v4l2_format *format, unsigned int type,
-+ unsigned int width, unsigned int height,
-+ unsigned int pixelformat)
-+{
-+ unsigned int sizeimage;
-+
-+ memset(format, 0, sizeof(*format));
-+ format->type = type;
-+
-+ sizeimage = V4L2_TYPE_IS_OUTPUT(type) ? 4 * 1024 * 1024 : 0;
-+
-+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
-+ format->fmt.pix_mp.width = width;
-+ format->fmt.pix_mp.height = height;
-+ format->fmt.pix_mp.plane_fmt[0].sizeimage = sizeimage;
-+ format->fmt.pix_mp.pixelformat = pixelformat;
-+ } else {
-+ format->fmt.pix.width = width;
-+ format->fmt.pix.height = height;
-+ format->fmt.pix.sizeimage = sizeimage;
-+ format->fmt.pix.pixelformat = pixelformat;
-+ }
-+}
-+
-+static int v4l2_set_format(int video_fd, unsigned int type, unsigned int pixelformat,
-+ unsigned int width, unsigned int height)
-+{
-+ struct v4l2_format format;
-+
-+ v4l2_setup_format(&format, type, width, height, pixelformat);
-+
-+ return ioctl(video_fd, VIDIOC_S_FMT, &format) ? -errno : 0;
-+}
-+
-+static int v4l2_query_capabilities(int video_fd, unsigned int *capabilities)
-+{
-+ struct v4l2_capability capability = { 0 };
-+ int rc;
-+
-+ rc = ioctl(video_fd, VIDIOC_QUERYCAP, &capability);
-+ if (rc < 0)
-+ return -errno;
-+
-+ if (capabilities != NULL) {
-+ if ((capability.capabilities & V4L2_CAP_DEVICE_CAPS) != 0)
-+ *capabilities = capability.device_caps;
-+ else
-+ *capabilities = capability.capabilities;
-+ }
-+
-+ return 0;
-+}
-+
-+static int devscan_add(struct devscan *const scan,
-+ enum v4l2_buf_type src_type,
-+ uint32_t src_fmt_v4l2,
-+ const char * vname,
-+ const char * mname)
-+{
-+ struct decdev *d;
-+
-+ if (scan->dev_size <= scan->dev_count) {
-+ unsigned int n = !scan->dev_size ? 4 : scan->dev_size * 2;
-+ d = realloc(scan->devs, n * sizeof(*d));
-+ if (!d)
-+ return -ENOMEM;
-+ scan->devs = d;
-+ scan->dev_size = n;
-+ }
-+
-+ d = scan->devs + scan->dev_count;
-+ d->src_type = src_type;
-+ d->src_fmt_v4l2 = src_fmt_v4l2;
-+ d->vname = strdup(vname);
-+ if (!d->vname)
-+ return -ENOMEM;
-+ d->mname = strdup(mname);
-+ if (!d->mname) {
-+ free((char *)d->vname);
-+ return -ENOMEM;
-+ }
-+ ++scan->dev_count;
-+ return 0;
-+}
-+
-+void devscan_delete(struct devscan **const pScan)
-+{
-+ unsigned int i;
-+ struct devscan * const scan = *pScan;
-+
-+ if (!scan)
-+ return;
-+ *pScan = NULL;
-+
-+ for (i = 0; i < scan->dev_count; ++i) {
-+ free((char*)scan->devs[i].mname);
-+ free((char*)scan->devs[i].vname);
-+ }
-+ free(scan->devs);
-+ free(scan);
-+}
-+
-+#define REQ_BUF_CAPS (\
-+ V4L2_BUF_CAP_SUPPORTS_DMABUF |\
-+ V4L2_BUF_CAP_SUPPORTS_REQUESTS |\
-+ V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF)
-+
-+static void probe_formats(void * const dc,
-+ struct devscan *const scan,
-+ const int fd,
-+ const unsigned int type_v4l2,
-+ const char *const mpath,
-+ const char *const vpath)
-+{
-+ unsigned int i;
-+ for (i = 0;; ++i) {
-+ struct v4l2_fmtdesc fmtdesc = {
-+ .index = i,
-+ .type = type_v4l2
-+ };
-+ struct v4l2_requestbuffers rbufs = {
-+ .count = 0,
-+ .type = type_v4l2,
-+ .memory = V4L2_MEMORY_MMAP
-+ };
-+ while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)) {
-+ if (errno == EINTR)
-+ continue;
-+ if (errno != EINVAL)
-+ request_err(dc, "Enum[%d] failed for type=%d\n", i, type_v4l2);
-+ return;
-+ }
-+ if (!video_src_pixfmt_supported(fmtdesc.pixelformat))
-+ continue;
-+
-+ if (v4l2_set_format(fd, type_v4l2, fmtdesc.pixelformat, 720, 480)) {
-+ request_debug(dc, "Set failed for type=%d, pf=%.4s\n", type_v4l2, (char*)&fmtdesc.pixelformat);
-+ continue;
-+ }
-+
-+ while (ioctl(fd, VIDIOC_REQBUFS, &rbufs)) {
-+ if (errno != EINTR) {
-+ request_debug(dc, "%s: Reqbufs failed\n", vpath);
-+ continue;
-+ }
-+ }
-+
-+ if ((rbufs.capabilities & REQ_BUF_CAPS) != REQ_BUF_CAPS) {
-+ request_debug(dc, "%s: Buf caps %#x insufficient\n", vpath, rbufs.capabilities);
-+ continue;
-+ }
-+
-+ request_debug(dc, "Adding: %s,%s pix=%#x, type=%d\n",
-+ mpath, vpath, fmtdesc.pixelformat, type_v4l2);
-+ devscan_add(scan, type_v4l2, fmtdesc.pixelformat, vpath, mpath);
-+ }
-+}
-+
-+
-+static int probe_video_device(void * const dc,
-+ struct udev_device *const device,
-+ struct devscan *const scan,
-+ const char *const mpath)
-+{
-+ int ret;
-+ unsigned int capabilities = 0;
-+ int video_fd = -1;
-+
-+ const char *path = udev_device_get_devnode(device);
-+ if (!path) {
-+ request_err(dc, "%s: get video device devnode failed\n", __func__);
-+ ret = -EINVAL;
-+ goto fail;
-+ }
-+
-+ video_fd = open(path, O_RDWR, 0);
-+ if (video_fd == -1) {
-+ ret = -errno;
-+ request_err(dc, "%s: opening %s failed, %s (%d)\n", __func__, path, strerror(errno), errno);
-+ goto fail;
-+ }
-+
-+ ret = v4l2_query_capabilities(video_fd, &capabilities);
-+ if (ret < 0) {
-+ request_err(dc, "%s: get video capability failed, %s (%d)\n", __func__, strerror(-ret), -ret);
-+ goto fail;
-+ }
-+
-+ request_debug(dc, "%s: path=%s capabilities=%#x\n", __func__, path, capabilities);
-+
-+ if (!(capabilities & V4L2_CAP_STREAMING)) {
-+ request_debug(dc, "%s: missing required streaming capability\n", __func__);
-+ ret = -EINVAL;
-+ goto fail;
-+ }
-+
-+ if (!(capabilities & (V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_VIDEO_M2M))) {
-+ request_debug(dc, "%s: missing required mem2mem capability\n", __func__);
-+ ret = -EINVAL;
-+ goto fail;
-+ }
-+
-+ /* Should check capture formats too... */
-+ if ((capabilities & V4L2_CAP_VIDEO_M2M) != 0)
-+ probe_formats(dc, scan, video_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT, mpath, path);
-+ if ((capabilities & V4L2_CAP_VIDEO_M2M_MPLANE) != 0)
-+ probe_formats(dc, scan, video_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, mpath, path);
-+
-+ close(video_fd);
-+ return 0;
-+
-+fail:
-+ if (video_fd >= 0)
-+ close(video_fd);
-+ return ret;
-+}
-+
-+static int probe_media_device(void * const dc,
-+ struct udev_device *const device,
-+ struct devscan *const scan)
-+{
-+ int ret;
-+ int rv;
-+ struct media_device_info device_info = { 0 };
-+ struct media_v2_topology topology = { 0 };
-+ struct media_v2_interface *interfaces = NULL;
-+ struct udev *udev = udev_device_get_udev(device);
-+ struct udev_device *video_device;
-+ dev_t devnum;
-+ int media_fd = -1;
-+
-+ const char *path = udev_device_get_devnode(device);
-+ if (!path) {
-+ request_err(dc, "%s: get media device devnode failed\n", __func__);
-+ ret = -EINVAL;
-+ goto fail;
-+ }
-+
-+ media_fd = open(path, O_RDWR, 0);
-+ if (media_fd < 0) {
-+ ret = -errno;
-+ request_err(dc, "%s: opening %s failed, %s (%d)\n", __func__, path, strerror(-ret), -ret);
-+ goto fail;
-+ }
-+
-+ rv = ioctl(media_fd, MEDIA_IOC_DEVICE_INFO, &device_info);
-+ if (rv < 0) {
-+ ret = -errno;
-+ request_err(dc, "%s: get media device info failed, %s (%d)\n", __func__, strerror(-ret), -ret);
-+ goto fail;
-+ }
-+
-+ rv = ioctl(media_fd, MEDIA_IOC_G_TOPOLOGY, &topology);
-+ if (rv < 0) {
-+ ret = -errno;
-+ request_err(dc, "%s: get media topology failed, %s (%d)\n", __func__, strerror(-ret), -ret);
-+ goto fail;
-+ }
-+
-+ if (topology.num_interfaces <= 0) {
-+ request_err(dc, "%s: media device has no interfaces\n", __func__);
-+ ret = -EINVAL;
-+ goto fail;
-+ }
-+
-+ interfaces = calloc(topology.num_interfaces, sizeof(*interfaces));
-+ if (!interfaces) {
-+ request_err(dc, "%s: allocating media interface struct failed\n", __func__);
-+ ret = -ENOMEM;
-+ goto fail;
-+ }
-+
-+ topology.ptr_interfaces = (__u64)(uintptr_t)interfaces;
-+ rv = ioctl(media_fd, MEDIA_IOC_G_TOPOLOGY, &topology);
-+ if (rv < 0) {
-+ ret = -errno;
-+ request_err(dc, "%s: get media topology failed, %s (%d)\n", __func__, strerror(-ret), -ret);
-+ goto fail;
-+ }
-+
-+ for (int i = 0; i < topology.num_interfaces; i++) {
-+ if (interfaces[i].intf_type != MEDIA_INTF_T_V4L_VIDEO)
-+ continue;
-+
-+ devnum = makedev(interfaces[i].devnode.major, interfaces[i].devnode.minor);
-+ video_device = udev_device_new_from_devnum(udev, 'c', devnum);
-+ if (!video_device) {
-+ ret = -errno;
-+ request_err(dc, "%s: video_device[%d]=%p\n", __func__, i, video_device);
-+ continue;
-+ }
-+
-+ ret = probe_video_device(dc, video_device, scan, path);
-+ udev_device_unref(video_device);
-+
-+ if (ret != 0)
-+ goto fail;
-+ }
-+
-+fail:
-+ free(interfaces);
-+ if (media_fd != -1)
-+ close(media_fd);
-+ return ret;
-+}
-+
-+const char *decdev_media_path(const struct decdev *const dev)
-+{
-+ return !dev ? NULL : dev->mname;
-+}
-+
-+const char *decdev_video_path(const struct decdev *const dev)
-+{
-+ return !dev ? NULL : dev->vname;
-+}
-+
-+enum v4l2_buf_type decdev_src_type(const struct decdev *const dev)
-+{
-+ return !dev ? 0 : dev->src_type;
-+}
-+
-+uint32_t decdev_src_pixelformat(const struct decdev *const dev)
-+{
-+ return !dev ? 0 : dev->src_fmt_v4l2;
-+}
-+
-+
-+const struct decdev *devscan_find(struct devscan *const scan,
-+ const uint32_t src_fmt_v4l2)
-+{
-+ unsigned int i;
-+
-+ if (scan->env.mname && scan->env.vname)
-+ return &scan->env;
-+
-+ if (!src_fmt_v4l2)
-+ return scan->dev_count ? scan->devs + 0 : NULL;
-+
-+ for (i = 0; i != scan->dev_count; ++i) {
-+ if (scan->devs[i].src_fmt_v4l2 == src_fmt_v4l2)
-+ return scan->devs + i;
-+ }
-+ return NULL;
-+}
-+
-+int devscan_build(void * const dc, struct devscan **pscan)
-+{
-+ int ret;
-+ struct udev *udev;
-+ struct udev_enumerate *enumerate;
-+ struct udev_list_entry *devices;
-+ struct udev_list_entry *entry;
-+ struct udev_device *device;
-+ struct devscan * scan;
-+
-+ *pscan = NULL;
-+
-+ scan = calloc(1, sizeof(*scan));
-+ if (!scan) {
-+ ret = -ENOMEM;
-+ goto fail;
-+ }
-+
-+ scan->env.mname = getenv("LIBVA_V4L2_REQUEST_MEDIA_PATH");
-+ scan->env.vname = getenv("LIBVA_V4L2_REQUEST_VIDEO_PATH");
-+ if (scan->env.mname && scan->env.vname) {
-+ request_info(dc, "Media/video device env overrides found: %s,%s\n",
-+ scan->env.mname, scan->env.vname);
-+ *pscan = scan;
-+ return 0;
-+ }
-+
-+ udev = udev_new();
-+ if (!udev) {
-+ request_err(dc, "%s: allocating udev context failed\n", __func__);
-+ ret = -ENOMEM;
-+ goto fail;
-+ }
-+
-+ enumerate = udev_enumerate_new(udev);
-+ if (!enumerate) {
-+ request_err(dc, "%s: allocating udev enumerator failed\n", __func__);
-+ ret = -ENOMEM;
-+ goto fail;
-+ }
-+
-+ udev_enumerate_add_match_subsystem(enumerate, "media");
-+ udev_enumerate_scan_devices(enumerate);
-+
-+ devices = udev_enumerate_get_list_entry(enumerate);
-+ 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;
-+
-+ probe_media_device(dc, device, scan);
-+ udev_device_unref(device);
-+ }
-+
-+ udev_enumerate_unref(enumerate);
-+
-+ *pscan = scan;
-+ return 0;
-+
-+fail:
-+ udev_unref(udev);
-+ devscan_delete(&scan);
-+ return ret;
-+}
-+
-diff --git a/libavcodec/v4l2_req_devscan.h b/libavcodec/v4l2_req_devscan.h
-new file mode 100644
-index 0000000000..956d9234f1
---- /dev/null
-+++ b/libavcodec/v4l2_req_devscan.h
-@@ -0,0 +1,23 @@
-+#ifndef _DEVSCAN_H_
-+#define _DEVSCAN_H_
-+
-+#include
-+
-+struct devscan;
-+struct decdev;
-+enum v4l2_buf_type;
-+
-+/* These return pointers to data in the devscan structure and so are vaild
-+ * for the lifetime of that
-+ */
-+const char *decdev_media_path(const struct decdev *const dev);
-+const char *decdev_video_path(const struct decdev *const dev);
-+enum v4l2_buf_type decdev_src_type(const struct decdev *const dev);
-+uint32_t decdev_src_pixelformat(const struct decdev *const dev);
-+
-+const struct decdev *devscan_find(struct devscan *const scan, const uint32_t src_fmt_v4l2);
-+
-+int devscan_build(void * const dc, struct devscan **pscan);
-+void devscan_delete(struct devscan **const pScan);
-+
-+#endif
-diff --git a/libavcodec/v4l2_req_dmabufs.c b/libavcodec/v4l2_req_dmabufs.c
-new file mode 100644
-index 0000000000..ae6c648369
---- /dev/null
-+++ b/libavcodec/v4l2_req_dmabufs.c
-@@ -0,0 +1,266 @@
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+
-+#include "v4l2_req_dmabufs.h"
-+#include "v4l2_req_utils.h"
-+
-+#define DMABUF_NAME1 "/dev/dma_heap/linux,cma"
-+#define DMABUF_NAME2 "/dev/dma_heap/reserved"
-+
-+#define TRACE_ALLOC 0
-+
-+struct dmabufs_ctl {
-+ int fd;
-+ size_t page_size;
-+};
-+
-+struct dmabuf_h {
-+ int fd;
-+ size_t size;
-+ size_t len;
-+ void * mapptr;
-+};
-+
-+#if TRACE_ALLOC
-+static unsigned int total_bufs = 0;
-+static size_t total_size = 0;
-+#endif
-+
-+struct dmabuf_h * dmabuf_import(int fd, size_t size)
-+{
-+ struct dmabuf_h *dh;
-+
-+ fd = dup(fd);
-+ if (fd < 0 || size == 0)
-+ return NULL;
-+
-+ dh = malloc(sizeof(*dh));
-+ if (!dh) {
-+ close(fd);
-+ return NULL;
-+ }
-+
-+ *dh = (struct dmabuf_h) {
-+ .fd = fd,
-+ .size = size,
-+ .mapptr = MAP_FAILED
-+ };
-+
-+#if TRACE_ALLOC
-+ ++total_bufs;
-+ total_size += dh->size;
-+ request_log("%s: Import: %zd, total=%zd, bufs=%d\n", __func__, dh->size, total_size, total_bufs);
-+#endif
-+
-+ return dh;
-+}
-+
-+struct dmabuf_h * dmabuf_realloc(struct dmabufs_ctl * dbsc, struct dmabuf_h * old, size_t size)
-+{
-+ struct dmabuf_h * dh;
-+ struct dma_heap_allocation_data data = {
-+ .len = (size + dbsc->page_size - 1) & ~(dbsc->page_size - 1),
-+ .fd = 0,
-+ .fd_flags = O_RDWR,
-+ .heap_flags = 0
-+ };
-+
-+ if (old != NULL) {
-+ if (old->size == data.len) {
-+ return old;
-+ }
-+ dmabuf_free(old);
-+ }
-+
-+ if (size == 0 ||
-+ (dh = malloc(sizeof(*dh))) == NULL)
-+ return NULL;
-+
-+ while (ioctl(dbsc->fd, DMA_HEAP_IOCTL_ALLOC, &data)) {
-+ int err = errno;
-+ request_log("Failed to alloc %" PRIu64 " from dma-heap(fd=%d): %d (%s)\n",
-+ (uint64_t)data.len,
-+ dbsc->fd,
-+ err,
-+ strerror(err));
-+ if (err == EINTR)
-+ continue;
-+ goto fail;
-+ }
-+
-+ *dh = (struct dmabuf_h){
-+ .fd = data.fd,
-+ .size = (size_t)data.len,
-+ .mapptr = MAP_FAILED
-+ };
-+
-+#if TRACE_ALLOC
-+ ++total_bufs;
-+ total_size += dh->size;
-+ request_log("%s: Alloc: %zd, total=%zd, bufs=%d\n", __func__, dh->size, total_size, total_bufs);
-+#endif
-+
-+ return dh;
-+
-+fail:
-+ free(dh);
-+ return NULL;
-+}
-+
-+int dmabuf_sync(struct dmabuf_h * const dh, unsigned int flags)
-+{
-+ struct dma_buf_sync sync = {
-+ .flags = flags
-+ };
-+ while (ioctl(dh->fd, DMA_BUF_IOCTL_SYNC, &sync) == -1) {
-+ const int err = errno;
-+ if (errno == EINTR)
-+ continue;
-+ request_log("%s: ioctl failed: flags=%#x\n", __func__, flags);
-+ return -err;
-+ }
-+ return 0;
-+}
-+
-+int dmabuf_write_start(struct dmabuf_h * const dh)
-+{
-+ return dmabuf_sync(dh, DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE);
-+}
-+
-+int dmabuf_write_end(struct dmabuf_h * const dh)
-+{
-+ return dmabuf_sync(dh, DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE);
-+}
-+
-+int dmabuf_read_start(struct dmabuf_h * const dh)
-+{
-+ if (!dmabuf_map(dh))
-+ return -1;
-+ return dmabuf_sync(dh, DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ);
-+}
-+
-+int dmabuf_read_end(struct dmabuf_h * const dh)
-+{
-+ return dmabuf_sync(dh, DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ);
-+}
-+
-+
-+void * dmabuf_map(struct dmabuf_h * const dh)
-+{
-+ if (!dh)
-+ return NULL;
-+ if (dh->mapptr != MAP_FAILED)
-+ return dh->mapptr;
-+ dh->mapptr = mmap(NULL, dh->size,
-+ PROT_READ | PROT_WRITE,
-+ MAP_SHARED | MAP_POPULATE,
-+ dh->fd, 0);
-+ if (dh->mapptr == MAP_FAILED) {
-+ request_log("%s: Map failed\n", __func__);
-+ return NULL;
-+ }
-+ return dh->mapptr;
-+}
-+
-+int dmabuf_fd(const struct dmabuf_h * const dh)
-+{
-+ if (!dh)
-+ return -1;
-+ return dh->fd;
-+}
-+
-+size_t dmabuf_size(const struct dmabuf_h * const dh)
-+{
-+ if (!dh)
-+ return 0;
-+ return dh->size;
-+}
-+
-+size_t dmabuf_len(const struct dmabuf_h * const dh)
-+{
-+ if (!dh)
-+ return 0;
-+ return dh->len;
-+}
-+
-+void dmabuf_len_set(struct dmabuf_h * const dh, const size_t len)
-+{
-+ dh->len = len;
-+}
-+
-+
-+
-+void dmabuf_free(struct dmabuf_h * dh)
-+{
-+ if (!dh)
-+ return;
-+
-+#if TRACE_ALLOC
-+ --total_bufs;
-+ total_size -= dh->size;
-+ request_log("%s: Free: %zd, total=%zd, bufs=%d\n", __func__, dh->size, total_size, total_bufs);
-+#endif
-+
-+ if (dh->mapptr != MAP_FAILED)
-+ munmap(dh->mapptr, dh->size);
-+ while (close(dh->fd) == -1 && errno == EINTR)
-+ /* loop */;
-+ free(dh);
-+}
-+
-+struct dmabufs_ctl * dmabufs_ctl_new(void)
-+{
-+ struct dmabufs_ctl * dbsc = malloc(sizeof(*dbsc));
-+
-+ if (!dbsc)
-+ return NULL;
-+
-+ while ((dbsc->fd = open(DMABUF_NAME1, O_RDWR)) == -1 &&
-+ errno == EINTR)
-+ /* Loop */;
-+
-+ if (dbsc->fd == -1) {
-+ while ((dbsc->fd = open(DMABUF_NAME2, O_RDWR)) == -1 &&
-+ errno == EINTR)
-+ /* Loop */;
-+ if (dbsc->fd == -1) {
-+ request_log("Unable to open either %s or %s\n",
-+ DMABUF_NAME1, DMABUF_NAME2);
-+ goto fail;
-+ }
-+ }
-+
-+ dbsc->page_size = (size_t)sysconf(_SC_PAGE_SIZE);
-+
-+ return dbsc;
-+
-+fail:
-+ free(dbsc);
-+ return NULL;
-+}
-+
-+void dmabufs_ctl_delete(struct dmabufs_ctl ** const pDbsc)
-+{
-+ struct dmabufs_ctl * const dbsc = *pDbsc;
-+
-+ if (!dbsc)
-+ return;
-+ *pDbsc = NULL;
-+
-+ while (close(dbsc->fd) == -1 && errno == EINTR)
-+ /* loop */;
-+
-+ free(dbsc);
-+}
-+
-+
-diff --git a/libavcodec/v4l2_req_dmabufs.h b/libavcodec/v4l2_req_dmabufs.h
-new file mode 100644
-index 0000000000..cfb17e801d
---- /dev/null
-+++ b/libavcodec/v4l2_req_dmabufs.h
-@@ -0,0 +1,40 @@
-+#ifndef DMABUFS_H
-+#define DMABUFS_H
-+
-+#include
-+
-+struct dmabufs_ctl;
-+struct dmabuf_h;
-+
-+struct dmabufs_ctl * dmabufs_ctl_new(void);
-+void dmabufs_ctl_delete(struct dmabufs_ctl ** const pdbsc);
-+
-+// Need not preserve old contents
-+// On NULL return old buffer is freed
-+struct dmabuf_h * dmabuf_realloc(struct dmabufs_ctl * dbsc, struct dmabuf_h *, size_t size);
-+
-+static inline struct dmabuf_h * dmabuf_alloc(struct dmabufs_ctl * dbsc, size_t size) {
-+ return dmabuf_realloc(dbsc, NULL, size);
-+}
-+/* Create from existing fd - dups(fd) */
-+struct dmabuf_h * dmabuf_import(int fd, size_t size);
-+void * dmabuf_map(struct dmabuf_h * const dh);
-+
-+/* flags from linux/dmabuf.h DMA_BUF_SYNC_xxx */
-+int dmabuf_sync(struct dmabuf_h * const dh, unsigned int flags);
-+
-+int dmabuf_write_start(struct dmabuf_h * const dh);
-+int dmabuf_write_end(struct dmabuf_h * const dh);
-+int dmabuf_read_start(struct dmabuf_h * const dh);
-+int dmabuf_read_end(struct dmabuf_h * const dh);
-+
-+int dmabuf_fd(const struct dmabuf_h * const dh);
-+/* Allocated size */
-+size_t dmabuf_size(const struct dmabuf_h * const dh);
-+/* Bytes in use */
-+size_t dmabuf_len(const struct dmabuf_h * const dh);
-+/* Set bytes in use */
-+void dmabuf_len_set(struct dmabuf_h * const dh, const size_t len);
-+void dmabuf_free(struct dmabuf_h * dh);
-+
-+#endif
-diff --git a/libavcodec/v4l2_req_hevc_v1.c b/libavcodec/v4l2_req_hevc_v1.c
-new file mode 100644
-index 0000000000..169b532832
---- /dev/null
-+++ b/libavcodec/v4l2_req_hevc_v1.c
-@@ -0,0 +1,3 @@
-+#define HEVC_CTRLS_VERSION 1
-+#include "v4l2_req_hevc_vx.c"
-+
-diff --git a/libavcodec/v4l2_req_hevc_v2.c b/libavcodec/v4l2_req_hevc_v2.c
-new file mode 100644
-index 0000000000..42af98e156
---- /dev/null
-+++ b/libavcodec/v4l2_req_hevc_v2.c
-@@ -0,0 +1,3 @@
-+#define HEVC_CTRLS_VERSION 2
-+#include "v4l2_req_hevc_vx.c"
-+
-diff --git a/libavcodec/v4l2_req_hevc_vx.c b/libavcodec/v4l2_req_hevc_vx.c
-new file mode 100644
-index 0000000000..0ae03b10c4
---- /dev/null
-+++ b/libavcodec/v4l2_req_hevc_vx.c
-@@ -0,0 +1,1213 @@
-+// File included by v4l2_req_hevc_v* - not compiled on its own
-+
-+#include "decode.h"
-+#include "hevcdec.h"
-+#include "hwconfig.h"
-+#include "internal.h"
-+#include "thread.h"
-+
-+#include "v4l2_request_hevc.h"
-+
-+#if HEVC_CTRLS_VERSION == 1
-+#include "hevc-ctrls-v1.h"
-+
-+// Fixup renamed entries
-+#define V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT
-+
-+#elif HEVC_CTRLS_VERSION == 2
-+#include "hevc-ctrls-v2.h"
-+#else
-+#error Unknown HEVC_CTRLS_VERSION
-+#endif
-+
-+#include "libavutil/hwcontext_drm.h"
-+
-+#include
-+#include
-+
-+#include "v4l2_req_devscan.h"
-+#include "v4l2_req_dmabufs.h"
-+#include "v4l2_req_pollqueue.h"
-+#include "v4l2_req_media.h"
-+#include "v4l2_req_utils.h"
-+
-+// Attached to buf[0] in frame
-+// Pooled in hwcontext so generally create once - 1/frame
-+typedef struct V4L2MediaReqDescriptor {
-+ AVDRMFrameDescriptor drm;
-+
-+ // Media
-+ uint64_t timestamp;
-+ struct qent_dst * qe_dst;
-+
-+ // Decode only - should be NULL by the time we emit the frame
-+ struct req_decode_ent decode_ent;
-+
-+ struct media_request *req;
-+ struct qent_src *qe_src;
-+
-+#if HEVC_CTRLS_VERSION >= 2
-+ struct v4l2_ctrl_hevc_decode_params dec;
-+#endif
-+
-+ size_t num_slices;
-+ size_t alloced_slices;
-+ struct v4l2_ctrl_hevc_slice_params * slice_params;
-+ struct slice_info * slices;
-+
-+} V4L2MediaReqDescriptor;
-+
-+struct slice_info {
-+ const uint8_t * ptr;
-+ size_t len; // bytes
-+};
-+
-+// Handy container for accumulating controls before setting
-+struct req_controls {
-+ int has_scaling;
-+ struct timeval tv;
-+ struct v4l2_ctrl_hevc_sps sps;
-+ struct v4l2_ctrl_hevc_pps pps;
-+ struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix;
-+};
-+
-+//static uint8_t nalu_slice_start_code[] = { 0x00, 0x00, 0x01 };
-+
-+
-+// Get an FFmpeg format from the v4l2 format
-+static enum AVPixelFormat pixel_format_from_format(const struct v4l2_format *const format)
-+{
-+ switch (V4L2_TYPE_IS_MULTIPLANAR(format->type) ?
-+ format->fmt.pix_mp.pixelformat : format->fmt.pix.pixelformat) {
-+ case V4L2_PIX_FMT_YUV420:
-+ return AV_PIX_FMT_YUV420P;
-+ case V4L2_PIX_FMT_NV12:
-+ return AV_PIX_FMT_NV12;
-+#if CONFIG_SAND
-+ case V4L2_PIX_FMT_NV12_COL128:
-+ return AV_PIX_FMT_RPI4_8;
-+ case V4L2_PIX_FMT_NV12_10_COL128:
-+ return AV_PIX_FMT_RPI4_10;
-+#endif
-+ default:
-+ break;
-+ }
-+ return AV_PIX_FMT_NONE;
-+}
-+
-+static inline uint64_t frame_capture_dpb(const AVFrame * const frame)
-+{
-+ const V4L2MediaReqDescriptor *const rd = (V4L2MediaReqDescriptor *)frame->data[0];
-+ return rd->timestamp;
-+}
-+
-+static inline void frame_set_capture_dpb(AVFrame * const frame, const uint64_t dpb_stamp)
-+{
-+ V4L2MediaReqDescriptor *const rd = (V4L2MediaReqDescriptor *)frame->data[0];
-+ rd->timestamp = dpb_stamp;
-+}
-+
-+static void fill_pred_table(const HEVCContext *h, struct v4l2_hevc_pred_weight_table *table)
-+{
-+ int32_t luma_weight_denom, chroma_weight_denom;
-+ const SliceHeader *sh = &h->sh;
-+
-+ if (sh->slice_type == HEVC_SLICE_I ||
-+ (sh->slice_type == HEVC_SLICE_P && !h->ps.pps->weighted_pred_flag) ||
-+ (sh->slice_type == HEVC_SLICE_B && !h->ps.pps->weighted_bipred_flag))
-+ return;
-+
-+ table->luma_log2_weight_denom = sh->luma_log2_weight_denom;
-+
-+ if (h->ps.sps->chroma_format_idc)
-+ table->delta_chroma_log2_weight_denom = sh->chroma_log2_weight_denom - sh->luma_log2_weight_denom;
-+
-+ luma_weight_denom = (1 << sh->luma_log2_weight_denom);
-+ chroma_weight_denom = (1 << sh->chroma_log2_weight_denom);
-+
-+ for (int i = 0; i < 15 && i < sh->nb_refs[L0]; i++) {
-+ table->delta_luma_weight_l0[i] = sh->luma_weight_l0[i] - luma_weight_denom;
-+ table->luma_offset_l0[i] = sh->luma_offset_l0[i];
-+ table->delta_chroma_weight_l0[i][0] = sh->chroma_weight_l0[i][0] - chroma_weight_denom;
-+ table->delta_chroma_weight_l0[i][1] = sh->chroma_weight_l0[i][1] - chroma_weight_denom;
-+ table->chroma_offset_l0[i][0] = sh->chroma_offset_l0[i][0];
-+ table->chroma_offset_l0[i][1] = sh->chroma_offset_l0[i][1];
-+ }
-+
-+ if (sh->slice_type != HEVC_SLICE_B)
-+ return;
-+
-+ for (int i = 0; i < 15 && i < sh->nb_refs[L1]; i++) {
-+ table->delta_luma_weight_l1[i] = sh->luma_weight_l1[i] - luma_weight_denom;
-+ table->luma_offset_l1[i] = sh->luma_offset_l1[i];
-+ table->delta_chroma_weight_l1[i][0] = sh->chroma_weight_l1[i][0] - chroma_weight_denom;
-+ table->delta_chroma_weight_l1[i][1] = sh->chroma_weight_l1[i][1] - chroma_weight_denom;
-+ table->chroma_offset_l1[i][0] = sh->chroma_offset_l1[i][0];
-+ table->chroma_offset_l1[i][1] = sh->chroma_offset_l1[i][1];
-+ }
-+}
-+
-+static int find_frame_rps_type(const HEVCContext *h, uint64_t timestamp)
-+{
-+ const HEVCFrame *frame;
-+ int i;
-+
-+ for (i = 0; i < h->rps[ST_CURR_BEF].nb_refs; i++) {
-+ frame = h->rps[ST_CURR_BEF].ref[i];
-+ if (frame && timestamp == frame_capture_dpb(frame->frame))
-+ return V4L2_HEVC_DPB_ENTRY_RPS_ST_CURR_BEFORE;
-+ }
-+
-+ for (i = 0; i < h->rps[ST_CURR_AFT].nb_refs; i++) {
-+ frame = h->rps[ST_CURR_AFT].ref[i];
-+ if (frame && timestamp == frame_capture_dpb(frame->frame))
-+ return V4L2_HEVC_DPB_ENTRY_RPS_ST_CURR_AFTER;
-+ }
-+
-+ for (i = 0; i < h->rps[LT_CURR].nb_refs; i++) {
-+ frame = h->rps[LT_CURR].ref[i];
-+ if (frame && timestamp == frame_capture_dpb(frame->frame))
-+ return V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR;
-+ }
-+
-+ return 0;
-+}
-+
-+static unsigned int
-+get_ref_pic_index(const HEVCContext *h, const HEVCFrame *frame,
-+ const struct v4l2_hevc_dpb_entry * const entries,
-+ const unsigned int num_entries)
-+{
-+ uint64_t timestamp;
-+
-+ if (!frame)
-+ return 0;
-+
-+ timestamp = frame_capture_dpb(frame->frame);
-+
-+ for (unsigned int i = 0; i < num_entries; i++) {
-+ if (entries[i].timestamp == timestamp)
-+ return i;
-+ }
-+
-+ return 0;
-+}
-+
-+static const uint8_t * ptr_from_index(const uint8_t * b, unsigned int idx)
-+{
-+ unsigned int z = 0;
-+ while (idx--) {
-+ if (*b++ == 0) {
-+ ++z;
-+ if (z >= 2 && *b == 3) {
-+ ++b;
-+ z = 0;
-+ }
-+ }
-+ else {
-+ z = 0;
-+ }
-+ }
-+ return b;
-+}
-+
-+static int slice_add(V4L2MediaReqDescriptor * const rd)
-+{
-+ if (rd->num_slices >= rd->alloced_slices) {
-+ struct v4l2_ctrl_hevc_slice_params * p2;
-+ struct slice_info * s2;
-+ size_t n2 = rd->num_slices == 0 ? 8 : rd->num_slices * 2;
-+
-+ p2 = av_realloc_array(rd->slice_params, n2, sizeof(*p2));
-+ if (p2 == NULL)
-+ return AVERROR(ENOMEM);
-+ rd->slice_params = p2;
-+
-+ s2 = av_realloc_array(rd->slices, n2, sizeof(*s2));
-+ if (s2 == NULL)
-+ return AVERROR(ENOMEM);
-+ rd->slices = s2;
-+
-+ rd->alloced_slices = n2;
-+ }
-+ ++rd->num_slices;
-+ return 0;
-+}
-+
-+static unsigned int
-+fill_dpb_entries(const HEVCContext * const h, struct v4l2_hevc_dpb_entry * const entries)
-+{
-+ unsigned int i;
-+ unsigned int n = 0;
-+ const HEVCFrame * const pic = h->ref;
-+
-+ for (i = 0; i < FF_ARRAY_ELEMS(h->DPB); i++) {
-+ const HEVCFrame * const frame = &h->DPB[i];
-+ if (frame != pic && (frame->flags & (HEVC_FRAME_FLAG_LONG_REF | HEVC_FRAME_FLAG_SHORT_REF))) {
-+ struct v4l2_hevc_dpb_entry * const entry = entries + n++;
-+
-+ entry->timestamp = frame_capture_dpb(frame->frame);
-+ entry->rps = find_frame_rps_type(h, entry->timestamp);
-+ entry->field_pic = frame->frame->interlaced_frame;
-+
-+ /* TODO: Interleaved: Get the POC for each field. */
-+ entry->pic_order_cnt[0] = frame->poc;
-+ entry->pic_order_cnt[1] = frame->poc;
-+ }
-+ }
-+ return n;
-+}
-+
-+static void fill_slice_params(const HEVCContext * const h,
-+#if HEVC_CTRLS_VERSION >= 2
-+ const struct v4l2_ctrl_hevc_decode_params * const dec,
-+#endif
-+ struct v4l2_ctrl_hevc_slice_params *slice_params,
-+ uint32_t bit_size, uint32_t bit_offset)
-+{
-+ const SliceHeader * const sh = &h->sh;
-+#if HEVC_CTRLS_VERSION >= 2
-+ const struct v4l2_hevc_dpb_entry *const dpb = dec->dpb;
-+ const unsigned int dpb_n = dec->num_active_dpb_entries;
-+#else
-+ struct v4l2_hevc_dpb_entry *const dpb = slice_params->dpb;
-+ unsigned int dpb_n;
-+#endif
-+ unsigned int i;
-+ RefPicList *rpl;
-+
-+ *slice_params = (struct v4l2_ctrl_hevc_slice_params) {
-+ .bit_size = bit_size,
-+ .data_bit_offset = bit_offset,
-+
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
-+ .slice_segment_addr = sh->slice_segment_addr,
-+
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: NAL unit header */
-+ .nal_unit_type = h->nal_unit_type,
-+ .nuh_temporal_id_plus1 = h->temporal_id + 1,
-+
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
-+ .slice_type = sh->slice_type,
-+ .colour_plane_id = sh->colour_plane_id,
-+ .slice_pic_order_cnt = h->ref->poc,
-+ .num_ref_idx_l0_active_minus1 = sh->nb_refs[L0] ? sh->nb_refs[L0] - 1 : 0,
-+ .num_ref_idx_l1_active_minus1 = sh->nb_refs[L1] ? sh->nb_refs[L1] - 1 : 0,
-+ .collocated_ref_idx = sh->slice_temporal_mvp_enabled_flag ? sh->collocated_ref_idx : 0,
-+ .five_minus_max_num_merge_cand = sh->slice_type == HEVC_SLICE_I ? 0 : 5 - sh->max_num_merge_cand,
-+ .slice_qp_delta = sh->slice_qp_delta,
-+ .slice_cb_qp_offset = sh->slice_cb_qp_offset,
-+ .slice_cr_qp_offset = sh->slice_cr_qp_offset,
-+ .slice_act_y_qp_offset = 0,
-+ .slice_act_cb_qp_offset = 0,
-+ .slice_act_cr_qp_offset = 0,
-+ .slice_beta_offset_div2 = sh->beta_offset / 2,
-+ .slice_tc_offset_div2 = sh->tc_offset / 2,
-+
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture timing SEI message */
-+ .pic_struct = h->sei.picture_timing.picture_struct,
-+
-+#if HEVC_CTRLS_VERSION < 2
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
-+ .num_rps_poc_st_curr_before = h->rps[ST_CURR_BEF].nb_refs,
-+ .num_rps_poc_st_curr_after = h->rps[ST_CURR_AFT].nb_refs,
-+ .num_rps_poc_lt_curr = h->rps[LT_CURR].nb_refs,
-+#endif
-+ };
-+
-+ if (sh->slice_sample_adaptive_offset_flag[0])
-+ slice_params->flags |= V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA;
-+
-+ if (sh->slice_sample_adaptive_offset_flag[1])
-+ slice_params->flags |= V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA;
-+
-+ if (sh->slice_temporal_mvp_enabled_flag)
-+ slice_params->flags |= V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED;
-+
-+ if (sh->mvd_l1_zero_flag)
-+ slice_params->flags |= V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO;
-+
-+ if (sh->cabac_init_flag)
-+ slice_params->flags |= V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT;
-+
-+ if (sh->collocated_list == L0)
-+ slice_params->flags |= V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0;
-+
-+ if (sh->disable_deblocking_filter_flag)
-+ slice_params->flags |= V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED;
-+
-+ if (sh->slice_loop_filter_across_slices_enabled_flag)
-+ slice_params->flags |= V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED;
-+
-+ if (sh->dependent_slice_segment_flag)
-+ slice_params->flags |= V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT;
-+
-+#if HEVC_CTRLS_VERSION < 2
-+ dpb_n = fill_dpb_entries(h, dpb);
-+ slice_params->num_active_dpb_entries = dpb_n;
-+#endif
-+
-+ if (sh->slice_type != HEVC_SLICE_I) {
-+ rpl = &h->ref->refPicList[0];
-+ for (i = 0; i < rpl->nb_refs; i++)
-+ slice_params->ref_idx_l0[i] = get_ref_pic_index(h, rpl->ref[i], dpb, dpb_n);
-+ }
-+
-+ if (sh->slice_type == HEVC_SLICE_B) {
-+ rpl = &h->ref->refPicList[1];
-+ for (i = 0; i < rpl->nb_refs; i++)
-+ slice_params->ref_idx_l1[i] = get_ref_pic_index(h, rpl->ref[i], dpb, dpb_n);
-+ }
-+
-+ fill_pred_table(h, &slice_params->pred_weight_table);
-+
-+ slice_params->num_entry_point_offsets = sh->num_entry_point_offsets;
-+ if (slice_params->num_entry_point_offsets > 256) {
-+ slice_params->num_entry_point_offsets = 256;
-+ av_log(NULL, AV_LOG_ERROR, "%s: Currently only 256 entry points are supported, but slice has %d entry points.\n", __func__, sh->num_entry_point_offsets);
-+ }
-+
-+ for (i = 0; i < slice_params->num_entry_point_offsets; i++)
-+ slice_params->entry_point_offset_minus1[i] = sh->entry_point_offset[i] - 1;
-+}
-+
-+#if HEVC_CTRLS_VERSION >= 2
-+static void
-+fill_decode_params(const HEVCContext * const h,
-+ struct v4l2_ctrl_hevc_decode_params * const dec)
-+{
-+ unsigned int i;
-+
-+ *dec = (struct v4l2_ctrl_hevc_decode_params){
-+ .pic_order_cnt_val = h->poc,
-+ .num_poc_st_curr_before = h->rps[ST_CURR_BEF].nb_refs,
-+ .num_poc_st_curr_after = h->rps[ST_CURR_AFT].nb_refs,
-+ .num_poc_lt_curr = h->rps[LT_CURR].nb_refs,
-+ };
-+
-+ dec->num_active_dpb_entries = fill_dpb_entries(h, dec->dpb);
-+
-+ // The docn does seem to ask that we fit our 32 bit signed POC into
-+ // a U8 so... (To be fair 16 bits would be enough)
-+ // Luckily we (Pi) don't use these fields
-+ for (i = 0; i != h->rps[ST_CURR_BEF].nb_refs; ++i)
-+ dec->poc_st_curr_before[i] = h->rps[ST_CURR_BEF].ref[i]->poc;
-+ for (i = 0; i != h->rps[ST_CURR_AFT].nb_refs; ++i)
-+ dec->poc_st_curr_after[i] = h->rps[ST_CURR_AFT].ref[i]->poc;
-+ for (i = 0; i != h->rps[LT_CURR].nb_refs; ++i)
-+ dec->poc_lt_curr[i] = h->rps[LT_CURR].ref[i]->poc;
-+
-+ if (IS_IRAP(h))
-+ dec->flags |= V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC;
-+ if (IS_IDR(h))
-+ dec->flags |= V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC;
-+ if (h->sh.no_output_of_prior_pics_flag)
-+ dec->flags |= V4L2_HEVC_DECODE_PARAM_FLAG_NO_OUTPUT_OF_PRIOR;
-+
-+}
-+#endif
-+
-+static void fill_sps(struct v4l2_ctrl_hevc_sps *ctrl, const HEVCSPS *sps)
-+{
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: Sequence parameter set */
-+ *ctrl = (struct v4l2_ctrl_hevc_sps) {
-+ .chroma_format_idc = sps->chroma_format_idc,
-+ .pic_width_in_luma_samples = sps->width,
-+ .pic_height_in_luma_samples = sps->height,
-+ .bit_depth_luma_minus8 = sps->bit_depth - 8,
-+ .bit_depth_chroma_minus8 = sps->bit_depth - 8,
-+ .log2_max_pic_order_cnt_lsb_minus4 = sps->log2_max_poc_lsb - 4,
-+ .sps_max_dec_pic_buffering_minus1 = sps->temporal_layer[sps->max_sub_layers - 1].max_dec_pic_buffering - 1,
-+ .sps_max_num_reorder_pics = sps->temporal_layer[sps->max_sub_layers - 1].num_reorder_pics,
-+ .sps_max_latency_increase_plus1 = sps->temporal_layer[sps->max_sub_layers - 1].max_latency_increase + 1,
-+ .log2_min_luma_coding_block_size_minus3 = sps->log2_min_cb_size - 3,
-+ .log2_diff_max_min_luma_coding_block_size = sps->log2_diff_max_min_coding_block_size,
-+ .log2_min_luma_transform_block_size_minus2 = sps->log2_min_tb_size - 2,
-+ .log2_diff_max_min_luma_transform_block_size = sps->log2_max_trafo_size - sps->log2_min_tb_size,
-+ .max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter,
-+ .max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra,
-+ .pcm_sample_bit_depth_luma_minus1 = sps->pcm.bit_depth - 1,
-+ .pcm_sample_bit_depth_chroma_minus1 = sps->pcm.bit_depth_chroma - 1,
-+ .log2_min_pcm_luma_coding_block_size_minus3 = sps->pcm.log2_min_pcm_cb_size - 3,
-+ .log2_diff_max_min_pcm_luma_coding_block_size = sps->pcm.log2_max_pcm_cb_size - sps->pcm.log2_min_pcm_cb_size,
-+ .num_short_term_ref_pic_sets = sps->nb_st_rps,
-+ .num_long_term_ref_pics_sps = sps->num_long_term_ref_pics_sps,
-+ .chroma_format_idc = sps->chroma_format_idc,
-+ .sps_max_sub_layers_minus1 = sps->max_sub_layers - 1,
-+ };
-+
-+ if (sps->separate_colour_plane_flag)
-+ ctrl->flags |= V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE;
-+
-+ if (sps->scaling_list_enable_flag)
-+ ctrl->flags |= V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED;
-+
-+ if (sps->amp_enabled_flag)
-+ ctrl->flags |= V4L2_HEVC_SPS_FLAG_AMP_ENABLED;
-+
-+ if (sps->sao_enabled)
-+ ctrl->flags |= V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET;
-+
-+ if (sps->pcm_enabled_flag)
-+ ctrl->flags |= V4L2_HEVC_SPS_FLAG_PCM_ENABLED;
-+
-+ if (sps->pcm.loop_filter_disable_flag)
-+ ctrl->flags |= V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED;
-+
-+ if (sps->long_term_ref_pics_present_flag)
-+ ctrl->flags |= V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT;
-+
-+ if (sps->sps_temporal_mvp_enabled_flag)
-+ ctrl->flags |= V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED;
-+
-+ if (sps->sps_strong_intra_smoothing_enable_flag)
-+ ctrl->flags |= V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED;
-+}
-+
-+static void fill_scaling_matrix(const ScalingList * const sl,
-+ struct v4l2_ctrl_hevc_scaling_matrix * const sm)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < 6; i++) {
-+ unsigned int j;
-+
-+ for (j = 0; j < 16; j++)
-+ sm->scaling_list_4x4[i][j] = sl->sl[0][i][j];
-+ for (j = 0; j < 64; j++) {
-+ sm->scaling_list_8x8[i][j] = sl->sl[1][i][j];
-+ sm->scaling_list_16x16[i][j] = sl->sl[2][i][j];
-+ if (i < 2)
-+ sm->scaling_list_32x32[i][j] = sl->sl[3][i * 3][j];
-+ }
-+ sm->scaling_list_dc_coef_16x16[i] = sl->sl_dc[0][i];
-+ if (i < 2)
-+ sm->scaling_list_dc_coef_32x32[i] = sl->sl_dc[1][i * 3];
-+ }
-+}
-+
-+static void fill_pps(struct v4l2_ctrl_hevc_pps * const ctrl, const HEVCPPS * const pps)
-+{
-+ uint64_t flags = 0;
-+
-+ if (pps->dependent_slice_segments_enabled_flag)
-+ flags |= V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED;
-+
-+ if (pps->output_flag_present_flag)
-+ flags |= V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT;
-+
-+ if (pps->sign_data_hiding_flag)
-+ flags |= V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED;
-+
-+ if (pps->cabac_init_present_flag)
-+ flags |= V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT;
-+
-+ if (pps->constrained_intra_pred_flag)
-+ flags |= V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED;
-+
-+ if (pps->transform_skip_enabled_flag)
-+ flags |= V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED;
-+
-+ if (pps->cu_qp_delta_enabled_flag)
-+ flags |= V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED;
-+
-+ if (pps->pic_slice_level_chroma_qp_offsets_present_flag)
-+ flags |= V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT;
-+
-+ if (pps->weighted_pred_flag)
-+ flags |= V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED;
-+
-+ if (pps->weighted_bipred_flag)
-+ flags |= V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED;
-+
-+ if (pps->transquant_bypass_enable_flag)
-+ flags |= V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED;
-+
-+ if (pps->tiles_enabled_flag)
-+ flags |= V4L2_HEVC_PPS_FLAG_TILES_ENABLED;
-+
-+ if (pps->entropy_coding_sync_enabled_flag)
-+ flags |= V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED;
-+
-+ if (pps->loop_filter_across_tiles_enabled_flag)
-+ flags |= V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED;
-+
-+ if (pps->seq_loop_filter_across_slices_enabled_flag)
-+ flags |= V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED;
-+
-+ if (pps->deblocking_filter_override_enabled_flag)
-+ flags |= V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED;
-+
-+ if (pps->disable_dbf)
-+ flags |= V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER;
-+
-+ if (pps->lists_modification_present_flag)
-+ flags |= V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT;
-+
-+ if (pps->slice_header_extension_present_flag)
-+ flags |= V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT;
-+
-+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture parameter set */
-+ *ctrl = (struct v4l2_ctrl_hevc_pps) {
-+ .num_extra_slice_header_bits = pps->num_extra_slice_header_bits,
-+ .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,
-+ .flags = flags
-+ };
-+
-+
-+ if (pps->tiles_enabled_flag) {
-+ ctrl->num_tile_columns_minus1 = pps->num_tile_columns - 1;
-+ ctrl->num_tile_rows_minus1 = pps->num_tile_rows - 1;
-+
-+ for (int i = 0; i < pps->num_tile_columns; i++)
-+ ctrl->column_width_minus1[i] = pps->column_width[i] - 1;
-+
-+ for (int i = 0; i < pps->num_tile_rows; i++)
-+ ctrl->row_height_minus1[i] = pps->row_height[i] - 1;
-+ }
-+}
-+
-+// Called before finally returning the frame to the user
-+// Set corrupt flag here as this is actually the frame structure that
-+// is going to the user (in MT land each thread has its own pool)
-+static int frame_post_process(void *logctx, AVFrame *frame)
-+{
-+ V4L2MediaReqDescriptor *rd = (V4L2MediaReqDescriptor*)frame->data[0];
-+
-+// av_log(NULL, AV_LOG_INFO, "%s\n", __func__);
-+ frame->flags &= ~AV_FRAME_FLAG_CORRUPT;
-+ if (rd->qe_dst) {
-+ MediaBufsStatus stat = qent_dst_wait(rd->qe_dst);
-+ if (stat != MEDIABUFS_STATUS_SUCCESS) {
-+ av_log(logctx, AV_LOG_ERROR, "%s: Decode fail\n", __func__);
-+ frame->flags |= AV_FRAME_FLAG_CORRUPT;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static inline struct timeval cvt_dpb_to_tv(uint64_t t)
-+{
-+ t /= 1000;
-+ return (struct timeval){
-+ .tv_usec = t % 1000000,
-+ .tv_sec = t / 1000000
-+ };
-+}
-+
-+static inline uint64_t cvt_timestamp_to_dpb(const unsigned int t)
-+{
-+ return (uint64_t)t * 1000;
-+}
-+
-+static int v4l2_request_hevc_start_frame(AVCodecContext *avctx,
-+ av_unused const uint8_t *buffer,
-+ av_unused uint32_t size)
-+{
-+ const HEVCContext *h = avctx->priv_data;
-+ V4L2MediaReqDescriptor *const rd = (V4L2MediaReqDescriptor *)h->ref->frame->data[0];
-+ V4L2RequestContextHEVC * const ctx = avctx->internal->hwaccel_priv_data;
-+
-+// av_log(NULL, AV_LOG_INFO, "%s\n", __func__);
-+ decode_q_add(&ctx->decode_q, &rd->decode_ent);
-+
-+ rd->num_slices = 0;
-+ ctx->timestamp++;
-+ rd->timestamp = cvt_timestamp_to_dpb(ctx->timestamp);
-+
-+ {
-+ FrameDecodeData * const fdd = (FrameDecodeData*)h->ref->frame->private_ref->data;
-+ fdd->post_process = frame_post_process;
-+ }
-+
-+ // qe_dst needs to be bound to the data buffer and only returned when that is
-+ if (!rd->qe_dst)
-+ {
-+ if ((rd->qe_dst = mediabufs_dst_qent_alloc(ctx->mbufs, ctx->dbufs)) == NULL) {
-+ av_log(avctx, AV_LOG_ERROR, "%s: Failed to get dst buffer\n", __func__);
-+ return AVERROR(ENOMEM);
-+ }
-+ }
-+
-+ ff_thread_finish_setup(avctx); // Allow next thread to enter rpi_hevc_start_frame
-+
-+ return 0;
-+}
-+
-+// Object fd & size will be zapped by this & need setting later
-+static int drm_from_format(AVDRMFrameDescriptor * const desc, const struct v4l2_format * const format)
-+{
-+ AVDRMLayerDescriptor *layer = &desc->layers[0];
-+ unsigned int width;
-+ unsigned int height;
-+ unsigned int bpl;
-+ uint32_t pixelformat;
-+
-+ if (V4L2_TYPE_IS_MULTIPLANAR(format->type)) {
-+ width = format->fmt.pix_mp.width;
-+ height = format->fmt.pix_mp.height;
-+ pixelformat = format->fmt.pix_mp.pixelformat;
-+ bpl = format->fmt.pix_mp.plane_fmt[0].bytesperline;
-+ }
-+ else {
-+ width = format->fmt.pix.width;
-+ height = format->fmt.pix.height;
-+ pixelformat = format->fmt.pix.pixelformat;
-+ bpl = format->fmt.pix.bytesperline;
-+ }
-+
-+ switch (pixelformat) {
-+ case V4L2_PIX_FMT_NV12:
-+ layer->format = DRM_FORMAT_NV12;
-+ desc->objects[0].format_modifier = DRM_FORMAT_MOD_LINEAR;
-+ break;
-+#if CONFIG_SAND
-+ case V4L2_PIX_FMT_NV12_COL128:
-+ layer->format = DRM_FORMAT_NV12;
-+ desc->objects[0].format_modifier = DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT(bpl);
-+ break;
-+ case V4L2_PIX_FMT_NV12_10_COL128:
-+ layer->format = DRM_FORMAT_P030;
-+ desc->objects[0].format_modifier = DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT(bpl);
-+ break;
-+#endif
-+#ifdef DRM_FORMAT_MOD_ALLWINNER_TILED
-+ case V4L2_PIX_FMT_SUNXI_TILED_NV12:
-+ layer->format = DRM_FORMAT_NV12;
-+ desc->objects[0].format_modifier = DRM_FORMAT_MOD_ALLWINNER_TILED;
-+ break;
-+#endif
-+#if defined(V4L2_PIX_FMT_NV15) && defined(DRM_FORMAT_NV15)
-+ case V4L2_PIX_FMT_NV15:
-+ layer->format = DRM_FORMAT_NV15;
-+ desc->objects[0].format_modifier = DRM_FORMAT_MOD_LINEAR;
-+ break;
-+#endif
-+ case V4L2_PIX_FMT_NV16:
-+ layer->format = DRM_FORMAT_NV16;
-+ desc->objects[0].format_modifier = DRM_FORMAT_MOD_LINEAR;
-+ break;
-+#if defined(V4L2_PIX_FMT_NV20) && defined(DRM_FORMAT_NV20)
-+ case V4L2_PIX_FMT_NV20:
-+ layer->format = DRM_FORMAT_NV20;
-+ desc->objects[0].format_modifier = DRM_FORMAT_MOD_LINEAR;
-+ break;
-+#endif
-+ default:
-+ return -1;
-+ }
-+
-+ desc->nb_objects = 1;
-+ desc->objects[0].fd = -1;
-+ desc->objects[0].size = 0;
-+
-+ desc->nb_layers = 1;
-+ layer->nb_planes = 2;
-+
-+ layer->planes[0].object_index = 0;
-+ layer->planes[0].offset = 0;
-+ layer->planes[0].pitch = bpl;
-+#if CONFIG_SAND
-+ if (pixelformat == V4L2_PIX_FMT_NV12_COL128) {
-+ layer->planes[1].object_index = 0;
-+ layer->planes[1].offset = height * 128;
-+ layer->planes[0].pitch = width;
-+ layer->planes[1].pitch = width;
-+ }
-+ else if (pixelformat == V4L2_PIX_FMT_NV12_10_COL128) {
-+ layer->planes[1].object_index = 0;
-+ layer->planes[1].offset = height * 128;
-+ layer->planes[0].pitch = width * 2; // Lies but it keeps DRM import happy
-+ layer->planes[1].pitch = width * 2;
-+ }
-+ else
-+#endif
-+ {
-+ layer->planes[1].object_index = 0;
-+ layer->planes[1].offset = layer->planes[0].pitch * height;
-+ layer->planes[1].pitch = layer->planes[0].pitch;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+set_req_ctls(V4L2RequestContextHEVC *ctx, struct media_request * const mreq,
-+ struct req_controls *const controls,
-+#if HEVC_CTRLS_VERSION >= 2
-+ struct v4l2_ctrl_hevc_decode_params * const dec,
-+#endif
-+ struct v4l2_ctrl_hevc_slice_params * const slices,
-+ const unsigned int slice_no,
-+ const unsigned int slice_count)
-+{
-+ int rv;
-+
-+ struct v4l2_ext_control control[] = {
-+ {
-+ .id = V4L2_CID_MPEG_VIDEO_HEVC_SPS,
-+ .ptr = &controls->sps,
-+ .size = sizeof(controls->sps),
-+ },
-+ {
-+ .id = V4L2_CID_MPEG_VIDEO_HEVC_PPS,
-+ .ptr = &controls->pps,
-+ .size = sizeof(controls->pps),
-+ },
-+#if HEVC_CTRLS_VERSION >= 2
-+ {
-+ .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS,
-+ .ptr = dec,
-+ .size = sizeof(*dec),
-+ },
-+#endif
-+ {
-+ .id = V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS,
-+ .ptr = slices + slice_no,
-+ .size = sizeof(*slices) * slice_count,
-+ },
-+ // Optional
-+ {
-+ .id = V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX,
-+ .ptr = &controls->scaling_matrix,
-+ .size = sizeof(controls->scaling_matrix),
-+ },
-+ };
-+
-+ rv = mediabufs_ctl_set_ext_ctrls(ctx->mbufs, mreq, control,
-+ controls->has_scaling ?
-+ FF_ARRAY_ELEMS(control) :
-+ FF_ARRAY_ELEMS(control) - 1);
-+
-+ return rv;
-+}
-+
-+static int v4l2_request_hevc_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)
-+{
-+ const HEVCContext * const h = avctx->priv_data;
-+ V4L2RequestContextHEVC * const ctx = avctx->internal->hwaccel_priv_data;
-+ V4L2MediaReqDescriptor * const rd = (V4L2MediaReqDescriptor*)h->ref->frame->data[0];
-+ int bcount = get_bits_count(&h->HEVClc->gb);
-+ uint32_t boff = (ptr_from_index(buffer, bcount/8 + 1) - (buffer + bcount/8 + 1)) * 8 + bcount;
-+
-+ int rv;
-+ struct slice_info * si;
-+
-+ if ((rv = slice_add(rd)) != 0)
-+ return rv;
-+
-+ si = rd->slices + rd->num_slices - 1;
-+ si->ptr = buffer;
-+ si->len = size;
-+
-+ if (ctx->multi_slice && rd->num_slices > 1) {
-+ struct slice_info *const si0 = rd->slices;
-+ const size_t offset = (buffer - si0->ptr);
-+ boff += offset * 8;
-+ size += offset;
-+ si0->len = si->len + offset;
-+ }
-+
-+#if HEVC_CTRLS_VERSION >= 2
-+ if (rd->num_slices == 1)
-+ fill_decode_params(h, &rd->dec);
-+ fill_slice_params(h, &rd->dec, rd->slice_params + rd->num_slices - 1, size * 8, boff);
-+#else
-+ fill_slice_params(h, rd->slice_params + rd->num_slices - 1, size * 8, boff);
-+#endif
-+
-+ return 0;
-+}
-+
-+static void v4l2_request_hevc_abort_frame(AVCodecContext * const avctx)
-+{
-+ const HEVCContext * const h = avctx->priv_data;
-+ if (h->ref != NULL) {
-+ V4L2MediaReqDescriptor *const rd = (V4L2MediaReqDescriptor *)h->ref->frame->data[0];
-+ V4L2RequestContextHEVC * const ctx = avctx->internal->hwaccel_priv_data;
-+
-+ media_request_abort(&rd->req);
-+ mediabufs_src_qent_abort(ctx->mbufs, &rd->qe_src);
-+
-+ decode_q_remove(&ctx->decode_q, &rd->decode_ent);
-+ }
-+}
-+
-+static int send_slice(AVCodecContext * const avctx,
-+ V4L2MediaReqDescriptor * const rd,
-+ struct req_controls *const controls,
-+ const unsigned int i, const unsigned int j)
-+{
-+ V4L2RequestContextHEVC * const ctx = avctx->internal->hwaccel_priv_data;
-+
-+ struct slice_info *const si = rd->slices + i;
-+ struct media_request * req = NULL;
-+ struct qent_src * src = NULL;
-+ MediaBufsStatus stat;
-+
-+ if ((req = media_request_get(ctx->mpool)) == NULL) {
-+ av_log(avctx, AV_LOG_ERROR, "%s: Failed to alloc media request\n", __func__);
-+ return AVERROR(ENOMEM);
-+ }
-+
-+ if (set_req_ctls(ctx, req,
-+ controls,
-+#if HEVC_CTRLS_VERSION >= 2
-+ &rd->dec,
-+#endif
-+ rd->slice_params,
-+ i, j - i)) {
-+ av_log(avctx, AV_LOG_ERROR, "%s: Failed to set req ctls\n", __func__);
-+ goto fail1;
-+ }
-+
-+ if ((src = mediabufs_src_qent_get(ctx->mbufs)) == NULL) {
-+ av_log(avctx, AV_LOG_ERROR, "%s: Failed to get src buffer\n", __func__);
-+ goto fail1;
-+ }
-+
-+ if (qent_src_data_copy(src, 0, si->ptr, si->len, ctx->dbufs) != 0) {
-+ av_log(avctx, AV_LOG_ERROR, "%s: Failed data copy\n", __func__);
-+ goto fail2;
-+ }
-+
-+ if (qent_src_params_set(src, &controls->tv)) {
-+ av_log(avctx, AV_LOG_ERROR, "%s: Failed src param set\n", __func__);
-+ goto fail2;
-+ }
-+
-+#warning ANNEX_B start code
-+// if (ctx->start_code == V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B) {
-+// }
-+
-+ stat = mediabufs_start_request(ctx->mbufs, &req, &src,
-+ i == 0 ? rd->qe_dst : NULL,
-+ j == rd->num_slices);
-+
-+ if (stat != MEDIABUFS_STATUS_SUCCESS) {
-+ av_log(avctx, AV_LOG_ERROR, "%s: Failed to start request\n", __func__);
-+ return AVERROR_UNKNOWN;
-+ }
-+ return 0;
-+
-+fail2:
-+ mediabufs_src_qent_abort(ctx->mbufs, &src);
-+fail1:
-+ media_request_abort(&req);
-+ return AVERROR_UNKNOWN;
-+}
-+
-+static int v4l2_request_hevc_end_frame(AVCodecContext *avctx)
-+{
-+ const HEVCContext * const h = avctx->priv_data;
-+ V4L2MediaReqDescriptor *rd = (V4L2MediaReqDescriptor*)h->ref->frame->data[0];
-+ V4L2RequestContextHEVC *ctx = avctx->internal->hwaccel_priv_data;
-+ struct req_controls rc;
-+ unsigned int i;
-+ int rv;
-+
-+ // It is possible, though maybe a bug, to get an end_frame without
-+ // a previous start_frame. If we do then give up.
-+ if (!decode_q_in_q(&rd->decode_ent)) {
-+ av_log(avctx, AV_LOG_DEBUG, "%s: Frame not in decode Q\n", __func__);
-+ return AVERROR_INVALIDDATA;
-+ }
-+
-+ {
-+ const ScalingList *sl = h->ps.pps->scaling_list_data_present_flag ?
-+ &h->ps.pps->scaling_list :
-+ h->ps.sps->scaling_list_enable_flag ?
-+ &h->ps.sps->scaling_list : NULL;
-+
-+
-+ memset(&rc, 0, sizeof(rc));
-+ rc.tv = cvt_dpb_to_tv(rd->timestamp);
-+ fill_sps(&rc.sps, h->ps.sps);
-+ fill_pps(&rc.pps, h->ps.pps);
-+ if (sl) {
-+ rc.has_scaling = 1;
-+ fill_scaling_matrix(sl, &rc.scaling_matrix);
-+ }
-+ }
-+
-+ decode_q_wait(&ctx->decode_q, &rd->decode_ent);
-+
-+ // qe_dst needs to be bound to the data buffer and only returned when that is
-+ // Alloc almost certainly wants to be serialised if there is any chance of blocking
-+ // so we get the next frame to be free in the thread that needs it for decode first.
-+ //
-+ // In our current world this probably isn't a concern but put it here anyway
-+ if (!rd->qe_dst)
-+ {
-+ if ((rd->qe_dst = mediabufs_dst_qent_alloc(ctx->mbufs, ctx->dbufs)) == NULL) {
-+ av_log(avctx, AV_LOG_ERROR, "%s: Failed to get dst buffer\n", __func__);
-+ rv = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+ }
-+
-+ // Send as slices
-+ if (ctx->multi_slice)
-+ {
-+ if ((rv = send_slice(avctx, rd, &rc, 0, rd->num_slices)) != 0)
-+ goto fail;
-+ }
-+ else
-+ {
-+ for (i = 0; i != rd->num_slices; ++i) {
-+ if ((rv = send_slice(avctx, rd, &rc, i, i + 1)) != 0)
-+ goto fail;
-+ }
-+ }
-+
-+ // Set the drm_prime desriptor
-+ drm_from_format(&rd->drm, mediabufs_dst_fmt(ctx->mbufs));
-+ rd->drm.objects[0].fd = dmabuf_fd(qent_dst_dmabuf(rd->qe_dst, 0));
-+ rd->drm.objects[0].size = dmabuf_size(qent_dst_dmabuf(rd->qe_dst, 0));
-+
-+ decode_q_remove(&ctx->decode_q, &rd->decode_ent);
-+ return 0;
-+
-+fail:
-+ decode_q_remove(&ctx->decode_q, &rd->decode_ent);
-+ return rv;
-+}
-+
-+// Initial check & init
-+static int
-+probe(AVCodecContext * const avctx, V4L2RequestContextHEVC * const ctx)
-+{
-+ const HEVCContext *h = avctx->priv_data;
-+ const HEVCSPS * const sps = h->ps.sps;
-+ struct v4l2_ctrl_hevc_sps ctrl_sps;
-+ unsigned int i;
-+
-+ // Check for var slice array
-+ struct v4l2_query_ext_ctrl qc[] = {
-+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS },
-+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_SPS },
-+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_PPS },
-+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX },
-+#if HEVC_CTRLS_VERSION >= 2
-+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS },
-+#endif
-+ };
-+ // Order & size must match!
-+ static const size_t ctrl_sizes[] = {
-+ sizeof(struct v4l2_ctrl_hevc_slice_params),
-+ sizeof(struct v4l2_ctrl_hevc_sps),
-+ sizeof(struct v4l2_ctrl_hevc_pps),
-+ sizeof(struct v4l2_ctrl_hevc_scaling_matrix),
-+#if HEVC_CTRLS_VERSION >= 2
-+ sizeof(struct v4l2_ctrl_hevc_decode_params),
-+#endif
-+ };
-+ const unsigned int noof_ctrls = FF_ARRAY_ELEMS(qc);
-+
-+ if (mediabufs_ctl_query_ext_ctrls(ctx->mbufs, qc, noof_ctrls)) {
-+ av_log(avctx, AV_LOG_DEBUG, "Probed V%d control missing\n", HEVC_CTRLS_VERSION);
-+ return AVERROR(EINVAL);
-+ }
-+ for (i = 0; i != noof_ctrls; ++i) {
-+ if (ctrl_sizes[i] != (size_t)qc[i].elem_size) {
-+ av_log(avctx, AV_LOG_DEBUG, "Probed V%d control %d size mismatch %zu != %zu\n",
-+ HEVC_CTRLS_VERSION, i, ctrl_sizes[i], (size_t)qc[i].elem_size);
-+ return AVERROR(EINVAL);
-+ }
-+ }
-+
-+ fill_sps(&ctrl_sps, sps);
-+
-+ if (mediabufs_set_ext_ctrl(ctx->mbufs, NULL, V4L2_CID_MPEG_VIDEO_HEVC_SPS, &ctrl_sps, sizeof(ctrl_sps))) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to set initial SPS\n");
-+ return AVERROR(EINVAL);
-+ }
-+
-+ ctx->multi_slice = (qc[0].flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY) != 0;
-+ return 0;
-+}
-+
-+// Final init
-+static int
-+set_controls(AVCodecContext * const avctx, V4L2RequestContextHEVC * const ctx)
-+{
-+ int ret;
-+
-+ struct v4l2_query_ext_ctrl querys[] = {
-+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE, },
-+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_START_CODE, },
-+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS, },
-+ };
-+
-+ struct v4l2_ext_control ctrls[] = {
-+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE, },
-+ { .id = V4L2_CID_MPEG_VIDEO_HEVC_START_CODE, },
-+ };
-+
-+ mediabufs_ctl_query_ext_ctrls(ctx->mbufs, querys, FF_ARRAY_ELEMS(querys));
-+
-+ ctx->decode_mode = querys[0].default_value;
-+
-+ if (ctx->decode_mode != V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED &&
-+ ctx->decode_mode != V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED) {
-+ av_log(avctx, AV_LOG_ERROR, "%s: unsupported decode mode, %d\n", __func__, ctx->decode_mode);
-+ return AVERROR(EINVAL);
-+ }
-+
-+ ctx->start_code = querys[1].default_value;
-+ if (ctx->start_code != V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE &&
-+ ctx->start_code != V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B) {
-+ av_log(avctx, AV_LOG_ERROR, "%s: unsupported start code, %d\n", __func__, ctx->start_code);
-+ return AVERROR(EINVAL);
-+ }
-+
-+ ctx->max_slices = querys[2].elems;
-+ if (ctx->max_slices > MAX_SLICES) {
-+ av_log(avctx, AV_LOG_ERROR, "%s: unsupported max slices, %d\n", __func__, ctx->max_slices);
-+ return AVERROR(EINVAL);
-+ }
-+
-+ ctrls[0].value = ctx->decode_mode;
-+ ctrls[1].value = ctx->start_code;
-+
-+ ret = mediabufs_ctl_set_ext_ctrls(ctx->mbufs, NULL, ctrls, FF_ARRAY_ELEMS(ctrls));
-+ return !ret ? 0 : AVERROR(-ret);
-+}
-+
-+static void v4l2_req_frame_free(void *opaque, uint8_t *data)
-+{
-+ AVCodecContext *avctx = opaque;
-+ V4L2MediaReqDescriptor * const rd = (V4L2MediaReqDescriptor*)data;
-+
-+ av_log(NULL, AV_LOG_DEBUG, "%s: avctx=%p data=%p\n", __func__, avctx, data);
-+
-+ qent_dst_unref(&rd->qe_dst);
-+
-+ // We don't expect req or qe_src to be set
-+ if (rd->req || rd->qe_src)
-+ av_log(NULL, AV_LOG_ERROR, "%s: qe_src %p or req %p not NULL\n", __func__, rd->req, rd->qe_src);
-+
-+ av_freep(&rd->slices);
-+ av_freep(&rd->slice_params);
-+
-+ av_free(rd);
-+}
-+
-+static AVBufferRef *v4l2_req_frame_alloc(void *opaque, int size)
-+{
-+ AVCodecContext *avctx = opaque;
-+// V4L2RequestContextHEVC *ctx = avctx->internal->hwaccel_priv_data;
-+// V4L2MediaReqDescriptor *req;
-+ AVBufferRef *ref;
-+ uint8_t *data;
-+// int ret;
-+
-+ data = av_mallocz(size);
-+ if (!data)
-+ return NULL;
-+
-+ av_log(avctx, AV_LOG_DEBUG, "%s: avctx=%p size=%d data=%p\n", __func__, avctx, size, data);
-+ ref = av_buffer_create(data, size, v4l2_req_frame_free, avctx, 0);
-+ if (!ref) {
-+ av_freep(&data);
-+ return NULL;
-+ }
-+ return ref;
-+}
-+
-+#if 0
-+static void v4l2_req_pool_free(void *opaque)
-+{
-+ av_log(NULL, AV_LOG_DEBUG, "%s: opaque=%p\n", __func__, opaque);
-+}
-+
-+static void v4l2_req_hwframe_ctx_free(AVHWFramesContext *hwfc)
-+{
-+ av_log(NULL, AV_LOG_DEBUG, "%s: hwfc=%p pool=%p\n", __func__, hwfc, hwfc->pool);
-+
-+ av_buffer_pool_uninit(&hwfc->pool);
-+}
-+#endif
-+
-+static int frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx)
-+{
-+ V4L2RequestContextHEVC *ctx = avctx->internal->hwaccel_priv_data;
-+ AVHWFramesContext *hwfc = (AVHWFramesContext*)hw_frames_ctx->data;
-+ const struct v4l2_format *vfmt = mediabufs_dst_fmt(ctx->mbufs);
-+
-+ hwfc->format = AV_PIX_FMT_DRM_PRIME;
-+ hwfc->sw_format = pixel_format_from_format(vfmt);
-+ if (V4L2_TYPE_IS_MULTIPLANAR(vfmt->type)) {
-+ hwfc->width = vfmt->fmt.pix_mp.width;
-+ hwfc->height = vfmt->fmt.pix_mp.height;
-+ } else {
-+ hwfc->width = vfmt->fmt.pix.width;
-+ hwfc->height = vfmt->fmt.pix.height;
-+ }
-+#if 0
-+ hwfc->pool = av_buffer_pool_init2(sizeof(V4L2MediaReqDescriptor), avctx, v4l2_req_frame_alloc, v4l2_req_pool_free);
-+ if (!hwfc->pool)
-+ return AVERROR(ENOMEM);
-+
-+ hwfc->free = v4l2_req_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;
-+ }
-+#endif
-+ av_log(avctx, AV_LOG_DEBUG, "%s: avctx=%p ctx=%p hw_frames_ctx=%p hwfc=%p pool=%p width=%d height=%d initial_pool_size=%d\n", __func__, avctx, ctx, hw_frames_ctx, hwfc, hwfc->pool, hwfc->width, hwfc->height, hwfc->initial_pool_size);
-+
-+ return 0;
-+}
-+
-+static int alloc_frame(AVCodecContext * avctx, AVFrame *frame)
-+{
-+ int rv;
-+
-+ frame->buf[0] = v4l2_req_frame_alloc(avctx, sizeof(V4L2MediaReqDescriptor));
-+ if (!frame->buf[0])
-+ return AVERROR(ENOMEM);
-+
-+ frame->data[0] = frame->buf[0]->data;
-+
-+ frame->hw_frames_ctx = av_buffer_ref(avctx->hw_frames_ctx);
-+
-+ if ((rv = ff_attach_decode_data(frame)) != 0) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to attach decode data to frame\n");
-+ av_frame_unref(frame);
-+ return rv;
-+ }
-+
-+ return 0;
-+}
-+
-+const v4l2_req_decode_fns V(ff_v4l2_req_hevc) = {
-+ .src_pix_fmt_v4l2 = V4L2_PIX_FMT_HEVC_SLICE,
-+ .name = "V4L2 HEVC stateless V" STR(HEVC_CTRLS_VERSION),
-+ .probe = probe,
-+ .set_controls = set_controls,
-+
-+ .start_frame = v4l2_request_hevc_start_frame,
-+ .decode_slice = v4l2_request_hevc_decode_slice,
-+ .end_frame = v4l2_request_hevc_end_frame,
-+ .abort_frame = v4l2_request_hevc_abort_frame,
-+ .frame_params = frame_params,
-+ .alloc_frame = alloc_frame,
-+};
-+
-diff --git a/libavcodec/v4l2_req_media.c b/libavcodec/v4l2_req_media.c
-new file mode 100644
-index 0000000000..eb00ecb406
---- /dev/null
-+++ b/libavcodec/v4l2_req_media.c
-@@ -0,0 +1,1596 @@
-+/*
-+ * Copyright (C) 2018 Paul Kocialkowski
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the
-+ * "Software"), to deal in the Software without restriction, including
-+ * without limitation the rights to use, copy, modify, merge, publish,
-+ * distribute, sub license, and/or sell copies of the Software, and to
-+ * permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the
-+ * next paragraph) shall be included in all copies or substantial portions
-+ * of the Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
-+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
-+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+
-+#include
-+
-+#include "v4l2_req_dmabufs.h"
-+#include "v4l2_req_media.h"
-+#include "v4l2_req_pollqueue.h"
-+#include "v4l2_req_utils.h"
-+#include "weak_link.h"
-+
-+
-+/* floor(log2(x)) */
-+static unsigned int log2_size(size_t x)
-+{
-+ unsigned int n = 0;
-+
-+ if (x & ~0xffff) {
-+ n += 16;
-+ x >>= 16;
-+ }
-+ if (x & ~0xff) {
-+ n += 8;
-+ x >>= 8;
-+ }
-+ if (x & ~0xf) {
-+ n += 4;
-+ x >>= 4;
-+ }
-+ if (x & ~3) {
-+ n += 2;
-+ x >>= 2;
-+ }
-+ return (x & ~1) ? n + 1 : n;
-+}
-+
-+static size_t round_up_size(const size_t x)
-+{
-+ /* Admit no size < 256 */
-+ const unsigned int n = x < 256 ? 8 : log2_size(x) - 1;
-+
-+ return x >= (3 << n) ? 4 << n : (3 << n);
-+}
-+
-+struct media_request;
-+
-+struct media_pool {
-+ int fd;
-+ sem_t sem;
-+ pthread_mutex_t lock;
-+ struct media_request * free_reqs;
-+ struct pollqueue * pq;
-+};
-+
-+struct media_request {
-+ struct media_request * next;
-+ struct media_pool * mp;
-+ int fd;
-+ struct polltask * pt;
-+};
-+
-+
-+static inline int do_trywait(sem_t *const sem)
-+{
-+ while (sem_trywait(sem)) {
-+ if (errno != EINTR)
-+ return -errno;
-+ }
-+ return 0;
-+}
-+
-+static inline int do_wait(sem_t *const sem)
-+{
-+ while (sem_wait(sem)) {
-+ if (errno != EINTR)
-+ return -errno;
-+ }
-+ return 0;
-+}
-+
-+static int request_buffers(int video_fd, unsigned int type,
-+ enum v4l2_memory memory, unsigned int buffers_count)
-+{
-+ struct v4l2_requestbuffers buffers;
-+ int rc;
-+
-+ memset(&buffers, 0, sizeof(buffers));
-+ buffers.type = type;
-+ buffers.memory = memory;
-+ buffers.count = buffers_count;
-+
-+ rc = ioctl(video_fd, VIDIOC_REQBUFS, &buffers);
-+ if (rc < 0) {
-+ rc = -errno;
-+ request_log("Unable to request %d type %d buffers: %s\n", buffers_count, type, strerror(-rc));
-+ return rc;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+static int set_stream(int video_fd, unsigned int type, bool enable)
-+{
-+ enum v4l2_buf_type buf_type = type;
-+ int rc;
-+
-+ rc = ioctl(video_fd, enable ? VIDIOC_STREAMON : VIDIOC_STREAMOFF,
-+ &buf_type);
-+ if (rc < 0) {
-+ rc = -errno;
-+ request_log("Unable to %sable stream: %s\n",
-+ enable ? "en" : "dis", strerror(-rc));
-+ return rc;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+
-+struct media_request * media_request_get(struct media_pool * const mp)
-+{
-+ struct media_request *req = NULL;
-+
-+ /* Timeout handled by poll code */
-+ if (do_wait(&mp->sem))
-+ return NULL;
-+
-+ pthread_mutex_lock(&mp->lock);
-+ req = mp->free_reqs;
-+ if (req) {
-+ mp->free_reqs = req->next;
-+ req->next = NULL;
-+ }
-+ pthread_mutex_unlock(&mp->lock);
-+ return req;
-+}
-+
-+int media_request_fd(const struct media_request * const req)
-+{
-+ return req->fd;
-+}
-+
-+int media_request_start(struct media_request * const req)
-+{
-+ while (ioctl(req->fd, MEDIA_REQUEST_IOC_QUEUE, NULL) == -1)
-+ {
-+ const int err = errno;
-+ if (err == EINTR)
-+ continue;
-+ request_log("%s: Failed to Q media: (%d) %s\n", __func__, err, strerror(err));
-+ return -err;
-+ }
-+
-+ pollqueue_add_task(req->pt, 2000);
-+ return 0;
-+}
-+
-+static void media_request_done(void *v, short revents)
-+{
-+ struct media_request *const req = v;
-+ struct media_pool *const mp = req->mp;
-+
-+ /* ** Not sure what to do about timeout */
-+
-+ if (ioctl(req->fd, MEDIA_REQUEST_IOC_REINIT, NULL) < 0)
-+ request_log("Unable to reinit media request: %s\n",
-+ strerror(errno));
-+
-+ pthread_mutex_lock(&mp->lock);
-+ req->next = mp->free_reqs;
-+ mp->free_reqs = req;
-+ pthread_mutex_unlock(&mp->lock);
-+ sem_post(&mp->sem);
-+}
-+
-+int media_request_abort(struct media_request ** const preq)
-+{
-+ struct media_request * const req = *preq;
-+
-+ if (req == NULL)
-+ return 0;
-+ *preq = NULL;
-+
-+ media_request_done(req, 0);
-+ return 0;
-+}
-+
-+static void delete_req_chain(struct media_request * const chain)
-+{
-+ struct media_request * next = chain;
-+ while (next) {
-+ struct media_request * const req = next;
-+ next = req->next;
-+ if (req->pt)
-+ polltask_delete(&req->pt);
-+ if (req->fd != -1)
-+ close(req->fd);
-+ free(req);
-+ }
-+}
-+
-+struct media_pool * media_pool_new(const char * const media_path,
-+ struct pollqueue * const pq,
-+ const unsigned int n)
-+{
-+ struct media_pool * const mp = calloc(1, sizeof(*mp));
-+ unsigned int i;
-+
-+ if (!mp)
-+ goto fail0;
-+
-+ mp->pq = pq;
-+ pthread_mutex_init(&mp->lock, NULL);
-+ mp->fd = open(media_path, O_RDWR | O_NONBLOCK);
-+ if (mp->fd == -1) {
-+ request_log("Failed to open '%s': %s\n", media_path, strerror(errno));
-+ goto fail1;
-+ }
-+
-+ for (i = 0; i != n; ++i) {
-+ struct media_request * req = malloc(sizeof(*req));
-+ if (!req)
-+ goto fail4;
-+
-+ *req = (struct media_request){
-+ .next = mp->free_reqs,
-+ .mp = mp,
-+ .fd = -1
-+ };
-+ mp->free_reqs = req;
-+
-+ if (ioctl(mp->fd, MEDIA_IOC_REQUEST_ALLOC, &req->fd) == -1) {
-+ request_log("Failed to alloc request %d: %s\n", i, strerror(errno));
-+ goto fail4;
-+ }
-+
-+ req->pt = polltask_new(pq, req->fd, POLLPRI, media_request_done, req);
-+ if (!req->pt)
-+ goto fail4;
-+ }
-+
-+ sem_init(&mp->sem, 0, n);
-+
-+ return mp;
-+
-+fail4:
-+ delete_req_chain(mp->free_reqs);
-+ close(mp->fd);
-+ pthread_mutex_destroy(&mp->lock);
-+fail1:
-+ free(mp);
-+fail0:
-+ return NULL;
-+}
-+
-+void media_pool_delete(struct media_pool ** pMp)
-+{
-+ struct media_pool * const mp = *pMp;
-+
-+ if (!mp)
-+ return;
-+ *pMp = NULL;
-+
-+ delete_req_chain(mp->free_reqs);
-+ close(mp->fd);
-+ sem_destroy(&mp->sem);
-+ pthread_mutex_destroy(&mp->lock);
-+ free(mp);
-+}
-+
-+
-+#define INDEX_UNSET (~(uint32_t)0)
-+
-+enum qent_status {
-+ QENT_NEW = 0, // Initial state - shouldn't last
-+ QENT_FREE, // On free chain
-+ QENT_PENDING, // User has ent
-+ QENT_WAITING, // On inuse
-+ QENT_DONE, // Frame rx
-+ QENT_ERROR, // Error
-+ QENT_IMPORT
-+};
-+
-+struct qent_base {
-+ atomic_int ref_count;
-+ struct qent_base *next;
-+ struct qent_base *prev;
-+ enum qent_status status;
-+ uint32_t index;
-+ struct dmabuf_h *dh[VIDEO_MAX_PLANES];
-+ struct timeval timestamp;
-+};
-+
-+struct qent_src {
-+ struct qent_base base;
-+ int fixed_size;
-+};
-+
-+struct qent_dst {
-+ struct qent_base base;
-+ bool waiting;
-+ pthread_mutex_t lock;
-+ pthread_cond_t cond;
-+ struct ff_weak_link_client * mbc_wl;
-+};
-+
-+struct qe_list_head {
-+ struct qent_base *head;
-+ struct qent_base *tail;
-+};
-+
-+struct buf_pool {
-+ pthread_mutex_t lock;
-+ sem_t free_sem;
-+ enum v4l2_buf_type buf_type;
-+ struct qe_list_head free;
-+ struct qe_list_head inuse;
-+};
-+
-+
-+static inline struct qent_dst *base_to_dst(struct qent_base *be)
-+{
-+ return (struct qent_dst *)be;
-+}
-+
-+static inline struct qent_src *base_to_src(struct qent_base *be)
-+{
-+ return (struct qent_src *)be;
-+}
-+
-+
-+#define QENT_BASE_INITIALIZER {\
-+ .ref_count = ATOMIC_VAR_INIT(0),\
-+ .status = QENT_NEW,\
-+ .index = INDEX_UNSET\
-+}
-+
-+static void qe_base_uninit(struct qent_base *const be)
-+{
-+ unsigned int i;
-+ for (i = 0; i != VIDEO_MAX_PLANES; ++i) {
-+ dmabuf_free(be->dh[i]);
-+ be->dh[i] = NULL;
-+ }
-+}
-+
-+static void qe_src_free(struct qent_src *const be_src)
-+{
-+ if (!be_src)
-+ return;
-+ qe_base_uninit(&be_src->base);
-+ free(be_src);
-+}
-+
-+static struct qent_src * qe_src_new(void)
-+{
-+ struct qent_src *const be_src = malloc(sizeof(*be_src));
-+ if (!be_src)
-+ return NULL;
-+ *be_src = (struct qent_src){
-+ .base = QENT_BASE_INITIALIZER
-+ };
-+ return be_src;
-+}
-+
-+static void qe_dst_free(struct qent_dst *const be_dst)
-+{
-+ if (!be_dst)
-+ return;
-+
-+ ff_weak_link_unref(&be_dst->mbc_wl);
-+ pthread_cond_destroy(&be_dst->cond);
-+ pthread_mutex_destroy(&be_dst->lock);
-+ qe_base_uninit(&be_dst->base);
-+ free(be_dst);
-+}
-+
-+static struct qent_dst* qe_dst_new(struct ff_weak_link_master * const wl)
-+{
-+ struct qent_dst *const be_dst = malloc(sizeof(*be_dst));
-+ if (!be_dst)
-+ return NULL;
-+ *be_dst = (struct qent_dst){
-+ .base = QENT_BASE_INITIALIZER,
-+ .lock = PTHREAD_MUTEX_INITIALIZER,
-+ .cond = PTHREAD_COND_INITIALIZER,
-+ .mbc_wl = ff_weak_link_ref(wl)
-+ };
-+ return be_dst;
-+}
-+
-+static void ql_add_tail(struct qe_list_head * const ql, struct qent_base * be)
-+{
-+ if (ql->tail)
-+ ql->tail->next = be;
-+ else
-+ ql->head = be;
-+ be->prev = ql->tail;
-+ be->next = NULL;
-+ ql->tail = be;
-+}
-+
-+static struct qent_base * ql_extract(struct qe_list_head * const ql, struct qent_base * be)
-+{
-+ if (!be)
-+ return NULL;
-+
-+ if (be->next)
-+ be->next->prev = be->prev;
-+ else
-+ ql->tail = be->prev;
-+ if (be->prev)
-+ be->prev->next = be->next;
-+ else
-+ ql->head = be->next;
-+ be->next = NULL;
-+ be->prev = NULL;
-+ return be;
-+}
-+
-+
-+static void bq_put_free(struct buf_pool *const bp, struct qent_base * be)
-+{
-+ ql_add_tail(&bp->free, be);
-+}
-+
-+static struct qent_base * bq_get_free(struct buf_pool *const bp)
-+{
-+ return ql_extract(&bp->free, bp->free.head);
-+}
-+
-+static struct qent_base * bq_extract_inuse(struct buf_pool *const bp, struct qent_base *const be)
-+{
-+ return ql_extract(&bp->inuse, be);
-+}
-+
-+static struct qent_base * bq_get_inuse(struct buf_pool *const bp)
-+{
-+ return ql_extract(&bp->inuse, bp->inuse.head);
-+}
-+
-+static void bq_free_all_free_src(struct buf_pool *const bp)
-+{
-+ struct qent_base *be;
-+ while ((be = bq_get_free(bp)) != NULL)
-+ qe_src_free(base_to_src(be));
-+}
-+
-+static void bq_free_all_inuse_src(struct buf_pool *const bp)
-+{
-+ struct qent_base *be;
-+ while ((be = bq_get_inuse(bp)) != NULL)
-+ qe_src_free(base_to_src(be));
-+}
-+
-+static void bq_free_all_free_dst(struct buf_pool *const bp)
-+{
-+ struct qent_base *be;
-+ while ((be = bq_get_free(bp)) != NULL)
-+ qe_dst_free(base_to_dst(be));
-+}
-+
-+static void queue_put_free(struct buf_pool *const bp, struct qent_base *be)
-+{
-+ unsigned int i;
-+
-+ pthread_mutex_lock(&bp->lock);
-+ /* Clear out state vars */
-+ be->timestamp.tv_sec = 0;
-+ be->timestamp.tv_usec = 0;
-+ be->status = QENT_FREE;
-+ for (i = 0; i < VIDEO_MAX_PLANES && be->dh[i]; ++i)
-+ dmabuf_len_set(be->dh[i], 0);
-+ bq_put_free(bp, be);
-+ pthread_mutex_unlock(&bp->lock);
-+ sem_post(&bp->free_sem);
-+}
-+
-+static bool queue_is_inuse(const struct buf_pool *const bp)
-+{
-+ return bp->inuse.tail != NULL;
-+}
-+
-+static void queue_put_inuse(struct buf_pool *const bp, struct qent_base *be)
-+{
-+ if (!be)
-+ return;
-+ pthread_mutex_lock(&bp->lock);
-+ ql_add_tail(&bp->inuse, be);
-+ be->status = QENT_WAITING;
-+ pthread_mutex_unlock(&bp->lock);
-+}
-+
-+static struct qent_base *queue_get_free(struct buf_pool *const bp)
-+{
-+ struct qent_base *buf;
-+
-+ if (do_wait(&bp->free_sem))
-+ return NULL;
-+ pthread_mutex_lock(&bp->lock);
-+ buf = bq_get_free(bp);
-+ pthread_mutex_unlock(&bp->lock);
-+ return buf;
-+}
-+
-+static struct qent_base *queue_tryget_free(struct buf_pool *const bp)
-+{
-+ struct qent_base *buf;
-+
-+ if (do_trywait(&bp->free_sem))
-+ return NULL;
-+ pthread_mutex_lock(&bp->lock);
-+ buf = bq_get_free(bp);
-+ pthread_mutex_unlock(&bp->lock);
-+ return buf;
-+}
-+
-+static struct qent_base * queue_find_extract_fd(struct buf_pool *const bp, const int fd)
-+{
-+ struct qent_base *be;
-+
-+ pthread_mutex_lock(&bp->lock);
-+ /* Expect 1st in Q, but allow anywhere */
-+ for (be = bp->inuse.head; be; be = be->next) {
-+ if (dmabuf_fd(be->dh[0]) == fd) {
-+ bq_extract_inuse(bp, be);
-+ break;
-+ }
-+ }
-+ pthread_mutex_unlock(&bp->lock);
-+
-+ return be;
-+}
-+
-+static void queue_delete(struct buf_pool *const bp)
-+{
-+ sem_destroy(&bp->free_sem);
-+ pthread_mutex_destroy(&bp->lock);
-+ free(bp);
-+}
-+
-+static struct buf_pool* queue_new(const int vfd)
-+{
-+ struct buf_pool *bp = calloc(1, sizeof(*bp));
-+ if (!bp)
-+ return NULL;
-+ pthread_mutex_init(&bp->lock, NULL);
-+ sem_init(&bp->free_sem, 0, 0);
-+ return bp;
-+}
-+
-+
-+struct mediabufs_ctl {
-+ atomic_int ref_count; /* 0 is single ref for easier atomics */
-+ void * dc;
-+ int vfd;
-+ bool stream_on;
-+ bool polling;
-+ bool dst_fixed; // Dst Q is fixed size
-+ pthread_mutex_t lock;
-+ struct buf_pool * src;
-+ struct buf_pool * dst;
-+ struct polltask * pt;
-+ struct pollqueue * pq;
-+ struct ff_weak_link_master * this_wlm;
-+
-+ struct v4l2_format src_fmt;
-+ struct v4l2_format dst_fmt;
-+};
-+
-+static int qe_v4l2_queue(struct qent_base *const be,
-+ const int vfd, struct media_request *const mreq,
-+ const struct v4l2_format *const fmt,
-+ const bool is_dst, const bool hold_flag)
-+{
-+ struct v4l2_buffer buffer = {
-+ .type = fmt->type,
-+ .memory = V4L2_MEMORY_DMABUF,
-+ .index = be->index
-+ };
-+ struct v4l2_plane planes[VIDEO_MAX_PLANES] = {{0}};
-+
-+ if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
-+ unsigned int i;
-+ for (i = 0; i < VIDEO_MAX_PLANES && be->dh[i]; ++i) {
-+ if (is_dst)
-+ dmabuf_len_set(be->dh[i], 0);
-+
-+ /* *** Really need a pixdesc rather than a format so we can fill in data_offset */
-+ planes[i].length = dmabuf_size(be->dh[i]);
-+ planes[i].bytesused = dmabuf_len(be->dh[i]);
-+ planes[i].m.fd = dmabuf_fd(be->dh[i]);
-+ }
-+ buffer.m.planes = planes;
-+ buffer.length = i;
-+ }
-+ else {
-+ if (is_dst)
-+ dmabuf_len_set(be->dh[0], 0);
-+
-+ buffer.bytesused = dmabuf_len(be->dh[0]);
-+ buffer.length = dmabuf_size(be->dh[0]);
-+ buffer.m.fd = dmabuf_fd(be->dh[0]);
-+ }
-+
-+ if (!is_dst && mreq) {
-+ buffer.flags |= V4L2_BUF_FLAG_REQUEST_FD;
-+ buffer.request_fd = media_request_fd(mreq);
-+ if (hold_flag)
-+ buffer.flags |= V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF;
-+ }
-+
-+ if (is_dst)
-+ be->timestamp = (struct timeval){0,0};
-+
-+ buffer.timestamp = be->timestamp;
-+
-+ while (ioctl(vfd, VIDIOC_QBUF, &buffer)) {
-+ const int err = errno;
-+ if (err != EINTR) {
-+ request_log("%s: Failed to Q buffer: err=%d (%s)\n", __func__, err, strerror(err));
-+ return -err;
-+ }
-+ }
-+ return 0;
-+}
-+
-+static struct qent_base * qe_dequeue(struct buf_pool *const bp,
-+ const int vfd,
-+ const struct v4l2_format * const f)
-+{
-+ int fd;
-+ struct qent_base *be;
-+ int rc;
-+ const bool mp = V4L2_TYPE_IS_MULTIPLANAR(f->type);
-+ struct v4l2_plane planes[VIDEO_MAX_PLANES] = {{0}};
-+ struct v4l2_buffer buffer = {
-+ .type = f->type,
-+ .memory = V4L2_MEMORY_DMABUF
-+ };
-+ if (mp) {
-+ buffer.length = f->fmt.pix_mp.num_planes;
-+ buffer.m.planes = planes;
-+ }
-+
-+ while ((rc = ioctl(vfd, VIDIOC_DQBUF, &buffer)) != 0 &&
-+ errno == EINTR)
-+ /* Loop */;
-+ if (rc) {
-+ request_log("Error DQing buffer type %d: %s\n", f->type, strerror(errno));
-+ return NULL;
-+ }
-+
-+ fd = mp ? planes[0].m.fd : buffer.m.fd;
-+ be = queue_find_extract_fd(bp, fd);
-+ if (!be) {
-+ request_log("Failed to find fd %d in Q\n", fd);
-+ return NULL;
-+ }
-+
-+ be->timestamp = buffer.timestamp;
-+ be->status = (buffer.flags & V4L2_BUF_FLAG_ERROR) ? QENT_ERROR : QENT_DONE;
-+ return be;
-+}
-+
-+static void qe_dst_done(struct qent_dst * dst_be)
-+{
-+ pthread_mutex_lock(&dst_be->lock);
-+ dst_be->waiting = false;
-+ pthread_cond_broadcast(&dst_be->cond);
-+ pthread_mutex_unlock(&dst_be->lock);
-+
-+ qent_dst_unref(&dst_be);
-+}
-+
-+static bool qe_dst_waiting(struct qent_dst *const dst_be)
-+{
-+ bool waiting;
-+ pthread_mutex_lock(&dst_be->lock);
-+ waiting = dst_be->waiting;
-+ dst_be->waiting = true;
-+ pthread_mutex_unlock(&dst_be->lock);
-+ return waiting;
-+}
-+
-+
-+static bool mediabufs_wants_poll(const struct mediabufs_ctl *const mbc)
-+{
-+ return queue_is_inuse(mbc->src) || queue_is_inuse(mbc->dst);
-+}
-+
-+static void mediabufs_poll_cb(void * v, short revents)
-+{
-+ struct mediabufs_ctl *mbc = v;
-+ struct qent_src *src_be = NULL;
-+ struct qent_dst *dst_be = NULL;
-+
-+ if (!revents)
-+ request_err(mbc->dc, "%s: Timeout\n", __func__);
-+
-+ pthread_mutex_lock(&mbc->lock);
-+ mbc->polling = false;
-+
-+ if ((revents & POLLOUT) != 0)
-+ src_be = base_to_src(qe_dequeue(mbc->src, mbc->vfd, &mbc->src_fmt));
-+ if ((revents & POLLIN) != 0)
-+ dst_be = base_to_dst(qe_dequeue(mbc->dst, mbc->vfd, &mbc->dst_fmt));
-+
-+ /* Reschedule */
-+ if (mediabufs_wants_poll(mbc)) {
-+ mbc->polling = true;
-+ pollqueue_add_task(mbc->pt, 2000);
-+ }
-+ pthread_mutex_unlock(&mbc->lock);
-+
-+ if (src_be)
-+ queue_put_free(mbc->src, &src_be->base);
-+ if (dst_be)
-+ qe_dst_done(dst_be);
-+}
-+
-+int qent_src_params_set(struct qent_src *const be_src, const struct timeval * timestamp)
-+{
-+ struct qent_base *const be = &be_src->base;
-+
-+ be->timestamp = *timestamp;
-+ return 0;
-+}
-+
-+struct timeval qent_dst_timestamp_get(const struct qent_dst *const be_dst)
-+{
-+ return be_dst->base.timestamp;
-+}
-+
-+static int qent_base_realloc(struct qent_base *const be, const size_t len, struct dmabufs_ctl * dbsc)
-+{
-+ if (!be->dh[0] || len > dmabuf_size(be->dh[0])) {
-+ size_t newsize = round_up_size(len);
-+ request_log("%s: Overrun %zd > %zd; trying %zd\n", __func__, len, dmabuf_size(be->dh[0]), newsize);
-+ if (!dbsc) {
-+ request_log("%s: No dmbabuf_ctrl for realloc\n", __func__);
-+ return -ENOMEM;
-+ }
-+ if ((be->dh[0] = dmabuf_realloc(dbsc, be->dh[0], newsize)) == NULL) {
-+ request_log("%s: Realloc %zd failed\n", __func__, newsize);
-+ return -ENOMEM;
-+ }
-+ }
-+ return 0;
-+}
-+
-+int qent_src_alloc(struct qent_src *const be_src, const size_t len, struct dmabufs_ctl * dbsc)
-+{
-+ struct qent_base *const be = &be_src->base;
-+ return qent_base_realloc(be, len, dbsc);
-+}
-+
-+
-+int qent_src_data_copy(struct qent_src *const be_src, const size_t offset, const void *const src, const size_t len, struct dmabufs_ctl * dbsc)
-+{
-+ void * dst;
-+ struct qent_base *const be = &be_src->base;
-+ int rv;
-+
-+ // Realloc doesn't copy so don't alloc if offset != 0
-+ if ((rv = qent_base_realloc(be, offset + len,
-+ be_src->fixed_size || offset ? NULL : dbsc)) != 0)
-+ return rv;
-+
-+ dmabuf_write_start(be->dh[0]);
-+ dst = dmabuf_map(be->dh[0]);
-+ if (!dst)
-+ return -1;
-+ memcpy((char*)dst + offset, src, len);
-+ dmabuf_len_set(be->dh[0], len);
-+ dmabuf_write_end(be->dh[0]);
-+ return 0;
-+}
-+
-+const struct dmabuf_h * qent_dst_dmabuf(const struct qent_dst *const be_dst, unsigned int plane)
-+{
-+ const struct qent_base *const be = &be_dst->base;
-+
-+ return (plane >= sizeof(be->dh)/sizeof(be->dh[0])) ? NULL : be->dh[plane];
-+}
-+
-+int qent_dst_dup_fd(const struct qent_dst *const be_dst, unsigned int plane)
-+{
-+ return dup(dmabuf_fd(qent_dst_dmabuf(be_dst, plane)));
-+}
-+
-+MediaBufsStatus mediabufs_start_request(struct mediabufs_ctl *const mbc,
-+ struct media_request **const pmreq,
-+ struct qent_src **const psrc_be,
-+ struct qent_dst *const dst_be,
-+ const bool is_final)
-+{
-+ struct media_request * mreq = *pmreq;
-+ struct qent_src *const src_be = *psrc_be;
-+
-+ // Req & src are always both "consumed"
-+ *pmreq = NULL;
-+ *psrc_be = NULL;
-+
-+ pthread_mutex_lock(&mbc->lock);
-+
-+ if (!src_be)
-+ goto fail1;
-+
-+ if (dst_be) {
-+ if (qe_dst_waiting(dst_be)) {
-+ request_info(mbc->dc, "Request buffer already waiting on start\n");
-+ goto fail1;
-+ }
-+ dst_be->base.timestamp = (struct timeval){0,0};
-+ if (qe_v4l2_queue(&dst_be->base, mbc->vfd, NULL, &mbc->dst_fmt, true, false))
-+ goto fail1;
-+
-+ qent_dst_ref(dst_be);
-+ queue_put_inuse(mbc->dst, &dst_be->base);
-+ }
-+
-+ if (qe_v4l2_queue(&src_be->base, mbc->vfd, mreq, &mbc->src_fmt, false, !is_final))
-+ goto fail1;
-+ queue_put_inuse(mbc->src, &src_be->base);
-+
-+ if (!mbc->polling && mediabufs_wants_poll(mbc)) {
-+ mbc->polling = true;
-+ pollqueue_add_task(mbc->pt, 2000);
-+ }
-+ pthread_mutex_unlock(&mbc->lock);
-+
-+ if (media_request_start(mreq))
-+ return MEDIABUFS_ERROR_OPERATION_FAILED;
-+
-+ return MEDIABUFS_STATUS_SUCCESS;
-+
-+fail1:
-+ media_request_abort(&mreq);
-+ if (src_be)
-+ queue_put_free(mbc->src, &src_be->base);
-+
-+// *** TODO: If src Q fails this doesnt unwind properly - separate dst Q from src Q
-+ if (dst_be) {
-+ dst_be->base.status = QENT_ERROR;
-+ qe_dst_done(dst_be);
-+ }
-+ pthread_mutex_unlock(&mbc->lock);
-+ return MEDIABUFS_ERROR_OPERATION_FAILED;
-+}
-+
-+
-+static int qe_alloc_from_fmt(struct qent_base *const be,
-+ struct dmabufs_ctl *const dbsc,
-+ const struct v4l2_format *const fmt)
-+{
-+ if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
-+ unsigned int i;
-+ for (i = 0; i != fmt->fmt.pix_mp.num_planes; ++i) {
-+ be->dh[i] = dmabuf_realloc(dbsc, be->dh[i],
-+ fmt->fmt.pix_mp.plane_fmt[i].sizeimage);
-+ /* On failure tidy up and die */
-+ if (!be->dh[i]) {
-+ while (i--) {
-+ dmabuf_free(be->dh[i]);
-+ be->dh[i] = NULL;
-+ }
-+ return -1;
-+ }
-+ }
-+ }
-+ else {
-+// be->dh[0] = dmabuf_alloc(dbsc, fmt->fmt.pix.sizeimage);
-+ size_t size = fmt->fmt.pix.sizeimage;
-+ be->dh[0] = dmabuf_realloc(dbsc, be->dh[0], size);
-+ if (!be->dh[0])
-+ return -1;
-+ }
-+ return 0;
-+}
-+
-+static MediaBufsStatus fmt_set(struct v4l2_format *const fmt, const int fd,
-+ const enum v4l2_buf_type buftype,
-+ uint32_t pixfmt,
-+ const unsigned int width, const unsigned int height,
-+ const size_t bufsize)
-+{
-+ *fmt = (struct v4l2_format){.type = buftype};
-+
-+ if (V4L2_TYPE_IS_MULTIPLANAR(buftype)) {
-+ fmt->fmt.pix_mp.width = width;
-+ fmt->fmt.pix_mp.height = height;
-+ fmt->fmt.pix_mp.pixelformat = pixfmt;
-+ if (bufsize) {
-+ fmt->fmt.pix_mp.num_planes = 1;
-+ fmt->fmt.pix_mp.plane_fmt[0].sizeimage = bufsize;
-+ }
-+ }
-+ else {
-+ fmt->fmt.pix.width = width;
-+ fmt->fmt.pix.height = height;
-+ fmt->fmt.pix.pixelformat = pixfmt;
-+ fmt->fmt.pix.sizeimage = bufsize;
-+ }
-+
-+ while (ioctl(fd, VIDIOC_S_FMT, fmt))
-+ if (errno != EINTR)
-+ return MEDIABUFS_ERROR_OPERATION_FAILED;
-+
-+ // Treat anything where we don't get at least what we asked for as a fail
-+ if (V4L2_TYPE_IS_MULTIPLANAR(buftype)) {
-+ if (fmt->fmt.pix_mp.width < width ||
-+ fmt->fmt.pix_mp.height < height ||
-+ fmt->fmt.pix_mp.pixelformat != pixfmt) {
-+ return MEDIABUFS_ERROR_UNSUPPORTED_BUFFERTYPE;
-+ }
-+ }
-+ else {
-+ if (fmt->fmt.pix.width < width ||
-+ fmt->fmt.pix.height < height ||
-+ fmt->fmt.pix.pixelformat != pixfmt) {
-+ return MEDIABUFS_ERROR_UNSUPPORTED_BUFFERTYPE;
-+ }
-+ }
-+
-+ return MEDIABUFS_STATUS_SUCCESS;
-+}
-+
-+static MediaBufsStatus find_fmt_flags(struct v4l2_format *const fmt,
-+ const int fd,
-+ const unsigned int type_v4l2,
-+ const uint32_t flags_must,
-+ const uint32_t flags_not,
-+ const unsigned int width,
-+ const unsigned int height,
-+ mediabufs_dst_fmt_accept_fn *const accept_fn,
-+ void *const accept_v)
-+{
-+ unsigned int i;
-+
-+ for (i = 0;; ++i) {
-+ struct v4l2_fmtdesc fmtdesc = {
-+ .index = i,
-+ .type = type_v4l2
-+ };
-+ while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)) {
-+ if (errno != EINTR)
-+ return MEDIABUFS_ERROR_UNSUPPORTED_BUFFERTYPE;
-+ }
-+ if ((fmtdesc.flags & flags_must) != flags_must ||
-+ (fmtdesc.flags & flags_not))
-+ continue;
-+ if (!accept_fn(accept_v, &fmtdesc))
-+ continue;
-+
-+ if (fmt_set(fmt, fd, fmtdesc.type, fmtdesc.pixelformat,
-+ width, height, 0) == MEDIABUFS_STATUS_SUCCESS)
-+ return MEDIABUFS_STATUS_SUCCESS;
-+ }
-+ return 0;
-+}
-+
-+
-+/* Wait for qent done */
-+
-+MediaBufsStatus qent_dst_wait(struct qent_dst *const be_dst)
-+{
-+ struct qent_base *const be = &be_dst->base;
-+ enum qent_status estat;
-+
-+ pthread_mutex_lock(&be_dst->lock);
-+ while (be_dst->waiting &&
-+ !pthread_cond_wait(&be_dst->cond, &be_dst->lock))
-+ /* Loop */;
-+ estat = be->status;
-+ pthread_mutex_unlock(&be_dst->lock);
-+
-+ return estat == QENT_DONE ? MEDIABUFS_STATUS_SUCCESS :
-+ estat == QENT_ERROR ? MEDIABUFS_ERROR_DECODING_ERROR :
-+ MEDIABUFS_ERROR_OPERATION_FAILED;
-+}
-+
-+const uint8_t * qent_dst_data(struct qent_dst *const be_dst, unsigned int buf_no)
-+{
-+ struct qent_base *const be = &be_dst->base;
-+ return dmabuf_map(be->dh[buf_no]);
-+}
-+
-+MediaBufsStatus qent_dst_read_start(struct qent_dst *const be_dst)
-+{
-+ struct qent_base *const be = &be_dst->base;
-+ unsigned int i;
-+ for (i = 0; i != VIDEO_MAX_PLANES && be->dh[i]; ++i) {
-+ if (dmabuf_read_start(be->dh[i])) {
-+ while (i--)
-+ dmabuf_read_end(be->dh[i]);
-+ return MEDIABUFS_ERROR_ALLOCATION_FAILED;
-+ }
-+ }
-+ return MEDIABUFS_STATUS_SUCCESS;
-+}
-+
-+MediaBufsStatus qent_dst_read_stop(struct qent_dst *const be_dst)
-+{
-+ struct qent_base *const be = &be_dst->base;
-+ unsigned int i;
-+ MediaBufsStatus status = MEDIABUFS_STATUS_SUCCESS;
-+
-+ for (i = 0; i != VIDEO_MAX_PLANES && be->dh[i]; ++i) {
-+ if (dmabuf_read_end(be->dh[i]))
-+ status = MEDIABUFS_ERROR_OPERATION_FAILED;
-+ }
-+ return status;
-+}
-+
-+struct qent_dst * qent_dst_ref(struct qent_dst * const be_dst)
-+{
-+ if (be_dst)
-+ atomic_fetch_add(&be_dst->base.ref_count, 1);
-+ return be_dst;
-+}
-+
-+void qent_dst_unref(struct qent_dst ** const pbe_dst)
-+{
-+ struct qent_dst * const be_dst = *pbe_dst;
-+ struct mediabufs_ctl * mbc;
-+ if (!be_dst)
-+ return;
-+ *pbe_dst = NULL;
-+
-+ if (atomic_fetch_sub(&be_dst->base.ref_count, 1) != 0)
-+ return;
-+
-+ if ((mbc = ff_weak_link_lock(&be_dst->mbc_wl)) != NULL) {
-+ queue_put_free(mbc->dst, &be_dst->base);
-+ ff_weak_link_unlock(be_dst->mbc_wl);
-+ }
-+ else {
-+ qe_dst_free(be_dst);
-+ }
-+}
-+
-+MediaBufsStatus qent_dst_import_fd(struct qent_dst *const be_dst,
-+ unsigned int plane,
-+ int fd, size_t size)
-+{
-+ struct qent_base *const be = &be_dst->base;
-+ struct dmabuf_h * dh;
-+
-+ if (be->status != QENT_IMPORT || be->dh[plane])
-+ return MEDIABUFS_ERROR_OPERATION_FAILED;
-+
-+ dh = dmabuf_import(fd, size);
-+ if (!dh)
-+ return MEDIABUFS_ERROR_ALLOCATION_FAILED;
-+
-+ be->dh[plane] = dh;
-+ return MEDIABUFS_STATUS_SUCCESS;
-+}
-+
-+// Returns noof buffers created, -ve for error
-+static int create_dst_bufs(struct mediabufs_ctl *const mbc, unsigned int n, struct qent_dst * const qes[])
-+{
-+ unsigned int i;
-+
-+ struct v4l2_create_buffers cbuf = {
-+ .count = n,
-+ .memory = V4L2_MEMORY_DMABUF,
-+ .format = mbc->dst_fmt,
-+ };
-+
-+ while (ioctl(mbc->vfd, VIDIOC_CREATE_BUFS, &cbuf)) {
-+ const int err = -errno;
-+ if (err != EINTR) {
-+ request_err(mbc->dc, "%s: Failed to create V4L2 buffer\n", __func__);
-+ return -err;
-+ }
-+ }
-+
-+ if (cbuf.count != n)
-+ request_warn(mbc->dc, "%s: Created %d of %d V4L2 buffers requested\n", __func__, cbuf.count, n);
-+
-+ for (i = 0; i != cbuf.count; ++i)
-+ qes[i]->base.index = cbuf.index + i;
-+
-+ return cbuf.count;
-+}
-+
-+struct qent_dst* mediabufs_dst_qent_alloc(struct mediabufs_ctl *const mbc, struct dmabufs_ctl *const dbsc)
-+{
-+ struct qent_dst * be_dst;
-+
-+ if (mbc == NULL) {
-+ be_dst = qe_dst_new(NULL);
-+ if (be_dst)
-+ be_dst->base.status = QENT_IMPORT;
-+ return be_dst;
-+ }
-+
-+ if (mbc->dst_fixed) {
-+ be_dst = base_to_dst(queue_get_free(mbc->dst));
-+ if (!be_dst)
-+ return NULL;
-+ }
-+ else {
-+ be_dst = base_to_dst(queue_tryget_free(mbc->dst));
-+ if (!be_dst) {
-+ be_dst = qe_dst_new(mbc->this_wlm);
-+ if (!be_dst)
-+ return NULL;
-+
-+ if (create_dst_bufs(mbc, 1, &be_dst) != 1) {
-+ qe_dst_free(be_dst);
-+ return NULL;
-+ }
-+ }
-+ }
-+
-+ if (qe_alloc_from_fmt(&be_dst->base, dbsc, &mbc->dst_fmt)) {
-+ /* Given how create buf works we can't uncreate it on alloc failure
-+ * all we can do is put it on the free Q
-+ */
-+ queue_put_free(mbc->dst, &be_dst->base);
-+ return NULL;
-+ }
-+
-+ be_dst->base.status = QENT_PENDING;
-+ atomic_store(&be_dst->base.ref_count, 0);
-+ return be_dst;
-+}
-+
-+const struct v4l2_format *mediabufs_dst_fmt(struct mediabufs_ctl *const mbc)
-+{
-+ return &mbc->dst_fmt;
-+}
-+
-+MediaBufsStatus mediabufs_dst_fmt_set(struct mediabufs_ctl *const mbc,
-+ const unsigned int width,
-+ const unsigned int height,
-+ mediabufs_dst_fmt_accept_fn *const accept_fn,
-+ void *const accept_v)
-+{
-+ MediaBufsStatus status;
-+ unsigned int i;
-+ const enum v4l2_buf_type buf_type = mbc->dst_fmt.type;
-+ static const struct {
-+ unsigned int flags_must;
-+ unsigned int flags_not;
-+ } trys[] = {
-+ {0, V4L2_FMT_FLAG_EMULATED},
-+ {V4L2_FMT_FLAG_EMULATED, 0},
-+ };
-+ for (i = 0; i != sizeof(trys)/sizeof(trys[0]); ++i) {
-+ status = find_fmt_flags(&mbc->dst_fmt, mbc->vfd,
-+ buf_type,
-+ trys[i].flags_must,
-+ trys[i].flags_not,
-+ width, height, accept_fn, accept_v);
-+ if (status != MEDIABUFS_ERROR_UNSUPPORTED_BUFFERTYPE)
-+ return status;
-+ }
-+
-+ if (status != MEDIABUFS_STATUS_SUCCESS)
-+ return status;
-+
-+ /* Try to create a buffer - don't alloc */
-+ return status;
-+}
-+
-+// ** This is a mess if we get partial alloc but without any way to remove
-+// individual V4L2 Q members we are somewhat stuffed
-+MediaBufsStatus mediabufs_dst_slots_create(struct mediabufs_ctl *const mbc, const unsigned int n, const bool fixed)
-+{
-+ unsigned int i;
-+ int a = 0;
-+ unsigned int qc;
-+ struct qent_dst * qes[32];
-+
-+ if (n > 32)
-+ return MEDIABUFS_ERROR_ALLOCATION_FAILED;
-+
-+ // Create qents first as it is hard to get rid of the V4L2 buffers on error
-+ for (qc = 0; qc != n; ++qc)
-+ {
-+ if ((qes[qc] = qe_dst_new(mbc->this_wlm)) == NULL)
-+ goto fail;
-+ }
-+
-+ if ((a = create_dst_bufs(mbc, n, qes)) < 0)
-+ goto fail;
-+
-+ for (i = 0; i != a; ++i)
-+ queue_put_free(mbc->dst, &qes[i]->base);
-+
-+ if (a != n)
-+ goto fail;
-+
-+ mbc->dst_fixed = fixed;
-+ return MEDIABUFS_STATUS_SUCCESS;
-+
-+fail:
-+ for (i = (a < 0 ? 0 : a); i != qc; ++i)
-+ qe_dst_free(qes[i]);
-+
-+ return MEDIABUFS_ERROR_ALLOCATION_FAILED;
-+}
-+
-+struct qent_src *mediabufs_src_qent_get(struct mediabufs_ctl *const mbc)
-+{
-+ struct qent_base * buf = queue_get_free(mbc->src);
-+ buf->status = QENT_PENDING;
-+ return base_to_src(buf);
-+}
-+
-+void mediabufs_src_qent_abort(struct mediabufs_ctl *const mbc, struct qent_src **const pqe_src)
-+{
-+ struct qent_src *const qe_src = *pqe_src;
-+ if (!qe_src)
-+ return;
-+ *pqe_src = NULL;
-+ queue_put_free(mbc->src, &qe_src->base);
-+}
-+
-+/* src format must have been set up before this */
-+MediaBufsStatus mediabufs_src_pool_create(struct mediabufs_ctl *const mbc,
-+ struct dmabufs_ctl * const dbsc,
-+ unsigned int n)
-+{
-+ unsigned int i;
-+ struct v4l2_requestbuffers req = {
-+ .count = n,
-+ .type = mbc->src_fmt.type,
-+ .memory = V4L2_MEMORY_DMABUF
-+ };
-+
-+ bq_free_all_free_src(mbc->src);
-+ while (ioctl(mbc->vfd, VIDIOC_REQBUFS, &req) == -1) {
-+ if (errno != EINTR) {
-+ request_err(mbc->dc, "%s: Failed to request src bufs\n", __func__);
-+ return MEDIABUFS_ERROR_OPERATION_FAILED;
-+ }
-+ }
-+
-+ if (n > req.count) {
-+ request_info(mbc->dc, "Only allocated %d of %d src buffers requested\n", req.count, n);
-+ n = req.count;
-+ }
-+
-+ for (i = 0; i != n; ++i) {
-+ struct qent_src *const be_src = qe_src_new();
-+ if (!be_src) {
-+ request_err(mbc->dc, "Failed to create src be %d\n", i);
-+ goto fail;
-+ }
-+ if (qe_alloc_from_fmt(&be_src->base, dbsc, &mbc->src_fmt)) {
-+ qe_src_free(be_src);
-+ goto fail;
-+ }
-+ be_src->base.index = i;
-+ be_src->fixed_size = !mediabufs_src_resizable(mbc);
-+
-+ queue_put_free(mbc->src, &be_src->base);
-+ }
-+
-+ return MEDIABUFS_STATUS_SUCCESS;
-+
-+fail:
-+ bq_free_all_free_src(mbc->src);
-+ req.count = 0;
-+ while (ioctl(mbc->vfd, VIDIOC_REQBUFS, &req) == -1 &&
-+ errno == EINTR)
-+ /* Loop */;
-+
-+ return MEDIABUFS_ERROR_OPERATION_FAILED;
-+}
-+
-+
-+
-+/*
-+ * Set stuff order:
-+ * Set src fmt
-+ * Set parameters (sps) on vfd
-+ * Negotiate dst format (dst_fmt_set)
-+ * Create src buffers
-+ * Alloc a dst buffer or Create dst slots
-+*/
-+MediaBufsStatus mediabufs_stream_on(struct mediabufs_ctl *const mbc)
-+{
-+ if (mbc->stream_on)
-+ return MEDIABUFS_STATUS_SUCCESS;
-+
-+ if (set_stream(mbc->vfd, mbc->src_fmt.type, true) < 0) {
-+ request_log("Failed to set stream on src type %d\n", mbc->src_fmt.type);
-+ return MEDIABUFS_ERROR_OPERATION_FAILED;
-+ }
-+
-+ if (set_stream(mbc->vfd, mbc->dst_fmt.type, true) < 0) {
-+ request_log("Failed to set stream on dst type %d\n", mbc->dst_fmt.type);
-+ set_stream(mbc->vfd, mbc->src_fmt.type, false);
-+ return MEDIABUFS_ERROR_OPERATION_FAILED;
-+ }
-+
-+ mbc->stream_on = true;
-+ return MEDIABUFS_STATUS_SUCCESS;
-+}
-+
-+MediaBufsStatus mediabufs_stream_off(struct mediabufs_ctl *const mbc)
-+{
-+ MediaBufsStatus status = MEDIABUFS_STATUS_SUCCESS;
-+
-+ if (!mbc->stream_on)
-+ return MEDIABUFS_STATUS_SUCCESS;
-+
-+ if (set_stream(mbc->vfd, mbc->dst_fmt.type, false) < 0) {
-+ request_log("Failed to set stream off dst type %d\n", mbc->dst_fmt.type);
-+ status = MEDIABUFS_ERROR_OPERATION_FAILED;
-+ }
-+
-+ if (set_stream(mbc->vfd, mbc->src_fmt.type, false) < 0) {
-+ request_log("Failed to set stream off src type %d\n", mbc->src_fmt.type);
-+ status = MEDIABUFS_ERROR_OPERATION_FAILED;
-+ }
-+
-+ mbc->stream_on = false;
-+ return status;
-+}
-+
-+int mediabufs_ctl_set_ext_ctrls(struct mediabufs_ctl * mbc, struct media_request * const mreq, struct v4l2_ext_control control_array[], unsigned int n)
-+{
-+ struct v4l2_ext_controls controls = {
-+ .controls = control_array,
-+ .count = n
-+ };
-+
-+ if (mreq) {
-+ controls.which = V4L2_CTRL_WHICH_REQUEST_VAL;
-+ controls.request_fd = media_request_fd(mreq);
-+ }
-+
-+ while (ioctl(mbc->vfd, VIDIOC_S_EXT_CTRLS, &controls))
-+ {
-+ const int err = errno;
-+ if (err != EINTR) {
-+ request_err(mbc->dc, "Unable to set controls: %s\n", strerror(err));
-+ return -err;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+MediaBufsStatus mediabufs_set_ext_ctrl(struct mediabufs_ctl *const mbc,
-+ struct media_request * const mreq,
-+ unsigned int id, void *data,
-+ unsigned int size)
-+{
-+ struct v4l2_ext_control control = {
-+ .id = id,
-+ .ptr = data,
-+ .size = size
-+ };
-+
-+ int rv = mediabufs_ctl_set_ext_ctrls(mbc, mreq, &control, 1);
-+ return !rv ? MEDIABUFS_STATUS_SUCCESS : MEDIABUFS_ERROR_OPERATION_FAILED;
-+}
-+
-+MediaBufsStatus mediabufs_src_fmt_set(struct mediabufs_ctl *const mbc,
-+ enum v4l2_buf_type buf_type,
-+ const uint32_t pixfmt,
-+ const uint32_t width, const uint32_t height,
-+ const size_t bufsize)
-+{
-+ MediaBufsStatus rv = fmt_set(&mbc->src_fmt, mbc->vfd, buf_type, pixfmt, width, height, bufsize);
-+ if (rv != MEDIABUFS_STATUS_SUCCESS)
-+ request_err(mbc->dc, "Failed to set src buftype %d, format %#x %dx%d\n", buf_type, pixfmt, width, height);
-+
-+ return rv;
-+}
-+
-+int mediabufs_ctl_query_ext_ctrls(struct mediabufs_ctl * mbc, struct v4l2_query_ext_ctrl ctrls[], unsigned int n)
-+{
-+ int rv = 0;
-+ while (n--) {
-+ while (ioctl(mbc->vfd, VIDIOC_QUERY_EXT_CTRL, ctrls)) {
-+ const int err = errno;
-+ if (err != EINTR) {
-+ // Often used for probing - errors are to be expected
-+ request_debug(mbc->dc, "Failed to query ext id=%#x, err=%d\n", ctrls->id, err);
-+ ctrls->type = 0; // 0 is invalid
-+ rv = -err;
-+ break;
-+ }
-+ }
-+ ++ctrls;
-+ }
-+ return rv;
-+}
-+
-+int mediabufs_src_resizable(const struct mediabufs_ctl *const mbc)
-+{
-+ // Single planar OUTPUT can only take exact size buffers
-+ // Multiplanar will take larger than negotiated
-+ return V4L2_TYPE_IS_MULTIPLANAR(mbc->src_fmt.type);
-+}
-+
-+static void mediabufs_ctl_delete(struct mediabufs_ctl *const mbc)
-+{
-+ if (!mbc)
-+ return;
-+
-+ // Break the weak link first
-+ ff_weak_link_break(&mbc->this_wlm);
-+
-+ polltask_delete(&mbc->pt);
-+
-+ mediabufs_stream_off(mbc);
-+
-+ // Empty v4l2 buffer stash
-+ request_buffers(mbc->vfd, mbc->src_fmt.type, V4L2_MEMORY_MMAP, 0);
-+ request_buffers(mbc->vfd, mbc->dst_fmt.type, V4L2_MEMORY_MMAP, 0);
-+
-+ bq_free_all_free_src(mbc->src);
-+ bq_free_all_inuse_src(mbc->src);
-+ bq_free_all_free_dst(mbc->dst);
-+
-+ {
-+ struct qent_dst *dst_be;
-+ while ((dst_be = base_to_dst(bq_get_inuse(mbc->dst))) != NULL) {
-+ dst_be->base.timestamp = (struct timeval){0};
-+ dst_be->base.status = QENT_ERROR;
-+ qe_dst_done(dst_be);
-+ }
-+ }
-+
-+ queue_delete(mbc->dst);
-+ queue_delete(mbc->src);
-+ close(mbc->vfd);
-+ pthread_mutex_destroy(&mbc->lock);
-+
-+ free(mbc);
-+}
-+
-+struct mediabufs_ctl * mediabufs_ctl_ref(struct mediabufs_ctl *const mbc)
-+{
-+ atomic_fetch_add(&mbc->ref_count, 1);
-+ return mbc;
-+}
-+
-+void mediabufs_ctl_unref(struct mediabufs_ctl **const pmbc)
-+{
-+ struct mediabufs_ctl *const mbc = *pmbc;
-+ int n;
-+
-+ if (!mbc)
-+ return;
-+ *pmbc = NULL;
-+ n = atomic_fetch_sub(&mbc->ref_count, 1);
-+ if (n)
-+ return;
-+ mediabufs_ctl_delete(mbc);
-+}
-+
-+static int set_capabilities(struct mediabufs_ctl *const mbc)
-+{
-+ struct v4l2_capability capability = { 0 };
-+ uint32_t caps;
-+
-+ if (ioctl(mbc->vfd, VIDIOC_QUERYCAP, &capability)) {
-+ int err = errno;
-+ request_err(mbc->dc, "Failed to get capabilities: %s\n", strerror(err));
-+ return -err;
-+ }
-+
-+ caps = (capability.capabilities & V4L2_CAP_DEVICE_CAPS) != 0 ?
-+ capability.device_caps :
-+ capability.capabilities;
-+
-+ if ((caps & V4L2_CAP_VIDEO_M2M_MPLANE) != 0) {
-+ mbc->src_fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-+ mbc->dst_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-+ }
-+ else if ((caps & V4L2_CAP_VIDEO_M2M) != 0) {
-+ mbc->src_fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-+ mbc->dst_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-+ }
-+ else {
-+ request_err(mbc->dc, "No M2M capabilities (%#x)\n", caps);
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+/* One of these per context */
-+struct mediabufs_ctl * mediabufs_ctl_new(void * const dc, const char * vpath, struct pollqueue *const pq)
-+{
-+ struct mediabufs_ctl *const mbc = calloc(1, sizeof(*mbc));
-+
-+ if (!mbc)
-+ return NULL;
-+
-+ mbc->dc = dc;
-+ // Default mono planar
-+ mbc->pq = pq;
-+ pthread_mutex_init(&mbc->lock, NULL);
-+
-+ /* Pick a default - could we scan for this? */
-+ if (vpath == NULL)
-+ vpath = "/dev/media0";
-+
-+ while ((mbc->vfd = open(vpath, O_RDWR)) == -1)
-+ {
-+ const int err = errno;
-+ if (err != EINTR) {
-+ request_err(dc, "Failed to open video dev '%s': %s\n", vpath, strerror(err));
-+ goto fail0;
-+ }
-+ }
-+
-+ if (set_capabilities(mbc)) {
-+ request_err(dc, "Bad capabilities for video dev '%s'\n", vpath);
-+ goto fail1;
-+ }
-+
-+ mbc->src = queue_new(mbc->vfd);
-+ if (!mbc->src)
-+ goto fail1;
-+ mbc->dst = queue_new(mbc->vfd);
-+ if (!mbc->dst)
-+ goto fail2;
-+ mbc->pt = polltask_new(pq, mbc->vfd, POLLIN | POLLOUT, mediabufs_poll_cb, mbc);
-+ if (!mbc->pt)
-+ goto fail3;
-+ mbc->this_wlm = ff_weak_link_new(mbc);
-+ if (!mbc->this_wlm)
-+ goto fail4;
-+
-+ /* Cannot add polltask now - polling with nothing pending
-+ * generates infinite error polls
-+ */
-+ return mbc;
-+
-+fail4:
-+ polltask_delete(&mbc->pt);
-+fail3:
-+ queue_delete(mbc->dst);
-+fail2:
-+ queue_delete(mbc->src);
-+fail1:
-+ close(mbc->vfd);
-+fail0:
-+ free(mbc);
-+ request_info(dc, "%s: FAILED\n", __func__);
-+ return NULL;
-+}
-+
-+
-+
-diff --git a/libavcodec/v4l2_req_media.h b/libavcodec/v4l2_req_media.h
-new file mode 100644
-index 0000000000..2f826cfb14
---- /dev/null
-+++ b/libavcodec/v4l2_req_media.h
-@@ -0,0 +1,151 @@
-+/*
-+e.h
-+*
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the
-+ * "Software"), to deal in the Software without restriction, including
-+ * without limitation the rights to use, copy, modify, merge, publish,
-+ * distribute, sub license, and/or sell copies of the Software, and to
-+ * permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the
-+ * next paragraph) shall be included in all copies or substantial portions
-+ * of the Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
-+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
-+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef _MEDIA_H_
-+#define _MEDIA_H_
-+
-+#include
-+#include
-+
-+struct v4l2_format;
-+struct v4l2_fmtdesc;
-+struct v4l2_query_ext_ctrl;
-+
-+struct pollqueue;
-+struct media_request;
-+struct media_pool;
-+
-+typedef enum media_buf_status {
-+ MEDIABUFS_STATUS_SUCCESS = 0,
-+ MEDIABUFS_ERROR_OPERATION_FAILED,
-+ MEDIABUFS_ERROR_DECODING_ERROR,
-+ MEDIABUFS_ERROR_UNSUPPORTED_BUFFERTYPE,
-+ MEDIABUFS_ERROR_UNSUPPORTED_RT_FORMAT,
-+ MEDIABUFS_ERROR_ALLOCATION_FAILED,
-+} MediaBufsStatus;
-+
-+struct media_pool * media_pool_new(const char * const media_path,
-+ struct pollqueue * const pq,
-+ const unsigned int n);
-+void media_pool_delete(struct media_pool ** pmp);
-+
-+// Obtain a media request
-+// Will block if none availible - has a 2sec timeout
-+struct media_request * media_request_get(struct media_pool * const mp);
-+int media_request_fd(const struct media_request * const req);
-+
-+// Start this request
-+// Request structure is returned to pool once done
-+int media_request_start(struct media_request * const req);
-+
-+// Return an *unstarted* media_request to the pool
-+// May later be upgraded to allow for aborting a started req
-+int media_request_abort(struct media_request ** const preq);
-+
-+
-+struct mediabufs_ctl;
-+struct qent_src;
-+struct qent_dst;
-+struct dmabuf_h;
-+struct dmabufs_ctl;
-+
-+int qent_src_params_set(struct qent_src *const be, const struct timeval * timestamp);
-+struct timeval qent_dst_timestamp_get(const struct qent_dst *const be_dst);
-+
-+// prealloc
-+int qent_src_alloc(struct qent_src *const be_src, const size_t len, struct dmabufs_ctl * dbsc);
-+// dbsc may be NULL if realloc not required
-+int qent_src_data_copy(struct qent_src *const be_src, const size_t offset, const void *const src, const size_t len, struct dmabufs_ctl * dbsc);
-+const struct dmabuf_h * qent_dst_dmabuf(const struct qent_dst *const be, unsigned int plane);
-+int qent_dst_dup_fd(const struct qent_dst *const be, unsigned int plane);
-+MediaBufsStatus qent_dst_wait(struct qent_dst *const be);
-+void qent_dst_delete(struct qent_dst *const be);
-+// Returns a qent_dst to its mbc free Q or deletes it if the mbc is dead
-+void qent_dst_unref(struct qent_dst ** const pbe_dst);
-+struct qent_dst * qent_dst_ref(struct qent_dst * const be_dst);
-+
-+const uint8_t * qent_dst_data(struct qent_dst *const be, unsigned int buf_no);
-+MediaBufsStatus qent_dst_read_start(struct qent_dst *const be);
-+MediaBufsStatus qent_dst_read_stop(struct qent_dst *const be);
-+/* Import an fd unattached to any mediabuf */
-+MediaBufsStatus qent_dst_import_fd(struct qent_dst *const be_dst,
-+ unsigned int plane,
-+ int fd, size_t size);
-+
-+MediaBufsStatus mediabufs_start_request(struct mediabufs_ctl *const mbc,
-+ struct media_request **const pmreq,
-+ struct qent_src **const psrc_be,
-+ struct qent_dst *const dst_be,
-+ const bool is_final);
-+// Get / alloc a dst buffer & associate with a slot
-+// If the dst pool is empty then behaviour depends on the fixed flag passed to
-+// dst_slots_create. Default is !fixed = unlimited alloc
-+struct qent_dst* mediabufs_dst_qent_alloc(struct mediabufs_ctl *const mbc,
-+ struct dmabufs_ctl *const dbsc);
-+// Create dst slots without alloc
-+// If fixed true then qent_alloc will only get slots from this pool and will
-+// block until a qent has been unrefed
-+MediaBufsStatus mediabufs_dst_slots_create(struct mediabufs_ctl *const mbc, const unsigned int n, const bool fixed);
-+
-+MediaBufsStatus mediabufs_stream_on(struct mediabufs_ctl *const mbc);
-+MediaBufsStatus mediabufs_stream_off(struct mediabufs_ctl *const mbc);
-+const struct v4l2_format *mediabufs_dst_fmt(struct mediabufs_ctl *const mbc);
-+
-+typedef int mediabufs_dst_fmt_accept_fn(void * v, const struct v4l2_fmtdesc *fmtdesc);
-+
-+MediaBufsStatus mediabufs_dst_fmt_set(struct mediabufs_ctl *const mbc,
-+ const unsigned int width,
-+ const unsigned int height,
-+ mediabufs_dst_fmt_accept_fn *const accept_fn,
-+ void *const accept_v);
-+struct qent_src *mediabufs_src_qent_get(struct mediabufs_ctl *const mbc);
-+void mediabufs_src_qent_abort(struct mediabufs_ctl *const mbc, struct qent_src **const pqe_src);
-+
-+int mediabufs_ctl_set_ext_ctrls(struct mediabufs_ctl * mbc, struct media_request * const mreq,
-+ struct v4l2_ext_control control_array[], unsigned int n);
-+MediaBufsStatus mediabufs_set_ext_ctrl(struct mediabufs_ctl *const mbc,
-+ struct media_request * const mreq,
-+ unsigned int id, void *data,
-+ unsigned int size);
-+int mediabufs_ctl_query_ext_ctrls(struct mediabufs_ctl * mbc, struct v4l2_query_ext_ctrl ctrls[], unsigned int n);
-+
-+int mediabufs_src_resizable(const struct mediabufs_ctl *const mbc);
-+
-+MediaBufsStatus mediabufs_src_fmt_set(struct mediabufs_ctl *const mbc,
-+ enum v4l2_buf_type buf_type,
-+ const uint32_t pixfmt,
-+ const uint32_t width, const uint32_t height,
-+ const size_t bufsize);
-+
-+MediaBufsStatus mediabufs_src_pool_create(struct mediabufs_ctl *const rw,
-+ struct dmabufs_ctl * const dbsc,
-+ unsigned int n);
-+
-+struct mediabufs_ctl * mediabufs_ctl_new(void * const dc,
-+ const char *vpath, struct pollqueue *const pq);
-+void mediabufs_ctl_unref(struct mediabufs_ctl **const pmbc);
-+struct mediabufs_ctl * mediabufs_ctl_ref(struct mediabufs_ctl *const mbc);
-+
-+
-+#endif
-diff --git a/libavcodec/v4l2_req_pollqueue.c b/libavcodec/v4l2_req_pollqueue.c
-new file mode 100644
-index 0000000000..cc8a5d4001
---- /dev/null
-+++ b/libavcodec/v4l2_req_pollqueue.c
-@@ -0,0 +1,361 @@
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+
-+#include "v4l2_req_pollqueue.h"
-+#include "v4l2_req_utils.h"
-+
-+
-+struct pollqueue;
-+
-+enum polltask_state {
-+ POLLTASK_UNQUEUED = 0,
-+ POLLTASK_QUEUED,
-+ POLLTASK_RUNNING,
-+ POLLTASK_Q_KILL,
-+ POLLTASK_RUN_KILL,
-+};
-+
-+struct polltask {
-+ struct polltask *next;
-+ struct polltask *prev;
-+ struct pollqueue *q;
-+ enum polltask_state state;
-+
-+ int fd;
-+ short events;
-+
-+ void (*fn)(void *v, short revents);
-+ void * v;
-+
-+ uint64_t timeout; /* CLOCK_MONOTONIC time, 0 => never */
-+ sem_t kill_sem;
-+};
-+
-+struct pollqueue {
-+ atomic_int ref_count;
-+ pthread_mutex_t lock;
-+
-+ struct polltask *head;
-+ struct polltask *tail;
-+
-+ bool kill;
-+ bool no_prod;
-+ int prod_fd;
-+ struct polltask *prod_pt;
-+ pthread_t worker;
-+};
-+
-+struct polltask *polltask_new(struct pollqueue *const pq,
-+ const int fd, const short events,
-+ void (*const fn)(void *v, short revents),
-+ void *const v)
-+{
-+ struct polltask *pt;
-+
-+ if (!events)
-+ return NULL;
-+
-+ pt = malloc(sizeof(*pt));
-+ if (!pt)
-+ return NULL;
-+
-+ *pt = (struct polltask){
-+ .next = NULL,
-+ .prev = NULL,
-+ .q = pollqueue_ref(pq),
-+ .fd = fd,
-+ .events = events,
-+ .fn = fn,
-+ .v = v
-+ };
-+
-+ sem_init(&pt->kill_sem, 0, 0);
-+
-+ return pt;
-+}
-+
-+static void pollqueue_rem_task(struct pollqueue *const pq, struct polltask *const pt)
-+{
-+ if (pt->prev)
-+ pt->prev->next = pt->next;
-+ else
-+ pq->head = pt->next;
-+ if (pt->next)
-+ pt->next->prev = pt->prev;
-+ else
-+ pq->tail = pt->prev;
-+ pt->next = NULL;
-+ pt->prev = NULL;
-+}
-+
-+static void polltask_free(struct polltask * const pt)
-+{
-+ sem_destroy(&pt->kill_sem);
-+ free(pt);
-+}
-+
-+static int pollqueue_prod(const struct pollqueue *const pq)
-+{
-+ static const uint64_t one = 1;
-+ return write(pq->prod_fd, &one, sizeof(one));
-+}
-+
-+void polltask_delete(struct polltask **const ppt)
-+{
-+ struct polltask *const pt = *ppt;
-+ struct pollqueue * pq;
-+ enum polltask_state state;
-+ bool prodme;
-+
-+ if (!pt)
-+ return;
-+
-+ pq = pt->q;
-+ pthread_mutex_lock(&pq->lock);
-+ state = pt->state;
-+ pt->state = (state == POLLTASK_RUNNING) ? POLLTASK_RUN_KILL : POLLTASK_Q_KILL;
-+ prodme = !pq->no_prod;
-+ pthread_mutex_unlock(&pq->lock);
-+
-+ if (state != POLLTASK_UNQUEUED) {
-+ if (prodme)
-+ pollqueue_prod(pq);
-+ while (sem_wait(&pt->kill_sem) && errno == EINTR)
-+ /* loop */;
-+ }
-+
-+ // Leave zapping the ref until we have DQed the PT as might well be
-+ // legitimately used in it
-+ *ppt = NULL;
-+ polltask_free(pt);
-+ pollqueue_unref(&pq);
-+}
-+
-+static uint64_t pollqueue_now(int timeout)
-+{
-+ struct timespec now;
-+ uint64_t now_ms;
-+
-+ if (clock_gettime(CLOCK_MONOTONIC, &now))
-+ return 0;
-+ now_ms = (now.tv_nsec / 1000000) + (uint64_t)now.tv_sec * 1000 + timeout;
-+ return now_ms ? now_ms : (uint64_t)1;
-+}
-+
-+void pollqueue_add_task(struct polltask *const pt, const int timeout)
-+{
-+ bool prodme = false;
-+ struct pollqueue * const pq = pt->q;
-+
-+ pthread_mutex_lock(&pq->lock);
-+ if (pt->state != POLLTASK_Q_KILL && pt->state != POLLTASK_RUN_KILL) {
-+ if (pq->tail)
-+ pq->tail->next = pt;
-+ else
-+ pq->head = pt;
-+ pt->prev = pq->tail;
-+ pt->next = NULL;
-+ pt->state = POLLTASK_QUEUED;
-+ pt->timeout = timeout < 0 ? 0 : pollqueue_now(timeout);
-+ pq->tail = pt;
-+ prodme = !pq->no_prod;
-+ }
-+ pthread_mutex_unlock(&pq->lock);
-+ if (prodme)
-+ pollqueue_prod(pq);
-+}
-+
-+static void *poll_thread(void *v)
-+{
-+ struct pollqueue *const pq = v;
-+ struct pollfd *a = NULL;
-+ size_t asize = 0;
-+
-+ pthread_mutex_lock(&pq->lock);
-+ do {
-+ unsigned int i;
-+ unsigned int n = 0;
-+ struct polltask *pt;
-+ struct polltask *pt_next;
-+ uint64_t now = pollqueue_now(0);
-+ int timeout = -1;
-+ int rv;
-+
-+ for (pt = pq->head; pt; pt = pt_next) {
-+ int64_t t;
-+
-+ pt_next = pt->next;
-+
-+ if (pt->state == POLLTASK_Q_KILL) {
-+ pollqueue_rem_task(pq, pt);
-+ sem_post(&pt->kill_sem);
-+ continue;
-+ }
-+
-+ if (n >= asize) {
-+ asize = asize ? asize * 2 : 4;
-+ a = realloc(a, asize * sizeof(*a));
-+ if (!a) {
-+ request_log("Failed to realloc poll array to %zd\n", asize);
-+ goto fail_locked;
-+ }
-+ }
-+
-+ a[n++] = (struct pollfd){
-+ .fd = pt->fd,
-+ .events = pt->events
-+ };
-+
-+ t = (int64_t)(pt->timeout - now);
-+ if (pt->timeout && t < INT_MAX &&
-+ (timeout < 0 || (int)t < timeout))
-+ timeout = (t < 0) ? 0 : (int)t;
-+ }
-+ pthread_mutex_unlock(&pq->lock);
-+
-+ if ((rv = poll(a, n, timeout)) == -1) {
-+ if (errno != EINTR) {
-+ request_log("Poll error: %s\n", strerror(errno));
-+ goto fail_unlocked;
-+ }
-+ }
-+
-+ pthread_mutex_lock(&pq->lock);
-+ now = pollqueue_now(0);
-+
-+ /* Prodding in this loop is pointless and might lead to
-+ * infinite looping
-+ */
-+ pq->no_prod = true;
-+ for (i = 0, pt = pq->head; i < n; ++i, pt = pt_next) {
-+ pt_next = pt->next;
-+
-+ /* Pending? */
-+ if (a[i].revents ||
-+ (pt->timeout && (int64_t)(now - pt->timeout) >= 0)) {
-+ pollqueue_rem_task(pq, pt);
-+ if (pt->state == POLLTASK_QUEUED)
-+ pt->state = POLLTASK_RUNNING;
-+ if (pt->state == POLLTASK_Q_KILL)
-+ pt->state = POLLTASK_RUN_KILL;
-+ pthread_mutex_unlock(&pq->lock);
-+
-+ /* This can add new entries to the Q but as
-+ * those are added to the tail our existing
-+ * chain remains intact
-+ */
-+ pt->fn(pt->v, a[i].revents);
-+
-+ pthread_mutex_lock(&pq->lock);
-+ if (pt->state == POLLTASK_RUNNING)
-+ pt->state = POLLTASK_UNQUEUED;
-+ if (pt->state == POLLTASK_RUN_KILL)
-+ sem_post(&pt->kill_sem);
-+ }
-+ }
-+ pq->no_prod = false;
-+
-+ } while (!pq->kill);
-+
-+fail_locked:
-+ pthread_mutex_unlock(&pq->lock);
-+fail_unlocked:
-+ free(a);
-+ return NULL;
-+}
-+
-+static void prod_fn(void *v, short revents)
-+{
-+ struct pollqueue *const pq = v;
-+ char buf[8];
-+ if (revents)
-+ read(pq->prod_fd, buf, 8);
-+ if (!pq->kill)
-+ pollqueue_add_task(pq->prod_pt, -1);
-+}
-+
-+struct pollqueue * pollqueue_new(void)
-+{
-+ struct pollqueue *pq = malloc(sizeof(*pq));
-+ if (!pq)
-+ return NULL;
-+ *pq = (struct pollqueue){
-+ .ref_count = ATOMIC_VAR_INIT(0),
-+ .lock = PTHREAD_MUTEX_INITIALIZER,
-+ .head = NULL,
-+ .tail = NULL,
-+ .kill = false,
-+ .prod_fd = -1
-+ };
-+
-+ pq->prod_fd = eventfd(0, EFD_NONBLOCK);
-+ if (pq->prod_fd == 1)
-+ goto fail1;
-+ pq->prod_pt = polltask_new(pq, pq->prod_fd, POLLIN, prod_fn, pq);
-+ if (!pq->prod_pt)
-+ goto fail2;
-+ pollqueue_add_task(pq->prod_pt, -1);
-+ if (pthread_create(&pq->worker, NULL, poll_thread, pq))
-+ goto fail3;
-+ // Reset ref count which will have been inced by the add_task
-+ atomic_store(&pq->ref_count, 0);
-+ return pq;
-+
-+fail3:
-+ polltask_free(pq->prod_pt);
-+fail2:
-+ close(pq->prod_fd);
-+fail1:
-+ free(pq);
-+ return NULL;
-+}
-+
-+static void pollqueue_free(struct pollqueue *const pq)
-+{
-+ void *rv;
-+
-+ pthread_mutex_lock(&pq->lock);
-+ pq->kill = true;
-+ pollqueue_prod(pq);
-+ pthread_mutex_unlock(&pq->lock);
-+
-+ pthread_join(pq->worker, &rv);
-+ polltask_free(pq->prod_pt);
-+ pthread_mutex_destroy(&pq->lock);
-+ close(pq->prod_fd);
-+ free(pq);
-+}
-+
-+struct pollqueue * pollqueue_ref(struct pollqueue *const pq)
-+{
-+ atomic_fetch_add(&pq->ref_count, 1);
-+ return pq;
-+}
-+
-+void pollqueue_unref(struct pollqueue **const ppq)
-+{
-+ struct pollqueue * const pq = *ppq;
-+
-+ if (!pq)
-+ return;
-+ *ppq = NULL;
-+
-+ if (atomic_fetch_sub(&pq->ref_count, 1) != 0)
-+ return;
-+
-+ pollqueue_free(pq);
-+}
-+
-+
-+
-diff --git a/libavcodec/v4l2_req_pollqueue.h b/libavcodec/v4l2_req_pollqueue.h
-new file mode 100644
-index 0000000000..e1182cb2fc
---- /dev/null
-+++ b/libavcodec/v4l2_req_pollqueue.h
-@@ -0,0 +1,18 @@
-+#ifndef POLLQUEUE_H_
-+#define POLLQUEUE_H_
-+
-+struct polltask;
-+struct pollqueue;
-+
-+struct polltask *polltask_new(struct pollqueue *const pq,
-+ const int fd, const short events,
-+ void (*const fn)(void *v, short revents),
-+ void *const v);
-+void polltask_delete(struct polltask **const ppt);
-+
-+void pollqueue_add_task(struct polltask *const pt, const int timeout);
-+struct pollqueue * pollqueue_new(void);
-+void pollqueue_unref(struct pollqueue **const ppq);
-+struct pollqueue * pollqueue_ref(struct pollqueue *const pq);
-+
-+#endif /* POLLQUEUE_H_ */
-diff --git a/libavcodec/v4l2_req_utils.h b/libavcodec/v4l2_req_utils.h
-new file mode 100644
-index 0000000000..a31cc1f4ec
---- /dev/null
-+++ b/libavcodec/v4l2_req_utils.h
-@@ -0,0 +1,27 @@
-+#ifndef AVCODEC_V4L2_REQ_UTILS_H
-+#define AVCODEC_V4L2_REQ_UTILS_H
-+
-+#include
-+#include "libavutil/log.h"
-+
-+#define request_log(...) av_log(NULL, AV_LOG_INFO, __VA_ARGS__)
-+
-+#define request_err(_ctx, ...) av_log(_ctx, AV_LOG_ERROR, __VA_ARGS__)
-+#define request_warn(_ctx, ...) av_log(_ctx, AV_LOG_WARNING, __VA_ARGS__)
-+#define request_info(_ctx, ...) av_log(_ctx, AV_LOG_INFO, __VA_ARGS__)
-+#define request_debug(_ctx, ...) av_log(_ctx, AV_LOG_DEBUG, __VA_ARGS__)
-+
-+static inline char safechar(char c) {
-+ return c > 0x20 && c < 0x7f ? c : '.';
-+}
-+
-+static inline const char * strfourcc(char tbuf[5], uint32_t fcc) {
-+ tbuf[0] = safechar((fcc >> 0) & 0xff);
-+ tbuf[1] = safechar((fcc >> 8) & 0xff);
-+ tbuf[2] = safechar((fcc >> 16) & 0xff);
-+ tbuf[3] = safechar((fcc >> 24) & 0xff);
-+ tbuf[4] = '\0';
-+ return tbuf;
-+}
-+
-+#endif
-diff --git a/libavcodec/v4l2_request_hevc.c b/libavcodec/v4l2_request_hevc.c
-new file mode 100644
-index 0000000000..b0a5930844
---- /dev/null
-+++ b/libavcodec/v4l2_request_hevc.c
-@@ -0,0 +1,297 @@
-+/*
-+ * 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 "decode.h"
-+#include "hevcdec.h"
-+#include "hwconfig.h"
-+#include "internal.h"
-+
-+#include "v4l2_request_hevc.h"
-+
-+#include "libavutil/hwcontext_drm.h"
-+
-+#include "v4l2_req_devscan.h"
-+#include "v4l2_req_dmabufs.h"
-+#include "v4l2_req_pollqueue.h"
-+#include "v4l2_req_media.h"
-+#include "v4l2_req_utils.h"
-+
-+static size_t bit_buf_size(unsigned int w, unsigned int h, unsigned int bits_minus8)
-+{
-+ const size_t wxh = w * h;
-+ size_t bits_alloc;
-+
-+ /* Annex A gives a min compression of 2 @ lvl 3.1
-+ * (wxh <= 983040) and min 4 thereafter but avoid
-+ * the odity of 983041 having a lower limit than
-+ * 983040.
-+ * Multiply by 3/2 for 4:2:0
-+ */
-+ bits_alloc = wxh < 983040 ? wxh * 3 / 4 :
-+ wxh < 983040 * 2 ? 983040 * 3 / 4 :
-+ wxh * 3 / 8;
-+ /* Allow for bit depth */
-+ bits_alloc += (bits_alloc * bits_minus8) / 8;
-+ /* Add a few bytes (16k) for overhead */
-+ bits_alloc += 0x4000;
-+ return bits_alloc;
-+}
-+
-+static int v4l2_req_hevc_start_frame(AVCodecContext *avctx,
-+ av_unused const uint8_t *buffer,
-+ av_unused uint32_t size)
-+{
-+ const V4L2RequestContextHEVC * const ctx = avctx->internal->hwaccel_priv_data;
-+ return ctx->fns->start_frame(avctx, buffer, size);
-+}
-+
-+static int v4l2_req_hevc_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)
-+{
-+ V4L2RequestContextHEVC * const ctx = avctx->internal->hwaccel_priv_data;
-+ return ctx->fns->decode_slice(avctx, buffer, size);
-+}
-+
-+static int v4l2_req_hevc_end_frame(AVCodecContext *avctx)
-+{
-+ V4L2RequestContextHEVC *ctx = avctx->internal->hwaccel_priv_data;
-+ return ctx->fns->end_frame(avctx);
-+}
-+
-+static void v4l2_req_hevc_abort_frame(AVCodecContext * const avctx)
-+{
-+ V4L2RequestContextHEVC * const ctx = avctx->internal->hwaccel_priv_data;
-+ ctx->fns->abort_frame(avctx);
-+}
-+
-+static int v4l2_req_hevc_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx)
-+{
-+ V4L2RequestContextHEVC * const ctx = avctx->internal->hwaccel_priv_data;
-+ return ctx->fns->frame_params(avctx, hw_frames_ctx);
-+}
-+
-+static int v4l2_req_hevc_alloc_frame(AVCodecContext * avctx, AVFrame *frame)
-+{
-+ V4L2RequestContextHEVC * const ctx = avctx->internal->hwaccel_priv_data;
-+ return ctx->fns->alloc_frame(avctx, frame);
-+}
-+
-+
-+static int v4l2_request_hevc_uninit(AVCodecContext *avctx)
-+{
-+ V4L2RequestContextHEVC * const ctx = avctx->internal->hwaccel_priv_data;
-+
-+ av_log(avctx, AV_LOG_DEBUG, "<<< %s\n", __func__);
-+
-+ decode_q_wait(&ctx->decode_q, NULL); // Wait for all other threads to be out of decode
-+
-+ mediabufs_ctl_unref(&ctx->mbufs);
-+ media_pool_delete(&ctx->mpool);
-+ pollqueue_unref(&ctx->pq);
-+ dmabufs_ctl_delete(&ctx->dbufs);
-+ devscan_delete(&ctx->devscan);
-+
-+ decode_q_uninit(&ctx->decode_q);
-+
-+// if (avctx->hw_frames_ctx) {
-+// AVHWFramesContext *hwfc = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
-+// av_buffer_pool_flush(hwfc->pool);
-+// }
-+ return 0;
-+}
-+
-+static int dst_fmt_accept_cb(void * v, const struct v4l2_fmtdesc *fmtdesc)
-+{
-+ AVCodecContext *const avctx = v;
-+ const HEVCContext *const h = avctx->priv_data;
-+
-+ if (h->ps.sps->bit_depth == 8) {
-+ if (fmtdesc->pixelformat == V4L2_PIX_FMT_NV12_COL128 ||
-+ fmtdesc->pixelformat == V4L2_PIX_FMT_NV12) {
-+ return 1;
-+ }
-+ }
-+ else if (h->ps.sps->bit_depth == 10) {
-+ if (fmtdesc->pixelformat == V4L2_PIX_FMT_NV12_10_COL128) {
-+ return 1;
-+ }
-+ }
-+ return 0;
-+}
-+
-+static int v4l2_request_hevc_init(AVCodecContext *avctx)
-+{
-+ const HEVCContext *h = avctx->priv_data;
-+ V4L2RequestContextHEVC * const ctx = avctx->internal->hwaccel_priv_data;
-+ const HEVCSPS * const sps = h->ps.sps;
-+ int ret;
-+ const struct decdev * decdev;
-+ const uint32_t src_pix_fmt = V2(ff_v4l2_req_hevc, 1).src_pix_fmt_v4l2; // Assuming constant for all APIs but avoiding V4L2 includes
-+ size_t src_size;
-+
-+ av_log(avctx, AV_LOG_DEBUG, "<<< %s\n", __func__);
-+
-+ if ((ret = devscan_build(avctx, &ctx->devscan)) != 0) {
-+ av_log(avctx, AV_LOG_WARNING, "Failed to find any V4L2 devices\n");
-+ return (AVERROR(-ret));
-+ }
-+ ret = AVERROR(ENOMEM); // Assume mem fail by default for these
-+
-+ if ((decdev = devscan_find(ctx->devscan, src_pix_fmt)) == NULL)
-+ {
-+ av_log(avctx, AV_LOG_WARNING, "Failed to find a V4L2 device for H265\n");
-+ ret = AVERROR(ENODEV);
-+ goto fail0;
-+ }
-+ av_log(avctx, AV_LOG_DEBUG, "Trying V4L2 devices: %s,%s\n",
-+ decdev_media_path(decdev), decdev_video_path(decdev));
-+
-+ if ((ctx->dbufs = dmabufs_ctl_new()) == NULL) {
-+ av_log(avctx, AV_LOG_ERROR, "Unable to open dmabufs\n");
-+ goto fail0;
-+ }
-+
-+ if ((ctx->pq = pollqueue_new()) == NULL) {
-+ av_log(avctx, AV_LOG_ERROR, "Unable to create pollqueue\n");
-+ goto fail1;
-+ }
-+
-+ if ((ctx->mpool = media_pool_new(decdev_media_path(decdev), ctx->pq, 4)) == NULL) {
-+ av_log(avctx, AV_LOG_ERROR, "Unable to create media pool\n");
-+ goto fail2;
-+ }
-+
-+ if ((ctx->mbufs = mediabufs_ctl_new(avctx, decdev_video_path(decdev), ctx->pq)) == NULL) {
-+ av_log(avctx, AV_LOG_ERROR, "Unable to create media controls\n");
-+ goto fail3;
-+ }
-+
-+ // Ask for an initial bitbuf size of max size / 4
-+ // We will realloc if we need more
-+ // Must use sps->h/w as avctx contains cropped size
-+ src_size = bit_buf_size(sps->width, sps->height, sps->bit_depth - 8);
-+ if (mediabufs_src_resizable(ctx->mbufs))
-+ src_size /= 4;
-+ // Kludge for conformance tests which break Annex A limits
-+ else if (src_size < 0x40000)
-+ src_size = 0x40000;
-+
-+ if (mediabufs_src_fmt_set(ctx->mbufs, decdev_src_type(decdev), src_pix_fmt,
-+ sps->width, sps->height, src_size)) {
-+ char tbuf1[5];
-+ av_log(avctx, AV_LOG_ERROR, "Failed to set source format: %s %dx%d\n", strfourcc(tbuf1, src_pix_fmt), sps->width, sps->height);
-+ goto fail4;
-+ }
-+
-+ if (V2(ff_v4l2_req_hevc, 2).probe(avctx, ctx) == 0) {
-+ av_log(avctx, AV_LOG_DEBUG, "HEVC API version 2 probed successfully\n");
-+ ctx->fns = &V2(ff_v4l2_req_hevc, 2);
-+ }
-+ else if (V2(ff_v4l2_req_hevc, 1).probe(avctx, ctx) == 0) {
-+ av_log(avctx, AV_LOG_DEBUG, "HEVC API version 1 probed successfully\n");
-+ ctx->fns = &V2(ff_v4l2_req_hevc, 1);
-+ }
-+ else {
-+ av_log(avctx, AV_LOG_ERROR, "No HEVC version probed successfully\n");
-+ ret = AVERROR(EINVAL);
-+ goto fail4;
-+ }
-+
-+ if (mediabufs_dst_fmt_set(ctx->mbufs, sps->width, sps->height, dst_fmt_accept_cb, avctx)) {
-+ char tbuf1[5];
-+ av_log(avctx, AV_LOG_ERROR, "Failed to set destination format: %s %dx%d\n", strfourcc(tbuf1, src_pix_fmt), sps->width, sps->height);
-+ goto fail4;
-+ }
-+
-+ if (mediabufs_src_pool_create(ctx->mbufs, ctx->dbufs, 6)) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to create source pool\n");
-+ goto fail4;
-+ }
-+
-+ {
-+ unsigned int dst_slots = sps->temporal_layer[sps->max_sub_layers - 1].max_dec_pic_buffering +
-+ avctx->thread_count + (avctx->extra_hw_frames > 0 ? avctx->extra_hw_frames : 6);
-+ av_log(avctx, AV_LOG_DEBUG, "Slots=%d: Reordering=%d, threads=%d, hw+=%d\n", dst_slots,
-+ sps->temporal_layer[sps->max_sub_layers - 1].max_dec_pic_buffering,
-+ avctx->thread_count, avctx->extra_hw_frames);
-+
-+ // extra_hw_frames is -1 if unset
-+ if (mediabufs_dst_slots_create(ctx->mbufs, dst_slots, (avctx->extra_hw_frames > 0))) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to create destination slots\n");
-+ goto fail4;
-+ }
-+ }
-+
-+ if (mediabufs_stream_on(ctx->mbufs)) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed stream on\n");
-+ goto fail4;
-+ }
-+
-+ if ((ret = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_DRM)) != 0) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to create frame ctx\n");
-+ goto fail4;
-+ }
-+
-+ if ((ret = ctx->fns->set_controls(avctx, ctx)) != 0) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed set controls\n");
-+ goto fail5;
-+ }
-+
-+ decode_q_init(&ctx->decode_q);
-+
-+ // Set our s/w format
-+ avctx->sw_pix_fmt = ((AVHWFramesContext *)avctx->hw_frames_ctx->data)->sw_format;
-+
-+ av_log(avctx, AV_LOG_INFO, "Hwaccel %s; devices: %s,%s\n",
-+ ctx->fns->name,
-+ decdev_media_path(decdev), decdev_video_path(decdev));
-+
-+ return 0;
-+
-+fail5:
-+ av_buffer_unref(&avctx->hw_frames_ctx);
-+fail4:
-+ mediabufs_ctl_unref(&ctx->mbufs);
-+fail3:
-+ media_pool_delete(&ctx->mpool);
-+fail2:
-+ pollqueue_unref(&ctx->pq);
-+fail1:
-+ dmabufs_ctl_delete(&ctx->dbufs);
-+fail0:
-+ devscan_delete(&ctx->devscan);
-+ return ret;
-+}
-+
-+const AVHWAccel ff_hevc_v4l2request_hwaccel = {
-+ .name = "hevc_v4l2request",
-+ .type = AVMEDIA_TYPE_VIDEO,
-+ .id = AV_CODEC_ID_HEVC,
-+ .pix_fmt = AV_PIX_FMT_DRM_PRIME,
-+ .alloc_frame = v4l2_req_hevc_alloc_frame,
-+ .start_frame = v4l2_req_hevc_start_frame,
-+ .decode_slice = v4l2_req_hevc_decode_slice,
-+ .end_frame = v4l2_req_hevc_end_frame,
-+ .abort_frame = v4l2_req_hevc_abort_frame,
-+ .init = v4l2_request_hevc_init,
-+ .uninit = v4l2_request_hevc_uninit,
-+ .priv_data_size = sizeof(V4L2RequestContextHEVC),
-+ .frame_params = v4l2_req_hevc_frame_params,
-+ .caps_internal = HWACCEL_CAP_ASYNC_SAFE | HWACCEL_CAP_MT_SAFE,
-+};
-diff --git a/libavcodec/v4l2_request_hevc.h b/libavcodec/v4l2_request_hevc.h
-new file mode 100644
-index 0000000000..f14f594564
---- /dev/null
-+++ b/libavcodec/v4l2_request_hevc.h
-@@ -0,0 +1,102 @@
-+#ifndef AVCODEC_V4L2_REQUEST_HEVC_H
-+#define AVCODEC_V4L2_REQUEST_HEVC_H
-+
-+#include
-+#include
-+#include "v4l2_req_decode_q.h"
-+
-+#ifndef DRM_FORMAT_NV15
-+#define DRM_FORMAT_NV15 fourcc_code('N', 'V', '1', '5')
-+#endif
-+
-+#ifndef DRM_FORMAT_NV20
-+#define DRM_FORMAT_NV20 fourcc_code('N', 'V', '2', '0')
-+#endif
-+
-+// P030 should be defined in drm_fourcc.h and hopefully will be sometime
-+// in the future but until then...
-+#ifndef DRM_FORMAT_P030
-+#define DRM_FORMAT_P030 fourcc_code('P', '0', '3', '0')
-+#endif
-+
-+#ifndef DRM_FORMAT_NV15
-+#define DRM_FORMAT_NV15 fourcc_code('N', 'V', '1', '5')
-+#endif
-+
-+#ifndef DRM_FORMAT_NV20
-+#define DRM_FORMAT_NV20 fourcc_code('N', 'V', '2', '0')
-+#endif
-+
-+#include
-+#ifndef V4L2_CID_CODEC_BASE
-+#define V4L2_CID_CODEC_BASE V4L2_CID_MPEG_BASE
-+#endif
-+
-+// V4L2_PIX_FMT_NV12_10_COL128 and V4L2_PIX_FMT_NV12_COL128 should be defined
-+// in drm_fourcc.h hopefully will be sometime in the future but until then...
-+#ifndef V4L2_PIX_FMT_NV12_10_COL128
-+#define V4L2_PIX_FMT_NV12_10_COL128 v4l2_fourcc('N', 'C', '3', '0')
-+#endif
-+
-+#ifndef V4L2_PIX_FMT_NV12_COL128
-+#define V4L2_PIX_FMT_NV12_COL128 v4l2_fourcc('N', 'C', '1', '2') /* 12 Y/CbCr 4:2:0 128 pixel wide column */
-+#endif
-+
-+#ifndef V4L2_CTRL_FLAG_DYNAMIC_ARRAY
-+#define V4L2_CTRL_FLAG_DYNAMIC_ARRAY 0x0800
-+#endif
-+
-+#define MAX_SLICES 128
-+
-+#define VCAT(name, version) name##_v##version
-+#define V2(n,v) VCAT(n, v)
-+#define V(n) V2(n, HEVC_CTRLS_VERSION)
-+
-+#define S2(x) #x
-+#define STR(x) S2(x)
-+
-+// 1 per decoder
-+struct v4l2_req_decode_fns;
-+
-+typedef struct V4L2RequestContextHEVC {
-+// V4L2RequestContext base;
-+ const struct v4l2_req_decode_fns * fns;
-+
-+ unsigned int timestamp; // ?? maybe uint64_t
-+
-+ int multi_slice;
-+ int decode_mode;
-+ int start_code;
-+ int max_slices;
-+
-+ req_decode_q decode_q;
-+
-+ struct devscan *devscan;
-+ struct dmabufs_ctl *dbufs;
-+ struct pollqueue *pq;
-+ struct media_pool * mpool;
-+ struct mediabufs_ctl *mbufs;
-+} V4L2RequestContextHEVC;
-+
-+typedef struct v4l2_req_decode_fns {
-+ int src_pix_fmt_v4l2;
-+ const char * name;
-+
-+ // Init setup
-+ int (*probe)(AVCodecContext * const avctx, V4L2RequestContextHEVC * const ctx);
-+ int (*set_controls)(AVCodecContext * const avctx, V4L2RequestContextHEVC * const ctx);
-+
-+ // Passthrough of hwaccel fns
-+ int (*start_frame)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size);
-+ int (*decode_slice)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size);
-+ int (*end_frame)(AVCodecContext *avctx);
-+ void (*abort_frame)(AVCodecContext *avctx);
-+ int (*frame_params)(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx);
-+ int (*alloc_frame)(AVCodecContext * avctx, AVFrame *frame);
-+} v4l2_req_decode_fns;
-+
-+
-+extern const v4l2_req_decode_fns V2(ff_v4l2_req_hevc, 1);
-+extern const v4l2_req_decode_fns V2(ff_v4l2_req_hevc, 2);
-+
-+#endif
-
-From c99a0fe4d59212079de9bed222114abf95f7c989 Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Tue, 27 Apr 2021 19:30:36 +0100
-Subject: [PATCH 013/151] Add no_cvt_hw option to ffmpeg
-
----
- fftools/ffmpeg.c | 6 ++++--
- fftools/ffmpeg.h | 2 ++
- fftools/ffmpeg_opt.c | 3 +++
- 3 files changed, 9 insertions(+), 2 deletions(-)
-
-diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
-index 15e084f0b2..5dc2cd73c1 100644
---- a/fftools/ffmpeg.c
-+++ b/fftools/ffmpeg.c
-@@ -2005,6 +2005,9 @@ static int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame, int keep_ref
- (ifilter->hw_frames_ctx && ifilter->hw_frames_ctx->data != frame->hw_frames_ctx->data))
- need_reinit = 1;
-
-+ if (no_cvt_hw && fg->graph)
-+ need_reinit = 0;
-+
- if (sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX)) {
- if (!ifilter->displaymatrix || memcmp(sd->data, ifilter->displaymatrix, sizeof(int32_t) * 9))
- need_reinit = 1;
-@@ -2274,8 +2277,7 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output, int64_
- decoded_frame->top_field_first = ist->top_field_first;
-
- ist->frames_decoded++;
--
-- if (ist->hwaccel_retrieve_data && decoded_frame->format == ist->hwaccel_pix_fmt) {
-+ if (!no_cvt_hw && ist->hwaccel_retrieve_data && decoded_frame->format == ist->hwaccel_pix_fmt) {
- err = ist->hwaccel_retrieve_data(ist->dec_ctx, decoded_frame);
- if (err < 0)
- goto fail;
-diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
-index f1412f6446..8f478619b3 100644
---- a/fftools/ffmpeg.h
-+++ b/fftools/ffmpeg.h
-@@ -729,6 +729,8 @@ extern enum VideoSyncMethod video_sync_method;
- extern float frame_drop_threshold;
- extern int do_benchmark;
- extern int do_benchmark_all;
-+extern int no_cvt_hw;
-+extern int do_deinterlace;
- extern int do_hex_dump;
- extern int do_pkt_dump;
- extern int copy_ts;
-diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
-index 055275d813..761db36588 100644
---- a/fftools/ffmpeg_opt.c
-+++ b/fftools/ffmpeg_opt.c
-@@ -71,6 +71,7 @@ enum VideoSyncMethod video_sync_method = VSYNC_AUTO;
- float frame_drop_threshold = 0;
- int do_benchmark = 0;
- int do_benchmark_all = 0;
-+int no_cvt_hw = 0;
- int do_hex_dump = 0;
- int do_pkt_dump = 0;
- int copy_ts = 0;
-@@ -1427,6 +1428,8 @@ const OptionDef options[] = {
- "add timings for benchmarking" },
- { "benchmark_all", OPT_BOOL | OPT_EXPERT, { &do_benchmark_all },
- "add timings for each task" },
-+ { "no_cvt_hw", OPT_BOOL | OPT_EXPERT, { &no_cvt_hw },
-+ "do not auto-convert hw frames to sw" },
- { "progress", HAS_ARG | OPT_EXPERT, { .func_arg = opt_progress },
- "write program-readable progress information", "url" },
- { "stdin", OPT_BOOL | OPT_EXPERT, { &stdin_interaction },
-
-From 27e0c78a2df53fb2337bee4c383cdb58cbbc717e Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Wed, 28 Apr 2021 10:16:39 +0100
-Subject: [PATCH 014/151] Add vout_drm
-
----
- configure | 4 +
- libavdevice/Makefile | 1 +
- libavdevice/alldevices.c | 1 +
- libavdevice/drm_vout.c | 638 +++++++++++++++++++++++++++++++++++++++
- 4 files changed, 644 insertions(+)
- create mode 100644 libavdevice/drm_vout.c
-
-diff --git a/configure b/configure
-index 199aa2b3d5..49744cab19 100755
---- a/configure
-+++ b/configure
-@@ -346,6 +346,7 @@ External library support:
- --enable-libnpp enable Nvidia Performance Primitives-based code [no]
- --enable-mmal enable Broadcom Multi-Media Abstraction Layer (Raspberry Pi) via MMAL [no]
- --enable-sand enable sand video formats [rpi]
-+ --enable-vout-drm enable the vout_drm module - for internal testing only [no]
- --disable-nvdec disable Nvidia video decoding acceleration (via hwaccel) [autodetect]
- --disable-nvenc disable Nvidia video encoding code [autodetect]
- --enable-omx enable OpenMAX IL code [no]
-@@ -1940,6 +1941,7 @@ FEATURE_LIST="
- small
- static
- swscale_alpha
-+ vout_drm
- "
-
- # this list should be kept in linking order
-@@ -3559,8 +3561,10 @@ sndio_indev_deps="sndio"
- sndio_outdev_deps="sndio"
- v4l2_indev_deps_any="linux_videodev2_h sys_videoio_h"
- v4l2_indev_suggest="libv4l2"
-+v4l2_outdev_deps="libdrm"
- v4l2_outdev_deps_any="linux_videodev2_h sys_videoio_h"
- v4l2_outdev_suggest="libv4l2"
-+vout_drm_outdev_deps="libdrm vout_drm"
- vfwcap_indev_deps="vfw32 vfwcap_defines"
- xcbgrab_indev_deps="libxcb"
- xcbgrab_indev_suggest="libxcb_shm libxcb_shape libxcb_xfixes"
-diff --git a/libavdevice/Makefile b/libavdevice/Makefile
-index 8a62822b69..36aac30186 100644
---- a/libavdevice/Makefile
-+++ b/libavdevice/Makefile
-@@ -48,6 +48,7 @@ OBJS-$(CONFIG_SNDIO_OUTDEV) += sndio_enc.o sndio.o
- OBJS-$(CONFIG_V4L2_INDEV) += v4l2.o v4l2-common.o timefilter.o
- OBJS-$(CONFIG_V4L2_OUTDEV) += v4l2enc.o v4l2-common.o
- OBJS-$(CONFIG_VFWCAP_INDEV) += vfwcap.o
-+OBJS-$(CONFIG_VOUT_DRM_OUTDEV) += drm_vout.o
- OBJS-$(CONFIG_XCBGRAB_INDEV) += xcbgrab.o
- OBJS-$(CONFIG_XV_OUTDEV) += xv.o
-
-diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c
-index 8a90fcb5d7..e2a8669f27 100644
---- a/libavdevice/alldevices.c
-+++ b/libavdevice/alldevices.c
-@@ -52,6 +52,7 @@ extern const FFOutputFormat ff_sndio_muxer;
- extern const AVInputFormat ff_v4l2_demuxer;
- extern const FFOutputFormat ff_v4l2_muxer;
- extern const AVInputFormat ff_vfwcap_demuxer;
-+extern const FFOutputFormat ff_vout_drm_muxer;
- extern const AVInputFormat ff_xcbgrab_demuxer;
- extern const FFOutputFormat ff_xv_muxer;
-
-diff --git a/libavdevice/drm_vout.c b/libavdevice/drm_vout.c
-new file mode 100644
-index 0000000000..cfb33ce7c3
---- /dev/null
-+++ b/libavdevice/drm_vout.c
-@@ -0,0 +1,638 @@
-+/*
-+ * Copyright (c) 2020 John Cox for Raspberry Pi Trading
-+ *
-+ * 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
-+ */
-+
-+
-+// *** This module is a work in progress and its utility is strictly
-+// limited to testing.
-+
-+#include "libavutil/opt.h"
-+#include "libavutil/pixdesc.h"
-+#include "libavutil/hwcontext_drm.h"
-+#include "libavformat/mux.h"
-+#include "avdevice.h"
-+
-+#include "pthread.h"
-+#include
-+#include
-+
-+#include
-+#include
-+
-+#define TRACE_ALL 0
-+
-+#define DRM_MODULE "vc4"
-+
-+#define ERRSTR strerror(errno)
-+
-+struct drm_setup {
-+ int conId;
-+ uint32_t crtcId;
-+ int crtcIdx;
-+ uint32_t planeId;
-+ unsigned int out_fourcc;
-+ struct {
-+ int x, y, width, height;
-+ } compose;
-+};
-+
-+typedef struct drm_aux_s {
-+ unsigned int fb_handle;
-+ uint32_t bo_handles[AV_DRM_MAX_PLANES];
-+ AVFrame * frame;
-+} drm_aux_t;
-+
-+// Aux size should only need to be 2, but on a few streams (Hobbit) under FKMS
-+// we get initial flicker probably due to dodgy drm timing
-+#define AUX_SIZE 3
-+typedef struct drm_display_env_s
-+{
-+ AVClass *class;
-+
-+ int drm_fd;
-+ uint32_t con_id;
-+ struct drm_setup setup;
-+ enum AVPixelFormat avfmt;
-+ int show_all;
-+
-+ unsigned int ano;
-+ drm_aux_t aux[AUX_SIZE];
-+
-+ pthread_t q_thread;
-+ sem_t q_sem_in;
-+ sem_t q_sem_out;
-+ int q_terminate;
-+ AVFrame * q_next;
-+
-+} drm_display_env_t;
-+
-+
-+static int drm_vout_write_trailer(AVFormatContext *s)
-+{
-+#if TRACE_ALL
-+ av_log(s, AV_LOG_DEBUG, "%s\n", __func__);
-+#endif
-+
-+ return 0;
-+}
-+
-+static int drm_vout_write_header(AVFormatContext *s)
-+{
-+ const AVCodecParameters * const par = s->streams[0]->codecpar;
-+
-+#if TRACE_ALL
-+ av_log(s, AV_LOG_DEBUG, "%s\n", __func__);
-+#endif
-+ if ( s->nb_streams > 1
-+ || par->codec_type != AVMEDIA_TYPE_VIDEO
-+ || par->codec_id != AV_CODEC_ID_WRAPPED_AVFRAME) {
-+ av_log(s, AV_LOG_ERROR, "Only supports one wrapped avframe stream\n");
-+ return AVERROR(EINVAL);
-+ }
-+
-+ return 0;
-+}
-+
-+static int find_plane(struct AVFormatContext * const avctx,
-+ const int drmfd, const int crtcidx, const uint32_t format,
-+ uint32_t * const pplane_id)
-+{
-+ drmModePlaneResPtr planes;
-+ drmModePlanePtr plane;
-+ unsigned int i;
-+ unsigned int j;
-+ int ret = 0;
-+
-+ planes = drmModeGetPlaneResources(drmfd);
-+ if (!planes)
-+ {
-+ av_log(avctx, AV_LOG_WARNING, "drmModeGetPlaneResources failed: %s\n", ERRSTR);
-+ return -1;
-+ }
-+
-+ for (i = 0; i < planes->count_planes; ++i) {
-+ plane = drmModeGetPlane(drmfd, planes->planes[i]);
-+ if (!planes)
-+ {
-+ av_log(avctx, AV_LOG_WARNING, "drmModeGetPlane failed: %s\n", ERRSTR);
-+ break;
-+ }
-+
-+ if (!(plane->possible_crtcs & (1 << crtcidx))) {
-+ drmModeFreePlane(plane);
-+ continue;
-+ }
-+
-+ for (j = 0; j < plane->count_formats; ++j) {
-+ if (plane->formats[j] == format)
-+ break;
-+ }
-+
-+ if (j == plane->count_formats) {
-+ drmModeFreePlane(plane);
-+ continue;
-+ }
-+
-+ *pplane_id = plane->plane_id;
-+ drmModeFreePlane(plane);
-+ break;
-+ }
-+
-+ if (i == planes->count_planes)
-+ ret = -1;
-+
-+ drmModeFreePlaneResources(planes);
-+ return ret;
-+}
-+
-+static void da_uninit(drm_display_env_t * const de, drm_aux_t * da)
-+{
-+ if (da->fb_handle != 0) {
-+ drmModeRmFB(de->drm_fd, da->fb_handle);
-+ da->fb_handle = 0;
-+ }
-+
-+ for (unsigned int i = 0; i != AV_DRM_MAX_PLANES; ++i) {
-+ if (da->bo_handles[i]) {
-+ struct drm_gem_close gem_close = {.handle = da->bo_handles[i]};
-+ drmIoctl(de->drm_fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
-+ da->bo_handles[i] = 0;
-+ }
-+ }
-+ av_frame_free(&da->frame);
-+}
-+
-+static int do_display(AVFormatContext * const s, drm_display_env_t * const de, AVFrame * frame)
-+{
-+ const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor*)frame->data[0];
-+ drm_aux_t * da = de->aux + de->ano;
-+ const uint32_t format = desc->layers[0].format;
-+ int ret = 0;
-+
-+#if TRACE_ALL
-+ av_log(s, AV_LOG_DEBUG, "<<< %s: fd=%d\n", __func__, desc->objects[0].fd);
-+#endif
-+
-+ if (de->setup.out_fourcc != format) {
-+ if (find_plane(s, de->drm_fd, de->setup.crtcIdx, format, &de->setup.planeId)) {
-+ av_frame_free(&frame);
-+ av_log(s, AV_LOG_WARNING, "No plane for format: %#x\n", format);
-+ return -1;
-+ }
-+ de->setup.out_fourcc = format;
-+ }
-+
-+ {
-+ drmVBlank vbl = {
-+ .request = {
-+ .type = DRM_VBLANK_RELATIVE,
-+ .sequence = 0
-+ }
-+ };
-+
-+ while (drmWaitVBlank(de->drm_fd, &vbl)) {
-+ if (errno != EINTR) {
-+// av_log(s, AV_LOG_WARNING, "drmWaitVBlank failed: %s\n", ERRSTR);
-+ break;
-+ }
-+ }
-+ }
-+
-+ da_uninit(de, da);
-+
-+ {
-+ uint32_t pitches[4] = {0};
-+ uint32_t offsets[4] = {0};
-+ uint64_t modifiers[4] = {0};
-+ uint32_t bo_handles[4] = {0};
-+ int i, j, n;
-+
-+ da->frame = frame;
-+
-+ for (i = 0; i < desc->nb_objects; ++i) {
-+ if (drmPrimeFDToHandle(de->drm_fd, desc->objects[i].fd, da->bo_handles + i) != 0) {
-+ av_log(s, AV_LOG_WARNING, "drmPrimeFDToHandle[%d](%d) failed: %s\n", i, desc->objects[i].fd, ERRSTR);
-+ return -1;
-+ }
-+ }
-+
-+ n = 0;
-+ for (i = 0; i < desc->nb_layers; ++i) {
-+ for (j = 0; j < desc->layers[i].nb_planes; ++j) {
-+ const AVDRMPlaneDescriptor * const p = desc->layers[i].planes + j;
-+ const AVDRMObjectDescriptor * const obj = desc->objects + p->object_index;
-+ pitches[n] = p->pitch;
-+ offsets[n] = p->offset;
-+ modifiers[n] = obj->format_modifier;
-+ bo_handles[n] = da->bo_handles[p->object_index];
-+ ++n;
-+ }
-+ }
-+
-+#if 1 && TRACE_ALL
-+ av_log(s, AV_LOG_DEBUG, "%dx%d, fmt: %x, boh=%d,%d,%d,%d, pitch=%d,%d,%d,%d,"
-+ " offset=%d,%d,%d,%d, mod=%llx,%llx,%llx,%llx\n",
-+ av_frame_cropped_width(frame),
-+ av_frame_cropped_height(frame),
-+ desc->layers[0].format,
-+ bo_handles[0],
-+ bo_handles[1],
-+ bo_handles[2],
-+ bo_handles[3],
-+ pitches[0],
-+ pitches[1],
-+ pitches[2],
-+ pitches[3],
-+ offsets[0],
-+ offsets[1],
-+ offsets[2],
-+ offsets[3],
-+ (long long)modifiers[0],
-+ (long long)modifiers[1],
-+ (long long)modifiers[2],
-+ (long long)modifiers[3]
-+ );
-+#endif
-+
-+ if (drmModeAddFB2WithModifiers(de->drm_fd,
-+ av_frame_cropped_width(frame),
-+ av_frame_cropped_height(frame),
-+ desc->layers[0].format, bo_handles,
-+ pitches, offsets, modifiers,
-+ &da->fb_handle, DRM_MODE_FB_MODIFIERS /** 0 if no mods */) != 0) {
-+ av_log(s, AV_LOG_WARNING, "drmModeAddFB2WithModifiers failed: %s\n", ERRSTR);
-+ return -1;
-+ }
-+ }
-+
-+ ret = drmModeSetPlane(de->drm_fd, de->setup.planeId, de->setup.crtcId,
-+ da->fb_handle, 0,
-+ de->setup.compose.x, de->setup.compose.y,
-+ de->setup.compose.width,
-+ de->setup.compose.height,
-+ 0, 0,
-+ av_frame_cropped_width(frame) << 16,
-+ av_frame_cropped_height(frame) << 16);
-+
-+ if (ret != 0) {
-+ av_log(s, AV_LOG_WARNING, "drmModeSetPlane failed: %s\n", ERRSTR);
-+ }
-+
-+ de->ano = de->ano + 1 >= AUX_SIZE ? 0 : de->ano + 1;
-+
-+ return ret;
-+}
-+
-+static int do_sem_wait(sem_t * const sem, const int nowait)
-+{
-+ while (nowait ? sem_trywait(sem) : sem_wait(sem)) {
-+ if (errno != EINTR)
-+ return -errno;
-+ }
-+ return 0;
-+}
-+
-+static void * display_thread(void * v)
-+{
-+ AVFormatContext * const s = v;
-+ drm_display_env_t * const de = s->priv_data;
-+ int i;
-+
-+#if TRACE_ALL
-+ av_log(s, AV_LOG_DEBUG, "<<< %s\n", __func__);
-+#endif
-+
-+ sem_post(&de->q_sem_out);
-+
-+ for (;;) {
-+ AVFrame * frame;
-+
-+ do_sem_wait(&de->q_sem_in, 0);
-+
-+ if (de->q_terminate)
-+ break;
-+
-+ frame = de->q_next;
-+ de->q_next = NULL;
-+ sem_post(&de->q_sem_out);
-+
-+ do_display(s, de, frame);
-+ }
-+
-+#if TRACE_ALL
-+ av_log(s, AV_LOG_DEBUG, ">>> %s\n", __func__);
-+#endif
-+
-+ for (i = 0; i != AUX_SIZE; ++i)
-+ da_uninit(de, de->aux + i);
-+
-+ av_frame_free(&de->q_next);
-+
-+ return NULL;
-+}
-+
-+static int drm_vout_write_packet(AVFormatContext *s, AVPacket *pkt)
-+{
-+ const AVFrame * const src_frame = (AVFrame *)pkt->data;
-+ AVFrame * frame;
-+ drm_display_env_t * const de = s->priv_data;
-+ int ret;
-+
-+#if TRACE_ALL
-+ av_log(s, AV_LOG_DEBUG, "%s\n", __func__);
-+#endif
-+
-+ if ((src_frame->flags & AV_FRAME_FLAG_CORRUPT) != 0) {
-+ av_log(s, AV_LOG_WARNING, "Discard corrupt frame: fmt=%d, ts=%" PRId64 "\n", src_frame->format, src_frame->pts);
-+ return 0;
-+ }
-+
-+ if (src_frame->format == AV_PIX_FMT_DRM_PRIME) {
-+ frame = av_frame_alloc();
-+ av_frame_ref(frame, src_frame);
-+ }
-+ else if (src_frame->format == AV_PIX_FMT_VAAPI) {
-+ frame = av_frame_alloc();
-+ frame->format = AV_PIX_FMT_DRM_PRIME;
-+ if (av_hwframe_map(frame, src_frame, 0) != 0)
-+ {
-+ av_log(s, AV_LOG_WARNING, "Failed to map frame (format=%d) to DRM_PRiME\n", src_frame->format);
-+ av_frame_free(&frame);
-+ return AVERROR(EINVAL);
-+ }
-+ }
-+ else {
-+ av_log(s, AV_LOG_WARNING, "Frame (format=%d) not DRM_PRiME\n", src_frame->format);
-+ return AVERROR(EINVAL);
-+ }
-+
-+ ret = do_sem_wait(&de->q_sem_out, !de->show_all);
-+ if (ret) {
-+ av_frame_free(&frame);
-+ }
-+ else {
-+ de->q_next = frame;
-+ sem_post(&de->q_sem_in);
-+ }
-+
-+ return 0;
-+}
-+
-+static int drm_vout_write_frame(AVFormatContext *s, int stream_index, AVFrame **ppframe,
-+ unsigned flags)
-+{
-+ av_log(s, AV_LOG_ERROR, "%s: NIF: idx=%d, flags=%#x\n", __func__, stream_index, flags);
-+ return AVERROR_PATCHWELCOME;
-+}
-+
-+static int drm_vout_control_message(AVFormatContext *s, int type, void *data, size_t data_size)
-+{
-+#if TRACE_ALL
-+ av_log(s, AV_LOG_DEBUG, "%s: %d\n", __func__, type);
-+#endif
-+ switch(type) {
-+ case AV_APP_TO_DEV_WINDOW_REPAINT:
-+ return 0;
-+ default:
-+ break;
-+ }
-+ return AVERROR(ENOSYS);
-+}
-+
-+static int find_crtc(struct AVFormatContext * const avctx, int drmfd, struct drm_setup *s, uint32_t * const pConId)
-+{
-+ int ret = -1;
-+ int i;
-+ drmModeRes *res = drmModeGetResources(drmfd);
-+ drmModeConnector *c;
-+
-+ if(!res)
-+ {
-+ printf( "drmModeGetResources failed: %s\n", ERRSTR);
-+ return -1;
-+ }
-+
-+ if (res->count_crtcs <= 0)
-+ {
-+ printf( "drm: no crts\n");
-+ goto fail_res;
-+ }
-+
-+ if (!s->conId) {
-+ fprintf(stderr,
-+ "No connector ID specified. Choosing default from list:\n");
-+
-+ for (i = 0; i < res->count_connectors; i++) {
-+ drmModeConnector *con =
-+ drmModeGetConnector(drmfd, res->connectors[i]);
-+ drmModeEncoder *enc = NULL;
-+ drmModeCrtc *crtc = NULL;
-+
-+ if (con->encoder_id) {
-+ enc = drmModeGetEncoder(drmfd, con->encoder_id);
-+ if (enc->crtc_id) {
-+ crtc = drmModeGetCrtc(drmfd, enc->crtc_id);
-+ }
-+ }
-+
-+ if (!s->conId && crtc) {
-+ s->conId = con->connector_id;
-+ s->crtcId = crtc->crtc_id;
-+ }
-+
-+ av_log(avctx, AV_LOG_DEBUG, "Connector %d (crtc %d): type %d, %dx%d%s\n",
-+ con->connector_id,
-+ crtc ? crtc->crtc_id : 0,
-+ con->connector_type,
-+ crtc ? crtc->width : 0,
-+ crtc ? crtc->height : 0,
-+ (s->conId == (int)con->connector_id ?
-+ " (chosen)" : ""));
-+ }
-+
-+ if (!s->conId) {
-+ av_log(avctx, AV_LOG_ERROR,
-+ "No suitable enabled connector found.\n");
-+ return -1;;
-+ }
-+ }
-+
-+ s->crtcIdx = -1;
-+
-+ for (i = 0; i < res->count_crtcs; ++i) {
-+ if (s->crtcId == res->crtcs[i]) {
-+ s->crtcIdx = i;
-+ break;
-+ }
-+ }
-+
-+ if (s->crtcIdx == -1)
-+ {
-+ av_log(avctx, AV_LOG_WARNING, "drm: CRTC %u not found\n", s->crtcId);
-+ goto fail_res;
-+ }
-+
-+ if (res->count_connectors <= 0)
-+ {
-+ av_log(avctx, AV_LOG_WARNING, "drm: no connectors\n");
-+ goto fail_res;
-+ }
-+
-+ c = drmModeGetConnector(drmfd, s->conId);
-+ if (!c)
-+ {
-+ av_log(avctx, AV_LOG_WARNING, "drmModeGetConnector failed: %s\n", ERRSTR);
-+ goto fail_res;
-+ }
-+
-+ if (!c->count_modes)
-+ {
-+ av_log(avctx, AV_LOG_WARNING, "connector supports no mode\n");
-+ goto fail_conn;
-+ }
-+
-+ {
-+ drmModeCrtc *crtc = drmModeGetCrtc(drmfd, s->crtcId);
-+ s->compose.x = crtc->x;
-+ s->compose.y = crtc->y;
-+ s->compose.width = crtc->width;
-+ s->compose.height = crtc->height;
-+ drmModeFreeCrtc(crtc);
-+ }
-+
-+ if (pConId)
-+ *pConId = c->connector_id;
-+ ret = 0;
-+
-+fail_conn:
-+ drmModeFreeConnector(c);
-+
-+fail_res:
-+ drmModeFreeResources(res);
-+
-+ return ret;
-+}
-+
-+// deinit is called if init fails so no need to clean up explicity here
-+static int drm_vout_init(struct AVFormatContext * s)
-+{
-+ drm_display_env_t * const de = s->priv_data;
-+ int rv;
-+ const char * drm_module = DRM_MODULE;
-+
-+ av_log(s, AV_LOG_DEBUG, "<<< %s\n", __func__);
-+
-+ de->drm_fd = -1;
-+ de->con_id = 0;
-+ de->setup = (struct drm_setup){0};
-+ de->q_terminate = 0;
-+
-+ if ((de->drm_fd = drmOpen(drm_module, NULL)) < 0)
-+ {
-+ rv = AVERROR(errno);
-+ av_log(s, AV_LOG_ERROR, "Failed to drmOpen %s: %s\n", drm_module, av_err2str(rv));
-+ return rv;
-+ }
-+
-+ if (find_crtc(s, de->drm_fd, &de->setup, &de->con_id) != 0)
-+ {
-+ av_log(s, AV_LOG_ERROR, "failed to find valid mode\n");
-+ rv = AVERROR(EINVAL);
-+ goto fail_close;
-+ }
-+
-+ sem_init(&de->q_sem_in, 0, 0);
-+ sem_init(&de->q_sem_out, 0, 0);
-+ if (pthread_create(&de->q_thread, NULL, display_thread, s)) {
-+ rv = AVERROR(errno);
-+ av_log(s, AV_LOG_ERROR, "Failed to creatye display thread: %s\n", av_err2str(rv));
-+ goto fail_close;
-+ }
-+
-+ av_log(s, AV_LOG_DEBUG, ">>> %s\n", __func__);
-+
-+ return 0;
-+
-+fail_close:
-+ close(de->drm_fd);
-+ de->drm_fd = -1;
-+ av_log(s, AV_LOG_DEBUG, ">>> %s: FAIL\n", __func__);
-+
-+ return rv;
-+}
-+
-+static void drm_vout_deinit(struct AVFormatContext * s)
-+{
-+ drm_display_env_t * const de = s->priv_data;
-+
-+ av_log(s, AV_LOG_DEBUG, "<<< %s\n", __func__);
-+
-+ de->q_terminate = 1;
-+ sem_post(&de->q_sem_in);
-+ pthread_join(de->q_thread, NULL);
-+ sem_destroy(&de->q_sem_in);
-+ sem_destroy(&de->q_sem_out);
-+
-+ for (unsigned int i = 0; i != AUX_SIZE; ++i)
-+ da_uninit(de, de->aux + i);
-+
-+ av_frame_free(&de->q_next);
-+
-+ if (de->drm_fd >= 0) {
-+ close(de->drm_fd);
-+ de->drm_fd = -1;
-+ }
-+
-+ av_log(s, AV_LOG_DEBUG, ">>> %s\n", __func__);
-+}
-+
-+
-+#define OFFSET(x) offsetof(drm_display_env_t, x)
-+static const AVOption options[] = {
-+ { "show_all", "show all frames", OFFSET(show_all), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
-+ { NULL }
-+};
-+
-+static const AVClass drm_vout_class = {
-+ .class_name = "drm vid outdev",
-+ .item_name = av_default_item_name,
-+ .option = options,
-+ .version = LIBAVUTIL_VERSION_INT,
-+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT,
-+};
-+
-+FFOutputFormat ff_vout_drm_muxer = {
-+ .p = {
-+ .name = "vout_drm",
-+ .long_name = NULL_IF_CONFIG_SMALL("Drm video output device"),
-+ .audio_codec = AV_CODEC_ID_NONE,
-+ .video_codec = AV_CODEC_ID_WRAPPED_AVFRAME,
-+ .flags = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS,
-+ .priv_class = &drm_vout_class,
-+ },
-+ .priv_data_size = sizeof(drm_display_env_t),
-+ .write_header = drm_vout_write_header,
-+ .write_packet = drm_vout_write_packet,
-+ .write_uncoded_frame = drm_vout_write_frame,
-+ .write_trailer = drm_vout_write_trailer,
-+ .control_message = drm_vout_control_message,
-+ .init = drm_vout_init,
-+ .deinit = drm_vout_deinit,
-+};
-+
-
-From cc536672adf4eefeaec16e9808f583c693ad7819 Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Wed, 28 Apr 2021 11:34:18 +0100
-Subject: [PATCH 015/151] Add vout_egl
-
----
- configure | 6 +
- libavdevice/Makefile | 1 +
- libavdevice/alldevices.c | 1 +
- libavdevice/egl_vout.c | 811 +++++++++++++++++++++++++++++++++++++++
- 4 files changed, 819 insertions(+)
- create mode 100644 libavdevice/egl_vout.c
-
-diff --git a/configure b/configure
-index 49744cab19..b41663c794 100755
---- a/configure
-+++ b/configure
-@@ -347,6 +347,7 @@ External library support:
- --enable-mmal enable Broadcom Multi-Media Abstraction Layer (Raspberry Pi) via MMAL [no]
- --enable-sand enable sand video formats [rpi]
- --enable-vout-drm enable the vout_drm module - for internal testing only [no]
-+ --enable-vout-egl enable the vout_egl module - for internal testing only [no]
- --disable-nvdec disable Nvidia video decoding acceleration (via hwaccel) [autodetect]
- --disable-nvenc disable Nvidia video encoding code [autodetect]
- --enable-omx enable OpenMAX IL code [no]
-@@ -1818,6 +1819,7 @@ EXTERNAL_LIBRARY_LIST="
- libdav1d
- libdc1394
- libdrm
-+ epoxy
- libflite
- libfontconfig
- libfreetype
-@@ -1942,6 +1944,7 @@ FEATURE_LIST="
- static
- swscale_alpha
- vout_drm
-+ vout_egl
- "
-
- # this list should be kept in linking order
-@@ -3565,6 +3568,8 @@ v4l2_outdev_deps="libdrm"
- v4l2_outdev_deps_any="linux_videodev2_h sys_videoio_h"
- v4l2_outdev_suggest="libv4l2"
- vout_drm_outdev_deps="libdrm vout_drm"
-+vout_egl_outdev_deps="xlib"
-+vout_egl_outdev_select="epoxy"
- vfwcap_indev_deps="vfw32 vfwcap_defines"
- xcbgrab_indev_deps="libxcb"
- xcbgrab_indev_suggest="libxcb_shm libxcb_shape libxcb_xfixes"
-@@ -6596,6 +6601,7 @@ enabled libdav1d && require_pkg_config libdav1d "dav1d >= 0.5.0" "dav1d
- enabled libdavs2 && require_pkg_config libdavs2 "davs2 >= 1.6.0" davs2.h davs2_decoder_open
- enabled libdc1394 && require_pkg_config libdc1394 libdc1394-2 dc1394/dc1394.h dc1394_new
- enabled libdrm && require_pkg_config libdrm libdrm xf86drm.h drmGetVersion
-+enabled epoxy && require_pkg_config epoxy epoxy epoxy/egl.h epoxy_egl_version
- enabled libfdk_aac && { check_pkg_config libfdk_aac fdk-aac "fdk-aac/aacenc_lib.h" aacEncOpen ||
- { require libfdk_aac fdk-aac/aacenc_lib.h aacEncOpen -lfdk-aac &&
- warn "using libfdk without pkg-config"; } }
-diff --git a/libavdevice/Makefile b/libavdevice/Makefile
-index 36aac30186..0989cb895f 100644
---- a/libavdevice/Makefile
-+++ b/libavdevice/Makefile
-@@ -49,6 +49,7 @@ OBJS-$(CONFIG_V4L2_INDEV) += v4l2.o v4l2-common.o timefilter.o
- OBJS-$(CONFIG_V4L2_OUTDEV) += v4l2enc.o v4l2-common.o
- OBJS-$(CONFIG_VFWCAP_INDEV) += vfwcap.o
- OBJS-$(CONFIG_VOUT_DRM_OUTDEV) += drm_vout.o
-+OBJS-$(CONFIG_VOUT_EGL_OUTDEV) += egl_vout.o
- OBJS-$(CONFIG_XCBGRAB_INDEV) += xcbgrab.o
- OBJS-$(CONFIG_XV_OUTDEV) += xv.o
-
-diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c
-index e2a8669f27..ffb410b92d 100644
---- a/libavdevice/alldevices.c
-+++ b/libavdevice/alldevices.c
-@@ -53,6 +53,7 @@ extern const AVInputFormat ff_v4l2_demuxer;
- extern const FFOutputFormat ff_v4l2_muxer;
- extern const AVInputFormat ff_vfwcap_demuxer;
- extern const FFOutputFormat ff_vout_drm_muxer;
-+extern const FFOutputFormat ff_vout_egl_muxer;
- extern const AVInputFormat ff_xcbgrab_demuxer;
- extern const FFOutputFormat ff_xv_muxer;
-
-diff --git a/libavdevice/egl_vout.c b/libavdevice/egl_vout.c
-new file mode 100644
-index 0000000000..7b9c610ace
---- /dev/null
-+++ b/libavdevice/egl_vout.c
-@@ -0,0 +1,811 @@
-+/*
-+ * Copyright (c) 2020 John Cox for Raspberry Pi Trading
-+ *
-+ * 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
-+ */
-+
-+
-+// *** This module is a work in progress and its utility is strictly
-+// limited to testing.
-+// Amongst other issues it doesn't wait for the pic to be displayed before
-+// returning the buffer so flikering does occur.
-+
-+#include
-+#include
-+
-+#include "libavutil/opt.h"
-+#include "libavutil/avassert.h"
-+#include "libavutil/pixdesc.h"
-+#include "libavutil/imgutils.h"
-+#include "libavutil/hwcontext_drm.h"
-+#include "libavformat/mux.h"
-+#include "avdevice.h"
-+
-+#include "pthread.h"
-+#include
-+#include
-+#include
-+
-+#include
-+#include
-+
-+#include "libavutil/rpi_sand_fns.h"
-+
-+#define TRACE_ALL 0
-+
-+struct egl_setup {
-+ int conId;
-+
-+ Display *dpy;
-+ EGLDisplay egl_dpy;
-+ EGLContext ctx;
-+ EGLSurface surf;
-+ Window win;
-+
-+ uint32_t crtcId;
-+ int crtcIdx;
-+ uint32_t planeId;
-+ struct {
-+ int x, y, width, height;
-+ } compose;
-+};
-+
-+typedef struct egl_aux_s {
-+ int fd;
-+ GLuint texture;
-+
-+} egl_aux_t;
-+
-+typedef struct egl_display_env_s
-+{
-+ AVClass *class;
-+
-+ struct egl_setup setup;
-+ enum AVPixelFormat avfmt;
-+
-+ int show_all;
-+ int window_width, window_height;
-+ int window_x, window_y;
-+ int fullscreen;
-+
-+ egl_aux_t aux[32];
-+
-+ pthread_t q_thread;
-+ pthread_mutex_t q_lock;
-+ sem_t display_start_sem;
-+ sem_t q_sem;
-+ int q_terminate;
-+ AVFrame * q_this;
-+ AVFrame * q_next;
-+
-+} egl_display_env_t;
-+
-+
-+/**
-+ * Remove window border/decorations.
-+ */
-+static void
-+no_border( Display *dpy, Window w)
-+{
-+ static const unsigned MWM_HINTS_DECORATIONS = (1 << 1);
-+ static const int PROP_MOTIF_WM_HINTS_ELEMENTS = 5;
-+
-+ typedef struct
-+ {
-+ unsigned long flags;
-+ unsigned long functions;
-+ unsigned long decorations;
-+ long inputMode;
-+ unsigned long status;
-+ } PropMotifWmHints;
-+
-+ PropMotifWmHints motif_hints;
-+ Atom prop, proptype;
-+ unsigned long flags = 0;
-+
-+ /* setup the property */
-+ motif_hints.flags = MWM_HINTS_DECORATIONS;
-+ motif_hints.decorations = flags;
-+
-+ /* get the atom for the property */
-+ prop = XInternAtom( dpy, "_MOTIF_WM_HINTS", True );
-+ if (!prop) {
-+ /* something went wrong! */
-+ return;
-+ }
-+
-+ /* not sure this is correct, seems to work, XA_WM_HINTS didn't work */
-+ proptype = prop;
-+
-+ XChangeProperty( dpy, w, /* display, window */
-+ prop, proptype, /* property, type */
-+ 32, /* format: 32-bit datums */
-+ PropModeReplace, /* mode */
-+ (unsigned char *) &motif_hints, /* data */
-+ PROP_MOTIF_WM_HINTS_ELEMENTS /* nelements */
-+ );
-+}
-+
-+
-+/*
-+ * Create an RGB, double-buffered window.
-+ * Return the window and context handles.
-+ */
-+static int
-+make_window(struct AVFormatContext * const s,
-+ egl_display_env_t * const de,
-+ Display *dpy, EGLDisplay egl_dpy, const char *name,
-+ Window *winRet, EGLContext *ctxRet, EGLSurface *surfRet)
-+{
-+ int scrnum = DefaultScreen( dpy );
-+ XSetWindowAttributes attr;
-+ unsigned long mask;
-+ Window root = RootWindow( dpy, scrnum );
-+ Window win;
-+ EGLContext ctx;
-+ const int fullscreen = de->fullscreen;
-+ EGLConfig config;
-+ int x = de->window_x;
-+ int y = de->window_y;
-+ int width = de->window_width ? de->window_width : 1280;
-+ int height = de->window_height ? de->window_height : 720;
-+
-+
-+ if (fullscreen) {
-+ int scrnum = DefaultScreen(dpy);
-+
-+ x = 0; y = 0;
-+ width = DisplayWidth(dpy, scrnum);
-+ height = DisplayHeight(dpy, scrnum);
-+ }
-+
-+ {
-+ EGLint num_configs;
-+ static const EGLint attribs[] = {
-+ EGL_RED_SIZE, 1,
-+ EGL_GREEN_SIZE, 1,
-+ EGL_BLUE_SIZE, 1,
-+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-+ EGL_NONE
-+ };
-+
-+ if (!eglChooseConfig(egl_dpy, attribs, &config, 1, &num_configs)) {
-+ av_log(s, AV_LOG_ERROR, "Error: couldn't get an EGL visual config\n");
-+ return -1;
-+ }
-+ }
-+
-+ {
-+ EGLint vid;
-+ if (!eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
-+ av_log(s, AV_LOG_ERROR, "Error: eglGetConfigAttrib() failed\n");
-+ return -1;
-+ }
-+
-+ {
-+ XVisualInfo visTemplate = {
-+ .visualid = vid,
-+ };
-+ int num_visuals;
-+ XVisualInfo *visinfo = XGetVisualInfo(dpy, VisualIDMask,
-+ &visTemplate, &num_visuals);
-+
-+ /* window attributes */
-+ attr.background_pixel = 0;
-+ attr.border_pixel = 0;
-+ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
-+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
-+ /* XXX this is a bad way to get a borderless window! */
-+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
-+
-+ win = XCreateWindow( dpy, root, x, y, width, height,
-+ 0, visinfo->depth, InputOutput,
-+ visinfo->visual, mask, &attr );
-+ XFree(visinfo);
-+ }
-+ }
-+
-+ if (fullscreen)
-+ no_border(dpy, win);
-+
-+ /* set hints and properties */
-+ {
-+ XSizeHints sizehints;
-+ sizehints.x = x;
-+ sizehints.y = y;
-+ sizehints.width = width;
-+ sizehints.height = height;
-+ sizehints.flags = USSize | USPosition;
-+ XSetNormalHints(dpy, win, &sizehints);
-+ XSetStandardProperties(dpy, win, name, name,
-+ None, (char **)NULL, 0, &sizehints);
-+ }
-+
-+ eglBindAPI(EGL_OPENGL_ES_API);
-+
-+ {
-+ static const EGLint ctx_attribs[] = {
-+ EGL_CONTEXT_CLIENT_VERSION, 2,
-+ EGL_NONE
-+ };
-+ ctx = eglCreateContext(egl_dpy, config, EGL_NO_CONTEXT, ctx_attribs );
-+ if (!ctx) {
-+ av_log(s, AV_LOG_ERROR, "Error: eglCreateContext failed\n");
-+ return -1;
-+ }
-+ }
-+
-+
-+ XMapWindow(dpy, win);
-+
-+ {
-+ EGLSurface surf = eglCreateWindowSurface(egl_dpy, config, (EGLNativeWindowType)win, NULL);
-+ if (!surf) {
-+ av_log(s, AV_LOG_ERROR, "Error: eglCreateWindowSurface failed\n");
-+ return -1;
-+ }
-+
-+ if (!eglMakeCurrent(egl_dpy, surf, surf, ctx)) {
-+ av_log(s, AV_LOG_ERROR, "Error: eglCreateContext failed\n");
-+ return -1;
-+ }
-+
-+ *winRet = win;
-+ *ctxRet = ctx;
-+ *surfRet = surf;
-+ }
-+
-+ return 0;
-+}
-+
-+static GLint
-+compile_shader(struct AVFormatContext * const avctx, GLenum target, const char *source)
-+{
-+ GLuint s = glCreateShader(target);
-+
-+ if (s == 0) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to create shader\n");
-+ return 0;
-+ }
-+
-+ glShaderSource(s, 1, (const GLchar **) &source, NULL);
-+ glCompileShader(s);
-+
-+ {
-+ GLint ok;
-+ glGetShaderiv(s, GL_COMPILE_STATUS, &ok);
-+
-+ if (!ok) {
-+ GLchar *info;
-+ GLint size;
-+
-+ glGetShaderiv(s, GL_INFO_LOG_LENGTH, &size);
-+ info = malloc(size);
-+
-+ glGetShaderInfoLog(s, size, NULL, info);
-+ av_log(avctx, AV_LOG_ERROR, "Failed to compile shader: %ssource:\n%s\n", info, source);
-+
-+ return 0;
-+ }
-+ }
-+
-+ return s;
-+}
-+
-+static GLuint link_program(struct AVFormatContext * const s, GLint vs, GLint fs)
-+{
-+ GLuint prog = glCreateProgram();
-+
-+ if (prog == 0) {
-+ av_log(s, AV_LOG_ERROR, "Failed to create program\n");
-+ return 0;
-+ }
-+
-+ glAttachShader(prog, vs);
-+ glAttachShader(prog, fs);
-+ glLinkProgram(prog);
-+
-+ {
-+ GLint ok;
-+ glGetProgramiv(prog, GL_LINK_STATUS, &ok);
-+ if (!ok) {
-+ /* Some drivers return a size of 1 for an empty log. This is the size
-+ * of a log that contains only a terminating NUL character.
-+ */
-+ GLint size;
-+ GLchar *info = NULL;
-+ glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &size);
-+ if (size > 1) {
-+ info = malloc(size);
-+ glGetProgramInfoLog(prog, size, NULL, info);
-+ }
-+
-+ av_log(s, AV_LOG_ERROR, "Failed to link: %s\n",
-+ (info != NULL) ? info : "");
-+ return 0;
-+ }
-+ }
-+
-+ return prog;
-+}
-+
-+static int
-+gl_setup(struct AVFormatContext * const s)
-+{
-+ const char *vs =
-+ "attribute vec4 pos;\n"
-+ "varying vec2 texcoord;\n"
-+ "\n"
-+ "void main() {\n"
-+ " gl_Position = pos;\n"
-+ " texcoord.x = (pos.x + 1.0) / 2.0;\n"
-+ " texcoord.y = (-pos.y + 1.0) / 2.0;\n"
-+ "}\n";
-+ const char *fs =
-+ "#extension GL_OES_EGL_image_external : enable\n"
-+ "precision mediump float;\n"
-+ "uniform samplerExternalOES s;\n"
-+ "varying vec2 texcoord;\n"
-+ "void main() {\n"
-+ " gl_FragColor = texture2D(s, texcoord);\n"
-+ "}\n";
-+
-+ GLuint vs_s;
-+ GLuint fs_s;
-+ GLuint prog;
-+
-+ if (!(vs_s = compile_shader(s, GL_VERTEX_SHADER, vs)) ||
-+ !(fs_s = compile_shader(s, GL_FRAGMENT_SHADER, fs)) ||
-+ !(prog = link_program(s, vs_s, fs_s)))
-+ return -1;
-+
-+ glUseProgram(prog);
-+
-+ {
-+ static const float verts[] = {
-+ -1, -1,
-+ 1, -1,
-+ 1, 1,
-+ -1, 1,
-+ };
-+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts);
-+ }
-+
-+ glEnableVertexAttribArray(0);
-+ return 0;
-+}
-+
-+static int egl_vout_write_trailer(AVFormatContext *s)
-+{
-+#if TRACE_ALL
-+ av_log(s, AV_LOG_INFO, "%s\n", __func__);
-+#endif
-+
-+ return 0;
-+}
-+
-+static int egl_vout_write_header(AVFormatContext *s)
-+{
-+ const AVCodecParameters * const par = s->streams[0]->codecpar;
-+
-+#if TRACE_ALL
-+ av_log(s, AV_LOG_INFO, "%s\n", __func__);
-+#endif
-+ if ( s->nb_streams > 1
-+ || par->codec_type != AVMEDIA_TYPE_VIDEO
-+ || par->codec_id != AV_CODEC_ID_WRAPPED_AVFRAME) {
-+ av_log(s, AV_LOG_ERROR, "Only supports one wrapped avframe stream\n");
-+ return AVERROR(EINVAL);
-+ }
-+
-+ return 0;
-+}
-+
-+
-+static int do_display(AVFormatContext * const s, egl_display_env_t * const de, AVFrame * const frame)
-+{
-+ const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor*)frame->data[0];
-+ egl_aux_t * da = NULL;
-+ unsigned int i;
-+
-+#if TRACE_ALL
-+ av_log(s, AV_LOG_INFO, "<<< %s\n", __func__);
-+#endif
-+
-+ for (i = 0; i != 32; ++i) {
-+ if (de->aux[i].fd == -1 || de->aux[i].fd == desc->objects[0].fd) {
-+ da = de->aux + i;
-+ break;
-+ }
-+ }
-+
-+ if (da == NULL) {
-+ av_log(s, AV_LOG_INFO, "%s: Out of handles\n", __func__);
-+ return AVERROR(EINVAL);
-+ }
-+
-+ if (da->texture == 0) {
-+ EGLint attribs[50];
-+ EGLint * a = attribs;
-+ int i, j;
-+ static const EGLint anames[] = {
-+ EGL_DMA_BUF_PLANE0_FD_EXT,
-+ EGL_DMA_BUF_PLANE0_OFFSET_EXT,
-+ EGL_DMA_BUF_PLANE0_PITCH_EXT,
-+ EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT,
-+ EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT,
-+ EGL_DMA_BUF_PLANE1_FD_EXT,
-+ EGL_DMA_BUF_PLANE1_OFFSET_EXT,
-+ EGL_DMA_BUF_PLANE1_PITCH_EXT,
-+ EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
-+ EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT,
-+ EGL_DMA_BUF_PLANE2_FD_EXT,
-+ EGL_DMA_BUF_PLANE2_OFFSET_EXT,
-+ EGL_DMA_BUF_PLANE2_PITCH_EXT,
-+ EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT,
-+ EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT,
-+ };
-+ const EGLint * b = anames;
-+
-+ *a++ = EGL_WIDTH;
-+ *a++ = av_frame_cropped_width(frame);
-+ *a++ = EGL_HEIGHT;
-+ *a++ = av_frame_cropped_height(frame);
-+ *a++ = EGL_LINUX_DRM_FOURCC_EXT;
-+ *a++ = desc->layers[0].format;
-+
-+ for (i = 0; i < desc->nb_layers; ++i) {
-+ for (j = 0; j < desc->layers[i].nb_planes; ++j) {
-+ const AVDRMPlaneDescriptor * const p = desc->layers[i].planes + j;
-+ const AVDRMObjectDescriptor * const obj = desc->objects + p->object_index;
-+ *a++ = *b++;
-+ *a++ = obj->fd;
-+ *a++ = *b++;
-+ *a++ = p->offset;
-+ *a++ = *b++;
-+ *a++ = p->pitch;
-+ if (obj->format_modifier == 0) {
-+ b += 2;
-+ }
-+ else {
-+ *a++ = *b++;
-+ *a++ = (EGLint)(obj->format_modifier & 0xFFFFFFFF);
-+ *a++ = *b++;
-+ *a++ = (EGLint)(obj->format_modifier >> 32);
-+ }
-+ }
-+ }
-+
-+ *a = EGL_NONE;
-+
-+#if TRACE_ALL
-+ for (a = attribs, i = 0; *a != EGL_NONE; a += 2, ++i) {
-+ av_log(s, AV_LOG_INFO, "[%2d] %4x: %d\n", i, a[0], a[1]);
-+ }
-+#endif
-+ {
-+ const EGLImage image = eglCreateImageKHR(de->setup.egl_dpy,
-+ EGL_NO_CONTEXT,
-+ EGL_LINUX_DMA_BUF_EXT,
-+ NULL, attribs);
-+ if (!image) {
-+ av_log(s, AV_LOG_ERROR, "Failed to import fd %d\n", desc->objects[0].fd);
-+ return -1;
-+ }
-+
-+ glGenTextures(1, &da->texture);
-+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, da->texture);
-+ glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-+ glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-+ glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image);
-+
-+ eglDestroyImageKHR(de->setup.egl_dpy, image);
-+ }
-+
-+ da->fd = desc->objects[0].fd;
-+
-+#if 0
-+ av_log(s, AV_LOG_INFO, "%dx%d, fmt: %x, boh=%d,%d,%d,%d, pitch=%d,%d,%d,%d,"
-+ " offset=%d,%d,%d,%d, mod=%llx,%llx,%llx,%llx\n",
-+ av_frame_cropped_width(frame),
-+ av_frame_cropped_height(frame),
-+ desc->layers[0].format,
-+ bo_plane_handles[0],
-+ bo_plane_handles[1],
-+ bo_plane_handles[2],
-+ bo_plane_handles[3],
-+ pitches[0],
-+ pitches[1],
-+ pitches[2],
-+ pitches[3],
-+ offsets[0],
-+ offsets[1],
-+ offsets[2],
-+ offsets[3],
-+ (long long)modifiers[0],
-+ (long long)modifiers[1],
-+ (long long)modifiers[2],
-+ (long long)modifiers[3]
-+ );
-+#endif
-+ }
-+
-+ glClearColor(0.5, 0.5, 0.5, 0.5);
-+ glClear(GL_COLOR_BUFFER_BIT);
-+
-+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, da->texture);
-+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-+ eglSwapBuffers(de->setup.egl_dpy, de->setup.surf);
-+
-+ glDeleteTextures(1, &da->texture);
-+ da->texture = 0;
-+ da->fd = -1;
-+
-+ return 0;
-+}
-+
-+static void * display_thread(void * v)
-+{
-+ AVFormatContext * const s = v;
-+ egl_display_env_t * const de = s->priv_data;
-+
-+#if TRACE_ALL
-+ av_log(s, AV_LOG_INFO, "<<< %s\n", __func__);
-+#endif
-+ {
-+ EGLint egl_major, egl_minor;
-+
-+ de->setup.dpy = XOpenDisplay(NULL);
-+ if (!de->setup.dpy) {
-+ av_log(s, AV_LOG_ERROR, "Couldn't open X display\n");
-+ goto fail;
-+ }
-+
-+ de->setup.egl_dpy = eglGetDisplay(de->setup.dpy);
-+ if (!de->setup.egl_dpy) {
-+ av_log(s, AV_LOG_ERROR, "eglGetDisplay() failed\n");
-+ goto fail;
-+ }
-+
-+ if (!eglInitialize(de->setup.egl_dpy, &egl_major, &egl_minor)) {
-+ av_log(s, AV_LOG_ERROR, "Error: eglInitialize() failed\n");
-+ goto fail;
-+ }
-+
-+ av_log(s, AV_LOG_INFO, "EGL version %d.%d\n", egl_major, egl_minor);
-+
-+ if (!epoxy_has_egl_extension(de->setup.egl_dpy, "EGL_KHR_image_base")) {
-+ av_log(s, AV_LOG_ERROR, "Missing EGL KHR image extension\n");
-+ goto fail;
-+ }
-+ }
-+
-+ if (!de->window_width || !de->window_height) {
-+ de->window_width = 1280;
-+ de->window_height = 720;
-+ }
-+ if (make_window(s, de, de->setup.dpy, de->setup.egl_dpy, "ffmpeg-vout",
-+ &de->setup.win, &de->setup.ctx, &de->setup.surf)) {
-+ av_log(s, AV_LOG_ERROR, "%s: make_window failed\n", __func__);
-+ goto fail;
-+ }
-+
-+ if (gl_setup(s)) {
-+ av_log(s, AV_LOG_ERROR, "%s: gl_setup failed\n", __func__);
-+ goto fail;
-+ }
-+
-+#if TRACE_ALL
-+ av_log(s, AV_LOG_INFO, "--- %s: Start done\n", __func__);
-+#endif
-+ sem_post(&de->display_start_sem);
-+
-+ for (;;) {
-+ AVFrame * frame;
-+
-+ while (sem_wait(&de->q_sem) != 0) {
-+ av_assert0(errno == EINTR);
-+ }
-+
-+ if (de->q_terminate)
-+ break;
-+
-+ pthread_mutex_lock(&de->q_lock);
-+ frame = de->q_next;
-+ de->q_next = NULL;
-+ pthread_mutex_unlock(&de->q_lock);
-+
-+ do_display(s, de, frame);
-+
-+ av_frame_free(&de->q_this);
-+ de->q_this = frame;
-+ }
-+
-+#if TRACE_ALL
-+ av_log(s, AV_LOG_INFO, ">>> %s\n", __func__);
-+#endif
-+
-+ return NULL;
-+
-+fail:
-+#if TRACE_ALL
-+ av_log(s, AV_LOG_INFO, ">>> %s: FAIL\n", __func__);
-+#endif
-+ de->q_terminate = 1;
-+ sem_post(&de->display_start_sem);
-+
-+ return NULL;
-+}
-+
-+static int egl_vout_write_packet(AVFormatContext *s, AVPacket *pkt)
-+{
-+ const AVFrame * const src_frame = (AVFrame *)pkt->data;
-+ AVFrame * frame;
-+ egl_display_env_t * const de = s->priv_data;
-+
-+#if TRACE_ALL
-+ av_log(s, AV_LOG_INFO, "%s\n", __func__);
-+#endif
-+
-+ if (src_frame->format == AV_PIX_FMT_DRM_PRIME) {
-+ frame = av_frame_alloc();
-+ av_frame_ref(frame, src_frame);
-+ }
-+ else if (src_frame->format == AV_PIX_FMT_VAAPI) {
-+ frame = av_frame_alloc();
-+ frame->format = AV_PIX_FMT_DRM_PRIME;
-+ if (av_hwframe_map(frame, src_frame, 0) != 0)
-+ {
-+ av_log(s, AV_LOG_WARNING, "Failed to map frame (format=%d) to DRM_PRiME\n", src_frame->format);
-+ av_frame_free(&frame);
-+ return AVERROR(EINVAL);
-+ }
-+ }
-+ else {
-+ av_log(s, AV_LOG_WARNING, "Frame (format=%d) not DRM_PRiME\n", src_frame->format);
-+ return AVERROR(EINVAL);
-+ }
-+
-+ // Really hacky sync
-+ while (de->show_all && de->q_next) {
-+ usleep(3000);
-+ }
-+
-+ pthread_mutex_lock(&de->q_lock);
-+ {
-+ AVFrame * const t = de->q_next;
-+ de->q_next = frame;
-+ frame = t;
-+ }
-+ pthread_mutex_unlock(&de->q_lock);
-+
-+ if (frame == NULL)
-+ sem_post(&de->q_sem);
-+ else
-+ av_frame_free(&frame);
-+
-+ return 0;
-+}
-+
-+static int egl_vout_write_frame(AVFormatContext *s, int stream_index, AVFrame **ppframe,
-+ unsigned flags)
-+{
-+ av_log(s, AV_LOG_ERROR, "%s: NIF: idx=%d, flags=%#x\n", __func__, stream_index, flags);
-+ return AVERROR_PATCHWELCOME;
-+}
-+
-+static int egl_vout_control_message(AVFormatContext *s, int type, void *data, size_t data_size)
-+{
-+#if TRACE_ALL
-+ av_log(s, AV_LOG_INFO, "%s: %d\n", __func__, type);
-+#endif
-+ switch(type) {
-+ case AV_APP_TO_DEV_WINDOW_REPAINT:
-+ return 0;
-+ default:
-+ break;
-+ }
-+ return AVERROR(ENOSYS);
-+}
-+
-+// deinit is called if init fails so no need to clean up explicity here
-+static int egl_vout_init(struct AVFormatContext * s)
-+{
-+ egl_display_env_t * const de = s->priv_data;
-+ unsigned int i;
-+
-+ av_log(s, AV_LOG_DEBUG, "<<< %s\n", __func__);
-+
-+ de->setup = (struct egl_setup){0};
-+
-+ for (i = 0; i != 32; ++i) {
-+ de->aux[i].fd = -1;
-+ }
-+
-+ de->q_terminate = 0;
-+ pthread_mutex_init(&de->q_lock, NULL);
-+ sem_init(&de->q_sem, 0, 0);
-+ sem_init(&de->display_start_sem, 0, 0);
-+ av_assert0(pthread_create(&de->q_thread, NULL, display_thread, s) == 0);
-+
-+ sem_wait(&de->display_start_sem);
-+ if (de->q_terminate) {
-+ av_log(s, AV_LOG_ERROR, "%s: Display startup failure\n", __func__);
-+ return -1;
-+ }
-+
-+ av_log(s, AV_LOG_DEBUG, ">>> %s\n", __func__);
-+
-+ return 0;
-+}
-+
-+static void egl_vout_deinit(struct AVFormatContext * s)
-+{
-+ egl_display_env_t * const de = s->priv_data;
-+
-+ av_log(s, AV_LOG_DEBUG, "<<< %s\n", __func__);
-+
-+ de->q_terminate = 1;
-+ sem_post(&de->q_sem);
-+ pthread_join(de->q_thread, NULL);
-+ sem_destroy(&de->q_sem);
-+ pthread_mutex_destroy(&de->q_lock);
-+
-+ av_frame_free(&de->q_next);
-+ av_frame_free(&de->q_this);
-+
-+ av_log(s, AV_LOG_DEBUG, ">>> %s\n", __func__);
-+}
-+
-+#define OFFSET(x) offsetof(egl_display_env_t, x)
-+static const AVOption options[] = {
-+ { "show_all", "show all frames", OFFSET(show_all), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
-+ { "window_size", "set window forced size", OFFSET(window_width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
-+ { "window_x", "set window x offset", OFFSET(window_x), AV_OPT_TYPE_INT, {.i64 = 0 }, -INT_MAX, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
-+ { "window_y", "set window y offset", OFFSET(window_y), AV_OPT_TYPE_INT, {.i64 = 0 }, -INT_MAX, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
-+ { "fullscreen", "set fullscreen display", OFFSET(fullscreen), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
-+ { NULL }
-+
-+};
-+
-+static const AVClass egl_vout_class = {
-+ .class_name = "egl vid outdev",
-+ .item_name = av_default_item_name,
-+ .option = options,
-+ .version = LIBAVUTIL_VERSION_INT,
-+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT,
-+};
-+
-+FFOutputFormat ff_vout_egl_muxer = {
-+ .p = {
-+ .name = "vout_egl",
-+ .long_name = NULL_IF_CONFIG_SMALL("Egl video output device"),
-+ .audio_codec = AV_CODEC_ID_NONE,
-+ .video_codec = AV_CODEC_ID_WRAPPED_AVFRAME,
-+ .flags = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS,
-+ .priv_class = &egl_vout_class,
-+ },
-+ .priv_data_size = sizeof(egl_display_env_t),
-+ .write_header = egl_vout_write_header,
-+ .write_packet = egl_vout_write_packet,
-+ .write_uncoded_frame = egl_vout_write_frame,
-+ .write_trailer = egl_vout_write_trailer,
-+ .control_message = egl_vout_control_message,
-+ .init = egl_vout_init,
-+ .deinit = egl_vout_deinit,
-+};
-+
-
-From 867bd7c243e66a1c1756878e20df8f35db8025ec Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Wed, 28 Apr 2021 12:51:22 +0100
-Subject: [PATCH 016/151] V4L2 stateful rework
-
----
- libavcodec/Makefile | 3 +-
- libavcodec/v4l2_buffers.c | 556 +++++++++++++++++++++++++++-----------
- libavcodec/v4l2_buffers.h | 28 +-
- libavcodec/v4l2_context.c | 536 +++++++++++++++++++++++++++---------
- libavcodec/v4l2_context.h | 20 +-
- libavcodec/v4l2_m2m.c | 20 +-
- libavcodec/v4l2_m2m.h | 31 +++
- libavcodec/v4l2_m2m_dec.c | 446 ++++++++++++++++++++++++++----
- 8 files changed, 1286 insertions(+), 354 deletions(-)
-
-diff --git a/libavcodec/Makefile b/libavcodec/Makefile
-index 2d440b5648..e1aa0ba014 100644
---- a/libavcodec/Makefile
-+++ b/libavcodec/Makefile
-@@ -169,7 +169,8 @@ OBJS-$(CONFIG_VIDEODSP) += videodsp.o
- 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_M2M) += v4l2_m2m.o v4l2_context.o v4l2_buffers.o v4l2_fmt.o\
-+ weak_link.o
- OBJS-$(CONFIG_V4L2_REQUEST) += v4l2_req_media.o v4l2_req_pollqueue.o v4l2_req_dmabufs.o\
- v4l2_req_devscan.o weak_link.o
- OBJS-$(CONFIG_WMA_FREQS) += wma_freqs.o
-diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
-index 3f5471067a..a003934ca1 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
-@@ -29,12 +30,14 @@
- #include
- #include "libavcodec/avcodec.h"
- #include "libavutil/pixdesc.h"
-+#include "libavutil/hwcontext.h"
- #include "v4l2_context.h"
- #include "v4l2_buffers.h"
- #include "v4l2_m2m.h"
-+#include "weak_link.h"
-
- #define USEC_PER_SEC 1000000
--static AVRational v4l2_timebase = { 1, USEC_PER_SEC };
-+static const AVRational v4l2_timebase = { 1, USEC_PER_SEC };
-
- static inline V4L2m2mContext *buf_to_m2mctx(V4L2Buffer *buf)
- {
-@@ -51,34 +54,44 @@ static inline AVCodecContext *logger(V4L2Buffer *buf)
- static inline AVRational v4l2_get_timebase(V4L2Buffer *avbuf)
- {
- V4L2m2mContext *s = buf_to_m2mctx(avbuf);
--
-- if (s->avctx->pkt_timebase.num)
-- return s->avctx->pkt_timebase;
-- return s->avctx->time_base;
-+ const AVRational tb = s->avctx->pkt_timebase.num ?
-+ s->avctx->pkt_timebase :
-+ s->avctx->time_base;
-+ return tb.num && tb.den ? tb : v4l2_timebase;
- }
-
--static inline void v4l2_set_pts(V4L2Buffer *out, int64_t pts)
-+static inline void v4l2_set_pts(V4L2Buffer *out, int64_t pts, int no_rescale)
- {
-- int64_t v4l2_pts;
--
-- if (pts == AV_NOPTS_VALUE)
-- pts = 0;
--
- /* convert pts to v4l2 timebase */
-- v4l2_pts = av_rescale_q(pts, v4l2_get_timebase(out), v4l2_timebase);
-+ const int64_t v4l2_pts =
-+ no_rescale ? pts :
-+ pts == AV_NOPTS_VALUE ? 0 :
-+ av_rescale_q(pts, v4l2_get_timebase(out), v4l2_timebase);
- out->buf.timestamp.tv_usec = v4l2_pts % USEC_PER_SEC;
- out->buf.timestamp.tv_sec = v4l2_pts / USEC_PER_SEC;
- }
-
--static inline int64_t v4l2_get_pts(V4L2Buffer *avbuf)
-+static inline int64_t v4l2_get_pts(V4L2Buffer *avbuf, int no_rescale)
- {
-- int64_t v4l2_pts;
--
- /* convert pts back to encoder timebase */
-- v4l2_pts = (int64_t)avbuf->buf.timestamp.tv_sec * USEC_PER_SEC +
-+ const int64_t v4l2_pts = (int64_t)avbuf->buf.timestamp.tv_sec * USEC_PER_SEC +
- avbuf->buf.timestamp.tv_usec;
-
-- return av_rescale_q(v4l2_pts, v4l2_timebase, v4l2_get_timebase(avbuf));
-+ return
-+ no_rescale ? v4l2_pts :
-+ v4l2_pts == 0 ? AV_NOPTS_VALUE :
-+ av_rescale_q(v4l2_pts, v4l2_timebase, v4l2_get_timebase(avbuf));
-+}
-+
-+static void set_buf_length(V4L2Buffer *out, unsigned int plane, uint32_t bytesused, uint32_t length)
-+{
-+ if (V4L2_TYPE_IS_MULTIPLANAR(out->buf.type)) {
-+ out->planes[plane].bytesused = bytesused;
-+ out->planes[plane].length = length;
-+ } else {
-+ out->buf.bytesused = bytesused;
-+ out->buf.length = length;
-+ }
- }
-
- static enum AVColorPrimaries v4l2_get_color_primaries(V4L2Buffer *buf)
-@@ -209,68 +222,143 @@ 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)
- {
-- V4L2Buffer* avbuf = opaque;
-- V4L2m2mContext *s = buf_to_m2mctx(avbuf);
-+ AVDRMFrameDescriptor *drm_desc = &avbuf->drm_frame;
-+ AVDRMLayerDescriptor *layer;
-
-- if (atomic_fetch_sub(&avbuf->context_refcount, 1) == 1) {
-- atomic_fetch_sub_explicit(&s->refcount, 1, memory_order_acq_rel);
-+ /* fill the DRM frame descriptor */
-+ drm_desc->nb_objects = avbuf->num_planes;
-+ drm_desc->nb_layers = 1;
-
-- if (s->reinit) {
-- if (!atomic_load(&s->refcount))
-- sem_post(&s->refsync);
-- } else {
-- if (s->draining && V4L2_TYPE_IS_OUTPUT(avbuf->context->type)) {
-- /* no need to queue more buffers to the driver */
-- avbuf->status = V4L2BUF_AVAILABLE;
-- }
-- else if (avbuf->context->streamon)
-- ff_v4l2_buffer_enqueue(avbuf);
-- }
-+ 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;
-
-- av_buffer_unref(&avbuf->context_ref);
-+ default:
-+ drm_desc->nb_layers = 0;
-+ break;
- }
-+
-+ return (uint8_t *) drm_desc;
- }
-
--static int v4l2_buf_increase_ref(V4L2Buffer *in)
-+static void v4l2_free_bufref(void *opaque, uint8_t *data)
- {
-- V4L2m2mContext *s = buf_to_m2mctx(in);
-+ AVBufferRef * bufref = (AVBufferRef *)data;
-+ V4L2Buffer *avbuf = (V4L2Buffer *)bufref->data;
-+ struct V4L2Context *ctx = ff_weak_link_lock(&avbuf->context_wl);
-
-- if (in->context_ref)
-- atomic_fetch_add(&in->context_refcount, 1);
-- else {
-- in->context_ref = av_buffer_ref(s->self_ref);
-- if (!in->context_ref)
-- return AVERROR(ENOMEM);
-+ if (ctx != NULL) {
-+ // Buffer still attached to context
-+ V4L2m2mContext *s = buf_to_m2mctx(avbuf);
-
-- in->context_refcount = 1;
-- }
-+ ff_mutex_lock(&ctx->lock);
-
-- in->status = V4L2BUF_RET_USER;
-- atomic_fetch_add_explicit(&s->refcount, 1, memory_order_relaxed);
-+ avbuf->status = V4L2BUF_AVAILABLE;
-
-- return 0;
-+ if (s->draining && V4L2_TYPE_IS_OUTPUT(ctx->type)) {
-+ av_log(logger(avbuf), AV_LOG_DEBUG, "%s: Buffer avail\n", ctx->name);
-+ /* no need to queue more buffers to the driver */
-+ }
-+ else if (ctx->streamon) {
-+ av_log(logger(avbuf), AV_LOG_DEBUG, "%s: Buffer requeue\n", ctx->name);
-+ avbuf->buf.timestamp.tv_sec = 0;
-+ avbuf->buf.timestamp.tv_usec = 0;
-+ ff_v4l2_buffer_enqueue(avbuf); // will set to IN_DRIVER
-+ }
-+ else {
-+ av_log(logger(avbuf), AV_LOG_DEBUG, "%s: Buffer freed but streamoff\n", ctx->name);
-+ }
-+
-+ ff_mutex_unlock(&ctx->lock);
-+ }
-+
-+ ff_weak_link_unlock(avbuf->context_wl);
-+ av_buffer_unref(&bufref);
- }
-
--static int v4l2_buf_to_bufref(V4L2Buffer *in, int plane, AVBufferRef **buf)
-+static int v4l2_buffer_export_drm(V4L2Buffer* avbuf)
- {
-- int ret;
-+ struct v4l2_exportbuffer expbuf;
-+ int i, ret;
-
-- if (plane >= in->num_planes)
-- return AVERROR(EINVAL);
-+ for (i = 0; i < avbuf->num_planes; i++) {
-+ memset(&expbuf, 0, sizeof(expbuf));
-
-- /* even though most encoders return 0 in data_offset encoding vp8 does require this value */
-- *buf = av_buffer_create((char *)in->plane_info[plane].mm_addr + in->planes[plane].data_offset,
-- in->plane_info[plane].length, v4l2_free_buffer, in, 0);
-- if (!*buf)
-- return AVERROR(ENOMEM);
-+ expbuf.index = avbuf->buf.index;
-+ expbuf.type = avbuf->buf.type;
-+ expbuf.plane = i;
-
-- ret = v4l2_buf_increase_ref(in);
-- if (ret)
-- av_buffer_unref(buf);
-+ ret = ioctl(buf_to_m2mctx(avbuf)->fd, VIDIOC_EXPBUF, &expbuf);
-+ if (ret < 0)
-+ return AVERROR(errno);
-
-- return ret;
-+ 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;
-+ 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;
-+ }
-+ }
-+
-+ return 0;
- }
-
- static int v4l2_bufref_to_buf(V4L2Buffer *out, int plane, const uint8_t* data, int size, int offset)
-@@ -285,30 +373,50 @@ static int v4l2_bufref_to_buf(V4L2Buffer *out, int plane, const uint8_t* data, i
-
- memcpy((uint8_t*)out->plane_info[plane].mm_addr+offset, data, FFMIN(size, length-offset));
-
-- if (V4L2_TYPE_IS_MULTIPLANAR(out->buf.type)) {
-- out->planes[plane].bytesused = bytesused;
-- out->planes[plane].length = length;
-- } else {
-- out->buf.bytesused = bytesused;
-- out->buf.length = length;
-- }
-+ set_buf_length(out, plane, bytesused, length);
-
- return 0;
- }
-
-+static AVBufferRef * wrap_avbuf(V4L2Buffer * const avbuf)
-+{
-+ AVBufferRef * bufref = av_buffer_ref(avbuf->context->bufrefs[avbuf->buf.index]);
-+ AVBufferRef * newbuf;
-+
-+ if (!bufref)
-+ return NULL;
-+
-+ newbuf = av_buffer_create((uint8_t *)bufref, sizeof(*bufref), v4l2_free_bufref, NULL, 0);
-+ if (newbuf == NULL)
-+ av_buffer_unref(&bufref);
-+
-+ avbuf->status = V4L2BUF_RET_USER;
-+ return newbuf;
-+}
-+
- static int v4l2_buffer_buf_to_swframe(AVFrame *frame, V4L2Buffer *avbuf)
- {
-- int i, ret;
-+ int i;
-
- frame->format = avbuf->context->av_pix_fmt;
-
-- for (i = 0; i < avbuf->num_planes; i++) {
-- ret = v4l2_buf_to_bufref(avbuf, i, &frame->buf[i]);
-- if (ret)
-- return ret;
-+ frame->buf[0] = wrap_avbuf(avbuf);
-+ if (frame->buf[0] == NULL)
-+ return AVERROR(ENOMEM);
-+
-+ if (buf_to_m2mctx(avbuf)->output_drm) {
-+ /* 1. get references to the actual data */
-+ frame->data[0] = (uint8_t *) v4l2_get_drm_frame(avbuf);
-+ frame->format = AV_PIX_FMT_DRM_PRIME;
-+ frame->hw_frames_ctx = av_buffer_ref(avbuf->context->frames_ref);
-+ return 0;
-+ }
-+
-
-+ /* 1. get references to the actual data */
-+ for (i = 0; i < avbuf->num_planes; i++) {
-+ frame->data[i] = (uint8_t *)avbuf->plane_info[i].mm_addr + avbuf->planes[i].data_offset;
- frame->linesize[i] = avbuf->plane_info[i].bytesperline;
-- frame->data[i] = frame->buf[i]->data;
- }
-
- /* fixup special cases */
-@@ -337,68 +445,95 @@ static int v4l2_buffer_buf_to_swframe(AVFrame *frame, V4L2Buffer *avbuf)
- return 0;
- }
-
-+static void cpy_2d(uint8_t * dst, int dst_stride, const uint8_t * src, int src_stride, int w, int h)
-+{
-+ if (dst_stride == src_stride && w + 32 >= dst_stride) {
-+ memcpy(dst, src, dst_stride * h);
-+ }
-+ else {
-+ while (--h >= 0) {
-+ memcpy(dst, src, w);
-+ dst += dst_stride;
-+ src += src_stride;
-+ }
-+ }
-+}
-+
-+static int is_chroma(const AVPixFmtDescriptor *desc, int i, int num_planes)
-+{
-+ return i != 0 && !(i == num_planes - 1 && (desc->flags & AV_PIX_FMT_FLAG_ALPHA));
-+}
-+
- static int v4l2_buffer_swframe_to_buf(const AVFrame *frame, V4L2Buffer *out)
- {
-- int i, ret;
-- struct v4l2_format fmt = out->context->format;
-- int pixel_format = V4L2_TYPE_IS_MULTIPLANAR(fmt.type) ?
-- fmt.fmt.pix_mp.pixelformat : fmt.fmt.pix.pixelformat;
-- int height = V4L2_TYPE_IS_MULTIPLANAR(fmt.type) ?
-- fmt.fmt.pix_mp.height : fmt.fmt.pix.height;
-- int is_planar_format = 0;
--
-- switch (pixel_format) {
-- case V4L2_PIX_FMT_YUV420M:
-- case V4L2_PIX_FMT_YVU420M:
--#ifdef V4L2_PIX_FMT_YUV422M
-- case V4L2_PIX_FMT_YUV422M:
--#endif
--#ifdef V4L2_PIX_FMT_YVU422M
-- case V4L2_PIX_FMT_YVU422M:
--#endif
--#ifdef V4L2_PIX_FMT_YUV444M
-- case V4L2_PIX_FMT_YUV444M:
--#endif
--#ifdef V4L2_PIX_FMT_YVU444M
-- case V4L2_PIX_FMT_YVU444M:
--#endif
-- case V4L2_PIX_FMT_NV12M:
-- case V4L2_PIX_FMT_NV21M:
-- case V4L2_PIX_FMT_NV12MT_16X16:
-- case V4L2_PIX_FMT_NV12MT:
-- case V4L2_PIX_FMT_NV16M:
-- case V4L2_PIX_FMT_NV61M:
-- is_planar_format = 1;
-- }
--
-- if (!is_planar_format) {
-- const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
-- int planes_nb = 0;
-- int offset = 0;
--
-- for (i = 0; i < desc->nb_components; i++)
-- planes_nb = FFMAX(planes_nb, desc->comp[i].plane + 1);
--
-- for (i = 0; i < planes_nb; i++) {
-- int size, h = height;
-- if (i == 1 || i == 2) {
-+ int i;
-+ int num_planes = 0;
-+ int pel_strides[4] = {0};
-+
-+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
-+
-+ if ((desc->flags & AV_PIX_FMT_FLAG_HWACCEL) != 0) {
-+ av_log(NULL, AV_LOG_ERROR, "%s: HWACCEL cannot be copied\n", __func__);
-+ return -1;
-+ }
-+
-+ for (i = 0; i != desc->nb_components; ++i) {
-+ if (desc->comp[i].plane >= num_planes)
-+ num_planes = desc->comp[i].plane + 1;
-+ pel_strides[desc->comp[i].plane] = desc->comp[i].step;
-+ }
-+
-+ if (out->num_planes > 1) {
-+ if (num_planes != out->num_planes) {
-+ av_log(NULL, AV_LOG_ERROR, "%s: Num planes mismatch: %d != %d\n", __func__, num_planes, out->num_planes);
-+ return -1;
-+ }
-+ for (i = 0; i != num_planes; ++i) {
-+ int w = frame->width;
-+ int h = frame->height;
-+ if (is_chroma(desc, i, num_planes)) {
-+ w = AV_CEIL_RSHIFT(w, desc->log2_chroma_w);
- h = AV_CEIL_RSHIFT(h, desc->log2_chroma_h);
- }
-- size = frame->linesize[i] * h;
-- ret = v4l2_bufref_to_buf(out, 0, frame->data[i], size, offset);
-- if (ret)
-- return ret;
-- offset += size;
-+
-+ cpy_2d(out->plane_info[i].mm_addr, out->plane_info[i].bytesperline,
-+ frame->data[i], frame->linesize[i],
-+ w * pel_strides[i], h);
-+ set_buf_length(out, i, out->plane_info[i].bytesperline * h, out->plane_info[i].length);
- }
-- return 0;
- }
-+ else
-+ {
-+ unsigned int offset = 0;
-+
-+ for (i = 0; i != num_planes; ++i) {
-+ int w = frame->width;
-+ int h = frame->height;
-+ int dst_stride = out->plane_info[0].bytesperline;
-+ uint8_t * const dst = (uint8_t *)out->plane_info[0].mm_addr + offset;
-+
-+ if (is_chroma(desc, i, num_planes)) {
-+ // Is chroma
-+ dst_stride >>= desc->log2_chroma_w;
-+ offset += dst_stride * (out->context->height >> desc->log2_chroma_h);
-+ w = AV_CEIL_RSHIFT(w, desc->log2_chroma_w);
-+ h = AV_CEIL_RSHIFT(h, desc->log2_chroma_h);
-+ }
-+ else {
-+ // Is luma or alpha
-+ offset += dst_stride * out->context->height;
-+ }
-+ if (offset > out->plane_info[0].length) {
-+ av_log(NULL, AV_LOG_ERROR, "%s: Plane total %d > buffer size %d\n", __func__, offset, out->plane_info[0].length);
-+ return -1;
-+ }
-
-- for (i = 0; i < out->num_planes; i++) {
-- ret = v4l2_bufref_to_buf(out, i, frame->buf[i]->data, frame->buf[i]->size, 0);
-- if (ret)
-- return ret;
-+ cpy_2d(dst, dst_stride,
-+ frame->data[i], frame->linesize[i],
-+ w * pel_strides[i], h);
-+ }
-+ set_buf_length(out, 0, offset, out->plane_info[0].length);
- }
--
- return 0;
- }
-
-@@ -410,14 +545,15 @@ static int v4l2_buffer_swframe_to_buf(const AVFrame *frame, V4L2Buffer *out)
-
- int ff_v4l2_buffer_avframe_to_buf(const AVFrame *frame, V4L2Buffer *out)
- {
-- v4l2_set_pts(out, frame->pts);
-+ v4l2_set_pts(out, frame->pts, 0);
-
- return v4l2_buffer_swframe_to_buf(frame, out);
- }
-
--int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *avbuf)
-+int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *avbuf, int no_rescale_pts)
- {
- int ret;
-+ V4L2Context * const ctx = avbuf->context;
-
- av_frame_unref(frame);
-
-@@ -432,13 +568,22 @@ int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *avbuf)
- frame->colorspace = v4l2_get_color_space(avbuf);
- frame->color_range = v4l2_get_color_range(avbuf);
- frame->color_trc = v4l2_get_color_trc(avbuf);
-- frame->pts = v4l2_get_pts(avbuf);
-+ frame->pts = v4l2_get_pts(avbuf, no_rescale_pts);
- frame->pkt_dts = AV_NOPTS_VALUE;
-
- /* these values are updated also during re-init in v4l2_process_driver_event */
-- frame->height = avbuf->context->height;
-- frame->width = avbuf->context->width;
-- frame->sample_aspect_ratio = avbuf->context->sample_aspect_ratio;
-+ frame->height = ctx->height;
-+ frame->width = ctx->width;
-+ frame->sample_aspect_ratio = ctx->sample_aspect_ratio;
-+
-+ if (ctx->selection.height && ctx->selection.width) {
-+ frame->crop_left = ctx->selection.left < frame->width ? ctx->selection.left : 0;
-+ frame->crop_top = ctx->selection.top < frame->height ? ctx->selection.top : 0;
-+ frame->crop_right = ctx->selection.left + ctx->selection.width < frame->width ?
-+ frame->width - (ctx->selection.left + ctx->selection.width) : 0;
-+ frame->crop_bottom = ctx->selection.top + ctx->selection.height < frame->height ?
-+ frame->height - (ctx->selection.top + ctx->selection.height) : 0;
-+ }
-
- /* 3. report errors upstream */
- if (avbuf->buf.flags & V4L2_BUF_FLAG_ERROR) {
-@@ -451,15 +596,14 @@ int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *avbuf)
-
- int ff_v4l2_buffer_buf_to_avpkt(AVPacket *pkt, V4L2Buffer *avbuf)
- {
-- int ret;
--
- av_packet_unref(pkt);
-- ret = v4l2_buf_to_bufref(avbuf, 0, &pkt->buf);
-- if (ret)
-- return ret;
-+
-+ pkt->buf = wrap_avbuf(avbuf);
-+ if (pkt->buf == NULL)
-+ return AVERROR(ENOMEM);
-
- pkt->size = V4L2_TYPE_IS_MULTIPLANAR(avbuf->buf.type) ? avbuf->buf.m.planes[0].bytesused : avbuf->buf.bytesused;
-- pkt->data = pkt->buf->data;
-+ pkt->data = (uint8_t*)avbuf->plane_info[0].mm_addr + avbuf->planes[0].data_offset;
-
- if (avbuf->buf.flags & V4L2_BUF_FLAG_KEYFRAME)
- pkt->flags |= AV_PKT_FLAG_KEY;
-@@ -469,20 +613,27 @@ int ff_v4l2_buffer_buf_to_avpkt(AVPacket *pkt, V4L2Buffer *avbuf)
- pkt->flags |= AV_PKT_FLAG_CORRUPT;
- }
-
-- pkt->dts = pkt->pts = v4l2_get_pts(avbuf);
-+ pkt->dts = pkt->pts = v4l2_get_pts(avbuf, 0);
-
- return 0;
- }
-
--int ff_v4l2_buffer_avpkt_to_buf(const AVPacket *pkt, V4L2Buffer *out)
-+int ff_v4l2_buffer_avpkt_to_buf_ext(const AVPacket *pkt, V4L2Buffer *out,
-+ const void *extdata, size_t extlen, int no_rescale_pts)
- {
- int ret;
-
-- ret = v4l2_bufref_to_buf(out, 0, pkt->data, pkt->size, 0);
-+ if (extlen) {
-+ ret = v4l2_bufref_to_buf(out, 0, extdata, extlen, 0);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ ret = v4l2_bufref_to_buf(out, 0, pkt->data, pkt->size, extlen);
- if (ret)
- return ret;
-
-- v4l2_set_pts(out, pkt->pts);
-+ v4l2_set_pts(out, pkt->pts, no_rescale_pts);
-
- if (pkt->flags & AV_PKT_FLAG_KEY)
- out->flags = V4L2_BUF_FLAG_KEYFRAME;
-@@ -490,15 +641,61 @@ int ff_v4l2_buffer_avpkt_to_buf(const AVPacket *pkt, V4L2Buffer *out)
- return 0;
- }
-
--int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index)
-+int ff_v4l2_buffer_avpkt_to_buf(const AVPacket *pkt, V4L2Buffer *out)
-+{
-+ return ff_v4l2_buffer_avpkt_to_buf_ext(pkt, out, NULL, 0, 0);
-+}
-+
-+
-+static void v4l2_buffer_buffer_free(void *opaque, uint8_t *data)
-+{
-+ V4L2Buffer * const avbuf = (V4L2Buffer *)data;
-+ int i;
-+
-+ for (i = 0; i != FF_ARRAY_ELEMS(avbuf->plane_info); ++i) {
-+ struct V4L2Plane_info *p = avbuf->plane_info + i;
-+ if (p->mm_addr != NULL)
-+ munmap(p->mm_addr, p->length);
-+ }
-+
-+ for (i = 0; i != FF_ARRAY_ELEMS(avbuf->drm_frame.objects); ++i) {
-+ if (avbuf->drm_frame.objects[i].fd != -1)
-+ close(avbuf->drm_frame.objects[i].fd);
-+ }
-+
-+ ff_weak_link_unref(&avbuf->context_wl);
-+
-+ av_free(avbuf);
-+}
-+
-+
-+int ff_v4l2_buffer_initialize(AVBufferRef ** pbufref, int index, V4L2Context *ctx)
- {
-- V4L2Context *ctx = avbuf->context;
- int ret, i;
-+ V4L2Buffer * const avbuf = av_mallocz(sizeof(*avbuf));
-+ AVBufferRef * bufref;
-+
-+ *pbufref = NULL;
-+ if (avbuf == NULL)
-+ return AVERROR(ENOMEM);
-+
-+ bufref = av_buffer_create((uint8_t*)avbuf, sizeof(*avbuf), v4l2_buffer_buffer_free, NULL, 0);
-+ if (bufref == NULL) {
-+ av_free(avbuf);
-+ return AVERROR(ENOMEM);
-+ }
-
-+ avbuf->context = ctx;
- avbuf->buf.memory = V4L2_MEMORY_MMAP;
- avbuf->buf.type = ctx->type;
- avbuf->buf.index = index;
-
-+ for (i = 0; i != FF_ARRAY_ELEMS(avbuf->drm_frame.objects); ++i) {
-+ avbuf->drm_frame.objects[i].fd = -1;
-+ }
-+
-+ avbuf->context_wl = ff_weak_link_ref(ctx->wl_master);
-+
- if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
- avbuf->buf.length = VIDEO_MAX_PLANES;
- avbuf->buf.m.planes = avbuf->planes;
-@@ -506,7 +703,7 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index)
-
- ret = ioctl(buf_to_m2mctx(avbuf)->fd, VIDIOC_QUERYBUF, &avbuf->buf);
- if (ret < 0)
-- return AVERROR(errno);
-+ goto fail;
-
- if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
- avbuf->num_planes = 0;
-@@ -526,25 +723,33 @@ 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)
-- return AVERROR(ENOMEM);
-+ if (avbuf->plane_info[i].mm_addr == MAP_FAILED) {
-+ avbuf->plane_info[i].mm_addr = NULL;
-+ ret = AVERROR(ENOMEM);
-+ goto fail;
-+ }
- }
-
- avbuf->status = V4L2BUF_AVAILABLE;
-
-- if (V4L2_TYPE_IS_OUTPUT(ctx->type))
-- return 0;
--
- if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
- avbuf->buf.m.planes = avbuf->planes;
- avbuf->buf.length = avbuf->num_planes;
-@@ -554,7 +759,20 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index)
- avbuf->buf.length = avbuf->planes[0].length;
- }
-
-- return ff_v4l2_buffer_enqueue(avbuf);
-+ if (!V4L2_TYPE_IS_OUTPUT(ctx->type)) {
-+ if (buf_to_m2mctx(avbuf)->output_drm) {
-+ ret = v4l2_buffer_export_drm(avbuf);
-+ if (ret)
-+ goto fail;
-+ }
-+ }
-+
-+ *pbufref = bufref;
-+ return 0;
-+
-+fail:
-+ av_buffer_unref(&bufref);
-+ return ret;
- }
-
- int ff_v4l2_buffer_enqueue(V4L2Buffer* avbuf)
-@@ -563,9 +781,27 @@ int ff_v4l2_buffer_enqueue(V4L2Buffer* avbuf)
-
- avbuf->buf.flags = avbuf->flags;
-
-+ if (avbuf->buf.timestamp.tv_sec || avbuf->buf.timestamp.tv_usec) {
-+ av_log(logger(avbuf), AV_LOG_DEBUG, "--- %s pre VIDIOC_QBUF: index %d, ts=%ld.%06ld count=%d\n",
-+ avbuf->context->name, avbuf->buf.index,
-+ avbuf->buf.timestamp.tv_sec, avbuf->buf.timestamp.tv_usec,
-+ avbuf->context->q_count);
-+ }
-+
- ret = ioctl(buf_to_m2mctx(avbuf)->fd, VIDIOC_QBUF, &avbuf->buf);
-- if (ret < 0)
-- return AVERROR(errno);
-+ if (ret < 0) {
-+ int err = errno;
-+ av_log(logger(avbuf), AV_LOG_ERROR, "--- %s VIDIOC_QBUF: index %d FAIL err %d (%s)\n",
-+ avbuf->context->name, avbuf->buf.index,
-+ err, strerror(err));
-+ return AVERROR(err);
-+ }
-+
-+ ++avbuf->context->q_count;
-+ av_log(logger(avbuf), AV_LOG_DEBUG, "--- %s VIDIOC_QBUF: index %d, ts=%ld.%06ld count=%d\n",
-+ avbuf->context->name, avbuf->buf.index,
-+ avbuf->buf.timestamp.tv_sec, avbuf->buf.timestamp.tv_usec,
-+ avbuf->context->q_count);
-
- avbuf->status = V4L2BUF_IN_DRIVER;
-
-diff --git a/libavcodec/v4l2_buffers.h b/libavcodec/v4l2_buffers.h
-index 3d2ff1b9a5..111526aee3 100644
---- a/libavcodec/v4l2_buffers.h
-+++ b/libavcodec/v4l2_buffers.h
-@@ -28,27 +28,37 @@
- #include
- #include
-
-+#include "avcodec.h"
- #include "libavutil/buffer.h"
- #include "libavutil/frame.h"
-+#include "libavutil/hwcontext_drm.h"
- #include "packet.h"
-
- enum V4L2Buffer_status {
- V4L2BUF_AVAILABLE,
- V4L2BUF_IN_DRIVER,
-+ V4L2BUF_IN_USE,
- V4L2BUF_RET_USER,
- };
-
- /**
- * V4L2Buffer (wrapper for v4l2_buffer management)
- */
-+struct V4L2Context;
-+struct ff_weak_link_client;
-+
- typedef struct V4L2Buffer {
-- /* each buffer needs to have a reference to its context */
-+ /* each buffer needs to have a reference to its context
-+ * The pointer is good enough for most operation but once the buffer has
-+ * been passed to the user the buffer may become orphaned so for free ops
-+ * the weak link must be used to ensure that the context is actually
-+ * there
-+ */
- struct V4L2Context *context;
-+ struct ff_weak_link_client *context_wl;
-
-- /* This object is refcounted per-plane, so we need to keep track
-- * of how many context-refs we are holding. */
-- AVBufferRef *context_ref;
-- atomic_uint context_refcount;
-+ /* DRM descriptor */
-+ AVDRMFrameDescriptor drm_frame;
-
- /* keep track of the mmap address and mmap length */
- struct V4L2Plane_info {
-@@ -73,11 +83,12 @@ typedef struct V4L2Buffer {
- *
- * @param[in] frame The AVFRame to push the information to
- * @param[in] buf The V4L2Buffer to get the information from
-+ * @param[in] no_rescale_pts If non-zero do not rescale PTS
- *
- * @returns 0 in case of success, AVERROR(EINVAL) if the number of planes is incorrect,
- * AVERROR(ENOMEM) if the AVBufferRef can't be created.
- */
--int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *buf);
-+int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *buf, int no_rescale_pts);
-
- /**
- * Extracts the data from a V4L2Buffer to an AVPacket
-@@ -101,6 +112,9 @@ int ff_v4l2_buffer_buf_to_avpkt(AVPacket *pkt, V4L2Buffer *buf);
- */
- int ff_v4l2_buffer_avpkt_to_buf(const AVPacket *pkt, V4L2Buffer *out);
-
-+int ff_v4l2_buffer_avpkt_to_buf_ext(const AVPacket *pkt, V4L2Buffer *out,
-+ const void *extdata, size_t extlen, int no_rescale_pts);
-+
- /**
- * Extracts the data from an AVFrame to a V4L2Buffer
- *
-@@ -119,7 +133,7 @@ int ff_v4l2_buffer_avframe_to_buf(const AVFrame *frame, V4L2Buffer *out);
- *
- * @returns 0 in case of success, a negative AVERROR code otherwise
- */
--int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index);
-+int ff_v4l2_buffer_initialize(AVBufferRef **avbuf, int index, struct V4L2Context *ctx);
-
- /**
- * Enqueues a V4L2Buffer
-diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
-index a40be94690..be76068af3 100644
---- a/libavcodec/v4l2_context.c
-+++ b/libavcodec/v4l2_context.c
-@@ -27,11 +27,13 @@
- #include
- #include
- #include
-+#include "libavutil/avassert.h"
- #include "libavcodec/avcodec.h"
- #include "decode.h"
- #include "v4l2_buffers.h"
- #include "v4l2_fmt.h"
- #include "v4l2_m2m.h"
-+#include "weak_link.h"
-
- struct v4l2_format_update {
- uint32_t v4l2_fmt;
-@@ -153,21 +155,99 @@ static inline void v4l2_save_to_context(V4L2Context* ctx, struct v4l2_format_upd
- }
- }
-
--static int v4l2_start_decode(V4L2Context *ctx)
-+static int get_default_selection(V4L2Context * const ctx, struct v4l2_rect *r)
- {
-- struct v4l2_decoder_cmd cmd = {
-- .cmd = V4L2_DEC_CMD_START,
-- .flags = 0,
-+ V4L2m2mContext * const s = ctx_to_m2mctx(ctx);
-+ struct v4l2_selection selection = {
-+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
-+ .target = V4L2_SEL_TGT_COMPOSE
- };
-- int ret;
-
-- ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_DECODER_CMD, &cmd);
-- if (ret)
-+ memset(r, 0, sizeof(*r));
-+ if (ioctl(s->fd, VIDIOC_G_SELECTION, &selection))
- return AVERROR(errno);
-
-+ *r = selection.r;
- return 0;
- }
-
-+static int do_source_change(V4L2m2mContext * const s)
-+{
-+ AVCodecContext *const avctx = s->avctx;
-+
-+ int ret;
-+ int reinit;
-+ int full_reinit;
-+ struct v4l2_format cap_fmt = s->capture.format;
-+
-+ s->resize_pending = 0;
-+ s->capture.done = 0;
-+
-+ ret = ioctl(s->fd, VIDIOC_G_FMT, &cap_fmt);
-+ if (ret) {
-+ av_log(avctx, AV_LOG_ERROR, "%s VIDIOC_G_FMT failed\n", s->capture.name);
-+ return 0;
-+ }
-+
-+ s->output.sample_aspect_ratio = v4l2_get_sar(&s->output);
-+
-+ get_default_selection(&s->capture, &s->capture.selection);
-+
-+ reinit = v4l2_resolution_changed(&s->capture, &cap_fmt);
-+ if (reinit) {
-+ s->capture.height = v4l2_get_height(&cap_fmt);
-+ s->capture.width = v4l2_get_width(&cap_fmt);
-+ }
-+ s->capture.sample_aspect_ratio = v4l2_get_sar(&s->capture);
-+
-+ av_log(avctx, AV_LOG_DEBUG, "Source change: SAR: %d/%d, crop %dx%d @ %d,%d\n",
-+ s->capture.sample_aspect_ratio.num, s->capture.sample_aspect_ratio.den,
-+ s->capture.selection.width, s->capture.selection.height,
-+ s->capture.selection.left, s->capture.selection.top);
-+
-+ s->reinit = 1;
-+
-+ if (reinit) {
-+ if (avctx)
-+ ret = ff_set_dimensions(s->avctx, s->capture.width, s->capture.height);
-+ if (ret < 0)
-+ av_log(avctx, AV_LOG_WARNING, "update avcodec height and width failed\n");
-+
-+ ret = ff_v4l2_m2m_codec_reinit(s);
-+ if (ret) {
-+ av_log(avctx, AV_LOG_ERROR, "v4l2_m2m_codec_reinit failed\n");
-+ return AVERROR(EINVAL);
-+ }
-+ goto reinit_run;
-+ }
-+
-+ /* Buffers are OK so just stream off to ack */
-+ av_log(avctx, AV_LOG_DEBUG, "%s: Parameters only\n", __func__);
-+
-+ ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
-+ if (ret)
-+ av_log(avctx, AV_LOG_ERROR, "capture VIDIOC_STREAMOFF failed\n");
-+ s->draining = 0;
-+
-+ /* reinit executed */
-+reinit_run:
-+ ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMON);
-+ return 1;
-+}
-+
-+static int ctx_done(V4L2Context * const ctx)
-+{
-+ int rv = 0;
-+ V4L2m2mContext * const s = ctx_to_m2mctx(ctx);
-+
-+ ctx->done = 1;
-+
-+ if (s->resize_pending && !V4L2_TYPE_IS_OUTPUT(ctx->type))
-+ rv = do_source_change(s);
-+
-+ return rv;
-+}
-+
- /**
- * handle resolution change event and end of stream event
- * returns 1 if reinit was successful, negative if it failed
-@@ -175,8 +255,7 @@ static int v4l2_start_decode(V4L2Context *ctx)
- */
- static int v4l2_handle_event(V4L2Context *ctx)
- {
-- V4L2m2mContext *s = ctx_to_m2mctx(ctx);
-- struct v4l2_format cap_fmt = s->capture.format;
-+ V4L2m2mContext * const s = ctx_to_m2mctx(ctx);
- struct v4l2_event evt = { 0 };
- int ret;
-
-@@ -186,44 +265,22 @@ static int v4l2_handle_event(V4L2Context *ctx)
- return 0;
- }
-
-+ av_log(logger(ctx), AV_LOG_INFO, "Dq event %d\n", evt.type);
-+
- if (evt.type == V4L2_EVENT_EOS) {
-- ctx->done = 1;
-+// ctx->done = 1;
-+ av_log(logger(ctx), AV_LOG_TRACE, "%s VIDIOC_EVENT_EOS\n", ctx->name);
- return 0;
- }
-
- if (evt.type != V4L2_EVENT_SOURCE_CHANGE)
- return 0;
-
-- ret = ioctl(s->fd, VIDIOC_G_FMT, &cap_fmt);
-- if (ret) {
-- av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_G_FMT\n", s->capture.name);
-- return 0;
-- }
--
-- if (v4l2_resolution_changed(&s->capture, &cap_fmt)) {
-- s->capture.height = v4l2_get_height(&cap_fmt);
-- s->capture.width = v4l2_get_width(&cap_fmt);
-- s->capture.sample_aspect_ratio = v4l2_get_sar(&s->capture);
-- } else {
-- v4l2_start_decode(ctx);
-+ s->resize_pending = 1;
-+ if (!ctx->done)
- return 0;
-- }
--
-- s->reinit = 1;
--
-- if (s->avctx)
-- ret = ff_set_dimensions(s->avctx, s->capture.width, s->capture.height);
-- if (ret < 0)
-- av_log(logger(ctx), AV_LOG_WARNING, "update avcodec height and width\n");
--
-- ret = ff_v4l2_m2m_codec_reinit(s);
-- if (ret) {
-- av_log(logger(ctx), AV_LOG_ERROR, "v4l2_m2m_codec_reinit\n");
-- return AVERROR(EINVAL);
-- }
-
-- /* reinit executed */
-- return 1;
-+ return do_source_change(s);
- }
-
- static int v4l2_stop_decode(V4L2Context *ctx)
-@@ -266,8 +323,26 @@ static int v4l2_stop_encode(V4L2Context *ctx)
- return 0;
- }
-
-+static int count_in_driver(const V4L2Context * const ctx)
-+{
-+ int i;
-+ int n = 0;
-+
-+ if (!ctx->bufrefs)
-+ return -1;
-+
-+ for (i = 0; i < ctx->num_buffers; ++i) {
-+ V4L2Buffer *const avbuf = (V4L2Buffer *)ctx->bufrefs[i]->data;
-+ if (avbuf->status == V4L2BUF_IN_DRIVER)
-+ ++n;
-+ }
-+ return n;
-+}
-+
- static V4L2Buffer* v4l2_dequeue_v4l2buf(V4L2Context *ctx, int timeout)
- {
-+ V4L2m2mContext * const s = ctx_to_m2mctx(ctx);
-+ const int is_capture = !V4L2_TYPE_IS_OUTPUT(ctx->type);
- struct v4l2_plane planes[VIDEO_MAX_PLANES];
- struct v4l2_buffer buf = { 0 };
- V4L2Buffer *avbuf;
-@@ -276,50 +351,84 @@ static V4L2Buffer* v4l2_dequeue_v4l2buf(V4L2Context *ctx, int timeout)
- .fd = ctx_to_m2mctx(ctx)->fd,
- };
- int i, ret;
-+ int no_rx_means_done = 0;
-
-- if (!V4L2_TYPE_IS_OUTPUT(ctx->type) && ctx->buffers) {
-+ if (is_capture && ctx->bufrefs) {
- for (i = 0; i < ctx->num_buffers; i++) {
-- if (ctx->buffers[i].status == V4L2BUF_IN_DRIVER)
-+ avbuf = (V4L2Buffer *)ctx->bufrefs[i]->data;
-+ if (avbuf->status == V4L2BUF_IN_DRIVER)
- break;
- }
- if (i == ctx->num_buffers)
-- av_log(logger(ctx), AV_LOG_WARNING, "All capture buffers returned to "
-+ av_log(logger(ctx), AV_LOG_WARNING, "All capture buffers (%d) returned to "
- "userspace. Increase num_capture_buffers "
- "to prevent device deadlock or dropped "
-- "packets/frames.\n");
-+ "packets/frames.\n", i);
- }
-
-+#if 0
-+ // I think this is true but pointless
-+ // we will get some other form of EOF signal
-+
- /* if we are draining and there are no more capture buffers queued in the driver we are done */
-- if (!V4L2_TYPE_IS_OUTPUT(ctx->type) && ctx_to_m2mctx(ctx)->draining) {
-+ if (is_capture && ctx_to_m2mctx(ctx)->draining) {
- for (i = 0; i < ctx->num_buffers; i++) {
- /* capture buffer initialization happens during decode hence
- * detection happens at runtime
- */
-- if (!ctx->buffers)
-+ if (!ctx->bufrefs)
- break;
-
-- if (ctx->buffers[i].status == V4L2BUF_IN_DRIVER)
-+ avbuf = (V4L2Buffer *)ctx->bufrefs[i]->data;
-+ if (avbuf->status == V4L2BUF_IN_DRIVER)
- goto start;
- }
- ctx->done = 1;
- return NULL;
- }
-+#endif
-
- start:
-- if (V4L2_TYPE_IS_OUTPUT(ctx->type))
-- pfd.events = POLLOUT | POLLWRNORM;
-- else {
-+ if (is_capture) {
- /* no need to listen to requests for more input while draining */
- if (ctx_to_m2mctx(ctx)->draining)
- pfd.events = POLLIN | POLLRDNORM | POLLPRI;
-+ } else {
-+ pfd.events = POLLOUT | POLLWRNORM;
- }
-+ no_rx_means_done = s->resize_pending && is_capture;
-
- for (;;) {
-- ret = poll(&pfd, 1, timeout);
-+ // If we have a resize pending then all buffers should be Qed
-+ // With a resize pending we should be in drain but evidence suggests
-+ // that not all decoders do this so poll to clear
-+ int t2 = no_rx_means_done ? 0 : timeout < 0 ? 3000 : timeout;
-+ const int e = pfd.events;
-+
-+ ret = poll(&pfd, 1, t2);
-+
- if (ret > 0)
- break;
-- if (errno == EINTR)
-- continue;
-+
-+ if (ret < 0) {
-+ int err = errno;
-+ if (err == EINTR)
-+ continue;
-+ av_log(logger(ctx), AV_LOG_ERROR, "=== poll error %d (%s): events=%#x, cap buffers=%d\n",
-+ err, strerror(err),
-+ e, count_in_driver(ctx));
-+ return NULL;
-+ }
-+
-+ // ret == 0 (timeout)
-+ if (no_rx_means_done) {
-+ av_log(logger(ctx), AV_LOG_DEBUG, "Ctx done on timeout\n");
-+ ret = ctx_done(ctx);
-+ if (ret > 0)
-+ goto start;
-+ }
-+ if (timeout == -1)
-+ av_log(logger(ctx), AV_LOG_ERROR, "=== poll unexpected TIMEOUT: events=%#x, cap buffers=%d\n", e, count_in_driver(ctx));;
- return NULL;
- }
-
-@@ -329,7 +438,8 @@ start:
- no need to raise a warning */
- if (timeout == 0) {
- for (i = 0; i < ctx->num_buffers; i++) {
-- if (ctx->buffers[i].status != V4L2BUF_AVAILABLE)
-+ avbuf = (V4L2Buffer *)ctx->bufrefs[i]->data;
-+ if (avbuf->status != V4L2BUF_AVAILABLE)
- av_log(logger(ctx), AV_LOG_WARNING, "%s POLLERR\n", ctx->name);
- }
- }
-@@ -347,22 +457,25 @@ start:
- ctx->done = 1;
- return NULL;
- }
-- if (ret) {
-- /* if re-init was successful drop the buffer (if there was one)
-- * since we had to reconfigure capture (unmap all buffers)
-- */
-- return NULL;
-- }
-+ if (ret > 0)
-+ goto start;
- }
-
- /* 2. dequeue the buffer */
- if (pfd.revents & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM)) {
-
-- if (!V4L2_TYPE_IS_OUTPUT(ctx->type)) {
-+ if (is_capture) {
- /* there is a capture buffer ready */
- if (pfd.revents & (POLLIN | POLLRDNORM))
- goto dequeue;
-
-+ // CAPTURE Q drained
-+ if (no_rx_means_done) {
-+ if (ctx_done(ctx) > 0)
-+ goto start;
-+ return NULL;
-+ }
-+
- /* the driver is ready to accept more input; instead of waiting for the capture
- * buffer to complete we return NULL so input can proceed (we are single threaded)
- */
-@@ -380,37 +493,58 @@ dequeue:
- buf.m.planes = planes;
- }
-
-- ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_DQBUF, &buf);
-- if (ret) {
-- if (errno != EAGAIN) {
-- ctx->done = 1;
-- if (errno != EPIPE)
-+ while ((ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_DQBUF, &buf)) == -1) {
-+ const int err = errno;
-+ if (err == EINTR)
-+ continue;
-+ if (err != EAGAIN) {
-+ // EPIPE on CAPTURE can be used instead of BUF_FLAG_LAST
-+ if (err != EPIPE || !is_capture)
- av_log(logger(ctx), AV_LOG_DEBUG, "%s VIDIOC_DQBUF, errno (%s)\n",
-- ctx->name, av_err2str(AVERROR(errno)));
-+ ctx->name, av_err2str(AVERROR(err)));
-+ if (ctx_done(ctx) > 0)
-+ goto start;
- }
- return NULL;
- }
-+ --ctx->q_count;
-+ av_log(logger(ctx), AV_LOG_DEBUG, "--- %s VIDIOC_DQBUF OK: index=%d, ts=%ld.%06ld, count=%d, dq=%d\n",
-+ ctx->name, buf.index,
-+ buf.timestamp.tv_sec, buf.timestamp.tv_usec,
-+ ctx->q_count, ++ctx->dq_count);
-
-- if (ctx_to_m2mctx(ctx)->draining && !V4L2_TYPE_IS_OUTPUT(ctx->type)) {
-+ avbuf = (V4L2Buffer *)ctx->bufrefs[buf.index]->data;
-+ avbuf->status = V4L2BUF_AVAILABLE;
-+ avbuf->buf = buf;
-+ if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
-+ memcpy(avbuf->planes, planes, sizeof(planes));
-+ avbuf->buf.m.planes = avbuf->planes;
-+ }
-+
-+ if (ctx_to_m2mctx(ctx)->draining && is_capture) {
- int bytesused = V4L2_TYPE_IS_MULTIPLANAR(buf.type) ?
- buf.m.planes[0].bytesused : buf.bytesused;
- if (bytesused == 0) {
-- ctx->done = 1;
-+ av_log(logger(ctx), AV_LOG_DEBUG, "Buffer empty - reQ\n");
-+
-+ // Must reQ so we don't leak
-+ // May not matter if the next thing we do is release all the
-+ // buffers but better to be tidy.
-+ ff_v4l2_buffer_enqueue(avbuf);
-+
-+ if (ctx_done(ctx) > 0)
-+ goto start;
- return NULL;
- }
- #ifdef V4L2_BUF_FLAG_LAST
-- if (buf.flags & V4L2_BUF_FLAG_LAST)
-- ctx->done = 1;
-+ if (buf.flags & V4L2_BUF_FLAG_LAST) {
-+ av_log(logger(ctx), AV_LOG_TRACE, "FLAG_LAST set\n");
-+ avbuf->status = V4L2BUF_IN_USE; // Avoid flushing this buffer
-+ ctx_done(ctx);
-+ }
- #endif
- }
-
-- avbuf = &ctx->buffers[buf.index];
-- avbuf->status = V4L2BUF_AVAILABLE;
-- avbuf->buf = buf;
-- if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
-- memcpy(avbuf->planes, planes, sizeof(planes));
-- avbuf->buf.m.planes = avbuf->planes;
-- }
- return avbuf;
- }
-
-@@ -429,8 +563,9 @@ static V4L2Buffer* v4l2_getfree_v4l2buf(V4L2Context *ctx)
- }
-
- for (i = 0; i < ctx->num_buffers; i++) {
-- if (ctx->buffers[i].status == V4L2BUF_AVAILABLE)
-- return &ctx->buffers[i];
-+ V4L2Buffer * const avbuf = (V4L2Buffer *)ctx->bufrefs[i]->data;
-+ if (avbuf->status == V4L2BUF_AVAILABLE)
-+ return avbuf;
- }
-
- return NULL;
-@@ -438,25 +573,45 @@ static V4L2Buffer* v4l2_getfree_v4l2buf(V4L2Context *ctx)
-
- 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 */
-- };
-- int i, j;
-+ int i;
-+ int ret = 0;
-+ const int fd = ctx_to_m2mctx(ctx)->fd;
-
-- for (i = 0; i < ctx->num_buffers; i++) {
-- V4L2Buffer *buffer = &ctx->buffers[i];
-+ // Orphan any buffers in the wild
-+ ff_weak_link_break(&ctx->wl_master);
-+
-+ if (ctx->bufrefs) {
-+ for (i = 0; i < ctx->num_buffers; i++)
-+ av_buffer_unref(ctx->bufrefs + i);
-+ }
-+
-+ if (fd != -1) {
-+ struct v4l2_requestbuffers req = {
-+ .memory = V4L2_MEMORY_MMAP,
-+ .type = ctx->type,
-+ .count = 0, /* 0 -> unmap all buffers from the driver */
-+ };
-+
-+ while ((ret = ioctl(fd, VIDIOC_REQBUFS, &req)) == -1) {
-+ if (errno == EINTR)
-+ continue;
-+
-+ ret = AVERROR(errno);
-
-- for (j = 0; j < buffer->num_planes; j++) {
-- struct V4L2Plane_info *p = &buffer->plane_info[j];
-- 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, "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");
- }
- }
-+ ctx->q_count = 0;
-
-- return ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_REQBUFS, &req);
-+ return ret;
- }
-
- static inline int v4l2_try_raw_format(V4L2Context* ctx, enum AVPixelFormat pixfmt)
-@@ -485,6 +640,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;
-@@ -503,6 +660,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){
-@@ -555,18 +719,73 @@ static int v4l2_get_coded_format(V4L2Context* ctx, uint32_t *p)
- *
- *****************************************************************************/
-
-+
-+static void flush_all_buffers_status(V4L2Context* const ctx)
-+{
-+ int i;
-+ for (i = 0; i < ctx->num_buffers; ++i) {
-+ struct V4L2Buffer * const buf = (struct V4L2Buffer *)ctx->bufrefs[i]->data;
-+ if (buf->status == V4L2BUF_IN_DRIVER)
-+ buf->status = V4L2BUF_AVAILABLE;
-+ }
-+ ctx->q_count = 0;
-+}
-+
-+static int stuff_all_buffers(AVCodecContext * avctx, V4L2Context* ctx)
-+{
-+ int i;
-+ int rv;
-+
-+ if (!ctx->bufrefs) {
-+ rv = ff_v4l2_context_init(ctx);
-+ if (rv) {
-+ av_log(avctx, AV_LOG_ERROR, "can't request capture buffers\n");
-+ return rv;
-+ }
-+ }
-+
-+ for (i = 0; i < ctx->num_buffers; ++i) {
-+ struct V4L2Buffer * const buf = (struct V4L2Buffer *)ctx->bufrefs[i]->data;
-+ if (buf->status == V4L2BUF_AVAILABLE) {
-+ rv = ff_v4l2_buffer_enqueue(buf);
-+ if (rv < 0)
-+ return rv;
-+ }
-+ }
-+ return 0;
-+}
-+
- int ff_v4l2_context_set_status(V4L2Context* ctx, uint32_t cmd)
- {
- int type = ctx->type;
- int ret;
-+ AVCodecContext * const avctx = logger(ctx);
-+
-+ ff_mutex_lock(&ctx->lock);
-+
-+ if (cmd == VIDIOC_STREAMON && !V4L2_TYPE_IS_OUTPUT(ctx->type))
-+ stuff_all_buffers(avctx, ctx);
-
- ret = ioctl(ctx_to_m2mctx(ctx)->fd, cmd, &type);
-- if (ret < 0)
-- return AVERROR(errno);
-+ if (ret < 0) {
-+ const int err = errno;
-+ av_log(avctx, AV_LOG_ERROR, "%s set status %d (%s) failed: err=%d\n", ctx->name,
-+ cmd, (cmd == VIDIOC_STREAMON) ? "ON" : "OFF", err);
-+ ret = AVERROR(err);
-+ }
-+ else
-+ {
-+ if (cmd == VIDIOC_STREAMOFF)
-+ flush_all_buffers_status(ctx);
-
-- ctx->streamon = (cmd == VIDIOC_STREAMON);
-+ ctx->streamon = (cmd == VIDIOC_STREAMON);
-+ av_log(avctx, AV_LOG_DEBUG, "%s set status %d (%s) OK\n", ctx->name,
-+ cmd, (cmd == VIDIOC_STREAMON) ? "ON" : "OFF");
-+ }
-
-- return 0;
-+ ff_mutex_unlock(&ctx->lock);
-+
-+ return ret;
- }
-
- int ff_v4l2_context_enqueue_frame(V4L2Context* ctx, const AVFrame* frame)
-@@ -594,7 +813,8 @@ int ff_v4l2_context_enqueue_frame(V4L2Context* ctx, const AVFrame* frame)
- return ff_v4l2_buffer_enqueue(avbuf);
- }
-
--int ff_v4l2_context_enqueue_packet(V4L2Context* ctx, const AVPacket* pkt)
-+int ff_v4l2_context_enqueue_packet(V4L2Context* ctx, const AVPacket* pkt,
-+ const void * extdata, size_t extlen, int no_rescale_pts)
- {
- V4L2m2mContext *s = ctx_to_m2mctx(ctx);
- V4L2Buffer* avbuf;
-@@ -602,8 +822,9 @@ int ff_v4l2_context_enqueue_packet(V4L2Context* ctx, const AVPacket* pkt)
-
- if (!pkt->size) {
- ret = v4l2_stop_decode(ctx);
-+ // Log but otherwise ignore stop failure
- if (ret)
-- av_log(logger(ctx), AV_LOG_ERROR, "%s stop_decode\n", ctx->name);
-+ av_log(logger(ctx), AV_LOG_ERROR, "%s stop_decode failed: err=%d\n", ctx->name, ret);
- s->draining = 1;
- return 0;
- }
-@@ -612,14 +833,14 @@ int ff_v4l2_context_enqueue_packet(V4L2Context* ctx, const AVPacket* pkt)
- if (!avbuf)
- return AVERROR(EAGAIN);
-
-- ret = ff_v4l2_buffer_avpkt_to_buf(pkt, avbuf);
-+ ret = ff_v4l2_buffer_avpkt_to_buf_ext(pkt, avbuf, extdata, extlen, no_rescale_pts);
- if (ret)
- return ret;
-
- return ff_v4l2_buffer_enqueue(avbuf);
- }
-
--int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* frame, int timeout)
-+int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* frame, int timeout, int no_rescale_pts)
- {
- V4L2Buffer *avbuf;
-
-@@ -636,7 +857,7 @@ int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* frame, int timeout)
- return AVERROR(EAGAIN);
- }
-
-- return ff_v4l2_buffer_buf_to_avframe(frame, avbuf);
-+ return ff_v4l2_buffer_buf_to_avframe(frame, avbuf, no_rescale_pts);
- }
-
- int ff_v4l2_context_dequeue_packet(V4L2Context* ctx, AVPacket* pkt)
-@@ -695,54 +916,57 @@ void ff_v4l2_context_release(V4L2Context* ctx)
- {
- int ret;
-
-- if (!ctx->buffers)
-+ if (!ctx->bufrefs)
- return;
-
- ret = v4l2_release_buffers(ctx);
- if (ret)
- av_log(logger(ctx), AV_LOG_WARNING, "V4L2 failed to unmap the %s buffers\n", ctx->name);
-
-- av_freep(&ctx->buffers);
-+ av_freep(&ctx->bufrefs);
-+ av_buffer_unref(&ctx->frames_ref);
-+
-+ ff_mutex_destroy(&ctx->lock);
- }
-
--int ff_v4l2_context_init(V4L2Context* ctx)
-+
-+static int create_buffers(V4L2Context* const ctx, const unsigned int req_buffers)
- {
-- V4L2m2mContext *s = ctx_to_m2mctx(ctx);
-+ V4L2m2mContext * const s = ctx_to_m2mctx(ctx);
- struct v4l2_requestbuffers req;
-- int ret, i;
--
-- if (!v4l2_type_supported(ctx)) {
-- av_log(logger(ctx), AV_LOG_ERROR, "type %i not supported\n", ctx->type);
-- return AVERROR_PATCHWELCOME;
-- }
--
-- ret = ioctl(s->fd, VIDIOC_G_FMT, &ctx->format);
-- if (ret)
-- av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_G_FMT failed\n", ctx->name);
-+ int ret;
-+ int i;
-
- memset(&req, 0, sizeof(req));
-- req.count = ctx->num_buffers;
-+ req.count = req_buffers;
- req.memory = V4L2_MEMORY_MMAP;
- req.type = ctx->type;
-- ret = ioctl(s->fd, VIDIOC_REQBUFS, &req);
-- if (ret < 0) {
-- av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_REQBUFS failed: %s\n", ctx->name, strerror(errno));
-- return AVERROR(errno);
-+ while ((ret = ioctl(s->fd, VIDIOC_REQBUFS, &req)) == -1) {
-+ if (errno != EINTR) {
-+ ret = AVERROR(errno);
-+ av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_REQBUFS failed: %s\n", ctx->name, av_err2str(ret));
-+ return ret;
-+ }
- }
-
- ctx->num_buffers = req.count;
-- ctx->buffers = av_mallocz(ctx->num_buffers * sizeof(V4L2Buffer));
-- if (!ctx->buffers) {
-+ ctx->bufrefs = av_mallocz(ctx->num_buffers * sizeof(*ctx->bufrefs));
-+ if (!ctx->bufrefs) {
- av_log(logger(ctx), AV_LOG_ERROR, "%s malloc enomem\n", ctx->name);
-- return AVERROR(ENOMEM);
-+ goto fail_release;
- }
-
-- for (i = 0; i < req.count; i++) {
-- ctx->buffers[i].context = ctx;
-- ret = ff_v4l2_buffer_initialize(&ctx->buffers[i], i);
-- if (ret < 0) {
-+ ctx->wl_master = ff_weak_link_new(ctx);
-+ if (!ctx->wl_master) {
-+ ret = AVERROR(ENOMEM);
-+ goto fail_release;
-+ }
-+
-+ for (i = 0; i < ctx->num_buffers; i++) {
-+ ret = ff_v4l2_buffer_initialize(&ctx->bufrefs[i], i, ctx);
-+ if (ret) {
- av_log(logger(ctx), AV_LOG_ERROR, "%s buffer[%d] initialization (%s)\n", ctx->name, i, av_err2str(ret));
-- goto error;
-+ goto fail_release;
- }
- }
-
-@@ -756,10 +980,62 @@ int ff_v4l2_context_init(V4L2Context* ctx)
-
- return 0;
-
--error:
-+fail_release:
- v4l2_release_buffers(ctx);
-+ av_freep(&ctx->bufrefs);
-+ return ret;
-+}
-+
-+int ff_v4l2_context_init(V4L2Context* ctx)
-+{
-+ V4L2m2mContext * const s = ctx_to_m2mctx(ctx);
-+ int ret;
-+
-+ // It is not valid to reinit a context without a previous release
-+ av_assert0(ctx->bufrefs == NULL);
-+
-+ if (!v4l2_type_supported(ctx)) {
-+ av_log(logger(ctx), AV_LOG_ERROR, "type %i not supported\n", ctx->type);
-+ return AVERROR_PATCHWELCOME;
-+ }
-+
-+ ff_mutex_init(&ctx->lock, NULL);
-
-- av_freep(&ctx->buffers);
-+ if (s->output_drm) {
-+ AVHWFramesContext *hwframes;
-+
-+ ctx->frames_ref = av_hwframe_ctx_alloc(s->device_ref);
-+ if (!ctx->frames_ref) {
-+ ret = AVERROR(ENOMEM);
-+ goto fail_unlock;
-+ }
-+
-+ 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)
-+ goto fail_unref_hwframes;
-+ }
-+
-+ ret = ioctl(s->fd, VIDIOC_G_FMT, &ctx->format);
-+ if (ret) {
-+ ret = AVERROR(errno);
-+ av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_G_FMT failed: %s\n", ctx->name, av_err2str(ret));
-+ goto fail_unref_hwframes;
-+ }
-+
-+ ret = create_buffers(ctx, ctx->num_buffers);
-+ if (ret < 0)
-+ goto fail_unref_hwframes;
-+
-+ return 0;
-
-+fail_unref_hwframes:
-+ av_buffer_unref(&ctx->frames_ref);
-+fail_unlock:
-+ ff_mutex_destroy(&ctx->lock);
- return ret;
- }
-diff --git a/libavcodec/v4l2_context.h b/libavcodec/v4l2_context.h
-index 6f7460c89a..59009d11d1 100644
---- a/libavcodec/v4l2_context.h
-+++ b/libavcodec/v4l2_context.h
-@@ -32,6 +32,8 @@
- #include "libavutil/rational.h"
- #include "codec_id.h"
- #include "packet.h"
-+#include "libavutil/buffer.h"
-+#include "libavutil/thread.h"
- #include "v4l2_buffers.h"
-
- typedef struct V4L2Context {
-@@ -71,11 +73,12 @@ typedef struct V4L2Context {
- */
- int width, height;
- AVRational sample_aspect_ratio;
-+ struct v4l2_rect selection;
-
- /**
-- * Indexed array of V4L2Buffers
-+ * Indexed array of pointers to V4L2Buffers
- */
-- V4L2Buffer *buffers;
-+ AVBufferRef **bufrefs;
-
- /**
- * Readonly after init.
-@@ -93,6 +96,12 @@ typedef struct V4L2Context {
- */
- int done;
-
-+ AVBufferRef *frames_ref;
-+ int q_count;
-+ int dq_count;
-+ struct ff_weak_link_master *wl_master;
-+
-+ AVMutex lock;
- } V4L2Context;
-
- /**
-@@ -157,9 +166,12 @@ int ff_v4l2_context_dequeue_packet(V4L2Context* ctx, AVPacket* pkt);
- * @param[in] ctx The V4L2Context to dequeue from.
- * @param[inout] f The AVFrame to dequeue to.
- * @param[in] timeout The timeout for dequeue (-1 to block, 0 to return immediately, or milliseconds)
-+ * @param[in] no_rescale_pts (0 rescale pts, 1 use pts as
-+ * timestamp directly)
-+ *
- * @return 0 in case of success, AVERROR(EAGAIN) if no buffer was ready, another negative error in case of error.
- */
--int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* f, int timeout);
-+int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* f, int timeout, int no_rescale_pts);
-
- /**
- * Enqueues a buffer to a V4L2Context from an AVPacket
-@@ -171,7 +183,7 @@ int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* f, int timeout);
- * @param[in] pkt A pointer to an AVPacket.
- * @return 0 in case of success, a negative error otherwise.
- */
--int ff_v4l2_context_enqueue_packet(V4L2Context* ctx, const AVPacket* pkt);
-+int ff_v4l2_context_enqueue_packet(V4L2Context* ctx, const AVPacket* pkt, const void * ext_data, size_t ext_size, int no_rescale_pts);
-
- /**
- * Enqueues a buffer to a V4L2Context from an AVFrame
-diff --git a/libavcodec/v4l2_m2m.c b/libavcodec/v4l2_m2m.c
-index 602efb7a16..516e6d9858 100644
---- a/libavcodec/v4l2_m2m.c
-+++ b/libavcodec/v4l2_m2m.c
-@@ -216,13 +216,7 @@ int ff_v4l2_m2m_codec_reinit(V4L2m2mContext *s)
- av_log(log_ctx, AV_LOG_ERROR, "capture VIDIOC_STREAMOFF\n");
-
- /* 2. unmap the capture buffers (v4l2 and ffmpeg):
-- * we must wait for all references to be released before being allowed
-- * to queue new buffers.
- */
-- av_log(log_ctx, AV_LOG_DEBUG, "waiting for user to release AVBufferRefs\n");
-- if (atomic_load(&s->refcount))
-- while(sem_wait(&s->refsync) == -1 && errno == EINTR);
--
- ff_v4l2_context_release(&s->capture);
-
- /* 3. get the new capture format */
-@@ -259,6 +253,8 @@ static void v4l2_m2m_destroy_context(void *opaque, uint8_t *context)
- av_frame_free(&s->frame);
- av_packet_unref(&s->buf_pkt);
-
-+ av_log(s->avctx, AV_LOG_DEBUG, "V4L2 Context destroyed\n");
-+
- av_free(s);
- }
-
-@@ -270,6 +266,11 @@ int ff_v4l2_m2m_codec_end(V4L2m2mPriv *priv)
- if (!s)
- return 0;
-
-+ av_log(s->avctx, AV_LOG_DEBUG, "V4L2 Codec end\n");
-+
-+ if (av_codec_is_decoder(s->avctx->codec))
-+ av_packet_unref(&s->buf_pkt);
-+
- if (s->fd >= 0) {
- ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF);
- if (ret)
-@@ -282,7 +283,14 @@ int ff_v4l2_m2m_codec_end(V4L2m2mPriv *priv)
-
- ff_v4l2_context_release(&s->output);
-
-+ close(s->fd);
-+ s->fd = -1;
-+
- s->self_ref = NULL;
-+ // This is only called on avctx close so after this point we don't have that
-+ // Crash sooner if we find we are using it (can still log with avctx = NULL)
-+ s->avctx = NULL;
-+ priv->context = NULL;
- av_buffer_unref(&priv->context_ref);
-
- return 0;
-diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
-index 04d86d7b92..24a9c94864 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) ({ \
-@@ -40,6 +41,17 @@
- { "num_output_buffers", "Number of buffers in the output context",\
- OFFSET(num_output_buffers), AV_OPT_TYPE_INT, { .i64 = 16 }, 2, INT_MAX, FLAGS }
-
-+#define FF_V4L2_M2M_TRACK_SIZE 128
-+typedef struct V4L2m2mTrackEl {
-+ int discard; // If we see this buffer its been flushed, so discard
-+ int pkt_size;
-+ int64_t pts;
-+ int64_t reordered_opaque;
-+ int64_t pkt_pos;
-+ int64_t pkt_duration;
-+ int64_t track_pts;
-+} V4L2m2mTrackEl;
-+
- typedef struct V4L2m2mContext {
- char devname[PATH_MAX];
- int fd;
-@@ -53,6 +65,7 @@ typedef struct V4L2m2mContext {
- sem_t refsync;
- atomic_uint refcount;
- int reinit;
-+ int resize_pending;
-
- /* null frame/packet received */
- int draining;
-@@ -66,6 +79,23 @@ typedef struct V4L2m2mContext {
-
- /* reference back to V4L2m2mPriv */
- void *priv;
-+
-+ AVBufferRef *device_ref;
-+
-+ /* generate DRM frames */
-+ int output_drm;
-+
-+ /* Frame tracking */
-+ int64_t last_pkt_dts;
-+ int64_t last_opaque;
-+ unsigned int track_no;
-+ V4L2m2mTrackEl track_els[FF_V4L2_M2M_TRACK_SIZE];
-+
-+ /* req pkt */
-+ int req_pkt;
-+
-+ /* Ext data sent */
-+ int extdata_sent;
- } V4L2m2mContext;
-
- typedef struct V4L2m2mPriv {
-@@ -76,6 +106,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 4944d08511..7f6033ac2c 100644
---- a/libavcodec/v4l2_m2m_dec.c
-+++ b/libavcodec/v4l2_m2m_dec.c
-@@ -23,6 +23,10 @@
-
- #include
- #include
-+
-+#include "libavutil/avassert.h"
-+#include "libavutil/hwcontext.h"
-+#include "libavutil/hwcontext_drm.h"
- #include "libavutil/pixfmt.h"
- #include "libavutil/pixdesc.h"
- #include "libavutil/opt.h"
-@@ -30,26 +34,51 @@
- #include "codec_internal.h"
- #include "libavcodec/decode.h"
-
-+#include "libavcodec/hwaccels.h"
-+#include "libavcodec/internal.h"
-+#include "libavcodec/hwconfig.h"
-+
- #include "v4l2_context.h"
- #include "v4l2_m2m.h"
- #include "v4l2_fmt.h"
-
-+static int check_output_streamon(AVCodecContext *const avctx, V4L2m2mContext *const s)
-+{
-+ int ret;
-+ struct v4l2_decoder_cmd cmd = {
-+ .cmd = V4L2_DEC_CMD_START,
-+ .flags = 0,
-+ };
-+
-+ if (s->output.streamon)
-+ return 0;
-+
-+ ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMON);
-+ if (ret < 0)
-+ av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMON on output context\n");
-+
-+ if (!s->capture.streamon || ret < 0)
-+ return ret;
-+
-+ ret = ioctl(s->fd, VIDIOC_DECODER_CMD, &cmd);
-+ if (ret < 0)
-+ av_log(avctx, AV_LOG_ERROR, "VIDIOC_DECODER_CMD start error: %d\n", errno);
-+ else
-+ av_log(avctx, AV_LOG_DEBUG, "VIDIOC_DECODER_CMD start OK\n");
-+
-+ return ret;
-+}
-+
- static int v4l2_try_start(AVCodecContext *avctx)
- {
- V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context;
- V4L2Context *const capture = &s->capture;
-- V4L2Context *const output = &s->output;
- struct v4l2_selection selection = { 0 };
- int ret;
-
- /* 1. start the output process */
-- if (!output->streamon) {
-- ret = ff_v4l2_context_set_status(output, VIDIOC_STREAMON);
-- if (ret < 0) {
-- av_log(avctx, AV_LOG_DEBUG, "VIDIOC_STREAMON on output context\n");
-- return ret;
-- }
-- }
-+ if ((ret = check_output_streamon(avctx, s)) != 0)
-+ return ret;
-
- if (capture->streamon)
- return 0;
-@@ -63,15 +92,29 @@ static int v4l2_try_start(AVCodecContext *avctx)
- }
-
- /* 2.1 update the AVCodecContext */
-- avctx->pix_fmt = ff_v4l2_format_v4l2_to_avfmt(capture->format.fmt.pix_mp.pixelformat, AV_CODEC_ID_RAWVIDEO);
-- capture->av_pix_fmt = avctx->pix_fmt;
-+ capture->av_pix_fmt =
-+ ff_v4l2_format_v4l2_to_avfmt(capture->format.fmt.pix_mp.pixelformat, AV_CODEC_ID_RAWVIDEO);
-+ if (s->output_drm) {
-+ avctx->pix_fmt = AV_PIX_FMT_DRM_PRIME;
-+ avctx->sw_pix_fmt = capture->av_pix_fmt;
-+ }
-+ else
-+ avctx->pix_fmt = capture->av_pix_fmt;
-
- /* 3. set the crop parameters */
-+#if 1
-+ selection.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-+ selection.target = V4L2_SEL_TGT_CROP_DEFAULT;
-+ ret = ioctl(s->fd, VIDIOC_G_SELECTION, &selection);
-+ av_log(avctx, AV_LOG_INFO, "Post G selection ret=%d, err=%d %dx%d\n", ret, errno, selection.r.width, selection.r.height);
-+#else
- selection.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- selection.r.height = avctx->coded_height;
- selection.r.width = avctx->coded_width;
-+ av_log(avctx, AV_LOG_INFO, "Try selection %dx%d\n", avctx->coded_width, avctx->coded_height);
- ret = ioctl(s->fd, VIDIOC_S_SELECTION, &selection);
-- if (!ret) {
-+ av_log(avctx, AV_LOG_INFO, "Post S selection ret=%d, err=%d %dx%d\n", ret, errno, selection.r.width, selection.r.height);
-+ if (1) {
- ret = ioctl(s->fd, VIDIOC_G_SELECTION, &selection);
- if (ret) {
- av_log(avctx, AV_LOG_WARNING, "VIDIOC_G_SELECTION ioctl\n");
-@@ -82,15 +125,7 @@ static int v4l2_try_start(AVCodecContext *avctx)
- capture->width = selection.r.width;
- }
- }
--
-- /* 4. init the capture context now that we have the capture format */
-- if (!capture->buffers) {
-- ret = ff_v4l2_context_init(capture);
-- if (ret) {
-- av_log(avctx, AV_LOG_ERROR, "can't request capture buffers\n");
-- return AVERROR(ENOMEM);
-- }
-- }
-+#endif
-
- /* 5. start the capture process */
- ret = ff_v4l2_context_set_status(capture, VIDIOC_STREAMON);
-@@ -133,50 +168,287 @@ static int v4l2_prepare_decoder(V4L2m2mContext *s)
- return 0;
- }
-
--static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame)
-+static inline int64_t track_to_pts(AVCodecContext *avctx, unsigned int n)
-+{
-+ return (int64_t)n;
-+}
-+
-+static inline unsigned int pts_to_track(AVCodecContext *avctx, const int64_t pts)
-+{
-+ return (unsigned int)pts;
-+}
-+
-+// FFmpeg requires us to propagate a number of vars from the coded pkt into
-+// the decoded frame. The only thing that tracks like that in V4L2 stateful
-+// is timestamp. PTS maps to timestamp for this decode. FFmpeg makes no
-+// guarantees about PTS being unique or specified for every frame so replace
-+// the supplied PTS with a simple incrementing number and keep a circular
-+// buffer of all the things we want preserved (including the original PTS)
-+// indexed by the tracking no.
-+static void
-+xlat_pts_in(AVCodecContext *const avctx, V4L2m2mContext *const s, AVPacket *const avpkt)
-+{
-+ int64_t track_pts;
-+
-+ // Avoid 0
-+ if (++s->track_no == 0)
-+ s->track_no = 1;
-+
-+ track_pts = track_to_pts(avctx, s->track_no);
-+
-+ av_log(avctx, AV_LOG_TRACE, "In PTS=%" PRId64 ", DTS=%" PRId64 ", track=%" PRId64 ", n=%u\n", avpkt->pts, avpkt->dts, track_pts, s->track_no);
-+ s->last_pkt_dts = avpkt->dts;
-+ s->track_els[s->track_no % FF_V4L2_M2M_TRACK_SIZE] = (V4L2m2mTrackEl){
-+ .discard = 0,
-+ .pkt_size = avpkt->size,
-+ .pts = avpkt->pts,
-+ .reordered_opaque = avctx->reordered_opaque,
-+ .pkt_pos = avpkt->pos,
-+ .pkt_duration = avpkt->duration,
-+ .track_pts = track_pts
-+ };
-+ avpkt->pts = track_pts;
-+}
-+
-+// Returns -1 if we should discard the frame
-+static int
-+xlat_pts_out(AVCodecContext *const avctx, V4L2m2mContext *const s, AVFrame *const frame)
-+{
-+ unsigned int n = pts_to_track(avctx, frame->pts) % FF_V4L2_M2M_TRACK_SIZE;
-+ const V4L2m2mTrackEl *const t = s->track_els + n;
-+ if (frame->pts == AV_NOPTS_VALUE || frame->pts != t->track_pts)
-+ {
-+ av_log(avctx, AV_LOG_INFO, "Tracking failure: pts=%" PRId64 ", track[%d]=%" PRId64 "\n", frame->pts, n, t->track_pts);
-+ frame->pts = AV_NOPTS_VALUE;
-+ frame->pkt_dts = s->last_pkt_dts;
-+ frame->reordered_opaque = s->last_opaque;
-+ frame->pkt_pos = -1;
-+ frame->pkt_duration = 0;
-+ frame->pkt_size = -1;
-+ }
-+ else if (!t->discard)
-+ {
-+ frame->pts = t->pts;
-+ frame->pkt_dts = s->last_pkt_dts;
-+ frame->reordered_opaque = t->reordered_opaque;
-+ frame->pkt_pos = t->pkt_pos;
-+ frame->pkt_duration = t->pkt_duration;
-+ frame->pkt_size = t->pkt_size;
-+
-+ s->last_opaque = s->track_els[n].reordered_opaque;
-+ s->track_els[n].pts = AV_NOPTS_VALUE; // If we hit this again deny accurate knowledge of PTS
-+ }
-+ else
-+ {
-+ av_log(avctx, AV_LOG_DEBUG, "Discard frame (flushed): pts=%" PRId64 ", track[%d]=%" PRId64 "\n", frame->pts, n, t->track_pts);
-+ return -1;
-+ }
-+
-+ frame->best_effort_timestamp = frame->pts;
-+ frame->pkt_dts = frame->pts; // We can't emulate what s/w does in a useful manner?
-+ av_log(avctx, AV_LOG_TRACE, "Out PTS=%" PRId64 ", DTS=%" PRId64 "\n", frame->pts, frame->pkt_dts);
-+ return 0;
-+}
-+
-+static inline int stream_started(const V4L2m2mContext * const s) {
-+ return s->capture.streamon && s->output.streamon;
-+}
-+
-+#define NQ_OK 0
-+#define NQ_Q_FULL 1
-+#define NQ_SRC_EMPTY 2
-+#define NQ_DRAINING 3
-+#define NQ_DEAD 4
-+
-+#define TRY_DQ(nq_status) ((nq_status) >= NQ_OK && (nq_status) <= NQ_DRAINING)
-+
-+// AVERROR_EOF Flushing an already flushed stream
-+// -ve Error (all errors except EOF are unexpected)
-+// NQ_OK (0) OK
-+// NQ_Q_FULL Dst full (retry if we think V4L2 Q has space now)
-+// NQ_SRC_EMPTY Src empty (do not retry)
-+// NQ_DRAINING At EOS, dQ dest until EOS there too
-+// NQ_DEAD Not running (do not retry, do not attempt capture dQ)
-+
-+static int try_enqueue_src(AVCodecContext * const avctx, V4L2m2mContext * const s)
- {
-- V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context;
-- V4L2Context *const capture = &s->capture;
-- V4L2Context *const output = &s->output;
- int ret;
-
-+ // If we don't already have a coded packet - get a new one
-+ // We will already have a coded pkt if the output Q was full last time we
-+ // tried to Q it
- if (!s->buf_pkt.size) {
- ret = ff_decode_get_packet(avctx, &s->buf_pkt);
-+
-+ if (ret == AVERROR(EAGAIN)) {
-+ if (!stream_started(s)) {
-+ av_log(avctx, AV_LOG_TRACE, "%s: receive_frame before 1st coded packet\n", __func__);
-+ return NQ_DEAD;
-+ }
-+ return NQ_SRC_EMPTY;
-+ }
-+
-+ if (ret == AVERROR_EOF) {
-+ // EOF - enter drain mode
-+ av_log(avctx, AV_LOG_TRACE, "--- EOS req: ret=%d, size=%d, started=%d, drain=%d\n",
-+ ret, s->buf_pkt.size, stream_started(s), s->draining);
-+ if (!stream_started(s)) {
-+ av_log(avctx, AV_LOG_DEBUG, "EOS on flushed stream\n");
-+ s->draining = 1;
-+ s->capture.done = 1;
-+ return AVERROR_EOF;
-+ }
-+
-+ if (!s->draining) {
-+ // Calling enqueue with an empty pkt starts drain
-+ av_assert0(s->buf_pkt.size == 0);
-+ ret = ff_v4l2_context_enqueue_packet(&s->output, &s->buf_pkt, NULL, 0, 1);
-+ if (ret) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to start drain: ret=%d\n", ret);
-+ return ret;
-+ }
-+ }
-+ return NQ_DRAINING;
-+ }
-+
- if (ret < 0) {
-- if (ret == AVERROR(EAGAIN))
-- return ff_v4l2_context_dequeue_frame(capture, frame, 0);
-- else if (ret != AVERROR_EOF)
-- return ret;
-+ av_log(avctx, AV_LOG_ERROR, "Failed to get coded packet: err=%d\n", ret);
-+ return ret;
- }
-+
-+ xlat_pts_in(avctx, s, &s->buf_pkt);
- }
-
-- if (s->draining)
-- goto dequeue;
-+ if ((ret = check_output_streamon(avctx, s)) != 0)
-+ return ret;
-
-- ret = ff_v4l2_context_enqueue_packet(output, &s->buf_pkt);
-- if (ret < 0 && ret != AVERROR(EAGAIN))
-- goto fail;
-+ ret = ff_v4l2_context_enqueue_packet(&s->output, &s->buf_pkt,
-+ avctx->extradata, s->extdata_sent ? 0 : avctx->extradata_size,
-+ 1);
-
-- /* if EAGAIN don't unref packet and try to enqueue in the next iteration */
-- if (ret != AVERROR(EAGAIN))
-+ if (ret == AVERROR(EAGAIN)) {
-+ // Out of input buffers - keep packet
-+ ret = NQ_Q_FULL;
-+ }
-+ else {
-+ // In all other cases we are done with this packet
- av_packet_unref(&s->buf_pkt);
-+ s->extdata_sent = 1;
-
-- if (!s->draining) {
-- ret = v4l2_try_start(avctx);
- if (ret) {
-- /* cant recover */
-- if (ret != AVERROR(ENOMEM))
-- ret = 0;
-- goto fail;
-+ av_log(avctx, AV_LOG_ERROR, "Packet enqueue failure: err=%d\n", ret);
-+ return ret;
-+ }
-+ }
-+
-+ // Start if we haven't
-+ {
-+ const int ret2 = v4l2_try_start(avctx);
-+ if (ret2) {
-+ av_log(avctx, AV_LOG_DEBUG, "Start failure: err=%d\n", ret2);
-+ ret = (ret2 == AVERROR(ENOMEM)) ? ret2 : NQ_DEAD;
-+ }
-+ }
-+
-+ return ret;
-+}
-+
-+static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame)
-+{
-+ V4L2m2mContext *const s = ((V4L2m2mPriv*)avctx->priv_data)->context;
-+ int src_rv;
-+ int dst_rv = 1; // Non-zero (done), non-negative (error) number
-+
-+ do {
-+ src_rv = try_enqueue_src(avctx, s);
-+
-+ // If we got a frame last time and we have nothing to enqueue then
-+ // return now. rv will be AVERROR(EAGAIN) indicating that we want more input
-+ // This should mean that once decode starts we enter a stable state where
-+ // we alternately ask for input and produce output
-+ if (s->req_pkt && src_rv == NQ_SRC_EMPTY)
-+ break;
-+
-+ if (src_rv == NQ_Q_FULL && dst_rv == AVERROR(EAGAIN)) {
-+ av_log(avctx, AV_LOG_WARNING, "Poll says src Q has space but enqueue fail");
-+ src_rv = NQ_SRC_EMPTY; // If we can't enqueue pretend that there is nothing to enqueue
-+ }
-+
-+ // Try to get a new frame if
-+ // (a) we haven't already got one AND
-+ // (b) enqueue returned a status indicating that decode should be attempted
-+ if (dst_rv != 0 && TRY_DQ(src_rv)) {
-+ do {
-+ // Dequeue frame will unref any previous contents of frame
-+ // if it returns success so we don't need an explicit unref
-+ // when discarding
-+ // This returns AVERROR(EAGAIN) if there isn't a frame ready yet
-+ // but there is room in the input Q
-+ dst_rv = ff_v4l2_context_dequeue_frame(&s->capture, frame, -1, 1);
-+
-+ if (dst_rv == AVERROR_EOF && (s->draining || s->capture.done))
-+ av_log(avctx, AV_LOG_DEBUG, "Dequeue EOF: draining=%d, cap.done=%d\n",
-+ s->draining, s->capture.done);
-+ else if (dst_rv && dst_rv != AVERROR(EAGAIN))
-+ av_log(avctx, AV_LOG_ERROR, "Packet dequeue failure: draining=%d, cap.done=%d, err=%d\n",
-+ s->draining, s->capture.done, dst_rv);
-+
-+ // Go again if we got a frame that we need to discard
-+ } while (dst_rv == 0 && xlat_pts_out(avctx, s, frame));
-+ }
-+
-+ // Continue trying to enqueue packets if either
-+ // (a) we succeeded last time OR
-+ // (b) enqueue failed due to input Q full AND there is now room
-+ } while (src_rv == NQ_OK || (src_rv == NQ_Q_FULL && dst_rv == AVERROR(EAGAIN)) );
-+
-+ // Ensure that the frame contains nothing if we aren't returning a frame
-+ // (might happen when discarding)
-+ if (dst_rv)
-+ av_frame_unref(frame);
-+
-+ // If we got a frame this time ask for a pkt next time
-+ s->req_pkt = (dst_rv == 0);
-+
-+#if 0
-+ if (dst_rv == 0)
-+ {
-+ static int z = 0;
-+ if (++z > 50) {
-+ av_log(avctx, AV_LOG_ERROR, "Streamoff and die?\n");
-+ ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
-+ return -1;
- }
- }
-+#endif
-+
-+ return dst_rv == 0 ? 0 :
-+ src_rv < 0 ? src_rv :
-+ dst_rv < 0 ? dst_rv :
-+ AVERROR(EAGAIN);
-+}
-+
-+#if 0
-+#include
-+static int64_t us_time(void)
-+{
-+ struct timespec ts;
-+ clock_gettime(CLOCK_MONOTONIC, &ts);
-+ return (int64_t)ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
-+}
-
--dequeue:
-- return ff_v4l2_context_dequeue_frame(capture, frame, -1);
--fail:
-- av_packet_unref(&s->buf_pkt);
-+static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame)
-+{
-+ int ret;
-+ const int64_t now = us_time();
-+ int64_t done;
-+ av_log(avctx, AV_LOG_TRACE, "<<< %s\n", __func__);
-+ ret = v4l2_receive_frame2(avctx, frame);
-+ done = us_time();
-+ av_log(avctx, AV_LOG_TRACE, ">>> %s: rx time=%" PRId64 ", rv=%d\n", __func__, done - now, ret);
- return ret;
- }
-+#endif
-
- static av_cold int v4l2_decode_init(AVCodecContext *avctx)
- {
-@@ -185,6 +457,9 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx)
- V4L2m2mPriv *priv = avctx->priv_data;
- int ret;
-
-+ av_log(avctx, AV_LOG_TRACE, "<<< %s\n", __func__);
-+ avctx->pix_fmt = AV_PIX_FMT_DRM_PRIME;
-+
- ret = ff_v4l2_m2m_create_context(priv, &s);
- if (ret < 0)
- return ret;
-@@ -205,6 +480,28 @@ 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.
-+ */
-+ switch (ff_get_format(avctx, avctx->codec->pix_fmts)) {
-+ default:
-+ s->output_drm = 1;
-+ 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) {
-@@ -217,7 +514,53 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx)
-
- static av_cold int v4l2_decode_close(AVCodecContext *avctx)
- {
-- return ff_v4l2_m2m_codec_end(avctx->priv_data);
-+ int rv;
-+ av_log(avctx, AV_LOG_TRACE, "<<< %s\n", __func__);
-+ rv = ff_v4l2_m2m_codec_end(avctx->priv_data);
-+ av_log(avctx, AV_LOG_TRACE, ">>> %s: rv=%d\n", __func__, rv);
-+ return rv;
-+}
-+
-+static void v4l2_decode_flush(AVCodecContext *avctx)
-+{
-+ // An alternatve and more drastic form of flush is to simply do this:
-+ // v4l2_decode_close(avctx);
-+ // v4l2_decode_init(avctx);
-+ // The downside is that this keeps a decoder open until all the frames
-+ // associated with it have been returned. This is a bit wasteful on
-+ // possibly limited h/w resources and fails on a Pi for this reason unless
-+ // more GPU mem is allocated than is the default.
-+
-+ V4L2m2mPriv * const priv = avctx->priv_data;
-+ V4L2m2mContext * const s = priv->context;
-+ V4L2Context * const output = &s->output;
-+ V4L2Context * const capture = &s->capture;
-+ int ret, i;
-+
-+ av_log(avctx, AV_LOG_TRACE, "<<< %s: streamon=%d\n", __func__, output->streamon);
-+
-+ // Reflushing everything is benign, quick and avoids having to worry about
-+ // states like EOS processing so don't try to optimize out (having got it
-+ // wrong once)
-+
-+ ret = ff_v4l2_context_set_status(output, VIDIOC_STREAMOFF);
-+ if (ret < 0)
-+ av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s error: %d\n", output->name, ret);
-+
-+ // V4L2 makes no guarantees about whether decoded frames are flushed or not
-+ // so mark all frames we are tracking to be discarded if they appear
-+ for (i = 0; i != FF_V4L2_M2M_TRACK_SIZE; ++i)
-+ s->track_els[i].discard = 1;
-+
-+ // resend extradata
-+ s->extdata_sent = 0;
-+ // clear EOS status vars
-+ s->draining = 0;
-+ output->done = 0;
-+ capture->done = 0;
-+
-+ // Stream on will occur when we actually submit a new frame
-+ av_log(avctx, AV_LOG_TRACE, ">>> %s\n", __func__);
- }
-
- #define OFFSET(x) offsetof(V4L2m2mPriv, x)
-@@ -227,9 +570,15 @@ 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},
- };
-
-+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", \
-@@ -250,11 +599,16 @@ static const AVOption options[] = {
- .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 | \
- FF_CODEC_CAP_SETS_PKT_DTS | 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, \
- }
-
- M2MDEC(h264, "H.264", AV_CODEC_ID_H264, "h264_mp4toannexb");
-
-From 12f8f12326b83dd3c22084f8922705d79a13d195 Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Thu, 10 Jun 2021 18:46:21 +0100
-Subject: [PATCH 017/151] Fix crash in hw_device_default_name if type not found
- (NONE)
-
----
- fftools/ffmpeg_hw.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/fftools/ffmpeg_hw.c b/fftools/ffmpeg_hw.c
-index 88fa782470..740a5e7153 100644
---- a/fftools/ffmpeg_hw.c
-+++ b/fftools/ffmpeg_hw.c
-@@ -75,6 +75,8 @@ static char *hw_device_default_name(enum AVHWDeviceType type)
- char *name;
- size_t index_pos;
- int index, index_limit = 1000;
-+ if (!type_name)
-+ return NULL;
- index_pos = strlen(type_name);
- name = av_malloc(index_pos + 4);
- if (!name)
-
-From 7f6bce459e683bff3a0b972922fbcc808e9177a6 Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Thu, 10 Jun 2021 18:59:18 +0100
-Subject: [PATCH 018/151] Allow v4l2m2m to select non-drm_prime output formats
-
----
- libavcodec/v4l2_buffers.c | 2 +-
- libavcodec/v4l2_m2m_dec.c | 14 ++++++++++----
- 2 files changed, 11 insertions(+), 5 deletions(-)
-
-diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
-index a003934ca1..1ca1128db6 100644
---- a/libavcodec/v4l2_buffers.c
-+++ b/libavcodec/v4l2_buffers.c
-@@ -524,7 +524,7 @@ static int v4l2_buffer_swframe_to_buf(const AVFrame *frame, V4L2Buffer *out)
- offset += dst_stride * out->context->height;
- }
- if (offset > out->plane_info[0].length) {
-- av_log(NULL, AV_LOG_ERROR, "%s: Plane total %d > buffer size %d\n", __func__, offset, out->plane_info[0].length);
-+ av_log(NULL, AV_LOG_ERROR, "%s: Plane total %u > buffer size %zu\n", __func__, offset, out->plane_info[0].length);
- return -1;
- }
-
-diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
-index 7f6033ac2c..a4b5a4e7e9 100644
---- a/libavcodec/v4l2_m2m_dec.c
-+++ b/libavcodec/v4l2_m2m_dec.c
-@@ -455,10 +455,10 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx)
- V4L2Context *capture, *output;
- V4L2m2mContext *s;
- V4L2m2mPriv *priv = avctx->priv_data;
-+ int gf_pix_fmt;
- int ret;
-
- av_log(avctx, AV_LOG_TRACE, "<<< %s\n", __func__);
-- avctx->pix_fmt = AV_PIX_FMT_DRM_PRIME;
-
- ret = ff_v4l2_m2m_create_context(priv, &s);
- if (ret < 0)
-@@ -486,10 +486,15 @@ 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.
- */
-- switch (ff_get_format(avctx, avctx->codec->pix_fmts)) {
-- default:
-+
-+ gf_pix_fmt = ff_get_format(avctx, avctx->codec->pix_fmts);
-+ av_log(avctx, AV_LOG_DEBUG, "avctx requested=%d (%s); get_format requested=%d (%s)\n",
-+ avctx->pix_fmt, av_get_pix_fmt_name(avctx->pix_fmt), gf_pix_fmt, av_get_pix_fmt_name(gf_pix_fmt));
-+
-+ s->output_drm = 0;
-+ if (gf_pix_fmt == AV_PIX_FMT_DRM_PRIME || avctx->pix_fmt == AV_PIX_FMT_DRM_PRIME) {
-+ avctx->pix_fmt = AV_PIX_FMT_DRM_PRIME;
- s->output_drm = 1;
-- break;
- }
-
- s->device_ref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_DRM);
-@@ -607,6 +612,7 @@ static const AVCodecHWConfigInternal *v4l2_m2m_hw_configs[] = {
- .p.wrapper_name = "v4l2m2m", \
- .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \
- AV_PIX_FMT_NV12, \
-+ AV_PIX_FMT_YUV420P, \
- AV_PIX_FMT_NONE}, \
- .hw_configs = v4l2_m2m_hw_configs, \
- }
-
-From 9b0d964b727d98271f7f2f4dcdbcb1b41a429e2b Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Thu, 10 Jun 2021 18:59:38 +0100
-Subject: [PATCH 019/151] Fix YUV420P output from v4l2m2m
-
-Also put get_width get_height inlines in header as they are generally
-useful.
----
- libavcodec/v4l2_buffers.c | 12 ++++++------
- libavcodec/v4l2_context.c | 22 ++++++----------------
- libavcodec/v4l2_m2m.h | 12 ++++++++++++
- 3 files changed, 24 insertions(+), 22 deletions(-)
-
-diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
-index 1ca1128db6..f4c11ca8d0 100644
---- a/libavcodec/v4l2_buffers.c
-+++ b/libavcodec/v4l2_buffers.c
-@@ -425,17 +425,17 @@ static int v4l2_buffer_buf_to_swframe(AVFrame *frame, V4L2Buffer *avbuf)
- case AV_PIX_FMT_NV21:
- if (avbuf->num_planes > 1)
- break;
-- frame->linesize[1] = avbuf->plane_info[0].bytesperline;
-- frame->data[1] = frame->buf[0]->data + avbuf->plane_info[0].bytesperline * avbuf->context->format.fmt.pix_mp.height;
-+ frame->linesize[1] = frame->linesize[0];
-+ frame->data[1] = frame->data[0] + frame->linesize[0] * ff_v4l2_get_format_height(&avbuf->context->format);
- break;
-
- case AV_PIX_FMT_YUV420P:
- if (avbuf->num_planes > 1)
- break;
-- frame->linesize[1] = avbuf->plane_info[0].bytesperline >> 1;
-- frame->linesize[2] = avbuf->plane_info[0].bytesperline >> 1;
-- frame->data[1] = frame->buf[0]->data + avbuf->plane_info[0].bytesperline * avbuf->context->format.fmt.pix_mp.height;
-- frame->data[2] = frame->data[1] + ((avbuf->plane_info[0].bytesperline * avbuf->context->format.fmt.pix_mp.height) >> 2);
-+ frame->linesize[1] = frame->linesize[0] / 2;
-+ frame->linesize[2] = frame->linesize[1];
-+ frame->data[1] = frame->data[0] + frame->linesize[0] * ff_v4l2_get_format_height(&avbuf->context->format);
-+ frame->data[2] = frame->data[1] + frame->linesize[1] * ff_v4l2_get_format_height(&avbuf->context->format) / 2;
- break;
-
- default:
-diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
-index be76068af3..6fe2586627 100644
---- a/libavcodec/v4l2_context.c
-+++ b/libavcodec/v4l2_context.c
-@@ -55,16 +55,6 @@ static inline AVCodecContext *logger(V4L2Context *ctx)
- return ctx_to_m2mctx(ctx)->avctx;
- }
-
--static inline unsigned int v4l2_get_width(struct v4l2_format *fmt)
--{
-- return V4L2_TYPE_IS_MULTIPLANAR(fmt->type) ? fmt->fmt.pix_mp.width : fmt->fmt.pix.width;
--}
--
--static inline unsigned int v4l2_get_height(struct v4l2_format *fmt)
--{
-- return V4L2_TYPE_IS_MULTIPLANAR(fmt->type) ? fmt->fmt.pix_mp.height : fmt->fmt.pix.height;
--}
--
- static AVRational v4l2_get_sar(V4L2Context *ctx)
- {
- struct AVRational sar = { 0, 1 };
-@@ -96,8 +86,8 @@ static inline unsigned int v4l2_resolution_changed(V4L2Context *ctx, struct v4l2
- if (ret)
- av_log(logger(ctx), AV_LOG_DEBUG, "%s changed (%dx%d) -> (%dx%d)\n",
- ctx->name,
-- v4l2_get_width(fmt1), v4l2_get_height(fmt1),
-- v4l2_get_width(fmt2), v4l2_get_height(fmt2));
-+ ff_v4l2_get_format_width(fmt1), ff_v4l2_get_format_height(fmt1),
-+ ff_v4l2_get_format_width(fmt2), ff_v4l2_get_format_height(fmt2));
-
- return ret;
- }
-@@ -195,8 +185,8 @@ static int do_source_change(V4L2m2mContext * const s)
-
- reinit = v4l2_resolution_changed(&s->capture, &cap_fmt);
- if (reinit) {
-- s->capture.height = v4l2_get_height(&cap_fmt);
-- s->capture.width = v4l2_get_width(&cap_fmt);
-+ s->capture.height = ff_v4l2_get_format_height(&cap_fmt);
-+ s->capture.width = ff_v4l2_get_format_width(&cap_fmt);
- }
- s->capture.sample_aspect_ratio = v4l2_get_sar(&s->capture);
-
-@@ -973,8 +963,8 @@ static int create_buffers(V4L2Context* const ctx, const unsigned int req_buffers
- av_log(logger(ctx), AV_LOG_DEBUG, "%s: %s %02d buffers initialized: %04ux%04u, sizeimage %08u, bytesperline %08u\n", ctx->name,
- V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? av_fourcc2str(ctx->format.fmt.pix_mp.pixelformat) : av_fourcc2str(ctx->format.fmt.pix.pixelformat),
- req.count,
-- v4l2_get_width(&ctx->format),
-- v4l2_get_height(&ctx->format),
-+ ff_v4l2_get_format_width(&ctx->format),
-+ ff_v4l2_get_format_height(&ctx->format),
- V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? ctx->format.fmt.pix_mp.plane_fmt[0].sizeimage : ctx->format.fmt.pix.sizeimage,
- V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? ctx->format.fmt.pix_mp.plane_fmt[0].bytesperline : ctx->format.fmt.pix.bytesperline);
-
-diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
-index 24a9c94864..8f054f2f50 100644
---- a/libavcodec/v4l2_m2m.h
-+++ b/libavcodec/v4l2_m2m.h
-@@ -160,4 +160,16 @@ int ff_v4l2_m2m_codec_reinit(V4L2m2mContext *ctx);
- */
- int ff_v4l2_m2m_codec_full_reinit(V4L2m2mContext *ctx);
-
-+
-+static inline unsigned int ff_v4l2_get_format_width(struct v4l2_format *fmt)
-+{
-+ return V4L2_TYPE_IS_MULTIPLANAR(fmt->type) ? fmt->fmt.pix_mp.width : fmt->fmt.pix.width;
-+}
-+
-+static inline unsigned int ff_v4l2_get_format_height(struct v4l2_format *fmt)
-+{
-+ return V4L2_TYPE_IS_MULTIPLANAR(fmt->type) ? fmt->fmt.pix_mp.height : fmt->fmt.pix.height;
-+}
-+
-+
- #endif /* AVCODEC_V4L2_M2M_H */
-
-From 14e9b4bf1b34b3d1e1e6a4fc755cc595416e7d7b Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Thu, 10 Jun 2021 19:23:44 +0100
-Subject: [PATCH 020/151] Report buffer overflows in v4l2m2m
-
----
- libavcodec/v4l2_buffers.c | 14 ++++++++++----
- libavcodec/v4l2_context.c | 5 ++++-
- 2 files changed, 14 insertions(+), 5 deletions(-)
-
-diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
-index f4c11ca8d0..de31f7ced9 100644
---- a/libavcodec/v4l2_buffers.c
-+++ b/libavcodec/v4l2_buffers.c
-@@ -364,6 +364,7 @@ static int v4l2_buffer_export_drm(V4L2Buffer* avbuf)
- static int v4l2_bufref_to_buf(V4L2Buffer *out, int plane, const uint8_t* data, int size, int offset)
- {
- unsigned int bytesused, length;
-+ int rv = 0;
-
- if (plane >= out->num_planes)
- return AVERROR(EINVAL);
-@@ -371,11 +372,16 @@ static int v4l2_bufref_to_buf(V4L2Buffer *out, int plane, const uint8_t* data, i
- length = out->plane_info[plane].length;
- bytesused = FFMIN(size+offset, length);
-
-- memcpy((uint8_t*)out->plane_info[plane].mm_addr+offset, data, FFMIN(size, length-offset));
-+ if (size > length - offset) {
-+ size = length - offset;
-+ rv = AVERROR(ENOMEM);
-+ }
-+
-+ memcpy((uint8_t*)out->plane_info[plane].mm_addr+offset, data, size);
-
- set_buf_length(out, plane, bytesused, length);
-
-- return 0;
-+ return rv;
- }
-
- static AVBufferRef * wrap_avbuf(V4L2Buffer * const avbuf)
-@@ -630,7 +636,7 @@ int ff_v4l2_buffer_avpkt_to_buf_ext(const AVPacket *pkt, V4L2Buffer *out,
- }
-
- ret = v4l2_bufref_to_buf(out, 0, pkt->data, pkt->size, extlen);
-- if (ret)
-+ if (ret && ret != AVERROR(ENOMEM))
- return ret;
-
- v4l2_set_pts(out, pkt->pts, no_rescale_pts);
-@@ -638,7 +644,7 @@ int ff_v4l2_buffer_avpkt_to_buf_ext(const AVPacket *pkt, V4L2Buffer *out,
- if (pkt->flags & AV_PKT_FLAG_KEY)
- out->flags = V4L2_BUF_FLAG_KEYFRAME;
-
-- return 0;
-+ return ret;
- }
-
- int ff_v4l2_buffer_avpkt_to_buf(const AVPacket *pkt, V4L2Buffer *out)
-diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
-index 6fe2586627..81aced0c2b 100644
---- a/libavcodec/v4l2_context.c
-+++ b/libavcodec/v4l2_context.c
-@@ -824,7 +824,10 @@ int ff_v4l2_context_enqueue_packet(V4L2Context* ctx, const AVPacket* pkt,
- return AVERROR(EAGAIN);
-
- ret = ff_v4l2_buffer_avpkt_to_buf_ext(pkt, avbuf, extdata, extlen, no_rescale_pts);
-- if (ret)
-+ if (ret == AVERROR(ENOMEM))
-+ av_log(logger(ctx), AV_LOG_ERROR, "Buffer overflow in %s: pkt->size=%d > buf->length=%d\n",
-+ __func__, pkt->size, avbuf->planes[0].length);
-+ else if (ret)
- return ret;
-
- return ff_v4l2_buffer_enqueue(avbuf);
-
-From 072907a7fcf160d12972997d24fdf62641687ea4 Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Mon, 14 Jun 2021 11:55:16 +0100
-Subject: [PATCH 021/151] Increase V4L2 H264 stateful coded buffer size
-
-Try to set a min size of frame size / 2 for bitbuffers passed to V4l2.
-This fixes a few streams that have large I-frames. You would hope
-Annex-A gave useful minCR so an appropriate size could be calculated
-but it doesn't really. It gives good guidance for bits required over
-time but the instantaneous limits are very weak so it is possible
-that even this won't be enough. The correct long term solution would
-be to have resizable dmabufs but that is a greter rewrite than seems
-sensible now.
----
- libavcodec/v4l2_context.c | 24 +++++++++++++++++++++++-
- libavcodec/v4l2_context.h | 6 ++++++
- libavcodec/v4l2_m2m_dec.c | 24 ++++++++++++++++++++++++
- 3 files changed, 53 insertions(+), 1 deletion(-)
-
-diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
-index 81aced0c2b..a17ae027a6 100644
---- a/libavcodec/v4l2_context.c
-+++ b/libavcodec/v4l2_context.c
-@@ -902,7 +902,29 @@ int ff_v4l2_context_get_format(V4L2Context* ctx, int probe)
-
- int ff_v4l2_context_set_format(V4L2Context* ctx)
- {
-- return ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_S_FMT, &ctx->format);
-+ int ret;
-+
-+ ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_S_FMT, &ctx->format);
-+ if (ret != 0)
-+ return ret;
-+
-+ // Check returned size against min size and if smaller have another go
-+ // Only worry about plane[0] as this is meant to enforce limits for
-+ // encoded streams where we might know a bit more about the shape
-+ // than the driver
-+ if (V4L2_TYPE_IS_MULTIPLANAR(ctx->format.type)) {
-+ if (ctx->min_buf_size <= ctx->format.fmt.pix_mp.plane_fmt[0].sizeimage)
-+ return 0;
-+ ctx->format.fmt.pix_mp.plane_fmt[0].sizeimage = ctx->min_buf_size;
-+ }
-+ else {
-+ if (ctx->min_buf_size <= ctx->format.fmt.pix.sizeimage)
-+ return 0;
-+ ctx->format.fmt.pix.sizeimage = ctx->min_buf_size;
-+ }
-+
-+ ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_S_FMT, &ctx->format);
-+ return ret;
- }
-
- void ff_v4l2_context_release(V4L2Context* ctx)
-diff --git a/libavcodec/v4l2_context.h b/libavcodec/v4l2_context.h
-index 59009d11d1..37b0431400 100644
---- a/libavcodec/v4l2_context.h
-+++ b/libavcodec/v4l2_context.h
-@@ -75,6 +75,12 @@ typedef struct V4L2Context {
- AVRational sample_aspect_ratio;
- struct v4l2_rect selection;
-
-+ /**
-+ * If the default size of buffer is less than this then try to
-+ * set to this.
-+ */
-+ uint32_t min_buf_size;
-+
- /**
- * Indexed array of pointers to V4L2Buffers
- */
-diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
-index a4b5a4e7e9..1851acbc93 100644
---- a/libavcodec/v4l2_m2m_dec.c
-+++ b/libavcodec/v4l2_m2m_dec.c
-@@ -450,6 +450,27 @@ static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame)
- }
- #endif
-
-+static uint32_t max_coded_size(const AVCodecContext * const avctx)
-+{
-+ uint32_t wxh = avctx->coded_width * avctx->coded_height;
-+ uint32_t size;
-+
-+ // Currently the only thing we try to set our own limits for is H264
-+ if (avctx->codec_id != AV_CODEC_ID_H264)
-+ return 0;
-+
-+ size = wxh * 3 / 2;
-+ // H.264 Annex A table A-1 gives minCR which is either 2 or 4
-+ // unfortunately that doesn't yield an actually useful limit
-+ // and it should be noted that frame 0 is special cased to allow
-+ // a bigger number which really isn't helpful for us. So just pick
-+ // frame_size / 2
-+ size /= 2;
-+ // Add 64k to allow for any overheads and/or encoder hopefulness
-+ // with small WxH
-+ return size + (1 << 16);
-+}
-+
- static av_cold int v4l2_decode_init(AVCodecContext *avctx)
- {
- V4L2Context *capture, *output;
-@@ -460,6 +481,7 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx)
-
- av_log(avctx, AV_LOG_TRACE, "<<< %s\n", __func__);
-
-+ av_log(avctx, AV_LOG_INFO, "level=%d\n", avctx->level);
- ret = ff_v4l2_m2m_create_context(priv, &s);
- if (ret < 0)
- return ret;
-@@ -476,9 +498,11 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx)
-
- output->av_codec_id = avctx->codec_id;
- output->av_pix_fmt = AV_PIX_FMT_NONE;
-+ output->min_buf_size = max_coded_size(avctx);
-
- capture->av_codec_id = AV_CODEC_ID_RAWVIDEO;
- capture->av_pix_fmt = avctx->pix_fmt;
-+ capture->min_buf_size = 0;
-
- /* the client requests the codec to generate DRM frames:
- * - data[0] will therefore point to the returned AVDRMFrameDescriptor
-
-From 6087c8c054e1ff3d2e6e62d5e32705d079928b64 Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Mon, 28 Jun 2021 12:13:35 +0100
-Subject: [PATCH 022/151] Fix raw video s.t. it respects any remaining cropping
-
-This fixes the long standing CONFWIN_A conformance test failure for drm.
----
- libavcodec/rawenc.c | 32 ++++++++---
- libavutil/hwcontext_drm.c | 112 ++++++++++++++++++++++++++++++++++++--
- 2 files changed, 130 insertions(+), 14 deletions(-)
-
-diff --git a/libavcodec/rawenc.c b/libavcodec/rawenc.c
-index 594a77c42a..8ca0379e12 100644
---- a/libavcodec/rawenc.c
-+++ b/libavcodec/rawenc.c
-@@ -124,32 +124,41 @@ static int raw_sand30_as_yuv420(AVCodecContext *avctx, AVPacket *pkt,
-
-
- static int raw_encode(AVCodecContext *avctx, AVPacket *pkt,
-- const AVFrame *frame, int *got_packet)
-+ const AVFrame *src_frame, int *got_packet)
- {
- int ret;
-+ AVFrame * frame = NULL;
-
- #if CONFIG_SAND
-- if (av_rpi_is_sand_frame(frame)) {
-- ret = av_rpi_is_sand8_frame(frame) ? raw_sand8_as_yuv420(avctx, pkt, frame) :
-- av_rpi_is_sand16_frame(frame) ? raw_sand16_as_yuv420(avctx, pkt, frame) :
-- av_rpi_is_sand30_frame(frame) ? raw_sand30_as_yuv420(avctx, pkt, frame) : -1;
-+ if (av_rpi_is_sand_frame(src_frame)) {
-+ ret = av_rpi_is_sand8_frame(src_frame) ? raw_sand8_as_yuv420(avctx, pkt, src_frame) :
-+ av_rpi_is_sand16_frame(src_frame) ? raw_sand16_as_yuv420(avctx, pkt, src_frame) :
-+ av_rpi_is_sand30_frame(src_frame) ? raw_sand30_as_yuv420(avctx, pkt, src_frame) : -1;
- *got_packet = (ret == 0);
- return ret;
- }
- #endif
-
-+ if ((frame = av_frame_clone(src_frame)) == NULL) {
-+ ret = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+
-+ if ((ret = av_frame_apply_cropping(frame, AV_FRAME_CROP_UNALIGNED)) < 0)
-+ goto fail;
-+
- ret = av_image_get_buffer_size(frame->format,
- frame->width, frame->height, 1);
- if (ret < 0)
-- return ret;
-+ goto fail;
-
- if ((ret = ff_get_encode_buffer(avctx, pkt, ret, 0)) < 0)
-- return ret;
-+ goto fail;
- if ((ret = av_image_copy_to_buffer(pkt->data, pkt->size,
- (const uint8_t **)frame->data, frame->linesize,
- frame->format,
- frame->width, frame->height, 1)) < 0)
-- return ret;
-+ goto fail;
-
- if(avctx->codec_tag == AV_RL32("yuv2") && ret > 0 &&
- frame->format == AV_PIX_FMT_YUYV422) {
-@@ -165,8 +174,15 @@ static int raw_encode(AVCodecContext *avctx, AVPacket *pkt,
- AV_WB64(&pkt->data[8 * x], v << 48 | v >> 16);
- }
- }
-+ pkt->flags |= AV_PKT_FLAG_KEY;
-+ av_frame_free(&frame);
- *got_packet = 1;
- return 0;
-+
-+fail:
-+ av_frame_free(&frame);
-+ *got_packet = 0;
-+ return ret;
- }
-
- const FFCodec ff_rawvideo_encoder = {
-diff --git a/libavutil/hwcontext_drm.c b/libavutil/hwcontext_drm.c
-index 7a9fdbd263..baf18920fa 100644
---- a/libavutil/hwcontext_drm.c
-+++ b/libavutil/hwcontext_drm.c
-@@ -21,6 +21,7 @@
- #include
- #include
- #include
-+#include
-
- /* This was introduced in version 4.6. And may not exist all without an
- * optional package. So to prevent a hard dependency on needing the Linux
-@@ -31,6 +32,7 @@
- #endif
-
- #include
-+#include
- #include
-
- #include "avassert.h"
-@@ -38,7 +40,9 @@
- #include "hwcontext_drm.h"
- #include "hwcontext_internal.h"
- #include "imgutils.h"
--
-+#if CONFIG_SAND
-+#include "libavutil/rpi_sand_fns.h"
-+#endif
-
- static void drm_device_free(AVHWDeviceContext *hwdev)
- {
-@@ -53,6 +57,11 @@ static int drm_device_create(AVHWDeviceContext *hwdev, const char *device,
- AVDRMDeviceContext *hwctx = hwdev->hwctx;
- drmVersionPtr version;
-
-+ if (device == NULL) {
-+ hwctx->fd = -1;
-+ return 0;
-+ }
-+
- hwctx->fd = open(device, O_RDWR);
- if (hwctx->fd < 0)
- return AVERROR(errno);
-@@ -139,6 +148,8 @@ static int drm_map_frame(AVHWFramesContext *hwfc,
- if (flags & AV_HWFRAME_MAP_WRITE)
- mmap_prot |= PROT_WRITE;
-
-+ if (dst->format == AV_PIX_FMT_NONE)
-+ dst->format = hwfc->sw_format;
- #if HAVE_LINUX_DMA_BUF_H
- if (flags & AV_HWFRAME_MAP_READ)
- map->sync_flags |= DMA_BUF_SYNC_READ;
-@@ -185,6 +196,23 @@ static int drm_map_frame(AVHWFramesContext *hwfc,
-
- dst->width = src->width;
- dst->height = src->height;
-+ dst->crop_top = src->crop_top;
-+ dst->crop_bottom = src->crop_bottom;
-+ dst->crop_left = src->crop_left;
-+ dst->crop_right = src->crop_right;
-+
-+#if CONFIG_SAND
-+ // Rework for sand frames
-+ if (av_rpi_is_sand_frame(dst)) {
-+ // As it stands the sand formats hold stride2 in linesize[3]
-+ // linesize[0] & [1] contain stride1 which is always 128 for everything we do
-+ // * Arguably this should be reworked s.t. stride2 is in linesize[0] & [1]
-+ dst->linesize[3] = fourcc_mod_broadcom_param(desc->objects[0].format_modifier);
-+ dst->linesize[0] = 128;
-+ dst->linesize[1] = 128;
-+ // *** Are we sure src->height is actually what we want ???
-+ }
-+#endif
-
- err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
- &drm_unmap_frame, map);
-@@ -212,7 +240,15 @@ static int drm_transfer_get_formats(AVHWFramesContext *ctx,
- if (!pix_fmts)
- return AVERROR(ENOMEM);
-
-- pix_fmts[0] = ctx->sw_format;
-+ // **** Offer native sand too ????
-+ pix_fmts[0] =
-+#if CONFIG_SAND
-+ ctx->sw_format == AV_PIX_FMT_RPI4_8 || ctx->sw_format == AV_PIX_FMT_SAND128 ?
-+ AV_PIX_FMT_YUV420P :
-+ ctx->sw_format == AV_PIX_FMT_RPI4_10 ?
-+ AV_PIX_FMT_YUV420P10LE :
-+#endif
-+ ctx->sw_format;
- pix_fmts[1] = AV_PIX_FMT_NONE;
-
- *formats = pix_fmts;
-@@ -231,18 +267,79 @@ static int drm_transfer_data_from(AVHWFramesContext *hwfc,
- map = av_frame_alloc();
- if (!map)
- return AVERROR(ENOMEM);
-- map->format = dst->format;
-
-+ // Map to default
-+ map->format = AV_PIX_FMT_NONE;
- err = drm_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
- if (err)
- goto fail;
-
-- map->width = dst->width;
-- map->height = dst->height;
-+#if 0
-+ av_log(hwfc, AV_LOG_INFO, "%s: src fmt=%d (%d), dst fmt=%d (%d) s=%dx%d l=%d/%d/%d/%d, d=%dx%d l=%d/%d/%d\n", __func__,
-+ hwfc->sw_format, AV_PIX_FMT_RPI4_8, dst->format, AV_PIX_FMT_YUV420P10LE,
-+ map->width, map->height,
-+ map->linesize[0],
-+ map->linesize[1],
-+ map->linesize[2],
-+ map->linesize[3],
-+ dst->width, dst->height,
-+ dst->linesize[0],
-+ dst->linesize[1],
-+ dst->linesize[2]);
-+#endif
-+#if CONFIG_SAND
-+ if (av_rpi_is_sand_frame(map)) {
-+ // Preserve crop - later ffmpeg code assumes that we have in that it
-+ // overwrites any crop that we create with the old values
-+ const unsigned int w = FFMIN(dst->width, map->width);
-+ const unsigned int h = FFMIN(dst->height, map->height);
-+
-+ if (map->format == AV_PIX_FMT_RPI4_8 && dst->format == AV_PIX_FMT_YUV420P) {
-+ av_rpi_sand_to_planar_y8(dst->data[0], dst->linesize[0],
-+ map->data[0],
-+ 128, stride2,
-+ 0, 0, w, h);
-+ av_rpi_sand_to_planar_c8(dst->data[1], dst->linesize[1],
-+ dst->data[2], dst->linesize[2],
-+ map->data[1],
-+ 128, stride2,
-+ 0, 0, w / 2, h / 2);
-+ }
-+ else if (map->format == AV_PIX_FMT_RPI4_10 && dst->format == AV_PIX_FMT_YUV420P10LE) {
-+ av_rpi_sand30_to_planar_y16(dst->data[0], dst->linesize[0],
-+ map->data[0],
-+ 128, stride2,
-+ 0, 0, w, h);
-+ av_rpi_sand30_to_planar_c16(dst->data[1], dst->linesize[1],
-+ dst->data[2], dst->linesize[2],
-+ map->data[1],
-+ 128, stride2,
-+ 0, 0, w / 2, h / 2);
-+ }
-+ else
-+ {
-+ av_log(hwfc, AV_LOG_ERROR, "%s: Incompatible output pixfmt for sand\n", __func__);
-+ err = AVERROR(EINVAL);
-+ goto fail;
-+ }
-+
-+ dst->width = w;
-+ dst->height = h;
-+ }
-+ else
-+#endif
-+ {
-+ // Kludge mapped h/w s.t. frame_copy works
-+ map->width = dst->width;
-+ map->height = dst->height;
-+ err = av_frame_copy(dst, map);
-+ }
-
-- err = av_frame_copy(dst, map);
- if (err)
-+ {
-+ av_log(hwfc, AV_LOG_ERROR, "%s: Copy fail\n", __func__);
- goto fail;
-+ }
-
- err = 0;
- fail:
-@@ -257,7 +354,10 @@ static int drm_transfer_data_to(AVHWFramesContext *hwfc,
- int err;
-
- if (src->width > hwfc->width || src->height > hwfc->height)
-+ {
-+ av_log(hwfc, AV_LOG_ERROR, "%s: H/w mismatch: %d/%d, %d/%d\n", __func__, dst->width, hwfc->width, dst->height, hwfc->height);
- return AVERROR(EINVAL);
-+ }
-
- map = av_frame_alloc();
- if (!map)
-
-From 597858c11fbfbe0f54c1b68d9683025929258bc1 Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Fri, 13 Aug 2021 15:38:28 +0100
-Subject: [PATCH 023/151] Set frame interlace from V4L2 buffer field
-
----
- libavcodec/v4l2_buffers.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
-diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
-index de31f7ced9..97b8eb1db3 100644
---- a/libavcodec/v4l2_buffers.c
-+++ b/libavcodec/v4l2_buffers.c
-@@ -222,6 +222,16 @@ static enum AVColorTransferCharacteristic v4l2_get_color_trc(V4L2Buffer *buf)
- return AVCOL_TRC_UNSPECIFIED;
- }
-
-+static int v4l2_buf_is_interlaced(const V4L2Buffer * const buf)
-+{
-+ return V4L2_FIELD_IS_INTERLACED(buf->buf.field);
-+}
-+
-+static int v4l2_buf_is_top_first(const V4L2Buffer * const buf)
-+{
-+ return buf->buf.field == V4L2_FIELD_INTERLACED_TB;
-+}
-+
- static uint8_t * v4l2_get_drm_frame(V4L2Buffer *avbuf)
- {
- AVDRMFrameDescriptor *drm_desc = &avbuf->drm_frame;
-@@ -576,6 +586,8 @@ int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *avbuf, int no_resc
- frame->color_trc = v4l2_get_color_trc(avbuf);
- frame->pts = v4l2_get_pts(avbuf, no_rescale_pts);
- frame->pkt_dts = AV_NOPTS_VALUE;
-+ frame->interlaced_frame = v4l2_buf_is_interlaced(avbuf);
-+ frame->top_field_first = v4l2_buf_is_top_first(avbuf);
-
- /* these values are updated also during re-init in v4l2_process_driver_event */
- frame->height = ctx->height;
-
-From 05906e2086b5087d615485ec9a09b1493dbb32e1 Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Fri, 13 Aug 2021 16:11:53 +0100
-Subject: [PATCH 024/151] Fix V4L2 stateful to avoid crash if flush before
- start
-
----
- libavcodec/v4l2_context.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
-index a17ae027a6..eb901e8fab 100644
---- a/libavcodec/v4l2_context.c
-+++ b/libavcodec/v4l2_context.c
-@@ -713,6 +713,10 @@ static int v4l2_get_coded_format(V4L2Context* ctx, uint32_t *p)
- static void flush_all_buffers_status(V4L2Context* const ctx)
- {
- int i;
-+
-+ if (!ctx->bufrefs)
-+ return;
-+
- for (i = 0; i < ctx->num_buffers; ++i) {
- struct V4L2Buffer * const buf = (struct V4L2Buffer *)ctx->bufrefs[i]->data;
- if (buf->status == V4L2BUF_IN_DRIVER)
-
-From 7157b6032e759078a7d751e5dd5762970f3d1e8c Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Thu, 9 Sep 2021 17:44:13 +0100
-Subject: [PATCH 025/151] Copy properties from frame to v4l2 buffer
-
-Now copies all the properties in ff_v4l2_buffer_avframe_to_buf that
-ff_v4l2_buffer_buf_to_avframe copies
----
- libavcodec/v4l2_buffers.c | 126 ++++++++++++++++++++++++++++++++++++++
- 1 file changed, 126 insertions(+)
-
-diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
-index 97b8eb1db3..126d2a17f4 100644
---- a/libavcodec/v4l2_buffers.c
-+++ b/libavcodec/v4l2_buffers.c
-@@ -128,6 +128,105 @@ static enum AVColorPrimaries v4l2_get_color_primaries(V4L2Buffer *buf)
- return AVCOL_PRI_UNSPECIFIED;
- }
-
-+static void v4l2_set_color(V4L2Buffer *buf,
-+ const enum AVColorPrimaries avcp,
-+ const enum AVColorSpace avcs,
-+ const enum AVColorTransferCharacteristic avxc)
-+{
-+ enum v4l2_ycbcr_encoding ycbcr = V4L2_YCBCR_ENC_DEFAULT;
-+ enum v4l2_colorspace cs = V4L2_COLORSPACE_DEFAULT;
-+ enum v4l2_xfer_func xfer = V4L2_XFER_FUNC_DEFAULT;
-+
-+ switch (avcp) {
-+ case AVCOL_PRI_BT709:
-+ cs = V4L2_COLORSPACE_REC709;
-+ ycbcr = V4L2_YCBCR_ENC_709;
-+ break;
-+ case AVCOL_PRI_BT470M:
-+ cs = V4L2_COLORSPACE_470_SYSTEM_M;
-+ ycbcr = V4L2_YCBCR_ENC_601;
-+ break;
-+ case AVCOL_PRI_BT470BG:
-+ cs = V4L2_COLORSPACE_470_SYSTEM_BG;
-+ break;
-+ case AVCOL_PRI_SMPTE170M:
-+ cs = V4L2_COLORSPACE_SMPTE170M;
-+ break;
-+ case AVCOL_PRI_SMPTE240M:
-+ cs = V4L2_COLORSPACE_SMPTE240M;
-+ break;
-+ case AVCOL_PRI_BT2020:
-+ cs = V4L2_COLORSPACE_BT2020;
-+ break;
-+ case AVCOL_PRI_SMPTE428:
-+ case AVCOL_PRI_SMPTE431:
-+ case AVCOL_PRI_SMPTE432:
-+ case AVCOL_PRI_EBU3213:
-+ case AVCOL_PRI_RESERVED:
-+ case AVCOL_PRI_FILM:
-+ case AVCOL_PRI_UNSPECIFIED:
-+ default:
-+ break;
-+ }
-+
-+ switch (avcs) {
-+ case AVCOL_SPC_RGB:
-+ cs = V4L2_COLORSPACE_SRGB;
-+ break;
-+ case AVCOL_SPC_BT709:
-+ cs = V4L2_COLORSPACE_REC709;
-+ break;
-+ case AVCOL_SPC_FCC:
-+ cs = V4L2_COLORSPACE_470_SYSTEM_M;
-+ break;
-+ case AVCOL_SPC_BT470BG:
-+ cs = V4L2_COLORSPACE_470_SYSTEM_BG;
-+ break;
-+ case AVCOL_SPC_SMPTE170M:
-+ cs = V4L2_COLORSPACE_SMPTE170M;
-+ break;
-+ case AVCOL_SPC_SMPTE240M:
-+ cs = V4L2_COLORSPACE_SMPTE240M;
-+ break;
-+ case AVCOL_SPC_BT2020_CL:
-+ cs = V4L2_COLORSPACE_BT2020;
-+ ycbcr = V4L2_YCBCR_ENC_BT2020_CONST_LUM;
-+ break;
-+ case AVCOL_SPC_BT2020_NCL:
-+ cs = V4L2_COLORSPACE_BT2020;
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ switch (xfer) {
-+ case AVCOL_TRC_BT709:
-+ xfer = V4L2_XFER_FUNC_709;
-+ break;
-+ case AVCOL_TRC_IEC61966_2_1:
-+ xfer = V4L2_XFER_FUNC_SRGB;
-+ break;
-+ case AVCOL_TRC_SMPTE240M:
-+ xfer = V4L2_XFER_FUNC_SMPTE240M;
-+ break;
-+ case AVCOL_TRC_SMPTE2084:
-+ xfer = V4L2_XFER_FUNC_SMPTE2084;
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ if (V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type)) {
-+ buf->context->format.fmt.pix_mp.colorspace = cs;
-+ buf->context->format.fmt.pix_mp.ycbcr_enc = ycbcr;
-+ buf->context->format.fmt.pix_mp.xfer_func = xfer;
-+ } else {
-+ buf->context->format.fmt.pix.colorspace = cs;
-+ buf->context->format.fmt.pix.ycbcr_enc = ycbcr;
-+ buf->context->format.fmt.pix.xfer_func = xfer;
-+ }
-+}
-+
- static enum AVColorRange v4l2_get_color_range(V4L2Buffer *buf)
- {
- enum v4l2_quantization qt;
-@@ -146,6 +245,20 @@ static enum AVColorRange v4l2_get_color_range(V4L2Buffer *buf)
- return AVCOL_RANGE_UNSPECIFIED;
- }
-
-+static void v4l2_set_color_range(V4L2Buffer *buf, const enum AVColorRange avcr)
-+{
-+ const enum v4l2_quantization q =
-+ avcr == AVCOL_RANGE_MPEG ? V4L2_QUANTIZATION_LIM_RANGE :
-+ avcr == AVCOL_RANGE_JPEG ? V4L2_QUANTIZATION_FULL_RANGE :
-+ V4L2_QUANTIZATION_DEFAULT;
-+
-+ if (V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type)) {
-+ buf->context->format.fmt.pix_mp.quantization = q;
-+ } else {
-+ buf->context->format.fmt.pix.quantization = q;
-+ }
-+}
-+
- static enum AVColorSpace v4l2_get_color_space(V4L2Buffer *buf)
- {
- enum v4l2_ycbcr_encoding ycbcr;
-@@ -232,6 +345,12 @@ static int v4l2_buf_is_top_first(const V4L2Buffer * const buf)
- return buf->buf.field == V4L2_FIELD_INTERLACED_TB;
- }
-
-+static void v4l2_set_interlace(V4L2Buffer * const buf, const int is_interlaced, const int is_tff)
-+{
-+ buf->buf.field = !is_interlaced ? V4L2_FIELD_NONE :
-+ is_tff ? V4L2_FIELD_INTERLACED_TB : V4L2_FIELD_INTERLACED_BT;
-+}
-+
- static uint8_t * v4l2_get_drm_frame(V4L2Buffer *avbuf)
- {
- AVDRMFrameDescriptor *drm_desc = &avbuf->drm_frame;
-@@ -561,7 +680,14 @@ static int v4l2_buffer_swframe_to_buf(const AVFrame *frame, V4L2Buffer *out)
-
- int ff_v4l2_buffer_avframe_to_buf(const AVFrame *frame, V4L2Buffer *out)
- {
-+ out->buf.flags = frame->key_frame ? (out->buf.flags & ~V4L2_BUF_FLAG_KEYFRAME) : (out->buf.flags | V4L2_BUF_FLAG_KEYFRAME);
-+ // Beware that colour info is held in format rather than the actual
-+ // v4l2 buffer struct so this may not be as useful as you might hope
-+ v4l2_set_color(out, frame->color_primaries, frame->colorspace, frame->color_trc);
-+ v4l2_set_color_range(out, frame->color_range);
-+ // PTS & interlace are buffer vars
- v4l2_set_pts(out, frame->pts, 0);
-+ v4l2_set_interlace(out, frame->interlaced_frame, frame->top_field_first);
-
- return v4l2_buffer_swframe_to_buf(frame, out);
- }
-
-From 15415ab226f966fd12e70d79fde3cb80f3d09144 Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Wed, 17 Nov 2021 16:49:01 +0000
-Subject: [PATCH 026/151] ffmpeg: Do not inc DTS on no decode output
-
-V4L2 H264 decode has long latency and sometimes spits out a long stream
-of output without input. In this case incrementing DTS is wrong. There
-may be cases where the condition as written is correct so only "fix" in
-the cases which cause problems
----
- fftools/ffmpeg.c | 7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
-diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
-index 5dc2cd73c1..ba0c1898cf 100644
---- a/fftools/ffmpeg.c
-+++ b/fftools/ffmpeg.c
-@@ -2609,7 +2609,12 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo
- case AVMEDIA_TYPE_VIDEO:
- ret = decode_video (ist, repeating ? NULL : avpkt, &got_output, &duration_pts, !pkt,
- &decode_failed);
-- if (!repeating || !pkt || got_output) {
-+ // Pi: Do not inc dts if no_cvt_hw set
-+ // V4L2 H264 decode has long latency and sometimes spits out a long
-+ // stream of output without input. In this case incrementing DTS is wrong.
-+ // There may be cases where the condition as written is correct so only
-+ // "fix" in the cases which cause problems
-+ if (!repeating || !pkt || (got_output && !no_cvt_hw)) {
- if (pkt && pkt->duration) {
- duration_dts = av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q);
- } else if(ist->dec_ctx->framerate.num != 0 && ist->dec_ctx->framerate.den != 0) {
-
-From 7bf6c062ed8a1e635aa5722c0072724f236daf00 Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Wed, 17 Nov 2021 17:32:59 +0000
-Subject: [PATCH 027/151] v4l2_m2m_dec: Adjust timebase if H264
-
-Adjust AVCodecContext time_base if H264 in the same way that the
-software decoder does.
----
- libavcodec/v4l2_m2m_dec.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
-diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
-index 1851acbc93..aa1e5c1597 100644
---- a/libavcodec/v4l2_m2m_dec.c
-+++ b/libavcodec/v4l2_m2m_dec.c
-@@ -481,6 +481,16 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx)
-
- av_log(avctx, AV_LOG_TRACE, "<<< %s\n", __func__);
-
-+ if (avctx->codec_id == AV_CODEC_ID_H264) {
-+ if (avctx->ticks_per_frame == 1) {
-+ if(avctx->time_base.den < INT_MAX/2) {
-+ avctx->time_base.den *= 2;
-+ } else
-+ avctx->time_base.num /= 2;
-+ }
-+ avctx->ticks_per_frame = 2;
-+ }
-+
- av_log(avctx, AV_LOG_INFO, "level=%d\n", avctx->level);
- ret = ff_v4l2_m2m_create_context(priv, &s);
- if (ret < 0)
-
-From 3cd23a761397ae75ed032c1687da5d6b76ddaaaa Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Wed, 17 Nov 2021 17:38:27 +0000
-Subject: [PATCH 028/151] v4l2_m2m_dec: Produce best guess PTSs if none
- supplied
-
-Filter scheduling gets confused by missing PTSs and makes poor guesses
-more often than not. Try to generate plausible timestamps where we are
-missing them.
----
- libavcodec/v4l2_m2m.h | 12 ++++++++
- libavcodec/v4l2_m2m_dec.c | 64 +++++++++++++++++++++++++++++++++++++--
- 2 files changed, 74 insertions(+), 2 deletions(-)
-
-diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
-index 8f054f2f50..82feb0afdb 100644
---- a/libavcodec/v4l2_m2m.h
-+++ b/libavcodec/v4l2_m2m.h
-@@ -52,6 +52,16 @@ typedef struct V4L2m2mTrackEl {
- int64_t track_pts;
- } V4L2m2mTrackEl;
-
-+typedef struct pts_stats_s
-+{
-+ void * logctx;
-+ const char * name; // For debug
-+ unsigned int last_count;
-+ unsigned int last_interval;
-+ int64_t last_pts;
-+ int64_t guess;
-+} pts_stats_t;
-+
- typedef struct V4L2m2mContext {
- char devname[PATH_MAX];
- int fd;
-@@ -91,6 +101,8 @@ typedef struct V4L2m2mContext {
- unsigned int track_no;
- V4L2m2mTrackEl track_els[FF_V4L2_M2M_TRACK_SIZE];
-
-+ pts_stats_t pts_stat;
-+
- /* req pkt */
- int req_pkt;
-
-diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
-index aa1e5c1597..a5a2afbd27 100644
---- a/libavcodec/v4l2_m2m_dec.c
-+++ b/libavcodec/v4l2_m2m_dec.c
-@@ -42,6 +42,62 @@
- #include "v4l2_m2m.h"
- #include "v4l2_fmt.h"
-
-+// Pick 64 for max last count - that is >1sec at 60fps
-+#define STATS_LAST_COUNT_MAX 64
-+#define STATS_INTERVAL_MAX (1 << 30)
-+
-+static int64_t pts_stats_guess(const pts_stats_t * const stats)
-+{
-+ if (stats->last_pts == AV_NOPTS_VALUE ||
-+ stats->last_interval == 0 ||
-+ stats->last_count >= STATS_LAST_COUNT_MAX)
-+ return AV_NOPTS_VALUE;
-+ return stats->last_pts + (int64_t)(stats->last_count - 1) * (int64_t)stats->last_interval;
-+}
-+
-+static void pts_stats_add(pts_stats_t * const stats, int64_t pts)
-+{
-+ if (pts == AV_NOPTS_VALUE || pts == stats->last_pts) {
-+ if (stats->last_count < STATS_LAST_COUNT_MAX)
-+ ++stats->last_count;
-+ return;
-+ }
-+
-+ if (stats->last_pts != AV_NOPTS_VALUE) {
-+ const int64_t interval = pts - stats->last_pts;
-+
-+ if (interval < 0 || interval >= STATS_INTERVAL_MAX ||
-+ stats->last_count >= STATS_LAST_COUNT_MAX) {
-+ if (stats->last_interval != 0)
-+ av_log(stats->logctx, AV_LOG_DEBUG, "%s: %s: Bad interval: %" PRId64 "/%d\n",
-+ __func__, stats->name, interval, stats->last_count);
-+ stats->last_interval = 0;
-+ }
-+ else {
-+ const int64_t frame_time = interval / (int64_t)stats->last_count;
-+
-+ if (frame_time != stats->last_interval)
-+ av_log(stats->logctx, AV_LOG_DEBUG, "%s: %s: New interval: %u->%" PRId64 "/%d=%" PRId64 "\n",
-+ __func__, stats->name, stats->last_interval, interval, stats->last_count, frame_time);
-+ stats->last_interval = frame_time;
-+ }
-+ }
-+
-+ stats->last_pts = pts;
-+ stats->last_count = 1;
-+}
-+
-+static void pts_stats_init(pts_stats_t * const stats, void * logctx, const char * name)
-+{
-+ *stats = (pts_stats_t){
-+ .logctx = logctx,
-+ .name = name,
-+ .last_count = 1,
-+ .last_interval = 0,
-+ .last_pts = AV_NOPTS_VALUE
-+ };
-+}
-+
- static int check_output_streamon(AVCodecContext *const avctx, V4L2m2mContext *const s)
- {
- int ret;
-@@ -244,9 +300,11 @@ xlat_pts_out(AVCodecContext *const avctx, V4L2m2mContext *const s, AVFrame *cons
- return -1;
- }
-
-- frame->best_effort_timestamp = frame->pts;
-+ pts_stats_add(&s->pts_stat, frame->pts);
-+
-+ frame->best_effort_timestamp = pts_stats_guess(&s->pts_stat);
- frame->pkt_dts = frame->pts; // We can't emulate what s/w does in a useful manner?
-- av_log(avctx, AV_LOG_TRACE, "Out PTS=%" PRId64 ", DTS=%" PRId64 "\n", frame->pts, frame->pkt_dts);
-+ av_log(avctx, AV_LOG_TRACE, "Out PTS=%" PRId64 "/%"PRId64", DTS=%" PRId64 "\n", frame->pts, frame->best_effort_timestamp, frame->pkt_dts);
- return 0;
- }
-
-@@ -496,6 +554,8 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx)
- if (ret < 0)
- return ret;
-
-+ pts_stats_init(&s->pts_stat, avctx, "decoder");
-+
- capture = &s->capture;
- output = &s->output;
-
-
-From ee8be1e900f98212b6c4940980cc7a80becfc07c Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Wed, 17 Nov 2021 17:59:27 +0000
-Subject: [PATCH 029/151] v4l2_m2m_dec: Try harder to get an initial frame
-
-If the input Q is full then wait on a short timeout for a capture frame
-rather than stuffing yet still another frame into the input if we could
-do that first. This attempts to restrict the sometimes daft initial
-buffering that ends up confusing the rest of the system.
----
- libavcodec/v4l2_context.c | 2 +-
- libavcodec/v4l2_m2m_dec.c | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
-index eb901e8fab..ee5dc7b8d4 100644
---- a/libavcodec/v4l2_context.c
-+++ b/libavcodec/v4l2_context.c
-@@ -381,7 +381,7 @@ static V4L2Buffer* v4l2_dequeue_v4l2buf(V4L2Context *ctx, int timeout)
- start:
- if (is_capture) {
- /* no need to listen to requests for more input while draining */
-- if (ctx_to_m2mctx(ctx)->draining)
-+ if (ctx_to_m2mctx(ctx)->draining || timeout > 0)
- pfd.events = POLLIN | POLLRDNORM | POLLPRI;
- } else {
- pfd.events = POLLOUT | POLLWRNORM;
-diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
-index a5a2afbd27..b49f470c0a 100644
---- a/libavcodec/v4l2_m2m_dec.c
-+++ b/libavcodec/v4l2_m2m_dec.c
-@@ -442,7 +442,7 @@ static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame)
- // when discarding
- // This returns AVERROR(EAGAIN) if there isn't a frame ready yet
- // but there is room in the input Q
-- dst_rv = ff_v4l2_context_dequeue_frame(&s->capture, frame, -1, 1);
-+ dst_rv = ff_v4l2_context_dequeue_frame(&s->capture, frame, src_rv == NQ_Q_FULL ? 100 : -1, 1);
-
- if (dst_rv == AVERROR_EOF && (s->draining || s->capture.done))
- av_log(avctx, AV_LOG_DEBUG, "Dequeue EOF: draining=%d, cap.done=%d\n",
-
-From 72da14331c2160a12b69d666d493e0e74c5e8914 Mon Sep 17 00:00:00 2001
-From: John Cox
-Date: Wed, 17 Nov 2021 18:04:56 +0000
-Subject: [PATCH 030/151] Add a V4L2 M2M deinterlace filter
-
-Add a V4L2 deinterlace filter that will accept DRMPRIME frames.
-
-Multiple people have contributed to this:
-Jernej Skrabec