這篇文章將主要結合源碼介紹mjpg-streamer,使小伙伴們了解視頻監控的實現。
一.移植
tar xvf mjpg-streamer-r63.tar.gz
cd mjpg-streamer-r63
修改所有的Makefile
--(1) 將 CC=gcc 修改為 CC=arm-linux-gcc
--(2) 修改plugins/input_uvc/Makfile
a. 將
CFLAGS += -O2 -DLINUX -D_GNU_SOURCE -Wall -shared -fPIC
改為
CFLAGS += -O2 -DLINUX -D_GNU_SOURCE -Wall -shared -fPIC -I /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include
注意:
-I /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include // 是編譯libjpeg 生成的文件
b. 將
input_uvc.so: $(OTHER_HEADERS) input_uvc.c v4l2uvc.lo jpeg_utils.lo dynctrl.lo
$(CC) $(CFLAGS) -ljpeg -o $@ input_uvc.c v4l2uvc.lo
jpeg_utils.lo dynctrl.lo
改為
input_uvc.so: $(OTHER_HEADERS) input_uvc.c v4l2uvc.lo jpeg_utils.lo dynctrl.lo
$(CC) $(CFLAGS) -ljpeg -L /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib -o $@ input_uvc.c v4l2uvc.lo jpeg_utils.lo dynctrl.lo
make
cp mjpg_streamer 靠別到開發板的/bin目錄
cp *so* 拷貝到開發板的/lib
二.軟件結構
軟件MJPG-streamer采用模塊化的設計方法,以功能塊為單位進行描述,這些功能塊被稱為plug-in(組件)。軟件中定義好了各組件的輸入、輸出,以及組件之間的銜接關系。用戶可自行根據對功能的需求,選擇需要的模塊。這種模塊化的程序設計簡化了代碼的編寫、調試、維護,程序員只需要遵守設計的規范,就可以輕松地改寫軟件,或者編寫新的模塊以增強軟件的功能。
input_uvc <----------------------- ------------------------> output_autofocus
input_file <-------------------- MJPG-streamer --------------------> output_file
input_testpicture <--------------------
input_gspcav <----------------------- ------------------------> output_http
我們選擇的組件是input_uvc (輸入USB攝像頭數據)和output_http(輸出網頁),output_file(輸出圖片)
三.初始化
從mjpg_streamer.c文件開始分析
1.輸入初始化(input_init();)
global.in.init(&global.in.param) //打開input_init()函數
input_init() //input_uvc.c
1.識別參數
2.調用init_videoIn() //設置結構體,調用init_v4l2,分配緩沖區(存放攝像頭數據)
init_v4l2() //根據設置的參數,做相應的操作,這里是真正調用驅動的地方
2.輸出初始化(output_init();)
global.out[i].init(&global.out[i].param) //調用output_run();
output_init() //解析參數,相應變量賦值
四.運行
從mjpg_streamer.c文件開始分析
1.輸入運行(input_run();)
global.in.run(); //調用input_run();
input_run()
pthread_create(&cam, 0, cam_thread, NULL); //創建線程
void *cam_thread( void *arg )
uvcGrab(videoIn) //獲得一幀數據
if (videoIn->formatIn == V4L2_PIX_FMT_YUYV) //如果YUV則壓縮,否則直接拷貝buffer中
2.輸出運行(output_run();)
global.out[i].run(global.out[i].param.id); //調用output_run();
output_run(int id)
pthread_create(&(servers[id].threadID), NULL, server_thread, &(servers[id])); //創建線程
void *server_thread( void *arg )
pthread_create(&client, NULL, &client_thread, pcfd)
void *client_thread( void *arg ) //客戶端連接服務
_readline(lcfd.fd, &iobuf, buffer, sizeof(buffer)-1, 5)
_read(fd, iobuf, &c, 1, timeout)
read(fd, &iobuf->buffer, IO_BUFFER)) //讀取數據
send_stream(lcfd.fd); //發送流
pthread_cond_wait(&pglobal->db_update, &pglobal->db); //等待數據更新
memcpy(frame, pglobal->buf, frame_size); //從buf中取出數據
write(fd, frame, frame_size) //發出數據
五.命令參數
這個是我設置的參數:輸入UVC,網頁輸出,圖片輸出(更詳細的設置,建議去看源碼)
mjpg_streamer -i "input_uvc.so -f 10 -r 320*240 -y" -o "output_http.so -c "ruoyun:liufeng" -w www -p 8888" -o "output_file.so -d 1000 -f /mnt "
-i 輸入
"input_uvc.so -f 10 -r 320*240 -y"
input_uvc.so:UVC輸入組件
-f 10 :表示10幀
-r 320*240 :分辨率
-y :YUV格式輸入(有卡頓),不加表示MJPG輸入(需要攝像頭支持)
-o輸出
"output_http.so -c "ruoyun:liufeng" -w www -p 8888"
output_http.so :網頁輸出組件
-c "ruoyun:liufeng" :用戶名:ruoyun 密碼:liufeng
-w www : 網頁輸出
-p 8888 :端口 8888
"output_file.so -d 1000 -f /mnt "
output_file.so :圖片輸出組件
-d 1000 : 時間1S
-f /mnt :輸出圖片放在哪,我是開機直接把/mnu掛載到本地文件夾了