Maze / Library /PackageCache /com.unity.timeline@1.6.5 /Samples~ /Customization /Video /VideoPlayableBehaviour.cs
| using UnityEngine; | |
| using UnityEngine.Playables; | |
| using UnityEngine.Video; | |
| namespace Timeline.Samples | |
| { | |
| // The runtime instance of a video clip player in Timeline. | |
| public sealed class VideoPlayableBehaviour : PlayableBehaviour | |
| { | |
| public VideoPlayer videoPlayer; | |
| public double preloadTime; | |
| public double clipInTime; | |
| public double startTime; | |
| private bool preparing; | |
| // Called by the mixer (VideoSchedulerPlayableBehaviour) when this is nearly active to | |
| // give the video time to load. | |
| public void PrepareVideo() | |
| { | |
| if (videoPlayer == null || videoPlayer.isPrepared || preparing) | |
| return; | |
| videoPlayer.targetCameraAlpha = 0.0f; | |
| videoPlayer.time = clipInTime; | |
| videoPlayer.Prepare(); | |
| preparing = true; | |
| } | |
| // Called each frame the clip is active. | |
| // | |
| public override void PrepareFrame(Playable playable, FrameData info) | |
| { | |
| if (videoPlayer == null) | |
| return; | |
| // Pause or Play the video to match whether the graph is being scrubbed or playing | |
| // If we need to hold the last frame, this will treat the last frame as a pause | |
| bool shouldBePlaying = info.evaluationType == FrameData.EvaluationType.Playback; | |
| if (!videoPlayer.isLooping && playable.GetTime() >= videoPlayer.clip.length) | |
| shouldBePlaying = false; | |
| if (shouldBePlaying) | |
| { | |
| // this will use the timeline time to prevent drift | |
| videoPlayer.timeReference = VideoTimeReference.ExternalTime; | |
| if (!videoPlayer.isPlaying) | |
| videoPlayer.Play(); | |
| videoPlayer.externalReferenceTime = playable.GetTime() / videoPlayer.playbackSpeed; | |
| } | |
| else | |
| { | |
| videoPlayer.timeReference = VideoTimeReference.Freerun; | |
| if (!videoPlayer.isPaused) | |
| videoPlayer.Pause(); | |
| SyncVideoToPlayable(playable); | |
| } | |
| // use the accumulated blend value to set the alpha and the audio volume | |
| videoPlayer.targetCameraAlpha = info.effectiveWeight; | |
| if (videoPlayer.audioOutputMode == VideoAudioOutputMode.Direct) | |
| { | |
| for (ushort i = 0; i < videoPlayer.clip.audioTrackCount; ++i) | |
| videoPlayer.SetDirectAudioVolume(i, info.effectiveWeight); | |
| } | |
| } | |
| // Called when the clip becomes active. | |
| public override void OnBehaviourPlay(Playable playable, FrameData info) | |
| { | |
| if (videoPlayer == null) | |
| return; | |
| SyncVideoToPlayable(playable); | |
| videoPlayer.playbackSpeed = Mathf.Clamp(info.effectiveSpeed, 1 / 10f, 10f); | |
| videoPlayer.Play(); | |
| preparing = false; | |
| } | |
| // Called when the clip becomes inactive OR the timeline is 'paused' | |
| public override void OnBehaviourPause(Playable playable, FrameData info) | |
| { | |
| if (videoPlayer == null) | |
| return; | |
| preparing = false; | |
| // The effective weight will be greater than 0 if the graph is paused and the playhead is still on this clip. | |
| if (info.effectiveWeight <= 0) | |
| videoPlayer.Stop(); | |
| else | |
| videoPlayer.Pause(); | |
| } | |
| // Called when the playable is destroyed. | |
| public override void OnPlayableDestroy(Playable playable) | |
| { | |
| if (videoPlayer != null) | |
| { | |
| videoPlayer.Stop(); | |
| if (Application.isPlaying) | |
| Object.Destroy(videoPlayer.gameObject); | |
| else | |
| Object.DestroyImmediate(videoPlayer.gameObject); | |
| } | |
| } | |
| // Syncs the video player time to playable time | |
| private void SyncVideoToPlayable(Playable playable) | |
| { | |
| if (videoPlayer == null || videoPlayer.clip == null) | |
| return; | |
| if (videoPlayer.isLooping) | |
| videoPlayer.time = playable.GetTime() % videoPlayer.clip.length; | |
| else | |
| videoPlayer.time = System.Math.Min(playable.GetTime(), videoPlayer.clip.length); | |
| } | |
| } | |
| } | |