1. 程式人生 > >【原創】IP攝像頭技術縱覽(五)---網路攝像頭初試—mjpg-streamer移植與部署

【原創】IP攝像頭技術縱覽(五)---網路攝像頭初試—mjpg-streamer移植與部署

【原創】IP攝像頭技術縱覽(五)—網路攝像頭初試—mjpg-streamer移植與部署

本文屬於《IP攝像頭技術縱覽》系列文章之一:

Author: chad
Mail: [email protected]

1、vgrabbj、spacview、Luvcview、mjpg-streamer評測對比

vgrabbj-0.9.6是基於v4l1設計的,與v4l2的API差別很大,該軟體已經沒有使用或參考價值。

spcaview 也相當古老,並且呼叫了SDL庫,不適合嵌入式系統,不建議研究。

什麼是SDL?
SDL(Simple DirectMedia Layer)是一套開放原始碼的跨平臺多媒體開發庫,使用C語言寫成。SDL提供了數種控制影象、聲音、輸出入的函式,讓開發者只要用相同或是相似的程式碼就可以開發出跨多個平臺(Linux、Windows、Mac OS X等)的應用軟體。目前SDL多用於開發遊戲、模擬器、媒體播放器等多媒體應用領域。

luvcview 該程式需要呼叫V4L2介面以及SDL庫,可以進行視訊採集與顯示,有一定的參考價值。
我在ubuntu下測試情況如下:
這裡寫圖片描述
攝像頭格式為MJPEG,而luvcview預設格式為yuv,所以,在ubuntu上執行時使用命令:

./luvcview -f jpg

注:luvcview 編譯時需要呼叫SDL庫與pthread庫。

強烈推薦:mjpg_streamer。
mjpg‐streamer是一個開源軟體,用於從webcam攝像頭採集影象,把它們以流的形式通過基於ip的網路傳輸到瀏覽器,關於它的介紹網上有一大堆,讀者可自行了解;

mjpg-streamer 需要很少的CPU和記憶體資源就可以工作,大部分編碼工作都是攝像頭完成的,所以對於記憶體和效能都有限的嵌入式系統十分適用。網上關於它的移植也很多,下面給出移植的過程與在編譯過程中出現的一些問題與解決方法。
在移植Mjpg-streamer之前必須移植好libjpeg;因為在mjpg-streamer原始碼包下的README檔案中有下面一句話:

the input plugin “input_uvc.so” depends on libjpeg, make sure it is installed.

2、mjpg-streamer移植與部署

(1)下載原始碼:

(2)交叉編譯jpeg庫,生成libjpeg.so.62.0.0庫檔案。

把libjpeg庫移植到mini2440arm板上步驟如下:

第一步:下載libjpeg原始碼
第二步:解壓
第三步:切換到解壓的目錄執行:
./configure –prefix=安裝目錄 CC=arm-linux-gcc –host=arm-linux –enable-shared –enable-static
第四步:
make && make install
第五步:庫的使用
在你的原始碼中加入
#include "jpeglib.h"


另外編譯的時候請一定使用下面的方法:
arm-linux-gcc -o 你的輸出 你的程式 -L/安裝目錄 -l:libjpeg.so.62

(3)交叉編譯mjpg-streamer。

要移植到arm上需要修改mjpg-streamer-r63/plugins/input_uvc目錄下的Makefile檔案,將ljpeg庫的路徑修改為移植好的jpeg庫的路徑:
這裡寫圖片描述
設定CC=arm-linux-gcc重新編譯:

make CC=arm-linux-gcc

將libjpeg.so.62.0.0庫檔案下載到目標板的lib目錄下,並建立連結:

ln -s /lib/libjpeg.so.62.0.0 /lib/libjpeg.so.62

同時,安裝好mjpg-streamer相關檔案:
這裡寫圖片描述
start.sh檔案修改如下:

./mjpg_streamer -i “input_uvc.so -d /dev/video1 -y -r QVGA” -o “output_http.so -w www -p 20002”

然後在電腦瀏覽器上輸入:

出現如下結果:
這裡寫圖片描述

要實現外網遠端監控,第一步:需要一個靜態IP地址,如果是區域網則需要設定埠轉發,如下是我的路由設定:
這裡寫圖片描述
第二步則是要正確配置嵌入式系統的ip、閘道器等引數,閘道器設定命令如下:

#route add default gw 192.168.0.1

第三步,首先查詢本的網路的外網IP的(180.175.93.247),由於系統監控的是20002埠,在瀏覽器中輸入:

結果如下:
這裡寫圖片描述
上圖是在手機微信中看到的實時監控畫面截圖。

*說明:上面的方法只適合固定ip且路由器埠對映可配置的情況,對於動態ip以及沒有路由器配置許可權這類情況的解決方法將在後續章節講解。這裡先劇透下解決方法:
(1)DNS動態域名。
(2)NAT內網穿透。
(3)VPN*。

3、mjpg-streamer實現分析

(1)mjpg-streamer工作流程

這裡寫圖片描述

