我正在处理一个播放视频的应用程序,并允许用户在视频中前后擦除。清理必须顺利进行,因此我们始终使用SDAVAssetExportSession
重新编写视频压缩属性AVVideoMaxKeyFrameIntervalKey:@1
的视频,以便每个帧都是关键帧并允许平滑的反向清理。这很好用,并提供流畅的播放。该应用程序使用来自各种来源的视频,可以记录在Android或iOS设备上,甚至可以从网上下载并添加到应用程序中,因此我们最终得到了完全不同的编码,其中一些已经适合擦洗(每帧是一个关键帧)。有没有办法检测视频文件的关键帧间隔,以便我可以避免不必要的视频处理?我已经浏览了很多AVFoundation的文档,并没有看到明显的方法来获取这些信息。感谢您的帮助。
答案 0 :(得分:2)
如果您可以通过使用nil AVAssetReaderTrackOutput
创建outputSettings
来快速解析文件而不解码图像。您遇到的帧样本缓冲区具有包含具有有用信息的字典的附件数组,包括帧是否依赖于其他帧,或者其他帧是否依赖于它。我会将前者解释为表示一个关键帧,虽然它给了我一些低数字(一个文件中有4%的关键帧?)。无论如何,代码:
let asset = AVAsset(url: inputUrl)
let reader = try! AVAssetReader(asset: asset)
let videoTrack = asset.tracks(withMediaType: AVMediaTypeVideo)[0]
let trackReaderOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: nil)
reader.add(trackReaderOutput)
reader.startReading()
var numFrames = 0
var keyFrames = 0
while true {
if let sampleBuffer = trackReaderOutput.copyNextSampleBuffer() {
// NB: not every sample buffer corresponds to a frame!
if CMSampleBufferGetNumSamples(sampleBuffer) > 0 {
numFrames += 1
if let attachmentArray = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, false) as? NSArray {
let attachment = attachmentArray[0] as! NSDictionary
// print("attach on frame \(frame): \(attachment)")
if let depends = attachment[kCMSampleAttachmentKey_DependsOnOthers] as? NSNumber {
if !depends.boolValue {
keyFrames += 1
}
}
}
}
} else {
break
}
}
print("\(keyFrames) on \(numFrames)")
N.B。这仅适用于本地文件资产。
P.S。你不会说你是如何擦洗或玩耍的。 AVPlayerViewController
和AVPlayer
?
答案 1 :(得分:1)
以下是相同答案的Objective C版本。在实现并使用它之后,应该具有所有关键帧的视频将从此代码返回大约96%的关键帧。我不确定为什么,所以我使用这个数字作为决定因素,即使我希望它更准确。我也只是查看前600帧或视频结尾(以先到者为准),因为我不需要通读整整20分钟的视频来做出这个决定。
琀
爀
愀
渀
愀
戀
答案 2 :(得分:0)
在某些情况下,当ffprobe返回关键帧时,使用 kCMSampleAttachmentKey_DependsOnOthers 给了我0个关键帧。 为了获得与ffprobe相同数量的关键帧,我使用了:
if attachment[CMSampleBuffer.PerSampleAttachmentsDictionary.Key.notSync] == nil {
keyFrames += 1
}
在CoreMedia标头中说:
/// Boolean (absence of this key implies Sync)
public static let notSync: CMSampleBuffer.PerSampleAttachmentsDictionary.Key
对于dependsOnOthers键,它说:
/// `true` (e.g., non-I-frame), `false` (e.g. I-frame), or absent if
/// unknown
public static let dependsOnOthers: CMSampleBuffer.PerSampleAttachmentsDictionary.Key