陈俊宏
www.jollen.org
本期将是我们一系列 Video Streaming 专栏的结束,本期最重要的工作当然免不了是对之前的内容做系统性的整理,然后再对 Video Streaming 的应用就目前最被讨论的理论做简单介绍。
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 端似乎是我们着墨不深的地方,但也没关系,在这最后一篇的文章里,我们针对理论方面做补充的介绍,我们将以VideoConferencing 实作时,实务上会面临的主题来做解,包括:多媒体资料的储存、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-SwitchedEnthernet上时,就会发生一些小问题。
unicasting 与 multicasting 都是属于 IP 的传输方式。unicasting 采取 1 对1的方向传影像给远端,称为 Video-on-Demand (VoD),multicasting 则是 1对多的传输方式,称为Near-Video-on-Demand (NVoD)。未来 IPv6 将支援 IP Multicasting,因此VideoStreaming 的应用将更为广泛。在通讯协定方面,我们也介绍了 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 是 RealNetworks公司所推荐配合他们产品的一张影像撷取卡,配合 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 网站上取得:
http://www.linux.org.tw/CLDP/Hardware-HOWTO-22.html
影像撷取卡支援的视讯系统
大部份影像撷取卡都会具备一组视讯输入端子, 即 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 则是 Linuxkernel 的 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 环境。VideoConferencing应用软体在多媒体程序设计上,常常也被视为「杀手级」的应用之一,可见 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 支援的磁盘排程 (DiskScheduler)也被列入我们考虑研究的项目之一。传统上,一般我们设计 OS 时都会选择 SCAN 或是SSTF算法,不过这些传统的磁盘排程算法并无法满足我们的需求。
较先进的磁盘排程算法应考虑到 Video 与 Audio 的应用,而目前较普遍被选择用来设计 multimedia I/O 系统的磁盘排程算法则是 SCAN-EDF 算法。
SCAN-EDF 演算是结合 SCAN 与 EDF 优点的解决方案,SCAN 是众所皆知的 seekoptimizing磁盘排程算法;而 EDF (Earliest Deadline First) 则是属于 real-timescheduling 的算法。
磁盘排程对于 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 图档部份
/*
* 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 应用探讨,我们已经可以有能力设计出许多简单的 VideoStreaming应用程式。例如以 video4linux、bttv、rtp 和 jpeg 压缩技术便能实作简单的 Webcam 应用程式。
底下是我们利用 Java 实作出来的 Linux Webcam 应用程式,在远端直接以浏览器来执行即可。
图 1 利用 Java 与 Video Streaming 技术设计的 Linux Webcam
图 2 利用 Java 与 Video Streaming 技术设计的 Linux Webcam
Webcam 与 CCD 结合的应用包括:远距教学、视讯会议、安全监控…等等。