*
* 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.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
GstElement *queue;
GstElement *conv;
GstElement *resample;
- GstPad *blockpad; /* srcpad of resample, used for switching the vis */
+ GstPad *blockpad; /* srcpad of queue, used for blocking the vis */
+ GstPad *vispeerpad; /* srcpad of resample, used for unlinking the vis */
GstPad *vissinkpad; /* visualisation sinkpad, */
GstElement *vis;
GstPad *vissrcpad; /* visualisation srcpad, */
gboolean mute_changed; /* ... has been created yet */
gint64 av_offset;
GstPlaySinkSendEventMode send_event_mode;
+ gboolean force_aspect_ratio;
/* videooverlay proxy interface */
GstVideoOverlay *overlay_element; /* protected with LOCK */
GstColorBalance *colorbalance_element;
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 text_custom_flush_finished;
+ gboolean text_ignore_wrong_state;
+ gboolean text_pending_flush;
};
struct _GstPlaySinkClass
PROP_AUDIO_SINK,
PROP_TEXT_SINK,
PROP_SEND_EVENT_MODE,
+ PROP_FORCE_ASPECT_RATIO,
PROP_LAST
};
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,
static void update_av_offset (GstPlaySink * playsink);
+static gboolean gst_play_sink_do_reconfigure (GstPlaySink * playsink);
+
+static GQuark _playsink_reset_segment_event_marker_id = 0;
+
/* static guint gst_play_sink_signals[LAST_SIGNAL] = { 0 }; */
static void gst_play_sink_overlay_init (gpointer g_iface,
GST_TYPE_PLAY_SINK_SEND_EVENT_MODE, MODE_DEFAULT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GstPlaySink::force-aspect-ratio:
+ *
+ * Requests the video sink to enforce the video display aspect ratio.
+ *
+ * Since: 0.10.37
+ */
+ g_object_class_install_property (gobject_klass, PROP_FORCE_ASPECT_RATIO,
+ g_param_spec_boolean ("force-aspect-ratio", "Force Aspect Ratio",
+ "When enabled, scaling will respect original aspect ratio", TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
g_signal_new ("reconfigure", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstPlaySinkClass,
reconfigure), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_BOOLEAN,
klass->reconfigure = GST_DEBUG_FUNCPTR (gst_play_sink_reconfigure);
klass->convert_sample = GST_DEBUG_FUNCPTR (gst_play_sink_convert_sample);
+
+ _playsink_reset_segment_event_marker_id =
+ g_quark_from_static_string ("gst-playsink-reset-segment-event-marker");
+
+ g_type_class_ref (GST_TYPE_STREAM_SYNCHRONIZER);
+ g_type_class_ref (GST_TYPE_COLOR_BALANCE_CHANNEL);
}
static void
playsink->subtitle_encoding = NULL;
playsink->flags = DEFAULT_FLAGS;
playsink->send_event_mode = MODE_DEFAULT;
+ playsink->force_aspect_ratio = TRUE;
playsink->stream_synchronizer =
g_object_new (GST_TYPE_STREAM_SYNCHRONIZER, NULL);
goto done;
/* unlink the old plugin and unghost the pad */
- gst_pad_unlink (chain->blockpad, chain->vissinkpad);
+ gst_pad_unlink (chain->vispeerpad, chain->vissinkpad);
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (chain->srcpad), NULL);
/* set the old plugin to NULL and remove */
chain->vissrcpad = gst_element_get_static_pad (chain->vis, "src");
/* link pads */
- gst_pad_link_full (chain->blockpad, chain->vissinkpad,
+ gst_pad_link_full (chain->vispeerpad, chain->vissinkpad,
GST_PAD_LINK_CHECK_NOTHING);
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (chain->srcpad),
chain->vissrcpad);
if (playsink->async_pending) {
GST_INFO_OBJECT (playsink, "Sending async_done message");
- message = gst_message_new_async_done (GST_OBJECT_CAST (playsink), FALSE);
+ message =
+ gst_message_new_async_done (GST_OBJECT_CAST (playsink),
+ GST_CLOCK_TIME_NONE);
GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (GST_BIN_CAST
(playsink), message);
GST_DEBUG_OBJECT (playsink, "creating deinterlace");
chain->deinterlace = gst_element_factory_make ("deinterlace", "deinterlace");
if (chain->deinterlace == NULL) {
+ chain->deinterlace =
+ gst_element_factory_make ("avdeinterlace", "deinterlace");
+ }
+ if (chain->deinterlace == NULL) {
post_missing_element_message (playsink, "deinterlace");
GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
gst_play_sink_find_property_sinks (playsink, chain->sink,
"force-aspect-ratio", G_TYPE_BOOLEAN);
if (elem)
- g_object_set (elem, "force-aspect-ratio", TRUE, NULL);
+ g_object_set (elem, "force-aspect-ratio", playsink->force_aspect_ratio,
+ NULL);
/* find ts-offset element */
gst_object_replace ((GstObject **) & chain->ts_offset, (GstObject *)
gst_object_unref (playsink->colorbalance_element);
}
playsink->colorbalance_element = find_color_balance_element (chain->sink);
+ if (playsink->colorbalance_element) {
+ g_signal_connect (playsink->colorbalance_element, "value-changed",
+ G_CALLBACK (colorbalance_value_changed_cb), playsink);
+ }
GST_OBJECT_UNLOCK (playsink);
if (!(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO)
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;
gst_play_sink_find_property_sinks (playsink, chain->sink,
"force-aspect-ratio", G_TYPE_BOOLEAN);
if (elem)
- g_object_set (elem, "force-aspect-ratio", TRUE, NULL);
+ g_object_set (elem, "force-aspect-ratio", playsink->force_aspect_ratio,
+ NULL);
GST_OBJECT_LOCK (playsink);
if (playsink->colorbalance_element) {
gst_object_unref (playsink->colorbalance_element);
}
playsink->colorbalance_element = find_color_balance_element (chain->sink);
+ if (playsink->colorbalance_element) {
+ g_signal_connect (playsink->colorbalance_element, "value-changed",
+ G_CALLBACK (colorbalance_value_changed_cb), playsink);
+ }
GST_OBJECT_UNLOCK (playsink);
if (chain->conv) {
return TRUE;
}
+static void
+_generate_update_newsegment_event (GstPad * pad, GstSegment * segment,
+ GstEvent ** event1)
+{
+ GstEvent *event;
+ GstStructure *structure;
+ event = gst_event_new_segment (segment);
+ structure = gst_event_writable_structure (event);
+ gst_structure_id_set (structure,
+ _playsink_reset_segment_event_marker_id, G_TYPE_BOOLEAN, TRUE, NULL);
+ *event1 = event;
+}
+
+static gboolean
+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) {
+ 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);
+ 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);
+ }
+
+ GST_DEBUG_OBJECT (pad, "Forwarding event %" GST_PTR_FORMAT, event);
+ ret = gst_pad_event_default (pad, parent, gst_event_ref (event));
+
+ if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
+ const GstSegment *segment;
+
+ gst_event_parse_segment (event, &segment);
+ GST_DEBUG_OBJECT (pad, "Segment event: %" GST_SEGMENT_FORMAT, segment);
+
+ 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 %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);
+ gst_object_unref (playsink);
+ return ret;
+}
+
+static GstFlowReturn
+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));
+ GstFlowReturn ret;
+
+ GST_PLAY_SINK_LOCK (playsink);
+
+ if (*sink_pending_flush) {
+ GstEvent *event;
+ GstStructure *structure;
+
+ *sink_pending_flush = FALSE;
+
+ 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. */
+ event = gst_event_new_flush_stop (TRUE);
+ 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-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 (sink_segment->format != GST_FORMAT_UNDEFINED) {
+ GstEvent *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);
+ }
+ } else {
+ GST_PLAY_SINK_UNLOCK (playsink);
+ }
+
+ ret = gst_proxy_pad_chain_default (pad, parent, buffer);
+
+ GST_PLAY_SINK_LOCK (playsink);
+ 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;
+ }
+ GST_PLAY_SINK_UNLOCK (playsink);
+
+ gst_object_unref (playsink);
+ gst_object_unref (tbin);
+ 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)
+{
+ gboolean ret;
+ const GstStructure *structure;
+
+ GST_DEBUG_OBJECT (pad, "Got event %" GST_PTR_FORMAT, event);
+
+ structure = gst_event_get_structure (event);
+
+ if (structure &&
+ gst_structure_id_has_field (structure,
+ _playsink_reset_segment_event_marker_id)) {
+ /* the events marked with a reset segment marker
+ * are sent internally to reset the queue and
+ * must be dropped here */
+ GST_DEBUG_OBJECT (pad, "Dropping event with reset "
+ "segment marker set: %" GST_PTR_FORMAT, event);
+ ret = TRUE;
+ goto out;
+ }
+
+ ret = gst_pad_event_default (pad, parent, gst_event_ref (event));
+
+out:
+ gst_event_unref (event);
+ return ret;
+}
+
/* make an element for playback of video with subtitles embedded.
* Only used for *raw* video streams.
*
if (textsinkpad) {
chain->textsinkpad = gst_ghost_pad_new ("text_sink", textsinkpad);
gst_object_unref (textsinkpad);
+
+ gst_pad_set_event_function (chain->textsinkpad,
+ GST_DEBUG_FUNCPTR (gst_play_sink_text_sink_event));
+ gst_pad_set_chain_function (chain->textsinkpad,
+ GST_DEBUG_FUNCPTR (gst_play_sink_text_sink_chain));
+
gst_element_add_pad (chain->chain.bin, chain->textsinkpad);
}
if (srcpad) {
chain->srcpad = gst_ghost_pad_new ("src", srcpad);
gst_object_unref (srcpad);
+
+ gst_pad_set_event_function (chain->srcpad,
+ GST_DEBUG_FUNCPTR (gst_play_sink_text_src_event));
+
gst_element_add_pad (chain->chain.bin, chain->srcpad);
}
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);
gst_bin_add (bin, chain->resample);
/* this pad will be used for blocking the dataflow and switching the vis
+ * plugin, we block right after the queue, this makes it possible for the
+ * resample and convert to convert to a format supported by the new vis
* plugin */
- chain->blockpad = gst_element_get_static_pad (chain->resample, "src");
+ chain->blockpad = gst_element_get_static_pad (chain->queue, "src");
+ /* this is the pad where the vis is linked to */
+ chain->vispeerpad = gst_element_get_static_pad (chain->resample, "src");
if (playsink->visualisation) {
GST_DEBUG_OBJECT (playsink, "trying configure vis");
post_missing_element_message (playsink, "audioconvert");
GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
(_("Missing element '%s' - check your GStreamer installation."),
- "audioconvert"), ("possibly a liboil version mismatch?"));
+ "audioconvert"), ("make sure audioconvert isn't blacklisted"));
free_chain ((GstPlayChain *) chain);
return NULL;
}
* have to construct the final pipeline. Based on the flags we construct the
* final output pipelines.
*/
-gboolean
-gst_play_sink_reconfigure (GstPlaySink * playsink)
+static gboolean
+gst_play_sink_do_reconfigure (GstPlaySink * playsink)
{
GstPlayFlags flags;
gboolean need_audio, need_video, need_deinterlace, need_vis, need_text;
need_text = TRUE;
}
- GST_OBJECT_LOCK (playsink);
- if (playsink->overlay_element)
- gst_object_unref (playsink->overlay_element);
- playsink->overlay_element = NULL;
-
- if (playsink->colorbalance_element) {
- g_signal_handlers_disconnect_by_func (playsink->colorbalance_element,
- G_CALLBACK (colorbalance_value_changed_cb), playsink);
- gst_object_unref (playsink->colorbalance_element);
- }
- playsink->colorbalance_element = NULL;
- GST_OBJECT_UNLOCK (playsink);
-
if (((flags & GST_PLAY_FLAG_VIDEO)
|| (flags & GST_PLAY_FLAG_NATIVE_VIDEO)) && playsink->video_pad) {
/* we have video and we are requested to show it */
activate_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
free_chain ((GstPlayChain *) playsink->videochain);
playsink->videochain = NULL;
+
+ GST_OBJECT_LOCK (playsink);
+ if (playsink->overlay_element)
+ gst_object_unref (playsink->overlay_element);
+ playsink->overlay_element = NULL;
+
+ if (playsink->colorbalance_element) {
+ g_signal_handlers_disconnect_by_func (playsink->colorbalance_element,
+ G_CALLBACK (colorbalance_value_changed_cb), playsink);
+ gst_object_unref (playsink->colorbalance_element);
+ }
+ playsink->colorbalance_element = NULL;
+ GST_OBJECT_UNLOCK (playsink);
}
}
add_chain (GST_PLAY_CHAIN (playsink->videodeinterlacechain), TRUE);
activate_chain (GST_PLAY_CHAIN (playsink->videodeinterlacechain), TRUE);
+ gst_pad_unlink (playsink->video_srcpad_stream_synchronizer,
+ playsink->videochain->sinkpad);
gst_pad_link_full (playsink->video_srcpad_stream_synchronizer,
playsink->videodeinterlacechain->sinkpad, GST_PAD_LINK_CHECK_NOTHING);
} else {
if (!need_vis && !need_text && (!playsink->textchain
|| !playsink->text_pad)) {
GST_DEBUG_OBJECT (playsink, "ghosting video sinkpad");
+ gst_pad_unlink (playsink->video_srcpad_stream_synchronizer,
+ playsink->videochain->sinkpad);
+ if (playsink->videodeinterlacechain
+ && playsink->videodeinterlacechain->srcpad)
+ gst_pad_unlink (playsink->videodeinterlacechain->srcpad,
+ playsink->videochain->sinkpad);
if (need_deinterlace)
gst_pad_link_full (playsink->videodeinterlacechain->srcpad,
playsink->videochain->sinkpad, GST_PAD_LINK_CHECK_NOTHING);
if (playsink->video_pad)
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad), NULL);
+
+ GST_OBJECT_LOCK (playsink);
+ if (playsink->overlay_element)
+ gst_object_unref (playsink->overlay_element);
+ playsink->overlay_element = NULL;
+
+ if (playsink->colorbalance_element) {
+ g_signal_handlers_disconnect_by_func (playsink->colorbalance_element,
+ G_CALLBACK (colorbalance_value_changed_cb), playsink);
+ gst_object_unref (playsink->colorbalance_element);
+ }
+ playsink->colorbalance_element = NULL;
+ GST_OBJECT_UNLOCK (playsink);
+
}
if (need_audio) {
vchain = (GstPlayVideoChain *) playsink->videochain;
if (achain && vchain && achain->ts_offset && vchain->ts_offset) {
- g_object_set (achain->ts_offset, "ts-offset", MAX (0, -av_offset), NULL);
- g_object_set (vchain->ts_offset, "ts-offset", MAX (0, av_offset), NULL);
+ g_object_set (achain->ts_offset,
+ "ts-offset", MAX (G_GINT64_CONSTANT (0), -av_offset), NULL);
+ g_object_set (vchain->ts_offset,
+ "ts-offset", MAX (G_GINT64_CONSTANT (0), av_offset), NULL);
} else {
GST_LOG_OBJECT (playsink, "no ts_offset elements");
}
}
}
+gboolean
+gst_play_sink_reconfigure (GstPlaySink * playsink)
+{
+ GST_LOG_OBJECT (playsink, "Triggering reconfiguration");
+
+ GST_PLAY_SINK_LOCK (playsink);
+ video_set_blocked (playsink, TRUE);
+ audio_set_blocked (playsink, TRUE);
+ text_set_blocked (playsink, TRUE);
+ GST_PLAY_SINK_UNLOCK (playsink);
+
+ return TRUE;
+}
+
static GstPadProbeReturn
sinkpad_blocked_cb (GstPad * blockedpad, GstPadProbeInfo * info,
gpointer user_data)
playsink->audio_pad_raw);
}
- gst_play_sink_reconfigure (playsink);
+ gst_play_sink_do_reconfigure (playsink);
video_set_blocked (playsink, FALSE);
audio_set_blocked (playsink, FALSE);
gst_caps_unref (caps);
- if (reconfigure) {
- GST_PLAY_SINK_LOCK (playsink);
- video_set_blocked (playsink, TRUE);
- audio_set_blocked (playsink, TRUE);
- text_set_blocked (playsink, TRUE);
- GST_PLAY_SINK_UNLOCK (playsink);
- }
+ if (reconfigure)
+ gst_play_sink_reconfigure (playsink);
}
void
res = &playsink->video_pad;
g_signal_handlers_disconnect_by_func (playsink->video_pad, caps_notify_cb,
playsink);
+ video_set_blocked (playsink, FALSE);
} else if (pad == playsink->audio_pad) {
res = &playsink->audio_pad;
g_signal_handlers_disconnect_by_func (playsink->audio_pad, caps_notify_cb,
playsink);
+ audio_set_blocked (playsink, FALSE);
} else if (pad == playsink->text_pad) {
res = &playsink->text_pad;
+ text_set_blocked (playsink, FALSE);
} else {
/* try to release the given pad anyway, these could be the FLUSHING pads. */
res = &pad;
playsink = GST_PLAY_SINK (element);
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_segment_init (&playsink->text_segment, GST_FORMAT_UNDEFINED);
+
playsink->need_async_start = TRUE;
/* we want to go async to PAUSED until we managed to configure and add the
* sinks */
ret = GST_STATE_CHANGE_ASYNC;
/* block all pads here */
- GST_PLAY_SINK_LOCK (playsink);
- if (playsink->video_pad && playsink->video_block_id == 0) {
- GstPad *opad =
- GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
- (playsink->video_pad)));
- playsink->video_block_id =
- gst_pad_add_probe (opad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
- sinkpad_blocked_cb, playsink, NULL);
- PENDING_FLAG_SET (playsink, GST_PLAY_SINK_TYPE_VIDEO);
- gst_object_unref (opad);
- }
-
- if (playsink->audio_pad && playsink->audio_block_id == 0) {
- GstPad *opad =
- GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
- (playsink->audio_pad)));
- playsink->audio_block_id =
- gst_pad_add_probe (opad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
- sinkpad_blocked_cb, playsink, NULL);
- PENDING_FLAG_SET (playsink, GST_PLAY_SINK_TYPE_AUDIO);
- gst_object_unref (opad);
- }
-
- if (playsink->text_pad && playsink->text_block_id == 0) {
- GstPad *opad =
- GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
- (playsink->text_pad)));
- playsink->text_block_id =
- gst_pad_add_probe (opad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
- sinkpad_blocked_cb, playsink, NULL);
- PENDING_FLAG_SET (playsink, GST_PLAY_SINK_TYPE_TEXT);
- gst_object_unref (opad);
- }
- GST_PLAY_SINK_UNLOCK (playsink);
+ if (!gst_play_sink_reconfigure (playsink))
+ ret = GST_STATE_CHANGE_FAILURE;
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
/* unblock all pads here */
case PROP_SEND_EVENT_MODE:
playsink->send_event_mode = g_value_get_enum (value);
break;
+ case PROP_FORCE_ASPECT_RATIO:{
+ GstPlayVideoChain *chain;
+ GstElement *elem;
+
+ playsink->force_aspect_ratio = g_value_get_boolean (value);
+
+ GST_PLAY_SINK_LOCK (playsink);
+ if (playsink->videochain) {
+ chain = (GstPlayVideoChain *) playsink->videochain;
+
+ if (chain->sink) {
+ elem =
+ gst_play_sink_find_property_sinks (playsink, chain->sink,
+ "force-aspect-ratio", G_TYPE_BOOLEAN);
+
+ if (elem)
+ g_object_set (elem, "force-aspect-ratio",
+ playsink->force_aspect_ratio, NULL);
+ }
+ }
+ GST_PLAY_SINK_UNLOCK (playsink);
+ break;
+ }
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, spec);
break;
case PROP_SEND_EVENT_MODE:
g_value_set_enum (value, playsink->send_event_mode);
break;
+ case PROP_FORCE_ASPECT_RATIO:
+ g_value_set_boolean (value, playsink->force_aspect_ratio);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, spec);
break;