浅析 Hi3516 中的 uvc_app

文件描述

application.c 主函数起始
camera.c 提供hicamera摄像头对象,负责hiuvc,hiuac控制
hiuvc.c 提供hiuvc对象,负责视频控制
uvc_gadget.c 实现uvc设备操作功能
histream.c 实现视频流操作功能
frame_cache.c 实现uvc缓存操作功能
sample*.c 实现对接mpp媒体开发框架操作功能
hiuac.c 提供hiuac对象,负责音频控制

对象操作

以文件划分功能,文件的操作函数都为静态文件作用域(对外部不可见),这些函数最终被赋值到变量中,而这个变量也是静态的,只能被唯一一个的全局作用域函数get_xxx()或取。

static int __init(void){};
static int __run(void){};

static hicamera __hi_camera =
{
    .init = __init,
    .run = __run,
};

hicamera *get_hicamera(void)
{
    return &__hi_camera;
}

对象分析

hiuvc对象为切入点,它由初始化、打开、关闭和运行四个部分组成。对象主要负责流程控制,不包含具体实现,可以发现提供该对象最终支持的是uvc_gadget.c。其中__init并没有做任何事,__open__close为直接调用,__run中创建了线程去执行uvc_send_data_thread,然后进入循环run_uvc_device状态。

浅析 Hi3516 中的 uvc_app

__open

深入open_uvc_device函数,可以发现它的最终执行的是v4l2常规流程,首先open设备视频设备节点获得fd,其次ioctl查询V4l2能力,最后再去设定订阅事件,如VC处理(UVC_EVENT_SETUP),VS处理(UVC_EVENT_DATA),开启流(UVC_EVENT_STREAMON), 停止流(UVC_EVENT_STREAMOFF)。

浅析 Hi3516 中的 uvc_app

__close

关闭是打开的相反操作,主要是去close掉打开的描述符,在这之前需要关闭视频能力。

浅析 Hi3516 中的 uvc_app

__run

这个函数会创建线程循环执行run_uvc_data,自身进入run_uvc_device循环。

浅析 Hi3516 中的 uvc_app

run_uvc_device

这个功能块负责执行UVC事件处理,函数通过select监听描述符,当描述符就绪时就从视频设备的事件队列中出队一个事件并做处理。当初始化事件完成后会收到UVC_EVENT_STREAMON事件,对应的执行enable_uvc_video()启动流。当不需要据流时收到UVC_EVENT_STREAMOFF事件,执行disable_uvc_video()停止流。

浅析 Hi3516 中的 uvc_app

run_uvc_data

这个功能块负责在启动流后当描述符就绪时就把一帧数据推入UVC视频缓冲区。

浅析 Hi3516 中的 uvc_app

数据缓存

数据由uvc_cache管理,它总共有2个帧队列和6个帧节点组成。队列free_queue表示空闲节点队列,节点创建时被putfree_queue中等待使用。

create_uvc_cache
    create_cache_node_list
        node = malloc //创建6块
        put_node_to_queue(uvc_cache->free_queue, node)

数据制造

数据来源由UVC_EVENT_STREAMON事件的histream_startup()这个函数动作产生,进入函数可以看到,它又创建了一条线程不断去监听Venc,当就绪时获取图像数据。这里涉及到第二个队列ok_queue,它用于存放填好数据的节点,节点正是由free_queue队列中取出,填充帧数据后putok_queue中,这是节点在队列中的第一次位置交换。

浅析 Hi3516 中的 uvc_app

相反过程就是UVC_EVENT_STREAMOFF事件,需要关闭流和清空缓冲区。

浅析 Hi3516 中的 uvc_app

数据首次消费

数据的首次消费也是在启动流 UVC_EVENT_STREAMON事件到来时,节点第一次被从ok_queue队列取出,其中node->mem会被赋值到v4l2_buff中由ioctrl入队到内核(这需要事先申请好空间),这个node还会被记录在__waited_node[]等待队列中。uvc_video_stream_userptr也是视频帧的第一个消费者。

浅析 Hi3516 中的 uvc_app

数据后续消费

帧入队完后_SAMPLE_COMM_VENC_SaveData()会继续从free_queue取出节点填充并挂到ok_queue中,此时初始化作为消费者的使命已经结束,交由线程的uvc_video_process_userptr进行消费,线程首先从内核出队一个帧,并从ok队列中取一个节点,被出队的帧号对应的等待队列的节点也不再需要了,把他丢弃到free队列去并赋值为新的节点值,最后同样将node->mem通过v4l2_buffioctrl到内核。这各过程被重复执行就实现了内核与用户数据源源不断的轮换。

浅析 Hi3516 中的 uvc_app

浅析 Hi3516 中的 uvc_app

上一篇:Android基础-Button点击事件(1.匿名内部类 2.内部类监听器 3.用本类实现activity 4.xml实现按钮点击事件)


下一篇:Android基础-ImageView图片组件