HandBrake/macosx/HBVideoController.m

305 lines
11 KiB
Objective-C

/* HBVideoController.m $
This file is part of the HandBrake source code.
Homepage: <http://handbrake.fr/>.
It may be used under the terms of the GNU General Public License. */
#import "HBVideoController.h"
#import "HBAdvancedController.h"
@import HandBrakeKit;
#include "hb.h"
static void *HBVideoControllerContext = &HBVideoControllerContext;
@interface HBVideoController () {
// Framerate Radio Button Framerate Controls
IBOutlet NSButtonCell *fFramerateVfrPfrCell;
// Video Encoder
IBOutlet NSSlider *fVidQualitySlider;
// Encoder options views
IBOutlet NSView *fPresetView;
IBOutlet NSView *fSimplePresetView;
IBOutlet NSTextField *fEncoderOptionsLabel;
// x264/x265 Presets Box
IBOutlet NSButton *fX264UseAdvancedOptionsCheck;
IBOutlet NSBox *fDividerLine;
IBOutlet NSBox *fPresetsBox;
IBOutlet NSSlider *fPresetsSlider;
// Text Field to show the expanded opts from unparse()
IBOutlet NSTextField *fDisplayX264PresetsUnparseTextField;
}
@property (nonatomic, strong, readwrite) HBAdvancedController *advancedController;
@property (nonatomic, readwrite) BOOL presetViewEnabled;
@property (nonatomic, readwrite) NSColor *labelColor;
@end
@implementation HBVideoController
- (instancetype)initWithAdvancedController:(HBAdvancedController *)advancedController
{
self = [self init];
if (self)
{
_advancedController = advancedController;
}
return self;
}
- (instancetype)init
{
self = [super initWithNibName:@"Video" bundle:nil];
if (self)
{
_labelColor = [NSColor disabledControlTextColor];
// Observe the advanced tab pref shown/hided state.
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self
forKeyPath:@"values.HBShowAdvancedTab"
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial
context:HBVideoControllerContext];
// Observe the x264 slider granularity, to update the slider when the pref is changed.
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self
forKeyPath:@"values.x264CqSliderFractional"
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial
context:HBVideoControllerContext];
// Observer a bunch of HBVideo properties to update the UI.
[self addObserver:self forKeyPath:@"video.encoder" options:NSKeyValueObservingOptionInitial context:HBVideoControllerContext];
[self addObserver:self forKeyPath:@"video.frameRate" options:NSKeyValueObservingOptionInitial context:HBVideoControllerContext];
[self addObserver:self forKeyPath:@"video.quality" options:NSKeyValueObservingOptionInitial context:HBVideoControllerContext];
[self addObserver:self forKeyPath:@"video.preset" options:NSKeyValueObservingOptionInitial context:HBVideoControllerContext];
[self addObserver:self forKeyPath:@"video.unparseOptions" options:NSKeyValueObservingOptionInitial context:HBVideoControllerContext];
[self addObserver:self forKeyPath:@"video.advancedOptions" options:NSKeyValueObservingOptionInitial context:HBVideoControllerContext];
}
return self;
}
- (void)setVideo:(HBVideo *)video
{
_video = video;
if (video)
{
self.labelColor = [NSColor controlTextColor];
}
else
{
self.labelColor = [NSColor disabledControlTextColor];
}
[self enableEncoderOptionsWidgets:(video != nil)];
}
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == HBVideoControllerContext)
{
if ([keyPath isEqualToString:@"video.encoder"])
{
[self switchPresetView];
[self setupQualitySlider];
}
else if ([keyPath isEqualToString:@"video.frameRate"])
{
// Hide and set the PFR Checkbox to OFF if we are set to Same as Source
// Depending on whether or not Same as source is selected modify the title for
// fFramerateVfrPfrCell
if (self.video.frameRate == 0) // We are Same as Source
{
[fFramerateVfrPfrCell setTitle:NSLocalizedString(@"Variable Framerate", nil)];
}
else
{
[fFramerateVfrPfrCell setTitle:NSLocalizedString(@"Peak Framerate (VFR)", nil)];
}
}
else if ([keyPath isEqualToString:@"video.quality"])
{
if ([fVidQualitySlider respondsToSelector:@selector(setAccessibilityValueDescription:)])
{
fVidQualitySlider.accessibilityValueDescription = [NSString stringWithFormat:@"%@ %.2f", self.video.constantQualityLabel, self.video.quality];;
}
}
else if ([keyPath isEqualToString:@"video.preset"])
{
if ([fPresetsSlider respondsToSelector:@selector(setAccessibilityValueDescription:)])
{
fPresetsSlider.accessibilityValueDescription = self.video.preset;
}
}
else if ([keyPath isEqualToString:@"video.unparseOptions"])
{
if (self.video.encoder & HB_VCODEC_X264_MASK)
{
fDisplayX264PresetsUnparseTextField.stringValue = [NSString stringWithFormat:@"x264 Unparse: %@", self.video.unparseOptions];
}
else
{
fDisplayX264PresetsUnparseTextField.stringValue = @"";
}
}
else if ([keyPath isEqualToString:@"video.advancedOptions"])
{
if (self.video.advancedOptions)
{
// Do not enable the advanced panel it isn't visible.
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"HBShowAdvancedTab"])
{
self.advancedController.videoSettings = self.video.advancedOptions ? self.video : nil;
}
else
{
self.video.advancedOptions = NO;
}
}
// enable/disable, populate and update the various widgets
[self enableEncoderOptionsWidgets:(self.video != nil)];
} else if ([keyPath isEqualToString:@"values.HBShowAdvancedTab"])
{
[self toggleAdvancedOptionsCheckBoxForEncoder:self.video.encoder];
}
else if ([keyPath isEqualToString:@"values.x264CqSliderFractional"])
{
[self setupQualitySlider];
}
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
#pragma mark - Interface setup
/*
* Use this method to setup the quality slider for cq/rf values depending on
* the video encoder selected.
*/
- (void)setupQualitySlider
{
int direction;
float minValue, maxValue, granularity;
hb_video_quality_get_limits(self.video.encoder,
&minValue, &maxValue, &granularity, &direction);
if (granularity < 1.0f)
{
// Encoders that allow fractional CQ values often have a low granularity
// which makes the slider hard to use, so use a value from preferences.
granularity = [[NSUserDefaults standardUserDefaults]
floatForKey:@"x264CqSliderFractional"];
}
fVidQualitySlider.minValue = minValue;
fVidQualitySlider.maxValue = maxValue;
[fVidQualitySlider setNumberOfTickMarks:(int)((maxValue - minValue) *
(1.0f / granularity)) + 1];
// Replace the slider transformer with a new one,
// configured with the new max/min/direction values.
[fVidQualitySlider unbind:@"value"];
HBQualityTransformer *transformer = [[HBQualityTransformer alloc] initWithReversedDirection:(direction != 0) min:minValue max:maxValue];
[fVidQualitySlider bind:@"value" toObject:self withKeyPath:@"self.video.quality" options:@{NSValueTransformerBindingOption: transformer}];
}
#pragma mark - Video x264/x265 Presets
/**
* Shows/hides the right preset view for the current video encoder.
*/
- (void)switchPresetView
{
self.advancedController.hidden = YES;
if (hb_video_encoder_get_presets(self.video.encoder) != NULL)
{
[self toggleAdvancedOptionsCheckBoxForEncoder:self.video.encoder];
fPresetsBox.contentView = fPresetView;
[self setupPresetsSlider];
if (self.video.encoder & HB_VCODEC_X264_MASK)
{
self.advancedController.hidden = NO;
}
}
else if (self.video.encoder & HB_VCODEC_FFMPEG_MASK)
{
fPresetsBox.contentView = fSimplePresetView;
}
else
{
fPresetsBox.contentView = nil;
}
}
/**
* Enables/disables the advanced panel and the preset panel.
*/
- (void)enableEncoderOptionsWidgets:(BOOL)enable
{
// check whether the x264 preset system and the advanced panel should be enabled
BOOL enable_x264_controls = (enable && !self.video.advancedOptions);
BOOL enable_advanced_panel = (enable && self.video.advancedOptions);
// enable/disable the checkbox and advanced panel
self.presetViewEnabled = enable_x264_controls;
self.advancedController.enabled = enable_advanced_panel;
}
/**
* Shows/Hides the advanced options checkbox
*
* @param encoder the current encoder
*/
- (void)toggleAdvancedOptionsCheckBoxForEncoder:(int)encoder
{
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"HBShowAdvancedTab"] && (encoder & HB_VCODEC_X264_MASK))
{
fX264UseAdvancedOptionsCheck.hidden = NO;
fDividerLine.hidden = YES;
fEncoderOptionsLabel.stringValue = NSLocalizedString(@"Encoder Options:", @"");
}
else
{
fX264UseAdvancedOptionsCheck.hidden =YES;
fDividerLine.hidden = NO;
fEncoderOptionsLabel.stringValue = NSLocalizedString(@"Encoder Options", @"");
self.video.advancedOptions = NO;
}
}
/**
* Setup the presets slider with the right
* number of ticks.
*/
- (void)setupPresetsSlider
{
// setup the preset slider
[fPresetsSlider setMaxValue:self.video.presets.count - 1];
[fPresetsSlider setNumberOfTickMarks:self.video.presets.count];
// Bind the slider value to a custom value transformer,
// done here because it can't be done in IB.
[fPresetsSlider unbind:@"value"];
HBPresetsTransformer *transformer = [[HBPresetsTransformer alloc] initWithEncoder:self.video.encoder];
[fPresetsSlider bind:@"value" toObject:self withKeyPath:@"self.video.preset" options:@{NSValueTransformerBindingOption: transformer}];
}
@end