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 NSBeginInformationalAlertSheet( _( @"Update is available" ),
61 _( @"Go get it!" ), _( @"Discard" ), NULL, fWindow, self,
62 @selector( UpdateAlertDone:returnCode:contextInfo: ),
63 NULL, NULL, [NSString stringWithFormat:
64 _( @"HandBrake %s (build %d) is now available for download." ),
69 /* Show scan panel ASAP */
70 [self performSelectorOnMainThread: @selector(ShowScanPanel:)
71 withObject: NULL waitUntilDone: NO];
74 - (NSApplicationTerminateReply) applicationShouldTerminate:
77 if( [[fRipButton title] isEqualToString: _( @"Cancel" )] )
80 return NSTerminateCancel;
85 return NSTerminateNow;
92 [self TranslateStrings];
95 [fDstFormatPopUp removeAllItems];
96 [fDstFormatPopUp addItemWithTitle: _( @"MP4 file" )];
97 [fDstFormatPopUp addItemWithTitle: _( @"AVI file" )];
98 [fDstFormatPopUp addItemWithTitle: _( @"OGM file" )];
99 [fDstFormatPopUp selectItemAtIndex: 0];
101 [self FormatPopUpChanged: NULL];
103 [fDstFile2Field setStringValue: [NSString stringWithFormat:
104 @"%@/Desktop/Movie.mp4", NSHomeDirectory()]];
107 [fVidEncoderPopUp removeAllItems];
108 [fVidEncoderPopUp addItemWithTitle: @"FFmpeg"];
109 [fVidEncoderPopUp addItemWithTitle: @"XviD"];
112 [fVidTargetSizeField setIntValue: 700];
113 [fVidBitrateField setIntValue: 1000];
114 [fVidQualityMatrix selectCell: fVidBitrateCell];
115 [self VideoMatrixChanged: NULL];
117 /* Video framerate */
118 [fVidRatePopUp removeAllItems];
119 [fVidRatePopUp addItemWithTitle: _( @"Same as source" )];
120 for( int i = 0; i < hb_video_rates_count; i++ )
122 [fVidRatePopUp addItemWithTitle:
123 [NSString stringWithCString: hb_video_rates[i].string]];
125 [fVidRatePopUp selectItemAtIndex: 0];
128 [fAudBitratePopUp removeAllItems];
129 for( int i = 0; i < hb_audio_bitrates_count; i++ )
131 [fAudBitratePopUp addItemWithTitle:
132 [NSString stringWithCString: hb_audio_bitrates[i].string]];
134 [fAudBitratePopUp selectItemAtIndex: hb_audio_bitrates_default];
136 /* Audio samplerate */
137 [fAudRatePopUp removeAllItems];
138 for( int i = 0; i < hb_audio_rates_count; i++ )
140 [fAudRatePopUp addItemWithTitle:
141 [NSString stringWithCString: hb_audio_rates[i].string]];
143 [fAudRatePopUp selectItemAtIndex: hb_audio_rates_default];
146 [fStatusField setStringValue: @""];
149 [fPauseButton setEnabled: NO];
150 [fRipButton setEnabled: NO];
153 - (void) TranslateStrings
155 [fSrcDVD1Field setStringValue: _( @"DVD:" )];
156 [fSrcTitleField setStringValue: _( @"Title:" )];
157 [fSrcChapterField setStringValue: _( @"Chapters:" )];
158 [fSrcChapterToField setStringValue: _( @"to" )];
159 [fSrcDuration1Field setStringValue: _( @"Duration:" )];
161 [fDstFormatField setStringValue: _( @"File format:" )];
162 [fDstCodecsField setStringValue: _( @"Codecs:" )];
163 [fDstFile1Field setStringValue: _( @"File:" )];
164 [fDstBrowseButton setTitle: _( @"Browse" )];
166 [fVidRateField setStringValue: _( @"Framerate (fps):" )];
167 [fVidEncoderField setStringValue: _( @"Encoder:" )];
168 [fVidQualityField setStringValue: _( @"Quality:" )];
171 /***********************************************************************
173 ***********************************************************************
174 * Shows a progression bar on the dock icon, filled according to
175 * 'progress' (0.0 <= progress <= 1.0).
176 * Called with progress < 0.0 or progress > 1.0, restores the original
178 **********************************************************************/
179 - (void) UpdateDockIcon: (float) progress
183 NSBitmapImageRep * bmp;
185 uint32_t black = htonl( 0x000000FF );
186 uint32_t red = htonl( 0xFF0000FF );
187 uint32_t white = htonl( 0xFFFFFFFF );
188 int row_start, row_end;
191 /* Get application original icon */
192 icon = [NSImage imageNamed: @"NSApplicationIcon"];
194 if( progress < 0.0 || progress > 1.0 )
196 [NSApp setApplicationIconImage: icon];
200 /* Get it in a raw bitmap form */
201 tiff = [icon TIFFRepresentationUsingCompression:
202 NSTIFFCompressionNone factor: 1.0];
203 bmp = [NSBitmapImageRep imageRepWithData: tiff];
205 /* Draw the progression bar */
206 /* It's pretty simple (ugly?) now, but I'm no designer */
208 row_start = 3 * (int) [bmp size].height / 4;
209 row_end = 7 * (int) [bmp size].height / 8;
211 for( i = row_start; i < row_start + 2; i++ )
213 pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
214 for( j = 0; j < (int) [bmp size].width; j++ )
219 for( i = row_start + 2; i < row_end - 2; i++ )
221 pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
224 for( j = 2; j < (int) [bmp size].width - 2; j++ )
226 if( j < 2 + (int) ( ( [bmp size].width - 4.0 ) * progress ) )
238 for( i = row_end - 2; i < row_end; i++ )
240 pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
241 for( j = 0; j < (int) [bmp size].width; j++ )
247 /* Now update the dock icon */
248 tiff = [bmp TIFFRepresentationUsingCompression:
249 NSTIFFCompressionNone factor: 1.0];
250 icon = [[NSImage alloc] initWithData: tiff];
251 [NSApp setApplicationIconImage: icon];
255 - (void) UpdateUI: (NSTimer *) timer
259 hb_get_state( fHandle, &s );
266 case HB_STATE_SCANNING:
267 [fScanController UpdateUI: &s];
270 #define p s.param.scandone
271 case HB_STATE_SCANDONE:
276 [fScanController UpdateUI: &s];
278 list = hb_get_titles( fHandle );
280 if( !hb_list_count( list ) )
285 [fSrcTitlePopUp removeAllItems];
286 for( int i = 0; i < hb_list_count( list ); i++ )
288 title = (hb_title_t *) hb_list_item( list, i );
289 [fSrcDVD2Field setStringValue: [NSString
290 stringWithUTF8String: title->name]];
292 [fSrcTitlePopUp addItemWithTitle: [NSString
293 stringWithFormat: @"%d - %02dh%02dm%02ds",
294 title->index, title->hours, title->minutes,
298 [self TitlePopUpChanged: NULL];
299 [self EnableUI: YES];
300 [fPauseButton setEnabled: NO];
301 [fRipButton setEnabled: YES];
306 #define p s.param.working
307 case HB_STATE_WORKING:
309 float progress_total;
310 NSMutableString * string;
312 /* Update text field */
313 string = [NSMutableString stringWithFormat:
314 _( @"Encoding: task %d of %d, %.2f %%" ),
315 p.job_cur, p.job_count, 100.0 * p.progress];
318 [string appendFormat:
319 _( @" (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)" ),
320 p.rate_cur, p.rate_avg, p.hours, p.minutes, p.seconds];
322 [fStatusField setStringValue: string];
325 progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count;
326 [fRipIndicator setDoubleValue: 100.0 * progress_total];
328 /* Update dock icon */
329 [self UpdateDockIcon: progress_total];
331 [fPauseButton setEnabled: YES];
332 [fPauseButton setTitle: _( @"Pause" )];
333 [fRipButton setEnabled: YES];
334 [fRipButton setTitle: _( @"Cancel" )];
339 case HB_STATE_PAUSED:
340 [fStatusField setStringValue: _( @"Paused" )];
341 [fPauseButton setEnabled: YES];
342 [fPauseButton setTitle: _( @"Resume" )];
343 [fRipButton setEnabled: YES];
344 [fRipButton setTitle: _( @"Cancel" )];
347 case HB_STATE_WORKDONE:
349 [self EnableUI: YES];
350 [fStatusField setStringValue: _( @"Done." )];
351 [fRipIndicator setDoubleValue: 0.0];
352 [fRipButton setTitle: _( @"Rip" )];
354 /* Restore dock icon */
355 [self UpdateDockIcon: -1.0];
357 [fPauseButton setEnabled: NO];
358 [fPauseButton setTitle: _( @"Pause" )];
359 [fRipButton setEnabled: YES];
360 [fRipButton setTitle: _( @"Rip" )];
364 while( ( job = hb_job( fHandle, 0 ) ) )
366 hb_rem( fHandle, job );
372 /* FIXME: we should only do that when necessary */
373 if( [fQueueCheck state] == NSOnState )
375 int count = hb_count( fHandle );
378 [fQueueCheck setTitle: [NSString stringWithFormat:
379 @"Enable queue (%d task%s in queue)",
380 count, ( count > 1 ) ? "s" : ""]];
384 [fQueueCheck setTitle: @"Enable queue (no task in queue)"];
388 [[NSRunLoop currentRunLoop] addTimer: [NSTimer
389 scheduledTimerWithTimeInterval: 0.2 target: self
390 selector: @selector( UpdateUI: ) userInfo: NULL repeats: FALSE]
391 forMode: NSModalPanelRunLoopMode];
394 - (void) EnableUI: (bool) b
396 NSControl * controls[] =
397 { fSrcDVD1Field, fSrcDVD2Field, fSrcTitleField, fSrcTitlePopUp,
398 fSrcChapterField, fSrcChapterStartPopUp, fSrcChapterToField,
399 fSrcChapterEndPopUp, fSrcDuration1Field, fSrcDuration2Field,
400 fDstFormatField, fDstFormatPopUp, fDstCodecsField,
401 fDstCodecsPopUp, fDstFile1Field, fDstFile2Field,
402 fDstBrowseButton, fVidRateField, fVidRatePopUp,
403 fVidEncoderField, fVidEncoderPopUp, fVidQualityField,
404 fVidQualityMatrix, fVidGrayscaleCheck, fSubField, fSubPopUp,
405 fAudLang1Field, fAudLang1PopUp, fAudLang2Field, fAudLang2PopUp,
406 fAudRateField, fAudRatePopUp, fAudBitrateField,
407 fAudBitratePopUp, fPictureButton };
410 i < sizeof( controls ) / sizeof( NSControl * ); i++ )
412 if( [[controls[i] className] isEqualToString: @"NSTextField"] )
414 NSTextField * tf = (NSTextField *) controls[i];
415 if( ![tf isBezeled] )
417 [tf setTextColor: b ? [NSColor controlTextColor] :
418 [NSColor disabledControlTextColor]];
422 [controls[i] setEnabled: b];
425 [self VideoMatrixChanged: NULL];
428 - (IBAction) ShowScanPanel: (id) sender
430 [fScanController Show];
433 - (BOOL) windowShouldClose: (id) sender
435 /* Stop the application when the user closes the window */
436 [NSApp terminate: self];
440 - (IBAction) VideoMatrixChanged: (id) sender;
442 bool target, bitrate, quality;
444 target = bitrate = quality = false;
445 if( [fVidQualityMatrix isEnabled] )
447 switch( [fVidQualityMatrix selectedRow] )
460 [fVidTargetSizeField setEnabled: target];
461 [fVidBitrateField setEnabled: bitrate];
462 [fVidQualitySlider setEnabled: quality];
463 [fVidTwoPassCheck setEnabled: !quality &&
464 [fVidQualityMatrix isEnabled]];
467 [fVidTwoPassCheck setState: NSOffState];
470 [self QualitySliderChanged: sender];
471 [self CalculateBitrate: sender];
474 - (IBAction) QualitySliderChanged: (id) sender
476 [fVidConstantCell setTitle: [NSString stringWithFormat:
477 _( @"Constant quality: %.0f %%" ), 100.0 *
478 [fVidQualitySlider floatValue]]];
481 - (IBAction) BrowseFile: (id) sender
483 /* Open a panel to let the user choose and update the text field */
484 NSSavePanel * panel = [NSSavePanel savePanel];
486 [panel beginSheetForDirectory: NULL file: NULL
487 modalForWindow: fWindow modalDelegate: self
488 didEndSelector: @selector( BrowseFileDone:returnCode:contextInfo: )
492 - (void) BrowseFileDone: (NSSavePanel *) sheet
493 returnCode: (int) returnCode contextInfo: (void *) contextInfo
495 if( returnCode == NSOKButton )
497 [fDstFile2Field setStringValue: [sheet filename]];
498 [self FormatPopUpChanged: NULL];
502 - (IBAction) ShowPicturePanel: (id) sender
504 hb_list_t * list = hb_get_titles( fHandle );
505 hb_title_t * title = (hb_title_t *) hb_list_item( list,
506 [fSrcTitlePopUp indexOfSelectedItem] );
508 /* Resize the panel */
510 newSize.width = 246 + title->width;
511 newSize.height = 80 + title->height;
512 [fPicturePanel setContentSize: newSize];
514 [fPictureController SetTitle: title];
516 [NSApp beginSheet: fPicturePanel modalForWindow: fWindow
517 modalDelegate: NULL didEndSelector: NULL contextInfo: NULL];
518 [NSApp runModalForWindow: fPicturePanel];
519 [NSApp endSheet: fPicturePanel];
520 [fPicturePanel orderOut: self];
523 - (IBAction) ShowQueuePanel: (id) sender
525 /* Update the OutlineView */
526 [fQueueController Update: sender];
529 [NSApp beginSheet: fQueuePanel modalForWindow: fWindow
530 modalDelegate: NULL didEndSelector: NULL contextInfo: NULL];
531 [NSApp runModalForWindow: fQueuePanel];
532 [NSApp endSheet: fQueuePanel];
533 [fQueuePanel orderOut: self];
538 hb_list_t * list = hb_get_titles( fHandle );
539 hb_title_t * title = (hb_title_t *) hb_list_item( list,
540 [fSrcTitlePopUp indexOfSelectedItem] );
541 hb_job_t * job = title->job;
543 /* Chapter selection */
544 job->chapter_start = [fSrcChapterStartPopUp indexOfSelectedItem] + 1;
545 job->chapter_end = [fSrcChapterEndPopUp indexOfSelectedItem] + 1;
547 /* Format and codecs */
548 int format = [fDstFormatPopUp indexOfSelectedItem];
549 int codecs = [fDstCodecsPopUp indexOfSelectedItem];
550 job->mux = FormatSettings[format][codecs] & HB_MUX_MASK;
551 job->vcodec = FormatSettings[format][codecs] & HB_VCODEC_MASK;
552 job->acodec = FormatSettings[format][codecs] & HB_ACODEC_MASK;
554 if( ( job->vcodec & HB_VCODEC_FFMPEG ) &&
555 [fVidEncoderPopUp indexOfSelectedItem] > 0 )
557 job->vcodec = HB_VCODEC_XVID;
559 if( job->vcodec & HB_VCODEC_X264 )
561 if ([fVidEncoderPopUp indexOfSelectedItem] < 1 )
563 /* Just use new Baseline Level 3.0
564 Lets Deprecate Baseline Level 1.3*/
565 job->h264_level = 30;
566 job->mux = HB_MUX_IPOD;
568 job->h264_13 = [fVidEncoderPopUp indexOfSelectedItem];
572 if( [fVidRatePopUp indexOfSelectedItem] > 0 )
574 job->vrate = 27000000;
575 job->vrate_base = hb_video_rates[[fVidRatePopUp
576 indexOfSelectedItem]-1].rate;
580 job->vrate = title->rate;
581 job->vrate_base = title->rate_base;
584 switch( [fVidQualityMatrix selectedRow] )
588 Bitrate should already have been calculated and displayed
589 in fVidBitrateField, so let's just use it */
591 job->vquality = -1.0;
592 job->vbitrate = [fVidBitrateField intValue];
595 job->vquality = [fVidQualitySlider floatValue];
600 job->grayscale = ( [fVidGrayscaleCheck state] == NSOnState );
602 /* Subtitle settings */
603 job->subtitle = [fSubPopUp indexOfSelectedItem] - 1;
606 job->audios[0] = [fAudLang1PopUp indexOfSelectedItem] - 1;
607 job->audios[1] = [fAudLang2PopUp indexOfSelectedItem] - 1;
611 job->arate = hb_audio_rates[[fAudRatePopUp
612 indexOfSelectedItem]].rate;
613 job->abitrate = hb_audio_bitrates[[fAudBitratePopUp
614 indexOfSelectedItem]].rate;
617 - (IBAction) EnableQueue: (id) sender
619 bool e = ( [fQueueCheck state] == NSOnState );
620 [fQueueAddButton setHidden: !e];
621 [fQueueShowButton setHidden: !e];
622 [fRipButton setTitle: e ? @"Start" : @"Rip"];
625 - (IBAction) AddToQueue: (id) sender
627 hb_list_t * list = hb_get_titles( fHandle );
628 hb_title_t * title = (hb_title_t *) hb_list_item( list,
629 [fSrcTitlePopUp indexOfSelectedItem] );
630 hb_job_t * job = title->job;
634 /* Destination file */
635 job->file = strdup( [[fDstFile2Field stringValue] UTF8String] );
637 if( [fVidTwoPassCheck state] == NSOnState )
640 hb_add( fHandle, job );
642 hb_add( fHandle, job );
647 hb_add( fHandle, job );
651 - (IBAction) Rip: (id) sender
653 /* Rip or Cancel ? */
654 if( [[fRipButton title] isEqualToString: _( @"Cancel" )] )
656 [self Cancel: sender];
660 if( [fQueueCheck state] == NSOffState )
662 [self AddToQueue: sender];
665 if( [[NSFileManager defaultManager] fileExistsAtPath:
666 [fDstFile2Field stringValue]] )
668 NSBeginCriticalAlertSheet( _( @"File already exists" ),
669 _( @"Cancel" ), _( @"Overwrite" ), NULL, fWindow, self,
670 @selector( OverwriteAlertDone:returnCode:contextInfo: ),
671 NULL, NULL, [NSString stringWithFormat:
672 _( @"Do you want to overwrite %@?" ),
673 [fDstFile2Field stringValue]] );
680 - (void) OverwriteAlertDone: (NSWindow *) sheet
681 returnCode: (int) returnCode contextInfo: (void *) contextInfo
683 if( returnCode == NSAlertAlternateReturn )
689 - (void) UpdateAlertDone: (NSWindow *) sheet
690 returnCode: (int) returnCode contextInfo: (void *) contextInfo
692 if( returnCode == NSAlertAlternateReturn )
694 /* Show scan panel */
695 [self performSelectorOnMainThread: @selector(ShowScanPanel:)
696 withObject: NULL waitUntilDone: NO];
700 /* Go to HandBrake homepage and exit */
701 [self OpenHomepage: NULL];
702 [NSApp terminate: self];
707 /* Let libhb do the job */
710 /* Disable interface */
712 [fPauseButton setEnabled: NO];
713 [fRipButton setEnabled: NO];
716 - (IBAction) Cancel: (id) sender
718 NSBeginCriticalAlertSheet( _( @"Cancel - Are you sure?" ),
719 _( @"Keep working" ), _( @"Cancel encoding" ), NULL, fWindow, self,
720 @selector( _Cancel:returnCode:contextInfo: ), NULL, NULL,
721 _( @"Encoding won't be recoverable." ) );
724 - (void) _Cancel: (NSWindow *) sheet
725 returnCode: (int) returnCode contextInfo: (void *) contextInfo
727 if( returnCode == NSAlertAlternateReturn )
730 [fPauseButton setEnabled: NO];
731 [fRipButton setEnabled: NO];
735 - (IBAction) Pause: (id) sender
737 [fPauseButton setEnabled: NO];
738 [fRipButton setEnabled: NO];
740 if( [[fPauseButton title] isEqualToString: _( @"Resume" )] )
742 hb_resume( fHandle );
750 - (IBAction) TitlePopUpChanged: (id) sender
752 hb_list_t * list = hb_get_titles( fHandle );
753 hb_title_t * title = (hb_title_t*)
754 hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
756 /* Update chapter popups */
757 [fSrcChapterStartPopUp removeAllItems];
758 [fSrcChapterEndPopUp removeAllItems];
759 for( int i = 0; i < hb_list_count( title->list_chapter ); i++ )
761 [fSrcChapterStartPopUp addItemWithTitle: [NSString
762 stringWithFormat: @"%d", i + 1]];
763 [fSrcChapterEndPopUp addItemWithTitle: [NSString
764 stringWithFormat: @"%d", i + 1]];
766 [fSrcChapterStartPopUp selectItemAtIndex: 0];
767 [fSrcChapterEndPopUp selectItemAtIndex:
768 hb_list_count( title->list_chapter ) - 1];
769 [self ChapterPopUpChanged: NULL];
771 /* Update subtitle popups */
772 hb_subtitle_t * subtitle;
773 [fSubPopUp removeAllItems];
774 [fSubPopUp addItemWithTitle: @"None"];
775 for( int i = 0; i < hb_list_count( title->list_subtitle ); i++ )
777 subtitle = (hb_subtitle_t *) hb_list_item( title->list_subtitle, i );
779 /* We cannot use NSPopUpButton's addItemWithTitle because
780 it checks for duplicate entries */
781 [[fSubPopUp menu] addItemWithTitle: [NSString stringWithCString:
782 subtitle->lang] action: NULL keyEquivalent: @""];
784 [fSubPopUp selectItemAtIndex: 0];
786 /* Update lang popups */
788 // PRI CHANGES 02/12/06
789 NSString * audiotmppri;
790 NSString * audiosearchpri=[[NSUserDefaults standardUserDefaults] stringForKey:@"DefaultLanguage"];
792 // End of pri changes 02/12/06
793 [fAudLang1PopUp removeAllItems];
794 [fAudLang2PopUp removeAllItems];
795 [fAudLang1PopUp addItemWithTitle: _( @"None" )];
796 [fAudLang2PopUp addItemWithTitle: _( @"None" )];
797 for( int i = 0; i < hb_list_count( title->list_audio ); i++ )
799 audio = (hb_audio_t *) hb_list_item( title->list_audio, i );
800 // PRI CHANGES 02/12/06
801 audiotmppri=(NSString *) [NSString stringWithCString: audio->lang];
802 // Try to find the desired default language
803 if ([audiotmppri hasPrefix:audiosearchpri] && indxpri==0)
807 // End of pri changes 02/12/06
809 [[fAudLang1PopUp menu] addItemWithTitle:
810 [NSString stringWithCString: audio->lang]
811 action: NULL keyEquivalent: @""];
812 [[fAudLang2PopUp menu] addItemWithTitle:
813 [NSString stringWithCString: audio->lang]
814 action: NULL keyEquivalent: @""];
816 // PRI CHANGES 02/12/06
817 if (indxpri==0) { indxpri=1; }
818 [fAudLang1PopUp selectItemAtIndex: indxpri];
819 // End of pri changes 02/12/06
820 [fAudLang2PopUp selectItemAtIndex: 0];
823 - (IBAction) ChapterPopUpChanged: (id) sender
825 hb_list_t * list = hb_get_titles( fHandle );
826 hb_title_t * title = (hb_title_t *)
827 hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
829 hb_chapter_t * chapter;
830 int64_t duration = 0;
831 for( int i = [fSrcChapterStartPopUp indexOfSelectedItem];
832 i <= [fSrcChapterEndPopUp indexOfSelectedItem]; i++ )
834 chapter = (hb_chapter_t *) hb_list_item( title->list_chapter, i );
835 duration += chapter->duration;
838 duration /= 90000; /* pts -> seconds */
839 [fSrcDuration2Field setStringValue: [NSString stringWithFormat:
840 @"%02lld:%02lld:%02lld", duration / 3600, ( duration / 60 ) % 60,
843 [self CalculateBitrate: sender];
846 - (IBAction) FormatPopUpChanged: (id) sender
848 NSString * string = [fDstFile2Field stringValue];
849 int format = [fDstFormatPopUp indexOfSelectedItem];
852 /* Update the codecs popup */
853 [fDstCodecsPopUp removeAllItems];
858 [fDstCodecsPopUp addItemWithTitle:
859 _( @"MPEG-4 Video / AAC Audio" )];
860 [fDstCodecsPopUp addItemWithTitle:
861 _( @"AVC/H.264 Video / AAC Audio" )];
865 [fDstCodecsPopUp addItemWithTitle:
866 _( @"MPEG-4 Video / MP3 Audio" )];
867 [fDstCodecsPopUp addItemWithTitle:
868 _( @"MPEG-4 Video / AC-3 Audio" )];
869 [fDstCodecsPopUp addItemWithTitle:
870 _( @"AVC/H.264 Video / MP3 Audio" )];
871 [fDstCodecsPopUp addItemWithTitle:
872 _( @"AVC/H.264 Video / AC-3 Audio" )];
876 [fDstCodecsPopUp addItemWithTitle:
877 _( @"MPEG-4 Video / Vorbis Audio" )];
878 [fDstCodecsPopUp addItemWithTitle:
879 _( @"MPEG-4 Video / MP3 Audio" )];
882 [self CodecsPopUpChanged: NULL];
884 /* Add/replace to the correct extension */
885 if( [string characterAtIndex: [string length] - 4] == '.' )
887 [fDstFile2Field setStringValue: [NSString stringWithFormat:
888 @"%@.%s", [string substringToIndex: [string length] - 4],
893 [fDstFile2Field setStringValue: [NSString stringWithFormat:
894 @"%@.%s", string, ext]];
898 - (IBAction) CodecsPopUpChanged: (id) sender
900 int format = [fDstFormatPopUp indexOfSelectedItem];
901 int codecs = [fDstCodecsPopUp indexOfSelectedItem];
903 /* Update the encoder popup */
904 if( ( FormatSettings[format][codecs] & HB_VCODEC_X264 ) )
906 /* MPEG-4 -> H.264 */
907 [fVidEncoderPopUp removeAllItems];
908 [fVidEncoderPopUp addItemWithTitle: @"x264 (h.264 Baseline iPod)"];
909 [fVidEncoderPopUp addItemWithTitle: @"x264 (h.264 Main)"];
912 else if( ( FormatSettings[format][codecs] & HB_VCODEC_FFMPEG ) )
914 /* H.264 -> MPEG-4 */
915 [fVidEncoderPopUp removeAllItems];
916 [fVidEncoderPopUp addItemWithTitle: @"FFmpeg"];
917 [fVidEncoderPopUp addItemWithTitle: @"XviD"];
918 [fVidEncoderPopUp selectItemAtIndex: 0];
921 if( FormatSettings[format][codecs] & HB_ACODEC_AC3 )
923 /* AC-3 pass-through: disable samplerate and bitrate */
924 [fAudRatePopUp setEnabled: NO];
925 [fAudBitratePopUp setEnabled: NO];
929 [fAudRatePopUp setEnabled: YES];
930 [fAudBitratePopUp setEnabled: YES];
933 [self CalculateBitrate: sender];
936 - (IBAction) CalculateBitrate: (id) sender
938 if( !fHandle || [fVidQualityMatrix selectedRow] != 0 )
943 hb_list_t * list = hb_get_titles( fHandle );
944 hb_title_t * title = (hb_title_t *) hb_list_item( list,
945 [fSrcTitlePopUp indexOfSelectedItem] );
946 hb_job_t * job = title->job;
950 [fVidBitrateField setIntValue: hb_calc_bitrate( job,
951 [fVidTargetSizeField intValue] )];
954 - (void) controlTextDidBeginEditing: (NSNotification *) notification
956 [self CalculateBitrate: NULL];
959 - (void) controlTextDidEndEditing: (NSNotification *) notification
961 [self CalculateBitrate: NULL];
964 - (void) controlTextDidChange: (NSNotification *) notification
966 [self CalculateBitrate: NULL];
969 - (IBAction) OpenHomepage: (id) sender
971 [[NSWorkspace sharedWorkspace] openURL: [NSURL
972 URLWithString:@"http://handbrake.m0k.org/"]];
975 - (IBAction) OpenForums: (id) sender
977 [[NSWorkspace sharedWorkspace] openURL: [NSURL
978 URLWithString:@"http://handbrake.m0k.org/forum/"]];