libextractor  1.11
About: GNU libextractor is a library used to extract meta-data from files of arbitrary type.
  Fossies Dox: libextractor-1.11.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

flac_extractor.c
Go to the documentation of this file.
1 /*
2  This file is part of libextractor.
3  Copyright (C) 2007, 2009, 2012 Vidyut Samanta and 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 
21 /**
22  * @file plugins/flac_extractor.c
23  * @brief plugin to support FLAC files
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "extractor.h"
28 #include <FLAC/all.h>
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  */
36 #define FLAC_HEADER "fLaC"
37 
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  */
48 static FLAC__StreamDecoderReadStatus
49 flac_read (const FLAC__StreamDecoder *decoder,
50  FLAC__byte buffer[],
51  size_t *bytes,
52  void *client_data)
53 {
54  struct EXTRACTOR_ExtractContext *ec = client_data;
55  void *data;
56  ssize_t ret;
57 
58  data = NULL;
59  ret = ec->read (ec->cls,
60  &data,
61  *bytes);
62  if (-1 == ret)
63  return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
64  if (0 == ret)
65  {
66  errno = 0;
67  return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
68  }
69  memcpy (buffer, data, ret);
70  *bytes = ret;
71  errno = 0;
72  return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
73 }
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  */
84 static FLAC__StreamDecoderSeekStatus
85 flac_seek (const FLAC__StreamDecoder *decoder,
86  FLAC__uint64 absolute_byte_offset,
87  void *client_data)
88 {
89  struct EXTRACTOR_ExtractContext *ec = client_data;
90 
91  if (absolute_byte_offset !=
92  ec->seek (ec->cls, (int64_t) absolute_byte_offset, SEEK_SET))
93  return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
94  return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
95 }
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  */
106 static FLAC__StreamDecoderTellStatus
107 flac_tell (const FLAC__StreamDecoder *decoder,
108  FLAC__uint64 *absolute_byte_offset,
109  void *client_data)
110 {
111  struct EXTRACTOR_ExtractContext *ec = client_data;
112 
113  *absolute_byte_offset = ec->seek (ec->cls,
114  0,
115  SEEK_CUR);
116  return FLAC__STREAM_DECODER_TELL_STATUS_OK;
117 }
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  */
128 static FLAC__StreamDecoderLengthStatus
129 flac_length (const FLAC__StreamDecoder *decoder,
130  FLAC__uint64 *stream_length,
131  void *client_data)
132 {
133  struct EXTRACTOR_ExtractContext *ec = client_data;
134 
135  *stream_length = ec->get_size (ec->cls);
136  return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
137 }
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  */
148 static FLAC__bool
149 flac_eof (const FLAC__StreamDecoder *decoder,
150  void *client_data)
151 {
152  struct EXTRACTOR_ExtractContext *ec = client_data;
153  uint64_t size;
154  int64_t seekresult;
155  size = ec->get_size (ec->cls);
156  seekresult = ec->seek (ec->cls, 0, SEEK_CUR);
157 
158  if (seekresult == -1)
159  /* Treat seek error as error (not as indication of file not being
160  * seekable).
161  */
162  return true;
163  return (size == seekresult) ? true : false;
164 }
165 
166 
167 /**
168  * FLAC wants to write. Always succeeds but does nothing.
169  *
170  * @param decoder unused
171  * @param frame unused
172  * @param buffer unused
173  * @param client_data the 'struct EXTRACTOR_ExtractContext'
174  * @return always claims success
175  */
176 static FLAC__StreamDecoderWriteStatus
177 flac_write (const FLAC__StreamDecoder *decoder,
178  const FLAC__Frame *frame,
179  const FLAC__int32 *const buffer[],
180  void *client_data)
181 {
182  return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
183 }
184 
185 
186 /**
187  * A mapping from FLAC meta data strings to extractor types.
188  */
189 struct Matches
190 {
191  /**
192  * FLAC Meta data description text.
193  */
194  const char *text;
195 
196  /**
197  * Corresponding LE type.
198  */
200 };
201 
202 
203 /**
204  * Mapping of FLAC meta data description texts to LE types.
205  * NULL-terminated.
206  */
207 static struct Matches tmap[] = {
208  {"TITLE", EXTRACTOR_METATYPE_TITLE},
209  {"VERSION", EXTRACTOR_METATYPE_SONG_VERSION},
210  {"ALBUM", EXTRACTOR_METATYPE_ALBUM},
211  {"ARTIST", EXTRACTOR_METATYPE_ARTIST},
212  {"PERFORMER", EXTRACTOR_METATYPE_PERFORMER},
213  {"COPYRIGHT", EXTRACTOR_METATYPE_COPYRIGHT},
214  {"LICENSE", EXTRACTOR_METATYPE_LICENSE},
215  {"ORGANIZATION", EXTRACTOR_METATYPE_ORGANIZATION},
216  {"DESCRIPTION", EXTRACTOR_METATYPE_DESCRIPTION},
217  {"GENRE", EXTRACTOR_METATYPE_GENRE},
221  {"TRACKNUMBER", EXTRACTOR_METATYPE_TRACK_NUMBER},
222  {"ISRC", EXTRACTOR_METATYPE_ISRC},
223  {NULL, 0}
224 };
225 
226 
227 /**
228  * Give meta data to extractor.
229  *
230  * @param t type of the meta data
231  * @param s meta data value in utf8 format
232  */
233 #define ADD(t,s) do { ec->proc (ec->cls, "flac", t, EXTRACTOR_METAFORMAT_UTF8, \
234  "text/plain", s, strlen (s) + 1); } while (0)
235 
236 
237 /**
238  * Create 0-terminated version of n-character string.
239  *
240  * @param s input string (non 0-terminated)
241  * @param n number of bytes in 's'
242  * @return NULL on error, otherwise 0-terminated version of 's'
243  */
244 static char *
245 xstrndup (const char *s,
246  size_t n)
247 {
248  char *d;
249 
250  if (NULL == (d = malloc (n + 1)))
251  return NULL;
252  memcpy (d, s, n);
253  d[n] = '\0';
254  return d;
255 }
256 
257 
258 /**
259  * Check if a mapping exists for the given meta data value
260  * and if so give the result to LE.
261  *
262  * @param type type of the meta data according to FLAC
263  * @param type_length number of bytes in 'type'
264  * @param value meta data as UTF8 string (non 0-terminated)
265  * @param value_length number of bytes in value
266  * @param ec extractor context
267  */
268 static void
269 check (const char *type,
270  unsigned int type_length,
271  const char *value,
272  unsigned int value_length,
273  struct EXTRACTOR_ExtractContext *ec)
274 {
275  unsigned int i;
276  char *tmp;
277 
278  for (i = 0; NULL != tmap[i].text; i++)
279  {
280  if ( (type_length != strlen (tmap[i].text)) ||
281  (0 != strncasecmp (tmap[i].text,
282  type,
283  type_length)) )
284  continue;
285  if (NULL ==
286  (tmp = xstrndup (value,
287  value_length)))
288  continue;
289  ADD (tmap[i].type, tmp);
290  free (tmp);
291  break;
292  }
293 }
294 
295 
296 /**
297  * Function called whenever FLAC finds meta data.
298  *
299  * @param decoder unused
300  * @param metadata meta data that was found
301  * @param client_data the 'struct EXTRACTOR_ExtractContext'
302  */
303 static void
304 flac_metadata (const FLAC__StreamDecoder *decoder,
305  const FLAC__StreamMetadata *metadata,
306  void *client_data)
307 {
308  struct EXTRACTOR_ExtractContext *ec = client_data;
310  const FLAC__StreamMetadata_VorbisComment *vc;
311  unsigned int count;
312  const FLAC__StreamMetadata_VorbisComment_Entry *entry;
313  const char *eq;
314  unsigned int len;
315  unsigned int ilen;
316  char buf[128];
317 
318  switch (metadata->type)
319  {
320  case FLAC__METADATA_TYPE_STREAMINFO:
321  {
322  snprintf (buf, sizeof (buf),
323  _ ("%u Hz, %u channels"),
324  metadata->data.stream_info.sample_rate,
325  metadata->data.stream_info.channels);
327  break;
328  }
329  case FLAC__METADATA_TYPE_APPLICATION:
330  /* FIXME: could find out generator application here:
331  http://flac.sourceforge.net/api/structFLAC____StreamMetadata__Application.html and
332  http://flac.sourceforge.net/id.html
333  */
334  break;
335  case FLAC__METADATA_TYPE_VORBIS_COMMENT:
336  {
337  vc = &metadata->data.vorbis_comment;
338  count = vc->num_comments;
339  while (count-- > 0)
340  {
341  entry = &vc->comments[count];
342  eq = (const char*) entry->entry;
343  if (NULL == eq)
344  break;
345  len = entry->length;
346  ilen = 0;
347  while ( ('=' != *eq) && ('\0' != *eq) &&
348  (ilen < len) )
349  {
350  eq++;
351  ilen++;
352  }
353  if ( ('=' != *eq) ||
354  (ilen == len) )
355  break;
356  eq++;
357  check ((const char*) entry->entry,
358  ilen,
359  eq,
360  len - ilen,
361  ec);
362  }
363  break;
364  }
365  case FLAC__METADATA_TYPE_PICTURE:
366  {
367  switch (metadata->data.picture.type)
368  {
369  case FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER:
370  case FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD:
371  case FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON:
373  break;
374  case FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER:
375  case FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER:
377  break;
378  case FLAC__STREAM_METADATA_PICTURE_TYPE_LEAD_ARTIST:
379  case FLAC__STREAM_METADATA_PICTURE_TYPE_ARTIST:
380  case FLAC__STREAM_METADATA_PICTURE_TYPE_CONDUCTOR:
381  case FLAC__STREAM_METADATA_PICTURE_TYPE_BAND:
382  case FLAC__STREAM_METADATA_PICTURE_TYPE_COMPOSER:
383  case FLAC__STREAM_METADATA_PICTURE_TYPE_LYRICIST:
385  break;
386  case FLAC__STREAM_METADATA_PICTURE_TYPE_RECORDING_LOCATION:
387  case FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_RECORDING:
388  case FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_PERFORMANCE:
389  case FLAC__STREAM_METADATA_PICTURE_TYPE_VIDEO_SCREEN_CAPTURE:
391  break;
392  case FLAC__STREAM_METADATA_PICTURE_TYPE_BAND_LOGOTYPE:
393  case FLAC__STREAM_METADATA_PICTURE_TYPE_PUBLISHER_LOGOTYPE:
395  break;
396  case FLAC__STREAM_METADATA_PICTURE_TYPE_LEAFLET_PAGE:
397  case FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA:
398  case FLAC__STREAM_METADATA_PICTURE_TYPE_FISH:
399  case FLAC__STREAM_METADATA_PICTURE_TYPE_ILLUSTRATION:
400  default:
402  break;
403  }
404  ec->proc (ec->cls,
405  "flac",
406  type,
408  metadata->data.picture.mime_type,
409  (const char*) metadata->data.picture.data,
410  metadata->data.picture.data_length);
411  break;
412  }
413  default:
414  break;
415  }
416 }
417 
418 
419 /**
420  * Function called whenever FLAC decoder has trouble. Does nothing.
421  *
422  * @param decoder the decoder handle
423  * @param status type of the error
424  * @param client_data our 'struct EXTRACTOR_ExtractContext'
425  */
426 static void
427 flac_error (const FLAC__StreamDecoder *decoder,
428  FLAC__StreamDecoderErrorStatus status,
429  void *client_data)
430 {
431  /* ignore errors */
432 }
433 
434 
435 /**
436  * Main entry method for the 'audio/flac' extraction plugin.
437  *
438  * @param ec extraction context provided to the plugin
439  */
440 void
442 {
443  FLAC__StreamDecoder *decoder;
444 
445  if (NULL == (decoder = FLAC__stream_decoder_new ()))
446  return;
447  FLAC__stream_decoder_set_md5_checking (decoder, false);
448  FLAC__stream_decoder_set_metadata_ignore_all (decoder);
449  if (false == FLAC__stream_decoder_set_metadata_respond_all (decoder))
450  {
451  FLAC__stream_decoder_delete (decoder);
452  return;
453  }
454  if (FLAC__STREAM_DECODER_INIT_STATUS_OK !=
455  FLAC__stream_decoder_init_stream (decoder,
456  &flac_read,
457  &flac_seek,
458  &flac_tell,
459  &flac_length,
460  &flac_eof,
461  &flac_write,
462  &flac_metadata,
463  &flac_error,
464  ec))
465  {
466  FLAC__stream_decoder_delete (decoder);
467  return;
468  }
469  if (FLAC__STREAM_DECODER_SEARCH_FOR_METADATA !=
470  FLAC__stream_decoder_get_state (decoder))
471  {
472  FLAC__stream_decoder_delete (decoder);
473  return;
474  }
475  if (! FLAC__stream_decoder_process_until_end_of_metadata (decoder))
476  {
477  FLAC__stream_decoder_delete (decoder);
478  return;
479  }
480  switch (FLAC__stream_decoder_get_state (decoder))
481  {
482  case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
483  case FLAC__STREAM_DECODER_READ_METADATA:
484  case FLAC__STREAM_DECODER_END_OF_STREAM:
485  case FLAC__STREAM_DECODER_READ_FRAME:
486  break;
487  default:
488  /* not so sure... */
489  break;
490  }
491  FLAC__stream_decoder_finish (decoder);
492  FLAC__stream_decoder_delete (decoder);
493 }
494 
495 
496 /* end of flac_extractor.c */
@ EXTRACTOR_METAFORMAT_BINARY
Definition: extractor.h:107
void EXTRACTOR_flac_extract_method(struct EXTRACTOR_ExtractContext *ec)
static FLAC__StreamDecoderLengthStatus flac_length(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
static void flac_error(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
static FLAC__StreamDecoderTellStatus flac_tell(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
static void flac_metadata(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
static FLAC__bool flac_eof(const FLAC__StreamDecoder *decoder, void *client_data)
static FLAC__StreamDecoderWriteStatus flac_write(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data)
static void check(const char *type, unsigned int type_length, const char *value, unsigned int value_length, struct EXTRACTOR_ExtractContext *ec)
static FLAC__StreamDecoderSeekStatus flac_seek(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
static char * xstrndup(const char *s, size_t n)
static struct Matches tmap[]
static FLAC__StreamDecoderReadStatus flac_read(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
#define ADD(t, s)
#define NULL
Definition: getopt1.c:60
EXTRACTOR_MetaType
Definition: extractor.h:126
@ EXTRACTOR_METATYPE_LOGO
Definition: extractor.h:290
@ EXTRACTOR_METATYPE_RESOURCE_TYPE
Definition: extractor.h:233
@ EXTRACTOR_METATYPE_SONG_VERSION
Definition: extractor.h:285
@ EXTRACTOR_METATYPE_GENRE
Definition: extractor.h:280
@ EXTRACTOR_METATYPE_THUMBNAIL
Definition: extractor.h:259
@ EXTRACTOR_METATYPE_EVENT_PICTURE
Definition: extractor.h:289
@ EXTRACTOR_METATYPE_TRACK_NUMBER
Definition: extractor.h:281
@ EXTRACTOR_METATYPE_COVER_PICTURE
Definition: extractor.h:287
@ EXTRACTOR_METATYPE_TITLE
Definition: extractor.h:134
@ EXTRACTOR_METATYPE_ARTIST
Definition: extractor.h:279
@ EXTRACTOR_METATYPE_PERFORMER
Definition: extractor.h:283
@ EXTRACTOR_METATYPE_ISRC
Definition: extractor.h:163
@ EXTRACTOR_METATYPE_CREATION_DATE
Definition: extractor.h:196
@ EXTRACTOR_METATYPE_LICENSE
Definition: extractor.h:226
@ EXTRACTOR_METATYPE_COPYRIGHT
Definition: extractor.h:183
@ EXTRACTOR_METATYPE_CONTRIBUTOR_PICTURE
Definition: extractor.h:288
@ EXTRACTOR_METATYPE_ORGANIZATION
Definition: extractor.h:327
@ EXTRACTOR_METATYPE_ALBUM
Definition: extractor.h:278
@ EXTRACTOR_METATYPE_LOCATION_SUBLOCATION
Definition: extractor.h:176
@ EXTRACTOR_METATYPE_CONTACT_INFORMATION
Definition: extractor.h:284
@ EXTRACTOR_METATYPE_DESCRIPTION
Definition: extractor.h:182
@ EXTRACTOR_METATYPE_PICTURE
Definition: extractor.h:286
enum EXTRACTOR_MetaType type
plaform specifics
#define _(a)
Definition: platform.h:32
static unsigned char * buffer
int64_t(* seek)(void *cls, int64_t pos, int whence)
Definition: extractor.h:509
uint64_t(* get_size)(void *cls)
Definition: extractor.h:520
EXTRACTOR_MetaDataProcessor proc
Definition: extractor.h:525
ssize_t(* read)(void *cls, void **data, size_t size)
Definition: extractor.h:494
const char * text
Definition: deb_extractor.c:77
enum EXTRACTOR_MetaType type
Definition: deb_extractor.c:82