1 /* GStreamer
2  *
3  * unit test for videorate
4  *
5  * Copyright (C) 2006 Thomas Vander Stichele <thomas at apestaart dot org>
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., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include <gst/check/gstcheck.h>
27 
28 /* For ease of programming we use globals to keep refs for our floating
29  * src and sink pads we create; otherwise we always have to do get_pad,
30  * get_peer, and then remove references in every test function */
31 static GstPad *mysrcpad, *mysinkpad;
32 
33 
34 #define VIDEO_CAPS_TEMPLATE_STRING     \
35     "video/x-raw"
36 
37 #define VIDEO_CAPS_STRING               \
38     "video/x-raw, "                 \
39     "width = (int) 320, "               \
40     "height = (int) 240, "              \
41     "framerate = (fraction) 25/1 , "    \
42     "format = (string) I420"
43 
44 #define VIDEO_CAPS_FORCE_VARIABLE_FRAMERATE_STRING \
45     "video/x-raw, "                 \
46     "framerate = (fraction) 0/1"
47 
48 #define VIDEO_CAPS_NO_FRAMERATE_STRING  \
49     "video/x-raw, "                 \
50     "width = (int) 320, "               \
51     "height = (int) 240, "              \
52     "format = (string) I420"
53 
54 #define VIDEO_CAPS_NEWSIZE_STRING       \
55     "video/x-raw, "                 \
56     "width = (int) 240, "               \
57     "height = (int) 120, "              \
58     "framerate = (fraction) 25/1 , "	\
59     "format = (string) I420"
60 
61 #define VIDEO_CAPS_UNUSUAL_FRAMERATE    \
62     "video/x-raw, "                 \
63     "width = (int) 240, "               \
64     "height = (int) 120, "              \
65     "framerate = (fraction) 999/7 , "	\
66     "format = (string) I420"
67 
68 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
69     GST_PAD_SINK,
70     GST_PAD_ALWAYS,
71     GST_STATIC_CAPS (VIDEO_CAPS_TEMPLATE_STRING)
72     );
73 static GstStaticPadTemplate downstreamsinktemplate =
74 GST_STATIC_PAD_TEMPLATE ("sink",
75     GST_PAD_SINK,
76     GST_PAD_ALWAYS,
77     GST_STATIC_CAPS (VIDEO_CAPS_STRING)
78     );
79 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
80     GST_PAD_SRC,
81     GST_PAD_ALWAYS,
82     GST_STATIC_CAPS (VIDEO_CAPS_TEMPLATE_STRING)
83     );
84 
85 static GstStaticPadTemplate force_variable_rate_template =
86 GST_STATIC_PAD_TEMPLATE ("sink",
87     GST_PAD_SINK,
88     GST_PAD_ALWAYS,
89     GST_STATIC_CAPS (VIDEO_CAPS_FORCE_VARIABLE_FRAMERATE_STRING)
90     );
91 
92 static void
assert_videorate_stats(GstElement * videorate,const gchar * reason,guint64 xin,guint64 xout,guint64 xdropped,guint64 xduplicated)93 assert_videorate_stats (GstElement * videorate, const gchar * reason,
94     guint64 xin, guint64 xout, guint64 xdropped, guint64 xduplicated)
95 {
96   guint64 in, out, dropped, duplicated;
97 
98   g_object_get (videorate, "in", &in, "out", &out, "drop", &dropped,
99       "duplicate", &duplicated, NULL);
100 #define _assert_equals_uint64(a, b)                                     \
101 G_STMT_START {                                                          \
102   guint64 first = a;                                                    \
103   guint64 second = b;                                                   \
104   fail_unless(first == second,                                          \
105     "%s: '" #a "' (%" G_GUINT64_FORMAT ") is not equal to "		\
106     "expected '" #a"' (%" G_GUINT64_FORMAT ")", reason, first, second); \
107 } G_STMT_END;
108 
109 
110   _assert_equals_uint64 (in, xin);
111   _assert_equals_uint64 (out, xout);
112   _assert_equals_uint64 (dropped, xdropped);
113   _assert_equals_uint64 (duplicated, xduplicated);
114 }
115 
116 static GstElement *
setup_videorate_full(GstStaticPadTemplate * srctemplate,GstStaticPadTemplate * sinktemplate)117 setup_videorate_full (GstStaticPadTemplate * srctemplate,
118     GstStaticPadTemplate * sinktemplate)
119 {
120   GstElement *videorate;
121 
122   GST_DEBUG ("setup_videorate");
123   videorate = gst_check_setup_element ("videorate");
124   mysrcpad = gst_check_setup_src_pad (videorate, srctemplate);
125   mysinkpad = gst_check_setup_sink_pad (videorate, sinktemplate);
126   gst_pad_set_active (mysrcpad, TRUE);
127   gst_pad_set_active (mysinkpad, TRUE);
128 
129   return videorate;
130 }
131 
132 static GstElement *
setup_videorate(void)133 setup_videorate (void)
134 {
135   return setup_videorate_full (&srctemplate, &sinktemplate);
136 }
137 
138 static void
cleanup_videorate(GstElement * videorate)139 cleanup_videorate (GstElement * videorate)
140 {
141   GST_DEBUG ("cleanup_videorate");
142 
143   g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
144   g_list_free (buffers);
145   buffers = NULL;
146 
147   gst_element_set_state (videorate, GST_STATE_NULL);
148   gst_element_get_state (videorate, NULL, NULL, GST_CLOCK_TIME_NONE);
149   gst_pad_set_active (mysrcpad, FALSE);
150   gst_pad_set_active (mysinkpad, FALSE);
151   gst_check_teardown_src_pad (videorate);
152   gst_check_teardown_sink_pad (videorate);
153   gst_check_teardown_element (videorate);
154 }
155 
156 static guint8
buffer_get_byte(GstBuffer * buffer,gint offset)157 buffer_get_byte (GstBuffer * buffer, gint offset)
158 {
159   guint8 res;
160 
161   gst_buffer_extract (buffer, offset, &res, 1);
162 
163   return res;
164 }
165 
GST_START_TEST(test_one)166 GST_START_TEST (test_one)
167 {
168   GstElement *videorate;
169   GstBuffer *inbuffer;
170   GstCaps *caps;
171 
172   videorate = setup_videorate ();
173   fail_unless (gst_element_set_state (videorate,
174           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
175       "could not set to playing");
176 
177   inbuffer = gst_buffer_new_and_alloc (4);
178   gst_buffer_memset (inbuffer, 0, 0, 4);
179   caps = gst_caps_from_string (VIDEO_CAPS_STRING);
180   gst_check_setup_events (mysrcpad, videorate, caps, GST_FORMAT_TIME);
181   GST_BUFFER_TIMESTAMP (inbuffer) = 0;
182   gst_caps_unref (caps);
183   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
184 
185   /* pushing gives away my reference ... */
186   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
187   /* ... and it is now stuck inside videorate */
188   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
189   fail_unless_equals_int (g_list_length (buffers), 0);
190 
191   /* cleanup */
192   cleanup_videorate (videorate);
193 }
194 
195 GST_END_TEST;
196 
GST_START_TEST(test_more)197 GST_START_TEST (test_more)
198 {
199   GstElement *videorate;
200   GstBuffer *first, *second, *third, *outbuffer;
201   GList *l;
202   GstCaps *caps;
203   GRand *rand;
204 
205   videorate = setup_videorate ();
206   fail_unless (gst_element_set_state (videorate,
207           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
208       "could not set to playing");
209   assert_videorate_stats (videorate, "creation", 0, 0, 0, 0);
210 
211   rand = g_rand_new ();
212 
213   /* first buffer */
214   first = gst_buffer_new_and_alloc (4);
215   GST_BUFFER_TIMESTAMP (first) = 0;
216   /* it shouldn't matter what the offsets are, videorate produces perfect
217      streams */
218   GST_BUFFER_OFFSET (first) = g_rand_int (rand);
219   GST_BUFFER_OFFSET_END (first) = g_rand_int (rand);
220   gst_buffer_memset (first, 0, 1, 4);
221   caps = gst_caps_from_string (VIDEO_CAPS_STRING);
222   gst_check_setup_events (mysrcpad, videorate, caps, GST_FORMAT_TIME);
223   gst_caps_unref (caps);
224   ASSERT_BUFFER_REFCOUNT (first, "first", 1);
225   gst_buffer_ref (first);
226 
227   /* pushing gives away my reference ... */
228   fail_unless (gst_pad_push (mysrcpad, first) == GST_FLOW_OK);
229   /* ... and a copy is now stuck inside videorate */
230   ASSERT_BUFFER_REFCOUNT (first, "first", 1);
231   fail_unless_equals_int (g_list_length (buffers), 0);
232   assert_videorate_stats (videorate, "first buffer", 1, 0, 0, 0);
233 
234   /* second buffer; inbetween second and third output frame's timestamp */
235   second = gst_buffer_new_and_alloc (4);
236   GST_BUFFER_TIMESTAMP (second) = GST_SECOND * 3 / 50;
237   GST_BUFFER_OFFSET (second) = g_rand_int (rand);
238   GST_BUFFER_OFFSET_END (second) = g_rand_int (rand);
239   gst_buffer_memset (second, 0, 2, 4);
240   ASSERT_BUFFER_REFCOUNT (second, "second", 1);
241   gst_buffer_ref (second);
242 
243   /* pushing gives away one of my references ... */
244   fail_unless (gst_pad_push (mysrcpad, second) == GST_FLOW_OK);
245   /* ... and a copy is now stuck inside videorate */
246   ASSERT_BUFFER_REFCOUNT (second, "second", 1);
247 
248   /* ... and the first one is pushed out, with timestamp 0 */
249   fail_unless_equals_int (g_list_length (buffers), 1);
250   assert_videorate_stats (videorate, "second buffer", 2, 1, 0, 0);
251   ASSERT_BUFFER_REFCOUNT (first, "first", 1);
252 
253   outbuffer = buffers->data;
254   fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (outbuffer), 0);
255 
256   /* third buffer */
257   third = gst_buffer_new_and_alloc (4);
258   GST_BUFFER_TIMESTAMP (third) = GST_SECOND * 12 / 50;
259   GST_BUFFER_OFFSET (third) = g_rand_int (rand);
260   GST_BUFFER_OFFSET_END (third) = g_rand_int (rand);
261   gst_buffer_memset (third, 0, 3, 4);
262   ASSERT_BUFFER_REFCOUNT (third, "third", 1);
263   gst_buffer_ref (third);
264 
265   /* pushing gives away my reference ... */
266   fail_unless (gst_pad_push (mysrcpad, third) == GST_FLOW_OK);
267   /* ... and a copy is now stuck inside videorate */
268   ASSERT_BUFFER_REFCOUNT (third, "third", 1);
269 
270   /* submitting the third buffer has triggered flushing of three more frames */
271   assert_videorate_stats (videorate, "third buffer", 3, 4, 0, 2);
272 
273   /* check timestamp and source correctness */
274   l = buffers;
275   fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (l->data), 0);
276   fail_unless_equals_int (buffer_get_byte (l->data, 0), 1);
277   fail_unless_equals_uint64 (GST_BUFFER_OFFSET (l->data), 0);
278   fail_unless_equals_uint64 (GST_BUFFER_OFFSET_END (l->data), 1);
279 
280   l = g_list_next (l);
281   fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (l->data), GST_SECOND / 25);
282   fail_unless_equals_int (buffer_get_byte (l->data, 0), 2);
283   fail_unless_equals_uint64 (GST_BUFFER_OFFSET (l->data), 1);
284   fail_unless_equals_uint64 (GST_BUFFER_OFFSET_END (l->data), 2);
285 
286   l = g_list_next (l);
287   fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (l->data),
288       GST_SECOND * 2 / 25);
289   fail_unless_equals_int (buffer_get_byte (l->data, 0), 2);
290   fail_unless_equals_uint64 (GST_BUFFER_OFFSET (l->data), 2);
291   fail_unless_equals_uint64 (GST_BUFFER_OFFSET_END (l->data), 3);
292 
293   l = g_list_next (l);
294   fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (l->data),
295       GST_SECOND * 3 / 25);
296   fail_unless_equals_int (buffer_get_byte (l->data, 0), 2);
297   fail_unless_equals_uint64 (GST_BUFFER_OFFSET (l->data), 3);
298   fail_unless_equals_uint64 (GST_BUFFER_OFFSET_END (l->data), 4);
299 
300   fail_unless_equals_int (g_list_length (buffers), 4);
301   /* one held by us, three held by each output frame taken from the second */
302   ASSERT_BUFFER_REFCOUNT (second, "second", 1);
303 
304   /* now send EOS */
305   fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
306 
307   /* submitting eos should flush out two more frames for tick 8 and 10 */
308   /* FIXME: right now it only flushes out one, so out is 5 instead of 6 ! */
309   assert_videorate_stats (videorate, "eos", 3, 5, 0, 2);
310   fail_unless_equals_int (g_list_length (buffers), 5);
311 
312   /* cleanup */
313   g_rand_free (rand);
314   gst_buffer_unref (first);
315   gst_buffer_unref (second);
316   gst_buffer_unref (third);
317   cleanup_videorate (videorate);
318 }
319 
320 GST_END_TEST;
321 
322 /* frames at 1, 0, 2 -> second one should be ignored */
GST_START_TEST(test_wrong_order_from_zero)323 GST_START_TEST (test_wrong_order_from_zero)
324 {
325   GstElement *videorate;
326   GstBuffer *first, *second, *third, *outbuffer;
327   GstCaps *caps;
328 
329   videorate = setup_videorate ();
330   fail_unless (gst_element_set_state (videorate,
331           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
332       "could not set to playing");
333   assert_videorate_stats (videorate, "start", 0, 0, 0, 0);
334 
335   /* first buffer */
336   first = gst_buffer_new_and_alloc (4);
337   GST_BUFFER_TIMESTAMP (first) = GST_SECOND;
338   gst_buffer_memset (first, 0, 0, 4);
339   caps = gst_caps_from_string (VIDEO_CAPS_STRING);
340   gst_check_setup_events (mysrcpad, videorate, caps, GST_FORMAT_TIME);
341   gst_caps_unref (caps);
342   ASSERT_BUFFER_REFCOUNT (first, "first", 1);
343   gst_buffer_ref (first);
344 
345   GST_DEBUG ("pushing first buffer");
346   /* pushing gives away my reference ... */
347   fail_unless (gst_pad_push (mysrcpad, first) == GST_FLOW_OK);
348   /* ... and a copy is now stuck inside videorate */
349   ASSERT_BUFFER_REFCOUNT (first, "first", 1);
350   fail_unless_equals_int (g_list_length (buffers), 0);
351   assert_videorate_stats (videorate, "first", 1, 0, 0, 0);
352 
353   /* second buffer */
354   second = gst_buffer_new_and_alloc (4);
355   GST_BUFFER_TIMESTAMP (second) = 0;
356   gst_buffer_memset (second, 0, 0, 4);
357   ASSERT_BUFFER_REFCOUNT (second, "second", 1);
358   gst_buffer_ref (second);
359 
360   /* pushing gives away my reference ... */
361   fail_unless (gst_pad_push (mysrcpad, second) == GST_FLOW_OK);
362   /* ... and it is now dropped because it is too old */
363   ASSERT_BUFFER_REFCOUNT (second, "second", 1);
364   fail_unless_equals_int (g_list_length (buffers), 0);
365 
366   /* ... and the first one is still there */
367   assert_videorate_stats (videorate, "second", 2, 0, 1, 0);
368   ASSERT_BUFFER_REFCOUNT (first, "first", 1);
369 
370   /* third buffer */
371   third = gst_buffer_new_and_alloc (4);
372   GST_BUFFER_TIMESTAMP (third) = 2 * GST_SECOND;
373   gst_buffer_memset (third, 0, 0, 4);
374   ASSERT_BUFFER_REFCOUNT (third, "third", 1);
375   gst_buffer_ref (third);
376 
377   /* pushing gives away my reference ... */
378   fail_unless (gst_pad_push (mysrcpad, third) == GST_FLOW_OK);
379   /* ... and a copy is now stuck inside videorate */
380   ASSERT_BUFFER_REFCOUNT (third, "third", 1);
381 
382   /* and now the first one should be pushed once and dupped 24 + 13 times, to
383    * reach the half point between 1 s (first) and 2 s (third) */
384   fail_unless_equals_int (g_list_length (buffers), 38);
385   ASSERT_BUFFER_REFCOUNT (first, "first", 1);
386   ASSERT_BUFFER_REFCOUNT (second, "second", 1);
387   ASSERT_BUFFER_REFCOUNT (third, "third", 1);
388   assert_videorate_stats (videorate, "third", 3, 38, 1, 37);
389 
390   /* verify last buffer */
391   outbuffer = g_list_last (buffers)->data;
392   fail_unless (GST_IS_BUFFER (outbuffer));
393   fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (outbuffer),
394       GST_SECOND * 37 / 25);
395 
396   /* cleanup */
397   gst_buffer_unref (first);
398   gst_buffer_unref (second);
399   gst_buffer_unref (third);
400   cleanup_videorate (videorate);
401 }
402 
403 GST_END_TEST;
404 
405 /* send frames with 0, 1, 2, 5, 6 seconds, max-duplication-time=2sec */
GST_START_TEST(test_max_duplication_time)406 GST_START_TEST (test_max_duplication_time)
407 {
408   GstElement *videorate;
409   GstBuffer *first, *second, *third, *fourth, *fifth, *outbuffer;
410   GstCaps *caps;
411 
412   videorate = setup_videorate ();
413   g_object_set (videorate, "max-duplication-time", 2 * GST_SECOND, NULL);
414   fail_unless (gst_element_set_state (videorate,
415           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
416       "could not set to playing");
417   assert_videorate_stats (videorate, "start", 0, 0, 0, 0);
418 
419   /* first buffer */
420   first = gst_buffer_new_and_alloc (4);
421   GST_BUFFER_TIMESTAMP (first) = 0;
422   gst_buffer_memset (first, 0, 0, 4);
423   caps = gst_caps_from_string (VIDEO_CAPS_STRING);
424   gst_check_setup_events (mysrcpad, videorate, caps, GST_FORMAT_TIME);
425   gst_caps_unref (caps);
426   ASSERT_BUFFER_REFCOUNT (first, "first", 1);
427   gst_buffer_ref (first);
428 
429   GST_DEBUG ("pushing first buffer");
430   /* pushing gives away my reference ... */
431   fail_unless (gst_pad_push (mysrcpad, first) == GST_FLOW_OK);
432   /* ... and a copy is now stuck inside videorate */
433   ASSERT_BUFFER_REFCOUNT (first, "first", 1);
434   fail_unless_equals_int (g_list_length (buffers), 0);
435   assert_videorate_stats (videorate, "first", 1, 0, 0, 0);
436 
437   /* second buffer */
438   second = gst_buffer_new_and_alloc (4);
439   GST_BUFFER_TIMESTAMP (second) = GST_SECOND;
440   gst_buffer_memset (second, 0, 0, 4);
441   ASSERT_BUFFER_REFCOUNT (second, "second", 1);
442   gst_buffer_ref (second);
443 
444   /* pushing gives away my reference ... */
445   fail_unless (gst_pad_push (mysrcpad, second) == GST_FLOW_OK);
446   /* ... and a copy is now stuck inside videorate */
447   ASSERT_BUFFER_REFCOUNT (second, "second", 1);
448   /* and it created 13 output buffers as copies of the first frame */
449   fail_unless_equals_int (g_list_length (buffers), 13);
450   assert_videorate_stats (videorate, "second", 2, 13, 0, 12);
451   ASSERT_BUFFER_REFCOUNT (first, "first", 1);
452 
453   /* third buffer */
454   third = gst_buffer_new_and_alloc (4);
455   GST_BUFFER_TIMESTAMP (third) = 2 * GST_SECOND;
456   gst_buffer_memset (third, 0, 0, 4);
457   ASSERT_BUFFER_REFCOUNT (third, "third", 1);
458   gst_buffer_ref (third);
459 
460   /* pushing gives away my reference ... */
461   fail_unless (gst_pad_push (mysrcpad, third) == GST_FLOW_OK);
462   /* ... and a copy is now stuck inside videorate */
463   ASSERT_BUFFER_REFCOUNT (third, "third", 1);
464 
465   /* submitting a frame with 2 seconds triggers output of 25 more frames */
466   fail_unless_equals_int (g_list_length (buffers), 38);
467   ASSERT_BUFFER_REFCOUNT (first, "first", 1);
468   ASSERT_BUFFER_REFCOUNT (second, "second", 1);
469   ASSERT_BUFFER_REFCOUNT (third, "third", 1);
470   /* three frames submitted; two of them output as is, and 36 duplicated */
471   assert_videorate_stats (videorate, "third", 3, 38, 0, 36);
472 
473   /* fourth buffer */
474   fourth = gst_buffer_new_and_alloc (4);
475   GST_BUFFER_TIMESTAMP (fourth) = 5 * GST_SECOND;
476   gst_buffer_memset (fourth, 0, 0, 4);
477   ASSERT_BUFFER_REFCOUNT (fourth, "fourth", 1);
478   gst_buffer_ref (fourth);
479 
480   /* pushing gives away my reference ... */
481   fail_unless (gst_pad_push (mysrcpad, fourth) == GST_FLOW_OK);
482   /* ... and a copy is now stuck inside videorate */
483   ASSERT_BUFFER_REFCOUNT (fourth, "fourth", 1);
484 
485   /* should now have drained everything up to the 2s buffer above */
486   fail_unless_equals_int (g_list_length (buffers), 51);
487   ASSERT_BUFFER_REFCOUNT (first, "first", 1);
488   ASSERT_BUFFER_REFCOUNT (second, "second", 1);
489   ASSERT_BUFFER_REFCOUNT (third, "third", 1);
490   ASSERT_BUFFER_REFCOUNT (fourth, "fourth", 1);
491   assert_videorate_stats (videorate, "fourth", 4, 51, 0, 48);
492 
493   /* verify last buffer */
494   outbuffer = g_list_last (buffers)->data;
495   fail_unless (GST_IS_BUFFER (outbuffer));
496   fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (outbuffer), 2 * GST_SECOND);
497 
498   /* fifth buffer */
499   fifth = gst_buffer_new_and_alloc (4);
500   GST_BUFFER_TIMESTAMP (fifth) = 6 * GST_SECOND;
501   gst_buffer_memset (fifth, 0, 0, 4);
502   ASSERT_BUFFER_REFCOUNT (fifth, "fifth", 1);
503   gst_buffer_ref (fifth);
504 
505   /* pushing gives away my reference ... */
506   fail_unless (gst_pad_push (mysrcpad, fifth) == GST_FLOW_OK);
507   /* ... and a copy is now stuck inside videorate */
508   ASSERT_BUFFER_REFCOUNT (third, "fifth", 1);
509 
510   /* submitting a frame with 6 seconds triggers output of 12 more frames */
511   fail_unless_equals_int (g_list_length (buffers), 63);
512   ASSERT_BUFFER_REFCOUNT (first, "first", 1);
513   ASSERT_BUFFER_REFCOUNT (second, "second", 1);
514   ASSERT_BUFFER_REFCOUNT (third, "third", 1);
515   ASSERT_BUFFER_REFCOUNT (fourth, "fourth", 1);
516   ASSERT_BUFFER_REFCOUNT (fifth, "fifth", 1);
517   /* five frames submitted; two of them output as is, 63 and 59 duplicated */
518   assert_videorate_stats (videorate, "fifth", 5, 63, 0, 59);
519 
520   /* push EOS to drain */
521   fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
522 
523   /* we should now have gotten one output for the last frame */
524   fail_unless_equals_int (g_list_length (buffers), 64);
525   ASSERT_BUFFER_REFCOUNT (first, "first", 1);
526   ASSERT_BUFFER_REFCOUNT (second, "second", 1);
527   ASSERT_BUFFER_REFCOUNT (third, "third", 1);
528   ASSERT_BUFFER_REFCOUNT (fourth, "fourth", 1);
529   ASSERT_BUFFER_REFCOUNT (fifth, "fifth", 1);
530   /* five frames submitted; two of them output as is, 64 and 60 duplicated */
531   assert_videorate_stats (videorate, "fifth", 5, 64, 0, 59);
532 
533   /* cleanup */
534   gst_buffer_unref (first);
535   gst_buffer_unref (second);
536   gst_buffer_unref (third);
537   gst_buffer_unref (fourth);
538   gst_buffer_unref (fifth);
539   cleanup_videorate (videorate);
540 }
541 
542 GST_END_TEST;
543 
544 /* send frames with 0, 1, 2, 0 seconds */
GST_START_TEST(test_wrong_order)545 GST_START_TEST (test_wrong_order)
546 {
547   GstElement *videorate;
548   GstBuffer *first, *second, *third, *fourth, *outbuffer;
549   GstCaps *caps;
550 
551   videorate = setup_videorate ();
552   fail_unless (gst_element_set_state (videorate,
553           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
554       "could not set to playing");
555   assert_videorate_stats (videorate, "start", 0, 0, 0, 0);
556 
557   /* first buffer */
558   first = gst_buffer_new_and_alloc (4);
559   GST_BUFFER_TIMESTAMP (first) = 0;
560   gst_buffer_memset (first, 0, 0, 4);
561   caps = gst_caps_from_string (VIDEO_CAPS_STRING);
562   gst_check_setup_events (mysrcpad, videorate, caps, GST_FORMAT_TIME);
563   gst_caps_unref (caps);
564   ASSERT_BUFFER_REFCOUNT (first, "first", 1);
565   gst_buffer_ref (first);
566 
567   GST_DEBUG ("pushing first buffer");
568   /* pushing gives away my reference ... */
569   fail_unless (gst_pad_push (mysrcpad, first) == GST_FLOW_OK);
570   /* ... and a copy is now stuck inside videorate */
571   ASSERT_BUFFER_REFCOUNT (first, "first", 1);
572   fail_unless_equals_int (g_list_length (buffers), 0);
573   assert_videorate_stats (videorate, "first", 1, 0, 0, 0);
574 
575   /* second buffer */
576   second = gst_buffer_new_and_alloc (4);
577   GST_BUFFER_TIMESTAMP (second) = GST_SECOND;
578   gst_buffer_memset (second, 0, 0, 4);
579   ASSERT_BUFFER_REFCOUNT (second, "second", 1);
580   gst_buffer_ref (second);
581 
582   /* pushing gives away my reference ... */
583   fail_unless (gst_pad_push (mysrcpad, second) == GST_FLOW_OK);
584   /* ... and a copy is now stuck inside videorate */
585   ASSERT_BUFFER_REFCOUNT (second, "second", 1);
586   /* and it created 13 output buffers as copies of the first frame */
587   fail_unless_equals_int (g_list_length (buffers), 13);
588   assert_videorate_stats (videorate, "second", 2, 13, 0, 12);
589   ASSERT_BUFFER_REFCOUNT (first, "first", 1);
590 
591   /* third buffer */
592   third = gst_buffer_new_and_alloc (4);
593   GST_BUFFER_TIMESTAMP (third) = 2 * GST_SECOND;
594   gst_buffer_memset (third, 0, 0, 4);
595   ASSERT_BUFFER_REFCOUNT (third, "third", 1);
596   gst_buffer_ref (third);
597 
598   /* pushing gives away my reference ... */
599   fail_unless (gst_pad_push (mysrcpad, third) == GST_FLOW_OK);
600   /* ... and a copy is now stuck inside videorate */
601   ASSERT_BUFFER_REFCOUNT (third, "third", 1);
602 
603   /* submitting a frame with 2 seconds triggers output of 25 more frames */
604   fail_unless_equals_int (g_list_length (buffers), 38);
605   ASSERT_BUFFER_REFCOUNT (first, "first", 1);
606   ASSERT_BUFFER_REFCOUNT (second, "second", 1);
607   /* three frames submitted; two of them output as is, and 36 duplicated */
608   assert_videorate_stats (videorate, "third", 3, 38, 0, 36);
609 
610   /* fourth buffer */
611   fourth = gst_buffer_new_and_alloc (4);
612   GST_BUFFER_TIMESTAMP (fourth) = 0;
613   gst_buffer_memset (fourth, 0, 0, 4);
614   ASSERT_BUFFER_REFCOUNT (fourth, "fourth", 1);
615   gst_buffer_ref (fourth);
616 
617   /* pushing gives away my reference ... */
618   fail_unless (gst_pad_push (mysrcpad, fourth) == GST_FLOW_OK);
619   /* ... and it is dropped */
620   ASSERT_BUFFER_REFCOUNT (fourth, "fourth", 1);
621 
622   fail_unless_equals_int (g_list_length (buffers), 38);
623   ASSERT_BUFFER_REFCOUNT (first, "first", 1);
624   ASSERT_BUFFER_REFCOUNT (second, "second", 1);
625   assert_videorate_stats (videorate, "fourth", 4, 38, 1, 36);
626 
627   /* verify last buffer */
628   outbuffer = g_list_last (buffers)->data;
629   fail_unless (GST_IS_BUFFER (outbuffer));
630   fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (outbuffer),
631       GST_SECOND * 37 / 25);
632 
633 
634   /* cleanup */
635   gst_buffer_unref (first);
636   gst_buffer_unref (second);
637   gst_buffer_unref (third);
638   gst_buffer_unref (fourth);
639   cleanup_videorate (videorate);
640 }
641 
642 GST_END_TEST;
643 
644 
645 /* if no framerate is negotiated, we should not be able to push a buffer */
GST_START_TEST(test_no_framerate)646 GST_START_TEST (test_no_framerate)
647 {
648   GstElement *videorate;
649   GstBuffer *inbuffer;
650   GstCaps *caps;
651 
652   videorate = setup_videorate ();
653   fail_unless (gst_element_set_state (videorate,
654           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
655       "could not set to playing");
656 
657   inbuffer = gst_buffer_new_and_alloc (4);
658   gst_buffer_memset (inbuffer, 0, 0, 4);
659   caps = gst_caps_from_string (VIDEO_CAPS_NO_FRAMERATE_STRING);
660   gst_check_setup_events (mysrcpad, videorate, caps, GST_FORMAT_TIME);
661   gst_caps_unref (caps);
662   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
663 
664   /* take a ref so we can later check refcount */
665   gst_buffer_ref (inbuffer);
666 
667   /* no framerate is negotiated so pushing should fail */
668   fail_if (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
669   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
670   gst_buffer_unref (inbuffer);
671   fail_unless_equals_int (g_list_length (buffers), 0);
672 
673   /* cleanup */
674   cleanup_videorate (videorate);
675 }
676 
677 GST_END_TEST;
678 
679 /* This test outputs 2 buffers of same dimensions (320x240), then 1 buffer of
680  * differing dimensions (240x120), and then another buffer of previous
681  * dimensions (320x240) and checks that the 3 buffers output as a result have
682  * correct caps (first 2 with 320x240 and 3rd with 240x120).
683  */
GST_START_TEST(test_changing_size)684 GST_START_TEST (test_changing_size)
685 {
686   GstElement *videorate;
687   GstBuffer *first;
688   GstBuffer *second;
689   GstBuffer *third;
690   GstBuffer *fourth;
691   GstBuffer *fifth;
692   GstBuffer *outbuf;
693   GstCaps *caps, *caps_newsize;
694 
695   videorate = setup_videorate ();
696   fail_unless (gst_element_set_state (videorate,
697           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
698       "could not set to playing");
699 
700   first = gst_buffer_new_and_alloc (4);
701   gst_buffer_memset (first, 0, 0, 4);
702   caps = gst_caps_from_string (VIDEO_CAPS_STRING);
703   GST_BUFFER_TIMESTAMP (first) = 0;
704   gst_check_setup_events (mysrcpad, videorate, caps, GST_FORMAT_TIME);
705 
706   GST_DEBUG ("pushing first buffer");
707   fail_unless (gst_pad_push (mysrcpad, first) == GST_FLOW_OK);
708 
709   /* second buffer */
710   second = gst_buffer_new_and_alloc (4);
711   GST_BUFFER_TIMESTAMP (second) = GST_SECOND / 25;
712   gst_buffer_memset (second, 0, 0, 4);
713 
714   fail_unless (gst_pad_push (mysrcpad, second) == GST_FLOW_OK);
715   fail_unless_equals_int (g_list_length (buffers), 1);
716   outbuf = buffers->data;
717   /* first buffer should be output here */
718   fail_unless (GST_BUFFER_TIMESTAMP (outbuf) == 0);
719 
720   /* third buffer with new size */
721   third = gst_buffer_new_and_alloc (4);
722   GST_BUFFER_TIMESTAMP (third) = 2 * GST_SECOND / 25;
723   gst_buffer_memset (third, 0, 0, 4);
724   caps_newsize = gst_caps_from_string (VIDEO_CAPS_NEWSIZE_STRING);
725   gst_pad_set_caps (mysrcpad, caps_newsize);
726 
727   fail_unless (gst_pad_push (mysrcpad, third) == GST_FLOW_OK);
728   /* new caps flushed the internal state, no new output yet */
729   fail_unless_equals_int (g_list_length (buffers), 1);
730   outbuf = g_list_last (buffers)->data;
731   /* first buffer should be output here */
732   //fail_unless (gst_caps_is_equal (GST_BUFFER_CAPS (outbuf), caps));
733   fail_unless (GST_BUFFER_TIMESTAMP (outbuf) == 0);
734 
735   /* fourth buffer with original size */
736   fourth = gst_buffer_new_and_alloc (4);
737   GST_BUFFER_TIMESTAMP (fourth) = 3 * GST_SECOND / 25;
738   gst_buffer_memset (fourth, 0, 0, 4);
739   gst_pad_set_caps (mysrcpad, caps);
740 
741   fail_unless (gst_pad_push (mysrcpad, fourth) == GST_FLOW_OK);
742   fail_unless_equals_int (g_list_length (buffers), 1);
743 
744   /* fifth buffer with original size */
745   fifth = gst_buffer_new_and_alloc (4);
746   GST_BUFFER_TIMESTAMP (fifth) = 4 * GST_SECOND / 25;
747   gst_buffer_memset (fifth, 0, 0, 4);
748 
749   fail_unless (gst_pad_push (mysrcpad, fifth) == GST_FLOW_OK);
750   /* all four missing buffers here, dups of fourth buffer */
751   fail_unless_equals_int (g_list_length (buffers), 4);
752   outbuf = g_list_last (buffers)->data;
753   /* third buffer should be output here */
754   fail_unless (GST_BUFFER_TIMESTAMP (outbuf) == 3 * GST_SECOND / 25);
755   //fail_unless (gst_caps_is_equal (GST_BUFFER_CAPS (outbuf), caps));
756 
757   gst_caps_unref (caps);
758   gst_caps_unref (caps_newsize);
759   cleanup_videorate (videorate);
760 }
761 
762 GST_END_TEST;
763 
GST_START_TEST(test_non_ok_flow)764 GST_START_TEST (test_non_ok_flow)
765 {
766   GstElement *videorate;
767   GstClockTime ts;
768   GstBuffer *buf;
769   GstCaps *caps;
770 
771   videorate = setup_videorate ();
772   fail_unless (gst_element_set_state (videorate,
773           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
774       "could not set to playing");
775 
776   buf = gst_buffer_new_and_alloc (4);
777   gst_buffer_memset (buf, 0, 0, 4);
778   caps = gst_caps_from_string (VIDEO_CAPS_STRING);
779   gst_check_setup_events (mysrcpad, videorate, caps, GST_FORMAT_TIME);
780   gst_caps_unref (caps);
781   ASSERT_BUFFER_REFCOUNT (buf, "inbuffer", 1);
782 
783   /* push a few 'normal' buffers */
784   for (ts = 0; ts < 100 * GST_SECOND; ts += GST_SECOND / 33) {
785     GstBuffer *inbuf;
786 
787     inbuf = gst_buffer_copy (buf);
788     GST_BUFFER_TIMESTAMP (inbuf) = ts;
789 
790     fail_unless_equals_int (gst_pad_push (mysrcpad, inbuf), GST_FLOW_OK);
791   }
792 
793   /* we should have buffers according to the output framerate of 25/1 */
794   fail_unless_equals_int (g_list_length (buffers), 100 * 25);
795 
796   /* now deactivate pad so we get a WRONG_STATE flow return */
797   gst_pad_set_active (mysinkpad, FALSE);
798 
799   /* push buffer on deactivated pad */
800   fail_unless (gst_buffer_is_writable (buf));
801   GST_BUFFER_TIMESTAMP (buf) = ts;
802 
803   /* pushing gives away our reference */
804   fail_unless_equals_int (gst_pad_push (mysrcpad, buf), GST_FLOW_FLUSHING);
805 
806   /* cleanup */
807   cleanup_videorate (videorate);
808 }
809 
810 GST_END_TEST;
811 
GST_START_TEST(test_upstream_caps_nego)812 GST_START_TEST (test_upstream_caps_nego)
813 {
814   GstElement *videorate;
815   GstPad *videorate_pad;
816   GstCaps *expected_caps;
817   GstCaps *caps;
818   GstStructure *structure;
819 
820   videorate = setup_videorate_full (&srctemplate, &downstreamsinktemplate);
821   fail_unless (gst_element_set_state (videorate,
822           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
823       "could not set to playing");
824 
825   videorate_pad = gst_element_get_static_pad (videorate, "sink");
826   caps = gst_pad_query_caps (videorate_pad, NULL);
827 
828   /* assemble the expected caps */
829   structure = gst_structure_from_string (VIDEO_CAPS_STRING, NULL);
830   expected_caps = gst_caps_new_empty ();
831   gst_caps_append_structure (expected_caps, structure);
832   structure = gst_structure_copy (structure);
833   gst_structure_set (structure, "framerate", GST_TYPE_FRACTION_RANGE,
834       0, 1, G_MAXINT, 1, NULL);
835   gst_caps_append_structure (expected_caps, structure);
836 
837   fail_unless (gst_caps_is_equal (expected_caps, caps));
838   gst_caps_unref (caps);
839   gst_caps_unref (expected_caps);
840   gst_object_unref (videorate_pad);
841 
842   /* cleanup */
843   cleanup_videorate (videorate);
844 }
845 
846 GST_END_TEST;
847 
848 
GST_START_TEST(test_selected_caps)849 GST_START_TEST (test_selected_caps)
850 {
851   GstElement *videorate;
852   GstElement *pipeline;
853   GstBus *bus;
854   GstMessage *msg;
855 
856   pipeline = gst_parse_launch ("videotestsrc num-buffers=1"
857       " ! identity ! videorate name=videorate0 ! " VIDEO_CAPS_UNUSUAL_FRAMERATE
858       " ! fakesink", NULL);
859   fail_if (pipeline == NULL);
860   videorate = gst_bin_get_by_name (GST_BIN (pipeline), "videorate0");
861   fail_if (videorate == NULL);
862   bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
863 
864   fail_if (gst_element_set_state (pipeline,
865           GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE,
866       "could not set to playing");
867 
868   msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
869       GST_MESSAGE_EOS | GST_MESSAGE_ERROR);
870   fail_if (msg == NULL || GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR);
871 
872   /* make sure upstream nego works right and videotestsrc has selected the
873    * caps we want downstream of videorate */
874   {
875     GstStructure *s;
876     const GValue *val;
877     GstCaps *caps = NULL;
878     GstPad *videorate_pad;
879 
880     videorate_pad = gst_element_get_static_pad (videorate, "sink");
881     g_object_get (videorate_pad, "caps", &caps, NULL);
882     fail_unless (caps != NULL);
883 
884     GST_DEBUG ("negotiated caps: %" GST_PTR_FORMAT, caps);
885 
886     s = gst_caps_get_structure (caps, 0);
887     val = gst_structure_get_value (s, "framerate");
888     fail_unless (val != NULL, "no framerate field in negotiated caps");
889     fail_unless (GST_VALUE_HOLDS_FRACTION (val));
890     fail_unless_equals_int (gst_value_get_fraction_numerator (val), 999);
891     fail_unless_equals_int (gst_value_get_fraction_denominator (val), 7);
892 
893     gst_caps_unref (caps);
894     gst_object_unref (videorate_pad);
895   }
896 
897   /* cleanup */
898   gst_object_unref (bus);
899   gst_message_unref (msg);
900   gst_element_set_state (pipeline, GST_STATE_NULL);
901   gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
902   gst_object_unref (videorate);
903   gst_object_unref (pipeline);
904 }
905 
906 GST_END_TEST;
907 
908 
909 /* Caps negotiation tests */
910 typedef struct
911 {
912   const gchar *caps;
913   gboolean drop_only;
914   int max_rate;
915   /* Result of the videomaxrate caps after transforming */
916   const gchar *expected_sink_caps;
917   const gchar *expected_src_caps;
918 } TestInfo;
919 
920 static TestInfo caps_negotiation_tests[] = {
921   {
922         .caps = "video/x-raw",
923         .drop_only = FALSE,
924         .expected_sink_caps = "video/x-raw",
925       .expected_src_caps = "video/x-raw, framerate=(fraction)[0/1, MAX]"},
926   {
927         .caps = "video/x-raw",
928         .drop_only = FALSE,
929         .max_rate = 15,
930         .expected_sink_caps = "video/x-raw",
931       .expected_src_caps = "video/x-raw, framerate=(fraction)[0/1, 15]"},
932   {
933         .caps = "video/x-raw",
934         .drop_only = TRUE,
935         .expected_sink_caps = "video/x-raw, framerate=(fraction)[0/1, MAX]",
936       .expected_src_caps = "video/x-raw, framerate=(fraction)[0/1, MAX]"},
937   {
938         .caps = "video/x-raw",
939         .drop_only = TRUE,
940         .max_rate = 15,
941         .expected_sink_caps =
942         "video/x-raw, framerate=(fraction)[0/1, 15];"
943         "video/x-raw, framerate=(fraction)[0/1, MAX]",
944       .expected_src_caps = "video/x-raw, framerate=(fraction)[0/1, 15]"},
945 
946 
947   {
948         .caps = "video/x-raw, framerate=(fraction)[0/1, MAX]",
949         .drop_only = FALSE,
950         .expected_sink_caps = "video/x-raw, framerate=(fraction)[0/1, MAX]",
951       .expected_src_caps = "video/x-raw, framerate=(fraction)[0/1, MAX]"},
952   {
953         .caps = "video/x-raw, framerate=(fraction)[0/1, MAX]",
954         .drop_only = FALSE,
955         .max_rate = 15,
956         .expected_sink_caps = "video/x-raw, framerate=(fraction)[0/1, MAX]",
957       .expected_src_caps = "video/x-raw, framerate=(fraction)[0/1, 15]"},
958   {
959         .caps = "video/x-raw, framerate=(fraction)[0/1, MAX]",
960         .drop_only = TRUE,
961         .expected_sink_caps = "video/x-raw, framerate=(fraction)[0/1, MAX]",
962       .expected_src_caps = "video/x-raw, framerate=(fraction)[0/1, MAX]"},
963   {
964         .caps = "video/x-raw, framerate=(fraction)[0/1, MAX]",
965         .drop_only = TRUE,
966         .max_rate = 15,
967         .expected_sink_caps =
968         "video/x-raw, framerate=(fraction)[0/1, 15];"
969         "video/x-raw, framerate=(fraction)[0/1, MAX]",
970       .expected_src_caps = "video/x-raw, framerate=(fraction)[0/1, 15]"},
971   {
972         .caps = "video/x-raw, framerate=15/1",
973         .drop_only = FALSE,
974         .expected_sink_caps =
975         "video/x-raw, framerate=(fraction)15/1;"
976         "video/x-raw, framerate=(fraction)[0/1, MAX]",
977       .expected_src_caps =
978         "video/x-raw, framerate=(fraction)15/1;"
979         "video/x-raw, framerate=(fraction)[0/1, MAX]"},
980   {
981         .caps = "video/x-raw, framerate=15/1",
982         .drop_only = FALSE,
983         .max_rate = 20,
984         .expected_sink_caps =
985         "video/x-raw, framerate=(fraction)15/1;"
986         "video/x-raw, framerate=(fraction)[0/1, MAX]",
987       .expected_src_caps =
988         "video/x-raw, framerate=(fraction)15/1;"
989         "video/x-raw, framerate=(fraction)[0/1, 20/1]"},
990   {
991         .caps = "video/x-raw, framerate=15/1",
992         .drop_only = TRUE,
993         .expected_sink_caps =
994         "video/x-raw, framerate=(fraction)15/1;"
995         "video/x-raw, framerate=(fraction)[15/1, MAX];"
996         "video/x-raw, framerate=(fraction)0/1",
997       .expected_src_caps =
998         "video/x-raw, framerate=(fraction)15/1;"
999         "video/x-raw, framerate=(fraction)[0/1, 15/1]"},
1000   {
1001         .caps = "video/x-raw, framerate=15/1",
1002         .drop_only = TRUE,
1003         .max_rate = 20,
1004         .expected_sink_caps =
1005         "video/x-raw, framerate=(fraction)15/1;"
1006         "video/x-raw, framerate=(fraction)[15/1, MAX];"
1007         "video/x-raw, framerate=(fraction)0/1",
1008       .expected_src_caps =
1009         "video/x-raw, framerate=(fraction)15/1;"
1010         "video/x-raw, framerate=(fraction)[0/1, 15/1];"},
1011   {
1012         .caps = "video/x-raw, framerate=[15/1, 30/1]",
1013         .drop_only = FALSE,
1014         .expected_sink_caps =
1015         "video/x-raw, framerate=(fraction)[15/1, 30/1];"
1016         "video/x-raw, framerate=(fraction)[0/1, MAX];",
1017       .expected_src_caps =
1018         "video/x-raw, framerate=(fraction)[15/1, 30/1];"
1019         "video/x-raw, framerate=(fraction)[0/1, MAX];"},
1020   {
1021         .caps = "video/x-raw, framerate=[15/1, 30/1]",
1022         .drop_only = FALSE,
1023         .max_rate = 20,
1024         .expected_sink_caps =
1025         "video/x-raw, framerate=(fraction)[15/1, 30/1];"
1026         "video/x-raw, framerate=(fraction)[0/1, MAX];",
1027       .expected_src_caps =
1028         "video/x-raw, framerate=(fraction)[15/1, 20/1];"
1029         "video/x-raw, framerate=(fraction)[0/1, 20/1];"},
1030   {
1031         .caps = "video/x-raw, framerate=[15/1, 30/1]",
1032         .drop_only = TRUE,
1033         .expected_sink_caps =
1034         "video/x-raw, framerate=(fraction)[15/1, 30/1];"
1035         "video/x-raw, framerate=(fraction)[15/1, MAX];"
1036         "video/x-raw, framerate=(fraction)0/1",
1037       .expected_src_caps =
1038         "video/x-raw, framerate=(fraction)[15/1, 30/1];"
1039         "video/x-raw, framerate=(fraction)[0/1, 30/1]"},
1040   {
1041         .caps = "video/x-raw, framerate=[15/1, 30/1]",
1042         .drop_only = TRUE,
1043         .max_rate = 20,
1044         .expected_sink_caps =
1045         "video/x-raw, framerate=(fraction)[15/1, 20/1];"
1046         "video/x-raw, framerate=(fraction)[15/1, 30/1];"
1047         "video/x-raw, framerate=(fraction)[15/1, MAX];"
1048         "video/x-raw, framerate=(fraction)0/1",
1049       .expected_src_caps =
1050         "video/x-raw, framerate=(fraction)[15/1, 20/1];"
1051         "video/x-raw, framerate=(fraction)[0/1, 20/1]"},
1052   {
1053         .caps = "video/x-raw, framerate={15/1, 30/1}",
1054         .drop_only = FALSE,
1055         .expected_sink_caps =
1056         "video/x-raw, framerate=(fraction){15/1, 30/1};"
1057         "video/x-raw, framerate=(fraction)[0/1, MAX];",
1058       .expected_src_caps =
1059         "video/x-raw, framerate=(fraction){15/1, 30/1};"
1060         "video/x-raw, framerate=(fraction)[0/1, MAX]"},
1061   {
1062         .caps = "video/x-raw, framerate={15/1, 30/1}",
1063         .drop_only = FALSE,
1064         .max_rate = 20,
1065         .expected_sink_caps =
1066         "video/x-raw, framerate=(fraction){15/1, 30/1};"
1067         "video/x-raw, framerate=(fraction)[0/1, MAX];",
1068       .expected_src_caps =
1069         "video/x-raw, framerate=(fraction)15/1;"
1070         "video/x-raw, framerate=(fraction)[0/1, 20/1];"},
1071   {
1072         .caps = "video/x-raw, framerate={15/1, 30/1}",
1073         .drop_only = TRUE,
1074         .expected_sink_caps =
1075         "video/x-raw, framerate=(fraction){15/1, 30/1};"
1076         "video/x-raw, framerate=(fraction)[15/1, MAX];"
1077         "video/x-raw, framerate=(fraction)0/1",
1078       .expected_src_caps =
1079         "video/x-raw, framerate=(fraction){15/1, 30/1};"
1080         "video/x-raw, framerate=(fraction)[0/1, 30/1];"},
1081   {
1082         .caps = "video/x-raw, framerate={15/1, 30/1}",
1083         .drop_only = TRUE,
1084         .max_rate = 20,
1085         .expected_sink_caps =
1086         "video/x-raw, framerate=(fraction)15/1;"
1087         "video/x-raw, framerate=(fraction){15/1, 30/1};"
1088         "video/x-raw, framerate=(fraction)[15/1, MAX];"
1089         "video/x-raw, framerate=(fraction)0/1",
1090       .expected_src_caps =
1091         "video/x-raw, framerate=(fraction)15/1;"
1092         "video/x-raw, framerate=(fraction)[0/1, 20/1]"},
1093 };
1094 
1095 static gboolean
_query_function(GstPad * pad,GstObject * parent,GstQuery * query)1096 _query_function (GstPad * pad, GstObject * parent, GstQuery * query)
1097 {
1098   gboolean res;
1099 
1100   switch (GST_QUERY_TYPE (query)) {
1101     case GST_QUERY_CAPS:{
1102       GstCaps *caps = g_object_get_data (G_OBJECT (pad), "caps");
1103 
1104       fail_unless (caps != NULL);
1105 
1106       gst_query_set_caps_result (query, caps);
1107       res = TRUE;
1108       break;
1109     }
1110     default:
1111       res = gst_pad_query_default (pad, parent, query);
1112       break;
1113   }
1114   return res;
1115 }
1116 
1117 static void
check_caps_identical(GstCaps * a,GstCaps * b,const char * name)1118 check_caps_identical (GstCaps * a, GstCaps * b, const char *name)
1119 {
1120   int i;
1121   gchar *caps_str_a;
1122   gchar *caps_str_b;
1123 
1124   if (gst_caps_get_size (a) != gst_caps_get_size (b))
1125     goto fail;
1126 
1127   for (i = 0; i < gst_caps_get_size (a); i++) {
1128     GstStructure *sa, *sb;
1129 
1130     sa = gst_caps_get_structure (a, i);
1131     sb = gst_caps_get_structure (b, i);
1132 
1133     if (!gst_structure_is_equal (sa, sb))
1134       goto fail;
1135   }
1136 
1137   return;
1138 
1139 fail:
1140   caps_str_a = gst_caps_to_string (a);
1141   caps_str_b = gst_caps_to_string (b);
1142   fail ("%s caps (%s) is not equal to caps (%s)", name, caps_str_a, caps_str_b);
1143   g_free (caps_str_a);
1144   g_free (caps_str_b);
1145 }
1146 
1147 static void
check_peer_caps(GstPad * pad,const char * expected,const char * name)1148 check_peer_caps (GstPad * pad, const char *expected, const char *name)
1149 {
1150   GstCaps *caps;
1151   GstCaps *expected_caps;
1152 
1153   caps = gst_pad_peer_query_caps (pad, NULL);
1154   fail_unless (caps != NULL);
1155 
1156   expected_caps = gst_caps_from_string (expected);
1157   fail_unless (expected_caps != NULL);
1158 
1159   check_caps_identical (caps, expected_caps, name);
1160 
1161   gst_caps_unref (caps);
1162   gst_caps_unref (expected_caps);
1163 }
1164 
GST_START_TEST(test_caps_negotiation)1165 GST_START_TEST (test_caps_negotiation)
1166 {
1167   GstElement *videorate;
1168   GstCaps *caps;
1169   TestInfo *test = &caps_negotiation_tests[__i__];
1170 
1171   videorate = setup_videorate_full (&srctemplate, &sinktemplate);
1172 
1173   caps = gst_caps_from_string (test->caps);
1174 
1175   g_object_set_data_full (G_OBJECT (mysrcpad), "caps",
1176       gst_caps_ref (caps), (GDestroyNotify) gst_caps_unref);
1177 
1178   g_object_set_data_full (G_OBJECT (mysinkpad), "caps",
1179       gst_caps_ref (caps), (GDestroyNotify) gst_caps_unref);
1180   gst_caps_unref (caps);
1181 
1182   g_object_set (videorate, "drop-only", test->drop_only, NULL);
1183   if (test->max_rate != 0)
1184     g_object_set (videorate, "max-rate", test->max_rate, NULL);
1185 
1186   gst_pad_set_query_function (mysrcpad, _query_function);
1187   gst_pad_set_query_function (mysinkpad, _query_function);
1188 
1189   check_peer_caps (mysrcpad, test->expected_sink_caps, "sink");
1190   check_peer_caps (mysinkpad, test->expected_src_caps, "src");
1191 
1192   cleanup_videorate (videorate);
1193 }
1194 
1195 GST_END_TEST;
1196 
1197 static void
videorate_send_buffers(GstElement * videorate,const gchar * pre_push_caps,const gchar * post_push_caps)1198 videorate_send_buffers (GstElement * videorate,
1199     const gchar * pre_push_caps, const gchar * post_push_caps)
1200 {
1201   GstCaps *caps, *expected_caps;
1202   GstBuffer *first;
1203   GstBuffer *second;
1204   GstBuffer *third;
1205 
1206   caps = gst_pad_get_current_caps (mysinkpad);
1207   expected_caps = gst_caps_from_string (pre_push_caps);
1208   gst_check_caps_equal (caps, expected_caps);
1209   gst_caps_unref (caps);
1210   gst_caps_unref (expected_caps);
1211 
1212   GST_DEBUG ("pushing first buffer");
1213   first = gst_buffer_new_and_alloc (4);
1214   gst_buffer_memset (first, 0, 0, 4);
1215   GST_BUFFER_TIMESTAMP (first) = 0;
1216   fail_unless (gst_pad_push (mysrcpad, first) == GST_FLOW_OK);
1217 
1218   /* second buffer */
1219   second = gst_buffer_new_and_alloc (4);
1220   GST_BUFFER_TIMESTAMP (second) = GST_SECOND / 25;
1221   gst_buffer_memset (second, 0, 0, 4);
1222 
1223   fail_unless (gst_pad_push (mysrcpad, second) == GST_FLOW_OK);
1224 
1225   /* third buffer with new size */
1226   third = gst_buffer_new_and_alloc (4);
1227   GST_BUFFER_TIMESTAMP (third) = 2 * GST_SECOND / 25;
1228   gst_buffer_memset (third, 0, 0, 4);
1229 
1230   fail_unless (gst_pad_push (mysrcpad, third) == GST_FLOW_OK);
1231 
1232   caps = gst_pad_get_current_caps (mysinkpad);
1233   expected_caps = gst_caps_from_string (post_push_caps);
1234   gst_check_caps_equal (caps, expected_caps);
1235   gst_caps_unref (caps);
1236   gst_caps_unref (expected_caps);
1237 
1238 }
1239 
GST_START_TEST(test_fixed_framerate)1240 GST_START_TEST (test_fixed_framerate)
1241 {
1242   GstElement *videorate;
1243   GstCaps *caps;
1244 
1245   /* 1) if upstream caps contain a non-0/1 framerate, we should use that and pass
1246    *    it on downstream (if possible; otherwise fixate_to_nearest)
1247    */
1248   videorate = setup_videorate_full (&srctemplate, &sinktemplate);
1249 
1250   caps = gst_caps_from_string ("video/x-raw,framerate=25/1");
1251   ASSERT_SET_STATE (videorate, GST_STATE_PLAYING, GST_STATE_CHANGE_SUCCESS);
1252   gst_check_setup_events (mysrcpad, videorate, caps, GST_FORMAT_TIME);
1253   gst_caps_unref (caps);
1254   videorate_send_buffers (videorate, "video/x-raw,framerate=25/1",
1255       "video/x-raw,framerate=25/1");
1256   cleanup_videorate (videorate);
1257 
1258   /* 2) if upstream framerate is 0/1 and downstream doesn't force a particular
1259    *    framerate, we try to guess based on buffer intervals and use that as output
1260    *    framerate */
1261   videorate = setup_videorate_full (&srctemplate, &sinktemplate);
1262   ASSERT_SET_STATE (videorate, GST_STATE_PLAYING, GST_STATE_CHANGE_SUCCESS);
1263   caps = gst_caps_from_string ("video/x-raw,framerate=0/1");
1264   gst_check_setup_events (mysrcpad, videorate, caps, GST_FORMAT_TIME);
1265   gst_caps_unref (caps);
1266   videorate_send_buffers (videorate, "video/x-raw,framerate=0/1",
1267       "video/x-raw,framerate=25/1");
1268   cleanup_videorate (videorate);
1269 
1270   /* 3) if downstream force variable framerate, do that */
1271   videorate =
1272       setup_videorate_full (&srctemplate, &force_variable_rate_template);
1273   ASSERT_SET_STATE (videorate, GST_STATE_PLAYING, GST_STATE_CHANGE_SUCCESS);
1274   caps = gst_caps_from_string ("video/x-raw,framerate=0/1");
1275   gst_check_setup_events (mysrcpad, videorate, caps, GST_FORMAT_TIME);
1276   gst_caps_unref (caps);
1277   videorate_send_buffers (videorate, "video/x-raw,framerate=0/1",
1278       "video/x-raw,framerate=0/1");
1279   cleanup_videorate (videorate);
1280 
1281 }
1282 
1283 GST_END_TEST;
1284 
GST_START_TEST(test_variable_framerate_renegotiation)1285 GST_START_TEST (test_variable_framerate_renegotiation)
1286 {
1287   GstElement *videorate;
1288   GstCaps *caps;
1289   GstCaps *allowed;
1290 
1291   videorate = setup_videorate_full (&srctemplate, &sinktemplate);
1292   ASSERT_SET_STATE (videorate, GST_STATE_PLAYING, GST_STATE_CHANGE_SUCCESS);
1293   caps = gst_caps_from_string ("video/x-raw,framerate=0/1");
1294   gst_check_setup_events (mysrcpad, videorate, caps, GST_FORMAT_TIME);
1295   videorate_send_buffers (videorate, "video/x-raw,framerate=0/1",
1296       "video/x-raw,framerate=25/1");
1297 
1298   /* framerate=0/1 must still be allowed to be configured on
1299    * the upstream side of videorate */
1300   allowed = gst_pad_get_allowed_caps (mysrcpad);
1301   fail_unless (gst_caps_is_subset (caps, allowed) == TRUE);
1302 
1303   gst_caps_unref (allowed);
1304   gst_caps_unref (caps);
1305   cleanup_videorate (videorate);
1306 }
1307 
1308 GST_END_TEST;
1309 
1310 /* Rate tests info */
1311 typedef struct
1312 {
1313   gdouble rate;
1314   guint64 expected_in, expected_out, expected_drop, expected_dup;
1315   gint current_buf;
1316   GstClockTime expected_ts;
1317 } RateInfo;
1318 
1319 static RateInfo rate_tests[] = {
1320   {
1321         .rate = 1.0,
1322         .expected_in = 34,
1323         .expected_out = 25,
1324         .expected_drop = 8,
1325         .expected_dup = 0,
1326         .current_buf = 0,
1327       .expected_ts = 0},
1328   {
1329         .rate = 0.5,
1330         .expected_in = 34,
1331         .expected_out = 50,
1332         .expected_drop = 0,
1333         .expected_dup = 17,
1334         .current_buf = 0,
1335       .expected_ts = 0},
1336   {
1337         .rate = 2.0,
1338         .expected_in = 34,
1339         .expected_out = 13,
1340         .expected_drop = 20,
1341         .expected_dup = 0,
1342         .current_buf = 0,
1343       .expected_ts = 0},
1344 };
1345 
1346 static GstPadProbeReturn
listen_outbuffer_ts(GstPad * pad,GstPadProbeInfo * info,gpointer user_data)1347 listen_outbuffer_ts (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
1348 {
1349   GstBuffer *buffer;
1350   guint64 buf_ts;
1351   RateInfo *test = (RateInfo *) user_data;
1352 
1353   buffer = GST_PAD_PROBE_INFO_BUFFER (info);
1354   buf_ts = GST_BUFFER_TIMESTAMP (buffer);
1355 
1356   GST_DEBUG ("Probed %d outbuf. ts : %" GST_TIME_FORMAT
1357       ", expected : %" GST_TIME_FORMAT, test->current_buf,
1358       GST_TIME_ARGS (buf_ts), GST_TIME_ARGS (test->expected_ts));
1359   fail_unless_equals_uint64 (buf_ts, test->expected_ts);
1360 
1361   /* Next expected timestamp with fps 25/1 */
1362   test->expected_ts += 40000000;
1363   test->current_buf += 1;
1364 
1365   fail_if (test->current_buf > test->expected_out);
1366 
1367   return GST_PAD_PROBE_OK;
1368 }
1369 
GST_START_TEST(test_rate)1370 GST_START_TEST (test_rate)
1371 {
1372   GstElement *videorate;
1373   RateInfo *test = &rate_tests[__i__];
1374   GstClockTime ts;
1375   GstBuffer *buf;
1376   GstCaps *caps;
1377   gulong probe;
1378 
1379   videorate = setup_videorate ();
1380   fail_unless (gst_element_set_state (videorate,
1381           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1382       "could not set to playing");
1383   probe = gst_pad_add_probe (mysinkpad, GST_PAD_PROBE_TYPE_BUFFER,
1384       (GstPadProbeCallback) listen_outbuffer_ts, test, NULL);
1385 
1386   buf = gst_buffer_new_and_alloc (4);
1387   gst_buffer_memset (buf, 0, 0, 4);
1388   caps = gst_caps_from_string (VIDEO_CAPS_STRING);
1389   gst_check_setup_events (mysrcpad, videorate, caps, GST_FORMAT_TIME);
1390   gst_caps_unref (caps);
1391   ASSERT_BUFFER_REFCOUNT (buf, "inbuffer", 1);
1392 
1393   /* Setting rate */
1394   g_object_set (videorate, "rate", test->rate, NULL);
1395 
1396   /* Push 1 second of buffers */
1397   for (ts = 0; ts < 1 * GST_SECOND; ts += GST_SECOND / 33) {
1398     GstBuffer *inbuf;
1399 
1400     inbuf = gst_buffer_copy (buf);
1401     GST_BUFFER_TIMESTAMP (inbuf) = ts;
1402 
1403     fail_unless_equals_int (gst_pad_push (mysrcpad, inbuf), GST_FLOW_OK);
1404   }
1405 
1406   fail_unless_equals_int (g_list_length (buffers), test->expected_out);
1407   assert_videorate_stats (videorate, "last buffer", test->expected_in,
1408       test->expected_out, test->expected_drop, test->expected_dup);
1409 
1410   /* cleanup */
1411   gst_pad_remove_probe (mysinkpad, probe);
1412   cleanup_videorate (videorate);
1413   gst_buffer_unref (buf);
1414 }
1415 
1416 GST_END_TEST;
1417 
1418 /* Probing the pad to force a fake upstream duration */
1419 static GstPadProbeReturn
listen_sink_query_duration(GstPad * pad,GstPadProbeInfo * info,gpointer user_data)1420 listen_sink_query_duration (GstPad * pad, GstPadProbeInfo * info,
1421     gpointer user_data)
1422 {
1423   GstQuery *query;
1424   gint64 *duration = (gint64 *) user_data;
1425 
1426   query = gst_pad_probe_info_get_query (info);
1427 
1428   if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
1429     gst_query_set_duration (query, GST_FORMAT_TIME, *duration);
1430     return GST_PAD_PROBE_HANDLED;
1431   }
1432   return GST_PAD_PROBE_OK;
1433 }
1434 
GST_START_TEST(test_query_duration)1435 GST_START_TEST (test_query_duration)
1436 {
1437   GstElement *videorate;
1438   gulong probe_sink;
1439   gint64 duration;
1440   GstQuery *query;
1441 
1442   videorate = setup_videorate ();
1443   fail_unless (gst_element_set_state (videorate,
1444           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1445       "could not set to playing");
1446   probe_sink =
1447       gst_pad_add_probe (mysrcpad,
1448       GST_PAD_PROBE_TYPE_QUERY_UPSTREAM,
1449       (GstPadProbeCallback) listen_sink_query_duration, &duration, NULL);
1450 
1451   query = gst_query_new_duration (GST_FORMAT_TIME);
1452   duration = GST_CLOCK_TIME_NONE;
1453   gst_pad_peer_query (mysinkpad, query);
1454   gst_query_parse_duration (query, NULL, &duration);
1455   fail_unless_equals_uint64 (duration, GST_CLOCK_TIME_NONE);
1456 
1457   /* Setting fake upstream duration to 1 second */
1458   duration = GST_SECOND;
1459 
1460   /* Setting rate to 2.0 */
1461   g_object_set (videorate, "rate", 2.0, NULL);
1462 
1463   gst_pad_peer_query (mysinkpad, query);
1464   gst_query_parse_duration (query, NULL, &duration);
1465   fail_unless_equals_uint64 (duration, 0.5 * GST_SECOND);
1466 
1467   /* cleanup */
1468   gst_query_unref (query);
1469   gst_pad_remove_probe (mysrcpad, probe_sink);
1470   cleanup_videorate (videorate);
1471 }
1472 
1473 GST_END_TEST;
1474 
1475 /* Position tests info */
1476 typedef struct
1477 {
1478   gdouble rate;
1479 } PositionInfo;
1480 
1481 static PositionInfo position_tests[] = {
1482   {
1483       .rate = 1.0},
1484   {
1485       .rate = 0.5},
1486   {
1487       .rate = 2.0},
1488   {
1489       .rate = 1.7},
1490 };
1491 
GST_START_TEST(test_query_position)1492 GST_START_TEST (test_query_position)
1493 {
1494   GstElement *videorate;
1495   PositionInfo *test = &position_tests[__i__];
1496   GstClockTime ts;
1497   GstBuffer *buf;
1498   GstCaps *caps;
1499   gint64 position, expected_position = 0;
1500 
1501   videorate = setup_videorate ();
1502   fail_unless (gst_element_set_state (videorate,
1503           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1504       "could not set to playing");
1505 
1506   buf = gst_buffer_new_and_alloc (4);
1507   gst_buffer_memset (buf, 0, 0, 4);
1508   caps = gst_caps_from_string (VIDEO_CAPS_STRING);
1509   gst_check_setup_events (mysrcpad, videorate, caps, GST_FORMAT_TIME);
1510   gst_caps_unref (caps);
1511   ASSERT_BUFFER_REFCOUNT (buf, "inbuffer", 1);
1512 
1513   /* Push a few buffers */
1514   g_object_set (videorate, "rate", test->rate, NULL);
1515   for (ts = 0; ts < GST_SECOND; ts += GST_SECOND / 20) {
1516     GstBuffer *inbuf;
1517 
1518     inbuf = gst_buffer_copy (buf);
1519     GST_BUFFER_TIMESTAMP (inbuf) = ts;
1520 
1521     fail_unless_equals_int (gst_pad_push (mysrcpad, inbuf), GST_FLOW_OK);
1522 
1523     expected_position = ts / test->rate;
1524     gst_element_query_position (videorate, GST_FORMAT_TIME, &position);
1525     GST_DEBUG_OBJECT (NULL,
1526         "pushed buffer %" GST_TIME_FORMAT ", queried pos: %" GST_TIME_FORMAT
1527         ", expected pos: %" GST_TIME_FORMAT, GST_TIME_ARGS (ts),
1528         GST_TIME_ARGS (position), GST_TIME_ARGS (expected_position));
1529     fail_unless_equals_uint64 (position, expected_position);
1530   }
1531 
1532   /* cleanup */
1533   cleanup_videorate (videorate);
1534   gst_buffer_unref (buf);
1535 }
1536 
1537 GST_END_TEST;
1538 
1539 static Suite *
videorate_suite(void)1540 videorate_suite (void)
1541 {
1542   Suite *s = suite_create ("videorate");
1543   TCase *tc_chain = tcase_create ("general");
1544 
1545   suite_add_tcase (s, tc_chain);
1546   tcase_add_test (tc_chain, test_one);
1547   tcase_add_test (tc_chain, test_more);
1548   tcase_add_test (tc_chain, test_wrong_order_from_zero);
1549   tcase_add_test (tc_chain, test_wrong_order);
1550   tcase_add_test (tc_chain, test_no_framerate);
1551   tcase_add_test (tc_chain, test_changing_size);
1552   tcase_add_test (tc_chain, test_non_ok_flow);
1553   tcase_add_test (tc_chain, test_upstream_caps_nego);
1554   tcase_add_test (tc_chain, test_selected_caps);
1555   tcase_add_loop_test (tc_chain, test_caps_negotiation,
1556       0, G_N_ELEMENTS (caps_negotiation_tests));
1557   tcase_add_test (tc_chain, test_fixed_framerate);
1558   tcase_add_test (tc_chain, test_variable_framerate_renegotiation);
1559   tcase_add_loop_test (tc_chain, test_rate, 0, G_N_ELEMENTS (rate_tests));
1560   tcase_add_test (tc_chain, test_query_duration);
1561   tcase_add_test (tc_chain, test_max_duplication_time);
1562   tcase_add_loop_test (tc_chain, test_query_position, 0,
1563       G_N_ELEMENTS (position_tests));
1564 
1565   return s;
1566 }
1567 
1568 GST_CHECK_MAIN (videorate)
1569