diff options
Diffstat (limited to 'src/plugins/ogg_extractor.c')
-rw-r--r-- | src/plugins/ogg_extractor.c | 178 |
1 files changed, 129 insertions, 49 deletions
diff --git a/src/plugins/ogg_extractor.c b/src/plugins/ogg_extractor.c index a9c4f05..971ac8c 100644 --- a/src/plugins/ogg_extractor.c +++ b/src/plugins/ogg_extractor.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of libextractor. | 2 | This file is part of libextractor. |
3 | (C) 2002, 2003, 2009 Vidyut Samanta and Christian Grothoff | 3 | (C) 2002, 2003, 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 |
@@ -17,84 +17,162 @@ | |||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
18 | Boston, MA 02111-1307, USA. | 18 | Boston, MA 02111-1307, USA. |
19 | */ | 19 | */ |
20 | |||
21 | #include "platform.h" | 20 | #include "platform.h" |
22 | #include "extractor.h" | 21 | #include "extractor.h" |
23 | #include "extractor_plugins.h" | 22 | #include "extractor_plugins.h" |
23 | #include <vorbis/vorbisfile.h> | ||
24 | 24 | ||
25 | #define DEBUG_EXTRACT_OGG 0 | 25 | /** |
26 | * Bytes each ogg file must begin with (not used, but we might | ||
27 | * choose to add this back in the future to improve performance | ||
28 | * for non-ogg files). | ||
29 | */ | ||
26 | #define OGG_HEADER 0x4f676753 | 30 | #define OGG_HEADER 0x4f676753 |
27 | 31 | ||
28 | #if HAVE_VORBIS_VORBISFILE_H | ||
29 | #include <vorbis/vorbisfile.h> | ||
30 | #else | ||
31 | #error You must install the libvorbis header files! | ||
32 | #endif | ||
33 | |||
34 | static char * | ||
35 | get_comment (vorbis_comment * vc, char *label) | ||
36 | { | ||
37 | char *tag; | ||
38 | if (vc && (tag = vorbis_comment_query (vc, label, 0)) != NULL) | ||
39 | return tag; | ||
40 | return NULL; | ||
41 | } | ||
42 | 32 | ||
33 | /** | ||
34 | * Custom read function for ogg. | ||
35 | * | ||
36 | * @param ptr where to write the data | ||
37 | * @param size number of bytes to read per member | ||
38 | * @param nmemb number of members to read | ||
39 | * @param datasource the 'struct EXTRACTOR_ExtractContext' | ||
40 | * @return 0 on end-of-data, 0 with errno set to indicate read error | ||
41 | */ | ||
43 | static size_t | 42 | static size_t |
44 | readOgg (void *ptr, size_t size, size_t nmemb, void *datasource) | 43 | read_ogg (void *ptr, size_t size, size_t nmemb, void *datasource) |
45 | { | 44 | { |
46 | struct EXTRACTOR_PluginList *plugin = datasource; | 45 | struct EXTRACTOR_ExtractContext *ec = datasource; |
47 | int64_t ret; | 46 | void *data; |
48 | unsigned char *read_data; | 47 | ssize_t ret; |
49 | 48 | ||
50 | ret = pl_read (plugin, &read_data, size*nmemb); | 49 | data = NULL; |
51 | if (ret <= 0) | 50 | ret = ec->read (ec->cls, |
52 | { | 51 | &data, |
53 | if (ret < 0) | 52 | size * nmemb); |
54 | errno = EIO; | 53 | if (-1 == ret) |
55 | return 0; | 54 | return 0; |
56 | } | 55 | if (0 == ret) |
57 | memcpy (ptr, read_data, ret); | 56 | { |
57 | errno = 0; | ||
58 | return 0; | ||
59 | } | ||
60 | memcpy (ptr, data, ret); | ||
61 | errno = 0; | ||
58 | return ret; | 62 | return ret; |
59 | } | 63 | } |
60 | 64 | ||
61 | #define ADD(t,s) do { if (0 != (ret = proc (proc_cls, "ogg", t, EXTRACTOR_METAFORMAT_UTF8, "text/plain", s, strlen(s)+1))) goto FINISH; } while (0) | ||
62 | 65 | ||
63 | #define ADDG(t,d) do { m = get_comment (comments, d); if (m != NULL) ADD(t,m); } while (0) | 66 | /** |
67 | * Seek to a particular position in the file. | ||
68 | * | ||
69 | * @param datasource the 'struct EXTRACTOR_ExtractContext' | ||
70 | * @param offset where to seek | ||
71 | * @param whence how to seek | ||
72 | * @return -1 on error | ||
73 | */ | ||
74 | static int | ||
75 | seek_ogg (void *datasource, | ||
76 | ogg_int64_t offset, | ||
77 | int whence) | ||
78 | { | ||
79 | struct EXTRACTOR_ExtractContext *ec = datasource; | ||
80 | |||
81 | if (-1 == ec->seek (ec->cls, | ||
82 | (int64_t) offset, | ||
83 | whence)) | ||
84 | return -1; | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | |||
89 | /** | ||
90 | * Tell ogg where we are in the file | ||
91 | * | ||
92 | * @param datasource the 'struct EXTRACTOR_ExtractContext' | ||
93 | * @return | ||
94 | */ | ||
95 | static long | ||
96 | tell_ogg (void *datasource) | ||
97 | { | ||
98 | struct EXTRACTOR_ExtractContext *ec = datasource; | ||
99 | |||
100 | return (long) ec->seek (ec->cls, | ||
101 | 0, | ||
102 | SEEK_CUR); | ||
103 | } | ||
104 | |||
105 | |||
106 | |||
107 | /** | ||
108 | * Extract the associated meta data for a given label from vorbis. | ||
109 | * | ||
110 | * @param vc vorbis comment data | ||
111 | * @param label label marking the desired entry | ||
112 | * @return NULL on error, otherwise the meta data | ||
113 | */ | ||
114 | static char * | ||
115 | get_comment (vorbis_comment *vc, | ||
116 | const char *label) | ||
117 | { | ||
118 | if (NULL == vc) | ||
119 | return NULL; | ||
120 | return vorbis_comment_query (vc, label, 0); | ||
121 | } | ||
122 | |||
123 | |||
124 | /** | ||
125 | * Extract meta data from vorbis using the given LE type and value. | ||
126 | * | ||
127 | * @param t LE meta data type | ||
128 | * @param s meta data to add | ||
129 | */ | ||
130 | #define ADD(t,s) do { if (0 != (ret = ec->proc (ec->cls, "ogg", t, EXTRACTOR_METAFORMAT_UTF8, "text/plain", s, strlen(s)+1))) goto FINISH; } while (0) | ||
131 | |||
132 | |||
133 | /** | ||
134 | * Extract meta data from vorbis using the given LE type and label. | ||
135 | * | ||
136 | * @param t LE meta data type | ||
137 | * @param d vorbis meta data label | ||
138 | */ | ||
139 | #define ADDG(t,d) do { m = get_comment (comments, d); if (NULL != m) ADD(t,m); } while (0) | ||
140 | |||
64 | 141 | ||
65 | /* mimetype = application/ogg */ | 142 | /** |
66 | int | 143 | * Main entry method for the 'application/ogg' extraction plugin. |
67 | EXTRACTOR_ogg_extract_method (struct EXTRACTOR_PluginList *plugin, | 144 | * |
68 | EXTRACTOR_MetaDataProcessor proc, void *proc_cls) | 145 | * @param ec extraction context provided to the plugin |
146 | */ | ||
147 | void | ||
148 | EXTRACTOR_ogg_extract_method (struct EXTRACTOR_ExtractContext *ec) | ||
69 | { | 149 | { |
150 | uint64_t fsize; | ||
151 | ov_callbacks callbacks; | ||
70 | OggVorbis_File vf; | 152 | OggVorbis_File vf; |
71 | vorbis_comment *comments; | 153 | vorbis_comment *comments; |
72 | ov_callbacks callbacks; | ||
73 | int ret; | 154 | int ret; |
74 | int64_t fsize; | ||
75 | const char *m; | 155 | const char *m; |
76 | 156 | ||
77 | fsize = pl_get_fsize (plugin); | 157 | fsize = ec->get_size (ec->cls); |
78 | if (fsize > 0 && fsize < 2 * sizeof (int)) | 158 | if (fsize < 8) |
79 | return 1; | 159 | return; |
80 | if (fsize == 0) | ||
81 | return 1; | ||
82 | 160 | ||
83 | /* TODO: rewrite pl_seek() to be STDIO-compatible (SEEK_END) and enable seeking. */ | 161 | /* TODO: rewrite pl_seek() to be STDIO-compatible (SEEK_END) and enable seeking. */ |
84 | callbacks.read_func = &readOgg; | 162 | callbacks.read_func = &read_ogg; |
85 | callbacks.seek_func = NULL; | 163 | callbacks.seek_func = &seek_ogg; |
86 | callbacks.close_func = NULL; | 164 | callbacks.close_func = NULL; |
87 | callbacks.tell_func = NULL; | 165 | callbacks.tell_func = &tell_ogg; |
88 | if (0 != ov_open_callbacks (plugin, &vf, NULL, 0, callbacks)) | 166 | if (0 != ov_open_callbacks (ec, &vf, NULL, 0, callbacks)) |
89 | { | 167 | { |
90 | ov_clear (&vf); | 168 | ov_clear (&vf); |
91 | return 1; | 169 | return; |
92 | } | 170 | } |
93 | comments = ov_comment (&vf, -1); | 171 | comments = ov_comment (&vf, -1); |
94 | if (NULL == comments) | 172 | if (NULL == comments) |
95 | { | 173 | { |
96 | ov_clear (&vf); | 174 | ov_clear (&vf); |
97 | return 1; | 175 | return; |
98 | } | 176 | } |
99 | ret = 0; | 177 | ret = 0; |
100 | ADD (EXTRACTOR_METATYPE_MIMETYPE, "application/ogg"); | 178 | ADD (EXTRACTOR_METATYPE_MIMETYPE, "application/ogg"); |
@@ -119,5 +197,7 @@ EXTRACTOR_ogg_extract_method (struct EXTRACTOR_PluginList *plugin, | |||
119 | ADDG (EXTRACTOR_METATYPE_SONG_VERSION, "version"); | 197 | ADDG (EXTRACTOR_METATYPE_SONG_VERSION, "version"); |
120 | FINISH: | 198 | FINISH: |
121 | ov_clear (&vf); | 199 | ov_clear (&vf); |
122 | return 1; | ||
123 | } | 200 | } |
201 | |||
202 | /* end of ogg_extractor.c */ | ||
203 | |||