Saturday, December 27, 2008

Using ffmpeg to split MOD movie files.

My wife and I recently purchased a Panasonic SDR-H40 for capturing video of our son and daughter, after our Canon MiniDV crapped out last year. It was disappointing when the Canon failed again...TWO times this thing decides to get tape debris caught in the heads. This was the most delicate camera ever owned, and captured excellent quality footage, but I will NEVER buy another tape-based machine.

The Panasonic falls short in the quality department as compared to the Canon, and we knew that going in. The maximum video quality is 10mbps, which seems to be pretty good quality on a laptop. I haven't tried it on a analog TV yet.

Image representing YouTube as depicted in Crun...Image via CrunchBase

I needed to post these clips on YouTube for family and friends located in various parts of the planet, and rapidly discovered that the MOD files stored on the SDR-H40 can be accessed easily as plugging in the USB card, and waiting for udev to automatically mount it on my shiny new installation of Ubuntu.

I discovered that the SDR-H40 encodes the video in MPEG2 and audio in Dolby Digital (2ch)/MPEG1 Audio Layer2. I seem to remember reading somewhere that this was a non-standard combination of video/audio. This was confirmed when I attempted to simply rename the files to either mpeg or mp2 and load them into Cinelerra. Sometimes I had audio, sometimes not. Sometimes video, sometimes not. I'm not as familiar with Cinelerra as I am with Premier, but thought they looked rather similar...not.

I eventually found that using ffmpeg could potentially do what I needed, but didn't want to type in a command for every file I had, splitting them into 10 minute segments that YouTube demands. The following script was what I eventually came up with, after scouring the web for examples from seemingly ffmpeg experts. Thanks Experts!!!!

UPDATE:
I've found that while the below script worked well for splitting longer videos efficiently, it failed to produce satisfactory results. There was a serious quality issue with the compression method that I was using, and it needed to change.

I started experimenting with different compression methods, but couldn't find one that worked. I finally just uploaded a .MOD video file (mpeg2video) and YouTube converted it! Great, but not so great since these videos in MPEG2 format get rather large. Downloading and installing WinFFMPEG resolved my lack of knowledge in the video compression area, as it has a built in set of methods, and shows you the command line used to produce conversions. VERY handy.

Unfortunately, the videos produced by this and many cameras like it format the size to 704x480, which looks best played at a 16:9 aspect ratio, but YouTube insists on 4:3. I began to play with padding, cropping, resizing, but nothing seemed to work. I was finally able to find an obscure thread on YouTubes' Community Help Forums (Search for 704x480) where the last post addresses this easily; simply tag your video with "yt:stretch=16:9". Wow, that's it? GREAT!

Below is my modified script, using the borrowed template XVID compression method from WinFFMPEG.

#!/bin/sh

# This script will recursively find all
# mod files beneath it in the file system
# and convert them to MPEG4 XVID format.
# If they are longer than 10 minutes,
# they will be split into 10 minute chunks.

FILES=`find . -type f -name "*.mod"`

for F in $FILES
do
		
	#
	# First, get file names from input
	######################################
	DIR=`dirname $F`  	
	FNAME=`basename $F`
	BASE=`basename $F .mod`
	EXT="mod"

	#
	# Now, get the length of the clip
	######################################
	HOURS=`ffmpeg -i $F 2>&1 | grep "Duration" | cut -d ' ' -f 4 | sed s/,// | cut -d ":" -f 1`
	MIN=`ffmpeg -i $F 2>&1 | grep "Duration" | cut -d ' ' -f 4 | sed s/,// | cut -d ":" -f 2`
	SEC=`ffmpeg -i $F 2>&1 | grep "Duration" | cut -d ' ' -f 4 | sed s/,// | cut -d ":" -f 3 | cut -b -2`
	
	echo "The duration of $BASE.$EXT is $HOURS:$MIN:$SEC."

	#
	# If minutes are greater than 10, we need to cut it up for YouTube
	##################################################################
	if [ $MIN -gt "10" ]; then
	
	echo "$FNAME is longer than 10 minutes long. Splitting now..."
	
	#
	# We need to get the minutes, so I've split these up into BMIN and SMIN, e.g. 15 minutes, BMIN=1 SMIN=5
	####################
	BMIN=`echo $MIN | cut -c 1`
	SMIN=`echo $MIN | cut -c 2`

	# Set a counter
	i=0
	
		#
		# Loop over the video, grabbing it in 10 minute increments.
		# I know I'll NEVER record anything that exceeds 1 hour.
		# While I'm sure this can be done easier, egg-nog and whiskey
		# prevents me from thinking of one...
		##########################################################
		while [ $i -le $BMIN ]
		do
		
			case $i in
				0)
				STIME="00:00:00"
				FTIME="00:10:00"
				;;
				1)
				STIME="00:10:00"
				if [ $MIN -lt "20" ]; then
					FTIME=$HOURS:$MIN:$SEC
				else
					FTIME="00:20:00"
				fi
				;;
				2)
				STIME="00:20:00"
				if [ $MIN -lt "30" ]; then
					FTIME=$HOURS:$MIN:$SEC
				else
					FTIME="00:30:00"
				fi
				;;
				3)
				STIME="00:30:00"
				if [ $MIN -lt "40" ]; then
					FTIME=$HOURS:$MIN:$SEC
				else
					FTIME="00:40:00"
				fi
				;;
				4)
				STIME="00:40:00"
				if [ $MIN -lt "50" ]; then
					FTIME=$HOURS:$MIN:$SEC
				else
					FTIME="00:50:00"
				fi
				;;
				5)
				STIME="00:50:00"
				if [ $MIN -lt "60" ]; then
					FTIME=$HOURS:$MIN:$SEC
				else
					FTIME="00:60:00"
				fi
				;;
				6)
				STIME="00:60:00"
				FTIME="01:00:00"
				;;
			esac
			
			ffmpeg -i $F -f avi -ss $STIME -t $FTIME -r 29.97 -vcodec libxvid -vtag XVID -maxrate 1800kb -b 1500kb -qmin 3 -qmax 5 -bufsize 4096 -mbd 2 -bf 2 -flags +4mv -trellis -aic -cmp 2 -subcmp 2 -g 300 -acodec libmp3lame -ar 48000 -ab 128kb -ac 2 $DIR/$BASE-$i.avi
			i=`/usr/bin/expr $i + 1`
		done


	else
		ffmpeg -i $F -f avi -r 29.97 -vcodec libxvid -vtag XVID -maxrate 1800kb -b 1500kb -qmin 3 -qmax 5 -bufsize 4096 -mbd 2 -bf 2 -flags +4mv -trellis -aic -cmp 2 -subcmp 2 -g 300 -acodec libmp3lame -ar 48000 -ab 128kb -ac 2 $DIR/$BASE.avi
	fi

done
Reblog this post [with Zemanta]

1 comment:

Anonymous said...

Interesting subject. Perhaps I can use some of the information