autoconvert: Handle reconfiguring on the srcpad

Only upstream renegotiation was properly handled, we needed to answer
that when downstream forces a renegotiation we take into account the
new downstream restrictions.

And add tests for it

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/899>
This commit is contained in:
Thibault Saunier 2021-05-25 20:44:46 -04:00 committed by GStreamer Marge Bot
parent 69db5b77d1
commit e153c558c7
4 changed files with 96 additions and 30 deletions

View file

@ -94,8 +94,6 @@ static GstPad *gst_auto_convert_get_internal_srcpad (GstAutoConvert *
static GstIterator *gst_auto_convert_iterate_internal_links (GstPad * pad, static GstIterator *gst_auto_convert_iterate_internal_links (GstPad * pad,
GstObject * parent); GstObject * parent);
static gboolean gst_auto_convert_sink_setcaps (GstAutoConvert * autoconvert,
GstCaps * caps);
static GstCaps *gst_auto_convert_getcaps (GstAutoConvert * autoconvert, static GstCaps *gst_auto_convert_getcaps (GstAutoConvert * autoconvert,
GstCaps * filter, GstPadDirection dir); GstCaps * filter, GstPadDirection dir);
static GstFlowReturn gst_auto_convert_sink_chain (GstPad * pad, static GstFlowReturn gst_auto_convert_sink_chain (GstPad * pad,
@ -624,7 +622,7 @@ gst_auto_convert_get_or_make_element_from_factory (GstAutoConvert * autoconvert,
/* /*
* This function checks if there is one and only one pad template on the * This function checks if there is one and only one pad template on the
* factory that can accept the given caps. If there is one and only one, * factory that can accept the given caps. If there is one and only one,
* it returns TRUE, otherwise, its FALSE * it returns TRUE, FALSE otherwise
*/ */
static gboolean static gboolean
@ -852,49 +850,62 @@ gst_auto_convert_iterate_internal_links (GstPad * pad, GstObject * parent)
*/ */
static gboolean static gboolean
gst_auto_convert_sink_setcaps (GstAutoConvert * autoconvert, GstCaps * caps) gst_auto_convert_sink_setcaps (GstAutoConvert * autoconvert, GstCaps * caps,
gboolean check_downstream)
{ {
GList *elem; GList *elem;
GstCaps *other_caps = NULL; GstCaps *other_caps = NULL;
GList *factories; GList *factories;
GstCaps *current_caps; GstCaps *current_caps = NULL;
gboolean res = FALSE; gboolean res = FALSE;
GstElement *current_subelement; GstElement *current_subelement = NULL;
g_return_val_if_fail (autoconvert != NULL, FALSE); g_return_val_if_fail (autoconvert != NULL, FALSE);
current_caps = gst_pad_get_current_caps (autoconvert->sinkpad); if (!check_downstream) {
if (current_caps) { current_caps = gst_pad_get_current_caps (autoconvert->sinkpad);
if (gst_caps_is_equal_fixed (caps, current_caps)) {
gst_caps_unref (current_caps); if (current_caps && gst_caps_is_equal_fixed (caps, current_caps))
return TRUE; goto get_out;
}
gst_caps_unref (current_caps);
} }
if (check_downstream)
other_caps = gst_pad_peer_query_caps (autoconvert->srcpad, NULL);
current_subelement = gst_auto_convert_get_subelement (autoconvert); current_subelement = gst_auto_convert_get_subelement (autoconvert);
if (current_subelement) { if (current_subelement) {
if (gst_pad_peer_query_accept_caps (autoconvert->current_internal_srcpad, if (gst_pad_peer_query_accept_caps (autoconvert->current_internal_srcpad,
caps)) { caps)) {
/* If we can set the new caps on the current element,
* then we just get out res = TRUE;
*/ if (other_caps) {
GST_DEBUG_OBJECT (autoconvert, "Could set %s:%s to %" GST_PTR_FORMAT, GstElementFactory *factory =
GST_DEBUG_PAD_NAME (autoconvert->current_internal_srcpad), caps); gst_element_get_factory (current_subelement);
goto get_out;
} else { if (!factory_can_intersect (autoconvert, factory, GST_PAD_SRC,
/* If the current element doesn't work, other_caps)) {
* then we remove the current element before finding a new one. GST_LOG_OBJECT (autoconvert,
*/ "Factory %s does not accept src caps %" GST_PTR_FORMAT,
GST_AUTOCONVERT_LOCK (autoconvert); gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)),
g_clear_object (&autoconvert->current_subelement); other_caps);
g_clear_object (&autoconvert->current_internal_sinkpad); res = FALSE;
g_clear_object (&autoconvert->current_internal_srcpad); }
GST_AUTOCONVERT_UNLOCK (autoconvert); }
if (res) {
/* If we can set the new caps on the current element,
* then we just get out
*/
GST_DEBUG_OBJECT (autoconvert, "Could set %s:%s to %" GST_PTR_FORMAT,
GST_DEBUG_PAD_NAME (autoconvert->current_internal_srcpad), caps);
goto get_out;
}
} }
} }
other_caps = gst_pad_peer_query_caps (autoconvert->srcpad, NULL); if (!check_downstream)
other_caps = gst_pad_peer_query_caps (autoconvert->srcpad, NULL);
/* We already queries downstream caps otherwise */
factories = gst_auto_convert_get_or_load_factories (autoconvert); factories = gst_auto_convert_get_or_load_factories (autoconvert);
for (elem = factories; elem; elem = g_list_next (elem)) { for (elem = factories; elem; elem = g_list_next (elem)) {
@ -940,6 +951,7 @@ gst_auto_convert_sink_setcaps (GstAutoConvert * autoconvert, GstCaps * caps)
get_out: get_out:
gst_clear_object (&current_subelement); gst_clear_object (&current_subelement);
gst_clear_caps (&other_caps); gst_clear_caps (&other_caps);
gst_clear_caps (&current_caps);
if (!res) if (!res)
GST_WARNING_OBJECT (autoconvert, GST_WARNING_OBJECT (autoconvert,
@ -1064,6 +1076,22 @@ gst_auto_convert_sink_chain (GstPad * pad, GstObject * parent,
GstFlowReturn ret = GST_FLOW_NOT_NEGOTIATED; GstFlowReturn ret = GST_FLOW_NOT_NEGOTIATED;
GstAutoConvert *autoconvert = GST_AUTO_CONVERT (parent); GstAutoConvert *autoconvert = GST_AUTO_CONVERT (parent);
if (gst_pad_check_reconfigure (autoconvert->srcpad)) {
GstCaps *sinkcaps = gst_pad_get_current_caps (pad);
GST_INFO_OBJECT (parent, "Needs reconfigure.");
/* if we need to reconfigure we pretend new caps arrived. This
* will reconfigure the transform with the new output format. */
if (sinkcaps
&& !gst_auto_convert_sink_setcaps (autoconvert, sinkcaps, TRUE)) {
gst_clear_caps (&sinkcaps);
GST_ERROR_OBJECT (autoconvert, "Could not reconfigure.");
return GST_FLOW_NOT_NEGOTIATED;
}
gst_clear_caps (&sinkcaps);
}
if (autoconvert->current_internal_srcpad) { if (autoconvert->current_internal_srcpad) {
ret = gst_pad_push (autoconvert->current_internal_srcpad, buffer); ret = gst_pad_push (autoconvert->current_internal_srcpad, buffer);
if (ret != GST_FLOW_OK) if (ret != GST_FLOW_OK)
@ -1112,7 +1140,7 @@ gst_auto_convert_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
GstCaps *caps; GstCaps *caps;
gst_event_parse_caps (event, &caps); gst_event_parse_caps (event, &caps);
ret = gst_auto_convert_sink_setcaps (autoconvert, caps); ret = gst_auto_convert_sink_setcaps (autoconvert, caps, FALSE);
if (!ret) { if (!ret) {
gst_event_unref (event); gst_event_unref (event);
return ret; return ret;

View file

@ -0,0 +1,22 @@
meta,
args = {
"gltestsrc ! gldownload ! autovideoconvert name=convert ! capsfilter name=capsfilter caps=\"video/x-raw(memory:GLMemory)\" ! fakevideosink name=sink",
},
configs = {
"$(validateflow), pad=convert:src, record-buffers=true, ignored-fields=\"stream-start={stream-id,group-id,stream},buffer={meta}\"",
}
crank-clock, repeat=2
wait, on-clock=true
foreach,
caps = <
"video/x-raw",
"video/x-raw(memory:GLMemory)",
"video/x-raw",
>,
actions = {
[set-properties, capsfilter::caps="$(caps)"],
[crank-clock, repeat=2],
[wait, on-clock=true],
}
stop

View file

@ -0,0 +1,15 @@
event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE;
event caps: video/x-raw(memory:GLMemory), format=(string)RGBA, framerate=(fraction)30/1, height=(int)240, texture-target=(string)2D, width=(int)320;
event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000
buffer: pts=0:00:00.000000000, dur=0:00:00.033333333, flags=discont
buffer: pts=0:00:00.033333333, dur=0:00:00.033333333
buffer: pts=0:00:00.066666666, dur=0:00:00.033333334
event caps: video/x-raw, format=(string)RGBA, framerate=(fraction)30/1, height=(int)240, texture-target=(string)2D, width=(int)320;
buffer: pts=0:00:00.100000000, dur=0:00:00.033333333
buffer: pts=0:00:00.133333333, dur=0:00:00.033333333
event caps: video/x-raw(memory:GLMemory), format=(string)RGBA, framerate=(fraction)30/1, height=(int)240, texture-target=(string)2D, width=(int)320;
buffer: pts=0:00:00.166666666, dur=0:00:00.033333334
buffer: pts=0:00:00.200000000, dur=0:00:00.033333333
event caps: video/x-raw, format=(string)RGBA, framerate=(fraction)30/1, height=(int)240, texture-target=(string)2D, width=(int)320;
buffer: pts=0:00:00.233333333, dur=0:00:00.033333333
buffer: pts=0:00:00.266666666, dur=0:00:00.033333334

View file

@ -12,6 +12,7 @@ tests = [
{'path': 'vtenc/vtenc_h264_b_frames', 'skip': not applemedia_found_deps}, {'path': 'vtenc/vtenc_h264_b_frames', 'skip': not applemedia_found_deps},
{'path': 'vtenc/vtenc_h265', 'skip': not applemedia_found_deps}, {'path': 'vtenc/vtenc_h265', 'skip': not applemedia_found_deps},
{'path': 'vtenc/vtenc_h265_b_frames', 'skip': not applemedia_found_deps}, {'path': 'vtenc/vtenc_h265_b_frames', 'skip': not applemedia_found_deps},
{'path': 'autovideoconvert/renegotiate'},
] ]
env = environment() env = environment()