OSDN Git Service

MacGui: Thinine's custom file size and x264 fix.
[handbrake-jp/handbrake-jp-git.git] / macosx / Controller.mm
1 /* $Id: Controller.mm,v 1.79 2005/11/04 19:41:32 titer Exp $
2
3    This file is part of the HandBrake source code.
4    Homepage: <http://handbrake.m0k.org/>.
5    It may be used under the terms of the GNU General Public License. */
6
7 #include "Controller.h"
8
9 #define _(a) NSLocalizedString(a,NULL)
10
11 static int FormatSettings[3][4] =
12   { { HB_MUX_MP4 | HB_VCODEC_FFMPEG | HB_ACODEC_FAAC,
13       HB_MUX_MP4 | HB_VCODEC_X264   | HB_ACODEC_FAAC,
14       0,
15       0 },
16     { HB_MUX_AVI | HB_VCODEC_FFMPEG | HB_ACODEC_LAME,
17       HB_MUX_AVI | HB_VCODEC_FFMPEG | HB_ACODEC_AC3,
18       HB_MUX_AVI | HB_VCODEC_X264   | HB_ACODEC_LAME,
19       HB_MUX_AVI | HB_VCODEC_X264   | HB_ACODEC_AC3 },
20     { HB_MUX_OGM | HB_VCODEC_FFMPEG | HB_ACODEC_VORBIS,
21       HB_MUX_OGM | HB_VCODEC_FFMPEG | HB_ACODEC_LAME,
22       0,
23       0 } };
24
25 /*******************************
26  * HBController implementation *
27  *******************************/
28 @implementation HBController
29
30 - init
31 {
32     self    = [super init];
33     fHandle = NULL;
34     return self;
35 }
36
37 - (void) applicationDidFinishLaunching: (NSNotification *) notification
38 {
39     int    build;
40     char * version;
41
42     /* Init libhb */
43     fHandle = hb_init( HB_DEBUG_NONE, [[NSUserDefaults
44         standardUserDefaults] boolForKey:@"CheckForUpdates"] );
45     
46     /* Init others controllers */
47     [fScanController    SetHandle: fHandle];
48     [fPictureController SetHandle: fHandle];
49     [fQueueController   SetHandle: fHandle];
50         
51
52      /* Call UpdateUI every 2/10 sec */
53     [[NSRunLoop currentRunLoop] addTimer: [NSTimer
54         scheduledTimerWithTimeInterval: 0.2 target: self
55         selector: @selector( UpdateUI: ) userInfo: NULL repeats: FALSE]
56         forMode: NSModalPanelRunLoopMode];
57
58     if( ( build = hb_check_update( fHandle, &version ) ) > -1 )
59     {
60         /* Update available - tell the user */
61         
62         NSBeginInformationalAlertSheet( _( @"Update is available" ),
63             _( @"Go get it!" ), _( @"Discard" ), NULL, fWindow, self,
64             @selector( UpdateAlertDone:returnCode:contextInfo: ),
65             NULL, NULL, [NSString stringWithFormat:
66             _( @"HandBrake %s (build %d) is now available for download." ),
67             version, build] );
68         return;
69
70     }
71
72     /* Show scan panel ASAP */
73     [self performSelectorOnMainThread: @selector(ShowScanPanel:)
74         withObject: NULL waitUntilDone: NO];
75 }
76
77 - (NSApplicationTerminateReply) applicationShouldTerminate:
78     (NSApplication *) app
79 {
80     if( [[fRipButton title] isEqualToString: _( @"Cancel" )] )
81     {
82         [self Cancel: NULL];
83         return NSTerminateCancel;
84     }
85     
86     /* Clean up */
87     hb_close( &fHandle );
88     return NSTerminateNow;
89 }
90
91 - (void) awakeFromNib
92 {
93     [fWindow center];
94
95     [self TranslateStrings];
96
97         /* Init User Presets .plist */
98         /* We declare the default NSFileManager into fileManager */
99         NSFileManager * fileManager = [NSFileManager defaultManager];
100         //presetPrefs = [[NSUserDefaults standardUserDefaults] retain];
101         /* we set the files and support paths here */
102         AppSupportDirectory = @"~/Library/Application Support/HandBrake";
103     AppSupportDirectory = [AppSupportDirectory stringByExpandingTildeInPath];
104     
105         UserPresetsFile = @"~/Library/Application Support/HandBrake/UserPresets.plist";
106     UserPresetsFile = [UserPresetsFile stringByExpandingTildeInPath];
107         
108         x264ProfilesFile = @"~/Library/Application Support/HandBrake/x264Profiles.plist";
109     x264ProfilesFile = [x264ProfilesFile stringByExpandingTildeInPath];
110         /* We check for the app support directory for media fork */
111         if ([fileManager fileExistsAtPath:AppSupportDirectory] == 0) 
112         {
113                 // If it doesnt exist yet, we create it here 
114                 [fileManager createDirectoryAtPath:AppSupportDirectory attributes:nil];
115         }
116         // We check for the presets.plist here
117         
118         if ([fileManager fileExistsAtPath:UserPresetsFile] == 0) 
119         {
120
121                 [fileManager createFileAtPath:UserPresetsFile contents:nil attributes:nil];
122                 
123         }
124         // We check for the x264profiles.plist here
125          
126         if ([fileManager fileExistsAtPath:x264ProfilesFile] == 0) 
127         {
128         
129                 [fileManager createFileAtPath:x264ProfilesFile contents:nil attributes:nil];
130         }
131     
132         
133   UserPresetsFile = @"~/Library/Application Support/HandBrake/UserPresets.plist";
134   UserPresetsFile = [[UserPresetsFile stringByExpandingTildeInPath]retain];
135
136   UserPresets = [[NSMutableArray alloc] initWithContentsOfFile:UserPresetsFile];
137   if (nil == UserPresets) 
138   {
139     UserPresets = [[NSMutableArray alloc] init];
140   }
141   /* Show/Dont Show Presets drawer upon launch based
142   on user preference DefaultPresetsDrawerShow*/
143 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultPresetsDrawerShow"] > 0)
144                 {
145                         [fPresetDrawer open];
146                 }
147
148
149
150     /* Destination box*/
151     [fDstFormatPopUp removeAllItems];
152     [fDstFormatPopUp addItemWithTitle: _( @"MP4 file" )];
153     [fDstFormatPopUp addItemWithTitle: _( @"AVI file" )];
154     [fDstFormatPopUp addItemWithTitle: _( @"OGM file" )];
155     [fDstFormatPopUp selectItemAtIndex: 0];
156
157     [self FormatPopUpChanged: NULL];
158
159     [fDstFile2Field setStringValue: [NSString stringWithFormat:
160         @"%@/Desktop/Movie.mp4", NSHomeDirectory()]];
161
162     /* Video encoder */
163     [fVidEncoderPopUp removeAllItems];
164     [fVidEncoderPopUp addItemWithTitle: @"FFmpeg"];
165     [fVidEncoderPopUp addItemWithTitle: @"XviD"];
166
167     /* Video quality */
168     [fVidTargetSizeField setIntValue: 700];
169         [fVidBitrateField    setIntValue: 1000];
170         /* Do we want to force the quality settings if PAR is on ?
171         if ([[NSUserDefaults standardUserDefaults] boolForKey:@"PixelRatio"])
172     {
173         [fVidBitrateField    setIntValue: 1500];
174         [fVidTwoPassCheck    setState: NSOnState];
175     }
176         else
177         {
178         [fVidBitrateField    setIntValue: 1000];
179     }
180         */
181     [fVidQualityMatrix   selectCell: fVidBitrateCell];
182     [self VideoMatrixChanged: NULL];
183
184     /* Video framerate */
185     [fVidRatePopUp removeAllItems];
186     [fVidRatePopUp addItemWithTitle: _( @"Same as source" )];
187     for( int i = 0; i < hb_video_rates_count; i++ )
188     {
189         [fVidRatePopUp addItemWithTitle:
190             [NSString stringWithCString: hb_video_rates[i].string]];
191     }
192     [fVidRatePopUp selectItemAtIndex: 0];
193         
194         /* Picture Settings */
195         [fPicLabelPAROutp setStringValue: @""];
196         [fPicLabelPAROutputX setStringValue: @""];
197         [fPicSettingPARWidth setStringValue: @""];
198         [fPicSettingPARHeight setStringValue:  @""];
199         
200     /* Audio bitrate */
201     [fAudBitratePopUp removeAllItems];
202     for( int i = 0; i < hb_audio_bitrates_count; i++ )
203     {
204         [fAudBitratePopUp addItemWithTitle:
205             [NSString stringWithCString: hb_audio_bitrates[i].string]];
206     }
207     [fAudBitratePopUp selectItemAtIndex: hb_audio_bitrates_default];
208
209     /* Audio samplerate */
210     [fAudRatePopUp removeAllItems];
211     for( int i = 0; i < hb_audio_rates_count; i++ )
212     {
213         [fAudRatePopUp addItemWithTitle:
214             [NSString stringWithCString: hb_audio_rates[i].string]];
215     }
216     [fAudRatePopUp selectItemAtIndex: hb_audio_rates_default];
217
218     /* Bottom */
219     [fStatusField setStringValue: @""];
220
221     [self EnableUI: NO];
222     [fPauseButton setEnabled: NO];
223     [fRipButton setEnabled: NO];
224
225
226
227 }
228
229
230 - (void) TranslateStrings
231 {
232     [fSrcDVD1Field      setStringValue: _( @"DVD:" )];
233     [fSrcTitleField     setStringValue: _( @"Title:" )];
234     [fSrcChapterField   setStringValue: _( @"Chapters:" )];
235     [fSrcChapterToField setStringValue: _( @"to" )];
236     [fSrcDuration1Field setStringValue: _( @"Duration:" )];
237
238     [fDstFormatField    setStringValue: _( @"File format:" )];
239     [fDstCodecsField    setStringValue: _( @"Codecs:" )];
240     [fDstFile1Field     setStringValue: _( @"File:" )];
241     [fDstBrowseButton   setTitle:       _( @"Browse" )];
242
243     [fVidRateField      setStringValue: _( @"Framerate (fps):" )];
244     [fVidEncoderField   setStringValue: _( @"Encoder:" )];
245     [fVidQualityField   setStringValue: _( @"Quality:" )];
246 }
247
248 /***********************************************************************
249  * UpdateDockIcon
250  ***********************************************************************
251  * Shows a progression bar on the dock icon, filled according to
252  * 'progress' (0.0 <= progress <= 1.0).
253  * Called with progress < 0.0 or progress > 1.0, restores the original
254  * icon.
255  **********************************************************************/
256 - (void) UpdateDockIcon: (float) progress
257 {
258     NSImage * icon;
259     NSData * tiff;
260     NSBitmapImageRep * bmp;
261     uint32_t * pen;
262     uint32_t black = htonl( 0x000000FF );
263     uint32_t red   = htonl( 0xFF0000FF );
264     uint32_t white = htonl( 0xFFFFFFFF );
265     int row_start, row_end;
266     int i, j;
267
268     /* Get application original icon */
269     icon = [NSImage imageNamed: @"NSApplicationIcon"];
270
271     if( progress < 0.0 || progress > 1.0 )
272     {
273         [NSApp setApplicationIconImage: icon];
274         return;
275     }
276
277     /* Get it in a raw bitmap form */
278     tiff = [icon TIFFRepresentationUsingCompression:
279             NSTIFFCompressionNone factor: 1.0];
280     bmp = [NSBitmapImageRep imageRepWithData: tiff];
281     
282     /* Draw the progression bar */
283     /* It's pretty simple (ugly?) now, but I'm no designer */
284
285     row_start = 3 * (int) [bmp size].height / 4;
286     row_end   = 7 * (int) [bmp size].height / 8;
287
288     for( i = row_start; i < row_start + 2; i++ )
289     {
290         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
291         for( j = 0; j < (int) [bmp size].width; j++ )
292         {
293             pen[j] = black;
294         }
295     }
296     for( i = row_start + 2; i < row_end - 2; i++ )
297     {
298         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
299         pen[0] = black;
300         pen[1] = black;
301         for( j = 2; j < (int) [bmp size].width - 2; j++ )
302         {
303             if( j < 2 + (int) ( ( [bmp size].width - 4.0 ) * progress ) )
304             {
305                 pen[j] = red;
306             }
307             else
308             {
309                 pen[j] = white;
310             }
311         }
312         pen[j]   = black;
313         pen[j+1] = black;
314     }
315     for( i = row_end - 2; i < row_end; i++ )
316     {
317         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
318         for( j = 0; j < (int) [bmp size].width; j++ )
319         {
320             pen[j] = black;
321         }
322     }
323
324     /* Now update the dock icon */
325     tiff = [bmp TIFFRepresentationUsingCompression:
326             NSTIFFCompressionNone factor: 1.0];
327     icon = [[NSImage alloc] initWithData: tiff];
328     [NSApp setApplicationIconImage: icon];
329     [icon release];
330 }
331
332 - (void) UpdateUI: (NSTimer *) timer
333 {
334
335     hb_state_t s;
336     hb_get_state( fHandle, &s );
337
338     switch( s.state )
339     {
340         case HB_STATE_IDLE:
341             break;
342
343         case HB_STATE_SCANNING:
344             [fScanController UpdateUI: &s];
345             break;
346
347 #define p s.param.scandone
348         case HB_STATE_SCANDONE:
349         {
350             hb_list_t  * list;
351             hb_title_t * title;
352                         int indxpri=0;    // Used to search the longuest title (default in combobox)
353                         int longuestpri=0; // Used to search the longuest title (default in combobox)
354
355             [fScanController UpdateUI: &s];
356
357             list = hb_get_titles( fHandle );
358
359             if( !hb_list_count( list ) )
360             {
361                 break;
362             }
363
364
365             [fSrcTitlePopUp removeAllItems];
366             for( int i = 0; i < hb_list_count( list ); i++ )
367             {
368                 title = (hb_title_t *) hb_list_item( list, i );
369                 /*Set DVD Name at top of window*/
370                                 [fSrcDVD2Field setStringValue: [NSString
371                   stringWithUTF8String: title->name]];  
372                                 
373                                 /* Use the dvd name in the default output field here 
374                                 May want to add code to remove blank spaces for some dvd names*/
375                                 /* Check to see if the last destination has been set,use if so, if not, use Desktop */
376                                 if ([[NSUserDefaults standardUserDefaults] stringForKey:@"LastDestinationDirectory"])
377                                 {
378                                 [fDstFile2Field setStringValue: [NSString stringWithFormat:
379                 @"%@/%@.mp4", [[NSUserDefaults standardUserDefaults] stringForKey:@"LastDestinationDirectory"],[NSString
380                   stringWithUTF8String: title->name]]];
381                                 }
382                                 else
383                                 {
384                                 [fDstFile2Field setStringValue: [NSString stringWithFormat:
385                 @"%@/Desktop/%@.mp4", NSHomeDirectory(),[NSString
386                   stringWithUTF8String: title->name]]];
387                                 }
388
389                   
390                 if (longuestpri < title->hours*60*60 + title->minutes *60 + title->seconds)
391                 {
392                         longuestpri=title->hours*60*60 + title->minutes *60 + title->seconds;
393                         indxpri=i;
394                 }
395                 
396                                 
397                 int format = [fDstFormatPopUp indexOfSelectedItem];
398                                 char * ext = NULL;
399                                 switch( format )
400                 {
401                  case 0:
402                                          
403                                          /*Get Default MP4 File Extension for mpeg4 (.mp4 or .m4v) from prefs*/
404                                          if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultMpegName"] > 0)
405                                          {
406                                          ext = "m4v";
407                                          }
408                                      else
409                                      {
410                                          ext = "mp4";
411                                          }
412                                         break;
413                                 case 1: 
414                      ext = "avi";
415                                 case 2:
416                                    break;
417                      ext = "ogm";
418                                break;
419                                    }
420                                 
421                                 
422                                 NSString * string = [fDstFile2Field stringValue];
423                                 /* Add/replace File Output name to the correct extension*/
424                                 if( [string characterAtIndex: [string length] - 4] == '.' )
425                                 {
426                                         [fDstFile2Field setStringValue: [NSString stringWithFormat:
427                                                 @"%@.%s", [string substringToIndex: [string length] - 4],
428                                                 ext]];
429                                 }
430                                 else
431                                 {
432                                         [fDstFile2Field setStringValue: [NSString stringWithFormat:
433                                                 @"%@.%s", string, ext]];
434                                 }
435
436                                 
437                             [fSrcTitlePopUp addItemWithTitle: [NSString
438                     stringWithFormat: @"%d - %02dh%02dm%02ds",
439                     title->index, title->hours, title->minutes,
440                     title->seconds]];
441                         
442             }
443             // Select the longuest title
444                         [fSrcTitlePopUp selectItemAtIndex: indxpri];
445                         
446             [self TitlePopUpChanged: NULL];
447             [self EnableUI: YES];
448             [fPauseButton setEnabled: NO];
449             [fRipButton   setEnabled: YES];
450             break;
451         }
452 #undef p
453
454 #define p s.param.working
455         case HB_STATE_WORKING:
456         {
457             float progress_total;
458             NSMutableString * string;
459
460             /* Update text field */
461             string = [NSMutableString stringWithFormat:
462                 _( @"Encoding: task %d of %d, %.2f %%" ),
463                 p.job_cur, p.job_count, 100.0 * p.progress];
464             if( p.seconds > -1 )
465             {
466                 [string appendFormat:
467                     _( @" (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)" ),
468                     p.rate_cur, p.rate_avg, p.hours, p.minutes, p.seconds];
469             }
470             [fStatusField setStringValue: string];
471
472             /* Update slider */
473             progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count;
474             [fRipIndicator setIndeterminate: NO];
475             [fRipIndicator setDoubleValue: 100.0 * progress_total];
476
477             /* Update dock icon */
478             [self UpdateDockIcon: progress_total];
479
480             [fPauseButton setEnabled: YES];
481             [fPauseButton setTitle: _( @"Pause" )];
482             [fRipButton setEnabled: YES];
483             [fRipButton setTitle: _( @"Cancel" )];
484             break;
485         }
486 #undef p
487
488 #define p s.param.muxing
489         case HB_STATE_MUXING:
490         {
491             NSMutableString * string;
492                         
493             /* Update text field */
494             string = [NSMutableString stringWithFormat:
495                 _( @"Muxing..." )];
496             [fStatusField setStringValue: string];
497                         
498             /* Update slider */
499             [fRipIndicator setIndeterminate: YES];
500             [fRipIndicator startAnimation: nil];
501                         
502             /* Update dock icon */
503             [self UpdateDockIcon: 1.0];
504                         
505             [fPauseButton setEnabled: YES];
506             [fPauseButton setTitle: _( @"Pause" )];
507             [fRipButton setEnabled: YES];
508             [fRipButton setTitle: _( @"Cancel" )];
509             break;
510         }
511 #undef p
512                         
513         case HB_STATE_PAUSED:
514             [fStatusField setStringValue: _( @"Paused" )];
515             [fPauseButton setEnabled: YES];
516             [fPauseButton setTitle: _( @"Resume" )];
517             [fRipButton setEnabled: YES];
518             [fRipButton setTitle: _( @"Cancel" )];
519             break;
520
521         case HB_STATE_WORKDONE:
522         {
523             [self EnableUI: YES];
524             [fStatusField setStringValue: _( @"Done." )];
525             [fRipIndicator setIndeterminate: NO];
526             [fRipIndicator setDoubleValue: 0.0];
527             [fRipButton setTitle: _( @"Rip" )];
528
529             /* Restore dock icon */
530             [self UpdateDockIcon: -1.0];
531
532             [fPauseButton setEnabled: NO];
533             [fPauseButton setTitle: _( @"Pause" )];
534             [fRipButton setEnabled: YES];
535             [fRipButton setTitle: _( @"Rip" )];
536
537             /* FIXME */
538             hb_job_t * job;
539             while( ( job = hb_job( fHandle, 0 ) ) )
540             {
541                 hb_rem( fHandle, job );
542             }
543             break;
544         }
545     }
546
547     /* FIXME: we should only do that when necessary */
548     if( [fQueueCheck state] == NSOnState )
549     {
550         int count = hb_count( fHandle );
551         if( count )
552         {
553             [fQueueCheck setTitle: [NSString stringWithFormat:
554                 @"Enable queue (%d task%s in queue)",
555                 count, ( count > 1 ) ? "s" : ""]];
556         }
557         else
558         {
559             [fQueueCheck setTitle: @"Enable queue (no task in queue)"];
560         }
561     }
562
563     [[NSRunLoop currentRunLoop] addTimer: [NSTimer
564         scheduledTimerWithTimeInterval: 0.2 target: self
565         selector: @selector( UpdateUI: ) userInfo: NULL repeats: FALSE]
566         forMode: NSModalPanelRunLoopMode];
567 }
568
569 - (void) EnableUI: (bool) b
570 {
571     NSControl * controls[] =
572       { fSrcDVD1Field, fSrcDVD2Field, fSrcTitleField, fSrcTitlePopUp,
573         fSrcChapterField, fSrcChapterStartPopUp, fSrcChapterToField,
574         fSrcChapterEndPopUp, fSrcDuration1Field, fSrcDuration2Field,
575         fDstFormatField, fDstFormatPopUp, fDstCodecsField,
576         fDstCodecsPopUp, fDstFile1Field, fDstFile2Field,
577         fDstBrowseButton, fVidRateField, fVidRatePopUp,
578         fVidEncoderField, fVidEncoderPopUp, fVidQualityField,
579         fVidQualityMatrix, fVidGrayscaleCheck, fSubField, fSubPopUp,
580         fAudLang1Field, fAudLang1PopUp, fAudLang2Field, fAudLang2PopUp,
581         fAudRateField, fAudRatePopUp, fAudBitrateField,
582         fAudBitratePopUp, fPictureButton, fQueueCheck, 
583                 fPicSrcWidth,fPicSrcHeight,fPicSettingWidth,fPicSettingHeight,
584                 fPicSettingARkeep,fPicSettingDeinterlace,fPicSettingARkeepDsply,
585                 fPicSettingDeinterlaceDsply,fPicLabelSettings,fPicLabelSrc,fPicLabelOutp,
586                 fPicLabelAr,fPicLabelDeinter,fPicLabelSrcX,fPicLabelOutputX,
587                 fPicLabelPAROutp,fPicLabelPAROutputX,fPicSettingPARWidth,fPicSettingPARHeight,
588                 fPicSettingPARDsply,fPicLabelAnamorphic,tableView,fPresetsAdd,fPresetsDelete};
589
590     for( unsigned i = 0;
591          i < sizeof( controls ) / sizeof( NSControl * ); i++ )
592     {
593         if( [[controls[i] className] isEqualToString: @"NSTextField"] )
594         {
595             NSTextField * tf = (NSTextField *) controls[i];
596             if( ![tf isBezeled] )
597             {
598                 [tf setTextColor: b ? [NSColor controlTextColor] :
599                     [NSColor disabledControlTextColor]];
600                 continue;
601             }
602         }
603         [controls[i] setEnabled: b];
604
605     }
606
607         /* Temporarily disable Lang2 until crash is fixed */
608         [fAudLang2PopUp setEnabled: NO];
609         [fAudLang2Field setEnabled: NO];
610         
611         if (b) {
612                 /* if we're enabling the interface, check if we should / should't offer 6-channel AAC extraction */
613                 [self Check6ChannelAACExtraction: NULL];
614         } else {
615                 /* if we're disabling the interface, turn it off */
616                 [fAudLang1SurroundCheck setEnabled: NO];
617         }
618
619     [self VideoMatrixChanged: NULL];
620 }
621
622 - (IBAction) ShowScanPanel: (id) sender
623 {
624     [fScanController Show];
625 }
626
627 - (BOOL) windowShouldClose: (id) sender
628 {
629     /* Stop the application when the user closes the window */
630     [NSApp terminate: self];
631     return YES;
632 }
633
634 - (IBAction) VideoMatrixChanged: (id) sender;
635 {
636     bool target, bitrate, quality;
637
638     target = bitrate = quality = false;
639     if( [fVidQualityMatrix isEnabled] )
640     {
641         switch( [fVidQualityMatrix selectedRow] )
642         {
643             case 0:
644                 target = true;
645                 break;
646             case 1:
647                 bitrate = true;
648                 break;
649             case 2:
650                 quality = true;
651                 break;
652         }
653     }
654     [fVidTargetSizeField  setEnabled: target];
655     [fVidBitrateField     setEnabled: bitrate];
656     [fVidQualitySlider    setEnabled: quality];
657     [fVidTwoPassCheck     setEnabled: !quality &&
658         [fVidQualityMatrix isEnabled]];
659     if( quality )
660     {
661         [fVidTwoPassCheck setState: NSOffState];
662     }
663
664     [self QualitySliderChanged: sender];
665     [self CalculateBitrate:     sender];
666 }
667
668 - (IBAction) QualitySliderChanged: (id) sender
669 {
670     [fVidConstantCell setTitle: [NSString stringWithFormat:
671         _( @"Constant quality: %.0f %%" ), 100.0 *
672         [fVidQualitySlider floatValue]]];
673 }
674
675 - (IBAction) BrowseFile: (id) sender
676 {
677     /* Open a panel to let the user choose and update the text field */
678     NSSavePanel * panel = [NSSavePanel savePanel];
679         /* We get the current file name and path from the destination field here */
680         [panel beginSheetForDirectory: [[fDstFile2Field stringValue] stringByDeletingLastPathComponent] file: [[fDstFile2Field stringValue] lastPathComponent]
681                                    modalForWindow: fWindow modalDelegate: self
682                                    didEndSelector: @selector( BrowseFileDone:returnCode:contextInfo: )
683                                           contextInfo: NULL];
684 }
685
686 - (void) BrowseFileDone: (NSSavePanel *) sheet
687     returnCode: (int) returnCode contextInfo: (void *) contextInfo
688 {
689     if( returnCode == NSOKButton )
690     {
691         [fDstFile2Field setStringValue: [sheet filename]];
692                 [self FormatPopUpChanged: NULL];
693     }
694 }
695
696 - (IBAction) ShowPicturePanel: (id) sender
697 {
698     hb_list_t  * list  = hb_get_titles( fHandle );
699     hb_title_t * title = (hb_title_t *) hb_list_item( list,
700             [fSrcTitlePopUp indexOfSelectedItem] );
701
702     /* Resize the panel */
703     NSSize newSize;
704     newSize.width  = 246 + title->width;
705     newSize.height = 80 + title->height;
706     [fPicturePanel setContentSize: newSize];
707
708     [fPictureController SetTitle: title];
709
710     [NSApp beginSheet: fPicturePanel modalForWindow: fWindow
711         modalDelegate: NULL didEndSelector: NULL contextInfo: NULL];
712     [NSApp runModalForWindow: fPicturePanel];
713     [NSApp endSheet: fPicturePanel];
714     [fPicturePanel orderOut: self];
715         [self CalculatePictureSizing: sender];
716 }
717
718 - (IBAction) ShowQueuePanel: (id) sender
719 {
720     /* Update the OutlineView */
721     [fQueueController Update: sender];
722
723     /* Show the panel */
724     [NSApp beginSheet: fQueuePanel modalForWindow: fWindow
725         modalDelegate: NULL didEndSelector: NULL contextInfo: NULL];
726     [NSApp runModalForWindow: fQueuePanel];
727     [NSApp endSheet: fQueuePanel];
728     [fQueuePanel orderOut: self];
729 }
730
731 - (void) PrepareJob
732 {
733     hb_list_t  * list  = hb_get_titles( fHandle );
734     hb_title_t * title = (hb_title_t *) hb_list_item( list,
735             [fSrcTitlePopUp indexOfSelectedItem] );
736     hb_job_t * job = title->job;
737
738     /* Chapter selection */
739     job->chapter_start = [fSrcChapterStartPopUp indexOfSelectedItem] + 1;
740     job->chapter_end   = [fSrcChapterEndPopUp   indexOfSelectedItem] + 1;
741         
742
743
744     /* Format and codecs */
745     int format = [fDstFormatPopUp indexOfSelectedItem];
746     int codecs = [fDstCodecsPopUp indexOfSelectedItem];
747     job->mux    = FormatSettings[format][codecs] & HB_MUX_MASK;
748     job->vcodec = FormatSettings[format][codecs] & HB_VCODEC_MASK;
749     job->acodec = FormatSettings[format][codecs] & HB_ACODEC_MASK;
750
751     if( ( job->vcodec & HB_VCODEC_FFMPEG ) &&
752         [fVidEncoderPopUp indexOfSelectedItem] > 0 )
753     {
754         job->vcodec = HB_VCODEC_XVID;
755     }
756     if( job->vcodec & HB_VCODEC_X264 )
757     {
758          if ([fVidEncoderPopUp indexOfSelectedItem] > 0 )
759             {
760                 /* Just use new Baseline Level 3.0 
761                 Lets Deprecate Baseline Level 1.3*/
762                 job->h264_level = 30;
763                 job->mux = HB_MUX_IPOD;
764                     /* move sanity check for iPod Encoding here */
765                 job->pixel_ratio = 0 ;
766
767                 }
768                 
769                 /* Set this flag to switch from Constant Quantizer(default) to Constant Rate Factor Thanks jbrjake
770                 Currently only used with Constant Quality setting*/
771                         if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultCrf"] > 0 && [fVidQualityMatrix selectedRow] == 2)
772                 {
773                 /* Can only be used with svn rev >= 89 */
774                         job->crf = 1;
775                 }
776                 
777                 /* Sends x264 options to the core library*/
778                 job->x264opts = [[[NSUserDefaults standardUserDefaults] stringForKey:@"DefAdvancedx264Flags"] UTF8String];
779                 
780                 
781         job->h264_13 = [fVidEncoderPopUp indexOfSelectedItem];
782     }
783
784     /* Video settings */
785     if( [fVidRatePopUp indexOfSelectedItem] > 0 )
786     {
787         job->vrate      = 27000000;
788         job->vrate_base = hb_video_rates[[fVidRatePopUp
789             indexOfSelectedItem]-1].rate;
790     }
791     else
792     {
793         job->vrate      = title->rate;
794         job->vrate_base = title->rate_base;
795     }
796
797     switch( [fVidQualityMatrix selectedRow] )
798     {
799         case 0:
800             /* Target size.
801                Bitrate should already have been calculated and displayed
802                in fVidBitrateField, so let's just use it */
803         case 1:
804             job->vquality = -1.0;
805             job->vbitrate = [fVidBitrateField intValue];
806             break;
807         case 2:
808             job->vquality = [fVidQualitySlider floatValue];
809             job->vbitrate = 0;
810             break;
811     }
812
813     job->grayscale = ( [fVidGrayscaleCheck state] == NSOnState );
814     
815
816
817     /* Subtitle settings */
818     job->subtitle = [fSubPopUp indexOfSelectedItem] - 1;
819
820     /* Audio tracks */
821     job->audios[0] = [fAudLang1PopUp indexOfSelectedItem] - 1;
822     job->audios[1] = [fAudLang2PopUp indexOfSelectedItem] - 1;
823     job->audios[2] = -1;
824
825     /* Audio settings */
826     job->arate = hb_audio_rates[[fAudRatePopUp
827                      indexOfSelectedItem]].rate;
828     job->abitrate = hb_audio_bitrates[[fAudBitratePopUp
829                         indexOfSelectedItem]].rate;
830         /* have we selected that 5.1 should be extracted as AAC? */
831         if (job->acodec == HB_ACODEC_FAAC && [fAudLang1SurroundCheck isEnabled] && [fAudLang1SurroundCheck state] == NSOnState) {
832                 job->surround = 1;
833         } else {
834                 job->surround = 0;
835         }
836
837 }
838
839 - (IBAction) EnableQueue: (id) sender
840 {
841     bool e = ( [fQueueCheck state] == NSOnState );
842     [fQueueAddButton  setHidden: !e];
843     [fQueueShowButton setHidden: !e];
844     [fRipButton       setTitle: e ? @"Start" : @"Rip"];
845 }
846
847 - (IBAction) AddToQueue: (id) sender
848 {
849 /* We get the destination directory from the destingation field here */
850         NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent];
851         /* We check for a valid destination here */
852         if ([[NSFileManager defaultManager] fileExistsAtPath:destinationDirectory] == 0) 
853         {
854                 NSRunAlertPanel(@"Warning!", @"This is not a valid destination directory!", @"OK", nil, nil);
855         }
856         else
857         {
858                 
859                 hb_list_t  * list  = hb_get_titles( fHandle );
860                 hb_title_t * title = (hb_title_t *) hb_list_item( list,
861                                                                                                                   [fSrcTitlePopUp indexOfSelectedItem] );
862                 hb_job_t * job = title->job;
863                 
864                 [self PrepareJob];
865                 
866                 /* Destination file */
867                 job->file = [[fDstFile2Field stringValue] UTF8String];
868                 
869                 if( [fVidTwoPassCheck state] == NSOnState )
870                 {
871                         job->pass = 1;
872                         hb_add( fHandle, job );
873                         job->pass = 2;
874                         job->x264opts = [[[NSUserDefaults standardUserDefaults] stringForKey:@"DefAdvancedx264Flags"] UTF8String];
875                         hb_add( fHandle, job );
876                 }
877                 else
878                 {
879                         job->pass = 0;
880                         hb_add( fHandle, job );
881                 }
882         
883         [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"];
884         }
885 }
886
887 - (IBAction) Rip: (id) sender
888 {
889    
890     
891     /* Rip or Cancel ? */
892     if( [[fRipButton title] isEqualToString: _( @"Cancel" )] )
893     {
894         [self Cancel: sender];
895         return;
896     }
897
898     if( [fQueueCheck state] == NSOffState )
899     {
900
901                         [self AddToQueue: sender];
902
903                 
904
905     }
906
907     /* We check for duplicate name here */
908         if( [[NSFileManager defaultManager] fileExistsAtPath:
909             [fDstFile2Field stringValue]] )
910     {
911         NSBeginCriticalAlertSheet( _( @"File already exists" ),
912             _( @"Cancel" ), _( @"Overwrite" ), NULL, fWindow, self,
913             @selector( OverwriteAlertDone:returnCode:contextInfo: ),
914             NULL, NULL, [NSString stringWithFormat:
915             _( @"Do you want to overwrite %@?" ),
916             [fDstFile2Field stringValue]] );
917         return;
918     }
919         /* We get the destination directory from the destingation field here */
920         NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent];
921         /* We check for a valid destination here */
922         if ([[NSFileManager defaultManager] fileExistsAtPath:destinationDirectory] == 0) 
923         {
924                 NSRunAlertPanel(@"Warning!", @"This is not a valid destination directory!", @"OK", nil, nil);
925         }
926         else
927         {
928         [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"];
929                 [self _Rip];
930         }
931         
932
933
934 }
935
936 - (void) OverwriteAlertDone: (NSWindow *) sheet
937     returnCode: (int) returnCode contextInfo: (void *) contextInfo
938 {
939     if( returnCode == NSAlertAlternateReturn )
940     {
941         [self _Rip];
942     }
943 }
944
945 - (void) UpdateAlertDone: (NSWindow *) sheet
946     returnCode: (int) returnCode contextInfo: (void *) contextInfo
947 {
948     if( returnCode == NSAlertAlternateReturn )
949     {
950         /* Show scan panel */
951         [self performSelectorOnMainThread: @selector(ShowScanPanel:)
952             withObject: NULL waitUntilDone: NO];
953         return;
954     }
955
956     /* Go to HandBrake homepage and exit */
957     [self OpenHomepage: NULL];
958     [NSApp terminate: self];
959 }
960
961 - (void) _Rip
962 {
963     /* Let libhb do the job */
964     hb_start( fHandle );
965
966     /* Disable interface */
967    [self EnableUI: NO];
968     [fPauseButton setEnabled: NO];
969     [fRipButton   setEnabled: NO];
970 }
971
972 - (IBAction) Cancel: (id) sender
973 {
974     NSBeginCriticalAlertSheet( _( @"Cancel - Are you sure?" ),
975         _( @"Keep working" ), _( @"Cancel encoding" ), NULL, fWindow, self,
976         @selector( _Cancel:returnCode:contextInfo: ), NULL, NULL,
977         _( @"Encoding won't be recoverable." ) );
978 }
979
980 - (void) _Cancel: (NSWindow *) sheet
981     returnCode: (int) returnCode contextInfo: (void *) contextInfo
982 {
983     if( returnCode == NSAlertAlternateReturn )
984     {
985         hb_stop( fHandle );
986         [fPauseButton setEnabled: NO];
987         [fRipButton   setEnabled: NO];
988     }
989 }
990
991 - (IBAction) Pause: (id) sender
992 {
993     [fPauseButton setEnabled: NO];
994     [fRipButton   setEnabled: NO];
995
996     if( [[fPauseButton title] isEqualToString: _( @"Resume" )] )
997     {
998         hb_resume( fHandle );
999     }
1000     else
1001     {
1002         hb_pause( fHandle );
1003     }
1004 }
1005
1006 - (IBAction) TitlePopUpChanged: (id) sender
1007 {
1008     hb_list_t  * list  = hb_get_titles( fHandle );
1009     hb_title_t * title = (hb_title_t*)
1010         hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
1011
1012
1013     /* Update chapter popups */
1014     [fSrcChapterStartPopUp removeAllItems];
1015     [fSrcChapterEndPopUp   removeAllItems];
1016     for( int i = 0; i < hb_list_count( title->list_chapter ); i++ )
1017     {
1018         [fSrcChapterStartPopUp addItemWithTitle: [NSString
1019             stringWithFormat: @"%d", i + 1]];
1020         [fSrcChapterEndPopUp addItemWithTitle: [NSString
1021             stringWithFormat: @"%d", i + 1]];
1022     }
1023     [fSrcChapterStartPopUp selectItemAtIndex: 0];
1024     [fSrcChapterEndPopUp   selectItemAtIndex:
1025         hb_list_count( title->list_chapter ) - 1];
1026     [self ChapterPopUpChanged: NULL];
1027
1028 /* Start Get and set the initial pic size for display */
1029         hb_job_t * job = title->job;
1030         fTitle = title; 
1031         /*Set Source Size Fields Here */
1032         [fPicSrcWidth setStringValue: [NSString stringWithFormat:
1033                                                          @"%d", fTitle->width]];
1034         [fPicSrcHeight setStringValue: [NSString stringWithFormat:
1035                                                          @"%d", fTitle->height]];
1036         /* Turn Deinterlace on/off depending on the preference */
1037         if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultDeinterlaceOn"] > 0)
1038         {
1039                 job->deinterlace = 1;
1040         }
1041         else
1042         {
1043                 job->deinterlace = 0;
1044         }
1045         
1046         /* Pixel Ratio Setting */
1047         if ([[NSUserDefaults standardUserDefaults] boolForKey:@"PixelRatio"])
1048     {
1049
1050                 job->pixel_ratio = 1 ;
1051         }
1052         else
1053         {
1054                 job->pixel_ratio = 0 ;
1055         }
1056         /* Run Through EncoderPopUpChanged to see if there
1057                 needs to be any pic value modifications based on encoder settings */
1058         [self EncoderPopUpChanged: NULL];
1059         /* END Get and set the initial pic size for display */ 
1060
1061
1062     /* Update subtitle popups */
1063     hb_subtitle_t * subtitle;
1064     [fSubPopUp removeAllItems];
1065     [fSubPopUp addItemWithTitle: @"None"];
1066     for( int i = 0; i < hb_list_count( title->list_subtitle ); i++ )
1067     {
1068         subtitle = (hb_subtitle_t *) hb_list_item( title->list_subtitle, i );
1069
1070         /* We cannot use NSPopUpButton's addItemWithTitle because
1071            it checks for duplicate entries */
1072         [[fSubPopUp menu] addItemWithTitle: [NSString stringWithCString:
1073             subtitle->lang] action: NULL keyEquivalent: @""];
1074     }
1075     [fSubPopUp selectItemAtIndex: 0];
1076
1077     /* START pri */
1078         hb_audio_t * audio;
1079
1080         // PRI CHANGES 02/12/06
1081         NSString * audiotmppri;
1082         NSString * audiosearchpri=[[NSUserDefaults standardUserDefaults] stringForKey:@"DefaultLanguage"];
1083         int indxpri=0;
1084         // End of pri changes 02/12/06
1085     [fAudLang1PopUp removeAllItems];
1086         /* Disable second audio language until crashing is resolved*/
1087         [fAudLang2Field setEnabled: NO];
1088         [fAudLang2PopUp setEnabled: NO];
1089     [fAudLang2PopUp removeAllItems];
1090     [fAudLang1PopUp addItemWithTitle: _( @"None" )];
1091         /* Display Currently Unavailable until crash is fixed */
1092     [fAudLang2PopUp addItemWithTitle: _( @"Currently Unavailable" )];
1093         //[fAudLang2PopUp addItemWithTitle: _( @"None" )];
1094     for( int i = 0; i < hb_list_count( title->list_audio ); i++ )
1095     {
1096         audio = (hb_audio_t *) hb_list_item( title->list_audio, i );
1097         // PRI CHANGES 02/12/06
1098                 if (audiosearchpri!= NULL) 
1099                 {
1100                         audiotmppri=(NSString *) [NSString stringWithCString: audio->lang];
1101                         // Try to find the desired default language
1102                         if ([audiotmppri hasPrefix:audiosearchpri] && indxpri==0)
1103                         {
1104                                 indxpri=i+1;
1105                         }
1106                 }
1107         // End of pri changes 02/12/06
1108
1109         [[fAudLang1PopUp menu] addItemWithTitle:
1110             [NSString stringWithCString: audio->lang]
1111             action: NULL keyEquivalent: @""];
1112        /*
1113            [[fAudLang2PopUp menu] addItemWithTitle:
1114             [NSString stringWithCString: audio->lang]
1115             action: NULL keyEquivalent: @""];
1116                         */
1117     }
1118         // PRI CHANGES 02/12/06
1119         if (indxpri==0) { indxpri=1; }
1120           [fAudLang1PopUp selectItemAtIndex: indxpri];
1121         // End of pri changes 02/12/06
1122     [fAudLang2PopUp selectItemAtIndex: 0];
1123         
1124         /* END pri */
1125
1126         /* changing the title may have changed the audio channels on offer, so */
1127         /* check if this change means we should / should't offer 6-channel AAC extraction */
1128         [self Check6ChannelAACExtraction: sender];
1129
1130 }
1131
1132 - (IBAction) ChapterPopUpChanged: (id) sender
1133 {
1134     hb_list_t  * list  = hb_get_titles( fHandle );
1135     hb_title_t * title = (hb_title_t *)
1136         hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
1137
1138     hb_chapter_t * chapter;
1139     int64_t        duration = 0;
1140     for( int i = [fSrcChapterStartPopUp indexOfSelectedItem];
1141          i <= [fSrcChapterEndPopUp indexOfSelectedItem]; i++ )
1142     {
1143         chapter = (hb_chapter_t *) hb_list_item( title->list_chapter, i );
1144         duration += chapter->duration;
1145     }
1146     
1147     duration /= 90000; /* pts -> seconds */
1148     [fSrcDuration2Field setStringValue: [NSString stringWithFormat:
1149         @"%02lld:%02lld:%02lld", duration / 3600, ( duration / 60 ) % 60,
1150         duration % 60]];
1151
1152     [self CalculateBitrate: sender];
1153 }
1154
1155 - (IBAction) FormatPopUpChanged: (id) sender
1156 {
1157     NSString * string = [fDstFile2Field stringValue];
1158     int format = [fDstFormatPopUp indexOfSelectedItem];
1159     char * ext = NULL;
1160
1161     /* Update the codecs popup */
1162     [fDstCodecsPopUp removeAllItems];
1163     switch( format )
1164     {
1165         case 0:
1166                                 /*Get Default MP4 File Extension*/
1167                                 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultMpegName"] > 0)
1168                                 {
1169                                 ext = "m4v";
1170                                 }
1171                                 else
1172                                 {
1173                                 ext = "mp4";
1174                                 }
1175             [fDstCodecsPopUp addItemWithTitle:
1176                 _( @"MPEG-4 Video / AAC Audio" )];
1177             [fDstCodecsPopUp addItemWithTitle:
1178                 _( @"AVC/H.264 Video / AAC Audio" )];
1179             break;
1180         case 1: 
1181             ext = "avi";
1182             [fDstCodecsPopUp addItemWithTitle:
1183                 _( @"MPEG-4 Video / MP3 Audio" )];
1184             [fDstCodecsPopUp addItemWithTitle:
1185                 _( @"MPEG-4 Video / AC-3 Audio" )];
1186             [fDstCodecsPopUp addItemWithTitle:
1187                 _( @"AVC/H.264 Video / MP3 Audio" )];
1188             [fDstCodecsPopUp addItemWithTitle:
1189                 _( @"AVC/H.264 Video / AC-3 Audio" )];
1190             break;
1191         case 2:
1192             ext = "ogm";
1193             [fDstCodecsPopUp addItemWithTitle:
1194                 _( @"MPEG-4 Video / Vorbis Audio" )];
1195             [fDstCodecsPopUp addItemWithTitle:
1196                 _( @"MPEG-4 Video / MP3 Audio" )];
1197             break;
1198     }
1199     [self CodecsPopUpChanged: NULL];
1200
1201     /* Add/replace to the correct extension */
1202     if( [string characterAtIndex: [string length] - 4] == '.' )
1203     {
1204         [fDstFile2Field setStringValue: [NSString stringWithFormat:
1205             @"%@.%s", [string substringToIndex: [string length] - 4],
1206             ext]];
1207     }
1208     else
1209     {
1210         [fDstFile2Field setStringValue: [NSString stringWithFormat:
1211             @"%@.%s", string, ext]];
1212     }
1213
1214         /* changing the codecs on offer may mean that we are/aren't now offering AAC, so */
1215         /* check if this change means we should / should't offer 6-channel AAC extraction */
1216         [self Check6ChannelAACExtraction: sender];
1217
1218 }
1219
1220 - (IBAction) CodecsPopUpChanged: (id) sender
1221 {
1222     int format = [fDstFormatPopUp indexOfSelectedItem];
1223     int codecs = [fDstCodecsPopUp indexOfSelectedItem];
1224
1225     /* Update the encoder popup */
1226     if( ( FormatSettings[format][codecs] & HB_VCODEC_X264 ) )
1227     {
1228         /* MPEG-4 -> H.264 */
1229         [fVidEncoderPopUp removeAllItems];
1230                 [fVidEncoderPopUp addItemWithTitle: @"x264 (h.264 Main)"];
1231                 [fVidEncoderPopUp addItemWithTitle: @"x264 (h.264 iPod)"];
1232         
1233         
1234     }
1235     else if( ( FormatSettings[format][codecs] & HB_VCODEC_FFMPEG ) )
1236     {
1237         /* H.264 -> MPEG-4 */
1238         [fVidEncoderPopUp removeAllItems];
1239         [fVidEncoderPopUp addItemWithTitle: @"FFmpeg"];
1240         [fVidEncoderPopUp addItemWithTitle: @"XviD"];
1241         [fVidEncoderPopUp selectItemAtIndex: 0];
1242     }
1243
1244     if( FormatSettings[format][codecs] & HB_ACODEC_AC3 )
1245     {
1246         /* AC-3 pass-through: disable samplerate and bitrate */
1247         [fAudRatePopUp    setEnabled: NO];
1248         [fAudBitratePopUp setEnabled: NO];
1249     }
1250     else
1251     {
1252         [fAudRatePopUp    setEnabled: YES];
1253         [fAudBitratePopUp setEnabled: YES];
1254     }
1255
1256         /* check if this change means we should / should't offer 6-channel AAC extraction */
1257         [self Check6ChannelAACExtraction: sender];
1258
1259     [self CalculateBitrate: sender];
1260
1261 }
1262
1263 - (IBAction) EncoderPopUpChanged: (id) sender
1264 {
1265     
1266         /* Check to see if we need to modify the job pic values based on x264 (iPod) encoder selection */
1267     if ([fDstFormatPopUp indexOfSelectedItem] == 0 && [fDstCodecsPopUp indexOfSelectedItem] == 1 && [fVidEncoderPopUp indexOfSelectedItem] == 1)
1268     {
1269         hb_job_t * job = fTitle->job;
1270         job->pixel_ratio = 0 ;
1271         
1272                  if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultPicSizeAutoiPod"] > 0)
1273                  {
1274                  
1275                  if (fTitle->job->width > 640)
1276                                 {
1277                                 fTitle->job->width = 640;
1278                                 }
1279                  fTitle->job->keep_ratio = 1;
1280                  hb_fix_aspect( job, HB_KEEP_WIDTH );
1281                  
1282                  }
1283
1284                 /* uncheck the "export 5.1 as 6-channel AAC" checkbox if it is checked */
1285                 [fAudLang1SurroundCheck setState: NSOffState];
1286
1287         }
1288     
1289         [self CalculatePictureSizing: sender];    
1290   
1291 }
1292
1293 - (IBAction) Check6ChannelAACExtraction: (id) sender
1294 {
1295
1296         /* make sure we have a selected title before continuing */
1297         if (fTitle == NULL) return;
1298
1299         /* get the current title's job into a convenience variable */
1300         hb_job_t * job = fTitle->job;
1301         
1302     /* get the current audio tracks */
1303         /* this is done in PrepareJob too, but we want them here to check against below */
1304     job->audios[0] = [fAudLang1PopUp indexOfSelectedItem] - 1;
1305     job->audios[1] = [fAudLang2PopUp indexOfSelectedItem] - 1;
1306     job->audios[2] = -1;
1307
1308         /* now, let's check if any selected audio track has 5.1 sound */
1309         hb_audio_t * audio;
1310         bool foundfiveoneaudio = false;
1311
1312         /* find out what the currently-selected audio codec is */
1313     int format = [fDstFormatPopUp indexOfSelectedItem];
1314     int codecs = [fDstCodecsPopUp indexOfSelectedItem];
1315         int acodec = FormatSettings[format][codecs] & HB_ACODEC_MASK;
1316
1317         /* we only offer the option to extract 5.1 to 6-channel if the selected audio codec is AAC */
1318         if (acodec == HB_ACODEC_FAAC) {
1319
1320                 bool doneaudios = false;
1321                 int thisaudio = 0;
1322                 
1323                 while (!doneaudios) {
1324
1325                         if (job->audios[thisaudio] == -1) {
1326                                 doneaudios = true;
1327                         } else {
1328                                 audio = (hb_audio_t *) hb_list_item( fTitle->list_audio, job->audios[thisaudio] );
1329                                 if (audio != NULL) {
1330                                         if (audio->channels == 5 && audio->lfechannels == 1) {
1331                                                 foundfiveoneaudio = true;
1332                                                 doneaudios = true; /* as it doesn't matter if we find any more! */
1333                                         }
1334                                 }
1335                         }
1336
1337                         thisaudio++;
1338                 }
1339         }
1340
1341     /* If we are extracting to AAC, and any of our soundtracks were 5.1, then enable the checkbox  */
1342         if (foundfiveoneaudio) {
1343                 [fAudLang1SurroundCheck setEnabled: YES];
1344                 /* Check default surround sound pref and if it is YES, lets also check the checkbox */
1345                 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultSurroundSound"] > 0)
1346                 {
1347                         [fAudLang1SurroundCheck setState: NSOnState];
1348                 }
1349         } else {
1350                 [fAudLang1SurroundCheck setEnabled: NO];
1351                 /* as well as disabling the checkbox, let's uncheck it if it is checked */
1352                 [fAudLang1SurroundCheck setState: NSOffState];
1353         }
1354
1355 }
1356
1357
1358 - (IBAction) LanguagePopUpChanged: (id) sender
1359 {
1360         
1361         /* selecting a different language may mean we have a different number of channels, so */
1362         /* check if this change means we should / should't offer 6-channel AAC extraction */
1363         [self Check6ChannelAACExtraction: sender];
1364         
1365         /* see if the new language setting will change the bitrate we need */
1366     [self CalculateBitrate:     sender];        
1367
1368 }
1369
1370
1371 /* Get and Display Current Pic Settings in main window */
1372 - (IBAction) CalculatePictureSizing: (id) sender
1373 {
1374
1375         hb_job_t * job = fTitle->job;           
1376
1377         [fPicSettingWidth setStringValue: [NSString stringWithFormat:
1378                 @"%d", fTitle->job->width]];
1379         [fPicSettingHeight setStringValue: [NSString stringWithFormat:
1380                 @"%d", fTitle->job->height]];
1381         [fPicSettingARkeep setStringValue: [NSString stringWithFormat:
1382                 @"%d", fTitle->job->keep_ratio]];                
1383         [fPicSettingDeinterlace setStringValue: [NSString stringWithFormat:
1384                 @"%d", fTitle->job->deinterlace]];
1385         [fPicSettingPAR setStringValue: [NSString stringWithFormat:
1386                 @"%d", fTitle->job->pixel_ratio]];
1387                 
1388         if (fTitle->job->pixel_ratio == 1)
1389         {
1390         int titlewidth = fTitle->width-fTitle->job->crop[2]-fTitle->job->crop[3];
1391         int arpwidth = fTitle->job->pixel_aspect_width;
1392         int arpheight = fTitle->job->pixel_aspect_height;
1393         int displayparwidth = titlewidth * arpwidth / arpheight;
1394         int displayparheight = fTitle->height-fTitle->job->crop[0]-fTitle->job->crop[1];
1395         [fPicLabelPAROutp setStringValue: @"Anamorphic Output:"];
1396         [fPicLabelPAROutputX setStringValue: @"x"];
1397     [fPicSettingPARWidth setStringValue: [NSString stringWithFormat:
1398         @"%d", displayparwidth]];
1399         [fPicSettingPARHeight setStringValue: [NSString stringWithFormat:
1400         @"%d", displayparheight]];
1401         [fPicSettingHeight setStringValue: [NSString stringWithFormat:
1402                 @"%d", displayparheight]];
1403         fTitle->job->keep_ratio = 0;
1404         }
1405         else
1406         {
1407         [fPicLabelPAROutp setStringValue: @""];
1408         [fPicLabelPAROutputX setStringValue: @""];
1409         [fPicSettingPARWidth setStringValue: @""];
1410         [fPicSettingPARHeight setStringValue:  @""];
1411         }
1412                 
1413         /* Set ON/Off values for the deinterlace/keep aspect ratio according to boolean */      
1414         if (fTitle->job->keep_ratio > 0)
1415                 {
1416                 [fPicSettingARkeepDsply setStringValue: @"On"];
1417         }
1418                 else
1419                 {
1420                 [fPicSettingARkeepDsply setStringValue: @"Off"];
1421                 }       
1422         if (fTitle->job->deinterlace > 0)
1423                 {
1424                 [fPicSettingDeinterlaceDsply setStringValue: @"On"];
1425         }
1426                 else
1427                 {
1428                 [fPicSettingDeinterlaceDsply setStringValue: @"Off"];
1429                 }
1430         if (fTitle->job->pixel_ratio > 0)
1431                 {
1432                 [fPicSettingPARDsply setStringValue: @"On"];
1433         }
1434                 else
1435                 {
1436                 [fPicSettingPARDsply setStringValue: @"Off"];
1437                 }       
1438                 
1439         
1440 }
1441
1442 - (IBAction) CalculateBitrate: (id) sender
1443 {
1444     if( !fHandle || [fVidQualityMatrix selectedRow] != 0 )
1445     {
1446         return;
1447     }
1448
1449     hb_list_t  * list  = hb_get_titles( fHandle );
1450     hb_title_t * title = (hb_title_t *) hb_list_item( list,
1451             [fSrcTitlePopUp indexOfSelectedItem] );
1452     hb_job_t * job = title->job;
1453
1454     [self PrepareJob];
1455
1456     [fVidBitrateField setIntValue: hb_calc_bitrate( job,
1457             [fVidTargetSizeField intValue] )];
1458 }
1459
1460 - (IBAction) ShowAddPresetPanel: (id) sender
1461 {
1462     /* Show the panel */
1463     [NSApp beginSheet: fAddPresetPanel modalForWindow: fWindow
1464         modalDelegate: NULL didEndSelector: NULL contextInfo: NULL];
1465     [NSApp runModalForWindow: fAddPresetPanel];
1466     [NSApp endSheet: fAddPresetPanel];
1467     [fAddPresetPanel orderOut: self];
1468 }
1469 - (IBAction) CloseAddPresetPanel: (id) sender
1470 {
1471     [NSApp stopModal];
1472 }
1473
1474 - (IBAction)addPreset:(id)sender
1475 {
1476     [UserPresets addObject:[self CreatePreset]];
1477         /* We Sort the Presets Alphabetically by name */
1478         NSSortDescriptor * lastNameDescriptor=[[[NSSortDescriptor alloc] initWithKey:@"PresetName" 
1479                                                     ascending:YES selector:@selector(caseInsensitiveCompare:)] autorelease];
1480         NSArray *sortDescriptors=[NSArray arrayWithObject:lastNameDescriptor];
1481         NSArray *sortedArray=[UserPresets sortedArrayUsingDescriptors:sortDescriptors];
1482         [UserPresets setArray:sortedArray];
1483         
1484         /* We stop the modal window for the new preset */
1485         [fPresetNewName    setStringValue: @""];
1486         [NSApp stopModal];
1487         /* We Reload the New Table data for presets */
1488     [tableView reloadData];
1489    /* We save all of the preset data here */
1490     [self savePreset];
1491 }
1492
1493 - (IBAction)insertPreset:(id)sender
1494 {
1495     int index = [tableView selectedRow];
1496     [UserPresets insertObject:[self CreatePreset] atIndex:index];
1497     [tableView reloadData];
1498     [self savePreset];
1499 }
1500
1501 - (NSDictionary *)CreatePreset
1502 {
1503     NSMutableDictionary *preset = [[NSMutableDictionary alloc] init];
1504         /* Get the New Preset Name from the field in the AddPresetPanel */
1505     [preset setObject:[fPresetNewName stringValue] forKey:@"PresetName"];
1506         /*Get the whether or not to apply pic settings in the AddPresetPanel*/
1507         [preset setObject:[NSNumber numberWithInt:[fPresetNewPicSettingsApply state]] forKey:@"UsesPictureSettings"];
1508         /* File Format */
1509     [preset setObject:[fDstFormatPopUp titleOfSelectedItem] forKey:@"FileFormat"];
1510         /* Codecs */
1511         [preset setObject:[fDstCodecsPopUp titleOfSelectedItem] forKey:@"FileCodecs"];
1512         /* Video encoder */
1513         [preset setObject:[fVidEncoderPopUp titleOfSelectedItem] forKey:@"VideoEncoder"];
1514         /* Video quality */
1515         [preset setObject:[NSNumber numberWithInt:[fVidQualityMatrix selectedRow]] forKey:@"VideoQualityType"];
1516         [preset setObject:[fVidTargetSizeField stringValue] forKey:@"VideoTargetSize"];
1517         [preset setObject:[fVidBitrateField stringValue] forKey:@"VideoAvgBitrate"];
1518         [preset setObject:[NSNumber numberWithFloat:[fVidQualitySlider floatValue]] forKey:@"VideoQualitySlider"];
1519         
1520         /* Video framerate */
1521         [preset setObject:[fVidRatePopUp titleOfSelectedItem] forKey:@"VideoFramerate"];
1522         /* GrayScale */
1523         [preset setObject:[NSNumber numberWithInt:[fVidGrayscaleCheck state]] forKey:@"VideoGrayScale"];
1524         /* 2 Pass Encoding */
1525         [preset setObject:[NSNumber numberWithInt:[fVidTwoPassCheck state]] forKey:@"VideoTwoPass"];
1526         
1527         /*Picture Settings*/
1528         hb_job_t * job = fTitle->job;
1529         /* Basic Picture Settings */
1530         [preset setObject:[NSNumber numberWithInt:fTitle->job->width] forKey:@"PictureWidth"];
1531         [preset setObject:[NSNumber numberWithInt:fTitle->job->height] forKey:@"PictureHeight"];
1532         [preset setObject:[NSNumber numberWithInt:fTitle->job->keep_ratio] forKey:@"PictureKeepRatio"];
1533         [preset setObject:[NSNumber numberWithInt:fTitle->job->deinterlace] forKey:@"PictureDeinterlace"];
1534         [preset setObject:[NSNumber numberWithInt:fTitle->job->pixel_ratio] forKey:@"PicturePAR"];
1535         /* Set crop settings here */
1536         /* The Auto Crop Matrix in the Picture Window autodetects differences in crop settings */
1537         [preset setObject:[NSNumber numberWithInt:job->crop[0]] forKey:@"PictureTopCrop"];
1538     [preset setObject:[NSNumber numberWithInt:job->crop[1]] forKey:@"PictureBottomCrop"];
1539         [preset setObject:[NSNumber numberWithInt:job->crop[2]] forKey:@"PictureLeftCrop"];
1540         [preset setObject:[NSNumber numberWithInt:job->crop[3]] forKey:@"PictureRightCrop"];
1541         
1542         /*Audio*/
1543         /* Audio Language One*/
1544         [preset setObject:[fAudLang1PopUp titleOfSelectedItem] forKey:@"AudioLang1"];
1545         /* Audio Language One Surround Sound Checkbox*/
1546         [preset setObject:[NSNumber numberWithInt:[fAudLang1SurroundCheck state]] forKey:@"AudioLang1Surround"];
1547         /* Audio Sample Rate*/
1548         [preset setObject:[fAudRatePopUp titleOfSelectedItem] forKey:@"AudioSampleRate"];
1549         /* Audio Bitrate Rate*/
1550         [preset setObject:[fAudBitratePopUp titleOfSelectedItem] forKey:@"AudioBitRate"];
1551         /* Subtitles*/
1552         [preset setObject:[fSubPopUp titleOfSelectedItem] forKey:@"Subtitles"];
1553         
1554
1555     [preset autorelease];
1556     return preset;
1557
1558 }
1559
1560 - (IBAction)deletePreset:(id)sender
1561 {
1562     int status;
1563     NSEnumerator *enumerator;
1564     NSNumber *index;
1565     NSMutableArray *tempArray;
1566     id tempObject;
1567     
1568     if ( [tableView numberOfSelectedRows] == 0 )
1569         return;
1570     /* Alert user before deleting preset */
1571         /* Comment out for now, tie to user pref eventually */
1572     //NSBeep();
1573     status = NSRunAlertPanel(@"Warning!", @"Are you sure that you want to delete the selected preset?", @"OK", @"Cancel", nil);
1574     
1575     if ( status == NSAlertDefaultReturn ) {
1576         enumerator = [tableView selectedRowEnumerator];
1577         tempArray = [NSMutableArray array];
1578         
1579         while ( (index = [enumerator nextObject]) ) {
1580             tempObject = [UserPresets objectAtIndex:[index intValue]];
1581             [tempArray addObject:tempObject];
1582         }
1583         
1584         [UserPresets removeObjectsInArray:tempArray];
1585         [tableView reloadData];
1586         [self savePreset];   
1587     }
1588 }
1589 - (IBAction)tableViewSelected:(id)sender
1590 {
1591
1592     /* we get the chosen preset from the UserPresets array */
1593         chosenPreset = [UserPresets objectAtIndex:[sender selectedRow]];
1594         /* we set the preset display field in main window here */
1595         //[fPresetSelectedDisplay setStringValue: [NSString stringWithFormat: @"%@", [chosenPreset valueForKey:@"PresetName"]]];
1596         /* File Format */
1597         [fDstFormatPopUp selectItemWithTitle: [NSString stringWithFormat:[chosenPreset valueForKey:@"FileFormat"]]];
1598         [self FormatPopUpChanged: NULL];
1599     /* Codecs */
1600         [fDstCodecsPopUp selectItemWithTitle: [NSString stringWithFormat:[chosenPreset valueForKey:@"FileCodecs"]]];
1601         [self CodecsPopUpChanged: NULL];
1602         /* Video encoder */
1603         [fVidEncoderPopUp selectItemWithTitle: [NSString stringWithFormat:[chosenPreset valueForKey:@"VideoEncoder"]]];
1604         /* Lets run through the following functions to get variables set there */
1605         [self EncoderPopUpChanged: sender];
1606         [self Check6ChannelAACExtraction: sender];
1607         [self CalculateBitrate: sender];
1608         
1609         /* Video quality */
1610         [fVidQualityMatrix selectCellAtRow:[[chosenPreset objectForKey:@"VideoQualityType"] intValue] column:0];
1611         
1612         [fVidTargetSizeField setStringValue: [NSString stringWithFormat:[chosenPreset valueForKey:@"VideoTargetSize"]]];
1613         [fVidBitrateField setStringValue: [NSString stringWithFormat:[chosenPreset valueForKey:@"VideoAvgBitrate"]]];
1614         
1615         [fVidQualitySlider setFloatValue: [[chosenPreset valueForKey:@"VideoQualitySlider"] floatValue]];
1616         [self VideoMatrixChanged: sender];
1617         
1618         /* Video framerate */
1619         [fVidRatePopUp selectItemWithTitle: [NSString stringWithFormat:[chosenPreset valueForKey:@"VideoFramerate"]]];
1620         
1621         /* GrayScale */
1622         [fVidGrayscaleCheck setState:[[chosenPreset objectForKey:@"VideoGrayScale"] intValue]];
1623
1624         /* 2 Pass Encoding */
1625         [fVidTwoPassCheck setState:[[chosenPreset objectForKey:@"VideoTwoPass"] intValue]];
1626     
1627         
1628         /*Audio*/
1629         /* Audio Language One*/
1630         [fAudLang1PopUp selectItemWithTitle: [NSString stringWithFormat:[chosenPreset valueForKey:@"AudioLang1"]]];
1631         /* Audio Language One Surround Sound Checkbox*/
1632         [fAudLang1SurroundCheck setState:[[chosenPreset objectForKey:@"AudioLang1Surround"] intValue]];
1633         [self Check6ChannelAACExtraction: sender];
1634         /* Audio Sample Rate*/
1635         [fAudRatePopUp selectItemWithTitle: [NSString stringWithFormat:[chosenPreset valueForKey:@"AudioSampleRate"]]];
1636         /* Audio Bitrate Rate*/
1637         [fAudBitratePopUp selectItemWithTitle: [NSString stringWithFormat:[chosenPreset valueForKey:@"AudioBitRate"]]];
1638         /*Subtitles*/
1639         [fSubPopUp selectItemWithTitle: [NSString stringWithFormat:[chosenPreset valueForKey:@"Subtitles"]]];
1640         
1641         /* Picture Settings */
1642         /* Look to see if we apply these here in objectForKey:@"UsesPictureSettings"] */
1643         if ([[chosenPreset objectForKey:@"UsesPictureSettings"]  intValue] == 1)
1644         {
1645                 hb_job_t * job = fTitle->job;
1646                 job->width = [[chosenPreset objectForKey:@"PictureWidth"]  intValue];
1647                 job->height = [[chosenPreset objectForKey:@"PictureHeight"]  intValue];
1648                 job->keep_ratio = [[chosenPreset objectForKey:@"PictureKeepRatio"]  intValue];
1649                 if (job->keep_ratio == 1)
1650                 {
1651                         hb_fix_aspect( job, HB_KEEP_WIDTH );
1652                 }
1653                 job->pixel_ratio = [[chosenPreset objectForKey:@"PicturePAR"]  intValue];
1654                 job->crop[0] = [[chosenPreset objectForKey:@"PictureTopCrop"]  intValue];
1655                 job->crop[1] = [[chosenPreset objectForKey:@"PictureBottomCrop"]  intValue];
1656                 job->crop[2] = [[chosenPreset objectForKey:@"PictureLeftCrop"]  intValue];
1657                 job->crop[3] = [[chosenPreset objectForKey:@"PictureRightCrop"]  intValue];
1658                 [self CalculatePictureSizing: sender]; 
1659         }
1660         
1661         // Deselect the currently selected table //
1662         //[tableView deselectRow:[tableView selectedRow]];
1663 }
1664
1665 - (int)numberOfRowsInTableView:(NSTableView *)aTableView
1666 {
1667     return [UserPresets count];
1668 }
1669
1670 - (id)tableView:(NSTableView *)aTableView
1671       objectValueForTableColumn:(NSTableColumn *)aTableColumn
1672       row:(int)rowIndex
1673 {
1674
1675         
1676         
1677         id theRecord, theValue;
1678     
1679     theRecord = [UserPresets objectAtIndex:rowIndex];
1680     theValue = [theRecord objectForKey:[aTableColumn identifier]];
1681     
1682     return theValue;
1683 }
1684
1685 // NSTableDataSource method that we implement to edit values directly in the table...
1686 - (void)tableView:(NSTableView *)aTableView
1687         setObjectValue:(id)anObject
1688         forTableColumn:(NSTableColumn *)aTableColumn
1689         row:(int)rowIndex
1690 {
1691     id theRecord;
1692     
1693     theRecord = [UserPresets objectAtIndex:rowIndex];
1694     [theRecord setObject:anObject forKey:[aTableColumn identifier]];
1695     
1696                 /* We Sort the Presets Alphabetically by name */
1697         NSSortDescriptor * lastNameDescriptor=[[[NSSortDescriptor alloc] initWithKey:@"PresetName" 
1698                                                     ascending:YES selector:@selector(caseInsensitiveCompare:)] autorelease];
1699         NSArray *sortDescriptors=[NSArray arrayWithObject:lastNameDescriptor];
1700         NSArray *sortedArray=[UserPresets sortedArrayUsingDescriptors:sortDescriptors];
1701         [UserPresets setArray:sortedArray];
1702         /* We Reload the New Table data for presets */
1703     [tableView reloadData];
1704    /* We save all of the preset data here */
1705     [self savePreset];
1706 }
1707
1708
1709 - (void)savePreset
1710 {
1711     [UserPresets writeToFile:UserPresetsFile atomically:YES];
1712
1713 }
1714
1715
1716
1717 - (void) controlTextDidBeginEditing: (NSNotification *) notification
1718 {
1719     [self CalculateBitrate: NULL];
1720 }
1721
1722 - (void) controlTextDidEndEditing: (NSNotification *) notification
1723 {
1724     [self CalculateBitrate: NULL];
1725 }
1726
1727 - (void) controlTextDidChange: (NSNotification *) notification
1728 {
1729     [self CalculateBitrate: NULL];
1730 }
1731
1732 - (IBAction) OpenHomepage: (id) sender
1733 {
1734     [[NSWorkspace sharedWorkspace] openURL: [NSURL
1735         URLWithString:@"http://handbrake.m0k.org/"]];
1736 }
1737
1738 - (IBAction) OpenForums: (id) sender
1739 {
1740     [[NSWorkspace sharedWorkspace] openURL: [NSURL
1741         URLWithString:@"http://handbrake.m0k.org/forum/"]];
1742 }
1743
1744
1745
1746 @end