<?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; Frameworks</title>
	<atom:link href="http://www.cimgf.com/category/frameworks/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>Cocoa Tutorial: Adding Plugins to a Cocoa Application</title>
		<link>http://www.cimgf.com/2008/09/17/cocoa-tutorial-adding-plugins-to-a-cocoa-application/</link>
		<comments>http://www.cimgf.com/2008/09/17/cocoa-tutorial-adding-plugins-to-a-cocoa-application/#comments</comments>
		<pubDate>Wed, 17 Sep 2008 17:45:11 +0000</pubDate>
		<dc:creator>Marcus Zarra</dc:creator>
				<category><![CDATA[Advanced]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Frameworks]]></category>
		<category><![CDATA[Objective-C]]></category>

		<guid isPermaLink="false">http://www.cimgf.com/?p=272</guid>
		<description><![CDATA[A couple of weeks ago we discussed how to build frameworks and how to bundle them with a Cocoa application. This week we are going to build on that knowledge and add Plug-ins to a Cocoa application. Why are these topics linked? Generally, there are a few ways to add plug-ins to a Cocoa application. [...]]]></description>
			<content:encoded><![CDATA[<p>A couple of weeks ago we discussed <a href="http://www.cimgf.com/2008/09/04/cocoa-tutorial-creating-your-very-own-framework/">how to build frameworks and how to bundle them with a Cocoa application</a>.  This week we are going to build on that knowledge and add Plug-ins to a Cocoa application.</p>

<p><span id="more-272"></span></p>

<h2>Why are these topics linked?</h2>

<p>Generally, there are a few ways to add plug-ins to a Cocoa application.</p>

<h3>Scriptable plug-ins</h3>

<p>Scriptable plug-ins are probably the easiest to add to an application.  They exist in a known location where the application can load them and run them in the appropriate virtual machine.  This makes them fairly easy to construct even though the code to run them may be rather complicated.</p>

<h3>Publishing a Formal Protocol Plug-ins Interface</h3>

<p>This one is a bit more complicated.  The developer (you and me) publish a formal protocol that the plug-ins must adhere to.  This design works rather well but does not allow us, the application developer, to impart any functionality to the plug-ins easily.</p>

<h3>Publishing an Informal Protocol Plug-ins Interface</h3>

<p>This is very similar to the formal plug-ins above but a little more tricky.  Since the protocol is informal, we have to test for each method that we want to use in the plug-ins before we can use it.  Again, it does not make it very easy for us to impart functionality to the plug-ins.</p>

<h3>Publishing a Base Class Plug-ins Interface</h3>

<p>This is the hardest option I have found so far.  Not only do we have to give our plug-ins developers a header file but something to actually compile against.  However, with a base class we can easily impart functionality to our plug-ins without the plug-ins developer having to jump through <em>too many</em> hoops.</p>

<p>Creating a base class solution is where frameworks come in.  It makes it fairly trivial to hand off a base class to plug-ins developers when we give them a framework.  Therefore, we are going to add one class to the plug-ins we wrote previously with the following header:</p>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #6e371a;">#import &lt;Cocoa/Cocoa.h&gt;</span>
&nbsp;
<span style="color: #a61390;">@interface</span> AbstractPlugin <span style="color: #002200;">:</span> <span style="color: #400080;">NSObject</span> 
<span style="color: #002200;">&#123;</span>
&nbsp;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>name;
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>fire<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></div></div>


<p>And since I like to make it stupidly easy for people, we are going to use the following implementation of the base &#8220;abstract&#8221; class:</p>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #6e371a;">#import &quot;AbstractPlugin.h&quot;</span>
&nbsp;
<span style="color: #6e371a;">#define kErrFormat @&quot;%s not implemented in subclass %@&quot;</span>
<span style="color: #6e371a;">#define kExceptName @&quot;CIMGF&quot;</span>
&nbsp;
<span style="color: #a61390;">@implementation</span> AbstractPlugin
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>name;
<span style="color: #002200;">&#123;</span>
  <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>reason <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSString</span> stringWithFormat<span style="color: #002200;">:</span>kErrFormat, 
    _cmd, <span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
  <span style="color: #a61390;">@throw</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSException</span> exceptionWithName<span style="color: #002200;">:</span>kExceptName 
                                 reason<span style="color: #002200;">:</span>reason 
                               userInfo<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;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>fire<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> reason <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSString</span> stringWithFormat<span style="color: #002200;">:</span>kErrFormat, 
    _cmd, <span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
  <span style="color: #a61390;">@throw</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSException</span> exceptionWithName<span style="color: #002200;">:</span>kExceptName 
                                 reason<span style="color: #002200;">:</span>reason 
                               userInfo<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: #a61390;">@end</span></pre></div></div>


<p>For every method that the subclass <strong>must</strong> override the abstract class will throw an exception if it is not overwritten with a polite message explaining what method in which class is missing.</p>

<h2>Building the plug-ins</h2>

<p>A plug-ins is effectively just a bundle, like a framework or an application.  Inside of the bundle is a Contents directory, MacOS directory (where the binary goes) and a Resources directory.</p>

<div style="text-align:center;">

<a href="http://www.cimgf.com/wp-content/uploads/2008/09/bundlestructure.png" rel="lightbox" title="Bundle Structure">

<img src="http://www.cimgf.com/wp-content/uploads/2008/09/bundlestructure.png" width="50%" alt="Bundle Structure"/>

</a>
</div>

<p>Xcode has a template for building plug-ins that we can use to get started.  For this first plug-ins, we are going to just add it to our existing project as a new target.</p>

<div style="text-align:center;">

<a href="http://www.cimgf.com/wp-content/uploads/2008/09/newproject.png" rel="lightbox" title="New Bundle Project">

<img src="http://www.cimgf.com/wp-content/uploads/2008/09/newproject.png" width="50%" alt="New Bundle Project"/>

</a>
</div>

<p>This new target is very similar to the Framework target that we built previously.  We want to drag it up into the Application&#8217;s target so that it is a dependency; this can also be done from the Get Info window.  We will also want to add the Framework product as a linked framework in the plug-ins.  The end result looks like this.</p>

<div style="text-align:center;">

<a href="http://www.cimgf.com/wp-content/uploads/2008/09/targetstructure.png" rel="lightbox" title="Target Structure">

<img src="http://www.cimgf.com/wp-content/uploads/2008/09/targetstructure.png" width="50%" alt="Target Structure"/>

</a>
</div>

<p>Once we have the target set up, it is time to add some code.  Plug-ins needs to have either a main class defined or a main nib defined.  It is this definition that helps determine how to launch the bundle.  In our case, we will want to define a main class which will be explained below.  To define a main class (or nib), we need to look at the properties tab of the target.</p>

<div style="text-align:center;">

<a href="http://www.cimgf.com/wp-content/uploads/2008/09/propertiestab.png" rel="lightbox" title="Properties Tab">

<img src="http://www.cimgf.com/wp-content/uploads/2008/09/propertiestab.png" width="50%" alt="Properties Tab"/>

</a>
</div>

<p>The next step is to create the main class for our plug-ins.  Since we are using a base class design for our plug-ins, our main class must extend the AbstractPlugin class and it needs to import the framework directly in the header.  For our example, our plug-ins is going to display a new window on the screen, therefore the header must also include a NSWindow attribute and since we want to programmatically close the window, a -closeWindow: IBAction.</p>


<div class="wp_syntax"><div 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;Example/Example.h&gt;</span>
&nbsp;
<span style="color: #a61390;">@interface</span> PluginMainClass <span style="color: #002200;">:</span> AbstractPlugin 
<span style="color: #002200;">&#123;</span>
  IBOutlet <span style="color: #400080;">NSWindow</span> <span style="color: #002200;">*</span>mainWindow;
<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>closeWindow<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></div></div>


<p>Note that we are importing the framework which contains the AbstractPlugin super class we built earlier.</p>

<p>Once we have the main class defined it is time to build the user interface to go along with this plug-ins.  It is not a requirement that plug-ins have a user interface, they can be pure code instead.  However for the sake of completeness, we are going to add one for this example.</p>

<div style="text-align:center;">

<a href="http://www.cimgf.com/wp-content/uploads/2008/09/pluginwindowstructure.png" rel="lightbox" title="Plug-ins Window Structure">

<img src="http://www.cimgf.com/wp-content/uploads/2008/09/pluginwindowstructure.png" width="50%" alt="Plug-ins Window Structure"/>

</a>
</div>

<p>The structure of the plug-ins nib is simple.  The file owner is the PluginMainClass we wrote previously and there is one window which we bind to the file owner.</p>

<div style="text-align:center;">

<a href="http://www.cimgf.com/wp-content/uploads/2008/09/pluginwindow.png" rel="lightbox" title="Plug-ins Window">

<img src="http://www.cimgf.com/wp-content/uploads/2008/09/pluginwindow.png" width="50%" alt="Plug-ins Window"/>

</a>
</div>

<p>The window is also equally simple, just one button that binds back to the file owner&#8217;s -closeWindow: method.</p>

<p>The last step is to add a copy phase to our application.  Like the framework copy phase we built last time, this is a &#8220;Copy Files&#8221; build phase and we need to configure it to copy files to the &#8220;PlugIns&#8221; directory.  This is another top level directory next to Resources and Frameworks.  Once the build phase is added, drag the plug-ins product into that build phase.</p>

<p>With the window and the main class built we can compile the plug-ins and make sure everything is ready for inclusion into our application.  Once the app is built, we should see a copy of the plug-ins inside of the application bundle.  Now it is time to dynamically load the bundle.</p>

<p>The flow of loading bundles dynamically is as follows:</p>

<ol>
  <li>Find the paths of the bundles.</li>
  <li>Instantiate NSBundle objects for the paths.</li>
  <li>Execute the -load method on the bundle.</li>
  <li>Retrieve the principal class from the bundle.</li>
  <li>Instantiate an object from the principal class.</li>
</ol>

<p>And the code for this is as follows:</p>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #400080;">NSArray</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>loadPlugins
<span style="color: #002200;">&#123;</span>
  <span style="color: #400080;">NSBundle</span> <span style="color: #002200;">*</span>main <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSBundle</span> mainBundle<span style="color: #002200;">&#93;</span>;
  <span style="color: #400080;">NSArray</span> <span style="color: #002200;">*</span>all <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>main pathsForResourcesOfType<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;bundle&quot;</span> 
                                   inDirectory<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;../PlugIns&quot;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
&nbsp;
  <span style="color: #400080;">NSMutableArray</span> <span style="color: #002200;">*</span>availablePlugins <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSMutableArray</span> array<span style="color: #002200;">&#93;</span>;
&nbsp;
  <span style="color: #a61390;">id</span> plugin <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
  <span style="color: #400080;">NSBundle</span> <span style="color: #002200;">*</span>pluginBundle <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
&nbsp;
  <span style="color: #a61390;">for</span> <span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>path <span style="color: #a61390;">in</span> all<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
    pluginBundle <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSBundle</span> bundleWithPath<span style="color: #002200;">:</span>path<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>pluginBundle load<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #a61390;">Class</span> prinClass <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>pluginBundle principalClass<span style="color: #002200;">&#93;</span>;
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">!</span><span style="color: #002200;">&#91;</span>prinClass isSubclassOfClass<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>AbstractPlugin class<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
      <span style="color: #a61390;">continue</span>;
    <span style="color: #002200;">&#125;</span>
&nbsp;
    plugin <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>prinClass alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>availablePlugins addObject<span style="color: #002200;">:</span>plugin<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>plugin release<span style="color: #002200;">&#93;</span>, plugin <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
    pluginBundle <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
  <span style="color: #002200;">&#125;</span>
  <span style="color: #a61390;">return</span> availablePlugins;
<span style="color: #002200;">&#125;</span></pre></div></div>


<p>In this new method that we have added to the AppDelegate we first get a reference to the main bundle and we then request a path for every file in the PlugIns directory that has an extension of bundle.  With that array in hand we then start to loop over the array and construct a new NSBundle for each path.  Once the bundle is constructed we ask for it to load.  After the load, we grab its principal class, check to make sure we can use it, and construct an object from it.</p>

<p>Since we want to have a list of the loaded plug-ins, we throw this new object into an array that will be returned back from the method.  Once this method is complete we now have every plug-ins dynamically loaded and ready to use.  So lets use them!</p>

<p>We really want to call this method before the application has finished loading, therefore we need to add an -init method to our AppDelegate and load the plug-ins there.  This will guarantee that they are loaded before the UI with some obvious benefits.</p>


<div class="wp_syntax"><div 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>
  <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">!</span><span style="color: #002200;">&#91;</span>super init<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #a61390;">return</span> <span style="color: #a61390;">nil</span>;
&nbsp;
  <span style="color: #002200;">&#91;</span>self setPlugins<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>self loadPlugins<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
&nbsp;
  <span style="color: #a61390;">return</span> self;
<span style="color: #002200;">&#125;</span></pre></div></div>


<p>Here are we calling our new -loadPlugins method and setting the returned array into a ivar.  This ivar will then be used by our UI once it loads to display a list of the plug-ins.</p>

<div style="text-align:center;">

<a href="http://www.cimgf.com/wp-content/uploads/2008/09/mainappwindow.png" rel="lightbox" title="Main Application Window">

<img src="http://www.cimgf.com/wp-content/uploads/2008/09/mainappwindow.png" width="50%" alt="Main Application Window"/>

</a>
</div>

<p>The main window has a pop up button with a list of the plug-ins using their inherited -name method for display.  When the run button is clicked, our application will find out which plug-ins were selected via the NSArrayController and call the inherited -run: method on the plug-ins with predictable results.</p>

<h2>Conclusion</h2>

<p>For clarity we did leave a few things out of this project.  For example, there is no code for unloading the plug-ins nor do we search the Application Support directory for user added plug-ins.  However these are easy to add based on the code that was included.</p>

<p>I should also note that we used the default extension for these plug-ins.  I would recommend changing this extension to something unique to your application and add that extension (or UTI) to your main application as an accepted file type.  See previous articles here on CIMGF to see how to do each of those.</p>

<p><center><a href="http://www.cimgf.com/wp-content/uploads/2008/09/frameworks.zip" title="Example Project"><img src="http://www.cimgf.com/wp-content/uploads/2008/03/xcode.png" alt="xcode.png" border="0" width="64"/><br/>Example Project</a></center></p>
]]></content:encoded>
			<wfw:commentRss>http://www.cimgf.com/2008/09/17/cocoa-tutorial-adding-plugins-to-a-cocoa-application/feed/</wfw:commentRss>
		<slash:comments>1</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: libxml and xmlreader</title>
		<link>http://www.cimgf.com/2008/08/18/cocoa-tutorial-libxml-and-xmlreader/</link>
		<comments>http://www.cimgf.com/2008/08/18/cocoa-tutorial-libxml-and-xmlreader/#comments</comments>
		<pubDate>Tue, 19 Aug 2008 01:49:24 +0000</pubDate>
		<dc:creator>Marcus Zarra</dc:creator>
				<category><![CDATA[Advanced]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Frameworks]]></category>
		<category><![CDATA[Objective-C]]></category>

		<guid isPermaLink="false">http://www.cimgf.com/?p=198</guid>
		<description><![CDATA[Let us pretend for a moment that NSXMLDocument was not available to your Cocoa application for some reason. Perhaps you have low memory requirements, perhaps you are running on a slimmed down version of OS X. Whatever the reason, for the purposes of this exercise, NSXMLDocument does not exist. Let us now assume that we [...]]]></description>
			<content:encoded><![CDATA[<p>Let us pretend for a moment that NSXMLDocument was not available to your Cocoa application for some reason. Perhaps you have low memory requirements, perhaps you are running on a slimmed down version of OS X.  Whatever the reason, for the purposes of this exercise, NSXMLDocument does not exist.</p>

<p>Let us now assume that we have a requirement to parse an xml document quickly and without loading the entire tree into memory in a object structure.  In a situation like this libxml comes in handy.  Unfortunately it is quite a bit more complicated than calling alloc init on NSXMLDocument.</p>

<p>libxml is a C library that is included with all current releases of OS X.  With this library we can quickly read in a document, scrape the information we need out of that document and avoid loading the entire tree into memory at once.  In addition, libxml (and more specifically xmlReader) does this very quickly, far faster than NSXMLDocument which is very useful when you have a lower end CPU.  In this project we are going to create a simple application that reads in an xml file containing a list of people, their names and their ages.  For the purposes of demonstration we are going to load that data into an array of NSDictionary objects and display it in a standard Cocoa window.</p>

<p><span id="more-198"></span></p>

<p>The raw XML file looks like this:</p>


<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;root<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;person<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>John Doe<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;age<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>14<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/age<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/person<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;person<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Mary Doe<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;age<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>14<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/age<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/person<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;person<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>John Smith<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;age<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>14<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/age<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/person<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/root<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>


<p>Besides being a C library, another difference in the way that we are going to read in this xml file is that the reading is iterative.  For each element in the xml file we will be looping over the reader.  Therefore, unlike our old friend NSXMLDocument, we will have to actually walk the file one element at a time and evaluate those elements as we receive them.  In the xml file listed above, we would first read in the opening root tag, then the opening person tag, the opening name tag, the first name, etc. until we were done with the file.</p>

<p>To accomplish our goal, I created a new Xcode project which can be downloaded below.  In this Xcode project, I added the libxml &#8220;framework&#8221; to the project by right clicking on the target, clicking on the add button, narrowing the focus to libraries and selecting the libxml2.dylib file.</p>

<p><a href='http://www.cimgf.com/wp-content/uploads/2008/08/addlibxml2.tif' rel='lightbox'><img src="http://www.cimgf.com/wp-content/uploads/2008/08/addlibxml2.tif" alt="Addlibxml2.tif" border="0" width="25%"/></a></p>

<p>This will link libxml to our project at compile time.  However, unlike an Objective-C framework, we do not get access to its headers for free.  Therefore the next step is to add the header to our search path.  To do so, open the target&#8217;s properties and select the build tab.  Narrow its focus to &#8220;header&#8221; and select the header search path entry.</p>

<p><a href='http://www.cimgf.com/wp-content/uploads/2008/08/addheadersearchpath.tif' rel='lightbox'><img src="http://www.cimgf.com/wp-content/uploads/2008/08/addheadersearchpath.tif" alt="AddHeaderSearchPath.tif" border="0" width="25%"/></a></p>

<p>Double click on this row and add /usr/include/libxml to the list of paths.  NOTE: Some people have had issues with this path and if you do then you will need to find another copy of these headers in your Xcode installation directory.</p>

<p><a href='http://www.cimgf.com/wp-content/uploads/2008/08/thepathtoadd.tif' rel='lightbox'><img src="http://www.cimgf.com/wp-content/uploads/2008/08/thepathtoadd.tif" alt="ThePathToAdd.tif" border="0" width="25%"/></a></p>

<p>Once this is done, we will be able to compile against this library with no errors or warnings.  Next, after we add an application delegate and wire it up in our xib file, we need to import libxml in our AppDelegate.h.  While we are in here we are going to add a reference for our records array that we will be loading the data into.</p>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #6e371a;">#import &lt;Cocoa/Cocoa.h&gt;</span>
<span style="color: #6e371a;">#include &lt;libxml/xmlreader.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>
  <span style="color: #400080;">NSArray</span> <span style="color: #002200;">*</span>_records;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@property</span> <span style="color: #002200;">&#40;</span>retain<span style="color: #002200;">&#41;</span> <span style="color: #400080;">NSArray</span> <span style="color: #002200;">*</span>records;
&nbsp;
<span style="color: #a61390;">@end</span></pre></div></div>


<p>Since xmlReader is so quick, our data set is so small and this is a demonstration only, we are going to read the xml file directly as the application starts.  <strong>BE WARNED:</strong> for a production application <strong><emph>THIS IS A BAD IDEA</emph></strong><sup>tm</sup>.  Fortunately I can get away with a lot in demos. :-)</p>

<p>The first thing we need to do in the -applicationDidFinishLaunching: method is to load the xml data and initialize the xml reader.</p>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;">  <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>path <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSBundle</span> mainBundle<span style="color: #002200;">&#93;</span> pathForResource<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;xmlExample&quot;</span> ofType<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;xml&quot;</span><span style="color: #002200;">&#93;</span>;
  <span style="color: #400080;">NSData</span> <span style="color: #002200;">*</span>xmlData <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSData</span> dataWithContentsOfFile<span style="color: #002200;">:</span>path<span style="color: #002200;">&#93;</span>;
  xmlTextReaderPtr reader <span style="color: #002200;">=</span> xmlReaderForMemory<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>xmlData bytes<span style="color: #002200;">&#93;</span>, 
                                               <span style="color: #002200;">&#91;</span>xmlData length<span style="color: #002200;">&#93;</span>, 
                                               <span style="color: #002200;">&#91;</span>path UTF8String<span style="color: #002200;">&#93;</span>, <span style="color: #a61390;">nil</span>, 
    <span style="color: #002200;">&#40;</span>XML_PARSE_NOBLANKS | XML_PARSE_NOCDATA | XML_PARSE_NOERROR | XML_PARSE_NOWARNING<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
  <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">!</span>reader<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 load xmlreader&quot;</span><span style="color: #002200;">&#41;</span>;
    <span style="color: #a61390;">return</span>;
  <span style="color: #002200;">&#125;</span></pre></div></div>


<p>In this section, again for demonstration purposes, we are reading in the included xml file into an NSData object.  Normally we would be retrieving this data from an NSURLConnection or some other external source.  Once the data is loaded, we pass the raw bytes off to the C function xmlReaderForMemory().  This function will return a pointer reference to our xmlReader.  This reader is now ready to walk, one way and one time, through our xml file.  Now we need to declare some local variables to store our state information while we walk the xml file.</p>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;">  <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>currentTagName <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
  <span style="color: #400080;">NSDictionary</span> <span style="color: #002200;">*</span>currentPerson <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
  <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>currentTagValue <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
  <span style="color: #400080;">NSMutableArray</span> <span style="color: #002200;">*</span>people <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSMutableArray</span> array<span style="color: #002200;">&#93;</span>;
  <span style="color: #a61390;">while</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">true</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">!</span>xmlTextReaderRead<span style="color: #002200;">&#40;</span>reader<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span> <span style="color: #a61390;">break</span>;
    <span style="color: #a61390;">switch</span> <span style="color: #002200;">&#40;</span>xmlTextReaderNodeType<span style="color: #002200;">&#40;</span>reader<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span></pre></div></div>


<p>Since this xml file is very simple we do not need to hold onto a lot of state information.  Basically when we hit a person tag we will create a new person dictionary and then every time we hit a text node we will store that text node&#8217;s value into the dictionary along with the tag name.  Finally we will store each of those person dictionaries into an array.</p>

<p>Once our variables are declared and initialized it is time to start walking the xml file.  Since we do not know how long it is going to be we will simply loop until we hit the end.  Therefore we have a while(true) to start the loop.  The first thing we do inside of the loop is to tell the reader to read the next element.  If that returns back a 0 we are done with the file and break.  If it returns back a positive value then we know the reader has advanced to the next node.  Since the node types are stored as integer values, we can use a switch statement to quickly sort them as we are looping.  The xmlTextReaderNodeType() function will return that type integer.</p>

<p>For our purposes, we really only care about two of the node types, opening tags and text values.  For a more complex xml file we would watch for more information but fortunately we are working in a controlled environment.  The tags we are going to watch for are XML_READER_TYPE_ELEMENT and XML_READER_TYPE_TEXT.</p>

<p>When we hit an element we will grab its name, store it temporarily and check to see if it is a person, if it isn&#8217;t then we loop.  If it is then we create a person and add it to our array.</p>

<p>When we hit a text node then we want to stick it in the current person object.  Since we previously stored the name of this element (remember, an element and its text value are two separate nodes), we can grab the value of the text and store it in the dictionary.</p>

<p>Any other type of node is ignored and we continue on the default: tag of the switch.</p>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">case</span> XML_READER_TYPE_ELEMENT<span style="color: #002200;">:</span>
  <span style="color: #11740a; font-style: italic;">//We are starting an element</span>
  temp <span style="color: #002200;">=</span>  <span style="color: #002200;">&#40;</span><span style="color: #a61390;">char</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>xmlTextReaderConstName<span style="color: #002200;">&#40;</span>reader<span style="color: #002200;">&#41;</span>;
  currentTagName <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSString</span> stringWithCString<span style="color: #002200;">:</span>temp 
                                      encoding<span style="color: #002200;">:</span>NSUTF8StringEncoding<span style="color: #002200;">&#93;</span>;
  <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>currentTagName isEqualToString<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;person&quot;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
    currentPerson <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSMutableDictionary</span> dictionary<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>people addObject<span style="color: #002200;">:</span>currentPerson<span style="color: #002200;">&#93;</span>;
  <span style="color: #002200;">&#125;</span> 
  <span style="color: #a61390;">continue</span>;
<span style="color: #a61390;">case</span> XML_READER_TYPE_TEXT<span style="color: #002200;">:</span>
  <span style="color: #11740a; font-style: italic;">//The current tag has a text value, stick it into the current person</span>
  temp <span style="color: #002200;">=</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">char</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>xmlTextReaderConstValue<span style="color: #002200;">&#40;</span>reader<span style="color: #002200;">&#41;</span>;
  currentTagValue <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSString</span> stringWithCString<span style="color: #002200;">:</span>temp 
                                       encoding<span style="color: #002200;">:</span>NSUTF8StringEncoding<span style="color: #002200;">&#93;</span>;
  <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">!</span>currentPerson<span style="color: #002200;">&#41;</span> <span style="color: #a61390;">return</span>;
  <span style="color: #002200;">&#91;</span>currentPerson setValue<span style="color: #002200;">:</span>currentTagValue forKey<span style="color: #002200;">:</span>currentTagName<span style="color: #002200;">&#93;</span>;
  currentTagValue <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
  currentTagName <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
<span style="color: #a61390;">default</span><span style="color: #002200;">:</span> <span style="color: #a61390;">continue</span>;</pre></div></div>


<p><a href='http://www.cimgf.com/wp-content/uploads/2008/08/finalwindow.tif' rel='lightbox'><img src="http://www.cimgf.com/wp-content/uploads/2008/08/finalwindow.tif" alt="FinalWindow.tif" border="0" width="25%" style="float:right;padding: 2px 2px 2px 2px;"/></a>Since we check for the completion of the file a the beginning of the loop that is all that we need to do for this example.  Once the while loop exits we pass the array to -setRecords: and we are done.  Cocoa bindings will take care of the rest for us.</p>

<p><a href="http://www.cimgf.com/wp-content/uploads/2008/08/xmlreaderexample.zip" title="XMLReaderExample.zip"><img src="http://www.cimgf.com/wp-content/uploads/2008/03/xcode.png" alt="xcode.png" border="0" width="64"/><br/>NSError Tutorial</a></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.cimgf.com/2008/08/18/cocoa-tutorial-libxml-and-xmlreader/feed/</wfw:commentRss>
		<slash:comments>7</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>
