diff --git a/gst-libs/gst/video/gstvideoaggregator.c b/gst-libs/gst/video/gstvideoaggregator.c index 2b0c87630e..1bf6ea0b20 100644 --- a/gst-libs/gst/video/gstvideoaggregator.c +++ b/gst-libs/gst/video/gstvideoaggregator.c @@ -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_pad_peer_query_caps (srcpad, template_caps); srccaps = gst_caps_make_writable (srccaps); has_alpha = gst_videoaggregator_caps_has_alpha (srccaps); diff --git a/tests/check/elements/compositor.c b/tests/check/elements/compositor.c index 77c65cfed1..cf50e15321 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);