使用 AV 播放器访问单个帧

use*_*305 5 video avfoundation ios avplayer swift

在最近的一个项目中,我必须使用 AV Foundation 单独访问我的视频的所有帧。此外,如果可能的话,随机访问它们(如数组)

我试图研究这个问题,但没有得到任何有用的信息。

注意:是否有任何有用的文档来熟悉 AV Foundation ?

Rhy*_*man 8

您可以使用 连续枚举视频的帧AVAssetReader,如下所示:

let asset = AVAsset(URL: inputUrl)
let reader = try! AVAssetReader(asset: asset)

let videoTrack = asset.tracksWithMediaType(AVMediaTypeVideo)[0]

// read video frames as BGRA
let trackReaderOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings:[String(kCVPixelBufferPixelFormatTypeKey): NSNumber(unsignedInt: kCVPixelFormatType_32BGRA)])

reader.addOutput(trackReaderOutput)
reader.startReading()

while let sampleBuffer = trackReaderOutput.copyNextSampleBuffer() {
    print("sample at time \(CMSampleBufferGetPresentationTimeStamp(sampleBuffer))")
    if let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) {
        // process each CVPixelBufferRef here
        // see CVPixelBufferGetWidth, CVPixelBufferLockBaseAddress, CVPixelBufferGetBaseAddress, etc
    }
}
Run Code Online (Sandbox Code Playgroud)

随机访问比较复杂。您可以使用AVPlayer+AVPlayerItemVideoOutput从任何时间获取帧t,使用copyPixelBufferForItemTime如本答案中所述,但微妙之处在于您如何选择它t

如果您想以统一的间隔对视频进行采样,那么这很容易,但是如果您想获得与串行AVAssetReader代码看到的相同的帧/演示时间戳,那么您可能必须使用 AVAssetReader, 对文件进行预处理以构建一个帧数字 -> 演示时间戳映射。这可能是快,如果你跳过使用解码nil输出设置AVAssetReaderTrackOutput