Branch data Line data Source code
1 : : /* GStreamer
2 : : * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 : : * 2000 Wim Taymans <wtay@chello.be>
4 : : *
5 : : * gstfdsink.c:
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Library General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Library General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Library General Public
18 : : * License along with this library; if not, write to the
19 : : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 : : * Boston, MA 02111-1307, USA.
21 : : */
22 : :
23 : : /**
24 : : * SECTION:element-fdsink
25 : : * @see_also: #GstFdSrc
26 : : *
27 : : * Write data to a unix file descriptor.
28 : : *
29 : : * This element will synchronize on the clock before writing the data on the
30 : : * socket. For file descriptors where this does not make sense (files, ...) the
31 : : * #GstBaseSink:sync property can be used to disable synchronisation.
32 : : *
33 : : * Last reviewed on 2006-04-28 (0.10.6)
34 : : */
35 : :
36 : : #ifdef HAVE_CONFIG_H
37 : : # include "config.h"
38 : : #endif
39 : :
40 : : #include "../../gst/gst-i18n-lib.h"
41 : :
42 : : #include <sys/types.h>
43 : :
44 : : #ifdef G_OS_WIN32
45 : : #include <io.h> /* lseek, open, close, read */
46 : : #undef lseek
47 : : #define lseek _lseeki64
48 : : #undef off_t
49 : : #define off_t guint64
50 : : #endif
51 : :
52 : : #include <sys/stat.h>
53 : : #ifdef HAVE_SYS_SOCKET_H
54 : : #include <sys/socket.h>
55 : : #endif
56 : : #include <fcntl.h>
57 : : #include <stdio.h>
58 : : #ifdef HAVE_UNISTD_H
59 : : #include <unistd.h>
60 : : #endif
61 : : #ifdef _MSC_VER
62 : : #undef stat
63 : : #define stat _stat
64 : : #define fstat _fstat
65 : : #define S_ISREG(m) (((m)&S_IFREG)==S_IFREG)
66 : : #endif
67 : : #include <errno.h>
68 : : #include <string.h>
69 : :
70 : : #include "gstfdsink.h"
71 : :
72 : : static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
73 : : GST_PAD_SINK,
74 : : GST_PAD_ALWAYS,
75 : : GST_STATIC_CAPS_ANY);
76 : :
77 : : GST_DEBUG_CATEGORY_STATIC (gst_fd_sink__debug);
78 : : #define GST_CAT_DEFAULT gst_fd_sink__debug
79 : :
80 : :
81 : : /* FdSink signals and args */
82 : : enum
83 : : {
84 : : /* FILL ME */
85 : : LAST_SIGNAL
86 : : };
87 : :
88 : : enum
89 : : {
90 : : ARG_0,
91 : : ARG_FD
92 : : };
93 : :
94 : : static void gst_fd_sink_uri_handler_init (gpointer g_iface,
95 : : gpointer iface_data);
96 : :
97 : : static void
98 : 153 : _do_init (GType gst_fd_sink_type)
99 : : {
100 : : static const GInterfaceInfo urihandler_info = {
101 : : gst_fd_sink_uri_handler_init,
102 : : NULL,
103 : : NULL
104 : : };
105 : :
106 : 153 : g_type_add_interface_static (gst_fd_sink_type, GST_TYPE_URI_HANDLER,
107 : : &urihandler_info);
108 : :
109 [ + - ]: 153 : GST_DEBUG_CATEGORY_INIT (gst_fd_sink__debug, "fdsink", 0, "fdsink element");
110 : 153 : }
111 : :
112 [ + + ]: 186 : GST_BOILERPLATE_FULL (GstFdSink, gst_fd_sink, GstBaseSink, GST_TYPE_BASE_SINK,
113 : 186 : _do_init);
114 : :
115 : : static void gst_fd_sink_set_property (GObject * object, guint prop_id,
116 : : const GValue * value, GParamSpec * pspec);
117 : : static void gst_fd_sink_get_property (GObject * object, guint prop_id,
118 : : GValue * value, GParamSpec * pspec);
119 : : static void gst_fd_sink_dispose (GObject * obj);
120 : :
121 : : static gboolean gst_fd_sink_query (GstPad * pad, GstQuery * query);
122 : : static GstFlowReturn gst_fd_sink_render (GstBaseSink * sink,
123 : : GstBuffer * buffer);
124 : : static gboolean gst_fd_sink_start (GstBaseSink * basesink);
125 : : static gboolean gst_fd_sink_stop (GstBaseSink * basesink);
126 : : static gboolean gst_fd_sink_unlock (GstBaseSink * basesink);
127 : : static gboolean gst_fd_sink_unlock_stop (GstBaseSink * basesink);
128 : : static gboolean gst_fd_sink_event (GstBaseSink * sink, GstEvent * event);
129 : :
130 : : static gboolean gst_fd_sink_do_seek (GstFdSink * fdsink, guint64 new_offset);
131 : :
132 : : static void
133 : 8 : gst_fd_sink_base_init (gpointer g_class)
134 : : {
135 : 8 : GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
136 : :
137 : 8 : gst_element_class_set_details_simple (gstelement_class,
138 : : "Filedescriptor Sink",
139 : : "Sink/File",
140 : : "Write data to a file descriptor", "Erik Walthinsen <omega@cse.ogi.edu>");
141 : 8 : gst_element_class_add_pad_template (gstelement_class,
142 : : gst_static_pad_template_get (&sinktemplate));
143 : 8 : }
144 : :
145 : : static void
146 : 8 : gst_fd_sink_class_init (GstFdSinkClass * klass)
147 : : {
148 : : GObjectClass *gobject_class;
149 : : GstBaseSinkClass *gstbasesink_class;
150 : :
151 : 8 : gobject_class = G_OBJECT_CLASS (klass);
152 : 8 : gstbasesink_class = GST_BASE_SINK_CLASS (klass);
153 : :
154 : 8 : gobject_class->set_property = gst_fd_sink_set_property;
155 : 8 : gobject_class->get_property = gst_fd_sink_get_property;
156 : 8 : gobject_class->dispose = gst_fd_sink_dispose;
157 : :
158 : 8 : gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_fd_sink_render);
159 : 8 : gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_fd_sink_start);
160 : 8 : gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_fd_sink_stop);
161 : 8 : gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_fd_sink_unlock);
162 : 8 : gstbasesink_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_fd_sink_unlock_stop);
163 : 8 : gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_fd_sink_event);
164 : :
165 : 8 : g_object_class_install_property (gobject_class, ARG_FD,
166 : : g_param_spec_int ("fd", "fd", "An open file descriptor to write to",
167 : : 0, G_MAXINT, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
168 : 8 : }
169 : :
170 : : static void
171 : 3 : gst_fd_sink_init (GstFdSink * fdsink, GstFdSinkClass * klass)
172 : : {
173 : : GstPad *pad;
174 : :
175 : 3 : pad = GST_BASE_SINK_PAD (fdsink);
176 : 3 : gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_fd_sink_query));
177 : :
178 : 3 : fdsink->fd = 1;
179 : 3 : fdsink->uri = g_strdup_printf ("fd://%d", fdsink->fd);
180 : 3 : fdsink->bytes_written = 0;
181 : 3 : fdsink->current_pos = 0;
182 : :
183 : 3 : gst_base_sink_set_sync (GST_BASE_SINK (fdsink), FALSE);
184 : 3 : }
185 : :
186 : : static void
187 : 3 : gst_fd_sink_dispose (GObject * obj)
188 : : {
189 : 3 : GstFdSink *fdsink = GST_FD_SINK (obj);
190 : :
191 : 3 : g_free (fdsink->uri);
192 : 3 : fdsink->uri = NULL;
193 : :
194 : 3 : G_OBJECT_CLASS (parent_class)->dispose (obj);
195 : 3 : }
196 : :
197 : : static gboolean
198 : 0 : gst_fd_sink_query (GstPad * pad, GstQuery * query)
199 : : {
200 : : GstFdSink *fdsink;
201 : : GstFormat format;
202 : :
203 : 0 : fdsink = GST_FD_SINK (GST_PAD_PARENT (pad));
204 : :
205 [ # # # # ]: 0 : switch (GST_QUERY_TYPE (query)) {
206 : : case GST_QUERY_POSITION:
207 : 0 : gst_query_parse_position (query, &format, NULL);
208 [ # # ]: 0 : switch (format) {
209 : : case GST_FORMAT_DEFAULT:
210 : : case GST_FORMAT_BYTES:
211 : 0 : gst_query_set_position (query, GST_FORMAT_BYTES, fdsink->current_pos);
212 : 0 : return TRUE;
213 : : default:
214 : 0 : return FALSE;
215 : : }
216 : :
217 : : case GST_QUERY_FORMATS:
218 : 0 : gst_query_set_formats (query, 2, GST_FORMAT_DEFAULT, GST_FORMAT_BYTES);
219 : 0 : return TRUE;
220 : :
221 : : case GST_QUERY_URI:
222 : 0 : gst_query_set_uri (query, fdsink->uri);
223 : 0 : return TRUE;
224 : :
225 : : default:
226 : 0 : return gst_pad_query_default (pad, query);
227 : : }
228 : : }
229 : :
230 : : static GstFlowReturn
231 : 0 : gst_fd_sink_render (GstBaseSink * sink, GstBuffer * buffer)
232 : : {
233 : : GstFdSink *fdsink;
234 : : guint8 *data;
235 : : guint size;
236 : : gint written;
237 : :
238 : : #ifndef HAVE_WIN32
239 : : gint retval;
240 : : #endif
241 : :
242 : 0 : fdsink = GST_FD_SINK (sink);
243 : :
244 [ # # ]: 0 : g_return_val_if_fail (fdsink->fd >= 0, GST_FLOW_ERROR);
245 : :
246 : 0 : data = GST_BUFFER_DATA (buffer);
247 : 0 : size = GST_BUFFER_SIZE (buffer);
248 : :
249 : : again:
250 : : #ifndef HAVE_WIN32
251 : : do {
252 [ # # ]: 0 : GST_DEBUG_OBJECT (fdsink, "going into select, have %d bytes to write",
253 : : size);
254 : 0 : retval = gst_poll_wait (fdsink->fdset, GST_CLOCK_TIME_NONE);
255 [ # # ][ # # ]: 0 : } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
[ # # ]
256 : :
257 [ # # ]: 0 : if (retval == -1) {
258 [ # # ]: 0 : if (errno == EBUSY)
259 : 0 : goto stopped;
260 : : else
261 : 0 : goto select_error;
262 : : }
263 : : #endif
264 : :
265 [ # # ]: 0 : GST_DEBUG_OBJECT (fdsink, "writing %d bytes to file descriptor %d", size,
266 : : fdsink->fd);
267 : :
268 : 0 : written = write (fdsink->fd, data, size);
269 : :
270 : : /* check for errors */
271 [ # # ]: 0 : if (G_UNLIKELY (written < 0)) {
272 : : /* try to write again on non-fatal errors */
273 [ # # ][ # # ]: 0 : if (errno == EAGAIN || errno == EINTR)
274 : : goto again;
275 : :
276 : : /* else go to our error handler */
277 : 0 : goto write_error;
278 : : }
279 : :
280 : : /* all is fine when we get here */
281 : 0 : size -= written;
282 : 0 : data += written;
283 : 0 : fdsink->bytes_written += written;
284 : 0 : fdsink->current_pos += written;
285 : :
286 [ # # ]: 0 : GST_DEBUG_OBJECT (fdsink, "wrote %d bytes, %d left", written, size);
287 : :
288 : : /* short write, select and try to write the remainder */
289 [ # # ]: 0 : if (G_UNLIKELY (size > 0))
290 : 0 : goto again;
291 : :
292 : 0 : return GST_FLOW_OK;
293 : :
294 : : #ifndef HAVE_WIN32
295 : : select_error:
296 : : {
297 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (fdsink, RESOURCE, READ, (NULL),
[ # # ][ # # ]
298 : : ("select on file descriptor: %s.", g_strerror (errno)));
299 [ # # ]: 0 : GST_DEBUG_OBJECT (fdsink, "Error during select");
300 : 0 : return GST_FLOW_ERROR;
301 : : }
302 : : stopped:
303 : : {
304 [ # # ]: 0 : GST_DEBUG_OBJECT (fdsink, "Select stopped");
305 : 0 : return GST_FLOW_WRONG_STATE;
306 : : }
307 : : #endif
308 : :
309 : : write_error:
310 : : {
311 [ # # ]: 0 : switch (errno) {
312 : : case ENOSPC:
313 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (fdsink, RESOURCE, NO_SPACE_LEFT, (NULL), (NULL));
[ # # ][ # # ]
314 : 0 : break;
315 : : default:{
316 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (fdsink, RESOURCE, WRITE, (NULL),
[ # # ][ # # ]
317 : : ("Error while writing to file descriptor %d: %s",
318 : : fdsink->fd, g_strerror (errno)));
319 : : }
320 : : }
321 : 0 : return GST_FLOW_ERROR;
322 : : }
323 : : }
324 : :
325 : : static gboolean
326 : 4 : gst_fd_sink_check_fd (GstFdSink * fdsink, int fd)
327 : : {
328 : : struct stat stat_results;
329 : : off_t result;
330 : :
331 : : /* see that it is a valid file descriptor */
332 [ - + ]: 4 : if (fstat (fd, &stat_results) < 0)
333 : 0 : goto invalid;
334 : :
335 [ + - ]: 4 : if (!S_ISREG (stat_results.st_mode))
336 : 4 : goto not_seekable;
337 : :
338 : : /* see if it is a seekable stream */
339 : 0 : result = lseek (fd, 0, SEEK_CUR);
340 [ # # ]: 0 : if (result == -1) {
341 [ # # # ]: 0 : switch (errno) {
342 : : case EINVAL:
343 : : case EBADF:
344 : 0 : goto invalid;
345 : :
346 : : case ESPIPE:
347 : 0 : goto not_seekable;
348 : : }
349 : : } else
350 [ # # ]: 0 : GST_DEBUG_OBJECT (fdsink, "File descriptor %d is seekable", fd);
351 : :
352 : 0 : return TRUE;
353 : :
354 : : invalid:
355 : : {
356 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (fdsink, RESOURCE, WRITE, (NULL),
[ # # ][ # # ]
357 : : ("File descriptor %d is not valid: %s", fd, g_strerror (errno)));
358 : 0 : return FALSE;
359 : : }
360 : : not_seekable:
361 : : {
362 [ - + ]: 4 : GST_DEBUG_OBJECT (fdsink, "File descriptor %d is a pipe", fd);
363 : 4 : return TRUE;
364 : : }
365 : : }
366 : :
367 : : static gboolean
368 : 4 : gst_fd_sink_start (GstBaseSink * basesink)
369 : : {
370 : : GstFdSink *fdsink;
371 : 4 : GstPollFD fd = GST_POLL_FD_INIT;
372 : :
373 : 4 : fdsink = GST_FD_SINK (basesink);
374 [ - + ]: 4 : if (!gst_fd_sink_check_fd (fdsink, fdsink->fd))
375 : 0 : return FALSE;
376 : :
377 [ - + ]: 4 : if ((fdsink->fdset = gst_poll_new (TRUE)) == NULL)
378 : 0 : goto socket_pair;
379 : :
380 : 4 : fd.fd = fdsink->fd;
381 : 4 : gst_poll_add_fd (fdsink->fdset, &fd);
382 : 4 : gst_poll_fd_ctl_write (fdsink->fdset, &fd, TRUE);
383 : :
384 : 4 : fdsink->bytes_written = 0;
385 : 4 : fdsink->current_pos = 0;
386 : :
387 : 4 : return TRUE;
388 : :
389 : : /* ERRORS */
390 : : socket_pair:
391 : : {
392 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (fdsink, RESOURCE, OPEN_READ_WRITE, (NULL),
[ # # ][ # # ]
393 : : GST_ERROR_SYSTEM);
394 : 4 : return FALSE;
395 : : }
396 : : }
397 : :
398 : : static gboolean
399 : 4 : gst_fd_sink_stop (GstBaseSink * basesink)
400 : : {
401 : 4 : GstFdSink *fdsink = GST_FD_SINK (basesink);
402 : :
403 [ + - ]: 4 : if (fdsink->fdset) {
404 : 4 : gst_poll_free (fdsink->fdset);
405 : 4 : fdsink->fdset = NULL;
406 : : }
407 : :
408 : 4 : return TRUE;
409 : : }
410 : :
411 : : static gboolean
412 : 7 : gst_fd_sink_unlock (GstBaseSink * basesink)
413 : : {
414 : 7 : GstFdSink *fdsink = GST_FD_SINK (basesink);
415 : :
416 [ - + ]: 7 : GST_LOG_OBJECT (fdsink, "Flushing");
417 : 7 : GST_OBJECT_LOCK (fdsink);
418 : 7 : gst_poll_set_flushing (fdsink->fdset, TRUE);
419 : 7 : GST_OBJECT_UNLOCK (fdsink);
420 : :
421 : 7 : return TRUE;
422 : : }
423 : :
424 : : static gboolean
425 : 7 : gst_fd_sink_unlock_stop (GstBaseSink * basesink)
426 : : {
427 : 7 : GstFdSink *fdsink = GST_FD_SINK (basesink);
428 : :
429 [ - + ]: 7 : GST_LOG_OBJECT (fdsink, "No longer flushing");
430 : 7 : GST_OBJECT_LOCK (fdsink);
431 : 7 : gst_poll_set_flushing (fdsink->fdset, FALSE);
432 : 7 : GST_OBJECT_UNLOCK (fdsink);
433 : :
434 : 7 : return TRUE;
435 : : }
436 : :
437 : : static gboolean
438 : 0 : gst_fd_sink_update_fd (GstFdSink * fdsink, int new_fd)
439 : : {
440 [ # # ]: 0 : if (new_fd < 0)
441 : 0 : return FALSE;
442 : :
443 [ # # ]: 0 : if (!gst_fd_sink_check_fd (fdsink, new_fd))
444 : 0 : goto invalid;
445 : :
446 : : /* assign the fd */
447 : 0 : GST_OBJECT_LOCK (fdsink);
448 [ # # ]: 0 : if (fdsink->fdset) {
449 : 0 : GstPollFD fd = GST_POLL_FD_INIT;
450 : :
451 : 0 : fd.fd = fdsink->fd;
452 : 0 : gst_poll_remove_fd (fdsink->fdset, &fd);
453 : :
454 : 0 : fd.fd = new_fd;
455 : 0 : gst_poll_add_fd (fdsink->fdset, &fd);
456 : 0 : gst_poll_fd_ctl_write (fdsink->fdset, &fd, TRUE);
457 : : }
458 : 0 : fdsink->fd = new_fd;
459 : 0 : g_free (fdsink->uri);
460 : 0 : fdsink->uri = g_strdup_printf ("fd://%d", fdsink->fd);
461 : :
462 : 0 : GST_OBJECT_UNLOCK (fdsink);
463 : :
464 : 0 : return TRUE;
465 : :
466 : : invalid:
467 : : {
468 : 0 : return FALSE;
469 : : }
470 : : }
471 : :
472 : : static void
473 : 0 : gst_fd_sink_set_property (GObject * object, guint prop_id,
474 : : const GValue * value, GParamSpec * pspec)
475 : : {
476 : : GstFdSink *fdsink;
477 : :
478 : 0 : fdsink = GST_FD_SINK (object);
479 : :
480 [ # # ]: 0 : switch (prop_id) {
481 : : case ARG_FD:{
482 : : int fd;
483 : :
484 : 0 : fd = g_value_get_int (value);
485 : 0 : gst_fd_sink_update_fd (fdsink, fd);
486 : 0 : break;
487 : : }
488 : : default:
489 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
490 : 0 : break;
491 : : }
492 : 0 : }
493 : :
494 : : static void
495 : 0 : gst_fd_sink_get_property (GObject * object, guint prop_id, GValue * value,
496 : : GParamSpec * pspec)
497 : : {
498 : : GstFdSink *fdsink;
499 : :
500 : 0 : fdsink = GST_FD_SINK (object);
501 : :
502 [ # # ]: 0 : switch (prop_id) {
503 : : case ARG_FD:
504 : 0 : g_value_set_int (value, fdsink->fd);
505 : 0 : break;
506 : : default:
507 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
508 : 0 : break;
509 : : }
510 : 0 : }
511 : :
512 : : static gboolean
513 : 0 : gst_fd_sink_do_seek (GstFdSink * fdsink, guint64 new_offset)
514 : : {
515 : : off_t result;
516 : :
517 : 0 : result = lseek (fdsink->fd, new_offset, SEEK_SET);
518 : :
519 [ # # ]: 0 : if (result == -1)
520 : 0 : goto seek_failed;
521 : :
522 : 0 : fdsink->current_pos = new_offset;
523 : :
524 [ # # ]: 0 : GST_DEBUG_OBJECT (fdsink, "File descriptor %d to seek to position "
525 : : "%" G_GUINT64_FORMAT, fdsink->fd, fdsink->current_pos);
526 : :
527 : 0 : return TRUE;
528 : :
529 : : /* ERRORS */
530 : : seek_failed:
531 : : {
532 [ # # ]: 0 : GST_DEBUG_OBJECT (fdsink, "File descriptor %d failed to seek to position "
533 : : "%" G_GUINT64_FORMAT, fdsink->fd, new_offset);
534 : 0 : return FALSE;
535 : : }
536 : : }
537 : :
538 : : static gboolean
539 : 0 : gst_fd_sink_event (GstBaseSink * sink, GstEvent * event)
540 : : {
541 : : GstEventType type;
542 : : GstFdSink *fdsink;
543 : :
544 : 0 : fdsink = GST_FD_SINK (sink);
545 : :
546 : 0 : type = GST_EVENT_TYPE (event);
547 : :
548 [ # # ]: 0 : switch (type) {
549 : : case GST_EVENT_NEWSEGMENT:
550 : : {
551 : : gint64 start, stop, pos;
552 : : GstFormat format;
553 : 0 : gst_event_parse_new_segment (event, NULL, NULL, &format, &start,
554 : : &stop, &pos);
555 : :
556 [ # # ]: 0 : if (format == GST_FORMAT_BYTES) {
557 : : /* only try to seek and fail when we are going to a different
558 : : * position */
559 [ # # ]: 0 : if (fdsink->current_pos != start) {
560 : : /* FIXME, the seek should be performed on the pos field, start/stop are
561 : : * just boundaries for valid bytes offsets. We should also fill the file
562 : : * with zeroes if the new position extends the current EOF (sparse streams
563 : : * and segment accumulation). */
564 [ # # ]: 0 : if (!gst_fd_sink_do_seek (fdsink, (guint64) start))
565 : 0 : goto seek_failed;
566 : : }
567 : : } else {
568 [ # # ]: 0 : GST_DEBUG_OBJECT (fdsink,
569 : : "Ignored NEWSEGMENT event of format %u (%s)", (guint) format,
570 : : gst_format_get_name (format));
571 : : }
572 : 0 : break;
573 : : }
574 : : default:
575 : 0 : break;
576 : : }
577 : :
578 : 0 : return TRUE;
579 : :
580 : : seek_failed:
581 : : {
582 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (fdsink, RESOURCE, SEEK, (NULL),
[ # # ][ # # ]
583 : : ("Error while seeking on file descriptor %d: %s",
584 : : fdsink->fd, g_strerror (errno)));
585 : 0 : return FALSE;
586 : : }
587 : :
588 : : }
589 : :
590 : : /*** GSTURIHANDLER INTERFACE *************************************************/
591 : :
592 : : static GstURIType
593 : 4 : gst_fd_sink_uri_get_type (void)
594 : : {
595 : 4 : return GST_URI_SINK;
596 : : }
597 : :
598 : : static gchar **
599 : 4 : gst_fd_sink_uri_get_protocols (void)
600 : : {
601 : : static gchar *protocols[] = { (char *) "fd", NULL };
602 : :
603 : 4 : return protocols;
604 : : }
605 : :
606 : : static const gchar *
607 : 0 : gst_fd_sink_uri_get_uri (GstURIHandler * handler)
608 : : {
609 : 0 : GstFdSink *sink = GST_FD_SINK (handler);
610 : :
611 : 0 : return sink->uri;
612 : : }
613 : :
614 : : static gboolean
615 : 0 : gst_fd_sink_uri_set_uri (GstURIHandler * handler, const gchar * uri)
616 : : {
617 : : gchar *protocol;
618 : 0 : GstFdSink *sink = GST_FD_SINK (handler);
619 : : gint fd;
620 : :
621 : 0 : protocol = gst_uri_get_protocol (uri);
622 [ # # ]: 0 : if (strcmp (protocol, "fd") != 0) {
623 : 0 : g_free (protocol);
624 : 0 : return FALSE;
625 : : }
626 : 0 : g_free (protocol);
627 : :
628 [ # # ]: 0 : if (sscanf (uri, "fd://%d", &fd) != 1)
629 : 0 : return FALSE;
630 : :
631 : 0 : return gst_fd_sink_update_fd (sink, fd);
632 : : }
633 : :
634 : : static void
635 : 8 : gst_fd_sink_uri_handler_init (gpointer g_iface, gpointer iface_data)
636 : : {
637 : 8 : GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
638 : :
639 : 8 : iface->get_type = gst_fd_sink_uri_get_type;
640 : 8 : iface->get_protocols = gst_fd_sink_uri_get_protocols;
641 : 8 : iface->get_uri = gst_fd_sink_uri_get_uri;
642 : 8 : iface->set_uri = gst_fd_sink_uri_set_uri;
643 : 8 : }
|