Skip to content
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

Meta issue for good DASH/HLS support in mpv #7033

Open
ghost opened this issue Oct 6, 2019 · 10 comments
Open

Meta issue for good DASH/HLS support in mpv #7033

ghost opened this issue Oct 6, 2019 · 10 comments
Labels
meta:help-wanted Anyone is invited to help with this. Suitable for new developers with no experience with mpv code. meta:rfc

Comments

@ghost
Copy link

ghost commented Oct 6, 2019

This is sort of a place holder issue, because it seems to come up all the time. May also serve for communication, random questions, or volunteers volunteering.

Existing support

FFmpeg has HLS support (aka m3u8). It also has DASH support (aka mpd), but this depends on an external library (XML parser) and thus is not enabled in FFmpeg by default.

ytdl_hook.lua and mpv's EDL support sometimes emulate DASH in special cases. It works by ytdl parsing the DASH manifest, returning it as JSON, and ytdl_hook.lua converting it to EDL. EDL has some mechanisms to make it efficient (for example not needing to open each EDL segment before playback start, which is normally done with EDL). This is here: https://github.com/mpv-player/mpv/blob/master/DOCS/edl-mpv.rst#mp4-dash

Problems

Most importantly, FFmpeg does not use HTTP2, which is apparently needed for getting pipelining at all. While FFmpeg's HLS demuxer tries to pipeline HTTP1.1 requests, this works badly and often not at all. It does not make any requests ahead of time. It does not open multiple HTTP connections at once (or use HTTP2 multiplexing). All this makes it slow due to added roundtrip latencies, or in other words, unnecessary waiting.

FFmpeg's DASH support has all the same problems as HLS, but in addition is often broken (judging by bug reports). It even seems to have some crashing bugs. The fact that it depends on an external library means we can't rely on its existence either.

Solution

I suspect for good support, we're going to need HTTP2. I have some libcurl support in a private branch, which may or may not help. But even then, FFmpeg would need to make requests ahead for better efficiency.

Someone could implement HLS/DASH support directly in mpv. Then we'd have control over fixing its issues. However, implementing these is probably not fun, given all the mess in the HLS "protocol", or DASH's fractal standard + XML nightmare.

Or someone needs to improve the existing support in FFmpeg. That means adding some sort of prefetch or parallel request support, and implementing either HTTP2 access, a libcurl wrapper, or something that would enable an API user (mpv) to receive prefetch requests. his someone would also need to be ready to fix all the issues in DASH whenever they happen, which should eventually result in solid DASH support.

@ghost
Copy link
Author

ghost commented Oct 6, 2019

Also I heard @tmm1 implemented some sort of custom HLS support on top of stream_cb. This is probably private code (that builds on top of libmpv), but I think it makes a nice anecdote about FFmpeg's HLS support, and how tmm1 specifically tried to improve it over the years. Correct me if I'm wrong.

@Akemi Akemi added meta:help-wanted Anyone is invited to help with this. Suitable for new developers with no experience with mpv code. meta:rfc labels Oct 6, 2019
@tmm1
Copy link
Contributor

tmm1 commented Oct 6, 2019

While FFmpeg's HLS demuxer tries to pipeline HTTP1.1 requests, this works badly and often not at all. It does not make any requests ahead of time. It does not open multiple HTTP connections at once (or use HTTP2 multiplexing).

FFmpeg currently uses two separate http connections, and will issue a http request for the next segment using the second connection while the first segment is being downloaded. Both connections also use http/1.1 keepalives so a new TCP+TLS negotiation is not required per segment.

While this improved throughput compared to the previous single-connection-per-segment, it's still pretty lacking and you're correct that further improvements are very hard to add given how hls.c works.

We ended up giving up on hls.c for these reasons, and now have our own hls client written in a higher level language which has a full http/2 client with pipelining and connection pooling. Our client includes bandwidth measurement and will open up as many parallel connections as possible to max out available bandwidth. To integrate with mpv, we expose an open/read/seek interface to C, and then use stream_cb to tie everything together. It's pretty hacky but it works well.

@hanguofu
Copy link

hanguofu commented Oct 8, 2019

Thanks for creating this thread to brainstorm good ideas :) tmm1's comment gives us some light on segments congestion for HLS/DASH applications. My questions go a little deeper :

  1. how to probe ( including hack ) the internal buffer of decoding pipeline so that we can pause the decoder at the last moment when we find out a bad internet connection for accessing segments ?
    Will the decoder resume to work ( including the display unit ) if we feed mpv with new segment during pause ? Is there any smarter solution for this manual intervention ?
  2. What is the current solution to the above underflow case ?

@ghost
Copy link
Author

ghost commented Oct 8, 2019

In what context? Are you also using a stream_cb thing or so?

@hanguofu
Copy link

hanguofu commented Oct 8, 2019

haven't decided yet . Can stream_cb be applied to DASH application ? If yes, we would like to have a trial provided that the decoder can be paused before underflow happened and it can resume to work after we feed mpv with new segments. Regards !

@ghost
Copy link
Author

ghost commented Oct 8, 2019

Yes, you could emulate DASH by using stream_cb and feeding it a concatenation of all segments (with the init segment as first thing). I think that's exactly what tmm1 does. You can block in the stream_cb read callback, then the player will pause and wait until there's more data available again as configured with https://mpv.io/manual/master/#options-cache-pause-wait . Though currently, it doesn't wait until the decoder/output has finished playing data buffered in these stages. Could be corrected I guess.

@tmm1
Copy link
Contributor

tmm1 commented Oct 8, 2019

One tricky thing that our solution is not good at handling: sometimes HLS and DASH will split out audio and video into separate segments. These would need to be merged back together before feeding to stream_cb/avformat-mpegts

@ghost
Copy link
Author

ghost commented Oct 8, 2019

You could use this: https://github.com/mpv-player/mpv/blob/master/DOCS/edl-mpv.rst#separate-files-for-tracks
Though it's a feature that could disappear any time.

@ghost
Copy link
Author

ghost commented Oct 12, 2019

(Turns out nobody uses HTTP2 for media delivery. They all just create multiple TCP connections go get around HTTP1.1 inability to multiplex/pipeline well.)

@AstralStorm
Copy link

AstralStorm commented May 2, 2020

Current hack using youtube-dl cannot work with DASH or HLS seeking for live streams.
HLS seeking is supported in Streamlink (hls-live-restream), but DASH is not due to internal structuring reasons.

mpv could be the first player that can properly seek those streams... A lot of work I bet. Perhaps libdash can be used for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
meta:help-wanted Anyone is invited to help with this. Suitable for new developers with no experience with mpv code. meta:rfc
Projects
None yet
Development

No branches or pull requests

4 participants