/* * @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; } static UriArgs * _uri_parse_args (const GnomeVFSURI *uri) { gchar *file; UriArgs *info = g_new0 (UriArgs, 1); GSList *args = NULL; gchar *c; GString *entry; gboolean open = FALSE; gchar **prop; GSList* walk; gchar *uri_str = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_USER_NAME | GNOME_VFS_URI_HIDE_PASSWORD | GNOME_VFS_URI_HIDE_HOST_NAME | GNOME_VFS_URI_HIDE_HOST_PORT | GNOME_VFS_URI_HIDE_TOPLEVEL_METHOD); file = gnome_vfs_unescape_string (uri_str, ""); c = file; entry = g_string_new (""); c = c + 1; do { if ((*c == '\"') || (*c == '\'')) { open = !open; } if (((*c == '?') || (c[1] == '\0')) && !open) { if (*c != '?') g_string_append_c (entry, *c); args = g_slist_append (args, g_strdup (entry->str)); entry = g_string_assign (entry, ""); } else { if (*c == '+') g_string_append_c (entry, "//"); else g_string_append_c (entry, *c); } c = c + 1; } while (*c != '\0'); g_string_free (entry, TRUE); for (walk = args; walk != NULL; walk = walk->next) { gchar *arg = (gchar *) walk->data; prop = g_strsplit(arg, "=", 2); g_debug ("arg = %s", arg); if (g_strv_length (prop) == 2) { if (strcmp (prop[0], "file") == 0) { info->file_name = g_strdup (prop[1]); } else 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) { g_debug("DENTRO DE OPT: %s", arg); //char* v = _parse_opt(walk); info->opt = g_strdup (arg); } } g_strfreev (prop); g_free (arg); } g_free (file); g_slist_free (args); return info; } static GnomeVFSResult do_open (GnomeVFSMethod *method, GnomeVFSMethodHandle **method_handle, GnomeVFSURI *uri, GnomeVFSOpenMode mode, GnomeVFSContext *context) { gmsHandle *handle = gmsHandle_new(uri); UriArgs *args; args = _uri_parse_args (uri); 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_INVALID_FILENAME; } 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_INVALID_FILENAME; } handle->fd = gmyth_stream_client_play_stream (handle->stream); if (handle->fd == -1) { gmyth_stream_client_disconnect (handle->stream); return GNOME_VFS_ERROR_INVALID_FILENAME; } *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; total_read = recv(handle->fd, buffer, BUFFER_SIZE, 0); *bytes_read = (GnomeVFSFileSize) total_read; 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; 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; }