简体   繁体   English

TCP中的TCP Webcam Streaming

[英]TCP Webcam Streaming in java

Thanks for reading and sorry for my bad English in advance. 感谢您提前阅读并抱歉我的英语不好。

I'm working on Webcam Streaming with OpenCV. 我正在使用OpenCV开发Webcam Streaming。 My final goal is making a Skype-like application. 我的最终目标是制作类似Skype的应用程序。 so I'm trying basic 1:1 TCP model first. 所以我先尝试基本的1:1 TCP模型。

About the TCP 1:1 model, 关于TCP 1:1模型,
After connection, client send its real-time Webcam frames and server receive and display it in on its jpanel. 连接后,客户端发送其实时网络摄像头帧和服务器接收并在其jpanel上显示它。

I did receiving a picture and displaying it on jpanel so far. 到目前为止,我确实收到了一张照片并在jpanel上显示。
I'm trying to receive successive frames. 我正在尝试接收连续的帧。
At first, the problem was Server side socket seems like waiting until inputs from client are finished, ie, it never stops because real-time frames are continuously sent. 起初,问题是服务器端套接字似乎等待直到客户端的输入完成,即它永远不会停止,因为实时帧连续发送。
So I sent every frame size before sending the frame to escape from unstoppable waiting. 所以我在发送帧之前发送了每个帧大小以逃避不可阻挡的等待。
But it doesn't work well. 但它效果不好。 Client keeps sending frames, but server doesn't receive it well. 客户端继续发送帧,但服务器不能很好地接收它。
For example, if client send around 25k byte sized frames, the server only receive 1 to 3 bytes per one read even the buffer size is 512. 例如,如果客户端发送大约25k字节大小的帧,则服务器每次读取只接收1到3个字节,即使缓冲区大小为512。

ClientThread.java ClientThread.java

package client;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

import javax.imageio.ImageIO;

import video.VideoCap;

public class ClientThread extends Thread
{

    String   serverIp;
    int      serverPort;
    Socket   socket;
    VideoCap videoCap;

    public ClientThread(Socket socket, String serverIp, int serverPort, VideoCap videoCap)
    {
        this.socket = socket;
        this.serverIp = serverIp;
        this.serverPort = serverPort;
        this.videoCap = videoCap;
    }

