RTOS UVC 介绍#

我们在RTOS上对UVC设备进行了支持,现在默认仅支持MJPEG格式。

API介绍#

我们用struct uvc_frame来描述一帧UVC的图像,下面我们介绍该结构体。

  struct uvc_frame {
      unsigned int index;               /* 系统默认会开4个Buffer来存UVC的图像,这代表其中的第几个Buffer */
      unsigned int reserve_1;           /* 系统保留字段 */
      unsigned int reserve_2;           /* 系统保留字段 */
      unsigned int len;                 /* 表示获取到的UVC图像的大小 */
      char *userptr;                    /* 表示获取到的UVC图像的用户态地址,例如可以将其内容写入到文件 */
      union {
          k_video_frame_info v_info;    /* 当支持YUYV的时候,返回的k_video_frame_info结构,可以传给kd_mpi_vo_chn_insert_frame显示 */
          k_vdec_stream v_stream;       /* 当支持MJPEG的时候,返回的k_vdec_stream结构,可以传给kd_mpi_vdec_send_stream解码 */
      };
  };

我们对UVC代码进行了简单封装后,提供了四个接口给用户调用,下面一一介绍:

/**
 * uvc_init - 对枚举成功后的UVC设备进行初始化,开启摄像头。
 * @width:用于输入用户预期的宽,初始化完成后会返回实际的宽。
 * @height:用于输入用户预期的高,初始化完成后会返回实际的高。
 * @is_jpeg:用于选择是MJPEG格式还是YUYV格式,现在默认仅支持MJPEG格式。
 *
 * 用户输入的宽高代表着用户预期的分辨率,系统会将预期分辨率与该UVC设备支持的所有分辨率进行比较,
 * 最后找出的最接近的分辨率,然后通过width和height返回给用户,用户后续应当使用系统返回的分辨率。
 *
 * 此接口会分配一些内存以支持UVC图像的流转,默认内存是在VB里面分配的。
 *
 * @Return:成功返回0,失败返回负值。
 */
int uvc_init(int *width, int *height, unsigned char is_jpeg);

/**
 * uvc_get_frame - 获取一帧UVC图像,也就是拿到了一帧图像的Buffer。
 * @frame:用于返回一帧图像,帧结构体如上所述。
 *
 * 该接口会阻塞等待一帧图像返回,系统实现是无限期等待。
 *
 * @Return:成功返回0.失败返回负值。
 */
int uvc_get_frame(struct uvc_frame *frame);

/**
 * uvc_put_frame - 释放一帧图像Buffer给系统使用
 *
 * @Return:成功返回0.失败返回负值。
 */
int uvc_put_frame(struct uvc_frame *frame);

/**
 * uvc_exit - 关闭摄像头,释放uvc_init申请的内存。
 */
void uvc_exit();

示例介绍#

对于UVC来说,它的主体使用框架应该如下:(假设UVC设备已经插入且枚举成功)#

  1. 调用kd_mpi_vb_set_config(&config) 和 kd_mpi_vb_init() 进行VB的初始化,因为uvc_init分配的内存将来自VB。

  2. 调用uvc_init,进行uvc设备的初始化,打开UVC摄像头。

  3. 循环调用uvc_get_frame和uvc_put_frame,不断获取UVC图像。

  4. 程序结束,调用uvc_exit(),关闭UVC设备。

/* 示意性代码如下 */

int i = 1;
struct uvc_frame frame;

kd_mpi_vb_set_config(&config);
kd_mpi_vb_init();

uvc_init(w, h , 1);

do {

    uvc_get_frame(&frame);

    /* Write Frame to SDCARD */
    FILE *file = fopen("sdcard/app/userapps/test.jpg", "wb");
    size_t written = fwrite((char *)frame.userptr, sizeof(char), frame.len, file);
    fclose(file);

    uvc_put_frame(&frame);
} while (--i);

uvc_exit();

一个稍微复杂一些的的示例代码放在src/rtsmart/mpp/userapps/sample/sample_uvc/uvc_test.c#


不带任何参数,直接运行sample_uvc,默认会给出如下提示:
Usage: ./sample_uvc [connector_type] [rotation] [is_jpeg] [width] [height] [total_frame]

connector_type:表示接入的pannel类型
rotation:表示图像是否要翻转
is_jpeg:表示是用MJPEG还是YUYV格式,默认仅支持MJPEG格式
width:表示图像宽度
height:表示图像高度
total_frame:表示需要显示多少帧


例如该例程在01studio的板子上运行,接入了一个ST7701_V1_MIPI_2LAN_480X800_30FPS(枚举值为2)的屏幕,接入了一个支持640 * 480分辨率的UVC摄像头。
那么我们可以这样运行程序:sdcard/app/userapps/sample_uvc.elf 2 1 1 640 480 100000

如果程序运行正常,就会看到屏幕有图像显示。

配置选项#

make menuconfig#

make menuconfig

make rtsmart-menuconfig#

make rtsmart-menuconfig

注意事项#

不建议接入Hub后,接入UVC设备和其他使用Bulk传输的设备一起用,可能会有带宽不够的问题。如果一定要这么用,请先接入UVC设备使用起来后再接入其他设备,但不确保一定不会遇到带宽不足的问题。