Wednesday, February 11, 2009

Canon FS10 recordings and Linux

I've been playing around with my new Canon FS10 digital camcorder (and having fun). The digital 2000x zoom sounds good but is not worth much in practice. The rest of the package is pretty good.

The recordings are saved as 2 files - a .MOD file (which is actually an MPEG-2 interlaced video file), and a corresponding .MOI file. The MOI file apparently contains information about the MOD file including date and time of the recording, duration and aspect ratio. Since I work on a Linux laptop most of the time, I was curious to see how easy it would be to transcode the MOD file into a smaller (e.g. DivX/XviD file), and also retain some of the information like the date and time of the recording. With a little help from Google, here's what I came up with, wrapped into a bash script:
  • pick up a .MOD file
  • read the corresponding .MOI file and extract the fields of interest (year, month, day, hour and minute of the recording, in my case). This page gives the structure of the .MOI file.
  • construct a human-readable string of the date and time
  • use FFMPEG to transcode the .MOD to an AVI using mpeg4 video and libmp3lame audio codecs, and also overlay the date and time string on the output using the drawtext.so vhook filter feature of FFMPEG
  • finally, use cfourcc to change the FourCC code as required.
Works like a charm, gets me good quality videos in half (or less) the original size, along with the date and time information embedded in the video. The complete script looks like this:

#!/bin/bash

### Convert .MOD files (from Canon FS10 digital camcorder) into AVI files.
### Source (.MOD) is MPEG-2 video sequence @ 9600 kbps, with AC3 audio @256 kbps,
### destination is .AVI with MPEG4 video @ 4800 kbps and MP3 audio @128 kbps.
### First pick the date/time of the recording from the .MOI file,
### then encode movie and overlay date/time info. using vhook of ffmpeg

months=(none Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)

for f in *.MOD
do
   bname=`basename $f .MOD`

   params=(`od -t x1 -j 6 -N 6 $bname.MOI | head -1`)
   yr=$((0x${params[1]}${params[2]}))
   mon=$((0x${params[3]}))
   day=$((0x${params[4]}))
   hr=$((0x${params[5]}))
   min=$((0x${params[6]}))

   if [ $hr -lt 10 ]
   then
      hr="0$hr"
   fi
   if [ $min -lt 10 ]
   then
      min="0$min"
   fi
   dtstr="$day ${months[$mon]} $yr, $hr:$min hrs"
   echo $dtstr > /tmp/mod.txt

   ffmpeg -i $f -deinterlace -vcodec mpeg4 -b 4800k -acodec libmp3lame -ab 128k -vhook '/usr/lib/vhook/drawtext.so -f /home/user/.fonts/Vera.ttf -s 14 -t mod.txt -T /tmp/mod.txt' $bname.avi

   cfourcc -u XVID $bname.avi

   rm /tmp/mod.txt
done

### end of script