    public void run()
    {
        while (ClientUI.calling)
        {
            try
            {
                InputStream in = socket.getInputStream();
                DataInputStream dis = new DataInputStream(in);
                OutputStream out = socket.getOutputStream();
                DataOutputStream dos = new DataOutputStream(out);

                // receive
                int bufSize = dis.readInt();
                while (ClientUI.calling)
                {
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    ImageIO.write(videoCap.getOneFrame(), "jpg", baos);
                    InputStream inputImage = new ByteArrayInputStream(baos.toByteArray());

                    // frame size
                    dos.writeInt(baos.size());
                    out(inputImage, baos, bufSize);
                    Thread.sleep(5000);
                }

            }
            catch (IOException | InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }

    void out(InputStream in, OutputStream out, int bufSize)
    {
        long size = 0;
        try
        {
            byte[] buf = new byte[bufSize];
            int n;
            while ((n = in.read(buf)) > 0)
            {
                out.write(buf, 0, n);
                size += n;
                System.out.println("size: " + size);
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }

        finally
        {
            System.out.println(getClass().getName() + " :: out >>> sent size: " + size);
        }
    }
}

ServerThread.java ServerThread.java

package server;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class ServerThread extends Thread
{
    ServerSocket serverSocket;
    Socket       socket;
    JPanel       panel;
    byte[]       buf;

    public ServerThread(ServerSocket serverSocket, JPanel panel, int bufSize)
    {
        this.serverSocket = serverSocket;
        this.panel = panel;
        buf = new byte[bufSize];
    }

    public void run()
    {
        try
        {
            System.out.println("waiting for client");
            socket = serverSocket.accept();
            System.out.println("client accepted");
            InputStream in = socket.getInputStream();
            DataInputStream dis = new DataInputStream(in);
            OutputStream out = socket.getOutputStream();
            DataOutputStream dos = new DataOutputStream(out);
            dos.writeInt(buf.length);

            while (ServerUI.calling)
            {
                int frameSize = dis.readInt();
                ByteArrayOutputStream outImage = new ByteArrayOutputStream();
                long size = 0;
                int n;

                while (frameSize >= size)
                {
                    n = dis.read(buf);
                    if (n == -1)
                        break;
                    outImage.write(buf, 0, n);
                    size += n;
                    System.out.println(n);

                }

                InputStream inputImage = new ByteArrayInputStream(outImage.toByteArray());
                BufferedImage bufferedImage = ImageIO.read(inputImage);
                panel.getGraphics().drawImage(bufferedImage, 0, 0, null);
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

}

I changed DataOutput/InputStream to ObjectOutput/InputStream. 我将DataOutput / InputStream更改为ObjectOutput / InputStream。 I'm not sure why it did not go well, but I guess this is because of serializing problem. 我不确定为什么它不顺利,但我想这是因为序列化问题。 but byte is not necessary to be serialized so I don't know exactly. 但字节不需要序列化,所以我不确切知道。

I'll provide with anyhow working codes. 无论如何我都会提供工作代码。 Because of AudioServer I divided into two Thread so the previous codes and the codes below are pretty different. 由于AudioServer我分为两个线程,所以以前的代码和下面的代码是非常不同的。

VideoServerThread.java VideoServerThread.java

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.net.ServerSocket;
import java.net.Socket;
import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class VideoServerThread extends Thread
{
    private ServerSocket serverSocket;
    int                  videoServerPort;
    private Socket       socket;
    private JPanel       panel;
    private boolean      calling;

    public VideoServerThread(ServerSocket serverSocket, int videoServerPort, JPanel panel, boolean calling)
    {
        this.serverSocket = serverSocket;
        this.videoServerPort = videoServerPort;
        this.panel = panel;
        this.calling = calling;
    }

    @Override
    public void run()
    {
        System.out.println("Video Server opened!");
        try
        {
            serverSocket = new ServerSocket(videoServerPort);
            socket = serverSocket.accept();
            InputStream in = socket.getInputStream();
            ObjectInputStream ois = new ObjectInputStream(in);
            BufferedImage bufferedImage;
            InputStream inputImage;
            Frame f;
            while (calling)
            {
                f = (Frame) ois.readObject();
                inputImage = new ByteArrayInputStream(f.bytes);
                bufferedImage = ImageIO.read(inputImage);
                panel.getGraphics().drawImage(bufferedImage, 0, 0, panel.getWidth(), panel.getHeight(), null);
                panel.getGraphics().drawImage(bufferedImage, 0, 0, null);
                bufferedImage.flush();
                inputImage.close();
                f = null;
            }

        }

        catch (IOException e)
        {
            e.printStackTrace();
        }
        catch (ClassNotFoundException e)
        {
            e.printStackTrace();
        }
    }

    class Frame implements Serializable
    {
        public byte[] bytes;
        public Frame(byte[] bytes)
        { 
            this.bytes = bytes;
        }

        public int size()
        {
            return bytes.length;
        }
    }
}

VideoClientThread.java VideoClientThread.java

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import javax.imageio.ImageIO;
import common.Frame;
import video.VideoCap;

public class VideoClientThread extends Thread
{
    private final String formatType = "jpg";
    private VideoCap     videoCap;
    private Socket       socket;
    private String       ip;
    private int          port;
    private boolean      calling;

    public VideoClientThread(VideoCap videoCap, Socket socket, String ip, int port, boolean calling)
    {
        this.videoCap = videoCap;
        this.socket = socket;
        this.ip = ip;
        this.port = port;
        this.calling = calling;
    }

    public void run()
    {
        try
        {
            socket = new Socket(ip, port);
            socket.setSoTimeout(5000);
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            Frame f;
            BufferedImage bufferedImage;
            while (calling)
            {
                ByteArrayOutputStream fbaos = new ByteArrayOutputStream();
                bufferedImage = videoCap.getOneFrame();
                ImageIO.write(bufferedImage, formatType, fbaos);
                f = new Frame(fbaos.toByteArray());
                oos.writeObject(f);
                oos.flush();
                bufferedImage.flush();
                // Thread.sleep(33);
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        // catch (InterruptedException e)
        // {
        // e.printStackTrace();
        // }
    }
}

TCP transport layer is reliable and packet lost never occur, therefore may packets have delay, you can using DatagramSocket instead of ServerSocket and Socket to transport via UDP protocol. TCP传输层是可靠的,丢包永远不会发生,因此数据包有延迟,你可以使用DatagramSocket代替ServerSocketSocket通过UDP协议传输。

sample server and client via DatagramSocket : 通过DatagramSocket示例服务器和客户端:

import java.io.IOException; 
import java.net.DatagramPacket; 
import java.net.DatagramSocket; 
public class smallserver { 

public static void main(String[] args) throws IOException { 

    string host = "127.0.0.1";
    int port = 5252;
    byte buf[] = new byte[2]; 
    byte send[] = { 13, 18 };

    //server
    DatagramSocket serverSocket  = new DatagramSocket(port);  
    DatagramPacket receivePacket = new DatagramPacket(buf, 2); 
    serverSocket.receive(receivePacket); 

    // client
    DatagramSocket clientSocket  = new DatagramSocket(host, port); 
    DatagramPacket sendPacket = new DatagramPacket(send, 2, clientSocket.getAddress(), clientSocket.getPort()); 
    clientSocket.send(sendPacket); 
 } 

} 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM