趙宇峰
(鄭州威科姆科技股份有限公司,河南 鄭州 450001)
責任編輯:任健男
三網融合作為國家級的長期戰略,目前已在全國多個省份進行試點,數字機頂盒是三網融合的著力點,隨著嵌入式芯片技術的飛速發展,其性能越來越高、功能越來越復雜,所能承載的業務越來越多樣化。而且隨著視頻編碼功能開始在嵌入式芯片上逐漸普及,以往只能在PC上實現的實時視頻通信業務在機頂盒上實現也成為可能。本文提出一種基于海思HI3716C平臺的實時視頻通信的實現方法,該方法采用USB攝像頭+數字機頂盒+電視機的模式,應用場景示意圖如圖1所示。USB攝像頭實現視頻原始數據的采集,機頂盒完成視頻數據的發送、接收以及編解碼,電視機作為顯示終端進行視頻圖像的顯示,管理服務器用來對在線用戶進行管理。

圖1 實時視頻通信應用場景示意圖
機頂盒終端以海思HI3716C為主芯片。海思HI3716C芯片采用ARM Cortex A9架構的處理器,頻率達到1 GHz,支持 H.264,MPEG-4,H.263 視頻編碼,最大分辨力可達720×576@25 f/s,視頻編碼提供動態碼率和固定碼率模式,支持1路語音編碼。終端的硬件總體結構如圖2所示。

圖2 機頂盒終端硬件總體結構
終端的軟件部分使用嵌入式Linux操作系統和yaffs2文件系統,并以此為基礎開發了視頻點播、網絡直播、本地磁盤音視頻播放、圖片瀏覽等多種業務,本文實現的實時視頻通信是其眾多業務中的一種,本文也只對該業務的實現方法做重點描述。圖3是實時視頻通信業務的軟件框架,其中的UI是與用戶之間的接口,負責接收用戶指令以及呈現給用戶指令處理結果;指令處理模塊負責處理來自UI的指令和來自網絡的消息;網絡交互模塊用于同其他用戶和管理服務器進行交互;采集編碼發送模塊完成視頻數據的采集、編碼和發送;接收解碼顯示模塊進行視頻數據的接解碼及顯示。視頻實時通信的重點在視頻數據的采集、編解碼和發送,因此本文也主要圍繞這幾點進行闡述。

