CaptureBaseEditor.cs 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317
  1. #if UNITY_2017_3_OR_NEWER
  2. #define AVPRO_MOVIECAPTURE_OFFLINE_AUDIOCAPTURE
  3. #endif
  4. #if UNITY_5_6_OR_NEWER && UNITY_2018_3_OR_NEWER
  5. #define AVPRO_MOVIECAPTURE_VIDEOPLAYER_SUPPORT
  6. #endif
  7. #if UNITY_2017_1_OR_NEWER
  8. #define AVPRO_MOVIECAPTURE_PLAYABLES_SUPPORT
  9. #endif
  10. #if UNITY_EDITOR
  11. using UnityEngine;
  12. using UnityEditor;
  13. using System.Collections;
  14. //-----------------------------------------------------------------------------
  15. // Copyright 2012-2022 RenderHeads Ltd. All rights reserved.
  16. //-----------------------------------------------------------------------------
  17. namespace RenderHeads.Media.AVProMovieCapture.Editor
  18. {
  19. [CanEditMultipleObjects]
  20. [CustomEditor(typeof(CaptureBase), true)]
  21. public class CaptureBaseEditor : UnityEditor.Editor
  22. {
  23. private const string SettingsPrefix = "AVProMovieCapture-BaseEditor-";
  24. internal const string UnityAssetStore_FullVersionUrl = "https://assetstore.unity.com/packages/tools/video/avpro-movie-capture-151061?aid=1101lcNgx";
  25. public readonly static string[] ResolutionStrings = { "8192x8192 (1:1)", "8192x4096 (2:1)", "4096x4096 (1:1)", "4096x2048 (2:1)", "2048x4096 (1:2)", "3840x2160 (16:9)", "3840x2048 (15:8)", "3840x1920 (2:1)", "2560x1440 (16:9)", "2048x2048 (1:1)", "2048x1024 (2:1)", "1920x1080 (16:9)", "1280x720 (16:9)", "1024x768 (4:3)", "800x600 (4:3)", "800x450 (16:9)", "640x480 (4:3)", "640x360 (16:9)", "320x240 (4:3)", "Original", "Custom" };
  26. private readonly static GUIContent _guiBlankSpace = new GUIContent(" ");
  27. private readonly static GUIContent _guiContentMotionBlurSamples = new GUIContent("Samples");
  28. private readonly static GUIContent _guiContentMotionBlurCameras = new GUIContent("Cameras");
  29. private readonly static GUIContent _guiContentFolder = new GUIContent("Folder");
  30. private readonly static GUIContent _guiContentPath = new GUIContent("Path");
  31. private readonly static GUIContent _guiContentSubfolders = new GUIContent("Subfolder(s)");
  32. private readonly static GUIContent _guiContentPrefix = new GUIContent("Prefix");
  33. private readonly static GUIContent _guiContentAppendTimestamp = new GUIContent("Append Timestamp");
  34. private readonly static GUIContent _guiContentManualExtension = new GUIContent("Manual Extension");
  35. private readonly static GUIContent _guiContentExtension = new GUIContent("Extension");
  36. private readonly static GUIContent _guiContentStartFrame = new GUIContent("Start Frame");
  37. private readonly static GUIContent _guiContentZeroDigits = new GUIContent("Zero Digits");
  38. private readonly static GUIContent _guiContentPipePath = new GUIContent("Pipe Path");
  39. private readonly static GUIContent _guiContentToggleKey = new GUIContent("Toggle Key");
  40. private readonly static GUIContent _guiContentStartMode = new GUIContent("Start Mode");
  41. private readonly static GUIContent _guiContentStartDelay = new GUIContent("Start Delay");
  42. private readonly static GUIContent _guiContentSeconds = new GUIContent("Seconds");
  43. private readonly static GUIContent _guiContentStopMode = new GUIContent("Stop Mode");
  44. private readonly static GUIContent _guiContentFrames = new GUIContent("Frames");
  45. private readonly static GUIContent _guiContentCodecSearchOrder = new GUIContent("Codec Search Order");
  46. private readonly static GUIContent _guiContentSupportTextureRecreate = new GUIContent("Support Texture Recreate", "Using this option will slow rendering (forces GPU sync), but is needed to handle cases where texture resources are recreated, due to alt-tab or window resizing.");
  47. private readonly static GUIContent _guiStreamableMP4 = new GUIContent("Streamable MP4");
  48. private readonly static GUIContent _guiStereoPacking = new GUIContent("Stereo Packing");
  49. private readonly static GUIContent _guiSphericalLayout = new GUIContent("Spherical Layout");
  50. private readonly static GUIContent _guiAndroidUpdateMediaGallery = new GUIContent("Update Media Gallery");
  51. private readonly static GUIContent _guiAndroidNoCaptureRotation = new GUIContent("No Capture Rotation");
  52. private static bool _isTrialVersion = false;
  53. private SerializedProperty _propCaptureKey;
  54. private SerializedProperty _propMinimumDiskSpaceMB;
  55. private SerializedProperty _propPersistAcrossSceneLoads;
  56. private SerializedProperty _propIsRealtime;
  57. private SerializedProperty _propOutputTarget;
  58. private SerializedProperty _propImageSequenceFormatWindows;
  59. private SerializedProperty _propImageSequenceFormatMacOS;
  60. private SerializedProperty _propImageSequenceFormatIOS;
  61. private SerializedProperty _propImageSequenceFormatAndroid;
  62. private SerializedProperty _propImageSequenceStartFrame;
  63. private SerializedProperty _propImageSequenceZeroDigits;
  64. private SerializedProperty _propOutputFolderType;
  65. private SerializedProperty _propOutputFolderPath;
  66. private SerializedProperty _propAppendFilenameTimestamp;
  67. private SerializedProperty _propFileNamePrefix;
  68. private SerializedProperty _propAllowManualFileExtension;
  69. private SerializedProperty _propFileNameExtension;
  70. private SerializedProperty _propForceFileName;
  71. private SerializedProperty _propNamedPipePath;
  72. private SerializedProperty _propVideoCodecPriorityWindows;
  73. private SerializedProperty _propVideoCodecPriorityMacOS;
  74. //private SerializedProperty _propVideoCodecPriorityAndroid;
  75. private SerializedProperty _propForceVideoCodecIndexWindows;
  76. private SerializedProperty _propForceVideoCodecIndexMacOS;
  77. private SerializedProperty _propForceVideoCodecIndexIOS;
  78. private SerializedProperty _propForceVideoCodecIndexAndroid;
  79. private SerializedProperty _propAudioCaptureSource;
  80. private SerializedProperty _propAudioCodecPriorityWindows;
  81. private SerializedProperty _propAudioCodecPriorityMacOS;
  82. //private SerializedProperty _propAudioCodecPriorityAndroid;
  83. private SerializedProperty _propForceAudioCodecIndexWindows;
  84. private SerializedProperty _propForceAudioCodecIndexMacOS;
  85. private SerializedProperty _propForceAudioCodecIndexIOS;
  86. private SerializedProperty _propForceAudioCodecIndexAndroid;
  87. private SerializedProperty _propForceAudioDeviceIndex;
  88. private SerializedProperty _propUnityAudioCapture;
  89. private SerializedProperty _propManualAudioSampleRate;
  90. private SerializedProperty _propManualAudioChannelCount;
  91. private SerializedProperty _propStartTrigger;
  92. private SerializedProperty _propStartDelay;
  93. private SerializedProperty _propStartDelaySeconds;
  94. private SerializedProperty _propStopMode;
  95. private SerializedProperty _propStopFrames;
  96. private SerializedProperty _propStopSeconds;
  97. // private SerializedProperty _propPauseCaptureOnAppPause;
  98. private class PropVideoHints
  99. {
  100. public SerializedProperty propAverageBitrate;
  101. public SerializedProperty propMaximumBitrate;
  102. public SerializedProperty propQuality;
  103. public SerializedProperty propKeyframeInterval;
  104. public SerializedProperty propTransparency;
  105. public SerializedProperty propHardwareEncoding;
  106. public SerializedProperty propFastStart;
  107. public SerializedProperty propInjectStereoPacking;
  108. public SerializedProperty propStereoPacking;
  109. public SerializedProperty propInjectSphericalVideoLayout;
  110. public SerializedProperty propSphericalVideoLayout;
  111. public SerializedProperty propEnableFragmentedWriting;
  112. public SerializedProperty propMovieFragmentInterval;
  113. }
  114. private class PropImageHints
  115. {
  116. public SerializedProperty propQuality;
  117. public SerializedProperty propTransparency;
  118. }
  119. private PropVideoHints[] _propVideoHints;
  120. private PropImageHints[] _propImageHints;
  121. private SerializedProperty _propDownScale;
  122. private SerializedProperty _propMaxVideoSize;
  123. private SerializedProperty _propFrameRate;
  124. private SerializedProperty _propTimelapseScale;
  125. private SerializedProperty _propFrameUpdateMode;
  126. private SerializedProperty _propFlipVertically;
  127. private SerializedProperty _propForceGpuFlush;
  128. private SerializedProperty _propWaitForEndOfFrame;
  129. private SerializedProperty _propAndroidUpdateMediaGallery;
  130. private SerializedProperty _propAndroidNoCaptureRotation;
  131. private SerializedProperty _propUseMotionBlur;
  132. private SerializedProperty _propMotionBlurSamples;
  133. private SerializedProperty _propMotionBlurCameras;
  134. private SerializedProperty _propLogCaptureStartStop;
  135. private SerializedProperty _propAllowVsyncDisable;
  136. private SerializedProperty _propSupportTextureRecreate;
  137. #if AVPRO_MOVIECAPTURE_PLAYABLES_SUPPORT
  138. private SerializedProperty _propTimelineController;
  139. #endif
  140. #if AVPRO_MOVIECAPTURE_VIDEOPLAYER_SUPPORT
  141. private SerializedProperty _propVideoPlayerController;
  142. #endif
  143. private static bool _isExpandedStartStop = false;
  144. private static bool _isExpandedOutput = false;
  145. private static bool _isExpandedVisual = false;
  146. private static bool _isExpandedAudio = false;
  147. private static bool _isExpandedPost = false;
  148. private static bool _isExpandedMisc = false;
  149. private static bool _isExpandedTrial = true;
  150. private static bool _isExpandedAbout = false;
  151. private static NativePlugin.Platform _selectedPlatform = NativePlugin.Platform.Windows;
  152. private static GUIStyle _stylePlatformBox = null;
  153. protected CaptureBase _baseCapture;
  154. public override void OnInspectorGUI()
  155. {
  156. // Warning if the base component is used
  157. if (this.target.GetType() == typeof(CaptureBase))
  158. {
  159. GUI.color = Color.yellow;
  160. GUILayout.BeginVertical("box");
  161. GUILayout.TextArea("Error: This is not a component, this is the base class.\n\nPlease add one of the components\n(eg:CaptureFromScene / CaptureFromCamera etc)");
  162. GUILayout.EndVertical();
  163. return;
  164. }
  165. if (_stylePlatformBox == null)
  166. {
  167. _stylePlatformBox = new GUIStyle(GUI.skin.box);
  168. _stylePlatformBox.padding.top = 0;
  169. _stylePlatformBox.padding.bottom = 0;
  170. }
  171. GUI_Header();
  172. GUI_BaseOptions();
  173. }
  174. protected virtual void GUI_User()
  175. {
  176. }
  177. protected void GUI_Header()
  178. {
  179. // Describe the watermark for trial version
  180. if (_isTrialVersion)
  181. {
  182. EditorUtils.DrawSectionColored("- AVPRO MOVIE CAPTURE -\nTRIAL VERSION", ref _isExpandedTrial, DrawTrialMessage, Color.magenta, Color.magenta, Color.magenta);
  183. }
  184. // Button to launch the capture window
  185. {
  186. GUI.backgroundColor = new Color(0.96f, 0.25f, 0.47f);
  187. if (GUILayout.Button("\n◄ Open Movie Capture Window ►\n"))
  188. {
  189. CaptureEditorWindow.Init();
  190. }
  191. GUI.backgroundColor = Color.white;
  192. }
  193. }
  194. protected void DrawTrialMessage()
  195. {
  196. string message = "The free trial version is watermarked. Upgrade to the full package to remove the watermark.";
  197. GUI.backgroundColor = Color.yellow;
  198. EditorGUILayout.BeginVertical(GUI.skin.box);
  199. //GUI.color = Color.yellow;
  200. //GUILayout.Label("AVPRO MOVIE CAPTURE - FREE TRIAL VERSION", EditorStyles.boldLabel);
  201. GUI.color = Color.white;
  202. GUILayout.Label(message, EditorStyles.wordWrappedLabel);
  203. if (GUILayout.Button("Upgrade Now"))
  204. {
  205. Application.OpenURL(UnityAssetStore_FullVersionUrl);
  206. }
  207. EditorGUILayout.EndVertical();
  208. GUI.backgroundColor = Color.white;
  209. GUI.color = Color.white;
  210. }
  211. protected void GUI_BaseOptions()
  212. {
  213. serializedObject.Update();
  214. if (_baseCapture == null)
  215. {
  216. return;
  217. }
  218. //DrawDefaultInspector();
  219. if (!_baseCapture.IsCapturing())
  220. {
  221. GUILayout.Space(8f);
  222. EditorUtils.BoolAsDropdown("Capture Mode", _propIsRealtime, "Realtime Capture", "Offline Render");
  223. GUILayout.Space(8f);
  224. if (serializedObject.ApplyModifiedProperties())
  225. {
  226. EditorUtility.SetDirty(target);
  227. }
  228. GUI_User();
  229. // After the user mode we must update the serialised object again
  230. serializedObject.Update();
  231. EditorUtils.DrawSection("Start / Stop", ref _isExpandedStartStop, GUI_StartStop);
  232. EditorUtils.DrawSection("Output", ref _isExpandedOutput, GUI_OutputFilePath);
  233. EditorUtils.DrawSection("Visual", ref _isExpandedVisual, GUI_Visual);
  234. if (_propOutputTarget.enumValueIndex == (int)OutputTarget.VideoFile)
  235. {
  236. EditorUtils.DrawSection("Audio", ref _isExpandedAudio, GUI_Audio);
  237. EditorUtils.DrawSection("Post", ref _isExpandedPost, GUI_Post);
  238. }
  239. EditorUtils.DrawSection("Misc", ref _isExpandedMisc, GUI_Misc);
  240. //EditorUtils.DrawSection("Platform Specific", ref _isExpandedMisc, GUI_PlatformSpecific);
  241. EditorUtils.DrawSection("Help", ref _isExpandedAbout, GUI_About);
  242. if (serializedObject.ApplyModifiedProperties())
  243. {
  244. EditorUtility.SetDirty(target);
  245. }
  246. GUI_Controls();
  247. }
  248. else
  249. {
  250. GUI_Stats();
  251. GUI_Progress();
  252. GUI_Controls();
  253. }
  254. }
  255. protected void GUI_Progress()
  256. {
  257. if (_baseCapture == null)
  258. {
  259. return;
  260. }
  261. if (_propStopMode.enumValueIndex != (int)StopMode.None)
  262. {
  263. Rect r = GUILayoutUtility.GetRect(128f, EditorStyles.label.CalcHeight(GUIContent.none, 32f), GUILayout.ExpandWidth(true));
  264. float progress = _baseCapture.GetProgress();
  265. EditorGUI.ProgressBar(r, progress, (progress * 100f).ToString("F1") + "%");
  266. }
  267. }
  268. protected void GUI_Stats()
  269. {
  270. if (_baseCapture == null)
  271. {
  272. return;
  273. }
  274. if (Application.isPlaying && _baseCapture.IsCapturing())
  275. {
  276. CaptureEditorWindow.DrawBaseCapturingGUI(_baseCapture);
  277. {
  278. EditorGUILayout.BeginVertical("box");
  279. EditorGUI.indentLevel++;
  280. {
  281. uint lastEncodedSeconds = (uint)Mathf.FloorToInt((float)_baseCapture.CaptureStats.NumEncodedFrames / _baseCapture.FrameRate);
  282. if (_baseCapture.IsRealTime)
  283. {
  284. lastEncodedSeconds = _baseCapture.CaptureStats.TotalEncodedSeconds;
  285. }
  286. uint lastEncodedMinutes = lastEncodedSeconds / 60;
  287. lastEncodedSeconds = lastEncodedSeconds % 60;
  288. uint lastEncodedFrame = _baseCapture.CaptureStats.NumEncodedFrames % (uint)_baseCapture.FrameRate;
  289. string lengthText = string.Format("{0:00}:{1:00}.{2:000}", lastEncodedMinutes, lastEncodedSeconds, lastEncodedFrame);
  290. EditorGUILayout.LabelField("Video Length", lengthText);
  291. if (!_baseCapture.IsRealTime)
  292. {
  293. long lastFileSize = _baseCapture.GetCaptureFileSize();
  294. EditorGUILayout.LabelField("File Size", ((float)lastFileSize / (1024f * 1024f)).ToString("F1") + "MB");
  295. EditorGUILayout.LabelField("Avg Bitrate", (8f * ((float)lastFileSize / (1024f * 1024f)) / (float)((lastEncodedMinutes * 60) + lastEncodedSeconds)).ToString("F2") + "Mb/s");
  296. }
  297. }
  298. EditorGUI.indentLevel--;
  299. EditorGUILayout.EndVertical();
  300. }
  301. }
  302. }
  303. protected void GUI_Controls()
  304. {
  305. if (_baseCapture == null)
  306. {
  307. return;
  308. }
  309. GUILayout.Space(8.0f);
  310. EditorGUI.BeginDisabledGroup(!Application.isPlaying);
  311. {
  312. if (!_baseCapture.IsCapturing())
  313. {
  314. GUI.backgroundColor = Color.green;
  315. string startString = "Start Capture";
  316. if (!_baseCapture.IsRealTime)
  317. {
  318. startString = "Start Render";
  319. }
  320. if (GUILayout.Button(startString, GUILayout.Height(32f)))
  321. {
  322. _baseCapture.SelectVideoCodec();
  323. _baseCapture.SelectAudioCodec();
  324. _baseCapture.SelectAudioInputDevice();
  325. // We have to queue the start capture otherwise Screen.width and height aren't correct
  326. _baseCapture.QueueStartCapture();
  327. }
  328. GUI.backgroundColor = Color.white;
  329. }
  330. else
  331. {
  332. GUILayout.BeginHorizontal();
  333. if (!_baseCapture.IsPaused())
  334. {
  335. GUI.backgroundColor = Color.yellow;
  336. if (GUILayout.Button("Pause", GUILayout.Height(32f)))
  337. {
  338. _baseCapture.PauseCapture();
  339. }
  340. }
  341. else
  342. {
  343. GUI.backgroundColor = Color.green;
  344. if (GUILayout.Button("Resume", GUILayout.Height(32f)))
  345. {
  346. _baseCapture.ResumeCapture();
  347. }
  348. }
  349. GUI.backgroundColor = Color.cyan;
  350. if (GUILayout.Button("Cancel", GUILayout.Height(32f)))
  351. {
  352. _baseCapture.CancelCapture();
  353. }
  354. GUI.backgroundColor = Color.red;
  355. if (GUILayout.Button("Stop", GUILayout.Height(32f)))
  356. {
  357. _baseCapture.StopCapture();
  358. }
  359. GUI.backgroundColor = Color.white;
  360. GUILayout.EndHorizontal();
  361. }
  362. }
  363. EditorGUI.EndDisabledGroup();
  364. EditorGUILayout.Space();
  365. EditorGUI.BeginDisabledGroup(string.IsNullOrEmpty(CaptureBase.LastFileSaved));
  366. GUILayout.BeginHorizontal();
  367. if (GUILayout.Button("Browse Last"))
  368. {
  369. if (!string.IsNullOrEmpty(CaptureBase.LastFileSaved))
  370. {
  371. Utils.ShowInExplorer(CaptureBase.LastFileSaved);
  372. }
  373. }
  374. {
  375. Color prevColor = GUI.color;
  376. GUI.color = Color.cyan;
  377. if (GUILayout.Button("View Last Capture"))
  378. {
  379. if (!string.IsNullOrEmpty(CaptureBase.LastFileSaved))
  380. {
  381. Utils.OpenInDefaultApp(CaptureBase.LastFileSaved);
  382. }
  383. }
  384. GUI.color = prevColor;
  385. }
  386. GUILayout.EndHorizontal();
  387. EditorGUI.EndDisabledGroup();
  388. }
  389. protected void GUI_OutputFilePath()
  390. {
  391. EditorUtils.EnumAsDropdown("Output Target", _propOutputTarget, EditorUtils.OutputTargetNames);
  392. if (_propOutputTarget.enumValueIndex == (int)OutputTarget.VideoFile ||
  393. _propOutputTarget.enumValueIndex == (int)OutputTarget.ImageSequence)
  394. {
  395. bool isImageSequence = (_propOutputTarget.enumValueIndex == (int)OutputTarget.ImageSequence);
  396. if (isImageSequence)
  397. {
  398. BeginPlatformSelection();
  399. if (_selectedPlatform == NativePlugin.Platform.Windows)
  400. {
  401. EditorUtils.EnumAsDropdown("Format", _propImageSequenceFormatWindows, Utils.WindowsImageSequenceFormatNames);
  402. }
  403. else if (_selectedPlatform == NativePlugin.Platform.macOS)
  404. {
  405. EditorUtils.EnumAsDropdown("Format", _propImageSequenceFormatMacOS, Utils.MacOSImageSequenceFormatNames);
  406. }
  407. else if (_selectedPlatform == NativePlugin.Platform.iOS)
  408. {
  409. EditorUtils.EnumAsDropdown("Format", _propImageSequenceFormatIOS, Utils.IOSImageSequenceFormatNames);
  410. }
  411. else if (_selectedPlatform == NativePlugin.Platform.Android)
  412. {
  413. EditorUtils.EnumAsDropdown("Format", _propImageSequenceFormatAndroid, Utils.AndroidImageSequenceFormatNames);
  414. }
  415. EndPlatformSelection();
  416. GUILayout.Space(8f);
  417. }
  418. GUILayout.Label(_guiContentFolder, EditorStyles.boldLabel);
  419. #if UNITY_EDITOR_OSX
  420. // Photo Library is only for the video output type so grab the current folder type in case we need to reset it
  421. int outputFolderTypePrevValue = _propOutputFolderType.enumValueIndex;
  422. if (outputFolderTypePrevValue == (int)CaptureBase.OutputPath.PhotoLibrary)
  423. // Already the Photo Library type so reset to the default option
  424. outputFolderTypePrevValue = (int)CaptureBase.DefaultOutputFolderType;
  425. #endif
  426. EditorGUILayout.PropertyField(_propOutputFolderType, _guiContentFolder);
  427. #if UNITY_EDITOR_OSX
  428. if (isImageSequence && _propOutputFolderType.enumValueIndex == (int)CaptureBase.OutputPath.PhotoLibrary)
  429. {
  430. Debug.LogWarning("Photo Library is unavailable for the Image Sequence output type");
  431. _propOutputFolderType.enumValueIndex = (int)outputFolderTypePrevValue;
  432. }
  433. #endif
  434. if (_propOutputFolderType.enumValueIndex == (int)CaptureBase.OutputPath.Absolute)
  435. {
  436. EditorGUILayout.BeginHorizontal();
  437. EditorGUILayout.PropertyField(_propOutputFolderPath, _guiContentPath);
  438. if (GUILayout.Button(">", GUILayout.Width(22)))
  439. {
  440. _propOutputFolderPath.stringValue = EditorUtility.SaveFolderPanel("Select Folder To Store Video Captures", System.IO.Path.GetFullPath(System.IO.Path.Combine(Application.dataPath, "../")), "");
  441. }
  442. EditorGUILayout.EndHorizontal();
  443. }
  444. else
  445. {
  446. EditorGUILayout.PropertyField(_propOutputFolderPath, _guiContentSubfolders);
  447. }
  448. GUILayout.Label("File Name", EditorStyles.boldLabel);
  449. if (!isImageSequence)
  450. {
  451. EditorGUILayout.PropertyField(_propFileNamePrefix, _guiContentPrefix);
  452. EditorGUILayout.PropertyField(_propAppendFilenameTimestamp,_guiContentAppendTimestamp);
  453. EditorGUILayout.PropertyField(_propAllowManualFileExtension, _guiContentManualExtension);
  454. if (_propAllowManualFileExtension.boolValue)
  455. {
  456. EditorGUILayout.PropertyField(_propFileNameExtension, _guiContentExtension);
  457. }
  458. }
  459. if (isImageSequence)
  460. {
  461. EditorGUILayout.PropertyField(_propFileNamePrefix,_guiContentPrefix);
  462. EditorGUILayout.PropertyField(_propImageSequenceStartFrame, _guiContentStartFrame);
  463. EditorGUILayout.PropertyField(_propImageSequenceZeroDigits, _guiContentZeroDigits);
  464. }
  465. }
  466. else
  467. {
  468. EditorGUILayout.PropertyField(_propNamedPipePath, _guiContentPipePath);
  469. }
  470. /*// File path
  471. EditorGUILayout.LabelField("File Path", EditorStyles.boldLabel);
  472. EditorGUI.indentLevel++;
  473. _outputFolderIndex = EditorGUILayout.Popup("Relative to", _outputFolderIndex, _outputFolders);
  474. if (_outputFolderIndex == 0 || _outputFolderIndex == 1)
  475. {
  476. _outputFolderRelative = EditorGUILayout.TextField("SubFolder(s)", _outputFolderRelative);
  477. }
  478. else
  479. {
  480. EditorGUILayout.BeginHorizontal();
  481. _outputFolderAbsolute = EditorGUILayout.TextField("Path", _outputFolderAbsolute);
  482. if (GUILayout.Button(">", GUILayout.Width(22)))
  483. {
  484. _outputFolderAbsolute = EditorUtility.SaveFolderPanel("Select Folder To Store Video Captures", System.IO.Path.GetFullPath(System.IO.Path.Combine(Application.dataPath, "../")), "");
  485. EditorUtility.SetDirty(this);
  486. }
  487. EditorGUILayout.EndHorizontal();
  488. }
  489. EditorGUI.indentLevel--;*/
  490. }
  491. protected void GUI_StartStop()
  492. {
  493. EditorGUILayout.PropertyField(_propCaptureKey, _guiContentToggleKey);
  494. EditorGUILayout.Separator();
  495. EditorGUILayout.PropertyField(_propStartTrigger, _guiContentStartMode);
  496. EditorGUILayout.PropertyField(_propStartDelay, _guiContentStartDelay);
  497. if ((StartDelayMode)_propStartDelay.enumValueIndex == StartDelayMode.RealSeconds ||
  498. (StartDelayMode)_propStartDelay.enumValueIndex == StartDelayMode.GameSeconds)
  499. {
  500. EditorGUILayout.PropertyField(_propStartDelaySeconds, _guiContentSeconds);
  501. }
  502. EditorGUILayout.Separator();
  503. EditorGUILayout.PropertyField(_propStopMode, _guiContentStopMode);
  504. if ((StopMode)_propStopMode.enumValueIndex == StopMode.FramesEncoded)
  505. {
  506. EditorGUILayout.PropertyField(_propStopFrames, _guiContentFrames);
  507. }
  508. else if ((StopMode)_propStopMode.enumValueIndex == StopMode.SecondsElapsed || (StopMode)_propStopMode.enumValueIndex == StopMode.SecondsEncoded)
  509. {
  510. EditorGUILayout.PropertyField(_propStopSeconds, _guiContentSeconds);
  511. }
  512. // EditorGUILayout.PropertyField(_propPauseCaptureOnAppPause);
  513. }
  514. private void BeginPlatformSelection(string title = null)
  515. {
  516. GUILayout.BeginVertical(_stylePlatformBox);
  517. if (!string.IsNullOrEmpty(title))
  518. {
  519. GUILayout.Label(title, EditorStyles.boldLabel);
  520. }
  521. int rowCount = 0;
  522. int platformIndex = (int)_selectedPlatform;
  523. for (int i = 0; i < NativePlugin.PlatformNames.Length; i++)
  524. {
  525. if (i % 3 == 0)
  526. {
  527. GUILayout.BeginHorizontal();
  528. rowCount++;
  529. }
  530. Color hilight = Color.yellow;
  531. if (i == platformIndex)
  532. {
  533. }
  534. else
  535. {
  536. // Unselected, unmodified
  537. if (EditorGUIUtility.isProSkin)
  538. {
  539. GUI.backgroundColor = Color.grey;
  540. GUI.color = new Color(0.65f, 0.66f, 0.65f);// Color.grey;
  541. }
  542. }
  543. if (i == platformIndex)
  544. {
  545. if (!GUILayout.Toggle(true, NativePlugin.PlatformNames[i], GUI.skin.button))
  546. {
  547. platformIndex = -1;
  548. }
  549. }
  550. else
  551. {
  552. if (GUILayout.Button(NativePlugin.PlatformNames[i]))
  553. {
  554. platformIndex = i;
  555. }
  556. }
  557. if ((i+1) % 3 == 0)
  558. {
  559. rowCount--;
  560. GUILayout.EndHorizontal();
  561. }
  562. GUI.backgroundColor = Color.white;
  563. GUI.contentColor = Color.white;
  564. GUI.color = Color.white;
  565. }
  566. if (rowCount > 0)
  567. {
  568. GUILayout.EndHorizontal();
  569. }
  570. if (platformIndex != (int)_selectedPlatform)
  571. {
  572. _selectedPlatform = (NativePlugin.Platform)platformIndex;
  573. // We do this to clear the focus, otherwise a focused text field will not change when the Toolbar index changes
  574. EditorGUI.FocusTextInControl("ClearFocus");
  575. }
  576. }
  577. private void EndPlatformSelection()
  578. {
  579. GUILayout.EndVertical();
  580. }
  581. protected virtual void GUI_Misc()
  582. {
  583. EditorGUILayout.PropertyField(_propLogCaptureStartStop);
  584. EditorGUILayout.PropertyField(_propAllowVsyncDisable);
  585. EditorGUILayout.PropertyField(_propWaitForEndOfFrame);
  586. EditorGUILayout.PropertyField(_propSupportTextureRecreate, _guiContentSupportTextureRecreate);
  587. EditorGUILayout.PropertyField(_propPersistAcrossSceneLoads);
  588. #if AVPRO_MOVIECAPTURE_PLAYABLES_SUPPORT
  589. EditorGUILayout.PropertyField(_propTimelineController);
  590. #endif
  591. #if AVPRO_MOVIECAPTURE_VIDEOPLAYER_SUPPORT
  592. EditorGUILayout.PropertyField(_propVideoPlayerController);
  593. #endif
  594. BeginPlatformSelection();
  595. if (_selectedPlatform == NativePlugin.Platform.Windows)
  596. {
  597. EditorGUILayout.PropertyField(_propForceGpuFlush);
  598. EditorGUILayout.PropertyField(_propMinimumDiskSpaceMB);
  599. }
  600. else if (_selectedPlatform == NativePlugin.Platform.Android)
  601. {
  602. EditorGUILayout.PropertyField(_propAndroidUpdateMediaGallery, _guiAndroidUpdateMediaGallery);
  603. EditorGUILayout.PropertyField(_propAndroidNoCaptureRotation, _guiAndroidNoCaptureRotation);
  604. }
  605. EndPlatformSelection();
  606. }
  607. protected virtual void GUI_About()
  608. {
  609. CaptureEditorWindow.DrawConfigGUI_About();
  610. }
  611. protected void GUI_Visual()
  612. {
  613. EditorGUILayout.PropertyField(_propDownScale);
  614. if (_propDownScale.enumValueIndex == 5) // 5 is DownScale.Custom
  615. {
  616. EditorGUILayout.PropertyField(_propMaxVideoSize, new GUIContent("Size"));
  617. _propMaxVideoSize.vector2Value = new Vector2(Mathf.Clamp((int)_propMaxVideoSize.vector2Value.x, 1, NativePlugin.MaxRenderWidth), Mathf.Clamp((int)_propMaxVideoSize.vector2Value.y, 1, NativePlugin.MaxRenderHeight));
  618. }
  619. GUILayout.BeginHorizontal();
  620. EditorGUILayout.PropertyField(_propFrameRate, GUILayout.ExpandWidth(false));
  621. _propFrameRate.floatValue = Mathf.Clamp(_propFrameRate.floatValue, 0.01f, 240f);
  622. EditorUtils.FloatAsPopup("▶", "Common Frame Rates", this.serializedObject, _propFrameRate, EditorUtils.CommonFrameRateNames, EditorUtils.CommonFrameRateValues);
  623. GUILayout.EndHorizontal();
  624. EditorGUI.BeginDisabledGroup(!_propIsRealtime.boolValue);
  625. EditorGUILayout.PropertyField(_propTimelapseScale);
  626. _propTimelapseScale.intValue = Mathf.Max(1, _propTimelapseScale.intValue);
  627. EditorGUI.EndDisabledGroup();
  628. EditorGUILayout.PropertyField(_propFrameUpdateMode);
  629. EditorGUILayout.PropertyField(_propFlipVertically);
  630. EditorGUILayout.Space();
  631. if (_propOutputTarget.enumValueIndex == (int)OutputTarget.VideoFile)
  632. {
  633. GUI_VisualCodecs();
  634. GUI_VideoHints();
  635. }
  636. else if (_propOutputTarget.enumValueIndex == (int)OutputTarget.ImageSequence)
  637. {
  638. GUI_ImageHints();
  639. }
  640. EditorGUILayout.Space();
  641. EditorGUI.BeginDisabledGroup(_propIsRealtime.boolValue);
  642. GUILayout.Label("Motion Blur", EditorStyles.boldLabel);
  643. if (_propIsRealtime.boolValue)
  644. {
  645. GUI.color = Color.yellow;
  646. GUILayout.TextArea("Motion Blur only available in Offline Render mode");
  647. GUI.color = Color.white;
  648. }
  649. else
  650. {
  651. GUI_MotionBlur();
  652. }
  653. EditorGUI.EndDisabledGroup();
  654. }
  655. protected void GUI_VisualCodecs_Windows()
  656. {
  657. bool searchByName = (_propForceVideoCodecIndexWindows.intValue < 0);
  658. bool newSearchByName = EditorGUILayout.Toggle("Search by name", searchByName);
  659. if (searchByName != newSearchByName)
  660. {
  661. if (newSearchByName)
  662. {
  663. _propForceVideoCodecIndexWindows.intValue = -1;
  664. }
  665. else
  666. {
  667. _propForceVideoCodecIndexWindows.intValue = 0;
  668. }
  669. }
  670. if (_propForceVideoCodecIndexWindows.intValue < 0)
  671. {
  672. EditorGUILayout.PropertyField(_propVideoCodecPriorityWindows, _guiContentCodecSearchOrder, true);
  673. }
  674. else
  675. {
  676. EditorGUILayout.PropertyField(_propForceVideoCodecIndexWindows);
  677. }
  678. }
  679. protected void GUI_VisualCodecs_Android()
  680. {
  681. EditorGUI.BeginDisabledGroup(true);
  682. EditorGUILayout.Toggle("Search by name", false);
  683. EditorGUI.EndDisabledGroup();
  684. _propForceVideoCodecIndexAndroid.intValue = EditorGUILayout.Popup(_propForceVideoCodecIndexAndroid.intValue, NativePlugin.VideoCodecNamesAndroid);
  685. }
  686. protected void GUI_VisualCodecs_MacOS()
  687. {
  688. bool searchByName = (_propForceVideoCodecIndexMacOS.intValue < 0);
  689. bool newSearchByName = EditorGUILayout.Toggle("Search by name", searchByName);
  690. if (searchByName != newSearchByName)
  691. {
  692. if (newSearchByName)
  693. {
  694. _propForceVideoCodecIndexMacOS.intValue = -1;
  695. }
  696. else
  697. {
  698. _propForceVideoCodecIndexMacOS.intValue = 0;
  699. }
  700. }
  701. if (_propForceVideoCodecIndexMacOS.intValue < 0)
  702. {
  703. EditorGUILayout.PropertyField(_propVideoCodecPriorityMacOS, _guiContentCodecSearchOrder, true);
  704. }
  705. else
  706. {
  707. _propForceVideoCodecIndexMacOS.intValue = EditorGUILayout.Popup(_propForceVideoCodecIndexMacOS.intValue, NativePlugin.VideoCodecNamesMacOS);
  708. }
  709. }
  710. protected void GUI_VisualCodecs_IOS()
  711. {
  712. EditorGUI.BeginDisabledGroup(true);
  713. EditorGUILayout.Toggle("Search by name", false);
  714. EditorGUI.EndDisabledGroup();
  715. _propForceVideoCodecIndexIOS.intValue = EditorGUILayout.Popup(_propForceVideoCodecIndexIOS.intValue, NativePlugin.VideoCodecNamesIOS);
  716. }
  717. protected void GUI_VisualCodecs()
  718. {
  719. BeginPlatformSelection("Video Codec");
  720. if (_selectedPlatform == NativePlugin.Platform.Windows)
  721. {
  722. GUI_VisualCodecs_Windows();
  723. }
  724. else if (_selectedPlatform == NativePlugin.Platform.macOS)
  725. {
  726. GUI_VisualCodecs_MacOS();
  727. }
  728. else if (_selectedPlatform == NativePlugin.Platform.iOS)
  729. {
  730. GUI_VisualCodecs_IOS();
  731. }
  732. else if (_selectedPlatform == NativePlugin.Platform.Android)
  733. {
  734. GUI_VisualCodecs_Android();
  735. }
  736. EndPlatformSelection();
  737. }
  738. protected void GUI_AudioCodecs()
  739. {
  740. BeginPlatformSelection("Audio Codec");
  741. if (_selectedPlatform == NativePlugin.Platform.Windows)
  742. {
  743. bool searchByName = (_propForceAudioCodecIndexWindows.intValue < 0);
  744. bool newSearchByName = EditorGUILayout.Toggle("Search by name", searchByName);
  745. if (searchByName != newSearchByName)
  746. {
  747. if (newSearchByName)
  748. {
  749. _propForceAudioCodecIndexWindows.intValue = -1;
  750. }
  751. else
  752. {
  753. _propForceAudioCodecIndexWindows.intValue = 0;
  754. }
  755. }
  756. if (_propForceAudioCodecIndexWindows.intValue < 0)
  757. {
  758. EditorGUILayout.PropertyField(_propAudioCodecPriorityWindows, _guiContentCodecSearchOrder, true);
  759. }
  760. else
  761. {
  762. EditorGUILayout.PropertyField(_propForceAudioCodecIndexWindows);
  763. }
  764. }
  765. else if (_selectedPlatform == NativePlugin.Platform.Android)
  766. {
  767. EditorGUI.BeginDisabledGroup(true);
  768. EditorGUILayout.Toggle("Search by name", false);
  769. EditorGUI.EndDisabledGroup();
  770. _propForceAudioCodecIndexAndroid.intValue = EditorGUILayout.Popup(_propForceAudioCodecIndexAndroid.intValue, NativePlugin.AudioCodecNamesAndroid);
  771. }
  772. else if (_selectedPlatform == NativePlugin.Platform.macOS)
  773. {
  774. bool searchByName = (_propForceAudioCodecIndexMacOS.intValue < 0);
  775. bool newSearchByName = EditorGUILayout.Toggle("Search by name", searchByName);
  776. if (searchByName != newSearchByName)
  777. {
  778. if (newSearchByName)
  779. {
  780. _propForceAudioCodecIndexMacOS.intValue = -1;
  781. }
  782. else
  783. {
  784. _propForceAudioCodecIndexMacOS.intValue = 0;
  785. }
  786. }
  787. if (_propForceAudioCodecIndexMacOS.intValue < 0)
  788. {
  789. EditorGUILayout.PropertyField(_propAudioCodecPriorityMacOS, _guiContentCodecSearchOrder, true);
  790. }
  791. else
  792. {
  793. _propForceAudioCodecIndexMacOS.intValue = EditorGUILayout.Popup(_propForceAudioCodecIndexMacOS.intValue, NativePlugin.AudioCodecNamesMacOS);
  794. }
  795. }
  796. else if (_selectedPlatform == NativePlugin.Platform.iOS)
  797. {
  798. EditorGUI.BeginDisabledGroup(true);
  799. EditorGUILayout.Toggle("Search by name", false);
  800. EditorGUI.EndDisabledGroup();
  801. _propForceAudioCodecIndexIOS.intValue = EditorGUILayout.Popup(_propForceAudioCodecIndexIOS.intValue, NativePlugin.AudioCodecNamesIOS);
  802. }
  803. EndPlatformSelection();
  804. }
  805. protected void GUI_Audio()
  806. {
  807. bool showAudioSources = true;
  808. if (_propOutputTarget.enumValueIndex != (int)OutputTarget.VideoFile)
  809. {
  810. GUI.color = Color.yellow;
  811. GUILayout.TextArea("Audio Capture only available for video file output");
  812. GUI.color = Color.white;
  813. showAudioSources = false;
  814. }
  815. if (showAudioSources)
  816. {
  817. EditorUtils.EnumAsDropdown("Audio Source", _propAudioCaptureSource, EditorUtils.AudioCaptureSourceNames );
  818. if (_propAudioCaptureSource.enumValueIndex != (int)AudioCaptureSource.None)
  819. {
  820. bool showAudioOptions = true;
  821. #if AVPRO_MOVIECAPTURE_OFFLINE_AUDIOCAPTURE
  822. if (!_propIsRealtime.boolValue && _propAudioCaptureSource.enumValueIndex != (int)AudioCaptureSource.Manual && _propAudioCaptureSource.enumValueIndex != (int)AudioCaptureSource.Unity && _propAudioCaptureSource.enumValueIndex != (int)AudioCaptureSource.Wwise)
  823. {
  824. GUI.color = Color.yellow;
  825. GUILayout.TextArea("Only Manual, Unity and Wwise Audio Sources are available in offline capture mode");
  826. GUI.color = Color.white;
  827. showAudioOptions = false;
  828. }
  829. #else
  830. if (!_propIsRealtime.boolValue && _propAudioCaptureSource.enumValueIndex != (int)AudioCaptureSource.Manual && _propAudioCaptureSource.enumValueIndex != (int)AudioCaptureSource.Wwise)
  831. {
  832. GUI.color = Color.yellow;
  833. GUILayout.TextArea("Only Manual and Wwise Audio Source is available in offline capture mode");
  834. GUI.color = Color.white;
  835. showAudioOptions = false;
  836. }
  837. #endif
  838. if (_propIsRealtime.boolValue && _propAudioCaptureSource.enumValueIndex == (int)AudioCaptureSource.Wwise)
  839. {
  840. GUI.color = Color.yellow;
  841. GUILayout.TextArea("Wwise Audio Source is not available in realtime capture mode");
  842. GUI.color = Color.white;
  843. showAudioOptions = false;
  844. }
  845. #if !AVPRO_MOVIECAPTURE_WWISE_SUPPORT
  846. if (!_propIsRealtime.boolValue && _propAudioCaptureSource.enumValueIndex == (int)AudioCaptureSource.Wwise)
  847. {
  848. GUI.color = Color.red;
  849. GUILayout.TextArea("To support Wwise audio capture: add AVPRO_MOVIECAPTURE_WWISE_SUPPORT to script defines in Player Settings");
  850. GUI.color = Color.white;
  851. showAudioOptions = false;
  852. }
  853. #endif
  854. if (showAudioOptions)
  855. {
  856. if (_propAudioCaptureSource.enumValueIndex == (int)AudioCaptureSource.Microphone)
  857. {
  858. // TODO: change this into platform specific........
  859. // TODO: add search by name support................
  860. EditorGUILayout.PropertyField(_propForceAudioDeviceIndex);
  861. }
  862. else if (_propAudioCaptureSource.enumValueIndex == (int)AudioCaptureSource.Unity || _propAudioCaptureSource.enumValueIndex == (int)AudioCaptureSource.Wwise)
  863. {
  864. EditorGUILayout.PropertyField(_propUnityAudioCapture);
  865. }
  866. else if (_propAudioCaptureSource.enumValueIndex == (int)AudioCaptureSource.Manual)
  867. {
  868. EditorUtils.IntAsDropdown("Sample Rate", _propManualAudioSampleRate, EditorUtils.CommonAudioSampleRateNames, EditorUtils.CommonAudioSampleRateValues);
  869. EditorGUILayout.PropertyField(_propManualAudioChannelCount, new GUIContent("Channels"));
  870. }
  871. EditorGUILayout.Space();
  872. GUI_AudioCodecs();
  873. EditorGUILayout.Space();
  874. }
  875. }
  876. }
  877. EditorGUI.EndDisabledGroup();
  878. }
  879. protected void GUI_VideoHints()
  880. {
  881. BeginPlatformSelection("Encoder Hints");
  882. if (_selectedPlatform >= NativePlugin.Platform.First && _selectedPlatform < NativePlugin.Platform.Count)
  883. {
  884. PropVideoHints props = _propVideoHints[(int)_selectedPlatform];
  885. EditorUtils.BitrateField("Average Bitrate", props.propAverageBitrate);
  886. EditorGUI.BeginDisabledGroup(_selectedPlatform != NativePlugin.Platform.Windows);
  887. EditorUtils.BitrateField("Maxiumum Bitrate", props.propMaximumBitrate);
  888. EditorGUI.EndDisabledGroup();
  889. EditorGUILayout.PropertyField(props.propQuality);
  890. EditorGUILayout.PropertyField(props.propKeyframeInterval);
  891. EditorGUILayout.PropertyField(props.propTransparency);
  892. if (_selectedPlatform == NativePlugin.Platform.Windows)
  893. {
  894. EditorGUILayout.PropertyField(props.propHardwareEncoding);
  895. }
  896. else
  897. {
  898. EditorGUI.BeginDisabledGroup(true);
  899. EditorGUILayout.Toggle("Use Hardware Encoding", true);
  900. EditorGUI.EndDisabledGroup();
  901. }
  902. if (_selectedPlatform == NativePlugin.Platform.macOS || _selectedPlatform == NativePlugin.Platform.iOS)
  903. {
  904. EditorGUILayout.PropertyField(props.propEnableFragmentedWriting);
  905. if (props.propEnableFragmentedWriting.boolValue)
  906. {
  907. EditorGUILayout.PropertyField(props.propMovieFragmentInterval);
  908. }
  909. }
  910. }
  911. EndPlatformSelection();
  912. }
  913. protected void GUI_ImageHints()
  914. {
  915. BeginPlatformSelection("Encoder Hints");
  916. if (_selectedPlatform >= NativePlugin.Platform.First && _selectedPlatform < NativePlugin.Platform.Count)
  917. {
  918. PropImageHints props = _propImageHints[(int)_selectedPlatform];
  919. if (_selectedPlatform != NativePlugin.Platform.Windows)
  920. {
  921. EditorGUILayout.PropertyField(props.propQuality);
  922. }
  923. EditorGUILayout.PropertyField(props.propTransparency);
  924. }
  925. EndPlatformSelection();
  926. }
  927. protected void GUI_PlatformSpecific()
  928. {
  929. BeginPlatformSelection();
  930. if (_selectedPlatform >= NativePlugin.Platform.First && _selectedPlatform < NativePlugin.Platform.Count)
  931. {
  932. GUILayout.Label("Video Codecs", EditorStyles.boldLabel);
  933. if (_selectedPlatform == NativePlugin.Platform.Windows)
  934. {
  935. GUI_VisualCodecs_Windows();
  936. }
  937. else if (_selectedPlatform == NativePlugin.Platform.macOS)
  938. {
  939. GUI_VisualCodecs_MacOS();
  940. }
  941. else if (_selectedPlatform == NativePlugin.Platform.iOS)
  942. {
  943. GUI_VisualCodecs_IOS();
  944. }
  945. else if (_selectedPlatform == NativePlugin.Platform.Android)
  946. {
  947. GUI_VisualCodecs_Android();
  948. }
  949. GUILayout.Label("Encoder Hints", EditorStyles.boldLabel);
  950. EditorGUILayout.PropertyField(_propVideoHints[(int)_selectedPlatform].propAverageBitrate);
  951. if (_selectedPlatform == NativePlugin.Platform.Windows)
  952. {
  953. EditorGUILayout.PropertyField(_propVideoHints[(int)_selectedPlatform].propMaximumBitrate);
  954. }
  955. EditorGUILayout.PropertyField(_propVideoHints[(int)_selectedPlatform].propQuality);
  956. EditorGUILayout.PropertyField(_propVideoHints[(int)_selectedPlatform].propKeyframeInterval);
  957. EditorGUILayout.PropertyField(_propVideoHints[(int)_selectedPlatform].propTransparency);
  958. if (_selectedPlatform == NativePlugin.Platform.Windows)
  959. {
  960. EditorGUILayout.PropertyField(_propVideoHints[(int)_selectedPlatform].propHardwareEncoding);
  961. }
  962. else
  963. {
  964. EditorGUI.BeginDisabledGroup(true);
  965. EditorGUILayout.Toggle("Use Hardware Encoding", true);
  966. EditorGUI.EndDisabledGroup();
  967. }
  968. }
  969. EndPlatformSelection();
  970. }
  971. protected void GUI_Post()
  972. {
  973. BeginPlatformSelection();
  974. if (_selectedPlatform >= NativePlugin.Platform.First && _selectedPlatform < NativePlugin.Platform.Count)
  975. {
  976. PropVideoHints propHints = _propVideoHints[(int)_selectedPlatform];
  977. EditorGUILayout.PropertyField(propHints.propFastStart, _guiStreamableMP4);
  978. EditorGUILayout.PropertyField(propHints.propInjectStereoPacking, _guiStereoPacking);
  979. if (propHints.propInjectStereoPacking.enumValueIndex == (int)NoneAutoCustom.Custom)
  980. {
  981. EditorGUILayout.PropertyField(propHints.propStereoPacking, _guiBlankSpace);
  982. }
  983. EditorGUILayout.PropertyField(propHints.propInjectSphericalVideoLayout, _guiSphericalLayout);
  984. if (propHints.propInjectSphericalVideoLayout.enumValueIndex == (int)NoneAutoCustom.Custom)
  985. {
  986. EditorGUILayout.PropertyField(propHints.propSphericalVideoLayout, _guiBlankSpace);
  987. }
  988. }
  989. EndPlatformSelection();
  990. }
  991. protected void GUI_MotionBlur()
  992. {
  993. EditorGUILayout.PropertyField(_propUseMotionBlur);
  994. if (_propUseMotionBlur.boolValue)
  995. {
  996. EditorGUILayout.PropertyField(_propMotionBlurSamples, _guiContentMotionBlurSamples);
  997. EditorGUILayout.PropertyField(_propMotionBlurCameras, _guiContentMotionBlurCameras, true);
  998. }
  999. }
  1000. private void LoadSettings()
  1001. {
  1002. _isExpandedStartStop = EditorPrefs.GetBool(SettingsPrefix + "ExpandStartStop", _isExpandedStartStop);
  1003. _isExpandedOutput = EditorPrefs.GetBool(SettingsPrefix + "ExpandOutput", _isExpandedOutput);
  1004. _isExpandedVisual = EditorPrefs.GetBool(SettingsPrefix + "ExpandVisual", _isExpandedVisual);
  1005. _isExpandedAudio = EditorPrefs.GetBool(SettingsPrefix + "ExpandAudio", _isExpandedAudio);
  1006. _isExpandedPost = EditorPrefs.GetBool(SettingsPrefix + "ExpandPost", _isExpandedPost);
  1007. _isExpandedMisc = EditorPrefs.GetBool(SettingsPrefix + "ExpandMisc", _isExpandedMisc);
  1008. _selectedPlatform = (NativePlugin.Platform)EditorPrefs.GetInt(SettingsPrefix + "SelectedPlatform", (int)_selectedPlatform);
  1009. }
  1010. private void SaveSettings()
  1011. {
  1012. EditorPrefs.SetBool(SettingsPrefix + "ExpandStartStop", _isExpandedStartStop);
  1013. EditorPrefs.SetBool(SettingsPrefix + "ExpandOutput", _isExpandedOutput);
  1014. EditorPrefs.SetBool(SettingsPrefix + "ExpandVisual", _isExpandedVisual);
  1015. EditorPrefs.SetBool(SettingsPrefix + "ExpandAudio", _isExpandedAudio);
  1016. EditorPrefs.SetBool(SettingsPrefix + "ExpandPost", _isExpandedPost);
  1017. EditorPrefs.SetBool(SettingsPrefix + "ExpandMisc", _isExpandedMisc);
  1018. EditorPrefs.SetInt(SettingsPrefix + "SelectedPlatform", (int)_selectedPlatform);
  1019. }
  1020. protected virtual void OnEnable()
  1021. {
  1022. #if UNITY_EDITOR_WIN
  1023. _selectedPlatform = NativePlugin.Platform.Windows;
  1024. #elif UNITY_EDITOR_OSX
  1025. _selectedPlatform = NativePlugin.Platform.macOS;
  1026. #endif
  1027. LoadSettings();
  1028. _baseCapture = (CaptureBase)this.target;
  1029. _propCaptureKey = serializedObject.AssertFindProperty("_captureKey");
  1030. _propPersistAcrossSceneLoads = serializedObject.AssertFindProperty("_persistAcrossSceneLoads");
  1031. _propIsRealtime = serializedObject.AssertFindProperty("_isRealTime");
  1032. _propMinimumDiskSpaceMB = serializedObject.AssertFindProperty("_minimumDiskSpaceMB");
  1033. _propOutputTarget = serializedObject.AssertFindProperty("_outputTarget");
  1034. _propImageSequenceFormatWindows = serializedObject.AssertFindProperty("_imageSequenceFormatWindows");
  1035. _propImageSequenceFormatMacOS = serializedObject.AssertFindProperty("_imageSequenceFormatMacOS");
  1036. _propImageSequenceFormatIOS = serializedObject.AssertFindProperty("_imageSequenceFormatIOS");
  1037. _propImageSequenceFormatAndroid = serializedObject.AssertFindProperty("_imageSequenceFormatAndroid");
  1038. _propImageSequenceStartFrame = serializedObject.AssertFindProperty("_imageSequenceStartFrame");
  1039. _propImageSequenceZeroDigits = serializedObject.AssertFindProperty("_imageSequenceZeroDigits");
  1040. _propOutputFolderType = serializedObject.AssertFindProperty("_outputFolderType");
  1041. _propOutputFolderPath = serializedObject.AssertFindProperty("_outputFolderPath");
  1042. _propAppendFilenameTimestamp = serializedObject.AssertFindProperty("_appendFilenameTimestamp");
  1043. _propFileNamePrefix = serializedObject.AssertFindProperty("_filenamePrefix");
  1044. _propAllowManualFileExtension = serializedObject.AssertFindProperty("_allowManualFileExtension");
  1045. _propFileNameExtension = serializedObject.AssertFindProperty("_filenameExtension");
  1046. _propNamedPipePath = serializedObject.AssertFindProperty("_namedPipePath");
  1047. _propVideoCodecPriorityWindows = serializedObject.AssertFindProperty("_videoCodecPriorityWindows");
  1048. _propVideoCodecPriorityMacOS = serializedObject.AssertFindProperty("_videoCodecPriorityMacOS");
  1049. //_propVideoCodecPriorityAndroid = serializedObject.AssertFindProperty("_videoCodecPriorityAndroid");
  1050. _propForceVideoCodecIndexWindows = serializedObject.AssertFindProperty("_forceVideoCodecIndexWindows");
  1051. _propForceVideoCodecIndexMacOS = serializedObject.AssertFindProperty("_forceVideoCodecIndexMacOS");
  1052. _propForceVideoCodecIndexIOS = serializedObject.AssertFindProperty("_forceVideoCodecIndexIOS");
  1053. _propForceVideoCodecIndexAndroid = serializedObject.AssertFindProperty("_forceVideoCodecIndexAndroid");
  1054. _propAudioCodecPriorityWindows = serializedObject.AssertFindProperty("_audioCodecPriorityWindows");
  1055. _propAudioCodecPriorityMacOS = serializedObject.AssertFindProperty("_audioCodecPriorityMacOS");
  1056. //_propAudioCodecPriorityIOS = serializedObject.AssertFindProperty("_audioCodecPriorityIOS");
  1057. //_propAudioCodecPriorityAndroid = serializedObject.AssertFindProperty("_audioCodecPriorityAndroid");
  1058. _propForceAudioCodecIndexWindows = serializedObject.AssertFindProperty("_forceAudioCodecIndexWindows");
  1059. _propForceAudioCodecIndexMacOS = serializedObject.AssertFindProperty("_forceAudioCodecIndexMacOS");
  1060. _propForceAudioCodecIndexIOS = serializedObject.AssertFindProperty("_forceAudioCodecIndexIOS");
  1061. _propForceAudioCodecIndexAndroid = serializedObject.AssertFindProperty("_forceAudioCodecIndexAndroid");
  1062. _propAudioCaptureSource = serializedObject.AssertFindProperty("_audioCaptureSource");
  1063. _propUnityAudioCapture = serializedObject.AssertFindProperty("_unityAudioCapture");
  1064. _propForceAudioDeviceIndex = serializedObject.AssertFindProperty("_forceAudioInputDeviceIndex");
  1065. _propManualAudioSampleRate = serializedObject.AssertFindProperty("_manualAudioSampleRate");
  1066. _propManualAudioChannelCount = serializedObject.AssertFindProperty("_manualAudioChannelCount");
  1067. _propDownScale = serializedObject.AssertFindProperty("_downScale");
  1068. _propMaxVideoSize = serializedObject.AssertFindProperty("_maxVideoSize");
  1069. _propFrameRate = serializedObject.AssertFindProperty("_frameRate");
  1070. _propTimelapseScale = serializedObject.AssertFindProperty("_timelapseScale");
  1071. _propFrameUpdateMode = serializedObject.AssertFindProperty("_frameUpdateMode");
  1072. _propFlipVertically = serializedObject.AssertFindProperty("_flipVertically");
  1073. _propForceGpuFlush = serializedObject.AssertFindProperty("_forceGpuFlush");
  1074. _propWaitForEndOfFrame = serializedObject.AssertFindProperty("_useWaitForEndOfFrame");
  1075. _propAndroidUpdateMediaGallery = serializedObject.AssertFindProperty("_androidUpdateMediaGallery");
  1076. _propAndroidNoCaptureRotation = serializedObject.AssertFindProperty("_androidNoCaptureRotation");
  1077. _propUseMotionBlur = serializedObject.AssertFindProperty("_useMotionBlur");
  1078. _propMotionBlurSamples = serializedObject.AssertFindProperty("_motionBlurSamples");
  1079. _propMotionBlurCameras = serializedObject.AssertFindProperty("_motionBlurCameras");
  1080. _propStartTrigger = serializedObject.AssertFindProperty("_startTrigger");
  1081. _propStartDelay = serializedObject.AssertFindProperty("_startDelay");
  1082. _propStartDelaySeconds = serializedObject.AssertFindProperty("_startDelaySeconds");
  1083. _propStopMode = serializedObject.AssertFindProperty("_stopMode");
  1084. _propStopFrames = serializedObject.AssertFindProperty("_stopFrames");
  1085. _propStopSeconds = serializedObject.AssertFindProperty("_stopSeconds");
  1086. // _propPauseCaptureOnAppPause = serializedObject.AssertFindProperty("_pauseCaptureOnAppPause");
  1087. _propVideoHints = new PropVideoHints[(int)NativePlugin.Platform.Count];
  1088. _propVideoHints[(int)NativePlugin.Platform.Windows] = GetProperties_VideoHints(serializedObject, "_encoderHintsWindows.videoHints");
  1089. _propVideoHints[(int)NativePlugin.Platform.macOS] = GetProperties_VideoHints(serializedObject, "_encoderHintsMacOS.videoHints");
  1090. _propVideoHints[(int)NativePlugin.Platform.iOS] = GetProperties_VideoHints(serializedObject, "_encoderHintsIOS.videoHints");
  1091. _propVideoHints[(int)NativePlugin.Platform.Android] = GetProperties_VideoHints(serializedObject, "_encoderHintsAndroid.videoHints");
  1092. _propImageHints = new PropImageHints[(int)NativePlugin.Platform.Count];
  1093. _propImageHints[(int)NativePlugin.Platform.Windows] = GetProperties_ImageHints(serializedObject, "_encoderHintsWindows.imageHints");
  1094. _propImageHints[(int)NativePlugin.Platform.macOS] = GetProperties_ImageHints(serializedObject, "_encoderHintsMacOS.imageHints");
  1095. _propImageHints[(int)NativePlugin.Platform.iOS] = GetProperties_ImageHints(serializedObject, "_encoderHintsIOS.imageHints");
  1096. _propImageHints[(int)NativePlugin.Platform.Android] = GetProperties_ImageHints(serializedObject, "_encoderHintsAndroid.imageHints");
  1097. _propLogCaptureStartStop = serializedObject.AssertFindProperty("_logCaptureStartStop");
  1098. _propAllowVsyncDisable = serializedObject.AssertFindProperty("_allowVSyncDisable");
  1099. _propSupportTextureRecreate = serializedObject.AssertFindProperty("_supportTextureRecreate");
  1100. #if AVPRO_MOVIECAPTURE_PLAYABLES_SUPPORT
  1101. _propTimelineController = serializedObject.AssertFindProperty("_timelineController");
  1102. #endif
  1103. #if AVPRO_MOVIECAPTURE_VIDEOPLAYER_SUPPORT
  1104. _propVideoPlayerController = serializedObject.AssertFindProperty("_videoPlayerController");
  1105. #endif
  1106. _isTrialVersion = false;
  1107. if (Application.isPlaying)
  1108. {
  1109. _isTrialVersion = IsTrialVersion();
  1110. }
  1111. }
  1112. private static PropVideoHints GetProperties_VideoHints(SerializedObject serializedObject, string prefix)
  1113. {
  1114. PropVideoHints result = new PropVideoHints();
  1115. result.propAverageBitrate = serializedObject.AssertFindProperty(prefix + ".averageBitrate");
  1116. result.propMaximumBitrate = serializedObject.AssertFindProperty(prefix + ".maximumBitrate");
  1117. result.propQuality = serializedObject.AssertFindProperty(prefix + ".quality");
  1118. result.propKeyframeInterval = serializedObject.AssertFindProperty(prefix + ".keyframeInterval");
  1119. result.propFastStart = serializedObject.AssertFindProperty(prefix + ".allowFastStartStreamingPostProcess");
  1120. result.propTransparency = serializedObject.AssertFindProperty(prefix + ".transparency");
  1121. result.propHardwareEncoding = serializedObject.AssertFindProperty(prefix + ".useHardwareEncoding");
  1122. result.propInjectStereoPacking = serializedObject.AssertFindProperty(prefix + ".injectStereoPacking");
  1123. result.propStereoPacking = serializedObject.AssertFindProperty(prefix + ".stereoPacking");
  1124. result.propInjectSphericalVideoLayout = serializedObject.AssertFindProperty(prefix + ".injectSphericalVideoLayout");
  1125. result.propSphericalVideoLayout = serializedObject.AssertFindProperty(prefix + ".sphericalVideoLayout");
  1126. result.propEnableFragmentedWriting = serializedObject.AssertFindProperty(prefix + ".enableFragmentedWriting");
  1127. result.propMovieFragmentInterval = serializedObject.AssertFindProperty(prefix + ".movieFragmentInterval");
  1128. return result;
  1129. }
  1130. private static PropImageHints GetProperties_ImageHints(SerializedObject serializedObject, string prefix)
  1131. {
  1132. PropImageHints result = new PropImageHints();
  1133. result.propQuality = serializedObject.AssertFindProperty(prefix + ".quality");
  1134. result.propTransparency = serializedObject.AssertFindProperty(prefix + ".transparency");
  1135. return result;
  1136. }
  1137. private void OnDisable()
  1138. {
  1139. SaveSettings();
  1140. }
  1141. protected static bool IsTrialVersion()
  1142. {
  1143. bool result = false;
  1144. try
  1145. {
  1146. result = NativePlugin.IsTrialVersion();
  1147. }
  1148. catch (System.DllNotFoundException)
  1149. {
  1150. // Silent catch as we report this error elsewhere
  1151. }
  1152. return result;
  1153. }
  1154. protected static void ShowNoticeBox(MessageType messageType, string message)
  1155. {
  1156. //GUI.backgroundColor = Color.yellow;
  1157. //EditorGUILayout.HelpBox(message, messageType);
  1158. switch (messageType)
  1159. {
  1160. case MessageType.Error:
  1161. GUI.color = Color.red;
  1162. message = "Error: " + message;
  1163. break;
  1164. case MessageType.Warning:
  1165. GUI.color = Color.yellow;
  1166. message = "Warning: " + message;
  1167. break;
  1168. }
  1169. //GUI.color = Color.yellow;
  1170. GUILayout.TextArea(message);
  1171. GUI.color = Color.white;
  1172. }
  1173. public override bool RequiresConstantRepaint()
  1174. {
  1175. CaptureBase capture = (this.target) as CaptureBase;
  1176. return (Application.isPlaying && capture.isActiveAndEnabled && capture.IsCapturing() && !capture.IsPaused());
  1177. }
  1178. }
  1179. }
  1180. #endif