检测AVAsset中的当前关键帧间隔

时间:2017-04-10 21:40:30

标签: ios avfoundation video-processing video-compression

我正在处理一个播放视频的应用程序,并允许用户在视频中前后擦除。清理必须顺利进行,因此我们始终使用SDAVAssetExportSession重新编写视频压缩属性AVVideoMaxKeyFrameIntervalKey:@1的视频,以便每个帧都是关键帧并允许平滑的反向清理。这很好用,并提供流畅的播放。该应用程序使用来自各种来源的视频,可以记录在Android或iOS设备上,甚至可以从网上下载并添加到应用程序中,因此我们最终得到了完全不同的编码,其中一些已经适合擦洗(每帧是一个关键帧)。有没有办法检测视频文件的关键帧间隔,以便我可以避免不必要的视频处理?我已经浏览了很多AVFoundation的文档,并没有看到明显的方法来获取这些信息。感谢您的帮助。

3 个答案:

答案 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。你不会说你是如何擦洗或玩耍的。 AVPlayerViewControllerAVPlayer

答案 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