您好,欢迎来到中国企业库   [请登陆]  [免费注册]
小程序  
APP  
微信公众号  
手机版  
 [ 免责声明 ]     [ 举报 ]
企业库免费B2B网站
搜产品 搜企业
客服电话:400-000-8722
企业库首页>资讯
行业

(翻译)为视频采集设备编写设备驱动_一个萝卜_百度空间

作者:企业资讯策划团队 来源:rwfb 发布时间:2010-04-24 浏览:223

为视频采集设备编写设备驱动

Last month I talked about how to write a device driver for radio-tuner cards. This month, I’ll cover video-capture devices, which share the same interfaces as radio devices.

上个月我讲述了怎样为音频接收卡编写设备驱动。这个月,我会覆盖视频采集设备,它跟音频设备的接口是一致的。

In order to explain the video-capture interface I will use the example of a camera that has no tuners or audio input. This keeps the example relatively clean. To get audio capabilities, you can combine this month’s driver with last month’s driver example.

为了更好的解释视频采集接口,我采用了一个没有接收机和没有音频输入的摄像头作例子。这使得例子相对简洁。为了拥有音频能力,你可以组合这个例子和上个月的例子。

Before I get into the details of video-capture devices, a little background on the technology is in order. Full-motion video, even at television resolution (which is relatively low) is resource-intensive. These devices continually pass megabytes of data every second from the capture card to the display. Because copying this amount of data through a user application is often unfeasible, several alternative approaches to television tuners have been developed.

在深入视频采集设备的细节之前,先说一点技术背景资料。全动视频,即使只有电视的解析度(这相对而言是比较低的),是资源密集型的。这些设备每秒从采集卡到显示端传递兆字节数据流。因为通过用户程序拷贝这么大量的数据是不可行的,于是在电视接收卡方面发展出了几种可选的方法。

The first is to transfer the television image onto the video output directly. This is also how some add-on 3D-rendering cards work, dropping the video into any chosen rectangle of the display. These cards, which include most MPEG-1 cards that use a feature connector, aren’t very friendly in a windowing environment. They don’t understand windows and clipping rectangles, which means that the video window is always on top of the display.

{dy}种是直接转发电视图像到视频输出端。这也是一些附加的3D渲染卡的工作机制,直接将视频丢到显示端的选择区域里。这些卡,包括绝大多数MPEG-1卡,采用了一个专门连接头,这在窗口环境下不是十分友好。它们并不理解窗口和剪贴区域,这意味着视频窗口要始终处于显示端的顶层。

Chromakeying is a technique used by cards to get around this. It is an old television mixing trick in which you mark all the areas you wish to replace with a single clear color not used in the image — TV people use an incredibly bright blue for this, while computing people tend to use a particularly virulent purple. This is because bright blue occurs on the desktop, and anyone with virulent purple windows has another problem besides their TV overlay.

色度键控是视频卡绕开这个问题的一项技术。这是一种老式的电视混合技术,你使用了单一亮色替换了整个区域,而不是用图像--电视的技术人员使用了亮蓝色,而计算机的技术人员倾向于使用一种深紫色。这是因为亮蓝色出现在桌面上,人们认为计算机出现了故障,而不是电视的覆盖替换造成的,所以计算机的技术人员选用了深紫色。

The third approach is to copy the data from the capture card to the video card, but to do it directly across the PCI bus. This relieves the processor from doing the work but does require some intelligence on the part of the video-capture chip, as well as a suitable video card. Programming and debugging these cards can be extremely tricky. There are some complicated interactions with the display, and you may also have to cope with various chipset bugs that show up when PCI cards start talking to each other directly (rather than via the CPU).

第三种方案是将数据从采集卡直接拷贝到视频卡,只是直接通过PCI总线。这减轻了处理器的压力,但是需要视频采集芯片具有一定智能,而且还要合适的视频卡。为这些卡编程和调试就变得极端复杂。跟显示端的互动也有了一定复杂度,你不得不去处理PCI直接相互对话中出现的芯片级别的bug(它们不再通过CPU)。

