/* * @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; }