videojs / http-streaming

HLS, DASH, and future HTTP streaming protocols library for video.js
https://videojs-http-streaming.netlify.app/
Other
2.46k stars 420 forks source link

ABR logic is selecting low-quality stream in good network conditions #1203

Closed evanfarina closed 2 years ago

evanfarina commented 2 years ago

Description

This stream switches to a low-quality rendition regardless of network quality or screen size. The issue is noticeable at various points. One such point is the 18 minute mark.

I debugged the stream a bit and found that the rendition is changing because the bandwidth of the next stream is < than bandwidth of the current stream: "allowing switch 4-QualityLevels(2200000)/Manifest(video,format=m3u8-aapl,filter=L565ee88caebac2b000-default-filter) -> 3-QualityLevels(1350000)/Manifest(video,format=m3u8-aapl,filter=L565ee88caebac2b000-default-filter) as next bandwidth < current bandwidth (1526836 < 2395536)". The check/request to switch media originates from the setupSegmentLoaderListeners_ method, which listens for the bandwidthupdate event. Anecdotally, it seems like this event is fired more frequently in this stream than in streams without the described issue. Furthermore, I found that enabling experimentalBufferBasedABR fixes the symptom of this issue (low-quality selected) because it causes the media-switching logic in setupSegmentLoaderListeners_ to be avoided altogether. Is this option stable for production use?

Sources

https://livectorprodmedia18-usct.licdn.com/29f102e1-c910-4752-8076-875489231a59/L565ee88caebac2b000-livemanifest.ism/manifest(format=m3u8-aapl)

Steps to reproduce

Explain in detail the exact steps necessary to reproduce the issue.

  1. Click on the above test-case URL
  2. Seek to 17:45 in the stream
  3. Let the stream play uninterrupted from 17:45 to 18:15. Around the 18:00 mark, you will notice the stream looks blurry and a low-quality rendition has been selected

Results

Expected

The stream should not go blurry and the high-quality rendition should be selected (assuming a strong network connection & standard screen size)

Error output

If there are any errors in the console, from the player, or anywhere else please include them here:

Additional Information

Player stats, taken from the demo page:

{ "bandwidth": 3724136, "resolution": { "width": 1280, "height": 720 }, "codecs": "avc1.64001f,mp4a.40.5", "byteLength": 78584, "uri": "https://livectorprodmedia18-usct.licdn.com/29f102e1-c910-4752-8076-875489231a59/L565ee88caebac2b000-livemanifest.ism/QualityLevels(3500000)/Fragments(video=98826030,format=m3u8-aapl)", "timeline": 0, "playlist": "5-QualityLevels(3500000)/Manifest(video,format=m3u8-aapl,filter=L565ee88caebac2b000-default-filter)", "start": 1098, "end": 1100.001 }

videojs-http-streaming version

I am testing with the latest release of http-streaming

videojs version

what version of videojs does this occur with? video.js x.y.z

Browsers

what browsers are affected? please include browser and version for each

Platforms

what platforms are affected? please include operating system and version or device and version for each *

Other Plugins

are any other videojs plugins being used on the page? If so, please list them with version below.

Other JavaScript

are you using any other javascript libraries or frameworks on the page? if so please list them below.

evanfarina commented 2 years ago

The issue appears to be resolved, providing more details below.

Background: To understand the issue, it's helpful to understand how the player chooses which video quality to show to the user. The player will select a video quality based on two factors: 1) the user’s network strength (measured by bandwidth) and 2) the resolution of the screen. This issue is caused by #1, how video.js estimates the user's bandwidth.

Details: Video.js estimates available bandwidth by measuring how much video data was downloaded and in how much time it was downloaded. It’s important to note that there is a minimum network overhead involved in downloading a segment. For simplicity's sake, let’s assume that this overhead is 1 second regardless of segment size. In this example, a segment that measures 1k bits would result in an estimated bandwidth of 1k bits / second whereas a segment that measures 1 bit would result in an estimated bandwidth of 1 bit/second. The point is that, given a constant network overhead, the estimated bandwidth is directly related to the size of the segment. The size of a segment is primarily impacted by two things: 1) The length, in seconds, of the segment (we use two-second segments for live streams, six-second segments for VOD) and 2) The bitrate used to encode the segment. I’ve found that this issue is caused by a combination of these two things (a small segment, and a relatively low bitrate measured in a particular segment). For those wondering why there may be bitrate variance between segments, it’s because a scene with a complicated background and moving parts requires more data than one with a static image (thanks @Yurong for the explanation). As the player comes across a segment with a low bitrate, it determines that the user has low bandwidth and decides to downgrade the video quality to maintain a healthy buffer.

Path forward:

http-streaming now provides an option called experimentalBufferBasedABR which basically keeps a running average of the estimated bandwidth and uses that value to determine which video quality to display rather than relying on a single data point as it does now. I've found that enabling this option resolves the quality issues.