flacextractor.c

Go to the documentation of this file.
00001 /*
00002      This file is part of libextractor.
00003      (C) 2007 Vidyut Samanta and Christian Grothoff
00004 
00005      libextractor is free software; you can redistribute it and/or modify
00006      it under the terms of the GNU General Public License as published
00007      by the Free Software Foundation; either version 2, or (at your
00008      option) any later version.
00009 
00010      libextractor is distributed in the hope that it will be useful, but
00011      WITHOUT ANY WARRANTY; without even the implied warranty of
00012      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013      General Public License for more details.
00014 
00015      You should have received a copy of the GNU General Public License
00016      along with libextractor; see the file COPYING.  If not, write to the
00017      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018      Boston, MA 02111-1307, USA.
00019  */
00020 
00021 #include "platform.h"
00022 #include "extractor.h"
00023 
00024 #define FLAC_HEADER "fLaC"
00025 
00026 #if HAVE_FLAC_ALL_H
00027 #include <FLAC/all.h>
00028 #else
00029 #error You must install the libflac header files!
00030 #endif
00031 
00032 static char * xstrndup(const char * s, size_t n){
00033   char * d;
00034 
00035   d= malloc(n+1);
00036   memcpy(d,s,n);
00037   d[n]='\0';
00038   return d;
00039 }
00040 
00041 static struct EXTRACTOR_Keywords *
00042 addKeyword (EXTRACTOR_KeywordType type,
00043             char *keyword, struct EXTRACTOR_Keywords *next)
00044 {
00045   EXTRACTOR_KeywordList *result;
00046 
00047   if (keyword == NULL)
00048     return next;
00049   result = malloc (sizeof (EXTRACTOR_KeywordList));
00050   result->next = next;
00051   result->keyword = keyword;
00052   result->keywordType = type;
00053   return result;
00054 }
00055 
00056 struct Context {
00057   const char * data;
00058   size_t size;
00059   struct EXTRACTOR_Keywords * prev;
00060   size_t pos;
00061 };
00062 
00063 static FLAC__StreamDecoderReadStatus
00064 flac_read (const FLAC__StreamDecoder *decoder, 
00065            FLAC__byte buffer[], 
00066            size_t *bytes, 
00067            void *client_data)
00068 {
00069   struct Context * ctx = client_data;
00070   
00071   if (*bytes <= 0)
00072     return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
00073   if (*bytes > ctx->size - ctx->pos)
00074     *bytes = ctx->size - ctx->pos;
00075   if (*bytes == 0)
00076     return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
00077   memcpy(buffer,
00078          &ctx->data[ctx->pos],
00079          *bytes);
00080   ctx->pos += *bytes;  
00081   return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
00082 }
00083 
00084 static FLAC__StreamDecoderSeekStatus 
00085 flac_seek(const FLAC__StreamDecoder *decoder,
00086           FLAC__uint64 absolute_byte_offset, void *client_data)
00087 {
00088   struct Context * ctx = client_data;
00089   
00090   if (absolute_byte_offset > ctx->size)
00091     return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
00092   ctx->pos = (size_t) absolute_byte_offset;
00093   return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
00094 }
00095 
00096 static FLAC__StreamDecoderTellStatus 
00097 flac_tell(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
00098 {
00099   struct Context * ctx = client_data;
00100   
00101   *absolute_byte_offset = ctx->pos;
00102   return FLAC__STREAM_DECODER_TELL_STATUS_OK;  
00103 }
00104 
00105 static FLAC__StreamDecoderLengthStatus 
00106 flac_length(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
00107 {
00108   struct Context * ctx = client_data;
00109   
00110   ctx->pos = *stream_length;
00111   return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
00112 }
00113 
00114 static FLAC__bool
00115 flac_eof(const FLAC__StreamDecoder *decoder, void *client_data) 
00116 {
00117   struct Context * ctx = client_data;
00118 
00119   return (ctx->pos == ctx->size) ? true : false;
00120 }
00121 
00122 static FLAC__StreamDecoderWriteStatus
00123 flac_write(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data) 
00124 {
00125   return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
00126 }
00127 
00128 typedef struct
00129 {
00130   char *text;
00131   EXTRACTOR_KeywordType type;
00132 } Matches;
00133 
00134 static Matches tmap[] = {
00135   {"TITLE", EXTRACTOR_TITLE},
00136   {"VERSION", EXTRACTOR_VERSION},
00137   {"ALBUM", EXTRACTOR_ALBUM},
00138   {"ARTIST", EXTRACTOR_ARTIST},
00139   {"PERFORMER", EXTRACTOR_INTERPRET},
00140   {"COPYRIGHT", EXTRACTOR_COPYRIGHT},
00141   {"LICENSE", EXTRACTOR_LICENSE},
00142   {"ORGANIZATION", EXTRACTOR_ORGANIZATION},
00143   {"DESCRIPTION", EXTRACTOR_DESCRIPTION},
00144   {"GENRE", EXTRACTOR_GENRE},
00145   {"DATE", EXTRACTOR_DATE},
00146   {"LOCATION", EXTRACTOR_LOCATION},
00147   {"CONTACT", EXTRACTOR_CONTACT}, 
00148   {"TRACKNUMBER", EXTRACTOR_TRACK_NUMBER},
00149   {"ISRC", EXTRACTOR_ISRC},
00150   {NULL, 0},
00151 };
00152 
00153 
00154 static EXTRACTOR_KeywordList *
00155 check(const char * type,
00156       unsigned int type_length,
00157       const char * value,
00158       unsigned int value_length,
00159       EXTRACTOR_KeywordList * prev)
00160 {
00161   unsigned int i;
00162   i = 0;
00163   while (tmap[i].text != NULL) 
00164     {
00165       if ( (type_length == strlen(tmap[i].text)) &&
00166            (0 == strncasecmp(tmap[i].text,
00167                              type,
00168                              type_length)) )
00169         return addKeyword(tmap[i].type,
00170                           xstrndup(value,
00171                                   value_length),
00172                           prev);
00173       i++;
00174     }
00175   return prev;
00176 }
00177 
00178 static void 
00179 flac_metadata(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) 
00180 {
00181   struct Context * ctx = client_data;
00182   
00183   switch (metadata->type)
00184     {
00185     case FLAC__METADATA_TYPE_STREAMINFO:
00186       {
00187         char buf[512];
00188         snprintf(buf, 512,
00189                 _("%u Hz, %u channels"), 
00190                 metadata->data.stream_info.sample_rate,
00191                 metadata->data.stream_info.channels); 
00192         ctx->prev = addKeyword(EXTRACTOR_FORMAT,
00193                                strdup(buf),
00194                                ctx->prev);
00195         break;
00196       }
00197     case FLAC__METADATA_TYPE_APPLICATION:
00198       /* FIXME: could find out generator application here:
00199          http://flac.sourceforge.net/api/structFLAC____StreamMetadata__Application.html and
00200          http://flac.sourceforge.net/id.html 
00201       */
00202       break;
00203     case FLAC__METADATA_TYPE_VORBIS_COMMENT:
00204       {
00205         const FLAC__StreamMetadata_VorbisComment * vc = &metadata->data.vorbis_comment;
00206         unsigned int count = vc->num_comments;
00207         const FLAC__StreamMetadata_VorbisComment_Entry * entry;
00208         const char * eq;
00209         unsigned int len;
00210         unsigned int ilen;
00211         
00212         while (count-- > 0) 
00213           {
00214             entry = &vc->comments[count];
00215             eq = (const char*) entry->entry;
00216             len = entry->length;
00217             ilen = 0;
00218             while ( ('=' != *eq) && (*eq != '\0') &&
00219                     (ilen < len) )
00220               {
00221                 eq++;
00222                 ilen++;
00223               }
00224             if ( ('=' != *eq) ||
00225                  (ilen == len) )
00226               break;
00227             eq++;
00228             ctx->prev = check((const char*) entry->entry,
00229                               ilen,
00230                               eq,
00231                               len - ilen,
00232                               ctx->prev);                 
00233           }
00234         break;
00235       }
00236     case FLAC__METADATA_TYPE_PICTURE:
00237       {
00238         FLAC__byte * data = metadata->data.picture.data;
00239         FLAC__uint32 length = metadata->data.picture.data_length;
00240         char * enc;
00241         
00242         enc = EXTRACTOR_binaryEncode(data, length);
00243         ctx->prev = addKeyword(EXTRACTOR_THUMBNAILS,
00244                                enc,
00245                                ctx->prev);      
00246         break;
00247       }
00248     case FLAC__METADATA_TYPE_PADDING:
00249     case FLAC__METADATA_TYPE_SEEKTABLE:
00250     case FLAC__METADATA_TYPE_CUESHEET:
00251     case FLAC__METADATA_TYPE_UNDEFINED:
00252       break;
00253     }
00254 }  
00255 
00256 static void
00257 flac_error(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) 
00258 {
00259 #if 0
00260   fprintf(stderr,
00261           "Got error: %u\n", status);
00262 #endif
00263 }
00264 
00265 /* mimetype = audio/flac */
00266 struct EXTRACTOR_Keywords *
00267 libextractor_flac_extract (const char *filename,
00268                            const char *data,
00269                            size_t size, struct EXTRACTOR_Keywords *prev)
00270 {
00271   FLAC__StreamDecoder * decoder;
00272   struct Context le_cls;
00273 
00274   if (size < strlen(FLAC_HEADER) + sizeof (int))    
00275     return prev;    
00276   if (0 != memcmp(FLAC_HEADER,
00277                   data,
00278                   strlen(FLAC_HEADER)))
00279     return prev;
00280   decoder = FLAC__stream_decoder_new();
00281   if (NULL == decoder)
00282     return prev;
00283   FLAC__stream_decoder_set_md5_checking(decoder, false);
00284   FLAC__stream_decoder_set_metadata_ignore_all(decoder);
00285   if (false == FLAC__stream_decoder_set_metadata_respond_all(decoder))
00286     {
00287       FLAC__stream_decoder_delete(decoder);     
00288       return prev;
00289     }
00290   le_cls.prev = prev;
00291   le_cls.prev = prev;
00292   le_cls.size = size;
00293   le_cls.data = data;
00294   le_cls.pos = 0;
00295   if (FLAC__STREAM_DECODER_INIT_STATUS_OK !=
00296       FLAC__stream_decoder_init_stream(decoder,
00297                                        &flac_read,
00298                                        &flac_seek,
00299                                        &flac_tell,
00300                                        &flac_length,
00301                                        &flac_eof,
00302                                        &flac_write,
00303                                        &flac_metadata,
00304                                        &flac_error,
00305                                        &le_cls))
00306     {
00307       FLAC__stream_decoder_delete(decoder);     
00308       return le_cls.prev;
00309     }
00310   if (FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
00311     {
00312       FLAC__stream_decoder_delete(decoder);     
00313       return le_cls.prev;
00314     }
00315   if (! FLAC__stream_decoder_process_until_end_of_metadata(decoder))
00316     {
00317       FLAC__stream_decoder_delete(decoder);     
00318       return le_cls.prev;
00319     }
00320   switch (FLAC__stream_decoder_get_state(decoder))
00321    {
00322    case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
00323    case FLAC__STREAM_DECODER_READ_METADATA:
00324    case FLAC__STREAM_DECODER_END_OF_STREAM:
00325    case FLAC__STREAM_DECODER_READ_FRAME:
00326      le_cls.prev = addKeyword(EXTRACTOR_MIMETYPE,
00327                               strdup("audio/flac"),
00328                               le_cls.prev);
00329      break;
00330    default:
00331      /* not so sure... */
00332      break;
00333    }
00334   FLAC__stream_decoder_finish (decoder); 
00335   FLAC__stream_decoder_delete(decoder);
00336   return le_cls.prev;
00337 }

Generated on Fri Jan 9 16:44:29 2009 for libextractor by  doxygen 1.5.1