[mythtv] mythmkmovie patch for cutlists in mpeg files (PVR-[23]50)

Russ Southern russ.southern at cox.net
Tue Aug 19 00:27:02 EDT 2003


Here is a patch for mythmkmovie to support cutlists with mpeg files, as
produced by the Hauppauge PVR-250.  It requires the "transcode" package to
be installed.

There should be no difference in usage or command-line options.  If you have
a cutlist, the script autodetects an mpeg file and behaves accordingly.
With no cutlist, it uses the original codepath (using mencoder only).

I have been using this code for about two weeks, and am pleased with its
workings.  Comments/flames are welcome.

Russ
-------------- next part --------------
--- mkmovie	2003-08-03 20:36:58.000000000 -0700
+++ mkmovie.russ	2003-08-03 22:32:41.000000000 -0700
@@ -243 +243 @@ use strict;
-my ($versionnum) = "1.0rc2";
+my ($versionnum) = "1.0rc3";
@@ -513 +513 @@ sub getFrameCount {
-	my ($dbh, $input, $stoprun) = @_;
+	my ($dbh, $input, $stoprun, $mpeg) = @_;
@@ -517,6 +517,23 @@ sub getFrameCount {
-	$command = "mythframes " . $input;
-	$finstring = `$command`;
-	if ($? and $stoprun) {
-		setError($dbh, $input, "mythframes FAILURE");\
-		die ("ERROR: mythframes FAILURE!\n") if ($? and $stoprun);
-		return (0);
+	print '(counting frames in mpeg files is currently slow)' if $mpeg;
+
+	if ($mpeg){
+		# Yes, it is wasteful to capture all this (noisy) output...
+		$finstring = `tcscan -x mpeg -i $input 2>&1 >/dev/null`;
+		if ($? and $stoprun) {
+			setError($dbh, $input, "tcscan FAILURE");\
+			die ("ERROR: tcscan FAILURE!\n") if ($? and $stoprun);
+			return (0);
+		}
+		# and just as wasteful to regex the whole string
+		$finstring =~ /detected a total of .* and (\d{1,}) sequence/;
+		$framecount = $1;
+	} else {
+		$command = "mythframes " . $input;
+		$finstring = `$command`;
+		if ($? and $stoprun) {
+			setError($dbh, $input, "mythframes FAILURE");\
+			die ("ERROR: mythframes FAILURE!\n") if ($? and $stoprun);
+			return (0);
+		}
+		$finstring =~ /^Total Frames: (\d+)\s*$/;
+		$framecount = $1;
@@ -524,2 +540,0 @@ sub getFrameCount {
-	$finstring =~ /^Total Frames: (\d+)\s*$/;
-	$framecount = $1;
@@ -600 +614,0 @@ sub getIncList {
-	my ($cutrange, $start, $end, $i);
@@ -605,2 +619,2 @@ sub getIncList {
-	foreach $cutrange (@cutlist) {
-		($start, $end) = split(/\-/, $cutrange);
+	foreach my $cutrange (@cutlist) {
+		my ($start, $end) = split(/\-/, $cutrange);
@@ -608 +622 @@ sub getIncList {
-			$inclist[0] = $end-1;
+			$inclist[0] = $end+1;
@@ -611,2 +625,2 @@ sub getIncList {
-		if ($end >= $inclist[$#inclist]) {
-			$inclist[$#inclist] = $start+1;
+		if ($end >= $inclist[-1]) {
+			$inclist[-1] = $start-1;
@@ -615,2 +629,2 @@ sub getIncList {
-		$start++;
-		$end--;
+		$start--;
+		$end++;
@@ -619 +633 @@ sub getIncList {
-		$i=0;
+		my $i=0;
@@ -621,2 +635 @@ sub getIncList {
-		@temp = splice(@inclist, $i);
-		@inclist = (@inclist, $start, $end, @temp);
+		splice(@inclist, $i, 0, ($start, $end));
@@ -945 +958,2 @@ sub clearError {
-# steps necessary to produce the output .avi file.
+# steps necessary to produce the output .avi file.  If it detects an mpeg
+# input file, it will use a separate codepath to process the files.
@@ -952,0 +967 @@ sub doshow {
+	my $mpeg = 0;
@@ -983,2 +997,0 @@ sub doshow {
-	$framecount = getFrameCount($dbh, $input, $stoprun);
-	return if (getError($dbh, $input));
@@ -986,0 +1000,11 @@ sub doshow {
+
+	# If we have a cutlist, autodetect MPEG format input files
+	$mpeg = (`mplayer -identify $input 2>/dev/null` =~ /MPEG.*? file format detected/)
+		if @cutlist;
+
+	# Confirm we have transcode installed if needed
+	die 'transcode package not installed, or not in your PATH'
+		if $mpeg and system('transcode -version') != 0;
+
+	$framecount = getFrameCount($dbh, $input, $stoprun, $mpeg);
+	return if (getError($dbh, $input));
@@ -989,0 +1014 @@ sub doshow {
+
@@ -1000,5 +1025,43 @@ sub doshow {
-	$files = makesegments($dbh, $input, $vbr, $keyint, $abr, $pause, $stoprun,
-		$transcode, $skiperrors, $autotrans, @inclist);
-	return if (getError($dbh, $input));
-	makevideo($dbh, $input, $files, $output, $remove, $pause, $stoprun, $skiperrors);
-	return if (getError($dbh, $input));
+
+	# If this is an MPEG file from a Hardware Encoder, use a combination of
+	# mencoder and the transcode package (mplayer/mencoder does not handle
+	# VBR, so cannot seek correctly)
+
+	if ($mpeg){
+		# Myth and tcscan seem to disagree on the number of frames.
+		# If the last segment is less than 1 second (30 frames), 
+		# discard it (I know, this is bad, but...)
+		if ($inclist[-1] - $inclist[-2] < 30){
+			pop @inclist for ('last', 'segment');
+		}
+		my $Includes = '';
+		$Includes .= ',' . join('-', shift(@inclist), shift(@inclist))
+			while @inclist;
+		my $KeyIntArg 	= $keyint 	? ":keyint=$keyint" 	: '';
+		my $VBRArg 	= $vbr 		? ":vbitrate=$vbr" 	: '';
+
+		# Why use both mencoder and transcode?
+		# Why video with one and audio with the other?  In short,
+		# because I could not make it work any other way.  mencoder does
+		# not seek correctly in Variable Bit Rate files (like MPEG), so
+		# cutlists won't work with mencoder.  transcode seems unwilling 
+		# to just do passthrough from mpeg to mpeg without encoding 
+		# *something*.  So, until mythtranscode works, or mplayer2
+		# is finished...this works. -- Russ (russ (at) undef.us)
+		my $BaseMencoder = 'mencoder -oac copy -ovc lavc -lavcopts vcodec=mpeg4:vstrict=1:vhq';
+
+		my $BaseTranscode = 'transcode -xdivx -yraw -P1';
+		my $ABRArg 	= $abr 		? "-b$abr" 		: '';
+		my $IncludeArg 	= $Includes 	? "-c$Includes" 	: '';
+		print qq{About to run $BaseMencoder$KeyIntArg$VBRArg -o $output.tmp $input\n} if $verbose;
+		print qq{ followed by $BaseTranscode $ABRArg $IncludeArg -i $output.tmp -o $output\n} if $verbose;
+		system(qq{$BaseMencoder$KeyIntArg$VBRArg -o $output.tmp $input}) and die "mencoder failed";
+		system(qq{$BaseTranscode $ABRArg $IncludeArg -i $output.tmp -o $output}) and die "transcode failed";
+		unlink "$output.tmp" || die "failed to remove temp file" if $remove;
+	} else {
+		$files = makesegments($dbh, $input, $vbr, $keyint, $abr, $pause, $stoprun,
+			$transcode, $skiperrors, $autotrans, @inclist);
+		return if (getError($dbh, $input));
+		makevideo($dbh, $input, $files, $output, $remove, $pause, $stoprun, $skiperrors);
+		return if (getError($dbh, $input));
+	}
@@ -1020,5 +1083,6 @@ sub doshow {
-		$dbh->do('delete from videometadata where filename="' . $output . '"');
-		$sth = $dbh->prepare('insert into videometadata(title, plot, rating, filename, showlevel) values(?, ?, ?, ?, ?)');
-		$sth->execute($title, $desc, "NR", $output, "1");
-		$sth->finish();
-	}
+	};
+
+	$dbh->do('delete from videometadata where filename="' . $output . '"');
+	$sth = $dbh->prepare('insert into videometadata(title, plot, rating, filename, showlevel) values(?, ?, ?, ?, ?)');
+	$sth->execute($title, $desc, "NR", $output, "1");
+	$sth->finish();
@@ -1049,3 +1113,3 @@ sub getinput {
-	my ($y, $x, $prompt, $input, $mask) = @_;
-	my ($pos, $line, $col, $startcol, $key, $msg);
-	my ($original, $temp) = $input;
+	my ($y, $x, $prompt, $input, $mask, $cancelvalue) = @_;
+	my ($pos, $line, $col, $startcol, $key, $msg, $temp);
+	my $original = $cancelvalue;
@@ -1080,0 +1145,2 @@ sub getinput {
+			move($y,$x);
+			clrtoeol();
@@ -1253 +1319 @@ sub dointeractive {
-	my (@shows, $lineno, $index, @vals, @info, $temp);
+	my (@shows, $lineno, $index, @vals, @info, $temp, $videodir);
@@ -1260,0 +1327 @@ sub dointeractive {
+	($videodir) = $dbh->selectrow_array('select data from settings where value="VideoStartupDir"');
@@ -1332 +1399,8 @@ sub dointeractive {
-			$vals[6] = getinput ($LINES-1, 0, "Enter Output Filename:", $vals[6], '[A-Za-z0-9\-_/\.]+');
+			# Provide a default filename (suggesting a full path)
+			my $tempoutput = '';
+			if (not $vals[6]){
+				my $temptitle = "$vals[3]-$vals[4]";
+				$temptitle =~ s/[^A-Za-z0-9\-_\.]/_/g;
+				$tempoutput = "$videodir/$temptitle";
+			}
+			$vals[6] = getinput ($LINES-1, 0, "Enter Output Filename:", ($vals[6] || $tempoutput), '[A-Za-z0-9\-_/\.]+', $vals[6]);


More information about the mythtv-dev mailing list