X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=macosx%2FController.m;h=92d31a822057b045c6dd824ba4f0cd29e6d660ad;hb=4b72a63eb61a01275493c4bfb51ba02152d1c5e1;hp=42b7a247651b804c41a183b6cd958eccc1bfb587;hpb=49d4a820f33a63fc9ae1948d26677a036ab261bf;p=handbrake-jp%2Fhandbrake-jp-git.git diff --git a/macosx/Controller.m b/macosx/Controller.m index 42b7a247..92d31a82 100644 --- a/macosx/Controller.m +++ b/macosx/Controller.m @@ -4,6 +4,7 @@ Homepage: . It may be used under the terms of the GNU General Public License. */ +#include #import "Controller.h" #import "HBOutputPanelController.h" #import "HBPreferencesController.h" @@ -11,6 +12,12 @@ #import "HBPresets.h" #import "HBPreviewController.h" +unsigned int maximumNumberOfAllowedAudioTracks = 24; +NSString *HBContainerChangedNotification = @"HBContainerChangedNotification"; +NSString *keyContainerTag = @"keyContainerTag"; +NSString *HBTitleChangedNotification = @"HBTitleChangedNotification"; +NSString *keyTitleTag = @"keyTitleTag"; + #define DragDropSimplePboardType @"MyCustomOutlineViewPboardType" /* We setup the toolbar values here ShowPreviewIdentifier */ @@ -30,6 +37,8 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It *******************************/ @implementation HBController ++ (unsigned int) maximumNumberOfAllowedAudioTracks { return maximumNumberOfAllowedAudioTracks; } + - (id)init { self = [super init]; @@ -82,7 +91,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It fPreferencesController = [[HBPreferencesController alloc] init]; /* Lets report the HandBrake version number here to the activity log and text log file */ NSString *versionStringFull = [[NSString stringWithFormat: @"Handbrake Version: %@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]] stringByAppendingString: [NSString stringWithFormat: @" (%@)", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]]]; - [self writeToActivityLog: "%s", [versionStringFull UTF8String]]; + [self writeToActivityLog: "%s", [versionStringFull UTF8String]]; return self; } @@ -117,16 +126,58 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It [fSubtitlesTable setDelegate:fSubtitlesDelegate]; [fSubtitlesTable setRowHeight:25.0]; + /* setup the audio controller */ + [fAudioDelegate setHBController: self]; + [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(autoSetM4vExtension:) name: HBMixdownChangedNotification object: nil]; + [fPresetsOutlineView setAutosaveName:@"Presets View"]; [fPresetsOutlineView setAutosaveExpandedItems:YES]; dockIconProgress = 0; - + + /* Init QueueFile .plist */ + [self loadQueueFile]; + /* Run hbInstances to get any info on other instances as well as set the + * pid number for this instance in the case of multi-instance encoding. */ + hbInstanceNum = [self hbInstances]; + + /* If we are a single instance it is safe to clean up the previews if there are any + * left over. This is a bit of a kludge but will prevent a build up of old instance + * live preview cruft. No danger of removing an active preview directory since they + * are created later in HBPreviewController if they don't exist at the moment a live + * preview encode is initiated. */ + if (hbInstanceNum == 1) + { + NSString *PreviewDirectory = [NSString stringWithFormat:@"~/Library/Application Support/HandBrake/Previews"]; + PreviewDirectory = [PreviewDirectory stringByExpandingTildeInPath]; + NSError *error; + NSArray *files = [ [NSFileManager defaultManager] contentsOfDirectoryAtPath: PreviewDirectory error: &error ]; + for( NSString *file in files ) + { + if( file != @"." && file != @".." ) + { + [ [NSFileManager defaultManager] removeItemAtPath: [ PreviewDirectory stringByAppendingPathComponent: file ] error: &error ]; + if( error ) + { + //an error occurred... + [self writeToActivityLog: "Could not remove existing preview at : %s",[file UTF8String] ]; + } + } + } + + } + + + /* Call UpdateUI every 1/2 sec */ + [[NSRunLoop currentRunLoop] addTimer:[NSTimer - scheduledTimerWithTimeInterval:0.5 target:self - selector:@selector(updateUI:) userInfo:nil repeats:YES] - forMode:NSDefaultRunLoopMode]; + scheduledTimerWithTimeInterval:0.5 + target:self + selector:@selector(updateUI:) + userInfo:nil repeats:YES] + forMode:NSDefaultRunLoopMode]; + // Open debug output window now if it was visible when HB was closed if ([[NSUserDefaults standardUserDefaults] boolForKey:@"OutputPanelIsOpen"]) @@ -164,11 +215,11 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It /* We check to see if there is already another instance of hb running. * Note: hbInstances == 1 means we are the only instance of HandBrake.app */ - if ([self hbInstances] > 1) + if (hbInstanceNum > 1) { - alertTitle = [NSString stringWithFormat: - NSLocalizedString(@"There is already an instance of HandBrake running.", @"")]; - NSBeginCriticalAlertSheet( + alertTitle = [NSString stringWithFormat: + NSLocalizedString(@"There is already an instance of HandBrake running.", @"")]; + NSBeginCriticalAlertSheet( alertTitle, NSLocalizedString(@"Reload Queue", nil), nil, @@ -179,29 +230,48 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It } else { - if (fWorkingCount > 0) + if (fWorkingCount > 0 || fPendingCount > 0) { - alertTitle = [NSString stringWithFormat: - NSLocalizedString(@"HandBrake Has Detected %d Previously Encoding Item and %d Pending Item(s) In Your Queue.", @""), - fWorkingCount,fPendingCount]; + if (fWorkingCount > 0) + { + alertTitle = [NSString stringWithFormat: + NSLocalizedString(@"HandBrake Has Detected %d Previously Encoding Item(s) and %d Pending Item(s) In Your Queue.", @""), + fWorkingCount,fPendingCount]; + } + else + { + alertTitle = [NSString stringWithFormat: + NSLocalizedString(@"HandBrake Has Detected %d Pending Item(s) In Your Queue.", @""), + fPendingCount]; + } + + NSBeginCriticalAlertSheet( + alertTitle, + NSLocalizedString(@"Reload Queue", nil), + nil, + NSLocalizedString(@"Empty Queue", nil), + fWindow, self, + nil, @selector(didDimissReloadQueue:returnCode:contextInfo:), nil, + NSLocalizedString(@" Do you want to reload them ?", nil)); } else { - alertTitle = [NSString stringWithFormat: - NSLocalizedString(@"HandBrake Has Detected %d Pending Item(s) In Your Queue.", @""), - fPendingCount]; + /* Since we addressed any pending or previously encoding items above, we go ahead and make sure the queue + * is empty of any finished items or cancelled items */ + [self clearQueueAllItems]; + /* We show whichever open source window specified in LaunchSourceBehavior preference key */ + if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"LaunchSourceBehavior"] isEqualToString: @"Open Source"]) + { + [self browseSources:nil]; + } + + if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"LaunchSourceBehavior"] isEqualToString: @"Open Source (Title Specific)"]) + { + [self browseSources:(id)fOpenSourceTitleMMenu]; + } } - NSBeginCriticalAlertSheet( - alertTitle, - NSLocalizedString(@"Reload Queue", nil), - nil, - NSLocalizedString(@"Empty Queue", nil), - fWindow, self, - nil, @selector(didDimissReloadQueue:returnCode:contextInfo:), nil, - NSLocalizedString(@" Do you want to reload them ?", nil)); } - } else { @@ -216,29 +286,67 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It [self browseSources:(id)fOpenSourceTitleMMenu]; } } + currentQueueEncodeNameString = @""; } +#pragma mark - +#pragma mark Multiple Instances + +/* hbInstances checks to see if other instances of HB are running and also sets the pid for this instance for multi-instance queue encoding */ + + /* Note for now since we are in early phases of multi-instance I have put in quite a bit of logging. Can be removed as we see fit. */ - (int) hbInstances { /* check to see if another instance of HandBrake.app is running */ NSArray *runningAppDictionaries = [[NSWorkspace sharedWorkspace] launchedApplications]; - NSDictionary *aDictionary; + NSDictionary *runningAppsDictionary; int hbInstances = 0; - for (aDictionary in runningAppDictionaries) + NSString * thisInstanceAppPath = [[NSBundle mainBundle] bundlePath]; + NSString * runningInstanceAppPath; + int runningInstancePidNum; + [self writeToActivityLog: "hbInstances path to this instance: %s", [thisInstanceAppPath UTF8String]]; + for (runningAppsDictionary in runningAppDictionaries) { - if ([[aDictionary valueForKey:@"NSApplicationName"] isEqualToString:@"HandBrake"]) + if ([[runningAppsDictionary valueForKey:@"NSApplicationName"] isEqualToString:@"HandBrake"]) { + /*Report the path to each active instances app path */ + runningInstancePidNum = [[runningAppsDictionary valueForKey:@"NSApplicationProcessIdentifier"] intValue]; + runningInstanceAppPath = [runningAppsDictionary valueForKey:@"NSApplicationPath"]; + [self writeToActivityLog: "hbInstance found instance pidnum:%d at path: %s", runningInstancePidNum, [runningInstanceAppPath UTF8String]]; + /* see if this is us by comparing the app path */ + if ([runningInstanceAppPath isEqualToString: thisInstanceAppPath]) + { + /* If so this is our pidnum */ + [self writeToActivityLog: "hbInstance MATCH FOUND, our pidnum is:%d", runningInstancePidNum]; + /* Get the PID number for this hb instance, used in multi instance encoding */ + pidNum = runningInstancePidNum; + /* Report this pid to the activity log */ + [self writeToActivityLog: "Pid for this instance:%d", pidNum]; + /* Tell fQueueController what our pidNum is */ + [fQueueController setPidNum:pidNum]; + } hbInstances++; - } - } + } + } return hbInstances; } +- (int) getPidnum +{ + return pidNum; +} + +#pragma mark - + - (void) didDimissReloadQueue: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo { + + [self writeToActivityLog: "didDimissReloadQueue number of hb instances:%d", hbInstanceNum]; if (returnCode == NSAlertOtherReturn) { + [self writeToActivityLog: "didDimissReloadQueue NSAlertOtherReturn Chosen"]; [self clearQueueAllItems]; + /* We show whichever open source window specified in LaunchSourceBehavior preference key */ if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"LaunchSourceBehavior"] isEqualToString: @"Open Source"]) { @@ -252,8 +360,10 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It } else { - if ([self hbInstances] == 1) + [self writeToActivityLog: "didDimissReloadQueue First Button Chosen"]; + if (hbInstanceNum == 1) { + [self setQueueEncodingItemsAsPending]; } [self showQueueWindow:NULL]; @@ -301,7 +411,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It - (void)applicationWillTerminate:(NSNotification *)aNotification { - + [currentQueueEncodeNameString release]; [browsedSourceDisplayName release]; [outputPanel release]; [fQueueController release]; @@ -335,9 +445,6 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It /* Init UserPresets .plist */ [self loadPresets]; - - /* Init QueueFile .plist */ - [self loadQueueFile]; fRipIndicatorShown = NO; // initially out of view in the nib @@ -454,26 +561,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It /* Set Auto Crop to On at launch */ [fPictureController setAutoCrop:YES]; - - /* Audio bitrate */ - [fAudTrack1BitratePopUp removeAllItems]; - for( int i = 0; i < hb_audio_bitrates_count; i++ ) - { - [fAudTrack1BitratePopUp addItemWithTitle: - [NSString stringWithUTF8String: hb_audio_bitrates[i].string]]; - - } - [fAudTrack1BitratePopUp selectItemAtIndex: hb_audio_bitrates_default]; - - /* Audio samplerate */ - [fAudTrack1RatePopUp removeAllItems]; - for( int i = 0; i < hb_audio_rates_count; i++ ) - { - [fAudTrack1RatePopUp addItemWithTitle: - [NSString stringWithUTF8String: hb_audio_rates[i].string]]; - } - [fAudTrack1RatePopUp selectItemAtIndex: hb_audio_rates_default]; - + /* Bottom */ [fStatusField setStringValue: @""]; @@ -489,8 +577,6 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It [self getDefaultPresets:nil]; /* lets initialize the current successful scancount here to 0 */ currentSuccessfulScanCount = 0; - - } - (void) enableUI: (bool) b @@ -502,19 +588,11 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It fDstFormatField, fDstFormatPopUp, fDstFile1Field, fDstFile2Field, fDstBrowseButton, fVidRateField, fVidRatePopUp,fVidEncoderField, fVidEncoderPopUp, fVidQualityField, fPictureSizeField,fPictureCroppingField, fVideoFiltersField,fVidQualityMatrix, fSubField, fSubPopUp, - fAudSourceLabel, fAudCodecLabel, fAudMixdownLabel, fAudSamplerateLabel, fAudBitrateLabel, - fAudTrack1Label, fAudTrack2Label, fAudTrack3Label, fAudTrack4Label, - fAudLang1PopUp, fAudLang2PopUp, fAudLang3PopUp, fAudLang4PopUp, - fAudTrack1CodecPopUp, fAudTrack2CodecPopUp, fAudTrack3CodecPopUp, fAudTrack4CodecPopUp, - fAudTrack1MixPopUp, fAudTrack2MixPopUp, fAudTrack3MixPopUp, fAudTrack4MixPopUp, - fAudTrack1RatePopUp, fAudTrack2RatePopUp, fAudTrack3RatePopUp, fAudTrack4RatePopUp, - fAudTrack1BitratePopUp, fAudTrack2BitratePopUp, fAudTrack3BitratePopUp, fAudTrack4BitratePopUp, - fAudDrcLabel, fAudTrack1DrcSlider, fAudTrack1DrcField, fAudTrack2DrcSlider, - fAudTrack2DrcField, fAudTrack3DrcSlider, fAudTrack3DrcField, fAudTrack4DrcSlider,fAudTrack4DrcField, fQueueStatus,fPresetsAdd,fPresetsDelete,fSrcAngleLabel,fSrcAnglePopUp, fCreateChapterMarkers,fVidTurboPassCheck,fDstMp4LargeFileCheck,fSubForcedCheck,fPresetsOutlineView, - fAudDrcLabel,fDstMp4HttpOptFileCheck,fDstMp4iPodFileCheck,fVidQualityRFField,fVidQualityRFLabel, - fEncodeStartStopPopUp,fSrcTimeStartEncodingField,fSrcTimeEndEncodingField,fSrcFrameStartEncodingField,fSrcFrameEndEncodingField}; + fDstMp4HttpOptFileCheck,fDstMp4iPodFileCheck,fVidQualityRFField,fVidQualityRFLabel, + fEncodeStartStopPopUp,fSrcTimeStartEncodingField,fSrcTimeEndEncodingField,fSrcFrameStartEncodingField, + fSrcFrameEndEncodingField, fLoadChaptersButton, fSaveChaptersButton, fFrameratePfrCheck}; for( unsigned i = 0; i < sizeof( controls ) / sizeof( NSControl * ); i++ ) @@ -533,19 +611,20 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It } - if (b) { + if (b) + { - /* if we're enabling the interface, check if the audio mixdown controls need to be enabled or not */ - /* these will have been enabled by the mass control enablement above anyway, so we're sense-checking it here */ - [self setEnabledStateOfAudioMixdownControls:nil]; /* we also call calculatePictureSizing here to sense check if we already have vfr selected */ [self calculatePictureSizing:nil]; - - } else { + /* Also enable the preview window hud controls */ + [fPictureController enablePreviewHudControls]; + } + else + { [fPresetsOutlineView setEnabled: NO]; - - } + [fPictureController disablePreviewHudControls]; + } [self videoMatrixChanged:nil]; [fAdvancedOptions enableUI:b]; @@ -756,10 +835,10 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It break; } #undef p - + #define p s.param.working - + case HB_STATE_SEARCHING: { NSMutableString * string; @@ -806,7 +885,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It break; } - + case HB_STATE_WORKING: { NSMutableString * string; @@ -828,7 +907,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It pass_desc = @""; } - string = [NSMutableString stringWithFormat: NSLocalizedString( @"Encoding: pass %d %@ of %d, %.2f %%", @"" ), p.job_cur, pass_desc, p.job_count, 100.0 * p.progress]; + string = [NSMutableString stringWithFormat: NSLocalizedString( @"Encoding: %@ \nPass %d %@ of %d, %.2f %%", @"" ), currentQueueEncodeNameString, p.job_cur, pass_desc, p.job_count, 100.0 * p.progress]; if( p.seconds > -1 ) { @@ -836,10 +915,9 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It NSLocalizedString( @" (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)", @"" ), p.rate_cur, p.rate_avg, p.hours, p.minutes, p.seconds]; } - [fStatusField setStringValue: string]; - /* Set the status string in fQueueController as well */ - [fQueueController setQueueStatusString: string]; + [fQueueController setQueueStatusString:string]; + /* Update slider */ CGFloat progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count; [fRipIndicator setIndeterminate: NO]; @@ -860,14 +938,14 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It fRipIndicatorShown = YES; } - + /* Update dock icon */ if( dockIconProgress < 100.0 * progress_total ) { [self UpdateDockIcon: progress_total]; dockIconProgress += 5; } - + break; } #undef p @@ -938,62 +1016,39 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It pathOfFinishedEncode = [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"DestinationPath"]; /* Both the Growl Alert and Sending to MetaX can be done as encodes roll off the queue */ - /* Growl alert */ - [self showGrowlDoneNotification:pathOfFinishedEncode]; - /* Send to MetaX */ - [self sendToMetaX:pathOfFinishedEncode]; - - /* since we have successfully completed an encode, we increment the queue counter */ - [self incrementQueueItemDone:nil]; - - /* all end of queue actions below need to be done after all queue encodes have finished - * and there are no pending jobs left to process - */ - if (fPendingCount == 0) + if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Growl Notification"] || + [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window And Growl"]) { - /* If Alert Window or Window and Growl has been selected */ - if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window"] || - [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window And Growl"] ) + /* If Play System Alert has been selected in Preferences */ + if( [[NSUserDefaults standardUserDefaults] boolForKey:@"AlertWhenDoneSound"] == YES ) { - /*On Screen Notification*/ - int status; NSBeep(); - status = NSRunAlertPanel(@"Put down that cocktail...",@"Your HandBrake queue is done!", @"OK", nil, nil); - [NSApp requestUserAttention:NSCriticalRequest]; - } - - /* If sleep has been selected */ - if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Put Computer To Sleep"] ) - { - /* Sleep */ - NSDictionary* errorDict; - NSAppleEventDescriptor* returnDescriptor = nil; - NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource: - @"tell application \"Finder\" to sleep"]; - returnDescriptor = [scriptObject executeAndReturnError: &errorDict]; - [scriptObject release]; - } - /* If Shutdown has been selected */ - if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Shut Down Computer"] ) - { - /* Shut Down */ - NSDictionary* errorDict; - NSAppleEventDescriptor* returnDescriptor = nil; - NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource: - @"tell application \"Finder\" to shut down"]; - returnDescriptor = [scriptObject executeAndReturnError: &errorDict]; - [scriptObject release]; } - + [self showGrowlDoneNotification:pathOfFinishedEncode]; } + /* Send to MetaX */ + [self sendToMetaX:pathOfFinishedEncode]; + /* since we have successfully completed an encode, we increment the queue counter */ + [self incrementQueueItemDone:currentQueueEncodeIndex]; + } break; } } + /* Since we can use multiple instance off of the same queue file it is imperative that we keep the QueueFileArray updated off of the QueueFile.plist + * so we go ahead and do it in this existing timer as opposed to using a new one */ + + NSMutableArray * tempQueueArray = [[NSMutableArray alloc] initWithContentsOfFile:QueueFile]; + [QueueFileArray setArray:tempQueueArray]; + [tempQueueArray release]; + /* Send Fresh QueueFileArray to fQueueController to update queue window */ + [fQueueController setQueueArray: QueueFileArray]; + [self getQueueStats]; + } /* We use this to write messages to stderr from the macgui which show up in the activity window and log*/ @@ -1349,23 +1404,19 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It -(void)showGrowlDoneNotification:(NSString *) filePath { /* This end of encode action is called as each encode rolls off of the queue */ + /* Setup the Growl stuff ... */ NSString * finishedEncode = filePath; /* strip off the path to just show the file name */ finishedEncode = [finishedEncode lastPathComponent]; - if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Growl Notification"] || - [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window And Growl"]) - { - NSString * growlMssg = [NSString stringWithFormat: @"your HandBrake encode %@ is done!",finishedEncode]; - [GrowlApplicationBridge - notifyWithTitle:@"Put down that cocktail..." - description:growlMssg - notificationName:SERVICE_NAME - iconData:nil - priority:0 - isSticky:1 - clickContext:nil]; - } - + NSString * growlMssg = [NSString stringWithFormat: @"your HandBrake encode %@ is done!",finishedEncode]; + [GrowlApplicationBridge + notifyWithTitle:@"Put down that cocktail..." + description:growlMssg + notificationName:SERVICE_NAME + iconData:nil + priority:0 + isSticky:1 + clickContext:nil]; } -(void)sendToMetaX:(NSString *) filePath { @@ -1383,6 +1434,49 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It } } + +- (void) queueCompletedAlerts +{ + /* If Play System Alert has been selected in Preferences */ + if( [[NSUserDefaults standardUserDefaults] boolForKey:@"AlertWhenDoneSound"] == YES ) + { + NSBeep(); + } + + /* If Alert Window or Window and Growl has been selected */ + if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window"] || + [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window And Growl"] ) + { + /*On Screen Notification*/ + int status; + status = NSRunAlertPanel(@"Put down that cocktail...",@"Your HandBrake queue is done!", @"OK", nil, nil); + [NSApp requestUserAttention:NSCriticalRequest]; + } + + /* If sleep has been selected */ + if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Put Computer To Sleep"] ) + { + /* Sleep */ + NSDictionary* errorDict; + NSAppleEventDescriptor* returnDescriptor = nil; + NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource: + @"tell application \"Finder\" to sleep"]; + returnDescriptor = [scriptObject executeAndReturnError: &errorDict]; + [scriptObject release]; + } + /* If Shutdown has been selected */ + if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Shut Down Computer"] ) + { + /* Shut Down */ + NSDictionary* errorDict; + NSAppleEventDescriptor* returnDescriptor = nil; + NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource: + @"tell application \"Finder\" to shut down"]; + returnDescriptor = [scriptObject executeAndReturnError: &errorDict]; + [scriptObject release]; + } +} + #pragma mark - #pragma mark Get New Source @@ -1610,35 +1704,32 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It [fSubtitlesDelegate resetWithTitle:nil]; [fSubtitlesTable reloadData]; + // Notify anyone interested (audio controller) that there's no title + [[NSNotificationCenter defaultCenter] postNotification: + [NSNotification notificationWithName: HBTitleChangedNotification + object: self + userInfo: [NSDictionary dictionaryWithObjectsAndKeys: + [NSData dataWithBytesNoCopy: &fTitle length: sizeof(fTitle) freeWhenDone: NO], keyTitleTag, + nil]]]; + [self enableUI: NO]; if( [detector isVideoDVD] ) { - int hb_arch; -#if defined( __LP64__ ) - /* we are 64 bit */ - hb_arch = 64; -#else - /* we are 32 bit */ - hb_arch = 32; -#endif - - // The chosen path was actually on a DVD, so use the raw block // device path instead. path = [detector devicePath]; [self writeToActivityLog: "trying to open a physical dvd at: %s", [scanPath UTF8String]]; /* lets check for vlc here to make sure we have a dylib available to use for decrypting */ - NSString *vlcPath = @"/Applications/VLC.app/Contents/MacOS/lib/libdvdcss.2.dylib"; - NSFileManager * fileManager = [NSFileManager defaultManager]; - if ([fileManager fileExistsAtPath:vlcPath] == 0) - { - /*vlc not found in /Applications so we set the bool to cancel scanning to 1 */ + void *dvdcss = dlopen("libdvdcss.2.dylib", RTLD_LAZY); + if (dvdcss == NULL) + { + /*compatible vlc not found, so we set the bool to cancel scanning to 1 */ cancelScanDecrypt = 1; [self writeToActivityLog: "VLC app not found for decrypting physical dvd"]; int status; - status = NSRunAlertPanel(@"HandBrake could not find VLC or your VLC is out of date.",@"Please download and install VLC media player in your /Applications folder if you wish to read encrypted DVDs.", @"Get VLC", @"Cancel Scan", @"Attempt Scan Anyway"); + status = NSRunAlertPanel(@"HandBrake could not find VLC or your VLC is incompatible (Note: 32 bit vlc is not compatible with 64 bit HandBrake and vice-versa).",@"Please download and install VLC media player if you wish to read encrypted DVDs.", @"Get VLC", @"Cancel Scan", @"Attempt Scan Anyway"); [NSApp requestUserAttention:NSCriticalRequest]; if (status == NSAlertDefaultReturn) @@ -1664,111 +1755,8 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It /* VLC was found in /Applications so all is well, we can carry on using vlc's libdvdcss.dylib for decrypting if needed */ [self writeToActivityLog: "VLC app found for decrypting physical dvd"]; vlcFound = 1; + dlclose(dvdcss); } - /* test for architecture of the vlc app */ - NSArray *vlc_architecturesArray = [[NSBundle bundleWithPath:@"/Applications/VLC.app"] executableArchitectures]; - BOOL vlcIntel32bit = NO; - BOOL vlcIntel64bit = NO; - BOOL vlcPPC32bit = NO; - BOOL vlcPPC64bit = NO; - /* check the available architectures for vlc and note accordingly */ - NSEnumerator *enumerator = [vlc_architecturesArray objectEnumerator]; - id tempObject; - while (tempObject = [enumerator nextObject]) - { - - if ([tempObject intValue] == NSBundleExecutableArchitectureI386) - { - vlcIntel32bit = YES; - } - if ([tempObject intValue] == NSBundleExecutableArchitectureX86_64) - { - vlcIntel64bit = YES; - } - if ([tempObject intValue] == NSBundleExecutableArchitecturePPC) - { - vlcPPC32bit = YES; - } - if ([tempObject intValue] == NSBundleExecutableArchitecturePPC64) - { - vlcPPC64bit = YES; - } - - } - /* Write vlc architecture findings to activity window */ - if (vlcIntel32bit) - { - [self writeToActivityLog: " 32-Bit VLC app found for decrypting physical dvd"]; - } - if (vlcIntel64bit) - { - [self writeToActivityLog: " 64-Bit VLC app found for decrypting physical dvd"]; - } - - - - if (vlcFound && hb_arch == 64 && !vlcIntel64bit && cancelScanDecrypt != 1) - { - - /* we are 64 bit */ - - /* Appropriate VLC not found, so cancel */ - cancelScanDecrypt = 1; - [self writeToActivityLog: "This version of HandBrake is 64 bit, 64 bit version of vlc not found, scan cancelled"]; - /*On Screen Notification*/ - int status; - NSBeep(); - status = NSRunAlertPanel(@"This version of HandBrake is 64 bit, VLC found but not 64 bit!",@"", @"Cancel Scan", @"Attempt Scan Anyway", @"Get 64 bit VLC", nil); - [NSApp requestUserAttention:NSCriticalRequest]; - - if (status == NSAlertDefaultReturn) - { - /* User chose to cancel the scan */ - [self writeToActivityLog: "cannot open physical dvd VLC found but not 64 bit, scan cancelled"]; - cancelScanDecrypt = 1; - } - else if (status == NSAlertAlternateReturn) - { - [self writeToActivityLog: "user overrode 64-bit warning trying to open physical dvd without proper decryption"]; - cancelScanDecrypt = 0; - } - else - { - /* User chose to go download vlc (as they rightfully should) so we send them to the vlc site */ - [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.videolan.org/vlc/download-macosx.html"]]; - } - - } - else if (vlcFound && hb_arch == 32 && !vlcIntel32bit && cancelScanDecrypt != 1) - { - /* we are 32 bit */ - /* Appropriate VLC not found, so cancel */ - cancelScanDecrypt = 1; - [self writeToActivityLog: "This version of HandBrake is 32 bit, 32 bit version of vlc not found, scan cancelled"]; - /*On Screen Notification*/ - int status; - NSBeep(); - status = NSRunAlertPanel(@"This version of HandBrake is 32 bit, VLC found but not 32 bit!",@"", @"Cancel Scan", @"Attempt Scan Anyway", @"Get 32 bit VLC", nil); - [NSApp requestUserAttention:NSCriticalRequest]; - - if (status == NSAlertDefaultReturn) - { - /* User chose to cancel the scan */ - [self writeToActivityLog: "cannot open physical dvd VLC found but not 32 bit, scan cancelled"]; - cancelScanDecrypt = 1; - } - else if (status == NSAlertAlternateReturn) - { - [self writeToActivityLog: "user overrode 32-bit warning trying to open physical dvd without proper decryption"]; - cancelScanDecrypt = 0; - } - else - { - /* User chose to go download vlc (as they rightfully should) so we send them to the vlc site */ - [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.videolan.org/vlc/download-macosx.html"]]; - } - - } } if (cancelScanDecrypt == 0) @@ -1785,11 +1773,14 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It { [self writeToActivityLog: "scanning specifically for title: %d", scanTitleNum]; } - /* We use our advance pref to determine how many previews to scan */ + /* We use our advanced pref to determine how many previews to scan */ int hb_num_previews = [[[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewsNumber"] intValue]; + /* We use our advanced pref to determine the minimum title length to use in seconds*/ + uint64_t min_title_duration_seconds = 90000L * [[[NSUserDefaults standardUserDefaults] objectForKey:@"MinTitleScanSeconds"] intValue]; /* set title to NULL */ fTitle = NULL; - hb_scan( fHandle, [path UTF8String], scanTitleNum, hb_num_previews, 1 ); + [self writeToActivityLog: "Minimum length of title for scan: %d", min_title_duration_seconds]; + hb_scan( fHandle, [path UTF8String], scanTitleNum, hb_num_previews, 1 , min_title_duration_seconds ); [fSrcDVD2Field setStringValue:@"Scanning new source ..."]; } } @@ -1802,10 +1793,8 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It - (IBAction) showNewScan:(id)sender { hb_list_t * list; - hb_title_t * title; - int indxpri=0; // Used to search the longuest title (default in combobox) - int longuestpri=0; // Used to search the longuest title (default in combobox) - + hb_title_t * title = NULL; + int feature_title=0; // Used to store the main feature title list = hb_get_titles( fHandle ); @@ -1822,6 +1811,14 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It // Notify Subtitles that there's no title [fChapterTitlesDelegate resetWithTitle:nil]; [fChapterTable reloadData]; + + // Notify anyone interested (audio controller) that there's no title + [[NSNotificationCenter defaultCenter] postNotification: + [NSNotification notificationWithName: HBTitleChangedNotification + object: self + userInfo: [NSDictionary dictionaryWithObjectsAndKeys: + [NSData dataWithBytesNoCopy: &fTitle length: sizeof(fTitle) freeWhenDone: NO], keyTitleTag, + nil]]]; } else { @@ -1879,11 +1876,10 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It @"%@/Desktop/%@.mp4", NSHomeDirectory(),[browsedSourceDisplayName stringByDeletingPathExtension]]]; } - - if (longuestpri < title->hours*60*60 + title->minutes *60 + title->seconds) + /* See if this is the main feature according to libhb */ + if (title->index == title->job->feature) { - longuestpri=title->hours*60*60 + title->minutes *60 + title->seconds; - indxpri=i; + feature_title = i; } [fSrcTitlePopUp addItemWithTitle: [NSString @@ -1899,8 +1895,8 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It } else { - /* if not then select the longest title (dvd) */ - [fSrcTitlePopUp selectItemAtIndex: indxpri]; + /* if not then select the main feature title */ + [fSrcTitlePopUp selectItemAtIndex: feature_title]; } [self titlePopUpChanged:nil]; @@ -1980,12 +1976,9 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag { if( !flag ) { - [fWindow makeKeyAndOrderFront:nil]; - - return YES; + [fWindow makeKeyAndOrderFront:nil]; } - - return NO; + return YES; } - (NSSize) drawerWillResizeContents:(NSDrawer *) drawer toSize:(NSSize) contentSize { @@ -2002,53 +1995,38 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It /*We define the location of the user presets file */ QueueFile = @"~/Library/Application Support/HandBrake/Queue.plist"; QueueFile = [[QueueFile stringByExpandingTildeInPath]retain]; - /* We check for the presets.plist */ + /* We check for the Queue.plist */ if ([fileManager fileExistsAtPath:QueueFile] == 0) { [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 (nil == QueueFileArray) { /* if not, then lets initialize an empty array */ QueueFileArray = [[NSMutableArray alloc] init]; - - /* Initialize our curQueueEncodeIndex to 0 - * so we can use it to track which queue - * item is to be used to track our encodes */ - /* NOTE: this should be changed if and when we - * are able to get the last unfinished encode - * in the case of a crash or shutdown */ - - } + } else { - [self clearQueueEncodedItems]; + /* ONLY clear out encoded items if we are single instance */ + if (hbInstanceNum == 1) + { + [self clearQueueEncodedItems]; + } } - currentQueueEncodeIndex = 0; } - (void)addQueueFileItem { - [QueueFileArray addObject:[self createQueueFileItem]]; - [self saveQueueFileItem]; - + [QueueFileArray addObject:[self createQueueFileItem]]; + [self saveQueueFileItem]; + } - (void) removeQueueFileItem:(int) queueItemToRemove { - - /* Find out if the item we are removing is a cancelled (3) or a finished (0) item*/ - if ([[[QueueFileArray objectAtIndex:queueItemToRemove] objectForKey:@"Status"] intValue] == 3 || [[[QueueFileArray objectAtIndex:queueItemToRemove] objectForKey:@"Status"] intValue] == 0) - { - /* Since we are removing a cancelled or finished item, WE need to decrement the currentQueueEncodeIndex - * by one to keep in sync with the queue array - */ - currentQueueEncodeIndex--; - [self writeToActivityLog: "removeQueueFileItem: Removing a cancelled/finished encode, decrement currentQueueEncodeIndex to %d", currentQueueEncodeIndex]; - } [QueueFileArray removeObjectAtIndex:queueItemToRemove]; [self saveQueueFileItem]; @@ -2092,7 +2070,13 @@ fWorkingCount = 0; if ([[thisQueueDict objectForKey:@"Status"] intValue] == 1) // being encoded { fWorkingCount++; - fEncodingQueueItem = i; + fEncodingQueueItem = i; + /* check to see if we are the instance doing this encoding */ + if ([thisQueueDict objectForKey:@"EncodingPID"] && [[thisQueueDict objectForKey:@"EncodingPID"] intValue] == pidNum) + { + currentQueueEncodeIndex = i; + } + } if ([[thisQueueDict objectForKey:@"Status"] intValue] == 2) // pending { @@ -2109,15 +2093,39 @@ fWorkingCount = 0; NSMutableString * string; if (fPendingCount == 1) { - string = [NSMutableString stringWithFormat: NSLocalizedString( @"%d encode pending in the queue", @"" ), fPendingCount]; + string = [NSMutableString stringWithFormat: NSLocalizedString( @"%d encode pending", @"" ), fPendingCount]; } else { - string = [NSMutableString stringWithFormat: NSLocalizedString( @"%d encode(s) pending in the queue", @"" ), fPendingCount]; + string = [NSMutableString stringWithFormat: NSLocalizedString( @"%d encode(s) pending", @"" ), fPendingCount]; } [fQueueStatus setStringValue:string]; } +/* Used to get the next pending queue item index and return it if found */ +- (int)getNextPendingQueueIndex +{ + /* initialize nextPendingIndex to -1, this value tells incrementQueueItemDone that there are no pending items in the queue */ + int nextPendingIndex = -1; + BOOL nextPendingFound = NO; + NSEnumerator *enumerator = [QueueFileArray objectEnumerator]; + id tempObject; + int i = 0; + while (tempObject = [enumerator nextObject]) + { + NSDictionary *thisQueueDict = tempObject; + if ([[thisQueueDict objectForKey:@"Status"] intValue] == 2 && nextPendingFound == NO) // pending + { + nextPendingFound = YES; + nextPendingIndex = [QueueFileArray indexOfObject: tempObject]; + [self writeToActivityLog: "getNextPendingQueueIndex next pending encod index is:%d", nextPendingIndex]; + } + i++; + } + return nextPendingIndex; +} + + /* This method will set any item marked as encoding back to pending * currently used right after a queue reload */ @@ -2130,15 +2138,19 @@ fWorkingCount = 0; /* we look here to see if the preset is we move on to the next one */ while ( tempObject = [enumerator nextObject] ) { - /* 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) + /* 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) { - [tempObject setObject:[NSNumber numberWithInt: 2] forKey:@"Status"]; + /* 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) + { + [tempObject setObject:[NSNumber numberWithInt: 2] forKey:@"Status"]; + } + [tempArray addObject:tempObject]; } - [tempArray addObject:tempObject]; } [QueueFileArray setArray:tempArray]; @@ -2244,7 +2256,7 @@ fWorkingCount = 0; /* 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); + 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"]; @@ -2302,6 +2314,7 @@ fWorkingCount = 0; [queueFileJob setObject:[NSNumber numberWithFloat:[fVidQualityRFField floatValue]] forKey:@"VideoQualitySlider"]; /* Framerate */ [queueFileJob setObject:[fVidRatePopUp titleOfSelectedItem] forKey:@"VideoFramerate"]; + [queueFileJob setObject:[NSNumber numberWithInt:[fFrameratePfrCheck state]] forKey:@"VideoFrameratePFR"]; /* 2 Pass Encoding */ [queueFileJob setObject:[NSNumber numberWithInt:[fVidTwoPassCheck state]] forKey:@"VideoTwoPass"]; @@ -2360,46 +2373,7 @@ fWorkingCount = 0; [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController grayscale]] forKey:@"VideoGrayScale"]; /*Audio*/ - if ([fAudLang1PopUp indexOfSelectedItem] > 0) - { - [queueFileJob setObject:[NSNumber numberWithInt:[fAudLang1PopUp indexOfSelectedItem]] forKey:@"Audio1Track"]; - [queueFileJob setObject:[fAudLang1PopUp titleOfSelectedItem] forKey:@"Audio1TrackDescription"]; - [queueFileJob setObject:[fAudTrack1CodecPopUp titleOfSelectedItem] forKey:@"Audio1Encoder"]; - [queueFileJob setObject:[fAudTrack1MixPopUp titleOfSelectedItem] forKey:@"Audio1Mixdown"]; - [queueFileJob setObject:[fAudTrack1RatePopUp titleOfSelectedItem] forKey:@"Audio1Samplerate"]; - [queueFileJob setObject:[fAudTrack1BitratePopUp titleOfSelectedItem] forKey:@"Audio1Bitrate"]; - [queueFileJob setObject:[NSNumber numberWithFloat:[fAudTrack1DrcSlider floatValue]] forKey:@"Audio1TrackDRCSlider"]; - } - if ([fAudLang2PopUp indexOfSelectedItem] > 0) - { - [queueFileJob setObject:[NSNumber numberWithInt:[fAudLang2PopUp indexOfSelectedItem]] forKey:@"Audio2Track"]; - [queueFileJob setObject:[fAudLang2PopUp titleOfSelectedItem] forKey:@"Audio2TrackDescription"]; - [queueFileJob setObject:[fAudTrack2CodecPopUp titleOfSelectedItem] forKey:@"Audio2Encoder"]; - [queueFileJob setObject:[fAudTrack2MixPopUp titleOfSelectedItem] forKey:@"Audio2Mixdown"]; - [queueFileJob setObject:[fAudTrack2RatePopUp titleOfSelectedItem] forKey:@"Audio2Samplerate"]; - [queueFileJob setObject:[fAudTrack2BitratePopUp titleOfSelectedItem] forKey:@"Audio2Bitrate"]; - [queueFileJob setObject:[NSNumber numberWithFloat:[fAudTrack2DrcSlider floatValue]] forKey:@"Audio2TrackDRCSlider"]; - } - if ([fAudLang3PopUp indexOfSelectedItem] > 0) - { - [queueFileJob setObject:[NSNumber numberWithInt:[fAudLang3PopUp indexOfSelectedItem]] forKey:@"Audio3Track"]; - [queueFileJob setObject:[fAudLang3PopUp titleOfSelectedItem] forKey:@"Audio3TrackDescription"]; - [queueFileJob setObject:[fAudTrack3CodecPopUp titleOfSelectedItem] forKey:@"Audio3Encoder"]; - [queueFileJob setObject:[fAudTrack3MixPopUp titleOfSelectedItem] forKey:@"Audio3Mixdown"]; - [queueFileJob setObject:[fAudTrack3RatePopUp titleOfSelectedItem] forKey:@"Audio3Samplerate"]; - [queueFileJob setObject:[fAudTrack3BitratePopUp titleOfSelectedItem] forKey:@"Audio3Bitrate"]; - [queueFileJob setObject:[NSNumber numberWithFloat:[fAudTrack3DrcSlider floatValue]] forKey:@"Audio3TrackDRCSlider"]; - } - if ([fAudLang4PopUp indexOfSelectedItem] > 0) - { - [queueFileJob setObject:[NSNumber numberWithInt:[fAudLang4PopUp indexOfSelectedItem]] forKey:@"Audio4Track"]; - [queueFileJob setObject:[fAudLang4PopUp titleOfSelectedItem] forKey:@"Audio4TrackDescription"]; - [queueFileJob setObject:[fAudTrack4CodecPopUp titleOfSelectedItem] forKey:@"Audio4Encoder"]; - [queueFileJob setObject:[fAudTrack4MixPopUp titleOfSelectedItem] forKey:@"Audio4Mixdown"]; - [queueFileJob setObject:[fAudTrack4RatePopUp titleOfSelectedItem] forKey:@"Audio4Samplerate"]; - [queueFileJob setObject:[fAudTrack4BitratePopUp titleOfSelectedItem] forKey:@"Audio4Bitrate"]; - [queueFileJob setObject:[NSNumber numberWithFloat:[fAudTrack4DrcSlider floatValue]] forKey:@"Audio4TrackDRCSlider"]; - } + [fAudioDelegate prepareAudioForQueueFileJob: queueFileJob]; /* Subtitles*/ NSMutableArray *subtitlesArray = [[NSMutableArray alloc] initWithArray:[fSubtitlesDelegate getSubtitleArray] copyItems:YES]; @@ -2440,41 +2414,7 @@ fWorkingCount = 0; [queueFileJob setObject:[NSNumber numberWithInt:job->crop[3]] forKey:@"PictureRightCrop"]; - /*Audio*/ - if ([fAudLang1PopUp indexOfSelectedItem] > 0) - { - //[queueFileJob setObject:[fAudTrack1CodecPopUp indexOfSelectedItem] forKey:@"JobAudio1Encoder"]; - [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack1CodecPopUp selectedItem] tag]] forKey:@"JobAudio1Encoder"]; - [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack1MixPopUp selectedItem] tag]] forKey:@"JobAudio1Mixdown"]; - [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack1RatePopUp selectedItem] tag]] forKey:@"JobAudio1Samplerate"]; - [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack1BitratePopUp selectedItem] tag]] forKey:@"JobAudio1Bitrate"]; - } - if ([fAudLang2PopUp indexOfSelectedItem] > 0) - { - //[queueFileJob setObject:[fAudTrack1CodecPopUp indexOfSelectedItem] forKey:@"JobAudio2Encoder"]; - [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack2CodecPopUp selectedItem] tag]] forKey:@"JobAudio2Encoder"]; - [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack2MixPopUp selectedItem] tag]] forKey:@"JobAudio2Mixdown"]; - [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack2RatePopUp selectedItem] tag]] forKey:@"JobAudio2Samplerate"]; - [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack2BitratePopUp selectedItem] tag]] forKey:@"JobAudio2Bitrate"]; - } - if ([fAudLang3PopUp indexOfSelectedItem] > 0) - { - //[queueFileJob setObject:[fAudTrack1CodecPopUp indexOfSelectedItem] forKey:@"JobAudio3Encoder"]; - [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack3CodecPopUp selectedItem] tag]] forKey:@"JobAudio3Encoder"]; - [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack3MixPopUp selectedItem] tag]] forKey:@"JobAudio3Mixdown"]; - [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack3RatePopUp selectedItem] tag]] forKey:@"JobAudio3Samplerate"]; - [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack3BitratePopUp selectedItem] tag]] forKey:@"JobAudio3Bitrate"]; - } - if ([fAudLang4PopUp indexOfSelectedItem] > 0) - { - //[queueFileJob setObject:[fAudTrack1CodecPopUp indexOfSelectedItem] forKey:@"JobAudio4Encoder"]; - [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack4CodecPopUp selectedItem] tag]] forKey:@"JobAudio4Encoder"]; - [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack4MixPopUp selectedItem] tag]] forKey:@"JobAudio4Mixdown"]; - [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack4RatePopUp selectedItem] tag]] forKey:@"JobAudio4Samplerate"]; - [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack4BitratePopUp selectedItem] tag]] forKey:@"JobAudio4Bitrate"]; - } - /* we need to auto relase the queueFileJob and return it */ [queueFileJob autorelease]; return queueFileJob; @@ -2520,46 +2460,58 @@ fWorkingCount = 0; - (void) incrementQueueItemDone:(int) queueItemDoneIndexNum { - int i = currentQueueEncodeIndex; - [[QueueFileArray objectAtIndex:i] setObject:[NSNumber numberWithInt:0] forKey:@"Status"]; + /* 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 */ [self saveQueueFileItem]; - /* We Reload the New Table data for presets */ - //[fPresetsOutlineView reloadData]; /* Since we have now marked a queue item as done * we can go ahead and increment currentQueueEncodeIndex * so that if there is anything left in the queue we can * go ahead and move to the next item if we want to */ - currentQueueEncodeIndex++ ; - [self writeToActivityLog: "incrementQueueItemDone currentQueueEncodeIndex is incremented to: %d", currentQueueEncodeIndex]; int queueItems = [QueueFileArray count]; - /* If we still have more items in our queue, lets go to the next one */ - if (currentQueueEncodeIndex < queueItems) - { - [self writeToActivityLog: "incrementQueueItemDone currentQueueEncodeIndex is incremented to: %d", currentQueueEncodeIndex]; - [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]]; + /* Check to see if there are any more pending items in the queue */ + int newQueueItemIndex = [self getNextPendingQueueIndex]; + /* 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 */ + 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"]; + [self 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]]; + } else { - [self writeToActivityLog: "incrementQueueItemDone the %d item queue is complete", currentQueueEncodeIndex - 1]; + [self writeToActivityLog: "incrementQueueItemDone there are no more pending encodes"]; + /*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*/ - (void) performNewQueueScan:(NSString *) scanPath scanTitleNum: (int) scanTitleNum { - /* Tell HB to output a new activity log file for this encode */ + /* 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 */ + [self saveQueueFileItem]; - /* use a bool to determine whether or not we can decrypt using vlc */ + /* use a bool to determine whether or not we can decrypt using vlc */ BOOL cancelScanDecrypt = 0; /* set the bool so that showNewScan knows to apply the appropriate queue - * settings as this is a queue rescan - */ - //applyQueueToScan = YES; + * settings as this is a queue rescan + */ NSString *path = scanPath; HBDVDDetector *detector = [HBDVDDetector detectorForPath:path]; @@ -2571,10 +2523,9 @@ fWorkingCount = 0; [self writeToActivityLog: "trying to open a physical dvd at: %s", [scanPath UTF8String]]; /* lets check for vlc here to make sure we have a dylib available to use for decrypting */ - NSString *vlcPath = @"/Applications/VLC.app"; - NSFileManager * fileManager = [NSFileManager defaultManager]; - if ([fileManager fileExistsAtPath:vlcPath] == 0) - { + void *dvdcss = dlopen("libdvdcss.2.dylib", RTLD_LAZY); + if (dvdcss == NULL) + { /*vlc not found in /Applications so we set the bool to cancel scanning to 1 */ cancelScanDecrypt = 1; [self writeToActivityLog: "VLC app not found for decrypting physical dvd"]; @@ -2603,6 +2554,7 @@ fWorkingCount = 0; else { /* VLC was found in /Applications so all is well, we can carry on using vlc's libdvdcss.dylib for decrypting if needed */ + dlclose(dvdcss); [self writeToActivityLog: "VLC app found for decrypting physical dvd"]; } } @@ -2622,10 +2574,9 @@ fWorkingCount = 0; [self writeToActivityLog: "scanning specifically for title: %d", scanTitleNum]; } - [self writeToActivityLog: "performNewQueueScan currentQueueEncodeIndex is: %d", currentQueueEncodeIndex]; - /* We use our advance pref to determine how many previews to scan */ + /* We use our advance pref to determine how many previews to scan */ int hb_num_previews = [[[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewsNumber"] intValue]; - hb_scan( fQueueEncodeLibhb, [path UTF8String], scanTitleNum, hb_num_previews, 0 ); + hb_scan( fQueueEncodeLibhb, [path UTF8String], scanTitleNum, hb_num_previews, 0 , 0 ); } } @@ -2645,7 +2596,6 @@ fWorkingCount = 0; [self writeToActivityLog: "Preset: %s", [[queueToApply objectForKey:@"PresetName"] UTF8String]]; [self writeToActivityLog: "processNewQueueEncode number of passes expected is: %d", ([[queueToApply objectForKey:@"VideoTwoPass"] intValue] + 1)]; job->file = [[queueToApply objectForKey:@"DestinationPath"] UTF8String]; - //[self writeToActivityLog: "processNewQueueEncode sending to prepareJob"]; [self prepareJob]; /* @@ -2720,13 +2670,10 @@ fWorkingCount = 0; free(subtitle); } - /* We should be all setup so let 'er rip */ [self doRip]; } - - #pragma mark - #pragma mark Queue Item Editing @@ -2817,7 +2764,7 @@ fWorkingCount = 0; } [self videoMatrixChanged:nil]; - [self writeToActivityLog: "applyQueueSettingsToMainWindow: video matrix changed"]; + /* Video framerate */ /* For video preset video framerate, we want to make sure that Same as source does not conflict with the detected framerate in the fVidRatePopUp so we use index 0*/ @@ -2840,88 +2787,8 @@ fWorkingCount = 0; /* Now lets add our new tracks to the audio list here */ - if ([[queueToApply objectForKey:@"Audio1Track"] intValue] > 0) - { - [fAudLang1PopUp selectItemAtIndex: [[queueToApply objectForKey:@"Audio1Track"] intValue]]; - [self audioTrackPopUpChanged: fAudLang1PopUp]; - [fAudTrack1CodecPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio1Encoder"]]; - [self audioTrackPopUpChanged: fAudTrack1CodecPopUp]; - - [fAudTrack1MixPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio1Mixdown"]]; - - [fAudTrack1RatePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio1Samplerate"]]; - [fAudTrack1BitratePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio1Bitrate"]]; - - [fAudTrack1DrcSlider setFloatValue:[[queueToApply objectForKey:@"Audio1TrackDRCSlider"] floatValue]]; - [self audioDRCSliderChanged: fAudTrack1DrcSlider]; - } - else - { - [fAudLang1PopUp selectItemAtIndex: 0]; - [self audioTrackPopUpChanged: fAudLang1PopUp]; - } - if ([[queueToApply objectForKey:@"Audio2Track"] intValue] > 0) - { - [fAudLang2PopUp selectItemAtIndex: [[queueToApply objectForKey:@"Audio2Track"] intValue]]; - [self audioTrackPopUpChanged: fAudLang2PopUp]; - [fAudTrack2CodecPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio2Encoder"]]; - [self audioTrackPopUpChanged: fAudTrack2CodecPopUp]; - - [fAudTrack2MixPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio2Mixdown"]]; - - [fAudTrack2RatePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio2Samplerate"]]; - [fAudTrack2BitratePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio2Bitrate"]]; - - [fAudTrack2DrcSlider setFloatValue:[[queueToApply objectForKey:@"Audio2TrackDRCSlider"] floatValue]]; - [self audioDRCSliderChanged: fAudTrack2DrcSlider]; - } - else - { - [fAudLang2PopUp selectItemAtIndex: 0]; - [self audioTrackPopUpChanged: fAudLang2PopUp]; - } - if ([[queueToApply objectForKey:@"Audio3Track"] intValue] > 0) - { - [fAudLang3PopUp selectItemAtIndex: [[queueToApply objectForKey:@"Audio3Track"] intValue]]; - [self audioTrackPopUpChanged: fAudLang3PopUp]; - [fAudTrack3CodecPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio3Encoder"]]; - [self audioTrackPopUpChanged: fAudTrack3CodecPopUp]; - - [fAudTrack3MixPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio3Mixdown"]]; - - [fAudTrack3RatePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio3Samplerate"]]; - [fAudTrack3BitratePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio3Bitrate"]]; - - [fAudTrack3DrcSlider setFloatValue:[[queueToApply objectForKey:@"Audio3TrackDRCSlider"] floatValue]]; - [self audioDRCSliderChanged: fAudTrack3DrcSlider]; - } - else - { - [fAudLang3PopUp selectItemAtIndex: 0]; - [self audioTrackPopUpChanged: fAudLang3PopUp]; - } - if ([[queueToApply objectForKey:@"Audio4Track"] intValue] > 0) - { - [fAudLang4PopUp selectItemAtIndex: [[queueToApply objectForKey:@"Audio4Track"] intValue]]; - [self audioTrackPopUpChanged: fAudLang4PopUp]; - [fAudTrack4CodecPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio4Encoder"]]; - [self audioTrackPopUpChanged: fAudTrack4CodecPopUp]; - - [fAudTrack4MixPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio4Mixdown"]]; - - [fAudTrack4RatePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio4Samplerate"]]; - [fAudTrack4BitratePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio4Bitrate"]]; - - [fAudTrack4DrcSlider setFloatValue:[[queueToApply objectForKey:@"Audio4TrackDRCSlider"] floatValue]]; - [self audioDRCSliderChanged: fAudTrack4DrcSlider]; - } - else - { - [fAudLang4PopUp selectItemAtIndex: 0]; - [self audioTrackPopUpChanged: fAudLang4PopUp]; - } + [fAudioDelegate addTracksFromQueue: queueToApply]; - [self writeToActivityLog: "applyQueueSettingsToMainWindow: audio set up"]; /*Subtitles*/ /* Crashy crashy right now, working on it */ [fSubtitlesDelegate setNewSubtitles:[queueToApply objectForKey:@"SubtitleList"]]; @@ -2981,9 +2848,6 @@ fWorkingCount = 0; job->anamorphic.mode = [[queueToApply objectForKey:@"PicturePAR"] intValue]; job->modulus = [[queueToApply objectForKey:@"PictureModulus"] intValue]; - [self writeToActivityLog: "applyQueueSettingsToMainWindow: picture sizing set up"]; - - /* Filters */ /* We only allow *either* Decomb or Deinterlace. So check for the PictureDecombDeinterlace key. @@ -3081,10 +2945,9 @@ fWorkingCount = 0; [fPictureController SetTitle:fTitle]; [self calculatePictureSizing:nil]; - [self writeToActivityLog: "applyQueueSettingsToMainWindow: picture filters set up"]; /* somehow we need to figure out a way to tie the queue item to a preset if it used one */ //[queueFileJob setObject:[fPresetSelectedDisplay stringValue] forKey:@"PresetName"]; - // [queueFileJob setObject:[NSNumber numberWithInt:[fPresetsOutlineView selectedRow]] forKey:@"PresetIndexNum"]; + //[queueFileJob setObject:[NSNumber numberWithInt:[fPresetsOutlineView selectedRow]] forKey:@"PresetIndexNum"]; if ([queueToApply objectForKey:@"PresetIndexNum"]) // This item used a preset so insert that info { /* Deselect the currently selected Preset if there is one*/ @@ -3167,7 +3030,14 @@ fWorkingCount = 0; /* We are not same as source so we set job->cfr to 1 * to enable constant frame rate since user has specified * a specific framerate*/ - job->cfr = 1; + if ([fFrameratePfrCheck state] == 1) + { + job->cfr = 2; + } + else + { + job->cfr = 1; + } } else { @@ -3243,23 +3113,18 @@ bool one_burned = FALSE; [self writeToActivityLog: "Foreign Language Search: %d", 1]; job->indepth_scan = 1; - if (burned == 1 || job->mux != HB_MUX_MP4) + + if (burned != 1) { - if (burned != 1 && job->mux == HB_MUX_MKV) - { - 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; - + 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 { @@ -3307,17 +3172,10 @@ bool one_burned = FALSE; { hb_subtitle_config_t sub_config = subt->config; - if (!burned && job->mux == HB_MUX_MKV && - subt->format == PICTURESUB) + if ( !burned && subt->format == PICTURESUB ) { sub_config.dest = PASSTHRUSUB; } - else if (!burned && job->mux == HB_MUX_MP4 && - subt->format == PICTURESUB) - { - // Skip any non-burned vobsubs when output is mp4 - continue; - } else if ( burned && subt->format == PICTURESUB ) { // Only allow one subtitle to be burned into the video @@ -3341,83 +3199,7 @@ bool one_burned = FALSE; /* Audio tracks and mixdowns */ - /* Lets make sure there arent any erroneous audio tracks in the job list, so lets make sure its empty*/ - int audiotrack_count = hb_list_count(job->list_audio); - for( int i = 0; i < audiotrack_count;i++) - { - hb_audio_t * temp_audio = (hb_audio_t*) hb_list_item( job->list_audio, 0 ); - hb_list_rem(job->list_audio, temp_audio); - } - /* Now lets add our new tracks to the audio list here */ - if ([fAudLang1PopUp indexOfSelectedItem] > 0) - { - audio = (hb_audio_config_t *) calloc(1, sizeof(*audio)); - hb_audio_config_init(audio); - audio->in.track = [fAudLang1PopUp indexOfSelectedItem] - 1; - /* We go ahead and assign values to our audio->out. */ - audio->out.track = [fAudLang1PopUp indexOfSelectedItem] - 1; - audio->out.codec = [[fAudTrack1CodecPopUp selectedItem] tag]; - audio->out.mixdown = [[fAudTrack1MixPopUp selectedItem] tag]; - audio->out.bitrate = [[fAudTrack1BitratePopUp selectedItem] tag]; - audio->out.samplerate = [[fAudTrack1RatePopUp selectedItem] tag]; - audio->out.dynamic_range_compression = [fAudTrack1DrcField floatValue]; - - hb_audio_add( job, audio ); - free(audio); - } - if ([fAudLang2PopUp indexOfSelectedItem] > 0) - { - audio = (hb_audio_config_t *) calloc(1, sizeof(*audio)); - hb_audio_config_init(audio); - audio->in.track = [fAudLang2PopUp indexOfSelectedItem] - 1; - /* We go ahead and assign values to our audio->out. */ - audio->out.track = [fAudLang2PopUp indexOfSelectedItem] - 1; - audio->out.codec = [[fAudTrack2CodecPopUp selectedItem] tag]; - audio->out.mixdown = [[fAudTrack2MixPopUp selectedItem] tag]; - audio->out.bitrate = [[fAudTrack2BitratePopUp selectedItem] tag]; - audio->out.samplerate = [[fAudTrack2RatePopUp selectedItem] tag]; - audio->out.dynamic_range_compression = [fAudTrack2DrcField floatValue]; - - hb_audio_add( job, audio ); - free(audio); - - } - - if ([fAudLang3PopUp indexOfSelectedItem] > 0) - { - audio = (hb_audio_config_t *) calloc(1, sizeof(*audio)); - hb_audio_config_init(audio); - audio->in.track = [fAudLang3PopUp indexOfSelectedItem] - 1; - /* We go ahead and assign values to our audio->out. */ - audio->out.track = [fAudLang3PopUp indexOfSelectedItem] - 1; - audio->out.codec = [[fAudTrack3CodecPopUp selectedItem] tag]; - audio->out.mixdown = [[fAudTrack3MixPopUp selectedItem] tag]; - audio->out.bitrate = [[fAudTrack3BitratePopUp selectedItem] tag]; - audio->out.samplerate = [[fAudTrack3RatePopUp selectedItem] tag]; - audio->out.dynamic_range_compression = [fAudTrack3DrcField floatValue]; - - hb_audio_add( job, audio ); - free(audio); - - } - - if ([fAudLang4PopUp indexOfSelectedItem] > 0) - { - audio = (hb_audio_config_t *) calloc(1, sizeof(*audio)); - hb_audio_config_init(audio); - audio->in.track = [fAudLang4PopUp indexOfSelectedItem] - 1; - /* We go ahead and assign values to our audio->out. */ - audio->out.track = [fAudLang4PopUp indexOfSelectedItem] - 1; - audio->out.codec = [[fAudTrack4CodecPopUp selectedItem] tag]; - audio->out.mixdown = [[fAudTrack4MixPopUp selectedItem] tag]; - audio->out.bitrate = [[fAudTrack4BitratePopUp selectedItem] tag]; - audio->out.samplerate = [[fAudTrack4RatePopUp selectedItem] tag]; - audio->out.dynamic_range_compression = [fAudTrack4DrcField floatValue]; - - hb_audio_add( job, audio ); - free(audio); - - } + [fAudioDelegate prepareAudioForJob: job]; @@ -3444,6 +3226,7 @@ bool one_burned = FALSE; */ /* Detelecine */ + hb_filter_detelecine.settings = NULL; if ([fPictureController detelecine] == 1) { /* use a custom detelecine string */ @@ -3462,6 +3245,7 @@ bool one_burned = FALSE; { /* Decomb */ /* we add the custom string if present */ + hb_filter_decomb.settings = NULL; if ([fPictureController decomb] == 1) { /* use a custom decomb string */ @@ -3572,51 +3356,28 @@ bool one_burned = FALSE; /* we are pts based start / stop */ [self writeToActivityLog: "Start / Stop set to seconds ..."]; - /* Point A to Point B. Since we cannot get frame accurate start times, attempt to glean a semi-accurate start time based on a percentage of the - * scanned title time as per live preview, while in some cases inaccurate its the best I can do with what I have barring a pre-scan index afaik. - */ - /* Attempt to bastardize the live preview code to get a roughly 1 second accurate point a to point b encode ... */ + /* 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->start_at_preview = start_seconds; - /* The number of seek points equals the number of seconds announced in the title as that is our current granularity */ - //job->seek_points = [[queueToApply objectForKey:@"SourceTotalSeconds"] 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; - - /* A bunch of verbose activity log messages to check on what should be expected */ - [self writeToActivityLog: "point a to b should start at: %d seconds", start_seconds]; - [self writeToActivityLog: "point a to b should start at (hh:mm:ss): %d:%d:%d", start_seconds / 3600, ( start_seconds / 60 ) % 60,start_seconds % 60]; - [self writeToActivityLog: "point a to b duration: %d seconds", stop_seconds]; - [self writeToActivityLog: "point a to b duration (hh:mm:ss): %d:%d:%d", stop_seconds / 3600, ( stop_seconds / 60 ) % 60,stop_seconds % 60]; - [self writeToActivityLog: "point a to b should end at: %d seconds", start_seconds + stop_seconds]; - [self writeToActivityLog: "point a to b should end at (hh:mm:ss): %d:%d:%d", (start_seconds + stop_seconds) / 3600, ( (start_seconds + stop_seconds) / 60 ) % 60,(start_seconds + stop_seconds) % 60]; + } else if ([[queueToApply objectForKey:@"fEncodeStartStop"] intValue] == 2) { /* we are frame based start / stop */ [self writeToActivityLog: "Start / Stop set to frames ..."]; - /* Point A to Point B. Since we cannot get frame accurate start times, attempt to glean a semi-accurate start time based on a percentage of the - * scanned title time as per live preview, while in some cases inaccurate its the best I can do with what I have barring a pre-scan index afaik. - */ - /* Attempt to bastardize the live preview code to get a roughly 1 second accurate point a to point b encode ... */ - /* get the start seconds from the start seconds field */ + /* 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->start_at_preview = start_seconds; - /* The number of seek points equals the number of seconds announced in the title as that is our current granularity */ - //job->seek_points = [[queueToApply objectForKey:@"SourceTotalSeconds"] intValue]; job->frame_to_start = start_frame; - /* Stop seconds is actually the duration of encode, so subtract the end seconds from the start seconds */ + /* get the frame to stop on from the end frame field */ int stop_frame = [[queueToApply objectForKey:@"StopFrame"] intValue]; job->frame_to_stop = stop_frame; - - /* A bunch of verbose activity log messages to check on what should be expected */ - [self writeToActivityLog: "point a to b should start at frame %d", start_frame]; - [self writeToActivityLog: "point a to b duration: %d frames", stop_frame]; - [self writeToActivityLog: "point a to b should end at frame %d", start_frame + stop_frame]; + } @@ -3757,7 +3518,15 @@ bool one_burned = FALSE; /* We are not same as source so we set job->cfr to 1 * to enable constant frame rate since user has specified * a specific framerate*/ - job->cfr = 1; + + if ([[queueToApply objectForKey:@"VideoFrameratePFR"] intValue] == 1) + { + job->cfr = 2; + } + else + { + job->cfr = 1; + } } else { @@ -3839,22 +3608,18 @@ bool one_burned = FALSE; [self writeToActivityLog: "Foreign Language Search: %d", 1]; job->indepth_scan = 1; - if (burned == 1 || job->mux != HB_MUX_MP4) + + if (burned != 1) { - if (burned != 1 && job->mux == HB_MUX_MKV) - { - 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; + 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 { @@ -3903,17 +3668,10 @@ bool one_burned = FALSE; { hb_subtitle_config_t sub_config = subt->config; - if (!burned && job->mux == HB_MUX_MKV && - subt->format == PICTURESUB) + if ( !burned && subt->format == PICTURESUB ) { sub_config.dest = PASSTHRUSUB; } - else if (!burned && job->mux == HB_MUX_MP4 && - subt->format == PICTURESUB) - { - // Skip any non-burned vobsubs when output is mp4 - continue; - } else if ( burned && subt->format == PICTURESUB ) { // Only allow one subtitle to be burned into the video @@ -3943,75 +3701,25 @@ bool one_burned = FALSE; hb_list_rem(job->list_audio, temp_audio); } /* Now lets add our new tracks to the audio list here */ - if ([[queueToApply objectForKey:@"Audio1Track"] intValue] > 0) - { - audio = (hb_audio_config_t *) calloc(1, sizeof(*audio)); - hb_audio_config_init(audio); - audio->in.track = [[queueToApply objectForKey:@"Audio1Track"] intValue] - 1; - /* We go ahead and assign values to our audio->out. */ - audio->out.track = [[queueToApply objectForKey:@"Audio1Track"] intValue] - 1; - audio->out.codec = [[queueToApply objectForKey:@"JobAudio1Encoder"] intValue]; - audio->out.mixdown = [[queueToApply objectForKey:@"JobAudio1Mixdown"] intValue]; - audio->out.bitrate = [[queueToApply objectForKey:@"JobAudio1Bitrate"] intValue]; - audio->out.samplerate = [[queueToApply objectForKey:@"JobAudio1Samplerate"] intValue]; - audio->out.dynamic_range_compression = [[queueToApply objectForKey:@"Audio1TrackDRCSlider"] floatValue]; - - hb_audio_add( job, audio ); - free(audio); - } - if ([[queueToApply objectForKey:@"Audio2Track"] intValue] > 0) - { - - audio = (hb_audio_config_t *) calloc(1, sizeof(*audio)); - hb_audio_config_init(audio); - audio->in.track = [[queueToApply objectForKey:@"Audio2Track"] intValue] - 1; - [self writeToActivityLog: "prepareJob audiotrack 2 is: %d", audio->in.track]; - /* We go ahead and assign values to our audio->out. */ - audio->out.track = [[queueToApply objectForKey:@"Audio2Track"] intValue] - 1; - audio->out.codec = [[queueToApply objectForKey:@"JobAudio2Encoder"] intValue]; - audio->out.mixdown = [[queueToApply objectForKey:@"JobAudio2Mixdown"] intValue]; - audio->out.bitrate = [[queueToApply objectForKey:@"JobAudio2Bitrate"] intValue]; - audio->out.samplerate = [[queueToApply objectForKey:@"JobAudio2Samplerate"] intValue]; - audio->out.dynamic_range_compression = [[queueToApply objectForKey:@"Audio2TrackDRCSlider"] floatValue]; - - hb_audio_add( job, audio ); - free(audio); - } - - if ([[queueToApply objectForKey:@"Audio3Track"] intValue] > 0) - { - audio = (hb_audio_config_t *) calloc(1, sizeof(*audio)); - hb_audio_config_init(audio); - audio->in.track = [[queueToApply objectForKey:@"Audio3Track"] intValue] - 1; - /* We go ahead and assign values to our audio->out. */ - audio->out.track = [[queueToApply objectForKey:@"Audio3Track"] intValue] - 1; - audio->out.codec = [[queueToApply objectForKey:@"JobAudio3Encoder"] intValue]; - audio->out.mixdown = [[queueToApply objectForKey:@"JobAudio3Mixdown"] intValue]; - audio->out.bitrate = [[queueToApply objectForKey:@"JobAudio3Bitrate"] intValue]; - audio->out.samplerate = [[queueToApply objectForKey:@"JobAudio3Samplerate"] intValue]; - audio->out.dynamic_range_compression = [[queueToApply objectForKey:@"Audio3TrackDRCSlider"] floatValue]; - - hb_audio_add( job, audio ); - free(audio); - } - - if ([[queueToApply objectForKey:@"Audio4Track"] intValue] > 0) - { - audio = (hb_audio_config_t *) calloc(1, sizeof(*audio)); - hb_audio_config_init(audio); - audio->in.track = [[queueToApply objectForKey:@"Audio4Track"] intValue] - 1; - /* We go ahead and assign values to our audio->out. */ - audio->out.track = [[queueToApply objectForKey:@"Audio4Track"] intValue] - 1; - audio->out.codec = [[queueToApply objectForKey:@"JobAudio4Encoder"] intValue]; - audio->out.mixdown = [[queueToApply objectForKey:@"JobAudio4Mixdown"] intValue]; - audio->out.bitrate = [[queueToApply objectForKey:@"JobAudio4Bitrate"] intValue]; - audio->out.samplerate = [[queueToApply objectForKey:@"JobAudio4Samplerate"] intValue]; - audio->out.dynamic_range_compression = [[queueToApply objectForKey:@"Audio4TrackDRCSlider"] floatValue]; - - hb_audio_add( job, audio ); - - - } + for (unsigned int counter = 0; counter < maximumNumberOfAllowedAudioTracks; counter++) { + NSString *prefix = [NSString stringWithFormat: @"Audio%d", counter + 1]; + if ([[queueToApply objectForKey: [prefix stringByAppendingString: @"Track"]] intValue] > 0) { + audio = (hb_audio_config_t *) calloc(1, sizeof(*audio)); + hb_audio_config_init(audio); + audio->in.track = [[queueToApply objectForKey: [prefix stringByAppendingString: @"Track"]] intValue] - 1; + /* We go ahead and assign values to our audio->out. */ + audio->out.track = audio->in.track; + audio->out.dynamic_range_compression = [[queueToApply objectForKey: [prefix stringByAppendingString: @"TrackDRCSlider"]] floatValue]; + prefix = [NSString stringWithFormat: @"JobAudio%d", counter + 1]; + audio->out.codec = [[queueToApply objectForKey: [prefix stringByAppendingString: @"Encoder"]] intValue]; + audio->out.mixdown = [[queueToApply objectForKey: [prefix stringByAppendingString: @"Mixdown"]] intValue]; + audio->out.bitrate = [[queueToApply objectForKey: [prefix stringByAppendingString: @"Bitrate"]] intValue]; + audio->out.samplerate = [[queueToApply objectForKey: [prefix stringByAppendingString: @"Samplerate"]] intValue]; + + hb_audio_add( job, audio ); + free(audio); + } + } /* Filters */ job->filters = hb_list_init(); @@ -4020,6 +3728,7 @@ bool one_burned = FALSE; * The order of the filters is critical */ /* Detelecine */ + hb_filter_detelecine.settings = NULL; if ([[queueToApply objectForKey:@"PictureDetelecine"] intValue] == 1) { /* use a custom detelecine string */ @@ -4036,6 +3745,7 @@ bool one_burned = FALSE; { /* Decomb */ /* we add the custom string if present */ + hb_filter_decomb.settings = NULL; if ([[queueToApply objectForKey:@"PictureDecomb"] intValue] == 1) { /* use a custom decomb string */ @@ -4120,7 +3830,7 @@ bool one_burned = FALSE; /* addToQueue: puts up an alert before ultimately calling doAddToQueue -*/ + */ - (IBAction) addToQueue: (id) sender { /* We get the destination directory from the destination field here */ @@ -4170,7 +3880,7 @@ bool one_burned = FALSE; } else if (fileExistsInQueue == YES) { - NSBeginCriticalAlertSheet( NSLocalizedString( @"There is already a queue item for this destination.", @"" ), + NSBeginCriticalAlertSheet( NSLocalizedString( @"There is already a queue item for this destination.", @"" ), NSLocalizedString( @"Cancel", @"" ), NSLocalizedString( @"Overwrite", @"" ), nil, fWindow, self, @selector( overwriteAddToQueueAlertDone:returnCode:contextInfo: ), NULL, NULL, [NSString stringWithFormat: @@ -4222,6 +3932,7 @@ bool one_burned = FALSE; // 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]]; @@ -4259,6 +3970,7 @@ bool one_burned = FALSE; } /* 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]]; } @@ -4396,23 +4108,29 @@ bool one_burned = FALSE; // and as always, save it in the queue .plist... /* We save all of the Queue data here */ [self saveQueueFileItem]; - // so now lets move to - currentQueueEncodeIndex++ ; + // ... and see if there are more items left in our queue int queueItems = [QueueFileArray count]; /* If we still have more items in our queue, lets go to the next one */ - if (currentQueueEncodeIndex < queueItems) - { - [self writeToActivityLog: "doCancelCurrentJob currentQueueEncodeIndex is incremented to: %d", currentQueueEncodeIndex]; - [self writeToActivityLog: "doCancelCurrentJob moving to the next job"]; - - [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]]; + /* Check to see if there are any more pending items in the queue */ + int newQueueItemIndex = [self getNextPendingQueueIndex]; + /* 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 */ + 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"]; + [self 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]]; + } else { - [self writeToActivityLog: "doCancelCurrentJob the item queue is complete"]; + [self writeToActivityLog: "incrementQueueItemDone there are no more pending encodes"]; } - } - (void) doCancelCurrentJobAndStop @@ -4559,7 +4277,15 @@ bool one_burned = FALSE; [fChapterTitlesDelegate resetWithTitle:title]; [fChapterTable reloadData]; - /* Lets make sure there arent any erroneous audio tracks in the job list, so lets make sure its empty*/ + /* Update audio table */ + [[NSNotificationCenter defaultCenter] postNotification: + [NSNotification notificationWithName: HBTitleChangedNotification + object: self + userInfo: [NSDictionary dictionaryWithObjectsAndKeys: + [NSData dataWithBytesNoCopy: &fTitle length: sizeof(fTitle) freeWhenDone: NO], keyTitleTag, + nil]]]; + + /* Lets make sure there arent any erroneous audio tracks in the job list, so lets make sure its empty*/ int audiotrack_count = hb_list_count(job->list_audio); for( int i = 0; i < audiotrack_count;i++) { @@ -4567,25 +4293,7 @@ bool one_burned = FALSE; hb_list_rem(job->list_audio, temp_audio); } - /* Update audio popups */ - [self addAllAudioTracksToPopUp: fAudLang1PopUp]; - [self addAllAudioTracksToPopUp: fAudLang2PopUp]; - [self addAllAudioTracksToPopUp: fAudLang3PopUp]; - [self addAllAudioTracksToPopUp: fAudLang4PopUp]; - /* search for the first instance of our prefs default language for track 1, and set track 2 to "none" */ - NSString * audioSearchPrefix = [[NSUserDefaults standardUserDefaults] stringForKey:@"DefaultLanguage"]; - [self selectAudioTrackInPopUp: fAudLang1PopUp searchPrefixString: audioSearchPrefix selectIndexIfNotFound: 1]; - [self selectAudioTrackInPopUp:fAudLang2PopUp searchPrefixString:nil selectIndexIfNotFound:0]; - [self selectAudioTrackInPopUp:fAudLang3PopUp searchPrefixString:nil selectIndexIfNotFound:0]; - [self selectAudioTrackInPopUp:fAudLang4PopUp searchPrefixString:nil selectIndexIfNotFound:0]; - - /* changing the title may have changed the audio channels on offer, */ - /* so call audioTrackPopUpChanged for both audio tracks to update the mixdown popups */ - [self audioTrackPopUpChanged: fAudLang1PopUp]; - [self audioTrackPopUpChanged: fAudLang2PopUp]; - [self audioTrackPopUpChanged: fAudLang3PopUp]; - [self audioTrackPopUpChanged: fAudLang4PopUp]; - + [fVidRatePopUp selectItemAtIndex: 0]; /* we run the picture size values through calculatePictureSizing to get all picture setting information*/ @@ -4775,6 +4483,15 @@ bool one_burned = FALSE; [fSubtitlesDelegate containerChanged:[[fDstFormatPopUp selectedItem] tag]]; [fSubtitlesTable reloadData]; + + /* post a notification for any interested observers to indicate that our video container has changed */ + [[NSNotificationCenter defaultCenter] postNotification: + [NSNotification notificationWithName: HBContainerChangedNotification + object: self + userInfo: [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithInt: [[fDstFormatPopUp selectedItem] tag]], keyContainerTag, + nil]]]; + /* if we have a previously selected vid encoder tag, then try to select it */ if (selectedVidEncoderTag) { @@ -4785,10 +4502,6 @@ bool one_burned = FALSE; [fVidEncoderPopUp selectItemAtIndex: 0]; } - [self audioAddAudioTrackCodecs: fAudTrack1CodecPopUp]; - [self audioAddAudioTrackCodecs: fAudTrack2CodecPopUp]; - [self audioAddAudioTrackCodecs: fAudTrack3CodecPopUp]; - [self audioAddAudioTrackCodecs: fAudTrack4CodecPopUp]; if( format == 0 ) [self autoSetM4vExtension: sender]; @@ -4798,10 +4511,6 @@ bool one_burned = FALSE; if( SuccessfulScan ) { /* Add/replace to the correct extension */ - [self audioTrackPopUpChanged: fAudLang1PopUp]; - [self audioTrackPopUpChanged: fAudLang2PopUp]; - [self audioTrackPopUpChanged: fAudLang3PopUp]; - [self audioTrackPopUpChanged: fAudLang4PopUp]; if( [fVidEncoderPopUp selectedItem] == nil ) { @@ -4827,9 +4536,8 @@ bool one_burned = FALSE; NSString * extension = @"mp4"; - if( [[fAudTrack1CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[fAudTrack2CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 || - [[fAudTrack3CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 || - [[fAudTrack4CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 || + BOOL anyCodecAC3 = [fAudioDelegate anyCodecMatches: HB_ACODEC_AC3]; + if (YES == anyCodecAC3 || [fCreateChapterMarkers state] == NSOnState || [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultMpegName"] > 0 ) { @@ -4928,6 +4636,17 @@ the user is using "Custom" settings by determining the sender*/ - (IBAction ) videoFrameRateChanged: (id) sender { + /* Hide and set the PFR Checkbox to OFF if we are set to Same as Source */ + if ([fVidRatePopUp indexOfSelectedItem] == 0) + { + [fFrameratePfrCheck setHidden:YES]; + [fFrameratePfrCheck setState:0]; + } + else + { + [fFrameratePfrCheck setHidden:NO]; + } + /* We call method method to calculatePictureSizing to error check detelecine*/ [self calculatePictureSizing: sender]; @@ -5079,82 +4798,7 @@ the user is using "Custom" settings by determining the sender*/ job->mux = [[fDstFormatPopUp selectedItem] tag]; /* Audio goes here */ - int audiotrack_count = hb_list_count(job->list_audio); - for( int i = 0; i < audiotrack_count;i++) - { - hb_audio_t * temp_audio = (hb_audio_t*) hb_list_item( job->list_audio, 0 ); - hb_list_rem(job->list_audio, temp_audio); - } - /* Now we need our audio info here for each track if applicable */ - if ([fAudLang1PopUp indexOfSelectedItem] > 0) - { - audio = (hb_audio_config_t *) calloc(1, sizeof(*audio)); - hb_audio_config_init(audio); - audio->in.track = [fAudLang1PopUp indexOfSelectedItem] - 1; - /* We go ahead and assign values to our audio->out. */ - audio->out.track = [fAudLang1PopUp indexOfSelectedItem] - 1; - audio->out.codec = [[fAudTrack1CodecPopUp selectedItem] tag]; - audio->out.mixdown = [[fAudTrack1MixPopUp selectedItem] tag]; - audio->out.bitrate = [[fAudTrack1BitratePopUp selectedItem] tag]; - audio->out.samplerate = [[fAudTrack1RatePopUp selectedItem] tag]; - audio->out.dynamic_range_compression = [fAudTrack1DrcField floatValue]; - - hb_audio_add( job, audio ); - free(audio); - } - if ([fAudLang2PopUp indexOfSelectedItem] > 0) - { - audio = (hb_audio_config_t *) calloc(1, sizeof(*audio)); - hb_audio_config_init(audio); - audio->in.track = [fAudLang2PopUp indexOfSelectedItem] - 1; - /* We go ahead and assign values to our audio->out. */ - audio->out.track = [fAudLang2PopUp indexOfSelectedItem] - 1; - audio->out.codec = [[fAudTrack2CodecPopUp selectedItem] tag]; - audio->out.mixdown = [[fAudTrack2MixPopUp selectedItem] tag]; - audio->out.bitrate = [[fAudTrack2BitratePopUp selectedItem] tag]; - audio->out.samplerate = [[fAudTrack2RatePopUp selectedItem] tag]; - audio->out.dynamic_range_compression = [fAudTrack2DrcField floatValue]; - - hb_audio_add( job, audio ); - free(audio); - - } - - if ([fAudLang3PopUp indexOfSelectedItem] > 0) - { - audio = (hb_audio_config_t *) calloc(1, sizeof(*audio)); - hb_audio_config_init(audio); - audio->in.track = [fAudLang3PopUp indexOfSelectedItem] - 1; - /* We go ahead and assign values to our audio->out. */ - audio->out.track = [fAudLang3PopUp indexOfSelectedItem] - 1; - audio->out.codec = [[fAudTrack3CodecPopUp selectedItem] tag]; - audio->out.mixdown = [[fAudTrack3MixPopUp selectedItem] tag]; - audio->out.bitrate = [[fAudTrack3BitratePopUp selectedItem] tag]; - audio->out.samplerate = [[fAudTrack3RatePopUp selectedItem] tag]; - audio->out.dynamic_range_compression = [fAudTrack3DrcField floatValue]; - - hb_audio_add( job, audio ); - free(audio); - - } - - if ([fAudLang4PopUp indexOfSelectedItem] > 0) - { - audio = (hb_audio_config_t *) calloc(1, sizeof(*audio)); - hb_audio_config_init(audio); - audio->in.track = [fAudLang4PopUp indexOfSelectedItem] - 1; - /* We go ahead and assign values to our audio->out. */ - audio->out.track = [fAudLang4PopUp indexOfSelectedItem] - 1; - audio->out.codec = [[fAudTrack4CodecPopUp selectedItem] tag]; - audio->out.mixdown = [[fAudTrack4MixPopUp selectedItem] tag]; - audio->out.bitrate = [[fAudTrack4BitratePopUp selectedItem] tag]; - audio->out.samplerate = [[fAudTrack4RatePopUp selectedItem] tag]; - audio->out.dynamic_range_compression = [fAudTrack4DrcField floatValue]; - - hb_audio_add( job, audio ); - free(audio); - - } + [fAudioDelegate prepareAudioForJob: job]; [fVidBitrateField setIntValue: hb_calc_bitrate( job, [fVidTargetSizeField intValue] )]; } @@ -5310,877 +4954,21 @@ the user is using "Custom" settings by determining the sender*/ #pragma mark - #pragma mark - Audio and Subtitles -- (IBAction) audioCodecsPopUpChanged: (id) sender -{ - - NSPopUpButton * audiotrackPopUp; - NSPopUpButton * sampleratePopUp; - NSPopUpButton * bitratePopUp; - NSPopUpButton * audiocodecPopUp; - if (sender == fAudTrack1CodecPopUp) - { - audiotrackPopUp = fAudLang1PopUp; - audiocodecPopUp = fAudTrack1CodecPopUp; - sampleratePopUp = fAudTrack1RatePopUp; - bitratePopUp = fAudTrack1BitratePopUp; - } - else if (sender == fAudTrack2CodecPopUp) - { - audiotrackPopUp = fAudLang2PopUp; - audiocodecPopUp = fAudTrack2CodecPopUp; - sampleratePopUp = fAudTrack2RatePopUp; - bitratePopUp = fAudTrack2BitratePopUp; - } - else if (sender == fAudTrack3CodecPopUp) - { - audiotrackPopUp = fAudLang3PopUp; - audiocodecPopUp = fAudTrack3CodecPopUp; - sampleratePopUp = fAudTrack3RatePopUp; - bitratePopUp = fAudTrack3BitratePopUp; - } - else - { - audiotrackPopUp = fAudLang4PopUp; - audiocodecPopUp = fAudTrack4CodecPopUp; - sampleratePopUp = fAudTrack4RatePopUp; - bitratePopUp = fAudTrack4BitratePopUp; - } - - /* changing the codecs on offer may mean that we can / can't offer mono or 6ch, */ - /* so call audioTrackPopUpChanged for both audio tracks to update the mixdown popups */ - [self audioTrackPopUpChanged: audiotrackPopUp]; - -} - -- (IBAction) setEnabledStateOfAudioMixdownControls: (id) sender -{ - /* We will be setting the enabled/disabled state of each tracks audio controls based on - * the settings of the source audio for that track. We leave the samplerate and bitrate - * to audiotrackMixdownChanged - */ - - /* We will first verify that a lower track number has been selected before enabling each track - * for example, make sure a track is selected for track 1 before enabling track 2, etc. - */ - - /* If the source has no audio then disable audio track 1 */ - if (hb_list_count( fTitle->list_audio ) == 0) - { - [fAudLang1PopUp selectItemAtIndex:0]; - } - - if ([fAudLang1PopUp indexOfSelectedItem] == 0) - { - [fAudLang2PopUp setEnabled: NO]; - [fAudLang2PopUp selectItemAtIndex: 0]; - } - else - { - [fAudLang2PopUp setEnabled: YES]; - } - - if ([fAudLang2PopUp indexOfSelectedItem] == 0) - { - [fAudLang3PopUp setEnabled: NO]; - [fAudLang3PopUp selectItemAtIndex: 0]; - } - else - { - [fAudLang3PopUp setEnabled: YES]; - } - if ([fAudLang3PopUp indexOfSelectedItem] == 0) - { - [fAudLang4PopUp setEnabled: NO]; - [fAudLang4PopUp selectItemAtIndex: 0]; - } - else - { - [fAudLang4PopUp setEnabled: YES]; - } - /* enable/disable the mixdown text and popupbutton for audio track 1 */ - [fAudTrack1CodecPopUp setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack1MixPopUp setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack1RatePopUp setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack1BitratePopUp setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack1DrcSlider setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack1DrcField setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES]; - if ([fAudLang1PopUp indexOfSelectedItem] == 0) - { - [fAudTrack1CodecPopUp removeAllItems]; - [fAudTrack1MixPopUp removeAllItems]; - [fAudTrack1RatePopUp removeAllItems]; - [fAudTrack1BitratePopUp removeAllItems]; - [fAudTrack1DrcSlider setFloatValue: 0.00]; - [self audioDRCSliderChanged: fAudTrack1DrcSlider]; - } - else if ([[fAudTrack1MixPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[fAudTrack1MixPopUp selectedItem] tag] == HB_ACODEC_DCA) - { - [fAudTrack1RatePopUp setEnabled: NO]; - [fAudTrack1BitratePopUp setEnabled: NO]; - [fAudTrack1DrcSlider setEnabled: NO]; - [fAudTrack1DrcField setEnabled: NO]; - } - - /* enable/disable the mixdown text and popupbutton for audio track 2 */ - [fAudTrack2CodecPopUp setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack2MixPopUp setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack2RatePopUp setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack2BitratePopUp setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack2DrcSlider setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack2DrcField setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES]; - if ([fAudLang2PopUp indexOfSelectedItem] == 0) - { - [fAudTrack2CodecPopUp removeAllItems]; - [fAudTrack2MixPopUp removeAllItems]; - [fAudTrack2RatePopUp removeAllItems]; - [fAudTrack2BitratePopUp removeAllItems]; - [fAudTrack2DrcSlider setFloatValue: 0.00]; - [self audioDRCSliderChanged: fAudTrack2DrcSlider]; - } - else if ([[fAudTrack2MixPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[fAudTrack2MixPopUp selectedItem] tag] == HB_ACODEC_DCA) - { - [fAudTrack2RatePopUp setEnabled: NO]; - [fAudTrack2BitratePopUp setEnabled: NO]; - [fAudTrack2DrcSlider setEnabled: NO]; - [fAudTrack2DrcField setEnabled: NO]; - } - - /* enable/disable the mixdown text and popupbutton for audio track 3 */ - [fAudTrack3CodecPopUp setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack3MixPopUp setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack3RatePopUp setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack3BitratePopUp setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack3DrcSlider setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack3DrcField setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES]; - if ([fAudLang3PopUp indexOfSelectedItem] == 0) - { - [fAudTrack3CodecPopUp removeAllItems]; - [fAudTrack3MixPopUp removeAllItems]; - [fAudTrack3RatePopUp removeAllItems]; - [fAudTrack3BitratePopUp removeAllItems]; - [fAudTrack3DrcSlider setFloatValue: 0.00]; - [self audioDRCSliderChanged: fAudTrack3DrcSlider]; - } - else if ([[fAudTrack3MixPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[fAudTrack3MixPopUp selectedItem] tag] == HB_ACODEC_DCA) - { - [fAudTrack3RatePopUp setEnabled: NO]; - [fAudTrack3BitratePopUp setEnabled: NO]; - [fAudTrack3DrcSlider setEnabled: NO]; - [fAudTrack3DrcField setEnabled: NO]; - } - - /* enable/disable the mixdown text and popupbutton for audio track 4 */ - [fAudTrack4CodecPopUp setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack4MixPopUp setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack4RatePopUp setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack4BitratePopUp setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack4DrcSlider setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES]; - [fAudTrack4DrcField setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES]; - if ([fAudLang4PopUp indexOfSelectedItem] == 0) - { - [fAudTrack4CodecPopUp removeAllItems]; - [fAudTrack4MixPopUp removeAllItems]; - [fAudTrack4RatePopUp removeAllItems]; - [fAudTrack4BitratePopUp removeAllItems]; - [fAudTrack4DrcSlider setFloatValue: 0.00]; - [self audioDRCSliderChanged: fAudTrack4DrcSlider]; - } - else if ([[fAudTrack4MixPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[fAudTrack4MixPopUp selectedItem] tag] == HB_ACODEC_DCA) - { - [fAudTrack4RatePopUp setEnabled: NO]; - [fAudTrack4BitratePopUp setEnabled: NO]; - [fAudTrack4DrcSlider setEnabled: NO]; - [fAudTrack4DrcField setEnabled: NO]; - } - -} -- (IBAction) addAllAudioTracksToPopUp: (id) sender -{ - hb_list_t * list = hb_get_titles( fHandle ); - hb_title_t * title = (hb_title_t*) - hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] ); +#pragma mark - - hb_audio_config_t * audio; +@synthesize hasValidPresetSelected; - [sender removeAllItems]; - [sender addItemWithTitle: NSLocalizedString( @"None", @"" )]; - for( int i = 0; i < hb_list_count( title->list_audio ); i++ ) - { - audio = (hb_audio_config_t *) hb_list_audio_config_item( title->list_audio, i ); - [[sender menu] addItemWithTitle: - [NSString stringWithUTF8String: audio->lang.description] - action: NULL keyEquivalent: @""]; - } - [sender selectItemAtIndex: 0]; +// This causes all audio tracks from the title to be used based on the current preset +- (IBAction) addAllAudioTracks: (id) sender +{ + [fAudioDelegate addAllTracksFromPreset: [fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]]]; + return; } -- (IBAction) selectAudioTrackInPopUp: (id) sender searchPrefixString: (NSString *) searchPrefixString selectIndexIfNotFound: (int) selectIndexIfNotFound -{ - - /* this method can be used to find a language, or a language-and-source-format combination, by passing in the appropriate string */ - /* e.g. to find the first French track, pass in an NSString * of "Francais" */ - /* e.g. to find the first English 5.1 AC3 track, pass in an NSString * of "English (AC3) (5.1 ch)" */ - /* if no matching track is found, then selectIndexIfNotFound is used to choose which track to select instead */ - if (hb_list_count( fTitle->list_audio ) != 0) - { - if (searchPrefixString) - { - - for( int i = 0; i < [sender numberOfItems]; i++ ) - { - /* Try to find the desired search string */ - if ([[[sender itemAtIndex: i] title] hasPrefix:searchPrefixString]) - { - [sender selectItemAtIndex: i]; - return; - } - } - /* couldn't find the string, so select the requested "search string not found" item */ - /* index of 0 means select the "none" item */ - /* index of 1 means select the first audio track */ - [sender selectItemAtIndex: selectIndexIfNotFound]; - } - else - { - /* if no search string is provided, then select the selectIndexIfNotFound item */ - [sender selectItemAtIndex: selectIndexIfNotFound]; - } - } - else - { - [sender selectItemAtIndex: 0]; - } - -} -- (IBAction) audioAddAudioTrackCodecs: (id)sender -{ - int format = [fDstFormatPopUp indexOfSelectedItem]; - - /* setup pointers to the appropriate popups for the correct track */ - NSPopUpButton * audiocodecPopUp; - NSPopUpButton * audiotrackPopUp; - if (sender == fAudTrack1CodecPopUp) - { - audiotrackPopUp = fAudLang1PopUp; - audiocodecPopUp = fAudTrack1CodecPopUp; - } - else if (sender == fAudTrack2CodecPopUp) - { - audiotrackPopUp = fAudLang2PopUp; - audiocodecPopUp = fAudTrack2CodecPopUp; - } - else if (sender == fAudTrack3CodecPopUp) - { - audiotrackPopUp = fAudLang3PopUp; - audiocodecPopUp = fAudTrack3CodecPopUp; - } - else - { - audiotrackPopUp = fAudLang4PopUp; - audiocodecPopUp = fAudTrack4CodecPopUp; - } - - [audiocodecPopUp removeAllItems]; - /* Make sure "None" isnt selected in the source track */ - if ([audiotrackPopUp indexOfSelectedItem] > 0) - { - [audiocodecPopUp setEnabled:YES]; - NSMenuItem *menuItem; - /* We setup our appropriate popups for codecs and put the int value in the popup tag for easy retrieval */ - switch( format ) - { - case 0: - /* MP4 */ - // CA_AAC - menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (CoreAudio)" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_ACODEC_CA_AAC]; - // FAAC - menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (faac)" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_ACODEC_FAAC]; - // AC3 Passthru - menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AC3 Passthru" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_ACODEC_AC3]; - break; - - case 1: - /* MKV */ - // CA_AAC - menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (CoreAudio)" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_ACODEC_CA_AAC]; - // FAAC - menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (faac)" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_ACODEC_FAAC]; - // AC3 Passthru - menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AC3 Passthru" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_ACODEC_AC3]; - // DTS Passthru - menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"DTS Passthru" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_ACODEC_DCA]; - // MP3 - menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"MP3 (lame)" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_ACODEC_LAME]; - // Vorbis - menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"Vorbis (vorbis)" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_ACODEC_VORBIS]; - break; - } - [audiocodecPopUp selectItemAtIndex:0]; - } - else - { - [audiocodecPopUp setEnabled:NO]; - } -} - -- (IBAction) audioTrackPopUpChanged: (id) sender -{ - /* utility function to call audioTrackPopUpChanged without passing in a mixdown-to-use */ - [self audioTrackPopUpChanged: sender mixdownToUse: 0]; -} - -- (IBAction) audioTrackPopUpChanged: (id) sender mixdownToUse: (int) mixdownToUse -{ - - /* make sure we have a selected title before continuing */ - if (fTitle == NULL) return; - /* make sure we have a source audio track before continuing */ - if (hb_list_count( fTitle->list_audio ) == 0) - { - [sender selectItemAtIndex:0]; - return; - } - /* if the sender is the lanaguage popup and there is nothing in the codec popup, lets call - * audioAddAudioTrackCodecs on the codec popup to populate it properly before moving on - */ - if (sender == fAudLang1PopUp && [[fAudTrack1CodecPopUp menu] numberOfItems] == 0) - { - [self audioAddAudioTrackCodecs: fAudTrack1CodecPopUp]; - } - if (sender == fAudLang2PopUp && [[fAudTrack2CodecPopUp menu] numberOfItems] == 0) - { - [self audioAddAudioTrackCodecs: fAudTrack2CodecPopUp]; - } - if (sender == fAudLang3PopUp && [[fAudTrack3CodecPopUp menu] numberOfItems] == 0) - { - [self audioAddAudioTrackCodecs: fAudTrack3CodecPopUp]; - } - if (sender == fAudLang4PopUp && [[fAudTrack4CodecPopUp menu] numberOfItems] == 0) - { - [self audioAddAudioTrackCodecs: fAudTrack4CodecPopUp]; - } - - /* Now lets make the sender the appropriate Audio Track popup from this point on */ - if (sender == fAudTrack1CodecPopUp || sender == fAudTrack1MixPopUp) - { - sender = fAudLang1PopUp; - } - if (sender == fAudTrack2CodecPopUp || sender == fAudTrack2MixPopUp) - { - sender = fAudLang2PopUp; - } - if (sender == fAudTrack3CodecPopUp || sender == fAudTrack3MixPopUp) - { - sender = fAudLang3PopUp; - } - if (sender == fAudTrack4CodecPopUp || sender == fAudTrack4MixPopUp) - { - sender = fAudLang4PopUp; - } - - /* pointer to this track's mixdown, codec, sample rate and bitrate NSPopUpButton's */ - NSPopUpButton * mixdownPopUp; - NSPopUpButton * audiocodecPopUp; - NSPopUpButton * sampleratePopUp; - NSPopUpButton * bitratePopUp; - if (sender == fAudLang1PopUp) - { - mixdownPopUp = fAudTrack1MixPopUp; - audiocodecPopUp = fAudTrack1CodecPopUp; - sampleratePopUp = fAudTrack1RatePopUp; - bitratePopUp = fAudTrack1BitratePopUp; - } - else if (sender == fAudLang2PopUp) - { - mixdownPopUp = fAudTrack2MixPopUp; - audiocodecPopUp = fAudTrack2CodecPopUp; - sampleratePopUp = fAudTrack2RatePopUp; - bitratePopUp = fAudTrack2BitratePopUp; - } - else if (sender == fAudLang3PopUp) - { - mixdownPopUp = fAudTrack3MixPopUp; - audiocodecPopUp = fAudTrack3CodecPopUp; - sampleratePopUp = fAudTrack3RatePopUp; - bitratePopUp = fAudTrack3BitratePopUp; - } - else - { - mixdownPopUp = fAudTrack4MixPopUp; - audiocodecPopUp = fAudTrack4CodecPopUp; - sampleratePopUp = fAudTrack4RatePopUp; - bitratePopUp = fAudTrack4BitratePopUp; - } - - /* get the index of the selected audio Track*/ - int thisAudioIndex = [sender indexOfSelectedItem] - 1; - - /* pointer for the hb_audio_s struct we will use later on */ - hb_audio_config_t * audio; - - int acodec; - /* check if the audio mixdown controls need their enabled state changing */ - [self setEnabledStateOfAudioMixdownControls:nil]; - - if (thisAudioIndex != -1) - { - - /* get the audio */ - audio = (hb_audio_config_t *) hb_list_audio_config_item( fTitle->list_audio, thisAudioIndex );// Should "fTitle" be title and be setup ? - - /* actually manipulate the proper mixdowns here */ - /* delete the previous audio mixdown options */ - [mixdownPopUp removeAllItems]; - - acodec = [[audiocodecPopUp selectedItem] tag]; - - if (audio != NULL) - { - - /* find out if our selected output audio codec supports mono and / or 6ch */ - /* audioCodecsSupportMono and audioCodecsSupport6Ch are the same for now, - but this may change in the future, so they are separated for flexibility */ - int audioCodecsSupportMono = (audio->in.codec && acodec != HB_ACODEC_LAME); - int audioCodecsSupport6Ch = (audio->in.codec && acodec != HB_ACODEC_LAME); - - /* check for AC-3 passthru */ - if (audio->in.codec == HB_ACODEC_AC3 && acodec == HB_ACODEC_AC3) - { - - NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle: - [NSString stringWithUTF8String: "AC3 Passthru"] - action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_ACODEC_AC3]; - } - else if (audio->in.codec == HB_ACODEC_DCA && acodec == HB_ACODEC_DCA) - { - NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle: - [NSString stringWithUTF8String: "DTS Passthru"] - action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_ACODEC_DCA]; - } - else - { - - /* add the appropriate audio mixdown menuitems to the popupbutton */ - /* in each case, we set the new menuitem's tag to be the amixdown value for that mixdown, - so that we can reference the mixdown later */ - - /* keep a track of the min and max mixdowns we used, so we can select the best match later */ - int minMixdownUsed = 0; - int maxMixdownUsed = 0; - - /* get the input channel layout without any lfe channels */ - int layout = audio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK; - - /* do we want to add a mono option? */ - if (audioCodecsSupportMono == 1) - { - NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle: - [NSString stringWithUTF8String: hb_audio_mixdowns[0].human_readable_name] - action: NULL keyEquivalent: @""]; - [menuItem setTag: hb_audio_mixdowns[0].amixdown]; - if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[0].amixdown; - maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[0].amixdown); - } - - /* do we want to add a stereo option? */ - /* offer stereo if we have a mono source and non-mono-supporting codecs, as otherwise we won't have a mixdown at all */ - /* also offer stereo if we have a stereo-or-better source */ - if ((layout == HB_INPUT_CH_LAYOUT_MONO && audioCodecsSupportMono == 0) || layout >= HB_INPUT_CH_LAYOUT_STEREO) - { - NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle: - [NSString stringWithUTF8String: hb_audio_mixdowns[1].human_readable_name] - action: NULL keyEquivalent: @""]; - [menuItem setTag: hb_audio_mixdowns[1].amixdown]; - if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[1].amixdown; - maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[1].amixdown); - } - - /* do we want to add a dolby surround (DPL1) option? */ - if (layout == HB_INPUT_CH_LAYOUT_3F1R || layout == HB_INPUT_CH_LAYOUT_3F2R || layout == HB_INPUT_CH_LAYOUT_DOLBY) - { - NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle: - [NSString stringWithUTF8String: hb_audio_mixdowns[2].human_readable_name] - action: NULL keyEquivalent: @""]; - [menuItem setTag: hb_audio_mixdowns[2].amixdown]; - if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[2].amixdown; - maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[2].amixdown); - } - - /* do we want to add a dolby pro logic 2 (DPL2) option? */ - if (layout == HB_INPUT_CH_LAYOUT_3F2R) - { - NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle: - [NSString stringWithUTF8String: hb_audio_mixdowns[3].human_readable_name] - action: NULL keyEquivalent: @""]; - [menuItem setTag: hb_audio_mixdowns[3].amixdown]; - if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[3].amixdown; - maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[3].amixdown); - } - - /* do we want to add a 6-channel discrete option? */ - if (audioCodecsSupport6Ch == 1 && layout == HB_INPUT_CH_LAYOUT_3F2R && (audio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE)) - { - NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle: - [NSString stringWithUTF8String: hb_audio_mixdowns[4].human_readable_name] - action: NULL keyEquivalent: @""]; - [menuItem setTag: hb_audio_mixdowns[4].amixdown]; - if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[4].amixdown; - maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[4].amixdown); - } - - /* do we want to add an AC-3 passthrough option? */ - if (audio->in.codec == HB_ACODEC_AC3 && acodec == HB_ACODEC_AC3) - { - NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle: - [NSString stringWithUTF8String: hb_audio_mixdowns[5].human_readable_name] - action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_ACODEC_AC3]; - if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[5].amixdown; - maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[5].amixdown); - } - - /* do we want to add a DTS Passthru option ? HB_ACODEC_DCA*/ - if (audio->in.codec == HB_ACODEC_DCA && acodec == HB_ACODEC_DCA) - { - NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle: - [NSString stringWithUTF8String: hb_audio_mixdowns[5].human_readable_name] - action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_ACODEC_DCA]; - if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[5].amixdown; - maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[5].amixdown); - } - - /* auto-select the best mixdown based on our saved mixdown preference */ - - /* for now, this is hard-coded to a "best" mixdown of HB_AMIXDOWN_DOLBYPLII */ - /* ultimately this should be a prefs option */ - int useMixdown; - - /* if we passed in a mixdown to use - in order to load a preset - then try and use it */ - if (mixdownToUse > 0) - { - useMixdown = mixdownToUse; - } - else - { - useMixdown = HB_AMIXDOWN_DOLBYPLII; - } - - /* if useMixdown > maxMixdownUsed, then use maxMixdownUsed */ - if (useMixdown > maxMixdownUsed) - { - useMixdown = maxMixdownUsed; - } - - /* if useMixdown < minMixdownUsed, then use minMixdownUsed */ - if (useMixdown < minMixdownUsed) - { - useMixdown = minMixdownUsed; - } - - /* select the (possibly-amended) preferred mixdown */ - [mixdownPopUp selectItemWithTag: useMixdown]; - - } - /* In the case of a source track that is not AC3 and the user tries to use AC3 Passthru (which does not work) - * we force the Audio Codec choice back to a workable codec. We use CoreAudio aac for all containers. - */ - if (audio->in.codec != HB_ACODEC_AC3 && [[audiocodecPopUp selectedItem] tag] == HB_ACODEC_AC3) - { - [audiocodecPopUp selectItemWithTag: HB_ACODEC_CA_AAC]; - } - - /* In the case of a source track that is not DTS and the user tries to use DTS Passthru (which does not work) - * we force the Audio Codec choice back to a workable codec. We use CoreAudio aac for all containers. - */ - if (audio->in.codec != HB_ACODEC_DCA && [[audiocodecPopUp selectedItem] tag] == HB_ACODEC_DCA) - { - [audiocodecPopUp selectItemWithTag: HB_ACODEC_CA_AAC]; - } - - /* Setup our samplerate and bitrate popups we will need based on mixdown */ - [self audioTrackMixdownChanged: mixdownPopUp]; - } - - } - if( [fDstFormatPopUp indexOfSelectedItem] == 0 ) - { - [self autoSetM4vExtension: sender]; - } -} - -- (IBAction) audioTrackMixdownChanged: (id) sender -{ - - int acodec; - /* setup pointers to all of the other audio track controls - * we will need later - */ - NSPopUpButton * mixdownPopUp; - NSPopUpButton * sampleratePopUp; - NSPopUpButton * bitratePopUp; - NSPopUpButton * audiocodecPopUp; - NSPopUpButton * audiotrackPopUp; - NSSlider * drcSlider; - NSTextField * drcField; - if (sender == fAudTrack1MixPopUp) - { - audiotrackPopUp = fAudLang1PopUp; - audiocodecPopUp = fAudTrack1CodecPopUp; - mixdownPopUp = fAudTrack1MixPopUp; - sampleratePopUp = fAudTrack1RatePopUp; - bitratePopUp = fAudTrack1BitratePopUp; - drcSlider = fAudTrack1DrcSlider; - drcField = fAudTrack1DrcField; - } - else if (sender == fAudTrack2MixPopUp) - { - audiotrackPopUp = fAudLang2PopUp; - audiocodecPopUp = fAudTrack2CodecPopUp; - mixdownPopUp = fAudTrack2MixPopUp; - sampleratePopUp = fAudTrack2RatePopUp; - bitratePopUp = fAudTrack2BitratePopUp; - drcSlider = fAudTrack2DrcSlider; - drcField = fAudTrack2DrcField; - } - else if (sender == fAudTrack3MixPopUp) - { - audiotrackPopUp = fAudLang3PopUp; - audiocodecPopUp = fAudTrack3CodecPopUp; - mixdownPopUp = fAudTrack3MixPopUp; - sampleratePopUp = fAudTrack3RatePopUp; - bitratePopUp = fAudTrack3BitratePopUp; - drcSlider = fAudTrack3DrcSlider; - drcField = fAudTrack3DrcField; - } - else - { - audiotrackPopUp = fAudLang4PopUp; - audiocodecPopUp = fAudTrack4CodecPopUp; - mixdownPopUp = fAudTrack4MixPopUp; - sampleratePopUp = fAudTrack4RatePopUp; - bitratePopUp = fAudTrack4BitratePopUp; - drcSlider = fAudTrack4DrcSlider; - drcField = fAudTrack4DrcField; - } - acodec = [[audiocodecPopUp selectedItem] tag]; - /* storage variable for the min and max bitrate allowed for this codec */ - int minbitrate; - int maxbitrate; - - switch( acodec ) - { - case HB_ACODEC_FAAC: - /* check if we have a 6ch discrete conversion in either audio track */ - if ([[mixdownPopUp selectedItem] tag] == HB_AMIXDOWN_6CH) - { - /* FAAC has a minimum of 192 kbps for 6-channel discrete */ - minbitrate = 192; - /* If either mixdown popup includes 6-channel discrete, then allow up to 448 kbps */ - maxbitrate = 448; - break; - } - else - { - /* FAAC is happy using our min bitrate of 32 kbps for stereo or mono */ - minbitrate = 32; - /* FAAC won't honour anything more than 160 for stereo, so let's not offer it */ - /* note: haven't dealt with mono separately here, FAAC will just use the max it can */ - maxbitrate = 160; - break; - } - - case HB_ACODEC_CA_AAC: - /* check if we have a 6ch discrete conversion in either audio track */ - if ([[mixdownPopUp selectedItem] tag] == HB_AMIXDOWN_6CH) - { - minbitrate = 128; - maxbitrate = 768; - break; - } - else - { - minbitrate = 64; - maxbitrate = 320; - break; - } - - case HB_ACODEC_LAME: - /* Lame is happy using our min bitrate of 32 kbps */ - minbitrate = 32; - /* Lame won't encode if the bitrate is higher than 320 kbps */ - maxbitrate = 320; - break; - - case HB_ACODEC_VORBIS: - if ([[mixdownPopUp selectedItem] tag] == HB_AMIXDOWN_6CH) - { - /* Vorbis causes a crash if we use a bitrate below 192 kbps with 6 channel */ - minbitrate = 192; - /* If either mixdown popup includes 6-channel discrete, then allow up to 384 kbps */ - maxbitrate = 384; - break; - } - else - { - /* Vorbis causes a crash if we use a bitrate below 48 kbps */ - minbitrate = 48; - /* Vorbis can cope with 384 kbps quite happily, even for stereo */ - maxbitrate = 384; - break; - } - - default: - /* AC3 passthru disables the bitrate dropdown anyway, so we might as well just use the min and max bitrate */ - minbitrate = 32; - maxbitrate = 384; - - } - - /* make sure we have a selected title before continuing */ - if (fTitle == NULL || hb_list_count( fTitle->list_audio ) == 0) return; - /* get the audio so we can find out what input rates are*/ - hb_audio_config_t * audio; - audio = (hb_audio_config_t *) hb_list_audio_config_item( fTitle->list_audio, [audiotrackPopUp indexOfSelectedItem] - 1 ); - int inputbitrate = audio->in.bitrate / 1000; - int inputsamplerate = audio->in.samplerate; - - if ([[mixdownPopUp selectedItem] tag] != HB_ACODEC_AC3 && [[mixdownPopUp selectedItem] tag] != HB_ACODEC_DCA) - { - [bitratePopUp removeAllItems]; - - for( int i = 0; i < hb_audio_bitrates_count; i++ ) - { - if (hb_audio_bitrates[i].rate >= minbitrate && hb_audio_bitrates[i].rate <= maxbitrate) - { - /* add a new menuitem for this bitrate */ - NSMenuItem *menuItem = [[bitratePopUp menu] addItemWithTitle: - [NSString stringWithUTF8String: hb_audio_bitrates[i].string] - action: NULL keyEquivalent: @""]; - /* set its tag to be the actual bitrate as an integer, so we can retrieve it later */ - [menuItem setTag: hb_audio_bitrates[i].rate]; - } - } - - /* select the default bitrate (but use 384 for 6-ch AAC) */ - if ([[mixdownPopUp selectedItem] tag] == HB_AMIXDOWN_6CH) - { - [bitratePopUp selectItemWithTag: 384]; - } - else - { - [bitratePopUp selectItemWithTag: hb_audio_bitrates[hb_audio_bitrates_default].rate]; - } - } - /* populate and set the sample rate popup */ - /* Audio samplerate */ - [sampleratePopUp removeAllItems]; - /* we create a same as source selection (Auto) so that we can choose to use the input sample rate */ - NSMenuItem *menuItem = [[sampleratePopUp menu] addItemWithTitle: @"Auto" action: NULL keyEquivalent: @""]; - [menuItem setTag: inputsamplerate]; - - for( int i = 0; i < hb_audio_rates_count; i++ ) - { - NSMenuItem *menuItem = [[sampleratePopUp menu] addItemWithTitle: - [NSString stringWithUTF8String: hb_audio_rates[i].string] - action: NULL keyEquivalent: @""]; - [menuItem setTag: hb_audio_rates[i].rate]; - } - /* We use the input sample rate as the default sample rate as downsampling just makes audio worse - * and there is no compelling reason to use anything else as default, though the users default - * preset will likely override any setting chosen here. - */ - [sampleratePopUp selectItemWithTag: inputsamplerate]; - - - /* Since AC3 Pass Thru and DTS Pass Thru uses the input bitrate and sample rate, we get the input tracks - * bitrate and display it in the bitrate popup even though libhb happily ignores any bitrate input from - * the gui. We do this for better user feedback in the audio tab as well as the queue for the most part - */ - if ([[mixdownPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[mixdownPopUp selectedItem] tag] == HB_ACODEC_DCA) - { - - /* lets also set the bitrate popup to the input bitrate as thats what passthru will use */ - [bitratePopUp removeAllItems]; - NSMenuItem *menuItem = [[bitratePopUp menu] addItemWithTitle: - [NSString stringWithFormat:@"%d", inputbitrate] - action: NULL keyEquivalent: @""]; - [menuItem setTag: inputbitrate]; - /* For ac3 passthru we disable the sample rate and bitrate popups as well as the drc slider*/ - [bitratePopUp setEnabled: NO]; - [sampleratePopUp setEnabled: NO]; - - [drcSlider setFloatValue: 0.00]; - [self audioDRCSliderChanged: drcSlider]; - [drcSlider setEnabled: NO]; - [drcField setEnabled: NO]; - } - else - { - [sampleratePopUp setEnabled: YES]; - [bitratePopUp setEnabled: YES]; - [drcSlider setEnabled: YES]; - [drcField setEnabled: YES]; - } -[self calculateBitrate:nil]; -} - -- (IBAction) audioDRCSliderChanged: (id) sender -{ - NSSlider * drcSlider; - NSTextField * drcField; - if (sender == fAudTrack1DrcSlider) - { - drcSlider = fAudTrack1DrcSlider; - drcField = fAudTrack1DrcField; - } - else if (sender == fAudTrack2DrcSlider) - { - drcSlider = fAudTrack2DrcSlider; - drcField = fAudTrack2DrcField; - } - else if (sender == fAudTrack3DrcSlider) - { - drcSlider = fAudTrack3DrcSlider; - drcField = fAudTrack3DrcField; - } - else - { - drcSlider = fAudTrack4DrcSlider; - drcField = fAudTrack4DrcField; - } - - /* If we are between 0.0 and 1.0 on the slider, snap it to 1.0 */ - if ([drcSlider floatValue] > 0.0 && [drcSlider floatValue] < 1.0) - { - [drcSlider setFloatValue:1.0]; - } - - - [drcField setStringValue: [NSString stringWithFormat: @"%.2f", [drcSlider floatValue]]]; - /* For now, do not call this until we have an intelligent way to determine audio track selections - * compared to presets - */ - //[self customSettingUsed: sender]; -} - -#pragma mark - - -- (IBAction) browseImportSrtFile: (id) sender +- (IBAction) browseImportSrtFile: (id) sender { NSOpenPanel * panel; @@ -6236,12 +5024,12 @@ the user is using "Custom" settings by determining the sender*/ - (IBAction) openForums: (id) sender { [[NSWorkspace sharedWorkspace] openURL: [NSURL - URLWithString:@"http://handbrake.fr/forum/"]]; + URLWithString:@"http://forum.handbrake.fr/"]]; } - (IBAction) openUserGuide: (id) sender { [[NSWorkspace sharedWorkspace] openURL: [NSURL - URLWithString:@"http://handbrake.fr/trac/wiki/HandBrakeGuide"]]; + URLWithString:@"http://trac.handbrake.fr/wiki/HandBrakeGuide"]]; } /** @@ -6643,6 +5431,7 @@ return YES; if ([fPresetsOutlineView selectedRow] >= 0 && [[[fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]] objectForKey:@"Folder"] intValue] != 1) { + [self setHasValidPresetSelected: YES]; chosenPreset = [fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]]; [fPresetSelectedDisplay setStringValue:[chosenPreset objectForKey:@"PresetName"]]; @@ -6725,7 +5514,9 @@ return YES; { [fVidRatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"VideoFramerate"]]; } - + /* Set PFR */ + [fFrameratePfrCheck setState:[[chosenPreset objectForKey:@"VideoFrameratePFR"] intValue]]; + [self videoFrameRateChanged:nil]; /* 2 Pass Encoding */ [fVidTwoPassCheck setState:[[chosenPreset objectForKey:@"VideoTwoPass"] intValue]]; @@ -6735,307 +5526,7 @@ return YES; [fVidTurboPassCheck setState:[[chosenPreset objectForKey:@"VideoTurboTwoPass"] intValue]]; /*Audio*/ - /* First we check to see if we are using the current audio track layout based on AudioList array */ - if ([chosenPreset objectForKey:@"AudioList"]) - { - - /* pointer to this track's mixdown, codec, sample rate and bitrate NSPopUpButton's */ - NSPopUpButton * trackLangPopUp = nil; - NSPopUpButton * mixdownPopUp = nil; - NSPopUpButton * audiocodecPopUp = nil; - NSPopUpButton * sampleratePopUp = nil; - NSPopUpButton * bitratePopUp = nil; - NSSlider * drcSlider = nil; - - - /* Populate the audio widgets based on the contents of the AudioList array */ - int i = 0; - NSEnumerator *enumerator = [[chosenPreset objectForKey:@"AudioList"] objectEnumerator]; - id tempObject; - while (tempObject = [enumerator nextObject]) - { - i++; - if( i == 1 ) - { - trackLangPopUp = fAudLang1PopUp; - mixdownPopUp = fAudTrack1MixPopUp; - audiocodecPopUp = fAudTrack1CodecPopUp; - sampleratePopUp = fAudTrack1RatePopUp; - bitratePopUp = fAudTrack1BitratePopUp; - drcSlider = fAudTrack1DrcSlider; - } - if( i == 2 ) - { - trackLangPopUp = fAudLang2PopUp; - mixdownPopUp = fAudTrack2MixPopUp; - audiocodecPopUp = fAudTrack2CodecPopUp; - sampleratePopUp = fAudTrack2RatePopUp; - bitratePopUp = fAudTrack2BitratePopUp; - drcSlider = fAudTrack2DrcSlider; - } - if( i == 3 ) - { - trackLangPopUp = fAudLang3PopUp; - mixdownPopUp = fAudTrack3MixPopUp; - audiocodecPopUp = fAudTrack3CodecPopUp; - sampleratePopUp = fAudTrack3RatePopUp; - bitratePopUp = fAudTrack3BitratePopUp; - drcSlider = fAudTrack3DrcSlider; - } - if( i == 4 ) - { - trackLangPopUp = fAudLang4PopUp; - mixdownPopUp = fAudTrack4MixPopUp; - audiocodecPopUp = fAudTrack4CodecPopUp; - sampleratePopUp = fAudTrack4RatePopUp; - bitratePopUp = fAudTrack4BitratePopUp; - drcSlider = fAudTrack4DrcSlider; - } - - - if ([trackLangPopUp indexOfSelectedItem] == 0) - { - [trackLangPopUp selectItemAtIndex: 1]; - } - [self audioTrackPopUpChanged: trackLangPopUp]; - [audiocodecPopUp selectItemWithTitle:[tempObject objectForKey:@"AudioEncoder"]]; - /* check our pref for core audio and use it in place of faac if preset is a built in */ - if ([[chosenPreset objectForKey:@"Type"] intValue] == 0 && - [[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && - [[tempObject objectForKey:@"AudioEncoder"] isEqualToString: @"AAC (faac)"]) - { - [audiocodecPopUp selectItemWithTitle:@"AAC (CoreAudio)"]; - } - - [self audioTrackPopUpChanged: audiocodecPopUp]; - [mixdownPopUp selectItemWithTitle:[tempObject objectForKey:@"AudioMixdown"]]; - [self audioTrackMixdownChanged: mixdownPopUp]; - /* check to see if the selection was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default - * mixdown*/ - if ([mixdownPopUp selectedItem] == nil) - { - [self audioTrackPopUpChanged: audiocodecPopUp]; - [self writeToActivityLog: "presetSelected mixdown not selected, rerun audioTrackPopUpChanged"]; - } - [sampleratePopUp selectItemWithTitle:[tempObject objectForKey:@"AudioSamplerate"]]; - /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */ - if (![[tempObject objectForKey:@"AudioEncoder"] isEqualToString:@"AC3 Passthru"]) - { - [bitratePopUp selectItemWithTitle:[tempObject objectForKey:@"AudioBitrate"]]; - /* check to see if the bitrate selection was available, if not, rerun audioTrackMixdownChanged using the mixdown to just set the - *default mixdown bitrate*/ - if ([bitratePopUp selectedItem] == nil) - { - [self audioTrackMixdownChanged: mixdownPopUp]; - } - } - [drcSlider setFloatValue:[[tempObject objectForKey:@"AudioTrackDRCSlider"] floatValue]]; - [self audioDRCSliderChanged: drcSlider]; - - - /* If we are any track greater than 1 check to make sure we have a matching source codec is using ac3 passthru or dts passthru, - * if not we will set the track to "None". Track 1 is allowed to mixdown to a suitable DPL2 mix if we cannot passthru */ - - if( i > 1 ) - { - /* Check to see if the preset asks for a passhthru track (AC3 or DTS) and verify there is a matching source track if not, set the track to "None". */ - if (([[tempObject objectForKey:@"AudioEncoder"] isEqualToString:@"AC3 Passthru"] || [[tempObject objectForKey:@"AudioEncoder"] isEqualToString:@"DTS Passthru"]) && [trackLangPopUp indexOfSelectedItem] != 0) - { - hb_audio_config_t * audio; - /* get the audio source audio codec */ - audio = (hb_audio_config_t *) hb_list_audio_config_item( fTitle->list_audio, [trackLangPopUp indexOfSelectedItem] - 1 ); - if (audio != NULL && [[tempObject objectForKey:@"AudioEncoder"] isEqualToString:@"AC3 Passthru"] && audio->in.codec != HB_ACODEC_AC3 || - [[tempObject objectForKey:@"AudioEncoder"] isEqualToString:@"DTS Passthru"] && audio->in.codec != HB_ACODEC_DCA ) - { - /* We have a preset using ac3 passthru but no ac3 source audio, so set the track to "None" and bail */ - if ([[tempObject objectForKey:@"AudioEncoder"] isEqualToString:@"AC3 Passthru"]) - { - [self writeToActivityLog: "Preset calls for AC3 Pass thru ..."]; - } - if ([[tempObject objectForKey:@"AudioEncoder"] isEqualToString:@"DTS Passthru"]) - { - [self writeToActivityLog: "Preset calls for DTS Pass thru ..."]; - } - [self writeToActivityLog: "No matching source codec, setting track %d to None", i]; - [trackLangPopUp selectItemAtIndex: 0]; - [self audioTrackPopUpChanged: trackLangPopUp]; - } - } - } - } - - /* We now cleanup any extra audio tracks that may have been previously set if we need to */ - - if (i < 4) - { - [fAudLang4PopUp selectItemAtIndex: 0]; - [self audioTrackPopUpChanged: fAudLang4PopUp]; - - if (i < 3) - { - [fAudLang3PopUp selectItemAtIndex: 0]; - [self audioTrackPopUpChanged: fAudLang3PopUp]; - - if (i < 2) - { - [fAudLang2PopUp selectItemAtIndex: 0]; - [self audioTrackPopUpChanged: fAudLang2PopUp]; - } - } - } - - } - else - { - if ([chosenPreset objectForKey:@"Audio1Track"] > 0) - { - if ([fAudLang1PopUp indexOfSelectedItem] == 0) - { - [fAudLang1PopUp selectItemAtIndex: 1]; - } - [self audioTrackPopUpChanged: fAudLang1PopUp]; - [fAudTrack1CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Encoder"]]; - /* check our pref for core audio and use it in place of faac if preset is built in */ - if ([[chosenPreset objectForKey:@"Type"] intValue] == 0 && - [[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && - [[chosenPreset objectForKey:@"Audio1Encoder"] isEqualToString: @"AAC (faac)"]) - { - [fAudTrack1CodecPopUp selectItemWithTitle:@"AAC (CoreAudio)"]; - } - - [self audioTrackPopUpChanged: fAudTrack1CodecPopUp]; - [fAudTrack1MixPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Mixdown"]]; - /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default - * mixdown*/ - if ([fAudTrack1MixPopUp selectedItem] == nil) - { - [self audioTrackPopUpChanged: fAudTrack1CodecPopUp]; - } - [fAudTrack1RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Samplerate"]]; - /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */ - if (![[chosenPreset objectForKey:@"Audio1Encoder"] isEqualToString:@"AC3 Passthru"]) - { - [fAudTrack1BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Bitrate"]]; - } - [fAudTrack1DrcSlider setFloatValue:[[chosenPreset objectForKey:@"Audio1TrackDRCSlider"] floatValue]]; - [self audioDRCSliderChanged: fAudTrack1DrcSlider]; - } - - if ([chosenPreset objectForKey:@"Audio2Track"] > 0) - { - if ([fAudLang2PopUp indexOfSelectedItem] == 0) - { - [fAudLang2PopUp selectItemAtIndex: 1]; - } - [self audioTrackPopUpChanged: fAudLang2PopUp]; - [fAudTrack2CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio2Encoder"]]; - /* check our pref for core audio and use it in place of faac if preset is built in */ - if ([[chosenPreset objectForKey:@"Type"] intValue] == 0 && - [[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && - [[chosenPreset objectForKey:@"Audio2Encoder"] isEqualToString: @"AAC (faac)"]) - { - [fAudTrack2CodecPopUp selectItemWithTitle:@"AAC (CoreAudio)"]; - } - [self audioTrackPopUpChanged: fAudTrack2CodecPopUp]; - [fAudTrack2MixPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio2Mixdown"]]; - /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default - * mixdown*/ - if ([fAudTrack2MixPopUp selectedItem] == nil) - { - [self audioTrackPopUpChanged: fAudTrack2CodecPopUp]; - } - [fAudTrack2RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio2Samplerate"]]; - /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */ - if (![[chosenPreset objectForKey:@"Audio2Encoder"] isEqualToString:@"AC3 Passthru"]) - { - [fAudTrack2BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio2Bitrate"]]; - } - [fAudTrack2DrcSlider setFloatValue:[[chosenPreset objectForKey:@"Audio2TrackDRCSlider"] floatValue]]; - [self audioDRCSliderChanged: fAudTrack2DrcSlider]; - } - if ([chosenPreset objectForKey:@"Audio3Track"] > 0) - { - if ([fAudLang3PopUp indexOfSelectedItem] == 0) - { - [fAudLang3PopUp selectItemAtIndex: 1]; - } - [self audioTrackPopUpChanged: fAudLang3PopUp]; - [fAudTrack3CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio3Encoder"]]; - /* check our pref for core audio and use it in place of faac if preset is built in */ - if ([[chosenPreset objectForKey:@"Type"] intValue] == 0 && - [[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && - [[chosenPreset objectForKey:@"Audio3Encoder"] isEqualToString: @"AAC (faac)"]) - { - [fAudTrack3CodecPopUp selectItemWithTitle:@"AAC (CoreAudio)"]; - } - [self audioTrackPopUpChanged: fAudTrack3CodecPopUp]; - [fAudTrack3MixPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio3Mixdown"]]; - /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default - * mixdown*/ - if ([fAudTrack3MixPopUp selectedItem] == nil) - { - [self audioTrackPopUpChanged: fAudTrack3CodecPopUp]; - } - [fAudTrack3RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio3Samplerate"]]; - /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */ - if (![[chosenPreset objectForKey:@"Audio3Encoder"] isEqualToString: @"AC3 Passthru"]) - { - [fAudTrack3BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio3Bitrate"]]; - } - [fAudTrack3DrcSlider setFloatValue:[[chosenPreset objectForKey:@"Audio3TrackDRCSlider"] floatValue]]; - [self audioDRCSliderChanged: fAudTrack3DrcSlider]; - } - if ([chosenPreset objectForKey:@"Audio4Track"] > 0) - { - if ([fAudLang4PopUp indexOfSelectedItem] == 0) - { - [fAudLang4PopUp selectItemAtIndex: 1]; - } - [self audioTrackPopUpChanged: fAudLang4PopUp]; - [fAudTrack4CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio4Encoder"]]; - /* check our pref for core audio and use it in place of faac if preset is built in */ - if ([[chosenPreset objectForKey:@"Type"] intValue] == 0 && - [[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && - [[chosenPreset objectForKey:@"Audio4Encoder"] isEqualToString: @"AAC (faac)"]) - { - [fAudTrack4CodecPopUp selectItemWithTitle:@"AAC (CoreAudio)"]; - } - [self audioTrackPopUpChanged: fAudTrack4CodecPopUp]; - [fAudTrack4MixPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio4Mixdown"]]; - /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default - * mixdown*/ - if ([fAudTrack4MixPopUp selectedItem] == nil) - { - [self audioTrackPopUpChanged: fAudTrack4CodecPopUp]; - } - [fAudTrack4RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio4Samplerate"]]; - /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */ - if (![[chosenPreset objectForKey:@"Audio4Encoder"] isEqualToString:@"AC3 Passthru"]) - { - [fAudTrack4BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio4Bitrate"]]; - } - [fAudTrack4DrcSlider setFloatValue:[[chosenPreset objectForKey:@"Audio4TrackDRCSlider"] floatValue]]; - [self audioDRCSliderChanged: fAudTrack4DrcSlider]; - } - - /* We now cleanup any extra audio tracks that may have been previously set if we need to */ - - if (![chosenPreset objectForKey:@"Audio2Track"] || [chosenPreset objectForKey:@"Audio2Track"] == 0) - { - [fAudLang2PopUp selectItemAtIndex: 0]; - [self audioTrackPopUpChanged: fAudLang2PopUp]; - } - if (![chosenPreset objectForKey:@"Audio3Track"] || [chosenPreset objectForKey:@"Audio3Track"] > 0) - { - [fAudLang3PopUp selectItemAtIndex: 0]; - [self audioTrackPopUpChanged: fAudLang3PopUp]; - } - if (![chosenPreset objectForKey:@"Audio4Track"] || [chosenPreset objectForKey:@"Audio4Track"] > 0) - { - [fAudLang4PopUp selectItemAtIndex: 0]; - [self audioTrackPopUpChanged: fAudLang4PopUp]; - } - } + [fAudioDelegate addTracksFromPreset: chosenPreset]; /*Subtitles*/ [fSubPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Subtitles"]]; @@ -7125,14 +5616,36 @@ return YES; job->keep_ratio = [[chosenPreset objectForKey:@"PictureKeepRatio"] intValue]; if (job->keep_ratio == 1) { + int height = fTitle->height; + + if ( job->height && job->height < fTitle->height ) + height = job->height; + hb_fix_aspect( job, HB_KEEP_WIDTH ); - if( job->height > fTitle->height ) + // Make sure the resulting height is less than + // the title height and less than the height + // requested in the preset. + if( job->height > height ) { - job->height = fTitle->height; + job->height = height; hb_fix_aspect( job, HB_KEEP_HEIGHT ); } } job->anamorphic.mode = [[chosenPreset objectForKey:@"PicturePAR"] intValue]; + if ( job->anamorphic.mode > 0 ) + { + int w, h, par_w, par_h; + + job->anamorphic.par_width = fTitle->pixel_aspect_width; + job->anamorphic.par_height = fTitle->pixel_aspect_height; + job->maxWidth = job->width; + job->maxHeight = job->height; + hb_set_anamorphic_size( job, &w, &h, &par_w, &par_h ); + job->maxWidth = 0; + job->maxHeight = 0; + job->width = w; + job->height = h; + } } @@ -7239,6 +5752,9 @@ return YES; [fPictureController SetTitle:fTitle]; [self calculatePictureSizing:nil]; } + else { + [self setHasValidPresetSelected: NO]; + } } @@ -7307,6 +5823,18 @@ return YES; } +- (IBAction) addPresetPicDropdownChanged: (id) sender +{ + if ([fPresetNewPicSettingsPopUp indexOfSelectedItem] == 1) + { + [fPresetNewPicWidthHeightBox setHidden:NO]; + } + else + { + [fPresetNewPicWidthHeightBox setHidden:YES]; + } +} + - (IBAction) showAddPresetPanel: (id) sender { /* Deselect the currently selected Preset if there is one*/ @@ -7315,7 +5843,7 @@ return YES; /* Populate the preset picture settings popup here */ [fPresetNewPicSettingsPopUp removeAllItems]; [fPresetNewPicSettingsPopUp addItemWithTitle:@"None"]; - [fPresetNewPicSettingsPopUp addItemWithTitle:@"Current"]; + [fPresetNewPicSettingsPopUp addItemWithTitle:@"Custom"]; [fPresetNewPicSettingsPopUp addItemWithTitle:@"Source Maximum (post source scan)"]; [fPresetNewPicSettingsPopUp selectItemAtIndex: 0]; /* Uncheck the preset use filters checkbox */ @@ -7325,6 +5853,12 @@ return YES; /* Erase info from the input fields*/ [fPresetNewName setStringValue: @""]; [fPresetNewDesc setStringValue: @""]; + + /* Initialize custom height and width settings to current values */ + + [fPresetNewPicWidth setStringValue: [NSString stringWithFormat:@"%d",fTitle->job->width]]; + [fPresetNewPicHeight setStringValue: [NSString stringWithFormat:@"%d",fTitle->job->height]]; + [self addPresetPicDropdownChanged:nil]; /* Show the panel */ [NSApp beginSheet:fAddPresetPanel modalForWindow:fWindow modalDelegate:nil didEndSelector:NULL contextInfo:NULL]; } @@ -7449,6 +5983,7 @@ return YES; { [preset setObject:[fVidRatePopUp titleOfSelectedItem] forKey:@"VideoFramerate"]; } + [preset setObject:[NSNumber numberWithInt:[fFrameratePfrCheck state]] forKey:@"VideoFrameratePFR"]; /* 2 Pass Encoding */ [preset setObject:[NSNumber numberWithInt:[fVidTwoPassCheck state]] forKey:@"VideoTwoPass"]; @@ -7456,11 +5991,11 @@ return YES; [preset setObject:[NSNumber numberWithInt:[fVidTurboPassCheck state]] forKey:@"VideoTurboTwoPass"]; /*Picture Settings*/ hb_job_t * job = fTitle->job; + /* Picture Sizing */ - /* Use Max Picture settings for whatever the dvd is.*/ [preset setObject:[NSNumber numberWithInt:0] forKey:@"UsesMaxPictureSettings"]; - [preset setObject:[NSNumber numberWithInt:fTitle->job->width] forKey:@"PictureWidth"]; - [preset setObject:[NSNumber numberWithInt:fTitle->job->height] forKey:@"PictureHeight"]; + [preset setObject:[NSNumber numberWithInt:[fPresetNewPicWidth intValue]] forKey:@"PictureWidth"]; + [preset setObject:[NSNumber numberWithInt:[fPresetNewPicHeight intValue]] forKey:@"PictureHeight"]; [preset setObject:[NSNumber numberWithInt:fTitle->job->keep_ratio] forKey:@"PictureKeepRatio"]; [preset setObject:[NSNumber numberWithInt:fTitle->job->anamorphic.mode] forKey:@"PicturePAR"]; [preset setObject:[NSNumber numberWithInt:fTitle->job->modulus] forKey:@"PictureModulus"]; @@ -7487,62 +6022,7 @@ return YES; /*Audio*/ NSMutableArray *audioListArray = [[NSMutableArray alloc] init]; - /* we actually call the methods for the nests here */ - if ([fAudLang1PopUp indexOfSelectedItem] > 0) - { - NSMutableDictionary *audioTrack1Array = [[NSMutableDictionary alloc] init]; - [audioTrack1Array setObject:[NSNumber numberWithInt:[fAudLang1PopUp indexOfSelectedItem]] forKey:@"AudioTrack"]; - [audioTrack1Array setObject:[fAudLang1PopUp titleOfSelectedItem] forKey:@"AudioTrackDescription"]; - [audioTrack1Array setObject:[fAudTrack1CodecPopUp titleOfSelectedItem] forKey:@"AudioEncoder"]; - [audioTrack1Array setObject:[fAudTrack1MixPopUp titleOfSelectedItem] forKey:@"AudioMixdown"]; - [audioTrack1Array setObject:[fAudTrack1RatePopUp titleOfSelectedItem] forKey:@"AudioSamplerate"]; - [audioTrack1Array setObject:[fAudTrack1BitratePopUp titleOfSelectedItem] forKey:@"AudioBitrate"]; - [audioTrack1Array setObject:[NSNumber numberWithFloat:[fAudTrack1DrcSlider floatValue]] forKey:@"AudioTrackDRCSlider"]; - [audioTrack1Array autorelease]; - [audioListArray addObject:audioTrack1Array]; - } - - if ([fAudLang2PopUp indexOfSelectedItem] > 0) - { - NSMutableDictionary *audioTrack2Array = [[NSMutableDictionary alloc] init]; - [audioTrack2Array setObject:[NSNumber numberWithInt:[fAudLang2PopUp indexOfSelectedItem]] forKey:@"AudioTrack"]; - [audioTrack2Array setObject:[fAudLang2PopUp titleOfSelectedItem] forKey:@"AudioTrackDescription"]; - [audioTrack2Array setObject:[fAudTrack2CodecPopUp titleOfSelectedItem] forKey:@"AudioEncoder"]; - [audioTrack2Array setObject:[fAudTrack2MixPopUp titleOfSelectedItem] forKey:@"AudioMixdown"]; - [audioTrack2Array setObject:[fAudTrack2RatePopUp titleOfSelectedItem] forKey:@"AudioSamplerate"]; - [audioTrack2Array setObject:[fAudTrack2BitratePopUp titleOfSelectedItem] forKey:@"AudioBitrate"]; - [audioTrack2Array setObject:[NSNumber numberWithFloat:[fAudTrack2DrcSlider floatValue]] forKey:@"AudioTrackDRCSlider"]; - [audioTrack2Array autorelease]; - [audioListArray addObject:audioTrack2Array]; - } - - if ([fAudLang3PopUp indexOfSelectedItem] > 0) - { - NSMutableDictionary *audioTrack3Array = [[NSMutableDictionary alloc] init]; - [audioTrack3Array setObject:[NSNumber numberWithInt:[fAudLang3PopUp indexOfSelectedItem]] forKey:@"AudioTrack"]; - [audioTrack3Array setObject:[fAudLang3PopUp titleOfSelectedItem] forKey:@"AudioTrackDescription"]; - [audioTrack3Array setObject:[fAudTrack3CodecPopUp titleOfSelectedItem] forKey:@"AudioEncoder"]; - [audioTrack3Array setObject:[fAudTrack3MixPopUp titleOfSelectedItem] forKey:@"AudioMixdown"]; - [audioTrack3Array setObject:[fAudTrack3RatePopUp titleOfSelectedItem] forKey:@"AudioSamplerate"]; - [audioTrack3Array setObject:[fAudTrack3BitratePopUp titleOfSelectedItem] forKey:@"AudioBitrate"]; - [audioTrack3Array setObject:[NSNumber numberWithFloat:[fAudTrack3DrcSlider floatValue]] forKey:@"AudioTrackDRCSlider"]; - [audioTrack3Array autorelease]; - [audioListArray addObject:audioTrack3Array]; - } - - if ([fAudLang4PopUp indexOfSelectedItem] > 0) - { - NSMutableDictionary *audioTrack4Array = [[NSMutableDictionary alloc] init]; - [audioTrack4Array setObject:[NSNumber numberWithInt:[fAudLang4PopUp indexOfSelectedItem]] forKey:@"AudioTrack"]; - [audioTrack4Array setObject:[fAudLang4PopUp titleOfSelectedItem] forKey:@"AudioTrackDescription"]; - [audioTrack4Array setObject:[fAudTrack4CodecPopUp titleOfSelectedItem] forKey:@"AudioEncoder"]; - [audioTrack4Array setObject:[fAudTrack4MixPopUp titleOfSelectedItem] forKey:@"AudioMixdown"]; - [audioTrack4Array setObject:[fAudTrack4RatePopUp titleOfSelectedItem] forKey:@"AudioSamplerate"]; - [audioTrack4Array setObject:[fAudTrack4BitratePopUp titleOfSelectedItem] forKey:@"AudioBitrate"]; - [audioTrack4Array setObject:[NSNumber numberWithFloat:[fAudTrack4DrcSlider floatValue]] forKey:@"AudioTrackDRCSlider"]; - [audioTrack4Array autorelease]; - [audioListArray addObject:audioTrack4Array]; - } + [fAudioDelegate prepareAudioForPreset: audioListArray]; [preset setObject:[NSMutableArray arrayWithArray: audioListArray] forKey:@"AudioList"]; @@ -8021,6 +6501,154 @@ return YES; } +#pragma mark - +#pragma mark Chapter Files Import / Export + +- (IBAction) browseForChapterFile: (id) sender +{ + /* Open a panel to let the user choose the file */ + NSOpenPanel * panel = [NSOpenPanel openPanel]; + /* We get the current file name and path from the destination field here */ + [panel beginSheetForDirectory: [NSString stringWithFormat:@"%@/", + [[NSUserDefaults standardUserDefaults] stringForKey:@"LastDestinationDirectory"]] + file: NULL + types: [NSArray arrayWithObjects:@"csv",nil] + modalForWindow: fWindow modalDelegate: self + didEndSelector: @selector( browseForChapterFileDone:returnCode:contextInfo: ) + contextInfo: NULL]; +} + +- (void) browseForChapterFileDone: (NSOpenPanel *) sheet + returnCode: (int) returnCode contextInfo: (void *) contextInfo +{ + NSArray *chaptersArray; /* temp array for chapters */ + NSMutableArray *chaptersMutableArray; /* temp array for chapters */ + NSString *chapterName; /* temp string from file */ + int chapters, i; + + if( returnCode == NSOKButton ) /* if they click OK */ + { + chapterName = [[NSString alloc] initWithContentsOfFile:[sheet filename] encoding:NSUTF8StringEncoding error:NULL]; + chaptersArray = [chapterName componentsSeparatedByString:@"\n"]; + chaptersMutableArray= [chaptersArray mutableCopy]; + chapters = [fChapterTitlesDelegate numberOfRowsInTableView:fChapterTable]; + if ([chaptersMutableArray count] > 0) + { + /* if last item is empty remove it */ + if ([[chaptersMutableArray objectAtIndex:[chaptersArray count]-1] length] == 0) + { + [chaptersMutableArray removeLastObject]; + } + } + /* if chapters in table is not equal to array count */ + if ((unsigned int) chapters != [chaptersMutableArray count]) + { + [sheet close]; + [[NSAlert alertWithMessageText:NSLocalizedString(@"Unable to load chapter file", @"Unable to load chapter file") + defaultButton:NSLocalizedString(@"OK", @"OK") + alternateButton:NULL + otherButton:NULL + informativeTextWithFormat:NSLocalizedString(@"%d chapters expected, %d chapters found in %@", @"%d chapters expected, %d chapters found in %@"), + chapters, [chaptersMutableArray count], [[sheet filename] lastPathComponent]] runModal]; + return; + } + /* otherwise, go ahead and populate table with array */ + for (i=0; i 5) + { + /* avoid a segfault */ + /* Get the Range.location of the first comma in the line and then put everything after that into chapterTitle */ + NSRange firstCommaRange = [[chaptersMutableArray objectAtIndex:i] rangeOfString:@","]; + NSString *chapterTitle = [[chaptersMutableArray objectAtIndex:i] substringFromIndex:firstCommaRange.location + 1]; + /* Since we store our chapterTitle commas as "\," for the cli, we now need to remove the escaping "\" from the title */ + chapterTitle = [chapterTitle stringByReplacingOccurrencesOfString:@"\\," withString:@","]; + [fChapterTitlesDelegate tableView:fChapterTable + setObjectValue:chapterTitle + forTableColumn:fChapterTableNameColumn + row:i]; + } + else + { + [sheet close]; + [[NSAlert alertWithMessageText:NSLocalizedString(@"Unable to load chapter file", @"Unable to load chapter file") + defaultButton:NSLocalizedString(@"OK", @"OK") + alternateButton:NULL + otherButton:NULL + informativeTextWithFormat:NSLocalizedString(@"%@ was not formatted as expected.", @"%@ was not formatted as expected."), [[sheet filename] lastPathComponent]] runModal]; + [fChapterTable reloadData]; + return; + } + } + [fChapterTable reloadData]; + } +} + +- (IBAction) browseForChapterFileSave: (id) sender +{ + NSSavePanel *panel = [NSSavePanel savePanel]; + /* Open a panel to let the user save to a file */ + [panel setAllowedFileTypes:[NSArray arrayWithObjects:@"csv",nil]]; + [panel beginSheetForDirectory: [[fDstFile2Field stringValue] stringByDeletingLastPathComponent] + file: [[[[fDstFile2Field stringValue] lastPathComponent] stringByDeletingPathExtension] + stringByAppendingString:@"-chapters.csv"] + modalForWindow: fWindow + modalDelegate: self + didEndSelector: @selector( browseForChapterFileSaveDone:returnCode:contextInfo: ) + contextInfo: NULL]; +} + +- (void) browseForChapterFileSaveDone: (NSSavePanel *) sheet + returnCode: (int) returnCode contextInfo: (void *) contextInfo +{ + NSString *chapterName; /* pointer for string for later file-writing */ + NSString *chapterTitle; + NSError *saveError = [[NSError alloc] init]; + int chapters, i; /* ints for the number of chapters in the table and the loop */ + + if( returnCode == NSOKButton ) /* if they clicked OK */ + { + chapters = [fChapterTitlesDelegate numberOfRowsInTableView:fChapterTable]; + chapterName = [NSString string]; + for (i=0; i