Преобразовать CMSampleBufferRef в UIImage с цветовым пространством YUV?
Я работаю с AVCaptureVideoDataOutput
и хочу конвертировать CMSampleBufferRef
в UIImage
, Многие ответы одинаковы, например, этот UIImage, созданный из CMSampleBufferRef, не отображается в UIImageView? и AVCaptureSession с несколькими превью
Это работает нормально, если я установил цветовое пространство VideoDataOutput в BGRA (зачислено на этот ответ CGBitmapContextCreateImage error)
NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA];
NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:value forKey:key];
[dataOutput setVideoSettings:videoSettings];
Без указанных выше настроек видео я получу следующие ошибки
CGBitmapContextCreate: invalid data bytes/row: should be at least 2560 for 8 integer bits/component, 3 components, kCGImageAlphaPremultipliedFirst.
<Error>: CGBitmapContextCreateImage: invalid context 0x0
Работа с BGRA не является хорошим выбором, так как есть издержки преобразования из YUV (цветового пространства AVCaptureSession по умолчанию) в BGRA, как заявлено Брэдом и Кодо в разделе Как получить компонент Y из CMSampleBuffer, полученного в результате AVCaptureSession?
Так есть ли способ конвертировать CMSampleBufferRef
в UIImage
и работа с цветовым пространством YUV?
1 ответ
После того, как проделал много исследований и прочитал яблочную документацию и википедию. Я разобрался с ответом, и он отлично работает для меня. Так что для будущих читателей я делюсь кодом для конвертации CMSampleBufferRef
в UIImage
когда тип пикселя видео установлен как kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
// Create a UIImage from sample buffer data
// Works only if pixel format is kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
-(UIImage *) imageFromSamplePlanerPixelBuffer:(CMSampleBufferRef) sampleBuffer{
@autoreleasepool {
// Get a CMSampleBuffer's Core Video image buffer for the media data
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
// Lock the base address of the pixel buffer
CVPixelBufferLockBaseAddress(imageBuffer, 0);
// Get the number of bytes per row for the plane pixel buffer
void *baseAddress = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);
// Get the number of bytes per row for the plane pixel buffer
size_t bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer,0);
// Get the pixel buffer width and height
size_t width = CVPixelBufferGetWidth(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
// Create a device-dependent gray color space
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
// Create a bitmap graphics context with the sample buffer data
CGContextRef context = CGBitmapContextCreate(baseAddress, width, height, 8,
bytesPerRow, colorSpace, kCGImageAlphaNone);
// Create a Quartz image from the pixel data in the bitmap graphics context
CGImageRef quartzImage = CGBitmapContextCreateImage(context);
// Unlock the pixel buffer
CVPixelBufferUnlockBaseAddress(imageBuffer,0);
// Free up the context and color space
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
// Create an image object from the Quartz image
UIImage *image = [UIImage imageWithCGImage:quartzImage];
// Release the Quartz image
CGImageRelease(quartzImage);
return (image);
}
}
// меня устраивает.
var image: CGImage?
VTCreateCGImageFromCVPixelBuffer(pixelBuffer, options: nil, imageOut: &image)
DispatchQueue.main.async {
self.imageView.image = UIImage(cgImage: image!)
}