Program.cs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. using Accord.Video.FFMPEG;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Drawing;
  5. using System.Drawing.Imaging;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Net;
  9. using System.Net.Sockets;
  10. using System.Runtime.InteropServices;
  11. using System.Text;
  12. using System.Threading;
  13. using System.Threading.Tasks;
  14. namespace ScreenBroadcast
  15. {
  16. internal class Program
  17. {
  18. //[DllImport("user32.dll", SetLastError = true)]
  19. //static extern bool GetWindowRect(int hWnd, out RECT lpRect);
  20. // For Windows Mobile, replace user32.dll with coredll.dll
  21. [DllImport("user32.dll", SetLastError = true)]
  22. private static extern int FindWindow(string lpClassName, string lpWindowName);
  23. [DllImport("user32.dll", SetLastError = true)]
  24. private static extern bool GetClientRect(int hWnd, out Rect lpRect);
  25. [DllImport("user32.dll")]
  26. private static extern bool ClientToScreen(int hWnd, ref Point lpPoint);
  27. [StructLayout(LayoutKind.Sequential)]
  28. public struct Rect
  29. {
  30. public int Left;
  31. public int Top;
  32. public int Right;
  33. public int Bottom;
  34. public int Height => Bottom - Top;
  35. public int Width => Right - Left;
  36. public Size Size => new Size(Width, Height);
  37. public Point Location => new Point(Left, Top);
  38. }
  39. private static void Main()
  40. {
  41. //comfig var
  42. string wndCls = "ConsoleWindowClass";
  43. string wndName = "管理员: 命令提示符";
  44. int port = 2333;
  45. var frameRate = 25;
  46. var broadcastQuality = 20L;
  47. //runtime var
  48. var runing = true;
  49. int clientNum = 0;
  50. byte[] buf = null;
  51. var waits = new List<AutoResetEvent>();
  52. var taskSource = Task.Factory.StartNew(() =>
  53. {
  54. //image encoding params
  55. var format = ImageFormat.Jpeg;
  56. var codec = ImageCodecInfo.GetImageDecoders().First(p => p.FormatID == format.Guid);
  57. var codecParam = new EncoderParameters(1);
  58. //buffer vars
  59. Bitmap imgBuf = null;
  60. var vdoWriter = new VideoFileWriter();
  61. var ms = new MemoryStream();
  62. var hWnd = 0;
  63. try
  64. {
  65. while (runing)
  66. {
  67. if (hWnd == 0) hWnd = FindWindow(wndCls, wndName);
  68. Rect rectWndCa;
  69. var ptWndLoc = Point.Empty;
  70. if (GetClientRect(hWnd, out rectWndCa) && ClientToScreen(hWnd, ref ptWndLoc))
  71. {
  72. Func<int, int> ensureBy2 = v => v % 2 != 0 ? v + 1 : v;
  73. Func<int, int> ensureBy4 = v => v % 4 != 0 ? v + (4 - v % 4) : v;
  74. Func<int, int, int> ensureBy = (b, v) => v % b != 0 ? v + (b - v % b) : v;
  75. var rect = new Rectangle(ptWndLoc, new Size(ensureBy(2, rectWndCa.Size.Width), ensureBy(2, rectWndCa.Height)));
  76. if (imgBuf == null || imgBuf.Size != rect.Size)
  77. {
  78. imgBuf = new Bitmap(rect.Width, rect.Height, PixelFormat.Format24bppRgb);
  79. if (vdoWriter.IsOpen)
  80. vdoWriter.Close();
  81. var recordPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "record");
  82. Directory.CreateDirectory(recordPath);
  83. var filename = $"record_{DateTime.Now:yyyyMMdd_HHmmss_fffff}-{rect.Width:0000}-{rect.Height:0000}.avi";
  84. vdoWriter.Open(Path.Combine(recordPath, filename), rect.Width, rect.Height, frameRate, VideoCodec.MPEG4, 8000000);
  85. }
  86. Graphics srcGraphics = Graphics.FromImage(imgBuf);
  87. srcGraphics.CopyFromScreen(rect.Location, Point.Empty, rect.Size);
  88. codecParam.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, broadcastQuality);
  89. ms.SetLength(0);
  90. imgBuf.Save(ms, codec, codecParam);
  91. //imgBuf.Save(ms, format);
  92. buf = ms.ToArray();
  93. foreach (var item in waits)
  94. {
  95. item.Set();
  96. }
  97. vdoWriter.WriteVideoFrame(imgBuf);
  98. }
  99. else
  100. {
  101. hWnd = 0; //re find win
  102. Console.WriteLine("waiting window found...");
  103. }
  104. Thread.Sleep(1000 / frameRate);
  105. }
  106. vdoWriter.Close();
  107. }
  108. catch (Exception ex)
  109. {
  110. throw;
  111. }
  112. });
  113. Task.Factory.StartNew(() =>
  114. {
  115. Socket Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  116. Server.Bind(new IPEndPoint(IPAddress.Any, port));
  117. Server.Listen(10);
  118. Console.WriteLine("Listening...");
  119. while (runing)
  120. {
  121. int num;
  122. var client = Server.Accept();
  123. Console.WriteLine("Acceped socket #{0} from {1} onlines {2}", num = ++clientNum, client.RemoteEndPoint, waits.Count);
  124. Task.Factory.StartNew(() =>
  125. {
  126. var wait = new AutoResetEvent(false);
  127. waits.Add(wait);
  128. try
  129. {
  130. var stream = new NetworkStream(client, true);
  131. var writer = new BinaryWriter(stream);
  132. writer.Write(Encoding.ASCII.GetBytes("HTTP / 1.1 200 OK\r\n"));
  133. writer.Write(Encoding.ASCII.GetBytes("Content-Type: multipart/x-mixed-replace; boundary=frame\r\n"));
  134. while (runing)
  135. {
  136. wait.WaitOne();
  137. var rbuf = buf;
  138. if (rbuf != null)
  139. {
  140. writer.Write(Encoding.ASCII.GetBytes("\r\n"));
  141. writer.Write(Encoding.ASCII.GetBytes("--frame\r\n"));
  142. writer.Write(Encoding.ASCII.GetBytes("Content-Type: image/png\r\n"));
  143. writer.Write(Encoding.ASCII.GetBytes("Content-Length: " + rbuf.Length + "\r\n"));
  144. writer.Write(Encoding.ASCII.GetBytes("\r\n"));
  145. writer.Write(rbuf);
  146. }
  147. }
  148. }
  149. catch (Exception ex)
  150. {
  151. Console.WriteLine("Lost socket #{1} from {0} onlines {2} by {3}", client.RemoteEndPoint, num, waits.Count, ex.Message);
  152. }
  153. waits.Remove(wait);
  154. });
  155. }
  156. });
  157. ConsoleKeyInfo k;
  158. while (char.ToLower((k = Console.ReadKey(true)).KeyChar) != 'q')
  159. {
  160. if (k.Key == ConsoleKey.UpArrow)
  161. {
  162. if (broadcastQuality + 1 == 0)
  163. broadcastQuality += 2;
  164. else
  165. broadcastQuality += 1;
  166. Console.WriteLine("Quality: {0}", broadcastQuality);
  167. }
  168. else if (k.Key == ConsoleKey.DownArrow)
  169. {
  170. if (broadcastQuality - 1 == 0)
  171. broadcastQuality -= 2;
  172. else
  173. broadcastQuality -= 1;
  174. Console.WriteLine("Quality: {0}", broadcastQuality);
  175. }
  176. else
  177. {
  178. Console.WriteLine("Press Q to exit. up-arrow to inc quality, down-arrow to dec");
  179. }
  180. }
  181. runing = false;
  182. taskSource.Wait();
  183. }
  184. }
  185. }