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.71k stars 6.02k forks source link

Exception Invalid NAL length in CMAF streams (clear video) #7698

Closed YongtaoS closed 4 years ago

YongtaoS commented 4 years ago

Hi there,

ExoPlayer throws Invalid NAL length exception while playing a CMAF live stream (sample files attached below). The video is not encrypted and safar/quicktime/bitmovin can play it without problem. I appreciate much if you could identify whether the issue is.

[REQUIRED] Issue description

HLS with CMAF fragments on Safari/QuickTime/Bitmovin : OK DASH witch CMAF fragments on Bitmovin player : OK DASH/HLS with CMAF fragments on ExoPlayer : failed with Invalid NAL length

[REQUIRED] Reproduction steps

Android Studio Add target stream to media.exolist.json Run Debug 'demo' Play the target stream Get playback failed

[REQUIRED] Link to test content

An init fragment and a video fragment are in cmaf.zip

[REQUIRED] A full bug report captured from the device

E/EventLogger: playerFailed [eventTime=1.07, mediaPos=68.00, window=0, period=0
      com.google.android.exoplayer2.ExoPlaybackException: com.google.android.exoplayer2.ParserException: Invalid NAL length
        at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:394)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:223)
        at android.os.HandlerThread.run(HandlerThread.java:67)
     Caused by: com.google.android.exoplayer2.ParserException: Invalid NAL length
        at com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor.readSample(FragmentedMp4Extractor.java:1317)
        at com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor.read(FragmentedMp4Extractor.java:321)
        at com.google.android.exoplayer2.source.hls.HlsMediaChunk.feedDataToExtractor(HlsMediaChunk.java:376)
        at com.google.android.exoplayer2.source.hls.HlsMediaChunk.loadMedia(HlsMediaChunk.java:343)
        at com.google.android.exoplayer2.source.hls.HlsMediaChunk.load(HlsMediaChunk.java:314)
        at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:415)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:923)
    ]

[REQUIRED] Version of ExoPlayer being used

r2.11.7

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

Virtual device: Pixel_3a_API_30_x86 (Android 10.0+)

tonihei commented 4 years ago

Could you also provide a valid manifest/playlist to play these files? Otherwise I need to hand-craft these files without knowing all the required metadata. If you don't want to share publicly, please send an email to dev.exoplayer@gmail.com with "Issue #7698" in the subject line.

YongtaoS commented 4 years ago

Hi tonihei, thank you for the reply. I just sent two links to the email address. Please confirm if you get them and reproduce the issues.

tonihei commented 4 years ago

Thanks, we received the streams and I can reproduce the problem. I'll assign to @kim-vde for further investigation.

kim-vde commented 4 years ago

There is a small issue in the media: the trun box specifies both first_sample_flags and sample_flags, which is not allowed according to ISO/IEC 14496-12:2015 (section 8.8.8.1).

I will update the code to make it more robust. This should fix your issue.

YongtaoS commented 4 years ago

Thank you for your quick response.

You are right.

If I understand the spec correctly, a proper setting would be : if first_sample_flags is present, the sample_flags of only the first sample should not be present, but the sample_flags of other samples can still be present. And the first_sample_flags_present and sample_flags_present both can still be true. Am I right?

kim-vde commented 4 years ago

My understanding is that you cannot have both first_sample_flags and sample_flags (i.e. first_sample_flags_present and sample_flags_present cannot be both true). If first_sample_flags is present, no sample_flags should be specified. Otherwise, sample_flags must be specified for every sample.

first_sample_flags is there to avoid repetition in case all samples are the same as the default_sample_flags except the first one (because it is a key frame).

YongtaoS commented 4 years ago

It makes sense.

FYI. Exoplayer is able to play the stream after removing first_sample_flags.

Thanks a lot!