我正在尝试查找刚刚打开的视频中的帧数,而不是解码所有帧。
我打开AVAsset
然后得到一个AVAssetTrack
视频。接下来是什么 ?
你可以这样做:
float durationInSeconds = CMTimeGetSeconds(asset.duration);
float framesPerSecond = assetTrack.nominalFrameRate;
float numberOfFrames = durationInSeconds * framesPerSecond;
一种相对昂贵的方法是使用 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)
这已更新到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
type video
,它将继续。否则,nil
返回一个值。
接下来,AVAssetReader
创建一个。如果此步骤失败,它将再次返回nil
。
由于一切都已正确设置,它现在将继续解析输出并计算帧数。只要sample
产生 a ,循环就会继续,帧计数会增加。一旦不再产生样本,它将终止循环并返回 的值frameCount
。
尽管使用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;
}