我正在开发一个可播放视频并允许用户在视频中前后滑动的应用程序。清理必须顺利进行,因此我们始终使用带有视频压缩属性SDAVAssetExportSessionAVVideoMaxKeyFrameIntervalKey:@1重写视频,以便每个帧都将成为关键帧并允许平滑的反向清理。这样效果很好,并提供了流畅的播放。该应用程序使用来自各种来源的视频,并且可以录制在android或iOS设备上,甚至可以从网络上下载并添加到该应用程序中,因此我们最终得到了完全不同的编码,其中某些编码已经适合进行擦洗(每个帧)是关键帧)。有没有一种方法可以检测视频文件的关键帧间隔,从而避免不必要的视频处理?我已经阅读过许多AVFoundation的文档,但没有找到一种明显的方式来获取此信息。感谢您对此的任何帮助。

最佳答案

如果您可以通过使用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.这仅适用于本地文件资产。

ps。您不会说自己如何擦洗或玩耍。 AVPlayerViewControllerAVPlayer吗?

关于ios - 在AVAsset中检测当前关键帧间隔,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43333313/

10-09 01:45
查看更多