loopPointReachedで動画再生を検出しようとしたところ、以下の問題が発生
■発生条件
動画を再生した後のVideoSourceで別の新しい動画を再生しようとした時、前の動画の再生中frameが、新しい動画の総frameより大きな値になっている。
※たとえば動画(長さ60秒)を20秒部分まで再生した後、別の動画(長さ10秒)を再生した場合など。
loopPointReachedに1つでもコールバック関数が1つも登録されていなければ発生しない様子。
■発生する問題
①新しい動画の再生開始直後に.loopPointReachedに登録されている関数が呼ばれる。
②PrepareCompletedを検出してすぐに.Play()しても、再生されない
正確には.Play()でisPlaying=trueになるが、直後に①の問題が発生することで強制的にisPlaying=falseにされる様子。
■問題が発生するコード
Start()内で関数を登録
videoPlayer.prepareCompleted += VideoPlayerOnPrepareCompleted;
videoPlayer.loopPointReached += FinishPlayingVideo;
動画再生処理
public void MovieStart(string filename)
{
videoPlayer.url = mp4path + filename;
videoPlayer.Prepare();
}
Prepare完了時に再生
private void VideoPlayerOnPrepareCompleted(VideoPlayer source)
{
source.Play();
}
再生終了時の処理
private void FinishPlayingVideo(VideoPlayer vp)
{
Debug.Log("再生終了時の処理");
}
■回避策
新しい動画を再生する前に前の動画を.frame = 0して再生時間を戻したり、再生時間を戻した状態で.Playして数frame待つ処理を入れても安定しなかった。
試行錯誤したところ、問題を回避せずに、発生させた後に影響を軽減させる方が良さそう。
①PrepareCompletedの後、少しの間は、loopPointReachedによる「再生終了」のイベントを無視させる
②PrepareCompletedの後、少し待ってから.Play()しなおす処理を入れる
■回避策を反映したコード
Start()内処理や、動画の再生処理は変更不要。
フラグ用の変数を追加。
private bool FinishPlayingVideoFlag = false;
Prepare完了時にコルーチン実行
private void VideoPlayerOnPrepareCompleted(VideoPlayer source)
{
source.Play();
StartCoroutine(loopPointReachedBugFix_Coroutine());
}
Prepare完了後、最大で1.3秒間の間、勝手に.isPlaying が falseになる(=問題発生)ことを検出させる。
問題が発生した場合は、改めて.Playする。
この間、FinishPlayingVideoFlagフラグを立てておく
private IEnumerator loopPointReachedBugFix_Coroutine()
{
FinishPlayingVideoFlag = true;
float Timer = 0;
while (Timer < 1.3f)
{
yield return null;
if (!videoPlayer.isPlaying)
{
Debug.Log("即終了バグ回避処理");
videoPlayer.Play();
break;
}
Timer += Time.deltaTime;
}
FinishPlayingVideoFlag = false;
}
フラグが立っている場合は、再生終了の検出を無視する。
private void FinishPlayingVideo(VideoPlayer vp)
{
if (!FinishPlayingVideoFlag)
Debug.Log("再生終了時の処理");
}
loopPointReachedの誤検知が発生するタイミングはバラツキが多いが、色々な条件で試したところ、他処理の負荷やFPSに関わらず、PrepareCompletedの直後frame~最大0.65秒程度の範囲で発生していたので、余裕をもって倍の1.3秒としている。