#!/usr/bin/perl
# Author: Alan J. Pippin
# Description: Extract the given chapter(s) from an mkv file into separate video files
+# Requires: Newer version of ffmpeg to be installed that supports MKV chapters
+
+# Howto compile the latest FFMPEG from src under Linux
+# FFMPEG - http://ubuntuforums.org/showthread.php?t=786095
+
+# Howto eliminate the non-monotonically increasing dts to muxer error
+# Comment out the error message in ffmpeg src tree in libavformat/utils.c
+# http://ffmpeg.zeranoe.com/forum/viewtopic.php?f=7&t=49
# MOV:
# major_brand : qt
####################################################################################################
# Command Line Options
-getopts("c:i:o:se:");
+getopts("c:i:o:kse:");
if(! -x $ffmpeg) { die "-E- Unable to find required program: ffmpeg\n"; }
if(! defined $opt_i) { &usage(); die "-E- Missing required argument input video name: -i <input.mkv>\n"; }
print " -e <ext> Specify the extension that should be used on the output files.\n";
print " This is automatically determined. You only need to specify it if autodetection fails.\n";
print " -s Simulate mode. Don't actually make the video, but tell us what you will do\n";
+ print " -k Keep intermediate mkv file created during the extraction/conversion of mp4 clips\n";
print "\n";
return 1;
}
# SUBROUTINES
sub detect_ext {
- my ($ffmpeg_info) = @_;
+ my ($ffmpeg_info, $progressive) = @_;
my $h264 = 0;
my $h264_high = 0;
}
}
+ # Quicktime/MOV
if($h264 && $pcm_s16le) { return "mov"; }
- if($h264_high && $ac3) { return "mts"; }
- if($h264 && $aac) { return "mp4"; }
+ # MTS
+ if($h264_high && $ac3) { if(!$progressive) { return "mkv"; } else { return "mp4"; } }
+ # 3GP/MP4
+ if($h264 && $aac) { if(!$progressive) { return "mkv"; } else { return "mp4"; } }
return "UNKNOWN";
}
if($opt_c =~ /all/) { $all_chapters = 1; }
print "-> Extracting the following chapters from $opt_i: @chapters\n";
+my $progressive = system('ffmpeg -i "$opt_i" 2>&1 | grep -q "frame rate differs"');
+if(!$progressive) {
+ print " Detected interlaced video content\n";
+} else {
+ print " Detected progressive video content\n";
+}
+
# Use ffmpeg to extract the list of chapters available to rip
# For each chapter specified on the command line, use ffmpeg to extract a video clip from that chapter
my @ffmpeg_info = `$ffmpeg -i $opt_i 2>&1`;
if($line =~ /Chapter #\d+\.(\d+): start (\S+), end (\S+)/) {
$chapter = $1;
$start = $2;
+ if($start > 0) { $start += 1; } # Add some margin to prevent taking a piece of the previous clip
$end = $3;
$duration = $end - $start;
if($duration < 0) { die "-E- Unexpected negative duration detected for chapter $chapter\n"; }
if($all_chapters || &export_chapter(\@chapters,$chapter)) {
$ext = "UNKNOWN";
if(defined $opt_e) { $ext = $opt_e; }
- else { $ext = &detect_ext(\@ffmpeg_info); }
+ else { $ext = &detect_ext(\@ffmpeg_info, $progressive); }
if($ext =~ /UNKNOWN/) { die "-E- Unable to determine the file type/extension to use for the output videos. Specify it with the -e <ext> option.\n"; }
$dstfile = $opt_o . ".c" . sprintf("%03d",$chapter) . "." . $ext;
- print "-> Exporting $chapter to $dstfile: ";
+ print "-> Exporting $chapter to $dstfile:\n";
$cmd = "ffmpeg -ss $start -t $duration -i $opt_i -map 0 -vcodec copy -acodec copy $dstfile 2>&1";
if(defined $opt_s) {
print "$cmd\n";
} else {
print "\n";
+ print "$cmd\n";
$errno = system("$cmd");
$errno = $errno >> 8;
if($errno > 0) { die "-E- ffmpeg encountered some errors with exit code $errno\n"; }
}
+ if(!$progressive && $ext =~ /mkv/i) {
+ $ext = "mp4";
+ $srcfile = $dstfile;
+ $dstfile = $dstfile = $opt_o . ".c" . sprintf("%03d",$chapter) . "." . $ext;
+ $cmd = "mencoder -oac copy -ovc copy -of lavf -lavfopts format=mp4 -o $dstfile $srcfile";
+ if(defined $opt_s) {
+ print "$cmd\n";
+ } else {
+ print "\n";
+ print "$cmd\n";
+ $errno = system("$cmd");
+ $errno = $errno >> 8;
+ if(! defined $opt_k) { unlink "$srcfile"; }
+ if($errno > 0) { die "-E- mencoder encountered some errors with exit code $errno\n"; }
+ }
+ }
}
}
}