1

IP カメラからビデオをストリーミングする Java アプリケーションに取り組んでいます。ビデオは IP カメラから MJPEG 形式でストリーミングされます。プロトコルは次のとおりです...

--ipcamera (\r\n)
Content-Type: image/jpeg (\r\n)
Content-Length: {length of frame} (\r\n)
(\r\n)
{frame}
(\r\n)
--ipcamera (\r\n)
etc.

BufferedReader や Scanner などのクラスを使用して「\r\n」まで読み取ろうとしましたが、これらはバイナリ データではなくテキスト用であるため、破損します。"\r\n" に遭遇するまでバイナリ ストリームを読み取る方法はありますか? これが私の現在の(壊れた)コードです。

編集:私はそれを機能させました。以下のコードを更新しました。ただし、そうするのは本当に遅いです。ArrayList と関係があるかどうかはわかりませんが、原因である可能性があります。コードを高速化するための指針はありますか? 現在、1 フレームあたり 500 ミリ秒から 900 ミリ秒かかっています。

public void run() {
    long startTime = System.currentTimeMillis();
    try {
        URLConnection urlConn = url.openConnection();
        urlConn.setReadTimeout(15000);
        urlConn.connect();
        urlStream = urlConn.getInputStream();
        DataInputStream dis = new DataInputStream(urlStream);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ArrayList<Byte> bytes = new ArrayList<Byte>();
        byte cur;
        int curi;
        byte[] curBytes;
        int length = 0;
        while ((curi = dis.read()) != -1) {
            cur = (byte) curi;
            bytes.add(cur);
            curBytes = getPrimativeArray(bytes);
            String curBytesString = new String(curBytes, "UTF-8");
            if (curBytesString.equals("--ipcamera\r\n")) {
                bytes.clear();
                continue;
            } else if (curBytesString.equals("Content-Type: image/jpeg\r\n")) {
                bytes.clear();
                continue;
            } else if (curBytesString.matches("^Content-Length: ([0-9]+)\r\n$")) {
                length = Integer.parseInt(curBytesString.replace("Content-Length: ", "").trim());
                bytes.clear();
                continue;
            } else if (curBytesString.equals("\r\n")) {
                if (length == 0) {
                    continue;
                }
                byte[] frame = new byte[length];
                dis.readFully(frame, 0, length);
                writeFrame(frame);
                bytes.clear();
                break;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    long curTime = System.currentTimeMillis() - startTime;
    System.out.println(curTime);
}

private byte[] getPrimativeArray(ArrayList<Byte> array) {
    byte[] bytes = new byte[array.size()];
    for (int i = 0; i < array.size(); i++) {
        bytes[i] = array.get(i).byteValue();
    }
    return bytes;
}

private void writeFrame(byte[] bytes) throws IOException {
    File file = new File("C:\\test.jpg");
    FileOutputStream fos = new FileOutputStream(file);
    fos.write(bytes);
    fos.close();
    System.out.println("done");
}
4

4 に答える 4

2

URLConnectionフレームデータを読み取った後に長さをゼロにリセットすると、投稿した例が機能するように見えます 。

} else if (line.equals("") && length != 0) {
    char[] buf = new char[length];
    reader.read(buf, 0, length);
    baos.write(new String(buf).getBytes());
    //break;
    length = 0;  // <-- reset length
}

ByteArrayOutputStreamこの方法では、すべてのフレーム データが連続して同じように書き込まれることに注意してください。それが望ましくない場合は、ByteArrayOutputStream遭遇するすべての新しいフレームに対して新しいを作成する必要があります。

于 2013-07-31T07:00:20.217 に答える
1
  1. BufferedReader送信の一部に を使用してから、残りの部分に他のストリームを使用することはできません。はそのBufferedReaderバッファをいっぱいにし、他のストリームで読み取りたいデータの一部を盗みます。非推奨であることに注意するDataInputStream.readLine(),か、独自の行読みコードをロールして、URLConnection.

  2. きっと必要ないですよね?URLConnectionヘッダーを読み取ります。content-length が必要な場合は、API を使用して取得します。あなたが読むことができるものは、送信の本文から始まります。

于 2013-07-31T07:10:36.557 に答える