AVCaptureSession将录制分为单独的文件

时间:2012-07-24 23:47:37

标签: objective-c ios stream avfoundation

我希望将视频从iOS相机直播到服务器。我意识到可以使用AVCaptureVideoDataOutput来获取单个帧;但是,我想主要用于iPad 2和3,这些iOS设备内置的mp4硬件压缩。 AVCaptureVideoDataOutput提供原始视频数据,这不是我真正想要的。虽然确实可以使用ffmpeg在发送到服务器之前获取原始视频并进行压缩,但ffmpeg是我们不能用作基于GPL的代码,而我们的代码是封闭源代码。经过几天的研究,主要是谷歌搜索,我没有找到很多关于如何创建一个新文件,比如每5或10秒,从这些小文件中获取所有字节并发送到服务器。

我一直在考虑的两种方法:

  1. 使用AVCaptureMovieFileOutput将该数据流式传输到iOS上的磁盘。然后在单独的线程或带有操作对象的异步操作队列中,读取特定数量的字节,将这些字节附加到可变NS数据对象,并以某种方式将NSMutableData变量重建为可在设备iPad上播放的视频。目前,我还没有建立任何网络通信,所以我想拍摄那个视频,从NSMutableData变量重建,只显示在我的AVCaptureViewPreviewLayer旁边。我觉得这样做不会很好。

    - 首先,AVCaptureMovieFileOutput可能是缓冲区,导致文件写入时间延迟。 - 第二,即使我要阅读部分书面文件,随着录制时间变长,文件也会增长,在某些时候,文件会变得太大而录制会停止。

  2. 所以第一种方法可能不是最好的。

    1. 在AVCaptureSession上分别录制到单独的文件中。这可能是一种更好的方法。我可以将录音分成每个文件5或10秒。
    2. 方法2是我要去的地方。

      这是我到目前为止所做的:

      #define LIVE_VIDEO_STREAM_INTERVAL 3
      
      @interface AVCam (FileOutputDelegate) <AVCaptureFileOutputRecordingDelegate>
      @end
      
      // class AVCam
      @implementation AVCam
      
      - (id) initWithSession:(AVCaptureSession *)aSession
      {
          if ( (self = [super init]) )
          {
              AVCaptureMovieFileOutput *aMovieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
              if ([aSession canAddOutput:aMovieFileOutput])
                  [aSession addOutput:aMovieFileOutput];
      
              // thinking of changing this to a property, not sure yet.
              _movieFileOutput = [aMovieFileOutput retain];
              [aMovieFileOutput release];
      
              [self setSession:aSession];
              _tempFileCount = 0;
      
              _writtenFiles = [[NSMutableArray alloc] init];
      
              _liveVideoStreamTimer = [[NSTimer scheduledTimerWithTimeInterval:LIVE_VIDEO_STREAM_INTERVAL target:self selector:@selector(onStreamingRecordFired:) userInfo:nil repeats:YES] retain];
              [self pauseTimer];
          }
      }
      
      - (void) startStream
      {
          [self startRecording];
          [_liveVideoStreamTimer setFireDate:[NSDate dateWithTimeIntervalSinceNow:LIVE_VIDEO_STREAM_INTERVAL]];
      }
      
      - (void) stopStream
      {
          [self stopRecording];
          [_liveVideoStreamTimer invalidate];
      }
      
      - (BOOL) isRecording
      {
          return [_movieFileOutput isRecording];
      }
      
      - (void) startRecording
      {
          _currentWritePath = [self tempFileURL];
      
          AVCaptureConnection *videoConnection = [AVCamUtilities connectionWithMediaType:AVMediaTypeVideo fromConnection:[_movieFileOutput connections]];
          if ([videoConnection isVideoOrientationSupported])
              [videoConnection setVideoOrientation:AVCaptureVideoOrientationPortrait];
      
          [_movieFileOutput startRecordingToOutputFileURL:_currentWritePath recordingDelegate:self];
      }
      
      - (void) stopRecording
      {
          [_movieFileOutput stopRecording];
      }
      
      - (NSURL *) tempFileURL
      {
          //NSURL *tempURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@%@%d%@", [[self appDelegate] applicationDocumentsDirectory], @"output", _tempFileCount, @".mov"]];
          NSURL *tempURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@%@%d%@", NSTemporaryDirectory(), @"output", _tempFileCount, @".mov"]];
          _tempFileCount++;
          return tempURL;
      }
      
      - (void) onStreamingRecordFired:(id)context
      {
          if ([self isRecording])
          {
              NSLog(@"onStreamingRecordFired and isRecording");
              [_session beginConfiguration];
      
              [self stopRecording];
      
              [_session removeOutput:_movieFileOutput];
              _movieFileOutput = nil;
              _movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
              if ([_session canAddOutput:_movieFileOutput])
                  [_session addOutput:_movieFileOutput];
      
              [self startRecording];
      
              [_session commitConfiguration];
          }
      }
      
      @end
      
      @implementation AVCam (FileOutputDelegate)
      
      - (void) captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnection:(NSArray *)connections
      {
          NSLog(@"recording started");
      }
      
      - (void) captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnection:(NSArray *)connections error:(NSError *)error
      {
          NSLog(@"recording finished at URL: %@", outputFileURL);
      
          // add outputFileURL to _writtenFiles array, will need to purge file(s) after
          // a specific amount of time, say 60 secs files that were recorded more than that
          // should be purged.
          [_writtenFiles addObject:outputFileURL];
      }
      
      @end
      

      我对AVFoundation没有太多经验,所以我不确定在beginConfiguration和commitConfiguration之间停止和启动录制是否正确。

      不幸的是,我的代码效果不佳。

      我在想,因为我停止录制然后立即从_session中移除movieFileOutput,因为它无法调用它的委托。 captureOutput:didFinishRecordingToOutputFileAtURL:fromConnection:error:被调用一次。

      这是我的调试输出:

      recording started
      onStreamingRecordFired and isRecording
      recording finished at URL: file://localhost/private/var/mobile/Applications/6768112A-10B4-41F9-B6A2-4579735B6F14/tmp/output1.mov
      

0 个答案:

没有答案