summaryrefslogtreecommitdiffstats
path: root/macosx/Controller.mm
diff options
context:
space:
mode:
Diffstat (limited to 'macosx/Controller.mm')
-rw-r--r--macosx/Controller.mm1496
1 files changed, 747 insertions, 749 deletions
diff --git a/macosx/Controller.mm b/macosx/Controller.mm
index eb53a9dd5..a4ba98afe 100644
--- a/macosx/Controller.mm
+++ b/macosx/Controller.mm
@@ -1,229 +1,488 @@
-/* $Id: Controller.mm,v 1.31 2004/04/21 21:21:17 titer Exp $
+/* $Id: Controller.mm,v 1.78 2005/11/04 13:09:41 titer Exp $
This file is part of the HandBrake source code.
Homepage: <http://handbrake.m0k.org/>.
It may be used under the terms of the GNU General Public License. */
-#include <paths.h>
-#include <IOKit/IOKitLib.h>
-#include <IOKit/IOBSD.h>
-#include <IOKit/storage/IOMedia.h>
-#include <IOKit/storage/IODVDMedia.h>
-
#include "Controller.h"
-#define _(a) NSLocalizedString(a,nil)
-
-static void _Scanning( void * data, int title, int titleCount );
-static void _ScanDone( void * data, HBList * titleList );
-static void _Encoding( void * data, float position, int pass,
- int passCount, float curFrameRate,
- float avgFrameRate, int remainingTime );
-static void _RipDone( void * data, int result );
+#define _(a) NSLocalizedString(a,NULL)
+
+static int FormatSettings[3][4] =
+ { { HB_MUX_MP4 | HB_VCODEC_FFMPEG | HB_ACODEC_FAAC,
+ HB_MUX_MP4 | HB_VCODEC_X264 | HB_ACODEC_FAAC,
+ 0,
+ 0 },
+ { HB_MUX_AVI | HB_VCODEC_FFMPEG | HB_ACODEC_LAME,
+ HB_MUX_AVI | HB_VCODEC_FFMPEG | HB_ACODEC_AC3,
+ HB_MUX_AVI | HB_VCODEC_X264 | HB_ACODEC_LAME,
+ HB_MUX_AVI | HB_VCODEC_X264 | HB_ACODEC_AC3 },
+ { HB_MUX_OGM | HB_VCODEC_FFMPEG | HB_ACODEC_VORBIS,
+ HB_MUX_OGM | HB_VCODEC_FFMPEG | HB_ACODEC_LAME,
+ 0,
+ 0 } };
/*******************************
* HBController implementation *
*******************************/
@implementation HBController
-- (void) applicationDidFinishLaunching: (NSNotification *) notification
+- init
{
- /* Init libhb */
- HBCallbacks callbacks;
- callbacks.data = self;
- callbacks.scanning = _Scanning;
- callbacks.scanDone = _ScanDone;
- callbacks.encoding = _Encoding;
- callbacks.ripDone = _RipDone;
+ self = [super init];
+ fHandle = NULL;
+ return self;
+}
- fHandle = HBInit( 1, 0 );
- HBSetCallbacks( fHandle, callbacks );
+- (void) applicationDidFinishLaunching: (NSNotification *) notification
+{
+ int build;
+ char * version;
- [fPictureGLView SetHandle: fHandle];
+ /* Init libhb */
+ fHandle = hb_init( HB_DEBUG_ALL, [[NSUserDefaults
+ standardUserDefaults] boolForKey:@"CheckForUpdates"] );
+
+ /* Init others controllers */
+ [fScanController SetHandle: fHandle];
+ [fPictureController SetHandle: fHandle];
+ [fQueueController SetHandle: fHandle];
+
+ /* Call UpdateUI every 2/10 sec */
+ [[NSRunLoop currentRunLoop] addTimer: [NSTimer
+ scheduledTimerWithTimeInterval: 0.2 target: self
+ selector: @selector( UpdateUI: ) userInfo: NULL repeats: FALSE]
+ forMode: NSModalPanelRunLoopMode];
+
+ if( ( build = hb_check_update( fHandle, &version ) ) > -1 )
+ {
+ /* Update available - tell the user */
+ NSBeginInformationalAlertSheet( _( @"Update is available" ),
+ _( @"Go get it!" ), _( @"Discard" ), NULL, fWindow, self,
+ @selector( UpdateAlertDone:returnCode:contextInfo: ),
+ NULL, NULL, [NSString stringWithFormat:
+ _( @"HandBrake %s (build %d) is now available for download." ),
+ version, build] );
+ return;
+ }
- /* Detect drives mounted after the app is started */
- [[[NSWorkspace sharedWorkspace] notificationCenter]
- addObserver: self selector: @selector( DetectDrives: )
- name: NSWorkspaceDidMountNotification object: nil];
+ /* Show scan panel ASAP */
+ [self performSelectorOnMainThread: @selector(ShowScanPanel:)
+ withObject: NULL waitUntilDone: NO];
}
- (NSApplicationTerminateReply) applicationShouldTerminate:
(NSApplication *) app
{
- if( [[fRipRipButton title] compare: _( @"Cancel" ) ]
- == NSOrderedSame )
+ if( [[fRipButton title] isEqualToString: _( @"Cancel" )] )
{
- [self Cancel: self];
+ [self Cancel: NULL];
return NSTerminateCancel;
}
/* Clean up */
- HBClose( &fHandle );
-
+ hb_close( &fHandle );
return NSTerminateNow;
}
- (void) awakeFromNib
{
- /* Strings for the Scan view */
- [fScWelcomeField setStringValue: _( @"Welcome to HandBrake" )];
- [fScSelectField setStringValue: _( @"Select a DVD:" )];
- [fScDetectedCell setTitle: _( @"Detected volume" )];
- [fScDetectedPopUp removeAllItems];
- [fScFolderCell setTitle: _( @"DVD Folder" )];
- [fScBrowseButton setTitle: _( @"Browse" )];
- [fScStatusField setStringValue: @""];
- [fScOpenButton setTitle: _( @"Open" )];
-
- /* Strings for the Rip view */
- /* General box */
- [fRipGeneralField setStringValue: _( @"General" )];
- [fRipTitleField setStringValue: _( @"DVD title" )];
- [fRipTitlePopUp removeAllItems];
- [fRipFormatField setStringValue: _( @"Output format" )];
- [fRipFormatPopUp removeAllItems];
- [fRipFormatPopUp addItemWithTitle:
- _( @"MP4 file / MPEG-4 video / AAC audio" )];
- [fRipFormatPopUp addItemWithTitle:
- _( @"AVI file / MPEG-4 video / MP3 audio" )];
- [fRipFormatPopUp addItemWithTitle:
- _( @"AVI file / H264 video / MP3 audio" )];
- [fRipFormatPopUp addItemWithTitle:
- _( @"OGM file / MPEG-4 video / Vorbis audio" )];
- [fRipFileField1 setStringValue: _( @"File" )];
- [fRipFileField2 setStringValue: [NSString stringWithFormat:
+ [fWindow center];
+
+ [self TranslateStrings];
+
+ /* Destination box */
+ [fDstFormatPopUp removeAllItems];
+ [fDstFormatPopUp addItemWithTitle: _( @"MP4 file" )];
+ [fDstFormatPopUp addItemWithTitle: _( @"AVI file" )];
+ [fDstFormatPopUp addItemWithTitle: _( @"OGM file" )];
+ [fDstFormatPopUp selectItemAtIndex: 0];
+
+ [self FormatPopUpChanged: NULL];
+
+ [fDstFile2Field setStringValue: [NSString stringWithFormat:
@"%@/Desktop/Movie.mp4", NSHomeDirectory()]];
- [fRipBrowseButton setTitle: _( @"Browse" )];
-
- /* Video box */
- [fRipVideoField setStringValue: _( @"Video" )];
- [fRipEncoderField setStringValue: _( @"MPEG-4 encoder" )];
- [fRipEncoderPopUp removeAllItems];
- [fRipEncoderPopUp addItemWithTitle: @"FFmpeg"];
- [fRipEncoderPopUp addItemWithTitle: @"XviD"];
- [fRipBitrateField setStringValue: _( @"Bitrate" )];
- [fRipCustomCell setTitle: _( @"Custom (kbps)" )];
- [fRipCustomField setIntValue: 1024];
- [fRipTargetCell setTitle: _( @"Target size (MB)" )];
- [fRipTargetField setIntValue: 700];
- [fRipTwoPassCheck setTitle: _( @"2-pass encoding" )];
- [fRipCropButton setTitle: _( @"Crop & Scale..." )];
-
- /* Audio box */
- [fRipAudioField setStringValue: _( @"Audio" )];
- [fRipLang1Field setStringValue: _( @"Language 1" )];
- [fRipLang1PopUp removeAllItems];
- [fRipLang2Field setStringValue: _( @"Language 2 (optional)" )];
- [fRipLang2PopUp removeAllItems];
- [fRipAudBitField setStringValue: _( @"Bitrate (kbps)" )];
- [fRipAudBitPopUp removeAllItems];
- [fRipAudBitPopUp addItemWithTitle: @"32"];
- [fRipAudBitPopUp addItemWithTitle: @"40"];
- [fRipAudBitPopUp addItemWithTitle: @"48"];
- [fRipAudBitPopUp addItemWithTitle: @"56"];
- [fRipAudBitPopUp addItemWithTitle: @"64"];
- [fRipAudBitPopUp addItemWithTitle: @"80"];
- [fRipAudBitPopUp addItemWithTitle: @"96"];
- [fRipAudBitPopUp addItemWithTitle: @"112"];
- [fRipAudBitPopUp addItemWithTitle: @"128"];
- [fRipAudBitPopUp addItemWithTitle: @"160"];
- [fRipAudBitPopUp addItemWithTitle: @"192"];
- [fRipAudBitPopUp addItemWithTitle: @"224"];
- [fRipAudBitPopUp addItemWithTitle: @"256"];
- [fRipAudBitPopUp addItemWithTitle: @"320"];
- [fRipAudBitPopUp selectItemWithTitle: @"128"];
+
+ /* Video encoder */
+ [fVidEncoderPopUp removeAllItems];
+ [fVidEncoderPopUp addItemWithTitle: @"FFmpeg"];
+ [fVidEncoderPopUp addItemWithTitle: @"XviD"];
+
+ /* Video quality */
+ [fVidTargetSizeField setIntValue: 700];
+ [fVidBitrateField setIntValue: 1000];
+ [fVidQualityMatrix selectCell: fVidBitrateCell];
+ [self VideoMatrixChanged: NULL];
+
+ /* Video framerate */
+ [fVidRatePopUp removeAllItems];
+ [fVidRatePopUp addItemWithTitle: _( @"Same as source" )];
+ for( int i = 0; i < hb_video_rates_count; i++ )
+ {
+ [fVidRatePopUp addItemWithTitle:
+ [NSString stringWithCString: hb_video_rates[i].string]];
+ }
+ [fVidRatePopUp selectItemAtIndex: 0];
+
+ /* Audio bitrate */
+ [fAudBitratePopUp removeAllItems];
+ for( int i = 0; i < hb_audio_bitrates_count; i++ )
+ {
+ [fAudBitratePopUp addItemWithTitle:
+ [NSString stringWithCString: hb_audio_bitrates[i].string]];
+ }
+ [fAudBitratePopUp selectItemAtIndex: hb_audio_bitrates_default];
+
+ /* Audio samplerate */
+ [fAudRatePopUp removeAllItems];
+ for( int i = 0; i < hb_audio_rates_count; i++ )
+ {
+ [fAudRatePopUp addItemWithTitle:
+ [NSString stringWithCString: hb_audio_rates[i].string]];
+ }
+ [fAudRatePopUp selectItemAtIndex: hb_audio_rates_default];
/* Bottom */
- [fRipStatusField setStringValue: @""];
- [fRipInfoField setStringValue: @""];
- [fRipPauseButton setTitle: _( @"Pause" )];
- [fRipRipButton setTitle: _( @"Rip" )];
-
- /* Strings for the crop panel */
- [fWidthField1 setStringValue: _( @"Picture width" )];
- [fDeinterlaceCheck setTitle: _( @"Deinterlace picture" )];
- [fTopField1 setStringValue: _( @"Top cropping" )];
- [fBottomField1 setStringValue: _( @"Bottom cropping" )];
- [fLeftField1 setStringValue: _( @"Left cropping" )];
- [fRightField1 setStringValue: _( @"Right cropping" )];
- [fPreviousButton setTitle: _( @"Previous" )];
- [fNextButton setTitle: _( @"Next" )];
- [fAutocropButton setTitle: _( @"Autocrop" )];
- [fOpenGLCheck setTitle: _( @"Useless OpenGL effects" )];
- [fInfoField setStringValue: @""];
- [fCloseButton setTitle: _( @"Close" )];
-
- [self VideoMatrixChanged: self];
-
- /* Show the scan view */
- [fWindow setContentSize: [fScView frame].size];
- [fWindow setContentView: fScView];
- [fWindow center];
+ [fStatusField setStringValue: @""];
- /* Detect DVD drives */
- [self DetectDrives: nil];
- [self ScanMatrixChanged: self];
+ [self EnableUI: NO];
+ [fPauseButton setEnabled: NO];
+ [fRipButton setEnabled: NO];
}
-- (BOOL) windowShouldClose: (id) sender
+- (void) TranslateStrings
{
- if( [[fRipRipButton title] compare: _( @"Cancel" ) ]
- == NSOrderedSame )
+ [fSrcDVD1Field setStringValue: _( @"DVD:" )];
+ [fSrcTitleField setStringValue: _( @"Title:" )];
+ [fSrcChapterField setStringValue: _( @"Chapters:" )];
+ [fSrcChapterToField setStringValue: _( @"to" )];
+ [fSrcDuration1Field setStringValue: _( @"Duration:" )];
+
+ [fDstFormatField setStringValue: _( @"File format:" )];
+ [fDstCodecsField setStringValue: _( @"Codecs:" )];
+ [fDstFile1Field setStringValue: _( @"File:" )];
+ [fDstBrowseButton setTitle: _( @"Browse" )];
+
+ [fVidRateField setStringValue: _( @"Framerate (fps):" )];
+ [fVidEncoderField setStringValue: _( @"Encoder:" )];
+ [fVidQualityField setStringValue: _( @"Quality:" )];
+}
+
+/***********************************************************************
+ * UpdateDockIcon
+ ***********************************************************************
+ * Shows a progression bar on the dock icon, filled according to
+ * 'progress' (0.0 <= progress <= 1.0).
+ * Called with progress < 0.0 or progress > 1.0, restores the original
+ * icon.
+ **********************************************************************/
+- (void) UpdateDockIcon: (float) progress
+{
+ NSImage * icon;
+ NSData * tiff;
+ NSBitmapImageRep * bmp;
+ uint32_t * pen;
+ int row_start, row_end;
+ int i, j;
+
+ /* Get application original icon */
+ icon = [NSImage imageNamed: @"NSApplicationIcon"];
+
+ if( progress < 0.0 || progress > 1.0 )
{
- [self Cancel: self];
- return NO;
+ [NSApp setApplicationIconImage: icon];
+ return;
}
- /* Stop the application when the user closes the window */
- [NSApp terminate: self];
- return YES;
+ /* Get it in a raw bitmap form */
+ tiff = [icon TIFFRepresentationUsingCompression:
+ NSTIFFCompressionNone factor: 1.0];
+ bmp = [NSBitmapImageRep imageRepWithData: tiff];
+
+ /* Draw the progression bar */
+ /* It's pretty simple (ugly?) now, but I'm no designer */
+
+ row_start = 3 * (int) [bmp size].height / 4;
+ row_end = 7 * (int) [bmp size].height / 8;
+
+ for( i = row_start; i < row_start + 2; i++ )
+ {
+ pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
+ for( j = 0; j < (int) [bmp size].width; j++ )
+ {
+ pen[j] = 0x000000FF; /* Black */
+ }
+ }
+ for( i = row_start + 2; i < row_end - 2; i++ )
+ {
+ pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
+ pen[0] = 0x000000FF;
+ pen[1] = 0x000000FF;
+ for( j = 2; j < (int) [bmp size].width - 2; j++ )
+ {
+ if( j < 2 + (int) ( ( [bmp size].width - 4.0 ) * progress ) )
+ {
+ pen[j] = 0xFF0000FF; /* Red */
+ }
+ else
+ {
+ pen[j] = 0xFFFFFFFF; /* White */
+ }
+ }
+ pen[j] = 0x000000FF;
+ pen[j+1] = 0x000000FF;
+ }
+ for( i = row_end - 2; i < row_end; i++ )
+ {
+ pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
+ for( j = 0; j < (int) [bmp size].width; j++ )
+ {
+ pen[j] = 0x000000FF; /* Black */
+ }
+ }
+
+ /* Now update the dock icon */
+ tiff = [bmp TIFFRepresentationUsingCompression:
+ NSTIFFCompressionNone factor: 1.0];
+ icon = [[NSImage alloc] initWithData: tiff];
+ [NSApp setApplicationIconImage: icon];
+ [icon release];
}
-- (IBAction) BrowseDVD: (id) sender
+- (void) UpdateUI: (NSTimer *) timer
{
- /* Open a panel to let the user choose and update the text field */
- NSOpenPanel * panel = [NSOpenPanel openPanel];
+ hb_state_t s;
+ hb_get_state( fHandle, &s );
+
+ switch( s.state )
+ {
+ case HB_STATE_IDLE:
+ /* If the scan panel is currently showing, recheck for DVD
+ drives. The clean way would be to use
+ NSWorkspaceDidMountNotification, but for some reason the
+ notifications don't work when having the sheet attached */
+ if( [fWindow attachedSheet] == fScanPanel )
+ {
+ [fScanController DetectDrives: NULL];
+ }
+ break;
- [panel setAllowsMultipleSelection: NO];
- [panel setCanChooseFiles: NO];
- [panel setCanChooseDirectories: YES ];
+ case HB_STATE_SCANNING:
+ [fScanController UpdateUI: &s];
+ break;
- [panel beginSheetForDirectory: nil file: nil types: nil
- modalForWindow: fWindow modalDelegate: self
- didEndSelector: @selector( BrowseDVDDone:returnCode:contextInfo: )
- contextInfo: nil];
+#define p s.param.scandone
+ case HB_STATE_SCANDONE:
+ {
+ hb_list_t * list;
+ hb_title_t * title;
+
+ [fScanController UpdateUI: &s];
+
+ list = hb_get_titles( fHandle );
+
+ if( !hb_list_count( list ) )
+ {
+ break;
+ }
+
+ [fSrcTitlePopUp removeAllItems];
+ for( int i = 0; i < hb_list_count( list ); i++ )
+ {
+ title = (hb_title_t *) hb_list_item( list, i );
+ [fSrcDVD2Field setStringValue: [NSString
+ stringWithUTF8String: title->dvd]];
+ [fSrcTitlePopUp addItemWithTitle: [NSString
+ stringWithFormat: @"%d - %02dh%02dm%02ds",
+ title->index, title->hours, title->minutes,
+ title->seconds]];
+ }
+
+ [self TitlePopUpChanged: NULL];
+ [self EnableUI: YES];
+ [fPauseButton setEnabled: NO];
+ [fRipButton setEnabled: YES];
+ break;
+ }
+#undef p
+
+#define p s.param.working
+ case HB_STATE_WORKING:
+ {
+ float progress_total;
+ NSMutableString * string;
+
+ /* Update text field */
+ string = [NSMutableString stringWithFormat:
+ _( @"Encoding: task %d of %d, %.2f %%" ),
+ p.job_cur, p.job_count, 100.0 * p.progress];
+ if( p.seconds > -1 )
+ {
+ [string appendFormat:
+ _( @" (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)" ),
+ p.rate_cur, p.rate_avg, p.hours, p.minutes, p.seconds];
+ }
+ [fStatusField setStringValue: string];
+
+ /* Update slider */
+ progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count;
+ [fRipIndicator setDoubleValue: 100.0 * progress_total];
+
+ /* Update dock icon */
+ [self UpdateDockIcon: progress_total];
+
+ [fPauseButton setEnabled: YES];
+ [fPauseButton setTitle: _( @"Pause" )];
+ [fRipButton setEnabled: YES];
+ [fRipButton setTitle: _( @"Cancel" )];
+ break;
+ }
+#undef p
+
+ case HB_STATE_PAUSED:
+ [fStatusField setStringValue: _( @"Paused" )];
+ [fPauseButton setEnabled: YES];
+ [fPauseButton setTitle: _( @"Resume" )];
+ [fRipButton setEnabled: YES];
+ [fRipButton setTitle: _( @"Cancel" )];
+ break;
+
+ case HB_STATE_WORKDONE:
+ {
+ [self EnableUI: YES];
+ [fStatusField setStringValue: _( @"Done." )];
+ [fRipIndicator setDoubleValue: 0.0];
+ [fRipButton setTitle: _( @"Rip" )];
+
+ /* Restore dock icon */
+ [self UpdateDockIcon: -1.0];
+
+ [fPauseButton setEnabled: NO];
+ [fPauseButton setTitle: _( @"Pause" )];
+ [fRipButton setEnabled: YES];
+ [fRipButton setTitle: _( @"Rip" )];
+
+ /* FIXME */
+ hb_job_t * job;
+ while( ( job = hb_job( fHandle, 0 ) ) )
+ {
+ hb_rem( fHandle, job );
+ }
+ break;
+ }
+ }
+
+ /* FIXME: we should only do that when necessary */
+ if( [fQueueCheck state] == NSOnState )
+ {
+ int count = hb_count( fHandle );
+ if( count )
+ {
+ [fQueueCheck setTitle: [NSString stringWithFormat:
+ @"Enable queue (%d task%s in queue)",
+ count, ( count > 1 ) ? "s" : ""]];
+ }
+ else
+ {
+ [fQueueCheck setTitle: @"Enable queue (no task in queue)"];
+ }
+ }
+
+ [[NSRunLoop currentRunLoop] addTimer: [NSTimer
+ scheduledTimerWithTimeInterval: 0.2 target: self
+ selector: @selector( UpdateUI: ) userInfo: NULL repeats: FALSE]
+ forMode: NSModalPanelRunLoopMode];
}
-- (void) BrowseDVDDone: (NSOpenPanel *) sheet
- returnCode: (int) returnCode contextInfo: (void *) contextInfo
+- (void) EnableUI: (bool) b
{
- if( returnCode == NSOKButton )
+ NSControl * controls[] =
+ { fSrcDVD1Field, fSrcDVD2Field, fSrcTitleField, fSrcTitlePopUp,
+ fSrcChapterField, fSrcChapterStartPopUp, fSrcChapterToField,
+ fSrcChapterEndPopUp, fSrcDuration1Field, fSrcDuration2Field,
+ fDstFormatField, fDstFormatPopUp, fDstCodecsField,
+ fDstCodecsPopUp, fDstFile1Field, fDstFile2Field,
+ fDstBrowseButton, fVidRateField, fVidRatePopUp,
+ fVidEncoderField, fVidEncoderPopUp, fVidQualityField,
+ fVidQualityMatrix, fVidGrayscaleCheck, fSubField, fSubPopUp,
+ fAudLang1Field, fAudLang1PopUp, fAudLang2Field, fAudLang2PopUp,
+ fAudRateField, fAudRatePopUp, fAudBitrateField,
+ fAudBitratePopUp, fPictureButton };
+
+ for( unsigned i = 0;
+ i < sizeof( controls ) / sizeof( NSControl * ); i++ )
{
- [fScFolderField setStringValue:
- [[sheet filenames] objectAtIndex: 0]];
+ if( [[controls[i] className] isEqualToString: @"NSTextField"] )
+ {
+ NSTextField * tf = (NSTextField *) controls[i];
+ if( ![tf isBezeled] )
+ {
+ [tf setTextColor: b ? [NSColor controlTextColor] :
+ [NSColor disabledControlTextColor]];
+ continue;
+ }
+ }
+ [controls[i] setEnabled: b];
}
+
+ [self VideoMatrixChanged: NULL];
+}
+
+- (IBAction) ShowScanPanel: (id) sender
+{
+ [NSApp beginSheet: fScanPanel modalForWindow: fWindow
+ modalDelegate: NULL didEndSelector: NULL contextInfo: NULL];
+ [NSApp runModalForWindow: fScanPanel];
+ [NSApp endSheet: fScanPanel];
+ [fScanPanel orderOut: self];
+}
+
+- (BOOL) windowShouldClose: (id) sender
+{
+ /* Stop the application when the user closes the window */
+ [NSApp terminate: self];
+ return YES;
}
- (IBAction) VideoMatrixChanged: (id) sender;
{
- if( ![fRipVideoMatrix isEnabled] )
- {
- [fRipCustomField setEnabled: NO];
- [fRipTargetField setEnabled: NO];
- return;
- }
-
- if( ![fRipVideoMatrix selectedRow] )
+ bool target, bitrate, quality;
+
+ target = bitrate = quality = false;
+ if( [fVidQualityMatrix isEnabled] )
{
- [fRipCustomField setEnabled: YES];
- [fRipTargetField setEnabled: NO];
+ switch( [fVidQualityMatrix selectedRow] )
+ {
+ case 0:
+ target = true;
+ break;
+ case 1:
+ bitrate = true;
+ break;
+ case 2:
+ quality = true;
+ break;
+ }
}
- else
+ [fVidTargetSizeField setEnabled: target];
+ [fVidBitrateField setEnabled: bitrate];
+ [fVidQualitySlider setEnabled: quality];
+ [fVidTwoPassCheck setEnabled: !quality &&
+ [fVidQualityMatrix isEnabled]];
+ if( quality )
{
- [fRipCustomField setEnabled: NO];
- [fRipTargetField setEnabled: YES];
- [fRipTargetField UpdateBitrate];
+ [fVidTwoPassCheck setState: NSOffState];
}
+
+ [self QualitySliderChanged: sender];
+ [self CalculateBitrate: sender];
+}
+
+- (IBAction) QualitySliderChanged: (id) sender
+{
+ [fVidConstantCell setTitle: [NSString stringWithFormat:
+ _( @"Constant quality: %.0f %%" ), 100.0 *
+ [fVidQualitySlider floatValue]]];
}
- (IBAction) BrowseFile: (id) sender
@@ -231,10 +490,10 @@ static void _RipDone( void * data, int result );
/* Open a panel to let the user choose and update the text field */
NSSavePanel * panel = [NSSavePanel savePanel];
- [panel beginSheetForDirectory: nil file: nil
+ [panel beginSheetForDirectory: NULL file: NULL
modalForWindow: fWindow modalDelegate: self
didEndSelector: @selector( BrowseFileDone:returnCode:contextInfo: )
- contextInfo: nil];
+ contextInfo: NULL];
}
- (void) BrowseFileDone: (NSSavePanel *) sheet
@@ -242,146 +501,176 @@ static void _RipDone( void * data, int result );
{
if( returnCode == NSOKButton )
{
- [fRipFileField2 setStringValue: [sheet filename]];
- [self FormatPopUpChanged: self];
- }
-}
-
-- (IBAction) Scan: (id) sender
-{
- [fScMatrix setEnabled: NO];
- [fScDetectedPopUp setEnabled: NO];
- [fScFolderField setEnabled: NO];
- [fScBrowseButton setEnabled: NO];
- [fScProgress setIndeterminate: YES];
- [fScProgress startAnimation: self];
- [fScOpenButton setEnabled: NO];
- [fScStatusField setStringValue: _( @"Opening device..." )];
-
- /* Ask libhb to start scanning the specified volume */
- if( ![fScMatrix selectedRow] )
- {
- /* DVD drive */
- HBScanDVD( fHandle,
- [[fScDetectedPopUp titleOfSelectedItem] cString], 0 );
- }
- else
- {
- /* DVD folder */
- HBScanDVD( fHandle,
- [[fScFolderField stringValue] cString], 0 );
+ [fDstFile2Field setStringValue: [sheet filename]];
+ [self FormatPopUpChanged: NULL];
}
}
- (IBAction) ShowPicturePanel: (id) sender
{
- HBTitle * title = (HBTitle*)
- HBListItemAt( fTitleList, [fRipTitlePopUp indexOfSelectedItem] );
-
- [fPictureGLView SetTitle: title];
-
- fPicture = 0;
- [fPictureGLView ShowPicture: fPicture animate: HB_ANIMATE_NONE];
-
- [fWidthStepper setValueWraps: NO];
- [fWidthStepper setIncrement: 16];
- [fWidthStepper setMinValue: 16];
- [fWidthStepper setMaxValue: title->outWidthMax];
- [fWidthStepper setIntValue: title->outWidth];
- [fWidthField2 setIntValue: title->outWidth];
- [fDeinterlaceCheck setState:
- title->deinterlace ? NSOnState : NSOffState];
- [fTopStepper setValueWraps: NO];
- [fTopStepper setIncrement: 2];
- [fTopStepper setMinValue: 0];
- [fTopStepper setMaxValue: title->inHeight / 4];
- [fTopStepper setIntValue: title->topCrop];
- [fTopField2 setIntValue: title->topCrop];
- [fBottomStepper setValueWraps: NO];
- [fBottomStepper setIncrement: 2];
- [fBottomStepper setMinValue: 0];
- [fBottomStepper setMaxValue: title->inHeight / 4];
- [fBottomStepper setIntValue: title->bottomCrop];
- [fBottomField2 setIntValue: title->bottomCrop];
- [fLeftStepper setValueWraps: NO];
- [fLeftStepper setIncrement: 2];
- [fLeftStepper setMinValue: 0];
- [fLeftStepper setMaxValue: title->inWidth / 4];
- [fLeftStepper setIntValue: title->leftCrop];
- [fLeftField2 setIntValue: title->leftCrop];
- [fRightStepper setValueWraps: NO];
- [fRightStepper setIncrement: 2];
- [fRightStepper setMinValue: 0];
- [fRightStepper setMaxValue: title->inWidth / 4];
- [fRightStepper setIntValue: title->rightCrop];
- [fRightField2 setIntValue: title->rightCrop];
-
- [fPreviousButton setEnabled: NO];
- [fNextButton setEnabled: YES];
-
- [fInfoField setStringValue: [NSString stringWithFormat:
- _( @"Final size: %dx%d" ), title->outWidth, title->outHeight] ];
+ hb_list_t * list = hb_get_titles( fHandle );
+ hb_title_t * title = (hb_title_t *) hb_list_item( list,
+ [fSrcTitlePopUp indexOfSelectedItem] );
/* Resize the panel */
NSSize newSize;
- newSize.width = 42 + MAX( 720, title->outWidthMax );
- newSize.height = 165 + title->outHeightMax;
+ newSize.width = 246 + title->width;
+ newSize.height = 80 + title->height;
[fPicturePanel setContentSize: newSize];
+ [fPictureController SetTitle: title];
+
[NSApp beginSheet: fPicturePanel modalForWindow: fWindow
- modalDelegate: nil didEndSelector: nil contextInfo: nil];
+ modalDelegate: NULL didEndSelector: NULL contextInfo: NULL];
[NSApp runModalForWindow: fPicturePanel];
[NSApp endSheet: fPicturePanel];
[fPicturePanel orderOut: self];
}
-- (IBAction) ClosePanel: (id) sender
+- (IBAction) ShowQueuePanel: (id) sender
{
- [NSApp stopModal];
+ /* Update the OutlineView */
+ [fQueueController Update: sender];
+
+ /* Show the panel */
+ [NSApp beginSheet: fQueuePanel modalForWindow: fWindow
+ modalDelegate: NULL didEndSelector: NULL contextInfo: NULL];
+ [NSApp runModalForWindow: fQueuePanel];
+ [NSApp endSheet: fQueuePanel];
+ [fQueuePanel orderOut: self];
}
-- (IBAction) Rip: (id) sender
+- (void) PrepareJob
{
- /* Rip or Cancel ? */
- if( [[fRipRipButton title] compare: _( @"Cancel" ) ]
- == NSOrderedSame )
+ hb_list_t * list = hb_get_titles( fHandle );
+ hb_title_t * title = (hb_title_t *) hb_list_item( list,
+ [fSrcTitlePopUp indexOfSelectedItem] );
+ hb_job_t * job = title->job;
+
+ /* Chapter selection */
+ job->chapter_start = [fSrcChapterStartPopUp indexOfSelectedItem] + 1;
+ job->chapter_end = [fSrcChapterEndPopUp indexOfSelectedItem] + 1;
+
+ /* Format and codecs */
+ int format = [fDstFormatPopUp indexOfSelectedItem];
+ int codecs = [fDstCodecsPopUp indexOfSelectedItem];
+ job->mux = FormatSettings[format][codecs] & HB_MUX_MASK;
+ job->vcodec = FormatSettings[format][codecs] & HB_VCODEC_MASK;
+ job->acodec = FormatSettings[format][codecs] & HB_ACODEC_MASK;
+
+ if( ( job->vcodec & HB_VCODEC_FFMPEG ) &&
+ [fVidEncoderPopUp indexOfSelectedItem] > 0 )
{
- [self Cancel: self];
- return;
+ job->vcodec = HB_VCODEC_XVID;
+ }
+ if( job->vcodec & HB_VCODEC_X264 )
+ {
+ job->h264_13 = [fVidEncoderPopUp indexOfSelectedItem];
}
- if( [fRipCustomField intValue] < 64 )
+ /* Video settings */
+ if( [fVidRatePopUp indexOfSelectedItem] > 0 )
{
- NSBeginCriticalAlertSheet( _( @"Invalid video bitrate" ),
- _( @"Ooops" ), nil, nil, fWindow, self, nil, nil, nil,
- _( @"Video bitrate is too low." ) );
- return;
+ job->vrate = 27000000;
+ job->vrate_base = hb_video_rates[[fVidRatePopUp
+ indexOfSelectedItem]-1].rate;
}
- if( [fRipCustomField intValue] > 8192 )
+ else
{
- NSBeginCriticalAlertSheet( _( @"Invalid video bitrate" ),
- _( @"Ooops" ), nil, nil, fWindow, self, nil, nil, nil,
- _( @"Video bitrate is too high." ) );
- return;
+ job->vrate = title->rate;
+ job->vrate_base = title->rate_base;
}
- if( [fRipLang1PopUp indexOfSelectedItem] ==
- [fRipLang2PopUp indexOfSelectedItem] )
+
+ switch( [fVidQualityMatrix selectedRow] )
{
- NSBeginCriticalAlertSheet( _( @"Invalid secondary language" ),
- _( @"Ooops" ), nil, nil, fWindow, self, nil, nil, nil,
- _( @"You can't encode the same audio track twice." ) );
+ case 0:
+ /* Target size.
+ Bitrate should already have been calculated and displayed
+ in fVidBitrateField, so let's just use it */
+ case 1:
+ job->vquality = -1.0;
+ job->vbitrate = [fVidBitrateField intValue];
+ break;
+ case 2:
+ job->vquality = [fVidQualitySlider floatValue];
+ job->vbitrate = 0;
+ break;
+ }
+
+ job->grayscale = ( [fVidGrayscaleCheck state] == NSOnState );
+
+ /* Subtitle settings */
+ job->subtitle = [fSubPopUp indexOfSelectedItem] - 1;
+
+ /* Audio tracks */
+ job->audios[0] = [fAudLang1PopUp indexOfSelectedItem] - 1;
+ job->audios[1] = [fAudLang2PopUp indexOfSelectedItem] - 1;
+ job->audios[2] = -1;
+
+ /* Audio settings */
+ job->arate = hb_audio_rates[[fAudRatePopUp
+ indexOfSelectedItem]].rate;
+ job->abitrate = hb_audio_bitrates[[fAudBitratePopUp
+ indexOfSelectedItem]].rate;
+}
+
+- (IBAction) EnableQueue: (id) sender
+{
+ bool e = ( [fQueueCheck state] == NSOnState );
+ [fQueueAddButton setHidden: !e];
+ [fQueueShowButton setHidden: !e];
+ [fRipButton setTitle: e ? @"Start" : @"Rip"];
+}
+
+- (IBAction) AddToQueue: (id) sender
+{
+ hb_list_t * list = hb_get_titles( fHandle );
+ hb_title_t * title = (hb_title_t *) hb_list_item( list,
+ [fSrcTitlePopUp indexOfSelectedItem] );
+ hb_job_t * job = title->job;
+
+ [self PrepareJob];
+
+ /* Destination file */
+ job->file = strdup( [[fDstFile2Field stringValue] UTF8String] );
+
+ if( [fVidTwoPassCheck state] == NSOnState )
+ {
+ job->pass = 1;
+ hb_add( fHandle, job );
+ job->pass = 2;
+ hb_add( fHandle, job );
+ }
+ else
+ {
+ job->pass = 0;
+ hb_add( fHandle, job );
+ }
+}
+
+- (IBAction) Rip: (id) sender
+{
+ /* Rip or Cancel ? */
+ if( [[fRipButton title] isEqualToString: _( @"Cancel" )] )
+ {
+ [self Cancel: sender];
return;
}
+ if( [fQueueCheck state] == NSOffState )
+ {
+ [self AddToQueue: sender];
+ }
+
if( [[NSFileManager defaultManager] fileExistsAtPath:
- [fRipFileField2 stringValue]] )
+ [fDstFile2Field stringValue]] )
{
NSBeginCriticalAlertSheet( _( @"File already exists" ),
- _( @"No" ), _( @"Yes" ), nil, fWindow, self,
+ _( @"Cancel" ), _( @"Overwrite" ), NULL, fWindow, self,
@selector( OverwriteAlertDone:returnCode:contextInfo: ),
- nil, nil, [NSString stringWithFormat:
+ NULL, NULL, [NSString stringWithFormat:
_( @"Do you want to overwrite %@?" ),
- [fRipFileField2 stringValue]] );
+ [fDstFile2Field stringValue]] );
return;
}
@@ -397,70 +686,38 @@ static void _RipDone( void * data, int result );
}
}
-- (void) _Rip
+- (void) UpdateAlertDone: (NSWindow *) sheet
+ returnCode: (int) returnCode contextInfo: (void *) contextInfo
{
- /* Get the specified title & audio track(s) */
- HBTitle * title = (HBTitle*) HBListItemAt( fTitleList,
- [fRipTitlePopUp indexOfSelectedItem] );
- HBAudio * audio1 = (HBAudio*) HBListItemAt( title->audioList,
- [fRipLang1PopUp indexOfSelectedItem] );
- HBAudio * audio2 = (HBAudio*) HBListItemAt( title->audioList,
- [fRipLang2PopUp indexOfSelectedItem] );
-
- /* Use user settings */
- title->file = strdup( [[fRipFileField2 stringValue] cString] );
- title->bitrate = [fRipCustomField intValue];
- title->twoPass = ( [fRipTwoPassCheck state] == NSOnState );
-
- int format = [fRipFormatPopUp indexOfSelectedItem];
- int codec = [fRipEncoderPopUp indexOfSelectedItem];
- title->mux = ( !format ) ? HB_MUX_MP4 : ( ( format == 3 ) ?
- HB_MUX_OGM : HB_MUX_AVI );
- title->codec = ( format == 2 ) ? HB_CODEC_X264 : ( ( !codec ) ?
- HB_CODEC_FFMPEG : HB_CODEC_XVID );
-
- audio1->outBitrate = [[fRipAudBitPopUp titleOfSelectedItem]
- intValue];
- audio1->outCodec = ( !format ) ? HB_CODEC_AAC : ( ( format == 3 ) ?
- HB_CODEC_VORBIS : HB_CODEC_MP3 );;
- HBListAdd( title->ripAudioList, audio1 );
- if( audio2 )
- {
- audio2->outBitrate = [[fRipAudBitPopUp
- titleOfSelectedItem] intValue];
- audio2->outCodec = ( !format ) ? HB_CODEC_AAC : ( ( format == 3 ) ?
- HB_CODEC_VORBIS : HB_CODEC_MP3 );
- HBListAdd( title->ripAudioList, audio2 );
+ if( returnCode == NSAlertAlternateReturn )
+ {
+ /* Show scan panel */
+ [self performSelectorOnMainThread: @selector(ShowScanPanel:)
+ withObject: NULL waitUntilDone: NO];
+ return;
}
- /* Disable interface */
- [fRipTitlePopUp setEnabled: NO];
- [fRipFormatPopUp setEnabled: NO];
- [fRipVideoMatrix setEnabled: NO];
- [fRipCustomField setEnabled: NO];
- [fRipTargetField setEnabled: NO];
- [fRipTwoPassCheck setEnabled: NO];
- [fRipCropButton setEnabled: NO];
- [fRipLang1PopUp setEnabled: NO];
- [fRipLang2PopUp setEnabled: NO];
- [fRipAudBitPopUp setEnabled: NO];
- [fRipFileField2 setEnabled: NO];
- [fRipEncoderPopUp setEnabled: NO];
- [fRipBrowseButton setEnabled: NO];
- [fRipPauseButton setEnabled: YES];
- [fRipRipButton setTitle: _( @"Cancel" )];
- [fRipProgress setIndeterminate: YES];
- [fRipProgress startAnimation: self];;
+ /* Go to HandBrake homepage and exit */
+ [self OpenHomepage: NULL];
+ [NSApp terminate: self];
+}
+- (void) _Rip
+{
/* Let libhb do the job */
- HBStartRip( fHandle, title );
+ hb_start( fHandle );
+
+ /* Disable interface */
+ [self EnableUI: NO];
+ [fPauseButton setEnabled: NO];
+ [fRipButton setEnabled: NO];
}
- (IBAction) Cancel: (id) sender
{
NSBeginCriticalAlertSheet( _( @"Cancel - Are you sure?" ),
- _( @"No" ), _( @"Yes" ), nil, fWindow, self,
- @selector( _Cancel:returnCode:contextInfo: ), nil, nil,
+ _( @"Keep working" ), _( @"Cancel encoding" ), NULL, fWindow, self,
+ @selector( _Cancel:returnCode:contextInfo: ), NULL, NULL,
_( @"Encoding won't be recoverable." ) );
}
@@ -469,500 +726,241 @@ static void _RipDone( void * data, int result );
{
if( returnCode == NSAlertAlternateReturn )
{
- if( [[fRipPauseButton title] compare: _( @"Resume" ) ]
- == NSOrderedSame )
- {
- HBResumeRip( fHandle );
- }
- HBStopRip( fHandle );
+ hb_stop( fHandle );
+ [fPauseButton setEnabled: NO];
+ [fRipButton setEnabled: NO];
}
}
- (IBAction) Pause: (id) sender
{
- if( [[fRipPauseButton title] compare: _( @"Resume" ) ]
- == NSOrderedSame )
- {
- [self Resume: self];
- return;
- }
-
- [fRipPauseButton setTitle: _( @"Resume" )];
- HBPauseRip( fHandle );
-}
-
-- (IBAction) Resume: (id) sender
-{
- [fRipPauseButton setTitle: _( @"Pause" )];
- HBResumeRip( fHandle );
-}
-
-- (IBAction) PreviousPicture: (id) sender
-{
- fPicture--;
- if( [fOpenGLCheck state] == NSOnState )
- {
- [fPictureGLView ShowPicture: fPicture
- animate: HB_ANIMATE_LEFT];
- }
- else
- {
- [fPictureGLView ShowPicture: fPicture
- animate: HB_ANIMATE_NONE];
- }
-
- [fPreviousButton setEnabled: ( fPicture > 0 )];
- [fNextButton setEnabled: YES];
-}
+ [fPauseButton setEnabled: NO];
+ [fRipButton setEnabled: NO];
-- (IBAction) NextPicture: (id) sender
-{
- fPicture++;
- if( [fOpenGLCheck state] == NSOnState )
+ if( [[fPauseButton title] isEqualToString: _( @"Resume" )] )
{
- [fPictureGLView ShowPicture: fPicture
- animate: HB_ANIMATE_RIGHT];
+ hb_resume( fHandle );
}
else
{
- [fPictureGLView ShowPicture: fPicture
- animate: HB_ANIMATE_NONE];
+ hb_pause( fHandle );
}
-
- [fPreviousButton setEnabled: YES];
- [fNextButton setEnabled: ( fPicture < 9 )];
}
-- (IBAction) UpdatePicture: (id) sender
-{
- HBTitle * title = (HBTitle*)
- HBListItemAt( fTitleList, [fRipTitlePopUp indexOfSelectedItem] );
- title->outWidth = [fWidthStepper intValue];
- title->deinterlace = ( [fDeinterlaceCheck state] == NSOnState );
- title->topCrop = [fTopStepper intValue];
- title->bottomCrop = [fBottomStepper intValue];
- title->leftCrop = [fLeftStepper intValue];
- title->rightCrop = [fRightStepper intValue];
-
- [fPictureGLView ShowPicture: fPicture animate: HB_ANIMATE_NONE];
-
- [fWidthStepper setIntValue: title->outWidth];
- [fTopStepper setIntValue: title->topCrop];
- [fBottomStepper setIntValue: title->bottomCrop];
- [fLeftStepper setIntValue: title->leftCrop];
- [fRightStepper setIntValue: title->rightCrop];
- [fWidthField2 setIntValue: [fWidthStepper intValue]];
- [fTopField2 setIntValue: [fTopStepper intValue]];
- [fBottomField2 setIntValue: [fBottomStepper intValue]];
- [fLeftField2 setIntValue: [fLeftStepper intValue]];
- [fRightField2 setIntValue: [fRightStepper intValue]];
-
- [fInfoField setStringValue: [NSString stringWithFormat:
- _( @"Final size: %dx%d" ), title->outWidth, title->outHeight]];
-}
-
-- (IBAction) AutoCrop: (id) sender
-{
- HBTitle * title = (HBTitle*)
- HBListItemAt( fTitleList, [fRipTitlePopUp indexOfSelectedItem] );
- title->topCrop = title->autoTopCrop;
- title->bottomCrop = title->autoBottomCrop;
- title->leftCrop = title->autoLeftCrop;
- title->rightCrop = title->autoRightCrop;
-
- [fPictureGLView ShowPicture: fPicture animate: HB_ANIMATE_NONE];
-
- [fWidthStepper setIntValue: title->outWidth];
- [fTopStepper setIntValue: title->topCrop];
- [fBottomStepper setIntValue: title->bottomCrop];
- [fLeftStepper setIntValue: title->leftCrop];
- [fRightStepper setIntValue: title->rightCrop];
- [fWidthField2 setIntValue: [fWidthStepper intValue]];
- [fTopField2 setIntValue: [fTopStepper intValue]];
- [fBottomField2 setIntValue: [fBottomStepper intValue]];
- [fLeftField2 setIntValue: [fLeftStepper intValue]];
- [fRightField2 setIntValue: [fRightStepper intValue]];
-
- [fInfoField setStringValue: [NSString stringWithFormat:
- _( @"Final size: %dx%d" ), title->outWidth, title->outHeight]];
-}
-
-- (void) DetectDrives: (NSNotification *) notification
+- (IBAction) TitlePopUpChanged: (id) sender
{
- /* Scan DVD drives (stolen from VLC) */
- io_object_t next_media;
- mach_port_t master_port;
- kern_return_t kern_result;
- io_iterator_t media_iterator;
- CFMutableDictionaryRef classes_to_match;
-
- kern_result = IOMasterPort( MACH_PORT_NULL, &master_port );
- if( kern_result != KERN_SUCCESS )
- {
- return;
- }
+ hb_list_t * list = hb_get_titles( fHandle );
+ hb_title_t * title = (hb_title_t*)
+ hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
- classes_to_match = IOServiceMatching( kIODVDMediaClass );
- if( classes_to_match == NULL )
+ /* Update chapter popups */
+ [fSrcChapterStartPopUp removeAllItems];
+ [fSrcChapterEndPopUp removeAllItems];
+ for( int i = 0; i < hb_list_count( title->list_chapter ); i++ )
{
- return;
+ [fSrcChapterStartPopUp addItemWithTitle: [NSString
+ stringWithFormat: @"%d", i + 1]];
+ [fSrcChapterEndPopUp addItemWithTitle: [NSString
+ stringWithFormat: @"%d", i + 1]];
}
+ [fSrcChapterStartPopUp selectItemAtIndex: 0];
+ [fSrcChapterEndPopUp selectItemAtIndex:
+ hb_list_count( title->list_chapter ) - 1];
+ [self ChapterPopUpChanged: NULL];
- CFDictionarySetValue( classes_to_match, CFSTR( kIOMediaEjectableKey ),
- kCFBooleanTrue );
-
- kern_result =
- IOServiceGetMatchingServices( master_port, classes_to_match,
- &media_iterator );
- if( kern_result != KERN_SUCCESS )
+ /* Update subtitle popups */
+ hb_subtitle_t * subtitle;
+ [fSubPopUp removeAllItems];
+ [fSubPopUp addItemWithTitle: @"None"];
+ for( int i = 0; i < hb_list_count( title->list_subtitle ); i++ )
{
- return;
- }
-
- NSMutableArray * drivesList;
- drivesList = [NSMutableArray arrayWithCapacity: 1];
-
- next_media = IOIteratorNext( media_iterator );
- if( next_media != NULL )
- {
- char psz_buf[0x32];
- size_t dev_path_length;
- CFTypeRef str_bsd_path;
- do
- {
- str_bsd_path =
- IORegistryEntryCreateCFProperty( next_media,
- CFSTR( kIOBSDNameKey ),
- kCFAllocatorDefault,
- 0 );
- if( str_bsd_path == NULL )
- {
- IOObjectRelease( next_media );
- continue;
- }
+ subtitle = (hb_subtitle_t *) hb_list_item( title->list_subtitle, i );
- snprintf( psz_buf, sizeof(psz_buf), "%s%c", _PATH_DEV, 'r' );
- dev_path_length = strlen( psz_buf );
-
- if( CFStringGetCString( (CFStringRef) str_bsd_path,
- (char*)&psz_buf + dev_path_length,
- sizeof(psz_buf) - dev_path_length,
- kCFStringEncodingASCII ) )
- {
- [drivesList addObject:
- [NSString stringWithCString: psz_buf]];
- }
-
- CFRelease( str_bsd_path );
-
- IOObjectRelease( next_media );
-
- } while( ( next_media = IOIteratorNext( media_iterator ) ) != NULL );
+ /* We cannot use NSPopUpButton's addItemWithTitle because
+ it checks for duplicate entries */
+ [[fSubPopUp menu] addItemWithTitle: [NSString stringWithCString:
+ subtitle->lang] action: NULL keyEquivalent: @""];
}
+ [fSubPopUp selectItemAtIndex: 0];
- IOObjectRelease( media_iterator );
-
- [fScDetectedPopUp removeAllItems];
- for( unsigned i = 0; i < [drivesList count]; i++ )
+ /* Update lang popups */
+ hb_audio_t * audio;
+ [fAudLang1PopUp removeAllItems];
+ [fAudLang2PopUp removeAllItems];
+ [fAudLang1PopUp addItemWithTitle: _( @"None" )];
+ [fAudLang2PopUp addItemWithTitle: _( @"None" )];
+ for( int i = 0; i < hb_list_count( title->list_audio ); i++ )
{
- [[fScDetectedPopUp menu] addItemWithTitle:
- [drivesList objectAtIndex: i] action: nil
- keyEquivalent: @""];
- }
- [self ScanMatrixChanged: self];
-}
+ audio = (hb_audio_t *) hb_list_item( title->list_audio, i );
-- (IBAction) ScanMatrixChanged: (id) sender
-{
- if( ![fScMatrix selectedRow] )
- {
- [fScDetectedPopUp setEnabled: YES];
- [fScFolderField setEnabled: NO];
- [fScBrowseButton setEnabled: NO];
- [fScOpenButton setEnabled: ( [fScDetectedPopUp selectedItem] != nil )];
- }
- else
- {
- [fScDetectedPopUp setEnabled: NO];
- [fScFolderField setEnabled: YES];
- [fScBrowseButton setEnabled: YES];
- [fScOpenButton setEnabled: YES];
+ [[fAudLang1PopUp menu] addItemWithTitle:
+ [NSString stringWithCString: audio->lang]
+ action: NULL keyEquivalent: @""];
+ [[fAudLang2PopUp menu] addItemWithTitle:
+ [NSString stringWithCString: audio->lang]
+ action: NULL keyEquivalent: @""];
}
+ [fAudLang1PopUp selectItemAtIndex: 1];
+ [fAudLang2PopUp selectItemAtIndex: 0];
}
-- (IBAction) TitlePopUpChanged: (id) sender
+- (IBAction) ChapterPopUpChanged: (id) sender
{
- HBTitle * title = (HBTitle*)
- HBListItemAt( fTitleList, [fRipTitlePopUp indexOfSelectedItem] );
+ hb_list_t * list = hb_get_titles( fHandle );
+ hb_title_t * title = (hb_title_t *)
+ hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
- [fRipLang1PopUp removeAllItems];
- [fRipLang2PopUp removeAllItems];
-
- HBAudio * audio;
- for( int i = 0; i < HBListCount( title->audioList ); i++ )
+ hb_chapter_t * chapter;
+ int64_t duration = 0;
+ for( int i = [fSrcChapterStartPopUp indexOfSelectedItem];
+ i <= [fSrcChapterEndPopUp indexOfSelectedItem]; i++ )
{
- audio = (HBAudio*) HBListItemAt( title->audioList, i );
-
- /* We cannot use NSPopUpButton's addItemWithTitle because
- it checks for duplicate entries */
- [[fRipLang1PopUp menu] addItemWithTitle:
- [NSString stringWithCString: audio->language]
- action: nil keyEquivalent: @""];
- [[fRipLang2PopUp menu] addItemWithTitle:
- [NSString stringWithCString: audio->language]
- action: nil keyEquivalent: @""];
+ chapter = (hb_chapter_t *) hb_list_item( title->list_chapter, i );
+ duration += chapter->duration;
}
- [fRipLang2PopUp addItemWithTitle: _( @"None" )];
- [fRipLang2PopUp selectItemWithTitle: _( @"None" )];
- [fRipLang2PopUp setEnabled:
- ( HBListCount( title->audioList ) > 1 )];
+
+ duration /= 90000; /* pts -> seconds */
+ [fSrcDuration2Field setStringValue: [NSString stringWithFormat:
+ @"%02lld:%02lld:%02lld", duration / 3600, ( duration / 60 ) % 60,
+ duration % 60]];
- [fRipTargetField SetHBTitle: title];
- if( [fRipVideoMatrix selectedRow] )
- {
- [fRipTargetField UpdateBitrate];
- }
+ [self CalculateBitrate: sender];
}
- (IBAction) FormatPopUpChanged: (id) sender
{
- /* Headers size changes depending on the format, so let's
- recalculate the bitrate if necessary */
- if( [fRipVideoMatrix selectedRow] )
+ NSString * string = [fDstFile2Field stringValue];
+ int format = [fDstFormatPopUp indexOfSelectedItem];
+ char * ext = NULL;
+
+ /* Update the codecs popup */
+ [fDstCodecsPopUp removeAllItems];
+ switch( format )
{
- [fRipTargetField UpdateBitrate];
+ case 0:
+ ext = "mp4";
+ [fDstCodecsPopUp addItemWithTitle:
+ _( @"MPEG-4 Video / AAC Audio" )];
+ [fDstCodecsPopUp addItemWithTitle:
+ _( @"AVC/H.264 Video / AAC Audio" )];
+ break;
+ case 1:
+ ext = "avi";
+ [fDstCodecsPopUp addItemWithTitle:
+ _( @"MPEG-4 Video / MP3 Audio" )];
+ [fDstCodecsPopUp addItemWithTitle:
+ _( @"MPEG-4 Video / AC-3 Audio" )];
+ [fDstCodecsPopUp addItemWithTitle:
+ _( @"AVC/H.264 Video / MP3 Audio" )];
+ [fDstCodecsPopUp addItemWithTitle:
+ _( @"AVC/H.264 Video / AC-3 Audio" )];
+ break;
+ case 2:
+ ext = "ogm";
+ [fDstCodecsPopUp addItemWithTitle:
+ _( @"MPEG-4 Video / Vorbis Audio" )];
+ [fDstCodecsPopUp addItemWithTitle:
+ _( @"MPEG-4 Video / MP3 Audio" )];
+ break;
}
+ [self CodecsPopUpChanged: NULL];
/* Add/replace to the correct extension */
- NSString * string = [fRipFileField2 stringValue];
- int format = [fRipFormatPopUp indexOfSelectedItem];
if( [string characterAtIndex: [string length] - 4] == '.' )
{
- [fRipFileField2 setStringValue: [NSString stringWithFormat:
+ [fDstFile2Field setStringValue: [NSString stringWithFormat:
@"%@.%s", [string substringToIndex: [string length] - 4],
- ( !format ) ? "mp4" : ( ( format == 3 ) ?
- "ogm" : "avi" )]];
+ ext]];
}
else
{
- [fRipFileField2 setStringValue: [NSString stringWithFormat:
- @"%@.%s", string, ( !format ) ? "mp4" :
- ( ( format == 3 ) ? "ogm" : "avi" )]];
+ [fDstFile2Field setStringValue: [NSString stringWithFormat:
+ @"%@.%s", string, ext]];
}
+}
- if( format == 2 )
+- (IBAction) CodecsPopUpChanged: (id) sender
+{
+ int format = [fDstFormatPopUp indexOfSelectedItem];
+ int codecs = [fDstCodecsPopUp indexOfSelectedItem];
+
+ /* Update the encoder popup if necessary */
+ if( ( FormatSettings[format][codecs] & HB_VCODEC_X264 ) &&
+ [fVidEncoderPopUp numberOfItems] > 1 )
{
- /* Can't set X264 bitrate */
- [fRipEncoderPopUp setEnabled: NO];
- [fRipVideoMatrix setEnabled: NO];
- [fRipTwoPassCheck setEnabled: NO];
+ /* MPEG-4 -> H.264 */
+ [fVidEncoderPopUp removeAllItems];
+ [fVidEncoderPopUp addItemWithTitle: @"x264 (Main profile)"];
+ [fVidEncoderPopUp addItemWithTitle: @"x264 (Baseline profile)"];
}
- else if( format == 3 )
+ else if( ( FormatSettings[format][codecs] & HB_VCODEC_FFMPEG ) &&
+ [fVidEncoderPopUp numberOfItems] < 2 )
+ {
+ /* H.264 -> MPEG-4 */
+ [fVidEncoderPopUp removeAllItems];
+ [fVidEncoderPopUp addItemWithTitle: @"FFmpeg"];
+ [fVidEncoderPopUp addItemWithTitle: @"XviD"];
+ [fVidEncoderPopUp selectItemAtIndex: 0];
+ }
+
+ if( FormatSettings[format][codecs] & HB_ACODEC_AC3 )
{
- [fRipEncoderPopUp setEnabled: YES];
- [fRipVideoMatrix setEnabled: YES];
- [fRipTwoPassCheck setEnabled: YES];
+ /* AC-3 pass-through: disable samplerate and bitrate */
+ [fAudRatePopUp setEnabled: NO];
+ [fAudBitratePopUp setEnabled: NO];
}
else
{
- [fRipEncoderPopUp setEnabled: YES];
- [fRipVideoMatrix setEnabled: YES];
- [fRipTwoPassCheck setEnabled: YES];
+ [fAudRatePopUp setEnabled: YES];
+ [fAudBitratePopUp setEnabled: YES];
}
- [self VideoMatrixChanged: self];
+
+ [self CalculateBitrate: sender];
}
-- (IBAction) AudioPopUpChanged: (id) sender
+- (IBAction) CalculateBitrate: (id) sender
{
- /* Recalculate the bitrate */
- if( [fRipVideoMatrix selectedRow] )
+ if( !fHandle || [fVidQualityMatrix selectedRow] != 0 )
{
- [fRipTargetField UpdateBitrate];
+ return;
}
+
+ hb_list_t * list = hb_get_titles( fHandle );
+ hb_title_t * title = (hb_title_t *) hb_list_item( list,
+ [fSrcTitlePopUp indexOfSelectedItem] );
+ hb_job_t * job = title->job;
+
+ [self PrepareJob];
+
+ [fVidBitrateField setIntValue: hb_calc_bitrate( job,
+ [fVidTargetSizeField intValue] )];
}
-/*******************
- * libhb callbacks *
- *******************/
-static void _Scanning( void * data, int title, int titleCount )
+- (void) controlTextDidBeginEditing: (NSNotification *) notification
{
- HBController * controller = (HBController*) data;
- controller->fTitle = title;
- controller->fTitleCount = titleCount;
- [controller performSelectorOnMainThread: @selector(Scanning:)
- withObject: nil waitUntilDone: YES];
+ [self CalculateBitrate: NULL];
}
-- (void) Scanning: (id) sender
-{
- [fScProgress stopAnimation: self];
- [fScProgress setIndeterminate: NO];
- [fScProgress setDoubleValue: 100.0 * fTitle / fTitleCount];
- [fScStatusField setStringValue: [NSString stringWithFormat:
- _( @"Scanning title %d of %d..." ), fTitle, fTitleCount]];
+- (void) controlTextDidEndEditing: (NSNotification *) notification
+{
+ [self CalculateBitrate: NULL];
}
-static void _ScanDone( void * data, HBList * titleList )
+- (void) controlTextDidChange: (NSNotification *) notification
{
- HBController * controller = (HBController*) data;
- controller->fTitleList = titleList;
- [controller performSelectorOnMainThread: @selector(ScanDone:)
- withObject: nil waitUntilDone: YES];
+ [self CalculateBitrate: NULL];
}
-- (void) ScanDone: (id) sender
+
+- (IBAction) OpenHomepage: (id) sender
{
- if( !fTitleList )
- {
- [fScMatrix setEnabled: YES];
- [self ScanMatrixChanged: self];
- [fScProgress stopAnimation: self];
- [fScProgress setIndeterminate: NO];
- [fScOpenButton setEnabled: YES];
- [fScStatusField setStringValue:
- _( @"Invalid volume, try again" ) ];
- return;
- }
+ [[NSWorkspace sharedWorkspace] openURL: [NSURL
+ URLWithString:@"http://handbrake.m0k.org/"]];
+}
- /* Show a temporary empty view while the window
- resizing animation */
- [fWindow setContentView: fTempView ];
-
- /* Actually resize it */
- NSRect newFrame;
- newFrame = [NSWindow contentRectForFrameRect: [fWindow frame]
- styleMask: [fWindow styleMask]];
- newFrame.origin.y += newFrame.size.height -
- [fRipView frame].size.height;
- newFrame.size.height = [fRipView frame].size.height;
- newFrame.size.width = [fRipView frame].size.width;
- newFrame = [NSWindow frameRectForContentRect: newFrame
- styleMask: [fWindow styleMask]];
- [fWindow setFrame: newFrame display: YES animate: YES];
-
- /* Show the new GUI */
- [fWindow setContentView: fRipView ];
- [fRipPauseButton setEnabled: NO];
-
- [fRipTitlePopUp removeAllItems];
- HBTitle * title;
- for( int i = 0; i < HBListCount( fTitleList ); i++ )
- {
- title = (HBTitle*) HBListItemAt( fTitleList, i );
- [[fRipTitlePopUp menu] addItemWithTitle:
- [NSString stringWithFormat: @"%d - %02dh%02dm%02ds",
- title->title, title->hours, title->minutes,
- title->seconds] action: nil keyEquivalent: @""];
- }
- [self TitlePopUpChanged: self];
-}
-
-static void _Encoding( void * data, float position, int pass,
- int passCount, float curFrameRate,
- float avgFrameRate, int remainingTime )
-{
- HBController * controller = (HBController*) data;
- controller->fPosition = position;
- controller->fPass = pass;
- controller->fPassCount = passCount;
- controller->fCurFrameRate = curFrameRate;
- controller->fAvgFrameRate = avgFrameRate;
- controller->fRemainingTime = remainingTime;
- [controller performSelectorOnMainThread: @selector(Encoding:)
- withObject: nil waitUntilDone: YES];
-}
-- (void) Encoding: (id) sender
-{
- [fRipStatusField setStringValue: [NSString stringWithFormat:
- _( @"Encoding: %.2f %% (pass %d of %d)" ),
- 100.0 * fPosition, fPass, fPassCount]];
- [fRipInfoField setStringValue: [NSString stringWithFormat:
- _( @"Speed: %.2f fps (avg %.2f fps), %02dh%02dm%02ds remaining" ),
- fCurFrameRate, fAvgFrameRate, fRemainingTime / 3600,
- ( fRemainingTime / 60 ) % 60, fRemainingTime % 60]];
-
- [fRipProgress setIndeterminate: NO];
- [fRipProgress setDoubleValue: 100.0 * fPosition];
-}
-
-static void _RipDone( void * data, int result )
-{
- HBController * controller = (HBController*) data;
- controller->fResult = result;
- [controller performSelectorOnMainThread: @selector(RipDone:)
- withObject: nil waitUntilDone: YES];
-}
-- (void) RipDone: (id) sender
-{
- [fRipTitlePopUp setEnabled: YES];
- [fRipFormatPopUp setEnabled: YES];
- [fRipVideoMatrix setEnabled: YES];
- [fRipTwoPassCheck setEnabled: YES];
- [fRipCropButton setEnabled: YES];
- [fRipLang1PopUp setEnabled: YES];
- [fRipLang2PopUp setEnabled: YES];
- [fRipAudBitPopUp setEnabled: YES];
- [fRipFileField2 setEnabled: YES];
- [fRipBrowseButton setEnabled: YES];
- [fRipEncoderPopUp setEnabled: YES];
- [fRipPauseButton setEnabled: NO];
- [fRipPauseButton setTitle: _( @"Pause" )];
- [fRipRipButton setTitle: _( @"Rip" )];
- [fRipProgress setIndeterminate: NO];
- [fRipProgress setDoubleValue: 0.0];
- [self VideoMatrixChanged: self];
-
- switch( fResult )
- {
- case HB_SUCCESS:
- [fRipStatusField setStringValue: _( @"Rip completed." )];
- [fRipInfoField setStringValue: @""];
- NSBeep();
- [NSApp requestUserAttention: NSInformationalRequest];
- [NSApp beginSheet: fDonePanel
- modalForWindow: fWindow modalDelegate: nil
- didEndSelector: nil contextInfo: nil];
- [NSApp runModalForWindow: fDonePanel];
- [NSApp endSheet: fDonePanel];
- [fDonePanel orderOut: self];
- break;
- case HB_CANCELED:
- [fRipStatusField setStringValue: _( @"Canceled." )];
- [fRipInfoField setStringValue: @""];
- break;
- case HB_ERROR_A52_SYNC:
- [fRipStatusField setStringValue: @"Error."];
- [fRipInfoField setStringValue: @"Corrupted AC3 data"];
- break;
- case HB_ERROR_AVI_WRITE:
- [fRipStatusField setStringValue: @"Error."];
- [fRipInfoField setStringValue: @"Write error"];
- break;
- case HB_ERROR_DVD_OPEN:
- [fRipStatusField setStringValue: @"Error."];
- [fRipInfoField setStringValue: @"Could not open the DVD"];
- break;
- case HB_ERROR_DVD_READ:
- [fRipStatusField setStringValue: @"Error."];
- [fRipInfoField setStringValue: @"DVD read error"];
- break;
- case HB_ERROR_MP3_INIT:
- [fRipStatusField setStringValue: @"Error."];
- [fRipInfoField setStringValue:
- @"MP3 encoder initialization failed"];
- break;
- case HB_ERROR_MP3_ENCODE:
- [fRipStatusField setStringValue: @"Error."];
- [fRipInfoField setStringValue: @"MP3 encoder failed"];
- break;
- case HB_ERROR_MPEG4_INIT:
- [fRipStatusField setStringValue: @"Error."];
- [fRipInfoField setStringValue:
- @"MPEG4 encoder initialization failed"];
- break;
- default:
- [fRipStatusField setStringValue: @"Error."];
- [fRipInfoField setStringValue: @"Unknown error"];
- }
+- (IBAction) OpenForums: (id) sender
+{
+ [[NSWorkspace sharedWorkspace] openURL: [NSURL
+ URLWithString:@"http://handbrake.m0k.org/forum/"]];
}
@end