gst/playback/: Rough port of playbin. Needs some more work, but is mostly done, and uses a few locks in important pla...

Original commit message from CVS:
* gst/playback/gstplaybasebin.c: (gst_play_base_bin_get_type),
(gst_play_base_bin_class_init), (gst_play_base_bin_finalize),
(get_active_group), (get_building_group), (group_destroy),
(group_commit), (check_queue), (queue_overrun),
(queue_threshold_reached), (queue_out_of_data),
(gen_preroll_element), (remove_groups), (unknown_type),
(add_element_stream), (no_more_pads), (probe_triggered),
(preroll_unlinked), (new_decoded_pad), (setup_subtitle),
(setup_substreams), (setup_source), (finish_source),
(prepare_output), (muted_group_change_state),
(gst_play_base_bin_set_property), (gst_play_base_bin_get_property),
(gst_play_base_bin_change_state):
* gst/playback/gstplaybasebin.h:
* gst/playback/gstplaybin.c: (gst_play_bin_class_init),
(gst_play_bin_init), (gst_play_bin_set_property),
(gen_video_element), (gen_text_element), (gen_audio_element),
(gen_vis_element), (remove_sinks), (add_sink), (setup_sinks),
(gst_play_bin_change_state):
* gst/playback/gststreaminfo.c: (gst_stream_info_class_init),
(cb_probe), (gst_stream_info_new), (gst_stream_info_dispose),
(stream_info_change_state), (gst_stream_info_set_mute),
(gst_stream_info_get_property):
* gst/playback/gststreaminfo.h:
* gst/playback/gststreamselector.c: (gst_stream_selector_init),
(gst_stream_selector_get_linked_pad),
(gst_stream_selector_getcaps),
(gst_stream_selector_get_linked_pads),
(gst_stream_selector_request_new_pad), (gst_stream_selector_chain):
* gst/playback/gststreamselector.h:
Rough port of playbin. Needs some more work, but is mostly done,
and uses a few locks in important places, which should make stuff
like chain-switches clean. Still uses GST_STATE() in a few places,
which isn't all that good an idea, subtitles/elements disabled
because no elements to test with and thus probably broken, query
and event handling moved to GstBin, internal thread removed
alltogether because the pipeline does that for us now. Can play
Ogg/Vorbis files. Haven't tested anything else yet.
This commit is contained in:
Ronald S. Bultje 2005-05-12 15:22:05 +00:00
parent 9d6b1f28fa
commit 0209cb45e5
8 changed files with 677 additions and 907 deletions

View file

@ -1,3 +1,43 @@
2005-05-12 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* gst/playback/gstplaybasebin.c: (gst_play_base_bin_get_type),
(gst_play_base_bin_class_init), (gst_play_base_bin_finalize),
(get_active_group), (get_building_group), (group_destroy),
(group_commit), (check_queue), (queue_overrun),
(queue_threshold_reached), (queue_out_of_data),
(gen_preroll_element), (remove_groups), (unknown_type),
(add_element_stream), (no_more_pads), (probe_triggered),
(preroll_unlinked), (new_decoded_pad), (setup_subtitle),
(setup_substreams), (setup_source), (finish_source),
(prepare_output), (muted_group_change_state),
(gst_play_base_bin_set_property), (gst_play_base_bin_get_property),
(gst_play_base_bin_change_state):
* gst/playback/gstplaybasebin.h:
* gst/playback/gstplaybin.c: (gst_play_bin_class_init),
(gst_play_bin_init), (gst_play_bin_set_property),
(gen_video_element), (gen_text_element), (gen_audio_element),
(gen_vis_element), (remove_sinks), (add_sink), (setup_sinks),
(gst_play_bin_change_state):
* gst/playback/gststreaminfo.c: (gst_stream_info_class_init),
(cb_probe), (gst_stream_info_new), (gst_stream_info_dispose),
(stream_info_change_state), (gst_stream_info_set_mute),
(gst_stream_info_get_property):
* gst/playback/gststreaminfo.h:
* gst/playback/gststreamselector.c: (gst_stream_selector_init),
(gst_stream_selector_get_linked_pad),
(gst_stream_selector_getcaps),
(gst_stream_selector_get_linked_pads),
(gst_stream_selector_request_new_pad), (gst_stream_selector_chain):
* gst/playback/gststreamselector.h:
Rough port of playbin. Needs some more work, but is mostly done,
and uses a few locks in important places, which should make stuff
like chain-switches clean. Still uses GST_STATE() in a few places,
which isn't all that good an idea, subtitles/elements disabled
because no elements to test with and thus probably broken, query
and event handling moved to GstBin, internal thread removed
alltogether because the pipeline does that for us now. Can play
Ogg/Vorbis files. Haven't tested anything else yet.
2005-05-12 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* ext/ogg/gstoggdemux.c: (gst_ogg_demux_activate_chain):

File diff suppressed because it is too large Load diff

View file

