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 */