mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-29 20:35:40 +00:00
Raw and crude port of decodebin.
Original commit message from CVS: * gst/playback/README: * gst/playback/gstdecodebin.c: (gst_decode_bin_class_init), (compare_ranks), (print_feature), (gst_decode_bin_init), (dynamic_create), (dynamic_free), (find_compatibles), (mimetype_is_raw), (close_pad_link), (got_redirect), (try_to_link_1), (get_our_ghost_pad), (remove_element_chain), (new_pad), (no_more_pads), (unlinked), (close_link), (type_found), (gst_decode_bin_change_state): * gst/playback/gstplaybasebin.c: (gst_play_base_bin_class_init), (gst_play_base_bin_init), (group_destroy), (group_commit), (check_queue), (queue_overrun), (queue_threshold_reached), (queue_out_of_data), (gen_preroll_element), (unknown_type), (new_decoded_pad), (setup_subtitle), (gen_source_element), (got_redirect), (setup_source), (play_base_eos), (gst_play_base_bin_change_state), (gst_play_base_bin_add_element), (gst_play_base_bin_remove_element): * gst/playback/gstplaybasebin.h: * gst/playback/gstplaybin.c: (gst_play_bin_class_init), (gst_play_bin_init), (gst_play_bin_dispose), (gst_play_bin_set_property), (gen_video_element), (gen_text_element), (gen_audio_element), (remove_sinks), (gst_play_bin_send_event): * gst/playback/gststreaminfo.c: (gst_stream_info_dispose), (stream_info_change_state), (gst_stream_info_set_mute): * gst/playback/gststreamselector.c: (gst_stream_selector_init), (gst_stream_selector_get_caps), (gst_stream_selector_setcaps), (gst_stream_selector_request_new_pad), (gst_stream_selector_event), (gst_stream_selector_chain): * gst/playback/test.c: (gen_video_element), (gen_audio_element), (main): * sys/xvimage/xvimagesink.c: (gst_xvimagesink_getcaps), (gst_xvimagesink_setcaps), (gst_xvimagesink_get_times), (gst_xvimagesink_show_frame), (gst_xvimagesink_chain), (gst_xvimagesink_buffer_alloc), (gst_xvimagesink_class_init): Raw and crude port of decodebin. Make playbin compile.
This commit is contained in:
parent
e51a02bd1d
commit
50e2f24b44
10 changed files with 525 additions and 287 deletions
39
ChangeLog
39
ChangeLog
|
@ -1,3 +1,42 @@
|
|||
2005-04-12 Wim Taymans <wim@fluendo.com>
|
||||
|
||||
* gst/playback/README:
|
||||
* gst/playback/gstdecodebin.c: (gst_decode_bin_class_init),
|
||||
(compare_ranks), (print_feature), (gst_decode_bin_init),
|
||||
(dynamic_create), (dynamic_free), (find_compatibles),
|
||||
(mimetype_is_raw), (close_pad_link), (got_redirect),
|
||||
(try_to_link_1), (get_our_ghost_pad), (remove_element_chain),
|
||||
(new_pad), (no_more_pads), (unlinked), (close_link), (type_found),
|
||||
(gst_decode_bin_change_state):
|
||||
* gst/playback/gstplaybasebin.c: (gst_play_base_bin_class_init),
|
||||
(gst_play_base_bin_init), (group_destroy), (group_commit),
|
||||
(check_queue), (queue_overrun), (queue_threshold_reached),
|
||||
(queue_out_of_data), (gen_preroll_element), (unknown_type),
|
||||
(new_decoded_pad), (setup_subtitle), (gen_source_element),
|
||||
(got_redirect), (setup_source), (play_base_eos),
|
||||
(gst_play_base_bin_change_state), (gst_play_base_bin_add_element),
|
||||
(gst_play_base_bin_remove_element):
|
||||
* gst/playback/gstplaybasebin.h:
|
||||
* gst/playback/gstplaybin.c: (gst_play_bin_class_init),
|
||||
(gst_play_bin_init), (gst_play_bin_dispose),
|
||||
(gst_play_bin_set_property), (gen_video_element),
|
||||
(gen_text_element), (gen_audio_element), (remove_sinks),
|
||||
(gst_play_bin_send_event):
|
||||
* gst/playback/gststreaminfo.c: (gst_stream_info_dispose),
|
||||
(stream_info_change_state), (gst_stream_info_set_mute):
|
||||
* gst/playback/gststreamselector.c: (gst_stream_selector_init),
|
||||
(gst_stream_selector_get_caps), (gst_stream_selector_setcaps),
|
||||
(gst_stream_selector_request_new_pad), (gst_stream_selector_event),
|
||||
(gst_stream_selector_chain):
|
||||
* gst/playback/test.c: (gen_video_element), (gen_audio_element),
|
||||
(main):
|
||||
* sys/xvimage/xvimagesink.c: (gst_xvimagesink_getcaps),
|
||||
(gst_xvimagesink_setcaps), (gst_xvimagesink_get_times),
|
||||
(gst_xvimagesink_show_frame), (gst_xvimagesink_chain),
|
||||
(gst_xvimagesink_buffer_alloc), (gst_xvimagesink_class_init):
|
||||
Raw and crude port of decodebin.
|
||||
Make playbin compile.
|
||||
|
||||
2005-04-06 Wim Taymans <wim@fluendo.com>
|
||||
|
||||
* ext/gnomevfs/Makefile.am:
|
||||
|
|
|
@ -12,6 +12,27 @@ decoderbin:
|
|||
- threading after demuxing?
|
||||
- new_media events should be handled.
|
||||
- caching of elements.
|
||||
- abstract more elements, pads (typefind, ...);
|
||||
|
||||
The autoplugging happens as follows:
|
||||
|
||||
1) typefind is added internally to the bin.
|
||||
2) the have_type signal is connected to typefind.
|
||||
3) in the have_type callback the close_pad_link function is called
|
||||
4) close_pad_link checks the type on the pad, if it is raw, a ghostpad
|
||||
is created and autoplugging for that pad stops.
|
||||
5) if the type of the pad is not raw, a list of possible elements that
|
||||
can connect to this type is generated in find_compatibles.
|
||||
6) try_to_link_1 with the element list is called. The function will loop
|
||||
over the element list and will try to connect one of the elements to
|
||||
the pad. If the link works, a call is made to close_link.
|
||||
7) close_link loops over all the source pads of the element and
|
||||
recursively calls 4) for any ALWAYS pad. For elements with
|
||||
a SOMETIMES pad, a structure is set up and is passed to the callback
|
||||
of the new_pad signal.
|
||||
8) in the new_pad callback, 4) is called to try to autoplug the
|
||||
new pad.
|
||||
|
||||
|
||||
playbasebin:
|
||||
|
||||
|
|
|
@ -78,8 +78,12 @@ struct _GstDecodeBinClass
|
|||
void (*removed_decoded_pad) (GstElement * element, GstPad * pad);
|
||||
/* signal fired when we found a pad that we cannot decode */
|
||||
void (*unknown_type) (GstElement * element, GstPad * pad, GstCaps * caps);
|
||||
/* signal fired when we got a redirect attempt */
|
||||
void (*got_redirect) (GstElement * element, const gchar * new_location);
|
||||
};
|
||||
|
||||
#define DEFAULT_THREADED FALSE
|
||||
|
||||
/* props */
|
||||
enum
|
||||
{
|
||||
|
@ -93,6 +97,7 @@ enum
|
|||
SIGNAL_NEW_DECODED_PAD,
|
||||
SIGNAL_REMOVED_DECODED_PAD,
|
||||
SIGNAL_UNKNOWN_TYPE,
|
||||
SIGNAL_REDIRECT,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
|
@ -127,6 +132,8 @@ static void close_pad_link (GstElement * element, GstPad * pad,
|
|||
GstCaps * caps, GstDecodeBin * decode_bin, gboolean more);
|
||||
static void unlinked (GstPad * pad, GstPad * peerpad,
|
||||
GstDecodeBin * decode_bin);
|
||||
static void new_pad (GstElement * element, GstPad * pad, GstDynamic * dynamic);
|
||||
static void no_more_pads (GstElement * element, GstDynamic * dynamic);
|
||||
|
||||
static GstElementClass *parent_class;
|
||||
static guint gst_decode_bin_signals[LAST_SIGNAL] = { 0 };
|
||||
|
@ -184,7 +191,7 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass)
|
|||
|
||||
g_object_class_install_property (gobject_klass, ARG_THREADED,
|
||||
g_param_spec_boolean ("threaded", "Threaded", "Use threads",
|
||||
FALSE, G_PARAM_READWRITE));
|
||||
DEFAULT_THREADED, G_PARAM_READWRITE));
|
||||
|
||||
gst_decode_bin_signals[SIGNAL_NEW_DECODED_PAD] =
|
||||
g_signal_new ("new-decoded-pad", G_TYPE_FROM_CLASS (klass),
|
||||
|
@ -202,6 +209,11 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass)
|
|||
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, unknown_type),
|
||||
NULL, NULL, gst_marshal_VOID__OBJECT_BOXED, G_TYPE_NONE, 2,
|
||||
GST_TYPE_PAD, GST_TYPE_CAPS);
|
||||
gst_decode_bin_signals[SIGNAL_REDIRECT] =
|
||||
g_signal_new ("got-redirect", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, got_redirect),
|
||||
NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1,
|
||||
G_TYPE_STRING);
|
||||
|
||||
gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_decode_bin_dispose);
|
||||
|
||||
|
@ -260,18 +272,28 @@ static gint
|
|||
compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
|
||||
{
|
||||
gint diff;
|
||||
const gchar *rname1, *rname2;
|
||||
|
||||
diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
|
||||
if (diff != 0)
|
||||
return diff;
|
||||
return strcmp (gst_plugin_feature_get_name (f2),
|
||||
gst_plugin_feature_get_name (f1));
|
||||
|
||||
rname1 = gst_plugin_feature_get_name (f1);
|
||||
rname2 = gst_plugin_feature_get_name (f2);
|
||||
|
||||
diff = strcmp (rname2, rname1);
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
static void
|
||||
print_feature (GstPluginFeature * feature)
|
||||
{
|
||||
GST_DEBUG ("%s", gst_plugin_feature_get_name (feature));
|
||||
const gchar *rname;
|
||||
|
||||
rname = gst_plugin_feature_get_name (feature);
|
||||
|
||||
GST_DEBUG ("%s", rname);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -307,6 +329,7 @@ gst_decode_bin_init (GstDecodeBin * decode_bin)
|
|||
G_CALLBACK (type_found), decode_bin);
|
||||
}
|
||||
|
||||
decode_bin->threaded = DEFAULT_THREADED;
|
||||
decode_bin->dynamics = NULL;
|
||||
}
|
||||
|
||||
|
@ -338,6 +361,40 @@ gst_decode_bin_dispose (GObject * object)
|
|||
}
|
||||
}
|
||||
|
||||
static GstDynamic *
|
||||
dynamic_create (GstElement * element, GstDecodeBin * decode_bin)
|
||||
{
|
||||
GstDynamic *dyn;
|
||||
|
||||
/* take refs */
|
||||
gst_object_ref (GST_OBJECT (element));
|
||||
gst_object_ref (GST_OBJECT (decode_bin));
|
||||
|
||||
dyn = g_new0 (GstDynamic, 1);
|
||||
dyn->element = element;
|
||||
dyn->decode_bin = decode_bin;
|
||||
dyn->np_sig_id = g_signal_connect (G_OBJECT (element), "new-pad",
|
||||
G_CALLBACK (new_pad), dyn);
|
||||
dyn->nmp_sig_id = g_signal_connect (G_OBJECT (element), "no-more-pads",
|
||||
G_CALLBACK (no_more_pads), dyn);
|
||||
|
||||
return dyn;
|
||||
}
|
||||
|
||||
static void
|
||||
dynamic_free (GstDynamic * dyn)
|
||||
{
|
||||
/* disconnect signals */
|
||||
g_signal_handler_disconnect (G_OBJECT (dyn->element), dyn->np_sig_id);
|
||||
g_signal_handler_disconnect (G_OBJECT (dyn->element), dyn->nmp_sig_id);
|
||||
|
||||
gst_object_unref (GST_OBJECT (dyn->element));
|
||||
gst_object_unref (GST_OBJECT (dyn->decode_bin));
|
||||
dyn->element = NULL;
|
||||
dyn->decode_bin = NULL;
|
||||
g_free (dyn);
|
||||
}
|
||||
|
||||
/* this function runs through the element factories and returns a list
|
||||
* of all elements that are able to sink the given caps
|
||||
*/
|
||||
|
@ -369,17 +426,27 @@ find_compatibles (GstDecodeBin * decode_bin, const GstCaps * caps)
|
|||
/* check if the intersection is empty */
|
||||
if (!gst_caps_is_empty (intersect)) {
|
||||
/* non empty intersection, we can use this element */
|
||||
to_try = g_list_append (to_try, factory);
|
||||
gst_caps_free (intersect);
|
||||
to_try = g_list_prepend (to_try, factory);
|
||||
gst_caps_unref (intersect);
|
||||
break;
|
||||
}
|
||||
gst_caps_free (intersect);
|
||||
gst_caps_unref (intersect);
|
||||
}
|
||||
}
|
||||
}
|
||||
to_try = g_list_reverse (to_try);
|
||||
|
||||
return to_try;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mimetype_is_raw (const gchar * mimetype)
|
||||
{
|
||||
return g_str_has_prefix (mimetype, "video/x-raw") ||
|
||||
g_str_has_prefix (mimetype, "audio/x-raw") ||
|
||||
g_str_has_prefix (mimetype, "text/plain");
|
||||
}
|
||||
|
||||
/* given a pad and a caps from an element, find the list of elements
|
||||
* that could connect to the pad
|
||||
*
|
||||
|
@ -393,26 +460,28 @@ static void
|
|||
close_pad_link (GstElement * element, GstPad * pad, GstCaps * caps,
|
||||
GstDecodeBin * decode_bin, gboolean more)
|
||||
{
|
||||
GList *to_try;
|
||||
GstStructure *structure;
|
||||
const gchar *mimetype;
|
||||
gchar *padname;
|
||||
gint diff;
|
||||
|
||||
if (!strncmp (gst_pad_get_name (pad), "current_", 8))
|
||||
padname = gst_pad_get_name (pad);
|
||||
diff = strncmp (padname, "current_", 8);
|
||||
g_free (padname);
|
||||
|
||||
/* hack.. ignore current pads */
|
||||
if (!diff)
|
||||
return;
|
||||
|
||||
/* the caps is empty, this means the pad has no type, we can only
|
||||
* decide to fire the unknown_type signal. */
|
||||
if (caps == NULL || gst_caps_is_empty (caps)) {
|
||||
g_signal_emit (G_OBJECT (decode_bin),
|
||||
gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, pad, caps);
|
||||
return;
|
||||
}
|
||||
if (caps == NULL || gst_caps_is_empty (caps))
|
||||
goto unknown_type;
|
||||
|
||||
/* the caps is any, this means the pad can be anything and
|
||||
* we don't know yet */
|
||||
if (gst_caps_is_any (caps)) {
|
||||
return;
|
||||
}
|
||||
if (gst_caps_is_any (caps))
|
||||
goto dont_know_yet;
|
||||
|
||||
GST_LOG_OBJECT (element, "trying to close %" GST_PTR_FORMAT, caps);
|
||||
|
||||
|
@ -424,9 +493,7 @@ close_pad_link (GstElement * element, GstPad * pad, GstCaps * caps,
|
|||
|
||||
/* first see if this is raw. If the type is raw, we can
|
||||
* create a ghostpad for this pad. */
|
||||
if (g_str_has_prefix (mimetype, "video/x-raw") ||
|
||||
g_str_has_prefix (mimetype, "audio/x-raw") ||
|
||||
g_str_has_prefix (mimetype, "text/plain")) {
|
||||
if (mimetype_is_raw (mimetype)) {
|
||||
gchar *padname;
|
||||
GstPad *ghost;
|
||||
|
||||
|
@ -444,27 +511,62 @@ close_pad_link (GstElement * element, GstPad * pad, GstCaps * caps,
|
|||
gst_decode_bin_signals[SIGNAL_NEW_DECODED_PAD], 0, ghost, !more);
|
||||
|
||||
g_free (padname);
|
||||
} else {
|
||||
GList *to_try;
|
||||
|
||||
/* if the caps has many types, we need to delay */
|
||||
if (gst_caps_get_size (caps) != 1)
|
||||
goto many_types;
|
||||
|
||||
/* continue plugging, first find all compatible elements */
|
||||
to_try = find_compatibles (decode_bin, caps);
|
||||
if (to_try == NULL)
|
||||
/* no compatible elements, we cannot go on */
|
||||
goto unknown_type;
|
||||
|
||||
try_to_link_1 (decode_bin, pad, to_try);
|
||||
/* can free the list again now */
|
||||
g_list_free (to_try);
|
||||
}
|
||||
return;
|
||||
|
||||
unknown_type:
|
||||
{
|
||||
GST_LOG_OBJECT (pad, "unkown type found, fire signal");
|
||||
g_signal_emit (G_OBJECT (decode_bin),
|
||||
gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, pad, caps);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gst_caps_get_size (caps) == 1) {
|
||||
/* then continue plugging, first find all compatible elements */
|
||||
to_try = find_compatibles (decode_bin, caps);
|
||||
if (to_try == NULL) {
|
||||
/* no compatible elements, fire the unknown_type signal, we cannot go
|
||||
* on */
|
||||
g_signal_emit (G_OBJECT (decode_bin),
|
||||
gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, pad, caps);
|
||||
return;
|
||||
}
|
||||
try_to_link_1 (decode_bin, pad, to_try);
|
||||
} else {
|
||||
GST_LOG_OBJECT (element, "multiple possibilities, delaying");
|
||||
dont_know_yet:
|
||||
{
|
||||
GST_LOG_OBJECT (pad, "type is not known yet, waiting to close link");
|
||||
return;
|
||||
}
|
||||
many_types:
|
||||
{
|
||||
GST_LOG_OBJECT (pad, "many possible types, waiting to close link");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* given a list of element factories, try to link one of the factories
|
||||
* to the given pad */
|
||||
/*
|
||||
* Called when we're redirected to a new URI.
|
||||
*/
|
||||
static void
|
||||
got_redirect (GstElement * element,
|
||||
const gchar * new_location, GstDecodeBin * decode_bin)
|
||||
{
|
||||
g_signal_emit (decode_bin, gst_decode_bin_signals[SIGNAL_REDIRECT], 0,
|
||||
new_location);
|
||||
}
|
||||
|
||||
/**
|
||||
* given a list of element factories, try to link one of the factories
|
||||
* to the given pad.
|
||||
*
|
||||
* The function returns the element that was successfully linked to the
|
||||
* pad.
|
||||
*/
|
||||
static GstElement *
|
||||
try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
|
||||
{
|
||||
|
@ -474,7 +576,7 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
|
|||
for (walk = factories; walk; walk = g_list_next (walk)) {
|
||||
GstElementFactory *factory = GST_ELEMENT_FACTORY (walk->data);
|
||||
GstElement *element;
|
||||
gboolean ret;
|
||||
GstPadLinkReturn ret;
|
||||
|
||||
GST_DEBUG_OBJECT (decode_bin, "trying to link %s",
|
||||
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
|
||||
|
@ -492,17 +594,17 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
|
|||
GST_DEBUG_OBJECT (decode_bin, "adding %s", gst_element_get_name (element));
|
||||
gst_bin_add (GST_BIN (decode_bin), element);
|
||||
|
||||
/* set to ready first so it can do negotiation */
|
||||
/* set to ready first so it is ready */
|
||||
gst_element_set_state (element, GST_STATE_READY);
|
||||
|
||||
/* keep out own list of elements */
|
||||
/* keep our own list of elements */
|
||||
decode_bin->elements = g_list_prepend (decode_bin->elements, element);
|
||||
|
||||
/* try to link the given pad to a sinkpad */
|
||||
/* FIXME, find the sinkpad by looping over the pads instead of
|
||||
* looking it up by name */
|
||||
ret = gst_pad_link (pad, gst_element_get_pad (element, "sink"));
|
||||
if (ret) {
|
||||
if (ret == GST_PAD_LINK_OK) {
|
||||
const gchar *klass;
|
||||
GstElementFactory *factory;
|
||||
guint sig;
|
||||
|
@ -522,6 +624,12 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
|
|||
* because that would consume less memory. */
|
||||
}
|
||||
}
|
||||
/* catch redirects */
|
||||
if (g_signal_lookup ("got-redirect", G_OBJECT_TYPE (element))) {
|
||||
g_signal_connect (element, "got-redirect",
|
||||
G_CALLBACK (got_redirect), decode_bin);
|
||||
}
|
||||
|
||||
/* make sure we catch unlink signals */
|
||||
sig = g_signal_connect (G_OBJECT (GST_PAD_REALIZE (pad)), "unlinked",
|
||||
G_CALLBACK (unlinked), decode_bin);
|
||||
|
@ -532,7 +640,7 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
|
|||
* on it until we have a raw type */
|
||||
close_link (element, decode_bin);
|
||||
/* change the state of the element to that of the parent */
|
||||
gst_element_sync_state_with_parent (element);
|
||||
gst_element_set_state (element, GST_STATE_PAUSED);
|
||||
return element;
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (decode_bin, "link failed on pad %s:%s",
|
||||
|
@ -560,6 +668,7 @@ get_our_ghost_pad (GstDecodeBin * decode_bin, GstPad * pad)
|
|||
|
||||
GST_DEBUG_OBJECT (decode_bin, "pad parent %s",
|
||||
gst_element_get_name (parent));
|
||||
|
||||
if (parent == GST_ELEMENT (decode_bin)) {
|
||||
GST_DEBUG_OBJECT (decode_bin, "pad is our ghostpad");
|
||||
return pad;
|
||||
|
@ -570,7 +679,7 @@ get_our_ghost_pad (GstDecodeBin * decode_bin, GstPad * pad)
|
|||
}
|
||||
|
||||
GST_DEBUG_OBJECT (decode_bin, "looping over ghostpads");
|
||||
ghostpads = gst_pad_get_ghost_pad_list (pad);
|
||||
ghostpads = GST_REAL_PAD (pad)->ghostpads;
|
||||
while (ghostpads) {
|
||||
GstPad *ghostpad;
|
||||
|
||||
|
@ -595,6 +704,10 @@ remove_element_chain (GstDecodeBin * decode_bin, GstPad * pad)
|
|||
GList *int_links;
|
||||
GstElement *elem = gst_pad_get_parent (pad);
|
||||
|
||||
while (GST_OBJECT_PARENT (elem) &&
|
||||
GST_OBJECT_PARENT (elem) != GST_OBJECT (decode_bin))
|
||||
elem = GST_ELEMENT (GST_OBJECT_PARENT (elem));
|
||||
|
||||
GST_DEBUG_OBJECT (decode_bin, "%s:%s", GST_DEBUG_PAD_NAME (pad));
|
||||
|
||||
/* remove all elements linked to this pad up to the ghostpad
|
||||
|
@ -657,7 +770,7 @@ new_pad (GstElement * element, GstPad * pad, GstDynamic * dynamic)
|
|||
caps = gst_pad_get_caps (pad);
|
||||
close_pad_link (element, pad, caps, decode_bin, more);
|
||||
if (caps)
|
||||
gst_caps_free (caps);
|
||||
gst_caps_unref (caps);
|
||||
}
|
||||
|
||||
/* this signal is fired when an element signals the no_more_pads signal.
|
||||
|
@ -673,14 +786,9 @@ no_more_pads (GstElement * element, GstDynamic * dynamic)
|
|||
GST_DEBUG_OBJECT (decode_bin, "no more pads on element %s",
|
||||
gst_element_get_name (element));
|
||||
|
||||
/* disconnect signals */
|
||||
g_signal_handler_disconnect (G_OBJECT (dynamic->element), dynamic->np_sig_id);
|
||||
g_signal_handler_disconnect (G_OBJECT (dynamic->element),
|
||||
dynamic->nmp_sig_id);
|
||||
|
||||
/* remove the element from the list of dynamic elements */
|
||||
decode_bin->dynamics = g_list_remove (decode_bin->dynamics, dynamic);
|
||||
g_free (dynamic);
|
||||
dynamic_free (dynamic);
|
||||
|
||||
/* if we have no more dynamic elements, we have no chance of creating
|
||||
* more pads, so we fire the no_more_pads signal */
|
||||
|
@ -697,7 +805,6 @@ no_more_pads (GstElement * element, GstDynamic * dynamic)
|
|||
static void
|
||||
unlinked (GstPad * pad, GstPad * peerpad, GstDecodeBin * decode_bin)
|
||||
{
|
||||
GList *walk;
|
||||
GstDynamic *dyn;
|
||||
GstElement *element;
|
||||
|
||||
|
@ -709,25 +816,17 @@ unlinked (GstPad * pad, GstPad * peerpad, GstDecodeBin * decode_bin)
|
|||
|
||||
/* if an element removes two pads, then we don't want this twice */
|
||||
element = gst_pad_get_parent (pad);
|
||||
for (walk = decode_bin->dynamics; walk != NULL; walk = walk->next) {
|
||||
dyn = walk->data;
|
||||
if (dyn->element == element)
|
||||
return;
|
||||
}
|
||||
if (g_list_find (decode_bin->dynamics, element) != NULL)
|
||||
goto exit;
|
||||
|
||||
GST_DEBUG_OBJECT (decode_bin, "pad removal while alive - chained?");
|
||||
|
||||
/* re-setup dynamic plugging */
|
||||
dyn = g_new0 (GstDynamic, 1);
|
||||
dyn->np_sig_id = g_signal_connect (G_OBJECT (element), "new-pad",
|
||||
G_CALLBACK (new_pad), dyn);
|
||||
dyn->nmp_sig_id = g_signal_connect (G_OBJECT (element), "no-more-pads",
|
||||
G_CALLBACK (no_more_pads), dyn);
|
||||
dyn->element = element;
|
||||
dyn->decode_bin = decode_bin;
|
||||
|
||||
dyn = dynamic_create (element, decode_bin);
|
||||
/* and add this element to the dynamic elements */
|
||||
decode_bin->dynamics = g_list_prepend (decode_bin->dynamics, dyn);
|
||||
|
||||
exit:
|
||||
gst_object_unref (GST_OBJECT (element));
|
||||
}
|
||||
|
||||
/* this function inspects the given element and tries to connect something
|
||||
|
@ -745,7 +844,7 @@ close_link (GstElement * element, GstDecodeBin * decode_bin)
|
|||
gst_element_get_name (element));
|
||||
|
||||
/* loop over all the padtemplates */
|
||||
for (pads = gst_element_get_pad_template_list (element); pads;
|
||||
for (pads = GST_ELEMENT_GET_CLASS (element)->padtemplates; pads;
|
||||
pads = g_list_next (pads)) {
|
||||
GstPadTemplate *templ = GST_PAD_TEMPLATE (pads->data);
|
||||
const gchar *templ_name;
|
||||
|
@ -809,14 +908,8 @@ close_link (GstElement * element, GstDecodeBin * decode_bin)
|
|||
GST_DEBUG_OBJECT (decode_bin, "got a dynamic element here");
|
||||
/* ok, this element has dynamic pads, set up the signal handlers to be
|
||||
* notified of them */
|
||||
dyn = g_new0 (GstDynamic, 1);
|
||||
dyn->np_sig_id = g_signal_connect (G_OBJECT (element), "new-pad",
|
||||
G_CALLBACK (new_pad), dyn);
|
||||
dyn->nmp_sig_id = g_signal_connect (G_OBJECT (element), "no-more-pads",
|
||||
G_CALLBACK (no_more_pads), dyn);
|
||||
dyn->element = element;
|
||||
dyn->decode_bin = decode_bin;
|
||||
|
||||
dyn = dynamic_create (element, decode_bin);
|
||||
/* and add this element to the dynamic elements */
|
||||
decode_bin->dynamics = g_list_prepend (decode_bin->dynamics, dyn);
|
||||
}
|
||||
|
@ -844,7 +937,7 @@ close_link (GstElement * element, GstDecodeBin * decode_bin)
|
|||
caps = gst_pad_get_caps (pad);
|
||||
close_pad_link (element, pad, caps, decode_bin, more);
|
||||
if (caps)
|
||||
gst_caps_free (caps);
|
||||
gst_caps_unref (caps);
|
||||
}
|
||||
|
||||
g_list_free (to_connect);
|
||||
|
@ -857,12 +950,14 @@ type_found (GstElement * typefind, guint probability, GstCaps * caps,
|
|||
GstDecodeBin * decode_bin)
|
||||
{
|
||||
gboolean dynamic;
|
||||
GstPad *pad;
|
||||
|
||||
GST_DEBUG_OBJECT (decode_bin, "typefind found caps %" GST_PTR_FORMAT, caps);
|
||||
|
||||
/* autoplug the new pad with the caps that the signal gave us. */
|
||||
close_pad_link (typefind, gst_element_get_pad (typefind, "src"), caps,
|
||||
decode_bin, FALSE);
|
||||
pad = gst_element_get_pad (typefind, "src");
|
||||
close_pad_link (typefind, pad, caps, decode_bin, FALSE);
|
||||
gst_object_unref (GST_OBJECT (pad));
|
||||
|
||||
dynamic = gst_decode_bin_is_dynamic (decode_bin);
|
||||
if (dynamic == FALSE) {
|
||||
|
@ -927,23 +1022,23 @@ gst_decode_bin_change_state (GstElement * 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;
|
||||
decode_bin->dynamics = NULL;
|
||||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
GST_DEBUG_CATEGORY_STATIC (gst_play_base_bin_debug);
|
||||
#define GST_CAT_DEFAULT gst_play_base_bin_debug
|
||||
|
||||
#define DEFAULT_QUEUE_THRESHOLD (2 * GST_SECOND)
|
||||
#define DEFAULT_QUEUE_SIZE (3 * GST_SECOND)
|
||||
|
||||
/* props */
|
||||
|
@ -37,9 +38,9 @@ enum
|
|||
ARG_0,
|
||||
ARG_URI,
|
||||
ARG_SUBURI,
|
||||
ARG_THREADED,
|
||||
ARG_NSTREAMS,
|
||||
ARG_QUEUE_SIZE,
|
||||
ARG_QUEUE_THRESHOLD,
|
||||
ARG_NSTREAMS,
|
||||
ARG_STREAMINFO,
|
||||
ARG_SOURCE,
|
||||
ARG_VIDEO,
|
||||
|
@ -56,6 +57,7 @@ enum
|
|||
GROUP_SWITCH_SIGNAL,
|
||||
LINK_STREAM_SIGNAL,
|
||||
UNLINK_STREAM_SIGNAL,
|
||||
REDIRECT,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
|
@ -70,8 +72,9 @@ static void gst_play_base_bin_get_property (GObject * object, guint prop_id,
|
|||
static GstElementStateReturn gst_play_base_bin_change_state (GstElement *
|
||||
element);
|
||||
|
||||
static void gst_play_base_bin_add_element (GstBin * bin, GstElement * element);
|
||||
static void gst_play_base_bin_remove_element (GstBin * bin,
|
||||
static gboolean gst_play_base_bin_add_element (GstBin * bin,
|
||||
GstElement * element);
|
||||
static gboolean gst_play_base_bin_remove_element (GstBin * bin,
|
||||
GstElement * element);
|
||||
|
||||
extern GstElementStateReturn gst_element_set_state_func (GstElement * element,
|
||||
|
@ -141,13 +144,19 @@ gst_play_base_bin_class_init (GstPlayBaseBinClass * klass)
|
|||
g_object_class_install_property (gobject_klass, ARG_SUBURI,
|
||||
g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
|
||||
NULL, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (gobject_klass, ARG_NSTREAMS,
|
||||
g_param_spec_int ("nstreams", "NStreams", "number of streams",
|
||||
0, G_MAXINT, 0, G_PARAM_READABLE));
|
||||
|
||||
g_object_class_install_property (gobject_klass, ARG_QUEUE_SIZE,
|
||||
g_param_spec_uint64 ("queue-size", "Queue size",
|
||||
"Size of internal queues in nanoseconds", 0, G_MAXINT64,
|
||||
DEFAULT_QUEUE_SIZE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (gobject_klass, ARG_QUEUE_THRESHOLD,
|
||||
g_param_spec_uint64 ("queue-threshold", "Queue threshold",
|
||||
"Buffering threshold of internal queues in nanoseconds", 0,
|
||||
G_MAXINT64, DEFAULT_QUEUE_THRESHOLD, G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (gobject_klass, ARG_NSTREAMS,
|
||||
g_param_spec_int ("nstreams", "NStreams", "number of streams",
|
||||
0, G_MAXINT, 0, G_PARAM_READABLE));
|
||||
g_object_class_install_property (gobject_klass, ARG_STREAMINFO,
|
||||
g_param_spec_pointer ("stream-info", "Stream info", "List of streaminfo",
|
||||
G_PARAM_READABLE));
|
||||
|
@ -192,6 +201,12 @@ gst_play_base_bin_class_init (GstPlayBaseBinClass * klass)
|
|||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GstPlayBaseBinClass, group_switch),
|
||||
NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
|
||||
gst_play_base_bin_signals[REDIRECT] =
|
||||
g_signal_new ("got-redirect", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GstPlayBaseBinClass, got_redirect),
|
||||
NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1,
|
||||
G_TYPE_STRING);
|
||||
|
||||
/* action signals */
|
||||
gst_play_base_bin_signals[LINK_STREAM_SIGNAL] =
|
||||
|
@ -209,7 +224,6 @@ gst_play_base_bin_class_init (GstPlayBaseBinClass * klass)
|
|||
gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_base_bin_dispose);
|
||||
|
||||
/* we handle state changes like an element */
|
||||
gstelement_klass->set_state = GST_ELEMENT_CLASS (element_class)->set_state;
|
||||
gstelement_klass->change_state =
|
||||
GST_DEBUG_FUNCPTR (gst_play_base_bin_change_state);
|
||||
|
||||
|
@ -227,6 +241,7 @@ gst_play_base_bin_init (GstPlayBaseBin * play_base_bin)
|
|||
play_base_bin->uri = NULL;
|
||||
play_base_bin->suburi = NULL;
|
||||
play_base_bin->need_rebuild = TRUE;
|
||||
play_base_bin->is_stream = FALSE;
|
||||
play_base_bin->source = NULL;
|
||||
play_base_bin->decoder = NULL;
|
||||
play_base_bin->subtitle = NULL;
|
||||
|
@ -238,8 +253,7 @@ gst_play_base_bin_init (GstPlayBaseBin * play_base_bin)
|
|||
play_base_bin->queued_groups = NULL;
|
||||
|
||||
play_base_bin->queue_size = DEFAULT_QUEUE_SIZE;
|
||||
|
||||
GST_FLAG_SET (play_base_bin, GST_BIN_SELF_SCHEDULABLE);
|
||||
play_base_bin->queue_threshold = DEFAULT_QUEUE_THRESHOLD;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -314,7 +328,7 @@ group_destroy (GstPlayBaseGroup * group)
|
|||
continue;
|
||||
|
||||
/* remove any fakesrc elements for this preroll element */
|
||||
for (item = gst_element_get_pad_list (group->type[n].selector);
|
||||
for (item = GST_ELEMENT (group->type[n].selector)->pads;
|
||||
item != NULL; item = item->next) {
|
||||
GstPad *pad = GST_PAD (item->data);
|
||||
guint sig_id;
|
||||
|
@ -417,7 +431,7 @@ group_commit (GstPlayBaseBin * play_base_bin, gboolean fatal)
|
|||
GST_DEBUG ("signaled group done");
|
||||
g_mutex_unlock (play_base_bin->group_lock);
|
||||
|
||||
if (!had_active_group && GST_STATE (play_base_bin) > GST_STATE_READY) {
|
||||
if (group && !had_active_group && GST_STATE (play_base_bin) > GST_STATE_READY) {
|
||||
setup_substreams (play_base_bin);
|
||||
GST_DEBUG ("Emitting signal");
|
||||
g_signal_emit (play_base_bin,
|
||||
|
@ -441,6 +455,30 @@ group_is_muted (GstPlayBaseGroup * group)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Buffer/cache checking.
|
||||
*/
|
||||
|
||||
static gboolean
|
||||
check_queue (GstProbe * probe, GstData ** data, gpointer user_data)
|
||||
{
|
||||
GstElement *queue = GST_ELEMENT (user_data);
|
||||
GstPlayBaseBin *play_base_bin = g_object_get_data (G_OBJECT (queue), "pbb");
|
||||
guint64 level = 0;
|
||||
|
||||
g_object_get (G_OBJECT (queue), "current-level-time", &level, NULL);
|
||||
GST_DEBUG ("Queue size: %" GST_TIME_FORMAT, GST_TIME_ARGS (level));
|
||||
level = level * 100 / play_base_bin->queue_threshold;
|
||||
if (level > 100)
|
||||
level = 100;
|
||||
|
||||
g_signal_emit (play_base_bin,
|
||||
gst_play_base_bin_signals[BUFFERING_SIGNAL], 0, level);
|
||||
|
||||
/* continue! */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* this signal will be fired when one of the queues with raw
|
||||
* data is filled. This means that the group building stage is over
|
||||
* and playback of the new queued group should start */
|
||||
|
@ -448,7 +486,72 @@ static void
|
|||
queue_overrun (GstElement * element, GstPlayBaseBin * play_base_bin)
|
||||
{
|
||||
GST_DEBUG ("queue %s overrun", gst_element_get_name (element));
|
||||
|
||||
group_commit (play_base_bin, FALSE);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (element,
|
||||
G_CALLBACK (queue_overrun), play_base_bin);
|
||||
}
|
||||
|
||||
/* Used for time-based buffering. */
|
||||
static void
|
||||
queue_threshold_reached (GstElement * queue, GstPlayBaseBin * play_base_bin)
|
||||
{
|
||||
GstProbe *probe;
|
||||
|
||||
GST_DEBUG ("Running");
|
||||
|
||||
/* play */
|
||||
g_object_set (queue, "min-threshold-time", (guint64) 0, NULL);
|
||||
|
||||
if ((probe = g_object_get_data (G_OBJECT (queue), "probe"))) {
|
||||
GstPad *sinkpad;
|
||||
|
||||
sinkpad = gst_element_get_pad (queue, "sink");
|
||||
GST_DEBUG_OBJECT (play_base_bin,
|
||||
"Removing buffer probe %p from pad %s:%s (%p)",
|
||||
probe, GST_DEBUG_PAD_NAME (sinkpad), sinkpad);
|
||||
|
||||
g_signal_emit (play_base_bin,
|
||||
gst_play_base_bin_signals[BUFFERING_SIGNAL], 0, 100);
|
||||
|
||||
g_object_set_data (G_OBJECT (queue), "probe", NULL);
|
||||
gst_pad_remove_probe (sinkpad, probe);
|
||||
gst_probe_destroy (probe);
|
||||
|
||||
g_signal_emit (play_base_bin,
|
||||
gst_play_base_bin_signals[BUFFERING_SIGNAL], 0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
queue_out_of_data (GstElement * queue, GstPlayBaseBin * play_base_bin)
|
||||
{
|
||||
GstProbe *probe;
|
||||
|
||||
GST_DEBUG ("Underrun, re-caching");
|
||||
|
||||
/* On underrun, we want to temoprarily pause playback, set a "min-size"
|
||||
* threshold and wait for the running signal and then play again. Take
|
||||
* care of possible deadlocks and so on, */
|
||||
g_object_set (queue, "min-threshold-time",
|
||||
(guint64) play_base_bin->queue_threshold, NULL);
|
||||
|
||||
/* re-connect probe */
|
||||
if (!(probe = g_object_get_data (G_OBJECT (queue), "probe"))) {
|
||||
GstPad *sinkpad;
|
||||
|
||||
probe = gst_probe_new (FALSE, check_queue, queue);
|
||||
sinkpad = gst_element_get_pad (queue, "sink");
|
||||
gst_pad_add_probe (sinkpad, probe);
|
||||
g_object_set_data (G_OBJECT (queue), "probe", probe);
|
||||
GST_DEBUG_OBJECT (play_base_bin,
|
||||
"Re-attaching buffering probe %p to pad %s:%s (%p)",
|
||||
probe, GST_DEBUG_PAD_NAME (sinkpad), sinkpad);
|
||||
|
||||
g_signal_emit (play_base_bin,
|
||||
gst_play_base_bin_signals[BUFFERING_SIGNAL], 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* generate a preroll element which is simply a queue. While there
|
||||
|
@ -491,6 +594,31 @@ gen_preroll_element (GstPlayBaseBin * play_base_bin,
|
|||
"max-size-time", play_base_bin->queue_size, NULL);
|
||||
sig = g_signal_connect (G_OBJECT (preroll), "overrun",
|
||||
G_CALLBACK (queue_overrun), play_base_bin);
|
||||
if (play_base_bin->is_stream &&
|
||||
((type == GST_STREAM_TYPE_VIDEO &&
|
||||
group->type[GST_STREAM_TYPE_AUDIO - 1].npads == 0) ||
|
||||
(type == GST_STREAM_TYPE_AUDIO &&
|
||||
group->type[GST_STREAM_TYPE_VIDEO - 1].npads == 0))) {
|
||||
GstProbe *probe;
|
||||
GstPad *sinkpad;
|
||||
|
||||
g_signal_connect (G_OBJECT (preroll), "running",
|
||||
G_CALLBACK (queue_threshold_reached), play_base_bin);
|
||||
g_object_set (G_OBJECT (preroll),
|
||||
"min-threshold-time", (guint64) play_base_bin->queue_threshold, NULL);
|
||||
|
||||
/* give updates on queue size */
|
||||
probe = gst_probe_new (FALSE, check_queue, preroll);
|
||||
sinkpad = gst_element_get_pad (preroll, "sink");
|
||||
gst_pad_add_probe (sinkpad, probe);
|
||||
GST_DEBUG_OBJECT (play_base_bin, "Attaching probe %p to pad %s:%s (%p)",
|
||||
probe, GST_DEBUG_PAD_NAME (sinkpad), sinkpad);
|
||||
g_object_set_data (G_OBJECT (preroll), "pbb", play_base_bin);
|
||||
g_object_set_data (G_OBJECT (preroll), "probe", probe);
|
||||
|
||||
g_signal_connect (G_OBJECT (preroll), "underrun",
|
||||
G_CALLBACK (queue_out_of_data), 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 (preroll), "signal_id", GINT_TO_POINTER (sig));
|
||||
|
@ -583,7 +711,7 @@ unknown_type (GstElement * element, GstPad * pad, GstCaps * caps,
|
|||
GstPlayBaseGroup *group = get_building_group (play_base_bin);
|
||||
|
||||
capsstr = gst_caps_to_string (caps);
|
||||
g_message /*warning */ ("don't know how to handle %s", capsstr);
|
||||
g_message ("don't know how to handle %s", capsstr);
|
||||
|
||||
/* add the stream to the list */
|
||||
info = gst_stream_info_new (GST_OBJECT (pad), GST_STREAM_TYPE_UNKNOWN,
|
||||
|
@ -807,7 +935,7 @@ new_decoded_pad (GstElement * element, GstPad * pad, gboolean last,
|
|||
g_warning ("no type on pad %s:%s",
|
||||
GST_DEBUG_PAD_NAME (GST_PAD_REALIZE (pad)));
|
||||
if (caps)
|
||||
gst_caps_free (caps);
|
||||
gst_caps_unref (caps);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -848,7 +976,7 @@ new_decoded_pad (GstElement * element, GstPad * pad, gboolean last,
|
|||
gst_pad_link (pad, sinkpad);
|
||||
|
||||
/* add the stream to the list */
|
||||
gst_caps_free (caps);
|
||||
gst_caps_unref (caps);
|
||||
info->origin = GST_OBJECT (pad);
|
||||
|
||||
/* select 1st for now - we'll select a preferred one after preroll */
|
||||
|
@ -905,67 +1033,6 @@ state_change (GstElement * element,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Buffer/cache checking. FIXME: make configurable.
|
||||
* Note that we could also do this (buffering) at the
|
||||
* preroll-level. The advantage there is that it'd
|
||||
* allow us to cache in time-units rather than byte-
|
||||
* units. Ohwell...
|
||||
*/
|
||||
|
||||
static gboolean
|
||||
check_queue (GstProbe * probe, GstData ** data, gpointer user_data)
|
||||
{
|
||||
GstElement *queue = GST_ELEMENT (user_data);
|
||||
GstPlayBaseBin *play_base_bin = g_object_get_data (G_OBJECT (queue), "pbb");
|
||||
guint level = 0;
|
||||
|
||||
g_object_get (G_OBJECT (queue), "current-level-bytes", &level, NULL);
|
||||
GST_DEBUG ("Queue size: %u bytes", level);
|
||||
g_signal_emit (play_base_bin,
|
||||
gst_play_base_bin_signals[BUFFERING_SIGNAL], 0,
|
||||
level * 100 / (512 * 1024));
|
||||
|
||||
/* continue! */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
buffer_underrun (GstElement * queue, GstPlayBaseBin * play_base_bin)
|
||||
{
|
||||
GST_DEBUG ("Underrun, re-caching");
|
||||
|
||||
/* On underrun, we want to temoprarily pause playback, set a "min-size"
|
||||
* treshold and wait for the running signal and then play again. Take
|
||||
* care of possible deadlocks and so on, */
|
||||
g_object_set (queue, "min-threshold-bytes", 64 * 1024, NULL);
|
||||
|
||||
g_signal_emit (play_base_bin,
|
||||
gst_play_base_bin_signals[BUFFERING_SIGNAL], 0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
buffer_running (GstElement * queue, GstPlayBaseBin * play_base_bin)
|
||||
{
|
||||
GST_DEBUG ("Running");
|
||||
|
||||
/* When we had an underrun, we now want to play again. */
|
||||
g_object_set (queue, "min-threshold-bytes", 0,
|
||||
"max-size-bytes", 512 * 1024, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
buffer_overrun (GstElement * queue, GstPlayBaseBin * play_base_bin)
|
||||
{
|
||||
GST_DEBUG ("Overrun, leaking upstream and flushing next few buffers");
|
||||
|
||||
/* we want to decrease max-size here so the next few bytes are flushed */
|
||||
g_object_set (queue, "max-size-bytes", 448 * 1024, NULL);
|
||||
|
||||
g_signal_emit (play_base_bin,
|
||||
gst_play_base_bin_signals[BUFFERING_SIGNAL], 0, 100);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate source ! subparse bins.
|
||||
*/
|
||||
|
@ -980,9 +1047,12 @@ setup_subtitle (GstPlayBaseBin * play_base_bin, gchar * sub_uri)
|
|||
if (!source)
|
||||
return NULL;
|
||||
|
||||
subparse = gst_element_factory_make ("subparse", NULL);
|
||||
if (!(subparse = gst_element_factory_make ("subparse", NULL))) {
|
||||
gst_object_unref (GST_OBJECT (source));
|
||||
return NULL;
|
||||
}
|
||||
name = g_strdup_printf ("subbin");
|
||||
subbin = gst_thread_new (name);
|
||||
subbin = gst_bin_new (name);
|
||||
g_free (name);
|
||||
|
||||
gst_bin_add_many (GST_BIN (subbin), source, subparse, NULL);
|
||||
|
@ -999,12 +1069,9 @@ setup_subtitle (GstPlayBaseBin * play_base_bin, gchar * sub_uri)
|
|||
*/
|
||||
|
||||
static GstElement *
|
||||
gen_source_element (GstPlayBaseBin * play_base_bin,
|
||||
GstElement ** subbin, gboolean * _is_stream)
|
||||
gen_source_element (GstPlayBaseBin * play_base_bin, GstElement ** subbin)
|
||||
{
|
||||
GstElement *source, *queue, *bin;
|
||||
GstProbe *probe;
|
||||
gboolean is_stream;
|
||||
GstElement *source;
|
||||
|
||||
/* stip subtitle from uri */
|
||||
if (!play_base_bin->uri)
|
||||
|
@ -1023,34 +1090,12 @@ gen_source_element (GstPlayBaseBin * play_base_bin,
|
|||
return NULL;
|
||||
|
||||
/* lame - FIXME, maybe we can use seek_types/mask here? */
|
||||
*_is_stream = is_stream = !strncmp (play_base_bin->uri, "http://", 7) ||
|
||||
!strncmp (play_base_bin->uri, "mms://", 6);
|
||||
if (!is_stream)
|
||||
return source;
|
||||
play_base_bin->is_stream = !strncmp (play_base_bin->uri, "http://", 7) ||
|
||||
!strncmp (play_base_bin->uri, "mms://", 6) ||
|
||||
!strncmp (play_base_bin->uri, "rtp://", 6) ||
|
||||
!strncmp (play_base_bin->uri, "rtsp://", 7);
|
||||
|
||||
/* buffer */
|
||||
bin = gst_thread_new ("sourcebin");
|
||||
queue = gst_element_factory_make ("queue", "buffer");
|
||||
g_object_set (queue, "max-size-bytes", 512 * 1024,
|
||||
"max-size-buffers", 0, NULL);
|
||||
/* I'd like it to be leaky too, but only for live sources. How? */
|
||||
g_signal_connect (queue, "underrun", G_CALLBACK (buffer_underrun),
|
||||
play_base_bin);
|
||||
g_signal_connect (queue, "running", G_CALLBACK (buffer_running),
|
||||
play_base_bin);
|
||||
g_signal_connect (queue, "overrun", G_CALLBACK (buffer_overrun),
|
||||
play_base_bin);
|
||||
|
||||
/* give updates on queue size */
|
||||
probe = gst_probe_new (FALSE, check_queue, queue);
|
||||
gst_pad_add_probe (gst_element_get_pad (source, "src"), probe);
|
||||
g_object_set_data (G_OBJECT (queue), "pbb", play_base_bin);
|
||||
|
||||
gst_element_link (source, queue);
|
||||
gst_bin_add_many (GST_BIN (bin), source, queue, NULL);
|
||||
gst_element_add_ghost_pad (bin, gst_element_get_pad (queue, "src"), "src");
|
||||
|
||||
return bin;
|
||||
return source;
|
||||
}
|
||||
|
||||
/* Setup the substreams (to be called right after group_commit ()) */
|
||||
|
@ -1097,18 +1142,29 @@ setup_substreams (GstPlayBaseBin * play_base_bin)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when we're redirected to a new URI.
|
||||
*/
|
||||
static void
|
||||
got_redirect (GstElement * element, const gchar * new_location, gpointer data)
|
||||
{
|
||||
gchar **location = data;
|
||||
|
||||
if (!*location)
|
||||
*location = g_strdup (new_location);
|
||||
}
|
||||
|
||||
/* 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,
|
||||
gboolean * _stream, GError ** error)
|
||||
gchar ** new_location, GError ** error)
|
||||
{
|
||||
GstElement *old_src;
|
||||
GstElement *old_dec;
|
||||
GstPad *srcpad = NULL;
|
||||
GstElement *subbin;
|
||||
gboolean stream;
|
||||
|
||||
if (!play_base_bin->need_rebuild)
|
||||
return TRUE;
|
||||
|
@ -1119,8 +1175,7 @@ setup_source (GstPlayBaseBin * play_base_bin,
|
|||
old_src = play_base_bin->source;
|
||||
|
||||
/* create and configure an element that can handle the uri */
|
||||
play_base_bin->source = gen_source_element (play_base_bin, &subbin, &stream);
|
||||
*_stream = stream;
|
||||
play_base_bin->source = gen_source_element (play_base_bin, &subbin);
|
||||
|
||||
if (!play_base_bin->source) {
|
||||
/* whoops, could not create the source element */
|
||||
|
@ -1137,11 +1192,14 @@ setup_source (GstPlayBaseBin * play_base_bin,
|
|||
}
|
||||
gst_bin_add (GST_BIN (play_base_bin->thread), play_base_bin->source);
|
||||
g_object_notify (G_OBJECT (play_base_bin), "source");
|
||||
|
||||
/* make sure the new element has the same state as the parent */
|
||||
#if 0
|
||||
if (gst_bin_sync_children_state (GST_BIN (play_base_bin->thread)) ==
|
||||
GST_STATE_FAILURE) {
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* remove the old decoder now, if any */
|
||||
|
@ -1180,7 +1238,7 @@ setup_source (GstPlayBaseBin * play_base_bin,
|
|||
/* 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 (play_base_bin->source)->pads;
|
||||
pads; pads = g_list_next (pads)) {
|
||||
GstPad *pad = GST_PAD (pads->data);
|
||||
GstStructure *structure;
|
||||
|
@ -1198,7 +1256,7 @@ setup_source (GstPlayBaseBin * play_base_bin,
|
|||
if (caps == NULL || gst_caps_is_empty (caps) ||
|
||||
gst_caps_get_size (caps) == 0) {
|
||||
if (caps != NULL)
|
||||
gst_caps_free (caps);
|
||||
gst_caps_unref (caps);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1212,7 +1270,7 @@ setup_source (GstPlayBaseBin * play_base_bin,
|
|||
is_raw = TRUE;
|
||||
}
|
||||
|
||||
gst_caps_free (caps);
|
||||
gst_caps_unref (caps);
|
||||
}
|
||||
if (is_raw) {
|
||||
no_more_pads (play_base_bin->source, play_base_bin);
|
||||
|
@ -1246,6 +1304,8 @@ setup_source (GstPlayBaseBin * play_base_bin,
|
|||
gst_object_unref (GST_OBJECT (old_dec));
|
||||
}
|
||||
|
||||
g_signal_connect (play_base_bin->decoder, "got_redirect",
|
||||
G_CALLBACK (got_redirect), new_location);
|
||||
res = gst_pad_link (srcpad,
|
||||
gst_element_get_pad (play_base_bin->decoder, "sink"));
|
||||
if (!res) {
|
||||
|
@ -1259,7 +1319,7 @@ setup_source (GstPlayBaseBin * play_base_bin,
|
|||
sig3 = g_signal_connect (G_OBJECT (play_base_bin->decoder), "no-more-pads",
|
||||
G_CALLBACK (no_more_pads), play_base_bin);
|
||||
|
||||
if (!stream) {
|
||||
if (!play_base_bin->is_stream) {
|
||||
sig4 = g_signal_connect (G_OBJECT (play_base_bin->decoder),
|
||||
"unknown-type", G_CALLBACK (unknown_type), play_base_bin);
|
||||
sig5 = g_signal_connect (G_OBJECT (play_base_bin->thread), "error",
|
||||
|
@ -1270,7 +1330,7 @@ setup_source (GstPlayBaseBin * play_base_bin,
|
|||
* the signal handlers then
|
||||
*/
|
||||
g_mutex_lock (play_base_bin->group_lock);
|
||||
if (gst_element_set_state (play_base_bin->thread, GST_STATE_PLAYING) ==
|
||||
if (gst_element_set_state (play_base_bin->thread, GST_STATE_PAUSED) ==
|
||||
GST_STATE_SUCCESS) {
|
||||
GST_DEBUG ("waiting for first group...");
|
||||
sig6 = g_signal_connect (G_OBJECT (play_base_bin->thread),
|
||||
|
@ -1300,7 +1360,7 @@ setup_source (GstPlayBaseBin * play_base_bin,
|
|||
/* make subs iterate from now on */
|
||||
gst_bin_add (GST_BIN (play_base_bin->thread), play_base_bin->subtitle);
|
||||
}
|
||||
if (!stream) {
|
||||
if (!play_base_bin->is_stream) {
|
||||
setup_substreams (play_base_bin);
|
||||
}
|
||||
}
|
||||
|
@ -1550,7 +1610,7 @@ play_base_eos (GstBin * bin, GstPlayBaseBin * play_base_bin)
|
|||
|
||||
GST_LOG ("forwarding EOS");
|
||||
|
||||
gst_element_set_eos (GST_ELEMENT (play_base_bin));
|
||||
//gst_element_set_eos (GST_ELEMENT (play_base_bin));
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
|
@ -1564,32 +1624,20 @@ gst_play_base_bin_change_state (GstElement * element)
|
|||
switch (GST_STATE_TRANSITION (element)) {
|
||||
case GST_STATE_NULL_TO_READY:
|
||||
{
|
||||
GstScheduler *sched;
|
||||
play_base_bin->thread = gst_bin_new ("internal_thread");
|
||||
|
||||
play_base_bin->thread = gst_thread_new ("internal_thread");
|
||||
sched = gst_scheduler_factory_make ("opt", play_base_bin->thread);
|
||||
if (sched) {
|
||||
gst_element_set_scheduler (play_base_bin->thread, sched);
|
||||
gst_element_set_state (play_base_bin->thread, GST_STATE_READY);
|
||||
|
||||
gst_element_set_state (play_base_bin->thread, GST_STATE_READY);
|
||||
|
||||
g_signal_connect (play_base_bin->thread, "found_tag",
|
||||
G_CALLBACK (gst_play_base_bin_found_tag), play_base_bin);
|
||||
} else {
|
||||
g_warning ("could not get 'opt' scheduler");
|
||||
gst_object_unref (GST_OBJECT (play_base_bin->thread));
|
||||
play_base_bin->thread = NULL;
|
||||
|
||||
ret = GST_STATE_FAILURE;
|
||||
}
|
||||
g_signal_connect (play_base_bin->thread, "found_tag",
|
||||
G_CALLBACK (gst_play_base_bin_found_tag), play_base_bin);
|
||||
break;
|
||||
}
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
{
|
||||
GError *error = NULL;
|
||||
gboolean stream;
|
||||
gchar *new_location = NULL;
|
||||
|
||||
if (!setup_source (play_base_bin, &stream, &error) || error != NULL) {
|
||||
if (!setup_source (play_base_bin, &new_location, &error) || error != NULL) {
|
||||
if (!error) {
|
||||
/* opening failed but no error - hellup */
|
||||
GST_ELEMENT_ERROR (GST_ELEMENT (play_base_bin), STREAM,
|
||||
|
@ -1602,7 +1650,12 @@ gst_play_base_bin_change_state (GstElement * element)
|
|||
g_error_free (error);
|
||||
}
|
||||
ret = GST_STATE_FAILURE;
|
||||
} else if (stream) {
|
||||
} else if (new_location) {
|
||||
g_signal_emit (play_base_bin, gst_play_base_bin_signals[REDIRECT],
|
||||
0, new_location);
|
||||
g_free (new_location);
|
||||
ret = GST_STATE_FAILURE;
|
||||
} else if (play_base_bin->is_stream) {
|
||||
ret = gst_element_set_state (play_base_bin->thread, GST_STATE_PAUSED);
|
||||
} else {
|
||||
const GList *item;
|
||||
|
@ -1652,6 +1705,7 @@ gst_play_base_bin_change_state (GstElement * element)
|
|||
("File \"%s\" is not a media file", play_base_bin->uri),
|
||||
(NULL));
|
||||
}
|
||||
gst_element_set_state (play_base_bin->thread, GST_STATE_READY);
|
||||
ret = GST_STATE_FAILURE;
|
||||
} else {
|
||||
ret = gst_element_set_state (play_base_bin->thread, GST_STATE_PAUSED);
|
||||
|
@ -1666,7 +1720,7 @@ gst_play_base_bin_change_state (GstElement * element)
|
|||
G_CALLBACK (gst_play_base_bin_error), play_base_bin);
|
||||
g_signal_connect (G_OBJECT (play_base_bin->thread), "eos",
|
||||
G_CALLBACK (play_base_eos), play_base_bin);
|
||||
if (!stream) {
|
||||
if (!play_base_bin->is_stream) {
|
||||
GST_DEBUG ("emit signal");
|
||||
g_signal_emit (play_base_bin,
|
||||
gst_play_base_bin_signals[SETUP_OUTPUT_PADS_SIGNAL], 0);
|
||||
|
@ -1713,7 +1767,7 @@ gst_play_base_bin_change_state (GstElement * element)
|
|||
/* virtual function to add elements to this bin. The idea is to
|
||||
* wrap the element in a thread automatically.
|
||||
*/
|
||||
static void
|
||||
static gboolean
|
||||
gst_play_base_bin_add_element (GstBin * bin, GstElement * element)
|
||||
{
|
||||
GstPlayBaseBin *play_base_bin;
|
||||
|
@ -1721,15 +1775,12 @@ gst_play_base_bin_add_element (GstBin * bin, GstElement * element)
|
|||
play_base_bin = GST_PLAY_BASE_BIN (bin);
|
||||
|
||||
if (play_base_bin->thread) {
|
||||
GstScheduler *sched;
|
||||
GstClock *clock;
|
||||
|
||||
if (play_base_bin->threaded) {
|
||||
gchar *name;
|
||||
GstElement *thread;
|
||||
|
||||
name = g_strdup_printf ("thread_%s", gst_element_get_name (element));
|
||||
thread = gst_thread_new (name);
|
||||
thread = gst_bin_new (name);
|
||||
g_free (name);
|
||||
|
||||
gst_bin_add (GST_BIN (thread), element);
|
||||
|
@ -1739,21 +1790,19 @@ gst_play_base_bin_add_element (GstBin * bin, GstElement * element)
|
|||
if (GST_STATE (play_base_bin) > GST_STATE_READY) {
|
||||
gst_element_set_state (element, GST_STATE (play_base_bin));
|
||||
}
|
||||
|
||||
/* 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);
|
||||
} else {
|
||||
g_warning ("adding elements is not allowed in NULL");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* 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 gboolean
|
||||
gst_play_base_bin_remove_element (GstBin * bin, GstElement * element)
|
||||
{
|
||||
GstPlayBaseBin *play_base_bin;
|
||||
|
@ -1786,7 +1835,9 @@ gst_play_base_bin_remove_element (GstBin * bin, GstElement * element)
|
|||
}
|
||||
} else {
|
||||
g_warning ("removing elements is not allowed in NULL");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -68,12 +68,14 @@ struct _GstPlayBaseBin {
|
|||
/* properties */
|
||||
gboolean threaded;
|
||||
guint64 queue_size;
|
||||
guint queue_threshold;
|
||||
|
||||
gint current[NUM_TYPES];
|
||||
|
||||
/* internal thread */
|
||||
GstElement *thread;
|
||||
gchar *uri, *suburi;
|
||||
gboolean is_stream;
|
||||
GstElement *source;
|
||||
GstElement *decoder;
|
||||
GstElement *subtitle; /* additional filesrc ! subparse bin */
|
||||
|
@ -103,6 +105,10 @@ struct _GstPlayBaseBinClass {
|
|||
gint percentage);
|
||||
void (*group_switch) (GstPlayBaseBin *play_base_bin);
|
||||
|
||||
/* 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,
|
||||
|
|
|
@ -49,6 +49,7 @@ struct _GstPlayBin
|
|||
GstElement *video_sink;
|
||||
GstElement *visualisation;
|
||||
GstElement *volume_element;
|
||||
GstElement *textoverlay_element;
|
||||
gfloat volume;
|
||||
|
||||
/* these are the currently active sinks */
|
||||
|
@ -65,6 +66,9 @@ struct _GstPlayBin
|
|||
|
||||
/* boolean to see if we're currently switching groups */
|
||||
gboolean group_switch;
|
||||
|
||||
/* font description */
|
||||
gchar *font_desc;
|
||||
};
|
||||
|
||||
struct _GstPlayBinClass
|
||||
|
@ -80,7 +84,8 @@ enum
|
|||
ARG_VIDEO_SINK,
|
||||
ARG_VIS_PLUGIN,
|
||||
ARG_VOLUME,
|
||||
ARG_FRAME
|
||||
ARG_FRAME,
|
||||
ARG_FONT_DESC
|
||||
};
|
||||
|
||||
/* signals */
|
||||
|
@ -182,13 +187,18 @@ gst_play_bin_class_init (GstPlayBinClass * klass)
|
|||
g_param_spec_object ("vis-plugin", "Vis plugin",
|
||||
"the visualization element to use (NULL = none)",
|
||||
GST_TYPE_ELEMENT, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (gobject_klass), ARG_VOLUME,
|
||||
g_object_class_install_property (gobject_klass, ARG_VOLUME,
|
||||
g_param_spec_double ("volume", "volume", "volume",
|
||||
0.0, VOLUME_MAX_DOUBLE, 1.0, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (gobject_klass), ARG_FRAME,
|
||||
g_object_class_install_property (gobject_klass, ARG_FRAME,
|
||||
g_param_spec_boxed ("frame", "Frame",
|
||||
"The last frame (NULL = no video available)",
|
||||
GST_TYPE_BUFFER, G_PARAM_READABLE));
|
||||
g_object_class_install_property (gobject_klass, ARG_FONT_DESC,
|
||||
g_param_spec_string ("subtitle-font-desc",
|
||||
"Subtitle font description",
|
||||
"Pango font description of font "
|
||||
"to be used for subtitle rendering", NULL, G_PARAM_WRITABLE));
|
||||
|
||||
gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_bin_dispose);
|
||||
|
||||
|
@ -216,16 +226,15 @@ gst_play_bin_init (GstPlayBin * play_bin)
|
|||
play_bin->audio_sink = NULL;
|
||||
play_bin->visualisation = NULL;
|
||||
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;
|
||||
play_bin->cache = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
NULL, (GDestroyNotify) gst_object_unref);
|
||||
play_bin->group_switch = FALSE;
|
||||
|
||||
/* no iterate is needed */
|
||||
GST_FLAG_SET (play_bin, GST_BIN_SELF_SCHEDULABLE);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -253,7 +262,8 @@ gst_play_bin_dispose (GObject * object)
|
|||
gst_object_unref (GST_OBJECT (play_bin->visualisation));
|
||||
play_bin->visualisation = NULL;
|
||||
}
|
||||
|
||||
g_free (play_bin->font_desc);
|
||||
play_bin->font_desc = NULL;
|
||||
|
||||
if (G_OBJECT_CLASS (parent_class)->dispose) {
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
|
@ -314,6 +324,14 @@ gst_play_bin_set_property (GObject * object, guint prop_id,
|
|||
play_bin->volume, NULL);
|
||||
}
|
||||
break;
|
||||
case ARG_FONT_DESC:
|
||||
g_free (play_bin->font_desc);
|
||||
play_bin->font_desc = g_strdup (g_value_get_string (value));
|
||||
if (play_bin->textoverlay_element) {
|
||||
g_object_set (G_OBJECT (play_bin->textoverlay_element),
|
||||
"font-desc", g_value_get_string (value), NULL);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -406,7 +424,7 @@ gen_video_element (GstPlayBin * play_bin)
|
|||
if (play_bin->video_sink) {
|
||||
sink = play_bin->video_sink;
|
||||
} else {
|
||||
sink = gst_element_factory_make (DEFAULT_VIDEOSINK, "sink");
|
||||
sink = gst_element_factory_make ("autovideosink", "sink");
|
||||
}
|
||||
gst_object_ref (GST_OBJECT (sink));
|
||||
g_hash_table_insert (play_bin->cache, "video_sink", sink);
|
||||
|
@ -455,6 +473,11 @@ gen_text_element (GstPlayBin * play_bin)
|
|||
overlay = gst_element_factory_make ("textoverlay", "overlay");
|
||||
g_object_set (G_OBJECT (overlay),
|
||||
"halign", "center", "valign", "bottom", NULL);
|
||||
play_bin->textoverlay_element = overlay;
|
||||
if (play_bin->font_desc) {
|
||||
g_object_set (G_OBJECT (play_bin->textoverlay_element),
|
||||
"font-desc", play_bin->font_desc, NULL);
|
||||
}
|
||||
vbin = gen_video_element (play_bin);
|
||||
if (!overlay) {
|
||||
g_warning ("No overlay (pango) element, subtitles disabled");
|
||||
|
@ -511,7 +534,7 @@ gen_audio_element (GstPlayBin * play_bin)
|
|||
if (play_bin->audio_sink) {
|
||||
sink = play_bin->audio_sink;
|
||||
} else {
|
||||
sink = gst_element_factory_make (DEFAULT_AUDIOSINK, "sink");
|
||||
sink = gst_element_factory_make ("autoaudiosink", "sink");
|
||||
play_bin->audio_sink = GST_ELEMENT (gst_object_ref (GST_OBJECT (sink)));
|
||||
}
|
||||
|
||||
|
@ -674,6 +697,9 @@ remove_sinks (GstPlayBin * play_bin)
|
|||
gst_buffer_unref (play_bin->frame);
|
||||
play_bin->frame = NULL;
|
||||
}
|
||||
|
||||
play_bin->textoverlay_element = NULL;
|
||||
play_bin->volume_element = NULL;
|
||||
}
|
||||
|
||||
/* loop over the streams and set up the pipeline to play this
|
||||
|
@ -855,7 +881,7 @@ gst_play_bin_send_event (GstElement * element, GstEvent * event)
|
|||
|
||||
play_bin = GST_PLAY_BIN (element);
|
||||
|
||||
state = gst_element_get_state (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) {
|
||||
|
|
|
@ -206,7 +206,7 @@ gst_stream_info_dispose (GObject * object)
|
|||
g_free (stream_info->decoder);
|
||||
stream_info->decoder = NULL;
|
||||
if (stream_info->caps) {
|
||||
gst_caps_free (stream_info->caps);
|
||||
gst_caps_unref (stream_info->caps);
|
||||
stream_info->caps = NULL;
|
||||
}
|
||||
|
||||
|
@ -225,7 +225,7 @@ stream_info_change_state (GstElement * element,
|
|||
/* state change will annoy us */
|
||||
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);
|
||||
//gst_pad_set_active_recursive (GST_PAD (stream_info->object), FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,8 +241,8 @@ gst_stream_info_set_mute (GstStreamInfo * stream_info, gboolean mute)
|
|||
|
||||
if (mute != stream_info->mute) {
|
||||
stream_info->mute = mute;
|
||||
gst_pad_set_active_recursive ((GstPad *)
|
||||
GST_PAD_REALIZE (stream_info->object), !mute);
|
||||
//gst_pad_set_active_recursive ((GstPad *)
|
||||
// GST_PAD_REALIZE (stream_info->object), !mute);
|
||||
|
||||
if (mute) {
|
||||
g_signal_connect (gst_pad_get_parent ((GstPad *)
|
||||
|
|
|
@ -58,12 +58,13 @@ 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 GstPadLinkReturn gst_stream_selector_link (GstPad * pad,
|
||||
const GstCaps * caps);
|
||||
static gboolean gst_stream_selector_setcaps (GstPad * pad, GstCaps * caps);
|
||||
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 void gst_stream_selector_chain (GstPad * pad, GstData * data);
|
||||
static gboolean gst_stream_selector_event (GstPad * pad, GstEvent * event);
|
||||
static GstFlowReturn gst_stream_selector_chain (GstPad * pad,
|
||||
GstBuffer * buffer);
|
||||
|
||||
static GstElementClass *parent_class = NULL;
|
||||
|
||||
|
@ -134,8 +135,8 @@ 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_link_function (sel->srcpad,
|
||||
GST_DEBUG_FUNCPTR (gst_stream_selector_link));
|
||||
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_element_add_pad (GST_ELEMENT (sel), sel->srcpad);
|
||||
|
@ -173,7 +174,6 @@ gst_stream_selector_get_linked_pad (GstPad * pad)
|
|||
static GstCaps *
|
||||
gst_stream_selector_get_caps (GstPad * pad)
|
||||
{
|
||||
GstStreamSelector *sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad));
|
||||
GstPad *otherpad = gst_stream_selector_get_linked_pad (pad);
|
||||
|
||||
if (!otherpad) {
|
||||
|
@ -181,19 +181,17 @@ gst_stream_selector_get_caps (GstPad * pad)
|
|||
"Pad %s not linked, returning ANY", gst_pad_get_name (pad));
|
||||
|
||||
return gst_caps_new_any ();
|
||||
} else if (otherpad == sel->last_active_sinkpad && sel->in_chain) {
|
||||
return gst_caps_copy (GST_PAD_CAPS (sel->last_active_sinkpad));
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (gst_pad_get_parent (pad),
|
||||
"Pad %s is linked (to %s), returning allowed-caps",
|
||||
"Pad %s is linked (to %s), returning peer-caps",
|
||||
gst_pad_get_name (pad), gst_pad_get_name (otherpad));
|
||||
|
||||
return gst_pad_get_allowed_caps (otherpad);
|
||||
return gst_pad_peer_get_caps (otherpad);
|
||||
}
|
||||
|
||||
static GstPadLinkReturn
|
||||
gst_stream_selector_link (GstPad * pad, const GstCaps * caps)
|
||||
static gboolean
|
||||
gst_stream_selector_setcaps (GstPad * pad, GstCaps * caps)
|
||||
{
|
||||
GstPad *otherpad = gst_stream_selector_get_linked_pad (pad);
|
||||
|
||||
|
@ -202,14 +200,16 @@ gst_stream_selector_link (GstPad * pad, const GstCaps * caps)
|
|||
"Pad %s not linked, returning %s",
|
||||
gst_pad_get_name (pad), GST_PAD_IS_SINK (pad) ? "ok" : "delayed");
|
||||
|
||||
return GST_PAD_IS_SINK (pad) ? GST_PAD_LINK_OK : GST_PAD_LINK_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));
|
||||
|
||||
return gst_pad_try_set_caps (otherpad, caps);
|
||||
gst_pad_set_caps (otherpad, caps);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GList *
|
||||
|
@ -241,12 +241,12 @@ gst_stream_selector_request_new_pad (GstElement * element,
|
|||
sel->last_active_sinkpad = sinkpad;
|
||||
g_free (name);
|
||||
|
||||
gst_pad_set_link_function (sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_stream_selector_link));
|
||||
gst_pad_set_getcaps_function (sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_stream_selector_get_caps));
|
||||
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);
|
||||
|
@ -254,33 +254,36 @@ gst_stream_selector_request_new_pad (GstElement * element,
|
|||
return sinkpad;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_stream_selector_chain (GstPad * pad, GstData * data)
|
||||
static gboolean
|
||||
gst_stream_selector_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
GstStreamSelector *sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad));
|
||||
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)
|
||||
{
|
||||
GstStreamSelector *sel = GST_STREAM_SELECTOR (GST_PAD_PARENT (pad));
|
||||
|
||||
/* first, check if the active pad changed. If so, redo
|
||||
* negotiation and fail if that fails. */
|
||||
if (pad != sel->last_active_sinkpad) {
|
||||
GstPadLinkReturn ret;
|
||||
|
||||
GST_LOG_OBJECT (sel, "stream change detected, switching from %s to %s",
|
||||
sel->last_active_sinkpad ?
|
||||
gst_pad_get_name (sel->last_active_sinkpad) : "none",
|
||||
gst_pad_get_name (pad));
|
||||
sel->last_active_sinkpad = pad;
|
||||
sel->in_chain = TRUE;
|
||||
ret = gst_pad_renegotiate (sel->srcpad);
|
||||
sel->in_chain = FALSE;
|
||||
if (GST_PAD_LINK_FAILED (ret)) {
|
||||
GST_ELEMENT_ERROR (sel, CORE, NEGOTIATION, (NULL), (NULL));
|
||||
sel->last_active_sinkpad = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* forward */
|
||||
GST_DEBUG_OBJECT (sel, "Forwarding %s %p from pad %s",
|
||||
GST_IS_EVENT (data) ? "event" : "buffer", data, gst_pad_get_name (pad));
|
||||
gst_pad_push (sel->srcpad, data);
|
||||
GST_DEBUG_OBJECT (sel, "Forwarding buffer %p from pad %s",
|
||||
buffer, GST_OBJECT_NAME (pad));
|
||||
|
||||
return gst_pad_push (sel->srcpad, buffer);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ gen_video_element ()
|
|||
GstElement *conv;
|
||||
GstElement *sink;
|
||||
|
||||
element = gst_thread_new ("vbin");
|
||||
element = gst_bin_new ("vbin");
|
||||
conv = gst_element_factory_make ("ffmpegcolorspace", "conv");
|
||||
sink = gst_element_factory_make (DEFAULT_VIDEOSINK, "sink");
|
||||
|
||||
|
@ -49,7 +49,7 @@ gen_audio_element ()
|
|||
GstElement *conv;
|
||||
GstElement *sink;
|
||||
|
||||
element = gst_thread_new ("abin");
|
||||
element = gst_bin_new ("abin");
|
||||
conv = gst_element_factory_make ("audioconvert", "conv");
|
||||
sink = gst_element_factory_make (DEFAULT_AUDIOSINK, "sink");
|
||||
|
||||
|
@ -130,8 +130,7 @@ main (gint argc, gchar * argv[])
|
|||
g_print ("could not play\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
gst_main ();
|
||||
//gst_main ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1183,8 +1183,6 @@ gst_xvimagesink_getcaps (GstBaseSink * bsink)
|
|||
|
||||
xvimagesink = GST_XVIMAGESINK (bsink);
|
||||
|
||||
g_print ("getcaps\n");
|
||||
|
||||
if (xvimagesink->xcontext)
|
||||
return gst_caps_ref (xvimagesink->xcontext->caps);
|
||||
|
||||
|
|
Loading…
Reference in a new issue