The following patch adds VBR "bitrates" to the bitrate drop-down for capable encoders, allowing you to use VBR audio from the MacGUI.
VBR settings are saved in presets, and should be compatible with LinGUI presets' VBR audio settings (untested), but not with presets created using previous versions of my patch (anything before 02/08/2012).
For VBR-capable encoders, the default VBR quality is used instead of the default bitrate where applicable.
http://paste.handbrake.fr/pastebin.php?show=3486
Code: Select all
Index: macosx/HBAudio.h
===================================================================
--- macosx/HBAudio.h (revision 4979)
+++ macosx/HBAudio.h (working copy)
@@ -17,6 +17,8 @@
extern NSString *keyAudioMixdown;
extern NSString *keyAudioSamplerate;
extern NSString *keyAudioBitrate;
+extern NSString *keyAudioQuality;
+extern NSString *keyAudioCompatible;
@interface HBAudio : NSObject
Index: macosx/HBAudio.m
===================================================================
--- macosx/HBAudio.m (revision 4979)
+++ macosx/HBAudio.m (working copy)
@@ -21,6 +21,8 @@
NSString *keyAudioMixdown = @"mixdown";
NSString *keyAudioSamplerate = @"samplerate";
NSString *keyAudioBitrate = @"bitrate";
+NSString *keyAudioQuality = @"quality";
+NSString *keyAudioCompatible = @"compatible";
static NSMutableArray *masterCodecArray = nil;
static NSMutableArray *masterMixdownArray = nil;
@@ -142,9 +144,51 @@
dict = [NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithUTF8String: hb_audio_bitrates[i].string], keyAudioBitrateName,
[NSNumber numberWithInt: hb_audio_bitrates[i].rate], keyAudioBitrate,
+ [NSNumber numberWithFloat: HB_INVALID_AUDIO_QUALITY], keyAudioQuality,
+ [NSNumber numberWithInt: HB_ACODEC_MASK], keyAudioCompatible,
nil];
[masterBitRateArray addObject: dict];
}
+ // add VBR "bitrates" for all capable encoders
+ // each "bitrate" is encoder-specific (keyAudioCompatible)
+ for (i = 0; i < hb_audio_encoders_count; i++)
+ {
+ if (hb_get_default_audio_quality(hb_audio_encoders[i].encoder) != HB_INVALID_AUDIO_QUALITY)
+ {
+ int direction;
+ float j, low, high, granularity;
+ hb_get_audio_quality_limits(hb_audio_encoders[i].encoder,
+ &low, &high, &granularity, &direction);
+ if (direction)
+ {
+ for (j = high; j >= low; j -= granularity)
+ {
+ dict = [NSDictionary dictionaryWithObjectsAndKeys:
+ [HBAudioController bitrateNameFromQuality: j
+ forCodec: hb_audio_encoders[i].encoder], keyAudioBitrateName,
+ [NSNumber numberWithInt: -1], keyAudioBitrate,
+ [NSNumber numberWithFloat: j], keyAudioQuality,
+ [NSNumber numberWithInt: hb_audio_encoders[i].encoder], keyAudioCompatible,
+ nil];
+ [masterBitRateArray addObject: dict];
+ }
+ }
+ else
+ {
+ for (j = low; j <= high; j += granularity)
+ {
+ dict = [NSDictionary dictionaryWithObjectsAndKeys:
+ [HBAudioController bitrateNameFromQuality: j
+ forCodec: hb_audio_encoders[i].encoder], keyAudioBitrateName,
+ [NSNumber numberWithInt: -1], keyAudioBitrate,
+ [NSNumber numberWithFloat: j], keyAudioQuality,
+ [NSNumber numberWithInt: hb_audio_encoders[i].encoder], keyAudioCompatible,
+ nil];
+ [masterBitRateArray addObject: dict];
+ }
+ }
+ }
+ }
[pool release];
}
@@ -271,6 +315,7 @@
int minBitRate;
int maxBitRate;
int currentBitRate;
+ int currentCompatibility;
BOOL shouldAdd;
unsigned int count = [masterBitRateArray count];
@@ -286,6 +331,7 @@
int ourMixdown = [[[self mixdown] objectForKey: keyAudioMixdown] intValue];
hb_get_audio_bitrate_limits(ourCodec, theSampleRate, ourMixdown, &minBitRate, &maxBitRate);
int theDefaultBitRate = hb_get_default_audio_bitrate(ourCodec, theSampleRate, ourMixdown);
+ float theDefaultQuality = hb_get_default_audio_quality(ourCodec);
BOOL codecIsPassthru = ([[codec objectForKey: keyAudioCodec] intValue] & HB_ACODEC_PASS_FLAG) ? YES : NO;
BOOL codecIsLossless = (theDefaultBitRate == -1) ? YES : NO;
@@ -300,6 +346,8 @@
sourceBitRate = [NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithFormat: @"%d", trackInputBitRate], keyAudioBitrateName,
[NSNumber numberWithInt: trackInputBitRate], keyAudioBitrate,
+ [NSNumber numberWithFloat: HB_INVALID_AUDIO_QUALITY], keyAudioQuality,
+ [NSNumber numberWithInt: ourCodec], keyAudioCompatible,
nil];
}
[permittedBitRates addObject: sourceBitRate];
@@ -309,6 +357,8 @@
NSDictionary *bitRateNotApplicable = [NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithString: @"N/A"], keyAudioBitrateName,
[NSNumber numberWithInt: -1], keyAudioBitrate,
+ [NSNumber numberWithFloat: HB_INVALID_AUDIO_QUALITY], keyAudioQuality,
+ [NSNumber numberWithInt: ourCodec], keyAudioCompatible,
nil];
[permittedBitRates addObject: bitRateNotApplicable];
}
@@ -318,9 +368,11 @@
{
dict = [masterBitRateArray objectAtIndex: i];
currentBitRate = [[dict objectForKey: keyAudioBitrate] intValue];
+ currentCompatibility = !!(ourCodec & [[dict objectForKey: keyAudioCompatible] intValue]);
// First ensure the bitrate falls within range of the codec
- shouldAdd = (currentBitRate >= minBitRate && currentBitRate <= maxBitRate);
+ shouldAdd = ((currentBitRate >= minBitRate && currentBitRate <= maxBitRate) ||
+ (currentBitRate == -1 && currentCompatibility)); // VBR "bitrate" compatible with ourCodec
if (shouldAdd)
{
@@ -338,9 +390,18 @@
[self setBitRates: permittedBitRates];
// Select the proper one
- if (shouldSetDefault)
+ if (shouldSetDefault || ![permittedBitRates containsObject: [self bitRate]])
{
- [self setBitRateFromName: [NSString stringWithFormat:@"%d", theDefaultBitRate]];
+ // set default quality for VBR-capable codecs
+ if (theDefaultQuality != HB_INVALID_AUDIO_QUALITY)
+ {
+ [self setBitRateFromName: [HBAudioController bitrateNameFromQuality: theDefaultQuality
+ forCodec: ourCodec]];
+ }
+ else
+ {
+ [self setBitRateFromName: [NSString stringWithFormat: @"%d", theDefaultBitRate]];
+ }
}
if (![self bitRate] || ![permittedBitRates containsObject: [self bitRate]])
Index: macosx/HBAudioController.h
===================================================================
--- macosx/HBAudioController.h (revision 4979)
+++ macosx/HBAudioController.h (working copy)
@@ -44,6 +44,11 @@
- (void) settingTrackToNone: (HBAudio *) newNoneTrack;
- (void) switchingTrackFromNone: (HBAudio *) noLongerNoneTrack;
+/* VBR audio convenience methods */
++ (NSString *) bitrateNameFromQuality: (float) aQuality forCodec: (int) aCodec;
++ (float) closestQualityFromValue: (float) aQuality forCodec: (int) aCodec;
++ (int) codecFromName: (NSString *) aCodecName;
+
@end
@interface HBAudioController (KVC)
Index: macosx/HBQueueController.mm
===================================================================
--- macosx/HBQueueController.mm (revision 4979)
+++ macosx/HBQueueController.mm (working copy)
@@ -1074,22 +1074,26 @@
NSString *base;
NSString *detailString;
NSNumber *drc;
- NSNumber *gain;
- BOOL autoPassthruPresent = NO;
+ NSNumber *gain;
+ NSNumber *quality;
+ BOOL autoPassthruPresent = NO;
for (unsigned int i = 1; i <= ourMaximumNumberOfAudioTracks; i++) {
base = [NSString stringWithFormat: @"Audio%d", i];
if (0 < [[item objectForKey: [base stringByAppendingString: @"Track"]] intValue])
{
audioCodecSummary = [NSString stringWithFormat: @"%@", [item objectForKey: [base stringByAppendingString: @"Encoder"]]];
drc = [item objectForKey: [base stringByAppendingString: @"TrackDRCSlider"]];
- gain = [item objectForKey: [base stringByAppendingString: @"TrackGainSlider"]];
- detailString = [NSString stringWithFormat: @"%@ Encoder: %@ Mixdown: %@ SampleRate: %@(khz) Bitrate: %@(kbps), DRC: %@, Gain: %@",
+ gain = [item objectForKey: [base stringByAppendingString: @"TrackGainSlider"]];
+ quality = [item objectForKey: [NSString stringWithFormat: @"JobAudio%dQuality", i]];
+ detailString = [NSString stringWithFormat: @"%@ Encoder: %@ Mixdown: %@ Samplerate: %@ (kHz) %@: %@ %@, DRC: %@, Gain: %@",
[item objectForKey: [base stringByAppendingString: @"TrackDescription"]],
[item objectForKey: [base stringByAppendingString: @"Encoder"]],
[item objectForKey: [base stringByAppendingString: @"Mixdown"]],
[item objectForKey: [base stringByAppendingString: @"Samplerate"]],
- [item objectForKey: [base stringByAppendingString: @"Bitrate"]],
- (0.0 < [drc floatValue]) ? (NSObject *)drc : (NSObject *)@"Off",
+ (HB_INVALID_AUDIO_QUALITY != [quality floatValue]) ? (NSObject *)@"Quality" : (NSObject *)@"Bitrate",
+ (HB_INVALID_AUDIO_QUALITY != [quality floatValue]) ? (NSObject *)quality : [item objectForKey: [base stringByAppendingString: @"Bitrate"]],
+ (HB_INVALID_AUDIO_QUALITY != [quality floatValue]) ? (NSObject *)@"(VBR)" : (NSObject *)@"(Kbps)",
+ (0.0 < [drc floatValue]) ? (NSObject *)drc : (NSObject *)@"Off",
(0.0 != [gain floatValue]) ? (NSObject *)gain : (NSObject *)@"Off"
]
;
Index: macosx/HBAudioController.m
===================================================================
--- macosx/HBAudioController.m (revision 4979)
+++ macosx/HBAudioController.m (working copy)
@@ -128,6 +128,7 @@
[aDict setObject: [[anAudio mixdown] objectForKey: keyAudioMixdown] forKey: [prefix stringByAppendingString: @"Mixdown"]];
[aDict setObject: sampleRateToUse forKey: [prefix stringByAppendingString: @"Samplerate"]];
[aDict setObject: [[anAudio bitRate] objectForKey: keyAudioBitrate] forKey: [prefix stringByAppendingString: @"Bitrate"]];
+ [aDict setObject: [[anAudio bitRate] objectForKey: keyAudioQuality] forKey: [prefix stringByAppendingString: @"Quality"]];
}
}
}
@@ -166,6 +167,7 @@
audio->out.compression_level = hb_get_default_audio_compression(audio->out.codec);
audio->out.mixdown = [[[anAudio mixdown] objectForKey: keyAudioMixdown] intValue];
audio->out.bitrate = [[[anAudio bitRate] objectForKey: keyAudioBitrate] intValue];
+ audio->out.quality = [[[anAudio bitRate] objectForKey: keyAudioQuality] floatValue];
audio->out.samplerate = [sampleRateToUse intValue];
audio->out.dynamic_range_compression = [[anAudio drc] floatValue];
audio->out.gain = [[anAudio gain] floatValue];
@@ -193,7 +195,13 @@
[dict setObject: [[anAudio codec] objectForKey: keyAudioCodecName] forKey: @"AudioEncoder"];
[dict setObject: [[anAudio mixdown] objectForKey: keyAudioMixdownName] forKey: @"AudioMixdown"];
[dict setObject: [[anAudio sampleRate] objectForKey: keyAudioSampleRateName] forKey: @"AudioSamplerate"];
- [dict setObject: [[anAudio bitRate] objectForKey: keyAudioBitrateName] forKey: @"AudioBitrate"];
+ [dict setObject:
+ [NSString stringWithFormat: @"%d", [[[anAudio bitRate] objectForKey: keyAudioBitrate] intValue]]
+ forKey: @"AudioBitrate"];
+ [dict setObject: [[anAudio bitRate] objectForKey: keyAudioQuality] forKey: @"AudioTrackQuality"];
+ [dict setObject:
+ [NSNumber numberWithInt: ([[[anAudio bitRate] objectForKey: keyAudioQuality] floatValue] != HB_INVALID_AUDIO_QUALITY)]
+ forKey: @"AudioTrackQualityEnable"];
[dict setObject: [anAudio drc] forKey: @"AudioTrackDRCSlider"];
[dict setObject: [anAudio gain] forKey: @"AudioTrackGainSlider"];
[anArray addObject: dict];
@@ -344,6 +352,16 @@
{
[dict setObject:[NSNumber numberWithFloat:0.0] forKey:@"AudioTrackGainSlider"];
}
+
+ // set default values for VBR audio if absent
+ if (![dict objectForKey: @"AudioTrackQualityEnable"])
+ {
+ [dict setObject:[NSNumber numberWithInt:0] forKey:@"AudioTrackQualityEnable"];
+ }
+ if (![dict objectForKey: @"AudioTrackQuality"])
+ {
+ [dict setObject:[NSNumber numberWithFloat:HB_INVALID_AUDIO_QUALITY] forKey:@"AudioTrackQuality"];
+ }
// map legacy mixdowns
key = [dict objectForKey: @"AudioMixdown"];
@@ -366,7 +384,19 @@
[newAudio setSampleRateFromName: [dict objectForKey: @"AudioSamplerate"]];
if (!fallenBack)
{
- [newAudio setBitRateFromName: [dict objectForKey: @"AudioBitrate"]];
+ // VBR audio
+ if ([[dict objectForKey: @"AudioTrackQualityEnable"] intValue])
+ {
+ [newAudio setBitRateFromName:
+ [HBAudioController bitrateNameFromQuality:
+ [[dict objectForKey: @"AudioTrackQuality"] floatValue]
+ forCodec:
+ [HBAudioController codecFromName: [dict objectForKey: @"AudioEncoder"]]]];
+ }
+ else
+ {
+ [newAudio setBitRateFromName: [dict objectForKey: @"AudioBitrate"]];
+ }
}
[newAudio setDrc: [dict objectForKey: @"AudioTrackDRCSlider"]];
[newAudio setGain: [dict objectForKey: @"AudioTrackGainSlider"]];
@@ -645,6 +675,67 @@
}
#pragma mark -
+#pragma mark VBR audio convenience methods
+
++ (NSString *) bitrateNameFromQuality: (float) aQuality forCodec: (int) aCodec
+
+{
+ if (aQuality == HB_INVALID_AUDIO_QUALITY || !aCodec)
+ return nil;
+ int direction, precision;
+ float low, high, granularity, quality;
+ hb_get_audio_quality_limits(aCodec, &low, &high, &granularity, &direction);
+ precision = granularity >= 1.0 ? 0 : granularity >= 0.1 ? 1 : 2;
+ quality = [HBAudioController closestQualityFromValue: aQuality forCodec: aCodec];
+ return [NSString stringWithFormat: @"Q%.*f", precision, quality];
+}
+
++ (float) closestQualityFromValue: (float) aQuality forCodec: (int) aCodec
+
+{
+ int direction;
+ float i, low, high, granularity;
+ hb_get_audio_quality_limits(aCodec, &low, &high, &granularity, &direction);
+ // return the highest quality that is less than granularity away from aQuality
+ if (direction)
+ {
+ for (i = low; i <= high; i += granularity)
+ {
+ if ((aQuality - i) < granularity)
+ {
+ return hb_get_best_audio_quality(aCodec, i);
+ }
+ }
+ }
+ else
+ {
+ for (i = high; i >= low; i -= granularity)
+ {
+ if ((i - aQuality) < granularity)
+ {
+ return hb_get_best_audio_quality(aCodec, i);
+ }
+ }
+ }
+ return hb_get_default_audio_quality(aCodec);
+}
+
++ (int) codecFromName: (NSString *) aCodecName
+
+{
+ int i;
+ for (i = 0; i < hb_audio_encoders_count; i++)
+ {
+ if ([[NSString stringWithUTF8String: hb_audio_encoders[i].human_readable_name]
+ isEqualToString: aCodecName])
+ {
+ return hb_audio_encoders[i].encoder;
+ }
+ }
+ return 0;
+}
+
+#pragma mark -
#pragma mark KVC
- (unsigned int) countOfAudioArray
Index: macosx/Controller.m
===================================================================
--- macosx/Controller.m (revision 4979)
+++ macosx/Controller.m (working copy)
@@ -3995,6 +3995,7 @@
audio->out.compression_level = hb_get_default_audio_compression(audio->out.codec);
audio->out.mixdown = [[queueToApply objectForKey: [prefix stringByAppendingString: @"Mixdown"]] intValue];
audio->out.bitrate = [[queueToApply objectForKey: [prefix stringByAppendingString: @"Bitrate"]] intValue];
+ audio->out.quality = [[queueToApply objectForKey: [prefix stringByAppendingString: @"Quality"]] floatValue];
audio->out.samplerate = [[queueToApply objectForKey: [prefix stringByAppendingString: @"Samplerate"]] intValue];
hb_audio_add( job, audio );
CLI users should use native VBR functionality (see --help).