2014-10-07 28 views
13

我写一个应用程序,并使用AVCaptureSession一些实时视频处理与AVCaptureVideoDataOutput作为输出和AVCaptureDeviceInput与视频文件(它不再需要在实时)作为输入。如何使用AVCaptureSession从文件读取视频?

是否可以使用视频文件作为输入AVCaptureSession,而不是相机? 如果不可能,使用视频捕获opencv on iOS(同时或顺序)处理视频文件的最佳方法是什么?

回答

1

由于您可以访问原始视频文件帧(来自您的AVCaptureVideoDataOutput),因此您可以将每个帧转换为cv::Mat对象(代表图像的opencv矩阵)。然后在每个单独的框架上进行图像处理。

退房https://developer.apple.com/library/ios/qa/qa1702/_index.html 使用相机的实时例子;您可以使用cvMatFromUIImage将您的UIImage转换为cv::Mat

0

因此,原来这不是很难做到的。基本轮廓是:

  1. 创建cv::VideoCapture从文件
  2. 读取创建CALayer接收和显示每个帧。
  3. 运行在给定的速率读取和处理每帧的方法。
  4. 一旦完成处理中,每个cv::Mat转换为CGImageRef并在CALayer显示它。

实际的实现如下:

步骤1:创建CV :: VideoCapture

std::string filename = "/Path/To/Video/File"; 
capture = cv::VideoCapture(filename); 
if(!capture.isOpened()) NSLog(@"Could not open file.mov"); 

步骤2:创建输出的CALayer

self.previewLayer = [CALayer layer]; 
self.previewLayer.frame = CGRectMake(0, 0, width, height); 
[self.view.layer addSublayer:self.previewLayer]; 

第3步:创建处理循环瓦特/ GCD

int kFPS = 30; 

dispatch_queue_t queue = dispatch_queue_create("timer", 0); 
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); 
dispatch_source_set_timer(self.timer, dispatch_walltime(NULL, 0), (1/kFPS) * NSEC_PER_SEC, (0.5/kFPS) * NSEC_PER_SEC); 

dispatch_source_set_event_handler(self.timer, ^{ 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [self processNextFrame]; 
    }); 
}); 

dispatch_resume(self.timer); 

步骤4:处理方法

-(void)processNextFrame { 
    /* Read */ 
    cv::Mat frame; 
    capture.read(frame); 

    /* Process */ 
    ... 

    /* Convert and Output to CALayer*/ 
    cvtColor(frame, frame, CV_BGR2RGB); 
    NSData *data = [NSData dataWithBytes:frame.data 
           length:frame.elemSize()*frame.total()]; 

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGBitmapInfo bitmapInfo = (frame.elemSize() == 3) ? kCGImageAlphaNone : kCGImageAlphaNoneSkipFirst; 
    CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef) data); 

    CGImageRef imageRef = CGImageCreate(frame.cols, 
             frame.rows, 
             8, 
             8 * frame.elemSize(), 
             frame.step[0], 
             colorSpace, 
             bitmapInfo, 
             provider, 
             NULL, 
             false, 
             kCGRenderingIntentDefault); 

    self.previewLayer.contents = (__bridge id)imageRef; 

    CGImageRelease(imageRef); 
    CGColorSpaceRelease(colorSpace); 
}