mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-24 02:31:03 +00:00
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:
parent
d3dbb10067
commit
216fb64b09
7 changed files with 180 additions and 45 deletions
23
ChangeLog
23
ChangeLog
|
@ -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>
|
2004-10-15 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
* ext/speex/gstspeexenc.c: (gst_speexenc_class_init),
|
* ext/speex/gstspeexenc.c: (gst_speexenc_class_init),
|
||||||
|
|
|
@ -40,6 +40,7 @@ playbin:
|
||||||
stream detected. implements seeking and querying on the configured sinks.
|
stream detected. implements seeking and querying on the configured sinks.
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
- visualisation
|
||||||
- reuse, refcounting, cleanup in READY state
|
- reuse, refcounting, cleanup in READY state
|
||||||
- debugging
|
- debugging
|
||||||
- error handling
|
- error handling
|
||||||
|
|
|
@ -25,13 +25,13 @@
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
/* generic templates */
|
/* generic templates */
|
||||||
GstStaticPadTemplate decoder_bin_sink_template =
|
static GstStaticPadTemplate decoder_bin_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS_ANY);
|
GST_STATIC_CAPS_ANY);
|
||||||
|
|
||||||
GstStaticPadTemplate decoder_bin_src_template =
|
static GstStaticPadTemplate decoder_bin_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src%d",
|
GST_STATIC_PAD_TEMPLATE ("src%d",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_SOMETIMES,
|
GST_PAD_SOMETIMES,
|
||||||
|
@ -192,6 +192,8 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass)
|
||||||
|
|
||||||
gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_decode_bin_dispose);
|
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_element_class_add_pad_template (gstelement_klass,
|
||||||
gst_static_pad_template_get (&decoder_bin_src_template));
|
gst_static_pad_template_get (&decoder_bin_src_template));
|
||||||
|
|
||||||
|
|
|
@ -206,6 +206,11 @@ queue_overrun (GstElement * element, GstPlayBaseBin * play_base_bin)
|
||||||
g_mutex_unlock (play_base_bin->preroll_lock);
|
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 *
|
static GstElement *
|
||||||
gen_preroll_element (GstPlayBaseBin * play_base_bin, GstPad * pad)
|
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);
|
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-buffers", 0, NULL);
|
||||||
g_object_set (G_OBJECT (element), "max-size-bytes", 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);
|
g_object_set (G_OBJECT (element), "max-size-time", play_base_bin->queue_size,
|
||||||
sig = g_signal_connect (G_OBJECT (element), "overrun",
|
NULL);
|
||||||
|
sig =
|
||||||
|
g_signal_connect (G_OBJECT (element), "overrun",
|
||||||
G_CALLBACK (queue_overrun), play_base_bin);
|
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_object_set_data (G_OBJECT (element), "signal_id", GINT_TO_POINTER (sig));
|
||||||
g_free (name);
|
g_free (name);
|
||||||
|
|
||||||
|
@ -231,6 +240,7 @@ remove_prerolls (GstPlayBaseBin * play_base_bin)
|
||||||
{
|
{
|
||||||
GList *prerolls, *infos;
|
GList *prerolls, *infos;
|
||||||
|
|
||||||
|
/* remove the preroll queues */
|
||||||
for (prerolls = play_base_bin->preroll_elems; prerolls;
|
for (prerolls = play_base_bin->preroll_elems; prerolls;
|
||||||
prerolls = g_list_next (prerolls)) {
|
prerolls = g_list_next (prerolls)) {
|
||||||
GstElement *element = GST_ELEMENT (prerolls->data);
|
GstElement *element = GST_ELEMENT (prerolls->data);
|
||||||
|
@ -241,6 +251,7 @@ remove_prerolls (GstPlayBaseBin * play_base_bin)
|
||||||
g_list_free (play_base_bin->preroll_elems);
|
g_list_free (play_base_bin->preroll_elems);
|
||||||
play_base_bin->preroll_elems = NULL;
|
play_base_bin->preroll_elems = NULL;
|
||||||
|
|
||||||
|
/* free the streaminfo too */
|
||||||
for (infos = play_base_bin->streaminfo; infos; infos = g_list_next (infos)) {
|
for (infos = play_base_bin->streaminfo; infos; infos = g_list_next (infos)) {
|
||||||
GstStreamInfo *info = GST_STREAM_INFO (infos->data);
|
GstStreamInfo *info = GST_STREAM_INFO (infos->data);
|
||||||
|
|
||||||
|
@ -254,6 +265,9 @@ remove_prerolls (GstPlayBaseBin * play_base_bin)
|
||||||
play_base_bin->nunknownpads = 0;
|
play_base_bin->nunknownpads = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* signal fired when an unknown stream is found. We create a new
|
||||||
|
* UNKNOWN streaminfo object
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
unknown_type (GstElement * element, GstPad * pad, GstCaps * caps,
|
unknown_type (GstElement * element, GstPad * pad, GstCaps * caps,
|
||||||
GstPlayBaseBin * play_base_bin)
|
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);
|
g_warning ("don't know how to handle %s", capsstr);
|
||||||
|
|
||||||
/* add the stream to the list */
|
/* 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);
|
play_base_bin->streaminfo = g_list_append (play_base_bin->streaminfo, info);
|
||||||
|
|
||||||
g_free (capsstr);
|
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
|
static void
|
||||||
no_more_pads (GstElement * element, GstPlayBaseBin * play_base_bin)
|
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);
|
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
|
static void
|
||||||
new_decoded_pad (GstElement * element, GstPad * pad, gboolean last,
|
new_decoded_pad (GstElement * element, GstPad * pad, gboolean last,
|
||||||
GstPlayBaseBin * play_base_bin)
|
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);
|
GST_DEBUG ("play base: new decoded pad %d", last);
|
||||||
|
|
||||||
|
/* first see if this pad has interesting caps */
|
||||||
caps = gst_pad_get_caps (pad);
|
caps = gst_pad_get_caps (pad);
|
||||||
|
if (caps == NULL || gst_caps_is_empty (caps)) {
|
||||||
if (gst_caps_is_empty (caps)) {
|
|
||||||
g_warning ("no type on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
|
g_warning ("no type on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* get the mime type */
|
||||||
structure = gst_caps_get_structure (caps, 0);
|
structure = gst_caps_get_structure (caps, 0);
|
||||||
mimetype = gst_structure_get_name (structure);
|
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 */
|
/* 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);
|
play_base_bin->streaminfo = g_list_append (play_base_bin->streaminfo, info);
|
||||||
|
|
||||||
/* signal the no more pads after adding the stream */
|
/* 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);
|
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
|
static void
|
||||||
state_change (GstElement * element,
|
state_change (GstElement * element,
|
||||||
GstElementState old_state, GstElementState new_state, gpointer data)
|
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
|
static gboolean
|
||||||
setup_source (GstPlayBaseBin * play_base_bin)
|
setup_source (GstPlayBaseBin * play_base_bin)
|
||||||
{
|
{
|
||||||
|
@ -387,14 +431,15 @@ setup_source (GstPlayBaseBin * play_base_bin)
|
||||||
if (!play_base_bin->need_rebuild)
|
if (!play_base_bin->need_rebuild)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
/* keep ref to old souce in case creating the new source fails */
|
||||||
old_src = play_base_bin->source;
|
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 =
|
play_base_bin->source =
|
||||||
gst_element_make_from_uri (GST_URI_SRC, play_base_bin->uri, "source");
|
gst_element_make_from_uri (GST_URI_SRC, play_base_bin->uri, "source");
|
||||||
|
|
||||||
if (!play_base_bin->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);
|
g_warning ("don't know how to read %s", play_base_bin->uri);
|
||||||
play_base_bin->source = old_src;
|
play_base_bin->source = old_src;
|
||||||
return FALSE;
|
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_remove (GST_BIN (play_base_bin->thread), old_src);
|
||||||
}
|
}
|
||||||
gst_bin_add (GST_BIN (play_base_bin->thread), play_base_bin->source);
|
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)) ==
|
if (gst_bin_sync_children_state (GST_BIN (play_base_bin->thread)) ==
|
||||||
GST_STATE_FAILURE) {
|
GST_STATE_FAILURE) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* remove the old decoder now, if any */
|
||||||
old_dec = play_base_bin->decoder;
|
old_dec = play_base_bin->decoder;
|
||||||
if (old_dec) {
|
if (old_dec) {
|
||||||
GST_LOG ("removing old decoder element %s", gst_element_get_name (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_remove (GST_BIN (play_base_bin->thread), old_dec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* remove our previous preroll queues */
|
||||||
remove_prerolls (play_base_bin);
|
remove_prerolls (play_base_bin);
|
||||||
|
|
||||||
/* now see if the source element emits raw audio/video all by itself,
|
/* 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;
|
const GList *pads;
|
||||||
gboolean is_raw = FALSE;
|
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);
|
for (pads = gst_element_get_pad_list (play_base_bin->source);
|
||||||
pads; pads = g_list_next (pads)) {
|
pads; pads = g_list_next (pads)) {
|
||||||
GstPad *pad = GST_PAD (pads->data);
|
GstPad *pad = GST_PAD (pads->data);
|
||||||
|
@ -435,6 +488,8 @@ setup_source (GstPlayBaseBin * play_base_bin)
|
||||||
if (GST_PAD_IS_SINK (pad))
|
if (GST_PAD_IS_SINK (pad))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
no_out = FALSE;
|
||||||
|
|
||||||
srcpad = pad;
|
srcpad = pad;
|
||||||
caps = gst_pad_get_caps (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")) {
|
g_str_has_prefix (mimetype, "video/x-raw")) {
|
||||||
new_decoded_pad (play_base_bin->source, pad, g_list_next (pads) == NULL,
|
new_decoded_pad (play_base_bin->source, pad, g_list_next (pads) == NULL,
|
||||||
play_base_bin);
|
play_base_bin);
|
||||||
|
|
||||||
is_raw = TRUE;
|
is_raw = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_raw) {
|
if (is_raw) {
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
if (no_out) {
|
||||||
|
/* create a stream to indicate that this uri is handled by a self
|
||||||
if (srcpad == NULL) {
|
* contained element */
|
||||||
/* FIXME we do not handle this yet, but we should just make sure that
|
add_element_stream (play_base_bin->source, play_base_bin);
|
||||||
* we don't error on this because there is no streaminfo. A possible element
|
return TRUE;
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
gboolean res;
|
gboolean res;
|
||||||
gint sig1, sig2, sig3, sig4;
|
gint sig1, sig2, sig3, sig4;
|
||||||
|
|
||||||
|
/* now create the decoder element */
|
||||||
play_base_bin->decoder = gst_element_factory_make ("decodebin", "decoder");
|
play_base_bin->decoder = gst_element_factory_make ("decodebin", "decoder");
|
||||||
if (!play_base_bin->decoder) {
|
if (!play_base_bin->decoder) {
|
||||||
g_warning ("can't find decoder element");
|
g_warning ("can't find decoder element");
|
||||||
|
@ -710,6 +762,9 @@ gst_play_base_bin_change_state (GstElement * element)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* virtual function to add elements to this bin. The idea is to
|
||||||
|
* wrap the element in a thread automatically.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
gst_play_base_bin_add_element (GstBin * bin, GstElement * element)
|
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);
|
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));
|
sched = gst_element_get_scheduler (GST_ELEMENT (play_base_bin->thread));
|
||||||
clock = gst_scheduler_get_clock (sched);
|
clock = gst_scheduler_get_clock (sched);
|
||||||
gst_scheduler_set_clock (sched, clock);
|
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
|
static void
|
||||||
gst_play_base_bin_remove_element (GstBin * bin, GstElement * element)
|
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) {
|
if (!thread) {
|
||||||
g_warning ("cannot find element to remove");
|
g_warning ("cannot find element to remove");
|
||||||
} else {
|
} else {
|
||||||
/* we remove the element from the thread first so that the
|
if (gst_element_get_parent (element) == GST_OBJECT (thread)) {
|
||||||
* state is not affected when someone holds a reference to it */
|
/* we remove the element from the thread first so that the
|
||||||
gst_bin_remove (GST_BIN (thread), element);
|
* state is not affected when someone holds a reference to it */
|
||||||
|
gst_bin_remove (GST_BIN (thread), element);
|
||||||
|
}
|
||||||
element = thread;
|
element = thread;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GST_LOG ("removing element %s", gst_element_get_name (element));
|
if (gst_element_get_parent (element) == GST_OBJECT (play_base_bin->thread)) {
|
||||||
gst_bin_remove (GST_BIN (play_base_bin->thread), element);
|
GST_LOG ("removing element %s", gst_element_get_name (element));
|
||||||
|
gst_bin_remove (GST_BIN (play_base_bin->thread), element);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
g_warning ("removing elements is not allowed in NULL");
|
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)) {
|
streams = g_list_next (streams)) {
|
||||||
GstStreamInfo *sinfo = (GstStreamInfo *) streams->data;
|
GstStreamInfo *sinfo = (GstStreamInfo *) streams->data;
|
||||||
|
|
||||||
if (gst_pad_is_linked (sinfo->pad))
|
if (sinfo->type == GST_STREAM_TYPE_ELEMENT)
|
||||||
continue;
|
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;
|
info = sinfo;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (info) {
|
if (info) {
|
||||||
if (!gst_pad_link (info->pad, pad)) {
|
if (!gst_pad_link (GST_PAD (info->object), pad)) {
|
||||||
GST_DEBUG ("could not link");
|
GST_DEBUG ("could not link");
|
||||||
g_object_set (G_OBJECT (info), "mute", TRUE, NULL);
|
g_object_set (G_OBJECT (info), "mute", TRUE, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,7 +111,7 @@ static GstElementDetails gst_play_bin_details = {
|
||||||
"Player Bin",
|
"Player Bin",
|
||||||
"Generic/Bin/Player",
|
"Generic/Bin/Player",
|
||||||
"Autoplug and play media from an uri",
|
"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
|
static void
|
||||||
handoff (GstElement * identity, GstBuffer * frame, gpointer data)
|
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);
|
play_bin->frame = gst_buffer_ref (frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* make the element (bin) that contains the elements needed to perform
|
||||||
|
* video display/
|
||||||
|
*/
|
||||||
static GstElement *
|
static GstElement *
|
||||||
gen_video_element (GstPlayBin * play_bin)
|
gen_video_element (GstPlayBin * play_bin)
|
||||||
{
|
{
|
||||||
|
@ -326,9 +332,12 @@ gen_video_element (GstPlayBin * play_bin)
|
||||||
GstElement *sink;
|
GstElement *sink;
|
||||||
GstElement *identity;
|
GstElement *identity;
|
||||||
|
|
||||||
|
/* first see if we have it in the cache */
|
||||||
element = g_hash_table_lookup (play_bin->cache, "vbin");
|
element = g_hash_table_lookup (play_bin->cache, "vbin");
|
||||||
if (element != NULL) {
|
if (element != NULL) {
|
||||||
g_object_ref (G_OBJECT (element));
|
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");
|
sink = g_hash_table_lookup (play_bin->cache, "video_sink");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -492,6 +501,9 @@ remove_sinks (GstPlayBin * play_bin)
|
||||||
if (element != NULL) {
|
if (element != NULL) {
|
||||||
parent = gst_element_get_parent (element);
|
parent = gst_element_get_parent (element);
|
||||||
if (parent != NULL) {
|
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);
|
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
|
static void
|
||||||
setup_sinks (GstPlayBin * play_bin)
|
setup_sinks (GstPlayBin * play_bin)
|
||||||
{
|
{
|
||||||
|
@ -539,8 +554,14 @@ setup_sinks (GstPlayBin * play_bin)
|
||||||
GstPad *srcpad;
|
GstPad *srcpad;
|
||||||
|
|
||||||
g_object_get (obj, "type", &type, NULL);
|
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))
|
if (gst_pad_is_linked (srcpad))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -558,6 +579,7 @@ setup_sinks (GstPlayBin * play_bin)
|
||||||
num_audio = 0;
|
num_audio = 0;
|
||||||
num_video = 0;
|
num_video = 0;
|
||||||
|
|
||||||
|
/* now actually connect everything */
|
||||||
for (s = streaminfo; s; s = g_list_next (s)) {
|
for (s = streaminfo; s; s = g_list_next (s)) {
|
||||||
GObject *obj = G_OBJECT (s->data);
|
GObject *obj = G_OBJECT (s->data);
|
||||||
gint type;
|
gint type;
|
||||||
|
@ -565,9 +587,18 @@ setup_sinks (GstPlayBin * play_bin)
|
||||||
GstElement *sink = NULL;
|
GstElement *sink = NULL;
|
||||||
gboolean res;
|
gboolean res;
|
||||||
gboolean mute = FALSE;
|
gboolean mute = FALSE;
|
||||||
|
GstObject *object;
|
||||||
|
|
||||||
g_object_get (obj, "type", &type, NULL);
|
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))
|
if (gst_pad_is_linked (srcpad))
|
||||||
continue;
|
continue;
|
||||||
|
@ -592,6 +623,8 @@ setup_sinks (GstPlayBin * play_bin)
|
||||||
sink = gen_video_element (play_bin);
|
sink = gen_video_element (play_bin);
|
||||||
num_video++;
|
num_video++;
|
||||||
}
|
}
|
||||||
|
} else if (type == 4) {
|
||||||
|
/* we can ignore these streams here */
|
||||||
} else {
|
} else {
|
||||||
g_warning ("unknown stream found");
|
g_warning ("unknown stream found");
|
||||||
mute = TRUE;
|
mute = TRUE;
|
||||||
|
|
|
@ -53,6 +53,9 @@ gst_stream_type_get_type (void)
|
||||||
{GST_STREAM_TYPE_UNKNOWN, "GST_STREAM_TYPE_UNKNOWN", "Unknown stream"},
|
{GST_STREAM_TYPE_UNKNOWN, "GST_STREAM_TYPE_UNKNOWN", "Unknown stream"},
|
||||||
{GST_STREAM_TYPE_AUDIO, "GST_STREAM_TYPE_AUDIO", "Audio stream"},
|
{GST_STREAM_TYPE_AUDIO, "GST_STREAM_TYPE_AUDIO", "Audio stream"},
|
||||||
{GST_STREAM_TYPE_VIDEO, "GST_STREAM_TYPE_VIDEO", "Video 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},
|
{0, NULL, NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -113,8 +116,9 @@ gst_stream_info_class_init (GstStreamInfoClass * klass)
|
||||||
gobject_klass->get_property = gst_stream_info_get_property;
|
gobject_klass->get_property = gst_stream_info_get_property;
|
||||||
|
|
||||||
g_object_class_install_property (gobject_klass, ARG_PAD,
|
g_object_class_install_property (gobject_klass, ARG_PAD,
|
||||||
g_param_spec_object ("pad", "Pad", "Source Pad of the stream",
|
g_param_spec_object ("object", "object",
|
||||||
GST_TYPE_PAD, G_PARAM_READABLE));
|
"Source Pad or object of the stream", GST_TYPE_OBJECT,
|
||||||
|
G_PARAM_READABLE));
|
||||||
g_object_class_install_property (gobject_klass, ARG_TYPE,
|
g_object_class_install_property (gobject_klass, ARG_TYPE,
|
||||||
g_param_spec_enum ("type", "Type", "Type of the stream",
|
g_param_spec_enum ("type", "Type", "Type of the stream",
|
||||||
GST_TYPE_STREAM_TYPE, GST_STREAM_TYPE_UNKNOWN, G_PARAM_READABLE));
|
GST_TYPE_STREAM_TYPE, GST_STREAM_TYPE_UNKNOWN, G_PARAM_READABLE));
|
||||||
|
@ -137,21 +141,21 @@ gst_stream_info_class_init (GstStreamInfoClass * klass)
|
||||||
static void
|
static void
|
||||||
gst_stream_info_init (GstStreamInfo * stream_info)
|
gst_stream_info_init (GstStreamInfo * stream_info)
|
||||||
{
|
{
|
||||||
stream_info->pad = NULL;
|
stream_info->object = NULL;
|
||||||
stream_info->type = GST_STREAM_TYPE_UNKNOWN;
|
stream_info->type = GST_STREAM_TYPE_UNKNOWN;
|
||||||
stream_info->decoder = NULL;
|
stream_info->decoder = NULL;
|
||||||
stream_info->mute = FALSE;
|
stream_info->mute = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
GstStreamInfo *
|
GstStreamInfo *
|
||||||
gst_stream_info_new (GstPad * pad, GstStreamType type, gchar * decoder)
|
gst_stream_info_new (GstObject * object, GstStreamType type, gchar * decoder)
|
||||||
{
|
{
|
||||||
GstStreamInfo *info;
|
GstStreamInfo *info;
|
||||||
|
|
||||||
info = g_object_new (GST_TYPE_STREAM_INFO, NULL);
|
info = g_object_new (GST_TYPE_STREAM_INFO, NULL);
|
||||||
|
|
||||||
gst_object_ref (GST_OBJECT (pad));
|
gst_object_ref (object);
|
||||||
info->pad = pad;
|
info->object = object;
|
||||||
info->type = type;
|
info->type = type;
|
||||||
info->decoder = g_strdup (decoder);
|
info->decoder = g_strdup (decoder);
|
||||||
|
|
||||||
|
@ -165,8 +169,8 @@ gst_stream_info_dispose (GObject * object)
|
||||||
|
|
||||||
stream_info = GST_STREAM_INFO (object);
|
stream_info = GST_STREAM_INFO (object);
|
||||||
|
|
||||||
gst_object_unref (GST_OBJECT (stream_info->pad));
|
gst_object_unref (stream_info->object);
|
||||||
stream_info->pad = NULL;
|
stream_info->object = NULL;
|
||||||
stream_info->type = GST_STREAM_TYPE_UNKNOWN;
|
stream_info->type = GST_STREAM_TYPE_UNKNOWN;
|
||||||
g_free (stream_info->decoder);
|
g_free (stream_info->decoder);
|
||||||
|
|
||||||
|
@ -222,11 +226,16 @@ gst_stream_info_set_property (GObject * object, guint prop_id,
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case ARG_MUTE:
|
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);
|
gboolean new_mute = g_value_get_boolean (value);
|
||||||
|
|
||||||
if (new_mute != stream_info->mute) {
|
if (new_mute != stream_info->mute) {
|
||||||
stream_info->mute = new_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;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -248,7 +257,7 @@ gst_stream_info_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case ARG_PAD:
|
case ARG_PAD:
|
||||||
g_value_set_object (value, stream_info->pad);
|
g_value_set_object (value, stream_info->object);
|
||||||
break;
|
break;
|
||||||
case ARG_TYPE:
|
case ARG_TYPE:
|
||||||
g_value_set_enum (value, stream_info->type);
|
g_value_set_enum (value, stream_info->type);
|
||||||
|
|
|
@ -39,12 +39,13 @@ typedef enum {
|
||||||
GST_STREAM_TYPE_AUDIO = 1,
|
GST_STREAM_TYPE_AUDIO = 1,
|
||||||
GST_STREAM_TYPE_VIDEO = 2,
|
GST_STREAM_TYPE_VIDEO = 2,
|
||||||
GST_STREAM_TYPE_TEXT = 3,
|
GST_STREAM_TYPE_TEXT = 3,
|
||||||
|
GST_STREAM_TYPE_ELEMENT = 4,
|
||||||
} GstStreamType;
|
} GstStreamType;
|
||||||
|
|
||||||
struct _GstStreamInfo {
|
struct _GstStreamInfo {
|
||||||
GObject parent;
|
GObject parent;
|
||||||
|
|
||||||
GstPad *pad;
|
GstObject *object;
|
||||||
GstStreamType type;
|
GstStreamType type;
|
||||||
gchar *decoder;
|
gchar *decoder;
|
||||||
gboolean mute;
|
gboolean mute;
|
||||||
|
@ -59,7 +60,7 @@ struct _GstStreamInfoClass {
|
||||||
|
|
||||||
GType gst_stream_info_get_type (void);
|
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
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue