diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-08-14 23:02:49 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-08-14 23:02:49 +0000 |
commit | 32910e8876316e209b5cef04e37e36a92c247eed (patch) | |
tree | d15bf84871f984a10797c3105d57a9b4c3f4a80d /src/plugins/old/mp3_extractor.c | |
parent | b63b31efdfc3abfa38e47ec708db499029191a6c (diff) | |
download | libextractor-32910e8876316e209b5cef04e37e36a92c247eed.tar.gz libextractor-32910e8876316e209b5cef04e37e36a92c247eed.zip |
moving plugins that currently do not compile to 'old' directory
Diffstat (limited to 'src/plugins/old/mp3_extractor.c')
-rw-r--r-- | src/plugins/old/mp3_extractor.c | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/src/plugins/old/mp3_extractor.c b/src/plugins/old/mp3_extractor.c new file mode 100644 index 0000000..68b0fce --- /dev/null +++ b/src/plugins/old/mp3_extractor.c | |||
@@ -0,0 +1,393 @@ | |||
1 | /* | ||
2 | This file is part of libextractor. | ||
3 | (C) 2002, 2003, 2004, 2006, 2009 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 2, 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., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | |||
20 | |||
21 | Some of this code is based on AVInfo 1.0 alpha 11 | ||
22 | (c) George Shuklin, gs]AT[shounen.ru, 2002-2004 | ||
23 | http://shounen.ru/soft/avinfo/ | ||
24 | |||
25 | */ | ||
26 | |||
27 | #define DEBUG_EXTRACT_MP3 0 | ||
28 | |||
29 | #include "platform.h" | ||
30 | #include "extractor.h" | ||
31 | #include "convert.h" | ||
32 | #include <string.h> | ||
33 | #include <stdio.h> | ||
34 | #include <sys/types.h> | ||
35 | #include <sys/stat.h> | ||
36 | #include <unistd.h> | ||
37 | #include <stdlib.h> | ||
38 | |||
39 | #include "extractor_plugins.h" | ||
40 | |||
41 | #include "le_architecture.h" | ||
42 | |||
43 | #define LARGEST_FRAME_SIZE 8065 | ||
44 | |||
45 | enum | ||
46 | { MPEG_ERR = 0, MPEG_V1 = 1, MPEG_V2 = 2, MPEG_V25 = 3 }; | ||
47 | |||
48 | enum | ||
49 | { LAYER_ERR = 0, LAYER_1 = 1, LAYER_2 = 2, LAYER_3 = 3 }; | ||
50 | |||
51 | #define MPA_SYNC_MASK ((unsigned int) 0xFFE00000) | ||
52 | #if __BYTE_ORDER == __BIG_ENDIAN | ||
53 | #define MPA_SYNC_MASK_MEM ((unsigned int) 0xFFE00000) | ||
54 | #else | ||
55 | #define MPA_SYNC_MASK_MEM ((unsigned int) 0x0000E0FF) | ||
56 | #endif | ||
57 | #define MPA_LAST_SYNC_BIT_MASK ((unsigned int) 0x00100000) | ||
58 | #define MPA_VERSION_MASK ((unsigned int) 0x00080000) | ||
59 | #define MPA_LAYER_MASK ((unsigned int) 0x3) | ||
60 | #define MPA_LAYER_SHIFT 17 | ||
61 | #define MPA_BITRATE_MASK ((unsigned int) 0xF) | ||
62 | #define MPA_BITRATE_SHIFT 12 | ||
63 | #define MPA_FREQ_MASK ((unsigned int) 0x3) | ||
64 | #define MPA_FREQ_SHIFT 10 | ||
65 | #define MPA_CHMODE_MASK ((unsigned int) 0x3) | ||
66 | #define MPA_CHMODE_SHIFT 6 | ||
67 | #define MPA_PADDING_SHIFT 9 | ||
68 | #define MPA_COPYRIGHT_SHIFT 3 | ||
69 | #define MPA_ORIGINAL_SHIFT 2 | ||
70 | |||
71 | static const unsigned int bitrate_table[16][6] = { | ||
72 | {0, 0, 0, 0, 0, 0}, | ||
73 | {32, 32, 32, 32, 8, 8}, | ||
74 | {64, 48, 40, 48, 16, 16}, | ||
75 | {96, 56, 48, 56, 24, 24}, | ||
76 | {128, 64, 56, 64, 32, 32}, | ||
77 | {160, 80, 64, 80, 40, 40}, | ||
78 | {192, 96, 80, 96, 48, 48}, | ||
79 | {224, 112, 96, 112, 56, 56}, | ||
80 | {256, 128, 112, 128, 64, 64}, | ||
81 | {288, 160, 128, 144, 80, 80}, | ||
82 | {320, 192, 160, 160, 96, 96}, | ||
83 | {352, 224, 192, 176, 112, 112}, | ||
84 | {384, 256, 224, 192, 128, 128}, | ||
85 | {416, 320, 256, 224, 144, 144}, | ||
86 | {448, 384, 320, 256, 160, 160}, | ||
87 | {-1, -1, -1, -1, -1, -1} | ||
88 | }; | ||
89 | static const int freq_table[4][3] = { | ||
90 | {44100, 22050, 11025}, | ||
91 | {48000, 24000, 12000}, | ||
92 | {32000, 16000, 8000} | ||
93 | }; | ||
94 | static const char * const channel_modes[4] = { | ||
95 | gettext_noop("stereo"), | ||
96 | gettext_noop("joint stereo"), | ||
97 | gettext_noop("dual channel"), | ||
98 | gettext_noop("mono") | ||
99 | }; | ||
100 | static const char * const mpeg_versions[3] = { | ||
101 | gettext_noop("MPEG-1"), | ||
102 | gettext_noop("MPEG-2"), | ||
103 | gettext_noop("MPEG-2.5") | ||
104 | }; | ||
105 | static const char * const layer_names[3] = { | ||
106 | gettext_noop("Layer I"), | ||
107 | gettext_noop("Layer II"), | ||
108 | gettext_noop("Layer III") | ||
109 | }; | ||
110 | |||
111 | |||
112 | #define OK 0 | ||
113 | #define SYSERR 1 | ||
114 | #define INVALID_ID3 2 | ||
115 | |||
116 | #define ADDR(s,t) do { if (0 != proc (proc_cls, "mp3", t, EXTRACTOR_METAFORMAT_UTF8, "text/plain", s, strlen(s)+1)) return 1; } while (0) | ||
117 | |||
118 | struct mp3_state | ||
119 | { | ||
120 | int state; | ||
121 | |||
122 | uint32_t header; | ||
123 | int sample_rate; | ||
124 | char mpeg_ver; | ||
125 | char layer; | ||
126 | char vbr_flag; | ||
127 | int ch; | ||
128 | char copyright_flag; | ||
129 | char original_flag; | ||
130 | int avg_bps; | ||
131 | int bitrate; | ||
132 | |||
133 | int64_t number_of_frames; | ||
134 | int64_t number_of_valid_frames; | ||
135 | }; | ||
136 | |||
137 | enum MP3State | ||
138 | { | ||
139 | MP3_LOOKING_FOR_FRAME = 0, | ||
140 | MP3_READING_FRAME = 1, | ||
141 | }; | ||
142 | |||
143 | static struct mp3_state * | ||
144 | EXTRACTOR_mp3_init_state_method () | ||
145 | { | ||
146 | struct mp3_state *state; | ||
147 | state = malloc (sizeof (struct mp3_state)); | ||
148 | if (state == NULL) | ||
149 | return NULL; | ||
150 | state->header = 0; | ||
151 | state->sample_rate = 0; | ||
152 | state->number_of_frames = 0; | ||
153 | state->number_of_valid_frames = 0; | ||
154 | state->mpeg_ver = 0; | ||
155 | state->layer = 0; | ||
156 | state->vbr_flag = 0; | ||
157 | state->ch = 0; | ||
158 | state->copyright_flag = 0; | ||
159 | state->original_flag = 0; | ||
160 | state->avg_bps = 0; | ||
161 | state->bitrate = 0; | ||
162 | state->state = 0; | ||
163 | return state; | ||
164 | } | ||
165 | |||
166 | static int | ||
167 | EXTRACTOR_mp3_discard_state_method (struct mp3_state *state) | ||
168 | { | ||
169 | if (state != NULL) | ||
170 | { | ||
171 | free (state); | ||
172 | } | ||
173 | return 1; | ||
174 | } | ||
175 | |||
176 | static int | ||
177 | calculate_frame_statistics_and_maybe_report_it (struct EXTRACTOR_PluginList *plugin, | ||
178 | struct mp3_state *state, EXTRACTOR_MetaDataProcessor proc, void *proc_cls) | ||
179 | { | ||
180 | int length; | ||
181 | char format[512]; | ||
182 | |||
183 | if (((double) state->number_of_valid_frames / (double) state->number_of_frames) < 0.8 || | ||
184 | state->number_of_valid_frames <= 2) | ||
185 | /* Unlikely to be an mp3 file */ | ||
186 | return 0; | ||
187 | ADDR ("audio/mpeg", EXTRACTOR_METATYPE_MIMETYPE); | ||
188 | state->avg_bps = state->avg_bps / state->number_of_valid_frames; | ||
189 | if (state->sample_rate > 0) | ||
190 | length = 1152 * state->number_of_valid_frames / state->sample_rate; | ||
191 | else if (state->avg_bps > 0 || state->bitrate > 0) | ||
192 | length = plugin->fsize / (state->avg_bps ? state->avg_bps : state->bitrate ? state->bitrate : 1) / 125; | ||
193 | else | ||
194 | length = 0; | ||
195 | |||
196 | ADDR (mpeg_versions[state->mpeg_ver - 1], EXTRACTOR_METATYPE_FORMAT_VERSION); | ||
197 | snprintf (format, | ||
198 | sizeof (format), | ||
199 | "%s %s audio, %d kbps (%s), %d Hz, %s, %s, %s", | ||
200 | mpeg_versions[state->mpeg_ver - 1], | ||
201 | layer_names[state->layer - 1], | ||
202 | state->avg_bps, | ||
203 | state->vbr_flag ? _("VBR") : _("CBR"), | ||
204 | state->sample_rate, | ||
205 | channel_modes[state->ch], | ||
206 | state->copyright_flag ? _("copyright") : _("no copyright"), | ||
207 | state->original_flag ? _("original") : _("copy") ); | ||
208 | |||
209 | ADDR (format, EXTRACTOR_METATYPE_RESOURCE_TYPE); | ||
210 | snprintf (format, | ||
211 | sizeof (format), "%dm%02d", | ||
212 | length / 60, length % 60); | ||
213 | ADDR (format, EXTRACTOR_METATYPE_DURATION); | ||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | int | ||
218 | EXTRACTOR_mp3_extract_method (struct EXTRACTOR_PluginList *plugin, | ||
219 | EXTRACTOR_MetaDataProcessor proc, | ||
220 | void *proc_cls) | ||
221 | { | ||
222 | int64_t offset = 0; | ||
223 | int64_t round_offset; | ||
224 | int64_t read_result; | ||
225 | int64_t i; | ||
226 | unsigned char *data; | ||
227 | struct mp3_state *state; | ||
228 | |||
229 | int start_anew = 0; | ||
230 | |||
231 | char mpeg_ver = 0; | ||
232 | char layer = 0; | ||
233 | int idx_num = 0; | ||
234 | int bitrate = 0; /*used for each frame */ | ||
235 | int copyright_flag = 0; | ||
236 | int original_flag = 0; | ||
237 | int sample_rate = 0; | ||
238 | int ch = 0; | ||
239 | int frame_size; | ||
240 | |||
241 | if (plugin == NULL) | ||
242 | return 1; | ||
243 | |||
244 | state = EXTRACTOR_mp3_init_state_method (); | ||
245 | if (state == NULL) | ||
246 | return 1; | ||
247 | |||
248 | while (1) | ||
249 | { | ||
250 | switch (state->state) | ||
251 | { | ||
252 | case MP3_LOOKING_FOR_FRAME: | ||
253 | /* Look for a frame header */ | ||
254 | round_offset = offset = pl_get_pos (plugin); | ||
255 | while (1) | ||
256 | { | ||
257 | pl_seek (plugin, offset, SEEK_SET); | ||
258 | read_result = pl_read (plugin, &data, 1024*1024); | ||
259 | if (read_result < 4) | ||
260 | { | ||
261 | calculate_frame_statistics_and_maybe_report_it (plugin, state, proc, proc_cls); | ||
262 | return EXTRACTOR_mp3_discard_state_method (state); | ||
263 | } | ||
264 | for (i = 0; i + 3 < read_result; i++) | ||
265 | if (((*((uint32_t *) &data[i])) & MPA_SYNC_MASK_MEM) == MPA_SYNC_MASK_MEM) | ||
266 | break; | ||
267 | if (i + 3 >= 1024*1024) | ||
268 | offset += read_result - 3; | ||
269 | else | ||
270 | break; | ||
271 | if (offset > round_offset + 31*1024*1024) | ||
272 | { | ||
273 | if (((state->number_of_valid_frames > 2) && ((double) state->number_of_valid_frames / (double) state->number_of_frames) < 0.8)) | ||
274 | { | ||
275 | calculate_frame_statistics_and_maybe_report_it (plugin, state, proc, proc_cls); | ||
276 | } | ||
277 | return EXTRACTOR_mp3_discard_state_method (state); | ||
278 | } | ||
279 | } | ||
280 | pl_seek (plugin, offset + i, SEEK_SET); | ||
281 | if (4 != pl_read (plugin, &data, 4)) | ||
282 | { | ||
283 | calculate_frame_statistics_and_maybe_report_it (plugin, state, proc, proc_cls); | ||
284 | return EXTRACTOR_mp3_discard_state_method (state); | ||
285 | } | ||
286 | state->header = (data[0] << 24) | (data[1] << 16) | | ||
287 | (data[2] << 8) | data[3]; | ||
288 | if ((state->header & MPA_SYNC_MASK) == MPA_SYNC_MASK) | ||
289 | { | ||
290 | state->state = MP3_READING_FRAME; | ||
291 | break; | ||
292 | } | ||
293 | break; | ||
294 | case MP3_READING_FRAME: | ||
295 | state->number_of_frames += 1; | ||
296 | start_anew = 0; | ||
297 | switch (state->header & (MPA_LAST_SYNC_BIT_MASK | MPA_VERSION_MASK)) | ||
298 | { | ||
299 | case (MPA_LAST_SYNC_BIT_MASK | MPA_VERSION_MASK): | ||
300 | mpeg_ver = MPEG_V1; | ||
301 | break; | ||
302 | case (MPA_LAST_SYNC_BIT_MASK): | ||
303 | mpeg_ver = MPEG_V2; | ||
304 | break; | ||
305 | case 0: | ||
306 | mpeg_ver = MPEG_V25; | ||
307 | break; | ||
308 | case (MPA_VERSION_MASK): | ||
309 | default: | ||
310 | state->state = MP3_LOOKING_FOR_FRAME; | ||
311 | offset += 1; | ||
312 | start_anew = 1; | ||
313 | } | ||
314 | if (start_anew) | ||
315 | break; | ||
316 | switch (state->header & (MPA_LAYER_MASK << MPA_LAYER_SHIFT)) | ||
317 | { | ||
318 | case (0x1 << MPA_LAYER_SHIFT): | ||
319 | layer = LAYER_3; | ||
320 | break; | ||
321 | case (0x2 << MPA_LAYER_SHIFT): | ||
322 | layer = LAYER_2; | ||
323 | break; | ||
324 | case (0x3 << MPA_LAYER_SHIFT): | ||
325 | layer = LAYER_1; | ||
326 | break; | ||
327 | case 0x0: | ||
328 | default: | ||
329 | state->state = MP3_LOOKING_FOR_FRAME; | ||
330 | offset += 1; | ||
331 | start_anew = 1; | ||
332 | } | ||
333 | if (start_anew) | ||
334 | break; | ||
335 | if (mpeg_ver < MPEG_V25) | ||
336 | idx_num = (mpeg_ver - 1) * 3 + layer - 1; | ||
337 | else | ||
338 | idx_num = 2 + layer; | ||
339 | bitrate = 1000 * bitrate_table[(state->header >> MPA_BITRATE_SHIFT) & | ||
340 | MPA_BITRATE_MASK][idx_num]; | ||
341 | if (bitrate < 0) | ||
342 | { | ||
343 | /*error in header */ | ||
344 | state->state = MP3_LOOKING_FOR_FRAME; | ||
345 | offset += 1; | ||
346 | break; | ||
347 | } | ||
348 | sample_rate = freq_table[(state->header >> MPA_FREQ_SHIFT) & | ||
349 | MPA_FREQ_MASK][mpeg_ver - 1]; | ||
350 | if (sample_rate <= 0) | ||
351 | { | ||
352 | /*error in header */ | ||
353 | state->state = MP3_LOOKING_FOR_FRAME; | ||
354 | offset += 1; | ||
355 | break; | ||
356 | } | ||
357 | ch = ((state->header >> MPA_CHMODE_SHIFT) & MPA_CHMODE_MASK); | ||
358 | copyright_flag = (state->header >> MPA_COPYRIGHT_SHIFT) & 0x1; | ||
359 | original_flag = (state->header >> MPA_ORIGINAL_SHIFT) & 0x1; | ||
360 | if (layer == LAYER_1) | ||
361 | frame_size = (12 * bitrate / sample_rate + ((state->header >> MPA_PADDING_SHIFT) & 0x1)) * 4; | ||
362 | else | ||
363 | frame_size = 144 * bitrate / sample_rate + ((state->header >> MPA_PADDING_SHIFT) & 0x1); | ||
364 | if (frame_size < 8) | ||
365 | { | ||
366 | /*error in header */ | ||
367 | state->state = MP3_LOOKING_FOR_FRAME; | ||
368 | offset += 1; | ||
369 | break; | ||
370 | } | ||
371 | |||
372 | /* Only save data from valid frames in the state */ | ||
373 | state->avg_bps += bitrate / 1000; | ||
374 | state->sample_rate = sample_rate; | ||
375 | state->mpeg_ver = mpeg_ver; | ||
376 | state->layer = layer; | ||
377 | state->ch = ch; | ||
378 | state->copyright_flag = copyright_flag; | ||
379 | state->original_flag = original_flag; | ||
380 | state->bitrate = bitrate; | ||
381 | |||
382 | state->number_of_valid_frames += 1; | ||
383 | if (state->avg_bps / state->number_of_valid_frames != bitrate / 1000) | ||
384 | state->vbr_flag = 1; | ||
385 | pl_seek (plugin, frame_size - 4, SEEK_CUR); | ||
386 | state->state = MP3_LOOKING_FOR_FRAME; | ||
387 | break; | ||
388 | } | ||
389 | } | ||
390 | return 1; | ||
391 | } | ||
392 | |||
393 | /* end of mp3_extractor.c */ | ||