diff options
Diffstat (limited to 'src/plugins/flac_extractor.c')
-rw-r--r-- | src/plugins/flac_extractor.c | 498 |
1 files changed, 298 insertions, 200 deletions
diff --git a/src/plugins/flac_extractor.c b/src/plugins/flac_extractor.c index 0b99a33..8b4ac9a 100644 --- a/src/plugins/flac_extractor.c +++ b/src/plugins/flac_extractor.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of libextractor. | 2 | This file is part of libextractor. |
3 | (C) 2007, 2009 Vidyut Samanta and Christian Grothoff | 3 | (C) 2007, 2009, 2012 Vidyut Samanta and Christian Grothoff |
4 | 4 | ||
5 | libextractor is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
7 | by the Free Software Foundation; either version 2, or (at your | 7 | by the Free Software Foundation; either version 3, or (at your |
8 | option) any later version. | 8 | option) any later version. |
9 | 9 | ||
10 | libextractor is distributed in the hope that it will be useful, but | 10 | libextractor is distributed in the hope that it will be useful, but |
@@ -18,99 +18,185 @@ | |||
18 | Boston, MA 02111-1307, USA. | 18 | Boston, MA 02111-1307, USA. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | /** | ||
22 | * @file plugins/flac_extractor.c | ||
23 | * @brief plugin to support FLAC files | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
21 | #include "platform.h" | 26 | #include "platform.h" |
22 | #include "extractor.h" | 27 | #include "extractor.h" |
28 | #include <FLAC/all.h> | ||
23 | 29 | ||
30 | |||
31 | /** | ||
32 | * Bytes each FLAC file must begin with (not used, but we might | ||
33 | * choose to add this back in the future to improve performance | ||
34 | * for non-ogg files). | ||
35 | */ | ||
24 | #define FLAC_HEADER "fLaC" | 36 | #define FLAC_HEADER "fLaC" |
25 | 37 | ||
26 | #if HAVE_FLAC_ALL_H | ||
27 | #include <FLAC/all.h> | ||
28 | #else | ||
29 | #error You must install the libflac header files! | ||
30 | #endif | ||
31 | |||
32 | |||
33 | struct Context { | ||
34 | const char * data; | ||
35 | size_t size; | ||
36 | size_t pos; | ||
37 | EXTRACTOR_MetaDataProcessor proc; | ||
38 | void *proc_cls; | ||
39 | int ret; | ||
40 | }; | ||
41 | 38 | ||
39 | /** | ||
40 | * Custom read function for flac. | ||
41 | * | ||
42 | * @param decoder unused | ||
43 | * @param buffer where to write the data | ||
44 | * @param bytes how many bytes to read, set to how many bytes were read | ||
45 | * @param client_data our 'struct EXTRACTOR_ExtractContxt*' | ||
46 | * @return status code (error, end-of-file or success) | ||
47 | */ | ||
42 | static FLAC__StreamDecoderReadStatus | 48 | static FLAC__StreamDecoderReadStatus |
43 | flac_read (const FLAC__StreamDecoder *decoder, | 49 | flac_read (const FLAC__StreamDecoder *decoder, |
44 | FLAC__byte buffer[], | 50 | FLAC__byte buffer[], |
45 | size_t *bytes, | 51 | size_t *bytes, |
46 | void *client_data) | 52 | void *client_data) |
47 | { | 53 | { |
48 | struct Context * ctx = client_data; | 54 | struct EXTRACTOR_ExtractContext *ec = client_data; |
49 | 55 | void *data; | |
50 | if (*bytes <= 0) | 56 | ssize_t ret; |
57 | |||
58 | data = NULL; | ||
59 | ret = ec->read (ec->cls, | ||
60 | &data, | ||
61 | *bytes); | ||
62 | if (-1 == ret) | ||
51 | return FLAC__STREAM_DECODER_READ_STATUS_ABORT; | 63 | return FLAC__STREAM_DECODER_READ_STATUS_ABORT; |
52 | if (*bytes > ctx->size - ctx->pos) | 64 | if (0 == ret) |
53 | *bytes = ctx->size - ctx->pos; | 65 | { |
54 | if (*bytes == 0) | 66 | errno = 0; |
55 | return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; | 67 | return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; |
56 | memcpy(buffer, | 68 | } |
57 | &ctx->data[ctx->pos], | 69 | memcpy (buffer, data, ret); |
58 | *bytes); | 70 | *bytes = ret; |
59 | ctx->pos += *bytes; | 71 | errno = 0; |
60 | return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; | 72 | return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; |
61 | } | 73 | } |
62 | 74 | ||
75 | |||
76 | /** | ||
77 | * Seek to a particular position in the file. | ||
78 | * | ||
79 | * @param decoder unused | ||
80 | * @param absolute_byte_offset where to seek | ||
81 | * @param client_data the 'struct EXTRACTOR_ExtractContext' | ||
82 | * @return status code (error or success) | ||
83 | */ | ||
63 | static FLAC__StreamDecoderSeekStatus | 84 | static FLAC__StreamDecoderSeekStatus |
64 | flac_seek(const FLAC__StreamDecoder *decoder, | 85 | flac_seek (const FLAC__StreamDecoder *decoder, |
65 | FLAC__uint64 absolute_byte_offset, void *client_data) | 86 | FLAC__uint64 absolute_byte_offset, |
87 | void *client_data) | ||
66 | { | 88 | { |
67 | struct Context * ctx = client_data; | 89 | struct EXTRACTOR_ExtractContext *ec = client_data; |
68 | 90 | ||
69 | if (absolute_byte_offset > ctx->size) | 91 | if (absolute_byte_offset != |
92 | ec->seek (ec->cls, (int64_t) absolute_byte_offset, SEEK_SET)) | ||
70 | return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; | 93 | return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; |
71 | ctx->pos = (size_t) absolute_byte_offset; | ||
72 | return FLAC__STREAM_DECODER_SEEK_STATUS_OK; | 94 | return FLAC__STREAM_DECODER_SEEK_STATUS_OK; |
73 | } | 95 | } |
74 | 96 | ||
97 | |||
98 | /** | ||
99 | * Tell FLAC about our current position in the file. | ||
100 | * | ||
101 | * @param decoder unused | ||
102 | * @param absolute_byte_offset location to store the current offset | ||
103 | * @param client_data the 'struct EXTRACTOR_ExtractContext' | ||
104 | * @return status code (error or success) | ||
105 | */ | ||
75 | static FLAC__StreamDecoderTellStatus | 106 | static FLAC__StreamDecoderTellStatus |
76 | flac_tell(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) | 107 | flac_tell (const FLAC__StreamDecoder *decoder, |
108 | FLAC__uint64 *absolute_byte_offset, | ||
109 | void *client_data) | ||
77 | { | 110 | { |
78 | struct Context * ctx = client_data; | 111 | struct EXTRACTOR_ExtractContext *ec = client_data; |
79 | 112 | ||
80 | *absolute_byte_offset = ctx->pos; | 113 | *absolute_byte_offset = ec->seek (ec->cls, |
114 | 0, | ||
115 | SEEK_CUR); | ||
81 | return FLAC__STREAM_DECODER_TELL_STATUS_OK; | 116 | return FLAC__STREAM_DECODER_TELL_STATUS_OK; |
82 | } | 117 | } |
83 | 118 | ||
119 | |||
120 | /** | ||
121 | * Tell FLAC the size of the file. | ||
122 | * | ||
123 | * @param decoder unused | ||
124 | * @param stream_length where to store the file size | ||
125 | * @param client_data the 'struct EXTRACTOR_ExtractContext' | ||
126 | * @return true at EOF, false if not | ||
127 | */ | ||
84 | static FLAC__StreamDecoderLengthStatus | 128 | static FLAC__StreamDecoderLengthStatus |
85 | flac_length(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) | 129 | flac_length (const FLAC__StreamDecoder *decoder, |
130 | FLAC__uint64 *stream_length, | ||
131 | void *client_data) | ||
86 | { | 132 | { |
87 | struct Context * ctx = client_data; | 133 | struct EXTRACTOR_ExtractContext *ec = client_data; |
88 | 134 | ||
89 | ctx->pos = *stream_length; | 135 | *stream_length = ec->get_size (ec->cls); |
90 | return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; | 136 | return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; |
91 | } | 137 | } |
92 | 138 | ||
139 | |||
140 | /** | ||
141 | * Tell FLAC if we are at the end of the file. | ||
142 | * | ||
143 | * @param decoder unused | ||
144 | * @param absolute_byte_offset location to store the current offset | ||
145 | * @param client_data the 'struct EXTRACTOR_ExtractContext' | ||
146 | * @return true at EOF, false if not | ||
147 | */ | ||
93 | static FLAC__bool | 148 | static FLAC__bool |
94 | flac_eof(const FLAC__StreamDecoder *decoder, void *client_data) | 149 | flac_eof (const FLAC__StreamDecoder *decoder, |
150 | void *client_data) | ||
95 | { | 151 | { |
96 | struct Context * ctx = client_data; | 152 | struct EXTRACTOR_ExtractContext *ec = client_data; |
97 | 153 | ||
98 | return (ctx->pos == ctx->size) ? true : false; | 154 | return (ec->get_size (ec->cls) == |
155 | ec->seek (ec->cls, 0, SEEK_CUR)) ? true : false; | ||
99 | } | 156 | } |
100 | 157 | ||
158 | |||
159 | /** | ||
160 | * FLAC wants to write. Always succeeds but does nothing. | ||
161 | * | ||
162 | * @param decoder unused | ||
163 | * @param frame unused | ||
164 | * @param buffer unused | ||
165 | * @param client_data the 'struct EXTRACTOR_ExtractContext' | ||
166 | * @return always claims success | ||
167 | */ | ||
101 | static FLAC__StreamDecoderWriteStatus | 168 | static FLAC__StreamDecoderWriteStatus |
102 | flac_write(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data) | 169 | flac_write (const FLAC__StreamDecoder *decoder, |
170 | const FLAC__Frame *frame, | ||
171 | const FLAC__int32 *const buffer[], | ||
172 | void *client_data) | ||
103 | { | 173 | { |
104 | return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; | 174 | return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; |
105 | } | 175 | } |
106 | 176 | ||
107 | typedef struct | 177 | |
178 | /** | ||
179 | * A mapping from FLAC meta data strings to extractor types. | ||
180 | */ | ||
181 | struct Matches | ||
108 | { | 182 | { |
183 | /** | ||
184 | * FLAC Meta data description text. | ||
185 | */ | ||
109 | const char *text; | 186 | const char *text; |
187 | |||
188 | /** | ||
189 | * Corresponding LE type. | ||
190 | */ | ||
110 | enum EXTRACTOR_MetaType type; | 191 | enum EXTRACTOR_MetaType type; |
111 | } Matches; | 192 | }; |
112 | 193 | ||
113 | static Matches tmap[] = { | 194 | |
195 | /** | ||
196 | * Mapping of FLAC meta data description texts to LE types. | ||
197 | * NULL-terminated. | ||
198 | */ | ||
199 | static struct Matches tmap[] = { | ||
114 | {"TITLE", EXTRACTOR_METATYPE_TITLE}, | 200 | {"TITLE", EXTRACTOR_METATYPE_TITLE}, |
115 | {"VERSION", EXTRACTOR_METATYPE_SONG_VERSION}, | 201 | {"VERSION", EXTRACTOR_METATYPE_SONG_VERSION}, |
116 | {"ALBUM", EXTRACTOR_METATYPE_ALBUM}, | 202 | {"ALBUM", EXTRACTOR_METATYPE_ALBUM}, |
@@ -126,72 +212,97 @@ static Matches tmap[] = { | |||
126 | {"CONTACT", EXTRACTOR_METATYPE_CONTACT_INFORMATION}, | 212 | {"CONTACT", EXTRACTOR_METATYPE_CONTACT_INFORMATION}, |
127 | {"TRACKNUMBER", EXTRACTOR_METATYPE_TRACK_NUMBER}, | 213 | {"TRACKNUMBER", EXTRACTOR_METATYPE_TRACK_NUMBER}, |
128 | {"ISRC", EXTRACTOR_METATYPE_ISRC}, | 214 | {"ISRC", EXTRACTOR_METATYPE_ISRC}, |
129 | {NULL, 0}, | 215 | {NULL, 0} |
130 | }; | 216 | }; |
131 | 217 | ||
132 | 218 | ||
133 | static char * xstrndup(const char * s, size_t n){ | 219 | /** |
220 | * FIXME. | ||
221 | */ | ||
222 | #define ADD (t,s) do { if (ctx->ret == 0) ctx->ret = ctx->proc (ctx->proc_cls, "flac", t, EXTRACTOR_METAFORMAT_UTF8, "text/plain", s, strlen(s)+1); } while (0) | ||
223 | |||
224 | |||
225 | /** | ||
226 | * Create 0-terminated version of n-character string. | ||
227 | * | ||
228 | * @param s input string (non 0-terminated) | ||
229 | * @param n number of bytes in 's' | ||
230 | * @return NULL on error, otherwise 0-terminated version of 's' | ||
231 | */ | ||
232 | static char * | ||
233 | xstrndup (const char *s, | ||
234 | size_t n) | ||
235 | { | ||
134 | char * d; | 236 | char * d; |
135 | 237 | ||
136 | d= malloc(n+1); | 238 | if (NULL == (d = malloc(n+1))) |
137 | if (d == NULL) | ||
138 | return NULL; | 239 | return NULL; |
139 | memcpy(d,s,n); | 240 | memcpy (d, s, n); |
140 | d[n]='\0'; | 241 | d[n] = '\0'; |
141 | return d; | 242 | return d; |
142 | } | 243 | } |
143 | 244 | ||
144 | #define ADD(t,s) do { if (ctx->ret == 0) ctx->ret = ctx->proc (ctx->proc_cls, "flac", t, EXTRACTOR_METAFORMAT_UTF8, "text/plain", s, strlen(s)+1); } while (0) | ||
145 | |||
146 | 245 | ||
246 | /** | ||
247 | * FIXME. | ||
248 | */ | ||
147 | static void | 249 | static void |
148 | check(const char * type, | 250 | check (const char *type, |
149 | unsigned int type_length, | 251 | unsigned int type_length, |
150 | const char * value, | 252 | const char *value, |
151 | unsigned int value_length, | 253 | unsigned int value_length, |
152 | struct Context *ctx) | 254 | struct EXTRACTOR_ExtractContext *ec) |
153 | { | 255 | { |
154 | unsigned int i; | 256 | unsigned int i; |
155 | char *tmp; | 257 | char *tmp; |
156 | 258 | ||
157 | i = 0; | 259 | for (i=0; NULL != tmap[i].text; i++) |
158 | while (tmap[i].text != NULL) | ||
159 | { | 260 | { |
160 | if ( (type_length == strlen(tmap[i].text)) && | 261 | if ( (type_length != strlen (tmap[i].text)) || |
161 | (0 == strncasecmp(tmap[i].text, | 262 | (0 != strncasecmp (tmap[i].text, |
162 | type, | 263 | type, |
163 | type_length)) ) | 264 | type_length)) ) |
164 | { | 265 | continue; |
165 | tmp = xstrndup(value, | 266 | if (NULL == |
166 | value_length); | 267 | (tmp = xstrndup (value, |
167 | if (tmp != NULL) | 268 | value_length))) |
168 | { | 269 | continue; |
169 | ADD (tmap[i].type, tmp); | 270 | ADD (tmap[i].type, tmp); |
170 | free (tmp); | 271 | free (tmp); |
171 | } | ||
172 | break; | ||
173 | } | ||
174 | i++; | ||
175 | } | 272 | } |
176 | } | 273 | } |
177 | 274 | ||
178 | 275 | ||
276 | /** | ||
277 | * Function called whenever FLAC finds meta data. | ||
278 | * | ||
279 | * @param decoder unused | ||
280 | * @param metadata meta data that was found | ||
281 | * @param client_data the 'struct EXTRACTOR_ExtractContext' | ||
282 | */ | ||
179 | static void | 283 | static void |
180 | flac_metadata(const FLAC__StreamDecoder *decoder, | 284 | flac_metadata (const FLAC__StreamDecoder *decoder, |
181 | const FLAC__StreamMetadata *metadata, | 285 | const FLAC__StreamMetadata *metadata, |
182 | void *client_data) | 286 | void *client_data) |
183 | { | 287 | { |
184 | struct Context * ctx = client_data; | 288 | struct EXTRACTOR_ExtractContext *ec = client_data; |
289 | enum EXTRACTOR_MetaType type; | ||
290 | const FLAC__StreamMetadata_VorbisComment * vc; | ||
291 | unsigned int count; | ||
292 | const FLAC__StreamMetadata_VorbisComment_Entry * entry; | ||
293 | const char * eq; | ||
294 | unsigned int len; | ||
295 | unsigned int ilen; | ||
185 | 296 | ||
186 | switch (metadata->type) | 297 | switch (metadata->type) |
187 | { | 298 | { |
188 | case FLAC__METADATA_TYPE_STREAMINFO: | 299 | case FLAC__METADATA_TYPE_STREAMINFO: |
189 | { | 300 | { |
190 | char buf[512]; | 301 | char buf[512]; |
191 | snprintf(buf, 512, | 302 | snprintf (buf, sizeof (buf), |
192 | _("%u Hz, %u channels"), | 303 | _("%u Hz, %u channels"), |
193 | metadata->data.stream_info.sample_rate, | 304 | metadata->data.stream_info.sample_rate, |
194 | metadata->data.stream_info.channels); | 305 | metadata->data.stream_info.channels); |
195 | ADD (EXTRACTOR_METATYPE_RESOURCE_TYPE, buf); | 306 | ADD (EXTRACTOR_METATYPE_RESOURCE_TYPE, buf); |
196 | break; | 307 | break; |
197 | } | 308 | } |
@@ -203,13 +314,8 @@ flac_metadata(const FLAC__StreamDecoder *decoder, | |||
203 | break; | 314 | break; |
204 | case FLAC__METADATA_TYPE_VORBIS_COMMENT: | 315 | case FLAC__METADATA_TYPE_VORBIS_COMMENT: |
205 | { | 316 | { |
206 | const FLAC__StreamMetadata_VorbisComment * vc = &metadata->data.vorbis_comment; | 317 | vc = &metadata->data.vorbis_comment; |
207 | unsigned int count = vc->num_comments; | 318 | count = vc->num_comments; |
208 | const FLAC__StreamMetadata_VorbisComment_Entry * entry; | ||
209 | const char * eq; | ||
210 | unsigned int len; | ||
211 | unsigned int ilen; | ||
212 | |||
213 | while (count-- > 0) | 319 | while (count-- > 0) |
214 | { | 320 | { |
215 | entry = &vc->comments[count]; | 321 | entry = &vc->comments[count]; |
@@ -226,64 +332,62 @@ flac_metadata(const FLAC__StreamDecoder *decoder, | |||
226 | (ilen == len) ) | 332 | (ilen == len) ) |
227 | break; | 333 | break; |
228 | eq++; | 334 | eq++; |
229 | check((const char*) entry->entry, | 335 | check ((const char*) entry->entry, |
230 | ilen, | 336 | ilen, |
231 | eq, | 337 | eq, |
232 | len - ilen, | 338 | len - ilen, |
233 | ctx); | 339 | ctx); |
234 | } | 340 | } |
235 | break; | 341 | break; |
236 | } | 342 | } |
237 | case FLAC__METADATA_TYPE_PICTURE: | 343 | case FLAC__METADATA_TYPE_PICTURE: |
238 | { | 344 | { |
239 | if (ctx->ret == 0) | 345 | if (0 != ctx->ret) |
346 | break; | ||
347 | switch (metadata->data.picture.type) | ||
240 | { | 348 | { |
241 | enum EXTRACTOR_MetaType type; | 349 | case FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER: |
242 | switch (metadata->data.picture.type) | 350 | case FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD: |
243 | { | 351 | case FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON: |
244 | case FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER: | 352 | type = EXTRACTOR_METATYPE_THUMBNAIL; |
245 | case FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD: | 353 | break; |
246 | case FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON: | 354 | case FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER: |
247 | type = EXTRACTOR_METATYPE_THUMBNAIL; | 355 | case FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER: |
248 | break; | 356 | type = EXTRACTOR_METATYPE_COVER_PICTURE; |
249 | case FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER: | 357 | break; |
250 | case FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER: | 358 | case FLAC__STREAM_METADATA_PICTURE_TYPE_LEAD_ARTIST: |
251 | type = EXTRACTOR_METATYPE_COVER_PICTURE; | 359 | case FLAC__STREAM_METADATA_PICTURE_TYPE_ARTIST: |
252 | break; | 360 | case FLAC__STREAM_METADATA_PICTURE_TYPE_CONDUCTOR: |
253 | case FLAC__STREAM_METADATA_PICTURE_TYPE_LEAD_ARTIST: | 361 | case FLAC__STREAM_METADATA_PICTURE_TYPE_BAND: |
254 | case FLAC__STREAM_METADATA_PICTURE_TYPE_ARTIST: | 362 | case FLAC__STREAM_METADATA_PICTURE_TYPE_COMPOSER: |
255 | case FLAC__STREAM_METADATA_PICTURE_TYPE_CONDUCTOR: | 363 | case FLAC__STREAM_METADATA_PICTURE_TYPE_LYRICIST: |
256 | case FLAC__STREAM_METADATA_PICTURE_TYPE_BAND: | 364 | type = EXTRACTOR_METATYPE_CONTRIBUTOR_PICTURE; |
257 | case FLAC__STREAM_METADATA_PICTURE_TYPE_COMPOSER: | 365 | break; |
258 | case FLAC__STREAM_METADATA_PICTURE_TYPE_LYRICIST: | 366 | case FLAC__STREAM_METADATA_PICTURE_TYPE_RECORDING_LOCATION: |
259 | type = EXTRACTOR_METATYPE_CONTRIBUTOR_PICTURE; | 367 | case FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_RECORDING: |
260 | break; | 368 | case FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_PERFORMANCE: |
261 | case FLAC__STREAM_METADATA_PICTURE_TYPE_RECORDING_LOCATION: | 369 | case FLAC__STREAM_METADATA_PICTURE_TYPE_VIDEO_SCREEN_CAPTURE: |
262 | case FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_RECORDING: | 370 | type = EXTRACTOR_METATYPE_EVENT_PICTURE; |
263 | case FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_PERFORMANCE: | 371 | break; |
264 | case FLAC__STREAM_METADATA_PICTURE_TYPE_VIDEO_SCREEN_CAPTURE: | 372 | case FLAC__STREAM_METADATA_PICTURE_TYPE_BAND_LOGOTYPE: |
265 | type = EXTRACTOR_METATYPE_EVENT_PICTURE; | 373 | case FLAC__STREAM_METADATA_PICTURE_TYPE_PUBLISHER_LOGOTYPE: |
266 | break; | 374 | type = EXTRACTOR_METATYPE_LOGO; |
267 | case FLAC__STREAM_METADATA_PICTURE_TYPE_BAND_LOGOTYPE: | 375 | break; |
268 | case FLAC__STREAM_METADATA_PICTURE_TYPE_PUBLISHER_LOGOTYPE: | 376 | case FLAC__STREAM_METADATA_PICTURE_TYPE_LEAFLET_PAGE: |
269 | type = EXTRACTOR_METATYPE_LOGO; | 377 | case FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA: |
270 | break; | 378 | case FLAC__STREAM_METADATA_PICTURE_TYPE_FISH: |
271 | case FLAC__STREAM_METADATA_PICTURE_TYPE_LEAFLET_PAGE: | 379 | case FLAC__STREAM_METADATA_PICTURE_TYPE_ILLUSTRATION: |
272 | case FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA: | 380 | default: |
273 | case FLAC__STREAM_METADATA_PICTURE_TYPE_FISH: | 381 | type = EXTRACTOR_METATYPE_PICTURE; |
274 | case FLAC__STREAM_METADATA_PICTURE_TYPE_ILLUSTRATION: | 382 | break; |
275 | default: | ||
276 | type = EXTRACTOR_METATYPE_PICTURE; | ||
277 | break; | ||
278 | } | ||
279 | ctx->ret = ctx->proc (ctx->proc_cls, | ||
280 | "flac", | ||
281 | type, | ||
282 | EXTRACTOR_METAFORMAT_BINARY, | ||
283 | metadata->data.picture.mime_type, | ||
284 | (const char*) metadata->data.picture.data, | ||
285 | metadata->data.picture.data_length); | ||
286 | } | 383 | } |
384 | ec->proc (ec->cls, | ||
385 | "flac", | ||
386 | type, | ||
387 | EXTRACTOR_METAFORMAT_BINARY, | ||
388 | metadata->data.picture.mime_type, | ||
389 | (const char*) metadata->data.picture.data, | ||
390 | metadata->data.picture.data_length)) | ||
287 | break; | 391 | break; |
288 | } | 392 | } |
289 | case FLAC__METADATA_TYPE_PADDING: | 393 | case FLAC__METADATA_TYPE_PADDING: |
@@ -294,81 +398,73 @@ flac_metadata(const FLAC__StreamDecoder *decoder, | |||
294 | } | 398 | } |
295 | } | 399 | } |
296 | 400 | ||
401 | |||
402 | /** | ||
403 | * Function called whenever FLAC decoder has trouble. Does nothing. | ||
404 | * | ||
405 | * @param decoder the decoder handle | ||
406 | * @param status type of the error | ||
407 | * @param client_data our 'struct EXTRACTOR_ExtractContext' | ||
408 | */ | ||
297 | static void | 409 | static void |
298 | flac_error(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) | 410 | flac_error (const FLAC__StreamDecoder *decoder, |
411 | FLAC__StreamDecoderErrorStatus status, | ||
412 | void *client_data) | ||
299 | { | 413 | { |
300 | #if 0 | 414 | /* ignore errors */ |
301 | fprintf(stderr, | ||
302 | "Got error: %u\n", status); | ||
303 | #endif | ||
304 | } | 415 | } |
305 | 416 | ||
306 | /* mimetype = audio/flac */ | 417 | |
307 | int | 418 | /** |
308 | EXTRACTOR_flac_extract (const char *data, | 419 | * Main entry method for the 'audio/flac' extraction plugin. |
309 | size_t size, | 420 | * |
310 | EXTRACTOR_MetaDataProcessor proc, | 421 | * @param ec extraction context provided to the plugin |
311 | void *proc_cls, | 422 | */ |
312 | const char *options) | 423 | void |
424 | EXTRACTOR_flac_extract_method (struct EXTRACTOR_ExtractContext *ec) | ||
313 | { | 425 | { |
314 | FLAC__StreamDecoder * decoder; | 426 | FLAC__StreamDecoder * decoder; |
315 | struct Context le_cls; | 427 | |
316 | struct Context *ctx; | 428 | if (NULL == (decoder = FLAC__stream_decoder_new ())) |
317 | 429 | return; | |
318 | if (size < strlen(FLAC_HEADER) + sizeof (int)) | 430 | FLAC__stream_decoder_set_md5_checking (decoder, false); |
319 | return 0; | 431 | FLAC__stream_decoder_set_metadata_ignore_all (decoder); |
320 | if (0 != memcmp(FLAC_HEADER, | 432 | if (false == FLAC__stream_decoder_set_metadata_respond_all (decoder)) |
321 | data, | ||
322 | strlen(FLAC_HEADER))) | ||
323 | return 0; | ||
324 | decoder = FLAC__stream_decoder_new(); | ||
325 | if (NULL == decoder) | ||
326 | return 0; | ||
327 | FLAC__stream_decoder_set_md5_checking(decoder, false); | ||
328 | FLAC__stream_decoder_set_metadata_ignore_all(decoder); | ||
329 | if (false == FLAC__stream_decoder_set_metadata_respond_all(decoder)) | ||
330 | { | 433 | { |
331 | FLAC__stream_decoder_delete(decoder); | 434 | FLAC__stream_decoder_delete (decoder); |
332 | return 0; | 435 | return; |
333 | } | 436 | } |
334 | le_cls.ret = 0; | ||
335 | le_cls.size = size; | ||
336 | le_cls.data = data; | ||
337 | le_cls.proc = proc; | ||
338 | le_cls.proc_cls = proc_cls; | ||
339 | le_cls.pos = 0; | ||
340 | if (FLAC__STREAM_DECODER_INIT_STATUS_OK != | 437 | if (FLAC__STREAM_DECODER_INIT_STATUS_OK != |
341 | FLAC__stream_decoder_init_stream(decoder, | 438 | FLAC__stream_decoder_init_stream (decoder, |
342 | &flac_read, | 439 | &flac_read, |
343 | &flac_seek, | 440 | &flac_seek, |
344 | &flac_tell, | 441 | &flac_tell, |
345 | &flac_length, | 442 | &flac_length, |
346 | &flac_eof, | 443 | &flac_eof, |
347 | &flac_write, | 444 | &flac_write, |
348 | &flac_metadata, | 445 | &flac_metadata, |
349 | &flac_error, | 446 | &flac_error, |
350 | &le_cls)) | 447 | ec)) |
351 | { | 448 | { |
352 | FLAC__stream_decoder_delete(decoder); | 449 | FLAC__stream_decoder_delete (decoder); |
353 | return le_cls.ret; | 450 | return; |
354 | } | 451 | } |
355 | if (FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA) | 452 | if (FLAC__STREAM_DECODER_SEARCH_FOR_METADATA != FLAC__stream_decoder_get_state(decoder)) |
356 | { | 453 | { |
357 | FLAC__stream_decoder_delete(decoder); | 454 | FLAC__stream_decoder_delete (decoder); |
358 | return le_cls.ret; | 455 | return; |
359 | } | 456 | } |
360 | if (! FLAC__stream_decoder_process_until_end_of_metadata(decoder)) | 457 | if (! FLAC__stream_decoder_process_until_end_of_metadata(decoder)) |
361 | { | 458 | { |
362 | FLAC__stream_decoder_delete(decoder); | 459 | FLAC__stream_decoder_delete (decoder); |
363 | return le_cls.ret; | 460 | return; |
364 | } | 461 | } |
365 | switch (FLAC__stream_decoder_get_state(decoder)) | 462 | switch (FLAC__stream_decoder_get_state (decoder)) |
366 | { | 463 | { |
367 | case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: | 464 | case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: |
368 | case FLAC__STREAM_DECODER_READ_METADATA: | 465 | case FLAC__STREAM_DECODER_READ_METADATA: |
369 | case FLAC__STREAM_DECODER_END_OF_STREAM: | 466 | case FLAC__STREAM_DECODER_END_OF_STREAM: |
370 | case FLAC__STREAM_DECODER_READ_FRAME: | 467 | case FLAC__STREAM_DECODER_READ_FRAME: |
371 | ctx = &le_cls; | ||
372 | ADD (EXTRACTOR_METATYPE_MIMETYPE, "audio/flac"); | 468 | ADD (EXTRACTOR_METATYPE_MIMETYPE, "audio/flac"); |
373 | break; | 469 | break; |
374 | default: | 470 | default: |
@@ -376,6 +472,8 @@ EXTRACTOR_flac_extract (const char *data, | |||
376 | break; | 472 | break; |
377 | } | 473 | } |
378 | FLAC__stream_decoder_finish (decoder); | 474 | FLAC__stream_decoder_finish (decoder); |
379 | FLAC__stream_decoder_delete(decoder); | 475 | FLAC__stream_decoder_delete (decoder); |
380 | return le_cls.ret; | ||
381 | } | 476 | } |
477 | |||
478 | /* end of flac_extractor.c */ | ||
479 | |||