morphbr@534: /* morphbr@534: * @author Artur Duque de Souza morphbr@534: * morphbr@534: * This program is free software; you can redistribute it and/or modify morphbr@534: * it under the terms of the GNU Lesser General Public License as published by morphbr@534: * the Free Software Foundation; either version 2 of the License, or morphbr@534: * (at your option) any later version. morphbr@534: * morphbr@534: * This program is distributed in the hope that it will be useful, morphbr@534: * but WITHOUT ANY WARRANTY; without even the implied warranty of morphbr@534: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the morphbr@534: * GNU General Public License for more details. morphbr@534: * morphbr@534: m * You should have received a copy of the GNU Lesser General Public License morphbr@534: * along with this program; if not, write to the Free Software morphbr@534: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA morphbr@534: */ morphbr@534: morphbr@534: #ifdef HAVE_CONFIG_H morphbr@534: #include morphbr@534: #endif morphbr@534: morphbr@534: #include /* for socket(), connect(), send(), and recv() */ morphbr@534: #include /* for sockaddr_in and inet_addr() */ morphbr@534: #include /* for atoi() and exit() */ morphbr@534: #include /* for memset() */ morphbr@534: #include /* for close() */ morphbr@534: #include morphbr@534: morphbr@534: #include morphbr@534: #include morphbr@534: #include morphbr@534: #include morphbr@534: morphbr@534: #include morphbr@534: #include morphbr@534: morphbr@534: #define BUFFER_SIZE 4096 morphbr@534: morphbr@534: typedef struct { morphbr@534: gint port; morphbr@534: gchar* hostname; morphbr@534: morphbr@534: GMythStreamClient *stream; morphbr@534: gint fd; morphbr@534: } gmsHandle; morphbr@534: morphbr@534: typedef struct { morphbr@534: gchar *file_name; morphbr@534: gchar *mux; morphbr@534: gchar *vcodec; morphbr@534: guint vbitrate; morphbr@534: gdouble fps; morphbr@534: gchar *acodec; morphbr@534: guint abitrate; morphbr@534: guint width; morphbr@534: guint height; morphbr@534: guint port; morphbr@534: gchar *opt; morphbr@534: } UriArgs; morphbr@534: morphbr@534: morphbr@534: static gmsHandle* gmsHandle_new(GnomeVFSURI *uri); morphbr@534: morphbr@534: static GnomeVFSResult morphbr@534: do_open (GnomeVFSMethod *method, morphbr@534: GnomeVFSMethodHandle **method_handle, morphbr@534: GnomeVFSURI *uri, morphbr@534: GnomeVFSOpenMode mode, morphbr@534: GnomeVFSContext *context); morphbr@534: morphbr@534: static GnomeVFSResult morphbr@534: do_read (GnomeVFSMethod *method, morphbr@534: GnomeVFSMethodHandle *method_handle, morphbr@534: gpointer buffer, morphbr@534: GnomeVFSFileSize bytes, morphbr@534: GnomeVFSFileSize *bytes_read, morphbr@534: GnomeVFSContext *context); morphbr@534: morphbr@534: static GnomeVFSResult morphbr@534: do_close (GnomeVFSMethod * method, morphbr@534: GnomeVFSMethodHandle * method_handle, morphbr@534: GnomeVFSContext * context); morphbr@534: morphbr@534: static GnomeVFSResult morphbr@534: do_get_file_info (GnomeVFSMethod * method, morphbr@534: GnomeVFSURI * uri, morphbr@534: GnomeVFSFileInfo * file_info, morphbr@534: GnomeVFSFileInfoOptions options, morphbr@534: GnomeVFSContext * context); morphbr@534: morphbr@534: morphbr@534: static GnomeVFSResult morphbr@534: do_get_file_info_from_handle (GnomeVFSMethod *method, morphbr@534: GnomeVFSMethodHandle *method_handle, morphbr@534: GnomeVFSFileInfo *file_info, morphbr@534: GnomeVFSFileInfoOptions options, morphbr@534: GnomeVFSContext *context); morphbr@534: morphbr@534: morphbr@534: static gboolean morphbr@534: do_is_local (GnomeVFSMethod * method, const GnomeVFSURI * uri); morphbr@534: morphbr@534: morphbr@534: static gmsHandle* gmsHandle_new(GnomeVFSURI *uri) morphbr@534: { morphbr@534: gmsHandle* handler = (gmsHandle*)g_malloc0(sizeof(gmsHandle)); morphbr@534: morphbr@534: handler->hostname = (gchar*)gnome_vfs_uri_get_host_name(uri); morphbr@534: handler->port = gnome_vfs_uri_get_host_port(uri); morphbr@534: handler->stream = gmyth_stream_client_new (); morphbr@534: morphbr@534: return handler; morphbr@534: } morphbr@534: morphbr@534: static GnomeVFSMethod method = { morphbr@534: sizeof (GnomeVFSMethod), morphbr@534: do_open, /* open */ morphbr@534: NULL, /* create */ morphbr@534: do_close, /* close */ morphbr@534: do_read, /* read */ morphbr@534: NULL, /* write */ morphbr@534: NULL, /* seek */ morphbr@534: NULL, /* tell */ morphbr@534: NULL, /* truncate_handle */ morphbr@534: NULL, /* open_directory */ morphbr@534: NULL, /* close_directory */ morphbr@534: NULL, /* read_directory */ morphbr@534: do_get_file_info, /* get_file_info */ morphbr@534: do_get_file_info_from_handle, /* get_file_info_from_handle */ morphbr@534: do_is_local, /* is_local */ morphbr@534: NULL, /* make_directory */ morphbr@534: NULL, /* remove_directory */ morphbr@534: NULL, /* move */ morphbr@534: NULL, /* unlink */ morphbr@534: NULL, /* check_same_fs */ morphbr@534: NULL, /* set_file_info */ morphbr@534: NULL, /* truncate */ morphbr@534: NULL, /* find_directory */ morphbr@534: NULL, /* create_symbolic_link */ morphbr@534: NULL, /* monitor_add */ morphbr@534: NULL, /* monitor_cancel */ morphbr@534: NULL /* file_control */ morphbr@534: }; morphbr@534: morphbr@534: GnomeVFSMethod * morphbr@534: vfs_module_init (const char *method_name, const char *args) morphbr@534: { morphbr@534: return &method; morphbr@534: } morphbr@534: morphbr@534: void morphbr@534: vfs_module_shutdown (GnomeVFSMethod* method) morphbr@534: { morphbr@534: return; morphbr@534: } morphbr@534: morphbr@534: static UriArgs * morphbr@534: _uri_parse_args (const GnomeVFSURI *uri) morphbr@534: { renatofilho@538: renatofilho@538: gchar *file; morphbr@534: UriArgs *info = g_new0 (UriArgs, 1); renatofilho@538: GSList *args = NULL; renatofilho@538: gchar *c; renatofilho@538: GString *entry; renatofilho@538: gboolean open = FALSE; renatofilho@538: gchar **prop; renatofilho@538: GSList* walk; renatofilho@539: gchar *uri_str = gnome_vfs_uri_to_string (uri, renatofilho@538: GNOME_VFS_URI_HIDE_USER_NAME | renatofilho@538: GNOME_VFS_URI_HIDE_PASSWORD | renatofilho@538: GNOME_VFS_URI_HIDE_HOST_NAME | renatofilho@538: GNOME_VFS_URI_HIDE_HOST_PORT | renatofilho@539: GNOME_VFS_URI_HIDE_TOPLEVEL_METHOD); morphbr@534: renatofilho@539: file = gnome_vfs_unescape_string (uri_str, ""); renatofilho@538: c = file; renatofilho@538: entry = g_string_new (""); renatofilho@538: c = c + 1; renatofilho@538: do { renatofilho@538: if ((*c == '\"') || (*c == '\'')) { renatofilho@538: open = !open; renatofilho@538: } morphbr@534: renatofilho@540: if (((*c == '?') || (c[1] == '\0')) && !open) { renatofilho@540: if (*c != '?') renatofilho@540: g_string_append_c (entry, *c); renatofilho@540: renatofilho@538: args = g_slist_append (args, g_strdup (entry->str)); renatofilho@538: entry = g_string_assign (entry, ""); renatofilho@538: } else { renatofilho@540: g_string_append_c (entry, *c); renatofilho@538: } renatofilho@538: c = c + 1; renatofilho@538: } while (*c != '\0'); morphbr@534: renatofilho@538: g_string_free (entry, TRUE); renatofilho@538: renatofilho@538: for (walk = args; walk != NULL; walk = walk->next) morphbr@534: { renatofilho@538: gchar *arg = (gchar *) walk->data; renatofilho@538: prop = g_strsplit(arg, "=", 2); renatofilho@540: g_debug ("arg = %s", arg); morphbr@534: morphbr@534: if (g_strv_length (prop) == 2) { renatofilho@538: if (strcmp (prop[0], "file") == 0) { renatofilho@538: info->file_name = g_strdup (prop[1]); renatofilho@538: } else if (strcmp (prop[0], "mux") == 0) { morphbr@534: info->mux = g_strdup (prop[1]); morphbr@534: } else if (strcmp (prop[0], "vcodec") == 0) { morphbr@534: info->vcodec = g_strdup (prop[1]); morphbr@534: } else if (strcmp (prop[0], "vbitrate") == 0) { morphbr@534: info->vbitrate = atoi (prop[1]); morphbr@534: } else if (strcmp (prop[0], "fps") == 0) { morphbr@534: info->fps = g_strtod (prop[1], NULL); morphbr@534: } else if (strcmp (prop[0], "acodec") == 0) { morphbr@534: info->acodec = g_strdup (prop[1]); morphbr@534: } else if (strcmp (prop[0], "abitrate") == 0) { morphbr@534: info->abitrate = atoi (prop[1]); morphbr@534: } else if (strcmp (prop[0], "width") == 0) { morphbr@534: info->width = atoi (prop[1]); morphbr@534: } else if (strcmp (prop[0], "height") == 0) { morphbr@534: info->height = atoi (prop[1]); morphbr@534: } else if (strcmp (prop[0], "opt") == 0) { renatofilho@538: g_debug("DENTRO DE OPT: %s", arg); renatofilho@538: //char* v = _parse_opt(walk); renatofilho@538: info->opt = g_strdup (arg); morphbr@534: } renatofilho@538: } morphbr@534: g_strfreev (prop); renatofilho@538: g_free (arg); morphbr@534: } morphbr@534: g_free (file); renatofilho@538: g_slist_free (args); morphbr@534: return info; morphbr@534: } morphbr@534: morphbr@534: static GnomeVFSResult morphbr@534: do_open (GnomeVFSMethod *method, morphbr@534: GnomeVFSMethodHandle **method_handle, morphbr@534: GnomeVFSURI *uri, morphbr@534: GnomeVFSOpenMode mode, morphbr@534: GnomeVFSContext *context) morphbr@534: { morphbr@534: gmsHandle *handle = gmsHandle_new(uri); morphbr@534: UriArgs *args; morphbr@534: renatofilho@540: args = _uri_parse_args (uri); renatofilho@540: morphbr@534: if (!gmyth_stream_client_connect (handle->stream, morphbr@534: gnome_vfs_uri_get_host_name (uri), morphbr@534: gnome_vfs_uri_get_host_port (uri))) { morphbr@534: morphbr@534: return GNOME_VFS_ERROR_INVALID_FILENAME; morphbr@534: } morphbr@534: morphbr@534: args = _uri_parse_args (uri); morphbr@534: morphbr@534: gint ret = gmyth_stream_client_open_stream (handle->stream, morphbr@534: args->file_name, morphbr@534: args->mux, morphbr@534: args->vcodec, morphbr@534: args->vbitrate, morphbr@534: args->fps, morphbr@534: args->acodec, morphbr@534: args->abitrate, morphbr@534: args->width, morphbr@534: args->height, morphbr@534: args->opt); morphbr@534: morphbr@534: g_free (args); morphbr@534: morphbr@534: if (ret == -1) { morphbr@534: gmyth_stream_client_disconnect (handle->stream); morphbr@534: return GNOME_VFS_ERROR_INVALID_FILENAME; morphbr@534: } morphbr@534: morphbr@534: handle->fd = gmyth_stream_client_play_stream (handle->stream); morphbr@534: morphbr@534: if (handle->fd == -1) { morphbr@534: gmyth_stream_client_disconnect (handle->stream); morphbr@534: return GNOME_VFS_ERROR_INVALID_FILENAME; morphbr@534: } morphbr@534: morphbr@534: *method_handle = (GnomeVFSMethodHandle *) handle; morphbr@534: return GNOME_VFS_OK; morphbr@534: } morphbr@534: morphbr@534: static GnomeVFSResult morphbr@534: do_read (GnomeVFSMethod *method, morphbr@534: GnomeVFSMethodHandle *method_handle, morphbr@534: gpointer buffer, morphbr@534: GnomeVFSFileSize bytes, morphbr@534: GnomeVFSFileSize *bytes_read, morphbr@534: GnomeVFSContext *context) morphbr@534: { morphbr@534: morphbr@534: gint64 total_read = 0; morphbr@534: gmsHandle *handle = (gmsHandle *) method_handle; morphbr@534: morphbr@534: total_read = recv(handle->fd, buffer, BUFFER_SIZE, 0); morphbr@534: *bytes_read = (GnomeVFSFileSize) total_read; morphbr@534: morphbr@534: if (total_read < 0) return GNOME_VFS_ERROR_INTERNAL; morphbr@534: else return GNOME_VFS_OK; morphbr@534: morphbr@534: } morphbr@534: morphbr@534: static GnomeVFSResult morphbr@534: do_close (GnomeVFSMethod * method, morphbr@534: GnomeVFSMethodHandle * method_handle, morphbr@534: GnomeVFSContext * context) morphbr@534: { morphbr@534: gmsHandle *handle = (gmsHandle *) method_handle; morphbr@534: morphbr@534: gmyth_stream_client_close_stream (handle->stream); morphbr@534: gmyth_stream_client_disconnect (handle->stream); morphbr@534: morphbr@534: g_free(handle); morphbr@534: return GNOME_VFS_OK; morphbr@534: } morphbr@534: morphbr@534: morphbr@534: static GnomeVFSResult morphbr@534: do_get_file_info (GnomeVFSMethod * method, morphbr@534: GnomeVFSURI * uri, morphbr@534: GnomeVFSFileInfo * file_info, morphbr@534: GnomeVFSFileInfoOptions options, morphbr@534: GnomeVFSContext * context) morphbr@534: { morphbr@534: file_info->valid_fields = GNOME_VFS_FILE_INFO_FIELDS_TYPE | morphbr@534: GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS; morphbr@534: morphbr@534: file_info->type = GNOME_VFS_FILE_TYPE_SOCKET; morphbr@534: morphbr@534: file_info->permissions = GNOME_VFS_PERM_USER_READ | morphbr@534: GNOME_VFS_PERM_OTHER_READ | morphbr@534: GNOME_VFS_PERM_GROUP_READ; morphbr@534: morphbr@534: return GNOME_VFS_OK; morphbr@534: } morphbr@534: morphbr@534: morphbr@534: static GnomeVFSResult morphbr@534: do_get_file_info_from_handle (GnomeVFSMethod *method, morphbr@534: GnomeVFSMethodHandle *method_handle, morphbr@534: GnomeVFSFileInfo *file_info, morphbr@534: GnomeVFSFileInfoOptions options, morphbr@534: GnomeVFSContext *context) morphbr@534: { morphbr@534: file_info->valid_fields = GNOME_VFS_FILE_INFO_FIELDS_TYPE | morphbr@534: GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS; morphbr@534: morphbr@534: file_info->type = GNOME_VFS_FILE_TYPE_SOCKET; morphbr@534: morphbr@534: file_info->permissions = GNOME_VFS_PERM_USER_READ | morphbr@534: GNOME_VFS_PERM_OTHER_READ | morphbr@534: GNOME_VFS_PERM_GROUP_READ; morphbr@534: morphbr@534: return GNOME_VFS_OK; morphbr@534: } morphbr@534: morphbr@534: morphbr@534: static gboolean morphbr@534: do_is_local (GnomeVFSMethod * method, const GnomeVFSURI * uri) morphbr@534: { morphbr@534: return FALSE; morphbr@534: }