284 lines
10 KiB
C#
284 lines
10 KiB
C#
using RenderHeads.Media.AVProVideo;
|
|
using System;
|
|
using System.Runtime.InteropServices;
|
|
using UnityEngine;
|
|
|
|
namespace Assets.AR
|
|
{
|
|
public class AVProVideoPlayer : MonoBehaviour
|
|
{
|
|
private const float DefaultFps = 29.97f;
|
|
public MediaPlayer videoPlayer;
|
|
private Vector2Int videoResolution = Vector2Int.zero;
|
|
private Vector2Int textureResolution = Vector2Int.zero;
|
|
private int displacement;
|
|
private bool interpolate;
|
|
private bool useFlow;
|
|
private bool pausedByTrainingPause = false;
|
|
private bool pausedByPlaybackSpeed = true;
|
|
private RenderTexture currentTexture;
|
|
private RenderTexture previousTexture;
|
|
private bool switchBuffer = true;
|
|
private bool canSwitchBuffer = true;
|
|
private int previousTextureFrameCount;
|
|
private float previousVideoTimeMs;
|
|
private float shift;
|
|
private DateTime lastPlaybackSpeedChange = DateTime.MinValue;
|
|
private float localCurrentFrame;
|
|
private bool intendedRear;
|
|
|
|
private void Awake()
|
|
{
|
|
//this.videoPlayer = this.gameObject.AddComponent<MediaPlayer>();
|
|
//this.videoPlayer.PlatformOptionsAndroid.videoApi = RenderHeads.Media.AVProVideo.Android.VideoApi.MediaPlayer;
|
|
//this.videoPlayer.PlatformOptionsAndroid.preferSoftwareDecoder = true;
|
|
//GameObject primitive = GameObject.CreatePrimitive(PrimitiveType.Quad);
|
|
//primitive.name = "VideoMesh";
|
|
//primitive.layer = 9;
|
|
//UnityEngine.Object.Destroy((UnityEngine.Object)primitive.GetComponent<MeshCollider>());
|
|
//this.VideoRenderer = (Renderer)primitive.GetComponent<MeshRenderer>();
|
|
//primitive.transform.parent = this.transform;
|
|
//this.VideoRenderer.material = new Material(Shader.Find("Rouvy/FrameInterpolation"));
|
|
}
|
|
|
|
private void OnDisable() => this.ReleaseRenderTextures();
|
|
|
|
private void OnDestroy() => UnityEngine.Object.Destroy((UnityEngine.Object)this.VideoRenderer?.material);
|
|
|
|
public bool Initialized => true;
|
|
|
|
public float CurrentFrame => (double)this.localCurrentFrame >= (double)this.StreamFrameCount ? this.localCurrentFrame - (float)this.StreamFrameCount : this.localCurrentFrame;
|
|
|
|
public bool IntendedRear
|
|
{
|
|
get => this.intendedRear;
|
|
set
|
|
{
|
|
if (this.intendedRear == value)
|
|
return;
|
|
this.intendedRear = value;
|
|
this.Seek((long)(int)this.CurrentFrame, true);
|
|
}
|
|
}
|
|
|
|
public bool IsRear => (double)this.localCurrentFrame >= (double)this.StreamFrameCount;
|
|
|
|
public int StreamFrameCount { get; set; }
|
|
|
|
public void UpdateCurrentFrame()
|
|
{
|
|
this.localCurrentFrame = (float)(this.videoPlayer.Control.GetCurrentTime() * 29.97f);
|
|
}
|
|
|
|
public float FrameRate { get; private set; } = 29.97f;
|
|
|
|
public bool HasOpticalFlow { get; private set; }
|
|
|
|
public float PlaybackSpeed => this.videoPlayer.Control.GetPlaybackRate();
|
|
|
|
public Renderer VideoRenderer { get; private set; }
|
|
|
|
public bool IsPaused => this.pausedByTrainingPause;
|
|
|
|
public bool IsSeeking => this.videoPlayer.Control.IsSeeking();
|
|
|
|
private bool Interpolate
|
|
{
|
|
get => this.interpolate;
|
|
set
|
|
{
|
|
if (this.interpolate == value)
|
|
return;
|
|
this.interpolate = value;
|
|
this.SetShaderKeywords();
|
|
}
|
|
}
|
|
|
|
private bool UseFlow
|
|
{
|
|
get => this.useFlow;
|
|
set
|
|
{
|
|
if (this.useFlow == value)
|
|
return;
|
|
this.useFlow = value;
|
|
this.SetShaderKeywords();
|
|
}
|
|
}
|
|
|
|
public void OpenVideo(string videoUrl, int streamFramesCount)
|
|
{
|
|
this.StreamFrameCount = streamFramesCount;
|
|
this.StopVideo();
|
|
//this.videoPlayer.OpenVideoFromFile(MediaPlayer.FileLocation.AbsolutePathOrURL, videoUrl);
|
|
}
|
|
|
|
public void Pause()
|
|
{
|
|
this.videoPlayer.Pause();
|
|
this.pausedByTrainingPause = true;
|
|
}
|
|
|
|
public void Resume()
|
|
{
|
|
if (!this.pausedByPlaybackSpeed)
|
|
this.videoPlayer.Play();
|
|
this.pausedByTrainingPause = false;
|
|
}
|
|
|
|
public void StopVideo()
|
|
{
|
|
this.videoPlayer.Stop();
|
|
this.videoPlayer.CloseMedia();
|
|
this.ReleaseRenderTextures();
|
|
}
|
|
private float pauseSpeed = 0.001f;
|
|
public bool SetPlaybackSpeed(float playbackSpeed)
|
|
{
|
|
if (this.IsSeeking || this.IsPaused || DateTime.UtcNow.Subtract(this.lastPlaybackSpeedChange).TotalSeconds < 1.0)
|
|
return false;
|
|
if ((double)playbackSpeed <= pauseSpeed && !this.pausedByPlaybackSpeed)
|
|
{
|
|
this.pausedByPlaybackSpeed = true;
|
|
this.videoPlayer.Pause();
|
|
}
|
|
else if ((double)playbackSpeed > pauseSpeed && this.pausedByPlaybackSpeed)
|
|
{
|
|
this.pausedByPlaybackSpeed = false;
|
|
if (!this.pausedByTrainingPause)
|
|
this.videoPlayer.Play();
|
|
}
|
|
this.videoPlayer.PlaybackRate = playbackSpeed;
|
|
this.lastPlaybackSpeedChange = DateTime.UtcNow;
|
|
return true;
|
|
}
|
|
|
|
public bool Seek(long frame, bool force = false)
|
|
{
|
|
if (this.IntendedRear)
|
|
frame += (long)this.StreamFrameCount;
|
|
if (!this.Initialized || this.IsSeeking && !force)
|
|
return false;
|
|
this.videoPlayer.Control.SeekToFrame((int)frame);
|
|
return true;
|
|
}
|
|
|
|
private void Initialize()
|
|
{
|
|
if (this.Initialized)
|
|
return;
|
|
this.VideoPrepareAction();
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
if (!this.Initialized)
|
|
{
|
|
this.Initialize();
|
|
}
|
|
else
|
|
{
|
|
this.previousVideoTimeMs = (float)this.videoPlayer.Control.GetCurrentTime();
|
|
if (!this.pausedByTrainingPause && this.videoPlayer.Control.IsPaused() && !this.pausedByPlaybackSpeed)
|
|
this.videoPlayer.Play();
|
|
if (!this.pausedByTrainingPause && !this.pausedByPlaybackSpeed || this.videoPlayer.Control.IsPaused())
|
|
return;
|
|
this.videoPlayer.Pause();
|
|
}
|
|
}
|
|
|
|
private void CheckAndPauseByPlaybackSpeed()
|
|
{
|
|
if ((double)this.videoPlayer.Control.GetPlaybackRate() != 0.0 || this.pausedByPlaybackSpeed)
|
|
return;
|
|
this.pausedByPlaybackSpeed = true;
|
|
this.videoPlayer.Pause();
|
|
}
|
|
|
|
private void VideoPrepareAction()
|
|
{
|
|
this.FrameRate = 29.97f;
|
|
this.videoPlayer.Control.SetTextureProperties(anisoLevel: 0);
|
|
if (Math.Abs(this.videoPlayer.Info.GetVideoWidth() - 1688) < 10)
|
|
{
|
|
this.videoResolution = new Vector2Int(1280, 720);
|
|
this.displacement = 40;
|
|
this.HasOpticalFlow = true;
|
|
}
|
|
else if (Math.Abs(this.videoPlayer.Info.GetVideoWidth() - 2528) < 10)
|
|
{
|
|
this.videoResolution = new Vector2Int(1920, 1080);
|
|
this.displacement = 64;
|
|
this.HasOpticalFlow = true;
|
|
}
|
|
else if (Math.Abs(this.videoPlayer.Info.GetVideoWidth() - 3372) < 10)
|
|
{
|
|
this.videoResolution = new Vector2Int(2560, 1440);
|
|
this.displacement = 128;
|
|
this.HasOpticalFlow = true;
|
|
}
|
|
else if (Math.Abs(this.videoPlayer.Info.GetVideoWidth() - 1264) < 10)
|
|
{
|
|
this.videoResolution = new Vector2Int(960, 540);
|
|
this.HasOpticalFlow = true;
|
|
this.displacement = 32;
|
|
}
|
|
else
|
|
{
|
|
this.videoResolution = new Vector2Int(this.videoPlayer.Info.GetVideoWidth(), this.videoPlayer.Info.GetVideoHeight());
|
|
this.HasOpticalFlow = false;
|
|
}
|
|
this.Interpolate = this.UseFlow = this.HasOpticalFlow;
|
|
this.videoPlayer.Play();
|
|
if (!this.pausedByTrainingPause)
|
|
return;
|
|
this.videoPlayer.Pause();
|
|
}
|
|
|
|
private void ReleaseRenderTextures()
|
|
{
|
|
if ((UnityEngine.Object)this.currentTexture != (UnityEngine.Object)null)
|
|
{
|
|
this.currentTexture.Release();
|
|
this.currentTexture = (RenderTexture)null;
|
|
}
|
|
if (!((UnityEngine.Object)this.previousTexture != (UnityEngine.Object)null))
|
|
return;
|
|
this.previousTexture.Release();
|
|
this.previousTexture = (RenderTexture)null;
|
|
}
|
|
|
|
private void SetShaderKeywords()
|
|
{
|
|
if (this.Interpolate)
|
|
this.VideoRenderer.material.EnableKeyword(AVProVideoPlayer.ShaderKeyword.interpolate);
|
|
else
|
|
this.VideoRenderer.material.DisableKeyword(AVProVideoPlayer.ShaderKeyword.interpolate);
|
|
if (this.UseFlow && this.videoResolution != this.textureResolution)
|
|
this.VideoRenderer.material.EnableKeyword(AVProVideoPlayer.ShaderKeyword.useFlow);
|
|
else
|
|
this.VideoRenderer.material.DisableKeyword(AVProVideoPlayer.ShaderKeyword.useFlow);
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Size = 1)]
|
|
private struct ShaderID
|
|
{
|
|
public static int previousFrame = Shader.PropertyToID("_PreviousFrame");
|
|
public static int currentFrame = Shader.PropertyToID("_CurrentFrame");
|
|
public static int displacement = Shader.PropertyToID("_MaxDisplacement");
|
|
public static int shift = Shader.PropertyToID("_Shift");
|
|
public static int flip = Shader.PropertyToID("_Flip");
|
|
public static int videoResolution = Shader.PropertyToID("_VideoResolution");
|
|
public static int textureResolution = Shader.PropertyToID("_TextureResolution");
|
|
public static int screenResolution = Shader.PropertyToID("_ScreenResolution");
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Size = 1)]
|
|
private struct ShaderKeyword
|
|
{
|
|
public static string interpolate = "INTERPOLATE";
|
|
public static string useFlow = "USE_FLOW";
|
|
}
|
|
}
|
|
}
|