MacGui: adds x264 option widgets for b-rdo, weight, and b-pyramid. And a little layou...
[HandBrake.git] / macosx / Controller.mm
blob697842053cb01fd502292d74627756669bf87cbb
1 /* $Id: Controller.mm,v 1.79 2005/11/04 19:41:32 titer Exp $
3    This file is part of the HandBrake source code.
4    Homepage: <http://handbrake.m0k.org/>.
5    It may be used under the terms of the GNU General Public License. */
7 #include "Controller.h"
8 #include "a52dec/a52.h"
10 #define _(a) NSLocalizedString(a,NULL)
16 static int FormatSettings[3][4] =
17   { { HB_MUX_MP4 | HB_VCODEC_FFMPEG | HB_ACODEC_FAAC,
18       HB_MUX_MP4 | HB_VCODEC_X264   | HB_ACODEC_FAAC,
19       0,
20       0 },
21     { HB_MUX_AVI | HB_VCODEC_FFMPEG | HB_ACODEC_LAME,
22       HB_MUX_AVI | HB_VCODEC_FFMPEG | HB_ACODEC_AC3,
23       HB_MUX_AVI | HB_VCODEC_X264   | HB_ACODEC_LAME,
24       HB_MUX_AVI | HB_VCODEC_X264   | HB_ACODEC_AC3 },
25     { HB_MUX_OGM | HB_VCODEC_FFMPEG | HB_ACODEC_VORBIS,
26       HB_MUX_OGM | HB_VCODEC_FFMPEG | HB_ACODEC_LAME,
27       0,
28       0 } };
30 /*******************************
31  * HBController implementation *
32  *******************************/
33 @implementation HBController
35 - init
37     self    = [super init];
38     fHandle = NULL;
39     return self;
42 - (void) applicationDidFinishLaunching: (NSNotification *) notification
46     int    build;
47     char * version;
50     /* Init libhb */
51     fHandle = hb_init( HB_DEBUG_NONE, [[NSUserDefaults
52         standardUserDefaults] boolForKey:@"CheckForUpdates"] );
53         /* Set the Growl Delegate */
54         HBController *hbGrowlDelegate = [[HBController alloc] init];
55         [GrowlApplicationBridge setGrowlDelegate: hbGrowlDelegate];    
56     /* Init others controllers */
57     [fScanController    SetHandle: fHandle];
58     [fPictureController SetHandle: fHandle];
59     [fQueueController   SetHandle: fHandle];
60         
61     fChapterTitlesDelegate = [[ChapterTitles alloc] init];
62     [fChapterTable setDataSource:fChapterTitlesDelegate];
64      /* Call UpdateUI every 2/10 sec */
65     [[NSRunLoop currentRunLoop] addTimer: [NSTimer
66         scheduledTimerWithTimeInterval: 0.2 target: self
67         selector: @selector( UpdateUI: ) userInfo: NULL repeats: FALSE]
68         forMode: NSModalPanelRunLoopMode];
70     if( ( build = hb_check_update( fHandle, &version ) ) > -1 )
71     {
72         /* Update available - tell the user */
73         
74         NSBeginInformationalAlertSheet( _( @"Update is available" ),
75             _( @"Go get it!" ), _( @"Discard" ), NULL, fWindow, self,
76             @selector( UpdateAlertDone:returnCode:contextInfo: ),
77             NULL, NULL, [NSString stringWithFormat:
78             _( @"HandBrake %s (build %d) is now available for download." ),
79             version, build] );
80         return;
82     }
84     /* Show scan panel ASAP */
85     [self performSelectorOnMainThread: @selector(ShowScanPanel:)
86         withObject: NULL waitUntilDone: NO];
89 - (NSApplicationTerminateReply) applicationShouldTerminate:
90     (NSApplication *) app
92     if( [[fRipButton title] isEqualToString: _( @"Cancel" )] )
93     {
94         [self Cancel: NULL];
95         return NSTerminateCancel;
96     }
97     
98     /* Clean up */
99     hb_close( &fHandle );
100     return NSTerminateNow;
103 - (void) awakeFromNib
105     [fWindow center];
107     [self TranslateStrings];
110 //[self registrationDictionaryForGrowl];
111 /* Init User Presets .plist */
112         /* We declare the default NSFileManager into fileManager */
113         NSFileManager * fileManager = [NSFileManager defaultManager];
114         //presetPrefs = [[NSUserDefaults standardUserDefaults] retain];
115         /* we set the files and support paths here */
116         AppSupportDirectory = @"~/Library/Application Support/HandBrake";
117     AppSupportDirectory = [AppSupportDirectory stringByExpandingTildeInPath];
118     
119         UserPresetsFile = @"~/Library/Application Support/HandBrake/UserPresets.plist";
120     UserPresetsFile = [UserPresetsFile stringByExpandingTildeInPath];
121         
122         x264ProfilesFile = @"~/Library/Application Support/HandBrake/x264Profiles.plist";
123     x264ProfilesFile = [x264ProfilesFile stringByExpandingTildeInPath];
124         /* We check for the app support directory for media fork */
125         if ([fileManager fileExistsAtPath:AppSupportDirectory] == 0) 
126         {
127                 // If it doesnt exist yet, we create it here 
128                 [fileManager createDirectoryAtPath:AppSupportDirectory attributes:nil];
129         }
130         // We check for the presets.plist here
131         
132         if ([fileManager fileExistsAtPath:UserPresetsFile] == 0) 
133         {
135                 [fileManager createFileAtPath:UserPresetsFile contents:nil attributes:nil];
136                 
137         }
138         // We check for the x264profiles.plist here
139          
140         if ([fileManager fileExistsAtPath:x264ProfilesFile] == 0) 
141         {
142         
143                 [fileManager createFileAtPath:x264ProfilesFile contents:nil attributes:nil];
144         }
145     
146         
147   UserPresetsFile = @"~/Library/Application Support/HandBrake/UserPresets.plist";
148   UserPresetsFile = [[UserPresetsFile stringByExpandingTildeInPath]retain];
150   UserPresets = [[NSMutableArray alloc] initWithContentsOfFile:UserPresetsFile];
151   if (nil == UserPresets) 
152   {
153     UserPresets = [[NSMutableArray alloc] init];
154         [self AddFactoryPresets:NULL];
155   }
156   /* Show/Dont Show Presets drawer upon launch based
157   on user preference DefaultPresetsDrawerShow*/
158   if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultPresetsDrawerShow"] > 0)
159                 {
160           [fPresetDrawer open];
161                 }
165     /* Destination box*/
166     [fDstFormatPopUp removeAllItems];
167     [fDstFormatPopUp addItemWithTitle: _( @"MP4 file" )];
168     [fDstFormatPopUp addItemWithTitle: _( @"AVI file" )];
169     [fDstFormatPopUp addItemWithTitle: _( @"OGM file" )];
170     [fDstFormatPopUp selectItemAtIndex: 0];
172     [self FormatPopUpChanged: NULL];
173     /* We enable the create chapters checkbox here since we are .mp4 */ 
174         [fCreateChapterMarkers setEnabled: YES];
175         if ([fDstFormatPopUp indexOfSelectedItem] == 0 && [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultChapterMarkers"] > 0)
176         {
177                 [fCreateChapterMarkers setState: NSOnState];
178         }
179     [fDstFile2Field setStringValue: [NSString stringWithFormat:
180         @"%@/Desktop/Movie.mp4", NSHomeDirectory()]];
182     /* Video encoder */
183     [fVidEncoderPopUp removeAllItems];
184     [fVidEncoderPopUp addItemWithTitle: @"FFmpeg"];
185     [fVidEncoderPopUp addItemWithTitle: @"XviD"];
187     /* Video quality */
188     [fVidTargetSizeField setIntValue: 700];
189         [fVidBitrateField    setIntValue: 1000];
191     [fVidQualityMatrix   selectCell: fVidBitrateCell];
192     [self VideoMatrixChanged: NULL];
194     /* Video framerate */
195     [fVidRatePopUp removeAllItems];
196         [fVidRatePopUp addItemWithTitle: _( @"Same as source" )];
197     for( int i = 0; i < hb_video_rates_count; i++ )
198     {
199         [fVidRatePopUp addItemWithTitle:
200             [NSString stringWithCString: hb_video_rates[i].string]];
201     }
202     [fVidRatePopUp selectItemAtIndex: 0];
203         
204         /* Picture Settings */
205         [fPicLabelPAROutp setStringValue: @""];
206         [fPicLabelPAROutputX setStringValue: @""];
207         [fPicSettingPARWidth setStringValue: @""];
208         [fPicSettingPARHeight setStringValue:  @""];
209         
210     /* Audio bitrate */
211     [fAudBitratePopUp removeAllItems];
212     for( int i = 0; i < hb_audio_bitrates_count; i++ )
213     {
214         [fAudBitratePopUp addItemWithTitle:
215             [NSString stringWithCString: hb_audio_bitrates[i].string]];
216     }
217     [fAudBitratePopUp selectItemAtIndex: hb_audio_bitrates_default];
219     /* Audio samplerate */
220     [fAudRatePopUp removeAllItems];
221     for( int i = 0; i < hb_audio_rates_count; i++ )
222     {
223         [fAudRatePopUp addItemWithTitle:
224             [NSString stringWithCString: hb_audio_rates[i].string]];
225     }
226     [fAudRatePopUp selectItemAtIndex: hb_audio_rates_default];
228     /* Bottom */
229     [fStatusField setStringValue: @""];
231     [self EnableUI: NO];
232     [fPauseButton setEnabled: NO];
233     [fRipButton setEnabled: NO];
239 // register a test notification and make
240 // it enabled by default
241 #define SERVICE_NAME @"Encode Done"
242 - (NSDictionary *)registrationDictionaryForGrowl 
244 NSDictionary *registrationDictionary = [NSDictionary dictionaryWithObjectsAndKeys: 
245 [NSArray arrayWithObjects:SERVICE_NAME,nil], GROWL_NOTIFICATIONS_ALL, 
246 [NSArray arrayWithObjects:SERVICE_NAME,nil], GROWL_NOTIFICATIONS_DEFAULT, 
247 nil]; 
249 return registrationDictionary; 
251 - (void) TranslateStrings
253     [fSrcDVD1Field      setStringValue: _( @"DVD:" )];
254     [fSrcTitleField     setStringValue: _( @"Title:" )];
255     [fSrcChapterField   setStringValue: _( @"Chapters:" )];
256     [fSrcChapterToField setStringValue: _( @"to" )];
257     [fSrcDuration1Field setStringValue: _( @"Duration:" )];
259     [fDstFormatField    setStringValue: _( @"File format:" )];
260     [fDstCodecsField    setStringValue: _( @"Codecs:" )];
261     [fDstFile1Field     setStringValue: _( @"File:" )];
262     [fDstBrowseButton   setTitle:       _( @"Browse" )];
264     [fVidRateField      setStringValue: _( @"Framerate (fps):" )];
265     [fVidEncoderField   setStringValue: _( @"Encoder:" )];
266     [fVidQualityField   setStringValue: _( @"Quality:" )];
269 /***********************************************************************
270  * UpdateDockIcon
271  ***********************************************************************
272  * Shows a progression bar on the dock icon, filled according to
273  * 'progress' (0.0 <= progress <= 1.0).
274  * Called with progress < 0.0 or progress > 1.0, restores the original
275  * icon.
276  **********************************************************************/
277 - (void) UpdateDockIcon: (float) progress
279     NSImage * icon;
280     NSData * tiff;
281     NSBitmapImageRep * bmp;
282     uint32_t * pen;
283     uint32_t black = htonl( 0x000000FF );
284     uint32_t red   = htonl( 0xFF0000FF );
285     uint32_t white = htonl( 0xFFFFFFFF );
286     int row_start, row_end;
287     int i, j;
289     /* Get application original icon */
290     icon = [NSImage imageNamed: @"NSApplicationIcon"];
292     if( progress < 0.0 || progress > 1.0 )
293     {
294         [NSApp setApplicationIconImage: icon];
295         return;
296     }
298     /* Get it in a raw bitmap form */
299     tiff = [icon TIFFRepresentationUsingCompression:
300             NSTIFFCompressionNone factor: 1.0];
301     bmp = [NSBitmapImageRep imageRepWithData: tiff];
302     
303     /* Draw the progression bar */
304     /* It's pretty simple (ugly?) now, but I'm no designer */
306     row_start = 3 * (int) [bmp size].height / 4;
307     row_end   = 7 * (int) [bmp size].height / 8;
309     for( i = row_start; i < row_start + 2; i++ )
310     {
311         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
312         for( j = 0; j < (int) [bmp size].width; j++ )
313         {
314             pen[j] = black;
315         }
316     }
317     for( i = row_start + 2; i < row_end - 2; i++ )
318     {
319         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
320         pen[0] = black;
321         pen[1] = black;
322         for( j = 2; j < (int) [bmp size].width - 2; j++ )
323         {
324             if( j < 2 + (int) ( ( [bmp size].width - 4.0 ) * progress ) )
325             {
326                 pen[j] = red;
327             }
328             else
329             {
330                 pen[j] = white;
331             }
332         }
333         pen[j]   = black;
334         pen[j+1] = black;
335     }
336     for( i = row_end - 2; i < row_end; i++ )
337     {
338         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
339         for( j = 0; j < (int) [bmp size].width; j++ )
340         {
341             pen[j] = black;
342         }
343     }
345     /* Now update the dock icon */
346     tiff = [bmp TIFFRepresentationUsingCompression:
347             NSTIFFCompressionNone factor: 1.0];
348     icon = [[NSImage alloc] initWithData: tiff];
349     [NSApp setApplicationIconImage: icon];
350     [icon release];
353 - (void) UpdateUI: (NSTimer *) timer
356     hb_state_t s;
357     hb_get_state( fHandle, &s );
359     switch( s.state )
360     {
361         case HB_STATE_IDLE:
362             break;
364         case HB_STATE_SCANNING:
365             [fScanController UpdateUI: &s];
366             break;
368 #define p s.param.scandone
369         case HB_STATE_SCANDONE:
370         {
371             hb_list_t  * list;
372             hb_title_t * title;
373                         int indxpri=0;    // Used to search the longuest title (default in combobox)
374                         int longuestpri=0; // Used to search the longuest title (default in combobox)
376             [fScanController UpdateUI: &s];
378             list = hb_get_titles( fHandle );
380             if( !hb_list_count( list ) )
381             {
382                 break;
383             }
386             [fSrcTitlePopUp removeAllItems];
387             for( int i = 0; i < hb_list_count( list ); i++ )
388             {
389                 title = (hb_title_t *) hb_list_item( list, i );
390                 /*Set DVD Name at top of window*/
391                                 [fSrcDVD2Field setStringValue: [NSString
392                   stringWithUTF8String: title->name]];  
393                                 
394                                 /* Use the dvd name in the default output field here 
395                                 May want to add code to remove blank spaces for some dvd names*/
396                                 /* Check to see if the last destination has been set,use if so, if not, use Desktop */
397                                 if ([[NSUserDefaults standardUserDefaults] stringForKey:@"LastDestinationDirectory"])
398                                 {
399                                 [fDstFile2Field setStringValue: [NSString stringWithFormat:
400                 @"%@/%@.mp4", [[NSUserDefaults standardUserDefaults] stringForKey:@"LastDestinationDirectory"],[NSString
401                   stringWithUTF8String: title->name]]];
402                                 }
403                                 else
404                                 {
405                                 [fDstFile2Field setStringValue: [NSString stringWithFormat:
406                 @"%@/Desktop/%@.mp4", NSHomeDirectory(),[NSString
407                   stringWithUTF8String: title->name]]];
408                                 }
410                   
411                 if (longuestpri < title->hours*60*60 + title->minutes *60 + title->seconds)
412                 {
413                         longuestpri=title->hours*60*60 + title->minutes *60 + title->seconds;
414                         indxpri=i;
415                 }
416                 
417                                 
418                 int format = [fDstFormatPopUp indexOfSelectedItem];
419                                 char * ext = NULL;
420                                 switch( format )
421                 {
422                  case 0:
423                                          
424                                          /*Get Default MP4 File Extension for mpeg4 (.mp4 or .m4v) from prefs*/
425                                          if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultMpegName"] > 0)
426                                          {
427                                          ext = "m4v";
428                                          }
429                                      else
430                                      {
431                                          ext = "mp4";
432                                          }
433                                         break;
434                                 case 1: 
435                      ext = "avi";
436                      break;
437                                 case 2:
438                      ext = "ogm";
439                                  break;
440                                    }
441                                 
442                                 
443                                 NSString * string = [fDstFile2Field stringValue];
444                                 /* Add/replace File Output name to the correct extension*/
445                                 if( [string characterAtIndex: [string length] - 4] == '.' )
446                                 {
447                                         [fDstFile2Field setStringValue: [NSString stringWithFormat:
448                                                 @"%@.%s", [string substringToIndex: [string length] - 4],
449                                                 ext]];
450                                 }
451                                 else
452                                 {
453                                         [fDstFile2Field setStringValue: [NSString stringWithFormat:
454                                                 @"%@.%s", string, ext]];
455                                 }
457                                 
458                             [fSrcTitlePopUp addItemWithTitle: [NSString
459                     stringWithFormat: @"%d - %02dh%02dm%02ds",
460                     title->index, title->hours, title->minutes,
461                     title->seconds]];
462                         
463             }
464             // Select the longuest title
465                         [fSrcTitlePopUp selectItemAtIndex: indxpri];
466             /* We set the Settings Display to "Default" here
467                         until we get default presets implemented */
468                         [fPresetSelectedDisplay setStringValue: @"Default"];
469                         
470             [self TitlePopUpChanged: NULL];
471             [self EnableUI: YES];
472             [fPauseButton setEnabled: NO];
473             [fRipButton   setEnabled: YES];
474             break;
475         }
476 #undef p
478 #define p s.param.working
479         case HB_STATE_WORKING:
480         {
481             float progress_total;
482             NSMutableString * string;
484             /* Update text field */
485             string = [NSMutableString stringWithFormat:
486                 _( @"Encoding: task %d of %d, %.2f %%" ),
487                 p.job_cur, p.job_count, 100.0 * p.progress];
488             if( p.seconds > -1 )
489             {
490                 [string appendFormat:
491                     _( @" (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)" ),
492                     p.rate_cur, p.rate_avg, p.hours, p.minutes, p.seconds];
493             }
494             [fStatusField setStringValue: string];
496             /* Update slider */
497             progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count;
498             [fRipIndicator setIndeterminate: NO];
499             [fRipIndicator setDoubleValue: 100.0 * progress_total];
501             /* Update dock icon */
502             [self UpdateDockIcon: progress_total];
504             [fPauseButton setEnabled: YES];
505             [fPauseButton setTitle: _( @"Pause" )];
506             [fRipButton setEnabled: YES];
507             [fRipButton setTitle: _( @"Cancel" )];
508             break;
509         }
510 #undef p
512 #define p s.param.muxing
513         case HB_STATE_MUXING:
514         {
515             NSMutableString * string;
516                         
517             /* Update text field */
518             string = [NSMutableString stringWithFormat:
519                 _( @"Muxing..." )];
520             [fStatusField setStringValue: string];
521                         
522             /* Update slider */
523             [fRipIndicator setIndeterminate: YES];
524             [fRipIndicator startAnimation: nil];
525                         
526             /* Update dock icon */
527             [self UpdateDockIcon: 1.0];
528                         
529             [fPauseButton setEnabled: YES];
530             [fPauseButton setTitle: _( @"Pause" )];
531             [fRipButton setEnabled: YES];
532             [fRipButton setTitle: _( @"Cancel" )];
533             break;
534         }
535 #undef p
536                         
537         case HB_STATE_PAUSED:
538                     [fStatusField setStringValue: _( @"Paused" )];
539             [fPauseButton setEnabled: YES];
540             [fPauseButton setTitle: _( @"Resume" )];
541             [fRipButton setEnabled: YES];
542             [fRipButton setTitle: _( @"Cancel" )];
543             break;
545         case HB_STATE_WORKDONE:
546         {
547             //[self EnableUI: YES];
548             [fStatusField setStringValue: _( @"Done." )];
549             [fRipIndicator setIndeterminate: NO];
550             [fRipIndicator setDoubleValue: 0.0];
551             [fRipButton setTitle: _( @"Start" )];
552                         
553             /* Restore dock icon */
554             [self UpdateDockIcon: -1.0];
555                         
556             [fPauseButton setEnabled: NO];
557             [fPauseButton setTitle: _( @"Pause" )];
558             [fRipButton setEnabled: YES];
559             [fRipButton setTitle: _( @"Start" )];
560                         
561             /* FIXME */
562             hb_job_t * job;
563             while( ( job = hb_job( fHandle, 0 ) ) )
564             {
565                 hb_rem( fHandle, job );
566             }
567             
568                         if (fEncodeState != 2) // if the encode has not been cancelled
569                         {
570                                 /* Lets alert the user that the encode has finished */
571                                 /*Growl Notification*/
572                                 [self showGrowlDoneNotification: NULL];
573                                 /*On Screen Notification*/
574                                 int status;
575                                 NSBeep();
576                                 status = NSRunAlertPanel(@"Put down that cocktail...",@"your HandBrake encode is done!", @"OK", nil, nil);
577                                 //[NSApp requestUserAttention:NSInformationalRequest];
578                                 [NSApp requestUserAttention:NSCriticalRequest];
579                                 if ( status == NSAlertDefaultReturn ) 
580                                 {
581                                         [self EnableUI: YES];
582                                 }
583                         }
584                         else
585                         {
586                         [self EnableUI: YES];
587                         }
588             break;
589         }
590     }
592     /* Lets show the queue status
593         here in the main window*/
595         int count = hb_count( fHandle );
596         if( count )
597         {
598             [fQueueStatus setStringValue: [NSString stringWithFormat:
599                 @"%d task%s in the queue",
600                 count, ( count > 1 ) ? "s" : ""]];
601         }
602         else
603         {
604             [fQueueStatus setStringValue: @""];
605         }
607     [[NSRunLoop currentRunLoop] addTimer: [NSTimer
608         scheduledTimerWithTimeInterval: 0.2 target: self
609         selector: @selector( UpdateUI: ) userInfo: NULL repeats: FALSE]
610         forMode: NSModalPanelRunLoopMode];
613 -(IBAction)showGrowlDoneNotification:(id)sender
616   
617   [GrowlApplicationBridge 
618           notifyWithTitle:@"Put down that cocktail..." 
619               description:@"your HandBrake encode is done!" 
620          notificationName:SERVICE_NAME
621                  iconData:nil 
622                  priority:0 
623                  isSticky:1 
624              clickContext:nil];
627 - (void) EnableUI: (bool) b
629     NSControl * controls[] =
630       { fSrcDVD1Field, fSrcDVD2Field, fSrcTitleField, fSrcTitlePopUp,
631         fSrcChapterField, fSrcChapterStartPopUp, fSrcChapterToField,
632         fSrcChapterEndPopUp, fSrcDuration1Field, fSrcDuration2Field,
633         fDstFormatField, fDstFormatPopUp, fDstCodecsField,
634         fDstCodecsPopUp, fDstFile1Field, fDstFile2Field,
635         fDstBrowseButton, fVidRateField, fVidRatePopUp,
636         fVidEncoderField, fVidEncoderPopUp, fVidQualityField,
637         fVidQualityMatrix, fVidGrayscaleCheck, fSubField, fSubPopUp,
638         fAudLang1Field, fAudLang1PopUp, fAudLang2Field, fAudLang2PopUp,
639         fAudTrack1MixLabel, fAudTrack1MixPopUp, fAudTrack2MixLabel, fAudTrack2MixPopUp,
640         fAudRateField, fAudRatePopUp, fAudBitrateField,
641         fAudBitratePopUp, fPictureButton,fQueueStatus, 
642                 fPicSrcWidth,fPicSrcHeight,fPicSettingWidth,fPicSettingHeight,
643                 fPicSettingARkeep,fPicSettingDeinterlace,fPicSettingARkeepDsply,
644                 fPicSettingDeinterlaceDsply,fPicLabelSettings,fPicLabelSrc,fPicLabelOutp,
645                 fPicLabelAr,fPicLabelDeinter,fPicLabelSrcX,fPicLabelOutputX,
646                 fPicLabelPAROutp,fPicLabelPAROutputX,fPicSettingPARWidth,fPicSettingPARHeight,
647                 fPicSettingPARDsply,fPicLabelAnamorphic,tableView,fPresetsAdd,fPresetsDelete,
648                 fCreateChapterMarkers,fX264optViewTitleLabel,fDisplayX264Options,fDisplayX264OptionsLabel,fX264optBframesLabel,
649                 fX264optBframesPopUp,fX264optRefLabel,fX264optRefPopUp,fX264optNfpskipLabel,fX264optNfpskipPopUp,
650                 fX264optNodctdcmtLabel,fX264optNodctdcmtPopUp,fX264optSubmeLabel,fX264optSubmePopUp,
651                 fX264optTrellisLabel,fX264optTrellisPopUp,fX264optMixedRefsLabel,fX264optMixedRefsPopUp,
652                 fX264optMotionEstLabel,fX264optMotionEstPopUp,fX264optMERangeLabel,fX264optMERangePopUp,
653                 fX264optWeightBLabel,fX264optWeightBPopUp,fX264optBRDOLabel,fX264optBRDOPopUp,
654                 fX264optBPyramidLabel,fX264optBPyramidPopUp};
656     for( unsigned i = 0;
657          i < sizeof( controls ) / sizeof( NSControl * ); i++ )
658     {
659         if( [[controls[i] className] isEqualToString: @"NSTextField"] )
660         {
661             NSTextField * tf = (NSTextField *) controls[i];
662             if( ![tf isBezeled] )
663             {
664                 [tf setTextColor: b ? [NSColor controlTextColor] :
665                     [NSColor disabledControlTextColor]];
666                 continue;
667             }
668         }
669         [controls[i] setEnabled: b];
671     }
672         
673         if (b) {
675         /* if we're enabling the interface, check if the audio mixdown controls need to be enabled or not */
676         /* these will have been enabled by the mass control enablement above anyway, so we're sense-checking it here */
677         [self SetEnabledStateOfAudioMixdownControls: NULL];
678         
679         } else {
681                 [tableView setEnabled: NO];
682         
683         }
685     [self VideoMatrixChanged: NULL];
688 - (IBAction) ShowScanPanel: (id) sender
690     [fScanController Show];
693 - (BOOL) windowShouldClose: (id) sender
695     /* Stop the application when the user closes the window */
696     [NSApp terminate: self];
697     return YES;
700 - (IBAction) VideoMatrixChanged: (id) sender;
702     bool target, bitrate, quality;
704     target = bitrate = quality = false;
705     if( [fVidQualityMatrix isEnabled] )
706     {
707         switch( [fVidQualityMatrix selectedRow] )
708         {
709             case 0:
710                 target = true;
711                 break;
712             case 1:
713                 bitrate = true;
714                 break;
715             case 2:
716                 quality = true;
717                 break;
718         }
719     }
720     [fVidTargetSizeField  setEnabled: target];
721     [fVidBitrateField     setEnabled: bitrate];
722     [fVidQualitySlider    setEnabled: quality];
723     [fVidTwoPassCheck     setEnabled: !quality &&
724         [fVidQualityMatrix isEnabled]];
725     if( quality )
726     {
727         [fVidTwoPassCheck setState: NSOffState];
728     }
730     [self QualitySliderChanged: sender];
731     [self CalculateBitrate:     sender];
732         [self CustomSettingUsed: sender];
735 - (IBAction) QualitySliderChanged: (id) sender
737     [fVidConstantCell setTitle: [NSString stringWithFormat:
738         _( @"Constant quality: %.0f %%" ), 100.0 *
739         [fVidQualitySlider floatValue]]];
740                 [self CustomSettingUsed: sender];
743 - (IBAction) BrowseFile: (id) sender
745     /* Open a panel to let the user choose and update the text field */
746     NSSavePanel * panel = [NSSavePanel savePanel];
747         /* We get the current file name and path from the destination field here */
748         [panel beginSheetForDirectory: [[fDstFile2Field stringValue] stringByDeletingLastPathComponent] file: [[fDstFile2Field stringValue] lastPathComponent]
749                                    modalForWindow: fWindow modalDelegate: self
750                                    didEndSelector: @selector( BrowseFileDone:returnCode:contextInfo: )
751                                           contextInfo: NULL];
754 - (void) BrowseFileDone: (NSSavePanel *) sheet
755     returnCode: (int) returnCode contextInfo: (void *) contextInfo
757     if( returnCode == NSOKButton )
758     {
759         [fDstFile2Field setStringValue: [sheet filename]];
760                 
761     }
764 - (IBAction) ShowPicturePanel: (id) sender
766     hb_list_t  * list  = hb_get_titles( fHandle );
767     hb_title_t * title = (hb_title_t *) hb_list_item( list,
768             [fSrcTitlePopUp indexOfSelectedItem] );
770     /* Resize the panel */
771     NSSize newSize;
772     newSize.width  = 246 + title->width;
773     newSize.height = 80 + title->height;
774     [fPicturePanel setContentSize: newSize];
776     [fPictureController SetTitle: title];
778     [NSApp beginSheet: fPicturePanel modalForWindow: fWindow
779         modalDelegate: NULL didEndSelector: NULL contextInfo: NULL];
780     [NSApp runModalForWindow: fPicturePanel];
781     [NSApp endSheet: fPicturePanel];
782     [fPicturePanel orderOut: self];
783         [self CalculatePictureSizing: sender];
786 - (IBAction) ShowQueuePanel: (id) sender
788     /* Update the OutlineView */
789     [fQueueController Update: sender];
791     /* Show the panel */
792     [NSApp beginSheet: fQueuePanel modalForWindow: fWindow
793         modalDelegate: NULL didEndSelector: NULL contextInfo: NULL];
794     [NSApp runModalForWindow: fQueuePanel];
795     [NSApp endSheet: fQueuePanel];
796     [fQueuePanel orderOut: self];
799 - (void) PrepareJob
801     hb_list_t  * list  = hb_get_titles( fHandle );
802     hb_title_t * title = (hb_title_t *) hb_list_item( list,
803             [fSrcTitlePopUp indexOfSelectedItem] );
804     hb_job_t * job = title->job;
805     //int i;
807     /* Chapter selection */
808     job->chapter_start = [fSrcChapterStartPopUp indexOfSelectedItem] + 1;
809     job->chapter_end   = [fSrcChapterEndPopUp   indexOfSelectedItem] + 1;
810         
811     /* Format and codecs */
812     int format = [fDstFormatPopUp indexOfSelectedItem];
813     int codecs = [fDstCodecsPopUp indexOfSelectedItem];
814     job->mux    = FormatSettings[format][codecs] & HB_MUX_MASK;
815     job->vcodec = FormatSettings[format][codecs] & HB_VCODEC_MASK;
816     job->acodec = FormatSettings[format][codecs] & HB_ACODEC_MASK;
817     /* We set the chapter marker extraction here based on the format being
818         mpeg4 and the checkbox being checked */
819         if ([fDstFormatPopUp indexOfSelectedItem] == 0 && [fCreateChapterMarkers state] == NSOnState)
820         {
821         job->chapter_markers = 1;
822         }
823         else
824         {
825         job->chapter_markers = 0;
826         }
827     if( ( job->vcodec & HB_VCODEC_FFMPEG ) &&
828         [fVidEncoderPopUp indexOfSelectedItem] > 0 )
829     {
830         job->vcodec = HB_VCODEC_XVID;
831     }
832     if( job->vcodec & HB_VCODEC_X264 )
833     {
834          if ([fVidEncoderPopUp indexOfSelectedItem] > 0 )
835             {
836                 /* Just use new Baseline Level 3.0 
837                 Lets Deprecate Baseline Level 1.3*/
838                 job->h264_level = 30;
839                 job->mux = HB_MUX_IPOD;
840         /* move sanity check for iPod Encoding here */
841                 job->pixel_ratio = 0 ;
843                 }
844                 
845                 /* Set this flag to switch from Constant Quantizer(default) to Constant Rate Factor Thanks jbrjake
846                 Currently only used with Constant Quality setting*/
847                 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultCrf"] > 0 && [fVidQualityMatrix selectedRow] == 2)
848                 {
849                 /* Can only be used with svn rev >= 89 */
850                         job->crf = 1;
851                 }
852                 
853                 /* Below Sends x264 options to the core library if x264 is selected*/
854                 /* First we look to see if a user preset has been selected that contains a x264 optional string CurUserPresetChosenNum = nil */
855                 //if (curUserPresetChosenNum != nil)
856                 //{
857                         
858                         /* Lets use this as per Nyx, Thanks Nyx! fDisplayX264Options*/
859                         job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */  
860                         strcpy(job->x264opts, [[fDisplayX264Options stringValue] UTF8String]);
861                         //strcpy(job->x264opts, [[chosenPreset valueForKey:@"x264Option"] UTF8String]);
862                         //job->x264opts = [[chosenPreset valueForKey:@"x264Option"] cString];
863                 //}
864                 //else
865                 //{
866                     /* if not, then we check to see if there is a x264 opt in the preferences and use that if we want */
867                         //job->x264opts = [[[NSUserDefaults standardUserDefaults] stringForKey:@"DefAdvancedx264Flags"] UTF8String];
868                         /* Lets use this as per Nyx, Thanks Nyx! */
869                         //job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */  
870                         //strcpy(job->x264opts, [[[NSUserDefaults standardUserDefaults] stringForKey:@"DefAdvancedx264Flags"] UTF8String]);
871                 //} 
872                 
873                 
874                 
875         job->h264_13 = [fVidEncoderPopUp indexOfSelectedItem];
876     }
878     /* Video settings */
879     if( [fVidRatePopUp indexOfSelectedItem] > 0 )
880     {
881         job->vrate      = 27000000;
882         job->vrate_base = hb_video_rates[[fVidRatePopUp
883             indexOfSelectedItem]-1].rate;
884     }
885     else
886     {
887         job->vrate      = title->rate;
888         job->vrate_base = title->rate_base;
889     }
891     switch( [fVidQualityMatrix selectedRow] )
892     {
893         case 0:
894             /* Target size.
895                Bitrate should already have been calculated and displayed
896                in fVidBitrateField, so let's just use it */
897         case 1:
898             job->vquality = -1.0;
899             job->vbitrate = [fVidBitrateField intValue];
900             break;
901         case 2:
902             job->vquality = [fVidQualitySlider floatValue];
903             job->vbitrate = 0;
904             break;
905     }
907     job->grayscale = ( [fVidGrayscaleCheck state] == NSOnState );
908     
911     /* Subtitle settings */
912     job->subtitle = [fSubPopUp indexOfSelectedItem] - 1;
914     /* Audio tracks and mixdowns */
915     /* check for the condition where track 2 has an audio selected, but track 1 does not */
916     /* we will use track 2 as track 1 in this scenario */
917     if ([fAudLang1PopUp indexOfSelectedItem] > 0)
918     {
919         job->audios[0] = [fAudLang1PopUp indexOfSelectedItem] - 1;
920         job->audios[1] = [fAudLang2PopUp indexOfSelectedItem] - 1; /* will be -1 if "none" is selected */
921         job->audios[2] = -1;
922         job->audio_mixdowns[0] = [[fAudTrack1MixPopUp selectedItem] tag];
923         job->audio_mixdowns[1] = [[fAudTrack2MixPopUp selectedItem] tag];
924     }
925     else if ([fAudLang2PopUp indexOfSelectedItem] > 0)
926     {
927         job->audios[0] = [fAudLang2PopUp indexOfSelectedItem] - 1;
928         job->audio_mixdowns[0] = [[fAudTrack2MixPopUp selectedItem] tag];
929         job->audios[1] = -1;
930     }
931     else
932     {
933         job->audios[0] = -1;
934     }
936     /* Audio settings */
937     job->arate = hb_audio_rates[[fAudRatePopUp
938                      indexOfSelectedItem]].rate;
939     job->abitrate = [[fAudBitratePopUp selectedItem] tag];
945 - (IBAction) AddToQueue: (id) sender
947 /* We get the destination directory from the destingation field here */
948         NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent];
949         /* We check for a valid destination here */
950         if ([[NSFileManager defaultManager] fileExistsAtPath:destinationDirectory] == 0) 
951         {
952                 NSRunAlertPanel(@"Warning!", @"This is not a valid destination directory!", @"OK", nil, nil);
953         }
954         else
955         {
956                 
957                 hb_list_t  * list  = hb_get_titles( fHandle );
958                 hb_title_t * title = (hb_title_t *) hb_list_item( list,
959                                                                                                                   [fSrcTitlePopUp indexOfSelectedItem] );
960                 hb_job_t * job = title->job;
961                 
962                 [self PrepareJob];
963                 
964                 /* Destination file */
965                 job->file = [[fDstFile2Field stringValue] UTF8String];
966                 
967                 if( [fVidTwoPassCheck state] == NSOnState )
968                 {
969                         job->pass = 1;
970                         hb_add( fHandle, job );
971                         job->pass = 2;
972                         
973                         job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */  
974                         strcpy(job->x264opts, [[fDisplayX264Options stringValue] UTF8String]);
975                         
976                         hb_add( fHandle, job );
977                 }
978                 else
979                 {
980                         job->pass = 0;
981                         hb_add( fHandle, job );
982                 }
983         
984         [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"];
985         }
988 - (IBAction) Rip: (id) sender
990     /* Rip or Cancel ? */
991     if( [[fRipButton title] isEqualToString: _( @"Cancel" )] )
992     {
993         [self Cancel: sender];
994         return;
995     }
996         /* if there is no job in the queue, then add it to the queue and rip 
997         otherwise, there are already jobs in queue, so just rip the queue */
998         int count = hb_count( fHandle );
999         if( count < 1 )
1000         {
1001                 [self AddToQueue: sender];
1002                 }
1003     
1004             /* We check for duplicate name here */
1005         if( [[NSFileManager defaultManager] fileExistsAtPath:
1006             [fDstFile2Field stringValue]] )
1007     {
1008         NSBeginCriticalAlertSheet( _( @"File already exists" ),
1009             _( @"Cancel" ), _( @"Overwrite" ), NULL, fWindow, self,
1010             @selector( OverwriteAlertDone:returnCode:contextInfo: ),
1011             NULL, NULL, [NSString stringWithFormat:
1012             _( @"Do you want to overwrite %@?" ),
1013             [fDstFile2Field stringValue]] );
1014         return;
1015     }
1016         /* We get the destination directory from the destination field here */
1017         NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent];
1018         /* We check for a valid destination here */
1019         if ([[NSFileManager defaultManager] fileExistsAtPath:destinationDirectory] == 0) 
1020         {
1021                 NSRunAlertPanel(@"Warning!", @"This is not a valid destination directory!", @"OK", nil, nil);
1022         }
1023         else
1024         {
1025         [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"];
1026                 [self _Rip];
1027         }
1028         
1033 - (void) OverwriteAlertDone: (NSWindow *) sheet
1034     returnCode: (int) returnCode contextInfo: (void *) contextInfo
1036     if( returnCode == NSAlertAlternateReturn )
1037     {
1038         [self _Rip];
1039     }
1042 - (void) UpdateAlertDone: (NSWindow *) sheet
1043     returnCode: (int) returnCode contextInfo: (void *) contextInfo
1045     if( returnCode == NSAlertAlternateReturn )
1046     {
1047         /* Show scan panel */
1048         [self performSelectorOnMainThread: @selector(ShowScanPanel:)
1049             withObject: NULL waitUntilDone: NO];
1050         return;
1051     }
1053     /* Go to HandBrake homepage and exit */
1054     [self OpenHomepage: NULL];
1055     [NSApp terminate: self];
1058 - (void) _Rip
1060     /* Let libhb do the job */
1061     hb_start( fHandle );
1062         /*set the fEncodeState State */
1063         fEncodeState = 1;
1065     /* Disable interface */
1066    [self EnableUI: NO];
1067     [fPauseButton setEnabled: NO];
1068     [fRipButton   setEnabled: NO];
1071 - (IBAction) Cancel: (id) sender
1073     NSBeginCriticalAlertSheet( _( @"Cancel - Are you sure?" ),
1074         _( @"Keep working" ), _( @"Cancel encoding" ), NULL, fWindow, self,
1075         @selector( _Cancel:returnCode:contextInfo: ), NULL, NULL,
1076         _( @"Encoding won't be recoverable." ) );
1079 - (void) _Cancel: (NSWindow *) sheet
1080     returnCode: (int) returnCode contextInfo: (void *) contextInfo
1082     if( returnCode == NSAlertAlternateReturn )
1083     {
1084         hb_stop( fHandle );
1085         [fPauseButton setEnabled: NO];
1086         [fRipButton   setEnabled: NO];
1087                 /*set the fEncodeState State */
1088              fEncodeState = 2;
1089     }
1092 - (IBAction) Pause: (id) sender
1094     [fPauseButton setEnabled: NO];
1095     [fRipButton   setEnabled: NO];
1097     if( [[fPauseButton title] isEqualToString: _( @"Resume" )] )
1098     {
1099         hb_resume( fHandle );
1100     }
1101     else
1102     {
1103         hb_pause( fHandle );
1104     }
1107 - (IBAction) TitlePopUpChanged: (id) sender
1109     hb_list_t  * list  = hb_get_titles( fHandle );
1110     hb_title_t * title = (hb_title_t*)
1111         hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
1112                 
1113                 
1114     /* If Auto Naming is on. We create an output filename of dvd name - title number */
1115     if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultAutoNaming"] > 0)
1116         {
1117                 [fDstFile2Field setStringValue: [NSString stringWithFormat:
1118                         @"%@/%@-%d.%@", [[fDstFile2Field stringValue] stringByDeletingLastPathComponent],
1119                         [NSString stringWithUTF8String: title->name],
1120                         [fSrcTitlePopUp indexOfSelectedItem] + 1,
1121                         [[fDstFile2Field stringValue] pathExtension]]]; 
1122         }
1124     /* Update chapter popups */
1125     [fSrcChapterStartPopUp removeAllItems];
1126     [fSrcChapterEndPopUp   removeAllItems];
1127     for( int i = 0; i < hb_list_count( title->list_chapter ); i++ )
1128     {
1129         [fSrcChapterStartPopUp addItemWithTitle: [NSString
1130             stringWithFormat: @"%d", i + 1]];
1131         [fSrcChapterEndPopUp addItemWithTitle: [NSString
1132             stringWithFormat: @"%d", i + 1]];
1133     }
1134     [fSrcChapterStartPopUp selectItemAtIndex: 0];
1135     [fSrcChapterEndPopUp   selectItemAtIndex:
1136         hb_list_count( title->list_chapter ) - 1];
1137     [self ChapterPopUpChanged: NULL];
1139 /* Start Get and set the initial pic size for display */
1140         hb_job_t * job = title->job;
1141         fTitle = title; 
1142         /* Turn Deinterlace on/off depending on the preference */
1143         if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultDeinterlaceOn"] > 0)
1144         {
1145                 job->deinterlace = 1;
1146         }
1147         else
1148         {
1149                 job->deinterlace = 0;
1150         }
1151         
1152         /* Pixel Ratio Setting */
1153         if ([[NSUserDefaults standardUserDefaults] boolForKey:@"PixelRatio"])
1154     {
1156                 job->pixel_ratio = 1 ;
1157         }
1158         else
1159         {
1160                 job->pixel_ratio = 0 ;
1161         }
1162         /*Set Source Size Fields Here */
1163         [fPicSrcWidth setStringValue: [NSString stringWithFormat:
1164                                                          @"%d", fTitle->width]];
1165         [fPicSrcHeight setStringValue: [NSString stringWithFormat:
1166                                                          @"%d", fTitle->height]];
1167         /* We get the originial output picture width and height and put them
1168         in variables for use with some presets later on */
1169         PicOrigOutputWidth = job->width;
1170         PicOrigOutputHeight = job->height;
1171         /* we test getting the max output value for pic sizing here to be used later*/
1172         [fPicSettingWidth setStringValue: [NSString stringWithFormat:
1173                 @"%d", PicOrigOutputWidth]];
1174         [fPicSettingHeight setStringValue: [NSString stringWithFormat:
1175                 @"%d", PicOrigOutputHeight]];
1176         /* we run the picture size values through
1177         CalculatePictureSizing to get all picture size
1178         information*/
1179         [self CalculatePictureSizing: NULL];
1180         /* Run Through EncoderPopUpChanged to see if there
1181                 needs to be any pic value modifications based on encoder settings */
1182         //[self EncoderPopUpChanged: NULL];
1183         /* END Get and set the initial pic size for display */ 
1185     /* Update subtitle popups */
1186     hb_subtitle_t * subtitle;
1187     [fSubPopUp removeAllItems];
1188     [fSubPopUp addItemWithTitle: @"None"];
1189     for( int i = 0; i < hb_list_count( title->list_subtitle ); i++ )
1190     {
1191         subtitle = (hb_subtitle_t *) hb_list_item( title->list_subtitle, i );
1193         /* We cannot use NSPopUpButton's addItemWithTitle because
1194            it checks for duplicate entries */
1195         [[fSubPopUp menu] addItemWithTitle: [NSString stringWithCString:
1196             subtitle->lang] action: NULL keyEquivalent: @""];
1197     }
1198     [fSubPopUp selectItemAtIndex: 0];
1199     
1200     /* Update chapter table */
1201     [fChapterTitlesDelegate resetWithTitle:title];
1202     [fChapterTable reloadData];
1204     /* Update audio popups */
1205     [self AddAllAudioTracksToPopUp: fAudLang1PopUp];
1206     [self AddAllAudioTracksToPopUp: fAudLang2PopUp];
1207     /* search for the first instance of our prefs default language for track 1, and set track 2 to "none" */
1208         NSString * audioSearchPrefix = [[NSUserDefaults standardUserDefaults] stringForKey:@"DefaultLanguage"];
1209     [self SelectAudioTrackInPopUp: fAudLang1PopUp searchPrefixString: audioSearchPrefix selectIndexIfNotFound: 1];
1210     [self SelectAudioTrackInPopUp: fAudLang2PopUp searchPrefixString: NULL selectIndexIfNotFound: 0];
1211         
1212         /* changing the title may have changed the audio channels on offer, */
1213         /* so call AudioTrackPopUpChanged for both audio tracks to update the mixdown popups */
1214         [self AudioTrackPopUpChanged: fAudLang1PopUp];
1215         [self AudioTrackPopUpChanged: fAudLang2PopUp];
1219 - (IBAction) ChapterPopUpChanged: (id) sender
1221     hb_list_t  * list  = hb_get_titles( fHandle );
1222     hb_title_t * title = (hb_title_t *)
1223         hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
1225     hb_chapter_t * chapter;
1226     int64_t        duration = 0;
1227     for( int i = [fSrcChapterStartPopUp indexOfSelectedItem];
1228          i <= [fSrcChapterEndPopUp indexOfSelectedItem]; i++ )
1229     {
1230         chapter = (hb_chapter_t *) hb_list_item( title->list_chapter, i );
1231         duration += chapter->duration;
1232     }
1233     
1234     duration /= 90000; /* pts -> seconds */
1235     [fSrcDuration2Field setStringValue: [NSString stringWithFormat:
1236         @"%02lld:%02lld:%02lld", duration / 3600, ( duration / 60 ) % 60,
1237         duration % 60]];
1239     [self CalculateBitrate: sender];
1242 - (IBAction) FormatPopUpChanged: (id) sender
1244     NSString * string = [fDstFile2Field stringValue];
1245     int format = [fDstFormatPopUp indexOfSelectedItem];
1246     char * ext = NULL;
1248     /* Update the codecs popup */
1249     [fDstCodecsPopUp removeAllItems];
1250     switch( format )
1251     {
1252         case 0:
1253                                 /*Get Default MP4 File Extension*/
1254                                 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultMpegName"] > 0)
1255                                 {
1256                                 ext = "m4v";
1257                                 }
1258                                 else
1259                                 {
1260                                 ext = "mp4";
1261                                 }
1262             [fDstCodecsPopUp addItemWithTitle:
1263                 _( @"MPEG-4 Video / AAC Audio" )];
1264             [fDstCodecsPopUp addItemWithTitle:
1265                 _( @"AVC/H.264 Video / AAC Audio" )];
1266                         /* We enable the create chapters checkbox here since we are .mp4*/
1267                         [fCreateChapterMarkers setEnabled: YES];
1268                         break;
1269         case 1: 
1270             ext = "avi";
1271             [fDstCodecsPopUp addItemWithTitle:
1272                 _( @"MPEG-4 Video / MP3 Audio" )];
1273             [fDstCodecsPopUp addItemWithTitle:
1274                 _( @"MPEG-4 Video / AC-3 Audio" )];
1275             [fDstCodecsPopUp addItemWithTitle:
1276                 _( @"AVC/H.264 Video / MP3 Audio" )];
1277             [fDstCodecsPopUp addItemWithTitle:
1278                 _( @"AVC/H.264 Video / AC-3 Audio" )];
1279                         /* We disable the create chapters checkbox here since we are NOT .mp4 
1280                         and make sure it is unchecked*/
1281                         [fCreateChapterMarkers setEnabled: NO];
1282                         [fCreateChapterMarkers setState: NSOffState];
1283             break;
1284         case 2:
1285             ext = "ogm";
1286             [fDstCodecsPopUp addItemWithTitle:
1287                 _( @"MPEG-4 Video / Vorbis Audio" )];
1288             [fDstCodecsPopUp addItemWithTitle:
1289                 _( @"MPEG-4 Video / MP3 Audio" )];
1290             /* We disable the create chapters checkbox here since we are NOT .mp4 
1291                         and make sure it is unchecked*/
1292                         [fCreateChapterMarkers setEnabled: NO];
1293                         [fCreateChapterMarkers setState: NSOffState];
1294                         break;
1295     }
1296     [self CodecsPopUpChanged: NULL];
1298     /* Add/replace to the correct extension */
1299     if( [string characterAtIndex: [string length] - 4] == '.' )
1300     {
1301         [fDstFile2Field setStringValue: [NSString stringWithFormat:
1302             @"%@.%s", [string substringToIndex: [string length] - 4],
1303             ext]];
1304     }
1305     else
1306     {
1307         [fDstFile2Field setStringValue: [NSString stringWithFormat:
1308             @"%@.%s", string, ext]];
1309     }
1311         /* changing the format may mean that we can / can't offer mono or 6ch, */
1312         /* so call AudioTrackPopUpChanged for both audio tracks to update the mixdown popups */
1313         [self AudioTrackPopUpChanged: fAudLang1PopUp];
1314         [self AudioTrackPopUpChanged: fAudLang2PopUp];
1316         /* We call method method to change UI to reflect whether a preset is used or not*/
1317         [self CustomSettingUsed: sender];       
1318         
1321 - (IBAction) CodecsPopUpChanged: (id) sender
1323     int format = [fDstFormatPopUp indexOfSelectedItem];
1324     int codecs = [fDstCodecsPopUp indexOfSelectedItem];
1325         [fX264optView setHidden: YES];
1326         [fX264optViewTitleLabel setStringValue: @"Only Used With The x264 (H.264) Codec"];
1327         
1329     /* Update the encoder popup*/
1330     if( ( FormatSettings[format][codecs] & HB_VCODEC_X264 ) )
1331     {
1332         /* MPEG-4 -> H.264 */
1333         [fVidEncoderPopUp removeAllItems];
1334                 [fVidEncoderPopUp addItemWithTitle: @"x264 (h.264 Main)"];
1335                 [fVidEncoderPopUp addItemWithTitle: @"x264 (h.264 iPod)"];
1336         [fX264optView setHidden: NO];
1337                 [fX264optViewTitleLabel setStringValue: @""];
1338                 
1339     }
1340     else if( ( FormatSettings[format][codecs] & HB_VCODEC_FFMPEG ) )
1341     {
1342         /* H.264 -> MPEG-4 */
1343         [fVidEncoderPopUp removeAllItems];
1344         [fVidEncoderPopUp addItemWithTitle: @"FFmpeg"];
1345         [fVidEncoderPopUp addItemWithTitle: @"XviD"];
1346         [fVidEncoderPopUp selectItemAtIndex: 0];
1347                                 
1348     }
1350     if( FormatSettings[format][codecs] & HB_ACODEC_AC3 )
1351     {
1352         /* AC-3 pass-through: disable samplerate and bitrate */
1353         [fAudRatePopUp    setEnabled: NO];
1354         [fAudBitratePopUp setEnabled: NO];
1355     }
1356     else
1357     {
1358         [fAudRatePopUp    setEnabled: YES];
1359         [fAudBitratePopUp setEnabled: YES];
1360     }
1362         /* changing the codecs on offer may mean that we can / can't offer mono or 6ch, */
1363         /* so call AudioTrackPopUpChanged for both audio tracks to update the mixdown popups */
1364         [self AudioTrackPopUpChanged: fAudLang1PopUp];
1365         [self AudioTrackPopUpChanged: fAudLang2PopUp];
1367     [self CalculateBitrate: sender];
1368     /* We call method method to change UI to reflect whether a preset is used or not*/
1369         [self CustomSettingUsed: sender];
1372 - (IBAction) EncoderPopUpChanged: (id) sender
1374     
1375         /* Check to see if we need to modify the job pic values based on x264 (iPod) encoder selection */
1376     if ([fDstFormatPopUp indexOfSelectedItem] == 0 && [fDstCodecsPopUp indexOfSelectedItem] == 1 && [fVidEncoderPopUp indexOfSelectedItem] == 1)
1377     {
1378         hb_job_t * job = fTitle->job;
1379         job->pixel_ratio = 0 ;
1380         
1381                  if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultPicSizeAutoiPod"] > 0)
1382                  {
1383                  
1384                  if (job->width > 640)
1385                                 {
1386                                 job->width = 640;
1387                                 }
1388                  job->keep_ratio = 1;
1389                  hb_fix_aspect( job, HB_KEEP_WIDTH );
1390                  
1391                  }
1393         }
1394     
1395         [self CalculatePictureSizing: sender];
1396         /* We call method method to change UI to reflect whether a preset is used or not*/    
1397     [self CustomSettingUsed: sender];
1400 - (IBAction) SetEnabledStateOfAudioMixdownControls: (id) sender
1403     /* enable/disable the mixdown text and popupbutton for audio track 1 */
1404     [fAudTrack1MixPopUp setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES];
1405     [fAudTrack1MixLabel setTextColor: ([fAudLang1PopUp indexOfSelectedItem] == 0) ?
1406         [NSColor disabledControlTextColor] : [NSColor controlTextColor]];
1408     /* enable/disable the mixdown text and popupbutton for audio track 2 */
1409     [fAudTrack2MixPopUp setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES];
1410     [fAudTrack2MixLabel setTextColor: ([fAudLang2PopUp indexOfSelectedItem] == 0) ?
1411         [NSColor disabledControlTextColor] : [NSColor controlTextColor]];
1415 - (IBAction) AddAllAudioTracksToPopUp: (id) sender
1418     hb_list_t  * list  = hb_get_titles( fHandle );
1419     hb_title_t * title = (hb_title_t*)
1420         hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
1422         hb_audio_t * audio;
1424     [sender removeAllItems];
1425     [sender addItemWithTitle: _( @"None" )];
1426     for( int i = 0; i < hb_list_count( title->list_audio ); i++ )
1427     {
1428         audio = (hb_audio_t *) hb_list_item( title->list_audio, i );
1429         [[sender menu] addItemWithTitle:
1430             [NSString stringWithCString: audio->lang]
1431             action: NULL keyEquivalent: @""];
1432     }
1433     [sender selectItemAtIndex: 0];
1437 - (IBAction) SelectAudioTrackInPopUp: (id) sender searchPrefixString: (NSString *) searchPrefixString selectIndexIfNotFound: (int) selectIndexIfNotFound
1440     /* this method can be used to find a language, or a language-and-source-format combination, by passing in the appropriate string */
1441     /* e.g. to find the first French track, pass in an NSString * of "Francais" */
1442     /* e.g. to find the first English 5.1 AC3 track, pass in an NSString * of "English (AC3) (5.1 ch)" */
1443     /* if no matching track is found, then selectIndexIfNotFound is used to choose which track to select instead */
1444     
1445         if (searchPrefixString != NULL) 
1446         {
1448         for( int i = 0; i < [sender numberOfItems]; i++ )
1449         {
1450             /* Try to find the desired search string */
1451             if ([[[sender itemAtIndex: i] title] hasPrefix:searchPrefixString])
1452             {
1453                 [sender selectItemAtIndex: i];
1454                 return;
1455             }
1456         }
1457         /* couldn't find the string, so select the requested "search string not found" item */
1458         /* index of 0 means select the "none" item */
1459         /* index of 1 means select the first audio track */
1460         [sender selectItemAtIndex: selectIndexIfNotFound];
1461         }
1462     else
1463     {
1464         /* if no search string is provided, then select the selectIndexIfNotFound item */
1465         [sender selectItemAtIndex: selectIndexIfNotFound];
1466     }
1470 - (IBAction) AudioTrackPopUpChanged: (id) sender
1472     /* utility function to call AudioTrackPopUpChanged without passing in a mixdown-to-use */
1473     [self AudioTrackPopUpChanged: sender mixdownToUse: 0];
1476 - (IBAction) AudioTrackPopUpChanged: (id) sender mixdownToUse: (int) mixdownToUse
1479     /* make sure we have a selected title before continuing */
1480     if (fTitle == NULL) return;
1482     /* find out if audio track 1 or 2 was changed - this is passed to us in the tag of the sender */
1483     /* the sender will have been either fAudLang1PopUp (tag = 0) or fAudLang2PopUp (tag = 1) */
1484     int thisAudio = [sender tag];
1486     /* get the index of the selected audio */
1487     int thisAudioIndex = [sender indexOfSelectedItem] - 1;
1489     /* Handbrake can't currently cope with ripping the same source track twice */
1490     /* So, if this audio is also selected in the other audio track popup, set that popup's selection to "none" */
1491     /* get a reference to the two audio track popups */
1492     NSPopUpButton * thisAudioPopUp  = (thisAudio == 1 ? fAudLang2PopUp : fAudLang1PopUp);
1493     NSPopUpButton * otherAudioPopUp = (thisAudio == 1 ? fAudLang1PopUp : fAudLang2PopUp);
1494     /* if the same track is selected in the other audio popup, then select "none" in that popup */
1495     /* unless, of course, both are selected as "none!" */
1496     if ([thisAudioPopUp indexOfSelectedItem] != 0 && [thisAudioPopUp indexOfSelectedItem] == [otherAudioPopUp indexOfSelectedItem]) {
1497         [otherAudioPopUp selectItemAtIndex: 0];
1498         [self AudioTrackPopUpChanged: otherAudioPopUp];
1499     }
1501     /* pointer for the hb_audio_s struct we will use later on */
1502     hb_audio_t * audio;
1504     /* find out what the currently-selected output audio codec is */
1505     int format = [fDstFormatPopUp indexOfSelectedItem];
1506     int codecs = [fDstCodecsPopUp indexOfSelectedItem];
1507     int acodec = FormatSettings[format][codecs] & HB_ACODEC_MASK;
1509     /* pointer to this track's mixdown NSPopUpButton */
1510     NSTextField   * mixdownTextField;
1511     NSPopUpButton * mixdownPopUp;
1513     /* find our mixdown NSTextField and NSPopUpButton */
1514     if (thisAudio == 0)
1515     {
1516         mixdownTextField = fAudTrack1MixLabel;
1517         mixdownPopUp = fAudTrack1MixPopUp;
1518     }
1519     else
1520     {
1521         mixdownTextField = fAudTrack2MixLabel;
1522         mixdownPopUp = fAudTrack2MixPopUp;
1523     }
1525     /* delete the previous audio mixdown options */
1526     [mixdownPopUp removeAllItems];
1528     /* check if the audio mixdown controls need their enabled state changing */
1529     [self SetEnabledStateOfAudioMixdownControls: NULL];
1531     if (thisAudioIndex != -1)
1532     {
1534         /* get the audio */
1535         audio = (hb_audio_t *) hb_list_item( fTitle->list_audio, thisAudioIndex );
1536         if (audio != NULL)
1537         {
1539             /* find out if our selected output audio codec supports mono and / or 6ch */
1540             /* we also check for an input codec of AC3 or DCA,
1541                as they are the only libraries able to do the mixdown to mono / conversion to 6-ch */
1542             /* audioCodecsSupportMono and audioCodecsSupport6Ch are the same for now,
1543                but this may change in the future, so they are separated for flexibility */
1544             int audioCodecsSupportMono = ((audio->codec == HB_ACODEC_AC3 ||
1545                 audio->codec == HB_ACODEC_DCA) && acodec == HB_ACODEC_FAAC);
1546             int audioCodecsSupport6Ch =  ((audio->codec == HB_ACODEC_AC3 ||
1547                 audio->codec == HB_ACODEC_DCA) && acodec == HB_ACODEC_FAAC);
1549             /* check for AC-3 passthru */
1550             if (audio->codec == HB_ACODEC_AC3 && acodec == HB_ACODEC_AC3)
1551             {
1552                     [[mixdownPopUp menu] addItemWithTitle:
1553                         [NSString stringWithCString: "AC3 Passthru"]
1554                         action: NULL keyEquivalent: @""];
1555             }
1556             else
1557             {
1559                 /* add the appropriate audio mixdown menuitems to the popupbutton */
1560                 /* in each case, we set the new menuitem's tag to be the amixdown value for that mixdown,
1561                    so that we can reference the mixdown later */
1563                 /* keep a track of the min and max mixdowns we used, so we can select the best match later */
1564                 int minMixdownUsed = 0;
1565                 int maxMixdownUsed = 0;
1566                 
1567                 /* get the input channel layout without any lfe channels */
1568                 int layout = audio->input_channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
1570                 /* do we want to add a mono option? */
1571                 if (audioCodecsSupportMono == 1) {
1572                     id<NSMenuItem> menuItem = [[mixdownPopUp menu] addItemWithTitle:
1573                         [NSString stringWithCString: hb_audio_mixdowns[0].human_readable_name]
1574                         action: NULL keyEquivalent: @""];
1575                     [menuItem setTag: hb_audio_mixdowns[0].amixdown];
1576                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[0].amixdown;
1577                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[0].amixdown);
1578                 }
1580                 /* do we want to add a stereo option? */
1581                 /* offer stereo if we have a mono source and non-mono-supporting codecs, as otherwise we won't have a mixdown at all */
1582                 /* also offer stereo if we have a stereo-or-better source */
1583                 if ((layout == HB_INPUT_CH_LAYOUT_MONO && audioCodecsSupportMono == 0) || layout >= HB_INPUT_CH_LAYOUT_STEREO) {
1584                     id<NSMenuItem> menuItem = [[mixdownPopUp menu] addItemWithTitle:
1585                         [NSString stringWithCString: hb_audio_mixdowns[1].human_readable_name]
1586                         action: NULL keyEquivalent: @""];
1587                     [menuItem setTag: hb_audio_mixdowns[1].amixdown];
1588                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[1].amixdown;
1589                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[1].amixdown);
1590                 }
1592                 /* do we want to add a dolby surround (DPL1) option? */
1593                 if (layout == HB_INPUT_CH_LAYOUT_3F1R || layout == HB_INPUT_CH_LAYOUT_3F2R || layout == HB_INPUT_CH_LAYOUT_DOLBY) {
1594                     id<NSMenuItem> menuItem = [[mixdownPopUp menu] addItemWithTitle:
1595                         [NSString stringWithCString: hb_audio_mixdowns[2].human_readable_name]
1596                         action: NULL keyEquivalent: @""];
1597                     [menuItem setTag: hb_audio_mixdowns[2].amixdown];
1598                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[2].amixdown;
1599                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[2].amixdown);
1600                 }
1602                 /* do we want to add a dolby pro logic 2 (DPL2) option? */
1603                 if (layout == HB_INPUT_CH_LAYOUT_3F2R) {
1604                     id<NSMenuItem> menuItem = [[mixdownPopUp menu] addItemWithTitle:
1605                         [NSString stringWithCString: hb_audio_mixdowns[3].human_readable_name]
1606                         action: NULL keyEquivalent: @""];
1607                     [menuItem setTag: hb_audio_mixdowns[3].amixdown];
1608                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[3].amixdown;
1609                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[3].amixdown);
1610                 }
1612                 /* do we want to add a 6-channel discrete option? */
1613                 if (audioCodecsSupport6Ch == 1 && layout == HB_INPUT_CH_LAYOUT_3F2R && (audio->input_channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE)) {
1614                     id<NSMenuItem> menuItem = [[mixdownPopUp menu] addItemWithTitle:
1615                         [NSString stringWithCString: hb_audio_mixdowns[4].human_readable_name]
1616                         action: NULL keyEquivalent: @""];
1617                     [menuItem setTag: hb_audio_mixdowns[4].amixdown];
1618                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[4].amixdown;
1619                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[4].amixdown);
1620                 }
1622                 /* auto-select the best mixdown based on our saved mixdown preference */
1623                 
1624                 /* for now, this is hard-coded to a "best" mixdown of HB_AMIXDOWN_DOLBYPLII */
1625                 /* ultimately this should be a prefs option */
1626                 int useMixdown;
1627                 
1628                 /* if we passed in a mixdown to use - in order to load a preset - then try and use it */
1629                 if (mixdownToUse > 0)
1630                 {
1631                     useMixdown = mixdownToUse;
1632                 }
1633                 else
1634                 {
1635                     useMixdown = HB_AMIXDOWN_DOLBYPLII;
1636                 }
1637                 
1638                 /* if useMixdown > maxMixdownUsed, then use maxMixdownUsed */
1639                 if (useMixdown > maxMixdownUsed) useMixdown = maxMixdownUsed;
1641                 /* if useMixdown < minMixdownUsed, then use minMixdownUsed */
1642                 if (useMixdown < minMixdownUsed) useMixdown = minMixdownUsed;
1644                 /* select the (possibly-amended) preferred mixdown */
1645                 [mixdownPopUp selectItemWithTag: useMixdown];
1646                                 
1647                                 /* lets call the AudioTrackMixdownChanged method here to determine appropriate bitrates, etc. */
1648                 [self AudioTrackMixdownChanged: NULL];
1649             }
1651         }
1652         
1653     }
1655         /* see if the new audio track choice will change the bitrate we need */
1656     [self CalculateBitrate: sender];    
1659 - (IBAction) AudioTrackMixdownChanged: (id) sender
1662     /* find out what the currently-selected output audio codec is */
1663     int format = [fDstFormatPopUp indexOfSelectedItem];
1664     int codecs = [fDstCodecsPopUp indexOfSelectedItem];
1665     int acodec = FormatSettings[format][codecs] & HB_ACODEC_MASK;
1666     
1667     /* storage variable for the min and max bitrate allowed for this codec */
1668     int minbitrate;
1669     int maxbitrate;
1670     
1671     switch( acodec )
1672     {
1673         case HB_ACODEC_FAAC:
1674             /* check if we have a 6ch discrete conversion in either audio track */
1675             if ([[fAudTrack1MixPopUp selectedItem] tag] == HB_AMIXDOWN_6CH || [[fAudTrack2MixPopUp selectedItem] tag] == HB_AMIXDOWN_6CH)
1676             {
1677                 /* FAAC is happy using our min bitrate of 32 kbps, even for 6ch */
1678                 minbitrate = 32;
1679                 /* If either mixdown popup includes 6-channel discrete, then allow up to 384 kbps */
1680                 maxbitrate = 384;
1681                 break;
1682             }
1683             else
1684             {
1685                 /* FAAC is happy using our min bitrate of 32 kbps for stereo or mono */
1686                 minbitrate = 32;
1687                 /* FAAC won't honour anything more than 160 for stereo, so let's not offer it */
1688                 /* note: haven't dealt with mono separately here, FAAC will just use the max it can */
1689                 maxbitrate = 160;
1690                 break;
1691             }
1693         case HB_ACODEC_LAME:
1694             /* Lame is happy using our min bitrate of 32 kbps */
1695             minbitrate = 32;
1696             /* Lame won't encode if the bitrate is higher than 320 kbps */
1697             maxbitrate = 320;
1698             break;
1700         case HB_ACODEC_VORBIS:
1701             /* Vorbis causes a crash if we use a bitrate below 48 kbps */
1702             minbitrate = 48;
1703             /* Vorbis can cope with 384 kbps quite happily, even for stereo */
1704             maxbitrate = 384;
1705             break;
1707         default:
1708             /* AC3 passthru disables the bitrate dropdown anyway, so we might as well just use the min and max bitrate */
1709             minbitrate = 32;
1710             maxbitrate = 384;
1711         
1712     }
1714     [fAudBitratePopUp removeAllItems];
1716     for( int i = 0; i < hb_audio_bitrates_count; i++ )
1717     {
1718         if (hb_audio_bitrates[i].rate >= minbitrate && hb_audio_bitrates[i].rate <= maxbitrate)
1719         {
1720             /* add a new menuitem for this bitrate */
1721             id<NSMenuItem> menuItem = [[fAudBitratePopUp menu] addItemWithTitle:
1722                 [NSString stringWithCString: hb_audio_bitrates[i].string]
1723                 action: NULL keyEquivalent: @""];
1724             /* set its tag to be the actual bitrate as an integer, so we can retrieve it later */
1725             [menuItem setTag: hb_audio_bitrates[i].rate];
1726         }
1727     }
1729     /* select the default bitrate (but use 384 for 6-ch AAC) */
1730     if ([[fAudTrack1MixPopUp selectedItem] tag] == HB_AMIXDOWN_6CH || [[fAudTrack2MixPopUp selectedItem] tag] == HB_AMIXDOWN_6CH)
1731     {
1732         [fAudBitratePopUp selectItemWithTag: 384];
1733     }
1734     else
1735     {
1736         [fAudBitratePopUp selectItemWithTag: hb_audio_bitrates[hb_audio_bitrates_default].rate];
1737     }
1740 /* lets set the picture size back to the max from right after title scan
1741    Lets use an IBAction here as down the road we could always use a checkbox
1742    in the gui to easily take the user back to max. Remember, the compiler
1743    resolves IBActions down to -(void) during compile anyway */
1744 - (IBAction) RevertPictureSizeToMax: (id) sender
1746          hb_job_t * job = fTitle->job;
1747         /* We use the output picture width and height
1748         as calculated from libhb right after title is set
1749         in TitlePopUpChanged */
1750         job->width = PicOrigOutputWidth;
1751         job->height = PicOrigOutputHeight;
1754     
1755         [self CalculatePictureSizing: sender];
1756         /* We call method method to change UI to reflect whether a preset is used or not*/    
1757     [self CustomSettingUsed: sender];
1761 /* Get and Display Current Pic Settings in main window */
1762 - (IBAction) CalculatePictureSizing: (id) sender
1764         
1766         [fPicSettingWidth setStringValue: [NSString stringWithFormat:
1767                 @"%d", fTitle->job->width]];
1768         [fPicSettingHeight setStringValue: [NSString stringWithFormat:
1769                 @"%d", fTitle->job->height]];
1770         [fPicSettingARkeep setStringValue: [NSString stringWithFormat:
1771                 @"%d", fTitle->job->keep_ratio]];                
1772         [fPicSettingDeinterlace setStringValue: [NSString stringWithFormat:
1773                 @"%d", fTitle->job->deinterlace]];
1774         [fPicSettingPAR setStringValue: [NSString stringWithFormat:
1775                 @"%d", fTitle->job->pixel_ratio]];
1776                 
1777         if (fTitle->job->pixel_ratio == 1)
1778         {
1779         int titlewidth = fTitle->width-fTitle->job->crop[2]-fTitle->job->crop[3];
1780         int arpwidth = fTitle->job->pixel_aspect_width;
1781         int arpheight = fTitle->job->pixel_aspect_height;
1782         int displayparwidth = titlewidth * arpwidth / arpheight;
1783         int displayparheight = fTitle->height-fTitle->job->crop[0]-fTitle->job->crop[1];
1784         [fPicSettingHeight setStringValue: [NSString stringWithFormat:
1785                 @"%d", displayparheight]];
1786         [fPicLabelPAROutp setStringValue: @"Anamorphic Output:"];
1787         [fPicLabelPAROutputX setStringValue: @"x"];
1788     [fPicSettingPARWidth setStringValue: [NSString stringWithFormat:
1789         @"%d", displayparwidth]];
1790         [fPicSettingPARHeight setStringValue: [NSString stringWithFormat:
1791         @"%d", displayparheight]];
1793         fTitle->job->keep_ratio = 0;
1794         }
1795         else
1796         {
1797         [fPicLabelPAROutp setStringValue: @""];
1798         [fPicLabelPAROutputX setStringValue: @""];
1799         [fPicSettingPARWidth setStringValue: @""];
1800         [fPicSettingPARHeight setStringValue:  @""];
1801         }
1802                 
1803         /* Set ON/Off values for the deinterlace/keep aspect ratio according to boolean */      
1804         if (fTitle->job->keep_ratio > 0)
1805                 {
1806                 [fPicSettingARkeepDsply setStringValue: @"On"];
1807         }
1808                 else
1809                 {
1810                 [fPicSettingARkeepDsply setStringValue: @"Off"];
1811                 }       
1812         if (fTitle->job->deinterlace > 0)
1813                 {
1814                 [fPicSettingDeinterlaceDsply setStringValue: @"On"];
1815         }
1816                 else
1817                 {
1818                 [fPicSettingDeinterlaceDsply setStringValue: @"Off"];
1819                 }
1820         if (fTitle->job->pixel_ratio > 0)
1821                 {
1822                 [fPicSettingPARDsply setStringValue: @"On"];
1823         }
1824                 else
1825                 {
1826                 [fPicSettingPARDsply setStringValue: @"Off"];
1827                 }       
1828         /* below will trigger the preset, if selected, to be
1829         changed to "Custom". Lets comment out for now until
1830         we figure out a way to determine if the picture values
1831         changed modify the preset values */     
1832         //[self CustomSettingUsed: sender];
1835 - (IBAction) CalculateBitrate: (id) sender
1837     if( !fHandle || [fVidQualityMatrix selectedRow] != 0 )
1838     {
1839         return;
1840     }
1842     hb_list_t  * list  = hb_get_titles( fHandle );
1843     hb_title_t * title = (hb_title_t *) hb_list_item( list,
1844             [fSrcTitlePopUp indexOfSelectedItem] );
1845     hb_job_t * job = title->job;
1847     [self PrepareJob];
1849     [fVidBitrateField setIntValue: hb_calc_bitrate( job,
1850             [fVidTargetSizeField intValue] )];
1851                         
1852                         
1855 /* Method to determine if we should change the UI
1856 To reflect whether or not a Preset is being used or if
1857 the user is using "Custom" settings by determining the sender*/
1858 - (IBAction) CustomSettingUsed: (id) sender
1860         if ([sender stringValue] != NULL)
1861         {
1862                 /* Deselect the currently selected Preset if there is one*/
1863                 [tableView deselectRow:[tableView selectedRow]];
1864                 /* Change UI to show "Custom" settings are being used */
1865                 [fPresetSelectedDisplay setStringValue: @"Custom"];
1866                 
1867                 curUserPresetChosenNum = nil;
1868                 /* If we have MP4, AVC H.264 and x264 Main then we look to see
1869                         if there are any x264 options from the preferences to use */
1870                 if ([fDstFormatPopUp indexOfSelectedItem] == 0 && [fDstCodecsPopUp indexOfSelectedItem] == 1)
1871                 {
1872                     /* Lets check to see there is a specified string in the prefs, and use that if need be */
1873                         if ([[NSUserDefaults standardUserDefaults] stringForKey:@"DefAdvancedx264Flags"] != @"")
1874                         {
1875                                 [fDisplayX264Options setStringValue: [NSString stringWithFormat:[[NSUserDefaults standardUserDefaults] stringForKey:@"DefAdvancedx264Flags"]]];
1876                         }
1877                 }
1878                 else
1879                 {
1880                         /* Empty the field to display custom x264 preset options*/
1881                         [fDisplayX264Options setStringValue: @""];
1882                 }
1883                 
1884         }
1885         [self X264AdvancedOptionsSet:NULL];
1888 - (IBAction) X264AdvancedOptionsSet: (id) sender
1890     /*Set opt widget values here*/
1891     
1892     /*B-Frames fX264optBframesPopUp*/
1893     int i;
1894     [fX264optBframesPopUp removeAllItems];
1895     [fX264optBframesPopUp addItemWithTitle:@"Default (0)"];
1896     for (i=0; i<17;i++)
1897     {
1898         [fX264optBframesPopUp addItemWithTitle:[NSString stringWithFormat:@"%d",i]];
1899     }
1900     
1901     /*Reference Frames fX264optRefPopUp*/
1902     [fX264optRefPopUp removeAllItems];
1903     [fX264optRefPopUp addItemWithTitle:@"Default (1)"];
1904     for (i=0; i<17;i++)
1905     {
1906         [fX264optRefPopUp addItemWithTitle:[NSString stringWithFormat:@"%d",i]];
1907     }
1908     
1909     /*No Fast P-Skip fX264optNfpskipPopUp BOOLEAN*/
1910     [fX264optNfpskipPopUp removeAllItems];
1911     [fX264optNfpskipPopUp addItemWithTitle:@"Default (No)"];
1912     for (i=0; i<2;i++)
1913     {
1914         if (i==0)
1915         {
1916             [fX264optNfpskipPopUp addItemWithTitle:[NSString stringWithFormat:@"No"]];
1917         }
1918         else
1919         {
1920             [fX264optNfpskipPopUp addItemWithTitle:[NSString stringWithFormat:@"Yes"]];
1921         }
1922     }
1923     
1924     /*No Dict Decimate fX264optNodctdcmtPopUp BOOLEAN*/
1925     [fX264optNodctdcmtPopUp removeAllItems];
1926     [fX264optNodctdcmtPopUp addItemWithTitle:@"Default (No)"];
1927     for (i=0; i<2;i++)
1928     {
1929         if (i==0)
1930         {
1931             [fX264optNodctdcmtPopUp addItemWithTitle:[NSString stringWithFormat:@"No"]];
1932         }
1933         else
1934         {
1935             [fX264optNodctdcmtPopUp addItemWithTitle:[NSString stringWithFormat:@"Yes"]];
1936         }
1937     }
1938     
1939     /*Sub Me fX264optSubmePopUp*/
1940     [fX264optSubmePopUp removeAllItems];
1941     [fX264optSubmePopUp addItemWithTitle:@"Default (4)"];
1942     for (i=0; i<8;i++)
1943     {
1944         [fX264optSubmePopUp addItemWithTitle:[NSString stringWithFormat:@"%d",i]];
1945     }
1946     
1947     /*Trellis fX264optTrellisPopUp*/
1948     [fX264optTrellisPopUp removeAllItems];
1949     [fX264optTrellisPopUp addItemWithTitle:@"Default (0)"];
1950     for (i=0; i<3;i++)
1951     {
1952         [fX264optTrellisPopUp addItemWithTitle:[NSString stringWithFormat:@"%d",i]];
1953     }
1954     
1955     /*Mixed-references fX264optMixedRefsPopUp BOOLEAN*/
1956     [fX264optMixedRefsPopUp removeAllItems];
1957     [fX264optMixedRefsPopUp addItemWithTitle:@"Default (No)"];
1958     for (i=0; i<2;i++)
1959     {
1960         if (i==0)
1961         {
1962             [fX264optMixedRefsPopUp addItemWithTitle:[NSString stringWithFormat:@"No"]];
1963         }
1964         else
1965         {
1966             [fX264optMixedRefsPopUp addItemWithTitle:[NSString stringWithFormat:@"Yes"]];
1967         }
1968     }
1969     
1970     /*Motion Estimation fX264optMotionEstPopUp*/
1971     [fX264optMotionEstPopUp removeAllItems];
1972     [fX264optMotionEstPopUp addItemWithTitle:@"Default (Hexagon)"];
1973     [fX264optMotionEstPopUp addItemWithTitle:@"Diamond"];
1974     [fX264optMotionEstPopUp addItemWithTitle:@"Hexagon"];
1975     [fX264optMotionEstPopUp addItemWithTitle:@"Uneven Multi-Hexagon"];
1976     [fX264optMotionEstPopUp addItemWithTitle:@"Exhaustive"];
1977     
1978     /*Motion Estimation range fX264optMERangePopUp*/
1979     [fX264optMERangePopUp removeAllItems];
1980     [fX264optMERangePopUp addItemWithTitle:@"Default (16)"];
1981     for (i=4; i<65;i++)
1982     {
1983         [fX264optMERangePopUp addItemWithTitle:[NSString stringWithFormat:@"%d",i]];
1984     }
1985     
1986     /*Weighted B-Frame Prediction fX264optWeightBPopUp BOOLEAN*/
1987     [fX264optWeightBPopUp removeAllItems];
1988     [fX264optWeightBPopUp addItemWithTitle:@"Default (No)"];
1989     for (i=0; i<2;i++)
1990     {
1991         if (i==0)
1992         {
1993             [fX264optWeightBPopUp addItemWithTitle:[NSString stringWithFormat:@"No"]];
1994         }
1995         else
1996         {
1997             [fX264optWeightBPopUp addItemWithTitle:[NSString stringWithFormat:@"Yes"]];
1998         }
1999     }
2000     
2001     /*B-Frame Rate Distortion Optimization fX264optBRDOPopUp BOOLEAN*/
2002     [fX264optBRDOPopUp removeAllItems];
2003     [fX264optBRDOPopUp addItemWithTitle:@"Default (No)"];
2004     for (i=0; i<2;i++)
2005     {
2006         if (i==0)
2007         {
2008             [fX264optBRDOPopUp addItemWithTitle:[NSString stringWithFormat:@"No"]];
2009         }
2010         else
2011         {
2012             [fX264optBRDOPopUp addItemWithTitle:[NSString stringWithFormat:@"Yes"]];
2013         }
2014     }
2015     
2016     /*B-frame Pyramids fX264optBPyramidPopUp BOOLEAN*/
2017     [fX264optBPyramidPopUp removeAllItems];
2018     [fX264optBPyramidPopUp addItemWithTitle:@"Default (No)"];
2019     for (i=0; i<2;i++)
2020     {
2021         if (i==0)
2022         {
2023             [fX264optBPyramidPopUp addItemWithTitle:[NSString stringWithFormat:@"No"]];
2024         }
2025         else
2026         {
2027             [fX264optBPyramidPopUp addItemWithTitle:[NSString stringWithFormat:@"Yes"]];
2028         }
2029     }
2030     
2031     /* Standardize the option string */
2032     [self X264AdvancedOptionsStandardizeOptString: NULL];
2033     /* Set Current GUI Settings based on newly standardized string */
2034     [self X264AdvancedOptionsSetCurrentSettings: NULL];
2037 - (IBAction) X264AdvancedOptionsStandardizeOptString: (id) sender
2039     /* Set widgets depending on the opt string in field */
2040     NSString * thisOpt; // The separated option such as "bframes=3"
2041     NSString * optName = @""; // The option name such as "bframes"
2042     NSString * optValue = @"";// The option value such as "3"
2043     NSString * changedOptString = @"";
2044     NSArray *currentOptsArray;
2046     /*First, we get an opt string to process */
2047     NSString *currentOptString = [fDisplayX264Options stringValue];
2049     /*verify there is an opt string to process */
2050     NSRange currentOptRange = [currentOptString rangeOfString:@"="];
2051     if (currentOptRange.location != NSNotFound)
2052     {
2053         /*Put individual options into an array based on the ":" separator for processing, result is "<opt>=<value>"*/
2054         currentOptsArray = [currentOptString componentsSeparatedByString:@":"];
2056         /*iterate through the array and get <opts> and <values*/
2057         //NSEnumerator * enumerator = [currentOptsArray objectEnumerator];
2058         int loopcounter;
2059         int currentOptsArrayCount = [currentOptsArray count];
2060         for (loopcounter = 0; loopcounter < currentOptsArrayCount; loopcounter++)
2061         {
2062             thisOpt = [currentOptsArray objectAtIndex:loopcounter];
2063             
2064             NSRange splitOptRange = [thisOpt rangeOfString:@"="];
2065             if (splitOptRange.location != NSNotFound)
2066             {
2067                 optName = [thisOpt substringToIndex:splitOptRange.location];
2068                 optValue = [thisOpt substringFromIndex:splitOptRange.location + 1];
2069                 
2070                 /* Standardize the names here depending on whats in the string */
2071                 optName = [self X264AdvancedOptionsStandardizeOptNames:optName];
2072                 thisOpt = [NSString stringWithFormat:@"%@=%@",optName,optValue];        
2073             }
2074             else // No value given so we use a default of "1"
2075             {
2076                 optName = thisOpt;
2077                 /* Standardize the names here depending on whats in the string */
2078                 optName = [self X264AdvancedOptionsStandardizeOptNames:optName];
2079                 thisOpt = [NSString stringWithFormat:@"%@=%d",optName,1];
2080             }
2081             
2082             /* Construct New String for opts here */
2083             if ([thisOpt isEqualToString:@""])
2084             {
2085                 changedOptString = [NSString stringWithFormat:@"%@%@",changedOptString,thisOpt];
2086             }
2087             else
2088             {
2089                 if ([changedOptString isEqualToString:@""])
2090                 {
2091                     changedOptString = [NSString stringWithFormat:@"%@",thisOpt];
2092                 }
2093                 else
2094                 {
2095                     changedOptString = [NSString stringWithFormat:@"%@:%@",changedOptString,thisOpt];
2096                 }
2097             }
2098         }
2099     }
2100     
2101     /* Change the option string to reflect the new standardized option string */
2102     [fDisplayX264Options setStringValue:[NSString stringWithFormat:changedOptString]];
2105 - (NSString *) X264AdvancedOptionsStandardizeOptNames:(NSString *) cleanOptNameString
2107     if ([cleanOptNameString isEqualToString:@"ref"] || [cleanOptNameString isEqualToString:@"frameref"])
2108     {
2109         cleanOptNameString = @"ref";
2110     }
2111     
2112     /*No Fast PSkip nofast_pskip*/
2113     if ([cleanOptNameString isEqualToString:@"no-fast-pskip"] || [cleanOptNameString isEqualToString:@"no_fast_pskip"] || [cleanOptNameString isEqualToString:@"nofast_pskip"])
2114     {
2115         cleanOptNameString = @"no-fast-pskip";
2116     }
2117     
2118     /*No Dict Decimate*/
2119     if ([cleanOptNameString isEqualToString:@"no-dct-decimate"] || [cleanOptNameString isEqualToString:@"no_dct_decimate"] || [cleanOptNameString isEqualToString:@"nodct_decimate"])
2120     {
2121         cleanOptNameString = @"no-dct-decimate";
2122     }
2123     
2124     /*Subme*/
2125     if ([cleanOptNameString isEqualToString:@"subme"])
2126     {
2127         cleanOptNameString = @"subq";
2128     }
2129     
2130     /*ME Range*/
2131     if ([cleanOptNameString isEqualToString:@"me-range"] || [cleanOptNameString isEqualToString:@"me_range"])
2132         cleanOptNameString = @"merange";
2133     
2134     /*WeightB*/
2135     if ([cleanOptNameString isEqualToString:@"weight-b"] || [cleanOptNameString isEqualToString:@"weight_b"])
2136     {
2137         cleanOptNameString = @"weightb";
2138     }
2139     
2140     /*BRDO*/
2141     if ([cleanOptNameString isEqualToString:@"b-rdo"] || [cleanOptNameString isEqualToString:@"b_rdo"])
2142     {
2143         cleanOptNameString = @"brdo";
2144     }
2145     
2146     /*B Pyramid*/
2147     if ([cleanOptNameString isEqualToString:@"b_pyramid"])
2148     {
2149         cleanOptNameString = @"b-pyramid";
2150     }
2151     
2152     return cleanOptNameString;  
2155 - (IBAction) X264AdvancedOptionsSetCurrentSettings: (id) sender
2157     /* Set widgets depending on the opt string in field */
2158     NSString * thisOpt; // The separated option such as "bframes=3"
2159     NSString * optName = @""; // The option name such as "bframes"
2160     NSString * optValue = @"";// The option value such as "3"
2161     NSArray *currentOptsArray;
2162     
2163     /*First, we get an opt string to process */
2164     //NSString *currentOptString = @"bframes=3:ref=1:subme=5:me=umh:no-fast-pskip=1:no-dct-decimate=1:trellis=2";
2165     NSString *currentOptString = [fDisplayX264Options stringValue];
2166     
2167     /*verify there is an opt string to process */
2168     NSRange currentOptRange = [currentOptString rangeOfString:@"="];
2169     if (currentOptRange.location != NSNotFound)
2170     {
2171         /* lets clean the opt string here to standardize any names*/
2172         /*Put individual options into an array based on the ":" separator for processing, result is "<opt>=<value>"*/
2173         currentOptsArray = [currentOptString componentsSeparatedByString:@":"];
2174         
2175         /*iterate through the array and get <opts> and <values*/
2176         //NSEnumerator * enumerator = [currentOptsArray objectEnumerator];
2177         int loopcounter;
2178         int currentOptsArrayCount = [currentOptsArray count];
2179         
2180         /*iterate through the array and get <opts> and <values*/
2181         for (loopcounter = 0; loopcounter < currentOptsArrayCount; loopcounter++)
2182         {
2183             thisOpt = [currentOptsArray objectAtIndex:loopcounter];
2184             NSRange splitOptRange = [thisOpt rangeOfString:@"="];
2185             
2186             if (splitOptRange.location != NSNotFound)
2187             {
2188                 optName = [thisOpt substringToIndex:splitOptRange.location];
2189                 optValue = [thisOpt substringFromIndex:splitOptRange.location + 1];
2190            
2191                 /*Run through the available widgets for x264 opts and set them, as you add widgets, 
2192                 they need to be added here. This should be moved to its own method probably*/
2193            
2194                 /*bframes NSPopUpButton*/
2195                 if ([optName isEqualToString:@"bframes"])
2196                 {
2197                     [fX264optBframesPopUp selectItemAtIndex:[optValue intValue]+1];
2198                 }
2199                 /*ref NSPopUpButton*/
2200                 if ([optName isEqualToString:@"ref"])
2201                 {
2202                    [fX264optRefPopUp selectItemAtIndex:[optValue intValue]+1];
2203                 }
2204                 /*No Fast PSkip NSPopUpButton*/
2205                 if ([optName isEqualToString:@"no-fast-pskip"])
2206                 {
2207                     [fX264optNfpskipPopUp selectItemAtIndex:[optValue intValue]+1];
2208                 }
2209                 /*No Dict Decimate NSPopUpButton*/
2210                 if ([optName isEqualToString:@"no-dct-decimate"])
2211                 {
2212                     [fX264optNodctdcmtPopUp selectItemAtIndex:[optValue intValue]+1];
2213                 }
2214                 /*Sub Me NSPopUpButton*/
2215                 if ([optName isEqualToString:@"subq"])
2216                 {
2217                     [fX264optSubmePopUp selectItemAtIndex:[optValue intValue]+1];
2218                 }
2219                 /*Trellis NSPopUpButton*/
2220                 if ([optName isEqualToString:@"trellis"])
2221                 {
2222                     [fX264optTrellisPopUp selectItemAtIndex:[optValue intValue]+1];
2223                 }
2224                 /*Mixed Refs NSPopUpButton*/
2225                 if ([optName isEqualToString:@"mixed-refs"])
2226                 {
2227                     [fX264optMixedRefsPopUp selectItemAtIndex:[optValue intValue]+1];
2228                 }
2229                 /*Motion Estimation NSPopUpButton*/
2230                 if ([optName isEqualToString:@"me"])
2231                 {
2232                     if ([optValue isEqualToString:@"dia"])
2233                         [fX264optMotionEstPopUp selectItemAtIndex:1];
2234                     else if ([optValue isEqualToString:@"hex"])
2235                         [fX264optMotionEstPopUp selectItemAtIndex:2];
2236                     else if ([optValue isEqualToString:@"umh"])
2237                         [fX264optMotionEstPopUp selectItemAtIndex:3];
2238                     else if ([optValue isEqualToString:@"esa"])
2239                         [fX264optMotionEstPopUp selectItemAtIndex:4];                        
2240                 }
2241                 /*ME Range NSPopUpButton*/
2242                 if ([optName isEqualToString:@"merange"])
2243                 {
2244                     [fX264optMERangePopUp selectItemAtIndex:[optValue intValue]-3];
2245                 }
2246                 /*Weighted B-Frames NSPopUpButton*/
2247                 if ([optName isEqualToString:@"weightb"])
2248                 {
2249                     [fX264optWeightBPopUp selectItemAtIndex:[optValue intValue]+1];
2250                 }
2251                 /*BRDO NSPopUpButton*/
2252                 if ([optName isEqualToString:@"brdo"])
2253                 {
2254                     [fX264optBRDOPopUp selectItemAtIndex:[optValue intValue]+1];
2255                 }
2256                 /*B Pyramid NSPopUpButton*/
2257                 if ([optName isEqualToString:@"b-pyramid"])
2258                 {
2259                     [fX264optBPyramidPopUp selectItemAtIndex:[optValue intValue]+1];
2260                 }
2261                 
2262                                                 
2263             }
2264         }
2265     }
2268 - (IBAction) X264AdvancedOptionsChanged: (id) sender
2270     /*Determine which outlet is being used and set optName to process accordingly */
2271     NSString * optNameToChange = @""; // The option name such as "bframes"
2273     if (sender == fX264optBframesPopUp)
2274     {
2275         optNameToChange = @"bframes";
2276     }
2277     if (sender == fX264optRefPopUp)
2278     {
2279         optNameToChange = @"ref";
2280     }
2281     if (sender == fX264optNfpskipPopUp)
2282     {
2283         optNameToChange = @"no-fast-pskip";
2284     }
2285     if (sender == fX264optNodctdcmtPopUp)
2286     {
2287         optNameToChange = @"no-dct-decimate";
2288     }
2289     if (sender == fX264optSubmePopUp)
2290     {
2291         optNameToChange = @"subq";
2292     }
2293     if (sender == fX264optTrellisPopUp)
2294     {
2295         optNameToChange = @"trellis";
2296     }
2297     if (sender == fX264optMixedRefsPopUp)
2298     {
2299         optNameToChange = @"mixed-refs";
2300     }
2301     if (sender == fX264optMotionEstPopUp)
2302     {
2303         optNameToChange = @"me";
2304     }
2305     if (sender == fX264optMERangePopUp)
2306     {
2307         optNameToChange = @"merange";
2308     }
2309     if (sender == fX264optWeightBPopUp)
2310     {
2311         optNameToChange = @"weightb";
2312     }
2313     if (sender == fX264optBRDOPopUp)
2314     {
2315         optNameToChange = @"brdo";
2316     }
2317     if (sender == fX264optBPyramidPopUp)
2318     {
2319         optNameToChange = @"b-pyramid";
2320     }
2321     
2322     /* Set widgets depending on the opt string in field */
2323     NSString * thisOpt; // The separated option such as "bframes=3"
2324     NSString * optName = @""; // The option name such as "bframes"
2325     NSString * optValue = @"";// The option value such as "3"
2326     NSArray *currentOptsArray;
2328     /*First, we get an opt string to process */
2329     //EXAMPLE: NSString *currentOptString = @"bframes=3:ref=1:subme=5:me=umh:no-fast-pskip=1:no-dct-decimate=1:trellis=2";
2330     NSString *currentOptString = [fDisplayX264Options stringValue];
2332     /*verify there is an occurrence of the opt specified by the sender to change */
2333     /*take care of any multi-value opt names here. This is extremely kludgy, but test for functionality
2334     and worry about pretty later */
2335         
2336         /*First, we create a pattern to check for ":"optNameToChange"=" to modify the option if the name falls after
2337         the first character of the opt string (hence the ":") */
2338         NSString *checkOptNameToChange = [NSString stringWithFormat:@":%@=",optNameToChange];
2339     NSRange currentOptRange = [currentOptString rangeOfString:checkOptNameToChange];
2340         /*Then we create a pattern to check for "<beginning of line>"optNameToChange"=" to modify the option to
2341         see if the name falls at the beginning of the line, where we would not have the ":" as a pattern to test against*/
2342         NSString *checkOptNameToChangeBeginning = [NSString stringWithFormat:@"%@=",optNameToChange];
2343     NSRange currentOptRangeBeginning = [currentOptString rangeOfString:checkOptNameToChangeBeginning];
2344     if (currentOptRange.location != NSNotFound || currentOptRangeBeginning.location == 0)
2345     {
2346         /* Create new empty opt string*/
2347         NSString *changedOptString = @"";
2349         /*Put individual options into an array based on the ":" separator for processing, result is "<opt>=<value>"*/
2350         currentOptsArray = [currentOptString componentsSeparatedByString:@":"];
2352         /*iterate through the array and get <opts> and <values*/
2353         int loopcounter;
2354         int currentOptsArrayCount = [currentOptsArray count];
2355         for (loopcounter = 0; loopcounter < currentOptsArrayCount; loopcounter++)
2356         {
2357             thisOpt = [currentOptsArray objectAtIndex:loopcounter];
2358             NSRange splitOptRange = [thisOpt rangeOfString:@"="];
2360             if (splitOptRange.location != NSNotFound)
2361             {
2362                 optName = [thisOpt substringToIndex:splitOptRange.location];
2363                 optValue = [thisOpt substringFromIndex:splitOptRange.location + 1];
2364                 
2365                 /*Run through the available widgets for x264 opts and set them, as you add widgets, 
2366                 they need to be added here. This should be moved to its own method probably*/
2367                 
2368                 /*If the optNameToChange is found, appropriately change the value or delete it if
2369                 "Unspecified" is set.*/
2370                 if ([optName isEqualToString:optNameToChange])
2371                 {
2372                     if ([sender indexOfSelectedItem] == 0) // means that "unspecified" is chosen, lets then remove it from the string
2373                     {
2374                         thisOpt = @"";
2375                     }
2376                     else if ([optNameToChange isEqualToString:@"me"])
2377                     {
2378                         switch ([sender indexOfSelectedItem])
2379                         {   
2380                             case 1:
2381                                thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"dia"];
2382                                break;
2384                             case 2:
2385                                thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"hex"];
2386                                break;
2388                             case 3:
2389                                thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"umh"];
2390                                break;
2392                             case 4:
2393                                thisOpt = [NSString stringWithFormat:@"%@=%@",optName,@"esa"];
2394                                break;
2395                             
2396                             default:
2397                                 break;
2398                         }
2399                     }
2400                     else if ([optNameToChange isEqualToString:@"merange"])
2401                     {
2402                         thisOpt = [NSString stringWithFormat:@"%@=%d",optName,[sender indexOfSelectedItem]+3];
2403                     }
2404                     else // we have a valid value to change, so change it
2405                     {
2406                         thisOpt = [NSString stringWithFormat:@"%@=%d",optName,[sender indexOfSelectedItem]-1];
2407                     }
2408                 }
2409             }
2411             /* Construct New String for opts here */
2412             if ([thisOpt isEqualToString:@""])
2413             {
2414                 changedOptString = [NSString stringWithFormat:@"%@%@",changedOptString,thisOpt];
2415             }
2416             else
2417             {
2418                 if ([changedOptString isEqualToString:@""])
2419                 {
2420                     changedOptString = [NSString stringWithFormat:@"%@",thisOpt];
2421                 }
2422                 else
2423                 {
2424                     changedOptString = [NSString stringWithFormat:@"%@:%@",changedOptString,thisOpt];
2425                 }
2426             }
2427         }
2429         /* Change the option string to reflect the new mod settings */
2430         [fDisplayX264Options setStringValue:[NSString stringWithFormat:changedOptString]];      
2431     }
2432     else // if none exists, add it to the string
2433     {
2434         if ([[fDisplayX264Options stringValue] isEqualToString: @""])
2435         {
2436             if ([optNameToChange isEqualToString:@"me"])
2437             {
2438                 switch ([sender indexOfSelectedItem])
2439                 {   
2440                     case 1:
2441                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
2442                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"dia"]]];
2443                         break;
2444                
2445                     case 2:
2446                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
2447                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"hex"]]];
2448                         break;
2449                
2450                    case 3:
2451                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
2452                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"umh"]]];
2453                         break;
2454                
2455                    case 4:
2456                         [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
2457                             [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"esa"]]];
2458                         break;
2459                    
2460                    default:
2461                         break;
2462                 }
2463             }
2464             else if ([optNameToChange isEqualToString:@"merange"])
2465             {
2466                 [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
2467                     [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"%d",[sender indexOfSelectedItem]+3]]];
2468             }
2469             else
2470             {
2471                 [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@=%@", 
2472                     [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"%d",[sender indexOfSelectedItem]-1]]];
2473             }
2474         }
2475         else
2476         {
2477             if ([optNameToChange isEqualToString:@"me"])
2478             {
2479                 switch ([sender indexOfSelectedItem])
2480                 {   
2481                     case 1:
2482                          [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@", 
2483                              [NSString stringWithFormat:[fDisplayX264Options stringValue]],
2484                              [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"dia"]]];
2485                          break;
2487                     case 2:
2488                          [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@", 
2489                              [NSString stringWithFormat:[fDisplayX264Options stringValue]],
2490                              [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"hex"]]];
2491                          break;
2493                     case 3:
2494                          [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@", 
2495                              [NSString stringWithFormat:[fDisplayX264Options stringValue]],
2496                              [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"umh"]]];
2497                          break;
2499                     case 4:
2500                          [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@", 
2501                              [NSString stringWithFormat:[fDisplayX264Options stringValue]],
2502                              [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"esa"]]];
2503                          break;
2505                     default:
2506                          break;
2507                 }
2508             }
2509             else if ([optNameToChange isEqualToString:@"merange"])
2510             {
2511                 [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@",[NSString stringWithFormat:[fDisplayX264Options stringValue]], 
2512                     [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"%d",[sender indexOfSelectedItem]+3]]];
2513             }
2514             else
2515             {
2516                 [fDisplayX264Options setStringValue:[NSString stringWithFormat:@"%@:%@=%@",[NSString stringWithFormat:[fDisplayX264Options stringValue]], 
2517                     [NSString stringWithFormat:optNameToChange],[NSString stringWithFormat:@"%d",[sender indexOfSelectedItem]-1]]];
2518             }
2519         }
2520     }
2522     /* We now need to reset the opt widgets since we changed some stuff */              
2523     [self X264AdvancedOptionsSet:NULL];         
2527    /* We use this method to recreate new, updated factory
2528    presets */
2529 - (IBAction)AddFactoryPresets:(id)sender
2531     /* First, we delete any existing built in presets */
2532     [self DeleteFactoryPresets: sender];
2533     /* Then, we re-create new built in presets programmatically CreatePSPPreset*/
2534         [UserPresets addObject:[self CreateIpodPreset]];
2535         [UserPresets addObject:[self CreateAppleTVPreset]];
2536         [UserPresets addObject:[self CreatePSThreePreset]];
2537         [UserPresets addObject:[self CreatePSPPreset]];
2538     [self AddPreset];
2540 - (IBAction)DeleteFactoryPresets:(id)sender
2542     //int status;
2543     NSEnumerator *enumerator = [UserPresets objectEnumerator];
2544         id tempObject;
2545     
2546         //NSNumber *index;
2547     NSMutableArray *tempArray;
2550         tempArray = [NSMutableArray array];
2551         /* we look here to see if the preset is we move on to the next one */
2552         while ( tempObject = [enumerator nextObject] )  
2553                 {
2554                         /* if the preset is "Factory" then we put it in the array of
2555                         presets to delete */
2556                         if ([[tempObject objectForKey:@"Type"] intValue] == 0)
2557                         {
2558                                 [tempArray addObject:tempObject];
2559                         }
2560         }
2561         
2562         [UserPresets removeObjectsInArray:tempArray];
2563         [tableView reloadData];
2564         [self savePreset];   
2568 - (IBAction) ShowAddPresetPanel: (id) sender
2570     /* Deselect the currently selected Preset if there is one*/
2571                 [tableView deselectRow:[tableView selectedRow]];
2573         /* Populate the preset picture settings popup here */
2574         [fPresetNewPicSettingsPopUp removeAllItems];
2575         [fPresetNewPicSettingsPopUp addItemWithTitle:@"None"];
2576         [fPresetNewPicSettingsPopUp addItemWithTitle:@"Current"];
2577         [fPresetNewPicSettingsPopUp addItemWithTitle:@"Source Maximum (post source scan)"];
2578         [fPresetNewPicSettingsPopUp selectItemAtIndex: 0];      
2579         
2580                 /* Erase info from the input fields */
2581         [fPresetNewName setStringValue: @""];
2582         /* Show the panel */
2583         [NSApp beginSheet: fAddPresetPanel modalForWindow: fWindow
2584         modalDelegate: NULL didEndSelector: NULL contextInfo: NULL];
2585     [NSApp runModalForWindow: fAddPresetPanel];
2586     [NSApp endSheet: fAddPresetPanel];
2587     [fAddPresetPanel orderOut: self];
2588         
2589         
2591 - (IBAction) CloseAddPresetPanel: (id) sender
2593         [NSApp stopModal];
2597 - (IBAction)AddUserPreset:(id)sender
2600     /* Here we create a custom user preset */
2601         [UserPresets addObject:[self CreatePreset]];
2602         /* Erase info from the input fields */
2603         [fPresetNewName setStringValue: @""];
2604         /* We stop the modal window for the new preset */
2605         [NSApp stopModal];
2606     [self AddPreset];
2607         
2610 - (void)AddPreset
2613         
2614         /* We Sort the Presets By Factory or Custom */
2615         NSSortDescriptor * presetTypeDescriptor=[[[NSSortDescriptor alloc] initWithKey:@"Type" 
2616                                                     ascending:YES] autorelease];
2617         /* We Sort the Presets Alphabetically by name */
2618         NSSortDescriptor * presetNameDescriptor=[[[NSSortDescriptor alloc] initWithKey:@"PresetName" 
2619                                                     ascending:YES selector:@selector(caseInsensitiveCompare:)] autorelease];
2620         NSArray *sortDescriptors=[NSArray arrayWithObjects:presetTypeDescriptor,presetNameDescriptor,nil];
2621         NSArray *sortedArray=[UserPresets sortedArrayUsingDescriptors:sortDescriptors];
2622         [UserPresets setArray:sortedArray];
2623         
2624         
2625         /* We Reload the New Table data for presets */
2626     [tableView reloadData];
2627    /* We save all of the preset data here */
2628     [self savePreset];
2631 - (IBAction)InsertPreset:(id)sender
2633     int index = [tableView selectedRow];
2634     [UserPresets insertObject:[self CreatePreset] atIndex:index];
2635     [tableView reloadData];
2636     [self savePreset];
2639 - (NSDictionary *)CreatePreset
2641     NSMutableDictionary *preset = [[NSMutableDictionary alloc] init];
2642         /* Get the New Preset Name from the field in the AddPresetPanel */
2643     [preset setObject:[fPresetNewName stringValue] forKey:@"PresetName"];
2644         /*Set whether or not this is a user preset or factory 0 is factory, 1 is user*/
2645         [preset setObject:[NSNumber numberWithInt:1] forKey:@"Type"];
2646         /*Set whether or not this is default, at creation set to 0*/
2647         [preset setObject:[NSNumber numberWithInt:0] forKey:@"Default"];
2648         /*Get the whether or not to apply pic settings in the AddPresetPanel*/
2649         [preset setObject:[NSNumber numberWithInt:[fPresetNewPicSettingsPopUp indexOfSelectedItem]] forKey:@"UsesPictureSettings"];
2650         /* File Format */
2651     [preset setObject:[fDstFormatPopUp titleOfSelectedItem] forKey:@"FileFormat"];
2652         /* Chapter Markers fCreateChapterMarkers*/
2653         [preset setObject:[NSNumber numberWithInt:[fCreateChapterMarkers state]] forKey:@"ChapterMarkers"];
2654         /* Codecs */
2655         [preset setObject:[fDstCodecsPopUp titleOfSelectedItem] forKey:@"FileCodecs"];
2656         /* Video encoder */
2657         [preset setObject:[fVidEncoderPopUp titleOfSelectedItem] forKey:@"VideoEncoder"];
2658         /* x264 Option String */
2659         [preset setObject:[fDisplayX264Options stringValue] forKey:@"x264Option"];
2660         
2661         [preset setObject:[NSNumber numberWithInt:[fVidQualityMatrix selectedRow]] forKey:@"VideoQualityType"];
2662         [preset setObject:[fVidTargetSizeField stringValue] forKey:@"VideoTargetSize"];
2663         [preset setObject:[fVidBitrateField stringValue] forKey:@"VideoAvgBitrate"];
2664         [preset setObject:[NSNumber numberWithFloat:[fVidQualitySlider floatValue]] forKey:@"VideoQualitySlider"];
2665         
2666         /* Video framerate */
2667         [preset setObject:[fVidRatePopUp titleOfSelectedItem] forKey:@"VideoFramerate"];
2668         /* GrayScale */
2669         [preset setObject:[NSNumber numberWithInt:[fVidGrayscaleCheck state]] forKey:@"VideoGrayScale"];
2670         /* 2 Pass Encoding */
2671         [preset setObject:[NSNumber numberWithInt:[fVidTwoPassCheck state]] forKey:@"VideoTwoPass"];
2672         
2673         /*Picture Settings*/
2674         hb_job_t * job = fTitle->job;
2675         /* Basic Picture Settings */
2676         /* Use Max Picture settings for whatever the dvd is.*/
2677         [preset setObject:[NSNumber numberWithInt:0] forKey:@"UsesMaxPictureSettings"];
2678         [preset setObject:[NSNumber numberWithInt:fTitle->job->width] forKey:@"PictureWidth"];
2679         [preset setObject:[NSNumber numberWithInt:fTitle->job->height] forKey:@"PictureHeight"];
2680         [preset setObject:[NSNumber numberWithInt:fTitle->job->keep_ratio] forKey:@"PictureKeepRatio"];
2681         [preset setObject:[NSNumber numberWithInt:fTitle->job->deinterlace] forKey:@"PictureDeinterlace"];
2682         [preset setObject:[NSNumber numberWithInt:fTitle->job->pixel_ratio] forKey:@"PicturePAR"];
2683         /* Set crop settings here */
2684         /* The Auto Crop Matrix in the Picture Window autodetects differences in crop settings */
2685         [preset setObject:[NSNumber numberWithInt:job->crop[0]] forKey:@"PictureTopCrop"];
2686     [preset setObject:[NSNumber numberWithInt:job->crop[1]] forKey:@"PictureBottomCrop"];
2687         [preset setObject:[NSNumber numberWithInt:job->crop[2]] forKey:@"PictureLeftCrop"];
2688         [preset setObject:[NSNumber numberWithInt:job->crop[3]] forKey:@"PictureRightCrop"];
2689         
2690         /*Audio*/
2691         /* Audio Sample Rate*/
2692         [preset setObject:[fAudRatePopUp titleOfSelectedItem] forKey:@"AudioSampleRate"];
2693         /* Audio Bitrate Rate*/
2694         [preset setObject:[fAudBitratePopUp titleOfSelectedItem] forKey:@"AudioBitRate"];
2695         /* Subtitles*/
2696         [preset setObject:[fSubPopUp titleOfSelectedItem] forKey:@"Subtitles"];
2697         
2699     [preset autorelease];
2700     return preset;
2704 - (NSDictionary *)CreateIpodPreset
2706     NSMutableDictionary *preset = [[NSMutableDictionary alloc] init];
2707         /* Get the New Preset Name from the field in the AddPresetPanel */
2708     [preset setObject:@"HB-iPod" forKey:@"PresetName"];
2709         /*Set whether or not this is a user preset or factory 0 is factory, 1 is user*/
2710         [preset setObject:[NSNumber numberWithInt:0] forKey:@"Type"];
2711         /*Set whether or not this is default, at creation set to 0*/
2712         [preset setObject:[NSNumber numberWithInt:0] forKey:@"Default"];
2713         /*Get the whether or not to apply pic settings in the AddPresetPanel*/
2714         [preset setObject:[NSNumber numberWithInt:0] forKey:@"UsesPictureSettings"];
2715         /* File Format */
2716     [preset setObject:@"MP4 file" forKey:@"FileFormat"];
2717         /* Chapter Markers*/
2718          [preset setObject:[NSNumber numberWithInt:1] forKey:@"ChapterMarkers"];
2719     /* Codecs */
2720         [preset setObject:@"AVC/H.264 Video / AAC Audio" forKey:@"FileCodecs"];
2721         /* Video encoder */
2722         [preset setObject:@"x264 (h.264 iPod)" forKey:@"VideoEncoder"];
2723         /* x264 Option String */
2724         [preset setObject:@"frameref=1:bframes=0:nofast_pskip:subq=6:partitions=p8x8,p8x4,p4x8,i4x4:qcomp=0:me=umh:nodct_decimate" forKey:@"x264Option"];
2725         /* Video quality */
2726         [preset setObject:[NSNumber numberWithInt:1] forKey:@"VideoQualityType"];
2727         [preset setObject:[fVidTargetSizeField stringValue] forKey:@"VideoTargetSize"];
2728         [preset setObject:@"1500" forKey:@"VideoAvgBitrate"];
2729         [preset setObject:[NSNumber numberWithFloat:[fVidQualitySlider floatValue]] forKey:@"VideoQualitySlider"];
2730         
2731         /* Video framerate */
2732         [preset setObject:@"Same as source" forKey:@"VideoFramerate"];
2733         /* GrayScale */
2734         [preset setObject:[NSNumber numberWithInt:0] forKey:@"VideoGrayScale"];
2735         /* 2 Pass Encoding */
2736         [preset setObject:[NSNumber numberWithInt:0] forKey:@"VideoTwoPass"];
2737         
2738         /*Picture Settings*/
2739         //hb_job_t * job = fTitle->job;
2740         /* Basic Picture Settings */
2741         /* Use Max Picture settings for whatever the dvd is.*/
2742         [preset setObject:[NSNumber numberWithInt:0] forKey:@"UsesMaxPictureSettings"];
2743         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureWidth"];
2744         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureHeight"];
2745         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureKeepRatio"];
2746         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureDeinterlace"];
2747         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PicturePAR"];
2748         /* Set crop settings here */
2749         /* The Auto Crop Matrix in the Picture Window autodetects differences in crop settings */
2750         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureTopCrop"];
2751     [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureBottomCrop"];
2752         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureLeftCrop"];
2753         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureRightCrop"];
2754         
2755         /*Audio*/
2756         /* Audio Sample Rate*/
2757         [preset setObject:@"48" forKey:@"AudioSampleRate"];
2758         /* Audio Bitrate Rate*/
2759         [preset setObject:@"160" forKey:@"AudioBitRate"];
2760         /* Subtitles*/
2761         [preset setObject:@"None" forKey:@"Subtitles"];
2762         
2764     [preset autorelease];
2765     return preset;
2769 - (NSDictionary *)CreateAppleTVPreset
2771     NSMutableDictionary *preset = [[NSMutableDictionary alloc] init];
2772         /* Get the New Preset Name from the field in the AddPresetPanel */
2773     [preset setObject:@"HB-AppleTV" forKey:@"PresetName"];
2774         /*Set whether or not this is a user preset where 0 is factory, 1 is user*/
2775         [preset setObject:[NSNumber numberWithInt:0] forKey:@"Type"];
2776         /*Set whether or not this is default, at creation set to 0*/
2777         [preset setObject:[NSNumber numberWithInt:0] forKey:@"Default"];
2778         /*Get the whether or not to apply pic settings in the AddPresetPanel*/
2779         [preset setObject:[NSNumber numberWithInt:2] forKey:@"UsesPictureSettings"];
2780         /* File Format */
2781     [preset setObject:@"MP4 file" forKey:@"FileFormat"];
2782         /* Chapter Markers*/
2783          [preset setObject:[NSNumber numberWithInt:1] forKey:@"ChapterMarkers"];
2784         /* Codecs */
2785         [preset setObject:@"AVC/H.264 Video / AAC Audio" forKey:@"FileCodecs"];
2786         /* Video encoder */
2787         [preset setObject:@"x264 (h.264 Main)" forKey:@"VideoEncoder"];
2788         /* x264 Option String (We can use this to tweak the appleTV output)*/
2789         [preset setObject:@"bframes=3:ref=1:subme=5:me=umh:no-fast-pskip=1:no-dct-decimate=1:trellis=2" forKey:@"x264Option"];
2790         /* Video quality */
2791         [preset setObject:[NSNumber numberWithInt:1] forKey:@"VideoQualityType"];
2792         [preset setObject:[fVidTargetSizeField stringValue] forKey:@"VideoTargetSize"];
2793         [preset setObject:@"2500" forKey:@"VideoAvgBitrate"];
2794         [preset setObject:[NSNumber numberWithFloat:[fVidQualitySlider floatValue]] forKey:@"VideoQualitySlider"];
2795         
2796         /* Video framerate */
2797         [preset setObject:@"Same as source" forKey:@"VideoFramerate"];
2798         /* GrayScale */
2799         [preset setObject:[NSNumber numberWithInt:0] forKey:@"VideoGrayScale"];
2800         /* 2 Pass Encoding */
2801         [preset setObject:[NSNumber numberWithInt:0] forKey:@"VideoTwoPass"];
2802         
2803         /*Picture Settings*/
2804         /* For AppleTV we only want to retain UsesMaxPictureSettings
2805         which depend on the source dvd picture settings, so we don't
2806         record the current dvd's picture info since it will vary from
2807         source to source*/
2808         //hb_job_t * job = fTitle->job;
2809         //hb_job_t * job = title->job;
2810         /* Basic Picture Settings */
2811         /* Use Max Picture settings for whatever the dvd is.*/
2812         [preset setObject:[NSNumber numberWithInt:1] forKey:@"UsesMaxPictureSettings"];
2813         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureWidth"];
2814         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureHeight"];
2815         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureKeepRatio"];
2816         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureDeinterlace"];
2817         [preset setObject:[NSNumber numberWithInt:1] forKey:@"PicturePAR"];
2818         /* Set crop settings here */
2819         /* The Auto Crop Matrix in the Picture Window autodetects differences in crop settings */
2820         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureTopCrop"];
2821     [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureBottomCrop"];
2822         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureLeftCrop"];
2823         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureRightCrop"];
2824         
2825         /*Audio*/
2826         /* Audio Sample Rate*/
2827         [preset setObject:@"48" forKey:@"AudioSampleRate"];
2828         /* Audio Bitrate Rate*/
2829         [preset setObject:@"160" forKey:@"AudioBitRate"];
2830         /* Subtitles*/
2831         [preset setObject:@"None" forKey:@"Subtitles"];
2832         
2834     [preset autorelease];
2835     return preset;
2839 - (NSDictionary *)CreatePSThreePreset
2841     NSMutableDictionary *preset = [[NSMutableDictionary alloc] init];
2842         /* Get the New Preset Name from the field in the AddPresetPanel */
2843     [preset setObject:@"HB-PS3" forKey:@"PresetName"];
2844         /*Set whether or not this is a user preset where 0 is factory, 1 is user*/
2845         [preset setObject:[NSNumber numberWithInt:0] forKey:@"Type"];
2846         /*Set whether or not this is default, at creation set to 0*/
2847         [preset setObject:[NSNumber numberWithInt:0] forKey:@"Default"];
2848         /*Get the whether or not to apply pic settings in the AddPresetPanel*/
2849         [preset setObject:[NSNumber numberWithInt:2] forKey:@"UsesPictureSettings"];
2850         /* File Format */
2851     [preset setObject:@"MP4 file" forKey:@"FileFormat"];
2852         /* Chapter Markers*/
2853          [preset setObject:[NSNumber numberWithInt:1] forKey:@"ChapterMarkers"];
2854         /* Codecs */
2855         [preset setObject:@"AVC/H.264 Video / AAC Audio" forKey:@"FileCodecs"];
2856         /* Video encoder */
2857         [preset setObject:@"x264 (h.264 Main)" forKey:@"VideoEncoder"];
2858         /* x264 Option String (We can use this to tweak the appleTV output)*/
2859         [preset setObject:@"level=41" forKey:@"x264Option"];
2860         /* Video quality */
2861         [preset setObject:[NSNumber numberWithInt:1] forKey:@"VideoQualityType"];
2862         [preset setObject:[fVidTargetSizeField stringValue] forKey:@"VideoTargetSize"];
2863         [preset setObject:@"2500" forKey:@"VideoAvgBitrate"];
2864         [preset setObject:[NSNumber numberWithFloat:[fVidQualitySlider floatValue]] forKey:@"VideoQualitySlider"];
2865         
2866         /* Video framerate */
2867         [preset setObject:@"Same as source" forKey:@"VideoFramerate"];
2868         /* GrayScale */
2869         [preset setObject:[NSNumber numberWithInt:0] forKey:@"VideoGrayScale"];
2870         /* 2 Pass Encoding */
2871         [preset setObject:[NSNumber numberWithInt:0] forKey:@"VideoTwoPass"];
2872         
2873         /*Picture Settings*/
2874         /* For PS3 we only want to retain UsesMaxPictureSettings
2875         which depend on the source dvd picture settings, so we don't
2876         record the current dvd's picture info since it will vary from
2877         source to source*/
2878         /* Use Max Picture settings for whatever the dvd is.*/
2879         [preset setObject:[NSNumber numberWithInt:1] forKey:@"UsesMaxPictureSettings"];
2880         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureWidth"];
2881         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureHeight"];
2882         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureKeepRatio"];
2883         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureDeinterlace"];
2884         [preset setObject:[NSNumber numberWithInt:1] forKey:@"PicturePAR"];
2885         /* Set crop settings here */
2886         /* The Auto Crop Matrix in the Picture Window autodetects differences in crop settings */
2887         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureTopCrop"];
2888     [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureBottomCrop"];
2889         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureLeftCrop"];
2890         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureRightCrop"];
2891         
2892         /*Audio*/
2893         /* Audio Sample Rate*/
2894         [preset setObject:@"48" forKey:@"AudioSampleRate"];
2895         /* Audio Bitrate Rate*/
2896         [preset setObject:@"160" forKey:@"AudioBitRate"];
2897         /* Subtitles*/
2898         [preset setObject:@"None" forKey:@"Subtitles"];
2899         
2901     [preset autorelease];
2902     return preset;
2905 - (NSDictionary *)CreatePSPPreset
2907     NSMutableDictionary *preset = [[NSMutableDictionary alloc] init];
2908         /* Get the New Preset Name from the field in the AddPresetPanel */
2909     [preset setObject:@"HB-PSP" forKey:@"PresetName"];
2910         /*Set whether or not this is a user preset where 0 is factory, 1 is user*/
2911         [preset setObject:[NSNumber numberWithInt:0] forKey:@"Type"];
2912         /*Set whether or not this is default, at creation set to 0*/
2913         [preset setObject:[NSNumber numberWithInt:0] forKey:@"Default"];
2914         /*Get the whether or not to apply pic settings in the AddPresetPanel*/
2915         [preset setObject:[NSNumber numberWithInt:1] forKey:@"UsesPictureSettings"];
2916         /* File Format */
2917     [preset setObject:@"MP4 file" forKey:@"FileFormat"];
2918         /* Chapter Markers*/
2919          [preset setObject:[NSNumber numberWithInt:1] forKey:@"ChapterMarkers"];
2920         /* Codecs */
2921         [preset setObject:@"MPEG-4 Video / AAC Audio" forKey:@"FileCodecs"];
2922         /* Video encoder */
2923         [preset setObject:@"FFmpeg" forKey:@"VideoEncoder"];
2924         /* x264 Option String (We can use this to tweak the appleTV output)*/
2925         [preset setObject:@"" forKey:@"x264Option"];
2926         /* Video quality */
2927         [preset setObject:[NSNumber numberWithInt:1] forKey:@"VideoQualityType"];
2928         [preset setObject:[fVidTargetSizeField stringValue] forKey:@"VideoTargetSize"];
2929         [preset setObject:@"1024" forKey:@"VideoAvgBitrate"];
2930         [preset setObject:[NSNumber numberWithFloat:[fVidQualitySlider floatValue]] forKey:@"VideoQualitySlider"];
2931         
2932         /* Video framerate */
2933         [preset setObject:@"Same as source" forKey:@"VideoFramerate"];
2934         /* GrayScale */
2935         [preset setObject:[NSNumber numberWithInt:0] forKey:@"VideoGrayScale"];
2936         /* 2 Pass Encoding */
2937         [preset setObject:[NSNumber numberWithInt:0] forKey:@"VideoTwoPass"];
2938         
2939         /*Picture Settings*/
2940         /* For PS3 we only want to retain UsesMaxPictureSettings
2941         which depend on the source dvd picture settings, so we don't
2942         record the current dvd's picture info since it will vary from
2943         source to source*/
2944         /* Use Max Picture settings for whatever the dvd is.*/
2945         [preset setObject:[NSNumber numberWithInt:0] forKey:@"UsesMaxPictureSettings"];
2946         [preset setObject:@"368" forKey:@"PictureWidth"];
2947         [preset setObject:@"208" forKey:@"PictureHeight"];
2948         [preset setObject:[NSNumber numberWithInt:1] forKey:@"PictureKeepRatio"];
2949         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureDeinterlace"];
2950         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PicturePAR"];
2951         /* Set crop settings here */
2952         /* The Auto Crop Matrix in the Picture Window autodetects differences in crop settings */
2953         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureTopCrop"];
2954     [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureBottomCrop"];
2955         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureLeftCrop"];
2956         [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureRightCrop"];
2957         
2958         /*Audio*/
2959         /* Audio Sample Rate*/
2960         [preset setObject:@"48" forKey:@"AudioSampleRate"];
2961         /* Audio Bitrate Rate*/
2962         [preset setObject:@"128" forKey:@"AudioBitRate"];
2963         /* Subtitles*/
2964         [preset setObject:@"None" forKey:@"Subtitles"];
2965         
2967     [preset autorelease];
2968     return preset;
2973 - (IBAction)DeletePreset:(id)sender
2975     int status;
2976     NSEnumerator *enumerator;
2977     NSNumber *index;
2978     NSMutableArray *tempArray;
2979     id tempObject;
2980     
2981     if ( [tableView numberOfSelectedRows] == 0 )
2982         return;
2983     /* Alert user before deleting preset */
2984         /* Comment out for now, tie to user pref eventually */
2986     //NSBeep();
2987     status = NSRunAlertPanel(@"Warning!", @"Are you sure that you want to delete the selected preset?", @"OK", @"Cancel", nil);
2988     
2989     if ( status == NSAlertDefaultReturn ) {
2990         enumerator = [tableView selectedRowEnumerator];
2991         tempArray = [NSMutableArray array];
2992         
2993         while ( (index = [enumerator nextObject]) ) {
2994             tempObject = [UserPresets objectAtIndex:[index intValue]];
2995             [tempArray addObject:tempObject];
2996         }
2997         
2998         [UserPresets removeObjectsInArray:tempArray];
2999         [tableView reloadData];
3000         [self savePreset];   
3001     }
3003 - (IBAction)tableViewSelected:(id)sender
3005     /* Since we cannot disable the presets tableView in terms of clickability
3006            we will use the enabled state of the add presets button to determine whether
3007            or not clicking on a preset will do anything */
3008         if ([fPresetsAdd isEnabled])
3009         {
3010                 
3011                 /* we get the chosen preset from the UserPresets array */
3012                 chosenPreset = [UserPresets objectAtIndex:[sender selectedRow]];
3013                 curUserPresetChosenNum = [sender selectedRow];
3014                 /* we set the preset display field in main window here */
3015                 [fPresetSelectedDisplay setStringValue: [NSString stringWithFormat: @"%@",[chosenPreset valueForKey:@"PresetName"]]];
3016                 /* File Format */
3017                 [fDstFormatPopUp selectItemWithTitle: [NSString stringWithFormat:[chosenPreset valueForKey:@"FileFormat"]]];
3018                 [self FormatPopUpChanged: NULL];
3019                 /* Chapter Markers*/
3020                 [fCreateChapterMarkers setState:[[chosenPreset objectForKey:@"ChapterMarkers"] intValue]];
3021             /* Codecs */
3022                 [fDstCodecsPopUp selectItemWithTitle: [NSString stringWithFormat:[chosenPreset valueForKey:@"FileCodecs"]]];
3023                 [self CodecsPopUpChanged: NULL];
3024                 /* Video encoder */
3025                 [fVidEncoderPopUp selectItemWithTitle: [NSString stringWithFormat:[chosenPreset valueForKey:@"VideoEncoder"]]];
3026                 
3027                 /* We can show the preset options here in the gui if we want to
3028                         so we check to see it the user has specified it in the prefs */
3029                 [fDisplayX264Options setStringValue: [NSString stringWithFormat:[chosenPreset valueForKey:@"x264Option"]]];
3031                 [self X264AdvancedOptionsSet:NULL];
3032                 
3033                 /* Lets run through the following functions to get variables set there */
3034                 [self EncoderPopUpChanged: NULL];
3035                 [self CalculateBitrate: NULL];
3036                 
3037                 /* Video quality */
3038                 [fVidQualityMatrix selectCellAtRow:[[chosenPreset objectForKey:@"VideoQualityType"] intValue] column:0];
3039                 
3040                 [fVidTargetSizeField setStringValue: [NSString stringWithFormat:[chosenPreset valueForKey:@"VideoTargetSize"]]];
3041                 [fVidBitrateField setStringValue: [NSString stringWithFormat:[chosenPreset valueForKey:@"VideoAvgBitrate"]]];
3042                 
3043                 [fVidQualitySlider setFloatValue: [[chosenPreset valueForKey:@"VideoQualitySlider"] floatValue]];
3044                 [self VideoMatrixChanged: NULL];
3045                 
3046                 /* Video framerate */
3047                 [fVidRatePopUp selectItemWithTitle: [NSString stringWithFormat:[chosenPreset valueForKey:@"VideoFramerate"]]];
3049                 /* GrayScale */
3050                 [fVidGrayscaleCheck setState:[[chosenPreset objectForKey:@"VideoGrayScale"] intValue]];
3051                 
3052                 /* 2 Pass Encoding */
3053                 [fVidTwoPassCheck setState:[[chosenPreset objectForKey:@"VideoTwoPass"] intValue]];
3054                 
3055                 
3056                 /*Audio*/
3057                 
3058                 /* Audio Sample Rate*/
3059                 [fAudRatePopUp selectItemWithTitle: [NSString stringWithFormat:[chosenPreset valueForKey:@"AudioSampleRate"]]];
3060                 /* Audio Bitrate Rate*/
3061                 [fAudBitratePopUp selectItemWithTitle: [NSString stringWithFormat:[chosenPreset valueForKey:@"AudioBitRate"]]];
3062                 /*Subtitles*/
3063                 [fSubPopUp selectItemWithTitle: [NSString stringWithFormat:[chosenPreset valueForKey:@"Subtitles"]]];
3064                 
3065                 /* Picture Settings */
3066                 /* Look to see if we apply these here in objectForKey:@"UsesPictureSettings"] */
3067                 if ([[chosenPreset objectForKey:@"UsesPictureSettings"]  intValue] > 0)
3068                 {
3069                         hb_job_t * job = fTitle->job;
3070                         /* Check to see if we should use the max picture setting for the current title*/
3071                         if ([[chosenPreset objectForKey:@"UsesPictureSettings"]  intValue] == 2 || [[chosenPreset objectForKey:@"UsesMaxPictureSettings"]  intValue] == 1)
3072                         {
3073                                 /* Use Max Picture settings for whatever the dvd is.*/
3074                                 [self RevertPictureSizeToMax: NULL];
3075                                 job->keep_ratio = [[chosenPreset objectForKey:@"PictureKeepRatio"]  intValue];
3076                                 if (job->keep_ratio == 1)
3077                                 {
3078                                         hb_fix_aspect( job, HB_KEEP_WIDTH );
3079                                 }
3080                                 job->pixel_ratio = [[chosenPreset objectForKey:@"PicturePAR"]  intValue];
3081                         }
3082                         else
3083                         {
3084                                 job->width = [[chosenPreset objectForKey:@"PictureWidth"]  intValue];
3085                                 job->height = [[chosenPreset objectForKey:@"PictureHeight"]  intValue];
3086                                 job->keep_ratio = [[chosenPreset objectForKey:@"PictureKeepRatio"]  intValue];
3087                                 if (job->keep_ratio == 1)
3088                                 {
3089                                         hb_fix_aspect( job, HB_KEEP_WIDTH );
3090                                 }
3091                                 job->pixel_ratio = [[chosenPreset objectForKey:@"PicturePAR"]  intValue];
3092                                 job->crop[0] = [[chosenPreset objectForKey:@"PictureTopCrop"]  intValue];
3093                                 job->crop[1] = [[chosenPreset objectForKey:@"PictureBottomCrop"]  intValue];
3094                                 job->crop[2] = [[chosenPreset objectForKey:@"PictureLeftCrop"]  intValue];
3095                                 job->crop[3] = [[chosenPreset objectForKey:@"PictureRightCrop"]  intValue];
3096                         }
3097                         [self CalculatePictureSizing: NULL]; 
3098                 }
3099                 
3108 - (int)numberOfRowsInTableView:(NSTableView *)aTableView
3110     return [UserPresets count];
3113 /* we use this to determine display characteristics for
3114 each table cell based on content currently only used to
3115 show the built in presets in a blue font. */
3116 - (void)tableView:(NSTableView *)aTableView
3117  willDisplayCell:(id)aCell 
3118  forTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
3120     NSDictionary *userPresetDict = [UserPresets objectAtIndex:rowIndex];
3121    if ([[userPresetDict objectForKey:@"Type"] intValue] == 0)
3122         {
3123                 [aCell setTextColor:[NSColor blueColor]];
3124         }
3125         else
3126         {
3127                 [aCell setTextColor:[NSColor blackColor]];
3128         }
3132 - (id)tableView:(NSTableView *)aTableView
3133       objectValueForTableColumn:(NSTableColumn *)aTableColumn
3134       row:(int)rowIndex
3136 id theRecord, theValue;
3137     
3138     theRecord = [UserPresets objectAtIndex:rowIndex];
3139     theValue = [theRecord objectForKey:[aTableColumn identifier]];
3140     return theValue;
3143 // NSTableDataSource method that we implement to edit values directly in the table...
3144 - (void)tableView:(NSTableView *)aTableView
3145         setObjectValue:(id)anObject
3146         forTableColumn:(NSTableColumn *)aTableColumn
3147         row:(int)rowIndex
3149     id theRecord;
3150     
3151     theRecord = [UserPresets objectAtIndex:rowIndex];
3152     [theRecord setObject:anObject forKey:@"PresetName"];
3153     /* We Sort the Presets By Factory or Custom */
3154         NSSortDescriptor * presetTypeDescriptor=[[[NSSortDescriptor alloc] initWithKey:@"Type" 
3155                                                     ascending:YES] autorelease];
3156                 /* We Sort the Presets Alphabetically by name */
3157         NSSortDescriptor * presetNameDescriptor=[[[NSSortDescriptor alloc] initWithKey:@"PresetName" 
3158                                                     ascending:YES selector:@selector(caseInsensitiveCompare:)] autorelease];
3159         NSArray *sortDescriptors=[NSArray arrayWithObjects:presetTypeDescriptor,presetNameDescriptor,nil];
3160     NSArray *sortedArray=[UserPresets sortedArrayUsingDescriptors:sortDescriptors];
3161         [UserPresets setArray:sortedArray];
3162         /* We Reload the New Table data for presets */
3163     [tableView reloadData];
3164    /* We save all of the preset data here */
3165     [self savePreset];
3169 - (void)savePreset
3171     [UserPresets writeToFile:UserPresetsFile atomically:YES];
3177 - (void) controlTextDidBeginEditing: (NSNotification *) notification
3179     [self CalculateBitrate: NULL];
3182 - (void) controlTextDidEndEditing: (NSNotification *) notification
3184     [self CalculateBitrate: NULL];
3187 - (void) controlTextDidChange: (NSNotification *) notification
3189     [self CalculateBitrate: NULL];
3192 - (IBAction) OpenHomepage: (id) sender
3194     [[NSWorkspace sharedWorkspace] openURL: [NSURL
3195         URLWithString:@"http://handbrake.m0k.org/"]];
3198 - (IBAction) OpenForums: (id) sender
3200     [[NSWorkspace sharedWorkspace] openURL: [NSURL
3201         URLWithString:@"http://handbrake.m0k.org/forum/"]];
3203 - (IBAction) OpenUserGuide: (id) sender
3205     [[NSWorkspace sharedWorkspace] openURL: [NSURL
3206         URLWithString:@"http://handbrake.m0k.org/trac/wiki/HandBrakeGuide"]];
3210 @end