122 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			122 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| 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);
 | |
|         }
 | |
|     }
 | |
| }
 |