AVPlayer seekToTime未在正确位置播放



我有一个AVPlayer,它正在播放HLS视频流。我的用户界面提供了一行按钮,视频中的每个"章节"都有一个按钮(按钮标记为"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"是包含切入点的局部var(如上所述)。

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

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

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

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

这些文件是从亚马逊云/S3存储桶中提供的。

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

CMTimeMakeWithSeconds(参见时间,600)

我也试过:

CMTimeMakeWithSeconds(参见时间,1)

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

我也试过:

CMTimeMakeWithSeconds(参见时间,23.967)

有些文章声称这就像一个分子/分母,所以n/1应该是正确的,其中"n"是秒数(如CMTimeMakeWithseconds(n,1))。但是,该代码最初是由另一位程序员创建的(他现在已经去世了),他使用600数字作为首选TimeScale(即CMTimeMakeWithseconds(n600))。

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

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

提前感谢!

int32_t timeScale = self.player.currentItem.asset.duration.timescale;
CMTime time = CMTimeMakeWithSeconds(77.000000, timeScale);
[self.player seekToTime:time toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];

我对"seekToTime"有问题。我用这个代码解决了我的问题。"时间刻度"是解决这个问题的诀窍。

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 */
}

我的建议:1) 不要使用[avplayer seekToTime:toleranceBefore:tolerance After:],这会将您的寻道时间延迟4-5秒。

2) HLS视频剪辑为每段10秒。你的章节起始位置应该符合10的倍数。当片段以I帧开始时,通过这种方式,您可以获得快速查找时间和准确时间。

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

把这段代码放进去,它可能会解决你的问题。

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

Swift5

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

最新更新