Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Desktop: Add dav1d library for AV1 software decoding #99

Merged
merged 4 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ name: Java CI with Gradle
on:
pull_request:
branches: [ master ]
workflow_dispatch:

jobs:
natives-macos:
Expand All @@ -23,10 +24,10 @@ jobs:
uses: gradle/gradle-build-action@v2

- name: Install additional build dependencies
run: brew install nasm
run: brew install nasm meson

- name: Build with Gradle
run: ./gradlew :gdx-video-desktop:buildFFmpegMacosAll :gdx-video-desktop:jnigenBuildMacosAll
run: ./gradlew :gdx-video-desktop:FFmpeg:buildFFmpegMacosAll :gdx-video-desktop:jnigenBuildMacosAll

- name: Upload artifacts
uses: actions/upload-artifact@v3
Expand Down Expand Up @@ -56,12 +57,12 @@ jobs:
run: |
sudo apt update
sudo apt install -y --force-yes gcc g++
sudo apt install -y --force-yes nasm
sudo apt install -y --force-yes nasm meson
sudo apt install -y --force-yes gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libc6-dev-arm64-cross
sudo apt install -y --force-yes gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf libc6-dev-armhf-cross

- name: Build natives with Gradle
run: ./gradlew :gdx-video-desktop:buildFFmpegLinuxAll :gdx-video-desktop:jnigenBuildLinuxAll
run: ./gradlew :gdx-video-desktop:FFmpeg:buildFFmpegLinuxAll :gdx-video-desktop:jnigenBuildLinuxAll

- name: Upload artifacts
uses: actions/upload-artifact@v3
Expand Down Expand Up @@ -90,11 +91,11 @@ jobs:
- name: Install build dependencies and cross-compilation toolchains
run: |
sudo apt update
sudo apt install -y --force-yes nasm
sudo apt install -y --force-yes nasm meson
sudo apt install -y --force-yes mingw-w64 lib32z1

- name: Build natives with Gradle
run: ./gradlew :gdx-video-desktop:buildFFmpegWindowsAll :gdx-video-desktop:jnigenBuildWindowsAll
run: ./gradlew :gdx-video-desktop:FFmpeg:buildFFmpegWindowsAll :gdx-video-desktop:jnigenBuildWindowsAll

- name: Upload artifacts
uses: actions/upload-artifact@v3
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/publish_snapshot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ jobs:
uses: gradle/gradle-build-action@v2

- name: Install additional build dependencies
run: brew install nasm
run: brew install nasm meson

- name: Build with Gradle
run: ./gradlew :gdx-video-desktop:buildFFmpegMacosAll :gdx-video-desktop:jnigenBuildMacosAll
run: ./gradlew :gdx-video-desktop:FFmpeg:buildFFmpegMacosAll :gdx-video-desktop:jnigenBuildMacosAll

- name: Upload artifacts
uses: actions/upload-artifact@v3
Expand Down Expand Up @@ -63,12 +63,12 @@ jobs:
run: |
sudo apt update
sudo apt install -y --force-yes gcc g++
sudo apt install -y --force-yes nasm
sudo apt install -y --force-yes nasm meson
sudo apt install -y --force-yes gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libc6-dev-arm64-cross
sudo apt install -y --force-yes gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf libc6-dev-armhf-cross

- name: Build natives with Gradle
run: ./gradlew :gdx-video-desktop:buildFFmpegLinuxAll :gdx-video-desktop:jnigenBuildLinuxAll
run: ./gradlew :gdx-video-desktop:FFmpeg:buildFFmpegLinuxAll :gdx-video-desktop:jnigenBuildLinuxAll

- name: Upload artifacts
uses: actions/upload-artifact@v3
Expand Down Expand Up @@ -97,11 +97,11 @@ jobs:
- name: Install build dependencies and cross-compilation toolchains
run: |
sudo apt update
sudo apt install -y --force-yes nasm
sudo apt install -y --force-yes nasm meson
sudo apt install -y --force-yes mingw-w64 lib32z1

- name: Build natives with Gradle
run: ./gradlew :gdx-video-desktop:buildFFmpegWindowsAll :gdx-video-desktop:jnigenBuildWindowsAll
run: ./gradlew :gdx-video-desktop:FFmpeg:buildFFmpegWindowsAll :gdx-video-desktop:jnigenBuildWindowsAll

