Skip to content

Commit c28c7ff

Browse files
committed
Add support for HLS and DASH streams
Proper fix for #184
1 parent 6f8da1f commit c28c7ff

5 files changed

Lines changed: 63 additions & 20 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ Prop | Description
114114
`youtubeConfig` | Configuration object for the YouTube player.<br />Set `playerVars` to override the [default player vars](https://developers.google.com/youtube/player_parameters?playerVersion=HTML5).<br />Set `preload` for [preloading](#preloading).
115115
`vidmeConfig` | Configuration object for the Vidme player.<br />Set `format` to use a certain quality of video, when available.<br />Possible values: `240p`, `480p`, `720p`, `1080p`, `dash`, `hls`
116116
`dailymotionConfig` | Configuration object for the DailyMotion player.<br />Set `params` to override the [default player vars](https://developer.dailymotion.com/player#player-parameters).<br />Set `preload` for [preloading](#preloading).
117-
`fileConfig` | Configuration object for the file player.<br />Set `attributes` to apply [element attributes](https://developer.mozilla.org/en/docs/Web/HTML/Element/video#Attributes).<br />Set `forceAudio` to always render an `<audio>` element.
117+
`fileConfig` | Configuration object for the file player.<br />Set `attributes` to apply [element attributes](https://developer.mozilla.org/en/docs/Web/HTML/Element/video#Attributes).<br />Set `forceAudio` to always render an `<audio>` element.<br />Set `forceHLS` to use [hls.js](https://github.com/video-dev/hls.js) for HLS streams.<br />Set `forceDASH` to always use [dash.js](https://github.com/Dash-Industry-Forum/dash.js) for DASH streams.
118118
`facebookConfig` | Configuration object for the Facebook player.<br />Set `appId` to your own [Facebook app ID](https://developers.facebook.com/docs/apps/register#app-id).
119119

120120
##### Preloading

src/demo/App.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,10 +226,12 @@ export default class App extends Component {
226226
<tr>
227227
<th>Files</th>
228228
<td>
229-
{this.renderLoadButton('http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4', 'MP4')}
230-
{this.renderLoadButton('http://clips.vorwaerts-gmbh.de/big_buck_bunny.ogv', 'OGV')}
231-
{this.renderLoadButton('http://clips.vorwaerts-gmbh.de/big_buck_bunny.webm', 'WEBM')}
229+
{this.renderLoadButton('http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4', 'mp4')}
230+
{this.renderLoadButton('http://clips.vorwaerts-gmbh.de/big_buck_bunny.ogv', 'ogv')}
231+
{this.renderLoadButton('http://clips.vorwaerts-gmbh.de/big_buck_bunny.webm', 'webm')}
232232
{this.renderLoadButton(MULTIPLE_SOURCES, 'Multiple')}
233+
{this.renderLoadButton('https://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8', 'HLS (m3u8)')}
234+
{this.renderLoadButton('http://dash.edgesuite.net/envivio/EnvivioDash3/manifest.mpd', 'DASH (mpd)')}
233235
</td>
234236
</tr>
235237
<tr>

src/demo/defaults.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ textarea {
5555
}
5656

5757
button {
58-
margin-right: 5px;
58+
margin: 3px;
5959
padding: 6px 12px;
6060
border: 0;
6161
border-radius: 3px;

src/players/FilePlayer.js

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
import React from 'react'
22

33
import Base from './Base'
4+
import loadScript from 'load-script'
45

56
const AUDIO_EXTENSIONS = /\.(m4a|mp4a|mpga|mp2|mp2a|mp3|m2a|m3a|wav|weba|aac|oga|spx)($|\?)/i
7+
const HLS_EXTENSIONS = /\.(m3u8)($|\?)/i
8+
const HLS_SDK_URL = 'https://cdn.jsdelivr.net/hls.js/latest/hls.min.js'
9+
const HLS_GLOBAL = 'Hls'
10+
const DASH_EXTENSIONS = /\.(mpd)($|\?)/i
11+
const DASH_SDK_URL = 'https://cdnjs.cloudflare.com/ajax/libs/dashjs/2.5.0/dash.all.min.js'
12+
const DASH_GLOBAL = 'dashjs'
613

714
export default class FilePlayer extends Base {
815
static displayName = 'FilePlayer'
@@ -35,8 +42,26 @@ export default class FilePlayer extends Base {
3542
this.player.removeEventListener('error', onError)
3643
super.componentWillUnmount()
3744
}
38-
load () {
39-
// Setting the src is handled by render
45+
shouldUseHLS (url) {
46+
return HLS_EXTENSIONS.test(url) || this.props.fileConfig.forceHLS
47+
}
48+
shouldUseDASH (url) {
49+
return DASH_EXTENSIONS.test(url) || this.props.fileConfig.forceDASH
50+
}
51+
load (url) {
52+
if (this.shouldUseHLS(url)) {
53+
loadSDK(HLS_SDK_URL, HLS_GLOBAL).then(Hls => {
54+
const hls = new Hls()
55+
hls.loadSource(url)
56+
hls.attachMedia(this.player)
57+
})
58+
}
59+
if (this.shouldUseDASH(url)) {
60+
loadSDK(DASH_SDK_URL, DASH_GLOBAL).then(dashjs => {
61+
const player = dashjs.MediaPlayer().create()
62+
player.initialize(this.player, url, true)
63+
})
64+
}
4065
}
4166
play () {
4267
this.player.play()
@@ -79,34 +104,46 @@ export default class FilePlayer extends Base {
79104
const { src, type } = source
80105
return <source key={src} src={src} type={type} />
81106
}
82-
renderSources = url => {
83-
if (url instanceof Array === false) {
84-
return null
85-
}
86-
return url.map(this.renderSource)
87-
}
88107
ref = player => {
89108
this.player = player
90109
}
91110
render () {
92111
const { url, loop, controls, fileConfig } = this.props
93-
const Media = AUDIO_EXTENSIONS.test(url) || fileConfig.forceAudio ? 'audio' : 'video'
112+
const useAudio = AUDIO_EXTENSIONS.test(url) || fileConfig.forceAudio
113+
const useHLS = this.shouldUseHLS(url)
114+
const useDASH = this.shouldUseDASH(url)
115+
const Element = useAudio ? 'audio' : 'video'
116+
const src = url instanceof Array || useHLS || useDASH ? undefined : url
94117
const style = {
95118
width: '100%',
96119
height: '100%',
97120
display: url ? 'block' : 'none'
98121
}
99122
return (
100-
<Media
123+
<Element
101124
ref={this.ref}
102-
src={url instanceof Array ? undefined : url}
125+
src={src}
103126
style={style}
104127
preload='auto'
105128
controls={controls}
106129
loop={loop}
107130
{...fileConfig.attributes}>
108-
{this.renderSources(url)}
109-
</Media>
131+
{url instanceof Array &&
132+
url.map(this.renderSource)
133+
}
134+
</Element>
110135
)
111136
}
112137
}
138+
139+
function loadSDK (url, globalVar) {
140+
if (window[globalVar]) {
141+
return Promise.resolve(window[globalVar])
142+
}
143+
return new Promise((resolve, reject) => {
144+
loadScript(url, err => {
145+
if (err) reject(err)
146+
resolve(window[globalVar])
147+
})
148+
})
149+
}

src/props.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ export const propTypes = {
3838
}),
3939
fileConfig: shape({
4040
attributes: object,
41-
forceAudio: bool
41+
forceAudio: bool,
42+
forceHLS: bool,
43+
forceDASH: bool
4244
}),
4345
onReady: func,
4446
onStart: func,
@@ -86,7 +88,9 @@ export const defaultProps = {
8688
},
8789
fileConfig: {
8890
attributes: {},
89-
forceAudio: false
91+
forceAudio: false,
92+
forceHLS: false,
93+
forceDASH: false
9094
},
9195
onReady: function () {},
9296
onStart: function () {},

0 commit comments

Comments
 (0)