前言
Motion是一种视频监控程序,监视来自摄像机的视频信号,侦测拍摄中的运动。
Motion的官方网站见:http://www.lavrsen.dk/foswiki/bin/view/Motion/WebHome
Motion的下载链接http://nchc.dl.sourceforge.net/project/motion/motion%20-%203.2/3.2.12/motion-3.2.12.tar.gz
FFmpeg的新旧版本之间差异较大,在这里,我们要用旧些的版本,用ffmpeg-0.5.1,下载链接如下:
http://ffmpeg.org/releases/ffmpeg-0.5.1.tar.bz2
ffmpeg编译
首先解压ffmpeg-0.5.1.tar.bz2,,执行configure命令如下:
./configure --cc=arm-linux-gnueabihf-gcc --host-cc=arm-linux-gnueabihf --prefix=/home/***/iWork/common/gcc-linaro-arm-linux-gnueabihf-4.8-2013.10_linux --enable-cross-compile --arch=arm --disable-yasm
编译:
make
出现错误如下:
arm-linux-gnueabihf-gcc -DHAVE_AV_CONFIG_H -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -I. -I"/home/***/iWork/lamobo/motion-3.2.12-arm-project/ffmpeg-0.5.1" -D_ISOC99_SOURCE -D_POSIX_C_SOURCE=200112 -std=c99 -fomit-frame-pointer -g -Wdeclaration-after-statement -Wall -Wno-switch -Wdisabled-optimization -Wpointer-arith -Wredundant-decls -Wno-pointer-sign -Wcast-qual -Wwrite-strings -Wtype-limits -Wundef -O3 -fno-math-errno -fno-signed-zeros -c -o libavcodec/dsputil.o libavcodec/dsputil.c /tmp/ccOmDdh7.s: Assembler messages: /tmp/ccOmDdh7.s:51789: Error: thumb conditional instruction should be in IT block -- `movgt fp,r9' /tmp/ccOmDdh7.s:51790: Error: thumb conditional instruction should be in IT block -- `movgt r9,r8' /tmp/ccOmDdh7.s:51792: Error: thumb conditional instruction should be in IT block -- `movle r9,r7' /tmp/ccOmDdh7.s:51794: Error: thumb conditional instruction should be in IT block -- `movgt fp,r9' /tmp/ccOmDdh7.s:51889: Error: thumb conditional instruction should be in IT block -- `movgt r9,r8' /tmp/ccOmDdh7.s:51890: Error: thumb conditional instruction should be in IT block -- `movgt r8,ip' /tmp/ccOmDdh7.s:51892: Error: thumb conditional instruction should be in IT block -- `movle r8,r6' /tmp/ccOmDdh7.s:51894: Error: thumb conditional instruction should be in IT block -- `movgt r9,r8' make: *** [libavcodec/dsputil.o] Error 1这需要修改~/ffmpeg-0.5.1/config.mak,在OPTFLAGS(line:16)选项中添加:
-Wa,-mimplicit-it=thumb加入这句的意思是在使用Thumb ISA指令编译时自动产生“IT”指令。 继续编译,又报错:
strip: Unable to recognise the format of the input file `ffmpeg'这是strip没有使用交叉编译的版本所致,由于此时我们需要的库文件已经编成,所以这个错误可以忽略不计,修改config.mak中的strip为arm-linux-gnueabihf-strip,继续让编译完成
motion编译
motion中的ffmpeg.c是对ffmpeg api的封装,向其他模块提供功能。如在主程序文件motion.c中
//...... #ifdef HAVE_FFMPEG /* FFMpeg initialization is only performed if FFMpeg support was found * and not disabled during the configure phase. */ ffmpeg_init(); #endif /* HAVE_FFMPEG */ //......
这里ffmpeg_init就是ffmpeg.c中封装的方法:
void ffmpeg_init() { motion_log(LOG_INFO, 0, "ffmpeg LIBAVCODEC_BUILD %d LIBAVFORMAT_BUILD %d", LIBAVCODEC_BUILD, LIBAVFORMAT_BUILD); av_register_all(); #if LIBAVCODEC_BUILD > 4680 av_log_set_callback( (void *)ffmpeg_avcodec_log ); #endif /* Copy the functions to use for the append file protocol from the standard * file protocol. */ mpeg1_file_protocol.url_read = file_protocol.url_read; mpeg1_file_protocol.url_write = file_protocol.url_write; mpeg1_file_protocol.url_seek = file_protocol.url_seek; mpeg1_file_protocol.url_close = file_protocol.url_close; /* Register the append file protocol. */ #if LIBAVFORMAT_BUILD >= (52<<16 | 31<<8) av_register_protocol(&mpeg1_file_protocol); #else register_protocol(&mpeg1_file_protocol); #endif }我们需要在motion的Makefile中加入对ffmpeg模块的编译,并且打开HAVE_FFMPEG等开关。首先执行configure如下:
./configure CC=arm-linux-gnueabihf-gcc --host=arm-linux-gnueabihf --prefix=/home/stewart/iWork/common/gcc-linaro-arm-linux-gnueabihf-4.8-2013.10_linux生成Makefile,在OBJ选项中添加ffmpeg.o:
OBJ = ffmpeg.o motion.o conf.o draw.o jpegutils.o $(VIDEO_OBJ) netcam.o \ netcam_ftp.o netcam_jpeg.o netcam_wget.o track.o \ alg.o event.o picture.o rotate.o webhttpd.o \ webcam.o
在CFLAGS选项中添加-DHAVE_FFMPEG -DFFMPEG_NEW_INCLUDES -DHAVE_FFMPEG_NEW的定义,加入libjpeg头文件搜索目录
libdir = ${prefix}/lib incdir = ${prefix}/include
CFLAGS = -g -O2 -DHAVE_FFMPEG -DFFMPEG_NEW_INCLUDES -DHAVE_FFMPEG_NEW -D_REENTRANT -DMOTION_V4L2 -DMOTION_V4L2_OLD -DTYPE_32BIT="int" -DHAVE_BSWAP -Wall -DVERSION=\"3.2.12\" -Dsysconfdir=\"$( sysconfdir)\"在LIBS中加入对ffmpeg库的支持:
LIBS = -L${libdir} -static -lavformat -lavcodec -lavutil -ljpeg -lm -lpthread
预备工作完成,make,编译报错:
motion.h:44:28: fatal error: linux/videodev.h: No such file or directory compilation terminated.
由于linux-2.4以上的内核已经取消了videodev.h文件,需要安装libv4l-dev,然后将motion.h,video.h中的
#include <linux/videodev.h>
修改为
#include <libv4l1-videodev.h>
继续,又报错:
track.c: In function ‘uvc_center’: track.c:587:29: error: storage size of ‘control_s’ isn’t known track.c:589:24: error: ‘V4L2_CID_PRIVATE_BASE’ undeclared (first use in this function) track.c:589:24: note: each undeclared identifier is reported only once for each function it appears in track.c:592:24: error: ‘VIDIOC_S_CTRL’ undeclared (first use in this function) track.c:601:31: error: storage size of ‘queryctrl’ isn’t known track.c:605:24: error: ‘VIDIOC_QUERYCTRL’ undeclared (first use in this function) track.c:601:31: warning: unused variable ‘queryctrl’ [-Wunused-variable] track.c:587:29: warning: unused variable ‘control_s’ [-Wunused-variable] track.c:636:25: error: storage size of ‘control_s’ isn’t known track.c:636:25: warning: unused variable ‘control_s’ [-Wunused-variable] track.c: In function ‘uvc_move’: track.c:724:29: error: storage size of ‘control_s’ isn’t known track.c:726:24: error: ‘V4L2_CID_PRIVATE_BASE’ undeclared (first use in this function) track.c:729:24: error: ‘VIDIOC_S_CTRL’ undeclared (first use in this function) track.c:724:29: warning: unused variable ‘control_s’ [-Wunused-variable] track.c:779:25: error: storage size of ‘control_s’ isn’t known track.c:779:25: warning: unused variable ‘control_s’ [-Wunused-variable] make: *** [track.o] Error 1在track.c中添加:
#include <linux/videodev2.h>继续,报错(怎么还有啊?):
gcc -L/usr/local/lib -o motion motion.o conf.o draw.o jpegutils.o video.o video2.o video_common.o netcam.o netcam_ftp.o netcam_jpeg.o netcam_wget.o track.o alg.o event.o picture.o rotate.o webhttpd.o webcam.o ffmpeg.o -lm -lpthread -ljpeg -L/usr/local/lib -lavformat -lavcodec -lavutil -lm -lz /usr/local/lib/libavformat.a(file.o):(.data+0x60): multiple definition of `file_protocol' ffmpeg.o:(.data+0x0): first defined here collect2: ld returned 1 exit status原来结构体file_protocol在libavformat.a和ffmpeg.o中重复定义了,分别打开两个定义:
//libavformat/file.c:85 URLProtocol file_protocol = { "file", file_open, file_read, file_write, file_seek, file_close, };
//ffmpeg.c URLProtocol file_protocol = { "file", file_open, file_read, file_write, file_seek, file_close, #if LIBAVFORMAT_BUILD >= (52<<16 | 31<<8) NULL, NULL, NULL, #endif };
将libavformat/file.c中的file_protocol定义注掉,重新编译一份libavformat.a。然后继续编译motion,又报错:
/home/xxx/iWork/Thrid_party/ffmpeg-0.5.1/libavformat/matroskadec.c:917: undefined reference to `BZ2_bzDecompressInit' /home/xxx/iWork/Thrid_party/ffmpeg-0.5.1/libavformat/matroskadec.c:926: undefined reference to `BZ2_bzDecompress' /home/xxx/iWork/Thrid_party/ffmpeg-0.5.1/libavformat/matroskadec.c:929: undefined reference to `BZ2_bzDecompressEnd'这个需要libbz2库,下载地址 http://www.bzip.org/downloads.html
编译安装libbz2后将-lbz2加入motion的Makefile的LIBS选项:
LIBS = -lpthread -ljpeg -L/usr/lib -lavformat -lavcodec -lavutil -lm -lz -lbz2
继续,终于完成!
motion运用
这里首先需要了解当前系统是否支持我们的摄像头,我用的是卖场送的垃圾USB摄像头,估计用的也是通用的摄像头芯片。插上摄像头,打开lamobo开发板的linaro系统中的/sys/class/video4linux,如果下面有设备目录,表示设备板子已经识别出摄像头,否则就是没有。在这里,该目录下有video0,摄像头已识别。
这里简单介绍下运用的方法。在motion中有三个线程,一个负责视频,一个负责工作,主线程则负责统计数据(源码分析将在稍后专文介绍)。我们将编译出的motion文件和配置文件motion-dist.conf复制到lamobo开发板的linaro系统中。首先修改下配置文件motion-dist.conf,这里简单介绍几个选项的设置:
# 是否以守护进程启动 daemon off # 开启Setup模式,图像类似热成像仪 setup_mode off # 图像宽度 width 640 # 图像高度 height 480 # 每秒获取的帧的数量 framerate 8 # Image文件的质量 quality 75 #在运动的图形区间加入方框 locate on #设定自动采集图片的周期,当有运动被检测到时,采集频率会自动变高 snapshot_interval 1 #图像帧的存放目录 target_dir ~/motion # 视频服务端口号 webcam_port 8081 # 视频服务jpg质量 webcam_quality 125 # Maximum framerate for webcam streams (default: 1) webcam_maxrate 8 #是否允许非本地访问 webcam_localhost off # 视频控制端口号 control_port 8080 #是否允许非本地控制 control_localhost off
配置完后,执行命令:
motion -c motion-dist.conf
然后再浏览器中输入ip_address:8081,就可以看到摄像头拍摄的效果了。
刷照片的效果实在太挫了,让我们看看如何打开ffmpeg录像的配置。这里需要修改motion-dist.conf中的两个选项:
# Use ffmpeg to encode a timelapse movie # Default value 0 = off - else save frame every Nth second ffmpeg_timelapse 1 # Enables and defines variable bitrate for the ffmpeg encoder. # ffmpeg_bps is ignored if variable bitrate is enabled. # Valid values: 0 (default) = fixed bitrate defined by ffmpeg_bps, # or the range 2 - 31 where 2 means best quality and 31 is worst. ffmpeg_variable_bitrate 1