- name: Upload artifacts
uses: actions/upload-artifact@v3
Expand Down
5 changes: 4 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
[submodule "gdx-video-desktop/FFmpeg"]
path = gdx-video-desktop/FFmpeg
path = gdx-video-desktop/FFmpeg/src/FFmpeg
url = https://github.com/FFmpeg/FFmpeg.git
branch = release/4.3
[submodule "gdx-video-desktop/dependencies/dav1d"]
path = gdx-video-desktop/FFmpeg/src/dav1d
url = https://code.videolan.org/videolan/dav1d.git
27 changes: 16 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,26 +112,31 @@ your game on real devices.

### File format and codec

| Format | Desktop | Android | iOS | Web |
|------------------------|----------|----------|---------|-----|
| MP4 (H.264/AVC + AAC) | ❌ * | ✅ * | ✅ | ⚠️ |
| MP4 (H.265/HEVC + AAC) | ❌ * | ⚠️ > 5.0 | ⚠️ > 11 | ⚠️ |
| WebM (VP8 + Vorbis) | ✅ | ✅ | ❌ | ✅ |
| WebM (VP9 + Opus) | ✅ | ⚠️ > 5.0 | ❌ | ❔ |
| MKV (AV1 + Opus) | ✅ | ⚠️ > 10 | ❌ | ⚠️ |
| Format | Desktop | Android | iOS | Web |
|------------------------|----------|----------|--------|-----|
| MP4 (H.264/AVC + AAC) | ❌ * | ✅ | ✅ | ⚠️ |
| MP4 (H.265/HEVC + AAC) | ❌ * | ⚠️ > 5.0 | > 11 | ⚠️ |
| WebM (VP8 + Vorbis) | ✅ | ✅ | ❌ | ✅ |
| WebM (VP9 + Opus) | ✅ | ⚠️ > 5.0 | ❌ | ❔ |
| MKV (AV1 + Opus) | ✅ | ⚠️ > 10 | ❌ * | ⚠️ |

#### Additional notes

**Desktop:** Additional formats and codecs can be enabled when compiling
gdx-video yourself. See the file [gdx-video-desktop/build.gradle](gdx-video-desktop/build.gradle).
gdx-video yourself. See the file [gdx-video-desktop/FFmpeg/build.gradle](gdx-video-desktop/FFmpeg/build.gradle).

**iOS**: H.265 support notes from apple: <https://support.apple.com/de-de/HT207022>
**iOS**: H.265 is supported since iOS 11. AV1 requires a current high-end
device with a hardware decoder.

**Android**: See the following webpage for officially supported media formats:
<https://developer.android.com/guide/topics/media/platform/supported-formats>.
Note that this support table is not always accurate, especially for devices
and emulator images without Google Play Services. When in doubt, use VP8, VP9
and Vorbis.
and emulator images without Google Play Services.

In practice, H.264 is a good choice for physical Android tablets / smartphones
as most devices (including old and cheap ones) have hardware decoding support.
Remember to dispose a VideoPlayer before loading a new one, as some devices
fail to load the next video otherwise.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this. The same holds true for web - I use H.264 there because older/low-spec hardware lacks hardware-based VP9 decoding and it has only recently been supported by Safari. Not that gdx-video works well on iOS (15) - it ends up opening the raw video full screen - but at least it's better than nothing.

It's a little annoying to ship VP9 for desktop and H.264 for GWT, since the GWT backend doesn't support multiple assets directories, but you can tell Gradle to exclude the web version from the desktop build.


### Resolution and framerate

Expand Down
1 change: 0 additions & 1 deletion gdx-video-desktop/FFmpeg
Submodule FFmpeg deleted from 25cd95
167 changes: 167 additions & 0 deletions gdx-video-desktop/FFmpeg/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
tasks.register('cleanFFmpeg')
tasks.register('cleanAV1')
clean.configure {
dependsOn 'cleanFFmpeg'
dependsOn 'cleanAV1'
}

String checkCrossPrefix(String crossToolchain) {
def tc = crossToolchain
if (tc == null || System.getProperty("os.name").startsWith("Win")) return ""
def result = project.exec {
ignoreExitValue = true
commandLine "bash", "-l", "-c",
"(command -v $tc-g++ && command -v $tc-ar && command -v $tc-ld)>/dev/null"
}
if (result.getExitValue() == 0) {
return "$tc-"
}
return ""
}

String checkCrossFile(String buildName, String crossToolchain) {
String prefix = checkCrossPrefix(crossToolchain)
if (prefix.isEmpty()) {
return ""
}
def options = [
"Windows32" : "i686-w64-mingw32",
"Windows64" : "x86_64-w64-mingw32",
"LinuxARM64": "aarch64-linux"
]
def name = options[buildName]
if(name == null) return ""
return "src/dav1d/package/crossfiles/${name}.meson"
}


