Using Applescript and FFmpeg (through ffmpegX) to create Flash Video Files (FLV)

by Greg Walsh (gregwalsh.com)

Problem

I often need to create a number of Flash Video Files from source video for e-learning. We use one dual-processor Macintosh G5 system for all of our audio and video needs. We develop Flash movies on PC Workstations and import the FLVs to be used in our custom video player.

Almost all of our tasks are instantanious or can happen in paralell. Our workflow hits a bottle neck when exporting to FLV files from Quicktime Pro using the Flash Video Exporter plug-in because it only allows you to export one file at a time and and requires human interaction to start the process again with the next movie when the current one has finished. Although the plug-in promises that you can use it in a program that uses Quicktime plug-ins (Final Cut Pro is often mentioned), I haven't been able to use it in Apple's Compressor program to batch process files. When I use the plug-in with FCP, I can only export one file at a time which, again, creates a bottleneck in my workflow because I need to see if it is done and it ties up the editing program.

Here is my group's current workflow:

  1. Record audio into digital files
  2. Edit audio into appropriate chunks
  3. Record video
  4. Capture raw digital video
  5. Cut up video into selected chunks using Quicktime Pro
  6. Create a new project in Final Cut Pro
  7. Import audio & video
  8. Edit together
  9. Export to video format
  10. Convert video to FLV

I wanted a solution that would let me submit my videos for batch processing at the end of my work session and either continue working on the mac (preferred but not mandatory) or walk away and do another part of the project on a pc without having to monitor the processing.

Solution (and how I came up with it)

My initial thought was to create an AppleScript that controlled the Quicktime Player and batched processed the files using the FLV exporter. I downloaded the AppleScripts for Quicktime from Apple's Web site and began looking through the various examples. Each of the exporting examples required the Quicktime Player to have a preset defined. Quicktime has some common presets but none to export to FLV. I used an AppleScript to create a new preset based on the FLV export, but, I never got an AppleScript to work using the new preset.

After searching for awhile, I started to see lots of references to FLVs and FFmpeg, the open source engine for media production and conversion. I had used ffmpegX for OS X so I started to look for info on if ffmpegX and FLVs. Unfortunately, ffmpegX is focused on more traditional video formats and portable video formats (It's a great set of tools). I did find an article on Cyril Godefroy's Web site that explained how to use ffmpeg to make FLVs but it required me compliling ffmpeg from scratch...or at least I thought it did. In a ffmpegX message board, I saw an example of how to use the embedded version of ffmpeg in ffmpegX to convert a video.

In the terminal, I combined Godefroy's shell commands with the ffmpeg in /Applications/ffmpegX.app/Contents/Resources/ to convert a Quicktime movie taken with my consumer digital camera to an FLV and it worked...it seemed to work significantly faster than the official FLV Exporter for Quicktime. Next, I made that into an AppleScipt using the do shell command. Finally, I took that code, combined it with the Quicktime droplet example AppleScript and set up variables to make it work as a Droplet.

I found that the only video format that it supports converting to an FLV with sound is MPEG-1. It worked without sound as a Quicktime movie encoded in the Sorenson format but none of the audio codecs worked for me. I kept getting Bus Errors from ffmpeg. I found that I could make the movies with audio an MPEG-1 in Compressor and that translated well into an FLV.

The last piece to this puzzle was hooking it into Compressor somehow. I created a Compressor preset to make the MPEG-1 file to the size I wanted. One of the options in Compressor is Action and it lets you designate some type of file or script to be run on the movie when it's done processing. I pointed this tab to the Droplet I created and it runs after the movie is exported to MPEG. The only problem I've had so far is if the processed movie takes longer in the droplet than the next movie being processed takes in Compressor, the second movie doesn't get converted in the Droplet.

I guess I'll have to work on that.

Some other things I'd like it to do: display a terminal window showing what's going on, make it work with another file format other than mpeg-1.

Solution Summary

Write an AppleScript that utlizes do shell to process a file with the ffmpeg that is part of ffmpegX.


AppleScript Code

-- AN EXAMPLE DROPLET WITH SETABLE PROPERTIES

property type_list : {"MooV"} -- the list of file types which will be processed
-- since file types are optional in Mac OS X,
-- check the name extension if there is no file type
-- NOTE: do not use periods (.) with the items in the name extensions list
-- eg: {"txt", "text", "jpg", "jpeg"}, NOT: {".txt", ".text", ".jpg", ".jpeg"}
property extension_list : {"mov", "mpg"}
property example_property_A : "On"
property example_property_B : "On"

-- THE FOLLOWING ROUTINE APPEARS ONLY WHEN THE DROPLET IS DOUBLE-CLICKED
on run
   
    display dialog "Convert an MPEG-1 w/Audio to an FLV file" & return & return & ¬
        "by Greg Walsh" & return & ¬
        "3/2006"
   
end run

-- This droplet processes both files or folders of files dropped onto the applet
on open these_items
    -- CHECK THE VERSION OF QUICKTIME INSTALLED
    -- make something that checks for ffmpegx
   
    repeat with i from 1 to the count of these_items
        set this_item to (item i of these_items)
        set the item_info to info for this_item
        if folder of the item_info is true then
            process_folder(this_item)
        else if (alias of the item_info is false) and ¬
            ((the file type of the item_info is in the type_list) or ¬
                the name extension of the item_info is in the extension_list) then
            process_item(this_item)
        end if
    end repeat
end open

-- this sub-routine processes folders
on process_folder(this_folder)
    set these_items to list folder this_folder without invisibles
    repeat with i from 1 to the count of these_items
        set this_item to alias ((this_folder as text) & (item i of these_items))
        set the item_info to info for this_item
        if folder of the item_info is true then
            process_folder(this_item)
        else if (alias of the item_info is false) and ¬
            ((the file type of the item_info is in the type_list) or ¬
                the name extension of the item_info is in the extension_list) then
            process_item(this_item)
        end if
    end repeat
end process_folder

-- this sub-routine processes files
on process_item(this_item)
    -- NOTE that the variable this_item is a file reference in alias format
    -- FILE PROCESSING STATEMENTS GOES HERE
    set myFileName to getFileName(this_item)
    with timeout of 3600 seconds -- one hour per movie time limit
       
        --display dialog "/Applications/ffmpegx.app/Contents/Resources/ffmpeg -i " & the POSIX path of this_item & " -acodec mp3 -ab 32 -f flv -s 320x240 -ar 22050 -aspect 4:3 -pass 1 -b 256 -r 15 -y ~/Desktop/" & myFileName & ".flv"
        do shell script "/Applications/ffmpegx.app/Contents/Resources/ffmpeg -i " & the POSIX path of this_item & " -acodec mp3 -ab 32 -f flv -s 320x240 -ar 22050 -aspect 4:3 -pass 1 -b 256 -r 15 -y ~/Desktop/" & myFileName & ".flv"
       
       
    end timeout
end process_item


on getFileName(thefile)
    set {oldDelims, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {":"}}
    set mytextfilename to last text item of (thefile as text)
    set AppleScript's text item delimiters to oldDelims
    return mytextfilename
end getFileName


Resources

(As of 2006/03/15):
Cyril Godefroy's Web site lelab - How to encode flash video - when you don't have Flash

Technical Note TN2065: do shell script in AppleScript

AppleScript - getting a file name from a path name

ffmpegX Homepage

Note: ffmpegX is shareware. I'm not sure what the "legality" is in using the ffmpeg from the app bundle without paying for it. It is open-source but I'm still not sure.