视频播放开发笔记-手机控制视频播放(简述WebSocket 的使用)

自己在MPV基础开发的视频播放器windows版,已经可以流畅的播放视频了,并拥有了比较实用的字幕控制和截屏功能,要求不高的话,可以拿来做播放器了。因为我有时候用做显示器,鼠标又不是特别好用,就萌生了用手机控制视频播放的想法。为了同时能支持安卓和IOS,决定采用浏览器的方式。这样一来二去,就用到了WebSocket。
因此本文主要记录WebSocket的使用,核心是两个,第一是HTML 和C#的通信,第二是WebSocket传输图像的处理方法。

C#和HTML通过WebSocket通信的基本操作

开发环境:win10, VS2017
直接说方法吧,非技术方面的东西就不写了,没时间和心情写这玩意儿, 本身我也是抄来的。
C# WebSocket的使用
我用的是:Fleck, 当然还有其他第三方的package。
安装方法请参考:
使用NuGet增加常见包引用
安装成功后,C#方面的代码
说明:这里面用了lamda 表达式,不清楚的同学自己查一查吧。我也是一会儿清楚一会儿不清楚,因为先入为主的原因,特不情愿用这个东西。但是确实简单。

测试界面如下:
在这里插入图片描述
Open socket 的代码如下:

      private void button1_Click(object sender, EventArgs e)
        {
            FleckLog.Level = LogLevel.Debug;
            var server = new WebSocketServer("ws://192.168.0.103:58888");
            server.Start(socket =>
            {
                socket.OnOpen = () =>
                {
                    Console.WriteLine("Open!");
                    m_allSockets.Add(socket);
                };
                socket.OnClose = () =>
                {
                    Console.WriteLine("Close!");
                    m_allSockets.Remove(socket);
                };
                socket.OnMessage = message =>
                {
                    Console.WriteLine(message);
                    m_allSockets.ToList().ForEach(s => s.Send("Echo:" + message));
                    //foreach (var socket in allSockets.ToList())
                    {
                        //socket.Send(input);
                        //socket.Send(dat);
                    }
                };
            });

        }

其中 m_allSockets 的定义

List<IWebSocketConnection> m_allSockets = new List<IWebSocketConnection>();

Send UI的功能是发动图片到web browser,代码如下:

        private void btnSendUI_Click(object sender, EventArgs e)
        {
            {
                foreach (var socket in m_allSockets.ToList())
                {
                    //socket.Send(input);
                    Byte[] image = imgLittleKit.ImageToBytes(Properties.Resources.play_solid);
                    string btnID = "btnPlay";
                    SendUIDat(image, btnID,socket);

                    image = imgLittleKit.ImageToBytes(Properties.Resources.skip_previous);
                    btnID = "btnPrev";
                    SendUIDat(image, btnID, socket);
                    //socket.Send(dat);
                    image = imgLittleKit.ImageToBytes(Properties.Resources.skip_next);
                    btnID = "btnNext";
                    SendUIDat(image, btnID, socket);

                    image = imgLittleKit.ImageToBytes(Properties.Resources.volume_down_solid);
                    btnID = "btnVDown";
                    SendUIDat(image, btnID, socket);
                    image = imgLittleKit.ImageToBytes(Properties.Resources.volume_up_solid);
                    btnID = "btnVUp";
                    SendUIDat(image, btnID, socket);

                    image = imgLittleKit.ImageToBytes(Properties.Resources.closedcaption);
                    btnID = "btnSubOff";
                    SendUIDat(image, btnID, socket);

                }
                //input = Console.ReadLine();
            }

        }

发送图片和标识的简单思路:
将标识(String)和图片转换为byte数组发送到web,web方进行解码处理。
imgLittleKit.ImageToBytes函数的代码如下,其功能是将各种格式的图片转换为byte[].

        //from https://www.cnblogs.com/luxiaoxun/p/3378416.html
        public static byte[] ImageToBytes(Image image)
        {
            ImageFormat format = image.RawFormat;
            using (MemoryStream ms = new MemoryStream())
            {
                //image.Save(ms, ImageFormat.MemoryBmp);
                if (format.Equals(ImageFormat.Jpeg))
                {
                    image.Save(ms, ImageFormat.Jpeg);
                }
                else if (format.Equals(ImageFormat.Png))
                {
                    image.Save(ms, ImageFormat.Png);
                }
                else if (format.Equals(ImageFormat.Bmp))
                {
                    image.Save(ms, ImageFormat.Bmp);
                }
                else if (format.Equals(ImageFormat.Gif))
                {
                    image.Save(ms, ImageFormat.Gif);
                }
                else if (format.Equals(ImageFormat.Icon))
                {
                    image.Save(ms, ImageFormat.Icon);
                }
                else if (format.Equals(ImageFormat.MemoryBmp))
                {
                    image.Save(ms, ImageFormat.Jpeg);
                }

                byte[] buffer = new byte[ms.Length];
                //Image.Save()会改变MemoryStream的Position,需要重新Seek到Begin
                ms.Seek(0, SeekOrigin.Begin);
                ms.Read(buffer, 0, buffer.Length);
                return buffer;
            }
        }

