<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Cocoa Is My Girlfriend &#187; QTKit</title>
	<atom:link href="http://www.cimgf.com/category/frameworks/qtkit/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.cimgf.com</link>
	<description>Taglines are for Windows programmers</description>
	<lastBuildDate>Thu, 15 Jul 2010 21:20:40 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Record Your Core Animation Animation</title>
		<link>http://www.cimgf.com/2009/02/03/record-your-core-animation-animation/</link>
		<comments>http://www.cimgf.com/2009/02/03/record-your-core-animation-animation/#comments</comments>
		<pubDate>Tue, 03 Feb 2009 05:38:37 +0000</pubDate>
		<dc:creator>Matt Long</dc:creator>
				<category><![CDATA[Core Animation]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[QTKit]]></category>

		<guid isPermaLink="false">http://www.cimgf.com/?p=437</guid>
		<description><![CDATA[Every once in a while I find a way to combine multiple technologies that, while they don&#8217;t produce anything terribly useful, are very interesting when combined. In this post I will be taking a look at combining Core Animation and QuickTime. As you may or may not be aware, you can draw in a graphics [...]]]></description>
			<content:encoded><![CDATA[<p>Every once in a while I find a way to combine multiple technologies that, while they don&#8217;t produce anything terribly useful, are very interesting when combined. In this post I will be taking a look at combining Core Animation and QuickTime. As you may or may not be aware, you can draw in a graphics context while your Core Animation animation is running and add each image created to a QTMovie object from QTKit. This enables you to create a QuickTime movie of your Core Animation animation. Here&#8217;s how.
<span id="more-437"></span></p>

<p>The basic process flow goes like this. Clicking the &#8216;Capture&#8217; button on the user interface calls an IBAction called <em>-saveAnimation</em>. It prompts the user to select an output file for the movie. When the user has selected the file, the animations are created and added to the layer. Next we create a timer that is going to call a function that will grab the current frame and place it into the QTMovie object using <em>-addImage</em> at a specified interval. We set our AppDelegate to also be the delegate for the animation group so that when the animation completes we get notified and can then write our QTMovie object data to disk.</p>

<h2>Use An Interesting Animation</h2>

<p>First you are going to need an animation that is worth recording. Of course any old animation will do, but we&#8217;ll keep it interesting by adding multiple animations to a single layer. I have created four different keyframe animations that we will add to an animation group. The keypaths are &#8220;backgroundColor&#8221;, &#8220;borderWidth&#8221;, &#8220;position&#8221;, and &#8220;bounds&#8221;. Check the sample code to see how these animations are constructed.</p>

<p>We set the duration for all of the animations to five seconds. We also need to make sure that we set the duration for the group itself, otherwise it will override the five second duration we set for the animations themselves and run in the default 0.25 seconds. The code below shows how the animations are added to the layer.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>loadAnimations;
<span style="color: #002200;">&#123;</span>
  CAAnimationGroup <span style="color: #002200;">*</span>group <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>CAAnimationGroup animation<span style="color: #002200;">&#93;</span>;
&nbsp;
  <span style="color: #002200;">&#91;</span>group setAnimations<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSArray</span> arrayWithObjects<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>self backgroundColorAnimation<span style="color: #002200;">&#93;</span>,
                          <span style="color: #002200;">&#91;</span>self borderWidthAnimation<span style="color: #002200;">&#93;</span>,
                          <span style="color: #002200;">&#91;</span>self positionAnimation<span style="color: #002200;">&#93;</span>,
                          <span style="color: #002200;">&#91;</span>self boundsAnimation<span style="color: #002200;">&#93;</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
&nbsp;
  <span style="color: #002200;">&#91;</span>group setValue<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;mainGroup&quot;</span> forKey<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;name&quot;</span><span style="color: #002200;">&#93;</span>;
  <span style="color: #002200;">&#91;</span>group setDuration<span style="color: #002200;">:</span><span style="color: #2400d9;">5.0</span><span style="color: #002200;">&#93;</span>;
  <span style="color: #002200;">&#91;</span>group setAutoreverses<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
  <span style="color: #002200;">&#91;</span>group setDelegate<span style="color: #002200;">:</span>self<span style="color: #002200;">&#93;</span>;
&nbsp;
  <span style="color: #002200;">&#91;</span>layer addAnimation<span style="color: #002200;">:</span>group forKey<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;group&quot;</span><span style="color: #002200;">&#93;</span>;  
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>Notice that we have used KVC here to set a name for the animation group. We will use this as a tag later to make sure the animation that triggers our <em>-animationDidStop:finished</em> animation delegate is the correct one. More on that later.</p>

<h2>Get Our Movie Ready</h2>

<p>Prior to loading the animations, we prompt the user to select a file to write the movie file to. After loading the animations, we start our timer.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>saveAnimation<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">&#123;</span>
  <span style="color: #400080;">NSSavePanel</span> <span style="color: #002200;">*</span>savePanel;
&nbsp;
  savePanel <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSSavePanel</span> savePanel<span style="color: #002200;">&#93;</span>;
  <span style="color: #002200;">&#91;</span>savePanel setExtensionHidden<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
  <span style="color: #002200;">&#91;</span>savePanel setCanSelectHiddenExtension<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;
  <span style="color: #002200;">&#91;</span>savePanel setTreatsFilePackagesAsDirectories<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;
&nbsp;
  <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> <span style="color: #002200;">&#91;</span>savePanel runModal<span style="color: #002200;">&#93;</span> <span style="color: #002200;">==</span> NSOKButton <span style="color: #002200;">&#41;</span>
  <span style="color: #002200;">&#123;</span>
    movie <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>QTMovie alloc<span style="color: #002200;">&#93;</span> initToWritableFile<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>savePanel filename<span style="color: #002200;">&#93;</span> error<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;    
  <span style="color: #002200;">&#125;</span>
&nbsp;
  <span style="color: #002200;">&#91;</span>self loadAnimations<span style="color: #002200;">&#93;</span>;
&nbsp;
  timer <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSTimer</span> scheduledTimerWithTimeInterval<span style="color: #002200;">:</span><span style="color: #2400d9;">1.0</span><span style="color: #002200;">/</span><span style="color: #002200;">&#40;</span>NSTimeInterval<span style="color: #002200;">&#41;</span><span style="color: #2400d9;">10.0</span>
                                           target<span style="color: #002200;">:</span>self
                                         selector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>updateTime<span style="color: #002200;">:</span><span style="color: #002200;">&#41;</span>
                                         userInfo<span style="color: #002200;">:</span><span style="color: #a61390;">NULL</span>
                                          repeats<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;    
&nbsp;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>Our <em>-updateTime</em> selector will get called every 1/10th of a second and will grab the current frame to save it to the QTMoive object. Here is the <em>-updateTime</em> code.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>updateTime<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSTimer</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>theTimer;
<span style="color: #002200;">&#123;</span>
  <span style="color: #400080;">NSBitmapImageRep</span> <span style="color: #002200;">*</span>image <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>self getCurrentFrame<span style="color: #002200;">&#93;</span>;
&nbsp;
  QTTime <span style="color: #a61390;">time</span> <span style="color: #002200;">=</span> QTMakeTime<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">1</span>, <span style="color: #2400d9;">10</span><span style="color: #002200;">&#41;</span>;
  <span style="color: #400080;">NSDictionary</span> <span style="color: #002200;">*</span>attrs <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDictionary</span> dictionaryWithObject<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;png &quot;</span> forKey<span style="color: #002200;">:</span>QTAddImageCodecType<span style="color: #002200;">&#93;</span>;
  <span style="color: #400080;">NSImage</span> <span style="color: #002200;">*</span>img <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSImage</span> alloc<span style="color: #002200;">&#93;</span> initWithData<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>image TIFFRepresentation<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
  <span style="color: #002200;">&#91;</span>movie addImage<span style="color: #002200;">:</span>img forDuration<span style="color: #002200;">:</span><span style="color: #a61390;">time</span> withAttributes<span style="color: #002200;">:</span>attrs<span style="color: #002200;">&#93;</span>;
&nbsp;
  <span style="color: #002200;">&#91;</span>image release<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<h2>Obtaining the Current Frame</h2>

<p>The code to obtain the current frame is somewhat lengthy, but the concepts are pretty simple. We need to create a graphics context that we can draw into and then draw into it using the presentationLayer of the contenView&#8217;s root layer. If you&#8217;re not familiar, the presentationLayer provides the current state of the animated fields while &#8220;in-flight&#8221;.</p>

<p>Core Animation doesn&#8217;t provide any callbacks for when a frame is ready to be displayed which is why we are using a timer. This means that we may be capturing more frames than we need to, so getting the right frame rate takes a bit of trial and error, which I have to confess I wasn&#8217;t able to get nailed down completely. I&#8217;m still working on it and will update here when I get that part figured out. Meanwhile, here is the code for <em>-getCurrentFrame</em></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #400080;">NSBitmapImageRep</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>getCurrentFrame;
<span style="color: #002200;">&#123;</span>
  CGContextRef    context <span style="color: #002200;">=</span> <span style="color: #a61390;">NULL</span>;
  CGColorSpaceRef colorSpace;
  <span style="color: #a61390;">int</span> bitmapByteCount;
  <span style="color: #a61390;">int</span> bitmapBytesPerRow;
&nbsp;
  <span style="color: #a61390;">int</span> pixelsHigh <span style="color: #002200;">=</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">int</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>window contentView<span style="color: #002200;">&#93;</span> layer<span style="color: #002200;">&#93;</span> bounds<span style="color: #002200;">&#93;</span>.size.height;
  <span style="color: #a61390;">int</span> pixelsWide <span style="color: #002200;">=</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">int</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>window contentView<span style="color: #002200;">&#93;</span> layer<span style="color: #002200;">&#93;</span> bounds<span style="color: #002200;">&#93;</span>.size.width;
&nbsp;
  bitmapBytesPerRow   <span style="color: #002200;">=</span> <span style="color: #002200;">&#40;</span>pixelsWide <span style="color: #002200;">*</span> <span style="color: #2400d9;">4</span><span style="color: #002200;">&#41;</span>;
  bitmapByteCount     <span style="color: #002200;">=</span> <span style="color: #002200;">&#40;</span>bitmapBytesPerRow <span style="color: #002200;">*</span> pixelsHigh<span style="color: #002200;">&#41;</span>;
&nbsp;
  colorSpace <span style="color: #002200;">=</span> CGColorSpaceCreateWithName<span style="color: #002200;">&#40;</span>kCGColorSpaceGenericRGB<span style="color: #002200;">&#41;</span>;
&nbsp;
  context <span style="color: #002200;">=</span> CGBitmapContextCreate <span style="color: #002200;">&#40;</span><span style="color: #a61390;">NULL</span>,
                                   pixelsWide,
                                   pixelsHigh,
                                   <span style="color: #2400d9;">8</span>,
                                   bitmapBytesPerRow,
                                   colorSpace,
                                   kCGImageAlphaPremultipliedLast<span style="color: #002200;">&#41;</span>;
  <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>context<span style="color: #002200;">==</span> <span style="color: #a61390;">NULL</span><span style="color: #002200;">&#41;</span>
  <span style="color: #002200;">&#123;</span>
    NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Failed to create context.&quot;</span><span style="color: #002200;">&#41;</span>;
    <span style="color: #a61390;">return</span> <span style="color: #a61390;">nil</span>;
  <span style="color: #002200;">&#125;</span>
&nbsp;
  CGColorSpaceRelease<span style="color: #002200;">&#40;</span> colorSpace <span style="color: #002200;">&#41;</span>;
&nbsp;
  <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>window contentView<span style="color: #002200;">&#93;</span> layer<span style="color: #002200;">&#93;</span> presentationLayer<span style="color: #002200;">&#93;</span> renderInContext<span style="color: #002200;">:</span>context<span style="color: #002200;">&#93;</span>;
&nbsp;
  CGImageRef img <span style="color: #002200;">=</span> CGBitmapContextCreateImage<span style="color: #002200;">&#40;</span>context<span style="color: #002200;">&#41;</span>;
  <span style="color: #400080;">NSBitmapImageRep</span> <span style="color: #002200;">*</span>bitmap <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSBitmapImageRep</span> alloc<span style="color: #002200;">&#93;</span> initWithCGImage<span style="color: #002200;">:</span>img<span style="color: #002200;">&#93;</span>;
  CFRelease<span style="color: #002200;">&#40;</span>img<span style="color: #002200;">&#41;</span>;
&nbsp;
  <span style="color: #a61390;">return</span> bitmap;
&nbsp;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>Notice that we are calling <em>-renderInContext</em> on the presentationLayer of the window&#8217;s contentView&#8217;s root layer. If we were only to render our animated layer, we wouldn&#8217;t be able to see the animation as it will only render the containing rectangle of the animating layer.</p>

<h2>Finishing Up</h2>

<p>Finally we need to write the movie data out to disk. The QTMovie object provides a single call to do so, but we need a way to know when the animation has finished so we can make this call. When we created our animation group, we set its delegate to our AppDelegate which will cause the delegate method <em>-animationDidStop:finished</em> to get called. Remember that setting the delegate for each of the individual animations gets ignored when you are using an animation group. We implement the <em>-animationDidStop:finished</em> delegate as shown below.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>animationDidStop<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>CAAnimation <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>theAnimation finished<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>flag;
<span style="color: #002200;">&#123;</span>
  NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Animation stopped: %@&quot;</span>, theAnimation<span style="color: #002200;">&#41;</span>;
&nbsp;
  <span style="color: #a61390;">id</span> name <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>theAnimation valueForKey<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;name&quot;</span><span style="color: #002200;">&#93;</span>;
  <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> name <span style="color: #002200;">&#41;</span>
    <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> <span style="color: #002200;">&#91;</span>name isEqualToString<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;mainGroup&quot;</span><span style="color: #002200;">&#93;</span> <span style="color: #002200;">&#41;</span>
    <span style="color: #002200;">&#123;</span>
      <span style="color: #002200;">&#91;</span>movie updateMovieFile<span style="color: #002200;">&#93;</span>;
      <span style="color: #002200;">&#91;</span>timer invalidate<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#125;</span>
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>The first thing we do is check the animation tag we set when creating the animation group. This really isn&#8217;t necessary in this code example since there is only one animation that is going to use it, but this code shows you how to differentiate if you were to use multiple animations or groups and wanted to know when each of them finished animating.</p>

<p>The call to <em>-updateMovieFile</em> writes the data to disk and we now have a QuickTime movie that will play our animation. Open the resulting file in QuickTime or just invoke QuickLook to see the result.</p>

<h2>Conclusion</h2>

<p>Maybe you can think of a use for this kind of thing. I haven&#8217;t yet&#8211;other than for writing a blog post of course. Shoot me your thoughts and comments in the comments section. Until next time.</p>

<p><a href='http://www.cimgf.com/wp-content/uploads/2009/02/caanimationcapture.zip'>CA Animation Capture Demo Project</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.cimgf.com/2009/02/03/record-your-core-animation-animation/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Core Animation Tutorial: Rendering QuickTime Movies In A CAOpenGLLayer</title>
		<link>http://www.cimgf.com/2008/09/10/core-animation-tutorial-rendering-quicktime-movies-in-a-caopengllayer/</link>
		<comments>http://www.cimgf.com/2008/09/10/core-animation-tutorial-rendering-quicktime-movies-in-a-caopengllayer/#comments</comments>
		<pubDate>Wed, 10 Sep 2008 15:20:38 +0000</pubDate>
		<dc:creator>Matt Long</dc:creator>
				<category><![CDATA[Advanced]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Core Animation]]></category>
		<category><![CDATA[Core Video]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[QTKit]]></category>

		<guid isPermaLink="false">http://www.cimgf.com/?p=219</guid>
		<description><![CDATA[I&#8217;ve been experimenting a great deal lately with OpenGL and QuickTime trying to see how the two technologies work together. It&#8217;s been a bit challenging, but fortunately Apple provides two really great resources&#8211;number one, sample code. I&#8217;ve been able to learn a lot just from the samples they provide in the development tools examples as [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been experimenting a great deal lately with OpenGL and QuickTime trying to see how the two technologies work together. It&#8217;s been a bit challenging, but fortunately Apple provides two really great resources&#8211;number one, sample code. I&#8217;ve been able to learn a lot just from the samples they provide in the development tools examples as well as online. And second, the cocoa-dev and quicktime-api lists are great. Lot&#8217;s of brilliant people there who are willing to share their knowledge. It&#8217;s very helpful, prohibition to discuss the iPhone SDK notwithstanding.</p>

<p>Getting two technologies to work together can be a challenge especially when the bridges between the two are not necessarily clearly laid out in documentation. As I pointed out Apple provides some excellent sample code to help you along, but there is no hand-holding approach to any of it. I actually appreciate that having come from the Windows world as it seems that there all you get sometimes is hand-holding where Microsoft doesn&#8217;t trust you, the developer to figure things out and really own what you&#8217;re doing. But I digress (wouldn&#8217;t be a CIMGF post if I didn&#8217;t dig on MS a bit).
<span id="more-219"></span></p>

<p>Like peanut butter and chocolate, what you get when you put together QuickTime and OpenGL is something greater than either of them left on their own (ok, this is subjective. Not everyone likes peanut butter and chocolate together, but again, I digress).</p>

<p>If you read the <a href="http://developer.apple.com/documentation/GraphicsImaging/Conceptual/CoreVideo/CVProg_Intro/chapter_1_section_1.html">Core Video Programming Guide</a> from Apple, you see they provide the reasons for using Core Video:</p>

<blockquote>
CoreVideo is necessary only if you want to manipulate individual video frames. For example, the following types of video processing would require CoreVideo:
<ul>
<li>Color correction or other filtering, such as provided by Core Image filters 
<li>Physical transforms of the video images (such as warping, or mapping on to a surface) 
<li>Adding video to an OpenGL scene 
<li>Adding additional information to frames, such as a visible timecode 
<li>Compositing multiple video streams 
</ul>
</blockquote>

<p>If all you need to do is display a movie, you should simply use either a QTMovieView or, if you want to stick with the Core Animation route, use a QTMovieLayer. They both function similarly, however, the view provides a lot of features that you won&#8217;t have to implement in the UI yourself such as a scrubber or play/pause buttons. Plus the view is very fast and efficient. I&#8217;m in the process of exploring performance differences between the two, but I will save my comments about that for another post.</p>

<p>For our example code we are most interested in the third point above&#8211;<strong>adding video to an OpenGL scene</strong>. It seems that new QuickTime developers often want to know how to manipulate movie images before displaying them. Often this leads them to pursue adding sub-views to the movie view which can become a big mess. Because we are using OpenGL, doing other drawing on the scene is very fast. I won&#8217;t kid you. OpenGL is a pain. I don&#8217;t know anybody who loves it, but everybody respects it because of its raw speed.</p>

<p>Point number five above&#8211;<strong>compositing multiple video streams</strong>&#8211;is also interesting. While I won&#8217;t be covering it in this post, I will say that it makes a world of difference performance wise if you composite the movies into a OpenGL scene. If you&#8217;ve ever tried to run multiple videos simultaneously in two different views or layers, it can get pretty herky jerky. You can see why it is necessary to use OpenGL instead.</p>

<h2>The OpenGL QuickTime Two Step</h2>

<p>Ok, it actually will take more than two steps, however, when you are working with Core Animation layers things get a whole lot easier than they are for rendering a movie in an NSOpenGLView. Here is what you get for free, as the kids say.</p>

<ul>
<li>You don&#8217;t have to set up the OpenGL context. It is already available for you to send your OpenGL calls to.
<li>The viewport for display is already configured
<li>You don&#8217;t need to set up a display link callback
</ul>

<p>What took over 400 lines of code when rendering a QuickTime movie with no filters to an NSOpengGLView now only takes around 150 lines. Any time you can reduce code to something simpler, it makes life easier. It also makes it much easier to grok, in my opinion.</p>

<p>There really are two primary steps you take when using a CAOpenGLLayer. First you check to see if you should draw. Then, depending upon the answer, drawInCGLContext gets called or doesn&#8217;t. Really thats it. Determining whether or not you should draw depends upon what you are trying to do. In our case, we only want to draw if all of the following are true:</p>

<ul>
<li>The movie is actually playing back
<li>The visual context for the movie has been initialized
<li>The visual context has a new image ready to be rendered
</ul>

<p>If all of these are true, then our call to canDrawInCGLContext returns YES. Here is the code I use to check these contraints in canDrawInCGLContext:</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>canDrawInCGLContext<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>CGLContextObj<span style="color: #002200;">&#41;</span>glContext 
                pixelFormat<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>CGLPixelFormatObj<span style="color: #002200;">&#41;</span>pixelFormat 
               forLayerTime<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>CFTimeInterval<span style="color: #002200;">&#41;</span>timeInterval 
                displayTime<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">const</span> CVTimeStamp <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>timeStamp
<span style="color: #002200;">&#123;</span> 
    <span style="color: #11740a; font-style: italic;">// There is no point in trying to draw anything if our</span>
    <span style="color: #11740a; font-style: italic;">// movie is not playing.</span>
    <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> <span style="color: #002200;">&#91;</span>movie rate<span style="color: #002200;">&#93;</span> &lt;<span style="color: #002200;">=</span> <span style="color: #2400d9;">0.0</span> <span style="color: #002200;">&#41;</span>
        <span style="color: #a61390;">return</span> <span style="color: #a61390;">NO</span>;
&nbsp;
    <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> <span style="color: #002200;">!</span>qtVisualContext <span style="color: #002200;">&#41;</span>
    <span style="color: #002200;">&#123;</span>
        <span style="color: #11740a; font-style: italic;">// If our visual context for our QTMovie has not been set up</span>
        <span style="color: #11740a; font-style: italic;">// we initialize it now</span>
        <span style="color: #002200;">&#91;</span>self setupVisualContext<span style="color: #002200;">:</span>glContext withPixelFormat<span style="color: #002200;">:</span>pixelFormat<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#125;</span>
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Check to see if a new frame (image) is ready to be draw at</span>
    <span style="color: #11740a; font-style: italic;">// the time specified.</span>
    <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span>QTVisualContextIsNewImageAvailable<span style="color: #002200;">&#40;</span>qtVisualContext,timeStamp<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>
    <span style="color: #002200;">&#123;</span>
        <span style="color: #11740a; font-style: italic;">// Release the previous frame</span>
        CVOpenGLTextureRelease<span style="color: #002200;">&#40;</span>currentFrame<span style="color: #002200;">&#41;</span>;
&nbsp;
        <span style="color: #11740a; font-style: italic;">// Copy the current frame into our image buffer</span>
        QTVisualContextCopyImageForTime<span style="color: #002200;">&#40;</span>qtVisualContext,
                                        <span style="color: #a61390;">NULL</span>,
                                        timeStamp,
                                        <span style="color: #002200;">&amp;</span>currentFrame<span style="color: #002200;">&#41;</span>;
&nbsp;
        <span style="color: #11740a; font-style: italic;">// Returns the texture coordinates for the part of the image that should be displayed</span>
        CVOpenGLTextureGetCleanTexCoords<span style="color: #002200;">&#40;</span>
                            currentFrame, 
                            lowerLeft, 
                            lowerRight, 
                            upperRight, upperLeft<span style="color: #002200;">&#41;</span>;
        <span style="color: #a61390;">return</span> <span style="color: #a61390;">YES</span>;
    <span style="color: #002200;">&#125;</span>
&nbsp;
    <span style="color: #a61390;">return</span> <span style="color: #a61390;">NO</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>The call to setup the visual context is where we are associating the QuickTime movie itself with a QTVisualContextRef object which is what OpenGL needs to draw the current frame. We will then use this object to load image data into a CVImageBufferRef which can be used for rendering with OpenGL. Here is the code to set up the visual context.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>setupVisualContext<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>CGLContextObj<span style="color: #002200;">&#41;</span>glContext 
           withPixelFormat<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>CGLPixelFormatObj<span style="color: #002200;">&#41;</span>pixelFormat;
<span style="color: #002200;">&#123;</span>
    OSStatus			    error;
&nbsp;
    <span style="color: #400080;">NSDictionary</span>	    <span style="color: #002200;">*</span>attributes <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
    attributes <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDictionary</span> dictionaryWithObjectsAndKeys<span style="color: #002200;">:</span>
                  <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDictionary</span> dictionaryWithObjectsAndKeys<span style="color: #002200;">:</span>
                   <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithFloat<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>self frame<span style="color: #002200;">&#93;</span>.size.width<span style="color: #002200;">&#93;</span>,
                   kQTVisualContextTargetDimensions_WidthKey,
                   <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithFloat<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>self frame<span style="color: #002200;">&#93;</span>.size.height<span style="color: #002200;">&#93;</span>,
                   kQTVisualContextTargetDimensions_HeightKey, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>, 
                  kQTVisualContextTargetDimensionsKey, 
                  <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDictionary</span> dictionaryWithObjectsAndKeys<span style="color: #002200;">:</span>
                   <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithFloat<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>self frame<span style="color: #002200;">&#93;</span>.size.width<span style="color: #002200;">&#93;</span>, 
                   kCVPixelBufferWidthKey, 
                   <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithFloat<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>self frame<span style="color: #002200;">&#93;</span>.size.height<span style="color: #002200;">&#93;</span>, 
                   kCVPixelBufferHeightKey, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>, 
                  kQTVisualContextPixelBufferAttributesKey,
                  <span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Create our quicktimee visual context</span>
    error <span style="color: #002200;">=</span> QTOpenGLTextureContextCreate<span style="color: #002200;">&#40;</span><span style="color: #a61390;">NULL</span>,
                                         glContext,
                                         pixelFormat,
                                         <span style="color: #002200;">&#40;</span>CFDictionaryRef<span style="color: #002200;">&#41;</span>attributes,
                                         <span style="color: #002200;">&amp;</span>qtVisualContext<span style="color: #002200;">&#41;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Associate it with our movie.</span>
    SetMovieVisualContext<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>movie quickTimeMovie<span style="color: #002200;">&#93;</span>,qtVisualContext<span style="color: #002200;">&#41;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>Next we check to see if there is an image ready using:</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span>QTVisualContextIsNewImageAvailable<span style="color: #002200;">&#40;</span>qtVisualContext,timeStamp<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span></pre></td></tr></table></div>


<p>And then we copy the image to our CVImageBufferRef with:</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">// Copy the current frame into our image buffer</span>
QTVisualContextCopyImageForTime<span style="color: #002200;">&#40;</span>qtVisualContext,
                                <span style="color: #a61390;">NULL</span>,
                                timeStamp,
                                <span style="color: #002200;">&amp;</span>currentFrame<span style="color: #002200;">&#41;</span>;</pre></td></tr></table></div>


<p>Now it&#8217;s all a matter of rendering the frame for the current time stamp.</p>

<h2>But Wait! What TimeStamp?</h2>

<p>If you asked this question, then you are a very astute reader. In order to obtain the next image, we simply passed the CVTimeStamp parameter, <em>timeStamp</em> to our call to QTVisualContextCopyImageForTime. But how do we even have a timestamp? Isn&#8217;t that something we need to get from a display link? If you&#8217;re asking what is a display link at this point, take a look at the <a href="http://developer.apple.com/documentation/GraphicsImaging/Conceptual/CoreVideo/CVProg_Concepts/chapter_2_section_3.html">Core Video Programming Guide</a> which states:</p>

<blockquote>
To simplify synchronization of video with a displayâ€™s refresh rate, Core Video provides a special timer called a display link. The display link runs as a separate high priority thread, which is not affected by interactions within your application process.

In the past, synchronizing your video frames with the displayâ€™s refresh rate was often a problem, especially if you also had audio. You could only make simple guesses for when to output a frame (by using a timer, for example), which didnâ€™t take into account possible latency from user interactions, CPU loading, window compositing and so on. The Core Video display link can make intelligent estimates for when a frame needs to be output, based on display type and latencies.
</blockquote>

<p>I will provide a more complete answer to the question in the future as I am still studying it myself, however, I will mention that a display link callback is unnecessary in this context as the CAOpenGLLayer is providing this for us. The timestamp field is all we need in order to get the current frame assuming that the movie is playing back.</p>

<h2>Drawing The Frame</h2>

<p>There is a special group of people who really get OpenGL. I salute all of you to whom this applies. You are amazing. I, however, only write as much of it as necessary and you&#8217;ll see that most of the code I have here is simply a copy and paste from sample code I got from Apple. I am starting to understand it more and more, however, it makes my brain hurt. Here is my drawing code for when a frame is ready to be rendered.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>drawInCGLContext<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>CGLContextObj<span style="color: #002200;">&#41;</span>glContext 
             pixelFormat<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>CGLPixelFormatObj<span style="color: #002200;">&#41;</span>pixelFormat 
            forLayerTime<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>CFTimeInterval<span style="color: #002200;">&#41;</span>interval 
             displayTime<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">const</span> CVTimeStamp <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>timeStamp
<span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">NSRect</span>    bounds <span style="color: #002200;">=</span> NSRectFromCGRect<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>self bounds<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
    GLfloat 	minX, minY, maxX, maxY;        
&nbsp;
    minX <span style="color: #002200;">=</span> NSMinX<span style="color: #002200;">&#40;</span>bounds<span style="color: #002200;">&#41;</span>;
    minY <span style="color: #002200;">=</span> NSMinY<span style="color: #002200;">&#40;</span>bounds<span style="color: #002200;">&#41;</span>;
    maxX <span style="color: #002200;">=</span> NSMaxX<span style="color: #002200;">&#40;</span>bounds<span style="color: #002200;">&#41;</span>;
    maxY <span style="color: #002200;">=</span> NSMaxY<span style="color: #002200;">&#40;</span>bounds<span style="color: #002200;">&#41;</span>;
&nbsp;
    glMatrixMode<span style="color: #002200;">&#40;</span>GL_MODELVIEW<span style="color: #002200;">&#41;</span>;
    glLoadIdentity<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span>;
    glMatrixMode<span style="color: #002200;">&#40;</span>GL_PROJECTION<span style="color: #002200;">&#41;</span>;
    glLoadIdentity<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span>;
    glOrtho<span style="color: #002200;">&#40;</span> minX, maxX, minY, maxY, <span style="color: #002200;">-</span><span style="color: #2400d9;">1.0</span>, <span style="color: #2400d9;">1.0</span><span style="color: #002200;">&#41;</span>;
&nbsp;
    glClearColor<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">0.0</span>, <span style="color: #2400d9;">0.0</span>, <span style="color: #2400d9;">0.0</span>, <span style="color: #2400d9;">0.0</span><span style="color: #002200;">&#41;</span>;	     
    glClear<span style="color: #002200;">&#40;</span>GL_COLOR_BUFFER_BIT<span style="color: #002200;">&#41;</span>;
&nbsp;
    CGRect imageRect <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>self frame<span style="color: #002200;">&#93;</span>;
    <span style="color: #11740a; font-style: italic;">// Enable target for the current frame</span>
    glEnable<span style="color: #002200;">&#40;</span>CVOpenGLTextureGetTarget<span style="color: #002200;">&#40;</span>currentFrame<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
    <span style="color: #11740a; font-style: italic;">// Bind to the current frame</span>
    <span style="color: #11740a; font-style: italic;">// This tells OpenGL which texture we are wanting </span>
    <span style="color: #11740a; font-style: italic;">// to draw so that when we make our glTexCord and </span>
    <span style="color: #11740a; font-style: italic;">// glVertex calls, our current frame gets drawn</span>
    <span style="color: #11740a; font-style: italic;">// to the context.</span>
    glBindTexture<span style="color: #002200;">&#40;</span>CVOpenGLTextureGetTarget<span style="color: #002200;">&#40;</span>currentFrame<span style="color: #002200;">&#41;</span>, 
                  CVOpenGLTextureGetName<span style="color: #002200;">&#40;</span>currentFrame<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
    glMatrixMode<span style="color: #002200;">&#40;</span>GL_TEXTURE<span style="color: #002200;">&#41;</span>;
    glLoadIdentity<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span>;
    glColor4f<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">1.0</span>, <span style="color: #2400d9;">1.0</span>, <span style="color: #2400d9;">1.0</span>, <span style="color: #2400d9;">1.0</span><span style="color: #002200;">&#41;</span>;
    glBegin<span style="color: #002200;">&#40;</span>GL_QUADS<span style="color: #002200;">&#41;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Draw the quads</span>
    glTexCoord2f<span style="color: #002200;">&#40;</span>upperLeft<span style="color: #002200;">&#91;</span><span style="color: #2400d9;">0</span><span style="color: #002200;">&#93;</span>, upperLeft<span style="color: #002200;">&#91;</span><span style="color: #2400d9;">1</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span>;
    glVertex2f  <span style="color: #002200;">&#40;</span>imageRect.origin.x, 
                 imageRect.origin.y <span style="color: #002200;">+</span> imageRect.size.height<span style="color: #002200;">&#41;</span>;
    glTexCoord2f<span style="color: #002200;">&#40;</span>upperRight<span style="color: #002200;">&#91;</span><span style="color: #2400d9;">0</span><span style="color: #002200;">&#93;</span>, upperRight<span style="color: #002200;">&#91;</span><span style="color: #2400d9;">1</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span>;
    glVertex2f  <span style="color: #002200;">&#40;</span>imageRect.origin.x <span style="color: #002200;">+</span> imageRect.size.width, 
                 imageRect.origin.y <span style="color: #002200;">+</span> imageRect.size.height<span style="color: #002200;">&#41;</span>;
    glTexCoord2f<span style="color: #002200;">&#40;</span>lowerRight<span style="color: #002200;">&#91;</span><span style="color: #2400d9;">0</span><span style="color: #002200;">&#93;</span>, lowerRight<span style="color: #002200;">&#91;</span><span style="color: #2400d9;">1</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span>;
    glVertex2f  <span style="color: #002200;">&#40;</span>imageRect.origin.x <span style="color: #002200;">+</span> imageRect.size.width, 
                 imageRect.origin.y<span style="color: #002200;">&#41;</span>;
    glTexCoord2f<span style="color: #002200;">&#40;</span>lowerLeft<span style="color: #002200;">&#91;</span><span style="color: #2400d9;">0</span><span style="color: #002200;">&#93;</span>, lowerLeft<span style="color: #002200;">&#91;</span><span style="color: #2400d9;">1</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span>;
    glVertex2f  <span style="color: #002200;">&#40;</span>imageRect.origin.x, imageRect.origin.y<span style="color: #002200;">&#41;</span>;
&nbsp;
    glEnd<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// This CAOpenGLLayer is responsible to flush</span>
    <span style="color: #11740a; font-style: italic;">// the OpenGL context so we call super</span>
    <span style="color: #002200;">&#91;</span>super drawInCGLContext<span style="color: #002200;">:</span>glContext 
                pixelFormat<span style="color: #002200;">:</span>pixelFormat 
               forLayerTime<span style="color: #002200;">:</span>interval 
                displayTime<span style="color: #002200;">:</span>timeStamp<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Task the context</span>
    QTVisualContextTask<span style="color: #002200;">&#40;</span>qtVisualContext<span style="color: #002200;">&#41;</span>;
&nbsp;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>If you&#8217;re not familiar with OpenGL it would help you to know that it&#8217;s all about the current state. What does this mean? Well, simply put, it means that the call you are making right now, applies to whatever state the context is in. These two calls are what are the most important for our purposes.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;">glEnable<span style="color: #002200;">&#40;</span>CVOpenGLTextureGetTarget<span style="color: #002200;">&#40;</span>currentFrame<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
glBindTexture<span style="color: #002200;">&#40;</span>CVOpenGLTextureGetTarget<span style="color: #002200;">&#40;</span>currentFrame<span style="color: #002200;">&#41;</span>, 
                  CVOpenGLTextureGetName<span style="color: #002200;">&#40;</span>currentFrame<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;</pre></td></tr></table></div>


<p>With these two calls we have told OpenGL which texture to use. Now, every subsequent call applies to this texture until the state is changed to something else. So now, when we set a color or draw a quad, it applies to the texture that has been set here.</p>

<h2>Conclusion</h2>

<p>I love both of these technologies, QuickTime and OpenGL. They are so powerful. It&#8217;s harnessing the power that&#8217;s the trick. I&#8217;ve got some other ideas for some related posts that I plan to cover in the weeks to come, but this was a real breakthrough for me. With the help of John Clayton, Jean-Daniel Dupas, and David Duncan on the cocoa-dev list, I was able to get the sample code put together for this post. Feel free to ask questions in the comments. I will do my best to answer, but I&#8217;m still pretty new to these technologies. Write some code yourself and have fun. This is really exciting stuff. Until next time.</p>

<h2>About The Demo Code</h2>

<p><strike>John Clayton has some issues getting the code to work on his Mac Pro. I successfully ran it on  my MacBook Pro, and the family iMac without any issues. Anyhow, we&#8217;re not sure what the problem is, so if you do run into trouble, let me know. Maybe we can figure it out. Meanwhile we&#8217;re investigating it as we have time.</strike></p>

<p><strong>Update:</strong> John Clayton figured it out. Apparently the visual context needs to be reset because the pixel format is not correct on the first run. We just reset the visual context now in the call to -copyCGLContextForPixelFormat and everything seems happy. The demo code has been updated to reflect the change.</p>

<p><a href='http://www.cimgf.com/wp-content/uploads/2008/09/qtglcalayerdemo.zip'><img src="http://www.cimgf.com/wp-content/uploads/2008/03/xcode.png" alt="Quicktime CAOpenGLLayer Demo" title="Quicktime CAOpenGLLayer Demo" width="64" class="aligncenter size-medium wp-image-49" /><br />Quicktime CAOpenGLLayer Demo</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.cimgf.com/2008/09/10/core-animation-tutorial-rendering-quicktime-movies-in-a-caopengllayer/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Cocoa Tutorial: Audio Scrub</title>
		<link>http://www.cimgf.com/2008/03/22/cocoa-tutorial-audio-scrub/</link>
		<comments>http://www.cimgf.com/2008/03/22/cocoa-tutorial-audio-scrub/#comments</comments>
		<pubDate>Sat, 22 Mar 2008 17:06:43 +0000</pubDate>
		<dc:creator>Matt Long</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[QTKit]]></category>

		<guid isPermaLink="false">http://www.cimgf.com/2008/03/22/cocoa-tutorial-audio-scrub/</guid>
		<description><![CDATA[I am currently working on an application that needs to set markers in audio and video tracks. While it&#8217;s easy to find a marker visually in the video tracks, it wasn&#8217;t quite so clear as to how to set a marker in an audio track. In this tutorial, I&#8217;ll demonstrate how to create an audio [...]]]></description>
			<content:encoded><![CDATA[<p>I am currently working on an application that needs to set markers in audio and video tracks. While it&#8217;s easy to find a marker visually in the video tracks, it wasn&#8217;t quite so clear as to how to set a marker in an audio track. In this tutorial, I&#8217;ll demonstrate how to create an audio scrub utility that will play a short audio clip when you drag an NSSlider. It shows the current time code of the track while you update the slider.
<span id="more-57"></span></p>

<p>You can download the demo project for this post here: <a href='http://www.cimgf.com/wp-content/uploads/2008/03/audioscrub.zip' title='Audio Scrub Demo Application'>Audio Scrub Demo Application</a></p>

<p>You may be wondering why you might want something like this. Here&#8217;s my reasoning. I sometimes set up to record audio through a high-end microphone while also video taping an event. The high end microphone doesn&#8217;t plug into my camcorder, so I just run it into another audio recording device. This way, I have a high-quality audio track to go along with the video. The problem then is that I need a way to merge the audio track with the video track. In my resulting video, I only want one audio track, so I need to overwrite the original audio track from the video clip with the audio track from the high-quality audio recording. It is necessary to match the track times to get it to sound/look right.</p>

<p>I will not go into any further depth as to what my application will do. Suffice it to say that to merge the high-quality audio track with the video, I have to set a marker in both tracks that will allow me to align them. That&#8217;s where the need for an audio scrubber comes in. I need to find the same marker (hand clap, other loud noise) in both files and set the two tracks to have that marker as their matching starting points.</p>

<h2>Timers and Selectors with Timeout</h2>

<p>QTKit provides this great little abstraction called QTMovie. It allows you to load up any media file and call <em>play:</em> on it and just starts to playback. What I wanted was for the audio to start playing back when the slider changed, but then to stop after a period of time so that it was just playing a quick sample on each change. My first approach was to use an NSTimer, but then I found something a little simpler.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>scrubAudio<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> <span style="color: #002200;">!</span>movie <span style="color: #002200;">&#41;</span>
        <span style="color: #a61390;">return</span>;
&nbsp;
    QTTime currentTime;
    NSTimeInterval sliderTime <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>sender floatValue<span style="color: #002200;">&#93;</span>;
&nbsp;
    currentTime.timeValue <span style="color: #002200;">=</span> movieDuration.timeValue <span style="color: #002200;">*</span> sliderTime;
    currentTime.timeScale <span style="color: #002200;">=</span> movieDuration.timeScale;
    currentTime.flags <span style="color: #002200;">=</span> <span style="color: #2400d9;">0</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Set the current time of the movie based upon the slider</span>
    <span style="color: #11740a; font-style: italic;">// position</span>
    <span style="color: #002200;">&#91;</span>movie setCurrentTime<span style="color: #002200;">:</span>currentTime<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Update our time code field.</span>
    <span style="color: #002200;">&#91;</span>self updateTimeTextField<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Start playback</span>
    <span style="color: #002200;">&#91;</span>movie setRate<span style="color: #002200;">:</span><span style="color: #2400d9;">1.0</span><span style="color: #002200;">&#93;</span>;
&nbsp;
    isPlaying <span style="color: #002200;">=</span> <span style="color: #a61390;">YES</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Let the audio play for nearly a second and then call checkPlayback which</span>
    <span style="color: #11740a; font-style: italic;">// will stop playback. This gives the user a chance to hear a sample of the </span>
    <span style="color: #11740a; font-style: italic;">// audio clip at the current time.</span>
    <span style="color: #002200;">&#91;</span>self performSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>checkPlayback<span style="color: #002200;">:</span><span style="color: #002200;">&#41;</span> withObject<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span> afterDelay<span style="color: #002200;">:</span><span style="color: #2400d9;">0.95</span><span style="color: #002200;">&#93;</span>;
&nbsp;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>This IBAction is connected to the slider in Interface Builder. Notice specifically the performSelector call. We&#8217;ll get into more depth with that call in a minute.</p>

<h2>Srubbing Without Bubbles</h2>

<p><img src='http://www.cimgf.com/wp-content/uploads/2008/03/audioscrub.png' alt='Audio Scrub' align='center' /><br />
<br />
I&#8217;m sure there are other ways to achieve an audio scrubbing feature, however, I was looking for the path of least resistance and using a QTMoive object seemed the best way to do that.</p>

<p>Now, here is what I figured was the most logical way to solve this problem.</p>

<ul>
<li>When the scrubber moves, an audio sample should be played from current position in the audio file</li><br />
<li>When the audio sample starts to play, it should only play for a moment and then stop playing</li><br />
<li>When the next or previous buttons are clicked, the sample at that point should be played and then stopped, but the playhead should be positioned at the next position though playback rolled ahead.</li><br />
</ul>

<p>To keep track of whether the audio is playing currently, I use a boolean flag called <em>isPlaying</em>. This gets toggled when the audio sample is set to play. It then gets toggled again when the playback gets stopped.</p>

<h2>Perform Selector After Delay</h2>

<p>When playback gets initiated, I call <strong>performSelector:withobject:afterDelay</strong>. This is a really handy little function that allows us to call another function after the specified delay. In the case of using the slider, we simply call <strong>checkPlayback:</strong> without any arguments. In the case of clicking the next or previous buttons, we pass in a QTTime object as an argument as we want the current time of playback to be set back to this time though playback has actually rolled ahead. Here is the implementation of <strong>checkPlayback:</strong>.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>checkPlayback<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>previousTime;
<span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> movie <span style="color: #002200;">&#41;</span>
    <span style="color: #002200;">&#123;</span>
        <span style="color: #11740a; font-style: italic;">// If it's still playing back...</span>
        <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> <span style="color: #002200;">&#91;</span>movie rate<span style="color: #002200;">&#93;</span> &gt; <span style="color: #2400d9;">0.0</span> <span style="color: #002200;">&#41;</span>
        <span style="color: #002200;">&#123;</span>
           <span style="color: #11740a; font-style: italic;">// stop playback</span>
            <span style="color: #002200;">&#91;</span>movie stop<span style="color: #002200;">&#93;</span>;
&nbsp;
            <span style="color: #11740a; font-style: italic;">// If the previousTime object was passed in, set</span>
            <span style="color: #11740a; font-style: italic;">// our currentTime in the audio file (movie) to use it.</span>
            <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> previousTime <span style="color: #002200;">&#41;</span>
                <span style="color: #002200;">&#91;</span>movie setCurrentTime<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>previousTime QTTimeValue<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
            <span style="color: #002200;">&#91;</span>self updateSlider<span style="color: #002200;">&#93;</span>;
            isPlaying <span style="color: #002200;">=</span> <span style="color: #a61390;">NO</span>;
        <span style="color: #002200;">&#125;</span>
    <span style="color: #002200;">&#125;</span>
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<h2>NSSlider Considerations</h2>

<p>The demo project has this set up already, but you need to understand that there are a few important details when creating your slider in Interface Builder. The first thing is that you need to make sure you minimum and maximum values are set to 0.0 and 1.0 respectively. This will give you the fractional number you need to calculate the position in the audio track where the current time is. Next, you need to make sure that continuous updating is enabled by checking the <strong>Continuous</strong> property. See the screenshot below. Continuous updating means that the IBAction for the slider gets called while you are dragging the slider. If you left this unchecked, it would only be called when you released your mouse button.
<img src='http://www.cimgf.com/wp-content/uploads/2008/03/slider-attributes.png' alt='Slider Attributes' /><br /><br /></p>

<h2>Conclusion</h2>

<p>If you know of a better way to achieve this affect, please let me know. I feel this method I&#8217;m using works adequately well, however, I&#8217;m sure there is room for improvement.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cimgf.com/2008/03/22/cocoa-tutorial-audio-scrub/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Core Animation Tutorial: QTMovieLayer and Image Animation</title>
		<link>http://www.cimgf.com/2008/03/05/core-animation-tutorial-qtmovielayer-and-image-animation/</link>
		<comments>http://www.cimgf.com/2008/03/05/core-animation-tutorial-qtmovielayer-and-image-animation/#comments</comments>
		<pubDate>Wed, 05 Mar 2008 19:33:26 +0000</pubDate>
		<dc:creator>Matt Long</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Core Animation]]></category>
		<category><![CDATA[Frameworks]]></category>
		<category><![CDATA[NSOperation]]></category>
		<category><![CDATA[QTKit]]></category>
		<category><![CDATA[calayer]]></category>
		<category><![CDATA[convert nsimage to cgimageref]]></category>
		<category><![CDATA[example]]></category>
		<category><![CDATA[qtmovielayer]]></category>
		<category><![CDATA[sample code]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.cimgf.com/2008/03/05/core-animation-tutorial-qtmovielayer-and-image-animation/</guid>
		<description><![CDATA[In my first post I wrote about using NSOperation to grab an image of the current frame of a QuickTime movie while it was playing and save it out to the filesystem. Considering the excitement that is surrounding Core Animation these days, I thought it might be interesting to take that project and change it [...]]]></description>
			<content:encoded><![CDATA[<p><a href='http://www.cimgf.com/wp-content/uploads/2008/03/qtmovielayer_desktop.jpg' title='QTMovieLayer App Desktop'  rel='lightbox'><img src='http://www.cimgf.com/wp-content/uploads/2008/03/qtmovielayer_desktop.thumbnail.jpg' alt='QTMovieLayer App Desktop' align="left" style="margin:5px;" /></a>In my <a href="http://www.cimgf.com/2008/02/23/nsoperation-example/">first post</a> I wrote about using NSOperation to grab an image of the current frame of a QuickTime movie while it was playing and save it out to the filesystem. Considering the excitement that is surrounding Core Animation these days, I thought it might be interesting to take that project and change it to instead grab the current frame and animate it across the screen using a Core Animation layer (CALayer). I had to employ a few tricks to get it to work, but the end result, while completely useless, is quite excellent.
<br /><br /><br /><br />
&nbsp;
<br /><br /><br /><br />
<span id="more-38"></span></p>

<h2>Getting Ready For The Image</h2>

<p>The focus of this tutorial is Core Animation and specifically how to use a QTMovieLayer as well as animating an image across the screen using a CALayer. I, therefore, will not spend any time addressing NSOperation and I think we&#8217;ve covered this adequately on this site. I would suggest, however, that you familiarize yourself with <a href="http://www.cimgf.com/2008/02/16/cocoa-tutorial-nsoperation-and-nsoperationqueue/">Marcus&#8217; post on NSOperation</a> as he discusses calling back into the main thread once the NSOperation has completed. I employ Marcus&#8217; technique in this project so that I can be notified when the image I&#8217;m wanting to animate is ready.</p>

<blockquote>
You can download the demo project for this post from here: <a href='http://www.cimgf.com/wp-content/uploads/2008/03/movieimageflick.zip' title='Movie Image Flick Demo Project'>Movie Image Flick Demo Project</a>
</blockquote>

<p>Download the project and run it. It will prompt you to select a QuickTime movie to play. Once the movie starts playing, tap your spacebar and watch the images pop off of the movie and animate to random places on the screen. Tap the spacebar quickly to see the effect work in rapid succession.</p>

<p>As in my NSOperation post, I want the video playback to be completely flicker free. I achieve this by obtaining a reference to a copy of the QTMovie object from which I obtain the image at the given time. If you take a look at my <em>main:</em> function in my NSOperation derived class, you&#8217;ll see how I am notifying the main thread that it may now do something with the image I&#8217;ve obtained.</p>

<p><strong>ImageGrabber.m:main</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>main;
<span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> movie <span style="color: #002200;">&#41;</span>
    <span style="color: #002200;">&#123;</span>
        <span style="color: #400080;">NSImage</span><span style="color: #002200;">*</span> image;
        image <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>movie frameImageAtTime<span style="color: #002200;">:</span><span style="color: #a61390;">time</span> 
                      withAttributes<span style="color: #002200;">:</span>imageAttrs error<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>image retain<span style="color: #002200;">&#93;</span>;
&nbsp;
        <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>AppDelegate shared<span style="color: #002200;">&#93;</span> performSelectorOnMainThread<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>imageReady<span style="color: #002200;">:</span><span style="color: #002200;">&#41;</span>
                                               withObject<span style="color: #002200;">:</span>image
                                            waitUntilDone<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>image release<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>In the second last line of the function, notice I am calling back into my main thread and letting the app delegate know that the image is ready. I am also handing the image to the <em>imageReady:</em> function. This is very convenient for what we need to do next. But first, let&#8217;s discuss drawing the layers with no backing view or window.</p>

<h2>Drawing Layers In Thin Air</h2>

<p>This project employs a trick that makes it appear as if the layers are being drawn without a backing view. This is, of course, not really possible, so instead we do a little trick. I achieved this effect by creating a borderless window with a transparent background. As usual, I want to give credit where credit is due. Lucas Newman answered a question <a href="http://theocacao.com/document.page/551">I posted on Scott Stevenson&#8217;s blog</a> to find out how Lucas did this in his demo project a the Silicon Valley CocoaHeads meeting on Core Animation. You simply create your own NSWindow derived class and override the initWithContentRect: method. Here is the resulting initialization code I came up with from his suggestion.</p>

<p><strong>BorderlessWindow.m:initWithContentRect</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span> initWithContentRect<span style="color: #002200;">:</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">NSRect</span><span style="color: #002200;">&#41;</span> contentRect
                 styleMask<span style="color: #002200;">:</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">unsigned</span> <span style="color: #a61390;">int</span><span style="color: #002200;">&#41;</span> aStyle
                   backing<span style="color: #002200;">:</span> <span style="color: #002200;">&#40;</span>NSBackingStoreType<span style="color: #002200;">&#41;</span> bufferingType
                     defer<span style="color: #002200;">:</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span> flag
<span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">!</span><span style="color: #002200;">&#91;</span>super initWithContentRect<span style="color: #002200;">:</span> contentRect 
                 styleMask<span style="color: #002200;">:</span> NSBorderlessWindowMask 
                   backing<span style="color: #002200;">:</span> bufferingType 
                   defer<span style="color: #002200;">:</span> flag<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #a61390;">return</span> <span style="color: #a61390;">nil</span>;
    <span style="color: #002200;">&#91;</span>self setBackgroundColor<span style="color: #002200;">:</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSColor</span> clearColor<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>self setOpaque<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #a61390;">return</span> self;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>The only issue with using a transparent backing window/view is that you cannot click through it even though it looks like you ought to be able to. There is probably a way to pass the click on to the next front most window, but I haven&#8217;t yet researched this. I&#8217;ll let you know when I find the answer, or if you know the answer, post it in the comments.</p>

<h2>Rapid Fire Image Animation</h2>

<p>I created a method to initialize my NSOperation derived objects and hand them off to the NSOperationQueue. I hooked it up to the spacebar and can then tap the spacebar as quickly as possible and watch the images just pop off the playing movie. Here is my <em>flickIt:</em> function.</p>

<p><strong>AppDelegate.m:flickIt</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>flickIt<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">&#123;</span>
    ImageGrabber <span style="color: #002200;">*</span>grabber <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>ImageGrabber alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #002200;">&#91;</span>grabber setTime<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>movie currentTime<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #11740a; font-style: italic;">// Hand off the background movie to the NSOperation derived</span>
    <span style="color: #11740a; font-style: italic;">// object</span>
    <span style="color: #002200;">&#91;</span>grabber setMovie<span style="color: #002200;">:</span>movieBak<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Add the oepration to the queue. It will be run immediately.</span>
    <span style="color: #002200;">&#91;</span>queue addOperation<span style="color: #002200;">:</span>grabber<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>This function creates the NSOpeartion derived objects and passes a reference to the current time in the playing movie as well as a reference to the background movie that I use to pull the image data from. Remember that this object is copied from the original QTMovie object and is used to keep from needing to pull the image data from the QTMovie object that is actually playing in the QTMovieLayer. Pulling the image from the QTMovie object that is being used for playback would cause the playback to stutter.</p>

<p>As stated earlier, when my image is ready, the NSOperation derived object, ImageGrabber, calls back into the main thread calling the function called <em>imageReady:</em>. Here is its implementation.</p>

<p><strong>AppDelegate.m:imageReady</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>imageReady<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSImage</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>image;
<span style="color: #002200;">&#123;</span>    
    <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSAnimationContext</span> currentContext<span style="color: #002200;">&#93;</span> setDuration<span style="color: #002200;">:</span>1.5f<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Save off the rectangle of the ready layer before</span>
    <span style="color: #11740a; font-style: italic;">// it gets animated. We will use this to reset the</span>
    <span style="color: #11740a; font-style: italic;">// ready layer.</span>
    CGRect prevRect <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>readyLayer frame<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Convert the NSImage to a CGImageRef</span>
    CGImageRef imageRef <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>self nsImageToCGImageRef<span style="color: #002200;">:</span>image<span style="color: #002200;">&#93;</span>;
    CFRetain<span style="color: #002200;">&#40;</span>imageRef<span style="color: #002200;">&#41;</span>;
    readyLayer.contents <span style="color: #002200;">=</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>imageRef;
    readyLayer.backgroundColor <span style="color: #002200;">=</span> CGColorCreateGenericRGB<span style="color: #002200;">&#40;</span>0.0f,0.0f,0.0f,1.0f<span style="color: #002200;">&#41;</span>;
    readyLayer.borderColor <span style="color: #002200;">=</span> CGColorCreateGenericRGB<span style="color: #002200;">&#40;</span>0.45f,0.45f,0.45f,1.0f<span style="color: #002200;">&#41;</span>;
    readyLayer.borderWidth <span style="color: #002200;">=</span> 4.0f;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Grab a random rectangle on the screen where our image</span>
    <span style="color: #11740a; font-style: italic;">// layer will animate to.</span>
    CGRect randRect <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>self getRandomRect<span style="color: #002200;">:</span>prevRect<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>readyLayer setFrame<span style="color: #002200;">:</span>randRect<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>readyLayer setOpacity<span style="color: #002200;">:</span>1.0f<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Reset the ready layer so that it is ready for the next image</span>
    readyLayer <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>CALayer alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span> retain<span style="color: #002200;">&#93;</span>;
    readyLayer.frame <span style="color: #002200;">=</span> prevRect;
    readyLayer.opacity <span style="color: #002200;">=</span> 0.01f;
&nbsp;
    <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>window contentView<span style="color: #002200;">&#93;</span> layer<span style="color: #002200;">&#93;</span> addSublayer<span style="color: #002200;">:</span>readyLayer<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>Notice that we are converting the <em>NSImage</em> that gets passed to this function into a <em>CGImageRef</em> which is what our Core Animation layer requires to set it contents. Here is the code to convert an <em>NSImage</em> to a <em>CGImageRef</em>.</p>

<p><strong>AppDelegate.m:nsImageToCGImageRef</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>CGImageRef<span style="color: #002200;">&#41;</span>nsImageToCGImageRef<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSImage</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>image;
<span style="color: #002200;">&#123;</span>
    <span style="color: #400080;">NSData</span> <span style="color: #002200;">*</span> imageData <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>image TIFFRepresentation<span style="color: #002200;">&#93;</span>;
    CGImageRef imageRef;
    <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span>imageData<span style="color: #002200;">&#41;</span>
    <span style="color: #002200;">&#123;</span>
        CGImageSourceRef imageSource <span style="color: #002200;">=</span> 
                     CGImageSourceCreateWithData<span style="color: #002200;">&#40;</span>
                           <span style="color: #002200;">&#40;</span>CFDataRef<span style="color: #002200;">&#41;</span>imageData,  <span style="color: #a61390;">NULL</span><span style="color: #002200;">&#41;</span>;
&nbsp;
        imageRef <span style="color: #002200;">=</span> CGImageSourceCreateImageAtIndex<span style="color: #002200;">&#40;</span>
                          imageSource, <span style="color: #2400d9;">0</span>, <span style="color: #a61390;">NULL</span><span style="color: #002200;">&#41;</span>;
    <span style="color: #002200;">&#125;</span>
    <span style="color: #a61390;">return</span> imageRef;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<h2>Preloading A Layer to Animate</h2>

<p>Instead of creating the layer, setting its contents, and then animating it all at once, I instead set an empty layer with a near zero opacity to overlay the QTMovieLayer when the movie first loads. Then, when the user taps the spacebar, I populate that invisible layer&#8217;s contents with the image data and then animate it. This keeps me from having to create a more complicated animation to get the desired effect.</p>

<p>Once the image layer has it&#8217;s new frame set, I re-initialize the ready layer. You see the ready layer get reset with this code from the <em>imageReady:</em> function.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">// Reset the ready layer so that it is ready for the next image</span>
readyLayer <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>CALayer alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span> retain<span style="color: #002200;">&#93;</span>;
readyLayer.frame <span style="color: #002200;">=</span> prevRect;
readyLayer.opacity <span style="color: #002200;">=</span> 0.01f;
&nbsp;
<span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>window contentView<span style="color: #002200;">&#93;</span> layer<span style="color: #002200;">&#93;</span> addSublayer<span style="color: #002200;">:</span>readyLayer<span style="color: #002200;">&#93;</span>;</pre></td></tr></table></div>


<blockquote>
<br />
<strong>Note:</strong> I set the opacity to near zero as when it is set to zero it won&#8217;t animate the opacity change properly. I&#8217;m looking into why this is and will update this post with what I find when I find it.
<br /><br />

&nbsp;
</blockquote>

<h2>Random Points</h2>

<p>When I animate the layers, I simply grab a random point and the screen and then scale the image down to 35% of the original. When I call <em>setFrame:</em> the magic ensues and my screen gets really cluttered with lots of images. As I said before, not very useful, but excellent. Here is the random rectangle calculation function, <em>getRandomRect:</em>.</p>

<p><strong>AppDelegate.m:getRandomRect</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>CGRect<span style="color: #002200;">&#41;</span>getRandomRect<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>CGRect<span style="color: #002200;">&#41;</span>startRect;
<span style="color: #002200;">&#123;</span>    
    CGPoint point <span style="color: #002200;">=</span> CGPointMake<span style="color: #002200;">&#40;</span>random<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">%</span> 
                          <span style="color: #002200;">&#40;</span>NSUInteger<span style="color: #002200;">&#41;</span>NSWidth<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>window frame<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span>, 
                          random<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">%</span> 
                           <span style="color: #002200;">&#40;</span>NSUInteger<span style="color: #002200;">&#41;</span>NSHeight<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>window frame<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
    <span style="color: #a61390;">return</span> CGRectMake<span style="color: #002200;">&#40;</span>point.x, point.y, 
                 startRect.size.width <span style="color: #002200;">*</span> 0.35f, startRect.size.height <span style="color: #002200;">*</span> 0.35f<span style="color: #002200;">&#41;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<h2>Conclusion</h2>

<p>The nuances of Core Animation are quite interesting and provide a fun challenge when trying to solve problems. In other words, the devil is in the details. There is probably a better way to achieve the animation code, but I felt that the solution I came up with here works pretty well. There are details about Core Animation that I am still learning, but this type of effect demonstrates exactly the kinds of interesting things that are possible.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cimgf.com/2008/03/05/core-animation-tutorial-qtmovielayer-and-image-animation/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>NSOperation Example</title>
		<link>http://www.cimgf.com/2008/02/23/nsoperation-example/</link>
		<comments>http://www.cimgf.com/2008/02/23/nsoperation-example/#comments</comments>
		<pubDate>Sat, 23 Feb 2008 06:46:05 +0000</pubDate>
		<dc:creator>Matt Long</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[NSOperation]]></category>
		<category><![CDATA[QTKit]]></category>
		<category><![CDATA[Threading]]></category>

		<guid isPermaLink="false">http://www.cimgf.com/2008/02/23/nsoperation-example/</guid>
		<description><![CDATA[Forget Mandelbrot sets (Apple coding headstarts) and Expression Trees. NSOperation is really not that hard. In his post, Marcus introduced how to use NSOperation to greatly simplify multi-threading tasks in your application. I am now going to provide a step-by-step walk-through sample application that uses NSOperation, NSOperationQueue, and QTKit. While looking around the Internet, I [...]]]></description>
			<content:encoded><![CDATA[<p><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-14.thumbnail.png' alt='QT Image Grab' border='0' style='margin:5px' align='left' /><strong>Forget Mandelbrot sets (Apple coding headstarts) and <a href="http://macresearch.org/node/4567" title="Mac Research NSOPeration Tutorial" target="_blank">Expression Trees</a>. NSOperation is really not that hard.</strong></p>

<p>In <a href="http://www.cimgf.com/2008/02/16/cocoa-tutorial-nsoperation-and-nsoperationqueue/">his post</a>, Marcus introduced how to use <em>NSOperation</em> to greatly simplify multi-threading tasks in your application. I am now going to provide a step-by-step walk-through sample application that uses <em>NSOperation</em>, <em>NSOperationQueue</em>, and <em>QTKit</em>.</p>

<p>While looking around the Internet, I noticed that the only examples of using <em>NSOperation</em> available were related to scientific applications. I wanted something that I could relate to a little better and since I&#8217;ve been working with <em>QTKit</em> a lot lately, I figured it would be a good framework to build from. This application simply grabs images of a movie while it is playing back and saves them out to a file. It&#8217;s pretty simple, but it shows how to do something fairly practical.
<span id="more-3"></span></p>

<h2>Grabbing Movie Image Frames</h2>

<p>The application displays a movie and provides a button for the user to click whenever the user wants to save the current frame of the movie to disk while it is playing. Here are some basic requirements I&#8217;ve given the app.</p>

<ul>
    <li>Images are only saved when the movie is playing back</li>
    <li>Clicking the button and the subsequent saving of the current image must not cause the movie to flicker</li>
    <li>Clicking in rapid succession should not cause the application to crash. For each click, a new task (operation) should be generated</li>
</ul>

<p>Here is a screenshot of the final application.</p>

<p><a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-14.png' title='QT Image Grab'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-14.thumbnail.png' alt='QT Image Grab' /></a></p>

<p>Follow along in XCode to create the application called QT Image Grab or <a href='http://www.cimgf.com/wp-content/uploads/2008/02/qtimagegrab.zip' title='Sample Project'>download the sample project here</a>.</p>

<p><strong>Note</strong> If you are already comfortable with setting up an AppDelegate class and making connections in Interface Builder, you can jump down to the section titled <a href="#derivedobject">Derive A Class From NSOperation</a></p>

<h2>Create The Application</h2>

<p>Create a Cocoa Application Using the following steps:</p>

<ol>
<li>Select <strong>File > New Projectâ€¦</strong> and choose <em>Cocoa Application</em> in the ensuing dialog. Click Next</li>
<li>Enter â€˜QTImageGrabâ€™ as the project name. Click Finish</li>
</ul>
</ol>

<p>You should see a project workspace like the following:</p>

<p><a href='http://www.cimgf.com/wp-content/uploads/2008/02/project.png' title='New Project Workspace'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/project.thumbnail.png' alt='New Project Workspace' /></a></p>

<h2>Create A Controller/Delegate Class</h2>

<p>The next thing you need to do is create an application controller, or delegate. To do so, use the following steps:</p>

<ol>
<li><strong>Option-Click</strong> on the <em>Classes</em> folder in your workspace and select &#8216;Add File&#8230;&#8217;

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-2.png' title='Add New Objective-C Class'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-2.thumbnail.png' alt='Add New Objective-C Class' /></a>
</li>
<li>Choose <strong>Object-C Class</strong> in the ensuing dialog and click <strong>Next</strong></li>

<li>Name the file &#8216;AppDelegate.m&#8217; and click <strong>Finish</strong></li>

<li>A new code window will display with your &#8216;AppDelegate&#8217; interface code (.h file). Edit the code so that it looks like this:


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #6e371a;">#import &lt;Cocoa/Cocoa.h&gt;</span>
<span style="color: #6e371a;">#import &lt;QTKit/QTKit.h&gt;</span>
<span style="color: #6e371a;">#import &lt;QuartzCore/CoreAnimation.h&gt;</span>
&nbsp;
<span style="color: #a61390;">@interface</span> AppDelegate <span style="color: #002200;">:</span> <span style="color: #400080;">NSObject</span> <span style="color: #002200;">&#123;</span>
	IBOutlet QTMovieView <span style="color: #002200;">*</span>movieView;
	IBOutlet <span style="color: #400080;">NSTextField</span> <span style="color: #002200;">*</span>outputPath;
	IBOutlet <span style="color: #400080;">NSWindow</span> <span style="color: #002200;">*</span>window;
&nbsp;
	<span style="color: #400080;">NSOperationQueue</span> <span style="color: #002200;">*</span>operationQueue;
	QTMovie <span style="color: #002200;">*</span>imagesMovie;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>grab<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>openMovie<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>selectOutputDir<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
&nbsp;
<span style="color: #a61390;">@end</span></pre></td></tr></table></div>



</li>

<li>Now we need to add the QTKit framework to your project. Option-Click the Frameworks folder in your project and select <strong>Add > Existing Frameworks&#8230;</strong>

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-3.png' title='Add Existing Frameworks'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-3.thumbnail.png' alt='Add Existing Frameworks' /></a>

In the ensuing dialog, navigate to <strong>/System/Library/Frameworks</strong> and select <strong>QTKit.framework</strong>.

Click <strong>Add</strong>

<li>Now switch over to your implementation file for &#8216;AppDelegate&#8217; (.m file). Add the implementation code so that the file looks like this:<br />


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@implementation</span> AppDelegate
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>awakeFromNib;
<span style="color: #002200;">&#123;</span>
    <span style="color: #11740a; font-style: italic;">// We're going to add some initialization code here</span>
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>grab<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">&#123;</span>
    <span style="color: #11740a; font-style: italic;">// This is where will will start the process for grabbing the current image.</span>
&nbsp;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>openMovie<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">&#123;</span>
    <span style="color: #11740a; font-style: italic;">// Here we load our movie using an open panel dialog.</span>
&nbsp;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>selectOutputDir<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">&#123;</span>
    <span style="color: #11740a; font-style: italic;">// Here we will select an output directory where the current frame</span>
    <span style="color: #11740a; font-style: italic;">// image will be saved to.</span>
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>dealloc;
<span style="color: #002200;">&#123;</span>
    <span style="color: #11740a; font-style: italic;">// We're going to have some cleanup to do.</span>
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></td></tr></table></div>



<br />
We will actually add some code to do something in each of these methods shortly, but first we need to hook it up to the user interface in Interface Builder.
</li><br />
</ol>

<h2>Make The Interface Builder Connections</h2>

<p>Now that we&#8217;ve specified all of our actions and outlets in the <em>AppDelegate</em> code, let&#8217;s make the connections in our NIB file. To do so, use the following steps.</p>

<ol>
<li>In the tree view of your project in XCode, expand the smart folder labeled <em>NIB Files</em> and double click the file called <strong>MainMenu.nib</strong>

<em>Interface Builder</em> will load the NIB file.
</li>
<li>In <em>Interface Builder</em> click and drag an NSObject from the <em>Library</em> palette into your NIB file and rename the object to <strong>AppDelegate</strong> as shown:

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-4.png' title='Add App Delegate Object'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-4.thumbnail.png' alt='Add App Delegate Object' /></a></li>

<li>With the <strong>AppDelegate</strong> selected, select <strong>Tools > Inspector</strong> from the menu bar. In the inspector, select the <em>Object Identity</em> tab (tab 6) and in the <em>Class</em> field, enter <strong>AppDelegate</strong>.

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-5.png' title='Set AppDelegate Object'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-5.thumbnail.png' alt='Set AppDelegate Object' /></a></li>

<li>Now we need to tell our application to use the <em>AppDelegate</em> object as its delegate. <em>Control-Click</em> on the <strong>File&#8217;s Owner</strong> object in the MainMenu.nib window and drag a connection to the <strong>AppDelegate</strong> object and select <strong>delegate</strong> in the ensuing pop-up menu.

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-6.png' title='Set Delegate'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-6.thumbnail.png' alt='Set Delegate' /></a></li>

<li>All we have left now is to drag the controls onto the window and connect the actions and outlets. Edit the main window dragging controls to it so as to make it look like this.

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-7.png' title='Main Window In Interface Builder'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-7.thumbnail.png' alt='Main Window In Interface Builder' /></a>

<strong>Note:</strong> The black area of the window is a <em>QTMovieView</em> which you&#8217;ll be able to find in the object library. It&#8217;s dimensions are set to a standard DV video format of 720 x 480 pixels.</li>

<li>Drag a connection (Control-Click) from the <em>Grab</em> button to the <em>AppDelegate</em> and select <strong>grab:</strong> from the dropdown.

 <a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-8.png' title='Connect Grab Button'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-8.thumbnail.png' alt='Connect Grab Button' /></a></li>

<li>Drag a connection from the <strong>File | Open&#8230;</strong> menu item to the <em>AppDelegate</em> and select <strong>openMovie:</strong> from the dropdown.

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-9.png' title='Connect Open Movie Menu'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-9.thumbnail.png' alt='Connect Open Movie Menu' /></a></li>

<li>Drag a connection from the <em>Select Output Folder Path</em> button to the <em>AppDelegate</em> and select <strong>selectOutputDir:</strong> from the dropdown.

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-11.png' title='Connect Select Output Folder Path Button'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-11.thumbnail.png' alt='Connect Select Output Folder Path Button' /></a></li>

<li>Drag a connection from the <em>AppDelegate</em> object to the Output Folder Path text field and select the <strong>outputPath</strong> <em>NSTextField</em> from the dropdown.

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-10.png' title='Connect AppDelegate To Output Path Textfield'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-10.thumbnail.png' alt='Connect AppDelegate To Output Path Textfield' /></a></li>

<li>Drag a connection from the <em>AppDelegate</em> object to the QTMovieView and select <strong>movieView</strong> from the dropdown.

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-13.png' title='Connect Movie View'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-13.thumbnail.png' alt='Connect Movie View' /></a></li>
</ol>

<p>Now we are finished in Interface Builder. Let&#8217;s return to XCode and start populating our event handlers with code. Don&#8217;t forget to save your NIB file in Interface Builder.</p>

<h2>Adding Event Handling Code</h2>

<p>For most of our event handlers, you can simply copy and paste the code from this section as their use is simply to set up the application and not directly related to the use of <em>NSOperation</em> or <em>NSOperationQueue</em>.</p>

<p><strong>- (void)awakeFromNib</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>awakeFromNib;
<span style="color: #002200;">&#123;</span>
    <span style="color: #11740a; font-style: italic;">// Initialize the queue</span>
    operationQueue <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSOperationQueue</span> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p><strong>- (IBAction)selectOutputDir:(id)sender;</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>selectOutputDir<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">&#123;</span>
    <span style="color: #400080;">NSOpenPanel</span> <span style="color: #002200;">*</span>openPanel;
&nbsp;
    openPanel <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSOpenPanel</span> openPanel<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>openPanel setCanChooseDirectories<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>openPanel setAllowsMultipleSelection<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>openPanel setResolvesAliases<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>openPanel setCanChooseFiles<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>openPanel runModalForTypes<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span> <span style="color: #002200;">==</span> NSOKButton<span style="color: #002200;">&#41;</span>
    <span style="color: #002200;">&#123;</span>
        <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>directory <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>openPanel directory<span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>outputPath setStringValue<span style="color: #002200;">:</span>directory<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p><strong>- (void)dealloc</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>dealloc;
<span style="color: #002200;">&#123;</span>
    <span style="color: #002200;">&#91;</span>super dealloc<span style="color: #002200;">&#93;</span>;
    <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> imagesMovie <span style="color: #002200;">&#41;</span>
        <span style="color: #002200;">&#91;</span>imagesMovie release<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>There are two other event handlers that we need to fill in, but they will require a little bit of explanation, so first let&#8217;s go and create our NSOpeation derived class that will do all of the work we need.</p>

<p><a name="derivedobject">&nbsp;</a></p>

<h2>Derive A Class From NSOperation</h2>

<p>In our application, we want to get the current image of the movie while it is playing back and save it out to disk. This is the operation that we want our NSOoperation to complete in a separate thread. In order to do this, we need to create a new Objective-C class that derives from NSOperation. To do so, complete the following steps.</p>

<ol>
<li>In the XCode treeview, Option-Click the <em>Classes</em> folder and select <strong>Add | New File&#8230;</strong>.

<a href='http://www.cimgf.com/wp-content/uploads/2008/02/picture-12.png' title='Add New File'><img src='http://www.cimgf.com/wp-content/uploads/2008/02/picture-12.thumbnail.png' alt='Add New File' /></a>

In the ensuing dialog, select <strong>Objective-C Class</strong> and click next. Enter the name &#8216;GragQTImageOperation.m&#8217; making sure that <strong>Also create &#8220;GrabQTImageOperation.h&#8221;</strong> is checked and click <strong>Finish</strong></li>

<li>In the header file for the new Objective-C class you just created, change the interface so that our object inherits from NSOperation.


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@interface</span> GrabQTImageOperation <span style="color: #002200;">:</span> <span style="color: #400080;">NSOperation</span> <span style="color: #002200;">&#123;</span>
&nbsp;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>



</ol>

<h2>Give Our NSOperation Something To Do</h2>

<p>Our new class now needs some objects to work with and a method to do the work. To do work, an NSOperation derived class, must override the method called <strong>main:</strong>. Edit the file <em>GrabQTImageOperation.m</em> and provide the following function declaration.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>main
<span style="color: #002200;">&#123;</span>
&nbsp;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>In order to do the work, we need the following objects:</p>

<ul>
<li><strong>QTMovie*</strong>: a pointer to a QTMovie view from which we will obtain our image to save.</li>
<li><strong>NSDictionary*</strong>: a dictionary to hold our attributes we will use when exporting to an image format</li>
<li><strong>NSLock*</strong>: a lock object to synchronize access to our QTMovie object.</li>
<li><strong>NSString*</strong>: a pointer to the output folder path we will use to save the files to.</li>
<li><strong>QTTime</strong>: a QTTime object representing the point in time as the movie was playing at which the grab button was clicked.</li>
</ul>

<p>Change the <em>GrabQTImageOperation</em> header file to look like this.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #6e371a;">#import &lt;Cocoa/Cocoa.h&gt;</span>
<span style="color: #6e371a;">#import &lt;QTKit/QTKit.h&gt;</span>
&nbsp;
<span style="color: #a61390;">@interface</span> GrabQTImageOperation <span style="color: #002200;">:</span> <span style="color: #400080;">NSOperation</span> <span style="color: #002200;">&#123;</span>
    QTMovie<span style="color: #002200;">*</span> movie;
    <span style="color: #400080;">NSDictionary</span> <span style="color: #002200;">*</span>imageAttrs;
    <span style="color: #400080;">NSLock</span> <span style="color: #002200;">*</span>lock;
    <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>outputPath;
    QTTime <span style="color: #a61390;">time</span>;
&nbsp;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@property</span> <span style="color: #002200;">&#40;</span>assign<span style="color: #002200;">&#41;</span> QTMovie <span style="color: #002200;">*</span>movie;
<span style="color: #a61390;">@property</span> <span style="color: #002200;">&#40;</span>assign<span style="color: #002200;">&#41;</span> <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>outputPath;
<span style="color: #a61390;">@property</span> <span style="color: #002200;">&#40;</span>assign<span style="color: #002200;">&#41;</span> QTTime <span style="color: #a61390;">time</span>;
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>main;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>saveImage<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSImage</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>image;
<span style="color: #a61390;">@end</span></pre></td></tr></table></div>


<p>The method <strong>saveImage:</strong> actually saves the image to disk. Go ahead and add its declaration in the header as shown above. We&#8217;ll get back to that in a minute.</p>

<h2>Implement main:</h2>

<p>Now we need to switch to our implementation file (<strong>GrabQTImageOperation.m</strong>) and enter the following code into the <strong>main:</strong> function.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>main
<span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> movie <span style="color: #002200;">&#41;</span>
    <span style="color: #002200;">&#123;</span>
        <span style="color: #400080;">NSImage</span><span style="color: #002200;">*</span> image;
        <span style="color: #002200;">&#91;</span>lock lock<span style="color: #002200;">&#93;</span>;
        image <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>movie frameImageAtTime<span style="color: #002200;">:</span><span style="color: #a61390;">time</span> withAttributes<span style="color: #002200;">:</span>imageAttrs error<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>lock unlock<span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>self saveImage<span style="color: #002200;">:</span>image<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#125;</span>
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>All we are doing at this point is getting the image at the specified time from our QTMovie reference and passing it on to our <strong>saveImage:</strong> method. Now fill we can populate the rest of the methods with the code we need to finish our NSOperation derived class.</p>

<p><strong>- (id)init</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>init
<span style="color: #002200;">&#123;</span>
    lock <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSLock</span> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
    <span style="color: #11740a; font-style: italic;">// Specify that we want to save out a high-quality image.</span>
    imageAttrs <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDictionary</span> dictionaryWithObjectsAndKeys<span style="color: #002200;">:</span>
                       QTMovieFrameImageTypeNSImage, QTMovieFrameImageType,
                       <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithBool<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>, QTMovieFrameImageHighQuality, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>imageAttrs retain<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>super init<span style="color: #002200;">&#93;</span>;
    <span style="color: #a61390;">return</span> self;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p><strong>- (void)saveImage:(NSImage*)image</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>saveImage<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSImage</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>image;
<span style="color: #002200;">&#123;</span>
    <span style="color: #400080;">NSArray</span> <span style="color: #002200;">*</span>representations;
    <span style="color: #400080;">NSData</span> <span style="color: #002200;">*</span>bitmapData;
&nbsp;
    representations <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>image representations<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Specify that we want to save the file as a JPG</span>
    bitmapData <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSBitmapImageRep</span> representationOfImageRepsInArray<span style="color: #002200;">:</span>representations 
                                usingType<span style="color: #002200;">:</span>NSJPEGFileType 
                                properties<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDictionary</span> dictionaryWithObject<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDecimalNumber</span> numberWithFloat<span style="color: #002200;">:</span><span style="color: #2400d9;">1.0</span><span style="color: #002200;">&#93;</span> 
                                forKey<span style="color: #002200;">:</span>NSImageCompressionFactor<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Creates a long filename, but at least it's unique.</span>
    <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>filename <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSProcessInfo</span> processInfo<span style="color: #002200;">&#93;</span> globallyUniqueString<span style="color: #002200;">&#93;</span>;
    filename <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>filename stringByAppendingString<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;.jpg&quot;</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>imgOut <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>outputPath stringByAppendingString<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;/&quot;</span><span style="color: #002200;">&#93;</span>;
    imgOut <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>imgOut stringByAppendingString<span style="color: #002200;">:</span>filename<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>bitmapData writeToFile<span style="color: #002200;">:</span>imgOut  atomically<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>And finally, don&#8217;t forget to add our synthesize calls at the top of the implementation.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@implementation</span> GrabQTImageOperation
&nbsp;
<span style="color: #a61390;">@synthesize</span> movie;
<span style="color: #a61390;">@synthesize</span> <span style="color: #a61390;">time</span>;
<span style="color: #a61390;">@synthesize</span> images;
<span style="color: #a61390;">@synthesize</span> outputPath;
...</pre></td></tr></table></div>


<h2>Finish Implementing AppDelegate</h2>

<p>Now that we&#8217;ve finished creating our <em>NSOperation</em> derived class, we can finish the implementation of our <em>AppDelegate</em>. First add the following code to the <strong>openMovie:</strong> event handler.</p>

<p><strong>- (IBAction)openMovie:(id)sender</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>openMovie<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">&#123;</span>
    <span style="color: #400080;">NSOpenPanel</span> <span style="color: #002200;">*</span>openPanel;
&nbsp;
    openPanel <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSOpenPanel</span> openPanel<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>openPanel setCanChooseDirectories<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>openPanel setAllowsMultipleSelection<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>openPanel setResolvesAliases<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>openPanel setCanChooseFiles<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>openPanel runModalForTypes<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span> <span style="color: #002200;">==</span> NSOKButton<span style="color: #002200;">&#41;</span>
    <span style="color: #002200;">&#123;</span>
        <span style="color: #400080;">NSArray</span> <span style="color: #002200;">*</span>filesToOpen <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>openPanel filenames<span style="color: #002200;">&#93;</span>;
        <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>theFilePath <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>filesToOpen objectAtIndex<span style="color: #002200;">:</span><span style="color: #2400d9;">0</span><span style="color: #002200;">&#93;</span>;
        QTMovie <span style="color: #002200;">*</span>movie <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>QTMovie movieWithFile<span style="color: #002200;">:</span>theFilePath error<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
        imagesMovie <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>QTMovie movieWithFile<span style="color: #002200;">:</span>theFilePath error<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>imagesMovie retain<span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>movieView setMovie<span style="color: #002200;">:</span>movie<span style="color: #002200;">&#93;</span>;		
    <span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>Take note of these two lines:</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;">QTMovie <span style="color: #002200;">*</span>movie <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>QTMovie movieWithFile<span style="color: #002200;">:</span>theFilePath error<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
imagesMovie <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>QTMovie movieWithFile<span style="color: #002200;">:</span>theFilePath error<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;</pre></td></tr></table></div>


<p>Notice that we are loading the same movie into memory twice. The first is for the object called <em>movie</em> which will be used in our <em>QTMovieView</em> for actual movie playback. The other movie is an instance variable called <em>imagesMovie</em> which will <em>act as a background movie</em>. It will be passed to our <em>NSOperation</em> derived class and it is the object from which the images will be obtained for saving to disk.</p>

<p>We use two movie objects representing the same file on disk in order to satisfy one of our requirements which was to ensure that the movie doesn&#8217;t flicker or stutter when the operation is happening. One movie reference is for display, the other for processing.</p>

<p>And finally, we now need to populate our <strong>grab:</strong> method which initializes our <em>NSOperation</em> derived objects and passes them off to the <em>NSOperationQueue</em> which runs them immediately. First, we need to import our header file at the top of <strong>AppDelegate.h</strong> like this:</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #6e371a;">#import &quot;GrabQTImageOperation.h&quot;</span></pre></td></tr></table></div>


<p>And now, here is the implementation of <strong>grab:</strong> in <strong>AppDelegate.m</strong>.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>grab<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">&#123;</span>
    <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>path <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>outputPath stringValue<span style="color: #002200;">&#93;</span>;
    <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> <span style="color: #002200;">!</span>path || <span style="color: #002200;">&#91;</span>path length<span style="color: #002200;">&#93;</span> &lt;<span style="color: #002200;">=</span> <span style="color: #2400d9;">0</span> <span style="color: #002200;">&#41;</span>
    <span style="color: #002200;">&#123;</span>
        <span style="color: #400080;">NSAlert</span> <span style="color: #002200;">*</span>alert <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSAlert</span> alertWithMessageText<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Set Output Directory&quot;</span> defaultButton<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;OK&quot;</span> alternateButton<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span> otherButton<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span> informativeTextWithFormat<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;You must first select an output directory before grabbing images.&quot;</span><span style="color: #002200;">&#93;</span>;
&nbsp;
        <span style="color: #002200;">&#91;</span>alert beginSheetModalForWindow<span style="color: #002200;">:</span>window
            modalDelegate<span style="color: #002200;">:</span>self
            didEndSelector<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span>
            contextInfo<span style="color: #002200;">:</span><span style="color: #a61390;">NULL</span><span style="color: #002200;">&#93;</span>;
&nbsp;
        <span style="color: #a61390;">return</span>;
    <span style="color: #002200;">&#125;</span>
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Check to see if the movie is playing	</span>
    <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>movieView movie<span style="color: #002200;">&#93;</span> rate<span style="color: #002200;">&#93;</span> &gt; 0.0f <span style="color: #002200;">&#41;</span>
    <span style="color: #002200;">&#123;</span>
        <span style="color: #11740a; font-style: italic;">// If so, create our NSOperation derived object and hand it off to the queue</span>
        GrabQTImageOperation <span style="color: #002200;">*</span>op <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>GrabQTImageOperation alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>op setMovie<span style="color: #002200;">:</span>imagesMovie<span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>op setTime<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>movieView movie<span style="color: #002200;">&#93;</span> currentTime<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>op setOutputPath<span style="color: #002200;">:</span>path<span style="color: #002200;">&#93;</span>;
&nbsp;
        <span style="color: #11740a; font-style: italic;">// As soon as this method finishes, the operation is set to work</span>
        <span style="color: #002200;">&#91;</span>operationQueue addOperation<span style="color: #002200;">:</span>op<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#125;</span>
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>The first thing we do is make sure our output path is set. If it is not, we alert the user and return. Otherwise, we check to see if our movie is playing by checking the movie&#8217;s current rate. If it is playing, then we are going to spin off one of our new <em>GrabQTImageOperation</em> objects to grab the image at the <em>currentTime</em>. Once we hand the image operation off to the <em>NSOperationQueue</em> we can watch the specified folder in the Finder and images will start to display.</p>

<p>To see the application run, click <strong>Build and Go</strong></p>

<h2>Conclusion</h2>

<p>Developing with <em>NSOperation</em> and <em>NSOperationQueue</em> is a very pleasant experience to me so far. This was a fun application to build and the results are quite pleasing. I was able to achieve all of my project requirements with very little effort. It&#8217;s a great addition to the toolset now available in OS X 10.5 Leopard.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cimgf.com/2008/02/23/nsoperation-example/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>
