summaryrefslogtreecommitdiff
path: root/src/plugins/vlc_extractor.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/vlc_extractor.c')
-rw-r--r--src/plugins/vlc_extractor.c334
1 files changed, 334 insertions, 0 deletions
diff --git a/src/plugins/vlc_extractor.c b/src/plugins/vlc_extractor.c
new file mode 100644
index 0000000..e90b3ea
--- /dev/null
+++ b/src/plugins/vlc_extractor.c
@@ -0,0 +1,334 @@
+/*
+ This file is part of libextractor.
+ Copyright (C) 2021 Christian Grothoff
+
+ libextractor is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ libextractor 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.
+
+ You should have received a copy of the GNU General Public License
+ along with libextractor; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+NOTE: This plugin is not yet working. Somehow libvlc never calls any of the IO callbacks.
+
+*/
+/**
+ * @file plugins/vlc_extractor.c
+ * @brief plugin to extract metadata using libvlc
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "extractor.h"
+#include <vlc/vlc.h>
+#include <signal.h>
+
+/**
+ * Function to help VLC open a custom bitstream input media.
+ *
+ * The same media item can be opened multiple times. Each time, this callback
+ * is invoked. It should allocate and initialize any instance-specific
+ * resources, then store them in *datap. The instance resources can be freed
+ * in the @ref libvlc_media_close_cb callback.
+ *
+ * @param opaque our `struct EXTRACTOR_ExtractContext`
+ * @param[out] datap storage space for a private data pointer
+ * @param[out] sizep byte length of the bitstream or UINT64_MAX if unknown
+ *
+ * @note For convenience, *datap is initially NULL and *sizep is initially 0.
+ *
+ * @return 0 on success, non-zero on error. In case of failure, the other
+ * callbacks will not be invoked and any value stored in *datap and *sizep is
+ * discarded.
+ */
+static int
+open_cb (void *opaque,
+ void **datap,
+ uint64_t *sizep)
+{
+ struct EXTRACTOR_ExtractContext *ec = opaque;
+
+ *datap = ec;
+ *sizep = ec->get_size (ec->cls);
+ if (UINT64_MAX == *sizep)
+ {
+ fprintf (stderr,
+ "Open failed!\n");
+ return 1;
+ }
+ fprintf (stderr,
+ "Open returns %llu file size!\n",
+ (unsigned long long) *sizep);
+ return 0;
+}
+
+
+/**
+ * Function to help VLC read data from a custom bitstream input media.
+ *
+ * @param opaque our `struct EXTRACTOR_ExtractContext`
+ * @param buf start address of the buffer to read data into
+ * @param len bytes length of the buffer
+ * @return strictly positive number of bytes read, 0 on end-of-stream,
+ * or -1 on non-recoverable error
+ *
+ * @note If no data is immediately available, then the callback should sleep.
+ * @warning The application is responsible for avoiding deadlock situations.
+ * In particular, the callback should return an error if playback is stopped;
+ * if it does not return, then libvlc_media_player_stop() will never return.
+ */
+static ssize_t
+read_cb (void *opaque,
+ unsigned char *buf,
+ size_t len)
+{
+ struct EXTRACTOR_ExtractContext *ec = opaque;
+ void *data;
+ ssize_t ret;
+
+ ret = ec->read (ec->cls,
+ &data,
+ len);
+ if (-1 == ret)
+ {
+ fprintf (stderr,
+ "Read failed!\n");
+ return -1;
+ }
+ memcpy (buf,
+ data,
+ ret);
+ fprintf (stderr,
+ "Read %u bytes!\n",
+ (unsigned int) ret);
+ return ret;
+}
+
+
+/**
+ * Allow VLC to seek a custom bitstream input media.
+ *
+ * @param opaque our `struct EXTRACTOR_ExtractContext`
+ * @param offset absolute byte offset to seek to
+ * @return 0 on success, -1 on error.
+ */
+static int
+seek_cb (void *opaque,
+ uint64_t offset)
+{
+ struct EXTRACTOR_ExtractContext *ec = opaque;
+
+ fprintf (stderr,
+ "Seek to %llu!\n",
+ (unsigned long long) offset);
+ if (offset > INT64_MAX)
+ {
+ fprintf (stderr,
+ "Excessive seek, impossible with LE!\n");
+ return -1;
+ }
+ if (-1 ==
+ ec->seek (ec->cls,
+ offset,
+ SEEK_SET))
+ {
+ fprintf (stderr,
+ "Seek failed!\n");
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * Callback prototype to close a custom bitstream input media.
+ *
+ * @param opaque our `struct EXTRACTOR_ExtractContext`
+ */
+static void
+close_cb (void *opaque)
+{
+ /* intentionally empty */
+ fprintf (stderr,
+ "Close called\n");
+}
+
+
+static void
+extract (struct EXTRACTOR_ExtractContext *ec,
+ libvlc_media_t *media)
+{
+ struct
+ {
+ enum libvlc_meta_t vt;
+ enum EXTRACTOR_MetaType mt;
+ } map[] = {
+ { libvlc_meta_Title,
+ EXTRACTOR_METATYPE_TITLE },
+ { libvlc_meta_Artist,
+ EXTRACTOR_METATYPE_ARTIST },
+ { libvlc_meta_Genre,
+ EXTRACTOR_METATYPE_GENRE },
+ { libvlc_meta_Copyright,
+ EXTRACTOR_METATYPE_COPYRIGHT },
+ { libvlc_meta_Album,
+ EXTRACTOR_METATYPE_ALBUM },
+ { libvlc_meta_TrackNumber,
+ EXTRACTOR_METATYPE_TRACK_NUMBER },
+ { libvlc_meta_Description,
+ EXTRACTOR_METATYPE_DESCRIPTION },
+ { libvlc_meta_Rating,
+ EXTRACTOR_METATYPE_RATING },
+ { libvlc_meta_Date,
+ EXTRACTOR_METATYPE_CREATION_TIME },
+ { libvlc_meta_Setting,
+ EXTRACTOR_METATYPE_UNKNOWN },
+ { libvlc_meta_URL,
+ EXTRACTOR_METATYPE_URL },
+ { libvlc_meta_Language,
+ EXTRACTOR_METATYPE_LANGUAGE },
+ { libvlc_meta_NowPlaying,
+ EXTRACTOR_METATYPE_UNKNOWN },
+ { libvlc_meta_Publisher,
+ EXTRACTOR_METATYPE_PUBLISHER },
+ { libvlc_meta_EncodedBy,
+ EXTRACTOR_METATYPE_ENCODED_BY },
+ { libvlc_meta_ArtworkURL,
+ EXTRACTOR_METATYPE_URL },
+ { libvlc_meta_TrackID,
+ EXTRACTOR_METATYPE_TRACK_NUMBER },
+ { libvlc_meta_TrackTotal,
+ EXTRACTOR_METATYPE_UNKNOWN },
+ { libvlc_meta_Director,
+ EXTRACTOR_METATYPE_MOVIE_DIRECTOR },
+ { libvlc_meta_Season,
+ EXTRACTOR_METATYPE_SHOW_SEASON_NUMBER },
+ { libvlc_meta_Episode,
+ EXTRACTOR_METATYPE_SHOW_EPISODE_NUMBER },
+ { libvlc_meta_ShowName,
+ EXTRACTOR_METATYPE_SHOW_NAME },
+ { libvlc_meta_Actors,
+ EXTRACTOR_METATYPE_PERFORMER },
+ { libvlc_meta_AlbumArtist,
+ EXTRACTOR_METATYPE_ARTIST },
+ { libvlc_meta_DiscNumber,
+ EXTRACTOR_METATYPE_DISC_NUMBER },
+ { libvlc_meta_DiscTotal,
+ EXTRACTOR_METATYPE_UNKNOWN },
+ { 0, 0 }
+ };
+
+ for (unsigned int i = 0;
+ EXTRACTOR_METATYPE_RESERVED != map[i].mt;
+ i++)
+ {
+ char *meta;
+
+ fprintf (stderr,
+ ".");
+ meta = libvlc_media_get_meta (media,
+ map[i].vt);
+ if (NULL == meta)
+ continue;
+ ec->proc (ec->cls,
+ "vlc",
+ map[i].mt,
+ EXTRACTOR_METAFORMAT_UTF8, /* ??? */
+ "text/plain",
+ meta,
+ strlen (meta) + 1);
+ free (meta);
+ }
+}
+
+
+static void
+media_ready (const struct libvlc_event_t *p_event,
+ void *p_data)
+{
+ fprintf (stderr,
+ "media status: %d, %d\n",
+ p_event->type == libvlc_MediaParsedChanged,
+ p_event->u.media_parsed_changed.new_status);
+ if (p_event->u.media_parsed_changed.new_status ==
+ libvlc_media_parsed_status_done)
+ {
+ fprintf (stderr,
+ "media ready\n");
+ }
+}
+
+
+/**
+ * Extract information using libvlc
+ *
+ * @param ec extraction context
+ */
+void
+EXTRACTOR_vlc_extract_method (struct EXTRACTOR_ExtractContext *ec)
+{
+ libvlc_instance_t *vlc;
+ libvlc_media_t *media;
+ libvlc_event_manager_t *em;
+
+ {
+ sigset_t set;
+
+ signal (SIGCHLD, SIG_DFL);
+ sigemptyset (&set);
+ sigaddset (&set, SIGPIPE);
+ pthread_sigmask (SIG_BLOCK, &set, NULL);
+ }
+
+ vlc = libvlc_new (0, NULL);
+ if (NULL == vlc)
+ return;
+ media = libvlc_media_new_callbacks (vlc,
+ &open_cb,
+ &read_cb,
+ &seek_cb,
+ &close_cb,
+ ec);
+ if (NULL == media)
+ {
+ libvlc_release (vlc);
+ return;
+ }
+
+ em = libvlc_media_event_manager (media);
+ libvlc_event_attach (em,
+ libvlc_MediaParsedChanged,
+ &media_ready,
+ ec);
+ fprintf (stderr,
+ "Triggering parser\n");
+ {
+ int status;
+
+ status = libvlc_media_parse_with_options (media,
+ libvlc_media_fetch_local
+ | libvlc_media_parse_network
+ | libvlc_media_fetch_network,
+ 30000); /* 30s timeout */
+ fprintf (stderr,
+ "Status: %d\n",
+ status);
+ }
+ fprintf (stderr,
+ "Sleeping\n");
+ sleep (1);
+ extract (ec,
+ media);
+ libvlc_media_release (media);
+ libvlc_release (vlc);
+}
+
+
+/* end of vlc_extractor.c */