Linux 的應用(刊載於 PC2000 雜誌十二月號)-- Video Streaming 探討 (6)
本期將是我們一系列 Video Streaming 專欄的結束,本期最重要的工作當然免不了是對之前的內容做系統性的整理,然後再對 Video Streaming 的應用就目前最被討論的理論做簡單介紹。
作者: 陳俊宏
www.jollen.org
Video Streaming 系統概觀
一個完整的 Video Streaming 系統應該包含四個部份:
-
Content (例如影像、聲音、coded 資料)
-
Server
-
Client
-
Data network (例如 Internet,或任何連結 server-client 的媒介)
那麼我們在這一系列 Video Streaming 主題介紹的有那些呢?從一開始的名詞介紹、影像擷取、RTP 通訊協定,我們將重心放在 contente 與 data network 上。當然我們系列主題名為「Linux 的應用」,最關鍵的地方則是在如何在 Linux 環境下設計影像擷取程式。
對於 data network 的部份因為與 Linux 較無關,但也是 Video Streaming 的重點主題之一,所以也介紹了 jrtplib 這套程式庫給大家,在底下的部份也會補充 Nsync 這套 toolkit。
而 server 端似乎是我們著墨不深的地方,但也沒關係,在這最後一篇的文章裡,我們針對理論方面做補充的介紹,我們將以 Video Conferencing 實作時,實務上會面臨的主題來做解,包括:多媒體資料的儲存、OS 的磁碟排程 (SCAN-EDF),以做為您搜尋參考資料的起頭。
在 client 方面,我們在最後的完整版範例程式時,示範了如何利用 SDL 將擷取下來的影像資料秀在螢幕上。這裡也會配合了上一篇所介紹的 mmap 擷取方式,以將影像資料填入 SDL 的 display 結構方式秀圖。
Video Streaming 的開始
我們一開始就介紹了 Video Streaming 是一種經由網路來撥放影音檔案的技術,Video "Streaming" 的基本概念爲「一邊下載一邊撥放」,我們稱之爲「Play as received」。
經由 Internet 如果要收看遠端伺服器的電影檔案,最原始的做爲是「下載後再撥放」,也就是經由 FTP 或 HTTP 將整個檔案下載至本地端後再利用撥放程式來撥放,我們稱之爲「Play after download」。
舉個最簡單的情況,你可能在下載 MP3 之前想要試聽一下音樂的內容,而下載音樂片段的方式又顯得不夠友善,這時如果利用 Video Streaming 的技術來讓網友視聽,不但方便,而且不必浪費時間來下載不喜歡的音樂的。
除此之外,大家最熟悉的莫過於在線上即時播放影片的 real player了。
Real Video 產品介紹
Real Video 是 Real Networks 公司的產品,Real Video 主要支援了 video-on-demand*1 的功能。Real Video 可以讓我們經由網站來播放串流影像 (streaming video)。
由於我們的最終目的是實作出一個可以做 video streaming 的軟體,所以在這裡我們將以 Real Video 做為標竿,並以 Linux 為基礎來設計 video streaming 的軟體。
其它經典的 streaming 範例程式
網路上有幾套很值得玩味研究的相關開放原始碼軟體,我們也曾經提過。VIC 和 VideoLAN 則是其中絕對優秀的教學範例。
VIC
VIC 也是屬於 Open Source 的軟體。VIC 全名為video conferencing,故名其義,VIC 是一種視訊會議的軟體。VIC 是由加州柏克來大學的 Network Research Group 所發展。
VIC 是相當棒非常適合用來研究 Video Streaming 的 Open Source 軟體,主要是因為 VIC 幾乎包含了 Video Streaming 相關的技術。
VIC 值得我們研究的原因是因為 VIC 支援了底下所列的功能:
-
IPv6
-
使用 video4linux 的影像擷取功能
-
H261、H263 與 H263+ codec
-
Software JPEG 與 BVC 編碼
-
Raw YUV packetiser/codec
-
RTIP/RTP 通訊協定
-
the IP Multicast Backbone (MBone)
-
支援 video4linux 的 mmap
這些特色幾乎已經包括 Video Streaming 所應具備的技術了,基於這些特點,VIC 的原始程式碼相當吸引人,因此有意研究 Video Streaming 的 programmer 應該好好閱讀一下 VIC 的原始程式碼。
VideoLAN
VideoLAN 是一個可以做 MPEG 與 DVD 擴播 (broadcast) 播放的軟體,VideoLAN 分成二個部份,一個是 VLAN server,另一個則是 vlc 用戶端播放程式。
VLAN server 將 DVD 與 MPEG 影像利用 broadcast 方式擴播到區域網路上,使用者端再利用 vlc 接收封包並播放。這樣做的好處是可以減少重覆的 I/O 動作,VLAN server 將影像擴播出去後,區域網路上的用戶端再利用 vlc 接收封包並播放。
VideoLAN 支援 X11、SDL、Linux framebuffer、GGI、BeOS API、MacOS X API 播放方式,並且支援 DVD 與 AC3 (杜比音效)。
影像編碼技術介紹 (coded)
目前學術界已經發展出許多處理影像訊號壓縮及編碼的技術 (codecs),談到這些技術,應用最廣泛的編碼標準底下四種:
-
H.261
-
H.263
-
JPEG, MJPEG
-
MPEG
本文第一篇文章就是在對這四種編碼技術做簡單的介紹。
data network 的技術主題
Video 在做 Streaming 時,有三種方式可以應用:broadcasting、unicasting、multicasting。
broadcasting 的方式比較單純,他是在 LAN 上直接將一個個的影像封包丟到網路上 (server 端),再由 client 的應用程式自網路上取回封包播放。但網路硬體層上,仍有許多需要考慮的問題,例如在 Shared Non-Switched Enthernet 上時,就會發生一些小問題。
unicasting 與 multicasting 都是屬於 IP 的傳輸方式。unicasting 採取 1 對 1 的方向傳影像給遠端,稱為 Video-on-Demand (VoD),multicasting 則是 1 對多的傳輸方式,稱為 Near-Video-on-Demand (NVoD)。未來 IPv6 將支援 IP Multicasting,因此 Video Streaming 的應用將更為廣泛。
在通訊協定方面,我們也介紹了 RTP。
RTP 全名為 Real-Time Protocol,RTP 是在 UDP 封包之前多加 10 bytes 的檔頭,裡面記載有時間、序號、壓縮型態等資訊。RTP 是目前大多數 Video Streaming 軟體所使用的通訊協定。
RTP 可用來針對各種不同的多媒體格式做 Streaming 的工作,因為我們將影像分解成數個 RTP 封包再傳送出去,因此會遇到許多網路技術常會遇到的問題。例如,因為封包送達的時間不一,造成播放時會畫面不流暢的現像,因此,在播發時就必須使用一個緩 衝區 (playout buffer) 來暫時存放並處理網路上接受到的封包。
由網路上接收的影像封包因為彼此之間到達的時間間隔不同 (Synchronous Data Packets),所以必須利用緩衝區將這些封包做緩衝,讓彼此之間的時間間隔一樣 (Isochronous Data Packets)。
其它重要的通訊協定像是 SIP、或是 FEC (forward error correction) 除錯技術,都是一定要去研究的主題。
影像擷取卡
在 Linux 下設計影像擷取程式,當然一定要配備有適合的影像擷取卡。
我們曾經介紹給大家的是 Osprey 100 這張影像擷取卡。Osprey 100 是 Real Networks 公司所推薦配合他們產品的一張影像擷取卡,配合 Osprey 100 與 RealNetworks 的產品我們可以利用 broadcast 或 on-demand 做到實況轉播 (live) 的功能。
Osprey 100 在硬體功能上可以支援到每秒 30 個畫面 (fps -- frame per second),並且支援 NTSC 與 PAL 輸入。
不過在實作上,筆者並不使用 Osprey 100。筆者使用的影像擷取卡是 ,這張卡算是比較「俗」一點的卡,但是也有好處,因為在 Linux 上很容易安裝。
以筆者這張卡為例,使用的是 Brooktree Corporation 的卡,所以只要安裝 bttv 模組即可,同時,bttv 模組在 Linux kernel 2.2.17 下也會用到 i2c-old 與 videodev 兩個模組,所以也要一併安裝。在命令列下,安裝這三個模組的命令為:
linux# insmod i2c-old
linux# insmod videodev
linux# insmod bttv
當然要確定 Linux kernel 有編譯這三個模組的支援,然後再把這三個模組加到 /etc/modules.conf (Red Hat 7.0) 裡。
不同版本的 kernel 所要安裝的模組不一定相同!還請注意,例如 i2c 相關模組就是如此。
Linux 上可用的影像擷取卡
在http://www.linhardware.com/db/searchproduct.cgi?_catid=17 網頁上可以找到在 Linux 上支援程度比較好的幾張影像擷取卡。而一般 Linux 上較受歡迎的影像擷取卡則是 Hauppauge 的幾張卡, 筆者使用的也是 Hauppauge 的卡。
在 linhardware 網站上可以找到底下六張卡:
-
Hauppauge 401 WinTV-radio dbx-TV stereo
-
Hauppauge WinTV PCI TV Card
-
Hauppauge WinTV-GO PCI TV Card
-
Hauppauge WinTV-PCI Hauppauge
-
Hauppauge WinTV-Radio+NICAM
-
Hauppauge WinTV/PCI TV Card
關於 Linux 對於影像擷取卡支援的中文文件 (HOWTO) 可以在 CLDP 網站上取得:
影像擷取卡支援的視訊系統
大部份影像擷取卡都會具備一組視訊輸入端子, 即 S-Video (Y/C) 端子或 Composite 端子。
在台灣的標準當然是 NTSC 系統, 一般而言, 我們是希望一張影像擷取卡可以支援越多視訊系統越好, 包括: NTSC/PAL/PALN/PLAM/SECAM。
可使用的視訊裝置有較常見的 CCD, 或是家用 V8、Hi8 皆可, 一般而言我們也是希望一張影像擷取卡可以接越多視訊裝置越好。
BT 878 晶片
跟隨在影像擷取卡之後的主題當然就是 BT878 晶片的介紹,因為支援 BT 8x8 晶片的 BTTV 軀動程式是我們設計影像擷取軟體的核力主力!
目前大部份的數位影像擷取卡大部份都是以 BT878 單顆晶片為影像擷取卡之中心。BT878 運作方式是以軟體來進行影像解壓縮工作, BT878 晶片負責將擷取之影像丟給 Linux 做影像處理, 而 BTTV 則是 Linux kernel 的 BT878 晶片軀動程式。
由於影像是利用 BT878 擷取後交由軟體來做影像處理, 因此在處理效能上自然就會比較差。如果是經由網路來傳送影像的話, 我們就會再利用影像壓縮技術 (H.261/H.263...等等) 來做影像處理。
什麼是 BTTV
BTTV 是 Linux 上的 Bt848/849/878/879 晶片的軀動程式, 主要功能是做頁框的截取 (frame grabber)。
BTTV 是 video4linux 裡重要的軀動程式, 目前分為二個版本:
-
0.8.x 的發展中版本
-
0.7.x 的穩定版本
BTTV 相關應用軟體 - xawtv
官方網站: http://bytesex.org/xawtv/index.html
安裝方式:
linux# ./configure
linux# make depend
linux# make
linux# make install
如果您有 Red Hat Linux 7.1 PowerTools 光碟片的話, 也可以直接由 PowerTools 光碟片安裝 xawtv 套件:
linux# rpm -ivh xawtv-3.34-1.i386.rpm
安裝 xawtv 需要 libjpeg 與 libjpeg-devel 套件, 如果您是使用 Red Hat Linux 7.1 的話, 應該安裝底下二個套件:
-
libjpeg-6b-15.i386.rpm (Disc 1)
-
libjpeg-devel-6b-15.i386.rpm (Disc 2)
xawtv 整個架構可以分成 7 個部份如下:
-
xawtv: 主程式部份。
-
fbtv: linux console 模式的 TV 應用程式, 使用 linux kernel 2.2.x 的 framebuffer。
-
set-tv: 命令列模式的工具, 用來設定 video4linux 的參數。
-
streamer: 命令列模式的工具, 用來捉取動態影像與 avi 影像。
-
radio: radio 應用程式。
-
webcam: 將捉取的影像以 FTP 方式上傳到 Web Server 端, 用來設計 Web 即時影像的工具。
-
alevtd: videotext pages 的 Web Server。
xawtv 的 video4linux
xawtv 是相當好的 video4linux 方面的教材,我們極力推薦讀者研究 xawtv 的 video4linux 部份的原始碼。
將取回 xawtv 的原始程式碼解開後, 在 libng/ 目錄下可以看到 grab-v4l.c 的檔案, 另外還有一個 grab-v4l2.c 的檔案, 這是 video4linux2 (version 2) 的版本。
在 xawtv 的 video4linux 主題現身之前,我們很詳盡介紹了 video4linux 的基本設計方法,接下來在 xawtv 之後更是再進一步說明了 video4linux 的經典 – mmap 擷取技巧。
那麼跨越三期內容的程式碼那一個才是完整的呢?事實上都沒有,不過請讀者們放心,本期我們將列出所有我們曾經介紹過的主題所實作的程式,當然是完整的實作程式碼!
video4linux 使用的設備檔
Linux 下與 video4linux 相關的設備檔與其用途:
/dev/video | Video | Capture Interface |
/dev/radio | AM/FM | Radio Devices |
/dev/vtx | Teletext | Interface Chips |
/dev/vbi | Raw | VBI Data (Intercast/teletext) |
video4linux 除了提供 programmer 與影像擷取有關的 API 外,也支援其它像是收音機裝置。
接下來介紹 video4linux 設計方式,所使用的 Linux kernel 版本為 2.2.16。這篇文章將簡單介紹實作 video4linux 的方法,所以請準備好 Linux kernel 原始碼下的 Documentation/v4l/API.html 文件並了解 What's video4linux。
Video Streaming 的其它關鍵議題
接下來的主題將介紹 Video Streaming 其它值得研究的主題,我們會在最後才提出來的原因是因為這些主題將不會影響我們之前的程式實作,但在設計完整的 Video Streaming 系統時,則是有必要加以考慮的。
Video Conferencing 應用的重要性
Video Conferencing 在多媒體設計上之所以重要,最重要的原因是因為 Video Conferencing 渉及的技術議題包括:
-
即時性問題 (real-time systems problem)
-
互動式應用程式的 latency 與 throughput 問題
這樣的問題當然首先是發生在網路頻寬的問題上,由於網路視訊會議系統耗費大量的頻寬,而且網路視訊會議的品質也容易受網路品質與頻寬影響,因此這是值得我們研究的問題之一。
Video Conferencing 另外一個迷人的地方是在於 Video Conferencing 提供良好的 person-to-person 環境。Video Conferencing 應用軟體在多媒體程式設計上,常常也被視為「殺手級」的應用之一,可見 Video Conferencing 應用的重要性。
Video Conferencing 的應用領域
Video Conferencing 目前的應用領域則是有:遠距教學 (distance learning systems)、遠端診視系統 (remote consultation systems)、遊戲…等等。
就如同我們先前所講的,解決網路、傳輸問題變成是下一代通訊應用的的關鍵。在軟體的支援上也是如此,當然這其中有許多的解決方案是設計新的多媒體作業系統 (Multimedia Operating Systems) 來解決。
因為我們要實現 VOD 的技術,因此將會涉及網路的主題,所以要考慮的層面也會比較多。除了網路相關問題外,也會在底下一併討論其它幾個主要的大問題。
Video Streaming 的傳送問題
Video Conferencing 所遭遇到的第一個問題是如何遞送 (deliver) 影像串流 (video streams),這其中又要考慮到串流的管理、與網際網路即時性 (real-time over the Internet) 問題。
Video Conferencing 重要的關鍵之一是在於如何有效縮短 latency。所以我們也必須尋找一個有效的方便,來適應各種不同網路頻寬的環境。
Video Streaming 的資料儲存問題
Video Streaming 的應用還要考慮的問題則是儲存設備 (storage) 的選擇。Video Streaming 的應用必須要有良好的儲存環境,來儲存各種型態的多媒體資料,包含:文字、影像、聲音、圖片等等,每種資料的特性都不相同。
檔案系統 (filesystem) 對於多媒體物件的管理也是很重要的因素之一,必須要有一個可以快速存取並且有效管理多媒體物件的檔案系統,才能滿足效能的需求。
作業系統的磁碟儲存
在現階段 Video Streaming 以至於多媒體應用程式的設計上,對於 OS 支援的磁碟排程 (Disk Scheduler) 也被列入我們考慮研究的項目之一。傳統上,一般我們設計 OS 時都會選擇 SCAN 或是 SSTF 演算法,不過這些傳統的磁碟排程演算法並無法滿足我們的需求。
較先進的磁碟排程演算法應考慮到 Video 與 Audio 的應用,而目前較普遍被選擇用來設計 multimedia I/O 系統的磁碟排程演算法則是 SCAN-EDF 演算法。
SCAN-EDF 演算是結合 SCAN 與 EDF 優點的解決方案,SCAN 是眾所皆知的 seek optimizing 磁碟排程演算法;而 EDF (Earliest Deadline First) 則是屬於 real-time scheduling 的演算法。
磁碟排程對於 Video Streaming 應用的影響
引進 SCAN-EDF 磁碟排程演算法的重要之處在於我們必須要能支援 real-time request,其影響的範圍包括:
-
Maximum allowable streams
-
Reponse time
SCAN-EDF 已被分析並證實可以改善以上的效能,那麼,對於目前廣受歡迎的 Linux 而言,由於 SCAN-EDF 已經早就在實作應用的範圍內了,我們可以將 SCAN-EDF 磁碟排程演算法加到 Linux kernel 裡。如此一來,Linux 在 Video Streaming 的應用上也算是重要的效能改良。
Video Conferencing 的 Synchronization 問題
當我們進行多方 (n-way) 視訊會議時,程式總不能讓每個人所看到的影像畫面都不相同吧!就算無法真正做到每個人的畫面同一時間都相同,但至少也要控制在合理可接受的範圍之內。
Synchronization (同步) 問題的研究主要是在建立互動式 (interactive) 的多媒體應用程式上,同步問題的解決是需要相當多的時間與精神的,好在目前有重量級的 toolkit 供我們使用,那就是 Nsync (in-sync)。
Nsync 共包含二大部份:
-
Synchronization definition language
-
Run-time presentation management system
當然我們的 Video Conferencing 應用程式當然也需要 Nsync 的幫忙!
程式補充包
底下我們將補充二個簡單的函數,供讀者使用,這二個函數與我們的範例程式並沒有直接關係,但在測試時可能會有機會使用到:
-
jpeg.c:將擷取的影像資料利用 libjpeg 存成 JPEG 圖檔。
-
ppm.c:將擷取的影像直接寫成 PPM 圖檔。
存成 JPEG 圖檔部份
檔案:jpeg.h
/*
* JoTV - Video Streaming Systems
* (c) 2001 Jollen <jollen@o3.net>
*/
#ifndef _JPEG_H_
#define _JPEG_H_
int write_jpeg(char *filename, IMG *img, int width, int height,
int quality, int gray);
#endif
檔案:jpeg.c
/*
* JoTV - Video Streaming Systems
*
* jpeg.c - output image to the jpeg files
* (c) 2001 Jollen <jollen@o3.net>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <jpeglib.h>
#include <jerror.h>
#include <jconfig.h>
#include <pthread.h>
#include <sys/param.h>
#include <sys/types.h>
#include "JoTV.h"
int write_jpeg(char *filename, IMG *img, int width, int height,
int quality, int gray)
{
struct jpeg_compress_struct jcfg;
struct jpeg_error_mgr jerr;
FILE *fp;
unsigned char *line;
int line_length;
int i;
if ((fp = fopen(filename,"wb")) == NULL) {
fprintf(stderr,"write_jpeg: can't open %s: %s\n", filename, strerror(errno));
return -1;
}
jcfg.err = jpeg_std_error(&jerr);
jpeg_create_compress(&jcfg);
jcfg.image_width = width;
jcfg.image_height = height;
jcfg.input_components = gray ? 1: 3; // 3 sample per pixel (RGB)
jcfg.in_color_space = gray ? JCS_GRAYSCALE: JCS_RGB;
jpeg_set_defaults(&jcfg); // problem ...
jpeg_stdio_dest(&jcfg, fp);
jpeg_set_quality(&jcfg, quality, TRUE);
jpeg_start_compress(&jcfg, TRUE);
line_length = gray ? width : width * 3;
line = (unsigned char *)img;
for (i = 0; i < height; i++, line += line_length)
jpeg_write_scanlines(&jcfg, &line, 1);
jpeg_finish_compress(&jcfg);
jpeg_destroy_compress(&jcfg);
fclose(fp);
return 0;
}
函數的呼叫方法如下,直接加到範例的主程式裡即可:
write_jpeg("JoTV.jpg", img, DEFAULT_WIDTH, DEFAULT_HEIGHT, 75, FALSE /*not grey*/);
中標=存成 PPM 圖檔部份
檔案:ppm.c
/*
* JoTV - Video Streaming Systems
*
* ppm.c - output image to the ppm file
* (c) 2001 Jollen <jollen@o3.net>
*/
int write_ppm(IMG *);
int write_ppm(IMG *img)
{
FILE *fp;
fp = fopen("test.ppm", "w");
fprintf(fp, "P6\n%d %d\n255\n", NTSC_WIDTH, NTSC_HEIGHT);
fwrite(img, NTSC_HEIGHT, 3*NTSC_WIDTH, fp);
fclose(fp);
}
數的呼叫方法如下,直接加到範例的主程式裡即可:
write_ppm(img);
圖檔會存成檔名:test.ppm,由於大部份的繪圖軟體對於 TIFF 的支援較好,所以可以再利用 ppm2tiff 工具將 PPM 圖檔轉成 TIFF 格式:
$ ppm2tiff test.ppm test.tif
Video Streaming 的應用實例
經過這一系列的 Linux Video Streaming 應用探討,我們已經可以有能力設計出許多簡單的 Video Streaming 應用程式。例如以 video4linux、bttv、rtp 和 jpeg 壓縮技術便能實作簡單的 Webcam 應用程式。
底下是我們利用 Java 實作出來的 Linux Webcam 應用程式,在遠端直接以瀏覽器來執行即可。
圖 1 利用 Java 與 Video Streaming 技術設計的 Linux Webcam
圖 2 利用 Java 與 Video Streaming 技術設計的 Linux Webcam
Webcam 與 CCD 結合的應用包括:遠距教學、視訊會議、安全監控…等等。