我正在研究Samuel Beckett剧本的Unity改编版-运行Unity 2018.3.4f1并使用C#进行编码。
我有一个剧本的视频和剧本;当播放器键入脚本行时,视频将播放他们键入的单词。剧本的脚本包括视频中每行结尾的时间戳。当用户完成给定行的键入时,浮点PlayUntil会增加,因此等于行末的时间戳。在FixedUpdate()中对照videoController.currentTime检查PlayUntil;如果视频比PlayUntil先进,它将暂停视频。
在我的Windows计算机上,无论是在编辑器中还是在构建中,都可以正常使用。但是,当我尝试在Mac上(在编辑器或内置版本中)播放时,音频滞后很大。更具体地说,每次暂停后,如果视频再次开始播放,视频中音频的前四分之一秒将被切断。
我已经尝试通过Unity和VLC将视频文件转码为各种不同的音频格式(AAC,mp3等);那里没有明显的变化。我被黑客入侵的解决方案是每次我再次开始播放时都倒带视频,但这简直太糟糕了。在Mac上通过VideoPlayer播放的视频暂停播放时,是否有任何方法可以减少音频截止?
VideoController.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Video;
using UnityEngine.UI;
using UnityEngine;
public class VideoController : MonoBehaviour
{
public VideoPlayer video;
public Slider slider;
public float PlayUntil = 0.0f;
public float timePaused = 0f;
public float startTime;
//properties of the video player
bool isDone;
public float getTimePaused
{
get { return timePaused; }
}
public bool IsPlaying
{
get { return video.isPlaying; }
}
public bool IsPrepared
{
get { return video.isPrepared; }
}
public bool IsDone
{
get { return isDone; }
}
public double currentTime
{
get { return video.time; }
}
public ulong Duration
{
get { return (ulong)(video.frameCount / video.frameRate); }
}
void OnEnable()
{
video.errorReceived += errorReceived;
video.frameReady += frameReady;
video.prepareCompleted += prepareCompleted;
video.seekCompleted += seekCompleted;
video.started += started;
video.time = 0.1f;
}
void OnDisable()
{
video.errorReceived -= errorReceived;
video.frameReady -= frameReady;
video.prepareCompleted -= prepareCompleted;
video.seekCompleted -= seekCompleted;
video.started -= started;
}
void errorReceived(VideoPlayer v, string msg)
{
Debug.Log("video player error: " + msg);
}
void frameReady(VideoPlayer v, long frame)
{
}
void prepareCompleted(VideoPlayer v)
{
Debug.Log("video player finished prepping");
isDone = false;
}
void seekCompleted(VideoPlayer v)
{
Debug.Log("video player finished seeking");
isDone = false;
}
void started(VideoPlayer v)
{
// Debug.Log("video player started");
}
private void Start()
{
video.Prepare();
Application.targetFrameRate = 20;
video.targetCameraAlpha = 0.1f;
video.time = 0.1f;
}
public void LoadVideo()
{
string temp = Application.dataPath + "/Video/" + "NotI.mp4";
if (video.url == temp) return;
video.url = temp;
video.Prepare();
Debug.Log("can set direct audio volume: " + video.canSetDirectAudioVolume);
Debug.Log("can set playback speed: " + video.canSetPlaybackSpeed);
Debug.Log("can set time: " + video.canSetTime);
Debug.Log("can step: " + video.canStep);
}
public void PlayVideo()
{
if (!IsPrepared) return;
if (IsPlaying) return;
video.Play();
timePaused += Time.time - startTime;
startTime = 0f;
}
public void PauseVideo()
{
if (!IsPlaying) return;
video.Pause();
startTime = Time.time;
}
public void Seek(float time)
{
if (!video.canSetTime) return;
if (!IsPrepared) return;
video.time = time;
}
public void SetPlaybackSpeed(float speed)
{
if (!video.canSetPlaybackSpeed) return;
video.playbackSpeed = speed;
}
public void IncrementPlaybackSpeed()
{
if (!video.canSetPlaybackSpeed) return;
video.playbackSpeed += 1;
}
public void DecrementPlaybackSpeed()
{
if (!video.canSetPlaybackSpeed) return;
video.playbackSpeed -= 1;
}
}
~~
和处理时间的WordManager.cs:
using System.Collections;
using System.Text;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class WordManager : MonoBehaviour
{
public List<Word> words;
public List<Word> settings;
// Make the main list:
// Use the test w/ timestamps
public TextAsset ATTTScript;
//public static string cleanText = System.IO.File.ReadAllText("Assets/Text/AlmostToTheTickScript.txt", System.Text.Encoding.ASCII);
//public static string[] listOfWords = cleanText.Split('\n');
public static string cleanText;
public static string[] listOfWords;
public VideoController videoController;
public WordSpawner wordSpawner;
private static float offset = 0f;
private bool hasActiveWord;
private Word activeWord;
public static int position = 0;
public string currentWord;
public float currentTime;
// if you're using an offset:
// variables for settings
public static Vector3 settingsLocation = new Vector3(-4.0f, -1f);
public static bool timerShowing = false;
public static bool wpmShowing;
public static bool accuracyShowing;
public static bool pauseTimerShowing = false;
public static bool progressShowing = false;
public static string settingsString;
public static float speedFactor = 1f;
private float PlayUntil = 0.00f;
private Vector3 defaultLocation = new Vector3(0f, 2.5f, 0f);
private Vector3 secondLocation = new Vector3(0f, 2.0f, 0f);
private void Start()
{
if (Application.platform == RuntimePlatform.OSXPlayer)
{
offset = -.15f;
}
cleanText = ATTTScript.ToString();
listOfWords = cleanText.Split('\n');
currentWord = listOfWords[position].Split('_')[0];
currentTime = float.Parse(listOfWords[position].Split('_')[1]) + offset;
GameObject InfoBox = GameObject.Find("InfoBox");
if (GameObject.Find("InfoBox") != null)
{
InfoBoxScript info = InfoBox.GetComponent<InfoBoxScript>();
speedFactor = info.getSpeed();
Debug.Log("Playing at " + speedFactor + "speed");
Debug.Log("StatsOn = " + info.getStatsOn());
if (info.getStatsOn())
{
timerShowing = true;
pauseTimerShowing = true;
progressShowing = true;
}
}
settingsString = makeSettingsString();
Word settingsWord = new Word("settings", 9999f, wordSpawner.SpawnWord(settingsLocation));
settingsWord.ChangeSize(14);
settingsWord.ChangeAlign("Upper Left");
settingsWord.ChangeWord(settingsString);
settings.Add(settingsWord);
AddWord();
AddWord();
videoController.SetPlaybackSpeed(speedFactor);
}
private void FixedUpdate()
{
//settings stuff
if (Input.GetKeyDown(KeyCode.Tab))
{
timerShowing = !timerShowing;
pauseTimerShowing = !pauseTimerShowing;
progressShowing = !progressShowing;
}
settingsString = makeSettingsString();
settings[0].ChangeWord(settingsString);
if (!videoController.IsPrepared)
{
// Debug.Log("Not ready!");
return;
}
if (videoController.currentTime < PlayUntil)
{
// Debug.Log(video.time + " < " + PlayUntil);
videoController.PlayVideo();
}
else
{
// Debug.Log(video.time + " > " + PlayUntil);
videoController.PauseVideo();
}
if (words[0].GetVector3() != defaultLocation)
{
words[0].MoveTowards(defaultLocation);
}
}
public void AddWord()
{
Vector3 newWordLocation = defaultLocation;
Word lastWord = null;
if (words.Count == 0)
{
newWordLocation = defaultLocation;
}
else
{
newWordLocation = secondLocation;
}
if (position > listOfWords.Length - 1)
{
Debug.Log("Done");
SceneManager.LoadScene(2);
}
currentWord = listOfWords[position].Split('_')[0];
currentTime = float.Parse(listOfWords[position].Split('_')[1]) + offset;
Word word = new Word(currentWord, currentTime, wordSpawner.SpawnWord(newWordLocation), lastWord);
Debug.Log(currentWord);
words.Add(word);
position = position + 1;
}
public void TypeLetter(char letter)
{
if (hasActiveWord)
{
if (activeWord.GetNextLetter() == letter)
{
activeWord.TypeLetter();
}
}
else
{
if (words[0].GetNextLetter() == letter)
{
activeWord = words[0];
hasActiveWord = true;
words[0].TypeLetter();
}
}
if (hasActiveWord && activeWord.WordTyped())
{
hasActiveWord = false;
PlayUntil = activeWord.GetEndTime();
words.Remove(activeWord);
AddWord();
}
// ` = skip mode.
if (hasActiveWord && letter == '`')
{
hasActiveWord = false;
PlayUntil = activeWord.GetEndTime();
words.Remove(activeWord);
activeWord.RemoveWord();
AddWord();
}
else if(!hasActiveWord && letter == '`')
{
activeWord = words[0];
hasActiveWord = true;
words[0].TypeLetter();
}
}
private string makeSettingsString()
{
settingsString = "";
if (timerShowing)
{
float videoTime = Mathf.Round((float)videoController.currentTime * 100.0f) / 100f;
settingsString += "Video Time: " + videoTime + "\n";
}
if(pauseTimerShowing)
{
float timePaused = Mathf.Round(videoController.getTimePaused*100f)/100f;
settingsString += "Time spent paused: " + timePaused + "\n";
}
if (progressShowing)
{
settingsString += "At position " + (position-2) + " of " + listOfWords.Length + "\n";
}
return settingsString;
}
}