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
31 lines
1.7 KiB
Prolog
31 lines
1.7 KiB
Prolog
# Flutter turns minification on for every release build (FlutterPlugin sets
|
|
# releaseBuildType.isMinifyEnabled), and appends this file when it exists. Anything the
|
|
# app reaches only by name — reflection or JNI — therefore needs an explicit keep here.
|
|
|
|
# The bundled Media3 FFmpeg audio decoder (ALAC, DTS, DTS-HD, TrueHD, ...).
|
|
#
|
|
# DefaultRenderersFactory instantiates FfmpegAudioRenderer through Class.forName and no
|
|
# app code references it, so R8 shrinks the class away; media3's own consumer rules only
|
|
# -keepclassmembers its constructor, which neither keeps the class nor pins its name.
|
|
# ffmpeg_jni.cc separately resolves FfmpegAudioDecoder and its growOutputBuffer callback
|
|
# by name in JNI_OnLoad, and returns JNI_ERR when either is missing, which fails the whole
|
|
# System.loadLibrary("ffmpegJNI") call.
|
|
#
|
|
# Without these keeps a release build silently loses every codec this decoder adds:
|
|
# TrueHD/DTS-HD land on MediaCodecAudioRenderer, which has no decoder for them, and
|
|
# playback bails to the mpv fallback and loses ExoPlayer's Dolby Vision handling (#1703).
|
|
-keep class androidx.media3.decoder.ffmpeg.** { *; }
|
|
|
|
# growOutputBuffer's JNI descriptor names this type, so it may not be renamed either.
|
|
-keep class androidx.media3.decoder.SimpleDecoderOutputBuffer { *; }
|
|
|
|
# ffmpeg_demuxer_jni.cc resolves the AVIO input proxy's callbacks by name
|
|
# (FindClass on the interface, GetMethodID for position/read/length). Keeping
|
|
# the interface members pins the names on every implementation, including the
|
|
# anonymous proxy inside FfmpegExtractor.
|
|
-keep interface com.edde746.plezy.exoplayer.FfmpegDemuxerJni$Input {
|
|
long position();
|
|
int read(byte[], int);
|
|
long length();
|
|
}
|