web-dev-qa-db-ja.com

AVPlayer seekToTimeが正しい位置で再生されない

HLSビデオストリームを再生しているAVPlayerがあります。ユーザーインターフェイスには、ビデオの各「チャプター」に1つずつ、一連​​のボタンが用意されています(ボタンには「1」、「2」、「3」というラベルが付いています)。アプリは、秒単位で表されたチャプターカットインポイントのリストを含むサーバーからメタデータをダウンロードします。たとえば、1本のビデオの長さは12分です。チャプターカットインポイントのリストは0、58、71、230、530などです。

ユーザーが「チャプターボタン」の1つをタップすると、ボタンハンドラーコードは次のようになります。

            [self.avPlayer pause];

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

「seekTime」は、カットインポイントを含むローカル変数です(上記のとおり)。

問題は、ビデオが常に正しいポイントから始まるとは限らないことです。時々そうします。ただし、要求されたseekTimeの1/10秒から2秒前の場合もあります。要求されたseekTimeの後に開始されることはありません。

ここにビデオエンコーディングに関するいくつかの統計があります:

エンコーダー:handbrakeCLIコーデック:h.264フレームレート:24(実際には23.976-撮影方法と同じ)ビデオビットレート:複数のビットレート(64/150/300/500/800/1200)オーディオビットレート:128kキーフレーム:23.976( 1秒あたり1)

もちろん、Apple mediafilesegmenterツールと、variantplaylistcreatorを使用してプレイリストを生成しています。

ファイルは、Amazon Cloud/S3バケットから提供されています。

不明な点の1つはCMTimeMakeWithSecondsです-読んださまざまな記事/ドキュメントに基づいていくつかのバリエーションを試しました。たとえば、上記の抜粋で私が使用しています:

CMTimeMakeWithSeconds(seekTime、600)

私も試しました:

CMTimeMakeWithSeconds(seekTime、1)

どちらが正しいのかわかりませんが、どちらも同じ一貫性のない結果を生み出すようです!

私も試しました:

CMTimeMakeWithSeconds(seekTime、23.967)

一部の記事では、これが分子/分母のように機能すると主張しているため、「n」は秒数です(CMTimeMakeWithseconds(n、1)のように)n/1は正しいはずです。ただし、コードは元々は別のプログラマー(現在は存在しません)によって作成され、preferredTimeScaleに600の数値を使用しました(つまり、CMTimeMakeWithseconds(n、600))。

誰かが私が間違っていることについての手がかりを提供できますか、または私が達成しようとしている種類の精度が可能であっても、

誰かが「代替」ソリューションを提供するように誘惑された場合、ビデオを章ごとに1つずつ別々のストリームに分割することをすでに検討していますが、章の変更に時間がかかるという意味で同じパフォーマンスが得られるとは考えていません。新しいAVPlayerItemが作成され、ロードされる必要があるためなどです。したがって、これが機能する唯一のソリューションであると考える場合(そして、これが私たちが望む結果を達成すると期待しています。つまり、各チャプターは私たちがそれをしたいところから正確に始めてください)そう言ってください.

前もって感謝します!

30
Jordan Bigel
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 */
}
83

私の提案:1)[avplayer seekToTime:leranceBefore:leranceAfter:]を使用しないでください。これにより、シーク時間が4〜5秒遅れます。

2)HLSビデオがセグメントごとに10秒にカットされます。チャプター開始位置は、10の倍数である値に適合している必要があります。セグメントがIフレームで始まるため、このようにして、迅速なシーク時間と正確な時間を得ることができます。

3
Ron

[player seekToTime:CMTimeMakeWithSeconds(seekTime,1)]のような関数を使用してください。
許容値kCMTimeZeroはシークに時間がかかるため。kCMTimeZeroの許容値を使用する代わりに、以前に指定した関数と同等のkCMTimeIndefiniteを使用できます。

1
prajul

このコードを入力すると、問題が解決する場合があります。

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