Media players made easy with

OSMF

Introduction

Since the first sneak-peeks about OSMF I knew it will be something worth getting interested in. Now it’s even better time, because its APIs have just been locked down along with the release of OSMF Sprint 10 (ver. 0.93). It means that all future changes or fixes won’t break your code. So, what is the Open Source Media Framework (codename Strobe). To be simple, it helps wherever it can in case of media players saving your time, so you can spend more time polishing user experience. To be more precise:

Open Source Media Framework (OSMF), currently in public prerelease, enables developers to easily assemble pluggable components to create high-quality, full-featured playback experiences. The open aspect of the framework enables collaborative development for web video monetization, with lower costs and faster turnaround.

http://osmf.org/

Foundation

Time to describe the basic bricks of OSMF:

  • MediaElement – basic class that contains all informations about media you want to use. It has lots of inherited classes, but here are the most important ones I used in the example: VideoElement, AudioElement, SWFElement, ImageElement, ParallelElement and SerialElement. Media Element’s subclasses have to be added to MediaPlayer and MediaContainer classes to be used.
  • VideoElement – As described above it containes all informations about video we want to play. As all loadable MediaElements it needs URLResource instance providing URL to the video.
    var videoElement:VideoElement = new VideoElement(new URLResource(VIDEO_URL));
    
  • MediaPlayer – this is the controller class that controlls all MediaElements assigned to it. It stores some important informations about the assigned media. These are called „traits”. Traits define the capabilities of a media element. Here are some of them: canPlay, canPause, canSeek or canLoad. They are quite self-explanatory and are very helpful while setting available elements of User Interface. A media we want to use is assigned to media property. If we want to listen to some events we add event listeners to MediaPlayer instance.
    var mediaPlayer:MediaPlayer = new MediaPlayer();
    mediaPlayer.media = videoElement;
    
  • MediaContainer – Classes described above were only „virtual” classes with no visual representation. Then it’s time for the class that can be added to the stage. It layouts and renders assigned content (MediaElement). MediaContainer inherits from Sprite. A media we want to use is assigned by addMediaElement method.
    var mediaContainer:MediaContainer = new MediaContainer();
    mediaContainer.addMediaElement(videoElement);
    addChild(mediaContainer);
    

User Interface

That’s all for the basics needed to create the most primitive video player. But that kind of video player has no User Interface, so it could only show the video without any user control. Whole the UI we have to asseble from scratch, because it’s independent from the media and MediaPlayer class is just the interface by which you control the media. It up to you how the UI will look like and how it will behave. But there’s an option, if you want to use just standard components and behavior. There’s a library in OSMF project called Chrome Library. It is ready to use and you can find it in zipped in the following path: source/libs/ChromeLibrary/. You can find a sample using this library with all needed comments here: source/apps/samples/framework/OSMFPlayer.

In my example I’m using MinimalComps by Keith Peters aka BIT-101. It seems to be the simplest set of basic components you may need in your test or sample apps. You need just one line of code to set in on stage with right behaviour and needed listeners. By using MinimalComps we don’t need Flash to compile it. All we need is Flex SDK along with your favourite code editor. I’m using FlashDevelop BTW. All the UI is created within createUI() function. I think I don’t need to describe this part of code, because it’s not in the scope of the post. If you have any questions, post them in comments at the bottom.

Layout

OK then. We have our movie displayed on the stage and it plays. We have working User Interface. It looks like this:

Application layout

Now we want to how it should be laid out in the MediaContaier. And here is the class we need: LayoutMetadata. It is stored in layoutMetadata property of all classes implementing ILayoutTarget interface. LayoutMetadata contains lots of different parameters which will will layout our content. Here they are:

  • horizontalAlign and verticalAlign (accept static constants stored in HorizontalAlign and VerticalAlign classes);
  • x, y, width and height;
  • percentX, percentY, percentWidth and percentHeight;
  • scaleMode (accept static constants stored in ScaleMode class);
  • layoutMode (accept static constants stored in LayoutMode class);
  • left, right, top and bottom;
  • paddingLeft, paddingRight, paddingTop and paddingBottom;
  • snapToPixel
  • includeInLayout
  • synthesizer

I think most of them need no explanation. If not here is all you need: OSMF Language Reference.

In my sample player I added an option to dynamically change content scaling options (little round control in top right corner) If we want to set how the content should be laid out we have to change parameters of layoutMetadata property. In case of MediaElement we’ve got to create new LayoutMetadata instance, set all params we need and assign to the MediaElement by addMetadata method. Following sample turns scaling off (sets to 100%) and aligns video to the center of the container.:

