tests: Add a check for the new compositor pad-is-obscured optimization

We verify that all the buffers on an obscured sinkpad are skipped by overriding
the map() function in the GstVideoMeta of the buffers to set a variable when
called. We also test that the buffers do get mapped when they're not obscured.

Blame^WCredit for the GstVideoMeta map() idea goes to Tim.

https://bugzilla.gnome.org/show_bug.cgi?id=746147
This commit is contained in:
Nirbheek Chauhan 2015-03-13 06:10:52 +05:30 committed by Tim-Philipp Müller
parent 070777498f
commit dbbfba76ea

View file

@ -33,6 +33,7 @@
#include <gst/check/gstcheck.h>
#include <gst/check/gstconsistencychecker.h>
#include <gst/video/gstvideometa.h>
#include <gst/base/gstbasesrc.h>
#define VIDEO_CAPS_STRING \
@ -1096,6 +1097,213 @@ GST_START_TEST (test_segment_base_handling)
GST_END_TEST;
static gboolean buffer_mapped;
static gboolean (*default_map) (GstVideoMeta * meta, guint plane,
GstMapInfo * info, gpointer * data, gint * stride, GstMapFlags flags);
static gboolean
test_obscured_new_videometa_map (GstVideoMeta * meta, guint plane,
GstMapInfo * info, gpointer * data, gint * stride, GstMapFlags flags)
{
buffer_mapped = TRUE;
return default_map (meta, plane, info, data, stride, flags);
}
static GstPadProbeReturn
test_obscured_pad_probe_cb (GstPad * srcpad, GstPadProbeInfo * info,
gpointer user_data)
{
GstBuffer *obuf, *nbuf;
GstVideoMeta *meta;
GST_DEBUG ("pad probe called");
/* We need to deep-copy the buffer here because videotestsrc reuses buffers
* and hence the GstVideoMap associated with the buffers, and that causes a
* segfault inside videotestsrc when it tries to reuse the buffer */
obuf = GST_PAD_PROBE_INFO_BUFFER (info);
nbuf = gst_buffer_new ();
gst_buffer_copy_into (nbuf, obuf, GST_BUFFER_COPY_ALL | GST_BUFFER_COPY_DEEP,
0, -1);
meta = gst_buffer_get_video_meta (nbuf);
/* Override the default map() function to set also buffer_mapped */
default_map = meta->map;
meta->map = test_obscured_new_videometa_map;
/* Replace the buffer that's going downstream */
GST_PAD_PROBE_INFO_DATA (info) = nbuf;
gst_buffer_unref (obuf);
return GST_PAD_PROBE_PASS;
}
static void
_test_obscured (const gchar * caps_str, gint xpos0, gint ypos0, gint width0,
gint height0, gdouble alpha0, gint xpos1, gint ypos1, gint width1,
gint height1, gdouble alpha1)
{
GstElement *pipeline, *sink, *mix, *src0, *cfilter0, *src1, *cfilter1;
GstPad *srcpad, *sinkpad;
GstSample *last_sample = NULL;
GstSample *sample;
GstCaps *caps;
GST_INFO ("preparing test");
pipeline = gst_pipeline_new ("pipeline");
src0 = gst_element_factory_make ("videotestsrc", "src0");
g_object_set (src0, "num-buffers", 5, NULL);
cfilter0 = gst_element_factory_make ("capsfilter", "capsfilter0");
caps = gst_caps_from_string (caps_str);
g_object_set (cfilter0, "caps", caps, NULL);
gst_caps_unref (caps);
src1 = gst_element_factory_make ("videotestsrc", "src1");
g_object_set (src1, "num-buffers", 5, NULL);
cfilter1 = gst_element_factory_make ("capsfilter", "capsfilter1");
caps = gst_caps_from_string (caps_str);
g_object_set (cfilter1, "caps", caps, NULL);
gst_caps_unref (caps);
mix = gst_element_factory_make ("compositor", "compositor");
sink = gst_element_factory_make ("appsink", "sink");
gst_bin_add_many (GST_BIN (pipeline), src0, cfilter0, src1, cfilter1, mix,
sink, NULL);
fail_unless (gst_element_link (src0, cfilter0));
fail_unless (gst_element_link (src1, cfilter1));
fail_unless (gst_element_link (mix, sink));
srcpad = gst_element_get_static_pad (cfilter0, "src");
sinkpad = gst_element_get_request_pad (mix, "sink_0");
g_object_set (sinkpad, "xpos", xpos0, "ypos", ypos0, "width", width0,
"height", height0, "alpha", alpha0, NULL);
fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK);
gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_BUFFER,
test_obscured_pad_probe_cb, NULL, NULL);
gst_object_unref (sinkpad);
gst_object_unref (srcpad);
srcpad = gst_element_get_static_pad (cfilter1, "src");
sinkpad = gst_element_get_request_pad (mix, "sink_1");
g_object_set (sinkpad, "xpos", xpos1, "ypos", ypos1, "width", width1,
"height", height1, "alpha", alpha1, NULL);
fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK);
gst_object_unref (sinkpad);
gst_object_unref (srcpad);
GST_INFO ("sample prepared");
gst_element_set_state (pipeline, GST_STATE_PLAYING);
do {
GST_DEBUG ("sample pulling");
g_signal_emit_by_name (sink, "pull-sample", &sample);
if (sample == NULL)
break;
if (last_sample)
gst_sample_unref (last_sample);
last_sample = sample;
GST_DEBUG ("sample pulled");
} while (TRUE);
gst_sample_unref (last_sample);
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
}
GST_START_TEST (test_obscured_skipped)
{
gint xpos0, xpos1;
gint ypos0, ypos1;
gint width0, width1;
gint height0, height1;
gdouble alpha0, alpha1;
const gchar *caps_str;
caps_str = "video/x-raw";
buffer_mapped = FALSE;
/* Set else to compositor defaults */
alpha0 = alpha1 = 1.0;
xpos0 = xpos1 = ypos0 = ypos1 = 0;
width0 = width1 = height0 = height1 = 0;
GST_INFO ("testing defaults");
/* With everything at defaults, sink_1 will obscure sink_0, so buffers from
* sink_0 will never get mapped by compositor. To verify, run with
* GST_DEBUG=compositor:6 and look for "Obscured by" messages */
_test_obscured (caps_str, xpos0, ypos0, width0, height0, alpha0, xpos1, ypos1,
width1, height1, alpha1);
fail_unless (buffer_mapped == FALSE);
buffer_mapped = FALSE;
caps_str = "video/x-raw,format=ARGB";
GST_INFO ("testing video with alpha channel");
_test_obscured (caps_str, xpos0, ypos0, width0, height0, alpha0, xpos1, ypos1,
width1, height1, alpha1);
fail_unless (buffer_mapped == TRUE);
caps_str = "video/x-raw";
buffer_mapped = FALSE;
alpha1 = 0.0;
GST_INFO ("testing alpha1 = %.2g", alpha1);
_test_obscured (caps_str, xpos0, ypos0, width0, height0, alpha0, xpos1, ypos1,
width1, height1, alpha1);
fail_unless (buffer_mapped == TRUE);
alpha1 = 1.0;
buffer_mapped = FALSE;
/* Test 0.1, ..., 0.9 */
for (alpha1 = 1; alpha1 < 10; alpha1 += 1) {
GST_INFO ("testing alpha1 = %.2g", alpha1 / 10);
_test_obscured (caps_str, xpos0, ypos0, width0, height0, alpha0, xpos1,
ypos1, width1, height1, alpha1 / 10);
fail_unless (buffer_mapped == TRUE);
}
alpha1 = 1.0;
buffer_mapped = FALSE;
width1 = height1 = 10;
GST_INFO ("testing smaller sink_1");
_test_obscured (caps_str, xpos0, ypos0, width0, height0, alpha0, xpos1, ypos1,
width1, height1, alpha1);
fail_unless (buffer_mapped == TRUE);
width1 = height1 = 0;
buffer_mapped = FALSE;
width0 = height0 = width1 = height1 = 10;
GST_INFO ("testing smaller sink_1 and sink0 (same sizes)");
_test_obscured (caps_str, xpos0, ypos0, width0, height0, alpha0, xpos1, ypos1,
width1, height1, alpha1);
fail_unless (buffer_mapped == FALSE);
width0 = height0 = width1 = height1 = 0;
buffer_mapped = FALSE;
width0 = height0 = 20;
width1 = height1 = 10;
GST_INFO ("testing smaller sink_1 and sink0 (sink_0 > sink_1)");
_test_obscured (caps_str, xpos0, ypos0, width0, height0, alpha0, xpos1, ypos1,
width1, height1, alpha1);
fail_unless (buffer_mapped == TRUE);
width0 = height0 = width1 = height1 = 0;
buffer_mapped = FALSE;
width0 = height0 = 10;
width1 = height1 = 20;
GST_INFO ("testing smaller sink_1 and sink0 (sink_0 < sink_1)");
_test_obscured (caps_str, xpos0, ypos0, width0, height0, alpha0, xpos1, ypos1,
width1, height1, alpha1);
fail_unless (buffer_mapped == FALSE);
width0 = height0 = width1 = height1 = 0;
buffer_mapped = FALSE;
xpos0 = ypos0 = 10000;
GST_INFO ("testing sink_0 outside the frame");
_test_obscured (caps_str, xpos0, ypos0, width0, height0, alpha0, xpos1, ypos1,
width1, height1, alpha1);
fail_unless (buffer_mapped == FALSE);
xpos0 = ypos0 = 0;
buffer_mapped = FALSE;
}
GST_END_TEST;
static Suite *
compositor_suite (void)
{
@ -1115,6 +1323,7 @@ compositor_suite (void)
tcase_add_test (tc_chain, test_loop);
tcase_add_test (tc_chain, test_flush_start_flush_stop);
tcase_add_test (tc_chain, test_segment_base_handling);
tcase_add_test (tc_chain, test_obscured_skipped);
/* Use a longer timeout */
#ifdef HAVE_VALGRIND