Skip to content

Instantly share code, notes, and snippets.

@DashW
Created October 24, 2018 15:46
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DashW/974a108bd98377bc1cd6b2f708699a52 to your computer and use it in GitHub Desktop.
Save DashW/974a108bd98377bc1cd6b2f708699a52 to your computer and use it in GitHub Desktop.
Scrubbable Video Player Track for Unity Timeline
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Video;
public class PlayableVideoAsset : PlayableAsset
{
public ExposedReference<VideoClip> Clip = new ExposedReference<VideoClip>();
public float Offset;
private double _duration;
public override double duration
{
get
{
return _duration > 0.0f ? _duration : base.duration;
}
}
public override Playable CreatePlayable(PlayableGraph graph, GameObject owner)
{
ScriptPlayable<PlayableVideoBehaviour> playable = ScriptPlayable<PlayableVideoBehaviour>.Create(graph);
var director = owner.GetComponent<PlayableDirector>();
var ps = director.GetGenericBinding(this) as VideoClip;
playable.GetBehaviour().Clip = Clip.Resolve(graph.GetResolver());
playable.GetBehaviour().Offset = Offset;
if(playable.GetBehaviour().Clip != null)
{
_duration = playable.GetBehaviour().Clip.length;
}
else
{
_duration = 0.0f;
}
return playable;
}
}
using System;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Video;
public class PlayableVideoBehaviour : PlayableBehaviour {
public VideoClip Clip;
public float Offset;
private VideoPlayer _player;
private double GetVideoSeekTime(Playable playable)
{
return Math.Max(playable.GetTime() + Offset, 0.0);
}
public override void OnBehaviourPause(Playable playable, FrameData info)
{
base.OnBehaviourPause(playable, info);
if (_player == null)
return;
_player.Pause();
}
public override void ProcessFrame(Playable playable, FrameData info, object playerData)
{
base.ProcessFrame(playable, info, playerData);
_player = (VideoPlayer)playerData;
if (_player == null)
return;
if(_player.clip != Clip)
_player.clip = Clip;
if (_player.timeReference != VideoTimeReference.InternalTime)
_player.timeReference = VideoTimeReference.InternalTime;
double videoSeekTime = GetVideoSeekTime(playable);
bool playing = Math.Abs(Time.unscaledDeltaTime - (playable.GetTime() - playable.GetPreviousTime())) < 0.002f;
//if(!playing)
// Debug.Log("Paused");
double videoSeekDifference = videoSeekTime - _player.time;
if (playing)
{
if (Math.Abs(videoSeekDifference) > 0.1f)
{
if (Math.Floor(Time.timeSinceLevelLoad) != Math.Floor(Time.timeSinceLevelLoad - Time.deltaTime))
{
_player.time = videoSeekTime + 0.05f;
}
}
if(!_player.isPlaying)
{
_player.Play();
}
}
else
{
_player.time = videoSeekTime;
_player.Pause();
}
if (Math.Floor(Time.timeSinceLevelLoad) != Math.Floor(Time.timeSinceLevelLoad - Time.deltaTime))
{
Debug.Log("Video seek difference: " + videoSeekDifference + " Playback Speed: " + _player.playbackSpeed);
}
}
}
using UnityEngine.Video;
using UnityEngine.Timeline;
[TrackClipType(typeof(PlayableVideoAsset), false)]
[TrackBindingType(typeof(VideoPlayer))]
public class PlayableVideoTrack : TrackAsset {
}
@mura94
Copy link

mura94 commented Nov 30, 2021

Thanks for sharing this!

For my purposes I found that it would start playing when the director was paused if I "skipped" to the same frame that the PlayableDirector was already on, but this alternative worked for me in PlayableVideoBehaviour.cs @ line 45:

bool playing = playable.GetGraph().IsPlaying();

(Just in case anyone else needs this in the future)

Thanks again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment