UVC攝像頭(3)應用層——webcam程式
阿新 • • 發佈:2019-02-18
完成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