OSDN Git Service

Merge the 0.8.0_mpeg4ip branch into the trunk
[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                 /* TEMPORARILY COMMENT OUT AS UPDATE CHECK IS NOT ACCURATE */
62                  /*
63         NSBeginInformationalAlertSheet( _( @"Update is available" ),
64             _( @"Go get it!" ), _( @"Discard" ), NULL, fWindow, self,
65             @selector( UpdateAlertDone:returnCode:contextInfo: ),
66             NULL, NULL, [NSString stringWithFormat:
67             _( @"HandBrake %s (build %d) is now available for download." ),
68             version, build] );
69         return;
70                 */
71     }
72
73     /* Show scan panel ASAP */
74     [self performSelectorOnMainThread: @selector(ShowScanPanel:)
75         withObject: NULL waitUntilDone: NO];
76 }
77
78 - (NSApplicationTerminateReply) applicationShouldTerminate:
79     (NSApplication *) app
80 {
81     if( [[fRipButton title] isEqualToString: _( @"Cancel" )] )
82     {
83         [self Cancel: NULL];
84         return NSTerminateCancel;
85     }
86     
87     /* Clean up */
88     hb_close( &fHandle );
89     return NSTerminateNow;
90 }
91
92 - (void) awakeFromNib
93 {
94     [fWindow center];
95
96     [self TranslateStrings];
97
98     /* Destination box */
99     [fDstFormatPopUp removeAllItems];
100     [fDstFormatPopUp addItemWithTitle: _( @"MP4 file" )];
101     [fDstFormatPopUp addItemWithTitle: _( @"AVI file" )];
102     [fDstFormatPopUp addItemWithTitle: _( @"OGM file" )];
103     [fDstFormatPopUp selectItemAtIndex: 0];
104
105     [self FormatPopUpChanged: NULL];
106
107     [fDstFile2Field setStringValue: [NSString stringWithFormat:
108         @"%@/Desktop/Movie.mp4", NSHomeDirectory()]];
109
110     /* Video encoder */
111     [fVidEncoderPopUp removeAllItems];
112     [fVidEncoderPopUp addItemWithTitle: @"FFmpeg"];
113     [fVidEncoderPopUp addItemWithTitle: @"XviD"];
114
115     /* Video quality */
116     [fVidTargetSizeField setIntValue: 700];
117         [fVidBitrateField    setIntValue: 1000];
118         /* Do we want to force the quality settings if PAR is on ?
119         if ([[NSUserDefaults standardUserDefaults] boolForKey:@"PixelRatio"])
120     {
121         [fVidBitrateField    setIntValue: 1500];
122         [fVidTwoPassCheck    setState: NSOnState];
123     }
124         else
125         {
126         [fVidBitrateField    setIntValue: 1000];
127     }
128         */
129     [fVidQualityMatrix   selectCell: fVidBitrateCell];
130     [self VideoMatrixChanged: NULL];
131
132     /* Video framerate */
133     [fVidRatePopUp removeAllItems];
134     [fVidRatePopUp addItemWithTitle: _( @"Same as source" )];
135     for( int i = 0; i < hb_video_rates_count; i++ )
136     {
137         [fVidRatePopUp addItemWithTitle:
138             [NSString stringWithCString: hb_video_rates[i].string]];
139     }
140     [fVidRatePopUp selectItemAtIndex: 0];
141         
142         /* Picture Settings */
143         [fPicLabelPAROutp setStringValue: @""];
144         [fPicLabelPAROutputX setStringValue: @""];
145         [fPicSettingPARWidth setStringValue: @""];
146         [fPicSettingPARHeight setStringValue:  @""];
147         
148     /* Audio bitrate */
149     [fAudBitratePopUp removeAllItems];
150     for( int i = 0; i < hb_audio_bitrates_count; i++ )
151     {
152         [fAudBitratePopUp addItemWithTitle:
153             [NSString stringWithCString: hb_audio_bitrates[i].string]];
154     }
155     [fAudBitratePopUp selectItemAtIndex: hb_audio_bitrates_default];
156
157     /* Audio samplerate */
158     [fAudRatePopUp removeAllItems];
159     for( int i = 0; i < hb_audio_rates_count; i++ )
160     {
161         [fAudRatePopUp addItemWithTitle:
162             [NSString stringWithCString: hb_audio_rates[i].string]];
163     }
164     [fAudRatePopUp selectItemAtIndex: hb_audio_rates_default];
165
166     /* Bottom */
167     [fStatusField setStringValue: @""];
168
169     [self EnableUI: NO];
170     [fPauseButton setEnabled: NO];
171     [fRipButton setEnabled: NO];
172 }
173
174 - (void) TranslateStrings
175 {
176     [fSrcDVD1Field      setStringValue: _( @"DVD:" )];
177     [fSrcTitleField     setStringValue: _( @"Title:" )];
178     [fSrcChapterField   setStringValue: _( @"Chapters:" )];
179     [fSrcChapterToField setStringValue: _( @"to" )];
180     [fSrcDuration1Field setStringValue: _( @"Duration:" )];
181
182     [fDstFormatField    setStringValue: _( @"File format:" )];
183     [fDstCodecsField    setStringValue: _( @"Codecs:" )];
184     [fDstFile1Field     setStringValue: _( @"File:" )];
185     [fDstBrowseButton   setTitle:       _( @"Browse" )];
186
187     [fVidRateField      setStringValue: _( @"Framerate (fps):" )];
188     [fVidEncoderField   setStringValue: _( @"Encoder:" )];
189     [fVidQualityField   setStringValue: _( @"Quality:" )];
190 }
191
192 /***********************************************************************
193  * UpdateDockIcon
194  ***********************************************************************
195  * Shows a progression bar on the dock icon, filled according to
196  * 'progress' (0.0 <= progress <= 1.0).
197  * Called with progress < 0.0 or progress > 1.0, restores the original
198  * icon.
199  **********************************************************************/
200 - (void) UpdateDockIcon: (float) progress
201 {
202     NSImage * icon;
203     NSData * tiff;
204     NSBitmapImageRep * bmp;
205     uint32_t * pen;
206     uint32_t black = htonl( 0x000000FF );
207     uint32_t red   = htonl( 0xFF0000FF );
208     uint32_t white = htonl( 0xFFFFFFFF );
209     int row_start, row_end;
210     int i, j;
211
212     /* Get application original icon */
213     icon = [NSImage imageNamed: @"NSApplicationIcon"];
214
215     if( progress < 0.0 || progress > 1.0 )
216     {
217         [NSApp setApplicationIconImage: icon];
218         return;
219     }
220
221     /* Get it in a raw bitmap form */
222     tiff = [icon TIFFRepresentationUsingCompression:
223             NSTIFFCompressionNone factor: 1.0];
224     bmp = [NSBitmapImageRep imageRepWithData: tiff];
225     
226     /* Draw the progression bar */
227     /* It's pretty simple (ugly?) now, but I'm no designer */
228
229     row_start = 3 * (int) [bmp size].height / 4;
230     row_end   = 7 * (int) [bmp size].height / 8;
231
232     for( i = row_start; i < row_start + 2; i++ )
233     {
234         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
235         for( j = 0; j < (int) [bmp size].width; j++ )
236         {
237             pen[j] = black;
238         }
239     }
240     for( i = row_start + 2; i < row_end - 2; i++ )
241     {
242         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
243         pen[0] = black;
244         pen[1] = black;
245         for( j = 2; j < (int) [bmp size].width - 2; j++ )
246         {
247             if( j < 2 + (int) ( ( [bmp size].width - 4.0 ) * progress ) )
248             {
249                 pen[j] = red;
250             }
251             else
252             {
253                 pen[j] = white;
254             }
255         }
256         pen[j]   = black;
257         pen[j+1] = black;
258     }
259     for( i = row_end - 2; i < row_end; i++ )
260     {
261         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
262         for( j = 0; j < (int) [bmp size].width; j++ )
263         {
264             pen[j] = black;
265         }
266     }
267
268     /* Now update the dock icon */
269     tiff = [bmp TIFFRepresentationUsingCompression:
270             NSTIFFCompressionNone factor: 1.0];
271     icon = [[NSImage alloc] initWithData: tiff];
272     [NSApp setApplicationIconImage: icon];
273     [icon release];
274 }
275
276 - (void) UpdateUI: (NSTimer *) timer
277 {
278
279     hb_state_t s;
280     hb_get_state( fHandle, &s );
281
282     switch( s.state )
283     {
284         case HB_STATE_IDLE:
285             break;
286
287         case HB_STATE_SCANNING:
288             [fScanController UpdateUI: &s];
289             break;
290
291 #define p s.param.scandone
292         case HB_STATE_SCANDONE:
293         {
294             hb_list_t  * list;
295             hb_title_t * title;
296                         int indxpri=0;    // Used to search the longuest title (default in combobox)
297                         int longuestpri=0; // Used to search the longuest title (default in combobox)
298
299             [fScanController UpdateUI: &s];
300
301             list = hb_get_titles( fHandle );
302
303             if( !hb_list_count( list ) )
304             {
305                 break;
306             }
307
308
309             [fSrcTitlePopUp removeAllItems];
310             for( int i = 0; i < hb_list_count( list ); i++ )
311             {
312                 title = (hb_title_t *) hb_list_item( list, i );
313                 /*Set DVD Name at top of window*/
314                                 [fSrcDVD2Field setStringValue: [NSString
315                   stringWithUTF8String: title->name]];  
316                                 
317                                 /* Use the dvd name in the default output field here 
318                                 May want to add code to remove blank spaces for some dvd names*/
319                                 
320                                 [fDstFile2Field setStringValue: [NSString stringWithFormat:
321                 @"%@/Desktop/%@.mp4", NSHomeDirectory(),[NSString
322                   stringWithUTF8String: title->name]]];
323                 /* Temporarily comment out to fix title selection*/   
324                 if (longuestpri < title->hours*60*60 + title->minutes *60 + title->seconds)
325                 {
326                         longuestpri=title->hours*60*60 + title->minutes *60 + title->seconds;
327                         indxpri=i;
328                 }
329                 
330                                 
331                 int format = [fDstFormatPopUp indexOfSelectedItem];
332                                 char * ext = NULL;
333                                 switch( format )
334                 {
335                  case 0:
336                                          
337                                          /*Get Default MP4 File Extension for mpeg4 (.mp4 or .m4v) from prefs*/
338                                          if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultMpegName"] > 0)
339                                          {
340                                          ext = "m4v";
341                                          }
342                                      else
343                                      {
344                                          ext = "mp4";
345                                          }
346                                         break;
347                                 case 1: 
348                      ext = "avi";
349                                 case 2:
350                                    break;
351                      ext = "ogm";
352                                break;
353                                    }
354                                 
355                                 
356                                 NSString * string = [fDstFile2Field stringValue];
357                                 /* Add/replace File Output name to the correct extension*/
358                                 if( [string characterAtIndex: [string length] - 4] == '.' )
359                                 {
360                                         [fDstFile2Field setStringValue: [NSString stringWithFormat:
361                                                 @"%@.%s", [string substringToIndex: [string length] - 4],
362                                                 ext]];
363                                 }
364                                 else
365                                 {
366                                         [fDstFile2Field setStringValue: [NSString stringWithFormat:
367                                                 @"%@.%s", string, ext]];
368                                 }
369
370                                 
371                             [fSrcTitlePopUp addItemWithTitle: [NSString
372                     stringWithFormat: @"%d - %02dh%02dm%02ds",
373                     title->index, title->hours, title->minutes,
374                     title->seconds]];
375                         
376             }
377             // Select the longuest title
378                         [fSrcTitlePopUp selectItemAtIndex: indxpri];
379                         
380             [self TitlePopUpChanged: NULL];
381             [self EnableUI: YES];
382             [fPauseButton setEnabled: NO];
383             [fRipButton   setEnabled: YES];
384             break;
385         }
386 #undef p
387
388 #define p s.param.working
389         case HB_STATE_WORKING:
390         {
391             float progress_total;
392             NSMutableString * string;
393
394             /* Update text field */
395             string = [NSMutableString stringWithFormat:
396                 _( @"Encoding: task %d of %d, %.2f %%" ),
397                 p.job_cur, p.job_count, 100.0 * p.progress];
398             if( p.seconds > -1 )
399             {
400                 [string appendFormat:
401                     _( @" (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)" ),
402                     p.rate_cur, p.rate_avg, p.hours, p.minutes, p.seconds];
403             }
404             [fStatusField setStringValue: string];
405
406             /* Update slider */
407             progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count;
408             [fRipIndicator setIndeterminate: NO];
409             [fRipIndicator setDoubleValue: 100.0 * progress_total];
410
411             /* Update dock icon */
412             [self UpdateDockIcon: progress_total];
413
414             [fPauseButton setEnabled: YES];
415             [fPauseButton setTitle: _( @"Pause" )];
416             [fRipButton setEnabled: YES];
417             [fRipButton setTitle: _( @"Cancel" )];
418             break;
419         }
420 #undef p
421
422 #define p s.param.muxing
423         case HB_STATE_MUXING:
424         {
425             NSMutableString * string;
426                         
427             /* Update text field */
428             string = [NSMutableString stringWithFormat:
429                 _( @"Muxing..." )];
430             [fStatusField setStringValue: string];
431                         
432             /* Update slider */
433             [fRipIndicator setIndeterminate: YES];
434             [fRipIndicator startAnimation: nil];
435                         
436             /* Update dock icon */
437             [self UpdateDockIcon: 1.0];
438                         
439             [fPauseButton setEnabled: YES];
440             [fPauseButton setTitle: _( @"Pause" )];
441             [fRipButton setEnabled: YES];
442             [fRipButton setTitle: _( @"Cancel" )];
443             break;
444         }
445 #undef p
446                         
447         case HB_STATE_PAUSED:
448             [fStatusField setStringValue: _( @"Paused" )];
449             [fPauseButton setEnabled: YES];
450             [fPauseButton setTitle: _( @"Resume" )];
451             [fRipButton setEnabled: YES];
452             [fRipButton setTitle: _( @"Cancel" )];
453             break;
454
455         case HB_STATE_WORKDONE:
456         {
457             [self EnableUI: YES];
458             [fStatusField setStringValue: _( @"Done." )];
459             [fRipIndicator setIndeterminate: NO];
460             [fRipIndicator setDoubleValue: 0.0];
461             [fRipButton setTitle: _( @"Rip" )];
462
463             /* Restore dock icon */
464             [self UpdateDockIcon: -1.0];
465
466             [fPauseButton setEnabled: NO];
467             [fPauseButton setTitle: _( @"Pause" )];
468             [fRipButton setEnabled: YES];
469             [fRipButton setTitle: _( @"Rip" )];
470
471             /* FIXME */
472             hb_job_t * job;
473             while( ( job = hb_job( fHandle, 0 ) ) )
474             {
475                 hb_rem( fHandle, job );
476             }
477             break;
478         }
479     }
480
481     /* FIXME: we should only do that when necessary */
482     if( [fQueueCheck state] == NSOnState )
483     {
484         int count = hb_count( fHandle );
485         if( count )
486         {
487             [fQueueCheck setTitle: [NSString stringWithFormat:
488                 @"Enable queue (%d task%s in queue)",
489                 count, ( count > 1 ) ? "s" : ""]];
490         }
491         else
492         {
493             [fQueueCheck setTitle: @"Enable queue (no task in queue)"];
494         }
495     }
496
497     [[NSRunLoop currentRunLoop] addTimer: [NSTimer
498         scheduledTimerWithTimeInterval: 0.2 target: self
499         selector: @selector( UpdateUI: ) userInfo: NULL repeats: FALSE]
500         forMode: NSModalPanelRunLoopMode];
501 }
502
503 - (void) EnableUI: (bool) b
504 {
505     NSControl * controls[] =
506       { fSrcDVD1Field, fSrcDVD2Field, fSrcTitleField, fSrcTitlePopUp,
507         fSrcChapterField, fSrcChapterStartPopUp, fSrcChapterToField,
508         fSrcChapterEndPopUp, fSrcDuration1Field, fSrcDuration2Field,
509         fDstFormatField, fDstFormatPopUp, fDstCodecsField,
510         fDstCodecsPopUp, fDstFile1Field, fDstFile2Field,
511         fDstBrowseButton, fVidRateField, fVidRatePopUp,
512         fVidEncoderField, fVidEncoderPopUp, fVidQualityField,
513         fVidQualityMatrix, fVidGrayscaleCheck, fSubField, fSubPopUp,
514         fAudLang1Field, fAudLang1PopUp, fAudLang2Field, fAudLang2PopUp,
515         fAudRateField, fAudRatePopUp, fAudBitrateField,
516         fAudBitratePopUp, fPictureButton, fQueueCheck, 
517                 fPicSrcWidth,fPicSrcHeight,fPicSettingWidth,fPicSettingHeight,
518                 fPicSettingARkeep,fPicSettingDeinterlace,fPicSettingARkeepDsply,
519                 fPicSettingDeinterlaceDsply,fPicLabelSettings,fPicLabelSrc,fPicLabelOutp,
520                 fPicLabelAr,fPicLabelDeinter,fPicLabelSrcX,fPicLabelOutputX,
521                 fPicLabelPAROutp,fPicLabelPAROutputX,fPicSettingPARWidth,fPicSettingPARHeight,
522                 fPicSettingPARDsply,fPicLabelAnamorphic};
523
524     for( unsigned i = 0;
525          i < sizeof( controls ) / sizeof( NSControl * ); i++ )
526     {
527         if( [[controls[i] className] isEqualToString: @"NSTextField"] )
528         {
529             NSTextField * tf = (NSTextField *) controls[i];
530             if( ![tf isBezeled] )
531             {
532                 [tf setTextColor: b ? [NSColor controlTextColor] :
533                     [NSColor disabledControlTextColor]];
534                 continue;
535             }
536         }
537         [controls[i] setEnabled: b];
538                 /* Temporarily disable Lang2 until crash is fixed */
539                 [fAudLang2PopUp setEnabled: NO];
540                 [fAudLang2Field setEnabled: NO];
541         
542     }
543
544     [self VideoMatrixChanged: NULL];
545 }
546
547 - (IBAction) ShowScanPanel: (id) sender
548 {
549     [fScanController Show];
550 }
551
552 - (BOOL) windowShouldClose: (id) sender
553 {
554     /* Stop the application when the user closes the window */
555     [NSApp terminate: self];
556     return YES;
557 }
558
559 - (IBAction) VideoMatrixChanged: (id) sender;
560 {
561     bool target, bitrate, quality;
562
563     target = bitrate = quality = false;
564     if( [fVidQualityMatrix isEnabled] )
565     {
566         switch( [fVidQualityMatrix selectedRow] )
567         {
568             case 0:
569                 target = true;
570                 break;
571             case 1:
572                 bitrate = true;
573                 break;
574             case 2:
575                 quality = true;
576                 break;
577         }
578     }
579     [fVidTargetSizeField  setEnabled: target];
580     [fVidBitrateField     setEnabled: bitrate];
581     [fVidQualitySlider    setEnabled: quality];
582     [fVidTwoPassCheck     setEnabled: !quality &&
583         [fVidQualityMatrix isEnabled]];
584     if( quality )
585     {
586         [fVidTwoPassCheck setState: NSOffState];
587     }
588
589     [self QualitySliderChanged: sender];
590     [self CalculateBitrate:     sender];
591 }
592
593 - (IBAction) QualitySliderChanged: (id) sender
594 {
595     [fVidConstantCell setTitle: [NSString stringWithFormat:
596         _( @"Constant quality: %.0f %%" ), 100.0 *
597         [fVidQualitySlider floatValue]]];
598 }
599
600 - (IBAction) BrowseFile: (id) sender
601 {
602     /* Open a panel to let the user choose and update the text field */
603     NSSavePanel * panel = [NSSavePanel savePanel];
604
605     [panel beginSheetForDirectory: NULL file: NULL
606         modalForWindow: fWindow modalDelegate: self
607         didEndSelector: @selector( BrowseFileDone:returnCode:contextInfo: )
608         contextInfo: NULL];
609 }
610
611 - (void) BrowseFileDone: (NSSavePanel *) sheet
612     returnCode: (int) returnCode contextInfo: (void *) contextInfo
613 {
614     if( returnCode == NSOKButton )
615     {
616         [fDstFile2Field setStringValue: [sheet filename]];
617         [self FormatPopUpChanged: NULL];
618     }
619 }
620
621 - (IBAction) ShowPicturePanel: (id) sender
622 {
623     hb_list_t  * list  = hb_get_titles( fHandle );
624     hb_title_t * title = (hb_title_t *) hb_list_item( list,
625             [fSrcTitlePopUp indexOfSelectedItem] );
626
627     /* Resize the panel */
628     NSSize newSize;
629     newSize.width  = 246 + title->width;
630     newSize.height = 80 + title->height;
631     [fPicturePanel setContentSize: newSize];
632
633     [fPictureController SetTitle: title];
634
635     [NSApp beginSheet: fPicturePanel modalForWindow: fWindow
636         modalDelegate: NULL didEndSelector: NULL contextInfo: NULL];
637     [NSApp runModalForWindow: fPicturePanel];
638     [NSApp endSheet: fPicturePanel];
639     [fPicturePanel orderOut: self];
640         [self CalculatePictureSizing: sender];
641 }
642
643 - (IBAction) ShowQueuePanel: (id) sender
644 {
645     /* Update the OutlineView */
646     [fQueueController Update: sender];
647
648     /* Show the panel */
649     [NSApp beginSheet: fQueuePanel modalForWindow: fWindow
650         modalDelegate: NULL didEndSelector: NULL contextInfo: NULL];
651     [NSApp runModalForWindow: fQueuePanel];
652     [NSApp endSheet: fQueuePanel];
653     [fQueuePanel orderOut: self];
654 }
655
656 - (void) PrepareJob
657 {
658     hb_list_t  * list  = hb_get_titles( fHandle );
659     hb_title_t * title = (hb_title_t *) hb_list_item( list,
660             [fSrcTitlePopUp indexOfSelectedItem] );
661     hb_job_t * job = title->job;
662
663     /* Chapter selection */
664     job->chapter_start = [fSrcChapterStartPopUp indexOfSelectedItem] + 1;
665     job->chapter_end   = [fSrcChapterEndPopUp   indexOfSelectedItem] + 1;
666         
667
668
669     /* Format and codecs */
670     int format = [fDstFormatPopUp indexOfSelectedItem];
671     int codecs = [fDstCodecsPopUp indexOfSelectedItem];
672     job->mux    = FormatSettings[format][codecs] & HB_MUX_MASK;
673     job->vcodec = FormatSettings[format][codecs] & HB_VCODEC_MASK;
674     job->acodec = FormatSettings[format][codecs] & HB_ACODEC_MASK;
675
676     if( ( job->vcodec & HB_VCODEC_FFMPEG ) &&
677         [fVidEncoderPopUp indexOfSelectedItem] > 0 )
678     {
679         job->vcodec = HB_VCODEC_XVID;
680     }
681     if( job->vcodec & HB_VCODEC_X264 )
682     {
683          if ([fVidEncoderPopUp indexOfSelectedItem] > 0 )
684             {
685                 /* Just use new Baseline Level 3.0 
686                 Lets Deprecate Baseline Level 1.3*/
687                 job->h264_level = 30;
688                 job->mux = HB_MUX_IPOD;
689         /* move sanity check for iPod Encoding here */
690                 job->pixel_ratio = 0 ;
691
692                 }
693                 
694                 /* Set this flag to switch from Constant Quantizer(default) to Constant Rate Factor Thanks jbrjake
695                 Currently only used with Constant Quality setting*/
696                         if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultCrf"] > 0 && [fVidQualityMatrix selectedRow] == 2)
697                 {
698                 /* Can only be used with svn rev >= 89 */
699                         job->crf = 1;
700                 }
701                 
702         job->h264_13 = [fVidEncoderPopUp indexOfSelectedItem];
703     }
704
705     /* Video settings */
706     if( [fVidRatePopUp indexOfSelectedItem] > 0 )
707     {
708         job->vrate      = 27000000;
709         job->vrate_base = hb_video_rates[[fVidRatePopUp
710             indexOfSelectedItem]-1].rate;
711     }
712     else
713     {
714         job->vrate      = title->rate;
715         job->vrate_base = title->rate_base;
716     }
717
718     switch( [fVidQualityMatrix selectedRow] )
719     {
720         case 0:
721             /* Target size.
722                Bitrate should already have been calculated and displayed
723                in fVidBitrateField, so let's just use it */
724         case 1:
725             job->vquality = -1.0;
726             job->vbitrate = [fVidBitrateField intValue];
727             break;
728         case 2:
729             job->vquality = [fVidQualitySlider floatValue];
730             job->vbitrate = 0;
731             break;
732     }
733
734     job->grayscale = ( [fVidGrayscaleCheck state] == NSOnState );
735     
736
737
738     /* Subtitle settings */
739     job->subtitle = [fSubPopUp indexOfSelectedItem] - 1;
740
741     /* Audio tracks */
742     job->audios[0] = [fAudLang1PopUp indexOfSelectedItem] - 1;
743     job->audios[1] = [fAudLang2PopUp indexOfSelectedItem] - 1;
744     job->audios[2] = -1;
745
746     /* Audio settings */
747     job->arate = hb_audio_rates[[fAudRatePopUp
748                      indexOfSelectedItem]].rate;
749     job->abitrate = hb_audio_bitrates[[fAudBitratePopUp
750                         indexOfSelectedItem]].rate;
751 }
752
753 - (IBAction) EnableQueue: (id) sender
754 {
755     bool e = ( [fQueueCheck state] == NSOnState );
756     [fQueueAddButton  setHidden: !e];
757     [fQueueShowButton setHidden: !e];
758     [fRipButton       setTitle: e ? @"Start" : @"Rip"];
759 }
760
761 - (IBAction) AddToQueue: (id) sender
762 {
763     hb_list_t  * list  = hb_get_titles( fHandle );
764     hb_title_t * title = (hb_title_t *) hb_list_item( list,
765             [fSrcTitlePopUp indexOfSelectedItem] );
766     hb_job_t * job = title->job;
767
768     [self PrepareJob];
769
770     /* Destination file */
771     job->file = strdup( [[fDstFile2Field stringValue] UTF8String] );
772
773     if( [fVidTwoPassCheck state] == NSOnState )
774     {
775         job->pass = 1;
776         hb_add( fHandle, job );
777         job->pass = 2;
778         hb_add( fHandle, job );
779     }
780     else
781     {
782         job->pass = 0;
783         hb_add( fHandle, job );
784     }
785 }
786
787 - (IBAction) Rip: (id) sender
788 {
789     /* Rip or Cancel ? */
790     if( [[fRipButton title] isEqualToString: _( @"Cancel" )] )
791     {
792         [self Cancel: sender];
793         return;
794     }
795
796     if( [fQueueCheck state] == NSOffState )
797     {
798         [self AddToQueue: sender];
799     }
800
801     if( [[NSFileManager defaultManager] fileExistsAtPath:
802             [fDstFile2Field stringValue]] )
803     {
804         NSBeginCriticalAlertSheet( _( @"File already exists" ),
805             _( @"Cancel" ), _( @"Overwrite" ), NULL, fWindow, self,
806             @selector( OverwriteAlertDone:returnCode:contextInfo: ),
807             NULL, NULL, [NSString stringWithFormat:
808             _( @"Do you want to overwrite %@?" ),
809             [fDstFile2Field stringValue]] );
810         return;
811     }
812
813     [self _Rip];
814 }
815
816 - (void) OverwriteAlertDone: (NSWindow *) sheet
817     returnCode: (int) returnCode contextInfo: (void *) contextInfo
818 {
819     if( returnCode == NSAlertAlternateReturn )
820     {
821         [self _Rip];
822     }
823 }
824
825 - (void) UpdateAlertDone: (NSWindow *) sheet
826     returnCode: (int) returnCode contextInfo: (void *) contextInfo
827 {
828     if( returnCode == NSAlertAlternateReturn )
829     {
830         /* Show scan panel */
831         [self performSelectorOnMainThread: @selector(ShowScanPanel:)
832             withObject: NULL waitUntilDone: NO];
833         return;
834     }
835
836     /* Go to HandBrake homepage and exit */
837     [self OpenHomepage: NULL];
838     [NSApp terminate: self];
839 }
840
841 - (void) _Rip
842 {
843     /* Let libhb do the job */
844     hb_start( fHandle );
845
846     /* Disable interface */
847     [self EnableUI: NO];
848     [fPauseButton setEnabled: NO];
849     [fRipButton   setEnabled: NO];
850 }
851
852 - (IBAction) Cancel: (id) sender
853 {
854     NSBeginCriticalAlertSheet( _( @"Cancel - Are you sure?" ),
855         _( @"Keep working" ), _( @"Cancel encoding" ), NULL, fWindow, self,
856         @selector( _Cancel:returnCode:contextInfo: ), NULL, NULL,
857         _( @"Encoding won't be recoverable." ) );
858 }
859
860 - (void) _Cancel: (NSWindow *) sheet
861     returnCode: (int) returnCode contextInfo: (void *) contextInfo
862 {
863     if( returnCode == NSAlertAlternateReturn )
864     {
865         hb_stop( fHandle );
866         [fPauseButton setEnabled: NO];
867         [fRipButton   setEnabled: NO];
868     }
869 }
870
871 - (IBAction) Pause: (id) sender
872 {
873     [fPauseButton setEnabled: NO];
874     [fRipButton   setEnabled: NO];
875
876     if( [[fPauseButton title] isEqualToString: _( @"Resume" )] )
877     {
878         hb_resume( fHandle );
879     }
880     else
881     {
882         hb_pause( fHandle );
883     }
884 }
885
886 - (IBAction) TitlePopUpChanged: (id) sender
887 {
888     hb_list_t  * list  = hb_get_titles( fHandle );
889     hb_title_t * title = (hb_title_t*)
890         hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
891
892
893     /* Update chapter popups */
894     [fSrcChapterStartPopUp removeAllItems];
895     [fSrcChapterEndPopUp   removeAllItems];
896     for( int i = 0; i < hb_list_count( title->list_chapter ); i++ )
897     {
898         [fSrcChapterStartPopUp addItemWithTitle: [NSString
899             stringWithFormat: @"%d", i + 1]];
900         [fSrcChapterEndPopUp addItemWithTitle: [NSString
901             stringWithFormat: @"%d", i + 1]];
902     }
903     [fSrcChapterStartPopUp selectItemAtIndex: 0];
904     [fSrcChapterEndPopUp   selectItemAtIndex:
905         hb_list_count( title->list_chapter ) - 1];
906     [self ChapterPopUpChanged: NULL];
907
908 /* Start Get and set the initial pic size for display */
909         hb_job_t * job = title->job;
910         fTitle = title; 
911         /*Set Source Size Fields Here */
912         [fPicSrcWidth setStringValue: [NSString stringWithFormat:
913                                                          @"%d", fTitle->width]];
914         [fPicSrcHeight setStringValue: [NSString stringWithFormat:
915                                                          @"%d", fTitle->height]];
916         /* Turn Deinterlace on/off depending on the preference */
917         if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultDeinterlaceOn"] > 0)
918         {
919                 job->deinterlace = 1;
920         }
921         else
922         {
923                 job->deinterlace = 0;
924         }
925         
926         /* Pixel Ratio Setting */
927         if ([[NSUserDefaults standardUserDefaults] boolForKey:@"PixelRatio"])
928     {
929
930                 job->pixel_ratio = 1 ;
931         }
932         else
933         {
934                 job->pixel_ratio = 0 ;
935         }
936         /* Run Through EncoderPopUpChanged to see if there
937                 needs to be any pic value modifications based on encoder settings */
938         [self EncoderPopUpChanged: NULL];
939         /* END Get and set the initial pic size for display */ 
940
941
942     /* Update subtitle popups */
943     hb_subtitle_t * subtitle;
944     [fSubPopUp removeAllItems];
945     [fSubPopUp addItemWithTitle: @"None"];
946     for( int i = 0; i < hb_list_count( title->list_subtitle ); i++ )
947     {
948         subtitle = (hb_subtitle_t *) hb_list_item( title->list_subtitle, i );
949
950         /* We cannot use NSPopUpButton's addItemWithTitle because
951            it checks for duplicate entries */
952         [[fSubPopUp menu] addItemWithTitle: [NSString stringWithCString:
953             subtitle->lang] action: NULL keyEquivalent: @""];
954     }
955     [fSubPopUp selectItemAtIndex: 0];
956
957     /* START pri */
958         hb_audio_t * audio;
959
960         // PRI CHANGES 02/12/06
961         NSString * audiotmppri;
962         NSString * audiosearchpri=[[NSUserDefaults standardUserDefaults] stringForKey:@"DefaultLanguage"];
963         int indxpri=0;
964         // End of pri changes 02/12/06
965     [fAudLang1PopUp removeAllItems];
966         /* Disable second audio language until crashing is resolved*/
967         [fAudLang2Field setEnabled: NO];
968         [fAudLang2PopUp setEnabled: NO];
969     [fAudLang2PopUp removeAllItems];
970     [fAudLang1PopUp addItemWithTitle: _( @"None" )];
971         /* Display Currently Unavailable until crash is fixed */
972     [fAudLang2PopUp addItemWithTitle: _( @"Currently Unavailable" )];
973         //[fAudLang2PopUp addItemWithTitle: _( @"None" )];
974     for( int i = 0; i < hb_list_count( title->list_audio ); i++ )
975     {
976         audio = (hb_audio_t *) hb_list_item( title->list_audio, i );
977         // PRI CHANGES 02/12/06
978                 if (audiosearchpri!= NULL) 
979                 {
980                         audiotmppri=(NSString *) [NSString stringWithCString: audio->lang];
981                         // Try to find the desired default language
982                         if ([audiotmppri hasPrefix:audiosearchpri] && indxpri==0)
983                         {
984                                 indxpri=i+1;
985                         }
986                 }
987         // End of pri changes 02/12/06
988
989         [[fAudLang1PopUp menu] addItemWithTitle:
990             [NSString stringWithCString: audio->lang]
991             action: NULL keyEquivalent: @""];
992        /*
993            [[fAudLang2PopUp menu] addItemWithTitle:
994             [NSString stringWithCString: audio->lang]
995             action: NULL keyEquivalent: @""];
996                         */
997     }
998         // PRI CHANGES 02/12/06
999         if (indxpri==0) { indxpri=1; }
1000           [fAudLang1PopUp selectItemAtIndex: indxpri];
1001         // End of pri changes 02/12/06
1002     [fAudLang2PopUp selectItemAtIndex: 0];
1003         
1004         /* END pri */
1005 }
1006
1007 - (IBAction) ChapterPopUpChanged: (id) sender
1008 {
1009     hb_list_t  * list  = hb_get_titles( fHandle );
1010     hb_title_t * title = (hb_title_t *)
1011         hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
1012
1013     hb_chapter_t * chapter;
1014     int64_t        duration = 0;
1015     for( int i = [fSrcChapterStartPopUp indexOfSelectedItem];
1016          i <= [fSrcChapterEndPopUp indexOfSelectedItem]; i++ )
1017     {
1018         chapter = (hb_chapter_t *) hb_list_item( title->list_chapter, i );
1019         duration += chapter->duration;
1020     }
1021     
1022     duration /= 90000; /* pts -> seconds */
1023     [fSrcDuration2Field setStringValue: [NSString stringWithFormat:
1024         @"%02lld:%02lld:%02lld", duration / 3600, ( duration / 60 ) % 60,
1025         duration % 60]];
1026
1027     [self CalculateBitrate: sender];
1028 }
1029
1030 - (IBAction) FormatPopUpChanged: (id) sender
1031 {
1032     NSString * string = [fDstFile2Field stringValue];
1033     int format = [fDstFormatPopUp indexOfSelectedItem];
1034     char * ext = NULL;
1035
1036     /* Update the codecs popup */
1037     [fDstCodecsPopUp removeAllItems];
1038     switch( format )
1039     {
1040         case 0:
1041                                 /*Get Default MP4 File Extension*/
1042                                 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultMpegName"] > 0)
1043                                 {
1044                                 ext = "m4v";
1045                                 }
1046                                 else
1047                                 {
1048                                 ext = "mp4";
1049                                 }
1050             [fDstCodecsPopUp addItemWithTitle:
1051                 _( @"MPEG-4 Video / AAC Audio" )];
1052             [fDstCodecsPopUp addItemWithTitle:
1053                 _( @"AVC/H.264 Video / AAC Audio" )];
1054             break;
1055         case 1: 
1056             ext = "avi";
1057             [fDstCodecsPopUp addItemWithTitle:
1058                 _( @"MPEG-4 Video / MP3 Audio" )];
1059             [fDstCodecsPopUp addItemWithTitle:
1060                 _( @"MPEG-4 Video / AC-3 Audio" )];
1061             [fDstCodecsPopUp addItemWithTitle:
1062                 _( @"AVC/H.264 Video / MP3 Audio" )];
1063             [fDstCodecsPopUp addItemWithTitle:
1064                 _( @"AVC/H.264 Video / AC-3 Audio" )];
1065             break;
1066         case 2:
1067             ext = "ogm";
1068             [fDstCodecsPopUp addItemWithTitle:
1069                 _( @"MPEG-4 Video / Vorbis Audio" )];
1070             [fDstCodecsPopUp addItemWithTitle:
1071                 _( @"MPEG-4 Video / MP3 Audio" )];
1072             break;
1073     }
1074     [self CodecsPopUpChanged: NULL];
1075
1076     /* Add/replace to the correct extension */
1077     if( [string characterAtIndex: [string length] - 4] == '.' )
1078     {
1079         [fDstFile2Field setStringValue: [NSString stringWithFormat:
1080             @"%@.%s", [string substringToIndex: [string length] - 4],
1081             ext]];
1082     }
1083     else
1084     {
1085         [fDstFile2Field setStringValue: [NSString stringWithFormat:
1086             @"%@.%s", string, ext]];
1087     }
1088 }
1089
1090 - (IBAction) CodecsPopUpChanged: (id) sender
1091 {
1092     int format = [fDstFormatPopUp indexOfSelectedItem];
1093     int codecs = [fDstCodecsPopUp indexOfSelectedItem];
1094
1095     /* Update the encoder popup */
1096     if( ( FormatSettings[format][codecs] & HB_VCODEC_X264 ) )
1097     {
1098         /* MPEG-4 -> H.264 */
1099         [fVidEncoderPopUp removeAllItems];
1100                 [fVidEncoderPopUp addItemWithTitle: @"x264 (h.264 Main)"];
1101                 [fVidEncoderPopUp addItemWithTitle: @"x264 (h.264 iPod)"];
1102         
1103         
1104     }
1105     else if( ( FormatSettings[format][codecs] & HB_VCODEC_FFMPEG ) )
1106     {
1107         /* H.264 -> MPEG-4 */
1108         [fVidEncoderPopUp removeAllItems];
1109         [fVidEncoderPopUp addItemWithTitle: @"FFmpeg"];
1110         [fVidEncoderPopUp addItemWithTitle: @"XviD"];
1111         [fVidEncoderPopUp selectItemAtIndex: 0];
1112     }
1113
1114     if( FormatSettings[format][codecs] & HB_ACODEC_AC3 )
1115     {
1116         /* AC-3 pass-through: disable samplerate and bitrate */
1117         [fAudRatePopUp    setEnabled: NO];
1118         [fAudBitratePopUp setEnabled: NO];
1119     }
1120     else
1121     {
1122         [fAudRatePopUp    setEnabled: YES];
1123         [fAudBitratePopUp setEnabled: YES];
1124     }
1125
1126     [self CalculateBitrate: sender];
1127 }
1128
1129 - (IBAction) EncoderPopUpChanged: (id) sender
1130 {
1131     
1132         /* Check to see if we need to modify the job pic values based on x264 (iPod) encoder selection */
1133     if ([fDstFormatPopUp indexOfSelectedItem] == 0 && [fVidEncoderPopUp indexOfSelectedItem] == 1)
1134     {
1135         hb_job_t * job = fTitle->job;
1136         job->pixel_ratio = 0 ;
1137         
1138                  if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultPicSizeAutoiPod"] > 0)
1139                  {
1140                  
1141                  if (fTitle->job->width > 640)
1142                                 {
1143                                 fTitle->job->width = 640;
1144                                 }
1145                  fTitle->job->keep_ratio = 1;
1146                  hb_fix_aspect( job, HB_KEEP_WIDTH );
1147                  
1148                  }
1149         }
1150     
1151 [self CalculatePictureSizing: sender];    
1152   
1153 }
1154
1155 /* Get and Display Current Pic Settings in main window */
1156 - (IBAction) CalculatePictureSizing: (id) sender
1157 {
1158
1159         hb_job_t * job = fTitle->job;           
1160
1161         [fPicSettingWidth setStringValue: [NSString stringWithFormat:
1162                 @"%d", fTitle->job->width]];
1163         [fPicSettingHeight setStringValue: [NSString stringWithFormat:
1164                 @"%d", fTitle->job->height]];
1165         [fPicSettingARkeep setStringValue: [NSString stringWithFormat:
1166                 @"%d", fTitle->job->keep_ratio]];                
1167         [fPicSettingDeinterlace setStringValue: [NSString stringWithFormat:
1168                 @"%d", fTitle->job->deinterlace]];
1169         [fPicSettingPAR setStringValue: [NSString stringWithFormat:
1170                 @"%d", fTitle->job->pixel_ratio]];
1171                 
1172         if (fTitle->job->pixel_ratio == 1)
1173         {
1174         int titlewidth = fTitle->width-fTitle->job->crop[2]-fTitle->job->crop[3];
1175         int arpwidth = fTitle->job->pixel_aspect_width;
1176         int arpheight = fTitle->job->pixel_aspect_height;
1177         int displayparwidth = titlewidth * arpwidth / arpheight;
1178         int displayparheight = fTitle->height-fTitle->job->crop[0]-fTitle->job->crop[1];
1179         [fPicLabelPAROutp setStringValue: @"Anamorphic Output:"];
1180         [fPicLabelPAROutputX setStringValue: @"x"];
1181     [fPicSettingPARWidth setStringValue: [NSString stringWithFormat:
1182         @"%d", displayparwidth]];
1183         [fPicSettingPARHeight setStringValue: [NSString stringWithFormat:
1184         @"%d", displayparheight]];
1185         [fPicSettingHeight setStringValue: [NSString stringWithFormat:
1186                 @"%d", displayparheight]];
1187         fTitle->job->keep_ratio = 0;
1188         }
1189         else
1190         {
1191         [fPicLabelPAROutp setStringValue: @""];
1192         [fPicLabelPAROutputX setStringValue: @""];
1193         [fPicSettingPARWidth setStringValue: @""];
1194         [fPicSettingPARHeight setStringValue:  @""];
1195         }
1196                 
1197         /* Set ON/Off values for the deinterlace/keep aspect ratio according to boolean */      
1198         if (fTitle->job->keep_ratio > 0)
1199                 {
1200                 [fPicSettingARkeepDsply setStringValue: @"On"];
1201         }
1202                 else
1203                 {
1204                 [fPicSettingARkeepDsply setStringValue: @"Off"];
1205                 }       
1206         if (fTitle->job->deinterlace > 0)
1207                 {
1208                 [fPicSettingDeinterlaceDsply setStringValue: @"On"];
1209         }
1210                 else
1211                 {
1212                 [fPicSettingDeinterlaceDsply setStringValue: @"Off"];
1213                 }
1214         if (fTitle->job->pixel_ratio > 0)
1215                 {
1216                 [fPicSettingPARDsply setStringValue: @"On"];
1217         }
1218                 else
1219                 {
1220                 [fPicSettingPARDsply setStringValue: @"Off"];
1221                 }       
1222                 
1223         
1224 }
1225
1226 - (IBAction) CalculateBitrate: (id) sender
1227 {
1228     if( !fHandle || [fVidQualityMatrix selectedRow] != 0 )
1229     {
1230         return;
1231     }
1232
1233     hb_list_t  * list  = hb_get_titles( fHandle );
1234     hb_title_t * title = (hb_title_t *) hb_list_item( list,
1235             [fSrcTitlePopUp indexOfSelectedItem] );
1236     hb_job_t * job = title->job;
1237
1238     [self PrepareJob];
1239
1240     [fVidBitrateField setIntValue: hb_calc_bitrate( job,
1241             [fVidTargetSizeField intValue] )];
1242 }
1243
1244 - (void) controlTextDidBeginEditing: (NSNotification *) notification
1245 {
1246     [self CalculateBitrate: NULL];
1247 }
1248
1249 - (void) controlTextDidEndEditing: (NSNotification *) notification
1250 {
1251     [self CalculateBitrate: NULL];
1252 }
1253
1254 - (void) controlTextDidChange: (NSNotification *) notification
1255 {
1256     [self CalculateBitrate: NULL];
1257 }
1258
1259 - (IBAction) OpenHomepage: (id) sender
1260 {
1261     [[NSWorkspace sharedWorkspace] openURL: [NSURL
1262         URLWithString:@"http://mediafork.dynalias.com/"]];
1263 }
1264
1265 - (IBAction) OpenForums: (id) sender
1266 {
1267     [[NSWorkspace sharedWorkspace] openURL: [NSURL
1268         URLWithString:@"http://mediafork.dynalias.com/forum/"]];
1269 }
1270
1271 @end