To keep our example fairly simple we will assume a card that supports overlaying a flat rectangular image onto the frame-buffer output, uses chromakey for selecting the region on which to draw, and can also capture video into processor memory.

为了保持我们的示例相对简单,我们假设采集卡支持覆盖一副平面长方图像到帧缓存输出,色度键控技术用来选择绘图区域,当然我们也要支持采集视频到处理器的内存。

The functions supported by our video-capture driver are shown in Listing One.

视频采集卡要支持的函数见表一



static struct video_device my_camera
{
“My Camera”,
VID_TYPE_OVERLAY|VID_TYPE_SCALES|VID_TYPE_CAPTURE|
VID_TYPE_CHROMAKEY,
VID_HARDWARE_MYCAMERA,
camera_open.
camera_close,
camera_read,
NULL, /* no write */
camera_poll,
camera_ioctl,
NULL, /* no special init function */
NULL /* no private data */
};

We are going to need a read function, which is used for capturing data from the card, and a poll function so that a driver can wait for the next frame to be captured.

我们需要一个read函数,用来捕获卡里的数据,需要一个poll函数,驱动可以等待要捕获的下一帧。

There are several additional video-capability flags that did not apply to the radio interface. These are:

有几个额外的视频能力标志,是音频接口没有的。它们是:

VID_TYPE_CAPTURE: We support image capture.

VID_TYPE_CAPTURE: 我们支持图像采集

VID_TYPE_TELETEXT: A teletext capture device (vbi[n])

VID_TYPE_TELETEXT: 图文电视采集设备 (vbi[n])

VID_TYPE_OVERLAY: The image can be directly overlaid onto the frame buffer.

VID_TYPE_OVERLAY: 图像可以直接覆盖到帧缓存。

VID_TYPE_CHROMAKEY: Chromakey can be used to select which parts of the image to display.

VID_TYPE_CHROMAKEY: 色度键控可以选择显示图像的那一部分。

VID_TYPE_CLIPPING: It is possible to give the board a list of rectangles to draw around.

VID_TYPE_CLIPPING: 具有给出一系列矩形绘图区域的能力。

VID_TYPE_FRAMERAM: The video capture goes into the video memory and actually changes it. Applications need to know this so they can clean up after the card.

VID_TYPE_FRAMERAM: 视频采集卡直接进入视频内存,改变了视频内存。应用程序需要知道这一点,这样他们能够随后qc。

VID_TYPE_SCALES: The image can be scaled to various sizes, rather than being a single fixed size.

VID_TYPE_SCALES: 图像可以被拉伸到各种尺寸,而不仅仅是单一的固定大小。

VID_TYPE_MONOCHROME: The capture will be monochrome. This isn’t a complete answer to the question, since a mono camera on a color capture card will still produce monochrome output.

VID_TYPE_MONOCHROME: 捕获单色视频。这不是问题的完整答案,因为彩色采集卡的单色摄像头仍然可以产生单色输出。

VID_TYPE_SUBCAPTURE: The card allows only part of its field of view to be captured. This enables applications to avoid copying all of a large image into memory when only some section is relevant.

VID_TYPE_SUBCAPTURE: 采集卡允许只采集视野中的部分区域。这可以使应用程序在仅需要某区域的时候拷贝整幅图像到内存中。

We set VID_TYPE_CAPTURE so that we are seen as a capture card, VID_TYPE_CHROMAKEY so that the application knows that it is time to draw in particularly virulent purple, and VID_TYPE_SCALES because the video can be resized.

我们设置VID_TYPE_CAPTURE,这样我们就会被视为采集卡,我们设置VID_TYPE_CHROMAKEY这样应用程序就知道到了画深紫色的时候了,我们设置VID_TYPE_SCALES是因为图像可以放大缩小。

Setup is similar to last month’s radio driver. This time we are going to want an interrupt line for the “frame captured” signal. Not all cards have this, so some of them cannot handle poll().

