应用速率大于 2 倍时 avplayer 的播放不稳定

Jerky playback from avplayer on Applying Rate greater than 2x

我想调整 Avplayer 速率,我可以在

的帮助下完成
[_avplayer play];
[_avplayer setRate:1.5];

也禁用音轨,小于2.0时运行很好。 但是当我们应用它大于 2 倍时,它会导致视频断断续续或抖动。

当我用谷歌搜索时 - 我发现这个 link 暗示了相同的行为

https://developer.apple.com/library/content/qa/qa1772/_index.html

Playing at rates greater than 2.0 can result in jerky or choppy playback when the data rate or other processing requirements of playing at the specified rate exceeds the ability of AVFoundation to keep up. In those cases, AVPlayer automatically degrades the quality of playback in order to keep up, employing a tier of fallback strategies depending on prevailing conditions. One tier of degradation is to decode and display only I-frames within the video substream, and this can indeed appear to be choppy.

任何人都可以提供帮助吗?我应该使用什么方法来实现同样的目标?

您可以尝试一些方法:

  1. 降低视频的帧率
  2. 向您的视频添加更多 I 帧(考虑到 QA-1772's advice,这可能有点不正常)
  3. 以较低的分辨率解码(或更好?编码)视频
  4. 降低视频的比特率
  5. 测量比实时 AVAssetReader 解码速度快多少,如果您认为某些性能已经丢失,则用您自己的 Metal + AVAssetReader 路径替换 AVPlayer在途中。如果您走这条路,也不要忘记考虑音频。

正如@Rhythmic 所建议的那样,这些方法都可以实现,但是这些都有些麻烦。我在谷歌上搜索了更多并找到了一种方法并且它工作得很好没有混蛋或断断续续。

就是不要设置费率,这样设置费率。首先创建 AVPlayer 、 AVPlayerItem 和 AVAsset 的实例。

  AVMutableComposition *composition = [AVMutableComposition composition];
        NSError *error = nil;
        [composition insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
                             ofAsset:asset
                              atTime:kCMTimeZero error:&error];
        [composition scaleTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
                         toDuration:CMTimeMultiplyByFloat64(asset.duration, 1 / rate)];
        AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:composition];
        self.avRefPlayer = [AVPlayer playerWithPlayerItem:playerItem];

        self.avRefPlayerLayer = [AVPlayerLayer layer];

        [self.avRefPlayerLayer setPlayer:self.avRefPlayer];
        [self.avRefPlayerLayer setFrame:_refrencedView.bounds];
        [self.avRefPlayerLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];

此代码甚至可以轻松支持超过 2 倍或 4 倍的速度。

这似乎是 AVFoundation 中的错误。对于许多视频,它可以 以快速流畅的速度播放,而在大多数情况下,它不能。例如,可以使用 AVPlayerView 的浮动控制器样式来显示 fast-forward 按钮。重复单击此按钮可实现流畅、快速的播放,而仅设置 AVPlayer.rate 则不会。

在我对 this question 的回答中,我解释了这个问题的解决方法。

谢谢 Kshitij Godara。

转换为Swift 4.

let timeRange = CMTimeRangeMake(kCMTimeZero, CMTime(seconds: videoDuration, preferredTimescale: 1))
let composition = AVMutableComposition()
try composition.insertTimeRange(timeRange,
                               of: asset,
                               at: kCMTimeZero)
composition.scaleTimeRange(timeRange, toDuration: CMTimeMultiplyByFloat64(asset.duration, Float64(1.0 / rate)))
let playerItem = AVPlayerItem(asset: composition)
let player = AVPlayer(playerItem: playerItem)
player.play()

如果想切换0~4的rate,可以初始化一个已经scale duration为1/2的AVMutableComposition,然后在播放时设置rate为0~2。