libextractor

GNU libextractor
Log | Files | Refs | Submodules | README | LICENSE

vlc_extractor.c (9096B)


      1 /*
      2      This file is part of libextractor.
      3      Copyright (C) 2021 Christian Grothoff
      4 
      5      libextractor is free software; you can redistribute it and/or modify
      6      it under the terms of the GNU General Public License as published
      7      by the Free Software Foundation; either version 3, or (at your
      8      option) any later version.
      9 
     10      libextractor is distributed in the hope that it will be useful, but
     11      WITHOUT ANY WARRANTY; without even the implied warranty of
     12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13      General Public License for more details.
     14 
     15      You should have received a copy of the GNU General Public License
     16      along with libextractor; see the file COPYING.  If not, write to the
     17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18      Boston, MA 02110-1301, USA.
     19 
     20 THIS PLUGIN IS NOT WORKING, see #2075!
     21 
     22 */
     23 /**
     24  * @file plugins/vlc_extractor.c
     25  * @brief plugin to extract metadata using libvlc
     26  * @author Christian Grothoff
     27  */
     28 #include "platform.h"
     29 #include "extractor.h"
     30 #include <vlc/vlc.h>
     31 #include <signal.h>
     32 
     33 /**
     34  * Function to help VLC open a custom bitstream input media.
     35  *
     36  * The same media item can be opened multiple times. Each time, this callback
     37  * is invoked. It should allocate and initialize any instance-specific
     38  * resources, then store them in *datap. The instance resources can be freed
     39  * in the @ref libvlc_media_close_cb callback.
     40  *
     41  * @param opaque our `struct EXTRACTOR_ExtractContext`
     42  * @param[out] datap storage space for a private data pointer
     43  * @param[out] sizep byte length of the bitstream or UINT64_MAX if unknown
     44  *
     45  * @note For convenience, *datap is initially NULL and *sizep is initially 0.
     46  *
     47  * @return 0 on success, non-zero on error. In case of failure, the other
     48  * callbacks will not be invoked and any value stored in *datap and *sizep is
     49  * discarded.
     50  */
     51 static int
     52 open_cb (void *opaque,
     53          void **datap,
     54          uint64_t *sizep)
     55 {
     56   struct EXTRACTOR_ExtractContext *ec = opaque;
     57 
     58   *datap = ec;
     59   *sizep = ec->get_size (ec->cls);
     60   if (UINT64_MAX == *sizep)
     61   {
     62     fprintf (stderr,
     63              "Open failed!\n");
     64     return 1;
     65   }
     66   fprintf (stderr,
     67            "Open returns %llu file size!\n",
     68            (unsigned long long) *sizep);
     69   return 0;
     70 }
     71 
     72 
     73 /**
     74  * Function to help VLC read data from a custom bitstream input media.
     75  *
     76  * @param opaque our `struct EXTRACTOR_ExtractContext`
     77  * @param buf start address of the buffer to read data into
     78  * @param len bytes length of the buffer
     79  * @return strictly positive number of bytes read, 0 on end-of-stream,
     80  *         or -1 on non-recoverable error
     81  *
     82  * @note If no data is immediately available, then the callback should sleep.
     83  * @warning The application is responsible for avoiding deadlock situations.
     84  * In particular, the callback should return an error if playback is stopped;
     85  * if it does not return, then libvlc_media_player_stop() will never return.
     86  */
     87 static ssize_t
     88 read_cb (void *opaque,
     89          unsigned char *buf,
     90          size_t len)
     91 {
     92   struct EXTRACTOR_ExtractContext *ec = opaque;
     93   void *data;
     94   ssize_t ret;
     95 
     96   ret = ec->read (ec->cls,
     97                   &data,
     98                   len);
     99   if (-1 == ret)
    100   {
    101     fprintf (stderr,
    102              "Read failed!\n");
    103     return -1;
    104   }
    105   memcpy (buf,
    106           data,
    107           ret);
    108   fprintf (stderr,
    109            "Read %u bytes!\n",
    110            (unsigned int) ret);
    111   return ret;
    112 }
    113 
    114 
    115 /**
    116  * Allow VLC to seek a custom bitstream input media.
    117  *
    118  * @param opaque our `struct EXTRACTOR_ExtractContext`
    119  * @param offset absolute byte offset to seek to
    120  * @return 0 on success, -1 on error.
    121  */
    122 static int
    123 seek_cb (void *opaque,
    124          uint64_t offset)
    125 {
    126   struct EXTRACTOR_ExtractContext *ec = opaque;
    127 
    128   fprintf (stderr,
    129            "Seek to %llu!\n",
    130            (unsigned long long) offset);
    131   if (offset > INT64_MAX)
    132   {
    133     fprintf (stderr,
    134              "Excessive seek, impossible with LE!\n");
    135     return -1;
    136   }
    137   if (-1 ==
    138       ec->seek (ec->cls,
    139                 offset,
    140                 SEEK_SET))
    141   {
    142     fprintf (stderr,
    143              "Seek failed!\n");
    144     return -1;
    145   }
    146   return 0;
    147 }
    148 
    149 
    150 /**
    151  * Callback prototype to close a custom bitstream input media.
    152  *
    153  * @param opaque our `struct EXTRACTOR_ExtractContext`
    154  */
    155 static void
    156 close_cb (void *opaque)
    157 {
    158   /* intentionally empty */
    159   fprintf (stderr,
    160            "Close called\n");
    161 }
    162 
    163 
    164 static void
    165 extract (struct EXTRACTOR_ExtractContext *ec,
    166          libvlc_media_t *media)
    167 {
    168   struct
    169   {
    170     enum libvlc_meta_t vt;
    171     enum EXTRACTOR_MetaType mt;
    172   } map[] = {
    173     { libvlc_meta_Title,
    174       EXTRACTOR_METATYPE_TITLE },
    175     { libvlc_meta_Artist,
    176       EXTRACTOR_METATYPE_ARTIST },
    177     { libvlc_meta_Genre,
    178       EXTRACTOR_METATYPE_GENRE },
    179     { libvlc_meta_Copyright,
    180       EXTRACTOR_METATYPE_COPYRIGHT },
    181     { libvlc_meta_Album,
    182       EXTRACTOR_METATYPE_ALBUM },
    183     { libvlc_meta_TrackNumber,
    184       EXTRACTOR_METATYPE_TRACK_NUMBER },
    185     { libvlc_meta_Description,
    186       EXTRACTOR_METATYPE_DESCRIPTION },
    187     { libvlc_meta_Rating,
    188       EXTRACTOR_METATYPE_RATING },
    189     { libvlc_meta_Date,
    190       EXTRACTOR_METATYPE_CREATION_TIME },
    191     { libvlc_meta_Setting,
    192       EXTRACTOR_METATYPE_UNKNOWN },
    193     { libvlc_meta_URL,
    194       EXTRACTOR_METATYPE_URL },
    195     { libvlc_meta_Language,
    196       EXTRACTOR_METATYPE_LANGUAGE },
    197     { libvlc_meta_NowPlaying,
    198       EXTRACTOR_METATYPE_UNKNOWN },
    199     { libvlc_meta_Publisher,
    200       EXTRACTOR_METATYPE_PUBLISHER },
    201     { libvlc_meta_EncodedBy,
    202       EXTRACTOR_METATYPE_ENCODED_BY },
    203     { libvlc_meta_ArtworkURL,
    204       EXTRACTOR_METATYPE_URL },
    205     { libvlc_meta_TrackID,
    206       EXTRACTOR_METATYPE_TRACK_NUMBER },
    207     { libvlc_meta_TrackTotal,
    208       EXTRACTOR_METATYPE_UNKNOWN },
    209     { libvlc_meta_Director,
    210       EXTRACTOR_METATYPE_MOVIE_DIRECTOR },
    211     { libvlc_meta_Season,
    212       EXTRACTOR_METATYPE_SHOW_SEASON_NUMBER },
    213     { libvlc_meta_Episode,
    214       EXTRACTOR_METATYPE_SHOW_EPISODE_NUMBER },
    215     { libvlc_meta_ShowName,
    216       EXTRACTOR_METATYPE_SHOW_NAME },
    217     { libvlc_meta_Actors,
    218       EXTRACTOR_METATYPE_PERFORMER },
    219     { libvlc_meta_AlbumArtist,
    220       EXTRACTOR_METATYPE_ARTIST },
    221     { libvlc_meta_DiscNumber,
    222       EXTRACTOR_METATYPE_DISC_NUMBER },
    223     { libvlc_meta_DiscTotal,
    224       EXTRACTOR_METATYPE_UNKNOWN },
    225     { 0, 0 }
    226   };
    227 
    228   for (unsigned int i = 0;
    229        EXTRACTOR_METATYPE_RESERVED != map[i].mt;
    230        i++)
    231   {
    232     char *meta;
    233 
    234     fprintf (stderr,
    235              ".");
    236     meta = libvlc_media_get_meta (media,
    237                                   map[i].vt);
    238     if (NULL == meta)
    239       continue;
    240     ec->proc (ec->cls,
    241               "vlc",
    242               map[i].mt,
    243               EXTRACTOR_METAFORMAT_UTF8, /* ??? */
    244               "text/plain",
    245               meta,
    246               strlen (meta) + 1);
    247     free (meta);
    248   }
    249 }
    250 
    251 
    252 static void
    253 media_ready (const struct libvlc_event_t *p_event,
    254              void *p_data)
    255 {
    256   fprintf (stderr,
    257            "media status: %d, %d\n",
    258            p_event->type == libvlc_MediaParsedChanged,
    259            p_event->u.media_parsed_changed.new_status);
    260   if (p_event->u.media_parsed_changed.new_status ==
    261       libvlc_media_parsed_status_done)
    262   {
    263     fprintf (stderr,
    264              "media ready\n");
    265   }
    266 }
    267 
    268 
    269 static void
    270 my_logger (void *data,
    271            int level,
    272            const libvlc_log_t *ctx,
    273            const char *fmt,
    274            va_list args)
    275 {
    276 #if 0
    277   vfprintf (stderr,
    278             fmt,
    279             args);
    280   fprintf (stderr, "\n");
    281 #endif
    282 }
    283 
    284 
    285 /**
    286  * Extract information using libvlc
    287  *
    288  * @param ec extraction context
    289  */
    290 void
    291 EXTRACTOR_vlc_extract_method (struct EXTRACTOR_ExtractContext *ec)
    292 {
    293   libvlc_instance_t *vlc;
    294   libvlc_media_t *media;
    295   libvlc_event_manager_t *em;
    296 
    297   {
    298     sigset_t set;
    299 
    300     signal (SIGCHLD, SIG_DFL);
    301     sigemptyset (&set);
    302     sigaddset (&set, SIGPIPE);
    303     pthread_sigmask (SIG_BLOCK, &set, NULL);
    304   }
    305 
    306   {
    307     const char *argv[] = {
    308       "-v",
    309       "3",
    310       NULL
    311     };
    312     vlc = libvlc_new (2, argv);
    313   }
    314   if (NULL == vlc)
    315     return;
    316   libvlc_log_set (vlc,
    317                   &my_logger,
    318                   NULL);
    319   media = libvlc_media_new_callbacks (vlc,
    320                                       &open_cb,
    321                                       &read_cb,
    322                                       &seek_cb,
    323                                       &close_cb,
    324                                       ec);
    325   if (NULL == media)
    326   {
    327     libvlc_release (vlc);
    328     return;
    329   }
    330 
    331   em = libvlc_media_event_manager (media);
    332   libvlc_event_attach (em,
    333                        libvlc_MediaParsedChanged,
    334                        &media_ready,
    335                        ec);
    336   {
    337     int status;
    338 
    339     status = libvlc_media_parse_with_options (media,
    340                                               libvlc_media_fetch_local
    341                                               | libvlc_media_parse_network
    342                                               | libvlc_media_fetch_network,
    343                                               30000); /* 30s timeout */
    344   }
    345   extract (ec,
    346            media);
    347   libvlc_media_release (media);
    348   libvlc_release (vlc);
    349 }
    350 
    351 
    352 /* end of vlc_extractor.c */