This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TDA4AH-Q1:用于马赛克输出的 H264 编码器、某些帧闪烁

Guru**** 2330840 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1521370/tda4ah-q1-h264-encoder-for-mosaic-output--some-frames-are-flickering

器件型号:TDA4AH-Q1

工具/软件:

我们将 TDA4AH 与 RTOS SDK 和 Linux (j784s4-evm-09_02_00_05) 用于软件开发、我们需要有 H264 编码视频输出、用于五个视频的马赛克输出组合。由于几帧损坏、H264 编码视频闪烁。

配置是:帧速率为 30fps ,我们正在捕捉 500 个连续帧,当所有帧都保存为 YUV 图像时,图像没有损坏,但当保存视频文件与 H264 编码的视频时,有些帧损坏,视频闪烁。 请参阅随附的视频。

我们遵循了“apps/vision_apps/multicam-codec"RTOS SDK“ SDK 中提供的示例代码。 我们是否需要使用 H264 对马赛克输出进行编码的任何特定设置? 请访问 suggest.e2e.ti.com/.../5226.output_5F00_video_5F00_0.mp4

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    e2e.ti.com/.../3125.output_5F00_video_5F00_0.mp4

    添加输出视频以供参考

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Suresh、  

    我们将在 b/w 释放时看看这一点。

    谢谢您、
    Sarabesh S.

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Suresh、

    请提供您对内核或应用程序所做的任何补丁。

    谢谢、
    Sarabesh S.

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    连接正确的帧循环 enq DEQ 片段、前一个缺少马赛克输出出队调用:

    for (i = 0; i < 500; i++)
            {
                if (i >= h264_graph_obj_ptr->enc_pool.bufq_depth)
                {
    #if 1
                    appPerfPointBegin(&h264_graph_obj_ptr->graph_perf);
                    start_time = tivxPlatformGetTimeInUsecs();
                    /* Dequeue one image buffer */
                    if (status != VX_SUCCESS)
                    {
                        GEN3_DBG_PRINTF_ERR("ERROR: graph dequeue failed for capt cl2 cl4 out arr[%d], status = %d\n", buf_id, status);
                    }
    #endif
                    status = vxGraphParameterDequeueDoneRef(h264_graph_obj_ptr->graph,
                                                        h264_graph_obj_ptr->h264_imgMosaicObj.graph_parameter_index,
                                                        (vx_reference *)&image_temp, 1, &num_refs);
                    appPerfPointEnd(&h264_graph_obj_ptr->graph_perf);
                    if (i % 50 == 0)
                    {
                        appPerfPointPrintFPS(&h264_graph_obj_ptr->graph_perf);
                        appPerfPointReset(&h264_graph_obj_ptr->graph_perf);
                        printf("mosaic time taken %lu\n", tivxPlatformGetTimeInUsecs() - start_time);
                    }
                    if (i >= h264_graph_obj_ptr->enc_pool.bufq_depth)
                    {
                        status = appCodecDeqAppSrc(h264_graph_obj_ptr->mosaic_enq_id);
                        if (status != VX_SUCCESS)
                        {
                            printf("App Codec DEqueue App src is  FAILED!\n");
                        }
                        else
                        {
                            status = unmap_vx_object_arr((vx_object_array)h264_graph_obj_ptr->enc_pool.arr[h264_graph_obj_ptr->mosaic_enq_id],
                                                         h264_graph_obj_ptr->enc_pool.map_id[h264_graph_obj_ptr->mosaic_enq_id], h264_graph_obj_ptr->num_ch);
    #ifdef TEST_ENC_STATIC_MOSAIC_OUTPUT
                            status = unmap_vx_image(test_img[h264_graph_obj_ptr->mosaic_enq_id],
                                                    h264_graph_obj_ptr->enc_pool.map_id[h264_graph_obj_ptr->mosaic_enq_id]);
    #endif
                        }
                    }
                }
    #if 1
                /*output*/
                status = vxGraphParameterEnqueueReadyRef(h264_graph_obj_ptr->graph,
                                                         5,
                                                         (vx_reference *)&h264_graph_obj_ptr->h264_imgMosaicObj.output_image[h264_graph_obj_ptr->mosaic_enq_id], // lm: changed [buf_id] -> [h264_graph_obj_ptr->mosaic_enq_id]
                                                         1);
                if (status != VX_SUCCESS)
                {
                    GEN3_DBG_PRINTF_ERR("ERROR: graph enqueue failed for capt cl2 cl4 out arr[%d], status = %d\n", buf_id, status);
                }
                {
                    status = map_vx_object_arr((vx_object_array)h264_graph_obj_ptr->enc_pool.arr[h264_graph_obj_ptr->appsrc_push_id],
                                               h264_graph_obj_ptr->enc_pool.data_ptr[h264_graph_obj_ptr->appsrc_push_id],
                                               h264_graph_obj_ptr->enc_pool.map_id[h264_graph_obj_ptr->appsrc_push_id], h264_graph_obj_ptr->num_ch);
    #ifdef TEST_ENC_STATIC_MOSAIC_OUTPUT
                    status = map_vx_image(test_img[h264_graph_obj_ptr->appsrc_push_id],
                                          h264_graph_obj_ptr->enc_pool.data_ptr[h264_graph_obj_ptr->appsrc_push_id],
                                          h264_graph_obj_ptr->enc_pool.map_id[h264_graph_obj_ptr->appsrc_push_id]);
    #endif
                }
                if (status == VX_SUCCESS)
                {
                    status = appCodecEnqAppSrc(h264_graph_obj_ptr->mosaic_enq_id);
                    {
                        if (status != VX_SUCCESS)
                        {
                            printf("pp Codec Enqueue App src is  FAILED!\n");
                        }
                    }
                }
                h264_graph_obj_ptr->appsrc_push_id++;
                h264_graph_obj_ptr->appsrc_push_id = (h264_graph_obj_ptr->appsrc_push_id >= h264_graph_obj_ptr->enc_pool.bufq_depth) ? 0 : h264_graph_obj_ptr->appsrc_push_id;
                h264_graph_obj_ptr->mosaic_enq_id++;
                h264_graph_obj_ptr->mosaic_enq_id = (h264_graph_obj_ptr->mosaic_enq_id >= h264_graph_obj_ptr->enc_pool.bufq_depth) ? 0 : h264_graph_obj_ptr->mosaic_enq_id;
    
            } // End of for loop
            first_file = 0;
            for (i = 0; i < h264_graph_obj_ptr->enc_pool.bufq_depth; i++)
            {
    #if 1
                status = vxGraphParameterDequeueDoneRef(h264_graph_obj_ptr->graph,
                                                        h264_graph_obj_ptr->h264_imgMosaicObj.graph_parameter_index,
                                                        (vx_reference *)&image_temp, 1, &num_refs);
                if (status != VX_SUCCESS)
                {
                    GEN3_DBG_PRINTF_ERR("ERROR: graph dequeue failed for capt cl2 cl4 out arr[%d], status = %d\n", buf_id, status);
                }
                value++;
    #endif
                status = appCodecDeqAppSrc(h264_graph_obj_ptr->mosaic_enq_id);
                unmap_vx_object_arr((vx_object_array)h264_graph_obj_ptr->enc_pool.arr[h264_graph_obj_ptr->mosaic_enq_id], h264_graph_obj_ptr->enc_pool.map_id[h264_graph_obj_ptr->mosaic_enq_id], h264_graph_obj_ptr->num_ch);
    #ifdef TEST_ENC_STATIC_MOSAIC_OUTPUT
                unmap_vx_image(test_img[h264_graph_obj_ptr->mosaic_enq_id], h264_graph_obj_ptr->enc_pool.map_id[h264_graph_obj_ptr->mosaic_enq_id]);
    #endif
                h264_graph_obj_ptr->mosaic_enq_id++;
                h264_graph_obj_ptr->mosaic_enq_id = ((h264_graph_obj_ptr->mosaic_enq_id >= h264_graph_obj_ptr->enc_pool.bufq_depth) ? 0 : h264_graph_obj_ptr->mosaic_enq_id);
            }
            if (h264_graph_obj_ptr->encode == 1)
            {
                printf("Pushing EoS to Codec Pipeline.\n");
                status = appCodecEnqEosAppSrc();
            }
    
            if (h264_graph_obj_ptr->encode == 1)
            {
                appCodecStop();
                printf("appCodecStop Done!\n");
            }
            i = 0;
            outer_loop++;
            for (buf_id = 0; buf_id < h264_graph_obj_ptr->enc_pool.bufq_depth; buf_id++)
            {
    #if defined(GEN3_APP_DEBUG_ENABLE)
                each_frame_processing_time = tivxPlatformGetTimeInUsecs();
    #endif
            } // for

    谢谢、

    Lalit

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你好 Lalit、  

    我到 23 日才下班、但在我有空时、我会看看这一点。 我在我们的 Vision Apps 专家的反馈中给出了一些见解、以了解您是否应该对马赛克输出进行任何特定设置。

    默认的多摄像头编解码器演示是否适用于马赛克输出(没有您的更改)?

    谢谢您、
    Sarabesh S.

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Sarabesh:

    是的,我没有尝试带马赛克的默认多摄像头,但我做了一个小实验来测试我的应用程序中的编码器。 我没有通过马赛克输出图像 ,而是创建了一些静态 图像  ,并将它们直接映射到编码器输入,从而完全移除马赛克节点。 这一次输出视频没有垃圾帧。 在进一步调试时,我发现我的 map_vx_object_array () 函数可能有一些问题。

    在下面附加 MAP 函数定义:

    static vx_status map_vx_object_arr(vx_object_array in_arr, void *data_ptr[CODEC_MAX_NUM_CHANNELS][CODEC_MAX_NUM_PLANES], vx_map_id map_id[CODEC_MAX_NUM_CHANNELS][CODEC_MAX_NUM_PLANES], vx_int32 num_channels)
    {
        vx_status status;
        vx_int32 ch;
    
        status = vxGetStatus((vx_reference)in_arr);
    
        for (ch = 0; status == VX_SUCCESS && ch < num_channels; ch++)
        {
            vx_rectangle_t rect;
            vx_imagepatch_addressing_t image_addr;
    
            vx_uint32 img_width;
            vx_uint32 img_height;
    
            vx_image in_img = (vx_image)vxGetObjectArrayItem(in_arr, ch);
    
            vxQueryImage(in_img, VX_IMAGE_WIDTH, &img_width, sizeof(vx_uint32));
            vxQueryImage(in_img, VX_IMAGE_HEIGHT, &img_height, sizeof(vx_uint32));
    
            rect.start_x = 0;
            rect.start_y = 0;
            rect.end_x = img_width;
            rect.end_y = img_height;
            // printf("(mapping arr)img_width: %d, img_height: %d\n", img_width, img_height);
            /* MAP Luma */
            status = vxMapImagePatch(in_img,
                                     &rect,
                                     0,
                                     &map_id[ch][0],
                                     &image_addr,
                                     &data_ptr[ch][0],
                                     VX_READ_ONLY,
                                     VX_MEMORY_TYPE_HOST,
                                     VX_NOGAP_X);
            if (status != VX_SUCCESS)
            {
                printf("map_obj_arr(): vxMap unsuccessful");
                return (status);
            }
            // printf("img_addr.h: %d, img_addr.w: %d, img_addr.strd_y:%d\n", image_addr.dim_x, image_addr.dim_y, image_addr.stride_y);
            // static int file_count = 1;
            // char name[100];
            // snprintf(name, 100, "/opt/vision_apps/test_data/mosaic_out_file_%d.yuv", file_count++);
            // FILE *fp = fopen(name, "wb");
            // if (!fp)
            // {
            //     printf("Error: Unable to open file %s\n", name);
            //     return -1;
            // }
            // uint8_t *y_data_ptr = data_ptr[ch][0];
            // for (int i = 0; i < img_height; i++)
            // {
            //     fwrite(y_data_ptr, 1, image_addr.stride_y, fp);
            //     y_data_ptr += image_addr.stride_y;
            // }
            // fflush(fp);
            // printf("dumped plane 1\n");
            /* Map CbCr */
            status = vxMapImagePatch(in_img,
                                     &rect,
                                     1,
                                     &map_id[ch][1],
                                     &image_addr,
                                     &data_ptr[ch][1],
                                     VX_READ_ONLY,
                                     VX_MEMORY_TYPE_HOST,
                                     VX_NOGAP_X);
            if (status != VX_SUCCESS)
            {
                printf("copy_image(): vxMap unsuccessful");
                return (status);
            }
            // uint8_t *uv_data_ptr = data_ptr[ch][1];
            // for (int i = 0; i < img_height/2; i++)
            // {
            //     fwrite(uv_data_ptr, 1, img_width, fp);
            //     uv_data_ptr += image_addr.stride_y;
            // }
            // fflush(fp);
            // printf("dumped plane 2\n");
            // fclose(fp);
            // vxReleaseReference((vx_reference *)&in_img);
        }
        return (status);
    }

    映射后、我尝试使用 data_ptr(请参阅注释代码)来保存两个平面的图像。 保存的图像不正确。 它们之间有很多垃圾像素。 我发现两个图像是正确的、接下来的四个图像不正确、然后再次发现两个图像是正确的、依此类推。 我怀疑它可能与缓冲区有关、但无法进行调试。

    如果您有空、请查看此部分。 请从我这边告诉我您需要什么。

    谢谢。此致、

    Lalit

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Lalit、

    若要配置马赛克窗口、可以参考 mult_cam_ demo 中的 set_img_mosaich_params。 其中 in_width 和 in_height 是 使用 appIssGetResizeParams () 计算的 、以便这些值与 8x 对齐。

    此致、
    Gokul

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Gokul:

    我尝试了这个,但它仍然不起作用。

    此致、

    Lalit

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Lalit、

    您能否将马赛克输出连接到显示节点而不是编码器、并查看问题是否仍然存在。

    此致、
    Gokul

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    嗨 Gokul,我可以尝试这个,但 fyi 我保存了所有 500 马赛克出队的缓冲区数据,所有保存的图像都是正确的。

    在这种情况下、带显示屏的测试是否有意义?  

    此致、

    Lalit

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Lalit、

    在这种情况下不需要它、因为马赛克的输出是正确的。 我怀疑缓冲区的入队/出队部分、马赛克和编解码器同时使用缓冲区、并在某处损坏缓冲区。 您还可以查看 multi_cam 编解码器演示、作为排队/出队器件的参考。

    此致、
    Gokul

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、

    我调试了问题并将更改放在这里。

    将参考列表从马赛克输出更改为 ENC 池 AR。

    之前:

    idx = 0;
        status = add_graph_parameter_by_node_index(h264_graph_obj_ptr->graph, h264_graph_obj_ptr->h264_imgMosaicObj.node, 1); // lm: idx 0 -> 1 using output image not config
        /* Set graph schedule config such that graph parameter @index is enqueuable */
        h264_graph_obj_ptr->h264_imgMosaicObj.graph_parameter_index = idx;
        graph_parameters_queue_params_list[idx].graph_parameter_index = idx;
        graph_parameters_queue_params_list[idx].refs_list_size = h264_graph_obj_ptr->enc_pool.bufq_depth; // lm: changed from GRAPH_PRM_REF_LIST_SIZE(=4) to enc_pool.bufq_depth(=6)
        graph_parameters_queue_params_list[idx].refs_list = (vx_reference *)&h264_graph_obj_ptr->h264_imgMosaicObj.output_image[0];
        idx++;

    之后:

    idx = 0;
        status = add_graph_parameter_by_node_index(h264_graph_obj_ptr->graph, h264_graph_obj_ptr->h264_imgMosaicObj.node, 1); // lm: idx 0 -> 1 using output image not config
        /* Set graph schedule config such that graph parameter @index is enqueuable */
        h264_graph_obj_ptr->h264_imgMosaicObj.graph_parameter_index = idx;
        graph_parameters_queue_params_list[idx].graph_parameter_index = idx;
        graph_parameters_queue_params_list[idx].refs_list_size = h264_graph_obj_ptr->enc_pool.bufq_depth; // lm: changed from GRAPH_PRM_REF_LIST_SIZE(=4) to enc_pool.bufq_depth(=6)
        graph_parameters_queue_params_list[idx].refs_list = (vx_reference *)&h264_graph_obj_ptr->enc_pool.arr[0];
        idx++;
    

    相应地在排队呼叫中更改此值:

    之前:

     /*output*/
                status = vxGraphParameterEnqueueReadyRef(h264_graph_obj_ptr->graph,
                                                         5,
                                                         (vx_reference *)&h264_graph_obj_ptr->h264_imgMosaicObj.output_image[h264_graph_obj_ptr->mosaic_enq_id], // lm: changed [buf_id] -> [h264_graph_obj_ptr->mosaic_enq_id]
                                                         1);

    之后:

    status = vxGraphParameterEnqueueReadyRef(h264_graph_obj_ptr->graph,
                                                         0,
                                                         (vx_reference *)&h264_graph_obj_ptr->enc_pool.arr[h264_graph_obj_ptr->mosaic_enq_id], // lm: changed [buf_id] -> [h264_graph_obj_ptr->mosaic_enq_id]
                                                         1);

    我提到了多摄像头编解码器应用程序并进行了这些更改。 我感到困惑、因为这与之前的实现有何不同。 在之前的实现中 、我将马赛克输出图像数组作为参考列表、并使其排队。 该数组引用了 enc 池阵列本身(请参阅 链接马赛克输出和编码器输入的片段 )。 那么这两种实现方式如何不同呢? 需要明确这一点。

    谢谢。此致、

    Lalit  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Lalit、

    我指的是缓冲器部分的入队/出队。

    我怀疑的是马赛克和编码器在某些情况下使用相同的缓冲区、因此它被损坏。

    i 引用了多摄像头编解码器应用程序并进行了这些更改。 我感到困惑、因为这与之前的实现有何不同。 在之前的实现中 、我将马赛克输出图像数组作为参考列表、并使其排队。 该数组引用了 enc 池阵列本身(请参阅 链接马赛克输出和编码器输入的片段 )。 那么这两种实现方式如何不同呢? 需要明确说明这一点。

    由于您将马赛克输出到编码器、因此图形创建部分似乎是正确的。

    此致、
    Gokul