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;
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);