如何修复 Gstreamer appsrc 元素生成的 "Internal data stream error"?

How can I fix "Internal data stream error" generated by the Gstreamer appsrc element?

我正在尝试在一个简单的示例中使用 Gstreamer 的 appsrc 元素。我正在创建一个缓冲区,用虚拟数据填充它并试图将它发送到一个 fakesink。该代码是下面 link 中给出的教程的简化版本。它只有两个元素,appsrc 和 fakesink。我的代码也在下面给出。

当我 运行 此代码时,我收到“错误:内部数据流错误”。我已经搜索了一个解决方案,据我所知,这个问题归因于元素之间的上限不匹配。我认为这不是这里的问题,因为我只有两个元素。

我已经尝试将 appsrc 的“caps”属性 设置为 NULL,但我也尝试传递正确的“caps”属性,即“audio/G729”。两者都失败了。此外,appsrc 对于前 4 个块似乎没问题,但随后会生成错误。它总是在 4 个块之后。不确定这是否是一个线索。

另外,我 运行 在嵌入式系统 (ARM Cortex-A15) 上编写代码,但我认为这不相关。我可以通过以下命令在此系统上成功流式传输 G729 编码的音频文件:

gst-launch-1.0 -v filesrc location=encodedData.g729 ! 'audio/G729' ! rtpg729pay ! udpsink host=192.168.XX.XX auto-multicast=true port=5004

此错误背后的原因可能是什么?我该如何解决这个问题?

感谢大家的回复。

Link: Link to Tutorial

代码:

#include <gst/gst.h>
#include <glib.h>
#include "glibconfig.h"
#include <stdio.h>

#define     CHUNK_SIZE          10

typedef struct gstreamstruct {
    GstElement  *pipeline, *app_source, *fakesink;
    guint       sourceid;        /* To control the GSource */
    GMainLoop   *main_loop;  /* GLib's Main Loop */
    guint       sample;
} gstreamstruct;

static gboolean busCall (GstBus *bus, GstMessage *msg, gpointer data)
{
    GMainLoop *loop = (GMainLoop *) data;

    switch (GST_MESSAGE_TYPE (msg)) {

    case GST_MESSAGE_EOS:
        g_print ("End of stream\n");
        g_main_loop_quit (loop);
        break;

    case GST_MESSAGE_ERROR: {
        gchar  *debug;
        GError *error;

        gst_message_parse_error (msg, &error, &debug);
        g_free (debug);

        g_printerr ("Error: %s\n", error->message);
        g_error_free (error);

        g_main_loop_quit (loop);
        break;
    }
    default:
        break;
    }

    return TRUE;
}

static gboolean pushData (gstreamstruct *streamer)
{
    printf("--->PushData!\n");
    GstMapInfo map;
    GstBuffer *buffer;
    GstFlowReturn ret;
    guint8 *raw;
    int i;

    /* Create a new empty buffer */
    buffer = gst_buffer_new_and_alloc (CHUNK_SIZE);

    /* Set its timestamp and duration */
    GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (streamer->sample, GST_SECOND, 1000);
    GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale (CHUNK_SIZE, GST_SECOND, 1000);

   //Put some dummy into buffer
    gst_buffer_map (buffer, &map, GST_MAP_WRITE);
    raw = (guint8 *)map.data;
    for(i = 0; i<CHUNK_SIZE; i++)
    {
        raw[0] = 0;
    }

    //update sample value
    streamer->sample += CHUNK_SIZE;
    printf("currentDuration: %d ms\n", streamer->sample);
    gst_buffer_unmap (buffer, &map);

    /* Push the buffer into the appsrc */
    g_signal_emit_by_name (streamer->app_source, "push-buffer", buffer, &ret);

    /* Free the buffer now that we are done with it */
    gst_buffer_unref (buffer);

    if (ret != GST_FLOW_OK)
    {
    /* We got some error, stop sending data */
        printf("Data sending Failed!\n");
        return FALSE;
    }

    return TRUE;
}

/* This signal callback triggers when appsrc needs data.
 * Here, we add an idle handler to the mainloop to start pushing data into the appsrc
 *
 * Whenever Gstreamer goes idle, it will call this function. Maybe we can utilize this for
 * G729 etc!
 *
 * */
static void startFeed (GstElement *source, guint size, gstreamstruct *streamer)
{
    if (streamer->sourceid == 0)
    {
        g_print ("Start feeding\n");
        streamer->sourceid = g_idle_add ((GSourceFunc) pushData, streamer);
    }
}

/* This callback triggers when appsrc has enough data and we can stop sending.
 * We remove the idle handler from the mainloop */
