aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/old/mp3_extractor.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-08-14 23:02:49 +0000
committerChristian Grothoff <christian@grothoff.org>2012-08-14 23:02:49 +0000
commit32910e8876316e209b5cef04e37e36a92c247eed (patch)
treed15bf84871f984a10797c3105d57a9b4c3f4a80d /src/plugins/old/mp3_extractor.c
parentb63b31efdfc3abfa38e47ec708db499029191a6c (diff)
downloadlibextractor-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.c393
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
45enum
46{ MPEG_ERR = 0, MPEG_V1 = 1, MPEG_V2 = 2, MPEG_V25 = 3 };
47
48enum
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
71static 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};
89static const int freq_table[4][3] = {
90 {44100, 22050, 11025},
91 {48000, 24000, 12000},
92 {32000, 16000, 8000}
93};
94static 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};
100static const char * const mpeg_versions[3] = {
101 gettext_noop("MPEG-1"),
102 gettext_noop("MPEG-2"),
103 gettext_noop("MPEG-2.5")
104};
105static 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
118struct 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
137enum MP3State
138{
139 MP3_LOOKING_FOR_FRAME = 0,
140 MP3_READING_FRAME = 1,
141};
142
143static struct mp3_state *
144EXTRACTOR_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
166static int
167EXTRACTOR_mp3_discard_state_method (struct mp3_state *state)
168{
169 if (state != NULL)
170 {
171 free (state);
172 }
173 return 1;
174}
175
176static int
177calculate_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
217int
218EXTRACTOR_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 */