2017-04-07 88 views
0

感谢您阅读并提前抱歉我的英文不好。TCP网络摄像头在Java流媒体

我正在使用OpenCV进行网络摄像头流式处理。 我的最终目标是制作一个类似Skype的应用程序。 所以我正在尝试基本的1:1 TCP模型。

关于TCP 1:1型号,
连接后,客户端发送其实时Webcam帧和服务器接收并显示在其jpanel上。

到目前为止我没有收到图片并在jpanel上显示。
我试图接收连续的帧。
起初,问题在于服务器端的套接字好像等待客户端的输入完成,即从不停止,因为实时帧不断发送。
所以我发送每一帧的大小之前发送帧逃脱不可阻挡的等待。
但它运作不好。客户端不断发送帧,但服务器收不到。
例如,如果客户端发送围绕25K字节大小的帧,该服务器只接收每一个读甚至缓冲区大小为1〜3个字节是512

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

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(); 
     } 
    } 

} 
+0

为什么服务器发送BUFSIZE到客户端? –

+0

@SteveSmith我想如果缓冲区的大小是相同的,接收和发送数据量将是相同的。 – Bana

回答

0

我将DataOutput/InputStream更改为ObjectOutput/InputStream。 我不知道为什么它不好,但我想这是因为序列化问题。但字节没有必要被序列化,所以我不完全知道。

我会提供任何工作代码。由于AudioServer我分为两个线程,所以以前的代码和下面的代码是非常不同的。

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

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(); 
     // } 
    } 
}