Swift AVPlayer seekToTime 问题

Swift AVPlayer seekToTime issue

我有这个代码:

let punto = sender.locationInView(self.barraVideo).x
        let larghezzaImg : Double = Double((self.barraVideoInvisTocco?.frame.width)!)

        let percTocco : Double = (100 / larghezzaImg) * Double(punto)

        let lunghezzaVideo : Double = Double(CGFloat((avPlayer?.currentItem?.asset.duration.value)!) / CGFloat(1000.0));
        let frameRate : Int32 = (avPlayer?.currentItem?.currentTime().timescale)!

        let secondo : Float64 = Float64((lunghezzaVideo/100)*percTocco)
        print("Val : \(secondo)");

        avPlayer?.currentItem?.seekToTime(CMTimeMakeWithSeconds(secondo, frameRate))

        avPlayer?.play()
        videoInPlay = true;
        playPauseBtn!.image = UIImage(named: "iconaPausa.png")!;

接收在 seekBar 上点击的 x 坐标并搜索视频。 该代码适用于日志视频,但适用于短视频。 当我点击短视频时,AVPlayer 只在视频的开头或结尾附近寻找,而不是在中间

打印:

Val : 3.36008475976495
Val : 7.14189817632069
Val : 13.3303201306846
Val : 3.70388597945183
Val : 3.93308679257642
Val : 3.24548435320265
Val : 3.70388597945183
Val : 18.8311396456748
Val : 27.0823689181601
Val : 40.1468152662618
Val : 51.3776551093667
Val : 17.2267339538027
Val : 9.54850671412889
Val : 23.4151559081666
Val : 37.6256063218913

val rappresents 正确的秒数,我不会去寻找。 抱歉英语不好,我是意大利人

对于AVPlayer来说,有不同的方式让播放寻找时间;

player.seekToTime(<#time: CMTime#CMTime#>)

对于这种方法,播放器会快速寻找seekingTime,但不会寻找seekingTime的确切位置,这意味着seekingTime会有一些offset

苹果文档

使用此方法寻找当前播放器项目的指定时间。

寻求的时间可能与指定的效率时间不同。

示例精确查找见seekToTime:toleranceBefore:toleranceAfter:.

player.seekToTime(<#T##time: CMTime##CMTime#>, completionHandler: <#T##(Bool) -> Void#>)

对于这种方法,播放器将快速寻找 seekingTime,并且通过偏移量,您可以使用 completionHandler

苹果文档

使用此方法为当前播放器项目搜索到指定时间,并在搜索操作完成时收到通知。

任何仍在处理中的先前搜索请求的完成处理程序将使用完成的参数立即调用

设置为否。如果新请求完成而没有被另一个搜索请求或任何其他指定的操作中断

完成处理程序将被调用,完成的参数设置为 YES。

如果想求的更准确,用下面的方法代替

player.seekToTime(<#T##time: CMTime##CMTime#>, toleranceBefore: <#T##CMTime#>, toleranceAfter: <#T##CMTime#>)

player.seekToTime(<#T##time: CMTime##CMTime#>, toleranceBefore: <#T##CMTime#>, toleranceAfter: <#T##CMTime#>, completionHandler: <#T##(Bool) -> Void#>)

此方法会让播放器在您要求的指定时间搜索,但速度会较慢(好吧..主要取决于当前媒体)

苹果文档

使用此方法寻找当前播放器项目的指定时间。

寻求的时间将在 [time-toleranceBefore, time+toleranceAfter] 范围内,可能与指定时间不同以提高效率。

为 toleranceBefore 和 toleranceAfter 传递 kCMTimeZero 以请求样本精确搜索,这可能会导致额外的解码延迟。

使用 beforeTolerance:kCMTimePositiveInfinity 和 afterTolerance:kCMTimePositiveInfinity 向此方法发送消息与直接向 seekToTime: 发送消息相同。

我注意到您当前使用的是

avPlayer?.currentItem?.seekToTime(CMTimeMakeWithSeconds(secondo, frameRate))

你可以试试用这个方法找指定的时间 (当然慢)

avPlayer?.currentItem?.seekToTime(CMTimeMakeWithSeconds(secondo, frameRate), toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)

希望能帮到你

我怀疑所提供的任何答案是否真的有效。试试这个:

技术问答QA1820 如何使用 AVPlayer seekToTime: 实现流畅的视频擦洗:?

问:我的应用程序允许用户结合使用滑块控件和 AVPlayer seekToTime: 来拖动视频文件:但是视频帧的显示存在相当大的延迟。如何实现更顺畅的擦洗?

A​​:避免快速连续调用 AVPlayer seekToTime:。这将取消正在进行的搜索,导致大量搜索而不是大量显示目标帧。相反,使用 AVPlayer seekToTime: 的完成处理程序变体,并等待正在进行的查找在发出另一个之前先完成。清单 1 和清单 2 给出了这种技术的示例(注意:这些示例假设已经创建了一个有效的播放器对象,并且播放器的当前项目状态正在通过键值观察来维护。有关更多信息,请参阅 AV Foundation Programming Guide):

使用 AVPlayer seekToTime 的完成处理程序变体:更平滑的擦洗(Swift)。

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()
            }
        })
    }

}

这对我有用。关键是将 kCMTimeZero 放在两个公差字段中。

player.seek(to: CMTimeMakeWithSeconds(value, duration), toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)

在 Swift 4.2 和 Xcode 10.1

player?.seek(to: CMTimeMakeWithSeconds(100, preferredTimescale: 1), toleranceBefore: CMTime.zero, toleranceAfter: CMTime.zero)