364 lines
11 KiB
C#
364 lines
11 KiB
C#
using UnityEngine;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using RenderHeads.Media.AVProVideo;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright 2015-2018 RenderHeads Ltd. All rights reserverd.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace RenderHeads.Media.AVProVideo.Demos
|
|
{
|
|
/// <summary>
|
|
/// Simple video player GUI built using IMGUI
|
|
/// Shows how a simpel video play can be created with scripting
|
|
/// Includes support for fading to black when a new video is loaded
|
|
/// </summary>
|
|
public class SimpleController : MonoBehaviour
|
|
{
|
|
public string _folder = "AVProVideoSamples/";
|
|
public string[] _filenames = new string[] { "SampleSphere.mp4", "BigBuckBunny_360p30.mp3", "BigBuckBunny_720p30.mp4" };
|
|
public string[] _streams;
|
|
public MediaPlayer _mediaPlayer;
|
|
public DisplayIMGUI _display;
|
|
public GUISkin _guiSkin;
|
|
|
|
private int _width;
|
|
private int _height;
|
|
private float _durationSeconds;
|
|
public bool _useFading = true;
|
|
private Queue<string> _eventLog = new Queue<string>(8);
|
|
private float _eventTimer = 1f;
|
|
private MediaPlayer.FileLocation _nextVideoLocation;
|
|
private string _nextVideoPath;
|
|
//private bool _seekDragStarted;
|
|
//private bool _seekDragWasPlaying;
|
|
|
|
private void Start()
|
|
{
|
|
_mediaPlayer.Events.AddListener(OnMediaPlayerEvent);
|
|
}
|
|
|
|
// Callback function to handle events
|
|
public void OnMediaPlayerEvent(MediaPlayer mp, MediaPlayerEvent.EventType et, ErrorCode errorCode)
|
|
{
|
|
switch (et)
|
|
{
|
|
case MediaPlayerEvent.EventType.ReadyToPlay:
|
|
break;
|
|
case MediaPlayerEvent.EventType.Started:
|
|
break;
|
|
case MediaPlayerEvent.EventType.FirstFrameReady:
|
|
break;
|
|
case MediaPlayerEvent.EventType.MetaDataReady:
|
|
GatherProperties();
|
|
break;
|
|
case MediaPlayerEvent.EventType.FinishedPlaying:
|
|
break;
|
|
}
|
|
|
|
AddEvent(et);
|
|
}
|
|
|
|
private void AddEvent(MediaPlayerEvent.EventType et)
|
|
{
|
|
Debug.Log("[SimpleController] Event: " + et.ToString());
|
|
_eventLog.Enqueue(et.ToString());
|
|
if (_eventLog.Count > 5)
|
|
{
|
|
_eventLog.Dequeue();
|
|
_eventTimer = 1f;
|
|
}
|
|
}
|
|
|
|
private void GatherProperties()
|
|
{
|
|
if (_mediaPlayer != null && _mediaPlayer.Info != null)
|
|
{
|
|
_width = _mediaPlayer.Info.GetVideoWidth();
|
|
_height = _mediaPlayer.Info.GetVideoHeight();
|
|
_durationSeconds = _mediaPlayer.Info.GetDurationMs() / 1000f;
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (!_useFading)
|
|
{
|
|
if (_display != null && _display._mediaPlayer != null && _display._mediaPlayer.Control != null)
|
|
{
|
|
_display._color = Color.white;
|
|
_display._mediaPlayer.Control.SetVolume(1f);
|
|
}
|
|
}
|
|
|
|
if (_eventLog != null && _eventLog.Count > 0)
|
|
{
|
|
_eventTimer -= Time.deltaTime;
|
|
if (_eventTimer < 0f)
|
|
{
|
|
_eventLog.Dequeue();
|
|
_eventTimer = 1f;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void LoadVideo(string filePath, bool url = false)
|
|
{
|
|
// Set the video file name and to load.
|
|
if (!url)
|
|
_nextVideoLocation = MediaPlayer.FileLocation.RelativeToStreamingAssetsFolder;
|
|
else
|
|
_nextVideoLocation = MediaPlayer.FileLocation.AbsolutePathOrURL;
|
|
_nextVideoPath = filePath;
|
|
|
|
// IF we're not using fading then load the video immediately
|
|
if (!_useFading)
|
|
{
|
|
// Load the video
|
|
if (!_mediaPlayer.OpenVideoFromFile(_nextVideoLocation, _nextVideoPath, _mediaPlayer.m_AutoStart))
|
|
{
|
|
Debug.LogError("Failed to open video!");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StartCoroutine("LoadVideoWithFading");
|
|
}
|
|
}
|
|
|
|
private static bool VideoIsReady(MediaPlayer mp)
|
|
{
|
|
return (mp != null && mp.TextureProducer != null && mp.TextureProducer.GetTextureFrameCount() <= 0);
|
|
|
|
}
|
|
private static bool AudioIsReady(MediaPlayer mp)
|
|
{
|
|
return (mp != null && mp.Control != null && mp.Control.CanPlay() && mp.Info.HasAudio() && !mp.Info.HasVideo());
|
|
}
|
|
|
|
private IEnumerator LoadVideoWithFading()
|
|
{
|
|
const float FadeDuration = 0.25f;
|
|
float fade = FadeDuration;
|
|
|
|
// Fade down
|
|
while (fade > 0f && Application.isPlaying)
|
|
{
|
|
fade -= Time.deltaTime;
|
|
fade = Mathf.Clamp(fade, 0f, FadeDuration);
|
|
|
|
_display._color = new Color(1f, 1f, 1f, fade / FadeDuration);
|
|
_display._mediaPlayer.Control.SetVolume(fade / FadeDuration);
|
|
|
|
yield return null;
|
|
}
|
|
|
|
// Wait 3 frames for display object to update
|
|
yield return new WaitForEndOfFrame();
|
|
yield return new WaitForEndOfFrame();
|
|
yield return new WaitForEndOfFrame();
|
|
|
|
// Load the video
|
|
if (Application.isPlaying)
|
|
{
|
|
if (!_mediaPlayer.OpenVideoFromFile(_nextVideoLocation, _nextVideoPath, _mediaPlayer.m_AutoStart))
|
|
{
|
|
Debug.LogError("Failed to open video!");
|
|
}
|
|
else
|
|
{
|
|
// Wait for the first frame to come through (could also use events for this)
|
|
while (Application.isPlaying && (VideoIsReady(_mediaPlayer) || AudioIsReady(_mediaPlayer)))
|
|
{
|
|
yield return null;
|
|
}
|
|
|
|
// Wait 3 frames for display object to update
|
|
yield return new WaitForEndOfFrame();
|
|
yield return new WaitForEndOfFrame();
|
|
yield return new WaitForEndOfFrame();
|
|
}
|
|
}
|
|
|
|
// Fade up
|
|
while (fade < FadeDuration && Application.isPlaying)
|
|
{
|
|
fade += Time.deltaTime;
|
|
fade = Mathf.Clamp(fade, 0f, FadeDuration);
|
|
|
|
_display._color = new Color(1f, 1f, 1f, fade / FadeDuration);
|
|
_display._mediaPlayer.Control.SetVolume(fade / FadeDuration);
|
|
|
|
yield return null;
|
|
}
|
|
}
|
|
|
|
void OnGUI()
|
|
{
|
|
if (_mediaPlayer == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Make sure we're set to render after the background IMGUI
|
|
GUI.depth = -10;
|
|
|
|
// Apply skin
|
|
if (_guiSkin != null)
|
|
{
|
|
GUI.skin = _guiSkin;
|
|
}
|
|
|
|
// Make sure the UI scales with screen resolution
|
|
const float UIWidth = 1920f / 2.0f;
|
|
const float UIHeight = 1080f / 2.0f;
|
|
GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(Screen.width / UIWidth, Screen.height / UIHeight, 1f));
|
|
|
|
GUILayout.BeginVertical("box");
|
|
|
|
if (_mediaPlayer.Control != null)
|
|
{
|
|
// Display properties
|
|
GUILayout.Label("Loaded: " + _mediaPlayer.m_VideoPath);
|
|
GUILayout.Label(string.Format("Size: {0}x{1} FPS: {3} Duration: {2}ms", _width, _height, _mediaPlayer.Info.GetDurationMs(), _mediaPlayer.Info.GetVideoFrameRate().ToString("F2")));
|
|
GUILayout.Label("Updates: " + _mediaPlayer.TextureProducer.GetTextureFrameCount() + " Rate: " + _mediaPlayer.Info.GetVideoDisplayRate().ToString("F1"));
|
|
|
|
GUILayout.BeginHorizontal();
|
|
|
|
// Fade option
|
|
_useFading = GUILayout.Toggle(_useFading, "Fade to Black During Loading");
|
|
|
|
// Auto play
|
|
_mediaPlayer.m_AutoStart = GUILayout.Toggle(_mediaPlayer.m_AutoStart, "Auto Play After Load");
|
|
|
|
// Looping
|
|
bool loopStatus = _mediaPlayer.m_Loop;
|
|
bool newLoopStatus = GUILayout.Toggle(loopStatus, "Loop");
|
|
if (newLoopStatus != loopStatus)
|
|
{
|
|
_mediaPlayer.m_Loop = newLoopStatus;
|
|
_mediaPlayer.Control.SetLooping(newLoopStatus);
|
|
}
|
|
|
|
GUILayout.EndHorizontal();
|
|
|
|
// Timeline scrubbing (note as use int as WebGL has float == precision issues)
|
|
int currentTime = (int)_mediaPlayer.Control.GetCurrentTimeMs();
|
|
int newTime = (int)GUILayout.HorizontalSlider(currentTime, 0f, _durationSeconds * 1000f);
|
|
Rect timeSliderRect = GUILayoutUtility.GetLastRect();
|
|
|
|
float thumbWidth = GUI.skin.horizontalSliderThumb.CalcSize(GUIContent.none).x;
|
|
|
|
|
|
// Draw buffering indication
|
|
Rect bufferingRect = timeSliderRect;
|
|
GUI.color = Color.green;
|
|
bufferingRect.xMin += thumbWidth;
|
|
bufferingRect.y = bufferingRect.yMax - 4;
|
|
bufferingRect.width -= thumbWidth * 1f;
|
|
bufferingRect.width *= _mediaPlayer.Control.GetBufferingProgress();
|
|
bufferingRect.height = 4;
|
|
GUI.DrawTexture(bufferingRect, Texture2D.whiteTexture, ScaleMode.StretchToFill);
|
|
|
|
|
|
GUI.color = Color.green;
|
|
int timeRangeCount = _mediaPlayer.Control.GetBufferedTimeRangeCount();
|
|
for (int i = 0; i < timeRangeCount; i++)
|
|
{
|
|
float startTimeMs = 0f;
|
|
float endTimeMs = 0f;
|
|
if (_mediaPlayer.Control.GetBufferedTimeRange(i, ref startTimeMs, ref endTimeMs))
|
|
{
|
|
bufferingRect.xMin = thumbWidth + timeSliderRect.x + (timeSliderRect.width - thumbWidth * 1f) * (startTimeMs / (_durationSeconds * 1000f));
|
|
bufferingRect.xMax = thumbWidth + timeSliderRect.x + (timeSliderRect.width - thumbWidth * 1f) * (endTimeMs / (_durationSeconds * 1000f));
|
|
GUI.DrawTexture(bufferingRect, Texture2D.whiteTexture, ScaleMode.StretchToFill);
|
|
}
|
|
}
|
|
GUI.color = Color.white;
|
|
|
|
|
|
// Handle possible slider move
|
|
if (newTime != currentTime)
|
|
{
|
|
_mediaPlayer.Control.Seek((float)newTime);
|
|
}
|
|
|
|
if (!_mediaPlayer.Control.IsPlaying())
|
|
{
|
|
if (GUILayout.Button("Play"))
|
|
{
|
|
_mediaPlayer.Control.Play();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GUILayout.Button("Pause"))
|
|
{
|
|
_mediaPlayer.Control.Pause();
|
|
}
|
|
}
|
|
|
|
// Audio tracks
|
|
GUILayout.BeginHorizontal();
|
|
int numAudioTracks = _mediaPlayer.Info.GetAudioTrackCount();
|
|
int selectedTrackIndex = _mediaPlayer.Control.GetCurrentAudioTrack();
|
|
for (int i = 0; i < numAudioTracks; i++)
|
|
{
|
|
if (i == selectedTrackIndex)
|
|
{
|
|
GUI.color = Color.green;
|
|
}
|
|
if (GUILayout.Button("Audio Track #" + (i + 1)))
|
|
{
|
|
_mediaPlayer.Control.SetAudioTrack(i);
|
|
}
|
|
GUI.color = Color.white;
|
|
}
|
|
GUILayout.EndHorizontal();
|
|
}
|
|
|
|
GUILayout.Label("Select a new file to play:");
|
|
|
|
// Display a grid of buttons containing the file names of videos to play
|
|
int newSelection = GUILayout.SelectionGrid(-1, _filenames, 3);
|
|
if (newSelection >= 0)
|
|
{
|
|
LoadVideo(System.IO.Path.Combine(_folder, _filenames[newSelection]));
|
|
}
|
|
|
|
GUILayout.Space(8f);
|
|
|
|
GUILayout.Label("Select a new stream to play:");
|
|
|
|
// Display a grid of buttons containing the file names of videos to play
|
|
int newSteam = GUILayout.SelectionGrid(-1, _streams, 1);
|
|
if (newSteam >= 0)
|
|
{
|
|
LoadVideo(_streams[newSteam], true);
|
|
}
|
|
|
|
GUILayout.Space(8f);
|
|
|
|
GUILayout.Label("Recent Events: ");
|
|
GUILayout.BeginVertical("box");
|
|
int eventIndex = 0;
|
|
foreach (string eventString in _eventLog)
|
|
{
|
|
GUI.color = Color.white;
|
|
if (eventIndex == 0)
|
|
{
|
|
GUI.color = new Color(1f, 1f, 1f, _eventTimer);
|
|
}
|
|
GUILayout.Label(eventString);
|
|
eventIndex++;
|
|
}
|
|
GUILayout.EndVertical();
|
|
GUI.color = Color.white;
|
|
|
|
|
|
GUILayout.EndVertical();
|
|
}
|
|
}
|
|
}
|