diff options
author | ritsuka <[email protected]> | 2014-12-27 10:46:04 +0000 |
---|---|---|
committer | ritsuka <[email protected]> | 2014-12-27 10:46:04 +0000 |
commit | df8b2ff3e109699e3dadd88404911f8dfc7b210a (patch) | |
tree | 8489fee4edaf57adf55f69d0c0d28f61a5757057 /macosx | |
parent | 8df584534c0c39f5c2f298d8ba480cc906743bbf (diff) |
MacGui: change the queue to work with serialized HBJob objects, remove the NSDictionary job representation and the duplicate prepareJob method. Implement NSCopying protocol in HBJob.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@6655 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'macosx')
39 files changed, 1214 insertions, 2079 deletions
diff --git a/macosx/Controller.h b/macosx/Controller.h index cb7610f26..a2a92ba47 100644 --- a/macosx/Controller.h +++ b/macosx/Controller.h @@ -144,15 +144,12 @@ int fPendingCount; // Number of various kinds of job groups in fJobGroups. int fWorkingCount; - NSInteger fqueueEditRescanItemNum; // queue array item to be reloaded into the main window pid_t pidNum; // The pid number for this instance NSString * currentQueueEncodeNameString; /* integer to set to determine the previous state of encode 0==idle, 1==encoding, 2==cancelled*/ int fEncodeState; - BOOL applyQueueToScan; - NSString * browsedSourceDisplayName; /* Dock progress variables */ double dockIconProgress; @@ -164,7 +161,6 @@ - (IBAction) showSourceTitleScanPanel: (id) sender; - (IBAction) closeSourceTitleScanPanel: (id) sender; - (void) performScan:(NSString *) scanPath scanTitleNum: (NSInteger) scanTitleNum; -- (IBAction) showNewScan: (id) sender; - (void) enableUI: (BOOL) enable; @@ -174,7 +170,6 @@ - (IBAction) titlePopUpChanged: (id) sender; - (IBAction) chapterPopUpChanged: (id) sender; -- (IBAction) formatPopUpChanged: (id) sender; - (IBAction) autoSetM4vExtension: (id) sender; - (IBAction) browseFile: (id) sender; @@ -184,10 +179,6 @@ - (void)pictureSettingsDidChange; - (IBAction) openMainWindow: (id) sender; -/* Text summaries of various settings */ -- (NSString*) pictureSettingsSummary; -- (NSString*) muxerOptionsSummary; - /* Add All titles to the queue */ - (IBAction) addAllTitlesToQueue: (id) sender; - (void) addAllTitlesToQueueAlertDone: (NSWindow *) sheet @@ -199,15 +190,13 @@ - (void) closeQueueFSEvent; - (void) loadQueueFile; - (void) reloadQueue; -- (NSDictionary *)createQueueFileItem; - (void)saveQueueFileItem; - (void) incrementQueueItemDone:(NSInteger) queueItemDoneIndexNum; - (void) performNewQueueScan:(NSString *) scanPath scanTitleNum: (NSInteger) scanTitleNum; - (void) processNewQueueEncode; - (void) clearQueueEncodedItems; /* Queue Editing */ -- (IBAction)applyQueueSettingsToMainWindow:(id)sender; -- (IBAction)rescanQueueItemToMainWindow:(NSString *) scanPath scanTitleNum: (NSUInteger) scanTitleNum selectedQueueItem: (NSUInteger) selectedQueueItem; +- (IBAction)rescanQueueItemToMainWindow:(NSUInteger) selectedQueueItem; - (void) removeQueueFileItem:(NSUInteger) queueItemToRemove; @@ -227,7 +216,6 @@ - (IBAction) Rip: (id) sender; - (void) overWriteAlertDone: (NSWindow *) sheet returnCode: (int) returnCode contextInfo: (void *) contextInfo; -- (void) doRip; - (IBAction) Cancel: (id) sender; - (void) doCancelCurrentJob; @@ -244,9 +232,7 @@ - (IBAction) browseImportPresetFile: (id) sender; /* Manage User presets */ -- (IBAction) customSettingUsed: (id) sender; - (IBAction) showAddPresetPanel: (id) sender; - - (IBAction)selectDefaultPreset:(id)sender; - (IBAction)addFactoryPresets:(id)sender; diff --git a/macosx/Controller.m b/macosx/Controller.m index 17055ff64..9aa015781 100644 --- a/macosx/Controller.m +++ b/macosx/Controller.m @@ -7,7 +7,6 @@ #import "Controller.h" #import "HBOutputPanelController.h" #import "HBPreferencesController.h" -#import "HBDVDDetector.h" #import "HBPresetsManager.h" #import "HBPreset.h" #import "HBPreviewController.h" @@ -18,9 +17,7 @@ #import "HBAddPresetController.h" #import "HBPicture+UIAdditions.h" - -#import "HBAudioDefaults.h" -#import "HBSubtitlesDefaults.h" +#import "HBFilters+UIAdditions.h" #import "HBCore.h" #import "HBJob.h" @@ -30,9 +27,14 @@ @interface HBController () <HBPresetsViewControllerDelegate, HBPreviewControllerDelegate> +@property (nonatomic, copy) NSString *browsedSourceDisplayName; + // The current job. @property (nonatomic, retain) HBJob *job; +// The job to be applied from the queue. +@property (nonatomic, retain) HBJob *jobFromQueue; + // The current selected preset. @property (nonatomic, retain) HBPreset *selectedPreset; @property (nonatomic) BOOL customPreset; @@ -124,13 +126,13 @@ [fPreviewController setCore:self.core]; - [fQueueController setHandle:self.queueCore.hb_handle]; + [fQueueController setCore:self.queueCore]; [fQueueController setHBController:self]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(autoSetM4vExtension:) name:HBMixdownChangedNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pictureSettingsDidChange) name:HBPictureChangedNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pictureSettingsDidChange) name:HBFiltersChangedNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(formatPopUpChanged:) name:HBContainerChangedNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(formatChanged:) name:HBContainerChangedNotification object:nil]; } return self; @@ -296,13 +298,28 @@ { if (self.core.state != HBStateScanning) { - [browsedSourceDisplayName release]; - browsedSourceDisplayName = [filePath.lastPathComponent retain]; - + self.browsedSourceDisplayName = filePath.lastPathComponent; [self performScan:filePath scanTitleNum:0]; } } +- (void)setJob:(HBJob *)job +{ + // Set the jobs info to the view controllers + fPictureController.picture = job.picture; + fPictureController.filters = job.filters; + fPreviewController.job = job; + + fVideoController.video = job.video; + fAudioController.job = job; + fSubtitlesViewController.job = job; + fChapterTitlesController.job = job; + + // Retain the new job + [_job autorelease]; + _job = [job retain]; +} + #pragma mark - #pragma mark Multiple Instances @@ -468,7 +485,6 @@ [self closeQueueFSEvent]; [currentQueueEncodeNameString release]; - [browsedSourceDisplayName release]; [outputPanel release]; [fQueueController release]; [fPreviewController release]; @@ -479,6 +495,7 @@ self.core = nil; self.queueCore = nil; + self.browsedSourceDisplayName = nil; [HBCore closeGlobal]; } @@ -563,13 +580,6 @@ keyEquivalent:@""]; [menuItem setTag:container->format]; } - // select the first container - [fDstFormatPopUp selectItemAtIndex:0]; - [self formatPopUpChanged:nil]; - - [fDstFile2Field setStringValue:[NSString - stringWithFormat:@"%@/Desktop/Movie.mp4", - NSHomeDirectory()]]; /* Bottom */ [fStatusField setStringValue: @""]; @@ -711,7 +721,7 @@ fScanIndicator.doubleValue = 0.0; [HBUtilities writeToActivityLog:"ScanDone state received from fHandle"]; - [self showNewScan:nil]; + [self showNewScan]; [[fWindow toolbar] validateVisibleItems]; }]; } @@ -794,8 +804,9 @@ NSString *pass_desc; if (p.job_cur == 1 && p.job_count > 1) { - if (QueueFileArray[currentQueueEncodeIndex][@"SubtitleList"] && - [[QueueFileArray[currentQueueEncodeIndex][@"SubtitleList"] firstObject][keySubTrackIndex] intValue] == -1) + HBJob *queueJob = QueueFileArray[currentQueueEncodeIndex]; + if (queueJob.subtitlesTracks.count && + [[queueJob.subtitlesTracks firstObject][keySubTrackIndex] intValue] == -1) { pass_desc = NSLocalizedString(@"(subtitle scan)", @""); } @@ -940,7 +951,8 @@ { NSString *pathOfFinishedEncode; // Get the output file name for the finished encode - pathOfFinishedEncode = [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"DestinationPath"]; + HBJob *finishedJob = QueueFileArray[currentQueueEncodeIndex]; + pathOfFinishedEncode = finishedJob.destURL.path; // Both the Growl Alert and Sending to tagger can be done as encodes roll off the queue if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Growl Notification"] || @@ -1057,7 +1069,7 @@ if (action == @selector(Rip:)) { [toolbarItem setImage: [NSImage imageNamed: @"encode"]]; - if (hb_count(self.core.hb_handle) > 0) + if (QueueFileArray.count > 0) [toolbarItem setLabel: @"Start Queue"]; else [toolbarItem setLabel: @"Start"]; @@ -1284,9 +1296,6 @@ { if (result == NSOKButton) { - // Free display name allocated previously by this code - [browsedSourceDisplayName release]; - NSURL *scanURL = panel.URL; // we set the last searched source directory in the prefs here [[NSUserDefaults standardUserDefaults] setURL:scanURL.URLByDeletingLastPathComponent forKey:@"LastSourceDirectoryURL"]; @@ -1320,7 +1329,7 @@ // we set the source display name in the title selection dialogue [fSrcDsplyNameTitleScan setStringValue:displayTitlescanSourceName]; // we set the attempted scans display name for main window to displayTitlescanSourceName - browsedSourceDisplayName = [displayTitlescanSourceName retain]; + self.browsedSourceDisplayName = displayTitlescanSourceName; // We show the actual sheet where the user specifies the title to be scanned // as we are going to do a title specific scan @@ -1340,7 +1349,7 @@ { [HBUtilities writeToActivityLog:"trying to open eyetv package"]; // We're looking at an EyeTV package - try to open its enclosed .mpg media file - browsedSourceDisplayName = [url.URLByDeletingPathExtension.lastPathComponent retain]; + self.browsedSourceDisplayName = url.URLByDeletingPathExtension.lastPathComponent; NSString *mpgname; NSUInteger n = [[[url path] stringByAppendingString: @"/"] completePathIntoString: &mpgname caseSensitive: YES @@ -1363,14 +1372,14 @@ else if ([[url pathExtension] isEqualToString: @"dvdmedia"]) { /* path IS a package - but dvdmedia packages can be treaded like normal directories */ - browsedSourceDisplayName = [[[url URLByDeletingPathExtension] lastPathComponent] retain]; + self.browsedSourceDisplayName = url.URLByDeletingPathExtension.lastPathComponent; [HBUtilities writeToActivityLog:"trying to open dvdmedia package"]; [self performScan:[url path] scanTitleNum:0]; } else { /* The package is not an eyetv package, try to open it anyway */ - browsedSourceDisplayName = [[url lastPathComponent] retain]; + self.browsedSourceDisplayName = url.lastPathComponent; [HBUtilities writeToActivityLog:"not a known to package"]; [self performScan:[url path] scanTitleNum:0]; } @@ -1382,16 +1391,15 @@ { [HBUtilities writeToActivityLog:"trying to open video_ts folder (video_ts folder chosen)"]; /* If VIDEO_TS Folder is chosen, choose its parent folder for the source display name*/ - browsedSourceDisplayName = [[[url URLByDeletingLastPathComponent] lastPathComponent] retain]; + self.browsedSourceDisplayName = url.URLByDeletingLastPathComponent.lastPathComponent; } else { [HBUtilities writeToActivityLog:"trying to open video_ts folder (parent directory chosen)"]; /* if not the VIDEO_TS Folder, we can assume the chosen folder is the source name */ /* make sure we remove any path extension as this can also be an '.mpg' file */ - browsedSourceDisplayName = [[url lastPathComponent] retain]; + self.browsedSourceDisplayName = url.lastPathComponent; } - applyQueueToScan = NO; [self performScan:[url path] scanTitleNum:0]; } } @@ -1417,17 +1425,15 @@ if(sender == fScanSrcTitleOpenButton) { - /* We setup the scan status in the main window to indicate a source title scan */ + // We setup the scan status in the main window to indicate a source title scan [fSrcDVD2Field setStringValue: @"Opening a new source titleā¦"]; [fScanIndicator setHidden: NO]; [fScanHorizontalLine setHidden: YES]; [fScanIndicator setIndeterminate: YES]; [fScanIndicator startAnimation: nil]; - /* We use the performScan method to actually perform the specified scan passing the path and the title - * to be scanned - */ - applyQueueToScan = NO; + // We use the performScan method to actually perform the specified scan passing the path and the title + // to be scanned [self performScan:[fScanSrcTitlePathField stringValue] scanTitleNum:[fScanSrcTitleNumField intValue]]; } } @@ -1436,23 +1442,13 @@ - (void)performScan:(NSString *)scanPath scanTitleNum:(NSInteger)scanTitleNum { // Save the current settings - if (self.job) { + if (self.job) + { self.selectedPreset = [self createPresetFromCurrentSettings]; } - // Notify anyone interested (audio/subtitles/chapters controller) that there's no title - fPictureController.picture = nil; - fPictureController.filters = nil; - fPreviewController.job = nil; - - fAudioController.job = nil; - fSubtitlesViewController.job = nil; - fVideoController.video = nil; - fChapterTitlesController.job = nil; - self.job = nil; - - [self enableUI: NO]; + [self enableUI:NO]; NSError *outError = NULL; NSURL *fileURL = [NSURL fileURLWithPath:scanPath]; @@ -1510,16 +1506,16 @@ } } -- (IBAction) showNewScan:(id)sender +- (void)showNewScan { if (!self.core.titles.count) { // We display a message if a valid source was not chosen - [fSrcDVD2Field setStringValue: @"No Valid Source Found"]; + fSrcDVD2Field.stringValue = @"No Valid Source Found"; } else { - if (applyQueueToScan == YES) + if (self.jobFromQueue) { // we are a rescan of an existing queue item and need to apply the queued settings to the scan [HBUtilities writeToActivityLog: "showNewScan: This is a queued item rescan"]; @@ -1534,39 +1530,11 @@ for (HBTitle *title in self.core.titles) { // Set Source Name at top of window with the browsedSourceDisplayName grokked right before -performScan - if (!browsedSourceDisplayName) + if (!self.browsedSourceDisplayName) { - browsedSourceDisplayName = @"NoNameDetected"; - } - [fSrcDVD2Field setStringValue:browsedSourceDisplayName]; - - // use the correct extension based on the container - int videoContainer = (int)[[fDstFormatPopUp selectedItem] tag]; - const char *ext = hb_container_get_default_extension(videoContainer); - - // If its a queue rescan for edit, get the queue item output path - // if not, its a new source scan. - // Check to see if the last destination has been set,use if so, if not, use Desktop - if (applyQueueToScan == YES) - { - [fDstFile2Field setStringValue: [NSString stringWithFormat:@"%@", QueueFileArray[fqueueEditRescanItemNum][@"DestinationPath"]]]; - } - else if ([[NSUserDefaults standardUserDefaults] stringForKey:@"LastDestinationDirectory"]) - { - [fDstFile2Field setStringValue: [NSString stringWithFormat: - @"%@/%@.%s", [[NSUserDefaults standardUserDefaults] stringForKey:@"LastDestinationDirectory"],[browsedSourceDisplayName stringByDeletingPathExtension],ext]]; - } - else - { - [fDstFile2Field setStringValue: [NSString stringWithFormat: - @"%@/Desktop/%@.%s", NSHomeDirectory(),[browsedSourceDisplayName stringByDeletingPathExtension],ext]]; - } - - // set m4v extension if necessary - do not override user-specified .mp4 extension - if ((videoContainer & HB_MUX_MASK_MP4) && (applyQueueToScan != YES)) - { - [self autoSetM4vExtension:sender]; + self.browsedSourceDisplayName = @"NoNameDetected"; } + fSrcDVD2Field.stringValue = self.browsedSourceDisplayName; [fSrcTitlePopUp addItemWithTitle:title.description]; @@ -1577,7 +1545,7 @@ } } - // Select the first item is nothing i selected + // Select the first item is nothing is selected if (!fSrcTitlePopUp.selectedItem) { [fSrcTitlePopUp selectItemAtIndex:0]; @@ -1587,8 +1555,6 @@ [self enableUI:YES]; [self titlePopUpChanged:nil]; - [self encodeStartStopPopUpChanged:nil]; - // Open preview window now if it was visible when HB was closed if ([[NSUserDefaults standardUserDefaults] boolForKey:@"PreviewWindowIsOpen"]) [self showPreviewWindow:nil]; @@ -1597,11 +1563,12 @@ if ([[NSUserDefaults standardUserDefaults] boolForKey:@"PictureSizeWindowIsOpen"]) [self showPicturePanel:nil]; - if (applyQueueToScan == YES) + if (self.jobFromQueue) { - // we are a rescan of an existing queue item and need to apply the queued settings to the scan - [HBUtilities writeToActivityLog: "showNewScan: calling applyQueueSettingsToMainWindow"]; - [self applyQueueSettingsToMainWindow:nil]; + [fPresetsView deselect]; + [self pictureSettingsDidChange]; + + self.jobFromQueue = nil; } } } @@ -1612,20 +1579,19 @@ - (IBAction)browseFile:(id)sender { // Open a panel to let the user choose and update the text field - NSSavePanel * panel = [NSSavePanel savePanel]; + NSSavePanel *panel = [NSSavePanel savePanel]; // We get the current file name and path from the destination field here - NSString *destinationDirectory = fDstFile2Field.stringValue.stringByDeletingLastPathComponent; - [panel setDirectoryURL:[NSURL fileURLWithPath:destinationDirectory]]; - [panel setNameFieldStringValue:[[fDstFile2Field stringValue] lastPathComponent]]; + [panel setDirectoryURL:self.job.destURL.URLByDeletingLastPathComponent]; + [panel setNameFieldStringValue:self.job.destURL.lastPathComponent]; [panel beginSheetModalForWindow:fWindow completionHandler:^(NSInteger result) { if (result == NSFileHandlingPanelOKButton) { - fDstFile2Field.stringValue = panel.URL.path; + self.job.destURL = panel.URL; // Save this path to the prefs so that on next browse destination window it opens there - NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent]; + NSString *destinationDirectory = [panel.URL.path stringByDeletingLastPathComponent]; [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"]; } }]; @@ -1663,8 +1629,16 @@ static void queueFSEventStreamCallback( const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) { - HBController *hb = (HBController *)clientCallBackInfo; - [hb reloadQueue]; + if (numEvents >= 1) + { + // Reload the queue only if one of the following events happened. + FSEventStreamEventFlags flags = eventFlags[0]; + if (flags & (kFSEventStreamEventFlagItemCreated | kFSEventStreamEventFlagItemRemoved | kFSEventStreamEventFlagItemRenamed | kFSEventStreamEventFlagItemModified)) + { + HBController *hb = (HBController *)clientCallBackInfo; + [hb reloadQueue]; + } + } } - (void)initQueueFSEvent @@ -1691,7 +1665,7 @@ static void queueFSEventStreamCallback( pathsToWatch, kFSEventStreamEventIdSinceNow, latency, - kFSEventStreamCreateFlagIgnoreSelf + kFSEventStreamCreateFlagIgnoreSelf | kFSEventStreamCreateFlagMarkSelf ); CFRelease(pathsToWatch); @@ -1710,35 +1684,42 @@ static void queueFSEventStreamCallback( - (void)loadQueueFile { - /* We declare the default NSFileManager into fileManager */ + // We declare the default NSFileManager into fileManager NSFileManager *fileManager = [NSFileManager defaultManager]; NSString *appSupportPath = [HBUtilities appSupportPath]; - /* We define the location of the user presets file */ - QueueFile = [[appSupportPath stringByAppendingPathComponent:@"Queue/Queue.plist"] retain]; + // We define the location of the user presets file + QueueFile = [[appSupportPath stringByAppendingPathComponent:@"Queue/Queue.hbqueue"] retain]; - /* We check for the Queue.plist */ - if( ![fileManager fileExistsAtPath:QueueFile] ) + // We check for the Queue.plist + if (![fileManager fileExistsAtPath:QueueFile]) { - if( ![fileManager fileExistsAtPath:[appSupportPath stringByAppendingPathComponent:@"Queue"]] ) + if (![fileManager fileExistsAtPath:[appSupportPath stringByAppendingPathComponent:@"Queue"]]) { [fileManager createDirectoryAtPath:[appSupportPath stringByAppendingPathComponent:@"Queue"] withIntermediateDirectories:YES attributes:nil error:NULL]; } - [fileManager createFileAtPath:QueueFile contents:nil attributes:nil]; } - QueueFileArray = [[NSMutableArray alloc] initWithContentsOfFile:QueueFile]; - /* lets check to see if there is anything in the queue file .plist */ - if( QueueFileArray == nil ) + @try + { + QueueFileArray = [[NSKeyedUnarchiver unarchiveObjectWithFile:QueueFile] retain]; + } + @catch (NSException *exception) + { + [HBUtilities writeToActivityLog:"failed to read the queue to disk"]; + } + + // lets check to see if there is anything in the queue file .plist + if (QueueFileArray == nil) { - /* if not, then lets initialize an empty array */ + // if not, then lets initialize an empty array QueueFileArray = [[NSMutableArray alloc] init]; } else { - /* ONLY clear out encoded items if we are single instance */ - if( hbInstanceNum == 1 ) + // ONLY clear out encoded items if we are single instance + if (hbInstanceNum == 1) { [self clearQueueEncodedItems]; } @@ -1749,31 +1730,41 @@ static void queueFSEventStreamCallback( { [HBUtilities writeToActivityLog:"Queue reloaded"]; - NSMutableArray * tempQueueArray = [[NSMutableArray alloc] initWithContentsOfFile:QueueFile]; + NSMutableArray *tempQueueArray = nil;; + @try + { + tempQueueArray = [NSKeyedUnarchiver unarchiveObjectWithFile:QueueFile]; + } + @catch (NSException *exception) + { + tempQueueArray = nil; + [HBUtilities writeToActivityLog:"failed to read the queue to disk"]; + } + [QueueFileArray setArray:tempQueueArray]; - [tempQueueArray release]; - /* Send Fresh QueueFileArray to fQueueController to update queue window */ - [fQueueController setQueueArray: QueueFileArray]; + // Send Fresh QueueFileArray to fQueueController to update queue window + [fQueueController setQueueArray:QueueFileArray]; [self getQueueStats]; } - (void)addQueueFileItem { - [QueueFileArray addObject:[self createQueueFileItem]]; + [QueueFileArray addObject:[[self.job copy] autorelease]]; [self saveQueueFileItem]; - } -- (void) removeQueueFileItem:(NSUInteger) queueItemToRemove +- (void)removeQueueFileItem:(NSUInteger)queueItemToRemove { [QueueFileArray removeObjectAtIndex:queueItemToRemove]; [self saveQueueFileItem]; - } - (void)saveQueueFileItem { - [QueueFileArray writeToFile:QueueFile atomically:YES]; + if (![NSKeyedArchiver archiveRootObject:QueueFileArray toFile:QueueFile]) + { + [HBUtilities writeToActivityLog:"failed to write the queue to disk"]; + } [fQueueController setQueueArray: QueueFileArray]; [self getQueueStats]; } @@ -1783,39 +1774,30 @@ static void queueFSEventStreamCallback( */ - (void)getQueueStats { - /* lets get the stats on the status of the queue array */ - + // lets get the stats on the status of the queue array fPendingCount = 0; fWorkingCount = 0; - /* We use a number system to set the encode status of the queue item - * in controller.mm - * 0 == already encoded - * 1 == is being encoded - * 2 == is yet to be encoded - * 3 == cancelled - */ - int i = 0; - for (NSDictionary *thisQueueDict in QueueFileArray) + for (HBJob *job in QueueFileArray) { - if ([[thisQueueDict objectForKey:@"Status"] intValue] == 1) // being encoded + if (job.state == HBJobStateWorking) // being encoded { fWorkingCount++; - /* check to see if we are the instance doing this encoding */ - if ([thisQueueDict objectForKey:@"EncodingPID"] && [[thisQueueDict objectForKey:@"EncodingPID"] intValue] == pidNum) + // check to see if we are the instance doing this encoding + if (job.pidId == pidNum) { currentQueueEncodeIndex = i; } } - if ([[thisQueueDict objectForKey:@"Status"] intValue] == 2) // pending + if (job.state == HBJobStateReady) // pending { fPendingCount++; } i++; } - /* Set the queue status field in the main window */ + // Set the queue status field in the main window NSString *string; if (fPendingCount == 0) { @@ -1833,63 +1815,58 @@ static void queueFSEventStreamCallback( [fQueueStatus setStringValue:string]; } -/* Used to get the next pending queue item index and return it if found */ +/** + * Used to get the next pending queue item index and return it if found + */ - (NSInteger)getNextPendingQueueIndex { - /* initialize nextPendingIndex to -1, this value tells incrementQueueItemDone that there are no pending items in the queue */ + // initialize nextPendingIndex to -1, this value tells incrementQueueItemDone that there are no pending items in the queue NSInteger nextPendingIndex = -1; BOOL nextPendingFound = NO; - for (id tempObject in QueueFileArray) + for (HBJob *job in QueueFileArray) { - NSDictionary *thisQueueDict = tempObject; - if ([[thisQueueDict objectForKey:@"Status"] intValue] == 2 && nextPendingFound == NO) // pending + if (job.state == HBJobStateReady && nextPendingFound == NO) // pending { nextPendingFound = YES; - nextPendingIndex = [QueueFileArray indexOfObject: tempObject]; + nextPendingIndex = [QueueFileArray indexOfObject:job]; [HBUtilities writeToActivityLog: "getNextPendingQueueIndex next pending encode index is:%d", nextPendingIndex]; } } return nextPendingIndex; } -/* This method will set any item marked as encoding back to pending +/** + * This method will set any item marked as encoding back to pending * currently used right after a queue reload */ - (void) setQueueEncodingItemsAsPending { - NSMutableArray *tempArray; - tempArray = [NSMutableArray array]; - /* we look here to see if the preset is we move on to the next one */ - for (id tempObject in QueueFileArray) + for (HBJob *job in QueueFileArray) { - /* We want to keep any queue item that is pending or was previously being encoded */ - if ([[tempObject objectForKey:@"Status"] intValue] == 1 || [[tempObject objectForKey:@"Status"] intValue] == 2) + // We want to keep any queue item that is pending or was previously being encoded + if (job.state == HBJobStateWorking || job.state == HBJobStateReady) { - /* If the queue item is marked as "encoding" (1) - * then change its status back to pending (2) which effectively - * puts it back into the queue to be encoded - */ - if ([[tempObject objectForKey:@"Status"] intValue] == 1) + // If the queue item is marked as "working" + // then change its status back to ready which effectively + // puts it back into the queue to be encoded + if (job.state == HBJobStateWorking) { - [tempObject setObject:[NSNumber numberWithInt: 2] forKey:@"Status"]; + job.state = HBJobStateReady; } - [tempArray addObject:tempObject]; } } - - [QueueFileArray setArray:tempArray]; + [self saveQueueFileItem]; } - -/* This method will clear the queue of any encodes that are not still pending - * this includes both successfully completed encodes as well as cancelled encodes */ +/** + * This method will clear the queue of any encodes that are not still pending + * this includes both successfully completed encodes as well as cancelled encodes + */ - (void) clearQueueEncodedItems { - NSMutableArray *tempArray; - tempArray = [NSMutableArray array]; - /* we look here to see if the preset is we move on to the next one */ - for (id tempObject in QueueFileArray) + NSMutableArray *tempArray = [NSMutableArray array]; + for (HBJob *job in QueueFileArray) { /* If the queue item is either completed (0) or cancelled (3) from the * last session, then we put it in tempArray to be deleted from QueueFileArray. @@ -1898,9 +1875,9 @@ static void queueFSEventStreamCallback( * from a previous session, we can conlude that HB was either shutdown, or crashed * during the encodes so we keep it and tell the user in the "Load Queue Alert" */ - if ([[tempObject objectForKey:@"Status"] intValue] == 0 || [[tempObject objectForKey:@"Status"] intValue] == 3) + if (job.state == HBJobStateCompleted || job.state == HBJobStateCanceled) { - [tempArray addObject:tempObject]; + [tempArray addObject:job]; } } @@ -1908,178 +1885,30 @@ static void queueFSEventStreamCallback( [self saveQueueFileItem]; } -/* This method will clear the queue of all encodes. effectively creating an empty queue */ +/** + * This method will clear the queue of all encodes. effectively creating an empty queue + */ - (void) clearQueueAllItems { - NSMutableArray *tempArray; - tempArray = [NSMutableArray array]; - /* we look here to see if the preset is we move on to the next one */ - for (id tempObject in QueueFileArray) + NSMutableArray *tempArray = [NSMutableArray array]; + // we look here to see if the preset is we move on to the next one + for (HBJob *job in QueueFileArray) { - [tempArray addObject:tempObject]; + [tempArray addObject:job]; } [QueueFileArray removeObjectsInArray:tempArray]; [self saveQueueFileItem]; } -/* This method will duplicate prepareJob however into the - * queue .plist instead of into the job structure so it can - * be recalled later */ -- (NSDictionary *)createQueueFileItem -{ - NSMutableDictionary *queueFileJob = [[NSMutableDictionary alloc] init]; - - hb_title_t *title = self.job.title.hb_title; - - /* We use a number system to set the encode status of the queue item - * 0 == already encoded - * 1 == is being encoded - * 2 == is yet to be encoded - * 3 == cancelled - */ - [queueFileJob setObject:[NSNumber numberWithInt:2] forKey:@"Status"]; - /* Source and Destination Information */ - - [queueFileJob setObject:[NSString stringWithUTF8String: title->path] forKey:@"SourcePath"]; - [queueFileJob setObject:[[fSrcDVD2Field stringValue] lastPathComponent] forKey:@"SourceName"]; - [queueFileJob setObject:[NSNumber numberWithInt:title->index] forKey:@"TitleNumber"]; - [queueFileJob setObject:[NSNumber numberWithInteger:[fSrcAnglePopUp indexOfSelectedItem] + 1] forKey:@"TitleAngle"]; - - /* Determine and set a variable to tell hb what start and stop times to use (chapters, seconds or frames) */ - if( [fEncodeStartStopPopUp indexOfSelectedItem] == 0 ) - { - [queueFileJob setObject:[NSNumber numberWithInt:0] forKey:@"fEncodeStartStop"]; - } - else if ([fEncodeStartStopPopUp indexOfSelectedItem] == 1) - { - [queueFileJob setObject:[NSNumber numberWithInt:1] forKey:@"fEncodeStartStop"]; - } - else if ([fEncodeStartStopPopUp indexOfSelectedItem] == 2) - { - [queueFileJob setObject:[NSNumber numberWithInt:2] forKey:@"fEncodeStartStop"]; - } - /* Chapter encode info */ - [queueFileJob setObject:[NSNumber numberWithInteger:[fSrcChapterStartPopUp indexOfSelectedItem] + 1] forKey:@"ChapterStart"]; - [queueFileJob setObject:[NSNumber numberWithInteger:[fSrcChapterEndPopUp indexOfSelectedItem] + 1] forKey:@"ChapterEnd"]; - /* Time (pts) encode info */ - [queueFileJob setObject:[NSNumber numberWithInt:[fSrcTimeStartEncodingField intValue]] forKey:@"StartSeconds"]; - [queueFileJob setObject:[NSNumber numberWithInt:[fSrcTimeEndEncodingField intValue] - [fSrcTimeStartEncodingField intValue]] forKey:@"StopSeconds"]; - /* Frame number encode info */ - [queueFileJob setObject:[NSNumber numberWithInt:[fSrcFrameStartEncodingField intValue]] forKey:@"StartFrame"]; - [queueFileJob setObject:[NSNumber numberWithInt:[fSrcFrameEndEncodingField intValue] - [fSrcFrameStartEncodingField intValue]] forKey:@"StopFrame"]; - - - /* The number of seek points equals the number of seconds announced in the title as that is our current granularity */ - int title_duration_seconds = (title->hours * 3600) + (title->minutes * 60) + (title->seconds); - [queueFileJob setObject:[NSNumber numberWithInt:title_duration_seconds] forKey:@"SourceTotalSeconds"]; - - [queueFileJob setObject:[fDstFile2Field stringValue] forKey:@"DestinationPath"]; - - /* Lets get the preset info if there is any */ - [queueFileJob setObject:[fPresetSelectedDisplay stringValue] forKey:@"PresetName"]; - - [queueFileJob setObject:[fDstFormatPopUp titleOfSelectedItem] forKey:@"FileFormat"]; - /* Chapter Markers*/ - /* If we are encoding by chapters and we have only one chapter or a title without chapters, set chapter markers to off. - Leave them on if we're doing point to point encoding, as libhb supports chapters when doing p2p. */ - if ([fEncodeStartStopPopUp indexOfSelectedItem] == 0 && - [fSrcChapterStartPopUp indexOfSelectedItem] == [fSrcChapterEndPopUp indexOfSelectedItem]) - { - [queueFileJob setObject:[NSNumber numberWithInt:0] forKey:@"ChapterMarkers"]; - } - else - { - [queueFileJob setObject:@(self.job.chaptersEnabled) forKey:@"ChapterMarkers"]; - } - - /* We need to get the list of chapter names to put into an array and store - * in our queue, so they can be reapplied in prepareJob when this queue - * item comes up if Chapter Markers is set to on. - */ - [queueFileJob setObject:[[self.job.chapterTitles copy] autorelease] forKey:@"ChapterNames"]; - - /* Mux mp4 with http optimization */ - [queueFileJob setObject:[NSNumber numberWithInteger:[fDstMp4HttpOptFileCheck state]] forKey:@"Mp4HttpOptimize"]; - /* Add iPod uuid atom */ - [queueFileJob setObject:[NSNumber numberWithInteger:[fDstMp4iPodFileCheck state]] forKey:@"Mp4iPodCompatible"]; - - /* Codecs */ - /* Video encoder */ - [self.job.video prepareVideoForQueueFileJob:queueFileJob]; - - /* Picture Sizing */ - [self.job.picture preparePictureForQueueFileJob:queueFileJob]; - - /* Text summaries of various settings */ - [queueFileJob setObject:[NSString stringWithString:[self pictureSettingsSummary]] - forKey:@"PictureSettingsSummary"]; - [queueFileJob setObject:self.job.filters.summary - forKey:@"PictureFiltersSummary"]; - [queueFileJob setObject:[NSString stringWithString:[self muxerOptionsSummary]] - forKey:@"MuxerOptionsSummary"]; - - /* Picture Filters */ - HBFilters *filters = self.job.filters; - queueFileJob[@"PictureDetelecine"] = @(filters.detelecine); - queueFileJob[@"PictureDetelecineCustom"] = filters.detelecineCustomString; - - queueFileJob[@"PictureDecombDeinterlace"] = @(filters.useDecomb); - queueFileJob[@"PictureDecomb"] = @(filters.decomb); - queueFileJob[@"PictureDecombCustom"] = filters.decombCustomString; - - queueFileJob[@"PictureDeinterlace"] = @(filters.deinterlace); - queueFileJob[@"PictureDeinterlaceCustom"] = filters.deinterlaceCustomString; - - queueFileJob[@"PictureDenoise"] = filters.denoise; - queueFileJob[@"PictureDenoisePreset"] = filters.denoisePreset; - queueFileJob[@"PictureDenoiseTune"] = filters.denoiseTune; - queueFileJob[@"PictureDenoiseCustom"] = filters.denoiseCustomString; - - queueFileJob[@"PictureDeblock"] = [NSString stringWithFormat:@"%ld",(long)filters.deblock]; - queueFileJob[@"VideoGrayScale"] = [NSString stringWithFormat:@"%ld",(long)filters.grayscale]; - - /* Audio Defaults */ - NSMutableDictionary *audioDefaults = [NSMutableDictionary dictionary]; - [self.job.audioDefaults prepareAudioDefaultsForPreset:audioDefaults]; - queueFileJob[@"AudioDefaults"] = audioDefaults; - - /* Audio */ - NSMutableArray *audioArray = [[NSMutableArray alloc] initWithArray:[fAudioController audioTracks] copyItems:YES]; - [queueFileJob setObject:audioArray forKey:@"AudioList"]; - [audioArray release]; - - /* Subtitles Defaults */ - NSMutableDictionary *subtitlesDefaults = [NSMutableDictionary dictionary]; - [self.job.subtitlesDefaults prepareSubtitlesDefaultsForPreset:subtitlesDefaults]; - queueFileJob[@"SubtitlesDefaults"] = subtitlesDefaults; - - /* Subtitles */ - NSMutableArray *subtitlesArray = [[NSMutableArray alloc] initWithArray:[fSubtitlesViewController subtitles] copyItems:YES]; - [queueFileJob setObject:subtitlesArray forKey:@"SubtitleList"]; - [subtitlesArray release]; - - /* Now we go ahead and set the "job->values in the plist for passing right to fQueueEncodeLibhb */ - [queueFileJob setObject:[NSNumber numberWithInteger:[[fDstFormatPopUp selectedItem] tag]] forKey:@"JobFileFormatMux"]; - - /* Codecs */ - /* Framerate */ - [queueFileJob setObject:[NSNumber numberWithInt:title->vrate.num] forKey:@"JobVrate"]; - [queueFileJob setObject:[NSNumber numberWithInt:title->vrate.den] forKey:@"JobVrateBase"]; - - /* we need to auto relase the queueFileJob and return it */ - [queueFileJob autorelease]; - return queueFileJob; - -} - -/* this is actually called from the queue controller to modify the queue array and return it back to the queue controller */ +/** + * this is actually called from the queue controller to modify the queue array and return it back to the queue controller + */ - (void)moveObjectsInQueueArray:(NSMutableArray *)array fromIndexes:(NSIndexSet *)indexSet toIndex:(NSUInteger)insertIndex { NSUInteger index = [indexSet lastIndex]; NSUInteger aboveInsertIndexCount = 0; - - + NSUInteger removeIndex; if (index >= insertIndex) @@ -2098,22 +1927,22 @@ static void queueFSEventStreamCallback( [QueueFileArray insertObject:object atIndex:insertIndex]; [object release]; - /* We save all of the Queue data here - * and it also gets sent back to the queue controller*/ + // We save all of the Queue data here + // and it also gets sent back to the queue controller [self saveQueueFileItem]; } - #pragma mark - #pragma mark Queue Job Processing -- (void) incrementQueueItemDone:(NSInteger) queueItemDoneIndexNum +- (void)incrementQueueItemDone:(NSInteger)queueItemDoneIndexNum { - /* Mark the encode just finished as done (status 0)*/ - [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] setObject:[NSNumber numberWithInt:0] forKey:@"Status"]; - - /* We save all of the Queue data here */ + // Mark the encode just finished as done (status 0) + HBJob *queueJob = QueueFileArray[currentQueueEncodeIndex]; + queueJob.state = HBJobStateCompleted; + + // We save all of the Queue data here [self saveQueueFileItem]; /* Since we have now marked a queue item as done @@ -2126,790 +1955,103 @@ static void queueFSEventStreamCallback( /* If we still have more pending items in our queue, lets go to the next one */ if (newQueueItemIndex >= 0 && newQueueItemIndex < queueItems) { - /*Set our currentQueueEncodeIndex now to the newly found Pending encode as we own it */ + // Set our currentQueueEncodeIndex now to the newly found Pending encode as we own it currentQueueEncodeIndex = newQueueItemIndex; - /* now we mark the queue item as Status = 1 ( being encoded ) so another instance can not come along and try to scan it while we are scanning */ - [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] setObject:[NSNumber numberWithInt:1] forKey:@"Status"]; + // now we mark the queue item as Status = 1 ( being encoded ) so another instance can not come along and try to scan it while we are scanning + queueJob = QueueFileArray[currentQueueEncodeIndex]; + queueJob.state = HBJobStateWorking; [HBUtilities writeToActivityLog: "incrementQueueItemDone new pending items found: %d", currentQueueEncodeIndex]; [self saveQueueFileItem]; - /* now we can go ahead and scan the new pending queue item */ - [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]]; - + queueJob = QueueFileArray[currentQueueEncodeIndex]; + // now we can go ahead and scan the new pending queue item + [self performNewQueueScan:queueJob.fileURL.path scanTitleNum:queueJob.titleIdx]; } else { [HBUtilities writeToActivityLog: "incrementQueueItemDone there are no more pending encodes"]; - /* Done encoding, allow system sleep for the encode handle */ - /* - * Since there are no more items to encode, go to queueCompletedAlerts - * for user specified alerts after queue completed - */ + // Since there are no more items to encode, go to queueCompletedAlerts + // for user specified alerts after queue completed [self queueCompletedAlerts]; } } -/* Here we actually tell hb_scan to perform the source scan, using the path to source and title number*/ +/** + * Here we actually tell hb_scan to perform the source scan, using the path to source and title number + */ - (void) performNewQueueScan:(NSString *) scanPath scanTitleNum: (NSInteger) scanTitleNum { - /* Tell HB to output a new activity log file for this encode */ - [outputPanel startEncodeLog:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"DestinationPath"]]; - - /* We now flag the queue item as being owned by this instance of HB using the PID */ - [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] setObject:[NSNumber numberWithInt:pidNum] forKey:@"EncodingPID"]; - /* Get the currentQueueEncodeNameString from the queue item to display in the status field */ - currentQueueEncodeNameString = [[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"DestinationPath"] lastPathComponent]retain]; - /* We save all of the Queue data here */ + HBJob *queueJob = QueueFileArray[currentQueueEncodeIndex]; + // Tell HB to output a new activity log file for this encode + [outputPanel startEncodeLog:[queueJob.destURL.path stringByDeletingLastPathComponent]]; + + // We now flag the queue item as being owned by this instance of HB using the PID + queueJob.pidId = pidNum; + // Get the currentQueueEncodeNameString from the queue item to display in the status field */ + currentQueueEncodeNameString = [[queueJob.destURL.path lastPathComponent]retain]; + // We save all of the Queue data here [self saveQueueFileItem]; - /* - * Only scan 10 previews before an encode - additional previews are - * only useful for autocrop and static previews, which are already taken - * care of at this point - */ + // Only scan 10 previews before an encode - additional previews are + // only useful for autocrop and static previews, which are already taken care of at this point NSURL *fileURL = [NSURL fileURLWithPath:scanPath]; [self.queueCore scan:fileURL titleNum:scanTitleNum previewsNum:10 minTitleDuration:0]; } -/* This assumes that we have re-scanned and loaded up a new queue item to send to libhb as fQueueEncodeLibhb */ -- (void) processNewQueueEncode +/** + * This assumes that we have re-scanned and loaded up a new queue item to send to libhb as fQueueEncodeLibhb + */ +- (void)processNewQueueEncode { - hb_list_t * list = hb_get_titles( self.queueCore.hb_handle ); - hb_title_t * title = (hb_title_t *) hb_list_item( list,0 ); // is always zero since now its a single title scan - hb_job_t * job = hb_job_init(title); - - if( !hb_list_count( list ) ) - { - [HBUtilities writeToActivityLog: "processNewQueueEncode WARNING nothing found in the title list"]; - } - - NSMutableDictionary * queueToApply = [QueueFileArray objectAtIndex:currentQueueEncodeIndex]; - [HBUtilities writeToActivityLog: "Preset: %s", [[queueToApply objectForKey:@"PresetName"] UTF8String]]; - [HBUtilities writeToActivityLog: "processNewQueueEncode number of passes expected is: %d", ([[queueToApply objectForKey:@"VideoTwoPass"] intValue] + 1)]; - hb_job_set_file(job, [[queueToApply objectForKey:@"DestinationPath"] UTF8String]); - [self prepareJob:job]; - - /* - * If scanning we need to do some extra setup of the job. - */ - if (job->indepth_scan == 1) - { - char *encoder_preset_tmp = job->encoder_preset != NULL ? strdup(job->encoder_preset) : NULL; - char *encoder_tune_tmp = job->encoder_tune != NULL ? strdup(job->encoder_tune) : NULL; - char *encoder_options_tmp = job->encoder_options != NULL ? strdup(job->encoder_options) : NULL; - char *encoder_profile_tmp = job->encoder_profile != NULL ? strdup(job->encoder_profile) : NULL; - char *encoder_level_tmp = job->encoder_level != NULL ? strdup(job->encoder_level) : NULL; - /* - * When subtitle scan is enabled do a fast pre-scan job - * which will determine which subtitles to enable, if any. - */ - hb_job_set_encoder_preset (job, NULL); - hb_job_set_encoder_tune (job, NULL); - hb_job_set_encoder_options(job, NULL); - hb_job_set_encoder_profile(job, NULL); - hb_job_set_encoder_level (job, NULL); - job->pass = -1; - hb_add(self.queueCore.hb_handle, job); - /* - * reset the advanced settings - */ - hb_job_set_encoder_preset (job, encoder_preset_tmp); - hb_job_set_encoder_tune (job, encoder_tune_tmp); - hb_job_set_encoder_options(job, encoder_options_tmp); - hb_job_set_encoder_profile(job, encoder_profile_tmp); - hb_job_set_encoder_level (job, encoder_level_tmp); - free(encoder_preset_tmp); - free(encoder_tune_tmp); - free(encoder_options_tmp); - free(encoder_profile_tmp); - free(encoder_level_tmp); - } + HBJob *queueJob = QueueFileArray[currentQueueEncodeIndex]; - - if ([[queueToApply objectForKey:@"VideoTwoPass"] intValue] == 1) + if (self.queueCore.titles.count) { - job->indepth_scan = 0; - job->pass = 1; - hb_add(self.queueCore.hb_handle, job); - job->pass = 2; - hb_add(self.queueCore.hb_handle, job); - + // Reset the title in the job. + queueJob.title = self.queueCore.titles[0]; + + // We should be all setup so let 'er rip + [self.queueCore encodeJob:queueJob]; + fEncodeState = 1; + + // Lets mark our new encode as 1 or "Encoding" + queueJob.state = HBJobStateWorking; + [self saveQueueFileItem]; } else { - job->indepth_scan = 0; - job->pass = 0; - hb_add(self.queueCore.hb_handle, job); + [HBUtilities writeToActivityLog: "processNewQueueEncode WARNING nothing found in the title list"]; } - - NSString *destinationDirectory = [[queueToApply objectForKey:@"DestinationPath"] stringByDeletingLastPathComponent]; - [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"]; - /* Lets mark our new encode as 1 or "Encoding" */ - [queueToApply setObject:[NSNumber numberWithInt:1] forKey:@"Status"]; - [self saveQueueFileItem]; - - /* libhb makes a copy of the job. So we need to free any resource - * that were allocated in construction of the job. This empties - * the audio, subtitle, and filter lists */ - hb_job_close(&job); - - /* We should be all setup so let 'er rip */ - [self doRip]; } #pragma mark - #pragma mark Queue Item Editing /* Rescans the chosen queue item back into the main window */ -- (void)rescanQueueItemToMainWindow:(NSString *) scanPath scanTitleNum: (NSUInteger) scanTitleNum selectedQueueItem: (NSUInteger) selectedQueueItem -{ - fqueueEditRescanItemNum = selectedQueueItem; - [HBUtilities writeToActivityLog: "rescanQueueItemToMainWindow: Re-scanning queue item at index:%d",fqueueEditRescanItemNum]; - applyQueueToScan = YES; - /* Make sure we release the display name before reassigning it */ - [browsedSourceDisplayName release]; - /* Set the browsedSourceDisplayName for showNewScan */ - browsedSourceDisplayName = [[[QueueFileArray objectAtIndex:fqueueEditRescanItemNum] objectForKey:@"SourceName"] retain]; - [self performScan:scanPath scanTitleNum:scanTitleNum]; -} - - -/* We use this method after a queue item rescan for edit. - * it largely mirrors -selectPreset in terms of structure. - * Assumes that a queue item has been reloaded into the main window. - */ -- (IBAction)applyQueueSettingsToMainWindow:(id)sender +- (void)rescanQueueItemToMainWindow:(NSUInteger)selectedQueueItem { - NSDictionary *queueToApply = [QueueFileArray objectAtIndex:fqueueEditRescanItemNum]; - - if (queueToApply) - { - [HBUtilities writeToActivityLog: "applyQueueSettingsToMainWindow: queue item found"]; - } - /* Set title number and chapters */ - /* since the queue only scans a single title, its already been selected in showNewScan - so do not try to reset it here. However if we do decide to do full source scans on - a queue edit rescan, we would need it. So leaving in for now but commenting out. */ - self.job.range.chapterStart = [[queueToApply objectForKey:@"ChapterStart"] intValue] - 1; - self.job.range.chapterStop = [[queueToApply objectForKey:@"ChapterEnd"] intValue] - 1; - - /* File Format */ - [fDstFormatPopUp selectItemWithTag:[queueToApply[@"JobFileFormatMux"] integerValue]]; - [self formatPopUpChanged:nil]; - - /* Chapter Markers*/ - self.job.chaptersEnabled = [[queueToApply objectForKey:@"ChapterMarkers"] boolValue]; - [fChapterTitlesController addChaptersFromQueue:[queueToApply objectForKey:@"ChapterNames"]]; - - /* Mux mp4 with http optimization */ - [fDstMp4HttpOptFileCheck setState:[[queueToApply objectForKey:@"Mp4HttpOptimize"] intValue]]; - - /* Set the state of ipod compatible with Mp4iPodCompatible. Only for x264*/ - [fDstMp4iPodFileCheck setState:[[queueToApply objectForKey:@"Mp4iPodCompatible"] intValue]]; - - /* video encoder */ - [self.job.video applyVideoSettingsFromQueue:queueToApply]; - - /* Audio Defaults */ - [self.job.audioDefaults applySettingsFromPreset:queueToApply[@"AudioDefaults"]]; - - /* Audio */ - /* Now lets add our new tracks to the audio list here */ - [fAudioController addTracksFromQueue:[queueToApply objectForKey:@"AudioList"]]; - - /* Subtitles Defaults */ - [self.job.subtitlesDefaults applySettingsFromPreset:queueToApply[@"SubtitlesDefaults"]]; - - /* Subtitles */ - [fSubtitlesViewController addTracksFromQueue:[queueToApply objectForKey:@"SubtitleList"]]; - - /* Picture Settings */ - [self.job.picture applyPictureSettingsFromQueue:queueToApply]; - - /* Filters */ - HBFilters *filters = self.job.filters; - - /* We only allow *either* Decomb or Deinterlace. So check for the PictureDecombDeinterlace key. */ - filters.useDecomb = YES; - filters.decomb = 0; - filters.deinterlace = 0; - if ([queueToApply[@"PictureDecombDeinterlace"] intValue] == 1) - { - /* we are using decomb */ - /* Decomb */ - if ([queueToApply[@"PictureDecomb"] intValue] > 0) - { - filters.decomb = [queueToApply[@"PictureDecomb"] intValue]; - - /* if we are using "Custom" in the decomb setting, also set the custom string*/ - if ([queueToApply[@"PictureDecomb"] intValue] == 1) - { - filters.decombCustomString = queueToApply[@"PictureDecombCustom"]; - } - } - } - else - { - /* We are using Deinterlace */ - /* Deinterlace */ - if ([queueToApply[@"PictureDeinterlace"] intValue] > 0) - { - filters.useDecomb = NO; - filters.deinterlace = [queueToApply[@"PictureDeinterlace"] intValue]; - /* if we are using "Custom" in the deinterlace setting, also set the custom string*/ - if ([queueToApply[@"PictureDeinterlace"] intValue] == 1) - { - filters.deinterlaceCustomString = queueToApply[@"PictureDeinterlaceCustom"]; - } - } - } - - /* Detelecine */ - if ([queueToApply[@"PictureDetelecine"] intValue] > 0) - { - filters.detelecine = [queueToApply[@"PictureDetelecine"] intValue]; - /* if we are using "Custom" in the detelecine setting, also set the custom string*/ - if ([queueToApply[@"PictureDetelecine"] intValue] == 1) - { - filters.detelecineCustomString = queueToApply[@"PictureDetelecineCustom"]; - } - } - else - { - filters.detelecine = 0; - } - - /* Denoise */ - filters.denoise = queueToApply[@"PictureDenoise"]; - filters.denoisePreset = queueToApply[@"PictureDenoisePreset"]; - filters.denoiseTune = queueToApply[@"PictureDenoiseTune"]; - filters.denoiseCustomString = queueToApply[@"PictureDenoiseCustom"]; + [HBUtilities writeToActivityLog:"rescanQueueItemToMainWindow: Re-scanning queue item at index:%d", selectedQueueItem]; - /* Deblock */ - if ([queueToApply[@"PictureDeblock"] intValue] == 1) - { - /* if its a one, then its the old on/off deblock, set on to 5*/ - filters.deblock = 5; - } - else - { - /* use the settings intValue */ - filters.deblock = [queueToApply[@"PictureDeblock"] intValue]; - } - - filters.grayscale = [queueToApply[@"VideoGrayScale"] boolValue]; + // Set the browsedSourceDisplayName for showNewScan + self.jobFromQueue = QueueFileArray[selectedQueueItem]; + self.browsedSourceDisplayName = self.jobFromQueue.fileURL.lastPathComponent; - // Updates the previews window and summary strings - [self pictureSettingsDidChange]; - - [fPresetSelectedDisplay setStringValue:queueToApply[@"PresetName"]]; - [fPresetsView deselect]; + [self performScan:self.jobFromQueue.fileURL.path scanTitleNum:self.jobFromQueue.titleIdx]; - /* Now that source is loaded and settings applied, delete the queue item from the queue */ - [HBUtilities writeToActivityLog: "applyQueueSettingsToMainWindow: deleting queue item:%d",fqueueEditRescanItemNum]; - [self removeQueueFileItem:fqueueEditRescanItemNum]; + // Now that source is loaded and settings applied, delete the queue item from the queue + [HBUtilities writeToActivityLog: "applyQueueSettingsToMainWindow: deleting queue item:%d", selectedQueueItem]; + [self removeQueueFileItem:selectedQueueItem]; } #pragma mark - #pragma mark Job Handling -- (void) prepareJob:(hb_job_t *)job -{ - NSDictionary * queueToApply = [QueueFileArray objectAtIndex:currentQueueEncodeIndex]; - - hb_list_t * list = hb_get_titles(self.queueCore.hb_handle); - hb_title_t * title = (hb_title_t *) hb_list_item( list,0 ); // is always zero since now its a single title scan - - hb_audio_config_t * audio; - hb_filter_object_t * filter; - /* Title Angle for dvdnav */ - job->angle = [[queueToApply objectForKey:@"TitleAngle"] intValue]; - - if([[queueToApply objectForKey:@"fEncodeStartStop"] intValue] == 0) - { - /* Chapter selection */ - [HBUtilities writeToActivityLog: "Start / Stop set to chapters"]; - job->chapter_start = [[queueToApply objectForKey:@"ChapterStart"] intValue]; - job->chapter_end = [[queueToApply objectForKey:@"ChapterEnd"] intValue]; - } - else if ([[queueToApply objectForKey:@"fEncodeStartStop"] intValue] == 1) - { - /* we are pts based start / stop */ - [HBUtilities writeToActivityLog: "Start / Stop set to secondsā¦"]; - - /* Point A to Point B. Time to time in seconds.*/ - /* get the start seconds from the start seconds field */ - int start_seconds = [[queueToApply objectForKey:@"StartSeconds"] intValue]; - job->pts_to_start = start_seconds * 90000LL; - /* Stop seconds is actually the duration of encode, so subtract the end seconds from the start seconds */ - int stop_seconds = [[queueToApply objectForKey:@"StopSeconds"] intValue]; - job->pts_to_stop = stop_seconds * 90000LL; - - } - else if ([[queueToApply objectForKey:@"fEncodeStartStop"] intValue] == 2) - { - /* we are frame based start / stop */ - [HBUtilities writeToActivityLog: "Start / Stop set to framesā¦"]; - - /* Point A to Point B. Frame to frame */ - /* get the start frame from the start frame field */ - int start_frame = [[queueToApply objectForKey:@"StartFrame"] intValue]; - job->frame_to_start = start_frame; - /* get the frame to stop on from the end frame field */ - int stop_frame = [[queueToApply objectForKey:@"StopFrame"] intValue]; - job->frame_to_stop = stop_frame; - - } - - - - - /* Format (Muxer) and Video Encoder */ - job->mux = [[queueToApply objectForKey:@"JobFileFormatMux"] intValue]; - job->vcodec = [[queueToApply objectForKey:@"JobVideoEncoderVcodec"] intValue]; - - /* We set http optimized mp4 here */ - if( [[queueToApply objectForKey:@"Mp4HttpOptimize"] intValue] == 1 ) - { - job->mp4_optimize = 1; - } - else - { - job->mp4_optimize = 0; - } - - - /* We set the chapter marker extraction here based on the format being - mpeg4 or mkv and the checkbox being checked */ - if ([[queueToApply objectForKey:@"ChapterMarkers"] intValue] == 1) - { - job->chapter_markers = 1; - - /* now lets get our saved chapter names out the array in the queue file - * and insert them back into the title chapter list. We have it here, - * because unless we are inserting chapter markers there is no need to - * spend the overhead of iterating through the chapter names array imo - * Also, note that if for some reason we don't apply chapter names, the - * chapters just come out 001, 002, etc. etc. - */ - - NSArray *chapterNamesArray = [queueToApply objectForKey:@"ChapterNames"]; - int i = 0; - for (id tempObject in chapterNamesArray) - { - hb_chapter_t *chapter = (hb_chapter_t *) hb_list_item( job->list_chapter, i ); - if( chapter != NULL ) - { - hb_chapter_set_title( chapter, [tempObject UTF8String] ); - } - i++; - } - } - else - { - job->chapter_markers = 0; - } - - if (job->vcodec == HB_VCODEC_X264 || job->vcodec == HB_VCODEC_X265) - { - /* iPod 5G atom */ - job->ipod_atom = ([[queueToApply objectForKey:@"Mp4iPodCompatible"] - intValue] == 1); - - /* set fastfirstpass if 2-pass and Turbo are enabled */ - if ([[queueToApply objectForKey:@"VideoTwoPass"] intValue] == 1) - { - job->fastfirstpass = ([[queueToApply objectForKey:@"VideoTurboTwoPass"] - intValue] == 1); - } - - /* advanced x264 options */ - NSString *tmpString; - // translate zero-length strings to NULL for libhb - const char *encoder_preset = NULL; - const char *encoder_tune = NULL; - const char *encoder_options = NULL; - const char *encoder_profile = NULL; - const char *encoder_level = NULL; - if ([[queueToApply objectForKey:@"x264UseAdvancedOptions"] intValue]) - { - // we are using the advanced panel - if ([(tmpString = [queueToApply objectForKey:@"x264Option"]) length]) - { - encoder_options = [tmpString UTF8String]; - } - } - else - { - // we are using the x264 preset system - if ([(tmpString = [queueToApply objectForKey:@"VideoTune"]) length]) - { - encoder_tune = [tmpString UTF8String]; - } - if ([(tmpString = [queueToApply objectForKey:@"VideoOptionExtra"]) length]) - { - encoder_options = [tmpString UTF8String]; - } - if ([(tmpString = [queueToApply objectForKey:@"VideoProfile"]) length]) - { - encoder_profile = [tmpString UTF8String]; - } - if ([(tmpString = [queueToApply objectForKey:@"VideoLevel"]) length]) - { - encoder_level = [tmpString UTF8String]; - } - encoder_preset = [[queueToApply objectForKey:@"VideoPreset"] UTF8String]; - } - hb_job_set_encoder_preset (job, encoder_preset); - hb_job_set_encoder_tune (job, encoder_tune); - hb_job_set_encoder_options(job, encoder_options); - hb_job_set_encoder_profile(job, encoder_profile); - hb_job_set_encoder_level (job, encoder_level); - } - else if (job->vcodec & HB_VCODEC_FFMPEG_MASK) - { - hb_job_set_encoder_options(job, - [[queueToApply objectForKey:@"VideoOptionExtra"] - UTF8String]); - } - - /* Picture Size Settings */ - job->par.num = [[queueToApply objectForKey:@"PicturePARPixelWidth"] intValue]; - job->par.den = [[queueToApply objectForKey:@"PicturePARPixelHeight"] intValue]; - - /* Video settings */ - /* Framerate */ - int fps_mode, fps_num, fps_den; - if ([[queueToApply objectForKey:@"JobIndexVideoFramerate"] intValue] > 0) - { - /* a specific framerate has been chosen */ - fps_num = 27000000; - fps_den = (int)[[queueToApply objectForKey:@"JobIndexVideoFramerate"] intValue]; - if ([[queueToApply objectForKey:@"VideoFramerateMode"] isEqualToString:@"cfr"]) - { - // CFR - fps_mode = 1; - } - else - { - // PFR - fps_mode = 2; - } - } - else - { - /* same as source */ - fps_num = [[queueToApply objectForKey:@"JobVrate"] intValue]; - fps_den = [[queueToApply objectForKey:@"JobVrateBase"] intValue]; - if ([[queueToApply objectForKey:@"VideoFramerateMode"] isEqualToString:@"cfr"]) - { - // CFR - fps_mode = 1; - } - else - { - // VFR - fps_mode = 0; - } - } - - if ( [[queueToApply objectForKey:@"VideoQualityType"] intValue] != 2 ) - { - job->vquality = -1.0; - job->vbitrate = [[queueToApply objectForKey:@"VideoAvgBitrate"] intValue]; - } - if ( [[queueToApply objectForKey:@"VideoQualityType"] intValue] == 2 ) - { - job->vquality = [[queueToApply objectForKey:@"VideoQualitySlider"] floatValue]; - job->vbitrate = 0; - - } - - job->grayscale = [[queueToApply objectForKey:@"VideoGrayScale"] intValue]; - - // Map the settings in the dictionaries for the SubtitleList array to match title->list_subtitle - BOOL one_burned = NO; - int i = 0; - - NSArray *subtitles = [queueToApply objectForKey:@"SubtitleList"]; - for (id subtitleDict in subtitles) - { - int subtitle = [subtitleDict[keySubTrackIndex] intValue]; - int force = [subtitleDict[keySubTrackForced] intValue]; - int burned = [subtitleDict[keySubTrackBurned] intValue]; - int def = [subtitleDict[keySubTrackDefault] intValue]; - - // if i is 0, then we are in the first item of the subtitles which we need to - // check for the "Foreign Audio Search" which would be keySubTrackIndex of -1 - - // if we are on the first track and using "Foreign Audio Search" - if (i == 0 && subtitle == -1) - { - [HBUtilities writeToActivityLog: "Foreign Language Search: %d", 1]; - - job->indepth_scan = 1; - - if (burned != 1) - { - job->select_subtitle_config.dest = PASSTHRUSUB; - } - else - { - job->select_subtitle_config.dest = RENDERSUB; - } - - job->select_subtitle_config.force = force; - job->select_subtitle_config.default_track = def; - } - else - { - // if we are getting the subtitles from an external srt file - if ([subtitleDict[keySubTrackType] intValue] == SRTSUB) - { - hb_subtitle_config_t sub_config; - - sub_config.offset = [subtitleDict[keySubTrackSrtOffset] intValue]; - - // we need to srncpy file name and codeset - strncpy(sub_config.src_filename, [subtitleDict[keySubTrackSrtFilePath] UTF8String], 255); - sub_config.src_filename[255] = 0; - strncpy(sub_config.src_codeset, [subtitleDict[keySubTrackSrtCharCode] UTF8String], 39); - sub_config.src_codeset[39] = 0; - - if( !burned && hb_subtitle_can_pass( SRTSUB, job->mux ) ) - { - sub_config.dest = PASSTHRUSUB; - } - else if( hb_subtitle_can_burn( SRTSUB ) ) - { - // Only allow one subtitle to be burned into the video - if( one_burned ) - continue; - one_burned = TRUE; - sub_config.dest = RENDERSUB; - } - - sub_config.force = 0; - sub_config.default_track = def; - hb_srt_add( job, &sub_config, [subtitleDict[keySubTrackLanguageIsoCode] UTF8String]); - continue; - } - - /* We are setting a source subtitle so access the source subtitle info */ - hb_subtitle_t * subt = (hb_subtitle_t *) hb_list_item( title->list_subtitle, subtitle ); - - if( subt != NULL ) - { - hb_subtitle_config_t sub_config = subt->config; - - if( !burned && hb_subtitle_can_pass( subt->source, job->mux ) ) - { - sub_config.dest = PASSTHRUSUB; - } - else if( hb_subtitle_can_burn( subt->source ) ) - { - // Only allow one subtitle to be burned into the video - if( one_burned ) - continue; - one_burned = TRUE; - sub_config.dest = RENDERSUB; - } - - sub_config.force = force; - sub_config.default_track = def; - hb_subtitle_add( job, &sub_config, subtitle ); - } - } - i++; - } - if( one_burned ) - { - filter = hb_filter_init( HB_FILTER_RENDER_SUB ); - hb_add_filter( job, filter, [[NSString stringWithFormat:@"%d:%d:%d:%d", - job->crop[0], job->crop[1], - job->crop[2], job->crop[3]] UTF8String] ); - } - - /* Auto Defaults */ - NSDictionary *audioDefaults = queueToApply[@"AudioDefaults"]; - - job->acodec_copy_mask = 0; - - if ([audioDefaults[@"AudioAllowAACPass"] boolValue]) - { - job->acodec_copy_mask |= HB_ACODEC_FFAAC; - } - if ([audioDefaults[@"AudioAllowAC3Pass"] boolValue]) - { - job->acodec_copy_mask |= HB_ACODEC_AC3; - } - if ([audioDefaults[@"AudioAllowDTSHDPass"] boolValue]) - { - job->acodec_copy_mask |= HB_ACODEC_DCA_HD; - } - if ([audioDefaults[@"AudioAllowDTSPass"] boolValue]) - { - job->acodec_copy_mask |= HB_ACODEC_DCA; - } - if ([audioDefaults[@"AudioAllowMP3Pass"] boolValue]) - { - job->acodec_copy_mask |= HB_ACODEC_MP3; - } - job->acodec_fallback = hb_audio_encoder_get_from_name([audioDefaults[@"AudioEncoderFallback"] UTF8String]); - - /* Audio tracks and mixdowns */ - /* Now lets add our new tracks to the audio list here */ - for (NSDictionary *audioDict in [queueToApply objectForKey:@"AudioList"]) - { - audio = (hb_audio_config_t *)calloc(1, sizeof(*audio)); - hb_audio_config_init(audio); - audio->in.track = [audioDict[@"Track"] intValue]; - /* We go ahead and assign values to our audio->out.<properties> */ - audio->out.track = audio->in.track; - audio->out.codec = [audioDict[@"JobEncoder"] intValue]; - audio->out.compression_level = hb_audio_compression_get_default(audio->out.codec); - audio->out.mixdown = [audioDict[@"JobMixdown"] intValue]; - audio->out.normalize_mix_level = 0; - audio->out.bitrate = [audioDict[@"JobBitrate"] intValue]; - audio->out.samplerate = [audioDict[@"JobSamplerate"] intValue]; - audio->out.dynamic_range_compression = [audioDict[@"TrackDRCSlider"] doubleValue]; - audio->out.gain = [audioDict[@"TrackGainSlider"] doubleValue]; - audio->out.dither_method = hb_audio_dither_get_default(); - - hb_audio_add(job, audio); - free(audio); - } - - /* Now lets call the filters if applicable. - * The order of the filters is critical - */ - /* Detelecine */ - filter = hb_filter_init( HB_FILTER_DETELECINE ); - if ([[queueToApply objectForKey:@"PictureDetelecine"] intValue] == 1) - { - /* use a custom detelecine string */ - hb_add_filter( job, filter, [[queueToApply objectForKey:@"PictureDetelecineCustom"] UTF8String] ); - } - else if ([[queueToApply objectForKey:@"PictureDetelecine"] intValue] == 2) - { - /* Use libhb's default values */ - hb_add_filter( job, filter, NULL ); - } - - if ([[queueToApply objectForKey:@"PictureDecombDeinterlace"] intValue] == 1) - { - /* Decomb */ - filter = hb_filter_init( HB_FILTER_DECOMB ); - if ([[queueToApply objectForKey:@"PictureDecomb"] intValue] == 1) - { - /* use a custom decomb string */ - hb_add_filter( job, filter, [[queueToApply objectForKey:@"PictureDecombCustom"] UTF8String] ); - } - else if ([[queueToApply objectForKey:@"PictureDecomb"] intValue] == 2) - { - /* use libhb defaults */ - hb_add_filter( job, filter, NULL ); - } - else if ([[queueToApply objectForKey:@"PictureDecomb"] intValue] == 3) - { - /* use old defaults (decomb fast) */ - hb_add_filter( job, filter, "7:2:6:9:1:80" ); - } - else if ([[queueToApply objectForKey:@"PictureDecomb"] intValue] == 4) - { - /* decomb 3 with bobbing enabled */ - hb_add_filter( job, filter, "455" ); - } - } - else - { - /* Deinterlace */ - filter = hb_filter_init( HB_FILTER_DEINTERLACE ); - if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 1) - { - /* we add the custom string if present */ - hb_add_filter( job, filter, [[queueToApply objectForKey:@"PictureDeinterlaceCustom"] UTF8String] ); - } - else if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 2) - { - /* Run old deinterlacer fd by default */ - hb_add_filter( job, filter, "0" ); - } - else if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 3) - { - /* Yadif mode 0 (without spatial deinterlacing) */ - hb_add_filter( job, filter, "1" ); - } - else if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 4) - { - /* Yadif (with spatial deinterlacing) */ - hb_add_filter( job, filter, "3" ); - } - else if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 5) - { - /* Yadif (with spatial deinterlacing and bobbing) */ - hb_add_filter( job, filter, "15" ); - } - } - /* Denoise */ - if (![queueToApply[@"PictureDenoise"] isEqualToString:@"off"]) - { - int filter_id = HB_FILTER_HQDN3D; - if ([queueToApply[@"PictureDenoise"] isEqualToString:@"nlmeans"]) - filter_id = HB_FILTER_NLMEANS; - - if ([queueToApply[@"PictureDenoisePreset"] isEqualToString:@"none"]) - { - const char *filter_str; - filter_str = [queueToApply[@"PictureDenoiseCustom"] UTF8String]; - filter = hb_filter_init(filter_id); - hb_add_filter(job, filter, filter_str); - } - else - { - const char *filter_str, *preset, *tune; - preset = [queueToApply[@"PictureDenoisePreset"] UTF8String]; - tune = [queueToApply[@"PictureDenoiseTune"] UTF8String]; - filter_str = hb_generate_filter_settings(filter_id, preset, tune); - filter = hb_filter_init(filter_id); - hb_add_filter(job, filter, filter_str); - } - } - - /* Deblock (uses pp7 default) */ - /* NOTE: even though there is a valid deblock setting of 0 for the filter, for - * the macgui's purposes a value of 0 actually means to not even use the filter - * current hb_filter_deblock.settings valid ranges are from 5 - 15 - */ - filter = hb_filter_init( HB_FILTER_DEBLOCK ); - if ([[queueToApply objectForKey:@"PictureDeblock"] intValue] != 0) - { - hb_add_filter( job, filter, [[queueToApply objectForKey:@"PictureDeblock"] UTF8String] ); - } - - /* Add Crop/Scale filter */ - filter = hb_filter_init(HB_FILTER_CROP_SCALE); - hb_add_filter( job, filter, [[NSString stringWithFormat:@"%d:%d:%d:%d:%d:%d", - [queueToApply[@"PictureWidth"] intValue], [queueToApply[@"PictureHeight"] intValue], - [queueToApply[@"PictureTopCrop"] intValue], [queueToApply[@"PictureBottomCrop"] intValue], - [queueToApply[@"PictureLeftCrop"] intValue], [queueToApply[@"PictureRightCrop"] intValue]] UTF8String] ); - - /* Add framerate shaping filter */ - filter = hb_filter_init(HB_FILTER_VFR); - hb_add_filter(job, filter, [[NSString stringWithFormat:@"%d:%d:%d", - fps_mode, fps_num, fps_den] UTF8String]); - - [HBUtilities writeToActivityLog: "prepareJob exiting"]; -} - - - /* addToQueue: puts up an alert before ultimately calling doAddToQueue */ -- (IBAction) addToQueue: (id) sender +- (IBAction)addToQueue:(id)sender { - /* We get the destination directory from the destination field here */ - NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent]; - /* We check for a valid destination here */ + // We get the destination directory from the destination field here + NSString *destinationDirectory = self.job.destURL.path.stringByDeletingLastPathComponent; + // We check for a valid destination here if ([[NSFileManager defaultManager] fileExistsAtPath:destinationDirectory] == 0) { NSAlert *alert = [[NSAlert alloc] init]; @@ -2926,29 +2068,28 @@ static void queueFSEventStreamCallback( BOOL fileExistsInQueue; fileExistsInQueue = NO; - /* We check for and existing file here */ - if([[NSFileManager defaultManager] fileExistsAtPath: [fDstFile2Field stringValue]]) + // We check for and existing file here + if([[NSFileManager defaultManager] fileExistsAtPath:self.job.destURL.path]) { fileExists = YES; } - /* We now run through the queue and make sure we are not overwriting an exisiting queue item */ - for (id tempObject in QueueFileArray) + // We now run through the queue and make sure we are not overwriting an exisiting queue item + for (HBJob *job in QueueFileArray) { - NSDictionary *thisQueueDict = tempObject; - if ([[thisQueueDict objectForKey:@"DestinationPath"] isEqualToString: [fDstFile2Field stringValue]]) + if ([job.destURL isEqualTo:self.job.destURL]) { fileExistsInQueue = YES; } } - if(fileExists == YES) + if (fileExists == YES) { NSAlert *alert = [NSAlert alertWithMessageText:@"File already exists." defaultButton:@"Cancel" alternateButton:@"Overwrite" otherButton:nil - informativeTextWithFormat:@"Do you want to overwrite %@?", [fDstFile2Field stringValue]]; + informativeTextWithFormat:@"Do you want to overwrite %@?", self.job.destURL.path]; [alert setAlertStyle:NSCriticalAlertStyle]; [alert beginSheetModalForWindow:fWindow modalDelegate:self didEndSelector:@selector( overwriteAddToQueueAlertDone:returnCode:contextInfo: ) contextInfo:NULL]; @@ -2960,7 +2101,7 @@ static void queueFSEventStreamCallback( defaultButton:@"Cancel" alternateButton:@"Overwrite" otherButton:nil - informativeTextWithFormat:@"Do you want to overwrite %@?", [fDstFile2Field stringValue]]; + informativeTextWithFormat:@"Do you want to overwrite %@?", self.job.destURL.path]; [alert setAlertStyle:NSCriticalAlertStyle]; [alert beginSheetModalForWindow:fWindow modalDelegate:self didEndSelector:@selector( overwriteAddToQueueAlertDone:returnCode:contextInfo: ) contextInfo:NULL]; @@ -2983,11 +2124,9 @@ static void queueFSEventStreamCallback( - (void) doAddToQueue { - [self addQueueFileItem ]; + [self addQueueFileItem]; } - - /* Rip: puts up an alert before ultimately calling doRip */ - (IBAction) Rip: (id) sender @@ -3000,23 +2139,23 @@ static void queueFSEventStreamCallback( return; } - /* We check to see if we need to warn the user that the computer will go to sleep - or shut down when encoding is finished */ - [self remindUserOfSleepOrShutdown]; + // We check to see if we need to warn the user that the computer will go to sleep + // or shut down when encoding is finished + [self remindUserOfSleepOrShutdown]; // If there are pending jobs in the queue, then this is a rip the queue if (fPendingCount > 0) { currentQueueEncodeIndex = [self getNextPendingQueueIndex]; - /* here lets start the queue with the first pending item */ - [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]]; + // here lets start the queue with the first pending item + HBJob *queueJob = QueueFileArray[currentQueueEncodeIndex]; + [self performNewQueueScan:queueJob.fileURL.path scanTitleNum:queueJob.titleIdx]; return; } // Before adding jobs to the queue, check for a valid destination. - - NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent]; + NSString *destinationDirectory = self.job.destURL.path.stringByDeletingLastPathComponent; if ([[NSFileManager defaultManager] fileExistsAtPath:destinationDirectory] == 0) { NSAlert *alert = [[NSAlert alloc] init]; @@ -3027,14 +2166,14 @@ static void queueFSEventStreamCallback( return; } - /* We check for duplicate name here */ - if( [[NSFileManager defaultManager] fileExistsAtPath:[fDstFile2Field stringValue]] ) + // We check for duplicate name here + if( [[NSFileManager defaultManager] fileExistsAtPath:self.job.destURL.path] ) { NSAlert *alert = [NSAlert alertWithMessageText:@"File already exists." defaultButton:@"Cancel" alternateButton:@"Overwrite" otherButton:nil - informativeTextWithFormat:@"Do you want to overwrite %@?", [fDstFile2Field stringValue]]; + informativeTextWithFormat:@"Do you want to overwrite %@?", self.job.destURL.path]; [alert setAlertStyle:NSCriticalAlertStyle]; [alert beginSheetModalForWindow:fWindow modalDelegate:self didEndSelector:@selector( overWriteAlertDone:returnCode:contextInfo: ) contextInfo:NULL]; @@ -3049,10 +2188,10 @@ static void queueFSEventStreamCallback( [self doAddToQueue]; } - /* go right to processing the new queue encode */ + // go right to processing the new queue encode currentQueueEncodeIndex = [self getNextPendingQueueIndex]; - [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]]; - + HBJob *queueJob = QueueFileArray[currentQueueEncodeIndex]; + [self performNewQueueScan:queueJob.fileURL.path scanTitleNum:queueJob.titleIdx]; } } @@ -3064,18 +2203,18 @@ static void queueFSEventStreamCallback( { if( returnCode == NSAlertAlternateReturn ) { - /* if there are no jobs in the queue, then add this one to the queue and rip - otherwise, just rip the queue */ - if( fPendingCount == 0 ) + // if there are no jobs in the queue, then add this one to the queue and rip + // otherwise, just rip the queue + if (fPendingCount == 0) { [self doAddToQueue]; } - NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent]; + NSString *destinationDirectory = [self.job.destURL.path stringByDeletingLastPathComponent]; [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"]; currentQueueEncodeIndex = [self getNextPendingQueueIndex]; - [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]]; - + HBJob *queueJob = QueueFileArray[currentQueueEncodeIndex]; + [self performNewQueueScan:queueJob.fileURL.path scanTitleNum:queueJob.titleIdx]; } } @@ -3122,15 +2261,6 @@ static void queueFSEventStreamCallback( } -- (void) doRip -{ - /* Let libhb do the job */ - [self.queueCore start]; - /* set the fEncodeState State */ - fEncodeState = 1; -} - - //------------------------------------------------------------------------------------ // Displays an alert asking user if the want to cancel encoding of current job. // Cancel: returns immediately after posting the alert. Later, when the user @@ -3193,13 +2323,12 @@ static void queueFSEventStreamCallback( - (void) doCancelCurrentJob { // Stop the current job. - [self.queueCore stop]; fEncodeState = 2; // don't alert at end of processing since this was a cancel // now that we've stopped the currently encoding job, lets mark it as cancelled - [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] setObject:[NSNumber numberWithInt:3] forKey:@"Status"]; + [QueueFileArray[currentQueueEncodeIndex] setState:HBJobStateCanceled]; // and as always, save it in Queue.plist /* We save all of the Queue data here */ [self saveQueueFileItem]; @@ -3214,13 +2343,14 @@ static void queueFSEventStreamCallback( { /*Set our currentQueueEncodeIndex now to the newly found Pending encode as we own it */ currentQueueEncodeIndex = newQueueItemIndex; - /* now we mark the queue item as Status = 1 ( being encoded ) so another instance can not come along and try to scan it while we are scanning */ - [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] setObject:[NSNumber numberWithInt:1] forKey:@"Status"]; + /* now we mark the queue item as worling so another instance can not come along and try to scan it while we are scanning */ + [QueueFileArray[currentQueueEncodeIndex] setState:HBJobStateWorking]; [HBUtilities writeToActivityLog: "incrementQueueItemDone new pending items found: %d", currentQueueEncodeIndex]; [self saveQueueFileItem]; - /* now we can go ahead and scan the new pending queue item */ - [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]]; + HBJob *queueJob = QueueFileArray[currentQueueEncodeIndex]; + // now we can go ahead and scan the new pending queue item + [self performNewQueueScan:queueJob.fileURL.path scanTitleNum:queueJob.titleIdx]; } else { @@ -3235,7 +2365,7 @@ static void queueFSEventStreamCallback( fEncodeState = 2; // don't alert at end of processing since this was a cancel // now that we've stopped the currently encoding job, lets mark it as cancelled - [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] setObject:[NSNumber numberWithInt:3] forKey:@"Status"]; + [QueueFileArray[currentQueueEncodeIndex] setState:HBJobStateCanceled]; // and as always, save it in Queue.plist /* We save all of the Queue data here */ [self saveQueueFileItem]; @@ -3278,22 +2408,21 @@ static void queueFSEventStreamCallback( - (void) doAddAllTitlesToQueue { - - /* first get the currently selected index so we can choose it again after cycling through the available titles. */ + // first get the currently selected index so we can choose it again after cycling through the available titles. NSInteger currentlySelectedTitle = [fSrcTitlePopUp indexOfSelectedItem]; /* For each title in the fSrcTitlePopUp, select it */ - for( int i = 0; i < [fSrcTitlePopUp numberOfItems]; i++ ) + for (int i = 0; i < [fSrcTitlePopUp numberOfItems]; i++) { [fSrcTitlePopUp selectItemAtIndex:i]; - /* Now call titlePopUpChanged to load it up */ + // Now call titlePopUpChanged to load it up [self titlePopUpChanged:nil]; - /* now add the title to the queue */ + // now add the title to the queue [self addToQueue:nil]; } - /* Now that we are done, reselect the previously selected title.*/ + // Now that we are done, reselect the previously selected title. [fSrcTitlePopUp selectItemAtIndex: currentlySelectedTitle]; - /* Now call titlePopUpChanged to load it up */ + // Now call titlePopUpChanged to load it up [self titlePopUpChanged:nil]; } @@ -3318,10 +2447,8 @@ static void queueFSEventStreamCallback( videoCodec:self.job.video.encoder]; // Swap the old one with the new one - [fDstFile2Field setStringValue: [NSString stringWithFormat:@"%@/%@.%@", - [[fDstFile2Field stringValue] stringByDeletingLastPathComponent], - fileName, - [[fDstFile2Field stringValue] pathExtension]]]; + self.job.destURL = [[self.job.destURL URLByDeletingLastPathComponent] URLByAppendingPathComponent: + [NSString stringWithFormat:@"%@.%@", fileName, self.job.destURL.pathExtension]]; } - (IBAction) titlePopUpChanged: (id) sender @@ -3332,58 +2459,63 @@ static void queueFSEventStreamCallback( self.selectedPreset = [self createPresetFromCurrentSettings]; } - HBTitle *hbtitle = self.core.titles[fSrcTitlePopUp.indexOfSelectedItem]; - HBJob *job = [[[HBJob alloc] initWithTitle:hbtitle - andPreset:self.selectedPreset] autorelease]; - - // Set the jobs info to the view controllers - fPictureController.picture = job.picture; - fPictureController.filters = job.filters; - fPreviewController.job = job; + HBTitle *title = self.core.titles[fSrcTitlePopUp.indexOfSelectedItem]; - fVideoController.video = job.video; - fAudioController.job = job; - fSubtitlesViewController.job = job; - fChapterTitlesController.job = job; + // Check if we are reapplying a job from the queue, or creating a new one + if (self.jobFromQueue) + { + self.jobFromQueue.title = title; + self.job = self.jobFromQueue; + } + else + { + self.job = [[[HBJob alloc] initWithTitle:title andPreset:self.selectedPreset] autorelease]; - // Set Auto Crop to on upon selecting a new title - job.picture.autocrop = YES; + // use the correct extension based on the container + const char *ext = hb_container_get_default_extension(self.job.container); - self.job = job; + // Check to see if the last destination has been set,use if so, if not, use Desktop + if ([[NSUserDefaults standardUserDefaults] stringForKey:@"LastDestinationDirectory"]) + { + NSURL *fileURL = [NSURL fileURLWithPath:[[NSUserDefaults standardUserDefaults] stringForKey:@"LastDestinationDirectory"]]; + fileURL = [fileURL URLByAppendingPathComponent:self.browsedSourceDisplayName.stringByDeletingPathExtension]; + fileURL = [fileURL URLByAppendingPathExtension:@(ext)]; + self.job.destURL = fileURL; + } + else + { + self.job.destURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/Desktop/%@.%s", + NSHomeDirectory(), + self.browsedSourceDisplayName.stringByDeletingPathExtension, + ext]]; + } - hb_title_t *title = hbtitle.hb_title; + // set m4v extension if necessary - do not override user-specified .mp4 extension + if (self.job.container & HB_MUX_MASK_MP4) + { + [self autoSetM4vExtension:nil]; + } + } // If we are a stream type and a batch scan, grok the output file name from title->name upon title change - if ((title->type == HB_STREAM_TYPE || title->type == HB_FF_STREAM_TYPE) && self.core.titles.count > 1) + if ((title.hb_title->type == HB_STREAM_TYPE || title.hb_title->type == HB_FF_STREAM_TYPE) && self.core.titles.count > 1) { // we set the default name according to the new title->name - [fDstFile2Field setStringValue: [NSString stringWithFormat: - @"%@/%@.%@", [[fDstFile2Field stringValue] stringByDeletingLastPathComponent], - [NSString stringWithUTF8String: title->name], - [[fDstFile2Field stringValue] pathExtension]]]; - + self.job.destURL = [[self.job.destURL URLByDeletingLastPathComponent] URLByAppendingPathComponent: + [NSString stringWithFormat:@"%@.%@", title.name, self.job.destURL.pathExtension]]; + // Change the source to read out the parent folder also - [fSrcDVD2Field setStringValue:[NSString stringWithFormat:@"%@/%@", browsedSourceDisplayName,[NSString stringWithUTF8String: title->name]]]; + fSrcDVD2Field.stringValue = [NSString stringWithFormat:@"%@/%@", self.browsedSourceDisplayName, title.name]; } - [self chapterPopUpChanged:nil]; - - [fSrcAnglePopUp removeAllItems]; - - for (int i = 0; i < hbtitle.angles; i++) + // apply the current preset + if (!self.jobFromQueue) { - [fSrcAnglePopUp addItemWithTitle:[NSString stringWithFormat: @"%d", i + 1]]; - } - [fSrcAnglePopUp selectItemAtIndex: 0]; + // Set Auto Crop to on upon selecting a new title + self.job.picture.autocrop = YES; - // If Auto Naming is on. We create an output filename of dvd name - title number - if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultAutoNaming"]) - { - [self updateFileName]; - } - - // apply the current preset - [self applyPreset:self.selectedPreset]; + [self applyPreset:self.selectedPreset]; + } } - (IBAction) encodeStartStopPopUpChanged: (id) sender; @@ -3449,20 +2581,20 @@ static void queueFSEventStreamCallback( } } -- (IBAction) formatPopUpChanged: (id) sender +- (void)formatChanged:(NSNotification *)notification { - NSString *string = [fDstFile2Field stringValue]; - int videoContainer = self.job.container; - const char *ext = NULL; - - // set the file extension - ext = hb_container_get_default_extension(videoContainer); - [fDstFile2Field setStringValue:[NSString stringWithFormat:@"%@.%s", - [string stringByDeletingPathExtension], - ext]]; - if (videoContainer & HB_MUX_MASK_MP4) + if (self.job) { - [self autoSetM4vExtension:sender]; + int videoContainer = self.job.container; + + // set the file extension + const char *ext = hb_container_get_default_extension(videoContainer); + self.job.destURL = [[self.job.destURL URLByDeletingPathExtension] URLByAppendingPathExtension:@(ext)]; + + if (videoContainer & HB_MUX_MASK_MP4) + { + [self autoSetM4vExtension:notification]; + } } } @@ -3486,28 +2618,30 @@ static void queueFSEventStreamCallback( extension = @"m4v"; } - if ([extension isEqualTo: [[fDstFile2Field stringValue] pathExtension]] ) + if ([extension isEqualTo:self.job.destURL.pathExtension]) + { return; + } else - [fDstFile2Field setStringValue: [NSString stringWithFormat:@"%@.%@", - [[fDstFile2Field stringValue] stringByDeletingPathExtension], extension]]; + { + self.job.destURL = [[self.job.destURL URLByDeletingPathExtension] URLByAppendingPathExtension:extension]; + } } -/* Method to determine if we should change the UI -To reflect whether or not a Preset is being used or if -the user is using "Custom" settings by determining the sender*/ -- (IBAction) customSettingUsed: (id) sender +/** + * Method to determine if we should change the UI + * To reflect whether or not a Preset is being used or if + * the user is using "Custom" settings by determining the sender + */ +- (void)customSettingUsed { - if ([sender stringValue]) - { - /* Deselect the currently selected Preset if there is one*/ - [fPresetsView deselect]; - /* Change UI to show "Custom" settings are being used */ - [fPresetSelectedDisplay setStringValue: @"Custom"]; - self.customPreset = YES; - } + // Deselect the currently selected Preset if there is one*/ + [fPresetsView deselect]; + // Change UI to show "Custom" settings are being used */ + fPresetSelectedDisplay.stringValue = NSLocalizedString(@"Custom", @""); + self.customPreset = YES; - /* If Auto Naming is on it might need to be update if it includes the quality token */ + // If Auto Naming is on it might need to be update if it includes the quality token if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultAutoNaming"]) { [self updateFileName]; @@ -3523,54 +2657,13 @@ the user is using "Custom" settings by determining the sender*/ - (void)pictureSettingsDidChange { // align picture settings and video filters in the UI using tabs - fVideoController.pictureSettings = [self pictureSettingsSummary]; + fVideoController.pictureSettings = self.job.picture.summary; fVideoController.pictureFilters = self.job.filters.summary; [fPreviewController reloadPreviews]; } #pragma mark - -#pragma mark - Text Summaries - -- (NSString *)pictureSettingsSummary -{ - NSMutableString *summary = [NSMutableString stringWithString:@""]; - if (self.job.picture) - { - HBPicture *pict = self.job.picture; - [summary appendString:pict.info]; - if (pict.anamorphicMode != HB_ANAMORPHIC_STRICT) - { - // anamorphic is not Strict, show the modulus - [summary appendFormat:@", Modulus: %d", pict.modulus]; - } - [summary appendFormat:@", Crop: %s %d/%d/%d/%d", - pict.autocrop ? "Auto" : "Custom", - pict.cropTop, pict.cropBottom, - pict.cropLeft, pict.cropRight]; - } - return [NSString stringWithString:summary]; -} - -- (NSString *) muxerOptionsSummary -{ - NSMutableString *summary = [NSMutableString stringWithString:@""]; - if ((self.job.container & HB_MUX_MASK_MP4) && self.job.mp4HttpOptimize) - { - [summary appendString:@" - Web optimized"]; - } - if ((self.job.container & HB_MUX_MASK_MP4) && self.job.mp4iPodCompatible) - { - [summary appendString:@" - iPod 5G support"]; - } - if ([summary hasPrefix:@" - "]) - { - [summary deleteCharactersInRange:NSMakeRange(0, 3)]; - } - return [NSString stringWithString:summary]; -} - -#pragma mark - #pragma mark Open New Windows - (IBAction) openHomepage: (id) sender @@ -3686,6 +2779,12 @@ the user is using "Custom" settings by determining the sender*/ // Subtitles [fSubtitlesViewController applySettingsFromPreset:chosenPreset]; + // If Auto Naming is on. We create an output filename of dvd name - title number + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultAutoNaming"]) + { + [self updateFileName]; + } + [self pictureSettingsDidChange]; } } diff --git a/macosx/English.lproj/MainMenu.xib b/macosx/English.lproj/MainMenu.xib index 439f95472..0b3ce8117 100644 --- a/macosx/English.lproj/MainMenu.xib +++ b/macosx/English.lproj/MainMenu.xib @@ -152,6 +152,7 @@ </popUpButtonCell> <accessibility description="Angle"/> <connections> + <binding destination="240" name="content" keyPath="self.job.angles" id="oFZ-d6-aeJ"/> <binding destination="5676" name="hidden" keyPath="values.UseDvdNav" id="8xq-AL-yDc"> <dictionary key="options"> <string key="NSValueTransformerName">NSNegateBoolean</string> @@ -245,11 +246,18 @@ <textField verticalHuggingPriority="750" id="1561"> <rect key="frame" x="56" y="455" width="782" height="19"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> - <textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" drawsBackground="YES" id="4919"> + <textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" continuous="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" drawsBackground="YES" id="4919"> <font key="font" metaFont="smallSystem"/> <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> </textFieldCell> + <connections> + <binding destination="240" name="value" keyPath="self.job.destURL" id="f8U-7W-7gP"> + <dictionary key="options"> + <string key="NSValueTransformerName">HBURLTransformer</string> + </dictionary> + </binding> + </connections> </textField> <textField hidden="YES" verticalHuggingPriority="750" id="5491"> <rect key="frame" x="581" y="492" width="54" height="19"/> @@ -409,8 +417,8 @@ <accessibility description="Start Chapter"/> <connections> <action selector="chapterPopUpChanged:" target="240" id="1615"/> - <binding destination="240" name="content" keyPath="self.job.range.chapters" id="6kP-TS-bEc"/> <binding destination="240" name="selectedIndex" keyPath="self.job.range.chapterStart" previousBinding="6kP-TS-bEc" id="U76-2W-TvD"/> + <binding destination="240" name="content" keyPath="self.job.range.chapters" id="6kP-TS-bEc"/> </connections> </popUpButton> <popUpButton verticalHuggingPriority="750" id="1548"> @@ -428,8 +436,8 @@ <accessibility description="End Chapter"/> <connections> <action selector="chapterPopUpChanged:" target="240" id="1616"/> - <binding destination="240" name="content" keyPath="self.job.range.chapters" id="Yqp-Sg-lBf"/> <binding destination="240" name="selectedIndex" keyPath="self.job.range.chapterStop" previousBinding="Yqp-Sg-lBf" id="4k2-Sm-RoJ"/> + <binding destination="240" name="content" keyPath="self.job.range.chapters" id="Yqp-Sg-lBf"/> </connections> </popUpButton> </subviews> @@ -973,7 +981,7 @@ DQ <outlet property="fChaptersTitlesTab" destination="1989" id="oUt-8L-Ag2"/> <outlet property="fDstBrowseButton" destination="1562" id="1578"/> <outlet property="fDstFile1Field" destination="1552" id="1596"/> - <outlet property="fDstFile2Field" destination="1561" id="1585"/> + <outlet property="fDstFile2Field" destination="1561" id="N8U-j2-c00"/> <outlet property="fDstFormatField" destination="1556" id="1583"/> <outlet property="fDstFormatPopUp" destination="1557" id="1584"/> <outlet property="fDstMp4HttpOptFileCheck" destination="4579" id="4581"/> diff --git a/macosx/HBAudio.h b/macosx/HBAudio.h index a54c4ac24..14b191646 100644 --- a/macosx/HBAudio.h +++ b/macosx/HBAudio.h @@ -18,7 +18,7 @@ extern NSString *keyAudioMixdown; extern NSString *keyAudioSamplerate; extern NSString *keyAudioBitrate; -@interface HBAudio : NSObject <NSCoding> +@interface HBAudio : NSObject <NSCoding, NSCopying> @property (nonatomic, retain) NSDictionary *track; @property (nonatomic, retain) NSDictionary *codec; diff --git a/macosx/HBAudio.m b/macosx/HBAudio.m index 6eae9a1f6..be50a51b3 100644 --- a/macosx/HBAudio.m +++ b/macosx/HBAudio.m @@ -575,6 +575,31 @@ static NSMutableArray *masterBitRateArray = nil; return retval; } +#pragma mark - NSCopying + +- (instancetype)copyWithZone:(NSZone *)zone +{ + HBAudio *copy = [[[self class] alloc] init]; + + if (copy) + { + copy->_track = [_track copy]; + copy->_codec = [_codec copy]; + copy->_mixdown = [_mixdown copy]; + copy->_sampleRate = [_sampleRate copy]; + copy->_bitRate = [_bitRate copy]; + copy->_drc = [_drc copy]; + copy->_gain = [_gain copy]; + copy->_videoContainerTag = [_videoContainerTag copy]; + + copy->_codecs = [_codecs copy]; + copy->_mixdowns = [_mixdowns copy]; + copy->_bitRates = [_bitRates copy]; + } + + return copy; +} + #pragma mark - NSCoding - (void)encodeWithCoder:(NSCoder *)coder diff --git a/macosx/HBAudioController.h b/macosx/HBAudioController.h index 878f23a88..2476bdfbb 100644 --- a/macosx/HBAudioController.h +++ b/macosx/HBAudioController.h @@ -33,11 +33,7 @@ extern NSString *HBMixdownChangedNotification; @property (nonatomic, readwrite, assign) HBJob *job; -// Get the list of audio tracks -@property (readonly, nonatomic, copy) NSArray *audioTracks; - - (void) applySettingsFromPreset:(NSDictionary *)preset; -- (void) addTracksFromQueue: (NSArray *) queueArray; - (BOOL) anyCodecMatches: (int) aCodecValue; - (void) settingTrackToNone: (HBAudio *) newNoneTrack; diff --git a/macosx/HBAudioController.m b/macosx/HBAudioController.m index bc2b6e45d..0c1c49293 100644 --- a/macosx/HBAudioController.m +++ b/macosx/HBAudioController.m @@ -114,96 +114,9 @@ NSString *HBMixdownChangedNotification = @"HBMixdownChangedNotification"; #pragma mark - #pragma mark HBController Support -- (NSArray *)audioTracks - -{ - NSMutableArray *tracksArray = [NSMutableArray array]; - - NSUInteger audioArrayCount = [self countOfAudioArray]; - for (NSUInteger counter = 0; counter < audioArrayCount; counter++) - { - HBAudio *anAudio = [self objectInAudioArrayAtIndex: counter]; - if ([anAudio enabled]) - { - NSMutableDictionary *dict = [NSMutableDictionary dictionary]; - NSNumber *sampleRateToUse = ([anAudio.sampleRate[keyAudioSamplerate] intValue] == 0 ? - anAudio.track[keyAudioInputSampleRate] : - anAudio.sampleRate[keyAudioSamplerate]); - - dict[@"Track"] = @([anAudio.track[keyAudioTrackIndex] intValue] -1); - dict[@"TrackDescription"] = anAudio.track[keyAudioTrackName]; - dict[@"Encoder"] = anAudio.codec[keyAudioCodecName]; - dict[@"Mixdown"] = anAudio.mixdown[keyAudioMixdownName]; - dict[@"Samplerate"] = anAudio.sampleRate[keyAudioSampleRateName]; - dict[@"Bitrate"] = anAudio.bitRate[keyAudioBitrateName]; - - // output is not passthru so apply gain - if (!([[anAudio codec][keyAudioCodec] intValue] & HB_ACODEC_PASS_FLAG)) - { - dict[@"TrackGainSlider"] = anAudio.gain; - } - else - { - // output is passthru - the Gain dial is disabled so don't apply its value - dict[@"TrackGainSlider"] = @0; - } - - if (hb_audio_can_apply_drc([anAudio.track[keyAudioInputCodec] intValue], - [anAudio.track[keyAudioInputCodecParam] intValue], - [anAudio.codec[keyAudioCodec] intValue])) - { - dict[@"TrackDRCSlider"] = anAudio.drc; - } - else - { - // source isn't AC3 or output is passthru - the DRC dial is disabled so don't apply its value - dict[@"TrackDRCSlider"] = @0; - } - - dict[@"JobEncoder"] = anAudio.codec[keyAudioCodec]; - dict[@"JobMixdown"] = anAudio.mixdown[keyAudioMixdown]; - dict[@"JobSamplerate"] = sampleRateToUse; - dict[@"JobBitrate"] = anAudio.bitRate[keyAudioBitrate]; - - [tracksArray addObject:dict]; - } - } - - return tracksArray; -} - -- (void) addTracksFromQueue: (NSArray *) queueArray - -{ - // Reinitialize the configured list of audio tracks - [self _clearAudioArray]; - - // The following is the pattern to follow, but with Audio%dTrack being the key to seek... - // Can we assume that there will be no skip in the data? - for (NSDictionary *audioDict in queueArray) - { - HBAudio *newAudio = [[HBAudio alloc] init]; - [newAudio setController: self]; - [self insertObject: newAudio inAudioArrayAtIndex: [self countOfAudioArray]]; - [newAudio setVideoContainerTag: [self videoContainerTag]]; - [newAudio setTrackFromIndex: [audioDict[@"Track"] intValue] + 1]; - [newAudio setCodecFromName: audioDict[@"Encoder"]]; - [newAudio setMixdownFromName: audioDict[@"Mixdown"]]; - [newAudio setSampleRateFromName: audioDict[@"Samplerate"]]; - [newAudio setBitRateFromName: audioDict[@"Bitrate"]]; - [newAudio setDrc: audioDict[@"TrackDRCSlider"]]; - [newAudio setGain: audioDict[@"TrackGainSlider"]]; - [newAudio release]; - } - - [self switchingTrackFromNone: nil]; // see if we need to add one to the list -} - - (void)applySettingsFromPreset:(NSDictionary *)preset { - [self.settings applySettingsFromPreset:preset]; [self.settings validateEncoderFallbackForVideoContainer:[self.videoContainerTag intValue]]; - [self addTracksFromDefaults:NO]; } @@ -507,6 +420,13 @@ NSString *HBMixdownChangedNotification = @"HBMixdownChangedNotification"; [newTrackArray addObject: noneTrack]; [newTrackArray addObjectsFromArray:job.title.audioTracks]; self.masterTrackArray = newTrackArray; + + // Readd the controller reference to the audio tracks. + for (HBAudio *audioTrack in audioArray) + { + audioTrack.controller = self; + } + [self switchingTrackFromNone: nil]; // this ensures there is a None track at the end of the list } else diff --git a/macosx/HBAudioDefaults.h b/macosx/HBAudioDefaults.h index a2e30a318..a99ff05d3 100644 --- a/macosx/HBAudioDefaults.h +++ b/macosx/HBAudioDefaults.h @@ -5,6 +5,7 @@ It may be used under the terms of the GNU General Public License. */ #import <Foundation/Foundation.h> +#import "HBPresetCoding.h" typedef NS_ENUM(NSUInteger, HBAudioTrackSelectionBehavior) { HBAudioTrackSelectionBehaviorNone, @@ -16,7 +17,7 @@ typedef NS_ENUM(NSUInteger, HBAudioTrackSelectionBehavior) { * HBAudioSettings * Stores the audio defaults settings. */ -@interface HBAudioDefaults : NSObject <NSCoding> +@interface HBAudioDefaults : NSObject <NSCoding, NSCopying, HBPresetCoding> @property (nonatomic, readwrite) HBAudioTrackSelectionBehavior trackSelectionBehavior; @property (nonatomic, readwrite, retain) NSMutableArray *trackSelectionLanguages; @@ -34,9 +35,6 @@ typedef NS_ENUM(NSUInteger, HBAudioTrackSelectionBehavior) { @property(nonatomic, readonly) NSArray *audioEncoderFallbacks; -- (void)applySettingsFromPreset:(NSDictionary *)preset; -- (void)prepareAudioDefaultsForPreset:(NSMutableDictionary *)preset; - - (void)validateEncoderFallbackForVideoContainer:(int)container; @end diff --git a/macosx/HBAudioDefaults.m b/macosx/HBAudioDefaults.m index 3628b5564..d6b184f33 100644 --- a/macosx/HBAudioDefaults.m +++ b/macosx/HBAudioDefaults.m @@ -70,7 +70,7 @@ return nil; } -- (void)applySettingsFromPreset:(NSDictionary *)preset +- (void)applyPreset:(NSDictionary *)preset { // Track selection behavior if ([preset[@"AudioTrackSelectionBehavior"] isEqualToString:@"first"]) @@ -165,7 +165,7 @@ } } -- (void)prepareAudioDefaultsForPreset:(NSMutableDictionary *)preset +- (void)writeToPreset:(NSMutableDictionary *)preset { // Track selection behavior if (self.trackSelectionBehavior == HBAudioTrackSelectionBehaviorFirst) @@ -241,6 +241,34 @@ self.container = container; } +#pragma mark - NSCopying + +- (instancetype)copyWithZone:(NSZone *)zone +{ + HBAudioDefaults *copy = [[[self class] alloc] init]; + + if (copy) + { + copy->_trackSelectionBehavior = _trackSelectionBehavior; + [copy->_trackSelectionLanguages release]; + copy->_trackSelectionLanguages = [_trackSelectionLanguages mutableCopy]; + + [copy->_tracksArray release]; + copy->_tracksArray = [[NSMutableArray alloc] initWithArray:_tracksArray copyItems:YES]; + + copy->_allowAACPassthru = _allowAACPassthru; + copy->_allowAC3Passthru = _allowAC3Passthru; + copy->_allowDTSHDPassthru = _allowDTSHDPassthru; + copy->_allowDTSPassthru = _allowDTSPassthru; + copy->_allowMP3Passthru = _allowMP3Passthru; + + copy->_encoderFallback = _encoderFallback; + copy->_secondaryEncoderMode = _secondaryEncoderMode; + } + + return copy; +} + #pragma mark - NSCoding - (void)encodeWithCoder:(NSCoder *)coder diff --git a/macosx/HBAudioTrackPreset.h b/macosx/HBAudioTrackPreset.h index 967351715..12ded68c8 100644 --- a/macosx/HBAudioTrackPreset.h +++ b/macosx/HBAudioTrackPreset.h @@ -13,7 +13,7 @@ * a KVO enabled class used in the Audio Defaults panels, * automatically validates the values. */ -@interface HBAudioTrackPreset : NSObject <NSCoding> +@interface HBAudioTrackPreset : NSObject <NSCoding, NSCopying> /** * track properties. diff --git a/macosx/HBAudioTrackPreset.m b/macosx/HBAudioTrackPreset.m index 7d5cc2e90..60e10986b 100644 --- a/macosx/HBAudioTrackPreset.m +++ b/macosx/HBAudioTrackPreset.m @@ -217,6 +217,26 @@ static void *HBAudioEncoderContex = &HBAudioEncoderContex; return retval; } +#pragma mark - NSCopying + +- (instancetype)copyWithZone:(NSZone *)zone +{ + HBAudioTrackPreset *copy = [[[self class] alloc] init]; + + if (copy) + { + copy->_encoder = _encoder; + copy->_mixdown = _mixdown; + copy->_sampleRate = _sampleRate; + copy->_bitRate = _bitRate; + + copy->_gain = _gain; + copy->_drc = _drc; + } + + return copy; +} + #pragma mark - NSCoding - (void)encodeWithCoder:(NSCoder *)coder diff --git a/macosx/HBCore.h b/macosx/HBCore.h index a0a831e5b..f78c26c55 100644 --- a/macosx/HBCore.h +++ b/macosx/HBCore.h @@ -8,6 +8,8 @@ #include "hb.h" +@class HBJob; + // These constants specify the current state of HBCore. typedef NS_ENUM(NSUInteger, HBState) { HBStateIdle = HB_STATE_IDLE, ///< HB is doing nothing @@ -111,6 +113,13 @@ extern NSString *HBCoreMuxingNotification; @property (nonatomic, readonly) NSArray *titles; /** + * Starts an asynchronous encoding session with the passed job. + * + * @param job the job to encode. + */ +- (void)encodeJob:(HBJob *)job; + +/** * Starts the libhb encoding session. * * This method must be called after all jobs have been added. diff --git a/macosx/HBCore.m b/macosx/HBCore.m index 84fc15cd5..fb46f20de 100644 --- a/macosx/HBCore.m +++ b/macosx/HBCore.m @@ -5,7 +5,7 @@ It may be used under the terms of the GNU General Public License. */ #import "HBCore.h" -#import "HBTitle.h" +#import "HBJob.h" #import "HBDVDDetector.h" #import "HBUtilities.h" @@ -231,6 +231,68 @@ NSString *HBCoreMuxingNotification = @"HBCoreMuxingNotification"; #pragma mark - Encodes +- (void)encodeJob:(HBJob *)job +{ + hb_job_t *hb_job = job.hb_job; + + [HBUtilities writeToActivityLog: "processNewQueueEncode number of passes expected is: %d", (job.video.twoPass + 1)]; + hb_job_set_file(hb_job, job.destURL.fileSystemRepresentation); + + // If scanning we need to do some extra setup of the job. + if (hb_job->indepth_scan == 1) + { + char *encoder_preset_tmp = hb_job->encoder_preset != NULL ? strdup(hb_job->encoder_preset) : NULL; + char *encoder_tune_tmp = hb_job->encoder_tune != NULL ? strdup(hb_job->encoder_tune) : NULL; + char *encoder_options_tmp = hb_job->encoder_options != NULL ? strdup(hb_job->encoder_options) : NULL; + char *encoder_profile_tmp = hb_job->encoder_profile != NULL ? strdup(hb_job->encoder_profile) : NULL; + char *encoder_level_tmp = hb_job->encoder_level != NULL ? strdup(hb_job->encoder_level) : NULL; + /* + * When subtitle scan is enabled do a fast pre-scan job + * which will determine which subtitles to enable, if any. + */ + hb_job_set_encoder_preset (hb_job, NULL); + hb_job_set_encoder_tune (hb_job, NULL); + hb_job_set_encoder_options(hb_job, NULL); + hb_job_set_encoder_profile(hb_job, NULL); + hb_job_set_encoder_level (hb_job, NULL); + hb_job->pass = -1; + hb_add(self.hb_handle, hb_job); + /* + * reset the advanced settings + */ + hb_job_set_encoder_preset (hb_job, encoder_preset_tmp); + hb_job_set_encoder_tune (hb_job, encoder_tune_tmp); + hb_job_set_encoder_options(hb_job, encoder_options_tmp); + hb_job_set_encoder_profile(hb_job, encoder_profile_tmp); + hb_job_set_encoder_level (hb_job, encoder_level_tmp); + free(encoder_preset_tmp); + free(encoder_tune_tmp); + free(encoder_options_tmp); + free(encoder_profile_tmp); + free(encoder_level_tmp); + } + + if (job.video.twoPass) + { + hb_job->indepth_scan = 0; + hb_job->pass = 1; + hb_add(self.hb_handle, hb_job); + hb_job->pass = 2; + hb_add(self.hb_handle, hb_job); + } + else + { + hb_job->indepth_scan = 0; + hb_job->pass = 0; + hb_add(self.hb_handle, hb_job); + } + + // Free the job + hb_job_close(&hb_job); + + [self start]; +} + - (void)start { // Start the timer to handle libhb state changes diff --git a/macosx/HBFilters+UIAdditions.h b/macosx/HBFilters+UIAdditions.h index a84e652d9..8b79a2056 100644 --- a/macosx/HBFilters+UIAdditions.h +++ b/macosx/HBFilters+UIAdditions.h @@ -24,6 +24,11 @@ @property (nonatomic, readonly) NSArray *denoisePresets; @property (nonatomic, readonly) NSArray *denoiseTunes; +/** + * A textual summary of the filters settings. + */ +@property (nonatomic, readonly) NSString *summary; + @end /** diff --git a/macosx/HBFilters+UIAdditions.m b/macosx/HBFilters+UIAdditions.m index 88fbc9e37..aae7b6bb5 100644 --- a/macosx/HBFilters+UIAdditions.m +++ b/macosx/HBFilters+UIAdditions.m @@ -141,4 +141,120 @@ extern NSDictionary *_HandBrake_nlmeansTunesDict; return @[@"None", @"Film", @"Grain", @"High Motion", @"Animation"]; } +- (NSString *)summary +{ + NSMutableString *summary = [NSMutableString string]; + + /* Detelecine */ + switch (self.detelecine) + { + case 1: + [summary appendFormat:@" - Detelecine (%@)", self.detelecineCustomString]; + break; + + case 2: + [summary appendString:@" - Detelecine (Default)"]; + break; + + default: + break; + } + + if (self.useDecomb) + { + /* Decomb */ + switch (self.decomb) + { + 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; + } + } + else + { + /* Deinterlace */ + switch (self.deinterlace) + { + 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; + } + } + + /* Deblock */ + if (self.deblock > 0) + { + [summary appendFormat:@" - Deblock (%ld)", self.deblock]; + } + + /* Denoise */ + if (![self.denoise isEqualToString:@"off"]) + { + [summary appendFormat:@" - Denoise (%@", [[_HandBrake_denoiseTypesDict allKeysForObject:self.denoise] firstObject]]; + if (![self.denoisePreset isEqualToString:@"none"]) + { + [summary appendFormat:@", %@", [[_HandBrake_denoisePresetsDict allKeysForObject:self.denoisePreset] firstObject]]; + + if ([self.denoise isEqualToString:@"nlmeans"]) + { + [summary appendFormat:@", %@", [[_HandBrake_nlmeansTunesDict allKeysForObject:self.denoiseTune] firstObject]]; + } + } + else + { + [summary appendFormat:@", %@", self.denoiseCustomString]; + } + + [summary appendString:@")"]; + + } + + /* Grayscale */ + if (self.grayscale) + { + [summary appendString:@" - Grayscale"]; + } + + if ([summary hasPrefix:@" - "]) + { + [summary deleteCharactersInRange:NSMakeRange(0, 3)]; + } + + return [NSString stringWithString:summary]; +} + @end diff --git a/macosx/HBFilters.h b/macosx/HBFilters.h index 81777259b..e64808a78 100644 --- a/macosx/HBFilters.h +++ b/macosx/HBFilters.h @@ -5,20 +5,20 @@ It may be used under the terms of the GNU General Public License. */ #import <Foundation/Foundation.h> +#import "HBPresetCoding.h" extern NSString * const HBFiltersChangedNotification; /** * Filters settings. */ -@interface HBFilters : NSObject <NSCoding> - -- (void)prepareFiltersForPreset:(NSMutableDictionary *)preset; -- (void)applySettingsFromPreset:(NSDictionary *)preset; +@interface HBFilters : NSObject <NSCoding, NSCopying, HBPresetCoding> @property (nonatomic, readwrite) NSInteger detelecine; @property (nonatomic, readwrite, copy) NSString *detelecineCustomString; +@property (nonatomic, readwrite) BOOL useDecomb; + @property (nonatomic, readwrite) NSInteger deinterlace; @property (nonatomic, readwrite, copy) NSString *deinterlaceCustomString; @@ -33,11 +33,4 @@ extern NSString * const HBFiltersChangedNotification; @property (nonatomic, readwrite) NSInteger deblock; @property (nonatomic, readwrite) BOOL grayscale; -@property (nonatomic, readwrite) BOOL useDecomb; - -/** - * A textual summary of the filters settings. - */ -@property (nonatomic, readonly) NSString *summary; - @end diff --git a/macosx/HBFilters.m b/macosx/HBFilters.m index b09ab7d27..86ec87180 100644 --- a/macosx/HBFilters.m +++ b/macosx/HBFilters.m @@ -199,6 +199,37 @@ NSDictionary *_HandBrake_nlmeansTunesDict; [self postChangedNotification]; } +#pragma mark - NSCopying + +- (instancetype)copyWithZone:(NSZone *)zone +{ + HBFilters *copy = [[[self class] alloc] init]; + + if (copy) + { + copy->_detelecine = _detelecine; + copy->_detelecineCustomString = [_detelecineCustomString copy]; + + copy->_deinterlace = _deinterlace; + copy->_deinterlaceCustomString = [_deinterlaceCustomString copy]; + + copy->_decomb = _decomb; + copy->_decombCustomString = [_decombCustomString copy]; + + copy->_denoise = [_denoise copy]; + copy->_denoisePreset = [_denoisePreset copy]; + copy->_denoiseTune = [_denoiseTune copy]; + copy->_denoiseCustomString = [_denoiseCustomString copy]; + + copy->_deblock = _deblock; + copy->_grayscale = _grayscale; + + copy->_useDecomb = _useDecomb; + } + + return copy; +} + #pragma mark - NSCoding - (void)encodeWithCoder:(NSCoder *)coder @@ -255,7 +286,7 @@ NSDictionary *_HandBrake_nlmeansTunesDict; #pragma mark - Presets and queue -- (void)prepareFiltersForPreset:(NSMutableDictionary *)preset +- (void)writeToPreset:(NSMutableDictionary *)preset { preset[@"PictureDecombDeinterlace"] = @(self.useDecomb); @@ -277,7 +308,7 @@ NSDictionary *_HandBrake_nlmeansTunesDict; preset[@"VideoGrayScale"] = @(self.grayscale); } -- (void)applySettingsFromPreset:(NSDictionary *)preset +- (void)applyPreset:(NSDictionary *)preset { self.notificationsEnabled = NO; @@ -394,120 +425,4 @@ NSDictionary *_HandBrake_nlmeansTunesDict; self.notificationsEnabled = YES; } -- (NSString *)summary -{ - NSMutableString *summary = [NSMutableString string]; - - /* Detelecine */ - switch (self.detelecine) - { - case 1: - [summary appendFormat:@" - Detelecine (%@)", self.detelecineCustomString]; - break; - - case 2: - [summary appendString:@" - Detelecine (Default)"]; - break; - - default: - break; - } - - if (self.useDecomb) - { - /* Decomb */ - switch (self.decomb) - { - 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; - } - } - else - { - /* Deinterlace */ - switch (self.deinterlace) - { - 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; - } - } - - /* Deblock */ - if (self.deblock > 0) - { - [summary appendFormat:@" - Deblock (%ld)", self.deblock]; - } - - /* Denoise */ - if (![self.denoise isEqualToString:@"off"]) - { - [summary appendFormat:@" - Denoise (%@", [[_HandBrake_denoiseTypesDict allKeysForObject:self.denoise] firstObject]]; - if (![self.denoisePreset isEqualToString:@"none"]) - { - [summary appendFormat:@", %@", [[_HandBrake_denoisePresetsDict allKeysForObject:self.denoisePreset] firstObject]]; - - if ([self.denoise isEqualToString:@"nlmeans"]) - { - [summary appendFormat:@", %@", [[_HandBrake_nlmeansTunesDict allKeysForObject:self.denoiseTune] firstObject]]; - } - } - else - { - [summary appendFormat:@", %@", self.denoiseCustomString]; - } - - [summary appendString:@")"]; - - } - - /* Grayscale */ - if (self.grayscale) - { - [summary appendString:@" - Grayscale"]; - } - - if ([summary hasPrefix:@" - "]) - { - [summary deleteCharactersInRange:NSMakeRange(0, 3)]; - } - - return [NSString stringWithString:summary]; -} - @end diff --git a/macosx/HBJob+UIAdditions.h b/macosx/HBJob+UIAdditions.h index 357f87cc5..c7d78ddc8 100644 --- a/macosx/HBJob+UIAdditions.h +++ b/macosx/HBJob+UIAdditions.h @@ -10,5 +10,9 @@ @interface HBJob (UIAdditions) @property (nonatomic, readonly) BOOL mp4OptionsEnabled; +@property (nonatomic, readonly) NSArray *angles; -@end
\ No newline at end of file +@end + +@interface HBURLTransformer : NSValueTransformer +@end diff --git a/macosx/HBJob+UIAdditions.m b/macosx/HBJob+UIAdditions.m index 29836553a..6e5bf030a 100644 --- a/macosx/HBJob+UIAdditions.m +++ b/macosx/HBJob+UIAdditions.m @@ -21,4 +21,42 @@ } } +- (NSArray *)angles +{ + NSMutableArray *angles = [NSMutableArray array]; + for (int i = 0; i < self.title.angles; i++) + { + [angles addObject:[NSString stringWithFormat: @"%d", i + 1]]; + } + return angles; +} + +@end + +@implementation HBURLTransformer + ++ (Class)transformedValueClass +{ + return [NSString class]; +} + +- (id)transformedValue:(id)value +{ + if (value) + return [value path]; + else + return nil; +} + ++ (BOOL)allowsReverseTransformation +{ + return YES; +} + +- (id)reverseTransformedValue:(id)value +{ + return [NSURL fileURLWithPath:value]; +} + @end + diff --git a/macosx/HBJob.h b/macosx/HBJob.h index 9a32c07c1..b3866f037 100644 --- a/macosx/HBJob.h +++ b/macosx/HBJob.h @@ -14,6 +14,8 @@ #import "HBPicture.h" #import "HBFilters.h" +#import "HBAudio.h" + #import "HBAudioDefaults.h" #import "HBSubtitlesDefaults.h" @@ -42,9 +44,11 @@ typedef NS_ENUM(NSUInteger, HBJobState) { /** * Current state of the job. */ -@property (nonatomic, readonly) HBJobState state; +@property (nonatomic, readwrite) HBJobState state; -@property (nonatomic, readonly) HBTitle *title; +@property (nonatomic, readwrite, assign) HBTitle *title; +@property (nonatomic, readonly) int titleIdx; +@property (nonatomic, readwrite) int pidId; // Urls @property (nonatomic, readonly) NSURL *fileURL; diff --git a/macosx/HBJob.m b/macosx/HBJob.m index 271075dfa..8e26f7275 100644 --- a/macosx/HBJob.m +++ b/macosx/HBJob.m @@ -16,12 +16,6 @@ NSString *HBContainerChangedNotification = @"HBContainerChangedNotification"; NSString *keyContainerTag = @"keyContainerTag"; -@interface HBJob () - -@property (nonatomic, readonly) int titleIdx; - -@end - @implementation HBJob - (instancetype)initWithTitle:(HBTitle *)title andPreset:(HBPreset *)preset @@ -64,42 +58,27 @@ NSString *keyContainerTag = @"keyContainerTag"; self.container = hb_container_get_from_name(hb_container_sanitize_name([content[@"FileFormat"] UTF8String])); - // Mux mp4 with http optimization + // MP4 specifics options. self.mp4HttpOptimize = [content[@"Mp4HttpOptimize"] boolValue]; self.mp4iPodCompatible = [content[@"Mp4iPodCompatible"] boolValue]; // Chapter Markers self.chaptersEnabled = [content[@"ChapterMarkers"] boolValue]; - [@[self.audioDefaults, self.subtitlesDefaults, self.video, self.picture, self.filters] makeObjectsPerformSelector:@selector(applySettingsFromPreset:) + [@[self.audioDefaults, self.subtitlesDefaults, self.filters, self.picture, self.video, ] makeObjectsPerformSelector:@selector(applyPreset:) withObject:content]; } - (void)applyCurrentSettingsToPreset:(NSMutableDictionary *)dict { dict[@"FileFormat"] = @(hb_container_get_name(self.container)); - dict[@"ChapterMarkers"] = @(self.chaptersEnabled); - - // Mux mp4 with http optimization + // MP4 specifics options. dict[@"Mp4HttpOptimize"] = @(self.mp4HttpOptimize); - // Add iPod uuid atom dict[@"Mp4iPodCompatible"] = @(self.mp4iPodCompatible); - // Video encoder - [self.video prepareVideoForPreset:dict]; - - // Picture Filters - [self.filters prepareFiltersForPreset:dict]; - - // Picture Size - [self.picture preparePictureForPreset:dict]; - - // Audio - [self.audioDefaults prepareAudioDefaultsForPreset:dict]; - - // Subtitles - [self.subtitlesDefaults prepareSubtitlesDefaultsForPreset:dict]; + [@[self.video, self.filters, self.picture, self.audioDefaults, self.subtitlesDefaults] makeObjectsPerformSelector:@selector(writeToPreset:) + withObject:dict]; } - (void)setContainer:(int)container @@ -114,6 +93,13 @@ NSString *keyContainerTag = @"keyContainerTag"; userInfo:@{keyContainerTag: @(self.container)}]]; } +- (void)setTitle:(HBTitle *)title +{ + _title = title; + self.range.title = title; + self.picture.title = title; +} + + (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key { NSSet *retval = nil; @@ -131,13 +117,18 @@ NSString *keyContainerTag = @"keyContainerTag"; [_audioTracks release]; [_subtitlesTracks release]; + [_fileURL release]; + [_destURL release]; + + [_range release]; [_video release]; [_picture release]; [_filters release]; [_audioDefaults release]; [_subtitlesDefaults release]; - [_fileURL release]; + + [_chapterTitles release]; [super dealloc]; } @@ -342,9 +333,6 @@ NSString *keyContainerTag = @"keyContainerTag"; for (NSDictionary *subtitleDict in self.subtitlesTracks) { - if (i == self.subtitlesTracks.count - 1) - continue; - int subtitle = [subtitleDict[keySubTrackIndex] intValue]; int force = [subtitleDict[keySubTrackForced] intValue]; int burned = [subtitleDict[keySubTrackBurned] intValue]; @@ -523,19 +511,20 @@ NSString *keyContainerTag = @"keyContainerTag"; // Detelecine hb_filter_object_t *filter; - filter = hb_filter_init(HB_FILTER_DETELECINE); if (self.filters.detelecine == 1) { + filter = hb_filter_init(HB_FILTER_DETELECINE); // use a custom detelecine string hb_add_filter(job, filter, self.filters.detelecineCustomString.UTF8String); } else if (self.filters.detelecine == 2) { + filter = hb_filter_init(HB_FILTER_DETELECINE); // Use libhb's default values hb_add_filter(job, filter, NULL); } - if (self.filters.useDecomb) + if (self.filters.useDecomb && self.filters.decomb) { // Decomb filter = hb_filter_init(HB_FILTER_DECOMB); @@ -560,7 +549,7 @@ NSString *keyContainerTag = @"keyContainerTag"; hb_add_filter(job, filter, "455"); } } - else + else if (self.filters.deinterlace) { // Deinterlace filter = hb_filter_init(HB_FILTER_DEINTERLACE); @@ -619,9 +608,9 @@ NSString *keyContainerTag = @"keyContainerTag"; // NOTE: even though there is a valid deblock setting of 0 for the filter, for // the macgui's purposes a value of 0 actually means to not even use the filter // current hb_filter_deblock.settings valid ranges are from 5 - 15 - filter = hb_filter_init(HB_FILTER_DEBLOCK); if (self.filters.deblock != 0) { + filter = hb_filter_init(HB_FILTER_DEBLOCK); hb_add_filter(job, filter, [NSString stringWithFormat:@"%ld", (long)self.filters.deblock].UTF8String); } @@ -640,6 +629,56 @@ NSString *keyContainerTag = @"keyContainerTag"; return job; } +#pragma mark - NSCopying + +- (instancetype)copyWithZone:(NSZone *)zone +{ + HBJob *copy = [[[self class] alloc] init]; + + if (copy) + { + copy->_state = HBJobStateReady; + copy->_titleIdx = _titleIdx; + copy->_pidId = _pidId; + + copy->_fileURL = [_fileURL copy]; + copy->_destURL = [_destURL copy]; + + copy->_container = _container; + copy->_angle = _angle; + copy->_mp4HttpOptimize = _mp4HttpOptimize; + copy->_mp4iPodCompatible = _mp4iPodCompatible; + + copy->_range = [_range copy]; + copy->_video = [_video copy]; + copy->_picture = [_picture copy]; + copy->_filters = [_filters copy]; + + // Copy the tracks, but not the last one because it's empty. + copy->_audioTracks = [[NSMutableArray alloc] init]; + [_audioTracks enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if (idx < _audioTracks.count - 1) + { + [copy->_audioTracks addObject:[[obj copy] autorelease]]; + } + }]; + copy->_subtitlesTracks = [[NSMutableArray alloc] init]; + [_subtitlesTracks enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if (idx < _subtitlesTracks.count - 1) + { + [copy->_subtitlesTracks addObject:[[obj copy] autorelease]]; + } + }]; + copy->_chaptersEnabled = _chaptersEnabled; + copy->_chapterTitles = [[NSMutableArray alloc] initWithArray:_chapterTitles copyItems:YES]; + + copy->_audioDefaults = [_audioDefaults copy]; + copy->_subtitlesDefaults = [_subtitlesDefaults copy]; + } + + return copy; +} + #pragma mark - NSCoding - (void)encodeWithCoder:(NSCoder *)coder @@ -648,6 +687,7 @@ NSString *keyContainerTag = @"keyContainerTag"; encodeInt(_state); encodeInt(_titleIdx); + encodeInt(_pidId); encodeObject(_fileURL); encodeObject(_destURL); @@ -678,6 +718,7 @@ NSString *keyContainerTag = @"keyContainerTag"; decodeInt(_state); decodeInt(_titleIdx); + decodeInt(_pidId); decodeObject(_fileURL); decodeObject(_destURL); @@ -692,6 +733,8 @@ NSString *keyContainerTag = @"keyContainerTag"; decodeObject(_picture); decodeObject(_filters); + _video.job = self; + decodeObject(_audioTracks); decodeObject(_subtitlesTracks); @@ -704,11 +747,4 @@ NSString *keyContainerTag = @"keyContainerTag"; return self; } -#pragma mark - NSCopying - -- (instancetype)copyWithZone:(NSZone *)zone -{ - return nil; -} - @end diff --git a/macosx/HBPicture+UIAdditions.h b/macosx/HBPicture+UIAdditions.h index 367127870..e19d627d2 100644 --- a/macosx/HBPicture+UIAdditions.h +++ b/macosx/HBPicture+UIAdditions.h @@ -13,6 +13,7 @@ * UI enabled bindings */ @property (nonatomic, readonly) NSString *info; +@property (nonatomic, readonly) NSString *summary; @property (nonatomic, readonly) int maxWidth; @property (nonatomic, readonly) int maxHeight; diff --git a/macosx/HBPicture+UIAdditions.m b/macosx/HBPicture+UIAdditions.m index 04a4a5afd..e07e30667 100644 --- a/macosx/HBPicture+UIAdditions.m +++ b/macosx/HBPicture+UIAdditions.m @@ -86,4 +86,23 @@ return sizeInfo; } +- (NSString *)summary +{ + NSMutableString *summary = [NSMutableString stringWithString:@""]; + [summary appendString:self.info]; + + if (self.anamorphicMode != HB_ANAMORPHIC_STRICT) + { + // anamorphic is not Strict, show the modulus + [summary appendFormat:@", Modulus: %d", self.modulus]; + } + + [summary appendFormat:@", Crop: %s %d/%d/%d/%d", + self.autocrop ? "Auto" : "Custom", + self.cropTop, self.cropBottom, + self.cropLeft, self.cropRight]; + + return [[summary copy] autorelease]; +} + @end diff --git a/macosx/HBPicture.h b/macosx/HBPicture.h index e68fa627c..ce63e68c2 100644 --- a/macosx/HBPicture.h +++ b/macosx/HBPicture.h @@ -5,6 +5,7 @@ It may be used under the terms of the GNU General Public License. */ #import <Foundation/Foundation.h> +#import "HBPresetCoding.h" @class HBTitle; @@ -13,16 +14,10 @@ extern NSString * const HBPictureChangedNotification; /** * HBPicture */ -@interface HBPicture : NSObject <NSCoding> +@interface HBPicture : NSObject <NSCoding, NSCopying, HBPresetCoding> - (instancetype)initWithTitle:(HBTitle *)title; -- (void)applyPictureSettingsFromQueue:(NSDictionary *)queueToApply; -- (void)preparePictureForQueueFileJob:(NSMutableDictionary *)queueFileJob; - -- (void)preparePictureForPreset:(NSMutableDictionary *)preset; -- (void)applySettingsFromPreset:(NSDictionary *)preset; - @property (nonatomic, readwrite) int width; @property (nonatomic, readwrite) int height; diff --git a/macosx/HBPicture.m b/macosx/HBPicture.m index 1719eeb1a..c758580a0 100644 --- a/macosx/HBPicture.m +++ b/macosx/HBPicture.m @@ -413,6 +413,35 @@ NSString * const HBPictureChangedNotification = @"HBPictureChangedNotification"; [self postChangedNotification]; } +#pragma mark - NSCopying + +- (instancetype)copyWithZone:(NSZone *)zone +{ + HBPicture *copy = [[[self class] alloc] init]; + + if (copy) + { + copy->_width = _width; + copy->_height = _height; + + copy->_keepDisplayAspect = _keepDisplayAspect; + copy->_anamorphicMode = _anamorphicMode; + copy->_modulus = _modulus; + + copy->_displayWidth = _displayWidth; + copy->_parWidth = _parWidth; + copy->_parHeight = _parHeight; + + copy->_autocrop = _autocrop; + copy->_cropTop = _cropTop; + copy->_cropBottom = _cropBottom; + copy->_cropLeft = _cropLeft; + copy->_cropRight = _cropRight; + } + + return copy; +} + #pragma mark - NSCoding - (void)encodeWithCoder:(NSCoder *)coder @@ -463,7 +492,7 @@ NSString * const HBPictureChangedNotification = @"HBPictureChangedNotification"; #pragma mark - Presets/Queue -- (void)preparePictureForPreset:(NSMutableDictionary *)preset +- (void)writeToPreset:(NSMutableDictionary *)preset { preset[@"PictureKeepRatio"] = @(self.keepDisplayAspect); preset[@"PicturePAR"] = @(self.anamorphicMode); @@ -478,7 +507,7 @@ NSString * const HBPictureChangedNotification = @"HBPictureChangedNotification"; preset[@"PictureRightCrop"] = @(self.cropRight); } -- (void)applySettingsFromPreset:(NSDictionary *)preset +- (void)applyPreset:(NSDictionary *)preset { self.validating = YES; hb_title_t *title = self.title.hb_title; @@ -607,64 +636,4 @@ NSString * const HBPictureChangedNotification = @"HBPictureChangedNotification"; self.validating = NO; } -- (void)preparePictureForQueueFileJob:(NSMutableDictionary *)queueFileJob -{ - queueFileJob[@"PictureWidth"] = @(self.width); - queueFileJob[@"PictureHeight"] = @(self.height); - - queueFileJob[@"PictureKeepRatio"] = @(self.keepDisplayAspect); - queueFileJob[@"PicturePAR"] = @(self.anamorphicMode); - - queueFileJob[@"PictureModulus"] = @(self.modulus); - - queueFileJob[@"PicturePARPixelWidth"] = @(self.parWidth); - queueFileJob[@"PicturePARPixelHeight"] = @(self.parHeight); - - queueFileJob[@"PictureAutoCrop"] = @(self.autocrop); - queueFileJob[@"PictureTopCrop"] = @(self.cropTop); - queueFileJob[@"PictureBottomCrop"] = @(self.cropBottom); - queueFileJob[@"PictureLeftCrop"] = @(self.cropLeft); - queueFileJob[@"PictureRightCrop"] = @(self.cropRight); -} - -- (void)applyPictureSettingsFromQueue:(NSDictionary *)queueToApply -{ - self.validating = YES; - /* If Cropping is set to custom, then recall all four crop values from - when the preset was created and apply them */ - if ([queueToApply[@"PictureAutoCrop"] intValue] == 0) - { - self.autocrop = NO; - - /* Here we use the custom crop values saved at the time the preset was saved */ - self.cropTop = [queueToApply[@"PictureTopCrop"] intValue]; - self.cropBottom = [queueToApply[@"PictureBottomCrop"] intValue]; - self.cropLeft = [queueToApply[@"PictureLeftCrop"] intValue]; - self.cropRight = [queueToApply[@"PictureRightCrop"] intValue]; - - } - else /* if auto crop has been saved in preset, set to auto and use post scan auto crop */ - { - self.autocrop = YES; - - hb_title_t *title = self.title.hb_title; - - /* Here we use the auto crop values determined right after scan */ - self.cropTop = title->crop[0]; - self.cropBottom = title->crop[1]; - self.cropLeft = title->crop[2]; - self.cropRight = title->crop[3]; - - } - - self.anamorphicMode = [[queueToApply objectForKey:@"PicturePAR"] intValue]; - self.modulus = [[queueToApply objectForKey:@"PictureModulus"] intValue]; - self.keepDisplayAspect = [[queueToApply objectForKey:@"PictureKeepRatio"] intValue]; - self.width = [[queueToApply objectForKey:@"PictureWidth"] intValue]; - self.height = [[queueToApply objectForKey:@"PictureHeight"] intValue]; - - self.validating = NO; - [self validateSettings]; -} - @end diff --git a/macosx/HBPresetCoding.h b/macosx/HBPresetCoding.h new file mode 100644 index 000000000..f1464c0b2 --- /dev/null +++ b/macosx/HBPresetCoding.h @@ -0,0 +1,15 @@ +/* HBPresetCoding.h $ + + 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 <Foundation/Foundation.h> + +@protocol HBPresetCoding <NSObject> + +- (void)applyPreset:(NSDictionary *)preset; +- (void)writeToPreset:(NSMutableDictionary *)preset; + + +@end
\ No newline at end of file diff --git a/macosx/HBQueueController.h b/macosx/HBQueueController.h index 4a366224f..41f76698b 100644 --- a/macosx/HBQueueController.h +++ b/macosx/HBQueueController.h @@ -1,27 +1,21 @@ -/* HBQueueController +/* HBQueueController.h 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 <Cocoa/Cocoa.h> -#include "hb.h" @class HBController; +@class HBCore; @interface HBQueueController : NSWindowController <NSToolbarDelegate, NSWindowDelegate> - (void)setPidNum: (int)myPidnum; -- (void)setHandle: (hb_handle_t *)handle; +- (void)setCore: (HBCore *)core; - (void)setHBController: (HBController *)controller; - (void)setQueueArray: (NSMutableArray *)QueueFileArray; - -/* Animate the icon for the current encode */ -- (void) animateWorkingEncodeIconInQueue; -- (void) startAnimatingCurrentWorkingEncodeInQueue; -- (void) stopAnimatingCurrentJobGroupInQueue; - (void)setQueueStatusString: (NSString *)statusString; - (IBAction)showQueueWindow: (id)sender; diff --git a/macosx/HBQueueController.mm b/macosx/HBQueueController.mm index d81870793..82bc7d83f 100644 --- a/macosx/HBQueueController.mm +++ b/macosx/HBQueueController.mm @@ -5,12 +5,18 @@ It may be used under the terms of the GNU General Public License. */ #import "HBQueueController.h" +#import "HBCore.h" #import "Controller.h" #import "HBQueueOutlineView.h" #import "HBImageAndTextCell.h" #import "HBUtilities.h" +#import "HBJob.h" + +#import "HBPicture+UIAdditions.h" +#import "HBFilters+UIAdditions.h" + #define HB_ROW_HEIGHT_TITLE_ONLY 17.0 // Pasteboard type for or drag operations @@ -39,7 +45,6 @@ @interface HBQueueController () <HBQueueOutlineViewDelegate> { - hb_handle_t *fQueueEncodeLibhb; // reference to libhb HBController *fHBController; // reference to HBController NSMutableArray *fJobGroups; // mirror image of the queue array from controller.mm @@ -70,6 +75,8 @@ NSDictionary *shortHeightAttr; } +@property (nonatomic, readonly) HBCore *queueCore; + /* control encodes in the window */ - (IBAction)removeSelectedQueueItem: (id)sender; - (IBAction)revealSelectedQueueItem: (id)sender; @@ -110,40 +117,31 @@ [fOutlineView reloadData]; - /* lets get the stats on the status of the queue array */ + // lets get the stats on the status of the queue array fPendingCount = 0; fWorkingCount = 0; - - /* We use a number system to set the encode status of the queue item - * in controller.mm - * 0 == already encoded - * 1 == is being encoded - * 2 == is yet to be encoded - * 3 == cancelled - */ + int i = 0; - NSDictionary *thisQueueDict = nil; - for (id tempObject in fJobGroups) + for (HBJob *job in fJobGroups) { - thisQueueDict = tempObject; - if ([thisQueueDict[@"Status"] intValue] == 1) // being encoded + if (job.state == HBJobStateWorking) // being encoded { fWorkingCount++; - /* we have an encoding job so, lets start the animation timer */ - if (thisQueueDict[@"EncodingPID"] && [thisQueueDict[@"EncodingPID"] intValue] == pidNum) + // we have an encoding job so, lets start the animation timer + if (job.pidId == pidNum) { fEncodingQueueItem = i; } } - if ([thisQueueDict[@"Status"] intValue] == 2) // pending + if (job.state == HBJobStateReady) // pending { fPendingCount++; } i++; } - - /* Set the queue status field in the queue window */ + + // Set the queue status field in the queue window NSMutableString *string; if (fPendingCount == 0) { @@ -199,9 +197,9 @@ //------------------------------------------------------------------------------------ // Receive HB handle //------------------------------------------------------------------------------------ -- (void)setHandle: (hb_handle_t *)handle +- (void)setCore: (HBCore *)core { - fQueueEncodeLibhb = handle; + _queueCore = core; } //------------------------------------------------------------------------------------ @@ -267,16 +265,14 @@ // Optional method: This message is sent to us since we are the target of some // toolbar item actions. - if (!fQueueEncodeLibhb) return NO; + if (!self.queueCore) return NO; BOOL enable = NO; - - hb_state_t s; - hb_get_state2 (fQueueEncodeLibhb, &s); + HBState s = self.queueCore.state; if ([[toolbarItem itemIdentifier] isEqualToString:@"HBQueueStartCancelToolbarIdentifier"]) { - if ((s.state == HB_STATE_PAUSED) || (s.state == HB_STATE_WORKING) || (s.state == HB_STATE_MUXING)) + if ((s == HBStatePaused) || (s == HBStateWorking) || (s == HBStateMuxing)) { enable = YES; [toolbarItem setImage:[NSImage imageNamed: @"stopencode"]]; @@ -303,7 +299,7 @@ if ([[toolbarItem itemIdentifier] isEqualToString:@"HBQueuePauseResumeToolbarIdentifier"]) { - if (s.state == HB_STATE_PAUSED) + if (s == HBStatePaused) { enable = YES; [toolbarItem setImage:[NSImage imageNamed: @"encode"]]; @@ -311,7 +307,7 @@ [toolbarItem setToolTip: @"Resume Encoding"]; } - else if ((s.state == HB_STATE_WORKING) || (s.state == HB_STATE_MUXING)) + else if ((s == HBStateWorking) || (s == HBStateMuxing)) { enable = YES; [toolbarItem setImage:[NSImage imageNamed: @"pauseencode"]]; @@ -348,13 +344,13 @@ { NSIndexSet *targetedRow = [fOutlineView targetedRowIndexes]; NSUInteger row = [targetedRow firstIndex]; - if( row == NSNotFound ) + if (row == NSNotFound) return; /* if this is a currently encoding job, we need to be sure to alert the user, * to let them decide to cancel it first, then if they do, we can come back and * remove it */ - if ([fJobGroups[row][@"Status"] integerValue] == 1) + if ([fJobGroups[row] state] == HBJobStateWorking) { /* We pause the encode here so that it doesn't finish right after and then * screw up the sync while the window is open @@ -383,8 +379,8 @@ } else { - /* since we are not a currently encoding item, we can just be removed */ - [fHBController removeQueueFileItem:row]; + // since we are not a currently encoding item, we can just be removed + [fHBController removeQueueFileItem:row]; } } @@ -437,16 +433,17 @@ //------------------------------------------------------------------------------------ - (IBAction)toggleStartCancel: (id)sender { - if (!fQueueEncodeLibhb) return; + if (!self.queueCore) return; - hb_state_t s; - hb_get_state2 (fQueueEncodeLibhb, &s); - - if ((s.state == HB_STATE_PAUSED) || (s.state == HB_STATE_WORKING) || (s.state == HB_STATE_MUXING)) + HBState s = self.queueCore.state; + if ((s == HBStatePaused) || (s == HBStateWorking) || (s == HBStateMuxing)) + { [fHBController Cancel: self]; - + } else if (fPendingCount > 0) + { [fHBController Rip: NULL]; + } } //------------------------------------------------------------------------------------ @@ -454,24 +451,21 @@ //------------------------------------------------------------------------------------ - (IBAction)togglePauseResume: (id)sender { - if (!fQueueEncodeLibhb) return; - - hb_state_t s; - hb_get_state2 (fQueueEncodeLibhb, &s); - - if (s.state == HB_STATE_PAUSED) + if (!self.queueCore) return; + + HBState s = self.queueCore.state; + if (s == HBStatePaused) { - hb_resume (fQueueEncodeLibhb); + [self.queueCore resume]; [self startAnimatingCurrentWorkingEncodeInQueue]; } - else if ((s.state == HB_STATE_WORKING) || (s.state == HB_STATE_MUXING)) + else if ((s == HBStateWorking) || (s == HBStateMuxing)) { - hb_pause (fQueueEncodeLibhb); + [self.queueCore pause]; [self stopAnimatingCurrentJobGroupInQueue]; } } - //------------------------------------------------------------------------------------ // Send the selected queue item back to the main window for rescan and possible edit. //------------------------------------------------------------------------------------ @@ -486,14 +480,14 @@ /* if this is a currently encoding job, we need to be sure to alert the user, * to let them decide to cancel it first, then if they do, we can come back and * remove it */ - - if ([fJobGroups[row][@"Status"] integerValue] == 1) + + HBJob *job = fJobGroups[row]; + if (job.state == HBJobStateWorking) { - /* We pause the encode here so that it doesn't finish right after and then - * screw up the sync while the window is open - */ - [fHBController Pause:NULL]; - NSString *alertTitle = [NSString stringWithFormat:NSLocalizedString(@"Stop This Encode and Remove It ?", nil)]; + // We pause the encode here so that it doesn't finish right after and then + // screw up the sync while the window is open + [fHBController Pause:NULL]; + NSString *alertTitle = [NSString stringWithFormat:NSLocalizedString(@"Stop This Encode and Remove It ?", nil)]; // Which window to attach the sheet to? NSWindow *docWindow = nil; if ([sender respondsToSelector: @selector(window)]) @@ -517,10 +511,7 @@ else { /* since we are not a currently encoding item, we can just be cancelled */ - [fHBController rescanQueueItemToMainWindow:fJobGroups[row][@"SourcePath"] - scanTitleNum:[fJobGroups[row][@"TitleNumber"] integerValue] - selectedQueueItem:row]; - + [fHBController rescanQueueItemToMainWindow:row]; } } @@ -721,45 +712,45 @@ { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; /* Below should be put into a separate method but I am way too f'ing lazy right now */ - NSMutableAttributedString * finalString = [[NSMutableAttributedString alloc] initWithString: @""]; - + NSMutableAttributedString *finalString = [[NSMutableAttributedString alloc] initWithString: @""]; + HBJob *job = item; + /* First line, we should strip the destination path and just show the file name and add the title num and chapters (if any) */ - NSString * summaryInfo; + NSString *summaryInfo; - NSString * titleString = [NSString stringWithFormat:@"Title %d", [item[@"TitleNumber"] intValue]]; + NSString *titleString = [NSString stringWithFormat:@"Title %d", job.titleIdx]; - NSString * startStopString = @""; - if ([item[@"fEncodeStartStop"] intValue] == 0) + NSString *startStopString = @""; + if (job.range.type == HBRangeTypeChapters) { - /* Start Stop is chapters */ - startStopString = ([item[@"ChapterStart"] intValue] == [item[@"ChapterEnd"] intValue]) ? - [NSString stringWithFormat:@"Chapter %d", [item[@"ChapterStart"] intValue]] : - [NSString stringWithFormat:@"Chapters %d through %d", [item[@"ChapterStart"] intValue], [item[@"ChapterEnd"] intValue]]; + // Start Stop is chapters + startStopString = (job.range.chapterStart == job.range.chapterStop) ? + [NSString stringWithFormat:@"Chapter %d", job.range.chapterStart] : + [NSString stringWithFormat:@"Chapters %d through %d", job.range.chapterStart, job.range.chapterStop]; } - else if ([item[@"fEncodeStartStop"] intValue] == 1) + else if (job.range.type == HBRangeTypeSeconds) { - /* Start Stop is seconds */ - startStopString = [NSString stringWithFormat:@"Seconds %d through %d", [item[@"StartSeconds"] intValue], [item[@"StartSeconds"] intValue] + [item[@"StopSeconds"] intValue]]; + // Start Stop is seconds + startStopString = [NSString stringWithFormat:@"Seconds %d through %d", job.range.secondsStart, job.range.secondsStop]; } - else if ([item[@"fEncodeStartStop"] intValue] == 2) + else if (job.range.type == HBRangeTypeFrames) { - /* Start Stop is Frames */ - startStopString = [NSString stringWithFormat:@"Frames %d through %d", [item[@"StartFrame"] intValue], [item[@"StartFrame"] intValue] + [item[@"StopFrame"] intValue]]; + // Start Stop is Frames + startStopString = [NSString stringWithFormat:@"Frames %d through %d", job.range.frameStart, job.range.frameStop]; } - - NSString * passesString = @""; - /* check to see if our first subtitle track is Foreign Language Search, in which case there is an in depth scan */ - if ([item[@"SubtitleList"] count] && [item[@"SubtitleList"][0][@"keySubTrackIndex"] intValue] == -1) + NSString *passesString = @""; + // check to see if our first subtitle track is Foreign Language Search, in which case there is an in depth scan + if (job.subtitlesTracks.count && [job.subtitlesTracks[0][@"keySubTrackIndex"] intValue] == -1) { - passesString = [passesString stringByAppendingString:@"1 Foreign Language Search Pass - "]; + passesString = [passesString stringByAppendingString:@"1 Foreign Language Search Pass - "]; } - if ([item[@"VideoTwoPass"] intValue] == 0) + if (job.video.twoPass == YES) { passesString = [passesString stringByAppendingString:@"1 Video Pass"]; } else { - if ([item[@"VideoTurboTwoPass"] intValue] == 1) + if (job.video.turboTwoPass == YES) { passesString = [passesString stringByAppendingString:@"2 Video Passes First Turbo"]; } @@ -768,197 +759,206 @@ passesString = [passesString stringByAppendingString:@"2 Video Passes"]; } } - - [finalString appendString:[NSString stringWithFormat:@"%@", item[@"SourceName"]] withAttributes:titleAttr]; - + + [finalString appendString:[NSString stringWithFormat:@"%@", job.fileURL.path.lastPathComponent] withAttributes:titleAttr]; + + /* lets add the output file name to the title string here */ - NSString * outputFilenameString = [item[@"DestinationPath"] lastPathComponent]; + NSString *outputFilenameString = job.destURL.lastPathComponent; summaryInfo = [NSString stringWithFormat: @" (%@, %@, %@) -> %@", titleString, startStopString, passesString, outputFilenameString]; - - [finalString appendString:[NSString stringWithFormat:@"%@\n", summaryInfo] withAttributes:detailAttr]; - + + [finalString appendString:[NSString stringWithFormat:@"%@\n", summaryInfo] withAttributes:detailAttr]; + // Insert a short-in-height line to put some white space after the title [finalString appendString:@"\n" withAttributes:shortHeightAttr]; // End of Title Stuff - - /* Second Line (Preset Name)*/ - [finalString appendString: @"Preset: " withAttributes:detailBoldAttr]; - [finalString appendString:[NSString stringWithFormat:@"%@\n", item[@"PresetName"]] withAttributes:detailAttr]; - - /* Third Line (Format Summary) */ - NSString * audioCodecSummary = @""; // This seems to be set by the last track we have available... - /* Lets also get our audio track detail since we are going through the logic for use later */ - NSMutableArray *audioDetails = [NSMutableArray arrayWithCapacity: [item[@"AudioList"] count]]; + // Second Line (Preset Name) + // FIXME + //[finalString appendString: @"Preset: " withAttributes:detailBoldAttr]; + //[finalString appendString:[NSString stringWithFormat:@"%@\n", item[@"PresetName"]] withAttributes:detailAttr]; + + + // Third Line (Format Summary) + NSString *audioCodecSummary = @""; // This seems to be set by the last track we have available... + // Lets also get our audio track detail since we are going through the logic for use later + + NSMutableArray *audioDetails = [NSMutableArray arrayWithCapacity:job.audioTracks.count]; BOOL autoPassthruPresent = NO; - for (NSDictionary *audioTrack in item[@"AudioList"]) + for (HBAudio *audioTrack in job.audioTracks) { - audioCodecSummary = [NSString stringWithFormat: @"%@", audioTrack[@"Encoder"]]; - NSNumber *drc = audioTrack[@"TrackDRCSlider"]; - NSNumber *gain = audioTrack[@"TrackGainSlider"]; + audioCodecSummary = [NSString stringWithFormat: @"%@", audioTrack.codec[keyAudioCodecName]]; + NSNumber *drc = audioTrack.drc; + NSNumber *gain = audioTrack.gain; NSString *detailString = [NSString stringWithFormat: @"%@ Encoder: %@ Mixdown: %@ SampleRate: %@(khz) Bitrate: %@(kbps), DRC: %@, Gain: %@", - audioTrack[@"TrackDescription"], - audioTrack[@"Encoder"], - audioTrack[@"Mixdown"], - audioTrack[@"Samplerate"], - audioTrack[@"Bitrate"], + audioTrack.track[keyAudioTrackName], + audioTrack.codec[keyAudioCodecName], + audioTrack.mixdown[keyAudioMixdownName], + audioTrack.sampleRate[keyAudioSampleRateName], + audioTrack.bitRate[keyAudioBitrateName], (0.0 < [drc floatValue]) ? (NSObject *)drc : (NSObject *)@"Off", (0.0 != [gain floatValue]) ? (NSObject *)gain : (NSObject *)@"Off" ]; [audioDetails addObject: detailString]; // check if we have an Auto Passthru output track - if ([audioTrack[@"Encoder"] isEqualToString: @"Auto Passthru"]) + if ([audioTrack.codec[keyAudioCodecName] isEqualToString: @"Auto Passthru"]) { autoPassthruPresent = YES; } } - NSString * jobFormatInfo; - if ([item[@"ChapterMarkers"] intValue] == 1) - jobFormatInfo = [NSString stringWithFormat:@"%@ Container, %@ Video %@ Audio, Chapter Markers\n", item[@"FileFormat"], item[@"VideoEncoder"], audioCodecSummary]; + NSString *jobFormatInfo; + if (job.chaptersEnabled) + jobFormatInfo = [NSString stringWithFormat:@"%@ Container, %@ Video %@ Audio, Chapter Markers\n", + @(hb_container_get_name(job.container)), @(hb_video_encoder_get_name(job.video.encoder)), audioCodecSummary]; else - jobFormatInfo = [NSString stringWithFormat:@"%@ Container, %@ Video %@ Audio\n", item[@"FileFormat"], item[@"VideoEncoder"], audioCodecSummary]; - + jobFormatInfo = [NSString stringWithFormat:@"%@ Container, %@ Video %@ Audio\n", + @(hb_container_get_name(job.container)), @(hb_video_encoder_get_name(job.video.encoder)), audioCodecSummary]; [finalString appendString: @"Format: " withAttributes:detailBoldAttr]; [finalString appendString: jobFormatInfo withAttributes:detailAttr]; - - /* Optional String for muxer options */ - if ([item[@"MuxerOptionsSummary"] length]) + + // Optional String for muxer options + NSMutableString *containerOptions = [NSMutableString stringWithString:@""]; + if ((job.container & HB_MUX_MASK_MP4) && job.mp4HttpOptimize) + { + [containerOptions appendString:@" - Web optimized"]; + } + if ((job.container & HB_MUX_MASK_MP4) && job.mp4iPodCompatible) + { + [containerOptions appendString:@" - iPod 5G support"]; + } + if ([containerOptions hasPrefix:@" - "]) + { + [containerOptions deleteCharactersInRange:NSMakeRange(0, 3)]; + } + if (containerOptions.length) { - NSString *containerOptions = [NSString stringWithFormat:@"%@", - item[@"MuxerOptionsSummary"]]; [finalString appendString:@"Container Options: " withAttributes:detailBoldAttr]; [finalString appendString:containerOptions withAttributes:detailAttr]; [finalString appendString:@"\n" withAttributes:detailAttr]; } - - /* Fourth Line (Destination Path)*/ + + // Fourth Line (Destination Path) [finalString appendString: @"Destination: " withAttributes:detailBoldAttr]; - [finalString appendString: item[@"DestinationPath"] withAttributes:detailAttr]; + [finalString appendString: job.destURL.path withAttributes:detailAttr]; [finalString appendString:@"\n" withAttributes:detailAttr]; - - /* Fifth Line Picture Details*/ - NSString *pictureInfo = [NSString stringWithFormat:@"%@", - item[@"PictureSettingsSummary"]]; - if ([item[@"PictureKeepRatio"] intValue] == 1) + + + // Fifth Line Picture Details + NSString *pictureInfo = [NSString stringWithFormat:@"%@", job.picture.summary]; + if (job.picture.keepDisplayAspect) { pictureInfo = [pictureInfo stringByAppendingString:@" Keep Aspect Ratio"]; } [finalString appendString:@"Picture: " withAttributes:detailBoldAttr]; [finalString appendString:pictureInfo withAttributes:detailAttr]; [finalString appendString:@"\n" withAttributes:detailAttr]; - + /* Optional String for Picture Filters */ - if ([item[@"PictureFiltersSummary"] length]) + if (job.filters.summary.length) { - NSString *pictureFilters = [NSString stringWithFormat:@"%@", - item[@"PictureFiltersSummary"]]; + NSString *pictureFilters = [NSString stringWithFormat:@"%@", job.filters.summary]; [finalString appendString:@"Filters: " withAttributes:detailBoldAttr]; [finalString appendString:pictureFilters withAttributes:detailAttr]; [finalString appendString:@"\n" withAttributes:detailAttr]; } + + // Sixth Line Video Details + NSString * videoInfo = [NSString stringWithFormat:@"Encoder: %@", @(hb_video_encoder_get_name(job.video.encoder))]; - /* Sixth Line Video Details*/ - NSString * videoInfo; - videoInfo = [NSString stringWithFormat:@"Encoder: %@", item[@"VideoEncoder"]]; - - /* for framerate look to see if we are using vfr detelecine */ - if ([item[@"JobIndexVideoFramerate"] intValue] == 0) + // for framerate look to see if we are using vfr detelecine + if (job.video.frameRate == 0) { - if ([item[@"VideoFramerateMode"] isEqualToString:@"vfr"]) + if (job.video.frameRateMode == 0) { - /* we are using same as source with vfr detelecine */ + // we are using same as source with vfr detelecine videoInfo = [NSString stringWithFormat:@"%@ Framerate: Same as source (Variable Frame Rate)", videoInfo]; } else { - /* we are using a variable framerate without dropping frames */ + // we are using a variable framerate without dropping frames videoInfo = [NSString stringWithFormat:@"%@ Framerate: Same as source (Constant Frame Rate)", videoInfo]; } } else { - /* we have a specified, constant framerate */ - if ([item[@"VideoFramerateMode"] isEqualToString:@"pfr"]) + // we have a specified, constant framerate + if (job.video.frameRate == 0) { - videoInfo = [NSString stringWithFormat:@"%@ Framerate: %@ (Peak Frame Rate)", videoInfo ,item[@"VideoFramerate"]]; + videoInfo = [NSString stringWithFormat:@"%@ Framerate: %@ (Peak Frame Rate)", videoInfo, @(hb_video_framerate_get_name(job.video.frameRate))]; } else { - videoInfo = [NSString stringWithFormat:@"%@ Framerate: %@ (Constant Frame Rate)", videoInfo ,item[@"VideoFramerate"]]; + videoInfo = [NSString stringWithFormat:@"%@ Framerate: %@ (Constant Frame Rate)", videoInfo, @(hb_video_framerate_get_name(job.video.frameRate))]; } } - - if ([item[@"VideoQualityType"] intValue] == 0)// Target Size MB - { - videoInfo = [NSString stringWithFormat:@"%@ Target Size: %@(MB) (%d(kbps) abr)", videoInfo ,item[@"VideoTargetSize"],[item[@"VideoAvgBitrate"] intValue]]; - } - else if ([item[@"VideoQualityType"] intValue] == 1) // ABR + + + if (job.video.qualityType == 0) // ABR { - videoInfo = [NSString stringWithFormat:@"%@ Bitrate: %d(kbps)", videoInfo ,[item[@"VideoAvgBitrate"] intValue]]; + videoInfo = [NSString stringWithFormat:@"%@ Bitrate: %d(kbps)", videoInfo, job.video.avgBitrate]; } else // CRF { - videoInfo = [NSString stringWithFormat:@"%@ Constant Quality: %.2f", videoInfo ,[item[@"VideoQualitySlider"] floatValue]]; + videoInfo = [NSString stringWithFormat:@"%@ Constant Quality: %.2f", videoInfo ,job.video.quality]; } - + [finalString appendString: @"Video: " withAttributes:detailBoldAttr]; [finalString appendString: videoInfo withAttributes:detailAttr]; [finalString appendString:@"\n" withAttributes:detailAttr]; - - if ([item[@"VideoEncoder"] isEqualToString: @"H.264 (x264)"] || [item[@"VideoEncoder"] isEqualToString: @"H.265 (x265)"]) + + + if (job.video.encoder == HB_VCODEC_X264 || job.video.encoder == HB_VCODEC_X265) { - /* we are using x264/x265 */ + // we are using x264/x265 NSString *encoderPresetInfo = @""; - if ([item[@"x264UseAdvancedOptions"] intValue]) + if (job.video.advancedOptions) { // we are using the old advanced panel - if (item[@"x264Option"] && - [item[@"x264Option"] length]) + if (job.video.videoOptionExtra.length) { - encoderPresetInfo = [encoderPresetInfo stringByAppendingString: item[@"x264Option"]]; + encoderPresetInfo = [encoderPresetInfo stringByAppendingString:job.video.videoOptionExtra]; } else { - encoderPresetInfo = [encoderPresetInfo stringByAppendingString: @"default settings"]; + encoderPresetInfo = [encoderPresetInfo stringByAppendingString:@"default settings"]; } } else { // we are using the x264 system - encoderPresetInfo = [encoderPresetInfo stringByAppendingString: [NSString stringWithFormat:@"Preset: %@", item[@"VideoPreset"]]]; - if ([item[@"VideoTune"] length]) + encoderPresetInfo = [encoderPresetInfo stringByAppendingString: [NSString stringWithFormat:@"Preset: %@", job.video.preset]]; + if (job.video.tune.length) { - encoderPresetInfo = [encoderPresetInfo stringByAppendingString: [NSString stringWithFormat:@" - Tune: %@", item[@"VideoTune"]]]; + encoderPresetInfo = [encoderPresetInfo stringByAppendingString: [NSString stringWithFormat:@" - Tune: %@", job.video.tune]]; } - if ([item[@"VideoOptionExtra"] length]) + if (job.video.videoOptionExtra.length) { - encoderPresetInfo = [encoderPresetInfo stringByAppendingString: [NSString stringWithFormat:@" - Options: %@", item[@"VideoOptionExtra"]]]; + encoderPresetInfo = [encoderPresetInfo stringByAppendingString: [NSString stringWithFormat:@" - Options: %@", job.video.videoOptionExtra]]; } - if ([item[@"VideoProfile"] length]) + if (job.video.profile.length) { - encoderPresetInfo = [encoderPresetInfo stringByAppendingString: [NSString stringWithFormat:@" - Profile: %@", item[@"VideoProfile"]]]; + encoderPresetInfo = [encoderPresetInfo stringByAppendingString: [NSString stringWithFormat:@" - Profile: %@", job.video.profile]]; } - if ([item[@"VideoLevel"] length]) + if (job.video.level.length) { - encoderPresetInfo = [encoderPresetInfo stringByAppendingString: [NSString stringWithFormat:@" - Level: %@", item[@"VideoLevel"]]]; + encoderPresetInfo = [encoderPresetInfo stringByAppendingString: [NSString stringWithFormat:@" - Level: %@", job.video.level]]; } } [finalString appendString: @"Encoder Options: " withAttributes:detailBoldAttr]; [finalString appendString: encoderPresetInfo withAttributes:detailAttr]; [finalString appendString:@"\n" withAttributes:detailAttr]; } - else if (![item[@"VideoEncoder"] isEqualToString: @"VP3 (Theora)"]) + else { - /* we are using libavcodec */ + // we are using libavcodec NSString *lavcInfo = @""; - if (item[@"VideoOptionExtra"] && - [item[@"VideoOptionExtra"] length]) + if (job.video.videoOptionExtra.length) { - lavcInfo = [lavcInfo stringByAppendingString: item[@"VideoOptionExtra"]]; + lavcInfo = [lavcInfo stringByAppendingString:job.video.videoOptionExtra]; } else { @@ -969,62 +969,63 @@ [finalString appendString:@"\n" withAttributes:detailAttr]; } - /* Seventh Line Audio Details*/ + + // Seventh Line Audio Details int audioDetailCount = 0; for (NSString *anAudioDetail in audioDetails) { audioDetailCount++; - if (0 < [anAudioDetail length]) { + if (anAudioDetail.length) { [finalString appendString: [NSString stringWithFormat: @"Audio Track %d ", audioDetailCount] withAttributes: detailBoldAttr]; [finalString appendString: anAudioDetail withAttributes: detailAttr]; [finalString appendString: @"\n" withAttributes: detailAttr]; } } - /* Eigth Line Auto Passthru Details */ + // Eigth Line Auto Passthru Details // only print Auto Passthru settings if we have an Auro Passthru output track if (autoPassthruPresent == YES) { NSString *autoPassthruFallback = @"", *autoPassthruCodecs = @""; - NSDictionary *audioDefaults = item[@"AudioDefaults"]; - autoPassthruFallback = [autoPassthruFallback stringByAppendingString: audioDefaults[@"AudioEncoderFallback"]]; - if (0 < [audioDefaults[@"AudioAllowAACPass"] intValue]) + HBAudioDefaults *audioDefaults = job.audioDefaults; + autoPassthruFallback = [autoPassthruFallback stringByAppendingString:@(hb_audio_encoder_get_name(audioDefaults.encoderFallback))]; + if (audioDefaults.allowAACPassthru) { - autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString: @"AAC"]; + autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString:@"AAC"]; } - if (0 < [audioDefaults[@"AudioAllowAC3Pass"] intValue]) + if (audioDefaults.allowAC3Passthru) { - if (0 < [autoPassthruCodecs length]) + if (autoPassthruCodecs.length) { - autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString: @", "]; + autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString:@", "]; } - autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString: @"AC3"]; + autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString:@"AC3"]; } - if (0 < [audioDefaults[@"AudioAllowDTSHDPass"] intValue]) + if (audioDefaults.allowDTSHDPassthru) { - if (0 < [autoPassthruCodecs length]) + if (autoPassthruCodecs.length) { - autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString: @", "]; + autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString:@", "]; } - autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString: @"DTS-HD"]; + autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString:@"DTS-HD"]; } - if (0 < [audioDefaults[@"AudioAllowDTSPass"] intValue]) + if (audioDefaults.allowDTSPassthru) { - if (0 < [autoPassthruCodecs length]) + if (autoPassthruCodecs.length) { - autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString: @", "]; + autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString:@", "]; } - autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString: @"DTS"]; + autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString:@"DTS"]; } - if (0 < [audioDefaults[@"AudioAllowMP3Pass"] intValue]) + if (audioDefaults.allowMP3Passthru) { - if (0 < [autoPassthruCodecs length]) + if (autoPassthruCodecs.length) { - autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString: @", "]; + autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString:@", "]; } - autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString: @"MP3"]; + autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString:@"MP3"]; } [finalString appendString: @"Auto Passthru Codecs: " withAttributes: detailBoldAttr]; - if (0 < [autoPassthruCodecs length]) + if (autoPassthruCodecs.length) { [finalString appendString: autoPassthruCodecs withAttributes: detailAttr]; } @@ -1037,22 +1038,22 @@ [finalString appendString: autoPassthruFallback withAttributes: detailAttr]; [finalString appendString: @"\n" withAttributes: detailAttr]; } - - /* Ninth Line Subtitle Details */ - for (id tempObject in item[@"SubtitleList"]) + + // Ninth Line Subtitle Details + for (NSDictionary *track in job.subtitlesTracks) { /* remember that index 0 of Subtitles can contain "Foreign Audio Search*/ [finalString appendString: @"Subtitle: " withAttributes:detailBoldAttr]; - [finalString appendString: tempObject[@"keySubTrackName"] withAttributes:detailAttr]; - if ([tempObject[@"keySubTrackForced"] intValue] == 1) + [finalString appendString: track[@"keySubTrackName"] withAttributes:detailAttr]; + if ([track[@"keySubTrackForced"] intValue] == 1) { [finalString appendString: @" - Forced Only" withAttributes:detailAttr]; } - if ([tempObject[@"keySubTrackBurned"] intValue] == 1) + if ([track[@"keySubTrackBurned"] intValue] == 1) { [finalString appendString: @" - Burned In" withAttributes:detailAttr]; } - if ([tempObject[@"keySubTrackDefault"] intValue] == 1) + if ([track[@"keySubTrackDefault"] intValue] == 1) { [finalString appendString: @" - Default" withAttributes:detailAttr]; } @@ -1065,15 +1066,16 @@ } else if ([[tableColumn identifier] isEqualToString:@"icon"]) { - if ([item[@"Status"] intValue] == 0) + HBJob *job = item; + if (job.state == HBJobStateCompleted) { return [NSImage imageNamed:@"EncodeComplete"]; } - else if ([item[@"Status"] intValue] == 1) + else if (job.state == HBJobStateWorking) { return [NSImage imageNamed: [NSString stringWithFormat: @"EncodeWorking%d", fAnimationIndex]]; } - else if ([item[@"Status"] intValue] == 3) + else if (job.state == HBJobStateCanceled) { return [NSImage imageNamed:@"EncodeCanceled"]; } @@ -1081,7 +1083,6 @@ { return [NSImage imageNamed:@"JobSmall"]; } - } else { @@ -1103,8 +1104,9 @@ { [cell setEnabled: YES]; BOOL highlighted = [outlineView isRowSelected:[outlineView rowForItem: item]] && [[outlineView window] isKeyWindow] && ([[outlineView window] firstResponder] == outlineView); - - if ([item[@"Status"] intValue] == 0 || ([item[@"Status"] intValue] == 1 && [item[@"EncodingPID"] intValue] != pidNum)) + + HBJob *job = item; + if (job.state == HBJobStateWorking && job.pidId != pidNum) { [cell setAction: @selector(revealSelectedQueueItem:)]; if (highlighted) @@ -1152,7 +1154,7 @@ - (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard { // Dragging is only allowed of the pending items. - if ([items[0][@"Status"] integerValue] != 2) // 2 is pending + if ([items[0] state] != HBJobStateReady) // 2 is pending { return NO; } @@ -1206,7 +1208,7 @@ { NSMutableIndexSet *moveItems = [NSMutableIndexSet indexSet]; - for( id obj in fDraggedNodes ) + for (id obj in fDraggedNodes) [moveItems addIndex:[fJobGroups indexOfObject:obj]]; // Successful drop, we use moveObjectsInQueueArray:... in fHBController diff --git a/macosx/HBRange.h b/macosx/HBRange.h index 65a185ec1..bbffb2ede 100644 --- a/macosx/HBRange.h +++ b/macosx/HBRange.h @@ -14,7 +14,7 @@ typedef NS_ENUM(NSUInteger, HBRangeType) { HBRangeTypeSeconds, }; -@interface HBRange : NSObject <NSCoding> +@interface HBRange : NSObject <NSCoding, NSCopying> - (instancetype)initWithTitle:(HBTitle *)title; diff --git a/macosx/HBRange.m b/macosx/HBRange.m index 731fcebf7..83df24b66 100644 --- a/macosx/HBRange.m +++ b/macosx/HBRange.m @@ -77,6 +77,26 @@ return retval; } +#pragma mark - NSCopying + +- (instancetype)copyWithZone:(NSZone *)zone +{ + HBRange *copy = [[[self class] alloc] init]; + + if (copy) + { + copy->_type = _type; + copy->_chapterStart = _chapterStart; + copy->_chapterStop = _chapterStop; + copy->_secondsStart = _secondsStart; + copy->_secondsStop = _secondsStop; + copy->_frameStart = _frameStart; + copy->_frameStop = _frameStop; + } + + return copy; +} + #pragma mark - NSCoding - (void)encodeWithCoder:(NSCoder *)coder diff --git a/macosx/HBSubtitlesController.h b/macosx/HBSubtitlesController.h index d44d514b1..56fc0dcb8 100644 --- a/macosx/HBSubtitlesController.h +++ b/macosx/HBSubtitlesController.h @@ -29,12 +29,8 @@ extern NSString *keySubTrackSrtCharCode; */ @interface HBSubtitlesController : NSViewController <HBViewValidation> -- (void)addTracksFromQueue:(NSArray *)queueSubtitleArray; - (void)applySettingsFromPreset:(NSDictionary *)preset; @property (nonatomic, readwrite, assign) HBJob *job; -// Get the list of subtitles tracks -@property (readonly, nonatomic, copy) NSArray *subtitles; - @end diff --git a/macosx/HBSubtitlesController.m b/macosx/HBSubtitlesController.m index 05eafa537..590093f5a 100644 --- a/macosx/HBSubtitlesController.m +++ b/macosx/HBSubtitlesController.m @@ -113,38 +113,22 @@ NSString *keySubTrackLanguageIndex = @"keySubTrackLanguageIndex"; { self.subtitleArray = job.subtitlesTracks; self.settings = job.subtitlesDefaults; - hb_title_t *title = job.title.hb_title; + self.subtitleSourceArray = [[job.title.subtitlesTracks mutableCopy] autorelease]; - /* now populate the array with the source subtitle track info */ - NSMutableArray *forcedSourceNamesArray = [[NSMutableArray alloc] init]; - for (int i = 0; i < hb_list_count(title->list_subtitle); i++) + NSMutableArray *forcedSourceNamesArray = [NSMutableArray array]; + for (NSDictionary *dict in self.subtitleSourceArray) { - hb_subtitle_t *subtitle = (hb_subtitle_t *)hb_list_item(title->list_subtitle, i); - - /* Human-readable representation of subtitle->source */ - NSString *bitmapOrText = subtitle->format == PICTURESUB ? @"Bitmap" : @"Text"; - NSString *subSourceName = @(hb_subsource_name(subtitle->source)); - - /* if the subtitle track can be forced, add its source name to the array */ - if (hb_subtitle_can_force(subtitle->source) && [forcedSourceNamesArray containsObject:subSourceName] == NO) + enum subsource source = [dict[keySubTrackType] intValue]; + NSString *subSourceName = @(hb_subsource_name(source)); + // if the subtitle track can be forced, add its source name to the array + if (hb_subtitle_can_force(source) && [forcedSourceNamesArray containsObject:subSourceName] == NO) { [forcedSourceNamesArray addObject:subSourceName]; } - - // Use the native language name if available - iso639_lang_t *language = lang_for_code2(subtitle->iso639_2); - NSString *nativeLanguage = strlen(language->native_name) ? @(language->native_name) : @(language->eng_name); - - /* create a dictionary of source subtitle information to store in our array */ - [self.subtitleSourceArray addObject:@{keySubTrackName: [NSString stringWithFormat:@"%d: %@ (%@) (%@)", i, nativeLanguage, bitmapOrText, subSourceName], - keySubTrackIndex: @(i), - keySubTrackType: @(subtitle->source), - keySubTrackLanguage: nativeLanguage, - keySubTrackLanguageIsoCode: @(subtitle->iso639_2)}]; } - /* now set the name of the Foreign Audio Search track */ - if ([forcedSourceNamesArray count]) + // now set the name of the Foreign Audio Search track + if (forcedSourceNamesArray.count) { [forcedSourceNamesArray sortUsingComparator:^(id obj1, id obj2) { @@ -154,7 +138,7 @@ NSString *keySubTrackLanguageIndex = @"keySubTrackLanguageIndex"; NSString *tempList = @""; for (NSString *tempString in forcedSourceNamesArray) { - if ([tempList length]) + if (tempList.length) { tempList = [tempList stringByAppendingString:@", "]; } @@ -166,7 +150,23 @@ NSString *keySubTrackLanguageIndex = @"keySubTrackLanguageIndex"; { self.foreignAudioSearchTrackName = @"Foreign Audio Search (Bitmap)"; } - [forcedSourceNamesArray release]; + + // Note: we need to look for external subtitles so it can be added to the source array track. + // Remember the source container subs are already loaded with resetTitle which is already called + // so any external sub sources need to be added to our source subs here + for (NSDictionary *dict in self.subtitleArray) + { + /* We have an srt track */ + if ([dict[keySubTrackType] intValue] == SRTSUB) + { + NSString *filePath = dict[keySubTrackSrtFilePath]; + /* create a dictionary of source subtitle information to store in our array */ + [self.subtitleSourceArray addObject:@{keySubTrackIndex: @(self.subtitleSourceArray.count + 1), + keySubTrackName: [filePath lastPathComponent], + keySubTrackType: @(SRTSUB), + keySubTrackSrtFilePath: filePath}]; + } + } // Append an empty track at the end // to display a "None" row in the table view @@ -186,43 +186,8 @@ NSString *keySubTrackLanguageIndex = @"keySubTrackLanguageIndex"; [self.fTableView reloadData]; } -- (NSArray *)subtitles -{ - NSMutableArray *ret = [self.subtitleArray mutableCopy]; - [ret removeLastObject]; - return [ret autorelease]; -} - -- (void)addTracksFromQueue:(NSArray *)queueSubtitleArray -{ - /* Note: we need to look for external subtitles so it can be added to the source array track. - * Remember the source container subs are already loaded with resetTitle which is already called - * so any external sub sources need to be added to our source subs here - */ - for (id tempObject in queueSubtitleArray) - { - /* We have an srt track */ - if ([tempObject[keySubTrackType] intValue] == SRTSUB) - { - NSString *filePath = tempObject[keySubTrackSrtFilePath]; - /* create a dictionary of source subtitle information to store in our array */ - [self.subtitleSourceArray addObject:@{keySubTrackIndex: @(self.subtitleSourceArray.count + 1), - keySubTrackName: [filePath lastPathComponent], - keySubTrackType: @(SRTSUB), - keySubTrackSrtFilePath: filePath}]; - } - } - - // Set the subtitleArray to the newSubtitleArray - [self.subtitleArray setArray:queueSubtitleArray]; - [self.subtitleArray addObject:[self createSubtitleTrack]]; - [self.fTableView reloadData]; -} - - (void)applySettingsFromPreset:(NSDictionary *)preset { - [self.settings applySettingsFromPreset:preset]; - [self addTracksFromDefaults:self]; } diff --git a/macosx/HBSubtitlesDefaults.h b/macosx/HBSubtitlesDefaults.h index b09da8127..ab65a20b3 100644 --- a/macosx/HBSubtitlesDefaults.h +++ b/macosx/HBSubtitlesDefaults.h @@ -5,6 +5,7 @@ It may be used under the terms of the GNU General Public License. */ #import <Foundation/Foundation.h> +#import "HBPresetCoding.h" typedef NS_ENUM(NSUInteger, HBSubtitleTrackSelectionBehavior) { HBSubtitleTrackSelectionBehaviorNone, @@ -12,7 +13,7 @@ typedef NS_ENUM(NSUInteger, HBSubtitleTrackSelectionBehavior) { HBSubtitleTrackSelectionBehaviorAll, }; -@interface HBSubtitlesDefaults : NSObject <NSCoding> +@interface HBSubtitlesDefaults : NSObject <NSCoding, NSCopying, HBPresetCoding> @property (nonatomic, readwrite) HBSubtitleTrackSelectionBehavior trackSelectionBehavior; @property (nonatomic, readwrite, retain) NSMutableArray *trackSelectionLanguages; @@ -21,7 +22,4 @@ typedef NS_ENUM(NSUInteger, HBSubtitleTrackSelectionBehavior) { @property (nonatomic, readwrite) BOOL addForeignAudioSubtitle; @property (nonatomic, readwrite) BOOL addCC; -- (void)applySettingsFromPreset:(NSDictionary *)preset; -- (void)prepareSubtitlesDefaultsForPreset:(NSMutableDictionary *)preset; - @end diff --git a/macosx/HBSubtitlesDefaults.m b/macosx/HBSubtitlesDefaults.m index efcd49c8d..359b19ea2 100644 --- a/macosx/HBSubtitlesDefaults.m +++ b/macosx/HBSubtitlesDefaults.m @@ -19,7 +19,7 @@ return self; } -- (void)applySettingsFromPreset:(NSDictionary *)preset +- (void)applyPreset:(NSDictionary *)preset { if ([preset[@"SubtitleTrackSelectionBehavior"] isEqualToString:@"first"]) { @@ -39,7 +39,7 @@ self.addForeignAudioSubtitle = [preset[@"SubtitleAddForeignAudioSubtitle"] boolValue]; } -- (void)prepareSubtitlesDefaultsForPreset:(NSMutableDictionary *)preset +- (void)writeToPreset:(NSMutableDictionary *)preset { if (self.trackSelectionBehavior == HBSubtitleTrackSelectionBehaviorFirst) { @@ -60,6 +60,26 @@ preset[@"SubtitleAddForeignAudioSubtitle"] = @(self.addForeignAudioSubtitle); } +#pragma mark - NSCopying + +- (instancetype)copyWithZone:(NSZone *)zone +{ + HBSubtitlesDefaults *copy = [[[self class] alloc] init]; + + if (copy) + { + copy->_trackSelectionBehavior = _trackSelectionBehavior; + [copy->_trackSelectionLanguages release]; + copy->_trackSelectionLanguages = [_trackSelectionLanguages mutableCopy]; + + copy->_addForeignAudioSearch = _addForeignAudioSearch; + copy->_addForeignAudioSubtitle = _addForeignAudioSubtitle; + copy->_addCC = _addCC; + } + + return copy; +} + #pragma mark - NSCoding - (void)encodeWithCoder:(NSCoder *)coder diff --git a/macosx/HBTitle.m b/macosx/HBTitle.m index 6d179e383..c2f6dc305 100644 --- a/macosx/HBTitle.m +++ b/macosx/HBTitle.m @@ -74,7 +74,15 @@ extern NSString *keySubTrackSrtCharCode; { if (!_name) { - _name = [@(self.hb_title->name) retain]; + _name = @(self.hb_title->name); + + // If the name is empty use file/directory name + if (_name.length == 0) + { + _name = [@(self.hb_title->path) lastPathComponent]; + } + + [_name retain]; } return _name; @@ -146,26 +154,17 @@ extern NSString *keySubTrackSrtCharCode; { NSMutableArray *tracks = [NSMutableArray array]; hb_subtitle_t *subtitle; - hb_list_t *list = self.hb_title->list_audio; + hb_list_t *list = self.hb_title->list_subtitle; int count = hb_list_count(list); - NSMutableArray *forcedSourceNamesArray = [[NSMutableArray alloc] init]; - //NSString *foreignAudioSearchTrackName = nil; - for (int i = 0; i < count; i++) { - subtitle = (hb_subtitle_t *)hb_list_item(self.hb_title->list_subtitle, i); + subtitle = (hb_subtitle_t *) hb_list_item(self.hb_title->list_subtitle, i); /* Human-readable representation of subtitle->source */ NSString *bitmapOrText = subtitle->format == PICTURESUB ? @"Bitmap" : @"Text"; NSString *subSourceName = @(hb_subsource_name(subtitle->source)); - /* if the subtitle track can be forced, add its source name to the array */ - if (hb_subtitle_can_force(subtitle->source) && [forcedSourceNamesArray containsObject:subSourceName] == NO) - { - [forcedSourceNamesArray addObject:subSourceName]; - } - // Use the native language name if available iso639_lang_t *language = lang_for_code2(subtitle->iso639_2); NSString *nativeLanguage = strlen(language->native_name) ? @(language->native_name) : @(language->eng_name); @@ -178,31 +177,6 @@ extern NSString *keySubTrackSrtCharCode; keySubTrackLanguageIsoCode: @(subtitle->iso639_2)}]; } - /* now set the name of the Foreign Audio Search track */ - if ([forcedSourceNamesArray count]) - { - [forcedSourceNamesArray sortUsingComparator:^(id obj1, id obj2) - { - return [((NSString *)obj1) compare:((NSString *)obj2)]; - }]; - - NSString *tempList = @""; - for (NSString *tempString in forcedSourceNamesArray) - { - if ([tempList length]) - { - tempList = [tempList stringByAppendingString:@", "]; - } - tempList = [tempList stringByAppendingString:tempString]; - } - //foreignAudioSearchTrackName = [NSString stringWithFormat:@"Foreign Audio Search (Bitmap) (%@)", tempList]; - } - else - { - //foreignAudioSearchTrackName = @"Foreign Audio Search (Bitmap)"; - } - [forcedSourceNamesArray release]; - _subtitlesTracks = [tracks copy]; } diff --git a/macosx/HBVideo.h b/macosx/HBVideo.h index 5936c8803..9e7b2631e 100644 --- a/macosx/HBVideo.h +++ b/macosx/HBVideo.h @@ -5,24 +5,19 @@ It may be used under the terms of the GNU General Public License. */ #import <Foundation/Foundation.h> +#import "HBPresetCoding.h" @class HBJob; /** * HBVideo */ -@interface HBVideo : NSObject <NSCoding> +@interface HBVideo : NSObject <NSCoding, NSCopying, HBPresetCoding> - (instancetype)initWithJob:(HBJob *)job; - (void)containerChanged; -- (void)applySettingsFromPreset:(NSDictionary *)preset; -- (void)prepareVideoForPreset:(NSMutableDictionary *)preset; - -- (void)applyVideoSettingsFromQueue:(NSDictionary *)queueToApply; -- (void)prepareVideoForQueueFileJob:(NSMutableDictionary *)queueFileJob; - @property (nonatomic, readwrite) int encoder; @property (nonatomic, readwrite) int qualityType; diff --git a/macosx/HBVideo.m b/macosx/HBVideo.m index 208ac9b17..4810fc397 100644 --- a/macosx/HBVideo.m +++ b/macosx/HBVideo.m @@ -244,6 +244,41 @@ return [[temp copy] autorelease]; } +#pragma mark - NSCopying + +- (instancetype)copyWithZone:(NSZone *)zone +{ + HBVideo *copy = [[[self class] alloc] init]; + + if (copy) + { + copy->_encoder = _encoder; + + copy->_qualityType = _qualityType; + copy->_avgBitrate = _avgBitrate; + copy->_quality = _quality; + + copy->_qualityMinValue = _qualityMinValue; + copy->_qualityMaxValue = _qualityMaxValue; + + copy->_frameRate = _frameRate; + copy->_frameRateMode = _frameRateMode; + + copy->_twoPass = _twoPass; + copy->_turboTwoPass = _turboTwoPass; + + copy->_advancedOptions = _advancedOptions; + copy->_preset = [_preset copy]; + copy->_tune = [_tune copy]; + copy->_profile = [_profile copy]; + copy->_level = [_level copy]; + copy->_videoOptionExtra = [_videoOptionExtra copy]; + copy->_fastDecode = _fastDecode; + } + + return copy; +} + #pragma mark - NSCoding - (void)encodeWithCoder:(NSCoder *)coder @@ -256,6 +291,9 @@ encodeInt(_avgBitrate); encodeDouble(_quality); + encodeDouble(_qualityMinValue); + encodeDouble(_qualityMaxValue); + encodeInt(_frameRate); encodeInt(_frameRateMode); @@ -283,6 +321,9 @@ decodeInt(_avgBitrate); decodeDouble(_quality); + decodeDouble(_qualityMinValue); + decodeDouble(_qualityMaxValue); + decodeInt(_frameRate); decodeInt(_frameRateMode); @@ -341,7 +382,7 @@ return [string autorelease]; } -- (void)applySettingsFromPreset:(NSDictionary *)preset +- (void)applyPreset:(NSDictionary *)preset { // map legacy encoder names via libhb. const char *strValue = hb_video_encoder_sanitize_name([preset[@"VideoEncoder"] UTF8String]); @@ -481,7 +522,7 @@ self.turboTwoPass = [preset[@"VideoTurboTwoPass"] intValue]; } -- (void)prepareVideoForPreset:(NSMutableDictionary *)preset +- (void)writeToPreset:(NSMutableDictionary *)preset { preset[@"VideoEncoder"] = @(hb_video_encoder_get_name(self.encoder)); @@ -544,137 +585,4 @@ preset[@"VideoTurboTwoPass"] = @(self.turboTwoPass); } -- (void)applyVideoSettingsFromQueue:(NSDictionary *)queueToApply -{ - // Video encoder - self.encoder = [queueToApply[@"JobVideoEncoderVcodec"] intValue]; - - // Advanced x264 options - if ([queueToApply[@"x264UseAdvancedOptions"] intValue]) - { - // we are using the advanced panel - self.preset = @"medium"; - self.tune = nil; - self.profile = nil; - self.level = nil; - self.videoOptionExtra = queueToApply[@"x264Option"]; - self.advancedOptions = YES; - } - else if (self.encoder == HB_VCODEC_X264 || self.encoder == HB_VCODEC_X265) - { - // we are using the x264 preset system - self.preset = queueToApply[@"VideoPreset"]; - self.tune = queueToApply[@"VideoTune"]; - self.videoOptionExtra = queueToApply[@"VideoOptionExtra"]; - self.profile = queueToApply[@"VideoProfile"]; - self.level = queueToApply[@"VideoLevel"]; - } - else - { - self.videoOptionExtra = queueToApply[@"VideoOptionExtra"]; - } - - self.qualityType = [queueToApply[@"VideoQualityType"] intValue] - 1; - - self.avgBitrate = [queueToApply[@"VideoAvgBitrate"] intValue]; - self.quality = [queueToApply[@"VideoQualitySlider"] doubleValue]; - - // Video framerate - if ([queueToApply[@"JobIndexVideoFramerate"] intValue] == 0) - { - // Now set the Video Frame Rate Mode to either vfr or cfr according to the preset - if ([queueToApply[@"VideoFramerateMode"] isEqualToString:@"vfr"]) - { - self.frameRateMode = 0; // we want vfr - } - else - { - self.frameRateMode = 1; // we want cfr - } - } - else - { - // Now set the Video Frame Rate Mode to either pfr or cfr according to the preset - if ([queueToApply[@"VideoFramerateMode"] isEqualToString:@"pfr"]) - { - self.frameRateMode = 0; // we want pfr - } - else - { - self.frameRateMode = 1; // we want cfr - } - } - - self.frameRate = hb_video_framerate_get_from_name([queueToApply[@"VideoFramerate"] UTF8String]); - - self.twoPass = [queueToApply[@"VideoTwoPass"] intValue]; - self.turboTwoPass = [queueToApply[@"VideoTurboTwoPass"] intValue]; -} - -- (void)prepareVideoForQueueFileJob:(NSMutableDictionary *)queueFileJob -{ - // Video encoder. - queueFileJob[@"VideoEncoder"] = @(hb_video_encoder_get_name(self.encoder)); - queueFileJob[@"JobVideoEncoderVcodec"] = @(self.encoder); - - // x264 advanced options. - if (self.advancedOptions) - { - // we are using the advanced panel - queueFileJob[@"x264UseAdvancedOptions"] = @1; - queueFileJob[@"x264Option"] = self.videoOptionExtra; - } - else if (self.encoder == HB_VCODEC_X264 || self.encoder == HB_VCODEC_X265) - { - // we are using the x264/x265 preset system. - queueFileJob[@"x264UseAdvancedOptions"] = @0; - queueFileJob[@"VideoPreset"] = self.preset; - queueFileJob[@"VideoTune"] = [self completeTune]; - queueFileJob[@"VideoOptionExtra"] = self.videoOptionExtra; - queueFileJob[@"VideoProfile"] = self.profile; - queueFileJob[@"VideoLevel"] = self.level; - } - else - { - // FFmpeg (lavc) Option String. - queueFileJob[@"VideoOptionExtra"] = self.videoOptionExtra; - } - - queueFileJob[@"VideoQualityType"] = @(self.qualityType + 1); - queueFileJob[@"VideoAvgBitrate"] = @(self.avgBitrate); - queueFileJob[@"VideoQualitySlider"] = @(self.quality); - - // Framerate - if (self.frameRate) - { - queueFileJob[@"VideoFramerate"] = @(hb_video_framerate_get_name(self.frameRate)); - } - else - { - queueFileJob[@"VideoFramerate"] = @"Same as source"; - } - queueFileJob[@"JobIndexVideoFramerate"] = @(self.frameRate); - - // Frame Rate Mode - if (self.frameRateMode == 1) // if selected we are cfr regardless of the frame rate popup - { - queueFileJob[@"VideoFramerateMode"] = @"cfr"; - } - else - { - if (self.frameRate == 0) // Same as source frame rate - { - queueFileJob[@"VideoFramerateMode"] = @"vfr"; - } - else - { - queueFileJob[@"VideoFramerateMode"] = @"pfr"; - } - } - - // 2 Pass Encoding - queueFileJob[@"VideoTwoPass"] = @(self.twoPass); - queueFileJob[@"VideoTurboTwoPass"] = @(self.turboTwoPass); -} - @end diff --git a/macosx/HandBrake.xcodeproj/project.pbxproj b/macosx/HandBrake.xcodeproj/project.pbxproj index c587bde9b..809678aad 100644 --- a/macosx/HandBrake.xcodeproj/project.pbxproj +++ b/macosx/HandBrake.xcodeproj/project.pbxproj @@ -401,6 +401,7 @@ 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>"; }; A9935212196F38A70069C6B7 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = ChaptersTitles.xib; sourceTree = "<group>"; }; + A997D8EB1A4ABB0900E19B6F /* HBPresetCoding.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HBPresetCoding.h; sourceTree = "<group>"; }; A9A2A77F1A4737DD006C219C /* NSCodingMacro.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSCodingMacro.h; sourceTree = "<group>"; }; A9AA44781970664A00D7DEFC /* HBUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBUtilities.h; sourceTree = "<group>"; }; A9AA44791970664A00D7DEFC /* HBUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBUtilities.m; sourceTree = "<group>"; }; @@ -911,6 +912,7 @@ 273F209814ADBE670021BE6D /* HBDVDDetector.m */, A9537BED1A48A7F900141102 /* UI Bindings Additions */, A9A2A77F1A4737DD006C219C /* NSCodingMacro.h */, + A997D8EB1A4ABB0900E19B6F /* HBPresetCoding.h */, ); name = Core; sourceTree = "<group>"; diff --git a/macosx/NSCodingMacro.h b/macosx/NSCodingMacro.h index 7cfbfc755..842da1121 100644 --- a/macosx/NSCodingMacro.h +++ b/macosx/NSCodingMacro.h @@ -18,6 +18,6 @@ #define decodeInteger(x) x = [decoder decodeIntegerForKey:OBJC_STRINGIFY(x)] #define decodeBool(x) x = [decoder decodeBoolForKey:OBJC_STRINGIFY(x)] #define decodeDouble(x) x = [decoder decodeDoubleForKey:OBJC_STRINGIFY(x)] -#define decodeObject(x) x = [decoder decodeObjectForKey:OBJC_STRINGIFY(x)] +#define decodeObject(x) x = [[decoder decodeObjectForKey:OBJC_STRINGIFY(x)] retain] #endif |