SendUIDat(image, btnID, socket); 函数的代码如下:

        private static  void SendUIDat(byte[] image, string btnID,IWebSocketConnection socket        )
        {
            byte[] headArr = new byte[10];

            byte[] imgIDArr = System.Text.Encoding.ASCII.GetBytes(btnID);


            byte[] dat = new byte[headArr.Length + image.Length];
            //form the  byte array to be sent to the clinet , headID and the image ;
            Buffer.BlockCopy(imgIDArr, 0, headArr, 0, imgIDArr.Length);
            headArr[btnID.Length] = 32;// the end of the string , space 
            Buffer.BlockCopy(headArr, 0, dat, 0, headArr.Length);
            Buffer.BlockCopy(image, 0, dat, headArr.Length, image.Length);
            socket.Send(dat);
        }

此时,C#放的代码已经结束了,发送过去的是二进制数字流。

web方的js代码如下,Socket的握手代码

         function ConnectSvr() {
			//init();

            var ip = HostIP.value;//界面录入的IP地址
			if(ip==''){
				alert('Input the IP address please. CLick on the [ip] button on the playter to get it.');
				return;
			}
            var inc = document.getElementById('incomming');
            var wsImpl = window.WebSocket || window.MozWebSocket;
            var form = document.getElementById('sendForm');
            var input = document.getElementById('sendText');

            inc.innerHTML = "Connecting to the Host ";
			inc.style.color = "Black";

            // create a new websocket and connect
			var connStr = 'ws://'+ip+':58888';
            window.ws = new wsImpl(connStr);
			//wsImpl.binaryType = 'arraybuffer'; 

            // when data is comming from the server, this method is called
            ws.onmessage = function (e) {

				//var imgDat = evt.data; // 获取用户接收到的消息数据,为一个ArrayBuffer对象
				
                inc.innerHTML = e.data + '<br/>';
				inc.style.color = "Green";
				
				if(e.data=="[object Blob]"){
					var blob = e.data;//blob 
					
					var  headBlob = blogSlice(blob,0,10);//取前10个字节,解码得到标识
					var blobImg = blogSlice(blob,10,blob.size);//10 开始是传递的图像
					var imgID ="Null";
					var reader = new FileReader();
					reader.onload = function(event){
						str = reader.result;//内容就在这里
						var imgID = str.substr(0,str.lastIndexOf(" "));  //截取最后一个点号后4个字符
						
						//alert(imgID);
						
						const imgUrl =URL.createObjectURL(blobImg);//生成图像链接,Chrome 可用。
						//alert(imgUrl);
						var btn = document.getElementById(imgID);
						if(btn!=null){
							if(imgID=="VImg"){
								document.getElementById('VImg').src=imgUrl;//显示图像
							}else{
							btn.style="background:url(" +imgUrl+");background-position:center;background-repeat:no-repeat;width:100px;height:10%;";
							btn.innerHTML = "";
							}
						}

					  };
					  reader.readAsText(headBlob);
  
					
				}

				
            };

            // when the connection is established, this method is called
            ws.onopen = function () {
                inc.innerHTML = 'Connected to the Host.';
				inc.style.color = "Green";
            };

            // when the connection is closed, this method is called
            ws.onclose = function () {
                inc.innerHTML = 'Disconnected from the Host.';
				inc.style.color = "Red";
            }
        }


程序中用到的另一个函数,其功能是截取blob中的字节。

	function blogSlice( blob,start,end ){
			if( blob.slice ){
				return blob.slice(start,end)
			}else if( blob.webkitSlice ){
				  return blob.webkitSlice(start,end)
			}else if( blob.mozSlice ){
				return blob.mozSlice(start,end)         
			}else{
				  return null
			}
		}

说明上面是demo,不是手机上界面更新的真实代码,因为真实代码比较复杂。

