6817395c6dc9c9bbedeba4754f3a8d7a8dbdebbb
[platform/upstream/gstreamer.git] / tests / check / elements / filesink.c
1 /* GStreamer unit test for the filesink element
2  *
3  * Copyright (C) 2006 Thomas Vander Stichele <thomas at apestaart dot org>
4  * Copyright (C) 2007 Tim-Philipp Müller <tim centricular net>
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., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <stdio.h>
27
28 #include <glib.h>
29 #include <glib/gstdio.h>
30
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>             /* for close() */
33 #endif
34
35 #include <gst/check/gstcheck.h>
36
37 static GstPad *mysrcpad;
38
39 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
40     GST_PAD_SRC,
41     GST_PAD_ALWAYS,
42     GST_STATIC_CAPS_ANY);
43
44 static GstElement *
45 setup_filesink (void)
46 {
47   GstElement *filesink;
48
49   GST_DEBUG ("setup_filesink");
50   filesink = gst_check_setup_element ("filesink");
51   mysrcpad = gst_check_setup_src_pad (filesink, &srctemplate, NULL);
52   gst_pad_set_active (mysrcpad, TRUE);
53   return filesink;
54 }
55
56 static void
57 cleanup_filesink (GstElement * filesink)
58 {
59   gst_pad_set_active (mysrcpad, FALSE);
60   gst_check_teardown_src_pad (filesink);
61   gst_check_teardown_element (filesink);
62 }
63
64 #if 0
65 /* this queries via the element vfunc, which is currently not implemented */
66 #define CHECK_QUERY_POSITION(filesink,format,position)                  \
67     G_STMT_START {                                                       \
68       GstFormat fmt = format;                                            \
69       gint64 pos;                                                        \
70       fail_unless (gst_element_query_position (filesink, &fmt, &pos));   \
71       fail_unless_equals_int (pos, position);                            \
72     } G_STMT_END
73 #else
74 #define CHECK_QUERY_POSITION(filesink,format,position)                   \
75     G_STMT_START {                                                       \
76       GstFormat fmt = format;                                            \
77       GstPad *pad;                                                       \
78       gint64 pos;                                                        \
79       pad = gst_element_get_static_pad (filesink, "sink");               \
80       fail_unless (gst_pad_query_position (pad, &fmt, &pos));            \
81       fail_unless_equals_int (pos, position);                            \
82       gst_object_unref (pad);                                            \
83     } G_STMT_END
84 #endif
85
86 #define PUSH_BYTES(num_bytes)                                             \
87     G_STMT_START {                                                        \
88       GstBuffer *buf = gst_buffer_new_and_alloc(num_bytes);               \
89       GRand *rand = g_rand_new_with_seed (num_bytes);                     \
90       guint8 *data;                                                       \
91       guint i;                                                            \
92       data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);             \
93       for (i = 0; i < num_bytes; ++i)                                     \
94         data[i] = (g_rand_int (rand) >> 24) & 0xff;                       \
95       gst_buffer_unmap (buf, data, num_bytes);                            \
96       fail_unless_equals_int (gst_pad_push (mysrcpad, buf), GST_FLOW_OK); \
97       g_rand_free (rand);                                                 \
98     } G_STMT_END
99
100 /* TODO: we don't check that the data is actually written to the right
101  * position after a seek */
102 GST_START_TEST (test_seeking)
103 {
104   const gchar *tmpdir;
105   GstElement *filesink;
106   gchar *tmp_fn;
107   gint fd;
108
109   tmpdir = g_get_tmp_dir ();
110   if (tmpdir == NULL)
111     return;
112
113   /* this is just silly, but gcc warns if we try to use tpmnam() */
114   tmp_fn = g_build_filename (tmpdir, "gstreamer-filesink-test-XXXXXX", NULL);
115   fd = g_mkstemp (tmp_fn);
116   if (fd < 0) {
117     GST_ERROR ("can't create temp file %s: %s", tmp_fn, g_strerror (errno));
118     g_free (tmp_fn);
119     return;
120   }
121   /* don't want the file, just a filename (hence silly, see above) */
122   close (fd);
123   g_remove (tmp_fn);
124
125   filesink = setup_filesink ();
126
127   GST_LOG ("using temp file '%s'", tmp_fn);
128   g_object_set (filesink, "location", tmp_fn, NULL);
129
130   fail_unless_equals_int (gst_element_set_state (filesink, GST_STATE_PLAYING),
131       GST_STATE_CHANGE_ASYNC);
132
133 #if 0
134   /* Test that filesink is seekable with a file fd */
135   /* filesink doesn't implement seekable query at the moment */
136   GstQuery *seeking_query;
137   gboolean seekable;
138
139   fail_unless ((seeking_query = gst_query_new_seeking (GST_FORMAT_BYTES))
140       != NULL);
141   fail_unless (gst_element_query (filesink, seeking_query) == TRUE);
142   gst_query_parse_seeking (seeking_query, NULL, &seekable, NULL, NULL);
143   fail_unless (seekable == TRUE);
144   gst_query_unref (seeking_query);
145 #endif
146
147   fail_unless (gst_pad_push_event (mysrcpad,
148           gst_event_new_new_segment (FALSE, 1.0, 1.0, GST_FORMAT_BYTES, 0, -1,
149               0)));
150
151   CHECK_QUERY_POSITION (filesink, GST_FORMAT_BYTES, 0);
152
153   /* push buffer with size 0 and NULL data */
154   PUSH_BYTES (0);
155   CHECK_QUERY_POSITION (filesink, GST_FORMAT_BYTES, 0);
156
157   PUSH_BYTES (1);
158   CHECK_QUERY_POSITION (filesink, GST_FORMAT_BYTES, 1);
159
160   PUSH_BYTES (99);
161   CHECK_QUERY_POSITION (filesink, GST_FORMAT_BYTES, 100);
162
163   PUSH_BYTES (8800);
164   CHECK_QUERY_POSITION (filesink, GST_FORMAT_BYTES, 8900);
165
166   if (gst_pad_push_event (mysrcpad,
167           gst_event_new_new_segment (TRUE, 1.0, 1.0, GST_FORMAT_BYTES, 8800, -1,
168               0))) {
169     GST_LOG ("seek ok");
170     /* make sure that that new position is reported immediately */
171     CHECK_QUERY_POSITION (filesink, GST_FORMAT_BYTES, 8800);
172     PUSH_BYTES (1);
173     CHECK_QUERY_POSITION (filesink, GST_FORMAT_BYTES, 8801);
174     PUSH_BYTES (9256);
175     CHECK_QUERY_POSITION (filesink, GST_FORMAT_BYTES, 18057);
176   } else {
177     GST_INFO ("seeking not supported for tempfile?!");
178   }
179
180   fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
181
182   fail_unless_equals_int (gst_element_set_state (filesink, GST_STATE_NULL),
183       GST_STATE_CHANGE_SUCCESS);
184
185   /* cleanup */
186   cleanup_filesink (filesink);
187
188   /* check that we wrote data to the right position after the seek */
189   {
190     gchar *data = NULL;
191     gsize len;
192
193     fail_unless (g_file_get_contents (tmp_fn, &data, &len, NULL),
194         "Failed to read in newly-created file '%s'", tmp_fn);
195     fail_unless_equals_int (len, 18057);
196     {
197       /* we wrote 9256 bytes at position 8801 */
198       GRand *rand = g_rand_new_with_seed (9256);
199       guint i;
200
201       for (i = 0; i < 9256; ++i) {
202         guint8 byte_written = *(((guint8 *) data) + 8801 + i);
203
204         fail_unless_equals_int (byte_written, g_rand_int (rand) >> 24);
205       }
206       g_rand_free (rand);
207     }
208     g_free (data);
209   }
210
211   /* remove file */
212   g_remove (tmp_fn);
213   g_free (tmp_fn);
214 }
215
216 GST_END_TEST;
217
218 GST_START_TEST (test_coverage)
219 {
220   GstElement *filesink;
221   gchar *location;
222   GstBus *bus;
223   GstMessage *message;
224
225   filesink = setup_filesink ();
226   bus = gst_bus_new ();
227
228   gst_element_set_bus (filesink, bus);
229
230   g_object_set (filesink, "location", "/i/do/not/exist", NULL);
231   g_object_get (filesink, "location", &location, NULL);
232   fail_unless_equals_string (location, "/i/do/not/exist");
233   g_free (location);
234
235   fail_unless_equals_int (gst_element_set_state (filesink, GST_STATE_PLAYING),
236       GST_STATE_CHANGE_FAILURE);
237
238   /* a state change and an error */
239   fail_if ((message = gst_bus_pop (bus)) == NULL);
240   fail_unless_message_error (message, RESOURCE, OPEN_WRITE);
241   gst_message_unref (message);
242
243   g_object_set (filesink, "location", NULL, NULL);
244   g_object_get (filesink, "location", &location, NULL);
245   fail_if (location);
246
247   /* cleanup */
248   gst_element_set_bus (filesink, NULL);
249   gst_object_unref (GST_OBJECT (bus));
250   cleanup_filesink (filesink);
251 }
252
253 GST_END_TEST;
254
255 GST_START_TEST (test_uri_interface)
256 {
257   GstElement *filesink;
258   gchar *location;
259   GstBus *bus;
260
261   filesink = setup_filesink ();
262   bus = gst_bus_new ();
263
264   gst_element_set_bus (filesink, bus);
265
266   g_object_set (G_OBJECT (filesink), "location", "/i/do/not/exist", NULL);
267   g_object_get (G_OBJECT (filesink), "location", &location, NULL);
268   fail_unless_equals_string (location, "/i/do/not/exist");
269   g_free (location);
270
271   location = (gchar *) gst_uri_handler_get_uri (GST_URI_HANDLER (filesink));
272   fail_unless_equals_string (location, "file:///i/do/not/exist");
273
274   /* should accept file:///foo/bar URIs */
275   fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (filesink),
276           "file:///foo/bar"));
277   location = (gchar *) gst_uri_handler_get_uri (GST_URI_HANDLER (filesink));
278   fail_unless_equals_string (location, "file:///foo/bar");
279   g_object_get (G_OBJECT (filesink), "location", &location, NULL);
280   fail_unless_equals_string (location, "/foo/bar");
281   g_free (location);
282
283   /* should accept file://localhost/foo/bar URIs */
284   fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (filesink),
285           "file://localhost/foo/baz"));
286   location = (gchar *) gst_uri_handler_get_uri (GST_URI_HANDLER (filesink));
287   fail_unless_equals_string (location, "file:///foo/baz");
288   g_object_get (G_OBJECT (filesink), "location", &location, NULL);
289   fail_unless_equals_string (location, "/foo/baz");
290   g_free (location);
291
292   /* should escape non-uri characters for the URI but not for the location */
293   g_object_set (G_OBJECT (filesink), "location", "/foo/b?r", NULL);
294   g_object_get (G_OBJECT (filesink), "location", &location, NULL);
295   fail_unless_equals_string (location, "/foo/b?r");
296   g_free (location);
297   location = (gchar *) gst_uri_handler_get_uri (GST_URI_HANDLER (filesink));
298   fail_unless_equals_string (location, "file:///foo/b%3Fr");
299
300   /* should fail with other hostnames */
301   fail_if (gst_uri_handler_set_uri (GST_URI_HANDLER (filesink),
302           "file://hostname/foo/foo"));
303
304   /* cleanup */
305   gst_element_set_bus (filesink, NULL);
306   gst_object_unref (GST_OBJECT (bus));
307   cleanup_filesink (filesink);
308 }
309
310 GST_END_TEST;
311
312 static Suite *
313 filesink_suite (void)
314 {
315   Suite *s = suite_create ("filesink");
316   TCase *tc_chain = tcase_create ("general");
317
318   suite_add_tcase (s, tc_chain);
319
320   tcase_add_test (tc_chain, test_coverage);
321   tcase_add_test (tc_chain, test_uri_interface);
322   tcase_add_test (tc_chain, test_seeking);
323
324   return s;
325 }
326
327 GST_CHECK_MAIN (filesink);