Converting video with FFmpeg and Adobe AIR

Something I have been wanting to do for a while now is build a video converter into my Module Builder to enable automatic conversion of video into the various web friendly formats but I could never find a way to do it.

Over the weekend I discovered this tutorial on playing back any video in Adobe AIR. The tutorial runs through how to set up a NativeProcess to hook into FFmpeg to stream video from any format into FLV. FFmpeg is an open source media library for playback and conversion of almost any type of video or audio and is used by VLC and many other applications. I finally had a possible way of converting video within an AIR app! And one of the great things about this is since its using the NativeProcess API the conversion works asynchronously and the app doesn’t lock up while its converting.


So the code below shows how to convert a video file into WebM using FFmpeg and a NativeProcess. I recommend you watch the tutorial I mentioned before using this to get some better understanding of the process.

// set up vars for the native process
var _process:NativeProcess;
var _processArgs:Vector.<String>;
var _nativeProcessStartupInfo:NativeProcessStartupInfo;

// these will be used to calculate progress
var _currentSeconds:Number = 0;
var _totalSeconds:Number = 0;

function convert(inPath:String,outPath:String):void
{
    _nativeProcessStartupInfo = new NativeProcessStartupInfo();
   
    // set executable to the location of ffmpeg.exe
    _nativeProcessStartupInfo.executable = File.applicationDirectory.resolvePath("path/to/ffmpeg.exe");
   
    // set up the process aarguments - these arguments work for WebM
    // you can find arguments on the net for specific formats by searching google
    // for example: ffmpeg convert mov to ogv
    _processArgs = new Vector.<String>();
    _processArgs.push('-y'); // always overwrite existing file
    _processArgs.push('-i'); // input flag
    _processArgs.push(inPath); // input path
    _processArgs.push('-s'); // video size flag
    _processArgs.push('640x360'); // video size
    _processArgs.push('-b:v'); // bitrate:video flag
    _processArgs.push('512K'); // bitrate
    _processArgs.push('-b:a'); // bitrate:audio flag
    _processArgs.push('128K'); // bitrate
    _processArgs.push(outPath); // output path
   
    _nativeProcessStartupInfo.arguments = _processArgs;
   
    // create new native process
    _process = new NativeProcess();
   
    // add listeners
    // ffmpeg sends conversion status data through the STANDARD_ERROR_DATA channel
    _process.addEventListener(ProgressEvent.STANDARD_ERROR_DATA, progress);

    // when conversion is completed
    _process.addEventListener(NativeProcessExitEvent.EXIT, onExit);
   
    // start the process
    _process.start(_nativeProcessStartupInfo);
   
}

Now for the STANDARD_ERROR_DATA event. This function will handle all messages sent from FFmpeg which contain valuable information such as video metadata, current encoding status and any errors.

function progress(e:ProgressEvent):void
{
    // read the data from the error channel bytearray to string
    var s:String = _process.standardError.readUTFBytes(_process.standardError.bytesAvailable);
   
    // stuff for finding timecodes
    var reg:RegExp;
    var matches:Array;
    var time:Array;
   
    // if the message includes frame=, this is a frame progress message
    // the message will be something like:
    //     frame= 1018 fps=226 q=31.0 size=    3634kB time=00:00:41.79 bitrate= 712.2kbits/s
    // we need to extract the current time: time=00:00:41:79
    if (s.indexOf("frame=") != -1)
    {
        //is progress
        reg = /time=([^ ]+)/; // regexp to extract time portion
        matches = s.match(reg);
       
        if (matches.length > 0)
        {
            // split timestamp into sections
            time = matches[0].substring(5).split(":");
            // calculate the total seconds from the time stamp to get current seconds
            _currentSeconds = Math.round(((Number(time[0]) * 3600) + (Number(time[1]) * 60) + Number(time[2])));
           
        }
    }
    // Duration is sent at the beginning of the process which tells us how long the video is
    else if (s.indexOf("Duration:") != -1)
    {
        // find duration
        reg = /Duration:([^,]+)/; // regepx to extract duration portion
        matches = s.match(reg);
       
        if (matches.length > 0)
        {
            // split timestamp into sections
            time = matches[0].split(":");
            // calculate the total seconds from the time stamp to get total seconds
            _totalSeconds = Math.round(((Number(time[1]) * 3600) + (Number(time[2]) * 60) + Number(time[3])));
        }
    }
    // trace out the message if it contains Error, as there was probably something wrong with the encoding settings
    else if (s.indexOf("Error ") != -1)
    {
        trace("Error: " + s);
    }
   
    // trace percentage
    trace( Math.round(_currentSeconds / _totalSeconds * 100) + "%");
}

And finally the EXIT event which we will just use to trace ‘Complete':

function onExit(e:NativeProcessExitEvent):void
{
    trace("Conversion complete.");
}

Now we can call convert to convert a video:

var inpath:String = File.desktopDirectory.resolvePath("path/to/video.mp4").nativePath;
var outpath:String = File.desktopDirectory.resolvePath("path/to/video.webm").nativePath;

convert(inpath,outpath);

This is just the basics of converting a video and there are a lot more things you can do with the process arguments and you could also handle arguments for different output formats.

Posted toActionScript AIR Flash NativeProcess Video
  • http://www.batchass.fr Bruce LANE

    I did the same thing for vpDude, using a queue for the videos to convert: https://github.com/batchass/vpDude

  • http://www.plugin.io Gary Paluk

    Besides being useful for video, this is useful for launching any task and something that I was about to start looking into so, thanks for the tutorial and thanks for getting me running with other similar applications.

    • http://www.nemenvisual.com Ben Foster

      Absolutely! I am thinking about doing post on running Java (.jar) applications with a native process soon too as it’s slightly different.

      I am glad you were able to get something from this.

  • Pingback: Converting video with FFmpeg and Adobe AIR - Purple Squirrels | Video Everywhere... with a headache | Scoop.it

  • http://iptvmyway.com chad

    do you have the source for this? i would like to add this to my site to help others out to work with our software. we use FFmpeg on windows and want a way to start it with some arguments. thanks!