Tuesday, September 22, 2009

More Housecleaning

Here's another category I found while cleaning out my dev folder. It's another bit of Quicktime code for Cocoa. This is a category on QTMovie that makes it easier to deal with standard movies (i.e. ones with one video track and any number of audio tracks).

This same category exists in the MovieStepper project, but that version won't compile for 64-bit Cocoa applications because Apple has removed access to the underlying Quicktime data structures like Track and Media. This version uses only QTKit objects to accomplish the same tasks, and thus will compile for both 32-bit and 64-bit applications.

QTMovie-Frame.h
//
// QTMovie-Frame.h
// MovieStepper
//
// These are methods designed to be used on movies that contain only
// sequential frame data, e.g. straight movies. These methods make
// the assumption that the framerate is constant and that each frame
// is displayed for the same length of time. Do not use these methods
// on movies that have tracks other than a single video track and
// some number of audio tracks.
//
// This code may be used freely in any project, commercial or otherwise
// without obligation. There is no attribution required, and no need
// to publish any code. The code is provided with absolutely no
// warranties of any sort.

#import <Cocoa/Cocoa.h>
#import <QTKit/QTKit.h>

@interface QTMovie(Frames)
- (long)numberOfFrames;
- (void)gotoFrameNumber:(long)frameNum;
- (long)currentFrameNumber;
- (int)displayFPS;
- (float)desiredFPS;
- (NSImage *)frameImageForFrame:(int)frameNumber;
- (NSSize)size;
@end



QTMovie.m
//
// QTMovie-Frame.m
// MovieStepper
//
// Copyright 2009 Jeff LaMarche. All rights reserved.
//
// This code may be used freely in any project, commercial or otherwise
// without obligation. There is no attribution required, and no need
// to publish any code. The code is provided with absolutely no
// warranties of any sort.
//
// This code has been updated to work in 64-bit mode where access to
// the underlying Quicktime Carbon structures has been removed.

#import "QTMovie-Frames.h"

@implementation QTMovie(Frames)
- (long)numberOfFrames
{
NSArray *tracks = [self tracksOfMediaType:QTMediaTypeVideo];

for (QTTrack *track in tracks)
{
QTMedia *media = [track media];
NSNumber *frames = [media attributeForKey:QTMediaSampleCountAttribute];
if (frames != nil)
return [frames longValue];
}


return -1L;
}

- (void)gotoFrameNumber:(long)frameNum
{
int frames = [self numberOfFrames];
double percentDone = (double)frameNum / (double) frames;
QTTime duration = [self duration];
QTTime newTime;
newTime.timeScale = duration.timeScale;
newTime.flags = duration.flags;
newTime.timeValue = duration.timeValue * percentDone;
[self setCurrentTime:newTime];
}

- (long)currentFrameNumber
{
QTTime now = [self currentTime];
QTTime duration = [self duration];

if (now.timeValue == 0 || duration.timeValue == 0)
return 0;

double percentDone = (double)now.timeValue / (double)duration.timeValue;
int frames = [self numberOfFrames];

return (int) ((double)frames * percentDone)+1;
}

- (Fixed)rawFPS
{
NSArray *tracks = [self tracksOfMediaType:QTMediaTypeVideo];

for (QTTrack *track in tracks)
{
QTMedia *media = [track media];
QTTime duration = [[media attributeForKey:QTMediaDurationAttribute] QTTimeValue];
long numFrames = [self numberOfFrames];
double frameRate = numFrames*(double)duration.timeScale/(double)duration.timeValue;
return X2Fix(frameRate);
}

return -1;
}

- (int)displayFPS
{
return FixRound([self rawFPS]);
}

- (float)desiredFPS
{
return FixedToFloat([self rawFPS]);
}

- (NSImage *)frameImageForFrame:(int)frameNumber
{
QTTime restoreTime = [self currentTime];
[self gotoFrameNumber:frameNumber];
NSImage *ret = [self currentFrameImage];
[self setCurrentTime:restoreTime];
return ret;
}

- (NSSize)size
{
return [[self attributeForKey:QTMovieNaturalSizeAttribute] sizeValue];
}


@end

No comments:

Post a Comment