@ -17,7 +17,6 @@
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_PLAYBASEBIN_H__
#define __GST_PLAYBASEBIN_H__
@ -52,6 +51,7 @@ typedef struct
gint nstreams;
GList *streaminfo;
/* contained decoded elementary streams */
struct {
gint npads;
GstBin *bin;
@ -63,17 +63,14 @@ typedef struct
} GstPlayBaseGroup;
struct _GstPlayBaseBin {
GstBin bin;
GstPipeline pipeline;
/* properties */
gboolean threaded;
guint64 queue_size;
guint queue_threshold;
/* currently loaded media */
gint current[NUM_TYPES];
/* internal thread */
GstElement *thread;
gchar *uri, *suburi;
gboolean is_stream;
GstElement *source;
@ -81,18 +78,15 @@ struct _GstPlayBaseBin {
GstElement *subtitle; /* additional filesrc ! subparse bin */
gboolean need_rebuild;
/* group management */
/* group management - using own lock */
GMutex *group_lock; /* lock and mutex to signal availability of new group */
GCond *group_cond;
GstPlayBaseGroup *building_group; /* the group that we are constructing */
GList *queued_groups; /* the constructed groups, head is the active one */
/* list of usable factories */
GList *factories;
};
struct _GstPlayBaseBinClass {
GstBinClass parent_class;
GstPipelineClass parent_class;
/* signals */
void (*setup_output_pads) (GstPlayBaseBin *play_base_bin);
@ -108,28 +102,10 @@ struct _GstPlayBaseBinClass {
/* Called on redirect */
void (*got_redirect) (GstPlayBaseBin *play_base_bin,
const gchar *new_location);
/* action signals */
gboolean (*link_stream) (GstPlayBaseBin *play_base_bin,
GstStreamInfo *info,
GstPad *pad);
void (*unlink_stream) (GstPlayBaseBin *play_base_bin,
GstStreamInfo *info);
};
GType gst_play_base_bin_get_type (void);
gint gst_play_base_bin_get_nstreams (GstPlayBaseBin *play_base_bin);
const GList* gst_play_base_bin_get_streaminfo (GstPlayBaseBin *play_base_bin);
gint gst_play_base_bin_get_nstreams_of_type (GstPlayBaseBin *play_base_bin,
GstStreamType type);
gboolean gst_play_base_bin_link_stream (GstPlayBaseBin *play_base_bin,
GstStreamInfo *info,
GstPad *pad);
void gst_play_base_bin_unlink_stream (GstPlayBaseBin *play_base_bin,
GstStreamInfo *info);
G_END_DECLS
#endif /* __GST_PLAYBASEBIN_H__ */

View file

@ -45,6 +45,7 @@ struct _GstPlayBin
GstPlayBaseBin parent;
/* the configurable elements */
GstElement *fakesink;
GstElement *audio_sink;
GstElement *video_sink;
GstElement *visualisation;
@ -55,9 +56,6 @@ struct _GstPlayBin
/* these are the currently active sinks */
GList *sinks;
/* these are the sink elements used for seeking/query etc.. */
GList *seekables;
/* the last captured frame for snapshots */
GstBuffer *frame;
@ -108,12 +106,6 @@ static void gst_play_bin_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * spec);
static GstElementStateReturn gst_play_bin_change_state (GstElement * element);
static gboolean gst_play_bin_send_event (GstElement * element,
GstEvent * event);
static const GstQueryType *gst_play_bin_get_query_types (GstElement * element);
static gboolean gst_play_bin_query (GstElement * element, GstQuery * query);
static GstElementClass *parent_class;
//static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
@ -200,10 +192,6 @@ gst_play_bin_class_init (GstPlayBinClass * klass)
gstelement_klass->change_state =
GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
gstelement_klass->send_event = GST_DEBUG_FUNCPTR (gst_play_bin_send_event);
gstelement_klass->get_query_types =
GST_DEBUG_FUNCPTR (gst_play_bin_get_query_types);
gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
playbasebin_klass->setup_output_pads = setup_sinks;
playbasebin_klass->group_switch = group_switch;
@ -218,7 +206,6 @@ gst_play_bin_init (GstPlayBin * play_bin)
play_bin->volume_element = NULL;
play_bin->textoverlay_element = NULL;
play_bin->volume = 1.0;
play_bin->seekables = NULL;
play_bin->sinks = NULL;
play_bin->frame = NULL;
play_bin->font_desc = NULL;
@ -308,8 +295,8 @@ gst_play_bin_set_property (GObject * object, guint prop_id,
}
break;
case ARG_VOLUME:
play_bin->volume = g_value_get_double (value);
if (play_bin->volume_element) {
play_bin->volume = g_value_get_double (value);
g_object_set (G_OBJECT (play_bin->volume_element), "volume",
play_bin->volume, NULL);
}
@ -393,42 +380,42 @@ gen_video_element (GstPlayBin * play_bin)
{
GstElement *element;
GstElement *conv;
GstElement *scale;
//GstElement *scale;
GstElement *sink;
GstElement *identity;
GstPad *pad;
/* first see if we have it in the cache */
element = g_hash_table_lookup (play_bin->cache, "vbin");
if (element != NULL) {
/* need to get the video sink element as we need to add it to the
* list of seekable elements */
sink = g_hash_table_lookup (play_bin->cache, "video_sink");
goto done;
return element;
}
element = gst_bin_new ("vbin");
identity = gst_element_factory_make ("identity", "id");
g_signal_connect (identity, "handoff", G_CALLBACK (handoff), play_bin);
conv = gst_element_factory_make ("ffmpegcolorspace", "vconv");
scale = gst_element_factory_make ("videoscale", "vscale");
//scale = gst_element_factory_make ("videoscale", "vscale");
if (play_bin->video_sink) {
sink = play_bin->video_sink;
} else {
sink = gst_element_factory_make ("autovideosink", "sink");
sink = gst_element_factory_make ("xvimagesink", "sink");
}
gst_object_ref (GST_OBJECT (sink));
g_hash_table_insert (play_bin->cache, "video_sink", sink);
gst_bin_add (GST_BIN (element), identity);
gst_bin_add (GST_BIN (element), conv);
gst_bin_add (GST_BIN (element), scale);
//gst_bin_add (GST_BIN (element), scale);
gst_bin_add (GST_BIN (element), sink);
gst_element_link_pads (identity, "src", conv, "sink");
gst_element_link_pads (conv, "src", scale, "sink");
gst_element_link_pads (scale, "src", sink, "sink");
gst_element_link_pads (conv, "src", /*scale, "sink");
gst_element_link_pads (scale, "src", */ sink, "sink");
gst_element_add_ghost_pad (element, gst_element_get_pad (identity, "sink"),
"sink");
pad = gst_element_get_pad (identity, "sink");
gst_element_add_ghost_pad (element, pad, "sink");
g_object_unref (G_OBJECT (pad));
gst_element_set_state (element, GST_STATE_READY);
@ -437,9 +424,6 @@ gen_video_element (GstPlayBin * play_bin)
gst_object_ref (GST_OBJECT (element));
g_hash_table_insert (play_bin->cache, "vbin", element);
done:
play_bin->seekables = g_list_append (play_bin->seekables, sink);
return element;
}
@ -459,6 +443,7 @@ static GstElement *
gen_text_element (GstPlayBin * play_bin)
{
GstElement *element, *csp, *overlay, *vbin;
GstPad *pad;
overlay = gst_element_factory_make ("textoverlay", "overlay");
g_object_set (G_OBJECT (overlay),
@ -478,10 +463,13 @@ gen_text_element (GstPlayBin * play_bin)
gst_element_link_many (csp, overlay, vbin, NULL);
gst_bin_add_many (GST_BIN (element), csp, overlay, vbin, NULL);
gst_element_add_ghost_pad (element,
gst_element_get_pad (overlay, "text_sink"), "text_sink");
gst_element_add_ghost_pad (element,
gst_element_get_pad (csp, "sink"), "sink");
pad = gst_element_get_pad (overlay, "text_sink");
gst_element_add_ghost_pad (element, pad, "text_sink");
g_object_unref (G_OBJECT (pad));
pad = gst_element_get_pad (csp, "sink");
gst_element_add_ghost_pad (element, pad, "sink");
g_object_unref (G_OBJECT (pad));
return element;
}
@ -507,11 +495,11 @@ gen_audio_element (GstPlayBin * play_bin)
GstElement *sink;
GstElement *volume;
GstElement *scale;
GstPad *pad;
element = g_hash_table_lookup (play_bin->cache, "abin");
if (element != NULL) {
sink = g_hash_table_lookup (play_bin->cache, "audio_sink");
goto done;
return element;
}
element = gst_bin_new ("abin");
conv = gst_element_factory_make ("audioconvert", "aconv");
@ -524,7 +512,7 @@ gen_audio_element (GstPlayBin * play_bin)
if (play_bin->audio_sink) {
sink = play_bin->audio_sink;
} else {
sink = gst_element_factory_make ("autoaudiosink", "sink");
sink = gst_element_factory_make ("alsasink", "sink");
play_bin->audio_sink = GST_ELEMENT (gst_object_ref (GST_OBJECT (sink)));
}
@ -532,16 +520,17 @@ gen_audio_element (GstPlayBin * play_bin)
g_hash_table_insert (play_bin->cache, "audio_sink", sink);
gst_bin_add (GST_BIN (element), conv);
gst_bin_add (GST_BIN (element), scale);
gst_bin_add (GST_BIN (element), volume);
//gst_bin_add (GST_BIN (element), scale);
//gst_bin_add (GST_BIN (element), volume);
gst_bin_add (GST_BIN (element), sink);
gst_element_link_pads (conv, "src", scale, "sink");
gst_element_link_pads (scale, "src", volume, "sink");
gst_element_link_pads (volume, "src", sink, "sink");
gst_element_link_pads (conv, "src", /*scale, "sink");
gst_element_link_pads (scale, "src", volume, "sink");
gst_element_link_pads (volume, "src", */ sink, "sink");
gst_element_add_ghost_pad (element,
gst_element_get_pad (conv, "sink"), "sink");
pad = gst_element_get_pad (conv, "sink");
gst_element_add_ghost_pad (element, pad, "sink");
g_object_unref (G_OBJECT (pad));
gst_element_set_state (element, GST_STATE_READY);
@ -550,9 +539,6 @@ gen_audio_element (GstPlayBin * play_bin)
gst_object_ref (GST_OBJECT (element));
g_hash_table_insert (play_bin->cache, "abin", element);
done:
play_bin->seekables = g_list_prepend (play_bin->seekables, sink);
return element;
}
@ -590,6 +576,7 @@ gen_vis_element (GstPlayBin * play_bin)
GstElement *vis;
GstElement *vqueue;
GstElement *vthread;
GstPad *pad;
element = gst_bin_new ("visbin");
tee = gst_element_factory_make ("tee", "tee");
@ -622,14 +609,17 @@ gen_vis_element (GstPlayBin * play_bin)
gst_element_link_pads (vqueue, "src", vsink, "sink");
gst_pad_link (gst_element_get_request_pad (tee, "src%d"),
gst_element_get_pad (asink, "sink"));
pad = gst_element_get_pad (asink, "sink");
gst_pad_link (gst_element_get_request_pad (tee, "src%d"), pad);
g_object_unref (G_OBJECT (pad));
gst_pad_link (gst_element_get_request_pad (tee, "src%d"),
gst_element_get_pad (conv, "sink"));
pad = gst_element_get_pad (conv, "sink");
gst_pad_link (gst_element_get_request_pad (tee, "src%d"), pad);
g_object_unref (G_OBJECT (pad));
gst_element_add_ghost_pad (element,
gst_element_get_pad (tee, "sink"), "sink");
pad = gst_element_get_pad (tee, "sink");
gst_element_add_ghost_pad (element, pad, "sink");
g_object_unref (G_OBJECT (pad));
return element;
}
@ -659,6 +649,7 @@ remove_sinks (GstPlayBin * play_bin)
* there is no unwanted state change when the parent
* is disposed */
gst_bin_remove (GST_BIN (parent), element);
g_object_unref (G_OBJECT (parent));
}
}
element = g_hash_table_lookup (play_bin->cache, "vbin");
@ -666,6 +657,7 @@ remove_sinks (GstPlayBin * play_bin)
parent = gst_element_get_parent (element);
if (parent != NULL) {
gst_bin_remove (GST_BIN (parent), element);
g_object_unref (G_OBJECT (parent));
}
}
@ -676,12 +668,11 @@ remove_sinks (GstPlayBin * play_bin)
GST_LOG ("removing sink %p", element);
if (GST_PAD_PEER (pad))
gst_pad_unlink (GST_PAD_PEER (pad), pad);
g_object_unref (G_OBJECT (pad));
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;
if (play_bin->frame) {
gst_buffer_unref (play_bin->frame);
@ -689,7 +680,6 @@ remove_sinks (GstPlayBin * play_bin)
}
play_bin->textoverlay_element = NULL;
play_bin->volume_element = NULL;
}
/* loop over the streams and set up the pipeline to play this
@ -705,17 +695,21 @@ static gboolean
add_sink (GstPlayBin * play_bin, GstElement * sink, GstPad * srcpad)
{
GstPad *sinkpad;
gboolean res;
GstPadLinkReturn res;
GstElement *parent;
/* we found a sink for this stream, now try to install it */
sinkpad = gst_element_get_pad (sink, "sink");
res = gst_pad_link (srcpad, sinkpad);
g_object_unref (G_OBJECT (sinkpad));
parent = gst_pad_get_parent (srcpad);
GST_DEBUG ("Adding sink with state %d (parent: %d, peer: %d)\n",
GST_STATE (sink), GST_STATE (play_bin),
GST_STATE (gst_pad_get_parent (srcpad)));
GST_STATE (sink), GST_STATE (play_bin), GST_STATE (parent));
g_object_unref (G_OBJECT (parent));
/* try to link the pad of the sink to the stream */
if (!res) {
if (res < 0) {
gchar *capsstr;
/* could not link this stream */
@ -726,6 +720,9 @@ add_sink (GstPlayBin * play_bin, GstElement * sink, GstPad * srcpad)
/* we got the sink succesfully linked, now keep the sink
* in out internal list */
play_bin->sinks = g_list_prepend (play_bin->sinks, sink);
gst_element_set_state (sink,
(GST_STATE (play_bin) == GST_STATE_PLAYING) ?
GST_STATE_PLAYING : GST_STATE_PAUSED);
gst_bin_add (GST_BIN (play_bin), sink);
}
@ -740,7 +737,7 @@ setup_sinks (GstPlayBaseBin * play_base_bin)
GList *streaminfo = NULL, *s;
gboolean need_vis = FALSE;
gboolean need_text = FALSE;
GstPad *textsrcpad = NULL, *textsinkpad = NULL;
GstPad *textsrcpad = NULL, *textsinkpad = NULL, *pad;
GstElement *sink;
/* get rid of existing sinks */
@ -769,11 +766,6 @@ setup_sinks (GstPlayBaseBin * play_base_bin)
g_object_get (obj, "type", &type, NULL);
g_object_get (obj, "object", &object, NULL);
/* use the sink elements as seek entry point */
if (type == 4) {
play_bin->seekables = g_list_prepend (play_bin->seekables, object);
}
}
/* link audio */
@ -783,9 +775,10 @@ setup_sinks (GstPlayBaseBin * play_base_bin)
} else {
sink = gen_audio_element (play_bin);
}
add_sink (play_bin, sink,
gst_element_get_pad (group->type[GST_STREAM_TYPE_AUDIO - 1].preroll,
"src"));
pad = gst_element_get_pad (group->type[GST_STREAM_TYPE_AUDIO - 1].preroll,
"src");
add_sink (play_bin, sink, pad);
g_object_unref (G_OBJECT (pad));
}
/* link video */
@ -797,15 +790,21 @@ setup_sinks (GstPlayBaseBin * play_base_bin)
textsrcpad =
gst_element_get_pad (group->type[GST_STREAM_TYPE_TEXT - 1].preroll,
"src");
if (textsinkpad && textsrcpad) {
gst_pad_link (textsrcpad, textsinkpad);
}
gst_pad_link (textsrcpad, textsinkpad);
g_object_unref (G_OBJECT (textsinkpad));
g_object_unref (G_OBJECT (textsrcpad));
} else {
sink = gen_video_element (play_bin);
}
add_sink (play_bin, sink,
gst_element_get_pad (group->type[GST_STREAM_TYPE_VIDEO - 1].preroll,
"src"));
pad = gst_element_get_pad (group->type[GST_STREAM_TYPE_VIDEO - 1].preroll,
"src");
add_sink (play_bin, sink, pad);
g_object_unref (G_OBJECT (pad));
}
if (play_bin->fakesink) {
gst_bin_remove (GST_BIN (play_bin), play_bin->fakesink);
play_bin->fakesink = NULL;
}
}
@ -820,6 +819,17 @@ gst_play_bin_change_state (GstElement * element)
transition = GST_STATE_TRANSITION (element);
switch (transition) {
case GST_STATE_READY_TO_PAUSED:
if (!play_bin->fakesink) {
play_bin->fakesink = gst_element_factory_make ("fakesink", "test");
gst_bin_add (GST_BIN (play_bin), play_bin->fakesink);
}
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
if (ret == GST_STATE_FAILURE)
return ret;
@ -828,10 +838,10 @@ gst_play_bin_change_state (GstElement * element)
case GST_STATE_PLAYING_TO_PAUSED:
/* Set audio sink state to NULL to release the sound device,
* but only if we own it (else we might be in chain-transition). */
if (play_bin->audio_sink != NULL && !play_bin->group_switch &&
GST_STATE (play_bin->audio_sink) == GST_STATE_PAUSED) {
gst_element_set_state (play_bin->audio_sink, GST_STATE_NULL);
}
//if (play_bin->audio_sink != NULL && !play_bin->group_switch &&
// GST_STATE (play_bin->audio_sink) == GST_STATE_PAUSED) {
// gst_element_set_state (play_bin->audio_sink, GST_STATE_NULL);
//}
break;
case GST_STATE_PAUSED_TO_READY:
/* Check for NULL because the state transition may be done by
@ -843,6 +853,10 @@ gst_play_bin_change_state (GstElement * element)
if (play_bin->cache != NULL) {
remove_sinks (play_bin);
}
if (play_bin->fakesink) {
gst_bin_remove (GST_BIN (play_bin), play_bin->fakesink);
play_bin->fakesink = NULL;
}
break;
default:
break;
@ -851,101 +865,6 @@ gst_play_bin_change_state (GstElement * element)
return ret;
}
#if 0
static const GstEventMask *
gst_play_bin_get_event_masks (GstElement * element)
{
/* FIXME, get the list from the number of installed sinks */
return NULL;
}
#endif
/* send an event to all the sinks */
static gboolean
gst_play_bin_send_event (GstElement * element, GstEvent * event)
{
gboolean res = FALSE;
GList *s;
GstPlayBin *play_bin;
GstElementState state;
gboolean need_pause = FALSE;
play_bin = GST_PLAY_BIN (element);
gst_element_get_state (element, &state, NULL, NULL);
/* we pause the pipeline first before sending the event. We only
* do this if the pipeline was playing. */
if (state == GST_STATE_PLAYING) {
need_pause = TRUE;
gst_element_set_state (element, GST_STATE_PAUSED);
}
/* loop over all seekables and send the event to them */
for (s = play_bin->seekables; s; s = g_list_next (s)) {
GstElement *element = GST_ELEMENT (s->data);
gboolean ok;
/* ref each event before sending it */
gst_event_ref (event);
ok = gst_element_send_event (element, event);
res |= ok;
}
gst_event_unref (event);
/* and restart the pipeline if we paused it */
if (need_pause)
gst_element_set_state (element, GST_STATE_PLAYING);
return res;
}
#if 0
static const GstFormat *
gst_play_bin_get_formats (GstElement * element)
{
/* FIXME, compile this list from the installed sinks */
static GstFormat formats[] = {
GST_FORMAT_TIME,
0,
};
return formats;
}
#endif
static const GstQueryType *
gst_play_bin_get_query_types (GstElement * element)
{
/* FIXME, compile from the installed sinks */
static const GstQueryType query_types[] = {
GST_QUERY_TOTAL,
GST_QUERY_POSITION,
0
};
return query_types;
}
static gboolean
gst_play_bin_query (GstElement * element, GstQuery * query)
{
gboolean res = FALSE;
GList *s;
GstPlayBin *play_bin;
play_bin = GST_PLAY_BIN (element);
for (s = play_bin->seekables; s; s = g_list_next (s)) {
GstElement *element = GST_ELEMENT (s->data);
res = gst_element_query (element, query);
if (res)
break;
}
return res;
}
static gboolean
plugin_init (GstPlugin * plugin)
{

View file

@ -36,7 +36,9 @@ enum
ARG_TYPE,
ARG_DECODER,
ARG_MUTE,
ARG_CAPS
ARG_CAPS,
ARG_LANG_CODE,
ARG_CODEC
};
/* signals */
@ -139,6 +141,13 @@ gst_stream_info_class_init (GstStreamInfoClass * klass)
g_param_spec_boxed ("caps", "Capabilities",
"Capabilities (or type) of this stream", GST_TYPE_CAPS,
G_PARAM_READABLE));
g_object_class_install_property (gobject_klass, ARG_LANG_CODE,
g_param_spec_string ("language-code", "Language code",
"Language code for this stream, conforming to ISO-639-1",
NULL, G_PARAM_READABLE));
g_object_class_install_property (gobject_klass, ARG_CODEC,
g_param_spec_string ("codec", "Codec",
"Codec used to encode the stream", NULL, G_PARAM_READABLE));
gst_stream_info_signals[SIGNAL_MUTED] =
g_signal_new ("muted", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
@ -163,6 +172,40 @@ gst_stream_info_init (GstStreamInfo * stream_info)
stream_info->caps = NULL;
}
static gboolean
cb_probe (GstProbe * probe, GstData ** data, gpointer user_data)
{
GstStreamInfo *info = user_data;
if (GST_IS_EVENT (*data)) {
GstEvent *e = GST_EVENT (*data);
if (GST_EVENT_TYPE (e) == GST_EVENT_TAG) {
gchar *codec; //, *lang;
GstTagList *list = gst_event_tag_get_list (e);
if (gst_tag_list_get_string (list, GST_TAG_VIDEO_CODEC, &codec)) {
g_free (info->codec);
info->codec = codec;
g_object_notify (G_OBJECT (info), "codec");
} else if (gst_tag_list_get_string (list, GST_TAG_AUDIO_CODEC, &codec)) {
g_free (info->codec);
info->codec = codec;
g_object_notify (G_OBJECT (info), "codec");
}
#if 0
if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
g_free (info->langcode);
info->langcode = lang;
g_object_notify (G_OBJECT (info), "language-code");
}
#endif
}
}
return TRUE;
}
GstStreamInfo *
gst_stream_info_new (GstObject * object,
GstStreamType type, const gchar * decoder, const GstCaps * caps)
@ -172,6 +215,12 @@ gst_stream_info_new (GstObject * object,
info = g_object_new (GST_TYPE_STREAM_INFO, NULL);
gst_object_ref (object);
if (GST_IS_PAD (object)) {
GstProbe *probe;
probe = gst_probe_new (FALSE, cb_probe, info);
gst_pad_add_probe (GST_PAD_REALIZE (object), probe);
}
info->object = object;
info->type = type;
info->decoder = g_strdup (decoder);
@ -191,11 +240,14 @@ gst_stream_info_dispose (GObject * object)
stream_info = GST_STREAM_INFO (object);
if (stream_info->object) {
if (GST_PAD_REALIZE (stream_info->object) && gst_pad_get_parent ((GstPad *)
GST_PAD_REALIZE (stream_info->object))) {
g_signal_handlers_disconnect_by_func (gst_pad_get_parent ((GstPad *)
GST_PAD_REALIZE (stream_info->object)),
GstElement *parent;
parent = gst_pad_get_parent ((GstPad *)
GST_PAD_REALIZE (stream_info->object));
if (parent != NULL) {
g_signal_handlers_disconnect_by_func (parent,
G_CALLBACK (stream_info_change_state), stream_info);
g_object_unref (G_OBJECT (parent));
}
gst_object_unref (stream_info->object);
@ -205,6 +257,10 @@ gst_stream_info_dispose (GObject * object)
stream_info->type = GST_STREAM_TYPE_UNKNOWN;
g_free (stream_info->decoder);
stream_info->decoder = NULL;
g_free (stream_info->langcode);
stream_info->langcode = NULL;
g_free (stream_info->codec);
stream_info->codec = NULL;
if (stream_info->caps) {
gst_caps_unref (stream_info->caps);
stream_info->caps = NULL;
@ -226,6 +282,7 @@ stream_info_change_state (GstElement * element,
g_return_if_fail (stream_info->mute == TRUE);
GST_DEBUG_OBJECT (stream_info, "Re-muting pads after state-change");
//gst_pad_set_active_recursive (GST_PAD (stream_info->object), FALSE);
g_warning ("FIXME");
}
}
@ -240,19 +297,23 @@ gst_stream_info_set_mute (GstStreamInfo * stream_info, gboolean mute)
}
if (mute != stream_info->mute) {
GstElement *element;
stream_info->mute = mute;
//gst_pad_set_active_recursive ((GstPad *)
// GST_PAD_REALIZE (stream_info->object), !mute);
//GST_PAD_REALIZE (stream_info->object), !mute);
g_warning ("FIXME");
element = gst_pad_get_parent ((GstPad *)
GST_PAD_REALIZE (stream_info->object));
if (mute) {
g_signal_connect (gst_pad_get_parent ((GstPad *)
GST_PAD_REALIZE (stream_info->object)), "state-change",
g_signal_connect (element, "state-change",
G_CALLBACK (stream_info_change_state), stream_info);
} else {
g_signal_handlers_disconnect_by_func (gst_pad_get_parent ((GstPad *)
GST_PAD_REALIZE (stream_info->object)),
g_signal_handlers_disconnect_by_func (element,
G_CALLBACK (stream_info_change_state), stream_info);
}
g_object_unref (G_OBJECT (element));
}
return TRUE;
}
@ -311,6 +372,12 @@ gst_stream_info_get_property (GObject * object, guint prop_id, GValue * value,
case ARG_CAPS:
g_value_set_boxed (value, stream_info->caps);
break;
case ARG_LANG_CODE:
g_value_set_string (value, stream_info->langcode);
break;
case ARG_CODEC:
g_value_set_string (value, stream_info->codec);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;

View file

@ -53,6 +53,11 @@ struct _GstStreamInfo {
be different from the object as the object can be
a queue pad, inserted for preroll. */
GstCaps *caps; /* the caps of the stream */
/* this is tream information cached here because the streaminfo may be
* created before the app can know about it. */
gchar *langcode,
*codec;
};
struct _GstStreamInfoClass {

View file

@ -57,14 +57,11 @@ static void gst_stream_selector_init (GstStreamSelector * sel);
static void gst_stream_selector_base_init (GstStreamSelectorClass * klass);
static void gst_stream_selector_class_init (GstStreamSelectorClass * klass);
static GstCaps *gst_stream_selector_get_caps (GstPad * pad);
static gboolean gst_stream_selector_setcaps (GstPad * pad, GstCaps * caps);
static GstCaps *gst_stream_selector_getcaps (GstPad * pad);
static GList *gst_stream_selector_get_linked_pads (GstPad * pad);
static GstPad *gst_stream_selector_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * unused);
static gboolean gst_stream_selector_event (GstPad * pad, GstEvent * event);
static GstFlowReturn gst_stream_selector_chain (GstPad * pad,
GstBuffer * buffer);
static GstFlowReturn gst_stream_selector_chain (GstPad * pad, GstBuffer * buf);
static GstElementClass *parent_class = NULL;
@ -135,16 +132,15 @@ gst_stream_selector_init (GstStreamSelector * sel)
sel->srcpad = gst_pad_new ("src", GST_PAD_SRC);
gst_pad_set_internal_link_function (sel->srcpad,
GST_DEBUG_FUNCPTR (gst_stream_selector_get_linked_pads));
gst_pad_set_setcaps_function (sel->srcpad,
GST_DEBUG_FUNCPTR (gst_stream_selector_setcaps));
gst_pad_set_getcaps_function (sel->srcpad,
GST_DEBUG_FUNCPTR (gst_stream_selector_get_caps));
GST_DEBUG_FUNCPTR (gst_stream_selector_getcaps));
gst_element_add_pad (GST_ELEMENT (sel), sel->srcpad);
/* sinkpad management */
sel->last_active_sinkpad = NULL;
sel->nb_sinkpads = 0;
sel->in_chain = FALSE;
//GST_FLAG_SET (sel, GST_ELEMENT_WORK_IN_PLACE);
}
static void
@ -158,23 +154,23 @@ gst_stream_selector_dispose (GObject * object)
}
static GstPad *
gst_stream_selector_get_linked_pad (GstPad * pad)
gst_stream_selector_get_linked_pad (GstPad * pad, gboolean strict)
{
GstStreamSelector *sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad));
GstPad *otherpad = NULL;
if (pad == sel->srcpad)
otherpad = sel->last_active_sinkpad;
else if (pad == sel->last_active_sinkpad)
else if (pad == sel->last_active_sinkpad || !strict)
otherpad = sel->srcpad;
return otherpad;
}
static GstCaps *
gst_stream_selector_get_caps (GstPad * pad)
gst_stream_selector_getcaps (GstPad * pad)
{
GstPad *otherpad = gst_stream_selector_get_linked_pad (pad);
GstPad *otherpad = gst_stream_selector_get_linked_pad (pad, FALSE);
if (!otherpad) {
GST_DEBUG_OBJECT (gst_pad_get_parent (pad),
@ -184,38 +180,16 @@ gst_stream_selector_get_caps (GstPad * pad)
}
GST_DEBUG_OBJECT (gst_pad_get_parent (pad),
"Pad %s is linked (to %s), returning peer-caps",
"Pad %s is linked (to %s), returning allowed-caps",
gst_pad_get_name (pad), gst_pad_get_name (otherpad));
return gst_pad_peer_get_caps (otherpad);
}
static gboolean
gst_stream_selector_setcaps (GstPad * pad, GstCaps * caps)
{
GstPad *otherpad = gst_stream_selector_get_linked_pad (pad);
if (!otherpad) {
GST_DEBUG_OBJECT (gst_pad_get_parent (pad),
"Pad %s not linked, returning %s",
gst_pad_get_name (pad), GST_PAD_IS_SINK (pad) ? "ok" : "delayed");
return FALSE;
}
GST_DEBUG_OBJECT (gst_pad_get_parent (pad),
"Pad %s is linked (to %s), returning other-trysetcaps",
gst_pad_get_name (pad), gst_pad_get_name (otherpad));
gst_pad_set_caps (otherpad, caps);
return TRUE;
}
static GList *
gst_stream_selector_get_linked_pads (GstPad * pad)
{
GstPad *otherpad = gst_stream_selector_get_linked_pad (pad);
GstPad *otherpad = gst_stream_selector_get_linked_pad (pad, TRUE);
if (!otherpad)
return NULL;
@ -242,34 +216,29 @@ gst_stream_selector_request_new_pad (GstElement * element,
g_free (name);
gst_pad_set_getcaps_function (sinkpad,
GST_DEBUG_FUNCPTR (gst_stream_selector_get_caps));
GST_DEBUG_FUNCPTR (gst_stream_selector_getcaps));
gst_pad_set_chain_function (sinkpad,
GST_DEBUG_FUNCPTR (gst_stream_selector_chain));
gst_pad_set_event_function (sinkpad,
GST_DEBUG_FUNCPTR (gst_stream_selector_event));
gst_pad_set_internal_link_function (sinkpad,
GST_DEBUG_FUNCPTR (gst_stream_selector_get_linked_pads));
gst_element_add_pad (GST_ELEMENT (sel), sinkpad);
GST_STATE_LOCK (sel);
if (GST_STATE (sel) >= GST_STATE_PAUSED) {
gst_pad_set_active (sinkpad, GST_ACTIVATE_PUSH);
}
GST_STATE_UNLOCK (sel);
return sinkpad;
}
static gboolean
gst_stream_selector_event (GstPad * pad, GstEvent * event)
{
GstStreamSelector *sel = GST_STREAM_SELECTOR (GST_PAD_PARENT (pad));
/* forward */
GST_DEBUG_OBJECT (sel, "Forwarding event %p from pad %s",
event, GST_OBJECT_NAME (pad));
return gst_pad_push_event (sel->srcpad, event);
}
static GstFlowReturn
gst_stream_selector_chain (GstPad * pad, GstBuffer * buffer)
gst_stream_selector_chain (GstPad * pad, GstBuffer * buf)
{
GstStreamSelector *sel = GST_STREAM_SELECTOR (GST_PAD_PARENT (pad));
GstStreamSelector *sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad));
GstFlowReturn res;
GST_STREAM_LOCK (pad);
/* first, check if the active pad changed. If so, redo
* negotiation and fail if that fails. */
@ -283,7 +252,10 @@ gst_stream_selector_chain (GstPad * pad, GstBuffer * buffer)
/* forward */
GST_DEBUG_OBJECT (sel, "Forwarding buffer %p from pad %s",
buffer, GST_OBJECT_NAME (pad));
"buf", gst_pad_get_name (pad));
res = gst_pad_push (sel->srcpad, buf);
return gst_pad_push (sel->srcpad, buffer);
GST_STREAM_UNLOCK (pad);
return res;
}

View file

@ -45,7 +45,6 @@ struct _GstStreamSelector {
GstPad *last_active_sinkpad;
GstPad *srcpad;
guint nb_sinkpads;
gboolean in_chain;
};
struct _GstStreamSelectorClass {