Losslessly split/merge AVI video files
Posted: Sat Feb 27, 2010 8:54 pm
I know that there are plenty ways of splitting AVI files, but I needed it with a bit more reliability and precision than most others require for home use. The video was encoded using Huffyuv (so it's lossless and only keyframes), and the audio was PCM 16bit 48kHz.
So it should be possible to exactly cut the video at a given frame/sample and merge it back together later on, without a single bit getting lost.
Well, it seems that ffmpeg/mencoder/etc are not really optimized for this, but rather for handling lossy formats (like XviD, mpeg, etc..) - so I had to fiddle around with their options a bit.
Here's what I've managed so far:
1) Split the video every minute, at exactly the last frame of each minute (e.g. 00:00:00.00 - 00:00:59.24):
About the variables (bash-style):
This is necessary in order to *make sure* we don't lose a single audio sample during split/merge due to muxing-synchronization oddities, depending on the tools used.
First of all, extract the audio out of the AVI file:
Now I'm using the awesome "swiss army knife of audio processing" tool "SoX" to split/merge the audio:
The variables are similar to the ones used for the video. I suppose you'll get the idea how it works.
Now, in order to merge everything back, you simply concatenate the audio files like this:
It's bit-proof. I've checked this, by inverting the original audio and mix it together with the merged copy. The outcome was a perfect flat-line audio.
I wish it was that easy with video with ffmpeg, but it seems that mencoder is easier for that:
The parameters "-oac copy" and "ovc copy" are again: "copy audio/video as-is. Don't transcode. Don't touch"
Again, I've verified that this method does not drop or multiply frames, by embedding a visual timecode (min:sec.frame) into the original video before splitting it (I've used kdenlive's embed-timecode-option for this).
So it should be possible to exactly cut the video at a given frame/sample and merge it back together later on, without a single bit getting lost.
Well, it seems that ffmpeg/mencoder/etc are not really optimized for this, but rather for handling lossy formats (like XviD, mpeg, etc..) - so I had to fiddle around with their options a bit.
Here's what I've managed so far:
1) Split the video every minute, at exactly the last frame of each minute (e.g. 00:00:00.00 - 00:00:59.24):
Code: Select all
ffmpeg -ss $OFFSET.000 -t (($INTERVAL - 1)).999 -i $INPUT -an -vcodec copy $OUTPUT.avi
- $OFFSET: time offset where to start the video sequence. You'll need a loop around the above line to get multiple segments.
$INTERVAL: time interval (in seconds) of each segment to extract.
$INPUT: (full length) input video filename (e.g. "long_video.avi")
$OUTPUT: output video filename of current video segment (e.g. "long_video-003.avi" for the 3rd segment)
- -ss: Start at a given timestamp. Format: "sec.msec"
-t: Only "play" (=extract) a certain interval. Format: "sec.msec"
-i: The input video filename (full length)
-vcodec copy: Copy the video data as-is. Don't transcode or touch it.
-an: Do *not* copy any audio. Yes. that's right: No audio - just the video. You'll see later on, why.
This is necessary in order to *make sure* we don't lose a single audio sample during split/merge due to muxing-synchronization oddities, depending on the tools used.
First of all, extract the audio out of the AVI file:
Code: Select all
ffmpeg -i $VIDEO.avi -vn -acodec copy $AUDIO.wav
Code: Select all
sox $AUDIO.wav $SEGMENT_X.wav trim $OFFSET $INTERVAL
Now, in order to merge everything back, you simply concatenate the audio files like this:
Code: Select all
sox $SEGMENT1 $SEGMENT2 ... $SEGMENT_N $OUTPUT_MERGED.wav
I wish it was that easy with video with ffmpeg, but it seems that mencoder is easier for that:
Code: Select all
mencoder -oac copy -ovc copy $SEGMENT1 $SEGMENT2 ... $SEGMENT_N -o $OUTPUT_MERGED.avi
Again, I've verified that this method does not drop or multiply frames, by embedding a visual timecode (min:sec.frame) into the original video before splitting it (I've used kdenlive's embed-timecode-option for this).