- Initialize player
- Use Renderers
- Use
stretching
modes - Responsive grid
- Setting new captions
- Destroy player
You can use this as a standalone library if you wish, or just stick with the full MediaElementPlayer.
IMPORTANT: If you use flash_video
renderer, it's always recommended to use media.load()
inside the success
callback to ensure that RTMP and FLV will play properly.
<script>
// You can use either a string for the player ID (i.e., `player`),
// or `document.querySelector()` for any selector
var player = new MediaElement('player', {
pluginPath: "/path/to/shims/",
success: function(mediaElement, originalNode) {
// do things
}
});
</script>
You can avoid running any startup scripts by adding class="mejs__player"
to the <video>
or <audio>
tag. All the player configuration can be added through data-mejsoptions
attribute.
<video src="myvideo.mp4" width="320" height="240"
class="mejs__player"
data-mejsoptions='{"pluginPath": "/path/to/shims/", "alwaysShowControls": "true"}'></video>
<script>
// You can use either a string for the player ID (i.e., `player`),
// or `document.querySelector()` for any selector
var player = new MediaElementPlayer('player', {
pluginPath: "/path/to/shims/",
// When using `MediaElementPlayer`, an `instance` argument
// is available in the `success` callback
success: function(mediaElement, originalNode, instance) {
// do things
}
});
</script>
<script>
$('#mediaplayer').mediaelementplayer({
pluginPath: "/path/to/shims/",
// When using jQuery's `mediaelementplayer`, an `instance` argument
// is available in the `success` callback
success: function(mediaElement, originalNode, instance) {
// do things
}
});
</script>
// To import only MediaElement class
import 'mediaelement/standalone';
// To import all the plugin (you will have access to the MediaElement and MediaElementPlayer classes,
// $.fn.mediaelementplayer plugin, all the native renderers, YouTube and Flash shims)
import 'mediaelement/full';
// To import renderers (i.e., Vimeo)
import 'mediaelement/build/renderers/vimeo';
// To import languages (i.e., Spanish)
import 'mediaelement/build/lang/es';
// Later on the code you need to use mejs.i18n.language('es') to set the language
IMPORTANT: To ensure you can use the $.fn.mediaelementplayer
plugin, you will need to import jQuery as well in your bundle like follows:
- Create a
jquery-global.js
file that contains:
'use strict';
import jquery from 'jquery';
window.jQuery = jquery;
window.$ = jquery;
- Import the
jquery-global.js
along with the desired package
'use strict';
import '/path/to/jquery-global';
import 'mediaelement'; // or import `mediaelement/standalone` if you only want the shim but not the full player;
With Require.js
, you will need the following setup if you are planning to use HLS, M(PEG)-DASH or FLV, given the way the packages are bundled.
To make it work, install via npm any of the external libraries you will need (i.e., HLS.js).
npm install hls.js
In your code, include a shim
for the external library and then assign the exported variable to the global scope.
requirejs.config({
// Other configuration
shim: {
// Other shims
'path/to/hls': {deps: ['require'], exports: "Hls"},
// If you only need the shim and not the player, use
//'path/to/mediaelement': {deps: ['require'], exports: "MediaElement"}
'path/to/mediaelement-and-player': {deps: ['require'], exports: "MediaElementPlayer"}
}
});
// Later on the code...
require(['path/to/hls'], function (Hls) {
window.Hls = Hls;
require(['path/to/mediaelement-and-player'], function (MediaElementPlayer) {
var player = new MediaElementPlayer('media-id', {
// Player configuration
});
});
});
IMPORTANT NOTE: To keep Flash shims working you MUST setup the path where the shims are via pluginPath
, and do not forget to add a slash at the end of the string. Please refer to the examples above. In Meteor, the right path to be used is /packages/johndyer_mediaelement/build/
;
With React.js
, you will need to install the external libraries the same way as Require
.
Once installed through npm, you will be able to create your component using MediaElement
. As an example:
MediaElement.js
import React, { Component } from 'react';
import flvjs from 'flv.js';
import hlsjs from 'hls.js';
import 'mediaelement';
// Import stylesheet and shims
import 'mediaelement/build/mediaelementplayer.min.css';
import 'mediaelement/build/mediaelement-flash-video.swf';
export default class MediaElement extends Component {
state = {}
success(media, node, instance) {
// Your action when media was successfully loaded
}
error(media) {
// Your action when media had an error loading
}
render() {
const
props = this.props,
sources = JSON.parse(props.sources),
tracks = JSON.parse(props.tracks),
sourceTags = [],
tracksTags = []
;
for (let i = 0, total = sources.length; i < total; i++) {
const source = sources[i];
sourceTags.push(`<source src="${source.src}" type="${source.type}">`);
}
for (let i = 0, total = tracks.length; i < total; i++) {
const track = tracks[i];
tracksTags.push(`<track src="${track.src}" kind="${track.kind}" srclang="${track.lang}"${(track.label ? ` label=${track.label}` : '')}>`);
}
const
mediaBody = `${sourceTags.join("\n")}
${tracksTags.join("\n")}`,
mediaHtml = props.mediaType === 'video' ?
`<video id="${props.id}" width="${props.width}" height="${props.height}"${(props.poster ? ` poster=${props.poster}` : '')}
${(props.controls ? ' controls' : '')}${(props.preload ? ` preload="${props.preload}"` : '')}>
${mediaBody}
</video>` :
`<audio id="${props.id}" width="${props.width}" controls>
${mediaBody}
</audio>`
;
return (<div dangerouslySetInnerHTML={{__html: mediaHtml}}></div>);
}
componentDidMount() {
const {MediaElementPlayer} = global;
if (!MediaElementPlayer) {
return;
}
const options = Object.assign({}, JSON.parse(this.props.options), {
// Read the Notes below for more explanation about how to set up the path for shims
pluginPath: './static/media/',
success: (media, node, instance) => this.success(media, node, instance),
error: (media, node) => this.error(media, node)
});
window.flvjs = flvjs;
window.Hls = hlsjs;
this.setState({player: new MediaElementPlayer(this.props.id, options)});
}
componentWillUnmount() {
if (this.state.player) {
this.state.player.remove();
this.setState({player: null});
}
}
}
So you can use your component like as follows.
App.js
import React, { Component } from 'react';
import './App.css';
import MediaElement from './MediaElement';
export default class App extends Component {
// Other code
render() {
const
sources = [
{src: 'http://www.streambox.fr/playlists/test_001/stream.m3u8', type: 'application/x-mpegURL'},
{src: 'http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4', type: 'video/mp4'},
{src: 'rtmp://firehose.cul.columbia.edu:1935/vod/mp4:sample.mp4', type: 'video/rtmp'}
],
config = {},
tracks = {}
;
return (
<MediaElement
id="player1"
mediaType="video"
preload="none"
controls
width="640"
height="360"
poster=""
sources={JSON.stringify(sources)}
options={JSON.stringify(config)}
tracks={JSON.stringify(tracks)}
/>);
}
}
IMPORTANT NOTES
- If you want to support Flash renderers, you MUST activate a file loader in WebPack's configuration file in order to send the shims to the correct location (
./static/media/
in the example above). Something like this:
module: {
// All previous code
loaders: [
// All previous loaders
{
test: /\.swf$/,
loader: 'file',
query: {
name: 'static/media/[name].[ext]'
}
}
]
}
- For other renderers that cannot be installed through npm, such as YouTube, you might need to load their script through
componentDidMount
method:
componentDidMount() {
let loaded = false;
if (!loaded) {
const tag = document.createElement('script');
tag.src = '//www.youtube.com/player_api';
const firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
loaded = true;
}
}
After the MediaElement
package has been loaded, include any renderer(s) you are planning to use that not part of the main bundle (mediaelement-and-player.js
). For example, to include Vimeo and Twitch support:
<script src="/path/to/mediaelement-and-player.min.js"></script>
<script src="/path/to/renderers/vimeo.min.js"></script>
<script src="/path/to/renderers/twitch.min.js"></script>
By default, all the renderers will be called by their IDs and the plugin will try to detect the best one.
However, if you need to use just a subset of renderers in a specific order, you must list their IDs using renderers
option when configuring your player.
// Use globally native M(PEG)-DASH renderer first, then Flash shim
mejs.Renderers.order = ['native_dash', 'flash_dash'];
$('video, audio').mediaelementplayer({
renderers: ['native_dash', 'flash_dash'], // Use only M(PEG)DASH renderers
// More configuration
});
MediaElement
can invoke methods from the current renderer's API. An example using native HLS:
$('video').mediaelementplayer({
pluginPath: '../build/',
// All the config related to HLS
hls: {
debug: true
},
// More configuration parameters...
success: function(media, node, instance) {
// Use the conditional to detect if you are using `native_hls` renderer for that given media;
// otherwise, you don't need it
if (Hls !== undefined) {
media.addEventListener(Hls.Events.MEDIA_ATTACHED, function () {
// All the code when this event is reached...
console.log('Media attached!');
});
// Manifest file was parsed, invoke loading method
media.addEventListener(Hls.Events.MANIFEST_PARSED, function () {
// All the code when this event is reached...
console.log('Manifest parsed!');
});
media.addEventListener(Hls.Events.FRAG_PARSING_METADATA, function (event, data) {
// All the code when this event is reached...
console.log(data);
});
}
}
});
Below are listed the renderers with their IDs and player instance to execute other methods from APIs.
Renderer | ID | Reference | MIME Type(s) |
---|---|---|---|
Native video/audio | html5 |
--- | video/mp4, audio/mp4, video/webm, audio/mpeg, audio/mp3, audio/ogg, audio/oga, video/ogg |
HLS native | native_hls |
hls.js API |
application/x-mpegURL, vnd.apple.mpegURL |
M(PEG)-DASH native | native_dash |
dash.js Documentation |
application/dash+xml |
FLV native | native_flv |
flv.js API |
video/flv |
SoundCloud | soundcloud_iframe |
SoundCloud Widget API | video/soundcloud, video/x-soundcloud |
facebook |
--- | video/facebook, video/x-facebook | |
Vimeo | vimeo_iframe |
Vimeo Player API | video/vimeo, video/x-vimeo |
YouTube | youtube_iframe |
YouTube IFrame Player API | video/youtube, video/x-youtube |
DailyMotion | dailymotion_iframe |
Dailymotion Player API | video/dailymotion, video/x-dailymotion |
Twitch | twitch_iframe |
Twitch Emded API | video/twitch, video/x-twitch |
Video shim | flash_video |
--- | video/mp4, video/rtmp, audio/rtmp, rtmp/mp4, audio/mp4 |
Audio shim | flash_audio |
--- | audio/mp3 |
OGG Audio shim | flash_audio_ogg |
--- | audio/ogg, audio/oga |
HLS shim | flash_hls |
FlasHLS Events | application/x-mpegURL, vnd.apple.mpegURL |
M(PEG)-DASH shim | flash_dash |
--- | application/dash+xml |
To know how well-supported are each one of the formats, visit http://caniuse.com/
IMPORTANT NOTES
- Only renderers prefixed as native, YouTube, and Flash shim, are integrated by default on the player. The rest of the renderers are stored in the
build/renderers
folder. - For
flash_hls
, you can use the events listed on https://github.com/mangui/flashls/blob/dev/API.md by prepending on followed by the event name in camelcase notation; i.e., to callFRAGMENT_PLAYING
, you need to writeonFragmentPlaying
on JS. The events that return objects will have the info in thedata
attribute of the object; the rest, on themessage
attribute.
Notes
- Support for
wmv
andwma
has been dropped since most of the major players are not supporting it as well. ogg
formats will not play consistently in all browsers so it is strongly recommended a MP3 fallback for audio, or MP4 for video.wav
andwebm
formats will only play on Browsers that support it natively since there is currently no Flash fallback to allow them to play in other browsers.flv
andmpd
will not work on iOS since it doesn't support MSE; formpd
use am3u8
fallback.- SoundCloud can play with
html5
renderer using the following URL format:https://api.soundcloud.com/tracks/XXX/stream?client_id=XXX
MediaElementPlayer
accepts 4 different stretching modes. The following table describes how to set each one of them.
Mode | Setup |
---|---|
auto | Mode by default, this mode checks if there are any elements in the video /audio tag to turn the responsive mode; if not, will set it up in none mode. |
responsive | Can be turned on by setting max-width: 100% style (inline, or in the stylesheet), or width="100%" height="100%" attributes in the video /audio tag. In JavaScript, set in the player's configuration stretching: 'responsive' (preferred) or videoWidth: '100%' videoHeight: '100%' . |
fill | This mode will crop the video to adapt it to the dimensions of the parent container by only setting up stretching: 'fill' . It is encouraged to set up the parent's height to 100% to make it work as expected. |
none | Use width and height attributes specified in the video /audio tags and no max-width: 100% or width="100%" height="100%" attributes; otherwise, use the stretching: 'none' configuration element to achieve this. |
Since MediaElement
can adapt its size to be responsive, some might be tempted to use CSS or JavaScript to create a responsive grid of videos.
So far, right now the best plugin to be used with MediaElement
for this task has been Flexr.
With MediaElementPlayer
, the way to do it is just setting the new values for required attributes (srclang
, kind
and src
) and optionally, label
,
in the track
tags for all browsers EXCEPT Safari Desktop.
With Safari Desktop in its latest version, due to a keyboard trap issue generated when appending the original video
tag containing track
element during the construction
of the player, it is necessary to create track
tags with the attributes specified above, and override the trackFiles
array.
var player = new MediaElementPlayer('#player');
const track = document.createElement('track');
track.kind = 'subtitles';
track.label = 'English';
track.src = '/path/to/captions.vtt';
track.srclang = 'en';
// In this example, we are assuming there is only one `track` tag;
// if there are more, implement your logic to override the necessary one(s)
if (player.trackFiles !== null) {
player.trackFiles = [track];
}
Once you set up the new values for the track attributes, or defined the workflow for Safari, it is required to register the new track(s) as follows:
player.findTracks();
// This way we are ensuring ALL tracks are being loaded, starting from the first one
player.loadTrack(0);
// Set the default language using the ID of the language.
// Check the radio buttons generated by the player to see the ID you want to set, or use `none`
player.setTrack('mep_0_track_0_subtitles_en');
In order to destroy the player, you must pause the player and then invoke the remove()
method.
var player = new MediaElementPlayer('#player');
// Using jQuery:
// var playerId = $('#mediaplayer').closest('.mejs__container').attr('id');
// var player = mejs.players[playerId];
if (!player.paused) {
player.pause();
}
player.remove();
// If you wanna destroy COMPLETELY the player (including also the `video` tag) use the above and also the following:
var videos = document.getElementsByTagName('video');
for( var i = 0, total = videos.length; i < total; i++ ){
videos[i].parentNode.removeChild(videos[i]);
}
// Using jQuery:
// $('video').each(function() {
// $(this).remove();
// });
Same code can be used for <audio>
elements.