From: Alan J. Pippin Date: Sun, 11 Dec 2011 17:45:25 +0000 (-0700) Subject: Added a workaround for a bug in mkv tool's ability to handle 1080i (interlaced HD... X-Git-Url: http://git.pippins.net/embedvideo/.git/%22%22.%24thumbnail.%22/images/static/git-favicon.png?a=commitdiff_plain;h=9580365135dbaa7c89e0e30f097c566e9a3a6650;p=videoscripts%2F.git Added a workaround for a bug in mkv tool's ability to handle 1080i (interlaced HD) video. --- diff --git a/make_mkv b/make_mkv index 042e38e..04556e5 100755 --- a/make_mkv +++ b/make_mkv @@ -106,8 +106,44 @@ print "$chapter_file_contents\n"; print "-> Creating the MKV video file '$opt_o'\n"; my $cmd = "$mkvmerge --title \"$opt_t\" $output_file_options -o \"$opt_o\""; + +# Make our input file command line options for all the videos my $video_count = 0; +my @video_tmp_files; foreach my $video (sort{$videos{$a} <=> $videos{$b}} keys %videos) { + # Detect if the input file is interlaced or not. + # There is a bug in mkvmerge 5.0.1 and earlier where if the video content is 1080i, it doesn't mux it properly, and it stutters. + # The quick solution to this issue is to run the interlaced video file through ffmpeg and tell it to copy the video/audio streams to a mkv container. + # We will then merge this temporarily created mkv container into the final mkv container instead of the original interlaced video. + # http://ubuntuforums.org/showthread.php?t=1627194 + # http://forum.doom9.org/showthread.php?t=155732&page=31 + my $interlaced = system('ffmpeg -i "$video" 2>&1 | grep -q "frame rate differs"'); + if($interlaced != 0) { + my $video_mkv = $video; + my $video_ext = $video; + $video_ext =~ s/.*\.(\S+)$/$1/; + print " Detected interlaced video content: $video\n"; + if($video_ext !~ /mkv/i) { + $video_mkv =~ s/\.[^.]*$//; $video_mkv .= ".mkv"; + print " Re-muxing the interlaced video content as an mkv file: $video_mkv\n"; + my $make_mkv_cmd = "ffmpeg -i \"$video\" -scodec copy -acodec copy -vcodec copy -f matroska \"$video_mkv\" > /dev/null 2>&1"; + if(! defined $opt_s) { + my $errno = system("$make_mkv_cmd"); + $errno = $errno >> 8; + if($errno > 1) { + unlink "$video_mkv"; + die "-E- ffmpeg encountered some errors with exit code $errno\n"; + } + } + # Push the name of our intermediate video file onto a list of files to delete on exit + push(@video_tmp_files, "$video_mkv"); + # Update the name of our video file to equal the name of our new intermediate video file name + $video = $video_mkv; + } + } else { + print " Detected progressive video content: $video\n"; + } + # Create our intput file command line options for this video if($video_count == 0) { $cmd .= " $input_file_options \"$video\""; } else { @@ -115,7 +151,9 @@ foreach my $video (sort{$videos{$a} <=> $videos{$b}} keys %videos) { } $video_count++; } -print "$cmd\n"; + +# Execute our command line +print "\n$cmd\n"; if(! defined $opt_s) { my $errno = system("$cmd"); $errno = $errno >> 8; @@ -128,5 +166,10 @@ if(! defined $opt_s) { # Remove the temporary file used for the chapter generation if(-e "$tmpfile") { unlink "$tmpfile"; } +# Remove any temporary video files created during the merge process +foreach my $video (@video_tmp_files) { + if(-e "$video") { unlink "$video"; } +} + #################################################################################################### diff --git a/mkv2mp4 b/mkv2mp4 index 463c3d3..afbd0a8 100755 --- a/mkv2mp4 +++ b/mkv2mp4 @@ -1,12 +1,27 @@ #!/bin/bash -# step 1: convert the mkv to mpg ; many mkv files do not directly get converted to mp4 -mencoder "$1" -ovc lavc -lavcopts vcodec=mpeg1video -aid 0 -oac pcm -o delete_me.mpg +INPUT=$1 +FILENAME=${INPUT%%.*} +OUTPUT="$FILENAME.mp4" -# step 2: convert the mpg file to mp4 -mencoder -of lavf -lavfopts format=mp4 -oac lavc -ovc lavc -lavcopts \ -aglobal=1:vglobal=1:acodec=libfaac:vcodec=mpeg4:abitrate=128:vbitrate=640:keyint=250:mbd=1:vqmax=10:lmax=10:turbo -af lavcresample=44100 \ --vf harddup,scale=640:-3 "delete_me.mpg" -o "$1.mp4" +echo "-> Converting $INPUT to $OUTPUT file" -# step 3: delete the temporary huge sized mpg file -rm "delete_me.mpg" +if [[ -e "$OUTPUT" ]]; then + echo "-E- Output file $OUTPUT already exists. Aborting..." + exit 1 +fi + +ffmpeg -i $INPUT \ + -b:v 3000k \ + -vcodec libx264 \ + -acodec copy \ + -coder 1 \ + -flags +loop -cmp +chroma -partitions +parti4x4+partp8x8+partb8x8 \ + -subq 5 \ + -me_range 16 \ + -g 250 \ + -keyint_min 25 \ + -sc_threshold 40 \ + -i_qfactor 0.71 \ + -threads 2 \ + $OUTPUT diff --git a/mkv_extract_chapter b/mkv_extract_chapter index 4653278..b70a750 100755 --- a/mkv_extract_chapter +++ b/mkv_extract_chapter @@ -44,7 +44,7 @@ my $tmpfile = `tempfile`; chomp($tmpfile); #################################################################################################### # 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 \n"; } @@ -64,6 +64,7 @@ sub usage { print " -e 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; } @@ -72,7 +73,7 @@ sub usage { # SUBROUTINES sub detect_ext { - my ($ffmpeg_info) = @_; + my ($ffmpeg_info, $interlaced) = @_; my $h264 = 0; my $h264_high = 0; @@ -93,9 +94,9 @@ sub detect_ext { # Quicktime/MOV if($h264 && $pcm_s16le) { return "mov"; } # MTS - if($h264_high && $ac3) { return "mp4"; } + if($h264_high && $ac3) { if($interlaced) { return "mkv"; } else { return "mp4"; } } # 3GP/MP4 - if($h264 && $aac) { return "mp4"; } + if($h264 && $aac) { if($interlaced) { return "mkv"; } else { return "mp4"; } } return "UNKNOWN"; } @@ -117,6 +118,13 @@ my $all_chapters = 0; if($opt_c =~ /all/) { $all_chapters = 1; } print "-> Extracting the following chapters from $opt_i: @chapters\n"; +my $interlaced = system('ffmpeg -i "$opt_i" 2>&1 | grep -q "frame rate differs"'); +if($interlaced != 0) { + 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`; @@ -131,10 +139,10 @@ foreach $line (@ffmpeg_info) { 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, $interlaced); } if($ext =~ /UNKNOWN/) { die "-E- Unable to determine the file type/extension to use for the output videos. Specify it with the -e 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"; @@ -145,6 +153,22 @@ foreach $line (@ffmpeg_info) { $errno = $errno >> 8; if($errno > 0) { die "-E- ffmpeg encountered some errors with exit code $errno\n"; } } + if($interlaced && $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"; } + } + } } } }