如何在使用AVPlayer时提高seek的性能

4
我正在使用AVPlayer创建视频播放器,但是seekToTime方法非常缓慢。我对苹果公司的应用程序“照片”所展示的快速搜索性能印象深刻。有人知道苹果是如何实现这样快速的搜索吗?
这是否与线程有关?我尝试将seekToTime调用放入一个调度队列中,但也没有帮助。

如果您能提供一些实现的示例代码,我认为人们会更清楚哪些方面需要改进。 - kchromik
嗨@kcpac,实际上我已经找到了解决方案。我试图让用户使用滑块控件来浏览视频。如果我使用seekToTime进行浏览,速度会相当慢。我应该使用AVPlayerItem中的stepByCount方法。 - Zhiqiang Li
3个回答

2

我已经找到了解决方案。

如果我使用seekToTime进行快进/倒退,速度会相当慢。我应该使用AVPlayerItem中的一个名为stepByCount的方法。


3
给出[playerItem stepByCount:x];的示例,我们需要在x的位置上写什么来重新开始同一个视频。 我们需要在x的位置上用0来重新开始同一个视频。 - Kumar

0
实现像苹果标准iOS用户界面中那样流畅的搜索需要结合几个技巧:
1. 如上所述,您需要在不取消待处理搜索的情况下链接搜索。这是必要的,否则如果搜索请求不断被取消,播放器将无法向前移动。
2. 在搜索操作期间,播放器必须暂停。当最后一个搜索请求结束时,您可以恢复预期的播放速率。
3. 根据AVPlayerItem声明的功能,您应该按照以下方式调整搜索容忍度:
如果项目从canStepForward返回true,则使用.zero作为两个容差进行搜索。这为此类内容提供了逐步搜索的用户体验。
如果项目从canPlayFastForward返回true,则使用.zero作为toleranceBefore,并使用.positiveInfinity作为toleranceAfter进行搜索。这确保播放器可以使用可用的I帧播放列表以获得更快的搜索用户体验(技巧模式)。
否则,只需使用.positiveInfinity作为两个容差进行搜索,因为这样可以确保播放器尽快到达所需位置(但没有额外的好处)。
请注意,以上内容据我所知并非由苹果官方记录。我只是简单地观察了 iOS 16+ 上 AVPlayerViewController 的行为,以及在不同类型的流中进行定位时所使用的附加 AVPlayer
您可以查看我们在 GitHub 上的实现细节。

0

这段代码来自于:https://developer.apple.com/library/archive/qa/qa1820/_index.html

它能够提供一些帮助,使得快进看起来很顺畅。但是快退仍然需要花费太多时间(这里的 SeekToTime在向前跳转时表现良好,但向后跳转时却会出现卡顿,这就是为什么)。

import AVFoundation
 
class MyClass {
 
    var isSeekInProgress = false
    let player = <#A valid player object #>
    var chaseTime = kCMTimeZero
    // your player.currentItem.status
    var playerCurrentItemStatus:AVPlayerItemStatus = .Unknown
 
    ...
 
    func stopPlayingAndSeekSmoothlyToTime(newChaseTime:CMTime)
    {
        player.pause()
 
        if CMTimeCompare(newChaseTime, chaseTime) != 0
        {
            chaseTime = newChaseTime;
 
            if !isSeekInProgress
            {
                trySeekToChaseTime()
            }
        }
    }
 
    func trySeekToChaseTime()
    {
        if playerCurrentItemStatus == .Unknown
        {
            // wait until item becomes ready (KVO player.currentItem.status)
        }
        else if playerCurrentItemStatus == .ReadyToPlay
        {
            actuallySeekToTime()
        }
    }
 
    func actuallySeekToTime()
    {
        isSeekInProgress = true
        let seekTimeInProgress = chaseTime
        player.seekToTime(seekTimeInProgress, toleranceBefore: kCMTimeZero,
                toleranceAfter: kCMTimeZero, completionHandler:
        { (isFinished:Bool) -> Void in
 
            if CMTimeCompare(seekTimeInProgress, chaseTime) == 0
            {
                isSeekInProgress = false
            }
            else
            {
                trySeekToChaseTime()
            }
        })
    }
 
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接