mirror of https://github.com/HandBrake/HandBrake
305 lines
11 KiB
Objective-C
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
|