关键词搜索

源码搜索 ×
×

C# 实现多分屏视频播放-自定义控件集合无序性问题

发布2018-07-09浏览3313次

详情内容

参考:自定义控件使其填充方格且自动变换大小文章,据此生成了多分屏的视频播放器。这里需要注意Controls的数组的无序性。

这里看下自定义控件的代码:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Drawing;
  5. using System.Data;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using System.Windows.Forms;
  10. using CvNetVideo.Event;
  11. using System.Runtime.InteropServices;
  12. using CvNetVideo.Play;
  13. using static CvNetVideo.UCVideo;
  14. namespace CvNetVideo
  15. {
  16. [Guid("f3943464-829d-4bb8-8b05-10516831ceed")]
  17. //指示应用该属性的对象对COM可见
  18. [ComVisible(true)]
  19. //将事件接收接口连接到托管类
  20. [ComSourceInterfacesAttribute(typeof(MulitiControlEvents))]
  21. public partial class UserControlVideo : UserControl
  22. {
  23. #region 属性变量
  24. /// <summary>
  25. /// 选择的分屏索引
  26. /// </summary>
  27. public int SelectedIndex { set; get; }
  28. /// <summary>
  29. /// 操作的分屏索引
  30. /// </summary>
  31. private int OperationIndex;
  32. /// <summary>
  33. /// 控件原始宽度
  34. /// </summary>
  35. public int OldWidth { set; get; }
  36. /// <summary>
  37. /// 控件原始高度
  38. /// </summary>
  39. public int OldHeight { set; get; }
  40. public bool IsFullScreenInSystem { get; set; }
  41. public bool IsFullScreen = false;
  42. #endregion
  43. public UserControlVideo()
  44. {
  45. InitializeComponent();
  46. }
  47. # region 事件回调
  48. /// <summary>
  49. /// 全屏或退出全屏事件
  50. /// </summary>
  51. public event MulitiFullScreenEvent OnFullScreenEvent;
  52. /// <summary>
  53. /// 直播退出事件
  54. /// </summary>
  55. public event MulitiRealTimeLiveAllStopEvent OnRealTimeLiveAllStopEvent;
  56. /// <summary>
  57. /// 控件双击事件(控制全屏)
  58. /// </summary>
  59. public event MulitiControlDoubleClickEvent OnControlDoubleClickEvent;
  60. /// <summary>
  61. /// 异步远程视频回放事件
  62. /// </summary>
  63. public event MulitiAsyncRemoteVideoPlaybackEvent OnAsyncRemoteVideoPlaybackEvent;
  64. /// <summary>
  65. /// 发生某个事件触发事件
  66. /// </summary>
  67. public event MulitidglEventTrigger OnEventTrigger;
  68. /// <summary>
  69. /// 异步FTP文件上传事件
  70. /// </summary>
  71. public event MulitiAsyncFtpFileUploadEvent OnAsyncFtpFileUploadEvent;
  72. /// <summary>
  73. /// 实时视频播放超时事件
  74. /// </summary>
  75. public event MulitiRealtimeVideoOuttimeEvent OnRealtimeVideoOuttimeEvent;
  76. /// <summary>
  77. /// OCX操作优先级通知事件
  78. /// </summary>
  79. public event MulitiRealtimeVideoPriorityNotifyEvent OnRealtimeVideoPriorityNotifyEvent;
  80. /// <summary>
  81. /// 视频截图完成回调事件
  82. /// </summary>
  83. public event MulitiScreenshotCompletedEvent OnScreenshotCompletedEvent;
  84. /// <summary>
  85. /// 视频点击选中回调事件
  86. /// </summary>
  87. public event MulitiScreenSelectEvent OnScreenSelectEvent;
  88. /// <summary>
  89. /// 视频分屏重载回调事件
  90. /// </summary>
  91. public event MulitiReloadControlScreenEvent OnReloadControlScreenEvent;
  92. /// <summary>
  93. /// 全部关闭实时视频回调事件
  94. /// </summary>
  95. public event MulitiStopAllRealtimeVideoScreenEvent OnStopAllRealtimeVideoScreenEvent;
  96. /// <summary>
  97. /// 视频控件选中事件回调
  98. /// </summary>
  99. /// <param name="id"></param>
  100. public void ControlSelectdCallback(int id)
  101. {
  102. this.SelectedIndex = id;
  103. this.OperationIndex = this.SelectedIndex;
  104. for (var i = 0; i < this.Controls.Count; i++)
  105. {
  106. UCVideo video = this.Controls[i] as UCVideo;
  107. if (this.SelectedIndex == video.Id)
  108. {
  109. video.BorderStyle = BorderStyle.Fixed3D;
  110. }
  111. else
  112. {
  113. video.BorderStyle = BorderStyle.FixedSingle;
  114. }
  115. }
  116. // 网页选中视频事件回调
  117. OnScreenSelectEvent?.Invoke(id);
  118. }
  119. /// <summary>
  120. /// 全屏回调事件回调
  121. /// </summary>
  122. /// <param name="id"></param>
  123. /// <param name="isFullScreen"></param>
  124. public void ControlFullScreenEventCallback(int id, bool isFullScreen)
  125. {
  126. OpenOrCloseFullScreen(id, isFullScreen);
  127. OnFullScreenEvent?.Invoke(id, isFullScreen);
  128. }
  129. /// <summary>
  130. /// 视频关闭事件回调
  131. /// </summary>
  132. /// <param name="id"></param>
  133. public void ControlRealTimeLiveAllStopEventCallback(int id)
  134. {
  135. OnRealTimeLiveAllStopEvent?.Invoke(id);
  136. }
  137. /// <summary>
  138. /// 视频双击(全屏/退出全屏)事件回调
  139. /// </summary>
  140. /// <param name="id"></param>
  141. /// <param name="isFullScreen"></param>
  142. public void ControlDoubleClickEventCallback(int id, bool isFullScreen)
  143. {
  144. OnControlDoubleClickEvent?.Invoke(id, isFullScreen);
  145. }
  146. /// <summary>
  147. /// 视频回放异步远程事件回调
  148. /// </summary>
  149. /// <param name="id"></param>
  150. /// <param name="json"></param>
  151. public void ControlAsyncRemoteVideoPlaybackEventCallback(int id, string json)
  152. {
  153. OnAsyncRemoteVideoPlaybackEvent?.Invoke(id, json);
  154. }
  155. /// <summary>
  156. /// 触发ID事件回调
  157. /// </summary>
  158. /// <param name="id"></param>
  159. /// <param name="eventId"></param>
  160. public void ControldglEventTriggerCallback(int id, int eventId)
  161. {
  162. OnEventTrigger?.Invoke(id,eventId);
  163. }
  164. /// <summary>
  165. /// 视频异步FTP文件上传事件回调
  166. /// </summary>
  167. /// <param name="id"></param>
  168. /// <param name="json"></param>
  169. public void ControlAsyncFtpFileUploadEventCallback(int id, string json)
  170. {
  171. OnAsyncFtpFileUploadEvent?.Invoke(id,json);
  172. }
  173. /// <summary>
  174. /// 实时视频播放超时事件回调
  175. /// </summary>
  176. /// <param name="id"></param>
  177. public void ControlRealtimeVideoOuttimeEventCallback()
  178. {
  179. OnRealtimeVideoOuttimeEvent?.Invoke();
  180. }
  181. /// <summary>
  182. /// 视频操作优先级通知回调
  183. /// </summary>
  184. /// <param name="id"></param>
  185. /// <param name="priority"></param>
  186. public void ControlRealtimeVideoPriorityNotifyEventCallback(int id, int priority)
  187. {
  188. OnRealtimeVideoPriorityNotifyEvent?.Invoke(id,priority);
  189. }
  190. /// <summary>
  191. /// 视频截图完成事件回调
  192. /// </summary>
  193. /// <param name="id"></param>
  194. /// <param name="fileLocation"></param>
  195. public void ControlScreenshotCompletedEventCallback(int id, string fileLocation)
  196. {
  197. OnScreenshotCompletedEvent?.Invoke(id,fileLocation);
  198. }
  199. /// <summary>
  200. /// 全部关闭实时视频事件回调
  201. /// </summary>
  202. public void ControlStopAllRealtimeVideoScreenEventCallback()
  203. {
  204. OnStopAllRealtimeVideoScreenEvent?.Invoke();
  205. }
  206. #endregion
  207. #region 全屏操作
  208. FullScreenObject fullScreenObject;
  209. /// <summary>
  210. /// 打开或关闭全屏
  211. /// </summary>
  212. public void OpenOrCloseFullScreen(int id,bool isOpen)
  213. {
  214. int Count = (int)Math.Sqrt(this.Controls.Count);
  215. int perWidth = OldWidth / Count;
  216. int perHeight = OldHeight / Count;
  217. if (isOpen)
  218. {
  219. OldWidth = this.Width;
  220. OldHeight = this.Height;
  221. if (fullScreenObject == null)
  222. {
  223. if (IsFullScreenInSystem)
  224. {
  225. // 系统级别的全屏
  226. fullScreenObject = new FullScreenHelper(this);
  227. }
  228. else
  229. {
  230. // 容器内的全屏
  231. fullScreenObject = new FullScreenInContainerHelper(this);
  232. }
  233. }
  234. fullScreenObject.FullScreen(isOpen);
  235. IsFullScreen = isOpen;
  236. Console.WriteLine("Entrance FullScreen Mode");
  237. // 全屏显示选择的屏幕视频窗口
  238. UCVideo fullscreenUcVideo = null;
  239. foreach (var ucVideo in this.Controls)
  240. {
  241. fullscreenUcVideo = ucVideo as UCVideo;
  242. if (id == fullscreenUcVideo.Id)
  243. {
  244. fullscreenUcVideo.Width = this.Width;
  245. fullscreenUcVideo.Height = this.Height;
  246. fullscreenUcVideo.Location = new Point(0, 0);
  247. fullscreenUcVideo.Visible = true;
  248. Console.WriteLine(">>>>>>>>>>>全屏Full ID=" + fullscreenUcVideo.Id);
  249. break;
  250. }
  251. }
  252. }
  253. else
  254. {
  255. if (fullScreenObject != null && IsFullScreen)
  256. {
  257. fullScreenObject.FullScreen(isOpen);
  258. IsFullScreen = isOpen;
  259. // 复位全屏元素
  260. UCVideo fullscreenUcVideo = null;
  261. foreach (var ucVideo in this.Controls)
  262. {
  263. fullscreenUcVideo = ucVideo as UCVideo;
  264. if (id == fullscreenUcVideo.Id)
  265. {
  266. fullscreenUcVideo.Width = perWidth;
  267. fullscreenUcVideo.Height = perHeight;
  268. fullscreenUcVideo.Location = new Point(fullscreenUcVideo.X, fullscreenUcVideo.Y);
  269. fullscreenUcVideo.Visible = true;
  270. Console.WriteLine(">>>>>>>>>>>复位Full ID=" + fullscreenUcVideo.Id);
  271. break;
  272. }
  273. }
  274. this.Width = OldWidth;
  275. this.Height = OldHeight;
  276. Console.WriteLine("Exit FullScreen Mode");
  277. }
  278. }
  279. }
  280. #endregion
  281. #region 分屏处理
  282. /// <summary>
  283. /// 获取视频对象
  284. /// </summary>
  285. /// <param name="id"></param>
  286. /// <returns></returns>
  287. public UCVideo GetUCVideoById(int id)
  288. {
  289. return this.Controls[id] as UCVideo;
  290. }
  291. /// 填充视频
  292. /// </summary>
  293. /// <param name="num">数量</param>
  294. public void FillUCVideo(int num)
  295. {
  296. // 触发重载事件
  297. OnReloadControlScreenEvent?.Invoke();
  298. this.OperationIndex = 0;
  299. this.Controls.Clear();
  300. //填充num*num个方格,现在放置的是罗列着的
  301. for (int i = 0; i < num * num; i++)
  302. {
  303. UCVideo uCVideo = new UCVideo();
  304. // 设置默认ID
  305. uCVideo.Id = i;
  306. // 注册视频选择事件
  307. uCVideo.ControlSelectdCallback = ControlSelectdCallback;
  308. // 注册视频全屏事件
  309. uCVideo.ControlFullScreenEventCallback = ControlFullScreenEventCallback;
  310. // 注册视频退出事件
  311. uCVideo.ControlRealTimeLiveAllStopEventCallback = ControlRealTimeLiveAllStopEventCallback;
  312. // 注册视频双击(全屏/退出全屏)事件
  313. uCVideo.ControlForDoubleClickEventCallback = ControlDoubleClickEventCallback;
  314. // 注册视频回放查询回调事件
  315. uCVideo.ControlAsyncRemoteVideoPlaybackEventCallback = ControlAsyncRemoteVideoPlaybackEventCallback;
  316. // 注册触发视频执行ID事件
  317. uCVideo.ControldglEventTriggerCallback = ControldglEventTriggerCallback;
  318. // 注册视频异步FTP文件上传事件
  319. uCVideo.ControlAsyncFtpFileUploadEventCallback = ControlAsyncFtpFileUploadEventCallback;
  320. // 注册实时视频播放超时事件
  321. //uCVideo.ControlRealtimeVideoOuttimeEventCallback = ControlRealtimeVideoOuttimeEventCallback;
  322. // 注册实时视频操作优先级通知事件
  323. uCVideo.ControlRealtimeVideoPriorityNotifyEventCallback = ControlRealtimeVideoPriorityNotifyEventCallback;
  324. // 注册视频截图完成回调事件
  325. uCVideo.ControlScreenshotCompletedEventCallback = ControlScreenshotCompletedEventCallback;
  326. // 是否开启桌面超时事件
  327. uCVideo.SetStartOuttimeListener(false);
  328. this.Controls.Add(uCVideo);
  329. }
  330. //定义方法,因为需要改变大小,所以单独
  331. this.LayoutUCVideos();
  332. }
  333. /// 填充视频
  334. /// </summary>
  335. /// <param name="num">数量</param>
  336. /// <param name="controlExeSelectd">选择代理函数</param>
  337. public void FillUCVideo(int num, ControlExeSelectd controlExeSelectd)
  338. {
  339. this.Controls.Clear();
  340. //填充num*num个方格,现在放置的是罗列着的
  341. for (int i = 0; i < num*num; i++)
  342. {
  343. UCVideo uCVideo = new UCVideo();
  344. // 设置默认ID
  345. uCVideo.Id = i;
  346. // 注册视频选择事件
  347. uCVideo.ControlSelectdCallback = ControlSelectdCallback;
  348. // 注册exe视频选择事件
  349. uCVideo.ControlExeSelectdCallback = controlExeSelectd;
  350. //注册视频全屏事件
  351. uCVideo.ControlFullScreenEventCallback = ControlFullScreenEventCallback;
  352. this.Controls.Add(uCVideo);
  353. }
  354. //定义方法,因为需要改变大小,所以单独
  355. this.LayoutUCVideos();
  356. }
  357. /// <summary>
  358. /// 布局视频
  359. /// </summary>
  360. /// <returns></returns>
  361. public void LayoutUCVideos()
  362. {
  363. OldWidth = this.Width;
  364. OldHeight = this.Height;
  365. //去除启动状态,以免开启的时候FillBtn_SizeChanged会报错
  366. if (this.Controls.Count == 0)
  367. {
  368. return;
  369. }
  370. //循环多少次?计算出来
  371. int Count = (int)Math.Sqrt(this.Controls.Count);
  372. //计算每个视频的的宽度和高度
  373. int perWidth = this.Width / Count;
  374. int perHeight = this.Height / Count;
  375. int Index = 0;
  376. int X = 0, Y = 0;
  377. //竖向的循环嵌套横着的循环
  378. for (int verticalIndex = 0; verticalIndex < Count; verticalIndex++)
  379. {
  380. Y = verticalIndex * perHeight;
  381. //水平向的循环
  382. for (int horizontalIndex = 0; horizontalIndex < Count; horizontalIndex++)
  383. {
  384. X = horizontalIndex * perWidth;
  385. //获取要放置的方格
  386. foreach (var ucVideo in this.Controls)
  387. {
  388. UCVideo video = ucVideo as UCVideo;
  389. if (video.Id==Index)
  390. {
  391. video.X = X;
  392. video.Y = Y;
  393. video.Width = perWidth;
  394. video.Height = perHeight;
  395. //设置当前方格的位置
  396. video.Location = new Point(X, Y);
  397. Console.WriteLine("=========ID:" + video.Id);
  398. break;
  399. }
  400. }
  401. //下一个方格
  402. Index++;
  403. }
  404. }
  405. }
  406. #endregion
  407. #region 控件事件
  408. /// <summary>
  409. /// 控件初始化时加载默认分屏
  410. /// </summary>
  411. /// <param name="sender"></param>
  412. /// <param name="e"></param>
  413. private void UserControlVideo_Load(object sender, EventArgs e)
  414. {
  415. FillUCVideo(4);
  416. LayoutUCVideos();
  417. }
  418. private void UserControlVideo_Resize(object sender, EventArgs e)
  419. {
  420. if (!IsFullScreen)
  421. {
  422. LayoutUCVideos();
  423. }
  424. }
  425. #endregion
  426. }
  427. }

关键代码处理:

  1. //获取要放置的方格
  2. foreach (var ucVideo in this.Controls)
  3. {
  4. UCVideo video = ucVideo as UCVideo;
  5. if (video.Id==Index)
  6. {
  7. video.X = X;
  8. video.Y = Y;
  9. video.Width = perWidth;
  10. video.Height = perHeight;
  11. //设置当前方格的位置
  12. video.Location = new Point(X, Y);
  13. Console.WriteLine("=========ID:" + video.Id);
  14. break;
  15. }
  16. }

这里的id不能理解为数组下标,因为是可变的。



相关技术文章

点击QQ咨询
开通会员
返回顶部
×
微信扫码支付
微信扫码支付
确定支付下载
请使用微信描二维码支付
×

提示信息

×

选择支付方式

  • 微信支付
  • 支付宝付款
确定支付下载