9db14125fd4059b67d9b4b5eeca823be20e910fe
[platform/upstream/gstreamer.git] / tests / check / libs / baseparse.c
1 /* GStreamer
2  *
3  * Copyright (C) 2014 Samsung Electronics. All rights reserved.
4  *   Author: Thiago Santos <ts.santos@sisa.samsung.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <gst/gst.h>
26 #include <gst/check/gstcheck.h>
27 #include <gst/base/gstbaseparse.h>
28
29 static GstPad *mysrcpad, *mysinkpad;
30 static GstElement *parsetest;
31 static GstBus *bus;
32 static GMainLoop *loop = NULL;
33 static gboolean have_eos = FALSE;
34 static gboolean have_data = FALSE;
35 static gint buffer_count = 0;
36 static gboolean caps_set = FALSE;
37 static gchar *raw_buffer = NULL;
38 static gint raw_buffer_size = 0;
39 static gint buffer_pull_count = 0;
40 static gint current_offset = 0;
41
42 #define TEST_VIDEO_WIDTH 640
43 #define TEST_VIDEO_HEIGHT 480
44 #define TEST_VIDEO_FPS_N 30
45 #define TEST_VIDEO_FPS_D 1
46
47 #define GST_PARSER_TESTER_TYPE gst_parser_tester_get_type()
48 static GType gst_parser_tester_get_type (void);
49
50 typedef struct _GstParserTester GstParserTester;
51 typedef struct _GstParserTesterClass GstParserTesterClass;
52
53 struct _GstParserTester
54 {
55   GstBaseParse parent;
56 };
57
58 struct _GstParserTesterClass
59 {
60   GstBaseParseClass parent_class;
61 };
62
63 G_DEFINE_TYPE (GstParserTester, gst_parser_tester, GST_TYPE_BASE_PARSE);
64
65 static gboolean
66 gst_parser_tester_start (GstBaseParse * parse)
67 {
68   return TRUE;
69 }
70
71 static gboolean
72 gst_parser_tester_stop (GstBaseParse * parse)
73 {
74   return TRUE;
75 }
76
77 static gboolean
78 gst_parser_tester_set_sink_caps (GstBaseParse * parse, GstCaps * caps)
79 {
80   gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
81   return TRUE;
82 }
83
84 static GstFlowReturn
85 gst_parser_tester_handle_frame (GstBaseParse * parse,
86     GstBaseParseFrame * frame, gint * skipsize)
87 {
88   GstFlowReturn ret = GST_FLOW_OK;
89
90   if (caps_set == FALSE) {
91     GstCaps *caps;
92     /* push caps */
93     caps =
94         gst_caps_new_simple ("video/x-test-custom", "width", G_TYPE_INT,
95         TEST_VIDEO_WIDTH, "height", G_TYPE_INT, TEST_VIDEO_HEIGHT, "framerate",
96         GST_TYPE_FRACTION, TEST_VIDEO_FPS_N, TEST_VIDEO_FPS_D, NULL);
97     gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
98     gst_caps_unref (caps);
99     caps_set = TRUE;
100   }
101
102   while (frame->buffer && gst_buffer_get_size (frame->buffer) >= 8) {
103     GST_BUFFER_DURATION (frame->buffer) =
104         gst_util_uint64_scale_round (GST_SECOND, TEST_VIDEO_FPS_D,
105         TEST_VIDEO_FPS_N);
106     ret = gst_base_parse_finish_frame (parse, frame, 8);
107   }
108   return ret;
109 }
110
111 static void
112 gst_parser_tester_class_init (GstParserTesterClass * klass)
113 {
114   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
115   GstBaseParseClass *baseparse_class = GST_BASE_PARSE_CLASS (klass);
116
117   static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
118       GST_PAD_SINK, GST_PAD_ALWAYS,
119       GST_STATIC_CAPS ("video/x-test-custom"));
120
121   static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
122       GST_PAD_SRC, GST_PAD_ALWAYS,
123       GST_STATIC_CAPS ("video/x-test-custom"));
124
125   gst_element_class_add_static_pad_template (element_class, &sink_templ);
126   gst_element_class_add_static_pad_template (element_class, &src_templ);
127
128   gst_element_class_set_metadata (element_class,
129       "ParserTester", "Parser/Video", "yep", "me");
130
131   baseparse_class->start = gst_parser_tester_start;
132   baseparse_class->stop = gst_parser_tester_stop;
133   baseparse_class->handle_frame = gst_parser_tester_handle_frame;
134   baseparse_class->set_sink_caps = gst_parser_tester_set_sink_caps;
135 }
136
137 static void
138 gst_parser_tester_init (GstParserTester * tester)
139 {
140 }
141
142 static void
143 setup_parsertester (void)
144 {
145   static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
146       GST_PAD_SINK,
147       GST_PAD_ALWAYS,
148       GST_STATIC_CAPS ("video/x-test-custom")
149       );
150   static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
151       GST_PAD_SRC,
152       GST_PAD_ALWAYS,
153       GST_STATIC_CAPS ("video/x-test-custom")
154       );
155
156   parsetest = g_object_new (GST_PARSER_TESTER_TYPE, NULL);
157   mysrcpad = gst_check_setup_src_pad (parsetest, &srctemplate);
158   mysinkpad = gst_check_setup_sink_pad (parsetest, &sinktemplate);
159   bus = gst_bus_new ();
160   gst_element_set_bus (parsetest, bus);
161 }
162
163 static void
164 cleanup_parsertest (void)
165 {
166   /* release the bus first to get rid of all refcounts */
167   gst_element_set_bus (parsetest, NULL);
168   gst_object_unref (bus);
169
170   gst_pad_set_active (mysrcpad, FALSE);
171   gst_pad_set_active (mysinkpad, FALSE);
172   gst_check_teardown_src_pad (parsetest);
173   gst_check_teardown_sink_pad (parsetest);
174   gst_check_teardown_element (parsetest);
175 }
176
177 static GstBuffer *
178 create_test_buffer (guint64 num)
179 {
180   GstBuffer *buffer;
181   guint64 *data = g_malloc (sizeof (guint64));
182
183   *data = num;
184
185   buffer = gst_buffer_new_wrapped (data, sizeof (guint64));
186
187   GST_BUFFER_PTS (buffer) =
188       gst_util_uint64_scale_round (num, GST_SECOND * TEST_VIDEO_FPS_D,
189       TEST_VIDEO_FPS_N);
190   GST_BUFFER_DURATION (buffer) =
191       gst_util_uint64_scale_round (GST_SECOND, TEST_VIDEO_FPS_D,
192       TEST_VIDEO_FPS_N);
193
194   return buffer;
195 }
196
197 static void
198 send_startup_events (void)
199 {
200   GstCaps *caps;
201
202   fail_unless (gst_pad_push_event (mysrcpad,
203           gst_event_new_stream_start ("randomvalue")));
204
205   /* push caps */
206   caps =
207       gst_caps_new_simple ("video/x-test-custom", "width", G_TYPE_INT,
208       TEST_VIDEO_WIDTH, "height", G_TYPE_INT, TEST_VIDEO_HEIGHT, "framerate",
209       GST_TYPE_FRACTION, TEST_VIDEO_FPS_N, TEST_VIDEO_FPS_D, NULL);
210   fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_caps (caps)));
211   gst_caps_unref (caps);
212 }
213
214 static void
215 check_no_error_received (void)
216 {
217   GstMessage *msg;
218
219   msg = gst_bus_pop_filtered (bus, GST_MESSAGE_ERROR);
220   fail_unless (msg == NULL);
221   if (msg)
222     gst_message_unref (msg);
223 }
224
225 static void
226 run_parser_playback_test (GList * input, gint expected_output, gdouble rate)
227 {
228   GstBuffer *buffer;
229   guint64 i;
230   GList *iter;
231   GstSegment segment;
232
233   gst_pad_set_active (mysrcpad, TRUE);
234   gst_element_set_state (parsetest, GST_STATE_PLAYING);
235   gst_pad_set_active (mysinkpad, TRUE);
236
237   send_startup_events ();
238
239   /* push a new segment */
240   gst_segment_init (&segment, GST_FORMAT_TIME);
241   segment.rate = rate;
242   fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
243
244   /* push buffers, the data is actually a number so we can track them */
245   for (iter = input; iter; iter = g_list_next (iter)) {
246     buffer = iter->data;
247
248     fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
249   }
250   g_list_free (input);
251
252   fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
253
254   /* check that all buffers were received by our source pad */
255   fail_unless (g_list_length (buffers) == expected_output);
256   i = 0;
257   for (iter = buffers; iter; iter = g_list_next (iter)) {
258     GstMapInfo map;
259     guint64 num;
260
261     buffer = iter->data;
262
263     gst_buffer_map (buffer, &map, GST_MAP_READ);
264
265     num = *(guint64 *) map.data;
266     fail_unless (i == num);
267     fail_unless (GST_BUFFER_PTS (buffer) == gst_util_uint64_scale_round (i,
268             GST_SECOND * TEST_VIDEO_FPS_D, TEST_VIDEO_FPS_N));
269     fail_unless (GST_BUFFER_DURATION (buffer) ==
270         gst_util_uint64_scale_round (GST_SECOND, TEST_VIDEO_FPS_D,
271             TEST_VIDEO_FPS_N));
272
273     gst_buffer_unmap (buffer, &map);
274     i++;
275   }
276
277   g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
278   buffers = NULL;
279
280   check_no_error_received ();
281
282   cleanup_parsertest ();
283 }
284
285
286 GST_START_TEST (parser_playback)
287 {
288   GList *input = NULL;
289   gint i;
290   GstBuffer *buffer;
291
292   setup_parsertester ();
293
294   /* push buffers, the data is actually a number so we can track them */
295   for (i = 0; i < 3; i++) {
296     buffer = create_test_buffer (i);
297     input = g_list_append (input, buffer);
298   }
299
300   run_parser_playback_test (input, 3, 1.0);
301 }
302
303 GST_END_TEST;
304
305
306 /* Check https://bugzilla.gnome.org/show_bug.cgi?id=721941 */
307 GST_START_TEST (parser_reverse_playback_on_passthrough)
308 {
309   GList *input = NULL;
310   gint i;
311   GstBuffer *buffer;
312
313   setup_parsertester ();
314
315   gst_base_parse_set_passthrough (GST_BASE_PARSE (parsetest), TRUE);
316
317   /* push buffers, the data is actually a number so we can track them */
318   for (i = 0; i < 6; i++) {
319     buffer = create_test_buffer (i);
320     if (i > 0)
321       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
322     input = g_list_append (input, buffer);
323   }
324   GST_BUFFER_FLAG_SET (g_list_nth (input, 3)->data, GST_BUFFER_FLAG_DISCONT);
325
326   run_parser_playback_test (input, 6, -1.0);
327 }
328
329 GST_END_TEST;
330
331 GST_START_TEST (parser_empty_stream)
332 {
333   setup_parsertester ();
334
335   run_parser_playback_test (NULL, 0, 1.0);
336 }
337
338 GST_END_TEST;
339
340 static GstFlowReturn
341 _sink_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
342 {
343   GstMapInfo map;
344   guint64 num;
345
346   gst_buffer_map (buffer, &map, GST_MAP_READ);
347
348   num = *(guint64 *) map.data;
349
350   fail_unless (buffer_count == num);
351   fail_unless (GST_BUFFER_PTS (buffer) ==
352       gst_util_uint64_scale_round (buffer_count, GST_SECOND * TEST_VIDEO_FPS_D,
353           TEST_VIDEO_FPS_N));
354   fail_unless (GST_BUFFER_DURATION (buffer) ==
355       gst_util_uint64_scale_round (GST_SECOND, TEST_VIDEO_FPS_D,
356           TEST_VIDEO_FPS_N));
357   gst_buffer_unmap (buffer, &map);
358   gst_buffer_unref (buffer);
359   buffer_count++;
360
361   have_data = TRUE;
362   return GST_FLOW_OK;
363 }
364
365 static gboolean
366 _sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
367 {
368   GST_INFO_OBJECT (pad, "got %s event %p: %" GST_PTR_FORMAT,
369       GST_EVENT_TYPE_NAME (event), event, event);
370
371   switch (GST_EVENT_TYPE (event)) {
372     case GST_EVENT_EOS:
373       if (loop) {
374         while (!g_main_loop_is_running (loop)) {
375           /* nothing */
376         };
377       }
378       have_eos = TRUE;
379       if (loop)
380         g_main_loop_quit (loop);
381       break;
382     default:
383       break;
384   }
385   gst_event_unref (event);
386
387   return TRUE;
388 }
389
390 static GstFlowReturn
391 _src_getrange (GstPad * pad, GstObject * parent, guint64 offset, guint length,
392     GstBuffer ** buffer)
393 {
394   gboolean ret = FALSE;
395   if (offset >= 80 && have_eos == FALSE) {
396     ret = gst_element_seek (parsetest, -1.0, GST_FORMAT_TIME,
397         GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH,
398         GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, gst_util_uint64_scale_round (5,
399             GST_SECOND * TEST_VIDEO_FPS_D, TEST_VIDEO_FPS_N));
400     fail_unless (ret == TRUE);
401     buffer_count = 0;
402   }
403
404   *buffer = create_test_buffer (offset / 8);
405
406   return GST_FLOW_OK;
407 }
408
409 static gboolean
410 _src_query (GstPad * pad, GstObject * parent, GstQuery * query)
411 {
412   gboolean res = FALSE;
413
414   switch (GST_QUERY_TYPE (query)) {
415     case GST_QUERY_SCHEDULING:{
416       gst_query_set_scheduling (query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0);
417       gst_query_add_scheduling_mode (query, GST_PAD_MODE_PULL);
418       res = TRUE;
419       break;
420     }
421     default:
422       GST_DEBUG_OBJECT (pad, "unhandled %s query", GST_QUERY_TYPE_NAME (query));
423       break;
424   }
425
426   return res;
427 }
428
429 GST_START_TEST (parser_reverse_playback)
430 {
431   have_eos = FALSE;
432   have_data = FALSE;
433   loop = g_main_loop_new (NULL, FALSE);
434
435   setup_parsertester ();
436   gst_pad_set_getrange_function (mysrcpad, _src_getrange);
437   gst_pad_set_query_function (mysrcpad, _src_query);
438   gst_pad_set_chain_function (mysinkpad, _sink_chain);
439   gst_pad_set_event_function (mysinkpad, _sink_event);
440
441   gst_pad_set_active (mysrcpad, TRUE);
442   gst_element_set_state (parsetest, GST_STATE_PLAYING);
443   gst_pad_set_active (mysinkpad, TRUE);
444
445   g_main_loop_run (loop);
446   fail_unless (have_eos == TRUE);
447   fail_unless (have_data == TRUE);
448
449   gst_element_set_state (parsetest, GST_STATE_NULL);
450
451   check_no_error_received ();
452   cleanup_parsertest ();
453
454   g_main_loop_unref (loop);
455   loop = NULL;
456 }
457
458 GST_END_TEST;
459
460 static GstFlowReturn
461 _sink_chain_pull_short_read (GstPad * pad, GstObject * parent,
462     GstBuffer * buffer)
463 {
464   GstMapInfo map;
465   gint buffer_size = 0;
466   gint compare_result = 0;
467
468   gst_buffer_map (buffer, &map, GST_MAP_READ);
469   buffer_size = map.size;
470
471   fail_unless (current_offset + buffer_size <= raw_buffer_size);
472   compare_result = memcmp (map.data, &raw_buffer[current_offset], buffer_size);
473   fail_unless_equals_int (compare_result, 0);
474
475   gst_buffer_unmap (buffer, &map);
476   gst_buffer_unref (buffer);
477
478   have_data = TRUE;
479   buffer_count++;
480
481   return GST_FLOW_OK;
482 }
483
484 static GstFlowReturn
485 _src_getrange_pull_short_read (GstPad * pad, GstObject * parent,
486     guint64 offset, guint length, GstBuffer ** buffer)
487 {
488   GstBuffer *buf = NULL;
489   gchar *data = NULL;
490   guint buffer_size = 0;
491
492   if (offset == raw_buffer_size) {
493     /* pulled all buffer */
494     return GST_FLOW_EOS;
495   }
496
497   if (offset + length <= raw_buffer_size) {
498     buffer_size = length;
499   } else {
500     /* buffer size is less than request size */
501     buffer_size = raw_buffer_size - offset;
502   }
503
504   data = g_malloc (buffer_size);
505   memcpy (data, &raw_buffer[offset], buffer_size);
506   buf = gst_buffer_new_wrapped (data, buffer_size);
507
508   GST_BUFFER_PTS (buffer) =
509       gst_util_uint64_scale_round (buffer_pull_count,
510       GST_SECOND * TEST_VIDEO_FPS_D, TEST_VIDEO_FPS_N);
511   GST_BUFFER_DURATION (buf) =
512       gst_util_uint64_scale_round (GST_SECOND, TEST_VIDEO_FPS_D,
513       TEST_VIDEO_FPS_N);
514
515   *buffer = buf;
516   current_offset = offset;
517   buffer_pull_count++;
518
519   return GST_FLOW_OK;
520 }
521
522 GST_START_TEST (parser_pull_short_read)
523 {
524   gint i, j;
525   raw_buffer_size = (64 * 1024) + 512;
526   raw_buffer = g_malloc (raw_buffer_size);
527
528   for (i = 0; i < raw_buffer_size; i++) {
529     j = i % 26;
530     raw_buffer[i] = 'a' + j;
531   }
532
533   have_eos = FALSE;
534   have_data = FALSE;
535   buffer_count = 0;
536   loop = g_main_loop_new (NULL, FALSE);
537
538   setup_parsertester ();
539   gst_pad_set_getrange_function (mysrcpad, _src_getrange_pull_short_read);
540   gst_pad_set_query_function (mysrcpad, _src_query);
541   gst_pad_set_chain_function (mysinkpad, _sink_chain_pull_short_read);
542   gst_pad_set_event_function (mysinkpad, _sink_event);
543   gst_base_parse_set_min_frame_size (GST_BASE_PARSE (parsetest), 1024);
544
545   gst_pad_set_active (mysrcpad, TRUE);
546   gst_element_set_state (parsetest, GST_STATE_PLAYING);
547   gst_pad_set_active (mysinkpad, TRUE);
548
549   g_main_loop_run (loop);
550   fail_unless_equals_int (have_eos, TRUE);
551   fail_unless_equals_int (have_data, TRUE);
552   fail_unless_equals_int (buffer_pull_count, buffer_count);
553
554   gst_element_set_state (parsetest, GST_STATE_NULL);
555
556   check_no_error_received ();
557   cleanup_parsertest ();
558
559   g_main_loop_unref (loop);
560   loop = NULL;
561 }
562
563 GST_END_TEST;
564
565 static void
566 baseparse_setup (void)
567 {
568   /* init/reset global state */
569   mysrcpad = mysinkpad = NULL;
570   parsetest = NULL;
571   bus = NULL;
572   loop = NULL;
573   have_eos = have_data = caps_set = FALSE;
574   buffer_count = 0;
575 }
576
577 static void
578 baseparse_teardown (void)
579 {
580 }
581
582 static Suite *
583 gst_baseparse_suite (void)
584 {
585   Suite *s = suite_create ("GstBaseParse");
586   TCase *tc = tcase_create ("general");
587
588   suite_add_tcase (s, tc);
589   tcase_add_checked_fixture (tc, baseparse_setup, baseparse_teardown);
590   tcase_add_test (tc, parser_playback);
591   tcase_add_test (tc, parser_empty_stream);
592   tcase_add_test (tc, parser_reverse_playback_on_passthrough);
593   tcase_add_test (tc, parser_reverse_playback);
594   tcase_add_test (tc, parser_pull_short_read);
595
596   return s;
597 }
598
599 GST_CHECK_MAIN (gst_baseparse);