[TI TDA4 J721E]TIOVX OpenVX Graph Pipelining理解和移植使用(更新版)

          首先感谢阅读,如果您也对TDA4相关的开发感兴趣,我们这边有个学习交流微信群,可以入群和大家一起交流学习。

资历较浅,水平有限,如遇错误,请大家多指正!

保持开源精神,共同分享、进步!

博主WX : AIR_12  我会拉你入群。

链接:TDA4 相关专栏        链接:TDA4  Demo  Gitee开源库

欢迎大家加入,一起维护这个开源库,给更多的朋友提供帮助。


更新时间:2022年06月30日

一、Graph和Pipeline的区别和对比:

1、Pipeline的本质:通过分时复用的方式,提高了硬件的整体利用率,但在本质上,运行单条流水线和运行一次graph的时间是相同的。

2、原有的Graph,如果执行vxProcessGraph,那么graph一旦运行起来,就不允许被打断;且同一个时刻,只有一个核参与整体的graph的处理过程。

3、但是Pipeline,可以实现在graph运行过程中,对关心的数据即通过(graph_parameters_queue_params_list)进行调整,比如图片替换、复制等等。

4、同时,pipeline还允许不同的核在同一个时间,参与到不同流水线的处理过程中。整体上提升了硬件的利用效率。

GraphPipeline
是否可打断不可以可以(通过graph_parameters_queue_params_list)
硬件同时运行不可以可以(同一个时刻,允许多个核同时运行不同的pipeline的处理)

二、例程说明

本例程以SDK 0800版本为基准,使用 ./apps/dl_demos/app_tidl_od_cam 作为示例。

在app_create_graph 函数内,创建了一下一系列的 node 顺序如下:

节点名称节点主要功能
CaptureNode从摄像头获取传感器图像数据
VpacVissNode将RAW 数据转换成YUV格式的数据
AewbNode实现图像自动白平衡等相关的处理
VpacLdcNode对图像进行畸变矫正等
VpacMscScaleNode图像缩放处理节点(缩放至训练网络接收的size)

ImgPreProcNode

