2016-01-30 2 views
2

Я создаю UIImage из CMSampleBuffer. Из основного потока я вызываю функцию для доступа к данным пикселя в CMSampleBuffer и преобразовываю плоскости YCbCr в растровое изображение ABGR, которое я обертываю в UIImage. Я вызвать функцию из основного потока с:UIImage, построенный из CMSampleBuffer, не сохраняется и вызывает EXC_BAD_ACCESS

let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT 
    dispatch_async(dispatch_get_global_queue(priority, 0), {() -> Void in 
    let image = self.imageFromSampleBuffer(frame) 
    dispatch_async(dispatch_get_main_queue(), {() -> Void in 
     self.testView.image = image 
     self.testView.hidden = false 
    }) 
}) 

Это обеспечивает отзывчивость интерфейса и основного потока, как хотелось бы надеяться. Функция обработки буфера является:

func imageFromSampleBuffer(sampleBuffer: CMSampleBuffer) -> UIImage { 

    let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)! 
    CVPixelBufferLockBaseAddress(pixelBuffer, 0) 
    let lumaBaseAddress = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0) 
    let chromaBaseAddress = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1) 

    let width = CVPixelBufferGetWidth(pixelBuffer) 
    let height = CVPixelBufferGetHeight(pixelBuffer) 

    let lumaBytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0) 
    let chromaBytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1) 
    let lumaBuffer = UnsafeMutablePointer<UInt8>(lumaBaseAddress) 
    let chromaBuffer = UnsafeMutablePointer<UInt8>(chromaBaseAddress) 

    var rgbaImage = [UInt8](count: 4*width*height, repeatedValue: 0) 
    for var x = 0; x < width; x++ { 
     for var y = 0; y < height; y++ { 
      let lumaIndex = x+y*lumaBytesPerRow 
      let chromaIndex = (y/2)*chromaBytesPerRow+(x/2)*2 
      let yp = lumaBuffer[lumaIndex] 
      let cb = chromaBuffer[chromaIndex] 
      let cr = chromaBuffer[chromaIndex+1] 

      let ri = Double(yp)        + 1.402 * (Double(cr) - 128) 
      let gi = Double(yp) - 0.34414 * (Double(cb) - 128) - 0.71414 * (Double(cr) - 128) 
      let bi = Double(yp) + 1.772 * (Double(cb) - 128) 

      let r = UInt8(min(max(ri,0), 255)) 
      let g = UInt8(min(max(gi,0), 255)) 
      let b = UInt8(min(max(bi,0), 255)) 
      rgbaImage[(x + y * width) * 4] = b 
      rgbaImage[(x + y * width) * 4 + 1] = g 
      rgbaImage[(x + y * width) * 4 + 2] = r 
      rgbaImage[(x + y * width) * 4 + 3] = 255 
     } 
    } 

    let colorSpace = CGColorSpaceCreateDeviceRGB() 
    let dataProvider: CGDataProviderRef = CGDataProviderCreateWithData(nil, rgbaImage, 4 * width * height, nil)! 
    let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.NoneSkipFirst.rawValue | CGBitmapInfo.ByteOrder32Little.rawValue) 
    let cgImage = CGImageCreate(width, height, 8, 32, width * 4, colorSpace!, bitmapInfo, dataProvider, nil, true, CGColorRenderingIntent.RenderingIntentDefault)! 
    let image = UIImage(CGImage: cgImage) 
    CVPixelBufferUnlockBaseAddress(pixelBuffer,0) 

    return image 
} 

Если я ставлю точку останова непосредственно перед функция возвращает, я могу использовать «Quick Look» и увидеть изображение (и это то, что я ожидал бы). Однако, как только функция вернется, я не могу использовать image где-нибудь еще, и Quick Look всегда терпит неудачу. Если я пытаюсь установить UIImageView возвращенному изображения, ничто в интерфейсе не изменится:

testView.image = image \\The UIImageView does not update. 

При попытке доступа к изображению любым другим способом (например, чтобы попытаться сохранить его в Разобрать), код сбой EXC_BAD_ACCESS. Опять же, если я сохраню изображение в Parse в указанной выше функции, он появится в бэкэнд-базе данных, как и ожидалось.

Я также попытался вызвать функцию обработки без отправки в глобальные и основные очереди, вызвав функцию напрямую. Результаты всегда одни и те же.

