UNPKG

24.4 kBMarkdownView Raw
1# video.js HLS Source Handler
2
3[![Build Status][travis-icon]][travis-link]
4[![Slack Status][slack-icon]][slack-link]
5
6
7Play back HLS with video.js, even where it's not natively supported.
8
9Lead Maintainer: Jon-Carlos Rivera [@imbcmdth](https://github.com/imbcmdth)
10
11Maintenance Status: Stable
12
13<!-- START doctoc generated TOC please keep comment here to allow auto update -->
14<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
15**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
16
17- [Installation](#installation)
18 - [NPM](#npm)
19 - [CDN](#cdn)
20 - [Releases](#releases)
21 - [Manual Build](#manual-build)
22- [Contributing](#contributing)
23- [Talk to us](#talk-to-us)
24- [Getting Started](#getting-started)
25 - [Video.js 6](#videojs-6)
26- [Documentation](#documentation)
27 - [Options](#options)
28 - [How to use](#how-to-use)
29 - [Initialization](#initialization)
30 - [Source](#source)
31 - [List](#list)
32 - [withCredentials](#withcredentials)
33 - [useCueTags](#usecuetags)
34 - [overrideNative](#overridenative)
35 - [blacklistDuration](#blacklistduration)
36 - [bandwidth](#bandwidth)
37 - [enableLowInitialPlaylist](#enablelowinitialplaylist)
38 - [Runtime Properties](#runtime-properties)
39 - [hls.playlists.master](#hlsplaylistsmaster)
40 - [hls.playlists.media](#hlsplaylistsmedia)
41 - [hls.segmentXhrTime](#hlssegmentxhrtime)
42 - [hls.bandwidth](#hlsbandwidth)
43 - [hls.bytesReceived](#hlsbytesreceived)
44 - [hls.selectPlaylist](#hlsselectplaylist)
45 - [hls.representations](#hlsrepresentations)
46 - [hls.xhr](#hlsxhr)
47 - [Events](#events)
48 - [loadedmetadata](#loadedmetadata)
49 - [HLS Usage Events](#hls-usage-events)
50 - [Presence Stats](#presence-stats)
51 - [Use Stats](#use-stats)
52 - [In-Band Metadata](#in-band-metadata)
53 - [Segment Metadata](#segment-metadata)
54- [Hosting Considerations](#hosting-considerations)
55- [Known Issues](#known-issues)
56 - [IE10 and Below](#ie10-and-below)
57 - [IE11](#ie11)
58 - [Fragmented MP4 Support](#fragmented-mp4-support)
59 - [Testing](#testing)
60- [Release History](#release-history)
61- [Building](#building)
62- [Development](#development)
63 - [Tools](#tools)
64 - [Commands](#commands)
65
66<!-- END doctoc generated TOC please keep comment here to allow auto update -->
67
68## Installation
69### NPM
70To install `videojs-contrib-hls` with npm run
71
72```bash
73npm install --save videojs-contrib-hls
74```
75
76### CDN
77Select a version of HLS from the [CDN](https://cdnjs.com/libraries/videojs-contrib-hls)
78
79### Releases
80Download a release of [videojs-contrib-hls](https://github.com/videojs/videojs-contrib-hls/releases)
81
82### Manual Build
83Download a copy of this git repository and then follow the steps in [Building](#building)
84
85## Contributing
86See [CONTRIBUTING.md](/CONTRIBUTING.md)
87
88## Talk to us
89Drop by our slack channel (#playback) on the [Video.js slack][slack-link].
90
91## Getting Started
92Get a copy of [videojs-contrib-hls](#installation) and include it in your page along with video.js:
93
94```html
95<video id=example-video width=600 height=300 class="video-js vjs-default-skin" controls>
96 <source
97 src="https://example.com/index.m3u8"
98 type="application/x-mpegURL">
99</video>
100<script src="video.js"></script>
101<script src="videojs-contrib-hls.min.js"></script>
102<script>
103var player = videojs('example-video');
104player.play();
105</script>
106```
107
108Check out our [live example](http://jsbin.com/vokipos/8/edit?html,output) if you're having trouble.
109
110### Video.js 6
111With Video.js 6, by default there is no flash support. Instead, flash support is provided
112through the [videojs-flash](https://github.com/videojs/videojs-flash) plugin. If you are
113trying to use Video.js version 6 and want to include flash support, you must include
114[videojs-flash](https://github.com/videojs/videojs-flash) on your page before including
115videojs-contrib-hls
116
117```html
118<script src="https://unpkg.com/videojs-flash/dist/videojs-flash.js"></script>
119<script src="https://unpkg.com/videojs-contrib-hls/dist/videojs-contrib-hls.js"></script>
120```
121
122Flash, and the [videojs-flash](https://github.com/videojs/videojs-flash) plugin, are not
123required, but are recommended as a fallback option for browsers that don't have a native
124HLS player or support for [Media Source Extensions](http://caniuse.com/#feat=mediasource).
125
126## Documentation
127[HTTP Live Streaming](https://developer.apple.com/streaming/) (HLS) has
128become a de-facto standard for streaming video on mobile devices
129thanks to its native support on iOS and Android. There are a number of
130reasons independent of platform to recommend the format, though:
131
132- Supports (client-driven) adaptive bitrate selection
133- Delivered over standard HTTP ports
134- Simple, text-based manifest format
135- No proprietary streaming servers required
136
137Unfortunately, all the major desktop browsers except for Safari are
138missing HLS support. That leaves web developers in the unfortunate
139position of having to maintain alternate renditions of the same video
140and potentially having to forego HTML-based video entirely to provide
141the best desktop viewing experience.
142
143This project addresses that situation by providing a polyfill for HLS
144on browsers that have support for [Media Source
145Extensions](http://caniuse.com/#feat=mediasource), or failing that,
146support Flash. You can deploy a single HLS stream, code against the
147regular HTML5 video APIs, and create a fast, high-quality video
148experience across all the big web device categories.
149
150Check out the [full documentation](docs/) for details on how HLS works
151and advanced configuration. A description of the [adaptive switching
152behavior](docs/bitrate-switching.md) is available, too.
153
154videojs-contrib-hls supports a bunch of HLS features. Here
155are some highlights:
156
157- video-on-demand and live playback modes
158- backup or redundant streams
159- mid-segment quality switching
160- AES-128 segment encryption
161- CEA-608 captions are automatically translated into standard HTML5
162 [caption text tracks][0]
163- In-Manifest WebVTT subtitles are automatically translated into standard HTML5
164 subtitle tracks
165- Timed ID3 Metadata is automatically translated into HTML5 metedata
166 text tracks
167- Highly customizable adaptive bitrate selection
168- Automatic bandwidth tracking
169- Cross-domain credentials support with CORS
170- Tight integration with video.js and a philosophy of exposing as much
171 as possible with standard HTML APIs
172- Stream with multiple audio tracks and switching to those audio tracks
173 (see the docs folder) for info
174- Media content in
175 [fragmented MP4s](https://developer.apple.com/videos/play/wwdc2016/504/)
176 instead of the MPEG2-TS container format.
177
178[0]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/track
179
180### Options
181#### How to use
182
183##### Initialization
184You may pass in an options object to the hls source handler at player
185initialization. You can pass in options just like you would for other
186parts of video.js:
187
188```javascript
189// html5 for html hls
190videojs(video, {html5: {
191 hls: {
192 withCredentials: true
193 }
194}});
195
196// or
197
198// flash for flash hls
199videojs(video, {flash: {
200 hls: {
201 withCredentials: true
202 }
203}});
204
205// or
206
207var options = {hls: {
208 withCredentials: true;
209}};
210
211videojs(video, {flash: options, html5: options});
212
213```
214
215##### Source
216Some options, such as `withCredentials` can be passed in to hls during
217`player.src`
218
219```javascript
220
221var player = videojs('some-video-id');
222
223player.src({
224 src: 'https://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/bipbop_16x9_variant.m3u8',
225 type: 'application/x-mpegURL',
226 withCredentials: true
227});
228```
229
230#### List
231##### withCredentials
232* Type: `boolean`
233* can be used as a source option
234* can be used as an initialization option
235
236When the `withCredentials` property is set to `true`, all XHR requests for
237manifests and segments would have `withCredentials` set to `true` as well. This
238enables storing and passing cookies from the server that the manifests and
239segments live on. This has some implications on CORS because when set, the
240`Access-Control-Allow-Origin` header cannot be set to `*`, also, the response
241headers require the addition of `Access-Control-Allow-Credentials` header which
242is set to `true`.
243See html5rocks's [article](http://www.html5rocks.com/en/tutorials/cors/)
244for more info.
245
246##### useCueTags
247* Type: `boolean`
248* can be used as an initialization option
249
250When the `useCueTags` property is set to `true,` a text track is created with
251label 'ad-cues' and kind 'metadata'. The track is then added to
252`player.textTracks()`. Changes in active cue may be
253tracked by following the Video.js cue points API for text tracks. For example:
254
255```javascript
256let textTracks = player.textTracks();
257let cuesTrack;
258
259for (let i = 0; i < textTracks.length; i++) {
260  if (textTracks[i].label === 'ad-cues') {
261    cuesTrack = textTracks[i];
262  }
263}
264
265cuesTrack.addEventListener('cuechange', function() {
266 let activeCues = cuesTrack.activeCues;
267
268  for (let i = 0; i < activeCues.length; i++) {
269 let activeCue = activeCues[i];
270
271    console.log('Cue runs from ' + activeCue.startTime +
272 ' to ' + activeCue.endTime);
273  }
274});
275```
276
277##### overrideNative
278* Type: `boolean`
279* can be used as an initialization option
280
281Try to use videojs-contrib-hls even on platforms that provide some
282level of HLS support natively. There are a number of platforms that
283*technically* play back HLS content but aren't very reliable or are
284missing features like CEA-608 captions support. When `overrideNative`
285is true, if the platform supports Media Source Extensions
286videojs-contrib-hls will take over HLS playback to provide a more
287consistent experience.
288
289__NOTE__: If you use this option, you must also set
290`videojs.options.html5.nativeAudioTracks` and
291`videojs.options.html5.nativeVideoTracks` to
292`false`. videojs-contrib-hls relies on audio and video tracks to play
293streams with alternate audio and requires additional capabilities only
294supported by non-native tracks in video.js.
295
296##### blacklistDuration
297* Type: `number`
298* can be used as an initialization option
299
300When the `blacklistDuration` property is set to a time duration in seconds,
301if a playlist is blacklisted, it will be blacklisted for a period of that
302customized duration. This enables the blacklist duration to be configured
303by the user.
304
305##### bandwidth
306* Type: `number`
307* can be used as an initialization option
308
309When the `bandwidth` property is set (bits per second), it will be used in
310the calculation for initial playlist selection, before more bandwidth
311information is seen by the player.
312
313##### enableLowInitialPlaylist
314* Type: `boolean`
315* can be used as an initialization option
316
317When `enableLowInitialPlaylist` is set to true, it will be used to select
318the lowest bitrate playlist initially. This helps to decrease playback start time.
319This setting is `false` by default.
320
321### Runtime Properties
322Runtime properties are attached to the tech object when HLS is in
323use. You can get a reference to the HLS source handler like this:
324
325```javascript
326var hls = player.tech({ IWillNotUseThisInPlugins: true }).hls;
327```
328
329If you *were* thinking about modifying runtime properties in a
330video.js plugin, we'd recommend you avoid it. Your plugin won't work
331with videos that don't use videojs-contrib-hls and the best plugins
332work across all the media types that video.js supports. If you're
333deploying videojs-contrib-hls on your own website and want to make a
334couple tweaks though, go for it!
335
336#### hls.playlists.master
337Type: `object`
338
339An object representing the parsed master playlist. If a media playlist
340is loaded directly, a master playlist with only one entry will be
341created.
342
343#### hls.playlists.media
344Type: `function`
345
346A function that can be used to retrieve or modify the currently active
347media playlist. The active media playlist is referred to when
348additional video data needs to be downloaded. Calling this function
349with no arguments returns the parsed playlist object for the active
350media playlist. Calling this function with a playlist object from the
351master playlist or a URI string as specified in the master playlist
352will kick off an asynchronous load of the specified media
353playlist. Once it has been retreived, it will become the active media
354playlist.
355
356#### hls.segmentXhrTime
357Type: `number`
358
359The number of milliseconds it took to download the last media segment.
360This value is updated after each segment download completes.
361
362#### hls.bandwidth
363Type: `number`
364
365The number of bits downloaded per second in the last segment download.
366This value is used by the default implementation of `selectPlaylist`
367to select an appropriate bitrate to play.
368
369Before the first video segment has been downloaded, it's hard to
370estimate bandwidth accurately. The HLS tech uses a heuristic based on
371the playlist download times to do this estimation by default. If you
372have a more accurate source of bandwidth information, you can override
373this value as soon as the HLS tech has loaded to provide an initial
374bandwidth estimate.
375
376#### hls.bytesReceived
377Type: `number`
378
379The total number of content bytes downloaded by the HLS tech.
380
381#### hls.selectPlaylist
382Type: `function`
383
384A function that returns the media playlist object to use to download
385the next segment. It is invoked by the tech immediately before a new
386segment is downloaded. You can override this function to provide your
387adaptive streaming logic. You must, however, be sure to return a valid
388media playlist object that is present in `player.hls.master`.
389
390Overridding this function with your own is very powerful but is overkill
391for many purposes. Most of the time, you should use the much simpler
392function below to selectively enable or disable a playlist from the
393adaptive streaming logic.
394
395#### hls.representations
396Type: `function`
397
398It is recommended to include the [videojs-contrib-quality-levels](https://github.com/videojs/videojs-contrib-quality-levels) plugin to your page so that videojs-contrib-hls 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.
399
400Example, only enabling representations with a width greater than or equal to 720:
401
402```javascript
403var qualityLevels = player.qualityLevels();
404
405for (var i = 0; i < qualityLevels.length; i++) {
406 var quality = qualityLevels[i];
407 if (quality.width >= 720) {
408 quality.enabled = true;
409 } else {
410 quality.enabled = false;
411 }
412}
413```
414
415If 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.hls`. This will return a list of plain objects, each with `width`, `height`, `bandwidth`, and `id` properties, and an `enabled()` method.
416
417```javascript
418player.hls.representations();
419```
420
421To 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.
422
423Example, only enabling representations with a width greater than or equal to 720:
424
425```javascript
426player.hls.representations().forEach(function(rep) {
427 if (rep.width >= 720) {
428 rep.enabled(true);
429 } else {
430 rep.enabled(false);
431 }
432});
433```
434
435#### hls.xhr
436Type: `function`
437
438The xhr function that is used by HLS internally is exposed on the per-
439player `hls` object. While it is possible, we do not recommend replacing
440the function with your own implementation. Instead, the `xhr` provides
441the ability to specify a `beforeRequest` function that will be called
442with an object containing the options that will be used to create the
443xhr request.
444
445Example:
446```javascript
447player.hls.xhr.beforeRequest = function(options) {
448 options.uri = options.uri.replace('example.com', 'foo.com');
449
450 return options;
451};
452```
453
454The global `videojs.Hls` also exposes an `xhr` property. Specifying a
455`beforeRequest` function on that will allow you to intercept the options
456for *all* requests in every player on a page. For consistency across
457browsers the video source should be set at runtime once the video player
458is ready.
459
460Example
461```javascript
462videojs.Hls.xhr.beforeRequest = function(options) {
463 /*
464 * Modifications to requests that will affect every player.
465 */
466
467 return options;
468};
469
470var player = videojs('video-player-id');
471player.ready(function() {
472 this.src({
473 src: 'https://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/bipbop_16x9_variant.m3u8',
474 type: 'application/x-mpegURL',
475 });
476});
477```
478
479For information on the type of options that you can modify see the
480documentation at [https://github.com/Raynos/xhr](https://github.com/Raynos/xhr).
481
482### Events
483Standard HTML video events are handled by video.js automatically and
484are triggered on the player object.
485
486#### loadedmetadata
487
488Fired after the first segment is downloaded for a playlist. This will not happen
489until playback if video.js's `metadata` setting is `none`
490
491### HLS Usage Events
492
493Usage tracking events are fired when we detect a certain HLS feature, encoding setting,
494or API is used. These can be helpful for analytics, and to pinpoint the cause of HLS errors.
495For instance, if errors are being fired in tandem with a usage event indicating that the
496player was playing an AES encrypted stream, then we have a possible avenue to explore when
497debugging the error.
498
499Note that although these usage events are listed below, they may change at any time without
500a major version change.
501
502HLS usage events are triggered on the tech with the exception of the 3 hls-reload-error
503events, which are triggered on the player.
504
505#### Presence Stats
506
507Each of the following usage events are fired once per source if (and when) detected:
508
509| Name | Description |
510| ------------- | ------------- |
511| hls-webvtt | master manifest has at least one segmented WebVTT playlist |
512| hls-aes | a playlist is AES encrypted |
513| hls-fmp4 | a playlist used fMP4 segments |
514| hls-demuxed | audio and video are demuxed by default |
515| hls-alternate-audio | alternate audio available in the master manifest |
516| hls-playlist-cue-tags | a playlist used cue tags (see useCueTags(#usecuetags) for details) |
517
518#### Use Stats
519
520Each of the following usage events are fired per use:
521
522| Name | Description |
523| ------------- | ------------- |
524| hls-gap-skip | player skipped a gap in the buffer |
525| hls-player-access | player.hls was accessed |
526| hls-audio-change | a user selected an alternate audio stream |
527| hls-rendition-disabled | a rendition was disabled |
528| hls-rendition-enabled | a rendition was enabled |
529| hls-rendition-blacklisted | a rendition was blacklisted |
530| hls-timestamp-offset | a timestamp offset was set in HLS (can identify discontinuities) |
531| hls-unknown-waiting | the player stopped for an unknown reason and we seeked to current time try to address it |
532| hls-live-resync | playback fell off the back of a live playlist and we resynced to the live point |
533| hls-video-underflow | we seeked to current time to address video underflow |
534| hls-error-reload-initialized | the reloadSourceOnError plugin was initialized |
535| hls-error-reload | the reloadSourceOnError plugin reloaded a source |
536| hls-error-reload-canceled | an error occurred too soon after the last reload, so we didn't reload again (to prevent error loops) |
537
538
539### In-Band Metadata
540The HLS tech supports [timed
541metadata](https://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/HTTP_Live_Streaming_Metadata_Spec/Introduction/Introduction.html)
542embedded as [ID3 tags](http://id3.org/id3v2.3.0). When a stream is
543encountered with embedded metadata, an [in-band metadata text
544track](https://html.spec.whatwg.org/multipage/embedded-content.html#text-track-in-band-metadata-track-dispatch-type)
545will automatically be created and populated with cues as they are
546encountered in the stream. UTF-8 encoded
547[TXXX](http://id3.org/id3v2.3.0#User_defined_text_information_frame)
548and [WXXX](http://id3.org/id3v2.3.0#User_defined_URL_link_frame) ID3
549frames are mapped to cue points and their values set as the cue
550text. Cues are created for all other frame types and the data is
551attached to the generated cue:
552
553```javascript
554cue.value.data
555```
556
557There are lots of guides and references to using text tracks [around
558the web](http://www.html5rocks.com/en/tutorials/track/basics/).
559
560### Segment Metadata
561You can get metadata about the segments currently in the buffer by using the `segment-metadata`
562text track. You can get the metadata of the currently rendered segment by looking at the
563track's `activeCues` array. The metadata will be attached to the `cue.value` property and
564will have this structure
565
566```javascript
567cue.value = {
568 uri, // The Segment uri
569 timeline, // Timeline of the segment for detecting discontinuities
570 playlist, // The Playlist uri
571 start, // Segment start time
572 end // Segment end time
573};
574```
575
576Example:
577Detect when a change in quality is rendered on screen
578```javascript
579let tracks = player.textTracks();
580let segmentMetadataTrack;
581
582for (let i = 0; i < tracks.length; i++) {
583 if (tracks[i].label === 'segment-metadata') {
584 segmentMetadataTrack = tracks[i];
585 }
586}
587
588let previousPlaylist;
589
590if (segmentMetadataTrack) {
591 segmentMetadataTrack.on('cuechange', function() {
592 let activeCue = segmentMetadataTrack.activeCues[0];
593
594 if (activeCue) {
595 if (previousPlaylist !== activeCue.value.playlist) {
596 console.log('Switched from rendition ' + previousPlaylist +
597 ' to rendition ' + activeCue.value.playlist);
598 }
599 previousPlaylist = activeCue.value.playlist;
600 }
601 });
602}
603```
604
605## Hosting Considerations
606Unlike a native HLS implementation, the HLS tech has to comply with
607the browser's security policies. That means that all the files that
608make up the stream must be served from the same domain as the page
609hosting the video player or from a server that has appropriate [CORS
610headers](https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS)
611configured. Easy [instructions are
612available](http://enable-cors.org/server.html) for popular webservers
613and most CDNs should have no trouble turning CORS on for your account.
614
615
616## Known Issues
617Issues that are currenty know about with workarounds. If you want to
618help find a solution that would be appreciated!
619
620### IE10 and Below
621As of version 5.0.0, IE10 and below are no longer supported.
622
623### IE11
624In some IE11 setups there are issues working with its native HTML
625SourceBuffers functionality. This leads to various issues, such as
626videos stopping playback with media decode errors. The known workaround
627for this issues is to force the player to use flash when running on IE11.
628
629### Fragmented MP4 Support
630Edge has native support for HLS but only in the MPEG2-TS container. If
631you attempt to play an HLS stream with fragmented MP4 segments, Edge
632will stall. Fragmented MP4s are only supported on browser that have
633[Media Source Extensions](http://caniuse.com/#feat=mediasource) available.
634
635### Testing
636
637For testing, you run `npm run test`. This will run tests using any of the
638browsers that karma-detect-browsers detects on your machine.
639
640## Release History
641Check out the [changelog](CHANGELOG.md) for a summary of each release.
642
643## Building
644To build a copy of videojs-contrib-hls run the following commands
645
646```bash
647git clone https://github.com/videojs/videojs-contrib-hls
648cd videojs-contrib-hls
649npm i
650npm run build
651```
652
653videojs-contrib-hls will have created all of the files for using it in a dist folder
654
655## Development
656
657### Tools
658* Download stream locally with the [HLS Fetcher](https://github.com/imbcmdth/hls-fetcher)
659* Simulate errors with [Murphy](https://github.com/mrocajr/murphy)
660
661### Commands
662All commands for development are listed in the `package.json` file and are run using
663```bash
664npm run <command>
665```
666
667[slack-icon]: http://slack.videojs.com/badge.svg
668[slack-link]: http://slack.videojs.com
669[travis-icon]: https://travis-ci.org/videojs/videojs-contrib-hls.svg?branch=master
670[travis-link]: https://travis-ci.org/videojs/videojs-contrib-hls