通过AVFoundation获取视频中的帧数

时间:2012-11-30 12:30:12

标签: swift macos avfoundation

我正在尝试查找刚刚打开的视频中的帧数,而不解码所有帧。

我使用AVAsset打开,然后获得视频的AVAssetTrack。下一步是什么?

4 个答案:

答案 0 :(得分:5)

执行此操作的一种相对昂贵的方法是使用AVAssetReader读取所有帧并随时计算它们。

let asset = AVAsset(url: url)
let assetTrack = asset.tracksWithMediaType(AVMediaTypeVideo).first!
let assetReader = try! AVAssetReader(asset: self)
let assetReaderOutputSettings = [
    kCVPixelBufferPixelFormatTypeKey as String: NSNumber(unsignedInt: kCVPixelFormatType_32BGRA)
]
let assetReaderOutput = AVAssetReaderTrackOutput(track: assetTrack, outputSettings: assetReaderOutputSettings)
assetReaderOutput.alwaysCopiesSampleData = false
assetReader.addOutput(assetReaderOutput)
assetReader.startReading()

var frameCount = 0
var sample: CMSampleBufferRef? = assetReaderOutput.copyNextSampleBuffer()

while (sample != nil) {
    frameCount++
    sample = assetReaderOutput.copyNextSampleBuffer()
}

// now you have frame count
print(frameCount)

答案 1 :(得分:4)

你可以这样做:

float durationInSeconds = CMTimeGetSeconds(asset.duration);
float framesPerSecond = assetTrack.nominalFrameRate;
float numberOfFrames = durationInSeconds * framesPerSecond;

答案 2 :(得分:2)

已更新为 Swift 4.2 ,并转换为URL的扩展名。

import AVFoundation

extension URL {
    var videoFrameCount: Int? {
        let asset = AVAsset(url: self)
        guard let assetTrack = asset.tracks(withMediaType: .video).first else {
            return nil
        }

        var assetReader: AVAssetReader?
        do {
            assetReader = try AVAssetReader(asset: asset)
        } catch {
            print(error.localizedDescription)
            return nil
        }

        let assetReaderOutputSettings = [
            kCVPixelBufferPixelFormatTypeKey as String: NSNumber(value: kCVPixelFormatType_32BGRA)
        ]
        let assetReaderOutput = AVAssetReaderTrackOutput(track: assetTrack,
                                                         outputSettings: assetReaderOutputSettings)
        assetReaderOutput.alwaysCopiesSampleData = false
        assetReader?.add(assetReaderOutput)
        assetReader?.startReading()

        var frameCount = 0
        var sample: CMSampleBuffer? = assetReaderOutput.copyNextSampleBuffer()

        while (sample != nil) {
            frameCount += 1
            sample = assetReaderOutput.copyNextSampleBuffer()
        }

        return frameCount
    }
}

如果能够将URL转换为类型AVAsset的{​​{1}},则会继续。否则,返回值video

接下来,创建nil。如果此步骤失败,它将再次返回AVAssetReader

由于所有内容都已正确设置,现在它将继续解析输出并计算帧数。只要生成nil,循环将继续帧计数递增。一旦不再生成样本,它将终止循环并返回sample的值。

答案 3 :(得分:0)

尽管使用Checkbutton + main.iconify() global motor_wire motor_wire = Toplevel(main) motorframe = LabelFrame(motor_wire, text="SIZE OF WIRE", font = ('Garamond', '25', 'bold', 'underline'), padx = 270, pady = 167, bd = 8) motorframe.place(x = 30, y = 5) Label(motorframe).pack() thirteen = Checkbutton(motor_wire, text = '#13',font=("Calibri", '30', 'bold'), relief = 'groove' , bd = 5,padx = 0, pady = 5).place(x = 52, y = 50) fourteen = Checkbutton(motor_wire, text = '#14',font=("Calibri", '30', 'bold'),relief = 'groove' , bd = 5,padx = 0, pady = 5).place(x = 189, y = 50) fifteen = Checkbutton(motor_wire, text = '#15',font=("Calibri", '30','bold'),relief = 'groove' , bd = 5, padx = 0, pady = 5).place(x = 326, y = 50) 的解决方案是正确的,但我建议使用AVAssetReader输出设置来创建AVAssetReaderTrackOutput。这样AVAssetReaderTrackOutput不会解压缩帧,您可以更快地得到结果。

这是一个示例实现:

nil