我正在开发一个Java应用程序,它将从IP Camera流式传输视频。来自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有关,但它可能是罪魁祸首。有没有加速代码的指针?目前单帧需要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");
}
答案 0 :(得分:3)
目前,您无法处理在框架部件中读取数据的情况。
粗略的假设是:
当前版本:
else if (line.equals("") && length != 0)
可能更正确的版本:
else if (!line.equals("") && length != 0)
答案 1 :(得分:2)
你不能使用BufferedReader读取二进制文件,它会破坏它。我想保持简单,使用DataInputStream.readLine()。虽然不理想,但在您的情况下可能是最简单的。
答案 2 :(得分: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
。
答案 3 :(得分:1)
您无法使用BufferedReader
进行部分传输,然后使用其他流进行其余部分传输。 BufferedReader
将填充其缓冲区并使用其他流窃取您要读取的一些数据。使用DataInputStream.readLine(),
URLConnection.
注意它已被弃用,或者使用自己的读取代码滚动
当然你没必要? URLConnection
为您读取标题。如果您想要内容长度,请使用API来获取它。你要阅读的内容从传输的主体开始。