using UnityEngine; using UnityEngine.Playables; using UnityEngine.Video; [System.Serializable] public class VideoPlayerBehaviour : PlayableBehaviour { public VideoClip videoClip; public float playbackSpeed = 1f; private VideoPlayer m_VideoPlayer; private PlayableDirector m_Director; private bool m_VideoSetup = false; private bool m_WasTimelinePlaying = false; private double m_LastSyncTime = -1; private int m_SyncCooldownFrames = 0; private const int SYNC_COOLDOWN_DURATION = 5; public override void OnPlayableCreate(Playable playable) { if (m_Director == null) { m_Director = Object.FindFirstObjectByType(); } m_VideoSetup = false; m_WasTimelinePlaying = false; m_LastSyncTime = -1; m_SyncCooldownFrames = 0; } public override void ProcessFrame(Playable playable, FrameData info, object playerData) { if (playerData == null) return; m_VideoPlayer = playerData as VideoPlayer; if (m_VideoPlayer == null) return; if (m_SyncCooldownFrames > 0) { m_SyncCooldownFrames--; } if (!m_VideoSetup && videoClip != null) { m_VideoPlayer.clip = videoClip; m_VideoSetup = true; } if (info.weight > 0.5f) { bool isTimelinePlaying = m_Director != null && m_Director.state == PlayState.Playing; double normalizedTime = playable.GetTime() / playable.GetDuration(); double targetTime = normalizedTime * videoClip.length; if (isTimelinePlaying != m_WasTimelinePlaying) { Debug.Log($"Timeline state changed: {m_WasTimelinePlaying} -> {isTimelinePlaying}"); if (isTimelinePlaying) { Debug.Log($"Starting playback at time: {targetTime:F3} (Timeline: {playable.GetTime():F3})"); m_VideoPlayer.time = targetTime; m_VideoPlayer.playbackSpeed = playbackSpeed; m_LastSyncTime = targetTime; m_SyncCooldownFrames = SYNC_COOLDOWN_DURATION; if (!m_VideoPlayer.isPlaying) { m_VideoPlayer.Play(); } } else { Debug.Log($"Pausing at time: {m_VideoPlayer.time:F3}"); if (m_VideoPlayer.isPlaying) { m_VideoPlayer.Pause(); } } m_WasTimelinePlaying = isTimelinePlaying; } if (isTimelinePlaying) { if (m_SyncCooldownFrames <= 0) { double timeDiff = Mathf.Abs((float)(m_VideoPlayer.time - targetTime)); if (timeDiff > 0.3) { Debug.Log($"Large drift detected - Re-syncing: Video={m_VideoPlayer.time:F3}, Target={targetTime:F3}, Diff={timeDiff:F3}"); if (m_VideoPlayer.isPrepared) { m_VideoPlayer.time = targetTime; m_LastSyncTime = targetTime; m_SyncCooldownFrames = SYNC_COOLDOWN_DURATION; } } } } else { if (m_SyncCooldownFrames <= 0) { double timeDiff = Mathf.Abs((float)(m_VideoPlayer.time - targetTime)); if (timeDiff > 0.033) { if (m_VideoPlayer.isPrepared) { m_VideoPlayer.time = targetTime; m_LastSyncTime = targetTime; m_SyncCooldownFrames = 2; } } } } } } public override void OnBehaviourPause(Playable playable, FrameData info) { Debug.Log("Clip ended - stopping video"); if (m_VideoPlayer != null) { m_VideoPlayer.Pause(); } m_WasTimelinePlaying = false; m_LastSyncTime = -1; m_SyncCooldownFrames = 0; } }