[vlc-devel] [PATCH 1/4] stream_filter/icy: Add ICY metadata stream filter
Marvin Scholz
epirat07 at gmail.com
Wed Nov 1 05:16:33 CET 2017
---
modules/stream_filter/Makefile.am | 3 +
modules/stream_filter/icy.c | 254 ++++++++++++++++++++++++++++++++++++++
2 files changed, 257 insertions(+)
create mode 100644 modules/stream_filter/icy.c
diff --git a/modules/stream_filter/Makefile.am b/modules/stream_filter/Makefile.am
index 50d99faac9..d125556452 100644
--- a/modules/stream_filter/Makefile.am
+++ b/modules/stream_filter/Makefile.am
@@ -22,6 +22,9 @@ if HAVE_ZLIB
stream_filter_LTLIBRARIES += libinflate_plugin.la
endif
+libicy_plugin_la_SOURCES = stream_filter/icy.c
+stream_filter_LTLIBRARIES += libicy_plugin.la
+
libprefetch_plugin_la_SOURCES = stream_filter/prefetch.c
libprefetch_plugin_la_LIBADD = $(LIBPTHREAD)
if !HAVE_WINSTORE
diff --git a/modules/stream_filter/icy.c b/modules/stream_filter/icy.c
new file mode 100644
index 0000000000..22e586128c
--- /dev/null
+++ b/modules/stream_filter/icy.c
@@ -0,0 +1,254 @@
+/*****************************************************************************
+ * icy.c: ICY metadata extraction module for VLC
+ *****************************************************************************
+ * Copyright (C) 2017 VLC authors and VideoLAN
+ *
+ * Authors: Marvin Scholz <epirat07 at gmail dot com>
+ *
+ * This file reuses code from the old http access module,
+ * Authors: Laurent Aimar <fenrir at via.ecp.fr>
+ * Christophe Massiot <massiot at via.ecp.fr>
+ * RĂ©mi Denis-Courmont <rem # videolan.org>
+ * Antoine Cellerier <dionoea at videolan dot org>
+ *
+ * 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.1 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 Lesser General Public License for more details.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_stream.h>
+#include <vlc_input.h>
+#include <vlc_charset.h>
+
+struct stream_sys_t
+{
+ int icy_metaint;
+ char *icy_title;
+
+ uint64_t offset;
+};
+
+static void ParseICYData(stream_t *stream, char *data)
+{
+ stream_sys_t *sys = stream->p_sys;
+ char *start = strcasestr(data, "StreamTitle=");
+
+ if (!start)
+ return;
+
+ start += strlen("StreamTitle=");
+ if (*start == '\'' || *start == '"')
+ {
+ char closing[] = { start[0], ';', '\0' };
+ char *end = strstr(&start[1], closing);
+ if (!end)
+ end = strchr(&start[1], ';');
+
+ if (end)
+ *end = '\0';
+ }
+ else
+ {
+ char *end = strchr( &start[1], ';' );
+ if (end)
+ *end = '\0';
+ }
+
+ if (!sys->icy_title || strcmp(sys->icy_title, &start[1]))
+ {
+ free(sys->icy_title);
+ char *tmp = strdup(&start[1]);
+ sys->icy_title = EnsureUTF8(tmp);
+ if (!sys->icy_title)
+ free(tmp);
+
+ msg_Dbg(stream, "New Icy-Title=%s", sys->icy_title);
+ input_thread_t *input = stream->p_input;
+ if (input)
+ {
+ input_item_t *input_item = input_GetItem(input);
+ if (input_item)
+ input_item_SetMeta( input_item, vlc_meta_NowPlaying, sys->icy_title );
+ }
+ }
+}
+
+static int ReadICYMeta( stream_t *stream )
+{
+ uint8_t buffer;
+ size_t data_read;
+ char *icy_data;
+
+ /* Read meta data length */
+ if (vlc_stream_Read(stream->p_source, &buffer, 1) != 1)
+ return VLC_EGENERIC;
+
+ const uint8_t icy_size = buffer << 4;
+
+ if (icy_size == 0)
+ return VLC_SUCCESS;
+
+ icy_data = malloc(icy_size + 1);
+ for (data_read = 0; data_read < icy_size;)
+ {
+ size_t tmp_read;
+
+ tmp_read = vlc_stream_Read(stream->p_source, &icy_data[data_read], icy_size - data_read);
+
+ if (tmp_read <= 0)
+ {
+ free(icy_data);
+ return VLC_EGENERIC;
+ }
+ data_read += tmp_read;
+ }
+ icy_data[data_read] = '\0'; /* Just in case */
+
+ /* Now parse the meta */
+ ParseICYData(stream, icy_data);
+
+ free(icy_data);
+
+ return VLC_SUCCESS;
+}
+
+static ssize_t Read(stream_t *stream, void *buf, size_t buflen)
+{
+ stream_sys_t *p_sys = stream->p_sys;
+ int i_read = 0;
+
+ if (p_sys->icy_metaint > 0 && p_sys->offset > 0)
+ {
+ int i_next = p_sys->icy_metaint - (p_sys->offset % p_sys->icy_metaint);
+
+ if (i_next == p_sys->icy_metaint)
+ {
+ p_sys->offset = 0;
+ if (ReadICYMeta(stream))
+ return 0;
+ }
+ if (buflen > (size_t)i_next)
+ buflen = i_next;
+ }
+
+ i_read = vlc_stream_Read(stream->p_source, buf, buflen);
+
+ if (i_read < 0)
+ return -1;
+
+ p_sys->offset += i_read;
+ return i_read;
+}
+
+static int ReadDir(stream_t *stream, input_item_node_t *node)
+{
+ (void) stream; (void) node;
+ return VLC_EGENERIC;
+}
+
+static int Seek(stream_t *stream, uint64_t offset)
+{
+ (void) stream; (void) offset;
+ return -1;
+}
+
+static int Control(stream_t *stream, int query, va_list args)
+{
+ switch (query)
+ {
+ case STREAM_CAN_SEEK:
+ case STREAM_CAN_FASTSEEK:
+ *va_arg(args, bool *) = false;
+ break;
+ case STREAM_CAN_PAUSE:
+ case STREAM_CAN_CONTROL_PACE:
+ case STREAM_GET_PTS_DELAY:
+ case STREAM_GET_META:
+ case STREAM_GET_CONTENT_TYPE:
+ case STREAM_GET_SIGNAL:
+ case STREAM_SET_PAUSE_STATE:
+ return vlc_stream_vaControl(stream->p_source, query, args);
+ case STREAM_IS_DIRECTORY:
+ case STREAM_GET_SIZE:
+ case STREAM_GET_TITLE_INFO:
+ case STREAM_GET_TITLE:
+ case STREAM_GET_SEEKPOINT:
+ case STREAM_SET_TITLE:
+ case STREAM_SET_SEEKPOINT:
+ case STREAM_SET_PRIVATE_ID_STATE:
+ case STREAM_SET_PRIVATE_ID_CA:
+ case STREAM_GET_PRIVATE_ID_STATE:
+ return VLC_EGENERIC;
+ default:
+ msg_Err(stream, "unimplemented query (%d) in control", query);
+ return VLC_EGENERIC;
+ }
+ return VLC_SUCCESS;
+}
+
+static int Open(vlc_object_t *obj)
+{
+ stream_t *stream = (stream_t *)obj;
+
+ int metaint = var_InheritInteger(stream, "icy-metaint");
+ if (metaint < 0)
+ return VLC_EGENERIC;
+
+ config_PutInt(stream, "icy-metaint", -1);
+
+ stream_sys_t *sys = malloc(sizeof (*sys));
+ if (unlikely(sys == NULL))
+ return VLC_ENOMEM;
+
+ sys->offset = 0;
+ sys->icy_metaint = metaint;
+ sys->icy_title = NULL;
+
+ stream->p_sys = sys;
+ stream->pf_read = Read;
+ stream->pf_readdir = ReadDir;
+ stream->pf_seek = Seek;
+ stream->pf_control = Control;
+
+ return VLC_SUCCESS;
+}
+
+static void Close (vlc_object_t *obj)
+{
+ stream_t *stream = (stream_t *)obj;
+ stream_sys_t *sys = stream->p_sys;
+ free(sys->icy_title);
+ free(sys);
+}
+
+vlc_module_begin()
+ set_category(CAT_INPUT)
+ set_subcategory(SUBCAT_INPUT_STREAM_FILTER)
+ set_capability("stream_filter", 30)
+
+ set_description(N_("ICY metadata filter"))
+
+ add_integer("icy-metaint", -1, "ICY metaint", NULL, true)
+ change_volatile()
+
+ set_callbacks(Open, Close)
+vlc_module_end()
--
2.13.5 (Apple Git-94)
More information about the vlc-devel
mailing list