Correct all relevant warnings found by the sparse semantic code analyzer. This includ...
[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 #define DEFAULT_BLOCKSIZE       4096
54
55 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
56     GST_PAD_SRC,
57     GST_PAD_ALWAYS,
58     GST_STATIC_CAPS_ANY);
59
60 GST_DEBUG_CATEGORY_STATIC (gst_fd_src_debug);
61 #define GST_CAT_DEFAULT gst_fd_src_debug
62
63 enum
64 {
65   PROP_0,
66   PROP_FD,
67 };
68
69 static void gst_fd_src_uri_handler_init (gpointer g_iface, gpointer iface_data);
70
71 static void
72 _do_init (GType fd_src_type)
73 {
74   static const GInterfaceInfo urihandler_info = {
75     gst_fd_src_uri_handler_init,
76     NULL,
77     NULL
78   };
79
80   g_type_add_interface_static (fd_src_type, GST_TYPE_URI_HANDLER,
81       &urihandler_info);
82
83   GST_DEBUG_CATEGORY_INIT (gst_fd_src_debug, "fdsrc", 0, "fdsrc element");
84 }
85
86 GST_BOILERPLATE_FULL (GstFdSrc, gst_fd_src, GstPushSrc, GST_TYPE_PUSH_SRC,
87     _do_init);
88
89 static void gst_fd_src_set_property (GObject * object, guint prop_id,
90     const GValue * value, GParamSpec * pspec);
91 static void gst_fd_src_get_property (GObject * object, guint prop_id,
92     GValue * value, GParamSpec * pspec);
93 static void gst_fd_src_dispose (GObject * obj);
94
95 static gboolean gst_fd_src_start (GstBaseSrc * bsrc);
96 static gboolean gst_fd_src_stop (GstBaseSrc * bsrc);
97 static gboolean gst_fd_src_unlock (GstBaseSrc * bsrc);
98 static gboolean gst_fd_src_unlock_stop (GstBaseSrc * bsrc);
99 static gboolean gst_fd_src_is_seekable (GstBaseSrc * bsrc);
100 static gboolean gst_fd_src_get_size (GstBaseSrc * src, guint64 * size);
101 static gboolean gst_fd_src_do_seek (GstBaseSrc * src, GstSegment * segment);
102
103 static GstFlowReturn gst_fd_src_create (GstPushSrc * psrc, GstBuffer ** outbuf);
104
105 static void
106 gst_fd_src_base_init (gpointer g_class)
107 {
108   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
109
110   gst_element_class_set_details_simple (gstelement_class,
111       "Filedescriptor Source",
112       "Source/File",
113       "Read from a file descriptor", "Erik Walthinsen <omega@cse.ogi.edu>");
114   gst_element_class_add_pad_template (gstelement_class,
115       gst_static_pad_template_get (&srctemplate));
116 }
117
118 static void
119 gst_fd_src_class_init (GstFdSrcClass * klass)
120 {
121   GObjectClass *gobject_class;
122   GstBaseSrcClass *gstbasesrc_class;
123   GstElementClass *gstelement_class;
124   GstPushSrcClass *gstpush_src_class;
125
126   gobject_class = G_OBJECT_CLASS (klass);
127   gstelement_class = GST_ELEMENT_CLASS (klass);
128   gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
129   gstpush_src_class = GST_PUSH_SRC_CLASS (klass);
130
131   parent_class = g_type_class_peek_parent (klass);
132
133   gobject_class->set_property = gst_fd_src_set_property;
134   gobject_class->get_property = gst_fd_src_get_property;
135   gobject_class->dispose = gst_fd_src_dispose;
136
137   g_object_class_install_property (gobject_class, PROP_FD,
138       g_param_spec_int ("fd", "fd", "An open file descriptor to read from",
139           0, G_MAXINT, 0, G_PARAM_READWRITE));
140
141   gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_fd_src_start);
142   gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_fd_src_stop);
143   gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_fd_src_unlock);
144   gstbasesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_fd_src_unlock_stop);
145   gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_fd_src_is_seekable);
146   gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_fd_src_get_size);
147   gstbasesrc_class->do_seek = GST_DEBUG_FUNCPTR (gst_fd_src_do_seek);
148
149   gstpush_src_class->create = GST_DEBUG_FUNCPTR (gst_fd_src_create);
150 }
151
152 static void
153 gst_fd_src_init (GstFdSrc * fdsrc, GstFdSrcClass * klass)
154 {
155   fdsrc->fd = -1;
156   fdsrc->new_fd = 0;
157   fdsrc->seekable_fd = FALSE;
158   fdsrc->uri = g_strdup_printf ("fd://0");
159   fdsrc->curoffset = 0;
160 }
161
162 static void
163 gst_fd_src_dispose (GObject * obj)
164 {
165   GstFdSrc *src = GST_FD_SRC (obj);
166
167   g_free (src->uri);
168   src->uri = NULL;
169
170   G_OBJECT_CLASS (parent_class)->dispose (obj);
171 }
172
173 static void
174 gst_fd_src_update_fd (GstFdSrc * src)
175 {
176   struct stat stat_results;
177
178   /* we need to always update the fdset since it may not have existed when
179    * gst_fd_src_update_fd() was called earlier */
180   if (src->fdset != NULL) {
181     GstPollFD fd = GST_POLL_FD_INIT;
182
183     if (src->fd >= 0) {
184       fd.fd = src->fd;
185       gst_poll_remove_fd (src->fdset, &fd);
186     }
187
188     fd.fd = src->new_fd;
189     gst_poll_add_fd (src->fdset, &fd);
190     gst_poll_fd_ctl_read (src->fdset, &fd, TRUE);
191   }
192
193   if (src->fd != src->new_fd) {
194     GST_INFO_OBJECT (src, "Updating to fd %d", src->new_fd);
195
196     src->fd = src->new_fd;
197
198     g_free (src->uri);
199     src->uri = g_strdup_printf ("fd://%d", src->fd);
200
201     if (fstat (src->fd, &stat_results) < 0)
202       goto not_seekable;
203
204     if (!S_ISREG (stat_results.st_mode))
205       goto not_seekable;
206
207     /* Try a seek of 0 bytes offset to check for seekability */
208     if (lseek (src->fd, 0, SEEK_CUR) < 0)
209       goto not_seekable;
210
211     GST_INFO_OBJECT (src, "marking fd %d as seekable", src->fd);
212     src->seekable_fd = TRUE;
213   }
214   return;
215
216 not_seekable:
217   {
218     GST_INFO_OBJECT (src, "marking fd %d as NOT seekable", src->fd);
219     src->seekable_fd = FALSE;
220   }
221 }
222
223 static gboolean
224 gst_fd_src_start (GstBaseSrc * bsrc)
225 {
226   GstFdSrc *src = GST_FD_SRC (bsrc);
227
228   src->curoffset = 0;
229
230   if ((src->fdset = gst_poll_new (GST_POLL_MODE_AUTO, TRUE)) == NULL)
231     goto socket_pair;
232
233   gst_fd_src_update_fd (src);
234
235   return TRUE;
236
237   /* ERRORS */
238 socket_pair:
239   {
240     GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL),
241         GST_ERROR_SYSTEM);
242     return FALSE;
243   }
244 }
245
246 static gboolean
247 gst_fd_src_stop (GstBaseSrc * bsrc)
248 {
249   GstFdSrc *src = GST_FD_SRC (bsrc);
250
251   if (src->fdset) {
252     gst_poll_free (src->fdset);
253     src->fdset = NULL;
254   }
255
256   return TRUE;
257 }
258
259 static gboolean
260 gst_fd_src_unlock (GstBaseSrc * bsrc)
261 {
262   GstFdSrc *src = GST_FD_SRC (bsrc);
263
264   GST_LOG_OBJECT (src, "Flushing");
265   GST_OBJECT_LOCK (src);
266   gst_poll_set_flushing (src->fdset, TRUE);
267   GST_OBJECT_UNLOCK (src);
268
269   return TRUE;
270 }
271
272 static gboolean
273 gst_fd_src_unlock_stop (GstBaseSrc * bsrc)
274 {
275   GstFdSrc *src = GST_FD_SRC (bsrc);
276
277   GST_LOG_OBJECT (src, "No longer flushing");
278   GST_OBJECT_LOCK (src);
279   gst_poll_set_flushing (src->fdset, FALSE);
280   GST_OBJECT_UNLOCK (src);
281
282   return TRUE;
283 }
284
285 static void
286 gst_fd_src_set_property (GObject * object, guint prop_id, const GValue * value,
287     GParamSpec * pspec)
288 {
289   GstFdSrc *src = GST_FD_SRC (object);
290
291   switch (prop_id) {
292     case PROP_FD:
293       src->new_fd = g_value_get_int (value);
294
295       /* If state is ready or below, update the current fd immediately
296        * so it is reflected in get_properties and uri */
297       GST_OBJECT_LOCK (object);
298       if (GST_STATE (GST_ELEMENT (src)) <= GST_STATE_READY) {
299         GST_DEBUG_OBJECT (src, "state ready or lower, updating to use new fd");
300         gst_fd_src_update_fd (src);
301       } else {
302         GST_DEBUG_OBJECT (src, "state above ready, not updating to new fd yet");
303       }
304       GST_OBJECT_UNLOCK (object);
305       break;
306     default:
307       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
308       break;
309   }
310 }
311
312 static void
313 gst_fd_src_get_property (GObject * object, guint prop_id, GValue * value,
314     GParamSpec * pspec)
315 {
316   GstFdSrc *src = GST_FD_SRC (object);
317
318   switch (prop_id) {
319     case PROP_FD:
320       g_value_set_int (value, src->fd);
321       break;
322     default:
323       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
324       break;
325   }
326 }
327
328 static GstFlowReturn
329 gst_fd_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
330 {
331   GstFdSrc *src;
332   GstBuffer *buf;
333   gssize readbytes;
334   guint blocksize;
335
336 #ifndef HAVE_WIN32
337   gint retval;
338 #endif
339
340   src = GST_FD_SRC (psrc);
341
342 #ifndef HAVE_WIN32
343   do {
344     retval = gst_poll_wait (src->fdset, GST_CLOCK_TIME_NONE);
345   } while (retval == -1 && errno == EINTR);
346
347   if (retval == -1) {
348     if (errno == EBUSY)
349       goto stopped;
350     else
351       goto select_error;
352   }
353 #endif
354
355   blocksize = GST_BASE_SRC (src)->blocksize;
356
357   /* create the buffer */
358   buf = gst_buffer_new_and_alloc (blocksize);
359
360   do {
361     readbytes = read (src->fd, GST_BUFFER_DATA (buf), blocksize);
362     GST_LOG_OBJECT (src, "read %" G_GSSIZE_FORMAT, readbytes);
363   } while (readbytes == -1 && errno == EINTR);  /* retry if interrupted */
364
365   if (readbytes < 0)
366     goto read_error;
367
368   if (readbytes == 0)
369     goto eos;
370
371   GST_BUFFER_OFFSET (buf) = src->curoffset;
372   GST_BUFFER_SIZE (buf) = readbytes;
373   GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
374   src->curoffset += readbytes;
375
376   GST_LOG_OBJECT (psrc, "Read buffer of size %" G_GSSIZE_FORMAT, readbytes);
377
378   /* we're done, return the buffer */
379   *outbuf = buf;
380
381   return GST_FLOW_OK;
382
383   /* ERRORS */
384 #ifndef HAVE_WIN32
385 select_error:
386   {
387     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
388         ("select on file descriptor: %s.", g_strerror (errno)));
389     GST_DEBUG_OBJECT (psrc, "Error during select");
390     return GST_FLOW_ERROR;
391   }
392 stopped:
393   {
394     GST_DEBUG_OBJECT (psrc, "Select stopped");
395     return GST_FLOW_WRONG_STATE;
396   }
397 #endif
398 eos:
399   {
400     GST_DEBUG_OBJECT (psrc, "Read 0 bytes. EOS.");
401     gst_buffer_unref (buf);
402     return GST_FLOW_UNEXPECTED;
403   }
404 read_error:
405   {
406     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
407         ("read on file descriptor: %s.", g_strerror (errno)));
408     GST_DEBUG_OBJECT (psrc, "Error reading from fd");
409     gst_buffer_unref (buf);
410     return GST_FLOW_ERROR;
411   }
412 }
413
414 static gboolean
415 gst_fd_src_is_seekable (GstBaseSrc * bsrc)
416 {
417   GstFdSrc *src = GST_FD_SRC (bsrc);
418
419   return src->seekable_fd;
420 }
421
422 static gboolean
423 gst_fd_src_get_size (GstBaseSrc * bsrc, guint64 * size)
424 {
425   GstFdSrc *src = GST_FD_SRC (bsrc);
426   struct stat stat_results;
427
428   if (!src->seekable_fd) {
429     /* If it isn't seekable, we won't know the length (but fstat will still
430      * succeed, and wrongly say our length is zero. */
431     return FALSE;
432   }
433
434   if (fstat (src->fd, &stat_results) < 0)
435     goto could_not_stat;
436
437   *size = stat_results.st_size;
438
439   return TRUE;
440
441   /* ERROR */
442 could_not_stat:
443   {
444     return FALSE;
445   }
446 }
447
448 static gboolean
449 gst_fd_src_do_seek (GstBaseSrc * bsrc, GstSegment * segment)
450 {
451   gint res;
452   gint64 offset;
453   GstFdSrc *src = GST_FD_SRC (bsrc);
454
455   offset = segment->start;
456
457   /* No need to seek to the current position */
458   if (offset == src->curoffset)
459     return TRUE;
460
461   res = lseek (src->fd, offset, SEEK_SET);
462   if (G_UNLIKELY (res < 0 || res != offset))
463     goto seek_failed;
464
465   segment->last_stop = segment->start;
466   segment->time = segment->start;
467
468   return TRUE;
469
470 seek_failed:
471   GST_DEBUG_OBJECT (src, "lseek returned %" G_GINT64_FORMAT, offset);
472   return FALSE;
473 }
474
475 /*** GSTURIHANDLER INTERFACE *************************************************/
476
477 static GstURIType
478 gst_fd_src_uri_get_type (void)
479 {
480   return GST_URI_SRC;
481 }
482 static gchar **
483 gst_fd_src_uri_get_protocols (void)
484 {
485   static gchar *protocols[] = { "fd", NULL };
486
487   return protocols;
488 }
489 static const gchar *
490 gst_fd_src_uri_get_uri (GstURIHandler * handler)
491 {
492   GstFdSrc *src = GST_FD_SRC (handler);
493
494   return src->uri;
495 }
496
497 static gboolean
498 gst_fd_src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
499 {
500   gchar *protocol;
501   GstFdSrc *src = GST_FD_SRC (handler);
502   gint fd;
503
504   protocol = gst_uri_get_protocol (uri);
505   if (strcmp (protocol, "fd") != 0) {
506     g_free (protocol);
507     return FALSE;
508   }
509   g_free (protocol);
510
511   if (sscanf (uri, "fd://%d", &fd) != 1 || fd < 0)
512     return FALSE;
513
514   src->new_fd = fd;
515
516   GST_OBJECT_LOCK (src);
517   if (GST_STATE (GST_ELEMENT (src)) <= GST_STATE_READY) {
518     gst_fd_src_update_fd (src);
519   }
520   GST_OBJECT_UNLOCK (src);
521
522   return TRUE;
523 }
524
525 static void
526 gst_fd_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
527 {
528   GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
529
530   iface->get_type = gst_fd_src_uri_get_type;
531   iface->get_protocols = gst_fd_src_uri_get_protocols;
532   iface->get_uri = gst_fd_src_uri_get_uri;
533   iface->set_uri = gst_fd_src_uri_set_uri;
534 }