deadlock when stop gstreamer
Shuke
shuke987 at qq.com
Thu Jan 17 09:49:16 UTC 2019
We call gst_alloc to start a gstreamer, which will create another thread to
do the main loop. And before EOF was retrieved, we'll call gst_destructor to
tell main loop to quit, which will call gst_element_set_state, which cause
deadlock with pipeline thread.
Deadlock is not always occurs, it occurs once in thousands.
Thanks a lot.
Source code is pasted below.
struct ausrc_st {
const struct ausrc *as; /**< Inheritance */
pthread_t tid; /**< Thread ID */
bool run; /**< Running flag */
...
/* Gstreamer */
char *uri;
GstElement *pipeline, *bin, *source, *capsfilt, *sink;
GMainLoop *loop;
};
static void *thread(void *arg)
{
struct ausrc_st *st = arg;
gst_element_set_state(st->pipeline, GST_STATE_PLAYING);
while (st->run) {
g_main_loop_run(st->loop);
}
//deadlock will happen in this line
gst_element_set_state(st->pipeline, GST_STATE_NULL);
return NULL;
}
static gboolean bus_watch_handler(GstBus *bus, GstMessage *msg, gpointer
data)
{
struct ausrc_st *st = data;
GMainLoop *loop = st->loop;
(void)bus;
switch (GST_MESSAGE_TYPE(msg)) {
case GST_MESSAGE_EOS:
break;
case GST_MESSAGE_ERROR:
st->run = false;
g_main_loop_quit(loop);
break;
default:
break;
}
return TRUE;
}
static void handoff_handler(GstFakeSink *fakesink, GstBuffer *buffer,
GstPad *pad, gpointer user_data)
{
struct ausrc_st *st = user_data;
(void)fakesink;
(void)pad;
// ... get data from buffer and sleep.
}
/**
* Set up the Gstreamer pipeline. The playbin element is used to decode
* all kinds of different formats. The capsfilter is used to deliver the
* audio in a fixed format (X Hz, 1-2 channels, 16 bit signed)
*
* The pipeline looks like this:
*
* <pre>
* .--------------. .------------------------------------------.
* | playbin | |mybin .------------. .------------. |
* |----. .----| |-----. | capsfilter | | fakesink | |
* |sink| |src |--->|ghost| |----. .---| |----. .---| |
handoff
* |----' '----| |pad |-->|sink| |src|-->|sink| |src|--+-->
handler
* | | |-----' '------------' '------------' |
* '--------------' '------------------------------------------'
* </pre>
*
* @param st Audio source state
*
* @return 0 if success, otherwise errorcode
*/
static int gst_setup(struct ausrc_st *st)
{
GstBus *bus;
GstPad *pad;
st->loop = g_main_loop_new(NULL, FALSE);
st->pipeline = gst_pipeline_new("pipeline");
if (!st->pipeline) {
warning("gst: failed to create pipeline element\n");
return ENOMEM;
}
/********************* Player BIN **************************/
st->source = gst_element_factory_make("playbin", "source");
if (!st->source) {
warning("gst: failed to create playbin source element\n");
return ENOMEM;
}
/********************* My BIN **************************/
st->bin = gst_bin_new("mybin");
st->capsfilt = gst_element_factory_make("capsfilter", NULL);
if (!st->capsfilt) {
warning("gst: failed to create capsfilter element\n");
return ENOMEM;
}
set_caps(st);
st->sink = gst_element_factory_make("fakesink", "sink");
if (!st->sink) {
warning("gst: failed to create sink element\n");
return ENOMEM;
}
gst_bin_add_many(GST_BIN(st->bin), st->capsfilt, st->sink, NULL);
gst_element_link_many(st->capsfilt, st->sink, NULL);
/* add ghostpad */
pad = gst_element_get_pad(st->capsfilt, "sink");
gst_element_add_pad(st->bin, gst_ghost_pad_new("sink", pad));
gst_object_unref(GST_OBJECT(pad));
/* put all elements in a bin */
gst_bin_add_many(GST_BIN(st->pipeline), st->source, NULL);
/* Override audio-sink handoff handler */
g_object_set(G_OBJECT(st->sink), "signal-handoffs", TRUE, NULL);
g_signal_connect(st->sink, "handoff", G_CALLBACK(handoff_handler), st);
g_object_set(G_OBJECT(st->source), "audio-sink", st->bin, NULL);
/********************* Misc **************************/
/* Bus watch */
bus = gst_pipeline_get_bus(GST_PIPELINE(st->pipeline));
gst_bus_add_watch(bus, bus_watch_handler, st);
gst_object_unref(bus);
/* Set URI */
g_object_set(G_OBJECT(st->source), "uri", st->uri, NULL);
return 0;
}
static void gst_destructor(void *arg)
{
struct ausrc_st *st = arg;
int err = 0;
if (st->run) {
st->run = false;
g_main_loop_quit(st->loop);
err = pthread_join(st->tid, NULL);
}
//deadlock will happen in this line
gst_element_set_state(st->pipeline, GST_STATE_NULL);
gst_object_unref(GST_OBJECT(st->pipeline));
mem_deref(st->call_id);
mem_deref(st->uri);
mem_deref(st->aubuf);
}
static int gst_alloc(struct ausrc_st **stp, const struct ausrc *as,
struct media_ctx **ctx,
struct ausrc_prm *prm, const char *device, const char
*call_id,
ausrc_read_h *rh, ausrc_error_h *errh, void *arg)
{
struct ausrc_st *st;
int err;
(void)ctx;
err = gst_setup(st);
if (err)
goto out;
st->run = true;
err = pthread_create(&st->tid, NULL, thread, st);
if (err) {
st->run = false;
goto out;
}
out:
if (err)
mem_deref(st);
else
*stp = st;
return err;
}
--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/
More information about the gstreamer-devel
mailing list