1 /* $Id: Controller.mm,v 1.79 2005/11/04 19:41:32 titer Exp $
3 This file is part of the HandBrake source code.
4 Homepage: <http://handbrake.m0k.org/>.
5 It may be used under the terms of the GNU General Public License. */
7 #include "Controller.h"
9 #define _(a) NSLocalizedString(a,NULL)
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,
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,
25 /*******************************
26 * HBController implementation *
27 *******************************/
28 @implementation HBController
37 - (void) applicationDidFinishLaunching: (NSNotification *) notification
43 fHandle = hb_init( HB_DEBUG_NONE, [[NSUserDefaults
44 standardUserDefaults] boolForKey:@"CheckForUpdates"] );
46 /* Init others controllers */
47 [fScanController SetHandle: fHandle];
48 [fPictureController SetHandle: fHandle];
49 [fQueueController SetHandle: fHandle];
51 /* Call UpdateUI every 2/10 sec */
52 [[NSRunLoop currentRunLoop] addTimer: [NSTimer
53 scheduledTimerWithTimeInterval: 0.2 target: self
54 selector: @selector( UpdateUI: ) userInfo: NULL repeats: FALSE]
55 forMode: NSModalPanelRunLoopMode];
57 if( ( build = hb_check_update( fHandle, &version ) ) > -1 )
59 /* Update available - tell the user */
60 /* TEMPORARILY COMMENT OUT AS UPDATE CHECK IS NOT ACCURATE */
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." ),
72 /* Show scan panel ASAP */
73 [self performSelectorOnMainThread: @selector(ShowScanPanel:)
74 withObject: NULL waitUntilDone: NO];
77 - (NSApplicationTerminateReply) applicationShouldTerminate:
80 if( [[fRipButton title] isEqualToString: _( @"Cancel" )] )
83 return NSTerminateCancel;
88 return NSTerminateNow;
95 [self TranslateStrings];
98 [fDstFormatPopUp removeAllItems];
99 [fDstFormatPopUp addItemWithTitle: _( @"MP4 file" )];
100 [fDstFormatPopUp addItemWithTitle: _( @"AVI file" )];
101 [fDstFormatPopUp addItemWithTitle: _( @"OGM file" )];
102 [fDstFormatPopUp selectItemAtIndex: 0];
104 [self FormatPopUpChanged: NULL];
106 [fDstFile2Field setStringValue: [NSString stringWithFormat:
107 @"%@/Desktop/Movie.mp4", NSHomeDirectory()]];
110 [fVidEncoderPopUp removeAllItems];
111 [fVidEncoderPopUp addItemWithTitle: @"FFmpeg"];
112 [fVidEncoderPopUp addItemWithTitle: @"XviD"];
115 [fVidTargetSizeField setIntValue: 700];
116 [fVidBitrateField setIntValue: 1000];
117 [fVidQualityMatrix selectCell: fVidBitrateCell];
118 [self VideoMatrixChanged: NULL];
120 /* Video framerate */
121 [fVidRatePopUp removeAllItems];
122 [fVidRatePopUp addItemWithTitle: _( @"Same as source" )];
123 for( int i = 0; i < hb_video_rates_count; i++ )
125 [fVidRatePopUp addItemWithTitle:
126 [NSString stringWithCString: hb_video_rates[i].string]];
128 [fVidRatePopUp selectItemAtIndex: 0];
131 [fAudBitratePopUp removeAllItems];
132 for( int i = 0; i < hb_audio_bitrates_count; i++ )
134 [fAudBitratePopUp addItemWithTitle:
135 [NSString stringWithCString: hb_audio_bitrates[i].string]];
137 [fAudBitratePopUp selectItemAtIndex: hb_audio_bitrates_default];
139 /* Audio samplerate */
140 [fAudRatePopUp removeAllItems];
141 for( int i = 0; i < hb_audio_rates_count; i++ )
143 [fAudRatePopUp addItemWithTitle:
144 [NSString stringWithCString: hb_audio_rates[i].string]];
146 [fAudRatePopUp selectItemAtIndex: hb_audio_rates_default];
149 [fStatusField setStringValue: @""];
152 [fPauseButton setEnabled: NO];
153 [fRipButton setEnabled: NO];
156 - (void) TranslateStrings
158 [fSrcDVD1Field setStringValue: _( @"DVD:" )];
159 [fSrcTitleField setStringValue: _( @"Title:" )];
160 [fSrcChapterField setStringValue: _( @"Chapters:" )];
161 [fSrcChapterToField setStringValue: _( @"to" )];
162 [fSrcDuration1Field setStringValue: _( @"Duration:" )];
164 [fDstFormatField setStringValue: _( @"File format:" )];
165 [fDstCodecsField setStringValue: _( @"Codecs:" )];
166 [fDstFile1Field setStringValue: _( @"File:" )];
167 [fDstBrowseButton setTitle: _( @"Browse" )];
169 [fVidRateField setStringValue: _( @"Framerate (fps):" )];
170 [fVidEncoderField setStringValue: _( @"Encoder:" )];
171 [fVidQualityField setStringValue: _( @"Quality:" )];
174 /***********************************************************************
176 ***********************************************************************
177 * Shows a progression bar on the dock icon, filled according to
178 * 'progress' (0.0 <= progress <= 1.0).
179 * Called with progress < 0.0 or progress > 1.0, restores the original
181 **********************************************************************/
182 - (void) UpdateDockIcon: (float) progress
186 NSBitmapImageRep * bmp;
188 uint32_t black = htonl( 0x000000FF );
189 uint32_t red = htonl( 0xFF0000FF );
190 uint32_t white = htonl( 0xFFFFFFFF );
191 int row_start, row_end;
194 /* Get application original icon */
195 icon = [NSImage imageNamed: @"NSApplicationIcon"];
197 if( progress < 0.0 || progress > 1.0 )
199 [NSApp setApplicationIconImage: icon];
203 /* Get it in a raw bitmap form */
204 tiff = [icon TIFFRepresentationUsingCompression:
205 NSTIFFCompressionNone factor: 1.0];
206 bmp = [NSBitmapImageRep imageRepWithData: tiff];
208 /* Draw the progression bar */
209 /* It's pretty simple (ugly?) now, but I'm no designer */
211 row_start = 3 * (int) [bmp size].height / 4;
212 row_end = 7 * (int) [bmp size].height / 8;
214 for( i = row_start; i < row_start + 2; i++ )
216 pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
217 for( j = 0; j < (int) [bmp size].width; j++ )
222 for( i = row_start + 2; i < row_end - 2; i++ )
224 pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
227 for( j = 2; j < (int) [bmp size].width - 2; j++ )
229 if( j < 2 + (int) ( ( [bmp size].width - 4.0 ) * progress ) )
241 for( i = row_end - 2; i < row_end; i++ )
243 pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
244 for( j = 0; j < (int) [bmp size].width; j++ )
250 /* Now update the dock icon */
251 tiff = [bmp TIFFRepresentationUsingCompression:
252 NSTIFFCompressionNone factor: 1.0];
253 icon = [[NSImage alloc] initWithData: tiff];
254 [NSApp setApplicationIconImage: icon];
258 - (void) UpdateUI: (NSTimer *) timer
262 hb_get_state( fHandle, &s );
269 case HB_STATE_SCANNING:
270 [fScanController UpdateUI: &s];
273 #define p s.param.scandone
274 case HB_STATE_SCANDONE:
279 [fScanController UpdateUI: &s];
281 list = hb_get_titles( fHandle );
283 if( !hb_list_count( list ) )
288 [fSrcTitlePopUp removeAllItems];
289 for( int i = 0; i < hb_list_count( list ); i++ )
291 title = (hb_title_t *) hb_list_item( list, i );
292 /*Set DVD Name at top of window*/
293 [fSrcDVD2Field setStringValue: [NSString
294 stringWithUTF8String: title->name]];
296 /* Use the dvd name in the default output field here
297 May want to add code to remove blank spaces for some dvd names*/
298 [fDstFile2Field setStringValue: [NSString stringWithFormat:
299 @"%@/Desktop/%@.mp4", NSHomeDirectory(),[NSString
300 stringWithUTF8String: title->name]]];
302 [fSrcTitlePopUp addItemWithTitle: [NSString
303 stringWithFormat: @"%d - %02dh%02dm%02ds",
304 title->index, title->hours, title->minutes,
312 [self TitlePopUpChanged: NULL];
313 [self EnableUI: YES];
314 [fPauseButton setEnabled: NO];
315 [fRipButton setEnabled: YES];
320 #define p s.param.working
321 case HB_STATE_WORKING:
323 float progress_total;
324 NSMutableString * string;
326 /* Update text field */
327 string = [NSMutableString stringWithFormat:
328 _( @"Encoding: task %d of %d, %.2f %%" ),
329 p.job_cur, p.job_count, 100.0 * p.progress];
332 [string appendFormat:
333 _( @" (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)" ),
334 p.rate_cur, p.rate_avg, p.hours, p.minutes, p.seconds];
336 [fStatusField setStringValue: string];
339 progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count;
340 [fRipIndicator setDoubleValue: 100.0 * progress_total];
342 /* Update dock icon */
343 [self UpdateDockIcon: progress_total];
345 [fPauseButton setEnabled: YES];
346 [fPauseButton setTitle: _( @"Pause" )];
347 [fRipButton setEnabled: YES];
348 [fRipButton setTitle: _( @"Cancel" )];
353 case HB_STATE_PAUSED:
354 [fStatusField setStringValue: _( @"Paused" )];
355 [fPauseButton setEnabled: YES];
356 [fPauseButton setTitle: _( @"Resume" )];
357 [fRipButton setEnabled: YES];
358 [fRipButton setTitle: _( @"Cancel" )];
361 case HB_STATE_WORKDONE:
363 [self EnableUI: YES];
364 [fStatusField setStringValue: _( @"Done." )];
365 [fRipIndicator setDoubleValue: 0.0];
366 [fRipButton setTitle: _( @"Rip" )];
368 /* Restore dock icon */
369 [self UpdateDockIcon: -1.0];
371 [fPauseButton setEnabled: NO];
372 [fPauseButton setTitle: _( @"Pause" )];
373 [fRipButton setEnabled: YES];
374 [fRipButton setTitle: _( @"Rip" )];
378 while( ( job = hb_job( fHandle, 0 ) ) )
380 hb_rem( fHandle, job );
386 /* FIXME: we should only do that when necessary */
387 if( [fQueueCheck state] == NSOnState )
389 int count = hb_count( fHandle );
392 [fQueueCheck setTitle: [NSString stringWithFormat:
393 @"Enable queue (%d task%s in queue)",
394 count, ( count > 1 ) ? "s" : ""]];
398 [fQueueCheck setTitle: @"Enable queue (no task in queue)"];
402 [[NSRunLoop currentRunLoop] addTimer: [NSTimer
403 scheduledTimerWithTimeInterval: 0.2 target: self
404 selector: @selector( UpdateUI: ) userInfo: NULL repeats: FALSE]
405 forMode: NSModalPanelRunLoopMode];
408 - (void) EnableUI: (bool) b
410 NSControl * controls[] =
411 { fSrcDVD1Field, fSrcDVD2Field, fSrcTitleField, fSrcTitlePopUp,
412 fSrcChapterField, fSrcChapterStartPopUp, fSrcChapterToField,
413 fSrcChapterEndPopUp, fSrcDuration1Field, fSrcDuration2Field,
414 fDstFormatField, fDstFormatPopUp, fDstCodecsField,
415 fDstCodecsPopUp, fDstFile1Field, fDstFile2Field,
416 fDstBrowseButton, fVidRateField, fVidRatePopUp,
417 fVidEncoderField, fVidEncoderPopUp, fVidQualityField,
418 fVidQualityMatrix, fVidGrayscaleCheck, fSubField, fSubPopUp,
419 fAudLang1Field, fAudLang1PopUp, fAudLang2Field, fAudLang2PopUp,
420 fAudRateField, fAudRatePopUp, fAudBitrateField,
421 fAudBitratePopUp, fPictureButton };
424 i < sizeof( controls ) / sizeof( NSControl * ); i++ )
426 if( [[controls[i] className] isEqualToString: @"NSTextField"] )
428 NSTextField * tf = (NSTextField *) controls[i];
429 if( ![tf isBezeled] )
431 [tf setTextColor: b ? [NSColor controlTextColor] :
432 [NSColor disabledControlTextColor]];
436 [controls[i] setEnabled: b];
439 [self VideoMatrixChanged: NULL];
442 - (IBAction) ShowScanPanel: (id) sender
444 [fScanController Show];
447 - (BOOL) windowShouldClose: (id) sender
449 /* Stop the application when the user closes the window */
450 [NSApp terminate: self];
454 - (IBAction) VideoMatrixChanged: (id) sender;
456 bool target, bitrate, quality;
458 target = bitrate = quality = false;
459 if( [fVidQualityMatrix isEnabled] )
461 switch( [fVidQualityMatrix selectedRow] )
474 [fVidTargetSizeField setEnabled: target];
475 [fVidBitrateField setEnabled: bitrate];
476 [fVidQualitySlider setEnabled: quality];
477 [fVidTwoPassCheck setEnabled: !quality &&
478 [fVidQualityMatrix isEnabled]];
481 [fVidTwoPassCheck setState: NSOffState];
484 [self QualitySliderChanged: sender];
485 [self CalculateBitrate: sender];
488 - (IBAction) QualitySliderChanged: (id) sender
490 [fVidConstantCell setTitle: [NSString stringWithFormat:
491 _( @"Constant quality: %.0f %%" ), 100.0 *
492 [fVidQualitySlider floatValue]]];
495 - (IBAction) BrowseFile: (id) sender
497 /* Open a panel to let the user choose and update the text field */
498 NSSavePanel * panel = [NSSavePanel savePanel];
500 [panel beginSheetForDirectory: NULL file: NULL
501 modalForWindow: fWindow modalDelegate: self
502 didEndSelector: @selector( BrowseFileDone:returnCode:contextInfo: )
506 - (void) BrowseFileDone: (NSSavePanel *) sheet
507 returnCode: (int) returnCode contextInfo: (void *) contextInfo
509 if( returnCode == NSOKButton )
511 [fDstFile2Field setStringValue: [sheet filename]];
512 [self FormatPopUpChanged: NULL];
516 - (IBAction) ShowPicturePanel: (id) sender
518 hb_list_t * list = hb_get_titles( fHandle );
519 hb_title_t * title = (hb_title_t *) hb_list_item( list,
520 [fSrcTitlePopUp indexOfSelectedItem] );
522 /* Resize the panel */
524 newSize.width = 246 + title->width;
525 newSize.height = 80 + title->height;
526 [fPicturePanel setContentSize: newSize];
528 [fPictureController SetTitle: title];
530 [NSApp beginSheet: fPicturePanel modalForWindow: fWindow
531 modalDelegate: NULL didEndSelector: NULL contextInfo: NULL];
532 [NSApp runModalForWindow: fPicturePanel];
533 [NSApp endSheet: fPicturePanel];
534 [fPicturePanel orderOut: self];
537 - (IBAction) ShowQueuePanel: (id) sender
539 /* Update the OutlineView */
540 [fQueueController Update: sender];
543 [NSApp beginSheet: fQueuePanel modalForWindow: fWindow
544 modalDelegate: NULL didEndSelector: NULL contextInfo: NULL];
545 [NSApp runModalForWindow: fQueuePanel];
546 [NSApp endSheet: fQueuePanel];
547 [fQueuePanel orderOut: self];
552 hb_list_t * list = hb_get_titles( fHandle );
553 hb_title_t * title = (hb_title_t *) hb_list_item( list,
554 [fSrcTitlePopUp indexOfSelectedItem] );
555 hb_job_t * job = title->job;
557 /* Chapter selection */
558 job->chapter_start = [fSrcChapterStartPopUp indexOfSelectedItem] + 1;
559 job->chapter_end = [fSrcChapterEndPopUp indexOfSelectedItem] + 1;
561 /* Format and codecs */
562 int format = [fDstFormatPopUp indexOfSelectedItem];
563 int codecs = [fDstCodecsPopUp indexOfSelectedItem];
564 job->mux = FormatSettings[format][codecs] & HB_MUX_MASK;
565 job->vcodec = FormatSettings[format][codecs] & HB_VCODEC_MASK;
566 job->acodec = FormatSettings[format][codecs] & HB_ACODEC_MASK;
568 if( ( job->vcodec & HB_VCODEC_FFMPEG ) &&
569 [fVidEncoderPopUp indexOfSelectedItem] > 0 )
571 job->vcodec = HB_VCODEC_XVID;
573 if( job->vcodec & HB_VCODEC_X264 )
575 if ([fVidEncoderPopUp indexOfSelectedItem] < 1 )
577 /* Just use new Baseline Level 3.0
578 Lets Deprecate Baseline Level 1.3*/
579 job->h264_level = 30;
580 job->mux = HB_MUX_IPOD;
582 job->h264_13 = [fVidEncoderPopUp indexOfSelectedItem];
586 if( [fVidRatePopUp indexOfSelectedItem] > 0 )
588 job->vrate = 27000000;
589 job->vrate_base = hb_video_rates[[fVidRatePopUp
590 indexOfSelectedItem]-1].rate;
594 job->vrate = title->rate;
595 job->vrate_base = title->rate_base;
598 switch( [fVidQualityMatrix selectedRow] )
602 Bitrate should already have been calculated and displayed
603 in fVidBitrateField, so let's just use it */
605 job->vquality = -1.0;
606 job->vbitrate = [fVidBitrateField intValue];
609 job->vquality = [fVidQualitySlider floatValue];
614 job->grayscale = ( [fVidGrayscaleCheck state] == NSOnState );
616 /* Subtitle settings */
617 job->subtitle = [fSubPopUp indexOfSelectedItem] - 1;
620 job->audios[0] = [fAudLang1PopUp indexOfSelectedItem] - 1;
621 job->audios[1] = [fAudLang2PopUp indexOfSelectedItem] - 1;
625 job->arate = hb_audio_rates[[fAudRatePopUp
626 indexOfSelectedItem]].rate;
627 job->abitrate = hb_audio_bitrates[[fAudBitratePopUp
628 indexOfSelectedItem]].rate;
631 - (IBAction) EnableQueue: (id) sender
633 bool e = ( [fQueueCheck state] == NSOnState );
634 [fQueueAddButton setHidden: !e];
635 [fQueueShowButton setHidden: !e];
636 [fRipButton setTitle: e ? @"Start" : @"Rip"];
639 - (IBAction) AddToQueue: (id) sender
641 hb_list_t * list = hb_get_titles( fHandle );
642 hb_title_t * title = (hb_title_t *) hb_list_item( list,
643 [fSrcTitlePopUp indexOfSelectedItem] );
644 hb_job_t * job = title->job;
648 /* Destination file */
649 job->file = strdup( [[fDstFile2Field stringValue] UTF8String] );
651 if( [fVidTwoPassCheck state] == NSOnState )
654 hb_add( fHandle, job );
656 hb_add( fHandle, job );
661 hb_add( fHandle, job );
665 - (IBAction) Rip: (id) sender
667 /* Rip or Cancel ? */
668 if( [[fRipButton title] isEqualToString: _( @"Cancel" )] )
670 [self Cancel: sender];
674 if( [fQueueCheck state] == NSOffState )
676 [self AddToQueue: sender];
679 if( [[NSFileManager defaultManager] fileExistsAtPath:
680 [fDstFile2Field stringValue]] )
682 NSBeginCriticalAlertSheet( _( @"File already exists" ),
683 _( @"Cancel" ), _( @"Overwrite" ), NULL, fWindow, self,
684 @selector( OverwriteAlertDone:returnCode:contextInfo: ),
685 NULL, NULL, [NSString stringWithFormat:
686 _( @"Do you want to overwrite %@?" ),
687 [fDstFile2Field stringValue]] );
694 - (void) OverwriteAlertDone: (NSWindow *) sheet
695 returnCode: (int) returnCode contextInfo: (void *) contextInfo
697 if( returnCode == NSAlertAlternateReturn )
703 - (void) UpdateAlertDone: (NSWindow *) sheet
704 returnCode: (int) returnCode contextInfo: (void *) contextInfo
706 if( returnCode == NSAlertAlternateReturn )
708 /* Show scan panel */
709 [self performSelectorOnMainThread: @selector(ShowScanPanel:)
710 withObject: NULL waitUntilDone: NO];
714 /* Go to HandBrake homepage and exit */
715 [self OpenHomepage: NULL];
716 [NSApp terminate: self];
721 /* Let libhb do the job */
724 /* Disable interface */
726 [fPauseButton setEnabled: NO];
727 [fRipButton setEnabled: NO];
730 - (IBAction) Cancel: (id) sender
732 NSBeginCriticalAlertSheet( _( @"Cancel - Are you sure?" ),
733 _( @"Keep working" ), _( @"Cancel encoding" ), NULL, fWindow, self,
734 @selector( _Cancel:returnCode:contextInfo: ), NULL, NULL,
735 _( @"Encoding won't be recoverable." ) );
738 - (void) _Cancel: (NSWindow *) sheet
739 returnCode: (int) returnCode contextInfo: (void *) contextInfo
741 if( returnCode == NSAlertAlternateReturn )
744 [fPauseButton setEnabled: NO];
745 [fRipButton setEnabled: NO];
749 - (IBAction) Pause: (id) sender
751 [fPauseButton setEnabled: NO];
752 [fRipButton setEnabled: NO];
754 if( [[fPauseButton title] isEqualToString: _( @"Resume" )] )
756 hb_resume( fHandle );
764 - (IBAction) TitlePopUpChanged: (id) sender
766 hb_list_t * list = hb_get_titles( fHandle );
767 hb_title_t * title = (hb_title_t*)
768 hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
770 /* Update chapter popups */
771 [fSrcChapterStartPopUp removeAllItems];
772 [fSrcChapterEndPopUp removeAllItems];
773 for( int i = 0; i < hb_list_count( title->list_chapter ); i++ )
775 [fSrcChapterStartPopUp addItemWithTitle: [NSString
776 stringWithFormat: @"%d", i + 1]];
777 [fSrcChapterEndPopUp addItemWithTitle: [NSString
778 stringWithFormat: @"%d", i + 1]];
780 [fSrcChapterStartPopUp selectItemAtIndex: 0];
781 [fSrcChapterEndPopUp selectItemAtIndex:
782 hb_list_count( title->list_chapter ) - 1];
783 [self ChapterPopUpChanged: NULL];
785 /* Update subtitle popups */
786 hb_subtitle_t * subtitle;
787 [fSubPopUp removeAllItems];
788 [fSubPopUp addItemWithTitle: @"None"];
789 for( int i = 0; i < hb_list_count( title->list_subtitle ); i++ )
791 subtitle = (hb_subtitle_t *) hb_list_item( title->list_subtitle, i );
793 /* We cannot use NSPopUpButton's addItemWithTitle because
794 it checks for duplicate entries */
795 [[fSubPopUp menu] addItemWithTitle: [NSString stringWithCString:
796 subtitle->lang] action: NULL keyEquivalent: @""];
798 [fSubPopUp selectItemAtIndex: 0];
800 /* Update lang popups */
802 // PRI CHANGES 02/12/06
803 NSString * audiotmppri;
804 NSString * audiosearchpri=[[NSUserDefaults standardUserDefaults] stringForKey:@"DefaultLanguage"];
806 // End of pri changes 02/12/06
807 [fAudLang1PopUp removeAllItems];
808 [fAudLang2PopUp removeAllItems];
809 [fAudLang1PopUp addItemWithTitle: _( @"None" )];
810 [fAudLang2PopUp addItemWithTitle: _( @"None" )];
811 for( int i = 0; i < hb_list_count( title->list_audio ); i++ )
813 audio = (hb_audio_t *) hb_list_item( title->list_audio, i );
814 // PRI CHANGES 02/12/06
815 audiotmppri=(NSString *) [NSString stringWithCString: audio->lang];
816 // Try to find the desired default language
817 if ([audiotmppri hasPrefix:audiosearchpri] && indxpri==0)
821 // End of pri changes 02/12/06
823 [[fAudLang1PopUp menu] addItemWithTitle:
824 [NSString stringWithCString: audio->lang]
825 action: NULL keyEquivalent: @""];
826 [[fAudLang2PopUp menu] addItemWithTitle:
827 [NSString stringWithCString: audio->lang]
828 action: NULL keyEquivalent: @""];
830 // PRI CHANGES 02/12/06
831 if (indxpri==0) { indxpri=1; }
832 [fAudLang1PopUp selectItemAtIndex: indxpri];
833 // End of pri changes 02/12/06
834 [fAudLang2PopUp selectItemAtIndex: 0];
837 - (IBAction) ChapterPopUpChanged: (id) sender
839 hb_list_t * list = hb_get_titles( fHandle );
840 hb_title_t * title = (hb_title_t *)
841 hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
843 hb_chapter_t * chapter;
844 int64_t duration = 0;
845 for( int i = [fSrcChapterStartPopUp indexOfSelectedItem];
846 i <= [fSrcChapterEndPopUp indexOfSelectedItem]; i++ )
848 chapter = (hb_chapter_t *) hb_list_item( title->list_chapter, i );
849 duration += chapter->duration;
852 duration /= 90000; /* pts -> seconds */
853 [fSrcDuration2Field setStringValue: [NSString stringWithFormat:
854 @"%02lld:%02lld:%02lld", duration / 3600, ( duration / 60 ) % 60,
857 [self CalculateBitrate: sender];
860 - (IBAction) FormatPopUpChanged: (id) sender
862 NSString * string = [fDstFile2Field stringValue];
863 int format = [fDstFormatPopUp indexOfSelectedItem];
866 /* Update the codecs popup */
867 [fDstCodecsPopUp removeAllItems];
872 [fDstCodecsPopUp addItemWithTitle:
873 _( @"MPEG-4 Video / AAC Audio" )];
874 [fDstCodecsPopUp addItemWithTitle:
875 _( @"AVC/H.264 Video / AAC Audio" )];
879 [fDstCodecsPopUp addItemWithTitle:
880 _( @"MPEG-4 Video / MP3 Audio" )];
881 [fDstCodecsPopUp addItemWithTitle:
882 _( @"MPEG-4 Video / AC-3 Audio" )];
883 [fDstCodecsPopUp addItemWithTitle:
884 _( @"AVC/H.264 Video / MP3 Audio" )];
885 [fDstCodecsPopUp addItemWithTitle:
886 _( @"AVC/H.264 Video / AC-3 Audio" )];
890 [fDstCodecsPopUp addItemWithTitle:
891 _( @"MPEG-4 Video / Vorbis Audio" )];
892 [fDstCodecsPopUp addItemWithTitle:
893 _( @"MPEG-4 Video / MP3 Audio" )];
896 [self CodecsPopUpChanged: NULL];
898 /* Add/replace to the correct extension */
899 if( [string characterAtIndex: [string length] - 4] == '.' )
901 [fDstFile2Field setStringValue: [NSString stringWithFormat:
902 @"%@.%s", [string substringToIndex: [string length] - 4],
907 [fDstFile2Field setStringValue: [NSString stringWithFormat:
908 @"%@.%s", string, ext]];
912 - (IBAction) CodecsPopUpChanged: (id) sender
914 int format = [fDstFormatPopUp indexOfSelectedItem];
915 int codecs = [fDstCodecsPopUp indexOfSelectedItem];
917 /* Update the encoder popup */
918 if( ( FormatSettings[format][codecs] & HB_VCODEC_X264 ) )
920 /* MPEG-4 -> H.264 */
921 [fVidEncoderPopUp removeAllItems];
922 [fVidEncoderPopUp addItemWithTitle: @"x264 (h.264 Baseline iPod)"];
923 [fVidEncoderPopUp addItemWithTitle: @"x264 (h.264 Main)"];
926 else if( ( FormatSettings[format][codecs] & HB_VCODEC_FFMPEG ) )
928 /* H.264 -> MPEG-4 */
929 [fVidEncoderPopUp removeAllItems];
930 [fVidEncoderPopUp addItemWithTitle: @"FFmpeg"];
931 [fVidEncoderPopUp addItemWithTitle: @"XviD"];
932 [fVidEncoderPopUp selectItemAtIndex: 0];
935 if( FormatSettings[format][codecs] & HB_ACODEC_AC3 )
937 /* AC-3 pass-through: disable samplerate and bitrate */
938 [fAudRatePopUp setEnabled: NO];
939 [fAudBitratePopUp setEnabled: NO];
943 [fAudRatePopUp setEnabled: YES];
944 [fAudBitratePopUp setEnabled: YES];
947 [self CalculateBitrate: sender];
950 - (IBAction) CalculateBitrate: (id) sender
952 if( !fHandle || [fVidQualityMatrix selectedRow] != 0 )
957 hb_list_t * list = hb_get_titles( fHandle );
958 hb_title_t * title = (hb_title_t *) hb_list_item( list,
959 [fSrcTitlePopUp indexOfSelectedItem] );
960 hb_job_t * job = title->job;
964 [fVidBitrateField setIntValue: hb_calc_bitrate( job,
965 [fVidTargetSizeField intValue] )];
968 - (void) controlTextDidBeginEditing: (NSNotification *) notification
970 [self CalculateBitrate: NULL];
973 - (void) controlTextDidEndEditing: (NSNotification *) notification
975 [self CalculateBitrate: NULL];
978 - (void) controlTextDidChange: (NSNotification *) notification
980 [self CalculateBitrate: NULL];
983 - (IBAction) OpenHomepage: (id) sender
985 [[NSWorkspace sharedWorkspace] openURL: [NSURL
986 URLWithString:@"http://handbrake.m0k.org/"]];
989 - (IBAction) OpenForums: (id) sender
991 [[NSWorkspace sharedWorkspace] openURL: [NSURL
992 URLWithString:@"http://handbrake.m0k.org/forum/"]];