static const gchar * gst_gnome_vfs_src_uri_get_uri (GstURIHandler * handler) { GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (handler); return src->uri_name; }
static void gst_gnome_vfs_src_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstGnomeVFSSrc *src; src = GST_GNOME_VFS_SRC (object); switch (prop_id) { case ARG_LOCATION: g_value_set_string (value, src->uri_name); break; case ARG_HANDLE: g_value_set_boxed (value, src->handle); break; case ARG_IRADIO_MODE: g_value_set_boolean (value, src->iradio_mode); break; case ARG_IRADIO_NAME: g_value_set_string (value, src->iradio_name); break; case ARG_IRADIO_GENRE: g_value_set_string (value, src->iradio_genre); break; case ARG_IRADIO_URL: g_value_set_string (value, src->iradio_url); break; case ARG_IRADIO_TITLE: g_value_set_string (value, src->iradio_title); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gboolean gst_gnome_vfs_src_stop (GstBaseSrc * basesrc) { GstGnomeVFSSrc *src; src = GST_GNOME_VFS_SRC (basesrc); gst_gnome_vfs_src_pop_callbacks (src); if (src->own_handle) { GnomeVFSResult res; res = gnome_vfs_close (src->handle); if (res != GNOME_VFS_OK) { GST_ELEMENT_ERROR (src, RESOURCE, CLOSE, (NULL), ("Could not close vfs handle: %s", gnome_vfs_result_to_string (res))); } src->handle = NULL; } src->curoffset = 0; src->interrupted = FALSE; gnome_vfs_context_free (src->context); src->context = NULL; return TRUE; }
/* open the file, do stuff necessary to go to PAUSED state */ static gboolean gst_gnome_vfs_src_start (GstBaseSrc * basesrc) { GnomeVFSResult res; GstGnomeVFSSrc *src; src = GST_GNOME_VFS_SRC (basesrc); gst_gnome_vfs_src_push_callbacks (src); if (src->uri != NULL) { GnomeVFSOpenMode mode = GNOME_VFS_OPEN_READ; /* this can block... */ res = gnome_vfs_open_uri (&src->handle, src->uri, mode); if (res != GNOME_VFS_OK) goto open_failed; src->own_handle = TRUE; } else if (!src->handle) { goto no_filename; } else { src->own_handle = FALSE; } if (gnome_vfs_seek (src->handle, GNOME_VFS_SEEK_CURRENT, 0) == GNOME_VFS_OK) { src->seekable = TRUE; } else { src->seekable = FALSE; } return TRUE; /* ERRORS */ open_failed: { gchar *filename = gnome_vfs_uri_to_string (src->uri, GNOME_VFS_URI_HIDE_PASSWORD); gst_gnome_vfs_src_pop_callbacks (src); if (res == GNOME_VFS_ERROR_NOT_FOUND || res == GNOME_VFS_ERROR_HOST_NOT_FOUND || res == GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE) { GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), ("Could not open vfs file \"%s\" for reading: %s (%d)", filename, gnome_vfs_result_to_string (res), res)); } else { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("Could not open vfs file \"%s\" for reading: %s (%d)", filename, gnome_vfs_result_to_string (res), res)); } g_free (filename); return FALSE; } no_filename: { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("No filename given")); return FALSE; } }
static gboolean gst_gnome_vfs_src_is_seekable (GstBaseSrc * basesrc) { GstGnomeVFSSrc *src; src = GST_GNOME_VFS_SRC (basesrc); return src->seekable; }
static void gst_gnome_vfs_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstGnomeVFSSrc *src; src = GST_GNOME_VFS_SRC (object); switch (prop_id) { case ARG_LOCATION:{ const gchar *new_location; /* the element must be stopped or paused in order to do this */ if (GST_STATE (src) == GST_STATE_PLAYING || GST_STATE (src) == GST_STATE_PAUSED) break; if (src->uri) { gnome_vfs_uri_unref (src->uri); src->uri = NULL; } if (src->uri_name) { g_free (src->uri_name); src->uri_name = NULL; } new_location = g_value_get_string (value); if (new_location) { src->uri_name = gst_gnome_vfs_location_to_uri_string (new_location); src->uri = gnome_vfs_uri_new (src->uri_name); } break; } case ARG_HANDLE: if (GST_STATE (src) == GST_STATE_NULL || GST_STATE (src) == GST_STATE_READY) { if (src->uri) { gnome_vfs_uri_unref (src->uri); src->uri = NULL; } if (src->uri_name) { g_free (src->uri_name); src->uri_name = NULL; } src->handle = g_value_get_boxed (value); } break; case ARG_IRADIO_MODE: src->iradio_mode = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
/* Interrupt interrupt. */ static gboolean gst_gnome_vfs_src_unlock_stop (GstBaseSrc * basesrc) { GstGnomeVFSSrc *src; src = GST_GNOME_VFS_SRC (basesrc); GST_DEBUG_OBJECT (src, "unlock_stop()"); src->interrupted = FALSE; return TRUE; }
static gboolean gst_gnome_vfs_src_uri_set_uri (GstURIHandler * handler, const gchar * uri) { GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (handler); if (GST_STATE (src) == GST_STATE_PLAYING || GST_STATE (src) == GST_STATE_PAUSED) return FALSE; g_object_set (G_OBJECT (src), "location", uri, NULL); return TRUE; }
static void gst_gnome_vfs_src_send_additional_headers_callback (gconstpointer in, gsize in_size, gpointer out, gsize out_size, gpointer callback_data) { GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (callback_data); GnomeVFSModuleCallbackAdditionalHeadersOut *out_args = (GnomeVFSModuleCallbackAdditionalHeadersOut *) out; if (!src->iradio_mode) return; GST_DEBUG_OBJECT (src, "sending headers\n"); out_args->headers = g_list_append (out_args->headers, g_strdup ("icy-metadata:1\r\n")); }
/* Interrupt a blocking request. */ static gboolean gst_gnome_vfs_src_unlock (GstBaseSrc * basesrc) { GstGnomeVFSSrc *src; src = GST_GNOME_VFS_SRC (basesrc); GST_DEBUG_OBJECT (src, "unlock()"); src->interrupted = TRUE; if (src->context) { GnomeVFSCancellation *cancel = gnome_vfs_context_get_cancellation (src->context); if (cancel) gnome_vfs_cancellation_cancel (cancel); } return TRUE; }
static gboolean gst_gnome_vfs_src_check_get_range (GstBaseSrc * basesrc) { GstGnomeVFSSrc *src; const gchar *protocol; src = GST_GNOME_VFS_SRC (basesrc); if (src->uri == NULL) { GST_WARNING_OBJECT (src, "no URI set yet"); return FALSE; } if (gnome_vfs_uri_is_local (src->uri)) { GST_LOG_OBJECT (src, "local URI (%s), assuming random access is possible", GST_STR_NULL (src->uri_name)); return TRUE; } /* blacklist certain protocols we know won't work getrange-based */ protocol = gnome_vfs_uri_get_scheme (src->uri); if (protocol == NULL) goto undecided; if (strcmp (protocol, "http") == 0 || strcmp (protocol, "https") == 0) { GST_LOG_OBJECT (src, "blacklisted protocol '%s', no random access possible" " (URI=%s)", protocol, GST_STR_NULL (src->uri_name)); return FALSE; } /* fall through to undecided */ undecided: { /* don't know what to do, let the basesrc class decide for us */ GST_LOG_OBJECT (src, "undecided about URI '%s', let base class handle it", GST_STR_NULL (src->uri_name)); if (GST_BASE_SRC_CLASS (parent_class)->check_get_range) return GST_BASE_SRC_CLASS (parent_class)->check_get_range (basesrc); return FALSE; } }
static gboolean gst_gnome_vfs_src_get_size (GstBaseSrc * basesrc, guint64 * size) { GstGnomeVFSSrc *src; GnomeVFSFileInfo *info; GnomeVFSFileInfoOptions options; GnomeVFSResult res; src = GST_GNOME_VFS_SRC (basesrc); *size = -1; info = gnome_vfs_file_info_new (); options = GNOME_VFS_FILE_INFO_DEFAULT | GNOME_VFS_FILE_INFO_FOLLOW_LINKS; res = gnome_vfs_get_file_info_from_handle (src->handle, info, options); if (res == GNOME_VFS_OK) { if ((info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) != 0) { *size = info->size; GST_DEBUG_OBJECT (src, "from handle: %" G_GUINT64_FORMAT " bytes", *size); } else if (src->own_handle && gnome_vfs_uri_is_local (src->uri)) { GST_DEBUG_OBJECT (src, "file size not known, file local, trying fallback"); res = gnome_vfs_get_file_info_uri (src->uri, info, options); if (res == GNOME_VFS_OK && (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) != 0) { *size = info->size; GST_DEBUG_OBJECT (src, "from uri: %" G_GUINT64_FORMAT " bytes", *size); } } } else { GST_WARNING_OBJECT (src, "getting info failed: %s", gnome_vfs_result_to_string (res)); } gnome_vfs_file_info_unref (info); if (*size == (GnomeVFSFileSize) - 1) return FALSE; GST_DEBUG_OBJECT (src, "return size %" G_GUINT64_FORMAT, *size); return TRUE; }
static gboolean gst_gnome_vfs_src_query (GstBaseSrc * basesrc, GstQuery * query) { gboolean ret = FALSE; GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (basesrc); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_URI: gst_query_set_uri (query, src->uri_name); ret = TRUE; break; default: ret = FALSE; break; } if (!ret) ret = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query); return ret; }
static void gst_gnome_vfs_src_finalize (GObject * object) { GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (object); g_static_mutex_lock (&count_lock); ref_count--; if (ref_count == 0 && vfs_owner) { if (gnome_vfs_initialized () == TRUE) { gnome_vfs_shutdown (); } } g_static_mutex_unlock (&count_lock); if (src->uri) { gnome_vfs_uri_unref (src->uri); src->uri = NULL; } g_free (src->uri_name); src->uri_name = NULL; g_free (src->iradio_name); src->iradio_name = NULL; g_free (src->iradio_genre); src->iradio_genre = NULL; g_free (src->iradio_url); src->iradio_url = NULL; g_free (src->iradio_title); src->iradio_title = NULL; G_OBJECT_CLASS (parent_class)->finalize (object); }
/* * Read a new buffer from src->reqoffset, takes care of events * and seeking and such. */ static GstFlowReturn gst_gnome_vfs_src_create (GstBaseSrc * basesrc, guint64 offset, guint size, GstBuffer ** buffer) { GnomeVFSResult res; GstBuffer *buf; GnomeVFSFileSize readbytes; guint8 *data; guint todo; GstGnomeVFSSrc *src; src = GST_GNOME_VFS_SRC (basesrc); GST_DEBUG ("now at %" G_GINT64_FORMAT ", reading from %" G_GUINT64_FORMAT ", size %u", src->curoffset, offset, size); /* seek if required */ if (G_UNLIKELY (src->curoffset != offset)) { GST_DEBUG ("need to seek"); if (src->seekable) { GST_DEBUG ("seeking to %" G_GUINT64_FORMAT, offset); res = gnome_vfs_seek (src->handle, GNOME_VFS_SEEK_START, offset); if (res != GNOME_VFS_OK) goto seek_failed; src->curoffset = offset; } else { goto cannot_seek; } } buf = gst_buffer_try_new_and_alloc (size); if (G_UNLIKELY (buf == NULL)) { GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", size); return GST_FLOW_ERROR; } data = GST_BUFFER_DATA (buf); todo = size; while (todo > 0) { /* this can return less that we ask for */ res = gnome_vfs_read (src->handle, data, todo, &readbytes); if (G_UNLIKELY (res == GNOME_VFS_ERROR_EOF || (res == GNOME_VFS_OK && readbytes == 0))) goto eos; if (G_UNLIKELY (res != GNOME_VFS_OK)) goto read_failed; if (readbytes < todo) { data = &data[readbytes]; todo -= readbytes; } else { todo = 0; } GST_LOG (" got size %" G_GUINT64_FORMAT, readbytes); } GST_BUFFER_OFFSET (buf) = src->curoffset; src->curoffset += size; /* we're done, return the buffer */ *buffer = buf; return GST_FLOW_OK; seek_failed: { GST_ELEMENT_ERROR (src, RESOURCE, SEEK, (NULL), ("Failed to seek to requested position %" G_GINT64_FORMAT ": %s", offset, gnome_vfs_result_to_string (res))); return GST_FLOW_ERROR; } cannot_seek: { GST_ELEMENT_ERROR (src, RESOURCE, SEEK, (NULL), ("Requested seek from %" G_GINT64_FORMAT " to %" G_GINT64_FORMAT " on non-seekable stream", src->curoffset, offset)); return GST_FLOW_ERROR; } read_failed: { gst_buffer_unref (buf); GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), ("Failed to read data: %s", gnome_vfs_result_to_string (res))); return GST_FLOW_ERROR; } eos: { gst_buffer_unref (buf); GST_DEBUG_OBJECT (src, "Reading data gave EOS"); return GST_FLOW_UNEXPECTED; } }
static void gst_gnome_vfs_src_received_headers_callback (gconstpointer in, gsize in_size, gpointer out, gsize out_size, gpointer callback_data) { GList *i; gint icy_metaint; GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (callback_data); GnomeVFSModuleCallbackReceivedHeadersIn *in_args = (GnomeVFSModuleCallbackReceivedHeadersIn *) in; /* This is only used for internet radio stuff right now */ if (!src->iradio_mode) return; GST_DEBUG_OBJECT (src, "receiving internet radio metadata\n"); /* FIXME: Could we use "Accept-Ranges: bytes" * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.5 * to enable pull-mode? */ for (i = in_args->headers; i; i = i->next) { char *data = (char *) i->data; char *key = data; char *value = strchr (data, ':'); if (!value) continue; value++; g_strstrip (value); if (!strlen (value)) continue; GST_LOG_OBJECT (src, "data %s", data); /* Icecast stuff */ if (strncmp (data, "icy-metaint:", 12) == 0) { /* ugh */ if (sscanf (data + 12, "%d", &icy_metaint) == 1) { if (icy_metaint > 0) { GstCaps *icy_caps; icy_caps = gst_caps_new_simple ("application/x-icy", "metadata-interval", G_TYPE_INT, icy_metaint, NULL); gst_pad_set_caps (GST_BASE_SRC_PAD (src), icy_caps); gst_caps_unref (icy_caps); } } continue; } if (!strncmp (data, "icy-", 4)) key = data + 4; else continue; GST_DEBUG_OBJECT (src, "key: %s", key); if (!strncmp (key, "name", 4)) { g_free (src->iradio_name); src->iradio_name = gst_gnome_vfs_src_unicodify (value); if (src->iradio_name) g_object_notify (G_OBJECT (src), "iradio-name"); } else if (!strncmp (key, "genre", 5)) { g_free (src->iradio_genre); src->iradio_genre = gst_gnome_vfs_src_unicodify (value); if (src->iradio_genre) g_object_notify (G_OBJECT (src), "iradio-genre"); } else if (!strncmp (key, "url", 3)) { g_free (src->iradio_url); src->iradio_url = gst_gnome_vfs_src_unicodify (value); if (src->iradio_url) g_object_notify (G_OBJECT (src), "iradio-url"); } } }