2012-07-13 120 views
27

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

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

  [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次)

我使用的是苹果mediafilesegmenter工具,当然,并生成播放列表中的variantplaylistcreator。

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

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

CMTimeMakeWithSeconds(seekTime,600)

我也曾尝试:

CMTimeMakeWithSeconds(seekTime,1)

我不能告诉哪个是正确的,虽然两者似乎产生相同的不一致的结果!

我也曾尝试:

CMTimeMakeWithSeconds(seekTime,23.967)

有些文章声称这就像一个分子/ denomenator,因此n/1应该是正确的,其中 'n' 是的秒数(如在CMTimeMakeWithseconds(n,1)中)。但是,代码最初是由另一位程序员创建的(他现在已经离开了),他使用600号码作为preferredTimeScale(即CMTimeMakeWithseconds(n,600))。

任何人都可以提供任何线索,我做错了什么,或者即使我试图达到的那种准确性甚至是可能的?

如果有人想要提供“替代”解决方案,我们已经在考虑将视频分成不同的流,每章一个,但我们不相信这会给我们提供相同的性能,由于必须创建和加载新的AVPlayerItem等,所以章节将花费更长的时间等等。因此,如果您认为这是唯一可行的解​​决方案(而且我们希望这将实现我们想要的结果 - 即每一章将开始在我们想要的位置)我们可以自由地这么说。

在此先感谢!

回答

2

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

+0

对不起,这是怎么回答的? – 2013-04-11 08:08:34

+1

错误。时间刻度为1意味着您只能指定整秒寻找。时间刻度是每秒钟的部分数量。正如Apple推荐的那样,视频采用600,因为它是每秒50,60,25和24帧等常见视频帧率的产品。 – 2015-10-27 02:41:25

3

我的建议: 1)请勿使用[avplayer seekToTime:toleranceBefore:toleranceAfter:],这会延迟您的寻找时间4-5秒。 2)将HLS视频剪辑为每段10秒。你的章节起始位置应该符合10的多值性。由于该段以I帧开始,因此可以快速找到时间和准确的时间。

+7

如果不使用'[avplayer seekToTime:toleranceBefore:toleranceAfter:]'那么应该使用什么方法? – Fennelouski 2015-02-04 18:06:20

+1

我不同意这一点。问题是“AVPlayer seekToTime无法播放正确的位置”。通过添加toleranceBefore:toleranceAfter:参数将seekToTime()设置为kCMTimeZero,您将解决此问题,因此这是问题的正确答案。如果你不使用这个,玩家开始的时候是任意的。 – Bocaxica 2015-11-17 16:17:10

+0

感谢您指出了这一点,我用替代方法解决了滞后问题。 – 2015-12-03 13:01:22

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

我遇到了'seekToTime'的问题。我用这段代码解决了我的问题。 '时间尺度'是这个问题的窍门。

+6

@ jordan-bigel这应该被选为正确的答案。 – 2016-01-14 02:56:21

+0

不错的解决方案@Muhmd – 2016-04-28 05:09:41

+0

感谢的人,它拯救了我的一天, – 2016-07-27 06:47:39

0

把这段代码可以解决你的问题。

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