gst/playback/: More playbin fixes. Added README. Do better element filtering.

Original commit message from CVS:
* gst/playback/Makefile.am:
* gst/playback/README:
* gst/playback/gstdecodebin.c: (gst_decode_bin_get_type),
(gst_decode_bin_class_init), (gst_decode_bin_factory_filter),
(compare_ranks), (print_feature), (gst_decode_bin_init),
(gst_decode_bin_dispose), (find_compatibles), (close_pad_link),
(try_to_link_1), (new_pad), (close_link), (type_found),
(gst_decode_bin_set_property), (gst_decode_bin_get_property),
(plugin_init):
* gst/playback/gstplaybasebin.c: (gst_play_base_bin_get_type),
(gst_play_base_bin_class_init), (gst_play_base_bin_init),
(gst_play_base_bin_dispose), (rebuild_pipeline), (queue_overrun),
(gen_preroll_element), (no_more_pads), (new_stream),
(setup_source), (gst_play_base_bin_set_property),
(gst_play_base_bin_get_property), (gst_play_base_bin_change_state),
(gst_play_base_bin_add_element),
(gst_play_base_bin_remove_element),
(gst_play_base_bin_mute_stream), (gst_play_base_bin_link_stream),
(gst_play_base_bin_unlink_stream),
(gst_play_base_bin_get_streaminfo):
* gst/playback/gstplaybasebin.h:
* gst/playback/gstplaybin.c: (gst_play_bin_get_type),
(gst_play_bin_class_init), (gst_play_bin_init),
(gst_play_bin_dispose), (gst_play_bin_set_property),
(gst_play_bin_get_property), (gen_video_element),
(gen_audio_element), (setup_sinks), (gst_play_bin_change_state),
(gst_play_bin_get_event_masks), (gst_play_bin_send_event),
(gst_play_bin_get_formats), (gst_play_bin_convert),
(gst_play_bin_get_query_types), (gst_play_bin_query),
(plugin_init):
* 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), (gst_stream_info_set_property),
(gst_stream_info_get_property):
* gst/playback/gststreaminfo.h:
* gst/playback/test.c: (gen_video_element), (gen_audio_element),
(main):
* gst/playback/test2.c: (main):
* gst/playback/test3.c: (update_scale), (main):
More playbin fixes. Added README. Do better element filtering.
Added base class to preroll media. Added test apps.
This commit is contained in:
Wim Taymans 2004-07-07 16:53:55 +00:00
parent 1450fccf30
commit d23e3dea3f
12 changed files with 1399 additions and 399 deletions

View file

@ -1,3 +1,48 @@
2004-07-07 Wim Taymans <wim@fluendo.com>
* gst/playback/Makefile.am:
* gst/playback/README:
* gst/playback/gstdecodebin.c: (gst_decode_bin_get_type),
(gst_decode_bin_class_init), (gst_decode_bin_factory_filter),
(compare_ranks), (print_feature), (gst_decode_bin_init),
(gst_decode_bin_dispose), (find_compatibles), (close_pad_link),
(try_to_link_1), (new_pad), (close_link), (type_found),
(gst_decode_bin_set_property), (gst_decode_bin_get_property),
(plugin_init):
* gst/playback/gstplaybasebin.c: (gst_play_base_bin_get_type),
(gst_play_base_bin_class_init), (gst_play_base_bin_init),
(gst_play_base_bin_dispose), (rebuild_pipeline), (queue_overrun),
(gen_preroll_element), (no_more_pads), (new_stream),
(setup_source), (gst_play_base_bin_set_property),
(gst_play_base_bin_get_property), (gst_play_base_bin_change_state),
(gst_play_base_bin_add_element),
(gst_play_base_bin_remove_element),
(gst_play_base_bin_mute_stream), (gst_play_base_bin_link_stream),
(gst_play_base_bin_unlink_stream),
(gst_play_base_bin_get_streaminfo):
* gst/playback/gstplaybasebin.h:
* gst/playback/gstplaybin.c: (gst_play_bin_get_type),
(gst_play_bin_class_init), (gst_play_bin_init),
(gst_play_bin_dispose), (gst_play_bin_set_property),
(gst_play_bin_get_property), (gen_video_element),
(gen_audio_element), (setup_sinks), (gst_play_bin_change_state),
(gst_play_bin_get_event_masks), (gst_play_bin_send_event),
(gst_play_bin_get_formats), (gst_play_bin_convert),
(gst_play_bin_get_query_types), (gst_play_bin_query),
(plugin_init):
* 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), (gst_stream_info_set_property),
(gst_stream_info_get_property):
* gst/playback/gststreaminfo.h:
* gst/playback/test.c: (gen_video_element), (gen_audio_element),
(main):
* gst/playback/test2.c: (main):
* gst/playback/test3.c: (update_scale), (main):
More playbin fixes. Added README. Do better element filtering.
Added base class to preroll media. Added test apps.
2004-07-07 Thomas Vander Stichele <thomas (at) apestaart (dot) org> 2004-07-07 Thomas Vander Stichele <thomas (at) apestaart (dot) org>
* ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_flush_decoder): * ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_flush_decoder):

View file

@ -2,7 +2,7 @@ plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
plugin_LTLIBRARIES = libgstplaybin.la libgstdecodebin.la plugin_LTLIBRARIES = libgstplaybin.la libgstdecodebin.la
libgstplaybin_la_SOURCES = gstplaybin.c libgstplaybin_la_SOURCES = gstplaybin.c gstplaybasebin.c gststreaminfo.c
libgstplaybin_la_CFLAGS = $(GST_CFLAGS) libgstplaybin_la_CFLAGS = $(GST_CFLAGS)
libgstplaybin_la_LIBADD = libgstplaybin_la_LIBADD =
libgstplaybin_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstplaybin_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
@ -12,10 +12,16 @@ libgstdecodebin_la_CFLAGS = $(GST_CFLAGS)
libgstdecodebin_la_LIBADD = libgstdecodebin_la_LIBADD =
libgstdecodebin_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstdecodebin_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
noinst_PROGRAMS = test decodetest noinst_PROGRAMS = test decodetest test2 test3
test_LDADD = $(GST_LIBS) test_LDADD = $(GST_LIBS)
test_CFLAGS = $(GST_CFLAGS) test_CFLAGS = $(GST_CFLAGS)
test2_LDADD = $(GST_LIBS)
test2_CFLAGS = $(GST_CFLAGS)
test3_LDADD = $(GST_LIBS)
test3_CFLAGS = $(GST_CFLAGS)
decodetest_LDADD = $(GST_LIBS) decodetest_LDADD = $(GST_LIBS)
decodetest_CFLAGS = $(GST_CFLAGS) decodetest_CFLAGS = $(GST_CFLAGS)

48
gst/playback/README Normal file
View file

@ -0,0 +1,48 @@
decoderbin:
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.
TODO
- reuse of decoderbin, cleanup in READY state
- debugging
- threading after demuxing?
- better factory selection, based on Demuxer/Decoder types and ranks.
- error handling
baseplaybin:
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.
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
- debugging
- 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.
- error handling
playbin:
Extends baseplaybin, sets up default audiosink and videosink for first audio/video
stream detected. implements seeking and querying on the configured sinks.
TODO
- reuse, refcounting, cleanup in READY state
- debugging
- error handling

View file

