PlaylistMediaPlayerEditor.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. using UnityEngine;
  2. using UnityEditor;
  3. using System.Collections.Generic;
  4. //-----------------------------------------------------------------------------
  5. // Copyright 2015-2022 RenderHeads Ltd. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. namespace RenderHeads.Media.AVProVideo.Editor
  8. {
  9. /// <summary>
  10. /// Editor for the MediaPlaylist class
  11. /// </summary>
  12. [CustomPropertyDrawer(typeof(MediaPlaylist))]
  13. public class MediaPlaylistDrawer : PropertyDrawer
  14. {
  15. private static readonly GUIContent _guiTextInsert = new GUIContent("Clone");
  16. private static readonly GUIContent _guiTextDelete = new GUIContent("Delete");
  17. private static readonly GUIContent _guiTextUp = new GUIContent("↑");
  18. private static readonly GUIContent _guiTextDown = new GUIContent("↓");
  19. private static GUIStyle _styleButtonFoldout = null;
  20. private static GUIStyle _styleHelpBoxNoPad = null;
  21. public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
  22. {
  23. if (_styleButtonFoldout == null)
  24. {
  25. _styleButtonFoldout = new GUIStyle(EditorStyles.foldout);
  26. _styleButtonFoldout.margin = new RectOffset();
  27. _styleButtonFoldout.fontStyle = FontStyle.Bold;
  28. _styleButtonFoldout.alignment = TextAnchor.MiddleLeft;
  29. }
  30. if (_styleHelpBoxNoPad == null)
  31. {
  32. _styleHelpBoxNoPad = new GUIStyle(EditorStyles.helpBox);
  33. _styleHelpBoxNoPad.padding = new RectOffset();
  34. _styleHelpBoxNoPad.overflow = new RectOffset();
  35. _styleHelpBoxNoPad.margin = new RectOffset();
  36. _styleHelpBoxNoPad.margin = new RectOffset(0, 0, 0, 0);
  37. _styleHelpBoxNoPad.stretchWidth = false;
  38. _styleHelpBoxNoPad.stretchHeight = false;
  39. }
  40. // Using BeginProperty / EndProperty on the parent property means that
  41. // prefab override logic works on the entire property.
  42. EditorGUI.BeginProperty(position, label, property);
  43. SerializedProperty propItems = property.FindPropertyRelative("_items");
  44. if (propItems.arraySize == 0)
  45. {
  46. if (GUILayout.Button("Insert Item"))
  47. {
  48. propItems.InsertArrayElementAtIndex(0);
  49. }
  50. }
  51. int insertIndex = -1;
  52. int deleteIndex = -1;
  53. for (int i = 0; i < propItems.arraySize; i++)
  54. {
  55. SerializedProperty propItem = propItems.GetArrayElementAtIndex(i);
  56. GUILayout.BeginVertical(_styleHelpBoxNoPad);
  57. GUI.backgroundColor = propItem.isExpanded ? Color.yellow : Color.white;
  58. GUILayout.Box(GUIContent.none, EditorStyles.miniButton, GUILayout.ExpandWidth(true));
  59. Rect buttonRect = GUILayoutUtility.GetLastRect();
  60. GUI.backgroundColor = Color.white;
  61. if (Event.current.type != EventType.Layout)
  62. {
  63. EditorGUI.indentLevel++;
  64. SerializedProperty propName = propItem.FindPropertyRelative("name");
  65. propItem.isExpanded = EditorGUI.Foldout(buttonRect, propItem.isExpanded, "#" + i + ": " + propName.stringValue, true, _styleButtonFoldout);
  66. EditorGUI.indentLevel--;
  67. }
  68. GUILayout.BeginHorizontal();
  69. GUILayout.FlexibleSpace();
  70. if (GUILayout.Button(_guiTextInsert, GUILayout.ExpandWidth(false)))
  71. {
  72. insertIndex = i;
  73. }
  74. if (GUILayout.Button(_guiTextDelete, GUILayout.ExpandWidth(false)))
  75. {
  76. deleteIndex = i;
  77. }
  78. EditorGUI.BeginDisabledGroup((i - 1) < 0);
  79. if (GUILayout.Button(_guiTextUp, GUILayout.ExpandWidth(false)))
  80. {
  81. propItems.MoveArrayElement(i, i - 1);
  82. }
  83. EditorGUI.EndDisabledGroup();
  84. EditorGUI.BeginDisabledGroup((i + 1) >= propItems.arraySize);
  85. if (GUILayout.Button(_guiTextDown, GUILayout.ExpandWidth(false)))
  86. {
  87. propItems.MoveArrayElement(i, i + 1);
  88. }
  89. EditorGUI.EndDisabledGroup();
  90. GUILayout.EndHorizontal();
  91. if (propItem.isExpanded)
  92. {
  93. EditorGUILayout.PropertyField(propItem);
  94. }
  95. GUILayout.EndVertical();
  96. GUILayout.Space(8f);
  97. }
  98. if (insertIndex >= 0)
  99. {
  100. propItems.InsertArrayElementAtIndex(insertIndex);
  101. }
  102. else if (deleteIndex >= 0)
  103. {
  104. propItems.DeleteArrayElementAtIndex(deleteIndex);
  105. }
  106. EditorGUI.EndProperty();
  107. }
  108. }
  109. /// <summary>
  110. /// Editor for the MediaPlaylist.MediaItem class
  111. /// </summary>
  112. [CustomPropertyDrawer(typeof(MediaPlaylist.MediaItem))]
  113. public class MediaPlaylistItemDrawer : PropertyDrawer
  114. {
  115. private static readonly GUIContent _guiTextTransition = new GUIContent("Transition");
  116. private static readonly GUIContent _guiTextOverrideTransition = new GUIContent("Override Transition");
  117. private static readonly GUIContent _guiTextDuration = new GUIContent("Duration");
  118. private static readonly GUIContent _guiTextEasing = new GUIContent("Easing");
  119. public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
  120. {
  121. EditorGUILayout.PropertyField(property.FindPropertyRelative("name"));
  122. SerializedProperty propSourceType = property.FindPropertyRelative("sourceType");
  123. EditorGUILayout.PropertyField(propSourceType);
  124. if (propSourceType.enumValueIndex == 0)
  125. {
  126. EditorGUILayout.PropertyField(property.FindPropertyRelative("mediaPath"));
  127. MediaPathDrawer.ShowBrowseButton(property.FindPropertyRelative("mediaPath"));
  128. }
  129. else
  130. {
  131. //EditorGUILayout.PropertyField(property.FindPropertyRelative("texture"));
  132. //EditorGUILayout.PropertyField(property.FindPropertyRelative("textureDuration"));
  133. }
  134. EditorGUILayout.Space();
  135. //EditorGUILayout.PropertyField(property.FindPropertyRelative("stereoPacking"));
  136. //EditorGUILayout.PropertyField(property.FindPropertyRelative("alphaPacking"));
  137. EditorGUILayout.Space();
  138. EditorGUILayout.PropertyField(property.FindPropertyRelative("loop"));
  139. EditorGUILayout.PropertyField(property.FindPropertyRelative("startMode"));
  140. SerializedProperty propProgressMode = property.FindPropertyRelative("progressMode");
  141. EditorGUILayout.PropertyField(propProgressMode);
  142. if (propProgressMode.enumValueIndex == (int)PlaylistMediaPlayer.ProgressMode.BeforeFinish)
  143. {
  144. EditorGUILayout.PropertyField(property.FindPropertyRelative("progressTimeSeconds"));
  145. }
  146. EditorGUILayout.Space();
  147. SerializedProperty propIsOverrideTransition = property.FindPropertyRelative("isOverrideTransition");
  148. EditorGUILayout.PropertyField(propIsOverrideTransition, _guiTextOverrideTransition);
  149. if (propIsOverrideTransition.boolValue)
  150. {
  151. EditorGUI.indentLevel++;
  152. SerializedProperty propTransitionMode = property.FindPropertyRelative("overrideTransition");
  153. EditorGUILayout.PropertyField(propTransitionMode, _guiTextTransition);
  154. if (propTransitionMode.enumValueIndex != (int)PlaylistMediaPlayer.Transition.None)
  155. {
  156. EditorGUILayout.PropertyField(property.FindPropertyRelative("overrideTransitionDuration"), _guiTextDuration);
  157. EditorGUILayout.PropertyField(property.FindPropertyRelative("overrideTransitionEasing"), _guiTextEasing);
  158. }
  159. EditorGUI.indentLevel--;
  160. }
  161. }
  162. }
  163. /// <summary>
  164. /// Editor for the PlaylistMediaPlayer component
  165. /// </summary>
  166. [CanEditMultipleObjects]
  167. [CustomEditor(typeof(PlaylistMediaPlayer))]
  168. public class PlaylistMediaPlayerEditor : UnityEditor.Editor
  169. {
  170. private SerializedProperty _propPlayerA;
  171. private SerializedProperty _propPlayerB;
  172. private SerializedProperty _propPlaylist;
  173. private SerializedProperty _propPlaylistAutoProgress;
  174. private SerializedProperty _propAutoCloseVideo;
  175. private SerializedProperty _propPlaylistLoopMode;
  176. private SerializedProperty _propPausePreviousOnTransition;
  177. private SerializedProperty _propDefaultTransition;
  178. private SerializedProperty _propDefaultTransitionDuration;
  179. private SerializedProperty _propDefaultTransitionEasing;
  180. private SerializedProperty _propAudioVolume;
  181. private SerializedProperty _propAudioMuted;
  182. private static bool _expandPlaylistItems = false;
  183. private static Material _materialIMGUI = null;
  184. private static GUIStyle _sectionBoxStyle = null;
  185. private const string SettingsPrefix = "AVProVideo-PlaylistMediaPlayerEditor-";
  186. private void OnEnable()
  187. {
  188. _propPlayerA = this.CheckFindProperty("_playerA");
  189. _propPlayerB = this.CheckFindProperty("_playerB");
  190. _propDefaultTransition = this.CheckFindProperty("_defaultTransition");
  191. _propDefaultTransitionDuration = this.CheckFindProperty("_defaultTransitionDuration");
  192. _propDefaultTransitionEasing = this.CheckFindProperty("_defaultTransitionEasing");
  193. _propPausePreviousOnTransition = this.CheckFindProperty("_pausePreviousOnTransition");
  194. _propPlaylist = this.CheckFindProperty("_playlist");
  195. _propPlaylistAutoProgress = this.CheckFindProperty("_playlistAutoProgress");
  196. _propAutoCloseVideo = this.CheckFindProperty("_autoCloseVideo");
  197. _propPlaylistLoopMode = this.CheckFindProperty("_playlistLoopMode");
  198. _propAudioVolume = this.CheckFindProperty("_playlistAudioVolume");
  199. _propAudioMuted = this.CheckFindProperty("_playlistAudioMuted");
  200. _expandPlaylistItems = EditorPrefs.GetBool(SettingsPrefix + "ExpandPlaylistItems", false);
  201. }
  202. private void OnDisable()
  203. {
  204. EditorPrefs.SetBool(SettingsPrefix + "ExpandPlaylistItems", _expandPlaylistItems);
  205. if (_materialIMGUI)
  206. {
  207. DestroyImmediate(_materialIMGUI); _materialIMGUI = null;
  208. }
  209. }
  210. public override bool RequiresConstantRepaint()
  211. {
  212. PlaylistMediaPlayer media = (this.target) as PlaylistMediaPlayer;
  213. return (media.Control != null && media.isActiveAndEnabled);
  214. }
  215. public override void OnInspectorGUI()
  216. {
  217. PlaylistMediaPlayer media = (this.target) as PlaylistMediaPlayer;
  218. serializedObject.Update();
  219. if (media == null || _propPlayerA == null)
  220. {
  221. return;
  222. }
  223. if (_sectionBoxStyle == null)
  224. {
  225. _sectionBoxStyle = new GUIStyle(GUI.skin.box);
  226. _sectionBoxStyle.padding.top = 0;
  227. _sectionBoxStyle.padding.bottom = 0;
  228. }
  229. EditorGUILayout.PropertyField(_propPlayerA);
  230. EditorGUILayout.PropertyField(_propPlayerB);
  231. EditorGUILayout.Space();
  232. EditorGUILayout.Space();
  233. GUILayout.Label("Audio", EditorStyles.boldLabel);
  234. EditorGUI.BeginChangeCheck();
  235. EditorGUILayout.PropertyField(_propAudioVolume, new GUIContent("Volume"));
  236. if (EditorGUI.EndChangeCheck())
  237. {
  238. foreach (PlaylistMediaPlayer player in this.targets)
  239. {
  240. player.AudioVolume = _propAudioVolume.floatValue;
  241. }
  242. }
  243. EditorGUI.BeginChangeCheck();
  244. EditorGUILayout.PropertyField(_propAudioMuted, new GUIContent("Muted"));
  245. if (EditorGUI.EndChangeCheck())
  246. {
  247. foreach (PlaylistMediaPlayer player in this.targets)
  248. {
  249. player.AudioMuted = _propAudioMuted.boolValue;
  250. }
  251. }
  252. EditorGUILayout.Space();
  253. EditorGUILayout.Space();
  254. GUILayout.Label("Playlist", EditorStyles.boldLabel);
  255. EditorGUILayout.PropertyField(_propPlaylistAutoProgress, new GUIContent("Auto Progress"));
  256. EditorGUILayout.PropertyField(_propPlaylistLoopMode, new GUIContent("Loop Mode"));
  257. EditorGUILayout.PropertyField(_propAutoCloseVideo);
  258. {
  259. EditorGUILayout.Space();
  260. EditorGUILayout.Space();
  261. GUI.color = Color.white;
  262. GUI.backgroundColor = Color.clear;
  263. if (_expandPlaylistItems)
  264. {
  265. GUI.color = Color.white;
  266. GUI.backgroundColor = new Color(0.8f, 0.8f, 0.8f, 0.1f);
  267. if (EditorGUIUtility.isProSkin)
  268. {
  269. GUI.backgroundColor = Color.black;
  270. }
  271. }
  272. GUILayout.BeginVertical(_sectionBoxStyle);
  273. GUI.backgroundColor = Color.white;
  274. if (GUILayout.Button("Playlist Items", EditorStyles.toolbarButton))
  275. {
  276. _expandPlaylistItems = !_expandPlaylistItems;
  277. }
  278. GUI.color = Color.white;
  279. if (_expandPlaylistItems)
  280. {
  281. EditorGUILayout.PropertyField(_propPlaylist);
  282. }
  283. GUILayout.EndVertical();
  284. }
  285. EditorGUILayout.Space();
  286. EditorGUILayout.Space();
  287. GUILayout.Label("Default Transition", EditorStyles.boldLabel);
  288. EditorGUILayout.PropertyField(_propDefaultTransition, new GUIContent("Transition"));
  289. EditorGUILayout.PropertyField(_propDefaultTransitionEasing, new GUIContent("Easing"));
  290. EditorGUILayout.PropertyField(_propDefaultTransitionDuration, new GUIContent("Duration"));
  291. EditorGUILayout.PropertyField(_propPausePreviousOnTransition, new GUIContent("Pause Previous"));
  292. EditorGUILayout.Space();
  293. EditorGUILayout.Space();
  294. if (Application.isPlaying)
  295. {
  296. ITextureProducer textureSource = media.TextureProducer;
  297. Texture texture = null;
  298. if (textureSource != null)
  299. {
  300. texture = textureSource.GetTexture();
  301. }
  302. if (texture == null)
  303. {
  304. texture = EditorGUIUtility.whiteTexture;
  305. }
  306. float ratio = 1f;// (float)texture.width / (float)texture.height;
  307. // Reserve rectangle for texture
  308. GUILayout.BeginHorizontal();
  309. GUILayout.FlexibleSpace();
  310. Rect textureRect;
  311. if (texture != EditorGUIUtility.whiteTexture)
  312. {
  313. textureRect = GUILayoutUtility.GetRect(Screen.width / 2, Screen.width / 2, (Screen.width / 2) / ratio, (Screen.width / 2) / ratio);
  314. }
  315. else
  316. {
  317. textureRect = GUILayoutUtility.GetRect(1920f / 40f, 1080f / 40f);
  318. }
  319. GUILayout.FlexibleSpace();
  320. GUILayout.EndHorizontal();
  321. string rateText = "0";
  322. string playerText = string.Empty;
  323. if (media.Info != null)
  324. {
  325. rateText = media.Info.GetVideoDisplayRate().ToString("F2");
  326. playerText = media.Info.GetPlayerDescription();
  327. }
  328. EditorGUILayout.LabelField("Display Rate", rateText);
  329. EditorGUILayout.LabelField("Using", playerText);
  330. // Draw the texture
  331. if (Event.current.type == EventType.Repaint)
  332. {
  333. Matrix4x4 prevMatrix = GUI.matrix;
  334. if (textureSource != null && textureSource.RequiresVerticalFlip())
  335. {
  336. GUIUtility.ScaleAroundPivot(new Vector2(1f, -1f), new Vector2(0f, textureRect.y + (textureRect.height / 2f)));
  337. }
  338. GUI.color = Color.gray;
  339. EditorGUI.DrawTextureTransparent(textureRect, Texture2D.blackTexture, ScaleMode.StretchToFill);
  340. GUI.color = Color.white;
  341. if (!GUI.enabled)
  342. {
  343. GUI.color = Color.grey;
  344. GUI.DrawTexture(textureRect, texture, ScaleMode.ScaleToFit, false);
  345. GUI.color = Color.white;
  346. }
  347. else
  348. {
  349. if (!_materialIMGUI)
  350. {
  351. _materialIMGUI = VideoRender.CreateResolveMaterial( false );
  352. VideoRender.SetupGammaMaterial(_materialIMGUI, true);
  353. }
  354. {
  355. EditorGUI.DrawPreviewTexture(textureRect, texture, _materialIMGUI, ScaleMode.ScaleToFit);
  356. }
  357. }
  358. GUI.matrix = prevMatrix;
  359. }
  360. }
  361. EditorGUI.BeginDisabledGroup(!(media.Control != null && media.Control.CanPlay() && media.isActiveAndEnabled && !EditorApplication.isPaused));
  362. OnInspectorGUI_PlayControls(media);
  363. EditorGUI.EndDisabledGroup();
  364. EditorGUILayout.Space();
  365. EditorGUILayout.Space();
  366. EditorGUI.BeginDisabledGroup(!Application.isPlaying);
  367. GUILayout.Label("Current Item: " + media.PlaylistIndex + " / " + Mathf.Max(0, media.Playlist.Items.Count - 1) );
  368. GUILayout.BeginHorizontal();
  369. EditorGUI.BeginDisabledGroup(!media.CanJumpToItem(media.PlaylistIndex - 1));
  370. if (GUILayout.Button("Prev"))
  371. {
  372. media.PrevItem();
  373. }
  374. EditorGUI.EndDisabledGroup();
  375. EditorGUI.BeginDisabledGroup(!media.CanJumpToItem(media.PlaylistIndex + 1));
  376. if (GUILayout.Button("Next"))
  377. {
  378. media.NextItem();
  379. }
  380. EditorGUI.EndDisabledGroup();
  381. GUILayout.EndHorizontal();
  382. EditorGUI.EndDisabledGroup();
  383. serializedObject.ApplyModifiedProperties();
  384. }
  385. private void OnInspectorGUI_PlayControls(PlaylistMediaPlayer player)
  386. {
  387. GUILayout.Space(8.0f);
  388. // Slider
  389. EditorGUILayout.BeginHorizontal();
  390. bool isPlaying = false;
  391. if (player.Control != null)
  392. {
  393. isPlaying = player.Control.IsPlaying();
  394. }
  395. float currentTime = 0f;
  396. if (player.Control != null)
  397. {
  398. currentTime = (float)player.Control.GetCurrentTime();
  399. }
  400. float durationTime = 0f;
  401. if (player.Info != null)
  402. {
  403. durationTime = (float)player.Info.GetDuration();
  404. if (float.IsNaN(durationTime))
  405. {
  406. durationTime = 0f;
  407. }
  408. }
  409. string timeUsed = Helper.GetTimeString(currentTime, true);
  410. GUILayout.Label(timeUsed, GUILayout.ExpandWidth(false));
  411. float newTime = GUILayout.HorizontalSlider(currentTime, 0f, durationTime, GUILayout.ExpandWidth(true));
  412. if (newTime != currentTime && player.Control != null)
  413. {
  414. player.Control.Seek(newTime);
  415. }
  416. string timeTotal = "Infinity";
  417. if (!float.IsInfinity(durationTime))
  418. {
  419. timeTotal = Helper.GetTimeString(durationTime, true);
  420. }
  421. GUILayout.Label(timeTotal, GUILayout.ExpandWidth(false));
  422. EditorGUILayout.EndHorizontal();
  423. // Buttons
  424. EditorGUILayout.BeginHorizontal();
  425. if (GUILayout.Button("Rewind", GUILayout.ExpandWidth(false)))
  426. {
  427. if (player.Control != null)
  428. {
  429. player.Control.Rewind();
  430. }
  431. }
  432. if (!isPlaying)
  433. {
  434. GUI.color = Color.green;
  435. if (GUILayout.Button("Play", GUILayout.ExpandWidth(true)))
  436. {
  437. player.Play();
  438. }
  439. }
  440. else
  441. {
  442. GUI.color = Color.yellow;
  443. if (GUILayout.Button("Pause", GUILayout.ExpandWidth(true)))
  444. {
  445. player.Pause();
  446. }
  447. }
  448. GUI.color = Color.white;
  449. EditorGUILayout.EndHorizontal();
  450. }
  451. }
  452. }