summaryrefslogtreecommitdiffstats
path: root/sys/wininet
diff options
context:
space:
mode:
authorOle André Vadla Ravnås <ole.andre.ravnas@tandberg.com>2008-04-10 15:29:44 +0000
committerTim-Philipp Müller <tim@centricular.net>2008-04-10 15:29:44 +0000
commit44611701ba38e51c0cc47512b572fd0a51fd2317 (patch)
tree3d0e0d5e587ed182d635ccc5931428cb401ca7fa /sys/wininet
parentc1193130c29d594635ed7547bb625e26e6123d75 (diff)
downloadgst-plugins-bad-44611701ba38e51c0cc47512b572fd0a51fd2317.tar.gz
gst-plugins-bad-44611701ba38e51c0cc47512b572fd0a51fd2317.tar.bz2
gst-plugins-bad-44611701ba38e51c0cc47512b572fd0a51fd2317.zip
Add wininetsrc for basic http/ftp support on windows (#520897).
Original commit message from CVS: Patch by: Ole André Vadla Ravnås <ole.andre.ravnas at tandberg com> * configure.ac: * sys/Makefile.am: * sys/wininet/Makefile.am: * sys/wininet/gstwininetsrc.c: * sys/wininet/gstwininetsrc.h: Add wininetsrc for basic http/ftp support on windows (#520897).
Diffstat (limited to 'sys/wininet')
-rw-r--r--sys/wininet/Makefile.am10
-rw-r--r--sys/wininet/gstwininetsrc.c453
-rw-r--r--sys/wininet/gstwininetsrc.h69
3 files changed, 532 insertions, 0 deletions
diff --git a/sys/wininet/Makefile.am b/sys/wininet/Makefile.am
new file mode 100644
index 00000000..bbd6453d
--- /dev/null
+++ b/sys/wininet/Makefile.am
@@ -0,0 +1,10 @@
+plugin_LTLIBRARIES = libgstwininet.la
+
+libgstwininet_la_SOURCES = gstwininetsrc.c
+
+libgstwininet_la_CFLAGS = $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstwininet_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) -lwininet
+libgstwininet_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstwininetsrc.h
+
diff --git a/sys/wininet/gstwininetsrc.c b/sys/wininet/gstwininetsrc.c
new file mode 100644
index 00000000..ea194d30
--- /dev/null
+++ b/sys/wininet/gstwininetsrc.c
@@ -0,0 +1,453 @@
+/* GStreamer Windows network source
+ * Copyright (C) 2008 Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-wininetsrc
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * <para>
+ * <programlisting>
+ * gst-launch-0.10 -v wininetsrc location="http://71.83.57.210:9000" ! application/x-icy,metadata-interval=0 ! icydemux ! mad ! audioconvert ! directsoundsink
+ * </programlisting>
+ * </para>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gstwininetsrc.h"
+
+#include <string.h>
+
+#define DEFAULT_LOCATION "http://localhost/"
+#define DEFAULT_POLL_MODE FALSE
+#define DEFAULT_IRADIO_MODE FALSE
+
+enum
+{
+ PROP_0,
+ PROP_LOCATION,
+ PROP_POLL_MODE,
+ PROP_IRADIO_MODE
+};
+
+GST_DEBUG_CATEGORY_STATIC (gst_win_inet_src_debug);
+#define GST_CAT_DEFAULT gst_win_inet_src_debug
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+static void gst_win_inet_src_init_interfaces (GType type);
+static void gst_win_inet_src_uri_handler_init (gpointer g_iface,
+ gpointer iface_data);
+
+static void gst_win_inet_src_dispose (GObject * object);
+static void gst_win_inet_src_finalize (GObject * object);
+static void gst_win_inet_src_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_win_inet_src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+
+static gboolean gst_win_inet_src_start (GstBaseSrc * basesrc);
+static gboolean gst_win_inet_src_stop (GstBaseSrc * basesrc);
+
+static GstFlowReturn gst_win_inet_src_create (GstPushSrc * pushsrc,
+ GstBuffer ** buffer);
+
+static void gst_win_inet_src_reset (GstWinInetSrc * self);
+
+GST_BOILERPLATE_FULL (GstWinInetSrc, gst_win_inet_src, GstPushSrc,
+ GST_TYPE_PUSH_SRC, gst_win_inet_src_init_interfaces);
+
+static void
+gst_win_inet_src_base_init (gpointer gclass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&src_template));
+
+ gst_element_class_set_details_simple (element_class,
+ "Windows Network Source", "Source/Network",
+ "Receive data as a client over the network via HTTP or FTP",
+ "Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>");
+}
+
+static void
+gst_win_inet_src_class_init (GstWinInetSrcClass * klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
+ GstPushSrcClass *gstpushsrc_class = GST_PUSH_SRC_CLASS (klass);
+
+ gobject_class->dispose = gst_win_inet_src_dispose;
+ gobject_class->finalize = gst_win_inet_src_finalize;
+ gobject_class->get_property = gst_win_inet_src_get_property;
+ gobject_class->set_property = gst_win_inet_src_set_property;
+
+ gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_win_inet_src_start);
+ gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_win_inet_src_stop);
+ gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_win_inet_src_create);
+
+ g_object_class_install_property (gobject_class,
+ PROP_LOCATION, g_param_spec_string ("location", "Location",
+ "Location to read from", DEFAULT_LOCATION, G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class,
+ PROP_POLL_MODE, g_param_spec_boolean ("poll-mode", "poll-mode",
+ "Enable poll mode (keep re-issuing request)",
+ DEFAULT_POLL_MODE, G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class,
+ PROP_IRADIO_MODE, g_param_spec_boolean ("iradio-mode", "iradio-mode",
+ "Enable Internet radio mode "
+ "(extraction of shoutcast/icecast metadata)",
+ DEFAULT_IRADIO_MODE, G_PARAM_READWRITE));
+}
+
+static void
+gst_win_inet_src_init_interfaces (GType type)
+{
+ static const GInterfaceInfo uri_handler_info = {
+ gst_win_inet_src_uri_handler_init,
+ NULL,
+ NULL
+ };
+
+ g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &uri_handler_info);
+
+ GST_DEBUG_CATEGORY_INIT (gst_win_inet_src_debug, "wininetsrc",
+ 0, "Wininet source");
+}
+
+static void
+gst_win_inet_src_init (GstWinInetSrc * self, GstWinInetSrcClass * gclass)
+{
+ self->location = g_strdup (DEFAULT_LOCATION);
+ self->poll_mode = DEFAULT_POLL_MODE;
+ self->iradio_mode = DEFAULT_IRADIO_MODE;
+
+ self->inet = NULL;
+ self->url = NULL;
+ self->cur_offset = 0;
+ self->icy_caps = NULL;
+}
+
+static void
+gst_win_inet_src_dispose (GObject * object)
+{
+ GstWinInetSrc *self = GST_WIN_INET_SRC (object);
+
+ gst_win_inet_src_reset (self);
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_win_inet_src_finalize (GObject * object)
+{
+ GstWinInetSrc *self = GST_WIN_INET_SRC (object);
+
+ g_free (self->location);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_win_inet_src_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstWinInetSrc *self = GST_WIN_INET_SRC (object);
+
+ switch (prop_id) {
+ case PROP_LOCATION:
+ g_value_set_string (value, self->location);
+ break;
+
+ case PROP_POLL_MODE:
+ g_value_set_boolean (value, self->poll_mode);
+ break;
+
+ case PROP_IRADIO_MODE:
+ g_value_set_boolean (value, self->iradio_mode);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_win_inet_src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstWinInetSrc *self = GST_WIN_INET_SRC (object);
+
+ switch (prop_id) {
+ case PROP_LOCATION:
+ if (GST_STATE (self) == GST_STATE_PLAYING ||
+ GST_STATE (self) == GST_STATE_PAUSED) {
+ GST_WARNING_OBJECT (self, "element must be in stopped or paused state "
+ "in order to change location");
+ break;
+ }
+
+ g_free (self->location);
+ self->location = g_value_dup_string (value);
+ break;
+
+ case PROP_POLL_MODE:
+ self->poll_mode = g_value_get_boolean (value);
+ break;
+
+ case PROP_IRADIO_MODE:
+ self->iradio_mode = g_value_get_boolean (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_win_inet_src_reset (GstWinInetSrc * self)
+{
+ if (self->url != NULL) {
+ InternetCloseHandle (self->url);
+ self->url = NULL;
+ }
+
+ if (self->inet != NULL) {
+ InternetCloseHandle (self->inet);
+ self->inet = NULL;
+ }
+
+ if (self->icy_caps != NULL) {
+ gst_caps_unref (self->icy_caps);
+ self->icy_caps = NULL;
+ }
+
+ self->cur_offset = 0;
+}
+
+static gboolean
+gst_win_inet_src_get_header_value_as_int (GstWinInetSrc * self,
+ const gchar * header_name, gint * header_value, gboolean log_failure)
+{
+ gchar buf[16] = { 0, };
+ DWORD buf_size = sizeof (buf);
+ gint *value = (gint *) buf;
+
+ strcpy (buf, header_name);
+
+ if (!HttpQueryInfo (self->url, HTTP_QUERY_CUSTOM | HTTP_QUERY_FLAG_NUMBER,
+ buf, &buf_size, NULL)) {
+ if (log_failure) {
+ DWORD error_code = GetLastError ();
+ const gchar *error_str = "unknown error";
+
+ if (error_code == ERROR_HTTP_HEADER_NOT_FOUND)
+ error_str = "ERROR_HTTP_HEADER_NOT_FOUND";
+
+ GST_WARNING_OBJECT (self, "HttpQueryInfo for header '%s' failed: %s "
+ "(0x%08x)", header_name, error_str, error_code);
+ }
+
+ return FALSE;
+ }
+
+ *header_value = *value;
+ return TRUE;
+}
+
+static gboolean
+gst_win_inet_src_open (GstWinInetSrc * self)
+{
+ const gchar *extra_headers = NULL;
+
+ gst_win_inet_src_reset (self);
+
+ self->inet = InternetOpen (NULL, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
+ if (self->inet == NULL)
+ goto error;
+
+ if (self->iradio_mode)
+ extra_headers = "Icy-MetaData:1"; /* exactly as sent by WinAmp, no space */
+
+ self->url = InternetOpenUrl (self->inet, self->location, extra_headers,
+ (extra_headers != NULL) ? -1 : 0, INTERNET_FLAG_NO_UI, (DWORD_PTR) self);
+ if (self->url == NULL)
+ goto error;
+
+ if (self->iradio_mode) {
+ gint value;
+
+ if (gst_win_inet_src_get_header_value_as_int (self, "icy-metaint", &value,
+ TRUE)) {
+ self->icy_caps = gst_caps_new_simple ("application/x-icy",
+ "metadata-interval", G_TYPE_INT, value, NULL);
+ }
+ }
+
+ return TRUE;
+
+error:
+ GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND, (NULL),
+ ("Could not open location \"%s\" for reading: 0x%08x",
+ self->location, GetLastError ()));
+ gst_win_inet_src_reset (self);
+
+ return FALSE;
+}
+
+static gboolean
+gst_win_inet_src_start (GstBaseSrc * basesrc)
+{
+ GstWinInetSrc *self = GST_WIN_INET_SRC (basesrc);
+
+ return gst_win_inet_src_open (self);
+}
+
+static gboolean
+gst_win_inet_src_stop (GstBaseSrc * basesrc)
+{
+ gst_win_inet_src_reset (GST_WIN_INET_SRC (basesrc));
+
+ return TRUE;
+}
+
+static GstFlowReturn
+gst_win_inet_src_create (GstPushSrc * pushsrc, GstBuffer ** buffer)
+{
+ GstWinInetSrc *self = GST_WIN_INET_SRC (pushsrc);
+ GstBaseSrc *basesrc = GST_BASE_SRC (pushsrc);
+ GstBuffer *buf = NULL;
+ GstFlowReturn ret = GST_FLOW_OK;
+ DWORD bytes_read = 0;
+
+ do {
+ GstCaps *caps = GST_PAD_CAPS (GST_BASE_SRC_PAD (self));
+
+ if (self->icy_caps != NULL)
+ caps = self->icy_caps;
+
+ ret = gst_pad_alloc_buffer (GST_BASE_SRC_PAD (basesrc),
+ self->cur_offset, basesrc->blocksize, caps, &buf);
+
+ if (G_LIKELY (ret == GST_FLOW_OK)) {
+ if (InternetReadFile (self->url, GST_BUFFER_DATA (buf),
+ basesrc->blocksize, &bytes_read)) {
+ if (bytes_read == 0) {
+ if (self->poll_mode) {
+ if (gst_win_inet_src_open (self)) {
+ gst_buffer_unref (buf);
+ buf = NULL;
+ } else {
+ ret = GST_FLOW_ERROR;
+ }
+ } else {
+ GST_ERROR_OBJECT (self, "short read (eof?)");
+ ret = GST_FLOW_UNEXPECTED;
+ }
+ }
+ } else {
+ GST_ERROR_OBJECT (self, "InternetReadFile failed: 0x%08x",
+ GetLastError ());
+
+ ret = GST_FLOW_ERROR;
+ }
+ }
+ }
+ while (bytes_read == 0 && ret == GST_FLOW_OK);
+
+ if (ret == GST_FLOW_OK) {
+ GST_BUFFER_SIZE (buf) = bytes_read;
+ self->cur_offset += bytes_read;
+
+ *buffer = buf;
+ } else {
+ if (buf != NULL)
+ gst_buffer_unref (buf);
+ }
+
+ return ret;
+}
+
+static GstURIType
+gst_win_inet_src_uri_get_type (void)
+{
+ return GST_URI_SRC;
+}
+
+static gchar **
+gst_win_inet_src_uri_get_protocols (void)
+{
+ static gchar *protocols[] = { "http", "https", "ftp", NULL };
+
+ return protocols;
+}
+
+static G_CONST_RETURN gchar *
+gst_win_inet_src_uri_get_uri (GstURIHandler * handler)
+{
+ GstWinInetSrc *src = GST_WIN_INET_SRC (handler);
+
+ return src->location;
+}
+
+static gboolean
+gst_win_inet_src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
+{
+ GstWinInetSrc *src = GST_WIN_INET_SRC (handler);
+
+ g_free (src->location);
+ src->location = g_strdup (uri);
+ return TRUE;
+}
+
+static void
+gst_win_inet_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+ GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+ iface->get_type = gst_win_inet_src_uri_get_type;
+ iface->get_protocols = gst_win_inet_src_uri_get_protocols;
+ iface->get_uri = gst_win_inet_src_uri_get_uri;
+ iface->set_uri = gst_win_inet_src_uri_set_uri;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "wininetsrc",
+ GST_RANK_NONE, GST_TYPE_WIN_INET_SRC);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "wininet",
+ "Windows network plugins",
+ plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/sys/wininet/gstwininetsrc.h b/sys/wininet/gstwininetsrc.h
new file mode 100644
index 00000000..d2a69183
--- /dev/null
+++ b/sys/wininet/gstwininetsrc.h
@@ -0,0 +1,69 @@
+/* GStreamer Windows network source
+ * Copyright (C) 2008 Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_WIN_INET_SRC_H__
+#define __GST_WIN_INET_SRC_H__
+
+#include <windows.h>
+#include <wininet.h>
+#include <gst/base/gstpushsrc.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_WIN_INET_SRC \
+ (gst_win_inet_src_get_type ())
+#define GST_WIN_INET_SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WIN_INET_SRC, GstWinInetSrc))
+#define GST_WIN_INET_SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_WIN_INET_SRC, GstWinInetSrcClass))
+#define GST_IS_WIN_INET_SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WIN_INET_SRC))
+#define GST_IS_WIN_INET_SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_WIN_INET_SRC))
+
+typedef struct _GstWinInetSrc GstWinInetSrc;
+typedef struct _GstWinInetSrcClass GstWinInetSrcClass;
+
+struct _GstWinInetSrc
+{
+ GstPushSrc push_src;
+
+ /* property storage */
+ gchar * location;
+ gboolean poll_mode;
+ gboolean iradio_mode;
+
+ /* state */
+ HINTERNET inet;
+ HINTERNET url;
+ guint64 cur_offset;
+ GstCaps * icy_caps;
+};
+
+struct _GstWinInetSrcClass
+{
+ GstPushSrcClass parent_class;
+};
+
+GType gst_win_inet_src_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_WIN_INET_SRC_H__ */
+