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.

[参考译文] AM62A7:Gstreamer 错误"vdec 3021100.video-codec:同步实例太多:32 (最大值:32)"

Guru**** 2473260 points
Other Parts Discussed in Thread: SK-AM62A-LP

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

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1426458/am62a7-gstreamer-error-vdec-30210000-video-codec-too-many-simultaneous-instances-32-max-32

器件型号:AM62A7
主题中讨论的其他器件:SK-AM62A-LP

工具与软件:

尊敬的 TI 团队:

我们将使用您的 SK-AM62A-LP 评估板、并编写了一个 C 应用程序、该应用程序使用 gst_parse_launch ()创建了一个 GStreamer 流水线。  

在我们需要 从 RGB 切换到 IR 或更改分辨率的情况下,我们将停止(GST_ELEMENT_SET_STATE (pipeline、GST_STATE_NULL)和 UNREF (GST_OBJECT_UNREF (pipeline )),并在我们再次使用 GST_PARSS_LAUNCH ()使用新的更新参数创建新的管道后不久。

这种方法在一段时间内可行,但随后突然(可能在第32个 UNREF 和  GST_Parse_launch()之后) GStreamer 崩溃,并出现以下错误:

"vdec 302100.video-codec:太多同步实例:32 (最大值:32)"

我在此主题中看到了相同的错误消息: AM62A7:正在寻求有关将 CSI 帧另存为 MP4文件的适当资源发布的指导-处理器论坛-处理器- TI E2E 支持论坛、 但未找到解决方案。

我可以通过适当发布资源来解决此问题吗? 我是否需要调用另一个函数?

非常感谢您提出任何建议。

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

    尊敬的 Christoph:

    您能否分享您尝试运行的 c 应用程序以便在最后重现问题  

    此外,您是否尝试使用 gst_bin_remove()删除编码器元素以查看其是否有用。

    此致、

    Suren

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

    谢谢 Christoph。

    将在下周早些时候尝试一下、并向您提供结果/解决方案的最新情况。

    此致、

    Suren

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

    尊敬的 Suren:

    DIE 您有机会在您的站点上测试演示代码?

    此致、

    Christoph

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

    尊敬的 Christoph:

    我没有 OX05B 摄像头传感器。 现在已经有了。 以便在明天之前验证和更新您的产品。

    对于延迟、我们深表歉意。

    此致、

    Suren

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

    尊敬的 Christoph:

    我能够重现此问题。 我正在与软件团队合作、以便找出问题的根本原因。

    会让您随时了解最新动态。

    此致、

    Suren

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

    感谢您发送编修。

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

    尊敬的 Christoph:  

    我们怀疑应用无法正确关闭流水线。 因此、CMA 内存已耗尽、您将结束出现错误的过程。

    我们还尝试了使用以下脚本、但看不到任何问题。

    #!/bin/bash
    
    x=1
    while true
    do
    gst-launch-1.0 videotestsrc is-live=true do-timestamp=true num-buffers=90 ! video/x-raw, width=1920, height=1080, framerate=30/1, format=NV12 ! v4l2h264enc ! filesink location=test.h264
    echo "Run $x"
    cat /proc/meminfo | grep Cma
    x=$(( $x + 1 ))
    done
    

    看起来、应用程序需要在更改分辨率或切换模式并删除/添加编码器元素时正确处理 EOS。

    此致、

    Suren

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

    您好、Suren、感谢您的测试和帮助。 你有什么建议我可以尝试正确处理 EOS 吗?

    该错误是否也可能是由于您所做的测试未使用 ISP、多标量等、因此我使用的某个 tiovx 插件引起的?

    此致、

    Christoph

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

    尊敬的 Christoph:

    请参阅以下有关处理 EOS 的主题。 在实际应用中、创建焊盘探头并发出 EOS 是相关的。

    https://stackoverflow.com/questions/50417045/gstreamer-change-source-element-dynamically

    此外、还尝试在流水线中取消引用 tiovx 元素、看看这是否有用。

    此致、

    Suren

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

    尊敬的 Christoph:

    另一种方法是从传感器获得两个虚拟通道、一个用于 RGB、另一个用于 IR。 这将在用户空间中创建两个视频节点。 然后、您可以同时从两个视频节点流式传输数据。 例如、下面的 GStreamer 流水线从每个视频节点获取输入并将其发送到编码器。 只需用 RTP 接收器替换"fakesink"即可。 然后在接收端、可以将这2个流组合在一起。

    gst-launch-1.0 -v \
    v4l2src device=/dev/video4 io-mode=dmabuf-import ! \
    video/x-bayer, width=2592, height=1944, framerate=30/1, format=bggi10 ! queue ! \
    tiovxisp sink_0::pool-size=2 sink_0::device=/dev/v4l-subdev2 sensor-name="SENSOR_OX05B1S" \
    dcc-isp-file=/opt/imaging/ox05b1s/linear/dcc_viss.bin sink_0::dcc-2a-file=/opt/imaging/ox05b1s/linear/dcc_2a.bin format-msb=9 ! \
    video/x-raw, format=NV12, width=2592, height=1944 ! queue ! \
    tiovxmultiscaler src_0::pool-size=3 target=1 ! video/x-raw, format=NV12, width=1600, height=1200 ! queue ! v4l2h264enc ! \
    fakesink \
    v4l2src device=/dev/video3 io-mode=dmabuf-import ! \
    video/x-bayer, width=2592, height=1944, framerate=30/1, format=bggi10 ! queue ! \
    tiovxisp sink_0::pool-size=2 sink_0::device=/dev/v4l-subdev2 sensor-name="SENSOR_OX05B1S" \
    dcc-isp-file=/opt/imaging/ox05b1s/linear/dcc_viss.bin sink_0::dcc-2a-file=/opt/imaging/ox05b1s/linear/dcc_2a.bin format-msb=9 ! \
    video/x-raw, format=GRAY8, width=2592, height=1944 ! queue ! \
    tiovxmultiscaler src_0::pool-size=3 target=0 ! video/x-raw, format=GRAY8, width=1600, height=1200 ! \
    videoconvert ! video/x-raw, format=NV12, width=1600, height=1200 ! queue ! v4l2h264enc ! \
    fakesink
    

    此致、

    建中

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

    您好 、建中、感谢您的答复。

    是否还有办法只获得一个 RTP 流输出并动态决定将 IR 或 RGB 数据发送到此流中?

    我们已经尝试使用"input-selector" 、但无法运行它。

    目前、我们唯一的工作方法是停止和联合国近东巴勒斯坦难民救济和工程处目前的管道、然后开始新的管道。

    但是、无论取消引用所有元素、发送 EOS 等、我们都会在一段时间后遇到内存问题

    此内存问题也可能与此 gstreamer 错误有关:

    https://discourse.gstreamer.org/t/memory-leaking-after-restarting-pipelines/607

    我们当前的管道如下所示:

    对于 IR RTP 流(同时以全分辨率接收 IR 和 RGB 图像):

    pipeline_desc =
    "v4l2src device=/dev/video4 io-mode=dmabuf-import! "
    "video/x-bayer、width=2592、height=1944、framerate=30/1、format=bggi10! "
    "队列! tiovxisp sink_0::pool-size=2 sink_0::device=/dev/v4l-subdev2 sensor-name=sensor_OX05B1S"
    "dcc-isp-file=/opt/imaging/ox05b1s/linear/dcc_viss.bin sink_0::dcc-2a-file=/opt/imaging/ox05b1s/linear/dcc_2a.bin format-msb=9 ! "
    "队列! tiovxldc dcc-file=/opt/imaging/ox05b1s/linear/dcc_ldc.bin sensor-name=sensor_OX05B1S! "
    "video/x-raw、format=NV12、width=2592、height=1944! appsink 名称=BGR_SINK DROP=TRUE"
    "v4l2src device=/dev/video3 io-mode=dmabuf-import! "
    "video/x-bayer、width=2592、height=1944、framerate=30/1、format=bggi10! "
    "队列! tiovxisp sink_0::pool-size=2 sensor-name=sensor_OX05B1S"
    "dcc-isp-file=/opt/imaging/ox05b1s/linear/dcc_viss.bin sink_0::dcc-2a-file=/opt/imaging/ox05b1s/linear/dcc_2a.bin format-msb=9 ! "
    "video/x-raw、format=gray8、width=2592、height=1944! TEE NAME=t "
    "T.! 队列! tiovxmultiscaler src_0::pool-size=2 target=1! video/x-raw、格式=GRAY8、宽度=1920、高度=1080! "
    "队列! textoverlay name=overlay! videoconvert name=videoconverter ! v4l2h264enc name=videoencer! RTPH264支付! udpsink host=192.168.1.10 port=5000"
    "T.! appsink name=ir_sink Drop=true";

    对于 RGB RTP 流(同时以全分辨率接收 IR 和 RGB 图像):


    pipeline_desc =
    "v4l2src device=/dev/video4 io-mode=dmabuf-import! "
    "video/x-bayer、width=2592、height=1944、framerate=30/1、format=bggi10! "
    "队列! tiovxisp sink_0::pool-size=2 sink_0::device=/dev/v4l-subdev2 sensor-name=sensor_OX05B1S"
    "dcc-isp-file=/opt/imaging/ox05b1s/linear/dcc_viss.bin sink_0::dcc-2a-file=/opt/imaging/ox05b1s/linear/dcc_2a.bin format-msb=9 ! "
    "队列! tiovxldc dcc-file=/opt/imaging/ox05b1s/linear/dcc_ldc.bin sensor-name=sensor_OX05B1S! "
    "video/x-raw、format=NV12、width=2592、height=1944! TEE NAME=t "
    "T.! 队列! tiovxmultiscaler src_0::pool-size=2 target=1! video/x-raw、格式=NV12、宽度=1920、高度=1080! "
    "队列! textoverlay name=overlay! videoconvert name=videoconverter ! "
    "v4l2h264enc name=videoencer! RTPH264支付! udpsink host=192.168.1.10 port=5000"
    "T.! appsink 名称=BGR_SINK DROP=TRUE"
    "v4l2src device=/dev/video3 io-mode=dmabuf-import! "
    "video/x-bayer、width=2592、height=1944、framerate=30/1、format=bggi10! "
    "队列! tiovxisp sink_0::pool-size=2 sensor-name=sensor_OX05B1S"
    "dcc-isp-file=/opt/imaging/ox05b1s/linear/dcc_viss.bin sink_0::dcc-2a-file=/opt/imaging/ox05b1s/linear/dcc_2a.bin format-msb=9 ! "
    "video/x-raw、format=gray8、width=2592、height=1944! appsink name=ir_sink Drop=true";

    我们希望能够在不终止旧流水线和重新启动另一条流水线的情况下动态地在两者之间切换。

    此致、

    Christoph

     

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

    您好、Christoph:

    感谢您的分享。  我很好奇、但为什么您即使只编码和发送一个流、也同时运行 RGB 和 IR 流?

    此致、

    建中

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

    尊敬的建中:

    我们只同时运行一条管道。

    我们的要求是通过 RTP 发送视频(IR 或 RGB)、同时以全分辨率接收 IR 和 RGB 图像帧、从而同时将其发送到我们的神经网络。

    目前、我们在 IR 和 RGB 之间切换的方法如下:

    当请求 RGB-RTP 流时、我们启动第一个流水线(IR IR 流(同时以全分辨率接收 IR 和 RGB 图像)。

    当 RGB-RTP 流在另一个时间点被请求时,我们停止当前运行的 IR RTP 管道,将 EOS 发送给它,将管道放入 GST_STATE_NULL, UNREF 所有元素,然后 UNREF 管道本身。

    完成此操作后、我们启动 另一个流水线 (RGB RTP 流(同时以全分辨率接收 IR 和 RGB 图像)。

    然后、如果再次请求 IR、我们会终止当前的 RGB 流水线、然后再次启动 IR 流水线。

    遗憾的是、此方法会在一段时间后占用 CMA 内存、如上所述。

    我们想知道是否有另一种在 IR 和 RGB 之间动态切换的方法、这种方法不需要终止当前流水线并重建新流水线。

    此致、

    Christoph

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

    尊敬的 Christoph:

    您可以尝试通过以下方式动态修改流水线(而不实际将其暂停):向流水线中的队列元素添加焊盘探头、并在焊盘探头回调中修改下游元素。 这可以使流水线保持正常运行、如果未使用该路径、则可以将下游元素替换为 fakesink。

    演示机制的测试程序(videotestsrc -> tee -> 3个路径、使用控制台上的命令打开不同路径上的处理/显示)

    #include <gst/gst.h>
    #include <stdbool.h>
    #include <glib.h>
    #include <glib/gprintf.h>
    #include <gio/gio.h>
    #include <stdbool.h>
    
    static GstPad *blockpad1, *blockpad2, *blockpad3;
    static GstElement *pipeline;
    static GstElement *q_stream1, *q_stream2, *q_stream3;
    GQueue sink[3] = { G_QUEUE_INIT, G_QUEUE_INIT, G_QUEUE_INIT };
    
    static GstPadProbeReturn pad_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
    {
            GstPad *srcpad, *sinkpad;
            GstElement * parent = gst_pad_get_parent_element(pad), *element;
            char name[11];
            int stream = -1;
            gboolean fake = false;
    
            GST_DEBUG_OBJECT(pad, "pad is blocked now");
    
            if (g_ascii_strncasecmp(gst_object_get_name(GST_OBJECT(parent)), "queue-stream-1", 14) == 0) {
                    stream = 0;
            }
            if (g_ascii_strncasecmp(gst_object_get_name(GST_OBJECT(parent)), "queue-stream-2", 14) == 0) {
                    stream = 1;
            }
            if (g_ascii_strncasecmp(gst_object_get_name(GST_OBJECT(parent)), "queue-stream-3", 14) == 0) {
                    stream = 2;
            }
    
            if (g_ascii_strncasecmp(gst_object_get_name(GST_OBJECT(g_queue_peek_head(&sink[stream]))), "fakesink", 8) == 0) {
                    fake = true;
            }
    
    
            /* empty the queue of elements currently connected */
            while (!g_queue_is_empty(&sink[stream])) {
                    element = g_queue_pop_head(&sink[stream]);
                    gst_element_set_state(element, GST_STATE_NULL);
    
                    GST_DEBUG_OBJECT(pipeline, "removing %" GST_PTR_FORMAT, element);
                    gst_bin_remove(GST_BIN(pipeline), element);
            }
    
            if (fake) {
                    GstElement *overlay, *new_sink;
                    char text[9];
                    sprintf(name, "overlay%d", stream + 1);
                    overlay = gst_element_factory_make("textoverlay", name);
                    g_object_set(overlay, "halignment", 0, NULL);
                    sprintf(text, "Camera %d", stream + 1);
                    g_object_set(overlay, "text", text, NULL);
    
                    sprintf(name, "videosink%d", stream + 1);
                    new_sink = gst_element_factory_make("xvimagesink", name);
    
                    GST_DEBUG_OBJECT(pipeline, "adding %" GST_PTR_FORMAT "%" GST_PTR_FORMAT, overlay, new_sink);
                    gst_bin_add_many(GST_BIN(pipeline), overlay, new_sink, NULL);
    
                    GST_DEBUG_OBJECT(pipeline, "linking...");
                    gst_element_link_many(parent, overlay, new_sink, NULL);
    
                    gst_element_set_state(overlay, GST_STATE_PLAYING);
                    gst_element_set_state(new_sink, GST_STATE_PLAYING);
                    g_queue_push_tail(&sink[stream], overlay);
                    g_queue_push_tail(&sink[stream], new_sink);
            } else {
                    GstElement *new_sink;
                    sprintf(name, "fakesink%d", stream + 1);
                    new_sink = gst_element_factory_make("fakesink", name);
    
                    GST_DEBUG_OBJECT(pipeline, "adding %" GST_PTR_FORMAT, new_sink);
                    gst_bin_add(GST_BIN(pipeline), new_sink);
    
                    GST_DEBUG_OBJECT(pipeline, "linking...");
                    gst_element_link_many(parent, new_sink, NULL);
    
                    gst_element_set_state(new_sink, GST_STATE_PLAYING);
                    g_queue_push_tail(&sink[stream], new_sink);
            }
    
            GST_DEBUG_OBJECT(pipeline, "done.");
            gst_object_unref(parent);
    
            return GST_PAD_PROBE_REMOVE;
    }
    
    static gboolean cli_cb(GIOChannel *iochannel, GIOCondition cond, gpointer data)
    {
            GMainLoop __attribute__((unused)) *loop = data;
            GError *error = NULL;
            gsize length;
            gsize terminator_pos;
            gchar *str_return;
    
            if (g_io_channel_read_line(iochannel, &str_return, &length, &terminator_pos, &error) == G_IO_STATUS_ERROR) {
                    g_warning("Unable to read from stdin!\n");
            }
    
            if (NULL != error) {
                    g_error("%s\n", error->message);
            }
    
            if (g_ascii_strncasecmp(str_return, "quit", 4) == 0) {
                    g_main_loop_quit(loop);
            }
            if (g_ascii_strncasecmp(str_return, "1", 1) == 0) {
                    gst_pad_add_probe(blockpad1, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, pad_probe_cb, data, NULL);
            }
            if (g_ascii_strncasecmp(str_return, "2", 1) == 0) {
                    gst_pad_add_probe(blockpad2, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, pad_probe_cb, data, NULL);
            }
            if (g_ascii_strncasecmp(str_return, "3", 1) == 0) {
                    gst_pad_add_probe(blockpad3, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, pad_probe_cb, data, NULL);
            }
    
            g_printf("> ");
            return TRUE;
    }
    
    static gboolean bus_cb(GstBus *bus, GstMessage *msg, gpointer user_data)
    {
            GMainLoop *loop = user_data;
    
            switch (GST_MESSAGE_TYPE(msg)) {
            case GST_MESSAGE_ERROR:
                    {
                    GError *err = NULL;
                    gchar *dbg;
    
                    gst_message_parse_error(msg, &err, &dbg);
                    gst_object_default_error(msg->src, err, dbg);
                    g_clear_error(&err);
                    g_free(dbg);
                    g_main_loop_quit(loop);
                    break;
                    }
            default:
                    break;
            }
    }
    
    int main(int argc, char **argv)
    {
            GMainLoop *loop;
            GstElement *src, *filter, *q1, *tee, *sink1, *sink2, *sink3;
            GstBus *bus;
            GIOChannel *iochannel;
            GError *error = NULL;
            guint source;
    
            gst_init(&argc, &argv);
    
            pipeline = gst_pipeline_new("pipeline");
    
            src = gst_element_factory_make("videotestsrc", NULL);
            g_object_set(src, "is-live", TRUE, NULL);
    
            filter = gst_element_factory_make("capsfilter", NULL);
            gst_util_set_object_arg(G_OBJECT(filter), "caps",
                            "video/x-raw, width=320, height=240, framerate=30/1, format=NV12");
    
            q1 = gst_element_factory_make("queue", NULL);
    
            tee = gst_element_factory_make("tee", "tee");
    
            q_stream1 = gst_element_factory_make("queue", "queue-stream-1");
            blockpad1 = gst_element_get_static_pad(q_stream1, "src");
            q_stream2 = gst_element_factory_make("queue", "queue-stream-2");
            blockpad2 = gst_element_get_static_pad(q_stream2, "src");
            q_stream3 = gst_element_factory_make("queue", "queue-stream-3");
            blockpad3 = gst_element_get_static_pad(q_stream3, "src");
    
            sink1 = gst_element_factory_make("fakesink", "fakesink1");
            if (sink1)
                    g_queue_push_tail(&sink[0], sink1);
            sink2 = gst_element_factory_make("fakesink", "fakesink2");
            if (sink2)
                    g_queue_push_tail(&sink[1], sink2);
            sink3 = gst_element_factory_make("fakesink", "fakesink3");
            if (sink3)
                    g_queue_push_tail(&sink[2], sink3);
    
            gst_bin_add_many(GST_BIN(pipeline), src, filter, q1, tee, q_stream1, sink1, q_stream2, sink2, q_stream3, sink3, NULL);
    
            if (!gst_element_link_many(src, filter, tee, NULL) ||
                !gst_element_link_many(tee, q_stream1, sink1, NULL) ||
                !gst_element_link_many(tee, q_stream2, sink2, NULL) ||
                !gst_element_link_many(tee, q_stream3, sink3, NULL)) {
                    g_error("Failed to link elements");
                    return -2;
            }
    
            if (gst_element_set_state(pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
                    g_error("Error starting pipeline");
                    return 1;
            }
    
            loop = g_main_loop_new(NULL, FALSE);
            gst_bus_add_watch(GST_ELEMENT_BUS(pipeline), bus_cb, loop);
    
            iochannel = g_io_channel_unix_new(STDIN_FILENO);
            g_io_channel_set_encoding(iochannel, NULL, &error);
            source = g_io_add_watch(iochannel, G_IO_IN, cli_cb, loop);
            g_print("> ");
    
            g_main_loop_run(loop);
            gst_element_set_state(pipeline, GST_STATE_NULL);
            g_source_remove(source);
            g_io_channel_unref(iochannel);
            gst_object_unref(blockpad1);
            gst_object_unref(blockpad2);
            gst_object_unref(blockpad3);
            gst_bus_remove_watch(GST_ELEMENT_BUS(pipeline));
            gst_object_unref(pipeline);
            g_main_loop_unref(loop);
    
            return 0;
    }

    我希望这对您有所帮助。

    此致、

    Bas Vermeulen