ScannerHandler.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. using System;
  2. using System.Collections;
  3. using EZXR.Glass.SixDof;
  4. using System.Runtime.InteropServices;
  5. using UnityEngine;
  6. using Wheels.Unity;
  7. using EZXR.Glass.Device;
  8. using EZXR.Glass.Core;
  9. namespace EZXR.Glass.QRScanner
  10. {
  11. public class ScannerHandler : MonoBehaviour
  12. {
  13. public GameObject scanningView;
  14. public GameObject successView;
  15. public GameObject failedView;
  16. private byte[] imageBuffer;
  17. private int[] imageBufferClamp;
  18. private NormalRGBCameraDevice rgbCameraDevice;
  19. private EZVIOInputImage camImageBuffer;
  20. private Action startListeners;
  21. private Action<bool, string> completeListeners;
  22. private ZXing.BarcodeReader barcodeReader;
  23. private bool isCameraOpen = false;
  24. private bool isScannerStarted = false;
  25. private bool isScannnerComplete = false;
  26. private string qrCodeContent;
  27. private Coroutine timerCoroutine;
  28. private void Awake()
  29. {
  30. // ZeroDof
  31. transform.ActAsChild(HMDPoseTracker.Instance.Head);
  32. }
  33. private void OnEnable()
  34. {
  35. scanningView.SetActive(true);
  36. successView.SetActive(false);
  37. failedView.SetActive(false);
  38. qrCodeContent = string.Empty;
  39. StartCoroutine(startRGBCamera());
  40. timerCoroutine = StartCoroutine(startScannerTimer());
  41. }
  42. private void OnDisable()
  43. {
  44. Debug.Log($"-- ScannerHandler --, Scannner Complete: {qrCodeContent}");
  45. var isScanned = !string.IsNullOrEmpty(qrCodeContent);
  46. completeListeners?.Invoke(isScanned, qrCodeContent);
  47. if (timerCoroutine != null)
  48. {
  49. StopCoroutine(timerCoroutine);
  50. timerCoroutine = null;
  51. }
  52. stopRGBCamera();
  53. isScannerStarted = false;
  54. isScannnerComplete = false;
  55. }
  56. private void Update()
  57. {
  58. if (!isScannnerComplete && UpdateRGBCamera())
  59. {
  60. if (!isScannerStarted)
  61. {
  62. isScannerStarted = true;
  63. startListeners?.Invoke();
  64. }
  65. if (DecodeYUVImage(out var something))
  66. {
  67. isScannnerComplete = true;
  68. qrCodeContent = something;
  69. StartCoroutine(DelayAndDisable(1f));
  70. scanningView.SetActive(false);
  71. successView.SetActive(true);
  72. gameObject.GetComponent<AudioSource>().Play();
  73. if (timerCoroutine != null)
  74. {
  75. StopCoroutine(timerCoroutine);
  76. timerCoroutine = null;
  77. }
  78. }
  79. }
  80. }
  81. private IEnumerator startRGBCamera()
  82. {
  83. yield return new WaitUntil(() => SessionManager.Instance != null && SessionManager.Instance.IsInited);
  84. Debug.Log("-- ScannerHandler --, startRGBCamera");
  85. camImageBuffer = new EZVIOInputImage();
  86. rgbCameraDevice = new NormalRGBCameraDevice();
  87. rgbCameraDevice.Open();
  88. isCameraOpen = true;
  89. }
  90. private void stopRGBCamera()
  91. {
  92. Debug.Log("-- ScannerHandler --, stopRGBCamera");
  93. rgbCameraDevice?.Close();
  94. isCameraOpen = false;
  95. if (camImageBuffer.fullImg != IntPtr.Zero)
  96. {
  97. Marshal.FreeHGlobal(camImageBuffer.fullImg);
  98. camImageBuffer.fullImg = IntPtr.Zero;
  99. }
  100. if (imageBuffer != null)
  101. imageBuffer = null;
  102. if (imageBufferClamp != null)
  103. imageBufferClamp = null;
  104. }
  105. public void SetupListeners(Action onStart, Action<bool, string> onComplete)
  106. {
  107. startListeners = onStart;
  108. completeListeners = onComplete;
  109. }
  110. private bool UpdateRGBCamera()
  111. {
  112. if (ARFrame.SessionStatus != EZVIOState.EZVIOCameraState_Tracking)
  113. return false;
  114. if (!isCameraOpen || rgbCameraDevice == null)
  115. return false;
  116. return rgbCameraDevice.getCurrentImage(ref camImageBuffer, new float[8]);
  117. }
  118. private bool DecodeYUVImage(out string something)
  119. {
  120. something = string.Empty;
  121. if (camImageBuffer.imgFormat != EZVIOImageFormat.EZVIOImageFormat_YUV420A)
  122. {
  123. Debug.LogError($"-- ScannerHandler --, incompatible image format({camImageBuffer.imgFormat}) when decode.");
  124. return false;
  125. }
  126. int width = (int)camImageBuffer.imgRes.width;
  127. int height = (int)camImageBuffer.imgRes.height;
  128. int channelSize = width * height/* * 3 / 2*/;
  129. if (imageBuffer == null) imageBuffer = new byte[channelSize];
  130. Marshal.Copy(camImageBuffer.fullImg, imageBuffer, 0, channelSize); //只读Y通道
  131. // create a reader with a custom luminance source
  132. if (barcodeReader == null) barcodeReader = new ZXing.BarcodeReader { AutoRotate = false, Options = new ZXing.Common.DecodingOptions { TryHarder = false } };
  133. var result = barcodeReader.Decode(new ZXing.PlanarYUVLuminanceSource(imageBuffer, width, height, 0, 0, width, height, false));
  134. if (result != null && !string.IsNullOrEmpty(result.Text))
  135. {
  136. something = result.Text;
  137. return true;
  138. }
  139. return false;
  140. }
  141. private IEnumerator startScannerTimer()
  142. {
  143. yield return new WaitForSeconds(60f);
  144. scanningView.SetActive(false);
  145. failedView.SetActive(true);
  146. isScannnerComplete = true;
  147. yield return DelayAndDisable(1f);
  148. }
  149. private IEnumerator DelayAndDisable(float delay)
  150. {
  151. yield return new WaitForSeconds(delay);
  152. gameObject.SetActive(false);
  153. }
  154. }
  155. }