如何使用AVCaptureSession从文件中读取视频?

时间:2014-10-07 11:02:17

标签: ios opencv video-processing

我正在编写一个使用AVCaptureSession进行实时视频处理的应用,输出为AVCaptureVideoDataOutput,视频文件为AVCaptureDeviceInput(不再需要实时)作为输入。

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

3 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:0)

事实证明,它太难了。基本概要是:

  1. 创建cv::VideoCapture以从文件中读取
  2. 创建CALayer以接收并显示每个框架。
  3. 以给定的速率运行方法,读取并处理每个帧。
  4. 完成处理后,将每个cv::Mat转换为CGImageRef并将其显示在CALayer上。
  5. 实际实施如下:

    第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);
    }
    

答案 2 :(得分:0)

我实现了pasawaya解决方案... PreviewLayer没有刷新...我发现问题出在哪里:

在第4步中,替换:

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

使用:

[self performSelectorOnMainThread:@selector(displayFrame:) withObject:(__bridge id)imageRef waitUntilDone:YES];

并添加:

- (void)displayFrame:(CGImageRef)frame {
    _previewLayer.contents = (__bridge id)frame;
    [CATransaction flush];
}

希望获得帮助!