aboutsummaryrefslogtreecommitdiff
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 @@
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
20NOTE: This plugin is not yet working. Somehow libvlc never calls any of the IO callbacks.
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 */
51static int
52open_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 */
87static ssize_t
88read_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 */
122static int
123seek_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 */
155static void
156close_cb (void *opaque)
157{
158 /* intentionally empty */
159 fprintf (stderr,
160 "Close called\n");
161}
162
163
164static void
165extract (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
252static void
253media_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/**
270 * Extract information using libvlc
271 *
272 * @param ec extraction context
273 */
274void
275EXTRACTOR_vlc_extract_method (struct EXTRACTOR_ExtractContext *ec)
276{
277 libvlc_instance_t *vlc;
278 libvlc_media_t *media;
279 libvlc_event_manager_t *em;
280
281 {
282 sigset_t set;
283
284 signal (SIGCHLD, SIG_DFL);
285 sigemptyset (&set);
286 sigaddset (&set, SIGPIPE);
287 pthread_sigmask (SIG_BLOCK, &set, NULL);
288 }
289
290 vlc = libvlc_new (0, NULL);
291 if (NULL == vlc)
292 return;
293 media = libvlc_media_new_callbacks (vlc,
294 &open_cb,
295 &read_cb,
296 &seek_cb,
297 &close_cb,
298 ec);
299 if (NULL == media)
300 {
301 libvlc_release (vlc);
302 return;
303 }
304
305 em = libvlc_media_event_manager (media);
306 libvlc_event_attach (em,
307 libvlc_MediaParsedChanged,
308 &media_ready,
309 ec);
310 fprintf (stderr,
311 "Triggering parser\n");
312 {
313 int status;
314
315 status = libvlc_media_parse_with_options (media,
316 libvlc_media_fetch_local
317 | libvlc_media_parse_network
318 | libvlc_media_fetch_network,
319 30000); /* 30s timeout */
320 fprintf (stderr,
321 "Status: %d\n",
322 status);
323 }
324 fprintf (stderr,
325 "Sleeping\n");
326 sleep (1);
327 extract (ec,
328 media);
329 libvlc_media_release (media);
330 libvlc_release (vlc);
331}
332
333
334/* end of vlc_extractor.c */