在Cubieboard上用USB WebCam 來做 real-time video streaming
想法
手上的CubieTruck 板子是用Allwinner A20的CPU, 其內部有一個A hardware video unit (VE), 可以用來做Video Encoder/Decoder. 看了一些sunxi 社群的資料CedarX, 及一些網站上的討論, 就手癢也來開始玩玩, 目標是將USB WebCam 抓下來的影像, 即時用H.264 硬體壓縮, 再 stream 出去. 在client 端, 我用VLC 來收看這個real-time 的 live video.
Linux Kernel
首先要使用CedarX 的Encoder, 在linux kernel 中要有sunxi_mem 及 cedar driver. 目前sunxi-linux 只有整合cedar driver, 但是並沒有把sunxi_mem driver 整合進去, 所以參考了juanfont的patch, 將其加入到sunxi-linux 的最新kenel source 中.
並且在kernel config 中確認有下列設定:
CONFIG_SUNXI_PHYS_MEM_ALLOCATOR=y
CONFIG_VIDEO_SUNXI_CEDAR=m
然後編譯linux kernel.
我已在這篇文章“從source code 開始打造最基本的Debian linux system” 提到的script 中加入sunxi_mem driver 的支援, 所以有興趣的人, 可以到GitHub這裏 中抓取這些script 來build linux kernel 比較快..
啟用kernel module.
做好kernel image 後, 將其放入你原有的root file system 中, 並且在/etc/modules 加入此行:
sunxi_cedar_mod
然後啟動linux, 請確認在/dev中有下列兩個device
# ls /dev/cedar_dev /dev/sunxi_mem
/dev/cedar_dev /dev/sunxi_mem
若出現這兩個device, 表示你的linux kernel 是ok的了.
若要讓一般user 也能有access 這兩個device 的權限, 請修改/etc/udev 的內容如下:
echo 'KERNEL=="sunxi_mem", MODE="0666"' >> /etc/udev/rules.d/80-cedar.rules
echo 'KERNEL=="cedar_dev", MODE="0666"' >> /etc/udev/rules.d/80-cedar.rules
順便也將USB webcam 的裝置也改成讓一般user 也能access.
echo 'KERNEL=="video?", SUBSYSTEM=="video4linux", MODE="0666"' >> /etc/udev/rules.d/81-v4l2.rules
編譯 libav
libav 是從ffmpeg fork 出來的project, 他也可以說是ffmpeg 的後繼. 它具有跟ffmepg 一樣的功能, 及非常相似的命令參數. 他也可以拿來做 live video stream . 目前許多linux distribution 已經將libav納入其official packages中了. 只是目前libav 及ffmpeg 不提供A20 VE 的支援.
但是網路總有神人出現. alcantor 的實作, 他已經提供libav 的patch file , 可以使用A20 CedarX 的hardware encoder., 所以我也依樣畫葫蘆做了一遍.
要在CubieTruck 板子中Debian 要編譯libav 需要先安裝 libx264-dev libmp3lame-dev libfaac-dev 這些library. 只是libfaac-dev 並不在official package list 中.
目前是由 deb-multimedia來maintain.
所以先將deb-multimedia 納入apt 的source list中, 作法如下:
# echo "deb http://www.deb-multimedia.org wheezy main non-free" >> /etc/apt/sources.list
# echo "deb http://www.deb-multimedia.org wheezy-backports main" >> /etc/apt/sources.list
# apt-get update
# apt-get install deb-multimedia-keyring
然後安裝 libx264-dev libmp3lame-dev libfaac-dev packages
# apt-get update
# apt-get install libx264-dev libmp3lame-dev libfaac-dev
若是在x86的環境下, 還需要安裝 yasm 這個package, 但由於目前是在ARM的環境中編譯libav, 所以就不用裝這個套件啦.
若是想要順便編譯avplay程式, 還需要安裝SDL library.
# apt-get install libsdl1.2-dev
接下來就是抓取libav 的source code, sunxi-armhf libcedarv binaries 及其header file.
然後加上這個libav 的patch. 詳細步驟請參考alcantor 的實作. 在這裡, 我已經將這些source code 整合到這個GitHub 的repository了, 所以步驟簡化如下:
# git clone https://github.com/haotseng/libav.git -b A20-cedar
# cd libav
# ./configure --enable-nonfree --enable-gpl --enable-vdpau --enable-libx264 --enable-libmp3lame --enable-libfaac
# make -j2
編譯完後, 就可以開始測試avconv 是否能用.
測試 libav 的 avconv
我使用的是Microsoft 的 Microsoft® LifeCam HD-3000. 插入USB WebCam 後, 先確認是否有支援此USB webcam.
# ls /dev/video?
/dev/video0
# v4l2-ctl --all
Driver Info (not using libv4l2):
Driver name : uvcvideo
Card type : Microsoft® LifeCam HD-3000
Bus info : usb-sw-ehci-1
Driver version: 3.4.103
Capabilities : 0x04000001
Video Capture
Streaming
Format Video Capture:
Width/Height : 640/480
Pixel Format : 'YUYV'
Field : None
Bytes per Line: 1280
Size Image : 68392364
Colorspace : SRGB
Crop Capability Video Capture:
Bounds : Left 0, Top 0, Width 640, Height 480
Default : Left 0, Top 0, Width 640, Height 480
Pixel Aspect: 1/1
Video input : 0 (Camera 1: ok)
Streaming Parameters Video Capture:
Capabilities : timeperframe
Frames per second: 0.009 (71/7635)
Read buffers : 0
使用avconv 來擷取WebCam 的Video 並且使用硬體壓縮成H2.64格式
# cd libav
# LD_LIBRARY_PATH=sunxicedar/lib/A20-sunxi-rt ./avconv -y -f video4linux2 -s 640x480 -r 30 -i /dev/video0 -filter:v pad="trunc((iw+0)/32)*32:ih:0:0" -c:v cedarh264 -f mp4 test.mp4
這時就開始錄製mp4 檔案了, 若要停止, 請按ctrl-c 結束. 把test.mp4 copy 到你的PC 來看看, 是否有錄製成功.
開始做 live video stream
avconv 支援即時串流協定(RTSP), 要使用之前, 要先產生SDP file, 假設你的client 端PC 的IP address 為 192.168.1.1, 則產生方式如下:
# cd libav
# LD_LIBRARY_PATH=sunxicedar/lib/A20-sunxi-rt ./avconv -y -f video4linux2 -s 640x480 -r 30 -i /dev/video0 -filter:v pad="trunc((iw+0)/32)*32:ih:0:0" -c:v cedarh264 -f rtp rtp://192.168.7.139:1234
avconv version v12_dev0-653-g64019ad, Copyright (c) 2000-2015 the Libav developers
built on Jan 9 2015 13:49:33 with gcc 4.6 (Debian 4.6.3-14)
[video4linux2 @ 0x237f100] Estimating duration from bitrate, this may be inaccurate
Input #0, video4linux2, from '/dev/video0':
Duration: N/A, start: 87106.926535, bitrate: 147456 kb/s
Stream #0:0: Video: rawvideo [YUY2 / 0x32595559]
yuyv422, 640x480, 147456 kb/s
30 fps, 1000k tbn
[cedarh264 @ 0x2381340] cedarx_hardware_init
D/cedarv_osal_linux: (177) use sunxi_alloc_open
D/cedarv_osal_linux: (321) init hw ref count:1
D/cedarv_osal_linux: (523) cedar_sys_phymalloc_map
D/cedarv_osal_linux: (528) cedar_sys_phymalloc_map2
D/cedarv_osal_linux: (523) cedar_sys_phymalloc_map
D/cedarv_osal_linux: (528) cedar_sys_phymalloc_map2
D/cedarv_osal_linux: (523) cedar_sys_phymalloc_map
D/cedarv_osal_linux: (528) cedar_sys_phymalloc_map2
D/cedarv_osal_linux: (523) cedar_sys_phymalloc_map
D/cedarv_osal_linux: (528) cedar_sys_phymalloc_map2
D/venc: (232) venc_ctx->base_cfg.codectype = 0
D/cedarv_osal_linux: (523) cedar_sys_phymalloc_map
D/cedarv_osal_linux: (528) cedar_sys_phymalloc_map2
D/cedarv_osal_linux: (523) cedar_sys_phymalloc_map
D/cedarv_osal_linux: (528) cedar_sys_phymalloc_map2
D/cedarv_osal_linux: (523) cedar_sys_phymalloc_map
D/cedarv_osal_linux: (528) cedar_sys_phymalloc_map2
D/cedarv_osal_linux: (523) cedar_sys_phymalloc_map
D/cedarv_osal_linux: (528) cedar_sys_phymalloc_map2
D/cedarv_osal_linux: (523) cedar_sys_phymalloc_map
D/cedarv_osal_linux: (528) cedar_sys_phymalloc_map2
D/cedarv_osal_linux: (523) cedar_sys_phymalloc_map
D/cedarv_osal_linux: (528) cedar_sys_phymalloc_map2
[cedarh264 @ 0x2381340] Input Stream: 640x480@30 fps encode at 200000 bits/s
Output #0, rtp, to 'rtp://192.168.1.1:1234':
Metadata:
encoder : Lavf56.11.0
Stream #0:0: Video: libx264
yuv420p, 640x480, q=2-31, 200 kb/s
30 fps, 90k tbn, 30 tbc
Metadata:
encoder : Lavc56.11.0 cedarh264
Stream mapping:
Stream #0:0 -> #0:0 (rawvideo (native) -> h264 (cedarh264))
SDP:
v=0
o=- 0 0 IN IP4 192.168.1.1
s=No Name
c=IN IP4 192.168.1.1
t=0 0
a=tool:libavformat 56.11.0
m=video 1234 RTP/AVP 96
b=AS:200
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z0IAH+VAUB7I,aM4xEg==; profile-level-id=42001F
Press ctrl-c to stop encoding
frame= 93 fps= 8 q=-1.0 size= 82kB time=3.07 bitrate= 218.4kbits/s
注意畫面中”SDP:” 以下的文字
v=0
o=- 0 0 IN IP4 192.168.1.1
s=No Name
c=IN IP4 192.168.1.1
t=0 0
a=tool:libavformat 56.11.0
m=video 1234 RTP/AVP 96
b=AS:200
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z0IAH+VAUB7I,aM4xEg==; profile-level-id=42001F
按下ctrl-c , 中斷avconv程式.
將此段文字擷取下來, 存成my_video_stream.sdp, copy 到你的PC 端中.
在你的PC 端, 使用VLC 來開啟my_video_stream.sdp 檔.
然後在CubieTruck 板子上再次執行
# LD_LIBRARY_PATH=sunxicedar/lib/A20-sunxi-rt ./avconv -y -f video4linux2 -s 640x480 -r 30 -i /dev/video0 -filter:v pad="trunc((iw+0)/32)*32:ih:0:0" -c:v cedarh264 -f rtp rtp://192.168.7.139:1234
大約10秒後, PC 端的VLC 就可以看到即時的影像了.
參考資料
- avconv H.264 Hardware encoding mit Cubietruck (Mediatomb transcoding)
- Streaming Video using RTP on the Beaglebone Black
- ffmpeg/avconv使用学习笔记
- ffmpeg/avconv 轉檔與影片連接範例
- avconv Documentation
- ffmpeg H264 encoding with cedrus
- VLC 建立 RTSP 串流伺服器
- H.264的SPS和PPS串 第一个字节的低5位判断是否为7(sps)或者8(pps)
- 在 Linux 以 VLC 搭配 Jtvlc 進行實況
- SDP (Session Description Protocol) 閱讀心得
- Raspberry Pi camera RTSP 影像串流
- 即時串流協定
- Advanced streaming using the command line
- Streaming webcam audio and video using ffmpeg/avconv
- How to stream video from webcam to network with ffmpeg?
您好
請問 只有 client 端PC (192.168.1.1) 能打開my_video_stream.sdp 檔,其他 IP 的client 端PC 不能使用嗎?
以這個例子來說, 是的, 他是傳送到指定的IP, 所以只有192.168.1.1 能夠收到.
若是想要讓其他的人也能收到. 我以前有實做過兩階段轉送影像.
(1)同上方法, 傳送到192.168.1.1
(2)在192.168.1.1 利用VLC收到即時影像後, 再轉成RTSP server.
如此就可以讓任何人連到RTSP server 來觀看即時串流影像了
補充說明, 上述的步驟1, 及步驟2, 都是在同一台機器上跑. 不需要2台機器.
基本上拿VLC 當作RTSP server , 而且串流格式不做修改, 對於CPU 的loading 還算OK, 所以當時就直接用同一台Cubieboard 來完成此功能了