#!/usr/bin/perl -w # ============================================================================ # = NAME # x264_transcode_efficient.pl # # = PURPOSE # Convert mpeg2 file from myth to h264 with aac audio. # # = USAGE my $usage = 'Usage: x264_transcode_efficient.pl -j %JOBID% x264_transcode_efficient.pl -f %FILE% '; # ============================================================================ use strict; use MythTV; use XML::Simple; # What file are we copying/transcoding? my $file = ''; my $jobid = -1; # do nothing? my $noexec = 0; # extra console output? my $DEBUG = 1; # some globals my ($chanid, $command, $query, $ref, $starttime, $showtitle, $episodetitle); my ($seasonnumber, $episodenumber, $episodedetails); my ($newfilename, $newstarttime); my $xmlparser = new XML::Simple; my $xmlstring; # globals for stream and resolution mapping my ($videostream, $audiostreamsurround, $audiostreamstereo, $framerate); # Set your desired output directory # my $outputdir = "/home/david/tmp"; # transcode options my $videocodec = "x264"; my $videoquality = "24"; # target quality my $audiostream = 1; # default audio channel my $audiocodec = "copy:ac3"; my $audiobitrate = "160"; my $audiochannels = "auto"; my $audiosamplerate = "Auto"; my $audiodrc = "0.0"; my $ftype = "mkv"; my $anamorphic = "--strict-anamorphic"; my $detelecine = "--detelecine"; my $decomb = "--decomb"; my $deinterlace = "--deinterlace"; my $chapters = "-m"; # long word options - type them here # # my $wordoptions = "$anamorphic $decomb $detelecine $deinterlace"; my $wordoptions = "$anamorphic $deinterlace"; # x264 options my $refoption = "ref=1"; my $bframeoption = "bframes=2"; my $submeoption = "subme=5"; my $mixedrefsoption = "mixed-refs=0"; my $weightboption = "weightb=0"; my $eightbyeightoption = "8x8dct=0"; my $trellisoption = "trellis=0"; my $entropyoption = "cabac=0"; my $partitionoption = "partitions=i4x4,i8x8"; my $motionoption = "me=dia"; my $x264options = "$refoption:$bframeoption:$submeoption:$mixedrefsoption:$weightboption:$eightbyeightoption:$trellisoption:$entropyoption:$partitionoption:$motionoption"; my $mt = ''; my $db = ''; sub Reconnect() { $mt = new MythTV(); $db = $mt->{'dbh'}; } # ============================================================================ sub Die($) { print STDERR "@_\n"; exit -1; } # ============================================================================ # Parse command-line arguments, check there is something to do: # if ( ! @ARGV ) { Die "$usage" } Reconnect; while ( @ARGV && $ARGV[0] =~ m/^-/ ) { my $arg = shift @ARGV; if ( $arg eq '-d' || $arg eq '--debug' ) { $DEBUG = 1 } elsif ( $arg eq '-n' || $arg eq '--noaction' ) { $noexec = 1 } elsif ( $arg eq '-j' || $arg eq '--jobid' ) { $jobid = shift @ARGV } elsif ( $arg eq '-f' || $arg eq '--file' ) { $file = shift @ARGV } else { unshift @ARGV, $arg; last; } } if ( ! $file && $jobid == -1 ) { Die "No file or job specified. $usage"; } # ============================================================================ # If we were supplied a jobid, lookup chanid # and starttime so that we can find the filename # if ( $jobid != -1 ) { $query = $db->prepare("SELECT chanid, starttime " . "FROM jobqueue WHERE id=$jobid;"); $query->execute || Die "Unable to query jobqueue table"; $ref = $query->fetchrow_hashref; $chanid = $ref->{'chanid'}; $starttime = $ref->{'starttime'}; $query->finish; if ( ! $chanid || ! $starttime ) { Die "Cannot find details for job $jobid" } $query = $db->prepare("SELECT basename FROM recorded " . "WHERE chanid=$chanid AND starttime='$starttime';"); $query->execute || Die "Unable to query recorded table"; ($file) = $query->fetchrow_array; $query->finish; if ( ! $file ) { Die "Cannot find recording for chan $chanid, starttime $starttime" } if ( $DEBUG ) { print "Job $jobid refers to recording chanid=$chanid,", " starttime=$starttime\n" } } else { if ( $file =~ m/(\d+)_(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/ ) { $chanid = $1, $starttime = "$2-$3-$4 $5:$6:$7" } else { print "File $file has a strange name. Searching in recorded table\n"; $query = $db->prepare("SELECT chanid, starttime " . "FROM recorded WHERE basename='$file';"); $query->execute || Die "Unable to query recorded table"; ($chanid,$starttime) = $query->fetchrow_array; $query->finish; if ( ! $chanid || ! $starttime ) { Die "Cannot find details for filename $file" } } } # A commonly used SQL row selector: my $whereChanAndStarttime = "WHERE chanid=$chanid AND starttime='$starttime'"; # ============================================================================ # Find the directory that contains the recordings, check the file exists # my $dir = undef; my $dirs = $mt->{'video_dirs'}; foreach my $d ( @$dirs ) { if ( ! -e $d ) { Die "Cannot find directory $dir that contains recordings" } if ( -e "$d/$file" ) { $dir = $d; last } else { print "$d/$file does not exist\n" } } if ( ! $dir ) { Die "Cannot find recording" } # ============================================================================ # Do you want to implement the deinterlace feature? #my $dowedeinterlace = ""; # ============================================================================ # Use ffmpeg to find if we need to deinterlace #my $deinterlace = ""; #if ( $dowedeinterlace == '1') # { # $command = "ffmpeg -i $dir/$file "; # open(FF_info, "$command 2>&1 |"); # while ( defined(my $line =) ) { # chomp($line); # if ( $line =~ /^\s*Stream.*#(\S\.\S).*:\sVideo.*\s(\S*)\stbr/ ) # { # $framerate = $2; # next; # } # } # if ( $framerate <= 30.0 ) { $deinterlace = "--deinterlace" } elsif ( $framerate > 30 && $framerate <= 60 ) { $deinterlace = "" } #} # ============================================================================ # First, generate a new filename, # $query = $db->prepare("SELECT title FROM recorded $whereChanAndStarttime;"); $query->execute || Die "Unable to query recorded table"; $showtitle = $query->fetchrow_array; $query->finish; $query = $db->prepare("SELECT subtitle FROM recorded $whereChanAndStarttime;"); $query->execute || Die "Unable to query recorded table"; $episodetitle = $query->fetchrow_array; $query->finish; if ( $episodetitle ne "" ) { $seasonnumber = ""; $episodenumber = ""; $xmlstring = `/usr/share/mythtv/metadata/Television/ttvdb.py -N "$showtitle" "$episodetitle"`; if ( $xmlstring ne "" ) { $episodedetails =$xmlparser->XMLin($xmlstring); $seasonnumber = $episodedetails->{item}->{season}; $episodenumber = $episodedetails->{item}->{episode}; } } my ($year,$month,$day,$hour,$mins,$secs) = split m/[- :]/, $starttime; my $oldShortTime = sprintf "%04d%02d%02d", $year, $month, $day; my $iter = 0; do { if ( $episodetitle eq "" || $seasonnumber eq "" || $episodenumber eq "" ) { $newfilename = sprintf "%s_%s.%s.%s", $showtitle, $month, $day, $year; } else { $newfilename = sprintf "%s_S%0sE%0s_%s", $showtitle, $seasonnumber, $episodenumber, $episodetitle; } $newfilename =~ s/\;/ AND /g; $newfilename =~ s/\&/ AND /g; $newfilename =~ s/\s+/ /g; $newfilename =~ s/\s/_/g; $newfilename =~ s/:/_/g; $newfilename =~ s/__/_/g; $newfilename =~ s/\(//g; $newfilename =~ s/\)//g; $newfilename =~ s/'//g; $newfilename =~ s/\!//g; $newfilename =~ s/\///g; if ( $iter != "0" ) { $newfilename = sprintf "%s_%d%s", $newfilename, $iter, ".mkv" } else { $newfilename = sprintf "%s%s", $newfilename, ".mkv" } $iter ++; $secs = $secs + $iter; $newstarttime = sprintf "%04d-%02d-%02d %02d:%02d:%02d", $year, $month, $day, $hour, $mins, $secs; } while ( -e "$dir/$newfilename" ); $DEBUG && print "$dir/$newfilename seems unique\n"; # ============================================================================ # Third, do the transcode # # $audiochannels = 6; # $audiostream = $audiostreamsurround; # if ( $audiostreamsurround eq "" ) # { # $audiochannels = 2; # $audiostream = $audiostreamstereo; # } $command = "/usr/bin/HandBrakeCLI -i $file"; $command = "$command -o $newfilename"; $command = "$command -e $videocodec"; $command = "$command -q $videoquality"; $command = "$command -a $audiostream"; $command = "$command -E $audiocodec"; $command = "$command -B $audiobitrate"; $command = "$command -6 $audiochannels"; $command = "$command -R $audiosamplerate"; $command = "$command -D $audiodrc"; $command = "$command -f $ftype"; $command = "$command $wordoptions"; $command = "$command $chapters"; $command = "$command $deinterlace"; $command = "$command -x $x264options"; $DEBUG && print "Executing: $command\n"; chdir $dir; system $command; if ( ! -e "$dir/$newfilename" ) { Die "Transcode failed\n" } # ============================================================================ # Last, copy the existing recorded details with the new file name. # Reconnect; $query = $db->prepare("SELECT * FROM recorded $whereChanAndStarttime;"); $query->execute || Die "Unable to query recorded table"; $ref = $query->fetchrow_hashref; $query->finish; $ref->{'starttime'} = $newstarttime; $ref->{'basename'} = $newfilename; if ( $DEBUG && ! $noexec ) { print 'Old file size = ' . (-s "$dir/$file") . "\n"; print 'New file size = ' . (-s "$dir/$newfilename") . "\n"; } $ref->{'filesize'} = -s "$dir/$newfilename"; my $extra = 'Copy'; # # The new recording file has no cutlist, so we don't insert that field # my @recKeys = grep(!/^cutlist$/, keys %$ref); # # Build up the SQL insert command: # $command = 'INSERT INTO recorded (' . join(',', @recKeys) . ') VALUES ("'; foreach my $key ( @recKeys ) { if (defined $ref->{$key}) { $command .= quotemeta($ref->{$key}) . '","' } else { chop $command; $command .= 'NULL,"' } } chop $command; chop $command; # remove trailing comma quote $command .= ');'; if ( $DEBUG || $noexec ) { print "# $command\n" } if ( ! $noexec ) { $db->do($command) || Die "Couldn't create new recording's record, but transcoded file exists $newfilename\n" } # Delete the old recording, keeping the new transcoded recording if ( -e "$dir/$newfilename" ) { $command = 'DELETE from recorded ' . join(',', $whereChanAndStarttime) . '; '; # Build up the SQL delete command: $db->do($command); # remove the mysql entry for the recording my $filepng = $file . join(',','.png'); # Create the file png filename unlink($file); # remove the original file unlink($filepng); # remove the file's png } # ============================================================================ $db->disconnect; 1;
Monday, March 12, 2012
Efficient Transcode script for MythTV using Handbrake
Efficient Transcode - transcodes to .mkv format, giving an improved human readable filename.
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment