-
Notifications
You must be signed in to change notification settings - Fork 6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix playback of I-FRAME only variants in Apple's advanced FMP4 stream #7512
Comments
@AquilesCanta what is happening is the This makes the subrange computed on HlsMediaChunk#L365 invalid (as the left over value in I have sample mp4 files that seem to re-create the issue, if you are ok with it I will add this to the Thanks for catching it!. |
I'm still not clear how the nextLoadPosition is involved. I thought nextLoadPosition was relevant when there was an error while reading the media. The error I ran into when I tried the media was an end of input exception. But when I added a catch to ignore that exception, and treat the chunk as completed (In which case nextLoadPosition should not matter), playback still failed. Any PRs are welcome though. If just for reference you can explain the phenomenon, it would be really useful. To be honest I didn't really dig that much. It's possible it's really simple. |
Well, nothing is ever really simple ;-). I'm not clear on the history (looks very long back) on the comments on line 355 but it seems the range in the At the completion of parsing of one of these ranged segments I will figure it out, right now we are updating our release to merge in your release tag r2.11.6 (which looks like the branch missed the cutoff to include our pull i-frame only support anyway). |
I'm sharing here what I've found so far on this issue. I'm not trying to propose any workaround/fix just yet. Apple's Fmp4 IFrame-only stream is simply a sequence of moof->mdat->moof->mdat->... atoms, where each pair (moof->mdat) contains entire GOP (similar to many regular video stream). Frames other than reference ones are also in there, however, the Apple's stream generator ranges them out in the HLS playlist. During playback, once initialized with 'moov' atom, the Fmp4Extractor, is fed with data chunks that always start with the 'moof' box and the following 'mdat' box, truncated past the first sample, which is the GOP opening IFrame. Upon 'moof' container reception the extractor is parsing the entire GOP as it doesn't know at this point that only the first IFrame is of player's interest. Besides minor CPU overhead, that doesn't seem to be an issue as the parser output lands in the temporary internal data structures such as TrackBundle. Once all the metadata is parsed and the 'mdat' box header has arrived, the extractor tries to extract out the first sample, which should be the IFrame. That part also works fine for Apple's IFrame stream as the byte range includes the 'mdat' part containing desired frame. The Fmp4Extractor.read(...) method is written to read one sample at a time so, after getting the IFrame data it saves its state and returns. Stream position is saved too. The value returned indicates whether the extractor expects to be called again to continue extracting from that spot. In Apple's IFrame stream case it would probably be best to say 'no-more' at this point but the current code doesn't check if the actual stream position is just few bytes away from the end of the byte range and it tries to keep going. Method HlsMediaChunk.feedDataToExtractor(...) calls Fmp4Extractor.read(...) again and that call gets an IOexception as it tries to read next sample beyond the actual byte range. Unfortunately, this exception is handled by the Loader.run() method, who applies its internal re-try logic in such a case without letting anyone else know about it. Ultimately 'loadable' object i.e. HlsMediaChunk gets loaded again (loadable.load()->loadMedia()->feedDataToExtractor()) and this time we hit assetrs for incorrect byte range update and other follow-up errors which fail the playback. The investigation is in progress, I'll soon add a unit test that will try to reproduce this issue. |
@AquilesCanta Basically the issue is Apple is referencing parts of the base MP4 file in both the playlist and the i-frame playlist. The playlist segments contain an entire MDAT (the full GOP), the i-Frame only playlist truncates the MDAT after the first sample (the IDR). Basically, Apple's Fmp4 IFrame-only stream, just like their TS streams, are produced by byte-ranging out part of the main stream. For example:
The BYTERANGE in the first i-Frame starts at the offset of the first MOOV in The Range includes the MOOV -> MOOF, but not all of the following MDAT You can see this by downloading main.mp4 and using the handy Online MP4 Parser to parse it out. It
I'll let Maciej (@mdobrzyn71 ) comment further on how this is causing the |
Hi @mdobrzyn71 and @stevemayhew, I think I got that far. However, I remember trying to catch and ignore Please feel free to try it yourselves: In |
Hi @AquilesCanta , @stevemayhew I've implemented a temporary patch that allows Apple's IFrame-only stream to be played : p-fix-apple-iframe-bug Although quick & working, this patch has some severe performance cons:
An ideal implementation should NOT destroy the As I mentioned, method Two options:
question to @ojw28 : Oliver, what about initialization of DRM for partial segments like i-Frame? |
The fix has been merged. Please reach back to us if you find any further issues with I-FRAME-ONLY variants playback. |
To reproduce, simply play the "Apple master playlist advanced (FMP4)" sample from the demo app and select (using the track selection UI) an I-FRAME only track.
Note: I-FRAME only variants are only accessible through track selection overrides.
The text was updated successfully, but these errors were encountered: