mpv-player / mpv

🎥 Command line video player
https://mpv.io
Other
28.02k stars 2.88k forks source link

Super high traffic usage when playing specific YouTube live stream #14360

Open Bakudankun opened 3 months ago

Bakudankun commented 3 months ago

mpv Information

mpv 0.38.0 Copyright © 2000-2024 mpv/MPlayer/mplayer2 projects
 built on Apr 20 2024 00:22:40
libplacebo version: v7.349.0 (v6.338.0-124-gd0eb997-dirty)
FFmpeg version: N-114897-gbba996d6c
FFmpeg library versions:
   libavutil       59.15.100
   libavcodec      61.5.103
   libavformat     61.3.100
   libswscale      8.2.100
   libavfilter     10.2.101
   libswresample   5.2.100

Other Information

Reproduction Steps

  1. Open Windows Resource Monitor to see network usage
  2. mpv https://www.youtube.com/watch?v=thYDM-UAMKg
  3. Wait a minute to see its traffic

Note: The stream lasts long but not permanent. In a few weeks, there may be no way to reproduce.

Expected Behavior

When played from a web browser e.g. chrome, its network usage is about 300KB per second (1080p).

with chrome

Actual Behavior

The stream is played successfully, but mpv downloads over 6MB per second (not 6 megabits, it's 6 megabytes per second).

with mpv

As far as I've tested, other streams do not have similar problem.

Log File

output.txt

Sample Files

No response

I carefully read all instruction and confirm that I did the following:

po5 commented 3 months ago

Use --ytdl-format. Default downloads the highest quality formats.

Bakudankun commented 3 months ago

@po5 Even playing lowest resolution video (144p) downloads about 3MB per second. Again, playing the stream at the highest quality (1080p) with Chrome only downloads around 300KB per second.

kasper93 commented 3 months ago

What is the problem exactly? I smell XY here...

Depending on your mpv cache options it will cache/download data as fast as possible, until the cache is filled.

It won't download more data than is needed for the playback, it will do it faster and stop the transfer quicker.

Bakudankun commented 3 months ago

@kasper93 No, this is mpv problem. Please read my report carefully. I beleave you can test on your side. Resource Monitor shows average traffic for a minute. That means mpv downloads 360MB per minute to play a stream which is less than 3Mbps. Is it expected behavior? If so, what is the extra 340MB? --no-cache does not solve the problem.

Bakudankun commented 3 months ago

You may not have noticed that is a live stream, so mpv starts playing from the current time. There is no such amount of data to cache. Or, does mpv cache the future?

kasper93 commented 3 months ago

You simply cannot take current average speed per second and extrapolate it to whatever duration you want. Note that resource monitor averages the values too.

Download https://learn.microsoft.com/en-us/sysinternals/downloads/process-explorer double click on mpv.exe and observe network tab. It will show you cumulative data received.

Bakudankun commented 3 months ago

@kasper93 I checked with procexp and saw the Receive Bytes increasing at a similar rate order (about 250MB per minute). Can't you reproduce the problem? What information is missing?

kasper93 commented 3 months ago

Feel free to report it to ffmpeg if there is a problem there, mpv doesn't control downloading rate/data.

Bakudankun commented 3 months ago

@kasper93 yt-dlp also utilizes ffmpeg, but it downloads in a reasonable rate.

I noticed that #EXT-X-PROGRAM-DATE-TIME in the mpv's log (in verbose mode) is 1 hour past from the current date & time. When I fed ffmpeg the .m3u8 URL which mpv showed, the #EXT-X-PROGRAM-DATE-TIME in its log was also 1 hour past, and ffmpeg also loaded a few megabytes per second. With yt-dlp, it was exact current date & time. With the .m3u8 which yt-dlp showed, ffmpeg also showed current time and load in reasonable rate (a few hundred kilobytes per second).

Maybe mpv loads the stream from the past 1 hour? How to let mpv to load the stream from current time?

na-na-hi commented 3 months ago

yt-dlp also utilizes ffmpeg, but it downloads in a reasonable rate.

yt-dlp only uses ffmpeg for muxing, not for networking. mpv uses ffmpeg for networking, and the issue is also reproducible with ffplay, so it's ffmpeg's HLS stream handling at fault.

(Side note: ffmpeg is bad at stream handling in general, especially HLS, and there are various bugs associated with it. VLC handles the link in the OP correctly without high traffic usage because it uses its own network layer. IMO mpv should also do the same, but for now you have to report the issue to ffmpeg.)

Bakudankun commented 3 months ago

Comparing both .m3u8 URLs, I noticed that mpv's URL has /playlist_type/DVR/ part while yt-dlp's has /playlist_type/LIVE/. DVR on YouTube means the feature to rewind the stream. That may make mpv to load the live from the past.

Seeing the output of yt-dlp --dump-single-json, LIVE formats seem to have both video and audio. So, I ran mpv with --ytdl-format=best (which specifies the best format with both video and audio), and now mpv's traffic is under 500KB/sec !

Why don't you make this behavior default? Is this still ffmpeg's problem??

Anyway, this problem has been solved on my end. Thank you for your help!

Bakudankun commented 3 months ago

Why don't you make this behavior default?

Well, when playing other streams, there is no problem about download rate even when .m3u8 URL contains DVR part. That may not always problematic. Please forget my suggestion.

na-na-hi commented 3 months ago

Why don't you make this behavior default?

--ytdl-format=best only selects a single format with both video and audio. For most videos this is only 720p30. It "works" for livestreams only because it selects a format from WEB which has both video and audio which doesn't trigger the ffmpeg bug. The default is to combine multiple formats with best video and audio from IOS.

Is this still ffmpeg's problem?

There is no reason why ffmpeg can't handle the mentioned stream properly.

kasper93 commented 3 months ago

There is no reason why ffmpeg can't handle the mentioned stream properly.

I think we should keep this issue open for visibility.

yt-dlp also utilizes ffmpeg, but it downloads in a reasonable rate.

Like already said by na-na-hi, only for muxing. It would indeed be nice to improve that. I will reopen in case anyone wants to work on the improvments, either in ffmpeg or directly in mpv.

MoSal commented 3 months ago

This is very interesting since similar behavior showed up in my own stream grabber.

Current HLS versions (might be still a draft) support DASH-style variable substitution, so this problem may go away in the future, but not anytime soon.

MoSal commented 3 months ago

I don't know why I didn't think of this yesterday, but here is a work-around:

--stream-lavf-o='http_seekable=0,headers=accept-encoding:gzip'

This makes use of the fact that HLS playlists are highly-compressible. http_seekable=0 is needed because, without it, ffmpeg includes a Range: bytes=0- request header which causes the server to send a non-compressed reply.

kasper93 commented 3 months ago

This should really be fixed on ffmpeg side or it cannot be used for modern content delivery services.

It is known issue for years: https://trac.ffmpeg.org/ticket/7158 Also ffmpeg supports only gzip.

MoSal commented 3 months ago

@kasper93

To be fair to ffmpeg, this is an unusual situation where the total duration of a live playlist is big, and the segment duration is small.

A segment duration of 5 seconds would reduce the overhead by ~25x, since you would have 1/5x of the segments in the playlist, and you would need to update the playlist 1/5x as frequently.

And a good client should allow controlling the frequency of playlist updates.

In my stream grabber, I already have a --playlist-req-freq=[0.1-1.0] option which is implemented like this:

    let playlist_req_freq = ctx.config.playlist_req_freq;
    let seg_avg_low_dur = (segs_dur / segs_count + min_seg_dur) / 2.0;

    // playlist_req_freq=0.1 => delay = seg_avg_low_dur*5
    // playlist_req_freq=0.5 => delay = seg_avg_low_dur
    // playlist_req_freq=1.0 => delay = seg_avg_low_dur*0.5
    let delay = seg_avg_low_dur / playlist_req_freq / 2.0;
    let delay = delay
        // in case the playlist is small (< 5 segments)
        .min(seg_avg_low_dur*segs_count)
        .max(1.0);

I thought this was enough, but in this use-case, the least frequent update period would still be 5 seconds. Better can be done, with taking the number of segments in the playlist into account.

As I already mentioned, variable substitution would help here too. So the problem may fix itself in X years :smiling_face_with_tear:.

GunGunGun commented 2 months ago

VLC handles the link in the OP correctly without high traffic usage because it uses its own network layer. IMO mpv should also do the same, but for now you have to report the issue to ffmpeg.)

Honestly I think mpv relies too much on ffmpeg, we should just reuse VLC code for HLS instead of waiting for ffmpeg to fix, they're super slow to improve nowadays.

We should only use ffmpeg or muxing and should recreate our own network layer, because it'll also making debugging network issues easier.

Current HLS versions (might be still a draft) support DASH-style variable substitution, so this problem may go away in the future, but not anytime soon.

This is pretty good to know, are we implementing our owns ?

llyyr commented 2 months ago

We should only use ffmpeg or muxing and should recreate our own network layer, because it'll also making debugging network issues easier.

Patches welcome

MoSal commented 2 months ago

Current HLS versions (might be still a draft) support DASH-style variable substitution, so this problem may go away in the future, but not anytime soon.

This is pretty good to know, are we implementing our owns ?

That would only be helpful if we are Google. YouTube Google to be more specific. If we are Chromium Google or ExoPlayer Google, we already implemented this.