iOS 自录制开始以来更新录制时间的正确方法

标签 ios iphone avfoundation avcapturesession avassetwriter

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

Mic -> AVCaptureDeviceInput -> AVCaptureSession -> AVCaptureAudioDataOutput

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

var currentTime: TimeInterval
// The time, in seconds, since the beginning of the recording.

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

现在在这个新管道中我没有这个属性,我想知道我是否遗漏了什么并且无法在任何地方找到它。我还注意到 AVCaptureSession 具有名为 masterClock 的 CMClock 属性,但我不确定如何使用它来计算时间,从录制开始。

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

CMClockGetHostTimeClock()
CMSyncConvertTime

AVCaptureAudioDataOutputSampleBufferDelegate方法中如何根据sampleBuffer获取开始录音后的秒数?

更新

我发现了一个名为 CMTimebase 的类,我认为这正是我要找的东西。目前我不知道如何使用它,但我在 Playground 上做了一些实验后发现了什么。

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!)))

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

最佳答案

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

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

A clock represents a source of time information: generally, a piece of hardware that measures the passage of time.

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

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

其实做自己想做的事很简单。下面是一个示例,您可以将其剪切并粘贴到 Playground 中。

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)

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

当您单击应用程序中的记录按钮时,获取 AVCaptureSession 时钟并捕获开始时间。

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

只需确保您没有在每个样本缓冲区上更新 UI,那样会太频繁,所以也许每 14,000 个样本左右(或任何适用于您正在使用的音频的频率)才更新一次。还要确保将其卸载到单独的线程。

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

关于iOS 自录制开始以来更新录制时间的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40384771/

相关文章:

ios - AVFoundation 相机变焦

video - AVfoundation 反向视频

ios - 我得到一个错误 - nib 必须恰好包含一个顶级对象,它必须是一个 UITableViewCell 实例'”

ios - ViewControllers 作为实例变量

iphone - 如何在 iPhone 应用程序中使用 Dropbox Api 共享文档?

ios - 恢复 iOS 应用程序源代码文件?

iOS:如何获取 iOS 9 的服务包 header ?

iphone - Dropbox 应用程序,例如视频和音频预览

swift - AVPlayer 无法加载通过 xcode 重新运行应用程序后保存的 .mov 文件

ios - 在 IOS 中从本地存储存储和检索 JSON 数据