6

我试图弄清楚如何通过 AVPlayer 检索视频帧速率。AVPlayerItem 有一个 rate 变量,但它只返回一个介于 0 和 2 之间的值(播放时通常为 1)。有人知道如何获得视频帧速率吗?

干杯

4

6 回答 6

16

使用AVAssetTrack's nominalFrameRate property.

下面的方法得到FrameRate:这里queuePlayerAVPlayer

-(float)getFrameRateFromAVPlayer
{
  float fps=0.00;
  if (self.queuePlayer.currentItem.asset) {
    AVAssetTrack * videoATrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] lastObject];
    if(videoATrack)
    {
        fps = videoATrack.nominalFrameRate;
    }
  }
  return fps;
}
于 2013-04-20T06:04:19.607 回答
4

Swift 4 版本的答案:

let asset = avplayer.currentItem.asset

let tracks = asset.tracks(withMediaType: .video)

let fps = tracks?.first?.nominalFrameRate

请记住处理 nil 检查。

于 2018-09-24T05:48:53.967 回答
2

对于在不同版本的 iOS 上播放的相同媒体,返回的这个nominalFrameRate 似乎存在差异。我有一个用 ffmpeg 以每秒 1 帧(125 帧)编码的视频,每 25 帧有一个关键帧,在 iOS 7.x 上的应用程序中加载时(标称)帧速率为 1.0,而在 iOS 8.x 上(标称)帧速率为 0.99。这似乎是一个非常小的差异,但是在我的情况下,我需要精确地导航到电影中的给定帧,而这种差异会破坏这种导航(电影是一系列演示幻灯片的编码)。鉴于我已经知道我的应用需要播放的视频的帧速率(例如 1 fps),我可以简单地依赖这个值而不是动态确定帧速率(通过nominalFrameRate 值),但是我想知道为什么 iOS 版本之间存在如此的差异,就这个nominalFrameRate 而言。有任何想法吗?

于 2015-02-23T00:08:58.690 回答
2

AVPlayer 上的速率值是相对于它正在播放的实时的速度,例如 0.5 是慢动作,2 是双倍速度。

正如 Paresh Navadiya 指出的那样,轨道也有一个nominalFrameRate 变量,但这似乎有时会产生奇怪的结果。到目前为止,我发现的最佳解决方案是使用以下内容:

CMTime frameDuration = [myAsset tracksWithMediaType:AVMediaTypeVideo][0].minFrameDuration;
float fps = frameDuration.timescale/(float)frameDuration.value;

上面给出了可变帧速率的稍微出乎意料的结果,但可变帧速率无论如何都有一些奇怪的行为。除此之外,它在我的测试中与 ffmpeg -i 匹配。

编辑 - -

我发现有时上面给出的时间是 kCMTimeZero。我为此使用的解决方法是创建一个带有轨道输出的 AVAssetReader,获取第一帧和第二帧的 pts,然后将两者相减。

于 2016-06-14T16:38:40.000 回答
1

我不知道有什么AVPlayer可以帮助您计算帧速率。

AVPlayerItem rate属性是播放速率,与帧速率无关。

更简单的选择是获取 aAVAssetTrack并读取其nominalFrameRate属性。只需创建一个AVAsset,您将获得一系列曲目。

或用于AVAssetReader逐帧读取视频,获取其呈现时间并计算同一秒内有多少帧,然后平均几秒钟或整个视频。

于 2012-05-22T10:16:41.237 回答
1

这不再起作用了,API 发生了变化,而且这篇文章已经过时了。:( swift 4 的答案也很酷,这个答案是相似的。

您从 获取视频轨道AVPlayerItem,然后检查那里的 FPS。:)

private var numberOfRenderingFailures = 0
func isVideoRendering() -> Bool {
    guard let currentItem = player.currentItem else { return false }

    // Check if we are playing video tracks
    let isRendering = currentItem.tracks.contains { ($0.assetTrack?.mediaType == .video) && ($0.currentVideoFrameRate > 5) }
    if isRendering {
        numberOfRenderingFailures = 0
        return true
    }
    numberOfRenderingFailures += 1
    if numberOfRenderingFailures < 5 {
        return true
    }
    return false
}
于 2019-07-23T13:51:16.923 回答