Capturing Video from Flash Movies with ActionScript

I recently had the problem to store a flash animation into a video file. I first tried some tools I found in the net, but they all run into problems because my flash movie doesn’t integrate the MovieClip timeline. Tools like swf2avi are stopping the conversion after the first frame, because they’re thinking it’s the only frame. One way round is make let your movie extend the MovieClip class instead of the Sprite and to integrate the timeline in your animation. But this starts to get very difficult if you’re making heavy use of the timers and tweening engines. The first thing you need to do, is to add a new event listener to the stage’s ENTER_FRAME event.

1
stage.addEventListener(Event.ENTER_FRAME, captureFrame);

Inside this event listener you have to check if the current frame is one of those you want to capture. It makes a lot of sense to limit the number of frames regarding to your requirements as all images will be stored uncompressed to your RAM, which might lead to problems if you capture too many frames at once. To capture a single frame you simply create a new BitmapData instance and draw the stage onto it. Since you don’t need transparent images for most video purposes, you set the third constructor parameter to false and define a background color as you like. Finally you store the frame in an array.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private const _fromFrame:uint = 0;
private const _toFrame:uint = 400;
private var _frame:uint = 0;
private var _bitmaps:Array = [];

private function captureFrame(e:Event):void
{
if (_frame >= _fromFrame && _frame < = _toFrame) {
var bmp:BitmapData = new BitmapData(
stage.stageWidth, stage.stageHeight,
false, 0x000000);
bmp.draw(stage);
_bitmaps.push(bmp);
}
_frame++;
}

Now that we stored all frames we wait till the movie finishes. The next thing to do is to compress the images. You can use the PNGEncoder class of the as3corelib. There is no way to save images directly to your harddrive via flash, so we need to go a way round using an http connection and a little php script on our local web server.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private function exportBitmaps():void
{
var j:uint = _bitmaps.length;
for (var i:uint = 0; i < j; i++) {
// encoding the image as png
var pngStream:ByteArray = PNGEncoder.encode(_bitmaps[i] as BitmapData);

// setup a simple http connection to the php script
var header:URLRequestHeader = new URLRequestHeader(
"Content-type", "application/octet-stream");
var urlReq:URLRequest = new URLRequest(
"http://localhost/saveImage.php?name=frame_"+i+".png");
urlReq.requestHeaders.push(header);
urlReq.method = URLRequestMethod.POST;
urlReq.data = pngStream;

// send out the data
new URLLoader(urlReq);
}
}

The php script is very simple, as it just puts the http post data into a new file on your harddisc.

1
2
3
4
if (isset($GLOBALS["HTTP_RAW_POST_DATA"]))
{
file_put_contents("folder/".$_GET["name"], $GLOBALS["HTTP_RAW_POST_DATA"];);
}

Now you got a nice set of images and you’re ready to convert them into a video file in your favorite format. You can do this with a lot of free tools, I chose VirtualDub, for instance. That’s all… framesframes