Я работаю над адаптацией Unity к пьесе Сэмюэля Беккета - запускаю Unity 2018.3.4f1 и пишу код на C #.
У меня есть видео игры и сценарий игры;Когда игрок набирает строки сценария, видео воспроизводит набранные слова.Сценарий воспроизведения включает в себя временные метки для конца каждой строки, как они появляются в видео;когда пользователь заканчивает вводить заданную строку, значение PlayUntil с плавающей запятой увеличивается, поэтому оно равно отметке времени конца строки.PlayUntil проверяется на videoController.currentTime в FixedUpdate ();если видео продвигается дальше, чем PlayUntil, оно приостанавливает видео.
Это прекрасно работает на моем компьютере с Windows, как в редакторе, так и в сборках.Тем не менее, когда я пытаюсь воспроизвести его на своем Mac - либо в редакторе, либо в встроенной версии - возникает существенная задержка звука.Точнее говоря, первая четверть секунды или около того аудио из видео обрезается при каждом возобновлении воспроизведения после паузы.
Я пытался перекодировать видеофайл, как через Unity, так и черезVLC, для различных аудиоформатов (AAC, mp3 и т. Д.);Там нет очевидных изменений.Мое взломанное решение состоит в том, чтобы перематывать видео каждый раз, когда я снова начинаю играть, но это чертовски неприятно.Есть ли способ уменьшить обрезание звука, когда видео, воспроизводимое с помощью VideoPlayer на Mac, приостанавливается и воспроизводится?
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;
}
}