【问题标题】:Video filtering in iPhone is slowiPhone中的视频过滤很慢
【发布时间】:2012-02-05 09:06:45
【问题描述】:

我正在尝试过滤 iPhone 中的视频。这是我的程序结构和源代码:

AppDelegate.h
AppDelegate.m
ViewController.h
ViewController.m

AppDelegate 文件与默认相同。这是我的 ViewController。

//ViewController.h

#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreMedia/CoreMedia.h>
#import <CoreVideo/CoreVideo.h>
#import <QuartzCore/QuartzCore.h>
#import <CoreImage/CoreImage.h>
#import <ImageIO/ImageIO.h>

@interface ViewController : GLKViewController <AVCaptureVideoDataOutputSampleBufferDelegate>{
    AVCaptureSession *avCaptureSession;
    CIContext *coreImageContext;
    CIImage *maskImage;
    CGSize screenSize;
    CGContextRef cgContext;
    GLuint _renderBuffer;
    float scale;
}

@property (strong, nonatomic) EAGLContext *context;

-(void)setupCGContext;

@end

// ViewController.m
#import "ViewController.h"

@implementation ViewController

@synthesize context;

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    if (!self.context) {
        NSLog(@"Failed to create ES context");
    }

    GLKView *view = (GLKView *)self.view;
    view.context = self.context;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;

    coreImageContext = [CIContext contextWithEAGLContext:self.context];

    glGenRenderbuffers(1, &_renderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffer);

    NSError *error;
    AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
    AVCaptureVideoDataOutput *dataOutput = [[AVCaptureVideoDataOutput alloc] init];

    [dataOutput setAlwaysDiscardsLateVideoFrames:YES]; 
    [dataOutput setVideoSettings:[NSDictionary  dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] 
                                                              forKey:(id)kCVPixelBufferPixelFormatTypeKey]];
    [dataOutput setSampleBufferDelegate:self queue:dispatch_get_main_queue()];

    avCaptureSession = [[AVCaptureSession alloc] init];
    [avCaptureSession beginConfiguration];
    [avCaptureSession setSessionPreset:AVCaptureSessionPreset1280x720];
    [avCaptureSession addInput:input];
    [avCaptureSession addOutput:dataOutput];
    [avCaptureSession commitConfiguration];
    [avCaptureSession startRunning];

    [self setupCGContext];
    CGImageRef cgImg = CGBitmapContextCreateImage(cgContext);
    maskImage = [CIImage imageWithCGImage:cgImg];
    CGImageRelease(cgImg);
}

-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {

    CVPixelBufferRef pixelBuffer = (CVPixelBufferRef)CMSampleBufferGetImageBuffer(sampleBuffer);
    CIImage *image = [CIImage imageWithCVPixelBuffer:pixelBuffer];
    image = [CIFilter   filterWithName:@"CISepiaTone" keysAndValues:kCIInputImageKey, 
                        image, @"inputIntensity", 
                        [NSNumber numberWithFloat:0.8], 
                        nil].outputImage;

    [coreImageContext drawImage:image atPoint:CGPointZero fromRect:[image extent] ];

    [self.context presentRenderbuffer:GL_RENDERBUFFER];
}

-(void)setupCGContext {
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * screenSize.width;
    NSUInteger bitsPerComponent = 8;
    cgContext = CGBitmapContextCreate(NULL, screenSize.width, screenSize.height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);

    CGColorSpaceRelease(colorSpace);
}

棕褐色滤镜有效,但视频速度稍慢。当我不应用过滤器时,视频是正常的。关于如何改进视频并使其更快的任何想法?

谢谢。

