mjpg-streamer
开源地址:https://github.com/jacksonliam/mjpg-streamer
这是http://sourceforge.net/projects/mjpg-streamer/ 的一个分支,通过 input_raspicam 插件增加了对 Raspberry Pi 相机的支持。
mjpg-streamer 是一种命令行应用程序,可将 JPEG 帧从一个或多个输入插件复制到多个输出插件。它可用于通过基于 IP 的网络将 JPEG 文件从网络摄像头流式传输到各种类型的查看器,例如 Chrome、Firefox、Cambozola、VLC、mplayer 和其他能够接收 MJPG 流的软件。
它最初是为 RAM 和 CPU 资源非常有限的嵌入式设备编写的。它的前身“uvc_streamer”是因为 Linux-UVC 兼容相机直接生成 JPEG 数据而创建的,即使来自运行 OpenWRT 的嵌入式设备也允许快速和高性能的 M-JPEG 流。输入模块“input_uvc.so”从连接的网络摄像头捕获此类 JPG 帧。mjpg-streamer 现在支持各种不同的输入设备。
安装支持插件
需要的插件
- input_file
- input_http
- input_opencv (documentation)
- input_ptp2
- input_raspicam (documentation)
- input_uvc (documentation)
输出插件:- output_file
- output_http (documentation)
output_rtsp (not functional)output_udp (not functional)- output_viewer (documentation)
- output_zmqserver (documentation)
安装环境
sudo apt-get install subversion sudo apt-get install imagemagick sudo apt-get install libv4l-dev sudo apt-get install cmake sudo apt-get install git gh clone https://github.com/jacksonliam/mjpg-streamer.git sudo apt-get install cmake libjpeg8-dev sudo apt-get install gcc g++
安装开源mjpg-streamer
cd mjpg_streamer make all sudo make install
使用mjpg-streamer
开机自启动
开机自启动,参考我之前的博客内容
命令行启动
cd mjpg_streamer
./mjpg_streamer -o "output_http.so -w ./www" -i "input_raspicam.so"
运行参数设置
mjpg_streamer -i "input_uvc.so -d /dev/video0 -r 352x288 -f 30 -q 80 -y" -o "output_http.so -p 8080 -w /www/webcam"
y是表示YUV格式。如果没有-y,默认启动是mjpeg格式,这个就报错。改成YUV格式
-d指定设备
-f 制订帧数,默认30帧
-r指定视频大小,如320×240
-q指定画质,默认80对于输出参数:
-p 指定端口,这里是8080
-w 指定网页目录,这里设置的是/www/webCam目录
-c设置通过密码访问
正常输出结果如下:
MJPG Streamer Version: svn rev: Unversioned directory
i: Using V4L2 device.: /dev/video0
i: Desired Resolution: 640 x 480
i: Frames Per Second.: 15
i: Format............: YUYV
i: JPEG Quality......: 80
i: TV-Norm...........: DEFAULT
i: FPS coerced ......: from 15 to 30
i: Frame period time ......: 66 ms
o: www-folder-path...: www/
o: HTTP TCP port.....: 8080
o: username:password.: disabled
o: commands..........: enabled
web查看
- 取一张图片:
http://192.168.1.1:8080?action=snapshot
- 在线查看视频:
http://192.168.1.1:8080?action=stream
mjpg-streamer分析
感觉这个开源项目,更像是一种jpg的web查看器,可以通过web查看到图片,压缩为jpg格式大概为34kb。
web查看mjpg-streamer图片
自带的html查看
自己制作网页查看
<img src = "http://192.168.1.125:8080/?action=stream" alt = "xxx001" >
可以通过html同时拉取多个mjpg-streamer
代码如下:
<body>
<div id="main">
<ul>
<li><img src = "http://192.168.1.125:8080/?action=stream" alt = "xxx001" ></li>
<li><img src = "http://192.168.1.168:8080/?action=stream" alt = "xxx002" ></li>
<li><img src = "http://192.168.1.210:8080/?action=stream" alt = "xxx003" ></li>
<li><img src = "http://192.168.1.190:8080/?action=stream" alt = "xxx004" ></li>
<li><img src = "http://192.168.1.247:8080/?action=stream" alt = "xxx005" ></li>
<li><img src = "http://192.168.1.196:8080/?action=stream" alt = "xxx006" ></li>
<li><img src = "http://192.168.1.220:8080/?action=stream" alt = "xxx007" ></li>
<li><img src = "http://192.168.1.164:8080/?action=stream" alt = "xxx008" ></li>
<li><img src = "http://192.168.1.147:8080/?action=stream" alt = "xxx009" ></li>
<li><img src = "http://192.168.1.186:8080/?action=stream" alt = "xxx010" ></li>
</ul>
<div>
<div id="gray">
<div class="IMG">
</div>
</div>
<div class="r-but"></div>
<div class="l-but"></div>
<script type="text/javascript" src="js/jquery-1.11.1.min.js"></script>
<script type="text/javascript">
var i =0;
$("#main ul li").click(function(){
$("#gray").show();
$(".l-but").show();
$(".r-but").show();
/*var _bigSrc=$(this).find("img").attr("src");
alert(_bigSrc);
$("#gray .IMG img").attr("src",_bigSrc);*/
index=$(this).index();
/*alert(index);*/
i=index;
$("#gray .IMG img").eq(i).fadeIn().siblings().fadeOut();
/*alert(i);*/
});
$(".r-but").click(function(){
/*
index++;
alert(index);
_bigSrc=$(#Main ul li).eq().find("img").attr("bigSrc");
$(".gray .IMG img .BIGIMG").attr("src",_bigSrc);
*/
i++;
if(i<16 && i>0){
/*$(".pic img").eq(i).show().siblings().hide();*/
$("#gray .IMG img").eq(i).fadeIn().siblings().fadeOut();
/*alert(i);*/
}else{
i=0;
$("#gray .IMG img").eq(i).fadeIn().siblings().fadeOut();
}14-12-10
});
$(".l-but").click(function(){
i--;
if(i<16 && i>0){
/*$(".pic img").eq(i).show().siblings().hide();*/
$("#gray .IMG img").eq(i).fadeIn().siblings().fadeOut();
/*alert(i);*/
}else{
i=16;
$("#gray .IMG img").eq(i).fadeIn().siblings().fadeOut();
}
});
$("#gray").click(function(){
$(this).hide();
$(".l-but").hide();
$(".r-but").hide();
});
</script>
</body>
</html>
</span></strong>
显示效果:
对于单张图片可以进行放大显示。
python爬取mjpg-streamer图片
可以通过urllib爬取图片,获取传输时延。
源码
# -*- coding:utf-8 -*-
import cv2
import numpy as np
from urllib import request
import time
# -*- coding: utf-8 -*-
from concurrent.futures import ThreadPoolExecutor
import threading
import time
url = "http://192.168.3.111:8080/?action=snapshot"
url2 = "http://192.168.3.101:8080/?action=snapshot"
# 定义获取线程return返回测试的方法
def action_a(max):
my_sum = max + 1
return my_sum
def action_b(max):
my_sum = max + 100
time.sleep(3)
return my_sum
def downloadImg(url):
time1=time.time()
with request.urlopen(url) as f:
data = f.read()
img1 = np.frombuffer(data, np.uint8)
# print("img1 shape ", img1.shape) # (83653,)
img_cv = cv2.imdecode(img1, cv2.IMREAD_ANYCOLOR)
print(url, "time:", time.time() - time1)
return img_cv
结果显示
python多台拉取显示
为了获取结果采用线程进行显示
线程池
while True: # 创建包含2个线程的线程池 pool = ThreadPoolExecutor(max_workers=2) # 向线程池提交一个任务, 20和10会作为action_a/b()方法的参数 future1 = pool.submit(downloadImg, url) future2 = pool.submit(downloadImg, url2) # 判断future1线程是否结束---返回False表示该线程未结束,True表示该线程已经结束 print("future1线程的状态:" + str(future1.done())) # 此时future1线程已结束 # 判断future2线程是否结束 print("future2线程的状态:" + str(future2.done())) # 此时future2线程未结束,因为休眠了3秒 cv2.imshow("frame", future1.result()) cv2.imshow("frame2", future2.result()) cv2.waitKey(1) # 关闭线程池 pool.shutdown() cv2.destroyAllWindows()
自制线程
# -*- coding: utf-8 -*- import threading, time """ 用类包装线程;调用时可以获取线程的return返回值 """ # 定义一个MyThread.py线程类 class MyThread(threading.Thread): def __init__(self, func, args=()): super(MyThread, self).__init__() self.func = func self.args = args def run(self): time.sleep(2) self.result = self.func(*self.args) def get_result(self): threading.Thread.join(self) # 等待线程执行完毕 try: return self.result except Exception: return None # 获取多线程return返回值的测试方法 def admin(number): uiu = number for i in range(10): uiu = uiu + i return uiu if __name__ == "__main__": # 创建四个线程 more_th1 = MyThread(admin, (5,)) more_th2 = MyThread(admin, (10,)) more_th3 = MyThread(admin, (50,)) more_th4 = MyThread(admin, (78,)) # 启动线程 more_th1.start() more_th2.start() more_th3.start() more_th4.start() # 线程等待(即:等待四个线程都运行完毕,才会执行之后的代码) more_th1.join() more_th2.join() more_th3.join() more_th4.join() # 输出线程执行方法后的的返回值 print(more_th1.get_result()) print(more_th2.get_result()) print(more_th3.get_result()) print(more_th4.get_result())
结论:
自制线程效果优于自制线程。
结果:更多内容:
参考文章
源码解析
https://wiki.openwrt.org/doc/howto/webcam