V4l2框架,rk3568遇到释放错误问题

近期在一个项目中,遇到摄像头连接线不稳定,导致获取数据卡死问题。这是硬件与底层问题所导致的,我们要在软件层进行一些处理;

初步方案是在获取数据错误时,重新初始化以达到恢复正常状态

部分初始化代码如下:

 fd = open(m_device_name, O_RDWR);
        if(fd == -1)
    {
        printf("Error opening V4L2 interface\n");
        return -1;
    }
    
    // Determine if fd is a V4L2 Device
    if (0 != wrap_ioctl(fd, VIDIOC_QUERYCAP, &cap)) {
        printf("Not v4l2 compatible\n");
        goto FAIL_EXIT;
    }
    
    printf("Driver Name:%s\nCard Name:%s\nBus info:%s\nDriver Version:%u.%u.%u\n",cap.driver,cap.card,cap.bus_info,(cap.version>>16)&0XFF, (cap.version>>8)&0XFF,cap.version&0XFF);

    if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)) {
        printf("Capture not supported\n");
        goto FAIL_EXIT;
    }

    if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
        printf("Streaming IO Not Supported\n");
        goto FAIL_EXIT;
    }

    struct v4l2_fmtdesc fmtdesc;
    fmtdesc.index=0;
    fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
    printf("Support format:\n");
    while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc)!=-1)
    {
        fmtdesc.index++;
    }
    vfmt = (struct v4l2_format) {0};
    vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
        vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;

    vfmt.fmt.pix.width = m_camera_w;
    vfmt.fmt.pix.height = m_camera_h;

    vfmt.fmt.pix.pixelformat = m_pixel_fmt;

    if (!vfmt.fmt.pix.pixelformat)
        vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_NV12;
    
    type = (v4l2_buf_type)vfmt.type;
    m_type = type;

    if (-1 == wrap_ioctl(fd, VIDIOC_S_FMT, &vfmt)) {
        printf("VIDIOC_S_FMT\n");
        goto FAIL_EXIT;
    }

部分反初始化代码如下:

  ioctl(fd, VIDIOC_STREAMOFF, &type);
    
    for (i = 0 ; i < m_bufcnt; i++) {
        buf = (struct v4l2_buffer) {0};
        buf.type    = type;
        buf.memory  = V4L2_MEMORY_MMAP;
        buf.index   = i;

        wrap_ioctl(fd, VIDIOC_QUERYBUF, &buf);

        munmap(m_video_buffer[i].start, buf.length);
    }

在通过调用获取数据接口无法获取数据时 进行反初始化,并重新初始化

wrap_ioctl(fd, VIDIOC_DQBUF, &buf);

程序段错误崩溃,代码在这里崩溃。

wrap_ioctl(fd, VIDIOC_S_FMT, &vfmt)

此时内核报错:

 rkcif_mipi_lvds: rkcif_s_fmt_vid_cap_mplane queue busy

跟踪内核代码,

static inline bool vb2_is_busy(struct vb2_queue *q)
{
	return (q->num_buffers > 0);
}

发现此时报错提示信息指向 queue 不为空,此时开始回到反初始化代码处,查看释放问题

需要注意一点的是:

VIDIOC_STREAMON 和 VIDIOC_STREAMOFF 两个 ioctl 用来开始和停止 capturing 或者 output ,而且VIDIOC_STREAMOFF 会删除输入和输出队列中的所有 buffer 。

重点在于 VIDIOC_STREAMOFF 会删除输入和输出队列中的所有 buffer 。

此时大概知道问题在哪里了,释放处我在VIDIOC_STREAMOFF之后,又调用了VIDIOC_QUERYBUF。

这时我加了打印,发现获取到的buf.length为0,导致munmap失败。也就是queue没有真正的释放。

修改代码如下:

    ioctl(fd, VIDIOC_STREAMOFF, &type);

    for (i = 0 ; i < m_bufcnt; i++) {


        munmap(m_video_buffer[i].start, m_video_buffer[i].length);
    }
    CLEAR(req);
    req.count = 0;
    req.type = type;
    req.memory = V4L2_MEMORY_MMAP;
    wrap_ioctl(fd, VIDIOC_REQBUFS, &req);

此时问题得到解决。

这就是本次调试的过程,个人理解或有不对之处,请指正。

你可能感兴趣的:(笔记,linux,arm开发)