From f231598370ebc4364d16eab1c7e3dbdd7001668a Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 18 Feb 2016 10:57:51 -0300 Subject: 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 --- tests/check/elements/compositor.c | 211 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) (limited to 'tests') diff --git a/tests/check/elements/compositor.c b/tests/check/elements/compositor.c index 77c65cfed..cf50e1532 100644 --- a/tests/check/elements/compositor.c +++ b/tests/check/elements/compositor.c @@ -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); -- cgit v1.2.1