如何在C#中从图像流传递视频流

8
我将尝试清楚地解释我的问题背景。
我有一个服务器从IP摄像头视频流中获取帧。我能够处理和编辑这些图像,但现在我需要再次传递这些图像作为视频流(MJPEG)。并不是必须要向每个人都提供流媒体,如果我现在可以通过TCP将流媒体发送给另一个客户端,那就足够了。
我不知道最佳方法是什么,因为我认为一次发送一张图片不是一个好的做法...有谁能在某种程度上帮助我吗?我从来没有处理过这种情况,而且我无法在Google上找到任何解决方案(可能是查询方式不对...)
你会如何处理它?

这取决于你的架构。这是PC对PC(因此是C#对C#)还是相机端更低级别?(C、C++、ASM等) - Nicolas Voron
摄像头正在流传,我可以通过RTSP或HTTP获取视频,因此摄像头体系结构不是问题。但我无法解决的是如何从我的服务器再次向客户端(C#到C#)流传。 - dnaranjo
2个回答

4
我发现了一个简单的CodeProject,可以执行非常类似的任务,即流式传输您的桌面。希望它也能对你有所帮助!

0

这是通过Tcp以最简单的方式发送图像作为视频流的方法。该方法可以发送和接收视频流。此方法基于Windows表单。

发送流(服务器):

    private void Start_Sending_Video_Conference(string remote_IP, int port_number)
    {
        try
        {

            ms = new MemoryStream();// Store it in Binary Array as Stream


            IDataObject data;
            Image bmap;

            //  Copy image to clipboard
            SendMessage(hHwnd, WM_CAP_EDIT_COPY, 0, 0);

            //  Get image from clipboard and convert it to a bitmap
            data = Clipboard.GetDataObject();

            if (data.GetDataPresent(typeof(System.Drawing.Bitmap)))
            {
                bmap = ((Image)(data.GetData(typeof(System.Drawing.Bitmap))));
                bmap.Save(ms, ImageFormat.Bmp);
            }


            picCapture.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
            byte[] arrImage = ms.GetBuffer();
            myclient = new TcpClient(remote_IP, 5000);//Connecting with server
            myns = myclient.GetStream();
            mysw = new BinaryWriter(myns);
            mysw.Write(arrImage);//send the stream to above address
            ms.Flush();
            mysw.Flush();
            myns.Flush();
            ms.Close();
            mysw.Close();
            myns.Close();
            myclient.Close();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "Video Conference Error Message", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }

接收流(客户端):

  private void Start_Receiving_Video_Conference()
    {
        try
        {

            // Open The Port
            mytcpl = new TcpListener(5000);
            mytcpl.Start();                      // Start Listening on That Port
            mysocket = mytcpl.AcceptSocket();        // Accept Any Request From Client and Start a Session
            ns = new NetworkStream(mysocket);    // Receives The Binary Data From Port

            picture_comming.Image = Image.FromStream(ns);
            mytcpl.Stop();                           // Close TCP Session

            if (mysocket.Connected == true)          // Looping While Connected to Receive Another Message 
            {
                while (true)
                {
                    Start_Receiving_Video_Conference();              // Back to First Method
                }
            }
            myns.Flush();

        }
        catch (Exception) { button1.Enabled = true; myth.Abort(); }
    }

非托管引用:

[System.Runtime.InteropServices.DllImport("user32", EntryPoint="SendMessageA")] 
    static extern int SendMessage(int hwnd, int wMsg, int wParam,  [MarshalAs(UnmanagedType.AsAny)] 
        object lParam); 
    [System.Runtime.InteropServices.DllImport("user32", EntryPoint="SetWindowPos")] 
    static extern int SetWindowPos(int hwnd, int hWndInsertAfter, int x, int y, int cx, int cy, int wFlags); 
    [System.Runtime.InteropServices.DllImport("user32")] 
    static extern bool DestroyWindow(int hndw); 
    [System.Runtime.InteropServices.DllImport("avicap32.dll")] 
    static extern int capCreateCaptureWindowA(string lpszWindowName, int dwStyle, int x, int y, int nWidth, short nHeight, int hWndParent, int nID); 
    [System.Runtime.InteropServices.DllImport("avicap32.dll")] 
    static extern bool capGetDriverDescriptionA(short wDriver, string lpszName, int cbName, string lpszVer, int cbVer);

在服务器上预览网络摄像头图像的方法

这个方法应该首先启动,以初始化网络摄像头的预览(在服务器端)。

    private void OpenPreviewWindow() 
    {
        int iHeight = 259;
        int iWidth = 369;
        // 
        //  Open Preview window in picturebox
        // 
        hHwnd = capCreateCaptureWindowA(iDevice.ToString (), (WS_VISIBLE | WS_CHILD), 0, 0, 640, 480, picCapture.Handle.ToInt32(), 0);
        // 
        //  Connect to device
        // 
        if (SendMessage(hHwnd, WM_CAP_DRIVER_CONNECT, iDevice, 0) == 1) 
        {
            // 
            // Set the preview scale
            // 
            SendMessage(hHwnd, WM_CAP_SET_SCALE, 1, 0);
            // 
            // Set the preview rate in milliseconds
            // 
            SendMessage(hHwnd, WM_CAP_SET_PREVIEWRATE, 66, 0);
            // 
            // Start previewing the image from the camera
            // 
            SendMessage(hHwnd, WM_CAP_SET_PREVIEW, 1, 0);
            // 
            //  Resize window to fit in picturebox
            // 
            SetWindowPos(hHwnd, HWND_BOTTOM, 0, 0, iWidth,iHeight, (SWP_NOMOVE | SWP_NOZORDER));
        }
        else 
        {
            // 
            //  Error connecting to device close window
            //  
            DestroyWindow(hHwnd);
        }
    }

结束预览:

private void ClosePreviewWindow() 
    {
        // 
        //  Disconnect from device
        // 
        SendMessage(hHwnd, WM_CAP_DRIVER_DISCONNECT, iDevice, 0);
        // 
        //  close window
        // 
        DestroyWindow(hHwnd);
    }

网络摄像头 API

    const short WM_CAP = 1024; 
    const int WM_CAP_DRIVER_CONNECT = WM_CAP + 10; 
    const int WM_CAP_DRIVER_DISCONNECT = WM_CAP + 11; 
    const int WM_CAP_EDIT_COPY = WM_CAP + 30; 
    const int WM_CAP_SET_PREVIEW = WM_CAP + 50; 
    const int WM_CAP_SET_PREVIEWRATE = WM_CAP + 52; 
    const int WM_CAP_SET_SCALE = WM_CAP + 53; 
    const int WS_CHILD = 1073741824; 
    const int WS_VISIBLE = 268435456; 
    const short SWP_NOMOVE = 2; 
    const short SWP_NOSIZE = 1; 
    const short SWP_NOZORDER = 4; 
    const short HWND_BOTTOM = 1; 

如有任何疑问,请随时提出。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接