This is a message.

Writing a Streaming plugin

Characteristics of a streaming plugin

  • Responsible for loading video content into the player.

  • Allows you to implement streaming protocols that integrate with different streaming servers, video hosting networks or Content Delivery Networks.

  • Written with ActionScript 3.0

  • Must implement a StreamProvider class. The Flowplayer library contains a default implementation for this class and you can extend it to implement your own provider.

  • Loaded into the player upon configuration or at runtime using the loadPlugin() method. This method is available for JavaScript and for ActionScript.

Flowplayer uses a HTTP streaming provider by default which uses HTTP progressive download for loading video data. Other implementations interact with “pseudostreaming” or the RTMP streaming protocol.

Streaming plugin basics

In Flash 9, video streaming is typically done using the NetStream class. Flowplayer has a NetStream implementation called StreamProvider. This is the class your streaming provider must implement. By default, Flowplayer uses NetStreamControllingStreamProvider for streaming video data. This provider does HTTP progressive downloading which is the most common way to stream videos in the Internet today.

Usually you don't want to implement your provider from scratch. You will extend NetStreamControllingStreamProvider instead.

This way you don't need to implement all the methods shown in the interface below, but rather override and customize just those methods that you need to achieve your desired custom behavior. Both our RTMP and pseudostreaming providers are implemented this way.

StreamProvider interface

If you want to write a provider from scratch, this is the inteface that your provider must implement:.

public interface StreamProvider {
/
* Starts loading the specified clip. This method supports the
* following arguments:

* event: the event that this provider should dispatch once
* loading has started. After that the player will call
* getVideo()
* clip: the clip to load
* autoPlay: if false the playback is paused on the first frame
* and buffering is continued
/
function load(event:ClipEvent, clip:Clip, autoPlay:Boolean = true):void;
 
// Returns the flash.media.Video object for the given clip.
function getVideo(clip:Clip):DisplayObject;
 
// when playback is paused the provider should dispatch given ClipEvent
function pause(event:ClipEvent):void;
 
// when playback is resumed the provider should dispatch given ClipEvent
function resume(event:ClipEvent):void;
 
/

* Stops and rewinds to the beginning of the current clip. The
* given event should be dispatched once the stream has been
* successfully stopped.
/
function stop(event:ClipEvent, closeStream:Boolean = false):void;
 
/
* Seeks to the specified point in the timeline.
* The specified event should be dispatched once the seek is in target
*/
function seek(event:ClipEvent, seconds:Number):void;
 
/

* Is this provider in the process of stopping the stream?
* When stopped the provider should not dispatch any events resulting
* from events that might get triggered by the underlying streaming
* implementation.
/
function get stopping():Boolean;
 
// This object is attached to the NetStream.client property.
function set netStreamClient(client:Object):void;
 
// File size in bytes.
function get fileSize():Number;
 
// Current playhead time.
function get time():Number;
 
// The point in the timeline where the buffered data region
// begins, in seconds.
function get bufferStart():Number;
 
// The point in the timeline where the buffered data region ends,
// in seconds.
function get bufferEnd():Number;
 
// Does this provider support random seeking to unbuffered areas
// in the timeline?
function get allowRandomSeek():Boolean;
 
// Returns volume controller used to control the video volume
function set volumeController(controller:VolumeController):void;
 
// Stops loading data into the buffer.
function stopBuffering():void;
}

ActionScript 3

The load(clip:Clip) method initiates loading of a video clip. The provider should connect to the server and request the video in this method. Once the provider receives data from the server it should dispatch the event object that was passed to it. Similarly, all methods that receive an event as a parameter should dispatch the event object once the corresponding action has been performed.

Example plugin: YouTube provider

It's fairly simple to implement a provider that shows videos from YouTube. The goal in this example is to show videos from YouTube using the following configuration:

clip: {
// video ID that is shown in YouTube's video page
url: 'kNJ6S2UqsE',
provider: 'youtube'
},
plugins: {
// here is our plugin configuration
youtube: {
url: 'youtube-provider.swf'
}
}

JavaScript

The tricky part here is that YouTube changes the URLs of their video files frequently and therefore the URL of the video needs to be regenerated for each playback. The provider implemented here uses the approach presented in this from Adobe. The idea is to use a proxy server that requests a page from the YouTube site and parses its HTML source to find out the "secret" video ID. This ID is then used to form a URL that will load the actual FLV video file from the YouTube servers.

Below is our provider implementation. It uses a proxy server to generate URLs for the YouTube video files. All streaming logic is inherited from the NetStreamControllingStreamProvider superclass.

public class YouTubeProvider extends NetStreamControllingStreamProvider {
// this gets called by the player. It gives us our model object.
public function onConfig(model:PluginModel):void {
_model = model;
// onLoad event must be dispatched once our plugin is
// completely initialized, if initialization fails we need to
// call _model.dispatchError(PluginError.INIT_FAILED)
_model.dispatchOnLoad();
}
 
/
* Overrides the superclass connect() method to generate a URL for
* the clip before it's actually needed. The URL needs to be
* regenerated for each playback of the clip because YouTube
* changes the URLs frequently.
/
override protected function connect(
clip:Clip, startAfterConnect:Boolean = false
):void {
// store parameter value for later use
_startAfterConnect = startAfterConnect;
 
// generate a URL for the clip, we will call super.connect()
// once we have the URL
generateYouTubeUrl(clip);
}
 
/
* Generates a URL to fetch the video from YouTube. The URL is
* loaded from our proxy server that receives the YouTube videoId
* and knows how to generate the URL based on that.
/
private function generateYouTubeUrl(clip:Clip):void {
var loader:URLLoader = new URLLoader();
 
// add a listener that gets called when loading is complete
loader.addEventListener(Event.COMPLETE, onUrlLoaded);
 
loader.load(
new URLRequest("http://flowplayer.org/youtube/" + clip.url)
);
}
 
/
* Triggered when we receive a response from the proxy.
/
private function onUrlLoaded(event:Event):void {
var loader:URLLoader = event.target as URLLoader;
 
// store the url as the clip's custom property
clip.setCustomProperty("youTubeUrl", loader.data);
 
// now we are ready to proceed with the connect
super.connect(clip, _startAfterConnect);
}
 
/
* Superclass uses this function whenever it needs the clip's url
/
override protected function getClipUrl(clip:Clip):String {
// use the url that was loaded from the proxy
return clip.getCustomProperty("youTubeUrl") as String;
}
}

ActionScript 3

Flash requires the main class of a SWF to be a DisplayObject, typically a Sprite or a MovieClip. A provider is not a visual object and therefore we need a way to create and pass the provider to the player from the plugin SWF's main class. To achieve this our plugin's main class implements the PluginFactory interface:

public class YouTube extends Sprite implements PluginFactory {
/*
* The factory method to create our provider plugin.
/
public function newPlugin():Object {
return new YouTubeProvider();
}
}

JavaScript

To build our plugin use the YouTube class shown above as your FLA's document class or as the main class when building with the Flex SDK's mxmlc compiler.

Here is a Java implementation for the proxy used to generate the URL based on the video ID. This needs to be installed on a Web server.

TODO: Add the proxy source here

JavaScript

We recommend that you download the source code of the RTMP and pseudostreaming providers from their own documentation pages. Study those to learn more!