* input-selector, so that we only post a
* warning once */
- gboolean pending_flush_finish; /* whether we are pending to send a custom
- * subtitleoverlay-flush-subtitle-finish event
+ gboolean video_pending_flush_finish; /* whether we are pending to send a custom
+ * custom-video-flush-finish event
+ * on pad activation */
+ gboolean audio_pending_flush_finish; /* whether we are pending to send a custom
+ * custom-audio-flush-finish event
+ * on pad activation */
+ gboolean text_pending_flush_finish; /* whether we are pending to send a custom
+ * custom-subtitle-flush-finish event
* on pad activation */
GstElement *audio_sink; /* configured audio sink, or NULL */
}
static gboolean
+gst_playbin2_send_custom_event (GstObject * selector, const gchar * event_name)
+{
+ GstPad *src;
+ GstPad *peer;
+ GstStructure *s;
+ GstEvent *event;
+ gboolean ret = FALSE;
+
+ src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
+ peer = gst_pad_get_peer (src);
+ if (peer) {
+ s = gst_structure_new_empty (event_name);
+ event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
+ gst_pad_send_event (peer, event);
+ gst_object_unref (peer);
+ ret = TRUE;
+ }
+ gst_object_unref (src);
+ return ret;
+}
+
+static gboolean
gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
{
GstSourceGroup *group;
GstObject *selector;
if ((selector = gst_pad_get_parent (sinkpad))) {
- /* activate the selected pad */
- g_object_set (selector, "active-pad", sinkpad, NULL);
+ GstPad *old_sinkpad;
+
+ g_object_get (selector, "active-pad", &old_sinkpad, NULL);
+
+ if (old_sinkpad != sinkpad) {
+ if (gst_playbin2_send_custom_event (selector,
+ "playsink-custom-video-flush"))
+ playbin->video_pending_flush_finish = TRUE;
+
+ /* activate the selected pad */
+ g_object_set (selector, "active-pad", sinkpad, NULL);
+ }
+
gst_object_unref (selector);
}
gst_object_unref (sinkpad);
GstObject *selector;
if ((selector = gst_pad_get_parent (sinkpad))) {
- /* activate the selected pad */
- g_object_set (selector, "active-pad", sinkpad, NULL);
+ GstPad *old_sinkpad;
+
+ g_object_get (selector, "active-pad", &old_sinkpad, NULL);
+
+ if (old_sinkpad != sinkpad) {
+ if (gst_playbin2_send_custom_event (selector,
+ "playsink-custom-audio-flush"))
+ playbin->audio_pending_flush_finish = TRUE;
+
+ /* activate the selected pad */
+ g_object_set (selector, "active-pad", sinkpad, NULL);
+ }
gst_object_unref (selector);
}
gst_object_unref (sinkpad);
if (old_sinkpad != sinkpad) {
gboolean need_unblock, need_block, need_seek;
- GstPad *src, *peer = NULL, *oldpeer = NULL;
+ GstPad *peer = NULL, *oldpeer = NULL;
GstElement *parent_element = NULL, *old_parent_element = NULL;
/* Now check if we need to seek the suburidecodebin to the beginning
gst_play_bin_suburidecodebin_block (group, group->suburidecodebin,
TRUE);
- src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
- peer = gst_pad_get_peer (src);
- if (peer) {
- GstStructure *s;
- GstEvent *event;
- /* Flush the subtitle renderer to remove any
- * currently displayed subtitles. This event will
- * never travel outside subtitleoverlay!
- */
- s = gst_structure_new_empty ("subtitleoverlay-flush-subtitle");
- event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
- gst_pad_send_event (peer, event);
- playbin->pending_flush_finish = TRUE;
- gst_object_unref (peer);
- }
- gst_object_unref (src);
+ if (gst_playbin2_send_custom_event (selector,
+ "playsink-custom-subtitle-flush"))
+ playbin->text_pending_flush_finish = TRUE;
/* activate the selected pad */
g_object_set (selector, "active-pad", sinkpad, NULL);
property = "current-video";
playbin->current_video = get_current_stream_number (playbin,
group->video_channels);
+
+ if (playbin->video_pending_flush_finish) {
+ playbin->video_pending_flush_finish = FALSE;
+ GST_PLAY_BIN_UNLOCK (playbin);
+ gst_playbin2_send_custom_event (GST_OBJECT (selector),
+ "playsink-custom-video-flush-finish");
+ goto notify;
+ }
break;
case GST_PLAY_SINK_TYPE_AUDIO:
case GST_PLAY_SINK_TYPE_AUDIO_RAW:
property = "current-audio";
playbin->current_audio = get_current_stream_number (playbin,
group->audio_channels);
+
+ if (playbin->audio_pending_flush_finish) {
+ playbin->audio_pending_flush_finish = FALSE;
+ GST_PLAY_BIN_UNLOCK (playbin);
+ gst_playbin2_send_custom_event (GST_OBJECT (selector),
+ "playsink-custom-audio-flush-finish");
+ goto notify;
+ }
break;
case GST_PLAY_SINK_TYPE_TEXT:
property = "current-text";
playbin->current_text = get_current_stream_number (playbin,
group->text_channels);
- if (playbin->pending_flush_finish) {
- GstEvent *ev;
- GstStructure *s;
- GstPad *src, *peer;
-
- playbin->pending_flush_finish = FALSE;
+ if (playbin->text_pending_flush_finish) {
+ playbin->text_pending_flush_finish = FALSE;
GST_PLAY_BIN_UNLOCK (playbin);
-
- /* Flush the subtitle renderer to remove any
- * currently displayed subtitles. This event will
- * never travel outside subtitleoverlay!
- */
- src = gst_element_get_static_pad (GST_ELEMENT_CAST (selector), "src");
- peer = gst_pad_get_peer (src);
- s = gst_structure_new_empty ("subtitleoverlay-flush-subtitle-finish");
- ev = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, s);
- gst_pad_send_event (peer, ev);
- gst_object_unref (peer);
- gst_object_unref (src);
-
+ gst_playbin2_send_custom_event (GST_OBJECT (selector),
+ "playsink-custom-subtitle-flush-finish");
goto notify;
}
break;
(_("Missing element '%s' - check your GStreamer installation."),
"input-selector"), (NULL));
} else {
- g_object_set (select->selector, "sync-streams", TRUE, NULL);
+ /* sync-mode=1, use clock */
+ if (select->type == GST_PLAY_SINK_TYPE_TEXT)
+ g_object_set (select->selector, "sync-streams", TRUE,
+ "sync-mode", 1, "cache-buffers", TRUE, NULL);
+ else
+ g_object_set (select->selector, "sync-streams", TRUE, NULL);
g_signal_connect (select->selector, "notify::active-pad",
G_CALLBACK (selector_active_pad_changed), playbin);
GList *colorbalance_channels; /* CONTRAST, BRIGHTNESS, HUE, SATURATION */
gint colorbalance_values[4];
+ /* sending audio/video flushes break stream changes when the pipeline
+ * is paused and played again in 0.10 */
+#if 0
+ GstSegment video_segment;
+ gboolean video_custom_flush_finished;
+ gboolean video_ignore_wrong_state;
+ gboolean video_pending_flush;
+
+ GstSegment audio_segment;
+ gboolean audio_custom_flush_finished;
+ gboolean audio_ignore_wrong_state;
+ gboolean audio_pending_flush;
+#endif
+
GstSegment text_segment;
- gboolean custom_flush_finished;
- gboolean ignore_wrong_state;
- gboolean pending_flush_stop;
+ gboolean text_custom_flush_finished;
+ gboolean text_ignore_wrong_state;
+ gboolean text_pending_flush;
};
struct _GstPlaySinkClass
static void gst_play_sink_handle_message (GstBin * bin, GstMessage * message);
+/* sending audio/video flushes break stream changes when the pipeline
+ * is paused and played again in 0.10 */
+#if 0
+static gboolean gst_play_sink_video_sink_event (GstPad * pad, GstEvent * event);
+static GstFlowReturn gst_play_sink_video_sink_chain (GstPad * pad,
+ GstBuffer * buffer);
+static gboolean gst_play_sink_audio_sink_event (GstPad * pad, GstEvent * event);
+static GstFlowReturn gst_play_sink_audio_sink_chain (GstPad * pad,
+ GstBuffer * buffer);
+#endif
+static gboolean gst_play_sink_text_sink_event (GstPad * pad, GstObject * parent,
+ GstEvent * event);
+static GstFlowReturn gst_play_sink_text_sink_chain (GstPad * pad,
+ GstObject * parent, GstBuffer * buffer);
+
static void notify_volume_cb (GObject * object, GParamSpec * pspec,
GstPlaySink * playsink);
static void notify_mute_cb (GObject * object, GParamSpec * pspec,
pad = gst_element_get_static_pad (head, "sink");
chain->sinkpad = gst_ghost_pad_new ("sink", pad);
- gst_object_unref (pad);
+ /* sending audio/video flushes break stream changes when the pipeline
+ * is paused and played again in 0.10 */
+#if 0
+ gst_pad_set_event_function (chain->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_play_sink_video_sink_event));
+ gst_pad_set_chain_function (chain->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_play_sink_video_sink_chain));
+#endif
+
+ gst_object_unref (pad);
gst_element_add_pad (chain->chain.bin, chain->sinkpad);
return chain;
}
static gboolean
-gst_play_sink_text_sink_event (GstPad * pad, GstObject * parent,
- GstEvent * event)
+gst_play_sink_sink_event (GstPad * pad, GstObject * parent, GstEvent * event,
+ const gchar * sink_type,
+ gboolean * sink_ignore_wrong_state,
+ gboolean * sink_custom_flush_finished,
+ gboolean * sink_pending_flush, GstSegment * sink_segment)
{
GstPlaySink *playsink = GST_PLAY_SINK_CAST (gst_object_get_parent (parent));
gboolean ret;
const GstStructure *structure = gst_event_get_structure (event);
- if (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_DOWNSTREAM_OOB &&
- structure
- && strcmp (gst_structure_get_name (structure),
- "subtitleoverlay-flush-subtitle") == 0) {
- GST_DEBUG_OBJECT (pad,
- "Custom subtitle flush event received, marking to flush text");
- GST_PLAY_SINK_LOCK (playsink);
- playsink->ignore_wrong_state = TRUE;
- playsink->custom_flush_finished = FALSE;
- GST_PLAY_SINK_UNLOCK (playsink);
- } else if (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_DOWNSTREAM_OOB &&
- structure && strcmp (gst_structure_get_name (structure),
- "subtitleoverlay-flush-subtitle-finish") == 0) {
- GST_DEBUG_OBJECT (pad, "Custom subtitle flush finish event received");
+ if (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_DOWNSTREAM_OOB && structure) {
+ gchar *custom_flush;
+ gchar *custom_flush_finish;
+
+ custom_flush = g_strdup_printf ("playsink-custom-%s-flush", sink_type);
+ custom_flush_finish =
+ g_strdup_printf ("playsink-custom-%s-flush-finish", sink_type);
+ if (strcmp (gst_structure_get_name (structure), custom_flush) == 0) {
+ GST_DEBUG_OBJECT (pad,
+ "Custom %s flush event received, marking to flush %s", sink_type,
+ sink_type);
+ GST_PLAY_SINK_LOCK (playsink);
+ *sink_ignore_wrong_state = TRUE;
+ *sink_custom_flush_finished = FALSE;
+ GST_PLAY_SINK_UNLOCK (playsink);
+ } else if (strcmp (gst_structure_get_name (structure),
+ custom_flush_finish) == 0) {
+ GST_DEBUG_OBJECT (pad, "Custom %s flush finish event received",
+ sink_type);
+ GST_PLAY_SINK_LOCK (playsink);
+ *sink_pending_flush = TRUE;
+ *sink_custom_flush_finished = TRUE;
+ GST_PLAY_SINK_UNLOCK (playsink);
+ }
+
+ g_free (custom_flush);
+ g_free (custom_flush_finish);
+ } else if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
GST_PLAY_SINK_LOCK (playsink);
- playsink->pending_flush_stop = TRUE;
- playsink->custom_flush_finished = TRUE;
+ GST_DEBUG_OBJECT (pad, "Resetting %s segment because of flush-stop event",
+ sink_type);
+ gst_segment_init (sink_segment, GST_FORMAT_UNDEFINED);
GST_PLAY_SINK_UNLOCK (playsink);
- } else if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
- GST_DEBUG_OBJECT (pad,
- "Resetting text segment because of flush-stop event");
- gst_segment_init (&playsink->text_segment, GST_FORMAT_UNDEFINED);
}
+ GST_DEBUG_OBJECT (pad, "Forwarding event %" GST_PTR_FORMAT, event);
ret = gst_proxy_pad_event_default (pad, parent, gst_event_ref (event));
if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
gst_event_parse_segment (event, &segment);
GST_DEBUG_OBJECT (pad, "Segment event: %" GST_SEGMENT_FORMAT, segment);
- if (playsink->text_segment.format != segment->format) {
- GST_DEBUG_OBJECT (pad, "Text segment format changed: %s -> %s",
- gst_format_get_name (playsink->text_segment.format),
+ GST_PLAY_SINK_LOCK (playsink);
+ if (sink_segment->format != segment->format) {
+ GST_DEBUG_OBJECT (pad, "%s segment format changed: %s -> %s",
+ sink_type,
+ gst_format_get_name (sink_segment->format),
gst_format_get_name (segment->format));
+ gst_segment_init (sink_segment, segment->format);
}
- GST_DEBUG_OBJECT (pad, "Old text segment: %" GST_SEGMENT_FORMAT,
- &playsink->text_segment);
- gst_segment_copy_into (segment, &playsink->text_segment);
- GST_DEBUG_OBJECT (pad, "New text segment: %" GST_SEGMENT_FORMAT,
- &playsink->text_segment);
+ GST_DEBUG_OBJECT (pad, "Old %s segment: %" GST_SEGMENT_FORMAT,
+ sink_type, sink_segment);
+ gst_segment_copy_into (&playsink->text_segment, sink_segment);
+ GST_DEBUG_OBJECT (pad, "New %s segment: %" GST_SEGMENT_FORMAT,
+ sink_type, sink_segment);
+ GST_PLAY_SINK_UNLOCK (playsink);
}
gst_event_unref (event);
}
static GstFlowReturn
-gst_play_sink_text_sink_chain (GstPad * pad, GstObject * parent,
- GstBuffer * buffer)
+gst_play_sink_sink_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer,
+ const gchar * sink_type,
+ gboolean * sink_ignore_wrong_state,
+ gboolean * sink_custom_flush_finished,
+ gboolean * sink_pending_flush, GstSegment * sink_segment)
{
GstBin *tbin = GST_BIN_CAST (gst_pad_get_parent (pad));
GstPlaySink *playsink = GST_PLAY_SINK_CAST (gst_pad_get_parent (tbin));
GST_PLAY_SINK_LOCK (playsink);
- if (playsink->pending_flush_stop) {
- GstSegment text_segment;
+ if (*sink_pending_flush) {
+ GstSegment segment_copy;
GstEvent *event;
GstStructure *structure;
- /* it will be replaced in flush_stop */
- text_segment = playsink->text_segment;
+ *sink_pending_flush = FALSE;
+
+ /* sink_segment will be updated in flush */
+ segment_copy = *sink_segment;
+
+ GST_PLAY_SINK_UNLOCK (playsink);
+
+ /* make the bin drop all cached data.
+ * This event will be dropped on the src pad, if any. */
+ event = gst_event_new_flush_start ();
+ structure = gst_event_writable_structure (event);
+ gst_structure_id_set (structure,
+ _playsink_reset_segment_event_marker_id, G_TYPE_BOOLEAN, TRUE, NULL);
+
+ GST_DEBUG_OBJECT (pad,
+ "Pushing %s flush-start event with reset segment marker set: %"
+ GST_PTR_FORMAT, sink_type, event);
+ gst_pad_send_event (pad, event);
/* make queue drop all cached data.
* This event will be dropped on the src pad. */
_playsink_reset_segment_event_marker_id, G_TYPE_BOOLEAN, TRUE, NULL);
GST_DEBUG_OBJECT (pad,
- "Pushing flush-stop event with reset segment marker set: %"
- GST_PTR_FORMAT, event);
+ "Pushing %s flush-stop event with reset segment marker set: %"
+ GST_PTR_FORMAT, sink_type, event);
gst_pad_send_event (pad, event);
/* Re-sync queue segment info after flush-stop.
* This event will be dropped on the src pad. */
- if (text_segment.format != GST_FORMAT_UNDEFINED) {
+ if (sink_segment->format != GST_FORMAT_UNDEFINED) {
GstEvent *event1;
- _generate_update_newsegment_event (pad, &text_segment, &event1);
+ _generate_update_newsegment_event (pad, sink_segment, &event1);
GST_DEBUG_OBJECT (playsink,
"Pushing segment event with reset "
"segment marker set: %" GST_PTR_FORMAT, event1);
gst_pad_send_event (pad, event1);
}
-
- playsink->pending_flush_stop = FALSE;
+ } else {
+ GST_PLAY_SINK_UNLOCK (playsink);
}
- GST_PLAY_SINK_UNLOCK (playsink);
ret = gst_proxy_pad_chain_default (pad, parent, buffer);
GST_PLAY_SINK_LOCK (playsink);
- if (ret == GST_FLOW_FLUSHING && playsink->ignore_wrong_state) {
- GST_DEBUG_OBJECT (pad, "Ignoring wrong state during flush");
- if (playsink->custom_flush_finished) {
- GST_DEBUG_OBJECT (pad,
- "custom flush finished, stop ignoring wrong state");
- playsink->ignore_wrong_state = FALSE;
+ if (ret == GST_FLOW_FLUSHING && *sink_ignore_wrong_state) {
+ GST_DEBUG_OBJECT (pad, "Ignoring wrong state for %s during flush",
+ sink_type);
+ if (*sink_custom_flush_finished) {
+ GST_DEBUG_OBJECT (pad, "Custom flush finished, stop ignoring "
+ "wrong state for %s", sink_type);
+ *sink_ignore_wrong_state = FALSE;
}
ret = GST_FLOW_OK;
return ret;
}
+/* sending audio/video flushes break stream changes when the pipeline
+ * is paused and played again in 0.10 */
+#if 0
+static gboolean
+gst_play_sink_video_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstBin *tbin = GST_BIN_CAST (gst_pad_get_parent (pad));
+ GstPlaySink *playsink = GST_PLAY_SINK_CAST (gst_pad_get_parent (tbin));
+ gboolean ret;
+
+ ret = gst_play_sink_sink_event (pad, event, "video",
+ &playsink->video_ignore_wrong_state,
+ &playsink->video_custom_flush_finished,
+ &playsink->video_pending_flush, &playsink->video_segment);
+
+ gst_object_unref (playsink);
+ gst_object_unref (tbin);
+ return ret;
+}
+
+static GstFlowReturn
+gst_play_sink_video_sink_chain (GstPad * pad, GstBuffer * buffer)
+{
+ GstBin *tbin = GST_BIN_CAST (gst_pad_get_parent (pad));
+ GstPlaySink *playsink = GST_PLAY_SINK_CAST (gst_pad_get_parent (tbin));
+ gboolean ret;
+
+ ret = gst_play_sink_sink_chain (pad, buffer, "video",
+ &playsink->video_ignore_wrong_state,
+ &playsink->video_custom_flush_finished,
+ &playsink->video_pending_flush, &playsink->video_segment);
+
+ gst_object_unref (playsink);
+ gst_object_unref (tbin);
+ return ret;
+}
+
+static gboolean
+gst_play_sink_audio_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstBin *tbin = GST_BIN_CAST (gst_pad_get_parent (pad));
+ GstPlaySink *playsink = GST_PLAY_SINK_CAST (gst_pad_get_parent (tbin));
+ gboolean ret;
+
+ ret = gst_play_sink_sink_event (pad, event, "audio",
+ &playsink->audio_ignore_wrong_state,
+ &playsink->audio_custom_flush_finished,
+ &playsink->audio_pending_flush, &playsink->audio_segment);
+
+ gst_object_unref (playsink);
+ gst_object_unref (tbin);
+ return ret;
+}
+
+static GstFlowReturn
+gst_play_sink_audio_sink_chain (GstPad * pad, GstBuffer * buffer)
+{
+ GstBin *tbin = GST_BIN_CAST (gst_pad_get_parent (pad));
+ GstPlaySink *playsink = GST_PLAY_SINK_CAST (gst_pad_get_parent (tbin));
+ gboolean ret;
+
+ ret = gst_play_sink_sink_chain (pad, buffer, "audio",
+ &playsink->audio_ignore_wrong_state,
+ &playsink->audio_custom_flush_finished,
+ &playsink->audio_pending_flush, &playsink->audio_segment);
+
+ gst_object_unref (playsink);
+ gst_object_unref (tbin);
+ return ret;
+}
+#endif
+
+static gboolean
+gst_play_sink_text_sink_event (GstPad * pad, GstObject * parent,
+ GstEvent * event)
+{
+ GstPlaySink *playsink = GST_PLAY_SINK_CAST (gst_object_get_parent (parent));
+ gboolean ret;
+
+ ret = gst_play_sink_sink_event (pad, parent, event, "subtitle",
+ &playsink->text_ignore_wrong_state,
+ &playsink->text_custom_flush_finished,
+ &playsink->text_pending_flush, &playsink->text_segment);
+
+ gst_object_unref (playsink);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_play_sink_text_sink_chain (GstPad * pad, GstObject * parent,
+ GstBuffer * buffer)
+{
+ gboolean ret;
+ GstPlaySink *playsink = GST_PLAY_SINK_CAST (gst_object_get_parent (parent));
+
+ ret = gst_play_sink_sink_chain (pad, parent, buffer, "subtitle",
+ &playsink->text_ignore_wrong_state,
+ &playsink->text_custom_flush_finished,
+ &playsink->text_pending_flush, &playsink->text_segment);
+
+ gst_object_unref (playsink);
+ return ret;
+}
+
static gboolean
gst_play_sink_text_src_event (GstPad * pad, GstObject * parent,
GstEvent * event)
GST_DEBUG_OBJECT (playsink, "ghosting sink pad");
pad = gst_element_get_static_pad (head, "sink");
chain->sinkpad = gst_ghost_pad_new ("sink", pad);
+
+ /* sending audio/video flushes break stream changes when the pipeline
+ * is paused and played again in 0.10 */
+#if 0
+ gst_pad_set_event_function (chain->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_play_sink_audio_sink_event));
+ gst_pad_set_chain_function (chain->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_play_sink_audio_sink_chain));
+#endif
+
gst_object_unref (pad);
gst_element_add_pad (chain->chain.bin, chain->sinkpad);