【问题标题】:AVPlayer seekToTime does not play at correct positionAVPlayer seekToTime 不在正确位置播放
【发布时间】:2012-07-12 20:28:27
【问题描述】:

我有一个正在播放 HLS 视频流的 AVPlayer。我的用户界面提供了一排按钮,视频中的每个“章节”都有一个按钮(按钮标记为“1”、“2”、“3”)。该应用程序从服务器下载一些元数据,其中包含以秒为单位的章节切入点列表。例如,一个视频时长为 12 分钟 - 章节切入点列表为 0、58、71、230、530 等。

当用户点击“章节按钮”之一时,按钮处理程序代码执行以下操作:

            [self.avPlayer pause];

    [self.avPlayer seekToTime: CMTimeMakeWithSeconds(seekTime, 600) 
              toleranceBefore: kCMTimeZero 
               toleranceAfter: kCMTimeZero 
            completionHandler: ^(BOOL finished) 
            {
                [self.avPlayer play];
            }];

其中“seekTime”是一个包含切入点的本地变量(如上所述)。

问题在于视频并不总是从正确的位置开始。有时确实如此。但有时它在请求的 seekTime 之前的十分之一秒到 2 秒之间。它永远不会在请求的 seekTime 之后开始。

以下是视频编码的一些统计数据:

编码器:handbrakeCLI 编解码器:h.264 帧速率:24(实际上是 23.976 - 与拍摄方式相同) 视频比特率:多种比特率(64/150/300/500/800/1200) 音频比特率:128k 关键帧:23.976(每秒 1 个)

当然,我正在使用 Apple mediafilesegmenter 工具和 variantplaylistcreator 来生成播放列表。

文件是从 Amazon Cloud/S3 存储桶提供的。

我仍然不清楚的一个领域是 CMTimeMakeWithSeconds - 我已经根据我阅读的不同文章/文档尝试了几种变体。例如,在上面的摘录中我使用的是:

CMTimeMakeWithSeconds(seekTime, 600)

我也试过了:

CMTimeMakeWithSeconds(seekTime, 1)

我不知道哪个是正确的,尽管两者似乎产生了相同的不一致结果!

我也试过了:

CMTimeMakeWithSeconds(seekTime, 23.967)

一些文章声称这就像一个分子/分母,所以 n/1 应该是正确的,其中“n”是秒数(如 CMTimeMakeWithseconds(n, 1))。但是,该代码最初是由另一个程序员(现在已经离开)创建的,他使用 600 数字作为首选时间刻度(即 CMTimeMakeWithseconds(n, 600))。

任何人都可以提供任何线索来说明我做错了什么,或者即使我试图达到的准确度是可能的吗?

如果有人想提供“替代”解决方案,我们已经在考虑将视频分成单独的流,每章一个,但我们不认为这会给我们带来与更改章节相同的性能将需要更长的时间,因为必须创建和加载一个新的 AVPlayerItem 等等等等。所以如果你认为这是唯一可行的解​​决方案(我们确实希望这会达到我们想要的结果 - 即。每一章都会从我们想要的地方开始)随意说出来。

提前致谢!

【问题讨论】:

    标签: ios video-streaming avplayer


    【解决方案1】:

    请使用[player seekToTime:CMTimeMakeWithSeconds(seekTime,1)]等函数。
    因为您的容差值kCMTimeZero 将需要更多时间来寻找。您可以使用 kCMTimeIndefinite 而不是使用 kCMTimeZero 的容差值,它与我之前指定的功能等效。

    【讨论】:

    • 很抱歉,这如何回答这个问题?
    • 错了。时间刻度为 1 意味着您只能指定要搜索的整秒。时间刻度是每秒的零件数。正如 Apple 建议的那样,将 600 用于视频,因为它是常见视频帧速率(例如每秒 50、60、25 和 24 帧)的产物。
    【解决方案2】:

    我的建议: 1)不要使用[avplayer seekToTime:toleranceBefore:toleranceAfter:],这会延迟你的搜索时间4-5秒。

    2) HLS 视频剪辑为每段 10 秒。您的章节起始位置应适合 10 的倍数。由于分段以 I 帧开始,这样您可以获得快速的查找时间和准确的时间。

    【讨论】:

    • 如果不使用`[avplayer seekToTime:toleranceBefore:toleranceAfter:]`那么应该使用什么方法呢?
    • 我不同意这一点。问题是“AVPlayer seekToTime 没有在正确的位置播放”。通过将 toleranceBefore: toleranceAfter: 参数添加到 seekToTime() 设置为 kCMTimeZero,您将解决此问题,因此这是问题的正确答案。如果不使用这个,播放器从哪里开始是任意的。
    • 感谢您指出这一点,我用替代方法解决了滞后问题。
    • 我将--segment-duration=10 选项与bento4 mp4hls 一起使用,似乎已经解决了,干杯
    【解决方案3】:
    int32_t timeScale = self.player.currentItem.asset.duration.timescale;
    CMTime time = CMTimeMakeWithSeconds(77.000000, timeScale);
    [self.player seekToTime:time toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
    

    “seekToTime”有问题。我用这段代码解决了我的问题。 'timescale' 是解决这个问题的窍门。

    Swift 版本:

    let playerTimescale = self.player.currentItem?.asset.duration.timescale ?? 1
    let time =  CMTime(seconds: 77.000000, preferredTimescale: playerTimescale)
    self.player.seek(to: time, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero) { (finished) in /* Add your completion code here */
    }
    

    【讨论】:

    • @jordan-bigel 这应该被选为正确答案。
    • 不错的解决方案@Muhmd
    • 谢谢,你也救了我。
    • This 解释了为什么这个解决方案有效。重点是它不适用于seekToTime:,但也必须实现零容忍。
    • self.player.currentItem?.duration.timescale 有用吗?还是需要访问asset
    【解决方案4】:

    输入此代码可能会解决您的问题。

    let targetTime = CMTimeMakeWithSeconds(videoLastDuration, 1) // videoLastDuration hold the previous video state.
    self.playerController.player?.currentItem?.seekToTime(targetTime, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)
    

    【讨论】:

      【解决方案5】:

      Swift5

      let seconds = 45.0
      let time = CMTimeMake(value: seconds, timescale: 1)
      player?.seek(to: time, toleranceBefore: CMTime.zero, toleranceAfter: CMTime.zero)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-09-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多