From: Sebastian Dröge Date: Fri, 2 Mar 2012 09:00:55 +0000 (+0100) Subject: Merge branch 'master' into 0.11 X-Git-Tag: 1.19.3~511^2~6734 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f7939bb43fca241472a61d394f2457f5978dd5ab;p=platform%2Fupstream%2Fgstreamer.git Merge branch 'master' into 0.11 Conflicts: NEWS RELEASE configure.ac docs/plugins/gst-plugins-base-plugins.args docs/plugins/gst-plugins-base-plugins.hierarchy docs/plugins/gst-plugins-base-plugins.interfaces docs/plugins/inspect/plugin-adder.xml docs/plugins/inspect/plugin-alsa.xml docs/plugins/inspect/plugin-app.xml docs/plugins/inspect/plugin-audioconvert.xml docs/plugins/inspect/plugin-audiorate.xml docs/plugins/inspect/plugin-audioresample.xml docs/plugins/inspect/plugin-audiotestsrc.xml docs/plugins/inspect/plugin-cdparanoia.xml docs/plugins/inspect/plugin-encoding.xml docs/plugins/inspect/plugin-ffmpegcolorspace.xml docs/plugins/inspect/plugin-gdp.xml docs/plugins/inspect/plugin-gio.xml docs/plugins/inspect/plugin-gnomevfs.xml docs/plugins/inspect/plugin-libvisual.xml docs/plugins/inspect/plugin-ogg.xml docs/plugins/inspect/plugin-pango.xml docs/plugins/inspect/plugin-playback.xml docs/plugins/inspect/plugin-subparse.xml docs/plugins/inspect/plugin-tcp.xml docs/plugins/inspect/plugin-theora.xml docs/plugins/inspect/plugin-typefindfunctions.xml docs/plugins/inspect/plugin-uridecodebin.xml docs/plugins/inspect/plugin-videorate.xml docs/plugins/inspect/plugin-videoscale.xml docs/plugins/inspect/plugin-videotestsrc.xml docs/plugins/inspect/plugin-volume.xml docs/plugins/inspect/plugin-vorbis.xml docs/plugins/inspect/plugin-ximagesink.xml docs/plugins/inspect/plugin-xvimagesink.xml gst-libs/gst/app/gstappsink.c gst-libs/gst/audio/mixer.c gst-libs/gst/audio/mixer.h gst-libs/gst/tag/gstxmptag.c gst-libs/gst/video/colorbalance.c gst-libs/gst/video/colorbalance.h gst/adder/gstadder.c gst/playback/gstplaybasebin.c gst/playback/gstplaybin2.c gst/playback/gstplaysink.c gst/videoscale/gstvideoscale.c tests/check/elements/videoscale.c tests/examples/seek/seek.c tests/examples/v4l/probe.c win32/common/_stdint.h win32/common/audio-enumtypes.c win32/common/config.h --- f7939bb43fca241472a61d394f2457f5978dd5ab diff --cc gst-libs/gst/app/gstappsink.c index 5239e82,871d6f0..25c95eb --- a/gst-libs/gst/app/gstappsink.c +++ b/gst-libs/gst/app/gstappsink.c @@@ -158,12 -158,17 +158,13 @@@ static gboolean gst_app_sink_unlock_sto static gboolean gst_app_sink_start (GstBaseSink * psink); static gboolean gst_app_sink_stop (GstBaseSink * psink); static gboolean gst_app_sink_event (GstBaseSink * sink, GstEvent * event); + static gboolean gst_app_sink_query (GstBaseSink * bsink, GstQuery * query); static GstFlowReturn gst_app_sink_preroll (GstBaseSink * psink, GstBuffer * buffer); -static GstFlowReturn gst_app_sink_render_common (GstBaseSink * psink, - GstMiniObject * data, gboolean is_list); static GstFlowReturn gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer); -static GstFlowReturn gst_app_sink_render_list (GstBaseSink * psink, - GstBufferList * list); -static GstCaps *gst_app_sink_getcaps (GstBaseSink * psink); -static GstMiniObject *gst_app_sink_pull_object (GstAppSink * appsink); +static gboolean gst_app_sink_setcaps (GstBaseSink * sink, GstCaps * caps); +static GstCaps *gst_app_sink_getcaps (GstBaseSink * psink, GstCaps * filter); static guint gst_app_sink_signals[LAST_SIGNAL] = { 0 }; @@@ -335,11 -435,13 +336,12 @@@ gst_app_sink_class_init (GstAppSinkClas basesink_class->event = gst_app_sink_event; basesink_class->preroll = gst_app_sink_preroll; basesink_class->render = gst_app_sink_render; - basesink_class->render_list = gst_app_sink_render_list; basesink_class->get_caps = gst_app_sink_getcaps; + basesink_class->set_caps = gst_app_sink_setcaps; + basesink_class->query = gst_app_sink_query; klass->pull_preroll = gst_app_sink_pull_preroll; - klass->pull_buffer = gst_app_sink_pull_buffer; - klass->pull_buffer_list = gst_app_sink_pull_buffer_list; + klass->pull_sample = gst_app_sink_pull_sample; g_type_class_add_private (klass, sizeof (GstAppSinkPrivate)); } @@@ -774,6 -877,79 +776,30 @@@ gst_app_sink_getcaps (GstBaseSink * psi return caps; } + static gboolean + gst_app_sink_query (GstBaseSink * bsink, GstQuery * query) + { + gboolean ret; + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_SEEKING:{ + GstFormat fmt; + + /* we don't supporting seeking */ + gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL); + gst_query_set_seeking (query, fmt, FALSE, 0, -1); + ret = TRUE; + break; + } + + default: + ret = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query); + break; + } + + return ret; + } + -static GstMiniObject * -gst_app_sink_pull_object (GstAppSink * appsink) -{ - GstMiniObject *obj = NULL; - GstAppSinkPrivate *priv; - - g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL); - - priv = appsink->priv; - - g_mutex_lock (priv->mutex); - - while (TRUE) { - GST_DEBUG_OBJECT (appsink, "trying to grab a buffer/list"); - if (!priv->started) - goto not_started; - - if (!g_queue_is_empty (priv->queue)) - break; - - if (priv->is_eos) - goto eos; - - /* nothing to return, wait */ - GST_DEBUG_OBJECT (appsink, "waiting for a buffer/list"); - g_cond_wait (priv->cond, priv->mutex); - } - obj = g_queue_pop_head (priv->queue); - GST_DEBUG_OBJECT (appsink, "we have a buffer/list %p", obj); - g_cond_signal (priv->cond); - g_mutex_unlock (priv->mutex); - - return obj; - - /* special conditions */ -eos: - { - GST_DEBUG_OBJECT (appsink, "we are EOS, return NULL"); - g_mutex_unlock (priv->mutex); - return NULL; - } -not_started: - { - GST_DEBUG_OBJECT (appsink, "we are stopped, return NULL"); - g_mutex_unlock (priv->mutex); - return NULL; - } -} - /* external API */ /** diff --cc gst-libs/gst/audio/mixer.c index 0fca9a8,5b8aeed..4c52b25 --- a/gst-libs/gst/audio/mixer.c +++ b/gst-libs/gst/audio/mixer.c @@@ -81,18 -94,58 +81,17 @@@ gst_mixer_get_type (void } static void -gst_mixer_class_init (GstMixerClass * klass) +gst_mixer_class_init (GstMixerInterface * iface) { - iface->mixer_type = GST_MIXER_SOFTWARE; -#ifndef GST_DISABLE_DEPRECATED - static gboolean initialized = FALSE; - - /* signals (deprecated) */ - if (!initialized) { - gst_mixer_signals[SIGNAL_RECORD_TOGGLED] = - g_signal_new ("record-toggled", - GST_TYPE_MIXER, G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstMixerClass, record_toggled), - NULL, NULL, - gst_interfaces_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 2, - GST_TYPE_MIXER_TRACK, G_TYPE_BOOLEAN); - gst_mixer_signals[SIGNAL_MUTE_TOGGLED] = - g_signal_new ("mute-toggled", - GST_TYPE_MIXER, G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstMixerClass, mute_toggled), - NULL, NULL, - gst_interfaces_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 2, - GST_TYPE_MIXER_TRACK, G_TYPE_BOOLEAN); - gst_mixer_signals[SIGNAL_VOLUME_CHANGED] = - g_signal_new ("volume-changed", - GST_TYPE_MIXER, G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstMixerClass, volume_changed), - NULL, NULL, - gst_interfaces_marshal_VOID__OBJECT_POINTER, G_TYPE_NONE, 2, - GST_TYPE_MIXER_TRACK, G_TYPE_POINTER); - gst_mixer_signals[SIGNAL_OPTION_CHANGED] = - g_signal_new ("option-changed", - GST_TYPE_MIXER, G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstMixerClass, option_changed), - NULL, NULL, - gst_interfaces_marshal_VOID__OBJECT_STRING, G_TYPE_NONE, 2, - GST_TYPE_MIXER_OPTIONS, G_TYPE_STRING); - - initialized = TRUE; - } -#endif - -#ifndef GST_REMOVE_DEPRECATED - klass->mixer_type = GST_MIXER_SOFTWARE; -#endif -- /* default virtual functions */ - klass->list_tracks = NULL; - klass->set_volume = NULL; - klass->get_volume = NULL; - klass->set_mute = NULL; - klass->set_record = NULL; - klass->set_option = NULL; - klass->get_option = NULL; ++ iface->get_mixer_type = NULL; + iface->list_tracks = NULL; + iface->set_volume = NULL; + iface->get_volume = NULL; + iface->set_mute = NULL; + iface->set_record = NULL; + iface->set_option = NULL; + iface->get_option = NULL; } /** @@@ -302,9 -355,16 +301,10 @@@ gst_mixer_get_option (GstMixer * mixer GstMixerType gst_mixer_get_mixer_type (GstMixer * mixer) { - GstMixerClass *klass = GST_MIXER_GET_CLASS (mixer); + GstMixerInterface *iface = GST_MIXER_GET_INTERFACE (mixer); - return iface->mixer_type; - if (klass->get_mixer_type) - return klass->get_mixer_type (mixer); - -#ifndef GST_REMOVE_DEPRECATED - return klass->mixer_type; -#else - g_return_if_reached (GST_MIXER_TYPE_SOFTWARE); -#endif ++ g_return_val_if_fail (iface->get_mixer_type != NULL, GST_MIXER_SOFTWARE); ++ return iface->get_mixer_type (mixer); } /** diff --cc gst-libs/gst/audio/mixer.h index 2cb618b,491c14c..1de602d --- a/gst-libs/gst/audio/mixer.h +++ b/gst-libs/gst/audio/mixer.h @@@ -31,16 -32,20 +31,14 @@@ G_BEGIN_DECL #define GST_TYPE_MIXER \ (gst_mixer_get_type ()) #define GST_MIXER(obj) \ - (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MIXER, GstMixer)) -#define GST_MIXER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MIXER, GstMixerClass)) + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MIXER, GstMixer)) #define GST_IS_MIXER(obj) \ - (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MIXER)) -#define GST_IS_MIXER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MIXER)) -#define GST_MIXER_GET_CLASS(inst) \ - (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_MIXER, GstMixerClass)) - -#define GST_MIXER_TYPE(klass) (klass->mixer_type) + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MIXER)) +#define GST_MIXER_GET_INTERFACE(inst) \ + (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_MIXER, GstMixerInterface)) - #define GST_MIXER_TYPE(iface) (iface->mixer_type) - typedef struct _GstMixer GstMixer; -typedef struct _GstMixerClass GstMixerClass; +typedef struct _GstMixerInterface GstMixerInterface; /** * GstMixerType: @@@ -109,11 -114,14 +107,9 @@@ typedef enu GST_MIXER_FLAG_GROUPING = (1<<2), } GstMixerFlags; -struct _GstMixerClass { - GTypeInterface klass; - -/* FIXME 0.11: Remove this */ -#ifndef GST_REMOVE_DEPRECATED - GstMixerType mixer_type; -#endif +struct _GstMixerInterface { + GTypeInterface iface; - GstMixerType mixer_type; - /* virtual functions */ const GList * (* list_tracks) (GstMixer *mixer); @@@ -130,13 -138,41 +126,15 @@@ void (* set_record) (GstMixer *mixer, GstMixerTrack *track, gboolean record); -#ifndef GST_DISABLE_DEPRECATED - /* signals (deprecated) */ - void (* mute_toggled) (GstMixer *mixer, - GstMixerTrack *channel, - gboolean mute); - void (* record_toggled) (GstMixer *mixer, - GstMixerTrack *channel, - gboolean record); - void (* volume_changed) (GstMixer *mixer, - GstMixerTrack *channel, - gint *volumes); -#else - gpointer padding1[3]; -#endif /* not GST_DISABLE_DEPRECATED */ - - void (* set_option) (GstMixer *mixer, + void (* set_option) (GstMixer *mixer, GstMixerOptions *opts, gchar *value); - const gchar * (* get_option) (GstMixer *mixer, + const gchar * (* get_option) (GstMixer *mixer, GstMixerOptions *opts); -#ifndef GST_DISABLE_DEPRECATED - void (* option_changed) (GstMixer *mixer, - GstMixerOptions *opts, - gchar *option); -#else - gpointer padding2; -#endif /* not GST_DISABLE_DEPRECATED */ - GstMixerFlags (* get_mixer_flags) (GstMixer *mixer); + + GstMixerType (* get_mixer_type) (GstMixer *mixer); - - /*< private >*/ - gpointer _gst_reserved[GST_PADDING-2]; }; GType gst_mixer_get_type (void); diff --cc gst-libs/gst/interfaces/navigation.h index 40cfff9,4b21441..6bbe010 --- a/gst-libs/gst/interfaces/navigation.h +++ b/gst-libs/gst/interfaces/navigation.h @@@ -41,13 -41,13 +41,13 @@@ typedef struct _GstNavigationInterface /** * GstNavigationInterface: - * @g_iface: the parent interface + * @iface: the parent interface * @send_event: sending a navigation event * - * Color-balance interface. + * Navigation interface. */ struct _GstNavigationInterface { - GTypeInterface g_iface; + GTypeInterface iface; /* virtual functions */ void (*send_event) (GstNavigation *navigation, GstStructure *structure); diff --cc gst-libs/gst/video/colorbalance.c index a73c7d7,464d737..57a4de4 --- a/gst-libs/gst/video/colorbalance.c +++ b/gst-libs/gst/video/colorbalance.c @@@ -105,13 -102,15 +105,12 @@@ gst_color_balance_class_init (GstColorB initialized = TRUE; } -#ifndef GST_REMOVE_DEPRECATED - klass->balance_type = GST_COLOR_BALANCE_SOFTWARE; -#endif - iface->balance_type = GST_COLOR_BALANCE_SOFTWARE; - /* default virtual functions */ - klass->list_channels = NULL; - klass->set_value = NULL; - klass->get_value = NULL; - klass->get_balance_type = NULL; + iface->list_channels = NULL; + iface->set_value = NULL; + iface->get_value = NULL; ++ iface->get_balance_type = NULL; } /** @@@ -213,9 -212,16 +212,12 @@@ gst_color_balance_get_balance_type (Gst g_return_val_if_fail (GST_IS_COLOR_BALANCE (balance), GST_COLOR_BALANCE_SOFTWARE); - klass = GST_COLOR_BALANCE_GET_CLASS (balance); + iface = GST_COLOR_BALANCE_GET_INTERFACE (balance); - return iface->balance_type; - if (klass->get_balance_type) - return klass->get_balance_type (balance); ++ g_return_val_if_fail (iface->get_balance_type != NULL, ++ GST_COLOR_BALANCE_SOFTWARE); + -#ifndef GST_REMOVE_DEPRECATED - return klass->balance_type; -#else - g_return_val_if_reached (GST_COLOR_BALANCE_SOFTWARE); -#endif ++ return iface->get_balance_type (balance); } /** diff --cc gst-libs/gst/video/colorbalance.h index 8cc4276,9f0a1cd..7f43b0d --- a/gst-libs/gst/video/colorbalance.h +++ b/gst-libs/gst/video/colorbalance.h @@@ -30,16 -31,22 +30,14 @@@ G_BEGIN_DECL #define GST_TYPE_COLOR_BALANCE \ (gst_color_balance_get_type ()) #define GST_COLOR_BALANCE(obj) \ - (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_COLOR_BALANCE, \ - GstColorBalance)) -#define GST_COLOR_BALANCE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_COLOR_BALANCE, \ - GstColorBalanceClass)) + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_COLOR_BALANCE, GstColorBalance)) #define GST_IS_COLOR_BALANCE(obj) \ - (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_COLOR_BALANCE)) -#define GST_IS_COLOR_BALANCE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_COLOR_BALANCE)) -#define GST_COLOR_BALANCE_GET_CLASS(inst) \ - (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_COLOR_BALANCE, GstColorBalanceClass)) - -#define GST_COLOR_BALANCE_TYPE(klass) (klass->balance_type) + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_COLOR_BALANCE)) +#define GST_COLOR_BALANCE_GET_INTERFACE(inst) \ + (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_COLOR_BALANCE, GstColorBalanceInterface)) - #define GST_COLOR_BALANCE_TYPE(iface) (iface->balance_type) - typedef struct _GstColorBalance GstColorBalance; -typedef struct _GstColorBalanceClass GstColorBalanceClass; +typedef struct _GstColorBalanceInterface GstColorBalanceInterface; /** * GstColorBalanceType: @@@ -70,11 -77,14 +68,9 @@@ typedef enu * * Color-balance interface. */ -struct _GstColorBalanceClass { - GTypeInterface klass; - -/* FIXME 0.11: Remove this */ -#ifndef GST_REMOVE_DEPRECATED - GstColorBalanceType balance_type; -#endif +struct _GstColorBalanceInterface { + GTypeInterface iface; - GstColorBalanceType balance_type; - /* virtual functions */ const GList * (* list_channels) (GstColorBalance *balance); @@@ -83,11 -93,16 +79,15 @@@ gint value); gint (* get_value) (GstColorBalance *balance, GstColorBalanceChannel *channel); ++ GstColorBalanceType (*get_balance_type) (GstColorBalance *balance); /* signals */ void (* value_changed) (GstColorBalance *balance, GstColorBalanceChannel *channel, gint value); + - GstColorBalanceType (*get_balance_type) (GstColorBalance *balance); - + /*< private >*/ + gpointer _gst_reserved[GST_PADDING-1]; }; GType gst_color_balance_get_type (void); diff --cc gst/adder/gstadder.c index 1256777,8910d6c..0e8af87 --- a/gst/adder/gstadder.c +++ b/gst/adder/gstadder.c @@@ -108,19 -129,14 +108,19 @@@ static void gst_adder_set_property (GOb static void gst_adder_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static gboolean gst_adder_setcaps (GstPad * pad, GstCaps * caps); -static gboolean gst_adder_query (GstPad * pad, GstQuery * query); -static gboolean gst_adder_src_event (GstPad * pad, GstEvent * event); +static gboolean gst_adder_setcaps (GstAdder * adder, GstPad * pad, + GstCaps * caps); +static gboolean gst_adder_src_query (GstPad * pad, GstObject * parent, + GstQuery * query); +static gboolean gst_adder_sink_query (GstPad * pad, GstObject * parent, + GstQuery * query); +static gboolean gst_adder_src_event (GstPad * pad, GstObject * parent, + GstEvent * event); - static gboolean gst_adder_sink_event (GstPad * pad, GstObject * parent, - GstEvent * event); + static gboolean gst_adder_sink_event (GstCollectPads2 * pads, + GstCollectData2 * pad, GstEvent * event, gpointer user_data); static GstPad *gst_adder_request_new_pad (GstElement * element, - GstPadTemplate * temp, const gchar * unused); + GstPadTemplate * temp, const gchar * unused, const GstCaps * caps); static void gst_adder_release_pad (GstElement * element, GstPad * pad); static GstStateChangeReturn gst_adder_change_state (GstElement * element, @@@ -763,67 -746,76 +763,75 @@@ done } static gboolean - gst_adder_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) + gst_adder_sink_event (GstCollectPads2 * pads, GstCollectData2 * pad, + GstEvent * event, gpointer user_data) { - GstAdder *adder; - gboolean ret = TRUE; - - adder = GST_ADDER (parent); + GstAdder *adder = GST_ADDER (user_data); + gboolean res = FALSE; - GST_DEBUG_OBJECT (pad, "Got %s event on sink pad", - GST_DEBUG_OBJECT (pad->pad, "Got %s event on sink pad from %s", - GST_EVENT_TYPE_NAME (event), GST_OBJECT_NAME (GST_EVENT_SRC (event))); ++ GST_DEBUG_OBJECT (pad->pad, "Got %s event on sink pad", + GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_START: - /* drop flush start events, as we forwarded one already when handing the - * flushing seek on the sink pad */ + case GST_EVENT_CAPS: + { + GstCaps *caps; + + gst_event_parse_caps (event, &caps); - ret = gst_adder_setcaps (adder, pad, caps); ++ res = gst_adder_setcaps (adder, pad->pad, caps); gst_event_unref (event); - res = TRUE; + - goto beach; ++ break; + } ++ case GST_EVENT_FLUSH_START: ++ res = gst_pad_event_default (pad->pad, GST_OBJECT (adder), event); + break; case GST_EVENT_FLUSH_STOP: - /* we received a flush-stop. The collect_event function will call the - * gst_adder_event function we have set on the GstCollectPads2, so we - * have control over whether the event is sent past our element. - * We will only forward it when flush_stop_pending is set, and we will - * unset it then. + /* we received a flush-stop. We will only forward it when + * flush_stop_pending is set, and we will unset it then. */ - GST_COLLECT_PADS2_STREAM_LOCK (adder->collect); - g_atomic_int_set (&adder->new_segment_pending, TRUE); + if (g_atomic_int_compare_and_exchange (&adder->flush_stop_pending, + TRUE, FALSE)) { + g_atomic_int_set (&adder->new_segment_pending, TRUE); + GST_DEBUG_OBJECT (pad->pad, "forwarding flush stop"); + } else { + gst_event_unref (event); + res = TRUE; + GST_DEBUG_OBJECT (pad->pad, "eating flush stop"); + } /* Clear pending tags */ if (adder->pending_events) { g_list_foreach (adder->pending_events, (GFunc) gst_event_unref, NULL); g_list_free (adder->pending_events); adder->pending_events = NULL; } - GST_COLLECT_PADS2_STREAM_UNLOCK (adder->collect); ++ res = gst_pad_event_default (pad->pad, GST_OBJECT (adder), event); break; case GST_EVENT_TAG: - GST_COLLECT_PADS2_STREAM_LOCK (adder->collect); /* collect tags here so we can push them out when we collect data */ adder->pending_events = g_list_append (adder->pending_events, event); - GST_COLLECT_PADS2_STREAM_UNLOCK (adder->collect); - goto beach; + res = TRUE; + break; - case GST_EVENT_NEWSEGMENT: + case GST_EVENT_SEGMENT: if (g_atomic_int_compare_and_exchange (&adder->wait_for_new_segment, TRUE, FALSE)) { /* make sure we push a new segment, to inform about new basetime * see FIXME in gst_adder_collected() */ g_atomic_int_set (&adder->new_segment_pending, TRUE); } + gst_event_unref (event); + res = TRUE; + break; ++ case GST_EVENT_EOS: ++ gst_event_unref (event); ++ res = TRUE; + break; default: ++ res = gst_pad_event_default (pad->pad, GST_OBJECT (adder), event); break; } - return res; -} - -static void -gst_adder_base_init (gpointer g_class) -{ - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); - /* now GstCollectPads2 can take care of the rest, e.g. EOS */ - ret = adder->collect_event (pad, parent, event); - - beach: - return ret; - gst_element_class_add_static_pad_template (gstelement_class, - &gst_adder_src_template); - gst_element_class_add_static_pad_template (gstelement_class, - &gst_adder_sink_template); - gst_element_class_set_details_simple (gstelement_class, "Adder", - "Generic/Audio", - "Add N audio channels together", - "Thomas Vander Stichele "); ++ return res; } static void @@@ -989,15 -979,11 +997,9 @@@ gst_adder_request_new_pad (GstElement GST_DEBUG_OBJECT (adder, "request new pad %s", name); g_free (name); - gst_pad_set_getcaps_function (newpad, - GST_DEBUG_FUNCPTR (gst_adder_sink_getcaps)); - gst_pad_set_setcaps_function (newpad, GST_DEBUG_FUNCPTR (gst_adder_setcaps)); + gst_pad_set_query_function (newpad, GST_DEBUG_FUNCPTR (gst_adder_sink_query)); gst_collect_pads2_add_pad (adder->collect, newpad, sizeof (GstCollectData2)); - /* FIXME: hacked way to override/extend the event function of - * GstCollectPads2; because it sets its own event function giving the - * element no access to events */ - adder->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad); - gst_pad_set_event_function (newpad, GST_DEBUG_FUNCPTR (gst_adder_sink_event)); - /* takes ownership of the pad */ if (!gst_element_add_pad (GST_ELEMENT (adder), newpad)) goto could_not_add; @@@ -1292,32 -1275,7 +1294,6 @@@ eos } } - static gboolean - gst_adder_event (GstCollectPads2 * pads, GstCollectData2 * pad, - GstEvent * event, gpointer user_data) - { - GstAdder *adder = GST_ADDER (user_data); - if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) { - if (g_atomic_int_compare_and_exchange (&adder->flush_stop_pending, - TRUE, FALSE)) { - - return gst_pad_event_default (pad->pad, GST_OBJECT (user_data), event); - } else { - gst_event_unref (event); - return TRUE; - } - } else { - if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT || - GST_EVENT_TYPE (event) == GST_EVENT_CAPS || - GST_EVENT_TYPE (event) == GST_EVENT_EOS) { - gst_event_unref (event); - return TRUE; - } else { - return gst_pad_event_default (pad->pad, GST_OBJECT (user_data), event); - } - } - } -- static GstStateChangeReturn gst_adder_change_state (GstElement * element, GstStateChange transition) { diff --cc gst/adder/gstadder.h index d5ce7ef,3895118..9fedf06 --- a/gst/adder/gstadder.h +++ b/gst/adder/gstadder.h @@@ -65,8 -82,11 +65,7 @@@ struct _GstAdder gint64 offset; /* sink event handling */ -- GstPadEventFunction collect_event; GstSegment segment; - guint64 segment_start, segment_end; - gdouble segment_rate; volatile gboolean new_segment_pending; volatile gboolean wait_for_new_segment; /* src event handling */ diff --cc gst/playback/gstplaybin2.c index f243c2a,0ed8b3a..c0f1da7 --- a/gst/playback/gstplaybin2.c +++ b/gst/playback/gstplaybin2.c @@@ -169,7 -172,7 +169,7 @@@ * Embedding the video window in your application * By default, playbin (or rather the video sinks used) will create their own * window. Applications will usually want to force output to a window of their -- * own, however. This can be done using the #GstXOverlay interface, which most ++ * own, however. This can be done using the #GstVideoOverlay interface, which most * video sinks implement. See the documentation there for more details. * * @@@ -228,16 -231,19 +228,16 @@@ #include #include -#include -#include +#include - ++#include + #include -#include - ++#include #include "gstplay-enum.h" #include "gstplay-marshal.h" #include "gstplayback.h" #include "gstplaysink.h" #include "gstsubtitleoverlay.h" -- #include "gst/glib-compat-private.h" -- GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug); #define GST_CAT_DEFAULT gst_play_bin_debug @@@ -580,6 -583,15 +580,12 @@@ if (id) id = 0; \ } -static void gst_play_bin_implements_interface_init (gpointer g_iface, - gpointer g_iface_data); -static void gst_play_bin_xoverlay_init (gpointer g_iface, - gpointer g_iface_data); ++static void gst_play_bin_overlay_init (gpointer g_iface, gpointer g_iface_data); + static void gst_play_bin_navigation_init (gpointer g_iface, + gpointer g_iface_data); + static void gst_play_bin_colorbalance_init (gpointer g_iface, + gpointer g_iface_data); + static GType gst_play_bin_get_type (void) { @@@ -601,12 -613,36 +607,30 @@@ static const GInterfaceInfo svol_info = { NULL, NULL, NULL }; - static const GInterfaceInfo xov_info = { - gst_play_bin_xoverlay_init, ++ static const GInterfaceInfo ov_info = { ++ gst_play_bin_overlay_init, + NULL, NULL + }; + static const GInterfaceInfo nav_info = { + gst_play_bin_navigation_init, + NULL, NULL + }; + static const GInterfaceInfo col_info = { + gst_play_bin_colorbalance_init, + NULL, NULL + }; gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE, - "GstPlayBin2", &gst_play_bin_info, 0); + "GstPlayBin", &gst_play_bin_info, 0); - g_type_add_interface_static (gst_play_bin_type, - GST_TYPE_IMPLEMENTS_INTERFACE, &impl_info); g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME, &svol_info); - g_type_add_interface_static (gst_play_bin_type, GST_TYPE_X_OVERLAY, - &xov_info); ++ g_type_add_interface_static (gst_play_bin_type, GST_TYPE_VIDEO_OVERLAY, ++ &ov_info); + g_type_add_interface_static (gst_play_bin_type, GST_TYPE_NAVIGATION, + &nav_info); + g_type_add_interface_static (gst_play_bin_type, GST_TYPE_COLOR_BALANCE, + &col_info); } return gst_play_bin_type; @@@ -1257,10 -1299,11 +1288,11 @@@ gst_play_bin_init (GstPlayBin * playbin init_group (playbin, &playbin->groups[1]); /* first filter out the interesting element factories */ - playbin->elements_lock = g_mutex_new (); + g_mutex_init (&playbin->elements_lock); /* add sink */ - playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL); + playbin->playsink = + g_object_new (GST_TYPE_PLAY_SINK, "name", "playsink", NULL); gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink)); gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS); /* Connect to notify::volume and notify::mute signals for proxying */ @@@ -4026,6 -4065,137 +4060,121 @@@ failure } } + static void -gst_play_bin_xoverlay_expose (GstXOverlay * overlay) ++gst_play_bin_overlay_expose (GstVideoOverlay * overlay) + { + GstPlayBin *playbin = GST_PLAY_BIN (overlay); + - gst_x_overlay_expose (GST_X_OVERLAY (playbin->playsink)); ++ gst_video_overlay_expose (GST_VIDEO_OVERLAY (playbin->playsink)); + } + + static void -gst_play_bin_xoverlay_handle_events (GstXOverlay * overlay, ++gst_play_bin_overlay_handle_events (GstVideoOverlay * overlay, + gboolean handle_events) + { + GstPlayBin *playbin = GST_PLAY_BIN (overlay); + - gst_x_overlay_handle_events (GST_X_OVERLAY (playbin->playsink), ++ gst_video_overlay_handle_events (GST_VIDEO_OVERLAY (playbin->playsink), + handle_events); + } + + static void -gst_play_bin_xoverlay_set_render_rectangle (GstXOverlay * overlay, gint x, ++gst_play_bin_overlay_set_render_rectangle (GstVideoOverlay * overlay, gint x, + gint y, gint width, gint height) + { + GstPlayBin *playbin = GST_PLAY_BIN (overlay); + - gst_x_overlay_set_render_rectangle (GST_X_OVERLAY (playbin->playsink), x, y, - width, height); ++ gst_video_overlay_set_render_rectangle (GST_VIDEO_OVERLAY (playbin->playsink), ++ x, y, width, height); + } + + static void -gst_play_bin_xoverlay_set_window_handle (GstXOverlay * overlay, guintptr handle) ++gst_play_bin_overlay_set_window_handle (GstVideoOverlay * overlay, ++ guintptr handle) + { + GstPlayBin *playbin = GST_PLAY_BIN (overlay); + - gst_x_overlay_set_window_handle (GST_X_OVERLAY (playbin->playsink), handle); -} - -static void -gst_play_bin_xoverlay_init (gpointer g_iface, gpointer g_iface_data) -{ - GstXOverlayClass *iface = (GstXOverlayClass *) g_iface; - iface->expose = gst_play_bin_xoverlay_expose; - iface->handle_events = gst_play_bin_xoverlay_handle_events; - iface->set_render_rectangle = gst_play_bin_xoverlay_set_render_rectangle; - iface->set_window_handle = gst_play_bin_xoverlay_set_window_handle; -} - -static gboolean -gst_play_bin_implements_interface_supported (GstImplementsInterface * iface, - GType type) -{ - if (type == GST_TYPE_X_OVERLAY || type == GST_TYPE_STREAM_VOLUME || - type == GST_TYPE_NAVIGATION || type == GST_TYPE_COLOR_BALANCE) - return TRUE; - else - return FALSE; ++ gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (playbin->playsink), ++ handle); + } + + static void -gst_play_bin_implements_interface_init (gpointer g_iface, gpointer g_iface_data) ++gst_play_bin_overlay_init (gpointer g_iface, gpointer g_iface_data) + { - GstImplementsInterfaceClass *iface = (GstImplementsInterfaceClass *) g_iface; - iface->supported = gst_play_bin_implements_interface_supported; ++ GstVideoOverlayInterface *iface = (GstVideoOverlayInterface *) g_iface; ++ iface->expose = gst_play_bin_overlay_expose; ++ iface->handle_events = gst_play_bin_overlay_handle_events; ++ iface->set_render_rectangle = gst_play_bin_overlay_set_render_rectangle; ++ iface->set_window_handle = gst_play_bin_overlay_set_window_handle; + } + + static void + gst_play_bin_navigation_send_event (GstNavigation * navigation, + GstStructure * structure) + { + GstPlayBin *playbin = GST_PLAY_BIN (navigation); + + gst_navigation_send_event (GST_NAVIGATION (playbin->playsink), structure); + } + + static void + gst_play_bin_navigation_init (gpointer g_iface, gpointer g_iface_data) + { + GstNavigationInterface *iface = (GstNavigationInterface *) g_iface; + + iface->send_event = gst_play_bin_navigation_send_event; + } + + static const GList * + gst_play_bin_colorbalance_list_channels (GstColorBalance * balance) + { + GstPlayBin *playbin = GST_PLAY_BIN (balance); + + return + gst_color_balance_list_channels (GST_COLOR_BALANCE (playbin->playsink)); + } + + static void + gst_play_bin_colorbalance_set_value (GstColorBalance * balance, + GstColorBalanceChannel * channel, gint value) + { + GstPlayBin *playbin = GST_PLAY_BIN (balance); + + gst_color_balance_set_value (GST_COLOR_BALANCE (playbin->playsink), channel, + value); + } + + static gint + gst_play_bin_colorbalance_get_value (GstColorBalance * balance, + GstColorBalanceChannel * channel) + { + GstPlayBin *playbin = GST_PLAY_BIN (balance); + + return gst_color_balance_get_value (GST_COLOR_BALANCE (playbin->playsink), + channel); + } + + static GstColorBalanceType + gst_play_bin_colorbalance_get_balance_type (GstColorBalance * balance) + { + GstPlayBin *playbin = GST_PLAY_BIN (balance); + + return + gst_color_balance_get_balance_type (GST_COLOR_BALANCE + (playbin->playsink)); + } + + static void + gst_play_bin_colorbalance_init (gpointer g_iface, gpointer g_iface_data) + { - GstColorBalanceClass *iface = (GstColorBalanceClass *) g_iface; ++ GstColorBalanceInterface *iface = (GstColorBalanceInterface *) g_iface; + + iface->list_channels = gst_play_bin_colorbalance_list_channels; + iface->set_value = gst_play_bin_colorbalance_set_value; + iface->get_value = gst_play_bin_colorbalance_get_value; + iface->get_balance_type = gst_play_bin_colorbalance_get_balance_type; + } + gboolean gst_play_bin2_plugin_init (GstPlugin * plugin) { diff --cc gst/playback/gstplaysink.c index e53b49c,61bdcee..c365378 --- a/gst/playback/gstplaysink.c +++ b/gst/playback/gstplaysink.c @@@ -28,6 -32,10 +28,10 @@@ #include #include #include -#include -#include -#include ++#include ++#include ++#include + #include #include "gstplaysink.h" #include "gststreamsynchronizer.h" @@@ -202,6 -207,20 +206,20 @@@ struct _GstPlaySin gboolean volume_changed; /* volume/mute changed while no audiochain */ gboolean mute_changed; /* ... has been created yet */ gint64 av_offset; + - /* xoverlay proxy interface */ - GstXOverlay *xoverlay_element; /* protected with LOCK */ - gboolean xoverlay_handle_set; - guintptr xoverlay_handle; - gboolean xoverlay_render_rectangle_set; - gint xoverlay_x, xoverlay_y, xoverlay_width, xoverlay_height; - gboolean xoverlay_handle_events_set; - gboolean xoverlay_handle_events; ++ /* videooverlay proxy interface */ ++ GstVideoOverlay *overlay_element; /* protected with LOCK */ ++ gboolean overlay_handle_set; ++ guintptr overlay_handle; ++ gboolean overlay_render_rectangle_set; ++ gint overlay_x, overlay_y, overlay_width, overlay_height; ++ gboolean overlay_handle_events_set; ++ gboolean overlay_handle_events; + + /* colorbalance proxy interface */ + GstColorBalance *colorbalance_element; + GList *colorbalance_channels; /* CONTRAST, BRIGHTNESS, HUE, SATURATION */ + gint colorbalance_values[4]; }; struct _GstPlaySinkClass @@@ -324,7 -343,47 +342,40 @@@ gst_play_marshal_SAMPLE__BOXED (GClosur /* static guint gst_play_sink_signals[LAST_SIGNAL] = { 0 }; */ - G_DEFINE_TYPE (GstPlaySink, gst_play_sink, GST_TYPE_BIN); -static void gst_play_sink_implements_interface_init (gpointer g_iface, - gpointer g_iface_data); -static void gst_play_sink_xoverlay_init (gpointer g_iface, ++static void gst_play_sink_overlay_init (gpointer g_iface, + gpointer g_iface_data); + static void gst_play_sink_navigation_init (gpointer g_iface, + gpointer g_iface_data); + static void gst_play_sink_colorbalance_init (gpointer g_iface, + gpointer g_iface_data); + + static void + _do_init (GType type) + { - static const GInterfaceInfo impl_info = { - gst_play_sink_implements_interface_init, - NULL, NULL - }; + static const GInterfaceInfo svol_info = { + NULL, NULL, NULL + }; - static const GInterfaceInfo xov_info = { - gst_play_sink_xoverlay_init, ++ static const GInterfaceInfo ov_info = { ++ gst_play_sink_overlay_init, + NULL, NULL + }; + static const GInterfaceInfo nav_info = { + gst_play_sink_navigation_init, + NULL, NULL + }; + static const GInterfaceInfo col_info = { + gst_play_sink_colorbalance_init, + NULL, NULL + }; + - g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, &impl_info); + g_type_add_interface_static (type, GST_TYPE_STREAM_VOLUME, &svol_info); - g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &xov_info); ++ g_type_add_interface_static (type, GST_TYPE_VIDEO_OVERLAY, &ov_info); + g_type_add_interface_static (type, GST_TYPE_NAVIGATION, &nav_info); + g_type_add_interface_static (type, GST_TYPE_COLOR_BALANCE, &col_info); + } + + G_DEFINE_TYPE_WITH_CODE (GstPlaySink, gst_play_sink, GST_TYPE_BIN, + _do_init (g_define_type_id)); static void gst_play_sink_class_init (GstPlaySinkClass * klass) @@@ -520,8 -583,48 +574,48 @@@ gst_play_sink_init (GstPlaySink * plays gst_bin_add (GST_BIN_CAST (playsink), GST_ELEMENT_CAST (playsink->stream_synchronizer)); - g_static_rec_mutex_init (&playsink->lock); - GST_OBJECT_FLAG_SET (playsink, GST_ELEMENT_IS_SINK); + g_rec_mutex_init (&playsink->lock); + GST_OBJECT_FLAG_SET (playsink, GST_ELEMENT_FLAG_SINK); + + channel = + GST_COLOR_BALANCE_CHANNEL (g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, + NULL)); + channel->label = g_strdup ("CONTRAST"); + channel->min_value = -1000; + channel->max_value = 1000; + playsink->colorbalance_channels = + g_list_append (playsink->colorbalance_channels, channel); + playsink->colorbalance_values[0] = 0; + + channel = + GST_COLOR_BALANCE_CHANNEL (g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, + NULL)); + channel->label = g_strdup ("BRIGHTNESS"); + channel->min_value = -1000; + channel->max_value = 1000; + playsink->colorbalance_channels = + g_list_append (playsink->colorbalance_channels, channel); + playsink->colorbalance_values[1] = 0; + + channel = + GST_COLOR_BALANCE_CHANNEL (g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, + NULL)); + channel->label = g_strdup ("HUE"); + channel->min_value = -1000; + channel->max_value = 1000; + playsink->colorbalance_channels = + g_list_append (playsink->colorbalance_channels, channel); + playsink->colorbalance_values[2] = 0; + + channel = + GST_COLOR_BALANCE_CHANNEL (g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, + NULL)); + channel->label = g_strdup ("SATURATION"); + channel->min_value = -1000; + channel->max_value = 1000; + playsink->colorbalance_channels = + g_list_append (playsink->colorbalance_channels, channel); + playsink->colorbalance_values[3] = 0; } static void @@@ -1231,6 -1343,150 +1330,149 @@@ link_failed } } + static gboolean -is_valid_color_balance_element (GstElement * element) ++is_valid_color_balance_element (GstColorBalance * bal) + { - GstColorBalance *bal = GST_COLOR_BALANCE (element); + gboolean have_brightness = FALSE; + gboolean have_contrast = FALSE; + gboolean have_hue = FALSE; + gboolean have_saturation = FALSE; + const GList *channels, *l; + + channels = gst_color_balance_list_channels (bal); + for (l = channels; l; l = l->next) { + GstColorBalanceChannel *ch = l->data; + + if (g_strrstr (ch->label, "BRIGHTNESS")) + have_brightness = TRUE; + else if (g_strrstr (ch->label, "CONTRAST")) + have_contrast = TRUE; + else if (g_strrstr (ch->label, "HUE")) + have_hue = TRUE; + else if (g_strrstr (ch->label, "SATURATION")) + have_saturation = TRUE; + } + + return have_brightness && have_contrast && have_hue && have_saturation; + } + + static void -iterate_color_balance_elements (gpointer data, gpointer user_data) ++iterate_color_balance_elements (const GValue * item, gpointer user_data) + { - gboolean valid = is_valid_color_balance_element (data); - GstColorBalance **cb_out = user_data; ++ gboolean valid; ++ GstColorBalance *cb, **cb_out = user_data; + ++ cb = GST_COLOR_BALANCE (g_value_get_object (item)); ++ valid = is_valid_color_balance_element (cb); + if (valid) { + if (*cb_out + && gst_color_balance_get_balance_type (*cb_out) == + GST_COLOR_BALANCE_SOFTWARE) { + gst_object_unref (*cb_out); - *cb_out = GST_COLOR_BALANCE (gst_object_ref (data)); ++ *cb_out = GST_COLOR_BALANCE (gst_object_ref (cb)); + } else if (!*cb_out) { - *cb_out = GST_COLOR_BALANCE (gst_object_ref (data)); ++ *cb_out = GST_COLOR_BALANCE (gst_object_ref (cb)); + } + } - - gst_object_unref (data); + } + + static GstColorBalance * + find_color_balance_element (GstElement * element) + { + GstIterator *it; + GstColorBalance *cb = NULL; + + if (GST_IS_COLOR_BALANCE (element) - && is_valid_color_balance_element (element)) ++ && is_valid_color_balance_element (GST_COLOR_BALANCE (element))) + return GST_COLOR_BALANCE (gst_object_ref (element)); + else if (!GST_IS_BIN (element)) + return FALSE; + + it = gst_bin_iterate_all_by_interface (GST_BIN (element), + GST_TYPE_COLOR_BALANCE); + while (gst_iterator_foreach (it, iterate_color_balance_elements, + &cb) == GST_ITERATOR_RESYNC) + gst_iterator_resync (it); + gst_iterator_free (it); + + return cb; + } + + static void + colorbalance_value_changed_cb (GstColorBalance * balance, + GstColorBalanceChannel * channel, gint value, GstPlaySink * playsink) + { + GList *l; + gint i; + + for (i = 0, l = playsink->colorbalance_channels; l; l = l->next, i++) { + GstColorBalanceChannel *proxy = l->data; + + if (g_strrstr (channel->label, proxy->label)) { + gdouble new_val; + + /* Convert to [0, 1] range */ + new_val = + ((gdouble) value - + (gdouble) channel->min_value) / ((gdouble) channel->max_value - + (gdouble) channel->min_value); + /* Convert to proxy range */ + new_val = + proxy->min_value + new_val * ((gdouble) proxy->max_value - + (gdouble) proxy->min_value); + playsink->colorbalance_values[i] = (gint) (0.5 + new_val); + + gst_color_balance_value_changed (GST_COLOR_BALANCE (playsink), proxy, + playsink->colorbalance_values[i]); + break; + } + } + } + + static void + update_colorbalance (GstPlaySink * playsink) + { + GstColorBalance *balance = NULL; + GList *l; + gint i; + + GST_OBJECT_LOCK (playsink); + if (playsink->colorbalance_element) { + balance = + GST_COLOR_BALANCE (gst_object_ref (playsink->colorbalance_element)); + } + GST_OBJECT_UNLOCK (playsink); + if (!balance) + return; + + g_signal_handlers_block_by_func (balance, + G_CALLBACK (colorbalance_value_changed_cb), playsink); + + for (i = 0, l = playsink->colorbalance_channels; l; l = l->next, i++) { + GstColorBalanceChannel *proxy = l->data; + GstColorBalanceChannel *channel = NULL; + const GList *channels, *k; + + channels = gst_color_balance_list_channels (balance); + for (k = channels; k; k = k->next) { + GstColorBalanceChannel *tmp = k->data; + + if (g_strrstr (tmp->label, proxy->label)) { + channel = tmp; + break; + } + } + + g_assert (channel); + + gst_color_balance_set_value (balance, channel, + playsink->colorbalance_values[i]); + } + + g_signal_handlers_unblock_by_func (balance, + G_CALLBACK (colorbalance_value_changed_cb), playsink); + } + /* make the element (bin) that contains the elements needed to perform * video display. * @@@ -1310,6 -1573,34 +1559,34 @@@ gen_video_chain (GstPlaySink * playsink gst_object_ref_sink (bin); gst_bin_add (bin, chain->sink); - /* Get the XOverlay element */ ++ /* Get the VideoOverlay element */ + { - GstXOverlay *xoverlay = NULL; ++ GstVideoOverlay *overlay = NULL; + + GST_OBJECT_LOCK (playsink); - if (playsink->xoverlay_element) - gst_object_unref (playsink->xoverlay_element); - playsink->xoverlay_element = - GST_X_OVERLAY (gst_bin_get_by_interface (GST_BIN (chain->chain.bin), - GST_TYPE_X_OVERLAY)); - if (playsink->xoverlay_element) - xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element)); ++ if (playsink->overlay_element) ++ gst_object_unref (playsink->overlay_element); ++ playsink->overlay_element = ++ GST_VIDEO_OVERLAY (gst_bin_get_by_interface (GST_BIN (chain->chain.bin), ++ GST_TYPE_VIDEO_OVERLAY)); ++ if (playsink->overlay_element) ++ overlay = GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element)); + GST_OBJECT_UNLOCK (playsink); + - if (xoverlay) { - if (playsink->xoverlay_handle_set) - gst_x_overlay_set_window_handle (xoverlay, playsink->xoverlay_handle); - if (playsink->xoverlay_handle_events_set) - gst_x_overlay_handle_events (xoverlay, - playsink->xoverlay_handle_events); - if (playsink->xoverlay_render_rectangle_set) - gst_x_overlay_set_render_rectangle (xoverlay, - playsink->xoverlay_x, playsink->xoverlay_y, - playsink->xoverlay_width, playsink->xoverlay_height); - gst_object_unref (xoverlay); ++ if (overlay) { ++ if (playsink->overlay_handle_set) ++ gst_video_overlay_set_window_handle (overlay, playsink->overlay_handle); ++ if (playsink->overlay_handle_events_set) ++ gst_video_overlay_handle_events (overlay, ++ playsink->overlay_handle_events); ++ if (playsink->overlay_render_rectangle_set) ++ gst_video_overlay_set_render_rectangle (overlay, ++ playsink->overlay_x, playsink->overlay_y, ++ playsink->overlay_width, playsink->overlay_height); ++ gst_object_unref (overlay); + } + } + /* decouple decoder from sink, this improves playback quite a lot since the * decoder can continue while the sink blocks for synchronisation. We don't * need a lot of buffers as this consumes a lot of memory and we don't want @@@ -1423,8 -1741,35 +1727,35 @@@ setup_video_chain (GstPlaySink * playsi if (ret == GST_STATE_CHANGE_FAILURE) return FALSE; - /* find ts-offset element */ - /* Get the XOverlay element */ ++ /* Get the VideoOverlay element */ + { - GstXOverlay *xoverlay = NULL; ++ GstVideoOverlay *overlay = NULL; + + GST_OBJECT_LOCK (playsink); - if (playsink->xoverlay_element) - gst_object_unref (playsink->xoverlay_element); - playsink->xoverlay_element = - GST_X_OVERLAY (gst_bin_get_by_interface (GST_BIN (chain->chain.bin), - GST_TYPE_X_OVERLAY)); - if (playsink->xoverlay_element) - xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element)); ++ if (playsink->overlay_element) ++ gst_object_unref (playsink->overlay_element); ++ playsink->overlay_element = ++ GST_VIDEO_OVERLAY (gst_bin_get_by_interface (GST_BIN (chain->chain.bin), ++ GST_TYPE_VIDEO_OVERLAY)); ++ if (playsink->overlay_element) ++ overlay = GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element)); + GST_OBJECT_UNLOCK (playsink); + - if (xoverlay) { - if (playsink->xoverlay_handle_set) - gst_x_overlay_set_window_handle (xoverlay, playsink->xoverlay_handle); - if (playsink->xoverlay_handle_events_set) - gst_x_overlay_handle_events (xoverlay, - playsink->xoverlay_handle_events); - if (playsink->xoverlay_render_rectangle_set) - gst_x_overlay_set_render_rectangle (xoverlay, - playsink->xoverlay_x, playsink->xoverlay_y, - playsink->xoverlay_width, playsink->xoverlay_height); - gst_object_unref (xoverlay); ++ if (overlay) { ++ if (playsink->overlay_handle_set) ++ gst_video_overlay_set_window_handle (overlay, playsink->overlay_handle); ++ if (playsink->overlay_handle_events_set) ++ gst_video_overlay_handle_events (overlay, ++ playsink->overlay_handle_events); ++ if (playsink->overlay_render_rectangle_set) ++ gst_video_overlay_set_render_rectangle (overlay, ++ playsink->overlay_x, playsink->overlay_y, ++ playsink->overlay_width, playsink->overlay_height); ++ gst_object_unref (overlay); + } + } + /* find ts-offset element */ gst_object_replace ((GstObject **) & chain->ts_offset, (GstObject *) gst_play_sink_find_property_sinks (playsink, chain->sink, "ts-offset", G_TYPE_INT64)); @@@ -2164,6 -2543,19 +2529,19 @@@ gst_play_sink_reconfigure (GstPlaySink need_text = TRUE; } + GST_OBJECT_LOCK (playsink); - if (playsink->xoverlay_element) - gst_object_unref (playsink->xoverlay_element); - playsink->xoverlay_element = NULL; ++ 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 */ @@@ -3355,6 -3714,43 +3733,44 @@@ gst_play_sink_handle_message (GstBin * GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (bin, message); break; } + case GST_MESSAGE_ELEMENT:{ - if (gst_structure_has_name (message->structure, "prepare-xwindow-id")) { - GstXOverlay *xoverlay; ++ if (gst_is_video_overlay_prepare_window_handle_message (message)) { ++ GstVideoOverlay *overlay; + + GST_OBJECT_LOCK (playsink); - if (playsink->xoverlay_element - && GST_OBJECT_CAST (playsink->xoverlay_element) != ++ if (playsink->overlay_element ++ && GST_OBJECT_CAST (playsink->overlay_element) != + GST_MESSAGE_SRC (message)) { - gst_object_unref (playsink->xoverlay_element); - playsink->xoverlay_element = NULL; ++ gst_object_unref (playsink->overlay_element); ++ playsink->overlay_element = NULL; + } + - if (!playsink->xoverlay_element) - playsink->xoverlay_element = - GST_X_OVERLAY (gst_object_ref (GST_MESSAGE_SRC (message))); - xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element)); ++ if (!playsink->overlay_element) ++ playsink->overlay_element = ++ GST_VIDEO_OVERLAY (gst_object_ref (GST_MESSAGE_SRC (message))); ++ overlay = ++ GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element)); + GST_OBJECT_UNLOCK (playsink); + + GST_DEBUG_OBJECT (playsink, "Got prepare-xwindow-id message"); + - if (playsink->xoverlay_handle_set) - gst_x_overlay_set_window_handle (playsink->xoverlay_element, - playsink->xoverlay_handle); - if (playsink->xoverlay_handle_events_set) - gst_x_overlay_handle_events (playsink->xoverlay_element, - playsink->xoverlay_handle_events); - if (playsink->xoverlay_render_rectangle_set) - gst_x_overlay_set_render_rectangle (playsink->xoverlay_element, - playsink->xoverlay_x, playsink->xoverlay_y, - playsink->xoverlay_width, playsink->xoverlay_height); - - gst_object_unref (xoverlay); ++ if (playsink->overlay_handle_set) ++ gst_video_overlay_set_window_handle (playsink->overlay_element, ++ playsink->overlay_handle); ++ if (playsink->overlay_handle_events_set) ++ gst_video_overlay_handle_events (playsink->overlay_element, ++ playsink->overlay_handle_events); ++ if (playsink->overlay_render_rectangle_set) ++ gst_video_overlay_set_render_rectangle (playsink->overlay_element, ++ playsink->overlay_x, playsink->overlay_y, ++ playsink->overlay_width, playsink->overlay_height); ++ ++ gst_object_unref (overlay); + gst_message_unref (message); - gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (playsink)); ++ gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (playsink)); + } + break; + } default: GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (bin, message); break; @@@ -3493,6 -3913,20 +3901,20 @@@ gst_play_sink_change_state (GstElement gst_object_unref (playsink->videochain->ts_offset); playsink->videochain->ts_offset = NULL; } + + GST_OBJECT_LOCK (playsink); - if (playsink->xoverlay_element) - gst_object_unref (playsink->xoverlay_element); - playsink->xoverlay_element = NULL; ++ 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); + ret = GST_STATE_CHANGE_SUCCESS; break; default: @@@ -3735,6 -4164,282 +4152,268 @@@ gst_play_sink_get_property (GObject * o } } + static void -gst_play_sink_xoverlay_expose (GstXOverlay * overlay) ++gst_play_sink_overlay_expose (GstVideoOverlay * overlay) + { + GstPlaySink *playsink = GST_PLAY_SINK (overlay); - GstXOverlay *xoverlay; ++ GstVideoOverlay *overlay_element; + + GST_OBJECT_LOCK (playsink); - if (playsink->xoverlay_element) - xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element)); ++ if (playsink->overlay_element) ++ overlay_element = ++ GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element)); + else - xoverlay = NULL; ++ overlay_element = NULL; + GST_OBJECT_UNLOCK (playsink); + - if (xoverlay) { - gst_x_overlay_expose (xoverlay); - gst_object_unref (xoverlay); ++ if (overlay_element) { ++ gst_video_overlay_expose (overlay_element); ++ gst_object_unref (overlay_element); + } + } + + static void -gst_play_sink_xoverlay_handle_events (GstXOverlay * overlay, ++gst_play_sink_overlay_handle_events (GstVideoOverlay * overlay, + gboolean handle_events) + { + GstPlaySink *playsink = GST_PLAY_SINK (overlay); - GstXOverlay *xoverlay; ++ GstVideoOverlay *overlay_element; + + GST_OBJECT_LOCK (playsink); - if (playsink->xoverlay_element) - xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element)); ++ if (playsink->overlay_element) ++ overlay_element = ++ GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element)); + else - xoverlay = NULL; ++ overlay_element = NULL; + GST_OBJECT_UNLOCK (playsink); + - playsink->xoverlay_handle_events_set = TRUE; - playsink->xoverlay_handle_events = handle_events; ++ playsink->overlay_handle_events_set = TRUE; ++ playsink->overlay_handle_events = handle_events; + - if (xoverlay) { - gst_x_overlay_handle_events (xoverlay, handle_events); - gst_object_unref (xoverlay); ++ if (overlay_element) { ++ gst_video_overlay_handle_events (overlay_element, handle_events); ++ gst_object_unref (overlay_element); + } + } + + static void -gst_play_sink_xoverlay_set_render_rectangle (GstXOverlay * overlay, gint x, ++gst_play_sink_overlay_set_render_rectangle (GstVideoOverlay * overlay, gint x, + gint y, gint width, gint height) + { + GstPlaySink *playsink = GST_PLAY_SINK (overlay); - GstXOverlay *xoverlay; ++ GstVideoOverlay *overlay_element; + + GST_OBJECT_LOCK (playsink); - if (playsink->xoverlay_element) - xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element)); ++ if (playsink->overlay_element) ++ overlay_element = ++ GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element)); + else - xoverlay = NULL; ++ overlay_element = NULL; + GST_OBJECT_UNLOCK (playsink); + - playsink->xoverlay_render_rectangle_set = TRUE; - playsink->xoverlay_x = x; - playsink->xoverlay_y = y; - playsink->xoverlay_width = width; - playsink->xoverlay_height = height; ++ playsink->overlay_render_rectangle_set = TRUE; ++ playsink->overlay_x = x; ++ playsink->overlay_y = y; ++ playsink->overlay_width = width; ++ playsink->overlay_height = height; + - if (xoverlay) { - gst_x_overlay_set_render_rectangle (xoverlay, x, y, width, height); - gst_object_unref (xoverlay); ++ if (overlay_element) { ++ gst_video_overlay_set_render_rectangle (overlay_element, x, y, width, ++ height); ++ gst_object_unref (overlay_element); + } + } + + static void -gst_play_sink_xoverlay_set_window_handle (GstXOverlay * overlay, ++gst_play_sink_overlay_set_window_handle (GstVideoOverlay * overlay, + guintptr handle) + { + GstPlaySink *playsink = GST_PLAY_SINK (overlay); - GstXOverlay *xoverlay; ++ GstVideoOverlay *overlay_element; + + GST_OBJECT_LOCK (playsink); - if (playsink->xoverlay_element) - xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element)); ++ if (playsink->overlay_element) ++ overlay_element = ++ GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element)); + else - xoverlay = NULL; ++ overlay_element = NULL; + GST_OBJECT_UNLOCK (playsink); + - playsink->xoverlay_handle_set = TRUE; - playsink->xoverlay_handle = handle; ++ playsink->overlay_handle_set = TRUE; ++ playsink->overlay_handle = handle; + - if (xoverlay) { - gst_x_overlay_set_window_handle (xoverlay, handle); - gst_object_unref (xoverlay); ++ if (overlay_element) { ++ gst_video_overlay_set_window_handle (overlay_element, handle); ++ gst_object_unref (overlay_element); + } + } + + static void -gst_play_sink_xoverlay_init (gpointer g_iface, gpointer g_iface_data) -{ - GstXOverlayClass *iface = (GstXOverlayClass *) g_iface; - iface->expose = gst_play_sink_xoverlay_expose; - iface->handle_events = gst_play_sink_xoverlay_handle_events; - iface->set_render_rectangle = gst_play_sink_xoverlay_set_render_rectangle; - iface->set_window_handle = gst_play_sink_xoverlay_set_window_handle; -} - -static gboolean -gst_play_sink_implements_interface_supported (GstImplementsInterface * iface, - GType type) -{ - if (type == GST_TYPE_X_OVERLAY || type == GST_TYPE_STREAM_VOLUME || - type == GST_TYPE_NAVIGATION || type == GST_TYPE_COLOR_BALANCE) - return TRUE; - else - return FALSE; -} - -static void -gst_play_sink_implements_interface_init (gpointer g_iface, - gpointer g_iface_data) ++gst_play_sink_overlay_init (gpointer g_iface, gpointer g_iface_data) + { - GstImplementsInterfaceClass *iface = (GstImplementsInterfaceClass *) g_iface; - iface->supported = gst_play_sink_implements_interface_supported; ++ GstVideoOverlayInterface *iface = (GstVideoOverlayInterface *) g_iface; ++ iface->expose = gst_play_sink_overlay_expose; ++ iface->handle_events = gst_play_sink_overlay_handle_events; ++ iface->set_render_rectangle = gst_play_sink_overlay_set_render_rectangle; ++ iface->set_window_handle = gst_play_sink_overlay_set_window_handle; + } + + static void + gst_play_sink_navigation_send_event (GstNavigation * navigation, + GstStructure * structure) + { + GstPlaySink *playsink = GST_PLAY_SINK (navigation); + GstBin *bin = NULL; + + GST_PLAY_SINK_LOCK (playsink); + if (playsink->videochain && playsink->videochain->chain.bin) + bin = GST_BIN (gst_object_ref (playsink->videochain->chain.bin)); + GST_PLAY_SINK_UNLOCK (playsink); + + if (bin) { + GstElement *nav = gst_bin_get_by_interface (bin, GST_TYPE_NAVIGATION); + + if (nav) { + gst_navigation_send_event (GST_NAVIGATION (nav), structure); + structure = NULL; + gst_object_unref (nav); + } + + gst_object_unref (bin); + } + + if (structure) + gst_structure_free (structure); + } + + static void + gst_play_sink_navigation_init (gpointer g_iface, gpointer g_iface_data) + { + GstNavigationInterface *iface = (GstNavigationInterface *) g_iface; + + iface->send_event = gst_play_sink_navigation_send_event; + } + + static const GList * + gst_play_sink_colorbalance_list_channels (GstColorBalance * balance) + { + GstPlaySink *playsink = GST_PLAY_SINK (balance); + + return playsink->colorbalance_channels; + } + + static void + gst_play_sink_colorbalance_set_value (GstColorBalance * balance, + GstColorBalanceChannel * proxy, gint value) + { + GstPlaySink *playsink = GST_PLAY_SINK (balance); + GList *l; + gint i; + GstColorBalance *balance_element = NULL; + + GST_OBJECT_LOCK (playsink); + if (playsink->colorbalance_element) + balance_element = + GST_COLOR_BALANCE (gst_object_ref (playsink->colorbalance_element)); + GST_OBJECT_UNLOCK (playsink); + + for (i = 0, l = playsink->colorbalance_channels; l; l = l->next, i++) { + GstColorBalanceChannel *proxy_tmp = l->data; + gdouble new_val; + + if (proxy_tmp != proxy) + continue; + + playsink->colorbalance_values[i] = value; + + if (balance_element) { + GstColorBalanceChannel *channel = NULL; + const GList *channels, *k; + + channels = gst_color_balance_list_channels (balance_element); + for (k = channels; k; k = k->next) { + GstColorBalanceChannel *tmp = l->data; + + if (g_strrstr (tmp->label, proxy->label)) { + channel = tmp; + break; + } + } + + g_assert (channel); + + /* Convert to [0, 1] range */ + new_val = + ((gdouble) value - + (gdouble) proxy->min_value) / ((gdouble) proxy->max_value - + (gdouble) proxy->min_value); + /* Convert to channel range */ + new_val = + channel->min_value + new_val * ((gdouble) channel->max_value - + (gdouble) channel->min_value); + + gst_color_balance_set_value (balance_element, channel, + (gint) (new_val + 0.5)); + + gst_object_unref (balance_element); + } + + gst_color_balance_value_changed (balance, proxy, value); + break; + } + } + + static gint + gst_play_sink_colorbalance_get_value (GstColorBalance * balance, + GstColorBalanceChannel * proxy) + { + GstPlaySink *playsink = GST_PLAY_SINK (balance); + GList *l; + gint i; + + for (i = 0, l = playsink->colorbalance_channels; l; l = l->next, i++) { + GstColorBalanceChannel *proxy_tmp = l->data; + + if (proxy_tmp != proxy) + continue; + + return playsink->colorbalance_values[i]; + } + + g_return_val_if_reached (0); + } + + static GstColorBalanceType + gst_play_sink_colorbalance_get_balance_type (GstColorBalance * balance) + { + GstPlaySink *playsink = GST_PLAY_SINK (balance); + GstColorBalance *balance_element = NULL; + GstColorBalanceType t = GST_COLOR_BALANCE_SOFTWARE; + + GST_OBJECT_LOCK (playsink); + if (playsink->colorbalance_element) + balance_element = + GST_COLOR_BALANCE (gst_object_ref (playsink->colorbalance_element)); + GST_OBJECT_UNLOCK (playsink); + + if (balance_element) { + t = gst_color_balance_get_balance_type (balance_element); + gst_object_unref (balance_element); + } + + return t; + } + + static void + gst_play_sink_colorbalance_init (gpointer g_iface, gpointer g_iface_data) + { - GstColorBalanceClass *iface = (GstColorBalanceClass *) g_iface; ++ GstColorBalanceInterface *iface = (GstColorBalanceInterface *) g_iface; + + iface->list_channels = gst_play_sink_colorbalance_list_channels; + iface->set_value = gst_play_sink_colorbalance_set_value; + iface->get_value = gst_play_sink_colorbalance_get_value; + iface->get_balance_type = gst_play_sink_colorbalance_get_balance_type; + } gboolean gst_play_sink_plugin_init (GstPlugin * plugin) diff --cc gst/videoscale/gstvideoscale.c index 3ee139e,60dd5ff..01015f1 --- a/gst/videoscale/gstvideoscale.c +++ b/gst/videoscale/gstvideoscale.c @@@ -395,50 -424,151 +395,170 @@@ gst_video_scale_get_property (GObject } } + #define NEAREST (1 << GST_VIDEO_SCALE_NEAREST) + #define BILINEAR (1 << GST_VIDEO_SCALE_BILINEAR) + #define FOURTAP (1 << GST_VIDEO_SCALE_4TAP) + #define LANCZOS (1 << GST_VIDEO_SCALE_LANCZOS) + + /* or we could just do lookups via table[format] if we could be bothered.. */ + static const struct + { + GstVideoFormat format; + guint8 methods; + } formats_methods_table[] = { + { + GST_VIDEO_FORMAT_RGBx, NEAREST | BILINEAR | FOURTAP | LANCZOS}, { + GST_VIDEO_FORMAT_xRGB, NEAREST | BILINEAR | FOURTAP | LANCZOS}, { + GST_VIDEO_FORMAT_BGRx, NEAREST | BILINEAR | FOURTAP | LANCZOS}, { + GST_VIDEO_FORMAT_xBGR, NEAREST | BILINEAR | FOURTAP | LANCZOS}, { + GST_VIDEO_FORMAT_RGBA, NEAREST | BILINEAR | FOURTAP | LANCZOS}, { + GST_VIDEO_FORMAT_ARGB, NEAREST | BILINEAR | FOURTAP | LANCZOS}, { + GST_VIDEO_FORMAT_BGRA, NEAREST | BILINEAR | FOURTAP | LANCZOS}, { + GST_VIDEO_FORMAT_ABGR, NEAREST | BILINEAR | FOURTAP | LANCZOS}, { + GST_VIDEO_FORMAT_AYUV, NEAREST | BILINEAR | FOURTAP | LANCZOS}, { + GST_VIDEO_FORMAT_ARGB64, NEAREST | BILINEAR | FOURTAP | LANCZOS}, { + GST_VIDEO_FORMAT_AYUV64, NEAREST | BILINEAR | FOURTAP | LANCZOS}, { + GST_VIDEO_FORMAT_RGB, NEAREST | BILINEAR | FOURTAP}, { + GST_VIDEO_FORMAT_BGR, NEAREST | BILINEAR | FOURTAP}, { + GST_VIDEO_FORMAT_v308, NEAREST | BILINEAR | FOURTAP}, { + GST_VIDEO_FORMAT_YUY2, NEAREST | BILINEAR | FOURTAP}, { + GST_VIDEO_FORMAT_YVYU, NEAREST | BILINEAR | FOURTAP}, { + GST_VIDEO_FORMAT_UYVY, NEAREST | BILINEAR | FOURTAP}, { + GST_VIDEO_FORMAT_Y800, NEAREST | BILINEAR | FOURTAP}, { + GST_VIDEO_FORMAT_GRAY8, NEAREST | BILINEAR | FOURTAP}, { + GST_VIDEO_FORMAT_GRAY16_LE, NEAREST | BILINEAR | FOURTAP}, { + GST_VIDEO_FORMAT_GRAY16_BE, NEAREST | BILINEAR | FOURTAP}, { + GST_VIDEO_FORMAT_Y16, NEAREST | BILINEAR | FOURTAP}, { + GST_VIDEO_FORMAT_I420, NEAREST | BILINEAR | FOURTAP | LANCZOS}, { + GST_VIDEO_FORMAT_YV12, NEAREST | BILINEAR | FOURTAP | LANCZOS}, { + GST_VIDEO_FORMAT_Y444, NEAREST | BILINEAR | FOURTAP | LANCZOS}, { + GST_VIDEO_FORMAT_Y42B, NEAREST | BILINEAR | FOURTAP | LANCZOS}, { + GST_VIDEO_FORMAT_Y41B, NEAREST | BILINEAR | FOURTAP | LANCZOS}, { + GST_VIDEO_FORMAT_NV12, NEAREST | BILINEAR}, { + GST_VIDEO_FORMAT_RGB16, NEAREST | BILINEAR | FOURTAP}, { + GST_VIDEO_FORMAT_RGB15, NEAREST | BILINEAR | FOURTAP} + }; + + static gboolean + gst_video_scale_format_supported_for_method (GstVideoFormat format, + GstVideoScaleMethod method) + { + int i; + + for (i = 0; i < G_N_ELEMENTS (formats_methods_table); ++i) { + if (formats_methods_table[i].format == format) + return ((formats_methods_table[i].methods & (1 << method)) != 0); + } + return FALSE; + } + + static gboolean + gst_video_scale_transform_supported (GstVideoScale * videoscale, + GstVideoScaleMethod method, GstStructure * structure) + { + const GValue *val; - GstVideoFormat fmt; ++ GstVideoInfo info; + gboolean supported = TRUE; + GstStructure *s; + GstCaps *c; + + /* we support these methods for all formats */ + if (method == GST_VIDEO_SCALE_NEAREST || method == GST_VIDEO_SCALE_BILINEAR) + return TRUE; + + /* we need fixed caps if we want to use gst_video_parse_caps() */ + s = gst_structure_new (gst_structure_get_name (structure), + "width", G_TYPE_INT, 1, "height", G_TYPE_INT, 1, NULL); + + if ((val = gst_structure_get_value (structure, "format"))) { + gst_structure_set_value (s, "format", val); + } else { + if ((val = gst_structure_get_value (structure, "endianness"))) + gst_structure_set_value (s, "endianness", val); + if ((val = gst_structure_get_value (structure, "red_mask"))) + gst_structure_set_value (s, "red_mask", val); + if ((val = gst_structure_get_value (structure, "blue_mask"))) + gst_structure_set_value (s, "blue_mask", val); + if ((val = gst_structure_get_value (structure, "green_mask"))) + gst_structure_set_value (s, "green_mask", val); + if ((val = gst_structure_get_value (structure, "alpha_mask"))) + gst_structure_set_value (s, "alpha_mask", val); + if ((val = gst_structure_get_value (structure, "depth"))) + gst_structure_set_value (s, "depth", val); + if ((val = gst_structure_get_value (structure, "bpp"))) + gst_structure_set_value (s, "bpp", val); + } + c = gst_caps_new_full (s, NULL); - if (!gst_video_format_parse_caps (c, &fmt, NULL, NULL)) { ++ ++ gst_video_info_init (&info); ++ if (!gst_video_info_from_caps (&info, c)) { + GST_ERROR_OBJECT (videoscale, "couldn't parse %" GST_PTR_FORMAT, c); - } else if (!gst_video_scale_format_supported_for_method (fmt, method)) { ++ } else if (!gst_video_scale_format_supported_for_method (info.finfo->format, ++ method)) { + supported = FALSE; + } + GST_LOG_OBJECT (videoscale, "method %d %ssupported for format %d", - method, (supported) ? "" : "not ", fmt); ++ method, (supported) ? "" : "not ", info.finfo->format); + gst_caps_unref (c); + + return supported; + } + static GstCaps * gst_video_scale_transform_caps (GstBaseTransform * trans, - GstPadDirection direction, GstCaps * caps) + GstPadDirection direction, GstCaps * caps, GstCaps * filter) { + GstVideoScale *videoscale = GST_VIDEO_SCALE (trans); + GstVideoScaleMethod method; GstCaps *ret; GstStructure *structure; - - /* this function is always called with a simple caps */ - g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), NULL); + gint i, n; GST_DEBUG_OBJECT (trans, "Transforming caps %" GST_PTR_FORMAT " in direction %s", caps, (direction == GST_PAD_SINK) ? "sink" : "src"); - ret = gst_caps_copy (caps); - structure = gst_structure_copy (gst_caps_get_structure (ret, 0)); - + GST_OBJECT_LOCK (videoscale); + method = videoscale->method; + GST_OBJECT_UNLOCK (videoscale); + - if (!gst_video_scale_transform_supported (videoscale, method, structure)) - goto format_not_supported; + ret = gst_caps_new_empty (); + n = gst_caps_get_size (caps); + for (i = 0; i < n; i++) { + structure = gst_caps_get_structure (caps, i); + + /* If this is already expressed by the existing caps + * skip this structure */ + if (i > 0 && gst_caps_is_subset_structure (ret, structure)) + continue; + ++ if (!gst_video_scale_transform_supported (videoscale, method, structure)) ++ goto format_not_supported; ++ + structure = gst_structure_copy (structure); + gst_structure_set (structure, + "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, + "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL); + + /* if pixel aspect ratio, make a range of it */ + if (gst_structure_has_field (structure, "pixel-aspect-ratio")) { + gst_structure_set (structure, "pixel-aspect-ratio", + GST_TYPE_FRACTION_RANGE, 1, G_MAXINT, G_MAXINT, 1, NULL); + } + gst_caps_append_structure (ret, structure); + } - gst_structure_set (structure, - "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, - "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL); + if (filter) { + GstCaps *intersection; - /* if pixel aspect ratio, make a range of it */ - if (gst_structure_has_field (structure, "pixel-aspect-ratio")) { - gst_structure_set (structure, "pixel-aspect-ratio", GST_TYPE_FRACTION_RANGE, - 1, G_MAXINT, G_MAXINT, 1, NULL); + intersection = + gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (ret); + ret = intersection; } - gst_caps_append_structure (ret, structure); + done: + GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, ret); return ret; diff --cc tests/check/elements/videoscale.c index 0cf0812,5572533..e428dc0 --- a/tests/check/elements/videoscale.c +++ b/tests/check/elements/videoscale.c @@@ -38,14 -38,12 +38,12 @@@ videoscale_get_allowed_caps_for_method GstStructure *s; gint i, n; - templ = - gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (scale), - "sink"); - fail_unless (templ != NULL); - - tmp = gst_pad_template_get_caps (templ); - caps = gst_caps_normalize (tmp); - gst_caps_unref (tmp); + scale = gst_element_factory_make ("videoscale", "vscale"); + g_object_set (scale, "method", method, NULL); + pad = gst_element_get_static_pad (scale, "sink"); - caps = gst_pad_get_caps (pad); ++ caps = gst_pad_query_caps (pad, NULL); + gst_object_unref (pad); + gst_object_unref (scale); n = gst_caps_get_size (caps); ret = g_new0 (GstCaps *, n + 1); @@@ -57,8 -56,6 +56,7 @@@ } gst_caps_unref (caps); - gst_object_unref (scale); + return ret; } @@@ -225,45 -219,40 +223,44 @@@ test_passthrough (int method while (*p) { GstCaps *caps = *p; - /* skip formats that ffmpegcolorspace can't handle */ - if (caps_are_64bpp (caps)) - goto skip; - - GST_DEBUG ("Running test for caps '%" GST_PTR_FORMAT "'" - " from %dx%u to %dx%d with method %d", caps, src_width, src_height, - dest_width, dest_height, method); - run_test (caps, src_width, src_height, - dest_width, dest_height, method, - G_CALLBACK (on_src_handoff_passthrough), &src_buffers, - G_CALLBACK (on_sink_handoff_passthrough), &sink_buffers); - - fail_unless (src_buffers && sink_buffers); - fail_unless_equals_int (g_list_length (src_buffers), - g_list_length (sink_buffers)); - - for (l1 = src_buffers, l2 = sink_buffers; l1 && l2; - l1 = l1->next, l2 = l2->next) { - GstBuffer *a = l1->data; - GstBuffer *b = l2->data; - - fail_unless_equals_int (GST_BUFFER_SIZE (a), GST_BUFFER_SIZE (b)); - fail_unless (GST_BUFFER_DATA (a) == GST_BUFFER_DATA (b)); - - gst_buffer_unref (a); - gst_buffer_unref (b); + for (method = 0; method < 3; method++) { + /* skip formats that videoconvert can't handle */ + if (caps_is_supported (caps)) + continue; + + GST_DEBUG ("Running test for caps '%" GST_PTR_FORMAT "'" + " from %dx%u to %dx%d with method %d", caps, src_width, src_height, + dest_width, dest_height, method); + run_test (caps, src_width, src_height, + dest_width, dest_height, method, + G_CALLBACK (on_src_handoff_passthrough), &src_buffers, + G_CALLBACK (on_sink_handoff_passthrough), &sink_buffers); + + fail_unless (src_buffers && sink_buffers); + fail_unless_equals_int (g_list_length (src_buffers), + g_list_length (sink_buffers)); + + for (l1 = src_buffers, l2 = sink_buffers; l1 && l2; + l1 = l1->next, l2 = l2->next) { + GstBuffer *a = l1->data; + GstBuffer *b = l2->data; + GstMapInfo mapa, mapb; + + gst_buffer_map (a, &mapa, GST_MAP_READ); + gst_buffer_map (b, &mapb, GST_MAP_READ); + fail_unless_equals_int (mapa.size, mapb.size); + fail_unless (mapa.data == mapb.data); + gst_buffer_unmap (b, &mapb); + gst_buffer_unmap (a, &mapa); + + gst_buffer_unref (a); + gst_buffer_unref (b); + } + g_list_free (src_buffers); + src_buffers = NULL; + g_list_free (sink_buffers); + sink_buffers = NULL; } - g_list_free (src_buffers); - src_buffers = NULL; - g_list_free (sink_buffers); - sink_buffers = NULL; - - skip: -- gst_caps_unref (caps); p++; } @@@ -868,10 -913,9 +924,11 @@@ videoscale_suite (void tcase_add_test (tc_chain, test_upscale_1x240_640x480_method_0); tcase_add_test (tc_chain, test_upscale_1x240_640x480_method_1); tcase_add_test (tc_chain, test_upscale_1x240_640x480_method_2); + tcase_add_test (tc_chain, test_upscale_1x240_640x480_method_3); tcase_add_test (tc_chain, test_negotiation); +#if 0 tcase_add_test (tc_chain, test_reverse_negotiation); +#endif tcase_add_test (tc_chain, test_basetransform_negotiation); GST_ERROR ("FIXME: test 64-bpp formats as well"); diff --cc tests/examples/seek/seek.c index 235af66,9502c8d..6e4592b --- a/tests/examples/seek/seek.c +++ b/tests/examples/seek/seek.c @@@ -44,8 -47,9 +47,9 @@@ #include #endif -#include +#include ++#include #include -#include GST_DEBUG_CATEGORY_STATIC (seek_debug); #define GST_CAT_DEFAULT (seek_debug) @@@ -137,12 -97,115 +97,115 @@@ typedef struc GstElementFactory *factory; } VisEntry; - static GArray *vis_entries; + typedef struct + { + /* GTK widgets */ + GtkWidget *window; + GtkWidget *video_combo, *audio_combo, *text_combo, *vis_combo; + GtkWidget *video_window; + + GtkWidget *vis_checkbox, *video_checkbox, *audio_checkbox; + GtkWidget *text_checkbox, *mute_checkbox, *volume_spinbutton; + GtkWidget *soft_volume_checkbox, *native_audio_checkbox, + *native_video_checkbox; + GtkWidget *download_checkbox, *buffering_checkbox, *deinterlace_checkbox; + GtkWidget *soft_colorbalance_checkbox; + GtkWidget *video_sink_entry, *audio_sink_entry, *text_sink_entry; + GtkWidget *buffer_size_entry, *buffer_duration_entry; + GtkWidget *ringbuffer_maxsize_entry, *connection_speed_entry; + GtkWidget *av_offset_entry, *subtitle_encoding_entry; + GtkWidget *subtitle_fontdesc_button; + + GtkWidget *seek_format_combo, *seek_position_label, *seek_duration_label; + GtkWidget *seek_entry; + + GtkWidget *seek_scale, *statusbar; + guint status_id; + + GtkWidget *step_format_combo, *step_amount_spinbutton, *step_rate_spinbutton; + GtkWidget *shuttle_scale; + + GtkWidget *contrast_scale, *brightness_scale, *hue_scale, *saturation_scale; + + struct + { + GstNavigationCommand cmd; + GtkWidget *button; + } navigation_buttons[14]; + + guintptr embed_xid; + + /* GStreamer pipeline */ + GstElement *pipeline; + + GstElement *navigation_element; + GstElement *colorbalance_element; - GstElement *xoverlay_element; ++ GstElement *overlay_element; + + /* Settings */ + gboolean accurate_seek; + gboolean keyframe_seek; + gboolean loop_seek; + gboolean flush_seek; + gboolean scrub; + gboolean play_scrub; + gboolean skip_seek; + gdouble rate; + + /* From commandline parameters */ + gboolean stats; + gboolean verbose; + const gchar *pipeline_spec; + gint pipeline_type; + GList *paths, *current_path; + GList *sub_paths, *current_sub_path; + + gchar *audiosink_str, *videosink_str; + + /* Internal state */ + gint64 position, duration; + + gboolean is_live; + gboolean buffering; + GstBufferingMode mode; + gint64 buffering_left; + GstState state; + guint update_id; + guint seek_timeout_id; + gulong changed_id; + guint fill_id; + + gboolean need_streams; + gint n_video, n_audio, n_text; + - GStaticMutex state_mutex; ++ GMutex state_mutex; + + GArray *vis_entries; /* Array of VisEntry structs */ + + gboolean shuttling; + gdouble shuttle_rate; + gdouble play_rate; + + const GstFormatDefinition *seek_format; + GList *formats; + } SeekApp; - static void clear_streams (GstElement * pipeline); + static void clear_streams (SeekApp * app); + static void find_interface_elements (SeekApp * app); static void volume_notify_cb (GstElement * pipeline, GParamSpec * arg, - gpointer user_dat); - static void find_navigation_element (void); + SeekApp * app); + static void mute_notify_cb (GstElement * pipeline, GParamSpec * arg, + SeekApp * app); + + static void video_sink_activate_cb (GtkEntry * entry, SeekApp * app); + static void text_sink_activate_cb (GtkEntry * entry, SeekApp * app); + static void audio_sink_activate_cb (GtkEntry * entry, SeekApp * app); + static void buffer_size_activate_cb (GtkEntry * entry, SeekApp * app); + static void buffer_duration_activate_cb (GtkEntry * entry, SeekApp * app); + static void ringbuffer_maxsize_activate_cb (GtkEntry * entry, SeekApp * app); + static void connection_speed_activate_cb (GtkEntry * entry, SeekApp * app); + static void av_offset_activate_cb (GtkEntry * entry, SeekApp * app); + static void subtitle_encoding_activate_cb (GtkEntry * entry, SeekApp * app); /* pipeline construction */ @@@ -193,39 -250,31 +250,31 @@@ set_uri_property (GObject * object, con } } - static GstElement * - construct_playbin (const gchar * name, const gchar * location) + static void + playbin_set_uri (GstElement * playbin, const gchar * location, + const gchar * sub_location) { - GstElement *player; - GstElement *avsink; - - player = gst_element_factory_make (name, "player"); - g_assert (player); - - playerbin_set_uri (player, location); - - seekable_elements = g_list_prepend (seekable_elements, player); - - avsink = gst_element_factory_make_or_warn (opt_audiosink_str, "a_sink"); - if (avsink) - g_object_set (player, "audio-sink", avsink, NULL); - - avsink = gst_element_factory_make_or_warn (opt_videosink_str, "v_sink"); - if (avsink) - g_object_set (player, "video-sink", avsink, NULL); - - return player; + set_uri_property (G_OBJECT (playbin), "uri", location); + set_uri_property (G_OBJECT (playbin), "suburi", sub_location); } - static GstElement * - make_playbin_pipeline (const gchar * location) + static void -make_playbin2_pipeline (SeekApp * app, const gchar * location) ++make_playbin_pipeline (SeekApp * app, const gchar * location) { - GstElement *pipeline = construct_playbin ("playbin", location); + GstElement *pipeline; + - app->pipeline = pipeline = gst_element_factory_make ("playbin2", "playbin2"); ++ app->pipeline = pipeline = gst_element_factory_make ("playbin", "playbin"); + g_assert (pipeline); + + playbin_set_uri (pipeline, location, + app->current_sub_path ? app->current_sub_path->data : NULL); - /* FIXME: this is not triggered, playbin is not forwarding it from the sink */ g_signal_connect (pipeline, "notify::volume", G_CALLBACK (volume_notify_cb), - NULL); - return pipeline; + app); + g_signal_connect (pipeline, "notify::mute", G_CALLBACK (mute_notify_cb), app); + + app->navigation_element = GST_ELEMENT (gst_object_ref (pipeline)); + app->colorbalance_element = GST_ELEMENT (gst_object_ref (pipeline)); } #ifndef GST_DISABLE_PARSE @@@ -250,8 -292,8 +292,8 @@@ typedef struc } Pipeline; - static Pipeline pipelines[] = { + static const Pipeline pipelines[] = { - {"playbin2", make_playbin2_pipeline}, + {"playbin", make_playbin_pipeline}, #ifndef GST_DISABLE_PARSE {"parse-launch", make_parselaunch_pipeline}, #endif @@@ -299,60 -337,47 +337,47 @@@ static seek_format seek_formats[] = {NULL, 0}, }; - G_GNUC_UNUSED static void - query_positions_elems (void) + static void + query_positions (SeekApp * app) { - GList *walk = seekable_elements; - - while (walk) { - GstElement *element = GST_ELEMENT (walk->data); - gint i = 0; + gint i = 0; - g_print ("positions %8.8s: ", GST_ELEMENT_NAME (element)); - while (seek_formats[i].name) { - gint64 position, total; - GstFormat format; + g_print ("positions %8.8s: ", GST_ELEMENT_NAME (app->pipeline)); + while (seek_formats[i].name) { + gint64 position, total; + GstFormat format; - format = seek_formats[i].format; + format = seek_formats[i].format; - if (gst_element_query_position (element, format, &position) && - gst_element_query_duration (element, format, &total)) { - g_print ("%s %13" G_GINT64_FORMAT " / %13" G_GINT64_FORMAT " | ", - seek_formats[i].name, position, total); - } else { - g_print ("%s %13.13s / %13.13s | ", seek_formats[i].name, "*NA*", - "*NA*"); - } - i++; - if (gst_element_query_position (app->pipeline, &format, &position) && - gst_element_query_duration (app->pipeline, &format, &total)) { ++ if (gst_element_query_position (app->pipeline, format, &position) && ++ gst_element_query_duration (app->pipeline, format, &total)) { + g_print ("%s %13" G_GINT64_FORMAT " / %13" G_GINT64_FORMAT " | ", + seek_formats[i].name, position, total); + } else { + g_print ("%s %13.13s / %13.13s | ", seek_formats[i].name, "*NA*", "*NA*"); } - g_print (" %s\n", GST_ELEMENT_NAME (element)); - - walk = g_list_next (walk); + i++; } + g_print (" %s\n", GST_ELEMENT_NAME (app->pipeline)); } - static gboolean start_seek (GtkWidget * widget, GdkEventButton * event, - gpointer user_data); - static gboolean stop_seek (GtkWidget * widget, GdkEventButton * event, - gpointer user_data); - static void seek_cb (GtkWidget * widget); + static gboolean start_seek (GtkRange * range, GdkEventButton * event, + SeekApp * app); + static gboolean stop_seek (GtkRange * range, GdkEventButton * event, + SeekApp * app); + static void seek_cb (GtkRange * range, SeekApp * app); static void - set_scale (gdouble value) + set_scale (SeekApp * app, gdouble value) { - g_signal_handlers_block_by_func (hscale, (void *) start_seek, - (void *) pipeline); - g_signal_handlers_block_by_func (hscale, (void *) stop_seek, - (void *) pipeline); - g_signal_handlers_block_by_func (hscale, (void *) seek_cb, (void *) pipeline); - gtk_adjustment_set_value (adjustment, value); - g_signal_handlers_unblock_by_func (hscale, (void *) start_seek, - (void *) pipeline); - g_signal_handlers_unblock_by_func (hscale, (void *) stop_seek, - (void *) pipeline); - g_signal_handlers_unblock_by_func (hscale, (void *) seek_cb, - (void *) pipeline); - gtk_widget_queue_draw (hscale); + g_signal_handlers_block_by_func (app->seek_scale, start_seek, app); + g_signal_handlers_block_by_func (app->seek_scale, stop_seek, app); + g_signal_handlers_block_by_func (app->seek_scale, seek_cb, app); + gtk_range_set_value (GTK_RANGE (app->seek_scale), value); + g_signal_handlers_unblock_by_func (app->seek_scale, start_seek, app); + g_signal_handlers_unblock_by_func (app->seek_scale, stop_seek, app); + g_signal_handlers_unblock_by_func (app->seek_scale, seek_cb, app); + gtk_widget_queue_draw (app->seek_scale); } static gboolean @@@ -399,29 -422,41 +422,41 @@@ update_fill (SeekApp * app } static gboolean - update_scale (gpointer data) + update_scale (SeekApp * app) { - if (seekable_elements) { - GstElement *element = GST_ELEMENT (seekable_elements->data); + GstFormat format = GST_FORMAT_TIME; + gint64 seek_pos, seek_dur; + gchar *str; - gst_element_query_position (element, GST_FORMAT_TIME, &position); - gst_element_query_duration (element, GST_FORMAT_TIME, &duration); - } + //position = 0; + //duration = 0; - if (stats) { - query_positions_elems (); - } - gst_element_query_position (app->pipeline, &format, &app->position); - gst_element_query_duration (app->pipeline, &format, &app->duration); ++ gst_element_query_position (app->pipeline, format, &app->position); ++ gst_element_query_duration (app->pipeline, format, &app->duration); + + if (app->stats) + query_positions (app); - if (position >= duration) - duration = position; + if (app->position >= app->duration) + app->duration = app->position; - if (duration > 0) { - set_scale (position * N_GRAD / duration); + if (app->duration > 0) { + set_scale (app, app->position * N_GRAD / app->duration); } - /* FIXME: see make_playerbin2_pipeline() and volume_notify_cb() */ - if (pipeline_type == 16) { - g_object_notify (G_OBJECT (pipeline), "volume"); + if (app->seek_format) { + format = app->seek_format->value; + seek_pos = seek_dur = -1; - gst_element_query_position (app->pipeline, &format, &seek_pos); - gst_element_query_duration (app->pipeline, &format, &seek_dur); ++ gst_element_query_position (app->pipeline, format, &seek_pos); ++ gst_element_query_duration (app->pipeline, format, &seek_dur); + + str = g_strdup_printf ("%" G_GINT64_FORMAT, seek_pos); + gtk_label_set_text (GTK_LABEL (app->seek_position_label), str); + g_free (str); + + str = g_strdup_printf ("%" G_GINT64_FORMAT, seek_dur); + gtk_label_set_text (GTK_LABEL (app->seek_duration_label), str); + g_free (str); } return TRUE; @@@ -662,15 -728,15 +728,15 @@@ failed } static void - pause_cb (GtkButton * button, gpointer data) + pause_cb (GtkButton * button, SeekApp * app) { - g_mutex_lock (&state_mutex); - if (state != GST_STATE_PAUSED) { - g_static_mutex_lock (&app->state_mutex); ++ g_mutex_lock (&app->state_mutex); + if (app->state != GST_STATE_PAUSED) { GstStateChangeReturn ret; - gtk_statusbar_pop (GTK_STATUSBAR (statusbar), status_id); + gtk_statusbar_pop (GTK_STATUSBAR (app->statusbar), app->status_id); g_print ("PAUSE pipeline\n"); - ret = gst_element_set_state (pipeline, GST_STATE_PAUSED); + ret = gst_element_set_state (app->pipeline, GST_STATE_PAUSED); switch (ret) { case GST_STATE_CHANGE_FAILURE: goto failed; @@@ -681,18 -747,20 +747,20 @@@ break; } - state = GST_STATE_PAUSED; - gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Paused"); + app->state = GST_STATE_PAUSED; + gtk_statusbar_push (GTK_STATUSBAR (app->statusbar), app->status_id, + "Paused"); } - g_mutex_unlock (&state_mutex); - g_static_mutex_unlock (&app->state_mutex); ++ g_mutex_unlock (&app->state_mutex); return; failed: { - g_mutex_unlock (&state_mutex); - g_static_mutex_unlock (&app->state_mutex); ++ g_mutex_unlock (&app->state_mutex); g_print ("PAUSE failed\n"); - gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Pause failed"); + gtk_statusbar_push (GTK_STATUSBAR (app->statusbar), app->status_id, + "Pause failed"); } } @@@ -704,55 -772,40 +772,40 @@@ stop_cb (GtkButton * button, SeekApp * gint i; g_print ("READY pipeline\n"); - gtk_statusbar_pop (GTK_STATUSBAR (statusbar), status_id); + gtk_statusbar_pop (GTK_STATUSBAR (app->statusbar), app->status_id); - g_mutex_lock (&state_mutex); - ret = gst_element_set_state (pipeline, STOP_STATE); - g_static_mutex_lock (&app->state_mutex); ++ g_mutex_lock (&app->state_mutex); + ret = gst_element_set_state (app->pipeline, STOP_STATE); if (ret == GST_STATE_CHANGE_FAILURE) goto failed; - state = STOP_STATE; - gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Stopped"); - gtk_widget_queue_draw (video_window); - - is_live = FALSE; - buffering = FALSE; - set_update_scale (FALSE); - set_scale (0.0); - set_update_fill (FALSE); - - if (pipeline_type == 16) - clear_streams (pipeline); - g_mutex_unlock (&state_mutex); - - #if 0 - /* if one uses parse_launch, play, stop and play again it fails as all the - * pads after the demuxer can't be reconnected - */ - if (!strcmp (pipelines[pipeline_type].name, "parse-launch")) { - gst_element_set_state (pipeline, GST_STATE_NULL); - gst_object_unref (pipeline); - - g_list_free (seekable_elements); - seekable_elements = NULL; - - pipeline = pipelines[pipeline_type].func (pipeline_spec); - g_assert (pipeline); - gst_element_set_state (pipeline, STOP_STATE); - connect_bus_signals (pipeline); - } - #endif - gtk_widget_set_sensitive (GTK_WIDGET (hscale), TRUE); - for (i = 0; i < G_N_ELEMENTS (navigation_buttons); i++) - gtk_widget_set_sensitive (navigation_buttons[i].button, FALSE); + app->state = STOP_STATE; + gtk_statusbar_push (GTK_STATUSBAR (app->statusbar), app->status_id, + "Stopped"); + gtk_widget_queue_draw (app->video_window); + + app->is_live = FALSE; + app->buffering = FALSE; + set_update_scale (app, FALSE); + set_scale (app, 0.0); + set_update_fill (app, FALSE); + + if (app->pipeline_type == 0) + clear_streams (app); - g_static_mutex_unlock (&app->state_mutex); ++ g_mutex_unlock (&app->state_mutex); + + gtk_widget_set_sensitive (GTK_WIDGET (app->seek_scale), TRUE); + for (i = 0; i < G_N_ELEMENTS (app->navigation_buttons); i++) + gtk_widget_set_sensitive (app->navigation_buttons[i].button, FALSE); } return; failed: { - g_mutex_unlock (&state_mutex); - g_static_mutex_unlock (&app->state_mutex); ++ g_mutex_unlock (&app->state_mutex); g_print ("STOP failed\n"); - gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Stop failed"); + gtk_statusbar_push (GTK_STATUSBAR (app->statusbar), app->status_id, + "Stop failed"); } } @@@ -960,18 -1071,19 +1071,19 @@@ update_streams (SeekApp * app gboolean state; /* remove previous info */ - clear_streams (GST_ELEMENT_CAST (pipeline)); + clear_streams (app); - /* here we get and update the different streams detected by playbin2 */ + /* here we get and update the different streams detected by playbin */ - g_object_get (pipeline, "n-video", &n_video, NULL); - g_object_get (pipeline, "n-audio", &n_audio, NULL); - g_object_get (pipeline, "n-text", &n_text, NULL); + g_object_get (app->pipeline, "n-video", &app->n_video, NULL); + g_object_get (app->pipeline, "n-audio", &app->n_audio, NULL); + g_object_get (app->pipeline, "n-text", &app->n_text, NULL); - g_print ("video %d, audio %d, text %d\n", n_video, n_audio, n_text); + g_print ("video %d, audio %d, text %d\n", app->n_video, app->n_audio, + app->n_text); active_idx = 0; - for (i = 0; i < n_video; i++) { - g_signal_emit_by_name (pipeline, "get-video-tags", i, &tags); + for (i = 0; i < app->n_video; i++) { + g_signal_emit_by_name (app->pipeline, "get-video-tags", i, &tags); if (tags) { str = gst_structure_to_string ((GstStructure *) tags); g_print ("video %d: %s\n", i, str); @@@ -1088,10 -1206,10 +1206,10 @@@ init_visualization_features (SeekApp * { GList *list, *walk; - vis_entries = g_array_new (FALSE, FALSE, sizeof (VisEntry)); + app->vis_entries = g_array_new (FALSE, FALSE, sizeof (VisEntry)); - list = gst_registry_feature_filter (gst_registry_get_default (), + list = gst_registry_feature_filter (gst_registry_get (), - filter_features, FALSE, NULL); + filter_vis_features, FALSE, NULL); for (walk = list; walk; walk = g_list_next (walk)) { VisEntry entry; @@@ -1123,8 -1241,8 +1241,8 @@@ vis_combo_cb (GtkComboBox * combo, Seek if (!element) return; - /* set vis plugin for playbin2 */ + /* set vis plugin for playbin */ - g_object_set (pipeline, "vis-plugin", element, NULL); + g_object_set (app->pipeline, "vis-plugin", element, NULL); } } @@@ -1158,26 -1277,60 +1277,58 @@@ volume_notify_idle_cb (SeekApp * app } static void - shot_cb (GtkButton * button, gpointer data) + volume_notify_cb (GstElement * pipeline, GParamSpec * arg, SeekApp * app) + { + /* Do this from the main thread */ + g_idle_add ((GSourceFunc) volume_notify_idle_cb, app); + } + + static gboolean + mute_notify_idle_cb (SeekApp * app) + { + gboolean cur_mute, new_mute; + + g_object_get (app->pipeline, "mute", &new_mute, NULL); + cur_mute = + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (app->mute_checkbox)); + if (cur_mute != new_mute) { + g_signal_handlers_block_by_func (app->mute_checkbox, mute_toggle_cb, app); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->mute_checkbox), + new_mute); + g_signal_handlers_unblock_by_func (app->mute_checkbox, mute_toggle_cb, app); + } + + return FALSE; + } + + static void + mute_notify_cb (GstElement * pipeline, GParamSpec * arg, SeekApp * app) + { + /* Do this from the main thread */ + g_idle_add ((GSourceFunc) mute_notify_idle_cb, app); + } + + static void + shot_cb (GtkButton * button, SeekApp * app) { - GstBuffer *buffer; + GstSample *sample = NULL; GstCaps *caps; + GST_DEBUG ("taking snapshot"); + /* convert to our desired format (RGB24) */ - caps = gst_caps_new_simple ("video/x-raw-rgb", - "bpp", G_TYPE_INT, 24, "depth", G_TYPE_INT, 24, + caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "RGB", /* Note: we don't ask for a specific width/height here, so that * videoscale can adjust dimensions from a non-1/1 pixel aspect * ratio to a 1/1 pixel-aspect-ratio */ - "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, - "endianness", G_TYPE_INT, G_BIG_ENDIAN, - "red_mask", G_TYPE_INT, 0xff0000, - "green_mask", G_TYPE_INT, 0x00ff00, - "blue_mask", G_TYPE_INT, 0x0000ff, NULL); - - /* convert the latest frame to the requested format */ - g_signal_emit_by_name (app->pipeline, "convert-frame", caps, &buffer); + "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, NULL); + + /* convert the latest sample to the requested format */ - g_signal_emit_by_name (pipeline, "convert-sample", caps, &sample); ++ g_signal_emit_by_name (app->pipeline, "convert-sample", caps, &sample); gst_caps_unref (caps); - if (buffer) { + if (sample) { + GstBuffer *buffer; GstCaps *caps; GstStructure *s; gboolean res; @@@ -1333,10 -1479,10 +1481,10 @@@ msg_sync_step_done (GstBus * bus, GstMe return; } - if (g_mutex_trylock (&state_mutex)) { - if (shuttling) - do_shuttle (element); - g_mutex_unlock (&state_mutex); - if (g_static_mutex_trylock (&app->state_mutex)) { ++ if (g_mutex_trylock (&app->state_mutex)) { + if (app->shuttling) + do_shuttle (app); - g_static_mutex_unlock (&app->state_mutex); ++ g_mutex_unlock (&app->state_mutex); } else { /* ignore step messages that come while we are doing a state change */ g_print ("state change is busy\n"); @@@ -1430,17 -1577,166 +1579,171 @@@ shuttle_value_changed (GtkRange * range } static void - msg_async_done (GstBus * bus, GstMessage * message, GstPipeline * pipeline) + colorbalance_value_changed (GtkRange * range, SeekApp * app) + { + const gchar *label; + gdouble val; + gint ival; + GstColorBalanceChannel *channel = NULL; + const GList *channels, *l; + + if (range == GTK_RANGE (app->contrast_scale)) + label = "CONTRAST"; + else if (range == GTK_RANGE (app->brightness_scale)) + label = "BRIGHTNESS"; + else if (range == GTK_RANGE (app->hue_scale)) + label = "HUE"; + else if (range == GTK_RANGE (app->saturation_scale)) + label = "SATURATION"; + else + g_assert_not_reached (); + + val = gtk_range_get_value (range); + + g_print ("colorbalance %s value changed %lf\n", label, val / N_GRAD); + + if (!app->colorbalance_element) { + find_interface_elements (app); + if (!app->colorbalance_element) + return; + } + + channels = + gst_color_balance_list_channels (GST_COLOR_BALANCE + (app->colorbalance_element)); + for (l = channels; l; l = l->next) { + GstColorBalanceChannel *tmp = l->data; + + if (g_strrstr (tmp->label, label)) { + channel = tmp; + break; + } + } + + if (!channel) + return; + + ival = + (gint) (0.5 + channel->min_value + + (val / N_GRAD) * ((gdouble) channel->max_value - + (gdouble) channel->min_value)); + gst_color_balance_set_value (GST_COLOR_BALANCE (app->colorbalance_element), + channel, ival); + } + + static void + seek_format_changed_cb (GtkComboBox * box, SeekApp * app) + { + gchar *format_str; + GList *l; + const GstFormatDefinition *format = NULL; + + format_str = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (box)); + + for (l = app->formats; l; l = l->next) { + const GstFormatDefinition *tmp = l->data; + + if (g_strcmp0 (tmp->nick, format_str) == 0) { + format = tmp; + break; + } + } + + if (!format) + goto done; + + app->seek_format = format; + update_scale (app); + + done: + g_free (format_str); + } + + static void + update_formats (SeekApp * app) + { + GstIterator *it; + gboolean done; + GList *l; - gpointer item; ++ GValue item = { 0, }; + gchar *selected; + gint selected_idx = 0, i; + + selected = + gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT + (app->seek_format_combo)); + if (selected == NULL) + selected = g_strdup ("time"); + + it = gst_format_iterate_definitions (); + done = FALSE; + + g_list_free (app->formats); + app->formats = NULL; + + while (!done) { + switch (gst_iterator_next (it, &item)) { - case GST_ITERATOR_OK: - app->formats = g_list_prepend (app->formats, item); ++ case GST_ITERATOR_OK:{ ++ GstFormatDefinition *def = g_value_get_pointer (&item); ++ ++ app->formats = g_list_prepend (app->formats, def); ++ g_value_reset (&item); + break; ++ } + case GST_ITERATOR_RESYNC: + g_list_free (app->formats); + app->formats = NULL; + gst_iterator_resync (it); + break; + case GST_ITERATOR_ERROR: + case GST_ITERATOR_DONE: + default: + done = TRUE; + break; + } + } ++ g_value_unset (&item); + + app->formats = g_list_reverse (app->formats); + gst_iterator_free (it); + + g_signal_handlers_block_by_func (app->seek_format_combo, + seek_format_changed_cb, app); + gtk_combo_box_text_remove_all (GTK_COMBO_BOX_TEXT (app->seek_format_combo)); + + for (i = 0, l = app->formats; l; l = l->next, i++) { + const GstFormatDefinition *def = l->data; + + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (app->seek_format_combo), + def->nick); + if (g_strcmp0 (def->nick, selected) == 0) + selected_idx = i; + } + g_signal_handlers_unblock_by_func (app->seek_format_combo, + seek_format_changed_cb, app); + + gtk_combo_box_set_active (GTK_COMBO_BOX (app->seek_format_combo), + selected_idx); + + g_free (selected); + } + + static void + msg_async_done (GstBus * bus, GstMessage * message, SeekApp * app) { GST_DEBUG ("async done"); + + /* Now query all available GstFormats */ + update_formats (app); + /* when we get ASYNC_DONE we can query position, duration and other * properties */ - update_scale (pipeline); + update_scale (app); /* update the available streams */ - update_streams (pipeline); + update_streams (app); - find_navigation_element (); + find_interface_elements (app); } static void @@@ -1606,30 -1904,105 +1911,106 @@@ msg_clock_lost (GstBus * bus, GstMessag } } - static GstElement *navigation_element = NULL; + static gboolean + is_valid_color_balance_element (GstElement * element) + { + GstColorBalance *bal = GST_COLOR_BALANCE (element); + gboolean have_brightness = FALSE; + gboolean have_contrast = FALSE; + gboolean have_hue = FALSE; + gboolean have_saturation = FALSE; + const GList *channels, *l; + + channels = gst_color_balance_list_channels (bal); + for (l = channels; l; l = l->next) { + GstColorBalanceChannel *ch = l->data; + + if (g_strrstr (ch->label, "BRIGHTNESS")) + have_brightness = TRUE; + else if (g_strrstr (ch->label, "CONTRAST")) + have_contrast = TRUE; + else if (g_strrstr (ch->label, "HUE")) + have_hue = TRUE; + else if (g_strrstr (ch->label, "SATURATION")) + have_saturation = TRUE; + } + + return have_brightness && have_contrast && have_hue && have_saturation; + } static void - find_navigation_element (void) + find_interface_elements (SeekApp * app) { - GstElement *video_sink; + GstIterator *it; - gpointer item; ++ GValue item = { 0, }; + gboolean done = FALSE, hardware = FALSE; - g_object_get (pipeline, "video-sink", &video_sink, NULL); - if (!video_sink) + if (app->pipeline_type == 0) return; - if (navigation_element) - gst_object_unref (navigation_element); + if (app->navigation_element) + gst_object_unref (app->navigation_element); + app->navigation_element = NULL; + + if (app->colorbalance_element) + gst_object_unref (app->colorbalance_element); + app->colorbalance_element = NULL; + + app->navigation_element = + gst_bin_get_by_interface (GST_BIN (app->pipeline), GST_TYPE_NAVIGATION); + + it = gst_bin_iterate_all_by_interface (GST_BIN (app->pipeline), + GST_TYPE_COLOR_BALANCE); + while (!done) { + switch (gst_iterator_next (it, &item)) { + case GST_ITERATOR_OK:{ - GstElement *element = GST_ELEMENT (item); ++ GstElement *element = GST_ELEMENT (g_value_get_object (&item)); + + if (is_valid_color_balance_element (element)) { + if (!app->colorbalance_element) { + app->colorbalance_element = + GST_ELEMENT_CAST (gst_object_ref (element)); + hardware = + (gst_color_balance_get_balance_type (GST_COLOR_BALANCE + (element)) == GST_COLOR_BALANCE_HARDWARE); + } else if (!hardware) { + gboolean tmp = + (gst_color_balance_get_balance_type (GST_COLOR_BALANCE + (element)) == GST_COLOR_BALANCE_HARDWARE); + + if (tmp) { + if (app->colorbalance_element) + gst_object_unref (app->colorbalance_element); + app->colorbalance_element = + GST_ELEMENT_CAST (gst_object_ref (element)); + hardware = TRUE; + } + } + } - if (GST_IS_NAVIGATION (video_sink)) { - navigation_element = gst_object_ref (video_sink); - } else if (GST_IS_BIN (video_sink)) { - navigation_element = - gst_bin_get_by_interface (GST_BIN (video_sink), GST_TYPE_NAVIGATION); - } else { - navigation_element = NULL; - gst_object_unref (element); ++ g_value_reset (&item); + + if (hardware && app->colorbalance_element) + done = TRUE; + break; + } + case GST_ITERATOR_RESYNC: + gst_iterator_resync (it); + done = FALSE; + hardware = FALSE; + if (app->colorbalance_element) + gst_object_unref (app->colorbalance_element); + app->colorbalance_element = NULL; + break; + case GST_ITERATOR_DONE: + case GST_ITERATOR_ERROR: + default: + done = TRUE; + } } - gst_object_unref (video_sink); ++ g_value_unset (&item); + gst_iterator_free (it); } /* called when Navigation command button is pressed */ @@@ -1658,40 -2036,35 +2044,35 @@@ navigation_cmd_cb (GtkButton * button, * or gconfvideosink may be used which create the actual videosink only once * the pipeline is started) */ static GstBusSyncReply - bus_sync_handler (GstBus * bus, GstMessage * message, GstPipeline * data) + bus_sync_handler (GstBus * bus, GstMessage * message, SeekApp * app) { - GstElement *element; - if ((GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT) && - gst_structure_has_name (message->structure, "prepare-xwindow-id")) { ++ if (gst_is_video_overlay_prepare_window_handle_message (message)) { + GstElement *element = GST_ELEMENT (GST_MESSAGE_SRC (message)); - if (!gst_is_video_overlay_prepare_window_handle_message (message)) - return GST_BUS_PASS; - if (app->xoverlay_element) - gst_object_unref (app->xoverlay_element); - app->xoverlay_element = GST_ELEMENT (gst_object_ref (element)); ++ if (app->overlay_element) ++ gst_object_unref (app->overlay_element); ++ app->overlay_element = GST_ELEMENT (gst_object_ref (element)); - element = GST_ELEMENT (GST_MESSAGE_SRC (message)); + g_print ("got prepare-xwindow-id, setting XID %" G_GUINTPTR_FORMAT "\n", + app->embed_xid); - if (overlay_element) - gst_object_unref (overlay_element); - overlay_element = GST_ELEMENT (gst_object_ref (element)); - - if (g_object_class_find_property (G_OBJECT_GET_CLASS (element), - "force-aspect-ratio")) { - g_object_set (element, "force-aspect-ratio", TRUE, NULL); - } - - /* Should have been initialised from main thread before (can't use - * GDK_WINDOW_XID here with Gtk+ >= 2.18, because the sync handler will - * be called from a streaming thread and GDK_WINDOW_XID maps to more than - * a simple structure lookup with Gtk+ >= 2.18, where 'more' is stuff that - * shouldn't be done from a non-GUI thread without explicit locking). */ - g_assert (embed_handle != 0); - - g_print ("got prepare-window-handle, setting handle %" G_GUINTPTR_FORMAT "\n", - embed_handle); + if (g_object_class_find_property (G_OBJECT_GET_CLASS (element), + "force-aspect-ratio")) { + g_object_set (element, "force-aspect-ratio", TRUE, NULL); + } - gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (element), - embed_handle); - gst_video_overlay_handle_events (GST_VIDEO_OVERLAY (element), FALSE); + /* Should have been initialised from main thread before (can't use + * GDK_WINDOW_XID here with Gtk+ >= 2.18, because the sync handler will + * be called from a streaming thread and GDK_WINDOW_XID maps to more than + * a simple structure lookup with Gtk+ >= 2.18, where 'more' is stuff that + * shouldn't be done from a non-GUI thread without explicit locking). */ + g_assert (app->embed_xid != 0); - find_navigation_element (); - gst_x_overlay_set_window_handle (GST_X_OVERLAY (element), app->embed_xid); ++ gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (element), ++ app->embed_xid); + find_interface_elements (app); + } return GST_BUS_PASS; } #endif @@@ -1710,8 -2083,8 +2091,8 @@@ draw_cb (GtkWidget * widget, cairo_t * return TRUE; } - if (overlay_element) - gst_video_overlay_expose (GST_VIDEO_OVERLAY (overlay_element)); - if (app->xoverlay_element) - gst_x_overlay_expose (GST_X_OVERLAY (app->xoverlay_element)); ++ if (app->overlay_element) ++ gst_video_overlay_expose (GST_VIDEO_OVERLAY (app->overlay_element)); return FALSE; } @@@ -1874,14 -2249,15 +2257,15 @@@ msg (GstBus * bus, GstMessage * message } static void - connect_bus_signals (GstElement * pipeline) + connect_bus_signals (SeekApp * app) { - GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); + GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (app->pipeline)); #if defined (GDK_WINDOWING_X11) || defined (GDK_WINDOWING_WIN32) || defined (GDK_WINDOWING_QUARTZ) - /* handle prepare-window-handle element message synchronously */ - gst_bus_set_sync_handler (bus, (GstBusSyncHandler) bus_sync_handler, - pipeline); + if (app->pipeline_type != 0) { - /* handle prepare-xwindow-id element message synchronously, but only for non-playbin2 */ ++ /* handle prepare-xwindow-id element message synchronously, but only for non-playbin */ + gst_bus_set_sync_handler (bus, (GstBusSyncHandler) bus_sync_handler, app); + } #endif gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH); @@@ -2320,82 -2907,135 +2915,135 @@@ create_ui (SeekApp * app /* seek bar */ adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.00, N_GRAD, 0.1, 1.0, 1.0)); - hscale = gtk_hscale_new (adjustment); - gtk_scale_set_digits (GTK_SCALE (hscale), 2); - gtk_scale_set_value_pos (GTK_SCALE (hscale), GTK_POS_RIGHT); - gtk_range_set_show_fill_level (GTK_RANGE (hscale), TRUE); - gtk_range_set_fill_level (GTK_RANGE (hscale), N_GRAD); - - g_signal_connect (hscale, "button_press_event", G_CALLBACK (start_seek), - pipeline); - g_signal_connect (hscale, "button_release_event", G_CALLBACK (stop_seek), - pipeline); - g_signal_connect (hscale, "format_value", G_CALLBACK (format_value), - pipeline); - - if (pipeline_type == 0) { + app->seek_scale = gtk_hscale_new (adjustment); + gtk_scale_set_digits (GTK_SCALE (app->seek_scale), 2); + gtk_scale_set_value_pos (GTK_SCALE (app->seek_scale), GTK_POS_RIGHT); + gtk_range_set_show_fill_level (GTK_RANGE (app->seek_scale), TRUE); + gtk_range_set_fill_level (GTK_RANGE (app->seek_scale), N_GRAD); + + g_signal_connect (app->seek_scale, "button_press_event", + G_CALLBACK (start_seek), app); + g_signal_connect (app->seek_scale, "button_release_event", + G_CALLBACK (stop_seek), app); + g_signal_connect (app->seek_scale, "format_value", G_CALLBACK (format_value), + app); + + if (app->pipeline_type == 0) { + GtkWidget *pb2vbox, *boxes, *boxes2, *panel, *boxes3; + GtkWidget *volume_label, *shot_button; + GtkWidget *label; + - playbin = gtk_expander_new ("playbin2 options"); - /* the playbin2 panel controls for the video/audio/subtitle tracks */ ++ playbin = gtk_expander_new ("playbin options"); + /* the playbin panel controls for the video/audio/subtitle tracks */ panel = gtk_hbox_new (FALSE, 0); - video_combo = gtk_combo_box_text_new (); - audio_combo = gtk_combo_box_text_new (); - text_combo = gtk_combo_box_text_new (); - gtk_widget_set_sensitive (video_combo, FALSE); - gtk_widget_set_sensitive (audio_combo, FALSE); - gtk_widget_set_sensitive (text_combo, FALSE); - gtk_box_pack_start (GTK_BOX (panel), video_combo, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (panel), audio_combo, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (panel), text_combo, TRUE, TRUE, 2); - g_signal_connect (G_OBJECT (video_combo), "changed", - G_CALLBACK (video_combo_cb), pipeline); - g_signal_connect (G_OBJECT (audio_combo), "changed", - G_CALLBACK (audio_combo_cb), pipeline); - g_signal_connect (G_OBJECT (text_combo), "changed", - G_CALLBACK (text_combo_cb), pipeline); + app->video_combo = gtk_combo_box_text_new (); + app->audio_combo = gtk_combo_box_text_new (); + app->text_combo = gtk_combo_box_text_new (); + gtk_widget_set_sensitive (app->video_combo, FALSE); + gtk_widget_set_sensitive (app->audio_combo, FALSE); + gtk_widget_set_sensitive (app->text_combo, FALSE); + gtk_box_pack_start (GTK_BOX (panel), app->video_combo, TRUE, TRUE, 2); + gtk_box_pack_start (GTK_BOX (panel), app->audio_combo, TRUE, TRUE, 2); + gtk_box_pack_start (GTK_BOX (panel), app->text_combo, TRUE, TRUE, 2); + g_signal_connect (G_OBJECT (app->video_combo), "changed", + G_CALLBACK (video_combo_cb), app); + g_signal_connect (G_OBJECT (app->audio_combo), "changed", + G_CALLBACK (audio_combo_cb), app); + g_signal_connect (G_OBJECT (app->text_combo), "changed", + G_CALLBACK (text_combo_cb), app); - /* playbin2 panel for flag checkboxes and volume/mute */ + /* playbin panel for flag checkboxes and volume/mute */ - boxes = gtk_hbox_new (FALSE, 0); - vis_checkbox = gtk_check_button_new_with_label ("Vis"); - video_checkbox = gtk_check_button_new_with_label ("Video"); - audio_checkbox = gtk_check_button_new_with_label ("Audio"); - text_checkbox = gtk_check_button_new_with_label ("Text"); - mute_checkbox = gtk_check_button_new_with_label ("Mute"); - download_checkbox = gtk_check_button_new_with_label ("Download"); - buffer_checkbox = gtk_check_button_new_with_label ("Buffer"); + boxes = gtk_grid_new (); + gtk_grid_set_row_spacing (GTK_GRID (boxes), 2); + gtk_grid_set_row_homogeneous (GTK_GRID (boxes), FALSE); + gtk_grid_set_column_spacing (GTK_GRID (boxes), 2); + gtk_grid_set_column_homogeneous (GTK_GRID (boxes), TRUE); + + app->video_checkbox = gtk_check_button_new_with_label ("Video"); + app->audio_checkbox = gtk_check_button_new_with_label ("Audio"); + app->text_checkbox = gtk_check_button_new_with_label ("Text"); + app->vis_checkbox = gtk_check_button_new_with_label ("Vis"); + app->soft_volume_checkbox = gtk_check_button_new_with_label ("Soft Volume"); + app->native_audio_checkbox = + gtk_check_button_new_with_label ("Native Audio"); + app->native_video_checkbox = + gtk_check_button_new_with_label ("Native Video"); + app->download_checkbox = gtk_check_button_new_with_label ("Download"); + app->buffering_checkbox = gtk_check_button_new_with_label ("Buffering"); + app->deinterlace_checkbox = gtk_check_button_new_with_label ("Deinterlace"); + app->soft_colorbalance_checkbox = + gtk_check_button_new_with_label ("Soft Colorbalance"); + app->mute_checkbox = gtk_check_button_new_with_label ("Mute"); volume_label = gtk_label_new ("Volume"); - volume_spinbutton = gtk_spin_button_new_with_range (0, 10.0, 0.1); - gtk_spin_button_set_value (GTK_SPIN_BUTTON (volume_spinbutton), 1.0); - gtk_box_pack_start (GTK_BOX (boxes), video_checkbox, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (boxes), audio_checkbox, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (boxes), text_checkbox, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (boxes), vis_checkbox, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (boxes), mute_checkbox, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (boxes), download_checkbox, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (boxes), buffer_checkbox, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (boxes), volume_label, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (boxes), volume_spinbutton, TRUE, TRUE, 2); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (vis_checkbox), FALSE); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (audio_checkbox), TRUE); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (video_checkbox), TRUE); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_checkbox), TRUE); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mute_checkbox), FALSE); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (download_checkbox), FALSE); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (buffer_checkbox), FALSE); - g_signal_connect (G_OBJECT (vis_checkbox), "toggled", - G_CALLBACK (vis_toggle_cb), pipeline); - g_signal_connect (G_OBJECT (audio_checkbox), "toggled", - G_CALLBACK (audio_toggle_cb), pipeline); - g_signal_connect (G_OBJECT (video_checkbox), "toggled", - G_CALLBACK (video_toggle_cb), pipeline); - g_signal_connect (G_OBJECT (text_checkbox), "toggled", - G_CALLBACK (text_toggle_cb), pipeline); - g_signal_connect (G_OBJECT (mute_checkbox), "toggled", - G_CALLBACK (mute_toggle_cb), pipeline); - g_signal_connect (G_OBJECT (download_checkbox), "toggled", - G_CALLBACK (download_toggle_cb), pipeline); - g_signal_connect (G_OBJECT (buffer_checkbox), "toggled", - G_CALLBACK (buffer_toggle_cb), pipeline); - g_signal_connect (G_OBJECT (volume_spinbutton), "value_changed", - G_CALLBACK (volume_spinbutton_changed_cb), pipeline); + app->volume_spinbutton = gtk_spin_button_new_with_range (0, 10.0, 0.1); + + gtk_grid_attach (GTK_GRID (boxes), app->video_checkbox, 0, 0, 1, 1); + gtk_grid_attach (GTK_GRID (boxes), app->audio_checkbox, 1, 0, 1, 1); + gtk_grid_attach (GTK_GRID (boxes), app->text_checkbox, 2, 0, 1, 1); + gtk_grid_attach (GTK_GRID (boxes), app->vis_checkbox, 3, 0, 1, 1); + gtk_grid_attach (GTK_GRID (boxes), app->soft_volume_checkbox, 4, 0, 1, 1); + gtk_grid_attach (GTK_GRID (boxes), app->native_audio_checkbox, 5, 0, 1, 1); + gtk_grid_attach (GTK_GRID (boxes), app->native_video_checkbox, 0, 1, 1, 1); + gtk_grid_attach (GTK_GRID (boxes), app->download_checkbox, 1, 1, 1, 1); + gtk_grid_attach (GTK_GRID (boxes), app->buffering_checkbox, 2, 1, 1, 1); + gtk_grid_attach (GTK_GRID (boxes), app->deinterlace_checkbox, 3, 1, 1, 1); + gtk_grid_attach (GTK_GRID (boxes), app->soft_colorbalance_checkbox, 4, 1, 1, + 1); + + gtk_grid_attach (GTK_GRID (boxes), app->mute_checkbox, 7, 0, 2, 1); + gtk_grid_attach (GTK_GRID (boxes), volume_label, 6, 1, 1, 1); + gtk_grid_attach (GTK_GRID (boxes), app->volume_spinbutton, 7, 1, 1, 1); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->video_checkbox), + TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->audio_checkbox), + TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->text_checkbox), TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->vis_checkbox), FALSE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->soft_volume_checkbox), + TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON + (app->native_audio_checkbox), FALSE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON + (app->native_video_checkbox), FALSE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->download_checkbox), + FALSE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->buffering_checkbox), + FALSE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->deinterlace_checkbox), + FALSE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON + (app->soft_colorbalance_checkbox), TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->mute_checkbox), + FALSE); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (app->volume_spinbutton), 1.0); + + g_signal_connect (G_OBJECT (app->video_checkbox), "toggled", + G_CALLBACK (video_toggle_cb), app); + g_signal_connect (G_OBJECT (app->audio_checkbox), "toggled", + G_CALLBACK (audio_toggle_cb), app); + g_signal_connect (G_OBJECT (app->text_checkbox), "toggled", + G_CALLBACK (text_toggle_cb), app); + g_signal_connect (G_OBJECT (app->vis_checkbox), "toggled", + G_CALLBACK (vis_toggle_cb), app); + g_signal_connect (G_OBJECT (app->soft_volume_checkbox), "toggled", + G_CALLBACK (soft_volume_toggle_cb), app); + g_signal_connect (G_OBJECT (app->native_audio_checkbox), "toggled", + G_CALLBACK (native_audio_toggle_cb), app); + g_signal_connect (G_OBJECT (app->native_video_checkbox), "toggled", + G_CALLBACK (native_video_toggle_cb), app); + g_signal_connect (G_OBJECT (app->download_checkbox), "toggled", + G_CALLBACK (download_toggle_cb), app); + g_signal_connect (G_OBJECT (app->buffering_checkbox), "toggled", + G_CALLBACK (buffering_toggle_cb), app); + g_signal_connect (G_OBJECT (app->deinterlace_checkbox), "toggled", + G_CALLBACK (deinterlace_toggle_cb), app); + g_signal_connect (G_OBJECT (app->soft_colorbalance_checkbox), "toggled", + G_CALLBACK (soft_colorbalance_toggle_cb), app); + g_signal_connect (G_OBJECT (app->mute_checkbox), "toggled", + G_CALLBACK (mute_toggle_cb), app); + g_signal_connect (G_OBJECT (app->volume_spinbutton), "value-changed", + G_CALLBACK (volume_spinbutton_changed_cb), app); - /* playbin2 panel for snapshot */ + /* playbin panel for snapshot */ boxes2 = gtk_hbox_new (FALSE, 0); shot_button = gtk_button_new_from_stock (GTK_STOCK_SAVE); gtk_widget_set_tooltip_text (shot_button, @@@ -2455,45 -3174,163 +3182,158 @@@ /* connect things ... */ g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb), - pipeline); + app); g_signal_connect (G_OBJECT (pause_button), "clicked", G_CALLBACK (pause_cb), - pipeline); + app); g_signal_connect (G_OBJECT (stop_button), "clicked", G_CALLBACK (stop_cb), - pipeline); - g_signal_connect (G_OBJECT (accurate_checkbox), "toggled", - G_CALLBACK (accurate_toggle_cb), pipeline); - g_signal_connect (G_OBJECT (key_checkbox), "toggled", - G_CALLBACK (key_toggle_cb), pipeline); - g_signal_connect (G_OBJECT (loop_checkbox), "toggled", - G_CALLBACK (loop_toggle_cb), pipeline); - g_signal_connect (G_OBJECT (flush_checkbox), "toggled", - G_CALLBACK (flush_toggle_cb), pipeline); - g_signal_connect (G_OBJECT (scrub_checkbox), "toggled", - G_CALLBACK (scrub_toggle_cb), pipeline); - g_signal_connect (G_OBJECT (play_scrub_checkbox), "toggled", - G_CALLBACK (play_scrub_toggle_cb), pipeline); - g_signal_connect (G_OBJECT (skip_checkbox), "toggled", - G_CALLBACK (skip_toggle_cb), pipeline); - g_signal_connect (G_OBJECT (rate_spinbutton), "value_changed", - G_CALLBACK (rate_spinbutton_changed_cb), pipeline); - - g_signal_connect (G_OBJECT (window), "delete-event", delete_event_cb, NULL); + app); + + g_signal_connect (G_OBJECT (app->window), "delete-event", + G_CALLBACK (delete_event_cb), app); + } + + static void + set_defaults (SeekApp * app) + { + memset (app, 0, sizeof (SeekApp)); + + app->flush_seek = TRUE; + app->scrub = TRUE; + app->rate = 1.0; + + app->position = app->duration = -1; + app->state = GST_STATE_NULL; + + app->need_streams = TRUE; + - g_static_mutex_init (&app->state_mutex); ++ g_mutex_init (&app->state_mutex); + + app->play_rate = 1.0; + } + + static void + reset_app (SeekApp * app) + { + g_free (app->audiosink_str); + g_free (app->videosink_str); + + g_list_free (app->formats); + - g_static_mutex_free (&app->state_mutex); ++ g_mutex_clear (&app->state_mutex); + - if (app->xoverlay_element) - gst_object_unref (app->xoverlay_element); ++ if (app->overlay_element) ++ gst_object_unref (app->overlay_element); + if (app->navigation_element) + gst_object_unref (app->navigation_element); + + g_list_foreach (app->paths, (GFunc) g_free, NULL); + g_list_free (app->paths); + g_list_foreach (app->sub_paths, (GFunc) g_free, NULL); + g_list_free (app->sub_paths); + + g_print ("free pipeline\n"); + gst_object_unref (app->pipeline); + } + + int + main (int argc, char **argv) + { + SeekApp app; + GOptionEntry options[] = { + {"stats", 's', 0, G_OPTION_ARG_NONE, &app.stats, + "Show pad stats", NULL}, + {"verbose", 'v', 0, G_OPTION_ARG_NONE, &app.verbose, + "Verbose properties", NULL}, + {NULL} + }; + GOptionContext *ctx; + GError *err = NULL; + + set_defaults (&app); + -#if !GLIB_CHECK_VERSION (2, 31, 0) - if (!g_thread_supported ()) - g_thread_init (NULL); -#endif - + ctx = g_option_context_new ("- test seeking in gsteamer"); + g_option_context_add_main_entries (ctx, options, NULL); + g_option_context_add_group (ctx, gst_init_get_option_group ()); + g_option_context_add_group (ctx, gtk_get_option_group (TRUE)); + + if (!g_option_context_parse (ctx, &argc, &argv, &err)) { + g_print ("Error initializing: %s\n", err->message); + exit (1); + } + + GST_DEBUG_CATEGORY_INIT (seek_debug, "seek", 0, "seek example"); + + if (argc < 3) { + print_usage (argc, argv); + exit (-1); + } + + app.pipeline_type = atoi (argv[1]); + + if (app.pipeline_type < 0 || app.pipeline_type >= G_N_ELEMENTS (pipelines)) { + print_usage (argc, argv); + exit (-1); + } + + app.pipeline_spec = argv[2]; + + if (g_path_is_absolute (app.pipeline_spec) && + (g_strrstr (app.pipeline_spec, "*") != NULL || + g_strrstr (app.pipeline_spec, "?") != NULL)) { + app.paths = handle_wildcards (app.pipeline_spec); + } else { + app.paths = g_list_prepend (app.paths, g_strdup (app.pipeline_spec)); + } + + if (!app.paths) { + g_print ("opening %s failed\n", app.pipeline_spec); + exit (-1); + } + + app.current_path = app.paths; + + if (argc > 3 && argv[3]) { + if (g_path_is_absolute (argv[3]) && + (g_strrstr (argv[3], "*") != NULL || + g_strrstr (argv[3], "?") != NULL)) { + app.sub_paths = handle_wildcards (argv[3]); + } else { + app.sub_paths = g_list_prepend (app.sub_paths, g_strdup (argv[3])); + } + + if (!app.sub_paths) { + g_print ("opening %s failed\n", argv[3]); + exit (-1); + } + + app.current_sub_path = app.sub_paths; + } + + pipelines[app.pipeline_type].func (&app, app.current_path->data); + g_assert (app.pipeline); + + create_ui (&app); /* show the gui. */ - gtk_widget_show_all (window); + gtk_widget_show_all (app.window); /* realize window now so that the video window gets created and we can * obtain its XID before the pipeline is started up and the videosink * asks for the XID of the window to render onto */ - gtk_widget_realize (window); + gtk_widget_realize (app.window); #if defined (GDK_WINDOWING_X11) || defined (GDK_WINDOWING_WIN32) || defined (GDK_WINDOWING_QUARTZ) - /* we should have the handle now */ - g_assert (embed_handle != 0); + /* we should have the XID now */ + g_assert (app.embed_xid != 0); + + if (app.pipeline_type == 0) { - gst_x_overlay_set_window_handle (GST_X_OVERLAY (app.pipeline), ++ gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (app.pipeline), + app.embed_xid); + } #endif - if (verbose) { - g_signal_connect (pipeline, "deep_notify", + if (app.verbose) { + g_signal_connect (app.pipeline, "deep_notify", G_CALLBACK (gst_object_default_deep_notify), NULL); }