1 /* GStreamer |
|
2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> |
|
3 * 2000 Wim Taymans <wtay@chello.be> |
|
4 * 2001 Bastien Nocera <hadess@hadess.net> |
|
5 * 2003 Colin Walters <walters@verbum.org> |
|
6 * 2005 Tim-Philipp Müller <tim centricular net> |
|
7 * |
|
8 * gstgnomevfssink.c: |
|
9 * |
|
10 * This library is free software; you can redistribute it and/or |
|
11 * modify it under the terms of the GNU Library General Public |
|
12 * License as published by the Free Software Foundation; either |
|
13 * version 2 of the License, or (at your option) any later version. |
|
14 * |
|
15 * This library is distributed in the hope that it will be useful, |
|
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
18 * Library General Public License for more details. |
|
19 * |
|
20 * You should have received a copy of the GNU Library General Public |
|
21 * License along with this library; if not, write to the |
|
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|
23 * Boston, MA 02111-1307, USA. |
|
24 */ |
|
25 |
|
26 /** |
|
27 * SECTION:element-gnomevfssink |
|
28 * @short_description: Write a stream to a GnomeVFS URI |
|
29 * @see_also: #GstFileSink, #GstGnomeVFSSrc |
|
30 * |
|
31 * <refsect2> |
|
32 * <para> |
|
33 * This plugin writes incoming data to a local or remote location specified |
|
34 * by an URI. This location can be specified using any protocol supported by |
|
35 * the GnomeVFS library. Common protocols are 'file', 'ftp', or 'smb'. |
|
36 * </para> |
|
37 * <para> |
|
38 * Example pipeline: |
|
39 * <programlisting> |
|
40 * gst-launch -v filesrc location=input.xyz ! gnomevfssink location=file:///home/joe/out.xyz |
|
41 * </programlisting> |
|
42 * The above pipeline will simply copy a local file. Instead of gnomevfssink, |
|
43 * we could just as well have used the filesink element here. |
|
44 * </para> |
|
45 * <para> |
|
46 * Another example pipeline: |
|
47 * <programlisting> |
|
48 * gst-launch -v filesrc location=foo.mp3 ! mad ! flacenc ! gnomevfssink location=smb://othercomputer/foo.flac |
|
49 * </programlisting> |
|
50 * The above pipeline will re-encode an mp3 file into FLAC format and store |
|
51 * it on a remote host using the Samba protocol. |
|
52 * </para> |
|
53 * <para> |
|
54 * Applications can connect to the allow-overwrite signal to receive a callback when an |
|
55 * existing file will be overwritten. The return value of the signal will determine if |
|
56 * gnomevfssink will overwrite the resource or abort with an error. |
|
57 * </para> |
|
58 * </refsect2> |
|
59 * |
|
60 * Last reviewed on 2006-02-28 (0.10.4) |
|
61 */ |
|
62 |
|
63 #ifdef HAVE_CONFIG_H |
|
64 #include "config.h" |
|
65 #endif |
|
66 |
|
67 #include "gstgnomevfssink.h" |
|
68 |
|
69 #include "gst/gst-i18n-plugin.h" |
|
70 |
|
71 #include <gst/gst.h> |
|
72 #include <libgnomevfs/gnome-vfs.h> |
|
73 #include <string.h> |
|
74 #include <errno.h> |
|
75 |
|
76 static const GstElementDetails gst_gnome_vfs_sink_details = |
|
77 GST_ELEMENT_DETAILS ("GnomeVFS Sink", |
|
78 "Sink/File", |
|
79 "Write a stream to a GnomeVFS URI", |
|
80 "Bastien Nocera <hadess@hadess.net>"); |
|
81 |
|
82 enum |
|
83 { |
|
84 SIGNAL_ERASE_ASK, |
|
85 LAST_SIGNAL |
|
86 }; |
|
87 |
|
88 enum |
|
89 { |
|
90 ARG_0, |
|
91 ARG_LOCATION, |
|
92 ARG_URI, |
|
93 ARG_HANDLE |
|
94 }; |
|
95 |
|
96 static void gst_gnome_vfs_sink_finalize (GObject * obj); |
|
97 |
|
98 static void gst_gnome_vfs_sink_uri_handler_init (gpointer g_iface, |
|
99 gpointer iface_data); |
|
100 |
|
101 static void gst_gnome_vfs_sink_set_property (GObject * object, guint prop_id, |
|
102 const GValue * value, GParamSpec * pspec); |
|
103 static void gst_gnome_vfs_sink_get_property (GObject * object, guint prop_id, |
|
104 GValue * value, GParamSpec * pspec); |
|
105 |
|
106 static gboolean gst_gnome_vfs_sink_open_file (GstGnomeVFSSink * sink); |
|
107 static void gst_gnome_vfs_sink_close_file (GstGnomeVFSSink * sink); |
|
108 static gboolean gst_gnome_vfs_sink_start (GstBaseSink * basesink); |
|
109 static gboolean gst_gnome_vfs_sink_stop (GstBaseSink * basesink); |
|
110 static GstFlowReturn gst_gnome_vfs_sink_render (GstBaseSink * basesink, |
|
111 GstBuffer * buffer); |
|
112 static gboolean gst_gnome_vfs_sink_handle_event (GstBaseSink * basesink, |
|
113 GstEvent * event); |
|
114 static gboolean gst_gnome_vfs_sink_query (GstPad * pad, GstQuery * query); |
|
115 |
|
116 static guint gst_gnome_vfs_sink_signals[LAST_SIGNAL]; /* all 0 */ |
|
117 |
|
118 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", |
|
119 GST_PAD_SINK, |
|
120 GST_PAD_ALWAYS, |
|
121 GST_STATIC_CAPS_ANY); |
|
122 |
|
123 GST_DEBUG_CATEGORY_STATIC (gst_gnome_vfs_sink_debug); |
|
124 #define GST_CAT_DEFAULT gst_gnome_vfs_sink_debug |
|
125 |
|
126 static void |
|
127 gst_gnome_vfs_sink_do_init (GType type) |
|
128 { |
|
129 static const GInterfaceInfo urihandler_info = { |
|
130 gst_gnome_vfs_sink_uri_handler_init, |
|
131 NULL, |
|
132 NULL |
|
133 }; |
|
134 |
|
135 g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info); |
|
136 |
|
137 GST_DEBUG_CATEGORY_INIT (gst_gnome_vfs_sink_debug, "gnomevfssink", 0, |
|
138 "Gnome VFS sink element"); |
|
139 } |
|
140 |
|
141 GST_BOILERPLATE_FULL (GstGnomeVFSSink, gst_gnome_vfs_sink, GstBaseSink, |
|
142 GST_TYPE_BASE_SINK, gst_gnome_vfs_sink_do_init); |
|
143 |
|
144 static void |
|
145 gst_gnome_vfs_sink_base_init (gpointer g_class) |
|
146 { |
|
147 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); |
|
148 |
|
149 gst_element_class_add_pad_template (element_class, |
|
150 gst_static_pad_template_get (&sinktemplate)); |
|
151 |
|
152 gst_element_class_set_details (element_class, &gst_gnome_vfs_sink_details); |
|
153 } |
|
154 |
|
155 static gboolean |
|
156 _gst_boolean_allow_overwrite_accumulator (GSignalInvocationHint * ihint, |
|
157 GValue * return_accu, const GValue * handler_return, gpointer dummy) |
|
158 { |
|
159 gboolean allow_overwrite; |
|
160 |
|
161 allow_overwrite = g_value_get_boolean (handler_return); |
|
162 if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP)) |
|
163 g_value_set_boolean (return_accu, allow_overwrite); |
|
164 |
|
165 /* stop emission if signal doesn't allow overwriting */ |
|
166 return allow_overwrite; |
|
167 } |
|
168 |
|
169 static void |
|
170 gst_gnome_vfs_sink_class_init (GstGnomeVFSSinkClass * klass) |
|
171 { |
|
172 GstBaseSinkClass *basesink_class; |
|
173 GObjectClass *gobject_class; |
|
174 |
|
175 gobject_class = (GObjectClass *) klass; |
|
176 basesink_class = (GstBaseSinkClass *) klass; |
|
177 |
|
178 gobject_class->set_property = gst_gnome_vfs_sink_set_property; |
|
179 gobject_class->get_property = gst_gnome_vfs_sink_get_property; |
|
180 gobject_class->finalize = gst_gnome_vfs_sink_finalize; |
|
181 |
|
182 g_object_class_install_property (gobject_class, ARG_LOCATION, |
|
183 g_param_spec_string ("location", "File Location", |
|
184 "Location of the file to write", NULL, G_PARAM_READWRITE)); |
|
185 g_object_class_install_property (gobject_class, ARG_URI, |
|
186 g_param_spec_boxed ("uri", "GnomeVFSURI", "URI for GnomeVFS", |
|
187 GST_TYPE_GNOME_VFS_URI, G_PARAM_READWRITE)); |
|
188 g_object_class_install_property (gobject_class, ARG_HANDLE, |
|
189 g_param_spec_boxed ("handle", |
|
190 "GnomeVFSHandle", "Handle for GnomeVFS", |
|
191 GST_TYPE_GNOME_VFS_HANDLE, G_PARAM_READWRITE)); |
|
192 |
|
193 /** |
|
194 * GstGnomeVFSSink::allow-overwrite |
|
195 * @sink: the object which received the signal |
|
196 * @uri: the URI to be overwritten |
|
197 * |
|
198 * This signal is fired when gnomevfssink is about to overwrite an |
|
199 * existing resource. The application can connect to this signal and ask |
|
200 * the user if the resource may be overwritten. |
|
201 * |
|
202 * Returns: A boolean indicating that the resource may be overwritten. |
|
203 */ |
|
204 gst_gnome_vfs_sink_signals[SIGNAL_ERASE_ASK] = |
|
205 g_signal_new ("allow-overwrite", G_TYPE_FROM_CLASS (klass), |
|
206 G_SIGNAL_RUN_CLEANUP, G_STRUCT_OFFSET (GstGnomeVFSSinkClass, erase_ask), |
|
207 _gst_boolean_allow_overwrite_accumulator, NULL, |
|
208 gst_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, GST_TYPE_GNOME_VFS_URI); |
|
209 |
|
210 basesink_class->stop = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_stop); |
|
211 basesink_class->start = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_start); |
|
212 basesink_class->event = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_handle_event); |
|
213 basesink_class->render = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_render); |
|
214 basesink_class->get_times = NULL; |
|
215 } |
|
216 |
|
217 static void |
|
218 gst_gnome_vfs_sink_finalize (GObject * obj) |
|
219 { |
|
220 GstGnomeVFSSink *sink = GST_GNOME_VFS_SINK (obj); |
|
221 |
|
222 if (sink->uri) { |
|
223 gnome_vfs_uri_unref (sink->uri); |
|
224 sink->uri = NULL; |
|
225 } |
|
226 |
|
227 if (sink->uri_name) { |
|
228 g_free (sink->uri_name); |
|
229 sink->uri_name = NULL; |
|
230 } |
|
231 |
|
232 G_OBJECT_CLASS (parent_class)->finalize (obj); |
|
233 } |
|
234 |
|
235 static void |
|
236 gst_gnome_vfs_sink_init (GstGnomeVFSSink * sink, GstGnomeVFSSinkClass * klass) |
|
237 { |
|
238 gst_pad_set_query_function (GST_BASE_SINK_PAD (sink), |
|
239 GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_query)); |
|
240 |
|
241 sink->uri = NULL; |
|
242 sink->uri_name = NULL; |
|
243 sink->handle = NULL; |
|
244 sink->own_handle = FALSE; |
|
245 sink->current_pos = 0; |
|
246 |
|
247 GST_BASE_SINK (sink)->sync = FALSE; |
|
248 } |
|
249 |
|
250 static void |
|
251 gst_gnome_vfs_sink_set_property (GObject * object, guint prop_id, |
|
252 const GValue * value, GParamSpec * pspec) |
|
253 { |
|
254 GstGnomeVFSSink *sink; |
|
255 GstState cur_state; |
|
256 |
|
257 sink = GST_GNOME_VFS_SINK (object); |
|
258 |
|
259 gst_element_get_state (GST_ELEMENT (sink), &cur_state, NULL, 0); |
|
260 |
|
261 if (cur_state == GST_STATE_PLAYING || cur_state == GST_STATE_PAUSED) { |
|
262 GST_WARNING_OBJECT (sink, "cannot set property when PAUSED or PLAYING"); |
|
263 return; |
|
264 } |
|
265 |
|
266 GST_OBJECT_LOCK (sink); |
|
267 |
|
268 switch (prop_id) { |
|
269 case ARG_LOCATION:{ |
|
270 const gchar *new_location; |
|
271 |
|
272 if (sink->uri) { |
|
273 gnome_vfs_uri_unref (sink->uri); |
|
274 sink->uri = NULL; |
|
275 } |
|
276 if (sink->uri_name) { |
|
277 g_free (sink->uri_name); |
|
278 sink->uri_name = NULL; |
|
279 } |
|
280 |
|
281 new_location = g_value_get_string (value); |
|
282 if (new_location) { |
|
283 sink->uri_name = gst_gnome_vfs_location_to_uri_string (new_location); |
|
284 sink->uri = gnome_vfs_uri_new (sink->uri_name); |
|
285 } |
|
286 break; |
|
287 } |
|
288 case ARG_URI:{ |
|
289 if (sink->uri) { |
|
290 gnome_vfs_uri_unref (sink->uri); |
|
291 sink->uri = NULL; |
|
292 } |
|
293 if (sink->uri_name) { |
|
294 g_free (sink->uri_name); |
|
295 sink->uri_name = NULL; |
|
296 } |
|
297 if (g_value_get_boxed (value)) { |
|
298 sink->uri = (GnomeVFSURI *) g_value_dup_boxed (value); |
|
299 sink->uri_name = gnome_vfs_uri_to_string (sink->uri, 0); |
|
300 } |
|
301 break; |
|
302 } |
|
303 case ARG_HANDLE:{ |
|
304 if (sink->uri) { |
|
305 gnome_vfs_uri_unref (sink->uri); |
|
306 sink->uri = NULL; |
|
307 } |
|
308 if (sink->uri_name) { |
|
309 g_free (sink->uri_name); |
|
310 sink->uri_name = NULL; |
|
311 } |
|
312 sink->handle = g_value_get_boxed (value); |
|
313 break; |
|
314 } |
|
315 default: |
|
316 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
|
317 break; |
|
318 } |
|
319 |
|
320 GST_OBJECT_UNLOCK (sink); |
|
321 } |
|
322 |
|
323 static void |
|
324 gst_gnome_vfs_sink_get_property (GObject * object, guint prop_id, |
|
325 GValue * value, GParamSpec * pspec) |
|
326 { |
|
327 GstGnomeVFSSink *sink; |
|
328 |
|
329 sink = GST_GNOME_VFS_SINK (object); |
|
330 |
|
331 GST_OBJECT_LOCK (sink); |
|
332 |
|
333 switch (prop_id) { |
|
334 case ARG_LOCATION: |
|
335 g_value_set_string (value, sink->uri_name); |
|
336 break; |
|
337 case ARG_URI: |
|
338 g_value_set_boxed (value, sink->uri); |
|
339 break; |
|
340 case ARG_HANDLE: |
|
341 g_value_set_boxed (value, sink->handle); |
|
342 break; |
|
343 default: |
|
344 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
|
345 break; |
|
346 } |
|
347 |
|
348 GST_OBJECT_UNLOCK (sink); |
|
349 } |
|
350 |
|
351 static gboolean |
|
352 gst_gnome_vfs_sink_open_file (GstGnomeVFSSink * sink) |
|
353 { |
|
354 GnomeVFSResult result; |
|
355 |
|
356 if (sink->uri) { |
|
357 /* open the file, all permissions, umask will apply */ |
|
358 result = gnome_vfs_create_uri (&(sink->handle), sink->uri, |
|
359 GNOME_VFS_OPEN_WRITE, TRUE, |
|
360 GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_USER_WRITE | |
|
361 GNOME_VFS_PERM_GROUP_READ | GNOME_VFS_PERM_GROUP_WRITE | |
|
362 GNOME_VFS_PERM_OTHER_READ | GNOME_VFS_PERM_OTHER_WRITE); |
|
363 |
|
364 /* if the file existed and the property says to ask, then ask! */ |
|
365 if (result == GNOME_VFS_ERROR_FILE_EXISTS) { |
|
366 gboolean erase_anyway = FALSE; |
|
367 |
|
368 g_signal_emit (G_OBJECT (sink), |
|
369 gst_gnome_vfs_sink_signals[SIGNAL_ERASE_ASK], 0, sink->uri, |
|
370 &erase_anyway); |
|
371 if (erase_anyway) { |
|
372 result = gnome_vfs_create_uri (&(sink->handle), sink->uri, |
|
373 GNOME_VFS_OPEN_WRITE, FALSE, |
|
374 GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_USER_WRITE | |
|
375 GNOME_VFS_PERM_GROUP_READ | GNOME_VFS_PERM_GROUP_WRITE | |
|
376 GNOME_VFS_PERM_OTHER_READ | GNOME_VFS_PERM_OTHER_WRITE); |
|
377 } |
|
378 } |
|
379 |
|
380 GST_DEBUG_OBJECT (sink, "open: %s", gnome_vfs_result_to_string (result)); |
|
381 |
|
382 if (result != GNOME_VFS_OK) { |
|
383 gchar *filename = gnome_vfs_uri_to_string (sink->uri, |
|
384 GNOME_VFS_URI_HIDE_PASSWORD); |
|
385 |
|
386 GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, |
|
387 (_("Could not open vfs file \"%s\" for writing: %s."), |
|
388 filename, gnome_vfs_result_to_string (result)), GST_ERROR_SYSTEM); |
|
389 g_free (filename); |
|
390 return FALSE; |
|
391 } |
|
392 sink->own_handle = TRUE; |
|
393 } else if (!sink->handle) { |
|
394 GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, (_("No filename given")), |
|
395 (NULL)); |
|
396 return FALSE; |
|
397 } else { |
|
398 sink->own_handle = FALSE; |
|
399 } |
|
400 |
|
401 sink->current_pos = 0; |
|
402 |
|
403 return TRUE; |
|
404 } |
|
405 |
|
406 static void |
|
407 gst_gnome_vfs_sink_close_file (GstGnomeVFSSink * sink) |
|
408 { |
|
409 GnomeVFSResult result; |
|
410 |
|
411 if (sink->own_handle) { |
|
412 /* close the file */ |
|
413 result = gnome_vfs_close (sink->handle); |
|
414 |
|
415 if (result != GNOME_VFS_OK) { |
|
416 gchar *filename = gnome_vfs_uri_to_string (sink->uri, |
|
417 GNOME_VFS_URI_HIDE_PASSWORD); |
|
418 |
|
419 GST_ELEMENT_ERROR (sink, RESOURCE, CLOSE, |
|
420 (_("Could not close vfs file \"%s\"."), filename), GST_ERROR_SYSTEM); |
|
421 g_free (filename); |
|
422 } |
|
423 |
|
424 sink->own_handle = FALSE; |
|
425 sink->handle = NULL; |
|
426 } |
|
427 } |
|
428 |
|
429 static gboolean |
|
430 gst_gnome_vfs_sink_start (GstBaseSink * basesink) |
|
431 { |
|
432 gboolean ret; |
|
433 |
|
434 ret = gst_gnome_vfs_sink_open_file (GST_GNOME_VFS_SINK (basesink)); |
|
435 |
|
436 return ret; |
|
437 } |
|
438 |
|
439 static gboolean |
|
440 gst_gnome_vfs_sink_stop (GstBaseSink * basesink) |
|
441 { |
|
442 GST_DEBUG_OBJECT (basesink, "closing ..."); |
|
443 gst_gnome_vfs_sink_close_file (GST_GNOME_VFS_SINK (basesink)); |
|
444 return TRUE; |
|
445 } |
|
446 |
|
447 static gboolean |
|
448 gst_gnome_vfs_sink_handle_event (GstBaseSink * basesink, GstEvent * event) |
|
449 { |
|
450 GstGnomeVFSSink *sink; |
|
451 gboolean ret = TRUE; |
|
452 |
|
453 sink = GST_GNOME_VFS_SINK (basesink); |
|
454 |
|
455 GST_DEBUG_OBJECT (sink, "processing %s event", GST_EVENT_TYPE_NAME (event)); |
|
456 |
|
457 switch (GST_EVENT_TYPE (event)) { |
|
458 case GST_EVENT_NEWSEGMENT:{ |
|
459 GnomeVFSResult res; |
|
460 GstFormat format; |
|
461 gint64 offset; |
|
462 |
|
463 gst_event_parse_new_segment (event, NULL, NULL, &format, &offset, |
|
464 NULL, NULL); |
|
465 |
|
466 if (format != GST_FORMAT_BYTES) { |
|
467 GST_WARNING_OBJECT (sink, "ignored NEWSEGMENT event in %s format", |
|
468 gst_format_get_name (format)); |
|
469 break; |
|
470 } |
|
471 |
|
472 GST_LOG_OBJECT (sink, "seeking to offset %" G_GINT64_FORMAT, offset); |
|
473 res = gnome_vfs_seek (sink->handle, GNOME_VFS_SEEK_START, offset); |
|
474 |
|
475 if (res != GNOME_VFS_OK) { |
|
476 GST_ERROR_OBJECT (sink, "Failed to seek to offset %" |
|
477 G_GINT64_FORMAT ": %s", offset, gnome_vfs_result_to_string (res)); |
|
478 ret = FALSE; |
|
479 } else { |
|
480 sink->current_pos = offset; |
|
481 } |
|
482 |
|
483 break; |
|
484 } |
|
485 |
|
486 case GST_EVENT_FLUSH_START: |
|
487 case GST_EVENT_EOS:{ |
|
488 /* No need to flush with GnomeVfs */ |
|
489 break; |
|
490 } |
|
491 default: |
|
492 break; |
|
493 } |
|
494 |
|
495 return ret; |
|
496 } |
|
497 |
|
498 static gboolean |
|
499 gst_gnome_vfs_sink_query (GstPad * pad, GstQuery * query) |
|
500 { |
|
501 GstGnomeVFSSink *sink; |
|
502 GstFormat format; |
|
503 |
|
504 sink = GST_GNOME_VFS_SINK (GST_PAD_PARENT (pad)); |
|
505 |
|
506 switch (GST_QUERY_TYPE (query)) { |
|
507 case GST_QUERY_POSITION: |
|
508 gst_query_parse_position (query, &format, NULL); |
|
509 switch (format) { |
|
510 case GST_FORMAT_DEFAULT: |
|
511 case GST_FORMAT_BYTES: |
|
512 gst_query_set_position (query, GST_FORMAT_BYTES, sink->current_pos); |
|
513 return TRUE; |
|
514 default: |
|
515 return FALSE; |
|
516 } |
|
517 |
|
518 case GST_QUERY_FORMATS: |
|
519 gst_query_set_formats (query, 2, GST_FORMAT_DEFAULT, GST_FORMAT_BYTES); |
|
520 return TRUE; |
|
521 |
|
522 default: |
|
523 return gst_pad_query_default (pad, query); |
|
524 } |
|
525 } |
|
526 |
|
527 static GstFlowReturn |
|
528 gst_gnome_vfs_sink_render (GstBaseSink * basesink, GstBuffer * buf) |
|
529 { |
|
530 GnomeVFSFileSize written, cur_pos; |
|
531 GstGnomeVFSSink *sink; |
|
532 GnomeVFSResult result; |
|
533 GstFlowReturn ret; |
|
534 |
|
535 sink = GST_GNOME_VFS_SINK (basesink); |
|
536 |
|
537 if (gnome_vfs_tell (sink->handle, &cur_pos) == GNOME_VFS_OK) { |
|
538 /* bring up to date with current position for proper reporting */ |
|
539 sink->current_pos = cur_pos; |
|
540 } |
|
541 |
|
542 result = gnome_vfs_write (sink->handle, GST_BUFFER_DATA (buf), |
|
543 GST_BUFFER_SIZE (buf), &written); |
|
544 |
|
545 switch (result) { |
|
546 case GNOME_VFS_OK:{ |
|
547 GST_DEBUG_OBJECT (sink, "wrote %" G_GINT64_FORMAT " bytes at %" |
|
548 G_GINT64_FORMAT, (gint64) written, (gint64) cur_pos); |
|
549 |
|
550 if (written < GST_BUFFER_SIZE (buf)) { |
|
551 /* FIXME: what to do here? (tpm) */ |
|
552 g_warning ("%s: %d bytes should be written, only %" |
|
553 G_GUINT64_FORMAT " bytes written", G_STRLOC, |
|
554 GST_BUFFER_SIZE (buf), written); |
|
555 } |
|
556 |
|
557 sink->current_pos += GST_BUFFER_SIZE (buf); |
|
558 ret = GST_FLOW_OK; |
|
559 break; |
|
560 } |
|
561 case GNOME_VFS_ERROR_NO_SPACE:{ |
|
562 /* TODO: emit signal/send msg on out-of-diskspace and |
|
563 * handle this gracefully (see open bug) (tpm) */ |
|
564 GST_ELEMENT_ERROR (sink, RESOURCE, NO_SPACE_LEFT, (NULL), |
|
565 ("bufsize=%u, written=%u", GST_BUFFER_SIZE (buf), (guint) written)); |
|
566 ret = GST_FLOW_ERROR; |
|
567 break; |
|
568 } |
|
569 default:{ |
|
570 gchar *filename = gnome_vfs_uri_to_string (sink->uri, |
|
571 GNOME_VFS_URI_HIDE_PASSWORD); |
|
572 |
|
573 GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, |
|
574 (_("Error while writing to file \"%s\"."), filename), |
|
575 ("%s, bufsize=%u, written=%u", gnome_vfs_result_to_string (result), |
|
576 GST_BUFFER_SIZE (buf), (guint) written)); |
|
577 |
|
578 g_free (filename); |
|
579 ret = GST_FLOW_ERROR; |
|
580 break; |
|
581 } |
|
582 } |
|
583 |
|
584 return GST_FLOW_OK; |
|
585 } |
|
586 |
|
587 /*** GSTURIHANDLER INTERFACE *************************************************/ |
|
588 |
|
589 static GstURIType |
|
590 gst_gnome_vfs_sink_uri_get_type (void) |
|
591 { |
|
592 return GST_URI_SINK; |
|
593 } |
|
594 |
|
595 static gchar ** |
|
596 gst_gnome_vfs_sink_uri_get_protocols (void) |
|
597 { |
|
598 static gchar **protocols = NULL; |
|
599 |
|
600 if (!protocols) |
|
601 protocols = gst_gnomevfs_get_supported_uris (); |
|
602 |
|
603 return protocols; |
|
604 } |
|
605 |
|
606 static const gchar * |
|
607 gst_gnome_vfs_sink_uri_get_uri (GstURIHandler * handler) |
|
608 { |
|
609 GstGnomeVFSSink *sink = GST_GNOME_VFS_SINK (handler); |
|
610 |
|
611 return sink->uri_name; |
|
612 } |
|
613 |
|
614 static gboolean |
|
615 gst_gnome_vfs_sink_uri_set_uri (GstURIHandler * handler, const gchar * uri) |
|
616 { |
|
617 GstGnomeVFSSink *sink = GST_GNOME_VFS_SINK (handler); |
|
618 GstState cur_state; |
|
619 |
|
620 gst_element_get_state (GST_ELEMENT (sink), &cur_state, NULL, 0); |
|
621 |
|
622 if (cur_state == GST_STATE_PLAYING || cur_state == GST_STATE_PAUSED) { |
|
623 GST_WARNING_OBJECT (sink, "cannot set uri when PAUSED or PLAYING"); |
|
624 return FALSE; |
|
625 } |
|
626 |
|
627 g_object_set (sink, "location", uri, NULL); |
|
628 |
|
629 return TRUE; |
|
630 } |
|
631 |
|
632 static void |
|
633 gst_gnome_vfs_sink_uri_handler_init (gpointer g_iface, gpointer iface_data) |
|
634 { |
|
635 GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; |
|
636 |
|
637 iface->get_type = gst_gnome_vfs_sink_uri_get_type; |
|
638 iface->get_protocols = gst_gnome_vfs_sink_uri_get_protocols; |
|
639 iface->get_uri = gst_gnome_vfs_sink_uri_get_uri; |
|
640 iface->set_uri = gst_gnome_vfs_sink_uri_set_uri; |
|
641 } |
|