目前,生活中很多事情都可以在电脑前完成,读书、写程序、听音乐、看视频等。如果也可以在电脑上收看有线电视节目的话,那就更好了。为此,我购买了圆刚视频采集卡AverMedia C725B。如下图所示。
官方给出的此卡介绍为(详见这里):
C725标清采集卡是一张支持AV端子、S端子以及立体声输入的PCI-E撷取卡,可将PAL、NTSC和SECAM等模拟格式影像数字化,撷取并另存为 无压缩的AVI格式档案。C725标清采集卡随附的软件开发工具包(SDK)提供常用功能,能帮助开发者或系统整合商轻松且有效率地完成工作。此外,这套 SDK可兼容于Visual C++和 Visual Basic等主流程序语言,让开发者可更轻易上手。
官方声称支持Linux,而且驱动程序需要向其索取,网站不提供下载。然而,AverMedia C725是否真的可以在自己的Debian Wheezy(3.2.0-4-amd64 #1 SMP Debian 3.2.51-1 x86_64 GNU/Linux)上工作就不好说了,只好冒点风险试一下。
在安装好AverMedia PCI卡后,首先向官方联系取得驱动程序。需要注意的是,一定要获得与自己的Linux内核版本一致的驱动,否则编译极有可能不通过。我自己就是在尝试了官方默认提供的适用于老版本内核的驱动失败后,才要求圆刚的技术人员重新为自己编译了一个适用于Linux 3.2.51的版本。有了官方提供的驱动,再安装linux-source包与linux-headers包,就可以开始编译驱动了。首先,需要导出环境变量C_INCLUDE_PATH,其中包含了linux-source提供的dvb相关文件:
export C_INCLUDE_PATH=/usr/include/:/usr/src/linux-source-3.2/drivers/media/dvb/dvb-core/:/usr/src/linux-source-3.2/drivers/media/dvb/frontends/
之后的编译过程就是通常的make三步曲,一切都很顺利。
有了硬件基础后,电视播放软件我选择使用mplayer,录制视频则是mencoder。由于命令行所需的参数很多,我写了一个脚本程序rtv.sh,可以方便的播放或录制节目。通过指定命令行参数watch、nowatch、onlywatch,该脚本可以在三种模式下运行:
watch:在播放电视的同时,将视频存为avi文件;
nowatch:只录制节目存为avi文件,不实时播放;
onlywatch:只用mplayer看节目而不录制。
该脚本用到了如下几个程序:
mencoder:从视频采集卡以指定的格式获取视频流并将其输出到一个名称FIFO管道(named FIFO pipe);
tee:从标准输入获得数据流再将其转向至标准输出。利用管道行,可以将名称FIFO管道的内容作为tee命令的标准输入,而tee命令的标准输出作为mplayer程序的标准输入予以播放。同时,tee命令可以使用命令行参数-a filename。这样,在将数据流送至标准输出乃至mplayer的同时,也会将其保存至指定的文件。利用这个机制,就可以实现同时播放并录制电视节目了;
mplayer:播放由tee转来的视频流。
脚本程序的执行过程是:首先检测用户的命令行参数输入,然后查看是否已有mencoder、tee、mplayer进程运行。若存在,则表明已经在播放或录制节目了,从而提示用户后退出;否则,执行如下的流程:
首先,使用mkfifo创建名称FIFO管道/tmp/tv.fifo;
其次,用cat命令输出该管道的内容至标准输出,利用管道行将该输出作为tee命令的标准输入。在录制与播放的模式下(watch),将其分为两路,一路送至avi文件,一路送至mplayer用于播放;在只录制不播放的模式下(nowatch),只输出至avi文件;在纯播放模式下(onlywatch),只送至mplayer。
最后,用mencoder从AverMedia C725B采集卡在系统中的设备节点/dev/video0截取视频流,以指定的格式输出到之前创建的名称管道。
脚本程序的源代码为:
#!/bin/bash
script_name="rtv.sh"
script_usage=$(cat <<EOF
rtv MODE [FILE]
EOF
)
script_function=$(cat <<EOF
Record or watch TV. MODE can be 'watch', 'onlywatch', 'nowatch'. When 'watch' or 'nowatch' is specified, the file name must be provided.
EOF
)
script_doc=$(cat <<EOF
-h Display this help.
EOF
)
script_examples=$(cat <<EOF
rtv nowatch test.avi
rtv watch test.avi
rtv onlywatch
EOF
)
state_prefix="==="
warning_prefix="***"
error_prefix="!!!"
function display_help() {
if [ -n "$script_usage" ]; then
echo -e "Usage: $script_usage"
fi
if [ -n "$script_function" ]; then
echo -e "$script_function"
fi
if [ -n "$script_doc" ] ; then
echo -e "\n$script_doc"
fi
if [ -n "$script_examples" ]; then
echo -e "\nExamples"
echo -e "$script_examples"
fi
}