美文网首页
Unity中,使用Recorder录制视频时,选择不同的Targ

Unity中,使用Recorder录制视频时,选择不同的Targ

作者: 全新的饭 | 来源:发表于2022-04-26 11:24 被阅读0次

    问题

    Unity中,使用Recorder录制视频时,因为选择的帧率不同,导致录制的视频中的VideoPlayer播放视频不正常。

    不正常体现在:Recorder的TargetFPS和VideoPlayer播放的视频的帧率不一致,导致VideoPlayer播放的视频被减慢和加快(为了去和TargetFPS匹配),而且原视频对应的音频的播放速度也和原视频不匹配。

    需求

    不同的帧率下VideoPlayer的视频的画面和声音播放速度均为原速。
    允许从中途指定帧数开始播放。(使用本功能时,最好将视频先播放一次,至少播放至“指定帧数”,确保设置videoPlayer的frame能起效)

    实现

    做法:使用VideoPlayer的StepForward去播放视频,因为这种播放方式下视频不播声音,因此需将视频转为一个mp3文件,使用AudioSource去专门播放声音。


    image.png

    在线工具:Mp4转Mp3

    MyVideoPlayer.cs

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Video;
    
    public class MyVideoPlayer : MonoBehaviour
    {
        [SerializeField]
        private VideoPlayer _videoPlayer;
        [SerializeField]
        private AudioSource _audioSource;
    
        private float _beginTime;
        private float CurTime{ get { return Time.time - _beginTime; } }
        private long _beginFrameIndex;
        private IEnumerator _playVideoCoroutine;
    
        [SerializeField]
        private bool _shouldAutoStart = true;
    
        private void Start()
        {
            Init();
        }
    
        private void OnDestroy()
        {
            Destroy();
        }
    
        public void Init()
        {
            _videoPlayer.playOnAwake = false;
            _videoPlayer.isLooping = false;
            _videoPlayer.Stop();
            _audioSource.playOnAwake = false;
            _audioSource.loop = false;
            _audioSource.Stop();
    
            if (_shouldAutoStart)
            {
                Play();
            }
        }
        public void Destroy()
        { }
    
        // 从触发后,等待多久后开始播放,从第几帧开始播放,是否要清除视频缓存
        public void Play(float delayTime = 0, long frameIndex = 0, bool shouldClearTexture = true)
        {
            Stop();
    
            // 为了确保跳到指定帧直接开始播放时,能跳到指定帧(若指定帧未准备好,_videoPlayer的frame设置不会成功,会是-1)
            // 实际用时,为确保设置frame有效,较好的做法:让videoPlayer的视频先完整播放一次(至少播到接下来要直接跳到的位置处),再使用从指定帧开始播放的功能
            _videoPlayer.Prepare();
    
            _beginFrameIndex = frameIndex;
    
            if (shouldClearTexture)
            {
                ReleaseTexture();
            }
    
            DelayCall(delayTime, () =>
            {
                _beginTime = Time.time;
                PlayVideo();
                PlayAudio();
            });
    
    
            void ReleaseTexture()
            {
                _videoPlayer.targetTexture.Release();
                _videoPlayer.targetTexture.MarkRestoreExpected();
            }
    
            void PlayVideo()
            {
                _videoPlayer.frame = _beginFrameIndex;
                _videoPlayer.Play();
                _playVideoCoroutine = PlayVideoCoroutine();
                StartCoroutine(_playVideoCoroutine);
            }
            void PlayAudio()
            {
                _audioSource.time = _beginFrameIndex / _videoPlayer.frameRate;
                _audioSource.Play();
            }
    
            IEnumerator PlayVideoCoroutine()
            {
                while (true)
                {
                    _videoPlayer.Pause();
                    if ((_videoPlayer.frame - _beginFrameIndex) / _videoPlayer.frameRate < CurTime)
                    {
                        _videoPlayer.StepForward();
                    }
                    yield return null;
    
                    // 循环播放
                    if (_videoPlayer.frame ==(long)_videoPlayer.frameCount - 1)
                    {
                        Play(0, 0, false);
                    }
                }
            }
        }
    
        public void Stop()
        {
            Stop(0f);
        }
    
        public void Stop(float delayTime)
        {
            DelayCall(delayTime, () =>
            {
                Stop(out long frame, out float time);
            });
        }
        /// <summary>
        /// 停止时,视频已播放了多少帧,多少秒(从视频开头计)
        /// </summary>
        /// <returns></returns>
        public void Stop(out long frame, out float time)
        {
            StopVideo();
            StopAudio();
    
            frame = _videoPlayer.frame;
            time = frame / _videoPlayer.frameRate;
    
    #if UNITY_EDITOR
            Debug.Log("停止播放,此时的frame:" + frame + "   time:" + time);
    #endif
    
            void StopVideo()
            {
                if (_playVideoCoroutine != null)
                {
                    StopCoroutine(_playVideoCoroutine);
                    _videoPlayer.Pause();
                    _playVideoCoroutine = null;
                }
            }
            void StopAudio()
            {
                _audioSource.Pause();
            }
        }
    
        private void DelayCall(float delayTime, Action action)
        {
            StartCoroutine(DelayCallCoroutine());
    
            IEnumerator DelayCallCoroutine()
            {
                yield return new WaitForSeconds(delayTime);
                action?.Invoke();
            }
        }
    }
    

    测试

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class TestMyVideoPlayer : MonoBehaviour
    {
        [SerializeField]
        private MyVideoPlayer _myVideoPlayer;
        void Start()
        {
            
        }
    
        // Update is called once per frame
        void Update()
        {
            if (Input.GetKeyDown(KeyCode.Space))
            {
                Test1();
            }
    
            if (Input.GetKeyDown(KeyCode.A))
            {
                Test2();
            }
        }
    
        private void Test1()
        {
            _myVideoPlayer.Play(3);
            _myVideoPlayer.Stop(15);
        }
        private void Test2()
        {
            var frameIndex = 360;
            _myVideoPlayer.Play(1, frameIndex, false);
        }
    
    }
    

    相关文章

      网友评论

          本文标题:Unity中,使用Recorder录制视频时,选择不同的Targ

          本文链接:https://www.haomeiwen.com/subject/jimcyrtx.html