mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-25 17:50:36 +00:00
videoaggregator: fix caps queries to allow proper renegotiation
When caps are already negotiated it should be possible to select formats other than the one that was negotiated. If downstream allows alpha video caps and it has already negotiated to a non-alpha format, caps queries should still return the alpha caps as a possible format as caps renegotiation can happen. Includes tests (for compositor) to check that caps queries done after a caps has been negotiated returns complete results https://bugzilla.gnome.org/show_bug.cgi?id=757610
This commit is contained in:
parent
a8862ac440
commit
86d21e9455
2 changed files with 212 additions and 9 deletions
|
@ -892,15 +892,7 @@ gst_videoaggregator_pad_sink_getcaps (GstPad * pad, GstVideoAggregator * vagg,
|
|||
|
||||
GST_DEBUG_OBJECT (pad, "Get caps with filter: %" GST_PTR_FORMAT, filter);
|
||||
|
||||
srccaps = gst_pad_get_current_caps (srcpad);
|
||||
if (srccaps == NULL) {
|
||||
srccaps = gst_pad_peer_query_caps (srcpad, template_caps);
|
||||
GST_DEBUG_OBJECT (pad, "No output caps, using possible formats: %"
|
||||
GST_PTR_FORMAT, srccaps);
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (pad, "Using output caps: %" GST_PTR_FORMAT, srccaps);
|
||||
}
|
||||
|
||||
srccaps = gst_caps_make_writable (srccaps);
|
||||
has_alpha = gst_videoaggregator_caps_has_alpha (srccaps);
|
||||
|
||||
|
|
|
@ -245,6 +245,216 @@ GST_START_TEST (test_event)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
static GstBuffer *
|
||||
create_video_buffer (GstCaps * caps, gint ts_in_seconds)
|
||||
{
|
||||
GstVideoInfo info;
|
||||
guint size;
|
||||
GstBuffer *buf;
|
||||
GstMapInfo mapinfo;
|
||||
|
||||
fail_unless (gst_video_info_from_caps (&info, caps));
|
||||
|
||||
size = GST_VIDEO_INFO_WIDTH (&info) * GST_VIDEO_INFO_HEIGHT (&info);
|
||||
|
||||
switch (GST_VIDEO_INFO_FORMAT (&info)) {
|
||||
case GST_VIDEO_FORMAT_RGB:
|
||||
size *= 3;
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_RGBA:
|
||||
case GST_VIDEO_FORMAT_ARGB:
|
||||
size *= 4;
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_I420:
|
||||
size *= 2;
|
||||
break;
|
||||
default:
|
||||
fail ("Unsupported test format");
|
||||
}
|
||||
|
||||
buf = gst_buffer_new_and_alloc (size);
|
||||
/* write something to avoid uninitialized error issues (valgrind) */
|
||||
gst_buffer_map (buf, &mapinfo, GST_MAP_WRITE);
|
||||
memset (mapinfo.data, 0, mapinfo.size);
|
||||
gst_buffer_unmap (buf, &mapinfo);
|
||||
|
||||
GST_BUFFER_PTS (buf) = ts_in_seconds * GST_SECOND;
|
||||
GST_BUFFER_DURATION (buf) = GST_SECOND;
|
||||
return buf;
|
||||
}
|
||||
|
||||
#define MODE_ALL 1
|
||||
#define MODE_NON_ALPHA 2
|
||||
|
||||
/* mostly copied from videoaggregator */
|
||||
static inline GstCaps *
|
||||
_get_non_alpha_caps_from_caps (GstCaps * caps)
|
||||
{
|
||||
GstCaps *result;
|
||||
guint i, size;
|
||||
|
||||
size = gst_caps_get_size (caps);
|
||||
result = gst_caps_new_empty ();
|
||||
for (i = 0; i < size; i++) {
|
||||
GstStructure *s = gst_caps_get_structure (caps, i);
|
||||
const GValue *formats = gst_structure_get_value (s, "format");
|
||||
GValue new_formats = { 0, };
|
||||
gboolean has_format = FALSE;
|
||||
|
||||
/* FIXME what to do if formats are missing? */
|
||||
if (formats) {
|
||||
const GstVideoFormatInfo *info;
|
||||
|
||||
if (GST_VALUE_HOLDS_LIST (formats)) {
|
||||
guint list_size = gst_value_list_get_size (formats);
|
||||
guint index;
|
||||
|
||||
g_value_init (&new_formats, GST_TYPE_LIST);
|
||||
|
||||
for (index = 0; index < list_size; index++) {
|
||||
const GValue *list_item = gst_value_list_get_value (formats, index);
|
||||
|
||||
info =
|
||||
gst_video_format_get_info (gst_video_format_from_string
|
||||
(g_value_get_string (list_item)));
|
||||
if (!GST_VIDEO_FORMAT_INFO_HAS_ALPHA (info)) {
|
||||
has_format = TRUE;
|
||||
gst_value_list_append_value (&new_formats, list_item);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (G_VALUE_HOLDS_STRING (formats)) {
|
||||
info =
|
||||
gst_video_format_get_info (gst_video_format_from_string
|
||||
(g_value_get_string (formats)));
|
||||
if (!GST_VIDEO_FORMAT_INFO_HAS_ALPHA (info)) {
|
||||
has_format = TRUE;
|
||||
gst_value_init_and_copy (&new_formats, formats);
|
||||
}
|
||||
|
||||
} else {
|
||||
g_assert_not_reached ();
|
||||
GST_WARNING ("Unexpected type for video 'format' field: %s",
|
||||
G_VALUE_TYPE_NAME (formats));
|
||||
}
|
||||
|
||||
if (has_format) {
|
||||
s = gst_structure_copy (s);
|
||||
gst_structure_take_value (s, "format", &new_formats);
|
||||
gst_caps_append_structure (result, s);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
run_late_caps_query_test (GstCaps * input_caps, GstCaps * output_allowed_caps,
|
||||
gint expected_caps_mode)
|
||||
{
|
||||
GstElement *compositor, *capsfilter, *sink;
|
||||
GstElement *pipeline;
|
||||
gboolean res;
|
||||
GstStateChangeReturn state_res;
|
||||
GstPad *srcpad1, *srcpad2;
|
||||
GstPad *sinkpad1, *sinkpad2;
|
||||
GstSegment segment;
|
||||
GstCaps *caps, *all_caps, *non_alpha_caps;
|
||||
|
||||
all_caps =
|
||||
gst_caps_from_string (GST_VIDEO_CAPS_MAKE
|
||||
(" { AYUV, BGRA, ARGB, RGBA, ABGR, Y444, Y42B, YUY2, UYVY, "
|
||||
" YVYU, I420, YV12, NV12, NV21, Y41B, RGB, BGR, xRGB, xBGR, "
|
||||
" RGBx, BGRx } "));
|
||||
non_alpha_caps =
|
||||
gst_caps_from_string (GST_VIDEO_CAPS_MAKE
|
||||
(" { Y444, Y42B, YUY2, UYVY, "
|
||||
" YVYU, I420, YV12, NV12, NV21, Y41B, RGB, BGR, xRGB, xBGR, "
|
||||
" RGBx, BGRx } "));
|
||||
|
||||
compositor = gst_element_factory_make ("compositor", "compositor");
|
||||
capsfilter = gst_element_factory_make ("capsfilter", "out-cf");
|
||||
sink = gst_element_factory_make ("fakesink", "sink");
|
||||
pipeline = gst_pipeline_new ("test-pipeline");
|
||||
|
||||
gst_bin_add_many (GST_BIN (pipeline), compositor, capsfilter, sink, NULL);
|
||||
res = gst_element_link (compositor, capsfilter);
|
||||
fail_unless (res == TRUE, NULL);
|
||||
res = gst_element_link (capsfilter, sink);
|
||||
fail_unless (res == TRUE, NULL);
|
||||
|
||||
sinkpad1 = gst_element_get_request_pad (compositor, "sink_%u");
|
||||
srcpad1 = gst_pad_new ("src1", GST_PAD_SRC);
|
||||
fail_unless (gst_pad_link (srcpad1, sinkpad1) == GST_PAD_LINK_OK);
|
||||
gst_pad_set_active (srcpad1, TRUE);
|
||||
|
||||
state_res = gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
fail_if (state_res == GST_STATE_CHANGE_FAILURE);
|
||||
|
||||
if (output_allowed_caps)
|
||||
g_object_set (capsfilter, "caps", output_allowed_caps, NULL);
|
||||
|
||||
gst_segment_init (&segment, GST_FORMAT_TIME);
|
||||
fail_unless (gst_pad_push_event (srcpad1,
|
||||
gst_event_new_stream_start ("test-1")));
|
||||
fail_unless (gst_pad_push_event (srcpad1, gst_event_new_caps (input_caps)));
|
||||
fail_unless (gst_pad_push_event (srcpad1, gst_event_new_segment (&segment)));
|
||||
fail_unless (gst_pad_push (srcpad1,
|
||||
create_video_buffer (input_caps, 0)) == GST_FLOW_OK);
|
||||
fail_unless (gst_pad_push (srcpad1,
|
||||
create_video_buffer (input_caps, 1)) == GST_FLOW_OK);
|
||||
|
||||
/* now comes the second pad */
|
||||
sinkpad2 = gst_element_get_request_pad (compositor, "sink_%u");
|
||||
srcpad2 = gst_pad_new ("src2", GST_PAD_SRC);
|
||||
fail_unless (gst_pad_link (srcpad2, sinkpad2) == GST_PAD_LINK_OK);
|
||||
gst_pad_set_active (srcpad2, TRUE);
|
||||
fail_unless (gst_pad_push_event (srcpad2,
|
||||
gst_event_new_stream_start ("test-2")));
|
||||
|
||||
caps = gst_pad_peer_query_caps (srcpad2, NULL);
|
||||
fail_unless (gst_caps_is_equal (caps,
|
||||
expected_caps_mode == MODE_ALL ? all_caps : non_alpha_caps));
|
||||
gst_caps_unref (caps);
|
||||
|
||||
gst_pad_set_active (srcpad1, FALSE);
|
||||
gst_pad_set_active (srcpad2, FALSE);
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
gst_element_release_request_pad (compositor, sinkpad1);
|
||||
gst_element_release_request_pad (compositor, sinkpad2);
|
||||
gst_object_unref (sinkpad1);
|
||||
gst_object_unref (sinkpad2);
|
||||
gst_object_unref (pipeline);
|
||||
gst_object_unref (srcpad1);
|
||||
gst_object_unref (srcpad2);
|
||||
gst_caps_unref (all_caps);
|
||||
gst_caps_unref (non_alpha_caps);
|
||||
}
|
||||
|
||||
GST_START_TEST (test_late_caps_query)
|
||||
{
|
||||
GstCaps *rgb_caps;
|
||||
GstCaps *non_alpha_caps;
|
||||
|
||||
rgb_caps = gst_caps_from_string ("video/x-raw, format=(string)RGB, "
|
||||
"width=(int)100, height=(int)100, framerate=(fraction)1/1");
|
||||
|
||||
non_alpha_caps = gst_caps_from_string ("video/x-raw, format=(string)RGB");
|
||||
|
||||
/* check that a 2nd pad that is added late to compositor will be able to
|
||||
* negotiate to formats that depend only on downstream caps and not on what
|
||||
* the other pads have already negotiated */
|
||||
run_late_caps_query_test (rgb_caps, NULL, MODE_ALL);
|
||||
run_late_caps_query_test (rgb_caps, non_alpha_caps, MODE_NON_ALPHA);
|
||||
|
||||
gst_caps_unref (non_alpha_caps);
|
||||
gst_caps_unref (rgb_caps);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static guint play_count = 0;
|
||||
static GstEvent *play_seek_event = NULL;
|
||||
|
||||
|
@ -1660,6 +1870,7 @@ compositor_suite (void)
|
|||
suite_add_tcase (s, tc_chain);
|
||||
tcase_add_test (tc_chain, test_caps);
|
||||
tcase_add_test (tc_chain, test_event);
|
||||
tcase_add_test (tc_chain, test_late_caps_query);
|
||||
tcase_add_test (tc_chain, test_play_twice);
|
||||
tcase_add_test (tc_chain, test_play_twice_then_add_and_play_again);
|
||||
tcase_add_test (tc_chain, test_add_pad);
|
||||
|
|
Loading…
Reference in a new issue