【问题标题】:NSTimer giving inexact resultsNSTimer 给出不准确的结果
【发布时间】:2015-06-25 17:33:15
【问题描述】:

我有一个相机应用程序,我试图将拍摄长度限制为正好 15 秒。

我尝试了两种不同的方法,但都没有让我满意。

第一种方法是每秒触发一个重复计时器:

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 需要一秒钟来刷新缓冲区...... ???

【问题讨论】:

  • 不确定 是什么 适合这个,但它不是 NSTimer: stackoverflow.com/questions/11835023/nstimer-accuracy
  • 您可以将视频裁剪到 15 秒后,然后使用一个简单的 NSTimer。
  • @Linuxios 是的,这可能是正确的选择......
  • 这正是你需要做的。
  • 开箱即用并不确定这是否可能,但不是停止捕获(您认为可能需要 1 秒才能停止),您可以先删除输出吗?从 AVCaptureSession 的 API 中,它说您可以在会话运行时删除输出。理论上,这会立即停止输入到输出,希望它仍然可以毫无问题地保存内容?

标签: ios avfoundation nstimer nstimeinterval


【解决方案1】:

NSTimer 不能保证在你想要它触发的时候触发它,就在你想要它触发之后:

来自 Apple 的文档:

定时器不是实时机制;它仅在已添加计时器的运行循环模式之一正在运行并且能够检查计时器的触发时间是否已过时触发。由于典型的运行循环管理的各种输入源,计时器的时间间隔的有效分辨率被限制在 50-100 毫秒的数量级。如果计时器的触发时间发生在长时间调用期间或运行循环处于不监视计时器的模式下,则计时器不会触发,直到运行循环下次检查计时器。因此,定时器触发的实际时间可能是计划触发时间之后的一个重要时间段。另请参阅计时器容差。

但要回答您的问题,我曾在一家视频最长 15 秒的公司工作。我没有编写视频代码,但我认为我们事后使用了 AVComposition 以确保视频不超过 15 秒。即便如此,有时它可能会更短。见How do I use AVFoundation to crop a video

【讨论】:

    【解决方案2】:

    感谢 Paul 和 Linuxious 提供的 cmets 和答案...以及 Rory 跳出框框思考(有趣的选项)。

    是的,最后很明显 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 ];
                        }
                    }
                }];
            }
    
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-20
      • 1970-01-01
      • 1970-01-01
      • 2021-09-20
      • 2020-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多