图像预处理节点(将图像数据预处理转换成Tidl模块可以处理的RGB格式等
TIDLNode深度网络,实现目标检测、推理等功能
DrawBoxDetectionsNode绘制检测到物体框的节点
ImgMosaicNode图像镶嵌节点,将多个图像嵌入到同一个图像内
DisplayNode显示节点,将经过镶嵌的图像显示到显示器

其中 VpacVissNode AewbNode VpacLdcNode VpacMscScaleNode ImgPreProcNode

在创建的时候,会使用vxReplicateNode节点进行相应节点的复制。这里我当时的主要疑问是复制了几个这样的节点。
在创建这些node的时候,会传入一个vx_object_array,具体说明参考这里

[TI TDA4 J721E] TIOVX 常用函数详解 之——vxReplicateNode_AIRKernel的博客-CSDN博客

创建的总数量应该是和这个参数包含的成员数量相当。(成员数量=4 ,创建的个数 = 4-1 =3),因为已经创建了一个Node了。


三、graph_parameters_queue_params_list

graph_parameters_queue_params_list 必须被设置,这个列表表示在graph运行过程中可以被访问对象的索引。

        graph_parameter_index = 0;
        add_graph_parameter_by_node_index(obj->graph, obj->captureObj.node, 1); //将captureNode 的序号为1的参数,加入到 graph_parameters_queue_params_list中

        obj->captureObj.graph_parameter_index = graph_parameter_index; //设置capture节点的 索引
        graph_parameters_queue_params_list[graph_parameter_index].graph_parameter_index = graph_parameter_index; //设置graph_parameters_queue_params_list中对应成员的索引
        graph_parameters_queue_params_list[graph_parameter_index].refs_list_size = APP_BUFFER_Q_DEPTH;          //注意:设置该成员包含的子成员的个数
        graph_parameters_queue_params_list[graph_parameter_index].refs_list = (vx_reference *)&obj->captureObj.raw_image_arr[0];    //成员指针指向被操作的对象地址
        graph_parameter_index++;    //索引数量增加

        vxSetGraphScheduleConfig(obj->graph,
                                 VX_GRAPH_SCHEDULE_MODE_QUEUE_AUTO,
                                 graph_parameter_index,
                                 graph_parameters_queue_params_list);

四、Enqueue 和 Dequeue 相关顺序说明

更新时间:2022年06月30日

工作流程(请结合第五点代码):

1、根据需要,可以将需要对enqueue对象进行的修改完成后,等待enqueue。

2、根据流水线深度,Enqueue相关的对象 。

3、执行Dequeue。

4、执行Dequeue后,会自动将流水线向前执行一条流水线,完成一个完整graph的运行(注意此处说的是整个pipline的graph_parameters_queue_params_list只有一个成员。如果有两个成员,需要继续再次Dequeue,才能完成整条流水线的工作)。


五、Enqueue 和 Dequeue

请结合代码注释阅读!!!


    if(obj->pipeline <= 0)
    {
        /* Enqueue outpus */
        /* Enqueue inputs during pipeup dont execute */
        //将capture获取到的图像,逐个入队到graph中
        vxGraphParameterEnqueueReadyRef(obj->graph, captureObj->graph_parameter_index, (vx_reference*)&captureObj->raw_image_arr[obj->enqueueCnt], 1);

        obj->enqueueCnt++;
        obj->enqueueCnt   = (obj->enqueueCnt  >= APP_BUFFER_Q_DEPTH)? 0 : obj->enqueueCnt;
        obj->pipeline++;
    }

    if(obj->pipeline > 0)
    {
        vx_image capture_input_image;
        uint32_t num_refs;

        /* Dequeue input */
        //将经过运行captureNode节点,得到的输出图像出队。
        vxGraphParameterDequeueDoneRef(obj->graph, captureObj->graph_parameter_index, (vx_reference*)&capture_input_image, 1, &num_refs);
        // Dequeue实际上是将TIOVX空间的数据,映射到用户空间内,用户可以根据这个指针对数据进行修改。
        //经过出对的图像数据,可以在这里进行操作。
        // 执行出队后,capture_input_image图像可能位于captureObj->raw_image_arr[array]中的任意位置,如果需要确定,需要将
        // capture_input_image和captureObj->raw_image_arr[array]中的对象进行对比,参考0703的decode部分。
        //
        /* Enqueue input - start execution */
        //将映射到用户空间的对象重新入队。原来的位置会被自动至为NULL,直到下次dequeue。
        vxGraphParameterEnqueueReadyRef(obj->graph, captureObj->graph_parameter_index, (vx_reference*)&capture_input_image, 1);

        obj->enqueueCnt++;
        obj->dequeueCnt++;

        obj->enqueueCnt = (obj->enqueueCnt >= APP_BUFFER_Q_DEPTH)? 0 : obj->enqueueCnt;
        obj->dequeueCnt = (obj->dequeueCnt >= APP_BUFFER_Q_DEPTH)? 0 : obj->dequeueCnt;
    }

    appPerfPointEnd(&obj->total_perf);

以下是0703版本Decode版本的相关代码:

其中这两个函数,就是为了查找到被dequeue出来的对象在array中的索引。

app_find_image_array_index
app_find_user_object_array_index 

vx_status app_run_decodeGraph(vx_graph graph, DecodeObj *decodeObj, vx_user_data_object *bitStream)
{
    vx_status status = VX_SUCCESS;

    if (decodeObj->pipeline < 0)
    {
        /* Enqueue output */
        vxGraphParameterEnqueueReadyRef(graph, decodeObj->output_image_graph_parameter_index, (vx_reference *)&decodeObj->output_image[decodeObj->enqueueCnt], 1);

        app_copy_encodeBitStream_to_decodeBitStream(&decodeObj->bitstream_obj[decodeObj->enqueueCnt], bitStream);

        /* Enqueue input - start execution */
        vxGraphParameterEnqueueReadyRef(graph, decodeObj->input_bitstream_graph_parameter_index, (vx_reference *)&decodeObj->bitstream_obj[decodeObj->enqueueCnt], 1);

        decodeObj->enqueueCnt++;
        decodeObj->enqueueCnt = (decodeObj->enqueueCnt >= decodeObj->num_buf) ? 0 : decodeObj->enqueueCnt;
        decodeObj->pipeline++;
    }
    else if (decodeObj->pipeline >= 0)
    {
        vx_int32 array_idx = -1, img_array_idx = -1;
        vx_image out_image;
        vx_user_data_object in_bitstream;
        uint32_t num_refs;
        /* Dequeue & Save output */
        //参数说明:要出队的参数索引、被出队的对象填充该区域、最大的出队个数、实际的出队个数
        vxGraphParameterDequeueDoneRef(graph, decodeObj->output_image_graph_parameter_index, (vx_reference *)&out_image, 1, &num_refs);
        app_find_image_array_index(decodeObj->output_image, (vx_reference)out_image, decodeObj->num_buf, &img_array_idx);

        if (img_array_idx != -1)
        {
            app_decode_saveImageToFile("/home/root/mydecode.yuv", &decodeObj->output_image[img_array_idx]);
        }
        /* Dequeue input */
        vxGraphParameterDequeueDoneRef(graph, decodeObj->input_bitstream_graph_parameter_index, (vx_reference *)&in_bitstream, 1, &num_refs);


        /* Enqueue output */
        vxGraphParameterEnqueueReadyRef(graph, decodeObj->output_image_graph_parameter_index, (vx_reference *)&out_image, 1);
        app_find_user_object_array_index(decodeObj->bitstream_obj, (vx_reference)in_bitstream, decodeObj->num_buf, &array_idx);

        if (array_idx != -1)
        {
            app_copy_encodeBitStream_to_decodeBitStream(&decodeObj->bitstream_obj[array_idx], bitStream);
        }
        /* Enqueue input - start execution */
        vxGraphParameterEnqueueReadyRef(graph, decodeObj->input_bitstream_graph_parameter_index, (vx_reference *)&in_bitstream, 1);
     }

    return status;
}

void app_find_user_object_array_index(vx_user_data_object object_array[], vx_reference ref, vx_int32 array_size, vx_int32 *array_idx)
{
    vx_int32 i;

    *array_idx = -1;
    for (i = 0; i < array_size; i++)
    {
        if (ref == (vx_reference)object_array[i])
        {
            *array_idx = i;
            break;
        }
    }
}

void app_find_image_array_index(vx_image image_array[], vx_reference ref, vx_int32 array_size, vx_int32 *array_idx)
{
    vx_int32 i;

    *array_idx = -1;
    for (i = 0; i < array_size; i++)
    {
        if (ref == (vx_reference)image_array[i])
        {
            *array_idx = i;
            break;
        }
    }
}

【声明】
【欢迎转载转发,请注明出处。原创比较辛苦,请尊重原创,祝大家学习愉快!】
【博主专注嵌入式开发,具有多年嵌入式软、硬件开发经验,欢迎大家学习交流!】
【如有嵌入式相关项目需求,欢迎私信】   

  • 10
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值