Home  >  

Akamai Open Video Player (OVP) initiative part of the Adobe Strobe framework

Author photo
AddThis Social Bookmark Button
There are many challenges involved in building Qos (quality of service) video player, let’s take a look:
  • User bandwidth detection
  • Support streaming and progressive download
  • Dynamic switching of bitrate profiles
  • Buffer policy
  • Monitor of NetStream messages
  • Improvement of seeking
  • DVR integration
  • Working with playlists
  • Frame drop policy
  • DRM
  • Overcome network proxy issues
  • Error handling
  • Live streams
As you can tell, the evolving complexity of the video player is hard to follow and implement, not to mention a tedious task that some of the most sophisticated developers out there will be glad to avoid. It can become pretty challenging to create a smart video player that takes into account these features, as well as new features.

Last year, Akamai has started an open source (sourceforge BSD through V1) project called the Open Video Player (OVP) (http://openvideoplayer.sourceforge.net/) that is an open source video player that address many of the challenges involved in building a high quality video player.

Adobe recently announced that they would adopt the OVP project and include it as part of the Adobe Strobe (http://www.adobe.com/products/strobe/).

Dynamic switching of video profiles

To understand how the OVP player work let’s take a look at the business diagram at figure below:

OVP_business_digram1.jpg

Getting the video information

The implementation or entry point will begin with a media XML file called SMIL that the user selects. The SMIL file can be hosted on a CMS and once the user selects a video file we can call the SMIL file, which will contain all the information that we need such as the host name and the different profile files. The DynamicSmilParser is based on ParserBase and includes URLLoader to load the SMIL file and method to check the integrity of the XML nodes.

Once the SMIL is loaded it is turned into a class called DynamicStreamItem, which holds the streams URLs and points to the video files and the bitrate of each video file.

Creating a NetConnection

Once the SMIL file is loaded the AkamaiConnection (which is the implementation of the super class OvpConnection) connect to the host name we received from the SMIL. OvpConnection builds an array of connection strings to be used in streaming and tries to connect to find out available connections.

Play stream

Once a connection was found OvpConnection.handleGoodConnect method calls NetConnection.Connect.Success event. The event will reach the AkamaiDynamicNetStream, which is a wrapper for the NetStream. At this point we can play the video. Note that to play the video. The AkamaiDynamicNetStream.play method calls the super class OvpDynamicNetStream.play method, which calls startPlay method to start playing the video as well as start a timer. The timer has an event listener that checks every 500 ms the switching rules.

OVP_business_digram2.jpg

Switching rules

During the first time the video is playing the application checks for the user’s bandwidth and adjusts to the appropriate profile. Every 500 ms there are three rules currently available with the OPV that will be examined:
  1. Bandwidth rule - holds the switching rule for bandwidth detection.
  2. Frame drop rule - holds the switching rule for drop of frames detection.
  3. Buffer rule - holds the switching rule for buffer detection.
Each rule is based on ISwitchingRule contract and can be configured, created or replaced easily. The rules are using a metric provider, which listen to NetStatusEvent messages such as NetStream.Buffer.Full or NetStream.Buffer.Empty as well as the NetStreamInfo and has an update method, which keeps information regarding the health of the stream so we can make a better decision every time we examine the switching rules.

Switching of video

Once the logic indicates that there is a need to switch the video with a different profile, the NetStream.play2 method is used.

OVP_business_digram3.jpg

Let’s take a look at part of implementation of the OVP core classes, so you can better understand how it works;

Once the application was created the init method is called, which creates new instances and adds event listeners to some of the class variables such as the SMIL parser and the AkamaiConnection. It also adds the video to the stage and sets the transition timer and location.
 

private function init():void {		
 	stage.addEventListener(FullScreenEvent.FULL_SCREEN, handleReturnFromFullScreen);
 
 	_smilMetafile = new DynamicSmilParser();
 				_smilMetafile.addEventListener(OvpEvent.PARSED,bossParsedHandler);
 	_smilMetafile.addEventListener(OvpEvent.ERROR,errorHandler);
 
 	_nc = new AkamaiConnection();
 	_nc.addEventListener(OvpEvent.ERROR,errorHandler);
 				_nc.addEventListener(NetStatusEvent.NET_STATUS,netStatusHandler);
 				
 	addVideoToStage();
 				
 	_transitionMsgTimer = new Timer(_TRANSITION_MSG_DISPLAY_TIME_);
 	_transitionMsgTimer.addEventListener(TimerEvent.TIMER, onTransitionMsgTimer);
 				
 	var pt:Point = videoWindow.contentToGlobal(new Point(videoWindow.x, videoWindow.y));
 	pt = transitionInfoContainer.globalToContent(pt);
 	transitionInfoContainer.x = pt.x;
 	transitionInfoContainer.y = pt.y + videoWindow.height - transitionInfoContainer.height ;
 				
 	_lastSwitch = 0;
}

The addVideoToStage method will attach the video to the stage using the videoHolder placeholder that was set

private function addVideoToStage():void {
 	_videoHolder= new UIComponent();
 	_video = new Video(480, 270);
 	_video.smoothing = true;
 	_video.visible = false;
 	_video.x = (_videoHolder.width-_video.width) / 2;
 	_video.y = (_videoHolder.height-_video.height) / 2;
 	_videoHolder.addChild(_video);
         videoWindow.addChild(_videoHolder);
    }

The startPlayback method gets called from a load button and clears the old session as well as starts the load process of the SMIL file.

private function startPlayback():void {
 	output.text = "";
 	bPlayPause.enabled = false;
 	bFullscreen.enabled = false;
 	_hasEnded = false;
 	multiBRCtrls.visible = false;
 
 	// Clean up from previous session, if it exists
 	if (_nc.netConnection is NetConnection) {
  		_ns.useFastStartBuffer = false;
  		_nc.close();
  	}
 
 	// Start parsing the SMIL file
 	_smilMetafile.load(bossLink.text)				
}

Once the SMIL file was loaded we have the host name and we can establish a connection to the FMS server, _nc.connect(_smilMetafile.hostName); When the connection will be established the netStatusHandler handler will be called since it was set in the init method.

private function bossParsedHandler(e:OvpEvent):void {
 	write("SMIL parsed successfully:");
 	write("  Host name: " + _smilMetafile.hostName);
 	write("  Stream name: " + _smilMetafile.streamName);
 
 	// Establish the connection
 	_nc.connect(_smilMetafile.hostName); 
}

netStatusHandler method listens to a successful connection and errors. connectedHandler method sends a request to play the video based on the SMIL file and once that was achieved it calls connectedHandler.

// Receives all status events dispatched by the active NetConnection
private function netStatusHandler(e:NetStatusEvent):void {
 	write(e.info.code);
 	switch (e.info.code) {
  		case "NetConnection.Connect.Rejected":
  			write("Rejected by server. Reason is "+e.info.description);
  			break;
  		case "NetConnection.Connect.Success":
  			connectedHandler();
  			break;
  	}
}

Once a connection was found and established, overcoming proxy firewalls when needed. The connectedHandler is called, which uses the AkamaiDynamicNetStream instance and passes the SMIL file information: _ns.play(_smilMetafile.dsi);

// Once a good connection is found, this handler will be called
private function connectedHandler():void {
 	_ns = new AkamaiDynamicNetStream(_nc);
 	_ns.addEventListener(OvpEvent.ERROR,errorHandler);
 	_ns.addEventListener(OvpEvent.DEBUG, debugMsgHandler);
 	_ns.addEventListener(OvpEvent.COMPLETE,completeHandler); 
 	_ns.addEventListener(OvpEvent.PROGRESS,update); 
 	_ns.addEventListener(NetStatusEvent.NET_STATUS,streamStatusHandler);					_ns.addEventListener(OvpEvent.NETSTREAM_PLAYSTATUS,streamPlayStatusHandler);
 	_ns.addEventListener(OvpEvent.NETSTREAM_METADATA,metadataHandler);
 	_ns.addEventListener(OvpEvent.NETSTREAM_CUEPOINT,cuepointHandler);	
 	_ns.addEventListener(OvpEvent.SUBSCRIBE_ATTEMPT, handleSubscribeAttempt);		
 	_ns.isLive = true;
 	_ns.maxBufferLength = 10;
 	_video.visible = false;
 	_video.attachNetStream(_ns);
 	write("Successfully connected to: " + _nc.netConnection.uri);
 	write("Port: " + _nc.actualPort);
 	write("Protocol: " + _nc.actualProtocol);
 	write("Server IP address: " + _nc.serverIPaddress);
 	_ns.play(_smilMetafile.dsi);
}

The errorHandler method will handle all the error events generated from the SMIL parser (DynamicSmilParser), net stream (AkamaiDynamicNetStream) and net connection (AkamaiConnection).

private function errorHandler(e:OvpEvent):void {
 	switch(e.data.errorNumber) {
  		case OvpError.INVALID_INDEX:
  			handleInvalidIndexError();
  			break;
  		case OvpError.STREAM_NOT_FOUND:
  			Alert.show("Connected to the server at " + _nc.serverIPaddress + " but timed-out trying to locate the live stream " + _smilMetafile.streamName, "UNABLE TO FIND STREAM ", Alert.OK);
  			break;
  		default:
  			Alert.show("Error #" + e.data.errorNumber+": " + e.data.errorDescription, "ERROR", Alert.OK);
  			break;
  	}
}
See screen shot below:
OVP_implementation.jpg

Enhance progressive download seeking

We showed how the OVP handles dynamic switching of bitrates profiles. Additionally, OVP provides service called Akamai JumpPoint (TM) which provides the ability to instantly seek progressively delivered FLV files beyond the point at which they have been downloaded, as well as preventing the FLV data from being cached in the client system. This feature is a major enhancement since it allows us to overcome two disadvantages that HTTP service has over streaming. Keep in mind that the service requires using the Akamai JumpPoint service and will not work on a standard HTTP server. The JumpPoint service can be used with the AkamaiEnhancedNetStream class, which extends the AkamaiNetStream class.

Read more from Elad Elrom. Elad Elrom's Atom feed

Comments

4 Comments

Jan said:

looks like competition for JW Player

Anonymous said:

I hope the other CDNs launch initiatives like this. Perhaps standards can be established based on OVP.

Elad Elrom said:

That's what Adobe are trying to achieve with Strobe:
http://www.insideria.com/2009/05/adobe-strobe-framework-review.html

Leave a comment


Tag Cloud

Question of the Week: Dream App

If you had an unlimited budget and unlimited resources what application would you build and why would you build it?

Answer

Latest Features

Recommended for You

@InsideRIA on Twitter

Archives

  • Or, visit our complete archive.  

About This Site

Welcome to the premiere community site for all things RIA sponsored by O'Reilly Media and Adobe Systems Incorporated.