Commit 24f28cfd authored by Tim-Philipp Müller's avatar Tim-Philipp Müller
Browse files

playback: remove old playbin and decodebin elements

parent 2c6dbae4
......@@ -6,16 +6,13 @@ glib_gen_basename = gstplay
built_sources = gstplay-marshal.c
built_headers = gstplay-marshal.h
plugin_LTLIBRARIES = libgstplaybin.la libgstdecodebin.la libgstdecodebin2.la
plugin_LTLIBRARIES = libgstplaybin.la libgstdecodebin2.la
libgstplaybin_la_SOURCES = \
gstplayback.c \
gstplaybin.c \
gstplaybin2.c \
gstplaysink.c \
gstplaybasebin.c \
gstplay-enum.c \
gststreaminfo.c \
gststreamselector.c \
gstsubtitleoverlay.c \
gstplaysinkvideoconvert.c \
......@@ -32,15 +29,6 @@ libgstplaybin_la_LIBADD = \
$(GST_LIBS)
libgstplaybin_la_LIBTOOLFLAGS = --tag=disable-static
libgstdecodebin_la_SOURCES = gstdecodebin.c
nodist_libgstdecodebin_la_SOURCES = $(built_sources)
libgstdecodebin_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
libgstdecodebin_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstdecodebin_la_LIBADD = \
$(top_builddir)/gst-libs/gst/pbutils/libgstpbutils-@GST_MAJORMINOR@.la \
$(GST_LIBS)
libgstdecodebin_la_LIBTOOLFLAGS = --tag=disable-static
libgstdecodebin2_la_SOURCES = gstdecodebin2.c gsturidecodebin.c gstplay-enum.c
nodist_libgstdecodebin2_la_SOURCES = $(built_sources)
libgstdecodebin2_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
......@@ -52,9 +40,7 @@ libgstdecodebin2_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = \
gstplayback.h \
gstplaybasebin.h \
gstplaysink.h \
gststreaminfo.h \
gstplay-enum.h \
gststreamselector.h \
gstrawcaps.h \
......@@ -73,18 +59,6 @@ include $(top_srcdir)/common/gst-glib-gen.mak
Android.mk: Makefile.am $(BUILT_SOURCES)
androgenizer \
-:PROJECT libgstdecodebin -:SHARED libgstdecodebin \
-:TAGS eng debug \
-:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
-:SOURCES $(libgstdecodebin_la_SOURCES) \
$(nodist_libgstdecodebin_la_SOURCES) \
-:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstdecodebin_la_CFLAGS) \
-:LDFLAGS $(libgstdecodebin_la_LDFLAGS) \
$(libgstdecodebin_la_LIBADD) \
-ldl \
-:PASSTHROUGH LOCAL_ARM_MODE:=arm \
LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
\
-:PROJECT libgstdecodebin2 -:SHARED libgstdecodebin2 \
-:TAGS eng debug \
-:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
......
decodebin:
A bin with a sinkpad that decodes the data into raw formats. It works by sending
the input data through a typefind element and then recursively autoplugs elements
from the registry until a raw format is obtained. It will then create a new ghostpad
on itself to signal the app of the new pad.
Decodebin will also remove pads when they are removed from the stream.
TODO
- reuse of decoderbin, cleanup in READY state
- 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:
A bin with an uri property. It will find the right source element from the registry
and connect a decoderbin to it. When going to the PAUSED state, it will iterate the
decoderbin and listen for new pad signals from it. It will connect a queue to each
new pad and will iterate the decoderbin until one of the queues is filled. It is
assumed that by that time all the streams will be found so that when leaving the
PAUSED state, one can query the number of streams in the media file with the given
uri.
Playbasebin internally groups related streams together in a GstPlayBaseGroup. This
is particulary important for chained oggs. Initially, a new group is created in
the 'building' state. All new streams will be added to the building group until
no-more-pads is signaled or one of the preroll queues overflows. When this happens,
the group is commited to a list of groups ready for playback. PlaybaseBin will then
attach a padprobe to each stream to figure out when it finished. It will remove
the current group and install the next playable group, then.
Before going to the PLAYING state, it is possible to connect a custom element to
each of the streams. To do that, you have to add the element to the bin and then
connect the pad(s) from the stream(s). You do not have to add the elements in
a thread, the bin will take care of then when it's needed. You are allowed to use
threads inside the elements, of course.
The bin tries to be smart and doesn't add a queue when there is only one possible
stream.
TODO
- reuse, cleanup in ready state
- when the first pad is closed, it's possible that another dynamic element is
added somewhere so that we need a queue for the first pad as well.
playbin:
Extends playbasebin, sets up default audiosink and videosink for first audio/video
stream detected. implements seeking and querying on the configured sinks.
It also waits for new notifications from playbasebin about any new groups that are
becomming active. It then disconnects the sinks and reconnects them to the new
pads in the group.
TODO
- reuse, refcounting, cleanup in READY state
- be smarter about replugging the sinks instead of removing them and readding them.
- Do not crap out when the audio device is in use.
general
TODO
- playlist support. maybe use a playlist bin that streams the contents of the
playlist on a pad, interleaved with new_media events. Also add a tuner
interface while we're at it.
This diff is collapsed.
......@@ -30,7 +30,6 @@
#include "gstplayback.h"
#include "gstplaysink.h"
#include "gststreamselector.h"
#include "gststreaminfo.h"
#include "gstsubtitleoverlay.h"
static gboolean
......@@ -49,11 +48,9 @@ plugin_init (GstPlugin * plugin)
/* ref class from a thread-safe context to work around missing bit of
* thread-safety in GObject */
g_type_class_ref (GST_TYPE_STREAM_INFO);
g_type_class_ref (GST_TYPE_STREAM_SELECTOR);
res = gst_play_bin_plugin_init (plugin);
res &= gst_play_bin2_plugin_init (plugin);
res = gst_play_bin2_plugin_init (plugin);
res &= gst_play_sink_plugin_init (plugin);
res &= gst_subtitle_overlay_plugin_init (plugin);
......
This diff is collapsed.
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* <2007> Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_PLAYBASEBIN_H__
#define __GST_PLAYBASEBIN_H__
#include <gst/gst.h>
#include "gststreaminfo.h"
G_BEGIN_DECLS
#define GST_TYPE_PLAY_BASE_BIN (gst_play_base_bin_get_type())
#define GST_PLAY_BASE_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BASE_BIN,GstPlayBaseBin))
#define GST_PLAY_BASE_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BASE_BIN,GstPlayBaseBinClass))
#define GST_IS_PLAY_BASE_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BASE_BIN))
#define GST_IS_PLAY_BASE_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BASE_BIN))
#define GST_PLAY_BASE_BIN_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PLAY_BASE_BIN, \
GstPlayBaseBinClass))
typedef struct _GstPlayBaseBin GstPlayBaseBin;
typedef struct _GstPlayBaseBinClass GstPlayBaseBinClass;
/* a GstPlayBaseGroup is a group of pads and streaminfo that together
* make up a playable stream. A new group is created from the current
* set of pads that are alive when the preroll elements are filled or
* when the no-more-pads signal is fired.
*
* We have to queue the groups as they can be created while the preroll
* queues are still playing the old group. We monitor the EOS signals
* on the preroll queues and when all the streams in the current group
* have EOSed, we switch to the next queued group.
*/
typedef struct
{
GstPlayBaseBin *bin; /* ref to the owner */
gint nstreams;
GList *streaminfo;
GValueArray *streaminfo_value_array;
/* contained decoded elementary streams */
struct {
gint npads;
GstBin *bin;
GstElement *preroll;
GstElement *selector;
gboolean done;
#define NUM_TYPES 4
} type[NUM_TYPES]; /* AUDIO, VIDEO, TEXT, SUBPIC */
} GstPlayBaseGroup;
struct _GstPlayBaseBin {
GstPipeline pipeline;
/* properties */
guint64 queue_size;
guint64 queue_threshold;
guint64 queue_min_threshold;
/* connection speed in bits/sec (0 = unknown) */
guint connection_speed;
/* currently loaded media */
gint current[NUM_TYPES];
gchar *uri, *suburi;
gboolean is_stream;
GstElement *source;
GSList *decoders;
GstElement *subtitle; /* additional filesrc ! subparse bin */
gboolean subtitle_done;
gboolean need_rebuild;
gboolean raw_decoding_mode; /* Use smaller queues when source outputs raw data */
GSList *subtitle_elements; /* subtitle elements that have 'subtitle-encoding' property */
gchar *subencoding; /* encoding to propagate to the above subtitle elements */
GMutex *sub_lock; /* protecting subtitle_elements and subencoding members */
/* group management - using own lock */
GMutex *group_lock; /* lock and mutex to signal availability of new group */
GCond *group_cond;
GstPlayBaseGroup *building_group; /* the group that we are constructing */
GList *queued_groups; /* the constructed groups, head is the active one */
/* for dynamic sources */
guint src_np_sig_id; /* new-pad signal id */
guint src_nmp_sig_id; /* no-more-pads signal id */
gint pending;
};
struct _GstPlayBaseBinClass {
GstPipelineClass parent_class;
/* virtual fuctions */
gboolean (*setup_output_pads) (GstPlayBaseBin *play_base_bin,
GstPlayBaseGroup *group);
void (*set_subtitles_visible) (GstPlayBaseBin *play_base_bin,
gboolean visible);
void (*set_audio_mute) (GstPlayBaseBin *play_base_bin,
gboolean mute);
};
GType gst_play_base_bin_get_type (void);
G_END_DECLS
#endif /* __GST_PLAYBASEBIN_H__ */
This diff is collapsed.
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <gst/gst.h>
#include "gststreaminfo.h"
GST_DEBUG_CATEGORY_STATIC (gst_streaminfo_debug);
#define GST_CAT_DEFAULT gst_streaminfo_debug
/* props */
enum
{
ARG_0,
ARG_PAD,
ARG_TYPE,
ARG_DECODER,
ARG_MUTE,
ARG_CAPS,
ARG_LANG_CODE,
ARG_CODEC
};
/* signals */
enum
{
SIGNAL_MUTED,
LAST_SIGNAL
};
static guint gst_stream_info_signals[LAST_SIGNAL] = { 0 };
#define GST_TYPE_STREAM_TYPE (gst_stream_type_get_type())
static GType
gst_stream_type_get_type (void)
{
static GType stream_type_type = 0;
static const GEnumValue stream_type[] = {
{GST_STREAM_TYPE_UNKNOWN, "Unknown stream", "unknown"},
{GST_STREAM_TYPE_AUDIO, "Audio stream", "audio"},
{GST_STREAM_TYPE_VIDEO, "Video stream", "video"},
{GST_STREAM_TYPE_TEXT, "Text stream", "text"},
{GST_STREAM_TYPE_SUBPICTURE, "Subpicture stream", "subpicture"},
{GST_STREAM_TYPE_ELEMENT,
"Stream handled by element", "element"},
{0, NULL, NULL},
};
if (!stream_type_type) {
stream_type_type = g_enum_register_static ("GstStreamType", stream_type);
}
return stream_type_type;
}
static void gst_stream_info_class_init (GstStreamInfoClass * klass);
static void gst_stream_info_init (GstStreamInfo * stream_info);
static void gst_stream_info_dispose (GObject * object);
static void stream_info_change_state (GstElement * element,
gint old_state, gint new_state, gpointer data);
static void gst_stream_info_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * spec);
static void gst_stream_info_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * spec);
static GObjectClass *parent_class;
//static guint gst_stream_info_signals[LAST_SIGNAL] = { 0 };
GType
gst_stream_info_get_type (void)
{
static GType gst_stream_info_type = 0;
if (!gst_stream_info_type) {
static const GTypeInfo gst_stream_info_info = {
sizeof (GstStreamInfoClass),
NULL,
NULL,
(GClassInitFunc) gst_stream_info_class_init,
NULL,
NULL,
sizeof (GstStreamInfo),
0,
(GInstanceInitFunc) gst_stream_info_init,
NULL
};
gst_stream_info_type = g_type_register_static (G_TYPE_OBJECT,
"GstStreamInfo", &gst_stream_info_info, 0);
}
return gst_stream_info_type;
}
static void
gst_stream_info_class_init (GstStreamInfoClass * klass)
{
GObjectClass *gobject_klass;
gobject_klass = (GObjectClass *) klass;
parent_class = g_type_class_peek_parent (klass);
gobject_klass->set_property = gst_stream_info_set_property;
gobject_klass->get_property = gst_stream_info_get_property;
g_object_class_install_property (gobject_klass, ARG_PAD,
g_param_spec_object ("object", "object",
"Source Pad or object of the stream", GST_TYPE_OBJECT,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_klass, ARG_TYPE,
g_param_spec_enum ("type", "Type", "Type of the stream",
GST_TYPE_STREAM_TYPE, GST_STREAM_TYPE_UNKNOWN,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_klass, ARG_DECODER,
g_param_spec_string ("decoder", "Decoder",
"The decoder used to decode the stream", NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_klass, ARG_MUTE,
g_param_spec_boolean ("mute", "Mute", "Mute or unmute this stream", FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_klass, ARG_CAPS,
g_param_spec_boxed ("caps", "Capabilities",
"Capabilities (or type) of this stream", GST_TYPE_CAPS,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_klass, ARG_LANG_CODE,
g_param_spec_string ("language-code", "Language code",
"Language code for this stream, conforming to ISO-639-1", NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_klass, ARG_CODEC,
g_param_spec_string ("codec", "Codec", "Codec used to encode the stream",
NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
gst_stream_info_signals[SIGNAL_MUTED] =
g_signal_new ("muted", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstStreamInfoClass, muted), NULL, NULL,
gst_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
gobject_klass->dispose = gst_stream_info_dispose;
GST_DEBUG_CATEGORY_INIT (gst_streaminfo_debug, "streaminfo", 0,
"Playbin Stream Info");
}
static void
gst_stream_info_init (GstStreamInfo * stream_info)
{
stream_info->object = NULL;
stream_info->origin = NULL;
stream_info->type = GST_STREAM_TYPE_UNKNOWN;
stream_info->decoder = NULL;
stream_info->mute = FALSE;
stream_info->caps = NULL;
}
static GstProbeReturn
cb_probe (GstPad * pad, GstProbeType type, gpointer type_data,
gpointer user_data)
{
GstEvent *e = type_data;
GstStreamInfo *info = user_data;
if (GST_EVENT_TYPE (e) == GST_EVENT_TAG) {
gchar *codec, *lang;
GstTagList *list;
gst_event_parse_tag (e, &list);
if (info->type != GST_STREAM_TYPE_AUDIO &&
gst_tag_list_get_string (list, GST_TAG_VIDEO_CODEC, &codec)) {
g_free (info->codec);
info->codec = codec;
GST_LOG_OBJECT (pad, "codec = %s (video)", codec);
g_object_notify (G_OBJECT (info), "codec");
} else if (info->type != GST_STREAM_TYPE_VIDEO &&
gst_tag_list_get_string (list, GST_TAG_AUDIO_CODEC, &codec)) {
g_free (info->codec);
info->codec = codec;
GST_LOG_OBJECT (pad, "codec = %s (audio)", codec);
g_object_notify (G_OBJECT (info), "codec");
} else if (gst_tag_list_get_string (list, GST_TAG_CODEC, &codec)) {
g_free (info->codec);
info->codec = codec;
GST_LOG_OBJECT (pad, "codec = %s (generic)", codec);
g_object_notify (G_OBJECT (info), "codec");
}
if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
g_free (info->langcode);
info->langcode = lang;
GST_LOG_OBJECT (pad, "language-code = %s", lang);
g_object_notify (G_OBJECT (info), "language-code");
}
}
return TRUE;
}
GstStreamInfo *
gst_stream_info_new (GstObject * object,
GstStreamType type, const gchar * decoder, const GstCaps * caps)
{
GstStreamInfo *info;
info = g_object_new (GST_TYPE_STREAM_INFO, NULL);
gst_object_ref (object);
if (GST_IS_PAD (object)) {
gst_pad_add_probe (GST_PAD_CAST (object), GST_PROBE_TYPE_EVENT,
cb_probe, info, NULL);
}
info->object = object;
info->type = type;
info->decoder = g_strdup (decoder);
info->origin = object;
if (caps) {
info->caps = gst_caps_copy (caps);
}
return info;
}
static void
gst_stream_info_dispose (GObject * object)
{
GstStreamInfo *stream_info;
stream_info = GST_STREAM_INFO (object);
if (stream_info->object) {
GstElement *parent;
parent = gst_pad_get_parent_element ((GstPad *)
GST_PAD_CAST (stream_info->object));
if (parent != NULL) {
g_signal_handlers_disconnect_by_func (parent,
(gpointer) stream_info_change_state, stream_info);
gst_object_unref (parent);
}
gst_object_unref (stream_info->object);
stream_info->object = NULL;
}
stream_info->origin = NULL;
stream_info->type = GST_STREAM_TYPE_UNKNOWN;
g_free (stream_info->decoder);
stream_info->decoder = NULL;
g_free (stream_info->langcode);
stream_info->langcode = NULL;
g_free (stream_info->codec);
stream_info->codec = NULL;
if (stream_info->caps) {
gst_caps_unref (stream_info->caps);
stream_info->caps = NULL;
}
if (G_OBJECT_CLASS (parent_class)->dispose) {
G_OBJECT_CLASS (parent_class)->dispose (object);
}
}
static void
stream_info_change_state (GstElement * element,
gint old_state, gint new_state, gpointer data)
{
GstStreamInfo *stream_info = data;
if (new_state == GST_STATE_PLAYING) {
/* 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);
g_warning ("FIXME");
}
}
gboolean
gst_stream_info_set_mute (GstStreamInfo * stream_info, gboolean mute)
{
g_return_val_if_fail (GST_IS_STREAM_INFO (stream_info), FALSE);
if (stream_info->type == GST_STREAM_TYPE_ELEMENT) {
g_warning ("cannot mute element stream");
return FALSE;
}
if (mute != stream_info->mute) {
/* nothing really happens here. it looks like gstplaybasebin installs a
* buffer probe hat drops buffers when muting. but the this removes it self
* after first call.
*/
stream_info->mute = mute;
#if 0
gst_pad_set_active ((GstPad *) GST_PAD_CAST (stream_info->object), !mute);
#endif
#if 0
{
GstElement *element;
element = gst_pad_get_parent_element ((GstPad *)
GST_PAD_CAST (stream_info->object));
if (element) {
if (mute) {