效果如下:
手机初始化界面:
初始界面
建立连接后,电脑端将图片发送过来,界面变成
在这里插入图片描述
这样就完成了一个简单手机控制器的生成。

另:播放器界面如下
在这里插入图片描述

以上代码涉及的东西还是比较多和凌乱的,如果认为对你有用,请尽情使用。如果有疑问,可以提出,我会给出解释。

马拉孙 于 泛五地区
2021–4-22

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: WebSocketHTML5新的通信技术,能够实现浏览器与服务器之间的实时双向通信。而websocket视频播放,则是通过WebSocket技术在前端页面上实现视频播放功能。 WebSocket技术相比传统的HTTP协议,具有更高的实时性和更低的延迟,因此在视频播放场景下应用广泛。首先,WebSocket能够实现实时传输视频流,不必等待整个视频文件下载完毕即可开始播放。其次,WebSocket的双向通信能力,能够实现服务器对客户端的即时响应,让视频播放更加流畅。 在实现websocket视频播放的过程中,需要通过WebSocket API建立WebSocket连接,并通过该连接向服务器发送请求,获取视频流。同时,前端也需要在页面上渲染视频播放器,并将获取到的视频流传递给播放器进行播放。为了保证播放流畅,还需要对视频流进行编码和解码等优化处理。 总的来说,websocket视频播放技术能够让用户在前端页面上实现高质量的视频播放体验,对于在线教育、直播等场景都具有广泛的应用前景。 ### 回答2: WebSocket 视频播放是一种通过 WebSocket 技术实现的实时视频传输和播放方式。WebSocket 是一种全双工通信协议,能够在客户端和服务器之间建立持久性的连接,实现即时通信。 在传统的视频播放方式中,客户端需要通过向服务器发送请求来获取视频数据,并且每次请求只能获取一部分数据。而在 WebSocket 视频播放中,客户端与服务器之间建立的连接可以保持持久性,视频数据可以实时地通过该连接进行传输和播放WebSocket 视频播放的基本原理是,客户端通过 WebSocket 协议与服务器建立连接,并发送视频播放请求。服务器接收到请求后,会向客户端实时传输视频数据。客户端通过接收到的视频数据进行解码和播放,以实现视频的实时播放效果。 WebSocket 视频播放具有如下优点: 1. 实时性:WebSocket 建立的持久连接可以保持客户端与服务器之间的实时数据传输,使得视频播放更加流畅。 2. 效率高:WebSocket 传输数据的方式更加高效,相比传统的请求-响应方式能够更快地获取数据。 3. 节省带宽:在 WebSocket 播放中,数据是通过持久连接实时传输的,不需要每次请求都重新建立连接,因此减少了连接建立和关闭的开销,节省了带宽。 4. 支持双向通信:WebSocket 可以实现客户端与服务器之间的双向通信,方便在播放过程中进行视频控制、错误处理等操作。 总之,WebSocket 视频播放通过建立持久连接,实时传输视频数据,提升了视频播放的流畅性和效率,是一种现代化的视频播放方式。 ### 回答3: WebSocket 是一种网络通信协议,可以在客户端和服务器之间实现实时的双向通信。在视频播放方面,使用 WebSocket 可以实现实时的视频流传输和播放控制。 通常情况下,视频播放是通过客户端向服务器请求视频文件,并通过 HTTP 下载完成后在客户端进行播放。但是,这种方式在实时视频播放场景下存在延迟较高的问题,无法满足实时性要求。 而使用 WebSocket 来进行视频播放,可以通过流式传输的方式将视频数据以实时的方式传输给客户端,实现低延迟和实时性的视频播放。客户端和服务器通过 WebSocket 建立长连接,实现双向的实时数据传输。 具体实现方式可以是,客户端向服务器发送视频播放请求,并建立 WebSocket 连接。服务器收到请求后,开始传输视频流给客户端。客户端收到视频流后,通过特定的视频播放器进行解码和播放。同时,客户端可以通过 WebSocket 向服务器发送控制指令,如播放、暂停、快进等操作。 使用 WebSocket 进行视频播放可以减少网络延迟,并且可以与服务器进行实时的交互,提供更好的用户体验。此外,WebSocket 还具有跨平台和跨浏览器的优势,可以在各种设备和浏览器上实现视频播放功能。 总之,使用 WebSocket 进行视频播放可以实现实时性和低延迟的视频传输,并且可以实现与服务器的实时交互,提供更好的用户体验。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值