@ -56,6 +56,7 @@ struct _GstDecodeBin
GstElement *typefind; GstElement *typefind;
gboolean threaded; gboolean threaded;
gboolean dynamic;
GList *factories; GList *factories;
gint numpads; gint numpads;
@ -64,6 +65,8 @@ struct _GstDecodeBin
struct _GstDecodeBinClass struct _GstDecodeBinClass
{ {
GstBinClass parent_class; GstBinClass parent_class;
void (*new_stream) (GstElement * element, GstPad * pad, gboolean last);
}; };
/* props */ /* props */
@ -76,6 +79,7 @@ enum
/* signals */ /* signals */
enum enum
{ {
SIGNAL_NEW_STREAM,
LAST_SIGNAL LAST_SIGNAL
}; };
@ -89,19 +93,6 @@ static void gst_decode_bin_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * spec); GValue * value, GParamSpec * spec);
static GstElementStateReturn gst_decode_bin_change_state (GstElement * element); static GstElementStateReturn gst_decode_bin_change_state (GstElement * element);
static const GstEventMask *gst_decode_bin_get_event_masks (GstElement *
element);
static gboolean gst_decode_bin_send_event (GstElement * element,
GstEvent * event);
static const GstFormat *gst_decode_bin_get_formats (GstElement * element);
static gboolean gst_decode_bin_convert (GstElement * element,
GstFormat src_format, gint64 src_value,
GstFormat * dest_format, gint64 * dest_value);
static const GstQueryType *gst_decode_bin_get_query_types (GstElement *
element);
static gboolean gst_decode_bin_query (GstElement * element, GstQueryType type,
GstFormat * format, gint64 * value);
static void type_found (GstElement * typefind, guint probability, static void type_found (GstElement * typefind, guint probability,
GstCaps * caps, GstDecodeBin * decode_bin); GstCaps * caps, GstDecodeBin * decode_bin);
static GstElement *try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, static GstElement *try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad,
@ -111,8 +102,7 @@ static void close_pad_link (GstElement * element, GstPad * pad,
GstCaps * caps, GstDecodeBin * decode_bin); GstCaps * caps, GstDecodeBin * decode_bin);
static GstElementClass *parent_class; static GstElementClass *parent_class;
static guint gst_decode_bin_signals[LAST_SIGNAL] = { 0 };
//static guint gst_decode_bin_signals[LAST_SIGNAL] = { 0 };
static GstElementDetails gst_decode_bin_details = { static GstElementDetails gst_decode_bin_details = {
"Decoder Bin", "Decoder Bin",
@ -169,6 +159,12 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass)
g_param_spec_boolean ("threaded", "Threaded", "Use threads", g_param_spec_boolean ("threaded", "Threaded", "Use threads",
FALSE, G_PARAM_READWRITE)); FALSE, G_PARAM_READWRITE));
gst_decode_bin_signals[SIGNAL_NEW_STREAM] =
g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstDecodeBinClass, new_stream), NULL, NULL,
gst_marshal_VOID__OBJECT_POINTER, G_TYPE_NONE, 2, G_TYPE_OBJECT,
G_TYPE_BOOLEAN);
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_element_class_add_pad_template (gstelement_klass,
@ -178,15 +174,6 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass)
gstelement_klass->change_state = gstelement_klass->change_state =
GST_DEBUG_FUNCPTR (gst_decode_bin_change_state); GST_DEBUG_FUNCPTR (gst_decode_bin_change_state);
gstelement_klass->get_event_masks =
GST_DEBUG_FUNCPTR (gst_decode_bin_get_event_masks);
gstelement_klass->send_event = GST_DEBUG_FUNCPTR (gst_decode_bin_send_event);
gstelement_klass->get_formats =
GST_DEBUG_FUNCPTR (gst_decode_bin_get_formats);
gstelement_klass->convert = GST_DEBUG_FUNCPTR (gst_decode_bin_convert);
gstelement_klass->get_query_types =
GST_DEBUG_FUNCPTR (gst_decode_bin_get_query_types);
gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_decode_bin_query);
} }
@ -195,12 +182,18 @@ gst_decode_bin_factory_filter (GstPluginFeature * feature,
GstDecodeBin * decode_bin) GstDecodeBin * decode_bin)
{ {
guint rank; guint rank;
const gchar *klass;
if (!GST_IS_ELEMENT_FACTORY (feature)) if (!GST_IS_ELEMENT_FACTORY (feature))
return FALSE; return FALSE;
klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature));
if (strstr (klass, "Demux") == NULL && strstr (klass, "Decoder") == NULL) {
return FALSE;
}
rank = gst_plugin_feature_get_rank (feature); rank = gst_plugin_feature_get_rank (feature);
if (rank < GST_RANK_SECONDARY) if (rank < GST_RANK_MARGINAL)
return FALSE; return FALSE;
return TRUE; return TRUE;
@ -212,6 +205,12 @@ compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
return gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1); return gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
} }
static void
print_feature (GstPluginFeature * feature)
{
g_print ("%s\n", gst_plugin_feature_get_name (feature));
}
static void static void
gst_decode_bin_init (GstDecodeBin * decode_bin) gst_decode_bin_init (GstDecodeBin * decode_bin)
{ {
@ -222,6 +221,7 @@ gst_decode_bin_init (GstDecodeBin * decode_bin)
FALSE, decode_bin); FALSE, decode_bin);
decode_bin->factories = g_list_sort (factories, (GCompareFunc) compare_ranks); decode_bin->factories = g_list_sort (factories, (GCompareFunc) compare_ranks);
g_list_foreach (decode_bin->factories, (GFunc) print_feature, NULL);
decode_bin->typefind = gst_element_factory_make ("typefind", "typefind"); decode_bin->typefind = gst_element_factory_make ("typefind", "typefind");
if (!decode_bin->typefind) { if (!decode_bin->typefind) {
@ -274,6 +274,7 @@ find_compatibles (GstDecodeBin * decode_bin, const GstCaps * caps)
if (!gst_caps_is_empty (intersect)) { if (!gst_caps_is_empty (intersect)) {
to_try = g_list_append (to_try, factory); to_try = g_list_append (to_try, factory);
} }
gst_caps_free (intersect);
} }
} }
} }
@ -295,11 +296,19 @@ close_pad_link (GstElement * element, GstPad * pad, GstCaps * caps,
if (g_str_has_prefix (mimetype, "video/x-raw") || if (g_str_has_prefix (mimetype, "video/x-raw") ||
g_str_has_prefix (mimetype, "audio/x-raw")) { g_str_has_prefix (mimetype, "audio/x-raw")) {
gchar *padname; gchar *padname;
GstPad *ghost;
padname = g_strdup_printf ("src%d", decode_bin->numpads); padname = g_strdup_printf ("src%d", decode_bin->numpads);
decode_bin->numpads++; decode_bin->numpads++;
gst_element_add_ghost_pad (GST_ELEMENT (decode_bin), pad, padname); gst_element_add_ghost_pad (GST_ELEMENT (decode_bin), pad, padname);
ghost = gst_element_get_pad (GST_ELEMENT (decode_bin), padname);
g_signal_emit (G_OBJECT (decode_bin),
gst_decode_bin_signals[SIGNAL_NEW_STREAM], 0,
ghost, !decode_bin->dynamic);
g_free (padname); g_free (padname);
return; return;
} }
@ -327,7 +336,8 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
GstElement *element; GstElement *element;
gboolean ret; gboolean ret;
//g_print ("trying to link %s\n", gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory))); g_print ("trying to link %s\n",
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
element = gst_element_factory_create (factory, NULL); element = gst_element_factory_create (factory, NULL);
if (element == NULL) if (element == NULL)
@ -344,7 +354,7 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
klass = gst_element_factory_get_klass (factory); klass = gst_element_factory_get_klass (factory);
if (decode_bin->threaded) { if (decode_bin->threaded) {
if (strstr (klass, "Demux") != NULL) { if (strstr (klass, "Demux") != NULL) {
//g_print ("thread after %s\n", gst_element_get_name (element)); /* FIXME, do something with threads here */
} }
} }
@ -369,6 +379,7 @@ close_link (GstElement * element, GstDecodeBin * decode_bin)
{ {
GList *pads; GList *pads;
gboolean dynamic = FALSE; gboolean dynamic = FALSE;
GList *to_connect = NULL;
for (pads = gst_element_get_pad_template_list (element); pads; for (pads = gst_element_get_pad_template_list (element); pads;
pads = g_list_next (pads)) { pads = g_list_next (pads)) {
@ -384,7 +395,7 @@ close_link (GstElement * element, GstDecodeBin * decode_bin)
gst_element_get_pad (element, gst_element_get_pad (element,
GST_PAD_TEMPLATE_NAME_TEMPLATE (templ)); GST_PAD_TEMPLATE_NAME_TEMPLATE (templ));
if (pad) { if (pad) {
close_pad_link (element, pad, gst_pad_get_caps (pad), decode_bin); to_connect = g_list_prepend (to_connect, pad);
} }
break; break;
} }
@ -394,7 +405,7 @@ close_link (GstElement * element, GstDecodeBin * decode_bin)
gst_element_get_pad (element, gst_element_get_pad (element,
GST_PAD_TEMPLATE_NAME_TEMPLATE (templ)); GST_PAD_TEMPLATE_NAME_TEMPLATE (templ));
if (pad) { if (pad) {
close_pad_link (element, pad, gst_pad_get_caps (pad), decode_bin); to_connect = g_list_prepend (to_connect, pad);
} else { } else {
dynamic = TRUE; dynamic = TRUE;
} }
@ -407,21 +418,29 @@ close_link (GstElement * element, GstDecodeBin * decode_bin)
if (dynamic) { if (dynamic) {
g_signal_connect (G_OBJECT (element), "new_pad", g_signal_connect (G_OBJECT (element), "new_pad",
G_CALLBACK (new_pad), decode_bin); G_CALLBACK (new_pad), decode_bin);
decode_bin->dynamic = TRUE;
} }
for (pads = to_connect; pads; pads = g_list_next (pads)) {
GstPad *pad = GST_PAD (pads->data);
close_pad_link (element, pad, gst_pad_get_caps (pad), decode_bin);
}
g_list_free (to_connect);
} }
static void static void
type_found (GstElement * typefind, guint probability, GstCaps * caps, type_found (GstElement * typefind, guint probability, GstCaps * caps,
GstDecodeBin * decode_bin) GstDecodeBin * decode_bin)
{ {
gchar *capsstr; decode_bin->dynamic = FALSE;
capsstr = gst_caps_to_string (caps);
//g_print ("found type %s\n", capsstr);
g_free (capsstr);
close_pad_link (typefind, gst_element_get_pad (typefind, "src"), caps, close_pad_link (typefind, gst_element_get_pad (typefind, "src"), caps,
decode_bin); decode_bin);
if (decode_bin->dynamic == FALSE) {
gst_element_no_more_pads (GST_ELEMENT (decode_bin));
}
} }
static void static void
@ -497,64 +516,6 @@ gst_decode_bin_change_state (GstElement * element)
return ret; return ret;
} }
static const GstEventMask *
gst_decode_bin_get_event_masks (GstElement * element)
{
return NULL;
}
static gboolean
gst_decode_bin_send_event (GstElement * element, GstEvent * event)
{
gboolean res = FALSE;
return res;
}
static const GstFormat *
gst_decode_bin_get_formats (GstElement * element)
{
static GstFormat formats[] = {
GST_FORMAT_TIME,
GST_FORMAT_BYTES,
GST_FORMAT_DEFAULT,
0,
};
return formats;
}
static gboolean
gst_decode_bin_convert (GstElement * element,
GstFormat src_format, gint64 src_value,
GstFormat * dest_format, gint64 * dest_value)
{
return FALSE;
}
static const GstQueryType *
gst_decode_bin_get_query_types (GstElement * element)
{
static const GstQueryType query_types[] = {
GST_QUERY_TOTAL,
GST_QUERY_POSITION,
GST_QUERY_START,
GST_QUERY_SEGMENT_END,
0
};
return query_types;
}
static gboolean
gst_decode_bin_query (GstElement * element, GstQueryType type,
GstFormat * format, gint64 * value)
{
gboolean res = FALSE;
return res;
}
static gboolean static gboolean
plugin_init (GstPlugin * plugin) plugin_init (GstPlugin * plugin)
{ {

View file

@ -0,0 +1,539 @@
/* 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 "gstplaybasebin.h"
GST_DEBUG_CATEGORY_STATIC (gst_play_base_bin_debug);
#define GST_CAT_DEFAULT gst_play_base_bin_debug
/* props */
enum
{
ARG_0,
ARG_URI,
ARG_THREADED,
ARG_NSTREAMS,
ARG_STREAMINFO,
};
/* signals */
enum
{
MUTE_STREAM_SIGNAL,
LINK_STREAM_SIGNAL,
UNLINK_STREAM_SIGNAL,
LAST_SIGNAL
};
static void gst_play_base_bin_class_init (GstPlayBaseBinClass * klass);
static void gst_play_base_bin_init (GstPlayBaseBin * play_base_bin);
static void gst_play_base_bin_dispose (GObject * object);
static void gst_play_base_bin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * spec);
static void gst_play_base_bin_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * spec);
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,
GstElement * element);
static GstElementClass *parent_class;
static guint gst_play_base_bin_signals[LAST_SIGNAL] = { 0 };
GType
gst_play_base_bin_get_type (void)
{
static GType gst_play_base_bin_type = 0;
if (!gst_play_base_bin_type) {
static const GTypeInfo gst_play_base_bin_info = {
sizeof (GstPlayBaseBinClass),
NULL,
NULL,
(GClassInitFunc) gst_play_base_bin_class_init,
NULL,
NULL,
sizeof (GstPlayBaseBin),
0,
(GInstanceInitFunc) gst_play_base_bin_init,
NULL
};
gst_play_base_bin_type = g_type_register_static (GST_TYPE_BIN,
"GstPlayBaseBin", &gst_play_base_bin_info, 0);
}
return gst_play_base_bin_type;
}
static void
gst_play_base_bin_class_init (GstPlayBaseBinClass * klass)
{
GObjectClass *gobject_klass;
GstElementClass *gstelement_klass;
GstBinClass *gstbin_klass;
gobject_klass = (GObjectClass *) klass;
gstelement_klass = (GstElementClass *) klass;
gstbin_klass = (GstBinClass *) klass;
parent_class = g_type_class_ref (gst_bin_get_type ());
gobject_klass->set_property = gst_play_base_bin_set_property;
gobject_klass->get_property = gst_play_base_bin_get_property;
g_object_class_install_property (gobject_klass, ARG_URI,
g_param_spec_string ("uri", "URI", "URI of the media to play",
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_STREAMINFO,
g_param_spec_pointer ("stream-info", "Stream info", "List of streaminfo",
G_PARAM_READABLE));
gst_play_base_bin_signals[MUTE_STREAM_SIGNAL] =
g_signal_new ("mute-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstPlayBaseBinClass, mute_stream),
NULL, NULL, gst_marshal_VOID__OBJECT_POINTER, G_TYPE_NONE, 2,
G_TYPE_OBJECT, G_TYPE_BOOLEAN);
gst_play_base_bin_signals[LINK_STREAM_SIGNAL] =
g_signal_new ("link-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstPlayBaseBinClass, link_stream),
NULL, NULL, gst_marshal_VOID__OBJECT_POINTER, G_TYPE_NONE, 2,
G_TYPE_OBJECT, GST_TYPE_PAD);
gst_play_base_bin_signals[UNLINK_STREAM_SIGNAL] =
g_signal_new ("unlink-stream", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstPlayBaseBinClass, unlink_stream),
NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 1, G_TYPE_OBJECT);
gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_base_bin_dispose);
gstelement_klass->change_state =
GST_DEBUG_FUNCPTR (gst_play_base_bin_change_state);
gstbin_klass->add_element = GST_DEBUG_FUNCPTR (gst_play_base_bin_add_element);
gstbin_klass->remove_element =
GST_DEBUG_FUNCPTR (gst_play_base_bin_remove_element);
klass->mute_stream = gst_play_base_bin_mute_stream;
klass->link_stream = gst_play_base_bin_link_stream;
klass->unlink_stream = gst_play_base_bin_unlink_stream;
}
static void
gst_play_base_bin_init (GstPlayBaseBin * play_base_bin)
{
play_base_bin->uri = NULL;
play_base_bin->threaded = FALSE;
play_base_bin->preroll_lock = g_mutex_new ();
play_base_bin->preroll_cond = g_cond_new ();
GST_FLAG_SET (play_base_bin, GST_BIN_SELF_SCHEDULABLE);
}
static void
gst_play_base_bin_dispose (GObject * object)
{
GstPlayBaseBin *play_base_bin;
play_base_bin = GST_PLAY_BASE_BIN (object);
g_free (play_base_bin->uri);
if (G_OBJECT_CLASS (parent_class)->dispose) {
G_OBJECT_CLASS (parent_class)->dispose (object);
}
}
static void
rebuild_pipeline (GstPlayBaseBin * play_base_bin)
{
GstElementState oldstate;
if (play_base_bin->thread == NULL)
return;
oldstate = gst_element_get_state (play_base_bin->thread);
gst_element_set_state (play_base_bin->thread, GST_STATE_NULL);
/* remove old elements */
/* set to old state again */
gst_element_set_state (play_base_bin->thread, oldstate);
}
static void
queue_overrun (GstElement * element, GstPlayBaseBin * play_base_bin)
{
g_mutex_lock (play_base_bin->preroll_lock);
g_cond_signal (play_base_bin->preroll_cond);
g_mutex_unlock (play_base_bin->preroll_lock);
//g_signal_handlers_disconnect_by_func(G_OBJECT (element),
// G_CALLBACK (queue_overrun), play_base_bin);
}
static GstElement *
gen_preroll_element (GstPlayBaseBin * play_base_bin, GstPad * pad)
{
GstElement *element;
gchar *name;
name = g_strdup_printf ("preroll_%s", gst_pad_get_name (pad));
element = gst_element_factory_make ("queue", name);
g_signal_connect (G_OBJECT (element), "overrun",
G_CALLBACK (queue_overrun), play_base_bin);
g_free (name);
return element;
}
static void
no_more_pads (GstElement * element, GstPlayBaseBin * play_base_bin)
{
g_mutex_lock (play_base_bin->preroll_lock);
g_cond_signal (play_base_bin->preroll_cond);
g_mutex_unlock (play_base_bin->preroll_lock);
}
static void
new_stream (GstElement * element, GstPad * pad, gboolean last,
GstPlayBaseBin * play_base_bin)
{
GstStructure *structure;
const gchar *mimetype;
GstCaps *caps;
GstElement *new_element = NULL;
GstStreamInfo *info;
GstStreamType type;
GstPad *srcpad;
caps = gst_pad_get_caps (pad);
structure = gst_caps_get_structure (caps, 0);
mimetype = gst_structure_get_name (structure);
play_base_bin->nstreams++;
if (g_str_has_prefix (mimetype, "audio/")) {
type = GST_STREAM_TYPE_AUDIO;
} else if (g_str_has_prefix (mimetype, "video/")) {
type = GST_STREAM_TYPE_VIDEO;
} else {
type = GST_STREAM_TYPE_UNKNOWN;
}
if (last) {
srcpad = pad;
no_more_pads (NULL, play_base_bin);
} else {
new_element = gen_preroll_element (play_base_bin, pad);
srcpad = gst_element_get_pad (new_element, "src");
gst_bin_add (GST_BIN (play_base_bin->thread), new_element);
play_base_bin->threaded = TRUE;
gst_pad_link (pad, gst_element_get_pad (new_element, "sink"));
gst_element_sync_state_with_parent (new_element);
}
info = gst_stream_info_new (srcpad, type, NULL);
play_base_bin->streaminfo = g_list_append (play_base_bin->streaminfo, info);
}
static gboolean
setup_source (GstPlayBaseBin * play_base_bin)
{
if (play_base_bin->source) {
gst_bin_remove (GST_BIN (play_base_bin->thread), play_base_bin->source);
gst_object_unref (GST_OBJECT (play_base_bin->source));
}
play_base_bin->source =
gst_element_make_from_uri (GST_URI_SRC, play_base_bin->uri, "source");
if (!play_base_bin->source) {
g_warning ("don't know how to read %s", play_base_bin->uri);
return FALSE;
}
{
GstElement *decoder;
gboolean res;
gst_bin_add (GST_BIN (play_base_bin->thread), play_base_bin->source);
decoder = gst_element_factory_make ("decodebin", "decoder");
if (!decoder) {
g_warning ("can't find decoder element");
return FALSE;
}
gst_bin_add (GST_BIN (play_base_bin->thread), decoder);
res = gst_element_link_pads (play_base_bin->source, "src", decoder, "sink");
if (!res) {
g_warning ("can't link source to typefind element");
return FALSE;
}
g_signal_connect (G_OBJECT (decoder), "new_stream",
G_CALLBACK (new_stream), play_base_bin);
g_signal_connect (G_OBJECT (decoder), "no-more-pads",
G_CALLBACK (no_more_pads), play_base_bin);
g_mutex_lock (play_base_bin->preroll_lock);
gst_element_set_state (play_base_bin->thread, GST_STATE_PLAYING);
g_cond_wait (play_base_bin->preroll_cond, play_base_bin->preroll_lock);
g_mutex_unlock (play_base_bin->preroll_lock);
}
return TRUE;
}
static void
gst_play_base_bin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstPlayBaseBin *play_base_bin;
g_return_if_fail (GST_IS_PLAY_BASE_BIN (object));
play_base_bin = GST_PLAY_BASE_BIN (object);
switch (prop_id) {
case ARG_URI:
{
const gchar *uri = g_value_get_string (value);
if (uri == NULL) {
g_warning ("cannot set NULL uri");
return;
}
if (!play_base_bin->uri || !strcmp (play_base_bin->uri, uri)) {
g_free (play_base_bin->uri);
play_base_bin->uri = g_strdup (uri);
rebuild_pipeline (play_base_bin);
}
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_play_base_bin_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstPlayBaseBin *play_base_bin;
g_return_if_fail (GST_IS_PLAY_BASE_BIN (object));
play_base_bin = GST_PLAY_BASE_BIN (object);
switch (prop_id) {
case ARG_URI:
g_value_set_string (value, play_base_bin->uri);
break;
case ARG_NSTREAMS:
g_value_set_int (value, play_base_bin->nstreams);
break;
case ARG_STREAMINFO:
g_value_set_pointer (value, play_base_bin->streaminfo);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GstElementStateReturn
gst_play_base_bin_change_state (GstElement * element)
{
GstElementStateReturn ret = GST_STATE_SUCCESS;
GstPlayBaseBin *play_base_bin;
play_base_bin = GST_PLAY_BASE_BIN (element);
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_NULL_TO_READY:
{
GstScheduler *sched;
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_object_set_parent (GST_OBJECT (play_base_bin->thread),
GST_OBJECT (play_base_bin));
gst_element_set_state (play_base_bin->thread, GST_STATE_READY);
} 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;
}
break;
}
case GST_STATE_READY_TO_PAUSED:
{
if (!setup_source (play_base_bin)) {
GST_ELEMENT_ERROR (GST_ELEMENT (play_base_bin), LIBRARY, TOO_LAZY,
(NULL), ("cannot handle uri \"%s\"", play_base_bin->uri));
ret = GST_STATE_FAILURE;
} else {
ret = gst_element_set_state (play_base_bin->thread, GST_STATE_PAUSED);
}
break;
}
case GST_STATE_PAUSED_TO_PLAYING:
ret = gst_element_set_state (play_base_bin->thread, GST_STATE_PLAYING);
break;
case GST_STATE_PLAYING_TO_PAUSED:
ret = gst_element_set_state (play_base_bin->thread, GST_STATE_PAUSED);
break;
case GST_STATE_PAUSED_TO_READY:
ret = gst_element_set_state (play_base_bin->thread, GST_STATE_READY);
break;
case GST_STATE_READY_TO_NULL:
ret = gst_element_set_state (play_base_bin->thread, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (play_base_bin->thread));
break;
default:
g_assert_not_reached ();
break;
}
if (ret == GST_STATE_SUCCESS) {
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
}
return ret;
}
static void
gst_play_base_bin_add_element (GstBin * bin, GstElement * element)
{
GstPlayBaseBin *play_base_bin;
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);
g_free (name);
gst_bin_add (GST_BIN (thread), element);
element = thread;
}
gst_bin_add (GST_BIN (play_base_bin->thread), element);
sched = gst_element_get_scheduler (GST_ELEMENT (play_base_bin->thread));
clock = gst_scheduler_get_clock (sched);
gst_scheduler_set_clock (sched, clock);
gst_element_sync_state_with_parent (element);
} else {
g_warning ("adding elements is not allowed in NULL");
}
}
static void
gst_play_base_bin_remove_element (GstBin * bin, GstElement * element)
{
GstPlayBaseBin *play_base_bin;
play_base_bin = GST_PLAY_BASE_BIN (bin);
if (play_base_bin->thread) {
gst_bin_remove (GST_BIN (play_base_bin->thread), element);
} else {
g_warning ("removing elements is not allowed in NULL");
}
}
void
gst_play_base_bin_mute_stream (GstPlayBaseBin * play_base_bin,
GstStreamInfo * info, gboolean mute)
{
g_print ("mute\n");
}
void
gst_play_base_bin_link_stream (GstPlayBaseBin * play_base_bin,
GstStreamInfo * info, GstPad * pad)
{
if (info == NULL) {
GList *streams;
for (streams = play_base_bin->streaminfo; streams;
streams = g_list_next (streams)) {
GstStreamInfo *sinfo = (GstStreamInfo *) streams->data;
if (gst_pad_is_linked (sinfo->pad))
continue;
if (gst_pad_can_link (sinfo->pad, pad)) {
info = sinfo;
break;
}
}
}
if (info) {
if (!gst_pad_link (info->pad, pad)) {
g_print ("could not link\n");
}
} else {
g_print ("could not find pad to link\n");
}
}
void
gst_play_base_bin_unlink_stream (GstPlayBaseBin * play_base_bin,
GstStreamInfo * info)
{
g_print ("unlink\n");
}
const GList *
gst_play_base_bin_get_streaminfo (GstPlayBaseBin * play_base_bin)
{
return play_base_bin->streaminfo;
}

