From 467c454d7575fd3ea2c31cbc1180092620b00663 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 12 Jul 2004 09:11:41 +0000 Subject: [PATCH] gst/playback/: More fixes on reusing of the element. Original commit message from CVS: * gst/playback/gstdecodebin.c: (gst_decode_bin_get_type), (gst_decode_bin_class_init), (gst_decode_bin_factory_filter), (compare_ranks), (print_feature), (gst_decode_bin_init), (gst_decode_bin_dispose), (find_compatibles), (close_pad_link), (try_to_link_1), (new_pad), (close_link), (type_found), (gst_decode_bin_set_property), (gst_decode_bin_get_property), (gst_decode_bin_change_state), (plugin_init): * gst/playback/gstplaybasebin.c: (gst_play_base_bin_get_type), (gst_play_base_bin_class_init), (gst_play_base_bin_init), (gst_play_base_bin_dispose), (queue_overrun), (gen_preroll_element), (remove_prerolls), (no_more_pads), (new_stream), (setup_source), (gst_play_base_bin_set_property), (gst_play_base_bin_get_property), (play_base_eos), (gst_play_base_bin_change_state), (gst_play_base_bin_add_element), (gst_play_base_bin_remove_element), (gst_play_base_bin_mute_stream), (gst_play_base_bin_link_stream), (gst_play_base_bin_unlink_stream), (gst_play_base_bin_get_streaminfo): * gst/playback/gstplaybasebin.h: * gst/playback/gstplaybin.c: (gst_play_bin_get_type), (gst_play_bin_class_init), (gst_play_bin_init), (gst_play_bin_dispose), (gst_play_bin_set_property), (gst_play_bin_get_property), (gen_video_element), (gen_audio_element), (remove_sinks), (setup_sinks), (gst_play_bin_change_state), (gst_play_bin_get_event_masks), (gst_play_bin_send_event), (gst_play_bin_get_formats), (gst_play_bin_convert), (gst_play_bin_get_query_types), (gst_play_bin_query), (plugin_init): * gst/playback/test4.c: (main): More fixes on reusing of the element. --- ChangeLog | 66 +++++++++++++++++++++ gst/playback/gstdecodebin.c | 42 +++++++++---- gst/playback/gstplaybasebin.c | 135 +++++++++++++++++++++++++++++++----------- gst/playback/gstplaybasebin.h | 3 + gst/playback/gstplaybin.c | 34 ++++++++++- gst/playback/test4.c | 5 ++ 6 files changed, 239 insertions(+), 46 deletions(-) diff --git a/ChangeLog b/ChangeLog index c2c9ff3..7a2ab4e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,36 @@ +2004-07-12 Wim Taymans + + * gst/playback/gstdecodebin.c: (gst_decode_bin_get_type), + (gst_decode_bin_class_init), (gst_decode_bin_factory_filter), + (compare_ranks), (print_feature), (gst_decode_bin_init), + (gst_decode_bin_dispose), (find_compatibles), (close_pad_link), + (try_to_link_1), (new_pad), (close_link), (type_found), + (gst_decode_bin_set_property), (gst_decode_bin_get_property), + (gst_decode_bin_change_state), (plugin_init): + * gst/playback/gstplaybasebin.c: (gst_play_base_bin_get_type), + (gst_play_base_bin_class_init), (gst_play_base_bin_init), + (gst_play_base_bin_dispose), (queue_overrun), + (gen_preroll_element), (remove_prerolls), (no_more_pads), + (new_stream), (setup_source), (gst_play_base_bin_set_property), + (gst_play_base_bin_get_property), (play_base_eos), + (gst_play_base_bin_change_state), (gst_play_base_bin_add_element), + (gst_play_base_bin_remove_element), + (gst_play_base_bin_mute_stream), (gst_play_base_bin_link_stream), + (gst_play_base_bin_unlink_stream), + (gst_play_base_bin_get_streaminfo): + * gst/playback/gstplaybasebin.h: + * gst/playback/gstplaybin.c: (gst_play_bin_get_type), + (gst_play_bin_class_init), (gst_play_bin_init), + (gst_play_bin_dispose), (gst_play_bin_set_property), + (gst_play_bin_get_property), (gen_video_element), + (gen_audio_element), (remove_sinks), (setup_sinks), + (gst_play_bin_change_state), (gst_play_bin_get_event_masks), + (gst_play_bin_send_event), (gst_play_bin_get_formats), + (gst_play_bin_convert), (gst_play_bin_get_query_types), + (gst_play_bin_query), (plugin_init): + * gst/playback/test4.c: (main): + More fixes on reusing of the element. + 2004-07-11 Benjamin Otte * ext/mad/gstmad.c: (normal_seek): @@ -15,6 +48,39 @@ 2004-07-09 Wim Taymans + * gst/playback/gstdecodebin.c: (gst_decode_bin_get_type), + (gst_decode_bin_class_init), (gst_decode_bin_factory_filter), + (compare_ranks), (print_feature), (gst_decode_bin_init), + (gst_decode_bin_dispose), (find_compatibles), (close_pad_link), + (try_to_link_1), (new_pad), (close_link), (type_found), + (gst_decode_bin_set_property), (gst_decode_bin_get_property), + (gst_decode_bin_change_state), (plugin_init): + * gst/playback/gstplaybasebin.c: (gst_play_base_bin_get_type), + (gst_play_base_bin_class_init), (gst_play_base_bin_init), + (gst_play_base_bin_dispose), (queue_overrun), + (gen_preroll_element), (remove_prerolls), (no_more_pads), + (new_stream), (setup_source), (gst_play_base_bin_set_property), + (gst_play_base_bin_get_property), (play_base_eos), + (gst_play_base_bin_change_state), (gst_play_base_bin_add_element), + (gst_play_base_bin_remove_element), + (gst_play_base_bin_mute_stream), (gst_play_base_bin_link_stream), + (gst_play_base_bin_unlink_stream), + (gst_play_base_bin_get_streaminfo): + * gst/playback/gstplaybasebin.h: + * gst/playback/gstplaybin.c: (gst_play_bin_get_type), + (gst_play_bin_class_init), (gst_play_bin_init), + (gst_play_bin_dispose), (gst_play_bin_set_property), + (gst_play_bin_get_property), (gen_video_element), + (gen_audio_element), (remove_sinks), (setup_sinks), + (gst_play_bin_change_state), (gst_play_bin_get_event_masks), + (gst_play_bin_send_event), (gst_play_bin_get_formats), + (gst_play_bin_convert), (gst_play_bin_get_query_types), + (gst_play_bin_query), (plugin_init): + * gst/playback/test4.c: (main): + Work on object reuse and seeking. + +2004-07-09 Wim Taymans + * examples/seeking/seek.c: (iterate): Don't consume all CPU in the idle loop. diff --git a/gst/playback/gstdecodebin.c b/gst/playback/gstdecodebin.c index 192354f..ecd1f2a 100644 --- a/gst/playback/gstdecodebin.c +++ b/gst/playback/gstdecodebin.c @@ -60,6 +60,10 @@ struct _GstDecodeBin GList *factories; gint numpads; + + GList *elements; + + guint have_type_id; }; struct _GstDecodeBinClass @@ -176,7 +180,6 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass) GST_DEBUG_FUNCPTR (gst_decode_bin_change_state); } - static gboolean gst_decode_bin_factory_filter (GstPluginFeature * feature, GstDecodeBin * decode_bin) @@ -208,7 +211,7 @@ compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2) static void print_feature (GstPluginFeature * feature) { - g_print ("%s\n", gst_plugin_feature_get_name (feature)); + GST_DEBUG ("%s\n", gst_plugin_feature_get_name (feature)); } static void @@ -231,11 +234,10 @@ gst_decode_bin_init (GstDecodeBin * decode_bin) gst_element_add_ghost_pad (GST_ELEMENT (decode_bin), gst_element_get_pad (decode_bin->typefind, "sink"), "sink"); - g_signal_connect (G_OBJECT (decode_bin->typefind), "have_type", + decode_bin->have_type_id = + g_signal_connect (G_OBJECT (decode_bin->typefind), "have_type", G_CALLBACK (type_found), decode_bin); - decode_bin->numpads = 0; - decode_bin->threaded = FALSE; } static void @@ -245,6 +247,13 @@ gst_decode_bin_dispose (GObject * object) decode_bin = GST_DECODE_BIN (object); + g_signal_handlers_disconnect_matched (G_OBJECT (decode_bin->typefind), + G_SIGNAL_MATCH_ID, decode_bin->have_type_id, 0, NULL, NULL, NULL); + + gst_bin_remove (GST_BIN (decode_bin), decode_bin->typefind); + + g_list_free (decode_bin->factories); + if (G_OBJECT_CLASS (parent_class)->dispose) { G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -305,6 +314,7 @@ close_pad_link (GstElement * element, GstPad * pad, GstCaps * caps, ghost = gst_element_get_pad (GST_ELEMENT (decode_bin), padname); + /* our own signal with an extra flag that this is the only pad */ g_signal_emit (G_OBJECT (decode_bin), gst_decode_bin_signals[SIGNAL_NEW_STREAM], 0, ghost, !decode_bin->dynamic); @@ -336,7 +346,7 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories) GstElement *element; gboolean ret; - g_print ("trying to link %s\n", + GST_DEBUG ("trying to link %s\n", gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory))); element = gst_element_factory_create (factory, NULL); @@ -344,6 +354,7 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories) continue; gst_bin_add (GST_BIN (decode_bin), element); + decode_bin->elements = g_list_prepend (decode_bin->elements, element); ret = gst_pad_link (pad, gst_element_get_pad (element, "sink")); if (ret) { @@ -486,13 +497,24 @@ gst_decode_bin_get_property (GObject * object, guint prop_id, GValue * value, static GstElementStateReturn gst_decode_bin_change_state (GstElement * element) { - GstElementStateReturn ret = GST_STATE_SUCCESS; + GstElementStateReturn ret; GstDecodeBin *decode_bin; + gint transition; decode_bin = GST_DECODE_BIN (element); - switch (GST_STATE_TRANSITION (element)) { + transition = GST_STATE_TRANSITION (element); + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element); + if (ret != GST_STATE_SUCCESS) { + return ret; + } + + switch (transition) { case GST_STATE_NULL_TO_READY: + decode_bin->numpads = 0; + decode_bin->threaded = FALSE; + break; case GST_STATE_READY_TO_PAUSED: case GST_STATE_PAUSED_TO_PLAYING: case GST_STATE_PLAYING_TO_PAUSED: @@ -503,10 +525,6 @@ gst_decode_bin_change_state (GstElement * element) break; } - if (ret == GST_STATE_SUCCESS) { - return GST_ELEMENT_CLASS (parent_class)->change_state (element); - } - return ret; } diff --git a/gst/playback/gstplaybasebin.c b/gst/playback/gstplaybasebin.c index 636ce2a..8d97770 100644 --- a/gst/playback/gstplaybasebin.c +++ b/gst/playback/gstplaybasebin.c @@ -117,6 +117,9 @@ gst_play_base_bin_class_init (GstPlayBaseBinClass * klass) g_param_spec_pointer ("stream-info", "Stream info", "List of streaminfo", G_PARAM_READABLE)); + GST_DEBUG_CATEGORY_INIT (gst_play_base_bin_debug, "playbasebin", 0, + "playbasebin"); + gst_play_base_bin_signals[MUTE_STREAM_SIGNAL] = g_signal_new ("mute-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstPlayBaseBinClass, mute_stream), @@ -151,9 +154,13 @@ gst_play_base_bin_init (GstPlayBaseBin * play_base_bin) { play_base_bin->uri = NULL; play_base_bin->threaded = FALSE; + play_base_bin->need_rebuild = TRUE; + play_base_bin->source = NULL; + play_base_bin->decoder = NULL; play_base_bin->preroll_lock = g_mutex_new (); play_base_bin->preroll_cond = g_cond_new (); + play_base_bin->preroll_elems = NULL; GST_FLAG_SET (play_base_bin, GST_BIN_SELF_SCHEDULABLE); } @@ -172,23 +179,6 @@ gst_play_base_bin_dispose (GObject * object) } static void -rebuild_pipeline (GstPlayBaseBin * play_base_bin) -{ - GstElementState oldstate; - - if (play_base_bin->thread == NULL) - return; - - oldstate = gst_element_get_state (play_base_bin->thread); - - gst_element_set_state (play_base_bin->thread, GST_STATE_NULL); - /* remove old elements */ - - /* set to old state again */ - gst_element_set_state (play_base_bin->thread, oldstate); -} - -static void queue_overrun (GstElement * element, GstPlayBaseBin * play_base_bin) { g_mutex_lock (play_base_bin->preroll_lock); @@ -214,6 +204,31 @@ gen_preroll_element (GstPlayBaseBin * play_base_bin, GstPad * pad) } static void +remove_prerolls (GstPlayBaseBin * play_base_bin) +{ + GList *prerolls, *infos; + + for (prerolls = play_base_bin->preroll_elems; prerolls; + prerolls = g_list_next (prerolls)) { + GstElement *element = GST_ELEMENT (prerolls->data); + + GST_LOG ("removing preroll element %s", gst_element_get_name (element)); + gst_bin_remove (GST_BIN (play_base_bin->thread), element); + } + g_list_free (play_base_bin->preroll_elems); + play_base_bin->preroll_elems = NULL; + + for (infos = play_base_bin->streaminfo; infos; infos = g_list_next (infos)) { + GstStreamInfo *info = GST_STREAM_INFO (infos->data); + + g_object_unref (info); + } + g_list_free (play_base_bin->streaminfo); + play_base_bin->streaminfo = NULL; + play_base_bin->nstreams = 0; +} + +static void no_more_pads (GstElement * element, GstPlayBaseBin * play_base_bin) { g_mutex_lock (play_base_bin->preroll_lock); @@ -257,6 +272,9 @@ new_stream (GstElement * element, GstPad * pad, gboolean last, gst_bin_add (GST_BIN (play_base_bin->thread), new_element); play_base_bin->threaded = TRUE; + play_base_bin->preroll_elems = + g_list_prepend (play_base_bin->preroll_elems, new_element); + gst_pad_link (pad, gst_element_get_pad (new_element, "sink")); gst_element_sync_state_with_parent (new_element); } @@ -269,46 +287,73 @@ new_stream (GstElement * element, GstPad * pad, gboolean last, static gboolean setup_source (GstPlayBaseBin * play_base_bin) { - if (play_base_bin->source) { - gst_bin_remove (GST_BIN (play_base_bin->thread), play_base_bin->source); - gst_object_unref (GST_OBJECT (play_base_bin->source)); - } + GstElement *old_src; + + if (!play_base_bin->need_rebuild) + return TRUE; + + old_src = play_base_bin->source; play_base_bin->source = gst_element_make_from_uri (GST_URI_SRC, play_base_bin->uri, "source"); if (!play_base_bin->source) { g_warning ("don't know how to read %s", play_base_bin->uri); + play_base_bin->source = old_src; return FALSE; + } else { + if (old_src) { + GST_LOG ("removing old src element %s", gst_element_get_name (old_src)); + gst_bin_remove (GST_BIN (play_base_bin->thread), old_src); + } + gst_bin_add (GST_BIN (play_base_bin->thread), play_base_bin->source); } { - GstElement *decoder; gboolean res; + gint sig1, sig2; + GstElement *old_dec; - gst_bin_add (GST_BIN (play_base_bin->thread), play_base_bin->source); + old_dec = play_base_bin->decoder; - decoder = gst_element_factory_make ("decodebin", "decoder"); - if (!decoder) { + play_base_bin->decoder = gst_element_factory_make ("decodebin", "decoder"); + if (!play_base_bin->decoder) { g_warning ("can't find decoder element"); + play_base_bin->decoder = old_dec; return FALSE; + } else { + if (old_dec) { + GST_LOG ("removing old decoder element %s", + gst_element_get_name (old_dec)); + gst_bin_remove (GST_BIN (play_base_bin->thread), old_dec); + } + gst_bin_add (GST_BIN (play_base_bin->thread), play_base_bin->decoder); } + remove_prerolls (play_base_bin); - gst_bin_add (GST_BIN (play_base_bin->thread), decoder); - res = gst_element_link_pads (play_base_bin->source, "src", decoder, "sink"); + res = + gst_element_link_pads (play_base_bin->source, "src", + play_base_bin->decoder, "sink"); if (!res) { g_warning ("can't link source to typefind element"); return FALSE; } - g_signal_connect (G_OBJECT (decoder), "new_stream", + sig1 = g_signal_connect (G_OBJECT (play_base_bin->decoder), "new_stream", G_CALLBACK (new_stream), play_base_bin); - g_signal_connect (G_OBJECT (decoder), "no-more-pads", + sig2 = g_signal_connect (G_OBJECT (play_base_bin->decoder), "no-more-pads", G_CALLBACK (no_more_pads), play_base_bin); g_mutex_lock (play_base_bin->preroll_lock); gst_element_set_state (play_base_bin->thread, GST_STATE_PLAYING); g_cond_wait (play_base_bin->preroll_cond, play_base_bin->preroll_lock); g_mutex_unlock (play_base_bin->preroll_lock); + + g_signal_handlers_disconnect_matched (G_OBJECT (play_base_bin->decoder), + G_SIGNAL_MATCH_ID, sig1, 0, NULL, NULL, NULL); + g_signal_handlers_disconnect_matched (G_OBJECT (play_base_bin->decoder), + G_SIGNAL_MATCH_ID, sig2, 0, NULL, NULL, NULL); + + play_base_bin->need_rebuild = FALSE; } return TRUE; @@ -337,7 +382,7 @@ gst_play_base_bin_set_property (GObject * object, guint prop_id, g_free (play_base_bin->uri); play_base_bin->uri = g_strdup (uri); - rebuild_pipeline (play_base_bin); + play_base_bin->need_rebuild = TRUE; } break; } @@ -373,6 +418,13 @@ gst_play_base_bin_get_property (GObject * object, guint prop_id, GValue * value, } } +static void +play_base_eos (GstBin * bin, GstPlayBaseBin * play_base_bin) +{ + g_print ("eos\n"); + gst_element_set_eos (GST_ELEMENT (play_base_bin)); +} + static GstElementStateReturn gst_play_base_bin_change_state (GstElement * element) { @@ -395,6 +447,9 @@ gst_play_base_bin_change_state (GstElement * element) GST_OBJECT (play_base_bin)); gst_element_set_state (play_base_bin->thread, GST_STATE_READY); + + g_signal_connect (G_OBJECT (play_base_bin->thread), "eos", + G_CALLBACK (play_base_eos), play_base_bin); } else { g_warning ("could not get 'opt' scheduler"); gst_object_unref (GST_OBJECT (play_base_bin->thread)); @@ -423,10 +478,9 @@ gst_play_base_bin_change_state (GstElement * element) break; case GST_STATE_PAUSED_TO_READY: ret = gst_element_set_state (play_base_bin->thread, GST_STATE_READY); + play_base_bin->need_rebuild = TRUE; break; case GST_STATE_READY_TO_NULL: - ret = gst_element_set_state (play_base_bin->thread, GST_STATE_NULL); - gst_object_unref (GST_OBJECT (play_base_bin->thread)); break; default: @@ -468,7 +522,7 @@ gst_play_base_bin_add_element (GstBin * bin, GstElement * element) clock = gst_scheduler_get_clock (sched); gst_scheduler_set_clock (sched, clock); - gst_element_sync_state_with_parent (element); + //gst_element_sync_state_with_parent (element); } else { g_warning ("adding elements is not allowed in NULL"); } @@ -482,6 +536,21 @@ gst_play_base_bin_remove_element (GstBin * bin, GstElement * element) play_base_bin = GST_PLAY_BASE_BIN (bin); if (play_base_bin->thread) { + if (play_base_bin->threaded) { + gchar *name; + GstElement *thread; + + name = g_strdup_printf ("thread_%s", gst_element_get_name (element)); + thread = gst_bin_get_by_name (GST_BIN (play_base_bin->thread), name); + g_free (name); + + if (!thread) { + g_warning ("cannot find element to remove"); + } else { + element = thread; + } + } + GST_LOG ("removing element %s", gst_element_get_name (element)); gst_bin_remove (GST_BIN (play_base_bin->thread), element); } else { g_warning ("removing elements is not allowed in NULL"); diff --git a/gst/playback/gstplaybasebin.h b/gst/playback/gstplaybasebin.h index f238508..f03b194 100644 --- a/gst/playback/gstplaybasebin.h +++ b/gst/playback/gstplaybasebin.h @@ -42,11 +42,14 @@ struct _GstPlayBaseBin { gboolean threaded; GMutex *preroll_lock; GCond *preroll_cond; + GList *preroll_elems; /* internal thread */ GstElement *thread; gchar *uri; GstElement *source; + GstElement *decoder; + gboolean need_rebuild; gint nstreams; GList *streaminfo; diff --git a/gst/playback/gstplaybin.c b/gst/playback/gstplaybin.c index 3b988f2..18f5eb1 100644 --- a/gst/playback/gstplaybin.c +++ b/gst/playback/gstplaybin.c @@ -46,6 +46,8 @@ struct _GstPlayBin GstElement *video_sink; GstElement *visualisation; + GList *sinks; + GList *seekables; }; @@ -181,6 +183,7 @@ gst_play_bin_init (GstPlayBin * play_bin) play_bin->audio_sink = NULL; play_bin->visualisation = NULL; play_bin->seekables = NULL; + play_bin->sinks = NULL; GST_FLAG_SET (play_bin, GST_BIN_SELF_SCHEDULABLE); } @@ -259,7 +262,7 @@ gen_video_element (GstPlayBin * play_bin) sink = gst_element_factory_make ("ximagesink", "sink"); } - play_bin->seekables = g_list_prepend (play_bin->seekables, sink); + play_bin->seekables = g_list_append (play_bin->seekables, sink); gst_bin_add (GST_BIN (element), conv); gst_bin_add (GST_BIN (element), sink); @@ -299,6 +302,23 @@ gen_audio_element (GstPlayBin * play_bin) } static void +remove_sinks (GstPlayBin * play_bin) +{ + GList *sinks; + + for (sinks = play_bin->sinks; sinks; sinks = g_list_next (sinks)) { + GstElement *element = GST_ELEMENT (sinks->data); + + GST_LOG ("removing sink %p", element); + gst_bin_remove (GST_BIN (play_bin), element); + } + g_list_free (play_bin->sinks); + g_list_free (play_bin->seekables); + play_bin->sinks = NULL; + play_bin->seekables = NULL; +} + +static void setup_sinks (GstPlayBin * play_bin) { GList *streaminfo; @@ -317,6 +337,9 @@ setup_sinks (GstPlayBin * play_bin) g_object_get (obj, "type", &type, NULL); g_object_get (obj, "pad", &srcpad, NULL); + if (gst_pad_is_linked (srcpad)) + continue; + if (type == 1) { sink = gen_audio_element (play_bin); } else if (type == 2) { @@ -335,6 +358,10 @@ setup_sinks (GstPlayBin * play_bin) capsstr = gst_caps_to_string (gst_pad_get_caps (srcpad)); g_warning ("could not link %s", capsstr); g_free (capsstr); + GST_LOG ("removing sink %p", sink); + gst_bin_remove (GST_BIN (play_bin), sink); + } else { + play_bin->sinks = g_list_prepend (play_bin->sinks, sink); } } } @@ -360,7 +387,10 @@ gst_play_bin_change_state (GstElement * element) break; case GST_STATE_PAUSED_TO_PLAYING: case GST_STATE_PLAYING_TO_PAUSED: + break; case GST_STATE_PAUSED_TO_READY: + remove_sinks (play_bin); + break; case GST_STATE_READY_TO_NULL: break; default: @@ -392,9 +422,11 @@ gst_play_bin_send_event (GstElement * element, GstEvent * event) GstElement *element = GST_ELEMENT (s->data); gboolean ok; + gst_event_ref (event); ok = gst_element_send_event (element, event); res |= ok; } + gst_event_unref (event); return res; } diff --git a/gst/playback/test4.c b/gst/playback/test4.c index 42361a3..043d1bd 100644 --- a/gst/playback/test4.c +++ b/gst/playback/test4.c @@ -31,6 +31,11 @@ main (gint argc, gchar * argv[]) player = gst_element_factory_make ("playbin", "player"); g_assert (player); + if (argc < 2) { + g_print ("usage: %s \n", argv[0]); + exit (-1); + } + g_object_set (G_OBJECT (player), "uri", argv[1], NULL); g_print ("play...\n"); -- 2.7.4