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
This commit is contained in:
Sebastian Dröge 2012-03-02 10:00:55 +01:00
commit f7939bb43f
30 changed files with 3264 additions and 1234 deletions

View file

@ -35,6 +35,9 @@ then
ln -s ../../common/hooks/pre-commit.hook .git/hooks/pre-commit
fi
# GNU gettext automake support doesn't get along with git.
# https://bugzilla.gnome.org/show_bug.cgi?id=661128
touch -t 200001010000 po/gst-plugins-base-0.10.pot
CONFIGURE_DEF_OPT='--enable-maintainer-mode --enable-gtk-doc'

View file

@ -19,6 +19,10 @@
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
* with newer GLib versions (>= 2.31.0) */
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

View file

@ -1361,7 +1361,7 @@ theora_enc_encode_and_push (GstTheoraEnc * enc, ogg_packet op,
GstClockTime next_time, duration;
GstClockTime timestamp = 0;
GST_DEBUG_OBJECT (enc, "encoded. granule:%" G_GINT64_FORMAT ", packet:%p, "
"bytes:%ld", op.granulepos, op.packet, op.bytes);
"bytes:%ld", (gint64) op.granulepos, op.packet, op.bytes);
next_time = th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
duration = next_time - enc->next_ts;

View file

@ -56,6 +56,10 @@
* Last reviewed on 2008-05-28 (0.10.20)
*/
/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
* with newer GLib versions (>= 2.31.0) */
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

View file

@ -158,6 +158,7 @@ static gboolean gst_app_sink_unlock_stop (GstBaseSink * bsink);
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 (GstBaseSink * psink,
@ -337,6 +338,7 @@ gst_app_sink_class_init (GstAppSinkClass * klass)
basesink_class->render = gst_app_sink_render;
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_sample = gst_app_sink_pull_sample;
@ -774,6 +776,30 @@ gst_app_sink_getcaps (GstBaseSink * psink, GstCaps * filter)
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;
}
/* external API */
/**

View file

@ -83,9 +83,8 @@ gst_mixer_get_type (void)
static void
gst_mixer_class_init (GstMixerInterface * iface)
{
iface->mixer_type = GST_MIXER_SOFTWARE;
/* default virtual functions */
iface->get_mixer_type = NULL;
iface->list_tracks = NULL;
iface->set_volume = NULL;
iface->get_volume = NULL;
@ -304,7 +303,8 @@ gst_mixer_get_mixer_type (GstMixer * mixer)
{
GstMixerInterface *iface = GST_MIXER_GET_INTERFACE (mixer);
return iface->mixer_type;
g_return_val_if_fail (iface->get_mixer_type != NULL, GST_MIXER_SOFTWARE);
return iface->get_mixer_type (mixer);
}
/**

View file

@ -37,8 +37,6 @@ G_BEGIN_DECLS
#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 _GstMixerInterface GstMixerInterface;
@ -112,8 +110,6 @@ typedef enum
struct _GstMixerInterface {
GTypeInterface iface;
GstMixerType mixer_type;
/* virtual functions */
const GList * (* list_tracks) (GstMixer *mixer);
@ -137,6 +133,8 @@ struct _GstMixerInterface {
GstMixerOptions *opts);
GstMixerFlags (* get_mixer_flags) (GstMixer *mixer);
GstMixerType (* get_mixer_type) (GstMixer *mixer);
};
GType gst_mixer_get_type (void);

View file

@ -31,6 +31,10 @@
* </refsect2>
*/
/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
* with newer GLib versions (>= 2.31.0) */
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

View file

@ -44,7 +44,7 @@ typedef struct _GstNavigationInterface GstNavigationInterface;
* @iface: the parent interface
* @send_event: sending a navigation event
*
* Color-balance interface.
* Navigation interface.
*/
struct _GstNavigationInterface {
GTypeInterface iface;

View file

@ -173,9 +173,11 @@ xmp_tag_type_get_name (GstXmpTagType tagtype)
case GstXmpTagTypeBag:
return "rdf:Bag";
default:
g_assert_not_reached ();
break;
}
return NULL; /* make compiler happy with -DG_DISABLE_ASSERT */
/* Make compiler happy */
g_return_val_if_reached ("");
}
struct _PendingXmpTag

View file

@ -106,12 +106,11 @@ gst_color_balance_class_init (GstColorBalanceInterface * iface)
initialized = TRUE;
}
iface->balance_type = GST_COLOR_BALANCE_SOFTWARE;
/* default virtual functions */
iface->list_channels = NULL;
iface->set_value = NULL;
iface->get_value = NULL;
iface->get_balance_type = NULL;
}
/**
@ -215,7 +214,10 @@ gst_color_balance_get_balance_type (GstColorBalance * balance)
iface = GST_COLOR_BALANCE_GET_INTERFACE (balance);
return iface->balance_type;
g_return_val_if_fail (iface->get_balance_type != NULL,
GST_COLOR_BALANCE_SOFTWARE);
return iface->get_balance_type (balance);
}
/**

View file

@ -36,8 +36,6 @@ G_BEGIN_DECLS
#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 _GstColorBalanceInterface GstColorBalanceInterface;
@ -73,8 +71,6 @@ typedef enum
struct _GstColorBalanceInterface {
GTypeInterface iface;
GstColorBalanceType balance_type;
/* virtual functions */
const GList * (* list_channels) (GstColorBalance *balance);
@ -83,11 +79,15 @@ struct _GstColorBalanceInterface {
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);
/*< private >*/
gpointer _gst_reserved[GST_PADDING-1];
};
GType gst_color_balance_get_type (void);

View file

