Я создаю 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?