我试图制作一个非常简单的摄像监控系统。在这种情况下,相机将是服务器,并且将有一个客户端应用程序在另一端观看视频输入。
为简单起见,我将通过捕获已保存视频文件中的帧来模拟相机,并通过套接字将这些帧逐个发送到所有连接的客户端( 是的,相机可以处理超过一个客户 )。在客户端,我将收到帧,然后我将一个接一个地在jPanel中显示它们以创建视频播放的效果。
我已经完成了所有这些,但它仅适用于几帧,然后突然停止而没有例外。
这是相机类中的主要功能:
public static void main(String[] args) throws InterruptedException, IOException, RemoteException, AlreadyBoundException {
ServerSocket ssock = new ServerSocket(1234);
System.out.println("Listening");
Camera.getInstance().startCamera(); // Starts reading the frames from the video file
while (true) {
Socket sock = ssock.accept();
System.out.println("Connected");
ClientConnection con = new ClientConnection(sock); // Creates a new connection
// Runs the connection on it's own thread
Thread conThread = new Thread(con);
conThread.start();
// Keeps a reference to the connection so it can be used later to send frames
Camera.getInstance().connections.add(con);
}
}
来自 ClientConnection 类的片段:
构造函数:
public ClientConnection(Socket csocket) throws IOException {
this.csocket = csocket;
outStream = new PrintStream(csocket.getOutputStream());
objectOutStream = new ObjectOutputStream(csocket.getOutputStream());
}
ClientConnection 类实现了可运行的接口,因此它可以在单独的线程上工作。 run方法将负责从客户端接收预定义消息(例如" SET_MOVIE")并相应地执行一些操作。这些行为及其所做的与问题无关,因此我们可以放心地忽略它们。这是run方法:
@Override
public void run() {
try {
inStream = new Scanner(csocket.getInputStream());
String msg;
while (inStream.hasNext()) {
msg = inStream.nextLine();
if (msg.equals("SET_MOVIE")) {
setMovie();
} else if (msg.equals("SET_IDLE")) {
setIdle();
} else if (msg.equals("FORCE_STATE_ON")) {
forceStateOn();
} else if (msg.equals("FORCE_STATE_OFF")) {
forceStateOff();
} else if (msg.equals("DISCONNECT")) {
// TO-DO
}
}
} catch (IOException ex) {
Logger.getLogger(ClientConnection.class.getName()).log(Level.SEVERE, null, ex);
}
}
这是 ClientConnection 类中的 sendFrame 方法。每当新帧可用并准备发送时,它就会被调用。
// SEND_FRAME here works as an indicator to the client so that it can expect
// the image and start reading it
public void sendFrame(Frame _frame) throws IOException {
outStream.println("SEND_FRAME"); //tells the client there is a new frame
outStream.println(_frame.getCaptureTime()); //sends the time in which the frame was captured
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(_frame.getFrame(), "jpg", byteArrayOutputStream);
byte[] size = ByteBuffer.allocate(4).putInt(byteArrayOutputStream.size()).array();
outStream.write(size);
outStream.write(byteArrayOutputStream.toByteArray());
outStream.flush();
}
这是主要的方法,它只是创建一个新的 CameraConnection 并在它自己的线程上运行它。
public static void main(String[] args) throws InterruptedException, IOException {
Thread client = new Thread(new CameraConnection("Cam_1", 1234));
client.start();
}
这是 CameraConnection 构造函数:
public CameraConnection(String name, int port) throws IOException {
this.name = name;
clientSocket = new Socket("localhost", port);
// This scanner will be used to read messages sent from the server
// such as "SEND_FRAME"
inStream_scanner = new Scanner(clientSocket.getInputStream());
// This inputStream will be used to read the bufferedImage in a array of bits
inStream = clientSocket.getInputStream();
// This is the outStream used to send messaages to the server
outStream = new PrintStream(clientSocket.getOutputStream());
}
这是 CameraConnection 中的run方法:
@Override
public void run() {
String msg;
while (inStream_scanner.hasNext()) {
// Stores the incoming message and prints it
msg = inStream_scanner.nextLine();
System.out.println(msg);
// Irrelevant
if (msg.equals("NOTIFY_MOTION")) {
onMotion();
}
// Here is where the image gets read
else if (msg.equals("SEND_FRAME")) {
Frame f = new Frame();
long capturedTime = inStream_scanner.nextLong();
try {
byte[] sizeAr = new byte[4];
inStream.read(sizeAr);
int size = ByteBuffer.wrap(sizeAr).asIntBuffer().get();
byte[] imageAr = new byte[size];
inStream.read(imageAr);
BufferedImage image = null;
image = ImageIO.read(new ByteArrayInputStream(imageAr));
long receivedTime = System.currentTimeMillis();
// Prints out the image dimension and the time in which it was received
System.out.println("Received " + image.getHeight() + "x" + image.getWidth() + ": " + receivedTime);
f.setCaptureTime(capturedTime);
f.setFrame(image);
f.setRecievedTime(receivedTime);
} catch (Exception e) {
System.out.println(e.toString());
}
}
}
}
如上所述,它可以正常工作几帧然后停止而没有异常,inputStream中的扫描程序也开始在控制台上读取和打印奇怪的符号,就好像它已经损坏一样。只要服务器继续发送帧,它就会不断打印这些奇怪的符号。这是输出的图像:
screenshot from the output
答案 0 :(得分:1)
read()
填充缓冲区。readInt()
(和writeInt()
进行编写),而非本土代码。readFully()
。DataInputStream
和DataOutputStream
。