gst/playback/: Add sink padtemplate to decodebin.

Original commit message from CVS:
* gst/playback/gstdecodebin.c: (gst_decode_bin_class_init),
(gst_decode_bin_init), (find_compatibles), (close_pad_link),
(try_to_link_1), (no_more_pads), (close_link), (type_found):
* gst/playback/gstplaybasebin.c: (gen_preroll_element),
(remove_prerolls), (unknown_type), (add_element_stream),
(new_decoded_pad), (setup_source), (gst_play_base_bin_add_element),
(gst_play_base_bin_remove_element),
(gst_play_base_bin_link_stream):
* gst/playback/gstplaybin.c: (gen_video_element),
(gen_vis_element), (remove_sinks), (setup_sinks):
* gst/playback/gststreaminfo.c: (gst_stream_type_get_type),
(gst_stream_info_get_type), (gst_stream_info_class_init),
(gst_stream_info_init), (gst_stream_info_new),
(gst_stream_info_dispose), (stream_info_mute_pad),
(gst_stream_info_set_property), (gst_stream_info_get_property):
* gst/playback/gststreaminfo.h:
Add sink padtemplate to decodebin.
Added some more comments.
Make queue size configurable in playbasebin.
Added possibility to use elements as sinks (ex cdaudio).
This commit is contained in:
Wim Taymans 2004-10-18 13:40:48 +00:00
parent d3dbb10067
commit 216fb64b09
7 changed files with 180 additions and 45 deletions

View file

@ -1,3 +1,26 @@
2004-10-18 Wim Taymans <wim@fluendo.com>
* gst/playback/gstdecodebin.c: (gst_decode_bin_class_init),
(gst_decode_bin_init), (find_compatibles), (close_pad_link),
(try_to_link_1), (no_more_pads), (close_link), (type_found):
* gst/playback/gstplaybasebin.c: (gen_preroll_element),
(remove_prerolls), (unknown_type), (add_element_stream),
(new_decoded_pad), (setup_source), (gst_play_base_bin_add_element),
(gst_play_base_bin_remove_element),
(gst_play_base_bin_link_stream):
* gst/playback/gstplaybin.c: (gen_video_element),
(gen_vis_element), (remove_sinks), (setup_sinks):
* gst/playback/gststreaminfo.c: (gst_stream_type_get_type),
(gst_stream_info_get_type), (gst_stream_info_class_init),
(gst_stream_info_init), (gst_stream_info_new),
(gst_stream_info_dispose), (stream_info_mute_pad),
(gst_stream_info_set_property), (gst_stream_info_get_property):
* gst/playback/gststreaminfo.h:
Add sink padtemplate to decodebin.
Added some more comments.
Make queue size configurable in playbasebin.
Added possibility to use elements as sinks (ex cdaudio).
2004-10-15 Wim Taymans <wim@fluendo.com>
* ext/speex/gstspeexenc.c: (gst_speexenc_class_init),

View file

@ -40,6 +40,7 @@ playbin:
stream detected. implements seeking and querying on the configured sinks.
TODO
- visualisation
- reuse, refcounting, cleanup in READY state
- debugging
- error handling

View file

@ -25,13 +25,13 @@
#include <gst/gst.h>
/* generic templates */
GstStaticPadTemplate decoder_bin_sink_template =
static GstStaticPadTemplate decoder_bin_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
GstStaticPadTemplate decoder_bin_src_template =
static GstStaticPadTemplate decoder_bin_src_template =
GST_STATIC_PAD_TEMPLATE ("src%d",
GST_PAD_SRC,
GST_PAD_SOMETIMES,
@ -192,6 +192,8 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass)
gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_decode_bin_dispose);
gst_element_class_add_pad_template (gstelement_klass,
gst_static_pad_template_get (&decoder_bin_sink_template));
gst_element_class_add_pad_template (gstelement_klass,
gst_static_pad_template_get (&decoder_bin_src_template));

View file

