5

I need to create a movie from a series of generated images. (I'm creating the images based on the output of a physics modeling program.)

I found Apple's sample in QtKitCreateMovie and used that as a starting point. Instead of loading jpgs from the application bundle, I'm drawing to an NSImage and then adding that NSImage to the movie object. Here's the basic code I used for testing. mMovie is an instance of QTMovie:

NSImage *anImage = [[NSImage alloc] initWithSize:NSMakeSize(frameSize, frameSize)];
[anImage lockFocus];

float blendValue;
for (blendValue = 0.0; blendValue <= 1.0; blendValue += 0.05) {
    [[[NSColor blueColor] blendedColorWithFraction:blendValue ofColor:[NSColor redColor]] setFill];
    [NSBezierPath fillRect:NSMakeRect(0, 0, frameSize, frameSize)];
    [mMovie addImage:anImage forDuration:duration withAttributes:myDict];
}
[anImage unlockFocus];
[anImage release];

This works under OS X 10.5, but under OS X 10.6 I get an array index beyond bounds exception on the call to addImage:forDuration:withAttributes: (http://openradar.appspot.com/radar?id=1146401)

What's the proper way to create a movie under 10.6?

Also, although this works under 10.5, I run out of memory if I try to create a movie with thousands of frames. That also makes me think I'm not using the correct approach.

SSteve
  • 10,550
  • 5
  • 46
  • 72
  • 1
    You can make your color fills a little faster by using the `NSRectFill` function, which uses `NSCompositeCopy`, rather than `+[NSBezierPath fillRect:]`, which defaults to `NSCompositeSourceOver`. The result will look no different (since all the colors you fill with have 1.0 alpha), but Copy, last I checked, was measurably faster. – Peter Hosey May 14 '11 at 09:50
  • Also, there's not much reason to set whether the context should anti-alias when you're not filling a curved path. – Peter Hosey May 14 '11 at 10:12
  • Thanks, Peter. I've changed my calls from `+[NSBezierPath fillRect:]` to `NSRectFill`. In my real code I am drawing curved paths. – SSteve May 14 '11 at 15:41

1 Answers1

3

You're doing it right, but you're doing it wrong.

The correct way hasn't changed in QTKit. Your mistake is that you're trying to add the image before you have finished it, which happens when you unlock focus. Since you don't unlock focus until after you try to add the image (20 times), you are trying to add an unfinished image (20 times), which doesn't work.

The “out of bounds” exception is because the image has no representations. QTMovie, it seems, is trying to loop through the array returned by the image in response to a representations message, but that array is empty because the image is not finished.

Somehow, you got away with this in Leopard (probably due to an implementation detail that changed in Snow Leopard), but I'd say it was no less your bug then.

The solution is simply to lock focus and unlock focus on the image each time through the loop:

float blendValue;
for (blendValue = 0.0; blendValue <= 1.0; blendValue += 0.05) {
    [anImage lockFocus];
    [[NSGraphicsContext currentContext] setShouldAntialias:NO];
    [[[NSColor blueColor] blendedColorWithFraction:blendValue ofColor:[NSColor redColor]] setFill];
    [NSBezierPath fillRect:NSMakeRect(0, 0, frameSize, frameSize)];
    [anImage unlockFocus];

    [mMovie addImage:anImage forDuration:duration withAttributes:myDict];
}
Peter Hosey
  • 95,783
  • 15
  • 211
  • 370