title: Rendering a video in a CALayer hierarchy using CIFilters
body: <p>In the UI of my iOS app, I display a complex hierarchy of <code>CALayer</code>s. One of these layers is a <code>AVPlayerLayer</code> that displays a video with <code>CIFilter</code>s applied in real time (using <code>AVVideoComposition(asset:, applyingCIFiltersWithHandler:)</code>).</p>
  
  <p>Now I want to export this layer composition to a video file. There are two tools in <code>AVFoundation</code> that seem helpful: </p>
  
  <p><strong>A</strong>: <code>AVVideoCompositionCoreAnimationTool</code> which allows rendering a video inside a (possibly animated) <code>CALayer</code> hierarchy</p>
  
  <p><strong>B</strong>: <code>AVVideoComposition(asset:, applyingCIFiltersWithHandler:)</code>, which I also use in the UI, to apply <code>CIFilter</code>s to a video asset.</p>
  
  <p>However, these two tools cannot be used simultaneously: If I start an <code>AVAssetExportSession</code> that combines these tools, <code>AVFoundation</code> throws an <code>NSInvalidArgumentException</code>:</p>
  
  <blockquote>
    <p>Expecting video composition to contain only <code>AVCoreImageFilterVideoCompositionInstruction</code></p>
  </blockquote>
  
  <p>I tried to workaround this limitation as follows:</p>
  
  <p><strong>Workaround 1</strong></p>
  
  <p>1) Setup an export using <code>AVAssetReader</code> and <code>AVAssetWriter</code></p>
  
  <p>2) Obtain the sample buffers from the asset reader and apply the <code>CIFilter</code>, save the result in a <code>CGImage</code>.</p>
  
  <p>3) Set the <code>CGImage</code> as the <code>content</code> of the video layer in the layer hierarchy. Now the layer hierarchy "looks like" one frame of the final video.</p>
  
  <p>4) Obtain the data of the <code>CVPixelBuffer</code> for each frame from the asset writer using <code>CVPixelBufferGetBaseAddress</code> and create a <code>CGContext</code> with that data.</p>
  
  <p>5) Render my layer to that context using <code>CALayer.render(in ctx: CGContext)</code>.</p>
  
  <p>This setup works, but is extremely slow - exporting a 5 second video sometimes takes a minute. It looks like the <code>CoreGraphics</code> calls are the bottleneck here (I guess that's because with this approach the composition happens on the CPU?)</p>
  
  <p><strong>Workaround 2</strong></p>
  
  <p>One other approach could be to do this in two steps: First, save the source video just with the filters applied to a file as in <strong>B</strong>, and then use that video file to embed the video in the layer composition as in <strong>A</strong>. However, as it uses two passes, I guess this isn't as efficient as it could be.</p>
  
  <p><strong>Summary</strong></p>
  
  <p>What is a good approach to export this video to a file, ideally in a single pass? How can I use <code>CIFilter</code>s and <code>AVVideoCompositionCoreAnimationTool</code> simultaneously? Is there a native way to set up a "pipeline" in <code>AVFoundation</code> which combines these tools?</p>