Tuesday, August 2, 2005

Using the Olympus C-770 with GNU/Linux


The Camedia C-770 Ultra Zoom was released in early 2004 by Olympus as the top-of-the-range camera in their UZ series. It features a 10x optical zoom with 4 Megapixel sensor, however the distinguishing feature of this camera is its ability to record 640x480 video at 30fps in MPEG-4 format. This allows the camera to record 30 minutes of TV quality video on a 512MB xD card. Olympus only includes Windows and Mac applications with the camera, therefore GNU/Linux or other OS users must find other software applications to utilise the camera. Olympus Camedia Master 4.2 for Windows and Macintosh provides the ability to upload, organise and print your photos. Also included is VideoStudio 7 (SE Basic) which provides video editing capabilities.

Connecting to your PC

The camera supports both the USB Mass Storage and PTP protocols therefore connecting the camera to a PC should not be a problem. In fact, if you use a modern distribution (such as Mandriva 2005 LE) you should not have to change your PC's configuration before uploading your photos and videos.

It is advisable to connect the camera to the recommended DC power source before uploading your photos since otherwise you will drain your batteries quickly. Connect the camera to the PC using the supplied USB cable and power-on the camera. Select the PC option and the camera will connect to PC. If you use an up-to-date desktop then an icon should appear that identifies the camera. If no icon appeared on the desktop then configure the desktop to display icons for newly mounted storage devices. However it may be that the OS has not mounted the device correctly. Check the directory /mnt/ to see if the camera is listed - if it is not listed then the OS requires correct configuration. This configuration is outside the scope of this document, however there is a lot of good documentation describing how to do this.

The Linux Documentation Project provides a HOWTO on connecting USB cameras to GNU/Linux PCs. The guide is a little out-dated but will point you in the right direction. The HOWTO is available at http://www.tldp.org/HOWTO/USB-Digital-Camera-HOWTO/index.html. A better option is to investigate web forums for your particular distribution - it is guaranteed that several users have solved the same problem already.

Photo Manipulation

Once the camera is correctly connected, photos can be uploaded to the PC using a variety of the methods. The most basic method is to open the directory on the camera that contains the photo and video files and to copy these to a directory on the PC. This works perfectly well but can become boring after a while so it is recommended to automate this process as much as possible. Use a photo album application to organise and automate the upload of your photos. One example of such an application is Digikam, the KDE photo application. Digikam allows the definition of one or multiple cameras and it then handles the upload of photos for these cameras and their organisation into albums. More information of Digikam is available at http://www.digikam.org/ and there should be a packaged version available for your distribution.

MPEG-4 Movies

The C-770 stores video in the MPEG-4 format and the soundtrack is stored in the AAC audio format. Both the audio and video streams are then packaged in the MP4 file format, which is essentially a Quicktime file format. As of the time of writing, common GNU/Linux media players such as Kaffeine may or may not play these files, depending on the version of the application you have. All of the software is available, however due to patent and licensing concerns it is not included as default in some distributions. Playing and editing MPEG-4 videos is possible, it justs requires a little know-how. Currently there are two options and these are now examined.

The first option is to acquire application software that will allow you to play and edit the MP4 files. The best option for playing the movies is Xine, a movie player that includes MPEG-4 support and which can use FAAD2 to provided AAC decoding. A FAAD2 enabled version of Xine is required therefore some investigation may be needed. As for the editing of MPEG-4 video and audio, I am not aware of a satisfactory application - the best option is to transcode the movies to a more editable format such as MPEG-2 (see below).

The second option is to convert these MP4 files to a more commonly supported format that will allow you to play, share and edit these movies. Converting the format of an audio or video stream is called transcoding and several tools are available to accomplish this task. FAAD2 is a decoder for AAC streams that can transcode them to other audio formats such as mp2, mp3 or AC3. FFMPEG is a powerful video decoder that supports the MPEG-4 video format. FFMPEG also includes a basic movie player called ffplay but this does not currently (version 0.4.9) support the AAC format. MENCODER can also be used to transcode the video from MPEG-4 to a range of other formats. The next decision to make is to decide the target file format to use. The most common GNU/Linux movie players such as Kaffeine and MPlayer support several movie formats such as mpg, avi and divx so if playing the movies on a GNU/Linux PC is the aim then any of these formats will suffice. If care is taken during the transcoding process then the movie quality will not be degraded but the file size may increase depending on the file format you use. If the aim is to create DVDs from the mp4 movies, then transcode the movies to either an MPEG-2 VOB format or a DivX format and use a tool such as QDVDAuthor to create the DVD. The movies can be edited and amalgamated with a tool such as Kdenlive or LVE if they are in the MPEG-2 format.

