Rework GstSegment handling
[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   GstSegment segment;
109
110   tmpdir = g_get_tmp_dir ();
111   if (tmpdir == NULL)
112     return;
113
114   /* this is just silly, but gcc warns if we try to use tpmnam() */
115   tmp_fn = g_build_filename (tmpdir, "gstreamer-filesink-test-XXXXXX", NULL);
116   fd = g_mkstemp (tmp_fn);
117   if (fd < 0) {
118     GST_ERROR ("can't create temp file %s: %s", tmp_fn, g_strerror (errno));
119     g_free (tmp_fn);
120     return;
121   }
122   /* don't want the file, just a filename (hence silly, see above) */
123   close (fd);
124   g_remove (tmp_fn);
125
126   filesink = setup_filesink ();
127
128   GST_LOG ("using temp file '%s'", tmp_fn);
129   g_object_set (filesink, "location", tmp_fn, NULL);
130
131   fail_unless_equals_int (gst_element_set_state (filesink, GST_STATE_PLAYING),
132       GST_STATE_CHANGE_ASYNC);
133
134 #if 0
135   /* Test that filesink is seekable with a file fd */
136   /* filesink doesn't implement seekable query at the moment */
137   GstQuery *seeking_query;
138   gboolean seekable;
139
140   fail_unless ((seeking_query = gst_query_new_seeking (GST_FORMAT_BYTES))
141       != NULL);
142   fail_unless (gst_element_query (filesink, seeking_query) == TRUE);
143   gst_query_parse_seeking (seeking_query, NULL, &seekable, NULL, NULL);
144   fail_unless (seekable == TRUE);
145   gst_query_unref (seeking_query);
146 #endif
147
148   gst_segment_init (&segment, GST_FORMAT_BYTES);
149   fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
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   segment.start = 8800;
167   if (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment))) {
168     GST_LOG ("seek ok");
169     /* make sure that that new position is reported immediately */
170     CHECK_QUERY_POSITION (filesink, GST_FORMAT_BYTES, 8800);
171     PUSH_BYTES (1);
172     CHECK_QUERY_POSITION (filesink, GST_FORMAT_BYTES, 8801);
173     PUSH_BYTES (9256);
174     CHECK_QUERY_POSITION (filesink, GST_FORMAT_BYTES, 18057);
175   } else {
176     GST_INFO ("seeking not supported for tempfile?!");
177   }
178
179   fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
180
181   fail_unless_equals_int (gst_element_set_state (filesink, GST_STATE_NULL),
182       GST_STATE_CHANGE_SUCCESS);
183
184   /* cleanup */
185   cleanup_filesink (filesink);
186
187   /* check that we wrote data to the right position after the seek */
188   {
189     gchar *data = NULL;
190     gsize len;
191
192     fail_unless (g_file_get_contents (tmp_fn, &data, &len, NULL),
193         "Failed to read in newly-created file '%s'", tmp_fn);
194     fail_unless_equals_int (len, 18057);
195     {
196       /* we wrote 9256 bytes at position 8801 */
197       GRand *rand = g_rand_new_with_seed (9256);
198       guint i;
199
200       for (i = 0; i < 9256; ++i) {
201         guint8 byte_written = *(((guint8 *) data) + 8801 + i);
202
203         fail_unless_equals_int (byte_written, g_rand_int (rand) >> 24);
204       }
205       g_rand_free (rand);
206     }
207     g_free (data);
208   }
209
210   /* remove file */
211   g_remove (tmp_fn);
212   g_free (tmp_fn);
213 }
214
215 GST_END_TEST;
216
217 GST_START_TEST (test_coverage)
218 {
219   GstElement *filesink;
220   gchar *location;
221   GstBus *bus;
222   GstMessage *message;
223
224   filesink = setup_filesink ();
225   bus = gst_bus_new ();
226
227   gst_element_set_bus (filesink, bus);
228
229   g_object_set (filesink, "location", "/i/do/not/exist", NULL);
230   g_object_get (filesink, "location", &location, NULL);
231   fail_unless_equals_string (location, "/i/do/not/exist");
232   g_free (location);
233
234   fail_unless_equals_int (gst_element_set_state (filesink, GST_STATE_PLAYING),
235       GST_STATE_CHANGE_FAILURE);
236
237   /* a state change and an error */
238   fail_if ((message = gst_bus_pop (bus)) == NULL);
239   fail_unless_message_error (message, RESOURCE, OPEN_WRITE);
240   gst_message_unref (message);
241
242   g_object_set (filesink, "location", NULL, NULL);
243   g_object_get (filesink, "location", &location, NULL);
244   fail_if (location);
245
246   /* cleanup */
247   gst_element_set_bus (filesink, NULL);
248   gst_object_unref (GST_OBJECT (bus));
249   cleanup_filesink (filesink);
250 }
251
252 GST_END_TEST;
253
254 GST_START_TEST (test_uri_interface)
255 {
256   GstElement *filesink;
257   gchar *location;
258   GstBus *bus;
259
260   filesink = setup_filesink ();
261   bus = gst_bus_new ();
262
263   gst_element_set_bus (filesink, bus);
264
265   g_object_set (G_OBJECT (filesink), "location", "/i/do/not/exist", NULL);
266   g_object_get (G_OBJECT (filesink), "location", &location, NULL);
267   fail_unless_equals_string (location, "/i/do/not/exist");
268   g_free (location);
269
270   location = (gchar *) gst_uri_handler_get_uri (GST_URI_HANDLER (filesink));
271   fail_unless_equals_string (location, "file:///i/do/not/exist");
272
273   /* should accept file:///foo/bar URIs */
274   fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (filesink),
275           "file:///foo/bar"));
276   location = (gchar *) gst_uri_handler_get_uri (GST_URI_HANDLER (filesink));
277   fail_unless_equals_string (location, "file:///foo/bar");
278   g_object_get (G_OBJECT (filesink), "location", &location, NULL);
279   fail_unless_equals_string (location, "/foo/bar");
280   g_free (location);
281
282   /* should accept file://localhost/foo/bar URIs */
283   fail_unless (gst_uri_handler_set_uri (GST_URI_HANDLER (filesink),
284           "file://localhost/foo/baz"));
285   location = (gchar *) gst_uri_handler_get_uri (GST_URI_HANDLER (filesink));
286   fail_unless_equals_string (location, "file:///foo/baz");
287   g_object_get (G_OBJECT (filesink), "location", &location, NULL);
288   fail_unless_equals_string (location, "/foo/baz");
289   g_free (location);
290
291   /* should escape non-uri characters for the URI but not for the location */
292   g_object_set (G_OBJECT (filesink), "location", "/foo/b?r", NULL);
293   g_object_get (G_OBJECT (filesink), "location", &location, NULL);
294   fail_unless_equals_string (location, "/foo/b?r");
295   g_free (location);
296   location = (gchar *) gst_uri_handler_get_uri (GST_URI_HANDLER (filesink));
297   fail_unless_equals_string (location, "file:///foo/b%3Fr");
298
299   /* should fail with other hostnames */
300   fail_if (gst_uri_handler_set_uri (GST_URI_HANDLER (filesink),
301           "file://hostname/foo/foo"));
302
303   /* cleanup */
304   gst_element_set_bus (filesink, NULL);
305   gst_object_unref (GST_OBJECT (bus));
306   cleanup_filesink (filesink);
307 }
308
309 GST_END_TEST;
310
311 static Suite *
312 filesink_suite (void)
313 {
314   Suite *s = suite_create ("filesink");
315   TCase *tc_chain = tcase_create ("general");
316
317   suite_add_tcase (s, tc_chain);
318
319   tcase_add_test (tc_chain, test_coverage);
320   tcase_add_test (tc_chain, test_uri_interface);
321   tcase_add_test (tc_chain, test_seeking);
322
323   return s;
324 }
325
326 GST_CHECK_MAIN (filesink);