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

MPEG-TS stream with SCTE subtitle track may fail to start #5330

Closed okycelt closed 5 years ago

okycelt commented 5 years ago

Issue description

When trying to play the .ts file sent via email, the player goes to prepared state but doesn't start playing anything. If we stream the .ts file by tsplay as a UDP multicast, the player won't throw any error. If we try playing the .ts file directly from the device, we get OutOfMemoryError after a few seconds. We've tried setting the FLAG_ALLOW_NON_IDR_KEYFRAMES and FLAG_DETECT_ACCESS_UNITS flags but it didn't have any effect.

12-31 05:27:09.890  5731  5731 E EventLogger: internalError [11.40, 0.00, window=0, period=0, loadError]
12-31 05:27:09.890  5731  5731 E EventLogger: com.google.android.exoplayer2.upstream.Loader$UnexpectedLoaderException: Unexpected OutOfMemoryError: Failed to allocate a 65548 byte allocation with 1904 free bytes and 1904B until OOM
12-31 05:27:09.890  5731  5731 E EventLogger:   at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:409)
12-31 05:27:09.890  5731  5731 E EventLogger:   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
12-31 05:27:09.890  5731  5731 E EventLogger:   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
12-31 05:27:09.890  5731  5731 E EventLogger:   at java.lang.Thread.run(Thread.java:818)
12-31 05:27:09.890  5731  5731 E EventLogger: Caused by: java.lang.OutOfMemoryError: Failed to allocate a 65548 byte allocation with 1904 free bytes and 1904B until OOM
12-31 05:27:09.890  5731  5731 E EventLogger:   at com.google.android.exoplayer2.upstream.DefaultAllocator.allocate(DefaultAllocator.java:102)
12-31 05:27:09.890  5731  5731 E EventLogger:   at com.google.android.exoplayer2.source.SampleQueue.preAppend(SampleQueue.java:626)
12-31 05:27:09.890  5731  5731 E EventLogger:   at com.google.android.exoplayer2.source.SampleQueue.sampleData(SampleQueue.java:562)
12-31 05:27:09.890  5731  5731 E EventLogger:   at com.google.android.exoplayer2.extractor.ts.MpegAudioReader.readHeaderRemainder(MpegAudioReader.java:192)
12-31 05:27:09.890  5731  5731 E EventLogger:   at com.google.android.exoplayer2.extractor.ts.MpegAudioReader.consume(MpegAudioReader.java:98)
12-31 05:27:09.890  5731  5731 E EventLogger:   at com.google.android.exoplayer2.extractor.ts.PesReader.consume(PesReader.java:136)
12-31 05:27:09.890  5731  5731 E EventLogger:   at com.google.android.exoplayer2.extractor.ts.TsExtractor.read(TsExtractor.java:325)
12-31 05:27:09.890  5731  5731 E EventLogger:   at com.google.android.exoplayer2.source.ExtractorMediaPeriod$ExtractingLoadable.load(ExtractorMediaPeriod.java:898)
12-31 05:27:09.890  5731  5731 E EventLogger:   at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:379)
12-31 05:27:09.890  5731  5731 E EventLogger:   ... 3 more

Also, regarding MPEG-TS content in general, we've been having issues with playing some content. From our experience, ExoPlayer is usually able to play about 90% of streams we encounter but we're often not sure why the problematic streams are problematic. Do you have any advice on what to pay attention to when debugging this or on what is ExoPlayer sensitive to?

Thank you.

Reproduction steps

Either play the .ts file directly using FileDataSource and ExtractorMediaSource or stream the .ts file using tsplay and play the stream using UdpDataSource and ExtractorMediaSource.

Link to test content

Sent via email

Version of ExoPlayer being used

ExoPlayer 2.9.0

Device(s) and version(s) of Android being used

Amlogic S905X, 1GB RAM, Android 6.0.1 HiSillicon Hi3798M V200, 2GB RAM, Android 8.0

A full bug report captured from the device

Sent via email (both when using FileDataSource and when using UdpDataSource)

ojw28 commented 5 years ago

@andrewlewis - This looks related to addition of DTS support [internal cr ref: 112774678]. There's a stream with type 0x82 (TS_STREAM_TYPE_HDMV_DTS) in this piece of content, but I think it's probably an SCTE subtitle track instead. As a result we don't ever get a format for the track, so end up stuck preparing. According to https://en.wikipedia.org/wiki/Program-specific_information 0x82 can be:

SCTE subtitle or DTS 6 channel audio for Blu-ray in a packetized stream",

however we currently assume the latter. This might not be easy to fix, unfortunately.

andrewlewis commented 5 years ago

@AquilesCanta Any ideas if there's some signaling that we can use to distinguish these?

okycelt commented 5 years ago

In theory, would it be possible to do something temporary on our end? Either signal the player manually that it should treat the 0x82 stream as SCTE subtitle or tell the player to skip the 0x82 stream completely? Thank you.

andrewlewis commented 5 years ago

TsExtractor can take a custom TsPayloadReaderFactory where you implement your own behavior, like delegating to a DefaultTsPayloadReaderFactory except when the stream type is 0x82. When creating ExtractorMediaSource you can pass a custom ExtractorsFactory that creates the TsExtractor with the custom payload reader factory.

whyvas commented 5 years ago

I can't help with your original question but I was wondering if you could tell me how you did UDP over multicast? I can't seem to figure it out. What uri do you use? How do you construct the player?

Cheers!

okycelt commented 5 years ago

@whyvas You can use UdpDataSource.Factory together with ExtractorsMediaSource.Factory. To createMediaSource method pass Uri.parse("udp://@239.0.0.1:1234").

ojw28 commented 5 years ago

Please can we keep this on topic. Thanks.

whyvas commented 5 years ago

Okycelt, you are a king among men! Thank you.

AquilesCanta commented 5 years ago

I think using a custom TsPayloadReaderFactory is the way to go. I'd just wrap the default implementation and intercept the 0x82 stream type.

As a library-side fix, I think sniffing the PES packets is the only way to go. Unfortunately, I cannot allocate time to do this. For the time being, I have added a flag to the DefaultTsPayloadReaderFactory: FLAG_IGNORE_HDMV_DTS_STREAM, which will be available in the next push. Setting this flag should save you the factory customization.

ojw28 commented 5 years ago

@andrewlewis - Given we can't reliably disambiguate between SCTE and DTS at the moment, should we consider disabling DTS support by default, and flipping the flag so that we only enable support if a flag is set?

The issue ref'd above contains more streams that are affected by this issue.