UVCManager.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  1. #define ENABLE_LOG
  2. /*
  3. * Copyright (c) 2014 - 2022 t_saki@serenegiant.com
  4. */
  5. using AOT;
  6. using System;
  7. using System.Collections;
  8. using System.Collections.Generic;
  9. using System.Runtime.InteropServices;
  10. using System.Threading;
  11. using UnityEngine;
  12. #if UNITY_ANDROID && UNITY_2018_3_OR_NEWER
  13. using UnityEngine.Android;
  14. #endif
  15. namespace Serenegiant.UVC
  16. {
  17. [RequireComponent(typeof(AndroidUtils))]
  18. public class UVCManager : MonoBehaviour
  19. {
  20. private const string TAG = "UVCManager#";
  21. private const string FQCN_DETECTOR = "com.serenegiant.usb.DeviceDetectorFragment";
  22. private const int FRAME_TYPE_MJPEG = 0x000007;
  23. private const int FRAME_TYPE_H264 = 0x000014;
  24. private const int FRAME_TYPE_H264_FRAME = 0x030011;
  25. /**
  26. * 未设置IUVCSElector时
  27. * 或IUVCSElector在选择分辨率时为空
  28. * 返回时的默认分辨率(宽度)
  29. */
  30. public Int32 DefaultWidth = 1280;
  31. /**
  32. * 未设置IUVCSElector时
  33. * 或IUVCSElector在选择分辨率时为空
  34. * 返回时的默认分辨率(高度)
  35. */
  36. public Int32 DefaultHeight = 720;
  37. /**
  38. * *与UVC设备协商时
  39. * H.264是否优先协商
  40. * 仅安卓实机有效
  41. * true: H.264 > MJPEG > YUV
  42. * false: MJPEG > H.264 > YUV
  43. */
  44. public bool PreferH264 = false;
  45. /**
  46. * 是否在场景渲染之前请求对UVC设备视频纹理进行渲染
  47. */
  48. public bool RenderBeforeSceneRendering = false;
  49. /**
  50. * UVC关系的处理程序
  51. */
  52. [SerializeField, ComponentRestriction(typeof(IUVCDrawer))]
  53. public Component[] UVCDrawers;
  54. /**
  55. * 保持正在使用的相机信息的保持架类
  56. */
  57. public class CameraInfo
  58. {
  59. internal readonly UVCDevice device;
  60. internal Texture previewTexture;
  61. internal int frameType;
  62. internal Int32 activeId;
  63. private Int32 currentWidth;
  64. private Int32 currentHeight;
  65. private bool isRenderBeforeSceneRendering;
  66. private bool isRendering;
  67. //PC测试用
  68. internal CameraInfo(Texture texture)
  69. {
  70. this.device = null;
  71. activeId = 1;
  72. previewTexture = texture;
  73. SetSize(texture.width, texture.height);
  74. }
  75. internal CameraInfo(UVCDevice device)
  76. {
  77. this.device = device;
  78. }
  79. /**
  80. * 获取设备id
  81. */
  82. public Int32 Id{
  83. get { return device.id; }
  84. }
  85. /**
  86. * 获取设备名称
  87. */
  88. public string DeviceName
  89. {
  90. get { return device.name; }
  91. }
  92. /**
  93. * 获取供应商标识
  94. */
  95. public int Vid
  96. {
  97. get { return device.vid; }
  98. }
  99. /**
  100. * 获取产品标识
  101. */
  102. public int Pid
  103. {
  104. get { return device.pid; }
  105. }
  106. /**
  107. * 是否正在获取视频
  108. */
  109. public bool IsPreviewing
  110. {
  111. get { return (activeId != 0) && (previewTexture != null); }
  112. }
  113. /**
  114. * Current resolution
  115. * 如果不是预览中0
  116. */
  117. public Int32 CurrentWidth
  118. {
  119. get { return currentWidth; }
  120. }
  121. /**
  122. * 当前分辨率(高度)
  123. * 如果不是预览中0
  124. */
  125. public Int32 CurrentHeight
  126. {
  127. get { return currentHeight; }
  128. }
  129. /**
  130. * 2024/01/19 返回一个size
  131. */
  132. public Vector2 Size => new Vector2(currentWidth, currentHeight);
  133. /**
  134. * 更改当前分辨率
  135. * @param width
  136. * @param height
  137. */
  138. internal void SetSize(Int32 width, Int32 height)
  139. {
  140. currentWidth = width;
  141. currentHeight = height;
  142. }
  143. public Vector2Int IndexToCoord(int i)
  144. {
  145. var y = i / currentWidth;
  146. var x = i % currentWidth;
  147. return new Vector2Int(x, y);
  148. }
  149. public int CoordToIndex(int x, int y)
  150. {
  151. return y * currentWidth + x;
  152. }
  153. public override string ToString()
  154. {
  155. return $"{base.ToString()}({currentWidth}x{currentHeight},id={Id},activeId={activeId},IsPreviewing={IsPreviewing})";
  156. }
  157. /**
  158. * 开始从UVC设备渲染视频
  159. * @param manager
  160. */
  161. internal Coroutine StartRender(UVCManager manager, bool renderBeforeSceneRendering)
  162. {
  163. StopRender(manager);
  164. isRenderBeforeSceneRendering = renderBeforeSceneRendering;
  165. isRendering = true;
  166. if (renderBeforeSceneRendering)
  167. {
  168. return manager.StartCoroutine(OnRenderBeforeSceneRendering());
  169. } else
  170. {
  171. return manager.StartCoroutine(OnRender());
  172. }
  173. }
  174. /**
  175. * 完成UVC设备的视频渲染
  176. * @param manager
  177. */
  178. internal void StopRender(UVCManager manager)
  179. {
  180. if (isRendering)
  181. {
  182. isRendering = false;
  183. if (isRenderBeforeSceneRendering)
  184. {
  185. manager.StopCoroutine(OnRenderBeforeSceneRendering());
  186. }
  187. else
  188. {
  189. manager.StopCoroutine(OnRender());
  190. }
  191. }
  192. }
  193. /**
  194. * 用于渲染事件处理
  195. * 作为代码例程执行
  196. * 在场景渲染之前,请求将UVC设备的视频渲染到纹理
  197. */
  198. private IEnumerator OnRenderBeforeSceneRendering()
  199. {
  200. var renderEventFunc = GetRenderEventFunc();
  201. for (; activeId != 0;)
  202. {
  203. yield return null;
  204. GL.IssuePluginEvent(renderEventFunc, activeId);
  205. }
  206. yield break;
  207. }
  208. /**
  209. * 用于渲染事件处理
  210. * 作为代码例程执行
  211. * 渲染后请求将UVC设备的视频渲染到纹理
  212. */
  213. private IEnumerator OnRender()
  214. {
  215. var renderEventFunc = GetRenderEventFunc();
  216. for (; activeId != 0;)
  217. {
  218. yield return new WaitForEndOfFrame();
  219. GL.IssuePluginEvent(renderEventFunc, activeId);
  220. }
  221. yield break;
  222. }
  223. }
  224. /**
  225. * 用于在主线程上运行的同步上下文实例
  226. */
  227. private SynchronizationContext mainContext;
  228. /**
  229. * 当连接到终端的UVC设备的状态发生变化时,接受事件回调的分配器
  230. */
  231. private OnDeviceChangedCallbackManager.OnDeviceChangedFunc callback;
  232. /**
  233. * 连接到终端的UVC设备列表
  234. */
  235. private List<UVCDevice> attachedDevices = new List<UVCDevice>();
  236. /**
  237. * 正在获取视频的UVC设备的地图
  238. * 保留设备标识的id-CameraInfo对
  239. */
  240. private Dictionary<Int32, CameraInfo> cameraInfos = new Dictionary<int, CameraInfo>();
  241. //--------------------------------------------------------------------------------
  242. // 从UnityEngine调用
  243. //--------------------------------------------------------------------------------
  244. // Start is called before the first frame update
  245. IEnumerator Start()
  246. {
  247. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  248. Console.WriteLine($"{TAG}Start:");
  249. #endif
  250. mainContext = SynchronizationContext.Current;
  251. callback = OnDeviceChangedCallbackManager.Add(this);
  252. yield return Initialize();
  253. }
  254. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  255. void OnApplicationFocus()
  256. {
  257. Console.WriteLine($"{TAG}OnApplicationFocus:");
  258. }
  259. #endif
  260. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  261. void OnApplicationPause(bool pauseStatus)
  262. {
  263. Console.WriteLine($"{TAG}OnApplicationPause:{pauseStatus}");
  264. }
  265. #endif
  266. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  267. void OnApplicationQuits()
  268. {
  269. Console.WriteLine($"{TAG}OnApplicationQuits:");
  270. }
  271. #endif
  272. void OnDestroy()
  273. {
  274. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  275. Console.WriteLine($"{TAG}OnDestroy:");
  276. #endif
  277. StopAll();
  278. OnDeviceChangedCallbackManager.Remove(this);
  279. }
  280. //--------------------------------------------------------------------------------
  281. // UVC设备连接状态变化时插件的回调函数
  282. //--------------------------------------------------------------------------------
  283. public void OnDeviceChanged(IntPtr devicePtr, bool attached)
  284. {
  285. var id = UVCDevice.GetId(devicePtr);
  286. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  287. Console.WriteLine($"{TAG}OnDeviceChangedInternal:id={id},attached={attached}");
  288. #endif
  289. if (attached)
  290. {
  291. UVCDevice device = new UVCDevice(devicePtr);
  292. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  293. Console.WriteLine($"{TAG}OnDeviceChangedInternal:device={device.ToString()}");
  294. #endif
  295. if (HandleOnAttachEvent(device))
  296. {
  297. attachedDevices.Add(device);
  298. StartPreview(device);
  299. }
  300. }
  301. else
  302. {
  303. var found = attachedDevices.Find(item =>
  304. {
  305. return item != null && item.id == id;
  306. });
  307. if (found != null)
  308. {
  309. HandleOnDetachEvent(found);
  310. StopPreview(found);
  311. attachedDevices.Remove(found);
  312. }
  313. }
  314. }
  315. //================================================================================
  316. /**
  317. * 获取正在连接的UVC设备列表
  318. * @return 连接中的UVC机器一览表List
  319. */
  320. public List<CameraInfo> GetAttachedDevices()
  321. {
  322. var result = new List<CameraInfo>(cameraInfos.Count);
  323. foreach (var info in cameraInfos.Values)
  324. {
  325. result.Add(info);
  326. }
  327. return result;
  328. }
  329. // /**
  330. // * 获取对应分辨率
  331. // * @param camera 指定获取对应分辨率的UVC设备
  332. // * @return 如果对应分辨率已经拆除/关闭相机,则为空
  333. // */
  334. // public SupportedFormats GetSupportedVideoSize(CameraInfo camera)
  335. // {
  336. // var info = (camera != null) ? Get(camera.DeviceName) : null;
  337. // if ((info != null) && info.IsOpen)
  338. // {
  339. // return GetSupportedVideoSize(info.DeviceName);
  340. // }
  341. // else
  342. // {
  343. // return null;
  344. // }
  345. // }
  346. // /**
  347. // * 更改分辨率
  348. // * @param 指定要更改分辨率的UVC设备
  349. // * @param 指定要更改的分辨率,如果为空,则返回默认值
  350. // * @param 分辨率是否已更改
  351. // */
  352. // public bool SetVideoSize(CameraInfo camera, SupportedFormats.Size size)
  353. // {
  354. // var info = (camera != null) ? Get(camera.DeviceName) : null;
  355. // var width = size != null ? size.Width : DefaultWidth;
  356. // var height = size != null ? size.Height : DefaultHeight;
  357. // if ((info != null) && info.IsPreviewing)
  358. // {
  359. // if ((width != info.CurrentWidth) || (height != info.CurrentHeight))
  360. // { // 分辨率变更时
  361. // StopPreview(info.DeviceName);
  362. // StartPreview(info.DeviceName, width, height);
  363. // return true;
  364. // }
  365. // }
  366. // return false;
  367. // }
  368. private void StartPreview(UVCDevice device)
  369. {
  370. var info = CreateIfNotExist(device);
  371. if ((info != null) && !info.IsPreviewing) {
  372. int width = DefaultWidth;
  373. int height = DefaultHeight;
  374. // var supportedVideoSize = GetSupportedVideoSize(deviceName);
  375. // if (supportedVideoSize == null)
  376. // {
  377. // throw new ArgumentException("fauled to get supported video size");
  378. // }
  379. // // 选择分辨率
  380. // if ((UVCDrawers != null) && (UVCDrawers.Length > 0))
  381. // {
  382. // foreach (var drawer in UVCDrawers)
  383. // {
  384. // if ((drawer is IUVCDrawer) && ((drawer as IUVCDrawer).CanDraw(this, info.device)))
  385. // {
  386. // var size = (drawer as IUVCDrawer).OnUVCSelectSize(this, info.device, supportedVideoSize);
  387. //#if (!NDEBUG && DEBUG && ENABLE_LOG)
  388. // Console.WriteLine($"{TAG}StartPreview:selected={size}");
  389. //#endif
  390. // if (size != null)
  391. // { // 如果第一个发现的可绘制IUVCdrawers返回非空值,则使用它
  392. // width = size.Width;
  393. // height = size.Height;
  394. // break;
  395. // }
  396. // }
  397. // }
  398. // }
  399. // FIXME对应分辨率の确认处理
  400. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  401. Console.WriteLine($"{TAG}StartPreview:({width}x{height}),id={device.id}");
  402. #endif
  403. int[] frameTypes = {
  404. PreferH264 ? FRAME_TYPE_H264 : FRAME_TYPE_MJPEG,
  405. PreferH264 ? FRAME_TYPE_MJPEG : FRAME_TYPE_H264,
  406. };
  407. foreach (var frameType in frameTypes)
  408. {
  409. if (Resize(device.id, frameType, width, height) == 0)
  410. {
  411. info.frameType = frameType;
  412. break;
  413. }
  414. }
  415. info.SetSize(width, height);
  416. info.activeId = device.id;
  417. mainContext.Post(__ =>
  418. { // 必须在主线程上生成纹理
  419. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  420. Console.WriteLine($"{TAG}影像接收用纹理生成:({width}x{height})");
  421. #endif
  422. Texture2D tex = new Texture2D(
  423. width, height,
  424. TextureFormat.ARGB32,
  425. false, /* mipmap */
  426. true /* linear */);
  427. tex.filterMode = FilterMode.Point;
  428. tex.Apply();
  429. info.previewTexture = tex;
  430. var nativeTexPtr = info.previewTexture.GetNativeTexturePtr();
  431. Start(device.id, nativeTexPtr.ToInt32());
  432. HandleOnStartPreviewEvent(info);
  433. info.StartRender(this, RenderBeforeSceneRendering);
  434. }, null);
  435. }
  436. }
  437. private void StopPreview(UVCDevice device) {
  438. var info = Get(device);
  439. if ((info != null) && info.IsPreviewing)
  440. {
  441. mainContext.Post(__ =>
  442. {
  443. HandleOnStopPreviewEvent(info);
  444. Stop(device.id);
  445. info.StopRender(this);
  446. info.SetSize(0, 0);
  447. info.activeId = 0;
  448. }, null);
  449. }
  450. }
  451. private void StopAll() {
  452. List<CameraInfo> values = new List<CameraInfo>(cameraInfos.Values);
  453. foreach (var info in values)
  454. {
  455. StopPreview(info.device);
  456. }
  457. }
  458. //--------------------------------------------------------------------------------
  459. /**
  460. * 连接UVC设备时的处理实体
  461. * @param info
  462. * @return true: 使用连接的UVC设备, false: 不使用连接的UVC设备
  463. */
  464. private bool HandleOnAttachEvent(UVCDevice device/*NonNull*/)
  465. {
  466. if ((UVCDrawers == null) || (UVCDrawers.Length == 0))
  467. { // 如果未分配IUVCdrawer,则返回真(使用连接的UVC设备)
  468. return true;
  469. }
  470. else
  471. {
  472. bool hasDrawer = false;
  473. foreach (var drawer in UVCDrawers)
  474. {
  475. if (drawer is IUVCDrawer)
  476. {
  477. hasDrawer = true;
  478. if ((drawer as IUVCDrawer).OnUVCAttachEvent(this, device))
  479. { // 如果其中一个IUVCdrawer返回真,则返回真(使用连接的UVC设备)
  480. return true;
  481. }
  482. }
  483. }
  484. // 如果未分配IUVCdrawer,则返回真(使用连接的UVC设备)
  485. return !hasDrawer;
  486. }
  487. }
  488. /**
  489. * UVC设备被拆除时的处理实体
  490. * @param info
  491. */
  492. private void HandleOnDetachEvent(UVCDevice device/*NonNull*/)
  493. {
  494. if ((UVCDrawers != null) && (UVCDrawers.Length > 0))
  495. {
  496. foreach (var drawer in UVCDrawers)
  497. {
  498. if (drawer is IUVCDrawer)
  499. {
  500. (drawer as IUVCDrawer).OnUVCDetachEvent(this, device);
  501. }
  502. }
  503. }
  504. }
  505. /**
  506. * 从UVC机器的影像取得结束
  507. * @param args UVC设备识别字符串
  508. */
  509. void HandleOnStartPreviewEvent(CameraInfo info)
  510. {
  511. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  512. Console.WriteLine($"{TAG}HandleOnStartPreviewEvent:({info})");
  513. #endif
  514. if ((info != null) && info.IsPreviewing && (UVCDrawers != null))
  515. {
  516. foreach (var drawer in UVCDrawers)
  517. {
  518. if ((drawer is IUVCDrawer) && (drawer as IUVCDrawer).CanDraw(this, info.device))
  519. {
  520. (drawer as IUVCDrawer).OnUVCStartEvent(this, info.device, info.previewTexture);
  521. }
  522. }
  523. } else {
  524. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  525. Console.WriteLine($"{TAG}HandleOnStartPreviewEvent:No UVCDrawers");
  526. #endif
  527. }
  528. }
  529. /**
  530. * 从UVC机器的影像取得结束
  531. * @param args UVC设备识别字符串
  532. */
  533. void HandleOnStopPreviewEvent(CameraInfo info)
  534. {
  535. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  536. Console.WriteLine($"{TAG}HandleOnStopPreviewEvent:({info})");
  537. #endif
  538. if (UVCDrawers != null)
  539. {
  540. foreach (var drawer in UVCDrawers)
  541. {
  542. if ((drawer is IUVCDrawer) && (drawer as IUVCDrawer).CanDraw(this, info.device))
  543. {
  544. (drawer as IUVCDrawer).OnUVCStopEvent(this, info.device);
  545. }
  546. }
  547. }
  548. }
  549. //--------------------------------------------------------------------------------
  550. /**
  551. * 获取与指定UVC标识字符串相对应的CameraInfo
  552. * 如果尚未注册,则新建
  553. * @param deviceName UVC机器识别文字列
  554. * @param 返回相机信息
  555. */
  556. /*NonNull*/
  557. private CameraInfo CreateIfNotExist(UVCDevice device)
  558. {
  559. if (!cameraInfos.ContainsKey(device.id))
  560. {
  561. cameraInfos[device.id] = new CameraInfo(device);
  562. }
  563. return cameraInfos[device.id];
  564. }
  565. /**
  566. * 获取与指定UVC标识字符串相对应的CameraInfo
  567. * @param deviceName UVC机器识别文字列
  568. * @param 注册时返回CameraInfo,未注册时为空
  569. */
  570. /*Nullable*/
  571. private CameraInfo Get(UVCDevice device)
  572. {
  573. return cameraInfos.ContainsKey(device.id) ? cameraInfos[device.id] : null;
  574. }
  575. //--------------------------------------------------------------------------------
  576. /**
  577. *初始化插件
  578. *如果确认并获取权限,则调用实际的插件初始化处理#InitPlugin
  579. */
  580. private IEnumerator Initialize()
  581. {
  582. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  583. Console.WriteLine($"{TAG}Initialize:");
  584. #endif
  585. if (AndroidUtils.CheckAndroidVersion(28))
  586. {
  587. yield return AndroidUtils.GrantCameraPermission((string permission, AndroidUtils.PermissionGrantResult result) =>
  588. {
  589. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  590. Console.WriteLine($"{TAG}OnPermission:{permission}={result}");
  591. #endif
  592. switch (result)
  593. {
  594. case AndroidUtils.PermissionGrantResult.PERMISSION_GRANT:
  595. InitPlugin();
  596. break;
  597. case AndroidUtils.PermissionGrantResult.PERMISSION_DENY:
  598. if (AndroidUtils.ShouldShowRequestPermissionRationale(AndroidUtils.PERMISSION_CAMERA))
  599. {
  600. //无法获得权限
  601. //必须显示FIXME说明用的对话框等
  602. }
  603. break;
  604. case AndroidUtils.PermissionGrantResult.PERMISSION_DENY_AND_NEVER_ASK_AGAIN:
  605. break;
  606. }
  607. });
  608. }
  609. else
  610. {
  611. InitPlugin();
  612. }
  613. yield break;
  614. }
  615. /**
  616. * 初始化插件
  617. * 对uvc-plugin-unity的处理请求
  618. */
  619. private void InitPlugin()
  620. {
  621. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  622. Console.WriteLine($"{TAG}InitPlugin:");
  623. #endif
  624. // 检查是否分配了IUVCdrawers
  625. var hasDrawer = false;
  626. if ((UVCDrawers != null) && (UVCDrawers.Length > 0))
  627. {
  628. foreach (var drawer in UVCDrawers)
  629. {
  630. if (drawer is IUVCDrawer)
  631. {
  632. hasDrawer = true;
  633. break;
  634. }
  635. }
  636. }
  637. if (!hasDrawer)
  638. {
  639. //在检查器中未设置IUVCdrawer时
  640. //尝试从带有此脚本的游戏对象获取
  641. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  642. Console.WriteLine($"{TAG}InitPlugin:has no IUVCDrawer, try to get from gameObject");
  643. #endif
  644. var drawers = GetComponents(typeof(IUVCDrawer));
  645. if ((drawers != null) && (drawers.Length > 0))
  646. {
  647. UVCDrawers = new Component[drawers.Length];
  648. int i = 0;
  649. foreach (var drawer in drawers)
  650. {
  651. UVCDrawers[i++] = drawer;
  652. }
  653. }
  654. }
  655. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  656. Console.WriteLine($"{TAG}InitPlugin:num drawers={UVCDrawers.Length}");
  657. #endif
  658. // 请求读取aandusb的DeviceDetector
  659. using (AndroidJavaClass clazz = new AndroidJavaClass(FQCN_DETECTOR))
  660. {
  661. clazz.CallStatic("initUVCDeviceDetector",
  662. AndroidUtils.GetCurrentActivity());
  663. }
  664. }
  665. //--------------------------------------------------------------------------------
  666. // 定义和声明本机插件关系
  667. //--------------------------------------------------------------------------------
  668. /**
  669. * 插件中的渲染事件获取native(c/c++)函数
  670. */
  671. [DllImport("unityuvcplugin")]
  672. private static extern IntPtr GetRenderEventFunc();
  673. /**
  674. * 初期设定
  675. */
  676. [DllImport("unityuvcplugin", EntryPoint = "Config")]
  677. private static extern Int32 Config(Int32 deviceId, Int32 enabled, Int32 useFirstConfig);
  678. /**
  679. * 镜像取得开始
  680. */
  681. [DllImport("unityuvcplugin", EntryPoint ="Start")]
  682. private static extern Int32 Start(Int32 deviceId, Int32 tex);
  683. /**
  684. * 镜像取得终了
  685. */
  686. [DllImport("unityuvcplugin", EntryPoint ="Stop")]
  687. private static extern Int32 Stop(Int32 deviceId);
  688. /**
  689. * 影像尺寸设定
  690. */
  691. [DllImport("unityuvcplugin")]
  692. private static extern Int32 Resize(Int32 deviceId, Int32 frameType, Int32 width, Int32 height);
  693. } // UVCManager
  694. /**
  695. *如果是IL2Cpp的话,就不能对用于从c/c++回调的引导者进行跟踪
  696. *必须使用static类函数进行处理。
  697. *但如果是这样,则无法调用调用对象的函数,因此创建管理器类
  698. *首先只接受UVCmanager,所以不作为接口
  699. */
  700. public static class OnDeviceChangedCallbackManager
  701. {
  702. //声明回调函数的类型
  703. [UnmanagedFunctionPointer(CallingConvention.StdCall)]
  704. public delegate void OnDeviceChangedFunc(Int32 id, IntPtr devicePtr, bool attached);
  705. /**
  706. * 插件的native侧注册函数
  707. */
  708. [DllImport("unityuvcplugin")]
  709. private static extern IntPtr Register(Int32 id, OnDeviceChangedFunc callback);
  710. /**
  711. * 插件的native侧注销函数
  712. */
  713. [DllImport("unityuvcplugin")]
  714. private static extern IntPtr Unregister(Int32 id);
  715. private static Dictionary<Int32, UVCManager> sManagers = new Dictionary<Int32, UVCManager>();
  716. /**
  717. * 将指定的UVCManager添加到连接设备变化回调中
  718. */
  719. public static OnDeviceChangedFunc Add(UVCManager manager)
  720. {
  721. Int32 id = manager.GetHashCode();
  722. OnDeviceChangedFunc callback = new OnDeviceChangedFunc(OnDeviceChanged);
  723. sManagers.Add(id, manager);
  724. Register(id, callback);
  725. return callback;
  726. }
  727. /**
  728. * 从连接设备变化回调中删除指定的UVCManager
  729. */
  730. public static void Remove(UVCManager manager)
  731. {
  732. Int32 id = manager.GetHashCode();
  733. Unregister(id);
  734. sManagers.Remove(id);
  735. }
  736. [MonoPInvokeCallback(typeof(OnDeviceChangedFunc))]
  737. public static void OnDeviceChanged(Int32 id, IntPtr devicePtr, bool attached)
  738. {
  739. var manager = sManagers.ContainsKey(id) ? sManagers[id] : null;
  740. if (manager != null)
  741. {
  742. manager.OnDeviceChanged(devicePtr, attached);
  743. }
  744. }
  745. } // OnDeviceChangedCallbackManager
  746. } // namespace Serenegiant.UVC