Kaynağa Gözat

Prefer the track with the most channels for the mixdown master. Resolve ties using the codec order list. Accept an optional note in the audio description parser.

Zachary Kotlarek 14 yıl önce
ebeveyn
işleme
3aad57e1d5
1 değiştirilmiş dosya ile 97 ekleme ve 79 silme
  1. 97 79
      encode.pl

+ 97 - 79
encode.pl

@@ -15,6 +15,7 @@ my $HD_WIDTH        = 1350;
 my $MIN_VIDEO_WIDTH = 100;
 my $MAX_CROP_DIFF   = .1;
 my $MAX_DURA_DIFF   = 5;
+my @CODEC_ORDER     = ('DTS-HD', 'DTS', 'PCM', 'AC3', 'AAC', 'OTHER');
 my $HB_EXEC         = $ENV{'HOME'} . '/bin/video/HandBrakeCLI';
 my $DEBUG           = 0;
 
@@ -217,88 +218,79 @@ sub audioOptions($) {
 	my ($scan) = @_;
 
 	# Type the audio tracks
-	my @channels = ();
-	my @dts_hd   = ();
-	my @dts      = ();
-	my @ac3      = ();
-	my @pcm      = ();
-	my @aac      = ();
-	my @oat      = ();
+	my %tracks = ();
 	foreach my $track (@{ $scan->{'audio'} }) {
-		my ($language, $codec, $chans, $iso) = $track->{'description'} =~ /^([^\(]+)\s+\(([^\)]+)\)\s+\((\d+\.\d+\s+ch|Dolby\s+Surround)\)(?:\s+\(([^\)]+)\))?/;
-		if (!defined($chans)) {
+		my ($language, $codec, $note, $channels, $iso) = $track->{'description'} =~ /^([^\(]+)\s+\(([^\)]+)\)\s+(?:\(([^\)]*Commentary[^\)]*)\)\s+)?\((\d+\.\d+\s+ch|Dolby\s+Surround)\)(?:\s+\(iso(\d+\-\d+)\:\s+\w\w\w\))?/;
+		if (!defined($channels)) {
 			print STDERR 'Could not parse audio description: ' . $track->{'description'} . "\n";
 
 			# Temporarily exit on parsing errors -- at least until we're sure about this new parser
+			#next;
 			exit(1);
-			next;
-		}
-		if ($DEBUG) {
-			print STDERR 'Found audio track: codec => ' . $codec . ', channels => ' . $chans . ', language => ' . $language . ', ISO => ' . $iso . "\n";
 		}
 
 		# Decode the channels string to a number
