Playing Video with JavaScript (AIR)

It is unfortunate but true that the HTML control in AIR Beta 2 does not yet support Flash content. Depending on the requirements of your application however, you shouldn’t let this stop you from using Flash content in your HTML-based AIR application. Huh? It’s important to remember that the HTML control is integrated, and indeed part of the very display pipe that is the Flash Player in AIR. To demonstrate this I put together a very simply Flash Video (FLV) player using HTML, JavaScript and AIR.

html-video-player.jpg

When you develop an HTML application for AIR, what do you see when you run it? What you see, at a high level, is the rendering of your application by WebKit, but you’re not directly seeing WebKit itslef. The output is actually displayed by Flash. The HTML control itself is a control put on the Flash “stage” and set to take up the entire viewable area. In Flash, the HTML control is considered to be just another “display object”.

The great thing about this is that you can instantiate additional Flash display objects and add them to the stage. You can even draw vectors on those display objects. Essentially, you’ve got all of JavaScript and all of Flash (ActionScript) at your fingertips, using only JavaScript as the language. One of the additional display objects available to you from Flash is a “Video” object. You can instantiate the Video object and add it to the Flash stage using the following code.

var video = new air.Video();

window.htmlControl.stage.addChild( video );

To connect to a video file, you need two additional classes from Flash; NetConnection and NetStream. The NetConnection object tells the runtime where the video file is located. It can be a remote file, or in the case of AIR, a local file. The NetStream class is what actually controls the flow of video. The NetStream class has a NetStream.play() method as an example. When you have a stream, you attach it to your Video object via Video.attachNetStream().

conn = new air.NetConnection();
conn.connect( null );

// Prepare to play the video stream
// Handle stream status and meta data availability events
stream = new runtime.flash.net.NetStream( conn );
stream.client = this;
stream.addEventListener( air.NetStatusEvent.NET_STATUS, doStatus );	

// Setup the video display object
// Attach the video stream to the display object
video.attachNetStream( stream );

Note that the NetStream must have a client assigned to it. The client will be called at various points in working with the video stream. One such call will occur when enough of the video has been read to use the meta data contained in the header. This generally includes details like the duration of the video. The other is a “status” which can be called for any variety of reasons, most notably for this example, when the video file has been read fully into the buffer and is ready to play.

// Called when meta data is available about the video itself
function onMetaData( e )
{
    // Get the total time in the video to control playhead
    totalTime = Math.floor( e.duration );

    // Make sure the metadata exists before adjusting the window
    if( e.width != null )
    {
        // Set the video display size
        video.width = e.width;
        video.height = e.height;

        // Set the video width and height for sizing
        fit( e.width, e.height );

        // Center the window on the screen
        center();
    }
}

// Called when stream information is available
function doStatus( e )
{
    // Check to see if the video has been loaded
    // Pause once complete to prevent autoplay
    if( e.info.code == NETSTREAM_BUFFER_FULL )
    {
        stream.pause();

        // Reset the playhead
        document.getElementById( 'viewport' ).contentWindow.childSandboxBridge.resetPlayhead();
    }
}

Using the duration meta data, it is possible to configure a playhead to scroll along the bottom of a progress bar. The status is used in this case to pause the video as soon as it is loaded, otherwise the stream will automatically play the video (which may be what you want).

The size of the video is where things get a little tricky. Ideally, the meta data should contain the dimensions of the video. The problem unfortunately, is that many videos encoded for Flash’s first video codec, the Sorenson codec, don’t have this information. One example is all the YouTube videos. Luckily, we know that YouTube videos will weigh in at 320 x 240 and can account for that. If you want more details, it’s also possible to parse the video file data at binary level to determine width and height if it is not present in the meta data.

This technique isn’t limited to just video, though it’s the most visually appealing example. Other Flash classes such as Sprite and Shape can also be instantiated and added to the stage. This is how you can accomplish additional vector drawing features. You can even load other (pre-existing) Flash content using this technique. While the player is very simplistic in nature, and there’s still plenty of work to be done (on the progress bar specifically), I’m making the source available.

The downside to this approach is largely that the objects added to the stage, stay where there are put. If the HTML page scrolls the display objects will stay where they are located. They are essentially floating on top of the HTML control itself. In many cases, when we’re building an application for the desktop with AIR, things staying put actually works out great, so this may just be ideal for your next application. This also opens the door for other visually interesting effects (like applying Flash filters to HTML content).

WordPress database error: [Can't open file: 'wp_comments.MYI' (errno: 145)]
SELECT * FROM wp_comments WHERE comment_post_ID = '122' AND comment_approved = '1' ORDER BY comment_date

Leave a Reply