Video.js Blog

Jim Whisenant2013-09-18

Running Video.js unit tests in real browsers with Karma

If you’ve ever cloned the video.js repository, either to contribute or to build your own version, you’ve no doubt run the video.js unit tests. Until just recently, though, we only had support for running unit tests with grunt, using the PhantomJS browser. Well, that’s changed, with the first phase of our integration with Karma. Now, you’ll be able to run your tests in real browsers.

Setting things up is a snap. After you pull down the latest from video.js and run npm install, simply copy the test/karma.conf.js.example file to test/karma.conf.js, add the browsers you wish to test to the browsers array, and run grunt karma:dev. That’s it. Of course, there are more options that you can configure, but if you want to get the ball rolling quickly, just add browsers, and run the tests. See the test/karma.conf.js.example file for more instructions.

For our next phases of integration, we’re planning to include support for running tests on mobile devices, as well as running these tests in a publicly-available location, so that anyone can tell at a glance how things are going.

You can learn more about Karma here.

Cheers!

-Jim

Steve Heffernan2013-09-15

Unauthorized modification of Video.js CDN files

UPDATE 2013-09-19:

The CDN continues to be secure and we have taken significant steps to ensure it never falls under a similar attack again.

  • Access to the CDN has been restricted to a few key individuals
  • A third-party service is now monitoring changes made to the CDN
  • Processes have been defined for responding to any such future issues

The original source of this event was the Sendori Auto-update Hack, which possibly affected millions of people including, unfortunately, an admin of the CDN.


On the morning of September 14, 2013 at 6:25am PDST, we discovered that certain versions of video.js being served from our content delivery network (CDN) had been modified by an unknown attacker. The file was changed to contain malicious code that would attempt to install malware on any Windows or Macintosh computer that loaded the video.js file. The malware has been identified to be a variant of Trojan.PWS.Stealer.1932 or Trojan.Ransom.ED. We quickly reverted to safe versions of the video.js file, and took steps to ensure that the issue could not reoccur.

The specific files affected were:

vjs.zencdn.net/c/video.js

vjs.zencdn.net/4.0/video.js

vjs.zencdn.net/4.1/video.js

No patch-level versions (e.g. vjs.zencdn.net/4.1.0/video.js) were affected, and neither was the latest version (4.2). Users who host their own copy of Video.js were also not affected.

Potential Impact: Any browsers that loaded the affected files during the compromised period may have prompted users to install malicious software on their computers.

It has been determined that the files were originally modified at 4:30am PDST. The files were repaired at 7:15am PDST and completed propagation to CDN edge caches around the world at 7:51am PDST.

Rest assured that video.js is once again safe to load. We are currently investigating the root cause. Once we fully understand the nature of the incident, we will provide an update with additional information.

Keeping our users safe is one of our top priorities, and we sincerely apologize to anyone who was negatively impacted by this event.

Steve Heffernan2013-09-06

Video.js 4.2.0 released! RTMP, CSS designer, and stability

Happy September! The 4.2.0 release of Video.js has a few interesting updates, and a bunch of stability and polish.

RTMP Support

First of all, thanks to an impressive collaboration of community members, we now have RTMP support (in beta). Check out the example.

Its still pretty basic support for RTMP, but we think it will cover a lot of the general use cases. The feature support includes:

  • Single stream (no client-side adaptive support)
  • Flash only, HTML5 video doesnt support RTMP (but HLS is supported on iOS devices)
  • On-demand only. We havent updated the UI to support live yet.

To load an RTMP stream in a Video.js player, youll use a source tag in the same way you would other source types:

<source
  src="rtmp://your.streaming.provider.net/cfx/st/&amp;mp4:path/to/video.mp4"
  type="rtmp/mp4"
/>

The connection and stream parts are determined by splitting the URL on the first ampersand (&) or the last slash (/).

