playback: Add video-/audio-filter properties
This provides an audio-filter and video-filter property to allow applications to set filter elements/bins. The idea is that these will be applied if possible -- for non-raw sinks, the filters will be skipped. If the application wishes to force the application of the filters, this can be done by setting the new flag introduced on playsink - GST_PLAY_FLAG_FORCE_FILTERS. https://bugzilla.gnome.org/show_bug.cgi?id=679031
This commit is contained in:
parent
d6bd37460a
commit
fb8fdedb4f
@ -57,6 +57,8 @@ GType gst_autoplug_select_result_get_type (void);
|
|||||||
* formats.
|
* formats.
|
||||||
* @GST_PLAY_FLAG_BUFFERING: enable buffering of the demuxed or parsed data.
|
* @GST_PLAY_FLAG_BUFFERING: enable buffering of the demuxed or parsed data.
|
||||||
* @GST_PLAY_FLAG_DEINTERLACE: deinterlace raw video (if native not forced).
|
* @GST_PLAY_FLAG_DEINTERLACE: deinterlace raw video (if native not forced).
|
||||||
|
* @GST_PLAY_FLAG_FORCE_FILTERS: force audio/video filters to be applied if
|
||||||
|
* set.
|
||||||
*
|
*
|
||||||
* Extra flags to configure the behaviour of the sinks.
|
* Extra flags to configure the behaviour of the sinks.
|
||||||
*/
|
*/
|
||||||
@ -71,7 +73,8 @@ typedef enum {
|
|||||||
GST_PLAY_FLAG_DOWNLOAD = (1 << 7),
|
GST_PLAY_FLAG_DOWNLOAD = (1 << 7),
|
||||||
GST_PLAY_FLAG_BUFFERING = (1 << 8),
|
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)
|
GST_PLAY_FLAG_SOFT_COLORBALANCE = (1 << 10),
|
||||||
|
GST_PLAY_FLAG_FORCE_FILTERS = (1 << 11),
|
||||||
} GstPlayFlags;
|
} GstPlayFlags;
|
||||||
|
|
||||||
#define GST_TYPE_PLAY_FLAGS (gst_play_flags_get_type())
|
#define GST_TYPE_PLAY_FLAGS (gst_play_flags_get_type())
|
||||||
|
@ -565,6 +565,8 @@ enum
|
|||||||
PROP_AV_OFFSET,
|
PROP_AV_OFFSET,
|
||||||
PROP_RING_BUFFER_MAX_SIZE,
|
PROP_RING_BUFFER_MAX_SIZE,
|
||||||
PROP_FORCE_ASPECT_RATIO,
|
PROP_FORCE_ASPECT_RATIO,
|
||||||
|
PROP_AUDIO_FILTER,
|
||||||
|
PROP_VIDEO_FILTER,
|
||||||
PROP_LAST
|
PROP_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -837,6 +839,14 @@ gst_play_bin_class_init (GstPlayBinClass * klass)
|
|||||||
"ISO-8859-15 will be assumed.", NULL,
|
"ISO-8859-15 will be assumed.", NULL,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_klass, PROP_VIDEO_FILTER,
|
||||||
|
g_param_spec_object ("video-filter", "Video filter",
|
||||||
|
"the video filter(s) to apply, if possible",
|
||||||
|
GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
g_object_class_install_property (gobject_klass, PROP_AUDIO_FILTER,
|
||||||
|
g_param_spec_object ("audio-filter", "Audio filter",
|
||||||
|
"the audio filter(s) to apply, if possible",
|
||||||
|
GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
|
g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
|
||||||
g_param_spec_object ("video-sink", "Video Sink",
|
g_param_spec_object ("video-sink", "Video Sink",
|
||||||
"the video output element to use (NULL = default sink)",
|
"the video output element to use (NULL = default sink)",
|
||||||
@ -2252,6 +2262,14 @@ gst_play_bin_set_property (GObject * object, guint prop_id,
|
|||||||
case PROP_SUBTITLE_ENCODING:
|
case PROP_SUBTITLE_ENCODING:
|
||||||
gst_play_bin_set_encoding (playbin, g_value_get_string (value));
|
gst_play_bin_set_encoding (playbin, g_value_get_string (value));
|
||||||
break;
|
break;
|
||||||
|
case PROP_VIDEO_FILTER:
|
||||||
|
gst_play_sink_set_filter (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
|
||||||
|
GST_ELEMENT (g_value_get_object (value)));
|
||||||
|
break;
|
||||||
|
case PROP_AUDIO_FILTER:
|
||||||
|
gst_play_sink_set_filter (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
|
||||||
|
GST_ELEMENT (g_value_get_object (value)));
|
||||||
|
break;
|
||||||
case PROP_VIDEO_SINK:
|
case PROP_VIDEO_SINK:
|
||||||
gst_play_bin_set_sink (playbin, GST_PLAY_SINK_TYPE_VIDEO, "video",
|
gst_play_bin_set_sink (playbin, GST_PLAY_SINK_TYPE_VIDEO, "video",
|
||||||
&playbin->video_sink, g_value_get_object (value));
|
&playbin->video_sink, g_value_get_object (value));
|
||||||
@ -2469,6 +2487,16 @@ gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
|
|||||||
gst_play_sink_get_subtitle_encoding (playbin->playsink));
|
gst_play_sink_get_subtitle_encoding (playbin->playsink));
|
||||||
GST_PLAY_BIN_UNLOCK (playbin);
|
GST_PLAY_BIN_UNLOCK (playbin);
|
||||||
break;
|
break;
|
||||||
|
case PROP_VIDEO_FILTER:
|
||||||
|
g_value_take_object (value,
|
||||||
|
gst_play_sink_get_filter (playbin->playsink,
|
||||||
|
GST_PLAY_SINK_TYPE_VIDEO));
|
||||||
|
break;
|
||||||
|
case PROP_AUDIO_FILTER:
|
||||||
|
g_value_take_object (value,
|
||||||
|
gst_play_sink_get_filter (playbin->playsink,
|
||||||
|
GST_PLAY_SINK_TYPE_AUDIO));
|
||||||
|
break;
|
||||||
case PROP_VIDEO_SINK:
|
case PROP_VIDEO_SINK:
|
||||||
g_value_take_object (value,
|
g_value_take_object (value,
|
||||||
gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
|
gst_play_bin_get_current_sink (playbin, &playbin->video_sink,
|
||||||
|
@ -99,6 +99,7 @@ typedef struct
|
|||||||
GstPlayChain chain;
|
GstPlayChain chain;
|
||||||
GstPad *sinkpad;
|
GstPad *sinkpad;
|
||||||
GstElement *queue;
|
GstElement *queue;
|
||||||
|
GstElement *filter;
|
||||||
GstElement *conv;
|
GstElement *conv;
|
||||||
GstElement *volume; /* element with the volume property */
|
GstElement *volume; /* element with the volume property */
|
||||||
gboolean sink_volume; /* if the volume was provided by the sink */
|
gboolean sink_volume; /* if the volume was provided by the sink */
|
||||||
@ -122,6 +123,7 @@ typedef struct
|
|||||||
GstPlayChain chain;
|
GstPlayChain chain;
|
||||||
GstPad *sinkpad;
|
GstPad *sinkpad;
|
||||||
GstElement *queue;
|
GstElement *queue;
|
||||||
|
GstElement *filter;
|
||||||
GstElement *conv;
|
GstElement *conv;
|
||||||
GstElement *sink;
|
GstElement *sink;
|
||||||
gboolean async;
|
gboolean async;
|
||||||
@ -237,6 +239,8 @@ struct _GstPlaySink
|
|||||||
/* properties */
|
/* properties */
|
||||||
GstElement *audio_sink;
|
GstElement *audio_sink;
|
||||||
GstElement *video_sink;
|
GstElement *video_sink;
|
||||||
|
GstElement *audio_filter;
|
||||||
|
GstElement *video_filter;
|
||||||
GstElement *visualisation;
|
GstElement *visualisation;
|
||||||
GstElement *text_sink;
|
GstElement *text_sink;
|
||||||
gdouble volume;
|
gdouble volume;
|
||||||
@ -338,6 +342,8 @@ enum
|
|||||||
PROP_TEXT_SINK,
|
PROP_TEXT_SINK,
|
||||||
PROP_SEND_EVENT_MODE,
|
PROP_SEND_EVENT_MODE,
|
||||||
PROP_FORCE_ASPECT_RATIO,
|
PROP_FORCE_ASPECT_RATIO,
|
||||||
|
PROP_VIDEO_FILTER,
|
||||||
|
PROP_AUDIO_FILTER,
|
||||||
PROP_LAST
|
PROP_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -510,6 +516,29 @@ gst_play_sink_class_init (GstPlaySinkClass * klass)
|
|||||||
G_MININT64, G_MAXINT64, 0,
|
G_MININT64, G_MAXINT64, 0,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstPlaySink:video-filter:
|
||||||
|
*
|
||||||
|
* Set the video filter element/bin to use. Will apply on a best-effort basis
|
||||||
|
* unless GST_PLAY_FLAG_FORCE_FILTERS is set. playsink must be in
|
||||||
|
* %GST_STATE_NULL
|
||||||
|
*/
|
||||||
|
g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
|
||||||
|
g_param_spec_object ("video-filter", "Video filter",
|
||||||
|
"the video filter(s) to apply, if possible",
|
||||||
|
GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
/**
|
||||||
|
* GstPlaySink:audio-filter:
|
||||||
|
*
|
||||||
|
* Set the audio filter element/bin to use. Will apply on a best-effort basis
|
||||||
|
* unless GST_PLAY_FLAG_FORCE_FILTERS is set. playsink must be in
|
||||||
|
* %GST_STATE_NULL
|
||||||
|
*/
|
||||||
|
g_object_class_install_property (gobject_klass, PROP_AUDIO_FILTER,
|
||||||
|
g_param_spec_object ("audio-filter", "Audio filter",
|
||||||
|
"the audio filter(s) to apply, if possible",
|
||||||
|
GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GstPlaySink:video-sink:
|
* GstPlaySink:video-sink:
|
||||||
*
|
*
|
||||||
@ -720,6 +749,16 @@ gst_play_sink_dispose (GObject * object)
|
|||||||
|
|
||||||
playsink = GST_PLAY_SINK (object);
|
playsink = GST_PLAY_SINK (object);
|
||||||
|
|
||||||
|
if (playsink->audio_filter != NULL) {
|
||||||
|
gst_element_set_state (playsink->audio_filter, GST_STATE_NULL);
|
||||||
|
gst_object_unref (playsink->audio_filter);
|
||||||
|
playsink->audio_filter = NULL;
|
||||||
|
}
|
||||||
|
if (playsink->video_filter != NULL) {
|
||||||
|
gst_element_set_state (playsink->video_filter, GST_STATE_NULL);
|
||||||
|
gst_object_unref (playsink->video_filter);
|
||||||
|
playsink->video_filter = NULL;
|
||||||
|
}
|
||||||
if (playsink->audio_sink != NULL) {
|
if (playsink->audio_sink != NULL) {
|
||||||
gst_element_set_state (playsink->audio_sink, GST_STATE_NULL);
|
gst_element_set_state (playsink->audio_sink, GST_STATE_NULL);
|
||||||
gst_object_unref (playsink->audio_sink);
|
gst_object_unref (playsink->audio_sink);
|
||||||
@ -888,6 +927,83 @@ gst_play_sink_get_sink (GstPlaySink * playsink, GstPlaySinkType type)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_play_sink_set_filter (GstPlaySink * playsink, GstPlaySinkType type,
|
||||||
|
GstElement * filter)
|
||||||
|
{
|
||||||
|
GstElement **elem = NULL, *old = NULL;
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (playsink,
|
||||||
|
"Setting filter %" GST_PTR_FORMAT " as filter type %d", filter, type);
|
||||||
|
|
||||||
|
GST_PLAY_SINK_LOCK (playsink);
|
||||||
|
switch (type) {
|
||||||
|
case GST_PLAY_SINK_TYPE_AUDIO:
|
||||||
|
case GST_PLAY_SINK_TYPE_AUDIO_RAW:
|
||||||
|
elem = &playsink->audio_filter;
|
||||||
|
break;
|
||||||
|
case GST_PLAY_SINK_TYPE_VIDEO:
|
||||||
|
case GST_PLAY_SINK_TYPE_VIDEO_RAW:
|
||||||
|
elem = &playsink->video_filter;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (elem) {
|
||||||
|
old = *elem;
|
||||||
|
if (filter)
|
||||||
|
gst_object_ref_sink (filter);
|
||||||
|
*elem = filter;
|
||||||
|
}
|
||||||
|
GST_PLAY_SINK_UNLOCK (playsink);
|
||||||
|
|
||||||
|
if (old) {
|
||||||
|
/* Set the old filter to NULL if it is not used any longer */
|
||||||
|
if (old != filter && !GST_OBJECT_PARENT (old))
|
||||||
|
gst_element_set_state (old, GST_STATE_NULL);
|
||||||
|
gst_object_unref (old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GstElement *
|
||||||
|
gst_play_sink_get_filter (GstPlaySink * playsink, GstPlaySinkType type)
|
||||||
|
{
|
||||||
|
GstElement *result = NULL;
|
||||||
|
GstElement *elem = NULL, *chainp = NULL;
|
||||||
|
|
||||||
|
GST_PLAY_SINK_LOCK (playsink);
|
||||||
|
switch (type) {
|
||||||
|
case GST_PLAY_SINK_TYPE_AUDIO_RAW:
|
||||||
|
{
|
||||||
|
GstPlayAudioChain *chain;
|
||||||
|
if ((chain = (GstPlayAudioChain *) playsink->audiochain))
|
||||||
|
chainp = chain->filter;
|
||||||
|
elem = playsink->audio_filter;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GST_PLAY_SINK_TYPE_VIDEO_RAW:
|
||||||
|
{
|
||||||
|
GstPlayVideoChain *chain;
|
||||||
|
if ((chain = (GstPlayVideoChain *) playsink->videochain))
|
||||||
|
chainp = chain->filter;
|
||||||
|
elem = playsink->video_filter;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (chainp) {
|
||||||
|
/* we have an active chain with a filter, get the filter */
|
||||||
|
result = gst_object_ref (chainp);
|
||||||
|
}
|
||||||
|
/* nothing found, return last configured filter */
|
||||||
|
if (result == NULL && elem)
|
||||||
|
result = gst_object_ref (elem);
|
||||||
|
GST_PLAY_SINK_UNLOCK (playsink);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static GstPadProbeReturn
|
static GstPadProbeReturn
|
||||||
gst_play_sink_vis_blocked (GstPad * tee_pad, GstPadProbeInfo * info,
|
gst_play_sink_vis_blocked (GstPad * tee_pad, GstPadProbeInfo * info,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
@ -1571,14 +1687,14 @@ update_colorbalance (GstPlaySink * playsink)
|
|||||||
/* make the element (bin) that contains the elements needed to perform
|
/* make the element (bin) that contains the elements needed to perform
|
||||||
* video display.
|
* video display.
|
||||||
*
|
*
|
||||||
* +------------------------------------------------------------+
|
* +------------------------------------------------------------------------+
|
||||||
* | vbin |
|
* | vbin |
|
||||||
* | +-------+ +----------+ +----------+ +---------+ |
|
* | +--------+ +-------+ +----------+ +----------+ +---------+ |
|
||||||
* | | queue | |colorspace| |videoscale| |videosink| |
|
* | | filter | | queue | |colorspace| |videoscale| |videosink| |
|
||||||
* | +-sink src-sink src-sink src-sink | |
|
* | +-sink src-sink src-sink src-sink src-sink | |
|
||||||
* | | +-------+ +----------+ +----------+ +---------+ |
|
* | | +--------+ +-------+ +----------+ +----------+ +---------+ |
|
||||||
* sink-+ |
|
* sink-+ |
|
||||||
* +------------------------------------------------------------+
|
* +------------------------------------------------------------------------+
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static GstPlayVideoChain *
|
static GstPlayVideoChain *
|
||||||
@ -1683,6 +1799,28 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
head = chain->sink;
|
||||||
|
prev = NULL;
|
||||||
|
|
||||||
|
/* add the video filter first, so everything is working with post-filter
|
||||||
|
* samples */
|
||||||
|
chain->filter = gst_play_sink_get_filter (playsink,
|
||||||
|
GST_PLAY_SINK_TYPE_VIDEO_RAW);
|
||||||
|
if (chain->filter) {
|
||||||
|
if (!raw) {
|
||||||
|
if (playsink->flags & GST_PLAY_FLAG_FORCE_FILTERS) {
|
||||||
|
goto filter_with_nonraw;
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (playsink,
|
||||||
|
"skipping video filter since we're not raw");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (playsink, "adding video filter");
|
||||||
|
gst_bin_add (bin, chain->filter);
|
||||||
|
head = prev = chain->filter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* decouple decoder from sink, this improves playback quite a lot since the
|
/* decouple decoder from sink, this improves playback quite a lot since the
|
||||||
* decoder can continue while the sink blocks for synchronisation. We don't
|
* 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
|
* need a lot of buffers as this consumes a lot of memory and we don't want
|
||||||
@ -1693,13 +1831,18 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
|
|||||||
GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
|
GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
|
||||||
(_("Missing element '%s' - check your GStreamer installation."),
|
(_("Missing element '%s' - check your GStreamer installation."),
|
||||||
"queue"), ("video rendering might be suboptimal"));
|
"queue"), ("video rendering might be suboptimal"));
|
||||||
head = chain->sink;
|
|
||||||
prev = NULL;
|
|
||||||
} else {
|
} else {
|
||||||
g_object_set (G_OBJECT (chain->queue), "max-size-buffers", 3,
|
g_object_set (G_OBJECT (chain->queue), "max-size-buffers", 3,
|
||||||
"max-size-bytes", 0, "max-size-time", (gint64) 0, "silent", TRUE, NULL);
|
"max-size-bytes", 0, "max-size-time", (gint64) 0, "silent", TRUE, NULL);
|
||||||
gst_bin_add (bin, chain->queue);
|
gst_bin_add (bin, chain->queue);
|
||||||
head = prev = chain->queue;
|
if (prev) {
|
||||||
|
if (!gst_element_link_pads_full (prev, "src", chain->queue, "sink",
|
||||||
|
GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
|
||||||
|
goto link_failed;
|
||||||
|
} else {
|
||||||
|
head = chain->queue;
|
||||||
|
}
|
||||||
|
prev = chain->queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_OBJECT_LOCK (playsink);
|
GST_OBJECT_LOCK (playsink);
|
||||||
@ -1813,13 +1956,21 @@ link_failed:
|
|||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (playsink, CORE, PAD,
|
GST_ELEMENT_ERROR (playsink, CORE, PAD,
|
||||||
(NULL), ("Failed to configure the video sink."));
|
(NULL), ("Failed to configure the video sink."));
|
||||||
/* checking sink made it READY */
|
goto cleanup;
|
||||||
gst_element_set_state (chain->sink, GST_STATE_NULL);
|
|
||||||
/* Remove chain from the bin to allow reuse later */
|
|
||||||
gst_bin_remove (bin, chain->sink);
|
|
||||||
free_chain ((GstPlayChain *) chain);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
filter_with_nonraw:
|
||||||
|
{
|
||||||
|
GST_ELEMENT_ERROR (playsink, CORE, NEGOTIATION,
|
||||||
|
(NULL), ("Cannot apply video-filter on non-raw stream"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
cleanup:
|
||||||
|
/* checking sink made it READY */
|
||||||
|
gst_element_set_state (chain->sink, GST_STATE_NULL);
|
||||||
|
/* Remove chain from the bin to allow reuse later */
|
||||||
|
gst_bin_remove (bin, chain->sink);
|
||||||
|
free_chain ((GstPlayChain *) chain);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -1831,6 +1982,10 @@ setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
|
|||||||
|
|
||||||
chain = playsink->videochain;
|
chain = playsink->videochain;
|
||||||
|
|
||||||
|
/* if we have a filter, and raw-ness changed, we have to force a rebuild */
|
||||||
|
if (chain->filter && chain->chain.raw != raw)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
chain->chain.raw = raw;
|
chain->chain.raw = raw;
|
||||||
|
|
||||||
/* if the chain was active we don't do anything */
|
/* if the chain was active we don't do anything */
|
||||||
@ -2444,14 +2599,14 @@ notify_mute_cb (GObject * object, GParamSpec * pspec, GstPlaySink * playsink)
|
|||||||
* We add a tee as the first element so that we can link the visualisation chain
|
* We add a tee as the first element so that we can link the visualisation chain
|
||||||
* to it when requested.
|
* to it when requested.
|
||||||
*
|
*
|
||||||
* +------------------------------------------------+
|
* +--------------------------------------------------------------+
|
||||||
* | abin |
|
* | abin |
|
||||||
* | +---------+ +---------+ +-----------+ |
|
* | +----------+ +--------+ +---------+ +-----------+ |
|
||||||
* | | queue | | convbin | | audiosink | |
|
* | | filter | | queue | | convbin | | audiosink | |
|
||||||
* | +-sink src-sink src-sink | |
|
* | +-sink src-sink src-sink src-sink | |
|
||||||
* | | +---------+ +---------+ +-----------+ |
|
* | | +----------+ +--------+ +---------+ +-----------+ |
|
||||||
* sink-+ |
|
* sink-+ |
|
||||||
* +------------------------------------------------+
|
* +--------------------------------------------------------------+
|
||||||
*/
|
*/
|
||||||
static GstPlayAudioChain *
|
static GstPlayAudioChain *
|
||||||
gen_audio_chain (GstPlaySink * playsink, gboolean raw)
|
gen_audio_chain (GstPlaySink * playsink, gboolean raw)
|
||||||
@ -2498,6 +2653,28 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw)
|
|||||||
gst_object_ref_sink (bin);
|
gst_object_ref_sink (bin);
|
||||||
gst_bin_add (bin, chain->sink);
|
gst_bin_add (bin, chain->sink);
|
||||||
|
|
||||||
|
head = chain->sink;
|
||||||
|
prev = NULL;
|
||||||
|
|
||||||
|
/* add the audio filter first, so everything is working with post-filter
|
||||||
|
* samples */
|
||||||
|
chain->filter = gst_play_sink_get_filter (playsink,
|
||||||
|
GST_PLAY_SINK_TYPE_AUDIO_RAW);
|
||||||
|
if (chain->filter) {
|
||||||
|
if (!raw) {
|
||||||
|
if (playsink->flags & GST_PLAY_FLAG_FORCE_FILTERS) {
|
||||||
|
goto filter_with_nonraw;
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (playsink,
|
||||||
|
"skipping video filter since we're not raw");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (playsink, "adding video filter");
|
||||||
|
gst_bin_add (bin, chain->filter);
|
||||||
|
head = prev = chain->filter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* we have to add a queue when we need to decouple for the video sink in
|
/* we have to add a queue when we need to decouple for the video sink in
|
||||||
* visualisations and for streamsynchronizer */
|
* visualisations and for streamsynchronizer */
|
||||||
GST_DEBUG_OBJECT (playsink, "adding audio queue");
|
GST_DEBUG_OBJECT (playsink, "adding audio queue");
|
||||||
@ -2507,12 +2684,17 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw)
|
|||||||
GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
|
GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
|
||||||
(_("Missing element '%s' - check your GStreamer installation."),
|
(_("Missing element '%s' - check your GStreamer installation."),
|
||||||
"queue"), ("audio playback and visualizations might not work"));
|
"queue"), ("audio playback and visualizations might not work"));
|
||||||
head = chain->sink;
|
|
||||||
prev = NULL;
|
|
||||||
} else {
|
} else {
|
||||||
g_object_set (chain->queue, "silent", TRUE, NULL);
|
g_object_set (chain->queue, "silent", TRUE, NULL);
|
||||||
gst_bin_add (bin, chain->queue);
|
gst_bin_add (bin, chain->queue);
|
||||||
prev = head = chain->queue;
|
if (prev) {
|
||||||
|
if (!gst_element_link_pads_full (prev, "src", chain->queue, "sink",
|
||||||
|
GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
|
||||||
|
goto link_failed;
|
||||||
|
} else {
|
||||||
|
head = chain->queue;
|
||||||
|
}
|
||||||
|
prev = chain->queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find ts-offset element */
|
/* find ts-offset element */
|
||||||
@ -2682,13 +2864,21 @@ link_failed:
|
|||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (playsink, CORE, PAD,
|
GST_ELEMENT_ERROR (playsink, CORE, PAD,
|
||||||
(NULL), ("Failed to configure the audio sink."));
|
(NULL), ("Failed to configure the audio sink."));
|
||||||
/* checking sink made it READY */
|
goto cleanup;
|
||||||
gst_element_set_state (chain->sink, GST_STATE_NULL);
|
|
||||||
/* Remove chain from the bin to allow reuse later */
|
|
||||||
gst_bin_remove (bin, chain->sink);
|
|
||||||
free_chain ((GstPlayChain *) chain);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
filter_with_nonraw:
|
||||||
|
{
|
||||||
|
GST_ELEMENT_ERROR (playsink, CORE, NEGOTIATION,
|
||||||
|
(NULL), ("Cannot apply video-filter on non-raw stream"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
cleanup:
|
||||||
|
/* checking sink made it READY */
|
||||||
|
gst_element_set_state (chain->sink, GST_STATE_NULL);
|
||||||
|
/* Remove chain from the bin to allow reuse later */
|
||||||
|
gst_bin_remove (bin, chain->sink);
|
||||||
|
free_chain ((GstPlayChain *) chain);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -2702,6 +2892,10 @@ setup_audio_chain (GstPlaySink * playsink, gboolean raw)
|
|||||||
chain = playsink->audiochain;
|
chain = playsink->audiochain;
|
||||||
conv = GST_PLAY_SINK_AUDIO_CONVERT_CAST (chain->conv);
|
conv = GST_PLAY_SINK_AUDIO_CONVERT_CAST (chain->conv);
|
||||||
|
|
||||||
|
/* if we have a filter, and raw-ness changed, we have to force a rebuild */
|
||||||
|
if (chain->filter && chain->chain.raw != raw)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
chain->chain.raw = raw;
|
chain->chain.raw = raw;
|
||||||
|
|
||||||
/* if the chain was active we don't do anything */
|
/* if the chain was active we don't do anything */
|
||||||
@ -3342,8 +3536,8 @@ gst_play_sink_do_reconfigure (GstPlaySink * playsink)
|
|||||||
/* unlink the old plugin and unghost the pad */
|
/* unlink the old plugin and unghost the pad */
|
||||||
gst_pad_unlink (playsink->vischain->vispeerpad,
|
gst_pad_unlink (playsink->vischain->vispeerpad,
|
||||||
playsink->vischain->vissinkpad);
|
playsink->vischain->vissinkpad);
|
||||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->
|
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->vischain->
|
||||||
vischain->srcpad), NULL);
|
srcpad), NULL);
|
||||||
|
|
||||||
/* set the old plugin to NULL and remove */
|
/* set the old plugin to NULL and remove */
|
||||||
gst_element_set_state (playsink->vischain->vis, GST_STATE_NULL);
|
gst_element_set_state (playsink->vischain->vis, GST_STATE_NULL);
|
||||||
@ -3365,8 +3559,8 @@ gst_play_sink_do_reconfigure (GstPlaySink * playsink)
|
|||||||
/* link pads */
|
/* link pads */
|
||||||
gst_pad_link_full (playsink->vischain->vispeerpad,
|
gst_pad_link_full (playsink->vischain->vispeerpad,
|
||||||
playsink->vischain->vissinkpad, GST_PAD_LINK_CHECK_NOTHING);
|
playsink->vischain->vissinkpad, GST_PAD_LINK_CHECK_NOTHING);
|
||||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->
|
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->vischain->
|
||||||
vischain->srcpad), playsink->vischain->vissrcpad);
|
srcpad), playsink->vischain->vissrcpad);
|
||||||
} else {
|
} else {
|
||||||
srcpad =
|
srcpad =
|
||||||
gst_element_get_static_pad (playsink->vischain->chain.bin, "src");
|
gst_element_get_static_pad (playsink->vischain->chain.bin, "src");
|
||||||
@ -3836,8 +4030,8 @@ video_set_blocked (GstPlaySink * playsink, gboolean blocked)
|
|||||||
(playsink->video_pad)));
|
(playsink->video_pad)));
|
||||||
if (blocked && playsink->video_block_id == 0) {
|
if (blocked && playsink->video_block_id == 0) {
|
||||||
if (playsink->vis_pad_block_id)
|
if (playsink->vis_pad_block_id)
|
||||||
gst_pad_remove_probe (((GstPlayVisChain *) playsink->
|
gst_pad_remove_probe (((GstPlayVisChain *) playsink->vischain)->
|
||||||
vischain)->blockpad, playsink->vis_pad_block_id);
|
blockpad, playsink->vis_pad_block_id);
|
||||||
playsink->vis_pad_block_id = 0;
|
playsink->vis_pad_block_id = 0;
|
||||||
|
|
||||||
playsink->video_block_id =
|
playsink->video_block_id =
|
||||||
@ -3863,8 +4057,8 @@ audio_set_blocked (GstPlaySink * playsink, gboolean blocked)
|
|||||||
(playsink->audio_pad)));
|
(playsink->audio_pad)));
|
||||||
if (blocked && playsink->audio_block_id == 0) {
|
if (blocked && playsink->audio_block_id == 0) {
|
||||||
if (playsink->vis_pad_block_id)
|
if (playsink->vis_pad_block_id)
|
||||||
gst_pad_remove_probe (((GstPlayVisChain *) playsink->
|
gst_pad_remove_probe (((GstPlayVisChain *) playsink->vischain)->
|
||||||
vischain)->blockpad, playsink->vis_pad_block_id);
|
blockpad, playsink->vis_pad_block_id);
|
||||||
playsink->vis_pad_block_id = 0;
|
playsink->vis_pad_block_id = 0;
|
||||||
|
|
||||||
playsink->audio_block_id =
|
playsink->audio_block_id =
|
||||||
@ -3872,8 +4066,8 @@ audio_set_blocked (GstPlaySink * playsink, gboolean blocked)
|
|||||||
sinkpad_blocked_cb, playsink, NULL);
|
sinkpad_blocked_cb, playsink, NULL);
|
||||||
} else if (!blocked && playsink->audio_block_id) {
|
} else if (!blocked && playsink->audio_block_id) {
|
||||||
if (playsink->vis_pad_block_id)
|
if (playsink->vis_pad_block_id)
|
||||||
gst_pad_remove_probe (((GstPlayVisChain *) playsink->
|
gst_pad_remove_probe (((GstPlayVisChain *) playsink->vischain)->
|
||||||
vischain)->blockpad, playsink->vis_pad_block_id);
|
blockpad, playsink->vis_pad_block_id);
|
||||||
playsink->vis_pad_block_id = 0;
|
playsink->vis_pad_block_id = 0;
|
||||||
|
|
||||||
gst_pad_remove_probe (opad, playsink->audio_block_id);
|
gst_pad_remove_probe (opad, playsink->audio_block_id);
|
||||||
@ -3895,8 +4089,8 @@ text_set_blocked (GstPlaySink * playsink, gboolean blocked)
|
|||||||
(playsink->text_pad)));
|
(playsink->text_pad)));
|
||||||
if (blocked && playsink->text_block_id == 0) {
|
if (blocked && playsink->text_block_id == 0) {
|
||||||
if (playsink->vis_pad_block_id)
|
if (playsink->vis_pad_block_id)
|
||||||
gst_pad_remove_probe (((GstPlayVisChain *) playsink->
|
gst_pad_remove_probe (((GstPlayVisChain *) playsink->vischain)->
|
||||||
vischain)->blockpad, playsink->vis_pad_block_id);
|
blockpad, playsink->vis_pad_block_id);
|
||||||
playsink->vis_pad_block_id = 0;
|
playsink->vis_pad_block_id = 0;
|
||||||
|
|
||||||
playsink->text_block_id =
|
playsink->text_block_id =
|
||||||
@ -4187,8 +4381,8 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
|
|||||||
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD (res)));
|
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD (res)));
|
||||||
|
|
||||||
if (playsink->vis_pad_block_id)
|
if (playsink->vis_pad_block_id)
|
||||||
gst_pad_remove_probe (((GstPlayVisChain *) playsink->
|
gst_pad_remove_probe (((GstPlayVisChain *) playsink->vischain)->
|
||||||
vischain)->blockpad, playsink->vis_pad_block_id);
|
blockpad, playsink->vis_pad_block_id);
|
||||||
playsink->vis_pad_block_id = 0;
|
playsink->vis_pad_block_id = 0;
|
||||||
|
|
||||||
*block_id =
|
*block_id =
|
||||||
@ -4497,8 +4691,8 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition)
|
|||||||
audio_set_blocked (playsink, FALSE);
|
audio_set_blocked (playsink, FALSE);
|
||||||
text_set_blocked (playsink, FALSE);
|
text_set_blocked (playsink, FALSE);
|
||||||
if (playsink->vis_pad_block_id)
|
if (playsink->vis_pad_block_id)
|
||||||
gst_pad_remove_probe (((GstPlayVisChain *) playsink->
|
gst_pad_remove_probe (((GstPlayVisChain *) playsink->vischain)->
|
||||||
vischain)->blockpad, playsink->vis_pad_block_id);
|
blockpad, playsink->vis_pad_block_id);
|
||||||
playsink->vis_pad_block_id = 0;
|
playsink->vis_pad_block_id = 0;
|
||||||
|
|
||||||
GST_PLAY_SINK_UNLOCK (playsink);
|
GST_PLAY_SINK_UNLOCK (playsink);
|
||||||
@ -4706,6 +4900,14 @@ gst_play_sink_set_property (GObject * object, guint prop_id,
|
|||||||
case PROP_AV_OFFSET:
|
case PROP_AV_OFFSET:
|
||||||
gst_play_sink_set_av_offset (playsink, g_value_get_int64 (value));
|
gst_play_sink_set_av_offset (playsink, g_value_get_int64 (value));
|
||||||
break;
|
break;
|
||||||
|
case PROP_VIDEO_FILTER:
|
||||||
|
gst_play_sink_set_filter (playsink, GST_PLAY_SINK_TYPE_VIDEO,
|
||||||
|
g_value_get_object (value));
|
||||||
|
break;
|
||||||
|
case PROP_AUDIO_FILTER:
|
||||||
|
gst_play_sink_set_filter (playsink, GST_PLAY_SINK_TYPE_AUDIO,
|
||||||
|
g_value_get_object (value));
|
||||||
|
break;
|
||||||
case PROP_VIDEO_SINK:
|
case PROP_VIDEO_SINK:
|
||||||
gst_play_sink_set_sink (playsink, GST_PLAY_SINK_TYPE_VIDEO,
|
gst_play_sink_set_sink (playsink, GST_PLAY_SINK_TYPE_VIDEO,
|
||||||
g_value_get_object (value));
|
g_value_get_object (value));
|
||||||
@ -4781,6 +4983,14 @@ gst_play_sink_get_property (GObject * object, guint prop_id,
|
|||||||
case PROP_AV_OFFSET:
|
case PROP_AV_OFFSET:
|
||||||
g_value_set_int64 (value, gst_play_sink_get_av_offset (playsink));
|
g_value_set_int64 (value, gst_play_sink_get_av_offset (playsink));
|
||||||
break;
|
break;
|
||||||
|
case PROP_VIDEO_FILTER:
|
||||||
|
g_value_take_object (value, gst_play_sink_get_filter (playsink,
|
||||||
|
GST_PLAY_SINK_TYPE_VIDEO));
|
||||||
|
break;
|
||||||
|
case PROP_AUDIO_FILTER:
|
||||||
|
g_value_take_object (value, gst_play_sink_get_filter (playsink,
|
||||||
|
GST_PLAY_SINK_TYPE_AUDIO));
|
||||||
|
break;
|
||||||
case PROP_VIDEO_SINK:
|
case PROP_VIDEO_SINK:
|
||||||
g_value_take_object (value, gst_play_sink_get_sink (playsink,
|
g_value_take_object (value, gst_play_sink_get_sink (playsink,
|
||||||
GST_PLAY_SINK_TYPE_VIDEO));
|
GST_PLAY_SINK_TYPE_VIDEO));
|
||||||
|
@ -72,6 +72,9 @@ GstPad * gst_play_sink_request_pad (GstPlaySink *playsink, GstPlaySin
|
|||||||
void gst_play_sink_release_pad (GstPlaySink *playsink, GstPad *pad);
|
void gst_play_sink_release_pad (GstPlaySink *playsink, GstPad *pad);
|
||||||
void gst_play_sink_refresh_pad (GstPlaySink *playsink, GstPad *pad, GstPlaySinkType type);
|
void gst_play_sink_refresh_pad (GstPlaySink *playsink, GstPad *pad, GstPlaySinkType type);
|
||||||
|
|
||||||
|
void gst_play_sink_set_filter (GstPlaySink * playsink, GstPlaySinkType type, GstElement * filter);
|
||||||
|
GstElement * gst_play_sink_get_filter (GstPlaySink * playsink, GstPlaySinkType type);
|
||||||
|
|
||||||
void gst_play_sink_set_sink (GstPlaySink * playsink, GstPlaySinkType type, GstElement * sink);
|
void gst_play_sink_set_sink (GstPlaySink * playsink, GstPlaySinkType type, GstElement * sink);
|
||||||
GstElement * gst_play_sink_get_sink (GstPlaySink * playsink, GstPlaySinkType type);
|
GstElement * gst_play_sink_get_sink (GstPlaySink * playsink, GstPlaySinkType type);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user