X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=macosx%2FController.mm;h=f7e79c4844b3489dc014d297558b898b5d538754;hb=83588c143bb574905fc23be31d1ab3b99ba5e791;hp=483dc8523a825e920e1618f6059c70d82bb35c37;hpb=768e31f1c2aaa91dc5a222525e1ac98805e50258;p=handbrake-jp%2Fhandbrake-jp-git.git diff --git a/macosx/Controller.mm b/macosx/Controller.mm index 483dc852..f7e79c48 100644 --- a/macosx/Controller.mm +++ b/macosx/Controller.mm @@ -9,15 +9,18 @@ #import "HBPreferencesController.h" #import "HBDVDDetector.h" #import "HBPresets.h" +#import "HBPreviewController.h" #define DragDropSimplePboardType @"MyCustomOutlineViewPboardType" -/* We setup the toolbar values here */ +/* We setup the toolbar values here ShowPreviewIdentifier */ static NSString * ToggleDrawerIdentifier = @"Toggle Drawer Item Identifier"; static NSString * StartEncodingIdentifier = @"Start Encoding Item Identifier"; static NSString * PauseEncodingIdentifier = @"Pause Encoding Item Identifier"; static NSString * ShowQueueIdentifier = @"Show Queue Item Identifier"; static NSString * AddToQueueIdentifier = @"Add to Queue Item Identifier"; +static NSString * ShowPictureIdentifier = @"Show Picture Window Item Identifier"; +static NSString * ShowPreviewIdentifier = @"Show Preview Window Item Identifier"; static NSString * ShowActivityIdentifier = @"Debug Output Item Identifier"; static NSString * ChooseSourceIdentifier = @"Choose Source Item Identifier"; @@ -35,6 +38,15 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It return nil; } + /* replace bundled app icon with one which is 32/64-bit savvy */ +#if defined( __LP64__ ) + fApplicationIcon = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:@"HandBrake-64.icns"]]; +#else + fApplicationIcon = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:@"HandBrake.icns"]]; +#endif + if( fApplicationIcon != nil ) + [NSApp setApplicationIconImage:fApplicationIcon]; + [HBPreferencesController registerUserDefaults]; fHandle = NULL; fQueueEncodeLibhb = NULL; @@ -42,28 +54,34 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It * outputPanel needs it right away, as may other future methods */ NSString *libraryDir = [NSSearchPathForDirectoriesInDomains( NSLibraryDirectory, - NSUserDomainMask, - YES ) objectAtIndex:0]; + NSUserDomainMask, + YES ) objectAtIndex:0]; AppSupportDirectory = [[libraryDir stringByAppendingPathComponent:@"Application Support"] - stringByAppendingPathComponent:@"HandBrake"]; + stringByAppendingPathComponent:@"HandBrake"]; if( ![[NSFileManager defaultManager] fileExistsAtPath:AppSupportDirectory] ) { [[NSFileManager defaultManager] createDirectoryAtPath:AppSupportDirectory attributes:nil]; } - + /* Check for and create the App Support Preview directory if necessary */ + NSString *PreviewDirectory = [AppSupportDirectory stringByAppendingPathComponent:@"Previews"]; + if( ![[NSFileManager defaultManager] fileExistsAtPath:PreviewDirectory] ) + { + [[NSFileManager defaultManager] createDirectoryAtPath:PreviewDirectory + attributes:nil]; + } outputPanel = [[HBOutputPanelController alloc] init]; - fPictureController = [[PictureController alloc] initWithDelegate:self]; + fPictureController = [[PictureController alloc] init]; fQueueController = [[HBQueueController alloc] init]; fAdvancedOptions = [[HBAdvancedController alloc] init]; /* we init the HBPresets class which currently is only used - * for updating built in presets, may move more functionality - * there in the future - */ + * for updating built in presets, may move more functionality + * there in the future + */ fPresetsBuiltin = [[HBPresets alloc] init]; 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:@"CFBundleGetInfoString"]] stringByAppendingString: [NSString stringWithFormat: @" (%@)", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]]]; + NSString *versionStringFull = [[NSString stringWithFormat: @"Handbrake Version: %@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]] stringByAppendingString: [NSString stringWithFormat: @" (%@)", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]]]; [self writeToActivityLog: "%s", [versionStringFull UTF8String]]; return self; @@ -73,26 +91,42 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It - (void) applicationDidFinishLaunching: (NSNotification *) notification { /* Init libhb with check for updates libhb style set to "0" so its ignored and lets sparkle take care of it */ - fHandle = hb_init(HB_DEBUG_ALL, 0); + int loggingLevel = [[[NSUserDefaults standardUserDefaults] objectForKey:@"LoggingLevel"] intValue]; + fHandle = hb_init(loggingLevel, 0); + /* Optional dvd nav UseDvdNav*/ + hb_dvd_set_dvdnav([[[NSUserDefaults standardUserDefaults] objectForKey:@"UseDvdNav"] boolValue]); /* Init a separate instance of libhb for user scanning and setting up jobs */ - fQueueEncodeLibhb = hb_init(HB_DEBUG_ALL, 0); + fQueueEncodeLibhb = hb_init(loggingLevel, 0); // Set the Growl Delegate [GrowlApplicationBridge setGrowlDelegate: self]; /* Init others controllers */ [fPictureController SetHandle: fHandle]; + [fPictureController setHBController: self]; + [fQueueController setHandle: fQueueEncodeLibhb]; [fQueueController setHBController: self]; fChapterTitlesDelegate = [[ChapterTitles alloc] init]; [fChapterTable setDataSource:fChapterTitlesDelegate]; [fChapterTable setDelegate:fChapterTitlesDelegate]; + + /* setup the subtitles delegate and connections to table */ + fSubtitlesDelegate = [[HBSubtitles alloc] init]; + [fSubtitlesTable setDataSource:fSubtitlesDelegate]; + [fSubtitlesTable setDelegate:fSubtitlesDelegate]; + [fSubtitlesTable setRowHeight:25.0]; + + [fPresetsOutlineView setAutosaveName:@"Presets View"]; + [fPresetsOutlineView setAutosaveExpandedItems:YES]; + + dockIconProgress = 0; /* Call UpdateUI every 1/2 sec */ [[NSRunLoop currentRunLoop] addTimer:[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(updateUI:) userInfo:nil repeats:YES] - forMode:NSEventTrackingRunLoopMode]; + forMode:NSDefaultRunLoopMode]; // Open debug output window now if it was visible when HB was closed if ([[NSUserDefaults standardUserDefaults] boolForKey:@"OutputPanelIsOpen"]) @@ -114,26 +148,94 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It * user if they want to reload the queue */ if ([QueueFileArray count] > 0) { + /* run getQueueStats to see whats in the queue file */ + [self getQueueStats]; + /* this results in these values + * fEncodingQueueItem = 0; + * fPendingCount = 0; + * fCompletedCount = 0; + * fCanceledCount = 0; + * fWorkingCount = 0; + */ + /*On Screen Notification*/ - NSString * alertTitle = [NSString stringWithFormat:NSLocalizedString(@"HandBrake Has Detected Item(s) From Your Previous Queue.", nil)]; + NSString * alertTitle; + + /* 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) + { + alertTitle = [NSString stringWithFormat: + NSLocalizedString(@"There is already an instance of HandBrake running.", @"")]; 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)); + alertTitle, + NSLocalizedString(@"Reload Queue", nil), + nil, + nil, + fWindow, self, + nil, @selector(didDimissReloadQueue:returnCode:contextInfo:), nil, + NSLocalizedString(@" HandBrake will now load up the existing queue.", nil)); + } + else + { + if (fWorkingCount > 0) + { + alertTitle = [NSString stringWithFormat: + NSLocalizedString(@"HandBrake Has Detected %d Previously Encoding Item 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)); + } + // call didDimissReloadQueue: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo // right below to either clear the old queue or keep it loaded up. } else { - - /* Show Browse Sources Window ASAP */ - [self performSelectorOnMainThread:@selector(browseSources:) - withObject:nil waitUntilDone:NO]; - } + /* 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]; + } + } +} + +- (int) hbInstances +{ + /* check to see if another instance of HandBrake.app is running */ + NSArray *runningAppDictionaries = [[NSWorkspace sharedWorkspace] launchedApplications]; + NSDictionary *aDictionary; + int hbInstances = 0; + for (aDictionary in runningAppDictionaries) + { + // NSLog(@"Open App: %@", [aDictionary valueForKey:@"NSApplicationName"]); + + if ([[aDictionary valueForKey:@"NSApplicationName"] isEqualToString:@"HandBrake"]) + { + hbInstances++; + } + } + return hbInstances; } - (void) didDimissReloadQueue: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo @@ -141,28 +243,51 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It if (returnCode == NSAlertOtherReturn) { [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]; + } + } + else + { + if ([self hbInstances] == 1) + { + [self setQueueEncodingItemsAsPending]; + } + [self showQueueWindow:NULL]; } - - [self performSelectorOnMainThread:@selector(browseSources:) - withObject:nil waitUntilDone:NO]; } - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication *) app { - // Warn if encoding a movie + /* if we are in preview full screen mode, we need to go to + * windowed mode and release the display before we terminate. + * We do it here (instead of applicationWillTerminate) so we + * release the displays and can then see the alerts below. + */ + if ([fPictureController previewFullScreenMode] == YES) + { + [fPictureController previewGoWindowed:nil]; + } + hb_state_t s; - hb_get_state( fHandle, &s ); + hb_get_state( fQueueEncodeLibhb, &s ); if ( s.state != HB_STATE_IDLE ) { int result = NSRunCriticalAlertPanel( - NSLocalizedString(@"Are you sure you want to quit HandBrake?", nil), - NSLocalizedString(@"If you quit HandBrake, your movie will be lost. Do you want to quit anyway?", nil), - NSLocalizedString(@"Quit", nil), NSLocalizedString(@"Don't Quit", nil), nil, @"A movie" ); + NSLocalizedString(@"Are you sure you want to quit HandBrake?", nil), + NSLocalizedString(@"If you quit HandBrake your current encode will be reloaded into your queue at next launch. Do you want to quit anyway?", nil), + NSLocalizedString(@"Quit", nil), NSLocalizedString(@"Don't Quit", nil), nil, @"A movie" ); if (result == NSAlertDefaultReturn) { - [self doCancelCurrentJob]; return NSTerminateNow; } else @@ -170,12 +295,12 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It } // Warn if items still in the queue - else if ( hb_count( fHandle ) > 0 ) + else if ( fPendingCount > 0 ) { int result = NSRunCriticalAlertPanel( - NSLocalizedString(@"Are you sure you want to quit HandBrake?", nil), - NSLocalizedString(@"One or more encodes are queued for encoding. Do you want to quit anyway?", nil), - NSLocalizedString(@"Quit", nil), NSLocalizedString(@"Don't Quit", nil), nil); + NSLocalizedString(@"Are you sure you want to quit HandBrake?", nil), + NSLocalizedString(@"There are pending encodes in your queue. Do you want to quit anyway?",nil), + NSLocalizedString(@"Quit", nil), NSLocalizedString(@"Don't Quit", nil), nil); if ( result == NSAlertDefaultReturn ) return NSTerminateNow; @@ -188,9 +313,14 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It - (void)applicationWillTerminate:(NSNotification *)aNotification { - [browsedSourceDisplayName release]; + + [browsedSourceDisplayName release]; [outputPanel release]; [fQueueController release]; + [fPreviewController release]; + [fPictureController release]; + [fApplicationIcon release]; + hb_close(&fHandle); hb_close(&fQueueEncodeLibhb); } @@ -201,17 +331,17 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It [fWindow center]; [fWindow setExcludedFromWindowsMenu:YES]; [fAdvancedOptions setView:fAdvancedView]; - + /* lets setup our presets drawer for drag and drop here */ [fPresetsOutlineView registerForDraggedTypes: [NSArray arrayWithObject:DragDropSimplePboardType] ]; [fPresetsOutlineView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES]; [fPresetsOutlineView setVerticalMotionCanBeginDrag: YES]; - + /* Initialize currentScanCount so HB can use it to - evaluate successive scans */ + evaluate successive scans */ currentScanCount = 0; - - + + /* Init UserPresets .plist */ [self loadPresets]; @@ -219,15 +349,38 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It [self loadQueueFile]; fRipIndicatorShown = NO; // initially out of view in the nib + + /* For 64 bit builds, the threaded animation in the progress + * indicators conflicts with the animation in the advanced tab + * for reasons not completely clear. jbrjake found a note in the + * 10.5 dev notes regarding this possiblility. It was also noted + * that unless specified, setUsesThreadedAnimation defaults to true. + * So, at least for now we set the indicator animation to NO for + * both the scan and regular progress indicators for both 32 and 64 bit + * as it test out fine on both and there is no reason our progress indicators + * should require their own thread. + */ + [fScanIndicator setUsesThreadedAnimation:NO]; + [fRipIndicator setUsesThreadedAnimation:NO]; + + + /* Show/Dont Show Presets drawer upon launch based - on user preference DefaultPresetsDrawerShow*/ - if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultPresetsDrawerShow"] > 0) + on user preference DefaultPresetsDrawerShow*/ + if( [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultPresetsDrawerShow"] > 0 ) { + [fPresetDrawer setDelegate:self]; + NSSize drawerSize = NSSizeFromString( [[NSUserDefaults standardUserDefaults] + stringForKey:@"Drawer Size"] ); + if( drawerSize.width ) + [fPresetDrawer setContentSize: drawerSize]; [fPresetDrawer open]; } - - + + /* Initially set the dvd angle widgets to hidden (dvdnav only) */ + [fSrcAngleLabel setHidden:YES]; + [fSrcAnglePopUp setHidden:YES]; /* Destination box*/ NSMenuItem *menuItem; @@ -238,43 +391,37 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It // MKV file menuItem = [[fDstFormatPopUp menu] addItemWithTitle:@"MKV file" action: NULL keyEquivalent: @""]; [menuItem setTag: HB_MUX_MKV]; - // AVI file - menuItem = [[fDstFormatPopUp menu] addItemWithTitle:@"AVI file" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_MUX_AVI]; - // OGM file - menuItem = [[fDstFormatPopUp menu] addItemWithTitle:@"OGM file" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_MUX_OGM]; + [fDstFormatPopUp selectItemAtIndex: 0]; - + [self formatPopUpChanged:nil]; - + /* We enable the create chapters checkbox here since we are .mp4 */ [fCreateChapterMarkers setEnabled: YES]; if ([fDstFormatPopUp indexOfSelectedItem] == 0 && [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultChapterMarkers"] > 0) { [fCreateChapterMarkers setState: NSOnState]; } - - - - + + + + [fDstFile2Field setStringValue: [NSString stringWithFormat: - @"%@/Desktop/Movie.mp4", NSHomeDirectory()]]; - + @"%@/Desktop/Movie.mp4", NSHomeDirectory()]]; + /* Video encoder */ [fVidEncoderPopUp removeAllItems]; [fVidEncoderPopUp addItemWithTitle: @"FFmpeg"]; - [fVidEncoderPopUp addItemWithTitle: @"XviD"]; - - - + + + /* Video quality */ [fVidTargetSizeField setIntValue: 700]; [fVidBitrateField setIntValue: 1000]; - + [fVidQualityMatrix selectCell: fVidBitrateCell]; [self videoMatrixChanged:nil]; - + /* Video framerate */ [fVidRatePopUp removeAllItems]; [fVidRatePopUp addItemWithTitle: NSLocalizedString( @"Same as source", @"" )]; @@ -283,22 +430,22 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It if ([[NSString stringWithCString: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%.3f",23.976]]) { [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@", - [NSString stringWithCString: hb_video_rates[i].string], @" (NTSC Film)"]]; + [NSString stringWithCString: hb_video_rates[i].string], @" (NTSC Film)"]]; } else if ([[NSString stringWithCString: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%d",25]]) { [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@", - [NSString stringWithCString: hb_video_rates[i].string], @" (PAL Film/Video)"]]; + [NSString stringWithCString: hb_video_rates[i].string], @" (PAL Film/Video)"]]; } else if ([[NSString stringWithCString: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%.2f",29.97]]) { [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@", - [NSString stringWithCString: hb_video_rates[i].string], @" (NTSC Video)"]]; + [NSString stringWithCString: hb_video_rates[i].string], @" (NTSC Video)"]]; } else { [fVidRatePopUp addItemWithTitle: - [NSString stringWithCString: hb_video_rates[i].string]]; + [NSString stringWithCString: hb_video_rates[i].string]]; } } [fVidRatePopUp selectItemAtIndex: 0]; @@ -311,8 +458,8 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It for( int i = 0; i < hb_audio_bitrates_count; i++ ) { [fAudTrack1BitratePopUp addItemWithTitle: - [NSString stringWithCString: hb_audio_bitrates[i].string]]; - + [NSString stringWithCString: hb_audio_bitrates[i].string]]; + } [fAudTrack1BitratePopUp selectItemAtIndex: hb_audio_bitrates_default]; @@ -321,39 +468,38 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It for( int i = 0; i < hb_audio_rates_count; i++ ) { [fAudTrack1RatePopUp addItemWithTitle: - [NSString stringWithCString: hb_audio_rates[i].string]]; + [NSString stringWithCString: hb_audio_rates[i].string]]; } [fAudTrack1RatePopUp selectItemAtIndex: hb_audio_rates_default]; /* Bottom */ [fStatusField setStringValue: @""]; - + [self enableUI: NO]; [self setupToolbar]; - + /* We disable the Turbo 1st pass checkbox since we are not x264 */ [fVidTurboPassCheck setEnabled: NO]; [fVidTurboPassCheck setState: NSOffState]; - - + + /* lets get our default prefs here */ [self getDefaultPresets:nil]; /* lets initialize the current successful scancount here to 0 */ currentSuccessfulScanCount = 0; - - + + } - (void) enableUI: (bool) b { NSControl * controls[] = - { fSrcTitleField, fSrcTitlePopUp, + { fSrcTitleField, fSrcTitlePopUp, fSrcChapterField, fSrcChapterStartPopUp, fSrcChapterToField, fSrcChapterEndPopUp, fSrcDuration1Field, fSrcDuration2Field, fDstFormatField, fDstFormatPopUp, fDstFile1Field, fDstFile2Field, - fDstBrowseButton, fVidRateField, fVidRatePopUp, - fVidEncoderField, fVidEncoderPopUp, fVidQualityField, - fVidQualityMatrix, fVidGrayscaleCheck, fSubField, fSubPopUp, + 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, @@ -363,16 +509,12 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It fAudTrack1BitratePopUp, fAudTrack2BitratePopUp, fAudTrack3BitratePopUp, fAudTrack4BitratePopUp, fAudDrcLabel, fAudTrack1DrcSlider, fAudTrack1DrcField, fAudTrack2DrcSlider, fAudTrack2DrcField, fAudTrack3DrcSlider, fAudTrack3DrcField, fAudTrack4DrcSlider,fAudTrack4DrcField, - fPictureButton,fQueueStatus,fPicSettingARkeep, fPicSettingDeinterlace,fPicLabelSettings,fPicLabelSrc, - fPicLabelOutp,fPicSettingsSrc,fPicSettingsOutp,fPicSettingsAnamorphic, - fPicLabelAr,fPicLabelDeinterlace,fPicSettingPAR,fPicLabelAnamorphic,fPresetsAdd,fPresetsDelete, - fCreateChapterMarkers,fVidTurboPassCheck,fDstMp4LargeFileCheck,fPicLabelAutoCrop, - fPicSettingAutoCrop,fPicSettingDetelecine,fPicLabelDetelecine,fPicLabelDenoise,fPicSettingDenoise, - fSubForcedCheck,fPicSettingDeblock,fPicLabelDeblock,fPicLabelDecomb,fPicSettingDecomb,fPresetsOutlineView, - fAudDrcLabel,fDstMp4HttpOptFileCheck,fDstMp4iPodFileCheck}; - + fQueueStatus,fPresetsAdd,fPresetsDelete,fSrcAngleLabel,fSrcAnglePopUp, + fCreateChapterMarkers,fVidTurboPassCheck,fDstMp4LargeFileCheck,fSubForcedCheck,fPresetsOutlineView, + fAudDrcLabel,fDstMp4HttpOptFileCheck,fDstMp4iPodFileCheck,fVidQualityRFField,fVidQualityRFLabel}; + for( unsigned i = 0; - i < sizeof( controls ) / sizeof( NSControl * ); i++ ) + i < sizeof( controls ) / sizeof( NSControl * ); i++ ) { if( [[controls[i] className] isEqualToString: @"NSTextField"] ) { @@ -380,29 +522,28 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It if( ![tf isBezeled] ) { [tf setTextColor: b ? [NSColor controlTextColor] : - [NSColor disabledControlTextColor]]; + [NSColor disabledControlTextColor]]; continue; } } [controls[i] setEnabled: 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]; - [self shouldEnableHttpMp4CheckBox: nil]; - + } else { - + [fPresetsOutlineView setEnabled: NO]; - + } - + [self videoMatrixChanged:nil]; [fAdvancedOptions enableUI:b]; } @@ -418,7 +559,6 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It **********************************************************************/ - (void) UpdateDockIcon: (float) progress { - NSImage * icon; NSData * tiff; NSBitmapImageRep * bmp; uint32_t * pen; @@ -428,17 +568,14 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It int row_start, row_end; int i, j; - /* Get application original icon */ - icon = [NSImage imageNamed: @"NSApplicationIcon"]; - if( progress < 0.0 || progress > 1.0 ) { - [NSApp setApplicationIconImage: icon]; + [NSApp setApplicationIconImage: fApplicationIcon]; return; } /* Get it in a raw bitmap form */ - tiff = [icon TIFFRepresentationUsingCompression: + tiff = [fApplicationIcon TIFFRepresentationUsingCompression: NSTIFFCompressionNone factor: 1.0]; bmp = [NSBitmapImageRep imageRepWithData: tiff]; @@ -487,7 +624,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It /* Now update the dock icon */ tiff = [bmp TIFFRepresentationUsingCompression: NSTIFFCompressionNone factor: 1.0]; - icon = [[NSImage alloc] initWithData: tiff]; + NSImage* icon = [[NSImage alloc] initWithData: tiff]; [NSApp setApplicationIconImage: icon]; [icon release]; } @@ -526,7 +663,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It NSLocalizedString( @"Scanning title %d of %d...", @"" ), p.title_cur, p.title_count]]; [fScanIndicator setHidden: NO]; - [fScanIndicator setDoubleValue: 100.0 * ( p.title_cur - 1 ) / p.title_count]; + [fScanIndicator setDoubleValue: 100.0 * ((double)( p.title_cur - 1 ) / p.title_count)]; break; } #undef p @@ -582,7 +719,6 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It if( checkScanCount > currentScanCount ) { currentScanCount = checkScanCount; - [self writeToActivityLog:"currentScanCount received from fQueueEncodeLibhb"]; } //hb_state_t s; @@ -598,8 +734,11 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It [fStatusField setStringValue: [NSString stringWithFormat: NSLocalizedString( @"Queue Scanning title %d of %d...", @"" ), p.title_cur, p.title_count]]; - [fRipIndicator setHidden: NO]; - [fRipIndicator setDoubleValue: 100.0 * ( p.title_cur - 1 ) / p.title_count]; + + /* Set the status string in fQueueController as well */ + [fQueueController setQueueStatusString: [NSString stringWithFormat: + NSLocalizedString( @"Queue Scanning title %d of %d...", @"" ), + p.title_cur, p.title_count]]; break; } #undef p @@ -607,9 +746,6 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It #define p s.param.scandone case HB_STATE_SCANDONE: { - [fRipIndicator setIndeterminate: NO]; - [fRipIndicator setDoubleValue: 0.0]; - [self writeToActivityLog:"ScanDone state received from fQueueEncodeLibhb"]; [self processNewQueueEncode]; [[fWindow toolbar] validateVisibleItems]; @@ -621,10 +757,26 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It #define p s.param.working case HB_STATE_WORKING: { - float progress_total; NSMutableString * string; + NSString * pass_desc; /* Update text field */ - string = [NSMutableString stringWithFormat: NSLocalizedString( @"Encoding: pass %d of %d, %.2f %%", @"" ), p.job_cur, p.job_count, 100.0 * p.progress]; + if (p.job_cur == 1 && p.job_count > 1) + { + if ([[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SubtitleList"] && [[[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex]objectForKey:@"SubtitleList"] objectAtIndex:0] objectForKey:@"subtitleSourceTrackNum"] intValue] == 1) + { + pass_desc = @"(subtitle scan)"; + } + else + { + pass_desc = @""; + } + } + else + { + pass_desc = @""; + } + + string = [NSMutableString stringWithFormat: NSLocalizedString( @"Encoding: pass %d %@ of %d, %.2f %%", @"" ), p.job_cur, pass_desc, p.job_count, 100.0 * p.progress]; if( p.seconds > -1 ) { @@ -634,11 +786,12 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It } [fStatusField setStringValue: string]; - + /* Set the status string in fQueueController as well */ + [fQueueController setQueueStatusString: string]; /* Update slider */ - progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count; + CGFloat progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count; [fRipIndicator setIndeterminate: NO]; - [fRipIndicator setDoubleValue: 100.0 * progress_total]; + [fRipIndicator setDoubleValue:100.0 * progress_total]; // If progress bar hasn't been revealed at the bottom of the window, do // that now. This code used to be in doRip. I moved it to here to handle @@ -653,14 +806,16 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It frame.origin.y -= 36; [fWindow setFrame:frame display:YES animate:YES]; fRipIndicatorShown = YES; - /* We check to see if we need to warn the user that the computer will go to sleep - or shut down when encoding is finished */ - [self remindUserOfSleepOrShutdown]; + } - + /* Update dock icon */ - [self UpdateDockIcon: progress_total]; - + if( dockIconProgress < 100.0 * progress_total ) + { + [self UpdateDockIcon: progress_total]; + dockIconProgress += 5; + } + break; } #undef p @@ -670,7 +825,8 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It { /* Update text field */ [fStatusField setStringValue: NSLocalizedString( @"Muxing...", @"" )]; - + /* Set the status string in fQueueController as well */ + [fQueueController setQueueStatusString: NSLocalizedString( @"Muxing...", @"" )]; /* Update slider */ [fRipIndicator setIndeterminate: YES]; [fRipIndicator startAnimation: nil]; @@ -684,6 +840,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It case HB_STATE_PAUSED: [fStatusField setStringValue: NSLocalizedString( @"Paused", @"" )]; + [fQueueController setQueueStatusString: NSLocalizedString( @"Paused", @"" )]; break; @@ -694,13 +851,17 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It // out the remaining passes/jobs in the queue. We'll do that here. // Delete all remaining jobs of this encode. - [fStatusField setStringValue: NSLocalizedString( @"Done.", @"" )]; + [fStatusField setStringValue: NSLocalizedString( @"Encode Finished.", @"" )]; + /* Set the status string in fQueueController as well */ + [fQueueController setQueueStatusString: NSLocalizedString( @"Encode Finished.", @"" )]; [fRipIndicator setIndeterminate: NO]; + [fRipIndicator stopAnimation: nil]; [fRipIndicator setDoubleValue: 0.0]; [[fWindow toolbar] validateVisibleItems]; /* Restore dock icon */ [self UpdateDockIcon: -1.0]; + dockIconProgress = 0; if( fRipIndicatorShown ) { @@ -712,44 +873,66 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It [fWindow setFrame:frame display:YES animate:YES]; fRipIndicatorShown = NO; } - - /* Check to see if the encode state has not been cancelled + /* Since we are done with this encode, tell output to stop writing to the + * individual encode log + */ + [outputPanel endEncodeLog]; + /* Check to see if the encode state has not been cancelled to determine if we should check for encode done notifications */ if( fEncodeState != 2 ) { + NSString *pathOfFinishedEncode; + /* Get the output file name for the finished encode */ + 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]; - /* 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; - NSBeep(); - status = NSRunAlertPanel(@"Put down that cocktail...",@"Your HandBrake encode 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"] ) + [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) { - /* Shut Down */ - NSDictionary* errorDict; - NSAppleEventDescriptor* returnDescriptor = nil; - NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource: - @"tell application \"Finder\" to shut down"]; - returnDescriptor = [scriptObject executeAndReturnError: &errorDict]; - [scriptObject release]; + /* 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; + 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]; + } + } @@ -762,7 +945,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It } /* We use this to write messages to stderr from the macgui which show up in the activity window and log*/ -- (void) writeToActivityLog:(char *) format, ... +- (void) writeToActivityLog:(const char *) format, ... { va_list args; va_start(args, format); @@ -847,7 +1030,27 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It [item setTarget: self]; [item setAction: @selector(Pause:)]; } - else if ([itemIdent isEqualToString: ShowActivityIdentifier]) { + else if ([itemIdent isEqualToString: ShowPictureIdentifier]) + { + [item setLabel: @"Picture Settings"]; + [item setPaletteLabel: @"Show Picture Settings"]; + [item setToolTip: @"Show Picture Settings"]; + [item setImage: [NSImage imageNamed: @"pref-picture"]]; + [item setTarget: self]; + [item setAction: @selector(showPicturePanel:)]; + } + else if ([itemIdent isEqualToString: ShowPreviewIdentifier]) + { + [item setLabel: @"Preview Window"]; + [item setPaletteLabel: @"Show Preview"]; + [item setToolTip: @"Show Preview"]; + //[item setImage: [NSImage imageNamed: @"pref-picture"]]; + [item setImage: [NSImage imageNamed: @"Brushed_Window"]]; + [item setTarget: self]; + [item setAction: @selector(showPreviewWindow:)]; + } + else if ([itemIdent isEqualToString: ShowActivityIdentifier]) + { [item setLabel: @"Activity Window"]; [item setPaletteLabel: @"Show Activity Window"]; [item setToolTip: @"Show Activity Window"]; @@ -877,13 +1080,13 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It { return [NSArray arrayWithObjects: ChooseSourceIdentifier, NSToolbarSeparatorItemIdentifier, StartEncodingIdentifier, PauseEncodingIdentifier, AddToQueueIdentifier, ShowQueueIdentifier, NSToolbarFlexibleSpaceItemIdentifier, - NSToolbarSpaceItemIdentifier, ShowActivityIdentifier, ToggleDrawerIdentifier, nil]; + NSToolbarSpaceItemIdentifier, ShowPictureIdentifier, ShowPreviewIdentifier, ShowActivityIdentifier, ToggleDrawerIdentifier, nil]; } - (NSArray *) toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar { return [NSArray arrayWithObjects: StartEncodingIdentifier, PauseEncodingIdentifier, AddToQueueIdentifier, - ChooseSourceIdentifier, ShowQueueIdentifier, ShowActivityIdentifier, ToggleDrawerIdentifier, + ChooseSourceIdentifier, ShowQueueIdentifier, ShowPictureIdentifier, ShowPreviewIdentifier, ShowActivityIdentifier, ToggleDrawerIdentifier, NSToolbarCustomizeToolbarItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier, NSToolbarSpaceItemIdentifier, NSToolbarSeparatorItemIdentifier, nil]; } @@ -916,8 +1119,14 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It return YES; } if (SuccessfulScan) + { if ([ident isEqualToString: AddToQueueIdentifier]) return YES; + if ([ident isEqualToString: ShowPictureIdentifier]) + return YES; + if ([ident isEqualToString: ShowPreviewIdentifier]) + return YES; + } } else if (s.state == HB_STATE_PAUSED) { @@ -933,6 +1142,10 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It return YES; if ([ident isEqualToString: AddToQueueIdentifier]) return YES; + if ([ident isEqualToString: ShowPictureIdentifier]) + return YES; + if ([ident isEqualToString: ShowPreviewIdentifier]) + return YES; } else if (s.state == HB_STATE_SCANNING) return NO; @@ -951,6 +1164,10 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It } if ([ident isEqualToString: AddToQueueIdentifier]) return YES; + if ([ident isEqualToString: ShowPictureIdentifier]) + return YES; + if ([ident isEqualToString: ShowPreviewIdentifier]) + return YES; } } @@ -1050,7 +1267,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It -(void)showGrowlDoneNotification:(NSString *) filePath { - /* This is called from HBQueueController as jobs roll off of the queue in currentJobChanged */ + /* This end of encode action is called as each encode rolls off of the queue */ NSString * finishedEncode = filePath; /* strip off the path to just show the file name */ finishedEncode = [finishedEncode lastPathComponent]; @@ -1071,7 +1288,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It } -(void)sendToMetaX:(NSString *) filePath { - /* This is called from HBQueueController as jobs roll off of the queue in currentJobChanged */ + /* This end of encode action is called as each encode rolls off of the queue */ if([[NSUserDefaults standardUserDefaults] boolForKey: @"sendToMetaX"] == YES) { NSAppleScript *myScript = [[NSAppleScript alloc] initWithSource: [NSString stringWithFormat: @"%@%@%@", @"tell application \"MetaX\" to open (POSIX file \"", filePath, @"\")"]]; @@ -1236,6 +1453,15 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It } } +- (IBAction)showAboutPanel:(id)sender +{ + NSMutableDictionary* d = [[NSMutableDictionary alloc] initWithObjectsAndKeys: + fApplicationIcon, @"ApplicationIcon", + nil ]; + [NSApp orderFrontStandardAboutPanelWithOptions:d]; + [d release]; +} + /* Here we open the title selection sheet where we can specify an exact title to be scanned */ - (IBAction) showSourceTitleScanPanel: (id) sender { @@ -1276,22 +1502,49 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It BOOL cancelScanDecrypt = 0; NSString *path = scanPath; HBDVDDetector *detector = [HBDVDDetector detectorForPath:path]; - + // Notify ChapterTitles that there's no title [fChapterTitlesDelegate resetWithTitle:nil]; [fChapterTable reloadData]; - + + // Notify Subtitles that there's no title + [fSubtitlesDelegate resetWithTitle:nil]; + [fSubtitlesTable reloadData]; + [self enableUI: NO]; - + if( [detector isVideoDVD] ) { // 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]]; + +#if defined( __LP64__ ) + /* If we are 64 bit, we cannot read encrypted dvd's as vlc is 32 bit only */ + cancelScanDecrypt = 1; + [self writeToActivityLog: "64 bit mode cannot read dvd's, scan cancelled"]; + /*On Screen Notification*/ + int status; + NSBeep(); + status = NSRunAlertPanel(@"64-bit HandBrake cannot read encrypted dvds!",@"", @"Cancel Scan", @"Attempt Scan Anyway", nil); + [NSApp requestUserAttention:NSCriticalRequest]; + + if (status == NSAlertDefaultReturn) + { + /* User chose to cancel the scan */ + [self writeToActivityLog: "cannot open physical dvd , scan cancelled"]; + cancelScanDecrypt = 1; + } + else + { + [self writeToActivityLog: "user overrode 64-bit warning trying to open physical dvd without decryption"]; + cancelScanDecrypt = 0; + } +#else /* lets check for vlc here to make sure we have a dylib available to use for decrypting */ - NSString *vlcPath = @"/Applications/VLC.app"; + NSString *vlcPath = @"/Applications/VLC.app/Contents/MacOS/lib/libdvdcss.2.dylib"; NSFileManager * fileManager = [NSFileManager defaultManager]; if ([fileManager fileExistsAtPath:vlcPath] == 0) { @@ -1299,7 +1552,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It cancelScanDecrypt = 1; [self writeToActivityLog: "VLC app not found for decrypting physical dvd"]; int status; - status = NSRunAlertPanel(@"HandBrake could not find VLC.",@"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 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"); [NSApp requestUserAttention:NSCriticalRequest]; if (status == NSAlertDefaultReturn) @@ -1309,24 +1562,25 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It } else if (status == NSAlertAlternateReturn) { - /* User chose to cancel the scan */ - [self writeToActivityLog: "cannot open physical dvd , scan cancelled"]; + /* User chose to cancel the scan */ + [self writeToActivityLog: "cannot open physical dvd , scan cancelled"]; } else { - /* User chose to override our warning and scan the physical dvd anyway, at their own peril. on an encrypted dvd this produces massive log files and fails */ - cancelScanDecrypt = 0; - [self writeToActivityLog: "user overrode vlc warning -trying to open physical dvd without decryption"]; + /* User chose to override our warning and scan the physical dvd anyway, at their own peril. on an encrypted dvd this produces massive log files and fails */ + cancelScanDecrypt = 0; + [self writeToActivityLog: "user overrode vlc warning -trying to open physical dvd without decryption"]; } - + } else { /* 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"]; } +#endif } - + if (cancelScanDecrypt == 0) { /* we actually pass the scan off to libhb here */ @@ -1341,8 +1595,11 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It { [self writeToActivityLog: "scanning specifically for title: %d", scanTitleNum]; } - - hb_scan( fHandle, [path UTF8String], scanTitleNum ); + /* We use our advance pref to determine how many previews to scan */ + int hb_num_previews = [[[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewsNumber"] intValue]; + /* set title to NULL */ + //fTitle = NULL; + hb_scan( fHandle, [path UTF8String], scanTitleNum, hb_num_previews, 1 ); [fSrcDVD2Field setStringValue:@"Scanning new source ..."]; } } @@ -1364,6 +1621,10 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It SuccessfulScan = NO; // Notify ChapterTitles that there's no title + [fSubtitlesDelegate resetWithTitle:nil]; + [fSubtitlesTable reloadData]; + + // Notify Subtitles that there's no title [fChapterTitlesDelegate resetWithTitle:nil]; [fChapterTable reloadData]; } @@ -1421,18 +1682,20 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It SuccessfulScan = YES; [self enableUI: YES]; - /* if its the initial successful scan after awakeFromNib */ - if (currentSuccessfulScanCount == 1) - { - [self selectDefaultPreset:nil]; - /* initially set deinterlace to 0, will be overridden reset by the default preset anyway */ - //[fPictureController setDeinterlace:0]; - - /* lets set Denoise to index 0 or "None" since this is the first scan */ - //[fPictureController setDenoise:0]; - - [fPictureController setInitialPictureFilters]; - } + /* if its the initial successful scan after awakeFromNib */ + if (currentSuccessfulScanCount == 1) + { + [self selectDefaultPreset:nil]; + + // Open preview window now if it was visible when HB was closed + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"PreviewWindowIsOpen"]) + [self showPreviewWindow:nil]; + + // Open picture sizing window now if it was visible when HB was closed + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"PictureSizeWindowIsOpen"]) + [self showPicturePanel:nil]; + + } } @@ -1455,11 +1718,14 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It } - (void) browseFileDone: (NSSavePanel *) sheet - returnCode: (int) returnCode contextInfo: (void *) contextInfo + returnCode: (int) returnCode contextInfo: (void *) contextInfo { if( returnCode == NSOKButton ) { [fDstFile2Field setStringValue: [sheet filename]]; + /* Save this path to the prefs so that on next browse destination window it opens there */ + NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent]; + [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"]; } } @@ -1488,6 +1754,10 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It return NO; } +- (NSSize) drawerWillResizeContents:(NSDrawer *) drawer toSize:(NSSize) contentSize { + [[NSUserDefaults standardUserDefaults] setObject:NSStringFromSize( contentSize ) forKey:@"Drawer Size"]; + return contentSize; +} #pragma mark - #pragma mark Queue File @@ -1536,14 +1806,14 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It - (void) removeQueueFileItem:(int) queueItemToRemove { - // NSMutableDictionary * queueToApply = [QueueFileArray objectAtIndex:currentQueueEncodeIndex]; - if ([[[QueueFileArray objectAtIndex:queueItemToRemove] objectForKey:@"Status"] intValue] == 3) //<-- Find out if the item we are removing is a cancelled item + /* 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 item, WE need to decrement the currentQueueEncodeIndex + /* 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 encode, decrement currentQueueEncodeIndex to %d", currentQueueEncodeIndex]; + [self writeToActivityLog: "removeQueueFileItem: Removing a cancelled/finished encode, decrement currentQueueEncodeIndex to %d", currentQueueEncodeIndex]; } [QueueFileArray removeObjectAtIndex:queueItemToRemove]; [self saveQueueFileItem]; @@ -1614,10 +1884,10 @@ fWorkingCount = 0; [fQueueStatus setStringValue:string]; } - -/* This method will clear the queue of any encodes that are not still pending - * this includes both successfully completed encodes as well as cancelled encodes */ -- (void) clearQueueEncodedItems +/* This method will set any item marked as encoding back to pending + * currently used right after a queue reload + */ +- (void) setQueueEncodingItemsAsPending { NSEnumerator *enumerator = [QueueFileArray objectEnumerator]; id tempObject; @@ -1626,22 +1896,25 @@ 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 not still pending (finished successfully or it was cancelled - * during the last session, then we put it in tempArray to be deleted from QueueFileArray*/ - if ([[tempObject objectForKey:@"Status"] intValue] != 2) + /* 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) { - [tempArray addObject:tempObject]; + [tempObject setObject:[NSNumber numberWithInt: 2] forKey:@"Status"]; } + [tempArray addObject:tempObject]; } - [QueueFileArray removeObjectsInArray:tempArray]; + [QueueFileArray setArray:tempArray]; [self saveQueueFileItem]; - } + /* This method will clear the queue of any encodes that are not still pending * this includes both successfully completed encodes as well as cancelled encodes */ -- (void) clearQueueAllItems +- (void) clearQueueEncodedItems { NSEnumerator *enumerator = [QueueFileArray objectEnumerator]; id tempObject; @@ -1650,12 +1923,38 @@ fWorkingCount = 0; /* we look here to see if the preset is we move on to the next one */ while ( tempObject = [enumerator nextObject] ) { - [tempArray addObject:tempObject]; - } - + /* If the queue item is either completed (0) or cancelled (3) from the + * last session, then we put it in tempArray to be deleted from QueueFileArray. + * NOTE: this means we retain pending (2) and also an item that is marked as + * still encoding (1). If the queue has an item that is still marked as encoding + * from a previous session, we can conlude that HB was either shutdown, or crashed + * during the encodes so we keep it and tell the user in the "Load Queue Alert" + */ + if ([[tempObject objectForKey:@"Status"] intValue] == 0 || [[tempObject objectForKey:@"Status"] intValue] == 3) + { + [tempArray addObject:tempObject]; + } + } + [QueueFileArray removeObjectsInArray:tempArray]; [self saveQueueFileItem]; +} + +/* This method will clear the queue of all encodes. effectively creating an empty queue */ +- (void) clearQueueAllItems +{ + NSEnumerator *enumerator = [QueueFileArray objectEnumerator]; + id tempObject; + NSMutableArray *tempArray; + tempArray = [NSMutableArray array]; + /* we look here to see if the preset is we move on to the next one */ + while ( tempObject = [enumerator nextObject] ) + { + [tempArray addObject:tempObject]; + } + [QueueFileArray removeObjectsInArray:tempArray]; + [self saveQueueFileItem]; } /* This method will duplicate prepareJob however into the @@ -1669,10 +1968,8 @@ fWorkingCount = 0; hb_title_t * title = (hb_title_t *) hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] ); hb_job_t * job = title->job; - //hb_audio_config_t * audio; - // For picture filters - //hb_job_t * job = fTitle->job; + /* We use a number system to set the encode status of the queue item * 0 == already encoded @@ -1686,6 +1983,7 @@ fWorkingCount = 0; [queueFileJob setObject:[NSString stringWithUTF8String: title->dvd] forKey:@"SourcePath"]; [queueFileJob setObject:[fSrcDVD2Field stringValue] forKey:@"SourceName"]; [queueFileJob setObject:[NSNumber numberWithInt:title->index] forKey:@"TitleNumber"]; + [queueFileJob setObject:[NSNumber numberWithInt:[fSrcAnglePopUp indexOfSelectedItem] + 1] forKey:@"TitleAngle"]; [queueFileJob setObject:[NSNumber numberWithInt:[fSrcChapterStartPopUp indexOfSelectedItem] + 1] forKey:@"ChapterStart"]; [queueFileJob setObject:[NSNumber numberWithInt:[fSrcChapterEndPopUp indexOfSelectedItem] + 1] forKey:@"ChapterEnd"]; @@ -1697,9 +1995,36 @@ fWorkingCount = 0; [queueFileJob setObject:[NSNumber numberWithInt:[fPresetsOutlineView selectedRow]] forKey:@"PresetIndexNum"]; [queueFileJob setObject:[fDstFormatPopUp titleOfSelectedItem] forKey:@"FileFormat"]; - /* Chapter Markers fCreateChapterMarkers*/ - [queueFileJob setObject:[NSNumber numberWithInt:[fCreateChapterMarkers state]] forKey:@"ChapterMarkers"]; - /* Allow Mpeg4 64 bit formatting +4GB file sizes */ + /* Chapter Markers*/ + /* If we have only one chapter or a title without chapters, set chapter markers to off */ + if ([fSrcChapterStartPopUp indexOfSelectedItem] == [fSrcChapterEndPopUp indexOfSelectedItem]) + { + [queueFileJob setObject:[NSNumber numberWithInt:0] forKey:@"ChapterMarkers"]; + } + else + { + [queueFileJob setObject:[NSNumber numberWithInt:[fCreateChapterMarkers state]] forKey:@"ChapterMarkers"]; + } + + /* We need to get the list of chapter names to put into an array and store + * in our queue, so they can be reapplied in prepareJob when this queue + * item comes up if Chapter Markers is set to on. + */ + int i; + NSMutableArray *ChapterNamesArray = [[NSMutableArray alloc] init]; + int chaptercount = hb_list_count( fTitle->list_chapter ); + for( i = 0; i < chaptercount; i++ ) + { + hb_chapter_t *chapter = (hb_chapter_t *) hb_list_item( fTitle->list_chapter, i ); + if( chapter != NULL ) + { + [ChapterNamesArray addObject:[NSString stringWithCString:chapter->title encoding:NSUTF8StringEncoding]]; + } + } + [queueFileJob setObject:[NSMutableArray arrayWithArray: ChapterNamesArray] forKey:@"ChapterNames"]; + [ChapterNamesArray autorelease]; + + /* Allow Mpeg4 64 bit formatting +4GB file sizes */ [queueFileJob setObject:[NSNumber numberWithInt:[fDstMp4LargeFileCheck state]] forKey:@"Mp4LargeFile"]; /* Mux mp4 with http optimization */ [queueFileJob setObject:[NSNumber numberWithInt:[fDstMp4HttpOptFileCheck state]] forKey:@"Mp4HttpOptimize"]; @@ -1715,12 +2040,10 @@ fWorkingCount = 0; [queueFileJob setObject:[NSNumber numberWithInt:[fVidQualityMatrix selectedRow]] forKey:@"VideoQualityType"]; [queueFileJob setObject:[fVidTargetSizeField stringValue] forKey:@"VideoTargetSize"]; [queueFileJob setObject:[fVidBitrateField stringValue] forKey:@"VideoAvgBitrate"]; - [queueFileJob setObject:[NSNumber numberWithFloat:[fVidQualitySlider floatValue]] forKey:@"VideoQualitySlider"]; + [queueFileJob setObject:[NSNumber numberWithFloat:[fVidQualityRFField floatValue]] forKey:@"VideoQualitySlider"]; /* Framerate */ [queueFileJob setObject:[fVidRatePopUp titleOfSelectedItem] forKey:@"VideoFramerate"]; - /* GrayScale */ - [queueFileJob setObject:[NSNumber numberWithInt:[fVidGrayscaleCheck state]] forKey:@"VideoGrayScale"]; /* 2 Pass Encoding */ [queueFileJob setObject:[NSNumber numberWithInt:[fVidTwoPassCheck state]] forKey:@"VideoTwoPass"]; /* Turbo 2 pass Encoding fVidTurboPassCheck*/ @@ -1732,12 +2055,22 @@ fWorkingCount = 0; [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->width] forKey:@"PictureWidth"]; [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->height] forKey:@"PictureHeight"]; [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->keep_ratio] forKey:@"PictureKeepRatio"]; - [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->pixel_ratio] forKey:@"PicturePAR"]; + [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->anamorphic.mode] forKey:@"PicturePAR"]; + /* if we are custom anamorphic, store the exact storage, par and display dims */ + if (fTitle->job->anamorphic.mode == 3) + { + [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->width] forKey:@"PicturePARStorageWidth"]; + [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->height] forKey:@"PicturePARStorageHeight"]; + + [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->anamorphic.par_width] forKey:@"PicturePARPixelWidth"]; + [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->anamorphic.par_height] forKey:@"PicturePARPixelHeight"]; + + [queueFileJob setObject:[NSNumber numberWithFloat:fTitle->job->anamorphic.dar_width] forKey:@"PicturePARDisplayWidth"]; + [queueFileJob setObject:[NSNumber numberWithFloat:fTitle->job->anamorphic.dar_height] forKey:@"PicturePARDisplayHeight"]; + + } NSString * pictureSummary; - pictureSummary = [NSString stringWithFormat:@"Source: %@ Output: %@ Anamorphic: %@", - [fPicSettingsSrc stringValue], - [fPicSettingsOutp stringValue], - [fPicSettingsAnamorphic stringValue]]; + pictureSummary = [fPictureSizeField stringValue]; [queueFileJob setObject:pictureSummary forKey:@"PictureSizingSummary"]; /* Set crop settings here */ [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController autoCrop]] forKey:@"PictureAutoCrop"]; @@ -1747,12 +2080,22 @@ fWorkingCount = 0; [queueFileJob setObject:[NSNumber numberWithInt:job->crop[3]] forKey:@"PictureRightCrop"]; /* Picture Filters */ - [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController deinterlace]] forKey:@"PictureDeinterlace"]; - [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController detelecine]] forKey:@"PictureDetelecine"]; - [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController vfr]] forKey:@"VFR"]; - [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController denoise]] forKey:@"PictureDenoise"]; - [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController deblock]] forKey:@"PictureDeblock"]; + [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController detelecine]] forKey:@"PictureDetelecine"]; + [queueFileJob setObject:[fPictureController detelecineCustomString] forKey:@"PictureDetelecineCustom"]; + + [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController useDecomb]] forKey:@"PictureDecombDeinterlace"]; [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController decomb]] forKey:@"PictureDecomb"]; + [queueFileJob setObject:[fPictureController decombCustomString] forKey:@"PictureDecombCustom"]; + + [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController deinterlace]] forKey:@"PictureDeinterlace"]; + [queueFileJob setObject:[fPictureController deinterlaceCustomString] forKey:@"PictureDeinterlaceCustom"]; + + [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController denoise]] forKey:@"PictureDenoise"]; + [queueFileJob setObject:[fPictureController denoiseCustomString] forKey:@"PictureDenoiseCustom"]; + + [queueFileJob setObject:[NSString stringWithFormat:@"%d",[fPictureController deblock]] forKey:@"PictureDeblock"]; + + [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController grayscale]] forKey:@"VideoGrayScale"]; /*Audio*/ if ([fAudLang1PopUp indexOfSelectedItem] > 0) @@ -1797,13 +2140,10 @@ fWorkingCount = 0; } /* Subtitles*/ - [queueFileJob setObject:[fSubPopUp titleOfSelectedItem] forKey:@"Subtitles"]; - [queueFileJob setObject:[NSNumber numberWithInt:[fSubPopUp indexOfSelectedItem]] forKey:@"JobSubtitlesIndex"]; - /* Forced Subtitles */ - [queueFileJob setObject:[NSNumber numberWithInt:[fSubForcedCheck state]] forKey:@"SubtitlesForced"]; - - - + NSMutableArray *subtitlesArray = [[NSMutableArray alloc] init]; + [queueFileJob setObject:[NSArray arrayWithArray: [fSubtitlesDelegate getSubtitleArray: subtitlesArray]] forKey:@"SubtitleList"]; + [subtitlesArray autorelease]; + /* Now we go ahead and set the "job->values in the plist for passing right to fQueueEncodeLibhb */ [queueFileJob setObject:[NSNumber numberWithInt:[fSrcChapterStartPopUp indexOfSelectedItem] + 1] forKey:@"JobChapterStart"]; @@ -1812,36 +2152,23 @@ fWorkingCount = 0; [queueFileJob setObject:[NSNumber numberWithInt:[[fDstFormatPopUp selectedItem] tag]] forKey:@"JobFileFormatMux"]; - /* Chapter Markers fCreateChapterMarkers*/ - //[queueFileJob setObject:[NSNumber numberWithInt:[fCreateChapterMarkers state]] forKey:@"ChapterMarkers"]; - /* Allow Mpeg4 64 bit formatting +4GB file sizes */ - //[queueFileJob setObject:[NSNumber numberWithInt:[fDstMp4LargeFileCheck state]] forKey:@"Mp4LargeFile"]; - /* Mux mp4 with http optimization */ - //[queueFileJob setObject:[NSNumber numberWithInt:[fDstMp4HttpOptFileCheck state]] forKey:@"Mp4HttpOptimize"]; - /* Add iPod uuid atom */ - //[queueFileJob setObject:[NSNumber numberWithInt:[fDstMp4iPodFileCheck state]] forKey:@"Mp4iPodCompatible"]; /* Codecs */ /* Video encoder */ [queueFileJob setObject:[NSNumber numberWithInt:[[fVidEncoderPopUp selectedItem] tag]] forKey:@"JobVideoEncoderVcodec"]; - /* x264 Option String */ - //[queueFileJob setObject:[fAdvancedOptions optionsString] forKey:@"x264Option"]; - - //[queueFileJob setObject:[NSNumber numberWithInt:[fVidQualityMatrix selectedRow]] forKey:@"VideoQualityType"]; - //[queueFileJob setObject:[fVidTargetSizeField stringValue] forKey:@"VideoTargetSize"]; - //[queueFileJob setObject:[fVidBitrateField stringValue] forKey:@"VideoAvgBitrate"]; - //[queueFileJob setObject:[NSNumber numberWithFloat:[fVidQualitySlider floatValue]] forKey:@"VideoQualitySlider"]; + /* Framerate */ [queueFileJob setObject:[NSNumber numberWithInt:[fVidRatePopUp indexOfSelectedItem]] forKey:@"JobIndexVideoFramerate"]; [queueFileJob setObject:[NSNumber numberWithInt:title->rate] forKey:@"JobVrate"]; [queueFileJob setObject:[NSNumber numberWithInt:title->rate_base] forKey:@"JobVrateBase"]; - /* Picture Sizing */ + + /* Picture Sizing */ /* Use Max Picture settings for whatever the dvd is.*/ [queueFileJob setObject:[NSNumber numberWithInt:0] forKey:@"UsesMaxPictureSettings"]; [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->width] forKey:@"PictureWidth"]; [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->height] forKey:@"PictureHeight"]; [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->keep_ratio] forKey:@"PictureKeepRatio"]; - [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->pixel_ratio] forKey:@"PicturePAR"]; + [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->anamorphic.mode] forKey:@"PicturePAR"]; /* Set crop settings here */ [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController autoCrop]] forKey:@"PictureAutoCrop"]; @@ -1850,8 +2177,6 @@ fWorkingCount = 0; [queueFileJob setObject:[NSNumber numberWithInt:job->crop[2]] forKey:@"PictureLeftCrop"]; [queueFileJob setObject:[NSNumber numberWithInt:job->crop[3]] forKey:@"PictureRightCrop"]; - /* Picture Filters */ - [queueFileJob setObject:[fPicSettingDecomb stringValue] forKey:@"JobPictureDecomb"]; /*Audio*/ if ([fAudLang1PopUp indexOfSelectedItem] > 0) @@ -1886,10 +2211,7 @@ fWorkingCount = 0; [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack4RatePopUp selectedItem] tag]] forKey:@"JobAudio4Samplerate"]; [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack4BitratePopUp selectedItem] tag]] forKey:@"JobAudio4Bitrate"]; } - /* Subtitles*/ - [queueFileJob setObject:[fSubPopUp titleOfSelectedItem] forKey:@"Subtitles"]; - /* Forced Subtitles */ - [queueFileJob setObject:[NSNumber numberWithInt:[fSubForcedCheck state]] forKey:@"SubtitlesForced"]; + /* we need to auto relase the queueFileJob and return it */ [queueFileJob autorelease]; @@ -1898,33 +2220,32 @@ fWorkingCount = 0; } /* this is actually called from the queue controller to modify the queue array and return it back to the queue controller */ -- (void)moveObjectsInQueueArray:(NSMutableArray *)array fromIndexes:(NSIndexSet *)indexSet toIndex:(unsigned)insertIndex +- (void)moveObjectsInQueueArray:(NSMutableArray *)array fromIndexes:(NSIndexSet *)indexSet toIndex:(NSUInteger)insertIndex { - unsigned index = [indexSet lastIndex]; - unsigned aboveInsertIndexCount = 0; + NSUInteger index = [indexSet lastIndex]; + NSUInteger aboveInsertIndexCount = 0; - while (index != NSNotFound) - { - unsigned removeIndex; - - if (index >= insertIndex) - { - removeIndex = index + aboveInsertIndexCount; - aboveInsertIndexCount++; - } - else - { - removeIndex = index; - insertIndex--; - } - - id object = [[QueueFileArray objectAtIndex:removeIndex] retain]; - [QueueFileArray removeObjectAtIndex:removeIndex]; - [QueueFileArray insertObject:object atIndex:insertIndex]; - [object release]; + + NSUInteger removeIndex; - index = [indexSet indexLessThanIndex:index]; + if (index >= insertIndex) + { + removeIndex = index + aboveInsertIndexCount; + aboveInsertIndexCount++; + } + else + { + removeIndex = index; + insertIndex--; } + + id object = [[QueueFileArray objectAtIndex:removeIndex] retain]; + [QueueFileArray removeObjectAtIndex:removeIndex]; + [QueueFileArray insertObject:object atIndex:insertIndex]; + [object release]; + + index = [indexSet indexLessThanIndex:index]; + /* We save all of the Queue data here * and it also gets sent back to the queue controller*/ [self saveQueueFileItem]; @@ -1967,8 +2288,10 @@ fWorkingCount = 0; /* 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 { - //NSRunAlertPanel(@"Hello!", @"We are now performing a new queue scan!", @"OK", nil, nil); - + /* Tell HB to output a new activity log file for this encode */ + [outputPanel startEncodeLog:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"DestinationPath"]]; + + /* 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 @@ -1983,12 +2306,6 @@ fWorkingCount = 0; //status = NSRunAlertPanel(@"HandBrake is now loading up a new queue item...",@"Would You Like to wait until you add another encode?", @"Cancel", @"Okay", nil); //[NSApp requestUserAttention:NSCriticalRequest]; - // Notify ChapterTitles that there's no title - [fChapterTitlesDelegate resetWithTitle:nil]; - [fChapterTable reloadData]; - - //[self enableUI: NO]; - if( [detector isVideoDVD] ) { // The chosen path was actually on a DVD, so use the raw block @@ -2047,8 +2364,11 @@ fWorkingCount = 0; { [self writeToActivityLog: "scanning specifically for title: %d", scanTitleNum]; } + [self writeToActivityLog: "performNewQueueScan currentQueueEncodeIndex is: %d", currentQueueEncodeIndex]; - hb_scan( fQueueEncodeLibhb, [path UTF8String], scanTitleNum ); + /* 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 ); } } @@ -2115,9 +2435,6 @@ fWorkingCount = 0; [fVidRatePopUp selectItemWithTitle:[queueToApply objectForKey:@"VideoFramerate"]]; } - /* GrayScale */ - [fVidGrayscaleCheck setState:[[queueToApply objectForKey:@"VideoGrayScale"] intValue]]; - /* 2 Pass Encoding */ [fVidTwoPassCheck setState:[[queueToApply objectForKey:@"VideoTwoPass"] intValue]]; [self twoPassCheckboxChanged:nil]; @@ -2256,7 +2573,7 @@ fWorkingCount = 0; hb_fix_aspect( job, HB_KEEP_HEIGHT ); } } - job->pixel_ratio = [[queueToApply objectForKey:@"PicturePAR"] intValue]; + job->anamorphic.mode = [[queueToApply objectForKey:@"PicturePAR"] intValue]; /* If Cropping is set to custom, then recall all four crop values from @@ -2286,8 +2603,7 @@ fWorkingCount = 0; /* Filters */ /* Deinterlace */ [fPictureController setDeinterlace:[[queueToApply objectForKey:@"PictureDeinterlace"] intValue]]; - /* VFR */ - [fPictureController setVFR:[[queueToApply objectForKey:@"VFR"] intValue]]; + /* Detelecine */ [fPictureController setDetelecine:[[queueToApply objectForKey:@"PictureDetelecine"] intValue]]; /* Denoise */ @@ -2296,6 +2612,8 @@ fWorkingCount = 0; [fPictureController setDeblock:[[queueToApply objectForKey:@"PictureDeblock"] intValue]]; /* Decomb */ [fPictureController setDecomb:[[queueToApply objectForKey:@"PictureDecomb"] intValue]]; + /* Grayscale */ + [fPictureController setGrayscale:[[queueToApply objectForKey:@"VideoGrayScale"] intValue]]; [self calculatePictureSizing:nil]; @@ -2345,27 +2663,18 @@ fWorkingCount = 0; { [self writeToActivityLog: "processNewQueueEncode WARNING nothing found in the title list"]; } - else - { - [self writeToActivityLog: "processNewQueueEncode title list is: %d", hb_list_count( list )]; - } NSMutableDictionary * queueToApply = [QueueFileArray objectAtIndex:currentQueueEncodeIndex]; - [self writeToActivityLog: "processNewQueueEncode currentQueueEncodeIndex is: %d", currentQueueEncodeIndex]; + [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 writeToActivityLog: "processNewQueueEncode sending to prepareJob"]; [self prepareJob]; - [self writeToActivityLog: "processNewQueueEncode back from prepareJob"]; - if( [[queueToApply objectForKey:@"SubtitlesForced"] intValue] == 1 ) - job->subtitle_force = 1; - else - job->subtitle_force = 0; /* - * subtitle of -1 is a scan + * If scanning we need to do some extra setup of the job. */ - if( job->subtitle == -1 ) + if( job->indepth_scan == 1 ) { char *x264opts_tmp; @@ -2375,14 +2684,11 @@ fWorkingCount = 0; */ job->pass = -1; x264opts_tmp = job->x264opts; - job->subtitle = -1; job->x264opts = NULL; job->indepth_scan = 1; - - job->select_subtitle = (hb_subtitle_t**)malloc(sizeof(hb_subtitle_t*)); - *(job->select_subtitle) = NULL; + /* * Add the pre-scan job @@ -2390,24 +2696,13 @@ fWorkingCount = 0; hb_add( fQueueEncodeLibhb, job ); job->x264opts = x264opts_tmp; } - else - job->select_subtitle = NULL; - - /* No subtitle were selected, so reset the subtitle to -1 (which before - * this point meant we were scanning - */ - if( job->subtitle == -2 ) - job->subtitle = -1; + if( [[queueToApply objectForKey:@"VideoTwoPass"] intValue] == 1 ) { - hb_subtitle_t **subtitle_tmp = job->select_subtitle; job->indepth_scan = 0; - /* - * Do not autoselect subtitles on the first pass of a two pass - */ - job->select_subtitle = NULL; + job->pass = 1; @@ -2418,8 +2713,6 @@ fWorkingCount = 0; job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */ strcpy(job->x264opts, [[queueToApply objectForKey:@"x264Option"] UTF8String]); - job->select_subtitle = subtitle_tmp; - hb_add( fQueueEncodeLibhb, job ); } @@ -2436,130 +2729,78 @@ fWorkingCount = 0; /* Lets mark our new encode as 1 or "Encoding" */ [queueToApply setObject:[NSNumber numberWithInt:1] forKey:@"Status"]; [self saveQueueFileItem]; + + /* we need to clean up the subtitle tracks after the job(s) have been set */ + int num_subtitle_tracks = hb_list_count(job->list_subtitle); + int ii; + for(ii = 0; ii < num_subtitle_tracks; ii++) + { + hb_subtitle_t * subtitle; + subtitle = (hb_subtitle_t *)hb_list_item(job->list_subtitle, 0); + + + hb_list_rem(job->list_subtitle, subtitle); + free(subtitle); + } + + /* We should be all setup so let 'er rip */ [self doRip]; } - #pragma mark - -#pragma mark Job Handling - - -- (void) prepareJob +#pragma mark Live Preview +/* Note,this is much like prepareJob, but directly sets the job vars so Picture Preview + * can encode to its temp preview directory and playback. This is *not* used for any actual user + * encodes + */ +- (void) prepareJobForPreview { - - NSMutableDictionary * queueToApply = [QueueFileArray objectAtIndex:currentQueueEncodeIndex]; - hb_list_t * list = hb_get_titles( fQueueEncodeLibhb ); - hb_title_t * title = (hb_title_t *) hb_list_item( list,0 ); // is always zero since now its a single title scan + hb_list_t * list = hb_get_titles( fHandle ); + hb_title_t * title = (hb_title_t *) hb_list_item( list, + [fSrcTitlePopUp indexOfSelectedItem] ); hb_job_t * job = title->job; hb_audio_config_t * audio; - [self writeToActivityLog: "prepareJob reached"]; + /* set job->angle for libdvdnav */ + job->angle = [fSrcAnglePopUp indexOfSelectedItem] + 1; /* Chapter selection */ - job->chapter_start = [[queueToApply objectForKey:@"JobChapterStart"] intValue]; - job->chapter_end = [[queueToApply objectForKey:@"JobChapterEnd"] intValue]; + job->chapter_start = [fSrcChapterStartPopUp indexOfSelectedItem] + 1; + job->chapter_end = [fSrcChapterEndPopUp indexOfSelectedItem] + 1; /* Format (Muxer) and Video Encoder */ - job->mux = [[queueToApply objectForKey:@"JobFileFormatMux"] intValue]; - job->vcodec = [[queueToApply objectForKey:@"JobVideoEncoderVcodec"] intValue]; - - - /* If mpeg-4, then set mpeg-4 specific options like chapters and > 4gb file sizes */ - //if( [fDstFormatPopUp indexOfSelectedItem] == 0 ) - //{ - /* We set the largeFileSize (64 bit formatting) variable here to allow for > 4gb files based on the format being - mpeg4 and the checkbox being checked - *Note: this will break compatibility with some target devices like iPod, etc.!!!!*/ - if( [[queueToApply objectForKey:@"Mp4LargeFile"] intValue] == 1) - { - job->largeFileSize = 1; - } - else - { - job->largeFileSize = 0; - } - /* We set http optimized mp4 here */ - if( [[queueToApply objectForKey:@"Mp4HttpOptimize"] intValue] == 1 ) - { - job->mp4_optimize = 1; - } - else - { - job->mp4_optimize = 0; - } - //} - - /* We set the chapter marker extraction here based on the format being - mpeg4 or mkv and the checkbox being checked */ - if ([[queueToApply objectForKey:@"ChapterMarkers"] intValue] == 1) - { - job->chapter_markers = 1; - } - else - { - job->chapter_markers = 0; - } + job->mux = [[fDstFormatPopUp selectedItem] tag]; + job->vcodec = [[fVidEncoderPopUp selectedItem] tag]; + + job->chapter_markers = 0; - - if( job->vcodec & HB_VCODEC_X264 ) + if( job->vcodec & HB_VCODEC_X264 ) { - if ([[queueToApply objectForKey:@"Mp4iPodCompatible"] intValue] == 1) - { - job->ipod_atom = 1; - } - else - { - job->ipod_atom = 0; - } - /* Set this flag to switch from Constant Quantizer(default) to Constant Rate Factor Thanks jbrjake Currently only used with Constant Quality setting*/ - if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultCrf"] > 0 && [[queueToApply objectForKey:@"VideoQualityType"] intValue] == 2) + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultCrf"] > 0 && [fVidQualityMatrix selectedRow] == 2) { job->crf = 1; } + /* Below Sends x264 options to the core library if x264 is selected*/ /* Lets use this as per Nyx, Thanks Nyx!*/ job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */ - /* Turbo first pass if two pass and Turbo First pass is selected */ - if( [[queueToApply objectForKey:@"VideoTwoPass"] intValue] == 1 && [[queueToApply objectForKey:@"VideoTurboTwoPass"] intValue] == 1 ) - { - /* pass the "Turbo" string to be appended to the existing x264 opts string into a variable for the first pass */ - NSString *firstPassOptStringTurbo = @":ref=1:subme=1:me=dia:analyse=none:trellis=0:no-fast-pskip=0:8x8dct=0:weightb=0"; - /* append the "Turbo" string variable to the existing opts string. - Note: the "Turbo" string must be appended, not prepended to work properly*/ - NSString *firstPassOptStringCombined = [[queueToApply objectForKey:@"x264Option"] stringByAppendingString:firstPassOptStringTurbo]; - strcpy(job->x264opts, [firstPassOptStringCombined UTF8String]); - } - else - { - strcpy(job->x264opts, [[queueToApply objectForKey:@"x264Option"] UTF8String]); - } + /* For previews we ignore the turbo option for the first pass of two since we only use 1 pass */ + strcpy(job->x264opts, [[fAdvancedOptions optionsString] UTF8String]); + } - - - [self writeToActivityLog: "prepareJob reached Picture Settings"]; - /* Picture Size Settings */ - job->width = [[queueToApply objectForKey:@"PictureWidth"] intValue]; - job->height = [[queueToApply objectForKey:@"PictureHeight"] intValue]; - - job->keep_ratio = [[queueToApply objectForKey:@"PictureKeepRatio"] intValue]; - job->pixel_ratio = [[queueToApply objectForKey:@"PicturePAR"] intValue]; - - - /* Here we use the crop values saved at the time the preset was saved */ - job->crop[0] = [[queueToApply objectForKey:@"PictureTopCrop"] intValue]; - job->crop[1] = [[queueToApply objectForKey:@"PictureBottomCrop"] intValue]; - job->crop[2] = [[queueToApply objectForKey:@"PictureLeftCrop"] intValue]; - job->crop[3] = [[queueToApply objectForKey:@"PictureRightCrop"] intValue]; - - [self writeToActivityLog: "prepareJob reached Frame Rate"]; - + /* Video settings */ - if( [[queueToApply objectForKey:@"JobIndexVideoFramerate"] intValue] > 0 ) + /* Set vfr to 0 as it's only on if using same as source in the framerate popup + * and detelecine is on, so we handle that in the logic below + */ + job->vfr = 0; + if( [fVidRatePopUp indexOfSelectedItem] > 0 ) { + /* a specific framerate has been chosen */ job->vrate = 27000000; - job->vrate_base = hb_video_rates[[[queueToApply objectForKey:@"JobIndexVideoFramerate"] intValue]-1].rate; + job->vrate_base = hb_video_rates[[fVidRatePopUp indexOfSelectedItem]-1].rate; /* 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*/ @@ -2567,54 +2808,732 @@ fWorkingCount = 0; } else { - job->vrate = [[queueToApply objectForKey:@"JobVrate"] intValue]; - job->vrate_base = [[queueToApply objectForKey:@"JobVrateBase"] intValue]; + /* We are same as source (variable) */ + job->vrate = title->rate; + job->vrate_base = title->rate_base; /* We are same as source so we set job->cfr to 0 * to enable true same as source framerate */ job->cfr = 0; + /* If we are same as source and we have detelecine on, we need to turn on + * job->vfr + */ + if ([fPictureController detelecine] == 1) + { + job->vfr = 1; + } } - [self writeToActivityLog: "prepareJob reached Bitrate Video Quality"]; - if ( [[queueToApply objectForKey:@"VideoQualityType"] intValue] == 0 ) - { - /* Target size. - Bitrate should already have been calculated and displayed - in fVidBitrateField, so let's just use it */ - } - if ( [[queueToApply objectForKey:@"VideoQualityType"] intValue] == 1 ) - { - job->vquality = -1.0; - job->vbitrate = [[queueToApply objectForKey:@"VideoAvgBitrate"] intValue]; - } - if ( [[queueToApply objectForKey:@"VideoQualityType"] intValue] == 2 ) + + switch( [fVidQualityMatrix selectedRow] ) { - job->vquality = [[queueToApply objectForKey:@"VideoQualitySlider"] floatValue]; - job->vbitrate = 0; - + case 0: + /* Target size. + Bitrate should already have been calculated and displayed + in fVidBitrateField, so let's just use it */ + case 1: + job->vquality = -1.0; + job->vbitrate = [fVidBitrateField intValue]; + break; + case 2: + job->vquality = [fVidQualityRFField floatValue]; + job->vbitrate = 0; + break; } - - job->grayscale = [[queueToApply objectForKey:@"VideoGrayScale"] intValue]; + /* Subtitle settings */ - job->subtitle = [[queueToApply objectForKey:@"JobSubtitlesIndex"] intValue] - 2; + NSMutableArray *subtitlesArray = nil; + subtitlesArray = [[NSMutableArray alloc] initWithArray:[fSubtitlesDelegate getSubtitleArray: subtitlesArray]]; - [self writeToActivityLog: "prepareJob reached Audio"]; - /* 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 ([[queueToApply objectForKey:@"Audio1Track"] intValue] > 0) + + + int subtitle = nil; +int force; +int burned; +int def; +bool one_burned = FALSE; + + int i = 0; + NSEnumerator *enumerator = [subtitlesArray objectEnumerator]; + id tempObject; + while (tempObject = [enumerator nextObject]) { - 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]; + + subtitle = [[tempObject objectForKey:@"subtitleSourceTrackNum"] intValue]; + force = [[tempObject objectForKey:@"subtitleTrackForced"] intValue]; + burned = [[tempObject objectForKey:@"subtitleTrackBurned"] intValue]; + def = [[tempObject objectForKey:@"subtitleTrackDefault"] intValue]; + + /* since the subtitleSourceTrackNum 0 is "None" in our array of the subtitle popups, + * we want to ignore it for display as well as encoding. + */ + if (subtitle > 0) + { + /* if i is 0, then we are in the first item of the subtitles which we need to + * check for the "Foreign Audio Search" which would be subtitleSourceTrackNum of 1 + * bearing in mind that for all tracks subtitleSourceTrackNum of 0 is None. + */ + + /* if we are on the first track and using "Foreign Audio Search" */ + if (i == 0 && subtitle == 1) + { + /* NOTE: Currently foreign language search is borked for preview. + * Commented out but left in for initial commit. */ + + + [self writeToActivityLog: "Foreign Language Search: %d", 1]; + + job->indepth_scan = 1; + if (burned == 1 || job->mux != HB_MUX_MP4) + { + if (burned != 1 && job->mux == HB_MUX_MKV) + { + job->select_subtitle_config.dest = hb_subtitle_config_s::PASSTHRUSUB; + } + else + { + job->select_subtitle_config.dest = hb_subtitle_config_s::RENDERSUB; + } + + job->select_subtitle_config.force = force; + job->select_subtitle_config.default_track = def; + + } + + + } + else + { + + /* for the actual source tracks, we must subtract the non source entries so + * that the menu index matches the source subtitle_list index for convenience */ + if (i == 0) + { + /* for the first track, the source tracks start at menu index 2 ( None is 0, + * Foreign Language Search is 1) so subtract 2 */ + subtitle = subtitle - 2; + } + else + { + /* for all other tracks, the source tracks start at menu index 1 (None is 0) + * so subtract 1. */ + + subtitle = subtitle - 1; + } + + /* We are setting a source subtitle so access the source subtitle info */ + hb_subtitle_t * subt; + + subt = (hb_subtitle_t *)hb_list_item(title->list_subtitle, subtitle); + + /* if we are getting the subtitles from an external srt file */ + if ([[tempObject objectForKey:@"subtitleSourceTrackType"] isEqualToString:@"SRT"]) + { + hb_subtitle_config_t sub_config; + + sub_config.offset = [[tempObject objectForKey:@"subtitleTrackSrtOffset"] intValue]; + + /* we need to srncpy file path and char code */ + strncpy(sub_config.src_filename, [[tempObject objectForKey:@"subtitleSourceSrtFilePath"] UTF8String], 128); + strncpy(sub_config.src_codeset, [[tempObject objectForKey:@"subtitleTrackSrtCharCode"] UTF8String], 40); + + sub_config.force = 0; + sub_config.dest = hb_subtitle_config_s::PASSTHRUSUB; + sub_config.default_track = def; + + hb_srt_add( job, &sub_config, [[tempObject objectForKey:@"subtitleTrackSrtLanguageIso3"] UTF8String]); + } + + if (subt != NULL) + { + [self writeToActivityLog: "Setting Subtitle: %s", subt]; + + hb_subtitle_config_t sub_config = subt->config; + + if (!burned && job->mux == HB_MUX_MKV && + subt->format == hb_subtitle_s::PICTURESUB) + { + sub_config.dest = hb_subtitle_config_s::PASSTHRUSUB; + } + else if (!burned && job->mux == HB_MUX_MP4 && + subt->format == hb_subtitle_s::PICTURESUB) + { + // Skip any non-burned vobsubs when output is mp4 + continue; + } + else if ( burned && subt->format == hb_subtitle_s::PICTURESUB ) + { + // Only allow one subtitle to be burned into the video + if (one_burned) + continue; + one_burned = TRUE; + } + sub_config.force = force; + sub_config.default_track = def; + hb_subtitle_add( job, &sub_config, subtitle ); + } + + } + } + i++; + } + + + +[subtitlesArray autorelease]; + + + /* 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); + + } + + + + /* Filters */ + + /* Though Grayscale is not really a filter, per se + * we put it here since its in the filters panel + */ + + if ([fPictureController grayscale]) + { + job->grayscale = 1; + } + else + { + job->grayscale = 0; + } + + /* Initialize the filters list */ + job->filters = hb_list_init(); + + /* Now lets call the filters if applicable. + * The order of the filters is critical + */ + + /* Detelecine */ + if ([fPictureController detelecine] == 1) + { + hb_list_add( job->filters, &hb_filter_detelecine ); + } + if ([fPictureController detelecine] == 2) + { + /* use a custom detelecine string */ + hb_filter_detelecine.settings = (char *) [[fPictureController detelecineCustomString] UTF8String]; + hb_list_add( job->filters, &hb_filter_detelecine ); + } + if ([fPictureController useDecomb] == 1) + { + /* Decomb */ + if ([fPictureController decomb] == 1) + { + /* Run old deinterlacer fd by default */ + //hb_filter_decomb.settings = (char *) [[fPicSettingDecomb stringValue] UTF8String]; + hb_list_add( job->filters, &hb_filter_decomb ); + } + /* we add the custom string if present */ + if ([fPictureController decomb] == 2) + { + /* use a custom decomb string */ + hb_filter_decomb.settings = (char *) [[fPictureController decombCustomString] UTF8String]; + hb_list_add( job->filters, &hb_filter_decomb ); + } + } + else + { + + /* Deinterlace */ + if ([fPictureController deinterlace] == 1) + { + /* Run old deinterlacer fd by default */ + hb_filter_deinterlace.settings = "-1"; + hb_list_add( job->filters, &hb_filter_deinterlace ); + } + else if ([fPictureController deinterlace] == 2) + { + /* Yadif mode 0 (without spatial deinterlacing.) */ + hb_filter_deinterlace.settings = "2"; + hb_list_add( job->filters, &hb_filter_deinterlace ); + } + else if ([fPictureController deinterlace] == 3) + { + /* Yadif (with spatial deinterlacing) */ + hb_filter_deinterlace.settings = "0"; + hb_list_add( job->filters, &hb_filter_deinterlace ); + } + else if ([fPictureController deinterlace] == 4) + { + /* we add the custom string if present */ + hb_filter_deinterlace.settings = (char *) [[fPictureController deinterlaceCustomString] UTF8String]; + hb_list_add( job->filters, &hb_filter_deinterlace ); + } + } + + /* Denoise */ + if ([fPictureController denoise] == 1) // Weak in popup + { + hb_filter_denoise.settings = "2:1:2:3"; + hb_list_add( job->filters, &hb_filter_denoise ); + } + else if ([fPictureController denoise] == 2) // Medium in popup + { + hb_filter_denoise.settings = "3:2:2:3"; + hb_list_add( job->filters, &hb_filter_denoise ); + } + else if ([fPictureController denoise] == 3) // Strong in popup + { + hb_filter_denoise.settings = "7:7:5:5"; + hb_list_add( job->filters, &hb_filter_denoise ); + } + else if ([fPictureController denoise] == 4) // custom in popup + { + /* we add the custom string if present */ + hb_filter_denoise.settings = (char *) [[fPictureController denoiseCustomString] UTF8String]; + hb_list_add( job->filters, &hb_filter_denoise ); + } + + /* Deblock (uses pp7 default) */ + /* NOTE: even though there is a valid deblock setting of 0 for the filter, for + * the macgui's purposes a value of 0 actually means to not even use the filter + * current hb_filter_deblock.settings valid ranges are from 5 - 15 + */ + if ([fPictureController deblock] != 0) + { + NSString *deblockStringValue = [NSString stringWithFormat: @"%d",[fPictureController deblock]]; + hb_filter_deblock.settings = (char *) [deblockStringValue UTF8String]; + hb_list_add( job->filters, &hb_filter_deblock ); + } + +} + + +#pragma mark - +#pragma mark Job Handling + + +- (void) prepareJob +{ + + NSMutableDictionary * queueToApply = [QueueFileArray objectAtIndex:currentQueueEncodeIndex]; + hb_list_t * list = hb_get_titles( fQueueEncodeLibhb ); + hb_title_t * title = (hb_title_t *) hb_list_item( list,0 ); // is always zero since now its a single title scan + hb_job_t * job = title->job; + hb_audio_config_t * audio; + /* Title Angle for dvdnav */ + job->angle = [[queueToApply objectForKey:@"TitleAngle"] intValue]; + /* Chapter selection */ + job->chapter_start = [[queueToApply objectForKey:@"JobChapterStart"] intValue]; + job->chapter_end = [[queueToApply objectForKey:@"JobChapterEnd"] intValue]; + + /* Format (Muxer) and Video Encoder */ + job->mux = [[queueToApply objectForKey:@"JobFileFormatMux"] intValue]; + job->vcodec = [[queueToApply objectForKey:@"JobVideoEncoderVcodec"] intValue]; + + + /* If mpeg-4, then set mpeg-4 specific options like chapters and > 4gb file sizes */ + if( [[queueToApply objectForKey:@"Mp4LargeFile"] intValue] == 1) + { + job->largeFileSize = 1; + } + else + { + job->largeFileSize = 0; + } + /* We set http optimized mp4 here */ + if( [[queueToApply objectForKey:@"Mp4HttpOptimize"] intValue] == 1 ) + { + job->mp4_optimize = 1; + } + else + { + job->mp4_optimize = 0; + } + + + /* We set the chapter marker extraction here based on the format being + mpeg4 or mkv and the checkbox being checked */ + if ([[queueToApply objectForKey:@"ChapterMarkers"] intValue] == 1) + { + job->chapter_markers = 1; + + /* now lets get our saved chapter names out the array in the queue file + * and insert them back into the title chapter list. We have it here, + * because unless we are inserting chapter markers there is no need to + * spend the overhead of iterating through the chapter names array imo + * Also, note that if for some reason we don't apply chapter names, the + * chapters just come out 001, 002, etc. etc. + */ + + NSMutableArray *ChapterNamesArray = [queueToApply objectForKey:@"ChapterNames"]; + int i = 0; + NSEnumerator *enumerator = [ChapterNamesArray objectEnumerator]; + id tempObject; + while (tempObject = [enumerator nextObject]) + { + hb_chapter_t *chapter = (hb_chapter_t *) hb_list_item( title->list_chapter, i ); + if( chapter != NULL ) + { + strncpy( chapter->title, [tempObject UTF8String], 1023); + chapter->title[1023] = '\0'; + } + i++; + } + } + else + { + job->chapter_markers = 0; + } + + if( job->vcodec & HB_VCODEC_X264 ) + { + if ([[queueToApply objectForKey:@"Mp4iPodCompatible"] intValue] == 1) + { + job->ipod_atom = 1; + } + else + { + job->ipod_atom = 0; + } + + /* Set this flag to switch from Constant Quantizer(default) to Constant Rate Factor Thanks jbrjake + Currently only used with Constant Quality setting*/ + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultCrf"] > 0 && [[queueToApply objectForKey:@"VideoQualityType"] intValue] == 2) + { + job->crf = 1; + } + /* Below Sends x264 options to the core library if x264 is selected*/ + /* Lets use this as per Nyx, Thanks Nyx!*/ + job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */ + /* Turbo first pass if two pass and Turbo First pass is selected */ + if( [[queueToApply objectForKey:@"VideoTwoPass"] intValue] == 1 && [[queueToApply objectForKey:@"VideoTurboTwoPass"] intValue] == 1 ) + { + /* pass the "Turbo" string to be appended to the existing x264 opts string into a variable for the first pass */ + NSString *firstPassOptStringTurbo = @":ref=1:subme=1:me=dia:analyse=none:trellis=0:no-fast-pskip=0:8x8dct=0:weightb=0"; + /* append the "Turbo" string variable to the existing opts string. + Note: the "Turbo" string must be appended, not prepended to work properly*/ + NSString *firstPassOptStringCombined = [[queueToApply objectForKey:@"x264Option"] stringByAppendingString:firstPassOptStringTurbo]; + strcpy(job->x264opts, [firstPassOptStringCombined UTF8String]); + } + else + { + strcpy(job->x264opts, [[queueToApply objectForKey:@"x264Option"] UTF8String]); + } + + } + + + /* Picture Size Settings */ + job->width = [[queueToApply objectForKey:@"PictureWidth"] intValue]; + job->height = [[queueToApply objectForKey:@"PictureHeight"] intValue]; + + job->keep_ratio = [[queueToApply objectForKey:@"PictureKeepRatio"] intValue]; + job->anamorphic.mode = [[queueToApply objectForKey:@"PicturePAR"] intValue]; + if ([[queueToApply objectForKey:@"PicturePAR"] intValue] == 3) + { + /* insert our custom values here for capuj */ + job->width = [[queueToApply objectForKey:@"PicturePARStorageWidth"] intValue]; + job->height = [[queueToApply objectForKey:@"PicturePARStorageHeight"] intValue]; + + job->anamorphic.par_width = [[queueToApply objectForKey:@"PicturePARPixelWidth"] intValue]; + job->anamorphic.par_height = [[queueToApply objectForKey:@"PicturePARPixelHeight"] intValue]; + + job->anamorphic.dar_width = [[queueToApply objectForKey:@"PicturePARDisplayWidth"] floatValue]; + job->anamorphic.dar_height = [[queueToApply objectForKey:@"PicturePARDisplayHeight"] floatValue]; + } + + /* Here we use the crop values saved at the time the preset was saved */ + job->crop[0] = [[queueToApply objectForKey:@"PictureTopCrop"] intValue]; + job->crop[1] = [[queueToApply objectForKey:@"PictureBottomCrop"] intValue]; + job->crop[2] = [[queueToApply objectForKey:@"PictureLeftCrop"] intValue]; + job->crop[3] = [[queueToApply objectForKey:@"PictureRightCrop"] intValue]; + + /* Video settings */ + /* Framerate */ + + /* Set vfr to 0 as it's only on if using same as source in the framerate popup + * and detelecine is on, so we handle that in the logic below + */ + job->vfr = 0; + if( [[queueToApply objectForKey:@"JobIndexVideoFramerate"] intValue] > 0 ) + { + /* a specific framerate has been chosen */ + job->vrate = 27000000; + job->vrate_base = hb_video_rates[[[queueToApply objectForKey:@"JobIndexVideoFramerate"] intValue]-1].rate; + /* 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; + } + else + { + /* We are same as source (variable) */ + job->vrate = [[queueToApply objectForKey:@"JobVrate"] intValue]; + job->vrate_base = [[queueToApply objectForKey:@"JobVrateBase"] intValue]; + /* We are same as source so we set job->cfr to 0 + * to enable true same as source framerate */ + job->cfr = 0; + /* If we are same as source and we have detelecine on, we need to turn on + * job->vfr + */ + if ([[queueToApply objectForKey:@"PictureDetelecine"] intValue] == 1) + { + job->vfr = 1; + } + } + + if ( [[queueToApply objectForKey:@"VideoQualityType"] intValue] != 2 ) + { + /* Target size. + Bitrate should already have been calculated and displayed + in fVidBitrateField, so let's just use it same as abr*/ + job->vquality = -1.0; + job->vbitrate = [[queueToApply objectForKey:@"VideoAvgBitrate"] intValue]; + } + if ( [[queueToApply objectForKey:@"VideoQualityType"] intValue] == 2 ) + { + job->vquality = [[queueToApply objectForKey:@"VideoQualitySlider"] floatValue]; + job->vbitrate = 0; + + } + + job->grayscale = [[queueToApply objectForKey:@"VideoGrayScale"] intValue]; + + + +#pragma mark - +#pragma mark Process Subtitles to libhb + +/* Map the settings in the dictionaries for the SubtitleList array to match title->list_subtitle + * which means that we need to account for the offset of non source language settings in from + * the NSPopUpCell menu. For all of the objects in the SubtitleList array this means 0 is "None" + * from the popup menu, additionally the first track has "Foreign Audio Search" at 1. So we use + * an int to offset the index number for the objectForKey:@"subtitleSourceTrackNum" to map that + * to the source tracks position in title->list_subtitle. + */ + +int subtitle = nil; +int force; +int burned; +int def; +bool one_burned = FALSE; + + int i = 0; + NSEnumerator *enumerator = [[queueToApply objectForKey:@"SubtitleList"] objectEnumerator]; + id tempObject; + while (tempObject = [enumerator nextObject]) + { + + subtitle = [[tempObject objectForKey:@"subtitleSourceTrackNum"] intValue]; + force = [[tempObject objectForKey:@"subtitleTrackForced"] intValue]; + burned = [[tempObject objectForKey:@"subtitleTrackBurned"] intValue]; + def = [[tempObject objectForKey:@"subtitleTrackDefault"] intValue]; + + /* since the subtitleSourceTrackNum 0 is "None" in our array of the subtitle popups, + * we want to ignore it for display as well as encoding. + */ + if (subtitle > 0) + { + /* if i is 0, then we are in the first item of the subtitles which we need to + * check for the "Foreign Audio Search" which would be subtitleSourceTrackNum of 1 + * bearing in mind that for all tracks subtitleSourceTrackNum of 0 is None. + */ + + /* if we are on the first track and using "Foreign Audio Search" */ + if (i == 0 && subtitle == 1) + { + [self writeToActivityLog: "Foreign Language Search: %d", 1]; + + job->indepth_scan = 1; + if (burned == 1 || job->mux != HB_MUX_MP4) + { + if (burned != 1 && job->mux == HB_MUX_MKV) + { + job->select_subtitle_config.dest = hb_subtitle_config_s::PASSTHRUSUB; + } + else + { + job->select_subtitle_config.dest = hb_subtitle_config_s::RENDERSUB; + } + + job->select_subtitle_config.force = force; + job->select_subtitle_config.default_track = def; + } + + + } + else + { + + /* for the actual source tracks, we must subtract the non source entries so + * that the menu index matches the source subtitle_list index for convenience */ + if (i == 0) + { + /* for the first track, the source tracks start at menu index 2 ( None is 0, + * Foreign Language Search is 1) so subtract 2 */ + subtitle = subtitle - 2; + } + else + { + /* for all other tracks, the source tracks start at menu index 1 (None is 0) + * so subtract 1. */ + + subtitle = subtitle - 1; + } + + /* We are setting a source subtitle so access the source subtitle info */ + hb_subtitle_t * subt; + + subt = (hb_subtitle_t *)hb_list_item(title->list_subtitle, subtitle); + + /* if we are getting the subtitles from an external srt file */ + if ([[tempObject objectForKey:@"subtitleSourceTrackType"] isEqualToString:@"SRT"]) + { + hb_subtitle_config_t sub_config; + + sub_config.offset = [[tempObject objectForKey:@"subtitleTrackSrtOffset"] intValue]; + + /* we need to srncpy file name and codeset */ + //sub_config.src_filename = [[tempObject objectForKey:@"subtitleSourceSrtFilePath"] UTF8String]; + strncpy(sub_config.src_filename, [[tempObject objectForKey:@"subtitleSourceSrtFilePath"] UTF8String], 128); + //sub_config.src_codeset = [[tempObject objectForKey:@"subtitleTrackSrtCharCode"] UTF8String]; + strncpy(sub_config.src_codeset, [[tempObject objectForKey:@"subtitleTrackSrtCharCode"] UTF8String], 40); + + sub_config.force = 0; + sub_config.dest = hb_subtitle_config_s::PASSTHRUSUB; + sub_config.default_track = def; + + hb_srt_add( job, &sub_config, [[tempObject objectForKey:@"subtitleTrackSrtLanguageIso3"] UTF8String]); + } + + + if (subt != NULL) + { + [self writeToActivityLog: "Setting Subtitle: %s", subt]; + + hb_subtitle_config_t sub_config = subt->config; + + if (!burned && job->mux == HB_MUX_MKV && + subt->format == hb_subtitle_s::PICTURESUB) + { + sub_config.dest = hb_subtitle_config_s::PASSTHRUSUB; + } + else if (!burned && job->mux == HB_MUX_MP4 && + subt->format == hb_subtitle_s::PICTURESUB) + { + // Skip any non-burned vobsubs when output is mp4 + continue; + } + else if ( burned && subt->format == hb_subtitle_s::PICTURESUB ) + { + // Only allow one subtitle to be burned into the video + if (one_burned) + continue; + one_burned = TRUE; + } + sub_config.force = force; + sub_config.default_track = def; + hb_subtitle_add( job, &sub_config, subtitle ); + } + + } + } + i++; + } + +#pragma mark - + + + /* 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 ([[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]; @@ -2669,24 +3588,14 @@ fWorkingCount = 0; 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:@"Audio3TrackDRCSlider"] floatValue]; + audio->out.dynamic_range_compression = [[queueToApply objectForKey:@"Audio4TrackDRCSlider"] floatValue]; hb_audio_add( job, audio ); - free(audio); - } - - /* set vfr according to the Picture Window */ - if ([[queueToApply objectForKey:@"VFR"] intValue] == 1) - { - job->vfr = 1; - } - else - { - job->vfr = 0; + + } - [self writeToActivityLog: "prepareJob reached Filters"]; - /* Filters */ + /* Filters */ job->filters = hb_list_init(); /* Now lets call the filters if applicable. @@ -2695,37 +3604,64 @@ fWorkingCount = 0; /* Detelecine */ if ([[queueToApply objectForKey:@"PictureDetelecine"] intValue] == 1) { + //if ([queueToApply objectForKey:@"PictureDetelecineCustom"]) hb_list_add( job->filters, &hb_filter_detelecine ); } - - /* Decomb */ - if ([[queueToApply objectForKey:@"PictureDecomb"] intValue] == 1) + if ([[queueToApply objectForKey:@"PictureDetelecine"] intValue] == 2) { - /* Run old deinterlacer fd by default */ - hb_filter_decomb.settings = (char *) [[queueToApply objectForKey:@"JobPictureDecomb"] UTF8String]; - hb_list_add( job->filters, &hb_filter_decomb ); + /* use a custom detelecine string */ + hb_filter_detelecine.settings = (char *) [[queueToApply objectForKey:@"PictureDetelecineCustom"] UTF8String]; + hb_list_add( job->filters, &hb_filter_detelecine ); } - /* Deinterlace */ - if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 1) + if ([[queueToApply objectForKey:@"PictureDecombDeinterlace"] intValue] == 1) { - /* Run old deinterlacer fd by default */ - hb_filter_deinterlace.settings = "-1"; - hb_list_add( job->filters, &hb_filter_deinterlace ); - } - else if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 2) - { - /* Yadif mode 0 (without spatial deinterlacing.) */ - hb_filter_deinterlace.settings = "2"; - hb_list_add( job->filters, &hb_filter_deinterlace ); + /* Decomb */ + if ([[queueToApply objectForKey:@"PictureDecomb"] intValue] == 1) + { + /* Run old deinterlacer fd by default */ + hb_list_add( job->filters, &hb_filter_decomb ); + } + /* we add the custom string if present */ + if ([[queueToApply objectForKey:@"PictureDecomb"] intValue] == 2) + { + /* use a custom decomb string */ + hb_filter_decomb.settings = (char *) [[queueToApply objectForKey:@"PictureDecombCustom"] UTF8String]; + hb_list_add( job->filters, &hb_filter_decomb ); + } + } - else if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 3) + else { - /* Yadif (with spatial deinterlacing) */ - hb_filter_deinterlace.settings = "0"; - hb_list_add( job->filters, &hb_filter_deinterlace ); + + /* Deinterlace */ + if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 1) + { + /* Run old deinterlacer fd by default */ + hb_filter_deinterlace.settings = "-1"; + hb_list_add( job->filters, &hb_filter_deinterlace ); + } + else if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 2) + { + /* Yadif mode 0 (without spatial deinterlacing.) */ + hb_filter_deinterlace.settings = "2"; + hb_list_add( job->filters, &hb_filter_deinterlace ); + } + else if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 3) + { + /* Yadif (with spatial deinterlacing) */ + hb_filter_deinterlace.settings = "0"; + hb_list_add( job->filters, &hb_filter_deinterlace ); + } + else if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 4) + { + /* we add the custom string if present */ + hb_filter_deinterlace.settings = (char *) [[queueToApply objectForKey:@"PictureDeinterlaceCustom"] UTF8String]; + hb_list_add( job->filters, &hb_filter_deinterlace ); + } + + } - /* Denoise */ if ([[queueToApply objectForKey:@"PictureDenoise"] intValue] == 1) // Weak in popup { @@ -2742,10 +3678,21 @@ fWorkingCount = 0; hb_filter_denoise.settings = "7:7:5:5"; hb_list_add( job->filters, &hb_filter_denoise ); } + else if ([[queueToApply objectForKey:@"PictureDenoise"] intValue] == 4) // Custom in popup + { + /* we add the custom string if present */ + hb_filter_denoise.settings = (char *) [[queueToApply objectForKey:@"PictureDenoiseCustom"] UTF8String]; + hb_list_add( job->filters, &hb_filter_denoise ); + } /* Deblock (uses pp7 default) */ - if ([[queueToApply objectForKey:@"PictureDeblock"] intValue] == 1) + /* NOTE: even though there is a valid deblock setting of 0 for the filter, for + * the macgui's purposes a value of 0 actually means to not even use the filter + * current hb_filter_deblock.settings valid ranges are from 5 - 15 + */ + if ([[queueToApply objectForKey:@"PictureDeblock"] intValue] != 0) { + hb_filter_deblock.settings = (char *) [[queueToApply objectForKey:@"PictureDeblock"] UTF8String]; hb_list_add( job->filters, &hb_filter_deblock ); } [self writeToActivityLog: "prepareJob exiting"]; @@ -2765,18 +3712,51 @@ fWorkingCount = 0; NSRunAlertPanel(@"Warning!", @"This is not a valid destination directory!", @"OK", nil, nil); return; } - - /* We check for duplicate name here */ - if( [[NSFileManager defaultManager] fileExistsAtPath: - [fDstFile2Field stringValue]] ) + + BOOL fileExists; + fileExists = NO; + + BOOL fileExistsInQueue; + fileExistsInQueue = NO; + + /* We check for and existing file here */ + if([[NSFileManager defaultManager] fileExistsAtPath: [fDstFile2Field stringValue]]) + { + fileExists = YES; + } + + /* We now run through the queue and make sure we are not overwriting an exisiting queue item */ + int i = 0; + NSEnumerator *enumerator = [QueueFileArray objectEnumerator]; + id tempObject; + while (tempObject = [enumerator nextObject]) + { + NSDictionary *thisQueueDict = tempObject; + if ([[thisQueueDict objectForKey:@"DestinationPath"] isEqualToString: [fDstFile2Field stringValue]]) + { + fileExistsInQueue = YES; + } + i++; + } + + + if(fileExists == YES) { - NSBeginCriticalAlertSheet( NSLocalizedString( @"File already exists", @"" ), - NSLocalizedString( @"Cancel", @"" ), NSLocalizedString( @"Overwrite", @"" ), nil, fWindow, self, - @selector( overwriteAddToQueueAlertDone:returnCode:contextInfo: ), - NULL, NULL, [NSString stringWithFormat: - NSLocalizedString( @"Do you want to overwrite %@?", @"" ), - [fDstFile2Field stringValue]] ); - // overwriteAddToQueueAlertDone: will be called when the alert is dismissed. + NSBeginCriticalAlertSheet( NSLocalizedString( @"File already exists.", @"" ), + NSLocalizedString( @"Cancel", @"" ), NSLocalizedString( @"Overwrite", @"" ), nil, fWindow, self, + @selector( overwriteAddToQueueAlertDone:returnCode:contextInfo: ), + NULL, NULL, [NSString stringWithFormat: + NSLocalizedString( @"Do you want to overwrite %@?", @"" ), + [fDstFile2Field stringValue]] ); + } + else if (fileExistsInQueue == YES) + { + 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: + NSLocalizedString( @"Do you want to overwrite %@?", @"" ), + [fDstFile2Field stringValue]] ); } else { @@ -2816,8 +3796,11 @@ fWorkingCount = 0; return; } - // If there are pending jobs in the queue, then this is a rip the queue + /* We check to see if we need to warn the user that the computer will go to sleep + or shut down when encoding is finished */ + [self remindUserOfSleepOrShutdown]; + // If there are pending jobs in the queue, then this is a rip the queue if (fPendingCount > 0) { /* here lets start the queue with the first pending item */ @@ -2853,15 +3836,13 @@ fWorkingCount = 0; otherwise, just rip the queue */ if(fPendingCount == 0) { - [self writeToActivityLog: "Rip: No pending jobs, so sending this one to doAddToQueue"]; - [self doAddToQueue]; + [self writeToActivityLog: "Rip: No pending jobs, so sending this one to doAddToQueue"]; + [self doAddToQueue]; } - NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent]; - [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"]; /* go right to processing the new queue encode */ - [self writeToActivityLog: "Rip: Going right to performNewQueueScan"]; - [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]]; + [self writeToActivityLog: "Rip: Going right to performNewQueueScan"]; + [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]]; } } @@ -2928,6 +3909,50 @@ fWorkingCount = 0; //------------------------------------------------------------------------------------ +// Displays an alert asking user if the want to cancel encoding of current job. +// Cancel: returns immediately after posting the alert. Later, when the user +// acknowledges the alert, doCancelCurrentJob is called. +//------------------------------------------------------------------------------------ +- (IBAction)Cancel: (id)sender +{ + if (!fQueueController) return; + + hb_pause( fQueueEncodeLibhb ); + NSString * alertTitle = [NSString stringWithFormat:NSLocalizedString(@"You are currently encoding. What would you like to do ?", nil)]; + + // Which window to attach the sheet to? + NSWindow * docWindow; + if ([sender respondsToSelector: @selector(window)]) + docWindow = [sender window]; + else + docWindow = fWindow; + + NSBeginCriticalAlertSheet( + alertTitle, + NSLocalizedString(@"Continue Encoding", nil), + NSLocalizedString(@"Cancel Current and Stop", nil), + NSLocalizedString(@"Cancel Current and Continue", nil), + docWindow, self, + nil, @selector(didDimissCancel:returnCode:contextInfo:), nil, + NSLocalizedString(@"Your encode will be cancelled if you don't continue encoding.", nil)); + + // didDimissCancelCurrentJob:returnCode:contextInfo: will be called when the dialog is dismissed +} + +- (void) didDimissCancel: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo +{ + hb_resume( fQueueEncodeLibhb ); + if (returnCode == NSAlertOtherReturn) + { + [self doCancelCurrentJob]; // <- this also stops libhb + } + if (returnCode == NSAlertAlternateReturn) + { + [self doCancelCurrentJobAndStop]; + } +} + +//------------------------------------------------------------------------------------ // Cancels and deletes the current job and stops libhb from processing the remaining // encodes. //------------------------------------------------------------------------------------ @@ -2941,6 +3966,12 @@ fWorkingCount = 0; hb_stop( fQueueEncodeLibhb ); + + // Delete all remaining jobs since libhb doesn't do this on its own. + hb_job_t * job; + while( ( job = hb_job(fQueueEncodeLibhb, 0) ) ) + hb_rem( fQueueEncodeLibhb, job ); + fEncodeState = 2; // don't alert at end of processing since this was a cancel // now that we've stopped the currently encoding job, lets mark it as cancelled @@ -2967,43 +3998,27 @@ fWorkingCount = 0; } -//------------------------------------------------------------------------------------ -// Displays an alert asking user if the want to cancel encoding of current job. -// Cancel: returns immediately after posting the alert. Later, when the user -// acknowledges the alert, doCancelCurrentJob is called. -//------------------------------------------------------------------------------------ -- (IBAction)Cancel: (id)sender +- (void) doCancelCurrentJobAndStop { - if (!fQueueController) return; + hb_stop( fQueueEncodeLibhb ); - - NSString * alertTitle = [NSString stringWithFormat:NSLocalizedString(@"Stop encoding ?", nil)]; - - // Which window to attach the sheet to? - NSWindow * docWindow; - if ([sender respondsToSelector: @selector(window)]) - docWindow = [sender window]; - else - docWindow = fWindow; - - NSBeginCriticalAlertSheet( - alertTitle, - NSLocalizedString(@"Keep Encoding", nil), - nil, - NSLocalizedString(@"Stop Encoding", nil), - docWindow, self, - nil, @selector(didDimissCancelCurrentJob:returnCode:contextInfo:), nil, - NSLocalizedString(@"Your movie will be lost if you don't continue encoding.", nil)); + // Delete all remaining jobs since libhb doesn't do this on its own. + hb_job_t * job; + while( ( job = hb_job(fQueueEncodeLibhb, 0) ) ) + hb_rem( fQueueEncodeLibhb, job ); + + + fEncodeState = 2; // don't alert at end of processing since this was a cancel - // didDimissCancelCurrentJob:returnCode:contextInfo: will be called when the dialog is dismissed -} - -- (void) didDimissCancelCurrentJob: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo -{ - if (returnCode == NSAlertOtherReturn) - [self doCancelCurrentJob]; // <- this also stops libhb + // now that we've stopped the currently encoding job, lets mark it as cancelled + [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] setObject:[NSNumber numberWithInt:3] forKey:@"Status"]; + // 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++ ; + [self writeToActivityLog: "cancelling current job and stopping the queue"]; } - - (IBAction) Pause: (id) sender { hb_state_t s; @@ -3053,15 +4068,31 @@ fWorkingCount = 0; [fSrcChapterEndPopUp selectItemAtIndex: hb_list_count( title->list_chapter ) - 1]; [self chapterPopUpChanged:nil]; - + + /* if using dvd nav, show the angle widget */ + if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"UseDvdNav"] boolValue]) + { + [fSrcAngleLabel setHidden:NO]; + [fSrcAnglePopUp setHidden:NO]; + + [fSrcAnglePopUp removeAllItems]; + for( int i = 0; i < title->angle_count; i++ ) + { + [fSrcAnglePopUp addItemWithTitle: [NSString stringWithFormat: @"%d", i + 1]]; + } + [fSrcAnglePopUp selectItemAtIndex: 0]; + } + else + { + [fSrcAngleLabel setHidden:YES]; + [fSrcAnglePopUp setHidden:YES]; + } + /* Start Get and set the initial pic size for display */ hb_job_t * job = title->job; fTitle = title; - - /*Set Source Size Field Here */ - [fPicSettingsSrc setStringValue: [NSString stringWithFormat: @"%d x %d", fTitle->width, fTitle->height]]; - - /* Set Auto Crop to on upon selecting a new title */ + + /* Set Auto Crop to on upon selecting a new title */ [fPictureController setAutoCrop:YES]; /* We get the originial output picture width and height and put them @@ -3073,28 +4104,14 @@ fWorkingCount = 0; AutoCropLeft = job->crop[2]; AutoCropRight = job->crop[3]; - /* Run Through encoderPopUpChanged to see if there - needs to be any pic value modifications based on encoder settings */ - //[self encoderPopUpChanged: NULL]; - /* END Get and set the initial pic size for display */ - - /* Update subtitle popups */ - hb_subtitle_t * subtitle; - [fSubPopUp removeAllItems]; - [fSubPopUp addItemWithTitle: @"None"]; - [fSubPopUp addItemWithTitle: @"Autoselect"]; - for( int i = 0; i < hb_list_count( title->list_subtitle ); i++ ) - { - subtitle = (hb_subtitle_t *) hb_list_item( title->list_subtitle, i ); - - /* We cannot use NSPopUpButton's addItemWithTitle because - it checks for duplicate entries */ - [[fSubPopUp menu] addItemWithTitle: [NSString stringWithCString: - subtitle->lang] action: NULL keyEquivalent: @""]; - } - [fSubPopUp selectItemAtIndex: 0]; + /* Reset the new title in fPictureController && fPreviewController*/ + [fPictureController SetTitle:title]; - [self subtitleSelectionChanged:nil]; + + /* Update Subtitle Table */ + [fSubtitlesDelegate resetWithTitle:title]; + [fSubtitlesTable reloadData]; + /* Update chapter table */ [fChapterTitlesDelegate resetWithTitle:title]; @@ -3133,7 +4150,7 @@ fWorkingCount = 0; [self calculatePictureSizing:nil]; /* lets call tableViewSelected to make sure that any preset we have selected is enforced after a title change */ - [self selectPreset:nil]; + [self selectPreset:nil]; } - (IBAction) chapterPopUpChanged: (id) sender @@ -3166,6 +4183,17 @@ fWorkingCount = 0; duration % 60]]; [self calculateBitrate: sender]; + + if ( [fSrcChapterStartPopUp indexOfSelectedItem] == [fSrcChapterEndPopUp indexOfSelectedItem] ) + { + /* Disable chapter markers for any source with less than two chapters as it makes no sense. */ + [fCreateChapterMarkers setEnabled: NO]; + [fCreateChapterMarkers setState: NSOffState]; + } + else + { + [fCreateChapterMarkers setEnabled: YES]; + } } - (IBAction) formatPopUpChanged: (id) sender @@ -3179,6 +4207,10 @@ fWorkingCount = 0; [fDstMp4iPodFileCheck setHidden: YES]; /* Update the Video Codec PopUp */ + /* lets get the tag of the currently selected item first so we might reset it later */ + int selectedVidEncoderTag; + selectedVidEncoderTag = [[fVidEncoderPopUp selectedItem] tag]; + /* Note: we now store the video encoder int values from common.c in the tags of each popup for easy retrieval later */ [fVidEncoderPopUp removeAllItems]; NSMenuItem *menuItem; @@ -3186,8 +4218,6 @@ fWorkingCount = 0; menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"MPEG-4 (FFmpeg)" action: NULL keyEquivalent: @""]; [menuItem setTag: HB_VCODEC_FFMPEG]; - menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"MPEG-4 (XviD)" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_VCODEC_XVID]; switch( format ) { case 0: @@ -3221,27 +4251,21 @@ fWorkingCount = 0; [fCreateChapterMarkers setEnabled: YES]; break; - case 2: - ext = "avi"; - /* Add additional video encoders here */ - menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"H.264 (x264)" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_VCODEC_X264]; - /* We disable the create chapters checkbox here and make sure it is unchecked*/ - [fCreateChapterMarkers setEnabled: NO]; - [fCreateChapterMarkers setState: NSOffState]; - break; - - case 3: - ext = "ogm"; - /* Add additional video encoders here */ - menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"VP3 (Theora)" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_VCODEC_THEORA]; - /* We disable the create chapters checkbox here and make sure it is unchecked*/ - [fCreateChapterMarkers setEnabled: NO]; - [fCreateChapterMarkers setState: NSOffState]; - break; + + } + /* tell fSubtitlesDelegate we have a new video container */ + + [fSubtitlesDelegate containerChanged:[[fDstFormatPopUp selectedItem] tag]]; + [fSubtitlesTable reloadData]; + /* if we have a previously selected vid encoder tag, then try to select it */ + if (selectedVidEncoderTag) + { + [fVidEncoderPopUp selectItemWithTag: selectedVidEncoderTag]; + } + else + { + [fVidEncoderPopUp selectItemAtIndex: 0]; } - [fVidEncoderPopUp selectItemAtIndex: 0]; [self audioAddAudioTrackCodecs: fAudTrack1CodecPopUp]; [self audioAddAudioTrackCodecs: fAudTrack2CodecPopUp]; @@ -3301,16 +4325,6 @@ fWorkingCount = 0; [[fDstFile2Field stringValue] stringByDeletingPathExtension], extension]]; } -- (void) shouldEnableHttpMp4CheckBox: (id) sender -{ - 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 ) - [fDstMp4HttpOptFileCheck setEnabled: NO]; - else - [fDstMp4HttpOptFileCheck setEnabled: YES]; -} - /* Method to determine if we should change the UI To reflect whether or not a Preset is being used or if the user is using "Custom" settings by determining the sender*/ @@ -3325,6 +4339,7 @@ the user is using "Custom" settings by determining the sender*/ curUserPresetChosenNum = nil; } +[self calculateBitrate:nil]; } @@ -3350,9 +4365,9 @@ the user is using "Custom" settings by determining the sender*/ to use the index itself but this is easier */ if (videoEncoder == HB_VCODEC_FFMPEG) { - if (job->pixel_ratio == 2) + if (job->anamorphic.mode == 2) { - job->pixel_ratio = 0; + job->anamorphic.mode = 0; } [fPictureController setAllowLooseAnamorphic:NO]; /* We set the iPod atom checkbox to disabled and uncheck it as its only for x264 in the mp4 @@ -3367,7 +4382,7 @@ the user is using "Custom" settings by determining the sender*/ [fPictureController setAllowLooseAnamorphic:YES]; [fDstMp4iPodFileCheck setEnabled: YES]; } - + [self setupQualitySlider]; [self calculatePictureSizing: sender]; [self twoPassCheckboxChanged: sender]; } @@ -3434,6 +4449,8 @@ the user is using "Custom" settings by determining the sender*/ [fVidTargetSizeField setEnabled: target]; [fVidBitrateField setEnabled: bitrate]; [fVidQualitySlider setEnabled: quality]; + [fVidQualityRFField setEnabled: quality]; + [fVidQualityRFLabel setEnabled: quality]; [fVidTwoPassCheck setEnabled: !quality && [fVidQualityMatrix isEnabled]]; if( quality ) @@ -3448,12 +4465,88 @@ the user is using "Custom" settings by determining the sender*/ [self customSettingUsed: sender]; } +/* Use this method to setup the quality slider for cq/rf values depending on + * the video encoder selected. + */ +- (void) setupQualitySlider +{ + /* Get the current slider maxValue to check for a change in slider scale later + * so that we can choose a new similar value on the new slider scale */ + float previousMaxValue = [fVidQualitySlider maxValue]; + float previousPercentOfSliderScale = [fVidQualitySlider floatValue] / ([fVidQualitySlider maxValue] - [fVidQualitySlider minValue] + 1); + NSString * qpRFLabelString = @"QP:"; + /* x264 0-51 */ + if ([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_X264) + { + [fVidQualitySlider setMinValue:0.0]; + [fVidQualitySlider setMaxValue:51.0]; + /* As x264 allows for qp/rf values that are fractional, we get the value from the preferences */ + int fractionalGranularity = 1 / [[NSUserDefaults standardUserDefaults] floatForKey:@"x264CqSliderFractional"]; + [fVidQualitySlider setNumberOfTickMarks:(([fVidQualitySlider maxValue] - [fVidQualitySlider minValue]) * fractionalGranularity) + 1]; + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultCrf"] > 0) + { + qpRFLabelString = @"RF:"; + } + } + /* ffmpeg 1-31 */ + if ([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_FFMPEG ) + { + [fVidQualitySlider setMinValue:1.0]; + [fVidQualitySlider setMaxValue:31.0]; + [fVidQualitySlider setNumberOfTickMarks:31]; + } + /* Theora 0-63 */ + if ([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_THEORA) + { + [fVidQualitySlider setMinValue:0.0]; + [fVidQualitySlider setMaxValue:63.0]; + [fVidQualitySlider setNumberOfTickMarks:64]; + } + [fVidQualityRFLabel setStringValue:qpRFLabelString]; + + /* check to see if we have changed slider scales */ + if (previousMaxValue != [fVidQualitySlider maxValue]) + { + /* if so, convert the old setting to the new scale as close as possible based on percentages */ + float rf = ([fVidQualitySlider maxValue] - [fVidQualitySlider minValue] + 1) * previousPercentOfSliderScale; + [fVidQualitySlider setFloatValue:rf]; + } + + [self qualitySliderChanged:nil]; +} + - (IBAction) qualitySliderChanged: (id) sender { + /* Our constant quality slider is in a range based + * on each encoders qp/rf values. The range depends + * on the encoder. Also, the range is inverse of quality + * for all of the encoders *except* for theora + * (ie. as the "quality" goes up, the cq or rf value + * actually goes down). Since the IB sliders always set + * their max value at the right end of the slider, we + * will calculate the inverse, so as the slider floatValue + * goes up, we will show the inverse in the rf field + * so, the floatValue at the right for x264 would be 51 + * and our rf field needs to show 0 and vice versa. + */ + + float sliderRfInverse = ([fVidQualitySlider maxValue] - [fVidQualitySlider floatValue]) + [fVidQualitySlider minValue]; + /* If the encoder is theora, use the float, otherwise use the inverse float*/ + float sliderRfToPercent; + if ([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_THEORA) + { + [fVidQualityRFField setStringValue: [NSString stringWithFormat: @"%.2f", [fVidQualitySlider floatValue]]]; + sliderRfToPercent = [fVidQualityRFField floatValue] / ([fVidQualitySlider maxValue] - [fVidQualitySlider minValue]); + } + else + { + [fVidQualityRFField setStringValue: [NSString stringWithFormat: @"%.2f", sliderRfInverse]]; + sliderRfToPercent = ( ([fVidQualitySlider maxValue] - [fVidQualitySlider minValue]) - ([fVidQualityRFField floatValue] - [fVidQualitySlider minValue])) / ([fVidQualitySlider maxValue] - [fVidQualitySlider minValue]); + } [fVidConstantCell setTitle: [NSString stringWithFormat: - NSLocalizedString( @"Constant quality: %.0f %%", @"" ), 100.0 * - [fVidQualitySlider floatValue]]]; - [self customSettingUsed: sender]; + NSLocalizedString( @"Constant quality: %.2f %%", @"" ), 100 * sliderRfToPercent]]; + + [self customSettingUsed: sender]; } - (void) controlTextDidChange: (NSNotification *) notification @@ -3472,9 +4565,98 @@ the user is using "Custom" settings by determining the sender*/ hb_title_t * title = (hb_title_t *) hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] ); hb_job_t * job = title->job; - - [fVidBitrateField setIntValue: hb_calc_bitrate( job, - [fVidTargetSizeField intValue] )]; + hb_audio_config_t * audio; + /* For hb_calc_bitrate in addition to the Target Size in MB out of the + * Target Size Field, we also need the job info for the Muxer, the Chapters + * as well as all of the audio track info. + * This used to be accomplished by simply calling prepareJob here, however + * since the resilient queue sets the queue array values instead of the job + * values directly, we duplicate the old prepareJob code here for the variables + * needed + */ + job->chapter_start = [fSrcChapterStartPopUp indexOfSelectedItem] + 1; + job->chapter_end = [fSrcChapterEndPopUp indexOfSelectedItem] + 1; + 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); + + } + +[fVidBitrateField setIntValue: hb_calc_bitrate( job, [fVidTargetSizeField intValue] )]; } #pragma mark - @@ -3487,18 +4669,9 @@ the user is using "Custom" settings by determining the sender*/ - (IBAction) revertPictureSizeToMax: (id) sender { hb_job_t * job = fTitle->job; - /* We use the output picture width and height - as calculated from libhb right after title is set - in TitlePopUpChanged */ - job->width = PicOrigOutputWidth; - job->height = PicOrigOutputHeight; - [fPictureController setAutoCrop:YES]; - /* Here we use the auto crop values determined right after scan */ - job->crop[0] = AutoCropTop; - job->crop[1] = AutoCropBottom; - job->crop[2] = AutoCropLeft; - job->crop[3] = AutoCropRight; - + /* Here we apply the title source and height */ + job->width = fTitle->width; + job->height = fTitle->height; [self calculatePictureSizing: sender]; /* We call method to change UI to reflect whether a preset is used or not*/ @@ -3509,156 +4682,123 @@ the user is using "Custom" settings by determining the sender*/ * Registers changes made in the Picture Settings Window. */ -- (void)pictureSettingsDidChange { +- (void)pictureSettingsDidChange +{ [self calculatePictureSizing:nil]; } /* Get and Display Current Pic Settings in main window */ - (IBAction) calculatePictureSizing: (id) sender { - [fPicSettingsOutp setStringValue: [NSString stringWithFormat:@"%d x %d", fTitle->job->width, fTitle->job->height]]; - - if (fTitle->job->pixel_ratio == 1) + if (fTitle->job->anamorphic.mode > 0) { - int titlewidth = fTitle->width-fTitle->job->crop[2]-fTitle->job->crop[3]; - int arpwidth = fTitle->job->pixel_aspect_width; - int arpheight = fTitle->job->pixel_aspect_height; - int displayparwidth = titlewidth * arpwidth / arpheight; - int displayparheight = fTitle->height-fTitle->job->crop[0]-fTitle->job->crop[1]; - [fPicSettingsOutp setStringValue: [NSString stringWithFormat:@"%d x %d", titlewidth, displayparheight]]; - [fPicSettingsAnamorphic setStringValue: [NSString stringWithFormat:@"%d x %d Strict", displayparwidth, displayparheight]]; fTitle->job->keep_ratio = 0; } - else if (fTitle->job->pixel_ratio == 2) - { - hb_job_t * job = fTitle->job; - int output_width, output_height, output_par_width, output_par_height; - hb_set_anamorphic_size(job, &output_width, &output_height, &output_par_width, &output_par_height); - int display_width; - display_width = output_width * output_par_width / output_par_height; - - [fPicSettingsOutp setStringValue: [NSString stringWithFormat:@"%d x %d", output_width, output_height]]; - [fPicSettingsAnamorphic setStringValue: [NSString stringWithFormat:@"%d x %d Loose", display_width, output_height]]; - - fTitle->job->keep_ratio = 0; - } - else - { - [fPicSettingsAnamorphic setStringValue:@"Off"]; - } - - /* Set ON/Off values for the deinterlace/keep aspect ratio according to boolean */ - if (fTitle->job->keep_ratio > 0) + + [fPictureSizeField setStringValue: [NSString stringWithFormat:@"Picture Size: %@", [fPictureController getPictureSizeInfoString]]]; + + NSString *picCropping; + /* Set the display field for crop as per boolean */ + if (![fPictureController autoCrop]) { - [fPicSettingARkeep setStringValue: @"On"]; + picCropping = @"Custom"; } else { - [fPicSettingARkeep setStringValue: @"Off"]; - } + picCropping = @"Auto"; + } + picCropping = [picCropping stringByAppendingString:[NSString stringWithFormat:@" %d/%d/%d/%d",fTitle->job->crop[0],fTitle->job->crop[1],fTitle->job->crop[2],fTitle->job->crop[3]]]; + + [fPictureCroppingField setStringValue: [NSString stringWithFormat:@"Picture Cropping: %@",picCropping]]; + NSString *videoFilters; + videoFilters = @""; /* Detelecine */ - if ([fPictureController detelecine]) { - [fPicSettingDetelecine setStringValue: @"Yes"]; + if ([fPictureController detelecine] == 1) + { + videoFilters = [videoFilters stringByAppendingString:@" - Detelecine (Default)"]; } - else { - [fPicSettingDetelecine setStringValue: @"No"]; + else if ([fPictureController detelecine] == 2) + { + videoFilters = [videoFilters stringByAppendingString:[NSString stringWithFormat:@" - Detelecine (%@)",[fPictureController detelecineCustomString]]]; } - /* Decomb */ - if ([fPictureController decomb] == 0) - { - [fPicSettingDecomb setStringValue: @"Off"]; - } - else if ([fPictureController decomb] == 1) - { - [fPicSettingDecomb setStringValue: @"1:2:6:9:80:16:16"]; - } - else if ([fPictureController decomb] == 2) + + if ([fPictureController useDecomb] == 1) { - [fPicSettingDecomb setStringValue:[[NSUserDefaults standardUserDefaults] stringForKey:@"DecombCustomString"]]; + /* Decomb */ + if ([fPictureController decomb] == 1) + { + videoFilters = [videoFilters stringByAppendingString:@" - Decomb (Default)"]; + } + else if ([fPictureController decomb] == 2) + { + videoFilters = [videoFilters stringByAppendingString:[NSString stringWithFormat:@" - Decomb (%@)",[fPictureController decombCustomString]]]; + } } - - /* VFR (Variable Frame Rate) */ - if ([fPictureController vfr]) { - /* We change the string of the fps popup to warn that vfr is on Framerate (FPS): */ - [fVidRateField setStringValue: @"Framerate (VFR On):"]; - /* for VFR we select same as source (or title framerate) and disable the popup. - * We know its index 0 as that is determined in titlePopUpChanged */ - [fVidRatePopUp selectItemAtIndex: 0]; - [fVidRatePopUp setEnabled: NO]; + else + { + /* Deinterlace */ + if ([fPictureController deinterlace] > 0) + { + fTitle->job->deinterlace = 1; + } + else + { + fTitle->job->deinterlace = 0; + } - } - else { - /* make sure the label for framerate is set to its default */ - [fVidRateField setStringValue: @"Framerate (FPS):"]; - [fVidRatePopUp setEnabled: YES]; - } - - /* Deinterlace */ - if ([fPictureController deinterlace] == 0) - { - [fPicSettingDeinterlace setStringValue: @"Off"]; - } - else if ([fPictureController deinterlace] == 1) - { - [fPicSettingDeinterlace setStringValue: @"Fast"]; - } - else if ([fPictureController deinterlace] == 2) - { - [fPicSettingDeinterlace setStringValue: @"Slow"]; - } - else if ([fPictureController deinterlace] == 3) - { - [fPicSettingDeinterlace setStringValue: @"Slower"]; + if ([fPictureController deinterlace] == 1) + { + videoFilters = [videoFilters stringByAppendingString:@" - Deinterlace (Fast)"]; + } + else if ([fPictureController deinterlace] == 2) + { + videoFilters = [videoFilters stringByAppendingString:@" - Deinterlace (Slow)"]; + } + else if ([fPictureController deinterlace] == 3) + { + videoFilters = [videoFilters stringByAppendingString:@" - Deinterlace (Slower)"]; + } + else if ([fPictureController deinterlace] == 4) + { + videoFilters = [videoFilters stringByAppendingString:[NSString stringWithFormat:@" - Deinterlace (%@)",[fPictureController deinterlaceCustomString]]]; + } } - + + /* Denoise */ - if ([fPictureController denoise] == 0) - { - [fPicSettingDenoise setStringValue: @"Off"]; - } - else if ([fPictureController denoise] == 1) + if ([fPictureController denoise] == 1) { - [fPicSettingDenoise setStringValue: @"Weak"]; - } + videoFilters = [videoFilters stringByAppendingString:@" - Denoise (Weak)"]; + } else if ([fPictureController denoise] == 2) { - [fPicSettingDenoise setStringValue: @"Medium"]; - } + videoFilters = [videoFilters stringByAppendingString:@" - Denoise (Medium)"]; + } else if ([fPictureController denoise] == 3) { - [fPicSettingDenoise setStringValue: @"Strong"]; + videoFilters = [videoFilters stringByAppendingString:@" - Denoise (Strong)"]; + } + else if ([fPictureController denoise] == 4) + { + videoFilters = [videoFilters stringByAppendingString:[NSString stringWithFormat:@" - Denoise (%@)",[fPictureController denoiseCustomString]]]; } /* Deblock */ - if ([fPictureController deblock]) { - [fPicSettingDeblock setStringValue: @"Yes"]; - } - else { - [fPicSettingDeblock setStringValue: @"No"]; + if ([fPictureController deblock] > 0) + { + videoFilters = [videoFilters stringByAppendingString:[NSString stringWithFormat:@" - Deblock (%d)",[fPictureController deblock]]]; } - if (fTitle->job->pixel_ratio > 0) - { - [fPicSettingPAR setStringValue: @""]; - } - else - { - [fPicSettingPAR setStringValue: @"Off"]; - } - - /* Set the display field for crop as per boolean */ - if (![fPictureController autoCrop]) - { - [fPicSettingAutoCrop setStringValue: @"Custom"]; - } - else - { - [fPicSettingAutoCrop setStringValue: @"Auto"]; - } - + /* Grayscale */ + if ([fPictureController grayscale]) + { + videoFilters = [videoFilters stringByAppendingString:@" - Grayscale"]; + } + [fVideoFiltersField setStringValue: [NSString stringWithFormat:@"Video Filters: %@", videoFilters]]; + //[fPictureController reloadStillPreview]; } @@ -3760,7 +4900,7 @@ the user is using "Custom" settings by determining the sender*/ [fAudTrack1DrcSlider setFloatValue: 1.00]; [self audioDRCSliderChanged: fAudTrack1DrcSlider]; } - else if ([[fAudTrack1MixPopUp selectedItem] tag] == HB_ACODEC_AC3) + else if ([[fAudTrack1MixPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[fAudTrack1MixPopUp selectedItem] tag] == HB_ACODEC_DCA) { [fAudTrack1RatePopUp setEnabled: NO]; [fAudTrack1BitratePopUp setEnabled: NO]; @@ -3784,7 +4924,7 @@ the user is using "Custom" settings by determining the sender*/ [fAudTrack2DrcSlider setFloatValue: 1.00]; [self audioDRCSliderChanged: fAudTrack2DrcSlider]; } - else if ([[fAudTrack2MixPopUp selectedItem] tag] == HB_ACODEC_AC3) + else if ([[fAudTrack2MixPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[fAudTrack2MixPopUp selectedItem] tag] == HB_ACODEC_DCA) { [fAudTrack2RatePopUp setEnabled: NO]; [fAudTrack2BitratePopUp setEnabled: NO]; @@ -3808,7 +4948,7 @@ the user is using "Custom" settings by determining the sender*/ [fAudTrack3DrcSlider setFloatValue: 1.00]; [self audioDRCSliderChanged: fAudTrack3DrcSlider]; } - else if ([[fAudTrack3MixPopUp selectedItem] tag] == HB_ACODEC_AC3) + else if ([[fAudTrack3MixPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[fAudTrack3MixPopUp selectedItem] tag] == HB_ACODEC_DCA) { [fAudTrack3RatePopUp setEnabled: NO]; [fAudTrack3BitratePopUp setEnabled: NO]; @@ -3832,7 +4972,7 @@ the user is using "Custom" settings by determining the sender*/ [fAudTrack4DrcSlider setFloatValue: 1.00]; [self audioDRCSliderChanged: fAudTrack4DrcSlider]; } - else if ([[fAudTrack4MixPopUp selectedItem] tag] == HB_ACODEC_AC3) + else if ([[fAudTrack4MixPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[fAudTrack4MixPopUp selectedItem] tag] == HB_ACODEC_DCA) { [fAudTrack4RatePopUp setEnabled: NO]; [fAudTrack4BitratePopUp setEnabled: NO]; @@ -3935,10 +5075,14 @@ the user is using "Custom" settings by determining the sender*/ { case 0: /* MP4 */ - // AAC + // FAAC menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (faac)" action: NULL keyEquivalent: @""]; [menuItem setTag: HB_ACODEC_FAAC]; - + + // CA_AAC + menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (CoreAudio)" action: NULL keyEquivalent: @""]; + [menuItem setTag: HB_ACODEC_CA_AAC]; + // AC3 Passthru menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AC3 Passthru" action: NULL keyEquivalent: @""]; [menuItem setTag: HB_ACODEC_AC3]; @@ -3946,12 +5090,18 @@ the user is using "Custom" settings by determining the sender*/ case 1: /* MKV */ - // AAC + // FAAC menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (faac)" action: NULL keyEquivalent: @""]; [menuItem setTag: HB_ACODEC_FAAC]; + // CA_AAC + menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (CoreAudio)" action: NULL keyEquivalent: @""]; + [menuItem setTag: HB_ACODEC_CA_AAC]; // 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]; @@ -4117,6 +5267,13 @@ the user is using "Custom" settings by determining the sender*/ 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 stringWithCString: "DTS Passthru"] + action: NULL keyEquivalent: @""]; + [menuItem setTag: HB_ACODEC_DCA]; + } else { @@ -4199,6 +5356,17 @@ the user is using "Custom" settings by determining the sender*/ 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 stringWithCString: 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 */ @@ -4247,6 +5415,24 @@ the user is using "Custom" settings by determining the sender*/ [audiocodecPopUp selectItemWithTag: HB_ACODEC_FAAC]; } } + + /* 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 MP3 for avi and aac for all + * other containers. + */ + if (audio->in.codec != HB_ACODEC_DCA && [[audiocodecPopUp selectedItem] tag] == HB_ACODEC_DCA) + { + /* If we are using the avi container, we select MP3 as there is no aac available*/ + if ([[fDstFormatPopUp selectedItem] tag] == HB_MUX_AVI) + { + [audiocodecPopUp selectItemWithTag: HB_ACODEC_LAME]; + } + else + { + [audiocodecPopUp selectItemWithTag: HB_ACODEC_FAAC]; + } + } + /* Setup our samplerate and bitrate popups we will need based on mixdown */ [self audioTrackMixdownChanged: mixdownPopUp]; } @@ -4255,7 +5441,6 @@ the user is using "Custom" settings by determining the sender*/ if( [fDstFormatPopUp indexOfSelectedItem] == 0 ) { [self autoSetM4vExtension: sender]; - [self shouldEnableHttpMp4CheckBox: sender]; } } @@ -4339,7 +5524,22 @@ the user is using "Custom" settings by determining the sender*/ 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; @@ -4380,7 +5580,7 @@ the user is using "Custom" settings by determining the sender*/ int inputbitrate = audio->in.bitrate / 1000; int inputsamplerate = audio->in.samplerate; - if ([[mixdownPopUp selectedItem] tag] != HB_ACODEC_AC3) + if ([[mixdownPopUp selectedItem] tag] != HB_ACODEC_AC3 && [[mixdownPopUp selectedItem] tag] != HB_ACODEC_DCA) { [bitratePopUp removeAllItems]; @@ -4428,11 +5628,11 @@ the user is using "Custom" settings by determining the sender*/ [sampleratePopUp selectItemWithTag: inputsamplerate]; - /* Since AC3 Pass Thru uses the input ac3 bitrate and sample rate, we get the input tracks - * bitrate and dispay it in the bitrate popup even though libhb happily ignores any bitrate input from + /* 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) + 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 */ @@ -4457,7 +5657,7 @@ the user is using "Custom" settings by determining the sender*/ [drcSlider setEnabled: YES]; [drcField setEnabled: YES]; } - +[self calculateBitrate:nil]; } - (IBAction) audioDRCSliderChanged: (id) sender @@ -4484,6 +5684,14 @@ the user is using "Custom" settings by determining the sender*/ 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 @@ -4491,22 +5699,51 @@ the user is using "Custom" settings by determining the sender*/ //[self customSettingUsed: sender]; } -- (IBAction) subtitleSelectionChanged: (id) sender +#pragma mark - + +- (IBAction) browseImportSrtFile: (id) sender { - if ([fSubPopUp indexOfSelectedItem] == 0) + + NSOpenPanel * panel; + + panel = [NSOpenPanel openPanel]; + [panel setAllowsMultipleSelection: NO]; + [panel setCanChooseFiles: YES]; + [panel setCanChooseDirectories: NO ]; + NSString * sourceDirectory; + if ([[NSUserDefaults standardUserDefaults] stringForKey:@"LastSrtImportDirectory"]) { - [fSubForcedCheck setState: NSOffState]; - [fSubForcedCheck setEnabled: NO]; + sourceDirectory = [[NSUserDefaults standardUserDefaults] stringForKey:@"LastSrtImportDirectory"]; } else { - [fSubForcedCheck setEnabled: YES]; + sourceDirectory = @"~/Desktop"; + sourceDirectory = [sourceDirectory stringByExpandingTildeInPath]; } - + /* we open up the browse srt sheet here and call for browseImportSrtFileDone after the sheet is closed */ + NSArray *fileTypes = [NSArray arrayWithObjects:@"plist", @"srt", nil]; + [panel beginSheetForDirectory: sourceDirectory file: nil types: fileTypes + modalForWindow: fWindow modalDelegate: self + didEndSelector: @selector( browseImportSrtFileDone:returnCode:contextInfo: ) + contextInfo: sender]; } - - +- (void) browseImportSrtFileDone: (NSSavePanel *) sheet + returnCode: (int) returnCode contextInfo: (void *) contextInfo +{ + if( returnCode == NSOKButton ) + { + NSString *importSrtDirectory = [[sheet filename] stringByDeletingLastPathComponent]; + NSString *importSrtFilePath = [sheet filename]; + [[NSUserDefaults standardUserDefaults] setObject:importSrtDirectory forKey:@"LastSrtImportDirectory"]; + + /* now pass the string off to fSubtitlesDelegate to add the srt file to the dropdown */ + [fSubtitlesDelegate createSubtitleSrtTrack:importSrtFilePath]; + + [fSubtitlesTable reloadData]; + + } +} #pragma mark - #pragma mark Open New Windows @@ -4567,45 +5804,134 @@ the user is using "Custom" settings by determining the sender*/ - (IBAction) showPicturePanel: (id) sender { - hb_list_t * list = hb_get_titles( fHandle ); - hb_title_t * title = (hb_title_t *) hb_list_item( list, - [fSrcTitlePopUp indexOfSelectedItem] ); - [fPictureController showPanelInWindow:fWindow forTitle:title]; + [fPictureController showPictureWindow:sender]; +} + +- (void) picturePanelFullScreen +{ + [fPictureController setToFullScreenMode]; +} + +- (void) picturePanelWindowed +{ + [fPictureController setToWindowedMode]; +} + +- (IBAction) showPreviewWindow: (id) sender +{ + [fPictureController showPreviewWindow:sender]; } #pragma mark - #pragma mark Preset Outline View Methods #pragma mark - Required /* These are required by the NSOutlineView Datasource Delegate */ + + +/* used to specify the number of levels to show for each item */ +- (int)outlineView:(NSOutlineView *)fPresetsOutlineView numberOfChildrenOfItem:(id)item +{ + /* currently use no levels to test outline view viability */ + if (item == nil) // for an outline view the root level of the hierarchy is always nil + { + return [UserPresets count]; + } + else + { + /* we need to return the count of the array in ChildrenArray for this folder */ + NSArray *children = nil; + children = [item objectForKey:@"ChildrenArray"]; + if ([children count] > 0) + { + return [children count]; + } + else + { + return 0; + } + } +} + /* We use this to deterimine children of an item */ - (id)outlineView:(NSOutlineView *)fPresetsOutlineView child:(NSInteger)index ofItem:(id)item { -if (item == nil) - return [UserPresets objectAtIndex:index]; + + /* we need to return the count of the array in ChildrenArray for this folder */ + NSArray *children = nil; + if (item == nil) + { + children = UserPresets; + } + else + { + if ([item objectForKey:@"ChildrenArray"]) + { + children = [item objectForKey:@"ChildrenArray"]; + } + } + if ((children == nil) || ( [children count] <= (NSUInteger) index)) + { + return nil; + } + else + { + return [children objectAtIndex:index]; + } + // We are only one level deep, so we can't be asked about children - NSAssert (NO, @"Presets View outlineView:child:ofItem: currently can't handle nested items."); - return nil; + //NSAssert (NO, @"Presets View outlineView:child:ofItem: currently can't handle nested items."); + //return nil; } + /* We use this to determine if an item should be expandable */ - (BOOL)outlineView:(NSOutlineView *)fPresetsOutlineView isItemExpandable:(id)item { - - /* For now, we maintain one level, so set to no - * when nested, we set to yes for any preset "folders" - */ - return NO; - -} -/* used to specify the number of levels to show for each item */ -- (int)outlineView:(NSOutlineView *)fPresetsOutlineView numberOfChildrenOfItem:(id)item -{ - /* currently use no levels to test outline view viability */ + + /* we need to return the count of the array in ChildrenArray for this folder */ + NSArray *children= nil; if (item == nil) - return [UserPresets count]; + { + children = UserPresets; + } + else + { + if ([item objectForKey:@"ChildrenArray"]) + { + children = [item objectForKey:@"ChildrenArray"]; + } + } + + /* To deterimine if an item should show a disclosure triangle + * we could do it by the children count as so: + * if ([children count] < 1) + * However, lets leave the triangle show even if there are no + * children to help indicate a folder, just like folder in the + * finder can show a disclosure triangle even when empty + */ + + /* We need to determine if the item is a folder */ + if ([[item objectForKey:@"Folder"] intValue] == 1) + { + return YES; + } else - return 0; + { + return NO; + } + +} + +- (BOOL)outlineView:(NSOutlineView *)outlineView shouldExpandItem:(id)item +{ + // Our outline view has no levels, but we can still expand every item. Doing so + // just makes the row taller. See heightOfRowByItem below. +//return ![(HBQueueOutlineView*)outlineView isDragging]; + +return YES; } + + /* Used to tell the outline view which information is to be displayed per item */ - (id)outlineView:(NSOutlineView *)fPresetsOutlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item { @@ -4617,17 +5943,26 @@ if (item == nil) } else { - return @"something"; + //return @""; + return nil; } } +- (id)outlineView:(NSOutlineView *)outlineView itemForPersistentObject:(id)object +{ + return [NSKeyedUnarchiver unarchiveObjectWithData:object]; +} +- (id)outlineView:(NSOutlineView *)outlineView persistentObjectForItem:(id)item +{ + return [NSKeyedArchiver archivedDataWithRootObject:item]; +} + #pragma mark - Added Functionality (optional) /* Use to customize the font and display characteristics of the title cell */ - (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item { if ([[tableColumn identifier] isEqualToString:@"PresetName"]) { - NSDictionary *userPresetDict = item; NSFont *txtFont; NSColor *fontColor; NSColor *shadowColor; @@ -4641,7 +5976,7 @@ if (item == nil) } else { - if ([[userPresetDict objectForKey:@"Type"] intValue] == 0) + if ([[item objectForKey:@"Type"] intValue] == 0) { fontColor = [NSColor blueColor]; } @@ -4649,15 +5984,21 @@ if (item == nil) { fontColor = [NSColor blackColor]; } - shadowColor = nil; + /* check to see if its a folder */ + //if ([[item objectForKey:@"Folder"] intValue] == 1) + //{ + //fontColor = [NSColor greenColor]; + //} + + } /* We use Bold Text for the HB Default */ - if ([[userPresetDict objectForKey:@"Default"] intValue] == 1)// 1 is HB default + if ([[item objectForKey:@"Default"] intValue] == 1)// 1 is HB default { txtFont = [NSFont boldSystemFontOfSize: [NSFont smallSystemFontSize]]; } /* We use Bold Text for the User Specified Default */ - if ([[userPresetDict objectForKey:@"Default"] intValue] == 2)// 2 is User default + if ([[item objectForKey:@"Default"] intValue] == 2)// 2 is User default { txtFont = [NSFont boldSystemFontOfSize: [NSFont smallSystemFontSize]]; } @@ -4714,7 +6055,8 @@ if (item == nil) - (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard { // Dragging is only allowed for custom presets. - if ([[[UserPresets objectAtIndex:[fPresetsOutlineView selectedRow]] objectForKey:@"Type"] intValue] == 0) // 0 is built in preset + //[[[fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]] objectForKey:@"Default"] intValue] != 1 + if ([[[fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]] objectForKey:@"Type"] intValue] == 0) // 0 is built in preset { return NO; } @@ -4730,18 +6072,17 @@ if (item == nil) return YES; } -- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id )info proposedItem:(id)item proposedChildIndex:(int)index +- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id )info proposedItem:(id)item proposedChildIndex:(NSInteger)index { + // Don't allow dropping ONTO an item since they can't really contain any children. BOOL isOnDropTypeProposal = index == NSOutlineViewDropOnItemIndex; if (isOnDropTypeProposal) return NSDragOperationNone; - - // Don't allow dropping INTO an item since they can't really contain any children as of yet. - - if (item != nil) + // Don't allow dropping INTO an item since they can't really contain any children as of yet. + if (item != nil) { index = [fPresetsOutlineView rowForItem: item] + 1; item = nil; @@ -4752,7 +6093,7 @@ if (item == nil) { return NSDragOperationNone; index = MAX (index, presetCurrentBuiltInCount); - } + } [outlineView setDropItem:item dropChildIndex:index]; return NSDragOperationGeneric; @@ -4760,50 +6101,58 @@ if (item == nil) -- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id )info item:(id)item childIndex:(int)index +- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id )info item:(id)item childIndex:(NSInteger)index { - NSMutableIndexSet *moveItems = [NSMutableIndexSet indexSet]; - - id obj; - NSEnumerator *enumerator = [fDraggedNodes objectEnumerator]; - while (obj = [enumerator nextObject]) - { - [moveItems addIndex:[UserPresets indexOfObject:obj]]; + /* first, lets see if we are dropping into a folder */ + if ([[fPresetsOutlineView itemAtRow:index] objectForKey:@"Folder"] && [[[fPresetsOutlineView itemAtRow:index] objectForKey:@"Folder"] intValue] == 1) // if its a folder + { + NSMutableArray *childrenArray = [[NSMutableArray alloc] init]; + childrenArray = [[fPresetsOutlineView itemAtRow:index] objectForKey:@"ChildrenArray"]; + [childrenArray addObject:item]; + [[fPresetsOutlineView itemAtRow:index] setObject:[NSMutableArray arrayWithArray: childrenArray] forKey:@"ChildrenArray"]; + [childrenArray autorelease]; + } + else // We are not, so we just move the preset into the existing array + { + NSMutableIndexSet *moveItems = [NSMutableIndexSet indexSet]; + id obj; + NSEnumerator *enumerator = [fDraggedNodes objectEnumerator]; + while (obj = [enumerator nextObject]) + { + [moveItems addIndex:[UserPresets indexOfObject:obj]]; + } + // Successful drop, lets rearrange the view and save it all + [self moveObjectsInPresetsArray:UserPresets fromIndexes:moveItems toIndex: index]; } - // Successful drop, lets rearrange the view and save it all - [self moveObjectsInPresetsArray:UserPresets fromIndexes:moveItems toIndex: index]; [fPresetsOutlineView reloadData]; [self savePreset]; return YES; } -- (void)moveObjectsInPresetsArray:(NSMutableArray *)array fromIndexes:(NSIndexSet *)indexSet toIndex:(unsigned)insertIndex +- (void)moveObjectsInPresetsArray:(NSMutableArray *)array fromIndexes:(NSIndexSet *)indexSet toIndex:(NSUInteger)insertIndex { - unsigned index = [indexSet lastIndex]; - unsigned aboveInsertIndexCount = 0; + NSUInteger index = [indexSet lastIndex]; + NSUInteger aboveInsertIndexCount = 0; - while (index != NSNotFound) + NSUInteger removeIndex; + + if (index >= insertIndex) { - unsigned removeIndex; - - if (index >= insertIndex) - { - removeIndex = index + aboveInsertIndexCount; - aboveInsertIndexCount++; - } - else - { - removeIndex = index; - insertIndex--; - } - - id object = [[array objectAtIndex:removeIndex] retain]; - [array removeObjectAtIndex:removeIndex]; - [array insertObject:object atIndex:insertIndex]; - [object release]; - - index = [indexSet indexLessThanIndex:index]; + removeIndex = index + aboveInsertIndexCount; + aboveInsertIndexCount++; + } + else + { + removeIndex = index; + insertIndex--; } + + id object = [[array objectAtIndex:removeIndex] retain]; + [array removeObjectAtIndex:removeIndex]; + [array insertObject:object atIndex:insertIndex]; + [object release]; + + index = [indexSet indexLessThanIndex:index]; } @@ -4812,12 +6161,12 @@ if (item == nil) - (IBAction)selectPreset:(id)sender { - - if ([fPresetsOutlineView selectedRow] >= 0) + + if ([fPresetsOutlineView selectedRow] >= 0 && [[[fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]] objectForKey:@"Folder"] intValue] != 1) { chosenPreset = [fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]]; - /* we set the preset display field in main window here */ [fPresetSelectedDisplay setStringValue:[chosenPreset objectForKey:@"PresetName"]]; + if ([[chosenPreset objectForKey:@"Default"] intValue] == 1) { [fPresetSelectedDisplay setStringValue:[NSString stringWithFormat:@"%@ (Default)", [chosenPreset objectForKey:@"PresetName"]]]; @@ -4826,67 +6175,66 @@ if (item == nil) { [fPresetSelectedDisplay setStringValue:[chosenPreset objectForKey:@"PresetName"]]; } + /* File Format */ [fDstFormatPopUp selectItemWithTitle:[chosenPreset objectForKey:@"FileFormat"]]; [self formatPopUpChanged:nil]; - + /* Chapter Markers*/ [fCreateChapterMarkers setState:[[chosenPreset objectForKey:@"ChapterMarkers"] intValue]]; + /* check to see if we have only one chapter */ + [self chapterPopUpChanged:nil]; + /* Allow Mpeg4 64 bit formatting +4GB file sizes */ [fDstMp4LargeFileCheck setState:[[chosenPreset objectForKey:@"Mp4LargeFile"] intValue]]; /* Mux mp4 with http optimization */ [fDstMp4HttpOptFileCheck setState:[[chosenPreset objectForKey:@"Mp4HttpOptimize"] intValue]]; - + /* Video encoder */ + [fVidEncoderPopUp selectItemWithTitle:[chosenPreset objectForKey:@"VideoEncoder"]]; /* We set the advanced opt string here if applicable*/ [fAdvancedOptions setOptions:[chosenPreset objectForKey:@"x264Option"]]; - /* We use a conditional to account for the new x264 encoder dropdown as well as presets made using legacy x264 settings*/ - if ([[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"x264 (h.264 Main)"] || - [[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"x264 (h.264 iPod)"] || - [[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"x264"]) - { - [fVidEncoderPopUp selectItemWithTitle:@"H.264 (x264)"]; - /* special case for legacy preset to check the new fDstMp4HttpOptFileCheck checkbox to set the ipod atom */ - if ([[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"x264 (h.264 iPod)"]) - { - [fDstMp4iPodFileCheck setState:NSOnState]; - /* We also need to add "level=30:" to the advanced opts string to set the correct level for the iPod when - encountering a legacy preset as it used to be handled separately from the opt string*/ - [fAdvancedOptions setOptions:[@"level=30:" stringByAppendingString:[fAdvancedOptions optionsString]]]; - } - else - { - [fDstMp4iPodFileCheck setState:NSOffState]; - } - } - else if ([[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"FFmpeg"]) - { - [fVidEncoderPopUp selectItemWithTitle:@"MPEG-4 (FFmpeg)"]; - } - else if ([[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"XviD"]) - { - [fVidEncoderPopUp selectItemWithTitle:@"MPEG-4 (XviD)"]; - } - else - { - [fVidEncoderPopUp selectItemWithTitle:[chosenPreset objectForKey:@"VideoEncoder"]]; - } - + /* Lets run through the following functions to get variables set there */ [self videoEncoderPopUpChanged:nil]; /* Set the state of ipod compatible with Mp4iPodCompatible. Only for x264*/ [fDstMp4iPodFileCheck setState:[[chosenPreset objectForKey:@"Mp4iPodCompatible"] intValue]]; [self calculateBitrate:nil]; - + /* Video quality */ [fVidQualityMatrix selectCellAtRow:[[chosenPreset objectForKey:@"VideoQualityType"] intValue] column:0]; - + [fVidTargetSizeField setStringValue:[chosenPreset objectForKey:@"VideoTargetSize"]]; [fVidBitrateField setStringValue:[chosenPreset objectForKey:@"VideoAvgBitrate"]]; - [fVidQualitySlider setFloatValue:[[chosenPreset objectForKey:@"VideoQualitySlider"] floatValue]]; - + + /* Since we are now using RF Values for the slider, we detect if the preset uses an old quality float. + * So, check to see if the quality value is less than 1.0 which should indicate the old ".062" type + * quality preset. Caveat: in the case of x264, where the RF scale starts at 0, it would misinterpret + * a preset that uses 0.0 - 0.99 for RF as an old style preset. Not sure how to get around that one yet, + * though it should be a corner case since it would pretty much be a preset for lossless encoding. */ + if ([[chosenPreset objectForKey:@"VideoQualitySlider"] floatValue] < 1.0) + { + /* For the quality slider we need to convert the old percent's to the new rf scales */ + float rf = (([fVidQualitySlider maxValue] - [fVidQualitySlider minValue]) * [[chosenPreset objectForKey:@"VideoQualitySlider"] floatValue]); + [fVidQualitySlider setFloatValue:rf]; + + } + else + { + /* Since theora's qp value goes up from left to right, we can just set the slider float value */ + if ([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_THEORA) + { + [fVidQualitySlider setFloatValue:[[chosenPreset objectForKey:@"VideoQualitySlider"] floatValue]]; + } + else + { + /* since ffmpeg and x264 use an "inverted" slider (lower qp/rf values indicate a higher quality) we invert the value on the slider */ + [fVidQualitySlider setFloatValue:([fVidQualitySlider maxValue] + [fVidQualitySlider minValue]) - [[chosenPreset objectForKey:@"VideoQualitySlider"] floatValue]]; + } + } + [self videoMatrixChanged:nil]; - + /* 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*/ @@ -4898,184 +6246,117 @@ if (item == nil) { [fVidRatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"VideoFramerate"]]; } - - /* GrayScale */ - [fVidGrayscaleCheck setState:[[chosenPreset objectForKey:@"VideoGrayScale"] intValue]]; - + + /* 2 Pass Encoding */ [fVidTwoPassCheck setState:[[chosenPreset objectForKey:@"VideoTwoPass"] intValue]]; [self twoPassCheckboxChanged:nil]; + /* Turbo 1st pass for 2 Pass Encoding */ [fVidTurboPassCheck setState:[[chosenPreset objectForKey:@"VideoTurboTwoPass"] intValue]]; - + /*Audio*/ - if ([chosenPreset objectForKey:@"FileCodecs"]) + /* First we check to see if we are using the current audio track layout based on AudioList array */ + if ([chosenPreset objectForKey:@"AudioList"]) { - /* We need to handle the audio codec popup by determining what was chosen from the deprecated Codecs PopUp for past presets*/ - if ([[chosenPreset objectForKey:@"FileCodecs"] isEqualToString: @"AVC/H.264 Video / AAC + AC3 Audio"]) + /* 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]) { - /* We need to address setting languages etc. here in the new multi track audio panel */ - /* Track One set here */ - /*for track one though a track should be selected but lets check here anyway and use track one if its not.*/ - if ([fAudLang1PopUp indexOfSelectedItem] == 0) + i++; + if( i == 1 ) { - [fAudLang1PopUp selectItemAtIndex: 1]; + if ([fAudLang1PopUp indexOfSelectedItem] == 0) + { + [fAudLang1PopUp selectItemAtIndex: 1]; + } [self audioTrackPopUpChanged: fAudLang1PopUp]; - } - [fAudTrack1CodecPopUp selectItemWithTitle: @"AAC (faac)"]; - [self audioTrackPopUpChanged: fAudTrack1CodecPopUp]; - /* Track Two, set source same as track one */ - [fAudLang2PopUp selectItemAtIndex: [fAudLang1PopUp indexOfSelectedItem]]; - [self audioTrackPopUpChanged: fAudLang2PopUp]; - [fAudTrack2CodecPopUp selectItemWithTitle: @"AC3 Passthru"]; - [self audioTrackPopUpChanged: fAudTrack2CodecPopUp]; - } - else if ([[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"MPEG-4 Video / AAC Audio"] || - [[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"AVC/H.264 Video / AAC Audio"]) - { - if ([fAudLang1PopUp indexOfSelectedItem] > 0) - { - [fAudTrack1CodecPopUp selectItemWithTitle: @"AAC (faac)"]; - [self audioTrackPopUpChanged: fAudTrack1CodecPopUp]; - } - if ([fAudLang2PopUp indexOfSelectedItem] > 0) - { - [fAudTrack2CodecPopUp selectItemWithTitle: @"AAC (faac)"]; - [self audioTrackPopUpChanged: fAudTrack2CodecPopUp]; - } - if ([fAudLang3PopUp indexOfSelectedItem] > 0) - { - [fAudTrack3CodecPopUp selectItemWithTitle: @"AAC (faac)"]; - [self audioTrackPopUpChanged: fAudTrack3CodecPopUp]; - } - if ([fAudLang4PopUp indexOfSelectedItem] > 0) - { - [fAudTrack4CodecPopUp selectItemWithTitle: @"AAC (faac)"]; - [self audioTrackPopUpChanged: fAudTrack4CodecPopUp]; - } - } - else if ([[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"MPEG-4 Video / AC-3 Audio"] || - [[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"AVC/H.264 Video / AC-3 Audio"]) - { - if ([fAudLang1PopUp indexOfSelectedItem] > 0) - { - [fAudTrack1CodecPopUp selectItemWithTitle: @"AC3 Passthru"]; - [self audioTrackPopUpChanged: fAudTrack1CodecPopUp]; - } - if ([fAudLang2PopUp indexOfSelectedItem] > 0) - { - [fAudTrack2CodecPopUp selectItemWithTitle: @"AC3 Passthru"]; - [self audioTrackPopUpChanged: fAudTrack2CodecPopUp]; - } - if ([fAudLang3PopUp indexOfSelectedItem] > 0) - { - [fAudTrack3CodecPopUp selectItemWithTitle: @"AC3 Passthru"]; - [self audioTrackPopUpChanged: fAudTrack3CodecPopUp]; - } - if ([fAudLang4PopUp indexOfSelectedItem] > 0) - { - [fAudTrack4CodecPopUp selectItemWithTitle: @"AC3 Passthru"]; - [self audioTrackPopUpChanged: fAudTrack4CodecPopUp]; - } - } - else if ([[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"MPEG-4 Video / MP3 Audio"] || - [[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"AVC/H.264 Video / MP3 Audio"]) - { - if ([fAudLang1PopUp indexOfSelectedItem] > 0) - { - [fAudTrack1CodecPopUp selectItemWithTitle: @"MP3 (lame)"]; - [self audioTrackPopUpChanged: fAudTrack1CodecPopUp]; - } - if ([fAudLang2PopUp indexOfSelectedItem] > 0) - { - [fAudTrack2CodecPopUp selectItemWithTitle: @"MP3 (lame)"]; - [self audioTrackPopUpChanged: fAudTrack2CodecPopUp]; - } - if ([fAudLang3PopUp indexOfSelectedItem] > 0) - { - [fAudTrack3CodecPopUp selectItemWithTitle: @"MP3 (lame)"]; - [self audioTrackPopUpChanged: fAudTrack3CodecPopUp]; - } - if ([fAudLang4PopUp indexOfSelectedItem] > 0) - { - [fAudTrack4CodecPopUp selectItemWithTitle: @"MP3 (lame)"]; - [self audioTrackPopUpChanged: fAudTrack4CodecPopUp]; - } - } - else if ([[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"MPEG-4 Video / Vorbis Audio"]) - { - if ([fAudLang1PopUp indexOfSelectedItem] > 0) - { - [fAudTrack1CodecPopUp selectItemWithTitle: @"Vorbis (vorbis)"]; + [fAudTrack1CodecPopUp selectItemWithTitle:[tempObject objectForKey:@"AudioEncoder"]]; + /* check our pref for core audio and use it in place of faac if applicable */ + if ([[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && + [[tempObject objectForKey:@"AudioEncoder"] isEqualToString: @"AAC (faac)"]) + { + [fAudTrack1CodecPopUp selectItemWithTitle:@"AAC (CoreAudio)"]; + } + [self audioTrackPopUpChanged: fAudTrack1CodecPopUp]; + [fAudTrack1MixPopUp selectItemWithTitle:[tempObject objectForKey:@"AudioMixdown"]]; + /* 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:[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"]) + { + [fAudTrack1BitratePopUp selectItemWithTitle:[tempObject objectForKey:@"AudioBitrate"]]; + } + [fAudTrack1DrcSlider setFloatValue:[[tempObject objectForKey:@"AudioTrackDRCSlider"] floatValue]]; + [self audioDRCSliderChanged: fAudTrack1DrcSlider]; } - if ([fAudLang2PopUp indexOfSelectedItem] > 0) + + if( i == 2 ) { - [fAudTrack2CodecPopUp selectItemWithTitle: @"Vorbis (vorbis)"]; + + if ([fAudLang2PopUp indexOfSelectedItem] == 0) + { + [fAudLang2PopUp selectItemAtIndex: 1]; + } + [self audioTrackPopUpChanged: fAudLang2PopUp]; + [fAudTrack2CodecPopUp selectItemWithTitle:[tempObject objectForKey:@"AudioEncoder"]]; + /* check our pref for core audio and use it in place of faac if applicable */ + if ([[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && + [[tempObject objectForKey:@"AudioEncoder"] isEqualToString: @"AAC (faac)"]) + { + [fAudTrack2CodecPopUp selectItemWithTitle:@"AAC (CoreAudio)"]; + } [self audioTrackPopUpChanged: fAudTrack2CodecPopUp]; + [fAudTrack2MixPopUp selectItemWithTitle:[tempObject objectForKey:@"AudioMixdown"]]; + /* 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:[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"]) + { + [fAudTrack2BitratePopUp selectItemWithTitle:[tempObject objectForKey:@"AudioBitrate"]]; + } + [fAudTrack2DrcSlider setFloatValue:[[tempObject objectForKey:@"AudioTrackDRCSlider"] floatValue]]; + [self audioDRCSliderChanged: fAudTrack2DrcSlider]; + } - if ([fAudLang3PopUp indexOfSelectedItem] > 0) - { - [fAudTrack3CodecPopUp selectItemWithTitle: @"Vorbis (vorbis)"]; - [self audioTrackPopUpChanged: fAudTrack3CodecPopUp]; - } - if ([fAudLang4PopUp indexOfSelectedItem] > 0) - { - [fAudTrack4CodecPopUp selectItemWithTitle: @"Vorbis (vorbis)"]; - [self audioTrackPopUpChanged: fAudTrack4CodecPopUp]; - } - } - /* We detect here if we have the old audio sample rate and if so we apply samplerate and bitrate to the existing four tracks if chosen - * UNLESS the CodecPopUp is AC3 in which case the preset values are ignored in favor of rates set in audioTrackMixdownChanged*/ - if ([chosenPreset objectForKey:@"AudioSampleRate"]) - { - if ([fAudLang1PopUp indexOfSelectedItem] > 0 && [fAudTrack1CodecPopUp titleOfSelectedItem] != @"AC3 Passthru") - { - [fAudTrack1RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioSampleRate"]]; - [fAudTrack1BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioBitRate"]]; - } - if ([fAudLang2PopUp indexOfSelectedItem] > 0 && [fAudTrack2CodecPopUp titleOfSelectedItem] != @"AC3 Passthru") - { - [fAudTrack2RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioSampleRate"]]; - [fAudTrack2BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioBitRate"]]; - } - if ([fAudLang3PopUp indexOfSelectedItem] > 0 && [fAudTrack3CodecPopUp titleOfSelectedItem] != @"AC3 Passthru") - { - [fAudTrack3RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioSampleRate"]]; - [fAudTrack3BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioBitRate"]]; - } - if ([fAudLang4PopUp indexOfSelectedItem] > 0 && [fAudTrack4CodecPopUp titleOfSelectedItem] != @"AC3 Passthru") - { - [fAudTrack4RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioSampleRate"]]; - [fAudTrack4BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioBitRate"]]; - } + } - /* We detect here if we have the old DRC Slider and if so we apply it to the existing four tracks if chosen */ - if ([chosenPreset objectForKey:@"AudioDRCSlider"]) + + /* We now cleanup any extra audio tracks that may have been previously set if we need to */ + + if (i < 4) { - if ([fAudLang1PopUp indexOfSelectedItem] > 0) - { - [fAudTrack1DrcSlider setFloatValue:[[chosenPreset objectForKey:@"AudioDRCSlider"] floatValue]]; - [self audioDRCSliderChanged: fAudTrack1DrcSlider]; - } - if ([fAudLang2PopUp indexOfSelectedItem] > 0) - { - [fAudTrack2DrcSlider setFloatValue:[[chosenPreset objectForKey:@"AudioDRCSlider"] floatValue]]; - [self audioDRCSliderChanged: fAudTrack2DrcSlider]; - } - if ([fAudLang3PopUp indexOfSelectedItem] > 0) - { - [fAudTrack3DrcSlider setFloatValue:[[chosenPreset objectForKey:@"AudioDRCSlider"] floatValue]]; - [self audioDRCSliderChanged: fAudTrack3DrcSlider]; - } - if ([fAudLang4PopUp indexOfSelectedItem] > 0) + [fAudLang4PopUp selectItemAtIndex: 0]; + [self audioTrackPopUpChanged: fAudLang4PopUp]; + + if (i < 3) { - [fAudTrack4DrcSlider setFloatValue:[[chosenPreset objectForKey:@"AudioDRCSlider"] floatValue]]; - [self audioDRCSliderChanged: fAudTrack4DrcSlider]; + [fAudLang3PopUp selectItemAtIndex: 0]; + [self audioTrackPopUpChanged: fAudLang3PopUp]; + + if (i < 2) + { + [fAudLang2PopUp selectItemAtIndex: 0]; + [self audioTrackPopUpChanged: fAudLang2PopUp]; + } } } + } - else // since there was no codecs key in the preset we know we can use new multi-audio track presets + else { if ([chosenPreset objectForKey:@"Audio1Track"] > 0) { @@ -5085,6 +6366,12 @@ if (item == nil) } [self audioTrackPopUpChanged: fAudLang1PopUp]; [fAudTrack1CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Encoder"]]; + /* check our pref for core audio and use it in place of faac if applicable */ + if ([[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 @@ -5110,6 +6397,12 @@ if (item == nil) } [self audioTrackPopUpChanged: fAudLang2PopUp]; [fAudTrack2CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio2Encoder"]]; + /* check our pref for core audio and use it in place of faac if applicable */ + if ([[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 @@ -5135,6 +6428,12 @@ if (item == nil) } [self audioTrackPopUpChanged: fAudLang3PopUp]; [fAudTrack3CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio3Encoder"]]; + /* check our pref for core audio and use it in place of faac if applicable */ + if ([[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 @@ -5160,6 +6459,12 @@ if (item == nil) } [self audioTrackPopUpChanged: fAudLang4PopUp]; [fAudTrack4CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio4Encoder"]]; + /* check our pref for core audio and use it in place of faac if applicable */ + if ([[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 @@ -5177,22 +6482,9 @@ if (item == nil) [fAudTrack4DrcSlider setFloatValue:[[chosenPreset objectForKey:@"Audio4TrackDRCSlider"] floatValue]]; [self audioDRCSliderChanged: fAudTrack4DrcSlider]; } - - - } - - /* We now cleanup any extra audio tracks that may be previously set if we need to, we do it here so we don't have to - * duplicate any code for legacy presets.*/ - /* First we handle the legacy Codecs crazy AVC/H.264 Video / AAC + AC3 Audio atv hybrid */ - if ([chosenPreset objectForKey:@"FileCodecs"] && [[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"AVC/H.264 Video / AAC + AC3 Audio"]) - { - [fAudLang3PopUp selectItemAtIndex: 0]; - [self audioTrackPopUpChanged: fAudLang3PopUp]; - [fAudLang4PopUp selectItemAtIndex: 0]; - [self audioTrackPopUpChanged: fAudLang4PopUp]; - } - else - { + + /* 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]; @@ -5209,25 +6501,50 @@ if (item == nil) [self audioTrackPopUpChanged: fAudLang4PopUp]; } } - + /*Subtitles*/ [fSubPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Subtitles"]]; /* Forced Subtitles */ [fSubForcedCheck setState:[[chosenPreset objectForKey:@"SubtitlesForced"] intValue]]; - + /* Picture Settings */ - /* Note: objectForKey:@"UsesPictureSettings" now refers to picture size, this encompasses: + /* Note: objectForKey:@"UsesPictureSettings" refers to picture size, which encompasses: * height, width, keep ar, anamorphic and crop settings. - * picture filters are now handled separately. - * We will be able to actually change the key names for legacy preset keys when preset file - * update code is done. But for now, lets hang onto the old legacy key name for backwards compatibility. + * picture filters are handled separately below. */ /* Check to see if the objectForKey:@"UsesPictureSettings is greater than 0, as 0 means use picture sizing "None" - * and the preset completely ignores any picture sizing values in the preset. + * ( 2 is use max for source and 1 is use exact size when the preset was created ) and the + * preset completely ignores any picture sizing values in the preset. */ if ([[chosenPreset objectForKey:@"UsesPictureSettings"] intValue] > 0) { hb_job_t * job = fTitle->job; + + /* If Cropping is set to custom, then recall all four crop values from + when the preset was created and apply them */ + if ([[chosenPreset objectForKey:@"PictureAutoCrop"] intValue] == 0) + { + [fPictureController setAutoCrop:NO]; + + /* Here we use the custom crop values saved at the time the preset was saved */ + job->crop[0] = [[chosenPreset objectForKey:@"PictureTopCrop"] intValue]; + job->crop[1] = [[chosenPreset objectForKey:@"PictureBottomCrop"] intValue]; + job->crop[2] = [[chosenPreset objectForKey:@"PictureLeftCrop"] intValue]; + job->crop[3] = [[chosenPreset objectForKey:@"PictureRightCrop"] intValue]; + + } + else /* if auto crop has been saved in preset, set to auto and use post scan auto crop */ + { + [fPictureController setAutoCrop:YES]; + /* Here we use the auto crop values determined right after scan */ + job->crop[0] = AutoCropTop; + job->crop[1] = AutoCropBottom; + job->crop[2] = AutoCropLeft; + job->crop[3] = AutoCropRight; + + } + + /* Check to see if the objectForKey:@"UsesPictureSettings is 2 which is "Use Max for the source */ if ([[chosenPreset objectForKey:@"UsesPictureSettings"] intValue] == 2 || [[chosenPreset objectForKey:@"UsesMaxPictureSettings"] intValue] == 1) { @@ -5243,7 +6560,7 @@ if (item == nil) hb_fix_aspect( job, HB_KEEP_HEIGHT ); } } - job->pixel_ratio = [[chosenPreset objectForKey:@"PicturePAR"] intValue]; + job->anamorphic.mode = [[chosenPreset objectForKey:@"PicturePAR"] intValue]; } else // /* If not 0 or 2 we assume objectForKey:@"UsesPictureSettings is 1 which is "Use picture sizing from when the preset was set" */ { @@ -5251,8 +6568,9 @@ if (item == nil) if (fTitle->width < [[chosenPreset objectForKey:@"PictureWidth"] intValue] || fTitle->height < [[chosenPreset objectForKey:@"PictureHeight"] intValue]) { /* if so, then we use the sources height and width to avoid scaling up */ - job->width = fTitle->width; - job->height = fTitle->height; + //job->width = fTitle->width; + //job->height = fTitle->height; + [self revertPictureSizeToMax:nil]; } else // source width/height is >= the preset height/width { @@ -5270,175 +6588,111 @@ if (item == nil) hb_fix_aspect( job, HB_KEEP_HEIGHT ); } } - job->pixel_ratio = [[chosenPreset objectForKey:@"PicturePAR"] intValue]; - + job->anamorphic.mode = [[chosenPreset objectForKey:@"PicturePAR"] intValue]; - /* If Cropping is set to custom, then recall all four crop values from - when the preset was created and apply them */ - if ([[chosenPreset objectForKey:@"PictureAutoCrop"] intValue] == 0) - { - [fPictureController setAutoCrop:NO]; - - /* Here we use the custom crop values saved at the time the preset was saved */ - job->crop[0] = [[chosenPreset objectForKey:@"PictureTopCrop"] intValue]; - job->crop[1] = [[chosenPreset objectForKey:@"PictureBottomCrop"] intValue]; - job->crop[2] = [[chosenPreset objectForKey:@"PictureLeftCrop"] intValue]; - job->crop[3] = [[chosenPreset objectForKey:@"PictureRightCrop"] intValue]; - - } - else /* if auto crop has been saved in preset, set to auto and use post scan auto crop */ - { - [fPictureController setAutoCrop:YES]; - /* Here we use the auto crop values determined right after scan */ - job->crop[0] = AutoCropTop; - job->crop[1] = AutoCropBottom; - job->crop[2] = AutoCropLeft; - job->crop[3] = AutoCropRight; - - } - /* If the preset has no objectForKey:@"UsesPictureFilters", then we know it is a legacy preset - * and handle the filters here as before. - * NOTE: This should be removed when the update presets code is done as we can be assured that legacy - * presets are updated to work properly with new keys. - */ - if (![chosenPreset objectForKey:@"UsesPictureFilters"]) - { - /* Filters */ - /* Deinterlace */ - if ([chosenPreset objectForKey:@"PictureDeinterlace"]) - { - /* We check to see if the preset used the past fourth "Slowest" deinterlaceing and set that to "Slower - * since we no longer have a fourth "Slowest" deinterlacing due to the mcdeint bug */ - if ([[chosenPreset objectForKey:@"PictureDeinterlace"] intValue] == 4) - { - [fPictureController setDeinterlace:3]; - } - else - { - - [fPictureController setDeinterlace:[[chosenPreset objectForKey:@"PictureDeinterlace"] intValue]]; - } - } - else - { - [fPictureController setDeinterlace:0]; - } - /* VFR */ - if ([[chosenPreset objectForKey:@"VFR"] intValue] == 1) - { - [fPictureController setVFR:[[chosenPreset objectForKey:@"VFR"] intValue]]; - } - else - { - [fPictureController setVFR:0]; - } - /* Detelecine */ - if ([[chosenPreset objectForKey:@"PictureDetelecine"] intValue] == 1) - { - [fPictureController setDetelecine:[[chosenPreset objectForKey:@"PictureDetelecine"] intValue]]; - } - else - { - [fPictureController setDetelecine:0]; - } - /* Denoise */ - if ([chosenPreset objectForKey:@"PictureDenoise"]) - { - [fPictureController setDenoise:[[chosenPreset objectForKey:@"PictureDenoise"] intValue]]; - } - else - { - [fPictureController setDenoise:0]; - } - /* Deblock */ - if ([[chosenPreset objectForKey:@"PictureDeblock"] intValue] == 1) - { - [fPictureController setDeblock:[[chosenPreset objectForKey:@"PictureDeblock"] intValue]]; - } - else - { - [fPictureController setDeblock:0]; - } - - [self calculatePictureSizing:nil]; - } - } - - + + } - /* If the preset has an objectForKey:@"UsesPictureFilters", then we know it is a newer style filters preset - * and handle the filters here depending on whether or not the preset specifies applying the filter. - */ + /* If the preset has an objectForKey:@"UsesPictureFilters", and handle the filters here */ if ([chosenPreset objectForKey:@"UsesPictureFilters"] && [[chosenPreset objectForKey:@"UsesPictureFilters"] intValue] > 0) { /* Filters */ - /* Deinterlace */ - if ([chosenPreset objectForKey:@"PictureDeinterlace"]) + + /* We only allow *either* Decomb or Deinterlace. So check for the PictureDecombDeinterlace key. + * also, older presets may not have this key, in which case we also check to see if that preset had PictureDecomb + * specified, in which case we use decomb and ignore any possible Deinterlace settings as using both was less than + * sane. + */ + [fPictureController setUseDecomb:1]; + [fPictureController setDecomb:0]; + [fPictureController setDeinterlace:0]; + if ([[chosenPreset objectForKey:@"PictureDecombDeinterlace"] intValue] == 1 || [[chosenPreset objectForKey:@"PictureDecomb"] intValue] > 0) { - /* We check to see if the preset used the past fourth "Slowest" deinterlaceing and set that to "Slower - * since we no longer have a fourth "Slowest" deinterlacing due to the mcdeint bug */ - if ([[chosenPreset objectForKey:@"PictureDeinterlace"] intValue] == 4) + /* we are using decomb */ + /* Decomb */ + if ([[chosenPreset objectForKey:@"PictureDecomb"] intValue] > 0) { - [fPictureController setDeinterlace:3]; + [fPictureController setDecomb:[[chosenPreset objectForKey:@"PictureDecomb"] intValue]]; + + /* if we are using "Custom" in the decomb setting, also set the custom string*/ + if ([[chosenPreset objectForKey:@"PictureDecomb"] intValue] == 2) + { + [fPictureController setDecombCustomString:[chosenPreset objectForKey:@"PictureDecombCustom"]]; + } } - else + } + else + { + /* We are using Deinterlace */ + /* Deinterlace */ + if ([[chosenPreset objectForKey:@"PictureDeinterlace"] intValue] > 0) { + [fPictureController setUseDecomb:0]; [fPictureController setDeinterlace:[[chosenPreset objectForKey:@"PictureDeinterlace"] intValue]]; + /* if we are using "Custom" in the deinterlace setting, also set the custom string*/ + if ([[chosenPreset objectForKey:@"PictureDeinterlace"] intValue] == 4) + { + [fPictureController setDeinterlaceCustomString:[chosenPreset objectForKey:@"PictureDeinterlaceCustom"]]; + } } } - else - { - [fPictureController setDeinterlace:0]; - } - /* VFR */ - if ([[chosenPreset objectForKey:@"VFR"] intValue] == 1) - { - [fPictureController setVFR:[[chosenPreset objectForKey:@"VFR"] intValue]]; - } - else - { - [fPictureController setVFR:0]; - } + + /* Detelecine */ - if ([[chosenPreset objectForKey:@"PictureDetelecine"] intValue] == 1) + if ([[chosenPreset objectForKey:@"PictureDetelecine"] intValue] > 0) { [fPictureController setDetelecine:[[chosenPreset objectForKey:@"PictureDetelecine"] intValue]]; + /* if we are using "Custom" in the detelecine setting, also set the custom string*/ + if ([[chosenPreset objectForKey:@"PictureDetelecine"] intValue] == 2) + { + [fPictureController setDetelecineCustomString:[chosenPreset objectForKey:@"PictureDetelecineCustom"]]; + } } else { [fPictureController setDetelecine:0]; } + /* Denoise */ - if ([chosenPreset objectForKey:@"PictureDenoise"]) + if ([[chosenPreset objectForKey:@"PictureDenoise"] intValue] > 0) { [fPictureController setDenoise:[[chosenPreset objectForKey:@"PictureDenoise"] intValue]]; + /* if we are using "Custom" in the denoise setting, also set the custom string*/ + if ([[chosenPreset objectForKey:@"PictureDenoise"] intValue] == 4) + { + [fPictureController setDenoiseCustomString:[chosenPreset objectForKey:@"PictureDenoiseCustom"]]; + } } else { [fPictureController setDenoise:0]; } + /* Deblock */ if ([[chosenPreset objectForKey:@"PictureDeblock"] intValue] == 1) { - [fPictureController setDeblock:[[chosenPreset objectForKey:@"PictureDeblock"] intValue]]; + /* if its a one, then its the old on/off deblock, set on to 5*/ + [fPictureController setDeblock:5]; } else { - [fPictureController setDeblock:0]; + /* use the settings intValue */ + [fPictureController setDeblock:[[chosenPreset objectForKey:@"PictureDeblock"] intValue]]; } - /* Decomb */ - /* Even though we currently allow for a custom setting for decomb, ultimately it will only have Off and - * Default so we just pay attention to anything greater than 0 as 1 (Default). 0 is Off. */ - if ([[chosenPreset objectForKey:@"PictureDecomb"] intValue] > 0) + + if ([[chosenPreset objectForKey:@"VideoGrayScale"] intValue] == 1) { - [fPictureController setDecomb:1]; + [fPictureController setGrayscale:1]; } else { - [fPictureController setDecomb:0]; + [fPictureController setGrayscale:0]; } } + /* we call SetTitle: in fPictureController so we get an instant update in the Picture Settings window */ + [fPictureController SetTitle:fTitle]; + [fPictureController SetTitle:fTitle]; [self calculatePictureSizing:nil]; } } @@ -5466,6 +6720,46 @@ if (item == nil) [self addFactoryPresets:nil]; } [fPresetsOutlineView reloadData]; + + [self checkBuiltInsForUpdates]; +} + +- (void) checkBuiltInsForUpdates { + + BOOL updateBuiltInPresets = NO; + int i = 0; + NSEnumerator *enumerator = [UserPresets objectEnumerator]; + id tempObject; + while (tempObject = [enumerator nextObject]) + { + /* iterate through the built in presets to see if any have an old build number */ + NSMutableDictionary *thisPresetDict = tempObject; + /*Key Type == 0 is built in, and key PresetBuildNumber is the build number it was created with */ + if ([[thisPresetDict objectForKey:@"Type"] intValue] == 0) + { + if (![thisPresetDict objectForKey:@"PresetBuildNumber"] || [[thisPresetDict objectForKey:@"PresetBuildNumber"] intValue] < [[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"] intValue]) + { + updateBuiltInPresets = YES; + } + } + i++; + } + /* if we have built in presets to update, then do so AlertBuiltInPresetUpdate*/ + if ( updateBuiltInPresets == YES) + { + if( [[NSUserDefaults standardUserDefaults] boolForKey:@"AlertBuiltInPresetUpdate"] == YES) + { + /* Show an alert window that built in presets will be updated */ + /*On Screen Notification*/ + int status; + NSBeep(); + status = NSRunAlertPanel(@"HandBrake has determined your built in presets are out of date...",@"HandBrake will now update your built-in presets.", @"OK", nil, nil); + [NSApp requestUserAttention:NSCriticalRequest]; + } + /* when alert is dismissed, go ahead and update the built in presets */ + [self addFactoryPresets:nil]; + } + } @@ -5482,6 +6776,8 @@ if (item == nil) [fPresetNewPicSettingsPopUp selectItemAtIndex: 0]; /* Uncheck the preset use filters checkbox */ [fPresetNewPicFiltersCheck setState:NSOffState]; + // fPresetNewFolderCheck + [fPresetNewFolderCheck setState:NSOffState]; /* Erase info from the input fields*/ [fPresetNewName setStringValue: @""]; [fPresetNewDesc setStringValue: @""]; @@ -5551,132 +6847,172 @@ if (item == nil) - (NSDictionary *)createPreset { NSMutableDictionary *preset = [[NSMutableDictionary alloc] init]; + /* Preset build number */ + [preset setObject:[NSString stringWithFormat: @"%d", [[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"] intValue]] forKey:@"PresetBuildNumber"]; + [preset setObject:[fPresetNewName stringValue] forKey:@"PresetName"]; /* Get the New Preset Name from the field in the AddPresetPanel */ [preset setObject:[fPresetNewName stringValue] forKey:@"PresetName"]; + /* Set whether or not this is to be a folder fPresetNewFolderCheck*/ + [preset setObject:[NSNumber numberWithBool:[fPresetNewFolderCheck state]] forKey:@"Folder"]; /*Set whether or not this is a user preset or factory 0 is factory, 1 is user*/ [preset setObject:[NSNumber numberWithInt:1] forKey:@"Type"]; /*Set whether or not this is default, at creation set to 0*/ [preset setObject:[NSNumber numberWithInt:0] forKey:@"Default"]; - /*Get the whether or not to apply pic Size and Cropping (includes Anamorphic)*/ - [preset setObject:[NSNumber numberWithInt:[fPresetNewPicSettingsPopUp indexOfSelectedItem]] forKey:@"UsesPictureSettings"]; - /* Get whether or not to use the current Picture Filter settings for the preset */ - [preset setObject:[NSNumber numberWithInt:[fPresetNewPicFiltersCheck state]] forKey:@"UsesPictureFilters"]; - - /* Get New Preset Description from the field in the AddPresetPanel*/ - [preset setObject:[fPresetNewDesc stringValue] forKey:@"PresetDescription"]; - /* File Format */ - [preset setObject:[fDstFormatPopUp titleOfSelectedItem] forKey:@"FileFormat"]; - /* Chapter Markers fCreateChapterMarkers*/ - [preset setObject:[NSNumber numberWithInt:[fCreateChapterMarkers state]] forKey:@"ChapterMarkers"]; - /* Allow Mpeg4 64 bit formatting +4GB file sizes */ - [preset setObject:[NSNumber numberWithInt:[fDstMp4LargeFileCheck state]] forKey:@"Mp4LargeFile"]; - /* Mux mp4 with http optimization */ - [preset setObject:[NSNumber numberWithInt:[fDstMp4HttpOptFileCheck state]] forKey:@"Mp4HttpOptimize"]; - /* Add iPod uuid atom */ - [preset setObject:[NSNumber numberWithInt:[fDstMp4iPodFileCheck state]] forKey:@"Mp4iPodCompatible"]; - - /* Codecs */ - /* Video encoder */ - [preset setObject:[fVidEncoderPopUp titleOfSelectedItem] forKey:@"VideoEncoder"]; - /* x264 Option String */ - [preset setObject:[fAdvancedOptions optionsString] forKey:@"x264Option"]; - - [preset setObject:[NSNumber numberWithInt:[fVidQualityMatrix selectedRow]] forKey:@"VideoQualityType"]; - [preset setObject:[fVidTargetSizeField stringValue] forKey:@"VideoTargetSize"]; - [preset setObject:[fVidBitrateField stringValue] forKey:@"VideoAvgBitrate"]; - [preset setObject:[NSNumber numberWithFloat:[fVidQualitySlider floatValue]] forKey:@"VideoQualitySlider"]; - - /* Video framerate */ - if ([fVidRatePopUp indexOfSelectedItem] == 0) // Same as source is selected - { - [preset setObject:@"Same as source" forKey:@"VideoFramerate"]; - } - else // we can record the actual titleOfSelectedItem - { - [preset setObject:[fVidRatePopUp titleOfSelectedItem] forKey:@"VideoFramerate"]; - } - /* GrayScale */ - [preset setObject:[NSNumber numberWithInt:[fVidGrayscaleCheck state]] forKey:@"VideoGrayScale"]; - /* 2 Pass Encoding */ - [preset setObject:[NSNumber numberWithInt:[fVidTwoPassCheck state]] forKey:@"VideoTwoPass"]; - /* Turbo 2 pass Encoding fVidTurboPassCheck*/ - [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:fTitle->job->keep_ratio] forKey:@"PictureKeepRatio"]; - [preset setObject:[NSNumber numberWithInt:fTitle->job->pixel_ratio] forKey:@"PicturePAR"]; - - /* Set crop settings here */ - [preset setObject:[NSNumber numberWithInt:[fPictureController autoCrop]] forKey:@"PictureAutoCrop"]; - [preset setObject:[NSNumber numberWithInt:job->crop[0]] forKey:@"PictureTopCrop"]; - [preset setObject:[NSNumber numberWithInt:job->crop[1]] forKey:@"PictureBottomCrop"]; - [preset setObject:[NSNumber numberWithInt:job->crop[2]] forKey:@"PictureLeftCrop"]; - [preset setObject:[NSNumber numberWithInt:job->crop[3]] forKey:@"PictureRightCrop"]; - - /* Picture Filters */ - [preset setObject:[NSNumber numberWithInt:[fPictureController deinterlace]] forKey:@"PictureDeinterlace"]; - [preset setObject:[NSNumber numberWithInt:[fPictureController detelecine]] forKey:@"PictureDetelecine"]; - [preset setObject:[NSNumber numberWithInt:[fPictureController vfr]] forKey:@"VFR"]; - [preset setObject:[NSNumber numberWithInt:[fPictureController denoise]] forKey:@"PictureDenoise"]; - [preset setObject:[NSNumber numberWithInt:[fPictureController deblock]] forKey:@"PictureDeblock"]; - [preset setObject:[NSNumber numberWithInt:[fPictureController decomb]] forKey:@"PictureDecomb"]; - - - /*Audio*/ - if ([fAudLang1PopUp indexOfSelectedItem] > 0) - { - [preset setObject:[NSNumber numberWithInt:[fAudLang1PopUp indexOfSelectedItem]] forKey:@"Audio1Track"]; - [preset setObject:[fAudLang1PopUp titleOfSelectedItem] forKey:@"Audio1TrackDescription"]; - [preset setObject:[fAudTrack1CodecPopUp titleOfSelectedItem] forKey:@"Audio1Encoder"]; - [preset setObject:[fAudTrack1MixPopUp titleOfSelectedItem] forKey:@"Audio1Mixdown"]; - [preset setObject:[fAudTrack1RatePopUp titleOfSelectedItem] forKey:@"Audio1Samplerate"]; - [preset setObject:[fAudTrack1BitratePopUp titleOfSelectedItem] forKey:@"Audio1Bitrate"]; - [preset setObject:[NSNumber numberWithFloat:[fAudTrack1DrcSlider floatValue]] forKey:@"Audio1TrackDRCSlider"]; - } - if ([fAudLang2PopUp indexOfSelectedItem] > 0) - { - [preset setObject:[NSNumber numberWithInt:[fAudLang2PopUp indexOfSelectedItem]] forKey:@"Audio2Track"]; - [preset setObject:[fAudLang2PopUp titleOfSelectedItem] forKey:@"Audio2TrackDescription"]; - [preset setObject:[fAudTrack2CodecPopUp titleOfSelectedItem] forKey:@"Audio2Encoder"]; - [preset setObject:[fAudTrack2MixPopUp titleOfSelectedItem] forKey:@"Audio2Mixdown"]; - [preset setObject:[fAudTrack2RatePopUp titleOfSelectedItem] forKey:@"Audio2Samplerate"]; - [preset setObject:[fAudTrack2BitratePopUp titleOfSelectedItem] forKey:@"Audio2Bitrate"]; - [preset setObject:[NSNumber numberWithFloat:[fAudTrack2DrcSlider floatValue]] forKey:@"Audio2TrackDRCSlider"]; - } - if ([fAudLang3PopUp indexOfSelectedItem] > 0) + if ([fPresetNewFolderCheck state] == YES) { - [preset setObject:[NSNumber numberWithInt:[fAudLang3PopUp indexOfSelectedItem]] forKey:@"Audio3Track"]; - [preset setObject:[fAudLang3PopUp titleOfSelectedItem] forKey:@"Audio3TrackDescription"]; - [preset setObject:[fAudTrack3CodecPopUp titleOfSelectedItem] forKey:@"Audio3Encoder"]; - [preset setObject:[fAudTrack3MixPopUp titleOfSelectedItem] forKey:@"Audio3Mixdown"]; - [preset setObject:[fAudTrack3RatePopUp titleOfSelectedItem] forKey:@"Audio3Samplerate"]; - [preset setObject:[fAudTrack3BitratePopUp titleOfSelectedItem] forKey:@"Audio3Bitrate"]; - [preset setObject:[NSNumber numberWithFloat:[fAudTrack3DrcSlider floatValue]] forKey:@"Audio3TrackDRCSlider"]; + /* initialize and set an empty array for children here since we are a new folder */ + NSMutableArray *childrenArray = [[NSMutableArray alloc] init]; + [preset setObject:[NSMutableArray arrayWithArray: childrenArray] forKey:@"ChildrenArray"]; + [childrenArray autorelease]; } - if ([fAudLang4PopUp indexOfSelectedItem] > 0) + else // we are not creating a preset folder, so we go ahead with the rest of the preset info { - [preset setObject:[NSNumber numberWithInt:[fAudLang4PopUp indexOfSelectedItem]] forKey:@"Audio4Track"]; - [preset setObject:[fAudLang4PopUp titleOfSelectedItem] forKey:@"Audio4TrackDescription"]; - [preset setObject:[fAudTrack4CodecPopUp titleOfSelectedItem] forKey:@"Audio4Encoder"]; - [preset setObject:[fAudTrack4MixPopUp titleOfSelectedItem] forKey:@"Audio4Mixdown"]; - [preset setObject:[fAudTrack4RatePopUp titleOfSelectedItem] forKey:@"Audio4Samplerate"]; - [preset setObject:[fAudTrack4BitratePopUp titleOfSelectedItem] forKey:@"Audio4Bitrate"]; - [preset setObject:[NSNumber numberWithFloat:[fAudTrack4DrcSlider floatValue]] forKey:@"Audio4TrackDRCSlider"]; + /*Get the whether or not to apply pic Size and Cropping (includes Anamorphic)*/ + [preset setObject:[NSNumber numberWithInt:[fPresetNewPicSettingsPopUp indexOfSelectedItem]] forKey:@"UsesPictureSettings"]; + /* Get whether or not to use the current Picture Filter settings for the preset */ + [preset setObject:[NSNumber numberWithInt:[fPresetNewPicFiltersCheck state]] forKey:@"UsesPictureFilters"]; + + /* Get New Preset Description from the field in the AddPresetPanel*/ + [preset setObject:[fPresetNewDesc stringValue] forKey:@"PresetDescription"]; + /* File Format */ + [preset setObject:[fDstFormatPopUp titleOfSelectedItem] forKey:@"FileFormat"]; + /* Chapter Markers fCreateChapterMarkers*/ + [preset setObject:[NSNumber numberWithInt:[fCreateChapterMarkers state]] forKey:@"ChapterMarkers"]; + /* Allow Mpeg4 64 bit formatting +4GB file sizes */ + [preset setObject:[NSNumber numberWithInt:[fDstMp4LargeFileCheck state]] forKey:@"Mp4LargeFile"]; + /* Mux mp4 with http optimization */ + [preset setObject:[NSNumber numberWithInt:[fDstMp4HttpOptFileCheck state]] forKey:@"Mp4HttpOptimize"]; + /* Add iPod uuid atom */ + [preset setObject:[NSNumber numberWithInt:[fDstMp4iPodFileCheck state]] forKey:@"Mp4iPodCompatible"]; + + /* Codecs */ + /* Video encoder */ + [preset setObject:[fVidEncoderPopUp titleOfSelectedItem] forKey:@"VideoEncoder"]; + /* x264 Option String */ + [preset setObject:[fAdvancedOptions optionsString] forKey:@"x264Option"]; + + [preset setObject:[NSNumber numberWithInt:[fVidQualityMatrix selectedRow]] forKey:@"VideoQualityType"]; + [preset setObject:[fVidTargetSizeField stringValue] forKey:@"VideoTargetSize"]; + [preset setObject:[fVidBitrateField stringValue] forKey:@"VideoAvgBitrate"]; + [preset setObject:[NSNumber numberWithFloat:[fVidQualityRFField floatValue]] forKey:@"VideoQualitySlider"]; + + /* Video framerate */ + if ([fVidRatePopUp indexOfSelectedItem] == 0) // Same as source is selected + { + [preset setObject:@"Same as source" forKey:@"VideoFramerate"]; + } + else // we can record the actual titleOfSelectedItem + { + [preset setObject:[fVidRatePopUp titleOfSelectedItem] forKey:@"VideoFramerate"]; + } + + /* 2 Pass Encoding */ + [preset setObject:[NSNumber numberWithInt:[fVidTwoPassCheck state]] forKey:@"VideoTwoPass"]; + /* Turbo 2 pass Encoding fVidTurboPassCheck*/ + [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:fTitle->job->keep_ratio] forKey:@"PictureKeepRatio"]; + [preset setObject:[NSNumber numberWithInt:fTitle->job->anamorphic.mode] forKey:@"PicturePAR"]; + + /* Set crop settings here */ + [preset setObject:[NSNumber numberWithInt:[fPictureController autoCrop]] forKey:@"PictureAutoCrop"]; + [preset setObject:[NSNumber numberWithInt:job->crop[0]] forKey:@"PictureTopCrop"]; + [preset setObject:[NSNumber numberWithInt:job->crop[1]] forKey:@"PictureBottomCrop"]; + [preset setObject:[NSNumber numberWithInt:job->crop[2]] forKey:@"PictureLeftCrop"]; + [preset setObject:[NSNumber numberWithInt:job->crop[3]] forKey:@"PictureRightCrop"]; + + /* Picture Filters */ + [preset setObject:[NSNumber numberWithInt:[fPictureController useDecomb]] forKey:@"PictureDecombDeinterlace"]; + [preset setObject:[NSNumber numberWithInt:[fPictureController deinterlace]] forKey:@"PictureDeinterlace"]; + [preset setObject:[fPictureController deinterlaceCustomString] forKey:@"PictureDeinterlaceCustom"]; + [preset setObject:[NSNumber numberWithInt:[fPictureController detelecine]] forKey:@"PictureDetelecine"]; + [preset setObject:[fPictureController detelecineCustomString] forKey:@"PictureDetelecineCustom"]; + [preset setObject:[NSNumber numberWithInt:[fPictureController denoise]] forKey:@"PictureDenoise"]; + [preset setObject:[fPictureController denoiseCustomString] forKey:@"PictureDenoiseCustom"]; + [preset setObject:[NSNumber numberWithInt:[fPictureController deblock]] forKey:@"PictureDeblock"]; + [preset setObject:[NSNumber numberWithInt:[fPictureController decomb]] forKey:@"PictureDecomb"]; + [preset setObject:[fPictureController decombCustomString] forKey:@"PictureDecombCustom"]; + [preset setObject:[NSNumber numberWithInt:[fPictureController grayscale]] forKey:@"VideoGrayScale"]; + + /*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]; + } + + + [preset setObject:[NSMutableArray arrayWithArray: audioListArray] forKey:@"AudioList"]; + + + /* Temporarily remove subtitles from creating a new preset as it has to be converted over to use the new + * subititle array code. */ + /* Subtitles*/ + //[preset setObject:[fSubPopUp titleOfSelectedItem] forKey:@"Subtitles"]; + /* Forced Subtitles */ + //[preset setObject:[NSNumber numberWithInt:[fSubForcedCheck state]] forKey:@"SubtitlesForced"]; } - - /* Subtitles*/ - [preset setObject:[fSubPopUp titleOfSelectedItem] forKey:@"Subtitles"]; - /* Forced Subtitles */ - [preset setObject:[NSNumber numberWithInt:[fSubForcedCheck state]] forKey:@"SubtitlesForced"]; - [preset autorelease]; return preset; - + } - (void)savePreset @@ -5689,106 +7025,390 @@ if (item == nil) - (IBAction)deletePreset:(id)sender { - int status; - NSEnumerator *enumerator; - NSNumber *index; - NSMutableArray *tempArray; - id tempObject; + if ( [fPresetsOutlineView numberOfSelectedRows] == 0 ) + { return; + } /* Alert user before deleting preset */ - /* Comment out for now, tie to user pref eventually */ - - //NSBeep(); + int status; status = NSRunAlertPanel(@"Warning!", @"Are you sure that you want to delete the selected preset?", @"OK", @"Cancel", nil); - if ( status == NSAlertDefaultReturn ) { - enumerator = [fPresetsOutlineView selectedRowEnumerator]; + if ( status == NSAlertDefaultReturn ) + { + int presetToModLevel = [fPresetsOutlineView levelForItem: [fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]]]; + NSDictionary *presetToMod = [fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]]; + NSDictionary *presetToModParent = [fPresetsOutlineView parentForItem: presetToMod]; + + NSEnumerator *enumerator; + NSMutableArray *presetsArrayToMod; + NSMutableArray *tempArray; + id tempObject; + /* If we are a root level preset, we are modding the UserPresets array */ + if (presetToModLevel == 0) + { + presetsArrayToMod = UserPresets; + } + else // We have a parent preset, so we modify the chidren array object for key + { + presetsArrayToMod = [presetToModParent objectForKey:@"ChildrenArray"]; + } + + enumerator = [presetsArrayToMod objectEnumerator]; tempArray = [NSMutableArray array]; - while ( (index = [enumerator nextObject]) ) { - tempObject = [UserPresets objectAtIndex:[index intValue]]; - [tempArray addObject:tempObject]; + while (tempObject = [enumerator nextObject]) + { + NSDictionary *thisPresetDict = tempObject; + if (thisPresetDict == presetToMod) + { + [tempArray addObject:tempObject]; + } } - [UserPresets removeObjectsInArray:tempArray]; + [presetsArrayToMod removeObjectsInArray:tempArray]; [fPresetsOutlineView reloadData]; [self savePreset]; } } + +#pragma mark - +#pragma mark Import Export Preset(s) + +- (IBAction) browseExportPresetFile: (id) sender +{ + /* Open a panel to let the user choose where and how to save the export file */ + NSSavePanel * panel = [NSSavePanel savePanel]; + /* We get the current file name and path from the destination field here */ + NSString *defaultExportDirectory = [NSString stringWithFormat: @"%@/Desktop/", NSHomeDirectory()]; + + [panel beginSheetForDirectory: defaultExportDirectory file: @"HB_Export.plist" + modalForWindow: fWindow modalDelegate: self + didEndSelector: @selector( browseExportPresetFileDone:returnCode:contextInfo: ) + contextInfo: NULL]; +} + +- (void) browseExportPresetFileDone: (NSSavePanel *) sheet + returnCode: (int) returnCode contextInfo: (void *) contextInfo +{ + if( returnCode == NSOKButton ) + { + NSString *presetExportDirectory = [[sheet filename] stringByDeletingLastPathComponent]; + NSString *exportPresetsFile = [sheet filename]; + [[NSUserDefaults standardUserDefaults] setObject:presetExportDirectory forKey:@"LastPresetExportDirectory"]; + /* We check for the presets.plist */ + if ([[NSFileManager defaultManager] fileExistsAtPath:exportPresetsFile] == 0) + { + [[NSFileManager defaultManager] createFileAtPath:exportPresetsFile contents:nil attributes:nil]; + } + NSMutableArray * presetsToExport = [[NSMutableArray alloc] initWithContentsOfFile:exportPresetsFile]; + if (nil == presetsToExport) + { + presetsToExport = [[NSMutableArray alloc] init]; + + /* now get and add selected presets to export */ + + } + if ([fPresetsOutlineView selectedRow] >= 0 && [[[fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]] objectForKey:@"Folder"] intValue] != 1) + { + [presetsToExport addObject:[fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]]]; + [presetsToExport writeToFile:exportPresetsFile atomically:YES]; + + } + + } +} + + +- (IBAction) browseImportPresetFile: (id) sender +{ + + NSOpenPanel * panel; + + panel = [NSOpenPanel openPanel]; + [panel setAllowsMultipleSelection: NO]; + [panel setCanChooseFiles: YES]; + [panel setCanChooseDirectories: NO ]; + NSString * sourceDirectory; + if ([[NSUserDefaults standardUserDefaults] stringForKey:@"LastPresetImportDirectory"]) + { + sourceDirectory = [[NSUserDefaults standardUserDefaults] stringForKey:@"LastPresetImportDirectory"]; + } + else + { + sourceDirectory = @"~/Desktop"; + sourceDirectory = [sourceDirectory stringByExpandingTildeInPath]; + } + /* we open up the browse sources sheet here and call for browseSourcesDone after the sheet is closed + * to evaluate whether we want to specify a title, we pass the sender in the contextInfo variable + */ + /* set this for allowed file types, not sure if we should allow xml or not */ + NSArray *fileTypes = [NSArray arrayWithObjects:@"plist", @"xml", nil]; + [panel beginSheetForDirectory: sourceDirectory file: nil types: fileTypes + modalForWindow: fWindow modalDelegate: self + didEndSelector: @selector( browseImportPresetDone:returnCode:contextInfo: ) + contextInfo: sender]; +} + +- (void) browseImportPresetDone: (NSSavePanel *) sheet + returnCode: (int) returnCode contextInfo: (void *) contextInfo +{ + if( returnCode == NSOKButton ) + { + NSString *importPresetsDirectory = [[sheet filename] stringByDeletingLastPathComponent]; + NSString *importPresetsFile = [sheet filename]; + [[NSUserDefaults standardUserDefaults] setObject:importPresetsDirectory forKey:@"LastPresetImportDirectory"]; + /* NOTE: here we need to do some sanity checking to verify we do not hose up our presets file */ + NSMutableArray * presetsToImport = [[NSMutableArray alloc] initWithContentsOfFile:importPresetsFile]; + /* iterate though the new array of presets to import and add them to our presets array */ + int i = 0; + NSEnumerator *enumerator = [presetsToImport objectEnumerator]; + id tempObject; + while (tempObject = [enumerator nextObject]) + { + /* make any changes to the incoming preset we see fit */ + /* make sure the incoming preset is not tagged as default */ + [tempObject setObject:[NSNumber numberWithInt:0] forKey:@"Default"]; + /* prepend "(imported) to the name of the incoming preset for clarification since it can be changed */ + NSString * prependedName = [@"(import) " stringByAppendingString:[tempObject objectForKey:@"PresetName"]] ; + [tempObject setObject:prependedName forKey:@"PresetName"]; + + /* actually add the new preset to our presets array */ + [UserPresets addObject:tempObject]; + i++; + } + [presetsToImport autorelease]; + [self sortPresets]; + [self addPreset]; + + } +} + #pragma mark - #pragma mark Manage Default Preset - (IBAction)getDefaultPresets:(id)sender { - int i = 0; + presetHbDefault = nil; + presetUserDefault = nil; + presetUserDefaultParent = nil; + presetUserDefaultParentParent = nil; + NSMutableDictionary *presetHbDefaultParent = nil; + NSMutableDictionary *presetHbDefaultParentParent = nil; + + int i = 0; + BOOL userDefaultFound = NO; presetCurrentBuiltInCount = 0; + /* First we iterate through the root UserPresets array to check for defaults */ NSEnumerator *enumerator = [UserPresets objectEnumerator]; id tempObject; while (tempObject = [enumerator nextObject]) { - NSDictionary *thisPresetDict = tempObject; + NSMutableDictionary *thisPresetDict = tempObject; if ([[thisPresetDict objectForKey:@"Default"] intValue] == 1) // 1 is HB default { - presetHbDefault = i; + presetHbDefault = thisPresetDict; } if ([[thisPresetDict objectForKey:@"Default"] intValue] == 2) // 2 is User specified default { - presetUserDefault = i; - } + presetUserDefault = thisPresetDict; + userDefaultFound = YES; + } if ([[thisPresetDict objectForKey:@"Type"] intValue] == 0) // Type 0 is a built in preset { presetCurrentBuiltInCount++; // <--increment the current number of built in presets } i++; + + /* if we run into a folder, go to level 1 and iterate through the children arrays for the default */ + if ([thisPresetDict objectForKey:@"ChildrenArray"]) + { + NSMutableDictionary *thisPresetDictParent = thisPresetDict; + NSEnumerator *enumerator = [[thisPresetDict objectForKey:@"ChildrenArray"] objectEnumerator]; + id tempObject; + while (tempObject = [enumerator nextObject]) + { + NSMutableDictionary *thisPresetDict = tempObject; + if ([[thisPresetDict objectForKey:@"Default"] intValue] == 1) // 1 is HB default + { + presetHbDefault = thisPresetDict; + presetHbDefaultParent = thisPresetDictParent; + } + if ([[thisPresetDict objectForKey:@"Default"] intValue] == 2) // 2 is User specified default + { + presetUserDefault = thisPresetDict; + presetUserDefaultParent = thisPresetDictParent; + userDefaultFound = YES; + } + + /* if we run into a folder, go to level 2 and iterate through the children arrays for the default */ + if ([thisPresetDict objectForKey:@"ChildrenArray"]) + { + NSMutableDictionary *thisPresetDictParentParent = thisPresetDict; + NSEnumerator *enumerator = [[thisPresetDict objectForKey:@"ChildrenArray"] objectEnumerator]; + id tempObject; + while (tempObject = [enumerator nextObject]) + { + NSMutableDictionary *thisPresetDict = tempObject; + if ([[thisPresetDict objectForKey:@"Default"] intValue] == 1) // 1 is HB default + { + presetHbDefault = thisPresetDict; + presetHbDefaultParent = thisPresetDictParent; + presetHbDefaultParentParent = thisPresetDictParentParent; + } + if ([[thisPresetDict objectForKey:@"Default"] intValue] == 2) // 2 is User specified default + { + presetUserDefault = thisPresetDict; + presetUserDefaultParent = thisPresetDictParent; + presetUserDefaultParentParent = thisPresetDictParentParent; + userDefaultFound = YES; + } + + } + } + } + } + } + /* check to see if a user specified preset was found, if not then assign the parents for + * the presetHbDefault so that we can open the parents for the nested presets + */ + if (userDefaultFound == NO) + { + presetUserDefaultParent = presetHbDefaultParent; + presetUserDefaultParentParent = presetHbDefaultParentParent; + } } - (IBAction)setDefaultPreset:(id)sender { +/* We need to determine if the item is a folder */ + if ([[[fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]] objectForKey:@"Folder"] intValue] == 1) + { + return; + } + int i = 0; NSEnumerator *enumerator = [UserPresets objectEnumerator]; id tempObject; /* First make sure the old user specified default preset is removed */ - while (tempObject = [enumerator nextObject]) + while (tempObject = [enumerator nextObject]) { - /* make sure we are not removing the default HB preset */ - if ([[[UserPresets objectAtIndex:i] objectForKey:@"Default"] intValue] != 1) // 1 is HB default + NSMutableDictionary *thisPresetDict = tempObject; + if ([[tempObject objectForKey:@"Default"] intValue] != 1) // if not the default HB Preset, set to 0 { - [[UserPresets objectAtIndex:i] setObject:[NSNumber numberWithInt:0] forKey:@"Default"]; + [[UserPresets objectAtIndex:i] setObject:[NSNumber numberWithInt:0] forKey:@"Default"]; } - i++; - } - /* Second, go ahead and set the appropriate user specfied preset */ - /* we get the chosen preset from the UserPresets array */ - if ([[[UserPresets objectAtIndex:[fPresetsOutlineView selectedRow]] objectForKey:@"Default"] intValue] != 1) // 1 is HB default - { - [[UserPresets objectAtIndex:[fPresetsOutlineView selectedRow]] setObject:[NSNumber numberWithInt:2] forKey:@"Default"]; + + /* if we run into a folder, go to level 1 and iterate through the children arrays for the default */ + if ([thisPresetDict objectForKey:@"ChildrenArray"]) + { + NSEnumerator *enumerator = [[thisPresetDict objectForKey:@"ChildrenArray"] objectEnumerator]; + id tempObject; + int ii = 0; + while (tempObject = [enumerator nextObject]) + { + NSMutableDictionary *thisPresetDict1 = tempObject; + if ([[tempObject objectForKey:@"Default"] intValue] != 1) // if not the default HB Preset, set to 0 + { + [[[thisPresetDict objectForKey:@"ChildrenArray"] objectAtIndex:ii] setObject:[NSNumber numberWithInt:0] forKey:@"Default"]; + } + /* if we run into a folder, go to level 2 and iterate through the children arrays for the default */ + if ([thisPresetDict1 objectForKey:@"ChildrenArray"]) + { + NSEnumerator *enumerator = [[thisPresetDict1 objectForKey:@"ChildrenArray"] objectEnumerator]; + id tempObject; + int iii = 0; + while (tempObject = [enumerator nextObject]) + { + if ([[tempObject objectForKey:@"Default"] intValue] != 1) // if not the default HB Preset, set to 0 + { + [[[thisPresetDict1 objectForKey:@"ChildrenArray"] objectAtIndex:iii] setObject:[NSNumber numberWithInt:0] forKey:@"Default"]; + } + iii++; + } + } + ii++; + } + + } + i++; } - /*FIX ME: I think we now need to use the items not rows in NSOutlineView */ - presetUserDefault = [fPresetsOutlineView selectedRow]; - - /* We save all of the preset data here */ + + + int presetToModLevel = [fPresetsOutlineView levelForItem: [fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]]]; + NSDictionary *presetToMod = [fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]]; + NSDictionary *presetToModParent = [fPresetsOutlineView parentForItem: presetToMod]; + + + NSMutableArray *presetsArrayToMod; + NSMutableArray *tempArray; + + /* If we are a root level preset, we are modding the UserPresets array */ + if (presetToModLevel == 0) + { + presetsArrayToMod = UserPresets; + } + else // We have a parent preset, so we modify the chidren array object for key + { + presetsArrayToMod = [presetToModParent objectForKey:@"ChildrenArray"]; + } + + enumerator = [presetsArrayToMod objectEnumerator]; + tempArray = [NSMutableArray array]; + int iiii = 0; + while (tempObject = [enumerator nextObject]) + { + NSDictionary *thisPresetDict = tempObject; + if (thisPresetDict == presetToMod) + { + if ([[tempObject objectForKey:@"Default"] intValue] != 1) // if not the default HB Preset, set to 2 + { + [[presetsArrayToMod objectAtIndex:iiii] setObject:[NSNumber numberWithInt:2] forKey:@"Default"]; + } + } + iiii++; + } + + + /* We save all of the preset data here */ [self savePreset]; - /* We Reload the New Table data for presets */ + /* We Reload the New Table data for presets */ [fPresetsOutlineView reloadData]; } - (IBAction)selectDefaultPreset:(id)sender { - /* if there is a user specified default, we use it */ + NSMutableDictionary *presetToMod; + /* if there is a user specified default, we use it */ if (presetUserDefault) { - [fPresetsOutlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:presetUserDefault] byExtendingSelection:NO]; - [self selectPreset:nil]; - } + presetToMod = presetUserDefault; + } else if (presetHbDefault) //else we use the built in default presetHbDefault { - [fPresetsOutlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:presetHbDefault] byExtendingSelection:NO]; - [self selectPreset:nil]; + presetToMod = presetHbDefault; } + else + { + return; + } + + if (presetUserDefaultParent != nil) + { + [fPresetsOutlineView expandItem:presetUserDefaultParent]; + + } + if (presetUserDefaultParentParent != nil) + { + [fPresetsOutlineView expandItem:presetUserDefaultParentParent]; + + } + + [fPresetsOutlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:[fPresetsOutlineView rowForItem: presetToMod]] byExtendingSelection:NO]; + [self selectPreset:nil]; } @@ -5824,25 +7444,39 @@ if (item == nil) } - /* We use this method to recreate new, updated factory - presets */ + /* We use this method to recreate new, updated factory presets */ - (IBAction)addFactoryPresets:(id)sender { - - /* First, we delete any existing built in presets */ + + /* First, we delete any existing built in presets */ [self deleteFactoryPresets: sender]; /* Then we generate new built in presets programmatically with fPresetsBuiltin - * which is all setup in HBPresets.h and HBPresets.m*/ + * which is all setup in HBPresets.h and HBPresets.m*/ [fPresetsBuiltin generateBuiltinPresets:UserPresets]; + /* update build number for built in presets */ + /* iterate though the new array of presets to import and add them to our presets array */ + int i = 0; + NSEnumerator *enumerator = [UserPresets objectEnumerator]; + id tempObject; + while (tempObject = [enumerator nextObject]) + { + /* Record the apps current build number in the PresetBuildNumber key */ + if ([[tempObject objectForKey:@"Type"] intValue] == 0) // Type 0 is a built in preset + { + /* Preset build number */ + [[UserPresets objectAtIndex:i] setObject:[NSNumber numberWithInt:[[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"] intValue]] forKey:@"PresetBuildNumber"]; + } + i++; + } + /* report the built in preset updating to the activity log */ + [self writeToActivityLog: "built in presets updated to build number: %d", [[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"] intValue]]; + [self sortPresets]; [self addPreset]; } - - - @end /******************************* @@ -5856,7 +7490,7 @@ if (item == nil) // By default, NSTableView only drags an image of the first column. Change this to // drag an image of the queue's icon and PresetName columns. - NSArray * cols = [NSArray arrayWithObjects: [self tableColumnWithIdentifier:@"icon"], [self tableColumnWithIdentifier:@"PresetName"], nil]; + NSArray * cols = [NSArray arrayWithObjects: [self tableColumnWithIdentifier:@"PresetName"], nil]; return [super dragImageForRowsWithIndexes:dragRows tableColumns:cols event:dragEvent offset:dragImageOffset]; }