http mjpeg 图像读取
Posted qianbo_insist
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了http mjpeg 图像读取相关的知识,希望对你有一定的参考价值。
http mjpeg 图像格式
网络摄像头的视频流解析直接使用通过http的Mjpeg是具有边界帧信息的multipart/x-mixed-replace,而jpeg数据只是以二进制形式发送。因此,实际上不需要关心HTTP协议标头。所有jpeg帧均以marker开头,0xff 0xd8并以0xff 0xd9 结尾。因此,代码可以从http流中提取此类帧,解码,编码h264 ,重新发送。
抓包
GET /stream/mjpeg HTTP/1.1
Host: 192.168.0.66:2401
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/90.0.4430.85 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
HTTP/1.1 200 OK
Content-Type: multipart/x-mixed-replace;boundary=----WebKitFormBoundaryIZDrYHwuf2VJdpHw
Cache-Control: no-cache
------WebKitFormBoundaryIZDrYHwuf2VJdpHw
Content-Type: image/jpg
Content-Length: 61108
…JFIF…
1、python opencv来读 http mjpeg
以下使用python来读http mjpeg,因为python 方便快速,可以做原型方法的测试
import cv2
import requests
import numpy as np
r = requests.get('http://192.168.1.xx/mjpeg.cgi', auth=('user', 'password'), stream=True)
if(r.status_code == 200):
bytes = bytes()
for chunk in r.iter_content(chunk_size=1024):
bytes += chunk
a = bytes.find(b'\\xff\\xd8')
b = bytes.find(b'\\xff\\xd9')
if a != -1 and b != -1:
jpg = bytes[a:b+2]
bytes = bytes[b+2:]
i = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8), cv2.IMREAD_COLOR)
cv2.imshow('i', i)
if cv2.waitKey(1) == 27:
exit(0)
else:
print("Received unexpected status code {}".format(r.status_code))
2、java读取
java读取也是很方便的
package net.thistleshrub.mechwarfare.mjpeg;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import javax.imageio.ImageIO;
public class MjpegRunner implements Runnable
{
private static final String CONTENT_LENGTH = "Content-length: ";
private static final String CONTENT_TYPE = "Content-type: image/jpeg";
private MJpegViewer viewer;
private InputStream urlStream;
private StringWriter stringWriter;
private boolean processing = true;
public MjpegRunner(MJpegViewer viewer, URL url) throws IOException
{
this.viewer = viewer;
URLConnection urlConn = url.openConnection();
// change the timeout to taste, I like 1 second
urlConn.setReadTimeout(1000);
urlConn.connect();
urlStream = urlConn.getInputStream();
stringWriter = new StringWriter(128);
}
public synchronized void stop()
{
processing = false;
}
@Override
public void run()
{
while(processing)
{
try
{
byte[] imageBytes = retrieveNextImage();
ByteArrayInputStream bais = new ByteArrayInputStream(imageBytes);
BufferedImage image = ImageIO.read(bais);
viewer.setBufferedImage(image);
viewer.repaint();
}catch(SocketTimeoutException ste){
System.err.println("failed stream read: " + ste);
viewer.setFailedString("Lost Camera connection: " + ste);
viewer.repaint();
stop();
}catch(IOException e){
System.err.println("failed stream read: " + e);
stop();
}
}
// close streams
try
{
urlStream.close();
}catch(IOException ioe){
System.err.println("Failed to close the stream: " + ioe);
}
}
/**
* Using the urlStream get the next JPEG image as a byte[]
* @return byte[] of the JPEG
* @throws IOException
*/
private byte[] retrieveNextImage() throws IOException
{
boolean haveHeader = false;
int currByte = -1;
String header = null;
// build headers
// the DCS-930L stops it's headers
while((currByte = urlStream.read()) > -1 && !haveHeader)
{
stringWriter.write(currByte);
String tempString = stringWriter.toString();
int indexOf = tempString.indexOf(CONTENT_TYPE);
if(indexOf > 0)
{
haveHeader = true;
header = tempString;
}
}
// 255 indicates the start of the jpeg image
while((urlStream.read()) != 255)
{
// just skip extras
}
// rest is the buffer
int contentLength = contentLength(header);
byte[] imageBytes = new byte[contentLength + 1];
// since we ate the original 255 , shove it back in
imageBytes[0] = (byte)255;
int offset = 1;
int numRead = 0;
while (offset < imageBytes.length
&& (numRead=urlStream.read(imageBytes, offset, imageBytes.length-offset)) >= 0)
{
offset += numRead;
}
stringWriter = new StringWriter(128);
return imageBytes;
}
// dirty but it works content-length parsing
private static int contentLength(String header)
{
int indexOfContentLength = header.indexOf(CONTENT_LENGTH);
int valueStartPos = indexOfContentLength + CONTENT_LENGTH.length();
int indexOfEOL = header.indexOf('\\n', indexOfContentLength);
String lengthValStr = header.substring(valueStartPos, indexOfEOL).trim();
int retValue = Integer.parseInt(lengthValStr);
return retValue;
}
}
3、c++读取
未完待续
以上是关于http mjpeg 图像读取的主要内容,如果未能解决你的问题,请参考以下文章