Sep 12, 2011
Good afternoon readers,
I spent a nice chunk of the weekend finishing up the sample code files I'll be presenting along with my talk on "Delivering Best Video Experiences with Flash", which I will be giving at Adobe MAX on October 5th, and LA Flash on September 21st.
This talk covers a lot of ground, from video compression optimization to WMODE settings — but mostly centers around the StageVideo enhancements in the recent versions of the Adobe Flash Player.
For those who don't know, StageVideo is a new way of rendering video in the Flash Player, that takes even more advantage of Graphics Processing Units (or GPUs, which are generally faster at working with video than CPUs).
With regular hardware accelerated video, the GPU decodes the video, but the CPU then still renders the video in the Flash Player.
With StageVideo hardware acceleration, the GPU decodes the video, and also renders the video, directly to the screen, underneath the Flash Player (and all the rest of your Flash content).
I've included the following graphics on one of my slides to help illustrate this point (click on the image for the full size):
I'll explain more about how this all works in the talk.
When it comes to using StageVideo, fortunately, it's pretty easy.
First off, if you use OSMF (the Open Source Media Framework for coding media experiences in Flash from Adobe), or Strobe Media Playback (Adobe's open-source media player built on OSMF), StageVideo just works for you (OSMF v1.6 and later). Really, it's that simple.
If you are using OSMF, and want to disable StageVideo, all you need to write is:
OSMFSettings.enableStageVideo = false; |
In AS3, there is a new API for StageVideo. The new StageVideo class essentially replaces the Video class in functionality (though you still need to use the Video class in your code, as fall-back in case your viewers do not support StageVideo). This means that all the rest of your video playback code (including the NetStream and NetConnection) work the same way. All you need to do is call attachNetStream() on the StageVideo object, instead of the Video object, like so:
myVideo.attachNetStream ( ns ) ; |
to:
myStageVideo.attachNetStream ( ns ) ; |
Now, the StageVideo class does work differently than the Video class. First, you do not create StageVideo instances — the Flash Player will create them for you if it can, and store references to them in a vector on the stage called stageVideos.
There are more differences than that, but if you just want to get started learning and using the AS3 StageVideo API, I'm posting one of the sample files from the talk. This is the 'simple' sample file, which demonstrates the basic code to get StageVideo playing, and little else. I've also prepared a more complex demo, including the RENDER_STATE event, the colorSpaces property, and pan and zoom functionality, which I'll be distributing to those who come to my talk (again, that will be at Adobe MAX on October 5th, and LA Flash on September 21st).
I've included the sample code, below, in this post. You can also download it as a zip file.
Again, this code is for the simple StageVideo demo. Just set this as your document class in Flash Professional CS5.5, and of course, update the _videoURL constant to point to your own video:
/* AS3 Copyright 2011 R Blank */ package { /** * This class illustrates a simple StageVideo implementation. * * @langversion ActionScript 3.0 * @playerversion Flash 10.2 * * @author R Blank * @since 09.09.2011 */ //import the MovieClip, because this class is a MovieClip import flash.display.MovieClip ; //import the Rectangle, so that we can size and position the StageVideo instance import flash.geom.Rectangle ; //import StageVideoAvailabilityEvent so we can hear //when StageVideo availability changes import flash.events.StageVideoAvailabilityEvent; //import StageVideo so we can use StageVideo import flash.media.StageVideo; //import StageVideoAvailability to get the values for the //StageVideoAvailabilityEvent.available property import flash.media.StageVideoAvailability; //import Video as a backup for when StageVideo is not available import flash.media.Video; //import the NetConnection and NetStream to play our video file import flash.net.NetConnection; import flash.net.NetStream; //import the TextField so we can log values visibly import flash.text.TextField ; public class StageVideoPlayerExample extends MovieClip { //-------------------------------------- // CLASS CONSTANTS //-------------------------------------- //the location of our video file private const _videoURL : String = "../_media/bunny.mov" ; //-------------------------------------- // CONSTRUCTOR //-------------------------------------- public function StageVideoPlayerExample ( ) { //call the _init function to startup _init () ; } //-------------------------------------- // PRIVATE VARIABLES //-------------------------------------- //the Video object to play video when StageVideo is not available private var _video : Video ; //the StageVideo object to play fully accelerated video private var _stageVideo : StageVideo ; //the NetStream and NetConnection objects to play video private var _ns : NetStream ; private var _nc : NetConnection ; //the TextField object to log informationvisibly in the browser private var _tf : TextField ; //-------------------------------------- // PRIVATE & PROTECTED INSTANCE METHODS //-------------------------------------- //called by the constructor to startup the player private function _init ( ) : void { //the NetConnection object over which video is delivered _nc = new NetConnection ( ) ; //connect _nc to null because we are playing video progressively _nc.connect ( null ) ; //create the NetStream to deliver video over the NetConnection _ns = new NetStream ( _nc ) ; //define the NetStream client as 'this' //where _ns will look for the onMetaData and onCuePoint methods _ns.client = this ; //tell the NetStream to play our video file _ns.play ( _videoURL ) ; //create the video object as back up, in case StageVideo is not available _video = new Video ( ) ; //listen for the StageVideoAvailabilityEvent //which is fired as soon as this listener is added //and when StageVideo becomes available or unavailable //throughout SWF playback stage.addEventListener(StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILABILITY, _onStageVideoAvailability); //create the TextField for logging _tf = new TextField ( ); _tf.height = stage.stageHeight ; _tf.width = stage.stageWidth ; _tf.mouseWheelEnabled = true ; _tf.multiline = true ; _tf.wordWrap = true ; //add the TextField to the display list addChild ( _tf ) ; } //called when we wish to start StageVideo playback private function _enableStageVideo() : void { //if we do not have a StageVideo object reference //already stored in _stageVideo if ( _stageVideo == null ) { //set _stageVideo to reference the first of our //available StageVideo objects (up to 8 available on desktops) _stageVideo = stage.stageVideos [ 0 ] ; //size and position our _stageVideo with a new Rectangle _stageVideo.viewPort = new Rectangle ( 0 , 0 , 320 , 240 ) ; } //if the _video object is in the display list if ( _video.parent ) //remove _video from the display list removeChild ( _video ) ; //attach our NetStream instance to our StageVideo instance _stageVideo.attachNetStream ( _ns ) ; } //called when StageVideo becomes unavailable //and we need to use a Video object as back-up private function _disableStageVideo() : void { //attach our NetStream to our Video object _video.attachNetStream ( _ns ) ; //add the Video object to the display list //(so that it can be seen) addChild ( _video ) ; //add the _tf TextField back to the display list //so that it is on top of the _video object addChild ( _tf ) ; } //-------------------------------------- // StageVideo Event Handlers //-------------------------------------- //our callback function for the //StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILABILITY event private function _onStageVideoAvailability ( evt : StageVideoAvailabilityEvent ) : void { //log the availability of StageVideo _tf.text = "Stage Video: " + evt.availability ; //if StageVideo is available if ( evt.availability ) //call _enableStageVideo _enableStageVideo ( ) ; else //otherwise call _disableStageVideo _disableStageVideo ( ) ; } //-------------------------------------- // NetStream Event Handlers //-------------------------------------- //the NetStream will look for these two methods //on whatever object is identified as the NetStream's client //if they do not exist, you will receive a run time error //when the NetStream encounters metadata or cuepoints in the video public function onMetaData( info:Object ) : void { } public function onCuePoint( info:Object ) : void { } } } |
Share and enjoy!
-r
Would love to see this working but I get an error
Error #2095: flash.net.NetStream was unable to invoke callback onXMPData.
something I guess to do with lack of meta data in my particular video clip. Shouldn't this be handled by the two last functions in your sample?
Thanks for sharing this.
Howdy Martin:
Sounds to me like not like your video is missing metadata, but instead includes XMP data (which is sort of unusual, in my experience with compressed video for the web).
The two functions included in my above code would NOT handle XMP data — they handle standard metadata (width, height, framerate, duration, etc) and cue points.
So, perhaps unsurprisingly, what you need to add is an onXMPData method, just like onCuePoint, located on the NetStream's client.
public function onXMPData ( info : Object ) : void {}
For reference, the full set of methods that the NetStream might look for on the client are:
- onCuePoint()
- onImageData()
- onMetaData()
- onPlayStatus() (FMS only — at least as far as I know)
- onTextData()
- onXMPData()
Good luck!
-r
Thanks for replying on that. You were absolutely right I was missing the onMetaData method. That certainly resolved that first error. Now it compiles fine but oddly with the sample video I am using I just get audio no video. I am using a clips from http://support.apple.com/kb/HT1425. So far I tried three of the clips – the m4v, mov and mp4 but they all behave the same. Am I missing something dumb here (won't be the first time).
Thanks Martin
ps Enjoy MAX – I attended MAX Europe a couple of times before they stopped running it over here. It was a fantastic event
Hello Martin,
It may seem silly, but the format of your video (.m4v, .mov, etc) does not tell you the codec. Flash supports H.264, so you need to see if your video is really H.264. If you are on Mac, you can tell by loading it into Quicktime and checking the Info panel; if you are on PC, you can install GSpot (http://www.headbands.com/gspot/) which will tell you what codec is in your video.
Also, please confirm what version of Flash Pro and the Flash Player you are using.
Cheers,
-r
Resolved it! Was to do with me not published my SWF from Flash Professional to Hardware acceleration 'direct' mode and also needed to amend my HTML wrapper to 'direct' mode too. Thanks for your swift response.
Ah yes, I spend a few slides covering that in my talk.
Glad you figured it out.
You can see a few words posted about that here, too: http://labs.almerblank.com/2011/03/the-wmode-embed-parameter-de-mystified/
Honestly, WMODE is sort of annoying in this workflow (especially when the two wmodes you need — "direct" or "gpu" — are not even available as options in the Flash Pro publish settings!)
Cheers,
-r
Hey, I get a "Cannot access a property or method of a null object reference." When I try to implement your code. The error occurs on line 92: stage.addEventListern…..
Anyways, the only changes I've made to the code are the _videoUrl constant and the constructor. I made the videoUrl constant into a normal variable which gets populated in the constructor. I'm using this class for an iPhone application. In one of my views I create an instance of this class that you created. Anyways, when I instantiate the class, I get the error. It would be really great if I get some help on this problem. Thank-you very much for your help
RJ
It sounds like the code can not see the stage.
In which case, my guess is that you have not implemented this code as the document class in your Flash Project. Can you confirm?
thank you very much!
any tips for getting this to work in Flash Builder 4.5.1 as a AS3 mobile project exporting to ios?
doesn't work on desktop emulation or ont he device. the StageVideoAvailabilityEvent never fires
Howdy Brian:
StageVideo is supposed to work for AIR for iOS (since AIR 3.0, I believe). I do not know what may be happening in your project. Can you query the Stage.stageVideos property?
-r
I'm having a similar problem as Brian and Martin had. Running your code in a project targeted for iOS, I get audio, but no video. Translating this code to my own document class, I have an issue with the 'stage.stageVideos[0]' call, which gives me the error 'The index 0 is out of range 0'. Even with that error, I do still get audio, but no video. I'm not sure what the 'direct' mode is and how I set that, if that's the solution to any of this. Thanks.
Hi Greg,
Sorry about the difficulties you are encountering. I'm not doing any work with AIR for mobile devices any more, so it's difficult for me to say exactly what you're seeing. If stage.stageVideos[0] doesn't exist, to my understanding, that means StageVideo is not supported (which also sounds consistent with the playback symptoms you mention).
What type of video file are you trying to play? Is it MP4?
Also, to set GPU mode of 'direct', you will want to set to 'direct' in your application descriptor file. And, according to this post you also need to add “-swf-version=13" to the additional compiler arguments.
Good luck,
-r
I just can't make it work! I've created a new AS3 project, created a blank fla file, attached the main class from Zip file. Placed a h264 video and changed the video source in code. Targeted flash player 10.3 and published with windows mode – direct.
As the result – when I open html file, I get StageVideo : available sign, but it does not play.
Thanks for the code!
Some discoveries, I found that StageVideo video playback ( I attached a webcam to it), the image quality is smoother, but the video colors are washed out.
Video, on the other hand, appears to be bit more pixelated, but with much better black and more vivid color.
Just wondering do you or anyone else here experience the same?
Those results are not surprising. Depending on the path your video follows to get rendered (the render path, discussed a bit here, http://labs.almerblank.com/2011/10/stagevideo-part-2-how-it-works/ ) — whether using the GPU or CPU — the image may look different. And the differences will often be different for the video content, vs. the other visual content overlaid on top of the video. And, what's worse — the differences also depend on the specific hardware you (or your viewers) has installed.
Good luck!