【问题讨论】:

  • 也许您可以将计算工作卸载到单独的线程。您可能会阅读NSThreadNSOperation 和块。
  • 这有什么不同吗,因为我正在过滤并在屏幕上显示视频,将过滤任务委托给另一个线程,然后从该线程获取过滤后的输出,并将其显示在屏幕上,不会和在同一个线程中做整个事情不一样吗?如果我猜它不是实时的,使用后台线程会很有帮助。请建议。谢谢。
  • 线程可能有助于双核设备。在后台线程上进行计算,在主线程上进行 UI 更新。可能会使用较小版本的应用进行配置文件。

标签: iphone ios


【解决方案1】:

正如我描述的here,Core Image 中的棕褐色过滤器不能实时运行,但其他过滤器可以。这取决于目标设备的硬件能力,以及 iOS 版本(Core Image 在性能上比过去几个 iOS 版本有了显着提升)。

但是,如果我可以再次插入我的开源框架,GPUImage 可以让您更快地完成此操作。它可以在 iPhone 4 上在 2.5 毫秒内对 640x480 帧的视频应用棕褐色调滤镜,这对于来自该相机的 30 FPS 视频来说已经足够快了。

以下代码将对来自 iOS 设备后置摄像头的视频进行实时过滤,并在纵向视图中显示该视频:

videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:AVCaptureSessionPreset640x480 cameraPosition:AVCaptureDevicePositionBack];

sepiaFilter = [[GPUImageSepiaFilter alloc] init];
GPUImageRotationFilter *rotationFilter = [[GPUImageRotationFilter alloc] initWithRotation:kGPUImageRotateRight];

[videoCamera addTarget:rotationFilter];
[rotationFilter addTarget:sepiaFilter];
filterView = [[GPUImageView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:filterView];
[sepiaFilter addTarget:filterView];

[videoCamera startCameraCapture];

【讨论】:

  • 这不仅仅是一个图像处理器框架......它是框架。干得好
  • 我们可以在从图库中挑选视频后添加过滤器吗?
【解决方案2】:

以下内容:

CIFilter   filterWithName:@"CISepiaTone" 

每次获得缓冲区/帧时都会调用。您只需要创建一次过滤器。所以把它移到外面,你仍然可以使用过滤器。

【讨论】:

    【解决方案3】:

    我现在意识到这是一个老问题了,但是......

    [dataOutput setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
    

    该行正在使您的视频回调在主 (UI) 线程上被调用。

    如果您将其更改为:

    [dataOutput setSampleBufferDelegate:self
                                  queue:dispatch_queue_create("cQ", DISPATCH_QUEUE_SERIAL)];
    

    然后在你的回调中,如果你需要更新你的 UI,你应该这样做:

    dispatch_async(dispatch_get_main_queue(), ^{
        [coreImageContext drawImage:image atPoint:CGPointZero fromRect:[image extent] ];
        [self.context presentRenderbuffer:GL_RENDERBUFFER];
    });
    

    这将有很大帮助,因为计算昂贵的东西将在后台线程上执行,并且图像绘制不会影响捕获。

    旁注:

    盲目地使用你在互联网上找到的示例代码而不阅读技术的工作原理并不是开发应用程序的好方法(很多人对此感到内疚)

    【讨论】:

    • 我在不使用 main_queue 时也得到了加速。但是,我发现 DISPATCH_QUEUE_SERIAL 和 DISPATCH_QUEUE_CONCURRENT 都没有简单地将 dispatch_queue_create 的 dispatch_queue_attr_t 设置为 NULL 一样快。奇怪的是,queue.h 的标题有这样的定义:“#define DISPATCH_QUEUE_SERIAL NULL”。所以我不明白那里发生了什么。在 iPad 3/iOS 6 上,我在主队列上得到 10fps,使用 SERIAL 大约 15fps,使用 CONCURRENT 大约 20fps,使用 NULL 捕获 640x480 前置视频捕获并在片段着色器上进行一些简单的图像处理时大约 25fps。希望它更快!
    • 您不应该使用并发队列,因为您的帧可能会被乱序处理。
    猜你喜欢
    • 1970-01-01
    • 2016-10-22
    • 2012-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多