程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WPF+WCF一步一步打造音頻聊天室(四):視頻會話

WPF+WCF一步一步打造音頻聊天室(四):視頻會話

編輯:關於.NET

前面三篇文章中,我實現了音頻聊天室的部分功能,包括:文字聊天,共享白板,語音聊天。這篇文章我將敘述一下視頻會話實現的技 術要點。

在Silerlight4中已經集成了攝像和采集聲音的功能,但是在WPF4中卻沒有直接可以用的的控件,由此也可以看出,由桌面程序走向web 程序的大趨勢。如果你想用Silverlight實現類似的音頻聊天室,下面我列出一些資料供你參考。

1、 Your First Step to the Silverlight Voice/Video Chatting Client/Server:

http://www.codeproject.com/KB/silverlight/SilverlightVoiceVideoChat.aspx

2、Accessing Web Camera and Microphone:

http://www.silverlight.net/learn/videos/all/access-web-camera-microphone/

3、Record The Audio Into A Wave File:

http://cspeex.codeplex.com/

4、Playback The Wave File in Silverlight:

http://blogs.msdn.com/gillesk/archive/2009/03/23/playing-back-wave-files-in-silverlight.aspx

5、Using the G.711 Codec:

http://www.codeproject.com/KB/security/g711audio.aspx

6、convert encode and decode silverlight:

http://kodierer.blogspot.com/2009/11/convert-encode-and-decode-silverlight.html

上面是Silverlight實現的方案和資料。這篇文章是用WPF+WCF去實現的。列出Silerlight是方便大家有個對照。

視頻會話實現的方式和語音通話實現的方式是一樣的。他們之間不一樣的地方在於,一個是通過麥克風獲取數據,一個是通過攝像頭獲 取數據。下面我用WF4畫了一個流程圖(這個流程圖只是為了說明問題,沒有用到程序裡面)。

實現

前面 說到了,WPF中沒有像Silerlight一樣集成了攝像的功能,在WPF中又如何去實現攝像呢?這也是首先要解決的問題,我經過一番google, 在Codeplex上找到了一個開源WPF的Webcam控件。地址是:WebCam control for WPF。

添加一個窗體,在這個窗體上使用這個控件 ,布局如下。

注意:左邊是本機的視頻,右邊是對方的視頻。修改窗體的構造函數;

private IPEndPoint _serverEndPoint;
        private UdpClient _socket;
        public WebcamPlayerForm(IPEndPoint serverEndpoint,  string caller, string callee)
        {
        }

與語音聊天一樣,數據傳遞我使 用了UdpClient,我感覺UdpClient簡單好用。_serverEndPoint是WCF服務的地址,_socket用於視頻數據傳遞。在客戶端我使用了兩個 System.Windows.Threading.DispatcherTimer,本來打算直接使用兩個線程,發現一些莫名奇妙的線程問題。兩個DispatcherTimer,一個 用來啟動接受來自WCF服務的視頻數據,一個用來將自己的視頻數據發送到WCF服務。代碼如下:

System.Windows.Threading.DispatcherTimer myDispatcherTimer = new  System.Windows.Threading.DispatcherTimer();
            myDispatcherTimer.Interval = new TimeSpan(0,  0, 0, 0, 1000);
            myDispatcherTimer.Tick += new EventHandler(captureVideo);
             myDispatcherTimer.Start();
            System.Windows.Threading.DispatcherTimer  myDispatcherTimer2 = new System.Windows.Threading.DispatcherTimer();
             myDispatcherTimer2.Interval = new TimeSpan(0, 0, 0, 0, 1000);
            myDispatcherTimer2.Tick  += new EventHandler(playVideo);
            myDispatcherTimer2.Start();

captureVideo用於從攝像頭捕獲數據通過UdpClient發送到WCF服務中,代碼如下。

private void captureVideo(object sender, EventArgs e)
         {
             try
             {
                     byte[] bytes;
                     if (webcamPlayer.CurrentBitmap != null)
                     {
                         bytes = ConvertImageSourceToByteArray (webcamPlayer.CurrentBitmap);//webcamPlayer.CurrentBitmap
                         _socket.Send(bytes, bytes.Length, _serverEndPoint);
                     }

             }
             catch (Exception) { }
         }