void registerBuild(String buildName, String crossToolchain, String... extraArgs) {
String outDir = file("build/${buildName.toLowerCase()}").absolutePath
String av1Dir = "$outDir/src/dav1d"
String ffDir = "$outDir/src/FFmpeg"

def crossPrefix = checkCrossPrefix(crossToolchain)
def crossFile = checkCrossFile(buildName, crossToolchain)

tasks.register("cleanAV1$buildName", Delete) {
delete av1Dir
delete "$outDir/lib/libdav1d.a"
}
cleanAV1.configure {
dependsOn "cleanAV1$buildName"
}
tasks.register("buildAV1$buildName") {
doFirst {
mkdir av1Dir
String[] crossArgs = []
String crossPath = ""
if (!crossFile.isEmpty()) {
crossPath = file(crossFile).absolutePath
} else if(buildName == "Macos64") {
crossPath = file("src/x86_64-macos.meson").absolutePath
} else if(buildName == "MacosARM64") {
crossPath = file("src/arm64-macos.meson").absolutePath
} else if(buildName == "Linux64" && System.getProperty("os.name") != "Linux") {
crossPath = file("src/x86_64-linux.meson").absolutePath
} else if(buildName == "LinuxARM32") {
crossPath = file("src/arm32-linux.meson").absolutePath
}
if (!crossPath.isEmpty()) {
crossArgs = ["--cross-file=$crossPath"]
}
project.exec {
workingDir av1Dir
executable 'meson'
args 'setup', '-Denable_tools=false', '-Denable_tests=false'
args crossArgs
args '../../../../src/dav1d', '--default-library=static'
args '--prefix', "$outDir"
args "--libdir=$outDir/lib"
}
project.exec {
workingDir av1Dir
commandLine 'ninja'
}
project.exec {
workingDir av1Dir
commandLine 'ninja', 'install'
}
}
outputs.upToDateWhen { file("$outDir/lib/libdav1d.a").exists() }
}

tasks.register("cleanFFmpeg$buildName", Delete) {
delete ffDir
delete "$outDir/lib/libavformat.a"
}
cleanFFmpeg.configure {
dependsOn "cleanFFmpeg$buildName"
}
tasks.register("buildFFmpeg$buildName") {
dependsOn "buildAV1$buildName"
doFirst {
mkdir ffDir
String[] crossArgs = []
if (!crossPrefix.isEmpty()) {
crossArgs = ["--enable-cross-compile", "--cross-prefix=$crossPrefix"]
}
project.exec {
workingDir ffDir
environment["PKG_CONFIG_PATH"] = "$outDir/lib/pkgconfig"
executable '../../../../src/FFmpeg/configure'
args '--pkg-config=pkg-config', '--pkg-config-flags=--static'
args '--disable-autodetect'
args '--enable-pic', '--disable-symver', '--disable-doc', '--disable-shared', '--enable-static'
args crossArgs
args '--disable-everything'
args '--enable-protocol=file', '--enable-filter=aresample', '--enable-filter=deshake'
args '--enable-demuxer=ogg', '--enable-demuxer=matroska', '--enable-demuxer=mov'
args '--enable-decoder=vorbis', '--enable-decoder=opus', '--enable-decoder=aac'
args '--enable-decoder=vp8', '--enable-decoder=vp9', '--enable-decoder=theora', '--enable-decoder=av1'
args '--enable-libdav1d', '--enable-decoder=libdav1d'
args "--extra-cflags=-I$outDir/include"
args "--extra-ldflags=-L$outDir/lib"
args "--prefix=$outDir"
// Uncomment the following line for MP4 video support:
//args '--enable-decoder=h264', '--enable-decoder=hevc'
args extraArgs
}
project.exec {
workingDir ffDir
commandLine 'make', '-j16'
}
project.exec {
workingDir ffDir
commandLine 'make', 'install'
}
}
outputs.upToDateWhen { file("$outDir/lib/libavformat.a").exists() }
}
}

registerBuild 'Windows32', 'i686-w64-mingw32', '--arch=x86', '--target-os=mingw32'
registerBuild 'Windows64', 'x86_64-w64-mingw32', '--arch=x86_64', '--target-os=mingw32'

registerBuild 'Linux64', 'x86_64-linux-gnu', '--arch=x86_64', '--target-os=linux', '--disable-cuda', '--disable-cuvid'

registerBuild 'LinuxARM32', 'arm-linux-gnueabihf', '--arch=arm', '--target-os=linux'
registerBuild 'LinuxARM64', 'aarch64-linux-gnu', '--arch=aarch64', '--target-os=linux'

