Silverlight+WCF 实战-网络象棋最终篇之对战视频-上篇[客户端开启视频/注册编号/接收视频](五)

前言:


近期在忙点“秋色园”的事情,所以网络象棋这一块文章就写的相对慢,而且刚好接上篇:Silverlight+WCF 实战-网络象棋最终篇之非线程阻塞倒计时窗口(四)  之后,

是一些代码修改,会比较枯燥,所以没接着写,不过有昨天有网页表示对象棋在线演示中的 对战视频 感兴趣,希望可以提前看到代码,所以本次就提前写里面的对战视频这一块。

由于对战视频采用控制台程序,并没有在服务器运行,所以在线演示版本里一进入显示是显示“未链接”的提示。

作者:路过秋天 博客:http://cyq1162.cnblogs.com/

 

 一:对战视频 简单原理:

1:由于Silverlight不支持点对点方式传输,因此只能通过服务器中转方式进行。

2:视频的传输是图片字节,因此压缩图片是相当必要的。

3:中间的服务选什么?一开始我是在尝试使用WCF的tcp方式,后来折腾配置文件太痛苦,直接转使用Socket通讯,一来有性能优势,二来减少折腾。

 

二:对战视频 步骤解析:

1:客户端打开视频

2:客户端向远端Socket注册[按规则定好的]编号[服务端根据编号查要转发的对象]

3:服务端接收编号并注册,收集一系列编号列表。

4:客户端发送视频

5:服务端接收视频,并根据规则查找另一个编号,将视频字节转发

6:另一个客户端接收视频并显示

 

三:对战视频 具体实施

 

1:如何打开视频

在Siverlight中打开视频相当的简单,都有注释,就不多解说了

代码如下:


        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]
            }
        }

界面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:与远程建立链接:


       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)//链接完成后
        {
           //这里要写点什么呢?
        }

 

2.2:注册编号[这里的规则是“房间号+棋手颜色值”]


        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)
        {  
           //号码发送过去了,接下这里干点什么呢?
        }

 

2.3:开新线程,等待接收对方视频


       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)
        {
            //如果收到视频,我们要怎么处理呢?            
        }

 

2.4:将视频显示出来,需要用主线程来操作


        SynchronizationContext syn=SynchronizationContext.Current;//获取当前主线程
        void receiveEvent_Completed(object sender, SocketAsyncEventArgs e)
        {
           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
            {
                return;
            }
            finally
            {
                if (stream != null)
                {
                    stream.Close();
                }
                if (img != null)
                {
                    img = null;
                }
            }
        }

上面的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

时间: 2024-11-01 07:10:56

Silverlight+WCF 实战-网络象棋最终篇之对战视频-上篇[客户端开启视频/注册编号/接收视频](五)的相关文章

Silverlight+WCF 实战-网络象棋最终篇之对战视频-下篇[客户端发送与服务端中转](六)

本篇继上一篇:Silverlight+WCF 实战-网络象棋最终篇之对战视频-上篇[客户端开启视频/注册编号/接收视频](五)    一:对战视频 简单原理 略,内容见上篇.   二:对战视频 步骤解析: 略,内容见上篇.   三:对战视频 具体实施 1:如何打开视频 略,内容见上篇.   2:Silverlight如何使用Socket进行通讯 2.1:与远程建立链接: 2.2:注册编号[这里的规则是"房间号+棋手颜色值"] 2.3:开新线程,等待接收对方视频 2.4:将视频显示出来,

Silverlight+WCF 实战-网络象棋最终篇之房间装修-Silverlight端[带第九阶段源码](三)

