TerminalImageCapturerV2.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. using Lennox.LibYuvSharp;
  2. using System;
  3. using System.Runtime.InteropServices;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using Vinno.vCloud.FIS.CrossPlatform.Common;
  7. using Vinno.vCloud.FIS.CrossPlatform.Common.Enum;
  8. using Vinno.vCloud.FIS.CrossPlatform.Common.LiveVideo;
  9. using Vinno.vCloud.FIS.CrossPlatform.Common.LiveVideo.Interface;
  10. namespace Vinno.vCloud.FIS.CrossPlatform.Windows.LiveVideo
  11. {
  12. internal class TerminalImageCapturerV2 : ICapturer
  13. {
  14. private readonly object _lock = new object();
  15. private readonly string _id;
  16. private readonly int _width;
  17. private readonly int _height;
  18. private bool _isCapturing;
  19. private int loggerCount = 0;
  20. private CPVideoFrameData _videoFrameData;
  21. private ImageFrameData _imageFrameData;
  22. private byte[] _screenTempBuffer;
  23. private byte[] _screenBuffer;
  24. private EnumImageType _imageType;
  25. private int _lastSendDataTime;
  26. private int _lastCaptureTime;
  27. private readonly ManualResetEvent _handlingImageEvent = new ManualResetEvent(true);
  28. public string Id => _id;
  29. public int OutputWidth => _width;
  30. public int OutputHeight => _height;
  31. public bool IsCapturing => _isCapturing;
  32. public event EventHandler<ImageFrameData> ImageFrameReceived;
  33. public event EventHandler<CPVideoFrameData> VideoFrameDataReceived;
  34. public TerminalImageCapturerV2(string id, int terminalWidth, int terminalHeight, EnumImageType imageType)
  35. {
  36. _id = id;
  37. _imageType = imageType;
  38. _width = terminalWidth;
  39. _height = terminalHeight;
  40. switch (_imageType)
  41. {
  42. case EnumImageType.ImageFrameData:
  43. _imageFrameData = new ImageFrameData(OutputWidth, OutputHeight);
  44. break;
  45. case EnumImageType.CPVideoFrameData:
  46. _videoFrameData = new CPVideoFrameData(OutputWidth, OutputHeight, null);
  47. break;
  48. }
  49. _imageFrameData = new ImageFrameData(terminalWidth, terminalHeight);
  50. CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"TerminalImageCaptureV2 Resolution:{terminalWidth} x {terminalHeight} ");
  51. }
  52. public void StartCapture()
  53. {
  54. if (_isCapturing)
  55. {
  56. CrossPlatformHelper.Instance.LogWriter?.WriteLineWarn($"TerminalImageCaptureV2 Has Been In Capturing!");
  57. return;
  58. }
  59. _isCapturing = true;
  60. ImageDataCapturer.ImdageDataCaptured += OnImageDataCaptured;
  61. Task.Run(() =>
  62. {
  63. while (_isCapturing)
  64. {
  65. try
  66. {
  67. _handlingImageEvent.Reset();
  68. if (Math.Abs(_lastSendDataTime - DateTime.Now.Millisecond) <= 40)
  69. {
  70. continue;
  71. }
  72. else
  73. {
  74. _lastSendDataTime = DateTime.Now.Millisecond;
  75. }
  76. switch (_imageType)
  77. {
  78. case EnumImageType.ImageFrameData:
  79. lock (_lock)
  80. {
  81. if (_screenTempBuffer == null)
  82. {
  83. Thread.Sleep(10);
  84. continue;
  85. }
  86. Marshal.Copy(_screenTempBuffer, 0, _imageFrameData.Data, _screenTempBuffer.Length);
  87. }
  88. ImageFrameReceived?.Invoke(this, _imageFrameData);
  89. Thread.Sleep(20);
  90. break;
  91. case EnumImageType.CPVideoFrameData:
  92. lock (_lock)
  93. {
  94. if (_screenTempBuffer == null)
  95. {
  96. Thread.Sleep(10);
  97. continue;
  98. }
  99. ResizeBuffer(ref _screenBuffer, _screenTempBuffer.Length);
  100. Buffer.BlockCopy(_screenTempBuffer, 0, _screenBuffer, 0, _screenTempBuffer.Length);
  101. }
  102. _videoFrameData.Data = _screenBuffer;
  103. VideoFrameDataReceived?.Invoke(this, _videoFrameData);
  104. Thread.Sleep(20);
  105. break;
  106. }
  107. }
  108. finally
  109. {
  110. _handlingImageEvent.Set();
  111. Thread.Sleep(10);
  112. }
  113. }
  114. });
  115. CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"TerminalImageCaptureV2:{Id} StartCapture");
  116. }
  117. private void ResizeBuffer(ref byte[] buffer, int size)
  118. {
  119. if (buffer == null)
  120. {
  121. buffer = new byte[size];
  122. }
  123. else if (buffer.Length != size)
  124. {
  125. Array.Resize(ref buffer, size);
  126. }
  127. }
  128. private void OnImageDataCaptured(object sender, CaptureDataInfo e)
  129. {
  130. try
  131. {
  132. if (Math.Abs(_lastCaptureTime - DateTime.Now.Millisecond) < 30)
  133. {
  134. return;
  135. }
  136. _lastCaptureTime = DateTime.Now.Millisecond;
  137. var width = e.Width;
  138. var height = e.Height;
  139. var dataSize = e.Width * e.Height * 4;
  140. if (loggerCount < 1)
  141. {
  142. CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"TerminalImageCaptureV2: Capture main window:{width}*{height}, Resize :{OutputWidth}*{OutputHeight}");
  143. loggerCount++;
  144. }
  145. if (width == OutputWidth && height == OutputHeight)
  146. {
  147. lock (_lock)
  148. {
  149. ResizeBuffer(ref _screenTempBuffer, dataSize);
  150. Buffer.BlockCopy(e.Data, 0, _screenTempBuffer, 0, dataSize);
  151. }
  152. }
  153. else
  154. {
  155. lock (_lock)
  156. {
  157. ResizeBuffer(ref _screenTempBuffer, OutputWidth * OutputHeight * 4);
  158. unsafe
  159. {
  160. fixed (byte* captureData = e.Data)
  161. {
  162. fixed (byte* tempData = _screenTempBuffer)
  163. {
  164. LibYuv.ARGBScale(captureData, e.Width * 4, e.Width, e.Height, tempData, OutputWidth * 4, OutputWidth, OutputHeight, FilterMode.None);
  165. }
  166. }
  167. }
  168. }
  169. }
  170. }
  171. catch (Exception ex)
  172. {
  173. CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"TerminalImageCaptureV2 OnImageDataCaptured Error:{ex}");
  174. }
  175. }
  176. public void StopCapture()
  177. {
  178. try
  179. {
  180. if (_isCapturing)
  181. {
  182. _isCapturing = false;
  183. ImageDataCapturer.ImdageDataCaptured -= OnImageDataCaptured;
  184. CrossPlatformHelper.Instance.LogWriter?.WriteLineInfo($"TerminalImageCaptureV2:{Id} StopCapture");
  185. }
  186. }
  187. catch (Exception e)
  188. {
  189. CrossPlatformHelper.Instance.LogWriter?.WriteLineError($"TerminalImageCaptureV2 Stop Capture Error:{e}");
  190. }
  191. }
  192. public void Dispose()
  193. {
  194. StopCapture();
  195. _handlingImageEvent.WaitOne();
  196. _imageFrameData?.Dispose();
  197. }
  198. }
  199. }