Linux&UVC驱动
+ -

LINUX&UVC驱动开启视频流VIDIOC_STREAMON

2024-04-02 0 0

实现不想看那个视频流队列相关的东西,但有时又很好奇。就看了一个一知半解,只是梳理了一下代码流程,至于细节,鬼才去看。
最终,其实想分析的是视频打开,只为只有这里有与UVC规范相关的请求。
使用VIDIOC_STREAMON请求来打开视频流。

    // 开始数据流
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (ioctl(fd, VIDIOC_STREAMON, &type) == -1) {
        perror("Failed to start streaming");
        close(fd);
        return EXIT_FAILURE;
    }

VIDIOC_STREAMON对应的UVC回调为:

const struct v4l2_ioctl_ops uvc_ioctl_ops = {
    .vidioc_streamon = uvc_ioctl_streamon,
    }

这里其实调用的是队列相关的streamon,这也是为什么要大概分析一下队列相关的代码。

static int uvc_ioctl_streamon(struct file *file, void *fh,
                  enum v4l2_buf_type type)
{
    struct uvc_fh *handle = fh;
    struct uvc_streaming *stream = handle->stream;
    int ret;

    if (!uvc_has_privileges(handle))
        return -EBUSY;

    mutex_lock(&stream->mutex);
    ret = uvc_queue_streamon(&stream->queue, type);
    mutex_unlock(&stream->mutex);

    return ret;
}

int uvc_queue_streamon(struct uvc_video_queue *queue, enum v4l2_buf_type type)
{
    int ret;

    mutex_lock(&queue->mutex);
    ret = vb2_streamon(&queue->queue, type);
    mutex_unlock(&queue->mutex);

    return ret;
}
int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
{
    if (vb2_fileio_is_active(q)) {
        dprintk(1, "file io in progress\n");
        return -EBUSY;
    }
    return vb2_core_streamon(q, type);
}

进入VB2模块的vb2_start_streaming函数,里面需要回调视频流节点注册的回调uvc_queue_qops的start_streaming回调。
关于start_streaming详见:https://www.usbzh.com/article/detail-1350.html

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;
    }

    /*
     * Tell driver to start streaming provided sufficient buffers
     * are available.
     */
    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)
            return ret;
    }

    q->streaming = 1;

    dprintk(3, "successful\n");
    return 0;
}
`

vb2_start_streaming

static int vb2_start_streaming(struct vb2_queue *q)
{
    struct vb2_buffer *vb;
    int ret;

    /*
     * If any buffers were queued before streamon,
     * we can now pass them to driver for processing.
     */
    list_for_each_entry(vb, &q->queued_list, queued_entry)
        __enqueue_in_driver(vb);

    /* Tell the driver to start streaming */
    q->start_streaming_called = 1;

    //调用start_streaming
    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 you see this warning, then the driver isn't cleaning up properly
     * after a failed start_streaming(). See the start_streaming()
     * documentation in videobuf2-core.h for more information how buffers
     * should be returned to vb2 in start_streaming().
     */
    if (WARN_ON(atomic_read(&q->owned_by_drv_count))) {
        unsigned i;

        /*
         * Forcefully reclaim buffers if the driver did not
         * correctly return them to vb2.
         */
        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);
        }
        /* Must be zero now */
        WARN_ON(atomic_read(&q->owned_by_drv_count));
    }
    /*
     * If done_list is not empty, then start_streaming() didn't call
     * vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED) but STATE_ERROR or
     * STATE_DONE.
     */
    WARN_ON(!list_empty(&q->done_list));
    return ret;
}

所以最终落到start_streaming的函数指针uvc_start_streaming函数。

static int uvc_start_streaming(struct vb2_queue *vq, unsigned int count)
{
    struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
    struct uvc_streaming *stream = uvc_queue_to_stream(queue);
    int ret;

    lockdep_assert_irqs_enabled();

    queue->buf_used = 0;

    ret = uvc_video_start_streaming(stream);
    if (ret == 0)
        return 0;

    spin_lock_irq(&queue->irqlock);
    uvc_queue_return_buffers(queue, UVC_BUF_STATE_QUEUED);
    spin_unlock_irq(&queue->irqlock);

    return ret;
}

uvc_video_start_streaming。

int uvc_video_start_streaming(struct uvc_streaming *stream)
{
    int ret;

    ret = uvc_video_clock_init(stream);
    if (ret < 0)
        return ret;

    /* Commit the streaming parameters. */
    ret = uvc_commit_video(stream, &stream->ctrl);
    if (ret < 0)
        goto error_commit;

    ret = uvc_video_start_transfer(stream, GFP_KERNEL);
    if (ret < 0)
        goto error_video;

    return 0;

error_video:
    usb_set_interface(stream->dev->udev, stream->intfnum, 0);
error_commit:
    uvc_video_clock_cleanup(stream);

    return ret;
}

uvc_commit_video调用VS_COMMIT_CONTROLL请求

static int uvc_commit_video(struct uvc_streaming *stream,
                struct uvc_streaming_control *probe)
{
    return uvc_set_video_ctrl(stream, probe, 0);
}

关于uvc_set_video_ctrl详见https://www.usbzh.com/article/detail-1349.html
至于uvc_video_start_transfer则见:https://www.usbzh.com/article/detail-186.html

0 篇笔记 写笔记

UVC摄像头批量传输的StreamOn和StreamOff
在UVC规范中,UVC摄像头视频数据的传输方式支持两种,分别为批量传输和同步传输。UVC摄像头数据传输的格式按负载数据头的方式按帧进行打包传输。根据USB规范可知,同步传输方式是只要带中带有同步端点的接口,系统会定时从设备中读取数据,无论设备中是否有数据。而如要要停止数据的传输,只需要选中不带有同步......
UVC摄像头VS_PROBE_CONTROL和VS_COMMIT_CONTROL对应的数据结构定义
UVC 视频流接口控制请求 http://www.usbzh.com/article/detail-45.html 需要使用一些数据字段进行通讯,如UVC1.0是26个字节的长度,UVC1.1是34字节的长度,UVC1.5是48字节的长度。这里我们定义一个通用长48字节结构体,对应VS_PROBE_......
USB中文网出品-UVC视频格式协商协议分析工具
有没有对USB摄像头在打开时数据协商时的UVC视频流接口控制请求的几十个字节分析有时有点郁闷,手动分析又麻烦,写个工具感觉又划不来。有时没办法为,为了定位问题所在,还得手动分析,但这几十个字节在分析时还得不停地查文档。我们知道UVC随着版本的不同,其VS_PROBE_CONTROL和VS_COM......
LINUX&UVC驱动开启视频流VIDIOC_STREAMON
实现不想看那个视频流队列相关的东西,但有时又很好奇。就看了一个一知半解,只是梳理了一下代码流程,至于细节,鬼才去看。最终,其实想分析的是视频打开,只为只有这里有与UVC规范相关的请求。使用VIDIOC_STREAMON请求来打开视频流。 // 开始数据流 type = V4L2_BU......
关注公众号
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!