UVCManager.cs 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543
  1. #define ENABLE_LOG
  2. #define DEBUG
  3. /*
  4. * Copyright (c) 2014 - 2022 t_saki@serenegiant.com
  5. */
  6. using AOT;
  7. using System;
  8. using System.Collections;
  9. using System.Collections.Generic;
  10. using System.Runtime.CompilerServices;
  11. using System.Runtime.InteropServices;
  12. using System.Threading;
  13. using UnityEngine;
  14. #if UNITY_ANDROID && UNITY_2018_3_OR_NEWER
  15. using UnityEngine.Android;
  16. #endif
  17. namespace Serenegiant.UVC
  18. {
  19. [RequireComponent(typeof(AndroidUtils))]
  20. public class UVCManager : MonoBehaviour
  21. {
  22. private const string TAG = "UVCManager#";
  23. private const string FQCN_DETECTOR = "com.serenegiant.usb.DeviceDetectorFragment";
  24. //--------------------------------------------------------------------------------
  25. private const int FRAME_TYPE_MJPEG = 0x000007;
  26. private const int FRAME_TYPE_H264 = 0x000014;
  27. private const int FRAME_TYPE_H264_FRAME = 0x030011;
  28. //--------------------------------------------------------------------------------
  29. // Camera Terminal DescriptorのbmControlsフィールドのビットマスク
  30. private const UInt64 CTRL_SCANNING = 0x00000001; // D0: Scanning Mode
  31. private const UInt64 CTRL_AE = 0x00000002; // D1: Auto-Exposure Mode
  32. private const UInt64 CTRL_AE_PRIORITY = 0x00000004; // D2: Auto-Exposure Priority
  33. private const UInt64 CTRL_AE_ABS = 0x00000008; // D3: Exposure Time (Absolute)
  34. private const UInt64 CTRL_AE_REL = 0x00000010; // D4: Exposure Time (Relative)
  35. private const UInt64 CTRL_FOCUS_ABS = 0x00000020; // D5: Focus (Absolute)
  36. private const UInt64 CTRL_FOCUS_REL = 0x00000040; // D6: Focus (Relative)
  37. private const UInt64 CTRL_IRIS_ABS = 0x00000080; // D7: Iris (Absolute)
  38. private const UInt64 CTRL_IRIS_REL = 0x00000100; // D8: Iris (Relative)
  39. private const UInt64 CTRL_ZOOM_ABS = 0x00000200; // D9: Zoom (Absolute)
  40. private const UInt64 CTRL_ZOOM_REL = 0x00000400; // D10: Zoom (Relative)
  41. private const UInt64 CTRL_PANTILT_ABS = 0x00000800; // D11: PanTilt (Absolute)
  42. private const UInt64 CTRL_PAN_ABS = 0x01000800; // D11: PanTilt (Absolute)
  43. private const UInt64 CTRL_TILT_ABS = 0x02000800; // D11: PanTilt (Absolute)
  44. private const UInt64 CTRL_PANTILT_REL = 0x00001000; // D12: PanTilt (Relative)
  45. private const UInt64 CTRL_PAN_REL = 0x01001000; // D12: PanTilt (Relative)
  46. private const UInt64 CTRL_TILT_REL = 0x02001000; // D12: PanTilt (Relative)
  47. private const UInt64 CTRL_ROLL_ABS = 0x00002000; // D13: Roll (Absolute)
  48. private const UInt64 CTRL_ROLL_REL = 0x00004000; // D14: Roll (Relative)
  49. private const UInt64 CTRL_D15 = 0x00008000; // D15: Reserved
  50. private const UInt64 CTRL_D16 = 0x00010000; // D16: Reserved
  51. private const UInt64 CTRL_FOCUS_AUTO = 0x00020000; // D17: Focus, Auto
  52. private const UInt64 CTRL_PRIVACY = 0x00040000; // D18: Privacy
  53. private const UInt64 CTRL_FOCUS_SIMPLE = 0x00080000; // D19: Focus, Simple
  54. private const UInt64 CTRL_WINDOW = 0x00100000; // D20: Window
  55. private const UInt64 CTRL_ROI = 0x00200000; // D21: ROI
  56. private const UInt64 CTRL_D22 = 0x00400000; // D22: Reserved
  57. private const UInt64 CTRL_D23 = 0x00800000; // D23: Reserved
  58. // Processing Unit DescriptorのbmControlsフィールドのビットマスク
  59. private const UInt64 PU_BRIGHTNESS = 0x00000001; // D0: Brightness
  60. private const UInt64 PU_CONTRAST = 0x00000002; // D1: Contrast
  61. private const UInt64 PU_HUE = 0x00000004; // D2: Hue
  62. private const UInt64 PU_SATURATION = 0x00000008; // D3: Saturation
  63. private const UInt64 PU_SHARPNESS = 0x00000010; // D4: Sharpness
  64. private const UInt64 PU_GAMMA = 0x00000020; // D5: Gamma
  65. private const UInt64 PU_WB_TEMP = 0x00000040; // D6: White Balance Temperature
  66. private const UInt64 PU_WB_COMPO = 0x00000080; // D7: White Balance Component
  67. private const UInt64 PU_BACKLIGHT = 0x00000100; // D8: Backlight Compensation
  68. private const UInt64 PU_GAIN = 0x00000200; // D9: Gain
  69. private const UInt64 PU_POWER_LF = 0x00000400; // D10: Power Line Frequency
  70. private const UInt64 PU_HUE_AUTO = 0x00000800; // D11: Hue, Auto
  71. private const UInt64 PU_WB_TEMP_AUTO = 0x00001000; // D12: White Balance Temperature, Auto
  72. private const UInt64 PU_WB_COMPO_AUTO = 0x00002000; // D13: White Balance Component, Auto
  73. private const UInt64 PU_DIGITAL_MULT = 0x00004000; // D14: Digital Multiplier
  74. private const UInt64 PU_DIGITAL_LIMIT = 0x00008000; // D15: Digital Multiplier Limit
  75. private const UInt64 PU_AVIDEO_STD = 0x00010000; // D16: Analog Video Standard
  76. private const UInt64 PU_AVIDEO_LOCK = 0x00020000; // D17: Analog Video Lock Status
  77. private const UInt64 PU_CONTRAST_AUTO = 0x00040000; // D18: Contrast, Auto
  78. private const UInt64 PU_D19 = 0x00080000; // D19: Reserved
  79. private const UInt64 PU_D20 = 0x00100000; // D20: Reserved
  80. private const UInt64 PU_D21 = 0x00200000; // D21: Reserved
  81. private const UInt64 PU_D22 = 0x00400000; // D22: Reserved
  82. private const UInt64 PU_D23 = 0x00800000; // D23: Reserved
  83. // プロセッシングユニットのコントロールタイプを識別するために最上位ビットを立てる
  84. private const UInt64 PU_MASK = 0x80000000;
  85. //--------------------------------------------------------------------------------
  86. private static readonly UInt64[] SUPPORTED_CTRLS = {
  87. CTRL_SCANNING,
  88. CTRL_AE,
  89. CTRL_AE_PRIORITY,
  90. CTRL_AE_ABS,
  91. //CTRL_AE_REL,
  92. CTRL_FOCUS_ABS,
  93. //CTRL_FOCUS_REL,
  94. CTRL_IRIS_ABS,
  95. //CTRL_IRIS_REL,
  96. CTRL_ZOOM_ABS,
  97. //CTRL_ZOOM_REL,
  98. //CTRL_PANTILT_ABS,
  99. CTRL_PAN_ABS,
  100. CTRL_TILT_ABS,
  101. //CTRL_PANTILT_REL,
  102. //CTRL_PAN_REL,
  103. //CTRL_TILT_REL,
  104. CTRL_ROLL_ABS,
  105. //CTRL_ROLL_REL,
  106. CTRL_FOCUS_AUTO,
  107. //CTRL_PRIVACY,
  108. //CTRL_FOCUS_SIMPLE,
  109. //CTRL_WINDOW,
  110. //CTRL_ROI,
  111. };
  112. private static readonly UInt64[] SUPPORTED_PROCS =
  113. {
  114. PU_BRIGHTNESS,
  115. PU_CONTRAST,
  116. PU_HUE,
  117. PU_SATURATION,
  118. PU_SHARPNESS,
  119. PU_GAMMA,
  120. PU_WB_TEMP,
  121. PU_WB_COMPO,
  122. PU_BACKLIGHT,
  123. PU_GAIN,
  124. PU_POWER_LF,
  125. PU_HUE_AUTO,
  126. PU_WB_TEMP_AUTO,
  127. PU_WB_COMPO_AUTO,
  128. PU_DIGITAL_MULT,
  129. PU_DIGITAL_LIMIT,
  130. PU_AVIDEO_STD,
  131. PU_AVIDEO_LOCK,
  132. PU_CONTRAST_AUTO,
  133. };
  134. //测试重置接口
  135. internal static int onResize(int id, int frameType, int width, int height)
  136. {
  137. return Resize(id, frameType, width, height);
  138. }
  139. //--------------------------------------------------------------------------------
  140. /**
  141. * IUVCSelectorがセットされていないとき
  142. * またはIUVCSelectorが解像度選択時にnullを
  143. * 返したときのデフォルトの解像度(幅)
  144. */
  145. public Int32 DefaultWidth = 1280;
  146. /**
  147. * IUVCSelectorがセットされていないとき
  148. * またはIUVCSelectorが解像度選択時にnullを
  149. * 返したときのデフォルトの解像度(高さ)
  150. */
  151. public Int32 DefaultHeight = 720;
  152. /**
  153. * UVC機器とのネゴシエーション時に
  154. * H.264を優先してネゴシエーションするかどうか
  155. * Android実機のみ有効
  156. * true: H.264 > MJPEG > YUV
  157. * false: MJPEG > H.264 > YUV
  158. */
  159. public bool PreferH264 = false;
  160. /**
  161. * 可能な場合にUACから音声取得を行うかどうか
  162. */
  163. public bool UACEnabled = false;
  164. /**
  165. * シーンレンダリングの前にUVC機器映像のテクスチャへのレンダリング要求を行うかどうか
  166. */
  167. public bool RenderBeforeSceneRendering = false;
  168. /**
  169. * UVC関係のイベンドハンドラー
  170. */
  171. [SerializeField, ComponentRestriction(typeof(IUVCDrawer))]
  172. public Component[] UVCDrawers;
  173. /**
  174. * 使用中のカメラ情報を保持するホルダークラス
  175. */
  176. public class CameraInfo
  177. {
  178. internal readonly UVCDevice device;
  179. internal Texture previewTexture;
  180. internal int frameType;
  181. internal volatile Int32 activeId;
  182. private Int32 currentWidth;
  183. private Int32 currentHeight;
  184. private bool isRenderBeforeSceneRendering;
  185. private bool isRendering;
  186. private Dictionary<UInt64, UVCCtrlInfo> ctrlInfos = new Dictionary<UInt64, UVCCtrlInfo>();
  187. //PC测试用
  188. internal CameraInfo(Texture texture)
  189. {
  190. this.device = null;
  191. activeId = 1;
  192. previewTexture = texture;
  193. SetSize(texture.width, texture.height);
  194. }
  195. internal CameraInfo(UVCDevice device)
  196. {
  197. this.device = device;
  198. }
  199. /**
  200. * 機器idを取得
  201. */
  202. public Int32 Id
  203. {
  204. get { return device.id; }
  205. }
  206. /**
  207. * 機器名を取得
  208. */
  209. public string DeviceName
  210. {
  211. get { return device.name; }
  212. }
  213. /**
  214. * ベンダーIDを取得
  215. */
  216. public int Vid
  217. {
  218. get { return device.vid; }
  219. }
  220. /**
  221. * プロダクトIDを取得
  222. */
  223. public int Pid
  224. {
  225. get { return device.pid; }
  226. }
  227. /**
  228. * 映像取得中かどうか
  229. */
  230. public bool IsPreviewing
  231. {
  232. get { return (activeId != 0) && (previewTexture != null); }
  233. }
  234. /**
  235. * 現在の解像度(幅)
  236. * プレビュー中でなければ0
  237. */
  238. public Int32 CurrentWidth
  239. {
  240. get { return currentWidth; }
  241. }
  242. /**
  243. * 現在の解像度(高さ)
  244. * プレビュー中でなければ0
  245. */
  246. public Int32 CurrentHeight
  247. {
  248. get { return currentHeight; }
  249. }
  250. /**
  251. * 2024/01/19 返回一个size
  252. */
  253. public Vector2 Size => new Vector2(currentWidth, currentHeight);
  254. public Vector2Int IndexToCoord(int i)
  255. {
  256. var y = i / currentWidth;
  257. var x = i % currentWidth;
  258. return new Vector2Int(x, y);
  259. }
  260. public int CoordToIndex(int x, int y)
  261. {
  262. return y * currentWidth + x;
  263. }
  264. /**
  265. * 現在の解像度を変更
  266. * @param width
  267. * @param height
  268. */
  269. internal void SetSize(Int32 width, Int32 height)
  270. {
  271. currentWidth = width;
  272. currentHeight = height;
  273. Debug.Log("设置 SetSize:[" + width + "," + height + "]");
  274. }
  275. /**
  276. * サポートしているUVCコントロール/プロセッシング機能の情報を更新する
  277. */
  278. public void UpdateCtrls()
  279. {
  280. ctrlInfos.Clear();
  281. var ctrls = GetCtrlSupports(Id);
  282. foreach (UInt64 ctrl in SUPPORTED_CTRLS)
  283. {
  284. if ((ctrls & ctrl) == ctrl)
  285. {
  286. UVCCtrlInfo info = new UVCCtrlInfo();
  287. info.type = ctrl;
  288. if (GetCtrlInfo(Id, ref info) == 0)
  289. {
  290. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  291. Console.WriteLine($"{TAG}ctrl({ctrl:X}):={info}");
  292. #endif
  293. ctrlInfos.Add(info.type, info);
  294. }
  295. }
  296. }
  297. ctrls = GetProcSupports(Id);
  298. foreach (UInt64 ctrl in SUPPORTED_PROCS)
  299. {
  300. if ((ctrls & ctrl) == ctrl)
  301. {
  302. UVCCtrlInfo info = new UVCCtrlInfo();
  303. info.type = ctrl | PU_MASK;
  304. if (GetCtrlInfo(Id, ref info) == 0)
  305. {
  306. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  307. Console.WriteLine($"{TAG}proc({ctrl:X}):={info}");
  308. #endif
  309. ctrlInfos.Add(info.type, info);
  310. }
  311. }
  312. }
  313. }
  314. /**
  315. * 対応しているUVCコントロール/プロセッシング機能のtype一覧を取得
  316. */
  317. public List<UInt64> GetCtrls()
  318. {
  319. return new List<UInt64>(ctrlInfos.Keys);
  320. }
  321. /**
  322. * 指定したUVCコントロール/プロセッシング機能の情報を取得
  323. * @param type
  324. * @return UVCCtrlInfo
  325. * @throws ArgumentOutOfRangeException
  326. */
  327. public UVCCtrlInfo GetInfo(UInt64 type)
  328. {
  329. if (ctrlInfos.ContainsKey(type))
  330. {
  331. return ctrlInfos.GetValueOrDefault(type, new UVCCtrlInfo());
  332. }
  333. else
  334. {
  335. throw new ArgumentOutOfRangeException($"Not supported control type{type:X}");
  336. }
  337. }
  338. public UInt64 GetTypeByName(string typeName)
  339. {
  340. UInt64 type = 0;
  341. switch (typeName)
  342. {
  343. // Control Unit Cases
  344. case "CTRL_SCANNING":
  345. type = CTRL_SCANNING;
  346. break;
  347. case "CTRL_AE":
  348. type = CTRL_AE;
  349. break;
  350. case "CTRL_AE_PRIORITY":
  351. type = CTRL_AE_PRIORITY;
  352. break;
  353. case "CTRL_AE_ABS":
  354. type = CTRL_AE_ABS;
  355. break;
  356. case "CTRL_FOCUS_ABS":
  357. type = CTRL_FOCUS_ABS;
  358. break;
  359. case "CTRL_IRIS_ABS":
  360. type = CTRL_IRIS_ABS;
  361. break;
  362. case "CTRL_ZOOM_ABS":
  363. type = CTRL_ZOOM_ABS;
  364. break;
  365. case "CTRL_PAN_ABS":
  366. type = CTRL_PAN_ABS;
  367. break;
  368. case "CTRL_TILT_ABS":
  369. type = CTRL_TILT_ABS;
  370. break;
  371. case "CTRL_ROLL_ABS":
  372. type = CTRL_ROLL_ABS;
  373. break;
  374. case "CTRL_FOCUS_AUTO":
  375. type = CTRL_FOCUS_AUTO;
  376. break;
  377. // Processing Unit Cases
  378. case "PU_BRIGHTNESS":
  379. type = PU_BRIGHTNESS | PU_MASK;
  380. break;
  381. case "PU_CONTRAST":
  382. type = PU_CONTRAST | PU_MASK;
  383. break;
  384. case "PU_HUE":
  385. type = PU_HUE | PU_MASK;
  386. break;
  387. case "PU_SATURATION":
  388. type = PU_SATURATION | PU_MASK;
  389. break;
  390. case "PU_SHARPNESS":
  391. type = PU_SHARPNESS | PU_MASK;
  392. break;
  393. case "PU_GAMMA":
  394. type = PU_GAMMA | PU_MASK;
  395. break;
  396. case "PU_WB_TEMP":
  397. type = PU_WB_TEMP | PU_MASK;
  398. break;
  399. case "PU_WB_COMPO":
  400. type = PU_WB_COMPO | PU_MASK;
  401. break;
  402. case "PU_BACKLIGHT":
  403. type = PU_BACKLIGHT | PU_MASK;
  404. break;
  405. case "PU_GAIN":
  406. type = PU_GAIN | PU_MASK;
  407. break;
  408. case "PU_POWER_LF":
  409. type = PU_POWER_LF | PU_MASK;
  410. break;
  411. case "PU_HUE_AUTO":
  412. type = PU_HUE_AUTO | PU_MASK;
  413. break;
  414. case "PU_WB_TEMP_AUTO":
  415. type = PU_WB_TEMP_AUTO | PU_MASK;
  416. break;
  417. case "PU_WB_COMPO_AUTO":
  418. type = PU_WB_COMPO_AUTO | PU_MASK;
  419. break;
  420. case "PU_DIGITAL_MULT":
  421. type = PU_DIGITAL_MULT | PU_MASK;
  422. break;
  423. case "PU_DIGITAL_LIMIT":
  424. type = PU_DIGITAL_LIMIT | PU_MASK;
  425. break;
  426. case "PU_AVIDEO_STD":
  427. type = PU_AVIDEO_STD | PU_MASK;
  428. break;
  429. case "PU_AVIDEO_LOCK":
  430. type = PU_AVIDEO_LOCK | PU_MASK;
  431. break;
  432. case "PU_CONTRAST_AUTO":
  433. type = PU_CONTRAST_AUTO | PU_MASK;
  434. break;
  435. default:
  436. Console.WriteLine($"Unknown processing unit: {type}");
  437. break;
  438. }
  439. return type;
  440. }
  441. public bool ContainsKey(UInt64 type)
  442. {
  443. return ctrlInfos.ContainsKey(type);
  444. }
  445. /**
  446. * UVCコントロール/プロセッシング機能の設定値を取得
  447. * @param type
  448. * @return 変更後の値
  449. * @throws ArgumentOutOfRangeException
  450. * @throws Exception
  451. */
  452. public Int32 GetValue(UInt64 type)
  453. {
  454. if (ctrlInfos.ContainsKey(type))
  455. {
  456. Int32 value = 0;
  457. var r = GetCtrlValue(Id, type, ref value);
  458. if (r == 0)
  459. {
  460. return value;
  461. }
  462. else
  463. {
  464. throw new Exception($"Failed to get control value,type={type},err={r}");
  465. }
  466. }
  467. else
  468. {
  469. throw new ArgumentOutOfRangeException($"Not supported control type{type:X}");
  470. }
  471. }
  472. /**
  473. * UVCコントロール/プロセッシング機能の設定変更
  474. * @param type
  475. * @param value
  476. * @return 変更後の値
  477. * @throws ArgumentOutOfRangeException
  478. * @throws Exception
  479. */
  480. public Int32 SetValue(UInt64 type, Int32 value)
  481. {
  482. if (ctrlInfos.ContainsKey(type))
  483. {
  484. var r = SetCtrlValue(Id, type, value);
  485. if (r == 0)
  486. {
  487. r = GetCtrlValue(Id, type, ref value);
  488. if (r == 0)
  489. {
  490. var info = ctrlInfos.GetValueOrDefault(type, new UVCCtrlInfo());
  491. info.current = value;
  492. ctrlInfos[type] = info;
  493. return value;
  494. }
  495. else
  496. {
  497. Debug.LogError($"Failed to get control value,type={type},err={r}");
  498. }
  499. }
  500. else
  501. {
  502. Debug.LogError($"Failed to set control value,type={type},err={r}");
  503. }
  504. }
  505. else
  506. {
  507. Debug.LogError($"Not supported control type{type:X}");
  508. }
  509. return 0;
  510. }
  511. public override string ToString()
  512. {
  513. return $"{base.ToString()}({currentWidth}x{currentHeight},id={Id},activeId={activeId},IsPreviewing={IsPreviewing})";
  514. }
  515. /**
  516. * UVC機器からの映像のレンダリングを開始
  517. * @param manager
  518. */
  519. internal Coroutine StartRender(UVCManager manager, bool renderBeforeSceneRendering)
  520. {
  521. StopRender(manager);
  522. isRenderBeforeSceneRendering = renderBeforeSceneRendering;
  523. isRendering = true;
  524. if (renderBeforeSceneRendering)
  525. {
  526. return manager.StartCoroutine(OnRenderBeforeSceneRendering());
  527. }
  528. else
  529. {
  530. return manager.StartCoroutine(OnRender());
  531. }
  532. }
  533. /**
  534. * UVC機器からの映像のレンダリングを終了
  535. * @param manager
  536. */
  537. internal void StopRender(UVCManager manager)
  538. {
  539. if (isRendering)
  540. {
  541. isRendering = false;
  542. if (isRenderBeforeSceneRendering)
  543. {
  544. manager.StopCoroutine(OnRenderBeforeSceneRendering());
  545. }
  546. else
  547. {
  548. manager.StopCoroutine(OnRender());
  549. }
  550. }
  551. }
  552. /**
  553. * レンダーイベント処理用
  554. * コールーチンとして実行される
  555. * シーンレンダリングの前にUVC機器からの映像をテクスチャへレンダリング要求する
  556. */
  557. private IEnumerator OnRenderBeforeSceneRendering()
  558. {
  559. var renderEventFunc = GetRenderEventFunc();
  560. for (; activeId != 0;)
  561. {
  562. yield return null;
  563. GL.IssuePluginEvent(renderEventFunc, activeId);
  564. }
  565. yield break;
  566. }
  567. /**
  568. * レンダーイベント処理用
  569. * コールーチンとして実行される
  570. * レンダリング後にUVC機器からの映像をテクスチャへレンダリング要求する
  571. */
  572. private IEnumerator OnRender()
  573. {
  574. var renderEventFunc = GetRenderEventFunc();
  575. for (; activeId != 0;)
  576. {
  577. yield return new WaitForEndOfFrame();
  578. GL.IssuePluginEvent(renderEventFunc, activeId);
  579. }
  580. yield break;
  581. }
  582. } // CameraInfo
  583. /**
  584. * UAC機器からの音声取得に関するオブジェクトを保持するためのホルダークラス
  585. */
  586. public class AudioInfo
  587. {
  588. internal readonly UVCDevice device;
  589. private UACInfo info = new UACInfo();
  590. private int samplesPerFrame = 0;
  591. private Int16[] buffer; // 今のところPCM16にしか対応しない, OnPCM16Readないではなくここで保持するともしかするとメモリーブロックが不連続になったり移動したりするかもしれないけど
  592. private volatile AudioClip audioClip;
  593. private volatile Int32 activeId;
  594. internal AudioInfo(UVCDevice device)
  595. {
  596. this.device = device;
  597. }
  598. /**
  599. * 音声取得中かどうか
  600. */
  601. public bool IsStreaming
  602. {
  603. get { return (activeId != 0) && (audioClip != null); }
  604. }
  605. /**
  606. * 音声取得開始する
  607. * すでに音声取得中なら何もしない
  608. * @param manager
  609. */
  610. internal AudioClip Start(UVCManager manager)
  611. {
  612. var result = StartUAC(device.id);
  613. if (result == 0)
  614. {
  615. if (GetUACInfo(device.id, ref info) == 0)
  616. {
  617. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  618. Console.WriteLine($"{TAG}Start:info={info}");
  619. #endif
  620. try
  621. {
  622. // PCM16のはず
  623. activeId = device.id;
  624. samplesPerFrame = info.packetBytes / (info.resolution / 8);
  625. buffer = new Int16[samplesPerFrame];
  626. audioClip = AudioClip.Create(device.name, Int32.MaxValue, info.channels, info.samplingFreq, true, OnPCM16Read);
  627. return audioClip;
  628. }
  629. catch (Exception e)
  630. {
  631. activeId = 0;
  632. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  633. Console.WriteLine($"Failed to create audio clip,err={e}");
  634. #endif
  635. throw e;
  636. }
  637. }
  638. else
  639. {
  640. manager.StopAudio(device);
  641. throw new Exception($"Failed to get streaming info,err={result}");
  642. }
  643. }
  644. else
  645. {
  646. throw new Exception($"Failed to start uac streaming,err={result}");
  647. }
  648. }
  649. /**
  650. * 音声取得停止する
  651. * @param manager
  652. */
  653. internal void Stop(UVCManager manager)
  654. {
  655. activeId = 0;
  656. audioClip = null;
  657. manager.StopAudio(device);
  658. }
  659. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  660. private int readCnt = 0;
  661. #endif
  662. /**
  663. * AudioClipからのコールバック
  664. * @param data
  665. */
  666. private void OnPCM16Read(float[] data)
  667. {
  668. if (!IsStreaming) return;
  669. var numSamples = data.Length; // 今回読み取る最大サンプル数
  670. var maxReadCnt = numSamples / samplesPerFrame; // 最大読み込み回数
  671. if (maxReadCnt == 0)
  672. {
  673. maxReadCnt = 1;
  674. }
  675. var result = -1;
  676. Int64 ptsUs = 0;
  677. //var buffer = new Int16[samplesPerFrame]; // 高速化のためにStartでアロケーションするように変更した
  678. Int32 dataBytes = 0;
  679. Int32 totalSamples = 0;
  680. for (int i = 0; (i < maxReadCnt) && (totalSamples < numSamples); i++)
  681. {
  682. result = GetUACFrame(device.id, buffer, ref dataBytes, ref ptsUs);
  683. if ((result == 0) && (dataBytes >= 2))
  684. {
  685. var samples = Math.Min(dataBytes / 2, samplesPerFrame);
  686. for (int j = 0; j < samples; j++)
  687. {
  688. data[j + totalSamples] = buffer[j] / (float)short.MaxValue;
  689. }
  690. totalSamples += samples;
  691. }
  692. else
  693. {
  694. break;
  695. }
  696. }
  697. if (totalSamples < numSamples)
  698. {
  699. Array.Resize<float>(ref data, totalSamples);
  700. }
  701. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  702. if ((readCnt++ % 100) == 0)
  703. {
  704. Console.WriteLine($"{TAG}OnPCM16Read:len={numSamples},total={totalSamples},r={result},bytes={dataBytes},pts={ptsUs}");
  705. }
  706. #endif
  707. }
  708. } // AudioInfo
  709. /**
  710. * メインスレッド上で実行するためのSynchronizationContextインスタンス
  711. */
  712. private SynchronizationContext mainContext;
  713. /**
  714. * 端末に接続されたUVC機器の状態が変化した時のイベントコールバックを受け取るデリゲーター
  715. */
  716. private PluginCallbackManager.OnDeviceChangedFunc callback;
  717. /**
  718. * 端末に接続されたUVC機器リスト
  719. */
  720. private List<UVCDevice> attachedDevices = new List<UVCDevice>();
  721. /**
  722. * 映像取得中のUVC機器のマップ
  723. * 機器識別用のid - CameraInfoペアを保持する
  724. */
  725. private Dictionary<Int32, CameraInfo> cameraInfos = new Dictionary<int, CameraInfo>();
  726. /**
  727. * 音声取得中のUVC機器のマップ
  728. * 機器識別用のid - AudioInfoペアを保持する
  729. */
  730. private Dictionary<Int32, AudioInfo> audioInFos = new Dictionary<int, AudioInfo>();
  731. #region 额外添加的操作
  732. public bool InitUVCEnabled = true;
  733. #endregion
  734. //--------------------------------------------------------------------------------
  735. // UnityEngineからの呼び出し
  736. //--------------------------------------------------------------------------------
  737. // Start is called before the first frame update
  738. IEnumerator Start()
  739. {
  740. if (!InitUVCEnabled) yield break;
  741. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  742. Console.WriteLine($"{TAG}Start:");
  743. #endif
  744. mainContext = SynchronizationContext.Current;
  745. callback = PluginCallbackManager.Add(this);
  746. Debug.Log($"{TAG}Start:");
  747. yield return Initialize();
  748. }
  749. /// <summary>
  750. /// 调用来初始化
  751. /// </summary>
  752. /// <returns></returns>
  753. public IEnumerator startUVCManager()
  754. {
  755. yield return new WaitForSeconds(1.0f);
  756. Debug.Log("startUVCManager Start:");
  757. Debug.Log($"{TAG} startUVCManager Start:");
  758. mainContext = SynchronizationContext.Current;
  759. callback = PluginCallbackManager.Add(this);
  760. yield return Initialize();
  761. }
  762. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  763. void OnApplicationFocus()
  764. {
  765. Console.WriteLine($"{TAG}OnApplicationFocus:");
  766. }
  767. #endif
  768. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  769. void OnApplicationPause(bool pauseStatus)
  770. {
  771. Console.WriteLine($"{TAG}OnApplicationPause:{pauseStatus}");
  772. }
  773. #endif
  774. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  775. void OnApplicationQuits()
  776. {
  777. Console.WriteLine($"{TAG}OnApplicationQuits:");
  778. }
  779. #endif
  780. void OnDestroy()
  781. {
  782. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  783. Console.WriteLine($"{TAG}OnDestroy:");
  784. #endif
  785. StopAll();
  786. PluginCallbackManager.Remove(this);
  787. }
  788. //--------------------------------------------------------------------------------
  789. // UVC機器接続状態が変化したときのプラグインからのコールバック関数
  790. //--------------------------------------------------------------------------------
  791. public void OnDeviceChanged(IntPtr devicePtr, bool attached)
  792. {
  793. var id = UVCDevice.GetId(devicePtr);
  794. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  795. Console.WriteLine($"{TAG}OnDeviceChangedInternal:id={id},attached={attached}");
  796. #endif
  797. if (attached)
  798. {
  799. UVCDevice device = new UVCDevice(devicePtr);
  800. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  801. Console.WriteLine($"{TAG}OnDeviceChangedInternal:device={device.ToString()}");
  802. #endif
  803. if (HandleOnAttachEvent(device))
  804. {
  805. attachedDevices.Add(device);
  806. StartPreview(device);
  807. if (UACEnabled)
  808. { // UVCManagerのUAC機能が有効な場合
  809. StartAudio(device);
  810. }
  811. }
  812. }
  813. else
  814. {
  815. var found = attachedDevices.Find(item =>
  816. {
  817. return item != null && item.id == id;
  818. });
  819. if (found != null)
  820. {
  821. HandleOnDetachEvent(found);
  822. StopPreview(found);
  823. StopAudio(found);
  824. RemoveCamera(found);
  825. RemoveAudio(found);
  826. attachedDevices.Remove(found);
  827. }
  828. }
  829. }
  830. //================================================================================
  831. /**
  832. * 接続中のUVC機器一覧を取得
  833. * @return 接続中のUVC機器一覧List
  834. */
  835. public List<CameraInfo> GetAttachedDevices()
  836. {
  837. return new List<CameraInfo>(cameraInfos.Values);
  838. }
  839. // /**
  840. // * 対応解像度を取得
  841. // * @param camera 対応解像度を取得するUVC機器を指定
  842. // * @return 対応解像度 既にカメラが取り外されている/closeしているのであればnull
  843. // */
  844. // public SupportedFormats GetSupportedVideoSize(CameraInfo camera)
  845. // {
  846. // var info = (camera != null) ? GetCamera(camera.device) : null;
  847. // if ((info != null) && info.IsOpen)
  848. // {
  849. // return GetSupportedVideoSize(info.DeviceName);
  850. // }
  851. // else
  852. // {
  853. // return null;
  854. // }
  855. // }
  856. // /**
  857. // * 解像度を変更
  858. // * @param 解像度を変更するUVC機器を指定
  859. // * @param 変更する解像度を指定, nullならデフォルトに戻す
  860. // * @param 解像度が変更されたかどうか
  861. // */
  862. // public bool SetVideoSize(CameraInfo camera, SupportedFormats.Size size)
  863. // {
  864. // var info = (camera != null) ? GetCamera(camera.device) : null;
  865. // var width = size != null ? size.Width : DefaultWidth;
  866. // var height = size != null ? size.Height : DefaultHeight;
  867. // if ((info != null) && info.IsPreviewing)
  868. // {
  869. // if ((width != info.CurrentWidth) || (height != info.CurrentHeight))
  870. // { // 解像度が変更になるとき
  871. // StopPreview(info.DeviceName);
  872. // StartPreview(info.DeviceName, width, height);
  873. // return true;
  874. // }
  875. // }
  876. // return false;
  877. // }
  878. public void onStartUVCManager()
  879. {
  880. StartCoroutine(startUVCManager());
  881. }
  882. public void onStartPreview(UVCDevice device)
  883. {
  884. // StartPreview(device);
  885. if (HandleOnAttachEvent(device))
  886. {
  887. attachedDevices.Add(device);
  888. StartPreview(device);
  889. if (UACEnabled)
  890. { // UVCManagerのUAC機能が有効な場合
  891. StartAudio(device);
  892. }
  893. }
  894. }
  895. public void onStopPreview(UVCDevice device)
  896. {
  897. var found = attachedDevices.Find(item =>
  898. {
  899. return item != null && item.id == device.id;
  900. });
  901. if (found != null)
  902. {
  903. HandleOnDetachEvent(found);
  904. StopPreview(found);
  905. StopAudio(found);
  906. RemoveCamera(found);
  907. RemoveAudio(found);
  908. attachedDevices.Remove(found);
  909. }
  910. }
  911. private void StartPreview(UVCDevice device)
  912. {
  913. var info = CreateCameraIfNotExist(device);
  914. if ((info != null) && !info.IsPreviewing)
  915. {
  916. Debug.Log("开始渲染StartPreview DefaultWidth:" + DefaultWidth + " , DefaultHeight:" + DefaultHeight);
  917. int width = DefaultWidth;
  918. int height = DefaultHeight;
  919. Debug.Log($"{TAG}StartPreview:({width}x{height}),id={device.id}");
  920. int[] frameTypes = {
  921. PreferH264 ? FRAME_TYPE_H264 : FRAME_TYPE_MJPEG,
  922. PreferH264 ? FRAME_TYPE_MJPEG : FRAME_TYPE_H264,
  923. };
  924. foreach (var frameType in frameTypes)
  925. {
  926. if (Resize(device.id, frameType, width, height) == 0)
  927. {
  928. info.frameType = frameType;
  929. break;
  930. }
  931. }
  932. info.SetSize(width, height);
  933. info.activeId = device.id;
  934. info.UpdateCtrls();
  935. mainContext.Post(__ =>
  936. {
  937. Texture2D tex = new Texture2D(
  938. width, height,
  939. TextureFormat.ARGB32,
  940. false, /* mipmap */
  941. true /* linear */);
  942. tex.filterMode = FilterMode.Point;
  943. tex.Apply();
  944. info.previewTexture = tex;
  945. var nativeTexPtr = info.previewTexture.GetNativeTexturePtr();
  946. Debug.Log(TAG + "nativeTexPtr:"+ nativeTexPtr.ToInt32() + "[" + width + "," + height + "]");
  947. Start(device.id, nativeTexPtr.ToInt32());
  948. HandleOnStartPreviewEvent(info);
  949. info.StartRender(this, RenderBeforeSceneRendering);
  950. }, null);
  951. }
  952. }
  953. private void StopPreview(UVCDevice device)
  954. {
  955. var info = GetCamera(device);
  956. if ((info != null) && info.IsPreviewing)
  957. {
  958. mainContext.Post(__ =>
  959. {
  960. HandleOnStopPreviewEvent(info);
  961. Stop(device.id);
  962. info.StopRender(this);
  963. // Release the old texture if it exists
  964. if (info.previewTexture != null)
  965. {
  966. Destroy(info.previewTexture);
  967. info.previewTexture = null;
  968. }
  969. info.SetSize(0, 0);
  970. info.activeId = 0;
  971. }, null);
  972. }
  973. }
  974. private void StartAudio(UVCDevice device)
  975. {
  976. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  977. Console.WriteLine($"{TAG}StartAudio:");
  978. #endif
  979. if (device.isUAC)
  980. {
  981. var audio = CreateAudioIfNotExist(device);
  982. if ((audio != null) && !audio.IsStreaming)
  983. {
  984. mainContext.Post(__ =>
  985. {
  986. var audioClip = audio.Start(this);
  987. HandleOnStartAudioEvent(audio, audioClip);
  988. }, null);
  989. }
  990. }
  991. else
  992. {
  993. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  994. Console.WriteLine($"{TAG}StartAudio:Not a UAC device");
  995. #endif
  996. }
  997. }
  998. private void StopAudio(UVCDevice device)
  999. {
  1000. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1001. Console.WriteLine($"{TAG}StopAudio:");
  1002. #endif
  1003. var audio = GetAudio(device);
  1004. if (audio != null && audio.IsStreaming)
  1005. {
  1006. mainContext.Post(__ =>
  1007. {
  1008. HandleOnStopAudioEvent(audio);
  1009. audio.Stop(this);
  1010. }, null);
  1011. }
  1012. }
  1013. private void StopAll()
  1014. {
  1015. List<CameraInfo> values = new List<CameraInfo>(cameraInfos.Values);
  1016. foreach (var info in values)
  1017. {
  1018. StopAudio(info.device);
  1019. StopPreview(info.device);
  1020. Debug.Log("******StopAll:" + info.device.ToString());
  1021. }
  1022. }
  1023. //--------------------------------------------------------------------------------
  1024. /**
  1025. * UVC機器が接続されたときの処理の実体
  1026. * @param info
  1027. * @return true: 接続されたUVC機器を使用する, false: 接続されたUVC機器を使用しない
  1028. */
  1029. private bool HandleOnAttachEvent(UVCDevice device/*NonNull*/)
  1030. {
  1031. if ((UVCDrawers == null) || (UVCDrawers.Length == 0))
  1032. { // IUVCDrawerが割り当てられていないときはtrue(接続されたUVC機器を使用する)を返す
  1033. return true;
  1034. }
  1035. else
  1036. {
  1037. bool hasDrawer = false;
  1038. foreach (var drawer in UVCDrawers)
  1039. {
  1040. if (drawer is IUVCDrawer)
  1041. {
  1042. hasDrawer = true;
  1043. if ((drawer as IUVCDrawer).OnUVCAttachEvent(this, device))
  1044. { // どれか1つのIUVCDrawerがtrueを返せばtrue(接続されたUVC機器を使用する)を返す
  1045. return true;
  1046. }
  1047. }
  1048. }
  1049. // IUVCDrawerが割り当てられていないときはtrue(接続されたUVC機器を使用する)を返す
  1050. return !hasDrawer;
  1051. }
  1052. }
  1053. /**
  1054. * UVC機器が取り外されたときの処理の実体
  1055. * @param info
  1056. */
  1057. private void HandleOnDetachEvent(UVCDevice device/*NonNull*/)
  1058. {
  1059. if ((UVCDrawers != null) && (UVCDrawers.Length > 0))
  1060. {
  1061. foreach (var drawer in UVCDrawers)
  1062. {
  1063. if (drawer is IUVCDrawer)
  1064. {
  1065. (drawer as IUVCDrawer).OnUVCDetachEvent(this, device);
  1066. }
  1067. }
  1068. }
  1069. }
  1070. /**
  1071. * UVC機器からの映像取得を開始した
  1072. * @param args UVC機器の識別文字列
  1073. */
  1074. void HandleOnStartPreviewEvent(CameraInfo camera)
  1075. {
  1076. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1077. Console.WriteLine($"{TAG}HandleOnStartPreviewEvent:({camera})");
  1078. #endif
  1079. if ((camera != null) && camera.IsPreviewing && (UVCDrawers != null))
  1080. {
  1081. foreach (var drawer in UVCDrawers)
  1082. {
  1083. if ((drawer is IUVCDrawer) && (drawer as IUVCDrawer).IsUVCEnabled(this, camera.device))
  1084. {
  1085. (drawer as IUVCDrawer).OnUVCStartEvent(this, camera.device, camera.previewTexture);
  1086. }
  1087. }
  1088. }
  1089. else
  1090. {
  1091. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1092. Console.WriteLine($"{TAG}HandleOnStartPreviewEvent:No UVCDrawers");
  1093. #endif
  1094. }
  1095. }
  1096. /**
  1097. * UVC機器からの映像取得を終了した
  1098. * @param args UVC機器の識別文字列
  1099. */
  1100. void HandleOnStopPreviewEvent(CameraInfo camera)
  1101. {
  1102. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1103. Console.WriteLine($"{TAG}HandleOnStopPreviewEvent:({camera})");
  1104. #endif
  1105. if (UVCDrawers != null)
  1106. {
  1107. foreach (var drawer in UVCDrawers)
  1108. {
  1109. if ((drawer is IUVCDrawer) && (drawer as IUVCDrawer).IsUVCEnabled(this, camera.device))
  1110. {
  1111. (drawer as IUVCDrawer).OnUVCStopEvent(this, camera.device);
  1112. }
  1113. }
  1114. }
  1115. }
  1116. void HandleOnStartAudioEvent(AudioInfo audio, AudioClip audioClip)
  1117. {
  1118. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1119. Console.WriteLine($"{TAG}HandleOnStartAudioEvent:({audio})");
  1120. #endif
  1121. if ((audio != null) && audio.IsStreaming && (UVCDrawers != null))
  1122. {
  1123. foreach (var drawer in UVCDrawers)
  1124. {
  1125. if ((drawer is IUVCDrawer) && (drawer as IUVCDrawer).IsUACEnabled(this, audio.device))
  1126. { // IsUACEnabledがtrueを返したIUVCDrawerだけOnUACStartEventを呼び出す
  1127. (drawer as IUVCDrawer).OnUACStartEvent(this, audio.device, audioClip);
  1128. }
  1129. }
  1130. }
  1131. }
  1132. void HandleOnStopAudioEvent(AudioInfo audio)
  1133. {
  1134. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1135. Console.WriteLine($"{TAG}HandleOnStopAudioEvent:({audio})");
  1136. #endif
  1137. if (UVCDrawers != null)
  1138. {
  1139. foreach (var drawer in UVCDrawers)
  1140. {
  1141. if ((drawer is IUVCDrawer) && (drawer as IUVCDrawer).IsUACEnabled(this, audio.device))
  1142. { // IsUACEnabledがtrueを返したIUVCDrawerだけOnUACStopEventを呼び出す
  1143. (drawer as IUVCDrawer).OnUACStopEvent(this, audio.device);
  1144. }
  1145. }
  1146. }
  1147. }
  1148. //--------------------------------------------------------------------------------
  1149. /**
  1150. * 指定したUVC識別文字列に対応するCameraInfoを取得する
  1151. * まだ登録させていなければ新規作成する
  1152. * @param deviceName UVC機器識別文字列
  1153. * @param CameraInfoを返す
  1154. */
  1155. /*NonNull*/
  1156. private CameraInfo CreateCameraIfNotExist(UVCDevice device)
  1157. {
  1158. if (!cameraInfos.ContainsKey(device.id))
  1159. {
  1160. cameraInfos[device.id] = new CameraInfo(device);
  1161. }
  1162. return cameraInfos[device.id];
  1163. }
  1164. /**
  1165. * 指定したUVC識別文字列に対応するCameraInfoを取得する
  1166. * @param device
  1167. * @param 登録してあればCameraInfoを返す、登録されていなければnull
  1168. */
  1169. /*Nullable*/
  1170. private CameraInfo GetCamera(UVCDevice device)
  1171. {
  1172. return cameraInfos.ContainsKey(device.id) ? cameraInfos[device.id] : null;
  1173. }
  1174. /**
  1175. * 指定したUVCDeviceに対応するCameraInfoを削除する
  1176. * @param device
  1177. * @param 対応するAudioInfoまたはnull
  1178. */
  1179. private CameraInfo RemoveCamera(UVCDevice device)
  1180. {
  1181. var result = GetCamera(device);
  1182. cameraInfos.Remove(device.id);
  1183. return result;
  1184. }
  1185. /**
  1186. * 指定したUVC識別文字列に対応するCameraInfoを取得する
  1187. * まだ登録させていなければ新規作成する
  1188. * @param deviceName UVC機器識別文字列
  1189. * @param CameraInfoを返す
  1190. */
  1191. /*NonNull*/
  1192. private AudioInfo CreateAudioIfNotExist(UVCDevice device)
  1193. {
  1194. if (!audioInFos.ContainsKey(device.id))
  1195. {
  1196. audioInFos[device.id] = new AudioInfo(device);
  1197. }
  1198. return audioInFos[device.id];
  1199. }
  1200. /**
  1201. * 指定したUVCDeviceに対応するAudioInfoを取得する
  1202. * @param device
  1203. * @param 登録してあればAudioInfoを返す、登録されていなければnull
  1204. */
  1205. /*Nullable*/
  1206. private AudioInfo GetAudio(UVCDevice device)
  1207. {
  1208. return audioInFos.ContainsKey(device.id) ? audioInFos[device.id] : null;
  1209. }
  1210. /**
  1211. * 指定したUVCDeviceに対応するAudioInfoを削除する
  1212. * @param device
  1213. * @param 対応するAudioInfoまたはnull
  1214. */
  1215. private AudioInfo RemoveAudio(UVCDevice device)
  1216. {
  1217. var result = GetAudio(device);
  1218. audioInFos.Remove(device.id);
  1219. return result;
  1220. }
  1221. //--------------------------------------------------------------------------------
  1222. /**
  1223. * プラグインを初期化
  1224. * パーミッションの確認を行って取得できれば実際のプラグイン初期化処理#InitPluginを呼び出す
  1225. */
  1226. private IEnumerator Initialize()
  1227. {
  1228. #if UNITY_ANDROID
  1229. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1230. Console.WriteLine($"{TAG}Initialize:");
  1231. #endif
  1232. if (AndroidUtils.CheckAndroidVersion(28))
  1233. {
  1234. yield return AndroidUtils.GrantCameraPermission((string permission, AndroidUtils.PermissionGrantResult result) =>
  1235. {
  1236. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1237. Console.WriteLine($"{TAG}OnPermission:{permission}={result}");
  1238. #endif
  1239. switch (result)
  1240. {
  1241. case AndroidUtils.PermissionGrantResult.PERMISSION_GRANT:
  1242. InitPlugin();
  1243. break;
  1244. case AndroidUtils.PermissionGrantResult.PERMISSION_DENY:
  1245. if (AndroidUtils.ShouldShowRequestPermissionRationale(AndroidUtils.PERMISSION_CAMERA))
  1246. {
  1247. // パーミッションを取得できなかった
  1248. // FIXME 説明用のダイアログ等を表示しないといけない
  1249. Debug.LogWarning($"{TAG}OnPermission:PERMISSION_DENY,没有办法获取权限");
  1250. }
  1251. break;
  1252. case AndroidUtils.PermissionGrantResult.PERMISSION_DENY_AND_NEVER_ASK_AGAIN:
  1253. Debug.Log($"{TAG} 2222222222222222222222222222");
  1254. break;
  1255. }
  1256. });
  1257. }
  1258. else
  1259. {
  1260. Debug.Log($"{TAG}OnPermission:CheckAndroidVersion(28) = false");
  1261. InitPlugin();
  1262. }
  1263. yield break;
  1264. #endif
  1265. #if UNITY_STANDALONE_WIN
  1266. yield break;
  1267. #endif
  1268. }
  1269. /**
  1270. * プラグインを初期化
  1271. * uvc-plugin-unityへの処理要求
  1272. */
  1273. private void InitPlugin()
  1274. {
  1275. #if UNITY_ANDROID
  1276. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1277. Console.WriteLine($"{TAG}InitPlugin:");
  1278. #endif
  1279. // IUVCDrawersが割り当てられているかどうかをチェック
  1280. var hasDrawer = false;
  1281. if ((UVCDrawers != null) && (UVCDrawers.Length > 0))
  1282. {
  1283. foreach (var drawer in UVCDrawers)
  1284. {
  1285. if (drawer is IUVCDrawer)
  1286. {
  1287. hasDrawer = true;
  1288. break;
  1289. }
  1290. }
  1291. }
  1292. if (!hasDrawer)
  1293. { // インスペクタでIUVCDrawerが設定されていないときは
  1294. // このスクリプトがaddされているゲームオブジェクトからの取得を試みる
  1295. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1296. Console.WriteLine($"{TAG}InitPlugin:has no IUVCDrawer, try to get from gameObject");
  1297. #endif
  1298. var drawers = GetComponents(typeof(IUVCDrawer));
  1299. if ((drawers != null) && (drawers.Length > 0))
  1300. {
  1301. UVCDrawers = new Component[drawers.Length];
  1302. int i = 0;
  1303. foreach (var drawer in drawers)
  1304. {
  1305. UVCDrawers[i++] = drawer;
  1306. }
  1307. }
  1308. }
  1309. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1310. Console.WriteLine($"{TAG}InitPlugin:num drawers={UVCDrawers.Length}");
  1311. #endif
  1312. // aandusbのDeviceDetectorを読み込み要求
  1313. using (AndroidJavaClass clazz = new AndroidJavaClass(FQCN_DETECTOR))
  1314. {
  1315. clazz.CallStatic("initUVCDeviceDetector",
  1316. AndroidUtils.GetCurrentActivity());
  1317. }
  1318. #endif
  1319. }
  1320. //--------------------------------------------------------------------------------
  1321. // ネイティブプラグイン関係の定義・宣言
  1322. //--------------------------------------------------------------------------------
  1323. /**
  1324. * プラグインでのレンダーイベント取得用native(c/c++)関数
  1325. */
  1326. [DllImport("unityuvcplugin")]
  1327. private static extern IntPtr GetRenderEventFunc();
  1328. /**
  1329. * 初期設定
  1330. */
  1331. [DllImport("unityuvcplugin", EntryPoint = "Config")]
  1332. private static extern Int32 Config(Int32 deviceId, Int32 enabled, Int32 useFirstConfig);
  1333. /**
  1334. * 映像取得開始
  1335. */
  1336. [DllImport("unityuvcplugin", EntryPoint = "Start")]
  1337. private static extern Int32 Start(Int32 deviceId, Int32 tex);
  1338. /**
  1339. * 映像取得終了
  1340. */
  1341. [DllImport("unityuvcplugin", EntryPoint = "Stop")]
  1342. private static extern Int32 Stop(Int32 deviceId);
  1343. /**
  1344. * 映像サイズ設定
  1345. */
  1346. [DllImport("unityuvcplugin")]
  1347. private static extern Int32 Resize(Int32 deviceId, Int32 frameType, Int32 width, Int32 height);
  1348. /**
  1349. * 対応するUVCコントロール機能マスクを取得
  1350. */
  1351. [DllImport("unityuvcplugin")]
  1352. private static extern UInt64 GetCtrlSupports(Int32 deviceId);
  1353. /**
  1354. * 対応するUVCプロセッシング機能マスクを取得
  1355. */
  1356. [DllImport("unityuvcplugin")]
  1357. private static extern UInt64 GetProcSupports(Int32 deviceId);
  1358. /**
  1359. * 対応するUVCコントロール/プロセッシング機能情報を取得
  1360. */
  1361. [DllImport("unityuvcplugin", CallingConvention = CallingConvention.StdCall)]
  1362. private static extern Int32 GetCtrlInfo(Int32 deviceId, ref UVCCtrlInfo info);
  1363. /**
  1364. * 対応するUVCコントロール/プロセッシング機能設定値を取得
  1365. */
  1366. [DllImport("unityuvcplugin")]
  1367. private static extern Int32 GetCtrlValue(Int32 deviceId, UInt64 ctrl, ref Int32 value);
  1368. /**
  1369. * 対応するUVCコントロール/プロセッシング機能設定値を設定
  1370. */
  1371. [DllImport("unityuvcplugin")]
  1372. private static extern Int32 SetCtrlValue(Int32 deviceId, UInt64 ctrl, Int32 value);
  1373. /**
  1374. * UACからの音声取得開始
  1375. */
  1376. [DllImport("unityuvcplugin")]
  1377. private static extern Int32 StartUAC(Int32 deviceId);
  1378. /**
  1379. * UACからの音声取得終了
  1380. */
  1381. [DllImport("unityuvcplugin")]
  1382. private static extern Int32 StopUAC(Int32 deviceId);
  1383. /**
  1384. * 対応するUVCコントロール/プロセッシング機能情報を取得
  1385. */
  1386. [DllImport("unityuvcplugin", CallingConvention = CallingConvention.StdCall)]
  1387. private static extern Int32 GetUACInfo(Int32 deviceId, ref UACInfo info);
  1388. /**
  1389. * UACからの音声データを取得(呼び出し元スレッドを最大で500ミリ秒ブロックする)
  1390. */
  1391. [DllImport("unityuvcplugin", CallingConvention = CallingConvention.StdCall)]
  1392. private static extern Int32 GetUACFrame(Int32 deviceId, short[] data, ref Int32 dataLen, ref Int64 ptsUs);
  1393. } // UVCManager
  1394. /**
  1395. * IL2Cppだとc/c++からのコールバックにつかうデリゲーターをマーシャリングできないので
  1396. * staticなクラス・関数で処理をしないといけない。
  1397. * だだしそれだと呼び出し元のオブジェクトの関数を呼び出せないのでマネージャークラスを作成
  1398. * とりあえずはUVCManagerだけを受け付けるのでインターフェースにはしていない
  1399. */
  1400. public static class PluginCallbackManager
  1401. {
  1402. //コールバック関数の型を宣言
  1403. [UnmanagedFunctionPointer(CallingConvention.StdCall)]
  1404. public delegate void OnDeviceChangedFunc(Int32 id, IntPtr devicePtr, bool attached);
  1405. /**
  1406. * プラグインのnative側登録関数
  1407. */
  1408. [DllImport("unityuvcplugin")]
  1409. private static extern IntPtr Register(Int32 id, OnDeviceChangedFunc deviceChanged);
  1410. /**
  1411. * プラグインのnative側登録解除関数
  1412. */
  1413. [DllImport("unityuvcplugin")]
  1414. private static extern IntPtr Unregister(Int32 id);
  1415. private static Dictionary<Int32, UVCManager> sManagers = new Dictionary<Int32, UVCManager>();
  1416. /**
  1417. * 指定したUVCManagerを接続機器変化コールバックに追加
  1418. */
  1419. public static OnDeviceChangedFunc Add(UVCManager manager)
  1420. {
  1421. Int32 id = manager.GetHashCode();
  1422. OnDeviceChangedFunc onDeviceChanged = new OnDeviceChangedFunc(OnDeviceChanged);
  1423. sManagers.Add(id, manager);
  1424. Register(id, onDeviceChanged);
  1425. return onDeviceChanged;
  1426. }
  1427. /**
  1428. * 指定したUVCManagerを接続機器変化コールバックから削除
  1429. */
  1430. public static void Remove(UVCManager manager)
  1431. {
  1432. Int32 id = manager.GetHashCode();
  1433. Unregister(id);
  1434. sManagers.Remove(id);
  1435. }
  1436. [MonoPInvokeCallback(typeof(OnDeviceChangedFunc))]
  1437. public static void OnDeviceChanged(Int32 id, IntPtr devicePtr, bool attached)
  1438. {
  1439. var manager = sManagers.ContainsKey(id) ? sManagers[id] : null;
  1440. if (manager != null)
  1441. {
  1442. manager.OnDeviceChanged(devicePtr, attached);
  1443. }
  1444. }
  1445. } // PluginCallbackManager
  1446. } // namespace Serenegiant.UVC