圖3 視頻實時通信業務軟件框架
攝像頭設備是視頻數據來源,要進行視頻通信,首先要使機頂盒能夠支持USB攝像頭設備。目前主流的USB攝像頭一般都符合UVC(USB Video Class)規范,Linux從2.6.26開始將UVC驅動納入內核原生包,只要在配置內核時選擇了UVC選項,嵌入式Linux系統就能很方便地支持符合UVC規范的USB攝像頭設備,另外Linux UVC驅動支持V4L2應用編程接口[1]。本文使用的Linux版本為2.6.35,其源碼中已經包含的UVC驅動,內核編譯完成后,在 linux-2.6.35/drivers/media/video/uvc 目錄下,生成的有uvcvideo.ko,在機頂盒啟動時加載該驅動,在/dev目錄下生成video0設備節點。
在Linux系統進行視頻采集基本都是用V4L2編程接口,V4L2(Video for Linux 2)是Linux內核中視頻設備統一的驅動接口,它采用流水線的方式,在打開視頻設備/dev/video0之后,剩余的操作完全通過ioctl系統調用向驅動發送控制命令的方式來完成[2],所使用到的控制命令按照調用順序如下:
1)控制命令VIDIOC_QUERYCAP,用于查詢視頻設備的功能,如本文中使用的USB攝像頭設備應該具有V4L2_CAP_VIDEO_CAPTURE功能。
2)控制命令VIDIOC_S_FMT,用來設置視頻設備的視頻數據格式,如視頻圖像數據的寬、高和像素格式等。
3)控制命令VIDIOC_REQBUFS,向V4L2驅動請求分配視頻緩沖區,申請多個視頻緩沖區可以提高捕獲圖像的效率,一般不超過5個。
4)控制命令VIDIOC_QUERYBUF,用于查詢在上一步中分配的視頻緩沖區的相關信息,如緩沖區在內核中的偏移地址、長度等信息。因為通過VIDIOC_REQBUFS申請到的緩沖區在內核空間,用戶空間不能直接訪問,所以一般會在通過VIDIOC_QUERYBUF命令獲得緩沖區相關信息后調用mmap內存映射函數將內核空間地址映射為用戶空間地址,之后應用程序就可以直接訪問用戶空間地址來獲取捕獲到的視頻圖像。
5)控制命令VIDIOC_QBUF,將一個空閑的緩沖區放入視頻緩沖區輸入隊列中,在啟動視頻采集后,捕獲到的視頻數據會被保存到此視頻緩沖區,在保存有一幀視頻數據后,這個緩沖區會被放入輸出隊列,在調用后面的VIDIOC_DQBUF命令時就能獲取到該緩沖區。
6)控制命令VIDIOC_STREAMON,用于啟動視頻采集。
7)控制命令VIDIOC_DQBUF,從視頻緩沖區的輸出隊列中取得一個已經保存有一幀視頻數據的視頻緩沖區,因為之前已經調用mmap進行過地址映射,所以應用程序可以直接從用戶空間地址來讀取該視頻數據,然后對視頻數據做進一步的處理。處理完數據之后需要調用VIDIOC_QBUF,將該緩沖區仍舊放入輸入隊列中,進行下一幀視頻數據的獲取。
在攝像頭捕獲到視頻數據之后,為便于數據的遠程傳輸,需要對數據進行壓縮編碼。海思HI3716C平臺支持H.264,H.263和MPEG-4編碼方式,考慮到后續工作中可能有機頂盒與手機終端視頻互同的需求,所以選擇在手機終端視頻解碼支持較好的H.263編碼。為便于應用程序的編寫,海思平臺在應用層中抽象出VI和VENC模塊,其中VI模塊負責將待編碼的視頻數據輸送給VENC模塊,VENC模塊負責對輸入的視頻數據進行壓縮編碼,在海思SDK中提供的有2個模塊的應用層API,這些API在實現視頻編碼時的調用關系如圖4所示。首先要調用相應的接口完成VI模塊和VENC通道的創建,在調用HI_UNF_VENC_CreateChn接口時可以指定視頻碼率,然后調用HI_UNF_VENC_AttachInput接口將VI模塊和VENC通道進行綁定,緊接著啟動圖像采集線程并調用接口HI_UNF_VENC_Start,在圖像采集線程中將V4L2輸出隊列中的一個視頻緩沖區內的數據拷貝到VI模塊的幀緩沖區,VENC模塊對這些數據進行壓縮編碼后輸出已編碼數據。

圖4 視頻編碼接口調用關系示意圖
經過壓縮編碼的數據需要通過網絡傳輸給遠端用戶,視頻傳輸對實時性、同步性要求很高,但是可以容忍數據丟失和出錯,因此所使用的傳輸協議可以是無可靠性保證的,但必須是實時高效的。UDP是面向無連接數據傳輸協議,由于其不提供數據的可靠性保證,所以傳輸時延較短,非常符合視頻傳輸的要求。另外家庭用戶終端多處于NAT設備之后,使用內網IP地址,這種情況下2個機頂盒進行互聯互通需要進行NAT穿透,UDP穿透NAT的技術相對成熟。鑒于以上原因,在此選擇UDP協議作為視頻傳輸協議。
因為IP協議最大傳輸單元(MTU)為1500 byte,如果UDP數據包長度過長,超過了MTU的長度,在IP層就會對其進行重新分組,這樣會大大降低傳輸的效率,而且出錯概率大大增加,所以最好將視頻數據經過分組打包之后再進行UDP傳輸,以保證在傳輸時不會造成IP碎片。本文借鑒RTP協議中RTP分組頭的格式[3],使用其中的M(Marker)、PT(Payload Type)和 SN(Sequence Number)字段,其中M字段占用1 bit,用來表示幀結束,PT字段占用7 bit,用來表示數據編碼類型(按照RTP協議,H.263對應的類型為34),SN字段占用16 bit,用來計數,每發送1個數據包該字段就加1。M,PT和SN字段的總長度占3 byte,UDP的首部是8 byte,IP協議的首部是20 byte,這樣每個UDP數據包中承載的靜負荷的最大長度是1469。對于長度大于1469的視頻幀數據要被打包成多個分組進行傳輸。比如一個長度為5000 byte的視頻幀就要分為4個分組進行傳輸,如圖5所示。

