// // MyDocument.h // UKTurboExport // // Created by Uli Kusterer on 09.02.08. // Copyright 2008 M. Uli Kusterer. All rights reserved. // // ----------------------------------------------------------------------------- // Headers: // ----------------------------------------------------------------------------- #import "MyDocument.h" #import "UKTurbo264.h" // Turbo "API". @implementation MyDocument // ----------------------------------------------------------------------------- // init: // ----------------------------------------------------------------------------- -(id) init { self = [super init]; if( self ) { // Make sure we get notified when a Turbo is plugged in/removed: // The call to [UKTurbo264 sharedTurbo264] causes the object to be // instantiated that sends these notifications. [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(turboDeviceCountChanged:) name: UKTurbo264DeviceCountChangedNotification object: [UKTurbo264 sharedTurbo264]]; } return self; } // ----------------------------------------------------------------------------- // dealloc: // ----------------------------------------------------------------------------- -(void) dealloc { [[NSNotificationCenter defaultCenter] removeObserver: self name: UKTurbo264DeviceCountChangedNotification object: [UKTurbo264 sharedTurbo264]]; [super dealloc]; } // ----------------------------------------------------------------------------- // windowNibName: // ----------------------------------------------------------------------------- -(NSString *) windowNibName { return @"MyDocument"; } // ----------------------------------------------------------------------------- // windowControllerDidLoadNib: // Set up our UI. This assigns the movie to our movie view (I don't // recommend doing it like this, by referencing [self fileName] in shipping // code), fills the presets popup with the avaiable presets and disables // the "export" button if there is no Turbo device plugged in right now. // ----------------------------------------------------------------------------- -(void) windowControllerDidLoadNib: (NSWindowController *) aController { [super windowControllerDidLoadNib: aController]; if( [self fileName] ) { QTMovie * movie = [[QTMovie alloc] initWithFile: [self fileName] error: nil]; if( movie ) { [movieView setMovie:movie]; [movie release]; } } // Fill presets popup with display names of all presets: [presetPopup removeAllItems]; NSArray* presets = [[UKTurbo264 sharedTurbo264] exportPresets]; NSDictionary* currentPreset = nil; NSEnumerator* enny = [presets objectEnumerator]; while(( currentPreset = [enny nextObject] )) [presetPopup addItemWithTitle: [currentPreset objectForKey: UKTurbo264PresetDisplayNameKey]]; // Enable/disable the "Export" button depending on whether we have a Turbo device right now: [exportButton setEnabled: [[UKTurbo264 sharedTurbo264] isAvailable]]; } // ----------------------------------------------------------------------------- // dataRepresentationOfType: // Stubbed out, this is only sample code, after all. // ----------------------------------------------------------------------------- - (NSData *)dataRepresentationOfType:(NSString *)aType { return nil; } // ----------------------------------------------------------------------------- // loadDataRepresentation:ofType: // Stubbed out, this is only sample code, after all. // ----------------------------------------------------------------------------- - (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)aType { return YES; } // ----------------------------------------------------------------------------- // turboDeviceCountChanged: // User plugged in or unplugged a Turbo device from the USB bus. Make sure // The export button's enable state is set up appropriately. // // Note that we currently support only one Turbo device, but these // notifications come in every time a device is registered/unregistered in // IOKit. // // Also, when we upload the Firmware to a device (we don't do this until // the first encode after a device was plugged in), we temporarily // unregister a device, so you may want to coalesce these notifications // if you do any obvious UI feedback when the device is unplugged. // ----------------------------------------------------------------------------- -(void) turboDeviceCountChanged: (NSNotification*)notif { [exportButton setEnabled: [[UKTurbo264 sharedTurbo264] isAvailable]]; } // ----------------------------------------------------------------------------- // exportMovie: // Action for the "Export" button that actually kicks off our export // in a secondary thread. // ----------------------------------------------------------------------------- -(IBAction) exportMovie: (id)sender { QTMovie *movie = [[movieView movie] retain]; // Will be released by finishExport: - this way we ensure no thread's autorelease pool kills the movie before another thread has managed to retain it. [movie setDelegate: self]; // Needed so we get progress messages. BOOL success = [movie detachFromCurrentThread]; if (!success) { NSLog(@"unable to detach movie from current thread"); } else { // Get settings from user: // We could use -exportSettingsFromPreset: instead and build the attributes // for QTMovie's writeToFile: ourselves, but for most people this method is // completely sufficient. NSDictionary* exportPreset = [[[UKTurbo264 sharedTurbo264] exportPresets] objectAtIndex: [presetPopup indexOfSelectedItem]]; NSDictionary* exportSettings = [[UKTurbo264 sharedTurbo264] writeToFileAttributesForPreset: exportPreset]; // Make sure user immediately sees we're working: [progress setIndeterminate: YES]; [progress setHidden: NO]; [progress startAnimation: nil]; // Start the export: [movieView setMovie:nil]; [NSThread detachNewThreadSelector: @selector(doExportOnThread:) toTarget:self withObject: [NSDictionary dictionaryWithObjectsAndKeys: movie, @"movie", exportSettings, @"exportSettings", nil]]; } } // ----------------------------------------------------------------------------- // doExportOnThread: // This is the actual exporting code that gets run in its own thread. // ----------------------------------------------------------------------------- -(void) doExportOnThread: (NSDictionary*)userInfo { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; QTMovie* movie = [userInfo objectForKey: @"movie"]; NSDictionary* exportSettings = [userInfo objectForKey: @"exportSettings"]; [QTMovie enterQTKitOnThreadDisablingThreadSafetyProtection]; [movie attachToCurrentThread]; // Export the movie: NSError* outError = nil; if( ![movie writeToFile: @"/tmp/exportedMovie.mov" withAttributes: exportSettings error: &outError] || outError ) NSLog(@"Error during export: %@",outError); [movie detachFromCurrentThread]; [QTMovie exitQTKitOnThread]; [self performSelectorOnMainThread: @selector(finishExport:) withObject: movie waitUntilDone: NO]; [pool release]; } // ----------------------------------------------------------------------------- // finishExport: // Called by the export thread once it has finished, on the main thread.. // ----------------------------------------------------------------------------- -(void) finishExport: (QTMovie *)movie { [movie attachToCurrentThread]; [movieView setMovie: movie]; [movie release]; [progress stopAnimation: nil]; [progress setHidden: YES]; } // ----------------------------------------------------------------------------- // Update the progress bar: -(void) takeProgressFrom: (NSNumber*)num { [progress setIndeterminate: NO]; [progress setDoubleValue: [num doubleValue]]; } -(BOOL) movie:(QTMovie *)movie shouldContinueOperation:(NSString *)op withPhase:(QTMovieOperationPhase)phase atPercent:(NSNumber *)percent withAttributes:(NSDictionary *)attributes { [self performSelectorOnMainThread: @selector(takeProgressFrom:) withObject: percent waitUntilDone: NO]; return YES; } @end |