//Assign layoutMetadata to mediaContainera (MediaContaiener)
mediaContainer.layoutMetadata.width = videoCont.width;
mediaContainer.layoutMetadata.height = videoCont.height;
mediaContainer.layoutMetadata.scaleMode = ScaleMode.NONE;

//Assign layoutMetadata to videoElementu using addMetadata method (MediaElement)
var layoutMetadata:LayoutMetadata = new LayoutMetadata();
layoutMetadata.scaleMode = ScaleMode.NONE;
layoutMetadata.width = videoCont.width;
layoutMetadata.height = videoCont.height;
layoutMetadata.horizontalAlign = HorizontalAlign.CENTER;
layoutMetadata.verticalAlign = VerticalAlign.MIDDLE;
videoElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata);

MediaElement

Now we can extend the informations about different MediaElements we use in the sample player. The base class is MediaElement. When we have MediaPlayer and MediaContainer instances ready all we need is just to create new MediaElement‚s subclass instance and assign it like this:

var myVideo:VideoElement = new VideoElement(new URLResource(VIDEO_URL))
mediaPlayer.media = myVideo
mediaContainer.addMediaElement(myVideo);

Here we added the videoElement to the mediaPlayer to be able to control it and also added it to mediaContainer to display it. With this bit of code we assigned mediaElement we want to use. What’s interesting we can easily change actually displayed media. You just need to remember to remove current mediaElement from the mediaContainer using removeMediaElement method.

Now I’ll describe MediaElements used in the player:

  • AudioElement – It supports both streaming and progressive formats. AudioElement can load and present any MP3 or AAC file. It supports MP3 files over HTTP, as well as audio-only streams from Flash Media Server.
  • ImageElement – Usign this class you can show any image formats supported by the FlashPlayer (i.e. PNG, GIF and JPG.
  • SWFElement – Here you can load and display any swf file.
  • ParallelElement – It adds a list of media elements which are played in the same time, e.g. am image with some music in background or video with different available sound tracks.
  • SerialElement – It adds a list of media elements which are played one after the other, e.g. series of videos. IMPORTANT: It’s not designed to be used as a playlist.

Bear in mind that all layout settings described before are applicable to all kind of MediaElement, of course if they can be displayed. And here is the problem, how do we know which properties can be changed in current media element?

Traits

It’s time for the concept of Traits. Traits define the capabilities of a media element. They describe what actions can be applied to the current media element. They can be easily accessed by MediaElement properties. Here are some of them: canPlay, canPause, canSeek, canLoad or hasAudio. If we want to know how they change (e.g. to disable UI elements which cannot be used) all you need to do is to add eventListeners to mediaPlayer:

mediaPlayer.addEventListener(MediaPlayerCapabilityChangeEvent.CAN_PLAY_CHANGE, onCanPlayChange);
mediaPlayer.addEventListener(MediaPlayerCapabilityChangeEvent.CAN_SEEK_CHANGE, onCanSeekChange);

private function onCanPlayChange(e:MediaPlayerCapabilityChangeEvent):void
{
playPauseBtn.enabled = e.enabled
stopBtn.enabled = e.enabled
}

private function onCanSeekChange(e:MediaPlayerCapabilityChangeEvent):void
{
progressBar.enabled = e.enabled
}

Now we are sure that our media has all needed controls for it.

Source

You don’t need Adobe Flash authoring tool to compile the player. All you need is Flex SDK. One important thing I didn’t mention. You have to target Flash Player 10 because it’s needed by OSMF. Of course you can compile it in Flash authoring tool using Document Class and addingOSMF and MinimalComps SWCs to the Publish Settings.

All the code is licensed under MIT license, so you can do use it freely.

Live player: link;
Player source: link;

OSMF: osmf.org;
OSMF downloads: link;
OSMF Language Reference: link;

Summary

Open Source Media Framework is great framework for all of them, creating lots of different media players. It will help you to spend more time being creative, and not freaked out about constant different problems about videos. It has very friendly and intuitive APIs, so once you learn it you’ll stick with it.
If you’ll find any bugs, ideas or just want to say thanks, feel free to post comments. All of them are words of appreciation for me no matter if good or bad (but no spam ;)) and motivates me to post more of tutorials like this one.

Thanks,
Michał Wróblewski
@wrobel221