Я считаю, что это связано с тем, что изображение не сохраняется. Я попытался определить как изображение, так и контекст CGImage на уровне классов и файлов, но не изменил результат. Я думал, что это будет поддерживать ссылку, но, похоже, это не так. Я достаточно новый для Swift, что я, очевидно, не понимаю, как ARC работает в этом случае.

Я также считаю, что при отладке с помощью функции быстрого просмотра в течение нескольких раз, когда я впервые нажал кнопку быстрого просмотра, был «недоступен» ... но несколько секунд ожидания и щелчок снова приводит к появлению изображения , Возможно ли, что данные будут доступны только дольше? Возможно, GPU-> CPU? Если да, то как я могу проверить/задержать, чтобы избежать сбоя?

Как сохранить ссылку? Есть ли лучший способ обработки изображения, созданного с помощью CMSampleBuffer?

ответ

0

Проблема заключается в том, как создается CGImage. Использование dataProvider и CGImageCreate является конкретный вопрос:

let dataProvider = CGDataProviderCreateWithData(nil, rgbaImage, 4 * width * height, nil)! 
let cgImage = CGImageCreate(width, height, 8, 32, width * 4, colorSpace!, bitmapInfo, dataProvider, nil, true, CGColorRenderingIntent.RenderingIntentDefault)! 

Рабочий раствор с использованием CGBitmapContextGetData и CGBitmapContextCreateImage следующим образом:

func imageFromSampleBuffer(sampleBuffer: CMSampleBuffer) -> UIImage? { 

    let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)! 
    CVPixelBufferLockBaseAddress(pixelBuffer, 0) 
    let lumaBaseAddress = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0) 
    let chromaBaseAddress = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1) 

    let width = CVPixelBufferGetWidth(pixelBuffer) 
    let height = CVPixelBufferGetHeight(pixelBuffer) 

    let lumaBytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0) 
    let chromaBytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1) 
    let lumaBuffer = UnsafeMutablePointer<UInt8>(lumaBaseAddress) 
    let chromaBuffer = UnsafeMutablePointer<UInt8>(chromaBaseAddress) 

    let contextBytesPerRow = Int(width) * 4 
    let contextByteCount = contextBytesPerRow * Int(height) 
    let colorSpace = CGColorSpaceCreateDeviceRGB() 

    let bitmapData = malloc(contextByteCount) 
    let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedFirst.rawValue | CGBitmapInfo.ByteOrder32Little.rawValue) 

    let context = CGBitmapContextCreate(bitmapData, width, height, 8, contextBytesPerRow, colorSpace, bitmapInfo.rawValue) 

    let data = CGBitmapContextGetData(context) 
    let rgbaImage = UnsafeMutablePointer<UInt8>(data) 
    for var x = 0; x < width; x++ { 
     for var y = 0; y < height; y++ { 
      let lumaIndex = x+y*lumaBytesPerRow 
      let chromaIndex = (y/2)*chromaBytesPerRow+(x/2)*2 
      let yp = lumaBuffer[lumaIndex] 
      let cb = chromaBuffer[chromaIndex] 
      let cr = chromaBuffer[chromaIndex+1] 

      let ri = Double(yp)        + 1.402 * (Double(cr) - 128) 
      let gi = Double(yp) - 0.34414 * (Double(cb) - 128) - 0.71414 * (Double(cr) - 128) 
      let bi = Double(yp) + 1.772 * (Double(cb) - 128) 

      let r = UInt8(min(max(ri,0), 255)) 
      let g = UInt8(min(max(gi,0), 255)) 
      let b = UInt8(min(max(bi,0), 255)) 
      rgbaImage[(x + y * width) * 4] = b 
      rgbaImage[(x + y * width) * 4 + 1] = g 
      rgbaImage[(x + y * width) * 4 + 2] = r 
      rgbaImage[(x + y * width) * 4 + 3] = 255 
     } 
    } 
    let quartzImage = CGBitmapContextCreateImage(context) 
    CVPixelBufferUnlockBaseAddress(pixelBuffer,0) 
    let image = UIImage(CGImage: quartzImage!, scale: CGFloat(1.0), orientation: UIImageOrientation.Right) 

    return (image) 
    // frontCameraImageOrientation = UIImageOrientation.LeftMirrored 
    // backCameraImageOrientation = UIImageOrientation.Right 
} 
Смежные вопросы