static void stopFeed (GstElement *source, gstreamstruct *streamer)
{
    if (streamer->sourceid != 0)
    {
        g_print ("Stop feeding\n");
        g_source_remove (streamer->sourceid);
        streamer->sourceid = 0;
    }
}

void appSrcTest (void* args)
{
    printf("---> appSrcTest\n");
    gstreamstruct my_streamer;
    GstCaps *caps;
    GstBus *bus;
    //GstPad *pad;
    guint bus_watch_id;

    memset (&my_streamer, 0, sizeof (gstreamstruct));

    gst_init (NULL, NULL);
    my_streamer.main_loop = g_main_loop_new (NULL, FALSE);

    printf("Gst Initialized!\n");
    my_streamer.sample = 0;

    my_streamer.app_source  = gst_element_factory_make("appsrc", "appSrc");
    my_streamer.fakesink     = gst_element_factory_make("fakesink", "fakeSink");

    my_streamer.pipeline = gst_pipeline_new ("g729-pipeline");

    if(!my_streamer.app_source || !my_streamer.fakesink || !my_streamer.pipeline)
    {
        g_printerr ("Not all elements could be created.\n");
        return;
    }
    printf("Elements Created!\n");
    caps=NULL;
    /*
    caps = gst_caps_new_simple ("audio/G729",
                            "channels", G_TYPE_INT, 1,
                            "rate", G_TYPE_INT, 8000,
                            NULL);
    */
    //g_object_set (G_OBJECT(my_streamer.app_source), "caps", caps, "format", GST_FORMAT_TIME,     NULL);
    g_signal_connect (my_streamer.app_source, "need-data", G_CALLBACK (startFeed), &my_streamer);
    g_signal_connect (my_streamer.app_source, "enough-data", G_CALLBACK (stopFeed), &my_streamer);

    printf("Properties Set!\n");

    /* we add a message handler */
    bus = gst_pipeline_get_bus (GST_PIPELINE (my_streamer.pipeline));
    bus_watch_id = gst_bus_add_watch (bus, busCall, my_streamer.main_loop);
    gst_object_unref (bus);

    gst_bin_add_many (GST_BIN (my_streamer.pipeline), my_streamer.app_source,     my_streamer.fakesink, NULL);
    printf("Elements Added!\n");


    printf("Pipeline Starting!\n");
    gst_element_set_state (my_streamer.pipeline, GST_STATE_PLAYING);

    g_main_loop_run (my_streamer.main_loop);

    gst_element_set_state (my_streamer.pipeline, GST_STATE_NULL);
    gst_object_unref (my_streamer.pipeline);
    g_source_remove (bus_watch_id);
    g_main_loop_unref (my_streamer.main_loop);
}

此代码的输出生成为:

Gst Initialized!
Elements Created!
Properties Set!
Elements Added!
Pipeline Starting!
Start feeding
--->PushData!
currentDuration: 10 ms
--->PushData!
currentDuration: 20 ms
--->PushData!
currentDuration: 30 ms
--->PushData!
currentDuration: 40 ms
Error: Internal data stream error.

编辑:经过更多试验后,我意识到在 4 个块后不会始终生成错误。例如,当我重新启动系统并调用该函数时,错误是在 156 个块之后生成的。再试几次后,错误开始得更快(比如 4 个块。)我也尝试 运行 将代码与 GST_DEBUG=2 结合,但找不到任何有用的东西。您可以在下方找到 DEBUG 输出。 调试:

---> appSrcTest
Gst Initialized!
Elements Created!
Properties Set!
Elements Added!
Pipeline Starting!
Start feeding
--->PushData!
currentDuration: 10 ms
--->PushData!
currentDuration: 20 ms
--->PushData!
currentDuration: 30 ms
--->PushData!
currentDuration: 40 ms
--->PushData!
0:00:00.084280528  1344   0x18fa00 WARN                 basesrc gstbasesrc.c:3055:gst_base_src_loop:<appSrc> error: Internal data stream error.
currentDuration: 50 ms
--->PushData!
0:00:00.084342504  1344   0x18fa00 WARN                 basesrc gstbasesrc.c:3055:gst_base_src_loop:<appSrc> error: streaming stopped, reason not-linked (-1)
currentDuration: 60 ms
--->PushData!
currentDuration: 70 ms
Error: Internal data stream error.

编辑 2:进一步调试后,我意识到 fakesink 元素没有linked 到 appsrc。所以我手动 link 通过以下行

编辑它们
gst_element_link_pads (my_streamer.app_source, "src", my_streamer.fakesink, "sink");

我觉得现在还可以,等我完全验证后再回来

编辑 3:是的,我可以确认这是问题所在。我忘了 link 元素。

我忘记了 link 元素。下面一行解决了这个问题。

gst_element_link_pads (my_streamer.app_source, "src", my_streamer.fakesink, "sink");