gst_plugins_base/ext/gio/gstgiobasesrc.c
branchRCL_3
changeset 30 7e817e7e631c
parent 0 0e761a78d257
equal deleted inserted replaced
29:567bb019e3e3 30:7e817e7e631c
       
     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;
       
   136   GError *err = NULL;
       
   137 
       
   138   if (G_IS_INPUT_STREAM (src->stream)) {
       
   139     GST_DEBUG_OBJECT (src, "closing stream");
       
   140 
       
   141     /* FIXME: can block but unfortunately we can't use async operations
       
   142      * here because they require a running main loop */
       
   143     success = g_input_stream_close (src->stream, src->cancel, &err);
       
   144 
       
   145     if (!success && !gst_gio_error (src, "g_input_stream_close", &err, NULL)) {
       
   146       GST_ELEMENT_WARNING (src, RESOURCE, CLOSE, (NULL),
       
   147           ("g_input_stream_close failed: %s", err->message));
       
   148       g_clear_error (&err);
       
   149     } else if (!success) {
       
   150       GST_ELEMENT_WARNING (src, RESOURCE, CLOSE, (NULL),
       
   151           ("g_input_stream_close failed"));
       
   152     } else {
       
   153       GST_DEBUG_OBJECT (src, "g_input_stream_close succeeded");
       
   154     }
       
   155 
       
   156     g_object_unref (src->stream);
       
   157     src->stream = NULL;
       
   158   }
       
   159 
       
   160   return TRUE;
       
   161 }
       
   162 
       
   163 static gboolean
       
   164 gst_gio_base_src_get_size (GstBaseSrc * base_src, guint64 * size)
       
   165 {
       
   166   GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
       
   167 
       
   168   if (G_IS_FILE_INPUT_STREAM (src->stream)) {
       
   169     GFileInfo *info;
       
   170     GError *err = NULL;
       
   171 
       
   172     info = g_file_input_stream_query_info (G_FILE_INPUT_STREAM (src->stream),
       
   173         G_FILE_ATTRIBUTE_STANDARD_SIZE, src->cancel, &err);
       
   174 
       
   175     if (info != NULL) {
       
   176       *size = g_file_info_get_size (info);
       
   177       g_object_unref (info);
       
   178       GST_DEBUG_OBJECT (src, "found size: %" G_GUINT64_FORMAT, *size);
       
   179       return TRUE;
       
   180     }
       
   181 
       
   182     if (!gst_gio_error (src, "g_file_input_stream_query_info", &err, NULL)) {
       
   183 
       
   184       if (GST_GIO_ERROR_MATCHES (err, NOT_SUPPORTED))
       
   185         GST_DEBUG_OBJECT (src, "size information not available");
       
   186       else
       
   187         GST_WARNING_OBJECT (src, "size information retrieval failed: %s",
       
   188             err->message);
       
   189 
       
   190       g_clear_error (&err);
       
   191     }
       
   192   } else if (GST_GIO_STREAM_IS_SEEKABLE (src->stream)) {
       
   193     goffset old;
       
   194     goffset stream_size;
       
   195     gboolean ret;
       
   196     GSeekable *seekable = G_SEEKABLE (src->stream);
       
   197     GError *err = NULL;
       
   198 
       
   199     old = g_seekable_tell (seekable);
       
   200 
       
   201     ret = g_seekable_seek (seekable, 0, G_SEEK_END, src->cancel, &err);
       
   202     if (!ret) {
       
   203       if (!gst_gio_error (src, "g_seekable_seek", &err, NULL)) {
       
   204         if (GST_GIO_ERROR_MATCHES (err, NOT_SUPPORTED))
       
   205           GST_DEBUG_OBJECT (src,
       
   206               "Seeking to the end of stream is not supported");
       
   207         else
       
   208           GST_WARNING_OBJECT (src, "Seeking to end of stream failed: %s",
       
   209               err->message);
       
   210         g_clear_error (&err);
       
   211       } else {
       
   212         GST_WARNING_OBJECT (src, "Seeking to end of stream failed");
       
   213       }
       
   214 
       
   215       return FALSE;
       
   216     }
       
   217 
       
   218     stream_size = g_seekable_tell (seekable);
       
   219 
       
   220     ret = g_seekable_seek (seekable, old, G_SEEK_SET, src->cancel, &err);
       
   221     if (!ret) {
       
   222       if (!gst_gio_error (src, "g_seekable_seek", &err, NULL)) {
       
   223         if (GST_GIO_ERROR_MATCHES (err, NOT_SUPPORTED))
       
   224           GST_ERROR_OBJECT (src, "Seeking to the old position not supported");
       
   225         else
       
   226           GST_ERROR_OBJECT (src, "Seeking to the old position failed: %s",
       
   227               err->message);
       
   228         g_clear_error (&err);
       
   229       } else {
       
   230         GST_ERROR_OBJECT (src, "Seeking to the old position faile");
       
   231       }
       
   232 
       
   233       return FALSE;
       
   234     }
       
   235 
       
   236     if (stream_size >= 0) {
       
   237       *size = stream_size;
       
   238       return TRUE;
       
   239     }
       
   240   }
       
   241 
       
   242   return FALSE;
       
   243 }
       
   244 
       
   245 static gboolean
       
   246 gst_gio_base_src_is_seekable (GstBaseSrc * base_src)
       
   247 {
       
   248   GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
       
   249   gboolean seekable;
       
   250 
       
   251   seekable = GST_GIO_STREAM_IS_SEEKABLE (src->stream);
       
   252 
       
   253   GST_DEBUG_OBJECT (src, "can seek: %d", seekable);
       
   254 
       
   255   return seekable;
       
   256 }
       
   257 
       
   258 static gboolean
       
   259 gst_gio_base_src_unlock (GstBaseSrc * base_src)
       
   260 {
       
   261   GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
       
   262 
       
   263   GST_LOG_OBJECT (src, "triggering cancellation");
       
   264 
       
   265   g_cancellable_cancel (src->cancel);
       
   266 
       
   267   return TRUE;
       
   268 }
       
   269 
       
   270 static gboolean
       
   271 gst_gio_base_src_unlock_stop (GstBaseSrc * base_src)
       
   272 {
       
   273   GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
       
   274 
       
   275   GST_LOG_OBJECT (src, "resetting cancellable");
       
   276 
       
   277   g_cancellable_reset (src->cancel);
       
   278 
       
   279   return TRUE;
       
   280 }
       
   281 
       
   282 static gboolean
       
   283 gst_gio_base_src_check_get_range (GstBaseSrc * base_src)
       
   284 {
       
   285   /* FIXME: Implement dry-run variant using guesswork like gnomevfssrc? */
       
   286 
       
   287   return GST_CALL_PARENT_WITH_DEFAULT (GST_BASE_SRC_CLASS,
       
   288       check_get_range, (base_src), FALSE);
       
   289 }
       
   290 
       
   291 static GstFlowReturn
       
   292 gst_gio_base_src_create (GstBaseSrc * base_src, guint64 offset, guint size,
       
   293     GstBuffer ** buf_return)
       
   294 {
       
   295   GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
       
   296   GstBuffer *buf;
       
   297   gssize read;
       
   298   gboolean success, eos;
       
   299   GstFlowReturn ret = GST_FLOW_OK;
       
   300   GError *err = NULL;
       
   301 
       
   302   g_return_val_if_fail (G_IS_INPUT_STREAM (src->stream), GST_FLOW_ERROR);
       
   303 
       
   304   if (G_UNLIKELY (offset != src->position)) {
       
   305     if (!GST_GIO_STREAM_IS_SEEKABLE (src->stream))
       
   306       return GST_FLOW_NOT_SUPPORTED;
       
   307 
       
   308     ret = gst_gio_seek (src, G_SEEKABLE (src->stream), offset, src->cancel);
       
   309 
       
   310     if (ret == GST_FLOW_OK)
       
   311       src->position = offset;
       
   312     else
       
   313       return ret;
       
   314   }
       
   315 
       
   316   buf = gst_buffer_new_and_alloc (size);
       
   317 
       
   318   GST_LOG_OBJECT (src, "reading %u bytes from offset %" G_GUINT64_FORMAT,
       
   319       size, offset);
       
   320 
       
   321   read =
       
   322       g_input_stream_read (G_INPUT_STREAM (src->stream), GST_BUFFER_DATA (buf),
       
   323       size, src->cancel, &err);
       
   324 
       
   325   success = (read >= 0);
       
   326   eos = (size > 0 && read == 0);
       
   327 
       
   328   if (!success && !gst_gio_error (src, "g_input_stream_read", &err, &ret)) {
       
   329     GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
       
   330         ("Could not read from stream: %s", err->message));
       
   331     g_clear_error (&err);
       
   332   }
       
   333 
       
   334   if (success && !eos) {
       
   335     src->position += read;
       
   336     GST_BUFFER_OFFSET (buf) = offset;
       
   337     GST_BUFFER_SIZE (buf) = read;
       
   338     *buf_return = buf;
       
   339   } else {
       
   340     /* !success || eos */
       
   341     gst_buffer_unref (buf);
       
   342   }
       
   343 
       
   344   if (eos)
       
   345     ret = GST_FLOW_UNEXPECTED;
       
   346 
       
   347   return ret;
       
   348 }
       
   349 
       
   350 void
       
   351 gst_gio_base_src_set_stream (GstGioBaseSrc * src, GInputStream * stream)
       
   352 {
       
   353   gboolean success;
       
   354   GError *err = NULL;
       
   355 
       
   356   g_return_if_fail (G_IS_INPUT_STREAM (stream));
       
   357   g_return_if_fail ((GST_STATE (src) != GST_STATE_PLAYING &&
       
   358           GST_STATE (src) != GST_STATE_PAUSED));
       
   359 
       
   360   if (G_IS_INPUT_STREAM (src->stream)) {
       
   361     GST_DEBUG_OBJECT (src, "closing old stream");
       
   362 
       
   363     /* FIXME: can block but unfortunately we can't use async operations
       
   364      * here because they require a running main loop */
       
   365     success = g_input_stream_close (src->stream, src->cancel, &err);
       
   366 
       
   367     if (!success && !gst_gio_error (src, "g_input_stream_close", &err, NULL)) {
       
   368       GST_ELEMENT_WARNING (src, RESOURCE, CLOSE, (NULL),
       
   369           ("g_input_stream_close failed: %s", err->message));
       
   370       g_clear_error (&err);
       
   371     } else if (!success) {
       
   372       GST_ELEMENT_WARNING (src, RESOURCE, CLOSE, (NULL),
       
   373           ("g_input_stream_close failed"));
       
   374     } else {
       
   375       GST_DEBUG_OBJECT (src, "g_input_stream_close succeeded");
       
   376     }
       
   377 
       
   378     g_object_unref (src->stream);
       
   379     src->stream = NULL;
       
   380   }
       
   381 
       
   382   src->stream = stream;
       
   383 }