Update to latest API changes in GLib/GIO and require at least gio-2.0 2.15.0 for...
[platform/upstream/gst-plugins-base.git] / ext / gio / gstgiobasesrc.c
1 /* GStreamer
2  *
3  * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
4  * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
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 "gstgiobasesrc.h"
27
28 GST_DEBUG_CATEGORY_STATIC (gst_gio_base_src_debug);
29 #define GST_CAT_DEFAULT gst_gio_base_src_debug
30
31 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
32     GST_PAD_SRC,
33     GST_PAD_ALWAYS,
34     GST_STATIC_CAPS_ANY);
35
36 GST_BOILERPLATE (GstGioBaseSrc, gst_gio_base_src, GstBaseSrc,
37     GST_TYPE_BASE_SRC);
38
39 static void gst_gio_base_src_finalize (GObject * object);
40 static gboolean gst_gio_base_src_start (GstBaseSrc * base_src);
41 static gboolean gst_gio_base_src_stop (GstBaseSrc * base_src);
42 static gboolean gst_gio_base_src_get_size (GstBaseSrc * base_src,
43     guint64 * size);
44 static gboolean gst_gio_base_src_is_seekable (GstBaseSrc * base_src);
45 static gboolean gst_gio_base_src_unlock (GstBaseSrc * base_src);
46 static gboolean gst_gio_base_src_unlock_stop (GstBaseSrc * base_src);
47 static gboolean gst_gio_base_src_check_get_range (GstBaseSrc * base_src);
48 static GstFlowReturn gst_gio_base_src_create (GstBaseSrc * base_src,
49     guint64 offset, guint size, GstBuffer ** buf);
50
51 static void
52 gst_gio_base_src_base_init (gpointer gclass)
53 {
54   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
55
56   GST_DEBUG_CATEGORY_INIT (gst_gio_base_src_debug, "gio_base_src", 0,
57       "GIO base source");
58
59   gst_element_class_add_pad_template (element_class,
60       gst_static_pad_template_get (&src_factory));
61 }
62
63 static void
64 gst_gio_base_src_class_init (GstGioBaseSrcClass * klass)
65 {
66   GObjectClass *gobject_class;
67   GstElementClass *gstelement_class;
68   GstBaseSrcClass *gstbasesrc_class;
69
70   gobject_class = (GObjectClass *) klass;
71   gstelement_class = (GstElementClass *) klass;
72   gstbasesrc_class = (GstBaseSrcClass *) klass;
73
74   gobject_class->finalize = gst_gio_base_src_finalize;
75
76   gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_gio_base_src_start);
77   gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_gio_base_src_stop);
78   gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_gio_base_src_get_size);
79   gstbasesrc_class->is_seekable =
80       GST_DEBUG_FUNCPTR (gst_gio_base_src_is_seekable);
81   gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_gio_base_src_unlock);
82   gstbasesrc_class->unlock_stop =
83       GST_DEBUG_FUNCPTR (gst_gio_base_src_unlock_stop);
84   gstbasesrc_class->check_get_range =
85       GST_DEBUG_FUNCPTR (gst_gio_base_src_check_get_range);
86   gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_gio_base_src_create);
87 }
88
89 static void
90 gst_gio_base_src_init (GstGioBaseSrc * src, GstGioBaseSrcClass * gclass)
91 {
92   src->cancel = g_cancellable_new ();
93 }
94
95 static void
96 gst_gio_base_src_finalize (GObject * object)
97 {
98   GstGioBaseSrc *src = GST_GIO_BASE_SRC (object);
99
100   if (src->cancel) {
101     g_object_unref (src->cancel);
102     src->cancel = NULL;
103   }
104
105   if (src->stream) {
106     g_object_unref (src->stream);
107     src->stream = NULL;
108   }
109
110   GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
111 }
112
113 static gboolean
114 gst_gio_base_src_start (GstBaseSrc * base_src)
115 {
116   GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
117
118   if (!G_IS_INPUT_STREAM (src->stream)) {
119     GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
120         ("No stream given yet"));
121     return FALSE;
122   }
123
124   src->position = 0;
125
126   GST_DEBUG_OBJECT (src, "started stream");
127
128   return TRUE;
129 }
130
131 static gboolean
132 gst_gio_base_src_stop (GstBaseSrc * base_src)
133 {
134   GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
135   gboolean success = TRUE;
136   GError *err = NULL;
137
138   if (src->stream != NULL) {
139     /* FIXME: In case that the call below would block, there is no one to
140      * trigger the cancellation! */
141
142     success = g_input_stream_close (src->stream, src->cancel, &err);
143
144     if (!success && !gst_gio_error (src, "g_input_stream_close", &err, NULL)) {
145       GST_ELEMENT_ERROR (src, RESOURCE, CLOSE, (NULL),
146           ("g_input_stream_close failed: %s", err->message));
147       g_clear_error (&err);
148     }
149
150     g_object_unref (src->stream);
151     src->stream = NULL;
152   }
153
154   GST_DEBUG_OBJECT (src, "closed stream");
155
156   return success;
157 }
158
159 static gboolean
160 gst_gio_base_src_get_size (GstBaseSrc * base_src, guint64 * size)
161 {
162   GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
163
164   if (G_IS_FILE_INPUT_STREAM (src->stream)) {
165     GFileInfo *info;
166     GError *err = NULL;
167
168     info = g_file_input_stream_query_info (G_FILE_INPUT_STREAM (src->stream),
169         G_FILE_ATTRIBUTE_STANDARD_SIZE, src->cancel, &err);
170
171     if (info != NULL) {
172       *size = g_file_info_get_size (info);
173       g_object_unref (info);
174       GST_DEBUG_OBJECT (src, "found size: %" G_GUINT64_FORMAT, *size);
175       return TRUE;
176     }
177
178     if (!gst_gio_error (src, "g_file_input_stream_query_info", &err, NULL)) {
179
180       if (GST_GIO_ERROR_MATCHES (err, NOT_SUPPORTED))
181         GST_DEBUG_OBJECT (src, "size information not available");
182       else
183         GST_WARNING_OBJECT (src, "size information retrieval failed: %s",
184             err->message);
185
186       g_clear_error (&err);
187     }
188   } else if (G_IS_MEMORY_INPUT_STREAM (src->stream)) {
189     gsize data_size;
190
191     data_size =
192         g_memory_input_stream_get_data_size (G_MEMORY_INPUT_STREAM (src->
193             stream));
194
195     if (data_size != -1) {
196       *size = data_size;
197       return TRUE;
198     }
199   }
200
201   return FALSE;
202 }
203
204 static gboolean
205 gst_gio_base_src_is_seekable (GstBaseSrc * base_src)
206 {
207   GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
208   gboolean seekable;
209
210   seekable = GST_GIO_STREAM_IS_SEEKABLE (src->stream);
211
212   GST_DEBUG_OBJECT (src, "can seek: %d", seekable);
213
214   return seekable;
215 }
216
217 static gboolean
218 gst_gio_base_src_unlock (GstBaseSrc * base_src)
219 {
220   GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
221
222   GST_LOG_OBJECT (src, "triggering cancellation");
223
224   g_cancellable_cancel (src->cancel);
225
226   return TRUE;
227 }
228
229 static gboolean
230 gst_gio_base_src_unlock_stop (GstBaseSrc * base_src)
231 {
232   GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
233
234   GST_LOG_OBJECT (src, "resetting cancellable");
235
236   g_cancellable_reset (src->cancel);
237
238   return TRUE;
239 }
240
241 static gboolean
242 gst_gio_base_src_check_get_range (GstBaseSrc * base_src)
243 {
244   /* FIXME: Implement dry-run variant using guesswork like gnomevfssrc? */
245
246   return GST_CALL_PARENT_WITH_DEFAULT (GST_BASE_SRC_CLASS,
247       check_get_range, (base_src), FALSE);
248 }
249
250 static GstFlowReturn
251 gst_gio_base_src_create (GstBaseSrc * base_src, guint64 offset, guint size,
252     GstBuffer ** buf_return)
253 {
254   GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
255   GstBuffer *buf;
256   gssize read;
257   gboolean success, eos;
258   GstFlowReturn ret = GST_FLOW_OK;
259   GError *err = NULL;
260
261   if (G_UNLIKELY (offset != src->position)) {
262     if (!GST_GIO_STREAM_IS_SEEKABLE (src->stream))
263       return GST_FLOW_NOT_SUPPORTED;
264
265     ret = gst_gio_seek (src, G_SEEKABLE (src->stream), offset, src->cancel);
266
267     if (ret == GST_FLOW_OK)
268       src->position = offset;
269     return ret;
270   }
271
272   buf = gst_buffer_new_and_alloc (size);
273
274   GST_LOG_OBJECT (src, "reading %u bytes from offset %" G_GUINT64_FORMAT,
275       size, offset);
276
277   read =
278       g_input_stream_read (G_INPUT_STREAM (src->stream), GST_BUFFER_DATA (buf),
279       size, src->cancel, &err);
280
281   success = (read >= 0);
282   eos = (size > 0 && read == 0);
283
284   if (!success && !gst_gio_error (src, "g_input_stream_read", &err, &ret)) {
285     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
286         ("Could not read from stream: %s", err->message));
287     g_clear_error (&err);
288   }
289
290   if (success && !eos) {
291     src->position += read;
292     GST_BUFFER_OFFSET (buf) = offset;
293     GST_BUFFER_SIZE (buf) = read;
294     *buf_return = buf;
295   } else {
296     /* !success || eos */
297     gst_buffer_unref (buf);
298   }
299
300   if (eos)
301     ret = GST_FLOW_UNEXPECTED;
302
303   return ret;
304 }
305
306 void
307 gst_gio_base_src_set_stream (GstGioBaseSrc * src, GInputStream * stream)
308 {
309   g_return_if_fail (G_IS_INPUT_STREAM (stream));
310   g_return_if_fail ((GST_STATE (src) != GST_STATE_PLAYING &&
311           GST_STATE (src) != GST_STATE_PAUSED));
312
313   if (src->stream) {
314     gboolean success;
315     GError *err = NULL;
316
317     success = g_input_stream_close (src->stream, src->cancel, &err);
318
319     if (!success && !gst_gio_error (src, "g_input_stream_close", &err, NULL)) {
320       GST_WARNING_OBJECT (src, "g_input_stream_close failed: %s", err->message);
321       g_clear_error (&err);
322     }
323
324     g_object_unref (src->stream);
325     src->stream = NULL;
326   }
327
328   src->stream = stream;
329 }