上面的captureVideo方法將視頻數據先轉發到WCF服務,在由WCF服務轉發給對方,在WCF服務中有一個UdpClient接受數據,方法是 listen(),它的代碼如下:

private void listen()
         {
             try
             {
                 while (true)
                 {

                     IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
                     //if (sender.ToString() != "0.0.0.0:0")
                     //{
                         byte[] received = UdpListener.Receive(ref sender);
                         if (!_users.Contains(sender))
                         {
                             _users.Add(sender);
                         }
                         foreach (IPEndPoint endpoint in _users)
                         {
                             if (!endpoint.Equals(sender))
                             {
                                 _udpSender.Send(received, received.Length,  endpoint);
                             }
                         }
                     //}
                 }
             }
             catch (Exception e)
             {

            }
             }

WCF服務中的listen()方法將接收到的數據發送給對方的客戶端,在客戶端有playVideo方法來接收和並播放來自WCF的視頻數據,代碼 如下:

private void playVideo(object sender, EventArgs e)
         {

             try
             {
                     lock (_socket)
                     {
                         if (_socket.Available != 0)
                         {
                             IPEndPoint endpoint = new IPEndPoint(IPAddress.Any,  0);
                             byte[] received = _socket.Receive(ref endpoint);
                             image1.Source = ConvertByteArrayToImageSource(received);
                         }
                 }
             }
             catch
             {

             }
         }

由於從攝像頭獲取的數據格式是ImageSource,我們需要將它轉換成byte[]傳輸,轉換的代碼如下:

/// <summary>
         /// Converts an <see cref="ImageSource"/> to an array of bytes.
         /// </summary>
         /// <param name="image"><see cref="ImageSource"/> to convert.</param>
         /// <returns>Array of bytes.</returns>
         public  byte[] ConvertImageSourceToByteArray( ImageSource image)
         {
             // Declare variables
             byte[] result = null;
             // Use a memory stream to convert
             using (MemoryStream memoryStream = new MemoryStream())
             {
                 // Get right encoder
                 JpegBitmapEncoder encoder = new JpegBitmapEncoder();
                 // Get right frame
                 if (image is BitmapSource)
                 {
                     encoder.Frames.Add(BitmapFrame.Create((BitmapSource)image));
                 }
                 // Now set some encoder values
                 encoder.QualityLevel = 100;
                 encoder.Save(memoryStream);
                 // Now convert
                 result = memoryStream.ToArray();
             }
             // Return result
             return result;
         }

從WCF服務收到到的數據是byte[] 格式,我們需要將其轉換成ImageSource,代碼如下:

/// <summary>
         /// Converts an array of bytes to a <see cref="ImageSource"/>.
         /// </summary>
         /// <param name="bytes">Bytes to convert.</param>
         /// <returns><see cref="ImageSource"/>.</returns>
         public ImageSource ConvertByteArrayToImageSource(byte[] bytes)
         {
             // Declare variables
             ImageSource result = null;
             // Validate input
             if (bytes.Length == 0) return null;
             // Create memory stream - it seems that if you clean up or dispose 
             // the memory stream, you cannot display the image any longer
             MemoryStream memoryStream = new MemoryStream(bytes);
             // Assign to bitmap image
             BitmapImage bitmapImage = new BitmapImage();
             bitmapImage.BeginInit();
             bitmapImage.StreamSource = memoryStream;
             bitmapImage.EndInit();
             // Assign bitmap to image source
             result = bitmapImage;
             // Return result
             return result;
         }

在前面文章的的基礎上完成這些操作,我們就可以實現視頻會話的功能。

效果:

1、選擇跟小花視頻:

2、小花接受到請求:

3、視頻中:

上圖是我在一台電腦上演示的,所以只有一邊顯示數據。但是,我用兩台筆記本測試過,效果也還不錯。

總結:

主要用到的技術有;WCF、WPF、UDPClient。還使用了一個開源的控件WebCam control for WPF。這個程序調試了我一天的時間。

由於博客的空間不夠用,過段時間整理好,會將代碼上傳到Codeplex上。

出處:http://zhuqil.cnblogs.com

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved