2013-12-02 3 views
14

Я разрабатываю приложение, которое требует захвата фреймбуфера как можно больше кадров. Я уже понял, как заставить Iphone, чтобы захватить в 60 кадров в секунду, ноAVCapture захват и получение фреймбуфера со скоростью 60 кадров в секунду в iOS 7

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection 

метод вызывается только 15 раз в секунду, что означает, что iPhone понижен выход захвата до 15 кадров в секунду.

Неужели кто-нибудь сталкивался с такой проблемой? Есть ли возможность увеличить частоту кадров захвата?

Update мой код:

camera = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 
if([camera isTorchModeSupported:AVCaptureTorchModeOn]) { 
    [camera lockForConfiguration:nil]; 
    camera.torchMode=AVCaptureTorchModeOn; 
    [camera unlockForConfiguration]; 
} 
[self configureCameraForHighestFrameRate:camera]; 

// Create a AVCaptureInput with the camera device 
NSError *error=nil; 
AVCaptureInput* cameraInput = [[AVCaptureDeviceInput alloc] initWithDevice:camera error:&error]; 
if (cameraInput == nil) { 
    NSLog(@"Error to create camera capture:%@",error); 
} 

// Set the output 
AVCaptureVideoDataOutput* videoOutput = [[AVCaptureVideoDataOutput alloc] init]; 

// create a queue to run the capture on 
dispatch_queue_t captureQueue=dispatch_queue_create("captureQueue", NULL); 

// setup our delegate 
[videoOutput setSampleBufferDelegate:self queue:captureQueue]; 

// configure the pixel format 
videoOutput.videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA], (id)kCVPixelBufferPixelFormatTypeKey, 
          nil]; 

// Add the input and output 
[captureSession addInput:cameraInput]; 
[captureSession addOutput:videoOutput]; 

Я взял configureCameraForHighestFrameRate метод здесь https://developer.apple.com/library/mac/documentation/AVFoundation/Reference/AVCaptureDevice_Class/Reference/Reference.html

ответ

20

Я получаю образцы при 60 кадров в секунду на iPhone 5 и 120 кадров в секунду на iPhone 5s, как при выполнении реальной в режиме захвата и при сохранении кадров в видео с помощью AVAssetWriter.

Вы должны установить таял AVCaptureSession в формат, который поддерживает 60 кадров в секунду:

AVsession = [[AVCaptureSession alloc] init]; 

AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 
AVCaptureDeviceInput *capInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error]; 
if (capInput) [AVsession addInput:capInput]; 

for(AVCaptureDeviceFormat *vFormat in [videoDevice formats]) 
{ 
    CMFormatDescriptionRef description= vFormat.formatDescription; 
    float maxrate=((AVFrameRateRange*)[vFormat.videoSupportedFrameRateRanges objectAtIndex:0]).maxFrameRate; 

    if(maxrate>59 && CMFormatDescriptionGetMediaSubType(description)==kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) 
    { 
     if (YES == [videoDevice lockForConfiguration:NULL]) 
     { 
      videoDevice.activeFormat = vFormat; 
      [videoDevice setActiveVideoMinFrameDuration:CMTimeMake(10,600)]; 
      [videoDevice setActiveVideoMaxFrameDuration:CMTimeMake(10,600)]; 
      [videoDevice unlockForConfiguration]; 
      NSLog(@"formats %@ %@ %@",vFormat.mediaType,vFormat.formatDescription,vFormat.videoSupportedFrameRateRanges); 
     } 
    } 
} 

prevLayer = [AVCaptureVideoPreviewLayer layerWithSession: AVsession]; 
prevLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; 
[self.view.layer addSublayer: prevLayer]; 

AVCaptureVideoDataOutput *videoOut = [[AVCaptureVideoDataOutput alloc] init]; 
dispatch_queue_t videoQueue = dispatch_queue_create("videoQueue", NULL); 
[videoOut setSampleBufferDelegate:self queue:videoQueue]; 

videoOut.videoSettings = @{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}; 
videoOut.alwaysDiscardsLateVideoFrames=YES; 

if (videoOut) 
{ 
    [AVsession addOutput:videoOut]; 
    videoConnection = [videoOut connectionWithMediaType:AVMediaTypeVideo]; 
} 

Два друга комментарий, если вы хотите записать в файл с помощью AVAssetWriter. Не используйте pixelAdaptor, только рекламные образцы с

[videoWriterInput appendSampleBuffer:sampleBuffer] 

Во-вторых при настройке использования assetwriter

[AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo 
            outputSettings:videoSettings 
           sourceFormatHint:formatDescription]; 

sourceFormatHint делает разницу в скорости записи.

+0

я точно такие же (за исключением, может быть, типа kCVPixelFormatType_420YpCbCr8BiPlanarFullRange), но метод делегата по-прежнему называют только 15 раз в секунду. Не могли бы вы предоставить полный исходный код, где вы инициализируете вход и выход видео? –

+0

Я добавил код вывода видео, он довольно стандартный. Вы не делаете никаких тяжелых вычислений в captureOutput, которые замедляют работу? – Sten

+0

Мой код выглядит так же. Я выяснил, как увеличить частоту кадров до 30 кадров в секунду (ранее я пытался установить предварительную настройку сеанса), но этого все равно недостаточно. У меня есть некоторые вычисления, но для целей тестирования я отключил их, и у меня все еще есть 30 кадров в секунду. –