安装类似于上月的音频驱动。这次我们需要一个中断行处理“帧捕获”信号。不是所有的卡都需要,如果不要,就可以不处理poll()函数。

static int io = 0×320;
static int irq = 11;

int_init mycamera_init(struct video_init *v)
{
if(check_region(io, MY_IO_SIZE))
{
printk(KERN_ERR “mycamera: port
0x%03Xisinuse.n”,io);
return -EBUSY;
}
if(video_device_register
(&my_camera,VFL_TYPE_GRABBER)==-1)
return -EINVAL;
request_region(io, MY_IO_SIZE,
“mycamera”);
return 0;
}

There is little changed here from the radio-card driver. We specify VFL_TYPE_GRABBER this time, since we want to be allocated a /dev/video device name.

相比音频卡驱动,这里有一点改变。这次我们指定了VFL_TYPE_GRABBER,因为我们要分配一个/dev/video设备名。

static int users = 0;

static int camera_open(struct video_device
*dev,int flags)
{
if(users)
return -EBUSY;
if(request_irq(irq, camera_irq, 0,
“camera”, dev)<0)
return -EBUSY;
users++;
MOD_INC_USE_COUNT;
return 0;
}

static int camera_close(struct video_device
*dev)
{
users–;
free_irq(irq, dev);
MOD_DEC_USE_COUNT;
}

The open and close routines are also quite similar. The only real change is that we now request an interrupt for the camera device interrupt line. If we cannot get the interrupt we report EBUSY to the application and give up.

打开和关闭处理例程也很类似。{wy}的实质性变化就是我们为摄像头设备中断行请求一个中断。如果我们得不到中断,我们向应用程序报告EBUSY,然后放弃。

Our example handler is for an ISA bus device. If it were PCI you would be able to share the interrupt and would have set SA_SHIRQ to indicate a shared IRQ.

我们的示例处理函数是针对ISA总线设备的。如果是PCI设备,你愿意共享中断,那么设置SA_SHIRQ,表明是一个共享的IRQ。

We pass the device pointer as the interrupt-routine argument. We don’t actually need to do this, since we support only one card, but it makes it easier to upgrade the driver for multiple devices in the future.

在中断例程参数这哦个你我们传递了一个设备指针。实际上我们并不需要它,因为目前我们只支持一块卡,但这样很方便以后升级驱动,使其未来可以支持多个设备。

Our interrupt routine needs to do little if we assume the card can simply queue one frame to be read after it captures it.

我们的中断处理函数只需要作一点工作,如果我们假设采集卡捕获图像后,队列中只有一帧图像可读的话。

static struct wait_queue *capture_wait;
static int capture_ready = 0;

static void camera_irq(int irq, void *dev_id,
struct pt_regs *regs)
{
capture_ready=1;
wake_up_interruptible(&capture_wait);
}

The interrupt handler is nice and simple for this card, since we are assuming the card is buffering the frame for us. This means we have very little to do except wake up anybody interested. We also set a capture_ready flag, as we may capture a frame before an application actually needs it.

对视频卡来说中断处理函数很友好很简单,因为我们假设卡已经为我们缓存好了这一帧。这意味着我们几乎无事可做,除了唤醒感兴趣的进程。同时我们设置了capture_ready标志,在我们捕获了一帧应用程序真正需要它之前。

The two new routines we need to supply are camera_ read, which returns a frame, and camera_poll, which waits for a frame to become ready.

我们需要提供的两个新函数是camera_ read,返回一帧,和camera_poll,等待一帧图像预备好。

Our wait queue for polling is the capture_wait queue (Listing Two). This will cause the task to be woken up by our camera_irq routine. We check capture_read to see if there is an image present and if so report that it is readable.

我们用于轮询的等待队列是capture_wait(列表二)。这会导致我们的camera_irq例程唤醒任务。我们检查capture_read标志,查看是否有图像提供,如果有,那么报告图像可读。



