5487f7cb2b9069eebcf3f2090232f1b52f6ba142
[platform/upstream/gstreamer.git] / tests / check / elements / filesrc.c
1 /* GStreamer
2  *
3  * Copyright (C) 2006 Thomas Vander Stichele <thomas at apestaart dot org>
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 #include <unistd.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25
26 #include <gst/check/gstcheck.h>
27
28 static gboolean have_eos = FALSE;
29 static GCond eos_cond;
30 static GMutex event_mutex;
31
32 static GstPad *mysinkpad;
33
34 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
35     GST_PAD_SINK,
36     GST_PAD_ALWAYS,
37     GST_STATIC_CAPS_ANY);
38
39 static gboolean
40 event_func (GstPad * pad, GstObject * parent, GstEvent * event)
41 {
42   gboolean res = TRUE;
43
44   g_mutex_lock (&event_mutex);
45   if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
46     have_eos = TRUE;
47     GST_DEBUG ("signal EOS");
48     g_cond_broadcast (&eos_cond);
49   }
50   g_mutex_unlock (&event_mutex);
51
52   gst_event_unref (event);
53
54   return res;
55 }
56
57 static void
58 wait_eos (void)
59 {
60   g_mutex_lock (&event_mutex);
61   GST_DEBUG ("waiting for EOS");
62   while (!have_eos) {
63     g_cond_wait (&eos_cond, &event_mutex);
64   }
65   GST_DEBUG ("received EOS");
66   g_mutex_unlock (&event_mutex);
67 }
68
69 static GstElement *
70 setup_filesrc (void)
71 {
72   GstElement *filesrc;
73
74   GST_DEBUG ("setup_filesrc");
75   filesrc = gst_check_setup_element ("filesrc");
76   mysinkpad = gst_check_setup_sink_pad (filesrc, &sinktemplate);
77   gst_pad_set_event_function (mysinkpad, event_func);
78   gst_pad_set_active (mysinkpad, TRUE);
79
80   return filesrc;
81 }
82
83 static void
84 cleanup_filesrc (GstElement * filesrc)
85 {
86   gst_pad_set_active (mysinkpad, FALSE);
87   gst_check_teardown_sink_pad (filesrc);
88   gst_check_teardown_element (filesrc);
89 }
90
91 GST_START_TEST (test_seeking)
92 {
93   GstElement *src;
94   GstQuery *seeking_query;
95   gboolean seekable;
96
97 #ifndef TESTFILE
98 #error TESTFILE not defined
99 #endif
100   src = setup_filesrc ();
101
102   g_object_set (G_OBJECT (src), "location", TESTFILE, NULL);
103   fail_unless (gst_element_set_state (src,
104           GST_STATE_PAUSED) == GST_STATE_CHANGE_SUCCESS,
105       "could not set to paused");
106
107   /* Test that filesrc is seekable with a file fd */
108   fail_unless ((seeking_query = gst_query_new_seeking (GST_FORMAT_BYTES))
109       != NULL);
110   fail_unless (gst_element_query (src, seeking_query) == TRUE);
111   gst_query_parse_seeking (seeking_query, NULL, &seekable, NULL, NULL);
112   fail_unless (seekable == TRUE);
113   gst_query_unref (seeking_query);
114
115   fail_unless (gst_element_set_state (src,
116           GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
117
118   /* cleanup */
119   cleanup_filesrc (src);
120 }
121
122 GST_END_TEST;
123
124 GST_START_TEST (test_reverse)
125 {
126   GstElement *src;
127
128 #ifndef TESTFILE
129 #error TESTFILE not defined
130 #endif
131   src = setup_filesrc ();
132
133   g_object_set (G_OBJECT (src), "location", TESTFILE, NULL);
134   /* we're going to perform the seek in ready */
135   fail_unless (gst_element_set_state (src,
136           GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS,
137       "could not set to ready");
138
139   /* reverse seek from end to start */
140   gst_element_seek (src, -1.0, GST_FORMAT_BYTES, 0, GST_SEEK_TYPE_SET, 100,
141       GST_SEEK_TYPE_SET, -1);
142
143   fail_unless (gst_element_set_state (src,
144           GST_STATE_PAUSED) == GST_STATE_CHANGE_SUCCESS,
145       "could not set to paused");
146
147   /* wait for EOS */
148   wait_eos ();
149
150   fail_unless (gst_element_set_state (src,
151           GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
152
153   /* cleanup */
154   cleanup_filesrc (src);
155 }
156
157 GST_END_TEST;
158
159 GST_START_TEST (test_pull)
160 {
161   GstElement *src;
162   GstQuery *seeking_query;
163   gboolean res, seekable;
164   gint64 start, stop;
165   GstPad *pad;
166   GstFlowReturn ret;
167   GstBuffer *buffer1, *buffer2;
168   GstMapInfo info1, info2;
169
170   src = setup_filesrc ();
171
172   g_object_set (G_OBJECT (src), "location", TESTFILE, NULL);
173   fail_unless (gst_element_set_state (src,
174           GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS,
175       "could not set to ready");
176
177   /* get the source pad */
178   pad = gst_element_get_static_pad (src, "src");
179   fail_unless (pad != NULL);
180
181   /* activate the pad in pull mode */
182   res = gst_pad_activate_mode (pad, GST_PAD_MODE_PULL, TRUE);
183   fail_unless (res == TRUE);
184
185   /* not start playing */
186   fail_unless (gst_element_set_state (src,
187           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
188       "could not set to paused");
189
190   /* Test that filesrc is seekable with a file fd */
191   fail_unless ((seeking_query = gst_query_new_seeking (GST_FORMAT_BYTES))
192       != NULL);
193   fail_unless (gst_element_query (src, seeking_query) == TRUE);
194
195   /* get the seeking capabilities */
196   gst_query_parse_seeking (seeking_query, NULL, &seekable, &start, &stop);
197   fail_unless (seekable == TRUE);
198   fail_unless (start == 0);
199   fail_unless (start != -1);
200   gst_query_unref (seeking_query);
201
202   /* do some pulls */
203   buffer1 = NULL;
204   ret = gst_pad_get_range (pad, 0, 100, &buffer1);
205   fail_unless (ret == GST_FLOW_OK);
206   fail_unless (buffer1 != NULL);
207   fail_unless (gst_buffer_get_size (buffer1) == 100);
208
209   buffer2 = NULL;
210   ret = gst_pad_get_range (pad, 0, 50, &buffer2);
211   fail_unless (ret == GST_FLOW_OK);
212   fail_unless (buffer2 != NULL);
213   fail_unless (gst_buffer_get_size (buffer2) == 50);
214
215   /* this should be the same */
216   fail_unless (gst_buffer_map (buffer1, &info1, GST_MAP_READ));
217   fail_unless (gst_buffer_map (buffer2, &info2, GST_MAP_READ));
218   fail_unless (memcmp (info1.data, info2.data, 50) == 0);
219   gst_buffer_unmap (buffer2, &info2);
220
221   gst_buffer_unref (buffer2);
222
223   /* read next 50 bytes */
224   buffer2 = NULL;
225   ret = gst_pad_get_range (pad, 50, 50, &buffer2);
226   fail_unless (ret == GST_FLOW_OK);
227   fail_unless (buffer2 != NULL);
228   fail_unless (gst_buffer_get_size (buffer2) == 50);
229
230   /* compare with previously read data */
231   fail_unless (gst_buffer_map (buffer2, &info2, GST_MAP_READ));
232   fail_unless (memcmp ((guint8 *) info1.data + 50, info2.data, 50) == 0);
233   gst_buffer_unmap (buffer2, &info2);
234
235   gst_buffer_unmap (buffer1, &info1);
236   gst_buffer_unref (buffer1);
237   gst_buffer_unref (buffer2);
238
239   /* read 10 bytes at end-10 should give exactly 10 bytes */
240   buffer1 = NULL;
241   ret = gst_pad_get_range (pad, stop - 10, 10, &buffer1);
242   fail_unless (ret == GST_FLOW_OK);
243   fail_unless (buffer1 != NULL);
244   fail_unless (gst_buffer_get_size (buffer1) == 10);
245   gst_buffer_unref (buffer1);
246
247   /* read 20 bytes at end-10 should give exactly 10 bytes */
248   buffer1 = NULL;
249   ret = gst_pad_get_range (pad, stop - 10, 20, &buffer1);
250   fail_unless (ret == GST_FLOW_OK);
251   fail_unless (buffer1 != NULL);
252   fail_unless (gst_buffer_get_size (buffer1) == 10);
253   gst_buffer_unref (buffer1);
254
255   /* read 0 bytes at end-1 should return 0 bytes */
256   buffer1 = NULL;
257   ret = gst_pad_get_range (pad, stop - 1, 0, &buffer1);
258   fail_unless (ret == GST_FLOW_OK);
259   fail_unless (buffer1 != NULL);
260   fail_unless (gst_buffer_get_size (buffer1) == 0);
261   gst_buffer_unref (buffer1);
262
263   /* read 10 bytes at end-1 should return 1 byte */
264   buffer1 = NULL;
265   ret = gst_pad_get_range (pad, stop - 1, 10, &buffer1);
266   fail_unless (ret == GST_FLOW_OK);
267   fail_unless (buffer1 != NULL);
268   fail_unless (gst_buffer_get_size (buffer1) == 1);
269   gst_buffer_unref (buffer1);
270
271   /* read 0 bytes at end should EOS */
272   buffer1 = NULL;
273   ret = gst_pad_get_range (pad, stop, 0, &buffer1);
274   fail_unless (ret == GST_FLOW_EOS);
275
276   /* read 10 bytes before end should EOS */
277   buffer1 = NULL;
278   ret = gst_pad_get_range (pad, stop, 10, &buffer1);
279   fail_unless (ret == GST_FLOW_EOS);
280
281   /* read 0 bytes after end should EOS */
282   buffer1 = NULL;
283   ret = gst_pad_get_range (pad, stop + 10, 0, &buffer1);
284   fail_unless (ret == GST_FLOW_EOS);
285
286   /* read 10 bytes after end should EOS too */
287   buffer1 = NULL;
288   ret = gst_pad_get_range (pad, stop + 10, 10, &buffer1);
289   fail_unless (ret == GST_FLOW_EOS);
290
291   fail_unless (gst_element_set_state (src,
292           GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
293
294   /* cleanup */
295   gst_object_unref (pad);
296   cleanup_filesrc (src);
297 }
298
299 GST_END_TEST;
300
301 GST_START_TEST (test_coverage)
302 {
303   GstElement *src;
304   gchar *location;
305   GstBus *bus;
306   GstMessage *message;
307
308   src = setup_filesrc ();
309   bus = gst_bus_new ();
310
311   gst_element_set_bus (src, bus);
312
313   g_object_set (G_OBJECT (src), "location", "/i/do/not/exist", NULL);
314   g_object_get (G_OBJECT (src), "location", &location, NULL);
315   fail_unless_equals_string (location, "/i/do/not/exist");
316   g_free (location);
317   fail_unless (gst_element_set_state (src,
318           GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE,
319       "could set to playing with wrong location");
320
321   /* a state change and an error */
322   fail_if ((message = gst_bus_pop (bus)) == NULL);
323   gst_message_unref (message);
324   fail_if ((message = gst_bus_pop (bus)) == NULL);
325   fail_unless_message_error (message, RESOURCE, NOT_FOUND);
326   gst_message_unref (message);
327
328   g_object_set (G_OBJECT (src), "location", NULL, NULL);
329   g_object_get (G_OBJECT (src), "location", &location, NULL);
330   fail_if (location);
331
332   /* cleanup */
333   gst_element_set_bus (src, NULL);
334   gst_object_unref (GST_OBJECT (bus));
335   cleanup_filesrc (src);
336 }
337
338 GST_END_TEST;
339
340 GST_START_TEST (test_uri_interface)
341 {
342   GstElement *src;
343   gchar *location;
344   GstBus *bus;
345   GstPad *pad;
346
347   src = setup_filesrc ();
348   bus = gst_bus_new ();
349
350   gst_element_set_bus (src, bus);
351
352   g_object_set (G_OBJECT (src), "location", NULL, NULL);
353   g_object_get (G_OBJECT (src), "location", &location, NULL);
354   fail_unless (location == NULL);
355
356   g_object_set (G_OBJECT (src), "location", "/i/do/not/exist", NULL);
357   g_object_get (G_OBJECT (src), "location", &location, NULL);
358   fail_unless_equals_string (location, "/i/do/not/exist");
359   g_free (location);
360
361   location = gst_uri_handler_get_uri (GST_URI_HANDLER (src));
362   fail_unless_equals_string (location, "file:///i/do/not/exist");
363   g_free (location);
364
365   /* should accept file:///foo/bar URIs */
366   fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (src),
367           "file:///foo/bar", NULL));
368   location = gst_uri_handler_get_uri (GST_URI_HANDLER (src));
369   fail_unless_equals_string (location, "file:///foo/bar");
370   g_free (location);
371   g_object_get (G_OBJECT (src), "location", &location, NULL);
372   fail_unless_equals_string (location, "/foo/bar");
373   g_free (location);
374
375   /* should accept file://localhost/foo/bar URIs */
376   fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (src),
377           "file://localhost/foo/baz", NULL));
378   location = gst_uri_handler_get_uri (GST_URI_HANDLER (src));
379   fail_unless_equals_string (location, "file:///foo/baz");
380   g_free (location);
381   g_object_get (G_OBJECT (src), "location", &location, NULL);
382   fail_unless_equals_string (location, "/foo/baz");
383   g_free (location);
384
385   /* should escape non-uri characters for the URI but not for the location */
386   g_object_set (G_OBJECT (src), "location", "/foo/b?r", NULL);
387   g_object_get (G_OBJECT (src), "location", &location, NULL);
388   fail_unless_equals_string (location, "/foo/b?r");
389   g_free (location);
390   location = gst_uri_handler_get_uri (GST_URI_HANDLER (src));
391   fail_unless_equals_string (location, "file:///foo/b%3Fr");
392   g_free (location);
393
394   /* should fail with other hostnames */
395   fail_if (gst_uri_handler_set_uri (GST_URI_HANDLER (src),
396           "file://hostname/foo/foo", NULL));
397
398   g_object_set (G_OBJECT (src), "location", TESTFILE, NULL);
399
400   pad = gst_element_get_static_pad (src, "src");
401   fail_unless (pad != NULL);
402   fail_unless (gst_pad_activate_mode (pad, GST_PAD_MODE_PULL, TRUE));
403   gst_object_unref (pad);
404
405   fail_unless (gst_element_set_state (src,
406           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
407       "could not set to playing");
408
409   ASSERT_WARNING (g_object_set (G_OBJECT (src), "location", "/wrong", NULL));
410   g_object_get (G_OBJECT (src), "location", &location, NULL);
411   fail_unless_equals_string (location, TESTFILE);
412   g_free (location);
413
414   fail_unless (gst_element_set_state (src,
415           GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
416
417   /* cleanup */
418   gst_element_set_bus (src, NULL);
419   gst_object_unref (GST_OBJECT (bus));
420   cleanup_filesrc (src);
421 }
422
423 GST_END_TEST;
424
425 #ifdef G_OS_UNIX
426 static void
427 check_uri_for_uri (GstElement * e, const gchar * in_uri, const gchar * uri)
428 {
429   GstQuery *query;
430   gchar *query_uri = NULL;
431
432   gst_uri_handler_set_uri (GST_URI_HANDLER (e), in_uri, NULL);
433
434   query = gst_query_new_uri ();
435   fail_unless (gst_element_query (e, query));
436   gst_query_parse_uri (query, &query_uri);
437   gst_query_unref (query);
438
439   if (uri != NULL) {
440     fail_unless_equals_string (query_uri, uri);
441   } else {
442     gchar *fn;
443
444     fail_unless (gst_uri_is_valid (query_uri));
445     fn = g_filename_from_uri (query_uri, NULL, NULL);
446     fail_unless (g_path_is_absolute (fn));
447     fail_unless (fn != NULL);
448     g_free (fn);
449   }
450
451   g_free (query_uri);
452 }
453
454 static void
455 check_uri_for_location (GstElement * e, const gchar * location,
456     const gchar * uri)
457 {
458   GstQuery *query;
459   gchar *query_uri = NULL;
460
461   g_object_set (e, "location", location, NULL);
462   query = gst_query_new_uri ();
463   fail_unless (gst_element_query (e, query));
464   gst_query_parse_uri (query, &query_uri);
465   gst_query_unref (query);
466
467   if (uri != NULL) {
468     fail_unless_equals_string (query_uri, uri);
469   } else {
470     gchar *fn;
471
472     fail_unless (gst_uri_is_valid (query_uri));
473     fn = g_filename_from_uri (query_uri, NULL, NULL);
474     fail_unless (g_path_is_absolute (fn));
475     fail_unless (fn != NULL);
476     g_free (fn);
477   }
478
479   g_free (query_uri);
480 }
481 #endif
482
483 GST_START_TEST (test_uri_query)
484 {
485   GstElement *src;
486
487   src = setup_filesrc ();
488
489 #ifdef G_OS_UNIX
490   {
491     GST_INFO ("*nix");
492     check_uri_for_location (src, "/i/do/not/exist", "file:///i/do/not/exist");
493     check_uri_for_location (src, "/i/do/not/../exist", "file:///i/do/exist");
494     check_uri_for_location (src, "/i/do/not/.././exist", "file:///i/do/exist");
495     check_uri_for_location (src, "/i/./do/not/../exist", "file:///i/do/exist");
496     check_uri_for_location (src, "/i/do/./not/../exist", "file:///i/do/exist");
497     check_uri_for_location (src, "/i/do/not/./../exist", "file:///i/do/exist");
498     check_uri_for_location (src, "/i/./do/./././././exist",
499         "file:///i/do/exist");
500     check_uri_for_location (src, "/i/do/not/../../exist", "file:///i/exist");
501     check_uri_for_location (src, "/i/../not/../exist", "file:///exist");
502     /* hard to test relative URIs, just make sure it returns an URI of sorts */
503     check_uri_for_location (src, "foo", NULL);
504     check_uri_for_location (src, "foo/../bar", NULL);
505     check_uri_for_location (src, "./foo", NULL);
506     check_uri_for_location (src, "../foo", NULL);
507     check_uri_for_location (src, "foo/./bar", NULL);
508     /* make sure non-ASCII characters are escaped properly (U+00F6 here) */
509     check_uri_for_location (src, "/i/./d\303\266/not/../exist",
510         "file:///i/d%C3%B6/exist");
511     /* let's see what happens if we set a malformed URI with ISO-8859-1 chars,
512      * i.e. one that the input characters haven't been escaped properly. We
513      * should get back a properly escaped URI */
514     check_uri_for_uri (src, "file:///M\366t\366r", "file:///M%F6t%F6r");
515   }
516 #endif
517
518   cleanup_filesrc (src);
519 }
520
521 GST_END_TEST;
522
523 static Suite *
524 filesrc_suite (void)
525 {
526   Suite *s = suite_create ("filesrc");
527   TCase *tc_chain = tcase_create ("general");
528
529   suite_add_tcase (s, tc_chain);
530   tcase_add_test (tc_chain, test_seeking);
531   tcase_add_test (tc_chain, test_reverse);
532   tcase_add_test (tc_chain, test_pull);
533   tcase_add_test (tc_chain, test_coverage);
534   tcase_add_test (tc_chain, test_uri_interface);
535   tcase_add_test (tc_chain, test_uri_query);
536
537   return s;
538 }
539
540 GST_CHECK_MAIN (filesrc);