Oooh ooh ooh!
So I wanted to write something I could run from a command line that would capture the image at a given timecode of a given QuickTime movie, and save it to a given location on the file system. I didn’t care particularly how — I held out hope for a QuickTime python library, but that was silliness.
I Googled and Googled and Googled and finally got the best guidance for what I wanted to do from Cocoa is My Girlfriend. Having no crapping idea how to write in Objective C, nor having any experience with XCode, I am pretty pleased with XCode that it was possible for me to make use of CiMG’s guidance in the afternoon.
I am providing all the objects for clarity’s sake, but all credit is due Cocoa is My Girlfriend for providing most of this code.
1) Set Target -> Info to be like this:
2) Set up command line arguments like this:
3) I didn’t need a GUI or threading, so my main.m looks like this. (FrameRipper is my frame-ripping object):
#import
#import
int main(int argc, char *argv[])
{
NSAutoreleasePool* myPool = [[NSAutoreleasePool alloc] init];
//Parameters are set up in Executables –> Info
NSUserDefaults* myArgs = [NSUserDefaults standardUserDefaults];
NSLog(@”moviePath = %@”, [myArgs stringForKey:@”moviePath”]);
NSLog(@”timeCode = %@”, [myArgs stringForKey:@”timeCode”]);
NSLog(@”imageDestinationPath = %@”, [myArgs stringForKey:@”imageDestinationPath”]);
QTMovie* currentMovie = [QTMovie movieWithFile: [myArgs stringForKey:@”moviePath”]
error: NULL];
// Create our NSOperation derived object
FrameRipper* op = [[FrameRipper alloc] init];
[op setMovie: currentMovie];
[op setTimeCode: [myArgs stringForKey:@”timeCode”]];
[op setImageDestinationPath: [myArgs stringForKey:@”imageDestinationPath”]];
// Run the object’s main method
[op main];
[myArgs release];
[op release];
[myPool release];
return 1;
}
You can see this code closely follows the Cocoa is My Girlfriend example. Note I changed an attribute name (outputPath –> imageDestinationPath).
4) FrameRipper.h looks like this:
#import
#import
#import
#import
@interface FrameRipper : NSOperation {
QTMovie* movie;
NSString* timeCode;
NSString* imageDestinationPath;
NSDictionary* imageAttributes;
NSLock* lock;
}
@property (assign) QTMovie* movie;
@property (assign) NSString* timeCode;
@property (assign) NSString* imageDestinationPath;
– (void)main;
– (void)saveImage:(NSImage*)image;
@end
5) FrameRipper.m looks like this:
#import “FrameRipper.h”
@implementation FrameRipper
@synthesize movie;
@synthesize timeCode;
@synthesize imageDestinationPath;
//********************************************************
// main()
//********************************************************
– (void) main
{
if (movie)
{
NSImage* image;
[lock lock];
QTTime time = QTTimeFromString(timeCode);
image = [movie frameImageAtTime:time
withAttributes:imageAttributes
error:NULL];
[lock unlock];
[self saveImage:image];
}
}
//********************************************************
// init()
//********************************************************
– (id)init
{
lock = [[NSLock alloc] init];
// Specify that we want to save out a high-quality image.
imageAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
QTMovieFrameImageTypeNSImage, QTMovieFrameImageType,
[NSNumber numberWithBool:YES], QTMovieFrameImageHighQuality, NULL];
[imageAttributes retain];
[super init];
return self;
}
//********************************************************
// saveImage()
//********************************************************
-(void)saveImage:(NSImage*)image
{
NSArray* representations;
NSData* bitmapData;
representations = [image representations];
// Specify that we want to save the file as a JPG
bitmapData = [NSBitmapImageRep representationOfImageRepsInArray:representations
usingType:NSJPEGFileType
properties:[NSDictionary dictionaryWithObject:[NSDecimalNumber numberWithFloat:1.0]
forKey:NSImageCompressionFactor]];
[bitmapData writeToFile:imageDestinationPath atomically:YES];
}
@end
6) Now build the app in XCode. The resulting app can be run from the command line like this:
build/Release/frameRipper.app/Contents/MacOS/frameRipper -moviePath /path/to/movie.mov -timeCode 0:00:00:04.403/600 -imageDestinationPath /path/to/imageYouWantToMake.jpg
Note the timeCode format. That’s something I’m working on right now — a bum timecode format (like 00:00:00:04) just gets you a capture of the first frame of the movie (since the bum timecode doesn’t exist as far as QuickTime’s concerned.)
Good luck!
Share this:
Related