9

我有一个从服务器流式传输视频 (MJPEG) 的 Java 小程序。我用 C#(Windows 服务)编写了一个代理服务器,用于放置在小程序和多个视频服务器之间。HTML/CSS/Js 前端与 Java 小程序一起使用。所有功能都可以正常工作(终于!!!),除了一件事。

视频服务器允许您通过 REST 接口播放录制的视频。剪辑完成后,服务器会保持连接打开,以防您要向其发送诸如倒带或搜索之类的命令。剪辑在小程序中播放良好,直到结束。如果您尝试开始一个新剪辑(这需要从 Javscript 向小程序发送命令),浏览器会冻结。但是,使用相同连接的后续命令会起作用,例如播放、暂停和搜索。如果我停止 Windows 服务,浏览器会再次响应。

这就是我假设正在发生的事情:剪辑结束(或暂停);不再发送数据,但连接仍处于活动状态。小程序在代理上等待下一帧,但代理在视频服务器上等待下一帧,不会再发送任何数据。

这是读取每一帧的while循环中的代码

byte[] img = new byte[mContentLength];
inputStream.skipBytes(headerLen);
inputStream.readFully(img);

我需要以某种方式中断这段代码。

当在 HTML 前端选择一个新的视频剪辑时,我们会通知小程序,它会调用 CameraStream 类的 disconnect()。这就是那个功能:

// DataInputStream inputStream
// HttpURLConnection conn
public void disconnect() {
    System.out.println("disconnect called.");
    if(running) {
        running = false;
        try {
            // close the socket
            if(inputStream != null) {
                inputStream.close();
            }
            if(conn != null) {
                conn.disconnect();
            }
            inputStream = null;
            System.out.println("closed.");
        } catch(Exception ignored) {
            System.out.println("exc:" + ignored.getMessage());
            main.reportErrorFromThrowable(ignored);
        }
    }
}

为了测试这一点,我让一个快速剪辑播放并运行到最后。然后我选择一个新剪辑。在我的 Java 控制台中,我得到了输出disconnect called.,但没有得到后续closed.消息,也没有捕获到通用异常。当我停止 Windows 服务时,我终于收到了closed.消息,所以看起来像是inputStream.close();被阻塞了。

所以我想我的问题是如何停止阻塞?通话是否被readFully(img)阻塞?或者它是断开功能(如我得到的控制台输出所建议的那样)?

编辑:澄清一下,我编写了 Java 小程序、HTML、CSS、Javascript 和 C# 代理服务器,因此我可以访问所有这些代码。我无法修改的唯一代码是视频服务器上的 REST 接口。

edit2:我打算为这篇文章提供赏金https://stackoverflow.com/questions/12219758/proxy-design-pattern

4

2 回答 2

0

一般来说,Java I/O 方法是阻塞的。最好的解决方案似乎是创建另一个线程来读取数据并使用 NIO 缓冲区。基于 NIO 的读取示例(警告:未经测试!):

// get the InputStream from somewhere (a queue possibly)
ReadableByteChannel inChannel = Channels.newChannel(inputStream);
ByteBuffer buf = ByteBuffer.allocate(mContentLength + headerLen);
inChannel.read(buf);
byte[] img = new byte[mContentLength];
inChannel.get(img, headerLen, mContentLength);

Channel此代码从 中创建一个InputStream并使用Channel来读取数据。该ReadableByteChannel.read(ByteBuffer)函数的 JavaDoc 说中断包含调用的线程inChannel.read(buf)将停止读取。

您将不得不调整此代码,我只是将其从脑海中拉出来。祝你好运!

于 2012-09-03T21:26:00.380 回答
0

我终于想出了答案:

public void disconnect() {
    if(running) {
        running = false;
        try {
            try{
                // had to add this
                conn.getOutputStream().close();
            }
            catch(Exception exc){
            }
            // close the socket
            if(inputStream != null) {
                inputStream.close();
            }
            if(conn != null) {
                conn.disconnect();
            }
            inputStream = null;


        } catch(Exception ignored) {
            main.reportErrorFromThrowable(ignored);
        }
    }
}

Even though I'm using an HttpUrlConnection, which is one way and doesn't have an output stream, trying to close the output stream raised an exception and for some reason made it all work.

于 2012-09-06T22:01:35.803 回答