google / ExoPlayer

This project is deprecated and stale. The latest ExoPlayer code is available in https://github.com/androidx/media
https://developer.android.com/media/media3/exoplayer
Apache License 2.0
21.7k stars 6.02k forks source link

ParserException for DASH Subtitles (WebVTT in MP4 container) #7985

Closed bhjortsberg closed 3 years ago

bhjortsberg commented 3 years ago

[REQUIRED] Issue description

This stream worked fine in 2.11.8 https://storage.googleapis.com/shaka-demo-assets/angel-one/dash.mpd

On ExoPlayer 2.12.0 I get this:

2020-09-24 22:22:52.987 6762-7202/com.mtdeer.exostreamr E/TextRenderer: Subtitle decoding failed. streamFormat=Format(2, null, application/mp4, text/vtt, wvtt, 736, en, [-1, -1, -1.0], [-1, -1])
      com.google.android.exoplayer2.text.SubtitleDecoderException: com.google.android.exoplayer2.ParserException: Expected WEBVTT. Got �����vtte
        at com.google.android.exoplayer2.text.webvtt.WebvttDecoder.decode(WebvttDecoder.java:63)
        at com.google.android.exoplayer2.text.SimpleSubtitleDecoder.decode(SimpleSubtitleDecoder.java:73)
        at com.google.android.exoplayer2.text.SimpleSubtitleDecoder.decode(SimpleSubtitleDecoder.java:27)
        at com.google.android.exoplayer2.decoder.SimpleDecoder.decode(SimpleDecoder.java:234)
        at com.google.android.exoplayer2.decoder.SimpleDecoder.run(SimpleDecoder.java:198)
        at com.google.android.exoplayer2.decoder.SimpleDecoder.access$000(SimpleDecoder.java:29)
        at com.google.android.exoplayer2.decoder.SimpleDecoder$1.run(SimpleDecoder.java:72)
     Caused by: com.google.android.exoplayer2.ParserException: Expected WEBVTT. Got �����vtte
        at com.google.android.exoplayer2.text.webvtt.WebvttParserUtil.validateWebvttHeaderLine(WebvttParserUtil.java:45)
        at com.google.android.exoplayer2.text.webvtt.WebvttDecoder.decode(WebvttDecoder.java:61)
        at com.google.android.exoplayer2.text.SimpleSubtitleDecoder.decode(SimpleSubtitleDecoder.java:73) 
        at com.google.android.exoplayer2.text.SimpleSubtitleDecoder.decode(SimpleSubtitleDecoder.java:27) 
        at com.google.android.exoplayer2.decoder.SimpleDecoder.decode(SimpleDecoder.java:234) 
        at com.google.android.exoplayer2.decoder.SimpleDecoder.run(SimpleDecoder.java:198) 
        at com.google.android.exoplayer2.decoder.SimpleDecoder.access$000(SimpleDecoder.java:29) 
        at com.google.android.exoplayer2.decoder.SimpleDecoder$1.run(SimpleDecoder.java:72) 

[REQUIRED] Reproduction steps

Stream https://storage.googleapis.com/shaka-demo-assets/angel-one/dash.mpd and select any of the subtitle tracks.

[REQUIRED] Link to test content

https://storage.googleapis.com/shaka-demo-assets/angel-one/dash.mpd

[REQUIRED] A full bug report captured from the device

bugreport-sdk_gphone_x86-QSR1.191030.002-2020-09-24-22-36-21.zip

[REQUIRED] Version of ExoPlayer being used

2.12.0

[REQUIRED] Device(s) and version(s) of Android being used

Android 10 on Pixel 3a emulator

marcbaechinger commented 3 years ago

The dash stream defines text tracks in application/mp4 and the stack trace suggests that the WebvttParserUtil reads a binary file while expecting a text file. ExoPlayer supports separate text tracks for text mime types as documented in the developer guide.

marcbaechinger commented 3 years ago

Seems like I'm wrong and this worked before 2.12. Thanks @icbaker for letting me know. :)

icbaker commented 3 years ago

Yep - i can repro that the stream you provided works on 2.11.8 and plays on 2.12 but without functioning subtitles (and with stack traces in logcat similar to the ones you posted).

I'll dig further in and work out what's changed here to cause the regression - thanks for the report!

icbaker commented 3 years ago

Looks like this is related to https://github.com/google/ExoPlayer/commit/74a9d8f680995f2096c59fde6cd1ef6e85bb4d55.

Specifically removing this:

} else if (codecs.startsWith("wvtt")) { 
  return MimeTypes.APPLICATION_MP4VTT;    // "application/x-mp4-vtt"
}

And instead delegating to MimeTypes.getMediaMimeType which translates 'wvtt' to 'text/vtt': https://github.com/google/ExoPlayer/blob/8a0d52be4b5402af0987fc7d009bc49977c72b67/library/common/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java#L341-L342

In the context of DashManifestParser that change makes sense - the method is called getSampleMimeType, and the samples are WebVTT.

The problem is that SubtitleDecoderFactory wasn't updated at the same time, and it expects to see application/x-mp4-vtt and uses that to decide to create a Mp4WebvttDecoder (which is the class that knows how to pull WebVTT data out of an MP4 container): https://github.com/google/ExoPlayer/blob/8a0d52be4b5402af0987fc7d009bc49977c72b67/library/core/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java#L101-L102

This means SubtitleDecoderFactory creates a WebvttDecoder which expects the input data to be a simple text file starting WEBVTT on the first line - which explains the error you're seeing, and why Marc concluded this was a binary file being read by something expecting plaintext (since that's exactly what's happening).

I'll send a change to SubtitleDecoderFactory to consider Format.containerMimeType as well: if container == "application/mp4" && sample == "text/vtt" then we should use Mp4WebvttDecoder.