ColdFusion UDF to get meta-info on podcast files
Jun/091
In order to automatically generate a podcast based on a couple of audio- or video-files, you’ll have to get some meta-information on those, like format, bitrate or duration. This function acts as a wrapper around FFmpeg which will make that information available to you from within your ColdFusion application. Most Linux distros will provide some ready-made binaries for FFmpeg from their package manager. On Debian you’d just do aptitude install ffmpeg and you’re set.
On other operating systems, your mileage may vary, but as far as I know there are binaries to be found on the interweb for almost any reasonably recent platform around and this does even include Windows. For this to work on the Microsoft OS, you may have to make some adjustments to this code however – I didn’t try that as I don’t have any Windows-Server running ColdFusion.
FFmpeg will output the required meta data to stderr; I originally wrote this for an older version of BlueDragon (BD JX 7.0 IIRC), and as this didn’t support some of the more advanced features of cfexecute that may be found in ColdFusion 8.0.1 and above (namely the option to capture stderr output), I used a more pragmatic workaround to get at the info – I created this little bash wrapper script in /usr/local/bin/wrapffmpeg.sh:
#!/bin/bash ffmpeg -i $1 2>&1
This would pipe all output from stderr to stdout. You could just get rid of this using either the new errorVariable attribute to cfexecute that has been added in ColdFusion 8.0.1 or you could go down the long and winding road of replacing cfexecute with the underlying calls to java.lang.Runtime as demonstrated in my previous post “Using wdiff to show differences between text strings”.
Anyway, here’s the UDF:
<cffunction name="getmpxinfo" returntype="struct" output="false" access="public"> <cfargument name="file" default="" required="yes" type="string"> <cfscript> var mpxInfo=StructNew(); var ffmpegout=''; mpxInfo.fileExists = false; mpxInfo.fileSize = 0; mpxInfo.duration = ''; mpxInfo.seconds = 0; mpxInfo.format = 'unknown'; mpxInfo.type = 'other'; mpxInfo.bitrate = 0; mpxInfo.podcastValidity = false; if (not fileExists(file)) { return mpxInfo; } mpxInfo.fileExists = true; mpxInfo.fileSize = createObject("java", "java.io.File").init("#file#").length(); if ( mpxInfo.FileSize eq 0) { return mpxInfo; } </cfscript> <cfexecute name="/usr/local/bin/wrapffmpeg.sh" arguments="#file#" timeout="10" variable="ffmpegOut"></cfexecute> <cfscript> // check file type if (FindNoCase('Unknown format',ffmpegOut,1)) { return mpxInfo; } mpxInfo.format = ReFindNoCase('Input ##0, [[:alnum:],]+, from',ffmpegOut,1,1); mpxInfo.format = mid(ffmpegOut,mpxInfo.format.pos[1]+10,mpxInfo.format.len[1]-16); switch (mpxInfo.format) { case 'mov,mp4,m4a,3gp,3g2,mj2': mpxInfo.type = 'video'; break; case 'mp3': mpxInfo.type = 'audio'; break; } if (mpxInfo.type eq 'other') { return mpxInfo; } // Now we can assume that it's either an audio-mp3 or an MPEG4-video, so it is suitable for podcasts mpxInfo.podcastValidity = true; // get playing time mpxInfo.duration = REFindNoCase('Duration: \d{2}:\d{2}:([\d\.]){0,4},',ffmpegOut,1,1); mpxInfo.duration = mid(ffmpegOut,mpxInfo.duration.pos[1]+10,mpxInfo.duration.len[1]-11); mpxInfo.seconds = ListGetAt(mpxInfo.duration,1,':') * 3600; mpxInfo.seconds = mpxInfo.seconds + ListGetAt(mpxInfo.duration,2,':') * 60; mpxInfo.seconds = mpxInfo.seconds + ListGetAt(mpxInfo.duration,3,':') ; // get bitrate mpxInfo.bitrate = REFindNoCase('bitrate: \d+ kb/s',ffmpegOut,1,1); mpxInfo.bitrate = mid(ffmpegOut,mpxInfo.bitrate.pos[1]+9,mpxInfo.bitrate.len[1]-14); return mpxInfo; </cfscript> </cffunction>
To use this, you’d just pass the full physical path to the file as single argument to the function and it will return a structure with the meta-data:
fileInfo = getmpxinfo('/path/to/my/file.mpg');The returned structure will provide the following information:
| fileExists | true or false |
|---|---|
| fileSize | filesize in bytes |
| type | audio, video or other |
| format | one of mp3,mov,mp4,m4a,3gp,3g2,mj2 |
| podcastValidity | Is it suitable for podcasts? – true or false |
| duration | playing time in hh:mm:ss,d format |
| seconds | playing time in seconds, rounded to the first positional after decimal point |
| bitrate | bitrate in kb/s |
Enjoy this article?
Leave a comment
No trackbacks yet.
19:39 on December 11th, 2009
Thanks for sharing this. Got me on the right track. I couldn’t get the errorVariable attribute to work for me, but using Java runtime did the trick. Now if I can just get past these irritating “codec frame rate differs from container frame rate” errors, my video conversion tool will be set to go. Thanks again…