+/* This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
#import "ExpressController.h"
-#import "DriveDetector.h"
-#define INSERT_STRING @"Insert a DVD"
+#define INSERT_STRING @"Insert a DVD"
+#define TOOLBAR_START @"TOOLBAR_START"
+#define TOOLBAR_PAUSE @"TOOLBAR_PAUSE"
+#define TOOLBAR_OPEN @"TOOLBAR_OPEN"
+#define TOOLBAR_ADVANCED @"TOOLBAR_ADVANCED"
+
+#define p fState->param
+
+#import "Device.h"
@interface ExpressController (Private)
- (void) openBrowseDidEnd: (NSOpenPanel *) sheet returnCode: (int)
returnCode contextInfo: (void *) contextInfo;
- (void) openEnable: (BOOL) b;
-- (void) openTimer: (NSTimer *) timer;
+- (id) updatePopUpIcon: (id) value;
- (void) convertShow;
- (void) convertEnable: (BOOL) b;
-- (void) convertTimer: (NSTimer *) timer;
@end
- (void) awakeFromNib
{
NSEnumerator * enumerator;
-
+
+ /* NSToolbar initializations */
+ fToolbar = [[NSToolbar alloc] initWithIdentifier: @"InstantHandBrake Toolbar"];
+ [fToolbar setDelegate: self];
+ [fToolbar setAllowsUserCustomization: NO];
+ [fToolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
+ [fToolbar setVisible:NO];
+ [fWindow setShowsToolbarButton:NO];
+ [fWindow setToolbar: fToolbar];
+
/* Show the "Open DVD" interface */
fDriveDetector = [[DriveDetector alloc] initWithCallback: self
selector: @selector( openUpdateDrives: )];
[tableColumn setDataCell: buttonCell];
/* Preferences */
- fConvertFolderString = [@"~/Movies" stringByExpandingTildeInPath];
+ fConvertFolderString = [NSHomeDirectory() stringByAppendingPathComponent:@"Desktop"];
[fConvertFolderString retain];
}
- (void) applicationWillFinishLaunching: (NSNotification *) n
{
- fHandle = hb_init_express( HB_DEBUG_NONE, 0 );
+ fCore = [[HBCore alloc] init];
+ [fCore openInDebugMode:NO checkForUpdates:NO];
+ fHandle = [fCore hb_handle];
+ fState = [fCore hb_state];
fList = hb_get_titles( fHandle );
+
+ fDevice = [[DeviceController alloc] init];
+
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(scanningSource:)
+ name:@"HBCoreScanningNotification" object:nil];
+
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(scanDone:)
+ name:@"HBCoreScanDoneNotification" object:nil];
+
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(muxing:)
+ name:@"HBCoreMuxingNotification" object:nil];
+
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(working:)
+ name:@"HBCoreWorkingNotification" object:nil];
+
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(workDone:)
+ name:@"HBCoreWorkDoneNotification" object:nil];
+
+ [GrowlApplicationBridge setGrowlDelegate: self];
}
- (void) applicationWillTerminate: (NSNotification *) n
{
- hb_close( &fHandle );
+ [fCore close];
+}
+
+- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag
+{
+ if( !flag ) {
+ [fWindow makeKeyAndOrderFront:nil];
+ return YES;
+ }
+ return NO;
+}
+
+- (NSToolbarItem *) toolbar: (NSToolbar *) toolbar itemForItemIdentifier: (NSString *) ident
+ willBeInsertedIntoToolbar: (BOOL) flag
+{
+ NSToolbarItem * item;
+ item = [[NSToolbarItem alloc] initWithItemIdentifier: ident];
+
+ if ([ident isEqualToString: TOOLBAR_START])
+ {
+ [item setLabel: NSLocalizedString(@"Convert", "Convert")];
+ [item setPaletteLabel: NSLocalizedString(@"Convert/Cancel", @"Convert/Cancel")];
+ [item setImage: [NSImage imageNamed: @"Play"]];
+ [item setTarget: self];
+ [item setAction: @selector(convertGo:)];
+ }
+ else if ([ident isEqualToString: TOOLBAR_PAUSE])
+ {
+ [item setLabel: NSLocalizedString(@"Pause", "Pause")];
+ [item setPaletteLabel: NSLocalizedString(@"Pause/Resume", @"Pause/Resume")];
+ [item setImage: [NSImage imageNamed: @"Pause"]];
+ [item setTarget: self];
+ [item setAction: @selector(pauseGo:)];
+ }
+ else if ([ident isEqualToString: TOOLBAR_OPEN])
+ {
+ [item setLabel: NSLocalizedString(@"Open...", "Open...")];
+ [item setPaletteLabel: NSLocalizedString(@"Open Another Source", "Open Another Source")];
+ [item setImage: [NSImage imageNamed: @"Open"]];
+ [item setTarget: self];
+ [item setAction: @selector(openShow:)];
+ }
+ else
+ {
+ [item release];
+ return nil;
+ }
+
+ return item;
+}
+
+- (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar
+{
+ return [NSArray arrayWithObjects: TOOLBAR_START, TOOLBAR_PAUSE,
+ NSToolbarFlexibleSpaceItemIdentifier, TOOLBAR_OPEN, nil];
+}
+
+- (NSArray *) toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar
+{
+ return [NSArray arrayWithObjects: TOOLBAR_START, TOOLBAR_PAUSE,
+ TOOLBAR_OPEN, NSToolbarFlexibleSpaceItemIdentifier, nil];
}
/***********************************************************************
title->seconds];
}
}
+ else if( [[col identifier] isEqualToString: @"Size"] )
+ {
+ return [NSString stringWithFormat:@"-"];
+ }
}
return nil;
}
- (void) openShow: (id) sender
{
NSRect frame = [fWindow frame];
- float offset = [fConvertView frame].size.height -
- [fOpenView frame].size.height;
+ float offset = ( [fConvertView frame].size.height -
+ [fOpenView frame].size.height ) * [fWindow userSpaceScaleFactor];
frame.origin.y += offset;
frame.size.height -= offset;
[fWindow setContentView: fEmptyView];
[fWindow setFrame: frame display: YES animate: YES];
+ [fToolbar setVisible:NO];
+ [fOpenProgressField setStringValue: @""];
[fWindow setContentView: fOpenView];
[fDriveDetector run];
[self openEnable: NO];
[fOpenIndicator setIndeterminate: YES];
[fOpenIndicator startAnimation: nil];
- [fOpenProgressField setStringValue: @"Opening..."];
+ [fOpenProgressField setStringValue: NSLocalizedString( @"Opening...", @"Opening...") ];
[fDriveDetector stop];
if( [fOpenMatrix selectedRow] )
hb_scan( fHandle, [[fDrives objectForKey: [fOpenPopUp
titleOfSelectedItem]] UTF8String], 0 );
}
+}
+
+- (void) selectFolderSheetShow: (id) sender
+{
+ NSOpenPanel * panel = [NSOpenPanel openPanel];
+
+ [panel setPrompt: NSLocalizedString(@"Select", @"Convert -> Save panel prompt")];
+ [panel setAllowsMultipleSelection: NO];
+ [panel setCanChooseFiles: NO];
+ [panel setCanChooseDirectories: YES];
+ [panel setCanCreateDirectories: YES];
+
+ [panel beginSheetForDirectory: nil file: nil types: nil
+ modalForWindow: fWindow modalDelegate: self didEndSelector:
+ @selector(selectFolderSheetClosed:returnCode:contextInfo:) contextInfo: nil];
+}
+
+- (void) selectFolderSheetClosed: (NSOpenPanel *) sheet returnCode: (int)
+ returnCode contextInfo: (void *) contextInfo
+{
+ if( returnCode != NSOKButton )
+ return;
- NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval: 2.0
- target: self selector: @selector( openTimer: ) userInfo: nil
- repeats: YES];
+ if( fConvertFolderString )
+ [fConvertFolderString release];
+ fConvertFolderString = [[[sheet filenames] objectAtIndex: 0] retain];
+ [[fConvertFolderPopUp itemAtIndex: 0] setTitle: [fConvertFolderString lastPathComponent]];
+ [fConvertFolderPopUp selectItemAtIndex:0];
+
+ NSMenuItem * item = [fConvertFolderPopUp itemAtIndex: 0];
+ [item setImage: [self updatePopUpIcon:fConvertFolderString]];
+
}
- (void) convertGo: (id) sender
{
int i, j;
+ Preset * currentPreset = [[[fDevice devicesList] objectAtIndex:[fConvertFormatPopUp indexOfSelectedItem]] firstPreset];
for( i = 0; i < hb_list_count( fList ); i++ )
{
hb_title_t * title = hb_list_item( fList, i );
hb_job_t * job = title->job;
- int pixels = 307200;
+ int maxwidth = [currentPreset maxWidth];
+ int maxheight = [currentPreset maxHeight];
+ int pixels = maxwidth * maxheight;
int aspect = title->aspect;
- if( [fConvertAspectPopUp indexOfSelectedItem] == 1)
+
+ if( [fConvertAspectPopUp indexOfSelectedItem] == 1 )
{
aspect = 4 * HB_ASPECT_BASE / 3;
}
+ else if ( [fConvertAspectPopUp indexOfSelectedItem] == 2 )
+ {
+ aspect = 16 * HB_ASPECT_BASE / 9;
+ }
- int maxwidth = 640;
- job->vbitrate = 1000;
- if( [fConvertMaxWidthPopUp indexOfSelectedItem] == 1)
- {
- maxwidth = 320;
- job->vbitrate = 500;
- }
- job->deinterlace = 1;
+ job->vbitrate = [currentPreset videoBitRate];
- do
+ if( [fConvertMaxWidthPopUp indexOfSelectedItem] == 2 )
{
- hb_set_size( job, aspect, pixels );
- pixels -= 10;
- } while(job->width > maxwidth);
-
- if( [fConvertFormatPopUp indexOfSelectedItem] == 0 )
+ maxwidth = 480;
+ job->vbitrate /= 1.5;
+ }
+ else if ( [fConvertMaxWidthPopUp indexOfSelectedItem] == 3 )
{
- /* iPod / H.264 */
- job->mux = HB_MUX_IPOD;
- job->vcodec = HB_VCODEC_X264;
- job->h264_level = 30;
+ maxwidth = 320;
+ job->vbitrate /= 2;
}
- else if( [fConvertFormatPopUp indexOfSelectedItem] == 1 )
+
+ if ( [fConvertAspectPopUp indexOfSelectedItem] > 0 )
{
- /* iPod / MPEG-4 */
- job->mux = HB_MUX_MP4;
- job->vcodec = HB_VCODEC_FFMPEG;
+ do
+ {
+ hb_set_size( job, aspect, pixels );
+ pixels -= 10;
+ } while(job->width > maxwidth || job->height > maxheight);
}
else
{
- /* PSP / MPEG-4 */
- job->mux = HB_MUX_PSP;
- job->vrate = 27000000;
- job->vrate_base = 900900; /* 29.97 fps */
- job->vcodec = HB_VCODEC_FFMPEG;
- job->vbitrate = 600;
- pixels = 76800;
- job->arate = 24000;
- job->abitrate = 96;
- aspect = 16 * HB_ASPECT_BASE / 9;
-
- if( [fConvertAspectPopUp indexOfSelectedItem] )
- {
- aspect = -1;
- }
-
- hb_set_size( job, aspect, pixels );
+ /* Reset job->crop values */
+ memcpy( job->crop, job->title->crop, 4 * sizeof( int ) );
+ job->width = maxwidth;
+ hb_fix_aspect( job, HB_KEEP_WIDTH );
}
-
+
+ job->mux = [currentPreset muxer];
+ job->vcodec = [currentPreset videoCodec];
+ job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */
+ strcpy(job->x264opts, [[currentPreset videoCodecOptions] UTF8String]);
+ job->chapter_markers = 1;
job->vquality = -1.0;
const char * lang;
hb_start( fHandle );
- NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval: 2.0
- target: self selector: @selector( convertTimer: ) userInfo: nil
- repeats: YES];
-
[self convertEnable: NO];
}
[self openGo: self];
}
+- (BOOL)validateToolbarItem: (NSToolbarItem *) toolbarItem
+{
+ NSString * ident = [toolbarItem itemIdentifier];
+
+ if ([ident isEqualToString: TOOLBAR_START] && [HBStateWorking isEqualToString:[fCore state]])
+ {
+ [toolbarItem setAction: @selector(convertCancel:)];
+ [toolbarItem setLabel:NSLocalizedString(@"Cancel", @"Cancel")];
+ return YES;
+ }
+ else if ([ident isEqualToString: TOOLBAR_START] && [HBStateWorkDone isEqualToString:[fCore state]])
+ {
+ [toolbarItem setAction: @selector(convertGo:)];
+ [toolbarItem setLabel:NSLocalizedString(@"Convert", @"Convert")];
+ return YES;
+ }
+ else if ([ident isEqualToString: TOOLBAR_OPEN] && [HBStateWorking isEqualToString:[fCore state]])
+ {
+ return NO;
+ }
+
+ return YES;
+}
+
- (void) openEnable: (BOOL) b
{
[fOpenMatrix setEnabled: b];
[fOpenPopUp setEnabled: b];
[fOpenFolderField setEnabled: b];
[fOpenBrowseButton setEnabled: b];
- [fOpenGoButton setEnabled: b];
+ [fOpenGoButton setEnabled: b];
if( b )
{
}
}
-- (void) openTimer: (NSTimer *) timer
+- (void) scanningSource: (NSNotification *) n
{
- hb_state_t s;
- hb_get_state( fHandle, &s );
- switch( s.state )
- {
-#define p s.param.scanning
- case HB_STATE_SCANNING:
- [fOpenIndicator setIndeterminate: NO];
- [fOpenIndicator setDoubleValue: 100.0 *
- ( (float) p.title_cur - 0.5 ) / p.title_count];
- [fOpenProgressField setStringValue: [NSString
- stringWithFormat: @"Scanning title %d of %d...",
- p.title_cur, p.title_count]];
- break;
-#undef p
-
- case HB_STATE_SCANDONE:
- [timer invalidate];
-
- [fOpenIndicator setIndeterminate: NO];
- [fOpenIndicator setDoubleValue: 0.0];
- [self openEnable: YES];
-
- if( hb_list_count( fList ) )
- {
- [self convertShow];
- }
- else
- {
- [fDriveDetector run];
- }
- break;
+ [fOpenIndicator setIndeterminate: NO];
+ [fOpenIndicator setDoubleValue: 100.0 *
+ ( (float) p.scanning.title_cur - 0.5 ) / p.scanning.title_count];
+ [fOpenProgressField setStringValue: [NSString
+ stringWithFormat: @"Scanning title %d of %d...",
+ p.scanning.title_cur, p.scanning.title_count]];
+}
- default:
- break;
+- (void) scanDone: (NSNotification *) n
+{
+ [fOpenIndicator setIndeterminate: NO];
+ [fOpenIndicator setDoubleValue: 0.0];
+
+ [self openEnable: YES];
+
+ if( hb_list_count( fList ) )
+ {
+ [self convertShow];
+ }
+ else
+ {
+ [fDriveDetector run];
+ [fOpenProgressField setStringValue: NSLocalizedString(@"No Title Found...",@"No Title Found...")];
}
}
[NSString stringWithUTF8String: audio->lang_simple]];
}
[fConvertAudioPopUp selectItemWithTitle: @"English"];
+
+ if ( [fConvertAudioPopUp selectedItem] == nil )
+ [fConvertAudioPopUp selectItemAtIndex:0];
/* Update subtitle popup */
hb_subtitle_t * subtitle;
}
}
[fConvertTableView reloadData];
+
+ NSEnumerator * enumerator;
+ Device * device;
+ enumerator = [[fDevice devicesList] objectEnumerator];
+
+ while( ( device = [enumerator nextObject] ) )
+ [fConvertFormatPopUp addItemWithTitle:[device name]];
NSRect frame = [fWindow frame];
- float offset = [fConvertView frame].size.height -
- [fOpenView frame].size.height;
+ float offset = ( [fConvertView frame].size.height -
+ [fOpenView frame].size.height ) * [fWindow userSpaceScaleFactor];;
frame.origin.y -= offset;
frame.size.height += offset;
[fWindow setContentView: fEmptyView];
[fWindow setFrame: frame display: YES animate: YES];
+ [fToolbar setVisible:YES];
[fWindow setContentView: fConvertView];
- /* Folder popup */
NSMenuItem * item = [fConvertFolderPopUp itemAtIndex: 0];
[item setTitle: [fConvertFolderString lastPathComponent]];
- NSImage * image32 = [[NSWorkspace sharedWorkspace] iconForFile:
- fConvertFolderString];
- NSImage * image16 = [[NSImage alloc] initWithSize:
- NSMakeSize(16,16)];
- [image16 lockFocus];
- [[NSGraphicsContext currentContext]
- setImageInterpolation: NSImageInterpolationHigh];
- [image32 drawInRect: NSMakeRect(0,0,16,16)
- fromRect: NSMakeRect(0,0,32,32) operation: NSCompositeCopy
- fraction: 1.0];
- [image16 unlockFocus];
- [item setImage: image16];
- [image16 release];
-
+ [item setImage: [self updatePopUpIcon:fConvertFolderString]];
+
[self convertEnable: YES];
}
[fConvertMaxWidthPopUp setEnabled: b];
[fConvertAudioPopUp setEnabled: b];
[fConvertSubtitlePopUp setEnabled: b];
- [fConvertOpenButton setEnabled: b];
- if( b )
- {
- [fConvertGoButton setTitle: @"Convert"];
- [fConvertGoButton setAction: @selector(convertGo:)];
- }
- else
- {
- [fConvertGoButton setTitle: @"Cancel"];
- [fConvertGoButton setAction: @selector(convertCancel:)];
- }
}
/***********************************************************************
[icon release];
}
-- (void) convertTimer: (NSTimer *) timer
+- (id) updatePopUpIcon: (id) value
{
- hb_state_t s;
- hb_get_state( fHandle, &s );
- switch( s.state )
+ if (!value)
+ return nil;
+
+ NSImage * icon;
+
+ icon = [[NSWorkspace sharedWorkspace] iconForFile: value];
+
+ [icon setScalesWhenResized: YES];
+ [icon setSize: NSMakeSize(16.0 , 16.0)];
+
+ return icon;
+}
+
+- (void) working: (NSNotification *) n
+{
+ float progress_total = ( p.working.progress + p.working.job_cur - 1 ) / p.working.job_count;
+ NSMutableString * string = [NSMutableString stringWithFormat: @"Converting: %.1f %%", 100.0 * progress_total];
+
+ if( p.working.seconds > -1 )
{
-#define p s.param.working
- case HB_STATE_WORKING:
+ [string appendFormat: @" (%.1f fps, ", p.working.rate_avg];
+ if( p.working.hours > 0 )
{
- float progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count;
- NSMutableString * string = [NSMutableString
- stringWithFormat: @"Converting: %.1f %%",
- 100.0 * progress_total];
- if( p.seconds > -1 )
- {
- [string appendFormat: @" (%.1f fps, ", p.rate_avg];
- if( p.hours > 0 )
- {
- [string appendFormat: @"%d hour%s %d min%s",
- p.hours, p.hours == 1 ? "" : "s",
- p.minutes, p.minutes == 1 ? "" : "s"];
- }
- else if( p.minutes > 0 )
- {
- [string appendFormat: @"%d min%s %d sec%s",
- p.minutes, p.minutes == 1 ? "" : "s",
- p.seconds, p.seconds == 1 ? "" : "s"];
- }
- else
- {
- [string appendFormat: @"%d second%s",
- p.seconds, p.seconds == 1 ? "" : "s"];
- }
- [string appendString: @" left)"];
- }
- [fConvertInfoString setStringValue: string];
- [fConvertIndicator setIndeterminate: NO];
- [fConvertIndicator setDoubleValue: 100.0 * progress_total];
- [self UpdateDockIcon: progress_total];
- break;
+ [string appendFormat: @"%d hour%s %d min%s",
+ p.working.hours, p.working.hours == 1 ? "" : "s",
+ p.working.minutes, p.working.minutes == 1 ? "" : "s"];
}
-#undef p
-
-#define p s.param.muxing
- case HB_STATE_MUXING:
+ else if( p.working.minutes > 0 )
{
- NSMutableString * string = [NSMutableString
- stringWithFormat: @"Muxing..."];
- [fConvertInfoString setStringValue: string];
- [fConvertIndicator setIndeterminate: YES];
- [fConvertIndicator startAnimation: nil];
- [self UpdateDockIcon: 1.0];
- break;
+ [string appendFormat: @"%d min%s %d sec%s",
+ p.working.minutes, p.working.minutes == 1 ? "" : "s",
+ p.working.seconds, p.working.seconds == 1 ? "" : "s"];
}
-#undef p
-
- case HB_STATE_WORKDONE:
- {
- [timer invalidate];
- [fConvertIndicator setIndeterminate: NO];
- [fConvertIndicator setDoubleValue: 0.0];
- [self UpdateDockIcon: -1.0];
- [self convertEnable: YES];
-
-#define p s.param.workdone
- switch(p.error)
- {
- case HB_ERROR_NONE:
- [fConvertInfoString setStringValue: @"Done."];
- break;
- case HB_ERROR_CANCELED:
- [fConvertInfoString setStringValue: @"Canceled."];
- break;
- case HB_ERROR_UNKNOWN:
- [fConvertInfoString setStringValue: @"Unknown Error."];
- break;
- }
-#undef p
-
- hb_job_t * job;
- while( ( job = hb_job( fHandle, 0 ) ) )
- {
- hb_rem( fHandle, job );
- }
- break;
- }
- default:
- break;
+ else
+ {
+ [string appendFormat: @"%d second%s",
+ p.working.seconds, p.working.seconds == 1 ? "" : "s"];
+ }
+ [string appendString: @" left)"];
}
+
+ [fConvertInfoString setStringValue: string];
+ [fConvertIndicator setIndeterminate: NO];
+ [fConvertIndicator setDoubleValue: 100.0 * progress_total];
+ [self UpdateDockIcon: progress_total];
+}
+
+- (void) muxing: (NSNotification *) n
+{
+ [fConvertInfoString setStringValue: NSLocalizedString(@"Muxing...",@"Muxing...")];
+ [fConvertIndicator setIndeterminate: YES];
+ [fConvertIndicator startAnimation: nil];
+ [self UpdateDockIcon: 1.0];
+}
+
+- (void) workDone: (NSNotification *) n
+{
+ [fConvertIndicator setIndeterminate: NO];
+ [fConvertIndicator setDoubleValue: 0.0];
+ [self UpdateDockIcon: -1.0];
+ [self convertEnable: YES];
+
+ [fConvertInfoString setStringValue: NSLocalizedString(@"Done.",@"Done.")];
+
+ [fCore removeAllJobs];
}
@end