-		if ($chans =~ /(\d+\.\d+)\s+ch/i) {
-			$chans = $1;
-		} elsif ($chans =~ /Dolby\s+Surround/i) {
-			$chans = 3.1;
+		if ($channels =~ /(\d+\.\d+)\s+ch/i) {
+			$channels = $1;
+		} elsif ($channels =~ /Dolby\s+Surround/i) {
+			$channels = 3.1;
 		}
-		$channels[ $track->{'index'} ] = $chans;
 
-		# Skip foreign langugae tracks
-		if ($language =~ /\b(Chinese|Espanol|Francais|Japanese|Korean|Portugues|Thai)\b/i) {
-			if ($DEBUG) {
-				print STDERR 'Skipping AC3 in track ' . $track->{'index'} . ' due to language: ' . $language . "\n";
+		# Standardize the codec
+		foreach my $code (@CODEC_ORDER) {
+			my $metacode = quotemeta($code);
+			if ($codec =~ /${metacode}/i) {
+				$codec = $code;
+				last;
+			} elsif ($code eq 'OTHER') {
+				if (!($codec =~ /MP3/i || $codec =~ /MPEG/i)) {
+					print STDERR 'Found unknown audio (' . $track->{'description'} . ') in track ' . $track->{'index'} . "\n";
+				}
+				$codec = $code;
 			}
-			next;
 		}
 
-		# Filter by codec
-		if ($codec =~ /DTS/i) {
-			if ($codec =~ /DTS\-MA/i) {
-				push(@dts_hd, $track->{'index'});
-			} else {
-				push(@dts, $track->{'index'});
-			}
-		} elsif ($codec =~ /AC3/i) {
-			push(@ac3, $track->{'index'});
-		} elsif ($codec =~ /PCM_[SF]\d+/i) {
-			push(@pcm, $track->{'index'});
-		} elsif ($codec =~ /AAC/i) {
-			push(@aac, $track->{'index'});
-		} else {
-			push(@oat, $track->{'index'});
-			if ($DEBUG) {
-				if (!($codec =~ /MP3/i || $codec =~ /MPEG/i)) {
-					print STDERR 'Found unknown audio (' . $track->{'description'} . ') in track ' . $track->{'index'} . "\n";
+		# Push all parsed data into the array
+		my %data = ('language' => $language, 'codec' => $codec, 'channels' => $channels, 'iso' => $iso, 'note' => $note);
+		$tracks{ $track->{'index'} } = \%data;
+
+		# Print what we found
+		if ($DEBUG) {
+			print STDERR 'Found audio track: ';
+			my $first = 1;
+			foreach my $key (keys(%data)) {
+				if ($data{$key}) {
+					if ($first) {
+						$first = 0;
+					} else {
+						print STDERR ', ';
+					}
+					print STDERR $key . ' => ' . $data{$key};
 				}
 			}
+			print STDERR "\n";
 		}
 	}
 
-	# We should sort the different codecs by number of channels
-	# But so far I've had good luck just taking the first track with the best codec
-
-	# Pick a stereo/mixdown plan based on the available track types
-	my $mixdown = undef();
-	if (scalar(@dts_hd) > 0) {
-		$mixdown = $dts_hd[0];
-	} elsif (scalar(@dts) > 0) {
-		$mixdown = $dts[0];
-	} elsif (scalar(@ac3) > 0 || scalar(@pcm) > 0) {
-		if (scalar(@pcm) < 1) {
-			$mixdown = $ac3[0];
-		} elsif (scalar(@ac3) < 1) {
-			$mixdown = $pcm[0];
-		} elsif ($channels[ $pcm[0] ] >= $channels[ $ac3[0] ]) {
-			$mixdown = $pcm[0];
-		} elsif ($channels[ $pcm[0] ] >= $channels[ $ac3[0] ]) {
-			$mixdown = $pcm[0];
+	# Find the track with the most channels for each codec, and the highest number of channels among all types of tracks
+	# Then choose the most desired codec among the set of codecs that contain the highest number of channels
+	# This chooses the track with the most channels for the mixdown, and resolves ties using CODEC_ORDER
+	my $mixdown      = undef();
+	my %bestByCodec  = ();
+	my $bestCodec    = undef();
+	my $mostChannels = 0;
+	foreach my $codec (@CODEC_ORDER) {
+		$bestByCodec{$codec} = findBestAudioTrack(\%tracks, $codec);
+		if (defined($bestByCodec{$codec}) && (!defined($bestCodec) || $mostChannels < $tracks{ $bestByCodec{$codec} }->{'channels'})) {
+			$bestCodec    = $codec;
+			$mostChannels = $tracks{ $bestByCodec{$codec} }->{'channels'};
+		}
+	}
+	foreach my $codec (@CODEC_ORDER) {
+		if (defined($bestByCodec{$codec}) && $tracks{ $bestByCodec{$codec} }->{'channels'} == $mostChannels) {
+			$mixdown = $bestByCodec{$codec};
+			last;
 		}
-	} elsif (scalar(@aac)) {
-		$mixdown = $aac[0];
-	} elsif (scalar(@oat)) {
-		$mixdown = $oat[0];
 	}
 
 	# Sanity check
@@ -312,7 +304,7 @@ sub audioOptions($) {
 	if (defined($mixdown) && $mixdown > 0) {
 		if ($DEBUG) {
 			print STDERR 'Using track ' . $mixdown . " as default AAC audio\n";
-			if ($channels[$mixdown] > 2) {
+			if ($tracks{$mixdown}->{'channels'} > 2) {
 				print STDERR "\tMixing down with Dolby Pro Logic II encoding\n";
 			}
 		}
@@ -322,32 +314,28 @@ sub audioOptions($) {
 
 	# Passthru DTS-MA, DTS, AC3, and AAC
 	# Keep other audio tracks, but recode to AAC (using Handbrake's audio-copy-mask/audio-fallback feature)
-	foreach my $codec_set (\@dts_hd, \@dts, \@ac3, \@aac, \@pcm, \@oat) {
-		foreach my $audio_track (@{$codec_set}) {
-			if ($mixdown == $audio_track && $channels[$mixdown] <= 2) {
-				if ($DEBUG) {
-					print STDERR 'Skipping AAC recode of track ' . $audio_track . ' since it is already used as the default track and contains only ' . $channels[$audio_track] . " channels\n";
-				}
-				next;
-			}
+	foreach my $index (keys(%tracks)) {
+		if ($mixdown == $index && $tracks{$index}->{'codec'} eq 'OTHER' && $tracks{$index}->{'channels'} <= 2) {
 			if ($DEBUG) {
-				print STDERR 'Keeping audio track: ' . $audio_track . "\n";
+				print STDERR 'Skipping recode of track ' . $index . ' since it is already used as the default track and contains only ' . $tracks{$index}->{'channels'} . " channels\n";
 			}
-			my %track = ('index' => $audio_track, 'encoder' => 'copy');
+			next;
+		} else {
+			my %track = ('index' => $index, 'encoder' => 'copy');
 			push(@audio_tracks, \%track);
 		}
 	}
 
 	# Consolidate from the hashes
-	my @tracks   = ();
-	my @encoders = ();
+	my @output_tracks   = ();
+	my @output_encoders = ();
 	foreach my $track (@audio_tracks) {
-		push(@tracks,   $track->{'index'});
-		push(@encoders, $track->{'encoder'});
+		push(@output_tracks,   $track->{'index'});
+		push(@output_encoders, $track->{'encoder'});
 	}
 
 	# Send back the argument strings
-	return ('--audio', join(',', @tracks), '--aencoder', join(',', @encoders));
+	return ('--audio', join(',', @output_tracks), '--aencoder', join(',', @output_encoders));
 }
 
 sub scan($) {
@@ -475,3 +463,33 @@ sub scan($) {
 	# Return
 	return %titles;
 }
+
+sub findBestAudioTrack($$) {
+	my ($tracks, $codec) = @_;
+	my $best         = undef();
+	my $bestChannels = 0;
+
+	for my $index (keys(%{$tracks})) {
+		my $track = $tracks->{$index};
+
+		# Skip tracks not in the specified codec
+		if ($track->{'codec'} ne $codec) {
+			next;
+		}
+
+		# Skip foreign langugae tracks
+		if ($track->{'language'} =~ /\b(Chinese|Espanol|Francais|Japanese|Korean|Portugues|Thai)\b/i) {
+			if ($DEBUG) {
+				print STDERR 'Skipping audio track ' . $index . ' due to language: ' . $track->{'language'} . "\n";
+			}
+			next;
+		}
+
+		if (!defined($best) || $track->{'channels'} > $bestChannels) {
+			$best         = $index;
+			$bestChannels = $track->{'channels'};
+		}
+	}
+
+	return $best;
+}