From 27f885c7fba8d41548b8fea93725d64fa924e892 Mon Sep 17 00:00:00 2001 From: Maximilian Wende Date: Thu, 26 Dec 2024 17:48:07 +0100 Subject: [PATCH 1/4] Desktop: Add libdav1d for AV1 software decoding --- .gitmodules | 5 +- gdx-video-desktop/build.gradle | 96 +++++++++++++++------ gdx-video-desktop/{ => dependencies}/FFmpeg | 0 gdx-video-desktop/dependencies/dav1d | 1 + 4 files changed, 77 insertions(+), 25 deletions(-) rename gdx-video-desktop/{ => dependencies}/FFmpeg (100%) create mode 160000 gdx-video-desktop/dependencies/dav1d diff --git a/.gitmodules b/.gitmodules index 11a4bb1..8f470d9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,7 @@ [submodule "gdx-video-desktop/FFmpeg"] - path = gdx-video-desktop/FFmpeg + path = gdx-video-desktop/dependencies/FFmpeg url = https://github.com/FFmpeg/FFmpeg.git branch = release/4.3 +[submodule "gdx-video-desktop/dependencies/dav1d"] + path = gdx-video-desktop/dependencies/dav1d + url = https://code.videolan.org/videolan/dav1d.git diff --git a/gdx-video-desktop/build.gradle b/gdx-video-desktop/build.gradle index 896762c..cddff60 100644 --- a/gdx-video-desktop/build.gradle +++ b/gdx-video-desktop/build.gradle @@ -33,8 +33,10 @@ dependencies { apply plugin: "com.badlogicgames.gdx.gdx-jnigen" tasks.register('cleanFFmpeg') +tasks.register('cleanAV1') clean.configure { dependsOn 'cleanFFmpeg' + dependsOn 'cleanAV1' } String checkCrossPrefix(String crossToolchain) { @@ -52,24 +54,62 @@ String checkCrossPrefix(String crossToolchain) { } void registerBuild(String buildName, String crossToolchain, String... extraArgs) { - String buildDir = "FFmpeg/build-${buildName.toLowerCase()}" + String av1Dir = "dependencies/build/${buildName.toLowerCase()}/dav1d" + String ffDir = file("dependencies/build/${buildName.toLowerCase()}/FFmpeg").absolutePath + + tasks.register("cleanAV1$buildName", Delete) { + delete av1Dir + } + cleanAV1.configure { + dependsOn "cleanAV1$buildName" + } + tasks.register("buildAV1$buildName") { + doFirst { + mkdir av1Dir + String[] crossArgs = [] + def crossPrefix = checkCrossPrefix(crossToolchain) + if(!crossPrefix.isEmpty()) { + crossArgs = ["--enable-cross-compile", "--cross-prefix=$crossPrefix"] + } + project.exec { + workingDir av1Dir + executable 'meson' + args 'setup', '-Denable_tools=false', '-Denable_tests=false' + args '../../../dav1d', '--default-library=static' + args '--prefix', "$ffDir/ffmpeg_build" + args "--libdir=$ffDir/ffmpeg_build/lib" + } + project.exec { + workingDir av1Dir + commandLine 'ninja' + } + project.exec { + workingDir av1Dir + commandLine 'ninja', 'install' + } + } + outputs.upToDateWhen { file("$ffDir/ffmpeg_build/lib/libdav1d.a").exists() } + } + tasks.register("cleanFFmpeg$buildName", Delete) { - delete buildDir + delete ffDir } cleanFFmpeg.configure { dependsOn "cleanFFmpeg$buildName" } tasks.register("buildFFmpeg$buildName") { + dependsOn "buildAV1$buildName" doFirst { - mkdir buildDir + mkdir ffDir String[] crossArgs = [] def crossPrefix = checkCrossPrefix(crossToolchain) if(!crossPrefix.isEmpty()) { crossArgs = ["--enable-cross-compile", "--cross-prefix=$crossPrefix"] } project.exec { - workingDir buildDir - executable '../configure' + workingDir ffDir + environment["PKG_CONFIG_PATH"] = "$ffDir/ffmpeg_build/lib/pkgconfig" + executable '../../../FFmpeg/configure' args '--enable-pic', '--disable-symver', '--disable-doc', '--disable-shared', '--enable-static' args crossArgs args '--disable-everything' @@ -77,16 +117,26 @@ void registerBuild(String buildName, String crossToolchain, String... extraArgs) args '--enable-demuxer=ogg', '--enable-demuxer=matroska' args '--enable-decoder=vorbis', '--enable-decoder=opus' args '--enable-decoder=vp8', '--enable-decoder=vp9', '--enable-decoder=theora', '--enable-decoder=av1' + args '--enable-libdav1d', '--enable-decoder=libdav1d' + args '--pkg-config-flags=--static' + args "--extra-cflags=-I$ffDir/ffmpeg_build/include" + args "--extra-ldflags=-L$ffDir/ffmpeg_build/lib" + args "--prefix=$ffDir/ffmpeg_build" // Uncomment the following line for MP4 video support: // args '--enable-demuxer=mov', '--enable-decoder=aac', '--enable-decoder=h264', '--enable-decoder=hevc' args extraArgs } project.exec { - workingDir buildDir + workingDir ffDir + environment['V'] = 1 commandLine 'make', '-j16' } + project.exec { + workingDir ffDir + commandLine 'make', 'install' + } } - outputs.upToDateWhen { file("$buildDir/libavformat/libavformat.a").exists() } + outputs.upToDateWhen { file("$ffDir/ffmpeg_build/lib/libavformat.a").exists() } } } @@ -106,58 +156,56 @@ registerBuild 'MacosARM64', null, '--enable-cross-compile', '--arch=arm64', '--t jnigen { sharedLibName = "gdx-video-desktop" all { - headerDirs = ["../FFmpeg"] + headerDirs = ["../dependencies/FFmpeg", "../dependencies/dav1d"] cFlags += " -fvisibility=hidden " cppFlags += " -fvisibility=hidden " //Using `-lavcodec -lavformat` order on linux drops filesize by half but mingw wont compile??? - libraries += " -lavformat -lavcodec -lavutil -lswscale -lswresample -lpthread " + libraries += " -lavformat -lavcodec -lavutil -lswscale -lswresample -lpthread -ldav1d" } def genLibs = { String buildName -> - String libraries = '' - String absPath = file("FFmpeg/build-$buildName").absolutePath - libraries += " -L$absPath/libavcodec" - libraries += " -L$absPath/libavformat" - libraries += " -L$absPath/libavutil" - libraries += " -L$absPath/libswscale" - libraries += " -L$absPath/libswresample" - return libraries + String ffPath = file("dependencies/build/$buildName/FFmpeg").absolutePath + return " -L$ffPath/ffmpeg_build/lib" + } + def genHeaders = { String buildName -> + String ffPath = file("dependencies/build/$buildName/FFmpeg").absolutePath + return " -I$ffPath/ffmpeg_build/include" } add(Windows, x32) { - headerDirs += "../FFmpeg/build-windows32/" + headerDirs += genHeaders("windows32") cppFlags += " -DWIN32 " libraries += genLibs("windows32") + " -lbcrypt -lws2_32" } add(Windows, x64) { - headerDirs += "../FFmpeg/build-windows64/" + headerDirs += genHeaders("windows64") cppFlags += " -DWIN32 " libraries += genLibs("windows64") + " -lbcrypt -lws2_32" } add(Linux, x64) { - headerDirs += "../FFmpeg/build-linux64/" + headerDirs += genHeaders("linux64") libraries += genLibs("linux64") compilerPrefix = checkCrossPrefix('x86_64-linux-gnu') linkerFlags += " -Wl,-Bsymbolic " } add(Linux, x32, ARM) { - headerDirs += "../FFmpeg/build-linuxarm32/" + headerDirs += genHeaders("linuxarm32") libraries += genLibs("linuxarm32") linkerFlags += " -Wl,-Bsymbolic " } add(Linux, x64, ARM) { - headerDirs += "../FFmpeg/build-linuxarm64/" + headerDirs += genHeaders("linuxarm64") libraries += genLibs("linuxarm64") linkerFlags += " -Wl,-Bsymbolic " } add(MacOsX, x64) { - headerDirs += "../FFmpeg/build-macos64/" + headerDirs += genHeaders("macos64") libraries += genLibs("macos64") + " -liconv -lbz2 -lz -framework CoreFoundation -framework CoreVideo" cFlags += " -mmacosx-version-min=10.11" cppFlags += " -mmacosx-version-min=10.11" linkerFlags += " -mmacosx-version-min=10.11" } add(MacOsX, x64, ARM) { - headerDirs += "../FFmpeg/build-macosarm64/" + headerDirs += genHeaders("macosarm64") libraries += genLibs("macosarm64") + " -liconv -lbz2 -lz -framework CoreFoundation -framework CoreVideo" cFlags += " -mmacosx-version-min=10.11" cppFlags += " -mmacosx-version-min=10.11" diff --git a/gdx-video-desktop/FFmpeg b/gdx-video-desktop/dependencies/FFmpeg similarity index 100% rename from gdx-video-desktop/FFmpeg rename to gdx-video-desktop/dependencies/FFmpeg diff --git a/gdx-video-desktop/dependencies/dav1d b/gdx-video-desktop/dependencies/dav1d new file mode 160000 index 0000000..2ba57aa --- /dev/null +++ b/gdx-video-desktop/dependencies/dav1d @@ -0,0 +1 @@ +Subproject commit 2ba57aa535896bcc8c450bbf7d0958791e38ec78 From fdd95cb2af40414ee3fbd35b6cdb2452ec50f0e1 Mon Sep 17 00:00:00 2001 From: Maximilian Wende Date: Fri, 27 Dec 2024 02:42:52 +0100 Subject: [PATCH 2/4] Update cross-compile configuration --- .github/workflows/gradle.yml | 7 ++++--- gdx-video-desktop/build.gradle | 29 ++++++++++++++++++++++------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 584cd39..55a172b 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -3,6 +3,7 @@ name: Java CI with Gradle on: pull_request: branches: [ master ] + workflow_dispatch: jobs: natives-macos: @@ -23,7 +24,7 @@ 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 @@ -56,7 +57,7 @@ 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 @@ -90,7 +91,7 @@ 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 diff --git a/gdx-video-desktop/build.gradle b/gdx-video-desktop/build.gradle index cddff60..547738d 100644 --- a/gdx-video-desktop/build.gradle +++ b/gdx-video-desktop/build.gradle @@ -53,6 +53,21 @@ String checkCrossPrefix(String crossToolchain) { 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] + return "dependencies/dav1d/packages/crossfiles/$name.meson" +} + + void registerBuild(String buildName, String crossToolchain, String... extraArgs) { String av1Dir = "dependencies/build/${buildName.toLowerCase()}/dav1d" String ffDir = file("dependencies/build/${buildName.toLowerCase()}/FFmpeg").absolutePath @@ -67,14 +82,16 @@ void registerBuild(String buildName, String crossToolchain, String... extraArgs) doFirst { mkdir av1Dir String[] crossArgs = [] - def crossPrefix = checkCrossPrefix(crossToolchain) - if(!crossPrefix.isEmpty()) { - crossArgs = ["--enable-cross-compile", "--cross-prefix=$crossPrefix"] + def crossFile = checkCrossFile(buildName, crossToolchain) + if(!crossFile.isEmpty()) { + def crosspath = file(crossFile).absolutePath + crossArgs = ["--cross-file=$crosspath"] } project.exec { workingDir av1Dir executable 'meson' args 'setup', '-Denable_tools=false', '-Denable_tests=false' + args crossArgs args '../../../dav1d', '--default-library=static' args '--prefix', "$ffDir/ffmpeg_build" args "--libdir=$ffDir/ffmpeg_build/lib" @@ -118,7 +135,6 @@ void registerBuild(String buildName, String crossToolchain, String... extraArgs) args '--enable-decoder=vorbis', '--enable-decoder=opus' args '--enable-decoder=vp8', '--enable-decoder=vp9', '--enable-decoder=theora', '--enable-decoder=av1' args '--enable-libdav1d', '--enable-decoder=libdav1d' - args '--pkg-config-flags=--static' args "--extra-cflags=-I$ffDir/ffmpeg_build/include" args "--extra-ldflags=-L$ffDir/ffmpeg_build/lib" args "--prefix=$ffDir/ffmpeg_build" @@ -128,7 +144,6 @@ void registerBuild(String buildName, String crossToolchain, String... extraArgs) } project.exec { workingDir ffDir - environment['V'] = 1 commandLine 'make', '-j16' } project.exec { @@ -145,7 +160,7 @@ registerBuild 'Windows64', 'x86_64-w64-mingw32', '--arch=x86_64', '--target-os=m 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 'LinuxARM32', 'arm-linux-gnueabihf', '--arch=arm', '--target-os=linux', '--disable-decoder=libdav1d' registerBuild 'LinuxARM64', 'aarch64-linux-gnu', '--arch=aarch64', '--target-os=linux' registerBuild 'Macos64', null, '--enable-cross-compile', '--arch=x86_64', '--target-os=darwin', '--cc=clang', '--cxx=clang++', '--dep-cc=clang', @@ -156,7 +171,7 @@ registerBuild 'MacosARM64', null, '--enable-cross-compile', '--arch=arm64', '--t jnigen { sharedLibName = "gdx-video-desktop" all { - headerDirs = ["../dependencies/FFmpeg", "../dependencies/dav1d"] + headerDirs = [] cFlags += " -fvisibility=hidden " cppFlags += " -fvisibility=hidden " //Using `-lavcodec -lavformat` order on linux drops filesize by half but mingw wont compile??? From c9088b52a92468c832a86f7b8efa06679ba2ca37 Mon Sep 17 00:00:00 2001 From: Maximilian Wende Date: Sun, 29 Dec 2024 17:12:09 +0100 Subject: [PATCH 3/4] Desktop: Separate gradle files, fix build on macOS --- .github/workflows/gradle.yml | 6 +- .github/workflows/publish_snapshot.yml | 12 +- .gitmodules | 4 +- gdx-video-desktop/FFmpeg/build.gradle | 167 ++++++++++++++++++ gdx-video-desktop/FFmpeg/src/FFmpeg | 1 + .../FFmpeg/src/arm32-linux.meson | 11 ++ .../FFmpeg/src/arm64-macos.meson | 23 +++ .../{dependencies => FFmpeg/src}/dav1d | 0 .../FFmpeg/src/x86_64-linux.meson | 11 ++ .../FFmpeg/src/x86_64-macos.meson | 23 +++ gdx-video-desktop/build.gradle | 164 +---------------- gdx-video-desktop/dependencies/FFmpeg | 1 - settings.gradle | 2 +- 13 files changed, 257 insertions(+), 168 deletions(-) create mode 100644 gdx-video-desktop/FFmpeg/build.gradle create mode 160000 gdx-video-desktop/FFmpeg/src/FFmpeg create mode 100644 gdx-video-desktop/FFmpeg/src/arm32-linux.meson create mode 100644 gdx-video-desktop/FFmpeg/src/arm64-macos.meson rename gdx-video-desktop/{dependencies => FFmpeg/src}/dav1d (100%) create mode 100644 gdx-video-desktop/FFmpeg/src/x86_64-linux.meson create mode 100644 gdx-video-desktop/FFmpeg/src/x86_64-macos.meson delete mode 160000 gdx-video-desktop/dependencies/FFmpeg diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 55a172b..e131861 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -27,7 +27,7 @@ jobs: 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 @@ -62,7 +62,7 @@ jobs: 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 @@ -95,7 +95,7 @@ jobs: 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 diff --git a/.github/workflows/publish_snapshot.yml b/.github/workflows/publish_snapshot.yml index 753349a..8fe2750 100644 --- a/.github/workflows/publish_snapshot.yml +++ b/.github/workflows/publish_snapshot.yml @@ -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 @@ -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 @@ -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 diff --git a/.gitmodules b/.gitmodules index 8f470d9..bc15eb3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,7 @@ [submodule "gdx-video-desktop/FFmpeg"] - path = gdx-video-desktop/dependencies/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/dependencies/dav1d + path = gdx-video-desktop/FFmpeg/src/dav1d url = https://code.videolan.org/videolan/dav1d.git diff --git a/gdx-video-desktop/FFmpeg/build.gradle b/gdx-video-desktop/FFmpeg/build.gradle new file mode 100644 index 0000000..e651c98 --- /dev/null +++ b/gdx-video-desktop/FFmpeg/build.gradle @@ -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'//, '--extra-libs=-lpthread' + 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 +} \ No newline at end of file diff --git a/gdx-video-desktop/FFmpeg/src/FFmpeg b/gdx-video-desktop/FFmpeg/src/FFmpeg new file mode 160000 index 0000000..cde3c5f --- /dev/null +++ b/gdx-video-desktop/FFmpeg/src/FFmpeg @@ -0,0 +1 @@ +Subproject commit cde3c5fc0c61281b4ee1e175a0ab0f367f297bf4 diff --git a/gdx-video-desktop/FFmpeg/src/arm32-linux.meson b/gdx-video-desktop/FFmpeg/src/arm32-linux.meson new file mode 100644 index 0000000..291ac6d --- /dev/null +++ b/gdx-video-desktop/FFmpeg/src/arm32-linux.meson @@ -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' diff --git a/gdx-video-desktop/FFmpeg/src/arm64-macos.meson b/gdx-video-desktop/FFmpeg/src/arm64-macos.meson new file mode 100644 index 0000000..8240447 --- /dev/null +++ b/gdx-video-desktop/FFmpeg/src/arm64-macos.meson @@ -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' diff --git a/gdx-video-desktop/dependencies/dav1d b/gdx-video-desktop/FFmpeg/src/dav1d similarity index 100% rename from gdx-video-desktop/dependencies/dav1d rename to gdx-video-desktop/FFmpeg/src/dav1d diff --git a/gdx-video-desktop/FFmpeg/src/x86_64-linux.meson b/gdx-video-desktop/FFmpeg/src/x86_64-linux.meson new file mode 100644 index 0000000..c16f16b --- /dev/null +++ b/gdx-video-desktop/FFmpeg/src/x86_64-linux.meson @@ -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' diff --git a/gdx-video-desktop/FFmpeg/src/x86_64-macos.meson b/gdx-video-desktop/FFmpeg/src/x86_64-macos.meson new file mode 100644 index 0000000..17afadc --- /dev/null +++ b/gdx-video-desktop/FFmpeg/src/x86_64-macos.meson @@ -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' \ No newline at end of file diff --git a/gdx-video-desktop/build.gradle b/gdx-video-desktop/build.gradle index 547738d..3330dec 100644 --- a/gdx-video-desktop/build.gradle +++ b/gdx-video-desktop/build.gradle @@ -32,142 +32,6 @@ dependencies { apply plugin: "com.badlogicgames.gdx.gdx-jnigen" -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] - return "dependencies/dav1d/packages/crossfiles/$name.meson" -} - - -void registerBuild(String buildName, String crossToolchain, String... extraArgs) { - String av1Dir = "dependencies/build/${buildName.toLowerCase()}/dav1d" - String ffDir = file("dependencies/build/${buildName.toLowerCase()}/FFmpeg").absolutePath - - tasks.register("cleanAV1$buildName", Delete) { - delete av1Dir - } - cleanAV1.configure { - dependsOn "cleanAV1$buildName" - } - tasks.register("buildAV1$buildName") { - doFirst { - mkdir av1Dir - String[] crossArgs = [] - def crossFile = checkCrossFile(buildName, crossToolchain) - if(!crossFile.isEmpty()) { - def crosspath = file(crossFile).absolutePath - crossArgs = ["--cross-file=$crosspath"] - } - project.exec { - workingDir av1Dir - executable 'meson' - args 'setup', '-Denable_tools=false', '-Denable_tests=false' - args crossArgs - args '../../../dav1d', '--default-library=static' - args '--prefix', "$ffDir/ffmpeg_build" - args "--libdir=$ffDir/ffmpeg_build/lib" - } - project.exec { - workingDir av1Dir - commandLine 'ninja' - } - project.exec { - workingDir av1Dir - commandLine 'ninja', 'install' - } - } - outputs.upToDateWhen { file("$ffDir/ffmpeg_build/lib/libdav1d.a").exists() } - } - - tasks.register("cleanFFmpeg$buildName", Delete) { - delete ffDir - } - cleanFFmpeg.configure { - dependsOn "cleanFFmpeg$buildName" - } - tasks.register("buildFFmpeg$buildName") { - dependsOn "buildAV1$buildName" - doFirst { - mkdir ffDir - String[] crossArgs = [] - def crossPrefix = checkCrossPrefix(crossToolchain) - if(!crossPrefix.isEmpty()) { - crossArgs = ["--enable-cross-compile", "--cross-prefix=$crossPrefix"] - } - project.exec { - workingDir ffDir - environment["PKG_CONFIG_PATH"] = "$ffDir/ffmpeg_build/lib/pkgconfig" - executable '../../../FFmpeg/configure' - 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' - args '--enable-decoder=vorbis', '--enable-decoder=opus' - args '--enable-decoder=vp8', '--enable-decoder=vp9', '--enable-decoder=theora', '--enable-decoder=av1' - args '--enable-libdav1d', '--enable-decoder=libdav1d' - args "--extra-cflags=-I$ffDir/ffmpeg_build/include" - args "--extra-ldflags=-L$ffDir/ffmpeg_build/lib" - args "--prefix=$ffDir/ffmpeg_build" - // Uncomment the following line for MP4 video support: - // args '--enable-demuxer=mov', '--enable-decoder=aac', '--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("$ffDir/ffmpeg_build/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', '--disable-decoder=libdav1d' -registerBuild 'LinuxARM64', 'aarch64-linux-gnu', '--arch=aarch64', '--target-os=linux' - -registerBuild 'Macos64', null, '--enable-cross-compile', '--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', '--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' - jnigen { sharedLibName = "gdx-video-desktop" all { @@ -178,12 +42,12 @@ jnigen { libraries += " -lavformat -lavcodec -lavutil -lswscale -lswresample -lpthread -ldav1d" } def genLibs = { String buildName -> - String ffPath = file("dependencies/build/$buildName/FFmpeg").absolutePath - return " -L$ffPath/ffmpeg_build/lib" + String outPath = file("FFmpeg/build/$buildName").absolutePath + return " -L$outPath/lib" } def genHeaders = { String buildName -> - String ffPath = file("dependencies/build/$buildName/FFmpeg").absolutePath - return " -I$ffPath/ffmpeg_build/include" + String outPath = file("FFmpeg/build/$buildName").absolutePath + return [ "$outPath/include" ] } add(Windows, x32) { @@ -199,7 +63,9 @@ jnigen { add(Linux, x64) { headerDirs += genHeaders("linux64") libraries += genLibs("linux64") - compilerPrefix = checkCrossPrefix('x86_64-linux-gnu') + if(os.name() != "Linux") { + compilerPrefix = 'x86_64-linux-gnu' + } linkerFlags += " -Wl,-Bsymbolic " } add(Linux, x32, ARM) { @@ -214,32 +80,20 @@ jnigen { } add(MacOsX, x64) { headerDirs += genHeaders("macos64") - libraries += genLibs("macos64") + " -liconv -lbz2 -lz -framework CoreFoundation -framework CoreVideo" + libraries += genLibs("macos64") + " -liconv -lbz2 -lz -framework CoreFoundation -framework CoreVideo -framework CoreMedia -framework VideoToolbox" cFlags += " -mmacosx-version-min=10.11" cppFlags += " -mmacosx-version-min=10.11" linkerFlags += " -mmacosx-version-min=10.11" } add(MacOsX, x64, ARM) { headerDirs += genHeaders("macosarm64") - libraries += genLibs("macosarm64") + " -liconv -lbz2 -lz -framework CoreFoundation -framework CoreVideo" + libraries += genLibs("macosarm64") + " -liconv -lbz2 -lz -framework CoreFoundation -framework CoreVideo -framework CoreMedia -framework VideoToolbox" cFlags += " -mmacosx-version-min=10.11" cppFlags += " -mmacosx-version-min=10.11" linkerFlags += " -mmacosx-version-min=10.11" } } -tasks.register('buildFFmpegWindowsAll') { - dependsOn buildFFmpegWindows32, buildFFmpegWindows64 -} - -tasks.register('buildFFmpegLinuxAll') { - dependsOn buildFFmpegLinux64, buildFFmpegLinuxARM32, buildFFmpegLinuxARM64 -} - -tasks.register('buildFFmpegMacosAll') { - dependsOn buildFFmpegMacos64, buildFFmpegMacosARM64 -} - tasks.register('jnigenBuildWindowsAll') { dependsOn jnigenBuildWindows, jnigenBuildWindows64 } diff --git a/gdx-video-desktop/dependencies/FFmpeg b/gdx-video-desktop/dependencies/FFmpeg deleted file mode 160000 index 25cd95a..0000000 --- a/gdx-video-desktop/dependencies/FFmpeg +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 25cd95a9dc3510c3cc0d7aad6f9d83f6a1078c7e diff --git a/settings.gradle b/settings.gradle index 921cf16..05ff538 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,2 @@ -include "gdx-video", "gdx-video-desktop", "gdx-video-desktop:gdx-video-lwjgl", "gdx-video-desktop:gdx-video-lwjgl3", "gdx-video-android", "gdx-video-gwt", "gdx-video-robovm", "test:core", "test:android", "test:desktop", "test:lwjgl3", "test:ios", "test:html" +include "gdx-video", "gdx-video-desktop", "gdx-video-desktop:FFmpeg", "gdx-video-desktop:gdx-video-lwjgl", "gdx-video-desktop:gdx-video-lwjgl3", "gdx-video-android", "gdx-video-gwt", "gdx-video-robovm", "test:core", "test:android", "test:desktop", "test:lwjgl3", "test:ios", "test:html" project(":gdx-video").name = "gdx-video-core" From cebf26c7d0cfe22c28dc9209eea4450533a42fa6 Mon Sep 17 00:00:00 2001 From: Maximilian Wende Date: Sun, 5 Jan 2025 15:40:52 +0100 Subject: [PATCH 4/4] Update documentation --- README.md | 27 ++++++++++++++++----------- gdx-video-desktop/FFmpeg/build.gradle | 2 +- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 55c4508..6b8d435 100644 --- a/README.md +++ b/README.md @@ -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: +**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: . 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. ### Resolution and framerate diff --git a/gdx-video-desktop/FFmpeg/build.gradle b/gdx-video-desktop/FFmpeg/build.gradle index e651c98..2692f0f 100644 --- a/gdx-video-desktop/FFmpeg/build.gradle +++ b/gdx-video-desktop/FFmpeg/build.gradle @@ -110,7 +110,7 @@ void registerBuild(String buildName, String crossToolchain, String... extraArgs) environment["PKG_CONFIG_PATH"] = "$outDir/lib/pkgconfig" executable '../../../../src/FFmpeg/configure' args '--pkg-config=pkg-config', '--pkg-config-flags=--static' - args '--disable-autodetect'//, '--extra-libs=-lpthread' + args '--disable-autodetect' args '--enable-pic', '--disable-symver', '--disable-doc', '--disable-shared', '--enable-static' args crossArgs args '--disable-everything'