AVPlayer seekToTime无法在正确的位置播放

时间:2012-07-13 01:14:37

标签: ios video-streaming avplayer

我有一个播放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数字作为preferredTimeScale(即CMTimeMakeWithseconds(n,600))。

任何人都可以提供任何关于我做错的线索,或者即使我想要实现的那种准确性甚至可能吗?

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

提前致谢!

5 个答案:

答案 0 :(得分:82)

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 :(得分:3)

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

2)HLS视频每段缩短10秒。你的章节开始位置应该适合10的多重值。由于段以I帧开头,这样你就可以获得快速的寻道时间和准确的时间。

答案 2 :(得分:2)

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

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

Swift5

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