完成UVC完成webcam.ko模块驱动后还需要一个程序带动驱动
需要的模组:
webcam.ko
dwc_otg.ko
wdt.ko
平台:海思某芯片
int main(int argc, char* argv[])
{
struct uvc_device dev;
system("insmod wdt.ko default_margin=5");
venc_init();//VENC编码设置初始化,参考海思sample_comm_venc.c
uvc_dev_init(&dev);
while (!gFlagExit)
{
if (uvc_dev_pulgged(&dev))//检测设备插入
{
uvc_dev_connected(&dev);//插入
uvc_dev_disconnected(&dev);//拔出
}
usleep(100 * 1000);
}
uvc_dev_deinit(&dev);
venc_deinit();
return 0;
}
int uvc_dev_connected(struct uvc_device* dev)
{
int ret;
system("insmod dwc_otg.ko");
system("insmod webcam.ko");
ret = uvc_open(dev);
if (ret)
{
return -1;
}
uvc_events_init(dev);//时间初始化
uvc_video_init(dev);
while (!gFlagExit)
{
struct timeval tv;
fd_set efds;
fd_set wfds;
FD_ZERO(&efds);
FD_SET(dev->fd, &efds);
FD_ZERO(&wfds);
FD_SET(dev->fd, &wfds);
tv.tv_sec = 0;
tv.tv_usec = 100 * 1000;
ret = select(dev->fd + 1, NULL, &wfds, &efds, &tv);
if (ret < 0)
{
printf("select error\n");
continue;
}
else if (ret == 0)
{
if (!uvc_dev_pulgged(dev))
return 0;
}
else
{
if (FD_ISSET(dev->fd, &efds))
{
uvc_events_process(dev);//时间轮训
}
if (FD_ISSET(dev->fd, &wfds))
{
uvc_video_process(dev);//流轮训,操作buf
}
}
}
return 0;
}
这里主要就是3个方法
uvc_events_init
uvc_events_process
uvc_video_process
uvc_events_init填充uvc_device的probe和comit,然后就是将UVC事件的setup、data、streamon、streamoff,通过VIDIOC_SUBSCRIBE_EVENT设置到驱动里
uvc_events_init(struct uvc_device* dev)
{
struct v4l2_event_subscription sub;
uvc_fill_streaming_control(dev, &dev->probe, 0, 0);
uvc_fill_streaming_control(dev, &dev->commit, 0, 0);
if (dev->bulk)
{
/* FIXME Crude hack, must be negotiated with the driver. */
dev->probe.dwMaxPayloadTransferSize = 16 * 1024;
dev->commit.dwMaxPayloadTransferSize = 16 * 1024;
}
memset(&sub, 0, sizeof sub);
sub.type = UVC_EVENT_SETUP;
ioctl(dev->fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
sub.type = UVC_EVENT_DATA;
ioctl(dev->fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
sub.type = UVC_EVENT_STREAMON;
ioctl(dev->fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
sub.type = UVC_EVENT_STREAMOFF;
ioctl(dev->fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
sub.type = UVC_EVENT_DISCONNECT;
ioctl(dev->fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
}```
uvc_events_process可以说是最核心的部分,处理事务
uvc_events_process(struct uvc_device* dev)
{
struct v4l2_event v4l2_event;
struct uvc_event* uvc_event = (struct uvc_event*)(void*)&v4l2_event.u.data;
struct uvc_request_data resp;
int ret;
ret = ioctl(dev->fd, VIDIOC_DQEVENT, &v4l2_event);
if (ret < 0)
{
UVC_DEBUG(1, ("VIDIOC_DQEVENT failed: %s (%d)\n", strerror(errno),
errno));
return;
}
memset(&resp, 0, sizeof resp);
resp.length = 32;
switch (v4l2_event.type)
{
case UVC_EVENT_CONNECT:
UVC_DEBUG(1, ("\nUVC_ENENT_CONNECT\n"));
return;
case UVC_EVENT_DISCONNECT:
UVC_DEBUG(1, ("\nUVC_EVENT_DISCONNECT\n"));
return;
case UVC_EVENT_SETUP:
UVC_DEBUG(1, ("\nUVC_EVENT_SETUP Type=%02x Request=%02x Index=%04x Value=%04x\n",uvc_event->req.bRequestType ,uvc_event->req.bRequest, uvc_event->req.wIndex,uvc_event->req.wValue));
uvc_events_process_setup(dev, &uvc_event->req, &resp);
break;
case UVC_EVENT_DATA:
UVC_DEBUG(1, ("\nUVC_EVENT_DATA len=%d\n",uvc_event->data.length));
uvc_events_process_data(dev, &uvc_event->data);
return;
case UVC_EVENT_STREAMON:
UVC_DEBUG(1, ("\nUVC_EVENT_STREAMON\n"));
if (dev->bulk == 0)
{
if (dev->streaming)
{
uvc_video_stream(dev, 0);
uvc_video_reqbufs(dev, 0);
venc_stop();
}
venc_set_format(dev->width,dev->height,dev->fcc,10000000/dev->dwFrameInterval,dev->wCompQuality, dev->venc_profile);
uvc_video_set_format(dev);
uvc_video_reqbufs(dev, USING_WEBCAM_VIDEO_BUF_NUM);
uvc_video_stream(dev, 1);
}
return;
case UVC_EVENT_STREAMOFF:
UVC_DEBUG(1, ("\nUVC_EVENT_STREAMOFF\n"));
if (dev->bulk == 0)
{
if (dev->streaming)
{
uvc_video_stream(dev, 0);
uvc_video_reqbufs(dev, 0);
venc_stop();
}
}
return;
}
ret = ioctl(dev->fd, UVCIOC_SEND_RESPONSE, &resp);
if (ret < 0)
{
UVC_DEBUG(1, ("UVCIOC_S_EVENT failed: %s (%d)\n", strerror(errno), errno));
return;
}
}
“`
UVC_EVENT_SETUP->uvc_events_process_setup->uvc_events_process_class获取生产者信息,主要是VC和VS事务之后UVC_EVENT_DATA用来消费
具体细分不写了,自行百度,这里只讲框架。
参考资料:
http://www.ee156.com/316.html