UNPKG

41.2 kBMarkdownView Raw
1<img width=300 src="./logo.svg" alt="VHS Logo consisting of a VHS tape, the Video.js logo and the words VHS" />
2
3# videojs-http-streaming (VHS)
4
5[![Build Status][travis-icon]][travis-link]
6[![Slack Status][slack-icon]][slack-link]
7[![Greenkeeper badge][greenkeeper-icon]][greenkeeper-link]
8
9Play HLS, DASH, and future HTTP streaming protocols with video.js, even where they're not
10natively supported.
11
12Included in video.js 7 by default! See the [video.js 7 blog post](https://blog.videojs.com/video-js-7-is-here/)
13
14Maintenance Status: Stable
15
16Video.js Compatibility: 6.0, 7.0
17
18<!-- START doctoc generated TOC please keep comment here to allow auto update -->
19<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
20
21- [Installation](#installation)
22 - [NPM](#npm)
23 - [CDN](#cdn)
24 - [Releases](#releases)
25 - [Manual Build](#manual-build)
26- [Contributing](#contributing)
27- [Troubleshooting](#troubleshooting)
28- [Talk to us](#talk-to-us)
29- [Getting Started](#getting-started)
30- [Compatibility](#compatibility)
31 - [Browsers which support MSE](#browsers-which-support-mse)
32 - [Native only](#native-only)
33 - [Flash Support](#flash-support)
34 - [DRM](#drm)
35- [Documentation](#documentation)
36 - [Options](#options)
37 - [How to use](#how-to-use)
38 - [Initialization](#initialization)
39 - [Source](#source)
40 - [List](#list)
41 - [withCredentials](#withcredentials)
42 - [handleManifestRedirects](#handlemanifestredirects)
43 - [useCueTags](#usecuetags)
44 - [parse708captions](#parse708captions)
45 - [overrideNative](#overridenative)
46 - [blacklistDuration](#blacklistduration)
47 - [maxPlaylistRetries](#maxplaylistretries)
48 - [bandwidth](#bandwidth)
49 - [useBandwidthFromLocalStorage](#usebandwidthfromlocalstorage)
50 - [enableLowInitialPlaylist](#enablelowinitialplaylist)
51 - [limitRenditionByPlayerDimensions](#limitrenditionbyplayerdimensions)
52 - [useDevicePixelRatio](#usedevicepixelratio)
53 - [smoothQualityChange](#smoothqualitychange)
54 - [allowSeeksWithinUnsafeLiveWindow](#allowseekswithinunsafelivewindow)
55 - [customTagParsers](#customtagparsers)
56 - [customTagMappers](#customtagmappers)
57 - [cacheEncryptionKeys](#cacheencryptionkeys)
58 - [handlePartialData](#handlepartialdata)
59 - [liveRangeSafeTimeDelta](#liverangesafetimedelta)
60 - [useNetworkInformationApi](#usenetworkinformationapi)
61 - [useDtsForTimestampOffset](#usedtsfortimestampoffset)
62 - [captionServices](#captionservices)
63 - [Format](#format)
64 - [Example](#example)
65 - [Runtime Properties](#runtime-properties)
66 - [vhs.playlists.master](#vhsplaylistsmaster)
67 - [vhs.playlists.media](#vhsplaylistsmedia)
68 - [vhs.systemBandwidth](#vhssystembandwidth)
69 - [vhs.bandwidth](#vhsbandwidth)
70 - [vhs.throughput](#vhsthroughput)
71 - [vhs.selectPlaylist](#vhsselectplaylist)
72 - [vhs.representations](#vhsrepresentations)
73 - [vhs.xhr](#vhsxhr)
74 - [vhs.stats](#vhsstats)
75 - [Events](#events)
76 - [loadedmetadata](#loadedmetadata)
77 - [VHS Usage Events](#vhs-usage-events)
78 - [Presence Stats](#presence-stats)
79 - [Use Stats](#use-stats)
80 - [In-Band Metadata](#in-band-metadata)
81 - [Segment Metadata](#segment-metadata)
82 - [Object as Source](#object-as-source)
83- [Hosting Considerations](#hosting-considerations)
84- [Known Issues and Workarounds](#known-issues-and-workarounds)
85 - [Fragmented MP4 Support](#fragmented-mp4-support)
86 - [Assets with an Audio-Only Rate Get Stuck in Audio-Only](#assets-with-an-audio-only-rate-get-stuck-in-audio-only)
87 - [DASH Assets with `$Time` Interpolation and `SegmentTimeline`s with No `t`](#dash-assets-with-time-interpolation-and-segmenttimelines-with-no-t)
88- [Testing](#testing)
89- [Debugging](#debugging)
90- [Release History](#release-history)
91- [Building](#building)
92- [Development](#development)
93 - [Tools](#tools)
94 - [Commands](#commands)
95
96<!-- END doctoc generated TOC please keep comment here to allow auto update -->
97
98## Installation
99### NPM
100To install `videojs-http-streaming` with npm run
101
102```bash
103npm install --save @videojs/http-streaming
104```
105
106### CDN
107Select a version of VHS from the [CDN](https://unpkg.com/@videojs/http-streaming/dist/)
108
109### Releases
110Download a release of [videojs-http-streaming](https://github.com/videojs/http-streaming/releases)
111
112### Manual Build
113Download a copy of this git repository and then follow the steps in [Building](#building)
114
115## Contributing
116See [CONTRIBUTING.md](/CONTRIBUTING.md)
117
118## Troubleshooting
119See [our troubleshooting guide](/docs/troubleshooting.md)
120
121## Talk to us
122Drop by our slack channel (#playback) on the [Video.js slack][slack-link].
123
124## Getting Started
125This library is included in video.js 7 by default, if you are using an older version of video.js then
126get a copy of [videojs-http-streaming](#installation) and include it in your page along with video.js:
127
128```html
129<video-js id=vid1 width=600 height=300 class="vjs-default-skin" controls>
130 <source
131 src="https://example.com/index.m3u8"
132 type="application/x-mpegURL">
133</video-js>
134<script src="video.js"></script>
135<script src="videojs-http-streaming.min.js"></script>
136<script>
137var player = videojs('vid1');
138player.play();
139</script>
140```
141
142Check out our [live example](https://jsbin.com/gejugat/edit?html,output) if you're having trouble.
143
144Is it recommended to use the `<video-js>` element or load a source with `player.src(sourceObject)` in order to prevent the video element from playing the source natively where HLS is supported.
145
146## Compatibility
147
148The [Media Source Extensions](http://caniuse.com/#feat=mediasource) API is required for http-streaming to play HLS or MPEG-DASH.
149
150### Browsers which support MSE
151
152- Chrome
153- Firefox
154- Internet Explorer 11 Windows 10 or 8.1
155
156These browsers have some level of native HLS support, which will be used unless the [overrideNative](#overridenative) option is used:
157
158- Chrome Android
159- Firefox Android
160- Edge
161
162### Native only
163
164- Mac Safari
165- iOS Safari
166
167Mac Safari does have MSE support, but native HLS is recommended
168
169### Flash Support
170This plugin does not support Flash playback. Instead, it is recommended that users use the [videojs-flashls-source-handler](https://github.com/brightcove/videojs-flashls-source-handler) plugin as a fallback option for browsers that don't have a native
171[HLS](https://caniuse.com/#feat=http-live-streaming)/[DASH](https://caniuse.com/#feat=mpeg-dash) player or support for [Media Source Extensions](http://caniuse.com/#feat=mediasource).
172
173### DRM
174
175DRM is supported through [videojs-contrib-eme](https://github.com/videojs/videojs-contrib-eme). In order to use DRM, include the videojs-contrib-eme plug, [initialize it](https://github.com/videojs/videojs-contrib-eme#initialization), and add options to either the [plugin](https://github.com/videojs/videojs-contrib-eme#plugin-options) or the [source](https://github.com/videojs/videojs-contrib-eme#source-options).
176
177Detailed option information can be found in the [videojs-contrib-eme README](https://github.com/videojs/videojs-contrib-eme/blob/master/README.md).
178
179## Documentation
180[HTTP Live Streaming](https://developer.apple.com/streaming/) (HLS) has
181become a de-facto standard for streaming video on mobile devices
182thanks to its native support on iOS and Android. There are a number of
183reasons independent of platform to recommend the format, though:
184
185- Supports (client-driven) adaptive bitrate selection
186- Delivered over standard HTTP ports
187- Simple, text-based manifest format
188- No proprietary streaming servers required
189
190Unfortunately, all the major desktop browsers except for Safari are
191missing HLS support. That leaves web developers in the unfortunate
192position of having to maintain alternate renditions of the same video
193and potentially having to forego HTML-based video entirely to provide
194the best desktop viewing experience.
195
196This project addresses that situation by providing a polyfill for HLS
197on browsers that have support for [Media Source
198Extensions](http://caniuse.com/#feat=mediasource).
199You can deploy a single HLS stream, code against the
200regular HTML5 video APIs, and create a fast, high-quality video
201experience across all the big web device categories.
202
203Check out the [full documentation](docs/README.md) for details on how HLS works
204and advanced configuration. A description of the [adaptive switching
205behavior](docs/bitrate-switching.md) is available, too.
206
207videojs-http-streaming supports a bunch of HLS features. Here
208are some highlights:
209
210- video-on-demand and live playback modes
211- backup or redundant streams
212- mid-segment quality switching
213- AES-128 segment encryption
214- CEA-608 captions are automatically translated into standard HTML5
215 [caption text tracks][0]
216- In-Manifest WebVTT subtitles are automatically translated into standard HTML5
217 subtitle tracks
218- Timed ID3 Metadata is automatically translated into HTML5 metedata
219 text tracks
220- Highly customizable adaptive bitrate selection
221- Automatic bandwidth tracking
222- Cross-domain credentials support with CORS
223- Tight integration with video.js and a philosophy of exposing as much
224 as possible with standard HTML APIs
225- Stream with multiple audio tracks and switching to those audio tracks
226 (see the docs folder) for info
227- Media content in
228 [fragmented MP4s](https://developer.apple.com/videos/play/wwdc2016/504/)
229 instead of the MPEG2-TS container format.
230
231[0]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/track
232
233For a more complete list of supported and missing features, refer to
234[this doc](docs/supported-features.md).
235
236### Options
237#### How to use
238
239##### Initialization
240You may pass in an options object to the hls source handler at player
241initialization. You can pass in options just like you would for other
242parts of video.js:
243
244```javascript
245// html5 for html hls
246videojs(video, {
247 html5: {
248 vhs: {
249 withCredentials: true
250 }
251 }
252});
253```
254
255##### Source
256Some options, such as `withCredentials` can be passed in to vhs during
257`player.src`
258
259```javascript
260
261var player = videojs('some-video-id');
262
263player.src({
264 src: 'https://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/bipbop_16x9_variant.m3u8',
265 type: 'application/x-mpegURL',
266 withCredentials: true
267});
268```
269
270#### List
271##### withCredentials
272* Type: `boolean`
273* can be used as a source option
274* can be used as an initialization option
275
276When the `withCredentials` property is set to `true`, all XHR requests for
277manifests and segments would have `withCredentials` set to `true` as well. This
278enables storing and passing cookies from the server that the manifests and
279segments live on. This has some implications on CORS because when set, the
280`Access-Control-Allow-Origin` header cannot be set to `*`, also, the response
281headers require the addition of `Access-Control-Allow-Credentials` header which
282is set to `true`.
283See html5rocks's [article](http://www.html5rocks.com/en/tutorials/cors/)
284for more info.
285
286##### handleManifestRedirects
287* Type: `boolean`
288* Default: `false`
289* can be used as a source option
290* can be used as an initialization option
291
292When the `handleManifestRedirects` property is set to `true`, manifest requests
293which are redirected will have their URL updated to the new URL for future
294requests.
295
296##### useCueTags
297* Type: `boolean`
298* can be used as an initialization option
299
300When the `useCueTags` property is set to `true,` a text track is created with
301label 'ad-cues' and kind 'metadata'. The track is then added to
302`player.textTracks()`. Changes in active cue may be
303tracked by following the Video.js cue points API for text tracks. For example:
304
305```javascript
306let textTracks = player.textTracks();
307let cuesTrack;
308
309for (let i = 0; i < textTracks.length; i++) {
310  if (textTracks[i].label === 'ad-cues') {
311    cuesTrack = textTracks[i];
312  }
313}
314
315cuesTrack.addEventListener('cuechange', function() {
316 let activeCues = cuesTrack.activeCues;
317
318  for (let i = 0; i < activeCues.length; i++) {
319 let activeCue = activeCues[i];
320
321    console.log('Cue runs from ' + activeCue.startTime +
322 ' to ' + activeCue.endTime);
323  }
324});
325```
326
327##### parse708captions
328* Type: `boolean`
329* Default: `true`
330* can be used as an initialization option
331
332When set to `false`, 708 captions in the stream are not parsed and will not show up in text track lists or the captions menu.
333
334##### overrideNative
335* Type: `boolean`
336* can be used as an initialization option
337
338Try to use videojs-http-streaming even on platforms that provide some
339level of HLS support natively. There are a number of platforms that
340*technically* play back HLS content but aren't very reliable or are
341missing features like CEA-608 captions support. When `overrideNative`
342is true, if the platform supports Media Source Extensions
343videojs-http-streaming will take over HLS playback to provide a more
344consistent experience.
345
346```javascript
347// via the constructor
348var player = videojs('playerId', {
349 html5: {
350 vhs: {
351 overrideNative: true
352 },
353 nativeAudioTracks: false,
354 nativeVideoTracks: false
355 }
356});
357```
358
359Since MSE playback may be desirable on all browsers with some native support other than Safari, `overrideNative: !videojs.browser.IS_SAFARI` could be used.
360
361##### blacklistDuration
362* Type: `number`
363* can be used as an initialization option
364
365When the `blacklistDuration` property is set to a time duration in seconds,
366if a playlist is blacklisted, it will be blacklisted for a period of that
367customized duration. This enables the blacklist duration to be configured
368by the user.
369
370##### maxPlaylistRetries
371* Type: `number`
372* Default: `Infinity`
373* can be used as an initialization option
374
375The max number of times that a playlist will retry loading following an error
376before being indefinitely excluded from the rendition selection algorithm. Note: the number of retry attempts needs to _exceed_ this value before a playlist will be excluded.
377
378##### bandwidth
379* Type: `number`
380* can be used as an initialization option
381
382When the `bandwidth` property is set (bits per second), it will be used in
383the calculation for initial playlist selection, before more bandwidth
384information is seen by the player.
385
386##### useBandwidthFromLocalStorage
387* Type: `boolean`
388* can be used as an initialization option
389
390If true, `bandwidth` and `throughput` values are stored in and retrieved from local
391storage on startup (for initial rendition selection). This setting is `false` by default.
392
393##### enableLowInitialPlaylist
394* Type: `boolean`
395* can be used as an initialization option
396
397When `enableLowInitialPlaylist` is set to true, it will be used to select
398the lowest bitrate playlist initially. This helps to decrease playback start time.
399This setting is `false` by default.
400
401##### limitRenditionByPlayerDimensions
402* Type: `boolean`
403* can be used as an initialization option
404
405When `limitRenditionByPlayerDimensions` is set to true, rendition
406selection logic will take into account the player size and rendition
407resolutions when making a decision.
408This setting is `true` by default.
409
410##### useDevicePixelRatio
411* Type: `boolean`
412* can be used as an initialization option.
413
414If true, this will take the device pixel ratio into account when doing rendition switching. This means that if you have a player with the width of `540px` in a high density display with a device pixel ratio of 2, a rendition of `1080p` will be allowed.
415This setting is `false` by default.
416
417##### smoothQualityChange
418* NOTE: DEPRECATED
419* Type: `boolean`
420* can be used as a source option
421* can be used as an initialization option
422
423smoothQualityChange is deprecated and will be removed in the next major version of VHS.
424
425Instead of its prior behavior, smoothQualityChange will now call fastQualityChange, which
426clears the buffer, chooses a new rendition, and starts loading content from the current
427playhead position.
428
429##### allowSeeksWithinUnsafeLiveWindow
430* Type: `boolean`
431* can be used as a source option
432
433When `allowSeeksWithinUnsafeLiveWindow` is set to `true`, if the active playlist is live
434and a seek is made to a time between the safe live point (end of manifest minus three
435times the target duration,
436see [the hls spec](https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-6.3.3)
437for details) and the end of the playlist, the seek is allowed, rather than corrected to
438the safe live point.
439
440This option can help in instances where the live stream's target duration is greater than
441the segment durations, playback ends up in the unsafe live window, and there are gaps in
442the content. In this case the player will attempt to seek past the gaps but end up seeking
443inside of the unsafe range, leading to a correction and seek back into a previously played
444content.
445
446The property defaults to `false`.
447
448##### customTagParsers
449* Type: `Array`
450* can be used as a source option
451
452With `customTagParsers` you can pass an array of custom m3u8 tag parser objects. See https://github.com/videojs/m3u8-parser#custom-parsers
453
454##### customTagMappers
455* Type: `Array`
456* can be used as a source option
457
458Similar to `customTagParsers`, with `customTagMappers` you can pass an array of custom m3u8 tag mapper objects. See https://github.com/videojs/m3u8-parser#custom-parsers
459
460##### cacheEncryptionKeys
461* Type: `boolean`
462* can be used as a source option
463* can be used as an initialization option
464
465This option forces the player to cache AES-128 encryption keys internally instead of requesting the key alongside every segment request.
466This option defaults to `false`.
467
468##### handlePartialData
469* Type: `boolean`,
470* Default: `false`
471* Use partial appends in the transmuxer and segment loader
472
473##### liveRangeSafeTimeDelta
474* Type: `number`,
475* Default: [`SAFE_TIME_DELTA`](https://github.com/videojs/http-streaming/blob/e7cb63af010779108336eddb5c8fd138d6390e95/src/ranges.js#L17)
476* Allow to re-define length (in seconds) of time delta when you compare current time and the end of the buffered range.
477
478##### useNetworkInformationApi
479* Type: `boolean`,
480* Default: `false`
481* Use [window.networkInformation.downlink](https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/downlink) to estimate the network's bandwidth. Per mdn, _The value is never greater than 10 Mbps, as a non-standard anti-fingerprinting measure_. Given this, if bandwidth estimates from both the player and networkInfo are >= 10 Mbps, the player will use the larger of the two values as its bandwidth estimate.
482
483##### useDtsForTimestampOffset
484* Type: `boolean`,
485* Default: `false`
486* Use [Decode Timestamp](https://www.w3.org/TR/media-source/#decode-timestamp) instead of [Presentation Timestamp](https://www.w3.org/TR/media-source/#presentation-timestamp) for [timestampOffset](https://www.w3.org/TR/media-source/#dom-sourcebuffer-timestampoffset) calculation. This option was introduced to align with DTS-based browsers. This option affects only transmuxed data (eg: transport stream). For more info please check the following [issue](https://github.com/videojs/http-streaming/issues/1247).
487
488##### captionServices
489* Type: `object`
490* Default: undefined
491* Provide extra information, like a label or a language, for instream (608 and 708) captions.
492
493The captionServices options object has properties that map to the caption services. Each property is an object itself that includes several properties, like a label or language.
494
495For 608 captions, the service names are `CC1`, `CC2`, `CC3`, and `CC4`. For 708 captions, the service names are `SERVICEn` where `n` is a digit between `1` and `63`.
496
497For 708 caption services, you may additionally provide an `encoding` value that will be used by the transmuxer to decode the captions using an instance of [TextDecoder](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder). This is to permit and is required for legacy multi-byte encodings. Please review the `TextDecoder` documentation for accepted encoding labels.
498
499###### Format
500```js
501{
502 vhs: {
503 captionServices: {
504 [serviceName]: {
505 language: String, // optional
506 label: String, // optional
507 default: boolean, // optional,
508 encoding: String // optional, 708 services only
509 }
510 }
511 }
512}
513```
514###### Example
515```js
516{
517 vhs: {
518 captionServices: {
519 CC1: {
520 language: 'en',
521 label: 'English'
522 },
523 SERVICE1: {
524 langauge: 'kr',
525 label: 'Korean',
526 encoding: 'euc-kr'
527 default: true,
528 }
529 }
530 }
531}
532```
533
534### Runtime Properties
535Runtime properties are attached to the tech object when HLS is in
536use. You can get a reference to the VHS source handler like this:
537
538```javascript
539var vhs = player.tech().vhs;
540```
541
542If you *were* thinking about modifying runtime properties in a
543video.js plugin, we'd recommend you avoid it. Your plugin won't work
544with videos that don't use videojs-http-streaming and the best plugins
545work across all the media types that video.js supports. If you're
546deploying videojs-http-streaming on your own website and want to make a
547couple tweaks though, go for it!
548
549#### vhs.playlists.master
550Type: `object`
551
552An object representing the parsed master playlist. If a media playlist
553is loaded directly, a master playlist with only one entry will be
554created.
555
556#### vhs.playlists.media
557Type: `function`
558
559A function that can be used to retrieve or modify the currently active
560media playlist. The active media playlist is referred to when
561additional video data needs to be downloaded. Calling this function
562with no arguments returns the parsed playlist object for the active
563media playlist. Calling this function with a playlist object from the
564master playlist or a URI string as specified in the master playlist
565will kick off an asynchronous load of the specified media
566playlist. Once it has been retreived, it will become the active media
567playlist.
568
569#### vhs.systemBandwidth
570Type: `number`
571
572`systemBandwidth` is a combination of two serial processes' bitrates. The first
573is the network bitrate provided by `bandwidth` and the second is the bitrate of
574the entire process after that (decryption, transmuxing, and appending) provided
575by `throughput`. This value is used by the default implementation of `selectPlaylist`
576to select an appropriate bitrate to play.
577
578Since the two process are serial, the overall system bandwidth is given by:
579`systemBandwidth = 1 / (1 / bandwidth + 1 / throughput)`
580
581#### vhs.bandwidth
582Type: `number`
583
584The number of bits downloaded per second in the last segment download.
585
586Before the first video segment has been downloaded, it's hard to
587estimate bandwidth accurately. The HLS tech uses a starting value of 4194304 or 0.5 MB/s. If you
588have a more accurate source of bandwidth information, you can override
589this value as soon as the HLS tech has loaded to provide an initial
590bandwidth estimate.
591
592#### vhs.throughput
593Type: `number`
594
595The number of bits decrypted, transmuxed, and appended per second as a cumulative average across active processing time.
596
597#### vhs.selectPlaylist
598Type: `function`
599
600A function that returns the media playlist object to use to download
601the next segment. It is invoked by the tech immediately before a new
602segment is downloaded. You can override this function to provide your
603adaptive streaming logic. You must, however, be sure to return a valid
604media playlist object that is present in `player.tech().vhs.master`.
605
606Overridding this function with your own is very powerful but is overkill
607for many purposes. Most of the time, you should use the much simpler
608function below to selectively enable or disable a playlist from the
609adaptive streaming logic.
610
611#### vhs.representations
612Type: `function`
613
614It is recommended to include the [videojs-contrib-quality-levels](https://github.com/videojs/videojs-contrib-quality-levels) plugin to your page so that videojs-http-streaming will automatically populate the QualityLevelList exposed on the player by the plugin. You can access this list by calling `player.qualityLevels()`. See the [videojs-contrib-quality-levels project page](https://github.com/videojs/videojs-contrib-quality-levels) for more information on how to use the api.
615
616Example, only enabling representations with a width greater than or equal to 720:
617
618```javascript
619var qualityLevels = player.qualityLevels();
620
621for (var i = 0; i < qualityLevels.length; i++) {
622 var quality = qualityLevels[i];
623 if (quality.width >= 720) {
624 quality.enabled = true;
625 } else {
626 quality.enabled = false;
627 }
628}
629```
630
631If including [videojs-contrib-quality-levels](https://github.com/videojs/videojs-contrib-quality-levels) is not an option, you can use the representations api. To get all of the available representations, call the `representations()` method on `player.tech().vhs`. This will return a list of plain objects, each with `width`, `height`, `bandwidth`, and `id` properties, and an `enabled()` method.
632
633```javascript
634player.tech().vhs.representations();
635```
636
637To see whether the representation is enabled or disabled, call its `enabled()` method with no arguments. To set whether it is enabled/disabled, call its `enabled()` method and pass in a boolean value. Calling `<representation>.enabled(true)` will allow the adaptive bitrate algorithm to select the representation while calling `<representation>.enabled(false)` will disallow any selection of that representation.
638
639Example, only enabling representations with a width greater than or equal to 720:
640
641```javascript
642player.tech().vhs.representations().forEach(function(rep) {
643 if (rep.width >= 720) {
644 rep.enabled(true);
645 } else {
646 rep.enabled(false);
647 }
648});
649```
650
651#### vhs.xhr
652Type: `function`
653
654The xhr function that is used by HLS internally is exposed on the per-
655player `vhs` object. While it is possible, we do not recommend replacing
656the function with your own implementation. Instead, the `xhr` provides
657the ability to specify a `beforeRequest` function that will be called
658with an object containing the options that will be used to create the
659xhr request.
660
661Example:
662```javascript
663player.tech().vhs.xhr.beforeRequest = function(options) {
664 options.uri = options.uri.replace('example.com', 'foo.com');
665
666 return options;
667};
668```
669
670The global `videojs.Vhs` also exposes an `xhr` property. Specifying a
671`beforeRequest` function on that will allow you to intercept the options
672for *all* requests in every player on a page. For consistency across
673browsers the video source should be set at runtime once the video player
674is ready.
675
676Example
677```javascript
678videojs.Vhs.xhr.beforeRequest = function(options) {
679 /*
680 * Modifications to requests that will affect every player.
681 */
682
683 return options;
684};
685
686var player = videojs('video-player-id');
687player.ready(function() {
688 this.src({
689 src: 'https://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/bipbop_16x9_variant.m3u8',
690 type: 'application/x-mpegURL',
691 });
692});
693```
694
695For information on the type of options that you can modify see the
696documentation at [https://github.com/Raynos/xhr](https://github.com/Raynos/xhr).
697
698#### vhs.stats
699Type: `object`
700
701This object contains a summary of HLS and player related stats.
702
703| Property Name | Type | Description |
704| --------------------- | ------ | ----------- |
705| bandwidth | number | Rate of the last segment download in bits/second |
706| mediaRequests | number | Total number of media segment requests |
707| mediaRequestsAborted | number | Total number of aborted media segment requests |
708| mediaRequestsTimedout | number | Total number of timedout media segment requests |
709| mediaRequestsErrored | number | Total number of errored media segment requests |
710| mediaTransferDuration | number | Total time spent downloading media segments in milliseconds |
711| mediaBytesTransferred | number | Total number of content bytes downloaded |
712| mediaSecondsLoaded | number | Total number of content seconds downloaded |
713| buffered | array | List of time ranges of content that are in the SourceBuffer |
714| currentTime | number | The current position of the player |
715| currentSource | object | The source object. Has the structure `{src: 'url', type: 'mimetype'}` |
716| currentTech | string | The name of the tech in use |
717| duration | number | Duration of the video in seconds |
718| master | object | The [master playlist object](#vhsplaylistsmaster) |
719| playerDimensions | object | Contains the width and height of the player |
720| seekable | array | List of time ranges that the player can seek to |
721| timestamp | number | Timestamp of when `vhs.stats` was accessed |
722| videoPlaybackQuality | object | Media playback quality metrics as specified by the [W3C's Media Playback Quality API](https://wicg.github.io/media-playback-quality/) |
723
724
725### Events
726Standard HTML video events are handled by video.js automatically and
727are triggered on the player object.
728
729#### loadedmetadata
730
731Fired after the first segment is downloaded for a playlist. This will not happen
732until playback if video.js's `metadata` setting is `none`
733
734### VHS Usage Events
735
736Usage tracking events are fired when we detect a certain HLS feature, encoding setting,
737or API is used. These can be helpful for analytics, and to pinpoint the cause of HLS errors.
738For instance, if errors are being fired in tandem with a usage event indicating that the
739player was playing an AES encrypted stream, then we have a possible avenue to explore when
740debugging the error.
741
742Note that although these usage events are listed below, they may change at any time without
743a major version change.
744
745VHS usage events are triggered on the tech with the exception of the 3 vhs-reload-error
746events, which are triggered on the player.
747
748To listen for usage events triggered on the tech, listen for the event type of `'usage'`:
749
750```javascript
751player.on('ready', () => {
752 player.tech().on('usage', (e) => {
753 console.log(e.name);
754 });
755});
756```
757
758Note that these events are triggered as soon as a case is encountered, and often only
759once. For example, the `vhs-demuxed` usage event will be triggered as soon as the master
760manifest is downloaded and parsed, and will not be triggered again.
761
762#### Presence Stats
763
764Each of the following usage events are fired once per source if (and when) detected:
765
766| Name | Description |
767| ------------- | ------------- |
768| vhs-webvtt | master manifest has at least one segmented WebVTT playlist |
769| vhs-aes | a playlist is AES encrypted |
770| vhs-fmp4 | a playlist used fMP4 segments |
771| vhs-demuxed | audio and video are demuxed by default |
772| vhs-alternate-audio | alternate audio available in the master manifest |
773| vhs-playlist-cue-tags | a playlist used cue tags (see useCueTags(#usecuetags) for details) |
774| vhs-bandwidth-from-local-storage | starting bandwidth was retrieved from local storage (see useBandwidthFromLocalStorage(#useBandwidthFromLocalStorage) for details) |
775| vhs-throughput-from-local-storage | starting throughput was retrieved from local storage (see useBandwidthFromLocalStorage(#useBandwidthFromLocalStorage) for details) |
776
777#### Use Stats
778
779Each of the following usage events are fired per use:
780
781| Name | Description |
782| ------------- | ------------- |
783| vhs-gap-skip | player skipped a gap in the buffer |
784| vhs-player-access | player.vhs was accessed |
785| vhs-audio-change | a user selected an alternate audio stream |
786| vhs-rendition-disabled | a rendition was disabled |
787| vhs-rendition-enabled | a rendition was enabled |
788| vhs-rendition-blacklisted | a rendition was blacklisted |
789| vhs-timestamp-offset | a timestamp offset was set in HLS (can identify discontinuities) |
790| vhs-unknown-waiting | the player stopped for an unknown reason and we seeked to current time try to address it |
791| vhs-live-resync | playback fell off the back of a live playlist and we resynced to the live point |
792| vhs-video-underflow | we seeked to current time to address video underflow |
793| vhs-error-reload-initialized | the reloadSourceOnError plugin was initialized |
794| vhs-error-reload | the reloadSourceOnError plugin reloaded a source |
795| vhs-error-reload-canceled | an error occurred too soon after the last reload, so we didn't reload again (to prevent error loops) |
796
797
798### In-Band Metadata
799The HLS tech supports [timed
800metadata](https://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/HTTP_Live_Streaming_Metadata_Spec/Introduction/Introduction.html)
801embedded as [ID3 tags](http://id3.org/id3v2.3.0). When a stream is
802encountered with embedded metadata, an [in-band metadata text
803track](https://html.spec.whatwg.org/multipage/embedded-content.html#text-track-in-band-metadata-track-dispatch-type)
804will automatically be created and populated with cues as they are
805encountered in the stream. UTF-8 encoded
806[TXXX](http://id3.org/id3v2.3.0#User_defined_text_information_frame)
807and [WXXX](http://id3.org/id3v2.3.0#User_defined_URL_link_frame) ID3
808frames are mapped to cue points and their values set as the cue
809text. Cues are created for all other frame types and the data is
810attached to the generated cue:
811
812```javascript
813cue.value.data
814```
815
816There are lots of guides and references to using text tracks [around
817the web](http://www.html5rocks.com/en/tutorials/track/basics/).
818
819### Segment Metadata
820You can get metadata about the segments currently in the buffer by using the `segment-metadata`
821text track. You can get the metadata of the currently rendered segment by looking at the
822track's `activeCues` array. The metadata will be attached to the `cue.value` property and
823will have this structure
824
825```javascript
826cue.value = {
827 byteLength, // The size of the segment in bytes
828 bandwidth, // The peak bitrate reported by the segment's playlist
829 resolution, // The resolution reported by the segment's playlist
830 codecs, // The codecs reported by the segment's playlist
831 uri, // The Segment uri
832 timeline, // Timeline of the segment for detecting discontinuities
833 playlist, // The Playlist uri
834 start, // Segment start time
835 end // Segment end time
836};
837```
838
839Example:
840Detect when a change in quality is rendered on screen
841```javascript
842let tracks = player.textTracks();
843let segmentMetadataTrack;
844
845for (let i = 0; i < tracks.length; i++) {
846 if (tracks[i].label === 'segment-metadata') {
847 segmentMetadataTrack = tracks[i];
848 }
849}
850
851let previousPlaylist;
852
853if (segmentMetadataTrack) {
854 segmentMetadataTrack.on('cuechange', function() {
855 let activeCue = segmentMetadataTrack.activeCues[0];
856
857 if (activeCue) {
858 if (previousPlaylist !== activeCue.value.playlist) {
859 console.log('Switched from rendition ' + previousPlaylist +
860 ' to rendition ' + activeCue.value.playlist);
861 }
862 previousPlaylist = activeCue.value.playlist;
863 }
864 });
865}
866```
867
868### Object as Source
869
870*Note* that this is an advanced use-case, and may be more fragile for production
871environments, as the schema for a VHS object and how it's used internally are not set in
872stone and may change in future releases.
873
874In normal use, VHS accepts a URL as the source of the video. But VHS also has the ability
875to accept a JSON object as the source.
876
877Passing a JSON object as the source has many uses. A couple of examples include:
878* The manifest has already been downloaded, so there's no need to make another request
879* You want to change some aspect of the manifest, e.g., add a segment, without modifying
880 the manifest itself
881
882In order to pass a JSON object as the source, provide a parsed manifest object in via a
883[data URI](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs),
884and using the "vnd.videojs.vhs+json" media type when setting the source type. For instance:
885
886```
887var player = videojs('some-video-id');
888const parser = new M3u8Parser();
889
890parser.push(manifestString);
891parser.end();
892
893player.src({
894 src: `data:application/vnd.videojs.vhs+json,${JSON.stringify(parser.manifest)}`,
895 type: 'application/vnd.videojs.vhs+json'
896});
897```
898
899The manifest object should follow the "VHS manifest object schema" (a somewhat flexible
900and informally documented structure) provided in the README of
901[m3u8-parser](https://github.com/videojs/m3u8-parser) and
902[mpd-parser](https://github.com/videojs/mpd-parser). This may be referred to in the
903project as `vhs-json`.
904
905## Hosting Considerations
906Unlike a native HLS implementation, the HLS tech has to comply with
907the browser's security policies. That means that all the files that
908make up the stream must be served from the same domain as the page
909hosting the video player or from a server that has appropriate [CORS
910headers](https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS)
911configured. Easy [instructions are
912available](http://enable-cors.org/server.html) for popular webservers
913and most CDNs should have no trouble turning CORS on for your account.
914
915
916## Known Issues and Workarounds
917Issues that are currenty known. If you want to
918help find a solution that would be appreciated!
919
920### Fragmented MP4 Support
921Edge has native support for HLS but only in the MPEG2-TS container. If
922you attempt to play an HLS stream with fragmented MP4 segments (without
923[overriding native playback](#overridenative)), Edge will stall.
924Fragmented MP4s are only supported on browsers that have
925[Media Source Extensions](http://caniuse.com/#feat=mediasource) available.
926
927### Assets with an Audio-Only Rate Get Stuck in Audio-Only
928Some assets which have an audio-only rate and the lowest-bandwidth
929audio + video rate isn't that low get stuck in audio-only mode. This is
930because the initial bandwidth calculation thinks it there's insufficient
931bandwidth for selecting the lowest-quality audio+video playlist, so it picks
932the only-audio one, which unfortunately locks it to being audio-only forever,
933preventing a switch to the audio+video playlist when it gets a better
934estimation of bandwidth.
935
936Until we've implemented a full fix, it is recommended to set the
937[`enableLowInitialPlaylist` option](#enablelowinitialplaylist) for any assets
938that include an audio-only rate; it should always select the lowest-bandwidth
939audio+video playlist for its first playlist.
940
941It's also worth mentioning that Apple no longer requires having an audio-only
942rate; instead, they require a 192kbps audio+video rate (see Apple's current
943[HLS Authoring Specification][]). Removing the audio-only rate would of course
944eliminate this problem since there would be only audio+video playlists to
945choose from.
946
947Follow progress on this in issue [#175](https://github.com/videojs/http-streaming/issues/175).
948
949[HLS Authoring Specification]: https://developer.apple.com/documentation/http_live_streaming/hls_authoring_specification_for_apple_devices
950
951### DASH Assets with `$Time` Interpolation and `SegmentTimeline`s with No `t`
952
953DASH assets which use `$Time` in a `SegmentTemplate`, and also have a
954`SegmentTimeline` where only the first `S` has a `t` and the rest only have a
955`d`, do not load currently.
956
957There is currently no workaround for this, but you can track progress on this
958in issue [#256](https://github.com/videojs/http-streaming/issues/256).
959
960## Testing
961
962For testing, you run `npm run test`. You will need Chrome and Firefox for running the tests.
963
964_videojs-http-streaming uses [BrowserStack](https://browserstack.com) for compatibility testing._
965
966## Debugging
967
968videojs-http-streaming makes use of `videojs.log` for debug logging. You can enable these logs
969by setting the log level to `debug` using `videojs.log.level('debug')`. You can access a complete
970history of the logs using `videojs.log.history()`. This history is maintained even when the
971log level is not set to `debug`.
972
973`vhs.stats` can also be helpful when debugging. Accessing this object will give you
974a snapshot summary of various HLS and player stats. See [vhs.stats](#vhsstats) for details
975about what this object contains.
976
977__NOTE__: The `debug` level is only available in video.js v6.6.0+. With earlier versions of
978video.js, no debug messages will be logged to console.
979
980## Release History
981Check out the [changelog](CHANGELOG.md) for a summary of each release.
982
983## Building
984To build a copy of videojs-http-streaming run the following commands
985
986```bash
987git clone https://github.com/videojs/http-streaming
988cd http-streaming
989npm i
990npm run build
991```
992
993videojs-http-streaming will have created all of the files for using it in a dist folder
994
995## Development
996
997### Tools
998* Download stream locally with the [HLS Fetcher](https://github.com/videojs/hls-fetcher)
999* Simulate errors with [Murphy](https://github.com/videojs/murphy)
1000* Inspect content with [Thumbcoil](http://thumb.co.il)
1001
1002### Commands
1003All commands for development are listed in the `package.json` file and are run using
1004```bash
1005npm run <command>
1006```
1007
1008[slack-icon]: http://slack.videojs.com/badge.svg
1009[slack-link]: http://slack.videojs.com
1010[travis-icon]: https://travis-ci.org/videojs/http-streaming.svg?branch=main
1011[travis-link]: https://travis-ci.org/videojs/http-streaming
1012[issue-stats-link]: http://issuestats.com/github/videojs/http-streaming
1013[issue-stats-pr-icon]: http://issuestats.com/github/videojs/http-streaming/badge/pr
1014[issue-stats-issues-icon]: http://issuestats.com/github/videojs/http-streaming/badge/issue
1015[greenkeeper-icon]: https://badges.greenkeeper.io/videojs/http-streaming.svg
1016[greenkeeper-link]: https://greenkeeper.io/