@ -116,8 +116,8 @@ 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, const GstCaps * caps);
@ -131,8 +131,6 @@ static GstFlowReturn gst_adder_do_clip (GstCollectPads2 * pads,
gpointer user_data);
static GstFlowReturn gst_adder_collected (GstCollectPads2 * pads,
gpointer user_data);
static gboolean gst_adder_event (GstCollectPads2 * pads, GstCollectData2 * pad,
GstEvent * event, gpointer user_data);
/* non-clipping versions (for float) */
#define MAKE_FUNC_NC(name,type) \
@ -561,6 +559,8 @@ gst_adder_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
return res;
}
/* event handling */
typedef struct
{
GstEvent *event;
@ -763,14 +763,13 @@ 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;
GstAdder *adder = GST_ADDER (user_data);
gboolean res = FALSE;
adder = GST_ADDER (parent);
GST_DEBUG_OBJECT (pad, "Got %s event on sink pad",
GST_DEBUG_OBJECT (pad->pad, "Got %s event on sink pad",
GST_EVENT_TYPE_NAME (event));
switch (GST_EVENT_TYPE (event)) {
@ -779,34 +778,40 @@ gst_adder_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
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);
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_SEGMENT:
if (g_atomic_int_compare_and_exchange (&adder->wait_for_new_segment,
TRUE, FALSE)) {
@ -814,16 +819,19 @@ gst_adder_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
* 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;
}
/* now GstCollectPads2 can take care of the rest, e.g. EOS */
ret = adder->collect_event (pad, parent, event);
beach:
return ret;
return res;
}
static void
@ -892,7 +900,7 @@ gst_adder_init (GstAdder * adder)
gst_collect_pads2_set_clip_function (adder->collect,
GST_DEBUG_FUNCPTR (gst_adder_do_clip), adder);
gst_collect_pads2_set_event_function (adder->collect,
GST_DEBUG_FUNCPTR (gst_adder_event), adder);
GST_DEBUG_FUNCPTR (gst_adder_sink_event), adder);
}
static void
@ -992,12 +1000,6 @@ gst_adder_request_new_pad (GstElement * element, GstPadTemplate * templ,
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;
@ -1218,7 +1220,7 @@ gst_adder_collected (GstCollectPads2 * pads, gpointer user_data)
if (event) {
if (!gst_pad_push_event (adder->srcpad, event)) {
GST_WARNING_OBJECT (adder->srcpad, "Sending event failed");
GST_WARNING_OBJECT (adder->srcpad, "Sending new segment event failed");
}
} else {
GST_WARNING_OBJECT (adder->srcpad, "Creating new segment event for "
@ -1292,32 +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)
{
@ -1359,7 +1335,6 @@ gst_adder_change_state (GstElement * element, GstStateChange transition)
return ret;
}
static gboolean
plugin_init (GstPlugin * plugin)
{

View file

@ -65,7 +65,6 @@ struct _GstAdder {
gint64 offset;
/* sink event handling */
GstPadEventFunction collect_event;
GstSegment segment;
volatile gboolean new_segment_pending;
volatile gboolean wait_for_new_segment;

View file

@ -65,6 +65,8 @@ gst_play_flags_get_type (void)
"buffering"},
{C_FLAGS (GST_PLAY_FLAG_DEINTERLACE), "Deinterlace video if necessary",
"deinterlace"},
{C_FLAGS (GST_PLAY_FLAG_SOFT_COLORBALANCE), "Use software color balance",
"soft-colorbalance"},
{0, NULL, NULL}
};
static volatile GType id = 0;

View file

@ -70,7 +70,8 @@ typedef enum {
GST_PLAY_FLAG_NATIVE_VIDEO = (1 << 6),
GST_PLAY_FLAG_DOWNLOAD = (1 << 7),
GST_PLAY_FLAG_BUFFERING = (1 << 8),
GST_PLAY_FLAG_DEINTERLACE = (1 << 9)
GST_PLAY_FLAG_DEINTERLACE = (1 << 9),
GST_PLAY_FLAG_SOFT_COLORBALANCE = (1 << 10)
} GstPlayFlags;
#define GST_TYPE_PLAY_FLAGS (gst_play_flags_get_type())

View file

@ -169,7 +169,7 @@
* <title>Embedding the video window in your application</title>
* 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.
* </refsect2>
* <refsect2>
@ -229,15 +229,15 @@
#include <gst/gst-i18n-plugin.h>
#include <gst/pbutils/pbutils.h>
#include <gst/audio/streamvolume.h>
#include <gst/video/videooverlay.h>
#include <gst/interfaces/navigation.h>
#include <gst/video/colorbalance.h>
#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
@ -458,7 +458,7 @@ struct _GstPlayBinClass
#define DEFAULT_SUBURI NULL
#define DEFAULT_SOURCE NULL
#define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
GST_PLAY_FLAG_SOFT_VOLUME
GST_PLAY_FLAG_SOFT_VOLUME | GST_PLAY_FLAG_SOFT_COLORBALANCE
#define DEFAULT_N_VIDEO 0
#define DEFAULT_CURRENT_VIDEO -1
#define DEFAULT_N_AUDIO 0
@ -580,6 +580,12 @@ if (id) { \
id = 0; \
}
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 +607,30 @@ gst_play_bin_get_type (void)
static const GInterfaceInfo svol_info = {
NULL, NULL, NULL
};
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,
"GstPlayBin", &gst_play_bin_info, 0);
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_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;
@ -1217,6 +1241,13 @@ notify_mute_cb (GObject * selector, GParamSpec * pspec, GstPlayBin * playbin)
g_object_notify (G_OBJECT (playbin), "mute");
}
static void
colorbalance_value_changed_cb (GstColorBalance * balance,
GstColorBalanceChannel * channel, gint value, GstPlayBin * playbin)
{
gst_color_balance_value_changed (GST_COLOR_BALANCE (playbin), channel, value);
}
/* Must be called with elements lock! */
static void
gst_play_bin_update_elements_list (GstPlayBin * playbin)
@ -1260,7 +1291,8 @@ gst_play_bin_init (GstPlayBin * playbin)
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 */
@ -1268,6 +1300,8 @@ gst_play_bin_init (GstPlayBin * playbin)
G_CALLBACK (notify_volume_cb), playbin);
g_signal_connect (playbin->playsink, "notify::mute",
G_CALLBACK (notify_mute_cb), playbin);
g_signal_connect (playbin->playsink, "value-changed",
G_CALLBACK (colorbalance_value_changed_cb), playbin);
playbin->current_video = DEFAULT_CURRENT_VIDEO;
playbin->current_audio = DEFAULT_CURRENT_AUDIO;
@ -4026,6 +4060,121 @@ failure:
}
}
static void
gst_play_bin_overlay_expose (GstVideoOverlay * overlay)
{
GstPlayBin *playbin = GST_PLAY_BIN (overlay);
gst_video_overlay_expose (GST_VIDEO_OVERLAY (playbin->playsink));
}
static void
gst_play_bin_overlay_handle_events (GstVideoOverlay * overlay,
gboolean handle_events)
{
GstPlayBin *playbin = GST_PLAY_BIN (overlay);
gst_video_overlay_handle_events (GST_VIDEO_OVERLAY (playbin->playsink),
handle_events);
}
static void
gst_play_bin_overlay_set_render_rectangle (GstVideoOverlay * overlay, gint x,
gint y, gint width, gint height)
{
GstPlayBin *playbin = GST_PLAY_BIN (overlay);
gst_video_overlay_set_render_rectangle (GST_VIDEO_OVERLAY (playbin->playsink),
x, y, width, height);
}
static void
gst_play_bin_overlay_set_window_handle (GstVideoOverlay * overlay,
guintptr handle)
{
GstPlayBin *playbin = GST_PLAY_BIN (overlay);
gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (playbin->playsink),
handle);
}
static void
gst_play_bin_overlay_init (gpointer g_iface, gpointer g_iface_data)
{
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)
{
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)
{

View file

@ -28,6 +28,10 @@
#include <gst/gst-i18n-plugin.h>
#include <gst/pbutils/pbutils.h>
#include <gst/video/video.h>
#include <gst/audio/streamvolume.h>
#include <gst/video/colorbalance.h>
#include <gst/video/videooverlay.h>
#include <gst/interfaces/navigation.h>
#include "gstplaysink.h"
#include "gststreamsynchronizer.h"
@ -40,7 +44,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_play_sink_debug);
#define VOLUME_MAX_DOUBLE 10.0
#define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
GST_PLAY_FLAG_SOFT_VOLUME
GST_PLAY_FLAG_SOFT_VOLUME | GST_PLAY_FLAG_SOFT_COLORBALANCE
#define GST_PLAY_CHAIN(c) ((GstPlayChain *)(c))
@ -202,6 +206,20 @@ struct _GstPlaySink
gboolean volume_changed; /* volume/mute changed while no audiochain */
gboolean mute_changed; /* ... has been created yet */
gint64 av_offset;
/* 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 +342,40 @@ gst_play_marshal_SAMPLE__BOXED (GClosure * closure,
/* static guint gst_play_sink_signals[LAST_SIGNAL] = { 0 }; */
G_DEFINE_TYPE (GstPlaySink, gst_play_sink, GST_TYPE_BIN);
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 svol_info = {
NULL, NULL, NULL
};
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_STREAM_VOLUME, &svol_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)
@ -434,6 +485,7 @@ gst_play_sink_class_init (GstPlaySinkClass * klass)
g_param_spec_object ("audio-sink", "Audio Sink",
"the audio output element to use (NULL = default sink)",
GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstPlaySink:text-sink:
*
@ -505,6 +557,8 @@ gst_play_sink_class_init (GstPlaySinkClass * klass)
static void
gst_play_sink_init (GstPlaySink * playsink)
{
GstColorBalanceChannel *channel;
/* init groups */
playsink->video_sink = NULL;
playsink->audio_sink = NULL;
@ -522,6 +576,46 @@ gst_play_sink_init (GstPlaySink * playsink)
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
@ -613,6 +707,11 @@ gst_play_sink_dispose (GObject * object)
playsink->stream_synchronizer = NULL;
g_list_foreach (playsink->colorbalance_channels, (GFunc) gst_object_unref,
NULL);
g_list_free (playsink->colorbalance_channels);
playsink->colorbalance_channels = NULL;
G_OBJECT_CLASS (gst_play_sink_parent_class)->dispose (object);
}
@ -1231,6 +1330,149 @@ link_failed:
}
}
static gboolean
is_valid_color_balance_element (GstColorBalance * bal)
{
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 (const GValue * item, gpointer 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 (cb));
} else if (!*cb_out) {
*cb_out = GST_COLOR_BALANCE (gst_object_ref (cb));
}
}
}
static GstColorBalance *
find_color_balance_element (GstElement * element)
{
GstIterator *it;
GstColorBalance *cb = NULL;
if (GST_IS_COLOR_BALANCE (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.
*
@ -1298,6 +1540,13 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
chain->async = TRUE;
}
/* Make sure the aspect ratio is kept */
elem =
gst_play_sink_find_property_sinks (playsink, chain->sink,
"force-aspect-ratio", G_TYPE_BOOLEAN);
if (elem)
g_object_set (elem, "force-aspect-ratio", TRUE, NULL);
/* find ts-offset element */
gst_object_replace ((GstObject **) & chain->ts_offset, (GstObject *)
gst_play_sink_find_property_sinks (playsink, chain->sink, "ts-offset",
@ -1310,6 +1559,34 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
gst_object_ref_sink (bin);
gst_bin_add (bin, chain->sink);
/* Get the VideoOverlay element */
{
GstVideoOverlay *overlay = NULL;
GST_OBJECT_LOCK (playsink);
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 (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
@ -1329,10 +1606,34 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
head = prev = chain->queue;
}
if (!(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO)) {
GST_OBJECT_LOCK (playsink);
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 = find_color_balance_element (chain->sink);
GST_OBJECT_UNLOCK (playsink);
if (!(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO)
|| (!playsink->colorbalance_element
&& (playsink->flags & GST_PLAY_FLAG_SOFT_COLORBALANCE))) {
gboolean use_converters = !(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO);
gboolean use_balance = !playsink->colorbalance_element
&& (playsink->flags & GST_PLAY_FLAG_SOFT_COLORBALANCE);
GST_DEBUG_OBJECT (playsink, "creating videoconverter");
chain->conv =
g_object_new (GST_TYPE_PLAY_SINK_VIDEO_CONVERT, "name", "vconv", NULL);
g_object_new (GST_TYPE_PLAY_SINK_VIDEO_CONVERT, "name", "vconv",
"use-converters", use_converters, "use-balance", use_balance, NULL);
GST_OBJECT_LOCK (playsink);
if (use_balance && GST_PLAY_SINK_VIDEO_CONVERT (chain->conv)->balance)
playsink->colorbalance_element =
GST_COLOR_BALANCE (gst_object_ref (GST_PLAY_SINK_VIDEO_CONVERT
(chain->conv)->balance));
GST_OBJECT_UNLOCK (playsink);
gst_bin_add (bin, chain->conv);
if (prev) {
if (!gst_element_link_pads_full (prev, "src", chain->conv, "sink",
@ -1344,6 +1645,8 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
prev = chain->conv;
}
update_colorbalance (playsink);
if (prev) {
GST_DEBUG_OBJECT (playsink, "linking to sink");
if (!gst_element_link_pads_full (prev, "src", chain->sink, NULL,
@ -1390,6 +1693,7 @@ no_sinks:
free_chain ((GstPlayChain *) chain);
return NULL;
}
link_failed:
{
GST_ELEMENT_ERROR (playsink, CORE, PAD,
@ -1423,8 +1727,35 @@ setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
if (ret == GST_STATE_CHANGE_FAILURE)
return FALSE;
/* find ts-offset element */
/* Get the VideoOverlay element */
{
GstVideoOverlay *overlay = NULL;
GST_OBJECT_LOCK (playsink);
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 (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));
@ -1443,6 +1774,39 @@ setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
GST_DEBUG_OBJECT (playsink, "no async property on the sink");
chain->async = TRUE;
}
/* Make sure the aspect ratio is kept */
elem =
gst_play_sink_find_property_sinks (playsink, chain->sink,
"force-aspect-ratio", G_TYPE_BOOLEAN);
if (elem)
g_object_set (elem, "force-aspect-ratio", TRUE, NULL);
GST_OBJECT_LOCK (playsink);
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 = find_color_balance_element (chain->sink);
GST_OBJECT_UNLOCK (playsink);
if (chain->conv) {
gboolean use_balance = !playsink->colorbalance_element
&& (playsink->flags & GST_PLAY_FLAG_SOFT_COLORBALANCE);
g_object_set (chain->conv, "use-balance", use_balance, NULL);
GST_OBJECT_LOCK (playsink);
if (use_balance && GST_PLAY_SINK_VIDEO_CONVERT (chain->conv)->balance)
playsink->colorbalance_element =
GST_COLOR_BALANCE (gst_object_ref (GST_PLAY_SINK_VIDEO_CONVERT
(chain->conv)->balance));
GST_OBJECT_UNLOCK (playsink);
}
update_colorbalance (playsink);
return TRUE;
}
@ -1801,10 +2165,10 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw)
}
if (!(playsink->flags & GST_PLAY_FLAG_NATIVE_AUDIO) || (!have_volume
&& playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME)) {
&& (playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME))) {
gboolean use_converters = !(playsink->flags & GST_PLAY_FLAG_NATIVE_AUDIO);
gboolean use_volume =
!have_volume && playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME;
!have_volume && (playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME);
GST_DEBUG_OBJECT (playsink,
"creating audioconvert with use-converters %d, use-volume %d",
use_converters, use_volume);
@ -1821,7 +2185,7 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw)
}
prev = chain->conv;
if (!have_volume && playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME) {
if (!have_volume && (playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME)) {
GstPlaySinkAudioConvert *conv =
GST_PLAY_SINK_AUDIO_CONVERT_CAST (chain->conv);
@ -1974,13 +2338,14 @@ setup_audio_chain (GstPlaySink * playsink, gboolean raw)
GST_PLAY_SINK_AUDIO_CONVERT_CAST (chain->conv);
/* no volume, we need to add a volume element when we can */
g_object_set (chain->conv, "use-volume", TRUE, NULL);
g_object_set (chain->conv, "use-volume",
! !(playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME), NULL);
GST_DEBUG_OBJECT (playsink, "the sink has no volume property");
/* Disconnect signals */
disconnect_chain (chain, playsink);
if (conv->volume) {
if (conv->volume && (playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME)) {
chain->volume = conv->volume;
chain->mute = chain->volume;
@ -2164,6 +2529,19 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
need_text = TRUE;
}
GST_OBJECT_LOCK (playsink);
if (playsink->overlay_element)
gst_object_unref (playsink->overlay_element);
playsink->overlay_element = NULL;
if (playsink->colorbalance_element) {
g_signal_handlers_disconnect_by_func (playsink->colorbalance_element,
G_CALLBACK (colorbalance_value_changed_cb), playsink);
gst_object_unref (playsink->colorbalance_element);
}
playsink->colorbalance_element = NULL;
GST_OBJECT_UNLOCK (playsink);
if (((flags & GST_PLAY_FLAG_VIDEO)
|| (flags & GST_PLAY_FLAG_NATIVE_VIDEO)) && playsink->video_pad) {
/* we have video and we are requested to show it */
@ -3355,6 +3733,44 @@ gst_play_sink_handle_message (GstBin * bin, GstMessage * message)
GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (bin, message);
break;
}
case GST_MESSAGE_ELEMENT:{
if (gst_is_video_overlay_prepare_window_handle_message (message)) {
GstVideoOverlay *overlay;
GST_OBJECT_LOCK (playsink);
if (playsink->overlay_element
&& GST_OBJECT_CAST (playsink->overlay_element) !=
GST_MESSAGE_SRC (message)) {
gst_object_unref (playsink->overlay_element);
playsink->overlay_element = NULL;
}
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->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_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (playsink));
}
break;
}
default:
GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (bin, message);
break;
@ -3370,7 +3786,6 @@ static gboolean
gst_play_sink_send_event_to_sink (GstPlaySink * playsink, GstEvent * event)
{
gboolean res = TRUE;
if (playsink->textchain && playsink->textchain->sink) {
gst_event_ref (event);
if ((res = gst_element_send_event (playsink->textchain->chain.bin, event))) {
@ -3411,9 +3826,7 @@ gst_play_sink_send_event (GstElement * element, GstEvent * event)
gboolean res = FALSE;
GstEventType event_type = GST_EVENT_TYPE (event);
GstPlaySink *playsink;
playsink = GST_PLAY_SINK_CAST (element);
switch (event_type) {
case GST_EVENT_SEEK:
GST_DEBUG_OBJECT (element, "Sending event to a sink");
@ -3425,10 +3838,8 @@ gst_play_sink_send_event (GstElement * element, GstEvent * event)
guint64 amount;
gdouble rate;
gboolean flush, intermediate;
gst_event_parse_step (event, &format, &amount, &rate, &flush,
&intermediate);
if (format == GST_FORMAT_BUFFERS) {
/* for buffers, we will try to step video frames, for other formats we
* send the step to all sinks */
@ -3454,11 +3865,8 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn ret;
GstStateChangeReturn bret;
GstPlaySink *playsink;
playsink = GST_PLAY_SINK (element);
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
playsink->need_async_start = TRUE;
@ -3493,6 +3901,20 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition)
gst_object_unref (playsink->videochain->ts_offset);
playsink->videochain->ts_offset = NULL;
}
GST_OBJECT_LOCK (playsink);
if (playsink->overlay_element)
gst_object_unref (playsink->overlay_element);
playsink->overlay_element = NULL;
if (playsink->colorbalance_element) {
g_signal_handlers_disconnect_by_func (playsink->colorbalance_element,
G_CALLBACK (colorbalance_value_changed_cb), playsink);
gst_object_unref (playsink->colorbalance_element);
}
playsink->colorbalance_element = NULL;
GST_OBJECT_UNLOCK (playsink);
ret = GST_STATE_CHANGE_SUCCESS;
break;
default:
@ -3602,7 +4024,6 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition)
if (playsink->textchain && playsink->textchain->sink)
gst_bin_remove (GST_BIN_CAST (playsink->textchain->chain.bin),
playsink->textchain->sink);
if (playsink->audio_sink != NULL)
gst_element_set_state (playsink->audio_sink, GST_STATE_NULL);
if (playsink->video_sink != NULL)
@ -3611,7 +4032,6 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition)
gst_element_set_state (playsink->visualisation, GST_STATE_NULL);
if (playsink->text_sink != NULL)
gst_element_set_state (playsink->text_sink, GST_STATE_NULL);
free_chain ((GstPlayChain *) playsink->videodeinterlacechain);
playsink->videodeinterlacechain = NULL;
free_chain ((GstPlayChain *) playsink->videochain);
@ -3628,7 +4048,6 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition)
break;
}
return ret;
/* ERRORS */
activate_failed:
{
@ -3643,7 +4062,6 @@ gst_play_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * spec)
{
GstPlaySink *playsink = GST_PLAY_SINK (object);
switch (prop_id) {
case PROP_FLAGS:
gst_play_sink_set_flags (playsink, g_value_get_flags (value));
@ -3690,7 +4108,6 @@ gst_play_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * spec)
{
GstPlaySink *playsink = GST_PLAY_SINK (object);
switch (prop_id) {
case PROP_FLAGS:
g_value_set_flags (value, gst_play_sink_get_flags (playsink));
@ -3735,12 +4152,273 @@ gst_play_sink_get_property (GObject * object, guint prop_id,
}
}
static void
gst_play_sink_overlay_expose (GstVideoOverlay * overlay)
{
GstPlaySink *playsink = GST_PLAY_SINK (overlay);
GstVideoOverlay *overlay_element;
GST_OBJECT_LOCK (playsink);
if (playsink->overlay_element)
overlay_element =
GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element));
else
overlay_element = NULL;
GST_OBJECT_UNLOCK (playsink);
if (overlay_element) {
gst_video_overlay_expose (overlay_element);
gst_object_unref (overlay_element);
}
}
static void
gst_play_sink_overlay_handle_events (GstVideoOverlay * overlay,
gboolean handle_events)
{
GstPlaySink *playsink = GST_PLAY_SINK (overlay);
GstVideoOverlay *overlay_element;
GST_OBJECT_LOCK (playsink);
if (playsink->overlay_element)
overlay_element =
GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element));
else
overlay_element = NULL;
GST_OBJECT_UNLOCK (playsink);
playsink->overlay_handle_events_set = TRUE;
playsink->overlay_handle_events = handle_events;
if (overlay_element) {
gst_video_overlay_handle_events (overlay_element, handle_events);
gst_object_unref (overlay_element);
}
}
static void
gst_play_sink_overlay_set_render_rectangle (GstVideoOverlay * overlay, gint x,
gint y, gint width, gint height)
{
GstPlaySink *playsink = GST_PLAY_SINK (overlay);
GstVideoOverlay *overlay_element;
GST_OBJECT_LOCK (playsink);
if (playsink->overlay_element)
overlay_element =
GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element));
else
overlay_element = NULL;
GST_OBJECT_UNLOCK (playsink);
playsink->overlay_render_rectangle_set = TRUE;
playsink->overlay_x = x;
playsink->overlay_y = y;
playsink->overlay_width = width;
playsink->overlay_height = height;
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_overlay_set_window_handle (GstVideoOverlay * overlay,
guintptr handle)
{
GstPlaySink *playsink = GST_PLAY_SINK (overlay);
GstVideoOverlay *overlay_element;
GST_OBJECT_LOCK (playsink);
if (playsink->overlay_element)
overlay_element =
GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element));
else
overlay_element = NULL;
GST_OBJECT_UNLOCK (playsink);
playsink->overlay_handle_set = TRUE;
playsink->overlay_handle = handle;
if (overlay_element) {
gst_video_overlay_set_window_handle (overlay_element, handle);
gst_object_unref (overlay_element);
}
}
static void
gst_play_sink_overlay_init (gpointer g_iface, gpointer g_iface_data)
{
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)
{
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)
{
GST_DEBUG_CATEGORY_INIT (gst_play_sink_debug, "playsink", 0, "play bin");
return gst_element_register (plugin, "playsink", GST_RANK_NONE,
GST_TYPE_PLAY_SINK);
}

View file

@ -64,7 +64,6 @@ gst_play_sink_audio_convert_add_conversion_elements (GstPlaySinkAudioConvert *
el = gst_play_sink_convert_bin_add_conversion_element_factory (cbin,
"audioresample", "resample");
if (el) {
if (prev) {
if (!gst_element_link_pads_full (prev, "src", el, "sink",
GST_PAD_LINK_CHECK_TEMPLATE_CAPS))

View file

@ -34,6 +34,13 @@ GST_DEBUG_CATEGORY_STATIC (gst_play_sink_video_convert_debug);
G_DEFINE_TYPE (GstPlaySinkVideoConvert, gst_play_sink_video_convert,
GST_TYPE_PLAY_SINK_CONVERT_BIN);
enum
{
PROP_0,
PROP_USE_CONVERTERS,
PROP_USE_BALANCE,
};
static gboolean
gst_play_sink_video_convert_add_conversion_elements (GstPlaySinkVideoConvert *
self)
@ -41,22 +48,51 @@ gst_play_sink_video_convert_add_conversion_elements (GstPlaySinkVideoConvert *
GstPlaySinkConvertBin *cbin = GST_PLAY_SINK_CONVERT_BIN (self);
GstElement *el, *prev = NULL;
el = gst_play_sink_convert_bin_add_conversion_element_factory (cbin,
COLORSPACE, "conv");
if (el)
prev = el;
g_assert (cbin->conversion_elements == NULL);
el = gst_play_sink_convert_bin_add_conversion_element_factory (cbin,
"videoscale", "scale");
if (el) {
/* Add black borders if necessary to keep the DAR */
g_object_set (el, "add-borders", TRUE, NULL);
GST_DEBUG_OBJECT (self,
"Building video conversion with use-converters %d, use-balance %d",
self->use_converters, self->use_balance);
if (self->use_converters) {
el = gst_play_sink_convert_bin_add_conversion_element_factory (cbin,
COLORSPACE, "conv");
if (el)
prev = el;
el = gst_play_sink_convert_bin_add_conversion_element_factory (cbin,
"videoscale", "scale");
if (el) {
/* Add black borders if necessary to keep the DAR */
g_object_set (el, "add-borders", TRUE, NULL);
if (prev) {
if (!gst_element_link_pads_full (prev, "src", el, "sink",
GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
goto link_failed;
}
prev = el;
}
}
if (self->use_balance && self->balance) {
el = self->balance;
gst_play_sink_convert_bin_add_conversion_element (cbin, el);
if (prev) {
if (!gst_element_link_pads_full (prev, "src", el, "sink",
GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
goto link_failed;
}
prev = el;
el = gst_play_sink_convert_bin_add_conversion_element_factory (cbin,
COLORSPACE, "conv2");
if (prev) {
if (!gst_element_link_pads_full (prev, "src", el, "sink",
GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
goto link_failed;
}
if (el)
prev = el;
}
return TRUE;
@ -65,16 +101,101 @@ link_failed:
return FALSE;
}
static void
gst_play_sink_video_convert_finalize (GObject * object)
{
GstPlaySinkVideoConvert *self = GST_PLAY_SINK_VIDEO_CONVERT_CAST (object);
if (self->balance)
gst_object_unref (self->balance);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gst_play_sink_video_convert_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstPlaySinkVideoConvert *self = GST_PLAY_SINK_VIDEO_CONVERT_CAST (object);
gboolean v, changed = FALSE;
GST_PLAY_SINK_CONVERT_BIN_LOCK (self);
switch (prop_id) {
case PROP_USE_CONVERTERS:
v = g_value_get_boolean (value);
if (v != self->use_converters) {
self->use_converters = v;
changed = TRUE;
}
break;
case PROP_USE_BALANCE:
v = g_value_get_boolean (value);
if (v != self->use_balance) {
self->use_balance = v;
changed = TRUE;
}
break;
default:
break;
}
if (changed) {
GstPlaySinkConvertBin *cbin = GST_PLAY_SINK_CONVERT_BIN (self);
GST_DEBUG_OBJECT (self, "Rebuilding converter bin");
gst_play_sink_convert_bin_remove_elements (cbin);
gst_play_sink_video_convert_add_conversion_elements (self);
gst_play_sink_convert_bin_add_identity (cbin);
gst_play_sink_convert_bin_cache_converter_caps (cbin);
}
GST_PLAY_SINK_CONVERT_BIN_UNLOCK (self);
}
static void
gst_play_sink_video_convert_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstPlaySinkVideoConvert *self = GST_PLAY_SINK_VIDEO_CONVERT_CAST (object);
GST_PLAY_SINK_CONVERT_BIN_LOCK (self);
switch (prop_id) {
case PROP_USE_CONVERTERS:
g_value_set_boolean (value, self->use_converters);
break;
case PROP_USE_BALANCE:
g_value_set_boolean (value, self->use_balance);
break;
default:
break;
}
GST_PLAY_SINK_CONVERT_BIN_UNLOCK (self);
}
static void
gst_play_sink_video_convert_class_init (GstPlaySinkVideoConvertClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GST_DEBUG_CATEGORY_INIT (gst_play_sink_video_convert_debug,
"playsinkvideoconvert", 0, "play bin");
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gobject_class->finalize = gst_play_sink_video_convert_finalize;
gobject_class->set_property = gst_play_sink_video_convert_set_property;
gobject_class->get_property = gst_play_sink_video_convert_get_property;
g_object_class_install_property (gobject_class, PROP_USE_CONVERTERS,
g_param_spec_boolean ("use-converters", "Use converters",
"Whether to use conversion elements", FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_USE_BALANCE,
g_param_spec_boolean ("use-balance", "Use balance",
"Whether to use a videobalance element", FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_details_simple (gstelement_class,
"Player Sink Video Converter", "Video/Bin/Converter",
"Convenience bin for video conversion",
@ -87,6 +208,14 @@ gst_play_sink_video_convert_init (GstPlaySinkVideoConvert * self)
GstPlaySinkConvertBin *cbin = GST_PLAY_SINK_CONVERT_BIN (self);
cbin->audio = FALSE;
/* FIXME: Only create this on demand but for now we need
* it to always exist because of playsink's color balance
* proxying logic.
*/
self->balance = gst_element_factory_make ("videobalance", "videobalance");
if (self->balance)
gst_object_ref_sink (self->balance);
gst_play_sink_video_convert_add_conversion_elements (self);
gst_play_sink_convert_bin_cache_converter_caps (cbin);
}

View file

@ -43,6 +43,10 @@ struct _GstPlaySinkVideoConvert
{
GstPlaySinkConvertBin parent;
/* < pseudo public > */
GstElement *balance;
gboolean use_converters;
gboolean use_balance;
};
struct _GstPlaySinkVideoConvertClass

View file

@ -395,10 +395,121 @@ gst_video_scale_get_property (GObject * object, guint prop_id, GValue * value,
}
}
#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;
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);
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 (info.finfo->format,
method)) {
supported = FALSE;
}
GST_LOG_OBJECT (videoscale, "method %d %ssupported for format %d",
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, GstCaps * filter)
{
GstVideoScale *videoscale = GST_VIDEO_SCALE (trans);
GstVideoScaleMethod method;
GstCaps *ret;
GstStructure *structure;
gint i, n;
@ -407,6 +518,10 @@ gst_video_scale_transform_caps (GstBaseTransform * trans,
"Transforming caps %" GST_PTR_FORMAT " in direction %s", caps,
(direction == GST_PAD_SINK) ? "sink" : "src");
GST_OBJECT_LOCK (videoscale);
method = videoscale->method;
GST_OBJECT_UNLOCK (videoscale);
ret = gst_caps_new_empty ();
n = gst_caps_get_size (caps);
for (i = 0; i < n; i++) {
@ -417,6 +532,9 @@ gst_video_scale_transform_caps (GstBaseTransform * trans,
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,
@ -439,9 +557,19 @@ gst_video_scale_transform_caps (GstBaseTransform * trans,
ret = intersection;
}
done:
GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, ret);
return ret;
format_not_supported:
{
gst_structure_free (structure);
gst_caps_unref (ret);
ret = gst_caps_new_empty ();
goto done;
}
}
static gboolean

View file

@ -109,6 +109,10 @@
/* for developers: there are two useful tools : xvinfo and xvattr */
/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
* with newer GLib versions (>= 2.31.0) */
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

View file

@ -101,8 +101,8 @@ GST_START_TEST (test_event)
GstBus *bus;
GstEvent *seek_event;
gboolean res;
GstPad *srcpad;
GstStreamConsistency *consist;
GstPad *srcpad, *sinkpad;
GstStreamConsistency *chk_1, *chk_2, *chk_3;
GST_INFO ("preparing test");
@ -130,7 +130,22 @@ GST_START_TEST (test_event)
fail_unless (res == TRUE, NULL);
srcpad = gst_element_get_static_pad (adder, "src");
consist = gst_consistency_checker_new (srcpad);
chk_3 = gst_consistency_checker_new (srcpad);
gst_object_unref (srcpad);
/* create consistency checkers for the pads */
srcpad = gst_element_get_static_pad (src1, "src");
chk_1 = gst_consistency_checker_new (srcpad);
sinkpad = gst_pad_get_peer (srcpad);
gst_consistency_checker_add_pad (chk_3, sinkpad);
gst_object_unref (sinkpad);
gst_object_unref (srcpad);
srcpad = gst_element_get_static_pad (src2, "src");
chk_2 = gst_consistency_checker_new (srcpad);
sinkpad = gst_pad_get_peer (srcpad);
gst_consistency_checker_add_pad (chk_3, sinkpad);
gst_object_unref (sinkpad);
gst_object_unref (srcpad);
seek_event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
@ -174,7 +189,9 @@ GST_START_TEST (test_event)
/* cleanup */
g_main_loop_unref (main_loop);
gst_consistency_checker_free (consist);
gst_consistency_checker_free (chk_1);
gst_consistency_checker_free (chk_2);
gst_consistency_checker_free (chk_3);
gst_object_unref (G_OBJECT (bus));
gst_object_unref (G_OBJECT (bin));
}

View file

@ -20,6 +20,10 @@
* Boston, MA 02111-1307, USA.
*/
/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
* with newer GLib versions (>= 2.31.0) */
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include <unistd.h>
#include <gst/check/gstcheck.h>

View file

@ -18,6 +18,10 @@
* Boston, MA 02111-1307, USA.
*/
/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
* with newer GLib versions (>= 2.31.0) */
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

View file

@ -30,22 +30,20 @@
#define LINK_CHECK_FLAGS GST_PAD_LINK_CHECK_NOTHING
static GstCaps **
videoscale_get_allowed_caps (void)
videoscale_get_allowed_caps_for_method (int method)
{
GstElement *scale = gst_element_factory_make ("videoscale", "scale");
GstPadTemplate *templ;
GstCaps *tmp, *caps, **ret;
GstElement *scale;
GstCaps *caps, **ret;
GstPad *pad;
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_query_caps (pad, NULL);
gst_object_unref (pad);
gst_object_unref (scale);
n = gst_caps_get_size (caps);
ret = g_new0 (GstCaps *, n + 1);
@ -54,10 +52,10 @@ videoscale_get_allowed_caps (void)
s = gst_caps_get_structure (caps, i);
ret[i] = gst_caps_new_empty ();
gst_caps_append_structure (ret[i], gst_structure_copy (s));
GST_LOG ("method %d supports: %" GST_PTR_FORMAT, method, s);
}
gst_caps_unref (caps);
gst_object_unref (scale);
return ret;
}
@ -212,15 +210,15 @@ on_src_handoff_passthrough (GstElement * element, GstBuffer * buffer,
*list = g_list_prepend (*list, gst_buffer_ref (buffer));
}
GST_START_TEST (test_passthrough)
static void
test_passthrough (int method)
{
GList *l1, *l2, *src_buffers = NULL, *sink_buffers = NULL;
GstCaps **allowed_caps = NULL, **p;
gint method;
static const gint src_width = 640, src_height = 480;
static const gint dest_width = 640, dest_height = 480;
p = allowed_caps = videoscale_get_allowed_caps ();
p = allowed_caps = videoscale_get_allowed_caps_for_method (method);
while (*p) {
GstCaps *caps = *p;
@ -263,13 +261,38 @@ GST_START_TEST (test_passthrough)
g_list_free (sink_buffers);
sink_buffers = NULL;
}
gst_caps_unref (caps);
p++;
}
g_free (allowed_caps);
}
GST_START_TEST (test_passthrough_method_0)
{
test_passthrough (0);
}
GST_END_TEST;
GST_START_TEST (test_passthrough_method_1)
{
test_passthrough (1);
}
GST_END_TEST;
GST_START_TEST (test_passthrough_method_2)
{
test_passthrough (2);
}
GST_END_TEST;
GST_START_TEST (test_passthrough_method_3)
{
test_passthrough (3);
}
GST_END_TEST;
#define CREATE_TEST(name,method,src_width,src_height,dest_width,dest_height) \
@ -277,7 +300,7 @@ GST_START_TEST (name) \
{ \
GstCaps **allowed_caps = NULL, **p; \
\
p = allowed_caps = videoscale_get_allowed_caps (); \
p = allowed_caps = videoscale_get_allowed_caps_for_method (method); \
\
while (*p) { \
GstCaps *caps = *p; \
@ -299,39 +322,51 @@ GST_END_TEST;
CREATE_TEST (test_downscale_640x480_320x240_method_0, 0, 640, 480, 320, 240);
CREATE_TEST (test_downscale_640x480_320x240_method_1, 1, 640, 480, 320, 240);
CREATE_TEST (test_downscale_640x480_320x240_method_2, 2, 640, 480, 320, 240);
CREATE_TEST (test_downscale_640x480_320x240_method_3, 3, 640, 480, 320, 240);
CREATE_TEST (test_upscale_320x240_640x480_method_0, 0, 320, 240, 640, 480);
CREATE_TEST (test_upscale_320x240_640x480_method_1, 1, 320, 240, 640, 480);
CREATE_TEST (test_upscale_320x240_640x480_method_2, 2, 320, 240, 640, 480);
CREATE_TEST (test_upscale_320x240_640x480_method_3, 3, 320, 240, 640, 480);
CREATE_TEST (test_downscale_640x480_1x1_method_0, 0, 640, 480, 1, 1);
CREATE_TEST (test_downscale_640x480_1x1_method_1, 1, 640, 480, 1, 1);
CREATE_TEST (test_downscale_640x480_1x1_method_2, 2, 640, 480, 1, 1);
CREATE_TEST (test_downscale_640x480_1x1_method_3, 3, 640, 480, 1, 1);
CREATE_TEST (test_upscale_1x1_640x480_method_0, 0, 1, 1, 640, 480);
CREATE_TEST (test_upscale_1x1_640x480_method_1, 1, 1, 1, 640, 480);
CREATE_TEST (test_upscale_1x1_640x480_method_2, 2, 1, 1, 640, 480);
CREATE_TEST (test_upscale_1x1_640x480_method_3, 3, 1, 1, 640, 480);
CREATE_TEST (test_downscale_641x481_111x30_method_0, 0, 641, 481, 111, 30);
CREATE_TEST (test_downscale_641x481_111x30_method_1, 1, 641, 481, 111, 30);
CREATE_TEST (test_downscale_641x481_111x30_method_2, 2, 641, 481, 111, 30);
CREATE_TEST (test_downscale_641x481_111x30_method_3, 3, 641, 481, 111, 30);
CREATE_TEST (test_upscale_111x30_641x481_method_0, 0, 111, 30, 641, 481);
CREATE_TEST (test_upscale_111x30_641x481_method_1, 1, 111, 30, 641, 481);
CREATE_TEST (test_upscale_111x30_641x481_method_2, 2, 111, 30, 641, 481);
CREATE_TEST (test_upscale_111x30_641x481_method_3, 2, 111, 30, 641, 481);
CREATE_TEST (test_downscale_641x481_30x111_method_0, 0, 641, 481, 30, 111);
CREATE_TEST (test_downscale_641x481_30x111_method_1, 1, 641, 481, 30, 111);
CREATE_TEST (test_downscale_641x481_30x111_method_2, 2, 641, 481, 30, 111);
CREATE_TEST (test_downscale_641x481_30x111_method_3, 3, 641, 481, 30, 111);
CREATE_TEST (test_upscale_30x111_641x481_method_0, 0, 30, 111, 641, 481);
CREATE_TEST (test_upscale_30x111_641x481_method_1, 1, 30, 111, 641, 481);
CREATE_TEST (test_upscale_30x111_641x481_method_2, 2, 30, 111, 641, 481);
CREATE_TEST (test_upscale_30x111_641x481_method_3, 3, 30, 111, 641, 481);
CREATE_TEST (test_downscale_640x480_320x1_method_0, 0, 640, 480, 320, 1);
CREATE_TEST (test_downscale_640x480_320x1_method_1, 1, 640, 480, 320, 1);
CREATE_TEST (test_downscale_640x480_320x1_method_2, 2, 640, 480, 320, 1);
CREATE_TEST (test_downscale_640x480_320x1_method_3, 3, 640, 480, 320, 1);
CREATE_TEST (test_upscale_320x1_640x480_method_0, 0, 320, 1, 640, 480);
CREATE_TEST (test_upscale_320x1_640x480_method_1, 1, 320, 1, 640, 480);
CREATE_TEST (test_upscale_320x1_640x480_method_2, 2, 320, 1, 640, 480);
CREATE_TEST (test_upscale_320x1_640x480_method_3, 3, 320, 1, 640, 480);
CREATE_TEST (test_downscale_640x480_1x240_method_0, 0, 640, 480, 1, 240);
CREATE_TEST (test_downscale_640x480_1x240_method_1, 1, 640, 480, 1, 240);
CREATE_TEST (test_downscale_640x480_1x240_method_2, 2, 640, 480, 1, 240);
CREATE_TEST (test_downscale_640x480_1x240_method_3, 3, 640, 480, 1, 240);
CREATE_TEST (test_upscale_1x240_640x480_method_0, 0, 1, 240, 640, 480);
CREATE_TEST (test_upscale_1x240_640x480_method_1, 1, 1, 240, 640, 480);
CREATE_TEST (test_upscale_1x240_640x480_method_2, 2, 1, 240, 640, 480);
CREATE_TEST (test_upscale_1x240_640x480_method_3, 3, 1, 240, 640, 480);
typedef struct
{
@ -823,6 +858,13 @@ GST_START_TEST (test_basetransform_negotiation)
GST_END_TEST;
#ifndef tcase_skip_broken_test
#define tcase_skip_broken_test(chain,test_func) \
if (0) { tcase_add_test(chain,test_func); } else { \
GST_ERROR ("FIXME: skipping test %s because it's broken.", G_STRINGIFY (test_func)); \
}
#endif
static Suite *
videoscale_suite (void)
{
@ -831,43 +873,58 @@ videoscale_suite (void)
suite_add_tcase (s, tc_chain);
tcase_set_timeout (tc_chain, 180);
tcase_add_test (tc_chain, test_passthrough);
tcase_add_test (tc_chain, test_passthrough_method_0);
tcase_add_test (tc_chain, test_passthrough_method_1);
tcase_add_test (tc_chain, test_passthrough_method_2);
tcase_add_test (tc_chain, test_passthrough_method_3);
tcase_add_test (tc_chain, test_downscale_640x480_320x240_method_0);
tcase_add_test (tc_chain, test_downscale_640x480_320x240_method_1);
tcase_add_test (tc_chain, test_downscale_640x480_320x240_method_2);
tcase_add_test (tc_chain, test_downscale_640x480_320x240_method_3);
tcase_add_test (tc_chain, test_upscale_320x240_640x480_method_0);
tcase_add_test (tc_chain, test_upscale_320x240_640x480_method_1);
tcase_add_test (tc_chain, test_upscale_320x240_640x480_method_2);
tcase_add_test (tc_chain, test_upscale_320x240_640x480_method_3);
tcase_add_test (tc_chain, test_downscale_640x480_1x1_method_0);
tcase_add_test (tc_chain, test_downscale_640x480_1x1_method_1);
tcase_add_test (tc_chain, test_downscale_640x480_1x1_method_2);
tcase_skip_broken_test (tc_chain, test_downscale_640x480_1x1_method_3);
tcase_add_test (tc_chain, test_upscale_1x1_640x480_method_0);
tcase_add_test (tc_chain, test_upscale_1x1_640x480_method_1);
tcase_add_test (tc_chain, test_upscale_1x1_640x480_method_2);
tcase_add_test (tc_chain, test_upscale_1x1_640x480_method_3);
tcase_add_test (tc_chain, test_downscale_641x481_111x30_method_0);
tcase_add_test (tc_chain, test_downscale_641x481_111x30_method_1);
tcase_add_test (tc_chain, test_downscale_641x481_111x30_method_2);
tcase_add_test (tc_chain, test_downscale_641x481_111x30_method_3);
tcase_add_test (tc_chain, test_upscale_111x30_641x481_method_0);
tcase_add_test (tc_chain, test_upscale_111x30_641x481_method_1);
tcase_add_test (tc_chain, test_upscale_111x30_641x481_method_2);
tcase_add_test (tc_chain, test_upscale_111x30_641x481_method_3);
tcase_add_test (tc_chain, test_downscale_641x481_30x111_method_0);
tcase_add_test (tc_chain, test_downscale_641x481_30x111_method_1);
tcase_add_test (tc_chain, test_downscale_641x481_30x111_method_2);
tcase_add_test (tc_chain, test_downscale_641x481_30x111_method_3);
tcase_add_test (tc_chain, test_upscale_30x111_641x481_method_0);
tcase_add_test (tc_chain, test_upscale_30x111_641x481_method_1);
tcase_add_test (tc_chain, test_upscale_30x111_641x481_method_2);
tcase_add_test (tc_chain, test_upscale_30x111_641x481_method_3);
tcase_add_test (tc_chain, test_downscale_640x480_320x1_method_0);
tcase_add_test (tc_chain, test_downscale_640x480_320x1_method_1);
tcase_add_test (tc_chain, test_downscale_640x480_320x1_method_2);
tcase_skip_broken_test (tc_chain, test_downscale_640x480_320x1_method_3);
tcase_add_test (tc_chain, test_upscale_320x1_640x480_method_0);
tcase_add_test (tc_chain, test_upscale_320x1_640x480_method_1);
tcase_add_test (tc_chain, test_upscale_320x1_640x480_method_2);
tcase_skip_broken_test (tc_chain, test_upscale_320x1_640x480_method_3);
tcase_add_test (tc_chain, test_downscale_640x480_1x240_method_0);
tcase_add_test (tc_chain, test_downscale_640x480_1x240_method_1);
tcase_add_test (tc_chain, test_downscale_640x480_1x240_method_2);
tcase_add_test (tc_chain, test_downscale_640x480_1x240_method_3);
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);

File diff suppressed because it is too large Load diff

View file

@ -22,8 +22,10 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
* with newer GTK versions (>= 3.3.0) */
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#define GDK_DISABLE_DEPRECATION_WARNINGS
#include <stdlib.h>

View file

@ -53,9 +53,6 @@
/* system wide data directory */
#define GST_DATADIR PREFIX "\\share"
/* set to disable libxml2-dependent code in subparse */
#undef GST_DISABLE_XML
/* Extra platform specific plugin suffix */
#undef GST_EXTRA_MODULE_SUFFIX
@ -152,6 +149,9 @@
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the <emmintrin.h> header file. */
#undef HAVE_EMMINTRIN_H
/* Define to enable building of experimental plug-ins. */
#undef HAVE_EXPERIMENTAL
@ -272,6 +272,9 @@
/* Define to enable X libraries and plugins (used by ximagesink). */
#undef HAVE_X
/* Define to 1 if you have the <xmmintrin.h> header file. */
#undef HAVE_XMMINTRIN_H
/* Define to enable X Shared Memory extension. */
#undef HAVE_XSHM