|
| 1 | +- Feature Name: renditions_list |
| 2 | +- Start Date: 2023-04-06 |
| 3 | +- PR: (leave this empty) |
| 4 | + |
| 5 | +# Summary |
| 6 | +[summary]: #summary |
| 7 | + |
| 8 | +This proposal introduces an addition to existing APIs to be able to control the quality level for currently playing HTTP Adaptive Streaming (HAS) video. |
| 9 | + |
| 10 | +# Motivation |
| 11 | +[motivation]: #motivation |
| 12 | + |
| 13 | +With the prevalence of segment media formats like HLS and DASH, playback uses Adaptive bitrate (ABR) algorithms to choose the reasonable quality for the user based on things like network conditions. However, users often want more control over the quality that of the stream that they are watching. For example, to force a high quality rendition for playback when watching a movie or a screen recording. |
| 14 | + |
| 15 | +This proposal provides the mechanism to be able to see what are the available renditions associated with the media that is being played and change the current selection. |
| 16 | + |
| 17 | +## Goals |
| 18 | +- Introduce an API that returns available renditions and allows selecting which renditions are used. |
| 19 | +- Take inspiration from existing `TrackList`s. |
| 20 | +- Support streams that can be interoperable via CTA-WAVE's [CTA-5005][]'s specification. |
| 21 | + |
| 22 | +## Non-Goals |
| 23 | +- Provide a comprehensive support for all potential valid segmented streams with multi-period and discontinuity support. |
| 24 | +- The API isn't intended to provide all potentially available information on the renditions. |
| 25 | +- Provide a renditions list for AudioTracks |
| 26 | + |
| 27 | +# Guide-level Explanation |
| 28 | +[guide-level-explanation]: #guide-level-explanation |
| 29 | + |
| 30 | +The main addition in this proposal is a `VideoRenditionList` which augments the [`VideoTrack`](https://html.spec.whatwg.org/multipage/media.html#videotrack) object API. This `VideoRenditionList` is a list of `VideoRendition`s which include the minimum set of information that's request by HAS formats. In addition, it includes a way to turn each individual rendition on and off. |
| 31 | + |
| 32 | +For example, if I wanted to limit a video to only play back SD content, I can loop through the `VideoRenditionList`, and enable only the renditions that have a height less than 720. |
| 33 | + |
| 34 | +```js |
| 35 | +// assuming a video is already loaded |
| 36 | +const video = document.querySelector('video'); |
| 37 | + |
| 38 | +const videoTrack = video.videoTracks[0]; |
| 39 | +const videoRenditions = videoTrack.renditions; |
| 40 | + |
| 41 | +// only keep renditions enabled that are of height less than or requal to 720 |
| 42 | +Array.from(videoRenditions).forEach(rendition => { |
| 43 | + rendition.enabled = rendition.height <= 720; |
| 44 | +}); |
| 45 | +``` |
| 46 | + |
| 47 | +To change the selected rendition, you can set the `selectedIndex` on the renditions list. |
| 48 | +```js |
| 49 | +// assuming a video is already loaded |
| 50 | +const video = document.querySelector('video'); |
| 51 | + |
| 52 | +const videoTrack = video.videoTracks[0]; |
| 53 | +const videoRenditions = videoTrack.renditions; |
| 54 | + |
| 55 | +// switch to the 3rd rendition |
| 56 | +videoRenditions.selectedIndex = 2; |
| 57 | +``` |
| 58 | + |
| 59 | +Changing the `selectedIndex` manually will trigger a `change` event on the renditions list. The ABR algorithm changing the selected rendition should also trigger a `change` event on the list object. |
| 60 | + |
| 61 | +# Reference-level explanation |
| 62 | +[reference-level-explanation]: #reference-level-explanation |
| 63 | + |
| 64 | +Below is WebIDL definitions for the changes and some explanation around it. |
| 65 | + |
| 66 | +```ts |
| 67 | +partial interface VideoTrack { |
| 68 | + readonly attribute VideoRenditionList renditions; |
| 69 | +}; |
| 70 | +``` |
| 71 | + |
| 72 | +`VideoRenditionList` is similar to [`VideoTrackList`](https://html.spec.whatwg.org/multipage/media.html#videotracklist). |
| 73 | +The main difference aside from naming is the addition of a read-write `selectedIndex` property. |
| 74 | +This value will default to `-1` when no rendition is selected, such as before metadata has loaded. |
| 75 | +Otherwise, it will reflect the index of the currently selected rendition. |
| 76 | +Setting the value to a number will request a rendition change to that rendition. |
| 77 | + |
| 78 | +When the rendition changes, either via manually setting the `selectedIndex`, or automatically via the ABR algorithm, a `change` event should be triggered. |
| 79 | + |
| 80 | +```ts |
| 81 | +interface VideoRenditionList : EventTarget { |
| 82 | + readonly attribute unsigned long length; |
| 83 | + getter VideoRendition (unsigned long index); |
| 84 | + VideoRendition? getRenditionById(DOMString id); |
| 85 | + attribute long selectedIndex; |
| 86 | + |
| 87 | + attribute EventHandler onchange; |
| 88 | + attribute EventHandler onaddrendition; |
| 89 | + attribute EventHandler onremoverendition; |
| 90 | +}; |
| 91 | +``` |
| 92 | +
|
| 93 | +Then each `VideoRendition` is includes some metadata on the rendition, like width, height, bitrate, and codec. |
| 94 | +It also includes a boolean to determine whether this rendition is enabled or not. |
| 95 | +This allowed the ABR algorithms to know whether they should be able to switch to this rendition or not. |
| 96 | +
|
| 97 | +If the currently active rendition is disabled, it should request a rendition change. |
| 98 | +
|
| 99 | +```ts |
| 100 | +interface VideoRendition { |
| 101 | + readonly attribute DOMString id; |
| 102 | + readonly attribute unsigned long width; |
| 103 | + readonly attribute unsigned long height; |
| 104 | + readonly attribute unsigned long bitrate; |
| 105 | + readonly attribute unsigned long frameRate; |
| 106 | + readonly attribute unsigned long codec; |
| 107 | + attribute boolean enabled; |
| 108 | +}; |
| 109 | +``` |
| 110 | +
|
| 111 | +# Drawbacks |
| 112 | +[drawbacks]: #drawbacks |
| 113 | +
|
| 114 | +The main drawbacks to the above proposal is that to implement this in userland makes it a lot harder since we're extending built-in pieces of HTML. However, since one of the goals of these proposals is to eventually land in the HTML spec, this is worth doing because the API would be more likely to stay the same if that happens. |
| 115 | +
|
| 116 | +# Rationale and alternatives |
| 117 | +[rationale-and-alternatives]: #rationale-and-alternatives |
| 118 | +
|
| 119 | +Some of the APIs for this mentioned in the Prior Art section are either overly complex or too simple to allow the flexibility mentioned above. |
| 120 | +For example, we want to be able to turn off individual renditions and have the underlying engine then only switch between these renditions. |
| 121 | +
|
| 122 | +# Prior art |
| 123 | +[prior-art]: #prior-art |
| 124 | +
|
| 125 | +Most web-based players that play back HAS have some kind of API to control renditions. |
| 126 | +
|
| 127 | +## Existing APIs in Web Players |
| 128 | +
|
| 129 | +### Video.js's videojs-contrib-quality-levels |
| 130 | +
|
| 131 | +Video.js has [videojs-contrib-quality-levels][]. It's a simple API that was designed to be augmented into a proposal like this. Here, each quality level is represented like so: |
| 132 | +``` |
| 133 | +Representation { |
| 134 | + id: string, |
| 135 | + width: number, |
| 136 | + height: number, |
| 137 | + bitrate: number, |
| 138 | + frameRate: number, |
| 139 | + enabled: boolean |
| 140 | +} |
| 141 | +``` |
| 142 | +`frameRate` is a recent addition. |
| 143 | +
|
| 144 | +In this API, each level can be separately enabled or disabled via the enabled getter and setter. |
| 145 | +
|
| 146 | +### Hls.js's Quality switch Control API |
| 147 | +
|
| 148 | +Hls.js has their [Quality switch Control API](https://github.com/video-dev/hls.js/blob/master/docs/API.md#quality-switch-control-api). |
| 149 | +
|
| 150 | +The level object has all the details available in the manifest. It's possible to control which level is used via the `currentLevel` setter. |
| 151 | +It is only possible to set a level cap to restrict which levels are allowed to be used. If a user wishes to have a more complex level selection, they'll need to create their own ABR Controller. |
| 152 | +
|
| 153 | +### Shaka Player's Variant Tracks |
| 154 | +
|
| 155 | +Shaka Player has a [`getVariantTracks()`](https://shaka-player-demo.appspot.com/docs/api/shaka.Player.html#getVariantTracks) method that returns a list of [Tracks](https://shaka-player-demo.appspot.com/docs/api/shaka.extern.html#.Track). Each Track object includes a lot of the information available from the manifests. |
| 156 | +It is possible to select a particular variant via [`selectVariantTrack`](https://shaka-player-demo.appspot.com/docs/api/shaka.Player.html#selectVariantTrack). |
| 157 | +It's also possible to configure the player with [ABR Restrictions](https://shaka-player-demo.appspot.com/docs/api/shaka.extern.html#.Restrictions) to limit the minimum and maximum resolutions or bitrates that can be used. |
| 158 | +
|
| 159 | +It's also possible to provide your own ABR Manager for more complex configurations. |
| 160 | +
|
| 161 | +### Other players |
| 162 | +
|
| 163 | +Dash.js also has some APIs around this. |
| 164 | +
|
| 165 | +# Unresolved questions |
| 166 | +[unresolved-questions]: #unresolved-questions |
| 167 | +
|
| 168 | +- Should VideoRendition and VideoRenditionList be generic Rendition and RenditionList to allow for usage with AudioTracks in the future? |
| 169 | +- Is there anything here that would be affected and need to be changed once AudioRenditions are added? Specifically, it's possible to have different AudioRenditions depending on the selected VideoRendition. |
| 170 | +
|
| 171 | +[CTA-5005]: https://cdn.cta.tech/cta/media/media/resources/standards/pdfs/cta-5005-final.pdf |
| 172 | +[videojs-contrib-quality-levels]: https://github.com/videojs/videojs-contrib-quality-levels |
0 commit comments