1 /* GStreamer unit test for avwait
2  *
3  * Copyright (C) 2018 Vivia Nikolaidou <vivia@toolsonair.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24 
25 #include <gst/check/gstcheck.h>
26 #include <gst/audio/audio.h>
27 #include <gst/video/video.h>
28 
29 typedef enum _SwitchType
30 {
31   DO_NOT_SWITCH = -1,
32   SWITCH_FALSE = 0,
33   SWITCH_TRUE = 1
34 } SwitchType;
35 
36 static guint audio_buffer_count, video_buffer_count;
37 static SwitchType switch_after_2s;
38 static GstVideoTimeCode *target_tc;
39 static GstVideoTimeCode *end_tc;
40 static GstClockTime target_running_time;
41 static gboolean recording;
42 static gint mode;
43 static gboolean audio_late;
44 
45 static GstAudioInfo ainfo;
46 
47 static guint n_abuffers, n_vbuffers;
48 static GstClockTime first_audio_timestamp, last_audio_timestamp;
49 static GstClockTime first_video_timestamp, last_video_timestamp;
50 
51 typedef struct _ElementPadAndSwitchType
52 {
53   GstElement *element;
54   GstPad *pad;
55   SwitchType switch_after_2s;
56 } ElementPadAndSwitchType;
57 
58 typedef struct _PadAndBoolean
59 {
60   GstPad *pad;
61   gboolean b;
62 } PadAndBoolean;
63 
64 static void
set_default_params(void)65 set_default_params (void)
66 {
67   n_abuffers = 16;
68   n_vbuffers = 160;
69   switch_after_2s = DO_NOT_SWITCH;
70   target_tc = NULL;
71   end_tc = NULL;
72   target_running_time = GST_CLOCK_TIME_NONE;
73   recording = TRUE;
74   mode = 2;
75   audio_late = FALSE;
76 
77   first_audio_timestamp = GST_CLOCK_TIME_NONE;
78   last_audio_timestamp = GST_CLOCK_TIME_NONE;
79   first_video_timestamp = GST_CLOCK_TIME_NONE;
80   last_video_timestamp = GST_CLOCK_TIME_NONE;
81 };
82 
83 static GstFlowReturn
output_achain(GstPad * pad,GstObject * parent,GstBuffer * buffer)84 output_achain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
85 {
86   GstClockTime timestamp, duration;
87 
88   timestamp = GST_BUFFER_TIMESTAMP (buffer);
89 
90   duration =
91       gst_util_uint64_scale (gst_buffer_get_size (buffer) / ainfo.bpf,
92       GST_SECOND, ainfo.rate);
93 
94   if (first_audio_timestamp == GST_CLOCK_TIME_NONE)
95     first_audio_timestamp = timestamp;
96 
97   last_audio_timestamp = timestamp + duration;
98 
99   audio_buffer_count++;
100   gst_buffer_unref (buffer);
101   return GST_FLOW_OK;
102 }
103 
104 static GstFlowReturn
output_vchain(GstPad * pad,GstObject * parent,GstBuffer * buffer)105 output_vchain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
106 {
107   GstClockTime timestamp;
108 
109   timestamp = GST_BUFFER_TIMESTAMP (buffer);
110 
111   if (first_video_timestamp == GST_CLOCK_TIME_NONE)
112     first_video_timestamp = timestamp;
113 
114   last_video_timestamp = timestamp + GST_BUFFER_DURATION (buffer);
115 
116   video_buffer_count++;
117   gst_buffer_unref (buffer);
118   return GST_FLOW_OK;
119 }
120 
121 static gpointer
push_abuffers(gpointer data)122 push_abuffers (gpointer data)
123 {
124   GstSegment segment;
125   gint i;
126   GstCaps *caps;
127   guint buf_size = 1000;
128   guint channels = 2;
129   PadAndBoolean *e = data;
130   GstPad *pad = e->pad;
131   gboolean audio_late = e->b;
132   GstClockTime timestamp;
133 
134   if (audio_late) {
135     timestamp = 50 * GST_MSECOND;
136   } else {
137     timestamp = 0;
138   }
139 
140   gst_pad_send_event (pad, gst_event_new_stream_start ("test"));
141 
142   gst_audio_info_set_format (&ainfo, GST_AUDIO_FORMAT_S8, buf_size, channels,
143       NULL);
144   caps = gst_audio_info_to_caps (&ainfo);
145   gst_pad_send_event (pad, gst_event_new_caps (caps));
146   gst_caps_unref (caps);
147 
148   gst_segment_init (&segment, GST_FORMAT_TIME);
149   gst_pad_send_event (pad, gst_event_new_segment (&segment));
150 
151   for (i = 0; i < n_abuffers; i++) {
152     GstBuffer *buf = gst_buffer_new_and_alloc (channels * buf_size);
153 
154     gst_buffer_memset (buf, 0, 0, channels * buf_size);
155 
156     GST_BUFFER_TIMESTAMP (buf) = timestamp;
157     timestamp += 1 * GST_SECOND;
158     GST_BUFFER_DURATION (buf) = timestamp - GST_BUFFER_TIMESTAMP (buf);
159 
160     fail_unless (gst_pad_chain (pad, buf) == GST_FLOW_OK);
161   }
162   gst_pad_send_event (pad, gst_event_new_eos ());
163 
164   return NULL;
165 }
166 
167 static gpointer
push_vbuffers(gpointer data)168 push_vbuffers (gpointer data)
169 {
170   GstSegment segment;
171   ElementPadAndSwitchType *e = data;
172   GstPad *pad = e->pad;
173   gint i;
174   GstClockTime timestamp = 0;
175   GstVideoTimeCode *tc;
176 
177   gst_pad_send_event (pad, gst_event_new_stream_start ("test"));
178   gst_segment_init (&segment, GST_FORMAT_TIME);
179   gst_pad_send_event (pad, gst_event_new_segment (&segment));
180   tc = gst_video_time_code_new (40, 1, NULL, GST_VIDEO_TIME_CODE_FLAGS_NONE, 0,
181       0, 0, 0, 0);
182 
183   for (i = 0; i < n_vbuffers; i++) {
184     GstBuffer *buf = gst_buffer_new_and_alloc (1000);
185 
186     gst_buffer_memset (buf, 0, i, 1);
187 
188     GST_BUFFER_TIMESTAMP (buf) = timestamp;
189     timestamp += 25 * GST_MSECOND;
190     GST_BUFFER_DURATION (buf) = timestamp - GST_BUFFER_TIMESTAMP (buf);
191     gst_buffer_add_video_time_code_meta (buf, tc);
192     gst_video_time_code_increment_frame (tc);
193 
194     fail_unless (gst_pad_chain (pad, buf) == GST_FLOW_OK);
195 
196     if (timestamp == 2 * GST_SECOND && e->switch_after_2s != DO_NOT_SWITCH) {
197       g_object_set (e->element, "recording", ! !e->switch_after_2s, NULL);
198     }
199   }
200   gst_pad_send_event (pad, gst_event_new_eos ());
201   gst_video_time_code_free (tc);
202 
203   return NULL;
204 }
205 
206 static void
test_avwait_generic(void)207 test_avwait_generic (void)
208 {
209   GstElement *avwait;
210   GstPad *asink, *vsink, *asrc, *vsrc, *aoutput_sink, *voutput_sink;
211   GThread *athread, *vthread;
212   GstBus *bus;
213   ElementPadAndSwitchType *e;
214   PadAndBoolean *pb;
215 
216   audio_buffer_count = 0;
217   video_buffer_count = 0;
218 
219   avwait = gst_element_factory_make ("avwait", NULL);
220   fail_unless (avwait != NULL);
221   g_object_set (avwait, "mode", mode,
222       "target-running-time", target_running_time, "recording", recording, NULL);
223   if (target_tc != NULL)
224     g_object_set (avwait, "target-timecode", target_tc, NULL);
225   if (end_tc != NULL)
226     g_object_set (avwait, "end-timecode", end_tc, NULL);
227 
228   bus = gst_bus_new ();
229   gst_element_set_bus (avwait, bus);
230 
231   asink = gst_element_get_static_pad (avwait, "asink");
232   fail_unless (asink != NULL);
233 
234   vsink = gst_element_get_static_pad (avwait, "vsink");
235   fail_unless (vsink != NULL);
236 
237   asrc = gst_element_get_static_pad (avwait, "asrc");
238   aoutput_sink = gst_pad_new ("sink", GST_PAD_SINK);
239   fail_unless (aoutput_sink != NULL);
240   fail_unless (gst_pad_link (asrc, aoutput_sink) == GST_PAD_LINK_OK);
241 
242   vsrc = gst_element_get_static_pad (avwait, "vsrc");
243   voutput_sink = gst_pad_new ("sink", GST_PAD_SINK);
244   fail_unless (voutput_sink != NULL);
245   fail_unless (gst_pad_link (vsrc, voutput_sink) == GST_PAD_LINK_OK);
246 
247   gst_pad_set_chain_function (aoutput_sink, output_achain);
248 
249   gst_pad_set_chain_function (voutput_sink, output_vchain);
250 
251   gst_pad_set_active (aoutput_sink, TRUE);
252   gst_pad_set_active (voutput_sink, TRUE);
253   fail_unless (gst_element_set_state (avwait,
254           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
255   e = g_new0 (ElementPadAndSwitchType, 1);
256   e->element = avwait;
257   e->pad = vsink;
258   e->switch_after_2s = switch_after_2s;
259   pb = g_new0 (PadAndBoolean, 1);
260   pb->pad = asink;
261   pb->b = audio_late;
262 
263   athread = g_thread_new ("athread", (GThreadFunc) push_abuffers, pb);
264   vthread = g_thread_new ("vthread", (GThreadFunc) push_vbuffers, e);
265 
266   g_thread_join (vthread);
267   g_thread_join (athread);
268 
269   /* teardown */
270   gst_element_set_state (avwait, GST_STATE_NULL);
271   gst_bus_set_flushing (bus, TRUE);
272   gst_object_unref (bus);
273   g_free (e);
274   g_free (pb);
275   gst_pad_unlink (asrc, aoutput_sink);
276   gst_object_unref (asrc);
277   gst_pad_unlink (vsrc, voutput_sink);
278   gst_object_unref (vsrc);
279   gst_object_unref (asink);
280   gst_object_unref (vsink);
281   gst_pad_set_active (aoutput_sink, FALSE);
282   gst_object_unref (aoutput_sink);
283   gst_pad_set_active (voutput_sink, FALSE);
284   gst_object_unref (voutput_sink);
285   gst_object_unref (avwait);
286 }
287 
GST_START_TEST(test_avwait_switch_to_true)288 GST_START_TEST (test_avwait_switch_to_true)
289 {
290   set_default_params ();
291   recording = FALSE;
292   switch_after_2s = SWITCH_TRUE;
293   test_avwait_generic ();
294   fail_unless_equals_uint64 (first_audio_timestamp, 2 * GST_SECOND);
295   fail_unless_equals_uint64 (first_video_timestamp, 2 * GST_SECOND);
296 }
297 
298 GST_END_TEST;
299 
GST_START_TEST(test_avwait_switch_to_false)300 GST_START_TEST (test_avwait_switch_to_false)
301 {
302   set_default_params ();
303   recording = TRUE;
304   switch_after_2s = SWITCH_FALSE;
305   test_avwait_generic ();
306   fail_unless_equals_uint64 (first_audio_timestamp, first_video_timestamp);
307   fail_unless_equals_uint64 (first_video_timestamp, 0);
308   fail_unless_equals_uint64 (last_video_timestamp, 2 * GST_SECOND);
309   fail_unless_equals_uint64 (last_audio_timestamp, 2 * GST_SECOND);
310 }
311 
312 GST_END_TEST;
313 
GST_START_TEST(test_avwait_1s_switch_to_true)314 GST_START_TEST (test_avwait_1s_switch_to_true)
315 {
316   set_default_params ();
317   recording = FALSE;
318   switch_after_2s = SWITCH_TRUE;
319   mode = 1;
320   target_running_time = 1 * GST_SECOND;
321   test_avwait_generic ();
322   fail_unless_equals_uint64 (first_audio_timestamp, 2 * GST_SECOND);
323   fail_unless_equals_uint64 (first_video_timestamp, 2 * GST_SECOND);
324 }
325 
326 GST_END_TEST;
327 
GST_START_TEST(test_avwait_1s_switch_to_false)328 GST_START_TEST (test_avwait_1s_switch_to_false)
329 {
330   set_default_params ();
331   recording = TRUE;
332   switch_after_2s = SWITCH_FALSE;
333   mode = 1;
334   target_running_time = 1 * GST_SECOND;
335   test_avwait_generic ();
336   fail_unless_equals_uint64 (first_audio_timestamp, 1 * GST_SECOND);
337   fail_unless_equals_uint64 (first_video_timestamp, 1 * GST_SECOND);
338   fail_unless_equals_uint64 (last_video_timestamp, 2 * GST_SECOND);
339   fail_unless_equals_uint64 (last_audio_timestamp, 2 * GST_SECOND);
340 }
341 
342 GST_END_TEST;
343 
GST_START_TEST(test_avwait_3s_switch_to_true)344 GST_START_TEST (test_avwait_3s_switch_to_true)
345 {
346   set_default_params ();
347   recording = FALSE;
348   switch_after_2s = SWITCH_TRUE;
349   mode = 1;
350   target_running_time = 3 * GST_SECOND;
351   test_avwait_generic ();
352   fail_unless_equals_uint64 (first_audio_timestamp, 3 * GST_SECOND);
353   fail_unless_equals_uint64 (first_video_timestamp, 3 * GST_SECOND);
354 }
355 
356 GST_END_TEST;
357 
GST_START_TEST(test_avwait_3s_switch_to_false)358 GST_START_TEST (test_avwait_3s_switch_to_false)
359 {
360   set_default_params ();
361   recording = TRUE;
362   switch_after_2s = SWITCH_FALSE;
363   mode = 1;
364   target_running_time = 3 * GST_SECOND;
365   test_avwait_generic ();
366   fail_unless_equals_uint64 (first_audio_timestamp, GST_CLOCK_TIME_NONE);
367   fail_unless_equals_uint64 (first_video_timestamp, GST_CLOCK_TIME_NONE);
368   fail_unless_equals_uint64 (last_audio_timestamp, GST_CLOCK_TIME_NONE);
369   fail_unless_equals_uint64 (last_video_timestamp, GST_CLOCK_TIME_NONE);
370 }
371 
372 GST_END_TEST;
373 
GST_START_TEST(test_avwait_1stc_switch_to_true)374 GST_START_TEST (test_avwait_1stc_switch_to_true)
375 {
376   set_default_params ();
377   recording = FALSE;
378   switch_after_2s = SWITCH_TRUE;
379   mode = 0;
380   target_tc =
381       gst_video_time_code_new (40, 1, NULL, GST_VIDEO_TIME_CODE_FLAGS_NONE, 0,
382       0, 1, 0, 0);
383   end_tc =
384       gst_video_time_code_new (40, 1, NULL, GST_VIDEO_TIME_CODE_FLAGS_NONE, 0,
385       0, 3, 0, 0);
386   test_avwait_generic ();
387   fail_unless_equals_uint64 (first_audio_timestamp, 2 * GST_SECOND);
388   fail_unless_equals_uint64 (first_video_timestamp, 2 * GST_SECOND);
389   fail_unless_equals_uint64 (last_video_timestamp, 3 * GST_SECOND);
390   fail_unless_equals_uint64 (last_audio_timestamp, 3 * GST_SECOND);
391 }
392 
393 GST_END_TEST;
394 
GST_START_TEST(test_avwait_1stc_switch_to_false)395 GST_START_TEST (test_avwait_1stc_switch_to_false)
396 {
397   set_default_params ();
398   recording = TRUE;
399   switch_after_2s = SWITCH_FALSE;
400   mode = 0;
401   target_tc =
402       gst_video_time_code_new (40, 1, NULL, GST_VIDEO_TIME_CODE_FLAGS_NONE, 0,
403       0, 1, 0, 0);
404   end_tc =
405       gst_video_time_code_new (40, 1, NULL, GST_VIDEO_TIME_CODE_FLAGS_NONE, 0,
406       0, 3, 0, 0);
407   test_avwait_generic ();
408   fail_unless_equals_uint64 (first_audio_timestamp, 1 * GST_SECOND);
409   fail_unless_equals_uint64 (first_video_timestamp, 1 * GST_SECOND);
410   fail_unless_equals_uint64 (last_video_timestamp, 2 * GST_SECOND);
411   fail_unless_equals_uint64 (last_audio_timestamp, 2 * GST_SECOND);
412 }
413 
414 GST_END_TEST;
415 
GST_START_TEST(test_avwait_3stc_switch_to_true)416 GST_START_TEST (test_avwait_3stc_switch_to_true)
417 {
418   set_default_params ();
419   recording = FALSE;
420   switch_after_2s = SWITCH_TRUE;
421   mode = 0;
422   target_tc =
423       gst_video_time_code_new (40, 1, NULL, GST_VIDEO_TIME_CODE_FLAGS_NONE, 0,
424       0, 3, 0, 0);
425   test_avwait_generic ();
426   fail_unless_equals_uint64 (first_audio_timestamp, 3 * GST_SECOND);
427   fail_unless_equals_uint64 (first_video_timestamp, 3 * GST_SECOND);
428 }
429 
430 GST_END_TEST;
431 
GST_START_TEST(test_avwait_3stc_switch_to_false)432 GST_START_TEST (test_avwait_3stc_switch_to_false)
433 {
434   set_default_params ();
435   recording = TRUE;
436   switch_after_2s = SWITCH_FALSE;
437   mode = 0;
438   target_tc =
439       gst_video_time_code_new (40, 1, NULL, GST_VIDEO_TIME_CODE_FLAGS_NONE, 0,
440       0, 3, 0, 0);
441   test_avwait_generic ();
442   fail_unless_equals_uint64 (first_audio_timestamp, GST_CLOCK_TIME_NONE);
443   fail_unless_equals_uint64 (first_video_timestamp, GST_CLOCK_TIME_NONE);
444   fail_unless_equals_uint64 (last_audio_timestamp, GST_CLOCK_TIME_NONE);
445   fail_unless_equals_uint64 (last_video_timestamp, GST_CLOCK_TIME_NONE);
446 }
447 
448 GST_END_TEST;
449 
GST_START_TEST(test_avwait_audio_late)450 GST_START_TEST (test_avwait_audio_late)
451 {
452   set_default_params ();
453   recording = TRUE;
454   audio_late = TRUE;
455   test_avwait_generic ();
456   fail_unless_equals_uint64 (first_audio_timestamp, 50 * GST_MSECOND);
457   fail_unless_equals_uint64 (first_video_timestamp, 50 * GST_MSECOND);
458 }
459 
460 GST_END_TEST;
461 
462 static Suite *
avwait_suite(void)463 avwait_suite (void)
464 {
465   Suite *s = suite_create ("avwait");
466   TCase *tc_chain;
467 
468   tc_chain = tcase_create ("avwait");
469   tcase_add_test (tc_chain, test_avwait_switch_to_true);
470   tcase_add_test (tc_chain, test_avwait_switch_to_false);
471   tcase_add_test (tc_chain, test_avwait_1s_switch_to_true);
472   tcase_add_test (tc_chain, test_avwait_1s_switch_to_false);
473   tcase_add_test (tc_chain, test_avwait_3s_switch_to_true);
474   tcase_add_test (tc_chain, test_avwait_3s_switch_to_false);
475   tcase_add_test (tc_chain, test_avwait_1stc_switch_to_true);
476   tcase_add_test (tc_chain, test_avwait_1stc_switch_to_false);
477   tcase_add_test (tc_chain, test_avwait_3stc_switch_to_true);
478   tcase_add_test (tc_chain, test_avwait_3stc_switch_to_false);
479   tcase_add_test (tc_chain, test_avwait_audio_late);
480   suite_add_tcase (s, tc_chain);
481 
482   return s;
483 }
484 
485 GST_CHECK_MAIN (avwait);
486