UVCDrawer.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. #define ENABLE_LOG
  2. /*
  3. * Copyright (c) 2014 - 2022 t_saki@serenegiant.com
  4. */
  5. using System;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using UnityEngine;
  9. using UnityEngine.UI;
  10. namespace Serenegiant.UVC
  11. {
  12. public class UVCDrawer : MonoBehaviour, IUVCDrawer
  13. {
  14. /**
  15. * IUVCSelectorがセットされていないとき
  16. * またはIUVCSelectorが解像度選択時にnullを
  17. * 返したときのデフォルトの解像度(幅)
  18. */
  19. public int DefaultWidth = 1280;
  20. /**
  21. * IUVCSelectorがセットされていないとき
  22. * またはIUVCSelectorが解像度選択時にnullを
  23. * 返したときのデフォルトの解像度(高さ)
  24. */
  25. public int DefaultHeight = 720;
  26. /**
  27. * 接続時及び描画時のフィルタ用
  28. */
  29. public UVCFilter[] UVCFilters;
  30. /**
  31. * GameObject保留UVC设备的视频目标材质
  32. * 如果未设置,则使用与分配此脚本相同的GameObjec。
  33. */
  34. public List<GameObject> RenderTargets;
  35. [HideInInspector]
  36. public Action<Texture> StartPreviewAction;
  37. [HideInInspector]
  38. public Action StopPreviewAction;
  39. //--------------------------------------------------------------------------------
  40. private const string TAG = "UVCDrawer#";
  41. /**
  42. * UVC機器からの映像の描画先Material
  43. * TargetGameObjectから取得する
  44. * 優先順位:
  45. * TargetGameObjectのSkybox
  46. * > TargetGameObjectのRenderer
  47. * > TargetGameObjectのRawImage
  48. * > TargetGameObjectのMaterial
  49. * いずれの方法でも取得できなければStartでUnityExceptionを投げる
  50. */
  51. private UnityEngine.Object[] TargetMaterials;
  52. /**
  53. * オリジナルのテクスチャ
  54. * UVCカメラ映像受け取り用テクスチャをセットする前に
  55. * GetComponent<Renderer>().material.mainTextureに設定されていた値
  56. */
  57. private Texture[] SavedTextures;
  58. private Quaternion[] quaternions;
  59. //================================================================================
  60. // Start is called before the first frame update
  61. void Start()
  62. {
  63. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  64. Console.WriteLine($"{TAG}Start:");
  65. #endif
  66. UpdateTarget();
  67. }
  68. // // Update is called once per frame
  69. // void Update()
  70. // {
  71. //
  72. // }
  73. //================================================================================
  74. /**
  75. * UVC機器が接続された
  76. * IOnUVCAttachHandlerの実装
  77. * @param manager 呼び出し元のUVCManager
  78. * @param device 対象となるUVC機器の情報
  79. * @return true: UVC機器を使用する, false: UVC機器を使用しない
  80. */
  81. public bool OnUVCAttachEvent(UVCManager manager, UVCDevice device)
  82. {
  83. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  84. Console.WriteLine($"{TAG}OnUVCAttachEvent:{device}");
  85. #endif
  86. // XXX 今の実装では基本的に全てのUVC機器を受け入れる
  87. // ただしTHETA SとTHETA VとTHETA Z1は映像を取得できないインターフェースがあるのでオミットする
  88. // CanDrawと同様にUVC機器フィルターをインスペクタで設定できるようにする
  89. var result = !device.IsRicoh || device.IsTHETA;
  90. result &= UVCFilter.Match(device, UVCFilters);
  91. return result;
  92. }
  93. /**
  94. * UVC機器が取り外された
  95. * IOnUVCDetachEventHandlerの実装
  96. * @param manager 呼び出し元のUVCManager
  97. * @param device 対象となるUVC機器の情報
  98. */
  99. public void OnUVCDetachEvent(UVCManager manager, UVCDevice device)
  100. {
  101. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  102. Console.WriteLine($"{TAG}OnUVCDetachEvent:{device}");
  103. #endif
  104. }
  105. // /**
  106. // * 解像度選択
  107. // * IOnUVCSelectSizeHandlerの実装
  108. // * @param manager 呼び出し元のUVCManager
  109. // * @param device 対象となるUVC機器の情報
  110. // * @param formats 対応している解像度についての情報
  111. // */
  112. // public SupportedFormats.Size OnUVCSelectSize(UVCManager manager, UVCDevice device, SupportedFormats formats)
  113. // {
  114. //#if (!NDEBUG && DEBUG && ENABLE_LOG)
  115. // Console.WriteLine($"{TAG}OnUVCSelectSize:{device}");
  116. //#endif
  117. // if (device.IsTHETA_V || device.IsTHETA_Z1)
  118. // {
  119. //#if (!NDEBUG && DEBUG && ENABLE_LOG)
  120. // Console.WriteLine($"{TAG}OnUVCSelectSize:THETA V/Z1");
  121. //#endif
  122. // return FindSize(formats, 3840, 1920);
  123. // }
  124. // else if (device.IsTHETA_S)
  125. // {
  126. //#if (!NDEBUG && DEBUG && ENABLE_LOG)
  127. // Console.WriteLine($"{TAG}OnUVCSelectSize:THETA S");
  128. //#endif
  129. // return FindSize(formats, 1920, 1080);
  130. // }
  131. // else
  132. // {
  133. //#if (!NDEBUG && DEBUG && ENABLE_LOG)
  134. // Console.WriteLine($"{TAG}OnUVCSelectSize:other UVC device,{device}");
  135. //#endif
  136. // return formats.Find(DefaultWidth, DefaultHeight);
  137. // }
  138. // }
  139. /**
  140. * 获取IUVCdrawer是否可以绘制指定的UVC设备的视频
  141. * 实现IUVCdrawer
  142. * @param manager 调用方UVCmanager
  143. * @param device 目标UVC设备信息
  144. */
  145. public bool CanDraw(UVCManager manager, UVCDevice device)
  146. {
  147. return UVCFilter.Match(device, UVCFilters);
  148. }
  149. /**
  150. * 已开始获取视频
  151. * 实现IUVCdrawer
  152. * @param manager 调用方UVCManager
  153. * @param device 对象的UVC设备的信息
  154. * @param tex 从UVC设备接收视频的纹理实例
  155. */
  156. public void OnUVCStartEvent(UVCManager manager, UVCDevice device, Texture tex)
  157. {
  158. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  159. Console.WriteLine($"{TAG}OnUVCStartEvent:{device}");
  160. #endif
  161. HandleOnStartPreview(tex);
  162. StartPreviewAction?.Invoke(tex);
  163. }
  164. /**
  165. * 视频获取已完成
  166. * 实现IUVCdrawer
  167. * @param manager 调用方UVCManager
  168. * @param device 对象的UVC设备的信息
  169. */
  170. public void OnUVCStopEvent(UVCManager manager, UVCDevice device)
  171. {
  172. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  173. Console.WriteLine($"{TAG}OnUVCStopEvent:{device}");
  174. #endif
  175. HandleOnStopPreview();
  176. StopPreviewAction?.Invoke();
  177. }
  178. //================================================================================
  179. /**
  180. * 更新目标
  181. */
  182. private void UpdateTarget()
  183. {
  184. bool found = false;
  185. if ((RenderTargets != null) && (RenderTargets.Count > 0))
  186. {
  187. TargetMaterials = new UnityEngine.Object[RenderTargets.Count];
  188. SavedTextures = new Texture[RenderTargets.Count];
  189. quaternions = new Quaternion[RenderTargets.Count];
  190. int i = 0;
  191. foreach (var target in RenderTargets)
  192. {
  193. if (target != null)
  194. {
  195. var material = TargetMaterials[i] = GetTargetMaterial(target);
  196. if (material != null)
  197. {
  198. found = true;
  199. }
  200. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  201. Console.WriteLine($"{TAG}UpdateTarget:material={material}");
  202. #endif
  203. }
  204. i++;
  205. }
  206. }
  207. if (!found)
  208. { //找不到一个目标时,该脚本
  209. //尝试从AddComponent GameObject获取
  210. //在XXX RenderTargets中设置gameObject?
  211. TargetMaterials = new UnityEngine.Object[1];
  212. SavedTextures = new Texture[1];
  213. quaternions = new Quaternion[1];
  214. TargetMaterials[0] = GetTargetMaterial(gameObject);
  215. found = TargetMaterials[0] != null;
  216. }
  217. if (!found)
  218. {
  219. throw new UnityException("no target material found.");
  220. }
  221. }
  222. /**
  223. * 获取将图像绘制为纹理的材质
  224. * 如果指定的GameObject具有Skybox/Render/RawImage/Material,则从中获取Material
  225. * 如果每个都分配了多个,则返回第一个找到的可用项
  226. * 优先级:Skybox>Render>RawImage>Material
  227. * @param target
  228. * @return如果找不到,则返回null
  229. */
  230. UnityEngine.Object GetTargetMaterial(GameObject target/*NonNull*/)
  231. {
  232. // Skyboxの取得を試みる
  233. var skyboxs = target.GetComponents<Skybox>();
  234. if (skyboxs != null)
  235. {
  236. foreach (var skybox in skyboxs)
  237. {
  238. if (skybox.isActiveAndEnabled && (skybox.material != null))
  239. {
  240. RenderSettings.skybox = skybox.material;
  241. return skybox.material;
  242. }
  243. }
  244. }
  245. // Skyboxが取得できなければRendererの取得を試みる
  246. var renderers = target.GetComponents<Renderer>();
  247. if (renderers != null)
  248. {
  249. foreach (var renderer in renderers)
  250. {
  251. if (renderer.enabled && (renderer.material != null))
  252. {
  253. return renderer.material;
  254. }
  255. }
  256. }
  257. // SkyboxもRendererも取得できなければRawImageの取得を試みる
  258. var rawImages = target.GetComponents<RawImage>();
  259. if (rawImages != null)
  260. {
  261. foreach (var rawImage in rawImages)
  262. {
  263. if (rawImage.enabled && (rawImage.material != null))
  264. {
  265. return rawImage;
  266. }
  267. }
  268. }
  269. // SkyboxもRendererもRawImageも取得できなければMaterialの取得を試みる
  270. var material = target.GetComponent<Material>();
  271. if (material != null)
  272. {
  273. return material;
  274. }
  275. return null;
  276. }
  277. private void RestoreTexture()
  278. {
  279. for (int i = 0; i < TargetMaterials.Length; i++)
  280. {
  281. var target = TargetMaterials[i];
  282. try
  283. {
  284. if (target is Material)
  285. {
  286. (target as Material).mainTexture = SavedTextures[i];
  287. }
  288. else if (target is RawImage)
  289. {
  290. (target as RawImage).texture = SavedTextures[i];
  291. }
  292. }
  293. catch
  294. {
  295. Console.WriteLine($"{TAG}RestoreTexture:Exception cought");
  296. }
  297. SavedTextures[i] = null;
  298. quaternions[i] = Quaternion.identity;
  299. }
  300. }
  301. private void ClearTextures()
  302. {
  303. for (int i = 0; i < SavedTextures.Length; i++)
  304. {
  305. SavedTextures[i] = null;
  306. }
  307. }
  308. /**
  309. * 映像取得開始時の処理
  310. * @param tex 映像を受け取るテクスチャ
  311. */
  312. private void HandleOnStartPreview(Texture tex)
  313. {
  314. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  315. Console.WriteLine($"{TAG}HandleOnStartPreview:({tex})");
  316. #endif
  317. int i = 0;
  318. foreach (var target in TargetMaterials)
  319. {
  320. if (target is Material)
  321. {
  322. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  323. Console.WriteLine($"{TAG}HandleOnStartPreview:assign Texture to Material({target})");
  324. #endif
  325. SavedTextures[i++] = (target as Material).mainTexture;
  326. (target as Material).mainTexture = tex;
  327. }
  328. else if (target is RawImage)
  329. {
  330. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  331. Console.WriteLine($"{TAG}HandleOnStartPreview:assign Texture to RawImage({target})");
  332. #endif
  333. SavedTextures[i++] = (target as RawImage).texture;
  334. (target as RawImage).texture = tex;
  335. }
  336. }
  337. }
  338. /**
  339. * 映像取得が終了したときのUnity側の処理
  340. */
  341. private void HandleOnStopPreview()
  342. {
  343. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  344. Console.WriteLine($"{TAG}HandleOnStopPreview:");
  345. #endif
  346. // 描画先のテクスチャをもとに戻す
  347. RestoreTexture();
  348. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  349. Console.WriteLine($"{TAG}HandleOnStopPreview:finished");
  350. #endif
  351. }
  352. } // class UVCDrawer
  353. } // namespace Serenegiant.UVC