在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 上一系列四十篇索引:Silverlight+WCF 新手实例 象棋 专题索引     本篇紧接着上一篇:Silverlight+WCF 实战-网络象棋最终篇之房间装修-WCF端(二) 继续为房间进行如下的装修:   代码实现[Silverlight端] 说明: 由于更换背景引入图片,房间的属性发生了较大的变化,由此引发了客户端房间类较大的改动.     1:Silverlight端:GameRoom类大调整[被注释的是原来的

Silverlight+WCF 实战-网络象棋最终篇之解决重复的消息提示-状态重置(九)

上节留下的问题: 在上一节:Silverlight+WCF 网络象棋 终极篇 解决重复的消息提示(八) 中,我们解决了重复登陆时产生的多次消息的重复提示. 不过由此优化产生的另一个问题:全局只有一个实例,在来回的切换房间或进出时,需要重置状态,我们这节来解决这个问题.     在上节的,我留下了几行这样的注释代码: //loginObj.Reset();//roomObj.Reset();//indexObj.Reset();   本节就顺路把这三个注册的方法给实现了: 1:loginObje.

Silverlight+WCF 实战-网络象棋最终篇之房间装修-WCF端(二)

在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 上一系列四十篇索引:Silverlight+WCF 新手实例 象棋 专题索引   佛靠金装,人要衣裳,房间也要加金砖.本篇我们来把房间装修下,让它看起来专业一点!   一:效果预览,先上图   这是之前的房间图片: 今天我们要装修成的房间图片: 再上一张游戏中的效果图:   二:实现说明   1:新增加图片 为了实现装修,我这里新增加了3张图片: 1:房间图片 2:房间游戏中状态的图片 3:QQ用户头像 图片是从QQ象棋游戏

Silverlight+WCF 实战-网络象棋最终篇之十字轨迹(一)

前言 继之前Silverlight+WCF 新手实例 象棋系列四十篇之后,一个多月的时间都在写CYQ.Data框架系列[CYQ.Data 轻量数据层之路 框架开源系列 索引], 让各位对该Silverlight+WCF 象棋系列有兴趣的网友久候了,上一系列详见:[Silverlight+WCF 新手实例 象棋 专题索引] 今天开始就在之前四十篇续上,直到把 [Silverlight+WCF 新手实例 象棋 在线演示] 上的最新代码写完,谢谢支持!   乱七杂八说两句: 一个多月没碰VS2010了

Silverlight+WCF 实战-网络象棋最终篇之非线程阻塞倒计时窗口(四)

前言: 在前面的系列中,我们虽然完成了其大部分功能,但是,离正真运行,还是有一大段距离 当你F5运行时,在弹出对话框之后,如果你不即时点确定,或者上个WC回来之后,你会发现已经提示出错了 这节开始,我们将对其进行一小步一小步的优化,来避免一些明显容易引发的错误.   感知一下最原始的消息弹出框如下图:     一:传统消息框,容易引发命案   1:原始的消息框,是线程阻塞类型的,很容易引发超时问题 线程阻塞?怎么理解? 简单的说就是,WCF服务端给客户端发送了消息提示之后,一直进入等待状态,直到

Silverlight+WCF 实战-网络象棋最终篇之解决重复的消息提示(八)

前言: 最近有网友经常会问,在跟着做象棋对战的通讯中,在重复退出进入的时候,消息会重复出现,本节就这问题进行解说与优化.   一:分析问题产生的原因?   1:首先看App.xaml,里面定义了一个全局客户端回调: public static GameService.ServiceClient client;//回调的客户端   并且这个回调我们全局只实例化一次,并且默认加载时定位到登陆页面: private void Application_Startup(object sender, Sta

Silverlight+WCF 新手实例 象棋 主界面-事件区-游戏开始(二十七)

本专题出产简单原由: 一开始的初衷,只是想写个简单的单机BS人机对战版的,开始还下了点AI算法看看的: 但是写到最后,都写成了通讯版本的对战了,只因中间不小心看到了WCF的相关内容,顺便加了进来; 最后就定局了,反正新手实例,能加多点内容就加多点了. 关于原始初衷,后期再补上了.       好了,先上几个附加索引: 1:Silverlight+WCF 新手实例 象棋 在线演示 2:Silverlight+WCF 简单部署问题集 3:Silverlight4 ListBox bug 4:Silv

Silverlight+WCF 新手实例 象棋 主界面-事件区-求和认输(三十二)

在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示   事隔几篇,我们又回到事件区,继续其它两个按钮事件,来张图吧: 在Silverlight+WCF 新手实例 象棋 主界面-事件区-游戏开始(二十七) 和之后的几篇,我们实现了游戏开始, 在这篇之前,基本上双方已可以对战了,看似主体功能已完成.只是,大伙都知道,细节的东西,才是花时间的,漫长的路还在后面....... 如标题所示,这节实现"求和+认输"两个事件.   每次开始,我们都习惯的先写WCF服务端代码,再回