OSDN Git Service

MacGui: Add encoding status readout to the queue window
[handbrake-jp/handbrake-jp-git.git] / macosx / Controller.mm
1 /* $Id: Controller.mm,v 1.79 2005/11/04 19:41:32 titer Exp $
2
3    This file is part of the HandBrake source code.
4    Homepage: <http://handbrake.fr/>.
5    It may be used under the terms of the GNU General Public License. */
6
7 #import "Controller.h"
8 #import "HBOutputPanelController.h"
9 #import "HBPreferencesController.h"
10 #import "HBDVDDetector.h"
11 #import "HBPresets.h"
12
13 #define DragDropSimplePboardType        @"MyCustomOutlineViewPboardType"
14
15 /* We setup the toolbar values here */
16 static NSString *        ToggleDrawerIdentifier             = @"Toggle Drawer Item Identifier";
17 static NSString *        StartEncodingIdentifier            = @"Start Encoding Item Identifier";
18 static NSString *        PauseEncodingIdentifier            = @"Pause Encoding Item Identifier";
19 static NSString *        ShowQueueIdentifier                = @"Show Queue Item Identifier";
20 static NSString *        AddToQueueIdentifier               = @"Add to Queue Item Identifier";
21 static NSString *        ShowActivityIdentifier             = @"Debug Output Item Identifier";
22 static NSString *        ChooseSourceIdentifier             = @"Choose Source Item Identifier";
23
24
25 /*******************************
26  * HBController implementation *
27  *******************************/
28 @implementation HBController
29
30 - (id)init
31 {
32     self = [super init];
33     if( !self )
34     {
35         return nil;
36     }
37
38     [HBPreferencesController registerUserDefaults];
39     fHandle = NULL;
40     fQueueEncodeLibhb = NULL;
41     /* Check for check for the app support directory here as
42      * outputPanel needs it right away, as may other future methods
43      */
44     NSString *libraryDir = [NSSearchPathForDirectoriesInDomains( NSLibraryDirectory,
45                                                                  NSUserDomainMask,
46                                                                  YES ) objectAtIndex:0];
47     AppSupportDirectory = [[libraryDir stringByAppendingPathComponent:@"Application Support"]
48                                        stringByAppendingPathComponent:@"HandBrake"];
49     if( ![[NSFileManager defaultManager] fileExistsAtPath:AppSupportDirectory] )
50     {
51         [[NSFileManager defaultManager] createDirectoryAtPath:AppSupportDirectory
52                                                    attributes:nil];
53     }
54
55     outputPanel = [[HBOutputPanelController alloc] init];
56     fPictureController = [[PictureController alloc] initWithDelegate:self];
57     fQueueController = [[HBQueueController alloc] init];
58     fAdvancedOptions = [[HBAdvancedController alloc] init];
59     /* we init the HBPresets class which currently is only used
60     * for updating built in presets, may move more functionality
61     * there in the future
62     */
63     fPresetsBuiltin = [[HBPresets alloc] init];
64     fPreferencesController = [[HBPreferencesController alloc] init];
65     /* Lets report the HandBrake version number here to the activity log and text log file */
66     NSString *versionStringFull = [[NSString stringWithFormat: @"Handbrake Version: %@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleGetInfoString"]] stringByAppendingString: [NSString stringWithFormat: @" (%@)", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]]];
67     [self writeToActivityLog: "%s", [versionStringFull UTF8String]];    
68     
69     return self;
70 }
71
72
73 - (void) applicationDidFinishLaunching: (NSNotification *) notification
74 {
75     /* Init libhb with check for updates libhb style set to "0" so its ignored and lets sparkle take care of it */
76     fHandle = hb_init(HB_DEBUG_ALL, 0);
77     /* Init a separate instance of libhb for user scanning and setting up jobs */
78     fQueueEncodeLibhb = hb_init(HB_DEBUG_ALL, 0);
79     
80         // Set the Growl Delegate
81     [GrowlApplicationBridge setGrowlDelegate: self];
82     /* Init others controllers */
83     [fPictureController SetHandle: fHandle];
84     [fQueueController   setHandle: fQueueEncodeLibhb];
85     [fQueueController   setHBController: self];
86
87     fChapterTitlesDelegate = [[ChapterTitles alloc] init];
88     [fChapterTable setDataSource:fChapterTitlesDelegate];
89     [fChapterTable setDelegate:fChapterTitlesDelegate];
90
91     /* Call UpdateUI every 1/2 sec */
92     [[NSRunLoop currentRunLoop] addTimer:[NSTimer
93                                           scheduledTimerWithTimeInterval:0.5 target:self
94                                           selector:@selector(updateUI:) userInfo:nil repeats:YES]
95                                  forMode:NSEventTrackingRunLoopMode];
96
97     // Open debug output window now if it was visible when HB was closed
98     if ([[NSUserDefaults standardUserDefaults] boolForKey:@"OutputPanelIsOpen"])
99         [self showDebugOutputPanel:nil];
100
101     // Open queue window now if it was visible when HB was closed
102     if ([[NSUserDefaults standardUserDefaults] boolForKey:@"QueueWindowIsOpen"])
103         [self showQueueWindow:nil];
104
105         [self openMainWindow:nil];
106     
107     /* We have to set the bool to tell hb what to do after a scan
108      * Initially we set it to NO until we start processing the queue
109      */
110      applyQueueToScan = NO;
111     
112     /* Now we re-check the queue array to see if there are
113      * any remaining encodes to be done in it and ask the
114      * user if they want to reload the queue */
115     if ([QueueFileArray count] > 0)
116         {
117         /*On Screen Notification*/
118         NSString * alertTitle = [NSString stringWithFormat:NSLocalizedString(@"HandBrake Has Detected Item(s) From Your Previous Queue.", nil)];
119         NSBeginCriticalAlertSheet(
120             alertTitle,
121             NSLocalizedString(@"Reload Queue", nil),
122             nil,
123             NSLocalizedString(@"Empty Queue", nil),
124             fWindow, self,
125             nil, @selector(didDimissReloadQueue:returnCode:contextInfo:), nil,
126             NSLocalizedString(@" Do you want to reload them ?", nil));
127         // call didDimissReloadQueue: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo
128         // right below to either clear the old queue or keep it loaded up.
129     }
130     else
131     {
132      
133     /* Show Browse Sources Window ASAP */
134     [self performSelectorOnMainThread:@selector(browseSources:)
135                            withObject:nil waitUntilDone:NO];
136    }
137 }
138
139 - (void) didDimissReloadQueue: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo
140 {
141     if (returnCode == NSAlertOtherReturn)
142     {
143         [self clearQueueAllItems];
144         [self performSelectorOnMainThread:@selector(browseSources:)
145                            withObject:nil waitUntilDone:NO];
146     }
147     
148     
149 }
150
151 - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication *) app
152 {
153     // Warn if encoding a movie
154     hb_state_t s;
155     hb_get_state( fHandle, &s );
156     
157     if ( s.state != HB_STATE_IDLE )
158     {
159         int result = NSRunCriticalAlertPanel(
160                 NSLocalizedString(@"Are you sure you want to quit HandBrake?", nil),
161                 NSLocalizedString(@"If you quit HandBrake, your movie will be lost. Do you want to quit anyway?", nil),
162                 NSLocalizedString(@"Quit", nil), NSLocalizedString(@"Don't Quit", nil), nil, @"A movie" );
163         
164         if (result == NSAlertDefaultReturn)
165         {
166             [self doCancelCurrentJob];
167             return NSTerminateNow;
168         }
169         else
170             return NSTerminateCancel;
171     }
172     
173     // Warn if items still in the queue
174     else if ( hb_count( fHandle ) > 0 )
175     {
176         int result = NSRunCriticalAlertPanel(
177                 NSLocalizedString(@"Are you sure you want to quit HandBrake?", nil),
178                 NSLocalizedString(@"One or more encodes are queued for encoding. Do you want to quit anyway?", nil),
179                 NSLocalizedString(@"Quit", nil), NSLocalizedString(@"Don't Quit", nil), nil);
180         
181         if ( result == NSAlertDefaultReturn )
182             return NSTerminateNow;
183         else
184             return NSTerminateCancel;
185     }
186     
187     return NSTerminateNow;
188 }
189
190 - (void)applicationWillTerminate:(NSNotification *)aNotification
191 {
192         [browsedSourceDisplayName release];
193     [outputPanel release];
194         [fQueueController release];
195         hb_close(&fHandle);
196     hb_close(&fQueueEncodeLibhb);
197 }
198
199
200 - (void) awakeFromNib
201 {
202     [fWindow center];
203     [fWindow setExcludedFromWindowsMenu:YES];
204     [fAdvancedOptions setView:fAdvancedView];
205
206     /* lets setup our presets drawer for drag and drop here */
207     [fPresetsOutlineView registerForDraggedTypes: [NSArray arrayWithObject:DragDropSimplePboardType] ];
208     [fPresetsOutlineView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES];
209     [fPresetsOutlineView setVerticalMotionCanBeginDrag: YES];
210
211     /* Initialize currentScanCount so HB can use it to
212                 evaluate successive scans */
213         currentScanCount = 0;
214
215
216     /* Init UserPresets .plist */
217         [self loadPresets];
218     
219     /* Init QueueFile .plist */
220     [self loadQueueFile];
221         
222     fRipIndicatorShown = NO;  // initially out of view in the nib
223
224         /* Show/Dont Show Presets drawer upon launch based
225                 on user preference DefaultPresetsDrawerShow*/
226         if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultPresetsDrawerShow"] > 0)
227         {
228                 [fPresetDrawer open];
229         }
230         
231         
232     
233     /* Destination box*/
234     NSMenuItem *menuItem;
235     [fDstFormatPopUp removeAllItems];
236     // MP4 file
237     menuItem = [[fDstFormatPopUp menu] addItemWithTitle:@"MP4 file" action: NULL keyEquivalent: @""];
238     [menuItem setTag: HB_MUX_MP4];
239         // MKV file
240     menuItem = [[fDstFormatPopUp menu] addItemWithTitle:@"MKV file" action: NULL keyEquivalent: @""];
241     [menuItem setTag: HB_MUX_MKV];
242     // AVI file
243     menuItem = [[fDstFormatPopUp menu] addItemWithTitle:@"AVI file" action: NULL keyEquivalent: @""];
244     [menuItem setTag: HB_MUX_AVI];
245     // OGM file
246     menuItem = [[fDstFormatPopUp menu] addItemWithTitle:@"OGM file" action: NULL keyEquivalent: @""];
247     [menuItem setTag: HB_MUX_OGM];
248     [fDstFormatPopUp selectItemAtIndex: 0];
249
250     [self formatPopUpChanged:nil];
251
252         /* We enable the create chapters checkbox here since we are .mp4 */
253         [fCreateChapterMarkers setEnabled: YES];
254         if ([fDstFormatPopUp indexOfSelectedItem] == 0 && [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultChapterMarkers"] > 0)
255         {
256                 [fCreateChapterMarkers setState: NSOnState];
257         }
258
259
260
261
262     [fDstFile2Field setStringValue: [NSString stringWithFormat:
263         @"%@/Desktop/Movie.mp4", NSHomeDirectory()]];
264
265     /* Video encoder */
266     [fVidEncoderPopUp removeAllItems];
267     [fVidEncoderPopUp addItemWithTitle: @"FFmpeg"];
268     [fVidEncoderPopUp addItemWithTitle: @"XviD"];
269
270
271
272     /* Video quality */
273     [fVidTargetSizeField setIntValue: 700];
274         [fVidBitrateField    setIntValue: 1000];
275
276     [fVidQualityMatrix   selectCell: fVidBitrateCell];
277     [self videoMatrixChanged:nil];
278
279     /* Video framerate */
280     [fVidRatePopUp removeAllItems];
281         [fVidRatePopUp addItemWithTitle: NSLocalizedString( @"Same as source", @"" )];
282     for( int i = 0; i < hb_video_rates_count; i++ )
283     {
284         if ([[NSString stringWithCString: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%.3f",23.976]])
285                 {
286                         [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@",
287                                 [NSString stringWithCString: hb_video_rates[i].string], @" (NTSC Film)"]];
288                 }
289                 else if ([[NSString stringWithCString: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%d",25]])
290                 {
291                         [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@",
292                                 [NSString stringWithCString: hb_video_rates[i].string], @" (PAL Film/Video)"]];
293                 }
294                 else if ([[NSString stringWithCString: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%.2f",29.97]])
295                 {
296                         [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@",
297                                 [NSString stringWithCString: hb_video_rates[i].string], @" (NTSC Video)"]];
298                 }
299                 else
300                 {
301                         [fVidRatePopUp addItemWithTitle:
302                                 [NSString stringWithCString: hb_video_rates[i].string]];
303                 }
304     }
305     [fVidRatePopUp selectItemAtIndex: 0];
306         
307         /* Set Auto Crop to On at launch */
308     [fPictureController setAutoCrop:YES];
309         
310         /* Audio bitrate */
311     [fAudTrack1BitratePopUp removeAllItems];
312     for( int i = 0; i < hb_audio_bitrates_count; i++ )
313     {
314         [fAudTrack1BitratePopUp addItemWithTitle:
315                                 [NSString stringWithCString: hb_audio_bitrates[i].string]];
316
317     }
318     [fAudTrack1BitratePopUp selectItemAtIndex: hb_audio_bitrates_default];
319         
320     /* Audio samplerate */
321     [fAudTrack1RatePopUp removeAllItems];
322     for( int i = 0; i < hb_audio_rates_count; i++ )
323     {
324         [fAudTrack1RatePopUp addItemWithTitle:
325             [NSString stringWithCString: hb_audio_rates[i].string]];
326     }
327     [fAudTrack1RatePopUp selectItemAtIndex: hb_audio_rates_default];
328         
329     /* Bottom */
330     [fStatusField setStringValue: @""];
331
332     [self enableUI: NO];
333         [self setupToolbar];
334
335         /* We disable the Turbo 1st pass checkbox since we are not x264 */
336         [fVidTurboPassCheck setEnabled: NO];
337         [fVidTurboPassCheck setState: NSOffState];
338
339
340         /* lets get our default prefs here */
341         [self getDefaultPresets:nil];
342         /* lets initialize the current successful scancount here to 0 */
343         currentSuccessfulScanCount = 0;
344
345
346 }
347
348 - (void) enableUI: (bool) b
349 {
350     NSControl * controls[] =
351       { fSrcTitleField, fSrcTitlePopUp,
352         fSrcChapterField, fSrcChapterStartPopUp, fSrcChapterToField,
353         fSrcChapterEndPopUp, fSrcDuration1Field, fSrcDuration2Field,
354         fDstFormatField, fDstFormatPopUp, fDstFile1Field, fDstFile2Field,
355         fDstBrowseButton, fVidRateField, fVidRatePopUp,
356         fVidEncoderField, fVidEncoderPopUp, fVidQualityField,
357         fVidQualityMatrix, fVidGrayscaleCheck, fSubField, fSubPopUp,
358         fAudSourceLabel, fAudCodecLabel, fAudMixdownLabel, fAudSamplerateLabel, fAudBitrateLabel,
359         fAudTrack1Label, fAudTrack2Label, fAudTrack3Label, fAudTrack4Label,
360         fAudLang1PopUp, fAudLang2PopUp, fAudLang3PopUp, fAudLang4PopUp,
361         fAudTrack1CodecPopUp, fAudTrack2CodecPopUp, fAudTrack3CodecPopUp, fAudTrack4CodecPopUp,
362         fAudTrack1MixPopUp, fAudTrack2MixPopUp, fAudTrack3MixPopUp, fAudTrack4MixPopUp,
363         fAudTrack1RatePopUp, fAudTrack2RatePopUp, fAudTrack3RatePopUp, fAudTrack4RatePopUp,
364         fAudTrack1BitratePopUp, fAudTrack2BitratePopUp, fAudTrack3BitratePopUp, fAudTrack4BitratePopUp,
365         fAudDrcLabel, fAudTrack1DrcSlider, fAudTrack1DrcField, fAudTrack2DrcSlider,
366         fAudTrack2DrcField, fAudTrack3DrcSlider, fAudTrack3DrcField, fAudTrack4DrcSlider,fAudTrack4DrcField,
367         fPictureButton,fQueueStatus,fPicSettingARkeep, fPicSettingDeinterlace,fPicLabelSettings,fPicLabelSrc,
368         fPicLabelOutp,fPicSettingsSrc,fPicSettingsOutp,fPicSettingsAnamorphic,
369                 fPicLabelAr,fPicLabelDeinterlace,fPicSettingPAR,fPicLabelAnamorphic,fPresetsAdd,fPresetsDelete,
370                 fCreateChapterMarkers,fVidTurboPassCheck,fDstMp4LargeFileCheck,fPicLabelAutoCrop,
371                 fPicSettingAutoCrop,fPicSettingDetelecine,fPicLabelDetelecine,fPicLabelDenoise,fPicSettingDenoise,
372         fSubForcedCheck,fPicSettingDeblock,fPicLabelDeblock,fPicLabelDecomb,fPicSettingDecomb,fPresetsOutlineView,
373         fAudDrcLabel,fDstMp4HttpOptFileCheck,fDstMp4iPodFileCheck};
374
375     for( unsigned i = 0;
376          i < sizeof( controls ) / sizeof( NSControl * ); i++ )
377     {
378         if( [[controls[i] className] isEqualToString: @"NSTextField"] )
379         {
380             NSTextField * tf = (NSTextField *) controls[i];
381             if( ![tf isBezeled] )
382             {
383                 [tf setTextColor: b ? [NSColor controlTextColor] :
384                     [NSColor disabledControlTextColor]];
385                 continue;
386             }
387         }
388         [controls[i] setEnabled: b];
389
390     }
391
392         if (b) {
393
394         /* if we're enabling the interface, check if the audio mixdown controls need to be enabled or not */
395         /* these will have been enabled by the mass control enablement above anyway, so we're sense-checking it here */
396         [self setEnabledStateOfAudioMixdownControls:nil];
397         /* we also call calculatePictureSizing here to sense check if we already have vfr selected */
398         [self calculatePictureSizing:nil];
399         [self shouldEnableHttpMp4CheckBox: nil];
400
401         } else {
402
403                 [fPresetsOutlineView setEnabled: NO];
404
405         }
406
407     [self videoMatrixChanged:nil];
408     [fAdvancedOptions enableUI:b];
409 }
410
411
412 /***********************************************************************
413  * UpdateDockIcon
414  ***********************************************************************
415  * Shows a progression bar on the dock icon, filled according to
416  * 'progress' (0.0 <= progress <= 1.0).
417  * Called with progress < 0.0 or progress > 1.0, restores the original
418  * icon.
419  **********************************************************************/
420 - (void) UpdateDockIcon: (float) progress
421 {
422     NSImage * icon;
423     NSData * tiff;
424     NSBitmapImageRep * bmp;
425     uint32_t * pen;
426     uint32_t black = htonl( 0x000000FF );
427     uint32_t red   = htonl( 0xFF0000FF );
428     uint32_t white = htonl( 0xFFFFFFFF );
429     int row_start, row_end;
430     int i, j;
431
432     /* Get application original icon */
433     icon = [NSImage imageNamed: @"NSApplicationIcon"];
434
435     if( progress < 0.0 || progress > 1.0 )
436     {
437         [NSApp setApplicationIconImage: icon];
438         return;
439     }
440
441     /* Get it in a raw bitmap form */
442     tiff = [icon TIFFRepresentationUsingCompression:
443             NSTIFFCompressionNone factor: 1.0];
444     bmp = [NSBitmapImageRep imageRepWithData: tiff];
445     
446     /* Draw the progression bar */
447     /* It's pretty simple (ugly?) now, but I'm no designer */
448
449     row_start = 3 * (int) [bmp size].height / 4;
450     row_end   = 7 * (int) [bmp size].height / 8;
451
452     for( i = row_start; i < row_start + 2; i++ )
453     {
454         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
455         for( j = 0; j < (int) [bmp size].width; j++ )
456         {
457             pen[j] = black;
458         }
459     }
460     for( i = row_start + 2; i < row_end - 2; i++ )
461     {
462         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
463         pen[0] = black;
464         pen[1] = black;
465         for( j = 2; j < (int) [bmp size].width - 2; j++ )
466         {
467             if( j < 2 + (int) ( ( [bmp size].width - 4.0 ) * progress ) )
468             {
469                 pen[j] = red;
470             }
471             else
472             {
473                 pen[j] = white;
474             }
475         }
476         pen[j]   = black;
477         pen[j+1] = black;
478     }
479     for( i = row_end - 2; i < row_end; i++ )
480     {
481         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
482         for( j = 0; j < (int) [bmp size].width; j++ )
483         {
484             pen[j] = black;
485         }
486     }
487
488     /* Now update the dock icon */
489     tiff = [bmp TIFFRepresentationUsingCompression:
490             NSTIFFCompressionNone factor: 1.0];
491     icon = [[NSImage alloc] initWithData: tiff];
492     [NSApp setApplicationIconImage: icon];
493     [icon release];
494 }
495
496 - (void) updateUI: (NSTimer *) timer
497 {
498     
499     /* Update UI for fHandle (user scanning instance of libhb ) */
500     
501     hb_list_t  * list;
502     list = hb_get_titles( fHandle );
503     /* check to see if there has been a new scan done
504      this bypasses the constraints of HB_STATE_WORKING
505      not allowing setting a newly scanned source */
506         int checkScanCount = hb_get_scancount( fHandle );
507         if( checkScanCount > currentScanCount )
508         {
509                 currentScanCount = checkScanCount;
510         [fScanIndicator setIndeterminate: NO];
511         [fScanIndicator setDoubleValue: 0.0];
512         [fScanIndicator setHidden: YES];
513                 [self showNewScan:nil];
514         }
515     
516     hb_state_t s;
517     hb_get_state( fHandle, &s );
518     
519     switch( s.state )
520     {
521         case HB_STATE_IDLE:
522             break;
523 #define p s.param.scanning
524         case HB_STATE_SCANNING:
525                 {
526             [fSrcDVD2Field setStringValue: [NSString stringWithFormat:
527                                             NSLocalizedString( @"Scanning title %d of %d...", @"" ),
528                                             p.title_cur, p.title_count]];
529             [fScanIndicator setHidden: NO];
530             [fScanIndicator setDoubleValue: 100.0 * ( p.title_cur - 1 ) / p.title_count];
531             break;
532                 }
533 #undef p
534             
535 #define p s.param.scandone
536         case HB_STATE_SCANDONE:
537         {
538             [fScanIndicator setIndeterminate: NO];
539             [fScanIndicator setDoubleValue: 0.0];
540             [fScanIndicator setHidden: YES];
541                         [self writeToActivityLog:"ScanDone state received from fHandle"];
542             [self showNewScan:nil];
543             [[fWindow toolbar] validateVisibleItems];
544             
545                         break;
546         }
547 #undef p
548             
549 #define p s.param.working
550         case HB_STATE_WORKING:
551         {
552             
553             break;
554         }
555 #undef p
556             
557 #define p s.param.muxing
558         case HB_STATE_MUXING:
559         {
560             
561             break;
562         }
563 #undef p
564             
565         case HB_STATE_PAUSED:
566             break;
567             
568         case HB_STATE_WORKDONE:
569         {
570             break;
571         }
572     }
573     
574     
575     /* Update UI for fQueueEncodeLibhb */
576     // hb_list_t  * list;
577     // list = hb_get_titles( fQueueEncodeLibhb ); //fQueueEncodeLibhb
578     /* check to see if there has been a new scan done
579      this bypasses the constraints of HB_STATE_WORKING
580      not allowing setting a newly scanned source */
581         
582     checkScanCount = hb_get_scancount( fQueueEncodeLibhb );
583         if( checkScanCount > currentScanCount )
584         {
585                 currentScanCount = checkScanCount;
586         [self writeToActivityLog:"currentScanCount received from fQueueEncodeLibhb"];
587         }
588     
589     //hb_state_t s;
590     hb_get_state( fQueueEncodeLibhb, &s );
591     
592     switch( s.state )
593     {
594         case HB_STATE_IDLE:
595             break;
596 #define p s.param.scanning
597         case HB_STATE_SCANNING:
598                 {
599             [fStatusField setStringValue: [NSString stringWithFormat:
600                                            NSLocalizedString( @"Queue Scanning title %d of %d...", @"" ),
601                                            p.title_cur, p.title_count]];
602             
603             /* Set the status string in fQueueController as well */                               
604             [fQueueController setQueueStatusString: [NSString stringWithFormat:
605                                            NSLocalizedString( @"Queue Scanning title %d of %d...", @"" ),
606                                            p.title_cur, p.title_count]];
607             
608             [fRipIndicator setHidden: NO];
609             [fRipIndicator setDoubleValue: 100.0 * ( p.title_cur - 1 ) / p.title_count];
610             break;
611                 }
612 #undef p
613             
614 #define p s.param.scandone
615         case HB_STATE_SCANDONE:
616         {
617             [fRipIndicator setIndeterminate: NO];
618             [fRipIndicator setDoubleValue: 0.0];
619             
620                         [self writeToActivityLog:"ScanDone state received from fQueueEncodeLibhb"];
621             [self processNewQueueEncode];
622             [[fWindow toolbar] validateVisibleItems];
623             
624                         break;
625         }
626 #undef p
627             
628 #define p s.param.working
629         case HB_STATE_WORKING:
630         {
631             float progress_total;
632             NSMutableString * string;
633                         /* Update text field */
634                         string = [NSMutableString stringWithFormat: NSLocalizedString( @"Encoding: pass %d of %d, %.2f %%", @"" ), p.job_cur, p.job_count, 100.0 * p.progress];
635             
636                         if( p.seconds > -1 )
637             {
638                 [string appendFormat:
639                  NSLocalizedString( @" (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)", @"" ),
640                  p.rate_cur, p.rate_avg, p.hours, p.minutes, p.seconds];
641             }
642             
643             [fStatusField setStringValue: string];
644             /* Set the status string in fQueueController as well */
645             [fQueueController setQueueStatusString: string];
646             /* Update slider */
647                         progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count;
648             [fRipIndicator setIndeterminate: NO];
649             [fRipIndicator setDoubleValue: 100.0 * progress_total];
650             
651             // If progress bar hasn't been revealed at the bottom of the window, do
652             // that now. This code used to be in doRip. I moved it to here to handle
653             // the case where hb_start is called by HBQueueController and not from
654             // HBController.
655             if( !fRipIndicatorShown )
656             {
657                 NSRect frame = [fWindow frame];
658                 if( frame.size.width <= 591 )
659                     frame.size.width = 591;
660                 frame.size.height += 36;
661                 frame.origin.y -= 36;
662                 [fWindow setFrame:frame display:YES animate:YES];
663                 fRipIndicatorShown = YES;
664                 /* We check to see if we need to warn the user that the computer will go to sleep
665                  or shut down when encoding is finished */
666                 [self remindUserOfSleepOrShutdown];
667             }
668             
669             /* Update dock icon */
670             [self UpdateDockIcon: progress_total];
671             
672             break;
673         }
674 #undef p
675             
676 #define p s.param.muxing
677         case HB_STATE_MUXING:
678         {
679             /* Update text field */
680             [fStatusField setStringValue: NSLocalizedString( @"Muxing...", @"" )];
681             /* Set the status string in fQueueController as well */
682             [fQueueController setQueueStatusString: NSLocalizedString( @"Muxing...", @"" )];
683             /* Update slider */
684             [fRipIndicator setIndeterminate: YES];
685             [fRipIndicator startAnimation: nil];
686             
687             /* Update dock icon */
688             [self UpdateDockIcon: 1.0];
689             
690                         break;
691         }
692 #undef p
693             
694         case HB_STATE_PAUSED:
695                     [fStatusField setStringValue: NSLocalizedString( @"Paused", @"" )];
696             [fQueueController setQueueStatusString: NSLocalizedString( @"Paused", @"" )];
697             
698                         break;
699             
700         case HB_STATE_WORKDONE:
701         {
702             // HB_STATE_WORKDONE happpens as a result of libhb finishing all its jobs
703             // or someone calling hb_stop. In the latter case, hb_stop does not clear
704             // out the remaining passes/jobs in the queue. We'll do that here.
705             
706             // Delete all remaining jobs of this encode.
707             [fStatusField setStringValue: NSLocalizedString( @"Encode Finished.", @"" )];
708             /* Set the status string in fQueueController as well */
709             [fQueueController setQueueStatusString: NSLocalizedString( @"Encode Finished.", @"" )];
710             [fRipIndicator setIndeterminate: NO];
711             [fRipIndicator setDoubleValue: 0.0];
712             [[fWindow toolbar] validateVisibleItems];
713             
714             /* Restore dock icon */
715             [self UpdateDockIcon: -1.0];
716             
717             if( fRipIndicatorShown )
718             {
719                 NSRect frame = [fWindow frame];
720                 if( frame.size.width <= 591 )
721                                     frame.size.width = 591;
722                 frame.size.height += -36;
723                 frame.origin.y -= -36;
724                 [fWindow setFrame:frame display:YES animate:YES];
725                                 fRipIndicatorShown = NO;
726                         }
727             
728                         /* Check to see if the encode state has not been cancelled
729              to determine if we should check for encode done notifications */
730                         if( fEncodeState != 2 )
731             {
732                 NSString *pathOfFinishedEncode;
733                 /* Get the output file name for the finished encode */
734                 pathOfFinishedEncode = [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"DestinationPath"];
735                 
736                 /* Both the Growl Alert and Sending to MetaX can be done as encodes roll off the queue */
737                 /* Growl alert */
738                 [self showGrowlDoneNotification:pathOfFinishedEncode];
739                 /* Send to MetaX */
740                 [self sendToMetaX:pathOfFinishedEncode];
741                 
742                 /* since we have successfully completed an encode, we increment the queue counter */
743                 [self incrementQueueItemDone:nil]; 
744                 
745                 /* all end of queue actions below need to be done after all queue encodes have finished 
746                  * and there are no pending jobs left to process
747                  */
748                 if (fPendingCount == 0)
749                 {
750                     /* If Alert Window or Window and Growl has been selected */
751                     if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window"] ||
752                        [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window And Growl"] )
753                     {
754                         /*On Screen Notification*/
755                         int status;
756                         NSBeep();
757                         status = NSRunAlertPanel(@"Put down that cocktail...",@"Your HandBrake queue is done!", @"OK", nil, nil);
758                         [NSApp requestUserAttention:NSCriticalRequest];
759                     }
760                     
761                     /* If sleep has been selected */
762                     if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Put Computer To Sleep"] )
763                     {
764                         /* Sleep */
765                         NSDictionary* errorDict;
766                         NSAppleEventDescriptor* returnDescriptor = nil;
767                         NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource:
768                                                        @"tell application \"Finder\" to sleep"];
769                         returnDescriptor = [scriptObject executeAndReturnError: &errorDict];
770                         [scriptObject release];
771                     }
772                     /* If Shutdown has been selected */
773                     if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Shut Down Computer"] )
774                     {
775                         /* Shut Down */
776                         NSDictionary* errorDict;
777                         NSAppleEventDescriptor* returnDescriptor = nil;
778                         NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource:
779                                                        @"tell application \"Finder\" to shut down"];
780                         returnDescriptor = [scriptObject executeAndReturnError: &errorDict];
781                         [scriptObject release];
782                     }
783                     
784                 }
785                 
786                 
787             }
788             
789             break;
790         }
791     }
792     
793 }
794
795 /* We use this to write messages to stderr from the macgui which show up in the activity window and log*/
796 - (void) writeToActivityLog:(char *) format, ...
797 {
798     va_list args;
799     va_start(args, format);
800     if (format != nil)
801     {
802         char str[1024];
803         vsnprintf( str, 1024, format, args );
804
805         time_t _now = time( NULL );
806         struct tm * now  = localtime( &_now );
807         fprintf(stderr, "[%02d:%02d:%02d] macgui: %s\n", now->tm_hour, now->tm_min, now->tm_sec, str );
808     }
809     va_end(args);
810 }
811
812 #pragma mark -
813 #pragma mark Toolbar
814 // ============================================================
815 // NSToolbar Related Methods
816 // ============================================================
817
818 - (void) setupToolbar {
819     NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier: @"HandBrake Toolbar"] autorelease];
820
821     [toolbar setAllowsUserCustomization: YES];
822     [toolbar setAutosavesConfiguration: YES];
823     [toolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
824
825     [toolbar setDelegate: self];
826
827     [fWindow setToolbar: toolbar];
828 }
829
830 - (NSToolbarItem *) toolbar: (NSToolbar *)toolbar itemForItemIdentifier:
831     (NSString *) itemIdent willBeInsertedIntoToolbar:(BOOL) willBeInserted {
832     NSToolbarItem * item = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdent] autorelease];
833
834     if ([itemIdent isEqualToString: ToggleDrawerIdentifier])
835     {
836         [item setLabel: @"Toggle Presets"];
837         [item setPaletteLabel: @"Toggler Presets"];
838         [item setToolTip: @"Open/Close Preset Drawer"];
839         [item setImage: [NSImage imageNamed: @"Drawer"]];
840         [item setTarget: self];
841         [item setAction: @selector(toggleDrawer:)];
842         [item setAutovalidates: NO];
843     }
844     else if ([itemIdent isEqualToString: StartEncodingIdentifier])
845     {
846         [item setLabel: @"Start"];
847         [item setPaletteLabel: @"Start Encoding"];
848         [item setToolTip: @"Start Encoding"];
849         [item setImage: [NSImage imageNamed: @"Play"]];
850         [item setTarget: self];
851         [item setAction: @selector(Rip:)];
852     }
853     else if ([itemIdent isEqualToString: ShowQueueIdentifier])
854     {
855         [item setLabel: @"Show Queue"];
856         [item setPaletteLabel: @"Show Queue"];
857         [item setToolTip: @"Show Queue"];
858         [item setImage: [NSImage imageNamed: @"Queue"]];
859         [item setTarget: self];
860         [item setAction: @selector(showQueueWindow:)];
861         [item setAutovalidates: NO];
862     }
863     else if ([itemIdent isEqualToString: AddToQueueIdentifier])
864     {
865         [item setLabel: @"Add to Queue"];
866         [item setPaletteLabel: @"Add to Queue"];
867         [item setToolTip: @"Add to Queue"];
868         [item setImage: [NSImage imageNamed: @"AddToQueue"]];
869         [item setTarget: self];
870         [item setAction: @selector(addToQueue:)];
871     }
872     else if ([itemIdent isEqualToString: PauseEncodingIdentifier])
873     {
874         [item setLabel: @"Pause"];
875         [item setPaletteLabel: @"Pause Encoding"];
876         [item setToolTip: @"Pause Encoding"];
877         [item setImage: [NSImage imageNamed: @"Pause"]];
878         [item setTarget: self];
879         [item setAction: @selector(Pause:)];
880     }
881     else if ([itemIdent isEqualToString: ShowActivityIdentifier]) {
882         [item setLabel: @"Activity Window"];
883         [item setPaletteLabel: @"Show Activity Window"];
884         [item setToolTip: @"Show Activity Window"];
885         [item setImage: [NSImage imageNamed: @"ActivityWindow"]];
886         [item setTarget: self];
887         [item setAction: @selector(showDebugOutputPanel:)];
888         [item setAutovalidates: NO];
889     }
890     else if ([itemIdent isEqualToString: ChooseSourceIdentifier])
891     {
892         [item setLabel: @"Source"];
893         [item setPaletteLabel: @"Source"];
894         [item setToolTip: @"Choose Video Source"];
895         [item setImage: [NSImage imageNamed: @"Source"]];
896         [item setTarget: self];
897         [item setAction: @selector(browseSources:)];
898     }
899     else
900     {
901         return nil;
902     }
903
904     return item;
905 }
906
907 - (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar
908 {
909     return [NSArray arrayWithObjects: ChooseSourceIdentifier, NSToolbarSeparatorItemIdentifier, StartEncodingIdentifier,
910         PauseEncodingIdentifier, AddToQueueIdentifier, ShowQueueIdentifier, NSToolbarFlexibleSpaceItemIdentifier, 
911                 NSToolbarSpaceItemIdentifier, ShowActivityIdentifier, ToggleDrawerIdentifier, nil];
912 }
913
914 - (NSArray *) toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar
915 {
916     return [NSArray arrayWithObjects:  StartEncodingIdentifier, PauseEncodingIdentifier, AddToQueueIdentifier,
917         ChooseSourceIdentifier, ShowQueueIdentifier, ShowActivityIdentifier, ToggleDrawerIdentifier,
918         NSToolbarCustomizeToolbarItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier,
919         NSToolbarSpaceItemIdentifier, NSToolbarSeparatorItemIdentifier, nil];
920 }
921
922 - (BOOL) validateToolbarItem: (NSToolbarItem *) toolbarItem
923 {
924     NSString * ident = [toolbarItem itemIdentifier];
925         
926     if (fHandle)
927     {
928         hb_state_t s;
929         hb_get_state2( fQueueEncodeLibhb, &s );
930         
931         if (s.state == HB_STATE_WORKING || s.state == HB_STATE_MUXING)
932         {
933             if ([ident isEqualToString: StartEncodingIdentifier])
934             {
935                 [toolbarItem setImage: [NSImage imageNamed: @"Stop"]];
936                 [toolbarItem setLabel: @"Stop"];
937                 [toolbarItem setPaletteLabel: @"Stop"];
938                 [toolbarItem setToolTip: @"Stop Encoding"];
939                 return YES;
940             }
941             if ([ident isEqualToString: PauseEncodingIdentifier])
942             {
943                 [toolbarItem setImage: [NSImage imageNamed: @"Pause"]];
944                 [toolbarItem setLabel: @"Pause"];
945                 [toolbarItem setPaletteLabel: @"Pause Encoding"];
946                 [toolbarItem setToolTip: @"Pause Encoding"];
947                 return YES;
948             }
949             if (SuccessfulScan)
950                 if ([ident isEqualToString: AddToQueueIdentifier])
951                     return YES;
952         }
953         else if (s.state == HB_STATE_PAUSED)
954         {
955             if ([ident isEqualToString: PauseEncodingIdentifier])
956             {
957                 [toolbarItem setImage: [NSImage imageNamed: @"Play"]];
958                 [toolbarItem setLabel: @"Resume"];
959                 [toolbarItem setPaletteLabel: @"Resume Encoding"];
960                 [toolbarItem setToolTip: @"Resume Encoding"];
961                 return YES;
962             }
963             if ([ident isEqualToString: StartEncodingIdentifier])
964                 return YES;
965             if ([ident isEqualToString: AddToQueueIdentifier])
966                 return YES;
967         }
968         else if (s.state == HB_STATE_SCANNING)
969             return NO;
970         else if (s.state == HB_STATE_WORKDONE || s.state == HB_STATE_SCANDONE || SuccessfulScan)
971         {
972             if ([ident isEqualToString: StartEncodingIdentifier])
973             {
974                 [toolbarItem setImage: [NSImage imageNamed: @"Play"]];
975                 if (hb_count(fHandle) > 0)
976                     [toolbarItem setLabel: @"Start Queue"];
977                 else
978                     [toolbarItem setLabel: @"Start"];
979                 [toolbarItem setPaletteLabel: @"Start Encoding"];
980                 [toolbarItem setToolTip: @"Start Encoding"];
981                 return YES;
982             }
983             if ([ident isEqualToString: AddToQueueIdentifier])
984                 return YES;
985         }
986
987     }
988     /* If there are any pending queue items, make sure the start/stop button is active */
989     if ([ident isEqualToString: StartEncodingIdentifier] && fPendingCount > 0)
990         return YES;
991     if ([ident isEqualToString: ShowQueueIdentifier])
992         return YES;
993     if ([ident isEqualToString: ToggleDrawerIdentifier])
994         return YES;
995     if ([ident isEqualToString: ChooseSourceIdentifier])
996         return YES;
997     if ([ident isEqualToString: ShowActivityIdentifier])
998         return YES;
999     
1000     return NO;
1001 }
1002
1003 - (BOOL) validateMenuItem: (NSMenuItem *) menuItem
1004 {
1005     SEL action = [menuItem action];
1006     
1007     hb_state_t s;
1008     hb_get_state2( fHandle, &s );
1009     
1010     if (fHandle)
1011     {
1012         if (action == @selector(addToQueue:) || action == @selector(showPicturePanel:) || action == @selector(showAddPresetPanel:))
1013             return SuccessfulScan && [fWindow attachedSheet] == nil;
1014         
1015         if (action == @selector(browseSources:))
1016         {
1017             if (s.state == HB_STATE_SCANNING)
1018                 return NO;
1019             else
1020                 return [fWindow attachedSheet] == nil;
1021         }
1022         if (action == @selector(selectDefaultPreset:))
1023             return [fPresetsOutlineView selectedRow] >= 0 && [fWindow attachedSheet] == nil;
1024         if (action == @selector(Pause:))
1025         {
1026             if (s.state == HB_STATE_WORKING)
1027             {
1028                 if(![[menuItem title] isEqualToString:@"Pause Encoding"])
1029                     [menuItem setTitle:@"Pause Encoding"];
1030                 return YES;
1031             }
1032             else if (s.state == HB_STATE_PAUSED)
1033             {
1034                 if(![[menuItem title] isEqualToString:@"Resume Encoding"])
1035                     [menuItem setTitle:@"Resume Encoding"];
1036                 return YES;
1037             }
1038             else
1039                 return NO;
1040         }
1041         if (action == @selector(Rip:))
1042         {
1043             if (s.state == HB_STATE_WORKING || s.state == HB_STATE_MUXING || s.state == HB_STATE_PAUSED)
1044             {
1045                 if(![[menuItem title] isEqualToString:@"Stop Encoding"])
1046                     [menuItem setTitle:@"Stop Encoding"];
1047                 return YES;
1048             }
1049             else if (SuccessfulScan)
1050             {
1051                 if(![[menuItem title] isEqualToString:@"Start Encoding"])
1052                     [menuItem setTitle:@"Start Encoding"];
1053                 return [fWindow attachedSheet] == nil;
1054             }
1055             else
1056                 return NO;
1057         }
1058     }
1059     if( action == @selector(setDefaultPreset:) )
1060     {
1061         return [fPresetsOutlineView selectedRow] != -1;
1062     }
1063
1064     return YES;
1065 }
1066
1067 #pragma mark -
1068 #pragma mark Encode Done Actions
1069 // register a test notification and make
1070 // it enabled by default
1071 #define SERVICE_NAME @"Encode Done"
1072 - (NSDictionary *)registrationDictionaryForGrowl 
1073
1074     NSDictionary *registrationDictionary = [NSDictionary dictionaryWithObjectsAndKeys: 
1075     [NSArray arrayWithObjects:SERVICE_NAME,nil], GROWL_NOTIFICATIONS_ALL, 
1076     [NSArray arrayWithObjects:SERVICE_NAME,nil], GROWL_NOTIFICATIONS_DEFAULT, 
1077     nil]; 
1078
1079     return registrationDictionary; 
1080
1081
1082 -(void)showGrowlDoneNotification:(NSString *) filePath
1083 {
1084     /* This end of encode action is called as each encode rolls off of the queue */
1085     NSString * finishedEncode = filePath;
1086     /* strip off the path to just show the file name */
1087     finishedEncode = [finishedEncode lastPathComponent];
1088     if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Growl Notification"] || 
1089         [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window And Growl"])
1090     {
1091         NSString * growlMssg = [NSString stringWithFormat: @"your HandBrake encode %@ is done!",finishedEncode];
1092         [GrowlApplicationBridge 
1093          notifyWithTitle:@"Put down that cocktail..." 
1094          description:growlMssg 
1095          notificationName:SERVICE_NAME
1096          iconData:nil 
1097          priority:0 
1098          isSticky:1 
1099          clickContext:nil];
1100     }
1101     
1102 }
1103 -(void)sendToMetaX:(NSString *) filePath
1104 {
1105     /* This end of encode action is called as each encode rolls off of the queue */
1106     if([[NSUserDefaults standardUserDefaults] boolForKey: @"sendToMetaX"] == YES)
1107     {
1108         NSAppleScript *myScript = [[NSAppleScript alloc] initWithSource: [NSString stringWithFormat: @"%@%@%@", @"tell application \"MetaX\" to open (POSIX file \"", filePath, @"\")"]];
1109         [myScript executeAndReturnError: nil];
1110         [myScript release];
1111     }
1112 }
1113 #pragma mark -
1114 #pragma mark Get New Source
1115
1116 /*Opens the source browse window, called from Open Source widgets */
1117 - (IBAction) browseSources: (id) sender
1118 {
1119     NSOpenPanel * panel;
1120         
1121     panel = [NSOpenPanel openPanel];
1122     [panel setAllowsMultipleSelection: NO];
1123     [panel setCanChooseFiles: YES];
1124     [panel setCanChooseDirectories: YES ];
1125     NSString * sourceDirectory;
1126         if ([[NSUserDefaults standardUserDefaults] stringForKey:@"LastSourceDirectory"])
1127         {
1128                 sourceDirectory = [[NSUserDefaults standardUserDefaults] stringForKey:@"LastSourceDirectory"];
1129         }
1130         else
1131         {
1132                 sourceDirectory = @"~/Desktop";
1133                 sourceDirectory = [sourceDirectory stringByExpandingTildeInPath];
1134         }
1135     /* we open up the browse sources sheet here and call for browseSourcesDone after the sheet is closed
1136         * to evaluate whether we want to specify a title, we pass the sender in the contextInfo variable
1137         */
1138     [panel beginSheetForDirectory: sourceDirectory file: nil types: nil
1139                    modalForWindow: fWindow modalDelegate: self
1140                    didEndSelector: @selector( browseSourcesDone:returnCode:contextInfo: )
1141                       contextInfo: sender]; 
1142 }
1143
1144 - (void) browseSourcesDone: (NSOpenPanel *) sheet
1145                 returnCode: (int) returnCode contextInfo: (void *) contextInfo
1146 {
1147     /* we convert the sender content of contextInfo back into a variable called sender
1148      * mostly just for consistency for evaluation later
1149      */
1150     id sender = (id)contextInfo;
1151     /* User selected a file to open */
1152         if( returnCode == NSOKButton )
1153     {
1154             /* Free display name allocated previously by this code */
1155         [browsedSourceDisplayName release];
1156        
1157         NSString *scanPath = [[sheet filenames] objectAtIndex: 0];
1158         /* we set the last searched source directory in the prefs here */
1159         NSString *sourceDirectory = [scanPath stringByDeletingLastPathComponent];
1160         [[NSUserDefaults standardUserDefaults] setObject:sourceDirectory forKey:@"LastSourceDirectory"];
1161         /* we order out sheet, which is the browse window as we need to open
1162          * the title selection sheet right away
1163          */
1164         [sheet orderOut: self];
1165         
1166         if (sender == fOpenSourceTitleMMenu)
1167         {
1168             /* We put the chosen source path in the source display text field for the
1169              * source title selection sheet in which the user specifies the specific title to be
1170              * scanned  as well as the short source name in fSrcDsplyNameTitleScan just for display
1171              * purposes in the title panel
1172              */
1173             /* Full Path */
1174             [fScanSrcTitlePathField setStringValue:scanPath];
1175             NSString *displayTitlescanSourceName;
1176
1177             if ([[scanPath lastPathComponent] isEqualToString: @"VIDEO_TS"])
1178             {
1179                 /* If VIDEO_TS Folder is chosen, choose its parent folder for the source display name
1180                  we have to use the title->dvd value so we get the proper name of the volume if a physical dvd is the source*/
1181                 displayTitlescanSourceName = [[scanPath stringByDeletingLastPathComponent] lastPathComponent];
1182             }
1183             else
1184             {
1185                 /* if not the VIDEO_TS Folder, we can assume the chosen folder is the source name */
1186                 displayTitlescanSourceName = [scanPath lastPathComponent];
1187             }
1188             /* we set the source display name in the title selection dialogue */
1189             [fSrcDsplyNameTitleScan setStringValue:displayTitlescanSourceName];
1190             /* we set the attempted scans display name for main window to displayTitlescanSourceName*/
1191             browsedSourceDisplayName = [displayTitlescanSourceName retain];
1192             /* We show the actual sheet where the user specifies the title to be scanned
1193              * as we are going to do a title specific scan
1194              */
1195             [self showSourceTitleScanPanel:nil];
1196         }
1197         else
1198         {
1199             /* We are just doing a standard full source scan, so we specify "0" to libhb */
1200             NSString *path = [[sheet filenames] objectAtIndex: 0];
1201             
1202             /* We check to see if the chosen file at path is a package */
1203             if ([[NSWorkspace sharedWorkspace] isFilePackageAtPath:path])
1204             {
1205                 [self writeToActivityLog: "trying to open a package at: %s", [path UTF8String]];
1206                 /* We check to see if this is an .eyetv package */
1207                 if ([[path pathExtension] isEqualToString: @"eyetv"])
1208                 {
1209                     [self writeToActivityLog:"trying to open eyetv package"];
1210                     /* We're looking at an EyeTV package - try to open its enclosed
1211                      .mpg media file */
1212                      browsedSourceDisplayName = [[[path stringByDeletingPathExtension] lastPathComponent] retain];
1213                     NSString *mpgname;
1214                     int n = [[path stringByAppendingString: @"/"]
1215                              completePathIntoString: &mpgname caseSensitive: NO
1216                              matchesIntoArray: nil
1217                              filterTypes: [NSArray arrayWithObject: @"mpg"]];
1218                     if (n > 0)
1219                     {
1220                         /* Found an mpeg inside the eyetv package, make it our scan path 
1221                         and call performScan on the enclosed mpeg */
1222                         path = mpgname;
1223                         [self writeToActivityLog:"found mpeg in eyetv package"];
1224                         [self performScan:path scanTitleNum:0];
1225                     }
1226                     else
1227                     {
1228                         /* We did not find an mpeg file in our package, so we do not call performScan */
1229                         [self writeToActivityLog:"no valid mpeg in eyetv package"];
1230                     }
1231                 }
1232                 /* We check to see if this is a .dvdmedia package */
1233                 else if ([[path pathExtension] isEqualToString: @"dvdmedia"])
1234                 {
1235                     /* path IS a package - but dvdmedia packages can be treaded like normal directories */
1236                     browsedSourceDisplayName = [[[path stringByDeletingPathExtension] lastPathComponent] retain];
1237                     [self writeToActivityLog:"trying to open dvdmedia package"];
1238                     [self performScan:path scanTitleNum:0];
1239                 }
1240                 else
1241                 {
1242                     /* The package is not an eyetv package, so we do not call performScan */
1243                     [self writeToActivityLog:"unable to open package"];
1244                 }
1245             }
1246             else // path is not a package, so we treat it as a dvd parent folder or VIDEO_TS folder
1247             {
1248                 /* path is not a package, so we call perform scan directly on our file */
1249                 if ([[path lastPathComponent] isEqualToString: @"VIDEO_TS"])
1250                 {
1251                     [self writeToActivityLog:"trying to open video_ts folder (video_ts folder chosen)"];
1252                     /* If VIDEO_TS Folder is chosen, choose its parent folder for the source display name*/
1253                     browsedSourceDisplayName = [[[path stringByDeletingLastPathComponent] lastPathComponent] retain];
1254                 }
1255                 else
1256                 {
1257                     [self writeToActivityLog:"trying to open video_ts folder (parent directory chosen)"];
1258                     /* if not the VIDEO_TS Folder, we can assume the chosen folder is the source name */
1259                     /* make sure we remove any path extension as this can also be an '.mpg' file */
1260                     browsedSourceDisplayName = [[path lastPathComponent] retain];
1261                 }
1262                 [self performScan:path scanTitleNum:0];
1263             }
1264
1265         }
1266
1267     }
1268 }
1269
1270 /* Here we open the title selection sheet where we can specify an exact title to be scanned */
1271 - (IBAction) showSourceTitleScanPanel: (id) sender
1272 {
1273     /* We default the title number to be scanned to "0" which results in a full source scan, unless the
1274     * user changes it
1275     */
1276     [fScanSrcTitleNumField setStringValue: @"0"];
1277         /* Show the panel */
1278         [NSApp beginSheet:fScanSrcTitlePanel modalForWindow:fWindow modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
1279 }
1280
1281 - (IBAction) closeSourceTitleScanPanel: (id) sender
1282 {
1283     [NSApp endSheet: fScanSrcTitlePanel];
1284     [fScanSrcTitlePanel orderOut: self];
1285
1286     if(sender == fScanSrcTitleOpenButton)
1287     {
1288         /* We setup the scan status in the main window to indicate a source title scan */
1289         [fSrcDVD2Field setStringValue: @"Opening a new source title ..."];
1290                 [fScanIndicator setHidden: NO];
1291         [fScanIndicator setIndeterminate: YES];
1292         [fScanIndicator startAnimation: nil];
1293                 
1294         /* We use the performScan method to actually perform the specified scan passing the path and the title
1295             * to be scanned
1296             */
1297         [self performScan:[fScanSrcTitlePathField stringValue] scanTitleNum:[fScanSrcTitleNumField intValue]];
1298     }
1299 }
1300
1301 /* Here we actually tell hb_scan to perform the source scan, using the path to source and title number*/
1302 - (void) performScan:(NSString *) scanPath scanTitleNum: (int) scanTitleNum
1303 {
1304     /* set the bool applyQueueToScan so that we dont apply a queue setting to the final scan */
1305     applyQueueToScan = NO;
1306     /* use a bool to determine whether or not we can decrypt using vlc */
1307     BOOL cancelScanDecrypt = 0;
1308     NSString *path = scanPath;
1309     HBDVDDetector *detector = [HBDVDDetector detectorForPath:path];
1310
1311     // Notify ChapterTitles that there's no title
1312     [fChapterTitlesDelegate resetWithTitle:nil];
1313     [fChapterTable reloadData];
1314
1315     [self enableUI: NO];
1316
1317     if( [detector isVideoDVD] )
1318     {
1319         // The chosen path was actually on a DVD, so use the raw block
1320         // device path instead.
1321         path = [detector devicePath];
1322         [self writeToActivityLog: "trying to open a physical dvd at: %s", [scanPath UTF8String]];
1323
1324         /* lets check for vlc here to make sure we have a dylib available to use for decrypting */
1325         NSString *vlcPath = @"/Applications/VLC.app";
1326         NSFileManager * fileManager = [NSFileManager defaultManager];
1327             if ([fileManager fileExistsAtPath:vlcPath] == 0) 
1328             {
1329             /*vlc not found in /Applications so we set the bool to cancel scanning to 1 */
1330             cancelScanDecrypt = 1;
1331             [self writeToActivityLog: "VLC app not found for decrypting physical dvd"];
1332             int status;
1333             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");
1334             [NSApp requestUserAttention:NSCriticalRequest];
1335             
1336             if (status == NSAlertDefaultReturn)
1337             {
1338                 /* User chose to go download vlc (as they rightfully should) so we send them to the vlc site */
1339                 [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.videolan.org/"]];
1340             }
1341             else if (status == NSAlertAlternateReturn)
1342             {
1343             /* User chose to cancel the scan */
1344             [self writeToActivityLog: "cannot open physical dvd , scan cancelled"];
1345             }
1346             else
1347             {
1348             /* 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 */
1349             cancelScanDecrypt = 0;
1350             [self writeToActivityLog: "user overrode vlc warning -trying to open physical dvd without decryption"];
1351             }
1352
1353         }
1354         else
1355         {
1356             /* VLC was found in /Applications so all is well, we can carry on using vlc's libdvdcss.dylib for decrypting if needed */
1357             [self writeToActivityLog: "VLC app found for decrypting physical dvd"];
1358         }
1359     }
1360
1361     if (cancelScanDecrypt == 0)
1362     {
1363         /* we actually pass the scan off to libhb here */
1364         /* If there is no title number passed to scan, we use "0"
1365          * which causes the default behavior of a full source scan
1366          */
1367         if (!scanTitleNum)
1368         {
1369             scanTitleNum = 0;
1370         }
1371         if (scanTitleNum > 0)
1372         {
1373             [self writeToActivityLog: "scanning specifically for title: %d", scanTitleNum];
1374         }
1375
1376         hb_scan( fHandle, [path UTF8String], scanTitleNum );
1377         [fSrcDVD2Field setStringValue:@"Scanning new source ..."];
1378     }
1379 }
1380
1381 - (IBAction) showNewScan:(id)sender
1382 {
1383     hb_list_t  * list;
1384         hb_title_t * title;
1385         int indxpri=0;    // Used to search the longuest title (default in combobox)
1386         int longuestpri=0; // Used to search the longuest title (default in combobox)
1387     
1388
1389         list = hb_get_titles( fHandle );
1390         
1391         if( !hb_list_count( list ) )
1392         {
1393             /* We display a message if a valid dvd source was not chosen */
1394             [fSrcDVD2Field setStringValue: @"No Valid Source Found"];
1395             SuccessfulScan = NO;
1396             
1397             // Notify ChapterTitles that there's no title
1398             [fChapterTitlesDelegate resetWithTitle:nil];
1399             [fChapterTable reloadData];
1400         }
1401         else
1402         {
1403             /* We increment the successful scancount here by one,
1404              which we use at the end of this function to tell the gui
1405              if this is the first successful scan since launch and whether
1406              or not we should set all settings to the defaults */
1407             
1408             currentSuccessfulScanCount++;
1409             
1410             [[fWindow toolbar] validateVisibleItems];
1411             
1412             [fSrcTitlePopUp removeAllItems];
1413             for( int i = 0; i < hb_list_count( list ); i++ )
1414             {
1415                 title = (hb_title_t *) hb_list_item( list, i );
1416                 
1417                 currentSource = [NSString stringWithUTF8String: title->name];
1418                 /*Set DVD Name at top of window with the browsedSourceDisplayName grokked right before -performScan */
1419                 [fSrcDVD2Field setStringValue:browsedSourceDisplayName];
1420                 
1421                 /* Use the dvd name in the default output field here
1422                  May want to add code to remove blank spaces for some dvd names*/
1423                 /* Check to see if the last destination has been set,use if so, if not, use Desktop */
1424                 if ([[NSUserDefaults standardUserDefaults] stringForKey:@"LastDestinationDirectory"])
1425                 {
1426                     [fDstFile2Field setStringValue: [NSString stringWithFormat:
1427                                                      @"%@/%@.mp4", [[NSUserDefaults standardUserDefaults] stringForKey:@"LastDestinationDirectory"],[browsedSourceDisplayName stringByDeletingPathExtension]]];
1428                 }
1429                 else
1430                 {
1431                     [fDstFile2Field setStringValue: [NSString stringWithFormat:
1432                                                      @"%@/Desktop/%@.mp4", NSHomeDirectory(),[browsedSourceDisplayName stringByDeletingPathExtension]]];
1433                 }
1434                 
1435                 
1436                 if (longuestpri < title->hours*60*60 + title->minutes *60 + title->seconds)
1437                 {
1438                     longuestpri=title->hours*60*60 + title->minutes *60 + title->seconds;
1439                     indxpri=i;
1440                 }
1441                 
1442                 [fSrcTitlePopUp addItemWithTitle: [NSString
1443                                                    stringWithFormat: @"%d - %02dh%02dm%02ds",
1444                                                    title->index, title->hours, title->minutes,
1445                                                    title->seconds]];
1446             }
1447             
1448             // Select the longuest title
1449             [fSrcTitlePopUp selectItemAtIndex: indxpri];
1450             [self titlePopUpChanged:nil];
1451             
1452             SuccessfulScan = YES;
1453             [self enableUI: YES];
1454
1455                 /* if its the initial successful scan after awakeFromNib */
1456                 if (currentSuccessfulScanCount == 1)
1457                 {
1458                     [self selectDefaultPreset:nil];
1459                     /* initially set deinterlace to 0, will be overridden reset by the default preset anyway */
1460                     //[fPictureController setDeinterlace:0];
1461                     
1462                     /* lets set Denoise to index 0 or "None" since this is the first scan */
1463                     //[fPictureController setDenoise:0];
1464                     
1465                     [fPictureController setInitialPictureFilters];
1466                 }
1467
1468             
1469         }
1470
1471 }
1472
1473
1474 #pragma mark -
1475 #pragma mark New Output Destination
1476
1477 - (IBAction) browseFile: (id) sender
1478 {
1479     /* Open a panel to let the user choose and update the text field */
1480     NSSavePanel * panel = [NSSavePanel savePanel];
1481         /* We get the current file name and path from the destination field here */
1482         [panel beginSheetForDirectory: [[fDstFile2Field stringValue] stringByDeletingLastPathComponent] file: [[fDstFile2Field stringValue] lastPathComponent]
1483                                    modalForWindow: fWindow modalDelegate: self
1484                                    didEndSelector: @selector( browseFileDone:returnCode:contextInfo: )
1485                                           contextInfo: NULL];
1486 }
1487
1488 - (void) browseFileDone: (NSSavePanel *) sheet
1489     returnCode: (int) returnCode contextInfo: (void *) contextInfo
1490 {
1491     if( returnCode == NSOKButton )
1492     {
1493         [fDstFile2Field setStringValue: [sheet filename]];
1494     }
1495 }
1496
1497
1498 #pragma mark -
1499 #pragma mark Main Window Control
1500
1501 - (IBAction) openMainWindow: (id) sender
1502 {
1503     [fWindow  makeKeyAndOrderFront:nil];
1504 }
1505
1506 - (BOOL) windowShouldClose: (id) sender
1507 {
1508     return YES;
1509 }
1510
1511 - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag
1512 {
1513     if( !flag ) {
1514         [fWindow  makeKeyAndOrderFront:nil];
1515                 
1516         return YES;
1517     }
1518     
1519     return NO;
1520 }
1521
1522
1523 #pragma mark -
1524 #pragma mark Queue File
1525
1526 - (void) loadQueueFile {
1527         /* We declare the default NSFileManager into fileManager */
1528         NSFileManager * fileManager = [NSFileManager defaultManager];
1529         /*We define the location of the user presets file */
1530     QueueFile = @"~/Library/Application Support/HandBrake/Queue.plist";
1531         QueueFile = [[QueueFile stringByExpandingTildeInPath]retain];
1532     /* We check for the presets.plist */
1533         if ([fileManager fileExistsAtPath:QueueFile] == 0)
1534         {
1535                 [fileManager createFileAtPath:QueueFile contents:nil attributes:nil];
1536         }
1537
1538         QueueFileArray = [[NSMutableArray alloc] initWithContentsOfFile:QueueFile];
1539         /* lets check to see if there is anything in the queue file .plist */
1540     if (nil == QueueFileArray)
1541         {
1542         /* if not, then lets initialize an empty array */
1543                 QueueFileArray = [[NSMutableArray alloc] init];
1544         
1545      /* Initialize our curQueueEncodeIndex to 0
1546      * so we can use it to track which queue
1547      * item is to be used to track our encodes */
1548      /* NOTE: this should be changed if and when we
1549       * are able to get the last unfinished encode
1550       * in the case of a crash or shutdown */
1551     
1552         }
1553     else
1554     {
1555     [self clearQueueEncodedItems];
1556     }
1557     currentQueueEncodeIndex = 0;
1558 }
1559
1560 - (void)addQueueFileItem
1561 {
1562         [QueueFileArray addObject:[self createQueueFileItem]];
1563         [self saveQueueFileItem];
1564
1565 }
1566
1567 - (void) removeQueueFileItem:(int) queueItemToRemove
1568 {
1569    
1570    /* Find out if the item we are removing is a cancelled item*/
1571    if ([[[QueueFileArray objectAtIndex:queueItemToRemove] objectForKey:@"Status"] intValue] == 3)
1572     {
1573     /* Since we are removing a cancelled item, WE need to decrement the currentQueueEncodeIndex
1574      * by one to keep in sync with the queue array
1575      */
1576     currentQueueEncodeIndex--;
1577     [self writeToActivityLog: "removeQueueFileItem: Removing a cancelled encode, decrement currentQueueEncodeIndex to %d", currentQueueEncodeIndex];
1578     }
1579     [QueueFileArray removeObjectAtIndex:queueItemToRemove];
1580     [self saveQueueFileItem];
1581
1582 }
1583
1584 - (void)saveQueueFileItem
1585 {
1586     [QueueFileArray writeToFile:QueueFile atomically:YES];
1587     [fQueueController setQueueArray: QueueFileArray];
1588     [self getQueueStats];
1589 }
1590
1591 - (void)getQueueStats
1592 {
1593 /* lets get the stats on the status of the queue array */
1594
1595 fEncodingQueueItem = 0;
1596 fPendingCount = 0;
1597 fCompletedCount = 0;
1598 fCanceledCount = 0;
1599 fWorkingCount = 0;
1600
1601     /* We use a number system to set the encode status of the queue item
1602      * in controller.mm
1603      * 0 == already encoded
1604      * 1 == is being encoded
1605      * 2 == is yet to be encoded
1606      * 3 == cancelled
1607      */
1608
1609         int i = 0;
1610     NSEnumerator *enumerator = [QueueFileArray objectEnumerator];
1611         id tempObject;
1612         while (tempObject = [enumerator nextObject])
1613         {
1614                 NSDictionary *thisQueueDict = tempObject;
1615                 if ([[thisQueueDict objectForKey:@"Status"] intValue] == 0) // Completed
1616                 {
1617                         fCompletedCount++;      
1618                 }
1619                 if ([[thisQueueDict objectForKey:@"Status"] intValue] == 1) // being encoded
1620                 {
1621                         fWorkingCount++;
1622             fEncodingQueueItem = i;     
1623                 }
1624         if ([[thisQueueDict objectForKey:@"Status"] intValue] == 2) // pending          
1625         {
1626                         fPendingCount++;
1627                 }
1628         if ([[thisQueueDict objectForKey:@"Status"] intValue] == 3) // cancelled                
1629         {
1630                         fCanceledCount++;
1631                 }
1632                 i++;
1633         }
1634
1635     /* Set the queue status field in the main window */
1636     NSMutableString * string;
1637     if (fPendingCount == 1)
1638     {
1639         string = [NSMutableString stringWithFormat: NSLocalizedString( @"%d encode pending in the queue", @"" ), fPendingCount];
1640     }
1641     else
1642     {
1643         string = [NSMutableString stringWithFormat: NSLocalizedString( @"%d encode(s) pending in the queue", @"" ), fPendingCount];
1644     }
1645     [fQueueStatus setStringValue:string];
1646 }
1647
1648
1649 /* This method will clear the queue of any encodes that are not still pending
1650  * this includes both successfully completed encodes as well as cancelled encodes */
1651 - (void) clearQueueEncodedItems
1652 {
1653     NSEnumerator *enumerator = [QueueFileArray objectEnumerator];
1654         id tempObject;
1655     NSMutableArray *tempArray;
1656     tempArray = [NSMutableArray array];
1657     /* we look here to see if the preset is we move on to the next one */
1658     while ( tempObject = [enumerator nextObject] )  
1659     {
1660         /* If the queue item is not still pending (finished successfully or it was cancelled
1661          * during the last session, then we put it in tempArray to be deleted from QueueFileArray*/
1662         if ([[tempObject objectForKey:@"Status"] intValue] != 2)
1663         {
1664             [tempArray addObject:tempObject];
1665         }
1666     }
1667     
1668     [QueueFileArray removeObjectsInArray:tempArray];
1669     [self saveQueueFileItem];
1670     
1671 }
1672
1673 /* This method will clear the queue of any encodes that are not still pending
1674  * this includes both successfully completed encodes as well as cancelled encodes */
1675 - (void) clearQueueAllItems
1676 {
1677     NSEnumerator *enumerator = [QueueFileArray objectEnumerator];
1678         id tempObject;
1679     NSMutableArray *tempArray;
1680     tempArray = [NSMutableArray array];
1681     /* we look here to see if the preset is we move on to the next one */
1682     while ( tempObject = [enumerator nextObject] )  
1683     {
1684         [tempArray addObject:tempObject];
1685     }
1686     
1687     [QueueFileArray removeObjectsInArray:tempArray];
1688     [self saveQueueFileItem];
1689     
1690 }
1691
1692 /* This method will duplicate prepareJob however into the
1693  * queue .plist instead of into the job structure so it can
1694  * be recalled later */
1695 - (NSDictionary *)createQueueFileItem
1696 {
1697     NSMutableDictionary *queueFileJob = [[NSMutableDictionary alloc] init];
1698     
1699        hb_list_t  * list  = hb_get_titles( fHandle );
1700     hb_title_t * title = (hb_title_t *) hb_list_item( list,
1701             [fSrcTitlePopUp indexOfSelectedItem] );
1702     hb_job_t * job = title->job;
1703     
1704     
1705     
1706     /* We use a number system to set the encode status of the queue item
1707      * 0 == already encoded
1708      * 1 == is being encoded
1709      * 2 == is yet to be encoded
1710      * 3 == cancelled
1711      */
1712     [queueFileJob setObject:[NSNumber numberWithInt:2] forKey:@"Status"];
1713     /* Source and Destination Information */
1714     
1715     [queueFileJob setObject:[NSString stringWithUTF8String: title->dvd] forKey:@"SourcePath"];
1716     [queueFileJob setObject:[fSrcDVD2Field stringValue] forKey:@"SourceName"];
1717     [queueFileJob setObject:[NSNumber numberWithInt:title->index] forKey:@"TitleNumber"];
1718     [queueFileJob setObject:[NSNumber numberWithInt:[fSrcChapterStartPopUp indexOfSelectedItem] + 1] forKey:@"ChapterStart"];
1719     
1720     [queueFileJob setObject:[NSNumber numberWithInt:[fSrcChapterEndPopUp indexOfSelectedItem] + 1] forKey:@"ChapterEnd"];
1721     
1722     [queueFileJob setObject:[fDstFile2Field stringValue] forKey:@"DestinationPath"];
1723     
1724     /* Lets get the preset info if there is any */
1725     [queueFileJob setObject:[fPresetSelectedDisplay stringValue] forKey:@"PresetName"];
1726     [queueFileJob setObject:[NSNumber numberWithInt:[fPresetsOutlineView selectedRow]] forKey:@"PresetIndexNum"];
1727     
1728     [queueFileJob setObject:[fDstFormatPopUp titleOfSelectedItem] forKey:@"FileFormat"];
1729         /* Chapter Markers fCreateChapterMarkers*/
1730         [queueFileJob setObject:[NSNumber numberWithInt:[fCreateChapterMarkers state]] forKey:@"ChapterMarkers"];
1731         
1732     /* We need to get the list of chapter names to put into an array and store 
1733      * in our queue, so they can be reapplied in prepareJob when this queue
1734      * item comes up if Chapter Markers is set to on.
1735      */
1736      int i;
1737      NSMutableArray *ChapterNamesArray = [[NSMutableArray alloc] init];
1738      int chaptercount = hb_list_count( fTitle->list_chapter );
1739      for( i = 0; i < chaptercount; i++ )
1740     {
1741         hb_chapter_t *chapter = (hb_chapter_t *) hb_list_item( fTitle->list_chapter, i );
1742         if( chapter != NULL )
1743         {
1744          [ChapterNamesArray addObject:[NSString stringWithFormat:@"%s",chapter->title]];
1745         }
1746     }
1747     [queueFileJob setObject:[NSMutableArray arrayWithArray: ChapterNamesArray] forKey:@"ChapterNames"];
1748     [ChapterNamesArray autorelease];
1749     
1750     /* Allow Mpeg4 64 bit formatting +4GB file sizes */
1751         [queueFileJob setObject:[NSNumber numberWithInt:[fDstMp4LargeFileCheck state]] forKey:@"Mp4LargeFile"];
1752     /* Mux mp4 with http optimization */
1753     [queueFileJob setObject:[NSNumber numberWithInt:[fDstMp4HttpOptFileCheck state]] forKey:@"Mp4HttpOptimize"];
1754     /* Add iPod uuid atom */
1755     [queueFileJob setObject:[NSNumber numberWithInt:[fDstMp4iPodFileCheck state]] forKey:@"Mp4iPodCompatible"];
1756     
1757     /* Codecs */
1758         /* Video encoder */
1759         [queueFileJob setObject:[fVidEncoderPopUp titleOfSelectedItem] forKey:@"VideoEncoder"];
1760         /* x264 Option String */
1761         [queueFileJob setObject:[fAdvancedOptions optionsString] forKey:@"x264Option"];
1762
1763         [queueFileJob setObject:[NSNumber numberWithInt:[fVidQualityMatrix selectedRow]] forKey:@"VideoQualityType"];
1764         [queueFileJob setObject:[fVidTargetSizeField stringValue] forKey:@"VideoTargetSize"];
1765         [queueFileJob setObject:[fVidBitrateField stringValue] forKey:@"VideoAvgBitrate"];
1766         [queueFileJob setObject:[NSNumber numberWithFloat:[fVidQualitySlider floatValue]] forKey:@"VideoQualitySlider"];
1767     /* Framerate */
1768     [queueFileJob setObject:[fVidRatePopUp titleOfSelectedItem] forKey:@"VideoFramerate"];
1769     
1770     /* GrayScale */
1771         [queueFileJob setObject:[NSNumber numberWithInt:[fVidGrayscaleCheck state]] forKey:@"VideoGrayScale"];
1772         /* 2 Pass Encoding */
1773         [queueFileJob setObject:[NSNumber numberWithInt:[fVidTwoPassCheck state]] forKey:@"VideoTwoPass"];
1774         /* Turbo 2 pass Encoding fVidTurboPassCheck*/
1775         [queueFileJob setObject:[NSNumber numberWithInt:[fVidTurboPassCheck state]] forKey:@"VideoTurboTwoPass"];
1776     
1777         /* Picture Sizing */
1778         /* Use Max Picture settings for whatever the dvd is.*/
1779         [queueFileJob setObject:[NSNumber numberWithInt:0] forKey:@"UsesMaxPictureSettings"];
1780         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->width] forKey:@"PictureWidth"];
1781         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->height] forKey:@"PictureHeight"];
1782         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->keep_ratio] forKey:@"PictureKeepRatio"];
1783         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->pixel_ratio] forKey:@"PicturePAR"];
1784     NSString * pictureSummary;
1785     pictureSummary = [NSString stringWithFormat:@"Source: %@ Output: %@ Anamorphic: %@", 
1786                      [fPicSettingsSrc stringValue], 
1787                      [fPicSettingsOutp stringValue], 
1788                      [fPicSettingsAnamorphic stringValue]];
1789     [queueFileJob setObject:pictureSummary forKey:@"PictureSizingSummary"];                 
1790     /* Set crop settings here */
1791         [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController autoCrop]] forKey:@"PictureAutoCrop"];
1792     [queueFileJob setObject:[NSNumber numberWithInt:job->crop[0]] forKey:@"PictureTopCrop"];
1793     [queueFileJob setObject:[NSNumber numberWithInt:job->crop[1]] forKey:@"PictureBottomCrop"];
1794         [queueFileJob setObject:[NSNumber numberWithInt:job->crop[2]] forKey:@"PictureLeftCrop"];
1795         [queueFileJob setObject:[NSNumber numberWithInt:job->crop[3]] forKey:@"PictureRightCrop"];
1796     
1797     /* Picture Filters */
1798     [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController deinterlace]] forKey:@"PictureDeinterlace"];
1799         [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController detelecine]] forKey:@"PictureDetelecine"];
1800     [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController vfr]] forKey:@"VFR"];
1801         [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController denoise]] forKey:@"PictureDenoise"];
1802     [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController deblock]] forKey:@"PictureDeblock"]; 
1803     [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController decomb]] forKey:@"PictureDecomb"];
1804     
1805     /*Audio*/
1806     if ([fAudLang1PopUp indexOfSelectedItem] > 0)
1807     {
1808         [queueFileJob setObject:[NSNumber numberWithInt:[fAudLang1PopUp indexOfSelectedItem]] forKey:@"Audio1Track"];
1809         [queueFileJob setObject:[fAudLang1PopUp titleOfSelectedItem] forKey:@"Audio1TrackDescription"];
1810         [queueFileJob setObject:[fAudTrack1CodecPopUp titleOfSelectedItem] forKey:@"Audio1Encoder"];
1811         [queueFileJob setObject:[fAudTrack1MixPopUp titleOfSelectedItem] forKey:@"Audio1Mixdown"];
1812         [queueFileJob setObject:[fAudTrack1RatePopUp titleOfSelectedItem] forKey:@"Audio1Samplerate"];
1813         [queueFileJob setObject:[fAudTrack1BitratePopUp titleOfSelectedItem] forKey:@"Audio1Bitrate"];
1814         [queueFileJob setObject:[NSNumber numberWithFloat:[fAudTrack1DrcSlider floatValue]] forKey:@"Audio1TrackDRCSlider"];
1815     }
1816     if ([fAudLang2PopUp indexOfSelectedItem] > 0)
1817     {
1818         [queueFileJob setObject:[NSNumber numberWithInt:[fAudLang2PopUp indexOfSelectedItem]] forKey:@"Audio2Track"];
1819         [queueFileJob setObject:[fAudLang2PopUp titleOfSelectedItem] forKey:@"Audio2TrackDescription"];
1820         [queueFileJob setObject:[fAudTrack2CodecPopUp titleOfSelectedItem] forKey:@"Audio2Encoder"];
1821         [queueFileJob setObject:[fAudTrack2MixPopUp titleOfSelectedItem] forKey:@"Audio2Mixdown"];
1822         [queueFileJob setObject:[fAudTrack2RatePopUp titleOfSelectedItem] forKey:@"Audio2Samplerate"];
1823         [queueFileJob setObject:[fAudTrack2BitratePopUp titleOfSelectedItem] forKey:@"Audio2Bitrate"];
1824         [queueFileJob setObject:[NSNumber numberWithFloat:[fAudTrack2DrcSlider floatValue]] forKey:@"Audio2TrackDRCSlider"];
1825     }
1826     if ([fAudLang3PopUp indexOfSelectedItem] > 0)
1827     {
1828         [queueFileJob setObject:[NSNumber numberWithInt:[fAudLang3PopUp indexOfSelectedItem]] forKey:@"Audio3Track"];
1829         [queueFileJob setObject:[fAudLang3PopUp titleOfSelectedItem] forKey:@"Audio3TrackDescription"];
1830         [queueFileJob setObject:[fAudTrack3CodecPopUp titleOfSelectedItem] forKey:@"Audio3Encoder"];
1831         [queueFileJob setObject:[fAudTrack3MixPopUp titleOfSelectedItem] forKey:@"Audio3Mixdown"];
1832         [queueFileJob setObject:[fAudTrack3RatePopUp titleOfSelectedItem] forKey:@"Audio3Samplerate"];
1833         [queueFileJob setObject:[fAudTrack3BitratePopUp titleOfSelectedItem] forKey:@"Audio3Bitrate"];
1834         [queueFileJob setObject:[NSNumber numberWithFloat:[fAudTrack3DrcSlider floatValue]] forKey:@"Audio3TrackDRCSlider"];
1835     }
1836     if ([fAudLang4PopUp indexOfSelectedItem] > 0)
1837     {
1838         [queueFileJob setObject:[NSNumber numberWithInt:[fAudLang4PopUp indexOfSelectedItem]] forKey:@"Audio4Track"];
1839         [queueFileJob setObject:[fAudLang4PopUp titleOfSelectedItem] forKey:@"Audio4TrackDescription"];
1840         [queueFileJob setObject:[fAudTrack4CodecPopUp titleOfSelectedItem] forKey:@"Audio4Encoder"];
1841         [queueFileJob setObject:[fAudTrack4MixPopUp titleOfSelectedItem] forKey:@"Audio4Mixdown"];
1842         [queueFileJob setObject:[fAudTrack4RatePopUp titleOfSelectedItem] forKey:@"Audio4Samplerate"];
1843         [queueFileJob setObject:[fAudTrack4BitratePopUp titleOfSelectedItem] forKey:@"Audio4Bitrate"];
1844         [queueFileJob setObject:[NSNumber numberWithFloat:[fAudTrack4DrcSlider floatValue]] forKey:@"Audio4TrackDRCSlider"];
1845     }
1846     
1847         /* Subtitles*/
1848         [queueFileJob setObject:[fSubPopUp titleOfSelectedItem] forKey:@"Subtitles"];
1849     [queueFileJob setObject:[NSNumber numberWithInt:[fSubPopUp indexOfSelectedItem]] forKey:@"JobSubtitlesIndex"];
1850     /* Forced Subtitles */
1851         [queueFileJob setObject:[NSNumber numberWithInt:[fSubForcedCheck state]] forKey:@"SubtitlesForced"];
1852     
1853     
1854     
1855     /* Now we go ahead and set the "job->values in the plist for passing right to fQueueEncodeLibhb */
1856      
1857     [queueFileJob setObject:[NSNumber numberWithInt:[fSrcChapterStartPopUp indexOfSelectedItem] + 1] forKey:@"JobChapterStart"];
1858     
1859     [queueFileJob setObject:[NSNumber numberWithInt:[fSrcChapterEndPopUp indexOfSelectedItem] + 1] forKey:@"JobChapterEnd"];
1860     
1861     
1862     [queueFileJob setObject:[NSNumber numberWithInt:[[fDstFormatPopUp selectedItem] tag]] forKey:@"JobFileFormatMux"];
1863         /* Chapter Markers fCreateChapterMarkers*/
1864         //[queueFileJob setObject:[NSNumber numberWithInt:[fCreateChapterMarkers state]] forKey:@"ChapterMarkers"];
1865         /* Allow Mpeg4 64 bit formatting +4GB file sizes */
1866         //[queueFileJob setObject:[NSNumber numberWithInt:[fDstMp4LargeFileCheck state]] forKey:@"Mp4LargeFile"];
1867     /* Mux mp4 with http optimization */
1868     //[queueFileJob setObject:[NSNumber numberWithInt:[fDstMp4HttpOptFileCheck state]] forKey:@"Mp4HttpOptimize"];
1869     /* Add iPod uuid atom */
1870     //[queueFileJob setObject:[NSNumber numberWithInt:[fDstMp4iPodFileCheck state]] forKey:@"Mp4iPodCompatible"];
1871     
1872     /* Codecs */
1873         /* Video encoder */
1874         [queueFileJob setObject:[NSNumber numberWithInt:[[fVidEncoderPopUp selectedItem] tag]] forKey:@"JobVideoEncoderVcodec"];
1875         /* x264 Option String */
1876         //[queueFileJob setObject:[fAdvancedOptions optionsString] forKey:@"x264Option"];
1877
1878         //[queueFileJob setObject:[NSNumber numberWithInt:[fVidQualityMatrix selectedRow]] forKey:@"VideoQualityType"];
1879         //[queueFileJob setObject:[fVidTargetSizeField stringValue] forKey:@"VideoTargetSize"];
1880         //[queueFileJob setObject:[fVidBitrateField stringValue] forKey:@"VideoAvgBitrate"];
1881         //[queueFileJob setObject:[NSNumber numberWithFloat:[fVidQualitySlider floatValue]] forKey:@"VideoQualitySlider"];
1882     /* Framerate */
1883     [queueFileJob setObject:[NSNumber numberWithInt:[fVidRatePopUp indexOfSelectedItem]] forKey:@"JobIndexVideoFramerate"];
1884     [queueFileJob setObject:[NSNumber numberWithInt:title->rate] forKey:@"JobVrate"];
1885     [queueFileJob setObject:[NSNumber numberWithInt:title->rate_base] forKey:@"JobVrateBase"];
1886         /* Picture Sizing */
1887         /* Use Max Picture settings for whatever the dvd is.*/
1888         [queueFileJob setObject:[NSNumber numberWithInt:0] forKey:@"UsesMaxPictureSettings"];
1889         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->width] forKey:@"PictureWidth"];
1890         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->height] forKey:@"PictureHeight"];
1891         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->keep_ratio] forKey:@"PictureKeepRatio"];
1892         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->pixel_ratio] forKey:@"PicturePAR"];
1893     
1894     /* Set crop settings here */
1895         [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController autoCrop]] forKey:@"PictureAutoCrop"];
1896     [queueFileJob setObject:[NSNumber numberWithInt:job->crop[0]] forKey:@"PictureTopCrop"];
1897     [queueFileJob setObject:[NSNumber numberWithInt:job->crop[1]] forKey:@"PictureBottomCrop"];
1898         [queueFileJob setObject:[NSNumber numberWithInt:job->crop[2]] forKey:@"PictureLeftCrop"];
1899         [queueFileJob setObject:[NSNumber numberWithInt:job->crop[3]] forKey:@"PictureRightCrop"];
1900     
1901     /* Picture Filters */
1902     [queueFileJob setObject:[fPicSettingDecomb stringValue] forKey:@"JobPictureDecomb"];
1903     
1904     /*Audio*/
1905     if ([fAudLang1PopUp indexOfSelectedItem] > 0)
1906     {
1907         //[queueFileJob setObject:[fAudTrack1CodecPopUp indexOfSelectedItem] forKey:@"JobAudio1Encoder"];
1908         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack1CodecPopUp selectedItem] tag]] forKey:@"JobAudio1Encoder"];
1909         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack1MixPopUp selectedItem] tag]] forKey:@"JobAudio1Mixdown"];
1910         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack1RatePopUp selectedItem] tag]] forKey:@"JobAudio1Samplerate"];
1911         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack1BitratePopUp selectedItem] tag]] forKey:@"JobAudio1Bitrate"];
1912      }
1913     if ([fAudLang2PopUp indexOfSelectedItem] > 0)
1914     {
1915         //[queueFileJob setObject:[fAudTrack1CodecPopUp indexOfSelectedItem] forKey:@"JobAudio2Encoder"];
1916         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack2CodecPopUp selectedItem] tag]] forKey:@"JobAudio2Encoder"];
1917         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack2MixPopUp selectedItem] tag]] forKey:@"JobAudio2Mixdown"];
1918         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack2RatePopUp selectedItem] tag]] forKey:@"JobAudio2Samplerate"];
1919         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack2BitratePopUp selectedItem] tag]] forKey:@"JobAudio2Bitrate"];
1920     }
1921     if ([fAudLang3PopUp indexOfSelectedItem] > 0)
1922     {
1923         //[queueFileJob setObject:[fAudTrack1CodecPopUp indexOfSelectedItem] forKey:@"JobAudio3Encoder"];
1924         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack3CodecPopUp selectedItem] tag]] forKey:@"JobAudio3Encoder"];
1925         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack3MixPopUp selectedItem] tag]] forKey:@"JobAudio3Mixdown"];
1926         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack3RatePopUp selectedItem] tag]] forKey:@"JobAudio3Samplerate"];
1927         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack3BitratePopUp selectedItem] tag]] forKey:@"JobAudio3Bitrate"];
1928     }
1929     if ([fAudLang4PopUp indexOfSelectedItem] > 0)
1930     {
1931         //[queueFileJob setObject:[fAudTrack1CodecPopUp indexOfSelectedItem] forKey:@"JobAudio4Encoder"];
1932         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack4CodecPopUp selectedItem] tag]] forKey:@"JobAudio4Encoder"];
1933         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack4MixPopUp selectedItem] tag]] forKey:@"JobAudio4Mixdown"];
1934         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack4RatePopUp selectedItem] tag]] forKey:@"JobAudio4Samplerate"];
1935         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack4BitratePopUp selectedItem] tag]] forKey:@"JobAudio4Bitrate"];
1936     }
1937         /* Subtitles*/
1938         [queueFileJob setObject:[fSubPopUp titleOfSelectedItem] forKey:@"Subtitles"];
1939     /* Forced Subtitles */
1940         [queueFileJob setObject:[NSNumber numberWithInt:[fSubForcedCheck state]] forKey:@"SubtitlesForced"];
1941  
1942     /* we need to auto relase the queueFileJob and return it */
1943     [queueFileJob autorelease];
1944     return queueFileJob;
1945
1946 }
1947
1948 /* this is actually called from the queue controller to modify the queue array and return it back to the queue controller */
1949 - (void)moveObjectsInQueueArray:(NSMutableArray *)array fromIndexes:(NSIndexSet *)indexSet toIndex:(unsigned)insertIndex
1950 {
1951     unsigned index = [indexSet lastIndex];
1952     unsigned aboveInsertIndexCount = 0;
1953     
1954     while (index != NSNotFound)
1955     {
1956         unsigned removeIndex;
1957         
1958         if (index >= insertIndex)
1959         {
1960             removeIndex = index + aboveInsertIndexCount;
1961             aboveInsertIndexCount++;
1962         }
1963         else
1964         {
1965             removeIndex = index;
1966             insertIndex--;
1967         }
1968         
1969         id object = [[QueueFileArray objectAtIndex:removeIndex] retain];
1970         [QueueFileArray removeObjectAtIndex:removeIndex];
1971         [QueueFileArray insertObject:object atIndex:insertIndex];
1972         [object release];
1973         
1974         index = [indexSet indexLessThanIndex:index];
1975     }
1976    /* We save all of the Queue data here 
1977     * and it also gets sent back to the queue controller*/
1978     [self saveQueueFileItem]; 
1979     
1980 }
1981
1982
1983 #pragma mark -
1984 #pragma mark Queue Job Processing
1985
1986 - (void) incrementQueueItemDone:(int) queueItemDoneIndexNum
1987 {
1988     int i = currentQueueEncodeIndex;
1989     [[QueueFileArray objectAtIndex:i] setObject:[NSNumber numberWithInt:0] forKey:@"Status"];
1990         
1991     /* We save all of the Queue data here */
1992     [self saveQueueFileItem];
1993         /* We Reload the New Table data for presets */
1994     //[fPresetsOutlineView reloadData];
1995
1996     /* Since we have now marked a queue item as done
1997      * we can go ahead and increment currentQueueEncodeIndex 
1998      * so that if there is anything left in the queue we can
1999      * go ahead and move to the next item if we want to */
2000     currentQueueEncodeIndex++ ;
2001     [self writeToActivityLog: "incrementQueueItemDone currentQueueEncodeIndex is incremented to: %d", currentQueueEncodeIndex];
2002     int queueItems = [QueueFileArray count];
2003     /* If we still have more items in our queue, lets go to the next one */
2004     if (currentQueueEncodeIndex < queueItems)
2005     {
2006     [self writeToActivityLog: "incrementQueueItemDone currentQueueEncodeIndex is incremented to: %d", currentQueueEncodeIndex];
2007     [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]];
2008     }
2009     else
2010     {
2011         [self writeToActivityLog: "incrementQueueItemDone the %d item queue is complete", currentQueueEncodeIndex - 1];
2012     }
2013 }
2014
2015 /* Here we actually tell hb_scan to perform the source scan, using the path to source and title number*/
2016 - (void) performNewQueueScan:(NSString *) scanPath scanTitleNum: (int) scanTitleNum
2017 {
2018    //NSRunAlertPanel(@"Hello!", @"We are now performing a new queue scan!", @"OK", nil, nil);
2019
2020      /* use a bool to determine whether or not we can decrypt using vlc */
2021     BOOL cancelScanDecrypt = 0;
2022     /* set the bool so that showNewScan knows to apply the appropriate queue
2023     * settings as this is a queue rescan
2024     */
2025     applyQueueToScan = YES;
2026     NSString *path = scanPath;
2027     HBDVDDetector *detector = [HBDVDDetector detectorForPath:path];
2028
2029         /*On Screen Notification*/
2030         //int status;
2031         //status = NSRunAlertPanel(@"HandBrake is now loading up a new queue item...",@"Would You Like to wait until you add another encode?", @"Cancel", @"Okay", nil);
2032         //[NSApp requestUserAttention:NSCriticalRequest];
2033
2034     // Notify ChapterTitles that there's no title
2035     [fChapterTitlesDelegate resetWithTitle:nil];
2036     [fChapterTable reloadData];
2037
2038     //[self enableUI: NO];
2039
2040     if( [detector isVideoDVD] )
2041     {
2042         // The chosen path was actually on a DVD, so use the raw block
2043         // device path instead.
2044         path = [detector devicePath];
2045         [self writeToActivityLog: "trying to open a physical dvd at: %s", [scanPath UTF8String]];
2046
2047         /* lets check for vlc here to make sure we have a dylib available to use for decrypting */
2048         NSString *vlcPath = @"/Applications/VLC.app";
2049         NSFileManager * fileManager = [NSFileManager defaultManager];
2050             if ([fileManager fileExistsAtPath:vlcPath] == 0) 
2051             {
2052             /*vlc not found in /Applications so we set the bool to cancel scanning to 1 */
2053             cancelScanDecrypt = 1;
2054             [self writeToActivityLog: "VLC app not found for decrypting physical dvd"];
2055             int status;
2056             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");
2057             [NSApp requestUserAttention:NSCriticalRequest];
2058             
2059             if (status == NSAlertDefaultReturn)
2060             {
2061                 /* User chose to go download vlc (as they rightfully should) so we send them to the vlc site */
2062                 [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.videolan.org/"]];
2063             }
2064             else if (status == NSAlertAlternateReturn)
2065             {
2066             /* User chose to cancel the scan */
2067             [self writeToActivityLog: "cannot open physical dvd , scan cancelled"];
2068             }
2069             else
2070             {
2071             /* 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 */
2072             cancelScanDecrypt = 0;
2073             [self writeToActivityLog: "user overrode vlc warning -trying to open physical dvd without decryption"];
2074             }
2075
2076         }
2077         else
2078         {
2079             /* VLC was found in /Applications so all is well, we can carry on using vlc's libdvdcss.dylib for decrypting if needed */
2080             [self writeToActivityLog: "VLC app found for decrypting physical dvd"];
2081         }
2082     }
2083
2084     if (cancelScanDecrypt == 0)
2085     {
2086         /* we actually pass the scan off to libhb here */
2087         /* If there is no title number passed to scan, we use "0"
2088          * which causes the default behavior of a full source scan
2089          */
2090         if (!scanTitleNum)
2091         {
2092             scanTitleNum = 0;
2093         }
2094         if (scanTitleNum > 0)
2095         {
2096             [self writeToActivityLog: "scanning specifically for title: %d", scanTitleNum];
2097         }
2098         [self writeToActivityLog: "performNewQueueScan currentQueueEncodeIndex is: %d", currentQueueEncodeIndex];
2099         hb_scan( fQueueEncodeLibhb, [path UTF8String], scanTitleNum );
2100     }
2101 }
2102
2103 /* This method was originally used to load up a new queue item in the gui and
2104  * then start processing it. However we now have modified -prepareJob and use a second
2105  * instance of libhb to do our actual encoding, therefor right now it is not required. 
2106  * Nonetheless I want to leave this in here
2107  * because basically its everything we need to be able to actually modify a pending queue
2108  * item in the gui and resave it. At least for now - dynaflash
2109  */
2110
2111 - (IBAction)applyQueueSettings:(id)sender
2112 {
2113     NSMutableDictionary * queueToApply = [QueueFileArray objectAtIndex:currentQueueEncodeIndex];
2114     hb_job_t * job = fTitle->job;
2115     
2116     /* Set title number and chapters */
2117     /* since the queue only scans a single title, we really don't need to pick a title */
2118     //[fSrcTitlePopUp selectItemAtIndex: [[queueToApply objectForKey:@"TitleNumber"] intValue] - 1];
2119     
2120     [fSrcChapterStartPopUp selectItemAtIndex: [[queueToApply objectForKey:@"ChapterStart"] intValue] - 1];
2121     [fSrcChapterEndPopUp selectItemAtIndex: [[queueToApply objectForKey:@"ChapterEnd"] intValue] - 1];
2122     
2123     /* File Format */
2124     [fDstFormatPopUp selectItemWithTitle:[queueToApply objectForKey:@"FileFormat"]];
2125     [self formatPopUpChanged:nil];
2126     
2127     /* Chapter Markers*/
2128     [fCreateChapterMarkers setState:[[queueToApply objectForKey:@"ChapterMarkers"] intValue]];
2129     /* Allow Mpeg4 64 bit formatting +4GB file sizes */
2130     [fDstMp4LargeFileCheck setState:[[queueToApply objectForKey:@"Mp4LargeFile"] intValue]];
2131     /* Mux mp4 with http optimization */
2132     [fDstMp4HttpOptFileCheck setState:[[queueToApply objectForKey:@"Mp4HttpOptimize"] intValue]];
2133     
2134     /* Video encoder */
2135     /* We set the advanced opt string here if applicable*/
2136     [fVidEncoderPopUp selectItemWithTitle:[queueToApply objectForKey:@"VideoEncoder"]];
2137     [fAdvancedOptions setOptions:[queueToApply objectForKey:@"x264Option"]];
2138     
2139     /* Lets run through the following functions to get variables set there */
2140     [self videoEncoderPopUpChanged:nil];
2141     /* Set the state of ipod compatible with Mp4iPodCompatible. Only for x264*/
2142     [fDstMp4iPodFileCheck setState:[[queueToApply objectForKey:@"Mp4iPodCompatible"] intValue]];
2143     [self calculateBitrate:nil];
2144     
2145     /* Video quality */
2146     [fVidQualityMatrix selectCellAtRow:[[queueToApply objectForKey:@"VideoQualityType"] intValue] column:0];
2147     
2148     [fVidTargetSizeField setStringValue:[queueToApply objectForKey:@"VideoTargetSize"]];
2149     [fVidBitrateField setStringValue:[queueToApply objectForKey:@"VideoAvgBitrate"]];
2150     [fVidQualitySlider setFloatValue:[[queueToApply objectForKey:@"VideoQualitySlider"] floatValue]];
2151     
2152     [self videoMatrixChanged:nil];
2153     
2154     /* Video framerate */
2155     /* For video preset video framerate, we want to make sure that Same as source does not conflict with the
2156      detected framerate in the fVidRatePopUp so we use index 0*/
2157     if ([[queueToApply objectForKey:@"VideoFramerate"] isEqualToString:@"Same as source"])
2158     {
2159         [fVidRatePopUp selectItemAtIndex: 0];
2160     }
2161     else
2162     {
2163         [fVidRatePopUp selectItemWithTitle:[queueToApply objectForKey:@"VideoFramerate"]];
2164     }
2165     
2166     /* GrayScale */
2167     [fVidGrayscaleCheck setState:[[queueToApply objectForKey:@"VideoGrayScale"] intValue]];
2168     
2169     /* 2 Pass Encoding */
2170     [fVidTwoPassCheck setState:[[queueToApply objectForKey:@"VideoTwoPass"] intValue]];
2171     [self twoPassCheckboxChanged:nil];
2172     /* Turbo 1st pass for 2 Pass Encoding */
2173     [fVidTurboPassCheck setState:[[queueToApply objectForKey:@"VideoTurboTwoPass"] intValue]];
2174     
2175     /*Audio*/
2176     if ([queueToApply objectForKey:@"Audio1Track"] > 0)
2177     {
2178         if ([fAudLang1PopUp indexOfSelectedItem] == 0)
2179         {
2180             [fAudLang1PopUp selectItemAtIndex: 1];
2181         }
2182         [self audioTrackPopUpChanged: fAudLang1PopUp];
2183         [fAudTrack1CodecPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio1Encoder"]];
2184         [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
2185         [fAudTrack1MixPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio1Mixdown"]];
2186         /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
2187          * mixdown*/
2188         if  ([fAudTrack1MixPopUp selectedItem] == nil)
2189         {
2190             [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
2191         }
2192         [fAudTrack1RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Samplerate"]];
2193         /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
2194         if (![[queueToApply objectForKey:@"Audio1Encoder"] isEqualToString:@"AC3 Passthru"])
2195         {
2196             [fAudTrack1BitratePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio1Bitrate"]];
2197         }
2198         [fAudTrack1DrcSlider setFloatValue:[[queueToApply objectForKey:@"Audio1TrackDRCSlider"] floatValue]];
2199         [self audioDRCSliderChanged: fAudTrack1DrcSlider];
2200     }
2201     if ([queueToApply objectForKey:@"Audio2Track"] > 0)
2202     {
2203         if ([fAudLang2PopUp indexOfSelectedItem] == 0)
2204         {
2205             [fAudLang2PopUp selectItemAtIndex: 1];
2206         }
2207         [self audioTrackPopUpChanged: fAudLang2PopUp];
2208         [fAudTrack2CodecPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio2Encoder"]];
2209         [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
2210         [fAudTrack2MixPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio2Mixdown"]];
2211         /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
2212          * mixdown*/
2213         if  ([fAudTrack2MixPopUp selectedItem] == nil)
2214         {
2215             [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
2216         }
2217         [fAudTrack2RatePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio2Samplerate"]];
2218         /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
2219         if (![[queueToApply objectForKey:@"Audio2Encoder"] isEqualToString:@"AC3 Passthru"])
2220         {
2221             [fAudTrack2BitratePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio2Bitrate"]];
2222         }
2223         [fAudTrack2DrcSlider setFloatValue:[[queueToApply objectForKey:@"Audio2TrackDRCSlider"] floatValue]];
2224         [self audioDRCSliderChanged: fAudTrack2DrcSlider];
2225     }
2226     if ([queueToApply objectForKey:@"Audio3Track"] > 0)
2227     {
2228         if ([fAudLang3PopUp indexOfSelectedItem] == 0)
2229         {
2230             [fAudLang3PopUp selectItemAtIndex: 1];
2231         }
2232         [self audioTrackPopUpChanged: fAudLang3PopUp];
2233         [fAudTrack3CodecPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio3Encoder"]];
2234         [self audioTrackPopUpChanged: fAudTrack3CodecPopUp];
2235         [fAudTrack3MixPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio3Mixdown"]];
2236         /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
2237          * mixdown*/
2238         if  ([fAudTrack3MixPopUp selectedItem] == nil)
2239         {
2240             [self audioTrackPopUpChanged: fAudTrack3CodecPopUp];
2241         }
2242         [fAudTrack3RatePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio3Samplerate"]];
2243         /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
2244         if (![[queueToApply objectForKey:@"Audio3Encoder"] isEqualToString: @"AC3 Passthru"])
2245         {
2246             [fAudTrack3BitratePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio3Bitrate"]];
2247         }
2248         [fAudTrack3DrcSlider setFloatValue:[[queueToApply objectForKey:@"Audio3TrackDRCSlider"] floatValue]];
2249         [self audioDRCSliderChanged: fAudTrack3DrcSlider];
2250     }
2251     if ([queueToApply objectForKey:@"Audio4Track"] > 0)
2252     {
2253         if ([fAudLang4PopUp indexOfSelectedItem] == 0)
2254         {
2255             [fAudLang4PopUp selectItemAtIndex: 1];
2256         }
2257         [self audioTrackPopUpChanged: fAudLang4PopUp];
2258         [fAudTrack4CodecPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio4Encoder"]];
2259         [self audioTrackPopUpChanged: fAudTrack4CodecPopUp];
2260         [fAudTrack4MixPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio4Mixdown"]];
2261         /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
2262          * mixdown*/
2263         if  ([fAudTrack4MixPopUp selectedItem] == nil)
2264         {
2265             [self audioTrackPopUpChanged: fAudTrack4CodecPopUp];
2266         }
2267         [fAudTrack4RatePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio4Samplerate"]];
2268         /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
2269         if (![[chosenPreset objectForKey:@"Audio4Encoder"] isEqualToString:@"AC3 Passthru"])
2270         {
2271             [fAudTrack4BitratePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio4Bitrate"]];
2272         }
2273         [fAudTrack4DrcSlider setFloatValue:[[queueToApply objectForKey:@"Audio4TrackDRCSlider"] floatValue]];
2274         [self audioDRCSliderChanged: fAudTrack4DrcSlider];
2275     }
2276     
2277     
2278     /*Subtitles*/
2279     [fSubPopUp selectItemWithTitle:[queueToApply objectForKey:@"Subtitles"]];
2280     /* Forced Subtitles */
2281     [fSubForcedCheck setState:[[queueToApply objectForKey:@"SubtitlesForced"] intValue]];
2282     
2283     /* Picture Settings */
2284     /* we check to make sure the presets width/height does not exceed the sources width/height */
2285     if (fTitle->width < [[queueToApply objectForKey:@"PictureWidth"]  intValue] || fTitle->height < [[queueToApply objectForKey:@"PictureHeight"]  intValue])
2286     {
2287         /* if so, then we use the sources height and width to avoid scaling up */
2288         job->width = fTitle->width;
2289         job->height = fTitle->height;
2290     }
2291     else // source width/height is >= the preset height/width
2292     {
2293         /* we can go ahead and use the presets values for height and width */
2294         job->width = [[queueToApply objectForKey:@"PictureWidth"]  intValue];
2295         job->height = [[queueToApply objectForKey:@"PictureHeight"]  intValue];
2296     }
2297     job->keep_ratio = [[queueToApply objectForKey:@"PictureKeepRatio"]  intValue];
2298     if (job->keep_ratio == 1)
2299     {
2300         hb_fix_aspect( job, HB_KEEP_WIDTH );
2301         if( job->height > fTitle->height )
2302         {
2303             job->height = fTitle->height;
2304             hb_fix_aspect( job, HB_KEEP_HEIGHT );
2305         }
2306     }
2307     job->pixel_ratio = [[queueToApply objectForKey:@"PicturePAR"]  intValue];
2308     
2309     
2310     /* If Cropping is set to custom, then recall all four crop values from
2311      when the preset was created and apply them */
2312     if ([[queueToApply objectForKey:@"PictureAutoCrop"]  intValue] == 0)
2313     {
2314         [fPictureController setAutoCrop:NO];
2315         
2316         /* Here we use the custom crop values saved at the time the preset was saved */
2317         job->crop[0] = [[queueToApply objectForKey:@"PictureTopCrop"]  intValue];
2318         job->crop[1] = [[queueToApply objectForKey:@"PictureBottomCrop"]  intValue];
2319         job->crop[2] = [[queueToApply objectForKey:@"PictureLeftCrop"]  intValue];
2320         job->crop[3] = [[queueToApply objectForKey:@"PictureRightCrop"]  intValue];
2321         
2322     }
2323     else /* if auto crop has been saved in preset, set to auto and use post scan auto crop */
2324     {
2325         [fPictureController setAutoCrop:YES];
2326         /* Here we use the auto crop values determined right after scan */
2327         job->crop[0] = AutoCropTop;
2328         job->crop[1] = AutoCropBottom;
2329         job->crop[2] = AutoCropLeft;
2330         job->crop[3] = AutoCropRight;
2331         
2332     }
2333     
2334     /* Filters */
2335     /* Deinterlace */
2336     [fPictureController setDeinterlace:[[queueToApply objectForKey:@"PictureDeinterlace"] intValue]];
2337     /* VFR */
2338     [fPictureController setVFR:[[queueToApply objectForKey:@"VFR"] intValue]];
2339     /* Detelecine */
2340     [fPictureController setDetelecine:[[queueToApply objectForKey:@"PictureDetelecine"] intValue]];
2341     /* Denoise */
2342     [fPictureController setDenoise:[[queueToApply objectForKey:@"PictureDenoise"] intValue]];
2343     /* Deblock */
2344     [fPictureController setDeblock:[[queueToApply objectForKey:@"PictureDeblock"] intValue]];
2345     /* Decomb */
2346     [fPictureController setDecomb:[[queueToApply objectForKey:@"PictureDecomb"] intValue]];
2347     
2348     [self calculatePictureSizing:nil];
2349     
2350     
2351     /* somehow we need to figure out a way to tie the queue item to a preset if it used one */
2352     //[queueFileJob setObject:[fPresetSelectedDisplay stringValue] forKey:@"PresetName"];
2353     //    [queueFileJob setObject:[NSNumber numberWithInt:[fPresetsOutlineView selectedRow]] forKey:@"PresetIndexNum"];
2354     if ([queueToApply objectForKey:@"PresetIndexNum"]) // This item used a preset so insert that info
2355         {
2356                 /* Deselect the currently selected Preset if there is one*/
2357         //[fPresetsOutlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:[[queueToApply objectForKey:@"PresetIndexNum"] intValue]] byExtendingSelection:NO];
2358         //[self selectPreset:nil];
2359                 
2360         //[fPresetsOutlineView selectRow:[[queueToApply objectForKey:@"PresetIndexNum"] intValue]];
2361                 /* Change UI to show "Custom" settings are being used */
2362                 //[fPresetSelectedDisplay setStringValue: [[queueToApply objectForKey:@"PresetName"] stringValue]];
2363         
2364                 curUserPresetChosenNum = nil;
2365         }
2366     else
2367     {
2368         /* Deselect the currently selected Preset if there is one*/
2369                 [fPresetsOutlineView deselectRow:[fPresetsOutlineView selectedRow]];
2370                 /* Change UI to show "Custom" settings are being used */
2371                 [fPresetSelectedDisplay setStringValue: @"Custom"];
2372         
2373                 //curUserPresetChosenNum = nil;
2374     }
2375     
2376     /* We need to set this bool back to NO, in case the user wants to do a scan */
2377     //applyQueueToScan = NO;
2378     
2379     /* so now we go ahead and process the new settings */
2380     [self processNewQueueEncode];
2381 }
2382
2383
2384
2385 /* This assumes that we have re-scanned and loaded up a new queue item to send to libhb as fQueueEncodeLibhb */
2386 - (void) processNewQueueEncode
2387 {
2388     hb_list_t  * list  = hb_get_titles( fQueueEncodeLibhb );
2389     hb_title_t * title = (hb_title_t *) hb_list_item( list,0 ); // is always zero since now its a single title scan
2390     hb_job_t * job = title->job;
2391     
2392     if( !hb_list_count( list ) )
2393     {
2394         [self writeToActivityLog: "processNewQueueEncode WARNING nothing found in the title list"];
2395     }
2396     else
2397     {
2398         [self writeToActivityLog: "processNewQueueEncode title list is: %d", hb_list_count( list )];
2399     }
2400     
2401     NSMutableDictionary * queueToApply = [QueueFileArray objectAtIndex:currentQueueEncodeIndex];
2402     [self writeToActivityLog: "processNewQueueEncode currentQueueEncodeIndex is: %d", currentQueueEncodeIndex];
2403     [self writeToActivityLog: "processNewQueueEncode number of passes expected is: %d", ([[queueToApply objectForKey:@"VideoTwoPass"] intValue] + 1)];
2404     job->file = [[queueToApply objectForKey:@"DestinationPath"] UTF8String];
2405     [self writeToActivityLog: "processNewQueueEncode sending to prepareJob"];
2406     [self prepareJob];
2407     [self writeToActivityLog: "processNewQueueEncode back from prepareJob"];
2408     if( [[queueToApply objectForKey:@"SubtitlesForced"] intValue] == 1 )
2409         job->subtitle_force = 1;
2410     else
2411         job->subtitle_force = 0;
2412     
2413     /*
2414      * subtitle of -1 is a scan
2415      */
2416     if( job->subtitle == -1 )
2417     {
2418         char *x264opts_tmp;
2419         
2420         /*
2421          * When subtitle scan is enabled do a fast pre-scan job
2422          * which will determine which subtitles to enable, if any.
2423          */
2424         job->pass = -1;
2425         x264opts_tmp = job->x264opts;
2426         job->subtitle = -1;
2427         
2428         job->x264opts = NULL;
2429         
2430         job->indepth_scan = 1;  
2431         
2432         job->select_subtitle = (hb_subtitle_t**)malloc(sizeof(hb_subtitle_t*));
2433         *(job->select_subtitle) = NULL;
2434         
2435         /*
2436          * Add the pre-scan job
2437          */
2438         hb_add( fQueueEncodeLibhb, job );
2439         job->x264opts = x264opts_tmp;
2440     }
2441     else
2442         job->select_subtitle = NULL;
2443     
2444     /* No subtitle were selected, so reset the subtitle to -1 (which before
2445      * this point meant we were scanning
2446      */
2447     if( job->subtitle == -2 )
2448         job->subtitle = -1;
2449     
2450     if( [[queueToApply objectForKey:@"VideoTwoPass"] intValue] == 1 )
2451     {
2452         hb_subtitle_t **subtitle_tmp = job->select_subtitle;
2453         job->indepth_scan = 0;
2454         
2455         /*
2456          * Do not autoselect subtitles on the first pass of a two pass
2457          */
2458         job->select_subtitle = NULL;
2459         
2460         job->pass = 1;
2461         
2462         hb_add( fQueueEncodeLibhb, job );
2463         
2464         job->pass = 2;
2465         
2466         job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */  
2467         strcpy(job->x264opts, [[queueToApply objectForKey:@"x264Option"] UTF8String]);
2468         
2469         job->select_subtitle = subtitle_tmp;
2470         
2471         hb_add( fQueueEncodeLibhb, job );
2472         
2473     }
2474     else
2475     {
2476         job->indepth_scan = 0;
2477         job->pass = 0;
2478         
2479         hb_add( fQueueEncodeLibhb, job );
2480     }
2481         
2482     NSString *destinationDirectory = [[queueToApply objectForKey:@"DestinationPath"] stringByDeletingLastPathComponent];
2483         [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"];
2484         /* Lets mark our new encode as 1 or "Encoding" */
2485     [queueToApply setObject:[NSNumber numberWithInt:1] forKey:@"Status"];
2486     [self saveQueueFileItem];
2487     /* We should be all setup so let 'er rip */   
2488     [self doRip];
2489 }
2490
2491
2492 #pragma mark -
2493 #pragma mark Job Handling
2494
2495
2496 - (void) prepareJob
2497 {
2498     
2499     NSMutableDictionary * queueToApply = [QueueFileArray objectAtIndex:currentQueueEncodeIndex];
2500     hb_list_t  * list  = hb_get_titles( fQueueEncodeLibhb );
2501     hb_title_t * title = (hb_title_t *) hb_list_item( list,0 ); // is always zero since now its a single title scan
2502     hb_job_t * job = title->job;
2503     hb_audio_config_t * audio;
2504     [self writeToActivityLog: "prepareJob reached"];
2505     /* Chapter selection */
2506     job->chapter_start = [[queueToApply objectForKey:@"JobChapterStart"] intValue];
2507     job->chapter_end   = [[queueToApply objectForKey:@"JobChapterEnd"] intValue];
2508         
2509     /* Format (Muxer) and Video Encoder */
2510     job->mux = [[queueToApply objectForKey:@"JobFileFormatMux"] intValue];
2511     job->vcodec = [[queueToApply objectForKey:@"JobVideoEncoderVcodec"] intValue];
2512     
2513     
2514     /* If mpeg-4, then set mpeg-4 specific options like chapters and > 4gb file sizes */
2515         //if( [fDstFormatPopUp indexOfSelectedItem] == 0 )
2516         //{
2517     /* We set the largeFileSize (64 bit formatting) variable here to allow for > 4gb files based on the format being
2518      mpeg4 and the checkbox being checked 
2519      *Note: this will break compatibility with some target devices like iPod, etc.!!!!*/
2520     if( [[queueToApply objectForKey:@"Mp4LargeFile"] intValue] == 1)
2521     {
2522         job->largeFileSize = 1;
2523     }
2524     else
2525     {
2526         job->largeFileSize = 0;
2527     }
2528     /* We set http optimized mp4 here */
2529     if( [[queueToApply objectForKey:@"Mp4HttpOptimize"] intValue] == 1 )
2530     {
2531         job->mp4_optimize = 1;
2532     }
2533     else
2534     {
2535         job->mp4_optimize = 0;
2536     }
2537     
2538     //}
2539         
2540     /* We set the chapter marker extraction here based on the format being
2541      mpeg4 or mkv and the checkbox being checked */
2542     if ([[queueToApply objectForKey:@"ChapterMarkers"] intValue] == 1)
2543     {
2544         job->chapter_markers = 1;
2545         
2546         /* now lets get our saved chapter names out the array in the queue file
2547          * and insert them back into the title chapter list. We have it here,
2548          * because unless we are inserting chapter markers there is no need to
2549          * spend the overhead of iterating through the chapter names array imo
2550          * Also, note that if for some reason we don't apply chapter names, the
2551          * chapters just come out 001, 002, etc. etc.
2552          */
2553          
2554         NSMutableArray *ChapterNamesArray = [queueToApply objectForKey:@"ChapterNames"];
2555         int i = 0;
2556         NSEnumerator *enumerator = [ChapterNamesArray objectEnumerator];
2557         id tempObject;
2558         while (tempObject = [enumerator nextObject])
2559         {
2560             hb_chapter_t *chapter = (hb_chapter_t *) hb_list_item( title->list_chapter, i );
2561             if( chapter != NULL )
2562             {
2563                 strncpy( chapter->title, [tempObject UTF8String], 1023);
2564                 chapter->title[1023] = '\0';
2565             }
2566             i++;
2567         }
2568     }
2569     else
2570     {
2571         job->chapter_markers = 0;
2572     }
2573     
2574
2575     
2576     
2577     
2578     if( job->vcodec & HB_VCODEC_X264 )
2579     {
2580                 if ([[queueToApply objectForKey:@"Mp4iPodCompatible"] intValue] == 1)
2581             {
2582             job->ipod_atom = 1;
2583                 }
2584         else
2585         {
2586             job->ipod_atom = 0;
2587         }
2588                 
2589                 /* Set this flag to switch from Constant Quantizer(default) to Constant Rate Factor Thanks jbrjake
2590          Currently only used with Constant Quality setting*/
2591                 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultCrf"] > 0 && [[queueToApply objectForKey:@"VideoQualityType"] intValue] == 2)
2592                 {
2593                 job->crf = 1;
2594                 }
2595                 /* Below Sends x264 options to the core library if x264 is selected*/
2596                 /* Lets use this as per Nyx, Thanks Nyx!*/
2597                 job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */
2598                 /* Turbo first pass if two pass and Turbo First pass is selected */
2599                 if( [[queueToApply objectForKey:@"VideoTwoPass"] intValue] == 1 && [[queueToApply objectForKey:@"VideoTurboTwoPass"] intValue] == 1 )
2600                 {
2601                         /* pass the "Turbo" string to be appended to the existing x264 opts string into a variable for the first pass */
2602                         NSString *firstPassOptStringTurbo = @":ref=1:subme=1:me=dia:analyse=none:trellis=0:no-fast-pskip=0:8x8dct=0:weightb=0";
2603                         /* append the "Turbo" string variable to the existing opts string.
2604              Note: the "Turbo" string must be appended, not prepended to work properly*/
2605                         NSString *firstPassOptStringCombined = [[queueToApply objectForKey:@"x264Option"] stringByAppendingString:firstPassOptStringTurbo];
2606                         strcpy(job->x264opts, [firstPassOptStringCombined UTF8String]);
2607                 }
2608                 else
2609                 {
2610                         strcpy(job->x264opts, [[queueToApply objectForKey:@"x264Option"] UTF8String]);
2611                 }
2612         
2613     }
2614     
2615     
2616     [self writeToActivityLog: "prepareJob reached Picture Settings"];
2617     /* Picture Size Settings */
2618     job->width = [[queueToApply objectForKey:@"PictureWidth"]  intValue];
2619     job->height = [[queueToApply objectForKey:@"PictureHeight"]  intValue];
2620     
2621     job->keep_ratio = [[queueToApply objectForKey:@"PictureKeepRatio"]  intValue];
2622     job->pixel_ratio = [[queueToApply objectForKey:@"PicturePAR"]  intValue];
2623     
2624     
2625     /* Here we use the crop values saved at the time the preset was saved */
2626     job->crop[0] = [[queueToApply objectForKey:@"PictureTopCrop"]  intValue];
2627     job->crop[1] = [[queueToApply objectForKey:@"PictureBottomCrop"]  intValue];
2628     job->crop[2] = [[queueToApply objectForKey:@"PictureLeftCrop"]  intValue];
2629     job->crop[3] = [[queueToApply objectForKey:@"PictureRightCrop"]  intValue];
2630     
2631     [self writeToActivityLog: "prepareJob reached Frame Rate"];
2632     
2633     /* Video settings */
2634     if( [[queueToApply objectForKey:@"JobIndexVideoFramerate"] intValue] > 0 )
2635     {
2636         job->vrate      = 27000000;
2637         job->vrate_base = hb_video_rates[[[queueToApply objectForKey:@"JobIndexVideoFramerate"] intValue]-1].rate;
2638         /* We are not same as source so we set job->cfr to 1 
2639          * to enable constant frame rate since user has specified
2640          * a specific framerate*/
2641         job->cfr = 1;
2642     }
2643     else
2644     {
2645         job->vrate      = [[queueToApply objectForKey:@"JobVrate"] intValue];
2646         job->vrate_base = [[queueToApply objectForKey:@"JobVrateBase"] intValue];
2647         /* We are same as source so we set job->cfr to 0 
2648          * to enable true same as source framerate */
2649         job->cfr = 0;
2650     }
2651     [self writeToActivityLog: "prepareJob reached Bitrate Video Quality"];
2652     if ( [[queueToApply objectForKey:@"VideoQualityType"] intValue] == 0 )
2653     {
2654         /* Target size.
2655          Bitrate should already have been calculated and displayed
2656          in fVidBitrateField, so let's just use it */
2657     }
2658     if ( [[queueToApply objectForKey:@"VideoQualityType"] intValue] == 1 )
2659     {
2660         job->vquality = -1.0;
2661         job->vbitrate = [[queueToApply objectForKey:@"VideoAvgBitrate"] intValue];
2662     }
2663     if ( [[queueToApply objectForKey:@"VideoQualityType"] intValue] == 2 )
2664     {
2665         job->vquality = [[queueToApply objectForKey:@"VideoQualitySlider"] floatValue];
2666         job->vbitrate = 0;
2667         
2668     }
2669     
2670     job->grayscale = [[queueToApply objectForKey:@"VideoGrayScale"] intValue];
2671     /* Subtitle settings */
2672     job->subtitle = [[queueToApply objectForKey:@"JobSubtitlesIndex"] intValue] - 2;
2673     
2674     [self writeToActivityLog: "prepareJob reached Audio"];
2675     /* Audio tracks and mixdowns */
2676     /* Lets make sure there arent any erroneous audio tracks in the job list, so lets make sure its empty*/
2677     int audiotrack_count = hb_list_count(job->list_audio);
2678     for( int i = 0; i < audiotrack_count;i++)
2679     {
2680         hb_audio_t * temp_audio = (hb_audio_t*) hb_list_item( job->list_audio, 0 );
2681         hb_list_rem(job->list_audio, temp_audio);
2682     }
2683     /* Now lets add our new tracks to the audio list here */
2684     if ([[queueToApply objectForKey:@"Audio1Track"] intValue] > 0)
2685     {
2686         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
2687         hb_audio_config_init(audio);
2688         audio->in.track = [[queueToApply objectForKey:@"Audio1Track"] intValue] - 1;
2689         /* We go ahead and assign values to our audio->out.<properties> */
2690         audio->out.track = [[queueToApply objectForKey:@"Audio1Track"] intValue] - 1;
2691         audio->out.codec = [[queueToApply objectForKey:@"JobAudio1Encoder"] intValue];
2692         audio->out.mixdown = [[queueToApply objectForKey:@"JobAudio1Mixdown"] intValue];
2693         audio->out.bitrate = [[queueToApply objectForKey:@"JobAudio1Bitrate"] intValue];
2694         audio->out.samplerate = [[queueToApply objectForKey:@"JobAudio1Samplerate"] intValue];
2695         audio->out.dynamic_range_compression = [[queueToApply objectForKey:@"Audio1TrackDRCSlider"] floatValue];
2696         
2697         hb_audio_add( job, audio );
2698         free(audio);
2699     }  
2700     if ([[queueToApply objectForKey:@"Audio2Track"] intValue] > 0)
2701     {
2702         
2703         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
2704         hb_audio_config_init(audio);
2705         audio->in.track = [[queueToApply objectForKey:@"Audio2Track"] intValue] - 1;
2706         [self writeToActivityLog: "prepareJob audiotrack 2 is: %d", audio->in.track];
2707         /* We go ahead and assign values to our audio->out.<properties> */
2708         audio->out.track = [[queueToApply objectForKey:@"Audio2Track"] intValue] - 1;
2709         audio->out.codec = [[queueToApply objectForKey:@"JobAudio2Encoder"] intValue];
2710         audio->out.mixdown = [[queueToApply objectForKey:@"JobAudio2Mixdown"] intValue];
2711         audio->out.bitrate = [[queueToApply objectForKey:@"JobAudio2Bitrate"] intValue];
2712         audio->out.samplerate = [[queueToApply objectForKey:@"JobAudio2Samplerate"] intValue];
2713         audio->out.dynamic_range_compression = [[queueToApply objectForKey:@"Audio2TrackDRCSlider"] floatValue];
2714         
2715         hb_audio_add( job, audio );
2716         free(audio);
2717     }
2718     
2719     if ([[queueToApply objectForKey:@"Audio3Track"] intValue] > 0)
2720     {
2721         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
2722         hb_audio_config_init(audio);
2723         audio->in.track = [[queueToApply objectForKey:@"Audio3Track"] intValue] - 1;
2724         /* We go ahead and assign values to our audio->out.<properties> */
2725         audio->out.track = [[queueToApply objectForKey:@"Audio3Track"] intValue] - 1;
2726         audio->out.codec = [[queueToApply objectForKey:@"JobAudio3Encoder"] intValue];
2727         audio->out.mixdown = [[queueToApply objectForKey:@"JobAudio3Mixdown"] intValue];
2728         audio->out.bitrate = [[queueToApply objectForKey:@"JobAudio3Bitrate"] intValue];
2729         audio->out.samplerate = [[queueToApply objectForKey:@"JobAudio3Samplerate"] intValue];
2730         audio->out.dynamic_range_compression = [[queueToApply objectForKey:@"Audio3TrackDRCSlider"] floatValue];
2731         
2732         hb_audio_add( job, audio );
2733         free(audio);        
2734     }
2735     
2736     if ([[queueToApply objectForKey:@"Audio4Track"] intValue] > 0)
2737     {
2738         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
2739         hb_audio_config_init(audio);
2740         audio->in.track = [[queueToApply objectForKey:@"Audio4Track"] intValue] - 1;
2741         /* We go ahead and assign values to our audio->out.<properties> */
2742         audio->out.track = [[queueToApply objectForKey:@"Audio4Track"] intValue] - 1;
2743         audio->out.codec = [[queueToApply objectForKey:@"JobAudio4Encoder"] intValue];
2744         audio->out.mixdown = [[queueToApply objectForKey:@"JobAudio4Mixdown"] intValue];
2745         audio->out.bitrate = [[queueToApply objectForKey:@"JobAudio4Bitrate"] intValue];
2746         audio->out.samplerate = [[queueToApply objectForKey:@"JobAudio4Samplerate"] intValue];
2747         audio->out.dynamic_range_compression = [[queueToApply objectForKey:@"Audio3TrackDRCSlider"] floatValue];
2748         
2749         hb_audio_add( job, audio );
2750         free(audio);
2751     }
2752     
2753     /* set vfr according to the Picture Window */
2754     if ([[queueToApply objectForKey:@"VFR"] intValue] == 1)
2755     {
2756         job->vfr = 1;
2757     }
2758     else
2759     {
2760         job->vfr = 0;
2761     }
2762     
2763    [self writeToActivityLog: "prepareJob reached Filters"];
2764      /* Filters */ 
2765     job->filters = hb_list_init();
2766     
2767     /* Now lets call the filters if applicable.
2768      * The order of the filters is critical
2769      */
2770     /* Detelecine */
2771     if ([[queueToApply objectForKey:@"PictureDetelecine"] intValue] == 1)
2772     {
2773         hb_list_add( job->filters, &hb_filter_detelecine );
2774     }
2775     
2776     /* Decomb */
2777     if ([[queueToApply objectForKey:@"PictureDecomb"] intValue] == 1)
2778     {
2779         /* Run old deinterlacer fd by default */
2780         hb_filter_decomb.settings = (char *) [[queueToApply objectForKey:@"JobPictureDecomb"] UTF8String];
2781         hb_list_add( job->filters, &hb_filter_decomb );
2782     }
2783     
2784     /* Deinterlace */
2785     if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 1)
2786     {
2787         /* Run old deinterlacer fd by default */
2788         hb_filter_deinterlace.settings = "-1"; 
2789         hb_list_add( job->filters, &hb_filter_deinterlace );
2790     }
2791     else if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 2)
2792     {
2793         /* Yadif mode 0 (without spatial deinterlacing.) */
2794         hb_filter_deinterlace.settings = "2"; 
2795         hb_list_add( job->filters, &hb_filter_deinterlace );            
2796     }
2797     else if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 3)
2798     {
2799         /* Yadif (with spatial deinterlacing) */
2800         hb_filter_deinterlace.settings = "0"; 
2801         hb_list_add( job->filters, &hb_filter_deinterlace );            
2802     }
2803         
2804     /* Denoise */
2805         if ([[queueToApply objectForKey:@"PictureDenoise"] intValue] == 1) // Weak in popup
2806         {
2807                 hb_filter_denoise.settings = "2:1:2:3"; 
2808         hb_list_add( job->filters, &hb_filter_denoise );        
2809         }
2810         else if ([[queueToApply objectForKey:@"PictureDenoise"] intValue] == 2) // Medium in popup
2811         {
2812                 hb_filter_denoise.settings = "3:2:2:3"; 
2813         hb_list_add( job->filters, &hb_filter_denoise );        
2814         }
2815         else if ([[queueToApply objectForKey:@"PictureDenoise"] intValue] == 3) // Strong in popup
2816         {
2817                 hb_filter_denoise.settings = "7:7:5:5"; 
2818         hb_list_add( job->filters, &hb_filter_denoise );        
2819         }
2820     
2821     /* Deblock  (uses pp7 default) */
2822     if ([[queueToApply objectForKey:@"PictureDeblock"] intValue] == 1)
2823     {
2824         hb_list_add( job->filters, &hb_filter_deblock );
2825     }
2826 [self writeToActivityLog: "prepareJob exiting"];    
2827 }
2828
2829
2830
2831 /* addToQueue: puts up an alert before ultimately calling doAddToQueue
2832 */
2833 - (IBAction) addToQueue: (id) sender
2834 {
2835         /* We get the destination directory from the destination field here */
2836         NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent];
2837         /* We check for a valid destination here */
2838         if ([[NSFileManager defaultManager] fileExistsAtPath:destinationDirectory] == 0) 
2839         {
2840                 NSRunAlertPanel(@"Warning!", @"This is not a valid destination directory!", @"OK", nil, nil);
2841         return;
2842         }
2843
2844     /* We check for duplicate name here */
2845         if( [[NSFileManager defaultManager] fileExistsAtPath:
2846             [fDstFile2Field stringValue]] )
2847     {
2848         NSBeginCriticalAlertSheet( NSLocalizedString( @"File already exists", @"" ),
2849             NSLocalizedString( @"Cancel", @"" ), NSLocalizedString( @"Overwrite", @"" ), nil, fWindow, self,
2850             @selector( overwriteAddToQueueAlertDone:returnCode:contextInfo: ),
2851             NULL, NULL, [NSString stringWithFormat:
2852             NSLocalizedString( @"Do you want to overwrite %@?", @"" ),
2853             [fDstFile2Field stringValue]] );
2854         // overwriteAddToQueueAlertDone: will be called when the alert is dismissed.
2855     }
2856     else
2857     {
2858         [self doAddToQueue];
2859     }
2860 }
2861
2862 /* overwriteAddToQueueAlertDone: called from the alert posted by addToQueue that asks
2863    the user if they want to overwrite an exiting movie file.
2864 */
2865 - (void) overwriteAddToQueueAlertDone: (NSWindow *) sheet
2866     returnCode: (int) returnCode contextInfo: (void *) contextInfo
2867 {
2868     if( returnCode == NSAlertAlternateReturn )
2869         [self doAddToQueue];
2870 }
2871
2872 - (void) doAddToQueue
2873 {
2874     [self addQueueFileItem ];
2875 }
2876
2877
2878
2879 /* Rip: puts up an alert before ultimately calling doRip
2880 */
2881 - (IBAction) Rip: (id) sender
2882 {
2883     [self writeToActivityLog: "Rip: Pending queue count is %d", fPendingCount];
2884     /* Rip or Cancel ? */
2885     hb_state_t s;
2886     hb_get_state2( fQueueEncodeLibhb, &s );
2887     
2888     if(s.state == HB_STATE_WORKING || s.state == HB_STATE_PAUSED)
2889         {
2890         [self Cancel: sender];
2891         return;
2892     }
2893     
2894     // If there are pending jobs in the queue, then this is a rip the queue
2895     
2896     if (fPendingCount > 0)
2897     {
2898         /* here lets start the queue with the first pending item */
2899         [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]]; 
2900         
2901         return;
2902     }
2903     
2904     // Before adding jobs to the queue, check for a valid destination.
2905     
2906     NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent];
2907     if ([[NSFileManager defaultManager] fileExistsAtPath:destinationDirectory] == 0) 
2908     {
2909         NSRunAlertPanel(@"Warning!", @"This is not a valid destination directory!", @"OK", nil, nil);
2910         return;
2911     }
2912     
2913     /* We check for duplicate name here */
2914     if( [[NSFileManager defaultManager] fileExistsAtPath:[fDstFile2Field stringValue]] )
2915     {
2916         NSBeginCriticalAlertSheet( NSLocalizedString( @"File already exists", @"" ),
2917                                   NSLocalizedString( @"Cancel", "" ), NSLocalizedString( @"Overwrite", @"" ), nil, fWindow, self,
2918                                   @selector( overWriteAlertDone:returnCode:contextInfo: ),
2919                                   NULL, NULL, [NSString stringWithFormat:
2920                                                NSLocalizedString( @"Do you want to overwrite %@?", @"" ),
2921                                                [fDstFile2Field stringValue]] );
2922         
2923         // overWriteAlertDone: will be called when the alert is dismissed. It will call doRip.
2924     }
2925     else
2926     {
2927         /* if there are no pending jobs in the queue, then add this one to the queue and rip
2928          otherwise, just rip the queue */
2929         if(fPendingCount == 0)
2930         {
2931          [self writeToActivityLog: "Rip: No pending jobs, so sending this one to doAddToQueue"];
2932                [self doAddToQueue];
2933         }
2934         
2935         NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent];
2936         [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"];
2937         /* go right to processing the new queue encode */
2938        [self writeToActivityLog: "Rip: Going right to performNewQueueScan"];
2939          [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]]; 
2940         
2941     }
2942 }
2943
2944 /* overWriteAlertDone: called from the alert posted by Rip: that asks the user if they
2945    want to overwrite an exiting movie file.
2946 */
2947 - (void) overWriteAlertDone: (NSWindow *) sheet
2948     returnCode: (int) returnCode contextInfo: (void *) contextInfo
2949 {
2950     if( returnCode == NSAlertAlternateReturn )
2951     {
2952         /* if there are no jobs in the queue, then add this one to the queue and rip 
2953         otherwise, just rip the queue */
2954         if( fPendingCount == 0 )
2955         {
2956             [self doAddToQueue];
2957         }
2958
2959         NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent];
2960         [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"];
2961         [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]]; 
2962       
2963     }
2964 }
2965
2966 - (void) remindUserOfSleepOrShutdown
2967 {
2968        if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Put Computer To Sleep"])
2969        {
2970                /*Warn that computer will sleep after encoding*/
2971                int reminduser;
2972                NSBeep();
2973                reminduser = NSRunAlertPanel(@"The computer will sleep after encoding is done.",@"You have selected to sleep the computer after encoding. To turn off sleeping, go to the HandBrake preferences.", @"OK", @"Preferences...", nil);
2974                [NSApp requestUserAttention:NSCriticalRequest];
2975                if ( reminduser == NSAlertAlternateReturn )
2976                {
2977                        [self showPreferencesWindow:nil];
2978                }
2979        }
2980        else if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Shut Down Computer"])
2981        {
2982                /*Warn that computer will shut down after encoding*/
2983                int reminduser;
2984                NSBeep();
2985                reminduser = NSRunAlertPanel(@"The computer will shut down after encoding is done.",@"You have selected to shut down the computer after encoding. To turn off shut down, go to the HandBrake preferences.", @"OK", @"Preferences...", nil);
2986                [NSApp requestUserAttention:NSCriticalRequest];
2987                if ( reminduser == NSAlertAlternateReturn )
2988                {
2989                        [self showPreferencesWindow:nil];
2990                }
2991        }
2992
2993 }
2994
2995
2996 - (void) doRip
2997 {
2998     /* Let libhb do the job */
2999     hb_start( fQueueEncodeLibhb );
3000     /*set the fEncodeState State */
3001         fEncodeState = 1;
3002 }
3003
3004
3005 //------------------------------------------------------------------------------------
3006 // Cancels and deletes the current job and stops libhb from processing the remaining
3007 // encodes.
3008 //------------------------------------------------------------------------------------
3009 - (void) doCancelCurrentJob
3010 {
3011     // Stop the current job. hb_stop will only cancel the current pass and then set
3012     // its state to HB_STATE_WORKDONE. It also does this asynchronously. So when we
3013     // see the state has changed to HB_STATE_WORKDONE (in updateUI), we'll delete the
3014     // remaining passes of the job and then start the queue back up if there are any
3015     // remaining jobs.
3016      
3017     
3018     hb_stop( fQueueEncodeLibhb );
3019     fEncodeState = 2;   // don't alert at end of processing since this was a cancel
3020     
3021     // now that we've stopped the currently encoding job, lets mark it as cancelled
3022     [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] setObject:[NSNumber numberWithInt:3] forKey:@"Status"];
3023     // and as always, save it in the queue .plist...
3024     /* We save all of the Queue data here */
3025     [self saveQueueFileItem];
3026     // so now lets move to 
3027     currentQueueEncodeIndex++ ;
3028     // ... and see if there are more items left in our queue
3029     int queueItems = [QueueFileArray count];
3030     /* If we still have more items in our queue, lets go to the next one */
3031     if (currentQueueEncodeIndex < queueItems)
3032     {
3033     [self writeToActivityLog: "doCancelCurrentJob currentQueueEncodeIndex is incremented to: %d", currentQueueEncodeIndex];
3034     [self writeToActivityLog: "doCancelCurrentJob moving to the next job"];
3035     
3036     [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]];
3037     }
3038     else
3039     {
3040         [self writeToActivityLog: "doCancelCurrentJob the item queue is complete"];
3041     }
3042
3043 }
3044
3045 //------------------------------------------------------------------------------------
3046 // Displays an alert asking user if the want to cancel encoding of current job.
3047 // Cancel: returns immediately after posting the alert. Later, when the user
3048 // acknowledges the alert, doCancelCurrentJob is called.
3049 //------------------------------------------------------------------------------------
3050 - (IBAction)Cancel: (id)sender
3051 {
3052     if (!fQueueController) return;
3053     
3054   hb_pause( fQueueEncodeLibhb );
3055     NSString * alertTitle = [NSString stringWithFormat:NSLocalizedString(@"You are currently encoding. What would you like to do ?", nil)];
3056    
3057     // Which window to attach the sheet to?
3058     NSWindow * docWindow;
3059     if ([sender respondsToSelector: @selector(window)])
3060         docWindow = [sender window];
3061     else
3062         docWindow = fWindow;
3063         
3064     NSBeginCriticalAlertSheet(
3065             alertTitle,
3066             NSLocalizedString(@"Continue Encoding", nil),
3067             NSLocalizedString(@"Cancel Current and Stop", nil),
3068             NSLocalizedString(@"Cancel Current and Continue", nil),
3069             docWindow, self,
3070             nil, @selector(didDimissCancel:returnCode:contextInfo:), nil,
3071             NSLocalizedString(@"Your encode will be cancelled if you don't continue encoding.", nil));
3072     
3073     // didDimissCancelCurrentJob:returnCode:contextInfo: will be called when the dialog is dismissed
3074 }
3075
3076 - (void) didDimissCancel: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo
3077 {
3078    hb_resume( fQueueEncodeLibhb );
3079      if (returnCode == NSAlertOtherReturn)
3080     {
3081         [self doCancelCurrentJob];  // <- this also stops libhb
3082     }
3083     if (returnCode == NSAlertAlternateReturn)
3084     {
3085     [self doCancelCurrentJobAndStop];
3086     }
3087 }
3088
3089 - (void) doCancelCurrentJobAndStop
3090 {
3091     hb_stop( fQueueEncodeLibhb );
3092     fEncodeState = 2;   // don't alert at end of processing since this was a cancel
3093     
3094     // now that we've stopped the currently encoding job, lets mark it as cancelled
3095     [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] setObject:[NSNumber numberWithInt:3] forKey:@"Status"];
3096     // and as always, save it in the queue .plist...
3097     /* We save all of the Queue data here */
3098     [self saveQueueFileItem];
3099     // so now lets move to 
3100     currentQueueEncodeIndex++ ;
3101     [self writeToActivityLog: "cancelling current job and stopping the queue"];
3102 }
3103 - (IBAction) Pause: (id) sender
3104 {
3105     hb_state_t s;
3106     hb_get_state2( fQueueEncodeLibhb, &s );
3107
3108     if( s.state == HB_STATE_PAUSED )
3109     {
3110         hb_resume( fQueueEncodeLibhb );
3111     }
3112     else
3113     {
3114         hb_pause( fQueueEncodeLibhb );
3115     }
3116 }
3117
3118 #pragma mark -
3119 #pragma mark GUI Controls Changed Methods
3120
3121 - (IBAction) titlePopUpChanged: (id) sender
3122 {
3123     hb_list_t  * list  = hb_get_titles( fHandle );
3124     hb_title_t * title = (hb_title_t*)
3125         hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
3126
3127     /* If Auto Naming is on. We create an output filename of dvd name - title number */
3128     if( [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultAutoNaming"] > 0 && ( hb_list_count( list ) > 1 ) )
3129         {
3130                 [fDstFile2Field setStringValue: [NSString stringWithFormat:
3131                         @"%@/%@-%d.%@", [[fDstFile2Field stringValue] stringByDeletingLastPathComponent],
3132                         [browsedSourceDisplayName stringByDeletingPathExtension],
3133             title->index,
3134                         [[fDstFile2Field stringValue] pathExtension]]]; 
3135         }
3136
3137     /* Update chapter popups */
3138     [fSrcChapterStartPopUp removeAllItems];
3139     [fSrcChapterEndPopUp   removeAllItems];
3140     for( int i = 0; i < hb_list_count( title->list_chapter ); i++ )
3141     {
3142         [fSrcChapterStartPopUp addItemWithTitle: [NSString
3143             stringWithFormat: @"%d", i + 1]];
3144         [fSrcChapterEndPopUp addItemWithTitle: [NSString
3145             stringWithFormat: @"%d", i + 1]];
3146     }
3147
3148     [fSrcChapterStartPopUp selectItemAtIndex: 0];
3149     [fSrcChapterEndPopUp   selectItemAtIndex:
3150         hb_list_count( title->list_chapter ) - 1];
3151     [self chapterPopUpChanged:nil];
3152
3153     /* Start Get and set the initial pic size for display */
3154         hb_job_t * job = title->job;
3155         fTitle = title;
3156
3157         /*Set Source Size Field Here */
3158     [fPicSettingsSrc setStringValue: [NSString stringWithFormat: @"%d x %d", fTitle->width, fTitle->height]];
3159         
3160         /* Set Auto Crop to on upon selecting a new title */
3161     [fPictureController setAutoCrop:YES];
3162     
3163         /* We get the originial output picture width and height and put them
3164         in variables for use with some presets later on */
3165         PicOrigOutputWidth = job->width;
3166         PicOrigOutputHeight = job->height;
3167         AutoCropTop = job->crop[0];
3168         AutoCropBottom = job->crop[1];
3169         AutoCropLeft = job->crop[2];
3170         AutoCropRight = job->crop[3];
3171
3172         /* Run Through encoderPopUpChanged to see if there
3173                 needs to be any pic value modifications based on encoder settings */
3174         //[self encoderPopUpChanged: NULL];
3175         /* END Get and set the initial pic size for display */ 
3176
3177     /* Update subtitle popups */
3178     hb_subtitle_t * subtitle;
3179     [fSubPopUp removeAllItems];
3180     [fSubPopUp addItemWithTitle: @"None"];
3181     [fSubPopUp addItemWithTitle: @"Autoselect"];
3182     for( int i = 0; i < hb_list_count( title->list_subtitle ); i++ )
3183     {
3184         subtitle = (hb_subtitle_t *) hb_list_item( title->list_subtitle, i );
3185
3186         /* We cannot use NSPopUpButton's addItemWithTitle because
3187            it checks for duplicate entries */
3188         [[fSubPopUp menu] addItemWithTitle: [NSString stringWithCString:
3189             subtitle->lang] action: NULL keyEquivalent: @""];
3190     }
3191     [fSubPopUp selectItemAtIndex: 0];
3192
3193         [self subtitleSelectionChanged:nil];
3194
3195     /* Update chapter table */
3196     [fChapterTitlesDelegate resetWithTitle:title];
3197     [fChapterTable reloadData];
3198
3199    /* Lets make sure there arent any erroneous audio tracks in the job list, so lets make sure its empty*/
3200     int audiotrack_count = hb_list_count(job->list_audio);
3201     for( int i = 0; i < audiotrack_count;i++)
3202     {
3203         hb_audio_t * temp_audio = (hb_audio_t*) hb_list_item( job->list_audio, 0 );
3204         hb_list_rem(job->list_audio, temp_audio);
3205     }
3206
3207     /* Update audio popups */
3208     [self addAllAudioTracksToPopUp: fAudLang1PopUp];
3209     [self addAllAudioTracksToPopUp: fAudLang2PopUp];
3210     [self addAllAudioTracksToPopUp: fAudLang3PopUp];
3211     [self addAllAudioTracksToPopUp: fAudLang4PopUp];
3212     /* search for the first instance of our prefs default language for track 1, and set track 2 to "none" */
3213         NSString * audioSearchPrefix = [[NSUserDefaults standardUserDefaults] stringForKey:@"DefaultLanguage"];
3214         [self selectAudioTrackInPopUp: fAudLang1PopUp searchPrefixString: audioSearchPrefix selectIndexIfNotFound: 1];
3215     [self selectAudioTrackInPopUp:fAudLang2PopUp searchPrefixString:nil selectIndexIfNotFound:0];
3216     [self selectAudioTrackInPopUp:fAudLang3PopUp searchPrefixString:nil selectIndexIfNotFound:0];
3217     [self selectAudioTrackInPopUp:fAudLang4PopUp searchPrefixString:nil selectIndexIfNotFound:0];
3218
3219         /* changing the title may have changed the audio channels on offer, */
3220         /* so call audioTrackPopUpChanged for both audio tracks to update the mixdown popups */
3221         [self audioTrackPopUpChanged: fAudLang1PopUp];
3222         [self audioTrackPopUpChanged: fAudLang2PopUp];
3223     [self audioTrackPopUpChanged: fAudLang3PopUp];
3224     [self audioTrackPopUpChanged: fAudLang4PopUp];
3225
3226     [fVidRatePopUp selectItemAtIndex: 0];
3227
3228     /* we run the picture size values through calculatePictureSizing to get all picture setting information*/
3229         [self calculatePictureSizing:nil];
3230
3231    /* lets call tableViewSelected to make sure that any preset we have selected is enforced after a title change */
3232         [self selectPreset:nil];
3233 }
3234
3235 - (IBAction) chapterPopUpChanged: (id) sender
3236 {
3237
3238         /* If start chapter popup is greater than end chapter popup,
3239         we set the end chapter popup to the same as start chapter popup */
3240         if ([fSrcChapterStartPopUp indexOfSelectedItem] > [fSrcChapterEndPopUp indexOfSelectedItem])
3241         {
3242                 [fSrcChapterEndPopUp selectItemAtIndex: [fSrcChapterStartPopUp indexOfSelectedItem]];
3243     }
3244
3245                 
3246         hb_list_t  * list  = hb_get_titles( fHandle );
3247     hb_title_t * title = (hb_title_t *)
3248         hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
3249
3250     hb_chapter_t * chapter;
3251     int64_t        duration = 0;
3252     for( int i = [fSrcChapterStartPopUp indexOfSelectedItem];
3253          i <= [fSrcChapterEndPopUp indexOfSelectedItem]; i++ )
3254     {
3255         chapter = (hb_chapter_t *) hb_list_item( title->list_chapter, i );
3256         duration += chapter->duration;
3257     }
3258     
3259     duration /= 90000; /* pts -> seconds */
3260     [fSrcDuration2Field setStringValue: [NSString stringWithFormat:
3261         @"%02lld:%02lld:%02lld", duration / 3600, ( duration / 60 ) % 60,
3262         duration % 60]];
3263
3264     [self calculateBitrate: sender];
3265 }
3266
3267 - (IBAction) formatPopUpChanged: (id) sender
3268 {
3269     NSString * string = [fDstFile2Field stringValue];
3270     int format = [fDstFormatPopUp indexOfSelectedItem];
3271     char * ext = NULL;
3272         /* Initially set the large file (64 bit formatting) output checkbox to hidden */
3273     [fDstMp4LargeFileCheck setHidden: YES];
3274     [fDstMp4HttpOptFileCheck setHidden: YES];
3275     [fDstMp4iPodFileCheck setHidden: YES];
3276     
3277     /* Update the Video Codec PopUp */
3278     /* Note: we now store the video encoder int values from common.c in the tags of each popup for easy retrieval later */
3279     [fVidEncoderPopUp removeAllItems];
3280     NSMenuItem *menuItem;
3281     /* These video encoders are available to all of our current muxers, so lets list them once here */
3282     menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"MPEG-4 (FFmpeg)" action: NULL keyEquivalent: @""];
3283     [menuItem setTag: HB_VCODEC_FFMPEG];
3284     
3285     menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"MPEG-4 (XviD)" action: NULL keyEquivalent: @""];
3286     [menuItem setTag: HB_VCODEC_XVID];
3287     switch( format )
3288     {
3289         case 0:
3290                         /*Get Default MP4 File Extension*/
3291                         if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultMpegName"] > 0)
3292                         {
3293                                 ext = "m4v";
3294                         }
3295                         else
3296                         {
3297                                 ext = "mp4";
3298                         }
3299             /* Add additional video encoders here */
3300             menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"H.264 (x264)" action: NULL keyEquivalent: @""];
3301             [menuItem setTag: HB_VCODEC_X264];
3302             /* We show the mp4 option checkboxes here since we are mp4 */
3303             [fCreateChapterMarkers setEnabled: YES];
3304                         [fDstMp4LargeFileCheck setHidden: NO];
3305                         [fDstMp4HttpOptFileCheck setHidden: NO];
3306             [fDstMp4iPodFileCheck setHidden: NO];
3307             break;
3308             
3309             case 1:
3310             ext = "mkv";
3311             /* Add additional video encoders here */
3312             menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"H.264 (x264)" action: NULL keyEquivalent: @""];
3313             [menuItem setTag: HB_VCODEC_X264];
3314             menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"VP3 (Theora)" action: NULL keyEquivalent: @""];
3315             [menuItem setTag: HB_VCODEC_THEORA];
3316             /* We enable the create chapters checkbox here */
3317                         [fCreateChapterMarkers setEnabled: YES];
3318                         break;
3319             
3320             case 2: 
3321             ext = "avi";
3322             /* Add additional video encoders here */
3323             menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"H.264 (x264)" action: NULL keyEquivalent: @""];
3324             [menuItem setTag: HB_VCODEC_X264];
3325             /* We disable the create chapters checkbox here and make sure it is unchecked*/
3326                         [fCreateChapterMarkers setEnabled: NO];
3327                         [fCreateChapterMarkers setState: NSOffState];
3328                         break;
3329             
3330             case 3:
3331             ext = "ogm";
3332             /* Add additional video encoders here */
3333             menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"VP3 (Theora)" action: NULL keyEquivalent: @""];
3334             [menuItem setTag: HB_VCODEC_THEORA];
3335             /* We disable the create chapters checkbox here and make sure it is unchecked*/
3336                         [fCreateChapterMarkers setEnabled: NO];
3337                         [fCreateChapterMarkers setState: NSOffState];
3338                         break;
3339     }
3340     [fVidEncoderPopUp selectItemAtIndex: 0];
3341
3342     [self audioAddAudioTrackCodecs: fAudTrack1CodecPopUp];
3343     [self audioAddAudioTrackCodecs: fAudTrack2CodecPopUp];
3344     [self audioAddAudioTrackCodecs: fAudTrack3CodecPopUp];
3345     [self audioAddAudioTrackCodecs: fAudTrack4CodecPopUp];
3346
3347     if( format == 0 )
3348         [self autoSetM4vExtension: sender];
3349     else
3350         [fDstFile2Field setStringValue: [NSString stringWithFormat:@"%@.%s", [string stringByDeletingPathExtension], ext]];
3351
3352     if( SuccessfulScan )
3353     {
3354         /* Add/replace to the correct extension */
3355         [self audioTrackPopUpChanged: fAudLang1PopUp];
3356         [self audioTrackPopUpChanged: fAudLang2PopUp];
3357         [self audioTrackPopUpChanged: fAudLang3PopUp];
3358         [self audioTrackPopUpChanged: fAudLang4PopUp];
3359
3360         if( [fVidEncoderPopUp selectedItem] == nil )
3361         {
3362
3363             [fVidEncoderPopUp selectItemAtIndex:0];
3364             [self videoEncoderPopUpChanged:nil];
3365
3366             /* changing the format may mean that we can / can't offer mono or 6ch, */
3367             /* so call audioTrackPopUpChanged for both audio tracks to update the mixdown popups */
3368
3369             /* We call the method to properly enable/disable turbo 2 pass */
3370             [self twoPassCheckboxChanged: sender];
3371             /* We call method method to change UI to reflect whether a preset is used or not*/
3372         }
3373     }
3374         [self customSettingUsed: sender];
3375 }
3376
3377 - (IBAction) autoSetM4vExtension: (id) sender
3378 {
3379     if ( [fDstFormatPopUp indexOfSelectedItem] )
3380         return;
3381
3382     NSString * extension = @"mp4";
3383
3384     if( [[fAudTrack1CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[fAudTrack2CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 ||
3385                                                         [[fAudTrack3CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 ||
3386                                                         [[fAudTrack4CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 ||
3387                                                         [fCreateChapterMarkers state] == NSOnState ||
3388                                                         [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultMpegName"] > 0 )
3389     {
3390         extension = @"m4v";
3391     }
3392
3393     if( [extension isEqualTo: [[fDstFile2Field stringValue] pathExtension]] )
3394         return;
3395     else
3396         [fDstFile2Field setStringValue: [NSString stringWithFormat:@"%@.%@",
3397                                     [[fDstFile2Field stringValue] stringByDeletingPathExtension], extension]];
3398 }
3399
3400 - (void) shouldEnableHttpMp4CheckBox: (id) sender
3401 {
3402     if( [[fAudTrack1CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[fAudTrack2CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 ||
3403                                                         [[fAudTrack3CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 ||
3404                                                         [[fAudTrack4CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 )
3405         [fDstMp4HttpOptFileCheck setEnabled: NO];
3406     else
3407         [fDstMp4HttpOptFileCheck setEnabled: YES];
3408 }
3409         
3410 /* Method to determine if we should change the UI
3411 To reflect whether or not a Preset is being used or if
3412 the user is using "Custom" settings by determining the sender*/
3413 - (IBAction) customSettingUsed: (id) sender
3414 {
3415         if ([sender stringValue])
3416         {
3417                 /* Deselect the currently selected Preset if there is one*/
3418                 [fPresetsOutlineView deselectRow:[fPresetsOutlineView selectedRow]];
3419                 /* Change UI to show "Custom" settings are being used */
3420                 [fPresetSelectedDisplay setStringValue: @"Custom"];
3421
3422                 curUserPresetChosenNum = nil;
3423         }
3424 }
3425
3426
3427 #pragma mark -
3428 #pragma mark - Video
3429
3430 - (IBAction) videoEncoderPopUpChanged: (id) sender
3431 {
3432     hb_job_t * job = fTitle->job;
3433     int videoEncoder = [[fVidEncoderPopUp selectedItem] tag];
3434     
3435     [fAdvancedOptions setHidden:YES];
3436     /* If we are using x264 then show the x264 advanced panel*/
3437     if (videoEncoder == HB_VCODEC_X264)
3438     {
3439         [fAdvancedOptions setHidden:NO];
3440         [self autoSetM4vExtension: sender];
3441     }
3442     
3443     /* We need to set loose anamorphic as available depending on whether or not the ffmpeg encoder
3444     is being used as it borks up loose anamorphic .
3445     For convenience lets use the titleOfSelected index. Probably should revisit whether or not we want
3446     to use the index itself but this is easier */
3447     if (videoEncoder == HB_VCODEC_FFMPEG)
3448     {
3449         if (job->pixel_ratio == 2)
3450         {
3451             job->pixel_ratio = 0;
3452         }
3453         [fPictureController setAllowLooseAnamorphic:NO];
3454         /* We set the iPod atom checkbox to disabled and uncheck it as its only for x264 in the mp4
3455          container. Format is taken care of in formatPopUpChanged method by hiding and unchecking
3456          anything other than MP4.
3457          */ 
3458         [fDstMp4iPodFileCheck setEnabled: NO];
3459         [fDstMp4iPodFileCheck setState: NSOffState];
3460     }
3461     else
3462     {
3463         [fPictureController setAllowLooseAnamorphic:YES];
3464         [fDstMp4iPodFileCheck setEnabled: YES];
3465     }
3466     
3467         [self calculatePictureSizing: sender];
3468         [self twoPassCheckboxChanged: sender];
3469 }
3470
3471
3472 - (IBAction) twoPassCheckboxChanged: (id) sender
3473 {
3474         /* check to see if x264 is chosen */
3475         if([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_X264)
3476     {
3477                 if( [fVidTwoPassCheck state] == NSOnState)
3478                 {
3479                         [fVidTurboPassCheck setHidden: NO];
3480                 }
3481                 else
3482                 {
3483                         [fVidTurboPassCheck setHidden: YES];
3484                         [fVidTurboPassCheck setState: NSOffState];
3485                 }
3486                 /* Make sure Two Pass is checked if Turbo is checked */
3487                 if( [fVidTurboPassCheck state] == NSOnState)
3488                 {
3489                         [fVidTwoPassCheck setState: NSOnState];
3490                 }
3491         }
3492         else
3493         {
3494                 [fVidTurboPassCheck setHidden: YES];
3495                 [fVidTurboPassCheck setState: NSOffState];
3496         }
3497         
3498         /* We call method method to change UI to reflect whether a preset is used or not*/
3499         [self customSettingUsed: sender];
3500 }
3501
3502 - (IBAction ) videoFrameRateChanged: (id) sender
3503 {
3504     /* We call method method to calculatePictureSizing to error check detelecine*/
3505     [self calculatePictureSizing: sender];
3506
3507     /* We call method method to change UI to reflect whether a preset is used or not*/
3508         [self customSettingUsed: sender];
3509 }
3510 - (IBAction) videoMatrixChanged: (id) sender;
3511 {
3512     bool target, bitrate, quality;
3513
3514     target = bitrate = quality = false;
3515     if( [fVidQualityMatrix isEnabled] )
3516     {
3517         switch( [fVidQualityMatrix selectedRow] )
3518         {
3519             case 0:
3520                 target = true;
3521                 break;
3522             case 1:
3523                 bitrate = true;
3524                 break;
3525             case 2:
3526                 quality = true;
3527                 break;
3528         }
3529     }
3530     [fVidTargetSizeField  setEnabled: target];
3531     [fVidBitrateField     setEnabled: bitrate];
3532     [fVidQualitySlider    setEnabled: quality];
3533     [fVidTwoPassCheck     setEnabled: !quality &&
3534         [fVidQualityMatrix isEnabled]];
3535     if( quality )
3536     {
3537         [fVidTwoPassCheck setState: NSOffState];
3538                 [fVidTurboPassCheck setHidden: YES];
3539                 [fVidTurboPassCheck setState: NSOffState];
3540     }
3541
3542     [self qualitySliderChanged: sender];
3543     [self calculateBitrate: sender];
3544         [self customSettingUsed: sender];
3545 }
3546
3547 - (IBAction) qualitySliderChanged: (id) sender
3548 {
3549     [fVidConstantCell setTitle: [NSString stringWithFormat:
3550         NSLocalizedString( @"Constant quality: %.0f %%", @"" ), 100.0 *
3551         [fVidQualitySlider floatValue]]];
3552                 [self customSettingUsed: sender];
3553 }
3554
3555 - (void) controlTextDidChange: (NSNotification *) notification
3556 {
3557     [self calculateBitrate:nil];
3558 }
3559
3560 - (IBAction) calculateBitrate: (id) sender
3561 {
3562     if( !fHandle || [fVidQualityMatrix selectedRow] != 0 || !SuccessfulScan )
3563     {
3564         return;
3565     }
3566
3567     hb_list_t  * list  = hb_get_titles( fHandle );
3568     hb_title_t * title = (hb_title_t *) hb_list_item( list,
3569             [fSrcTitlePopUp indexOfSelectedItem] );
3570     hb_job_t * job = title->job;
3571      
3572     [fVidBitrateField setIntValue: hb_calc_bitrate( job,
3573             [fVidTargetSizeField intValue] )];
3574 }
3575
3576 #pragma mark -
3577 #pragma mark - Picture
3578
3579 /* lets set the picture size back to the max from right after title scan
3580    Lets use an IBAction here as down the road we could always use a checkbox
3581    in the gui to easily take the user back to max. Remember, the compiler
3582    resolves IBActions down to -(void) during compile anyway */
3583 - (IBAction) revertPictureSizeToMax: (id) sender
3584 {
3585         hb_job_t * job = fTitle->job;
3586         /* We use the output picture width and height
3587      as calculated from libhb right after title is set
3588      in TitlePopUpChanged */
3589         job->width = PicOrigOutputWidth;
3590         job->height = PicOrigOutputHeight;
3591     [fPictureController setAutoCrop:YES];
3592         /* Here we use the auto crop values determined right after scan */
3593         job->crop[0] = AutoCropTop;
3594         job->crop[1] = AutoCropBottom;
3595         job->crop[2] = AutoCropLeft;
3596         job->crop[3] = AutoCropRight;
3597     
3598     
3599     [self calculatePictureSizing: sender];
3600     /* We call method to change UI to reflect whether a preset is used or not*/    
3601     [self customSettingUsed: sender];
3602 }
3603
3604 /**
3605  * Registers changes made in the Picture Settings Window.
3606  */
3607
3608 - (void)pictureSettingsDidChange {
3609         [self calculatePictureSizing:nil];
3610 }
3611
3612 /* Get and Display Current Pic Settings in main window */
3613 - (IBAction) calculatePictureSizing: (id) sender
3614 {
3615         [fPicSettingsOutp setStringValue: [NSString stringWithFormat:@"%d x %d", fTitle->job->width, fTitle->job->height]];
3616         
3617     if (fTitle->job->pixel_ratio == 1)
3618         {
3619         int titlewidth = fTitle->width-fTitle->job->crop[2]-fTitle->job->crop[3];
3620         int arpwidth = fTitle->job->pixel_aspect_width;
3621         int arpheight = fTitle->job->pixel_aspect_height;
3622         int displayparwidth = titlewidth * arpwidth / arpheight;
3623         int displayparheight = fTitle->height-fTitle->job->crop[0]-fTitle->job->crop[1];
3624         [fPicSettingsOutp setStringValue: [NSString stringWithFormat:@"%d x %d", titlewidth, displayparheight]];
3625         [fPicSettingsAnamorphic setStringValue: [NSString stringWithFormat:@"%d x %d Strict", displayparwidth, displayparheight]];
3626         fTitle->job->keep_ratio = 0;
3627         }
3628     else if (fTitle->job->pixel_ratio == 2)
3629     {
3630         hb_job_t * job = fTitle->job;
3631         int output_width, output_height, output_par_width, output_par_height;
3632         hb_set_anamorphic_size(job, &output_width, &output_height, &output_par_width, &output_par_height);
3633         int display_width;
3634         display_width = output_width * output_par_width / output_par_height;
3635
3636         [fPicSettingsOutp setStringValue: [NSString stringWithFormat:@"%d x %d", output_width, output_height]];
3637         [fPicSettingsAnamorphic setStringValue: [NSString stringWithFormat:@"%d x %d Loose", display_width, output_height]];
3638
3639         fTitle->job->keep_ratio = 0;
3640     }
3641         else
3642         {
3643         [fPicSettingsAnamorphic setStringValue:@"Off"];
3644         }
3645
3646         /* Set ON/Off values for the deinterlace/keep aspect ratio according to boolean */
3647         if (fTitle->job->keep_ratio > 0)
3648         {
3649                 [fPicSettingARkeep setStringValue: @"On"];
3650         }
3651         else
3652         {
3653                 [fPicSettingARkeep setStringValue: @"Off"];
3654         }       
3655     
3656     /* Detelecine */
3657     if ([fPictureController detelecine]) {
3658         [fPicSettingDetelecine setStringValue: @"Yes"];
3659     }
3660     else {
3661         [fPicSettingDetelecine setStringValue: @"No"];
3662     }
3663     
3664     /* Decomb */
3665         if ([fPictureController decomb] == 0)
3666         {
3667                 [fPicSettingDecomb setStringValue: @"Off"];
3668         }
3669         else if ([fPictureController decomb] == 1)
3670         {
3671                 [fPicSettingDecomb setStringValue: @"1:2:6:9:80:16:16"];
3672         }
3673     else if ([fPictureController decomb] == 2)
3674     {
3675         [fPicSettingDecomb setStringValue:[[NSUserDefaults standardUserDefaults] stringForKey:@"DecombCustomString"]];
3676     }
3677
3678     /* VFR (Variable Frame Rate) */
3679     if ([fPictureController vfr]) {
3680         /* We change the string of the fps popup to warn that vfr is on Framerate (FPS): */
3681         [fVidRateField setStringValue: @"Framerate (VFR On):"]; 
3682         /* for VFR we select same as source (or title framerate) and disable the popup.
3683         * We know its index 0 as that is determined in titlePopUpChanged */
3684         [fVidRatePopUp selectItemAtIndex: 0];
3685         [fVidRatePopUp setEnabled: NO];  
3686         
3687     }
3688     else {
3689         /* make sure the label for framerate is set to its default */  
3690         [fVidRateField setStringValue: @"Framerate (FPS):"];
3691         [fVidRatePopUp setEnabled: YES];
3692     }
3693     
3694         /* Deinterlace */
3695         if ([fPictureController deinterlace] == 0)
3696         {
3697                 [fPicSettingDeinterlace setStringValue: @"Off"];
3698         }
3699         else if ([fPictureController deinterlace] == 1)
3700         {
3701                 [fPicSettingDeinterlace setStringValue: @"Fast"];
3702         }
3703         else if ([fPictureController deinterlace] == 2)
3704         {
3705                 [fPicSettingDeinterlace setStringValue: @"Slow"];
3706         }
3707         else if ([fPictureController deinterlace] == 3)
3708         {
3709                 [fPicSettingDeinterlace setStringValue: @"Slower"];
3710         }
3711                 
3712     /* Denoise */
3713         if ([fPictureController denoise] == 0)
3714         {
3715                 [fPicSettingDenoise setStringValue: @"Off"];
3716         }
3717         else if ([fPictureController denoise] == 1)
3718         {
3719                 [fPicSettingDenoise setStringValue: @"Weak"];
3720         }
3721         else if ([fPictureController denoise] == 2)
3722         {
3723                 [fPicSettingDenoise setStringValue: @"Medium"];
3724         }
3725         else if ([fPictureController denoise] == 3)
3726         {
3727                 [fPicSettingDenoise setStringValue: @"Strong"];
3728         }
3729     
3730     /* Deblock */
3731     if ([fPictureController deblock]) {
3732         [fPicSettingDeblock setStringValue: @"Yes"];
3733     }
3734     else {
3735         [fPicSettingDeblock setStringValue: @"No"];
3736     }
3737         
3738         if (fTitle->job->pixel_ratio > 0)
3739         {
3740                 [fPicSettingPAR setStringValue: @""];
3741         }
3742         else
3743         {
3744                 [fPicSettingPAR setStringValue: @"Off"];
3745         }
3746         
3747     /* Set the display field for crop as per boolean */
3748         if (![fPictureController autoCrop])
3749         {
3750             [fPicSettingAutoCrop setStringValue: @"Custom"];
3751         }
3752         else
3753         {
3754                 [fPicSettingAutoCrop setStringValue: @"Auto"];
3755         }       
3756         
3757     
3758 }
3759
3760
3761 #pragma mark -
3762 #pragma mark - Audio and Subtitles
3763 - (IBAction) audioCodecsPopUpChanged: (id) sender
3764 {
3765     
3766     NSPopUpButton * audiotrackPopUp;
3767     NSPopUpButton * sampleratePopUp;
3768     NSPopUpButton * bitratePopUp;
3769     NSPopUpButton * audiocodecPopUp;
3770     if (sender == fAudTrack1CodecPopUp)
3771     {
3772         audiotrackPopUp = fAudLang1PopUp;
3773         audiocodecPopUp = fAudTrack1CodecPopUp;
3774         sampleratePopUp = fAudTrack1RatePopUp;
3775         bitratePopUp = fAudTrack1BitratePopUp;
3776     }
3777     else if (sender == fAudTrack2CodecPopUp)
3778     {
3779         audiotrackPopUp = fAudLang2PopUp;
3780         audiocodecPopUp = fAudTrack2CodecPopUp;
3781         sampleratePopUp = fAudTrack2RatePopUp;
3782         bitratePopUp = fAudTrack2BitratePopUp;
3783     }
3784     else if (sender == fAudTrack3CodecPopUp)
3785     {
3786         audiotrackPopUp = fAudLang3PopUp;
3787         audiocodecPopUp = fAudTrack3CodecPopUp;
3788         sampleratePopUp = fAudTrack3RatePopUp;
3789         bitratePopUp = fAudTrack3BitratePopUp;
3790     }
3791     else
3792     {
3793         audiotrackPopUp = fAudLang4PopUp;
3794         audiocodecPopUp = fAudTrack4CodecPopUp;
3795         sampleratePopUp = fAudTrack4RatePopUp;
3796         bitratePopUp = fAudTrack4BitratePopUp;
3797     }
3798         
3799     /* changing the codecs on offer may mean that we can / can't offer mono or 6ch, */
3800         /* so call audioTrackPopUpChanged for both audio tracks to update the mixdown popups */
3801     [self audioTrackPopUpChanged: audiotrackPopUp];
3802     
3803 }
3804
3805 - (IBAction) setEnabledStateOfAudioMixdownControls: (id) sender
3806 {
3807     /* We will be setting the enabled/disabled state of each tracks audio controls based on
3808      * the settings of the source audio for that track. We leave the samplerate and bitrate
3809      * to audiotrackMixdownChanged
3810      */
3811     
3812     /* We will first verify that a lower track number has been selected before enabling each track
3813      * for example, make sure a track is selected for track 1 before enabling track 2, etc.
3814      */
3815     if ([fAudLang1PopUp indexOfSelectedItem] == 0)
3816     {
3817         [fAudLang2PopUp setEnabled: NO];
3818         [fAudLang2PopUp selectItemAtIndex: 0];
3819     }
3820     else
3821     {
3822         [fAudLang2PopUp setEnabled: YES];
3823     }
3824     
3825     if ([fAudLang2PopUp indexOfSelectedItem] == 0)
3826     {
3827         [fAudLang3PopUp setEnabled: NO];
3828         [fAudLang3PopUp selectItemAtIndex: 0];
3829     }
3830     else
3831     {
3832         [fAudLang3PopUp setEnabled: YES];
3833     }
3834     if ([fAudLang3PopUp indexOfSelectedItem] == 0)
3835     {
3836         [fAudLang4PopUp setEnabled: NO];
3837         [fAudLang4PopUp selectItemAtIndex: 0];
3838     }
3839     else
3840     {
3841         [fAudLang4PopUp setEnabled: YES];
3842     }
3843     /* enable/disable the mixdown text and popupbutton for audio track 1 */
3844     [fAudTrack1CodecPopUp setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES];
3845     [fAudTrack1MixPopUp setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES];
3846     [fAudTrack1RatePopUp setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES];
3847     [fAudTrack1BitratePopUp setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES];
3848     [fAudTrack1DrcSlider setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES];
3849     [fAudTrack1DrcField setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES];
3850     if ([fAudLang1PopUp indexOfSelectedItem] == 0)
3851     {
3852         [fAudTrack1CodecPopUp removeAllItems];
3853         [fAudTrack1MixPopUp removeAllItems];
3854         [fAudTrack1RatePopUp removeAllItems];
3855         [fAudTrack1BitratePopUp removeAllItems];
3856         [fAudTrack1DrcSlider setFloatValue: 1.00];
3857         [self audioDRCSliderChanged: fAudTrack1DrcSlider];
3858     }
3859     else if ([[fAudTrack1MixPopUp selectedItem] tag] == HB_ACODEC_AC3)
3860     {
3861         [fAudTrack1RatePopUp setEnabled: NO];
3862         [fAudTrack1BitratePopUp setEnabled: NO];
3863         [fAudTrack1DrcSlider setEnabled: NO];
3864         [fAudTrack1DrcField setEnabled: NO];
3865     }
3866     
3867     /* enable/disable the mixdown text and popupbutton for audio track 2 */
3868     [fAudTrack2CodecPopUp setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES];
3869     [fAudTrack2MixPopUp setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES];
3870     [fAudTrack2RatePopUp setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES];
3871     [fAudTrack2BitratePopUp setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES];
3872     [fAudTrack2DrcSlider setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES];
3873     [fAudTrack2DrcField setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES];
3874     if ([fAudLang2PopUp indexOfSelectedItem] == 0)
3875     {
3876         [fAudTrack2CodecPopUp removeAllItems];
3877         [fAudTrack2MixPopUp removeAllItems];
3878         [fAudTrack2RatePopUp removeAllItems];
3879         [fAudTrack2BitratePopUp removeAllItems];
3880         [fAudTrack2DrcSlider setFloatValue: 1.00];
3881         [self audioDRCSliderChanged: fAudTrack2DrcSlider];
3882     }
3883     else if ([[fAudTrack2MixPopUp selectedItem] tag] == HB_ACODEC_AC3)
3884     {
3885         [fAudTrack2RatePopUp setEnabled: NO];
3886         [fAudTrack2BitratePopUp setEnabled: NO];
3887         [fAudTrack2DrcSlider setEnabled: NO];
3888         [fAudTrack2DrcField setEnabled: NO];
3889     }
3890     
3891     /* enable/disable the mixdown text and popupbutton for audio track 3 */
3892     [fAudTrack3CodecPopUp setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES];
3893     [fAudTrack3MixPopUp setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES];
3894     [fAudTrack3RatePopUp setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES];
3895     [fAudTrack3BitratePopUp setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES];
3896     [fAudTrack3DrcSlider setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES];
3897     [fAudTrack3DrcField setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES];
3898     if ([fAudLang3PopUp indexOfSelectedItem] == 0)
3899     {
3900         [fAudTrack3CodecPopUp removeAllItems];
3901         [fAudTrack3MixPopUp removeAllItems];
3902         [fAudTrack3RatePopUp removeAllItems];
3903         [fAudTrack3BitratePopUp removeAllItems];
3904         [fAudTrack3DrcSlider setFloatValue: 1.00];
3905         [self audioDRCSliderChanged: fAudTrack3DrcSlider];
3906     }
3907     else if ([[fAudTrack3MixPopUp selectedItem] tag] == HB_ACODEC_AC3)
3908     {
3909         [fAudTrack3RatePopUp setEnabled: NO];
3910         [fAudTrack3BitratePopUp setEnabled: NO];
3911         [fAudTrack3DrcSlider setEnabled: NO];
3912         [fAudTrack3DrcField setEnabled: NO];
3913     }
3914     
3915     /* enable/disable the mixdown text and popupbutton for audio track 4 */
3916     [fAudTrack4CodecPopUp setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES];
3917     [fAudTrack4MixPopUp setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES];
3918     [fAudTrack4RatePopUp setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES];
3919     [fAudTrack4BitratePopUp setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES];
3920     [fAudTrack4DrcSlider setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES];
3921     [fAudTrack4DrcField setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES];
3922     if ([fAudLang4PopUp indexOfSelectedItem] == 0)
3923     {
3924         [fAudTrack4CodecPopUp removeAllItems];
3925         [fAudTrack4MixPopUp removeAllItems];
3926         [fAudTrack4RatePopUp removeAllItems];
3927         [fAudTrack4BitratePopUp removeAllItems];
3928         [fAudTrack4DrcSlider setFloatValue: 1.00];
3929         [self audioDRCSliderChanged: fAudTrack4DrcSlider];
3930     }
3931     else if ([[fAudTrack4MixPopUp selectedItem] tag] == HB_ACODEC_AC3)
3932     {
3933         [fAudTrack4RatePopUp setEnabled: NO];
3934         [fAudTrack4BitratePopUp setEnabled: NO];
3935         [fAudTrack4DrcSlider setEnabled: NO];
3936         [fAudTrack4DrcField setEnabled: NO];
3937     }
3938     
3939 }
3940
3941 - (IBAction) addAllAudioTracksToPopUp: (id) sender
3942 {
3943
3944     hb_list_t  * list  = hb_get_titles( fHandle );
3945     hb_title_t * title = (hb_title_t*)
3946         hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
3947
3948         hb_audio_config_t * audio;
3949
3950     [sender removeAllItems];
3951     [sender addItemWithTitle: NSLocalizedString( @"None", @"" )];
3952     for( int i = 0; i < hb_list_count( title->list_audio ); i++ )
3953     {
3954         audio = (hb_audio_config_t *) hb_list_audio_config_item( title->list_audio, i );
3955         [[sender menu] addItemWithTitle:
3956             [NSString stringWithCString: audio->lang.description]
3957             action: NULL keyEquivalent: @""];
3958     }
3959     [sender selectItemAtIndex: 0];
3960
3961 }
3962
3963 - (IBAction) selectAudioTrackInPopUp: (id) sender searchPrefixString: (NSString *) searchPrefixString selectIndexIfNotFound: (int) selectIndexIfNotFound
3964 {
3965
3966     /* this method can be used to find a language, or a language-and-source-format combination, by passing in the appropriate string */
3967     /* e.g. to find the first French track, pass in an NSString * of "Francais" */
3968     /* e.g. to find the first English 5.1 AC3 track, pass in an NSString * of "English (AC3) (5.1 ch)" */
3969     /* if no matching track is found, then selectIndexIfNotFound is used to choose which track to select instead */
3970
3971         if (searchPrefixString)
3972         {
3973
3974         for( int i = 0; i < [sender numberOfItems]; i++ )
3975         {
3976             /* Try to find the desired search string */
3977             if ([[[sender itemAtIndex: i] title] hasPrefix:searchPrefixString])
3978             {
3979                 [sender selectItemAtIndex: i];
3980                 return;
3981             }
3982         }
3983         /* couldn't find the string, so select the requested "search string not found" item */
3984         /* index of 0 means select the "none" item */
3985         /* index of 1 means select the first audio track */
3986         [sender selectItemAtIndex: selectIndexIfNotFound];
3987         }
3988     else
3989     {
3990         /* if no search string is provided, then select the selectIndexIfNotFound item */
3991         [sender selectItemAtIndex: selectIndexIfNotFound];
3992     }
3993
3994 }
3995 - (IBAction) audioAddAudioTrackCodecs: (id)sender
3996 {
3997     int format = [fDstFormatPopUp indexOfSelectedItem];
3998     
3999     /* setup pointers to the appropriate popups for the correct track */
4000     NSPopUpButton * audiocodecPopUp;
4001     NSPopUpButton * audiotrackPopUp;
4002     if (sender == fAudTrack1CodecPopUp)
4003     {
4004         audiotrackPopUp = fAudLang1PopUp;
4005         audiocodecPopUp = fAudTrack1CodecPopUp;
4006     }
4007     else if (sender == fAudTrack2CodecPopUp)
4008     {
4009         audiotrackPopUp = fAudLang2PopUp;
4010         audiocodecPopUp = fAudTrack2CodecPopUp;
4011     }
4012     else if (sender == fAudTrack3CodecPopUp)
4013     {
4014         audiotrackPopUp = fAudLang3PopUp;
4015         audiocodecPopUp = fAudTrack3CodecPopUp;
4016     }
4017     else
4018     {
4019         audiotrackPopUp = fAudLang4PopUp;
4020         audiocodecPopUp = fAudTrack4CodecPopUp;
4021     }
4022     
4023     [audiocodecPopUp removeAllItems];
4024     /* Make sure "None" isnt selected in the source track */
4025     if ([audiotrackPopUp indexOfSelectedItem] > 0)
4026     {
4027         [audiocodecPopUp setEnabled:YES];
4028         NSMenuItem *menuItem;
4029         /* We setup our appropriate popups for codecs and put the int value in the popup tag for easy retrieval */
4030         switch( format )
4031         {
4032             case 0:
4033                 /* MP4 */
4034                 // AAC
4035                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (faac)" action: NULL keyEquivalent: @""];
4036                 [menuItem setTag: HB_ACODEC_FAAC];
4037                 
4038                 // AC3 Passthru
4039                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AC3 Passthru" action: NULL keyEquivalent: @""];
4040                 [menuItem setTag: HB_ACODEC_AC3];
4041                 break;
4042                 
4043             case 1:
4044                 /* MKV */
4045                 // AAC
4046                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (faac)" action: NULL keyEquivalent: @""];
4047                 [menuItem setTag: HB_ACODEC_FAAC];
4048                 // AC3 Passthru
4049                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AC3 Passthru" action: NULL keyEquivalent: @""];
4050                 [menuItem setTag: HB_ACODEC_AC3];
4051                 // MP3
4052                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"MP3 (lame)" action: NULL keyEquivalent: @""];
4053                 [menuItem setTag: HB_ACODEC_LAME];
4054                 // Vorbis
4055                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"Vorbis (vorbis)" action: NULL keyEquivalent: @""];
4056                 [menuItem setTag: HB_ACODEC_VORBIS];
4057                 break;
4058                 
4059             case 2: 
4060                 /* AVI */
4061                 // MP3
4062                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"MP3 (lame)" action: NULL keyEquivalent: @""];
4063                 [menuItem setTag: HB_ACODEC_LAME];
4064                 // AC3 Passthru
4065                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AC3 Passthru" action: NULL keyEquivalent: @""];
4066                 [menuItem setTag: HB_ACODEC_AC3];
4067                 break;
4068                 
4069             case 3:
4070                 /* OGM */
4071                 // Vorbis
4072                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"Vorbis (vorbis)" action: NULL keyEquivalent: @""];
4073                 [menuItem setTag: HB_ACODEC_VORBIS];
4074                 // MP3
4075                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"MP3 (lame)" action: NULL keyEquivalent: @""];
4076                 [menuItem setTag: HB_ACODEC_LAME];
4077                 break;
4078         }
4079         [audiocodecPopUp selectItemAtIndex:0];
4080     }
4081     else
4082     {
4083         [audiocodecPopUp setEnabled:NO];
4084     }
4085 }
4086
4087 - (IBAction) audioTrackPopUpChanged: (id) sender
4088 {
4089     /* utility function to call audioTrackPopUpChanged without passing in a mixdown-to-use */
4090     [self audioTrackPopUpChanged: sender mixdownToUse: 0];
4091 }
4092
4093 - (IBAction) audioTrackPopUpChanged: (id) sender mixdownToUse: (int) mixdownToUse
4094 {
4095     
4096     /* make sure we have a selected title before continuing */
4097     if (fTitle == NULL) return;
4098     /* if the sender is the lanaguage popup and there is nothing in the codec popup, lets call
4099     * audioAddAudioTrackCodecs on the codec popup to populate it properly before moving on
4100     */
4101     if (sender == fAudLang1PopUp && [[fAudTrack1CodecPopUp menu] numberOfItems] == 0)
4102     {
4103         [self audioAddAudioTrackCodecs: fAudTrack1CodecPopUp];
4104     }
4105     if (sender == fAudLang2PopUp && [[fAudTrack2CodecPopUp menu] numberOfItems] == 0)
4106     {
4107         [self audioAddAudioTrackCodecs: fAudTrack2CodecPopUp];
4108     }
4109     if (sender == fAudLang3PopUp && [[fAudTrack3CodecPopUp menu] numberOfItems] == 0)
4110     {
4111         [self audioAddAudioTrackCodecs: fAudTrack3CodecPopUp];
4112     }
4113     if (sender == fAudLang4PopUp && [[fAudTrack4CodecPopUp menu] numberOfItems] == 0)
4114     {
4115         [self audioAddAudioTrackCodecs: fAudTrack4CodecPopUp];
4116     }
4117     
4118     /* Now lets make the sender the appropriate Audio Track popup from this point on */
4119     if (sender == fAudTrack1CodecPopUp || sender == fAudTrack1MixPopUp)
4120     {
4121         sender = fAudLang1PopUp;
4122     }
4123     if (sender == fAudTrack2CodecPopUp || sender == fAudTrack2MixPopUp)
4124     {
4125         sender = fAudLang2PopUp;
4126     }
4127     if (sender == fAudTrack3CodecPopUp || sender == fAudTrack3MixPopUp)
4128     {
4129         sender = fAudLang3PopUp;
4130     }
4131     if (sender == fAudTrack4CodecPopUp || sender == fAudTrack4MixPopUp)
4132     {
4133         sender = fAudLang4PopUp;
4134     }
4135     
4136     /* pointer to this track's mixdown, codec, sample rate and bitrate NSPopUpButton's */
4137     NSPopUpButton * mixdownPopUp;
4138     NSPopUpButton * audiocodecPopUp;
4139     NSPopUpButton * sampleratePopUp;
4140     NSPopUpButton * bitratePopUp;
4141     if (sender == fAudLang1PopUp)
4142     {
4143         mixdownPopUp = fAudTrack1MixPopUp;
4144         audiocodecPopUp = fAudTrack1CodecPopUp;
4145         sampleratePopUp = fAudTrack1RatePopUp;
4146         bitratePopUp = fAudTrack1BitratePopUp;
4147     }
4148     else if (sender == fAudLang2PopUp)
4149     {
4150         mixdownPopUp = fAudTrack2MixPopUp;
4151         audiocodecPopUp = fAudTrack2CodecPopUp;
4152         sampleratePopUp = fAudTrack2RatePopUp;
4153         bitratePopUp = fAudTrack2BitratePopUp;
4154     }
4155     else if (sender == fAudLang3PopUp)
4156     {
4157         mixdownPopUp = fAudTrack3MixPopUp;
4158         audiocodecPopUp = fAudTrack3CodecPopUp;
4159         sampleratePopUp = fAudTrack3RatePopUp;
4160         bitratePopUp = fAudTrack3BitratePopUp;
4161     }
4162     else
4163     {
4164         mixdownPopUp = fAudTrack4MixPopUp;
4165         audiocodecPopUp = fAudTrack4CodecPopUp;
4166         sampleratePopUp = fAudTrack4RatePopUp;
4167         bitratePopUp = fAudTrack4BitratePopUp;
4168     }
4169
4170     /* get the index of the selected audio Track*/
4171     int thisAudioIndex = [sender indexOfSelectedItem] - 1;
4172
4173     /* pointer for the hb_audio_s struct we will use later on */
4174     hb_audio_config_t * audio;
4175
4176     int acodec;
4177     /* check if the audio mixdown controls need their enabled state changing */
4178     [self setEnabledStateOfAudioMixdownControls:nil];
4179
4180     if (thisAudioIndex != -1)
4181     {
4182
4183         /* get the audio */
4184         audio = (hb_audio_config_t *) hb_list_audio_config_item( fTitle->list_audio, thisAudioIndex );// Should "fTitle" be title and be setup ?
4185
4186         /* actually manipulate the proper mixdowns here */
4187         /* delete the previous audio mixdown options */
4188         [mixdownPopUp removeAllItems];
4189
4190         acodec = [[audiocodecPopUp selectedItem] tag];
4191
4192         if (audio != NULL)
4193         {
4194
4195             /* find out if our selected output audio codec supports mono and / or 6ch */
4196             /* we also check for an input codec of AC3 or DCA,
4197              as they are the only libraries able to do the mixdown to mono / conversion to 6-ch */
4198             /* audioCodecsSupportMono and audioCodecsSupport6Ch are the same for now,
4199              but this may change in the future, so they are separated for flexibility */
4200             int audioCodecsSupportMono =
4201                     (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
4202                     (acodec != HB_ACODEC_LAME);
4203             int audioCodecsSupport6Ch =
4204                     (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
4205                     (acodec != HB_ACODEC_LAME);
4206             
4207             /* check for AC-3 passthru */
4208             if (audio->in.codec == HB_ACODEC_AC3 && acodec == HB_ACODEC_AC3)
4209             {
4210                 
4211             NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
4212                  [NSString stringWithCString: "AC3 Passthru"]
4213                                                action: NULL keyEquivalent: @""];
4214              [menuItem setTag: HB_ACODEC_AC3];   
4215             }
4216             else
4217             {
4218                 
4219                 /* add the appropriate audio mixdown menuitems to the popupbutton */
4220                 /* in each case, we set the new menuitem's tag to be the amixdown value for that mixdown,
4221                  so that we can reference the mixdown later */
4222                 
4223                 /* keep a track of the min and max mixdowns we used, so we can select the best match later */
4224                 int minMixdownUsed = 0;
4225                 int maxMixdownUsed = 0;
4226                 
4227                 /* get the input channel layout without any lfe channels */
4228                 int layout = audio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
4229                 
4230                 /* do we want to add a mono option? */
4231                 if (audioCodecsSupportMono == 1)
4232                 {
4233                     NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
4234                                             [NSString stringWithCString: hb_audio_mixdowns[0].human_readable_name]
4235                                                                           action: NULL keyEquivalent: @""];
4236                     [menuItem setTag: hb_audio_mixdowns[0].amixdown];
4237                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[0].amixdown;
4238                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[0].amixdown);
4239                 }
4240                 
4241                 /* do we want to add a stereo option? */
4242                 /* offer stereo if we have a mono source and non-mono-supporting codecs, as otherwise we won't have a mixdown at all */
4243                 /* also offer stereo if we have a stereo-or-better source */
4244                 if ((layout == HB_INPUT_CH_LAYOUT_MONO && audioCodecsSupportMono == 0) || layout >= HB_INPUT_CH_LAYOUT_STEREO)
4245                 {
4246                     NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
4247                                             [NSString stringWithCString: hb_audio_mixdowns[1].human_readable_name]
4248                                                                           action: NULL keyEquivalent: @""];
4249                     [menuItem setTag: hb_audio_mixdowns[1].amixdown];
4250                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[1].amixdown;
4251                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[1].amixdown);
4252                 }
4253                 
4254                 /* do we want to add a dolby surround (DPL1) option? */
4255                 if (layout == HB_INPUT_CH_LAYOUT_3F1R || layout == HB_INPUT_CH_LAYOUT_3F2R || layout == HB_INPUT_CH_LAYOUT_DOLBY)
4256                 {
4257                     NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
4258                                             [NSString stringWithCString: hb_audio_mixdowns[2].human_readable_name]
4259                                                                           action: NULL keyEquivalent: @""];
4260                     [menuItem setTag: hb_audio_mixdowns[2].amixdown];
4261                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[2].amixdown;
4262                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[2].amixdown);
4263                 }
4264                 
4265                 /* do we want to add a dolby pro logic 2 (DPL2) option? */
4266                 if (layout == HB_INPUT_CH_LAYOUT_3F2R)
4267                 {
4268                     NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
4269                                             [NSString stringWithCString: hb_audio_mixdowns[3].human_readable_name]
4270                                                                           action: NULL keyEquivalent: @""];
4271                     [menuItem setTag: hb_audio_mixdowns[3].amixdown];
4272                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[3].amixdown;
4273                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[3].amixdown);
4274                 }
4275                 
4276                 /* do we want to add a 6-channel discrete option? */
4277                 if (audioCodecsSupport6Ch == 1 && layout == HB_INPUT_CH_LAYOUT_3F2R && (audio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE))
4278                 {
4279                     NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
4280                                             [NSString stringWithCString: hb_audio_mixdowns[4].human_readable_name]
4281                                                                           action: NULL keyEquivalent: @""];
4282                     [menuItem setTag: hb_audio_mixdowns[4].amixdown];
4283                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[4].amixdown;
4284                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[4].amixdown);
4285                 }
4286                 
4287                 /* do we want to add an AC-3 passthrough option? */
4288                 if (audio->in.codec == HB_ACODEC_AC3 && acodec == HB_ACODEC_AC3) 
4289                 {
4290                     NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
4291                                             [NSString stringWithCString: hb_audio_mixdowns[5].human_readable_name]
4292                                                                           action: NULL keyEquivalent: @""];
4293                     [menuItem setTag: HB_ACODEC_AC3];
4294                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[5].amixdown;
4295                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[5].amixdown);
4296                 }
4297                 
4298                 /* auto-select the best mixdown based on our saved mixdown preference */
4299                 
4300                 /* for now, this is hard-coded to a "best" mixdown of HB_AMIXDOWN_DOLBYPLII */
4301                 /* ultimately this should be a prefs option */
4302                 int useMixdown;
4303                 
4304                 /* if we passed in a mixdown to use - in order to load a preset - then try and use it */
4305                 if (mixdownToUse > 0)
4306                 {
4307                     useMixdown = mixdownToUse;
4308                 }
4309                 else
4310                 {
4311                     useMixdown = HB_AMIXDOWN_DOLBYPLII;
4312                 }
4313                 
4314                 /* if useMixdown > maxMixdownUsed, then use maxMixdownUsed */
4315                 if (useMixdown > maxMixdownUsed)
4316                 { 
4317                     useMixdown = maxMixdownUsed;
4318                 }
4319                 
4320                 /* if useMixdown < minMixdownUsed, then use minMixdownUsed */
4321                 if (useMixdown < minMixdownUsed)
4322                 { 
4323                     useMixdown = minMixdownUsed;
4324                 }
4325                 
4326                 /* select the (possibly-amended) preferred mixdown */
4327                 [mixdownPopUp selectItemWithTag: useMixdown];
4328
4329             }
4330             /* In the case of a source track that is not AC3 and the user tries to use AC3 Passthru (which does not work)
4331              * we force the Audio Codec choice back to a workable codec. We use MP3 for avi and aac for all
4332              * other containers.
4333              */
4334             if (audio->in.codec != HB_ACODEC_AC3 && [[audiocodecPopUp selectedItem] tag] == HB_ACODEC_AC3)
4335             {
4336                 /* If we are using the avi container, we select MP3 as there is no aac available*/
4337                 if ([[fDstFormatPopUp selectedItem] tag] == HB_MUX_AVI)
4338                 {
4339                     [audiocodecPopUp selectItemWithTag: HB_ACODEC_LAME];
4340                 }
4341                 else
4342                 {
4343                     [audiocodecPopUp selectItemWithTag: HB_ACODEC_FAAC];
4344                 }
4345             }
4346             /* Setup our samplerate and bitrate popups we will need based on mixdown */
4347             [self audioTrackMixdownChanged: mixdownPopUp];             
4348         }
4349     
4350     }
4351     if( [fDstFormatPopUp indexOfSelectedItem] == 0 )
4352     {
4353         [self autoSetM4vExtension: sender];
4354         [self shouldEnableHttpMp4CheckBox: sender];
4355     }
4356 }
4357
4358 - (IBAction) audioTrackMixdownChanged: (id) sender
4359 {
4360     
4361     int acodec;
4362     /* setup pointers to all of the other audio track controls
4363     * we will need later
4364     */
4365     NSPopUpButton * mixdownPopUp;
4366     NSPopUpButton * sampleratePopUp;
4367     NSPopUpButton * bitratePopUp;
4368     NSPopUpButton * audiocodecPopUp;
4369     NSPopUpButton * audiotrackPopUp;
4370     NSSlider * drcSlider;
4371     NSTextField * drcField;
4372     if (sender == fAudTrack1MixPopUp)
4373     {
4374         audiotrackPopUp = fAudLang1PopUp;
4375         audiocodecPopUp = fAudTrack1CodecPopUp;
4376         mixdownPopUp = fAudTrack1MixPopUp;
4377         sampleratePopUp = fAudTrack1RatePopUp;
4378         bitratePopUp = fAudTrack1BitratePopUp;
4379         drcSlider = fAudTrack1DrcSlider;
4380         drcField = fAudTrack1DrcField;
4381     }
4382     else if (sender == fAudTrack2MixPopUp)
4383     {
4384         audiotrackPopUp = fAudLang2PopUp;
4385         audiocodecPopUp = fAudTrack2CodecPopUp;
4386         mixdownPopUp = fAudTrack2MixPopUp;
4387         sampleratePopUp = fAudTrack2RatePopUp;
4388         bitratePopUp = fAudTrack2BitratePopUp;
4389         drcSlider = fAudTrack2DrcSlider;
4390         drcField = fAudTrack2DrcField;
4391     }
4392     else if (sender == fAudTrack3MixPopUp)
4393     {
4394         audiotrackPopUp = fAudLang3PopUp;
4395         audiocodecPopUp = fAudTrack3CodecPopUp;
4396         mixdownPopUp = fAudTrack3MixPopUp;
4397         sampleratePopUp = fAudTrack3RatePopUp;
4398         bitratePopUp = fAudTrack3BitratePopUp;
4399         drcSlider = fAudTrack3DrcSlider;
4400         drcField = fAudTrack3DrcField;
4401     }
4402     else
4403     {
4404         audiotrackPopUp = fAudLang4PopUp;
4405         audiocodecPopUp = fAudTrack4CodecPopUp;
4406         mixdownPopUp = fAudTrack4MixPopUp;
4407         sampleratePopUp = fAudTrack4RatePopUp;
4408         bitratePopUp = fAudTrack4BitratePopUp;
4409         drcSlider = fAudTrack4DrcSlider;
4410         drcField = fAudTrack4DrcField;
4411     }
4412     acodec = [[audiocodecPopUp selectedItem] tag];
4413     /* storage variable for the min and max bitrate allowed for this codec */
4414     int minbitrate;
4415     int maxbitrate;
4416     
4417     switch( acodec )
4418     {
4419         case HB_ACODEC_FAAC:
4420             /* check if we have a 6ch discrete conversion in either audio track */
4421             if ([[mixdownPopUp selectedItem] tag] == HB_AMIXDOWN_6CH)
4422             {
4423                 /* FAAC is happy using our min bitrate of 32 kbps, even for 6ch */
4424                 minbitrate = 32;
4425                 /* If either mixdown popup includes 6-channel discrete, then allow up to 384 kbps */
4426                 maxbitrate = 384;
4427                 break;
4428             }
4429             else
4430             {
4431                 /* FAAC is happy using our min bitrate of 32 kbps for stereo or mono */
4432                 minbitrate = 32;
4433                 /* FAAC won't honour anything more than 160 for stereo, so let's not offer it */
4434                 /* note: haven't dealt with mono separately here, FAAC will just use the max it can */
4435                 maxbitrate = 160;
4436                 break;
4437             }
4438             
4439             case HB_ACODEC_LAME:
4440             /* Lame is happy using our min bitrate of 32 kbps */
4441             minbitrate = 32;
4442             /* Lame won't encode if the bitrate is higher than 320 kbps */
4443             maxbitrate = 320;
4444             break;
4445             
4446             case HB_ACODEC_VORBIS:
4447             if ([[mixdownPopUp selectedItem] tag] == HB_AMIXDOWN_6CH)
4448             {
4449                 /* Vorbis causes a crash if we use a bitrate below 192 kbps with 6 channel */
4450                 minbitrate = 192;
4451                 /* If either mixdown popup includes 6-channel discrete, then allow up to 384 kbps */
4452                 maxbitrate = 384;
4453                 break;
4454             }
4455             else
4456             {
4457                 /* Vorbis causes a crash if we use a bitrate below 48 kbps */
4458                 minbitrate = 48;
4459                 /* Vorbis can cope with 384 kbps quite happily, even for stereo */
4460                 maxbitrate = 384;
4461                 break;
4462             }
4463             
4464             default:
4465             /* AC3 passthru disables the bitrate dropdown anyway, so we might as well just use the min and max bitrate */
4466             minbitrate = 32;
4467             maxbitrate = 384;
4468             
4469     }
4470     
4471     /* make sure we have a selected title before continuing */
4472     if (fTitle == NULL) return;
4473     /* get the audio so we can find out what input rates are*/
4474     hb_audio_config_t * audio;
4475     audio = (hb_audio_config_t *) hb_list_audio_config_item( fTitle->list_audio, [audiotrackPopUp indexOfSelectedItem] - 1 );
4476     int inputbitrate = audio->in.bitrate / 1000;
4477     int inputsamplerate = audio->in.samplerate;
4478     
4479     if ([[mixdownPopUp selectedItem] tag] != HB_ACODEC_AC3)
4480     {
4481         [bitratePopUp removeAllItems];
4482         
4483         for( int i = 0; i < hb_audio_bitrates_count; i++ )
4484         {
4485             if (hb_audio_bitrates[i].rate >= minbitrate && hb_audio_bitrates[i].rate <= maxbitrate)
4486             {
4487                 /* add a new menuitem for this bitrate */
4488                 NSMenuItem *menuItem = [[bitratePopUp menu] addItemWithTitle:
4489                                         [NSString stringWithCString: hb_audio_bitrates[i].string]
4490                                                                       action: NULL keyEquivalent: @""];
4491                 /* set its tag to be the actual bitrate as an integer, so we can retrieve it later */
4492                 [menuItem setTag: hb_audio_bitrates[i].rate];
4493             }
4494         }
4495         
4496         /* select the default bitrate (but use 384 for 6-ch AAC) */
4497         if ([[mixdownPopUp selectedItem] tag] == HB_AMIXDOWN_6CH)
4498         {
4499             [bitratePopUp selectItemWithTag: 384];
4500         }
4501         else
4502         {
4503             [bitratePopUp selectItemWithTag: hb_audio_bitrates[hb_audio_bitrates_default].rate];
4504         }
4505     }
4506     /* populate and set the sample rate popup */
4507     /* Audio samplerate */
4508     [sampleratePopUp removeAllItems];
4509     /* we create a same as source selection (Auto) so that we can choose to use the input sample rate */
4510     NSMenuItem *menuItem = [[sampleratePopUp menu] addItemWithTitle: @"Auto" action: NULL keyEquivalent: @""];
4511     [menuItem setTag: inputsamplerate];
4512     
4513     for( int i = 0; i < hb_audio_rates_count; i++ )
4514     {
4515         NSMenuItem *menuItem = [[sampleratePopUp menu] addItemWithTitle:
4516                                 [NSString stringWithCString: hb_audio_rates[i].string]
4517                                                                  action: NULL keyEquivalent: @""];
4518         [menuItem setTag: hb_audio_rates[i].rate];
4519     }
4520     /* We use the input sample rate as the default sample rate as downsampling just makes audio worse
4521     * and there is no compelling reason to use anything else as default, though the users default
4522     * preset will likely override any setting chosen here.
4523     */
4524     [sampleratePopUp selectItemWithTag: inputsamplerate];
4525     
4526     
4527     /* Since AC3 Pass Thru uses the input ac3 bitrate and sample rate, we get the input tracks
4528     * bitrate and dispay it in the bitrate popup even though libhb happily ignores any bitrate input from
4529     * the gui. We do this for better user feedback in the audio tab as well as the queue for the most part
4530     */
4531     if ([[mixdownPopUp selectedItem] tag] == HB_ACODEC_AC3)
4532     {
4533         
4534         /* lets also set the bitrate popup to the input bitrate as thats what passthru will use */
4535         [bitratePopUp removeAllItems];
4536         NSMenuItem *menuItem = [[bitratePopUp menu] addItemWithTitle:
4537                                 [NSString stringWithFormat:@"%d", inputbitrate]
4538                                                               action: NULL keyEquivalent: @""];
4539         [menuItem setTag: inputbitrate];
4540         /* For ac3 passthru we disable the sample rate and bitrate popups as well as the drc slider*/
4541         [bitratePopUp setEnabled: NO];
4542         [sampleratePopUp setEnabled: NO];
4543         
4544         [drcSlider setFloatValue: 1.00];
4545         [self audioDRCSliderChanged: drcSlider];
4546         [drcSlider setEnabled: NO];
4547         [drcField setEnabled: NO];
4548     }
4549     else
4550     {
4551         [sampleratePopUp setEnabled: YES];
4552         [bitratePopUp setEnabled: YES];
4553         [drcSlider setEnabled: YES];
4554         [drcField setEnabled: YES];
4555     }
4556     
4557 }
4558
4559 - (IBAction) audioDRCSliderChanged: (id) sender
4560 {
4561     NSSlider * drcSlider;
4562     NSTextField * drcField;
4563     if (sender == fAudTrack1DrcSlider)
4564     {
4565         drcSlider = fAudTrack1DrcSlider;
4566         drcField = fAudTrack1DrcField;
4567     }
4568     else if (sender == fAudTrack2DrcSlider)
4569     {
4570         drcSlider = fAudTrack2DrcSlider;
4571         drcField = fAudTrack2DrcField;
4572     }
4573     else if (sender == fAudTrack3DrcSlider)
4574     {
4575         drcSlider = fAudTrack3DrcSlider;
4576         drcField = fAudTrack3DrcField;
4577     }
4578     else
4579     {
4580         drcSlider = fAudTrack4DrcSlider;
4581         drcField = fAudTrack4DrcField;
4582     }
4583     [drcField setStringValue: [NSString stringWithFormat: @"%.2f", [drcSlider floatValue]]];
4584     /* For now, do not call this until we have an intelligent way to determine audio track selections
4585     * compared to presets
4586     */
4587     //[self customSettingUsed: sender];
4588 }
4589
4590 - (IBAction) subtitleSelectionChanged: (id) sender
4591 {
4592         if ([fSubPopUp indexOfSelectedItem] == 0)
4593         {
4594         [fSubForcedCheck setState: NSOffState];
4595         [fSubForcedCheck setEnabled: NO];       
4596         }
4597         else
4598         {
4599         [fSubForcedCheck setEnabled: YES];      
4600         }
4601         
4602 }
4603
4604
4605
4606
4607 #pragma mark -
4608 #pragma mark Open New Windows
4609
4610 - (IBAction) openHomepage: (id) sender
4611 {
4612     [[NSWorkspace sharedWorkspace] openURL: [NSURL
4613         URLWithString:@"http://handbrake.fr/"]];
4614 }
4615
4616 - (IBAction) openForums: (id) sender
4617 {
4618     [[NSWorkspace sharedWorkspace] openURL: [NSURL
4619         URLWithString:@"http://handbrake.fr/forum/"]];
4620 }
4621 - (IBAction) openUserGuide: (id) sender
4622 {
4623     [[NSWorkspace sharedWorkspace] openURL: [NSURL
4624         URLWithString:@"http://handbrake.fr/trac/wiki/HandBrakeGuide"]];
4625 }
4626
4627 /**
4628  * Shows debug output window.
4629  */
4630 - (IBAction)showDebugOutputPanel:(id)sender
4631 {
4632     [outputPanel showOutputPanel:sender];
4633 }
4634
4635 /**
4636  * Shows preferences window.
4637  */
4638 - (IBAction) showPreferencesWindow: (id) sender
4639 {
4640     NSWindow * window = [fPreferencesController window];
4641     if (![window isVisible])
4642         [window center];
4643
4644     [window makeKeyAndOrderFront: nil];
4645 }
4646
4647 /**
4648  * Shows queue window.
4649  */
4650 - (IBAction) showQueueWindow:(id)sender
4651 {
4652     [fQueueController showQueueWindow:sender];
4653 }
4654
4655
4656 - (IBAction) toggleDrawer:(id)sender {
4657     [fPresetDrawer toggle:self];
4658 }
4659
4660 /**
4661  * Shows Picture Settings Window.
4662  */
4663
4664 - (IBAction) showPicturePanel: (id) sender
4665 {
4666         hb_list_t  * list  = hb_get_titles( fHandle );
4667     hb_title_t * title = (hb_title_t *) hb_list_item( list,
4668             [fSrcTitlePopUp indexOfSelectedItem] );
4669     [fPictureController showPanelInWindow:fWindow forTitle:title];
4670 }
4671
4672 #pragma mark -
4673 #pragma mark Preset Outline View Methods
4674 #pragma mark - Required
4675 /* These are required by the NSOutlineView Datasource Delegate */
4676 /* We use this to deterimine children of an item */
4677 - (id)outlineView:(NSOutlineView *)fPresetsOutlineView child:(NSInteger)index ofItem:(id)item
4678 {
4679 if (item == nil)
4680         return [UserPresets objectAtIndex:index];
4681     
4682     // We are only one level deep, so we can't be asked about children
4683     NSAssert (NO, @"Presets View outlineView:child:ofItem: currently can't handle nested items.");
4684     return nil;
4685 }
4686 /* We use this to determine if an item should be expandable */
4687 - (BOOL)outlineView:(NSOutlineView *)fPresetsOutlineView isItemExpandable:(id)item
4688 {
4689
4690     /* For now, we maintain one level, so set to no
4691     * when nested, we set to yes for any preset "folders"
4692     */
4693     return NO;
4694
4695 }
4696 /* used to specify the number of levels to show for each item */
4697 - (int)outlineView:(NSOutlineView *)fPresetsOutlineView numberOfChildrenOfItem:(id)item
4698 {
4699     /* currently use no levels to test outline view viability */
4700     if (item == nil)
4701         return [UserPresets count];
4702     else
4703         return 0;
4704 }
4705 /* Used to tell the outline view which information is to be displayed per item */
4706 - (id)outlineView:(NSOutlineView *)fPresetsOutlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
4707 {
4708         /* We have two columns right now, icon and PresetName */
4709         
4710     if ([[tableColumn identifier] isEqualToString:@"PresetName"])
4711     {
4712         return [item objectForKey:@"PresetName"];
4713     }
4714     else
4715     {
4716         return @"something";
4717     }
4718 }
4719
4720 #pragma mark - Added Functionality (optional)
4721 /* Use to customize the font and display characteristics of the title cell */
4722 - (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
4723 {
4724     if ([[tableColumn identifier] isEqualToString:@"PresetName"])
4725     {
4726         NSDictionary *userPresetDict = item;
4727         NSFont *txtFont;
4728         NSColor *fontColor;
4729         NSColor *shadowColor;
4730         txtFont = [NSFont systemFontOfSize: [NSFont smallSystemFontSize]];
4731         /*check to see if its a selected row */
4732         if ([fPresetsOutlineView selectedRow] == [fPresetsOutlineView rowForItem:item])
4733         {
4734             
4735             fontColor = [NSColor blackColor];
4736             shadowColor = [NSColor colorWithDeviceRed:(127.0/255.0) green:(140.0/255.0) blue:(160.0/255.0) alpha:1.0];
4737         }
4738         else
4739         {
4740             if ([[userPresetDict objectForKey:@"Type"] intValue] == 0)
4741             {
4742                 fontColor = [NSColor blueColor];
4743             }
4744             else // User created preset, use a black font
4745             {
4746                 fontColor = [NSColor blackColor];
4747             }
4748             shadowColor = nil;
4749         }
4750         /* We use Bold Text for the HB Default */
4751         if ([[userPresetDict objectForKey:@"Default"] intValue] == 1)// 1 is HB default
4752         {
4753             txtFont = [NSFont boldSystemFontOfSize: [NSFont smallSystemFontSize]];
4754         }
4755         /* We use Bold Text for the User Specified Default */
4756         if ([[userPresetDict objectForKey:@"Default"] intValue] == 2)// 2 is User default
4757         {
4758             txtFont = [NSFont boldSystemFontOfSize: [NSFont smallSystemFontSize]];
4759         }
4760         
4761         
4762         [cell setTextColor:fontColor];
4763         [cell setFont:txtFont];
4764         
4765     }
4766 }
4767
4768 /* We use this to edit the name field in the outline view */
4769 - (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
4770 {
4771     if ([[tableColumn identifier] isEqualToString:@"PresetName"])
4772     {
4773         id theRecord;
4774         
4775         theRecord = item;
4776         [theRecord setObject:object forKey:@"PresetName"];
4777         
4778         [self sortPresets];
4779         
4780         [fPresetsOutlineView reloadData];
4781         /* We save all of the preset data here */
4782         [self savePreset];
4783     }
4784 }
4785 /* We use this to provide tooltips for the items in the presets outline view */
4786 - (NSString *)outlineView:(NSOutlineView *)fPresetsOutlineView toolTipForCell:(NSCell *)cell rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)tc item:(id)item mouseLocation:(NSPoint)mouseLocation
4787 {
4788     //if ([[tc identifier] isEqualToString:@"PresetName"])
4789     //{
4790         /* initialize the tooltip contents variable */
4791         NSString *loc_tip;
4792         /* if there is a description for the preset, we show it in the tooltip */
4793         if ([item objectForKey:@"PresetDescription"])
4794         {
4795             loc_tip = [item objectForKey:@"PresetDescription"];
4796             return (loc_tip);
4797         }
4798         else
4799         {
4800             loc_tip = @"No description available";
4801         }
4802         return (loc_tip);
4803     //}
4804 }
4805
4806 #pragma mark -
4807 #pragma mark Preset Outline View Methods (dragging related)
4808
4809
4810 - (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard
4811 {
4812         // Dragging is only allowed for custom presets.
4813         if ([[[UserPresets objectAtIndex:[fPresetsOutlineView selectedRow]] objectForKey:@"Type"] intValue] == 0) // 0 is built in preset
4814     {
4815         return NO;
4816     }
4817     // Don't retain since this is just holding temporaral drag information, and it is
4818     //only used during a drag!  We could put this in the pboard actually.
4819     fDraggedNodes = items;
4820     // Provide data for our custom type, and simple NSStrings.
4821     [pboard declareTypes:[NSArray arrayWithObjects: DragDropSimplePboardType, nil] owner:self];
4822     
4823     // the actual data doesn't matter since DragDropSimplePboardType drags aren't recognized by anyone but us!.
4824     [pboard setData:[NSData data] forType:DragDropSimplePboardType]; 
4825     
4826     return YES;
4827 }
4828
4829 - (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index
4830 {
4831         // Don't allow dropping ONTO an item since they can't really contain any children.
4832     
4833     BOOL isOnDropTypeProposal = index == NSOutlineViewDropOnItemIndex;
4834     if (isOnDropTypeProposal)
4835         return NSDragOperationNone;
4836     
4837     
4838         // Don't allow dropping INTO an item since they can't really contain any children as of yet.
4839         
4840     if (item != nil)
4841         {
4842                 index = [fPresetsOutlineView rowForItem: item] + 1;
4843                 item = nil;
4844         }
4845     
4846     // Don't allow dropping into the Built In Presets.
4847     if (index < presetCurrentBuiltInCount)
4848     {
4849         return NSDragOperationNone;
4850         index = MAX (index, presetCurrentBuiltInCount);
4851         }
4852         
4853     [outlineView setDropItem:item dropChildIndex:index];
4854     return NSDragOperationGeneric;
4855 }
4856
4857
4858
4859 - (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index
4860 {
4861     NSMutableIndexSet *moveItems = [NSMutableIndexSet indexSet];
4862     
4863     id obj;
4864     NSEnumerator *enumerator = [fDraggedNodes objectEnumerator];
4865     while (obj = [enumerator nextObject])
4866     {
4867         [moveItems addIndex:[UserPresets indexOfObject:obj]];
4868     }
4869     // Successful drop, lets rearrange the view and save it all
4870     [self moveObjectsInPresetsArray:UserPresets fromIndexes:moveItems toIndex: index];
4871     [fPresetsOutlineView reloadData];
4872     [self savePreset];
4873     return YES;
4874 }
4875
4876 - (void)moveObjectsInPresetsArray:(NSMutableArray *)array fromIndexes:(NSIndexSet *)indexSet toIndex:(unsigned)insertIndex
4877 {
4878     unsigned index = [indexSet lastIndex];
4879     unsigned aboveInsertIndexCount = 0;
4880     
4881     while (index != NSNotFound)
4882     {
4883         unsigned removeIndex;
4884         
4885         if (index >= insertIndex)
4886         {
4887             removeIndex = index + aboveInsertIndexCount;
4888             aboveInsertIndexCount++;
4889         }
4890         else
4891         {
4892             removeIndex = index;
4893             insertIndex--;
4894         }
4895         
4896         id object = [[array objectAtIndex:removeIndex] retain];
4897         [array removeObjectAtIndex:removeIndex];
4898         [array insertObject:object atIndex:insertIndex];
4899         [object release];
4900         
4901         index = [indexSet indexLessThanIndex:index];
4902     }
4903 }
4904
4905
4906
4907 #pragma mark - Functional Preset NSOutlineView Methods
4908
4909 - (IBAction)selectPreset:(id)sender
4910 {
4911
4912     if ([fPresetsOutlineView selectedRow] >= 0)
4913     {
4914         chosenPreset = [fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]];
4915         /* we set the preset display field in main window here */
4916         [fPresetSelectedDisplay setStringValue:[chosenPreset objectForKey:@"PresetName"]];
4917         if ([[chosenPreset objectForKey:@"Default"] intValue] == 1)
4918         {
4919             [fPresetSelectedDisplay setStringValue:[NSString stringWithFormat:@"%@ (Default)", [chosenPreset objectForKey:@"PresetName"]]];
4920         }
4921         else
4922         {
4923             [fPresetSelectedDisplay setStringValue:[chosenPreset objectForKey:@"PresetName"]];
4924         }
4925         /* File Format */
4926         [fDstFormatPopUp selectItemWithTitle:[chosenPreset objectForKey:@"FileFormat"]];
4927         [self formatPopUpChanged:nil];
4928
4929         /* Chapter Markers*/
4930         [fCreateChapterMarkers setState:[[chosenPreset objectForKey:@"ChapterMarkers"] intValue]];
4931         /* Allow Mpeg4 64 bit formatting +4GB file sizes */
4932         [fDstMp4LargeFileCheck setState:[[chosenPreset objectForKey:@"Mp4LargeFile"] intValue]];
4933         /* Mux mp4 with http optimization */
4934         [fDstMp4HttpOptFileCheck setState:[[chosenPreset objectForKey:@"Mp4HttpOptimize"] intValue]];
4935
4936         /* Video encoder */
4937         /* We set the advanced opt string here if applicable*/
4938         [fAdvancedOptions setOptions:[chosenPreset objectForKey:@"x264Option"]];
4939         /* We use a conditional to account for the new x264 encoder dropdown as well as presets made using legacy x264 settings*/
4940         if ([[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"x264 (h.264 Main)"] ||
4941             [[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"x264 (h.264 iPod)"] ||
4942             [[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"x264"])
4943         {
4944             [fVidEncoderPopUp selectItemWithTitle:@"H.264 (x264)"];
4945             /* special case for legacy preset to check the new fDstMp4HttpOptFileCheck checkbox to set the ipod atom */
4946             if ([[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"x264 (h.264 iPod)"])
4947             {
4948                 [fDstMp4iPodFileCheck setState:NSOnState];
4949                 /* We also need to add "level=30:" to the advanced opts string to set the correct level for the iPod when
4950                  encountering a legacy preset as it used to be handled separately from the opt string*/
4951                 [fAdvancedOptions setOptions:[@"level=30:" stringByAppendingString:[fAdvancedOptions optionsString]]];
4952             }
4953             else
4954             {
4955                 [fDstMp4iPodFileCheck setState:NSOffState];
4956             }
4957         }
4958         else if ([[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"FFmpeg"])
4959         {
4960             [fVidEncoderPopUp selectItemWithTitle:@"MPEG-4 (FFmpeg)"];
4961         }
4962         else if ([[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"XviD"])
4963         {
4964             [fVidEncoderPopUp selectItemWithTitle:@"MPEG-4 (XviD)"];
4965         }
4966         else
4967         {
4968             [fVidEncoderPopUp selectItemWithTitle:[chosenPreset objectForKey:@"VideoEncoder"]];
4969         }
4970
4971         /* Lets run through the following functions to get variables set there */
4972         [self videoEncoderPopUpChanged:nil];
4973         /* Set the state of ipod compatible with Mp4iPodCompatible. Only for x264*/
4974         [fDstMp4iPodFileCheck setState:[[chosenPreset objectForKey:@"Mp4iPodCompatible"] intValue]];
4975         [self calculateBitrate:nil];
4976
4977         /* Video quality */
4978         [fVidQualityMatrix selectCellAtRow:[[chosenPreset objectForKey:@"VideoQualityType"] intValue] column:0];
4979
4980         [fVidTargetSizeField setStringValue:[chosenPreset objectForKey:@"VideoTargetSize"]];
4981         [fVidBitrateField setStringValue:[chosenPreset objectForKey:@"VideoAvgBitrate"]];
4982         [fVidQualitySlider setFloatValue:[[chosenPreset objectForKey:@"VideoQualitySlider"] floatValue]];
4983
4984         [self videoMatrixChanged:nil];
4985
4986         /* Video framerate */
4987         /* For video preset video framerate, we want to make sure that Same as source does not conflict with the
4988          detected framerate in the fVidRatePopUp so we use index 0*/
4989         if ([[chosenPreset objectForKey:@"VideoFramerate"] isEqualToString:@"Same as source"])
4990         {
4991             [fVidRatePopUp selectItemAtIndex: 0];
4992         }
4993         else
4994         {
4995             [fVidRatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"VideoFramerate"]];
4996         }
4997
4998         /* GrayScale */
4999         [fVidGrayscaleCheck setState:[[chosenPreset objectForKey:@"VideoGrayScale"] intValue]];
5000
5001         /* 2 Pass Encoding */
5002         [fVidTwoPassCheck setState:[[chosenPreset objectForKey:@"VideoTwoPass"] intValue]];
5003         [self twoPassCheckboxChanged:nil];
5004         /* Turbo 1st pass for 2 Pass Encoding */
5005         [fVidTurboPassCheck setState:[[chosenPreset objectForKey:@"VideoTurboTwoPass"] intValue]];
5006
5007         /*Audio*/
5008         if ([chosenPreset objectForKey:@"FileCodecs"])
5009         {
5010             /* We need to handle the audio codec popup by determining what was chosen from the deprecated Codecs PopUp for past presets*/
5011             if ([[chosenPreset objectForKey:@"FileCodecs"] isEqualToString: @"AVC/H.264 Video / AAC + AC3 Audio"])
5012             {
5013                 /* We need to address setting languages etc. here in the new multi track audio panel */
5014                 /* Track One set here */
5015                 /*for track one though a track should be selected but lets check here anyway and use track one if its not.*/
5016                 if ([fAudLang1PopUp indexOfSelectedItem] == 0)
5017                 {
5018                     [fAudLang1PopUp selectItemAtIndex: 1];
5019                     [self audioTrackPopUpChanged: fAudLang1PopUp];
5020                 }
5021                 [fAudTrack1CodecPopUp selectItemWithTitle: @"AAC (faac)"];
5022                 [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
5023                 /* Track Two, set source same as track one */
5024                 [fAudLang2PopUp selectItemAtIndex: [fAudLang1PopUp indexOfSelectedItem]];
5025                 [self audioTrackPopUpChanged: fAudLang2PopUp];
5026                 [fAudTrack2CodecPopUp selectItemWithTitle: @"AC3 Passthru"];
5027                 [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
5028             }
5029             else if ([[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"MPEG-4 Video / AAC Audio"] ||
5030                      [[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"AVC/H.264 Video / AAC Audio"])
5031             {
5032                 if ([fAudLang1PopUp indexOfSelectedItem] > 0)
5033                 {
5034                     [fAudTrack1CodecPopUp selectItemWithTitle: @"AAC (faac)"];
5035                     [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
5036                 }
5037                 if ([fAudLang2PopUp indexOfSelectedItem] > 0)
5038                 {
5039                     [fAudTrack2CodecPopUp selectItemWithTitle: @"AAC (faac)"];
5040                     [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
5041                 }
5042                 if ([fAudLang3PopUp indexOfSelectedItem] > 0)
5043                 {
5044                     [fAudTrack3CodecPopUp selectItemWithTitle: @"AAC (faac)"];
5045                     [self audioTrackPopUpChanged: fAudTrack3CodecPopUp];
5046                 }
5047                 if ([fAudLang4PopUp indexOfSelectedItem] > 0)
5048                 {
5049                     [fAudTrack4CodecPopUp selectItemWithTitle: @"AAC (faac)"];
5050                     [self audioTrackPopUpChanged: fAudTrack4CodecPopUp];
5051                 }
5052             }
5053             else if ([[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"MPEG-4 Video / AC-3 Audio"] ||
5054                      [[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"AVC/H.264 Video / AC-3 Audio"])
5055             {
5056                 if ([fAudLang1PopUp indexOfSelectedItem] > 0)
5057                 {
5058                     [fAudTrack1CodecPopUp selectItemWithTitle: @"AC3 Passthru"];
5059                     [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
5060                 }
5061                 if ([fAudLang2PopUp indexOfSelectedItem] > 0)
5062                 {
5063                     [fAudTrack2CodecPopUp selectItemWithTitle: @"AC3 Passthru"];
5064                     [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
5065                 }
5066                 if ([fAudLang3PopUp indexOfSelectedItem] > 0)
5067                 {
5068                     [fAudTrack3CodecPopUp selectItemWithTitle: @"AC3 Passthru"];
5069                     [self audioTrackPopUpChanged: fAudTrack3CodecPopUp];
5070                 }
5071                 if ([fAudLang4PopUp indexOfSelectedItem] > 0)
5072                 {
5073                     [fAudTrack4CodecPopUp selectItemWithTitle: @"AC3 Passthru"];
5074                     [self audioTrackPopUpChanged: fAudTrack4CodecPopUp];
5075                 }
5076             }
5077             else if ([[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"MPEG-4 Video / MP3 Audio"] ||
5078                      [[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"AVC/H.264 Video / MP3 Audio"])
5079             {
5080                 if ([fAudLang1PopUp indexOfSelectedItem] > 0)
5081                 {
5082                     [fAudTrack1CodecPopUp selectItemWithTitle: @"MP3 (lame)"];
5083                     [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
5084                 }
5085                 if ([fAudLang2PopUp indexOfSelectedItem] > 0)
5086                 {
5087                     [fAudTrack2CodecPopUp selectItemWithTitle: @"MP3 (lame)"];
5088                     [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
5089                 }
5090                 if ([fAudLang3PopUp indexOfSelectedItem] > 0)
5091                 {
5092                     [fAudTrack3CodecPopUp selectItemWithTitle: @"MP3 (lame)"];
5093                     [self audioTrackPopUpChanged: fAudTrack3CodecPopUp];
5094                 }
5095                 if ([fAudLang4PopUp indexOfSelectedItem] > 0)
5096                 {
5097                     [fAudTrack4CodecPopUp selectItemWithTitle: @"MP3 (lame)"];
5098                     [self audioTrackPopUpChanged: fAudTrack4CodecPopUp];
5099                 }
5100             }
5101             else if ([[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"MPEG-4 Video / Vorbis Audio"])
5102             {
5103                 if ([fAudLang1PopUp indexOfSelectedItem] > 0)
5104                 {
5105                     [fAudTrack1CodecPopUp selectItemWithTitle: @"Vorbis (vorbis)"];
5106                     [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
5107                 }
5108                 if ([fAudLang2PopUp indexOfSelectedItem] > 0)
5109                 {
5110                     [fAudTrack2CodecPopUp selectItemWithTitle: @"Vorbis (vorbis)"];
5111                     [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
5112                 }
5113                 if ([fAudLang3PopUp indexOfSelectedItem] > 0)
5114                 {
5115                     [fAudTrack3CodecPopUp selectItemWithTitle: @"Vorbis (vorbis)"];
5116                     [self audioTrackPopUpChanged: fAudTrack3CodecPopUp];
5117                 }
5118                 if ([fAudLang4PopUp indexOfSelectedItem] > 0)
5119                 {
5120                     [fAudTrack4CodecPopUp selectItemWithTitle: @"Vorbis (vorbis)"];
5121                     [self audioTrackPopUpChanged: fAudTrack4CodecPopUp];
5122                 }
5123             }
5124             /* 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
5125             * UNLESS the CodecPopUp is AC3 in which case the preset values are ignored in favor of rates set in audioTrackMixdownChanged*/
5126             if ([chosenPreset objectForKey:@"AudioSampleRate"])
5127             {
5128                 if ([fAudLang1PopUp indexOfSelectedItem] > 0 && [fAudTrack1CodecPopUp titleOfSelectedItem] != @"AC3 Passthru")
5129                 {
5130                     [fAudTrack1RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioSampleRate"]];
5131                     [fAudTrack1BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioBitRate"]];
5132                 }
5133                 if ([fAudLang2PopUp indexOfSelectedItem] > 0 && [fAudTrack2CodecPopUp titleOfSelectedItem] != @"AC3 Passthru")
5134                 {
5135                     [fAudTrack2RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioSampleRate"]];
5136                     [fAudTrack2BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioBitRate"]];
5137                 }
5138                 if ([fAudLang3PopUp indexOfSelectedItem] > 0 && [fAudTrack3CodecPopUp titleOfSelectedItem] != @"AC3 Passthru")
5139                 {
5140                     [fAudTrack3RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioSampleRate"]];
5141                     [fAudTrack3BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioBitRate"]];
5142                 }
5143                 if ([fAudLang4PopUp indexOfSelectedItem] > 0 && [fAudTrack4CodecPopUp titleOfSelectedItem] != @"AC3 Passthru")
5144                 {
5145                     [fAudTrack4RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioSampleRate"]];
5146                     [fAudTrack4BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioBitRate"]];
5147                 }
5148             }
5149             /* We detect here if we have the old DRC Slider and if so we apply it to the existing four tracks if chosen */
5150             if ([chosenPreset objectForKey:@"AudioDRCSlider"])
5151             {
5152                 if ([fAudLang1PopUp indexOfSelectedItem] > 0)
5153                 {
5154                     [fAudTrack1DrcSlider setFloatValue:[[chosenPreset objectForKey:@"AudioDRCSlider"] floatValue]];
5155                     [self audioDRCSliderChanged: fAudTrack1DrcSlider];
5156                 }
5157                 if ([fAudLang2PopUp indexOfSelectedItem] > 0)
5158                 {
5159                     [fAudTrack2DrcSlider setFloatValue:[[chosenPreset objectForKey:@"AudioDRCSlider"] floatValue]];
5160                     [self audioDRCSliderChanged: fAudTrack2DrcSlider];
5161                 }
5162                 if ([fAudLang3PopUp indexOfSelectedItem] > 0)
5163                 {
5164                     [fAudTrack3DrcSlider setFloatValue:[[chosenPreset objectForKey:@"AudioDRCSlider"] floatValue]];
5165                     [self audioDRCSliderChanged: fAudTrack3DrcSlider];
5166                 }
5167                 if ([fAudLang4PopUp indexOfSelectedItem] > 0)
5168                 {
5169                     [fAudTrack4DrcSlider setFloatValue:[[chosenPreset objectForKey:@"AudioDRCSlider"] floatValue]];
5170                     [self audioDRCSliderChanged: fAudTrack4DrcSlider];
5171                 }
5172             }
5173         }
5174         else // since there was no codecs key in the preset we know we can use new multi-audio track presets
5175         {
5176             if ([chosenPreset objectForKey:@"Audio1Track"] > 0)
5177             {
5178                 if ([fAudLang1PopUp indexOfSelectedItem] == 0)
5179                 {
5180                     [fAudLang1PopUp selectItemAtIndex: 1];
5181                 }
5182                 [self audioTrackPopUpChanged: fAudLang1PopUp];
5183                 [fAudTrack1CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Encoder"]];
5184                 [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
5185                 [fAudTrack1MixPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Mixdown"]];
5186                 /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
5187                  * mixdown*/
5188                 if  ([fAudTrack1MixPopUp selectedItem] == nil)
5189                 {
5190                     [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
5191                 }
5192                 [fAudTrack1RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Samplerate"]];
5193                 /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
5194                 if (![[chosenPreset objectForKey:@"Audio1Encoder"] isEqualToString:@"AC3 Passthru"])
5195                 {
5196                     [fAudTrack1BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Bitrate"]];
5197                 }
5198                 [fAudTrack1DrcSlider setFloatValue:[[chosenPreset objectForKey:@"Audio1TrackDRCSlider"] floatValue]];
5199                 [self audioDRCSliderChanged: fAudTrack1DrcSlider];
5200             }
5201             if ([chosenPreset objectForKey:@"Audio2Track"] > 0)
5202             {
5203                 if ([fAudLang2PopUp indexOfSelectedItem] == 0)
5204                 {
5205                     [fAudLang2PopUp selectItemAtIndex: 1];
5206                 }
5207                 [self audioTrackPopUpChanged: fAudLang2PopUp];
5208                 [fAudTrack2CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio2Encoder"]];
5209                 [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
5210                 [fAudTrack2MixPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio2Mixdown"]];
5211                 /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
5212                  * mixdown*/
5213                 if  ([fAudTrack2MixPopUp selectedItem] == nil)
5214                 {
5215                     [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
5216                 }
5217                 [fAudTrack2RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio2Samplerate"]];
5218                 /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
5219                 if (![[chosenPreset objectForKey:@"Audio2Encoder"] isEqualToString:@"AC3 Passthru"])
5220                 {
5221                     [fAudTrack2BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio2Bitrate"]];
5222                 }
5223                 [fAudTrack2DrcSlider setFloatValue:[[chosenPreset objectForKey:@"Audio2TrackDRCSlider"] floatValue]];
5224                 [self audioDRCSliderChanged: fAudTrack2DrcSlider];
5225             }
5226             if ([chosenPreset objectForKey:@"Audio3Track"] > 0)
5227             {
5228                 if ([fAudLang3PopUp indexOfSelectedItem] == 0)
5229                 {
5230                     [fAudLang3PopUp selectItemAtIndex: 1];
5231                 }
5232                 [self audioTrackPopUpChanged: fAudLang3PopUp];
5233                 [fAudTrack3CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio3Encoder"]];
5234                 [self audioTrackPopUpChanged: fAudTrack3CodecPopUp];
5235                 [fAudTrack3MixPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio3Mixdown"]];
5236                 /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
5237                  * mixdown*/
5238                 if  ([fAudTrack3MixPopUp selectedItem] == nil)
5239                 {
5240                     [self audioTrackPopUpChanged: fAudTrack3CodecPopUp];
5241                 }
5242                 [fAudTrack3RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio3Samplerate"]];
5243                 /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
5244                 if (![[chosenPreset objectForKey:@"Audio3Encoder"] isEqualToString: @"AC3 Passthru"])
5245                 {
5246                     [fAudTrack3BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio3Bitrate"]];
5247                 }
5248                 [fAudTrack3DrcSlider setFloatValue:[[chosenPreset objectForKey:@"Audio3TrackDRCSlider"] floatValue]];
5249                 [self audioDRCSliderChanged: fAudTrack3DrcSlider];
5250             }
5251             if ([chosenPreset objectForKey:@"Audio4Track"] > 0)
5252             {
5253                 if ([fAudLang4PopUp indexOfSelectedItem] == 0)
5254                 {
5255                     [fAudLang4PopUp selectItemAtIndex: 1];
5256                 }
5257                 [self audioTrackPopUpChanged: fAudLang4PopUp];
5258                 [fAudTrack4CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio4Encoder"]];
5259                 [self audioTrackPopUpChanged: fAudTrack4CodecPopUp];
5260                 [fAudTrack4MixPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio4Mixdown"]];
5261                 /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
5262                  * mixdown*/
5263                 if  ([fAudTrack4MixPopUp selectedItem] == nil)
5264                 {
5265                     [self audioTrackPopUpChanged: fAudTrack4CodecPopUp];
5266                 }
5267                 [fAudTrack4RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio4Samplerate"]];
5268                 /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
5269                 if (![[chosenPreset objectForKey:@"Audio4Encoder"] isEqualToString:@"AC3 Passthru"])
5270                 {
5271                     [fAudTrack4BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio4Bitrate"]];
5272                 }
5273                 [fAudTrack4DrcSlider setFloatValue:[[chosenPreset objectForKey:@"Audio4TrackDRCSlider"] floatValue]];
5274                 [self audioDRCSliderChanged: fAudTrack4DrcSlider];
5275             }
5276
5277
5278         }
5279
5280         /* 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
5281          * duplicate any code for legacy presets.*/
5282         /* First we handle the legacy Codecs crazy AVC/H.264 Video / AAC + AC3 Audio atv hybrid */
5283         if ([chosenPreset objectForKey:@"FileCodecs"] && [[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"AVC/H.264 Video / AAC + AC3 Audio"])
5284         {
5285             [fAudLang3PopUp selectItemAtIndex: 0];
5286             [self audioTrackPopUpChanged: fAudLang3PopUp];
5287             [fAudLang4PopUp selectItemAtIndex: 0];
5288             [self audioTrackPopUpChanged: fAudLang4PopUp];
5289         }
5290         else
5291         {
5292             if (![chosenPreset objectForKey:@"Audio2Track"] || [chosenPreset objectForKey:@"Audio2Track"] == 0)
5293             {
5294                 [fAudLang2PopUp selectItemAtIndex: 0];
5295                 [self audioTrackPopUpChanged: fAudLang2PopUp];
5296             }
5297             if (![chosenPreset objectForKey:@"Audio3Track"] || [chosenPreset objectForKey:@"Audio3Track"] > 0)
5298             {
5299                 [fAudLang3PopUp selectItemAtIndex: 0];
5300                 [self audioTrackPopUpChanged: fAudLang3PopUp];
5301             }
5302             if (![chosenPreset objectForKey:@"Audio4Track"] || [chosenPreset objectForKey:@"Audio4Track"] > 0)
5303             {
5304                 [fAudLang4PopUp selectItemAtIndex: 0];
5305                 [self audioTrackPopUpChanged: fAudLang4PopUp];
5306             }
5307         }
5308
5309         /*Subtitles*/
5310         [fSubPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Subtitles"]];
5311         /* Forced Subtitles */
5312         [fSubForcedCheck setState:[[chosenPreset objectForKey:@"SubtitlesForced"] intValue]];
5313
5314         /* Picture Settings */
5315         /* Note: objectForKey:@"UsesPictureSettings" now refers to picture size, this encompasses:
5316          * height, width, keep ar, anamorphic and crop settings.
5317          * picture filters are now handled separately.
5318          * We will be able to actually change the key names for legacy preset keys when preset file
5319          * update code is done. But for now, lets hang onto the old legacy key name for backwards compatibility.
5320          */
5321         /* Check to see if the objectForKey:@"UsesPictureSettings is greater than 0, as 0 means use picture sizing "None" 
5322          * and the preset completely ignores any picture sizing values in the preset.
5323          */
5324         if ([[chosenPreset objectForKey:@"UsesPictureSettings"]  intValue] > 0)
5325         {
5326             hb_job_t * job = fTitle->job;
5327             /* Check to see if the objectForKey:@"UsesPictureSettings is 2 which is "Use Max for the source */
5328             if ([[chosenPreset objectForKey:@"UsesPictureSettings"]  intValue] == 2 || [[chosenPreset objectForKey:@"UsesMaxPictureSettings"]  intValue] == 1)
5329             {
5330                 /* Use Max Picture settings for whatever the dvd is.*/
5331                 [self revertPictureSizeToMax:nil];
5332                 job->keep_ratio = [[chosenPreset objectForKey:@"PictureKeepRatio"]  intValue];
5333                 if (job->keep_ratio == 1)
5334                 {
5335                     hb_fix_aspect( job, HB_KEEP_WIDTH );
5336                     if( job->height > fTitle->height )
5337                     {
5338                         job->height = fTitle->height;
5339                         hb_fix_aspect( job, HB_KEEP_HEIGHT );
5340                     }
5341                 }
5342                 job->pixel_ratio = [[chosenPreset objectForKey:@"PicturePAR"]  intValue];
5343             }
5344             else // /* If not 0 or 2 we assume objectForKey:@"UsesPictureSettings is 1 which is "Use picture sizing from when the preset was set" */
5345             {
5346                 /* we check to make sure the presets width/height does not exceed the sources width/height */
5347                 if (fTitle->width < [[chosenPreset objectForKey:@"PictureWidth"]  intValue] || fTitle->height < [[chosenPreset objectForKey:@"PictureHeight"]  intValue])
5348                 {
5349                     /* if so, then we use the sources height and width to avoid scaling up */
5350                     job->width = fTitle->width;
5351                     job->height = fTitle->height;
5352                 }
5353                 else // source width/height is >= the preset height/width
5354                 {
5355                     /* we can go ahead and use the presets values for height and width */
5356                     job->width = [[chosenPreset objectForKey:@"PictureWidth"]  intValue];
5357                     job->height = [[chosenPreset objectForKey:@"PictureHeight"]  intValue];
5358                 }
5359                 job->keep_ratio = [[chosenPreset objectForKey:@"PictureKeepRatio"]  intValue];
5360                 if (job->keep_ratio == 1)
5361                 {
5362                     hb_fix_aspect( job, HB_KEEP_WIDTH );
5363                     if( job->height > fTitle->height )
5364                     {
5365                         job->height = fTitle->height;
5366                         hb_fix_aspect( job, HB_KEEP_HEIGHT );
5367                     }
5368                 }
5369                 job->pixel_ratio = [[chosenPreset objectForKey:@"PicturePAR"]  intValue];
5370                 
5371                 
5372                 /* If Cropping is set to custom, then recall all four crop values from
5373                  when the preset was created and apply them */
5374                 if ([[chosenPreset objectForKey:@"PictureAutoCrop"]  intValue] == 0)
5375                 {
5376                     [fPictureController setAutoCrop:NO];
5377                     
5378                     /* Here we use the custom crop values saved at the time the preset was saved */
5379                     job->crop[0] = [[chosenPreset objectForKey:@"PictureTopCrop"]  intValue];
5380                     job->crop[1] = [[chosenPreset objectForKey:@"PictureBottomCrop"]  intValue];
5381                     job->crop[2] = [[chosenPreset objectForKey:@"PictureLeftCrop"]  intValue];
5382                     job->crop[3] = [[chosenPreset objectForKey:@"PictureRightCrop"]  intValue];
5383                     
5384                 }
5385                 else /* if auto crop has been saved in preset, set to auto and use post scan auto crop */
5386                 {
5387                     [fPictureController setAutoCrop:YES];
5388                     /* Here we use the auto crop values determined right after scan */
5389                     job->crop[0] = AutoCropTop;
5390                     job->crop[1] = AutoCropBottom;
5391                     job->crop[2] = AutoCropLeft;
5392                     job->crop[3] = AutoCropRight;
5393                     
5394                 }
5395                 /* If the preset has no objectForKey:@"UsesPictureFilters", then we know it is a legacy preset
5396                  * and handle the filters here as before.
5397                  * NOTE: This should be removed when the update presets code is done as we can be assured that legacy
5398                  * presets are updated to work properly with new keys.
5399                  */
5400                 if (![chosenPreset objectForKey:@"UsesPictureFilters"])
5401                 {
5402                     /* Filters */
5403                     /* Deinterlace */
5404                     if ([chosenPreset objectForKey:@"PictureDeinterlace"])
5405                     {
5406                         /* We check to see if the preset used the past fourth "Slowest" deinterlaceing and set that to "Slower
5407                          * since we no longer have a fourth "Slowest" deinterlacing due to the mcdeint bug */
5408                         if ([[chosenPreset objectForKey:@"PictureDeinterlace"] intValue] == 4)
5409                         {
5410                             [fPictureController setDeinterlace:3];
5411                         }
5412                         else
5413                         {
5414                             
5415                             [fPictureController setDeinterlace:[[chosenPreset objectForKey:@"PictureDeinterlace"] intValue]];
5416                         }
5417                     }
5418                     else
5419                     {
5420                         [fPictureController setDeinterlace:0];
5421                     }
5422                     /* VFR */
5423                     if ([[chosenPreset objectForKey:@"VFR"] intValue] == 1)
5424                     {
5425                         [fPictureController setVFR:[[chosenPreset objectForKey:@"VFR"] intValue]];
5426                     }
5427                     else
5428                     {
5429                         [fPictureController setVFR:0];
5430                     }
5431                     /* Detelecine */
5432                     if ([[chosenPreset objectForKey:@"PictureDetelecine"] intValue] == 1)
5433                     {
5434                         [fPictureController setDetelecine:[[chosenPreset objectForKey:@"PictureDetelecine"] intValue]];
5435                     }
5436                     else
5437                     {
5438                         [fPictureController setDetelecine:0];
5439                     }
5440                     /* Denoise */
5441                     if ([chosenPreset objectForKey:@"PictureDenoise"])
5442                     {
5443                         [fPictureController setDenoise:[[chosenPreset objectForKey:@"PictureDenoise"] intValue]];
5444                     }
5445                     else
5446                     {
5447                         [fPictureController setDenoise:0];
5448                     }   
5449                     /* Deblock */
5450                     if ([[chosenPreset objectForKey:@"PictureDeblock"] intValue] == 1)
5451                     {
5452                         [fPictureController setDeblock:[[chosenPreset objectForKey:@"PictureDeblock"] intValue]];
5453                     }
5454                     else
5455                     {
5456                         [fPictureController setDeblock:0];
5457                     }
5458
5459                    [self calculatePictureSizing:nil];
5460                 }
5461
5462             }
5463
5464
5465         }
5466         /* If the preset has an objectForKey:@"UsesPictureFilters", then we know it is a newer style filters preset
5467          * and handle the filters here depending on whether or not the preset specifies applying the filter.
5468          */
5469         if ([chosenPreset objectForKey:@"UsesPictureFilters"] && [[chosenPreset objectForKey:@"UsesPictureFilters"]  intValue] > 0)
5470         {
5471             /* Filters */
5472             /* Deinterlace */
5473             if ([chosenPreset objectForKey:@"PictureDeinterlace"])
5474             {
5475                 /* We check to see if the preset used the past fourth "Slowest" deinterlaceing and set that to "Slower
5476                  * since we no longer have a fourth "Slowest" deinterlacing due to the mcdeint bug */
5477                 if ([[chosenPreset objectForKey:@"PictureDeinterlace"] intValue] == 4)
5478                 {
5479                     [fPictureController setDeinterlace:3];
5480                 }
5481                 else
5482                 {
5483                     [fPictureController setDeinterlace:[[chosenPreset objectForKey:@"PictureDeinterlace"] intValue]];
5484                 }
5485             }
5486             else
5487             {
5488                 [fPictureController setDeinterlace:0];
5489             }
5490             /* VFR */
5491             if ([[chosenPreset objectForKey:@"VFR"] intValue] == 1)
5492             {
5493                 [fPictureController setVFR:[[chosenPreset objectForKey:@"VFR"] intValue]];
5494             }
5495             else
5496             {
5497                 [fPictureController setVFR:0];
5498             }
5499             /* Detelecine */
5500             if ([[chosenPreset objectForKey:@"PictureDetelecine"] intValue] == 1)
5501             {
5502                 [fPictureController setDetelecine:[[chosenPreset objectForKey:@"PictureDetelecine"] intValue]];
5503             }
5504             else
5505             {
5506                 [fPictureController setDetelecine:0];
5507             }
5508             /* Denoise */
5509             if ([chosenPreset objectForKey:@"PictureDenoise"])
5510             {
5511                 [fPictureController setDenoise:[[chosenPreset objectForKey:@"PictureDenoise"] intValue]];
5512             }
5513             else
5514             {
5515                 [fPictureController setDenoise:0];
5516             }   
5517             /* Deblock */
5518             if ([[chosenPreset objectForKey:@"PictureDeblock"] intValue] == 1)
5519             {
5520                 [fPictureController setDeblock:[[chosenPreset objectForKey:@"PictureDeblock"] intValue]];
5521             }
5522             else
5523             {
5524                 [fPictureController setDeblock:0];
5525             }
5526             /* Decomb */
5527             /* Even though we currently allow for a custom setting for decomb, ultimately it will only have Off and
5528              * Default so we just pay attention to anything greater than 0 as 1 (Default). 0 is Off. */
5529             if ([[chosenPreset objectForKey:@"PictureDecomb"] intValue] > 0)
5530             {
5531                 [fPictureController setDecomb:1];
5532             }
5533             else
5534             {
5535                 [fPictureController setDecomb:0];
5536             }
5537         }
5538         [self calculatePictureSizing:nil];
5539     }
5540 }
5541
5542
5543 #pragma mark -
5544 #pragma mark Manage Presets
5545
5546 - (void) loadPresets {
5547         /* We declare the default NSFileManager into fileManager */
5548         NSFileManager * fileManager = [NSFileManager defaultManager];
5549         /*We define the location of the user presets file */
5550     UserPresetsFile = @"~/Library/Application Support/HandBrake/UserPresets.plist";
5551         UserPresetsFile = [[UserPresetsFile stringByExpandingTildeInPath]retain];
5552     /* We check for the presets.plist */
5553         if ([fileManager fileExistsAtPath:UserPresetsFile] == 0)
5554         {
5555                 [fileManager createFileAtPath:UserPresetsFile contents:nil attributes:nil];
5556         }
5557
5558         UserPresets = [[NSMutableArray alloc] initWithContentsOfFile:UserPresetsFile];
5559         if (nil == UserPresets)
5560         {
5561                 UserPresets = [[NSMutableArray alloc] init];
5562                 [self addFactoryPresets:nil];
5563         }
5564         [fPresetsOutlineView reloadData];
5565 }
5566
5567
5568 - (IBAction) showAddPresetPanel: (id) sender
5569 {
5570     /* Deselect the currently selected Preset if there is one*/
5571     [fPresetsOutlineView deselectRow:[fPresetsOutlineView selectedRow]];
5572
5573     /* Populate the preset picture settings popup here */
5574     [fPresetNewPicSettingsPopUp removeAllItems];
5575     [fPresetNewPicSettingsPopUp addItemWithTitle:@"None"];
5576     [fPresetNewPicSettingsPopUp addItemWithTitle:@"Current"];
5577     [fPresetNewPicSettingsPopUp addItemWithTitle:@"Source Maximum (post source scan)"];
5578     [fPresetNewPicSettingsPopUp selectItemAtIndex: 0];  
5579     /* Uncheck the preset use filters checkbox */
5580     [fPresetNewPicFiltersCheck setState:NSOffState];
5581     /* Erase info from the input fields*/
5582         [fPresetNewName setStringValue: @""];
5583         [fPresetNewDesc setStringValue: @""];
5584         /* Show the panel */
5585         [NSApp beginSheet:fAddPresetPanel modalForWindow:fWindow modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
5586 }
5587
5588 - (IBAction) closeAddPresetPanel: (id) sender
5589 {
5590     [NSApp endSheet: fAddPresetPanel];
5591     [fAddPresetPanel orderOut: self];
5592 }
5593
5594 - (IBAction)addUserPreset:(id)sender
5595 {
5596     if (![[fPresetNewName stringValue] length])
5597             NSRunAlertPanel(@"Warning!", @"You need to insert a name for the preset.", @"OK", nil , nil);
5598     else
5599     {
5600         /* Here we create a custom user preset */
5601         [UserPresets addObject:[self createPreset]];
5602         [self addPreset];
5603
5604         [self closeAddPresetPanel:nil];
5605     }
5606 }
5607 - (void)addPreset
5608 {
5609
5610         
5611         /* We Reload the New Table data for presets */
5612     [fPresetsOutlineView reloadData];
5613    /* We save all of the preset data here */
5614     [self savePreset];
5615 }
5616
5617 - (void)sortPresets
5618 {
5619
5620         
5621         /* We Sort the Presets By Factory or Custom */
5622         NSSortDescriptor * presetTypeDescriptor=[[[NSSortDescriptor alloc] initWithKey:@"Type" 
5623                                                     ascending:YES] autorelease];
5624         /* We Sort the Presets Alphabetically by name  We do not use this now as we have drag and drop*/
5625         /*
5626     NSSortDescriptor * presetNameDescriptor=[[[NSSortDescriptor alloc] initWithKey:@"PresetName" 
5627                                                     ascending:YES selector:@selector(caseInsensitiveCompare:)] autorelease];
5628         //NSArray *sortDescriptors=[NSArray arrayWithObjects:presetTypeDescriptor,presetNameDescriptor,nil];
5629     
5630     */
5631     /* Since we can drag and drop our custom presets, lets just sort by type and not name */
5632     NSArray *sortDescriptors=[NSArray arrayWithObjects:presetTypeDescriptor,nil];
5633         NSArray *sortedArray=[UserPresets sortedArrayUsingDescriptors:sortDescriptors];
5634         [UserPresets setArray:sortedArray];
5635         
5636
5637 }
5638
5639 - (IBAction)insertPreset:(id)sender
5640 {
5641     int index = [fPresetsOutlineView selectedRow];
5642     [UserPresets insertObject:[self createPreset] atIndex:index];
5643     [fPresetsOutlineView reloadData];
5644     [self savePreset];
5645 }
5646
5647 - (NSDictionary *)createPreset
5648 {
5649     NSMutableDictionary *preset = [[NSMutableDictionary alloc] init];
5650         /* Get the New Preset Name from the field in the AddPresetPanel */
5651     [preset setObject:[fPresetNewName stringValue] forKey:@"PresetName"];
5652         /*Set whether or not this is a user preset or factory 0 is factory, 1 is user*/
5653         [preset setObject:[NSNumber numberWithInt:1] forKey:@"Type"];
5654         /*Set whether or not this is default, at creation set to 0*/
5655         [preset setObject:[NSNumber numberWithInt:0] forKey:@"Default"];
5656         /*Get the whether or not to apply pic Size and Cropping (includes Anamorphic)*/
5657         [preset setObject:[NSNumber numberWithInt:[fPresetNewPicSettingsPopUp indexOfSelectedItem]] forKey:@"UsesPictureSettings"];
5658     /* Get whether or not to use the current Picture Filter settings for the preset */
5659     [preset setObject:[NSNumber numberWithInt:[fPresetNewPicFiltersCheck state]] forKey:@"UsesPictureFilters"];
5660  
5661     /* Get New Preset Description from the field in the AddPresetPanel*/
5662         [preset setObject:[fPresetNewDesc stringValue] forKey:@"PresetDescription"];
5663         /* File Format */
5664     [preset setObject:[fDstFormatPopUp titleOfSelectedItem] forKey:@"FileFormat"];
5665         /* Chapter Markers fCreateChapterMarkers*/
5666         [preset setObject:[NSNumber numberWithInt:[fCreateChapterMarkers state]] forKey:@"ChapterMarkers"];
5667         /* Allow Mpeg4 64 bit formatting +4GB file sizes */
5668         [preset setObject:[NSNumber numberWithInt:[fDstMp4LargeFileCheck state]] forKey:@"Mp4LargeFile"];
5669     /* Mux mp4 with http optimization */
5670     [preset setObject:[NSNumber numberWithInt:[fDstMp4HttpOptFileCheck state]] forKey:@"Mp4HttpOptimize"];
5671     /* Add iPod uuid atom */
5672     [preset setObject:[NSNumber numberWithInt:[fDstMp4iPodFileCheck state]] forKey:@"Mp4iPodCompatible"];
5673
5674     /* Codecs */
5675         /* Video encoder */
5676         [preset setObject:[fVidEncoderPopUp titleOfSelectedItem] forKey:@"VideoEncoder"];
5677         /* x264 Option String */
5678         [preset setObject:[fAdvancedOptions optionsString] forKey:@"x264Option"];
5679
5680         [preset setObject:[NSNumber numberWithInt:[fVidQualityMatrix selectedRow]] forKey:@"VideoQualityType"];
5681         [preset setObject:[fVidTargetSizeField stringValue] forKey:@"VideoTargetSize"];
5682         [preset setObject:[fVidBitrateField stringValue] forKey:@"VideoAvgBitrate"];
5683         [preset setObject:[NSNumber numberWithFloat:[fVidQualitySlider floatValue]] forKey:@"VideoQualitySlider"];
5684
5685         /* Video framerate */
5686     if ([fVidRatePopUp indexOfSelectedItem] == 0) // Same as source is selected
5687         {
5688         [preset setObject:@"Same as source" forKey:@"VideoFramerate"];
5689     }
5690     else // we can record the actual titleOfSelectedItem
5691     {
5692     [preset setObject:[fVidRatePopUp titleOfSelectedItem] forKey:@"VideoFramerate"];
5693     }
5694         /* GrayScale */
5695         [preset setObject:[NSNumber numberWithInt:[fVidGrayscaleCheck state]] forKey:@"VideoGrayScale"];
5696         /* 2 Pass Encoding */
5697         [preset setObject:[NSNumber numberWithInt:[fVidTwoPassCheck state]] forKey:@"VideoTwoPass"];
5698         /* Turbo 2 pass Encoding fVidTurboPassCheck*/
5699         [preset setObject:[NSNumber numberWithInt:[fVidTurboPassCheck state]] forKey:@"VideoTurboTwoPass"];
5700         /*Picture Settings*/
5701         hb_job_t * job = fTitle->job;
5702         /* Picture Sizing */
5703         /* Use Max Picture settings for whatever the dvd is.*/
5704         [preset setObject:[NSNumber numberWithInt:0] forKey:@"UsesMaxPictureSettings"];
5705         [preset setObject:[NSNumber numberWithInt:fTitle->job->width] forKey:@"PictureWidth"];
5706         [preset setObject:[NSNumber numberWithInt:fTitle->job->height] forKey:@"PictureHeight"];
5707         [preset setObject:[NSNumber numberWithInt:fTitle->job->keep_ratio] forKey:@"PictureKeepRatio"];
5708         [preset setObject:[NSNumber numberWithInt:fTitle->job->pixel_ratio] forKey:@"PicturePAR"];
5709     
5710     /* Set crop settings here */
5711         [preset setObject:[NSNumber numberWithInt:[fPictureController autoCrop]] forKey:@"PictureAutoCrop"];
5712     [preset setObject:[NSNumber numberWithInt:job->crop[0]] forKey:@"PictureTopCrop"];
5713     [preset setObject:[NSNumber numberWithInt:job->crop[1]] forKey:@"PictureBottomCrop"];
5714         [preset setObject:[NSNumber numberWithInt:job->crop[2]] forKey:@"PictureLeftCrop"];
5715         [preset setObject:[NSNumber numberWithInt:job->crop[3]] forKey:@"PictureRightCrop"];
5716     
5717     /* Picture Filters */
5718     [preset setObject:[NSNumber numberWithInt:[fPictureController deinterlace]] forKey:@"PictureDeinterlace"];
5719         [preset setObject:[NSNumber numberWithInt:[fPictureController detelecine]] forKey:@"PictureDetelecine"];
5720     [preset setObject:[NSNumber numberWithInt:[fPictureController vfr]] forKey:@"VFR"];
5721         [preset setObject:[NSNumber numberWithInt:[fPictureController denoise]] forKey:@"PictureDenoise"];
5722     [preset setObject:[NSNumber numberWithInt:[fPictureController deblock]] forKey:@"PictureDeblock"]; 
5723     [preset setObject:[NSNumber numberWithInt:[fPictureController decomb]] forKey:@"PictureDecomb"];
5724     
5725     
5726     /*Audio*/
5727     if ([fAudLang1PopUp indexOfSelectedItem] > 0)
5728     {
5729         [preset setObject:[NSNumber numberWithInt:[fAudLang1PopUp indexOfSelectedItem]] forKey:@"Audio1Track"];
5730         [preset setObject:[fAudLang1PopUp titleOfSelectedItem] forKey:@"Audio1TrackDescription"];
5731         [preset setObject:[fAudTrack1CodecPopUp titleOfSelectedItem] forKey:@"Audio1Encoder"];
5732         [preset setObject:[fAudTrack1MixPopUp titleOfSelectedItem] forKey:@"Audio1Mixdown"];
5733         [preset setObject:[fAudTrack1RatePopUp titleOfSelectedItem] forKey:@"Audio1Samplerate"];
5734         [preset setObject:[fAudTrack1BitratePopUp titleOfSelectedItem] forKey:@"Audio1Bitrate"];
5735         [preset setObject:[NSNumber numberWithFloat:[fAudTrack1DrcSlider floatValue]] forKey:@"Audio1TrackDRCSlider"];
5736     }
5737     if ([fAudLang2PopUp indexOfSelectedItem] > 0)
5738     {
5739         [preset setObject:[NSNumber numberWithInt:[fAudLang2PopUp indexOfSelectedItem]] forKey:@"Audio2Track"];
5740         [preset setObject:[fAudLang2PopUp titleOfSelectedItem] forKey:@"Audio2TrackDescription"];
5741         [preset setObject:[fAudTrack2CodecPopUp titleOfSelectedItem] forKey:@"Audio2Encoder"];
5742         [preset setObject:[fAudTrack2MixPopUp titleOfSelectedItem] forKey:@"Audio2Mixdown"];
5743         [preset setObject:[fAudTrack2RatePopUp titleOfSelectedItem] forKey:@"Audio2Samplerate"];
5744         [preset setObject:[fAudTrack2BitratePopUp titleOfSelectedItem] forKey:@"Audio2Bitrate"];
5745         [preset setObject:[NSNumber numberWithFloat:[fAudTrack2DrcSlider floatValue]] forKey:@"Audio2TrackDRCSlider"];
5746     }
5747     if ([fAudLang3PopUp indexOfSelectedItem] > 0)
5748     {
5749         [preset setObject:[NSNumber numberWithInt:[fAudLang3PopUp indexOfSelectedItem]] forKey:@"Audio3Track"];
5750         [preset setObject:[fAudLang3PopUp titleOfSelectedItem] forKey:@"Audio3TrackDescription"];
5751         [preset setObject:[fAudTrack3CodecPopUp titleOfSelectedItem] forKey:@"Audio3Encoder"];
5752         [preset setObject:[fAudTrack3MixPopUp titleOfSelectedItem] forKey:@"Audio3Mixdown"];
5753         [preset setObject:[fAudTrack3RatePopUp titleOfSelectedItem] forKey:@"Audio3Samplerate"];
5754         [preset setObject:[fAudTrack3BitratePopUp titleOfSelectedItem] forKey:@"Audio3Bitrate"];
5755         [preset setObject:[NSNumber numberWithFloat:[fAudTrack3DrcSlider floatValue]] forKey:@"Audio3TrackDRCSlider"];
5756     }
5757     if ([fAudLang4PopUp indexOfSelectedItem] > 0)
5758     {
5759         [preset setObject:[NSNumber numberWithInt:[fAudLang4PopUp indexOfSelectedItem]] forKey:@"Audio4Track"];
5760         [preset setObject:[fAudLang4PopUp titleOfSelectedItem] forKey:@"Audio4TrackDescription"];
5761         [preset setObject:[fAudTrack4CodecPopUp titleOfSelectedItem] forKey:@"Audio4Encoder"];
5762         [preset setObject:[fAudTrack4MixPopUp titleOfSelectedItem] forKey:@"Audio4Mixdown"];
5763         [preset setObject:[fAudTrack4RatePopUp titleOfSelectedItem] forKey:@"Audio4Samplerate"];
5764         [preset setObject:[fAudTrack4BitratePopUp titleOfSelectedItem] forKey:@"Audio4Bitrate"];
5765         [preset setObject:[NSNumber numberWithFloat:[fAudTrack4DrcSlider floatValue]] forKey:@"Audio4TrackDRCSlider"];
5766     }
5767     
5768         /* Subtitles*/
5769         [preset setObject:[fSubPopUp titleOfSelectedItem] forKey:@"Subtitles"];
5770     /* Forced Subtitles */
5771         [preset setObject:[NSNumber numberWithInt:[fSubForcedCheck state]] forKey:@"SubtitlesForced"];
5772     
5773     [preset autorelease];
5774     return preset;
5775
5776 }
5777
5778 - (void)savePreset
5779 {
5780     [UserPresets writeToFile:UserPresetsFile atomically:YES];
5781         /* We get the default preset in case it changed */
5782         [self getDefaultPresets:nil];
5783
5784 }
5785
5786 - (IBAction)deletePreset:(id)sender
5787 {
5788     int status;
5789     NSEnumerator *enumerator;
5790     NSNumber *index;
5791     NSMutableArray *tempArray;
5792     id tempObject;
5793     
5794     if ( [fPresetsOutlineView numberOfSelectedRows] == 0 )
5795         return;
5796     /* Alert user before deleting preset */
5797         /* Comment out for now, tie to user pref eventually */
5798
5799     //NSBeep();
5800     status = NSRunAlertPanel(@"Warning!", @"Are you sure that you want to delete the selected preset?", @"OK", @"Cancel", nil);
5801     
5802     if ( status == NSAlertDefaultReturn ) {
5803         enumerator = [fPresetsOutlineView selectedRowEnumerator];
5804         tempArray = [NSMutableArray array];
5805         
5806         while ( (index = [enumerator nextObject]) ) {
5807             tempObject = [UserPresets objectAtIndex:[index intValue]];
5808             [tempArray addObject:tempObject];
5809         }
5810         
5811         [UserPresets removeObjectsInArray:tempArray];
5812         [fPresetsOutlineView reloadData];
5813         [self savePreset];   
5814     }
5815 }
5816
5817 #pragma mark -
5818 #pragma mark Manage Default Preset
5819
5820 - (IBAction)getDefaultPresets:(id)sender
5821 {
5822         int i = 0;
5823     presetCurrentBuiltInCount = 0;
5824     NSEnumerator *enumerator = [UserPresets objectEnumerator];
5825         id tempObject;
5826         while (tempObject = [enumerator nextObject])
5827         {
5828                 NSDictionary *thisPresetDict = tempObject;
5829                 if ([[thisPresetDict objectForKey:@"Default"] intValue] == 1) // 1 is HB default
5830                 {
5831                         presetHbDefault = i;    
5832                 }
5833                 if ([[thisPresetDict objectForKey:@"Default"] intValue] == 2) // 2 is User specified default
5834                 {
5835                         presetUserDefault = i;  
5836                 }
5837         if ([[thisPresetDict objectForKey:@"Type"] intValue] == 0) // Type 0 is a built in preset               
5838         {
5839                         presetCurrentBuiltInCount++; // <--increment the current number of built in presets     
5840                 }
5841                 i++;
5842         }
5843 }
5844
5845 - (IBAction)setDefaultPreset:(id)sender
5846 {
5847     int i = 0;
5848     NSEnumerator *enumerator = [UserPresets objectEnumerator];
5849         id tempObject;
5850         /* First make sure the old user specified default preset is removed */
5851         while (tempObject = [enumerator nextObject])
5852         {
5853                 /* make sure we are not removing the default HB preset */
5854                 if ([[[UserPresets objectAtIndex:i] objectForKey:@"Default"] intValue] != 1) // 1 is HB default
5855                 {
5856                         [[UserPresets objectAtIndex:i] setObject:[NSNumber numberWithInt:0] forKey:@"Default"];
5857                 }
5858                 i++;
5859         }
5860         /* Second, go ahead and set the appropriate user specfied preset */
5861         /* we get the chosen preset from the UserPresets array */
5862         if ([[[UserPresets objectAtIndex:[fPresetsOutlineView selectedRow]] objectForKey:@"Default"] intValue] != 1) // 1 is HB default
5863         {
5864                 [[UserPresets objectAtIndex:[fPresetsOutlineView selectedRow]] setObject:[NSNumber numberWithInt:2] forKey:@"Default"];
5865         }
5866         /*FIX ME: I think we now need to use the items not rows in NSOutlineView */
5867     presetUserDefault = [fPresetsOutlineView selectedRow];
5868         
5869         /* We save all of the preset data here */
5870     [self savePreset];
5871         /* We Reload the New Table data for presets */
5872     [fPresetsOutlineView reloadData];
5873 }
5874
5875 - (IBAction)selectDefaultPreset:(id)sender
5876 {
5877         /* if there is a user specified default, we use it */
5878         if (presetUserDefault)
5879         {
5880         [fPresetsOutlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:presetUserDefault] byExtendingSelection:NO];
5881         [self selectPreset:nil];
5882         }
5883         else if (presetHbDefault) //else we use the built in default presetHbDefault
5884         {
5885         [fPresetsOutlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:presetHbDefault] byExtendingSelection:NO];
5886         [self selectPreset:nil];
5887         }
5888 }
5889
5890
5891 #pragma mark -
5892 #pragma mark Manage Built In Presets
5893
5894
5895 - (IBAction)deleteFactoryPresets:(id)sender
5896 {
5897     //int status;
5898     NSEnumerator *enumerator = [UserPresets objectEnumerator];
5899         id tempObject;
5900     
5901         //NSNumber *index;
5902     NSMutableArray *tempArray;
5903
5904
5905         tempArray = [NSMutableArray array];
5906         /* we look here to see if the preset is we move on to the next one */
5907         while ( tempObject = [enumerator nextObject] )  
5908                 {
5909                         /* if the preset is "Factory" then we put it in the array of
5910                         presets to delete */
5911                         if ([[tempObject objectForKey:@"Type"] intValue] == 0)
5912                         {
5913                                 [tempArray addObject:tempObject];
5914                         }
5915         }
5916         
5917         [UserPresets removeObjectsInArray:tempArray];
5918         [fPresetsOutlineView reloadData];
5919         [self savePreset];   
5920
5921 }
5922
5923    /* We use this method to recreate new, updated factory
5924    presets */
5925 - (IBAction)addFactoryPresets:(id)sender
5926 {
5927    
5928    /* First, we delete any existing built in presets */
5929     [self deleteFactoryPresets: sender];
5930     /* Then we generate new built in presets programmatically with fPresetsBuiltin
5931     * which is all setup in HBPresets.h and  HBPresets.m*/
5932     [fPresetsBuiltin generateBuiltinPresets:UserPresets];
5933     [self sortPresets];
5934     [self addPreset];
5935     
5936 }
5937
5938
5939
5940
5941
5942 @end
5943
5944 /*******************************
5945  * Subclass of the HBPresetsOutlineView *
5946  *******************************/
5947
5948 @implementation HBPresetsOutlineView
5949 - (NSImage *)dragImageForRowsWithIndexes:(NSIndexSet *)dragRows tableColumns:(NSArray *)tableColumns event:(NSEvent*)dragEvent offset:(NSPointPointer)dragImageOffset
5950 {
5951     fIsDragging = YES;
5952
5953     // By default, NSTableView only drags an image of the first column. Change this to
5954     // drag an image of the queue's icon and PresetName columns.
5955     NSArray * cols = [NSArray arrayWithObjects: [self tableColumnWithIdentifier:@"icon"], [self tableColumnWithIdentifier:@"PresetName"], nil];
5956     return [super dragImageForRowsWithIndexes:dragRows tableColumns:cols event:dragEvent offset:dragImageOffset];
5957 }
5958
5959
5960
5961 - (void) mouseDown:(NSEvent *)theEvent
5962 {
5963     [super mouseDown:theEvent];
5964         fIsDragging = NO;
5965 }
5966
5967
5968
5969 - (BOOL) isDragging;
5970 {
5971     return fIsDragging;
5972 }
5973 @end
5974
5975
5976