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; /// /// update video play rate /// /// 播放速度 /// 骑行距离 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; } } } } }