static long camera_read(struct video_device *dev, char
*buf,unsigned long count)
{
struct wait_queue wait = { current, NULL};
u8 *ptr;
int len;
int i;

add_wait_queue(&capture_wait, &wait);

while(!capture_ready)
{
if(file->flags&O_NDELAY)
{
remove_wait_queue(&capture_wait,&wait);
current->state = TASK_RUNNING;
return -EWOULDBLOCK;
}
if(signal_pending(current))
{
remove_wait_queue(&capture_wait,&wait);
current->state = TASK_RUNNING;
return -ERESTARTSYS;
}
schedule();
current->state = TASK_INTERRUPTIBLE;
}
remove_wait_queue(&capture_wait, &wait);
current->state = TASK_RUNNING;

The first thing we have to do is to ensure that the application waits until the next frame is ready. The code here is almost identical to the mouse code in the October Gearheads Only column, which can be found at . It is one of the common building blocks of Linux device-driver code and probably one that you will use in any driver you write.

我们必须做的{dy}件事情是保证应用程序等待,知道下一帧准备好。这里的代码和鼠标驱动的代码几乎wq相同,十月份Gearheads Only栏目。它是Linux设备驱动代码的一个公共构建代码块,你在编写任何驱动时都可能用到。

We wait for a frame to be ready or for a signal to interrupt our wait. If a signal occurs we need to return from the system call so that the signal can be sent to the application itself. We also check to see if the user actually wanted to avoid waiting — that is, if they are using non-blocking I/O and have other things to get on with.

我们等待一帧准备好,或者等待一个中断信号。如果出现了一个信号,我们需要从系统调用返回,这样信号可以传递到应用程序。我们也要检查用户是否选择避免等待--也就是,是否它们使用了非阻塞I/O标志,这样它们可以继续去做其他的事。

Next we copy the data from the card to the user application. This is rarely as easy as our example makes out. We will add the variables capture_w and capture_h here to hold the width and height of the captured image. We assume the card supports only 24-bit RGB for now.

接着,我们将数据从卡拷贝到用户程序。这和我们之前开列的示例一样容易。我们加了变量capture_w和capture_h保存图像的宽度和高度。我们暂时假设采集卡只支持24位RGB。

capture_ready = 0;

ptr = (u8 *)buf;
len=capture_w * 3 * capture_h;
/* 24bit RGB */

if(len>count)
len = count;
/* Doesn’t all fit */

for(i=0; i<len; i++)
{
put_user
(inb (io+IMAGE_
DATA),ptr);
ptr++;
}

hardware_restart_
capture();

return i;
}

For a real hardware device you would try to avoid the loop with put_user(). Each call to put_user() must check whether access to user space is allowed, which is costly. It would be better to read a line into a temporary buffer and then copy this to user space in one go.

对一个真正的硬件设备而言,你要试着避免循环使用put_user()函数。每次调用put_user()一定要检查是够允许访问用户空间,这需要一定消耗。比较好的方法是读取一行到临时缓冲区,然后将这一行一次性拷贝到用户空间。

Having captured the image and put it into user space, we can kick the card to acquire a new frame. Next month we will talk about how to do that.

我们已经完成了捕获图像,将图像放到用户空间,我们现在可以踢开采集卡,获取新的一帧了。下个月我们会继续讲述如何做到这一点。




郑重声明:资讯 【(翻译)为视频采集设备编写设备驱动_一个萝卜_百度空间】由 企业资讯策划团队 发布,版权归原作者及其所在单位,其原创性以及文中陈述文字和内容未经(企业库www.qiyeku.com)证实,请读者仅作参考,并请自行核实相关内容。若本文有侵犯到您的版权, 请你提供相关证明及申请并与我们联系(qiyeku # qq.com)或【在线投诉】,我们审核后将会尽快处理。
会员咨询QQ群:902340051 入群验证:企业库会员咨询.
免费注册只需30秒,立刻尊享
免费开通旗舰型网络商铺
免费发布无限量供求信息
每天查看30万求购信息