彭老師在錄制的《物聯(lián)網(wǎng)綜合項目實戰(zhàn)》課程中,在web頁面中加入了實時監(jiān)控攝像頭的功能,特地整理了一篇如何移植視頻流服務器的文章,供大家學習。

在嵌入式系統(tǒng)中,常用的視頻圖像處理開源系統(tǒng)有:luvcview、cheese、motion、mjpg-streamer或者ffmpeg,其中:
? luvcview: 基于V4L2、SDL的程序,支持拍照錄像,參數(shù)調(diào)節(jié),代碼精簡實用,適合學習V4L2編程
? cheese:基于V4L2、GTK的程序,支持拍照錄像,特殊視頻效果
? motion:移動偵測拍照程序
? mjpg-streamer:網(wǎng)絡攝像機程序
MJPG-streamer是一個優(yōu)秀的開源project,它可以通過HTTP的方式訪問linux上面的兼容攝像頭,從而做到遠程視頻傳輸?shù)男Ч?/p>
MJPG-streamer從webcam攝像頭采集圖像,把他們以流的形式通過基于ip的網(wǎng)絡傳輸?shù)綖g覽器如Firehox,Cambozola,VLC播放器,Windows的移動設備或者其他擁有瀏覽器的移動設備。
它可以利用某些webcams的硬件壓縮功能來降低服務器CPU的開銷。
它為嵌入式設備和一些常規(guī)服務器提供了一個輕量且更少CPU消耗的方案,因為它無需為視頻幀壓縮浪費大量的計算效率。

1)按上圖的方式將羅技攝像頭連接入虛擬機
2)下載安裝cheese 檢測攝像頭是否能夠正常工作
$?sudo?apt-get?update
$?sudo?apt-get?install?cheese
ubuntu 16.04已經(jīng)自帶該程序
3)測試
攝像頭連接后會生成以下設備文件
root@ubuntu:/home/peng/work#?ls?/dev/video0?-l
crw-rw----+?1?root?video?81,?0?Mar?25?07:18?/dev/video0
運行
root@ubuntu:/home/peng/work#?cheese?

安裝準備:
sudo?apt-get?install?libsdl1.2-dev?subversion
sudo?apt-get?install?libjpeg62-dev
sudo?apt-get?install?imagemagick
?
git?clone?https://github.com/shrkey/mjpg-streamer
如果沒有安裝git,執(zhí)行以下命令
sudo?apt-get?install?git
cd?mjpg-streamer/mjpg-streamer

