deinterleave: implement accept-caps

Avoid using default accept-caps handler that will query downstream
and is more expensive. Just check if the caps is compatible with
the template and check if the channels are the same.
This commit is contained in:
Thiago Santos 2015-09-30 17:35:33 -03:00
parent c0c8d503da
commit 5c7b051b90
2 changed files with 96 additions and 38 deletions

View file

@ -360,6 +360,56 @@ gst_deinterleave_set_process_function (GstDeinterleave * self)
return TRUE;
}
static gboolean
gst_deinterleave_check_caps_change (GstDeinterleave * self,
GstAudioInfo * old_info, GstAudioInfo * new_info)
{
gint i;
gboolean same_layout = TRUE;
gboolean was_unpositioned;
gboolean is_unpositioned = GST_AUDIO_INFO_IS_UNPOSITIONED (new_info);
gint new_channels = GST_AUDIO_INFO_CHANNELS (new_info);
gint old_channels;
was_unpositioned = GST_AUDIO_INFO_IS_UNPOSITIONED (old_info);
old_channels = GST_AUDIO_INFO_CHANNELS (old_info);
/* We allow caps changes as long as the number of channels doesn't change
* and the channel positions stay the same. _getcaps() should've cared
* for this already but better be safe.
*/
if (new_channels != old_channels)
goto cannot_change_caps;
/* Now check the channel positions. If we had no channel positions
* and get them or the other way around things have changed.
* If we had channel positions and get different ones things have
* changed too of course
*/
if ((!was_unpositioned && is_unpositioned) || (was_unpositioned
&& !is_unpositioned))
goto cannot_change_caps;
if (!is_unpositioned) {
if (GST_AUDIO_INFO_CHANNELS (old_info) !=
GST_AUDIO_INFO_CHANNELS (new_info))
goto cannot_change_caps;
for (i = 0; i < GST_AUDIO_INFO_CHANNELS (old_info); i++) {
if (new_info->position[i] != old_info->position[i]) {
same_layout = FALSE;
break;
}
}
if (!same_layout)
goto cannot_change_caps;
}
return TRUE;
cannot_change_caps:
return FALSE;
}
static gboolean
gst_deinterleave_sink_setcaps (GstDeinterleave * self, GstCaps * caps)
{
@ -375,51 +425,17 @@ gst_deinterleave_sink_setcaps (GstDeinterleave * self, GstCaps * caps)
goto unsupported_caps;
if (self->sinkcaps && !gst_caps_is_equal (caps, self->sinkcaps)) {
gint i;
gboolean same_layout = TRUE;
gboolean was_unpositioned;
gboolean is_unpositioned =
GST_AUDIO_INFO_IS_UNPOSITIONED (&self->audio_info);
gint new_channels = GST_AUDIO_INFO_CHANNELS (&self->audio_info);
gint old_channels;
GstAudioInfo old_info;
gst_audio_info_init (&old_info);
if (!gst_audio_info_from_caps (&old_info, self->sinkcaps))
goto info_from_caps_failed;
was_unpositioned = GST_AUDIO_INFO_IS_UNPOSITIONED (&old_info);
old_channels = GST_AUDIO_INFO_CHANNELS (&old_info);
/* We allow caps changes as long as the number of channels doesn't change
* and the channel positions stay the same. _getcaps() should've cared
* for this already but better be safe.
*/
if (new_channels != old_channels ||
!gst_deinterleave_set_process_function (self))
goto cannot_change_caps;
/* Now check the channel positions. If we had no channel positions
* and get them or the other way around things have changed.
* If we had channel positions and get different ones things have
* changed too of course
*/
if ((!was_unpositioned && is_unpositioned) || (was_unpositioned
&& !is_unpositioned))
goto cannot_change_caps;
if (!is_unpositioned) {
if (GST_AUDIO_INFO_CHANNELS (&old_info) !=
GST_AUDIO_INFO_CHANNELS (&self->audio_info))
if (gst_deinterleave_check_caps_change (self, &old_info, &self->audio_info)) {
if (!gst_deinterleave_set_process_function (self))
goto cannot_change_caps;
for (i = 0; i < GST_AUDIO_INFO_CHANNELS (&old_info); i++) {
if (self->audio_info.position[i] != old_info.position[i]) {
same_layout = FALSE;
break;
}
}
if (!same_layout)
goto cannot_change_caps;
}
} else
goto cannot_change_caps;
}
@ -504,6 +520,35 @@ __set_channels (GstCaps * caps, gint channels)
}
}
static gboolean
gst_deinterleave_sink_acceptcaps (GstPad * pad, GstObject * parent,
GstCaps * caps)
{
GstDeinterleave *self = GST_DEINTERLEAVE (parent);
GstCaps *templ_caps = gst_pad_get_pad_template_caps (pad);
gboolean ret;
ret = gst_caps_can_intersect (templ_caps, caps);
gst_caps_unref (templ_caps);
if (ret && self->sinkcaps) {
GstAudioInfo new_info;
gst_audio_info_init (&new_info);
if (!gst_audio_info_from_caps (&new_info, caps))
goto info_from_caps_failed;
ret =
gst_deinterleave_check_caps_change (self, &self->audio_info, &new_info);
}
return ret;
info_from_caps_failed:
{
GST_ERROR_OBJECT (self, "coud not get info from caps");
return FALSE;
}
}
static GstCaps *
gst_deinterleave_getcaps (GstPad * pad, GstObject * parent, GstCaps * filter)
{
@ -642,6 +687,16 @@ gst_deinterleave_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
res = TRUE;
break;
}
case GST_QUERY_ACCEPT_CAPS:{
GstCaps *caps;
gboolean ret;
gst_query_parse_accept_caps (query, &caps);
ret = gst_deinterleave_sink_acceptcaps (pad, parent, caps);
gst_query_set_accept_caps_result (query, ret);
res = TRUE;
break;
}
default:
res = gst_pad_query_default (pad, parent, query);
break;

View file

@ -306,6 +306,7 @@ GST_START_TEST (test_2_channels_caps_change)
ret_caps = gst_pad_peer_query_caps (mysrcpad, caps);
fail_if (gst_caps_is_empty (ret_caps));
fail_unless (gst_pad_peer_query_accept_caps (mysrcpad, caps));
gst_caps_unref (ret_caps);
gst_check_setup_events (mysrcpad, deinterleave, caps, GST_FORMAT_TIME);
@ -340,6 +341,7 @@ GST_START_TEST (test_2_channels_caps_change)
NULL);
ret_caps = gst_pad_peer_query_caps (mysrcpad, caps2);
fail_if (gst_caps_is_empty (ret_caps));
fail_unless (gst_pad_peer_query_accept_caps (mysrcpad, caps2));
gst_caps_unref (ret_caps);
gst_pad_set_caps (mysrcpad, caps2);
@ -371,6 +373,7 @@ GST_START_TEST (test_2_channels_caps_change)
ret_caps = gst_pad_peer_query_caps (mysrcpad, caps2);
fail_unless (gst_caps_is_empty (ret_caps));
gst_caps_unref (ret_caps);
fail_if (gst_pad_peer_query_accept_caps (mysrcpad, caps2));
gst_pad_set_caps (mysrcpad, caps2);
inbuf = gst_buffer_new_and_alloc (3 * 48000 * sizeof (gfloat));