diff options
Diffstat (limited to 'src/plugins/vlc_extractor.c')
-rw-r--r-- | src/plugins/vlc_extractor.c | 334 |
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 */ |