View file

@ -0,0 +1,90 @@
/* 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.
*/
#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))
typedef struct _GstPlayBaseBin GstPlayBaseBin;
typedef struct _GstPlayBaseBinClass GstPlayBaseBinClass;
struct _GstPlayBaseBin {
GstBin bin;
/* properties */
gboolean threaded;
GMutex *preroll_lock;
GCond *preroll_cond;
/* internal thread */
GstElement *thread;
gchar *uri;
GstElement *source;
gint nstreams;
GList *streaminfo;
/* list of usable factories */
GList *factories;
};
struct _GstPlayBaseBinClass {
GstBinClass parent_class;
void (*mute_stream) (GstPlayBaseBin *play_base_bin,
GstStreamInfo *info,
gboolean mute);
void (*link_stream) (GstPlayBaseBin *play_base_bin,
GstStreamInfo *info,
GstPad *pad);
void (*unlink_stream) (GstPlayBaseBin *play_base_bin,
GstStreamInfo *info);
};
GType gst_play_base_bin_get_type (void);
gint gst_play_base_bin_get_nstreams (GstPlayBaseBin *play_base_bin);
const GList* gst_play_base_bin_get_streaminfo (GstPlayBaseBin *play_base_bin);
gint gst_play_base_bin_get_nstreams_of_type (GstPlayBaseBin *play_base_bin,
GstStreamType type);
void gst_play_base_bin_mute_stream (GstPlayBaseBin *play_base_bin,
GstStreamInfo *info,
gboolean mute);
void gst_play_base_bin_link_stream (GstPlayBaseBin *play_base_bin,
GstStreamInfo *info,
GstPad *pad);
void gst_play_base_bin_unlink_stream (GstPlayBaseBin *play_base_bin,
GstStreamInfo *info);
G_END_DECLS
#endif /* __GST_PLAYBASEBIN_H__ */

