30 June, 2009

Power of the Pipe

For quite some time I've it's been a mystery to me why many Unix-flavored toolsuites offer a command line interface supporting inputting or outputting to stdin/stdout respectively.

For example, ffmpeg can utilize stdin in leu of a input file by specifying -; similarly it can utilize stdout in leu of an output file using the same - specifier.

I've recently become aware of how useful this option can be. In particular it allows you to bypass creating unnecessary temporary files.

For example, using ffmpeg you can redirect the output to stdout and into mplayer to review the impacts of varying codecs and video quality specifiers.

$ ffmpeg -i /var/tmp/foo.mpg -f asf - | mplayer -cache 8192 -

Similarly, you can make use of the similar feature with ImageMagick like so:

$ convert Lenna.jpg - | display -

In each case, redirecting to stdout and piping to a consuming display utility eliminates the need for creating a temporary file.

26 June, 2009

Drawing Primitives with ImageMagick

ImageMagick offers far more than simple image conversion utilities. It also extends to you the ability to create new images using drawing primitives. I've recently found this useful in creating artificially created videos use to test image processing and tracking techniques. The following script supports creating a series of circular targets in a newly created frame. By creating a series of frames, stitching them together with FFMpeg and you can create a video of moving targets of know positions. Useful for testing algorithms.



proc createFrame { fileName imageL targets } {
array set image $imageL
set tL ""

foreach e $targets {
switch [lindex $e 0] {
set x0 [lindex [split [lindex $e 1] ,] 0]
set y0 [lindex [split [lindex $e 1] ,] 1]
set r [lindex $e 2]
set x1 [expr $x0 + $r]
set y1 $y0
set tL [concat $tL "-fill red -draw 'circle $x0,$y0 $x1,$y1'"]

set cmd "/usr/bin/convert -size $image(width)x$image(height) xc:white $tL $fileName"
puts $cmd
exec bash -c $cmd

set image(width) 640
set image(height) 480
set fileName /tmp/frame00000001.pnm
lappend targets [list circle 320,240 10]
lappend targets [list circle 100,100 10]
createFrame $fileName [array get image] $targets

19 June, 2009

Cpu Load Monitoring

We've recently had explore collecting and analyzing CPU resource loading metrics for our project. The host OS is Linux 2.6 based and rather than install a performance-specific set of utilities we aimed at utilizing readily available services.

Ask any Linux weenie what CPU loading they have been experiencing and most will respond by starting the top utility. Top is available on most Unix distributions, is a well known utility and has pretty much stood the test of time. For those reasons it seemed obvious to incorporate it into a performance monitoring data collection and analysis tool suite.

The following Tcl script takes two arguments, the first an output file which will be populated with the redirected top log file, the second is a duration (in seconds) of how long to monitor the performance. After the raw collection has completed the script parses the log, extracts the CPU loading metrics and outputs a median and mean CPU processing load expressed in percentage of utilization.

It's worth noting that the script incorporates searching for the regular expression *Cpu* to find the top line item holding the Cpu metrics. As a result, if you have a process running that matches *Cpu* you'll find the script errors out during processing of the log file. I'll leave it as a lesson to the reader how to correct (wink).

We've extended on the same principle to monitor network activities.

Have fun.


proc log { msg } {
# puts stderr __$msg

proc mean { L } {
set sum 0.0
foreach e $L {
set sum [expr $sum + $e]
return [expr $sum / [llength $L].]

proc median { L } {
set L1 [lsort -real $L]
return [lindex $L1 [expr [llength $L1] / 2]]

proc process { fileName } {
set fp [open $fileName r]
while { [gets $fp line] >= 0 } {
switch -glob -- $line {
log "processing line '$line'"
set el [split $line ,]
set userLoad [string trimleft [lindex $el 0] "Cpu(s):"]
set sysLoad [lindex $el 1]
set niceLoad [lindex $el 2]
set idleLoad [lindex $el 3]
log "parsing $userLoad"
log "parsing $sysLoad"
log "parsing $niceLoad"
log "parsing $idleLoad"
set userLoad [lindex [split $userLoad \%] 0]
set sysLoad [lindex [split $sysLoad \%] 0]
set niceLoad [lindex [split $niceLoad \%] 0]
set idleLoad [lindex [split $idleLoad \%] 0]
log "extracted $userLoad"
log "extracted $sysLoad"
log "extracted $niceLoad"
log "extracted $idleLoad"
# puts [expr $userLoad+$sysLoad+$niceLoad+$idleLoad]
lappend L [expr 100.0-$idleLoad]
close $fp
puts "mean cpu load: [mean $L]"
puts "median cpu load: [median $L]"

proc monitorCpuLoad { fileName duration } {
catch { exec top -b -n $duration -d 1 > $fileName }
process $fileName

proc help { } {
upvar #0 argv0 argv0
puts stderr "usage: $argv0 \[logFileName\] \[duration\]"

if { [llength $argv] != 2 } {
monitorCpuLoad [lindex $argv 0] [lindex $argv 1]

18 June, 2009

Capturing Radio Broadcast Streams with Mplayer

My wife and I took our honeymoon in Australia and I can admit that there are numerous occasions where I hunger for a bit of Aussie. I recently explored how to capture an audio stream to play back on my MP3 player (since our office frowns on streaming).

This is how I've been capturing Triple-J streams for fun;

$ mplayer -dumpstream -dumpfile /tmp/audio.mp3

12 June, 2009

Screen Capture with FFmpeg

Sometimes it's useful to capture the display output as a means of archiving a procedure or to demonstrate a user experience. The following command will capture the display region 1680x1050 at 30fps for 90 seconds and shrink it to a 640x480 video at near raw resolution (fixed quantizer scale of 1).

The important thing is to confirm your ffmpeg format supports x11grab, otherwise you'll get the following error:

Unknown input or output format: x11grab

ffmpeg -y -f x11grab -r 30 -s 1680x1050 -i :0.0 -t 90 -qscale 1 -s 640x480 out.mpg

As you can imagine, capturing 30fps adds significant resource loading, if you so choose you can down-sample the frame rate but you may need to use an alternative encoder for non-compliant frame rates of some codecs.

The MJPEG encoder seems to work well enough for slow frame rates, like 1 Hz.

ffmpeg -y -f x11grab -r 1/1 -s 1680x1050 -i :0.0 -t 90 -qscale 1 -s 640x480 -vcodec mjpeg out.avi

07 June, 2009

Code Monkey

This video always makes me smile: