File: programming/cocoa/UKTurboExport.zip/UKTurboExport/MyDocument.m


//
//  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

This code uses the PclZip Zip File reading code, which is subject to the GNU LGPL. It also uses the GeSHi syntax highlighter, subject to the GPL. Ask if you want this for your own web site, it's free.