Enable support for WebVTT and TTML subtitles for the player (#4377)

All subtitle formats used to be enabled by default in older versions of
media3.
After the media3 library was upgraded to 1.3.0, Extractors should
specify a `SubtitleParser.Factory` explicitly. By default, no subtitle
formats are supported when using the now deprecated empty constructor of
Extractors.

Limit support to **WebVTT** and **TTML** which are the only true web
standards amongst all the subtitle formats supported by ExoPlayer.

Note that only subtitles embedded in MP4 and WebM files are supported
until Mastodon provides a way to upload subtitles separately.
This commit is contained in:
Christophe Beyls 2024-04-17 21:29:21 +02:00 committed by GitHub
parent 4e822c9a0a
commit 72ee0b4292
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 43 additions and 4 deletions

View File

@ -21,6 +21,8 @@ import android.content.Context
import android.os.Looper
import androidx.annotation.OptIn
import androidx.media3.common.C
import androidx.media3.common.Format
import androidx.media3.common.MimeTypes
import androidx.media3.common.util.UnstableApi
import androidx.media3.datasource.DataSource
import androidx.media3.datasource.DefaultDataSource
@ -44,6 +46,10 @@ import androidx.media3.extractor.mp3.Mp3Extractor
import androidx.media3.extractor.mp4.FragmentedMp4Extractor
import androidx.media3.extractor.mp4.Mp4Extractor
import androidx.media3.extractor.ogg.OggExtractor
import androidx.media3.extractor.text.SubtitleParser
import androidx.media3.extractor.text.ttml.TtmlParser
import androidx.media3.extractor.text.webvtt.Mp4WebvttParser
import androidx.media3.extractor.text.webvtt.WebvttParser
import androidx.media3.extractor.wav.WavExtractor
import dagger.Module
import dagger.Provides
@ -98,17 +104,50 @@ object PlayerModule {
}
@Provides
fun provideExtractorsFactory(): ExtractorsFactory {
fun providesSubtitleParserFactory(): SubtitleParser.Factory {
return object : SubtitleParser.Factory {
override fun supportsFormat(format: Format): Boolean {
return when (format.sampleMimeType) {
MimeTypes.TEXT_VTT,
MimeTypes.APPLICATION_MP4VTT,
MimeTypes.APPLICATION_TTML -> true
else -> false
}
}
override fun getCueReplacementBehavior(format: Format): Int {
return when (val mimeType = format.sampleMimeType) {
MimeTypes.TEXT_VTT -> WebvttParser.CUE_REPLACEMENT_BEHAVIOR
MimeTypes.APPLICATION_MP4VTT -> Mp4WebvttParser.CUE_REPLACEMENT_BEHAVIOR
MimeTypes.APPLICATION_TTML -> TtmlParser.CUE_REPLACEMENT_BEHAVIOR
else -> throw IllegalArgumentException("Unsupported MIME type: $mimeType")
}
}
override fun create(format: Format): SubtitleParser {
return when (val mimeType = format.sampleMimeType) {
MimeTypes.TEXT_VTT -> WebvttParser()
MimeTypes.APPLICATION_MP4VTT -> Mp4WebvttParser()
MimeTypes.APPLICATION_TTML -> TtmlParser()
else -> throw IllegalArgumentException("Unsupported MIME type: $mimeType")
}
}
}
}
@Provides
fun provideExtractorsFactory(subtitleParserFactory: SubtitleParser.Factory): ExtractorsFactory {
// Extractors order is optimized according to
// https://docs.google.com/document/d/1w2mKaWMxfz2Ei8-LdxqbPs1VLe_oudB-eryXXw9OvQQ
return ExtractorsFactory {
arrayOf(
FlacExtractor(),
WavExtractor(),
Mp4Extractor(),
FragmentedMp4Extractor(),
Mp4Extractor(subtitleParserFactory),
FragmentedMp4Extractor(subtitleParserFactory),
OggExtractor(),
MatroskaExtractor(),
MatroskaExtractor(subtitleParserFactory),
Mp3Extractor()
)
}