diff --git a/ChangeLog b/ChangeLog index 449a09be2f..ad2e526e5d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,34 @@ +2008-01-07 Wim Taymans + + * gst/playback/gstplay-enum.c: + (register_gst_autoplug_select_result), + (gst_autoplug_select_result_get_type), (register_gst_play_flags), + (gst_play_flags_get_type): + * gst/playback/gstplay-enum.h: + Add enums for configuration flags. + + * gst/playback/gstplaybin2.c: (gst_play_bin_class_init), + (init_group), (gst_play_bin_init), (gst_play_bin_set_property), + (gst_play_bin_get_property), (no_more_pads_cb), + (autoplug_select_cb), (gst_play_bin_change_state): + Merge mode with flags. + Add more property getters/setters, defaults and docs. + Add properties to get number of audio/video/text streams. + Create sink object in _init so that we can always rely on it being + there. + + * gst/playback/gstplaysink.c: (gst_play_sink_init), + (gen_video_chain), (gen_audio_chain), (gen_vis_chain), + (activate_vis), (gst_play_sink_reconfigure), + (gst_play_sink_set_flags), (gst_play_sink_get_flags), + (gst_play_sink_change_state): + * gst/playback/gstplaysink.h: + Use flags to configure the sink pipelines. + Add tee before audio pipeline so that we can use it for visualisations. + Start working on integrating visualisations. + Remove mode, we can do everything with the flags now. + Add method to configue the sink pipeline. + 2008-01-06 Tim-Philipp Müller * tests/check/pipelines/theoraenc.c: (check_buffer_is_header), diff --git a/gst/playback/gstplay-enum.c b/gst/playback/gstplay-enum.c index c10f092bed..fcd650f6b1 100644 --- a/gst/playback/gstplay-enum.c +++ b/gst/playback/gstplay-enum.c @@ -20,6 +20,7 @@ #include "gstplay-enum.h" #define C_ENUM(v) ((gint) v) +#define C_FLAGS(v) ((guint) v) static void register_gst_autoplug_select_result (GType * id) @@ -43,3 +44,32 @@ gst_autoplug_select_result_get_type (void) g_once (&once, (GThreadFunc) register_gst_autoplug_select_result, &id); return id; } + +static void +register_gst_play_flags (GType * id) +{ + static const GFlagsValue values[] = { + {C_FLAGS (GST_PLAY_FLAG_VIDEO), "Render the video stream", "video"}, + {C_FLAGS (GST_PLAY_FLAG_AUDIO), "Render the audio stream", "audio"}, + {C_FLAGS (GST_PLAY_FLAG_TEXT), "Render subtitles", "text"}, + {C_FLAGS (GST_PLAY_FLAG_VIS), + "Render visualisation when no video is present", "vis"}, + {C_FLAGS (GST_PLAY_FLAG_SOFT_VOLUME), "Use software volume", "soft-volume"}, + {C_FLAGS (GST_PLAY_FLAG_NATIVE_AUDIO), "Only use native audio formats", + "native-audio"}, + {C_FLAGS (GST_PLAY_FLAG_NATIVE_VIDEO), "Only use native video formats", + "native-video"}, + {0, NULL, NULL} + }; + *id = g_flags_register_static ("GstPlayFlags", values); +} + +GType +gst_play_flags_get_type (void) +{ + static GType id; + static GOnce once = G_ONCE_INIT; + + g_once (&once, (GThreadFunc) register_gst_play_flags, &id); + return id; +} diff --git a/gst/playback/gstplay-enum.h b/gst/playback/gstplay-enum.h index ac8c3c7e32..dabde5cc4c 100644 --- a/gst/playback/gstplay-enum.h +++ b/gst/playback/gstplay-enum.h @@ -41,6 +41,34 @@ typedef enum { #define GST_TYPE_AUTOPLUG_SELECT_RESULT (gst_autoplug_select_result_get_type()) GType gst_autoplug_select_result_get_type (void); +/** + * GstPlayFlags: + * @GST_PLAY_FLAG_VIDEO: Enable rendering of the video stream + * @GST_PLAY_FLAG_AUDIO: Enable rendering of the audio stream + * @GST_PLAY_FLAG_TEXT: Enable rendering of subtitles + * @GST_PLAY_FLAG_VIS: Enable rendering of visualisations when there is + * no video stream. + * @GST_PLAY_FLAG_SOFT_VOLUME: Use software volume + * @GST_PLAY_FLAG_NATIVE_AUDIO: only allow native audio formats, this omits + * configuration of audioconvert and audioresample. + * @GST_PLAY_FLAG_NATIVE_VIDEO: only allow native video formats, this omits + * configuration of ffmpegcolorspace and videoscale. + * + * Extra flags to configure the behaviour of the sinks. + */ +typedef enum { + GST_PLAY_FLAG_VIDEO = (1 << 0), + GST_PLAY_FLAG_AUDIO = (1 << 1), + GST_PLAY_FLAG_TEXT = (1 << 2), + GST_PLAY_FLAG_VIS = (1 << 3), + GST_PLAY_FLAG_SOFT_VOLUME = (1 << 4), + GST_PLAY_FLAG_NATIVE_AUDIO = (1 << 5), + GST_PLAY_FLAG_NATIVE_VIDEO = (1 << 6) +} GstPlayFlags; + +#define GST_TYPE_PLAY_FLAGS (gst_play_flags_get_type()) +GType gst_play_flags_get_type (void); + G_END_DECLS #endif /* __GST_PLAY_ENUM_H__ */ diff --git a/gst/playback/gstplaybin2.c b/gst/playback/gstplaybin2.c index ff374cc426..97987e5c16 100644 --- a/gst/playback/gstplaybin2.c +++ b/gst/playback/gstplaybin2.c @@ -264,7 +264,6 @@ GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug); #define GST_IS_PLAY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN)) #define VOLUME_MAX_DOUBLE 10.0 -#define CONNECTION_SPEED_DEFAULT 0 typedef struct _GstPlayBin GstPlayBin; typedef struct _GstPlayBinClass GstPlayBinClass; @@ -276,7 +275,6 @@ struct _GstSourceSelect { const gchar *media; /* the media type of the selector */ GstPlaySinkType type; /* the sink pad type of the selector */ - GstPlaySinkMode mode; /* the sink pad mode of the selector */ GstElement *selector; /* the selector */ gint current; /* the currently selected stream */ @@ -336,6 +334,27 @@ struct _GstPlayBinClass }; /* props */ +#define DEFAULT_URI NULL +#define DEFAULT_SUBURI NULL +#define DEFAULT_STREAMINFO NULL +#define DEFAULT_SOURCE NULL +#define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \ + GST_PLAY_FLAG_SOFT_VOLUME +#define DEFAULT_N_VIDEO 0 +#define DEFAULT_CURRENT_VIDEO -1 +#define DEFAULT_N_AUDIO 0 +#define DEFAULT_CURRENT_AUDIO -1 +#define DEFAULT_N_TEXT 0 +#define DEFAULT_CURRENT_TEXT -1 +#define DEFAULT_SUBTITLE_ENCODING NULL +#define DEFAULT_AUDIO_SINK NULL +#define DEFAULT_VIDEO_SINK NULL +#define DEFAULT_VIS_PLUGIN NULL +#define DEFAULT_VOLUME 1.0 +#define DEFAULT_FRAME NULL +#define DEFAULT_FONT_DESC NULL +#define DEFAULT_CONNECTION_SPEED 0 + enum { PROP_0, @@ -343,8 +362,12 @@ enum PROP_SUBURI, PROP_STREAMINFO, PROP_SOURCE, + PROP_FLAGS, + PROP_N_VIDEO, PROP_CURRENT_VIDEO, + PROP_N_AUDIO, PROP_CURRENT_AUDIO, + PROP_N_TEXT, PROP_CURRENT_TEXT, PROP_SUBTITLE_ENCODING, PROP_AUDIO_SINK, @@ -433,9 +456,22 @@ gst_play_bin_class_init (GstPlayBinClass * klass) gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_play_bin_finalize); + /** + * GstPlayBin:uri + * + * Set the next URI that playbin will play. This property can be set from the + * about-to-finish signal to queue the next media file. + */ g_object_class_install_property (gobject_klass, PROP_URI, g_param_spec_string ("uri", "URI", "URI of the media to play", NULL, G_PARAM_READWRITE)); + + /** + * GstPlayBin:suburi + * + * Set the next subtitle URI that playbin will play. This property can be + * set from the about-to-finish signal to queue the next subtitle media file. + */ g_object_class_install_property (gobject_klass, PROP_SUBURI, g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle", NULL, G_PARAM_READWRITE)); @@ -450,18 +486,70 @@ gst_play_bin_class_init (GstPlayBinClass * klass) g_param_spec_object ("source", "Source", "Source element", GST_TYPE_ELEMENT, G_PARAM_READABLE)); + g_object_class_install_property (gobject_klass, PROP_FLAGS, + g_param_spec_flags ("flags", "Flags", "Flags to control behaviour", + GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS, G_PARAM_READWRITE)); + + /** + * GstPlayBin:n-video + * + * Get the total number of available video streams. + */ + g_object_class_install_property (gobject_klass, PROP_N_VIDEO, + g_param_spec_int ("n-video", "Number Video", + "Total number of video streams", 0, G_MAXINT, 0, G_PARAM_READABLE)); + /** + * GstPlayBin:current-video + * + * Get or set the currently playing video stream. By default the first video + * stream with data is played. + * + * Setting this property to -2 will disable the video stream. + */ g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO, - g_param_spec_int ("current-video", "Current video", - "Currently playing video stream (-1 = none)", - -1, G_MAXINT, -1, G_PARAM_READWRITE)); + g_param_spec_int ("current-video", "Current Video", + "Currently playing video stream (-1 = auto, -2 = none)", + -2, G_MAXINT, -1, G_PARAM_READWRITE)); + /** + * GstPlayBin:n-audio + * + * Get the total number of available audio streams. + */ + g_object_class_install_property (gobject_klass, PROP_N_AUDIO, + g_param_spec_int ("n-audio", "Number Audio", + "Total number of audio streams", 0, G_MAXINT, 0, G_PARAM_READABLE)); + /** + * GstPlayBin:current-audio + * + * Get or set the currently playing audio stream. By default the first audio + * stream with data is played. + * + * Setting this property to -2 will disable the audio stream. + */ g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO, g_param_spec_int ("current-audio", "Current audio", - "Currently playing audio stream (-1 = none)", - -1, G_MAXINT, -1, G_PARAM_READWRITE)); + "Currently playing audio stream (-1 = none, -2 = none)", + -2, G_MAXINT, -1, G_PARAM_READWRITE)); + /** + * GstPlayBin:n-text + * + * Get the total number of available subtitle streams. + */ + g_object_class_install_property (gobject_klass, PROP_N_TEXT, + g_param_spec_int ("n-text", "Number Text", + "Total number of text streams", 0, G_MAXINT, 0, G_PARAM_READABLE)); + /** + * GstPlayBin:current-text + * + * Get or set the currently playing subtitle stream. By default the first audio + * stream with data is played. + * + * Setting this property to -2 will disable the text stream. + */ g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT, - g_param_spec_int ("current-text", "Current text", - "Currently playing text stream (-1 = none)", - -1, G_MAXINT, -1, G_PARAM_READWRITE)); + g_param_spec_int ("current-text", "Current Text", + "Currently playing text stream (-1 = none, -2 = none)", + -2, G_MAXINT, -1, G_PARAM_READWRITE)); g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING, g_param_spec_string ("subtitle-encoding", "subtitle encoding", @@ -482,6 +570,7 @@ 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 (gobject_klass, PROP_VOLUME, g_param_spec_double ("volume", "volume", "volume", 0.0, VOLUME_MAX_DOUBLE, 1.0, G_PARAM_READWRITE)); @@ -498,7 +587,7 @@ gst_play_bin_class_init (GstPlayBinClass * klass) g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED, g_param_spec_uint ("connection-speed", "Connection Speed", "Network connection speed in kbps (0 = unknown)", - 0, G_MAXUINT, CONNECTION_SPEED_DEFAULT, G_PARAM_READWRITE)); + 0, G_MAXUINT, DEFAULT_CONNECTION_SPEED, G_PARAM_READWRITE)); /** * GstPlayBin::about-to-finish: * @@ -527,19 +616,14 @@ init_group (GstPlayBin * playbin, GstSourceGroup * group) group->playbin = playbin; group->selector[0].media = "audio/x-raw-"; group->selector[0].type = GST_PLAY_SINK_TYPE_AUDIO_RAW; - group->selector[0].mode = GST_PLAY_SINK_MODE_AUDIO; group->selector[1].media = "audio/"; group->selector[1].type = GST_PLAY_SINK_TYPE_AUDIO; - group->selector[1].mode = GST_PLAY_SINK_MODE_AUDIO; group->selector[2].media = "video/x-raw-"; group->selector[2].type = GST_PLAY_SINK_TYPE_VIDEO_RAW; - group->selector[2].mode = GST_PLAY_SINK_MODE_VIDEO; group->selector[3].media = "video/"; group->selector[3].type = GST_PLAY_SINK_TYPE_VIDEO; - group->selector[3].mode = GST_PLAY_SINK_MODE_VIDEO; group->selector[4].media = "text/"; group->selector[4].type = GST_PLAY_SINK_TYPE_TEXT; - group->selector[4].mode = GST_PLAY_SINK_MODE_TEXT; } static void @@ -558,6 +642,11 @@ gst_play_bin_init (GstPlayBin * playbin) playbin->elements = gst_factory_list_get_elements (type); gst_factory_list_debug (playbin->elements); + /* add sink */ + playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL); + gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink)); + gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS); + /* get the caps */ } @@ -632,6 +721,17 @@ gst_play_bin_set_property (GObject * object, guint prop_id, case PROP_SUBURI: gst_play_bin_set_suburi (playbin, g_value_get_string (value)); break; + case PROP_FLAGS: + gst_play_sink_set_flags (playbin->playsink, g_value_get_flags (value)); + break; + case PROP_CURRENT_VIDEO: + break; + case PROP_CURRENT_AUDIO: + break; + case PROP_CURRENT_TEXT: + break; + case PROP_SUBTITLE_ENCODING: + break; case PROP_VIDEO_SINK: break; case PROP_AUDIO_SINK: @@ -681,6 +781,27 @@ gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value, g_value_set_string (value, playbin->next_group->suburi); GST_OBJECT_UNLOCK (playbin); break; + case PROP_STREAMINFO: + break; + case PROP_SOURCE: + break; + case PROP_FLAGS: + g_value_set_flags (value, gst_play_sink_get_flags (playbin->playsink)); + break; + case PROP_N_VIDEO: + break; + case PROP_CURRENT_VIDEO: + break; + case PROP_N_AUDIO: + break; + case PROP_CURRENT_AUDIO: + break; + case PROP_N_TEXT: + break; + case PROP_CURRENT_TEXT: + break; + case PROP_SUBTITLE_ENCODING: + break; case PROP_VIDEO_SINK: break; case PROP_AUDIO_SINK: @@ -691,6 +812,8 @@ gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value, break; case PROP_FRAME: break; + case PROP_FONT_DESC: + break; case PROP_CONNECTION_SPEED: GST_OBJECT_LOCK (playbin); g_value_set_uint (value, playbin->connection_speed / 1000); @@ -881,7 +1004,6 @@ static void no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group) { GstPlayBin *playbin; - GstPlaySinkMode mode = 0; GstPadLinkReturn res; gint i; @@ -896,12 +1018,11 @@ no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group) select->sinkpad = gst_play_sink_request_pad (playbin->playsink, select->type); res = gst_pad_link (select->srcpad, select->sinkpad); - GST_DEBUG_OBJECT (playbin, "linking type %s: %d", select->media, res); - mode |= select->mode; + GST_DEBUG_OBJECT (playbin, "linked type %s: %d", select->media, res); } } /* configure the modes now */ - gst_play_sink_set_mode (playbin->playsink, mode); + gst_play_sink_reconfigure (playbin->playsink); } /* send an EOS event to all of the selectors */ @@ -1214,11 +1335,6 @@ gst_play_bin_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_READY_TO_PAUSED: - if (playbin->playsink == NULL) { - playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL); - gst_bin_add (GST_BIN_CAST (playbin), - GST_ELEMENT_CAST (playbin->playsink)); - } if (!setup_next_source (playbin)) goto source_failed; break; @@ -1238,13 +1354,6 @@ gst_play_bin_change_state (GstElement * element, GstStateChange transition) break; case GST_STATE_CHANGE_PAUSED_TO_READY: save_current_group (playbin); - if (playbin->playsink) { - gst_element_set_state (GST_ELEMENT_CAST (playbin->playsink), - GST_STATE_NULL); - gst_bin_remove (GST_BIN_CAST (playbin), - GST_ELEMENT_CAST (playbin->playsink)); - playbin->playsink = NULL; - } break; default: break; diff --git a/gst/playback/gstplaysink.c b/gst/playback/gstplaysink.c index 21798554d6..105233fdb0 100644 --- a/gst/playback/gstplaysink.c +++ b/gst/playback/gstplaysink.c @@ -49,6 +49,8 @@ typedef struct typedef struct { GstPlayChain chain; + GstElement *tee; + GstPad *teesrc; GstElement *conv; GstElement *resample; GstElement *volume; @@ -64,6 +66,17 @@ typedef struct GstElement *sink; } GstPlayVideoChain; +typedef struct +{ + GstPlayChain chain; + GstPad *teesrc; + GstElement *queue; + GstElement *conv; + GstElement *resample; + GstElement *vis; + GstPad *srcpad; +} GstPlayVisChain; + #define GST_PLAY_SINK_GET_LOCK(playsink) (((GstPlaySink *)playsink)->lock) #define GST_PLAY_SINK_LOCK(playsink) g_mutex_lock (GST_PLAY_SINK_GET_LOCK (playsink)) #define GST_PLAY_SINK_UNLOCK(playsink) g_mutex_unlock (GST_PLAY_SINK_GET_LOCK (playsink)) @@ -74,11 +87,11 @@ struct _GstPlaySink GMutex *lock; - GstPlaySinkMode mode; - GstPlaySinkFlags flags; + GstPlayFlags flags; GstPlayChain *audiochain; GstPlayChain *videochain; + GstPlayChain *vischain; GstPad *audio_pad; gboolean audio_pad_raw; @@ -241,7 +254,7 @@ gst_play_sink_init (GstPlaySink * playsink) playsink->textoverlay_element = NULL; playsink->volume = 1.0; playsink->font_desc = NULL; - playsink->flags = GST_PLAY_SINK_FLAG_SOFT_VOLUME; + playsink->flags = GST_PLAY_FLAG_SOFT_VOLUME; playsink->lock = g_mutex_new (); } @@ -841,14 +854,17 @@ no_overlay: /* make the chain that contains the elements needed to perform * audio playback. * - * +-------------------------------------------------------------+ - * | abin | - * | +---------+ +----------+ +---------+ +---------+ | - * | |audioconv| |audioscale| | volume | |audiosink| | - * | +-sink src-sink src-sink src-sink | | - * | | +---------+ +----------+ +---------+ +---------+ | - * sink-+ | - * +-------------------------------------------------------------+ + * We add a tee as the first element so that we can link the visualisation chain + * to it when requested. + * + * +-----------------------------------------------------------------------+ + * | abin | + * | +-----+ +---------+ +----------+ +---------+ +---------+ | + * | | tee | |audioconv| |audioscale| | volume | |audiosink| | + * | +-sink src-sink src-sink src-sink src-sink | | + * | | +-----+ +---------+ +----------+ +---------+ +---------+ | + * sink-+ | + * +-----------------------------------------------------------------------+ */ static GstPlayChain * gen_audio_chain (GstPlaySink * playsink, gboolean raw) @@ -878,6 +894,9 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw) gst_bin_add (bin, chain->sink); if (raw) { + chain->tee = gst_element_factory_make ("tee", "atee"); + gst_bin_add (bin, chain->tee); + chain->conv = gst_element_factory_make ("audioconvert", "aconv"); if (chain->conv == NULL) goto no_audioconvert; @@ -888,9 +907,14 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw) goto no_audioresample; gst_bin_add (bin, chain->resample); + chain->teesrc = gst_element_get_request_pad (chain->tee, "src%d"); + pad = gst_element_get_pad (chain->conv, "sink"); + gst_pad_link (chain->teesrc, pad); + gst_object_unref (pad); + res = gst_element_link_pads (chain->conv, "src", chain->resample, "sink"); - if (playsink->flags & GST_PLAY_SINK_FLAG_SOFT_VOLUME) { + if (playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME) { chain->volume = gst_element_factory_make ("volume", "volume"); g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume, NULL); gst_bin_add (bin, chain->volume); @@ -904,7 +928,7 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw) if (!res) goto link_failed; - pad = gst_element_get_pad (chain->conv, "sink"); + pad = gst_element_get_pad (chain->tee, "sink"); } else { pad = gst_element_get_pad (chain->sink, "sink"); } @@ -951,118 +975,73 @@ link_failed: } } -#if 0 -/* make the element (bin) that contains the elements needed to perform - * visualisation ouput. The idea is to split the audio using tee, then - * sending the output to the regular audio bin and the other output to - * the vis plugin that transforms it into a video that is rendered with the - * normal video bin. The video and audio bins are run in threads to make sure - * they don't block eachother. - * - * +-----------------------------------------------------------------------+ - * | visbin | - * | +------+ +--------+ +----------------+ | - * | | tee | | aqueue | | abin ... | | - * | +-sink src-sink src-sink | | - * | | | | +--------+ +----------------+ | - * | | | | | - * | | | | +------+ +------------+ +------+ +-----------+ | - * | | | | |vqueue| | audioconv | | vis | | vbin ... | | - * | | | src-sink src-sink + samp src-sink src-sink | | - * | | | | +------+ +------------+ +------+ +-----------+ | - * | | | | | - * | | +------+ | - * sink-+ | - * +-----------------------------------------------------------------------+ +/* + * +--------------------------------------------------+ + * | visbin | + * | +--------+ +------------+ +-------+ | + * | | vqueue | | audioconv | | vis | | + * | +-sink src-sink + samp src-sink src-+ | + * | | +--------+ +------------+ +-------+ | | + * sink-+ +-src + * +--------------------------------------------------+ + * */ -static GstElement * -gen_vis_element (GstPlaySink * playsink) +#if 0 +static GstPlayChain * +gen_vis_chain (GstPlaySink * playsink) { + GstPlayVisChain *chain; + GstBin *bin; gboolean res; - GstElement *element; - GstElement *tee; - GstElement *asink; - GstElement *vsink; - GstElement *conv; - GstElement *resamp; - GstElement *conv2; - GstElement *vis; - GstElement *vqueue, *aqueue; - GstPad *pad, *rpad; + GstPad *pad; - /* errors are already posted when these fail. */ - asink = gen_audio_element (playsink); - if (!asink) - return NULL; - vsink = gen_video_element (playsink); - if (!vsink) { - gst_object_unref (asink); - return NULL; - } + chain = g_new0 (GstPlayVisChain, 1); + chain->chain.playsink = gst_object_ref (playsink); - element = gst_bin_new ("visbin"); - tee = gst_element_factory_make ("tee", "tee"); + chain->chain.bin = gst_bin_new ("abin"); + bin = GST_BIN_CAST (chain->chain.bin); + gst_object_ref (bin); + gst_object_sink (bin); - vqueue = gst_element_factory_make ("queue", "vqueue"); - aqueue = gst_element_factory_make ("queue", "aqueue"); + chain->queue = gst_element_factory_make ("queue", "visqueue"); + gst_bin_add (bin, chain->queue); - gst_bin_add (GST_BIN_CAST (element), asink); - gst_bin_add (GST_BIN_CAST (element), vqueue); - gst_bin_add (GST_BIN_CAST (element), aqueue); - gst_bin_add (GST_BIN_CAST (element), vsink); - gst_bin_add (GST_BIN_CAST (element), tee); - - conv = gst_element_factory_make ("audioconvert", "aconv"); - if (conv == NULL) + chain->conv = gst_element_factory_make ("audioconvert", "aconv"); + if (chain->conv == NULL) goto no_audioconvert; - gst_bin_add (GST_BIN_CAST (element), conv); + gst_bin_add (bin, chain->conv); - resamp = gst_element_factory_make ("audioresample", "aresamp"); - if (resamp == NULL) + chain->resample = gst_element_factory_make ("audioresample", "aresample"); + if (chain->resample == NULL) goto no_audioresample; - gst_bin_add (GST_BIN_CAST (element), resamp); - - conv2 = gst_element_factory_make ("audioconvert", "aconv2"); - if (conv2 == NULL) - goto no_audioconvert; - gst_bin_add (GST_BIN_CAST (element), conv2); + gst_bin_add (bin, chain->resample); if (playsink->visualisation) { - gst_object_ref (playsink->visualisation); - vis = playsink->visualisation; + chain->vis = playsink->visualisation; } else { - vis = gst_element_factory_make ("goom", "vis"); - if (!vis) + chain->vis = gst_element_factory_make ("goom", "vis"); + if (!chain->vis) goto no_goom; } - gst_bin_add (GST_BIN_CAST (element), vis); + gst_bin_add (bin, chain->vis); - res = gst_element_link_pads (vqueue, "src", conv, "sink"); - res &= gst_element_link_pads (conv, "src", resamp, "sink"); - res &= gst_element_link_pads (resamp, "src", conv2, "sink"); - res &= gst_element_link_pads (conv2, "src", vis, "sink"); - res &= gst_element_link_pads (vis, "src", vsink, "sink"); + res = gst_element_link_pads (chain->queue, "src", chain->conv, "sink"); + res &= gst_element_link_pads (chain->conv, "src", chain->resample, "sink"); + res &= gst_element_link_pads (chain->resample, "src", chain->vis, "sink"); if (!res) goto link_failed; - pad = gst_element_get_pad (aqueue, "sink"); - rpad = gst_element_get_request_pad (tee, "src%d"); - gst_pad_link (rpad, pad); - gst_object_unref (rpad); + pad = gst_element_get_pad (chain->queue, "sink"); + chain->chain.sinkpad = gst_ghost_pad_new ("sink", pad); gst_object_unref (pad); - gst_element_link_pads (aqueue, "src", asink, "sink"); + gst_element_add_pad (chain->chain.bin, chain->chain.sinkpad); - pad = gst_element_get_pad (vqueue, "sink"); - rpad = gst_element_get_request_pad (tee, "src%d"); - gst_pad_link (rpad, pad); - gst_object_unref (rpad); + pad = gst_element_get_pad (chain->vis, "src"); + chain->srcpad = gst_ghost_pad_new ("src", pad); gst_object_unref (pad); + gst_element_add_pad (chain->chain.bin, chain->srcpad); - pad = gst_element_get_pad (tee, "sink"); - gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad)); - gst_object_unref (pad); - - return element; + return (GstPlayChain *) chain; /* ERRORS */ no_audioconvert: @@ -1071,7 +1050,7 @@ no_audioconvert: GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN, (_("Missing element '%s' - check your GStreamer installation."), "audioconvert"), ("possibly a liboil version mismatch?")); - gst_object_unref (element); + free_chain ((GstPlayChain *) chain); return NULL; } no_audioresample: @@ -1080,7 +1059,7 @@ no_audioresample: GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN, (_("Missing element '%s' - check your GStreamer installation."), "audioresample"), (NULL)); - gst_object_unref (element); + free_chain ((GstPlayChain *) chain); return NULL; } no_goom: @@ -1089,41 +1068,60 @@ no_goom: GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN, (_("Missing element '%s' - check your GStreamer installation."), "goom"), (NULL)); - gst_object_unref (element); + free_chain ((GstPlayChain *) chain); return NULL; } link_failed: { GST_ELEMENT_ERROR (playsink, CORE, PAD, (NULL), ("Failed to configure the visualisation element.")); - gst_object_unref (element); + free_chain ((GstPlayChain *) chain); return NULL; } } #endif -GstPlaySinkMode -gst_play_sink_get_mode (GstPlaySink * playsink) +#if 0 +static gboolean +activate_vis (GstPlaySink * playsink, gboolean activate) { - GstPlaySinkMode res; + /* need to have an audio chain */ + if (!playsink->audiochain || !playsink->vischain) + return FALSE; - GST_PLAY_SINK_LOCK (playsink); - res = playsink->mode; - GST_PLAY_SINK_UNLOCK (playsink); + if (playsink->vischain->activated == activate) + return TRUE; - return res; + if (activate) { + /* activation: Add the vis chain to the sink bin . Take a new srcpad from + * the tee of the audio chain and link it to the sinkpad of the vis chain. + */ + + } else { + /* deactivation: release the srcpad from the tee of the audio chain. Set the + * vis chain to NULL and remove it from the sink bin */ + + } + return TRUE; } +#endif /* this function is called when all the request pads are requested and when we * have to construct the final pipeline. */ gboolean -gst_play_sink_set_mode (GstPlaySink * playsink, GstPlaySinkMode mode) +gst_play_sink_reconfigure (GstPlaySink * playsink) { - GST_DEBUG_OBJECT (playsink, "setting mode to %d", mode); + GstPlayFlags flags; + + GST_DEBUG_OBJECT (playsink, "reconfiguring"); GST_PLAY_SINK_LOCK (playsink); - if (mode & GST_PLAY_SINK_MODE_AUDIO && playsink->audio_pad) { + GST_OBJECT_LOCK (playsink); + flags = playsink->flags; + GST_OBJECT_UNLOCK (playsink); + + if (flags & GST_PLAY_FLAG_AUDIO && playsink->audio_pad) { if (!playsink->audiochain) playsink->audiochain = gen_audio_chain (playsink, playsink->audio_pad_raw); @@ -1140,7 +1138,7 @@ gst_play_sink_set_mode (GstPlaySink * playsink, GstPlaySinkMode mode) gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->audio_pad), NULL); } - if (mode & GST_PLAY_SINK_MODE_VIDEO && playsink->video_pad) { + if (flags & GST_PLAY_FLAG_VIDEO && playsink->video_pad) { if (!playsink->videochain) playsink->videochain = gen_video_chain (playsink, playsink->video_pad_raw); @@ -1156,35 +1154,33 @@ gst_play_sink_set_mode (GstPlaySink * playsink, GstPlaySinkMode mode) if (playsink->video_pad) gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad), NULL); } - - playsink->mode = mode; GST_PLAY_SINK_UNLOCK (playsink); return TRUE; } gboolean -gst_play_sink_set_flags (GstPlaySink * playsink, GstPlaySinkFlags flags) +gst_play_sink_set_flags (GstPlaySink * playsink, GstPlayFlags flags) { g_return_val_if_fail (GST_IS_PLAY_SINK (playsink), FALSE); GST_OBJECT_LOCK (playsink); playsink->flags = flags; - GST_OBJECT_LOCK (playsink); + GST_OBJECT_UNLOCK (playsink); return TRUE; } -GstPlaySinkFlags +GstPlayFlags gst_play_sink_get_flags (GstPlaySink * playsink) { - GstPlaySinkFlags res; + GstPlayFlags res; g_return_val_if_fail (GST_IS_PLAY_SINK (playsink), 0); GST_OBJECT_LOCK (playsink); res = playsink->flags; - GST_OBJECT_LOCK (playsink); + GST_OBJECT_UNLOCK (playsink); return res; } @@ -1342,6 +1338,14 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition) break; case GST_STATE_CHANGE_PAUSED_TO_READY: /* remove sinks we added */ + if (playsink->videochain) { + activate_chain (playsink->videochain, FALSE); + add_chain (playsink->videochain, FALSE); + } + if (playsink->audiochain) { + activate_chain (playsink->audiochain, FALSE); + add_chain (playsink->audiochain, FALSE); + } break; default: break; diff --git a/gst/playback/gstplaysink.h b/gst/playback/gstplaysink.h index 5c1f1e46c4..6373edd332 100644 --- a/gst/playback/gstplaysink.h +++ b/gst/playback/gstplaysink.h @@ -22,6 +22,8 @@ #include +#include "gstplay-enum.h" + G_BEGIN_DECLS #define GST_TYPE_PLAY_SINK \ @@ -35,22 +37,6 @@ G_BEGIN_DECLS #define GST_IS_PLAY_SINK_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PLAY_SINK)) -/** - * GstPlaySinkMode: - * @GST_PLAY_SINK_MODE_VIDEO: - * @GST_PLAY_SINK_MODE_AUDIO: - * @GST_PLAY_SINK_MODE_TEXT: - * @GST_PLAY_SINK_MODE_VIS: - * - * Features to enable in the sink. - */ -typedef enum { - GST_PLAY_SINK_MODE_VIDEO = (1 << 0), - GST_PLAY_SINK_MODE_AUDIO = (1 << 1), - GST_PLAY_SINK_MODE_TEXT = (1 << 2), - GST_PLAY_SINK_MODE_VIS = (1 << 3) -} GstPlaySinkMode; - /** * GstPlaySinkType: * @GST_PLAY_SINK_TYPE_AUDIO: A non-raw audio pad @@ -71,22 +57,6 @@ typedef enum { GST_PLAY_SINK_TYPE_LAST = 5 } GstPlaySinkType; -/** - * GstPlaySinkFlags: - * @GST_PLAY_SINK_FLAG_SOFT_VOLUME: Use software volume in the sink - * @GST_PLAY_SINK_FLAG_NATIVE_AUDIO: only allow native audio formats, this omits - * configuration of audioconvert and audioresample. - * @GST_PLAY_SINK_FLAG_NATIVE_VIDEO: only allow native video formats, this omits - * configuration of ffmpegcolorspace and videoscale. - * - * Extra flags to configure the behaviour of the sinks. - */ -typedef enum { - GST_PLAY_SINK_FLAG_SOFT_VOLUME = (1 << 0), - GST_PLAY_SINK_FLAG_NATIVE_AUDIO = (1 << 1), - GST_PLAY_SINK_FLAG_NATIVE_VIDEO = (1 << 2) -} GstPlaySinkFlags; - typedef struct _GstPlaySink GstPlaySink; typedef struct _GstPlaySinkClass GstPlaySinkClass; @@ -99,11 +69,10 @@ void gst_play_sink_set_video_sink (GstPlaySink * playsink, GstElemen void gst_play_sink_set_audio_sink (GstPlaySink * playsink, GstElement * sink); void gst_play_sink_set_vis_plugin (GstPlaySink * playsink, GstElement * vis); -gboolean gst_play_sink_set_flags (GstPlaySink * playsink, GstPlaySinkFlags flags); -GstPlaySinkFlags gst_play_sink_get_flags (GstPlaySink * playsink); +gboolean gst_play_sink_set_flags (GstPlaySink * playsink, GstPlayFlags flags); +GstPlayFlags gst_play_sink_get_flags (GstPlaySink * playsink); -gboolean gst_play_sink_set_mode (GstPlaySink *playsink, GstPlaySinkMode mode); -GstPlaySinkMode gst_play_sink_get_mode (GstPlaySink *playsink); +gboolean gst_play_sink_reconfigure (GstPlaySink * playsink); G_END_DECLS