前言:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
由于对战视频采用控制台程序,并没有在服务器运行,所以在线演示版本里一进入显示是显示“未链接”的提示。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
1:由于silverlight不支持点对点方式传输,因此只能通过服务器中转方式进行。
2:视频的传输是图片字节,因此压缩图片是相当必要的。
3:中间的服务选什么?一开始我是在尝试使用wcf的tcp方式,后来折腾配置文件太痛苦,直接转使用socket通讯,一来有性能优势,二来减少折腾。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
1:客户端打开视频
2:客户端向远端socket注册[按规则定好的]编号[服务端根据编号查要转发的对象]
3:服务端接收编号并注册,收集一系列编号列表。
4:客户端发送视频
5:服务端接收视频,并根据规则查找另一个编号,将视频字节转发
6:另一个客户端接收视频并显示
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
1:如何打开视频
在siverlight中打开视频相当的简单,都有注释,就不多解说了
代码如下:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
private void btnstart_click(object sender, routedeventargs e)
{
videocapturedevice device = capturedeviceconfiguration.getdefaultvideocapturedevice();//获取系统默认视频设备
if (device == null)
{
messagebox.show("没有检测到设备!");
return;
}
if (capturedeviceconfiguration.requestdeviceaccess())//请求设备
capturesource source = new capturesource()//数据源
{
videocapturedevice = device//设置属性,将数据源绑定到视频
};
videobrush brush = new videobrush();//视频刷子
brush.setsource(source);//视频刷子从视频源获取视频
source.start();
myvideo.fill = brush;//最后填充rectangle [myvideo只是一个普通rectangle]
}
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
界面rectangle代码:
<canvas width="160" height="160" background="red" margin="22,109,518,531" name="canvideo">
<rectangle height="160" name="myvideo" stroke="black" strokethickness="1" width="160" canvas.left="0" canvas.top="0" />
</canvas>
运行后我们看下效果,[这里用了本地的虚拟视频,开了3个浏览器并排截了图,第4张是不一样的哦],中间提示确认是否打开视频就不截图了:
2:silverlight如何使用socket进行通讯
由于silverlight一般是不允许跨域通讯,因此,其socket通讯也要比普通的socket通讯麻烦一小点,不过这麻烦的小点只表现在服务端。
下面进行代码解析:以下代码将一步扣一步,具体的连环扣如下:建立链接-》注册编号-》开新线程待接收视频-》收到视频处理显示。
2.1:与远程建立链接:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
socket videosocket;//全局定义一个socket
private void btnsocketconn_click(object sender, routedeventargs e)
if (videosocket == null)//实例化socket
videosocket = new socket(addressfamily.internetwork, sockettype.stream, protocoltype.tcp);
socketasynceventargs socketevent=new socketasynceventargs()//通讯参数
remoteendpoint=new ipendpoint(ipaddress.parse("192.168.0.48"),4505),//设置连接的ip与端口
};
socketevent.completed += new eventhandler<socketasynceventargs>(socketevent_completed);
videosocket.connectasync(socketevent);//异步链接到远程
void socketevent_completed(object sender, socketasynceventargs e)//链接完成后
//这里要写点什么呢?
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
2.2:注册编号[这里的规则是“房间号+棋手颜色值”]
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
void socketevent_completed(object sender, socketasynceventargs e)
if (e.socketerror == socketerror.success)
byte[] buffer = system.text.encoding.utf8.getbytes("11");//我的编号,11=1房间+红色玩家1,对应的就是12=1房间+黑色玩家2
socketasynceventargs dataevent = new socketasynceventargs();
dataevent.setbuffer(buffer, 0, buffer.length);
dataevent.completed += new eventhandler<socketasynceventargs>(dataevent_completed);
videosocket.sendasync(dataevent);//发送号码到服务端注册
void dataevent_completed(object sender, socketasynceventargs e)
{
//号码发送过去了,接下这里干点什么呢?
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
2.3:开新线程,等待接收对方视频
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
void dataevent_completed(object sender, socketasynceventargs e)
system.threading.thread thread = new system.threading.thread(new system.threading.threadstart(receive));//开启线程
thread.start();
void receive()//接收视频处理
byte[] buffer = new byte[1024 * 1024];
while (true)
socketasynceventargs receiveevent = new socketasynceventargs();
receiveevent.setbuffer(buffer, 0, buffer.length);
receiveevent.completed += new eventhandler<socketasynceventargs>(receiveevent_completed);
videosocket.receiveasync(receiveevent);
system.threading.thread.sleep(50);//小小休眠一下,不要干活太累
void receiveevent_completed(object sender, socketasynceventargs e)
//如果收到视频,我们要怎么处理呢?
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
2.4:将视频显示出来,需要用主线程来操作
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
synchronizationcontext syn=synchronizationcontext.current;//获取当前主线程
byte[] data=e.buffer;
if (data[0]>0)
{
syn.post(setvideo, data);//由于新线程无法对控件进行操作,需要主线程来调用
}
}
void setvideo(object data)//设置视频
memorystream stream=null;
writeablebitmap img=null;
try
stream = new memorystream(data as byte[]);
img = new writeablebitmap(160, 160);
img.setsource(stream);
imgvideo.source = img;//直接赋下值,就设置好了。
catch
finally
if (stream != null)
stream.close();
}
if (img != null)
img = null;
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLlR2bjlHcvN2LcNXZnFWbp9CXt92YuM3ZvxmYuNmLu9Wbt92Yvw1LcpDc0RHaiojIsJye.gif)
上面的imgvideo为:
<image height="160" horizontalalignment="left" margin="207,109,0,0" name="imgvideo" stretch="fill" verticalalignment="top" width="160" />
至此,我们连续完成了“打开视频—》注册—》等待接收-》接收时开主线程显示”,我们提前看一下完成后接收时的效果图:
红色块是显示视频的区域,当前图片说明左侧没有开启视频,只是开了接收,右侧开了视频,并发送视频。
下面再顺路看一下开启的服务端中转socket的运行:
ok,本节就先到此,下节我们再讲“视频图片的压缩与发送”+服务端处理中转流程
最后:谢谢大家对本系列的喜欢,谢谢支持~
ps:传说点一下推荐会有10个园豆,喜欢麻烦点一下“推荐”,thank you very much!!
版权声明:本文原创发表于博客园,作者为路过秋天,原文链接:
http://www.cnblogs.com/cyq1162/archive/2010/12/01/1893583.html