【问题标题】:Swift AVPlayer seekToTime issueSwift AVPlayer seekToTime 问题
【发布时间】:2016-11-23 08:41:28
【问题描述】:

我有这个代码:

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 rap表示我不会寻找的正确秒数。 抱歉英语不好,我是意大利人

【问题讨论】:

    标签: ios swift cocoa-touch avplayer avplayerviewcontroller


    【解决方案1】:

    对于AVPlayer,有不同的方式让游戏寻找时间;

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

    对于这种方法,玩家会快速寻找到 seekTime 而不是寻找 seekTime 的确切位置,这意味着 seekTime 会有一些偏移

    Apple 的文档

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

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

    如需准确求样,请参见 seekToTime:toleranceBefore:toleranceAfter:。

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

    对于这个方法,玩家会快速寻找到seekingTime,而且,有了offset,你可以用completionHandler做一些事情

    Apple 的文档

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

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

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

    完成处理程序将在finished参数设置为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#>)
    

    这种方法会让播放器搜索到你要求的指定时间,但会更慢(嗯..主要取决于当前媒体)

    Apple 的文档

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

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

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

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

    我注意到您当前正在使用

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

    你可以试试用这个方法来求指定时间 (当然更慢)

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

    希望能帮到你

    【讨论】:

      【解决方案2】:

      在 Swift 4.2 和 Xcode 10.1 中

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

      【讨论】:

        【解决方案3】:

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

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

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

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

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

        【讨论】:

          【解决方案4】:

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-09-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-05-18
            相关资源
            最近更新 更多