The Video Js API – Referencing Video Objects

video js api
After using the excellent VideoJs HTML5 video player today, I thought a small article regarding improving site performance for video heavy websites was in order. The site in question is a project I inherited from a very large agency. The site was an internal application (so no need to worry about video SEO). By correctly referencing the VideoJS object through the Video Js API and displaying videos dynamically through JavaScript the site in question loaded faster and is more flexible for future updates.

The current site output the video HTML (36 video DOM elements nonetheless!) directly onto the webpage, as below. Dummy data has been used, a silly mammoth JavaScript closure and additional video setup options are omitted for the sake of brevity/sanity:

<video id="vid-section-1" class="video-js vjs-default-skin" 
 poster="/public/assets/media/images/videos/rotary.png" 
 preload 
 controls="controls" width="1280" height="720" 
 data-setup="{"controls": false, "autoplay": true, "preload": "auto", "loop": false}">
    <source src="/public/assets/media/videos/rotary.webm" type="video/webm" />
</video>

<video id="vid-section-2" class="video-js vjs-default-skin" 
 poster="/public/assets/media/images/videos/machines.png" 
 preload 
 controls="controls" width="1280" height="720" 
 data-setup="{"controls": false, "autoplay": true, "preload": "auto", "loop": false}">
    <source src="/public/assets/media/videos/machines.webm" type="video/webm" />
</video>

// More video HTML ...

When a button on the webpage is clicked, the target element (#stage) was populated with the latter video HTML:

$('.video-button').on('click', function() {
 setVideo($(this).data('videoId'));
});

// Additional code omitted for brevity
setVideo: function(video) {
 var pane = $('#stage');
 var paneVideo = pane.find('video#video-section-' + video).html();
 pane.html('');
 pane.html(paneVideo).show();
},

Due to the setup options passed through each “data-setup” attribute, the video would of course play automatically once the #stage had been populated with the appropriate HTML.

I’m sure this method worked fine previously, but the site took almost 3 minutes to load and made the web browser crash frequently. Unfortunately, due to the previous developer passing the “preload” option to VideoJs, the majority of devices attempt to download all 36 video files in one fell swoop, when the page loads. Again, this is fine for a few, small videos, but for 36 videos this was a serious issue and caused very high memory usage in the web browser – even Google Chrome was brought to its knees, with no other tabs open.

Amongst other items, I was tasked with the following:

  • Improve page load and stop the lockups
  • Performs actions after the video has finished

The Video Js API – Woohoo!

Firstly, I decided to remove the code that generated HTML for the 36 videos. The page loaded almost instantly as expected. To load the actual video, I set the video HTML directly via JavaScript, altering the “setVideo” function slightly:

// Additional code omitted for brevity
setVideo: function(video) {
	var pane = $('#stage');
	pane.html('');
	pane.html("<video id=\"video-section-"+video+"\"" /* Remainder of HTML to generate the video */).show();

	_V_("video_overlay_1_"+segment).ready(function(){
		this.play();
	});
},
// Additional code omitted for brevity

Note when setting the video HTML I removed the “data-setup” options completely.

The video is now loaded dynamically, because it did not exist at the page load. However, at this point the video will not play. To correctly reference the player after the target video has been loaded into the DOM, make use of the Video Js API (see highlighted lines above). Within the JavaScript callback function, the video can be accessed directly via a “this” object. So in my example I wrote this.play() to autoplay the video. However, any of the HTML5 API functions can be used aswell. THis change alone made viewing the videos much faster.

Once the video has finished playing fully I needed to perform some arbitrary actions. The previous implementation was rather clunky and consisted of working out how long the video was due to play for and then using SetTimout after the siad period to run some functions. Not ideal.

Luckily, the Video Js API fire events at important points – there are a lot. In my case, when the video has fully finished playing, a “ended” event is fired – perfect. The documentation describes this event as follows: “fired when the end of the media resource is reached (currentTime == duration)”. Perfect.

A small change to the “setVideo” function is required:

// Additional code omitted for brevity
setVideo: function(video) {
	var pane = $('#stage');
	pane.html('');
	pane.html("<video id=\"video-section-"+video+"\"").show();

	_V_("video_overlay_1_"+segment).ready(function(){
		this.play();
		this.on("ended", function(){
			App.syncGoogleAnalytics(video);
			App.setPostVideoPaneHtml(video);
			App.setActiveNav();
// Additional code removed for brevity ...
		});
	});
},
// Additional code omitted for brevity

That’s it. By referencing the VideoJs object through the Video Js API, the site loads faster and is flexible when initiating videos. For instance I could pass dynamic arguments through to each video that previously wouldn’t have been possible. E.g. video sizes, start positions etc.

/Fin

Published by

Rob Allport

Web Developer based in Stoke-on-Trent Staffordshire Google+ - Twitter

Leave a Reply

Your email address will not be published. Required fields are marked *