Merge branch 'master' into 0.11
[platform/upstream/gst-plugins-base.git] / tests / check / elements / videoscale.c
1 /* GStreamer
2  *
3  * unit test for videoscale
4  *
5  * Copyright (C) <2009,2010> Sebastian Dröge <sebastian.droege@collabora.co.uk>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <gst/video/video.h>
24 #include <gst/base/gstbasesink.h>
25
26 #include <gst/check/gstcheck.h>
27 #include <string.h>
28
29 /* kids, don't do this at home, skipping checks is *BAD* */
30 #define LINK_CHECK_FLAGS GST_PAD_LINK_CHECK_NOTHING
31
32 static GstCaps **
33 videoscale_get_allowed_caps_for_method (int method)
34 {
35   GstElement *scale;
36   GstCaps *caps, **ret;
37   GstPad *pad;
38   GstStructure *s;
39   gint i, n;
40
41   scale = gst_element_factory_make ("videoscale", "vscale");
42   g_object_set (scale, "method", method, NULL);
43   pad = gst_element_get_static_pad (scale, "sink");
44   caps = gst_pad_query_caps (pad, NULL);
45   gst_object_unref (pad);
46   gst_object_unref (scale);
47
48   n = gst_caps_get_size (caps);
49   ret = g_new0 (GstCaps *, n + 1);
50
51   for (i = 0; i < n; i++) {
52     s = gst_caps_get_structure (caps, i);
53     ret[i] = gst_caps_new_empty ();
54     gst_caps_append_structure (ret[i], gst_structure_copy (s));
55     GST_LOG ("method %d supports: %" GST_PTR_FORMAT, method, s);
56   }
57
58   gst_caps_unref (caps);
59
60   return ret;
61 }
62
63 static void
64 on_sink_handoff (GstElement * element, GstBuffer * buffer, GstPad * pad,
65     gpointer user_data)
66 {
67   guint *n_buffers = user_data;
68
69   *n_buffers = *n_buffers + 1;
70 }
71
72 static gboolean
73 caps_is_supported (const GstCaps * caps)
74 {
75   GstVideoFormat fmt;
76   GstStructure *s;
77   const gchar *format;
78
79   GST_DEBUG ("have caps %" GST_PTR_FORMAT, caps);
80
81   s = gst_caps_get_structure (caps, 0);
82   format = gst_structure_get_string (s, "format");
83   fail_if (format == NULL);
84
85   fmt = gst_video_format_from_string (format);
86   fail_if (fmt == GST_VIDEO_FORMAT_UNKNOWN);
87
88   return (fmt == GST_VIDEO_FORMAT_ARGB64 || fmt == GST_VIDEO_FORMAT_AYUV64
89       || fmt == GST_VIDEO_FORMAT_GRAY8 || fmt == GST_VIDEO_FORMAT_GRAY16_BE
90       || GST_VIDEO_FORMAT_GRAY16_LE);
91 }
92
93 static void
94 run_test (const GstCaps * caps, gint src_width, gint src_height,
95     gint dest_width, gint dest_height, gint method,
96     GCallback src_handoff, gpointer src_handoff_user_data,
97     GCallback sink_handoff, gpointer sink_handoff_user_data)
98 {
99   GstElement *pipeline;
100   GstElement *src, *videoconvert, *capsfilter1, *identity, *scale,
101       *capsfilter2, *sink;
102   GstMessage *msg;
103   GstBus *bus;
104   GstCaps *copy;
105   guint n_buffers = 0;
106
107   /* skip formats that videoconvert can't handle */
108   if (caps_is_supported (caps))
109     return;
110
111   pipeline = gst_element_factory_make ("pipeline", "pipeline");
112   fail_unless (pipeline != NULL);
113
114   src = gst_element_factory_make ("videotestsrc", "src");
115   fail_unless (src != NULL);
116   g_object_set (G_OBJECT (src), "num-buffers", 1, NULL);
117
118   videoconvert = gst_element_factory_make ("videoconvert", "csp");
119   fail_unless (videoconvert != NULL);
120
121   capsfilter1 = gst_element_factory_make ("capsfilter", "filter1");
122   fail_unless (capsfilter1 != NULL);
123   copy = gst_caps_copy (caps);
124   gst_caps_set_simple (copy, "width", G_TYPE_INT, src_width, "height",
125       G_TYPE_INT, src_height, "framerate", GST_TYPE_FRACTION, 30, 1, NULL);
126   g_object_set (G_OBJECT (capsfilter1), "caps", copy, NULL);
127   gst_caps_unref (copy);
128
129   identity = gst_element_factory_make ("identity", "identity");
130   fail_unless (identity != NULL);
131   if (src_handoff) {
132     g_object_set (G_OBJECT (identity), "signal-handoffs", TRUE, NULL);
133     g_signal_connect (identity, "handoff", G_CALLBACK (src_handoff),
134         src_handoff_user_data);
135   }
136
137   scale = gst_element_factory_make ("videoscale", "scale");
138   fail_unless (scale != NULL);
139   g_object_set (G_OBJECT (scale), "method", method, NULL);
140
141   capsfilter2 = gst_element_factory_make ("capsfilter", "filter2");
142   fail_unless (capsfilter2 != NULL);
143   copy = gst_caps_copy (caps);
144   gst_caps_set_simple (copy, "width", G_TYPE_INT, dest_width, "height",
145       G_TYPE_INT, dest_height, NULL);
146   g_object_set (G_OBJECT (capsfilter2), "caps", copy, NULL);
147   gst_caps_unref (copy);
148
149   sink = gst_element_factory_make ("fakesink", "sink");
150   fail_unless (sink != NULL);
151   g_object_set (G_OBJECT (sink), "signal-handoffs", TRUE, "async", FALSE, NULL);
152   g_signal_connect (sink, "handoff", G_CALLBACK (on_sink_handoff), &n_buffers);
153   if (sink_handoff) {
154     g_signal_connect (sink, "handoff", G_CALLBACK (sink_handoff),
155         sink_handoff_user_data);
156   }
157
158   gst_bin_add_many (GST_BIN (pipeline), src, videoconvert, capsfilter1,
159       identity, scale, capsfilter2, sink, NULL);
160
161   fail_unless (gst_element_link_pads_full (src, "src", videoconvert, "sink",
162           LINK_CHECK_FLAGS));
163   fail_unless (gst_element_link_pads_full (videoconvert, "src", capsfilter1,
164           "sink", LINK_CHECK_FLAGS));
165   fail_unless (gst_element_link_pads_full (capsfilter1, "src", identity, "sink",
166           LINK_CHECK_FLAGS));
167   fail_unless (gst_element_link_pads_full (identity, "src", scale, "sink",
168           LINK_CHECK_FLAGS));
169   fail_unless (gst_element_link_pads_full (scale, "src", capsfilter2, "sink",
170           LINK_CHECK_FLAGS));
171   fail_unless (gst_element_link_pads_full (capsfilter2, "src", sink, "sink",
172           LINK_CHECK_FLAGS));
173
174   bus = gst_element_get_bus (pipeline);
175   fail_unless (bus != NULL);
176
177   fail_unless (gst_element_set_state (pipeline,
178           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
179
180   msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
181       GST_MESSAGE_EOS | GST_MESSAGE_ERROR | GST_MESSAGE_WARNING);
182
183   fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_EOS);
184
185   fail_unless (gst_element_set_state (pipeline,
186           GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
187
188   fail_unless (n_buffers == 1);
189
190   gst_object_unref (pipeline);
191   gst_message_unref (msg);
192   gst_object_unref (bus);
193 }
194
195 static void
196 on_sink_handoff_passthrough (GstElement * element, GstBuffer * buffer,
197     GstPad * pad, gpointer user_data)
198 {
199   GList **list = user_data;
200
201   *list = g_list_prepend (*list, gst_buffer_ref (buffer));
202 }
203
204 static void
205 on_src_handoff_passthrough (GstElement * element, GstBuffer * buffer,
206     gpointer user_data)
207 {
208   GList **list = user_data;
209
210   *list = g_list_prepend (*list, gst_buffer_ref (buffer));
211 }
212
213 static void
214 test_passthrough (int method)
215 {
216   GList *l1, *l2, *src_buffers = NULL, *sink_buffers = NULL;
217   GstCaps **allowed_caps = NULL, **p;
218   static const gint src_width = 640, src_height = 480;
219   static const gint dest_width = 640, dest_height = 480;
220
221   p = allowed_caps = videoscale_get_allowed_caps_for_method (method);
222
223   while (*p) {
224     GstCaps *caps = *p;
225
226     for (method = 0; method < 3; method++) {
227       /* skip formats that videoconvert can't handle */
228       if (caps_is_supported (caps))
229         continue;
230
231       GST_DEBUG ("Running test for caps '%" GST_PTR_FORMAT "'"
232           " from %dx%u to %dx%d with method %d", caps, src_width, src_height,
233           dest_width, dest_height, method);
234       run_test (caps, src_width, src_height,
235           dest_width, dest_height, method,
236           G_CALLBACK (on_src_handoff_passthrough), &src_buffers,
237           G_CALLBACK (on_sink_handoff_passthrough), &sink_buffers);
238
239       fail_unless (src_buffers && sink_buffers);
240       fail_unless_equals_int (g_list_length (src_buffers),
241           g_list_length (sink_buffers));
242
243       for (l1 = src_buffers, l2 = sink_buffers; l1 && l2;
244           l1 = l1->next, l2 = l2->next) {
245         GstBuffer *a = l1->data;
246         GstBuffer *b = l2->data;
247         GstMapInfo mapa, mapb;
248
249         gst_buffer_map (a, &mapa, GST_MAP_READ);
250         gst_buffer_map (b, &mapb, GST_MAP_READ);
251         fail_unless_equals_int (mapa.size, mapb.size);
252         fail_unless (mapa.data == mapb.data);
253         gst_buffer_unmap (b, &mapb);
254         gst_buffer_unmap (a, &mapa);
255
256         gst_buffer_unref (a);
257         gst_buffer_unref (b);
258       }
259       g_list_free (src_buffers);
260       src_buffers = NULL;
261       g_list_free (sink_buffers);
262       sink_buffers = NULL;
263     }
264     gst_caps_unref (caps);
265     p++;
266   }
267   g_free (allowed_caps);
268 }
269
270 GST_START_TEST (test_passthrough_method_0)
271 {
272   test_passthrough (0);
273 }
274
275 GST_END_TEST;
276
277 GST_START_TEST (test_passthrough_method_1)
278 {
279   test_passthrough (1);
280 }
281
282 GST_END_TEST;
283
284 GST_START_TEST (test_passthrough_method_2)
285 {
286   test_passthrough (2);
287 }
288
289 GST_END_TEST;
290
291 GST_START_TEST (test_passthrough_method_3)
292 {
293   test_passthrough (3);
294 }
295
296 GST_END_TEST;
297
298 #define CREATE_TEST(name,method,src_width,src_height,dest_width,dest_height) \
299 GST_START_TEST (name) \
300 { \
301   GstCaps **allowed_caps = NULL, **p; \
302   \
303   p = allowed_caps = videoscale_get_allowed_caps_for_method (method); \
304   \
305   while (*p) { \
306     GstCaps *caps = *p; \
307     \
308     GST_DEBUG ("Running test for caps '%" GST_PTR_FORMAT "'" \
309         " from %dx%u to %dx%d with method %d", caps, src_width, src_height, \
310         dest_width, dest_height, method); \
311     run_test (caps, src_width, src_height, \
312         dest_width, dest_height, method, \
313         NULL, NULL, NULL, NULL); \
314     gst_caps_unref (caps); \
315     p++; \
316   } \
317   g_free (allowed_caps); \
318 } \
319 \
320 GST_END_TEST;
321
322 CREATE_TEST (test_downscale_640x480_320x240_method_0, 0, 640, 480, 320, 240);
323 CREATE_TEST (test_downscale_640x480_320x240_method_1, 1, 640, 480, 320, 240);
324 CREATE_TEST (test_downscale_640x480_320x240_method_2, 2, 640, 480, 320, 240);
325 CREATE_TEST (test_downscale_640x480_320x240_method_3, 3, 640, 480, 320, 240);
326 CREATE_TEST (test_upscale_320x240_640x480_method_0, 0, 320, 240, 640, 480);
327 CREATE_TEST (test_upscale_320x240_640x480_method_1, 1, 320, 240, 640, 480);
328 CREATE_TEST (test_upscale_320x240_640x480_method_2, 2, 320, 240, 640, 480);
329 CREATE_TEST (test_upscale_320x240_640x480_method_3, 3, 320, 240, 640, 480);
330 CREATE_TEST (test_downscale_640x480_1x1_method_0, 0, 640, 480, 1, 1);
331 CREATE_TEST (test_downscale_640x480_1x1_method_1, 1, 640, 480, 1, 1);
332 CREATE_TEST (test_downscale_640x480_1x1_method_2, 2, 640, 480, 1, 1);
333 CREATE_TEST (test_downscale_640x480_1x1_method_3, 3, 640, 480, 1, 1);
334 CREATE_TEST (test_upscale_1x1_640x480_method_0, 0, 1, 1, 640, 480);
335 CREATE_TEST (test_upscale_1x1_640x480_method_1, 1, 1, 1, 640, 480);
336 CREATE_TEST (test_upscale_1x1_640x480_method_2, 2, 1, 1, 640, 480);
337 CREATE_TEST (test_upscale_1x1_640x480_method_3, 3, 1, 1, 640, 480);
338 CREATE_TEST (test_downscale_641x481_111x30_method_0, 0, 641, 481, 111, 30);
339 CREATE_TEST (test_downscale_641x481_111x30_method_1, 1, 641, 481, 111, 30);
340 CREATE_TEST (test_downscale_641x481_111x30_method_2, 2, 641, 481, 111, 30);
341 CREATE_TEST (test_downscale_641x481_111x30_method_3, 3, 641, 481, 111, 30);
342 CREATE_TEST (test_upscale_111x30_641x481_method_0, 0, 111, 30, 641, 481);
343 CREATE_TEST (test_upscale_111x30_641x481_method_1, 1, 111, 30, 641, 481);
344 CREATE_TEST (test_upscale_111x30_641x481_method_2, 2, 111, 30, 641, 481);
345 CREATE_TEST (test_upscale_111x30_641x481_method_3, 2, 111, 30, 641, 481);
346 CREATE_TEST (test_downscale_641x481_30x111_method_0, 0, 641, 481, 30, 111);
347 CREATE_TEST (test_downscale_641x481_30x111_method_1, 1, 641, 481, 30, 111);
348 CREATE_TEST (test_downscale_641x481_30x111_method_2, 2, 641, 481, 30, 111);
349 CREATE_TEST (test_downscale_641x481_30x111_method_3, 3, 641, 481, 30, 111);
350 CREATE_TEST (test_upscale_30x111_641x481_method_0, 0, 30, 111, 641, 481);
351 CREATE_TEST (test_upscale_30x111_641x481_method_1, 1, 30, 111, 641, 481);
352 CREATE_TEST (test_upscale_30x111_641x481_method_2, 2, 30, 111, 641, 481);
353 CREATE_TEST (test_upscale_30x111_641x481_method_3, 3, 30, 111, 641, 481);
354 CREATE_TEST (test_downscale_640x480_320x1_method_0, 0, 640, 480, 320, 1);
355 CREATE_TEST (test_downscale_640x480_320x1_method_1, 1, 640, 480, 320, 1);
356 CREATE_TEST (test_downscale_640x480_320x1_method_2, 2, 640, 480, 320, 1);
357 CREATE_TEST (test_downscale_640x480_320x1_method_3, 3, 640, 480, 320, 1);
358 CREATE_TEST (test_upscale_320x1_640x480_method_0, 0, 320, 1, 640, 480);
359 CREATE_TEST (test_upscale_320x1_640x480_method_1, 1, 320, 1, 640, 480);
360 CREATE_TEST (test_upscale_320x1_640x480_method_2, 2, 320, 1, 640, 480);
361 CREATE_TEST (test_upscale_320x1_640x480_method_3, 3, 320, 1, 640, 480);
362 CREATE_TEST (test_downscale_640x480_1x240_method_0, 0, 640, 480, 1, 240);
363 CREATE_TEST (test_downscale_640x480_1x240_method_1, 1, 640, 480, 1, 240);
364 CREATE_TEST (test_downscale_640x480_1x240_method_2, 2, 640, 480, 1, 240);
365 CREATE_TEST (test_downscale_640x480_1x240_method_3, 3, 640, 480, 1, 240);
366 CREATE_TEST (test_upscale_1x240_640x480_method_0, 0, 1, 240, 640, 480);
367 CREATE_TEST (test_upscale_1x240_640x480_method_1, 1, 1, 240, 640, 480);
368 CREATE_TEST (test_upscale_1x240_640x480_method_2, 2, 1, 240, 640, 480);
369 CREATE_TEST (test_upscale_1x240_640x480_method_3, 3, 1, 240, 640, 480);
370
371 typedef struct
372 {
373   gint width, height;
374   gint par_n, par_d;
375   gboolean ok;
376   GMainLoop *loop;
377 } TestNegotiationData;
378
379 static void
380 _test_negotiation_message (GstBus * bus, GstMessage * message,
381     TestNegotiationData * data)
382 {
383   GError *err = NULL;
384   gchar *debug;
385
386   switch (GST_MESSAGE_TYPE (message)) {
387     case GST_MESSAGE_ERROR:
388       gst_message_parse_error (message, &err, &debug);
389       gst_object_default_error (GST_MESSAGE_SRC (message), err, debug);
390       g_error_free (err);
391       g_free (debug);
392       g_assert_not_reached ();
393       break;
394     case GST_MESSAGE_WARNING:
395       gst_message_parse_warning (message, &err, &debug);
396       gst_object_default_error (GST_MESSAGE_SRC (message), err, debug);
397       g_error_free (err);
398       g_free (debug);
399       g_assert_not_reached ();
400       break;
401     case GST_MESSAGE_EOS:
402       g_main_loop_quit (data->loop);
403       break;
404     default:
405       break;
406   }
407 }
408
409 static void
410 _test_negotiation_notify_caps (GObject * src, GParamSpec * pspec,
411     TestNegotiationData * data)
412 {
413   GstCaps *caps;
414   GstStructure *s;
415   gint width, height;
416   gint par_n = 0, par_d = 0;
417
418   g_object_get (src, "caps", &caps, NULL);
419   if (caps == NULL)
420     return;
421
422   s = gst_caps_get_structure (caps, 0);
423
424   fail_unless (gst_structure_get_int (s, "width", &width));
425   fail_unless (gst_structure_get_int (s, "height", &height));
426   fail_unless (gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n,
427           &par_d) || (data->par_n == 1 && data->par_d == 1));
428
429   gst_caps_unref (caps);
430
431   fail_unless_equals_int (width, data->width);
432   fail_unless_equals_int (height, data->height);
433   if (par_n != 0 || par_d != 0) {
434     fail_unless_equals_int (par_n, data->par_n);
435     fail_unless_equals_int (par_d, data->par_d);
436   }
437
438   data->ok = (width == data->width) && (height == data->height)
439       && (par_n == data->par_n) && (par_d == data->par_d);
440
441   g_main_loop_quit (data->loop);
442 }
443
444 static void
445 _test_negotiation (const gchar * src_templ, const gchar * sink_templ,
446     gint width, gint height, gint par_n, gint par_d)
447 {
448   GstElement *pipeline;
449   GstElement *src, *capsfilter1, *scale, *capsfilter2, *sink;
450   GstBus *bus;
451   GMainLoop *loop;
452   GstCaps *caps;
453   TestNegotiationData data = { 0, 0, 0, 0, FALSE, NULL };
454   GstPad *pad;
455
456   GST_DEBUG ("Running test for src templ caps '%s' and sink templ caps '%s'",
457       src_templ, sink_templ);
458
459   pipeline = gst_element_factory_make ("pipeline", "pipeline");
460   fail_unless (pipeline != NULL);
461
462   src = gst_element_factory_make ("videotestsrc", "src");
463   fail_unless (src != NULL);
464   g_object_set (G_OBJECT (src), "num-buffers", 1, NULL);
465
466   capsfilter1 = gst_element_factory_make ("capsfilter", "filter1");
467   fail_unless (capsfilter1 != NULL);
468   caps = gst_caps_from_string (src_templ);
469   fail_unless (caps != NULL);
470   g_object_set (G_OBJECT (capsfilter1), "caps", caps, NULL);
471   gst_caps_unref (caps);
472
473   scale = gst_element_factory_make ("videoscale", "scale");
474   fail_unless (scale != NULL);
475
476   capsfilter2 = gst_element_factory_make ("capsfilter", "filter2");
477   fail_unless (capsfilter2 != NULL);
478   caps = gst_caps_from_string (sink_templ);
479   fail_unless (caps != NULL);
480   g_object_set (G_OBJECT (capsfilter2), "caps", caps, NULL);
481   gst_caps_unref (caps);
482
483   pad = gst_element_get_static_pad (capsfilter2, "sink");
484   fail_unless (pad != NULL);
485   g_signal_connect (pad, "notify::caps",
486       G_CALLBACK (_test_negotiation_notify_caps), &data);
487   gst_object_unref (pad);
488
489   sink = gst_element_factory_make ("fakesink", "sink");
490   fail_unless (sink != NULL);
491   g_object_set (sink, "async", FALSE, NULL);
492
493   gst_bin_add_many (GST_BIN (pipeline), src, capsfilter1, scale, capsfilter2,
494       sink, NULL);
495
496   fail_unless (gst_element_link_pads_full (src, "src", capsfilter1, "sink",
497           LINK_CHECK_FLAGS));
498   fail_unless (gst_element_link_pads_full (capsfilter1, "src", scale, "sink",
499           LINK_CHECK_FLAGS));
500   fail_unless (gst_element_link_pads_full (scale, "src", capsfilter2, "sink",
501           LINK_CHECK_FLAGS));
502   fail_unless (gst_element_link_pads_full (capsfilter2, "src", sink, "sink",
503           LINK_CHECK_FLAGS));
504
505   loop = g_main_loop_new (NULL, FALSE);
506
507   bus = gst_element_get_bus (pipeline);
508   fail_unless (bus != NULL);
509   gst_bus_add_signal_watch (bus);
510
511   data.loop = loop;
512   data.width = width;
513   data.height = height;
514   data.par_n = par_n;
515   data.par_d = par_d;
516   data.ok = FALSE;
517
518   g_signal_connect (bus, "message", G_CALLBACK (_test_negotiation_message),
519       &data);
520
521   gst_object_unref (bus);
522
523   fail_unless (gst_element_set_state (pipeline,
524           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
525
526   g_main_loop_run (loop);
527
528   fail_unless (data.ok == TRUE);
529
530   fail_unless (gst_element_set_state (pipeline,
531           GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
532
533   gst_object_unref (pipeline);
534   g_main_loop_unref (loop);
535 }
536
537 GST_START_TEST (test_negotiation)
538 {
539   _test_negotiation
540       ("video/x-raw,format=(string)AYUV,width=720,height=576,pixel-aspect-ratio=16/15",
541       "video/x-raw,format=(string)AYUV,width=768,height=576", 768, 576, 1, 1);
542
543   _test_negotiation
544       ("video/x-raw,format=(string)AYUV,width=320,height=240",
545       "video/x-raw,format=(string)AYUV,width=640,height=320", 640, 320, 2, 3);
546
547   _test_negotiation
548       ("video/x-raw,format=(string)AYUV,width=320,height=240",
549       "video/x-raw,format=(string)AYUV,width=640,height=320,pixel-aspect-ratio=[0/1, 1/1]",
550       640, 320, 2, 3);
551
552   _test_negotiation
553       ("video/x-raw,format=(string)AYUV,width=1920,height=2560,pixel-aspect-ratio=1/1",
554       "video/x-raw,format=(string)AYUV,width=[1, 2048],height=[1, 2048],pixel-aspect-ratio=1/1",
555       1536, 2048, 1, 1);
556
557   _test_negotiation
558       ("video/x-raw,format=(string)AYUV,width=1920,height=2560,pixel-aspect-ratio=1/1",
559       "video/x-raw,format=(string)AYUV,width=[1, 2048],height=[1, 2048]",
560       1920, 2048, 4, 5);
561
562   _test_negotiation
563       ("video/x-raw,format=(string)AYUV,width=1920,height=2560",
564       "video/x-raw,format=(string)AYUV,width=[1, 2048],height=[1, 2048]",
565       1920, 2048, 4, 5);
566
567   _test_negotiation
568       ("video/x-raw,format=(string)AYUV,width=1920,height=2560",
569       "video/x-raw,format=(string)AYUV,width=1200,height=[1, 2048],pixel-aspect-ratio=1/1",
570       1200, 1600, 1, 1);
571
572   /* Doesn't keep DAR but must be possible! */
573   _test_negotiation
574       ("video/x-raw,format=(string)AYUV,width=320,height=240,pixel-aspect-ratio=1/1",
575       "video/x-raw,format=(string)AYUV,width=200,height=200,pixel-aspect-ratio=1/2",
576       200, 200, 1, 2);
577 }
578
579 GST_END_TEST;
580
581 #define GST_TYPE_TEST_REVERSE_NEGOTIATION_SINK \
582   (gst_test_reverse_negotiation_sink_get_type())
583 #define GST_TEST_REVERSE_NEGOTIATION_SINK(obj) \
584   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TEST_REVERSE_NEGOTIATION_SINK,GstTestReverseNegotiationSink))
585 #define GST_TEST_REVERSE_NEGOTIATION_SINK_CLASS(klass) \
586   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TEST_REVERSE_NEGOTIATION_SINK,GstTestReverseNegotiationSinkClass))
587 #define GST_IS_TEST_REVERSE_NEGOTIATION_SINK(obj) \
588   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TEST_REVERSE_NEGOTIATION_SINK))
589 #define GST_IS_TEST_REVERSE_NEGOTIATION_SINK_CLASS(klass) \
590   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TEST_REVERSE_NEGOTIATION_SINK))
591 #define GST_TEST_REVERSE_NEGOTIATION_SINK_CAST(obj) ((GstTestReverseNegotiationSink *)obj)
592
593 typedef struct _GstTestReverseNegotiationSink GstTestReverseNegotiationSink;
594 typedef struct _GstTestReverseNegotiationSinkClass
595     GstTestReverseNegotiationSinkClass;
596 struct _GstTestReverseNegotiationSink
597 {
598   GstBaseSink element;
599   gint nbuffers;
600 };
601
602 struct _GstTestReverseNegotiationSinkClass
603 {
604   GstBaseSinkClass parent_class;
605 };
606
607 GType gst_test_reverse_negotiation_sink_get_type (void);
608
609 G_DEFINE_TYPE (GstTestReverseNegotiationSink,
610     gst_test_reverse_negotiation_sink, GST_TYPE_BASE_SINK);
611
612 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
613     GST_PAD_SINK,
614     GST_PAD_ALWAYS,
615     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("xRGB")));
616
617 #if 0
618 static GstFlowReturn
619 gst_test_reverse_negotiation_sink_buffer_alloc (GstBaseSink * bsink,
620     guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf)
621 {
622   GstTestReverseNegotiationSink *sink =
623       GST_TEST_REVERSE_NEGOTIATION_SINK (bsink);
624   GstVideoFormat fmt;
625   gint width, height;
626
627   fail_unless (gst_video_format_parse_caps (caps, &fmt, &width, &height));
628
629   if (sink->nbuffers < 2) {
630     *buf =
631         gst_buffer_new_and_alloc (gst_video_format_get_size (fmt, width,
632             height));
633     gst_buffer_set_caps (*buf, caps);
634   } else {
635     gint fps_n, fps_d;
636
637     fail_unless (gst_video_parse_caps_framerate (caps, &fps_n, &fps_d));
638
639     width = 512;
640     height = 128;
641     *buf =
642         gst_buffer_new_and_alloc (gst_video_format_get_size (fmt, width,
643             height));
644     caps = gst_video_format_new_caps (fmt, width, height, fps_n, fps_d, 1, 1);
645     gst_buffer_set_caps (*buf, caps);
646     gst_caps_unref (caps);
647   }
648
649   return GST_FLOW_OK;
650 }
651 #endif
652
653 static GstFlowReturn
654 gst_test_reverse_negotiation_sink_render (GstBaseSink * bsink,
655     GstBuffer * buffer)
656 {
657   GstTestReverseNegotiationSink *sink =
658       GST_TEST_REVERSE_NEGOTIATION_SINK (bsink);
659   GstCaps *caps;
660   GstVideoInfo info;
661
662   caps = gst_pad_get_current_caps (GST_BASE_SINK_PAD (bsink));
663
664   fail_unless (caps != NULL);
665   fail_unless (gst_video_info_from_caps (&info, caps));
666
667   sink->nbuffers++;
668
669   /* The third buffer is still in the old size
670    * because the videoconverts can't convert
671    * the frame sizes
672    */
673   if (sink->nbuffers > 3) {
674     fail_unless_equals_int (GST_VIDEO_INFO_WIDTH (&info), 512);
675     fail_unless_equals_int (GST_VIDEO_INFO_HEIGHT (&info), 128);
676   }
677
678   gst_caps_unref (caps);
679
680   return GST_FLOW_OK;
681 }
682
683 static void
684 gst_test_reverse_negotiation_sink_class_init (GstTestReverseNegotiationSinkClass
685     * klass)
686 {
687   GstElementClass *gstelement_class;
688   GstBaseSinkClass *gstbase_sink_class;
689
690   gstelement_class = GST_ELEMENT_CLASS (klass);
691   gstbase_sink_class = GST_BASE_SINK_CLASS (klass);
692
693   gst_element_class_set_details_simple (gstelement_class,
694       "Test Reverse Negotiation Sink",
695       "Sink",
696       "Some test sink", "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
697   gst_element_class_add_pad_template (gstelement_class,
698       gst_static_pad_template_get (&sinktemplate));
699
700 #if 0
701   gstbase_sink_class->buffer_alloc =
702       GST_DEBUG_FUNCPTR (gst_test_reverse_negotiation_sink_buffer_alloc);
703 #endif
704   gstbase_sink_class->render =
705       GST_DEBUG_FUNCPTR (gst_test_reverse_negotiation_sink_render);
706 }
707
708 static void
709 gst_test_reverse_negotiation_sink_init (GstTestReverseNegotiationSink * sink)
710 {
711   sink->nbuffers = 0;
712 }
713
714 #if 0
715 static void
716 _test_reverse_negotiation_message (GstBus * bus, GstMessage * message,
717     GMainLoop * loop)
718 {
719   GError *err = NULL;
720   gchar *debug;
721
722   switch (GST_MESSAGE_TYPE (message)) {
723     case GST_MESSAGE_ERROR:
724       gst_message_parse_error (message, &err, &debug);
725       gst_object_default_error (GST_MESSAGE_SRC (message), err, debug);
726       g_error_free (err);
727       g_free (debug);
728       g_assert_not_reached ();
729       break;
730     case GST_MESSAGE_WARNING:
731       gst_message_parse_warning (message, &err, &debug);
732       gst_object_default_error (GST_MESSAGE_SRC (message), err, debug);
733       g_error_free (err);
734       g_free (debug);
735       g_assert_not_reached ();
736       break;
737     case GST_MESSAGE_EOS:
738       g_main_loop_quit (loop);
739       break;
740     default:
741       break;
742   }
743 }
744 #endif
745
746 #if 0
747 GST_START_TEST (test_reverse_negotiation)
748 {
749   GstElement *pipeline;
750   GstElement *src, *csp1, *scale, *csp2, *sink;
751   GstBus *bus;
752   GMainLoop *loop;
753
754   pipeline = gst_element_factory_make ("pipeline", "pipeline");
755   fail_unless (pipeline != NULL);
756
757   src = gst_element_factory_make ("videotestsrc", "src");
758   fail_unless (src != NULL);
759   g_object_set (G_OBJECT (src), "num-buffers", 8, NULL);
760
761   csp1 = gst_element_factory_make ("videoconvert", "csp1");
762   fail_unless (csp1 != NULL);
763
764   scale = gst_element_factory_make ("videoscale", "scale");
765   fail_unless (scale != NULL);
766
767   csp2 = gst_element_factory_make ("videoconvert", "csp2");
768   fail_unless (csp2 != NULL);
769
770   sink = g_object_new (GST_TYPE_TEST_REVERSE_NEGOTIATION_SINK, NULL);
771   fail_unless (sink != NULL);
772   g_object_set (sink, "async", FALSE, NULL);
773
774   gst_bin_add_many (GST_BIN (pipeline), src, csp1, scale, csp2, sink, NULL);
775
776   fail_unless (gst_element_link_pads_full (src, "src", csp1, "sink",
777           LINK_CHECK_FLAGS));
778   fail_unless (gst_element_link_pads_full (csp1, "src", scale, "sink",
779           LINK_CHECK_FLAGS));
780   fail_unless (gst_element_link_pads_full (scale, "src", csp2, "sink",
781           LINK_CHECK_FLAGS));
782   fail_unless (gst_element_link_pads_full (csp2, "src", sink, "sink",
783           LINK_CHECK_FLAGS));
784
785   loop = g_main_loop_new (NULL, FALSE);
786
787   bus = gst_element_get_bus (pipeline);
788   fail_unless (bus != NULL);
789   gst_bus_add_signal_watch (bus);
790
791   g_signal_connect (bus, "message",
792       G_CALLBACK (_test_reverse_negotiation_message), loop);
793
794   gst_object_unref (bus);
795
796   fail_unless (gst_element_set_state (pipeline,
797           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
798
799   g_main_loop_run (loop);
800
801   fail_unless (gst_element_set_state (pipeline,
802           GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
803
804   gst_object_unref (pipeline);
805   g_main_loop_unref (loop);
806 }
807
808 GST_END_TEST;
809 #endif
810
811 GST_START_TEST (test_basetransform_negotiation)
812 {
813   GstElement *pipeline, *src, *sink, *scale, *capsfilter1, *capsfilter2;
814   GstMessage *msg;
815   GstCaps *caps;
816
817   pipeline = gst_pipeline_new (NULL);
818   src = gst_element_factory_make ("videotestsrc", NULL);
819   capsfilter1 = gst_element_factory_make ("capsfilter", NULL);
820   scale = gst_element_factory_make ("videoscale", NULL);
821   capsfilter2 = gst_element_factory_make ("capsfilter", NULL);
822   sink = gst_element_factory_make ("fakesink", NULL);
823   fail_unless (pipeline && src && capsfilter1 && scale && capsfilter2 && sink);
824
825   g_object_set (src, "num-buffers", 3, NULL);
826
827   caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING,
828       "UYVY", "width", G_TYPE_INT, 352,
829       "height", G_TYPE_INT, 288, "framerate", GST_TYPE_FRACTION, 30, 1,
830       "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, NULL);
831   g_object_set (capsfilter1, "caps", caps, NULL);
832   gst_caps_unref (caps);
833
834   /* same caps, just different pixel-aspect-ratio */
835   caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING,
836       "UYVY", "width", G_TYPE_INT, 352,
837       "height", G_TYPE_INT, 288, "framerate", GST_TYPE_FRACTION, 30, 1,
838       "pixel-aspect-ratio", GST_TYPE_FRACTION, 12, 11, NULL);
839   g_object_set (capsfilter2, "caps", caps, NULL);
840   gst_caps_unref (caps);
841
842   gst_bin_add_many (GST_BIN (pipeline), src, capsfilter1, scale, capsfilter2,
843       sink, NULL);
844   fail_unless (gst_element_link_many (src, capsfilter1, scale, capsfilter2,
845           sink, NULL));
846
847   fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
848       GST_STATE_CHANGE_ASYNC);
849
850   msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipeline), -1,
851       GST_MESSAGE_EOS | GST_MESSAGE_ERROR);
852   fail_unless_equals_int (GST_MESSAGE_TYPE (msg), GST_MESSAGE_EOS);
853   gst_message_unref (msg);
854
855   gst_element_set_state (pipeline, GST_STATE_NULL);
856   gst_object_unref (pipeline);
857 }
858
859 GST_END_TEST;
860
861 #ifndef tcase_skip_broken_test
862 #define tcase_skip_broken_test(chain,test_func) \
863   if (0) { tcase_add_test(chain,test_func); } else { \
864     GST_ERROR ("FIXME: skipping test %s because it's broken.", G_STRINGIFY (test_func)); \
865   }
866 #endif
867
868 static Suite *
869 videoscale_suite (void)
870 {
871   Suite *s = suite_create ("videoscale");
872   TCase *tc_chain = tcase_create ("general");
873
874   suite_add_tcase (s, tc_chain);
875   tcase_set_timeout (tc_chain, 180);
876   tcase_add_test (tc_chain, test_passthrough_method_0);
877   tcase_add_test (tc_chain, test_passthrough_method_1);
878   tcase_add_test (tc_chain, test_passthrough_method_2);
879   tcase_add_test (tc_chain, test_passthrough_method_3);
880   tcase_add_test (tc_chain, test_downscale_640x480_320x240_method_0);
881   tcase_add_test (tc_chain, test_downscale_640x480_320x240_method_1);
882   tcase_add_test (tc_chain, test_downscale_640x480_320x240_method_2);
883   tcase_add_test (tc_chain, test_downscale_640x480_320x240_method_3);
884   tcase_add_test (tc_chain, test_upscale_320x240_640x480_method_0);
885   tcase_add_test (tc_chain, test_upscale_320x240_640x480_method_1);
886   tcase_add_test (tc_chain, test_upscale_320x240_640x480_method_2);
887   tcase_add_test (tc_chain, test_upscale_320x240_640x480_method_3);
888   tcase_add_test (tc_chain, test_downscale_640x480_1x1_method_0);
889   tcase_add_test (tc_chain, test_downscale_640x480_1x1_method_1);
890   tcase_add_test (tc_chain, test_downscale_640x480_1x1_method_2);
891   tcase_skip_broken_test (tc_chain, test_downscale_640x480_1x1_method_3);
892   tcase_add_test (tc_chain, test_upscale_1x1_640x480_method_0);
893   tcase_add_test (tc_chain, test_upscale_1x1_640x480_method_1);
894   tcase_add_test (tc_chain, test_upscale_1x1_640x480_method_2);
895   tcase_add_test (tc_chain, test_upscale_1x1_640x480_method_3);
896   tcase_add_test (tc_chain, test_downscale_641x481_111x30_method_0);
897   tcase_add_test (tc_chain, test_downscale_641x481_111x30_method_1);
898   tcase_add_test (tc_chain, test_downscale_641x481_111x30_method_2);
899   tcase_add_test (tc_chain, test_downscale_641x481_111x30_method_3);
900   tcase_add_test (tc_chain, test_upscale_111x30_641x481_method_0);
901   tcase_add_test (tc_chain, test_upscale_111x30_641x481_method_1);
902   tcase_add_test (tc_chain, test_upscale_111x30_641x481_method_2);
903   tcase_add_test (tc_chain, test_upscale_111x30_641x481_method_3);
904   tcase_add_test (tc_chain, test_downscale_641x481_30x111_method_0);
905   tcase_add_test (tc_chain, test_downscale_641x481_30x111_method_1);
906   tcase_add_test (tc_chain, test_downscale_641x481_30x111_method_2);
907   tcase_add_test (tc_chain, test_downscale_641x481_30x111_method_3);
908   tcase_add_test (tc_chain, test_upscale_30x111_641x481_method_0);
909   tcase_add_test (tc_chain, test_upscale_30x111_641x481_method_1);
910   tcase_add_test (tc_chain, test_upscale_30x111_641x481_method_2);
911   tcase_add_test (tc_chain, test_upscale_30x111_641x481_method_3);
912   tcase_add_test (tc_chain, test_downscale_640x480_320x1_method_0);
913   tcase_add_test (tc_chain, test_downscale_640x480_320x1_method_1);
914   tcase_add_test (tc_chain, test_downscale_640x480_320x1_method_2);
915   tcase_skip_broken_test (tc_chain, test_downscale_640x480_320x1_method_3);
916   tcase_add_test (tc_chain, test_upscale_320x1_640x480_method_0);
917   tcase_add_test (tc_chain, test_upscale_320x1_640x480_method_1);
918   tcase_add_test (tc_chain, test_upscale_320x1_640x480_method_2);
919   tcase_skip_broken_test (tc_chain, test_upscale_320x1_640x480_method_3);
920   tcase_add_test (tc_chain, test_downscale_640x480_1x240_method_0);
921   tcase_add_test (tc_chain, test_downscale_640x480_1x240_method_1);
922   tcase_add_test (tc_chain, test_downscale_640x480_1x240_method_2);
923   tcase_add_test (tc_chain, test_downscale_640x480_1x240_method_3);
924   tcase_add_test (tc_chain, test_upscale_1x240_640x480_method_0);
925   tcase_add_test (tc_chain, test_upscale_1x240_640x480_method_1);
926   tcase_add_test (tc_chain, test_upscale_1x240_640x480_method_2);
927   tcase_add_test (tc_chain, test_upscale_1x240_640x480_method_3);
928   tcase_add_test (tc_chain, test_negotiation);
929 #if 0
930   tcase_add_test (tc_chain, test_reverse_negotiation);
931 #endif
932   tcase_add_test (tc_chain, test_basetransform_negotiation);
933
934   GST_ERROR ("FIXME: test 64-bpp formats as well");
935   return s;
936 }
937
938 GST_CHECK_MAIN (videoscale);