As with all GNU/Linux software, the choices are almost limitless and can be confusing. To simplify the process for users of the C-770 and other mp4 capable cameras, I have created a Perl script that automates the transcoding of the mp4 files to more usable formats.

mp4conv

mp4conv.pl is a perl script that uses the FAAD2, FFMPEG and MPEG2ENC tools to transcode mp4 file to other common formats. Download the script and place it in a directory that is on your PATH so that you can execute it. Also, don't forget to chmod +x it to make the script executable. The command mp4conv --help will then print the usage options of the script. It currently supports the following operations;

  • MPEG2: --mpeg2 transcodes the video and audio to plain old MPEG2 at the same quality and packages then in an mpg file. Expect a much larger file that can be viewed almost anywhere.
  • MPEG4. --mpeg4 doesn´t touch the video, transcodes the audio to MPEG2 and stores the movie in the avi format. This makes the movie more viewable but keeps the same level of compression.
  • DVD. --dvd creates a PAL compatible MPEG2 stream, with MP2 soundtrack and DVD NAV packets that you can then use to create DVDs. Supporting NTSC only requires changing the image dimensions and fps within the script.
  • WINDOWS. --windows creates an avi file that all your sad Windows-using friends can view.
  • DV. --dv is supposed to create a DVI file that you can then edit. This option is currently not completed.

The power of this script is that with one command you can convert all your mp4 files to a range or common movie formats - no more pointing and clicking for hours!

Conclusion

The C-770 is a good camera with impressive movie recording abilities but some effort is required to use it to full effect with current GNU/Linux distributions. Use the following references to investigate the options and utilize the mp4conv.pl script to automate the drudgery. Happy snapping!

References

http://linux.omnipotent.net/article.php?article_id=11500 gives a basic introduction to the AAC audio format.

http://www.ndeepak.info/tech/c770uz.php provides a guide to connecting the camera to an older Debian PC. Debian Sarge may provide better support out of the box - I'm not sure.

http://www.audiocoding.com is home of the FAAD2 audio decoder.

http://ffmpeg.sourceforge.net/ is the home of FFMPEG, the video decoder.

http://mjpeg.sourceforge.net/ is home to the excellent MJPEG toolset, which provides mpeg2enc.

http://xinehq.de/ is the HQ of Xine, a powerful media player.

The Script

#! /usr/bin/perl -w

# Olympus C-770 MPEG-4 Movie Conversion Script
#
# M.McCarthy
# Version 0.6

use strict 'vars';
use English;

# constants
my $SUCCESS = 0;
my $FAIL = 77;

# Video formats
my $MPEG2 = "MPEG2 MPG";
my $MPEG2EXT = "_mpeg2";
my $DVD = "DVD AVI";
my $DVDEXT = "_dvd";
my $MPEG4 = "MPEG4 AVI";
my $MPEG4EXT = "_mpeg4";
my $WINMV = "WINDOWS AVI";
my $WINMVEXT = "_wmv";
my $DV = "DV";
my $DVEXT = "_dv";
my $YOUTUBE = "YOUTUBE PREFERRED";
my $YOUTUBEEXT = "_youtube";

my $VERSION = "0.6";

# function prototypes
sub mp4convert( $$ );
sub printHelp();

#### Main Function starts here ####

# print header info
print "*************************************************\n";
print "* Olympus C-770 Movie Conversion Utility v.".$VERSION." *\n";
print "* (c) M.McCarthy 2005,2006 *\n";
print "*************************************************\n";

