iOS 更新录音开始后的录音时间的正确方法

Mar*_*sta 5 iphone avfoundation ios avcapturesession avassetwriter

如何使用 AVFoundation 中的捕获管道在录制过程中更新时间标签:

Mic -> AVCaptureDeviceInput -> AVCaptureSession -> AVCaptureAudioDataOutput
Run Code Online (Sandbox Code Playgroud)

AVCaptureAudioDataOutput 有 Delegate 和 AVAssetWritter 将sampleBuffers写入输出文件。在此解决方案中,我想更新录制时间。我可以记录用户点击“记录/暂停/恢复/停止”按钮时的时间,但是 Apple 是否有任何官方方法如何在开始时以 00:00:00 时间更新某些 UILabel。我知道我可以使用 NSTimer 但当我使用 AVAudioRecorder 时我有属性:

var currentTime: TimeInterval
// The time, in seconds, since the beginning of the recording.
Run Code Online (Sandbox Code Playgroud)

上述属性也适用于暂停/继续按钮。

现在,在这个新管道中,我没有这个属性,我想知道我是否丢失了某些东西并且无法在任何地方找到它。我还注意到 AVCaptureSession 有名为 masterClock 的 CMClock 属性,但自记录开始以来我不确定如何使用它来计算时间。

我不明白时钟和方法的全部概念,例如:

CMClockGetHostTimeClock()
CMSyncConvertTime
Run Code Online (Sandbox Code Playgroud)

如何在基于sampleBuffer的AVCaptureAudioDataOutputSampleBufferDelegate方法中获取自录音开始以来的秒数?

更新

我发现了一个名为 CMTimebase 的类,我认为这正是我正在寻找的。目前我不知道如何使用它,但我在操场上进行了一些实验后发现了这一点。

import CoreMedia

let masterClock = CMClockGetHostTimeClock() // This masterclock should be from captureSession
var timebase: CMTimebase? = nil
CMTimebaseCreateWithMasterClock(kCFAllocatorDefault, masterClock, &timebase)

print(CMTimeGetSeconds(CMTimebaseGetTime(timebase!)))

CMTimebaseSetRate(timebase!, 1.0) // Start/Resume recording

sleep(1)
print(CMTimeGetSeconds(CMTimebaseGetTime(timebase!)))

sleep(1)
CMTimebaseSetRate(timebase!, 0.0) // Pause Recording
print(CMTimeGetSeconds(CMTimebaseGetTime(timebase!)))


sleep(1)
print(CMTimeGetSeconds(CMTimebaseGetTime(timebase!)))
Run Code Online (Sandbox Code Playgroud)

所以这个对象真的很有用。当我将速率设置为 1.0 时,它开始与 masterClock 同步测量时间。当我将速率设置为 0.0 时,它会停止测量时间。我还注意到我可以将计时器附加到该对象。不幸的是,根本没有关于 Core Media 内容的好的教程,只有 Apple 网站上的一些 api 文档。有谁知道 WWDC 是否有关于 CoreMedia 框架相关主题的优秀教程/视频?

Tim*_*ull 5

当您处理 AVCaptureAudioOutput 时,您现在正在使用示例缓冲区。无论是视频还是音频,您都需要两个关键信息:样本数据和样本数据的录制时间。

这是“时钟” https://developer.apple.com/reference/coremedia/cmclock

时钟代表时间信息源:通常是测量时间流逝的硬件。

它非常准确,这就是重点。它是只读的,您只能从中获取引用而无法设置它。缓冲区可能会发生各种各样的事情,它们会排队,它们可以通过网络转发,但如果您有 CMTime 引用,它们可以被重建为正确的顺序和正确的时间。

CMSync 是处理时钟漂移(报告值略有不同的两个不同时钟之间)的函数子集。你完全不需要担心这些。

其实做自己想做的事很简单。这是一个可以剪切并粘贴到游乐场中的示例。

import AVFoundation

let masterClock : CMClock = CMClockGetHostTimeClock()
let startTime : CMTime = CMClockGetTime(masterClock)
sleep(1)
let endTime : CMTime = CMClockGetTime(masterClock)
let difference : CMTime = CMTimeSubtract(endTime, startTime)
let seconds = CMTimeGetSeconds(difference)
Run Code Online (Sandbox Code Playgroud)

这应该会给你一个略大于 1 的秒值。

当您单击应用程序中的录制按钮时,获取 AVCaptureSession 时钟并捕获 startTime。

当您想要更新 UI 时,只需再次检查 AVCaptureSession 时钟,减去两个 CMTime 并转换为秒。

只需确保您不会更新每个样本缓冲区上的 UI,这会太频繁,因此可能仅每 14,000 个样本左右(或任何适用于您正在使用的音频的频率)更新一次。还要确保将其卸载到单独的线程。

希望这对时钟有所帮助并解释一些。祝你好运!