7

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

我打开AVAsset然后得到一个AVAssetTrack视频。接下来是什么 ?

4

4 回答 4

8

你可以这样做:

float durationInSeconds = CMTimeGetSeconds(asset.duration);
float framesPerSecond = assetTrack.nominalFrameRate;
float numberOfFrames = durationInSeconds * framesPerSecond;
于 2014-05-15T12:23:44.947 回答
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)
于 2016-01-15T03:12:03.050 回答
5

这已更新到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
    }
}

如果它能够将 转换URLAVAssettype video,它将继续。否则,nil返回一个值。

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

由于一切都已正确设置,它现在将继续解析输出并计算帧数。只要sample产生 a ,循环就会继续,帧计数会增加。一旦不再产生样本,它将终止循环并返回 的值frameCount

于 2017-03-10T03:03:16.267 回答
3

尽管使用AVAssetReader+的解决方案AVAssetReaderTrackOutput是正确的,但我建议AVAssetReaderTrackOutput使用nil输出设置进行创建。这样AVAssetReader就不会解压缩帧,并且您可以更快地获得结果。

这是一个示例实现:

int getNumberOfFrames(NSURL *url)
{
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil];

    AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];

    AVAssetReaderTrackOutput *readerVideoTrackOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:videoTrack outputSettings:nil];

    AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:asset error:nil];
    [assetReader addOutput:readerVideoTrackOutput];

    [assetReader startReading];

    int nframes = 0;
    for (;;)
    {
        CMSampleBufferRef buffer = [readerVideoTrackOutput copyNextSampleBuffer];
        if (buffer == NULL)
        {
            break;
        }

        CMFormatDescriptionRef formatDescription = CMSampleBufferGetFormatDescription(buffer);
        CMMediaType mediaType = CMFormatDescriptionGetMediaType(formatDescription);
        if (mediaType == kCMMediaType_Video)
        {
            nframes++;
        }

        CFRelease(buffer);
    }

    return nframes;
}
于 2019-02-27T04:30:18.870 回答