# check dependencies
my @clargsFaad = ("which", "faad");
system(@clargsFaad) == 0
or die "Error: FAAD2 not available";
my @clargsMencoder = ("which", "ffmpeg");
system(@clargsMencoder) == 0
or die "Error: FFMPEG not available";
@clargsMencoder = ("which", "mpeg2enc");
system(@clargsMencoder) == 0
or die "Error: mpeg2enc not available";

my $file;

# set defaults
my $outputFormat = $MPEG4; # default is MPEG-4 AVI with sound
# used to generate statistics at end
my $numOfFiles = 0;
my $numOfConversions = 0;

not @ARGV
and die "Error: No filename passed as argument";

# parse the commandline arguements
for $file ( @ARGV )
{
if ( -e $file
and $file =~ m/.+mp4$/ )
{
$numOfFiles= $numOfFiles+1;

if( mp4convert( $file, $outputFormat ) != 0 )
{
warn "Error: $file could not be converted";
}
else
{
$numOfConversions = $numOfConversions + 1;
}
}
elsif( $file =~ m/.*(--mpeg2).*/ )
{
$outputFormat = $MPEG2;
}
elsif( $file =~ m/.*(--dvd).*/ )
{
$outputFormat = $DVD;
}
elsif( $file =~ m/.*(--mpeg4).*/ )
{
$outputFormat = $MPEG4;
}
elsif( $file =~ m/.*(--windows).*/ )
{
$outputFormat = $WINMV;
}
elsif( $file =~ m/.*(--dv).*/ )
{
$outputFormat = $DV;
}
elsif( $file =~ m/.*(--youtube).*/ )
{
$outputFormat = $YOUTUBE;
}
elsif( $file =~ m/.*(--help).*/ )
{
printHelp();
}
else
{
warn "Warning: $file is not a valid option or filename";
}
}

print "**********************************************\n";
print " Summary:\n";
print " Files Processed : ", $numOfFiles, "\n";
print " Successful : ", $numOfConversions, "\n";
print " Errors : ", ($numOfFiles-$numOfConversions), "\n";
print "**********************************************\n";

exit;