mjpg-streamer通過外掛機制進行功能組合,程式擴充套件性非常好。目錄結構如下:
➜ mjpg-streamer-r63 (下面的目錄已經刪除很多內容)
.
├── CHANGELOG
├── LICENSE
├── Makefile
├── mjpg_streamer.c //主函式檔案
├── mjpg_streamer.h
├── plugins //外掛目錄
│ ├── input_file //檔案輸入外掛
│ │ └── input_file.c
│ ├── input_gspcav1 //gspcav攝像頭輸入外掛
│ ├── input.h
│ ├── input_testpicture //圖片輸入源外掛
│ ├── input_uvc //uvc攝像頭輸入源外掛
│ │ ├── dynctrl.c
│ │ ├── dynctrl.h
│ │ ├── huffman.h
│ │ ├── input_uvc.c
│ │ ├── jpeg_utils.c
│ │ ├── jpeg_utils.h
│ │ ├── Makefile
│ │ ├── uvc_compat.h
│ │ ├── uvcvideo.h
│ │ ├── v4l2uvc.c
│ │ └── v4l2uvc.h
│ ├── output_autofocus //autofocus輸出控制外掛
│ ├── output_file //外掛–輸出到檔案
│ ├── output.h
│ └── output_http //通過http協議輸出
│ ├── httpd.c
│ ├── httpd.h
│ ├── Makefile
│ └── output_http.c
├── README
├── start.sh //啟動控制指令碼
├── utils.c
├── utils.h
└── www //html頁面資原始檔,使用http輸出外掛時呼叫
├── bodybg.gif
├── cambozola.jar
。。。。。
└── style.css

input-plugin負責產生圖片並把這些複製到記憶體中去。相應的output-plugin則負責把這些記憶體中的圖片取出來以便後續的處理。最常用的是webserver-output-plugin,他允許將圖片傳送到網路瀏覽器上。mjpg-streamer充當粘合劑的角色,把這單一的input-plugin和眾多的output-plugin給連在一起,而幾乎所有的工作都交給了這些個外掛。

input_testpicture.so
這個模組編譯的時候已經加入了圖片(正如其名:test),就是說你沒攝像頭也能進行測試工作(你編譯的對不對)。他也為你提供了一個模板,一個你想寫自己的input-plugin的模板,因為他被實現的儘可能的簡單易懂。它的作用就是把由testpictures模組得到的JPEG-files檔案轉變成一個頭檔案,這個標頭檔案包含了一些被編譯進testpictures模組的圖片(前面說過了)。當被啟用時就會不停的往復上面的那個動作:獲得->轉變。

input_uvc.so
如其名它從相容Linux-UVC V4L2標準的裝置中抓取圖片。

output_http.so
這絕對是個全版本的符合HTTP1.0標準的webserver。通過訪問www資料夾內的html等資原始檔可以實現複雜的網頁功能,入css,javascript,java等。並可接收瀏覽器客戶端的命令實現攝像頭引數調整。

(2)mjpg-streamer視訊傳輸原理

mjpg-streamer程式的視訊傳輸正向它名字描述的一樣,它的原理是把視訊鏡頭拍成的視訊分解成一張張分離的jpg影象資料傳送到客戶端。當客戶端不斷顯示圖片,即可形成相應的影象。

該方法的優點是實現簡單,客戶端實現簡單,不會出現馬賽克的情況。缺點就是佔頻寬比較大,因為是一幀一幀按影象來傳輸的。

MJPG可以在多種傳輸協議上傳輸,比如TCP/UDP,最常見是在HTTP上採用傳輸。大部分的攝像頭也是採用HTTP+MJPG的傳輸形式的。

(3)mjpg瀏覽器傳輸技術分析

mjpg的在http的mime type是”x-mixed-replace”,但mjpg 首先是要由客戶發一個GET取一個特殊檔案(不同攝像頭有不同的定義)。如果ipcam返回200,表示已經接收的請求,並在返回的頭裡指明邊界字串,這是在context type的boundary子屬性來指明的。
然後ipcam開始傳送JPG資料,首先是傳送型別和長度。Content-Type= image/jpeg以及用Content-Length指向隨後的長度。當一個圖傳送完畢後,以邊界字串來結束。

(4)mjpg-streamer的協議說明

首先是傳送 GET /?action=stream\n\n
伺服器響應200表示聯接成功。並指明是multipart/x-mixed-replace的mjpg資料,邊界字串是“boundarydonotcross”

HTTP/1.0 200 OK
Connection: close
Server: MJPG-Streamer/0.2
Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0
Pragma: no-cache
Expires: Mon, 3 Jan 2000 12:34:56 GMT
Content-Type: multipart/x-mixed-replace;boundary=boundarydonotcross
--boundarydonotcross

接下是開發傳送JPG資料

Content-Type: image/jpeg
Content-Length: 19454
<中間19454位元組就是一個JPG完整的影象>
--boundarydonotcross

當連續不斷髮送這個資料,在客戶端即可顯示視訊