From 98c015281edde85ca84602d1926b77c682d35474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 14 May 2016 11:09:48 +0300 Subject: [PATCH] Implement GstURIHandler interface and handle short reads --- src/plugin.c | 2 +- src/rsfilesrc.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++- src/rsfilesrc.rs | 27 ++++++------ 3 files changed, 116 insertions(+), 17 deletions(-) diff --git a/src/plugin.c b/src/plugin.c index 8c9e4623..c40d3856 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -6,7 +6,7 @@ static gboolean plugin_init (GstPlugin * plugin) { - if (!gst_element_register (plugin, "rsfilesrc", GST_RANK_NONE, + if (!gst_element_register (plugin, "rsfilesrc", GST_RANK_PRIMARY+100, GST_TYPE_RSFILE_SRC)) { return FALSE; } diff --git a/src/rsfilesrc.c b/src/rsfilesrc.c index 88434197..1e1bf0fe 100644 --- a/src/rsfilesrc.c +++ b/src/rsfilesrc.c @@ -1,11 +1,12 @@ #include "rsfilesrc.h" +#include #include /* Declarations for Rust code */ extern void * filesrc_new (void); extern void filesrc_drop (void * filesrc); -extern GstFlowReturn filesrc_fill (void * filesrc, void * data, size_t data_len); +extern GstFlowReturn filesrc_fill (void * filesrc, void * data, size_t * data_len); extern void filesrc_set_location (void * filesrc, const char *location); extern char * filesrc_get_location (void * filesrc); extern uint64_t filesrc_get_size (void * filesrc); @@ -27,6 +28,9 @@ enum PROP_LOCATION }; +static void gst_rsfile_src_uri_handler_init (gpointer g_iface, + gpointer iface_data); + static void gst_rsfile_src_finalize (GObject * object); static void gst_rsfile_src_set_property (GObject * object, guint prop_id, @@ -43,6 +47,7 @@ static GstFlowReturn gst_rsfile_src_fill (GstBaseSrc * src, guint64 offset, guint length, GstBuffer * buf); #define _do_init \ + G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, gst_rsfile_src_uri_handler_init); \ GST_DEBUG_CATEGORY_INIT (gst_rsfile_src_debug, "rsfilesrc", 0, "rsfilesrc element"); #define gst_rsfile_src_parent_class parent_class G_DEFINE_TYPE_WITH_CODE (GstRsfileSrc, gst_rsfile_src, GST_TYPE_BASE_SRC, _do_init); @@ -140,10 +145,14 @@ gst_rsfile_src_fill (GstBaseSrc * basesrc, guint64 offset, guint length, GstRsfileSrc *src = GST_RSFILE_SRC (basesrc); GstMapInfo map; GstFlowReturn ret; + gsize size; gst_buffer_map (buf, &map, GST_MAP_READWRITE); - ret = filesrc_fill (src->instance, map.data, map.size); + size = map.size; + ret = filesrc_fill (src->instance, map.data, &size); gst_buffer_unmap (buf, &map); + if (ret == GST_FLOW_OK) + gst_buffer_resize (buf, 0, size); return ret; } @@ -184,4 +193,95 @@ gst_rsfile_src_stop (GstBaseSrc * basesrc) return filesrc_stop (src->instance); } +static GstURIType +gst_rsfile_src_uri_get_type (GType type) +{ + return GST_URI_SRC; +} +static const gchar *const * +gst_rsfile_src_uri_get_protocols (GType type) +{ + static const gchar *protocols[] = { "file", NULL }; + + return protocols; +} + +static gchar * +gst_rsfile_src_uri_get_uri (GstURIHandler * handler) +{ + GstRsfileSrc *src = GST_RSFILE_SRC (handler); + gchar *location, *uri; + + location = filesrc_get_location (src->instance); + if (!location) + return NULL; + uri = gst_filename_to_uri (location, NULL); + g_free (location); + + return uri; +} + +static gboolean +gst_rsfile_src_uri_set_uri (GstURIHandler * handler, const gchar * uri, + GError ** err) +{ + gchar *location, *hostname = NULL; + gboolean ret = FALSE; + GstRsfileSrc *src = GST_RSFILE_SRC (handler); + + if (strcmp (uri, "file://") == 0) { + /* Special case for "file://" as this is used by some applications + * to test with gst_element_make_from_uri if there's an element + * that supports the URI protocol. */ + filesrc_set_location (src->instance, location); + return TRUE; + } + + location = g_filename_from_uri (uri, &hostname, err); + + if (!location || (err != NULL && *err != NULL)) { + GST_WARNING_OBJECT (src, "Invalid URI '%s' for filesrc: %s", uri, + (err != NULL && *err != NULL) ? (*err)->message : "unknown error"); + goto beach; + } + + if ((hostname) && (strcmp (hostname, "localhost"))) { + /* Only 'localhost' is permitted */ + GST_WARNING_OBJECT (src, "Invalid hostname '%s' for filesrc", hostname); + g_set_error (err, GST_URI_ERROR, GST_URI_ERROR_BAD_URI, + "File URI with invalid hostname '%s'", hostname); + goto beach; + } +#ifdef G_OS_WIN32 + /* Unfortunately, g_filename_from_uri() doesn't handle some UNC paths + * correctly on windows, it leaves them with an extra backslash + * at the start if they're of the mozilla-style file://///host/path/file + * form. Correct this. + */ + if (location[0] == '\\' && location[1] == '\\' && location[2] == '\\') + memmove (location, location + 1, strlen (location + 1) + 1); +#endif + + ret = TRUE; + filesrc_set_location (src->instance, location); + +beach: + if (location) + g_free (location); + if (hostname) + g_free (hostname); + + return ret; +} + +static void +gst_rsfile_src_uri_handler_init (gpointer g_iface, gpointer iface_data) +{ + GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; + + iface->get_type = gst_rsfile_src_uri_get_type; + iface->get_protocols = gst_rsfile_src_uri_get_protocols; + iface->get_uri = gst_rsfile_src_uri_get_uri; + iface->set_uri = gst_rsfile_src_uri_set_uri; +} diff --git a/src/rsfilesrc.rs b/src/rsfilesrc.rs index 8d982f36..4d618019 100644 --- a/src/rsfilesrc.rs +++ b/src/rsfilesrc.rs @@ -78,24 +78,17 @@ impl FileSrc { true } - fn fill(&mut self, data: &mut [u8]) -> GstFlowReturn { + fn fill(&mut self, data: &mut [u8]) -> Result { match self.file { - None => return GstFlowReturn::Error, + None => return Err(GstFlowReturn::Error), Some(ref mut f) => { // FIXME: Need to return the actual size, handle EOF, etc - f.read(data); - return GstFlowReturn::Ok; + return Ok(f.read(data).unwrap()); }, } } } -impl Drop for FileSrc { - fn drop(&mut self) { - println!("drop"); - } -} - #[no_mangle] pub extern "C" fn filesrc_new() -> *mut FileSrc { let instance = Box::new(FileSrc::new()); @@ -132,12 +125,18 @@ pub extern "C" fn filesrc_get_location(ptr: *mut FileSrc) -> *mut c_char { } #[no_mangle] -pub extern "C" fn filesrc_fill(ptr: *mut FileSrc, data_ptr: *mut u8, data_len: usize) -> GstFlowReturn { +pub extern "C" fn filesrc_fill(ptr: *mut FileSrc, data_ptr: *mut u8, data_len_ptr: *mut usize) -> GstFlowReturn { let filesrc: &mut FileSrc = unsafe { &mut *ptr }; - println!("{:?}", filesrc); - let mut data = unsafe { slice::from_raw_parts_mut(data_ptr, data_len) }; - return filesrc.fill(data); + let mut data_len: &mut usize = unsafe { &mut *data_len_ptr }; + let mut data = unsafe { slice::from_raw_parts_mut(data_ptr, *data_len) }; + match filesrc.fill(data) { + Ok(actual_len) => { + *data_len = actual_len; + GstFlowReturn::Ok + }, + Err(ret) => ret, + } } #[no_mangle]