全部博文(668)
分类:
2009-08-01 15:59:28
Listen 7000其中的设定项目说明如下:
ServerName
MP3Engine On
MP3CastName "jollen box"
MP3Genre "Much, nutty"
MP3 /home/nfs/private/mp3
MP3Random On
Timeout 600
ErrorLog /var/log/mp3_stream.log
linux# insmod i2c-old当然要确定 Linux kernel有编译这三个模组的支援,然后再把这三个模组加到 /etc/modules.conf(Red Hat 7.0) 里。
linux# insmod videodev
linux# insmod bttv
/dev/video | Video Capture Interface |
/dev/radio | AM/FM Radio Devices |
/dev/vtx | Teletext Interface Chips |
/dev/vbi | Raw VBI Data (Intercast/teletext) |
#ifndef _V4L_H_实作 video4linux 时,必须 include 底下二个档案:
#define _V4L_H_
#include接下来是 PAL、CIF、NTSC 规格的画面大小定义:
#include
#define PAL_WIDTH 768接下来我们的重点是 _v4l_struct structure,这个 structure 包含了在API.html 提到,将会使用到的 data structure,底下将完整地定义 _v4l_struct,但在实作时并不会全部用到。 _v4l_struct 定义如下:
#define PAL_HEIGHT 576
#define CIF_WIDTH 352
#define CIF_HEIGHT 288
#define NTSC_WIDTH 640
#define NTSC_HEIGHT 480
struct _v4l_struct为了设计方便,我们再做底下的定义:
{
int fd;
struct video_capability capability;
struct video_buffer buffer;
struct video_window window;
struct video_channel channel[8];
struct video_picture picture;
struct video_tuner tuner;
struct video_audio audio[8];
struct video_mmap mmap;
struct video_mbuf mbuf;
unsigned char *map;
};
typedef struct _v4l_struct v4l_device;以后宣告 struct _v4l_struct 时,将一律使用 v4l_device。
extern int v4l_open(char *, v4l_device *);v4l_open() -- 开启 device file
extern int v4l_close(v4l_device *);
extern int v4l_get_capability(v4l_device *);
extern int v4l_set_norm(v4l_device *, int);
extern int v4l_get_channels(v4l_device *);
extern int v4l_get_audios(v4l_device *);
extern int v4l_get_picture(v4l_device *);
extern int v4l_grab_init(v4l_device *, int, int);
extern int v4l_grab_frame(v4l_device *, int);
extern int v4l_grab_sync(v4l_device *);
extern int v4l_mmap_init(v4l_device *);
extern int v4l_get_mbuf(v4l_device *);
extern int v4l_get_picture(v4l_device *);
extern int v4l_grab_picture(v4l_device *, unsigned int);
extern int v4l_set_buffer(v4l_device *);
extern int v4l_get_buffer(v4l_device *);
extern int v4l_switch_channel(v4l_device *, int);
v4l_device vd;在应用程式里,我们宣告了一个 vd 变数 (v4l_device 型态),再呼叫v4l_open() 将设备档开启。如果可以开启 "/dev/video0" 则将取回的信息放到 vd 里,vd 是v4l_device 也就是之前宣告的 _v4l_struct。接下来,让我们来看看 v4l_open() 要如何实作:
if (v4l_open("/dev/video0", &vd)) {
return -1;
}
#define DEFAULT_DEVICE "/dev/video0"为了设计出完整的 video4linux 程序库,一开始我们就定义了DEFAULT_DEVICE,当应用程式输入的 dev设备档参数不存在时,就使用预设的设备档名称。程序片段如下:
int v4l_open(char *dev, v4l_device *vd)
{
if (!dev)
dev = DEFAULT_DEVICE;
if ((vd->fd = open(dev, O_RDWR)) < 0) {
perror("v4l_open:");
return -1;
}
if (v4l_get_capability(vd))
return -1;
if (v4l_get_picture(vd))
return -1;
return 0;
}
if (!dev)与一般 Linux Programming 一样,我们使用 open() 将 device file 打开:
dev = DEFAULT_DEVICE;
if ((vd->fd = open(dev, O_RDWR)) < 0) {如果您不熟悉 Linux 下 open() 的使用方法,请参考 Linux programming相关资料。熟悉 UNIXprogramming 的读者一定知道,open() 也与 STREAMS 的观念相关,这部份在后面会再另外做介绍。
perror("v4l_open:");
return -1;
}
int v4l_get_capability(v4l_device *vd)在这里,其实只有底下这一行才是 v4l_get_capability 的主力:
{
if (ioctl(vd->fd, VIDIOCGCAP, &(vd->capability)) < 0) {
perror("v4l_get_capability:");
return -1;
}
return 0;
}
ioctl(vd->fd, VIDIOCGCAP, &(vd->capability));其它部份都是属于错误处理的程序码,在本文,笔者都将函数写的完整一点,即包含了错误检查,因为我们想要实作一个v4l 的 library。
struct video_picture picture;初始化 picture的意思就是要取得输入到影像捕捉卡的影像信息,我们设计 v4l_get_picture() 函数来完成这件工作。v4l_get_ picture () 完整程序码如下:
int v4l_get_picture(v4l_device *vd)传递VIDIOCGPICT 给 ioctl() 则会传回影像的属性 (image properties),这里则是将影像属性存放于vd-> picture。
{
if (ioctl(vd->fd, VIDIOCGPICT, &(vd->picture)) < 0) {
perror("v4l_get_picture:");
return -1;
}
return 0;
}
struct video_channel channel[8];channel 是一个 8 个元素的数组,一般绝大部份都会宣告 4 个元素,因为大部份的影像捕捉卡都只有 4 个 channel。几乎没有影像捕捉卡有8 个 channel的。
int v4l_get_channels(v4l_device *vd)要记得,我们是对每个 channel做初始化,所以必须用一个回圈来处理每个 channel。那我们怎么知道影像捕捉卡上有几个channel 呢?记得我们设计 v4l_open() 时也「顺路」呼叫了v4l_get_capability()吗!v4l_get_capability()所取得的设备信息,就包含了影像捕捉卡的 channel 数。这个信息储存于vd->capability.channels 里。
{
int i;
for (i = 0; i < vd->capability.channels; i++) {
vd->channel.channel = i;
if (ioctl(vd->fd, VIDIOCGCHAN, &(vd->channel)) < 0) {
perror("v4l_get_channel:");
return -1;
}
}
return 0;
}
vd->channel.channel = i然后再取得 channel 的信息:
ioctl(vd->fd, VIDIOCGCHAN, &(vd->channel);传递 VIDIOCGCHAN 给 ioctl() 则会传回 channel 的资 讯,这里则是将channel 的信息存放于 vd-> channel。 要注意一下,在 kernel 2.4 的 API.html 文件里,粗心的 programmer 将VIDIOCGCHAN 打成 VDIOCGCHAN,少了一个 "I"。
struct video_audio audio[8];audio 是一个 8 个元素的数组,与 channel 一样。一般绝大部份都会宣告 4个元素,因为大部份的影像捕捉卡都只有 4 个audio。几乎没有影像捕捉卡有8 个audio的。
int v4l_get_audios(v4l_device *vd)别忘了,我们仍然要对每个 audio 做初始化,所以必须用一个回圈来处理每个 audio。那我们怎么知道影像捕捉卡上有几个audio 呢?与取得 channel 的方式一样,audio 数量的信息储存于vd->capability.audios 里。
{
int i;
for (i = 0; i < vd->capability.audios; i++) {
vd->audio.audio = i;
if (ioctl(vd->fd, VIDIOCGAUDIO, &(vd->audio)) < 0) {
perror("v4l_get_audio:");
return -1;
}
}
return 0;
}
vd->audio.audio = i;然后再取得 audio 的信息:
ioctl(vd->fd, VIDIOCGAUDIO, &(vd->audio);传递 VIDIOCGAUDIO 给 ioctl() 则会传回 audio 的信息,这里则是将 audio的信息存放于 vd-> audio。
int v4l_close(v4l_device *vd)配合应用程式来设计
{
close(vd->fd);
return 0;
}
#include我们将这个程序存成 main.c,整个程序不用再多做介绍了吧!程序里用到的地方都有介绍过,其中vd.capability.name 代表界面的 canonical name。
#include
#include
#include "v4l/v4l.h"
v4l_device vd;
int device_init(char *dev)
{
if (dev == NULL) {
dev = "/dev/video0"; //set to default device
}
if (v4l_open(dev, &vd)) return -1;
if (v4l_get_channels(&vd)) return -1;
printf("%s: initialization OK... %s\n"
"%d channels\n"
"%d audios\n\n",
dev, vd.capability.name, vd.capability.channels,
vd.capability.audios);
v4l_close(&vd);
return 0;
}
int main()
{
if (device_init("/dev/video0") == -1) {
perror("device_init: failed...");
exit(1);
} else {
printf("OK!\n");
}
exit(0);
}
#ifndef _V4L_H_为了维护方便,这里我们建立一个 v4l/ 的目录来放 v4l.h 与底下的v4l.c 档案。编译 main.c 时,也别了也要编译 v4l.c,并且要指定 v4l.o 的位置给 main.o 才能顺利link;或者我们可以把 v4l.o 再做成 libv4l.a形式,这是属于 Linux programming相关的主题,请自行参考这方面的资料。
#define _V4L_H_
#include
#include
#define PAL_WIDTH 768
#define PAL_HEIGHT 576
#define CIF_WIDTH 352
#define CIF_HEIGHT 288
#define NTSC_WIDTH 640
#define NTSC_HEIGHT 480
struct _v4l_struct
{
int fd;
struct video_capability capability;
struct video_buffer buffer;
struct video_window window;
struct video_channel channel[8];
struct video_picture picture;
struct video_tuner tuner;
struct video_audio audio[8];
struct video_mmap mmap;
struct video_mbuf mbuf;
unsigned char *map;
};
typedef struct _v4l_struct v4l_device;
extern int v4l_open(char *, v4l_device *);
extern int v4l_close(v4l_device *);
extern int v4l_get_capability(v4l_device *);
extern int v4l_set_norm(v4l_device *, int);
extern int v4l_get_channels(v4l_device *);
extern int v4l_get_audios(v4l_device *);
extern int v4l_get_picture(v4l_device *);
extern int v4l_grab_init(v4l_device *, int, int);
extern int v4l_grab_frame(v4l_device *, int);
extern int v4l_grab_sync(v4l_device *);
extern int v4l_mmap_init(v4l_device *);
extern int v4l_get_mbuf(v4l_device *);
extern int v4l_get_picture(v4l_device *);
extern int v4l_grab_picture(v4l_device *, unsigned int);
extern int v4l_set_buffer(v4l_device *);
extern int v4l_get_buffer(v4l_device *);
extern int v4l_switch_channel(v4l_device *, int);
#endif
#include当程程序无法初始化装置时,会出现的错误讯息:
#include
#include
#include
#include
#include
#include
#include
#include
#include "v4l.h"
#define DEFAULT_DEVICE "/dev/video0"
int v4l_open(char *dev, v4l_device *vd)
{
if (!dev)
dev = DEFAULT_DEVICE;
if ((vd->fd = open(dev, O_RDWR)) < 0) {
perror("v4l_open:");
return -1;
}
if (v4l_get_capability(vd))
return -1;
if (v4l_get_picture(vd))
return -1;
return 0;
}
int v4l_get_capability(v4l_device *vd)
{
if (ioctl(vd->fd, VIDIOCGCAP, &(vd->capability)) < 0) {
perror("v4l_get_capability:");
return -1;
}
return 0;
}
int v4l_get_channels(v4l_device *vd)
{
int i;
for (i = 0; i < vd->capability.channels; i++) {
vd->channel.channel = i;
if (ioctl(vd->fd, VIDIOCGCHAN, &(vd->channel)) < 0) {
perror("v4l_get_channel:");
return -1;
}
}
return 0;
}
int v4l_get_audios(v4l_device *vd)
{
int i;
for (i = 0; i < vd->capability.audios; i++) {
vd->audio.audio = i;
if (ioctl(vd->fd, VIDIOCGAUDIO, &(vd->audio)) < 0) {
perror("v4l_get_audio:");
return -1;
}
}
return 0;
}
int v4l_get_picture(v4l_device *vd)
{
if (ioctl(vd->fd, VIDIOCGPICT, &(vd->picture)) < 0) {
perror("v4l_get_picture:");
return -1;
}
return 0;
}
int v4l_close(v4l_device *vd)
{
close(vd->fd);
return 0;
}
v4l_open:: No such device如果出现这样的错误:
device_init: failed...: No such device
v4l_open:: Device or resource busy最大可能的原因可能是:(1 )躯动程序没有安装好或躯动程序不适用,(2)「前人」的程序忘了将装置档关闭。如果程序可以顺利初始化装置,就会看到这样的讯息:
device_init: failed...: Device or resource busy
/dev/video0: initialization OK... BT878(Hauppauge new)我们将取得的装置信息 print到屏幕上,以了解取得的相关信息。在下一期的文章里,我们将会介绍更多video4linux 的设计方法,来做到更高级的工作。在这里我们看到程序已经成功初始代我们的装置,并且知道装置有 3 个 channel、1 个 audio。
3 channels
1 audios
OK!
图
1
图
2
main()对 Network programming 而言,如果我们要经由 Socket读取字元,可以写一个简单的程序如下:
{
char buf[1024];
int fd;
int count;
if ((fd = open("/dev/tty1", )_RDWR)) < 0) {
perror("open: /dev/tty1");
exit(1);
}
while ((count = read(fd, buf, sizeof(buf))) > 0) {
if (write(fd, buf, count) != count) {
perror("write: /dev/tty1");
break;
}
}
exit(0);
}
int main(int argc, char *argv[])这是一个 client 端向 server送出字元的程序范例,这段程序主要是要让读者看出,经由终端机设备写入字元时,是利用write() 函数,而在 socket 上写入字元,却也是利用 write() 函数。
{
char *buff = "Hello, socket!";
int sockfd;
struct sockaddr_in serv_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("192.168.1.10"); // ip
serv_addr.sin_port = htons(3999); // port
connect(sockfd, &serv_addr, sizeof(serv_addr));
write(fd, buff, strlen(buff));
close(sockfd);
exit(0);
}