2015-06-25 2 views
0

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

Я пробовал два разных подхода, и ни один из них не работает на мое удовлетворение.

Первый подход заключается в огнь повторяющегося таймера каждую секунды:

self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(countTime:) userInfo:[NSDate date] repeats:YES]; 

- (void)countTime:(NSTimer*)sender { 
    NSDate *start = sender.userInfo; 
    NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:start]; 
    NSInteger time = round(duration); 
    if (time > 15) { 
     [self capture:nil]; // this stops capture 
    } 
} 

это дает мне 15-секундное видео 8/10 раз, с периодическим 16 вторым ... и я попробовал смесь из NSTimeInterval двойных и закругленное целое здесь, без видимой разницы ...

второго подход заключается в раз огня селектора после требуемой продолжительности, например, так:

self.timer = [NSTimer scheduledTimerWithTimeInterval:15.0f target:self selector:@selector(capture:) userInfo:nil repeats:NO]; 

это просто вызывает метод захвата - который останавливает захват камеры - напрямую, и дает мне те же результаты ...

Есть ли что-то, что я пропускаю здесь?

Теперь, потому что я испытал с числом подредактированны значений с плавающей точкой в ​​качестве колпачка (14,5, 15,0, 15,1, 15,5, 16,0 и т.д.), и я почти всегда видеть 16 второй видео после нескольких попыток, я я начинаю задаваться вопросом, является ли это просто AVFoundation, взяв второй, чтобы сбросить буфер ... ???

+1

Не знаете, что это за *, для этого, но это не 'NSTimer': http: // stackoverflow.com/questions/11835023/nstimer-precision – Linuxios

+1

Возможно, вы можете просто обрезать видео до 15 секунд и просто остаться с простым NSTimer. – Linuxios

+0

@ Linuxios да, это, вероятно, правильный вариант .... –

ответ

2

NSTimer не гарантируются огнем, когда вы хотите его, только после того, как вы хотите, чтобы огнь:

От Документов Apple:

Таймер не является механизм реального времени; он срабатывает только тогда, когда работает один из режимов цикла запуска, к которому был добавлен таймер, и он может проверить, прошло ли время срабатывания таймера. Из-за различных источников входных данных управляется типичный цикл запуска, эффективное разрешение временного интервала для таймера ограничено порядком 50-100 миллисекунд. Если время срабатывания таймера происходит во время длинной выноски или в то время, когда цикл цикла находится в режиме, который не контролирует таймер, таймер не срабатывает до следующего цикла проверки таймера. Поэтому фактическое время, в течение которого таймер срабатывает потенциально, может быть значительным периодом времени после запланированного времени стрельбы. См. Также Толерантность по таймеру.

Но для ответа на ваш вопрос я работал в компании, у которой было максимально 15 секунд видео. Я не писал видеокодек, но я думаю, что мы использовали AVComposition после того, как убедиться, что видео было не более 15 секунд. И даже тогда это может быть иногда короче. См. How do I use AVFoundation to crop a video

0

Спасибо Paul и Linuxious за их комментарии и ответы ... и Рори за то, что подумали вне коробки (интригующий вариант).

И да, в конце ясно, что NSTimer сам по себе недостаточен.

В конце концов, я слушаю метод делегата captureOutput для запуска, проверки длины актива и правильной подгонки композиции.

- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL 
     fromConnections:(NSArray *)connections error:(NSError *)error 
{ 
    _isRecording = NO; 

    AVURLAsset *videoAsset = [AVURLAsset assetWithURL:outputFileURL]; 
    CMTime length = [videoAsset duration]; 
    CMTimeShow(length); 

    if(CMTimeGetSeconds(length) > 15) 
    { 
     NSLog(@"Capture Longer Than 15 Seconds - Attempting to Trim"); 

     Float64 preferredDuration = 15; 
     int32_t preferredTimeScale = 30; 
     CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(preferredDuration, preferredTimeScale)); 

     AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:videoAsset presetName:AVAssetExportPresetHighestQuality]; 
     exportSession.outputURL = outputFileURL; 
     exportSession.outputFileType = AVFileTypeQuickTimeMovie; 
     exportSession.timeRange = timeRange; 

     NSError *err = nil; 
     [[NSFileManager defaultManager] removeItemAtURL:outputFileURL error:&err]; 
     if (err) { 
      NSLog(@"Error deleting File: %@", [err localizedDescription]); 
     } 
     else { 
      [exportSession exportAsynchronouslyWithCompletionHandler:^{ 
       if (exportSession.status == AVAssetExportSessionStatusCompleted) { 
        NSLog(@"Export Completed - Passing URL to Delegate"); 
        if ([self.delegate respondsToSelector:@selector(didFinishRecordingToOutputFileAtURL:error:)]) { 
         [self.delegate didFinishRecordingToOutputFileAtURL:outputFileURL error:error]; 
        } 
       } 
       else if(exportSession.status == AVAssetExportSessionStatusFailed) { 
        NSLog(@"Export Error: %@", [exportSession.error localizedDescription]); 
        if ([self.delegate respondsToSelector:@selector(didFinishRecordingToOutputFileAtURL:error:)]) { 
         [self.delegate didFinishRecordingToOutputFileAtURL:outputFileURL error:exportSession.error ]; 
        } 
       } 
      }]; 
     } 

    } 

} 
Смежные вопросы