libextractor

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

ogg_extractor.c (5731B)


      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,
     87                            (int64_t) offset,
     88                            whence);
     89   return (long) new_position;
     90 }
     91 
     92 
     93 /**
     94  * Tell ogg where we are in the file
     95  *
     96  * @param datasource  the 'struct EXTRACTOR_ExtractContext'
     97  * @return
     98  */
     99 static long
    100 tell_ogg (void *datasource)
    101 {
    102   struct EXTRACTOR_ExtractContext *ec = datasource;
    103 
    104   return (long) ec->seek (ec->cls,
    105                           0,
    106                           SEEK_CUR);
    107 }
    108 
    109 
    110 /**
    111  * Extract the associated meta data for a given label from vorbis.
    112  *
    113  * @param vc vorbis comment data
    114  * @param label label marking the desired entry
    115  * @return NULL on error, otherwise the meta data
    116  */
    117 static char *
    118 get_comment (vorbis_comment *vc,
    119              const char *label)
    120 {
    121   if (NULL == vc)
    122     return NULL;
    123   return vorbis_comment_query (vc, label, 0);
    124 }
    125 
    126 
    127 /**
    128  * Extract meta data from vorbis using the given LE type and value.
    129  *
    130  * @param t LE meta data type
    131  * @param s meta data to add
    132  */
    133 #define ADD(t,s) do { if (0 != (ret = ec->proc (ec->cls, "ogg", t, \
    134                                                 EXTRACTOR_METAFORMAT_UTF8, \
    135                                                 "text/plain", s, strlen (s) \
    136                                                 + 1))) goto FINISH; \
    137 } while (0)
    138 
    139 
    140 /**
    141  * Extract meta data from vorbis using the given LE type and label.
    142  *
    143  * @param t LE meta data type
    144  * @param d vorbis meta data label
    145  */
    146 #define ADDG(t,d) do { m = get_comment (comments, d); if (NULL != m) ADD (t,m); \
    147 } while (0)
    148 
    149 
    150 /**
    151  * Main entry method for the 'application/ogg' extraction plugin.
    152  *
    153  * @param ec extraction context provided to the plugin
    154  */
    155 void
    156 EXTRACTOR_ogg_extract_method (struct EXTRACTOR_ExtractContext *ec)
    157 {
    158   uint64_t fsize;
    159   ov_callbacks callbacks;
    160   OggVorbis_File vf;
    161   vorbis_comment *comments;
    162   int ret;
    163   const char *m;
    164 
    165   fsize = ec->get_size (ec->cls);
    166   if (fsize < 8)
    167     return;
    168 
    169   callbacks.read_func = &read_ogg;
    170   callbacks.seek_func = &seek_ogg;
    171   callbacks.close_func = NULL;
    172   callbacks.tell_func = &tell_ogg;
    173   ret = ov_open_callbacks (ec, &vf, NULL, 0, callbacks);
    174   if (0 != ret)
    175   {
    176     ov_clear (&vf);
    177     return;
    178   }
    179   comments = ov_comment (&vf, -1);
    180   if (NULL == comments)
    181   {
    182     ov_clear (&vf);
    183     return;
    184   }
    185   ADD (EXTRACTOR_METATYPE_MIMETYPE, "application/ogg");
    186   if ((comments->vendor != NULL) && (strlen (comments->vendor) > 0))
    187     ADD (EXTRACTOR_METATYPE_VENDOR, comments->vendor);
    188   ADDG (EXTRACTOR_METATYPE_TITLE, "title");
    189   ADDG (EXTRACTOR_METATYPE_ARTIST, "artist");
    190   ADDG (EXTRACTOR_METATYPE_PERFORMER, "performer");
    191   ADDG (EXTRACTOR_METATYPE_ALBUM, "album");
    192   ADDG (EXTRACTOR_METATYPE_TRACK_NUMBER, "tracknumber");
    193   ADDG (EXTRACTOR_METATYPE_DISC_NUMBER, "discnumber");
    194   ADDG (EXTRACTOR_METATYPE_CONTACT_INFORMATION, "contact");
    195   ADDG (EXTRACTOR_METATYPE_GENRE, "genre");
    196   ADDG (EXTRACTOR_METATYPE_CREATION_DATE, "date");
    197   ADDG (EXTRACTOR_METATYPE_COMMENT, "");
    198   ADDG (EXTRACTOR_METATYPE_LOCATION_SUBLOCATION, "location");
    199   ADDG (EXTRACTOR_METATYPE_DESCRIPTION, "description");
    200   ADDG (EXTRACTOR_METATYPE_ISRC, "isrc");
    201   ADDG (EXTRACTOR_METATYPE_ORGANIZATION, "organization");
    202   ADDG (EXTRACTOR_METATYPE_COPYRIGHT, "copyright");
    203   ADDG (EXTRACTOR_METATYPE_LICENSE, "license");
    204   ADDG (EXTRACTOR_METATYPE_SONG_VERSION, "version");
    205 FINISH:
    206   ov_clear (&vf);
    207 }
    208 
    209 
    210 /* end of ogg_extractor.c */