Simplifying StageVideo with StageVideoProxy

Adobe recently took a large step in changing the way video gets rendered in the Flash player. For the most part the player has always taken a large role in rendering video to the screen. With the release of Flash player 10.2 this has all changed. Now if you explicitly tell the player to, you can offload the video completely to the hardware which decreases CPU usage (literally to 0%), lowers memory usage, enables higher frame rates, and overall enables greater pixel fidelity and video quality.

Obviously with all the upcoming phones, tablets, and connected TVs this has an even higher impact on a video applications experience. At Dreamsocket we’ve been fortunate enough to be an early adopter with projects on these platforms. From developing video player’s tailored for Android phones to creating Cartoon Network and Adult Swim’s GoogleTV apps, we’ve been able to see the impact this new change has, in addition to figuring out the best way to integrate it into existing applications.

All that said, the one thing that really struck us was how unique the new StageVideo API is. I say unique because it is a completely new API and is completely different than working with the Video object. I understand the differences, however do you really need to force someone to go back and recode everything just to use it? I know it forces a user to explicitly think and spend time putting StageVideo into an app, but why? It should be EASY. I mean really EASY.

Enter StageVideoProxy. We wanted to go into all of our video applications and simply swap out a Video object reference for a new Class that would use StageVideo if present and fallback to using a standard Video object if it failed. By having a simple class that extended Video, we could just swap out the instance and proxy all the calls to StageVideo when it was available. This made it EXTREMELY easy to retro fit any existing application with StageVideo functionality. In addition, we kept all 10.2 API references in places that would not get called in players below 10.2, making the code backwards compatible.

Super right? Well we did find a few limitations. First, StageVideo doesn’t really have a way to clear the video, so we had set the size to 0 width and 0 height to “clear” it. Second, we don’t really know depth of display objects vs other display objects easily, so we don’t have a way to determine z depth for the videos. The second step doesn’t really matter though, given the implementation currently only supports a single StageVideo instance. I’d like to add support for multi videos, but I’m still unclear on how many I can have and what dictates that. I understand how to know when they are there and when you hit your limit, but I’d still like to fully understand it before I add it in.

Regardless, this is super useful code so merry nerdmas! Here you go in all its MIT licensed glory

/**
* Copyright (c) 2010 Dreamsocket Incorporated.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
**/
 
 
package com.dreamsocket.media 
{
	import flash.events.Event;
	import flash.events.StageVideoEvent;
	import flash.events.StageVideoAvailabilityEvent;
	import flash.events.VideoEvent;
	import flash.geom.Rectangle;
	import flash.media.StageVideo;
	import flash.media.StageVideoAvailability;
	import flash.media.Video;
	import flash.net.NetStream;
 
	public class StageVideoProxy extends Video
	{
		protected var m_netStream:NetStream;
		protected var m_stageVideo:Object;
 
 
		public function StageVideoProxy (p_width:int = 320, p_height:int = 240)
		{
			super(p_width, p_height);
 
			this.addEventListener(Event.ADDED_TO_STAGE, this.onAddedToStage);
			this.addEventListener(Event.REMOVED_FROM_STAGE, this.onRemovedFromStage);
		}
 
 
		override public function set height(p_value:Number):void
		{
			if(p_value != this.height)
			{
				super.height = p_value;
				this.layoutView();
			}
		}
 
 
		override public function get videoHeight():int
		{
			return this.m_stageVideo ? this.m_stageVideo.videoHeight : super.videoHeight;
		}
 
 
		override public function get videoWidth():int
		{
			return this.m_stageVideo ? this.m_stageVideo.videoWidth : super.videoWidth;
		}
 
 
		override public function set width(p_value:Number):void
		{
			if(p_value != this.width)
			{
				super.width = p_value;
				this.layoutView();
			}
		}
 
 
		override public function set x(p_value:Number):void
		{
			if(p_value != this.x)
			{
				super.x = p_value;
				this.layoutView();
			}
		}
 
 
		override public function set y(p_value:Number):void
		{
			if(p_value != this.y)
			{
				super.y = p_value;
				this.layoutView();
			}
		}
 
 
		override public function attachNetStream(p_stream:NetStream):void
		{
			if(p_stream != this.m_netStream)
			{
				this.m_netStream = p_stream;
				this.teardownStream();
				this.setupStageVideo();
			}
		}
 
		protected function setupSpriteVideo():void
		{		
			this.m_stageVideo = null;
			super.attachNetStream(this.m_netStream);		
		}
 
 
		protected function setupStageVideo():void
		{	// only setup the view when video is on stage and there is a netstream attached
			// this helps prevent as much as possible the time when a StageVideo is initialized
			if(!this.stage || !this.m_netStream) return;
 
			try
			{
				if(!this.m_stageVideo && this.stage.stageVideos.length >= 1)
				{
					this.m_stageVideo = this.stage.stageVideos[0];
					this.m_stageVideo.addEventListener(StageVideoEvent.RENDER_STATE, this.onRenderStateChanged);
					this.layoutView();
				}
 
				if(this.m_stageVideo)
				{
					this.m_stageVideo.attachNetStream(this.m_netStream);
				}
				else
				{
					this.setupSpriteVideo();
				}
			}
			catch(error:Error)
			{
				this.setupSpriteVideo();
			}
		}
 
 
		protected function teardownStream():void
		{	
			try
			{
				if(this.m_stageVideo)
				{
					this.m_stageVideo.viewPort = new Rectangle(this.x, this.y, 0, 0);
					this.m_stageVideo.attachNetStream(null);
				}
				else if(this.m_netStream)
				{
					super.attachNetStream(null);
					this.clear();
				}
 
			}
			catch(error:Error){}
		}	
 
 
		protected function layoutView():void
		{
			if(this.m_stageVideo)
				this.m_stageVideo.viewPort = new Rectangle(this.x, this.y, this.width, this.height);
		}
 
 
		protected function onAddedToStage(p_event:Event):void
		{
			//this.stage.addEventListener(StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILABILITY, this.onStageVideoAvailabilityChanged);
			this.setupStageVideo();
			this.layoutView();
		}
 
 
		protected function onRemovedFromStage(p_event:Event):void
		{	
			//this.stage.removeEventListener(StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILABILITY, this.onStageVideoAvailabilityChanged);
			this.teardownStream();
		}
 
 
		protected function onRenderStateChanged(p_event:Event):void
		{
			switch(StageVideoEvent(p_event).status)
			{
				case VideoEvent.RENDER_STATUS_UNAVAILABLE: 
					this.teardownStream();
					this.setupStageVideo();
					break;
			}
		}
 
 
		protected function onStageVideoAvailabilityChanged(p_event:Event):void
		{
			this.teardownStream();
			this.setupStageVideo();
		}
	}
}

Post a comment

You may use the following HTML:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre lang="" line="" escaped="" cssfile="">