+#!/usr/bin/perl
+# Author: Alan J. Pippin
+# Description: Extract the given chapter(s) from an mkv file into separate video files
# MOV:
+# major_brand : qt
# Video: h264 (avc1 / 0x31637661)
# Audio: pcm_s16le
-ffmpeg -ss 00:00:00.000 -t 00:00:38.299 -i 2010-12-04.000.mkv -map 0 -vcodec copy -acodec copy test.mov
# MTS:
-# Video: h264 (High)
-# Audio: ac3
+# Video: h264 (High) (HDMV / 0x564D4448)
+# Audio: ac3 (AC-3 / 0x332D4341)
# MP4:
# Video: h264 (Baseline) (avc1 / 0x31637661)
# Audio: aac (mp4a / 0x6134706D)
+# 3GP:
+# Video: h264 (Baseline) (avc1 / 0x31637661)
+# Audio: aac (mp4a / 0x6134706D)
+
+# FFMPEG EXAMPLE CMD:
+#ffmpeg -ss 00:00:00.000 -t 00:00:38.299 -i 2010-12-04.000.mkv -map 0 -vcodec copy -acodec copy test.mov
+
+####################################################################################################
+# Includes
+use File::Copy;
+use File::Basename;
+use Getopt::Std;
+
+####################################################################################################
+# Configuration parameters - CHANGE THESE TO SUITE YOUR NEEDS
+my $ffmpeg=`which ffmpeg`; chomp($ffmpeg);
+my $tmpfile = `tempfile`; chomp($tmpfile);
+####################################################################################################
+
+####################################################################################################
+# Command Line Options
+getopts("c:i:o:se:");
+
+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"; }
+if(! defined $opt_c) { &usage(); die "-E- Missing required chapter: -c <all|1,2,...>"; }
+if(! -r $opt_i) { &usage(); die "-E- Unable to open/find the input mkv file: $opt_i\n"; }
+if(! defined $opt_o) {
+ if($opt_i =~ /^(\d+-\d+-\d+)/) { $opt_o = $1; }
+ elsif($opt_i =~ /^(.*?)\./) { $opt_o = $1; }
+}
+
+sub usage {
+ print "usage: $0 -i <input.mkv> -o <output_base_name> -c <chapter,chapter,...>\n";
+ print " -c <chapter,chapter,...> Specify which chapter from the mkv file to extract (all or 1,2,3, ...)\n";
+ print " -i <input.mkv> Specify the name of the input mkv file\n";
+ print " -o <output_base_name> Sets the base name to use when naming the output videos extracted from the chapters\n";
+ print " If not specified, the base name will be taken from the name of your input video\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 "\n";
+ return 1;
+}
+
+####################################################################################################
+# SUBROUTINES
+
+sub detect_ext {
+ my ($ffmpeg_info) = @_;
+
+ my $h264 = 0;
+ my $h264_high = 0;
+ my $ac3 = 0;
+ my $aac = 0;
+ my $pcm_s16le = 0;
+
+ foreach $line (@{$ffmpeg_info}) {
+ if($line =~ /Stream/) {
+ if($line =~ /h264/i) { $h264 = 1; }
+ if($line =~ /h264.*High/i) { $h264_high = 1; }
+ if($line =~ /ac3/i) { $ac3 = 1; }
+ if($line =~ /aac/i) { $aac = 1; }
+ if($line =~ /pcm_s16le/i) { $pcm_s16le = 1; }
+ }
+ }
+
+ if($h264 && $pcm_s16le) { return "mov"; }
+ if($h264_high && $ac3) { return "mts"; }
+ if($h264 && $aac) { return "mp4"; }
+
+ return "UNKNOWN";
+}
+
+sub export_chapter {
+ my ($chapters, $chapter) = @_;
+ foreach $ch (@{$chapters}) {
+ if($ch == $chapter) { return 1; }
+ }
+ return 0;
+}
+
+####################################################################################################
+# MAIN
+
+# Turn our list of chapters into an ordered array
+my @chapters = sort(split(/,/, $opt_c));
+my $all_chapters = 0;
+if($opt_c =~ /all/) { $all_chapters = 1; }
+print "-> Extracting the following chapters from $opt_i: @chapters\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`;
+foreach $line (@ffmpeg_info) {
+ if($line =~ /Chapter #\d+\.(\d+): start (\S+), end (\S+)/) {
+ $chapter = $1;
+ $start = $2;
+ $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); }
+ 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: ";
+ $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";
+ $errno = system("$cmd");
+ $errno = $errno >> 8;
+ if($errno > 0) { die "-E- ffmpeg encountered some errors with exit code $errno\n"; }
+ }
+ }
+ }
+}
+
+####################################################################################################