862 lines
25 KiB
C#
862 lines
25 KiB
C#
#if UNITY_2017_3_OR_NEWER
|
|
#define AVPRO_MOVIECAPTURE_OFFLINE_AUDIOCAPTURE
|
|
#endif
|
|
|
|
using UnityEngine;
|
|
using System.Text;
|
|
using System.Collections;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright 2012-2021 RenderHeads Ltd. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace RenderHeads.Media.AVProMovieCapture
|
|
{
|
|
/// <summary>
|
|
/// Uses IMGUI to render a GUI to control video capture. This is mainly used for the demos.
|
|
/// </summary>
|
|
[AddComponentMenu("AVPro Movie Capture/Utils/Capture GUI", 300)]
|
|
public class CaptureGUI : MonoBehaviour
|
|
{
|
|
private enum Section
|
|
{
|
|
None,
|
|
VideoCodecs,
|
|
AudioCodecs,
|
|
AudioInputDevices,
|
|
ImageCodecs,
|
|
}
|
|
[SerializeField] CaptureBase _movieCapture = null;
|
|
[SerializeField] bool _showUI = true;
|
|
[SerializeField] bool _whenRecordingAutoHideUI = true;
|
|
[SerializeField] GUISkin _guiSkin = null;
|
|
|
|
public CaptureBase MovieCapture
|
|
{
|
|
get { return _movieCapture; }
|
|
set { _movieCapture = value; }
|
|
}
|
|
public bool HideUiWhenRecording
|
|
{
|
|
get { return _whenRecordingAutoHideUI; }
|
|
set { _whenRecordingAutoHideUI = value; }
|
|
}
|
|
public bool ShowUI
|
|
{
|
|
get { return _showUI; }
|
|
set { _showUI = value; }
|
|
}
|
|
|
|
private readonly static string[] CommonFrameRateNames = { "1", "10", "15", "23.98", "24", "25", "29.97", "30", "50", "59.94", "60", "75", "90", "120" };
|
|
private readonly static float[] CommonFrameRateValues = { 1f, 10f, 15f, 23.976f, 24f, 25f, 29.97f, 30f, 50f, 59.94f, 60f, 75f, 90f, 120f };
|
|
|
|
// GUI
|
|
private Section _shownSection = Section.None;
|
|
private string[] _videoCodecNames = new string[0];
|
|
private string[] _audioCodecNames = new string[0];
|
|
private bool[] _videoCodecConfigurable = new bool[0];
|
|
private bool[] _audioCodecConfigurable = new bool[0];
|
|
private string[] _audioDeviceNames = new string[0];
|
|
private string[] _downScales = { "Original", "Half", "Quarter", "Eighth", "Sixteenth", "Custom" };
|
|
private string[] _outputType = { "Video File", "Image Sequence", "Named Pipe" };
|
|
private int _downScaleIndex;
|
|
private GUIStyle _tintableBox;
|
|
|
|
private Vector2 _videoPos = Vector2.zero;
|
|
private Vector2 _audioPos = Vector2.zero;
|
|
private Vector2 _audioCodecPos = Vector2.zero;
|
|
private Vector2 _imageCodecPos = Vector2.zero;
|
|
|
|
// Status
|
|
private long _lastFileSize;
|
|
private uint _lastEncodedMinutes;
|
|
private uint _lastEncodedSeconds;
|
|
private uint _lastEncodedFrame;
|
|
|
|
private void Start()
|
|
{
|
|
if (_movieCapture != null)
|
|
{
|
|
CreateGUI();
|
|
}
|
|
}
|
|
|
|
private void CreateGUI()
|
|
{
|
|
switch (_movieCapture.ResolutionDownScale)
|
|
{
|
|
default:
|
|
case CaptureBase.DownScale.Original:
|
|
_downScaleIndex = 0;
|
|
break;
|
|
case CaptureBase.DownScale.Half:
|
|
_downScaleIndex = 1;
|
|
break;
|
|
case CaptureBase.DownScale.Quarter:
|
|
_downScaleIndex = 2;
|
|
break;
|
|
case CaptureBase.DownScale.Eighth:
|
|
_downScaleIndex = 3;
|
|
break;
|
|
case CaptureBase.DownScale.Sixteenth:
|
|
_downScaleIndex = 4;
|
|
break;
|
|
case CaptureBase.DownScale.Custom:
|
|
_downScaleIndex = 5;
|
|
break;
|
|
}
|
|
|
|
if (CodecManager.VideoCodecs.Count > 0)
|
|
{
|
|
_videoCodecNames = new string[CodecManager.VideoCodecs.Count];
|
|
_videoCodecConfigurable = new bool[CodecManager.VideoCodecs.Count];
|
|
int i = 0;
|
|
foreach (Codec codec in CodecManager.VideoCodecs)
|
|
{
|
|
_videoCodecNames[i] = codec.Name;
|
|
_videoCodecConfigurable[i] = codec.HasConfigwindow;
|
|
i++;
|
|
}
|
|
}
|
|
if (CodecManager.AudioCodecs.Count > 0)
|
|
{
|
|
_audioCodecNames = new string[CodecManager.AudioCodecs.Count];
|
|
_audioCodecConfigurable = new bool[CodecManager.AudioCodecs.Count];
|
|
int i = 0;
|
|
foreach (Codec codec in CodecManager.AudioCodecs)
|
|
{
|
|
_audioCodecNames[i] = codec.Name;
|
|
_audioCodecConfigurable[i] = codec.HasConfigwindow;
|
|
i++;
|
|
}
|
|
}
|
|
int numAudioDevices = NativePlugin.GetAudioInputDeviceCount();
|
|
if (numAudioDevices > 0)
|
|
{
|
|
_audioDeviceNames = new string[numAudioDevices];
|
|
for (int i = 0; i < numAudioDevices; i++)
|
|
{
|
|
_audioDeviceNames[i] = NativePlugin.GetAudioInputDeviceName(i);
|
|
}
|
|
}
|
|
|
|
_movieCapture.SelectVideoCodec();
|
|
_movieCapture.SelectAudioCodec();
|
|
_movieCapture.SelectAudioInputDevice();
|
|
}
|
|
|
|
private void OnGUI()
|
|
{
|
|
GUI.skin = _guiSkin;
|
|
GUI.depth = -10;
|
|
|
|
if (_tintableBox == null)
|
|
{
|
|
_tintableBox = new GUIStyle(GUI.skin.box);
|
|
_tintableBox.normal.background = Texture2D.whiteTexture;
|
|
_tintableBox.border.left = _tintableBox.border.right = _tintableBox.border.top = _tintableBox.border.bottom = 0;
|
|
}
|
|
|
|
#if UNITY_IOS && !UNITY_EDITOR_OSX
|
|
float sf = 1.0f;
|
|
#else
|
|
float sf = 1.5f;
|
|
#endif
|
|
GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(Screen.width / 1920f * sf, Screen.height / 1080f * sf, 1f));
|
|
|
|
if (_showUI)
|
|
{
|
|
GUILayout.Window(4, new Rect(0f, 0f, 480f, 256f), MyWindow, "AVPro Movie Capture UI");
|
|
}
|
|
}
|
|
|
|
private void MyWindow(int id)
|
|
{
|
|
if (_movieCapture == null)
|
|
{
|
|
GUILayout.Label("CaptureGUI - No CaptureFrom component set");
|
|
return;
|
|
}
|
|
|
|
// NOTE: From Unity 2020.1 onwards it seems this correction isn't needed, but it's needed
|
|
// for older versions of Unity when running in Linear colorspace
|
|
bool sRGBWritePrev = GL.sRGBWrite;
|
|
GL.sRGBWrite = false;
|
|
|
|
if (_movieCapture.IsCapturing())
|
|
{
|
|
GUI_RecordingStatus();
|
|
GL.sRGBWrite = sRGBWritePrev;
|
|
return;
|
|
}
|
|
|
|
GUILayout.BeginVertical();
|
|
|
|
if (_movieCapture != null)
|
|
{
|
|
GUILayout.Label("Resolution:");
|
|
GUILayout.BeginHorizontal();
|
|
_downScaleIndex = GUILayout.SelectionGrid(_downScaleIndex, _downScales, _downScales.Length);
|
|
switch (_downScaleIndex)
|
|
{
|
|
case 0:
|
|
_movieCapture.ResolutionDownScale = CaptureBase.DownScale.Original;
|
|
break;
|
|
case 1:
|
|
_movieCapture.ResolutionDownScale = CaptureBase.DownScale.Half;
|
|
break;
|
|
case 2:
|
|
_movieCapture.ResolutionDownScale = CaptureBase.DownScale.Quarter;
|
|
break;
|
|
case 3:
|
|
_movieCapture.ResolutionDownScale = CaptureBase.DownScale.Eighth;
|
|
break;
|
|
case 4:
|
|
_movieCapture.ResolutionDownScale = CaptureBase.DownScale.Sixteenth;
|
|
break;
|
|
case 5:
|
|
_movieCapture.ResolutionDownScale = CaptureBase.DownScale.Custom;
|
|
break;
|
|
}
|
|
GUILayout.EndHorizontal();
|
|
|
|
GUILayout.BeginHorizontal(GUILayout.Width(256));
|
|
if (_movieCapture.ResolutionDownScale == CaptureBase.DownScale.Custom)
|
|
{
|
|
string maxWidthString = GUILayout.TextField(Mathf.FloorToInt(_movieCapture.ResolutionDownscaleCustom.x).ToString(), 4);
|
|
int maxWidth = 0;
|
|
if (int.TryParse(maxWidthString, out maxWidth))
|
|
{
|
|
_movieCapture.ResolutionDownscaleCustom = new Vector2(Mathf.Clamp(maxWidth, 0, NativePlugin.MaxRenderWidth), _movieCapture.ResolutionDownscaleCustom.y);
|
|
}
|
|
|
|
GUILayout.Label("x", GUILayout.Width(20));
|
|
|
|
string maxHeightString = GUILayout.TextField(Mathf.FloorToInt(_movieCapture.ResolutionDownscaleCustom.y).ToString(), 4);
|
|
int maxHeight = 0;
|
|
if (int.TryParse(maxHeightString, out maxHeight))
|
|
{
|
|
_movieCapture.ResolutionDownscaleCustom = new Vector2(_movieCapture.ResolutionDownscaleCustom.x, Mathf.Clamp(maxHeight, 0, NativePlugin.MaxRenderHeight));
|
|
}
|
|
}
|
|
GUILayout.EndHorizontal();
|
|
|
|
GUILayout.Space(16f);
|
|
|
|
GUILayout.Label("Frame Rate: " + _movieCapture.FrameRate.ToString("F2"));
|
|
GUILayout.BeginHorizontal();
|
|
for (int i = 0; i < CommonFrameRateNames.Length; i++)
|
|
{
|
|
if (GUILayout.Toggle(_movieCapture.FrameRate == CommonFrameRateValues[i], CommonFrameRateNames[i]))
|
|
{
|
|
_movieCapture.FrameRate = CommonFrameRateValues[i];
|
|
}
|
|
}
|
|
GUILayout.EndHorizontal();
|
|
|
|
GUILayout.Space(16f);
|
|
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.Label("Output:", GUILayout.ExpandWidth(false));
|
|
OutputTarget outputType = (OutputTarget)GUILayout.SelectionGrid((int)_movieCapture.OutputTarget, _outputType, _outputType.Length);
|
|
if (outputType != _movieCapture.OutputTarget)
|
|
{
|
|
_movieCapture.OutputTarget = outputType;
|
|
// TODO: Set this to last used or sensible platform default
|
|
switch (outputType) {
|
|
case OutputTarget.VideoFile:
|
|
break;
|
|
case OutputTarget.ImageSequence:
|
|
break;
|
|
case OutputTarget.NamedPipe:
|
|
break;
|
|
}
|
|
}
|
|
GUILayout.EndHorizontal();
|
|
|
|
GUILayout.Space(16f);
|
|
|
|
_movieCapture.IsRealTime = GUILayout.Toggle(_movieCapture.IsRealTime, "RealTime");
|
|
|
|
GUILayout.Space(16f);
|
|
|
|
|
|
if (_movieCapture.OutputTarget == OutputTarget.VideoFile)
|
|
{
|
|
// Video Codec
|
|
GUILayout.BeginHorizontal();
|
|
if (_shownSection != Section.VideoCodecs)
|
|
{
|
|
if (GUILayout.Button("+", GUILayout.Width(24)))
|
|
{
|
|
_shownSection = Section.VideoCodecs;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GUILayout.Button("-", GUILayout.Width(24)))
|
|
{
|
|
_shownSection = Section.None;
|
|
}
|
|
}
|
|
GUILayout.Label("Using Video Codec: " + ((_movieCapture.SelectedVideoCodec != null)?_movieCapture.SelectedVideoCodec.Name:"None"));
|
|
#if UNITY_EDITOR_WIN || (!UNITY_EDITOR && UNITY_STANDALONE_WIN)
|
|
if (_movieCapture.SelectedVideoCodec != null && _movieCapture.SelectedVideoCodec.HasConfigwindow)
|
|
{
|
|
GUILayout.Space(16f);
|
|
if (GUILayout.Button("Configure Codec"))
|
|
{
|
|
_movieCapture.SelectedVideoCodec.ShowConfigWindow();
|
|
}
|
|
}
|
|
#endif
|
|
GUILayout.EndHorizontal();
|
|
|
|
if (_videoCodecNames != null && _shownSection == Section.VideoCodecs)
|
|
{
|
|
GUILayout.Label("Select Video Codec:");
|
|
_videoPos = GUILayout.BeginScrollView(_videoPos, GUILayout.Height(100));
|
|
int videoIndex = _movieCapture.NativeForceVideoCodecIndex;
|
|
int newCodecIndex = GUILayout.SelectionGrid(videoIndex, _videoCodecNames, 1);
|
|
GUILayout.EndScrollView();
|
|
|
|
if (newCodecIndex != videoIndex)
|
|
{
|
|
_movieCapture.NativeForceVideoCodecIndex = newCodecIndex;
|
|
Codec newCodec = _movieCapture.SelectVideoCodec();
|
|
if (newCodec != null)
|
|
{
|
|
_movieCapture.NativeForceVideoCodecIndex = newCodec.Index;
|
|
}
|
|
newCodec = _movieCapture.SelectAudioCodec();
|
|
if (newCodec != null)
|
|
{
|
|
_movieCapture.NativeForceAudioCodecIndex = newCodec.Index;
|
|
}
|
|
Device newDevice = _movieCapture.SelectAudioInputDevice();
|
|
if (newDevice != null)
|
|
{
|
|
_movieCapture.ForceAudioInputDeviceIndex = newDevice.Index;
|
|
}
|
|
_shownSection = Section.None;
|
|
}
|
|
}
|
|
GUILayout.Space(16f);
|
|
|
|
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.Label("Audio Source:", GUILayout.ExpandWidth(false));
|
|
_movieCapture.AudioCaptureSource = (AudioCaptureSource)GUILayout.SelectionGrid((int)_movieCapture.AudioCaptureSource, new string[] { "None", "Unity", "Microphone", "Manual" }, 4);
|
|
GUILayout.EndHorizontal();
|
|
GUILayout.Space(16f);
|
|
|
|
GUI.enabled = (_movieCapture.IsRealTime || _movieCapture.AudioCaptureSource == AudioCaptureSource.Manual
|
|
#if AVPRO_MOVIECAPTURE_OFFLINE_AUDIOCAPTURE
|
|
|| _movieCapture.AudioCaptureSource == AudioCaptureSource.Unity
|
|
#endif
|
|
);
|
|
|
|
if (_movieCapture.AudioCaptureSource == AudioCaptureSource.Microphone && _audioDeviceNames != null)
|
|
{
|
|
// Audio Device
|
|
GUILayout.BeginHorizontal();
|
|
if (_shownSection != Section.AudioInputDevices)
|
|
{
|
|
if (GUILayout.Button("+", GUILayout.Width(24)))
|
|
{
|
|
_shownSection = Section.AudioInputDevices;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GUILayout.Button("-", GUILayout.Width(24)))
|
|
{
|
|
_shownSection = Section.None;
|
|
}
|
|
}
|
|
|
|
if (_movieCapture.ForceAudioInputDeviceIndex >= 0 && _movieCapture.ForceAudioInputDeviceIndex < _audioDeviceNames.Length)
|
|
{
|
|
GUILayout.Label("Using Microphone: " + _audioDeviceNames[_movieCapture.ForceAudioInputDeviceIndex]);
|
|
}
|
|
GUILayout.EndHorizontal();
|
|
|
|
if (_shownSection == Section.AudioInputDevices)
|
|
{
|
|
GUILayout.Label("Select Microphone:");
|
|
_audioPos = GUILayout.BeginScrollView(_audioPos, GUILayout.Height(100));
|
|
int audioIndex = _movieCapture.ForceAudioInputDeviceIndex;
|
|
int newAudioIndex = GUILayout.SelectionGrid(audioIndex, _audioDeviceNames, 1);
|
|
GUILayout.EndScrollView();
|
|
|
|
if (newAudioIndex != audioIndex)
|
|
{
|
|
_movieCapture.ForceAudioInputDeviceIndex = newAudioIndex;
|
|
Device newDevice = _movieCapture.SelectAudioInputDevice();
|
|
if (newDevice != null)
|
|
{
|
|
_movieCapture.ForceAudioInputDeviceIndex = newDevice.Index;
|
|
}
|
|
_shownSection = Section.None;
|
|
}
|
|
}
|
|
GUILayout.Space(16f);
|
|
}
|
|
if (_movieCapture.AudioCaptureSource != AudioCaptureSource.None)
|
|
{
|
|
// Audio Codec
|
|
GUILayout.BeginHorizontal();
|
|
if (_shownSection != Section.AudioCodecs)
|
|
{
|
|
if (GUILayout.Button("+", GUILayout.Width(24)))
|
|
{
|
|
_shownSection = Section.AudioCodecs;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GUILayout.Button("-", GUILayout.Width(24)))
|
|
{
|
|
_shownSection = Section.None;
|
|
}
|
|
}
|
|
GUILayout.Label("Using Audio Codec: " + ((_movieCapture.SelectedAudioCodec != null)?_movieCapture.SelectedAudioCodec.Name:"None"));
|
|
if (_movieCapture.SelectedAudioCodec != null && _movieCapture.SelectedAudioCodec.HasConfigwindow)
|
|
{
|
|
GUILayout.Space(16f);
|
|
if (GUILayout.Button("Configure Codec"))
|
|
{
|
|
_movieCapture.SelectedAudioCodec.ShowConfigWindow();
|
|
}
|
|
}
|
|
GUILayout.EndHorizontal();
|
|
|
|
if (_audioCodecNames != null && _shownSection == Section.AudioCodecs)
|
|
{
|
|
GUILayout.Label("Select Audio Codec:");
|
|
_audioCodecPos = GUILayout.BeginScrollView(_audioCodecPos, GUILayout.Height(100));
|
|
int codecIndex = _movieCapture.NativeForceAudioCodecIndex;
|
|
int newCodecIndex = GUILayout.SelectionGrid(codecIndex, _audioCodecNames, 1);
|
|
GUILayout.EndScrollView();
|
|
if (newCodecIndex != codecIndex)
|
|
{
|
|
_movieCapture.NativeForceAudioCodecIndex = newCodecIndex;
|
|
Codec newCodec = _movieCapture.SelectAudioCodec();
|
|
if (newCodec != null)
|
|
{
|
|
_movieCapture.NativeForceAudioCodecIndex = newCodec.Index;
|
|
}
|
|
newCodec = _movieCapture.SelectVideoCodec();
|
|
if (newCodec != null)
|
|
{
|
|
_movieCapture.NativeForceVideoCodecIndex = newCodec.Index;
|
|
}
|
|
newCodec = _movieCapture.SelectAudioCodec();
|
|
if (newCodec != null)
|
|
{
|
|
_movieCapture.NativeForceAudioCodecIndex = newCodec.Index;
|
|
}
|
|
Device newDevice = _movieCapture.SelectAudioInputDevice();
|
|
if (newDevice != null)
|
|
{
|
|
_movieCapture.ForceAudioInputDeviceIndex = newDevice.Index;
|
|
}
|
|
_shownSection = Section.None;
|
|
}
|
|
|
|
}
|
|
GUILayout.Space(16f);
|
|
}
|
|
|
|
GUI.enabled = true;
|
|
|
|
GUILayout.Space(16f);
|
|
}
|
|
else if (_movieCapture.OutputTarget == OutputTarget.ImageSequence)
|
|
{
|
|
// Image Codec
|
|
GUILayout.BeginHorizontal();
|
|
if (_shownSection != Section.ImageCodecs)
|
|
{
|
|
if (GUILayout.Button("+", GUILayout.Width(24)))
|
|
{
|
|
_shownSection = Section.ImageCodecs;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GUILayout.Button("-", GUILayout.Width(24)))
|
|
{
|
|
_shownSection = Section.None;
|
|
}
|
|
}
|
|
GUILayout.Label("Using Image Codec: " + _movieCapture.NativeImageSequenceFormat);
|
|
GUILayout.EndHorizontal();
|
|
|
|
if (_shownSection == Section.ImageCodecs)
|
|
{
|
|
GUILayout.Label("Select Image Codec:");
|
|
_imageCodecPos = GUILayout.BeginScrollView(_imageCodecPos, GUILayout.Height(100));
|
|
int newCodecIndex = GUILayout.SelectionGrid(-1, Utils.GetNativeImageSequenceFormatNames(), 1);
|
|
GUILayout.EndScrollView();
|
|
if (newCodecIndex >= 0)
|
|
{
|
|
_movieCapture.NativeImageSequenceFormat = (ImageSequenceFormat)newCodecIndex;
|
|
_shownSection = Section.None;
|
|
}
|
|
}
|
|
GUILayout.Space(16f);
|
|
}
|
|
|
|
GUILayout.BeginHorizontal();
|
|
if (_movieCapture.OutputTarget == OutputTarget.VideoFile)
|
|
{
|
|
_movieCapture.AllowManualFileExtension = false;
|
|
GUILayout.Label("Filename Prefix: ");
|
|
_movieCapture.FilenamePrefix = GUILayout.TextField(_movieCapture.FilenamePrefix, 64);
|
|
}
|
|
else if (_movieCapture.OutputTarget == OutputTarget.ImageSequence)
|
|
{
|
|
GUILayout.Label("Filename Prefix: ");
|
|
_movieCapture.FilenamePrefix = GUILayout.TextField(_movieCapture.FilenamePrefix, 64);
|
|
}
|
|
else if (_movieCapture.OutputTarget == OutputTarget.NamedPipe)
|
|
{
|
|
GUILayout.Label("Path: ");
|
|
_movieCapture.NamedPipePath = GUILayout.TextField(_movieCapture.NamedPipePath, 64);
|
|
}
|
|
|
|
|
|
GUILayout.EndHorizontal();
|
|
GUILayout.Space(16f);
|
|
GUILayout.Space(16f);
|
|
|
|
if (_whenRecordingAutoHideUI)
|
|
{
|
|
GUILayout.Label("(Press CTRL-F5 to stop capture)");
|
|
}
|
|
|
|
GUILayout.BeginHorizontal();
|
|
if (!_movieCapture.IsCapturing())
|
|
{
|
|
GUI.color = Color.green;
|
|
if (GUILayout.Button(_movieCapture.IsRealTime?"Start Capture":"Start Render"))
|
|
{
|
|
StartCapture();
|
|
}
|
|
GUI.color = Color.white;
|
|
}
|
|
else
|
|
{
|
|
/*if (!_movieCapture.IsPaused())
|
|
{
|
|
if (GUILayout.Button("Pause Capture"))
|
|
{
|
|
PauseCapture();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GUILayout.Button("Resume Capture"))
|
|
{
|
|
ResumeCapture();
|
|
}
|
|
}
|
|
|
|
if (GUILayout.Button("Cancel Capture"))
|
|
{
|
|
CancelCapture();
|
|
}
|
|
if (GUILayout.Button("Stop Capture"))
|
|
{
|
|
StopCapture();
|
|
}*/
|
|
}
|
|
GUILayout.EndHorizontal();
|
|
|
|
if (_movieCapture.IsCapturing())
|
|
{
|
|
if (!string.IsNullOrEmpty(_movieCapture.LastFilePath))
|
|
{
|
|
GUILayout.Label("Writing file: '" + System.IO.Path.GetFileName(_movieCapture.LastFilePath) + "'");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!string.IsNullOrEmpty(CaptureBase.LastFileSaved))
|
|
{
|
|
GUILayout.Space(16f);
|
|
GUILayout.Label("Last file written: '" + System.IO.Path.GetFileName(CaptureBase.LastFileSaved) + "'");
|
|
|
|
GUILayout.BeginHorizontal();
|
|
if (GUILayout.Button("Browse"))
|
|
{
|
|
Utils.ShowInExplorer(CaptureBase.LastFileSaved);
|
|
}
|
|
Color prevColor = GUI.color;
|
|
GUI.color = Color.cyan;
|
|
if (GUILayout.Button("View Last Capture"))
|
|
{
|
|
Utils.OpenInDefaultApp(CaptureBase.LastFileSaved);
|
|
}
|
|
GUI.color = prevColor;
|
|
|
|
GUILayout.EndHorizontal();
|
|
}
|
|
}
|
|
}
|
|
|
|
GUILayout.EndVertical();
|
|
|
|
GL.sRGBWrite = sRGBWritePrev;
|
|
}
|
|
|
|
private void GUI_RecordingStatus()
|
|
{
|
|
GUILayout.Space(8.0f);
|
|
DrawPauseResumeButtons();
|
|
GUILayout.Label("Output", GUI.skin.box);
|
|
GUILayout.BeginVertical(GUI.skin.box);
|
|
|
|
Texture texture = _movieCapture.GetPreviewTexture();
|
|
if (texture != null)
|
|
{
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.FlexibleSpace();
|
|
float width = (Screen.width / 8f);
|
|
float aspect = (float)texture.width / (float)texture.height;
|
|
Rect textureRect = GUILayoutUtility.GetRect(width, width / aspect, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(false));
|
|
GUI.DrawTexture(textureRect, texture, ScaleMode.ScaleToFit, false);
|
|
GUILayout.FlexibleSpace();
|
|
GUILayout.EndHorizontal();
|
|
}
|
|
|
|
GUILayout.Label(System.IO.Path.GetFileName(_movieCapture.LastFilePath), GUI.skin.box);
|
|
GUILayout.Space(8.0f);
|
|
|
|
GUILayout.Label("Video", GUI.skin.box);
|
|
DrawGuiField("Dimensions", _movieCapture.GetRecordingWidth() + "x" + _movieCapture.GetRecordingHeight() + " @ " + _movieCapture.FrameRate.ToString("F2") + "hz");
|
|
if (_movieCapture.OutputTarget == OutputTarget.VideoFile)
|
|
{
|
|
DrawGuiField("Codec", (_movieCapture.SelectedVideoCodec != null)?_movieCapture.SelectedVideoCodec.Name:"None");
|
|
}
|
|
else if (_movieCapture.OutputTarget == OutputTarget.ImageSequence)
|
|
{
|
|
DrawGuiField("Codec",_movieCapture.NativeImageSequenceFormat.ToString());
|
|
}
|
|
|
|
if (_movieCapture.OutputTarget == OutputTarget.VideoFile)
|
|
{
|
|
if (_movieCapture.CaptureStats.AudioCaptureSource != AudioCaptureSource.None)
|
|
{
|
|
GUILayout.Label("Audio", GUI.skin.box);
|
|
if (_movieCapture.AudioCaptureSource == AudioCaptureSource.Unity)
|
|
{
|
|
DrawGuiField("Source", "Unity");
|
|
}
|
|
else if (_movieCapture.AudioCaptureSource == AudioCaptureSource.Microphone)
|
|
{
|
|
DrawGuiField("Source", (_movieCapture.SelectedAudioInputDevice != null)?_movieCapture.SelectedAudioInputDevice.Name:"None");
|
|
}
|
|
DrawGuiField("Codec", (_movieCapture.SelectedAudioCodec != null)?_movieCapture.SelectedAudioCodec.Name:"None");
|
|
if (_movieCapture.AudioCaptureSource == AudioCaptureSource.Unity)
|
|
{
|
|
DrawGuiField("Sample Rate", _movieCapture.CaptureStats.UnityAudioSampleRate.ToString() + "hz");
|
|
DrawGuiField("Channels", _movieCapture.CaptureStats.UnityAudioChannelCount.ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
GUILayout.EndVertical();
|
|
|
|
GUILayout.Space(8.0f);
|
|
|
|
// Draw progress bar
|
|
if (_movieCapture.StopMode != (int)StopMode.None)
|
|
{
|
|
Rect r = GUILayoutUtility.GetRect(128f, GUI.skin.label.CalcHeight(GUIContent.none, 32f), GUILayout.ExpandWidth(true));
|
|
float progress = _movieCapture.GetProgress();
|
|
Rect progressRect = new Rect(r);
|
|
progressRect.width *= progress;
|
|
GUI.color = new Color(0f, 0.5f, 0f, 1f);
|
|
GUI.Box(progressRect, GUIContent.none, _tintableBox);
|
|
GUI.color = Color.white;
|
|
GUI.backgroundColor = Color.clear;
|
|
GUI.Box(r, (progress * 100f).ToString("F1") + "%", _tintableBox);
|
|
GUI.color = Color.white;
|
|
}
|
|
|
|
GUILayout.Label("Stats", GUI.skin.box);
|
|
GUILayout.BeginVertical(GUI.skin.box);
|
|
|
|
if (_movieCapture.CaptureStats.FPS > 0f)
|
|
{
|
|
Color originalColor = GUI.color;
|
|
if (_movieCapture.IsRealTime)
|
|
{
|
|
float fpsDelta = (_movieCapture.CaptureStats.FPS - _movieCapture.FrameRate);
|
|
GUI.color = Color.red;
|
|
if (fpsDelta > -10)
|
|
{
|
|
GUI.color = Color.yellow;
|
|
}
|
|
if (fpsDelta > -2)
|
|
{
|
|
GUI.color = Color.green;
|
|
}
|
|
}
|
|
|
|
DrawGuiField("Capture Rate", string.Format("{0:0.##} / {1:F2} FPS", _movieCapture.CaptureStats.FPS, _movieCapture.FrameRate));
|
|
|
|
GUI.color = originalColor;
|
|
}
|
|
else
|
|
{
|
|
DrawGuiField("Capture Rate", string.Format(".. / {0:F2} FPS", _movieCapture.FrameRate));
|
|
}
|
|
|
|
DrawGuiField("File Size", ((float)_lastFileSize / (1024f * 1024f)).ToString("F1") + "MB");
|
|
DrawGuiField("Video Length", _lastEncodedMinutes.ToString("00") + ":" + _lastEncodedSeconds.ToString("00") + "." + _lastEncodedFrame.ToString("000"));
|
|
|
|
GUILayout.Label("Dropped Frames", GUI.skin.box);
|
|
DrawGuiField("In Unity", _movieCapture.CaptureStats.NumDroppedFrames.ToString());
|
|
DrawGuiField("In Encoder ", _movieCapture.CaptureStats.NumDroppedEncoderFrames.ToString());
|
|
if (_movieCapture.CaptureStats.AudioCaptureSource != AudioCaptureSource.None)
|
|
{
|
|
if (_movieCapture.AudioCaptureSource == AudioCaptureSource.Unity && _movieCapture.UnityAudioCapture != null)
|
|
{
|
|
DrawGuiField("Audio Overflows", _movieCapture.UnityAudioCapture.OverflowCount.ToString());
|
|
}
|
|
}
|
|
|
|
GUILayout.EndVertical();
|
|
}
|
|
|
|
private void DrawPauseResumeButtons()
|
|
{
|
|
GUILayout.BeginHorizontal();
|
|
|
|
if (!_movieCapture.IsPaused())
|
|
{
|
|
GUI.backgroundColor = Color.yellow;
|
|
if (GUILayout.Button("Pause Capture"))
|
|
{
|
|
PauseCapture();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GUI.backgroundColor = Color.green;
|
|
if (GUILayout.Button("Resume Capture"))
|
|
{
|
|
ResumeCapture();
|
|
}
|
|
}
|
|
|
|
GUI.backgroundColor = Color.cyan;
|
|
if (GUILayout.Button("Cancel Capture"))
|
|
{
|
|
CancelCapture();
|
|
}
|
|
GUI.backgroundColor = Color.red;
|
|
if (GUILayout.Button("Stop Capture"))
|
|
{
|
|
StopCapture();
|
|
}
|
|
GUI.backgroundColor = Color.white;
|
|
|
|
GUILayout.EndHorizontal();
|
|
}
|
|
|
|
private void DrawGuiField(string a, string b)
|
|
{
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.Label(a);
|
|
GUILayout.FlexibleSpace();
|
|
GUILayout.Label(b);
|
|
GUILayout.EndHorizontal();
|
|
}
|
|
|
|
private void StartCapture()
|
|
{
|
|
_lastFileSize = 0;
|
|
_lastEncodedMinutes = _lastEncodedSeconds = _lastEncodedFrame = 0;
|
|
if (_whenRecordingAutoHideUI)
|
|
{
|
|
_showUI = false;
|
|
}
|
|
if (_movieCapture != null)
|
|
{
|
|
_movieCapture.StartCapture();
|
|
}
|
|
}
|
|
|
|
private void StopCapture()
|
|
{
|
|
if (_movieCapture != null)
|
|
{
|
|
_movieCapture.StopCapture();
|
|
}
|
|
}
|
|
|
|
private void CancelCapture()
|
|
{
|
|
if (_movieCapture != null)
|
|
{
|
|
_movieCapture.CancelCapture();
|
|
}
|
|
}
|
|
|
|
private void ResumeCapture()
|
|
{
|
|
if (_movieCapture != null)
|
|
{
|
|
_movieCapture.ResumeCapture();
|
|
}
|
|
}
|
|
|
|
private void PauseCapture()
|
|
{
|
|
if (_movieCapture != null)
|
|
{
|
|
_movieCapture.PauseCapture();
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (_movieCapture != null)
|
|
{
|
|
if (_whenRecordingAutoHideUI && !_showUI)
|
|
{
|
|
if (!_movieCapture.IsCapturing())
|
|
_showUI = true;
|
|
}
|
|
|
|
if (Input.GetKey(KeyCode.LeftControl) && Input.GetKeyDown(KeyCode.F5))
|
|
{
|
|
if (_movieCapture.IsCapturing())
|
|
{
|
|
_movieCapture.StopCapture();
|
|
}
|
|
}
|
|
|
|
if (_movieCapture.IsCapturing())
|
|
{
|
|
_lastFileSize = _movieCapture.GetCaptureFileSize();
|
|
if (!_movieCapture.IsRealTime)
|
|
{
|
|
_lastEncodedSeconds = (uint)Mathf.FloorToInt((float)_movieCapture.CaptureStats.NumEncodedFrames / _movieCapture.FrameRate);
|
|
}
|
|
else
|
|
{
|
|
_lastEncodedSeconds = _movieCapture.CaptureStats.TotalEncodedSeconds;
|
|
}
|
|
_lastEncodedMinutes = _lastEncodedSeconds / 60;
|
|
_lastEncodedSeconds = _lastEncodedSeconds % 60;
|
|
_lastEncodedFrame = _movieCapture.CaptureStats.NumEncodedFrames % (uint)_movieCapture.FrameRate;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |