[gst-devel] Leaking buffers
Will Newton
will.newton at gmail.com
Wed May 30 17:45:02 CEST 2007
Hi all,
I have an app that streams audio using the neon source plugin, the
icydemux plugin and a fakesink. Occasionally the source plugin will
throw an error when the http connection resets. I try to handle this
by dismantling and rebuilding the pipeline. Unfortunately it seems
that the way I do this is leaking buffers.
I diagnosed this by running under valgrind massif and the space used
by gst_buffer_new_and_alloc takes a little uptick every time the
stream resets.
I have attached the app I am using. Could anyone help me find where
these buffers should be getting unreffed but presumably aren't?
Thanks,
-------------- next part --------------
#include <stdlib.h>
#include <glib.h>
#include <gst/gst.h>
typedef struct stream {
char *name;
char *url;
} stream_t;
/* I think we can get the station name out of the metadata of the stream
* by doing a get_property on the http src plugin but by then it's too late
* to be useful.
*/
stream_t streams[] = {
{ "Smooth Jazz", "http://82.197.167.134:80" },
{ "Swiss Classical", "http://82.197.167.137:80" },
{ "RadioCrazy Jazz", "http://82.197.165.138:80" },
{ "Smooth Jazz", "http://82.197.167.134:80" },
/* { "HotMixRadio", "http://91.121.6.37:80" }, */
{ NULL, NULL },
};
static int current_stream = 0;
static GstElement *http_src;
static GstElement *icydemux_filter;
static GstElement *fake_sink;
static GstElement *pipeline;
static GMainLoop *loop;
static GstBus *bus;
static void next_stream(void);
static gboolean
bus_call (GstBus *bus,
GstMessage *msg,
gpointer data)
{
GMainLoop *loop = (GMainLoop *)data;
switch (GST_MESSAGE_TYPE(msg)) {
case GST_MESSAGE_TAG: {
GstTagList *tag_list;
gchar *title;
gst_message_parse_tag(msg, &tag_list);
if (gst_tag_list_get_string (tag_list, GST_TAG_TITLE, &title)) {
g_print("Title: %s\n", title);
g_free(title);
}
gst_tag_list_free(tag_list);
break;
}
case GST_MESSAGE_EOS:
g_print("End-of-stream\n");
next_stream();
break;
case GST_MESSAGE_ERROR: {
gchar *debug;
GError *err;
gst_message_parse_error(msg, &err, &debug);
g_print("Error: %s (%s)\n", err->message, debug);
g_error_free(err);
g_free(debug);
if (msg->src == (GstObject *)http_src)
next_stream();
else
g_main_loop_quit(loop);
break;
}
default:
break;
}
return TRUE;
}
static void
new_pad (GstElement *element,
GstPad *pad,
gpointer data)
{
GstPad *sinkpad;
/* We can now link this pad with the audio decoder */
g_print("Dynamic pad created, linking icydemux to sink\n");
sinkpad = gst_element_get_pad(fake_sink, "sink");
gst_pad_link(pad, sinkpad);
gst_object_unref(sinkpad);
}
static void
init_http_src(void)
{
g_object_set(G_OBJECT(http_src), "location",
streams[current_stream].url, NULL);
g_object_set(G_OBJECT(http_src), "user-agent",
"Metagence-Zappa/1.0", NULL);
g_object_set(G_OBJECT(http_src), "iradio-mode", TRUE, NULL);
}
static void
print_stream_name(void)
{
g_print("Playing stream \"%s\".\n", streams[current_stream].name);
}
static void
shutdown_stream(void)
{
//gst_debug_set_default_threshold(GST_LEVEL_DEBUG);
g_print("Stopping stream\n");
g_assert(gst_element_set_state(pipeline, GST_STATE_NULL) == 1);
//gst_debug_set_default_threshold(GST_LEVEL_DEFAULT);
g_print("Unlinking elements\n");
gst_element_unlink(http_src, icydemux_filter);
gst_element_unlink(icydemux_filter, fake_sink);
g_print("Destroying icydemux\n");
/* This will unref and delete the object */
g_assert(gst_bin_remove(GST_BIN(pipeline), icydemux_filter));
g_print("Destroying http source\n");
/* This will unref and delete the object */
g_assert(gst_bin_remove(GST_BIN(pipeline), http_src));
}
static void
start_stream(void)
{
g_print("Creating new http source\n");
http_src = gst_element_factory_make("neonhttpsrc", "neonhttpsrc");
g_assert(http_src);
gst_bin_add(GST_BIN(pipeline), http_src);
g_print("Creating new icydemux\n");
icydemux_filter = gst_element_factory_make("icydemux", "icydemux");
g_assert(icydemux_filter);
gst_bin_add(GST_BIN(pipeline), icydemux_filter);
g_print("Initting http source\n");
init_http_src();
g_assert(gst_element_link(http_src, icydemux_filter));
gst_element_link(http_src, icydemux_filter);
g_signal_connect(icydemux_filter, "pad-added", G_CALLBACK(new_pad), NULL);
g_print("Setting pipeline to playing\n");
gst_element_set_state(pipeline, GST_STATE_PLAYING);
print_stream_name();
}
static void
next_stream(void)
{
int new_stream = current_stream;
if (streams[new_stream].url == NULL)
new_stream = 0;
current_stream = new_stream;
shutdown_stream();
start_stream();
}
int main(void)
{
g_print("Initting gstreamer\n");
gst_init(NULL, NULL);
loop = g_main_loop_new(NULL, FALSE);
g_print("Creating pipeline elements\n");
pipeline = gst_pipeline_new("pipeline");
fake_sink = gst_element_factory_make("fakesink", "fakesink");
g_assert(fake_sink);
bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
gst_bus_add_watch(bus, bus_call, loop);
gst_object_unref(bus);
gst_bin_add(GST_BIN(pipeline), fake_sink);
start_stream();
g_main_loop_run(loop);
g_print("Returned, stopping playback\n");
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(GST_OBJECT(pipeline));
return 0;
}
More information about the gstreamer-devel
mailing list