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@544: char* _parse_opt(char* opt) morphbr@544: { morphbr@544: char** list = g_strsplit(opt, "opt=", 2); morphbr@544: char** opts = g_strsplit(list[1], "+", 32); morphbr@544: char* value = ""; morphbr@544: char* aux; morphbr@544: gint i = 0; morphbr@544: morphbr@544: for (aux = opts[0]; aux != NULL; aux = opts[++i]) morphbr@544: value = g_strdup_printf("%s %s", value, aux); morphbr@544: morphbr@544: g_free(aux); morphbr@544: g_strfreev(list); morphbr@544: g_strfreev(opts); morphbr@544: return value; morphbr@544: } morphbr@544: morphbr@534: static UriArgs * morphbr@534: _uri_parse_args (const GnomeVFSURI *uri) morphbr@534: { morphbr@544: gchar *file = gnome_vfs_unescape_string (uri->text, NULL); renatofilho@538: morphbr@544: gchar **list = g_strsplit(file, "\'", 3); morphbr@544: gchar **prefix = g_strsplit_set(list[0], "/=", 3); morphbr@544: gchar **lst = g_strsplit (list[2], "?", 0); morphbr@544: morphbr@534: UriArgs *info = g_new0 (UriArgs, 1); morphbr@544: gint i = 1; morphbr@534: morphbr@544: gchar** prop = NULL; morphbr@544: prop = g_strsplit_set(lst[0], "/=", 3); morphbr@534: morphbr@544: info->file_name = g_strdup_printf ("%s://%s",\ morphbr@544: prefix[1],list[1]); morphbr@534: morphbr@544: //g_debug("FILENAME: [%s]", info->file_name); renatofilho@538: morphbr@544: g_strfreev(prop); morphbr@544: morphbr@544: gchar* walk; morphbr@544: for (walk = lst[1]; walk != NULL; walk = lst[++i]) morphbr@534: { morphbr@544: prop = g_strsplit(walk, "=", 2); morphbr@534: morphbr@534: if (g_strv_length (prop) == 2) { morphbr@544: 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) { morphbr@544: info->opt = g_strdup (_parse_opt(walk)); morphbr@534: } renatofilho@538: } morphbr@534: g_strfreev (prop); morphbr@534: } morphbr@544: morphbr@534: g_free (file); morphbr@544: g_strfreev (list); morphbr@544: g_strfreev (prefix); morphbr@544: g_strfreev (lst); 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: 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@544: //g_debug("waiting something"); morphbr@544: morphbr@534: total_read = recv(handle->fd, buffer, BUFFER_SIZE, 0); morphbr@544: //g_debug("COULD READ: %d bytes", total_read); morphbr@534: *bytes_read = (GnomeVFSFileSize) total_read; morphbr@534: morphbr@544: //if (total_read < 0) g_debug("ERROR!!!!!!!!!!!!!!!!"); morphbr@544: 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@544: g_debug("close close close"); morphbr@544: 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: }