/macosx/Controller.m
Objective C | 6731 lines | 4636 code | 972 blank | 1123 comment | 908 complexity | d7b57d2e706aa732da110d208559e42e MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, BSD-2-Clause, MIT
Large files files are truncated, but you can click here to view the full file
- /* $Id: Controller.mm,v 1.79 2005/11/04 19:41:32 titer Exp $
- 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. */
- #include <dlfcn.h>
- #import "Controller.h"
- #import "HBOutputPanelController.h"
- #import "HBPreferencesController.h"
- #import "HBDVDDetector.h"
- #import "HBPresets.h"
- #import "HBPreviewController.h"
- unsigned int maximumNumberOfAllowedAudioTracks = 24;
- NSString *HBContainerChangedNotification = @"HBContainerChangedNotification";
- NSString *keyContainerTag = @"keyContainerTag";
- NSString *HBTitleChangedNotification = @"HBTitleChangedNotification";
- NSString *keyTitleTag = @"keyTitleTag";
- #define DragDropSimplePboardType @"MyCustomOutlineViewPboardType"
- /* We setup the toolbar values here ShowPreviewIdentifier */
- static NSString * ToggleDrawerIdentifier = @"Toggle Drawer Item Identifier";
- static NSString * StartEncodingIdentifier = @"Start Encoding Item Identifier";
- static NSString * PauseEncodingIdentifier = @"Pause Encoding Item Identifier";
- static NSString * ShowQueueIdentifier = @"Show Queue Item Identifier";
- static NSString * AddToQueueIdentifier = @"Add to Queue Item Identifier";
- static NSString * ShowPictureIdentifier = @"Show Picture Window Item Identifier";
- static NSString * ShowPreviewIdentifier = @"Show Preview Window Item Identifier";
- static NSString * ShowActivityIdentifier = @"Debug Output Item Identifier";
- static NSString * ChooseSourceIdentifier = @"Choose Source Item Identifier";
- /*******************************
- * HBController implementation *
- *******************************/
- @implementation HBController
- + (unsigned int) maximumNumberOfAllowedAudioTracks { return maximumNumberOfAllowedAudioTracks; }
- - (id)init
- {
- self = [super init];
- if( !self )
- {
- return nil;
- }
- /* replace bundled app icon with one which is 32/64-bit savvy */
- #if defined( __LP64__ )
- fApplicationIcon = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:@"HandBrake-64.icns"]];
- #else
- fApplicationIcon = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:@"HandBrake.icns"]];
- #endif
- if( fApplicationIcon != nil )
- [NSApp setApplicationIconImage:fApplicationIcon];
-
- [HBPreferencesController registerUserDefaults];
- fHandle = NULL;
- fQueueEncodeLibhb = NULL;
- /* Check for check for the app support directory here as
- * outputPanel needs it right away, as may other future methods
- */
- NSString *libraryDir = [NSSearchPathForDirectoriesInDomains( NSLibraryDirectory,
- NSUserDomainMask,
- YES ) objectAtIndex:0];
- AppSupportDirectory = [[libraryDir stringByAppendingPathComponent:@"Application Support"]
- stringByAppendingPathComponent:@"HandBrake"];
- if( ![[NSFileManager defaultManager] fileExistsAtPath:AppSupportDirectory] )
- {
- [[NSFileManager defaultManager] createDirectoryAtPath:AppSupportDirectory
- attributes:nil];
- }
- /* Check for and create the App Support Preview directory if necessary */
- NSString *PreviewDirectory = [AppSupportDirectory stringByAppendingPathComponent:@"Previews"];
- if( ![[NSFileManager defaultManager] fileExistsAtPath:PreviewDirectory] )
- {
- [[NSFileManager defaultManager] createDirectoryAtPath:PreviewDirectory
- attributes:nil];
- }
- outputPanel = [[HBOutputPanelController alloc] init];
- fPictureController = [[PictureController alloc] init];
- fQueueController = [[HBQueueController alloc] init];
- fAdvancedOptions = [[HBAdvancedController alloc] init];
- /* we init the HBPresets class which currently is only used
- * for updating built in presets, may move more functionality
- * there in the future
- */
- fPresetsBuiltin = [[HBPresets alloc] init];
- fPreferencesController = [[HBPreferencesController alloc] init];
- /* Lets report the HandBrake version number here to the activity log and text log file */
- NSString *versionStringFull = [[NSString stringWithFormat: @"Handbrake Version: %@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]] stringByAppendingString: [NSString stringWithFormat: @" (%@)", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]]];
- [self writeToActivityLog: "%s", [versionStringFull UTF8String]];
-
- return self;
- }
- - (void) applicationDidFinishLaunching: (NSNotification *) notification
- {
- /* Init libhb with check for updates libhb style set to "0" so its ignored and lets sparkle take care of it */
- int loggingLevel = [[[NSUserDefaults standardUserDefaults] objectForKey:@"LoggingLevel"] intValue];
- fHandle = hb_init(loggingLevel, 0);
- /* Optional dvd nav UseDvdNav*/
- hb_dvd_set_dvdnav([[[NSUserDefaults standardUserDefaults] objectForKey:@"UseDvdNav"] boolValue]);
- /* Init a separate instance of libhb for user scanning and setting up jobs */
- fQueueEncodeLibhb = hb_init(loggingLevel, 0);
-
- // Set the Growl Delegate
- [GrowlApplicationBridge setGrowlDelegate: self];
- /* Init others controllers */
- [fPictureController SetHandle: fHandle];
- [fPictureController setHBController: self];
-
- [fQueueController setHandle: fQueueEncodeLibhb];
- [fQueueController setHBController: self];
- fChapterTitlesDelegate = [[ChapterTitles alloc] init];
- [fChapterTable setDataSource:fChapterTitlesDelegate];
- [fChapterTable setDelegate:fChapterTitlesDelegate];
-
- /* setup the subtitles delegate and connections to table */
- fSubtitlesDelegate = [[HBSubtitles alloc] init];
- [fSubtitlesTable setDataSource:fSubtitlesDelegate];
- [fSubtitlesTable setDelegate:fSubtitlesDelegate];
- [fSubtitlesTable setRowHeight:25.0];
-
- /* setup the audio controller */
- [fAudioDelegate setHBController: self];
- [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(autoSetM4vExtension:) name: HBMixdownChangedNotification object: nil];
- [fPresetsOutlineView setAutosaveName:@"Presets View"];
- [fPresetsOutlineView setAutosaveExpandedItems:YES];
-
- dockIconProgress = 0;
-
- /* Init QueueFile .plist */
- [self loadQueueFile];
- /* Run hbInstances to get any info on other instances as well as set the
- * pid number for this instance in the case of multi-instance encoding. */
- hbInstanceNum = [self hbInstances];
-
- /* If we are a single instance it is safe to clean up the previews if there are any
- * left over. This is a bit of a kludge but will prevent a build up of old instance
- * live preview cruft. No danger of removing an active preview directory since they
- * are created later in HBPreviewController if they don't exist at the moment a live
- * preview encode is initiated. */
- if (hbInstanceNum == 1)
- {
- NSString *PreviewDirectory = [NSString stringWithFormat:@"~/Library/Application Support/HandBrake/Previews"];
- PreviewDirectory = [PreviewDirectory stringByExpandingTildeInPath];
- NSError *error;
- NSArray *files = [ [NSFileManager defaultManager] contentsOfDirectoryAtPath: PreviewDirectory error: &error ];
- for( NSString *file in files )
- {
- if( file != @"." && file != @".." )
- {
- [ [NSFileManager defaultManager] removeItemAtPath: [ PreviewDirectory stringByAppendingPathComponent: file ] error: &error ];
- if( error )
- {
- //an error occurred...
- [self writeToActivityLog: "Could not remove existing preview at : %s",[file UTF8String] ];
- }
- }
- }
-
- }
-
-
-
- /* Call UpdateUI every 1/2 sec */
-
- [[NSRunLoop currentRunLoop] addTimer:[NSTimer
- scheduledTimerWithTimeInterval:0.5
- target:self
- selector:@selector(updateUI:)
- userInfo:nil repeats:YES]
- forMode:NSDefaultRunLoopMode];
-
- // Open debug output window now if it was visible when HB was closed
- if ([[NSUserDefaults standardUserDefaults] boolForKey:@"OutputPanelIsOpen"])
- [self showDebugOutputPanel:nil];
- // Open queue window now if it was visible when HB was closed
- if ([[NSUserDefaults standardUserDefaults] boolForKey:@"QueueWindowIsOpen"])
- [self showQueueWindow:nil];
- [self openMainWindow:nil];
-
- /* We have to set the bool to tell hb what to do after a scan
- * Initially we set it to NO until we start processing the queue
- */
- applyQueueToScan = NO;
-
- /* Now we re-check the queue array to see if there are
- * any remaining encodes to be done in it and ask the
- * user if they want to reload the queue */
- if ([QueueFileArray count] > 0)
- {
- /* run getQueueStats to see whats in the queue file */
- [self getQueueStats];
- /* this results in these values
- * fEncodingQueueItem = 0;
- * fPendingCount = 0;
- * fCompletedCount = 0;
- * fCanceledCount = 0;
- * fWorkingCount = 0;
- */
-
- /*On Screen Notification*/
- NSString * alertTitle;
-
- /* We check to see if there is already another instance of hb running.
- * Note: hbInstances == 1 means we are the only instance of HandBrake.app
- */
- if (hbInstanceNum > 1)
- {
- alertTitle = [NSString stringWithFormat:
- NSLocalizedString(@"There is already an instance of HandBrake running.", @"")];
- NSBeginCriticalAlertSheet(
- alertTitle,
- NSLocalizedString(@"Reload Queue", nil),
- nil,
- nil,
- fWindow, self,
- nil, @selector(didDimissReloadQueue:returnCode:contextInfo:), nil,
- NSLocalizedString(@" HandBrake will now load up the existing queue.", nil));
- }
- else
- {
- if (fWorkingCount > 0 || fPendingCount > 0)
- {
- if (fWorkingCount > 0)
- {
- alertTitle = [NSString stringWithFormat:
- NSLocalizedString(@"HandBrake Has Detected %d Previously Encoding Item(s) and %d Pending Item(s) In Your Queue.", @""),
- fWorkingCount,fPendingCount];
- }
- else
- {
- alertTitle = [NSString stringWithFormat:
- NSLocalizedString(@"HandBrake Has Detected %d Pending Item(s) In Your Queue.", @""),
- fPendingCount];
- }
-
- NSBeginCriticalAlertSheet(
- alertTitle,
- NSLocalizedString(@"Reload Queue", nil),
- nil,
- NSLocalizedString(@"Empty Queue", nil),
- fWindow, self,
- nil, @selector(didDimissReloadQueue:returnCode:contextInfo:), nil,
- NSLocalizedString(@" Do you want to reload them ?", nil));
- }
- else
- {
- /* Since we addressed any pending or previously encoding items above, we go ahead and make sure the queue
- * is empty of any finished items or cancelled items */
- [self clearQueueAllItems];
- /* We show whichever open source window specified in LaunchSourceBehavior preference key */
- if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"LaunchSourceBehavior"] isEqualToString: @"Open Source"])
- {
- [self browseSources:nil];
- }
-
- if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"LaunchSourceBehavior"] isEqualToString: @"Open Source (Title Specific)"])
- {
- [self browseSources:(id)fOpenSourceTitleMMenu];
- }
- }
-
- }
- }
- else
- {
- /* We show whichever open source window specified in LaunchSourceBehavior preference key */
- if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"LaunchSourceBehavior"] isEqualToString: @"Open Source"])
- {
- [self browseSources:nil];
- }
-
- if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"LaunchSourceBehavior"] isEqualToString: @"Open Source (Title Specific)"])
- {
- [self browseSources:(id)fOpenSourceTitleMMenu];
- }
- }
- currentQueueEncodeNameString = @"";
- }
- #pragma mark -
- #pragma mark Multiple Instances
- /* hbInstances checks to see if other instances of HB are running and also sets the pid for this instance for multi-instance queue encoding */
-
- /* Note for now since we are in early phases of multi-instance I have put in quite a bit of logging. Can be removed as we see fit. */
- - (int) hbInstances
- {
- /* check to see if another instance of HandBrake.app is running */
- NSArray *runningAppDictionaries = [[NSWorkspace sharedWorkspace] launchedApplications];
- NSDictionary *runningAppsDictionary;
- int hbInstances = 0;
- NSString * thisInstanceAppPath = [[NSBundle mainBundle] bundlePath];
- NSString * runningInstanceAppPath;
- int runningInstancePidNum;
- [self writeToActivityLog: "hbInstances path to this instance: %s", [thisInstanceAppPath UTF8String]];
- for (runningAppsDictionary in runningAppDictionaries)
- {
- if ([[runningAppsDictionary valueForKey:@"NSApplicationName"] isEqualToString:@"HandBrake"])
- {
- /*Report the path to each active instances app path */
- runningInstancePidNum = [[runningAppsDictionary valueForKey:@"NSApplicationProcessIdentifier"] intValue];
- runningInstanceAppPath = [runningAppsDictionary valueForKey:@"NSApplicationPath"];
- [self writeToActivityLog: "hbInstance found instance pidnum:%d at path: %s", runningInstancePidNum, [runningInstanceAppPath UTF8String]];
- /* see if this is us by comparing the app path */
- if ([runningInstanceAppPath isEqualToString: thisInstanceAppPath])
- {
- /* If so this is our pidnum */
- [self writeToActivityLog: "hbInstance MATCH FOUND, our pidnum is:%d", runningInstancePidNum];
- /* Get the PID number for this hb instance, used in multi instance encoding */
- pidNum = runningInstancePidNum;
- /* Report this pid to the activity log */
- [self writeToActivityLog: "Pid for this instance:%d", pidNum];
- /* Tell fQueueController what our pidNum is */
- [fQueueController setPidNum:pidNum];
- }
- hbInstances++;
- }
- }
- return hbInstances;
- }
- - (int) getPidnum
- {
- return pidNum;
- }
- #pragma mark -
- - (void) didDimissReloadQueue: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo
- {
-
- [self writeToActivityLog: "didDimissReloadQueue number of hb instances:%d", hbInstanceNum];
- if (returnCode == NSAlertOtherReturn)
- {
- [self writeToActivityLog: "didDimissReloadQueue NSAlertOtherReturn Chosen"];
- [self clearQueueAllItems];
-
- /* We show whichever open source window specified in LaunchSourceBehavior preference key */
- if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"LaunchSourceBehavior"] isEqualToString: @"Open Source"])
- {
- [self browseSources:nil];
- }
-
- if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"LaunchSourceBehavior"] isEqualToString: @"Open Source (Title Specific)"])
- {
- [self browseSources:(id)fOpenSourceTitleMMenu];
- }
- }
- else
- {
- [self writeToActivityLog: "didDimissReloadQueue First Button Chosen"];
- if (hbInstanceNum == 1)
- {
-
- [self setQueueEncodingItemsAsPending];
- }
- [self showQueueWindow:NULL];
- }
- }
- - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication *) app
- {
-
- hb_state_t s;
- hb_get_state( fQueueEncodeLibhb, &s );
-
- if ( s.state != HB_STATE_IDLE )
- {
- int result = NSRunCriticalAlertPanel(
- NSLocalizedString(@"Are you sure you want to quit HandBrake?", nil),
- NSLocalizedString(@"If you quit HandBrake your current encode will be reloaded into your queue at next launch. Do you want to quit anyway?", nil),
- NSLocalizedString(@"Quit", nil), NSLocalizedString(@"Don't Quit", nil), nil, @"A movie" );
-
- if (result == NSAlertDefaultReturn)
- {
- return NSTerminateNow;
- }
- else
- return NSTerminateCancel;
- }
-
- // Warn if items still in the queue
- else if ( fPendingCount > 0 )
- {
- int result = NSRunCriticalAlertPanel(
- NSLocalizedString(@"Are you sure you want to quit HandBrake?", nil),
- NSLocalizedString(@"There are pending encodes in your queue. Do you want to quit anyway?",nil),
- NSLocalizedString(@"Quit", nil), NSLocalizedString(@"Don't Quit", nil), nil);
-
- if ( result == NSAlertDefaultReturn )
- return NSTerminateNow;
- else
- return NSTerminateCancel;
- }
-
- return NSTerminateNow;
- }
- - (void)applicationWillTerminate:(NSNotification *)aNotification
- {
- [currentQueueEncodeNameString release];
- [browsedSourceDisplayName release];
- [outputPanel release];
- [fQueueController release];
- [fPreviewController release];
- [fPictureController release];
- [fApplicationIcon release];
- hb_close(&fHandle);
- hb_close(&fQueueEncodeLibhb);
- hb_global_close();
- }
- - (void) awakeFromNib
- {
- [fWindow center];
- [fWindow setExcludedFromWindowsMenu:NO];
-
- [fAdvancedOptions setView:fAdvancedView];
-
- /* lets setup our presets drawer for drag and drop here */
- [fPresetsOutlineView registerForDraggedTypes: [NSArray arrayWithObject:DragDropSimplePboardType] ];
- [fPresetsOutlineView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES];
- [fPresetsOutlineView setVerticalMotionCanBeginDrag: YES];
-
- /* Initialize currentScanCount so HB can use it to
- evaluate successive scans */
- currentScanCount = 0;
-
-
- /* Init UserPresets .plist */
- [self loadPresets];
-
- fRipIndicatorShown = NO; // initially out of view in the nib
-
- /* For 64 bit builds, the threaded animation in the progress
- * indicators conflicts with the animation in the advanced tab
- * for reasons not completely clear. jbrjake found a note in the
- * 10.5 dev notes regarding this possiblility. It was also noted
- * that unless specified, setUsesThreadedAnimation defaults to true.
- * So, at least for now we set the indicator animation to NO for
- * both the scan and regular progress indicators for both 32 and 64 bit
- * as it test out fine on both and there is no reason our progress indicators
- * should require their own thread.
- */
- [fScanIndicator setUsesThreadedAnimation:NO];
- [fRipIndicator setUsesThreadedAnimation:NO];
-
-
-
- /* Show/Dont Show Presets drawer upon launch based
- on user preference DefaultPresetsDrawerShow*/
- if( [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultPresetsDrawerShow"] > 0 )
- {
- [fPresetDrawer setDelegate:self];
- NSSize drawerSize = NSSizeFromString( [[NSUserDefaults standardUserDefaults]
- stringForKey:@"Drawer Size"] );
- if( drawerSize.width )
- [fPresetDrawer setContentSize: drawerSize];
- [fPresetDrawer open];
- }
-
- /* Initially set the dvd angle widgets to hidden (dvdnav only) */
- [fSrcAngleLabel setHidden:YES];
- [fSrcAnglePopUp setHidden:YES];
-
- /* Setup the start / stop popup */
- [fEncodeStartStopPopUp removeAllItems];
- [fEncodeStartStopPopUp addItemWithTitle: @"Chapters"];
- [fEncodeStartStopPopUp addItemWithTitle: @"Seconds"];
- [fEncodeStartStopPopUp addItemWithTitle: @"Frames"];
- /* Align the start / stop widgets with the chapter popups */
- [fSrcTimeStartEncodingField setFrameOrigin:[fSrcChapterStartPopUp frame].origin];
- [fSrcTimeEndEncodingField setFrameOrigin:[fSrcChapterEndPopUp frame].origin];
-
- [fSrcFrameStartEncodingField setFrameOrigin:[fSrcChapterStartPopUp frame].origin];
- [fSrcFrameEndEncodingField setFrameOrigin:[fSrcChapterEndPopUp frame].origin];
-
- /* Destination box*/
- NSMenuItem *menuItem;
- [fDstFormatPopUp removeAllItems];
- // MP4 file
- menuItem = [[fDstFormatPopUp menu] addItemWithTitle:@"MP4 file" action: NULL keyEquivalent: @""];
- [menuItem setTag: HB_MUX_MP4];
- // MKV file
- menuItem = [[fDstFormatPopUp menu] addItemWithTitle:@"MKV file" action: NULL keyEquivalent: @""];
- [menuItem setTag: HB_MUX_MKV];
-
- [fDstFormatPopUp selectItemAtIndex: 0];
-
- [self formatPopUpChanged:nil];
-
- /* We enable the create chapters checkbox here since we are .mp4 */
- [fCreateChapterMarkers setEnabled: YES];
- if ([fDstFormatPopUp indexOfSelectedItem] == 0 && [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultChapterMarkers"] > 0)
- {
- [fCreateChapterMarkers setState: NSOnState];
- }
-
-
-
-
- [fDstFile2Field setStringValue: [NSString stringWithFormat:
- @"%@/Desktop/Movie.mp4", NSHomeDirectory()]];
-
- /* Video encoder */
- [fVidEncoderPopUp removeAllItems];
- [fVidEncoderPopUp addItemWithTitle: @"FFmpeg"];
-
-
- /* Video quality */
- [fVidTargetSizeField setIntValue: 700];
- [fVidBitrateField setIntValue: 1000];
-
- [fVidQualityMatrix selectCell: fVidBitrateCell];
- [self videoMatrixChanged:nil];
-
- /* Video framerate */
- [fVidRatePopUp removeAllItems];
- [fVidRatePopUp addItemWithTitle: NSLocalizedString( @"Same as source", @"" )];
- for( int i = 0; i < hb_video_rates_count; i++ )
- {
- if ([[NSString stringWithUTF8String: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%.3f",23.976]])
- {
- [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@",
- [NSString stringWithUTF8String: hb_video_rates[i].string], @" (NTSC Film)"]];
- }
- else if ([[NSString stringWithUTF8String: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%d",25]])
- {
- [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@",
- [NSString stringWithUTF8String: hb_video_rates[i].string], @" (PAL Film/Video)"]];
- }
- else if ([[NSString stringWithUTF8String: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%.2f",29.97]])
- {
- [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@",
- [NSString stringWithUTF8String: hb_video_rates[i].string], @" (NTSC Video)"]];
- }
- else
- {
- [fVidRatePopUp addItemWithTitle:
- [NSString stringWithUTF8String: hb_video_rates[i].string]];
- }
- }
- [fVidRatePopUp selectItemAtIndex: 0];
-
- /* Set Auto Crop to On at launch */
- [fPictureController setAutoCrop:YES];
-
- /* Bottom */
- [fStatusField setStringValue: @""];
-
- [self enableUI: NO];
- [self setupToolbar];
-
- /* We disable the Turbo 1st pass checkbox since we are not x264 */
- [fVidTurboPassCheck setEnabled: NO];
- [fVidTurboPassCheck setState: NSOffState];
-
-
- /* lets get our default prefs here */
- [self getDefaultPresets:nil];
- /* lets initialize the current successful scancount here to 0 */
- currentSuccessfulScanCount = 0;
- }
- - (void) enableUI: (bool) b
- {
- NSControl * controls[] =
- { fSrcTitleField, fSrcTitlePopUp,
- fSrcChapterField, fSrcChapterStartPopUp, fSrcChapterToField,
- fSrcChapterEndPopUp, fSrcDuration1Field, fSrcDuration2Field,
- fDstFormatField, fDstFormatPopUp, fDstFile1Field, fDstFile2Field,
- fDstBrowseButton, fVidRateField, fVidRatePopUp,fVidEncoderField, fVidEncoderPopUp, fVidQualityField,
- fPictureSizeField,fPictureCroppingField, fVideoFiltersField,fVidQualityMatrix, fSubField, fSubPopUp,
- fQueueStatus,fPresetsAdd,fPresetsDelete,fSrcAngleLabel,fSrcAnglePopUp,
- fCreateChapterMarkers,fVidTurboPassCheck,fDstMp4LargeFileCheck,fSubForcedCheck,fPresetsOutlineView,
- fDstMp4HttpOptFileCheck,fDstMp4iPodFileCheck,fVidQualityRFField,fVidQualityRFLabel,
- fEncodeStartStopPopUp,fSrcTimeStartEncodingField,fSrcTimeEndEncodingField,fSrcFrameStartEncodingField,
- fSrcFrameEndEncodingField, fLoadChaptersButton, fSaveChaptersButton, fFrameratePfrCheck};
-
- for( unsigned i = 0;
- i < sizeof( controls ) / sizeof( NSControl * ); i++ )
- {
- 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];
-
- }
-
- if (b)
- {
-
- /* we also call calculatePictureSizing here to sense check if we already have vfr selected */
- [self calculatePictureSizing:nil];
- /* Also enable the preview window hud controls */
- [fPictureController enablePreviewHudControls];
- }
- else
- {
-
- [fPresetsOutlineView setEnabled: NO];
- [fPictureController disablePreviewHudControls];
- }
-
- [self videoMatrixChanged:nil];
- [fAdvancedOptions enableUI:b];
- }
- /***********************************************************************
- * 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
- {
- NSData * tiff;
- NSBitmapImageRep * bmp;
- uint32_t * pen;
- uint32_t black = htonl( 0x000000FF );
- uint32_t red = htonl( 0xFF0000FF );
- uint32_t white = htonl( 0xFFFFFFFF );
- int row_start, row_end;
- int i, j;
- if( progress < 0.0 || progress > 1.0 )
- {
- [NSApp setApplicationIconImage: fApplicationIcon];
- return;
- }
- /* Get it in a raw bitmap form */
- tiff = [fApplicationIcon 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] = black;
- }
- }
- for( i = row_start + 2; i < row_end - 2; i++ )
- {
- pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
- pen[0] = black;
- pen[1] = black;
- for( j = 2; j < (int) [bmp size].width - 2; j++ )
- {
- if( j < 2 + (int) ( ( [bmp size].width - 4.0 ) * progress ) )
- {
- pen[j] = red;
- }
- else
- {
- pen[j] = white;
- }
- }
- pen[j] = black;
- pen[j+1] = black;
- }
- 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] = black;
- }
- }
- /* Now update the dock icon */
- tiff = [bmp TIFFRepresentationUsingCompression:
- NSTIFFCompressionNone factor: 1.0];
- NSImage* icon = [[NSImage alloc] initWithData: tiff];
- [NSApp setApplicationIconImage: icon];
- [icon release];
- }
- - (void) updateUI: (NSTimer *) timer
- {
-
- /* Update UI for fHandle (user scanning instance of libhb ) */
-
- hb_list_t * list;
- list = hb_get_titles( fHandle );
- /* check to see if there has been a new scan done
- this bypasses the constraints of HB_STATE_WORKING
- not allowing setting a newly scanned source */
- int checkScanCount = hb_get_scancount( fHandle );
- if( checkScanCount > currentScanCount )
- {
- currentScanCount = checkScanCount;
- [fScanIndicator setIndeterminate: NO];
- [fScanIndicator setDoubleValue: 0.0];
- [fScanIndicator setHidden: YES];
- [self showNewScan:nil];
- }
-
- hb_state_t s;
- hb_get_state( fHandle, &s );
-
- switch( s.state )
- {
- case HB_STATE_IDLE:
- break;
- #define p s.param.scanning
- case HB_STATE_SCANNING:
- {
- [fSrcDVD2Field setStringValue: [NSString stringWithFormat:
- NSLocalizedString( @"Scanning title %d of %d...", @"" ),
- p.title_cur, p.title_count]];
- [fScanIndicator setHidden: NO];
- [fScanIndicator setDoubleValue: 100.0 * ((double)( p.title_cur - 1 ) / p.title_count)];
- break;
- }
- #undef p
-
- #define p s.param.scandone
- case HB_STATE_SCANDONE:
- {
- [fScanIndicator setIndeterminate: NO];
- [fScanIndicator setDoubleValue: 0.0];
- [fScanIndicator setHidden: YES];
- [self writeToActivityLog:"ScanDone state received from fHandle"];
- [self showNewScan:nil];
- [[fWindow toolbar] validateVisibleItems];
-
- break;
- }
- #undef p
-
- #define p s.param.working
- case HB_STATE_WORKING:
- {
-
- break;
- }
- #undef p
-
- #define p s.param.muxing
- case HB_STATE_MUXING:
- {
-
- break;
- }
- #undef p
-
- case HB_STATE_PAUSED:
- break;
-
- case HB_STATE_WORKDONE:
- {
- break;
- }
- }
-
-
- /* Update UI for fQueueEncodeLibhb */
- // hb_list_t * list;
- // list = hb_get_titles( fQueueEncodeLibhb ); //fQueueEncodeLibhb
- /* check to see if there has been a new scan done
- this bypasses the constraints of HB_STATE_WORKING
- not allowing setting a newly scanned source */
-
- checkScanCount = hb_get_scancount( fQueueEncodeLibhb );
- if( checkScanCount > currentScanCount )
- {
- currentScanCount = checkScanCount;
- }
-
- //hb_state_t s;
- hb_get_state( fQueueEncodeLibhb, &s );
-
- switch( s.state )
- {
- case HB_STATE_IDLE:
- break;
- #define p s.param.scanning
- case HB_STATE_SCANNING:
- {
- [fStatusField setStringValue: [NSString stringWithFormat:
- NSLocalizedString( @"Queue Scanning title %d of %d...", @"" ),
- p.title_cur, p.title_count]];
-
- /* Set the status string in fQueueController as well */
- [fQueueController setQueueStatusString: [NSString stringWithFormat:
- NSLocalizedString( @"Queue Scanning title %d of %d...", @"" ),
- p.title_cur, p.title_count]];
- break;
- }
- #undef p
-
- #define p s.param.scandone
- case HB_STATE_SCANDONE:
- {
- [self writeToActivityLog:"ScanDone state received from fQueueEncodeLibhb"];
- [self processNewQueueEncode];
- [[fWindow toolbar] validateVisibleItems];
-
- break;
- }
- #undef p
-
-
- #define p s.param.working
-
- case HB_STATE_SEARCHING:
- {
- NSMutableString * string;
- NSString * pass_desc;
-
- /* Update text field */
- pass_desc = @"";
- //string = [NSMutableString stringWithFormat: NSLocalizedString( @"Searching for start point: pass %d %@ of %d, %.2f %%", @"" ), p.job_cur, pass_desc, p.job_count, 100.0 * p.progress];
- /* For now, do not announce "pass x of x for the search phase ... */
- string = [NSMutableString stringWithFormat: NSLocalizedString( @"Searching for start point ... : %.2f %%", @"" ), 100.0 * p.progress];
-
- if( p.seconds > -1 )
- {
- [string appendFormat:
- NSLocalizedString( @" (ETA %02dh%02dm%02ds)", @"" ), p.hours, p.minutes, p.seconds];
- }
-
- [fStatusField setStringValue: string];
- /* Set the status string in fQueueController as well */
- [fQueueController setQueueStatusString: string];
- /* Update slider */
- CGFloat progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count;
- [fRipIndicator setIndeterminate: NO];
- [fRipIndicator setDoubleValue:100.0 * progress_total];
-
- // If progress bar hasn't been revealed at the bottom of the window, do
- // that now. This code used to be in doRip. I moved it to here to handle
- // the case where hb_start is called by HBQueueController and not from
- // HBController.
- if( !fRipIndicatorShown )
- {
- NSRect frame = [fWindow frame];
- if( frame.size.width <= 591 )
- frame.size.width = 591;
- frame.size.height += 36;
- frame.origin.y -= 36;
- [fWindow setFrame:frame display:YES animate:YES];
- fRipIndicatorShown = YES;
-
- }
-
- /* Update dock icon */
- /* Note not done yet */
- break;
- }
-
-
- case HB_STATE_WORKING:
- {
- NSMutableString * string;
- NSString * pass_desc;
- /* Update text field */
- if (p.job_cur == 1 && p.job_count > 1)
- {
- if ([[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SubtitleList"] && [[[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex]objectForKey:@"SubtitleList"] objectAtIndex:0] objectForKey:@"subtitleSourceTrackNum"] intValue] == 1)
- {
- pass_desc = @"(subtitle scan)";
- }
- else
- {
- pass_desc = @"";
- }
- }
- else
- {
- pass_desc = @"";
- }
-
- string = [NSMutableString stringWithFormat: NSLocalizedString( @"Encoding: %@ \nPass %d %@ of %d, %.2f %%", @"" ), currentQueueEncodeNameString, p.job_cur, pass_desc, p.job_count, 100.0 * p.progress];
-
- if( p.seconds > -1 )
- {
- [string appendFormat:
- NSLocalizedString( @" (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)", @"" ),
- p.rate_cur, p.rate_avg, p.hours, p.minutes, p.seconds];
- }
- [fStatusField setStringValue: string];
- [fQueueController setQueueStatusString:string];
-
- /* Update slider */
- CGFloat progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count;
- [fRipIndicator setIndeterminate: NO];
- [fRipIndicator setDoubleValue:100.0 * progress_total];
-
- // If progress bar hasn't been revealed at the bottom of the window, do
- // that now. This code used to be in doRip. I moved it to here to handle
- // the case where hb_start is called by HBQueueController and not from
- // HBController.
- if( !fRipIndicatorShown )
- {
- NSRect frame = [fWindow frame];
- if( frame.size.width <= 591 )
- frame.size.width = 591;
- frame.size.height += 36;
- frame.origin.y -= 36;
- [fWindow setFrame:frame display:YES animate:YES];
- fRipIndicatorShown = YES;
-
- }
-
- /* Update dock icon */
- if( dockIconProgress < 100.0 * progress_total )
- {
- [self UpdateDockIcon: progress_total];
- dockIconProgress += 5;
- }
-
- break;
- }
- #undef p
-
- #define p s.param.muxing
- case HB_STATE_MUXING:
- {
- /* Update text field */
- [fStatusField setStringValue: NSLocalizedString( @"Muxing...", @"" )];
- /* Set the status string in fQueueController as well */
- [fQueueController setQueueStatusString: NSLocalizedString( @"Muxing...", @"" )];
- /* Update slider */
- [fRipIndicator setIndeterminate: YES];
- [fRipIndicator startAnimation: nil];
-
- /* Update dock icon */
- [self UpdateDockIcon: 1.0];
-
- break;
- }
- #undef p
-
- case HB_STATE_PAUSED:
- [fStatusField setStringValue: NSLocalizedString( @"Paused", @"" )];
- [fQueueController setQueueStatusString: NSLocalizedString( @"Paused", @"" )];
-
- break;
-
- case HB_STATE_WORKDONE:
- {
- // HB_STATE_WORKDONE happpens as a result of libhb finishing all its jobs
- // or someone calling hb_stop. In the latter case, hb_stop does not clear
- // out the remaining passes/jobs in the queue. We'll do that here.
-
- // Delete all remaining jobs of this encode.
- [fStatusField setStringValue: NSLocalizedString( @"Encode Finished.", @"" )];
- /* Set the status string in fQueueController as well */
- [fQueueController setQueueStatusString: NSLocalizedString( @"Encode Finished.", @"" )];
- [fRipIndicator setIndeterminate: NO];
- [fRipIndicator stopAnimation: nil];
- [fRipIndicator setDoubleValue: 0.0];
- [[fWindow toolbar] validateVisibleItems];
-
- /* Restore dock icon */
- [self UpdateDockIcon: -1.0];
- dockIconProgress = 0;
-
- if( fRipIndicatorShown )
- {
- NSRect frame = [fWindow frame];
- if( frame.size.width <= 591 )
- frame.size.width = 591;
- frame.size.height += -36;
- frame.origin.y -= -36;
- [fWindow setFrame:frame display:YES animate:YES];
- fRipIndicatorShown = NO;
- }
- /* Since we are done with this encode, tell output to stop writing to the
- * individual encode log
- */
- [outputPanel endEncodeLog];
- /* Check to see if the encode state has not been cancelled
- to determine if we should check for encode done notifications */
- if( fEncodeState != 2 )
- {
- NSString *pathOfFinishedEncode;
- /* Get the output file name for the finished encode */
- pathOfFinishedEncode = [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"DestinationPath"];
-
- /* Both the Growl Alert and Sending to MetaX can be done as encodes roll off the queue */
- if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Growl Notification"] ||
- [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window And Growl"])
- {
- /* If Play System Alert has been selected in Preferences */
- if( [[NSUserDefaults standardUserDefaults] boolForKey:@"AlertWhenDoneSound"] == YES )
- {
- NSBeep();
- }
- [self showGrowlDoneNotification:pathOfFinishedEncode];
- }
-
- /* Send to MetaX */
- [self sendToMetaX:pathOfFinishedEncode];
-
- /* since we have successfully completed an encode, we increment the queue counter */
- [self incrementQueueItemDone:currentQueueEncodeIndex];
- }
-
- break;
- }
- }
-
- /* Since we can use multiple instance off of the same queue file it is imperative that we keep the QueueFileArray updated off of the QueueFile.plist
- * so we go ahead and do it in this existing timer as opposed to using a new one */
-
- NSMutableArray * tempQueueArray = [[NSMutableArray alloc] initWithContentsOfFile:QueueFile];
- [QueueFileArray setArray:tempQueueArray];
- [tempQueueArray release];
- /* Send Fresh QueueFileArray to fQueueController to update queue window */
- [fQueueController setQueueArray: QueueFileArray];
- [self getQueueStats];
-
- }
- /* We use this to write messages to stderr from the macgui which show up in the activity window and log*/
- - (void) writeToActivityLog:(const char *) format, ...
- {
- va_list args;
- va_start(args, format);
- if (format != nil)
- {
- char str[1024];
- vsnprintf( str, 1024, format, args );
- time_t _now = time( NULL );
- struct tm * now = localtime( &_now );
- fprintf(stderr, "[%02d:%02d:%02d] macgui: %s\n", now->tm_hour, now->tm_min, now->tm_sec, str );
- }
- va_end(args);
- }
- #pragma mark -
- #pragma mark Toolbar
- // ============================================================
- // NSToolbar Related Methods
- // ============================================================
- - (void) setupToolbar {
- NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier: @"HandBrake Toolbar"] autorelease];
- [toolbar setAllowsUserCustomization: YES];
- [toolbar setAutosavesConfiguration: YES];
- [toolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
- [toolbar setDelegate: self];
- [fWindow setToolbar: toolbar];
- }
- - (NSToolbarItem *) toolbar: (NSToolbar *)toolbar itemForItemIdentifier:
- (NSString *) itemIdent willBeInsertedIntoToolbar:(BOOL) willBeInserted {
- NSToolbarItem * item = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdent] autorelease];
- if ([itemIdent isEqualToString: ToggleDrawerIdentifier])
- {
- [item setLabel: @"Toggle Presets"];
- [item setPaletteLabel: @"Toggler Presets"];
- [item setToolTip: @"Open/Close Preset Drawer"];
- [item setImage: [NSImage imageNamed: @"Drawer"]];
- [item setTarget: self];
- [item setAction: @selector(toggleDrawer:)];
- [item setAutovalidates: NO];
- }
- else if ([itemIdent isEqualToString: StartEncodingIdentifier])
- {
- [item setLabel: @"Start"];
- [item setPaletteLabel: @"Start Encoding"];
- [item setToolTip: @"Start Encoding"];
- [item setImage: [NSImage imageNamed: @"Play"]];
- [item setTarget: self];
- [item setAction: @selector(Rip:)];
- }
- else if ([itemIdent isEqualToString: ShowQueueIdentifier])
- {
- [item setLabel: @"Show Queue"];
- [item setPaletteLabel: @"Show Queue"];
- [item setToolTip: @"Show Queue"];
- [item setImage: [NSImage imageNamed: @"Queue"]];
- [item setTarget: self];
- [item setAction: @selector(showQueueWindow:)];
- [item setAutovalidates: NO];
- }
- else if ([itemIdent isEqualToString: AddToQueueIdentifier])
- {
- [item setLabel: @"Add to Queue"];
- [item setPaletteLabel: @"Add to Queue"];
- [item setToolTip: @"Add to Queue"];
- [item setImage: [NSImage imageNamed: @"AddToQueue"]];
- [item setTarget: self];
- [item setAction: @selector(addToQueue:)];
- }
- else if ([itemIdent isEqualToString: PauseEncodingIdentifier])
- {
- [item setLabel: @"Pause"];
- [item setPaletteLabel: @"Pause Encoding"];
- [item setToolTip: @"Pause Encoding"];
- [item setImage: [NSImage imageNamed: @"Pause"]];
- [item setTarget: self];
- [item setAction: @selector(Pause:)];
- }
- else if ([itemIdent isEqualToString: ShowPictureIdentifier])
- {
- [item setLabel: @"Picture Settings"];
- [item setPaletteLabel: @"Show Picture Settings"];
- [item setToolTip: @"Show Picture Settings"];
- [item setImage: [NSImage imageNamed: @"pref-picture"]];
- [item setTarget: self];
- [item setAction: @selector(showPicturePanel:)];
- }
- else if ([itemIdent isEqualToString: ShowPreviewIdentifier])
- {
- [item setLabel: @"Preview Window"];
- [item setPaletteLabel: @"Show Preview"];
- [item setToolTip: @"Show Preview"];
- //[item setImage: [NSImage imageNamed: @"pref-picture"]];
- [item setImage: [NSImage imageNamed: @"Brushed_Window"]];
- [item setTarget: self];
- [item setAction: @selector(showPreviewWindow:)];
- }
- else if ([itemIdent isEqualToString: ShowActivityIdentifier])
- {
- [item setLabel: @"Activity Window"];
- [item setPaletteLabel: @"Show Activity Window"];
- [item setToolTip: @"Show Activity Window"];
- [item setImage: [NSImage imageNamed: @"ActivityWindow"]];
- [item setTarget: self];
- [item setAction: @selector(showDebugOutputPanel:)];
- [item setAutovalidates: NO];
- }
- else if ([itemIdent isEqualToString: ChooseSourceIdentifier])
- {
- [item setLabel: @"Source"];
- [item setPaletteLabel: @"Source"];
- [item setToolTip: @"Choose Video Source"];
- [item setImage: [NSImage imageNamed: @"Source"]];
- [item setTarget: self];
- [item setAction: @selector(browseSources:)];
- }
- else
- {
- return nil;
- }
- return item;
- }
- - (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar
- {
- return [NSArray arrayWithObjects: ChooseSourceIdentifier, NSToolbarSeparatorItemIdentifier, StartEncodingIdentifier,
- PauseEncodingIdentifier, AddToQueueIdentifier, ShowQueueIdentifier, NSToolbarFlexibleSpaceItemIdentifier,
- NSToolbarSpaceItemIdentifier, ShowPictureIdentifier, ShowPreviewIdentifier, ShowActivityIdentifier, ToggleDrawerIdentifier, nil];
- }
- - (NSArray *) toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar
- {
- return [NSArray arrayWithObjects: StartEncodingIdentifier, PauseEncodingIdentifier, AddToQueueIdentifier,
- ChooseSourceIdentifier, ShowQueueIdentifier, ShowPictureIdentifier, ShowPreviewIdentifier, ShowActivityIdentifier, ToggleDrawerIdentifier,
- NSToolbarCustomizeToolbarItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier,
- NSToolbarSpaceItemIdentifier, NSToolbarSeparatorItemIdentifier, nil];
- }
- - (BOOL) validateToolbarItem: (NSToolbarItem *) toolbarItem
- {
- NSString * ident = [toolbarItem itemIdentifier];
-
- if (fHandle)
- {
- hb_state_t s;
-
- hb_get_state( fHandle, &s );
- if (s.state == HB_STATE_SCANNING)
- {
-
- if ([ident isEqualToString: ChooseSourceIdentifier])
- {
- [toolbarItem setImage: [NSImage imageNamed: @"Stop"]];
- [toolbarItem setLabel: @"Cancel Scan"];
- [toolbarItem setPaletteLabel: @"Cancel Scanning"];
- [toolbarItem setToolTip: @"Cancel Scanning Source"];
- return YES;
- }
-
- if ([ident isEqualToString: StartEncodingIdentifier] || [ident isEqualToString: AddToQueueIdentifier])
- return NO;
- }
- else
- {
- if ([ident isEqualToString: ChooseSourceIdentifier])
- {
- [toolbarItem setImage: [NSImage imageNamed: @"Source"]];
- [toolbarItem setLabel: @"Source"];
- [toolbarItem setPaletteLabel: @"Source"];
- [toolbarItem setToolTip: @"Choose Video Source"];
- return YES;
- }
- }
- hb_get_state2( fQueueEncodeLibhb, &s );
-
- if (s.state == HB_STATE_WORKING || s.state == HB_STATE_SEARCHING || s.state == HB_STATE_MUXING)
- {
- if ([ident isEqualToString: StartEncodingIdentifier])
- {
- [toolbarItem setImage: [NSImage imageNamed: @"Stop"]];
- [toolbarItem setLabel: @"Stop"];
- [toolbarItem setPaletteLabel: @"Stop"];
- [toolbarItem setToolTip: @"Stop Encoding"];
- return YES;
- }
- if ([ident isEqualToString: PauseEncodingIdentifie…
Large files files are truncated, but you can click here to view the full file