root@ubuntu:/home/peng/work/camera/mjpg-streamer#?tree?-L?1?./
./
├──?doc
├──?mjpeg-client?????#分別有?linux和windows?的客戶端
├──?mjpg-streamer????#目錄下提供了?的執(zhí)行程序和各個輸入輸出設備組件
├──?mjpg-streamer-experimental
├──?mjpg-streamer.tar.gz
├──?README.md
├──?udp_client
└──?uvc-streamer?????#目錄下提供了?uvc-streamer的可執(zhí)行目錄
6?directories,?2?files
ps:重新編譯前,需要執(zhí)行
make
sudo?make?install
root@ubuntu:/home/peng/work/camera/mjpg-streamer/mjpg-streamer#?make?install
install?--mode=755?mjpg_streamer?/usr/local/bin
install?--mode=644?input_uvc.so?output_file.so?output_udp.so?output_http.so?input_testpicture.so?input_file.so?/usr/local/lib/
install?--mode=755?-d?/usr/local/www
install?--mode=644?-D?www/*?/usr/local/www

編譯生成的庫文件功能
(1)input_testpicture.so。這是一個圖像測試插件,它將預設好的圖像編譯成一個頭文件,可以在沒有攝像頭的情況下傳輸圖像,從而方便調(diào)試程序。
(2)input_uvc.so。此文件調(diào)用USB攝像頭驅(qū)動程序V4L2,從攝像頭讀取視頻數(shù)據(jù)。
(3)input_control.so。這個文件實現(xiàn)對攝像頭轉(zhuǎn)動的控制接口。
(4)output_http.so。這是一個功能齊全的網(wǎng)站服務器,它不僅可以從單一文件夾中處理文件,還可以執(zhí)行一定的命令,它可以從輸入插件中處理一幅圖像,也可以將輸入插件的視頻文件根據(jù)現(xiàn)有M-JPEG標準以HTTP視頻數(shù)據(jù)服務流形式輸出。
(5)output_file.so。這個插件的功能是將輸入插件的JPEG圖像存儲到特定的文件夾下,它可以用來抓取圖像。
修改腳本文件
/home/peng/work/camera/mjpg-streamer/mjpg-streamer/start.sh
./mjpg_streamer?-i?"./input_uvc.so?-y"?-o?"./output_http.so?-w?./www"?-o?"./output_file.so?-f?/www/pice?-d?15000"

"./input_uvc.so?-y"?:指定攝像頭是YUV,默認是JPEG,一口君使用的羅技攝像頭是YUV
"./output_http.so?-w?./www"?:指定web服務器根目錄./www,我們可以通過瀏覽器測試攝像頭
"./output_file.so?-f?/www/pice?-d?15000"?:?指定拍照保存照片目錄/www/pice,并且每15s保存一次照片
也可以指定分辨率:
./mjpg_streamer?-i?"input_uvc.so?-d?/dev/video0?-n?-y?-r?640x480?-f?30"?-o?"./output_http.so?-w?./www"?-o?"./output_file.so?-f?/www/pice?-d?15000"
市面上有的攝像頭支持格式有YUV,MJPEG,H264 ;mjpg-stream支持MJPEG和YUV兩種格式
運行
./start.sh
(1)網(wǎng)頁測試
(2)網(wǎng)頁視頻流測試

(3) 拍照功能實現(xiàn)
瀏覽器上地址欄輸入如下內(nèi)容:
http://127.0.0.1:8080/?action=snapshot
或者
http://127.0.0.1:8080/?action=stream
snapshot 表示每次抓拍一張圖形顯示在網(wǎng)頁上,stream 表示視頻流也就是連續(xù)的圖 像
一口君還使用了一款z-star攝像頭,該款攝像頭不要添加-y選項
./mjpg_streamer?-i?"./input_uvc.so??-d?/dev/video0"?-o?"./output_http.so?-w?./www"?-o?"./output_file.so?-f?/www/pice?-d?150000"
有時候攝像頭生成的設備文件不是/dev/video0
我們需要對應參數(shù):
-d?/dev/video1

由于 mjpg_stream 中 output-file.so 能實現(xiàn)連續(xù)拍照的功能,不能實現(xiàn)單拍或 連拍幾張的功能所以需要對 output_file 原碼進行修改。修改文件目錄:
peng@ubuntu:~/work/camera/mjpg-streamer/mjpg-streamer/plugins/output_file/output_file.c
char?buf[10];???//用于存放從管道讀取的命令
int?flags?=?0;???//拍照標志,1:表示11張照片,2:表示1張照片
int?fd_com?=?0;?//打開管道的文件描述符
int?stop_num?=?0;?//拍照計數(shù)
if?(?access("/tmp/webcom",F_OK)?0?)????//創(chuàng)建有名管道用于接收拍照命令
{
?if?(?mkfifo("/tmp/webcom",0666?)?0)
?{
??printf("photo?fifo?create?failed\n");
?}
}
fd_com?=?open?("/tmp/webcom",O_RDONLY,0666);
if?(fd_com?0)
{
?perror?("open?the?file?webcom?error");
}
while( ok >= 0 && !pglobal->stop){ 后加入if?(flags?==?0)
?{
??while(1)
??{
???read(fd_com,buf,sizeof(buf));
???if?(strncmp(buf,"danger",6)?==?0)????//拍11張照片
???{
????flags?=?1;
????bzero(buf,sizeof(buf));
????break;
???}
???if?(strncmp(buf,"one",3)?==?0)???//拍1張照片
???{
????flags?=?2;
????bzero(buf,sizeof(buf));
????break;
???}
??}
?}
355?????????/*?if?specified,?wait?now?*/
356?????????if(delay?>?0)?{
357?????????????usleep(1000?*?delay);
358?????????}
后加入
??stop_num++;
??if?(flags?==?1)????????//判斷拍照的數(shù)量
??{
???if??(?stop_num?>?9)
???{
????stop_num?=?0;
????flags?=?0;
???}
??}
??else?if?(flags?==?2)
??{
???stop_num?=?0;
???flags?=?0;
??}
