diff options
-rw-r--r-- | macosx/English.lproj/PictureSettings.xib | 50 | ||||
-rw-r--r-- | macosx/HBAddPresetController.m | 3 | ||||
-rw-r--r-- | macosx/HBAppDelegate.m | 16 | ||||
-rw-r--r-- | macosx/HBAudioDefaults.m | 97 | ||||
-rw-r--r-- | macosx/HBAudioTrackPreset.h | 2 | ||||
-rw-r--r-- | macosx/HBAudioTrackPreset.m | 4 | ||||
-rw-r--r-- | macosx/HBController.m | 94 | ||||
-rw-r--r-- | macosx/HBFilters+UIAdditions.h | 17 | ||||
-rw-r--r-- | macosx/HBFilters+UIAdditions.m | 202 | ||||
-rw-r--r-- | macosx/HBFilters.h | 6 | ||||
-rw-r--r-- | macosx/HBFilters.m | 201 | ||||
-rw-r--r-- | macosx/HBJob+HBJobConversion.m | 22 | ||||
-rw-r--r-- | macosx/HBJob.m | 11 | ||||
-rw-r--r-- | macosx/HBPicture.h | 2 | ||||
-rw-r--r-- | macosx/HBPicture.m | 52 | ||||
-rw-r--r-- | macosx/HBPreset.h | 65 | ||||
-rw-r--r-- | macosx/HBPreset.m | 187 | ||||
-rw-r--r-- | macosx/HBPresetsManager.h | 14 | ||||
-rw-r--r-- | macosx/HBPresetsManager.m | 296 | ||||
-rw-r--r-- | macosx/HBPresetsViewController.m | 6 | ||||
-rw-r--r-- | macosx/HBTreeNode.h | 22 | ||||
-rw-r--r-- | macosx/HBTreeNode.m | 59 | ||||
-rw-r--r-- | macosx/HBVideo.m | 79 | ||||
-rw-r--r-- | macosx/HandBrake.xcodeproj/project.pbxproj | 8 |
24 files changed, 896 insertions, 619 deletions
diff --git a/macosx/English.lproj/PictureSettings.xib b/macosx/English.lproj/PictureSettings.xib index 39946b7ce..81b957b64 100644 --- a/macosx/English.lproj/PictureSettings.xib +++ b/macosx/English.lproj/PictureSettings.xib @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="7702" systemVersion="14E11f" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none"> +<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="7702" systemVersion="14E17e" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none"> <dependencies> <deployment version="1060" identifier="macosx"/> <development version="5100" identifier="xcode"/> @@ -204,7 +204,7 @@ <stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" id="44"> <rect key="frame" x="143" y="103" width="15" height="22"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> - <stepperCell key="cell" controlSize="small" continuous="YES" alignment="left" increment="16" minValue="64" maxValue="59" doubleValue="64" id="169"> + <stepperCell key="cell" controlSize="small" continuous="YES" alignment="left" increment="16" minValue="64" maxValue="59" doubleValue="59" id="169"> <font key="font" metaFont="smallSystem"/> </stepperCell> <connections> @@ -254,7 +254,7 @@ <stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" id="46"> <rect key="frame" x="143" y="78" width="15" height="22"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> - <stepperCell key="cell" controlSize="small" continuous="YES" alignment="left" increment="16" minValue="64" maxValue="59" doubleValue="59" id="171"> + <stepperCell key="cell" controlSize="small" continuous="YES" alignment="left" increment="16" minValue="64" maxValue="59" doubleValue="64" id="171"> <font key="font" metaFont="smallSystem"/> </stepperCell> <connections> @@ -589,9 +589,9 @@ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> </textFieldCell> <connections> - <binding destination="-2" name="hidden" keyPath="self.filters.detelecine" id="GeL-Hh-N04"> + <binding destination="-2" name="hidden" keyPath="self.filters.customDetelecineSelected" id="xn5-rR-hyv"> <dictionary key="options"> - <string key="NSValueTransformerName">HBCustomFilterTransformer</string> + <string key="NSValueTransformerName">NSNegateBoolean</string> </dictionary> </binding> </connections> @@ -605,8 +605,12 @@ <menu key="menu" title="OtherViews" id="349"/> </popUpButtonCell> <connections> - <binding destination="-2" name="selectedIndex" keyPath="self.filters.detelecine" previousBinding="pGd-yk-F9V" id="nJ6-iy-GiP"/> - <binding destination="-2" name="content" keyPath="self.filters.detelecineSettings" id="pGd-yk-F9V"/> + <binding destination="-2" name="selectedValue" keyPath="self.filters.detelecine" previousBinding="rmK-X3-zA9" id="x5y-hX-luP"> + <dictionary key="options"> + <string key="NSValueTransformerName">HBDetelecineTransformer</string> + </dictionary> + </binding> + <binding destination="-2" name="contentValues" keyPath="self.filters.detelecineSettings" id="rmK-X3-zA9"/> </connections> </popUpButton> <textField verticalHuggingPriority="750" id="343"> @@ -618,9 +622,9 @@ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> </textFieldCell> <connections> - <binding destination="-2" name="hidden" keyPath="self.filters.detelecine" id="BLn-QV-lw8"> + <binding destination="-2" name="hidden" keyPath="self.filters.customDetelecineSelected" id="fF2-eT-6RN"> <dictionary key="options"> - <string key="NSValueTransformerName">HBCustomFilterTransformer</string> + <string key="NSValueTransformerName">NSNegateBoolean</string> </dictionary> </binding> <binding destination="-2" name="value" keyPath="self.filters.detelecineCustomString" id="gSO-TA-w8P"> @@ -693,9 +697,9 @@ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> </textFieldCell> <connections> - <binding destination="-2" name="hidden" keyPath="self.filters.decomb" id="SgL-u6-Y9a"> + <binding destination="-2" name="hidden" keyPath="self.filters.customDecombSelected" id="pks-wo-Nne"> <dictionary key="options"> - <string key="NSValueTransformerName">HBCustomFilterTransformer</string> + <string key="NSValueTransformerName">NSNegateBoolean</string> </dictionary> </binding> </connections> @@ -709,7 +713,11 @@ <menu key="menu" title="OtherViews" id="322"/> </popUpButtonCell> <connections> - <binding destination="-2" name="selectedIndex" keyPath="self.filters.decomb" previousBinding="Rky-63-XUy" id="0LF-hS-iFS"/> + <binding destination="-2" name="selectedValue" keyPath="self.filters.decomb" previousBinding="Rky-63-XUy" id="TQt-JS-VHx"> + <dictionary key="options"> + <string key="NSValueTransformerName">HBDecombTransformer</string> + </dictionary> + </binding> <binding destination="-2" name="contentValues" keyPath="self.filters.decombSettings" id="Rky-63-XUy"/> </connections> </popUpButton> @@ -722,9 +730,9 @@ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> </textFieldCell> <connections> - <binding destination="-2" name="hidden" keyPath="self.filters.decomb" id="akE-8W-aND"> + <binding destination="-2" name="hidden" keyPath="self.filters.customDecombSelected" id="nJx-xP-xY9"> <dictionary key="options"> - <string key="NSValueTransformerName">HBCustomFilterTransformer</string> + <string key="NSValueTransformerName">NSNegateBoolean</string> </dictionary> </binding> <binding destination="-2" name="value" keyPath="self.filters.decombCustomString" id="y3W-Df-Jgn"> @@ -764,9 +772,9 @@ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> </textFieldCell> <connections> - <binding destination="-2" name="hidden" keyPath="self.filters.deinterlace" id="rIM-KR-bUf"> + <binding destination="-2" name="hidden" keyPath="self.filters.customDeinterlaceSelected" id="Nh0-4S-cCl"> <dictionary key="options"> - <string key="NSValueTransformerName">HBCustomFilterTransformer</string> + <string key="NSValueTransformerName">NSNegateBoolean</string> </dictionary> </binding> </connections> @@ -780,7 +788,11 @@ <menu key="menu" title="OtherViews" id="336"/> </popUpButtonCell> <connections> - <binding destination="-2" name="selectedIndex" keyPath="self.filters.deinterlace" previousBinding="hol-Lh-FVF" id="5jK-2w-2Fq"/> + <binding destination="-2" name="selectedValue" keyPath="self.filters.deinterlace" previousBinding="hol-Lh-FVF" id="xvF-2Y-wvz"> + <dictionary key="options"> + <string key="NSValueTransformerName">HBDeinterlaceTransformer</string> + </dictionary> + </binding> <binding destination="-2" name="contentValues" keyPath="self.filters.deinterlaceSettings" id="hol-Lh-FVF"/> </connections> </popUpButton> @@ -793,9 +805,9 @@ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> </textFieldCell> <connections> - <binding destination="-2" name="hidden" keyPath="self.filters.deinterlace" id="7f6-Fd-pfo"> + <binding destination="-2" name="hidden" keyPath="self.filters.customDeinterlaceSelected" id="CFf-Mz-6Hc"> <dictionary key="options"> - <string key="NSValueTransformerName">HBCustomFilterTransformer</string> + <string key="NSValueTransformerName">NSNegateBoolean</string> </dictionary> </binding> <binding destination="-2" name="value" keyPath="self.filters.deinterlaceCustomString" id="aSX-hF-LBO"> diff --git a/macosx/HBAddPresetController.m b/macosx/HBAddPresetController.m index cdc0caf14..ac3ea4829 100644 --- a/macosx/HBAddPresetController.m +++ b/macosx/HBAddPresetController.m @@ -8,6 +8,7 @@ #import "HBAddPresetController.h" #import "HBPreset.h" + #include "hb.h" @interface HBAddPresetController () @@ -121,6 +122,8 @@ self.preset.content = [dict copy]; + [self.preset cleanUp]; + [[self window] orderOut:nil]; [NSApp endSheet:[self window] returnCode:NSModalResponseContinue]; } diff --git a/macosx/HBAppDelegate.m b/macosx/HBAppDelegate.m index 03e10a921..39f6671ea 100644 --- a/macosx/HBAppDelegate.m +++ b/macosx/HBAppDelegate.m @@ -16,7 +16,7 @@ #import "HBCore.h" #import "HBController.h" -#define PRESET_FILE @"UserPresets.plist" +#define PRESET_FILE @"UserPresets.json" @interface HBAppDelegate () @@ -77,8 +77,6 @@ - (void)applicationDidFinishLaunching:(NSNotification *)notification { - // Updates built-ins presets if needed - [self checkBuiltInsForUpdates]; [self buildPresetsMenu]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(buildPresetsMenu) name:HBPresetsChangedNotification object:nil]; @@ -286,9 +284,9 @@ - (void)checkBuiltInsForUpdates { // if we have built in presets to update, then do so AlertBuiltInPresetUpdate - if ([self.presetsManager checkBuiltInsForUpdates]) - { - if( [[NSUserDefaults standardUserDefaults] boolForKey:@"AlertBuiltInPresetUpdate"] == YES) + //if ([self.presetsManager checkBuiltInsForUpdates]) + //{ + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"AlertBuiltInPresetUpdate"] == YES) { // Show an alert window that built in presets will be updated [NSApp requestUserAttention:NSCriticalRequest]; @@ -297,9 +295,7 @@ [alert setInformativeText:@"HandBrake will now update your built-in presets."]; [alert runModal]; } - // when alert is dismissed, go ahead and update the built in presets - [self.presetsManager generateBuiltInPresets]; - } + //} } /** @@ -336,7 +332,7 @@ item.representedObject = obj; } // Make the default preset font bold. - if ([obj isDefault]) + if ([obj isEqualTo:self.presetsManager.defaultPreset]) { NSAttributedString *newTitle = [[NSAttributedString alloc] initWithString:[obj name] attributes:@{NSFontAttributeName: [NSFont boldSystemFontOfSize:14]}]; diff --git a/macosx/HBAudioDefaults.m b/macosx/HBAudioDefaults.m index a5c6f100a..727910aa9 100644 --- a/macosx/HBAudioDefaults.m +++ b/macosx/HBAudioDefaults.m @@ -117,14 +117,41 @@ } // Passthru settings - self.allowAACPassthru = [preset[@"AudioAllowAACPass"] boolValue]; - self.allowAC3Passthru = [preset[@"AudioAllowAC3Pass"] boolValue]; - self.allowEAC3Passthru = [preset[@"AudioAllowEAC3Pass"] boolValue]; - self.allowDTSHDPassthru = [preset[@"AudioAllowDTSHDPass"] boolValue]; - self.allowDTSPassthru= [preset[@"AudioAllowDTSPass"] boolValue]; - self.allowMP3Passthru = [preset[@"AudioAllowMP3Pass"] boolValue]; - self.allowTrueHDPassthru = [preset[@"AudioAllowTrueHDPass"] boolValue]; - self.allowFLACPassthru = [preset[@"AudioAllowFlacPass"] boolValue]; + for (NSString *copyMask in preset[@"AudioCopyMask"]) + { + if ([copyMask isEqualToString:@"copy:aac"]) + { + self.allowAACPassthru = YES; + } + else if ([copyMask isEqualToString:@"copy:ac3"]) + { + self.allowAC3Passthru = YES; + } + else if ([copyMask isEqualToString:@"copy:eac3"]) + { + self.allowEAC3Passthru = YES; + } + else if ([copyMask isEqualToString:@"copy:dtshd"]) + { + self.allowDTSHDPassthru = YES; + } + else if ([copyMask isEqualToString:@"copy:dts"]) + { + self.allowDTSPassthru = YES; + } + else if ([copyMask isEqualToString:@"copy:mp3"]) + { + self.allowMP3Passthru = YES; + } + else if ([copyMask isEqualToString:@"copy:truehd"]) + { + self.allowTrueHDPassthru = YES; + } + else if ([copyMask isEqualToString:@"copy:flac"]) + { + self.allowFLACPassthru = YES; + } + } self.secondaryEncoderMode = [preset[@"AudioSecondaryEncoderMode"] boolValue]; @@ -160,8 +187,8 @@ } newTrack.bitRate = [track[@"AudioBitrate"] intValue]; - newTrack.drc = [track[@"AudioTrackDRCSlider"] floatValue]; - newTrack.gain = [track[@"AudioTrackGainSlider"] intValue]; + newTrack.drc = [track[@"AudioTrackDRCSlider"] doubleValue]; + newTrack.gain = [track[@"AudioTrackGainSlider"] doubleValue]; [self.tracksArray addObject:newTrack]; } } @@ -184,16 +211,42 @@ preset[@"AudioLanguageList"] = [self.trackSelectionLanguages copy]; // Passthru settings - preset[@"AudioAllowAACPass"] = @(self.allowAACPassthru); - preset[@"AudioAllowAC3Pass"] = @(self.allowAC3Passthru); - preset[@"AudioAllowEAC3Pass"] = @(self.allowEAC3Passthru); - preset[@"AudioAllowDTSHDPass"] = @(self.allowDTSHDPassthru); - preset[@"AudioAllowDTSPass"] = @(self.allowDTSPassthru); - preset[@"AudioAllowMP3Pass"] = @(self.allowMP3Passthru); - preset[@"AudioAllowTrueHDPass"] = @(self.allowTrueHDPassthru); - preset[@"AudioAllowFlacPass"] = @(self.allowFLACPassthru); + NSMutableArray *copyMask = [NSMutableArray array]; + if (self.allowAACPassthru) + { + [copyMask addObject:@"copy:aac"]; + } + if (self.allowAC3Passthru) + { + [copyMask addObject:@"copy:ac3"]; + } + if (self.allowEAC3Passthru) + { + [copyMask addObject:@"copy:eac3"]; + } + if (self.allowDTSHDPassthru) + { + [copyMask addObject:@"copy:dtshd"]; + } + if (self.allowDTSPassthru) + { + [copyMask addObject:@"copy:dts"]; + } + if (self.allowMP3Passthru) + { + [copyMask addObject:@"copy:mp3"]; + } + if (self.allowTrueHDPassthru) + { + [copyMask addObject:@"copy:truehd"]; + } + if (self.allowFLACPassthru) + { + [copyMask addObject:@"copy:flac"]; + } + preset[@"AudioCopyMask"] = [copyMask copy]; - preset[@"AudioEncoderFallback"] = @(hb_audio_encoder_get_name(self.encoderFallback)); + preset[@"AudioEncoderFallback"] = @(hb_audio_encoder_get_short_name(self.encoderFallback)); preset[@"AudioSecondaryEncoderMode"] = @(self.secondaryEncoderMode); @@ -201,13 +254,13 @@ for (HBAudioTrackPreset *track in self.tracksArray) { - NSString *sampleRate = @"Auto"; + NSString *sampleRate = @"auto"; if (hb_audio_samplerate_get_name(track.sampleRate)) { sampleRate = @(hb_audio_samplerate_get_name(track.sampleRate)); } - NSDictionary *newTrack = @{@"AudioEncoder": @(hb_audio_encoder_get_name(track.encoder)), - @"AudioMixdown": @(hb_mixdown_get_name(track.mixdown)), + NSDictionary *newTrack = @{@"AudioEncoder": @(hb_audio_encoder_get_short_name(track.encoder)), + @"AudioMixdown": @(hb_mixdown_get_short_name(track.mixdown)), @"AudioSamplerate": sampleRate, @"AudioBitrate": @(track.bitRate), @"AudioTrackDRCSlider": @(track.drc), diff --git a/macosx/HBAudioTrackPreset.h b/macosx/HBAudioTrackPreset.h index 3ca97d97e..a7d849757 100644 --- a/macosx/HBAudioTrackPreset.h +++ b/macosx/HBAudioTrackPreset.h @@ -24,7 +24,7 @@ @property (nonatomic, readwrite) int sampleRate; @property (nonatomic, readwrite) int bitRate; -@property (nonatomic, readwrite) int gain; +@property (nonatomic, readwrite) double gain; @property (nonatomic, readwrite) double drc; /** diff --git a/macosx/HBAudioTrackPreset.m b/macosx/HBAudioTrackPreset.m index 2e479f4fc..f3f40d813 100644 --- a/macosx/HBAudioTrackPreset.m +++ b/macosx/HBAudioTrackPreset.m @@ -276,7 +276,7 @@ static void *HBAudioEncoderContex = &HBAudioEncoderContex; encodeInt(_sampleRate); encodeInt(_bitRate); - encodeInt(_gain); + encodeDouble(_gain); encodeDouble(_drc); encodeInt(_container); @@ -291,7 +291,7 @@ static void *HBAudioEncoderContex = &HBAudioEncoderContex; decodeInt(_sampleRate); decodeInt(_bitRate); - decodeInt(_gain); + decodeDouble(_gain); decodeDouble(_drc); decodeInt(_container); diff --git a/macosx/HBController.m b/macosx/HBController.m index 07086cd2d..c169e0fdc 100644 --- a/macosx/HBController.m +++ b/macosx/HBController.m @@ -51,7 +51,7 @@ @property (nonatomic, strong) HBJob *jobFromQueue; /// The current selected preset. -@property (nonatomic, strong) HBPreset *selectedPreset; +@property (nonatomic, strong) HBPreset *currentPreset; @property (nonatomic) BOOL customPreset; /// The HBCore used for scanning. @@ -82,7 +82,6 @@ fQueueController.controller = self; presetManager = manager; - _selectedPreset = presetManager.defaultPreset; } return self; @@ -397,7 +396,7 @@ } if (action == @selector(selectPresetFromMenu:)) { - if ([menuItem.representedObject isEqualTo:self.selectedPreset]) + if ([menuItem.representedObject isEqualTo:self.currentPreset]) { menuItem.state = NSOnState; } @@ -625,7 +624,7 @@ // Save the current settings if (self.job) { - self.selectedPreset = [self createPresetFromCurrentSettings]; + self.currentPreset = [self createPresetFromCurrentSettings]; } self.job = nil; @@ -833,7 +832,11 @@ // If there is already a title load, save the current settings to a preset if (self.job) { - self.selectedPreset = [self createPresetFromCurrentSettings]; + self.currentPreset = [self createPresetFromCurrentSettings]; + } + else + { + self.currentPreset = fPresetsView.selectedPreset; } HBTitle *title = self.core.titles[fSrcTitlePopUp.indexOfSelectedItem]; @@ -846,7 +849,7 @@ } else { - self.job = [[HBJob alloc] initWithTitle:title andPreset:self.selectedPreset]; + self.job = [[HBJob alloc] initWithTitle:title andPreset:self.currentPreset]; self.job.destURL = [self destURLForJob:self.job]; } @@ -1271,7 +1274,7 @@ { if (preset != nil && self.job) { - self.selectedPreset = preset; + self.currentPreset = preset; // Remove the job observer so we don't update the file name // too many times while the preset is being applied @@ -1309,7 +1312,7 @@ - (HBPreset *)createPresetFromCurrentSettings { NSMutableDictionary *preset = [NSMutableDictionary dictionary]; - NSDictionary *currentPreset = self.selectedPreset.content; + NSDictionary *currentPreset = self.currentPreset.content; preset[@"PresetBuildNumber"] = [NSString stringWithFormat: @"%d", [[[NSBundle mainBundle] infoDictionary][@"CFBundleVersion"] intValue]]; preset[@"PresetName"] = self.job.presetName; @@ -1317,7 +1320,7 @@ // Set whether or not this is a user preset or factory 0 is factory, 1 is user preset[@"Type"] = @1; - preset[@"Default"] = @0; + preset[@"Default"] = @NO; // Get the whether or not to apply pic Size and Cropping (includes Anamorphic) preset[@"UsesPictureSettings"] = currentPreset[@"UsesPictureSettings"]; @@ -1337,38 +1340,23 @@ #pragma mark - #pragma mark Import Export Preset(s) -- (IBAction) browseExportPresetFile: (id) sender +- (IBAction)browseExportPresetFile:(id)sender { // Open a panel to let the user choose where and how to save the export file NSSavePanel *panel = [NSSavePanel savePanel]; // We get the current file name and path from the destination field here NSURL *defaultExportDirectory = [[NSURL fileURLWithPath:NSHomeDirectory()] URLByAppendingPathComponent:@"Desktop"]; - [panel setDirectoryURL:defaultExportDirectory]; - [panel setNameFieldStringValue:@"HB_Export.plist"]; - [panel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) { - if( result == NSOKButton ) + panel.directoryURL = defaultExportDirectory; + panel.nameFieldStringValue = [NSString stringWithFormat:@"%@.json", fPresetsView.selectedPreset.name]; + + [panel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) + { + if (result == NSOKButton) { - NSURL *exportPresetsFile = [panel URL]; - NSURL *presetExportDirectory = [exportPresetsFile URLByDeletingLastPathComponent]; + NSURL *presetExportDirectory = [panel.URL URLByDeletingLastPathComponent]; [[NSUserDefaults standardUserDefaults] setURL:presetExportDirectory forKey:@"LastPresetExportDirectoryURL"]; - // We check for the presets.plist - if ([[NSFileManager defaultManager] fileExistsAtPath:[exportPresetsFile path]] == 0) - { - [[NSFileManager defaultManager] createFileAtPath:[exportPresetsFile path] contents:nil attributes:nil]; - } - - NSMutableArray *presetsToExport = [[NSMutableArray alloc] initWithContentsOfURL:exportPresetsFile]; - if (presetsToExport == nil) - { - presetsToExport = [[NSMutableArray alloc] init]; - // now get and add selected presets to export - } - if (fPresetsView.selectedPreset != nil) - { - [presetsToExport addObject:[fPresetsView.selectedPreset content]]; - [presetsToExport writeToURL:exportPresetsFile atomically:YES]; - } + [fPresetsView.selectedPreset writeToURL:panel.URL atomically:YES format:HBPresetFormatJson removeRoot:NO]; } }]; } @@ -1376,43 +1364,31 @@ - (IBAction)browseImportPresetFile:(id)sender { NSOpenPanel *panel = [NSOpenPanel openPanel]; - [panel setAllowsMultipleSelection:NO]; - [panel setCanChooseFiles:YES]; - [panel setCanChooseDirectories:NO]; - [panel setAllowedFileTypes:@[@"plist", @"xml"]]; + panel.allowsMultipleSelection = YES; + panel.canChooseFiles = YES; + panel.canChooseDirectories = NO; + panel.allowedFileTypes = @[@"plist", @"xml", @"json"]; - NSURL *sourceDirectory; if ([[NSUserDefaults standardUserDefaults] URLForKey:@"LastPresetImportDirectoryURL"]) { - sourceDirectory = [[NSUserDefaults standardUserDefaults] URLForKey:@"LastPresetImportDirectoryURL"]; + panel.directoryURL = [[NSUserDefaults standardUserDefaults] URLForKey:@"LastPresetImportDirectoryURL"]; } else { - sourceDirectory = [[NSURL fileURLWithPath:NSHomeDirectory()] URLByAppendingPathComponent:@"Desktop"]; + panel.directoryURL = [[NSURL fileURLWithPath:NSHomeDirectory()] URLByAppendingPathComponent:@"Desktop"]; } - // set this for allowed file types, not sure if we should allow xml or not. - [panel setDirectoryURL:sourceDirectory]; [panel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) { - NSURL *importPresetsFile = [panel URL]; - NSURL *importPresetsDirectory = [importPresetsFile URLByDeletingLastPathComponent]; - [[NSUserDefaults standardUserDefaults] setURL:importPresetsDirectory forKey:@"LastPresetImportDirectoryURL"]; + [[NSUserDefaults standardUserDefaults] setURL:panel.directoryURL forKey:@"LastPresetImportDirectoryURL"]; - // NOTE: here we need to do some sanity checking to verify we do not hose up our presets file - NSMutableArray *presetsToImport = [[NSMutableArray alloc] initWithContentsOfURL:importPresetsFile]; - // iterate though the new array of presets to import and add them to our presets array - for (NSMutableDictionary *dict in presetsToImport) + for (NSURL *url in panel.URLs) { - // make any changes to the incoming preset we see fit - // make sure the incoming preset is not tagged as default - dict[@"Default"] = @0; - // prepend "(imported) to the name of the incoming preset for clarification since it can be changed - NSString *prependedName = [@"(import) " stringByAppendingString:dict[@"PresetName"]] ; - dict[@"PresetName"] = prependedName; - - // actually add the new preset to our presets array - [presetManager addPresetFromDictionary:dict]; + HBPreset *import = [[HBPreset alloc] initWithContentsOfURL:url]; + if (import) + { + [presetManager addPreset:import]; + } } }]; } @@ -1423,7 +1399,7 @@ - (IBAction)selectDefaultPreset:(id)sender { [self applyPreset:presetManager.defaultPreset]; - [fPresetsView setSelection:_selectedPreset]; + [fPresetsView setSelection:_currentPreset]; } - (IBAction)insertFolder:(id)sender diff --git a/macosx/HBFilters+UIAdditions.h b/macosx/HBFilters+UIAdditions.h index c4dbaeaa7..9a3f0c428 100644 --- a/macosx/HBFilters+UIAdditions.h +++ b/macosx/HBFilters+UIAdditions.h @@ -12,10 +12,18 @@ /** * Getters to get the possible values for the filters. */ ++ (NSDictionary *)detelecinePresetsDict; ++ (NSDictionary *)decombPresetsDict; ++ (NSDictionary *)deinterlacePresetsDict; + + (NSDictionary *)denoisePresetDict; + (NSDictionary *)nlmeansTunesDict; + (NSDictionary *)denoiseTypesDict; +- (BOOL)customDetelecineSelected; +- (BOOL)customDecombSelected; +- (BOOL)customDeinterlaceSelected; + @property (nonatomic, readonly) NSArray *detelecineSettings; @property (nonatomic, readonly) NSArray *deinterlaceSettings; @property (nonatomic, readonly) NSArray *decombSettings; @@ -40,6 +48,15 @@ @property (nonatomic, strong) NSDictionary *dict; @end +@interface HBDetelecineTransformer : HBGenericDictionaryTransformer +@end + +@interface HBDecombTransformer : HBGenericDictionaryTransformer +@end + +@interface HBDeinterlaceTransformer : HBGenericDictionaryTransformer +@end + @interface HBDenoisePresetTransformer : HBGenericDictionaryTransformer @end diff --git a/macosx/HBFilters+UIAdditions.m b/macosx/HBFilters+UIAdditions.m index dc867fbe5..6d2c255fe 100644 --- a/macosx/HBFilters+UIAdditions.m +++ b/macosx/HBFilters+UIAdditions.m @@ -67,6 +67,42 @@ static NSDictionary * filterParamsToNamesDict(hb_filter_param_t * (f)(int), int @end +@implementation HBDetelecineTransformer + +- (instancetype)init +{ + if (self = [super init]) + self.dict = [HBFilters detelecinePresetsDict]; + + return self; +} + +@end + +@implementation HBDecombTransformer + +- (instancetype)init +{ + if (self = [super init]) + self.dict = [HBFilters decombPresetsDict]; + + return self; +} + +@end + +@implementation HBDeinterlaceTransformer + +- (instancetype)init +{ + if (self = [super init]) + self.dict = [HBFilters deinterlacePresetsDict]; + + return self; +} + +@end + @implementation HBDenoisePresetTransformer - (instancetype)init @@ -125,25 +161,72 @@ static NSDictionary * filterParamsToNamesDict(hb_filter_param_t * (f)(int), int @end +static NSDictionary *detelecinePresetsDict = nil; +static NSDictionary *decombPresetsDict = nil; +static NSDictionary *deinterlacePresetsDict = nil; + +static NSDictionary *denoisePresetDict = nil; +static NSDictionary *nlmeansTunesDict = nil; +static NSDictionary *denoiseTypesDict = nil; + @implementation HBFilters (UIAdditions) #pragma mark - Valid values ++ (NSDictionary *)detelecinePresetsDict +{ + if (!detelecinePresetsDict) + { + detelecinePresetsDict = filterParamsToNamesDict(hb_filter_param_get_presets, HB_FILTER_DETELECINE); + } + return detelecinePresetsDict; +} + ++ (NSDictionary *)decombPresetsDict +{ + if (!decombPresetsDict) + { + decombPresetsDict = filterParamsToNamesDict(hb_filter_param_get_presets, HB_FILTER_DECOMB); + } + return decombPresetsDict; +} + ++ (NSDictionary *)deinterlacePresetsDict +{ + if (!deinterlacePresetsDict) + { + deinterlacePresetsDict = filterParamsToNamesDict(hb_filter_param_get_presets, HB_FILTER_DEINTERLACE); + } + return deinterlacePresetsDict; +} + + (NSDictionary *)denoisePresetDict { - return filterParamsToNamesDict(hb_filter_param_get_presets, HB_FILTER_NLMEANS); + if (!denoisePresetDict) + { + denoisePresetDict = filterParamsToNamesDict(hb_filter_param_get_presets, HB_FILTER_NLMEANS); + } + return denoisePresetDict; } + (NSDictionary *)nlmeansTunesDict { - return filterParamsToNamesDict(hb_filter_param_get_tunes, HB_FILTER_NLMEANS); + if (!nlmeansTunesDict) + { + nlmeansTunesDict = filterParamsToNamesDict(hb_filter_param_get_tunes, HB_FILTER_NLMEANS); + } + return nlmeansTunesDict; } + (NSDictionary *)denoiseTypesDict { - return @{NSLocalizedString(@"Off", nil): @"off", - NSLocalizedString(@"NLMeans", nil): @"nlmeans", - NSLocalizedString(@"HQDN3D", nil): @"hqdn3d"};; + if (!denoiseTypesDict) + { + denoiseTypesDict = @{NSLocalizedString(@"Off", nil): @"off", + NSLocalizedString(@"NLMeans", nil): @"nlmeans", + NSLocalizedString(@"HQDN3D", nil): @"hqdn3d"};; + } + return denoiseTypesDict; } - (NSArray *)detelecineSettings @@ -176,97 +259,80 @@ static NSDictionary * filterParamsToNamesDict(hb_filter_param_t * (f)(int), int return filterParamsToNamesArray(hb_filter_param_get_tunes, HB_FILTER_NLMEANS); } +- (BOOL)customDetelecineSelected +{ + return [self.detelecine isEqualToString:@"custom"] ? YES : NO; +} + +- (BOOL)customDecombSelected +{ + return [self.decomb isEqualToString:@"custom"] ? YES : NO; +} + +- (BOOL)customDeinterlaceSelected +{ + return [self.deinterlace isEqualToString:@"custom"] ? YES : NO; +} + - (NSString *)summary { NSMutableString *summary = [NSMutableString string]; - /* Detelecine */ - switch (self.detelecine) + // Detelecine + if (![self.detelecine isEqualToString:@"off"]) { - case 1: + if ([self.detelecine isEqualToString:@"custom"]) + { [summary appendFormat:@" - Detelecine (%@)", self.detelecineCustomString]; - break; - - case 2: - [summary appendString:@" - Detelecine (Default)"]; - break; - - default: - break; + } + else + { + [summary appendFormat:@" - Detelecine (%@)", [[[HBFilters detelecinePresetsDict] allKeysForObject:self.detelecine] firstObject]]; + } } - if (self.useDecomb) + if (self.useDecomb && ![self.decomb isEqualToString:@"off"]) { - /* Decomb */ - switch (self.decomb) + // Decomb + if ([self.decomb isEqualToString:@"custom"]) { - case 1: - [summary appendFormat:@" - Decomb (%@)", self.decombCustomString]; - break; - - case 2: - [summary appendString:@" - Decomb (Default)"]; - break; - - case 3: - [summary appendString:@" - Decomb (Fast)"]; - break; - - case 4: - [summary appendString:@" - Decomb (Bob)"]; - break; - - default: - break; + [summary appendFormat:@" - Decomb (%@)", self.decombCustomString]; + } + else + { + [summary appendFormat:@" - Decomb (%@)", [[[HBFilters decombPresetsDict] allKeysForObject:self.decomb] firstObject]]; } } - else + else if (![self.deinterlace isEqualToString:@"off"]) { - /* Deinterlace */ - switch (self.deinterlace) + // Deinterlace + if ([self.deinterlace isEqualToString:@"custom"]) { - case 1: - [summary appendFormat:@" - Deinterlace (%@)", self.deinterlaceCustomString]; - break; - - case 2: - [summary appendString:@" - Deinterlace (Fast)"]; - break; - - case 3: - [summary appendString:@" - Deinterlace (Slow)"]; - break; - - case 4: - [summary appendString:@" - Deinterlace (Slower)"]; - break; - - case 5: - [summary appendString:@" - Deinterlace (Bob)"]; - break; - - default: - break; + [summary appendFormat:@" - Deinterlace (%@)", self.deinterlaceCustomString]; + } + else + { + [summary appendFormat:@" - Deinterlace (%@)", [[[HBFilters deinterlacePresetsDict] allKeysForObject:self.deinterlace] firstObject]]; } } - /* Deblock */ + // Deblock if (self.deblock > 0) { [summary appendFormat:@" - Deblock (%ld)", self.deblock]; } - /* Denoise */ + // Denoise if (![self.denoise isEqualToString:@"off"]) { - [summary appendFormat:@" - Denoise (%@", self.denoise]; + [summary appendFormat:@" - Denoise (%@", [[[HBFilters denoiseTypesDict] allKeysForObject:self.denoise] firstObject]]; if (![self.denoisePreset isEqualToString:@"custom"]) { - [summary appendFormat:@", %@", self.denoisePreset]; + [summary appendFormat:@", %@", [[[HBFilters denoisePresetDict] allKeysForObject:self.denoisePreset] firstObject]]; if ([self.denoise isEqualToString:@"nlmeans"]) { - [summary appendFormat:@", %@", self.denoiseTune]; + [summary appendFormat:@", %@", [[[HBFilters nlmeansTunesDict] allKeysForObject:self.denoiseTune] firstObject]]; } } else @@ -278,7 +344,7 @@ static NSDictionary * filterParamsToNamesDict(hb_filter_param_t * (f)(int), int } - /* Grayscale */ + // Grayscale if (self.grayscale) { [summary appendString:@" - Grayscale"]; diff --git a/macosx/HBFilters.h b/macosx/HBFilters.h index 90876877d..9d13a018b 100644 --- a/macosx/HBFilters.h +++ b/macosx/HBFilters.h @@ -14,15 +14,15 @@ extern NSString * const HBFiltersChangedNotification; */ @interface HBFilters : NSObject <NSSecureCoding, NSCopying, HBPresetCoding> -@property (nonatomic, readwrite) NSInteger detelecine; +@property (nonatomic, readwrite, copy) NSString *detelecine; @property (nonatomic, readwrite, copy) NSString *detelecineCustomString; @property (nonatomic, readwrite) BOOL useDecomb; -@property (nonatomic, readwrite) NSInteger deinterlace; +@property (nonatomic, readwrite, copy) NSString *deinterlace; @property (nonatomic, readwrite, copy) NSString *deinterlaceCustomString; -@property (nonatomic, readwrite) NSInteger decomb; +@property (nonatomic, readwrite, copy) NSString *decomb; @property (nonatomic, readwrite, copy) NSString *decombCustomString; @property (nonatomic, readwrite, copy) NSString *denoise; diff --git a/macosx/HBFilters.m b/macosx/HBFilters.m index 77d11defc..90a031c6d 100644 --- a/macosx/HBFilters.m +++ b/macosx/HBFilters.m @@ -23,8 +23,11 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; self = [super init]; if (self) { + _detelecine = @"off"; _detelecineCustomString = @""; + _deinterlace = @"off"; _deinterlaceCustomString = @""; + _decomb = @"off"; _decombCustomString = @""; _denoise = @"off"; _denoiseCustomString = @""; @@ -48,9 +51,16 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; #pragma mark - Setters -- (void)setDetelecine:(NSInteger)detelecine +- (void)setDetelecine:(NSString *)detelecine { - _detelecine = detelecine; + if (detelecine) + { + _detelecine = [detelecine copy]; + } + else + { + _detelecine = @"off"; + } [self postChangedNotification]; } @@ -69,9 +79,16 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; [self postChangedNotification]; } -- (void)setDeinterlace:(NSInteger)deinterlace +- (void)setDeinterlace:(NSString *)deinterlace { - _deinterlace = deinterlace; + if (deinterlace) + { + _deinterlace = [deinterlace copy]; + } + else + { + _deinterlace = @"off"; + } [self postChangedNotification]; } @@ -89,9 +106,16 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; [self postChangedNotification]; } -- (void)setDecomb:(NSInteger)decomb +- (void)setDecomb:(NSString *)decomb { - _decomb = decomb; + if (decomb) + { + _decomb = [decomb copy]; + } + else + { + _decomb = @"off"; + } [self postChangedNotification]; } @@ -191,6 +215,12 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; { retval = [NSSet setWithObjects:@"detelecine", @"detelecineCustomString", @"useDecomb", @"deinterlace", @"deinterlaceCustomString", @"decomb", @"decombCustomString", @"denoise", @"denoisePreset", @"denoiseTune", @"denoiseCustomString", @"deblock", @"grayscale", nil]; } + if ([key isEqualToString:@"customDetelecineSelected"] || + [key isEqualToString:@"customDecombSelected"] || + [key isEqualToString:@"customDeinterlaceSelected"]) + { + retval = [NSSet setWithObjects:@"detelecine", @"decomb", @"deinterlace", @"useDecomb", nil]; + } return retval; } @@ -204,13 +234,13 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; if (copy) { - copy->_detelecine = _detelecine; + copy->_detelecine = [_detelecine copy]; copy->_detelecineCustomString = [_detelecineCustomString copy]; - copy->_deinterlace = _deinterlace; + copy->_deinterlace = [_deinterlace copy]; copy->_deinterlaceCustomString = [_deinterlaceCustomString copy]; - copy->_decomb = _decomb; + copy->_decomb = [_decomb copy]; copy->_decombCustomString = [_decombCustomString copy]; copy->_denoise = [_denoise copy]; @@ -223,7 +253,7 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; copy->_useDecomb = _useDecomb; } - + return copy; } @@ -238,13 +268,13 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; { [coder encodeInt:1 forKey:@"HBFiltersVersion"]; - encodeInteger(_detelecine); + encodeObject(_detelecine); encodeObject(_detelecineCustomString); - encodeInteger(_deinterlace); + encodeObject(_deinterlace); encodeObject(_deinterlaceCustomString); - encodeInteger(_decomb); + encodeObject(_decomb); encodeObject(_decombCustomString); encodeObject(_denoise); @@ -262,13 +292,13 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; { self = [super init]; - decodeInteger(_detelecine); + decodeObject(_detelecine, NSString); decodeObject(_detelecineCustomString, NSString); - decodeInteger(_deinterlace); + decodeObject(_deinterlace, NSString); decodeObject(_deinterlaceCustomString, NSString); - decodeInteger(_decomb); + decodeObject(_decomb, NSString); decodeObject(_decombCustomString, NSString); decodeObject(_denoise, NSString); @@ -292,13 +322,13 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; { preset[@"PictureDecombDeinterlace"] = @(self.useDecomb); - preset[@"PictureDeinterlace"] = @(self.deinterlace); + preset[@"PictureDeinterlace"] = self.deinterlace; preset[@"PictureDeinterlaceCustom"] = self.deinterlaceCustomString; - preset[@"PictureDecomb"] = @(self.decomb); + preset[@"PictureDecomb"] = self.decomb; preset[@"PictureDecombCustom"] = self.decombCustomString; - preset[@"PictureDetelecine"] = @(self.detelecine); + preset[@"PictureDetelecine"] = self.detelecine; preset[@"PictureDetelecineCustom"] = self.detelecineCustomString; preset[@"PictureDenoiseFilter"] = self.denoise; @@ -314,127 +344,38 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; { self.notificationsEnabled = NO; - /* If the preset has an objectForKey:@"UsesPictureFilters", and handle the filters here */ - if (preset[@"UsesPictureFilters"] && [preset[@"UsesPictureFilters"] intValue] > 0) + // If the preset has an objectForKey:@"UsesPictureFilters", and handle the filters here + if ([preset[@"UsesPictureFilters"] boolValue]) { - /* We only allow *either* Decomb or Deinterlace. So check for the PictureDecombDeinterlace key. */ - self.useDecomb = 1; - self.decomb = 0; - self.deinterlace = 0; - if ([preset[@"PictureDecombDeinterlace"] intValue] == 1) - { - /* we are using decomb */ - /* Decomb */ - if ([preset[@"PictureDecomb"] intValue] > 0) - { - self.decomb = [preset[@"PictureDecomb"] intValue]; - - /* if we are using "Custom" in the decomb setting, also set the custom string*/ - if ([preset[@"PictureDecomb"] intValue] == 1) - { - self.decombCustomString = preset[@"PictureDecombCustom"]; - } - } - } - else - { - /* We are using Deinterlace */ - /* Deinterlace */ - if ([preset[@"PictureDeinterlace"] intValue] > 0) - { - self.useDecomb = 0; - self.deinterlace = [preset[@"PictureDeinterlace"] intValue]; - /* if we are using "Custom" in the deinterlace setting, also set the custom string*/ - if ([preset[@"PictureDeinterlace"] intValue] == 1) - { - self.deinterlaceCustomString = preset[@"PictureDeinterlaceCustom"]; - } - } - } + // We only allow *either* Decomb or Deinterlace. So check for the PictureDecombDeinterlace key. + self.useDecomb = [preset[@"PictureDecombDeinterlace"] boolValue]; - /* Detelecine */ - if ([preset[@"PictureDetelecine"] intValue] > 0) - { - self.detelecine = [preset[@"PictureDetelecine"] intValue]; - /* if we are using "Custom" in the detelecine setting, also set the custom string*/ - if ([preset[@"PictureDetelecine"] intValue] == 1) - { - self.detelecineCustomString = preset[@"PictureDetelecineCustom"]; - } - } - else - { - self.detelecine = 0; - } + self.decomb = preset[@"PictureDecomb"]; + self.decombCustomString = preset[@"PictureDecombCustom"]; - /* Denoise */ - if (preset[@"PictureDenoise"]) - { - // Old preset denoise format, try to map it to the new one - if ([preset[@"PictureDenoise"] intValue] > 0) - { - self.denoise = @"hqdn3d"; - /* if we are using "Custom" in the denoise setting, also set the custom string*/ - if ([preset[@"PictureDenoise"] intValue] == 1) - { - self.denoisePreset = @"custom"; - self.denoiseCustomString = preset[@"PictureDenoiseCustom"]; - } - switch ([preset[@"PictureDenoise"] intValue]) { - case 2: - self.denoisePreset = @"light"; - break; - case 3: - self.denoisePreset = @"medium"; - break; - case 4: - self.denoisePreset = @"strong"; - break; - default: - self.denoisePreset = @"medium"; - break; - } - } - else - { - self.denoise = @"off"; - } - } - else - { - // New format, read the values directly - if ([@[@"off", @"nlmeans", @"hqdn3d"] containsObject:preset[@"PictureDenoiseFilter"]]) - { - self.denoise = preset[@"PictureDenoiseFilter"]; - } - else - { - self.denoise = @"off"; - } - - if (hb_validate_filter_preset(HB_FILTER_DENOISE, [preset[@"PictureDenoisePreset"] UTF8String], [preset[@"PictureDenoiseTune"] UTF8String])) - { - self.denoisePreset = preset[@"PictureDenoisePreset"]; - self.denoiseTune = preset[@"PictureDenoiseTune"]; - } - else - { - self.denoisePreset = @"medium"; - self.denoiseTune = @"none"; - } - - self.denoiseCustomString = preset[@"PictureDenoiseCustom"]; - } + self.deinterlace = preset[@"PictureDeinterlace"]; + self.deinterlaceCustomString = preset[@"PictureDeinterlaceCustom"]; + + //Detelecine + self.detelecine = preset[@"PictureDetelecine"]; + self.detelecineCustomString = preset[@"PictureDetelecineCustom"]; + + // Denoise + self.denoise = preset[@"PictureDenoiseFilter"]; + self.denoisePreset = preset[@"PictureDenoisePreset"]; + self.denoiseTune = preset[@"PictureDenoiseTune"]; + + self.denoiseCustomString = preset[@"PictureDenoiseCustom"]; - /* Deblock */ + // Deblock if ([preset[@"PictureDeblock"] intValue] == 1) { - /* if its a one, then its the old on/off deblock, set on to 5*/ + // if its a one, then its the old on/off deblock, set on to 5 self.deblock = 5; } else { - /* use the settings intValue */ + // use the settings intValue self.deblock = [preset[@"PictureDeblock"] intValue]; } diff --git a/macosx/HBJob+HBJobConversion.m b/macosx/HBJob+HBJobConversion.m index 4778316f2..811602062 100644 --- a/macosx/HBJob+HBJobConversion.m +++ b/macosx/HBJob+HBJobConversion.m @@ -417,30 +417,30 @@ if (self.filters.detelecine) { int filter_id = HB_FILTER_DETELECINE; - const char *filter_str = hb_generate_filter_settings_by_index(filter_id, - (int)self.filters.detelecine, - self.filters.detelecineCustomString.UTF8String); + const char *filter_str = hb_generate_filter_settings(filter_id, + self.filters.detelecine.UTF8String, + self.filters.detelecineCustomString.UTF8String); filter = hb_filter_init(filter_id); hb_add_filter(job, filter, filter_str); } - if (self.filters.useDecomb && self.filters.decomb) + if (self.filters.useDecomb && ![self.filters.decomb isEqualToString:@"off"]) { // Decomb int filter_id = HB_FILTER_DECOMB; - const char *filter_str = hb_generate_filter_settings_by_index(filter_id, - (int)self.filters.decomb, - self.filters.decombCustomString.UTF8String); + const char *filter_str = hb_generate_filter_settings(filter_id, + self.filters.decomb.UTF8String, + self.filters.decombCustomString.UTF8String); filter = hb_filter_init(filter_id); hb_add_filter(job, filter, filter_str); } - else if (!self.filters.useDecomb && self.filters.deinterlace) + else if (!self.filters.useDecomb && [self.filters.deinterlace isEqualToString:@"off"]) { // Deinterlace int filter_id = HB_FILTER_DEINTERLACE; - const char *filter_str = hb_generate_filter_settings_by_index(filter_id, - (int)self.filters.deinterlace, - self.filters.deinterlaceCustomString.UTF8String); + const char *filter_str = hb_generate_filter_settings(filter_id, + self.filters.deinterlace.UTF8String, + self.filters.deinterlaceCustomString.UTF8String); filter = hb_filter_init(filter_id); hb_add_filter(job, filter, filter_str); } diff --git a/macosx/HBJob.m b/macosx/HBJob.m index 6578c9710..921eb4304 100644 --- a/macosx/HBJob.m +++ b/macosx/HBJob.m @@ -61,14 +61,7 @@ NSString *HBChaptersChangedNotification = @"HBChaptersChangedNotification"; - (void)applyPreset:(HBPreset *)preset { - if (preset.isDefault) - { - self.presetName = [NSString stringWithFormat:@"%@ (Default)", preset.name]; - } - else - { - self.presetName = preset.name; - } + self.presetName = preset.name; NSDictionary *content = preset.content; @@ -87,7 +80,7 @@ NSString *HBChaptersChangedNotification = @"HBChaptersChangedNotification"; - (void)applyCurrentSettingsToPreset:(NSMutableDictionary *)dict { - dict[@"FileFormat"] = @(hb_container_get_name(self.container)); + dict[@"FileFormat"] = @(hb_container_get_short_name(self.container)); dict[@"ChapterMarkers"] = @(self.chaptersEnabled); // MP4 specifics options. dict[@"Mp4HttpOptimize"] = @(self.mp4HttpOptimize); diff --git a/macosx/HBPicture.h b/macosx/HBPicture.h index 9cace8fd9..cc0f3dfd8 100644 --- a/macosx/HBPicture.h +++ b/macosx/HBPicture.h @@ -21,7 +21,7 @@ extern NSString * const HBPictureChangedNotification; @property (nonatomic, readwrite) int width; @property (nonatomic, readwrite) int height; -@property (nonatomic, readwrite) int keepDisplayAspect; +@property (nonatomic, readwrite) BOOL keepDisplayAspect; @property (nonatomic, readwrite) int anamorphicMode; @property (nonatomic, readwrite) int modulus; diff --git a/macosx/HBPicture.m b/macosx/HBPicture.m index 8ebfb8477..9a0b7f931 100644 --- a/macosx/HBPicture.m +++ b/macosx/HBPicture.m @@ -305,7 +305,7 @@ NSString * const HBPictureChangedNotification = @"HBPictureChangedNotification"; } } -- (void)setKeepDisplayAspect:(int)keepDisplayAspect +- (void)setKeepDisplayAspect:(BOOL)keepDisplayAspect { _keepDisplayAspect = keepDisplayAspect; if (!self.isValidating) @@ -564,7 +564,25 @@ NSString * const HBPictureChangedNotification = @"HBPictureChangedNotification"; - (void)writeToPreset:(NSMutableDictionary *)preset { preset[@"PictureKeepRatio"] = @(self.keepDisplayAspect); - preset[@"PicturePAR"] = @(self.anamorphicMode); + + switch (self.anamorphicMode) { + case HB_ANAMORPHIC_NONE: + preset[@"PicturePAR"] = @"none"; + break; + case HB_ANAMORPHIC_LOOSE: + preset[@"PicturePAR"] = @"loose"; + break; + case HB_ANAMORPHIC_STRICT: + preset[@"PicturePAR"] = @"strict"; + break; + case HB_ANAMORPHIC_CUSTOM: + preset[@"PicturePAR"] = @"custom"; + break; + default: + preset[@"PicturePAR"] = @"loose"; + break; + } + preset[@"PictureModulus"] = @(self.modulus); // Set crop settings @@ -597,7 +615,7 @@ NSString * const HBPictureChangedNotification = @"HBPictureChangedNotification"; { // If Cropping is set to custom, then recall all four crop values from // when the preset was created and apply them - if ([preset[@"PictureAutoCrop"] intValue] == 0) + if ([preset[@"PictureAutoCrop"] intValue] == 0) { self.autocrop = NO; @@ -632,17 +650,33 @@ NSString * const HBPictureChangedNotification = @"HBPictureChangedNotification"; } // Assume max picture settings initially. - self.keepDisplayAspect = [preset[@"PictureKeepRatio"] intValue]; - self.anamorphicMode = [preset[@"PicturePAR"] intValue]; + self.keepDisplayAspect = [preset[@"PictureKeepRatio"] boolValue]; + + if ([preset[@"PicturePAR"] isEqualToString:@"none"]) + { + self.anamorphicMode = HB_ANAMORPHIC_NONE; + } + else if ([preset[@"PicturePAR"] isEqualToString:@"strict"]) + { + self.anamorphicMode = HB_ANAMORPHIC_STRICT; + } + else if ([preset[@"PicturePAR"] isEqualToString:@"custom"]) + { + self.anamorphicMode = HB_ANAMORPHIC_CUSTOM; + } + else + { + self.anamorphicMode = HB_ANAMORPHIC_LOOSE; + } + self.width = self.sourceWidth - self.cropLeft - self.cropRight; self.height = self.sourceHeight - self.cropTop - self.cropBottom; - // Check to see if the objectForKey:@"UsesPictureSettings" is 2, + // Check to see if the "UsesPictureSettings" is 2, // which means "Use max. picture size for source" // If not 2 it must be 1 here which means "Use the picture // size specified in the preset" - if ([preset[@"UsesPictureSettings"] intValue] != 2 && - [preset[@"UsesMaxPictureSettings"] intValue] != 1) + if ([preset[@"UsesPictureSettings"] intValue] != 2) { // if the preset specifies neither max. width nor height // (both are 0), use the max. picture size @@ -653,7 +687,7 @@ NSString * const HBPictureChangedNotification = @"HBPictureChangedNotification"; { jobMaxWidth = [preset[@"PictureWidth"] intValue]; } - if ([preset[@"PictureHeight"] intValue] > 0) + if ([preset[@"PictureHeight"] intValue] > 0) { jobMaxHeight = [preset[@"PictureHeight"] intValue]; } diff --git a/macosx/HBPreset.h b/macosx/HBPreset.h index a0a10e7f6..1b74bcd3a 100644 --- a/macosx/HBPreset.h +++ b/macosx/HBPreset.h @@ -4,9 +4,13 @@ Homepage: <http://handbrake.fr/>. It may be used under the terms of the GNU General Public License. */ -#import <Cocoa/Cocoa.h> +#import <Foundation/Foundation.h> #import "HBTreeNode.h" +typedef NS_ENUM(NSUInteger, HBPresetFormat) { + HBPresetFormatPlist, + HBPresetFormatJson, +}; /** * HBPreset * Stores a preset dictionary. @@ -15,14 +19,67 @@ */ @interface HBPreset : HBTreeNode <NSCopying> -- (instancetype)initWithName:(NSString *)title content:(NSDictionary *)content builtIn:(BOOL)builtIn; - (instancetype)initWithFolderName:(NSString *)title builtIn:(BOOL)builtIn; +- (instancetype)initWithName:(NSString *)title content:(NSDictionary *)content builtIn:(BOOL)builtIn; + +- (instancetype)initWithDictionary:(NSDictionary *)dict; + +/** + * Initializes a newly allocated preset object initialized with the data found at a given URL. + * + * @param url An URL that identifies a resource containing a string representation of a property list or json in the HandBrake preset format. + * + * @return An initialized preset—which might be different than the original receiver—that contains the preset at URL, + * or nil if there is an error or if the contents of the resource are not and HandBrake preset. + */ +- (instancetype)initWithContentsOfURL:(NSURL *)url; + +/** + * Writes a property list or json representation of the contents of the preset to a given URL. + * + * @param url The URL to which to write the preset. + * @param atomically A flag that specifies whether the output should be written atomically. + * @param format the format of the file to write. + * @param removeRoot whether the root preset should be written or not. + * + * @return YES if the location is written successfully, otherwise NO. + */ +- (BOOL)writeToURL:(NSURL *)url atomically:(BOOL)atomically format:(HBPresetFormat)format removeRoot:(BOOL)removeRoot; + +/** + * Removes unknown keys and normalizes values. + */ +- (void)cleanUp; + +/** + * The name of the preset. + */ @property (nonatomic, copy) NSString *name; + +/** + * A long textual description of the preset. + */ @property (nonatomic, copy) NSString *presetDescription; -@property (nonatomic, strong) NSDictionary *content; -@property (nonatomic) BOOL isDefault; +/** + * Whether the preset is one of the HandBrake built-in ones or not. + */ @property (nonatomic, readonly) BOOL isBuiltIn; +/** + * Whether the preset is the default one or not. Only one preset can be the default. + */ +@property (nonatomic) BOOL isDefault; + +/** + * The actual content of the preset. + */ +@property (nonatomic, strong) NSDictionary *content; + +/** + * A dictionary representation of the preset. + */ +@property (readonly, copy) NSDictionary *dictionary; + @end diff --git a/macosx/HBPreset.m b/macosx/HBPreset.m index 0ad0a8c86..314704205 100644 --- a/macosx/HBPreset.m +++ b/macosx/HBPreset.m @@ -5,9 +5,22 @@ It may be used under the terms of the GNU General Public License. */ #import "HBPreset.h" +#include "preset.h" @implementation HBPreset +- (instancetype)init +{ + self = [super init]; + if (self) + { + _name = @"New Preset"; + _presetDescription = @""; + self.isLeaf = YES; + } + return self; +} + - (instancetype)initWithName:(NSString *)title content:(NSDictionary *)content builtIn:(BOOL)builtIn; { self = [self init]; @@ -15,7 +28,7 @@ { _name = [title copy]; _isBuiltIn = builtIn; - _content = content; + _content = [content copy]; _presetDescription = [content[@"PresetDescription"] copy]; } return self; @@ -33,24 +46,157 @@ return self; } -- (instancetype)init +- (instancetype)initWithDictionary:(NSDictionary *)dict { - self = [super init]; - if (self) + NSParameterAssert(dict); + + if ([dict[@"Folder"] boolValue]) { - _name = @"New Preset"; - _presetDescription = @""; - self.isLeaf = YES; + self = [self initWithFolderName:dict[@"PresetName"] builtIn:![dict[@"Type"] boolValue]]; + + for (NSDictionary *childDict in [dict[@"ChildrenArray"] reverseObjectEnumerator]) + { + HBPreset *childPreset = [[HBPreset alloc] initWithDictionary:childDict]; + [self insertObject:childPreset inChildrenAtIndex:0]; + } } + else + { + self = [self initWithName:dict[@"PresetName"] + content:dict + builtIn:![dict[@"Type"] boolValue]]; + self.isDefault = [dict[@"Default"] boolValue]; + } + return self; } +- (instancetype)initWithContentsOfURL:(NSURL *)url +{ + NSArray *presetsArray; + NSString *presetsJson; + + if ([url.pathExtension isEqualToString:@"json"]) + { + NSData *data = [[NSData alloc] initWithContentsOfURL:url]; + presetsJson = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + } + else + { + NSArray *array = [[NSArray alloc] initWithContentsOfURL:url]; + if ([NSJSONSerialization isValidJSONObject:array]) + { + NSData *data = [NSJSONSerialization dataWithJSONObject:array options:0 error:NULL]; + presetsJson = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + } + } + + // Run the json through the libhb import function + // to avoid importing unknowns keys. + if (presetsJson.length) { + char *importedJson = hb_presets_import_json(presetsJson.UTF8String); + + if (importedJson) + { + NSData *modernizedData = [NSData dataWithBytes:importedJson length:strlen(importedJson)]; + id importedPresets = [NSJSONSerialization JSONObjectWithData:modernizedData options:0 error:NULL]; + + if ([importedPresets isKindOfClass:[NSDictionary class]]) + { + presetsArray = importedPresets[@"PresetList"]; + } + else if ([importedPresets isKindOfClass:[NSArray class]]) + { + presetsArray = importedPresets; + } + } + } + + if (presetsArray.count) + { + self = [self initWithFolderName:@"Imported Presets" builtIn:NO]; + + if (self) + { + for (NSDictionary *dict in presetsArray) + { + HBPreset *preset = [[HBPreset alloc] initWithDictionary:dict]; + [self.children addObject:preset]; + } + } + return self; + } + + return nil; +} + +- (NSDictionary *)dictionary +{ + NSMutableDictionary *output = [[NSMutableDictionary alloc] init]; + [output addEntriesFromDictionary:self.content]; + + output[@"PresetName"] = self.name; + output[@"PresetDescription"] = self.presetDescription; + output[@"Folder"] = [NSNumber numberWithBool:!self.isLeaf]; + output[@"Type"] = @(!self.isBuiltIn); + output[@"Default"] = @(self.isDefault); + + if (!self.isLeaf) + { + NSMutableArray *childArray = [[NSMutableArray alloc] init]; + for (HBPreset *child in self.children) + { + [childArray addObject:[child dictionary]]; + } + + output[@"ChildrenArray"] = childArray; + } + + return output; +} + +- (BOOL)writeToURL:(NSURL *)url atomically:(BOOL)atomically format:(HBPresetFormat)format removeRoot:(BOOL)removeRoot; +{ + BOOL success = NO; + NSArray *presetList; + + if (removeRoot) + { + presetList = self.dictionary[@"ChildrenArray"]; + } + else + { + presetList = @[self.dictionary]; + } + + int major, minor, micro; + hb_presets_current_version(&major, &minor, µ); + + NSDictionary *dict = @{ @"PresetList": presetList, + @"VersionMajor": @(major), + @"VersionMicro": @(minor), + @"VersionMinor": @(micro) }; + + if (format == HBPresetFormatPlist) + { + success = [dict writeToURL:url atomically:atomically]; + } + else + { + NSData *jsonPreset = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:NULL]; + success = [jsonPreset writeToURL:url atomically:atomically]; + } + + return success; +} + - (id)copyWithZone:(NSZone *)zone { HBPreset *node = [[self class] allocWithZone:zone]; node->_name = [self.name copy]; node->_content = [self.content copy]; node->_presetDescription = [self.presetDescription copy]; + for (HBPreset *children in self.children) { [node.children addObject:[children copy]]; @@ -64,11 +210,36 @@ return self.name.hash + self.isBuiltIn + self.isLeaf; } +- (void)cleanUp +{ + // Run the libhb clean function + NSData *presetData = [NSJSONSerialization dataWithJSONObject:self.dictionary options:0 error:NULL]; + NSString *presetJson = [[NSString alloc] initWithData:presetData encoding:NSUTF8StringEncoding]; + + if (presetJson.length) + { + char *cleanedJson = hb_presets_clean_json(presetJson.UTF8String); + + NSData *cleanedData = [NSData dataWithBytes:cleanedJson length:strlen(cleanedJson)]; + NSDictionary *cleanedDict = [NSJSONSerialization JSONObjectWithData:cleanedData options:0 error:NULL]; + + if ([cleanedDict isKindOfClass:[NSDictionary class]]) + { + self.content = cleanedDict; + } + } +} + - (void)setName:(NSString *)name { _name = [name copy]; + [self.delegate nodeDidChange:self]; +} - [self.delegate nodeDidChange]; +- (void)setIsDefault:(BOOL)isDefault +{ + _isDefault = isDefault; + [self.delegate nodeDidChange:self]; } #pragma mark - KVC diff --git a/macosx/HBPresetsManager.h b/macosx/HBPresetsManager.h index 453475152..4921768e9 100644 --- a/macosx/HBPresetsManager.h +++ b/macosx/HBPresetsManager.h @@ -39,13 +39,6 @@ extern NSString *HBPresetsChangedNotification; - (instancetype)initWithURL:(NSURL *)url; /** - * Checks the version number of the builtin presets. - * - * @return YES if the builtin presets are out of date. - */ -- (BOOL)checkBuiltInsForUpdates; - -/** * Saves the presets to disk. */ - (BOOL)savePresets; @@ -55,13 +48,6 @@ extern NSString *HBPresetsChangedNotification; * * @param preset the preset dict. */ -- (void)addPresetFromDictionary:(NSDictionary *)preset; - -/** - * Adds a given preset to the manager. - * - * @param preset the preset dict. - */ - (void)addPreset:(HBPreset *)preset; /** diff --git a/macosx/HBPresetsManager.m b/macosx/HBPresetsManager.m index 2420e5acb..29205e371 100644 --- a/macosx/HBPresetsManager.m +++ b/macosx/HBPresetsManager.m @@ -9,6 +9,8 @@ #import "HBUtilities.h" +#include "preset.h" + NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification"; @interface HBPresetsManager () <HBTreeNodeDelegate> @@ -42,183 +44,130 @@ NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification"; return self; } -- (NSIndexPath *)indexPathOfPreset:(HBPreset *)preset -{ - __block NSIndexPath *retValue = nil; - - // Visit the whole tree to find the index path. - [self.root enumerateObjectsUsingBlock:^(id obj, NSIndexPath *idx, BOOL *stop) - { - if ([obj isEqualTo:preset]) - { - retValue = idx; - *stop = YES; - } - }]; - - return retValue; -} - #pragma mark - HBTreeNode delegate -- (void)nodeDidChange +- (void)nodeDidChange:(id)node { [[NSNotificationCenter defaultCenter] postNotificationName:HBPresetsChangedNotification object:nil]; } -#pragma mark - Load/Save - -- (BOOL)loadPresetsFromURL:(NSURL *)url +- (void)treeDidRemoveNode:(id)node { - NSArray *presetsArray = [[NSArray alloc] initWithContentsOfURL:url]; - - for (NSDictionary *child in presetsArray) + if (node == self.defaultPreset) { - [self.root.children addObject:[self loadFromDict:child]]; + // Select a new default preset + [self selectNewDefault]; } +} - // If the preset list contains no leaf, - // add back the built in presets. - __block BOOL leafFound = NO; - [self.root enumerateObjectsUsingBlock:^(id obj, NSIndexPath *idx, BOOL *stop) { - if ([obj isLeaf]) - { - leafFound = YES; - *stop = YES; - } - }]; +#pragma mark - Load/Save - if (!leafFound) - { - [self generateBuiltInPresets]; - } +/** + * Loads the old presets format (0.10 and earlier) plist + * + * @param url the url of the plist + */ +- (void)loadOldPresetsFromURL:(NSURL *)url +{ + HBPreset *oldPresets = [[HBPreset alloc] initWithContentsOfURL:url]; - if (self.defaultPreset == nil) + for (HBPreset *preset in oldPresets.children) { - [self selectNewDefault]; + [self.root.children addObject:preset]; } - - return YES; } -- (BOOL)savePresetsToURL:(NSURL *)url +- (BOOL)checkIfOutOfDate:(NSDictionary *)dict { - NSMutableArray *presetsArray = [[NSMutableArray alloc] init]; + int major, minor, micro; + hb_presets_current_version(&major, &minor, µ); - for (HBPreset *node in self.root.children) + if (major != [dict[@"VersionMajor"] intValue] || + minor != [dict[@"VersionMinor"] intValue] || + micro != [dict[@"VersionMicro"] intValue]) { - [presetsArray addObject:[self convertToDict:node]]; + return YES; } - - return [presetsArray writeToURL:url atomically:YES]; - - return YES; + return NO; } -- (BOOL)savePresets +- (BOOL)loadPresetsFromURL:(NSURL *)url { - return [self savePresetsToURL:self.fileURL]; -} + NSData *presetData = [[NSData alloc] initWithContentsOfURL:url]; -#pragma mark - NSDictionary conversions - -/** - * Converts the NSDictionary to a HBPreset object, - */ -- (HBPreset *)loadFromDict:(NSDictionary *)dict -{ - HBPreset *node = nil; - if ([dict[@"Folder"] boolValue]) + // Try to load to load the old presets file + // if the new one is empty + if (presetData == nil) { - node = [[HBPreset alloc] initWithFolderName:dict[@"PresetName"] - builtIn:![dict[@"Type"] boolValue]]; - - for (NSDictionary *child in dict[@"ChildrenArray"]) - { - [node.children addObject:[self loadFromDict:child]]; - } + [self loadOldPresetsFromURL:[url.URLByDeletingPathExtension URLByAppendingPathExtension:@"plist"]]; + [self generateBuiltInPresets]; } else { - node = [[HBPreset alloc] initWithName:dict[@"PresetName"] - content:dict - builtIn:![dict[@"Type"] boolValue]]; - node.isDefault = [dict[@"Default"] boolValue]; + const char *json = [[NSString alloc] initWithData:presetData encoding:NSUTF8StringEncoding].UTF8String; + const char *cleanedJson = hb_presets_clean_json(json); + + NSData *cleanedData = [NSData dataWithBytes:cleanedJson length:strlen(cleanedJson)]; + NSDictionary *presetsDict = [NSJSONSerialization JSONObjectWithData:cleanedData options:0 error:NULL]; - if ([dict[@"Default"] boolValue]) + if ([self checkIfOutOfDate:presetsDict]) { - self.defaultPreset = node; + const char *updatedJson = hb_presets_import_json(cleanedJson); + NSData *updatedData = [NSData dataWithBytes:updatedJson length:strlen(cleanedJson)]; + presetsDict = [NSJSONSerialization JSONObjectWithData:updatedData options:0 error:NULL]; } - } - - node.delegate = self; - - return node; -} -/** - * Converts the HBPreset and its childrens to a NSDictionary. - */ -- (NSDictionary *)convertToDict:(HBPreset *)node -{ - NSMutableDictionary *output = [[NSMutableDictionary alloc] init]; - [output addEntriesFromDictionary:node.content]; - - output[@"PresetName"] = node.name; - output[@"Folder"] = @(!node.isLeaf); - output[@"Type"] = @(!node.isBuiltIn); - output[@"Default"] = @(node.isDefault); - - if (!node.isLeaf) - { - NSMutableArray *childArray = [[NSMutableArray alloc] init]; - for (HBPreset *child in node.children) + for (NSDictionary *child in presetsDict[@"PresetList"]) { - [childArray addObject:[self convertToDict:child]]; + [self.root.children addObject:[[HBPreset alloc] initWithDictionary:child]]; } - output[@"ChildrenArray"] = childArray; + if ([self checkIfOutOfDate:presetsDict]) + { + [self generateBuiltInPresets]; + } } - return output; -} - -#pragma mark - Presets Management - -- (BOOL)checkBuiltInsForUpdates -{ - __block BOOL retValue = NO; - + // If the preset list contains no leaf, + // add back the built in presets. + __block BOOL leafFound = NO; [self.root enumerateObjectsUsingBlock:^(id obj, NSIndexPath *idx, BOOL *stop) { - NSDictionary *dict = [obj content]; - - if ([obj isBuiltIn] && [obj isLeaf]) + if ([obj isLeaf]) { - if (!dict[@"PresetBuildNumber"] || - [dict[@"PresetBuildNumber"] intValue] < [[[NSBundle mainBundle] infoDictionary][@"CFBundleVersion"] intValue]) - { - retValue = YES; - *stop = YES; - } + leafFound = YES; + *stop = YES; } }]; - return retValue; + if (!leafFound) + { + [self generateBuiltInPresets]; + } + + [self selectNewDefault]; + + return YES; } -- (void)addPresetFromDictionary:(NSDictionary *)preset +- (BOOL)savePresetsToURL:(NSURL *)url { - HBPreset *presetNode = [[HBPreset alloc] initWithName:preset[@"PresetName"] - content:preset - builtIn:NO]; - - [self.root insertObject:presetNode inChildrenAtIndex:[self.root countOfChildren]]; + return [self.root writeToURL:url atomically:YES format:HBPresetFormatJson removeRoot:YES]; +} - [self savePresets]; +- (BOOL)savePresets +{ + return [self savePresetsToURL:self.fileURL]; } +#pragma mark - Presets Management + - (void)addPreset:(HBPreset *)preset { + // Make sure no preset has the default flag enabled. + [preset enumerateObjectsUsingBlock:^(id obj, NSIndexPath *idx, BOOL *stop) { + [obj setIsDefault:NO]; + }]; + [self.root insertObject:preset inChildrenAtIndex:[self.root countOfChildren]]; [self savePresets]; @@ -226,39 +175,16 @@ NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification"; - (void)deletePresetAtIndexPath:(NSIndexPath *)idx { - HBPreset *parentNode = self.root; - - // Find the preset parent array - // and delete it. - NSUInteger currIdx = 0; - NSUInteger i = 0; - for (i = 0; i < idx.length - 1; i++) - { - currIdx = [idx indexAtPosition:i]; - - if (parentNode.children.count > currIdx) - { - parentNode = (parentNode.children)[currIdx]; - } - } - - currIdx = [idx indexAtPosition:i]; + [self.root removeObjectAtIndexPath:idx]; +} - if (parentNode.children.count > currIdx) - { - if ([(parentNode.children)[currIdx] isDefault]) - { - [parentNode removeObjectFromChildrenAtIndex:currIdx]; - // Try to select a new default preset - [self selectNewDefault]; - } - else - { - [parentNode removeObjectFromChildrenAtIndex:currIdx]; - } - } +- (NSIndexPath *)indexPathOfPreset:(HBPreset *)preset +{ + return [self.root indexPathOfObject:preset]; } +#pragma mark - Default preset + /** * Private method to select a new default after the default preset is deleted * or when the built-in presets are regenerated. @@ -290,12 +216,15 @@ NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification"; *stop = YES; } - if ([obj isDefault]) { + if ([obj isDefault]) + { + self.defaultPreset = obj; defaultAlreadySetted = YES; } }]; - if (defaultAlreadySetted) { + if (defaultAlreadySetted) + { return; } else if (normalPreset) @@ -308,7 +237,8 @@ NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification"; self.defaultPreset = firstUserPreset; firstUserPreset.isDefault = YES; } - else if (firstBuiltInPreset) { + else if (firstBuiltInPreset) + { self.defaultPreset = firstBuiltInPreset; firstBuiltInPreset.isDefault = YES; } @@ -324,8 +254,6 @@ NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification"; } defaultPreset.isDefault = YES; _defaultPreset = defaultPreset; - - [self nodeDidChange]; } } @@ -333,39 +261,43 @@ NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification"; /** * Built-in preset folders at the root of the hierarchy -* + * * Note: the built-in presets will *not* sort themselves alphabetically, * so they will appear in the order you create them. */ - (void)generateBuiltInPresets { - [self deleteBuiltInPresets]; + // Load the built-in presets from libhb. + const char *presets = hb_presets_builtin_get_json(); + NSData *presetsData = [NSData dataWithBytes:presets length:strlen(presets)]; - // Load the built-in presets from the app bundle Resources folder. - NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"presets" withExtension:@"plist"]; - NSArray *presetsArray = [[NSArray alloc] initWithContentsOfURL:fileURL]; + NSError *error = nil; + NSArray *presetsArray = [NSJSONSerialization JSONObjectWithData:presetsData options:NSJSONReadingAllowFragments error:&error]; - for (NSDictionary *child in presetsArray.reverseObjectEnumerator) + if (presetsArray.count == 0) { - HBPreset *preset = [self loadFromDict:child]; + [HBUtilities writeToActivityLog:"failed to update built-in presets"]; - [preset enumerateObjectsUsingBlock:^(id obj, NSIndexPath *idx, BOOL *stop) + if (error) { - NSMutableDictionary *presetDict = [[obj content] mutableCopy]; - - // Set the current version in the built-in presets, to they won't be reupdated - // each time the app checks the version. - presetDict[@"PresetBuildNumber"] = [[NSBundle mainBundle] infoDictionary][@"CFBundleVersion"]; - [obj setContent:presetDict]; - }]; - - [self.root insertObject:preset inChildrenAtIndex:0]; + [HBUtilities writeToActivityLog:"Error raised:\n%s", error.localizedFailureReason]; + } } + else + { + [self deleteBuiltInPresets]; - // set a new Default preset - [self selectNewDefault]; + for (NSDictionary *child in presetsArray.reverseObjectEnumerator) + { + HBPreset *preset = [[HBPreset alloc] initWithDictionary:child]; + [self.root insertObject:preset inChildrenAtIndex:0]; + } + + // set a new Default preset + [self selectNewDefault]; - [HBUtilities writeToActivityLog: "built in presets updated to build number: %d", [[[NSBundle mainBundle] infoDictionary][@"CFBundleVersion"] intValue]]; + [HBUtilities writeToActivityLog: "built-in presets updated"]; + } } - (void)deleteBuiltInPresets diff --git a/macosx/HBPresetsViewController.m b/macosx/HBPresetsViewController.m index aab6e29f5..509ae9892 100644 --- a/macosx/HBPresetsViewController.m +++ b/macosx/HBPresetsViewController.m @@ -244,9 +244,9 @@ /** * draggingSourceOperationMaskForLocal <NSDraggingSource override> */ -- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal +- (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context { - return NSDragOperationMove; + return NSDragOperationMove; } /** @@ -330,7 +330,7 @@ // the KVC accessors method for the root node. if (indexPath.length == 1) { - [self.presets performSelector:@selector(nodeDidChange)]; + [self.presets performSelector:@selector(nodeDidChange:) withObject:nil]; } } diff --git a/macosx/HBTreeNode.h b/macosx/HBTreeNode.h index 0a8ade45b..52fa0aa37 100644 --- a/macosx/HBTreeNode.h +++ b/macosx/HBTreeNode.h @@ -13,7 +13,10 @@ */ @protocol HBTreeNodeDelegate <NSObject> -- (void)nodeDidChange; +- (void)nodeDidChange:(id)node; + +@optional +- (void)treeDidRemoveNode:(id)node; @end @@ -35,7 +38,24 @@ */ - (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSIndexPath *idx, BOOL *stop))block; +/** + * Returns the index path of an object in the tree. + * + * @param obj the object of the wanted NSIndexPath + * + * @return The index path whose corresponding value is equal to the preset. Returns nil if not found. + */ +- (NSIndexPath *)indexPathOfObject:(id)obj; + +/** + * Removes the object at the specified index path. + * + * @param idx the NSIndexPath of the object to delete. + */ +- (void)removeObjectAtIndexPath:(NSIndexPath *)idx; + // KVC Accessor Methods + @property (nonatomic, readonly) NSUInteger countOfChildren; - (id)objectInChildrenAtIndex:(NSUInteger)index; - (void)insertObject:(HBTreeNode *)presetObject inChildrenAtIndex:(NSUInteger)index; diff --git a/macosx/HBTreeNode.m b/macosx/HBTreeNode.m index 7b4a3bd76..786e9500b 100644 --- a/macosx/HBTreeNode.m +++ b/macosx/HBTreeNode.m @@ -33,13 +33,18 @@ [self.children insertObject:presetObject atIndex:index]; [presetObject setDelegate:self.delegate]; - [self.delegate nodeDidChange]; + for (HBTreeNode *node in self.children) + { + node.delegate = self.delegate; + } + + [self.delegate nodeDidChange:self]; } - (void)removeObjectFromChildrenAtIndex:(NSUInteger)index { [self.children removeObjectAtIndex:index]; - [self.delegate nodeDidChange]; + [self.delegate nodeDidChange:self]; } #pragma mark - Enumeration @@ -83,4 +88,54 @@ } } +- (NSIndexPath *)indexPathOfObject:(id)obj +{ + __block NSIndexPath *retValue = nil; + + // Visit the whole tree to find the index path. + [self enumerateObjectsUsingBlock:^(id obj2, NSIndexPath *idx, BOOL *stop) + { + if ([obj2 isEqualTo:obj]) + { + retValue = idx; + *stop = YES; + } + }]; + + return retValue; +} + +- (void)removeObjectAtIndexPath:(NSIndexPath *)idx +{ + HBTreeNode *parentNode = self; + + // Find the object parent array + // and delete it. + NSUInteger currIdx = 0; + NSUInteger i = 0; + for (i = 0; i < idx.length - 1; i++) + { + currIdx = [idx indexAtPosition:i]; + + if (parentNode.children.count > currIdx) + { + parentNode = (parentNode.children)[currIdx]; + } + } + + currIdx = [idx indexAtPosition:i]; + + if (parentNode.children.count > currIdx) + { + id removedNode = parentNode.children[currIdx]; + + [parentNode removeObjectFromChildrenAtIndex:currIdx]; + + if ([self.delegate respondsToSelector:@selector(treeDidRemoveNode:)]) + { + [self.delegate treeDidRemoveNode:removedNode]; + } + } +} + @end diff --git a/macosx/HBVideo.m b/macosx/HBVideo.m index 48cd9f4a3..490bb29be 100644 --- a/macosx/HBVideo.m +++ b/macosx/HBVideo.m @@ -509,9 +509,7 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification"; if (self.encoder == HB_VCODEC_X264 || self.encoder == HB_VCODEC_X265) { - if (self.encoder == HB_VCODEC_X264 && - (!preset[@"x264UseAdvancedOptions"] || - [preset[@"x264UseAdvancedOptions"] intValue])) + if (self.encoder == HB_VCODEC_X264 && [preset[@"x264UseAdvancedOptions"] boolValue]) { // preset does not use the x264 preset system, reset the widgets. self.preset = @"medium"; @@ -520,18 +518,8 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification"; self.level = @"auto"; self.fastDecode = NO; - // x264UseAdvancedOptions is not set (legacy preset) - // or set to 1 (enabled), so we use the old advanced panel. - if (preset[@"x264Option"]) - { - // we set the advanced options string here if applicable. - self.videoOptionExtra = preset[@"x264Option"]; - self.advancedOptions = YES; - } - else - { - self.videoOptionExtra = nil; - } + self.videoOptionExtra = preset[@"VideoOptionExtra"]; + self.advancedOptions = YES; } else { @@ -540,24 +528,11 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification"; // disable the advanced panel self.advancedOptions = NO; - if (preset[@"x264Preset"]) - { - // Read the old x264 preset keys - self.preset = preset[@"x264Preset"]; - self.tune = preset[@"x264Tune"]; - self.videoOptionExtra = preset[@"x264OptionExtra"]; - self.profile = preset[@"h264Profile"]; - self.level = preset[@"h264Level"]; - } - else - { - // Read the new preset keys (0.10) - self.preset = preset[@"VideoPreset"]; - self.tune = preset[@"VideoTune"]; - self.videoOptionExtra = preset[@"VideoOptionExtra"]; - self.profile = preset[@"VideoProfile"]; - self.level = preset[@"VideoLevel"]; - } + self.preset = preset[@"VideoPreset"]; + self.tune = preset[@"VideoTune"]; + self.videoOptionExtra = preset[@"VideoOptionExtra"]; + self.profile = preset[@"VideoProfile"]; + self.level = preset[@"VideoLevel"]; if ([self.tune rangeOfString:@"fastdecode"].location != NSNotFound) { @@ -573,15 +548,7 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification"; } else { - if (preset[@"lavcOption"]) - { - // Load the old format - self.videoOptionExtra = preset[@"lavcOption"]; - } - else - { - self.videoOptionExtra = preset[@"VideoOptionExtra"]; - } + self.videoOptionExtra = preset[@"VideoOptionExtra"]; } int qualityType = [preset[@"VideoQualityType"] intValue] - 1; @@ -600,7 +567,7 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification"; self.quality = [preset[@"VideoQualitySlider"] floatValue]; // Video framerate - if ([preset[@"VideoFramerate"] isEqualToString:@"Same as source"]) + if ([preset[@"VideoFramerate"] isEqualToString:@"auto"]) { // Now set the Video Frame Rate Mode to either vfr or cfr according to the preset. if (!preset[@"VideoFramerateMode"] || @@ -645,24 +612,26 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification"; - (void)writeToPreset:(NSMutableDictionary *)preset { - preset[@"VideoEncoder"] = @(hb_video_encoder_get_name(self.encoder)); + preset[@"VideoEncoder"] = @(hb_video_encoder_get_short_name(self.encoder)); - // x264 Options, this will either be advanced panel or the video tabs x264 presets panel with modded option string - if (self.advancedOptions) - { - // use the old advanced panel. - preset[@"x264UseAdvancedOptions"] = @1; - preset[@"x264Option"] = self.videoOptionExtra; - } - else if (self.encoder == HB_VCODEC_X264 || self.encoder == HB_VCODEC_X265) + if (self.encoder == HB_VCODEC_X264 || self.encoder == HB_VCODEC_X265) { - // use the new preset system. - preset[@"x264UseAdvancedOptions"] = @0; preset[@"VideoPreset"] = self.preset; preset[@"VideoTune"] = [self completeTune]; preset[@"VideoOptionExtra"] = self.videoOptionExtra; preset[@"VideoProfile"] = self.profile; preset[@"VideoLevel"] = self.level; + + // x264 Options, this will either be advanced panel or the video tabs x264 presets panel with modded option string + if (self.advancedOptions) + { + // use the old advanced panel. + preset[@"x264UseAdvancedOptions"] = @YES; + } + else + { + preset[@"x264UseAdvancedOptions"] = @NO; + } } else { @@ -684,7 +653,7 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification"; } if (self.frameRate == 0) // Same as source is selected { - preset[@"VideoFramerate"] = @"Same as source"; + preset[@"VideoFramerate"] = @"auto"; if (self.frameRateMode == 0) { diff --git a/macosx/HandBrake.xcodeproj/project.pbxproj b/macosx/HandBrake.xcodeproj/project.pbxproj index e595f4c30..19e786608 100644 --- a/macosx/HandBrake.xcodeproj/project.pbxproj +++ b/macosx/HandBrake.xcodeproj/project.pbxproj @@ -157,7 +157,6 @@ A9706CBA1AC1452800BAEAA8 /* ExceptionAlert.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9706CB81AC1452800BAEAA8 /* ExceptionAlert.xib */; }; A971281F1A2C75180088C076 /* HBTitle.m in Sources */ = {isa = PBXBuildFile; fileRef = A971281E1A2C75180088C076 /* HBTitle.m */; }; A975C08E1AE8C5270061870D /* HBStateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = A975C08D1AE8C5270061870D /* HBStateFormatter.m */; }; - A983494F1A9A64B80059CB94 /* presets.plist in Resources */ = {isa = PBXBuildFile; fileRef = A983494E1A9A64B80059CB94 /* presets.plist */; }; A98C29C41977B10600AF5DED /* HBLanguagesSelection.m in Sources */ = {isa = PBXBuildFile; fileRef = A98C29C31977B10600AF5DED /* HBLanguagesSelection.m */; }; A9906B2C1A710920001D82D5 /* HBQueueController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9906B2B1A710920001D82D5 /* HBQueueController.m */; }; A990D9071A64562200139032 /* HBJob+HBJobConversion.m in Sources */ = {isa = PBXBuildFile; fileRef = A990D9061A64562200139032 /* HBJob+HBJobConversion.m */; }; @@ -434,7 +433,6 @@ A971281E1A2C75180088C076 /* HBTitle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBTitle.m; sourceTree = "<group>"; }; A975C08C1AE8C5270061870D /* HBStateFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBStateFormatter.h; sourceTree = "<group>"; }; A975C08D1AE8C5270061870D /* HBStateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBStateFormatter.m; sourceTree = "<group>"; }; - A983494E1A9A64B80059CB94 /* presets.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = presets.plist; sourceTree = "<group>"; }; A98C29C21977B10600AF5DED /* HBLanguagesSelection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBLanguagesSelection.h; sourceTree = "<group>"; }; A98C29C31977B10600AF5DED /* HBLanguagesSelection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBLanguagesSelection.m; sourceTree = "<group>"; }; A9906B2B1A710920001D82D5 /* HBQueueController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBQueueController.m; sourceTree = "<group>"; }; @@ -733,7 +731,6 @@ 273F20CD14ADC8E60021BE6D /* Resources */ = { isa = PBXGroup; children = ( - A983494E1A9A64B80059CB94 /* presets.plist */, 3490BCB31614CF8D002A5AD7 /* HandBrake.icns */, 273F217914ADDDA10021BE6D /* English.lproj */, 273F212014ADCBF70021BE6D /* icons */, @@ -1262,7 +1259,6 @@ D2BCB12816F5154E0084604C /* stopencode.png in Resources */, A9252C041A17343500B8B7F8 /* [email protected] in Resources */, D2BCB12916F5154E0084604C /* [email protected] in Resources */, - A983494F1A9A64B80059CB94 /* presets.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1667,7 +1663,7 @@ "\"$(EXTERNAL_BUILD)/libhb\"", "\"$(EXTERNAL_BUILD)/contrib/lib\"", ); - MACOSX_DEPLOYMENT_TARGET = 10.6; + MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -1692,7 +1688,7 @@ "\"$(EXTERNAL_BUILD)/libhb\"", "\"$(EXTERNAL_BUILD)/contrib/lib\"", ); - MACOSX_DEPLOYMENT_TARGET = 10.6; + MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; |