2012-01-08 2 views
6

iPhone에서 비디오를 필터링하려고합니다. 다음은 프로그램 구조 및 소스 코드입니다.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); 
} 

세피아 필터가 작동하지만 비디오가 느린 조금이다. 필터를 적용하지 않으면 비디오가 정상입니다. 비디오를 개선하고 더 빨리 만들 수있는 방법에 대한 아이디어가 있습니까?

감사합니다.

+0

아마도 별도의 스레드로 오프로드 할 수있는 계산 작업이있을 것입니다. 'NSThread','NSOperation' 및 블록을 읽을 수 있습니다. –

+0

그것은 필터링을하고 화면에 비디오를 보여주고 필터링 작업을 다른 스레드에 위임 한 다음 해당 스레드에서 필터링 된 출력을 가져 와서 화면에 표시하면 차이가 있습니다. 같은 실에있는 모든 것?실시간 스레드가 아닌 경우 백그라운드 스레드를 사용하면 도움이 될 것입니다. 제발 제안 해주세요. 감사. – rookieRailer

+0

스레딩은 듀얼 코어 장치에서 도움이 될 것입니다. 백그라운드 스레드에서의 계산과 메인 스레드에서의 UI 업데이트. 더 작은 버전의 앱으로 프로필하십시오. –

답변

11

here을 설명 했으므로 코어 이미지의 세피아 필터는 실시간으로 실행할 수 없었지만 다른 필터가있을 수 있습니다. 대상 장치의 하드웨어 기능과 iOS 버전 (Core Image의 성능이 지난 몇 가지 iOS 버전에서 크게 향상되었습니다)에 따라 다릅니다.

그러나 오픈 소스 프레임 워크를 다시 연결할 수 있다면 GPUImage을 사용하면 훨씬 더 빠르게이 작업을 수행 할 수 있습니다. 이 카메라는 iPhone 4에서 640x480 프레임의 비디오를 2.5ms 간격으로 세피아 톤 필터를 적용 할 수 있습니다.이 필터는 해당 카메라의 30FPS 비디오보다 빠릅니다. 나는 이것이 지금 오래된 질문입니다 실현

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]; 
+1

이것은 단지 이미지 프로세서 프레임 워크가 아닙니다 ... 프레임 워크입니다. 훌륭한 직장 –

+0

갤러리에서 비디오를 가져 와서 필터를 추가 할 수 있습니까? – Imran

3

:

다음 코드는 세로 지향보기 내에서 그 비디오를 표시, 아이폰 OS 장치의 후면에 장착 된 카메라의 비디오의 실시간 필터링을 할 것입니다 하지만 ...

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

이 비디오 회신으로 메인 (UI) 스레드에서 호출되도록하고 있습니다.

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

는 계산 비용이 물건으로 많은 도움이됩니다 : 당신이해야 당신이 당신의 UI를 업데이트해야하는 경우 콜백에서 다음

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

: 당신이 뭔가로 변경하는 경우

배경 스레드에서 실행되며 이미지 그리기는 캡처에 영향을 미치지 않습니다.

사이드 참고 : 맹목적으로 기술이 어떻게 작동하는지에 최대 읽지 않고 당신이 인터넷에서 찾을 샘플 코드를 사용하여

응용 프로그램 (많은 사람들이의 유죄)

을 개발하는 좋은 방법이 아니다 다음
+0

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, 연속 15fps, 연속 20fps, 캡쳐 된 640x480 앞면 캡쳐 및 캡쳐 및 캡쳐 및 캡쳐 및 캡쳐 작업을 수행합니다. 더 빨라 졌으면 좋겠다! –

+1

프레임이 순서가 잘못 처리 될 수 있으므로 동시 대기열을 사용하면 안됩니다. –

2

:

CIFilter filterWithName:@"CISepiaTone" 

은 당신이 버퍼/프레임을받을 때마다 호출된다. 오직 한 번만 필터를 만들어야합니다. 따라서 이것을 외부로 옮기면 필터를 사용할 수 있습니다.