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