Entries for month: December 2009

ColdFusion & FFmpeg - video conversion plus thumbnails

While writing an application last year for a large client I came across the need to convert uploaded video files and create thumbnails of those videos... on the fly. At the time I found it difficult to get many good search results from The Googs but from what I did find I ended up creating a great solution.

Note for the reader:

  • This article is targeted at Windows users, but the idea is the same for other Operating Systems
  • To use FFmpeg with ColdFusion your hosting environment will need to allow the use of CFEXECUTE - some Shared Hosts do not allow the use of this tag.

Scenario:

Client staff are to be able to upload vidoes from their PCs via the admin/CMS section of the site and be able to indicate at what second in the video they wish to capture a thumbnail preview. The videos uploaded are to be converted to FLV on the fly to enable instant playability in the site's flash-driven video player.

Solution:

You need,

  • Adobe ColdFusion
  • Hosting environment permission to use CFEXECUTE (CFEXECUTE is blocked/disabled by some Shared Hosting services)
  • FFmpeg (Download, Author, Documentation) - FFmpeg is a complete solution to record, convert and stream audio and video. It is a command line tool to convert one video file format to another. It also supports grabbing and encoding in real time from a TV card. Several FrontEnds/GUIs available like WinFF, Super, Avanti, AutoFF, Xpegt, GVC.

FFmpeg will download as an archive, you can extract the folder in this archive to a specific site you have or to anywhere centralised on your server, for example: "X:\ffmpeg". This location will be your installation directory.

Create a .bat (Windows Batch) file (in Notepad will do). here is an example:

video-converter-ffmpeg.bat

CALL X:\ffmpeg\ffmpeg -i %1 -ar 22050 -ab 64 -aspect 16:9 -b 400 -r 12 -f flv -s 460x258 -qscale 5 -ac 1 -y %2
EXIT

The above batch file calls the ffmpeg.exe and passes a string of arguments. This batch file script example also accepts arguments (%1 & %2). You will see these later when we call and run this batch file from ColdFusion.

FFmpeg Argument definitions:

  • -i filename Input file name
  • -ar freq Set the audio sampling frequency (default = 44100 Hz)
  • -aspect aspect Set aspect ratio (4:3, 16:9 or 1.3333, 1.7777)
  • -b bitrate Set the video bitrate in bit/s (default = 200 kb/s)
  • -r fps Set frame rate (Hz value, fraction or abbreviation), (default = 25)
  • -f fmt Force format
  • -s size Set frame size. The format is `wxh' (ffserver default = 160x128, ffmpeg default = same as source)
  • -qscale q Use fixed video quantizer scale (VBR).
  • -ac channels Set the number of audio channels (default = 1).
  • -y Overwrite output files

Definitions for all other FFmpeg arguments can be found in the ffmpeg documentation (linked to above).

Now to call on this batch file and run it from ColdFusion, you simply need to use the CFEXECUTE tag built into ColdFusion. Example:

<cfexecute name="{path_to_batch_file}\video-converter-ffmpeg.bat" arguments="{argument_1} {argument_2}" timeout="600" errorVariable="variables.ffmpegExecuteError" />

Note that the "{argument_1}" and "{argument_2}" correspond to "%1" and "%2" argument variables within the batch file script.

So that's it!

If you are also wanting to generate a thumbnail preview for the video then you simply need to add that to your batch file script. I personally made a separate batch file for my application. Example:

thumbnail-generate-ffmpeg.bat

CALL C:\ffmpeg\ffmpeg -i %1 -vcodec mjpeg -ss %3 -vframes 1 -an -f rawvideo -s 130x72 -y %2
EXIT

FFmpeg argument definitions:

  • -i filename Input file name
  • -vcodec codec Force video codec to codec. Use the copy special value to tell that the raw codec data must be copied as is.
  • -ss position Seek to given time position in seconds. hh:mm:ss[.xxx] syntax is also supported
  • -vframes number Set the number of video frames to record.
  • -an Disable audio recording
  • -f fmt Force format
  • -s size Set frame size. The format is `wxh' (ffserver default = 160x128, ffmpeg default = same as source)
  • -y Overwrite output files

Then the ColdFusion call, as before:

<cfexecute name="{path_to_batch_file}\thumbnail-generate-ffmpeg.bat" arguments="{argument_1} {argument_2} {argument_3}" timeout="600" errorVariable="variables.ffmpegExecuteError" />

So there you go... you can go play now. Of course, one thing to keep in mind is that you really don't even need batch files; you could always just call ffmpeg.exe directly from CFEXECUTE and pass the whole string of arguments as you please.

As for an example live site that uses this approach to handle and manage it's videos, try CliniqueTV

Bookmark and ShareSubscribe

Oops... SQL Server Like statement and brackets

I've come across some thing a little *duh* and thought I'd put it up here to help me remember better in the future.

I had a small test application that allowed a user to upload an image, the that image was copied and resized, each resizing saved with a naming convention that would make it easy for the application to work with.

Example:

I upload my_image.jpg

The application creates:

  • [large]_my_image.jpg
  • [medium]_my_image.jpg
  • [small]_my_image.jpg

Using brackets is not something I normally do in naming conventions and from now on will not do again. I really added it as it seemed to help visually when looking at my file system through Windows Explorer. Call it a brain fart, it just suited at the time.

The problem arose when I then went and tried running SQL with a LIKE statement in the WHERE clause.

Example:

select ID from mytable where imageName LIKE '[large]_%'

I had not read the SQL Server LIKE statement details, therefore had not realised that using brackets in a LIKE statement actually tries to invoke wild card pattern matching on the part of the string between the brackets. Also, using an underscore calls for an 'any single character' pattern match.

Note: Microsoft SQL Server 2008 Books Online: LIKE - also checked back to the 2000 version and it does not seem anything has changed with this statement's syntax

So yeah, moral of the story, keep it simple.

There are lots of ways to make names unique and named within a convention. I do prefer using a UUID or a timestamp in the file name.

So I might end up with something like:

  • small_{UUID}.jpg
  • small_{ddmmyyhhmmss}.jpg

Then if you do need to run an SQL LIKE statement you could just use:

select ID from mytable where imageName LIKE 'small%'

Anyway, just a note really for myself, but it's always nice if it help someone else.

Bookmark and ShareSubscribe