X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst%2Fplayback%2Fgstplaysink.c;h=475ae2fa431991325336ab4c47de82d28387542e;hb=f19acfc60b4949564f61cf5c0941ac96725974af;hp=bd66def188402593462d4fc8321549845e8b403a;hpb=4ce453de9730a2fc490343e3678a369eb663ad18;p=platform%2Fupstream%2Fgstreamer.git diff --git a/gst/playback/gstplaysink.c b/gst/playback/gstplaysink.c index bd66def..475ae2f 100644 --- a/gst/playback/gstplaysink.c +++ b/gst/playback/gstplaysink.c @@ -14,8 +14,8 @@ * * 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 @@ -133,7 +133,8 @@ typedef struct 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, */ @@ -242,6 +243,7 @@ struct _GstPlaySink 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 */ @@ -256,6 +258,25 @@ struct _GstPlaySink 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 @@ -312,6 +333,7 @@ enum PROP_AUDIO_SINK, PROP_TEXT_SINK, PROP_SEND_EVENT_MODE, + PROP_FORCE_ASPECT_RATIO, PROP_LAST }; @@ -339,6 +361,21 @@ static GstStateChangeReturn gst_play_sink_change_state (GstElement * element, 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, @@ -346,6 +383,10 @@ 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, @@ -520,6 +561,18 @@ gst_play_sink_class_init (GstPlaySinkClass * klass) 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, @@ -572,6 +625,12 @@ gst_play_sink_class_init (GstPlaySinkClass * klass) 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 @@ -589,6 +648,7 @@ gst_play_sink_init (GstPlaySink * playsink) 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); @@ -852,7 +912,7 @@ gst_play_sink_vis_blocked (GstPad * tee_pad, GstPadProbeInfo * info, 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 */ @@ -869,7 +929,7 @@ gst_play_sink_vis_blocked (GstPad * tee_pad, GstPadProbeInfo * info, 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); @@ -1189,9 +1249,10 @@ gst_play_sink_find_property (GstPlaySink * playsink, GstElement * obj, found = gst_iterator_find_custom (it, (GCompareFunc) find_property, &item, &helper); gst_iterator_free (it); - if (found) + if (found) { result = g_value_dup_object (&item); - g_value_unset (&item); + g_value_unset (&item); + } } else { if (element_has_property (obj, name, expected_type)) { result = obj; @@ -1226,7 +1287,9 @@ do_async_done (GstPlaySink * playsink) 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); @@ -1305,6 +1368,10 @@ gen_video_deinterlace_chain (GstPlaySink * playsink) 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."), @@ -1568,7 +1635,8 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) 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 *) @@ -1636,6 +1704,10 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) 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) @@ -1679,8 +1751,17 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) 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; @@ -1803,7 +1884,8 @@ setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) 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) { @@ -1812,6 +1894,10 @@ setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) 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) { @@ -1833,6 +1919,312 @@ setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) 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. * @@ -1889,7 +2281,7 @@ gen_text_chain (GstPlaySink * playsink) "queue"), ("rendering might be suboptimal")); } else { g_object_set (G_OBJECT (chain->queue), "max-size-buffers", 3, - "max-size-bytes", 0, "max-size-time", (gint64) 0, + "max-size-bytes", 0, "max-size-time", (gint64) GST_SECOND, "silent", TRUE, NULL); gst_bin_add (bin, chain->queue); } @@ -1978,7 +2370,7 @@ gen_text_chain (GstPlaySink * playsink) "queue"), ("rendering might be suboptimal")); } else { g_object_set (G_OBJECT (element), "max-size-buffers", 3, - "max-size-bytes", 0, "max-size-time", (gint64) 0, + "max-size-bytes", 0, "max-size-time", (gint64) GST_SECOND, "silent", TRUE, NULL); gst_bin_add (bin, element); if (gst_element_link_pads_full (element, "src", chain->overlay, @@ -2026,11 +2418,21 @@ gen_text_chain (GstPlaySink * playsink) 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); } @@ -2251,6 +2653,16 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw) 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); @@ -2435,8 +2847,12 @@ gen_vis_chain (GstPlaySink * playsink) 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"); @@ -2491,7 +2907,7 @@ no_audioconvert: 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; } @@ -2528,8 +2944,8 @@ link_failed: * 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; @@ -2551,19 +2967,6 @@ gst_play_sink_reconfigure (GstPlaySink * playsink) 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 */ @@ -2649,6 +3052,19 @@ gst_play_sink_reconfigure (GstPlaySink * playsink) 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); } } @@ -2692,6 +3108,8 @@ gst_play_sink_reconfigure (GstPlaySink * 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 { @@ -2709,6 +3127,12 @@ gst_play_sink_reconfigure (GstPlaySink * playsink) 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); @@ -2762,6 +3186,20 @@ gst_play_sink_reconfigure (GstPlaySink * playsink) 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) { @@ -3174,8 +3612,10 @@ update_av_offset (GstPlaySink * playsink) 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"); } @@ -3409,6 +3849,20 @@ text_set_blocked (GstPlaySink * playsink, gboolean blocked) } } +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) @@ -3455,7 +3909,7 @@ sinkpad_blocked_cb (GstPad * blockedpad, GstPadProbeInfo * info, 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); @@ -3498,13 +3952,8 @@ caps_notify_cb (GstPad * pad, GParamSpec * unused, GstPlaySink * playsink) 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 @@ -3532,7 +3981,7 @@ gst_play_sink_refresh_pad (GstPlaySink * playsink, GstPad * pad, block_id = &playsink->text_block_id; } - if (type != GST_PLAY_SINK_TYPE_FLUSHING) { + if (type != GST_PLAY_SINK_TYPE_FLUSHING && (block_id && *block_id == 0)) { GstPad *blockpad = GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD (pad))); @@ -3732,12 +4181,15 @@ gst_play_sink_release_pad (GstPlaySink * playsink, GstPad * pad) 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; @@ -3953,6 +4405,8 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition) 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 */ @@ -3960,40 +4414,8 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition) 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 */ @@ -4220,6 +4642,29 @@ gst_play_sink_set_property (GObject * object, guint prop_id, 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; @@ -4272,6 +4717,9 @@ gst_play_sink_get_property (GObject * object, guint prop_id, 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;