[http://myurl.com/streaming&amp;/is/fun](http://myurl.com/streaming&amp;/is/fun) --&gt;
  connection: [http://myurl.com/streaming](http://myurl.com/streaming)
  stream: /is/fun

-or-

[http://myurl.com/streaming/is/fun](http://myurl.com/streaming/is/fun) --&gt;
  connection: [http://myurl.com/streaming/is](http://myurl.com/streaming/is)
  stream: fun

The available source types include rtmp/mp4 or rtmp/flv.

RTMP has been a much requested feature over the years and its great to finally have it in the player. Thanks to everyone involved in that work.

Player Skin Designer

If you missed the previous blog post, be sure to check out the new interface for designing the player skin. It really shows off the customizability of the video.js controls, which are built completely in HTML and CSS.

With the 4.2 release the styles in the designer have been brought up-to-date with the latest player styles.

Control Bar Updates

Also in a previous post, I described a number of updates that were made to the control bar to fix cross browser/device issues and improve the overall functionality. As of 4.2.0 all of those updates have made it into the stable release.

Other Updates

Along with previous updates theres been a number of patches and enhancements along the way. Heres a full list:

  • Added LESS as a CSS preprocessor for the default skin (view)
  • Exported MenuButtons for use in the API (view)
  • Fixed ability to remove listeners added with one() (view)
  • Updated buffered() to account for multiple loaded ranges (view)
  • Exported createItems() for custom menus (view)
  • Preventing media events from bubbling up the DOM (view)
  • Major reworking of the control bar and many issues fixed (view)
  • Fixed an issue with minifiying the code on Windows systems (view)
  • Added support for RTMP streaming through Flash (view)
  • Made tech.features available to external techs (view)
  • Minor code improvements (view)
  • Updated time formatting to support NaN and Infinity (view)
  • Fixed an undefined error in cases where no tech is loaded (view)
  • Exported addClass and removeClass for player components (view)
  • Made the fallback message customizable (view)
  • Fixed an issue with the loading spinner placement and rotation (view)
  • Fixed an issue with fonts being flaky in IE8

The latest version can be found on videojs.com through the download link or the CDN hosted version.

Cheers,

-heff

Steve Heffernan2013-08-09

Hiding and Showing Video Player Controls

Last week I decided to tackle a number of outstanding issues around the control bar, and then proceeded to fall down a rabbit hole of related player updates. Ive thankfully resurfaced now, and figured Id write about a few of the updates that came from it.

One of the expected behaviors of the players control bar is that it will fade out after a couple of seconds when the user is inactive while watching a video. Previously, the way we achieved this with video.js was through a bit of a CSS trick. When the users mouse would move out of the video player area, the control bar would be given the classname vjs-fade-out. This class had a visibility transition with an added 2 second delay.

.vjs-fade-out {
  display: block;
  visibility: hidden;
  opacity: 0;

  -webkit-transition: visibility 1.5s, opacity 1.5s;
  -moz-transition: visibility 1.5s, opacity 1.5s;
  -ms-transition: visibility 1.5s, opacity 1.5s;
  -o-transition: visibility 1.5s, opacity 1.5s;
  transition: visibility 1.5s, opacity 1.5s;

  /* Wait a moment before fading out the control bar */
  -webkit-transition-delay: 2s;
  -moz-transition-delay: 2s;
  -ms-transition-delay: 2s;
  -o-transition-delay: 2s;
  transition-delay: 2s;
}

When the users mouse moved back over the player, the class would be removed, canceling any delayed fade-out. This provided a similar experience to how you might expect the controls fading to work, and only took a few lines of javascript to add/remove the class.

player.on('mouseout', function() {
  controlBar.addClass('vjs-fade-out');
});

player.on('mouseover', function() {
  controlBar.removeClass('vjs-fade-out');
});

Theres a few drawbacks though that have made it necessary to move away from this approach.

  1. Controls dont fade out in fullscreen mode because the mouse can never move out of the player area.

  2. There is no mouse on mobile devices so different events and interactions are needed to show/hide the controls.

In addition to these issues, we want it to be possible for any player component or plugin to hook into the same trigger that hides the controls. Components like social sharing icons should fade out in the same way that the controls do.

User State

One of the first things that is being added is a userActive property on the player, that can be either true or false. What this does is abstract the controls hiding out to what it is were actually concerned with, that is, whether the user is currently interacting with the player or just passively watching the video. This also decouples the control bar from tracking the user activity itself, and allows other components to more easily behave the same way as the control bar, through a player-level state.

That actual property is player.userActive() and returns either true or false. When this value is changed, it triggers an event on the player.

player.userActive(true);
// -&gt; 'useractive' event triggered
player.userActive(false);
// -&gt; 'userinactive' event triggered

A CSS classname of either vjs-user-active or vjs-user-inactive is also added to the player element. The classname is whats actually used now to hide and show the control bar.

.vjs-default-skin.vjs-user-inactive .vjs-control-bar {
  display: block;
  visibility: hidden;
  opacity: 0;

  -webkit-transition: visibility 1.5s, opacity 1.5s;
  -moz-transition: visibility 1.5s, opacity 1.5s;
  -ms-transition: visibility 1.5s, opacity 1.5s;
  -o-transition: visibility 1.5s, opacity 1.5s;
  transition: visibility 1.5s, opacity 1.5s;
}

The 2 second delay has been removed from the CSS, and instead will be built into the process of setting the userActive state to false through a javascript timeout. Anytime a mouse event occurs on the player, this timeout will reset. e.g.

var resetDelay, inactivityTimeout;

resetDelay = function() {
  clearTimeout(inactivityTimeout);
  inactivityTimeout = setTimeout(function() {
    player.userActive(false);
  }, 2000);
};

player.on('mousemove', function() {
  resetDelay();
});

The mousemove event is called very rapidly while the mouse is moving, and we want to bog down the player process as little as possible during this action, so were using a technique written about by John Resig.

Instead of resetting the timeout for every mousemove, the mousemove event will instead set a variable that can be picked up by a javascript interval thats running at a controlled pace.

var userActivity, activityCheck;

player.on('mousemove', function() {
  userActivity = true;
});

activityCheck = setInterval(function() {
  // Check to see if the mouse has been moved
  if (userActivity) {
    // Reset the activity tracker
    userActivity = false;

    // If the user state was inactive, set the state to active
    if (player.userActive() === false) {
      player.userActive(true);
    }

    // Clear any existing inactivity timeout to start the timer over
    clearTimeout(inactivityTimeout);

    // In X seconds, if no more activity has occurred
    // the user will be considered inactive
    inactivityTimeout = setTimeout(function() {
      // Protect against the case where the inactivity timeout can trigger
      // before the next user activity is picked up  by the
      // activityCheck loop.
      if (!userActivity) {
        this.userActive(false);
      }
    }, 2000);
  }
}, 250);

That may be a lot to follow, and its a bit simplified from whats actually in the player now, but essentially it allows us to take some of the processing weight off of the browser while the mouse is moving.

Hiding controls in fullscreen

Thanks to the new userActive state and the javascript timeout for the delay, the controls no longer require the mouse to move outside of the player area in order to hide, and can now hide in fullscreen mode the same way they do when the player is in the page. This also means we can now hide the mouse cursor in the same way we do the controls, so that it doesnt sit over the player while watching in fullscreen.

.vjs-fullscreen.vjs-user-inactive {
  cursor: none;
}

Hiding controls on touch devices

The expected behavior on touch devices is a little different than in desktop browsers. There is no mousemove event to help determine if the user is active or inactive, so typically a longer delay is added before the controls are faded out. Also, while a click on the video itself in desktop browsers will typically toggle between play and pause, a tap on the video on mobile devices will toggle the controls visibility.

Luckily the framework weve set up around userActive has made this last part easy enough to set up.

video.on('tap', function() {
  if (player.userActive() === true) {
    player.userActive(false);
  } else {
    player.userActive(true);
  }
});

Manually toggling userActive between true and false will apply the appropriate classnames and trigger the events needed to show and hide the controls as youd expect on a mobile device.

The tap event is actually a custom made event, similar to the tap event youll find in jQuery mobile, Hammer.js, and other mobile touch libraries. A tap event occurs whenever a touchstart event is fired with the associated touchend event firing within 250 milliseconds. If the touchend event takes longer to fire, or if a touchmove event happens between the two, it is not considered a tap.

Conclusion

I hope this has given some insight into how that piece of the controls operate in Video.js, and how you can mimic the same interaction if youre building your own plugins for Video.js. Feedback is always appreciated.

Cheers,

-heff

Steve Heffernan2013-07-15

New Player Skin Designer for Video.js

Last week Brightcove had an internal hack week where everyone could work on any project they wanted. One of the projects that came out of that was a new video.js skin designer.

The designer allows you to watch changes happen to the skin live as you edit the CSS, making it easier to create a custom look.

Check out this familiar looking example that was done in just a few minutes.

Try creating your own and let us know what you think. Better yet, create your own, share it on CodePen.io and post a link in the comments. (Its probably easiest if you start by forking this unedited example.)

One of my favorite things about video.js is that the skins are built in HTML and CSS, while working across both HTML5 and Flash video. I think this designer does a nice job of showing off how easy that makes it to customize a players skin.

Some notes on how we built it

As a starting point we used Brian Frichettes awesome LESS2CSS, which gave us a huge head start. Brian has offered to help with the skin designer as well, so thats great!

We havent added a CSS preprocessor to video.js before because we didnt want the extra layer of abstraction, or the extra step in the build process. When looking at the CSS in the new designer however, it became clear how valuable things like variables can be for helping people understand whats happening in the CSS. Still, were trying to find the balance between using LESS features and keeping the CSS easily readable by anyone who just knows CSS. That means avoiding some of the more advanced LESS features like conditional statements (though we do use one for big play button positioning).

We chose to use LESS because of the ability to parse the LESS markup in javascript in the browser. Im not aware of any up-to-date in-browser SASS parsers. The completeness of LESS2CSS also influenced that decision. Were using a small enough subset of features that it doesnt really matter which one we use otherwise, though I do like the idea of using \$ for variables over @.

Its hosted on Nodejitsu, and were taking advantage of their free hosting for open source. I have to say, it was pretty simple to get the app deployed with their command line tool.

Let us know if you have any thoughts. The code for the designer can be found here: https://github.com/videojs/designer

Cheers,
-heff

Steve Heffernan2013-06-28

Video.js 4.1.0 Released

Just in time for the weekend, the next minor version of Video.js is now available. Updates include:

  • Turned on method queuing for unready playback technologies (flash) (view)
  • Blocking user text selection on player components (view)
  • Exported requestFullScreen() and cancelFullScreen() in the minified version (view)
  • Exported the global players reference, videojs.players (view)
  • Added google analytics to the CDN version (view)
  • Exported fadeIn/fadeOut for the Component API (view)
  • Fixed an IE poster error when autoplaying (view)
  • Exported bufferedPercent for the API (view)
  • Augmented user agent detection, specifically for Android versions (view)
  • Fixed IE9 canPlayType error (view)
  • Fixed various issues with captions (view)

You can get the latest version on videojs.com, either as a download or hosted on our CDN.

Have a great weekend!

-heff

Steve Heffernan2013-05-09

Video.js 4.0 now available!

Today were releasing Video.js 4.0, which is the most solid, lightweight, and I dare say prettiest version yet. Its available for download, on Github, and hosted for free on our CDN.

Version 4.0 received the most community collaboration of any previous version, which speaks to the growing strength of the JavaScript community, the growing popularity of HTML5 video, and an increase in Video.js usage. Over the last year the number of sites using Video.js has more than doubled, and each month there are over 200 million hits to the CDN-hosted version alone! Thank you to all of the Video.js community members for contributing code and filing bug reports.

This version is also a milestone in that its the first version released since Brightcove acquired Zencoder last year. For those who missed the announcement, it was a very good thing for Video.js. In the past, Video.js was a side project for Zencoder that I maintained on top of my regular responsibilities (as if startup life isnt exciting enough). Post-acquisition, Brightcove has not only put me full-time on Video.js, but the Brightcove video player team has become contributors to the project. The Brightcove team is probably the most experienced video player team in the world, supporting the most advanced video technology, for the biggest brands, across all the devices. Its been a privilege to work with them and theyve made major contributions to this version.

4.0 Major Feature Summary:

Improved performance through an 18% size reduction using Google Closure Compiler in advanced mode

  • Greater stability through an automated cross-browser/device test suite using TravisCI, Bunyip, and Browserstack.
  • New plugin interface and plugin listing for extending Video.js
  • New default skin design that uses font icons for greater customization
  • Responsive design and retina display support
  • Improved accessibility through better ARIA support
  • Moved to Apache 2.0 license
  • 100% JavaScript development tool set including Grunt

Improved Performance

With version 4.0, performance was our top priority, and a major factor of performance is the time it takes to load the library. What would seem to be minor size reductions can have a big impact, especially when a library will be loaded millions of times a month all over the world. We chose to use Google’s Closure Compiler because its “advanced mode” currently provides the most aggressive options for code minification, and so far we’ve seen an 18% reduction in code size, with the potential for more.

Closure Compiler also claims to rewrite code for better runtime performance, though we haven’t had a chance to benchmark this yet.

Some preliminary load-time benchmarking* shows:

  • Player load times in under 50 milliseconds
  • Playback start times in under 150 milliseconds
  • Actual video playback seen in under 0.5 seconds (using a CDN hosted MP4)

*Initial tests used Chrome with an empty cache on a modern MacBook Pro with a Wi-Fi connection. More formal testing to follow.

Greater Stability

Automated cross-browser, cross-device testing is the Holy Grail of testing for a JavaScript library. While building version 4.0, we’ve been able to reach that goal through the use of a number of tools, including:

  • TravisCI - Automatically runs unit tests through PhantomJS on every pull request made to the Video.js source code
  • Bunyip + Browserstack - Allows us to run tests in cloud-hosted instances of any browser from IE6 to the latest Chrome, and also a wide range of iOS and Android devices.

This ability to easily run tests across environments before any new release will give us more protection against regressions, and can allow for a faster feature release cycle.

New Plugin Interface

The new plugins API allows developers to more easily add custom features to Video.js. The API works similarly to the jQuery plugin interface, giving developers access to add to or overwrite any piece of Video.js. Once a plugin has been created, it can be shared on the Video.js plugin list page on the wiki.

New Default Skin

With help from the Brightcove UX team, we’ve created a new default skin that’s simpler, more polished, and more customizable. One of the most interesting features is that we’ve moved from using images for icons to font icons. The use of font icons allows you to change the color and size of the icons simply by changing a CSS value. You can see an example of this on the Video.js homepage.

Improved Accessibility

Greg Kraus, a Video.js community member from NCSU.edu, did some great work testing and improving Video.js accessibility through better use of ARIA roles. The changes make it so keyboard-only users, screen reader users, and voice-interface users will be able to interact with the video player. UPDATE: Read more in Gregs blog post.

Moved to Apache 2.0 License

Earlier versions of Video.js were released under the LGPLv3 license. LGPL often gets confused with its stricter sibling, GPL, which requires that all code the software touches must also be open source. Video.js is meant to be open and free to use in all contexts, and we want that to be clear, so version 4.0 is now released under Apache 2.0, the same license Twitter Bootstrap is released under.

100% JavaScript Tool Set

Previously Video.js used Ruby for development tools, including Rake for deployment tasks, and zenflow–an internal Zencoder tool that builds on gitflow for development process workflow. With 4.0 we’ve moved to Grunt for tasks and we’re building out a tool similar to zenflow in Node.js.

Videojs.com Now Open Source

As part of this release we’ve also made the Videojs.com website open source. So if you see something that should be added or fixed, fork it.

What now?

Even with all of the updates listed above, this is simply a jumping-off point for what will be an exciting year for Video.js. We’re continuing to improve performance, multi-platform stability, and customizability through plugins and skins. Members of the community have already started work on plugins for some of the more requested features, like playlists, analytics, and advertising.

Follow @videojs or sign up for our newsletter to stay up-to-date on new features and roadmap updates.

If you’d like to get involved in the project, check out our contributing guide.

Cheers,
-heff

Steve Heffernan2013-05-06

Repo Moved!

In preparation for the next version weve moved the source code repository from github.com/zencoder/video-js to github.com/videojs/video.js

If you have a local clone you can update your clones upstream URL with:

git remote set-url upstream git://github.com/videojs/video.js.git

The relationship between your fork (e.g. github.com/you/video-js) should still be intact, including any pull requests.

Cheers,
-heff

Steve Heffernan2012-11-15

Site and Support Updates

After a brief hiatus of helping Brightcove and Zencoder come together, Im moving full time to developing and supporting Video.js. Thank you to everyone who has continued to commit code and help out in the forums.

As part of this move Im trying to optimize the tools used for video.js project management and support. The first big change is that the forums are being replaced with Stack Overflow (tag with video.js) and Github Issues.

Over the last few years Video.js has become more popular than I ever expected, and at the same time Stack Overflow has come up as an incredible tool for supporting developer communities. So along with many other projects like Facebook, Android, and HTML5 Boilerplate, Im excited to move support to Stack Overflows awesome tool and community. Ill be leaving the forums up for bit but from here forward please post questions to Stack Overflow and use the video.js tag.

Ive also begun cleaning up and organizing the Github Issues for Video.js, which previously existed, but issues were split between the forum and Github. If you find specific bugs with video.js please submit them there.

On the project management side of things Ill be using Trello, and exposing boards so others can see the progress of development.

Im also paring down the site and moving more complex sections to other services that can better handle them. Ive already moved the blog to Tumblr, and Im moving the docs to the Github repo, which has built-in docs formatting.

For those starting an open source project today, you can look at this as my guide to supporting an open source project. I wish I would have know to do all this when I started on Video.js.

More project updates coming soon.

Cheers,
-heff

Steve Heffernan2012-07-26

Brightcove Acquires Zencoder

Today, Zencoder announced that it is being acquired by Brightcove, the leading online video platform (OVP). You can read more on the specifics in the Zencoder blog post and press release, but I also wanted to be clear on what this means for Video.js. As you may know, Video.js was created by me (Steve Heffernan, Co-founder of Zencoder) and Zencoder continues to be its core contributor and sponsor (like 37signals to Rails or Joyent to Node.js).

This acquisition means only great things for Video.js. To quickly summarize, Video.js will continue to be a free and open source video player & framework, and Brightcove will be investing more in Video.js than Zencoder ever could.

I wrote the first version of Video.js in early 2010 during Zencoder’s time in Y Combinator (while secluded in our rented house deep in the Santa Cruz mountains). Over the past few years I’ve continued to build the library and pull in contributions from other Zencoder team members and the community, but only on the side of my ongoing Founder and VP of Marketing duties at Zencoder. While Video.js has continued to gain popularity among developers and is now being used on over 25,000 websites, there’s still work to be done and room to grow. So one of the more significant changes that will be happening is that Brightcove will be putting me on Video.js full time, freeing me up to work on the core of the project and to better support the Video.js community, both users and contributors.

Beyond this, Brightcove has a first-class player development team backing their platform’s video player. While the specifics of how the two teams and players will work together are still being discussed, we have agreement on our philosophies and views about where player technology is going. This combined knowledge and collaboration is sure to have a positive impact for both players.

While the additional resources will have a big impact, the best open source software projects only got to where they are through the contributions of developers in the community. So if you’ve previously been cautious to dig into the source or push back a specific feature or bug fix, I hope this news only helps encourage you to jump in and help make Video.js the best resource for working with video in the browser.

There will be more info to come as things progress, but please feel free to ask any questions in the comments below.

Cheers,

Steve & The Zencoder Team