То, что я пытаюсь достичь:
Я пытаюсь создать очень простую систему видеонаблюдения. В этом случае камера будет сервером, и будет клиентское приложение для просмотра видеопотока на другом конце.Программирование сокетов: входной поток поврежден без исключения
Для простоты я буду подражать камеру захвата кадров из сохраненного видеофайла и отправка эти кадры один за другим через сокеты для всех подключенных клиентов (Да, камера может обрабатывать более одного клиента). На стороне клиента я получаю кадры, а затем я буду отображать их в jPanel один за другим, чтобы создать эффект воспроизведения видео.
Я уже сделал все это, но он работает только на пару кадров, после чего он внезапно останавливается без исключения.
Сервер-Side:
Это основная функция в камеры класса:
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») от клиента и выполнить соответствующие действия. Эти действия и то, что они делают, не имеют отношения к вопросу, поэтому мы можем смело игнорировать их. Вот метод запуска:
@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);
}
}
Это метод sendFrame в ClientConnection класса. Он вызывается каждый раз, когда новый фрейм доступен и готов к отправке.
// 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();
}
Клиент-Side:
Это основной метод, он просто создает новый 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:
@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
@HovercraftFullOfEels Здесь нет кода [tag: swing]. – EJP
Да, я не включил код поворота, потому что я смог воспроизвести проблему на консоли. –