libextractor

GNU libextractor
Log | Files | Refs | Submodules | README | LICENSE

ogg_extractor.c (5677B)


      1 /*
      2      This file is part of libextractor.
      3      Copyright (C) 2002, 2003, 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  * @file plugins/ogg_extractor.c
     22  * @brief plugin to support OGG files
     23  * @author Christian Grothoff
     24  */
     25 #include "platform.h"
     26 #include "extractor.h"
     27 #include <vorbis/vorbisfile.h>
     28 
     29 /**
     30  * Bytes each ogg file must begin with (not used, but we might
     31  * choose to add this back in the future to improve performance
     32  * for non-ogg files).
     33  */
     34 #define OGG_HEADER 0x4f676753
     35 
     36 
     37 /**
     38  * Custom read function for ogg.
     39  *
     40  * @param ptr where to write the data
     41  * @param size number of bytes to read per member
     42  * @param nmemb number of members to read
     43  * @param datasource the 'struct EXTRACTOR_ExtractContext'
     44  * @return 0 on end-of-data, 0 with errno set to indicate read error
     45  */
     46 static size_t
     47 read_ogg (void *ptr, size_t size, size_t nmemb, void *datasource)
     48 {
     49   struct EXTRACTOR_ExtractContext *ec = datasource;
     50   void *data;
     51   ssize_t ret;
     52 
     53   data = NULL;
     54   ret = ec->read (ec->cls,
     55                   &data,
     56                   size * nmemb);
     57   if (-1 == ret)
     58     return 0;
     59   if (0 == ret)
     60   {
     61     errno = 0;
     62     return 0;
     63   }
     64   memcpy (ptr, data, ret);
     65   errno = 0;
     66   return ret;
     67 }
     68 
     69 
     70 /**
     71  * Seek to a particular position in the file.
     72  *
     73  * @param datasource  the 'struct EXTRACTOR_ExtractContext'
     74  * @param offset where to seek
     75  * @param whence how to seek
     76  * @return -1 on error, new position on success
     77  */
     78 static int
     79 seek_ogg (void *datasource,
     80           ogg_int64_t offset,
     81           int whence)
     82 {
     83   struct EXTRACTOR_ExtractContext *ec = datasource;
     84   int64_t new_position;
     85 
     86   new_position = ec->seek (ec->cls, (int64_t) offset, whence);
     87   return (long) new_position;
     88 }
     89 
     90 
     91 /**
     92  * Tell ogg where we are in the file
     93  *
     94  * @param datasource  the 'struct EXTRACTOR_ExtractContext'
     95  * @return
     96  */
     97 static long
     98 tell_ogg (void *datasource)
     99 {
    100   struct EXTRACTOR_ExtractContext *ec = datasource;
    101 
    102   return (long) ec->seek (ec->cls,
    103                           0,
    104                           SEEK_CUR);
    105 }
    106 
    107 
    108 /**
    109  * Extract the associated meta data for a given label from vorbis.
    110  *
    111  * @param vc vorbis comment data
    112  * @param label label marking the desired entry
    113  * @return NULL on error, otherwise the meta data
    114  */
    115 static char *
    116 get_comment (vorbis_comment *vc,
    117              const char *label)
    118 {
    119   if (NULL == vc)
    120     return NULL;
    121   return vorbis_comment_query (vc, label, 0);
    122 }
    123 
    124 
    125 /**
    126  * Extract meta data from vorbis using the given LE type and value.
    127  *
    128  * @param t LE meta data type
    129  * @param s meta data to add
    130  */
    131 #define ADD(t,s) do { if (0 != (ret = ec->proc (ec->cls, "ogg", t, \
    132                                                 EXTRACTOR_METAFORMAT_UTF8, \
    133                                                 "text/plain", s, strlen (s) \
    134                                                 + 1))) goto FINISH; \
    135 } while (0)
    136 
    137 
    138 /**
    139  * Extract meta data from vorbis using the given LE type and label.
    140  *
    141  * @param t LE meta data type
    142  * @param d vorbis meta data label
    143  */
    144 #define ADDG(t,d) do { m = get_comment (comments, d); if (NULL != m) ADD (t,m); \
    145 } while (0)
    146 
    147 
    148 /**
    149  * Main entry method for the 'application/ogg' extraction plugin.
    150  *
    151  * @param ec extraction context provided to the plugin
    152  */
    153 void
    154 EXTRACTOR_ogg_extract_method (struct EXTRACTOR_ExtractContext *ec)
    155 {
    156   uint64_t fsize;
    157   ov_callbacks callbacks;
    158   OggVorbis_File vf;
    159   vorbis_comment *comments;
    160   int ret;
    161   const char *m;
    162 
    163   fsize = ec->get_size (ec->cls);
    164   if (fsize < 8)
    165     return;
    166 
    167   callbacks.read_func = &read_ogg;
    168   callbacks.seek_func = &seek_ogg;
    169   callbacks.close_func = NULL;
    170   callbacks.tell_func = &tell_ogg;
    171   ret = ov_open_callbacks (ec, &vf, NULL, 0, callbacks);
    172   if (0 != ret)
    173   {
    174     ov_clear (&vf);
    175     return;
    176   }
    177   comments = ov_comment (&vf, -1);
    178   if (NULL == comments)
    179   {
    180     ov_clear (&vf);
    181     return;
    182   }
    183   ADD (EXTRACTOR_METATYPE_MIMETYPE, "application/ogg");
    184   if ((comments->vendor != NULL) && (strlen (comments->vendor) > 0))
    185     ADD (EXTRACTOR_METATYPE_VENDOR, comments->vendor);
    186   ADDG (EXTRACTOR_METATYPE_TITLE, "title");
    187   ADDG (EXTRACTOR_METATYPE_ARTIST, "artist");
    188   ADDG (EXTRACTOR_METATYPE_PERFORMER, "performer");
    189   ADDG (EXTRACTOR_METATYPE_ALBUM, "album");
    190   ADDG (EXTRACTOR_METATYPE_TRACK_NUMBER, "tracknumber");
    191   ADDG (EXTRACTOR_METATYPE_DISC_NUMBER, "discnumber");
    192   ADDG (EXTRACTOR_METATYPE_CONTACT_INFORMATION, "contact");
    193   ADDG (EXTRACTOR_METATYPE_GENRE, "genre");
    194   ADDG (EXTRACTOR_METATYPE_CREATION_DATE, "date");
    195   ADDG (EXTRACTOR_METATYPE_COMMENT, "");
    196   ADDG (EXTRACTOR_METATYPE_LOCATION_SUBLOCATION, "location");
    197   ADDG (EXTRACTOR_METATYPE_DESCRIPTION, "description");
    198   ADDG (EXTRACTOR_METATYPE_ISRC, "isrc");
    199   ADDG (EXTRACTOR_METATYPE_ORGANIZATION, "organization");
    200   ADDG (EXTRACTOR_METATYPE_COPYRIGHT, "copyright");
    201   ADDG (EXTRACTOR_METATYPE_LICENSE, "license");
    202   ADDG (EXTRACTOR_METATYPE_SONG_VERSION, "version");
    203 FINISH:
    204   ov_clear (&vf);
    205 }
    206 
    207 
    208 /* end of ogg_extractor.c */