CIContext drawImage 速度很慢

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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值