圖5 視頻數據分組封裝示意圖
在接收到遠端用戶發送過來的視頻數據之后,需要對數據進行解碼顯示。與視頻編碼相類似,海思平臺在應用層抽象出了AVPlay和VO模塊,AVPlay模塊用于音視頻的解碼和同步,VO模塊負責視頻的顯示。運用模塊的API可以很方便地實現視頻解碼和顯示,調用關系示意圖如圖6所示。

圖6 視頻解碼接口調用關系示意圖
完成了AVPlay模塊和VO模塊的創建后需要調用HI_UNF_VO_AttachWindow接口將兩者綁定,同時要調用HI_UNF_VO_SetWindowEnable接口將VO中創建的窗口使能,否則視頻是不會顯示的。然后調用HI_UNF_AVPLAY_Start接口并啟動數據接收線程,在線程中接收到來自遠端用戶的視頻數據包之后,需要組裝成幀放入AVPlay幀緩沖區。此后只要AVPlay緩沖區中有數據就會進行視頻數據的解碼。
本節以用戶A和用戶B要進行視頻通信為例來描述一下數據的交互過程。
當用戶啟動機頂盒后,需要向管理服務器發送登錄信息,管理服務器對用戶信息進行記錄,用戶信息包括用戶名、所使用的本地IP、端口號以及是否接有USB攝像頭設備等,同時服務器能獲取到它們登錄管理服務器所使用的公網IP和端口號,也作為用戶信息進行保存。當用戶需要查看在線用戶信息時,向管理服務器發送獲取在線用戶信息的請求,服務器將當前在線的所有用戶的信息返回給用戶。
當用戶A希望和用戶B進行視頻通信時,首先要判斷對方是否和自己在同一局域網,如果是在同一局域網,用戶A可以直接向用戶B的本地IP和端口號發送請求,用戶B收到請求后返回給用戶A確認信息,同時啟動視頻編解碼,用戶A在收到用戶B的確認信息后也啟動視頻編解碼,兩用戶的實時視頻通信就此建立。如果用戶A和用戶B不在同一局域網,則需要進行UDP穿透NAT[4],用戶A向管理服務器發送穿透請求,管理服務器收到之后向用戶B發送穿透NAT指令,用戶B向用戶A的公網IP和端口方向隨便發送一些數據即完成了NAT穿透,用戶A在等待一段時間之后向用戶B的公網IP和端口發送視頻通信請求,此時該請求會被用戶B成功接收,之后兩者可以正常進行通信。此時管理服務器起到了輔助UDP穿透的作用。圖7所示是用戶A和用戶B不在同一局域網的情況。
本文在嵌入式Linux機頂盒上實現了實時視頻通信功能,在局域網內,能較通暢地進行碼率為1 Mbit/s的實時視頻通信,在公網上則需要將碼率限制在500 kbit/s以下。本文只是在初步實現了實時視頻通信,驗證了其在嵌入式終端實現的可行性,在后續的工作中仍需要對業務功能進行不斷優化,首先要添加對音頻的支持,其次要增加根據網絡狀況進行編碼碼率動態調整功能的支持,另外還要考慮機頂盒與其他類型終端的實時視頻通信。

圖7 不同局域網內兩終端視頻通信建立過程
[1]唐人財,劉連浩.基于嵌入式Linux遠程圖像監控系統的設計[J].計算機與現代化,2010(11):31-38.
[2]劉升,趙晶晶,范秀麗.基于V4L2的嵌入式視頻監控系統[J].微計算機應用,2011,32(1):37-42.
[3]陳慶余,朱光喜.一種MPEG-4 over RTP的實現方法[J].電視技術,2001,25(6):27-29.
[4]劉昊東,陳天煌.基于P2P網絡中UDP穿透NAT技術的研究[J].計算機與數字工程,2009,37(12):112-114.