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

170 lines
7.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Assets.AR
{
public class ARVideoPlayerControl
{
private const float MinVideoPlaybackSpeedChangeInterval = 0.2f;
private const float MaxPlaybackSpeed = 1.5f;
private const float MaxCameraDistanceError = 200f;
private DateTime lastPlaybackSpeedChange = DateTime.MinValue;
private float fixedTimeFrame;
private DateTime fixedTimeSeekFinished = DateTime.MinValue;
private int lapCount = 1;
private double lapLength;
public float FixedVideoFrame => this.fixedTimeFrame;
//public IDistanceSource RiderDistance { get; set;
public AVProVideoPlayer VideoPlayer { get; private set; }
//public ISpeedSource RiderSpeed { get; set; }
public VideoPointsSync VideoSyncSource { get; set; }
public ARRoute Route { get; set; }
public int VideoFrameOffset { get; set; }
public float CameraFollowDistance { get; set; }
public bool AllowUpdate { get; set; } = true;
public float CameraDistanceError { get; private set; }
public bool IsTimeFixed { get; private set; }
public float FrameIndexDistanceCorrection { get; private set; }
public bool IsMultilap => this.lapCount > 1;
public void SetVideoPlayer(AVProVideoPlayer player) => this.VideoPlayer = player;
public void SetMultiLap(int lapCount, double lapLength)
{
this.lapCount = lapCount;
this.lapLength = lapLength;
}
public void FixTimeByDistance(float distance) => this.FixTimeByFrame(this.VideoSyncSource.GetVideoFrameAtDistance(distance));
public void FixTimeByFrame(float frame)
{
this.IsTimeFixed = true;
this.fixedTimeFrame = frame;
this.fixedTimeSeekFinished = DateTime.MinValue;
if (this.VideoPlayer.IsPaused)
this.VideoPlayer.Resume();
this.VideoPlayer.SetPlaybackSpeed(0.25f);
this.VideoPlayer.Seek((long)frame, true);
}
public void UnFixTime()
{
//this.IsTimeFixed = false;
//float videoFrameAtDistance = this.VideoSyncSource.GetVideoFrameAtDistance(this.RiderDistance.LapDistance);
//float num = this.VideoSyncSource.AverageVideoSpeed(videoFrameAtDistance, videoFrameAtDistance);
//float playbackSpeed = (double)num != 0.0 ? this.RiderSpeed.Speed / num : 0.0f;
//if (this.VideoPlayer.IsPaused)
// this.VideoPlayer.Resume();
//this.VideoPlayer.SetPlaybackSpeed(playbackSpeed);
//this.lastPlaybackSpeedChange = DateTime.UtcNow;
//this.VideoPlayer.Seek((long)videoFrameAtDistance, true);
}
private void SkipVideoToDistance(float distance) => this.SkipVideoToFrame((long)this.VideoSyncSource.GetVideoFrameAtDistance(distance));
private void SkipVideoToFrame(long frame) => this.VideoPlayer.Seek(frame);
private const float TimerInterval = 0.2f;
/// <summary>
/// update video play rate
/// </summary>
/// <param name="speed">播放速度</param>
/// <param name="routeDistance">骑行距离</param>
public void UpdateVideoPlayRate(float speed, float routeDistance)
{
if (!this.AllowUpdate)
return;
if (this.IsTimeFixed)
{
if (this.VideoPlayer.IsSeeking)
return;
if (this.fixedTimeSeekFinished == DateTime.MinValue)
this.fixedTimeSeekFinished = DateTime.UtcNow;
if (DateTime.UtcNow.Subtract(this.fixedTimeSeekFinished).TotalSeconds < 0.25)
return;
if (this.VideoPlayer.CurrentFrame > this.fixedTimeFrame)
this.VideoPlayer.Pause();
this.VideoPlayer.UpdateCurrentFrame();
this.FrameIndexDistanceCorrection = 0.0f;
}
else
{
var videoFrameAtDistance1 = this.VideoSyncSource.GetVideoFrameAtDistance(routeDistance);
var val2 = routeDistance - this.CameraFollowDistance;
var distance = Math.Max(0.0f, val2);
var frame = this.VideoSyncSource.GetVideoFrameAtDistance(distance) + this.VideoFrameOffset;
if (this.Route != null && this.Route.GetVisibility(frame) > 10.0)
frame = (float)this.Route.GetFrameAtDistance(Math.Max(0.0, this.Route.GetDistanceForFrame(videoFrameAtDistance1) - this.CameraFollowDistance)) + this.VideoFrameOffset;
this.VideoPlayer.UpdateCurrentFrame();
var distanceForVideoFrame = this.VideoSyncSource.GetDistanceForVideoFrame(this.VideoPlayer.CurrentFrame - (float)this.VideoFrameOffset);
float frameOffset;
if (this.Route != null)
{
var frameAtDistance = this.Route.GetFrameAtDistance(this.Route.GetDistanceForFrame(this.VideoPlayer.CurrentFrame - this.VideoFrameOffset) + Mathf.Min(routeDistance, this.CameraFollowDistance));
frameOffset = videoFrameAtDistance1 - (float)frameAtDistance;
}
else
frameOffset = frame - (this.VideoPlayer.CurrentFrame - this.VideoFrameOffset);
var num1 = Mathf.Clamp01(PFMath.Lerp(0.0f, 1f, 100f, 0.0f, Mathf.Abs(frameOffset)));
this.FrameIndexDistanceCorrection = frameOffset * num1;
this.CameraDistanceError = distance - distanceForVideoFrame;
if (this.IsMultilap)
{
var num2 = distance - (distanceForVideoFrame + (float)this.lapLength);
if (Math.Abs(num2) < Math.Abs(this.CameraDistanceError) && Math.Abs(num2) < 200.0)
return;
}
if (Math.Abs(this.CameraDistanceError) > 200.0)
{
this.SkipVideoToDistance(distance);
}
else
{
var totalSeconds = DateTime.UtcNow.Subtract(this.lastPlaybackSpeedChange).TotalSeconds;
if (totalSeconds >= 0.0 && totalSeconds < TimerInterval)
return;
var num3 = (float)totalSeconds;
var num4 = num3 * speed;
var offset = this.VideoSyncSource.GetDistanceForVideoFrame((this.VideoPlayer.CurrentFrame - this.VideoFrameOffset + num3 * this.VideoPlayer.PlaybackSpeed * this.VideoPlayer.FrameRate));
var left = (double)Math.Abs(distance + num4 - offset);
var right = (double)Math.Abs(this.CameraDistanceError);
if (left <= right)
return;
var videoFrameAtDistance2 = this.VideoSyncSource.GetVideoFrameAtDistance(routeDistance + num4);
var num5 = this.VideoSyncSource.AverageVideoSpeed(videoFrameAtDistance1, videoFrameAtDistance2);
var ratio = (num5 != 0.0 ? speed / num5 : 0.0f);
var deltaRatio = (float)((frame - (this.VideoPlayer.CurrentFrame - this.VideoFrameOffset)) / 2.0) / this.VideoPlayer.FrameRate;
var playbackSpeed = Mathf.Clamp(ratio + deltaRatio, 0.0f, 1.5f);
if (playbackSpeed == this.VideoPlayer.PlaybackSpeed || !this.VideoPlayer.SetPlaybackSpeed(playbackSpeed))
return;
this.lastPlaybackSpeedChange = DateTime.UtcNow;
}
}
}
}
}