uridecodebin: Ensure that pads caps are set before exposing them

We are supposed to guarantee that pads that are exposed have the caps
set, but for sources that have pad with "all raw caps" templates, we end
up exposing pads that don't have caps set yet, which can break code (in
GES for example).

To avoid that we let uridecodebin plug a `decodebin` after such pads and
let decodebin to handle that for us. In the end the only thing that
decodebin does in those cases is to wait for pads to be ready and expose
them, after that `uridecodebin` will expose those pads.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3009>
This commit is contained in:
Thibault Saunier 2022-09-07 10:39:21 -04:00 committed by GStreamer Marge Bot
parent 86dfe03be9
commit 1c6adcab89
3 changed files with 26 additions and 15 deletions

View file

@ -1478,23 +1478,23 @@ no_source:
}
/**
* has_all_raw_caps:
* has_raw_caps:
* @pad: a #GstPad
* @all_raw: pointer to hold the result
*
* check if the caps of the pad are all raw. The caps are all raw if
* all of its structures contain audio/x-raw or video/x-raw.
*
* Returns: %FALSE @pad has no caps. Else TRUE and @all_raw set t the result.
* Returns: %FALSE @pad caps are not set and raw
*/
static gboolean
has_all_raw_caps (GstPad * pad, GstCaps * rawcaps, gboolean * all_raw)
has_raw_caps (GstPad * pad, GstCaps * rawcaps)
{
GstCaps *caps, *intersection;
gint capssize;
gboolean res = FALSE;
caps = gst_pad_query_caps (pad, NULL);
caps = gst_pad_get_current_caps (pad);
if (caps == NULL)
return FALSE;
@ -1506,12 +1506,9 @@ has_all_raw_caps (GstPad * pad, GstCaps * rawcaps, gboolean * all_raw)
goto done;
intersection = gst_caps_intersect (caps, rawcaps);
*all_raw = !gst_caps_is_empty (intersection)
&& (gst_caps_get_size (intersection) == capssize);
res = !gst_caps_is_empty (intersection);
gst_caps_unref (intersection);
res = TRUE;
done:
gst_caps_unref (caps);
return res;
@ -1593,16 +1590,15 @@ analyse_source (GstURIDecodeBin * decoder, gboolean * is_raw,
*have_out = TRUE;
/* if FALSE, this pad has no caps and we continue with the next pad. */
if (!has_all_raw_caps (pad, rawcaps, is_raw)) {
if (!has_raw_caps (pad, rawcaps)) {
gst_object_unref (pad);
g_value_reset (&item);
break;
}
/* caps on source pad are all raw, we can add the pad */
if (*is_raw) {
} else {
/* caps on source pad are all raw, we can add the pad */
GstElement *outelem;
*is_raw = TRUE;
if (use_queue) {
GstPad *sinkpad;
@ -2169,7 +2165,6 @@ static void
source_new_pad (GstElement * element, GstPad * pad, GstURIDecodeBin * bin)
{
GstElement *decoder;
gboolean is_raw;
GstCaps *rawcaps;
GstPad *sinkpad;
@ -2182,7 +2177,7 @@ source_new_pad (GstElement * element, GstPad * pad, GstURIDecodeBin * bin)
rawcaps = DEFAULT_CAPS;
/* if this is a pad with all raw caps, we can expose it */
if (has_all_raw_caps (pad, rawcaps, &is_raw) && is_raw) {
if (has_raw_caps (pad, rawcaps)) {
/* it's all raw, create output pads. */
GST_URI_DECODE_BIN_UNLOCK (bin);
gst_caps_unref (rawcaps);

View file

@ -20,6 +20,7 @@ tests = [
'compositor/renogotiate_failing_unsupported_src_format',
'giosrc/read-growing-file',
'encodebin/set-encoder-properties',
'uridecodebin/expose_raw_pad_caps',
]
env = environment()

View file

@ -0,0 +1,15 @@
meta,
args = {
"uridecodebin uri=testbin://video,num-buffers=1 ! fakesink",
},
handles-states=true,
ignore-eos=true
wait, signal-name="pad-added", target-element-factory-name="uridecodebin", non-blocking=true,
check=[
check-current-pad-caps, expected-caps=[video/x-raw], target-element-factory-name="uridecodebin", pad="src_0", comparison-mode="intersect",
]
pause
stop