1 Востаннє редагувалося Юрій Ляхор (18.02.2015 12:42:51)

Тема: Потокова передача відео з Web камери використовуючи UDP протокол

Вирішив написати шпигунчика, котрий би спостерігав за тим, що коїться у моїй кімнаті, поки мене не має вдома, передаючи відео сигнал на інший комп'ютер, а в майбутньому і на смартфон. У інтернеті порадили використовувати бібліотеки AForge, так, як у Framework немає бібліотек для роботи з відео.

Програма працює справно доти, доки діло не заходить до передачі відео зображення.
Як я тільки не переписував udp.Send там постійно вилітають якісь "Socket Exception"

Допоможіть мені з цим розібратись.

Клієнт:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.IO;
using AForge.Video;
using AForge.Video.DirectShow;

namespace FClient
{
    public partial class Client : Form
    {
        public Client()
        {
            InitializeComponent();
        }
        private void button1_Click(object sender, EventArgs e)               // Кнопка "Connect"
        {
            tcpclient_connect();
        }
        private void button2_Click(object sender, EventArgs e)              // Кнопка "Watch"
        {
            tcpclient_watch();
        }
        public TcpClient tcpClient = new TcpClient();                         //TcpClint
        public static IPAddress IP = IPAddress.Parse("127.0.0.1");
        public static IPEndPoint ipEndPoint = new IPEndPoint(IP, 5001);


