【问题标题】:how to use AVCaptureSession to read a video from a file?如何使用 AVCaptureSession 从文件中读取视频?
【发布时间】:2014-12-01 19:00:39
【问题描述】:

我正在编写一个应用程序,它使用AVCaptureSessionAVCaptureVideoDataOutput 作为输出和AVCaptureDeviceInput 和视频文件(它不再需要实时)进行一些实时视频处理输入。

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

【问题讨论】:

    标签: ios opencv video-processing


    【解决方案1】:

    我实现了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];
    }
    

    希望有帮助!

    【讨论】:

      【解决方案2】:

      所以事实证明这并不是难做到。基本大纲是:

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

      第四步:处理方法

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

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-17
          • 2013-10-13
          相关资源
          最近更新 更多