【正点原子阿尔法 IMX6ULL Linux开发板】5、mjpg-streamer搭建网络摄像头视频监控
[复制链接]
一、mjpg-streamer介绍
mjpg-streamer是一款免费基于IP地址的视频流服务器,它的输入插件从摄像头读取视频数据,这个输入插件产生视频数据并将视频数据复制到内存中,它有多个输出插件将这些视频数据经过处理,其中最重要的输出插件是网站服务器插件,它将视频数据传送到用户浏览器中,mjpg-streamer的工作就是将其中的一个输入插件和多个输出插件绑定在一起,所有的工作都是通过它的各个插件完成的。mjpg-streamer各个文件如下:
(1)input_testpicture.so。这是一个图像测试插件,它将预设好的图像编译成一个头文件,可以在没有摄像头的情况下传输图像,从而方便调试程序。
(2)input_uvc.so。此文件调用USB摄像头驱动程序V4L2,从摄像头读取视频数据。
(3)input_control.so。这个文件实现对摄像头转动的控制接口。
(4)output_http.so。这是一个功能齐全的网站服务器,它不仅可以从单一文件夹中处理文件,还可以执行一定的命令,它可以从输入插件中处理一幅图像,也可以将输入插件的视频文件根据现有M-JPEG标准以HTTP视频数据服务流形式输出。
(5)output_file.so。这个插件的功能是将输入插件的JPEG图像存储到特定的文件夹下,它可以用来抓取图像。
mjpg-streamer优点是对RAM和CPU的消耗比较少,可以快速的传输jpeg流。
二、libjpeg交叉编译
有些UVC摄像头只支持输出YUV原始图像,此时mjpg-streamer会将其转码为mjpeg,然后进行传输,此时会对CPU的消耗以及实时流的流畅度有影响,特别是分辨率比较大的时候。
因此mjpg-streamer 依赖 libjpeg, libjpeg下载地址:
http://www.ijg.org/
目前最新版本是v9e。这里下载v9d版本,libjpeg交叉编译命令:
cd jpeg-9d
make clean
./configure CC=arm-linux-gnueabihf-gcc --host=arm-linux --prefix=/home/alientek/linux/nfs/mjpg_streamer/build_jpeg
make
make install
编译成功后得到动态库:
正点原子阿尔法 IMX6ULL Linux内核已经配置好了UVC和USB 驱动,因此无需重新配置编译内核。
三、mjpg-streamer交叉编译
mjpeg-streamer下载
https://sourceforge.net/p/mjpg-streamer/code/HEAD/tree/
目前最新版本为r182,本次测试使用版本r182。
在ubuntu可通过2种命令下载代码:
svn checkout svn://svn.code.sf.net/p/mjpg-streamer/code/ mjpg-streamer-code
或者
svn checkout https://svn.code.sf.net/p/mjpg-streamer/code/ mjpg-streamer-code
在编译前需要对源码的mjpg-streamer-code-r182/mjpg-streamer/Makefile做以下修改:
将源码的所有Makefile(包含其子目录)中的编译工具链CC修改为IMX6ULL的编译工具链arm-linux-gnueabihf-gcc。
###############################################################
#
# Purpose: Makefile for "M-JPEG Streamer"
# Author.: Tom Stoeveken (TST)
# Version: 0.4
# License: GPL
#
###############################################################
# specifies where to install the binaries after compilation
# to use another directory you can specify it with:
# $ sudo make DESTDIR=/some/path install
DESTDIR = /usr/local
# set the compiler to use
CC = arm-linux-gnueabihf-gcc
SVNDEV := -D'SVN_REV="$(shell svnversion -c .)"'
CFLAGS += $(SVNDEV)
# general compile flags, enable all warnings to make compile more verbose
CFLAGS += -O2 -DLINUX -D_GNU_SOURCE -Wall
# CFLAGS += -g
#CFLAGS += -DDEBUG
# we are using the libraries "libpthread" and "libdl"
# libpthread is used to run several tasks (virtually) in parallel
# libdl is used to load the plugins (shared objects) at runtime
LFLAGS += -lpthread -ldl
# define the name of the program
APP_BINARY = mjpg_streamer
# define the names and targets of the plugins
PLUGINS = input_uvc.so
#PLUGINS += output_file.so
#PLUGINS += output_udp.so
PLUGINS += output_http.so
#PLUGINS += input_testpicture.so
#PLUGINS += output_autofocus.so
#PLUGINS += input_gspcav1.so
#PLUGINS += input_file.so
# PLUGINS += output_rtsp.so
# PLUGINS += output_ptp2.so # commented out because it depends on libgphoto
# PLUGINS += input_control.so # commented out because the output_http does it's job
# PLUGINS += input_http.so
# PLUGINS += output_viewer.so # commented out because it depends on SDL
# define the names of object files
OBJECTS=mjpg_streamer.o utils.o
# this is the first target, thus it will be used implictely if no other target
# was given. It defines that it is dependent on the application target and
# the plugins
all: application plugins
application: $(APP_BINARY)
plugins: $(PLUGINS)
$(APP_BINARY): mjpg_streamer.c mjpg_streamer.h mjpg_streamer.o utils.c utils.h utils.o
$(CC) $(CFLAGS) $(OBJECTS) $(LFLAGS) -o $(APP_BINARY)
chmod 755 $(APP_BINARY)
output_autofocus.so: mjpg_streamer.h utils.h
make -C plugins/output_autofocus all
cp plugins/output_autofocus/output_autofocus.so .
input_testpicture.so: mjpg_streamer.h utils.h
make -C plugins/input_testpicture all
cp plugins/input_testpicture/input_testpicture.so .
ifeq ($(USE_LIBV4L2),true)
input_uvc.so: mjpg_streamer.h utils.h
make -C plugins/input_uvc USE_LIBV4L2=true all
cp plugins/input_uvc/input_uvc.so .
else
input_uvc.so: mjpg_streamer.h utils.h
make -C plugins/input_uvc all
cp plugins/input_uvc/input_uvc.so .
endif
input_control.so: mjpg_streamer.h utils.h
make -C plugins/input_control all
cp plugins/input_control/input_control.so .
output_file.so: mjpg_streamer.h utils.h
make -C plugins/output_file all
cp plugins/output_file/output_file.so .
ifeq ($(WXP_COMPAT),true)
output_http.so: mjpg_streamer.h utils.h
make -C plugins/output_http -DWXP_COMPAT all
cp plugins/output_http/output_http.so .
else
output_http.so: mjpg_streamer.h utils.h
make -C plugins/output_http all
cp plugins/output_http/output_http.so .
endif
output_udp.so: mjpg_streamer.h utils.h
make -C plugins/output_udp all
cp plugins/output_udp/output_udp.so .
input_gspcav1.so: mjpg_streamer.h utils.h
make -C plugins/input_gspcav1 all
cp plugins/input_gspcav1/input_gspcav1.so .
input_file.so: mjpg_streamer.h utils.h
make -C plugins/input_file all
cp plugins/input_file/input_file.so .
output_rtsp.so: mjpg_streamer.h utils.h
make -C plugins/output_rtsp all
cp plugins/output_rtsp/output_rtsp.so .
output_ptp2.so: mjpg_streamer.h utils.h
make -C plugins/input_ptp2 all
cp plugins/input_ptp2/input_ptp2.so .
#input_http.so: mjpg_streamer.h utils.h
# make -C plugins/input_http all
# cp plugins/input_http/input_http.so .
# The viewer plugin requires the SDL library for compilation
# This is very uncommmon on embedded devices, so it is commented out and will
# not be build automatically. If you compile for PC, install libsdl and then
# execute the following command:
# make output_viewer.so
output_viewer.so: mjpg_streamer.h utils.h
make -C plugins/output_viewer all
cp plugins/output_viewer/output_viewer.so .
# cleanup
clean:
make -C plugins/input_uvc $@
make -C plugins/input_testpicture $@
make -C plugins/output_file $@
make -C plugins/output_http $@
make -C plugins/output_udp $@
make -C plugins/output_autofocus $@
make -C plugins/input_gspcav1 $@
make -C plugins/output_viewer $@
make -C plugins/input_control $@
make -C plugins/output_rtsp $@
# make -C plugins/input_http $@
rm -f *.a *.o $(APP_BINARY) core *~ *.so *.lo
# useful to make a backup "make tgz"
tgz: clean
mkdir -p backups
tar czvf ./backups/mjpg_streamer_`date +"%Y_%m_%d_%H.%M.%S"`.tgz --exclude backups --exclude .svn *
# install MJPG-streamer and example webpages
install: all
install --mode=755 $(APP_BINARY) $(DESTDIR)/bin
install --mode=644 $(PLUGINS) $(DESTDIR)/lib/
install --mode=755 -d $(DESTDIR)/www
install --mode=644 -D www/* $(DESTDIR)/www
# remove the files installed above
uninstall:
rm -f $(DESTDIR)/bin/$(APP_BINARY)
for plug in $(PLUGINS); do \
rm -f $(DESTDIR)/lib/$$plug; \
done;
本次测试只需要 input_uvc.so 和 output_http.so,在主目录中的Makefile里面只选择这两个,其它的去掉。
插件input_uvc依赖jpeg,因此修改plugins/input_uvc/Makefile文件,指定jpeg库头文件路径:CFLAGS += -I/home/alientek/linux/nfs/mjpg_streamer/build_jpeg/include
指定链接jpeg动态库路径:-ljpeg -L/home/alientek/linux/nfs/mjpg_streamer/build_jpeg/lib
input_uvc插件的Makefile修改后如下:
###############################################################
#
# Purpose: Makefile for "M-JPEG Streamer"
# Author.: Tom Stoeveken (TST)
# Version: 0.3
# License: GPL
#
###############################################################
CC = arm-linux-gnueabihf-gcc
OTHER_HEADERS = ../../mjpg_streamer.h ../../utils.h ../output.h ../input.h
CFLAGS += -O1 -DLINUX -D_GNU_SOURCE -Wall -shared -fPIC -I/home/alientek/linux/nfs/mjpg_streamer/build_jpeg/include
#CFLAGS += -g
#CFLAGS += -DDEBUG
ifeq ($(USE_LIBV4L2),true)
LFLAGS += -lv4l2
CFLAGS += -DUSE_LIBV4L2
endif
LFLAGS += -ljpeg -L/home/alientek/linux/nfs/mjpg_streamer/build_jpeg/lib
all: input_uvc.so
clean:
rm -f *.a *.o core *~ *.so *.lo
input_uvc.so: $(OTHER_HEADERS) input_uvc.c v4l2uvc.lo jpeg_utils.lo dynctrl.lo
$(CC) $(CFLAGS) -o $@ input_uvc.c v4l2uvc.lo jpeg_utils.lo dynctrl.lo $(LFLAGS)
v4l2uvc.lo: huffman.h uvc_compat.h v4l2uvc.c v4l2uvc.h
$(CC) -c $(CFLAGS) -o $@ v4l2uvc.c
jpeg_utils.lo: jpeg_utils.c jpeg_utils.h
$(CC) -c $(CFLAGS) -o $@ jpeg_utils.c
dynctrl.lo: dynctrl.c dynctrl.h
$(CC) -c $(CFLAGS) -o $@ dynctrl.c
mjpg-streamer-code-r182/mjpg-streamer/plugins/output_http/Makefile修改后如下:
###############################################################
#
# Purpose: Makefile for "M-JPEG Streamer"
# Author.: Tom Stoeveken (TST)
# Version: 0.3
# License: GPL
#
###############################################################
CC = arm-linux-gnueabihf-gcc
OTHER_HEADERS = ../../mjpg_streamer.h ../../utils.h ../output.h ../input.h
CFLAGS += -O1 -DLINUX -D_GNU_SOURCE -Wall -shared -fPIC
#CFLAGS += -g
#CFLAGS += -DDEBUG
LFLAGS += -lpthread -ldl
all: output_http.so
clean:
rm -f *.a *.o core *~ *.so *.lo
output_http.so: $(OTHER_HEADERS) output_http.c httpd.lo
$(CC) $(CFLAGS) -o $@ output_http.c httpd.lo
httpd.lo: $(OTHER_HEADERS) httpd.h httpd.c
$(CC) -c $(CFLAGS) -o $@ httpd.c
在mjpg-streamer-code-r182/mjpg-streamer目录生成mjpg-streamer可执行文件和动态库input_uvc.so、output_http.so:
将上面生成的可执行文件和动态库文件、文件夹mjpg-streamer-code-r182/mjpg-streamer/www都复制到test目录:
接下来使用nfs挂载方式进行测试(开发板ip为192.168.2.136、ubuntu虚拟机ip为192.168.2.11、win10主机ip为192.168.2.10,按照正点原子网络搭建章节确保三者能互相ping通)。
在开发板终端执行:
mount -t nfs -o nolock,nfsvers=3 192.168.2.11:/home/alientek/linux/nfs /mnt
进入test目录
手动指定一下库路径:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
执行下列命令启动mjpg-streamer:
./mjpg_streamer -i "input_uvc.so -d /dev/video2 -r 640x480" -o "output_http.so -w ./www"
如果是输出YUV格式的UVC摄像头,则执行命令:
./mjpg_streamer -i "input_uvc.so -y -r 640x480" -o "output_http.so -w ./www
查看图片,在浏览器输入:
http://192.168.2.136:8080/?action=snapshot
查看视频,在浏览器输入:
http://192.168.2.136:8080/?action=stream
使用命令:
v4l2-ctl --list-framesizes=MJPG -d /dev/video2
查看摄像头支持的分辨率。
按照上述方法是无法正常使用的,r182源码有点小bug,需要修改3个文件:
一是:
mjpg-streamer/plugins/input_uvc/v4l2uvc.h文件第108行增加变量int dd;
二是:
mjpg-streamer/plugins/input_uvc/v4l2uvc.c文件第453行增加代码vd->dd=vd->buf.bytesused;
三是:
mjpg-streamer/plugins/input_uvc/input_uvc.c文件第391行代码if(pcontext->videoIn->buf.bytesused < minimum_size)修改为if ( pcontext->videoIn->dd < minimum_size )
第410行代码pglobal->in[pcontext->id].size = memcpy_picture(pglobal->in[pcontext->id].buf, pcontext->videoIn->tmpbuffer, pcontext->videoIn->buf.bytesused)修改为pglobal->in[pcontext->id].size = memcpy_picture(pglobal->in[pcontext->id].buf, pcontext->videoIn->tmpbuffer, pcontext->videoIn->dd)
修改好后重新测试效果:
视频
抓拍
|