Tôi đã cố gắng trả lời điều này trong chuỗi ban đầu nhưng SO không cho phép tôi. Hy vọng rằng một người có thẩm quyền hơn có thể hợp nhất điều này vào câu hỏi ban đầu.Làm thế nào để chuyển đổi bộ đệm kCVPixelFormatType_420YpCbCr8BiPlanarFullRange sang UIImage trong iOS
OK đây là câu trả lời hoàn chỉnh hơn. Thứ nhất, thiết lập chụp:
// Create capture session
self.captureSession = [[AVCaptureSession alloc] init];
[self.captureSession setSessionPreset:AVCaptureSessionPresetPhoto];
// Setup capture input
self.inputDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *captureInput = [AVCaptureDeviceInput deviceInputWithDevice:self.inputDevice
error:nil];
[self.captureSession addInput:captureInput];
// Setup video processing (capture output)
AVCaptureVideoDataOutput *captureOutput = [[AVCaptureVideoDataOutput alloc] init];
// Don't add frames to the queue if frames are already processing
captureOutput.alwaysDiscardsLateVideoFrames = YES;
// Create a serial queue to handle processing of frames
_videoQueue = dispatch_queue_create("cameraQueue", NULL);
[captureOutput setSampleBufferDelegate:self queue:_videoQueue];
// Set the video output to store frame in YUV
NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange];
NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:value forKey:key];
[captureOutput setVideoSettings:videoSettings];
[self.captureSession addOutput:captureOutput];
OK bây giờ thực hiện cho các đại biểu/callback:
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection
{
// Create autorelease pool because we are not in the main_queue
@autoreleasepool {
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
//Lock the imagebuffer
CVPixelBufferLockBaseAddress(imageBuffer,0);
// Get information about the image
uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer);
// size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
size_t width = CVPixelBufferGetWidth(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
CVPlanarPixelBufferInfo_YCbCrBiPlanar *bufferInfo = (CVPlanarPixelBufferInfo_YCbCrBiPlanar *)baseAddress;
// This just moved the pointer past the offset
baseAddress = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);
// convert the image
_prefImageView.image = [self makeUIImage:baseAddress bufferInfo:bufferInfo width:width height:height bytesPerRow:bytesPerRow];
// Update the display with the captured image for DEBUG purposes
dispatch_async(dispatch_get_main_queue(), ^{
[_myMainView.yUVImage setImage:_prefImageView.image];
});
}
và cuối cùng ở đây là phương pháp để chuyển đổi từ YUV tới một UIImage
- (UIImage *)makeUIImage:(uint8_t *)inBaseAddress bufferInfo:(CVPlanarPixelBufferInfo_YCbCrBiPlanar *)inBufferInfo width:(size_t)inWidth height:(size_t)inHeight bytesPerRow:(size_t)inBytesPerRow {
NSUInteger yPitch = EndianU32_BtoN(inBufferInfo->componentInfoY.rowBytes);
uint8_t *rgbBuffer = (uint8_t *)malloc(inWidth * inHeight * 4);
uint8_t *yBuffer = (uint8_t *)inBaseAddress;
uint8_t val;
int bytesPerPixel = 4;
// for each byte in the input buffer, fill in the output buffer with four bytes
// the first byte is the Alpha channel, then the next three contain the same
// value of the input buffer
for(int y = 0; y < inHeight*inWidth; y++)
{
val = yBuffer[y];
// Alpha channel
rgbBuffer[(y*bytesPerPixel)] = 0xff;
// next three bytes same as input
rgbBuffer[(y*bytesPerPixel)+1] = rgbBuffer[(y*bytesPerPixel)+2] = rgbBuffer[y*bytesPerPixel+3] = val;
}
// Create a device-dependent RGB color space
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(rgbBuffer, yPitch, inHeight, 8,
yPitch*bytesPerPixel, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);
CGImageRef quartzImage = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
UIImage *image = [UIImage imageWithCGImage:quartzImage];
CGImageRelease(quartzImage);
free(rgbBuffer);
return image;
}
Bạn cũng cần phải #import "Endian.h"
Lưu ý rằng cuộc gọi đến CGBitmapContextCrea te là phức tạp hơn nhiều mà tôi mong đợi. Tôi không hiểu lắm về xử lý video, tuy nhiên, cuộc gọi này đã làm tôi bối rối một lúc. Sau đó, khi nó cuối cùng đã làm việc nó giống như ma thuật.
Tôi vừa dành hai ngày cuối cùng cố gắng viết một UIImage trong bộ đệm để thêm vào video Tôi hiểu sự phấn khích của bạn! –
@NicolasManzini Giải pháp này có phù hợp với bạn không? Tôi đang nhận được ': copy_read_only: vm_copy không thành công: trạng thái 1. 'Có vẻ liên quan đến http://stackoverflow.com/questions/3367849/cgbitmapcontextcreateimage-vm-copy-failed-iphone-sdk –
kiểm tra kích thước của bitmap của bạn bối cảnh có thể. nhưng tôi đã làm theo cách khác xung quanh CGContextDrawImage (...) –