        private void tcpclient_connect()
        {
            try
            {
                if (tcpClient.Connected == false)
                    tcpClient.Connect(ipEndPoint);
                NetworkStream NS = tcpClient.GetStream();                   //NetworkStream
                StreamReader SR = new StreamReader(NS);
                StreamWriter SW = new StreamWriter(NS);
                SW.WriteLine("Запит");
                SW.Flush();
                comboBox1.Items.Clear();
                while (true)
                {
                    string WebCams = SR.ReadLine();
                    if (WebCams == "Stop") break;
                    comboBox1.Items.Add(WebCams);
                }
                comboBox1.SelectedIndex = 0;
            }
            catch (SocketException ex)
            {
                MessageBox.Show(ex.ToString(), "Помилка", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void tcpclient_watch()
        {
            try
            {
                NetworkStream NS = tcpClient.GetStream();                     //NetworkStream
                StreamReader SR = new StreamReader(NS);
                StreamWriter SW = new StreamWriter(NS);
                SW.WriteLine(comboBox1.SelectedIndex);
                SW.Flush();
                SW.WriteLine("VideoStreaming");
                SW.Flush();

                IPEndPoint RemoteIPEndPoint = null;
                //UdpClient udp = new UdpClient(5003);
                Socket udp = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                //byte[] bVideo = udp.Receive(ref RemoteIPEndPoint);
                byte[] bVideo = new byte[458500];
                byte[] bPiece = new byte[65500];
                for (int i = 0; i < 7; i++)
                {
                    udp.Receive(bPiece, 65500, SocketFlags.None);                //(ref RemoteIPEndPoint);
                    bVideo = bVideo.Concat(bPiece).ToArray();
                }
                Bitmap Video = ConvertToBitmap(bVideo);
                pictureBox1.Image = Video;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Помилка", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        private static Bitmap ConvertToBitmap(byte[] imagesSource)
        {
            var imageConverter = new ImageConverter();
            var image = (Image)imageConverter.ConvertFrom(imagesSource);
            return new Bitmap(image);
        }

    }
}

Сервер:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using AForge.Video;
using AForge.Video.DirectShow;
using System.Reflection;
using System.Diagnostics;
using System.IO;
using System.Drawing;

namespace UDP
{
    class Server
    {
        //private UdpClient udp = new UdpClient();
        private Socket udp = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        public static void Main(string[] args)
        {
            try
            {
                VideoCaptureDevice FinalVideo;
                FilterInfoCollection VideoCaptureDevices = null;
                int Moniker;

                while (true)
                {
                    IPAddress connectedIP = IPAddress.Any;
                    TcpListener listener = new TcpListener(connectedIP, 5001);
                    listener.Start();

                    Console.WriteLine("Сервер ожидает {0}", listener.LocalEndpoint);
                    Socket serverSocket = listener.AcceptSocket();

                    Console.WriteLine(connectedIP);

                    NetworkStream NS = new NetworkStream(serverSocket);
                    StreamReader SR = new StreamReader(NS);
                    StreamWriter SW = new StreamWriter(NS);
                    Console.WriteLine("Принято соединение ...");
                    string Code = SR.ReadLine();
                    Console.WriteLine(Code);
                    if (Code == "Запит")
                    {
                        List<string> WeBCams = new List<string>();
                        VideoCaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
                        foreach (FilterInfo VideoCaptureDevice in VideoCaptureDevices)
                        {
                            WeBCams.Add(VideoCaptureDevice.Name);
                        }
                        for (int i = 0; i < WeBCams.Count; i++)
                        {
                            SW.WriteLine(WeBCams[i]);
                            SW.Flush();
                            Console.WriteLine(WeBCams[i]);
                        }
                        SW.WriteLine("Stop");
                        SW.Flush();
                    }
                    Moniker = Convert.ToInt32(SR.ReadLine());
                    Console.WriteLine(Moniker);

                    string VideoStreaming = SR.ReadLine();
                    Console.WriteLine(VideoStreaming);
                    serverSocket.Close();
                    Console.WriteLine("Begin " + VideoStreaming);
                    if (VideoStreaming == "VideoStreaming")
                        break;
                }
                FinalVideo = new VideoCaptureDevice();
                if (FinalVideo.IsRunning) FinalVideo.Stop();
                FinalVideo = new VideoCaptureDevice(VideoCaptureDevices[Moniker].MonikerString);
                FinalVideo.NewFrame += new NewFrameEventHandler(FinalVideo_NewFrame);
                FinalVideo.Start();
            }
            catch (SocketException ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        private void udpSend(byte[] cadr)
        {
            IPAddress IP = IPAddress.Parse("127.0.0.1");
            udp.Connect(IP, 5003);
            for (int i = 0; i <= 458500; i = i + 65500)
            {
                udp.Send(cadr, i, 65500, SocketFlags.None);
            }
        }

        private static void FinalVideo_NewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            Bitmap Video = (Bitmap)eventArgs.Frame.Clone();
            byte[] Cadr = GetBytesOfImage(Video);
            Server sr = new Server();                                      // Доступ нестатичного методу до статичного
            sr.udpSend(Cadr);
        }
        public static byte[] GetBytesOfImage(Bitmap video)
        {
            ImageConverter converter = new ImageConverter();
            return (byte[])converter.ConvertTo(video, typeof(byte[]));
        }
    }
}

Файл проекту у Visual Studio 2013

Post's attachments

UDP.rar 386.53 kb, 185 downloads since 2015-02-18 

Подякували: 0xDADA11C71

2

Re: Потокова передача відео з Web камери використовуючи UDP протокол

1) Що виводить в ex.ToString() (сервер, 81 рядок)?
2) Замініть ToString на ErrorCode, що буде в результаті?

3

Re: Потокова передача відео з Web камери використовуючи UDP протокол

quez написав:

1) Що виводить в ex.ToString() (сервер, 81 рядок)?
2) Замініть ToString на ErrorCode, що буде в результаті?

саме там помилки не видає.
помилка у 90 рядку:
Исключение типа "System.ArgumentOutOfRangeException" возникло в System.dll, но не было обработано в коде пользователя

Дополнительные сведения: Specified argument was out of the range of valid values.

4 Востаннє редагувалося quez (18.02.2015 13:45:34)

Re: Потокова передача відео з Web камери використовуючи UDP протокол

Так ви ж пишете, що SocketException кидає.

msdn написав:

ArgumentOutOfRangeException   

Значение параметра offset меньше 0.

-или-

Длина значения offset больше, чем длина buffer.

-или-

Значение параметра size меньше 0.

-или-

Значение параметра size больше разности значений длины в параметре buffer и значения параметра offset.

перевіряйте

5

Re: Потокова передача відео з Web камери використовуючи UDP протокол

По ходу "Длина значения offset больше, чем длина buffer."

Виходить мій алгоритм відправки одного масиву байтів пакетами лажовий.
Допоможіть мені реалізувати це місце якимось іншим способом.

По суті мені треба оминути ліміт максимального розміру пакету у 65535 байтів, відправити масив частинами, а потім у клієнті склеїти.

6

Re: Потокова передача відео з Web камери використовуючи UDP протокол

А якщо 90-тий рядок

udp.Send(cadr + i, 0, 65500, SocketFlags.None);

7

Re: Потокова передача відео з Web камери використовуючи UDP протокол

yarko написав:

А якщо 90-тий рядок

udp.Send(cadr + i, 0, 65500, SocketFlags.None);

Шта?
Навіщо до масиву з байтами додавати лічильник?

8

Re: Потокова передача відео з Web камери використовуючи UDP протокол

Не до масиву з байтами, а до вказівника на початок масиву.
Для функції Send це означатиме читати блок розміром 65500 байт, починаючи з i-ої позиції.
Принаймні в плюсах така конструкція цілком коректна. Хз як в шарпі..

9

Re: Потокова передача відео з Web камери використовуючи UDP протокол

Юрій Ляхор написав:

По ходу "Длина значения offset больше, чем длина buffer."

Виходить мій алгоритм відправки одного масиву байтів пакетами лажовий.
Допоможіть мені реалізувати це місце якимось іншим способом.

По суті мені треба оминути ліміт максимального розміру пакету у 65535 байтів, відправити масив частинами, а потім у клієнті склеїти.

Звідки взялося число 458500? Цілком логічна межа для нього - cadr.Length.

for(int i = 0; i < cadr.Length; i += 65500){
    int offset = i < cadr.Length ? i : cadr.Length - 1;
    int size = cadr.Length - offset < 65500 ? cadr.Length - offset : 65500;
    udp.Send(cadr, offset, size, SocketFlags.None);
}
Подякували: Юрій Ляхор1

10 Востаннє редагувалося Юрій Ляхор (18.02.2015 17:47:36)

Re: Потокова передача відео з Web камери використовуючи UDP протокол

Звідки взялося число 458500? Цілком логічна межа для нього - cadr.Length.

for(int i = 0; i < cadr.Length; i += 65500){
    int offset = i < cadr.Length ? i : cadr.Length - 1;
    int size = cadr.Length - offset < 65500 ? cadr.Length - offset : 65500;
    udp.Send(cadr, offset, size, SocketFlags.None);
}

Ухти дякую, а як потім це правильно зібрати у клієнті?

11

Re: Потокова передача відео з Web камери використовуючи UDP протокол

Тут треба з протоколом розбиратись, навряд чи я вам в цьому допоможу.