I am doing video recording. I need to snapshoot a view to a UIImage, and then convert it to CVPixelBufferRef. And it work fine with RGBA color space. But the CVPixelBufferRef I need should be with YUV color space.
Anyone have any ideas? Thanks.
+ (CVPixelBufferRef) pixelBufferFromLayer:(CALayer *)layer forSize:(CGSize)size
{
UIImage * image = [self fetchScreenShotFromLayer:layer forSize:size];
// this worked fine
// CVPixelBufferRef rgbBuffer = [self RGBPixelBufferFromCGImage:image.CGImage];
// return rgbBuffer;
// NSData * imageData = UIImageJPEGRepresentation(image, 0.5);
NSData * imageData = UIImagePNGRepresentation(image);
CVPixelBufferRef buffer = [self yuvPixelBufferWithData:imageData width:size.width heigth:size.height];
return buffer;
}
create CVPixelBufferRef with RGB color space is fine.
// RGB color space pixel buffer
+ (CVPixelBufferRef) RGBPixelBufferFromCGImage:(CGImageRef)image
{
NSDictionary * options = @{
(NSString *)kCVPixelBufferCGImageCompatibilityKey: @(YES),
(NSString *)kCVPixelBufferCGBitmapContextCompatibilityKey: @(YES),
};
CVPixelBufferRef pxbuffer = NULL;
CGFloat frameWidth = CGImageGetWidth(image);
CGFloat frameHeight = CGImageGetHeight(image);
CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, frameWidth, frameHeight, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef)options, &pxbuffer);
NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);
CVPixelBufferLockBaseAddress(pxbuffer, 0);
void * pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
NSParameterAssert(pxdata != NULL);
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pxdata, frameWidth, frameHeight, 8, CVPixelBufferGetBytesPerRow(pxbuffer), rgbColorSpace, (CGBitmapInfo)kCGImageAlphaNoneSkipFirst);
NSParameterAssert(context);
CGContextConcatCTM(context, CGAffineTransformIdentity);
CGContextDrawImage(context, CGRectMake(0, 0, frameWidth, frameHeight), image);
CGColorSpaceRelease(rgbColorSpace);
CGContextRelease(context);
CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
return pxbuffer;
}
// snapshoot for layer
+ (UIImage *) fetchScreenShotFromLayer:(CALayer *)layer forSize:(CGSize)size
{
UIImage * image = nil;
@autoreleasepool {
NSLock * aLock = [NSLock new];
[aLock lock];
CGSize imageSize = size;
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
[layer renderInContext:context];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[aLock unlock];
}
return image;
}
Something is wrong with this.
// data to yuv buffer
+ (CVPixelBufferRef)yuvPixelBufferWithData:(NSData *)dataFrame
width:(size_t)w
heigth:(size_t)h
{
unsigned char* buffer = (unsigned char*) dataFrame.bytes;
CVPixelBufferRef getCroppedPixelBuffer = [self copyDataFromBuffer:buffer toYUVPixelBufferWithWidth:w Height:h];
return getCroppedPixelBuffer;
}
+ (CVPixelBufferRef) copyDataFromBuffer:(const unsigned char*)buffer toYUVPixelBufferWithWidth:(size_t)w Height:(size_t)h
{
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
[NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
nil];
CVPixelBufferRef pixelBuffer;
CVPixelBufferCreate(NULL, w, h, kCVPixelFormatType_420YpCbCr8BiPlanarFullRange, (__bridge CFDictionaryRef)(options), &pixelBuffer);
size_t count = CVPixelBufferGetPlaneCount(pixelBuffer);
NSLog(@"PlaneCount = %zu", count); // 2
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
size_t d = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0);
const unsigned char* src = buffer;
unsigned char* dst = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
for (unsigned int rIdx = 0; rIdx < h; ++rIdx, dst += d, src += w) {
memcpy(dst, src, w);
}
d = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1);
dst = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
h = h >> 1;
for (unsigned int rIdx = 0; rIdx < h; ++rIdx, dst += d, src += w) {
memcpy(dst, src, w);
}
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
return pixelBuffer;
}
Here is the images.
Thanks for your help.