Thursday, February 17, 2011

Compile FFmpeg Alpha Channel Images & Embed FLV In Flash AS3

The battle with flash video alpha channels has resulted in victory. Three days of trying every angle to get alpha channels on the cheap and I broke down and downloaded a trial version of Sorenson Squeeze to compress the video in the proprietary VP6a (A for Alpha) codec. That was just the beginning of the end of solving the transparent background.

The general idea is that we use FFmpeg to compile JPG to video with alpha then Sorenson Squeeze export to the vp6a codec and then use flash to export to the Flash 9 flv container. The VP6a codec is offered in Sorenson Squeeze for Flash 8 only. When you attempt to load the Flash 8 FLV into a movieclip for easy control it will bug out and say it can't deal with AVM1 files as Flash 10 is now using AVM2. Big deal right? Should get sorted out in Flash 11 more clearly how to do all this stuff but at the moment FLV transparent background video can a tough issue to tackle. Although you can download ffmpeg and many features and codecs are immediately available it is impossible to create transparency-supported embedded flash video formats.

You need a paid solution like Sorenson Squeeze so go ahead and download the trial version. My example exports the correct video format to preserve the alpha channel present in the PNG files (could as well be JPG) by using the flags "-vcodec rawvideo". If your output video comes out upside down then the flags '-vf "vflip"' are needed for you to unflip it. Even though these instructions are for converting still frames to video you should be able to use these settings to convert from video to video if your format isn't supported in Squeeze somehow.

1. Compress the image series with rawvideo codec which uses bgra pixel format by default:
ffmpeg -i "D:\animations\DemoFiles1\Animation1\Animation1.%d.png" -vcodec rawvideo -vf "vflip" testPNGtoRAW.avi
2. Compress to FLV with on2's codec VP6a in Sorenson Squeeze (Codec only available for Flash 8 AVM1 format).
3. Embed in Flash 9 AVM2 video swf container using Flash IDE. (This step is optional and only to use SWF movieclip functionality in code instead of netstream.)

All told over a week spent in the video encoding department (w/ alpha and w/o alpha) reading, testing and learning... Now I can get back to coding ^_^

To embed this flv alpha channel video into our flash movie you may use the following:
[Embed(source = "../data/playeranims/Player1/playerDefend.swf", mimeType = "application/octet-stream")] private var PlayerDefend:Class;
 Nevermind the parent folder notation in the example but make sure to include the correct mime type. I have embedded the video in the object class for each player character.

Now in my code I have different player objects each with their own videos and so each has functionality to access the embedded video with the next code example:
public function getDefendVideo():ByteArray { return new PlayerDefend(); }
 Now we can play the flv video with alpha channel functionality. This function loads the video's bytes from the character object and gets ready for the completion event which will fire soon as the video is embedded. This makes things kind of easy. ^_^
private function playVideo():void
{
_loader.loadBytes(playerCharacter.getDefenseVideoOne()); _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
}

The request to load the embedded video's bytes completes with the ability to easily use a movieclip to control the playback of the transparent flv video in flash. Without the proper version of Flash flv container it is not quite so easy to dynamically load and play your videos. As mentioned before you will get an AVM1 error as being an "outdated" video FLV container.

I have also implemented an EnterFrame event that checks the position of the video every cycle to determine what to do which is in this case unload the video after fading out:

private function onLoadComplete(event:Event):void {_loader.content.addEventListener(Event.ENTER_FRAME, onMovieEnter);}

private function onMovieEnter(event:Event):void {

var swfTimeline:MovieClip = _loader.content as MovieClip;

if (swfTimeline.currentFrame == swfTimeline.totalFrames)

{

_loader.content.removeEventListener(Event.ENTER_FRAME, onMovieEnter);

swfTimeline.stop();

Tweener.addTween(_loader.content, { alpha:0.2, time:0.3, transition:"easeOutCirc"} );

Tweener.addTween(_loader.content, { alpha:0, time:0.3, delay:0.3, transition:"easeOutCirc" , onComplete:function():void { _loader.unloadAndStop(); }} );

}

}

The code example then goes on to tween the video in and out as well as unloading and stopping the transparent flv movie upon completion of the fade-out. As you can see I am using the Tweener library and format here in the example as3. Put simply, the second Tweener command fades the alpha to zero over 3 tenths of a second using circular outer easing and unloads the movie on completion.

You are going to need to declare the loader up top in your controlling code portion:
public var _loader:Loader;

Also your imports for this as3 transparent video tutorial are:
import flash.display.loader
import flash.events.Event

2 comments:

  1. I was just doing some work with this process again and I bumped into some interesting issues.

    The ffmpeg command where the images are parsed requires a length specifier before %d:

    ffmpeg -i "D:\animations\DemoFiles1\Animation1\Animation1.%5d.png"


    Also, when doing another round of images with an odd ratio where the height is taller than the width I was generating invalid avi video files. I used MediaInfo to see that the height values for the videos were astronomical.

    To fix this I opened each avi file in a hex editor and in the same locations about 90~100 bytes in I identified the four bytes describing the height and changed them to some little-endian hex for 1280 which looks like .

    After this the avi video files would load correctly with alpha into the next video software piece from Sorenson.

    ReplyDelete
  2. edit* ...some little-endian hex for 1280 which looks like "2C","01","00","00". (Which in my avi files starts at byte 8C.

    ReplyDelete

Give me your best comment. *_*