gstreamer

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


I am trying to use appsrc element of Gstreamer on a trivial example. I am creating a buffer, filling it with dummy data and trying to send it to a fakesink. The code is a watered down version of the tutorial given in link below. It only has two elements, appsrc and fakesink. My code is also given below.

When I run this code I get "Error: Internal data stream error." I have searched for a solution and as far as I can tell, the issue is attributed to mismatch of caps between elements. I don't think this is the issue here since I only have two elements.

I have tried setting "caps" property of appsrc to NULL here, but I have also tried passing the proper "caps" property which was "audio/G729." Both have failed. Also it seems like the appsrc is fine for the first 4 chunks but then it generates an error. It is always after 4 Chunks. Not sure if that is a clue.

Also, I am running the code on an embedded system (ARM Cortex-A15) but I don't think that is related. I can succesfully stream a G729 encoded Audio file on this system via following command:

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

What could be the reason behind this error? How can I fix this?

Thanks for all the responses.

Link: Link to Tutorial

Code:

#include <gst/gst.h>
#include <glib.h>
#include "glibconfig.h"
#include <stdio.h>
#include <string.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);
}

The output from this code is generated as:

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.

Edit: After more trials I have realized that the error is not generated after 4 Chunks consistently. When I reboot the system and call the function the error is generated after 156 Chunks for instance. After a couple more tries, the error starts occur much sooner (like 4 Chunks.) Also I have tried running the code with GST_DEBUG=2 but could not really find anything useful. Below you can find the DEBUG output. 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.

Edit 2: After further debugging I have realized that the fakesink element was not linked to appsrc. So I manually linked them via the following line

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

I think it works fine now, I will come back again after I verify it completely.

Edit 3: Yeah, I can confirm that was the issue. I forgot to link the elements.


Solution

  • I forgot to link the elements. The following line solves the issue.

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