title: How to extract pixel data for processing from CMSampleBuffer using Swift in iOS 9?
body: <p>I am writing an app in Swift which employs the Scandit barcode scanning SDK.  The SDK permits you to access camera frames directly and provides the frame as a CMSampleBuffer.  They provide documentation in Objective-C, which I am having trouble getting to work in Swift.  I do not know if the problem is in porting the code, or if there is something amiss with the sample buffer itself, perhaps due to a change in Core Media since their documentation was generated.</p>
  
  <p>Their API exposes the frame as follows (Objective-C):</p>
  
  <pre><code>interface YourViewController () &lt;SBSProcessFrameDelegate&gt;
  ...
  - (void)barcodePicker:(SBSBarcodePicker*)barcodePicker
        didProcessFrame:(CMSampleBufferRef)frame
                session:(SBSScanSession*)session {
      // Process the frame yourself.
  }
  </code></pre>
  
  <p>Building from several answers here on SO, I attempt to process the frame with:</p>
  
  <pre><code>let imageBuffer = CMSampleBufferGetImageBuffer(frame)!
  CVPixelBufferLockBaseAddress(imageBuffer, 0)
  let baseAddress = CVPixelBufferGetBaseAddress(imageBuffer)
  
  let width = CVPixelBufferGetWidth(imageBuffer)
  let height = CVPixelBufferGetHeight(imageBuffer)
  let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer)
  
  let colorSpace = CGColorSpaceCreateDeviceRGB()
  let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.NoneSkipFirst.rawValue | CGBitmapInfo.ByteOrder32Little.rawValue)
  let context = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, bitmapInfo.rawValue)
  
  let quartzImage = CGBitmapContextCreateImage(context)
  CVPixelBufferUnlockBaseAddress(imageBuffer,0)
  
  let image = UIImage(CGImage: quartzImage!)
  </code></pre>
  
  <p>But, this fails with:</p>
  
  <pre><code>Jan 29 09:01:30  Scandit[1308] &lt;Error&gt;: CGBitmapContextCreate: invalid data bytes/row: should be at least 7680 for 8 integer bits/component, 3 components, kCGImageAlphaNoneSkipFirst.
  Jan 29 09:01:30  Scandit[1308] &lt;Error&gt;: CGBitmapContextCreateImage: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
  fatal error: unexpectedly found nil while unwrapping an Optional value
  </code></pre>
  
  <p>The fatal error is in attempting to resolve a UIImage from <code>quartzImage</code>.</p>
  
  <p>The width, height, and bytesPerRow are (at the base address):</p>
  
  <pre><code>Width: 1920
  Height: 1080
  Bytes per row: 2904
  </code></pre>
  
  <p>As passed from the delegate, here is what the buffer contains according to <code>CMSampleBufferGetFormatDescription(frame)</code>:</p>
  
  <pre><code>Optional(&lt;CMVideoFormatDescription 0x1447dafa0 [0x1a1864b68]&gt; {
      mediaType:'vide' 
      mediaSubType:'420f' 
      mediaSpecific: {
          codecType: '420f'       dimensions: 1920 x 1080 
      } 
      extensions: {&lt;CFBasicHash 0x1447dba10 [0x1a1864b68]&gt;{type = immutable dict, count = 6,
  entries =&gt;
      0 : &lt;CFString 0x19d28b678 [0x1a1864b68]&gt;{contents = "CVImageBufferYCbCrMatrix"} = &lt;CFString 0x19d28b6b8 [0x1a1864b68]&gt;{contents = "ITU_R_601_4"}
      1 : &lt;CFString 0x19d28b7d8 [0x1a1864b68]&gt;{contents = "CVImageBufferTransferFunction"} = &lt;CFString 0x19d28b698 [0x1a1864b68]&gt;{contents = "ITU_R_709_2"}
      2 : &lt;CFString 0x19d2b65c0 [0x1a1864b68]&gt;{contents = "CVBytesPerRow"} = &lt;CFNumber 0xb00000000000b582 [0x1a1864b68]&gt;{value = +2904, type = kCFNumberSInt32Type}
      3 : &lt;CFString 0x19d2b6640 [0x1a1864b68]&gt;{contents = "Version"} = &lt;CFNumber 0xb000000000000022 [0x1a1864b68]&gt;{value = +2, type = kCFNumberSInt32Type}
      5 : &lt;CFString 0x19d28b758 [0x1a1864b68]&gt;{contents = "CVImageBufferColorPrimaries"} = &lt;CFString 0x19d28b698 [0x1a1864b68]&gt;{contents = "ITU_R_709_2"}
      6 : &lt;CFString 0x19d28b818 [0x1a1864b68]&gt;{contents = "CVImageBufferChromaLocationTopField"} = &lt;CFString 0x19d28b878 [0x1a1864b68]&gt;{contents = "Center"}
  }
  }
  })
  </code></pre>
  
  <p>I realize there may be multiple "planes" here, but even with:</p>
  
  <pre><code>let pixelBufferBytesPerRow0 = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0)
  let pixelBufferBytesPerRow1 = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 1)
  </code></pre>
  
  <p>Gives:</p>
  
  <pre><code>Pixel buffer bytes per row (Plane 0): 1920
  Pixel buffer bytes per row (Plane 1): 1920
  </code></pre>
  
  <p>I don't understand that discrepancy.</p>
  
  <p>I also attempted to process each pixel individually as it is clear the buffer contains some manner of YCbCr, but it fails every way I have tried.  The Scandit API suggest (Objective-C):</p>
  
  <pre><code>// Get the buffer info for the YCbCrBiPlanar format.
  void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
  CVPlanarPixelBufferInfo_YCbCrBiPlanar *bufferInfo = (CVPlanarPixelBufferInfo_YCbCrBiPlanar *)baseAddress;
  </code></pre>
  
  <p>But, I cannot find a Swift implementation that permits access to the buffer info using CVPlanarPixelBufferInfo... everything I have tried fails, so I am unable to determine the offset for "Y", "Cr", etc.</p>
  
  <p>How can I access the pixel data in the buffer?  Is this a problem with the CMSampleBuffer the SDK is passing, a problem with iOS9, or both?</p>