@ -206,6 +206,11 @@ queue_overrun (GstElement * element, GstPlayBaseBin * play_base_bin)
g_mutex_unlock (play_base_bin->preroll_lock);
}
/* generate a preroll element which is simply a queue. While there
* are still dynamic elements in the pipeline, we wait for one
* of the queues to fill. The assumption is that all the dynamic
* streams will be detected by that time.
*/
static GstElement *
gen_preroll_element (GstPlayBaseBin * play_base_bin, GstPad * pad)
{
@ -217,9 +222,13 @@ gen_preroll_element (GstPlayBaseBin * play_base_bin, GstPad * pad)
element = gst_element_factory_make ("queue", name);
g_object_set (G_OBJECT (element), "max-size-buffers", 0, NULL);
g_object_set (G_OBJECT (element), "max-size-bytes", 0, NULL);
g_object_set (G_OBJECT (element), "max-size-time", 3 * GST_SECOND, NULL);
sig = g_signal_connect (G_OBJECT (element), "overrun",
g_object_set (G_OBJECT (element), "max-size-time", play_base_bin->queue_size,
NULL);
sig =
g_signal_connect (G_OBJECT (element), "overrun",
G_CALLBACK (queue_overrun), play_base_bin);
/* keep a ref to the signal id so that we can disconnect the signal callback
* when we are done with the preroll */
g_object_set_data (G_OBJECT (element), "signal_id", GINT_TO_POINTER (sig));
g_free (name);
@ -231,6 +240,7 @@ remove_prerolls (GstPlayBaseBin * play_base_bin)
{
GList *prerolls, *infos;
/* remove the preroll queues */
for (prerolls = play_base_bin->preroll_elems; prerolls;
prerolls = g_list_next (prerolls)) {
GstElement *element = GST_ELEMENT (prerolls->data);
@ -241,6 +251,7 @@ remove_prerolls (GstPlayBaseBin * play_base_bin)
g_list_free (play_base_bin->preroll_elems);
play_base_bin->preroll_elems = NULL;
/* free the streaminfo too */
for (infos = play_base_bin->streaminfo; infos; infos = g_list_next (infos)) {
GstStreamInfo *info = GST_STREAM_INFO (infos->data);
@ -254,6 +265,9 @@ remove_prerolls (GstPlayBaseBin * play_base_bin)
play_base_bin->nunknownpads = 0;
}
/* signal fired when an unknown stream is found. We create a new
* UNKNOWN streaminfo object
*/
static void
unknown_type (GstElement * element, GstPad * pad, GstCaps * caps,
GstPlayBaseBin * play_base_bin)
@ -265,12 +279,31 @@ unknown_type (GstElement * element, GstPad * pad, GstCaps * caps,
g_warning ("don't know how to handle %s", capsstr);
/* add the stream to the list */
info = gst_stream_info_new (pad, GST_STREAM_TYPE_UNKNOWN, NULL);
info = gst_stream_info_new (GST_OBJECT (pad), GST_STREAM_TYPE_UNKNOWN, NULL);
play_base_bin->streaminfo = g_list_append (play_base_bin->streaminfo, info);
g_free (capsstr);
}
/* add a streaminfo that indicates that the stream is handled by the
* given element. This usually means that a stream without actual data is
* produced but one that is sunken by an element. Examples of this are:
* cdaudio, a hardware decoder/sink, dvd meta bins etc...
*/
static void
add_element_stream (GstElement * element, GstPlayBaseBin * play_base_bin)
{
GstStreamInfo *info;
/* add the stream to the list */
info =
gst_stream_info_new (GST_OBJECT (element), GST_STREAM_TYPE_ELEMENT, NULL);
play_base_bin->streaminfo = g_list_append (play_base_bin->streaminfo, info);
}
/* when the decoder element signals that no more pads will be generated, we
* can stop the preroll
*/
static void
no_more_pads (GstElement * element, GstPlayBaseBin * play_base_bin)
{
@ -282,6 +315,9 @@ no_more_pads (GstElement * element, GstPlayBaseBin * play_base_bin)
g_mutex_unlock (play_base_bin->preroll_lock);
}
/* signal fired when decodebin has found a new raw pad. We create
* a preroll element if needed and the appropriate streaminfo.
*/
static void
new_decoded_pad (GstElement * element, GstPad * pad, gboolean last,
GstPlayBaseBin * play_base_bin)
@ -297,13 +333,14 @@ new_decoded_pad (GstElement * element, GstPad * pad, gboolean last,
GST_DEBUG ("play base: new decoded pad %d", last);
/* first see if this pad has interesting caps */
caps = gst_pad_get_caps (pad);
if (gst_caps_is_empty (caps)) {
if (caps == NULL || gst_caps_is_empty (caps)) {
g_warning ("no type on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
return;
}
/* get the mime type */
structure = gst_caps_get_structure (caps, 0);
mimetype = gst_structure_get_name (structure);
@ -352,7 +389,7 @@ new_decoded_pad (GstElement * element, GstPad * pad, gboolean last,
}
/* add the stream to the list */
info = gst_stream_info_new (srcpad, type, NULL);
info = gst_stream_info_new (GST_OBJECT (srcpad), type, NULL);
play_base_bin->streaminfo = g_list_append (play_base_bin->streaminfo, info);
/* signal the no more pads after adding the stream */
@ -360,6 +397,10 @@ new_decoded_pad (GstElement * element, GstPad * pad, gboolean last,
no_more_pads (NULL, play_base_bin);
}
/* signal fired when the internal thread performed an unexpected
* state change. This usually indicated an error occured. We stop the
* preroll stage.
*/
static void
state_change (GstElement * element,
GstElementState old_state, GstElementState new_state, gpointer data)
@ -377,6 +418,9 @@ state_change (GstElement * element,
}
}
/* construct and run the source and decoder elements until we found
* all the streams or until a preroll queue has been filled.
*/
static gboolean
setup_source (GstPlayBaseBin * play_base_bin)
{
@ -387,14 +431,15 @@ setup_source (GstPlayBaseBin * play_base_bin)
if (!play_base_bin->need_rebuild)
return TRUE;
/* keep ref to old souce in case creating the new source fails */
old_src = play_base_bin->source;
/* create and configure an element that can handle the uri
*/
/* create and configure an element that can handle the uri */
play_base_bin->source =
gst_element_make_from_uri (GST_URI_SRC, play_base_bin->uri, "source");
if (!play_base_bin->source) {
/* whoops, could not create the source element */
g_warning ("don't know how to read %s", play_base_bin->uri);
play_base_bin->source = old_src;
return FALSE;
@ -404,27 +449,35 @@ setup_source (GstPlayBaseBin * play_base_bin)
gst_bin_remove (GST_BIN (play_base_bin->thread), old_src);
}
gst_bin_add (GST_BIN (play_base_bin->thread), play_base_bin->source);
/* make sure the new element has the same state as the parent */
if (gst_bin_sync_children_state (GST_BIN (play_base_bin->thread)) ==
GST_STATE_FAILURE) {
return FALSE;
}
}
/* remove the old decoder now, if any */
old_dec = play_base_bin->decoder;
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);
}
/* remove our previous preroll queues */
remove_prerolls (play_base_bin);
/* now see if the source element emits raw audio/video all by itself,
* if so, we can create streams for the pads and be done with it
* if so, we can create streams for the pads and be done with it.
* Also check that is has source pads, if now, we assume it will
* do everything itself.
*/
{
const GList *pads;
gboolean is_raw = FALSE;
/* assume we are going to have no output streams */
gboolean no_out = TRUE;
for (pads = gst_element_get_pad_list (play_base_bin->source);
pads; pads = g_list_next (pads)) {
GstPad *pad = GST_PAD (pads->data);
@ -435,6 +488,8 @@ setup_source (GstPlayBaseBin * play_base_bin)
if (GST_PAD_IS_SINK (pad))
continue;
no_out = FALSE;
srcpad = pad;
caps = gst_pad_get_caps (pad);
@ -449,28 +504,25 @@ setup_source (GstPlayBaseBin * play_base_bin)
g_str_has_prefix (mimetype, "video/x-raw")) {
new_decoded_pad (play_base_bin->source, pad, g_list_next (pads) == NULL,
play_base_bin);
is_raw = TRUE;
}
}
if (is_raw) {
return TRUE;
}
}
if (srcpad == NULL) {
/* FIXME we do not handle this yet, but we should just make sure that
* we don't error on this because there is no streaminfo. A possible element
* without any source pads could be cdaudio, which just plays an audio cd
*/
GST_DEBUG_OBJECT (play_base_bin, "have source element without source pad");
return FALSE;
if (no_out) {
/* create a stream to indicate that this uri is handled by a self
* contained element */
add_element_stream (play_base_bin->source, play_base_bin);
return TRUE;
}
}
{
gboolean res;
gint sig1, sig2, sig3, sig4;
/* now create the decoder element */
play_base_bin->decoder = gst_element_factory_make ("decodebin", "decoder");
if (!play_base_bin->decoder) {
g_warning ("can't find decoder element");
@ -710,6 +762,9 @@ gst_play_base_bin_change_state (GstElement * element)
return ret;
}
/* virtual function to add elements to this bin. The idea is to
* wrap the element in a thread automatically.
*/
static void
gst_play_base_bin_add_element (GstBin * bin, GstElement * element)
{
@ -734,7 +789,7 @@ gst_play_base_bin_add_element (GstBin * bin, GstElement * element)
}
gst_bin_add (GST_BIN (play_base_bin->thread), element);
/* hack */
/* hack, the clock is not correctly distributed in the core */
sched = gst_element_get_scheduler (GST_ELEMENT (play_base_bin->thread));
clock = gst_scheduler_get_clock (sched);
gst_scheduler_set_clock (sched, clock);
@ -748,6 +803,10 @@ gst_play_base_bin_add_element (GstBin * bin, GstElement * element)
}
}
/* virtual function to remove an element from this bin. We have to make
* sure that we also remove the thread that we used as a container for
* this element.
*/
static void
gst_play_base_bin_remove_element (GstBin * bin, GstElement * element)
{
@ -767,14 +826,18 @@ gst_play_base_bin_remove_element (GstBin * bin, GstElement * element)
if (!thread) {
g_warning ("cannot find element to remove");
} else {
/* we remove the element from the thread first so that the
* state is not affected when someone holds a reference to it */
gst_bin_remove (GST_BIN (thread), element);
if (gst_element_get_parent (element) == GST_OBJECT (thread)) {
/* we remove the element from the thread first so that the
* state is not affected when someone holds a reference to it */
gst_bin_remove (GST_BIN (thread), element);
}
element = thread;
}
}
GST_LOG ("removing element %s", gst_element_get_name (element));
gst_bin_remove (GST_BIN (play_base_bin->thread), element);
if (gst_element_get_parent (element) == GST_OBJECT (play_base_bin->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");
}
@ -839,17 +902,20 @@ gst_play_base_bin_link_stream (GstPlayBaseBin * play_base_bin,
streams = g_list_next (streams)) {
GstStreamInfo *sinfo = (GstStreamInfo *) streams->data;
if (gst_pad_is_linked (sinfo->pad))
if (sinfo->type == GST_STREAM_TYPE_ELEMENT)
continue;
if (gst_pad_can_link (sinfo->pad, pad)) {
if (gst_pad_is_linked (GST_PAD (sinfo->object)))
continue;
if (gst_pad_can_link (GST_PAD (sinfo->object), pad)) {
info = sinfo;
break;
}
}
}
if (info) {
if (!gst_pad_link (info->pad, pad)) {
if (!gst_pad_link (GST_PAD (info->object), pad)) {
GST_DEBUG ("could not link");
g_object_set (G_OBJECT (info), "mute", TRUE, NULL);
}

View file

@ -111,7 +111,7 @@ static GstElementDetails gst_play_bin_details = {
"Player Bin",
"Generic/Bin/Player",
"Autoplug and play media from an uri",
"Wim Taymans <wim.taymans@chello.be>"
"Wim Taymans <wim@fluendo.com>"
};
@ -306,6 +306,9 @@ gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
}
}
/* signal fired when the identity has received a new buffer. This is used for
* making screenshots.
*/
static void
handoff (GstElement * identity, GstBuffer * frame, gpointer data)
{
@ -317,6 +320,9 @@ handoff (GstElement * identity, GstBuffer * frame, gpointer data)
play_bin->frame = gst_buffer_ref (frame);
}
/* make the element (bin) that contains the elements needed to perform
* video display/
*/
static GstElement *
gen_video_element (GstPlayBin * play_bin)
{
@ -326,9 +332,12 @@ gen_video_element (GstPlayBin * play_bin)
GstElement *sink;
GstElement *identity;
/* first see if we have it in the cache */
element = g_hash_table_lookup (play_bin->cache, "vbin");
if (element != NULL) {
g_object_ref (G_OBJECT (element));
/* 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;
}
@ -492,6 +501,9 @@ remove_sinks (GstPlayBin * play_bin)
if (element != NULL) {
parent = gst_element_get_parent (element);
if (parent != NULL) {
/* we remove the element from the parent so that
* there is no unwanted state change when the parent
* is disposed */
gst_bin_remove (GST_BIN (parent), element);
}
}
@ -520,6 +532,9 @@ remove_sinks (GstPlayBin * play_bin)
}
}
/* loop over the streams and set up the pipeline to play this
* media file
*/
static void
setup_sinks (GstPlayBin * play_bin)
{
@ -539,8 +554,14 @@ setup_sinks (GstPlayBin * play_bin)
GstPad *srcpad;
g_object_get (obj, "type", &type, NULL);
g_object_get (obj, "pad", &srcpad, NULL);
/* we don't care about streams with their own sink */
if (type == 4)
continue;
/* else we need to get the pad */
g_object_get (obj, "object", &srcpad, NULL);
/* hmm.. pad is allready linked */
if (gst_pad_is_linked (srcpad))
continue;
@ -558,6 +579,7 @@ setup_sinks (GstPlayBin * play_bin)
num_audio = 0;
num_video = 0;
/* now actually connect everything */
for (s = streaminfo; s; s = g_list_next (s)) {
GObject *obj = G_OBJECT (s->data);
gint type;
@ -565,9 +587,18 @@ setup_sinks (GstPlayBin * play_bin)
GstElement *sink = NULL;
gboolean res;
gboolean mute = FALSE;
GstObject *object;
g_object_get (obj, "type", &type, NULL);
g_object_get (obj, "pad", &srcpad, 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);
continue;
}
srcpad = GST_PAD (object);
if (gst_pad_is_linked (srcpad))
continue;
@ -592,6 +623,8 @@ setup_sinks (GstPlayBin * play_bin)
sink = gen_video_element (play_bin);
num_video++;
}
} else if (type == 4) {
/* we can ignore these streams here */
} else {
g_warning ("unknown stream found");
mute = TRUE;

View file

@ -53,6 +53,9 @@ gst_stream_type_get_type (void)
{GST_STREAM_TYPE_UNKNOWN, "GST_STREAM_TYPE_UNKNOWN", "Unknown stream"},
{GST_STREAM_TYPE_AUDIO, "GST_STREAM_TYPE_AUDIO", "Audio stream"},
{GST_STREAM_TYPE_VIDEO, "GST_STREAM_TYPE_VIDEO", "Video stream"},
{GST_STREAM_TYPE_TEXT, "GST_STREAM_TYPE_TEXT", "Text stream"},
{GST_STREAM_TYPE_ELEMENT, "GST_STREAM_TYPE_ELEMENT",
"Stream handled by element"},
{0, NULL, NULL},
};
@ -113,8 +116,9 @@ gst_stream_info_class_init (GstStreamInfoClass * klass)
gobject_klass->get_property = gst_stream_info_get_property;
g_object_class_install_property (gobject_klass, ARG_PAD,
g_param_spec_object ("pad", "Pad", "Source Pad of the stream",
GST_TYPE_PAD, G_PARAM_READABLE));
g_param_spec_object ("object", "object",
"Source Pad or object of the stream", GST_TYPE_OBJECT,
G_PARAM_READABLE));
g_object_class_install_property (gobject_klass, ARG_TYPE,
g_param_spec_enum ("type", "Type", "Type of the stream",
GST_TYPE_STREAM_TYPE, GST_STREAM_TYPE_UNKNOWN, G_PARAM_READABLE));
@ -137,21 +141,21 @@ gst_stream_info_class_init (GstStreamInfoClass * klass)
static void
gst_stream_info_init (GstStreamInfo * stream_info)
{
stream_info->pad = NULL;
stream_info->object = NULL;
stream_info->type = GST_STREAM_TYPE_UNKNOWN;
stream_info->decoder = NULL;
stream_info->mute = FALSE;
}
GstStreamInfo *
gst_stream_info_new (GstPad * pad, GstStreamType type, gchar * decoder)
gst_stream_info_new (GstObject * object, GstStreamType type, gchar * decoder)
{
GstStreamInfo *info;
info = g_object_new (GST_TYPE_STREAM_INFO, NULL);
gst_object_ref (GST_OBJECT (pad));
info->pad = pad;
gst_object_ref (object);
info->object = object;
info->type = type;
info->decoder = g_strdup (decoder);
@ -165,8 +169,8 @@ gst_stream_info_dispose (GObject * object)
stream_info = GST_STREAM_INFO (object);
gst_object_unref (GST_OBJECT (stream_info->pad));
stream_info->pad = NULL;
gst_object_unref (stream_info->object);
stream_info->object = NULL;
stream_info->type = GST_STREAM_TYPE_UNKNOWN;
g_free (stream_info->decoder);
@ -222,11 +226,16 @@ gst_stream_info_set_property (GObject * object, guint prop_id,
switch (prop_id) {
case ARG_MUTE:
{
if (stream_info->type == GST_STREAM_TYPE_ELEMENT) {
g_warning ("cannot mute element stream");
break;
}
gboolean new_mute = g_value_get_boolean (value);
if (new_mute != stream_info->mute) {
stream_info->mute = new_mute;
stream_info_mute_pad (stream_info, stream_info->pad, new_mute);
stream_info_mute_pad (stream_info, GST_PAD (stream_info->object),
new_mute);
}
break;
}
@ -248,7 +257,7 @@ gst_stream_info_get_property (GObject * object, guint prop_id, GValue * value,
switch (prop_id) {
case ARG_PAD:
g_value_set_object (value, stream_info->pad);
g_value_set_object (value, stream_info->object);
break;
case ARG_TYPE:
g_value_set_enum (value, stream_info->type);

View file

@ -39,12 +39,13 @@ typedef enum {
GST_STREAM_TYPE_AUDIO = 1,
GST_STREAM_TYPE_VIDEO = 2,
GST_STREAM_TYPE_TEXT = 3,
GST_STREAM_TYPE_ELEMENT = 4,
} GstStreamType;
struct _GstStreamInfo {
GObject parent;
GstPad *pad;
GstObject *object;
GstStreamType type;
gchar *decoder;
gboolean mute;
@ -59,7 +60,7 @@ struct _GstStreamInfoClass {
GType gst_stream_info_get_type (void);
GstStreamInfo* gst_stream_info_new (GstPad *pad, GstStreamType type, gchar *decoder);
GstStreamInfo* gst_stream_info_new (GstObject *object, GstStreamType type, gchar *decoder);
G_END_DECLS