# passed an mp4 filename, converts to avi format
sub mp4convert( $$ )
{
my $status = $SUCCESS;

my $srcFile = shift( @_ );
print "Source File: ", $srcFile, "\n";

my $output = shift( @_);
print "Target Format: ", $output, "\n";

# generate temp audio filename
$_ = $srcFile;
s/(mp4)$/wav/;
my $audioFile = $_;
print "==> Temp audio file: ", $audioFile, "\n";

# extract audio from mp4 file
my $faadArgs = "faad -o ".$audioFile." ".$srcFile;
print "==> ", $faadArgs, "\n";
system($faadArgs) == 0
or warn "Error: Could not extract audio from MPEG-4 file";
if( -e $audioFile )
{
print "OK: Audio extraction completed.\n";
}
else
{
warn "Error: No temp audio file produced";
return $FAIL;
}

# setup output options for conversion
my $outOpts;
my $nameExt;

if( $output eq $MPEG2 )
{
$outOpts = "-sameq -s 640x480 -aspect 4:3 -vcodec mpeg2video -acodec mp2";
$nameExt = $MPEG2EXT.".mpg";
}
elsif( $output eq $DVD )
{
$outOpts = "-b 2000 -s 720x576 -r 25 -an -f yuv4mpegpipe";
# $outOpts = "-sameq -target pal-dvd -an";
$nameExt = $DVDEXT.".yuv";
}
elsif( $output eq $MPEG4 )
{
$outOpts = "-sameq -s 640x480 -vcodec mpeg4 -acodec mp2";
$nameExt = $MPEG4EXT.".avi";
}
elsif( $output eq $WINMV )
{
$outOpts = "-sameq -s 640x480 -vcodec wmv2 -acodec mp2";
$nameExt = $WINMVEXT.".avi";
}
elsif( $output eq $DV )
{
$outOpts = "-sameq -s 720x576 -vcodec dvvideo";
$nameExt = $DVEXT.".dv";
}
elsif( $output eq $YOUTUBE )
{
$outOpts = "-sameq -s 320x240 -vcodec mpeg4 -acodec mp3";
$nameExt = $YOUTUBEEXT.".mpg";
}
else
{
warn "Error: No output option selected";
$status = $FAIL;
}

# generate target filename
$_ = $srcFile;
s/(\.mp4)$/$nameExt/;
my $outFile = $_;
print "Target File: ", $outFile, "\n";

# generate the target file
my $mencArgs = "ffmpeg -y -i ".$srcFile." -i ".$audioFile." ".$outOpts." ".$outFile;
print "==> ", $mencArgs, "\n";

if( $status == $SUCCESS
&& system($mencArgs) != 0 )
{
warn "Error: could not convert $srcFile";
$status = $FAIL;
}
else
{
print "OK: Video conversion successful.\n";
}

# if dvd source required, then generate a DVD standard stream

# generate temp mp2 filename
$_ = $audioFile;
s/(\.wav)$/_tmp\.ac3/;
my $m2aFile = $_;

# convert pcm file to MPEG-2 audio
if( $output eq $DVD
&& $status == $SUCCESS )
{
# print "AC3 Audio File: ", $m2aFile, "\n";
$mencArgs = "ffmpeg -i ".$audioFile." -acodec ac3 -ab 128 ".$m2aFile;
print "==> ", $mencArgs, "\n";

if( system($mencArgs) != 0 )
{
warn "Error: could not convert $audioFile to AC3 format";
$status = $FAIL;
}
else
{
print "OK: AC3 Audio conversion successful.\n";
}
}

# generate temp mpeg-2 filename
$_ = $srcFile;
s/(\.mp4)$/_tmp\.mpg/;
my $m2vFile = $_;

# convert MPEG-2 video to DVD standard MPEG-2 video
if( $output eq $DVD
&& $status == $SUCCESS )
{

# print "MPEG-2 Video File: ", $m2vFile, "\n";

$mencArgs = "mpeg2enc -n p -f 8 -s -o ".$m2vFile." < ".$outFile;
print "==> ", $mencArgs, "\n";

if( system($mencArgs) != 0 )
{
warn "Error: could not convert $outFile to MPEG-2 DVD video format";
$status = $FAIL;
}
else
{
print "OK: MPEG-2 DVD video conversion successful.\n";
}

}

# multiplex MPEG-2 video, MP2 audio and DVD NAV packets
if( $output eq $DVD
&& $status == $SUCCESS )
{
# multiplex the files together
$_ = $outFile;
s/dvd\.yuv/dvdvob\.mpg/;
my $dvdFile = $_;
print "Target File: ", $outFile, "\n";

$mencArgs = "mplex -f 8 -o ".$dvdFile." ".$m2vFile." ".$m2aFile;
print "==> ", $mencArgs, "\n";

if( system($mencArgs) != 0 )
{
warn "Error: could not create DVD VOB file";
$status = $FAIL;
}
else
{
print "OK: DVD VOB file creation was successful.\n";
}
}


#cleanup temporary files
if ( -e $audioFile )
{
system("rm -f $audioFile") == 0
or warn "Warning: Could not remove temp file $audioFile";
}
if ( -e $m2aFile )
{
system("rm -f $m2aFile") == 0
or warn "Warning: Could not remove temp file $m2aFile";
}
if ( -e $m2vFile )
{
system("rm -f $m2vFile") == 0
or warn "Warning: Could not remove temp file $m2vFile";
}
if ( $output eq $DVD
&& -e $outFile )
{
system("rm -f $outFile") == 0
or warn "Warning: Could not remove temp file $outFile";
}

return $status;
}


sub printHelp()
{
print "\n";
print $PROGRAM_NAME, " input filename(s)\n";
print " --help\n";
print " Print this screen\n";
print " --mpeg2\n";
print " MPEG-2 Video with MP2 Audio\n";
print " --divx\n";
print " MPEG-4 DIVX-5 Video with AC-3 Audio\n";
print " --mpeg4 (default)\n";
print " MPEG-4 Video with MP2 Audio\n";
print " --windows\n";
print " WMV Video with MP2Audio\n";
print " --dv\n";
print " Digital Video DV\n";
print " --youtube\n";
print " Youtube Preferred Format\n";
return;
}