Direct play on Android kept accumulating container patches: AVI with XviD packed-bitstream timestamps and missing VOL csd played broken, ASF/WMV and MPEG-PS/VOB had no media3 extractor at all, and MKV needed a custom extractor stack for zlib-compressed subtitles, LOAS/LATM audio, cueless seeking, and font attachments. Demux progressive containers with libavformat behind media3's extractor API. An AVIO bridge serves libavformat from the ExtractorInput: every position divergence defers into a RESULT_SEEK round trip, header reads replay from a block cache while avformat_open_input restarts, and avformat_seek_file executes seeks with bounded loader round trips. Packets feed media3's TrackOutputs, so decoders, passthrough carriers, Dolby Vision RPU/EL conversion (dvh1 codecs string surfaced from DOVI side data), and the subtitle pipeline are untouched: embedded fonts feed AssHandler over JNI, ASS reaches libass as per-sample dialogue, SRT/VTT render as cues, VobSub maps through media3's VobsubParser, and LOAS/LATM AAC unwraps via LatmTrackOutput. Under the default Auto preference FFmpeg demuxes AVI, ASF/WMV, MPEG-PS, and Matroska/WebM and sits behind media3's list as an any-container fallback; MP4/TS keep media3's extractors. A playback setting exposes auto / FFmpeg first / media3 only, and the JNI load-failure path falls back to stock media3. The custom Matroska extractor stack and its reflection keeps are retired. Verified on Pixel 7 (API 36), Box R 4K Plus TV (API 34), and SHIELD TV (API 30): instrumentation playback suites, the minified R8 reachability gate, and an on-device container matrix with forward and backward seek landings plus visual subtitle checks. close #2052
64 lines
1.9 KiB
Kotlin
64 lines
1.9 KiB
Kotlin
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
|
|
|
// Static-linking the native core here avoids shipping a separate libass.so with
|
|
// different merge rules from the app.
|
|
plugins {
|
|
id("com.android.library")
|
|
id("org.jetbrains.kotlin.android")
|
|
}
|
|
|
|
android {
|
|
namespace = "com.edde746.plezy.libass"
|
|
compileSdk = 36
|
|
// Matches the app's latest stable NDK so every project-owned native library
|
|
// is built with the same 16 KB page-size-capable libc++ toolchain. That copy
|
|
// is NOT what ships: the app packages the libmpv AAR's newer copy with top
|
|
// merge priority (see app/build.gradle.kts packaging { jniLibs } + sourceSets).
|
|
ndkVersion = "29.0.14206865"
|
|
|
|
defaultConfig {
|
|
minSdk = 21
|
|
consumerProguardFiles("consumer-rules.pro")
|
|
externalNativeBuild {
|
|
cmake {
|
|
// HarfBuzz pulls in C++, so the JNI library must use the shared STL that
|
|
// the app already pins through libmpv.
|
|
// A shared cache keeps per-ABI CMake runs from redownloading libass.
|
|
arguments += listOf(
|
|
"-DANDROID_STL=c++_shared",
|
|
"-DLIBASS_CACHE_DIR=${layout.buildDirectory.get().asFile}/libass-prebuilt"
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
compileOptions {
|
|
sourceCompatibility = JavaVersion.VERSION_17
|
|
targetCompatibility = JavaVersion.VERSION_17
|
|
}
|
|
|
|
externalNativeBuild {
|
|
cmake {
|
|
path = file("src/main/cpp/CMakeLists.txt")
|
|
version = "4.1.2"
|
|
}
|
|
}
|
|
}
|
|
|
|
kotlin {
|
|
compilerOptions {
|
|
jvmTarget.set(JvmTarget.JVM_17)
|
|
}
|
|
}
|
|
|
|
dependencies {
|
|
implementation("androidx.annotation:annotation:1.10.0")
|
|
implementation("androidx.annotation:annotation-experimental:1.6.0")
|
|
implementation("androidx.media3:media3-exoplayer:1.11.0")
|
|
implementation("androidx.media3:media3-ui:1.11.0")
|
|
|
|
testImplementation("junit:junit:4.13.2")
|
|
// media3 Format/MimeTypes touch android.util in static initializers.
|
|
testImplementation("org.robolectric:robolectric:4.16.1")
|
|
}
|