registerBuild 'Macos64', null, '--enable-cross-compile',// '--enable-hwaccel=h264_videotoolbox', '--enable-hwaccel=hevc_videotoolbox',
'--arch=x86_64', '--target-os=darwin', '--cc=clang', '--cxx=clang++', '--dep-cc=clang',
'--extra-cflags=-mmacosx-version-min=10.11 -arch x86_64', '--extra-cxxflags=-mmacosx-version-min=10.11 -arch x86_64', '--extra-ldflags=-mmacosx-version-min=10.11 -arch x86_64'
registerBuild 'MacosARM64', null, '--enable-cross-compile',// '--enable-hwaccel=h264_videotoolbox', '--enable-hwaccel=hevc_videotoolbox',
'--arch=arm64', '--target-os=darwin', '--cc=clang', '--cxx=clang++', '--dep-cc=clang',
'--extra-cflags=-mmacosx-version-min=10.11 -arch arm64', '--extra-cxxflags=-mmacosx-version-min=10.11 -arch arm64', '--extra-ldflags=-mmacosx-version-min=10.11 -arch arm64'

tasks.register('buildFFmpegWindowsAll') {
dependsOn buildFFmpegWindows32, buildFFmpegWindows64
}

tasks.register('buildFFmpegLinuxAll') {
dependsOn buildFFmpegLinux64, buildFFmpegLinuxARM32, buildFFmpegLinuxARM64
}

tasks.register('buildFFmpegMacosAll') {
dependsOn buildFFmpegMacos64, buildFFmpegMacosARM64
}
1 change: 1 addition & 0 deletions gdx-video-desktop/FFmpeg/src/FFmpeg
Submodule FFmpeg added at cde3c5
11 changes: 11 additions & 0 deletions gdx-video-desktop/FFmpeg/src/arm32-linux.meson
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[binaries]
c = 'arm-linux-gnueabihf-gcc'
cpp = 'arm-linux-gnueabihf-gcc'
ar = 'arm-linux-gnueabihf-ar'
strip = 'arm-linux-gnueabihf-strip'

[host_machine]
system = 'linux'
cpu_family = 'arm'
cpu = 'arm'
endian = 'little'
23 changes: 23 additions & 0 deletions gdx-video-desktop/FFmpeg/src/arm64-macos.meson
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[binaries]
c = ['clang', '-arch', 'arm64']
cpp = ['clang++', '-arch', 'arm64']
objc = ['clang', '-arch', 'arm64']
objcpp = ['clang++', '-arch', 'arm64']
ar = 'ar'
strip = 'strip'

[built-in options]
c_args = ['-mmacos-version-min=10.11']
cpp_args = ['-mmacos-version-min=10.11']
c_link_args = ['-mmacos-version-min=10.11']
cpp_link_args = ['-mmacos-version-min=10.11']
objc_args = ['-mmacos-version-min=10.11']
objcpp_args = ['-mmacos-version-min=10.11']

[host_machine]
system = 'darwin'
subsystem = 'macos'
kernel = 'xnu'
cpu_family = 'aarch64'
cpu = 'aarch64'
endian = 'little'
1 change: 1 addition & 0 deletions gdx-video-desktop/FFmpeg/src/dav1d
Submodule dav1d added at 2ba57a
11 changes: 11 additions & 0 deletions gdx-video-desktop/FFmpeg/src/x86_64-linux.meson
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[binaries]
c = 'x86_64-linux-gnu-gcc'
cpp = 'x86_64-linux-gnu-g++'
ar = 'x86_64-linux-gnu-ar'
strip = 'x86_64-linux-gnu-strip'

[host_machine]
system = 'linux'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
23 changes: 23 additions & 0 deletions gdx-video-desktop/FFmpeg/src/x86_64-macos.meson
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[binaries]
c = ['clang', '-arch', 'x86_64']
cpp = ['clang++', '-arch', 'x86_64']
objc = ['clang', '-arch', 'x86_64']
objcpp = ['clang++', '-arch', 'x86_64']
ar = 'ar'
strip = 'strip'

[built-in options]
c_args = ['-mmacos-version-min=10.11']
cpp_args = ['-mmacos-version-min=10.11']
c_link_args = ['-mmacos-version-min=10.11']
cpp_link_args = ['-mmacos-version-min=10.11']
objc_args = ['-mmacos-version-min=10.11']
objcpp_args = ['-mmacos-version-min=10.11']

[host_machine]
system = 'darwin'
subsystem = 'macos'
kernel = 'xnu'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
Loading