plugins/elements/gstfdsrc.c: Another printf fix (#371493).
[platform/upstream/gstreamer.git] / plugins / elements / gstfdsrc.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *                    2005 Philippe Khalaf <burger@speedy.org>
5  *
6  * gstfdsrc.c:
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23 /**
24  * SECTION:element-fdsrc
25  * @short_description: read from a unix file descriptor
26  * @see_also: #GstFdSink
27  *
28  * Read data from a unix file descriptor.
29  */
30
31
32 #ifdef HAVE_CONFIG_H
33 #  include "config.h"
34 #endif
35 #include "gst/gst_private.h"
36
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <sys/socket.h>
40 #include <fcntl.h>
41 #include <stdio.h>
42 #ifdef HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
45 #ifdef _MSC_VER
46 #include <io.h>
47 #endif
48 #include <stdlib.h>
49 #include <errno.h>
50
51 #include "gstfdsrc.h"
52
53 /* the select call is also performed on the control sockets, that way
54  * we can send special commands to unblock the select call */
55 #define CONTROL_STOP            'S'     /* stop the select call */
56 #define CONTROL_SOCKETS(src)   src->control_sock
57 #define WRITE_SOCKET(src)      src->control_sock[1]
58 #define READ_SOCKET(src)       src->control_sock[0]
59
60 #define SEND_COMMAND(src, command)          \
61 G_STMT_START {                              \
62   unsigned char c; c = command;             \
63   write (WRITE_SOCKET(src), &c, 1);         \
64 } G_STMT_END
65
66 #define READ_COMMAND(src, command, res)        \
67 G_STMT_START {                                 \
68   res = read(READ_SOCKET(src), &command, 1);   \
69 } G_STMT_END
70
71 #define DEFAULT_BLOCKSIZE       4096
72
73 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
74     GST_PAD_SRC,
75     GST_PAD_ALWAYS,
76     GST_STATIC_CAPS_ANY);
77
78 GST_DEBUG_CATEGORY_STATIC (gst_fd_src_debug);
79 #define GST_CAT_DEFAULT gst_fd_src_debug
80
81 static const GstElementDetails gst_fd_src_details =
82 GST_ELEMENT_DETAILS ("Disk Source",
83     "Source/File",
84     "Synchronous read from a file",
85     "Erik Walthinsen <omega@cse.ogi.edu>");
86
87 enum
88 {
89   PROP_0,
90   PROP_FD,
91 };
92
93 static void gst_fd_src_uri_handler_init (gpointer g_iface, gpointer iface_data);
94
95 static void
96 _do_init (GType fd_src_type)
97 {
98   static const GInterfaceInfo urihandler_info = {
99     gst_fd_src_uri_handler_init,
100     NULL,
101     NULL
102   };
103
104   g_type_add_interface_static (fd_src_type, GST_TYPE_URI_HANDLER,
105       &urihandler_info);
106
107   GST_DEBUG_CATEGORY_INIT (gst_fd_src_debug, "fdsrc", 0, "fdsrc element");
108 }
109
110 GST_BOILERPLATE_FULL (GstFdSrc, gst_fd_src, GstElement, GST_TYPE_PUSH_SRC,
111     _do_init);
112
113 static void gst_fd_src_set_property (GObject * object, guint prop_id,
114     const GValue * value, GParamSpec * pspec);
115 static void gst_fd_src_get_property (GObject * object, guint prop_id,
116     GValue * value, GParamSpec * pspec);
117 static void gst_fd_src_dispose (GObject * obj);
118
119 static gboolean gst_fd_src_start (GstBaseSrc * bsrc);
120 static gboolean gst_fd_src_stop (GstBaseSrc * bsrc);
121 static gboolean gst_fd_src_unlock (GstBaseSrc * bsrc);
122 static gboolean gst_fd_src_is_seekable (GstBaseSrc * bsrc);
123 static gboolean gst_fd_src_get_size (GstBaseSrc * src, guint64 * size);
124
125 static GstFlowReturn gst_fd_src_create (GstPushSrc * psrc, GstBuffer ** outbuf);
126
127 static void
128 gst_fd_src_base_init (gpointer g_class)
129 {
130   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
131
132   gst_element_class_add_pad_template (gstelement_class,
133       gst_static_pad_template_get (&srctemplate));
134   gst_element_class_set_details (gstelement_class, &gst_fd_src_details);
135 }
136
137 static void
138 gst_fd_src_class_init (GstFdSrcClass * klass)
139 {
140   GObjectClass *gobject_class;
141   GstBaseSrcClass *gstbasesrc_class;
142   GstElementClass *gstelement_class;
143   GstPushSrcClass *gstpush_src_class;
144
145   gobject_class = G_OBJECT_CLASS (klass);
146   gstelement_class = GST_ELEMENT_CLASS (klass);
147   gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
148   gstpush_src_class = GST_PUSH_SRC_CLASS (klass);
149
150   parent_class = g_type_class_peek_parent (klass);
151
152   gobject_class->set_property = gst_fd_src_set_property;
153   gobject_class->get_property = gst_fd_src_get_property;
154   gobject_class->dispose = gst_fd_src_dispose;
155
156   g_object_class_install_property (gobject_class, PROP_FD,
157       g_param_spec_int ("fd", "fd", "An open file descriptor to read from",
158           0, G_MAXINT, 0, G_PARAM_READWRITE));
159
160   gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_fd_src_start);
161   gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_fd_src_stop);
162   gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_fd_src_unlock);
163   gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_fd_src_is_seekable);
164   gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_fd_src_get_size);
165
166   gstpush_src_class->create = GST_DEBUG_FUNCPTR (gst_fd_src_create);
167 }
168
169 static void
170 gst_fd_src_init (GstFdSrc * fdsrc, GstFdSrcClass * klass)
171 {
172   fdsrc->fd = 0;
173   fdsrc->new_fd = 0;
174   fdsrc->seekable_fd = FALSE;
175   fdsrc->uri = g_strdup_printf ("fd://%d", fdsrc->fd);
176   fdsrc->curoffset = 0;
177 }
178
179 static void
180 gst_fd_src_dispose (GObject * obj)
181 {
182   GstFdSrc *src = GST_FD_SRC (obj);
183
184   g_free (src->uri);
185   src->uri = NULL;
186
187   G_OBJECT_CLASS (parent_class)->dispose (obj);
188 }
189
190 static void
191 gst_fd_src_update_fd (GstFdSrc * src)
192 {
193   struct stat stat_results;
194
195   if (src->fd != src->new_fd) {
196     GST_INFO_OBJECT (src, "Updating to fd %d", src->new_fd);
197
198     src->fd = src->new_fd;
199
200     g_free (src->uri);
201     src->uri = g_strdup_printf ("fd://%d", src->fd);
202
203     if (fstat (src->fd, &stat_results) < 0)
204       goto not_seekable;
205
206     if (!S_ISREG (stat_results.st_mode))
207       goto not_seekable;
208
209     /* Try a seek of 0 bytes offset to check for seekability */
210     if (lseek (src->fd, 0, SEEK_CUR) < 0)
211       goto not_seekable;
212
213     GST_INFO_OBJECT (src, "marking fd %d as seekable", src->fd);
214     src->seekable_fd = TRUE;
215   }
216   return;
217
218 not_seekable:
219   {
220     GST_INFO_OBJECT (src, "marking fd %d as NOT seekable", src->fd);
221     src->seekable_fd = FALSE;
222   }
223 }
224
225 static gboolean
226 gst_fd_src_start (GstBaseSrc * bsrc)
227 {
228   GstFdSrc *src = GST_FD_SRC (bsrc);
229   gint control_sock[2];
230
231   src->curoffset = 0;
232
233   gst_fd_src_update_fd (src);
234
235   if (socketpair (PF_UNIX, SOCK_STREAM, 0, control_sock) < 0)
236     goto socket_pair;
237
238   READ_SOCKET (src) = control_sock[0];
239   WRITE_SOCKET (src) = control_sock[1];
240
241   fcntl (READ_SOCKET (src), F_SETFL, O_NONBLOCK);
242   fcntl (WRITE_SOCKET (src), F_SETFL, O_NONBLOCK);
243
244   return TRUE;
245
246   /* ERRORS */
247 socket_pair:
248   {
249     GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL),
250         GST_ERROR_SYSTEM);
251     return FALSE;
252   }
253 }
254
255 static gboolean
256 gst_fd_src_stop (GstBaseSrc * bsrc)
257 {
258   GstFdSrc *src = GST_FD_SRC (bsrc);
259
260   close (READ_SOCKET (src));
261   close (WRITE_SOCKET (src));
262
263   return TRUE;
264 }
265
266 static gboolean
267 gst_fd_src_unlock (GstBaseSrc * bsrc)
268 {
269   GstFdSrc *src = GST_FD_SRC (bsrc);
270
271   SEND_COMMAND (src, CONTROL_STOP);
272
273   return TRUE;
274 }
275
276 static void
277 gst_fd_src_set_property (GObject * object, guint prop_id, const GValue * value,
278     GParamSpec * pspec)
279 {
280   GstFdSrc *src = GST_FD_SRC (object);
281
282   switch (prop_id) {
283     case PROP_FD:
284       src->new_fd = g_value_get_int (value);
285
286       /* If state is ready or below, update the current fd immediately
287        * so it is reflected in get_properties and uri */
288       GST_OBJECT_LOCK (object);
289       if (GST_STATE (GST_ELEMENT (src)) <= GST_STATE_READY) {
290         GST_DEBUG_OBJECT (src, "state ready or lower, updating to use new fd");
291         gst_fd_src_update_fd (src);
292       } else {
293         GST_DEBUG_OBJECT (src, "state above ready, not updating to new fd yet");
294       }
295       GST_OBJECT_UNLOCK (object);
296       break;
297     default:
298       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
299       break;
300   }
301 }
302
303 static void
304 gst_fd_src_get_property (GObject * object, guint prop_id, GValue * value,
305     GParamSpec * pspec)
306 {
307   GstFdSrc *src = GST_FD_SRC (object);
308
309   switch (prop_id) {
310     case PROP_FD:
311       g_value_set_int (value, src->fd);
312       break;
313     default:
314       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
315       break;
316   }
317 }
318
319 static GstFlowReturn
320 gst_fd_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
321 {
322   GstFdSrc *src;
323   GstBuffer *buf;
324   gssize readbytes;
325   guint blocksize;
326
327 #ifndef HAVE_WIN32
328   fd_set readfds;
329   gint retval;
330 #endif
331
332   src = GST_FD_SRC (psrc);
333
334 #ifndef HAVE_WIN32
335   FD_ZERO (&readfds);
336   FD_SET (src->fd, &readfds);
337   FD_SET (READ_SOCKET (src), &readfds);
338
339   do {
340     retval = select (FD_SETSIZE, &readfds, NULL, NULL, NULL);
341   } while ((retval == -1 && errno == EINTR));
342
343   if (retval == -1)
344     goto select_error;
345
346   if (FD_ISSET (READ_SOCKET (src), &readfds)) {
347     /* read all stop commands */
348     while (TRUE) {
349       gchar command;
350       int res;
351
352       GST_LOG_OBJECT (src, "reading command");
353
354       READ_COMMAND (src, command, res);
355       if (res < 0) {
356         GST_LOG_OBJECT (src, "no more commands");
357         /* no more commands */
358         break;
359       }
360     }
361     goto stopped;
362   }
363 #endif
364
365   blocksize = GST_BASE_SRC (src)->blocksize;
366
367   /* create the buffer */
368   buf = gst_buffer_new_and_alloc (blocksize);
369
370   do {
371     readbytes = read (src->fd, GST_BUFFER_DATA (buf), blocksize);
372     GST_LOG_OBJECT (src, "read %" G_GSSIZE_FORMAT, readbytes);
373   } while (readbytes == -1 && errno == EINTR);  /* retry if interrupted */
374
375   if (readbytes < 0)
376     goto read_error;
377
378   if (readbytes == 0)
379     goto eos;
380
381   GST_BUFFER_OFFSET (buf) = src->curoffset;
382   GST_BUFFER_SIZE (buf) = readbytes;
383   GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
384   src->curoffset += readbytes;
385
386   GST_LOG_OBJECT (psrc, "Read buffer of size %" G_GSSIZE_FORMAT, readbytes);
387
388   /* we're done, return the buffer */
389   *outbuf = buf;
390
391   return GST_FLOW_OK;
392
393   /* ERRORS */
394 #ifndef HAVE_WIN32
395 select_error:
396   {
397     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
398         ("select on file descriptor: %s.", g_strerror (errno)));
399     GST_DEBUG_OBJECT (psrc, "Error during select");
400     return GST_FLOW_ERROR;
401   }
402 stopped:
403   {
404     GST_DEBUG_OBJECT (psrc, "Select stopped");
405     return GST_FLOW_WRONG_STATE;
406   }
407 #endif
408 eos:
409   {
410     GST_DEBUG_OBJECT (psrc, "Read 0 bytes. EOS.");
411     gst_buffer_unref (buf);
412     return GST_FLOW_UNEXPECTED;
413   }
414 read_error:
415   {
416     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
417         ("read on file descriptor: %s.", g_strerror (errno)));
418     GST_DEBUG_OBJECT (psrc, "Error reading from fd");
419     gst_buffer_unref (buf);
420     return GST_FLOW_ERROR;
421   }
422 }
423
424 gboolean
425 gst_fd_src_is_seekable (GstBaseSrc * bsrc)
426 {
427   GstFdSrc *src = GST_FD_SRC (bsrc);
428
429   return src->seekable_fd;
430 }
431
432 gboolean
433 gst_fd_src_get_size (GstBaseSrc * bsrc, guint64 * size)
434 {
435   GstFdSrc *src = GST_FD_SRC (bsrc);
436   struct stat stat_results;
437
438   if (!src->seekable_fd) {
439     /* If it isn't seekable, we won't know the length (but fstat will still
440      * succeed, and wrongly say our length is zero. */
441     return FALSE;
442   }
443
444   if (fstat (src->fd, &stat_results) < 0)
445     goto could_not_stat;
446
447   *size = stat_results.st_size;
448
449   return TRUE;
450
451   /* ERROR */
452 could_not_stat:
453   {
454     return FALSE;
455   }
456
457 }
458
459 /*** GSTURIHANDLER INTERFACE *************************************************/
460
461 static GstURIType
462 gst_fd_src_uri_get_type (void)
463 {
464   return GST_URI_SRC;
465 }
466 static gchar **
467 gst_fd_src_uri_get_protocols (void)
468 {
469   static gchar *protocols[] = { "fd", NULL };
470
471   return protocols;
472 }
473 static const gchar *
474 gst_fd_src_uri_get_uri (GstURIHandler * handler)
475 {
476   GstFdSrc *src = GST_FD_SRC (handler);
477
478   return src->uri;
479 }
480
481 static gboolean
482 gst_fd_src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
483 {
484   gchar *protocol;
485   GstFdSrc *src = GST_FD_SRC (handler);
486   gint fd;
487
488   protocol = gst_uri_get_protocol (uri);
489   if (strcmp (protocol, "fd") != 0) {
490     g_free (protocol);
491     return FALSE;
492   }
493   g_free (protocol);
494
495   if (sscanf (uri, "fd://%d", &fd) != 1)
496     return FALSE;
497
498   src->new_fd = fd;
499
500   GST_OBJECT_LOCK (src);
501   if (GST_STATE (GST_ELEMENT (src)) <= GST_STATE_READY) {
502     gst_fd_src_update_fd (src);
503   }
504   GST_OBJECT_UNLOCK (src);
505
506   return TRUE;
507 }
508
509 static void
510 gst_fd_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
511 {
512   GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
513
514   iface->get_type = gst_fd_src_uri_get_type;
515   iface->get_protocols = gst_fd_src_uri_get_protocols;
516   iface->get_uri = gst_fd_src_uri_get_uri;
517   iface->set_uri = gst_fd_src_uri_set_uri;
518 }