喜欢的可以加微信群:
![【genius_platform软件平台开发】第六十二讲:Linux系统之V4L2视频驱动-VIDIOC_STREAMON开启视频流_第1张图片](http://img.e-com-net.com/image/info8/f4cc8ee28d8b4b74ac99ca50aee875b2.jpg)
![【genius_platform软件平台开发】第六十二讲:Linux系统之V4L2视频驱动-VIDIOC_STREAMON开启视频流_第2张图片](http://img.e-com-net.com/image/info8/a2e10959321448c187a46c1f286b9c68.jpg)
VIDIOC_STREAMON开启视频流
- 喜欢的可以加微信群:
- 1. 概述
- 2.应用层
- 3. 驱动层
-
- 3.1 vb2_streamon函数
- 3.2 vb2_core_streamon函数
- 3.3 vb2_start_streaming函数
- 3.4 __enqueue_in_driver函数
- 3.5 vb2_buffer_done函数
1. 概述
- 主要就是让设备启动视频流,驱动中不停的获取视频数据,queued_list中产生源源不断的视频数据帧。
2.应用层
unBuffType = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == this->ioCtrl(m_nFd, VIDIOC_STREAMON, &unBuffType))
{
LOGERROR("CV4l2CaptureIr::startCapture is error... VIDIOC_STREAMON m_unIoMethod=[%d]", m_unIoMethod);
return ReturnCode_Error;
}
LOGMSG("CV4l2CaptureIr::startCapture is suc... VIDIOC_STREAMON nTotalCostTm=[%llu] unBuffType=[%u]", (currentTime() - nTotalCostTm).count(), unBuffType);
3. 驱动层
3.1 vb2_streamon函数
int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
{
return vb2_core_streamon(q, type);
}
3.2 vb2_core_streamon函数
int vb2_core_streamon(struct vb2_queue *q, unsigned int type)
{
int ret;
if (type != q->type) {
dprintk(1, "invalid stream type\n");
return -EINVAL;
}
if (q->streaming) {
dprintk(3, "already streaming\n");
return 0;
}
if (!q->num_buffers) {
dprintk(1, "no buffers have been allocated\n");
return -EINVAL;
}
if (q->num_buffers < q->min_buffers_needed) {
dprintk(1, "need at least %u allocated buffers\n",
q->min_buffers_needed);
return -EINVAL;
}
if (q->queued_count >= q->min_buffers_needed) {
ret = v4l_vb2q_enable_media_source(q);
if (ret)
return ret;
ret = vb2_start_streaming(q);
if (ret) {
__vb2_queue_cancel(q);
return ret;
}
}
q->streaming = 1;
dprintk(3, "successful\n");
return 0;
}
EXPORT_SYMBOL_GPL(vb2_core_streamon);
3.3 vb2_start_streaming函数
static int vb2_start_streaming(struct vb2_queue *q)
{
struct vb2_buffer *vb;
int ret;
list_for_each_entry(vb, &q->queued_list, queued_entry)
__enqueue_in_driver(vb);
q->start_streaming_called = 1;
ret = call_qop(q, start_streaming, q, atomic_read(&q->owned_by_drv_count));
if (!ret)
{
return 0;
}
q->start_streaming_called = 0;
dprintk(1, "driver refused to start streaming\n");
if (WARN_ON(atomic_read(&q->owned_by_drv_count))) {
unsigned i;
for (i = 0; i < q->num_buffers; ++i) {
vb = q->bufs[i];
if (vb->state == VB2_BUF_STATE_ACTIVE)
vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED);
}
WARN_ON(atomic_read(&q->owned_by_drv_count));
}
WARN_ON(!list_empty(&q->done_list));
return ret;
}
3.4 __enqueue_in_driver函数
static void __enqueue_in_driver(struct vb2_buffer *vb)
{
struct vb2_queue *q = vb->vb2_queue;
vb->state = VB2_BUF_STATE_ACTIVE;
atomic_inc(&q->owned_by_drv_count);
trace_vb2_buf_queue(q, vb);
call_void_vb_qop(vb, buf_queue, vb);
}
3.5 vb2_buffer_done函数
- 经过特定设备在on之后开启内核线程,通过中断不停的填充数据到vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);然后更新vb->state = VB2_BUF_STATE_DONE。标识已经好了。
void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
{
struct vb2_queue *q = vb->vb2_queue;
unsigned long flags;
unsigned int plane;
for (plane = 0; plane < vb->num_planes; ++plane)
call_memop(q, finish, vb->planes[plane].mem_priv);
spin_lock_irqsave(&q->done_lock, flags);
vb->state = state;
list_add_tail(&vb->done_entry, &q->done_list);
atomic_dec(&q->queued_count);
#ifdef CONFIG_SYNC
sw_sync_timeline_inc(q->timeline, 1);
#endif
spin_unlock_irqrestore(&q->done_lock, flags);
wake_up(&q->done_wq);
}