powerfun-unity/Assets/AR/AVProVideoPlayer.cs
2023-04-18 17:10:48 +08:00

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() * DefaultFps);
}
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";
}
}
}