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