UNPKG

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