自己在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
转载:https://blog.csdn.net/Uman/article/details/116032676