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: renatofilho@754: #include /* for socket(), connect(), send(), and renatofilho@754: * recv() */ renatofilho@754: #include /* for sockaddr_in and inet_addr() */ renatofilho@754: #include /* for atoi() and exit() */ renatofilho@754: #include /* for memset() */ renatofilho@754: #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 { renatofilho@754: gint port; renatofilho@754: gchar *hostname; morphbr@534: morphbr@534: GMythStreamClient *stream; renatofilho@754: gint fd; morphbr@534: } gmsHandle; morphbr@534: morphbr@534: typedef struct { renatofilho@754: gchar *file_name; renatofilho@754: gchar *mux; renatofilho@754: gchar *vcodec; renatofilho@754: guint vbitrate; renatofilho@754: gdouble fps; renatofilho@754: gchar *acodec; renatofilho@754: guint abitrate; renatofilho@754: guint width; renatofilho@754: guint height; renatofilho@754: guint port; renatofilho@754: gchar *opt; morphbr@534: } UriArgs; morphbr@534: morphbr@534: renatofilho@754: static gmsHandle *gmsHandle_new(GnomeVFSURI * uri); morphbr@534: renatofilho@754: static GnomeVFSResult renatofilho@754: do_open(GnomeVFSMethod * method, renatofilho@754: GnomeVFSMethodHandle ** method_handle, renatofilho@754: GnomeVFSURI * uri, renatofilho@754: GnomeVFSOpenMode mode, GnomeVFSContext * context); morphbr@534: renatofilho@754: static GnomeVFSResult renatofilho@754: do_read(GnomeVFSMethod * method, renatofilho@754: GnomeVFSMethodHandle * method_handle, renatofilho@754: gpointer buffer, renatofilho@754: GnomeVFSFileSize bytes, renatofilho@754: GnomeVFSFileSize * bytes_read, GnomeVFSContext * context); morphbr@534: renatofilho@754: static GnomeVFSResult renatofilho@754: do_close(GnomeVFSMethod * method, renatofilho@754: GnomeVFSMethodHandle * method_handle, GnomeVFSContext * context); morphbr@534: renatofilho@754: static GnomeVFSResult renatofilho@754: do_get_file_info(GnomeVFSMethod * method, renatofilho@754: GnomeVFSURI * uri, renatofilho@754: GnomeVFSFileInfo * file_info, renatofilho@754: GnomeVFSFileInfoOptions options, renatofilho@754: GnomeVFSContext * context); morphbr@534: morphbr@534: renatofilho@754: static GnomeVFSResult renatofilho@754: do_get_file_info_from_handle(GnomeVFSMethod * method, renatofilho@754: GnomeVFSMethodHandle * method_handle, renatofilho@754: GnomeVFSFileInfo * file_info, renatofilho@754: GnomeVFSFileInfoOptions options, renatofilho@754: GnomeVFSContext * context); morphbr@534: morphbr@534: renatofilho@754: static gboolean renatofilho@754: do_is_local(GnomeVFSMethod * method, const GnomeVFSURI * uri); morphbr@534: morphbr@534: renatofilho@754: static gmsHandle * renatofilho@754: gmsHandle_new(GnomeVFSURI * uri) morphbr@534: { renatofilho@754: gmsHandle *handler = (gmsHandle *) g_malloc0(sizeof(gmsHandle)); morphbr@534: renatofilho@754: handler->hostname = (gchar *) gnome_vfs_uri_get_host_name(uri); morphbr@534: handler->port = gnome_vfs_uri_get_host_port(uri); renatofilho@754: handler->stream = gmyth_stream_client_new(); morphbr@534: morphbr@534: return handler; morphbr@534: } morphbr@534: morphbr@534: static GnomeVFSMethod method = { renatofilho@754: sizeof(GnomeVFSMethod), renatofilho@754: do_open, /* open */ renatofilho@754: NULL, /* create */ renatofilho@754: do_close, /* close */ renatofilho@754: do_read, /* read */ renatofilho@754: NULL, /* write */ renatofilho@754: NULL, /* seek */ renatofilho@754: NULL, /* tell */ renatofilho@754: NULL, /* truncate_handle */ renatofilho@754: NULL, /* open_directory */ renatofilho@754: NULL, /* close_directory */ renatofilho@754: NULL, /* read_directory */ renatofilho@754: do_get_file_info, /* get_file_info */ renatofilho@754: do_get_file_info_from_handle, /* get_file_info_from_handle */ renatofilho@754: do_is_local, /* is_local */ renatofilho@754: NULL, /* make_directory */ renatofilho@754: NULL, /* remove_directory */ renatofilho@754: NULL, /* move */ renatofilho@754: NULL, /* unlink */ renatofilho@754: NULL, /* check_same_fs */ renatofilho@754: NULL, /* set_file_info */ renatofilho@754: NULL, /* truncate */ renatofilho@754: NULL, /* find_directory */ renatofilho@754: NULL, /* create_symbolic_link */ renatofilho@754: NULL, /* monitor_add */ renatofilho@754: NULL, /* monitor_cancel */ renatofilho@754: NULL /* file_control */ morphbr@534: }; morphbr@534: morphbr@534: GnomeVFSMethod * renatofilho@754: vfs_module_init(const char *method_name, const char *args) morphbr@534: { morphbr@534: return &method; morphbr@534: } morphbr@534: morphbr@534: void renatofilho@754: vfs_module_shutdown(GnomeVFSMethod * method) morphbr@534: { morphbr@534: return; morphbr@534: } morphbr@534: renatofilho@754: char * renatofilho@754: _parse_opt(char *opt) morphbr@544: { renatofilho@754: char **list = g_strsplit(opt, "opt=", 2); renatofilho@754: char **opts = g_strsplit(list[1], "+", 32); renatofilho@754: char *value = ""; renatofilho@754: char *aux; renatofilho@754: 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 * renatofilho@754: _uri_parse_args(const GnomeVFSURI * uri) morphbr@534: { renatofilho@754: gchar *file = gnome_vfs_unescape_string(uri->text, NULL); renatofilho@538: renatofilho@754: gchar **list = g_strsplit(file, "\'", 3); renatofilho@754: gchar **prefix = g_strsplit_set(list[0], "/=", 3); renatofilho@754: gchar **lst = g_strsplit(list[2], "?", 0); morphbr@544: renatofilho@754: UriArgs *info = g_new0(UriArgs, 1); renatofilho@754: gint i = 1; morphbr@534: renatofilho@754: gchar **prop = NULL; morphbr@544: prop = g_strsplit_set(lst[0], "/=", 3); morphbr@534: renatofilho@754: info->file_name = g_strdup_printf("%s://%s", prefix[1], list[1]); morphbr@534: renatofilho@754: // g_debug("FILENAME: [%s]", info->file_name); renatofilho@538: morphbr@544: g_strfreev(prop); morphbr@544: renatofilho@754: gchar *walk; renatofilho@754: for (walk = lst[1]; walk != NULL; walk = lst[++i]) { morphbr@544: prop = g_strsplit(walk, "=", 2); morphbr@534: renatofilho@754: if (g_strv_length(prop) == 2) { renatofilho@754: if (strcmp(prop[0], "mux") == 0) { renatofilho@754: info->mux = g_strdup(prop[1]); renatofilho@754: } else if (strcmp(prop[0], "vcodec") == 0) { renatofilho@754: info->vcodec = g_strdup(prop[1]); renatofilho@754: } else if (strcmp(prop[0], "vbitrate") == 0) { renatofilho@754: info->vbitrate = atoi(prop[1]); renatofilho@754: } else if (strcmp(prop[0], "fps") == 0) { renatofilho@754: info->fps = g_strtod(prop[1], NULL); renatofilho@754: } else if (strcmp(prop[0], "acodec") == 0) { renatofilho@754: info->acodec = g_strdup(prop[1]); renatofilho@754: } else if (strcmp(prop[0], "abitrate") == 0) { renatofilho@754: info->abitrate = atoi(prop[1]); renatofilho@754: } else if (strcmp(prop[0], "width") == 0) { renatofilho@754: info->width = atoi(prop[1]); renatofilho@754: } else if (strcmp(prop[0], "height") == 0) { renatofilho@754: info->height = atoi(prop[1]); renatofilho@754: } else if (strcmp(prop[0], "opt") == 0) { renatofilho@754: info->opt = g_strdup(_parse_opt(walk)); morphbr@534: } renatofilho@538: } renatofilho@754: g_strfreev(prop); morphbr@534: } morphbr@544: renatofilho@754: g_free(file); renatofilho@754: g_strfreev(list); renatofilho@754: g_strfreev(prefix); renatofilho@754: g_strfreev(lst); morphbr@534: return info; morphbr@534: } morphbr@534: renatofilho@754: static GnomeVFSResult renatofilho@754: do_open(GnomeVFSMethod * method, renatofilho@754: GnomeVFSMethodHandle ** method_handle, renatofilho@754: GnomeVFSURI * uri, renatofilho@754: GnomeVFSOpenMode mode, GnomeVFSContext * context) morphbr@534: { renatofilho@754: gmsHandle *handle = gmsHandle_new(uri); renatofilho@754: UriArgs *args; morphbr@534: renatofilho@754: if (!gmyth_stream_client_connect(handle->stream, renatofilho@754: gnome_vfs_uri_get_host_name(uri), renatofilho@754: gnome_vfs_uri_get_host_port(uri))) { morphbr@534: renatofilho@556: return GNOME_VFS_ERROR_HOST_NOT_FOUND; morphbr@534: } morphbr@534: renatofilho@754: args = _uri_parse_args(uri); morphbr@534: renatofilho@754: gint ret = gmyth_stream_client_open_stream(handle->stream, renatofilho@754: args->file_name, renatofilho@754: args->mux, renatofilho@754: args->vcodec, renatofilho@754: args->vbitrate, renatofilho@754: args->fps, renatofilho@754: args->acodec, renatofilho@754: args->abitrate, renatofilho@754: args->width, renatofilho@754: args->height, renatofilho@754: args->opt); morphbr@534: renatofilho@754: g_free(args); morphbr@534: morphbr@534: if (ret == -1) { renatofilho@754: gmyth_stream_client_disconnect(handle->stream); renatofilho@556: return GNOME_VFS_ERROR_HOST_NOT_FOUND; morphbr@534: } morphbr@534: renatofilho@754: handle->fd = gmyth_stream_client_play_stream(handle->stream); morphbr@534: morphbr@534: if (handle->fd == -1) { renatofilho@754: gmyth_stream_client_disconnect(handle->stream); renatofilho@556: return GNOME_VFS_ERROR_HOST_NOT_FOUND; morphbr@534: } morphbr@534: morphbr@534: *method_handle = (GnomeVFSMethodHandle *) handle; morphbr@534: return GNOME_VFS_OK; morphbr@534: } morphbr@534: renatofilho@754: static GnomeVFSResult renatofilho@754: do_read(GnomeVFSMethod * method, renatofilho@754: GnomeVFSMethodHandle * method_handle, renatofilho@754: gpointer buffer, renatofilho@754: GnomeVFSFileSize bytes, renatofilho@754: GnomeVFSFileSize * bytes_read, GnomeVFSContext * context) morphbr@534: { morphbr@534: renatofilho@754: gint64 total_read = 0; renatofilho@754: gmsHandle *handle = (gmsHandle *) method_handle; morphbr@534: renatofilho@754: // g_debug("waiting something"); morphbr@544: morphbr@534: total_read = recv(handle->fd, buffer, BUFFER_SIZE, 0); renatofilho@754: // g_debug("COULD READ: %d bytes", total_read); morphbr@534: *bytes_read = (GnomeVFSFileSize) total_read; morphbr@534: renatofilho@754: // if (total_read < 0) g_debug("ERROR!!!!!!!!!!!!!!!!"); morphbr@544: renatofilho@754: if (total_read < 0) renatofilho@754: return GNOME_VFS_ERROR_INTERNAL; renatofilho@754: else renatofilho@754: return GNOME_VFS_OK; morphbr@534: morphbr@534: } morphbr@534: renatofilho@754: static GnomeVFSResult renatofilho@754: do_close(GnomeVFSMethod * method, renatofilho@754: GnomeVFSMethodHandle * method_handle, GnomeVFSContext * context) morphbr@534: { renatofilho@754: gmsHandle *handle = (gmsHandle *) method_handle; morphbr@534: morphbr@544: g_debug("close close close"); morphbr@544: renatofilho@754: gmyth_stream_client_close_stream(handle->stream); renatofilho@754: 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: renatofilho@754: static GnomeVFSResult renatofilho@754: do_get_file_info(GnomeVFSMethod * method, renatofilho@754: GnomeVFSURI * uri, renatofilho@754: GnomeVFSFileInfo * file_info, renatofilho@754: GnomeVFSFileInfoOptions options, renatofilho@754: 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 | renatofilho@754: GNOME_VFS_PERM_OTHER_READ | GNOME_VFS_PERM_GROUP_READ; morphbr@534: morphbr@534: return GNOME_VFS_OK; morphbr@534: } morphbr@534: morphbr@534: renatofilho@754: static GnomeVFSResult renatofilho@754: do_get_file_info_from_handle(GnomeVFSMethod * method, renatofilho@754: GnomeVFSMethodHandle * method_handle, renatofilho@754: GnomeVFSFileInfo * file_info, renatofilho@754: GnomeVFSFileInfoOptions options, renatofilho@754: 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 | renatofilho@754: GNOME_VFS_PERM_OTHER_READ | GNOME_VFS_PERM_GROUP_READ; morphbr@534: morphbr@534: return GNOME_VFS_OK; morphbr@534: } morphbr@534: morphbr@534: renatofilho@754: static gboolean renatofilho@754: do_is_local(GnomeVFSMethod * method, const GnomeVFSURI * uri) morphbr@534: { morphbr@534: return FALSE; morphbr@534: }