CIContext drawImage 速度很慢

来源:互联网 发布:韦德去骑士数据 编辑:程序博客网 时间:2024/05/16 05:14

CIContext drawImage 速度很慢

背景:在做视频/图片编辑软件的时候, 自己写一个视频图片的播放器,
播放流程:
视频->CVPixelBufferRef->CIImage->CIFilter处理字幕, 滤镜, 转场->新的CIImage->通过CIContext将CIImage显示到GLKView上

图片->UIImage->CGImageRef->CIImage->CIFilter处理字幕, 滤镜, 转场->新的CIImage->通过CIContext将CIImage显示到GLKView上

导出流程:
视频->CVPixelBufferRef->CIImage->CIFilter处理字幕, 滤镜, 转场->新的CIImage->通过CIContext将CIImage转换成CVPixelBuffer->写入文件

图片->UIImage->CGImageRef->CIImage->CIFilter处理字幕, 滤镜, 转场->新的CIImage->通过CIContext将CIImage转换成CVPixelBuffer->写入文件

然后发现, 视频在播放的时候很顺畅, 但是图片却会卡顿, 很慢, 经排查后发现跟CIImage创建时候的来源有关

CIImage
数据来源CGImageRef, 用CIContext绘制的时候比较慢

_CIImage = [CIImage imageWithCGImage:_image.CGImage];调试的时候 po _CIImage 如下:<CIImage: 0x14c9e0bd0 extent [0 0 1280 960]>  affine [1 0 0 -1 0 960] extent=[0 0 1280 960] opaque    colormatch "sRGB IEC61966-2.1"-to-workingspace extent=[0 0 1280 960] opaque      CGImageRef 0x147fd89c0 RGBX8 1280x960  alpha_one extent=[0 0 1280 960] opaque

数据来源CVPixelBufferRef, 用CIContext绘制的时候比较快

_CIImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];调试时候 po _CIImage 如下:<CIImage: 0x1291dd5a0 extent [0 0 1920 1080]>  colorkernel filterKernel(image,scaling=[1 1080]) extent=[0 0 1920 1080]    affine [2.85714 0 0 2.85714 0 0] extent=[0 0 1920 1080] opaque      affine [1 0 0 -1 0 378] extent=[0 0 672 378] opaque        colormatch "Composite NTSC"-to-workingspace extent=[0 0 672 378] opaque          IOSurface 0x1258002a8 YCC420v 709 alpha_one extent=[0 0 672 378] opaque

接下来这段纯属个人推断, 没有验证过
=======
CIImage内部的实现应该有分CPU和GPU, 如果同样是CPU到CPU,
UIImage->CGImageRef->CIImage经过处理后->CIImage->UIImage, 假设处理也是在CPU上的话, 这样的处理应该是比较快的,因为没有数据搬移.
或者GPU到GPU的处理,
CVPixelBufferRef->CIImage->经过CIFilter处理->CIImage->通过CIContext的drawImage显示或者renderImage:toCVPixelBuffer生成新的CVPixelBufferRef导出
这样速度应该会很快, 因为不需要数据搬移, 数据的处理也都在GPU层面上

但是如果过程是这样的UIImage->CIImage->经过CIFilter处理->CIImage->CIContext显示在GPU上, 这样的速度就会变慢.

因为经历了CPU->GPU的数据搬移

=======
解决思路:
既然是因为CIImage创建的时候如果从UIImage过来就会慢, 从CVPixelBufferRef来的就不会慢, 是不是可以对图片的处理的时候, 创建CIImage可以类似从CVPixelBufferRef中来
简单的说, 就是可不可以用GPU的方式来创建图片

解决办法:
将UIImage转换成CVPixelBufferRef, 然后CIImage在从CVPixelBufferRef中创建

- (CVPixelBufferRef) pixelBufferFromCGImage: (CGImageRef) image {    NSDictionary *options = @{                              (NSString*)kCVPixelBufferCGImageCompatibilityKey : @YES,                              (NSString*)kCVPixelBufferCGBitmapContextCompatibilityKey : @YES,                              };    CVPixelBufferRef pxbuffer = NULL;    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, CGImageGetWidth(image),                                          CGImageGetHeight(image), kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options,                                          &pxbuffer);    if (status!=kCVReturnSuccess) {        NSLog(@"Operation failed");    }    NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);    CVPixelBufferLockBaseAddress(pxbuffer, 0);    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();    CGContextRef context = CGBitmapContextCreate(pxdata, CGImageGetWidth(image),                                                 CGImageGetHeight(image), 8, 4*CGImageGetWidth(image), rgbColorSpace,                                                 kCGImageAlphaNoneSkipFirst);    NSParameterAssert(context);//    CGContextConcatCTM(context, CGAffineTransformMakeRotation(0));//    CGAffineTransform flipVertical = CGAffineTransformMake( 1, 0, 0, -1, 0, CGImageGetHeight(image) );//    CGContextConcatCTM(context, flipVertical);//    CGAffineTransform flipHorizontal = CGAffineTransformMake( -1.0, 0.0, 0.0, 1.0, CGImageGetWidth(image), 0.0 );//    CGContextConcatCTM(context, flipHorizontal);    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image),                                           CGImageGetHeight(image)), image);    CGColorSpaceRelease(rgbColorSpace);    CGContextRelease(context);    CVPixelBufferUnlockBaseAddress(pxbuffer, 0);    return pxbuffer;}

然后

CVPixelBufferRef pixelBuffer = [self pixelBufferFromCGImage:_image.CGImage];_CIImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];CVPixelBufferRelease(pixelBuffer);
0 0
原创粉丝点击