2

Я разработал ту же функцию для Swift 2.0. Здесь я пишу код для тех, кому он может понадобиться:

// Set your desired frame rate 
func setupCamera(maxFpsDesired: Double = 120) { 
var captureSession = AVCaptureSession() 
    captureSession.sessionPreset = AVCaptureSessionPreset1920x1080 
    let backCamera = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) 
    do{ let input = try AVCaptureDeviceInput(device: backCamera) 
     captureSession.addInput(input) } 
    catch { print("Error: can't access camera") 
     return 
    } 
    do { 
     var finalFormat = AVCaptureDeviceFormat() 
     var maxFps: Double = 0 
     for vFormat in backCamera!.formats { 
      var ranges  = vFormat.videoSupportedFrameRateRanges as! [AVFrameRateRange] 
      let frameRates = ranges[0] 
      /* 
       "frameRates.maxFrameRate >= maxFps" select the video format 
       desired with the highest resolution available, because 
       the camera formats are ordered; else 
       "frameRates.maxFrameRate > maxFps" select the first 
       format available with the desired fps 
      */ 
      if frameRates.maxFrameRate >= maxFps && frameRates.maxFrameRate <= maxFpsDesired { 
       maxFps = frameRates.maxFrameRate 
       finalFormat = vFormat as! AVCaptureDeviceFormat 
      } 
     } 
     if maxFps != 0 { 
      let timeValue = Int64(1200.0/maxFps) 
      let timeScale: Int64 = 1200 
      try backCamera!.lockForConfiguration() 
      backCamera!.activeFormat = finalFormat 
      backCamera!.activeVideoMinFrameDuration = CMTimeMake(timeValue, timeScale) 
      backCamera!.activeVideoMaxFrameDuration = CMTimeMake(timeValue, timeScale)    backCamera!.focusMode = AVCaptureFocusMode.AutoFocus 
      backCamera!.unlockForConfiguration() 
     } 
    } 
    catch { 
     print("Something was wrong") 
    } 
    let videoOutput = AVCaptureVideoDataOutput() 
    videoOutput.alwaysDiscardsLateVideoFrames = true 
    videoOutput.videoSettings = NSDictionary(object: Int(kCVPixelFormatType_32BGRA), 
     forKey: kCVPixelBufferPixelFormatTypeKey as String) as [NSObject : AnyObject] 
    videoOutput.setSampleBufferDelegate(self, queue: dispatch_queue_create("sample buffer delegate", DISPATCH_QUEUE_SERIAL)) 
    if captureSession.canAddOutput(videoOutput){ 
     captureSession.addOutput(videoOutput) } 
    let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) 
    view.layer.addSublayer(previewLayer) 
    previewLayer.transform = CATransform3DMakeRotation(-1.5708, 0, 0, 1); 
    previewLayer.frame = self.view.bounds 
    previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; 
    self.view.layer.addSublayer(previewLayer) 
    captureSession.startRunning() 
} 
+2

NICE! Тем не менее, мой iPhone 6 plus сообщил о следующей частоте кадров Framerates = , поэтому вы должны внести небольшое дополнение в свой ответ: if frameRates.maxFrameRate == 120 || frameRates.maxFrameRate == 240 { – Thyselius

+1

также изменился на CMTimeMake (5,1200) Затем я получил свою камеру на 240 – Thyselius

+1

Я редактирую свой ответ. CMTimeMake (5, 1200) запустит вашу камеру на 240, потому что 1200/5 = 240. В CMTimeMake первое значение - это числитель, второй - знаменатель. См. Http://stackoverflow.com/questions/12902410/trying-to-understand-cmtime –

1

Была такая же проблема. Исправлено с помощью этой функции после [AVCaptureSession addInput:cameraDeviceInput]. Каким-то образом я не мог изменить частоту кадров в своем iPad-профессионале до начала сеанса захвата. Поэтому сначала я изменил формат видео после добавления устройства в сеанс захвата.

- (void)switchFormatWithDesiredFPS:(CGFloat)desiredFPS 
{ 
    BOOL isRunning = _captureSession.isRunning; 

    if (isRunning) [_captureSession stopRunning]; 

    AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 
    AVCaptureDeviceFormat *selectedFormat = nil; 
    int32_t maxWidth = 0; 
    AVFrameRateRange *frameRateRange = nil; 

    for (AVCaptureDeviceFormat *format in [videoDevice formats]) { 

     for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges) { 

      CMFormatDescriptionRef desc = format.formatDescription; 
      CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(desc); 
      int32_t width = dimensions.width; 

      if (range.minFrameRate <= desiredFPS && desiredFPS <= range.maxFrameRate && width >= maxWidth) { 

       selectedFormat = format; 
       frameRateRange = range; 
       maxWidth = width; 
      } 
     } 
    } 

    if (selectedFormat) { 

     if ([videoDevice lockForConfiguration:nil]) { 

      NSLog(@"selected format:%@", selectedFormat); 
      videoDevice.activeFormat = selectedFormat; 
      videoDevice.activeVideoMinFrameDuration = CMTimeMake(1, (int32_t)desiredFPS); 
      videoDevice.activeVideoMaxFrameDuration = CMTimeMake(1, (int32_t)desiredFPS); 
      [videoDevice unlockForConfiguration]; 
     } 
    } 

    if (isRunning) [_captureSession startRunning]; 
} 
Смежные вопросы