View file

@ -24,6 +24,8 @@
#include <string.h> #include <string.h>
#include <gst/gst.h> #include <gst/gst.h>
#include "gstplaybasebin.h"
GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug); GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
#define GST_CAT_DEFAULT gst_play_bin_debug #define GST_CAT_DEFAULT gst_play_bin_debug
@ -38,38 +40,24 @@ typedef struct _GstPlayBinClass GstPlayBinClass;
struct _GstPlayBin struct _GstPlayBin
{ {
GstBin bin; GstPlayBaseBin parent;
GstElement *thread;
gboolean threaded;
/* properties */
gchar *uri;
GstElement *source;
GList *factories;
GstElement *audio_sink; GstElement *audio_sink;
GstElement *video_sink; GstElement *video_sink;
GstElement *vis_plugin; GstElement *visualisation;
gboolean audio_added; GList *seekables;
gboolean video_added;
GList *outpads;
}; };
struct _GstPlayBinClass struct _GstPlayBinClass
{ {
GstBinClass parent_class; GstPlayBaseBinClass parent_class;
}; };
/* props */ /* props */
enum enum
{ {
ARG_0, ARG_0,
ARG_URI,
ARG_THREADED,
ARG_AUDIO_SINK, ARG_AUDIO_SINK,
ARG_VIDEO_SINK, ARG_VIDEO_SINK,
ARG_VIS_PLUGIN, ARG_VIS_PLUGIN,
@ -101,9 +89,6 @@ static gboolean gst_play_bin_convert (GstElement * element,
static const GstQueryType *gst_play_bin_get_query_types (GstElement * element); static const GstQueryType *gst_play_bin_get_query_types (GstElement * element);
static gboolean gst_play_bin_query (GstElement * element, GstQueryType type, static gboolean gst_play_bin_query (GstElement * element, GstQueryType type,
GstFormat * format, gint64 * value); GstFormat * format, gint64 * value);
static GstClock *gst_play_bin_get_clock (GstElement * element);
static void gst_play_bin_add_element (GstBin * bin, GstElement * element);
static void gst_play_bin_remove_element (GstBin * bin, GstElement * element);
static GstElementClass *parent_class; static GstElementClass *parent_class;
@ -137,9 +122,8 @@ gst_play_bin_get_type (void)
NULL NULL
}; };
gst_play_bin_type = gst_play_bin_type = g_type_register_static (GST_TYPE_PLAY_BASE_BIN,
g_type_register_static (GST_TYPE_BIN, "GstPlayBin", &gst_play_bin_info, "GstPlayBin", &gst_play_bin_info, 0);
0);
} }
return gst_play_bin_type; return gst_play_bin_type;
@ -156,17 +140,11 @@ gst_play_bin_class_init (GstPlayBinClass * klass)
gstelement_klass = (GstElementClass *) klass; gstelement_klass = (GstElementClass *) klass;
gstbin_klass = (GstBinClass *) klass; gstbin_klass = (GstBinClass *) klass;
parent_class = g_type_class_ref (gst_bin_get_type ()); parent_class = g_type_class_ref (gst_play_base_bin_get_type ());
gobject_klass->set_property = gst_play_bin_set_property; gobject_klass->set_property = gst_play_bin_set_property;
gobject_klass->get_property = gst_play_bin_get_property; gobject_klass->get_property = gst_play_bin_get_property;
g_object_class_install_property (gobject_klass, ARG_URI,
g_param_spec_string ("uri", "URI", "URI of the media to play",
NULL, G_PARAM_READWRITE));
g_object_class_install_property (gobject_klass, ARG_THREADED,
g_param_spec_boolean ("threaded", "Threaded", "Use threads",
TRUE, G_PARAM_READWRITE));
g_object_class_install_property (gobject_klass, ARG_VIDEO_SINK, g_object_class_install_property (gobject_klass, ARG_VIDEO_SINK,
g_param_spec_object ("video-sink", "Video Sink", g_param_spec_object ("video-sink", "Video Sink",
"the video output element to use (NULL = default sink)", "the video output element to use (NULL = default sink)",
@ -194,23 +172,15 @@ gst_play_bin_class_init (GstPlayBinClass * klass)
gstelement_klass->get_query_types = gstelement_klass->get_query_types =
GST_DEBUG_FUNCPTR (gst_play_bin_get_query_types); GST_DEBUG_FUNCPTR (gst_play_bin_get_query_types);
gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query); gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
gstelement_klass->get_clock = GST_DEBUG_FUNCPTR (gst_play_bin_get_clock);
gstbin_klass->add_element = GST_DEBUG_FUNCPTR (gst_play_bin_add_element);
gstbin_klass->remove_element =
GST_DEBUG_FUNCPTR (gst_play_bin_remove_element);
} }
static void static void
gst_play_bin_init (GstPlayBin * play_bin) gst_play_bin_init (GstPlayBin * play_bin)
{ {
play_bin->uri = NULL;
play_bin->video_sink = NULL; play_bin->video_sink = NULL;
play_bin->audio_sink = NULL; play_bin->audio_sink = NULL;
play_bin->vis_plugin = NULL; play_bin->visualisation = NULL;
play_bin->audio_added = FALSE; play_bin->seekables = NULL;
play_bin->video_added = FALSE;
play_bin->threaded = TRUE;
GST_FLAG_SET (play_bin, GST_BIN_SELF_SCHEDULABLE); GST_FLAG_SET (play_bin, GST_BIN_SELF_SCHEDULABLE);
} }
@ -221,181 +191,12 @@ gst_play_bin_dispose (GObject * object)
GstPlayBin *play_bin; GstPlayBin *play_bin;
play_bin = GST_PLAY_BIN (object); play_bin = GST_PLAY_BIN (object);
g_free (play_bin->uri);
if (G_OBJECT_CLASS (parent_class)->dispose) { if (G_OBJECT_CLASS (parent_class)->dispose) {
G_OBJECT_CLASS (parent_class)->dispose (object); G_OBJECT_CLASS (parent_class)->dispose (object);
} }
} }
static void
rebuild_pipeline (GstPlayBin * play_bin)
{
GstElementState oldstate;
if (play_bin->thread == NULL)
return;
oldstate = gst_element_get_state (play_bin->thread);
gst_element_set_state (play_bin->thread, GST_STATE_NULL);
/* remove old elements */
/* set to old state again */
gst_element_set_state (play_bin->thread, oldstate);
}
static GstElement *
get_audio_element (GstPlayBin * play_bin)
{
GstElement *result;
GstElement *queue;
GstElement *conv;
GstElement *sink;
GstPad *sinkpad;
conv = gst_element_factory_make ("audioconvert", "a_conv");
if (play_bin->threaded) {
result = gst_thread_new ("audio_thread");
queue = gst_element_factory_make ("queue", "a_queue");
gst_bin_add (GST_BIN (result), queue);
gst_bin_add (GST_BIN (result), conv);
gst_element_link_pads (queue, "src", conv, "sink");
sinkpad = gst_element_get_pad (queue, "sink");
} else {
result = gst_bin_new ("audio_bin");
gst_bin_add (GST_BIN (result), conv);
sinkpad = gst_element_get_pad (conv, "sink");
}
sink = gst_element_factory_make ("osssink", "a_sink");
gst_bin_add (GST_BIN (result), sink);
gst_element_link_pads (conv, "src", sink, "sink");
gst_element_add_ghost_pad (result, sinkpad, "sink");
return result;
}
static GstElement *
get_video_element (GstPlayBin * play_bin)
{
GstElement *result;
GstElement *queue;
GstElement *conv;
GstElement *sink;
GstPad *sinkpad;
conv = gst_element_factory_make ("ffmpegcolorspace", "v_conv");
if (play_bin->threaded) {
result = gst_thread_new ("video_thread");
queue = gst_element_factory_make ("queue", "v_queue");
gst_bin_add (GST_BIN (result), queue);
gst_bin_add (GST_BIN (result), conv);
gst_element_link_pads (queue, "src", conv, "sink");
sinkpad = gst_element_get_pad (queue, "sink");
} else {
result = gst_bin_new ("video_bin");
gst_bin_add (GST_BIN (result), conv);
sinkpad = gst_element_get_pad (conv, "sink");
}
sink = gst_element_factory_make ("ximagesink", "v_sink");
gst_bin_add (GST_BIN (result), sink);
gst_element_link_pads (conv, "src", sink, "sink");
gst_element_add_ghost_pad (result, sinkpad, "sink");
return result;
}
static void
new_pad (GstElement * element, GstPad * pad, GstPlayBin * play_bin)
{
GstStructure *structure;
const gchar *mimetype;
GstCaps *caps;
GstClock *clock;
GstElement *new_element = NULL;
caps = gst_pad_get_caps (pad);
structure = gst_caps_get_structure (caps, 0);
mimetype = gst_structure_get_name (structure);
if (g_str_has_prefix (mimetype, "audio/")) {
if (!play_bin->audio_added) {
new_element = get_audio_element (play_bin);
play_bin->audio_added = TRUE;
}
} else if (g_str_has_prefix (mimetype, "video/")) {
if (!play_bin->video_added) {
new_element = get_video_element (play_bin);
play_bin->video_added = TRUE;
}
} else {
}
if (new_element) {
GstScheduler *sched;
gst_bin_add (GST_BIN (play_bin->thread), new_element);
gst_pad_link (pad, gst_element_get_pad (new_element, "sink"));
sched = gst_element_get_scheduler (GST_ELEMENT (play_bin->thread));
gst_bin_auto_clock (GST_BIN (play_bin->thread));
clock = gst_bin_get_clock (GST_BIN (play_bin->thread));
gst_scheduler_set_clock (sched, clock);
gst_element_sync_state_with_parent (new_element);
}
}
static gboolean
setup_source (GstPlayBin * play_bin)
{
if (play_bin->source) {
gst_bin_remove (GST_BIN (play_bin->thread), play_bin->source);
gst_object_unref (GST_OBJECT (play_bin->source));
}
play_bin->source =
gst_element_make_from_uri (GST_URI_SRC, play_bin->uri, "source");
if (!play_bin->source) {
g_warning ("don't know how to read %s", play_bin->uri);
return FALSE;
}
{
GstElement *decoder;
gboolean res;
gst_bin_add (GST_BIN (play_bin->thread), play_bin->source);
decoder = gst_element_factory_make ("decodebin", "decoder");
if (!decoder) {
g_warning ("can't find decoder element");
return FALSE;
}
gst_bin_add (GST_BIN (play_bin->thread), decoder);
res = gst_element_link_pads (play_bin->source, "src", decoder, "sink");
if (!res) {
g_warning ("can't link source to typefind element");
return FALSE;
}
g_signal_connect (G_OBJECT (decoder), "new_pad",
G_CALLBACK (new_pad), play_bin);
}
return TRUE;
}
static void static void
gst_play_bin_set_property (GObject * object, guint prop_id, gst_play_bin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec) const GValue * value, GParamSpec * pspec)
@ -407,25 +208,6 @@ gst_play_bin_set_property (GObject * object, guint prop_id,
play_bin = GST_PLAY_BIN (object); play_bin = GST_PLAY_BIN (object);
switch (prop_id) { switch (prop_id) {
case ARG_URI:
{
const gchar *uri = g_value_get_string (value);
if (uri == NULL) {
g_warning ("cannot set NULL uri");
return;
}
if (!play_bin->uri || !strcmp (play_bin->uri, uri)) {
g_free (play_bin->uri);
play_bin->uri = g_strdup (uri);
rebuild_pipeline (play_bin);
}
break;
}
case ARG_THREADED:
play_bin->threaded = g_value_get_boolean (value);
break;
case ARG_VIDEO_SINK: case ARG_VIDEO_SINK:
break; break;
case ARG_AUDIO_SINK: case ARG_AUDIO_SINK:
@ -449,12 +231,6 @@ gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
play_bin = GST_PLAY_BIN (object); play_bin = GST_PLAY_BIN (object);
switch (prop_id) { switch (prop_id) {
case ARG_URI:
g_value_set_string (value, play_bin->uri);
break;
case ARG_THREADED:
g_value_set_boolean (value, play_bin->threaded);
break;
case ARG_VIDEO_SINK: case ARG_VIDEO_SINK:
break; break;
case ARG_AUDIO_SINK: case ARG_AUDIO_SINK:
@ -467,89 +243,137 @@ gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
} }
} }
static GstElement *
gen_video_element (GstPlayBin * play_bin)
{
GstElement *element;
GstElement *conv;
GstElement *sink;
element = gst_bin_new ("vbin");
conv = gst_element_factory_make ("ffmpegcolorspace", "conv");
if (play_bin->video_sink) {
sink = play_bin->video_sink;
} else {
sink = gst_element_factory_make ("ximagesink", "sink");
}
play_bin->seekables = g_list_prepend (play_bin->seekables, sink);
gst_bin_add (GST_BIN (element), conv);
gst_bin_add (GST_BIN (element), sink);
gst_element_link_pads (conv, "src", sink, "sink");
gst_element_add_ghost_pad (element, gst_element_get_pad (conv, "sink"),
"sink");
return element;
}
static GstElement *
gen_audio_element (GstPlayBin * play_bin)
{
GstElement *element;
GstElement *conv;
GstElement *sink;
element = gst_bin_new ("abin");
conv = gst_element_factory_make ("audioconvert", "conv");
if (play_bin->audio_sink) {
sink = play_bin->audio_sink;
} else {
sink = gst_element_factory_make ("osssink", "sink");
}
play_bin->seekables = g_list_prepend (play_bin->seekables, sink);
gst_bin_add (GST_BIN (element), conv);
gst_bin_add (GST_BIN (element), sink);
gst_element_link_pads (conv, "src", sink, "sink");
gst_element_add_ghost_pad (element,
gst_element_get_pad (conv, "sink"), "sink");
return element;
}
static void
setup_sinks (GstPlayBin * play_bin)
{
GList *streaminfo;
GList *s;
/* get info about the stream */
g_object_get (G_OBJECT (play_bin), "stream-info", &streaminfo, NULL);
for (s = streaminfo; s; s = g_list_next (s)) {
GObject *obj = G_OBJECT (s->data);
int type;
GstPad *srcpad, *sinkpad;
GstElement *sink;
gboolean res;
g_object_get (obj, "type", &type, NULL);
g_object_get (obj, "pad", &srcpad, NULL);
if (type == 1) {
sink = gen_audio_element (play_bin);
} else if (type == 2) {
sink = gen_video_element (play_bin);
} else {
g_warning ("unknown stream found");
continue;
}
gst_bin_add (GST_BIN (play_bin), sink);
sinkpad = gst_element_get_pad (sink, "sink");
res = gst_pad_link (srcpad, sinkpad);
if (!res) {
gchar *capsstr;
capsstr = gst_caps_to_string (gst_pad_get_caps (srcpad));
g_warning ("could not link %s", capsstr);
g_free (capsstr);
}
}
}
static GstElementStateReturn static GstElementStateReturn
gst_play_bin_change_state (GstElement * element) gst_play_bin_change_state (GstElement * element)
{ {
GstElementStateReturn ret = GST_STATE_SUCCESS; GstElementStateReturn ret;
GstPlayBin *play_bin; GstPlayBin *play_bin;
int transition;
play_bin = GST_PLAY_BIN (element); play_bin = GST_PLAY_BIN (element);
switch (GST_STATE_TRANSITION (element)) { transition = GST_STATE_TRANSITION (element);
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
switch (transition) {
case GST_STATE_NULL_TO_READY: case GST_STATE_NULL_TO_READY:
{
GstScheduler *sched;
play_bin->thread = gst_thread_new ("internal_thread");
sched = gst_scheduler_factory_make ("opt", play_bin->thread);
if (sched) {
gst_element_set_scheduler (play_bin->thread, sched);
gst_object_set_parent (GST_OBJECT (play_bin->thread),
GST_OBJECT (play_bin));
gst_element_set_state (play_bin->thread, GST_STATE_READY);
} else {
g_warning ("could not get 'opt' scheduler");
gst_object_unref (GST_OBJECT (play_bin->thread));
play_bin->thread = NULL;
ret = GST_STATE_FAILURE;
}
break; break;
}
case GST_STATE_READY_TO_PAUSED: case GST_STATE_READY_TO_PAUSED:
{ setup_sinks (play_bin);
if (!setup_source (play_bin)) {
GST_ELEMENT_ERROR (GST_ELEMENT (play_bin), LIBRARY, TOO_LAZY, (NULL),
("cannot handle uri \"%s\"", play_bin->uri));
ret = GST_STATE_FAILURE;
} else {
ret = gst_element_set_state (play_bin->thread, GST_STATE_PAUSED);
}
break; break;
}
case GST_STATE_PAUSED_TO_PLAYING: case GST_STATE_PAUSED_TO_PLAYING:
ret = gst_element_set_state (play_bin->thread, GST_STATE_PLAYING);
break; break;
case GST_STATE_PLAYING_TO_PAUSED: case GST_STATE_PLAYING_TO_PAUSED:
ret = gst_element_set_state (play_bin->thread, GST_STATE_PAUSED);
break; break;
case GST_STATE_PAUSED_TO_READY: case GST_STATE_PAUSED_TO_READY:
ret = gst_element_set_state (play_bin->thread, GST_STATE_READY);
break; break;
case GST_STATE_READY_TO_NULL: case GST_STATE_READY_TO_NULL:
ret = gst_element_set_state (play_bin->thread, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (play_bin->thread));
break; break;
default: default:
g_assert_not_reached (); g_assert_not_reached ();
break; break;
} }
if (ret == GST_STATE_SUCCESS) {
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
}
return ret; return ret;
} }
static void
gst_play_bin_add_element (GstBin * bin, GstElement * element)
{
GstPlayBin *play_bin;
play_bin = GST_PLAY_BIN (bin);
}
static void
gst_play_bin_remove_element (GstBin * bin, GstElement * element)
{
GstPlayBin *play_bin;
play_bin = GST_PLAY_BIN (bin);
}
static const GstEventMask * static const GstEventMask *
gst_play_bin_get_event_masks (GstElement * element) gst_play_bin_get_event_masks (GstElement * element)
@ -561,7 +385,20 @@ static gboolean
gst_play_bin_send_event (GstElement * element, GstEvent * event) gst_play_bin_send_event (GstElement * element, GstEvent * event)
{ {
gboolean res = FALSE; gboolean res = FALSE;
GList *s;
GstPlayBin *play_bin;
play_bin = GST_PLAY_BIN (element);
s = play_bin->seekables;
for (s = play_bin->seekables; s; s = g_list_next (s)) {
GstElement *element = GST_ELEMENT (s->data);
gboolean ok;
ok = gst_element_send_event (element, event);
res |= ok;
}
return res; return res;
} }
@ -570,8 +407,6 @@ gst_play_bin_get_formats (GstElement * element)
{ {
static GstFormat formats[] = { static GstFormat formats[] = {
GST_FORMAT_TIME, GST_FORMAT_TIME,
GST_FORMAT_BYTES,
GST_FORMAT_DEFAULT,
0, 0,
}; };
@ -583,7 +418,23 @@ gst_play_bin_convert (GstElement * element,
GstFormat src_format, gint64 src_value, GstFormat src_format, gint64 src_value,
GstFormat * dest_format, gint64 * dest_value) GstFormat * dest_format, gint64 * dest_value)
{ {
return FALSE; gboolean res = FALSE;
GList *s;
GstPlayBin *play_bin;
play_bin = GST_PLAY_BIN (element);
s = play_bin->seekables;
for (s = play_bin->seekables; s; s = g_list_next (s)) {
GstElement *element = GST_ELEMENT (s->data);
res = gst_element_convert (element, src_format, src_value,
dest_format, dest_value);
if (res)
break;
}
return res;
} }
static const GstQueryType * static const GstQueryType *
@ -592,8 +443,6 @@ gst_play_bin_get_query_types (GstElement * element)
static const GstQueryType query_types[] = { static const GstQueryType query_types[] = {
GST_QUERY_TOTAL, GST_QUERY_TOTAL,
GST_QUERY_POSITION, GST_QUERY_POSITION,
GST_QUERY_START,
GST_QUERY_SEGMENT_END,
0 0
}; };
@ -605,18 +454,21 @@ gst_play_bin_query (GstElement * element, GstQueryType type,
GstFormat * format, gint64 * value) GstFormat * format, gint64 * value)
{ {
gboolean res = FALSE; gboolean res = FALSE;
GList *s;
return res;
}
static GstClock *
gst_play_bin_get_clock (GstElement * element)
{
GstPlayBin *play_bin; GstPlayBin *play_bin;
play_bin = GST_PLAY_BIN (element); play_bin = GST_PLAY_BIN (element);
return gst_bin_get_clock (GST_BIN (play_bin->thread)); s = play_bin->seekables;
for (s = play_bin->seekables; s; s = g_list_next (s)) {
GstElement *element = GST_ELEMENT (s->data);
res = gst_element_query (element, type, format, value);
if (res)
break;
}
return res;
} }
static gboolean static gboolean

View file

@ -0,0 +1,208 @@
/* 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"
/* props */
enum
{
ARG_0,
ARG_PAD,
ARG_TYPE,
ARG_DECODER,
};
/* signals */
enum
{
LAST_SIGNAL
};
#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 GEnumValue stream_type[] = {
{GST_STREAM_TYPE_UNKNOWN, "GST_STREAM_TYPE_UNKNOWN", "Unknown stream"},
{GST_STREAM_TYPE_AUDIO, "GST_STREAM_TYPE_AUDIO", "Audio stream"},
{GST_STREAM_TYPE_VIDEO, "GST_STREAM_TYPE_VIDEO", "Video stream"},
{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 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_ref (G_TYPE_OBJECT);
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 ("pad", "Pad", "Source Pad of the stream",
GST_TYPE_PAD, G_PARAM_READABLE));
g_object_class_install_property (gobject_klass, ARG_TYPE,
g_param_spec_enum ("type", "Type", "Type of the stream",
GST_TYPE_STREAM_TYPE, GST_STREAM_TYPE_UNKNOWN, G_PARAM_READABLE));
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));
gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_stream_info_dispose);
}
static void
gst_stream_info_init (GstStreamInfo * stream_info)
{
stream_info->pad = NULL;
stream_info->type = GST_STREAM_TYPE_UNKNOWN;
stream_info->decoder = NULL;
}
GstStreamInfo *
gst_stream_info_new (GstPad * pad, GstStreamType type, gchar * decoder)
{
GstStreamInfo *info;
info = g_object_new (GST_TYPE_STREAM_INFO, NULL);
gst_object_ref (GST_OBJECT (pad));
info->pad = pad;
info->type = type;
info->decoder = g_strdup (decoder);
return info;
}
static void
gst_stream_info_dispose (GObject * object)
{
GstStreamInfo *stream_info;
stream_info = GST_STREAM_INFO (object);
gst_object_unref (GST_OBJECT (stream_info->pad));
stream_info->pad = NULL;
stream_info->type = GST_STREAM_TYPE_UNKNOWN;
g_free (stream_info->decoder);
if (G_OBJECT_CLASS (parent_class)->dispose) {
G_OBJECT_CLASS (parent_class)->dispose (object);
}
}
static void
gst_stream_info_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstStreamInfo *stream_info;
g_return_if_fail (GST_IS_STREAM_INFO (object));
stream_info = GST_STREAM_INFO (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_stream_info_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstStreamInfo *stream_info;
g_return_if_fail (GST_IS_STREAM_INFO (object));
stream_info = GST_STREAM_INFO (object);
switch (prop_id) {
case ARG_PAD:
g_value_set_object (value, stream_info->pad);
break;
case ARG_TYPE:
g_value_set_enum (value, stream_info->type);
break;
case ARG_DECODER:
g_value_set_string (value, stream_info->decoder);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}

View file

@ -0,0 +1,63 @@
/* 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.
*/
#ifndef __GST_STREAMINFO_H__
#define __GST_STREAMINFO_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_STREAM_INFO (gst_stream_info_get_type())
#define GST_STREAM_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_STREAM_INFO,GstStreamInfo))
#define GST_STREAM_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_STREAM_INFO,GstStreamInfoClass))
#define GST_IS_STREAM_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_STREAM_INFO))
#define GST_IS_STREAM_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_STREAM_INFO))
typedef struct _GstStreamInfo GstStreamInfo;
typedef struct _GstStreamInfoClass GstStreamInfoClass;
typedef enum {
GST_STREAM_TYPE_UNKNOWN = 0,
GST_STREAM_TYPE_AUDIO = 1,
GST_STREAM_TYPE_VIDEO = 2,
} GstStreamType;
struct _GstStreamInfo {
GObject parent;
GstPad *pad;
GstStreamType type;
gchar *decoder;
};
struct _GstStreamInfoClass {
GObjectClass parent_class;
};
GType gst_stream_info_get_type (void);
GstStreamInfo* gst_stream_info_new (GstPad *pad, GstStreamType type, gchar *decoder);
G_END_DECLS
#endif /* __GST_STREAMINFO_H__ */

View file

@ -18,11 +18,56 @@
*/ */
#include <gst/gst.h> #include <gst/gst.h>
static GstElement *
gen_video_element ()
{
GstElement *element;
GstElement *conv;
GstElement *sink;
element = gst_thread_new ("vbin");
conv = gst_element_factory_make ("ffmpegcolorspace", "conv");
sink = gst_element_factory_make ("ximagesink", "sink");
gst_bin_add (GST_BIN (element), conv);
gst_bin_add (GST_BIN (element), sink);
gst_element_link_pads (conv, "src", sink, "sink");
gst_element_add_ghost_pad (element, gst_element_get_pad (conv, "sink"),
"sink");
return element;
}
static GstElement *
gen_audio_element ()
{
GstElement *element;
GstElement *conv;
GstElement *sink;
element = gst_thread_new ("abin");
conv = gst_element_factory_make ("audioconvert", "conv");
sink = gst_element_factory_make ("osssink", "sink");
gst_bin_add (GST_BIN (element), conv);
gst_bin_add (GST_BIN (element), sink);
gst_element_link_pads (conv, "src", sink, "sink");
gst_element_add_ghost_pad (element,
gst_element_get_pad (conv, "sink"), "sink");
return element;
}
gint gint
main (gint argc, gchar * argv[]) main (gint argc, gchar * argv[])
{ {
GstElement *player; GstElement *player;
GstElementStateReturn res; GstElementStateReturn res;
gint streams;
GList *streaminfo;
GList *s;
gst_init (&argc, &argv); gst_init (&argc, &argv);
@ -33,10 +78,48 @@ main (gint argc, gchar * argv[])
res = gst_element_set_state (player, GST_STATE_PAUSED); res = gst_element_set_state (player, GST_STATE_PAUSED);
if (res != GST_STATE_SUCCESS) { if (res != GST_STATE_SUCCESS) {
g_print ("could not play\n"); g_print ("could not pause\n");
return -1; return -1;
} }
/* get info about the stream */ /* get info about the stream */
g_print ("stream info:\n");
g_object_get (G_OBJECT (player), "nstreams", &streams, NULL);
g_print (" number of streams: %d\n", streams);
g_object_get (G_OBJECT (player), "stream-info", &streaminfo, NULL);
for (s = streaminfo; s; s = g_list_next (s)) {
GObject *obj = G_OBJECT (s->data);
int type;
GstPad *srcpad, *sinkpad;
GstElement *sink;
gboolean res;
g_object_get (obj, "type", &type, NULL);
g_print (" type: %d\n", type);
g_object_get (obj, "pad", &srcpad, NULL);
g_print (" pad: %p\n", srcpad);
if (type == 1) {
sink = gen_audio_element ();
} else if (type == 2) {
sink = gen_video_element ();
} else {
g_warning ("unknown stream found");
continue;
}
gst_bin_add (GST_BIN (player), sink);
sinkpad = gst_element_get_pad (sink, "sink");
res = gst_pad_link (srcpad, sinkpad);
if (!res) {
gchar *capsstr;
capsstr = gst_caps_to_string (gst_pad_get_caps (srcpad));
g_warning ("could not link %s", capsstr);
g_free (capsstr);
}
//g_signal_emit_by_name (G_OBJECT (player), "link_stream", obj, sinkpad);
}
/* set effects sinks */ /* set effects sinks */
res = gst_element_set_state (player, GST_STATE_PLAYING); res = gst_element_set_state (player, GST_STATE_PLAYING);

43
gst/playback/test2.c Normal file
View file

@ -0,0 +1,43 @@
/* 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.
*/
#include <gst/gst.h>
gint
main (gint argc, gchar * argv[])
{
GstElement *player;
GstElementStateReturn res;
gst_init (&argc, &argv);
player = gst_element_factory_make ("playbin", "player");
g_assert (player);
g_object_set (G_OBJECT (player), "uri", argv[1], NULL);
res = gst_element_set_state (player, GST_STATE_PLAYING);
if (res != GST_STATE_SUCCESS) {
g_print ("could not play\n");
return -1;
}
gst_main ();
return 0;
}

62
gst/playback/test3.c Normal file
View file

@ -0,0 +1,62 @@
/* 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.
*/
#include <gst/gst.h>
#define UPDATE_INTERVAL 500
static gboolean
update_scale (GstElement * element)
{
guint64 duration;
guint64 position;
GstFormat format = GST_FORMAT_TIME;
gst_element_query (element, GST_QUERY_TOTAL, &format, &duration);
gst_element_query (element, GST_QUERY_POSITION, &format, &position);
g_print ("%lld %lld\n", duration, position);
return TRUE;
}
gint
main (gint argc, gchar * argv[])
{
GstElement *player;
GstElementStateReturn res;
gst_init (&argc, &argv);
player = gst_element_factory_make ("playbin", "player");
g_assert (player);
g_object_set (G_OBJECT (player), "uri", argv[1], NULL);
res = gst_element_set_state (player, GST_STATE_PLAYING);
if (res != GST_STATE_SUCCESS) {
g_print ("could not play\n");
return -1;
}
g_timeout_add (UPDATE_INTERVAL, (GSourceFunc) update_scale, player);
gst_main ();
return 0;
}