videoaggregator: Guarantee that the output format is supported

In the case `videoaggregator` is set as allowing format conversions,
and as we convert only on the sinkpads, we should ensure that the
chosen format is usable by the subclass. This in turns implies
that the format is usable on the srcpad.

When doing conversion *any* format can be used on the sinkpads, and this
is the only way that we can avoid race conditions during renegotiations
so we can not change that fact, we just need to ensure that the chosen
intermediary format is usable, which was not actually ensured before
that patch.

Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/issues/834

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/909>
This commit is contained in:
Thibault Saunier 2020-10-30 13:56:16 -03:00 committed by GStreamer Merge Bot
parent 660b5e4a98
commit d268c193ad
6 changed files with 167 additions and 31 deletions

View file

@ -1766,7 +1766,7 @@
"long-name": "Compositor",
"pad-templates": {
"sink_%%u": {
"caps": "video/x-raw:\n format: { AYUV, VUYA, BGRA, ARGB, RGBA, ABGR, Y444, Y42B, YUY2, UYVY, YVYU, I420, YV12, NV12, NV21, Y41B, RGB, BGR, xRGB, xBGR, RGBx, BGRx }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n",
"caps": "video/x-raw:\n format: { AYUV64, ARGB64, GBRA_12LE, GBRA_12BE, Y412_LE, Y412_BE, A444_10LE, GBRA_10LE, A444_10BE, GBRA_10BE, A422_10LE, A422_10BE, A420_10LE, A420_10BE, RGB10A2_LE, BGR10A2_LE, Y410, GBRA, ABGR, VUYA, BGRA, AYUV, ARGB, RGBA, A420, Y444_16LE, Y444_16BE, v216, P016_LE, P016_BE, Y444_12LE, GBR_12LE, Y444_12BE, GBR_12BE, I422_12LE, I422_12BE, Y212_LE, Y212_BE, I420_12LE, I420_12BE, P012_LE, P012_BE, Y444_10LE, GBR_10LE, Y444_10BE, GBR_10BE, r210, I422_10LE, I422_10BE, NV16_10LE32, Y210, v210, UYVP, I420_10LE, I420_10BE, P010_10LE, NV12_10LE32, NV12_10LE40, P010_10BE, Y444, GBR, NV24, xBGR, BGRx, xRGB, RGBx, BGR, IYU2, v308, RGB, Y42B, NV61, NV16, VYUY, UYVY, YVYU, YUY2, I420, YV12, NV21, NV12, NV12_64Z32, NV12_4L4, NV12_32L32, Y41B, IYU1, YVU9, YUV9, RGB16, BGR16, RGB15, BGR15, RGB8P, GRAY16_LE, GRAY16_BE, GRAY10_LE32, GRAY8 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n",
"direction": "sink",
"presence": "request",
"type": "GstCompositorPad"

View file

@ -751,6 +751,10 @@ struct _GstVideoAggregatorPrivate
GstCaps *current_caps;
gboolean live;
/* The (ordered) list of #GstVideoFormatInfo supported by the aggregation
method (from the srcpad template caps). */
GPtrArray *supported_formats;
};
/* Can't use the G_DEFINE_TYPE macros because we need the
@ -792,6 +796,35 @@ gst_video_aggregator_get_instance_private (GstVideoAggregator * self)
return (G_STRUCT_MEMBER_P (self, video_aggregator_private_offset));
}
static gboolean
gst_video_aggregator_supports_format (GstVideoAggregator * vagg,
GstVideoFormat format)
{
gint i;
for (i = 0; i < vagg->priv->supported_formats->len; i++) {
GstVideoFormatInfo *format_info = vagg->priv->supported_formats->pdata[i];
if (GST_VIDEO_FORMAT_INFO_FORMAT (format_info) == format)
return TRUE;
}
return FALSE;
}
static GstCaps *
gst_video_aggregator_get_possible_caps_for_info (GstVideoInfo * info)
{
GstStructure *s;
GstCaps *possible_caps = gst_video_info_to_caps (info);
s = gst_caps_get_structure (possible_caps, 0);
gst_structure_remove_fields (s, "width", "height", "framerate",
"pixel-aspect-ratio", "interlace-mode", NULL);
return possible_caps;
}
static void
gst_video_aggregator_find_best_format (GstVideoAggregator * vagg,
GstCaps * downstream_caps, GstVideoInfo * best_info,
@ -801,13 +834,12 @@ gst_video_aggregator_find_best_format (GstVideoAggregator * vagg,
GstCaps *possible_caps;
GstVideoAggregatorPad *pad;
gboolean need_alpha = FALSE;
gint best_format_number = 0;
gint best_format_number = 0, i;
GHashTable *formats_table = g_hash_table_new (g_direct_hash, g_direct_equal);
GST_OBJECT_LOCK (vagg);
for (tmp = GST_ELEMENT (vagg)->sinkpads; tmp; tmp = tmp->next) {
GstStructure *s;
gint format_number;
gint format_number = 0;
pad = tmp->data;
@ -825,28 +857,29 @@ gst_video_aggregator_find_best_format (GstVideoAggregator * vagg,
if (GST_VIDEO_INFO_FORMAT (&pad->info) == GST_VIDEO_FORMAT_UNKNOWN)
continue;
possible_caps = gst_video_info_to_caps (&pad->info);
s = gst_caps_get_structure (possible_caps, 0);
gst_structure_remove_fields (s, "width", "height", "framerate",
"pixel-aspect-ratio", "interlace-mode", NULL);
/* Can downstream accept this format ? */
if (!gst_caps_can_intersect (downstream_caps, possible_caps)) {
gst_caps_unref (possible_caps);
continue;
if (!GST_IS_VIDEO_AGGREGATOR_CONVERT_PAD (pad)) {
possible_caps =
gst_video_aggregator_get_possible_caps_for_info (&pad->info);
if (!gst_caps_can_intersect (downstream_caps, possible_caps)) {
gst_caps_unref (possible_caps);
continue;
}
}
gst_caps_unref (possible_caps);
/* If the format is supported, consider it very high weight */
if (gst_video_aggregator_supports_format (vagg,
GST_VIDEO_INFO_FORMAT (&pad->info))) {
format_number =
GPOINTER_TO_INT (g_hash_table_lookup (formats_table,
GINT_TO_POINTER (GST_VIDEO_INFO_FORMAT (&pad->info))));
format_number =
GPOINTER_TO_INT (g_hash_table_lookup (formats_table,
GINT_TO_POINTER (GST_VIDEO_INFO_FORMAT (&pad->info))));
format_number += pad->info.width * pad->info.height;
format_number += pad->info.width * pad->info.height;
g_hash_table_replace (formats_table,
GINT_TO_POINTER (GST_VIDEO_INFO_FORMAT (&pad->info)),
GINT_TO_POINTER (format_number));
g_hash_table_replace (formats_table,
GINT_TO_POINTER (GST_VIDEO_INFO_FORMAT (&pad->info)),
GINT_TO_POINTER (format_number));
}
/* If that pad is the first with alpha, set it as the new best format */
if (!need_alpha && (pad->priv->needs_alpha
@ -872,6 +905,41 @@ gst_video_aggregator_find_best_format (GstVideoAggregator * vagg,
GST_OBJECT_UNLOCK (vagg);
g_hash_table_unref (formats_table);
if (gst_video_aggregator_supports_format (vagg,
GST_VIDEO_INFO_FORMAT (best_info))) {
possible_caps = gst_video_aggregator_get_possible_caps_for_info (best_info);
if (gst_caps_can_intersect (downstream_caps, possible_caps)) {
gst_caps_unref (possible_caps);
return;
}
gst_caps_unref (possible_caps);
}
for (i = 0; i < vagg->priv->supported_formats->len; i++) {
GstVideoFormatInfo *format_info = vagg->priv->supported_formats->pdata[i];
if ((! !GST_VIDEO_FORMAT_INFO_HAS_ALPHA (format_info)) == (! !need_alpha)) {
gst_video_info_set_format (best_info, format_info->format,
best_info->width, best_info->height);
possible_caps =
gst_video_aggregator_get_possible_caps_for_info (best_info);
if (gst_caps_can_intersect (downstream_caps, possible_caps)) {
GST_INFO_OBJECT (vagg, "Using supported caps: %" GST_PTR_FORMAT,
possible_caps);
gst_caps_unref (possible_caps);
return;
}
gst_caps_unref (possible_caps);
}
}
GST_WARNING_OBJECT (vagg, "Nothing compatible with %" GST_PTR_FORMAT,
downstream_caps);
gst_video_info_init (best_info);
}
static GstCaps *
@ -2576,6 +2644,7 @@ gst_video_aggregator_finalize (GObject * o)
GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (o);
g_mutex_clear (&vagg->priv->lock);
g_ptr_array_unref (vagg->priv->supported_formats);
G_OBJECT_CLASS (gst_video_aggregator_parent_class)->finalize (o);
}
@ -2669,12 +2738,48 @@ static void
gst_video_aggregator_init (GstVideoAggregator * vagg,
GstVideoAggregatorClass * klass)
{
vagg->priv = gst_video_aggregator_get_instance_private (vagg);
GstCaps *src_template;
GstPadTemplate *pad_template;
vagg->priv = gst_video_aggregator_get_instance_private (vagg);
vagg->priv->current_caps = NULL;
g_mutex_init (&vagg->priv->lock);
/* initialize variables */
gst_video_aggregator_reset (vagg);
/* Finding all supported formats */
vagg->priv->supported_formats = g_ptr_array_new ();
pad_template =
gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "src");
src_template = gst_pad_template_get_caps (pad_template);
for (gint i = 0; i < gst_caps_get_size (src_template); i++) {
const GValue *v =
gst_structure_get_value (gst_caps_get_structure (src_template, i),
"format");
if (G_VALUE_HOLDS_STRING (v)) {
GstVideoFormat f = gst_video_format_from_string (g_value_get_string (v));
GstVideoFormatInfo *format_info =
(GstVideoFormatInfo *) gst_video_format_get_info (f);
g_ptr_array_add (vagg->priv->supported_formats, format_info);
continue;
}
if (GST_VALUE_HOLDS_LIST (v)) {
gint j;
for (j = 0; j < gst_value_list_get_size (v); j++) {
const GValue *v1 = gst_value_list_get_value (v, j);
GstVideoFormat f =
gst_video_format_from_string (g_value_get_string (v1));
GstVideoFormatInfo *format_info =
(GstVideoFormatInfo *) gst_video_format_get_info (f);
g_ptr_array_add (vagg->priv->supported_formats, format_info);
}
}
}
gst_caps_unref (src_template);
}

View file

@ -116,7 +116,7 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%u",
GST_PAD_SINK,
GST_PAD_REQUEST,
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (FORMATS))
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL))
);
static void gst_compositor_child_proxy_init (gpointer g_iface,

View file

@ -47,19 +47,37 @@ static GMainLoop *main_loop;
static GstCaps *
_compositor_get_all_supported_caps (void)
{
return gst_caps_from_string (GST_VIDEO_CAPS_MAKE
(" { AYUV, VUYA, BGRA, ARGB, RGBA, ABGR, Y444, Y42B, YUY2, UYVY, "
" YVYU, I420, YV12, NV12, NV21, Y41B, RGB, BGR, xRGB, xBGR, "
" RGBx, BGRx } "));
return gst_caps_from_string (GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL));
}
static GstCaps *
_compositor_get_non_alpha_supported_caps (void)
{
return gst_caps_from_string (GST_VIDEO_CAPS_MAKE
(" { Y444, Y42B, YUY2, UYVY, "
" YVYU, I420, YV12, NV12, NV21, Y41B, RGB, BGR, xRGB, xBGR, "
" RGBx, BGRx } "));
gint j;
GValue all_formats = G_VALUE_INIT;
GValue nonalpha_formats = G_VALUE_INIT;
GstCaps *all_caps = _compositor_get_all_supported_caps ();
g_value_init (&all_formats, GST_TYPE_LIST);
g_value_init (&nonalpha_formats, GST_TYPE_LIST);
gst_value_deserialize (&all_formats, GST_VIDEO_FORMATS_ALL);
for (j = 0; j < gst_value_list_get_size (&all_formats); j++) {
const GValue *v1 = gst_value_list_get_value (&all_formats, j);
GstVideoFormat f = gst_video_format_from_string (g_value_get_string (v1));
GstVideoFormatInfo *format_info =
(GstVideoFormatInfo *) gst_video_format_get_info (f);
if (!GST_VIDEO_FORMAT_INFO_HAS_ALPHA (format_info))
gst_value_list_append_value (&nonalpha_formats, v1);
}
gst_structure_set_value (gst_caps_get_structure (all_caps, 0), "format",
&nonalpha_formats);
g_value_unset (&all_formats);
g_value_unset (&nonalpha_formats);
return all_caps;
}
/* make sure downstream gets a CAPS event before buffers are sent */

View file

@ -0,0 +1,12 @@
meta,
args = {
"videotestsrc num-buffers=20 ! capsfilter caps=\"video/x-raw,format=I420\" ! capssetter name=cs ! compositor name=c ! fakesink sync=true\
videotestsrc num-buffers=20 ! capsfilter caps=\"video/x-raw,format=I420\" ! c.",
},
handles-states=true
play;
crank-clock, repeat=10;
set-properties, cs::caps="video/x-raw,format=ARGB64"
crank-clock, repeat=11;
play

View file

@ -17,6 +17,7 @@ tests = [
'videorate/rate_0_5_with_decoder',
'videorate/rate_2_0',
'videorate/rate_2_0_with_decoder',
'compositor/renogotiate_failing_unsupported_src_format',
]
env = environment()