CaptureGUI.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881
  1. #if UNITY_2017_3_OR_NEWER
  2. #define AVPRO_MOVIECAPTURE_OFFLINE_AUDIOCAPTURE
  3. #endif
  4. using UnityEngine;
  5. using System.Text;
  6. using System.Collections;
  7. //-----------------------------------------------------------------------------
  8. // Copyright 2012-2022 RenderHeads Ltd. All rights reserved.
  9. //-----------------------------------------------------------------------------
  10. namespace RenderHeads.Media.AVProMovieCapture
  11. {
  12. /// <summary>
  13. /// Uses IMGUI to render a GUI to control video capture. This is mainly used for the demos.
  14. /// </summary>
  15. [AddComponentMenu("AVPro Movie Capture/Utils/Capture GUI", 300)]
  16. public class CaptureGUI : MonoBehaviour
  17. {
  18. private enum Section
  19. {
  20. None,
  21. VideoCodecs,
  22. AudioCodecs,
  23. AudioInputDevices,
  24. ImageCodecs,
  25. }
  26. [SerializeField] CaptureBase _movieCapture = null;
  27. [SerializeField] bool _showUI = true;
  28. [SerializeField] bool _whenRecordingAutoHideUI = true;
  29. [SerializeField] GUISkin _guiSkin = null;
  30. public CaptureBase MovieCapture
  31. {
  32. get { return _movieCapture; }
  33. set { _movieCapture = value; }
  34. }
  35. public bool HideUiWhenRecording
  36. {
  37. get { return _whenRecordingAutoHideUI; }
  38. set { _whenRecordingAutoHideUI = value; }
  39. }
  40. public bool ShowUI
  41. {
  42. get { return _showUI; }
  43. set { _showUI = value; }
  44. }
  45. private readonly static string[] CommonFrameRateNames = { "1", "10", "15", "23.98", "24", "25", "29.97", "30", "50", "59.94", "60", "75", "90", "120" };
  46. private readonly static float[] CommonFrameRateValues = { 1f, 10f, 15f, 23.976f, 24f, 25f, 29.97f, 30f, 50f, 59.94f, 60f, 75f, 90f, 120f };
  47. // GUI
  48. private Section _shownSection = Section.None;
  49. private string[] _videoCodecNames = new string[0];
  50. private string[] _audioCodecNames = new string[0];
  51. private bool[] _videoCodecConfigurable = new bool[0];
  52. private bool[] _audioCodecConfigurable = new bool[0];
  53. private string[] _audioDeviceNames = new string[0];
  54. private string[] _downScales = { "Original", "Half", "Quarter", "Eighth", "Sixteenth", "Custom" };
  55. private string[] _outputType = { "Video File", "Image Sequence", "Named Pipe" };
  56. private int _downScaleIndex;
  57. private GUIStyle _tintableBox;
  58. private Vector2 _videoPos = Vector2.zero;
  59. private Vector2 _audioPos = Vector2.zero;
  60. private Vector2 _audioCodecPos = Vector2.zero;
  61. private Vector2 _imageCodecPos = Vector2.zero;
  62. // Status
  63. private long _lastFileSize;
  64. private uint _lastEncodedMinutes;
  65. private uint _lastEncodedSeconds;
  66. private uint _lastEncodedFrame;
  67. private void Start()
  68. {
  69. if (_movieCapture != null)
  70. {
  71. CreateGUI();
  72. }
  73. }
  74. private void CreateGUI()
  75. {
  76. switch (_movieCapture.ResolutionDownScale)
  77. {
  78. default:
  79. case CaptureBase.DownScale.Original:
  80. _downScaleIndex = 0;
  81. break;
  82. case CaptureBase.DownScale.Half:
  83. _downScaleIndex = 1;
  84. break;
  85. case CaptureBase.DownScale.Quarter:
  86. _downScaleIndex = 2;
  87. break;
  88. case CaptureBase.DownScale.Eighth:
  89. _downScaleIndex = 3;
  90. break;
  91. case CaptureBase.DownScale.Sixteenth:
  92. _downScaleIndex = 4;
  93. break;
  94. case CaptureBase.DownScale.Custom:
  95. _downScaleIndex = 5;
  96. break;
  97. }
  98. if (CodecManager.VideoCodecs.Count > 0)
  99. {
  100. _videoCodecNames = new string[CodecManager.VideoCodecs.Count];
  101. _videoCodecConfigurable = new bool[CodecManager.VideoCodecs.Count];
  102. int i = 0;
  103. foreach (Codec codec in CodecManager.VideoCodecs)
  104. {
  105. _videoCodecNames[i] = codec.Name;
  106. _videoCodecConfigurable[i] = codec.HasConfigwindow;
  107. i++;
  108. }
  109. }
  110. if (CodecManager.AudioCodecs.Count > 0)
  111. {
  112. _audioCodecNames = new string[CodecManager.AudioCodecs.Count];
  113. _audioCodecConfigurable = new bool[CodecManager.AudioCodecs.Count];
  114. int i = 0;
  115. foreach (Codec codec in CodecManager.AudioCodecs)
  116. {
  117. _audioCodecNames[i] = codec.Name;
  118. _audioCodecConfigurable[i] = codec.HasConfigwindow;
  119. i++;
  120. }
  121. }
  122. int numAudioDevices = NativePlugin.GetAudioInputDeviceCount();
  123. if (numAudioDevices > 0)
  124. {
  125. _audioDeviceNames = new string[numAudioDevices];
  126. for (int i = 0; i < numAudioDevices; i++)
  127. {
  128. _audioDeviceNames[i] = NativePlugin.GetAudioInputDeviceName(i);
  129. }
  130. }
  131. _movieCapture.SelectVideoCodec();
  132. _movieCapture.SelectAudioCodec();
  133. _movieCapture.SelectAudioInputDevice();
  134. }
  135. private void OnGUI()
  136. {
  137. GUI.skin = _guiSkin;
  138. GUI.depth = -10;
  139. if (_tintableBox == null)
  140. {
  141. _tintableBox = new GUIStyle(GUI.skin.box);
  142. _tintableBox.normal.background = Texture2D.whiteTexture;
  143. _tintableBox.border.left = _tintableBox.border.right = _tintableBox.border.top = _tintableBox.border.bottom = 0;
  144. }
  145. #if (UNITY_IOS || UNITY_ANDROID) && !UNITY_EDITOR
  146. float sf = Screen.dpi > 300.0f ? 2.0f : 1.5f;
  147. #else
  148. float sf = 1.0f;
  149. #endif
  150. if (Screen.width >= Screen.height)
  151. GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(Screen.width / 1920f * sf, Screen.height / 1080f * sf, 1f));
  152. else
  153. GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(Screen.width / 1080f * sf, Screen.height / 1920f * sf, 1f));
  154. if (_showUI)
  155. {
  156. #if UNITY_IOS && !UNITY_EDITOR_OSX
  157. float y = 40.0f;
  158. #else
  159. float y = 0.0f;
  160. #endif
  161. GUILayout.Window(4, new Rect(0f, y, 480f, 256f), MyWindow, "AVPro Movie Capture UI");
  162. }
  163. }
  164. private void MyWindow(int id)
  165. {
  166. if (_movieCapture == null)
  167. {
  168. GUILayout.Label("CaptureGUI - No CaptureFrom component set");
  169. return;
  170. }
  171. // NOTE: From Unity 2020.1 onwards it seems this correction isn't needed, but it's needed
  172. // for older versions of Unity when running in Linear colorspace
  173. bool sRGBWritePrev = GL.sRGBWrite;
  174. GL.sRGBWrite = false;
  175. if (_movieCapture.IsCapturing())
  176. {
  177. GUI_RecordingStatus();
  178. GL.sRGBWrite = sRGBWritePrev;
  179. return;
  180. }
  181. GUILayout.BeginVertical();
  182. if (_movieCapture != null)
  183. {
  184. GUILayout.Label("Resolution:");
  185. GUILayout.BeginHorizontal();
  186. _downScaleIndex = GUILayout.SelectionGrid(_downScaleIndex, _downScales, _downScales.Length);
  187. switch (_downScaleIndex)
  188. {
  189. case 0:
  190. _movieCapture.ResolutionDownScale = CaptureBase.DownScale.Original;
  191. break;
  192. case 1:
  193. _movieCapture.ResolutionDownScale = CaptureBase.DownScale.Half;
  194. break;
  195. case 2:
  196. _movieCapture.ResolutionDownScale = CaptureBase.DownScale.Quarter;
  197. break;
  198. case 3:
  199. _movieCapture.ResolutionDownScale = CaptureBase.DownScale.Eighth;
  200. break;
  201. case 4:
  202. _movieCapture.ResolutionDownScale = CaptureBase.DownScale.Sixteenth;
  203. break;
  204. case 5:
  205. _movieCapture.ResolutionDownScale = CaptureBase.DownScale.Custom;
  206. break;
  207. }
  208. GUILayout.EndHorizontal();
  209. GUILayout.BeginHorizontal(GUILayout.Width(256));
  210. if (_movieCapture.ResolutionDownScale == CaptureBase.DownScale.Custom)
  211. {
  212. string maxWidthString = GUILayout.TextField(Mathf.FloorToInt(_movieCapture.ResolutionDownscaleCustom.x).ToString(), 4);
  213. int maxWidth = 0;
  214. if (int.TryParse(maxWidthString, out maxWidth))
  215. {
  216. _movieCapture.ResolutionDownscaleCustom = new Vector2(Mathf.Clamp(maxWidth, 0, NativePlugin.MaxRenderWidth), _movieCapture.ResolutionDownscaleCustom.y);
  217. }
  218. GUILayout.Label("x", GUILayout.Width(20));
  219. string maxHeightString = GUILayout.TextField(Mathf.FloorToInt(_movieCapture.ResolutionDownscaleCustom.y).ToString(), 4);
  220. int maxHeight = 0;
  221. if (int.TryParse(maxHeightString, out maxHeight))
  222. {
  223. _movieCapture.ResolutionDownscaleCustom = new Vector2(_movieCapture.ResolutionDownscaleCustom.x, Mathf.Clamp(maxHeight, 0, NativePlugin.MaxRenderHeight));
  224. }
  225. }
  226. GUILayout.EndHorizontal();
  227. GUILayout.Space(16f);
  228. GUILayout.Label("Frame Rate: " + _movieCapture.FrameRate.ToString("F2"));
  229. GUILayout.BeginHorizontal();
  230. for (int i = 0; i < CommonFrameRateNames.Length; i++)
  231. {
  232. if (GUILayout.Toggle(_movieCapture.FrameRate == CommonFrameRateValues[i], CommonFrameRateNames[i]))
  233. {
  234. _movieCapture.FrameRate = CommonFrameRateValues[i];
  235. }
  236. }
  237. GUILayout.EndHorizontal();
  238. GUILayout.Space(16f);
  239. GUILayout.BeginHorizontal();
  240. GUILayout.Label("Output:", GUILayout.ExpandWidth(false));
  241. OutputTarget outputType = (OutputTarget)GUILayout.SelectionGrid((int)_movieCapture.OutputTarget, _outputType, _outputType.Length);
  242. if (outputType != _movieCapture.OutputTarget)
  243. {
  244. _movieCapture.OutputTarget = outputType;
  245. // TODO: Set this to last used or sensible platform default
  246. switch (outputType) {
  247. case OutputTarget.VideoFile:
  248. break;
  249. case OutputTarget.ImageSequence:
  250. break;
  251. case OutputTarget.NamedPipe:
  252. break;
  253. }
  254. }
  255. GUILayout.EndHorizontal();
  256. GUILayout.Space(16f);
  257. _movieCapture.IsRealTime = GUILayout.Toggle(_movieCapture.IsRealTime, "RealTime");
  258. GUILayout.Space(16f);
  259. if (_movieCapture.OutputTarget == OutputTarget.VideoFile)
  260. {
  261. // Video Codec
  262. GUILayout.BeginHorizontal();
  263. if (_shownSection != Section.VideoCodecs)
  264. {
  265. if (GUILayout.Button("+", GUILayout.Width(24)))
  266. {
  267. _shownSection = Section.VideoCodecs;
  268. }
  269. }
  270. else
  271. {
  272. if (GUILayout.Button("-", GUILayout.Width(24)))
  273. {
  274. _shownSection = Section.None;
  275. }
  276. }
  277. GUILayout.Label("Using Video Codec: " + ((_movieCapture.SelectedVideoCodec != null)?_movieCapture.SelectedVideoCodec.Name:"None"));
  278. #if UNITY_EDITOR_WIN || (!UNITY_EDITOR && UNITY_STANDALONE_WIN)
  279. if (_movieCapture.SelectedVideoCodec != null && _movieCapture.SelectedVideoCodec.HasConfigwindow)
  280. {
  281. GUILayout.Space(16f);
  282. if (GUILayout.Button("Configure Codec"))
  283. {
  284. _movieCapture.SelectedVideoCodec.ShowConfigWindow();
  285. }
  286. }
  287. #endif
  288. GUILayout.EndHorizontal();
  289. if (_videoCodecNames != null && _shownSection == Section.VideoCodecs)
  290. {
  291. GUILayout.Label("Select Video Codec:");
  292. _videoPos = GUILayout.BeginScrollView(_videoPos, GUILayout.Height(100));
  293. int videoIndex = _movieCapture.NativeForceVideoCodecIndex;
  294. int newCodecIndex = GUILayout.SelectionGrid(videoIndex, _videoCodecNames, 1);
  295. GUILayout.EndScrollView();
  296. if (newCodecIndex != videoIndex)
  297. {
  298. _movieCapture.NativeForceVideoCodecIndex = newCodecIndex;
  299. Codec newCodec = _movieCapture.SelectVideoCodec();
  300. if (newCodec != null)
  301. {
  302. _movieCapture.NativeForceVideoCodecIndex = newCodec.Index;
  303. }
  304. newCodec = _movieCapture.SelectAudioCodec();
  305. if (newCodec != null)
  306. {
  307. _movieCapture.NativeForceAudioCodecIndex = newCodec.Index;
  308. }
  309. Device newDevice = _movieCapture.SelectAudioInputDevice();
  310. if (newDevice != null)
  311. {
  312. _movieCapture.ForceAudioInputDeviceIndex = newDevice.Index;
  313. }
  314. _shownSection = Section.None;
  315. }
  316. }
  317. GUILayout.Space(16f);
  318. GUILayout.BeginHorizontal();
  319. GUILayout.Label("Audio Source:", GUILayout.ExpandWidth(false));
  320. _movieCapture.AudioCaptureSource = (AudioCaptureSource)GUILayout.SelectionGrid((int)_movieCapture.AudioCaptureSource, new string[] { "None", "Unity", "Microphone", "Manual", "Wwise" }, 5);
  321. GUILayout.EndHorizontal();
  322. GUILayout.Space(16f);
  323. GUI.enabled = (_movieCapture.IsRealTime || _movieCapture.AudioCaptureSource == AudioCaptureSource.Manual
  324. #if AVPRO_MOVIECAPTURE_OFFLINE_AUDIOCAPTURE
  325. || _movieCapture.AudioCaptureSource == AudioCaptureSource.Unity
  326. #endif
  327. || _movieCapture.AudioCaptureSource == AudioCaptureSource.Wwise
  328. );
  329. if (_movieCapture.AudioCaptureSource == AudioCaptureSource.Microphone && _audioDeviceNames != null)
  330. {
  331. // Audio Device
  332. GUILayout.BeginHorizontal();
  333. if (_shownSection != Section.AudioInputDevices)
  334. {
  335. if (GUILayout.Button("+", GUILayout.Width(24)))
  336. {
  337. _shownSection = Section.AudioInputDevices;
  338. }
  339. }
  340. else
  341. {
  342. if (GUILayout.Button("-", GUILayout.Width(24)))
  343. {
  344. _shownSection = Section.None;
  345. }
  346. }
  347. if (_movieCapture.ForceAudioInputDeviceIndex >= 0 && _movieCapture.ForceAudioInputDeviceIndex < _audioDeviceNames.Length)
  348. {
  349. GUILayout.Label("Using Microphone: " + _audioDeviceNames[_movieCapture.ForceAudioInputDeviceIndex]);
  350. }
  351. GUILayout.EndHorizontal();
  352. if (_shownSection == Section.AudioInputDevices)
  353. {
  354. GUILayout.Label("Select Microphone:");
  355. _audioPos = GUILayout.BeginScrollView(_audioPos, GUILayout.Height(100));
  356. int audioIndex = _movieCapture.ForceAudioInputDeviceIndex;
  357. int newAudioIndex = GUILayout.SelectionGrid(audioIndex, _audioDeviceNames, 1);
  358. GUILayout.EndScrollView();
  359. if (newAudioIndex != audioIndex)
  360. {
  361. _movieCapture.ForceAudioInputDeviceIndex = newAudioIndex;
  362. Device newDevice = _movieCapture.SelectAudioInputDevice();
  363. if (newDevice != null)
  364. {
  365. _movieCapture.ForceAudioInputDeviceIndex = newDevice.Index;
  366. }
  367. _shownSection = Section.None;
  368. }
  369. }
  370. GUILayout.Space(16f);
  371. }
  372. if (_movieCapture.AudioCaptureSource != AudioCaptureSource.None)
  373. {
  374. // Audio Codec
  375. GUILayout.BeginHorizontal();
  376. if (_shownSection != Section.AudioCodecs)
  377. {
  378. if (GUILayout.Button("+", GUILayout.Width(24)))
  379. {
  380. _shownSection = Section.AudioCodecs;
  381. }
  382. }
  383. else
  384. {
  385. if (GUILayout.Button("-", GUILayout.Width(24)))
  386. {
  387. _shownSection = Section.None;
  388. }
  389. }
  390. GUILayout.Label("Using Audio Codec: " + ((_movieCapture.SelectedAudioCodec != null)?_movieCapture.SelectedAudioCodec.Name:"None"));
  391. if (_movieCapture.SelectedAudioCodec != null && _movieCapture.SelectedAudioCodec.HasConfigwindow)
  392. {
  393. GUILayout.Space(16f);
  394. if (GUILayout.Button("Configure Codec"))
  395. {
  396. _movieCapture.SelectedAudioCodec.ShowConfigWindow();
  397. }
  398. }
  399. GUILayout.EndHorizontal();
  400. if (_audioCodecNames != null && _shownSection == Section.AudioCodecs)
  401. {
  402. GUILayout.Label("Select Audio Codec:");
  403. _audioCodecPos = GUILayout.BeginScrollView(_audioCodecPos, GUILayout.Height(100));
  404. int codecIndex = _movieCapture.NativeForceAudioCodecIndex;
  405. int newCodecIndex = GUILayout.SelectionGrid(codecIndex, _audioCodecNames, 1);
  406. GUILayout.EndScrollView();
  407. if (newCodecIndex != codecIndex)
  408. {
  409. _movieCapture.NativeForceAudioCodecIndex = newCodecIndex;
  410. Codec newCodec = _movieCapture.SelectAudioCodec();
  411. if (newCodec != null)
  412. {
  413. _movieCapture.NativeForceAudioCodecIndex = newCodec.Index;
  414. }
  415. newCodec = _movieCapture.SelectVideoCodec();
  416. if (newCodec != null)
  417. {
  418. _movieCapture.NativeForceVideoCodecIndex = newCodec.Index;
  419. }
  420. newCodec = _movieCapture.SelectAudioCodec();
  421. if (newCodec != null)
  422. {
  423. _movieCapture.NativeForceAudioCodecIndex = newCodec.Index;
  424. }
  425. Device newDevice = _movieCapture.SelectAudioInputDevice();
  426. if (newDevice != null)
  427. {
  428. _movieCapture.ForceAudioInputDeviceIndex = newDevice.Index;
  429. }
  430. _shownSection = Section.None;
  431. }
  432. }
  433. GUILayout.Space(16f);
  434. }
  435. GUI.enabled = true;
  436. GUILayout.Space(16f);
  437. }
  438. else if (_movieCapture.OutputTarget == OutputTarget.ImageSequence)
  439. {
  440. // Image Codec
  441. GUILayout.BeginHorizontal();
  442. if (_shownSection != Section.ImageCodecs)
  443. {
  444. if (GUILayout.Button("+", GUILayout.Width(24)))
  445. {
  446. _shownSection = Section.ImageCodecs;
  447. }
  448. }
  449. else
  450. {
  451. if (GUILayout.Button("-", GUILayout.Width(24)))
  452. {
  453. _shownSection = Section.None;
  454. }
  455. }
  456. GUILayout.Label("Using Image Codec: " + _movieCapture.NativeImageSequenceFormat);
  457. GUILayout.EndHorizontal();
  458. if (_shownSection == Section.ImageCodecs)
  459. {
  460. GUILayout.Label("Select Image Codec:");
  461. _imageCodecPos = GUILayout.BeginScrollView(_imageCodecPos, GUILayout.Height(100));
  462. int newCodecIndex = GUILayout.SelectionGrid(-1, Utils.GetNativeImageSequenceFormatNames(), 1);
  463. GUILayout.EndScrollView();
  464. if (newCodecIndex >= 0)
  465. {
  466. _movieCapture.NativeImageSequenceFormat = (ImageSequenceFormat)newCodecIndex;
  467. _shownSection = Section.None;
  468. }
  469. }
  470. GUILayout.Space(16f);
  471. }
  472. GUILayout.BeginHorizontal();
  473. if (_movieCapture.OutputTarget == OutputTarget.VideoFile)
  474. {
  475. _movieCapture.AllowManualFileExtension = false;
  476. GUILayout.Label("Filename Prefix: ");
  477. _movieCapture.FilenamePrefix = GUILayout.TextField(_movieCapture.FilenamePrefix, 64);
  478. }
  479. else if (_movieCapture.OutputTarget == OutputTarget.ImageSequence)
  480. {
  481. GUILayout.Label("Filename Prefix: ");
  482. _movieCapture.FilenamePrefix = GUILayout.TextField(_movieCapture.FilenamePrefix, 64);
  483. }
  484. else if (_movieCapture.OutputTarget == OutputTarget.NamedPipe)
  485. {
  486. GUILayout.Label("Path: ");
  487. _movieCapture.NamedPipePath = GUILayout.TextField(_movieCapture.NamedPipePath, 64);
  488. }
  489. GUILayout.EndHorizontal();
  490. GUILayout.Space(16f);
  491. GUILayout.Space(16f);
  492. if (_whenRecordingAutoHideUI)
  493. {
  494. GUILayout.Label("(Press CTRL-F5 to stop capture)");
  495. }
  496. GUILayout.BeginHorizontal();
  497. if (!_movieCapture.IsCapturing())
  498. {
  499. GUI.color = Color.green;
  500. if (GUILayout.Button(_movieCapture.IsRealTime?"Start Capture":"Start Render"))
  501. {
  502. StartCapture();
  503. }
  504. GUI.color = Color.white;
  505. }
  506. else
  507. {
  508. /*if (!_movieCapture.IsPaused())
  509. {
  510. if (GUILayout.Button("Pause Capture"))
  511. {
  512. PauseCapture();
  513. }
  514. }
  515. else
  516. {
  517. if (GUILayout.Button("Resume Capture"))
  518. {
  519. ResumeCapture();
  520. }
  521. }
  522. if (GUILayout.Button("Cancel Capture"))
  523. {
  524. CancelCapture();
  525. }
  526. if (GUILayout.Button("Stop Capture"))
  527. {
  528. StopCapture();
  529. }*/
  530. }
  531. GUILayout.EndHorizontal();
  532. if (_movieCapture.IsCapturing())
  533. {
  534. if (!string.IsNullOrEmpty(_movieCapture.LastFilePath))
  535. {
  536. GUILayout.Label("Writing file: '" + System.IO.Path.GetFileName(_movieCapture.LastFilePath) + "'");
  537. }
  538. }
  539. else
  540. {
  541. if (!string.IsNullOrEmpty(CaptureBase.LastFileSaved))
  542. {
  543. GUILayout.Space(16f);
  544. GUILayout.Label("Last file written: '" + System.IO.Path.GetFileName(CaptureBase.LastFileSaved) + "'");
  545. GUILayout.BeginHorizontal();
  546. #if (!UNITY_EDITOR && UNITY_ANDROID)
  547. #else
  548. if (GUILayout.Button("Browse"))
  549. {
  550. Utils.ShowInExplorer(CaptureBase.LastFileSaved);
  551. }
  552. #endif
  553. Color prevColor = GUI.color;
  554. GUI.color = Color.cyan;
  555. if (GUILayout.Button("View Last Capture"))
  556. {
  557. #if (!UNITY_EDITOR && UNITY_ANDROID)
  558. if (CaptureBase.LastFileSaved.ToLower().EndsWith(".mp4"))
  559. {
  560. Handheld.PlayFullScreenMovie(CaptureBase.LastFileSaved, Color.black, FullScreenMovieControlMode.CancelOnInput);
  561. }
  562. #else
  563. Utils.OpenInDefaultApp(CaptureBase.LastFileSaved);
  564. #endif
  565. }
  566. GUI.color = prevColor;
  567. GUILayout.EndHorizontal();
  568. }
  569. }
  570. }
  571. GUILayout.EndVertical();
  572. GL.sRGBWrite = sRGBWritePrev;
  573. }
  574. private void GUI_RecordingStatus()
  575. {
  576. GUILayout.Space(8.0f);
  577. DrawPauseResumeButtons();
  578. GUILayout.Label("Output", GUI.skin.box);
  579. GUILayout.BeginVertical(GUI.skin.box);
  580. Texture texture = _movieCapture.GetPreviewTexture();
  581. if (texture != null)
  582. {
  583. GUILayout.BeginHorizontal();
  584. GUILayout.FlexibleSpace();
  585. float width = (Screen.width / 8f);
  586. float aspect = (float)texture.width / (float)texture.height;
  587. Rect textureRect = GUILayoutUtility.GetRect(width, width / aspect, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(false));
  588. GUI.DrawTexture(textureRect, texture, ScaleMode.ScaleToFit, false);
  589. GUILayout.FlexibleSpace();
  590. GUILayout.EndHorizontal();
  591. }
  592. GUILayout.Label(System.IO.Path.GetFileName(_movieCapture.LastFilePath), GUI.skin.box);
  593. GUILayout.Space(8.0f);
  594. GUILayout.Label("Video", GUI.skin.box);
  595. DrawGuiField("Dimensions", _movieCapture.GetRecordingWidth() + "x" + _movieCapture.GetRecordingHeight() + " @ " + _movieCapture.FrameRate.ToString("F2") + "hz");
  596. if (_movieCapture.OutputTarget == OutputTarget.VideoFile)
  597. {
  598. DrawGuiField("Codec", (_movieCapture.SelectedVideoCodec != null)?_movieCapture.SelectedVideoCodec.Name:"None");
  599. }
  600. else if (_movieCapture.OutputTarget == OutputTarget.ImageSequence)
  601. {
  602. DrawGuiField("Codec",_movieCapture.NativeImageSequenceFormat.ToString());
  603. }
  604. if (_movieCapture.OutputTarget == OutputTarget.VideoFile)
  605. {
  606. if (_movieCapture.CaptureStats.AudioCaptureSource != AudioCaptureSource.None)
  607. {
  608. GUILayout.Label("Audio", GUI.skin.box);
  609. if (_movieCapture.AudioCaptureSource == AudioCaptureSource.Unity)
  610. {
  611. DrawGuiField("Source", "Unity");
  612. }
  613. else if (_movieCapture.AudioCaptureSource == AudioCaptureSource.Microphone)
  614. {
  615. DrawGuiField("Source", (_movieCapture.SelectedAudioInputDevice != null)?_movieCapture.SelectedAudioInputDevice.Name:"None");
  616. }
  617. DrawGuiField("Codec", (_movieCapture.SelectedAudioCodec != null)?_movieCapture.SelectedAudioCodec.Name:"None");
  618. if (_movieCapture.AudioCaptureSource == AudioCaptureSource.Unity)
  619. {
  620. DrawGuiField("Sample Rate", _movieCapture.CaptureStats.UnityAudioSampleRate.ToString() + "hz");
  621. DrawGuiField("Channels", _movieCapture.CaptureStats.UnityAudioChannelCount.ToString());
  622. }
  623. }
  624. }
  625. GUILayout.EndVertical();
  626. GUILayout.Space(8.0f);
  627. // Draw progress bar
  628. if (_movieCapture.StopMode != (int)StopMode.None)
  629. {
  630. Rect r = GUILayoutUtility.GetRect(128f, GUI.skin.label.CalcHeight(GUIContent.none, 32f), GUILayout.ExpandWidth(true));
  631. float progress = _movieCapture.GetProgress();
  632. Rect progressRect = new Rect(r);
  633. progressRect.width *= progress;
  634. GUI.color = new Color(0f, 0.5f, 0f, 1f);
  635. GUI.Box(progressRect, GUIContent.none, _tintableBox);
  636. GUI.color = Color.white;
  637. GUI.backgroundColor = Color.clear;
  638. GUI.Box(r, (progress * 100f).ToString("F1") + "%", _tintableBox);
  639. GUI.color = Color.white;
  640. }
  641. GUILayout.Label("Stats", GUI.skin.box);
  642. GUILayout.BeginVertical(GUI.skin.box);
  643. if (_movieCapture.CaptureStats.FPS > 0f)
  644. {
  645. Color originalColor = GUI.color;
  646. if (_movieCapture.IsRealTime)
  647. {
  648. float fpsDelta = (_movieCapture.CaptureStats.FPS - _movieCapture.FrameRate);
  649. GUI.color = Color.red;
  650. if (fpsDelta > -10)
  651. {
  652. GUI.color = Color.yellow;
  653. }
  654. if (fpsDelta > -2)
  655. {
  656. GUI.color = Color.green;
  657. }
  658. }
  659. DrawGuiField("Capture Rate", string.Format("{0:0.##} / {1:F2} FPS", _movieCapture.CaptureStats.FPS, _movieCapture.FrameRate));
  660. GUI.color = originalColor;
  661. }
  662. else
  663. {
  664. DrawGuiField("Capture Rate", string.Format(".. / {0:F2} FPS", _movieCapture.FrameRate));
  665. }
  666. DrawGuiField("File Size", ((float)_lastFileSize / (1024f * 1024f)).ToString("F1") + "MB");
  667. DrawGuiField("Video Length", _lastEncodedMinutes.ToString("00") + ":" + _lastEncodedSeconds.ToString("00") + "." + _lastEncodedFrame.ToString("000"));
  668. GUILayout.Label("Dropped Frames", GUI.skin.box);
  669. DrawGuiField("In Unity", _movieCapture.CaptureStats.NumDroppedFrames.ToString());
  670. DrawGuiField("In Encoder ", _movieCapture.CaptureStats.NumDroppedEncoderFrames.ToString());
  671. if (_movieCapture.CaptureStats.AudioCaptureSource != AudioCaptureSource.None)
  672. {
  673. if (_movieCapture.AudioCaptureSource == AudioCaptureSource.Unity && _movieCapture.UnityAudioCapture != null)
  674. {
  675. DrawGuiField("Audio Overflows", _movieCapture.UnityAudioCapture.OverflowCount.ToString());
  676. }
  677. }
  678. GUILayout.EndVertical();
  679. }
  680. private void DrawPauseResumeButtons()
  681. {
  682. GUILayout.BeginHorizontal();
  683. if (!_movieCapture.IsPaused())
  684. {
  685. GUI.backgroundColor = Color.yellow;
  686. if (GUILayout.Button("Pause Capture"))
  687. {
  688. PauseCapture();
  689. }
  690. }
  691. else
  692. {
  693. GUI.backgroundColor = Color.green;
  694. if (GUILayout.Button("Resume Capture"))
  695. {
  696. ResumeCapture();
  697. }
  698. }
  699. GUI.backgroundColor = Color.cyan;
  700. if (GUILayout.Button("Cancel Capture"))
  701. {
  702. CancelCapture();
  703. }
  704. GUI.backgroundColor = Color.red;
  705. if (GUILayout.Button("Stop Capture"))
  706. {
  707. StopCapture();
  708. }
  709. GUI.backgroundColor = Color.white;
  710. GUILayout.EndHorizontal();
  711. }
  712. private void DrawGuiField(string a, string b)
  713. {
  714. GUILayout.BeginHorizontal();
  715. GUILayout.Label(a);
  716. GUILayout.FlexibleSpace();
  717. GUILayout.Label(b);
  718. GUILayout.EndHorizontal();
  719. }
  720. private void StartCapture()
  721. {
  722. _lastFileSize = 0;
  723. _lastEncodedMinutes = _lastEncodedSeconds = _lastEncodedFrame = 0;
  724. if (_whenRecordingAutoHideUI)
  725. {
  726. _showUI = false;
  727. }
  728. if (_movieCapture != null)
  729. {
  730. _movieCapture.StartCapture();
  731. }
  732. }
  733. private void StopCapture()
  734. {
  735. if (_movieCapture != null)
  736. {
  737. _movieCapture.StopCapture();
  738. }
  739. }
  740. private void CancelCapture()
  741. {
  742. if (_movieCapture != null)
  743. {
  744. _movieCapture.CancelCapture();
  745. }
  746. }
  747. private void ResumeCapture()
  748. {
  749. if (_movieCapture != null)
  750. {
  751. _movieCapture.ResumeCapture();
  752. }
  753. }
  754. private void PauseCapture()
  755. {
  756. if (_movieCapture != null)
  757. {
  758. _movieCapture.PauseCapture();
  759. }
  760. }
  761. private void Update()
  762. {
  763. if (_movieCapture != null)
  764. {
  765. if (_whenRecordingAutoHideUI && !_showUI)
  766. {
  767. if (!_movieCapture.IsCapturing())
  768. _showUI = true;
  769. }
  770. if (Input.GetKey(KeyCode.LeftControl) && Input.GetKeyDown(KeyCode.F5))
  771. {
  772. if (_movieCapture.IsCapturing())
  773. {
  774. _movieCapture.StopCapture();
  775. }
  776. }
  777. if (_movieCapture.IsCapturing())
  778. {
  779. _lastFileSize = _movieCapture.GetCaptureFileSize();
  780. if (!_movieCapture.IsRealTime)
  781. {
  782. _lastEncodedSeconds = (uint)Mathf.FloorToInt((float)_movieCapture.CaptureStats.NumEncodedFrames / _movieCapture.FrameRate);
  783. }
  784. else
  785. {
  786. _lastEncodedSeconds = _movieCapture.CaptureStats.TotalEncodedSeconds;
  787. }
  788. _lastEncodedMinutes = _lastEncodedSeconds / 60;
  789. _lastEncodedSeconds = _lastEncodedSeconds % 60;
  790. _lastEncodedFrame = _movieCapture.CaptureStats.NumEncodedFrames % (uint)_movieCapture.FrameRate;
  791. }
  792. }
  793. }
  794. }
  795. }