1 /*
2 MPEG decoder plugin for DeaDBeeF Player
3 Copyright (C) 2009-2014 Alexey Yakovenko
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17
18 2. Altered source versions must be plainly marked as such, and must not be
19 misrepresented as being the original software.
20
21 3. This notice may not be removed or altered from any source distribution.
22 */
23
24 #include <string.h>
25 #include <stdio.h>
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <limits.h>
29 #include <unistd.h>
30 #include <sys/time.h>
31 #include "../../deadbeef.h"
32 #include "mp3.h"
33 #ifdef USE_LIBMAD
34 #include "mp3_mad.h"
35 #endif
36 #ifdef USE_LIBMPG123
37 #include "mp3_mpg123.h"
38 #endif
39
40 //#define trace(...) { fprintf(stderr, __VA_ARGS__); }
41 #define trace(fmt,...)
42
43 //#define WRITE_DUMP 1
44
45 #if WRITE_DUMP
46 FILE *out;
47 #endif
48
49 #define min(x,y) ((x)<(y)?(x):(y))
50 #define max(x,y) ((x)>(y)?(x):(y))
51
52 #define likely(x) __builtin_expect((x),1)
53 #define unlikely(x) __builtin_expect((x),0)
54
55 static DB_decoder_t plugin;
56 DB_functions_t *deadbeef;
57
58 static uint32_t
extract_i32(unsigned char * buf)59 extract_i32 (unsigned char *buf)
60 {
61 uint32_t x;
62 // big endian extract
63
64 x = buf[0];
65 x <<= 8;
66 x |= buf[1];
67 x <<= 8;
68 x |= buf[2];
69 x <<= 8;
70 x |= buf[3];
71
72 return x;
73 }
74
75 // useful for parsing lame header, but unused right now
76 #if 0
77 static inline uint32_t
78 extract_i32_le (unsigned char *buf)
79 {
80 uint32_t x;
81 // little endian extract
82
83 x = buf[3];
84 x <<= 8;
85 x |= buf[2];
86 x <<= 8;
87 x |= buf[1];
88 x <<= 8;
89 x |= buf[0];
90
91 return x;
92 }
93 static inline uint16_t
94 extract_i16 (unsigned char *buf)
95 {
96 uint16_t x;
97 // big endian extract
98
99 x = buf[0];
100 x <<= 8;
101 x |= buf[1];
102 x <<= 8;
103
104 return x;
105 }
106
107 static inline float
108 extract_f32 (unsigned char *buf) {
109 float f;
110 uint32_t *x = (uint32_t *)&f;
111 *x = buf[0];
112 *x <<= 8;
113 *x |= buf[1];
114 *x <<= 8;
115 *x |= buf[2];
116 *x <<= 8;
117 *x |= buf[3];
118 return f;
119 }
120 #endif
121
122 static int
mp3_check_xing_header(buffer_t * buffer,int packetlength,int sample,int samples_per_frame,int samplerate,int64_t framepos,int64_t fsize)123 mp3_check_xing_header (buffer_t *buffer, int packetlength, int sample, int samples_per_frame, int samplerate, int64_t framepos, int64_t fsize) {
124 const char xing[] = "Xing";
125 const char info[] = "Info";
126 char magic[4];
127
128 // ignore mpeg version, and try both 17 and 32 byte offsets
129 deadbeef->fseek (buffer->file, 17, SEEK_CUR);
130
131 if (deadbeef->fread (magic, 1, 4, buffer->file) != 4) {
132 trace ("cmp3_scan_stream: EOF while checking for Xing header\n");
133 return -1; // EOF
134 }
135
136 if (strncmp (xing, magic, 4) && strncmp (info, magic, 4)) {
137 deadbeef->fseek (buffer->file, 11, SEEK_CUR);
138 if (deadbeef->fread (magic, 1, 4, buffer->file) != 4) {
139 trace ("cmp3_scan_stream: EOF while checking for Xing header\n");
140 return -1; // EOF
141 }
142 }
143
144 if (!strncmp (xing, magic, 4) || !strncmp (info, magic, 4)) {
145 trace ("xing/info frame found\n");
146 buffer->startoffset += packetlength;
147 // read flags
148 uint32_t flags;
149 uint8_t buf[4];
150 if (deadbeef->fread (buf, 1, 4, buffer->file) != 4) {
151 trace ("cmp3_scan_stream: EOF while parsing Xing header\n");
152 return -1; // EOF
153 }
154 flags = extract_i32 (buf);
155 if (flags & FRAMES_FLAG) {
156 // read number of frames
157 if (deadbeef->fread (buf, 1, 4, buffer->file) != 4) {
158 trace ("cmp3_scan_stream: EOF while parsing Xing header\n");
159 return -1; // EOF
160 }
161 uint32_t nframes = extract_i32 (buf);
162 if (sample <= 0) {
163 buffer->duration = (((uint64_t)nframes * (uint64_t)samples_per_frame) - buffer->delay - buffer->padding)/ (float)samplerate;
164 }
165 trace ("xing totalsamples: %d, nframes: %d, samples_per_frame: %d\n", nframes*samples_per_frame, nframes, samples_per_frame);
166 if (nframes <= 0 || samples_per_frame <= 0) {
167 trace ("bad xing header\n");
168 return -1;
169 }
170 buffer->totalsamples = nframes * samples_per_frame;
171 buffer->samplerate = samplerate;
172 }
173 if (flags & BYTES_FLAG) {
174 deadbeef->fseek (buffer->file, 4, SEEK_CUR);
175 }
176 if (flags & TOC_FLAG) {
177 deadbeef->fseek (buffer->file, 100, SEEK_CUR);
178 }
179 if (flags & VBR_SCALE_FLAG) {
180 deadbeef->fseek (buffer->file, 4, SEEK_CUR);
181 }
182 // lame header
183 if (deadbeef->fread (buf, 1, 4, buffer->file) != 4) {
184 trace ("cmp3_scan_stream: EOF while reading LAME header\n");
185 return -1; // EOF
186 }
187
188 deadbeef->fseek (buffer->file, 5, SEEK_CUR);
189 uint8_t rev = 0;
190 if (deadbeef->fread (&rev, 1, 1, buffer->file) != 1) {
191 trace ("cmp3_scan_stream: EOF while reading info tag revision / vbr method\n");
192 }
193 switch (rev & 0x0f) {
194 case XING_CBR ... XING_ABR2:
195 buffer->vbr = rev & 0x0f;
196 break;
197 default:
198 buffer->vbr = DETECTED_VBR;
199 break;
200 }
201 if (!memcmp (buf, "LAME", 4)) {
202 trace ("lame header found\n");
203
204 // FIXME: that can be optimized with a single read
205 // FIXME: add error handling
206 uint8_t lpf;
207 deadbeef->fread (&lpf, 1, 1, buffer->file);
208 //3 floats: replay gain
209 deadbeef->fread (buf, 1, 4, buffer->file);
210 // float rg_peaksignalamp = extract_f32 (buf);
211 deadbeef->fread (buf, 1, 2, buffer->file);
212 // uint16_t rg_radio = extract_i16 (buf);
213
214 deadbeef->fread (buf, 1, 2, buffer->file);
215 // uint16_t rg_audiophile = extract_i16 (buf);
216
217 // skip
218 deadbeef->fseek (buffer->file, 2, SEEK_CUR);
219 deadbeef->fread (buf, 1, 3, buffer->file);
220
221 buffer->delay = (((uint32_t)buf[0]) << 4) | ((((uint32_t)buf[1]) & 0xf0)>>4);
222 buffer->padding = ((((uint32_t)buf[1])&0x0f)<<8) | ((uint32_t)buf[2]);
223 // skip
224 deadbeef->fseek (buffer->file, 1, SEEK_CUR);
225 // mp3gain
226 uint8_t mp3gain;
227 deadbeef->fread (&mp3gain, 1, 1, buffer->file);
228 // lame preset nr
229 uint8_t lamepreset_bytes[2];
230 deadbeef->fread (lamepreset_bytes, 2, 1, buffer->file);
231 buffer->lamepreset = lamepreset_bytes[1] | (lamepreset_bytes[0] << 8);
232 // musiclen
233 deadbeef->fread (buf, 1, 4, buffer->file);
234 trace ("lame totalsamples: %d\n", buffer->totalsamples);
235 }
236 if (flags&FRAMES_FLAG) {
237 buffer->have_xing_header = 1;
238 buffer->startoffset = framepos+packetlength;
239 if (fsize >= 0) {
240 buffer->bitrate = (int)((fsize - buffer->startoffset - buffer->endoffset) / buffer->duration * 8);
241 }
242 }
243 }
244
245 return 0;
246 }
247
248 // sample=-1: scan entire stream, calculate precise duration
249 // sample=0: read headers/tags, calculate approximate duration
250 // sample>0: seek to the frame with the sample, update skipsamples
251 // return value: -1 on error
252 static int
cmp3_scan_stream(buffer_t * buffer,int sample)253 cmp3_scan_stream (buffer_t *buffer, int sample) {
254 trace ("cmp3_scan_stream %d (offs: %lld)\n", sample, deadbeef->ftell (buffer->file));
255
256 // {{{ prepare for scan - seek, reset averages, etc
257 int64_t initpos = deadbeef->ftell (buffer->file);
258 trace ("initpos: %d\n", initpos);
259 int packetlength = 0;
260 int nframe = 0;
261 int scansamples = 0;
262 buffer->currentsample = 0;
263 buffer->skipsamples = 0;
264 // int avg_bitrate = 0;
265 int valid_frames = 0;
266 int prev_bitrate = -1;
267 buffer->samplerate = 0;
268
269 if (sample <= 0) { // rescanning the stream, reset the xing header flag
270 buffer->have_xing_header = 0;
271 }
272 // this flag is used to make sure we only check the 1st frame for xing info
273 int checked_xing_header = buffer->have_xing_header;
274
275 int64_t fsize = deadbeef->fgetlength (buffer->file);
276
277 if (sample <= 0) {
278 buffer->totalsamples = 0;
279 }
280 if (sample <= 0 && buffer->avg_packetlength == 0) {
281 buffer->avg_packetlength = 0;
282 buffer->avg_samplerate = 0;
283 buffer->avg_samples_per_frame = 0;
284 buffer->nframes = 0;
285 trace ("setting startoffset to %d\n", initpos);
286 buffer->startoffset = initpos;
287 }
288
289 int lastframe_valid = 0;
290 int64_t offs = -1;
291 // }}}
292
293 int64_t lead_in_frame_pos = buffer->startoffset;
294 int64_t lead_in_frame_no = 0;
295
296 #define MAX_LEAD_IN_FRAMES 10
297 int64_t frame_positions[MAX_LEAD_IN_FRAMES]; // positions of nframe-9, nframe-8, nframe-7, ...
298 for (int i = 0; i < MAX_LEAD_IN_FRAMES; i++) {
299 frame_positions[i] = buffer->startoffset;
300 }
301
302 for (;;) {
303 uint32_t hdr;
304 uint8_t sync;
305 // {{{ parse frame header, sync stream
306 if (!lastframe_valid && offs >= 0) {
307 deadbeef->fseek (buffer->file, offs+1, SEEK_SET);
308 }
309 offs = deadbeef->ftell (buffer->file);
310 //uint8_t fb[4+2+2]; // 4b frame header + 2b crc + 2b sideinfo main_data_begin
311 uint8_t fb[4]; // just the header
312 if (deadbeef->fread (fb, 1, sizeof(fb), buffer->file) != sizeof(fb)) {
313 break; // eof
314 }
315
316 retry_sync:
317
318 sync = fb[0];
319 if (sync != 0xff) {
320 // trace ("[1]frame %d didn't seek to frame end\n", nframe);
321 lastframe_valid = 0;
322 memmove (fb, fb+1, 3);
323 if (deadbeef->fread (fb+3, 1, 1, buffer->file) != 1) {
324 break; // eof
325 }
326 offs++;
327 goto retry_sync; // not an mpeg frame
328 }
329 else {
330 // 2nd sync byte
331 sync = fb[1];
332 if ((sync >> 5) != 7) {
333 // trace ("[2]frame %d didn't seek to frame end\n", nframe);
334 lastframe_valid = 0;
335 memmove (fb, fb+1, 3);
336 if (deadbeef->fread (fb+3, 1, 1, buffer->file) != 1) {
337 break; // eof
338 }
339 offs++;
340 goto retry_sync; // not an mpeg frame
341 }
342 }
343 // found frame
344 hdr = (0xff<<24) | (sync << 16);
345 sync = fb[2];
346 hdr |= sync << 8;
347 sync = fb[3];
348 hdr |= sync;
349
350 // parse header
351
352 // sync bits
353 int usync = hdr & 0xffe00000;
354 if (usync != 0xffe00000) {
355 fprintf (stderr, "fatal error: mp3 header parser is broken\n");
356 }
357
358 // mpeg version
359 static const int vertbl[] = {3, -1, 2, 1}; // 3 is 2.5
360 int ver = (hdr & (3<<19)) >> 19;
361 ver = vertbl[ver];
362 if (ver < 0) {
363 trace ("frame %d bad mpeg version %d\n", nframe, (hdr & (3<<19)) >> 19);
364 lastframe_valid = 0;
365 continue; // invalid frame
366 }
367
368 // layer info
369 static const int ltbl[] = { -1, 3, 2, 1 };
370 int layer = (hdr & (3<<17)) >> 17;
371 layer = ltbl[layer];
372 if (layer < 0) {
373 trace ("frame %d bad layer %d\n", nframe, (hdr & (3<<17)) >> 17);
374 lastframe_valid = 0;
375 continue; // invalid frame
376 }
377
378 // protection bit (crc)
379 // int prot = (hdr & (1<<16)) >> 16;
380
381 // bitrate
382 static const int brtable[5][16] = {
383 { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1 },
384 { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1 },
385 { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 },
386 { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1 },
387 { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 }
388 };
389 int bitrate = (hdr & (0x0f<<12)) >> 12;
390 int idx = 0;
391 if (ver == 1) {
392 idx = layer - 1;
393 }
394 else {
395 idx = layer == 1 ? 3 : 4;
396 }
397 bitrate = brtable[idx][bitrate];
398 if (bitrate <= 0) {
399 trace ("frame %d bad bitrate %d\n", nframe, (hdr & (0x0f<<12)) >> 12);
400 lastframe_valid = 0;
401 continue; // invalid frame
402 }
403
404 // samplerate
405 static const int srtable[3][4] = {
406 {44100, 48000, 32000, -1},
407 {22050, 24000, 16000, -1},
408 {11025, 12000, 8000, -1},
409 };
410 int samplerate = (hdr & (0x03<<10))>>10;
411 samplerate = srtable[ver-1][samplerate];
412 if (samplerate < 0) {
413 trace ("frame %d bad samplerate %d\n", nframe, (hdr & (0x03<<10))>>10);
414 lastframe_valid = 0;
415 continue; // invalid frame
416 }
417
418 // padding
419 int padding = (hdr & (0x1 << 9)) >> 9;
420
421 static const int chantbl[4] = { 2, 2, 2, 1 };
422 int nchannels = (hdr & (0x3 << 6)) >> 6;
423 nchannels = chantbl[nchannels];
424
425 // check if channel/bitrate combination is valid for layer2
426 if (layer == 2) {
427 if ((bitrate <= 56 || bitrate == 80) && nchannels != 1) {
428 trace ("mp3: bad frame %d: layer %d, channels %d, bitrate %d\n", nframe, layer, nchannels, bitrate);
429 lastframe_valid = 0;
430 continue; // bad frame
431 }
432 if (bitrate >= 224 && nchannels == 1) {
433 trace ("mp3: bad frame %d: layer %d, channels %d, bitrate %d\n", nframe, layer, nchannels, bitrate);
434 lastframe_valid = 0;
435 continue; // bad frame
436 }
437 }
438 // }}}
439
440 // {{{ get side info ptr
441 // uint8_t *si = fb + 4;
442 // if (prot) {
443 // si += 2;
444 // }
445 // int data_ptr = ((uint16_t)si[1]) | (((uint16_t)si[1]&0)<<8);
446 // }}}
447
448 // {{{ calc packet length, number of samples in a frame
449 // packetlength
450 packetlength = 0;
451 bitrate *= 1000;
452 int samples_per_frame = 0;
453 if (samplerate > 0 && bitrate > 0) {
454 if (layer == 1) {
455 samples_per_frame = 384;
456 }
457 else if (layer == 2) {
458 samples_per_frame = 1152;
459 }
460 else if (layer == 3) {
461 if (ver == 1) {
462 samples_per_frame = 1152;
463 }
464 else {
465 samples_per_frame = 576;
466 }
467 }
468 packetlength = samples_per_frame / 8 * bitrate / samplerate + padding;
469 // if (sample > 0) {
470 // printf ("frame: %d, crc: %d, layer: %d, bitrate: %d, samplerate: %d, filepos: 0x%llX, dataoffs: 0x%X, size: 0x%X\n", nframe, prot, layer, bitrate, samplerate, deadbeef->ftell (buffer->file)-8, data_ptr, packetlength);
471 // }
472 }
473 else {
474 trace ("frame %d samplerate or bitrate is invalid\n", nframe);
475 lastframe_valid = 0;
476 continue;
477 }
478 // }}}
479
480 // {{{ vbr adjustement
481 if (!buffer->have_xing_header && prev_bitrate != -1 && prev_bitrate != bitrate) {
482 buffer->vbr = DETECTED_VBR;
483 }
484 prev_bitrate = bitrate;
485 // }}}
486
487 valid_frames++;
488
489 // {{{ update stream parameters, only when sample!=0 or 1st frame
490 if (sample != 0 || nframe == 0)
491 {
492 if (sample == 0 && lastframe_valid) {
493 return 0;
494 }
495 // don't get parameters from frames coming after any bad frame
496 buffer->version = ver;
497 buffer->layer = layer;
498 buffer->bitrate = bitrate;
499 buffer->samplerate = samplerate;
500 buffer->packetlength = packetlength;
501 if (nchannels > buffer->channels) {
502 buffer->channels = nchannels;
503 }
504 buffer->bitspersample = 16;
505 // trace ("frame %d mpeg v%d layer %d bitrate %d samplerate %d packetlength %d channels %d\n", nframe, ver, layer, bitrate, samplerate, packetlength, nchannels);
506 }
507 // }}}
508
509 lastframe_valid = 1;
510
511 int64_t framepos = deadbeef->ftell (buffer->file)-(int)sizeof(fb);
512
513 // allow at least 10 lead-in frames, to fill bit-reservoir
514 if (nframe - lead_in_frame_no > MAX_LEAD_IN_FRAMES) {
515 lead_in_frame_pos = frame_positions[0];
516 lead_in_frame_no++;
517 }
518 memmove (frame_positions, &frame_positions[1], sizeof (int64_t) * (MAX_LEAD_IN_FRAMES-1));
519 frame_positions[MAX_LEAD_IN_FRAMES-1] = framepos;
520
521 // {{{ detect/load xing frame, only on 1st pass
522 // try to read xing/info tag (only on initial scans)
523 if (sample <= 0 && !buffer->have_xing_header && !checked_xing_header)
524 {
525 checked_xing_header = 1;
526 mp3_check_xing_header (buffer, packetlength, sample, samples_per_frame, samplerate, framepos, fsize);
527
528 if (buffer->have_xing_header) {
529 // trust the xing header -- even if requested to scan for precise duration
530 if (sample <= 0) {
531 // parameters have been discovered from xing header, no need to continue
532 deadbeef->fseek (buffer->file, buffer->startoffset, SEEK_SET);
533 return 0;
534 }
535 else {
536 // skip to the next frame
537 deadbeef->fseek (buffer->file, framepos+packetlength, SEEK_SET);
538 continue;
539 }
540 }
541
542 if (sample == 0) {
543 if (buffer->file->vfs->is_streaming ()) {
544 // guess duration from filesize
545 int64_t sz = deadbeef->fgetlength (buffer->file) - buffer->startoffset;
546 if (sz > 0) {
547 sz -= buffer->startoffset + buffer->endoffset;
548 if (sz < 0) {
549 trace ("cmp3_scan_stream: bad file headers\n");
550 return -1;
551 }
552 }
553 if (sz < 0) {
554 // unable to determine duration
555 buffer->duration = -1;
556 buffer->totalsamples = -1;
557 if (sample == 0) {
558 trace ("check validity of the next frame...\n");
559 deadbeef->fseek (buffer->file, framepos+packetlength, SEEK_SET);
560 continue;
561 }
562 trace ("cmp3_scan_stream: unable to determine duration");
563 return 0;
564 }
565 buffer->nframes = (int)(sz / packetlength);
566 buffer->avg_packetlength = packetlength;
567 buffer->avg_samplerate = samplerate;
568 buffer->avg_samples_per_frame = samples_per_frame;
569 buffer->duration = (((uint64_t)buffer->nframes * (uint64_t)samples_per_frame) - buffer->delay - buffer->padding)/ (float)samplerate;
570 buffer->totalsamples = buffer->nframes * samples_per_frame;
571 trace ("totalsamples: %d, samplesperframe: %d, fsize=%lld\n", buffer->totalsamples, samples_per_frame, fsize);
572 // trace ("bitrate=%d, layer=%d, packetlength=%d, fsize=%d, nframes=%d, samples_per_frame=%d, samplerate=%d, duration=%f, totalsamples=%d\n", bitrate, layer, packetlength, sz, nframe, samples_per_frame, samplerate, buffer->duration, buffer->totalsamples);
573
574 deadbeef->fseek (buffer->file, framepos, SEEK_SET);
575
576 return 0;
577 }
578 else {
579 deadbeef->fseek (buffer->file, framepos, SEEK_SET);
580 }
581 }
582 else {
583 deadbeef->fseek (buffer->file, framepos+packetlength, SEEK_SET);
584 }
585 }
586 // }}}
587
588 if (sample == 0) {
589 // {{{ update averages, interrupt scan on frame #100
590 if (fsize <= 0) {
591 trace ("cmp3_scan_stream: negative file size\n");
592 return -1;
593 }
594 // calculating apx duration based on 1st 100 frames
595 buffer->avg_packetlength += packetlength;
596 buffer->avg_samplerate += samplerate;
597 buffer->avg_samples_per_frame += samples_per_frame;
598 //avg_bitrate += bitrate;
599 if (nframe >= 100) {
600 goto end_scan;
601 }
602 // }}}
603 }
604 else {
605 // seeking to particular sample, interrupt if reached
606 if (sample > 0 && scansamples + samples_per_frame >= sample) {
607 deadbeef->fseek (buffer->file, lead_in_frame_pos, SEEK_SET);
608 buffer->lead_in_frames = (int)(nframe-lead_in_frame_no);
609 buffer->currentsample = sample;
610 buffer->skipsamples = sample - scansamples;
611 trace ("scan: cursample=%d, frame: %d, skipsamples: %d, filepos: %llX, lead-in frames: %d\n", buffer->currentsample, nframe, buffer->skipsamples, deadbeef->ftell (buffer->file), buffer->lead_in_frames);
612 return 0;
613 }
614 }
615 scansamples += samples_per_frame;
616 nframe++;
617 if (packetlength > 0) {
618 deadbeef->fseek (buffer->file, packetlength-(int)sizeof(fb), SEEK_CUR);
619 }
620 }
621 end_scan:
622 if (nframe == 0) {
623 trace ("cmp3_scan_stream: couldn't find mpeg frames in file\n");
624 return -1;
625 }
626 if (sample == 0) {
627 // {{{ calculate final averages
628 buffer->avg_packetlength /= (float)valid_frames;
629 buffer->avg_samplerate /= valid_frames;
630 buffer->avg_samples_per_frame /= valid_frames;
631 // avg_bitrate /= valid_frames;
632 //trace ("valid_frames=%d, avg_bitrate=%d, avg_packetlength=%f, avg_samplerate=%d, avg_samples_per_frame=%d\n", valid_frames, avg_bitrate, buffer->avg_packetlength, buffer->avg_samplerate, buffer->avg_samples_per_frame);
633 trace ("startoffs: %lld, endoffs: %lld\n", buffer->startoffset, buffer->endoffset);
634
635 buffer->nframes = (fsize - buffer->startoffset - buffer->endoffset) / buffer->avg_packetlength;
636 if (!buffer->have_xing_header) {
637 buffer->totalsamples = buffer->nframes * buffer->avg_samples_per_frame;
638 buffer->duration = (buffer->totalsamples - buffer->delay - buffer->padding) / (float)buffer->avg_samplerate;
639 }
640 buffer->bitrate = (fsize - buffer->startoffset - buffer->endoffset) / buffer->duration * 8;
641 trace ("nframes: %d, fsize: %lld, spf: %d, smp: %d, totalsamples: %d\n", buffer->nframes, fsize, buffer->avg_samples_per_frame, buffer->avg_samplerate, buffer->totalsamples);
642 // }}}
643 return 0;
644 }
645
646 buffer->totalsamples = scansamples;
647 buffer->duration = (buffer->totalsamples - buffer->delay - buffer->padding) / (float)buffer->samplerate;
648 // printf ("nframes=%d, totalsamples=%d, samplerate=%d, dur=%f\n", nframe, scansamples, buffer->samplerate, buffer->duration);
649 return 0;
650 }
651
652 int
cmp3_seek_stream(DB_fileinfo_t * _info,int sample)653 cmp3_seek_stream (DB_fileinfo_t *_info, int sample) {
654 mp3_info_t *info = (mp3_info_t *)_info;
655 if (sample == 0) {
656 _info->readpos = 0;
657 info->buffer.currentsample = 0;
658 info->buffer.skipsamples = 0;
659 return 0;
660
661 }
662 #if WRITE_DUMP
663 if (out) {
664 fclose (out);
665 out = fopen ("out.raw", "w+b");
666 }
667 #endif
668
669 int res = cmp3_scan_stream (&info->buffer, sample);
670 return res;
671 }
672
673
674 static DB_fileinfo_t *
cmp3_open(uint32_t hints)675 cmp3_open (uint32_t hints) {
676 DB_fileinfo_t *_info = malloc (sizeof (mp3_info_t));
677 mp3_info_t *info = (mp3_info_t *)_info;
678 memset (info, 0, sizeof (mp3_info_t));
679 return _info;
680 }
681
682 void
cmp3_set_extra_properties(buffer_t * buffer,int fake)683 cmp3_set_extra_properties (buffer_t *buffer, int fake) {
684 char s[100];
685 int64_t size = deadbeef->fgetlength (buffer->file);
686 if (size >= 0) {
687 snprintf (s, sizeof (s), "%lld", size);
688 deadbeef->pl_replace_meta (buffer->it, ":FILE_SIZE", s);
689 }
690 else {
691 deadbeef->pl_replace_meta (buffer->it, ":FILE_SIZE", "∞");
692 }
693 if (buffer->bitrate > 0) {
694 snprintf (s, sizeof (s), "%d", buffer->bitrate/1000);
695 deadbeef->pl_replace_meta (buffer->it, ":BITRATE", s);
696 }
697 deadbeef->pl_replace_meta (buffer->it, ":BPS", "16");
698 snprintf (s, sizeof (s), "%d", buffer->channels);
699 deadbeef->pl_replace_meta (buffer->it, ":CHANNELS", s);
700 snprintf (s, sizeof (s), "%d", buffer->samplerate);
701 deadbeef->pl_replace_meta (buffer->it, ":SAMPLERATE", s);
702
703 // set codec profile (cbr or vbr) and mp3 vbr method (guessed, or from Xing/Info header)
704
705 char codec_profile[100];
706 snprintf (codec_profile, sizeof (codec_profile), "MP3 %s", (buffer->vbr == XING_CBR || buffer->vbr == XING_CBR2) ? "CBR" : "VBR");
707 if (buffer->vbr != XING_CBR && buffer->vbr != XING_CBR2 && (buffer->lamepreset & 0x7ff)) {
708 const static struct {
709 int v;
710 const char *name;
711 } presets[] = {
712 { 8, "ABR_8" },
713 { 320, "ABR_320" },
714 { 410, "V9" },
715 { 420, "V8" },
716 { 430, "V7" },
717 { 440, "V6" },
718 { 450, "V5" },
719 { 460, "V4" },
720 { 470, "V3" },
721 { 480, "V2" },
722 { 490, "V1" },
723 { 500, "V0" },
724 { 1000, "R3MIX" },
725 { 1001, "STANDARD" },
726 { 1002, "EXTREME" },
727 { 1003, "INSANE" },
728 { 1004, "STANDARD_FAST" },
729 { 1005, "EXTREME_FAST" },
730 { 1006, "MEDIUM" },
731 { 1007, "MEDIUM_FAST" },
732 { 0, NULL },
733 };
734
735 for (int i = 0; presets[i].name; i++) {
736 if (presets[i].v == (buffer->lamepreset&0x7ff)) {
737 size_t l = strlen (codec_profile);
738 char *preset = codec_profile + l;
739 snprintf (preset, sizeof (codec_profile) - l, " %s", presets[i].name);
740 break;
741 }
742 }
743 }
744
745 deadbeef->pl_replace_meta (buffer->it, ":CODEC_PROFILE", codec_profile);
746
747 switch (buffer->vbr) {
748 case XING_ABR:
749 deadbeef->pl_replace_meta (buffer->it, ":MP3_VBR_METHOD", "ABR");
750 break;
751 case XING_VBR1:
752 deadbeef->pl_replace_meta (buffer->it, ":MP3_VBR_METHOD", "full VBR method 1");
753 break;
754 case XING_VBR2:
755 deadbeef->pl_replace_meta (buffer->it, ":MP3_VBR_METHOD", "full VBR method 2");
756 break;
757 case XING_VBR3:
758 deadbeef->pl_replace_meta (buffer->it, ":MP3_VBR_METHOD", "full VBR method 3");
759 break;
760 case XING_VBR4:
761 deadbeef->pl_replace_meta (buffer->it, ":MP3_VBR_METHOD", "full VBR method 4");
762 break;
763 case XING_ABR2:
764 deadbeef->pl_replace_meta (buffer->it, ":MP3_VBR_METHOD", "ABR 2 pass");
765 break;
766 case DETECTED_VBR:
767 deadbeef->pl_replace_meta (buffer->it, ":MP3_VBR_METHOD", "unspecified");
768 break;
769 }
770 const char *versions[] = {"1", "2", "2.5"};
771 snprintf (s, sizeof (s), "MPEG%s layer%d", versions[buffer->version-1], buffer->layer);
772 deadbeef->pl_replace_meta (buffer->it, ":MPEG_VERSION", s);
773 deadbeef->pl_replace_meta (buffer->it, ":XING_HEADER", buffer->have_xing_header ? "Yes" : "No");
774 deadbeef->pl_replace_meta (buffer->it, fake ? "!FILETYPE" : ":FILETYPE", "MP3");
775 }
776
777 static int
cmp3_init(DB_fileinfo_t * _info,DB_playItem_t * it)778 cmp3_init (DB_fileinfo_t *_info, DB_playItem_t *it) {
779 mp3_info_t *info = (mp3_info_t *)_info;
780 #if defined(USE_LIBMAD) && defined(USE_LIBMPG123)
781 int backend = deadbeef->conf_get_int ("mp3.backend", 0);
782 switch (backend) {
783 case 0:
784 info->dec = &mpg123_api;
785 break;
786 case 1:
787 info->dec = &mad_api;
788 break;
789 default:
790 info->dec = &mpg123_api;
791 break;
792 }
793 #else
794 #if defined(USE_LIBMAD)
795 info->dec = &mad_api;
796 #else
797 info->dec = &mpg123_api;
798 #endif
799 #endif
800
801 _info->plugin = &plugin;
802 memset (&info->buffer, 0, sizeof (info->buffer));
803 deadbeef->pl_lock ();
804 info->buffer.file = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
805 deadbeef->pl_unlock ();
806 if (!info->buffer.file) {
807 return -1;
808 }
809 info->info.file = info->buffer.file;
810 deadbeef->pl_item_ref (it);
811 info->buffer.it = it;
812 info->info.readpos = 0;
813 if (!info->buffer.file->vfs->is_streaming ()) {
814 int skip = deadbeef->junk_get_leading_size (info->buffer.file);
815 if (skip > 0) {
816 trace ("mp3: skipping %d(%xH) bytes of junk\n", skip, skip);
817 deadbeef->fseek (info->buffer.file, skip, SEEK_SET);
818 }
819 int res = cmp3_scan_stream (&info->buffer, deadbeef->conf_get_int ("mp3.disable_gapless", 0) ? 0 : -1);
820 if (res < 0) {
821 trace ("mp3: cmp3_init: initial cmp3_scan_stream failed\n");
822 return -1;
823 }
824 info->buffer.delay += 529;
825 if (info->buffer.padding >= 529) {
826 info->buffer.padding -= 529;
827 }
828 if (it->endsample > 0) {
829 info->buffer.startsample = it->startsample + info->buffer.delay;
830 info->buffer.endsample = it->endsample + info->buffer.delay;
831 // that comes from cue, don't calc duration, just seek and play
832 trace ("mp3 totalsamples: %d\n", info->buffer.endsample-info->buffer.startsample+1);
833 }
834 else {
835 ddb_playlist_t *plt = deadbeef->pl_get_playlist (it);
836 deadbeef->plt_set_item_duration (plt, it, info->buffer.duration);
837 if (plt) {
838 deadbeef->plt_unref (plt);
839 }
840 info->buffer.startsample = info->buffer.delay;
841 info->buffer.endsample = info->buffer.totalsamples-info->buffer.padding-1;
842 trace ("mp3 totalsamples: %d (%d, %d, %d | %d %d)\n", info->buffer.endsample-info->buffer.startsample+1, info->buffer.totalsamples, info->buffer.delay, info->buffer.padding, info->buffer.startsample, info->buffer.endsample);
843 trace ("mp3: seeking to %d(%xH) start offset\n", info->buffer.startoffset, info->buffer.startoffset);
844 deadbeef->fseek (info->buffer.file, info->buffer.startoffset, SEEK_SET);
845 }
846 plugin.seek_sample (_info, 0);
847 trace ("mp3: startsample: %d, endsample: %d, currentsample: %d\n", info->buffer.startsample, info->buffer.endsample, info->buffer.currentsample);
848 }
849 else {
850 deadbeef->fset_track (info->buffer.file, it);
851 deadbeef->pl_add_meta (it, "title", NULL);
852 int skip = deadbeef->junk_get_leading_size (info->buffer.file);
853 if (skip > 0) {
854 trace ("mp3: skipping %d(%xH) bytes of junk\n", skip, skip);
855 deadbeef->fseek (info->buffer.file, skip, SEEK_SET);
856 }
857 int res = cmp3_scan_stream (&info->buffer, 0);
858 if (res < 0) {
859 trace ("mp3: cmp3_init: initial cmp3_scan_stream failed\n");
860 return -1;
861 }
862 deadbeef->fseek (info->buffer.file, 0, SEEK_SET);
863
864 cmp3_set_extra_properties (&info->buffer, 1);
865
866 ddb_playlist_t *plt = deadbeef->pl_get_playlist (it);
867 deadbeef->plt_set_item_duration (plt, it, info->buffer.duration);
868 if (plt) {
869 deadbeef->plt_unref (plt);
870 }
871 if (info->buffer.duration >= 0) {
872 info->buffer.endsample = info->buffer.totalsamples - 1;
873 }
874 else {
875 // info->buffer.duration = 200;
876 // info->buffer.totalsamples = 10000000;
877 // info->buffer.endsample = info->buffer.totalsamples-1;
878 info->buffer.endsample = -1;
879 info->buffer.totalsamples = -1;
880 }
881 info->buffer.skipsamples = 0;
882 info->buffer.currentsample = 0;
883 if (info->buffer.duration < 0) {
884 info->buffer.duration = -1;
885 info->buffer.totalsamples = -1;
886 info->buffer.endsample = -1;
887 }
888 trace ("duration=%f, endsample=%d, totalsamples=%d\n", info->buffer.duration, info->buffer.endsample, info->buffer.totalsamples);
889 }
890 if (info->buffer.samplerate == 0) {
891 trace ("bad mpeg file: %s\n", deadbeef->pl_find_meta (it, ":URI"));
892 return -1;
893 }
894 _info->fmt.bps = info->buffer.bitspersample;
895 _info->fmt.samplerate = info->buffer.samplerate;
896 _info->fmt.channels = info->buffer.channels;
897 _info->fmt.channelmask = _info->fmt.channels == 1 ? DDB_SPEAKER_FRONT_LEFT : (DDB_SPEAKER_FRONT_LEFT | DDB_SPEAKER_FRONT_RIGHT);
898 trace ("mp3 format: bps:%d sr:%d channels:%d\n", _info->fmt.bps, _info->fmt.samplerate, _info->fmt.channels);
899
900 info->dec->init (info);
901 return 0;
902 }
903
904 static inline void
cmp3_skip(mp3_info_t * info)905 cmp3_skip (mp3_info_t *info) {
906 if (info->buffer.skipsamples > 0) {
907 int skip = min (info->buffer.skipsamples, info->buffer.decode_remaining);
908 // printf ("skip %d / %d\n", skip, info->buffer.skipsamples);
909 info->buffer.skipsamples -= skip;
910 info->buffer.decode_remaining -= skip;
911 }
912 }
913
914 #if 0
915 static void
916 dump_buffer (buffer_t *buffer) {
917 printf ("*** DUMP ***\n");
918 printf ("remaining: %d\n", buffer->remaining);
919
920 printf ("readsize: %d\n", buffer->readsize);
921 printf ("decode_remaining: %d\n", buffer->decode_remaining);
922
923 // information, filled by cmp3_scan_stream
924 printf ("%d\n", buffer->version);
925 printf ("%d\n", buffer->layer);
926 printf ("%d\n", buffer->bitrate);
927 printf ("%d\n", buffer->samplerate);
928 printf ("%d\n", buffer->packetlength);
929 printf ("%d\n", buffer->bitspersample);
930 printf ("%d\n", buffer->channels);
931 printf ("%f\n", buffer->duration);
932
933 printf ("%d\n", buffer->currentsample);
934 printf ("%d\n", buffer->totalsamples);
935 printf ("%d\n", buffer->skipsamples);
936 printf ("%d\n", buffer->startoffset);
937 printf ("%d\n", buffer->endoffset);
938 printf ("%d\n", buffer->startsample);
939 printf ("%d\n", buffer->endsample);
940 printf ("%d\n", buffer->delay);
941 printf ("%d\n", buffer->padding);
942
943 printf ("%f\n", buffer->avg_packetlength);
944 printf ("%d\n", buffer->avg_samplerate);
945 printf ("%d\n", buffer->avg_samples_per_frame);
946 printf ("%d\n", buffer->nframes);
947 printf ("%d\n", buffer->last_comment_update);
948 printf ("%d\n", buffer->vbr);
949 printf ("%d\n", buffer->have_xing_header);
950 printf ("%d\n", buffer->current_decode_frame);
951 printf ("%lld\n", buffer->lastframe_filepos);
952
953 printf ("*** END ***\n");
954 }
955 #endif
956
957 // decoded requested number of samples to int16 format
958 static void
cmp3_decode_requested_int16(mp3_info_t * info)959 cmp3_decode_requested_int16 (mp3_info_t *info) {
960 cmp3_skip (info);
961 if (info->buffer.skipsamples > 0) {
962 return;
963 }
964 info->dec->decode (info);
965
966 assert (info->buffer.readsize >= 0);
967 }
968
969 static int
cmp3_stream_frame(mp3_info_t * info)970 cmp3_stream_frame (mp3_info_t *info) {
971 return info->dec->stream_frame (info);
972 }
973
974 static int
cmp3_decode_int16(mp3_info_t * info)975 cmp3_decode_int16 (mp3_info_t *info) {
976 int eof = 0;
977 while (!eof) {
978 eof = cmp3_stream_frame (info);
979 if (info->buffer.decode_remaining > 0) {
980 cmp3_decode_requested_int16 (info);
981 if (info->buffer.readsize == 0) {
982 return 0;
983 }
984 }
985 }
986 return 0;
987 }
988
989 static void
cmp3_free(DB_fileinfo_t * _info)990 cmp3_free (DB_fileinfo_t *_info) {
991 mp3_info_t *info = (mp3_info_t *)_info;
992 if (info->buffer.it) {
993 deadbeef->pl_item_unref (info->buffer.it);
994 }
995 if (info->buffer.file) {
996 deadbeef->fclose (info->buffer.file);
997 info->buffer.file = NULL;
998 info->info.file = NULL;
999 info->dec->free (info);
1000 }
1001 free (info);
1002 }
1003
1004 static int
cmp3_read(DB_fileinfo_t * _info,char * bytes,int size)1005 cmp3_read (DB_fileinfo_t *_info, char *bytes, int size) {
1006 #if WRITE_DUMP
1007 if (!out) {
1008 out = fopen ("out.raw", "w+b");
1009 }
1010 #endif
1011 int samplesize = _info->fmt.channels * _info->fmt.bps / 8;
1012 mp3_info_t *info = (mp3_info_t *)_info;
1013 if (info->buffer.duration >= 0 && !info->buffer.file->vfs->is_streaming ()) {
1014 int curr = info->buffer.currentsample;
1015 //printf ("curr: %d -> end %d, padding: %d\n", curr, info->buffer.endsample, info->buffer.padding);
1016 if (size / samplesize + curr > info->buffer.endsample) {
1017 size = (info->buffer.endsample - curr + 1) * samplesize;
1018 trace ("\033[0;32mmp3: size truncated to %d bytes (%d samples), cursample=%d, endsample=%d\033[37;0m\n", size, info->buffer.endsample - curr + 1, curr, info->buffer.endsample);
1019 if (size <= 0) {
1020 return 0;
1021 }
1022 }
1023 }
1024 int initsize = size;
1025 info->buffer.readsize = size;
1026 info->buffer.out = bytes;
1027 cmp3_decode_int16 (info);
1028 info->buffer.currentsample += (size - info->buffer.readsize) / samplesize;
1029 _info->readpos = (float)(info->buffer.currentsample - info->buffer.startsample) / info->buffer.samplerate;
1030 #if WRITE_DUMP
1031 if (size - info->buffer.readsize > 0) {
1032 fwrite (bytes, 1, size - info->buffer.readsize, out);
1033 }
1034 #endif
1035 // if (initsize-info->buffer.readsize != size) {
1036 // printf ("\033[0;31meof at sample %d\033[37;0m\n", info->buffer.currentsample);
1037 // }
1038 return initsize - info->buffer.readsize;
1039 }
1040
1041 static int
cmp3_seek_sample(DB_fileinfo_t * _info,int sample)1042 cmp3_seek_sample (DB_fileinfo_t *_info, int sample) {
1043 mp3_info_t *info = (mp3_info_t *)_info;
1044 if (!info->buffer.file) {
1045 return -1;
1046 }
1047
1048 // {{{ handle net streaming case
1049 if (info->buffer.file->vfs->is_streaming ()) {
1050 if (info->buffer.totalsamples > 0 && info->buffer.avg_samples_per_frame > 0 && info->buffer.avg_packetlength > 0) { // that means seekable remote stream, like podcast
1051 trace ("seeking is possible!\n");
1052
1053 int r;
1054
1055 // seek to beginning of the frame
1056 int64_t frm = sample / info->buffer.avg_samples_per_frame;
1057 r = deadbeef->fseek (info->buffer.file, frm * info->buffer.avg_packetlength + info->buffer.startoffset, SEEK_SET);
1058
1059 if (!r) {
1060 info->buffer.skipsamples = (int)(sample - frm * info->buffer.avg_samples_per_frame);
1061
1062 info->buffer.currentsample = sample;
1063 _info->readpos = (float)(info->buffer.currentsample - info->buffer.startsample) / info->buffer.samplerate;
1064
1065 info->dec->free (info);
1066 info->buffer.remaining = 0;
1067 info->buffer.decode_remaining = 0;
1068 info->dec->init (info);
1069 return 0;
1070 }
1071 trace ("seek failed!\n");
1072 return -1;
1073 }
1074 trace ("seek is impossible (avg_samples_per_frame=%d, avg_packetlength=%f)!\n", info->buffer.avg_samples_per_frame, info->buffer.avg_packetlength);
1075 return 0;
1076 }
1077 // }}}
1078
1079 sample += info->buffer.startsample;
1080 if (sample > info->buffer.endsample) {
1081 trace ("seek sample %d is beyond end of track (%d)\n", sample, info->buffer.endsample);
1082 return -1; // eof
1083 }
1084 // restart file, and load until we hit required pos
1085 deadbeef->fseek (info->buffer.file, info->buffer.startoffset, SEEK_SET);
1086
1087 info->buffer.remaining = 0;
1088 info->buffer.readsize = 0;
1089 info->buffer.decode_remaining = 0;
1090
1091 info->dec->free (info);
1092 info->dec->init (info);
1093
1094 // struct timeval tm1;
1095 // gettimeofday (&tm1, NULL);
1096 if (cmp3_seek_stream (_info, sample) == -1) {
1097 trace ("failed to seek to sample %d\n", sample);
1098 _info->readpos = 0;
1099 return -1;
1100 }
1101 // struct timeval tm2;
1102 // gettimeofday (&tm2, NULL);
1103 // int ms = (tm2.tv_sec*1000+tm2.tv_usec/1000) - (tm1.tv_sec*1000+tm1.tv_usec/1000);
1104 // printf ("cmp3_scan_stream took %d ms\n", ms);
1105 trace ("seeked to %d\n", info->buffer.currentsample);
1106 _info->readpos = (float)(info->buffer.currentsample - info->buffer.startsample) / info->buffer.samplerate;
1107 return 0;
1108 }
1109
1110 static int
cmp3_seek(DB_fileinfo_t * _info,float time)1111 cmp3_seek (DB_fileinfo_t *_info, float time) {
1112 mp3_info_t *info = (mp3_info_t *)_info;
1113 int sample = time * info->buffer.samplerate;
1114 return cmp3_seek_sample (_info, sample);
1115 }
1116
1117 static DB_playItem_t *
cmp3_insert(ddb_playlist_t * plt,DB_playItem_t * after,const char * fname)1118 cmp3_insert (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname) {
1119 trace ("cmp3_insert %s\n", fname);
1120 DB_FILE *fp = deadbeef->fopen (fname);
1121 if (!fp) {
1122 trace ("failed to open file %s\n", fname);
1123 return NULL;
1124 }
1125 if (fp->vfs->is_streaming ()) {
1126 DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
1127 deadbeef->fclose (fp);
1128 deadbeef->pl_add_meta (it, "title", NULL);
1129 deadbeef->plt_set_item_duration (plt, it, -1);
1130 after = deadbeef->plt_insert_item (plt, after, it);
1131 deadbeef->pl_item_unref (it);
1132 return after;
1133 }
1134 buffer_t buffer;
1135 memset (&buffer, 0, sizeof (buffer));
1136 buffer.file = fp;
1137 int skip = deadbeef->junk_get_leading_size (buffer.file);
1138 if (skip > 0) {
1139 trace ("mp3: skipping %d bytes (tag)\n", skip);
1140 deadbeef->fseek(buffer.file, skip, SEEK_SET);
1141 }
1142 // calc approx. mp3 duration
1143 int res = cmp3_scan_stream (&buffer, 0);
1144 if (res < 0) {
1145 trace ("mp3: cmp3_scan_stream returned error\n");
1146 deadbeef->fclose (fp);
1147 return NULL;
1148 }
1149
1150 DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, plugin.plugin.id);
1151
1152 deadbeef->rewind (fp);
1153 // reset tags
1154 uint32_t f = deadbeef->pl_get_item_flags (it);
1155 f &= ~DDB_TAG_MASK;
1156 deadbeef->pl_set_item_flags (it, f);
1157 /*int apeerr = */deadbeef->junk_apev2_read (it, fp);
1158 /*int v2err = */deadbeef->junk_id3v2_read (it, fp);
1159 /*int v1err = */deadbeef->junk_id3v1_read (it, fp);
1160 deadbeef->pl_set_meta_int (it, ":MP3_DELAY", buffer.delay);
1161 deadbeef->pl_set_meta_int (it, ":MP3_PADDING", buffer.padding);
1162
1163 buffer.it = it;
1164 cmp3_set_extra_properties (&buffer, 0);
1165
1166 deadbeef->plt_set_item_duration (plt, it, buffer.duration);
1167 deadbeef->fclose (fp);
1168
1169 deadbeef->pl_lock ();
1170 {
1171 const char *cuesheet = deadbeef->pl_find_meta (it, "cuesheet");
1172 if (cuesheet) {
1173 DB_playItem_t *last = deadbeef->plt_insert_cue_from_buffer (plt, after, it, (const uint8_t *)cuesheet, (int)strlen (cuesheet), buffer.totalsamples-buffer.delay-buffer.padding, buffer.samplerate);
1174 if (last) {
1175 deadbeef->pl_item_unref (it);
1176 deadbeef->pl_item_unref (last);
1177 deadbeef->pl_unlock ();
1178 return last;
1179 }
1180 }
1181 }
1182 deadbeef->pl_unlock ();
1183
1184
1185 // FIXME! bad numsamples passed to cue
1186 DB_playItem_t *cue_after = deadbeef->plt_insert_cue (plt, after, it, buffer.totalsamples-buffer.delay-buffer.padding, buffer.samplerate);
1187 if (cue_after) {
1188 deadbeef->pl_item_unref (it);
1189 deadbeef->pl_item_unref (cue_after);
1190 return cue_after;
1191 }
1192
1193 after = deadbeef->plt_insert_item (plt, after, it);
1194 deadbeef->pl_item_unref (it);
1195 return after;
1196 }
1197
1198 int
cmp3_read_metadata(DB_playItem_t * it)1199 cmp3_read_metadata (DB_playItem_t *it) {
1200 deadbeef->pl_lock ();
1201 DB_FILE *fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI"));
1202 deadbeef->pl_unlock ();
1203 if (!fp) {
1204 return -1;
1205 }
1206 deadbeef->pl_delete_all_meta (it);
1207 // FIXME: reload and apply the Xing header
1208 /*int apeerr = */deadbeef->junk_apev2_read (it, fp);
1209 /*int v2err = */deadbeef->junk_id3v2_read (it, fp);
1210 /*int v1err = */deadbeef->junk_id3v1_read (it, fp);
1211 deadbeef->pl_add_meta (it, "title", NULL);
1212 deadbeef->fclose (fp);
1213 return 0;
1214 }
1215
1216 int
cmp3_write_metadata(DB_playItem_t * it)1217 cmp3_write_metadata (DB_playItem_t *it) {
1218 // get options
1219
1220 int strip_id3v2 = deadbeef->conf_get_int ("mp3.strip_id3v2", 0);
1221 int strip_id3v1 = deadbeef->conf_get_int ("mp3.strip_id3v1", 0);
1222 int strip_apev2 = deadbeef->conf_get_int ("mp3.strip_apev2", 0);
1223 int write_id3v2 = deadbeef->conf_get_int ("mp3.write_id3v2", 1);
1224 int write_id3v1 = deadbeef->conf_get_int ("mp3.write_id3v1", 1);
1225 int write_apev2 = deadbeef->conf_get_int ("mp3.write_apev2", 0);
1226
1227 uint32_t junk_flags = 0;
1228 if (strip_id3v2) {
1229 junk_flags |= JUNK_STRIP_ID3V2;
1230 }
1231 if (strip_id3v1) {
1232 junk_flags |= JUNK_STRIP_ID3V1;
1233 }
1234 if (strip_apev2) {
1235 junk_flags |= JUNK_STRIP_APEV2;
1236 }
1237 if (write_id3v2) {
1238 junk_flags |= JUNK_WRITE_ID3V2;
1239 }
1240 if (write_id3v1) {
1241 junk_flags |= JUNK_WRITE_ID3V1;
1242 }
1243 if (write_apev2) {
1244 junk_flags |= JUNK_WRITE_APEV2;
1245 }
1246
1247 int id3v2_version = deadbeef->conf_get_int ("mp3.id3v2_version", 3);
1248 if (id3v2_version != 3 && id3v2_version != 4) {
1249 id3v2_version = 3;
1250 }
1251 char id3v1_encoding[50];
1252 deadbeef->conf_get_str ("mp3.id3v1_encoding", "iso8859-1", id3v1_encoding, sizeof (id3v1_encoding));
1253 return deadbeef->junk_rewrite_tags (it, junk_flags, id3v2_version, id3v1_encoding);
1254 }
1255
1256 static const char *exts[] = {
1257 "mp1", "mp2", "mp3", "mpga", NULL
1258 };
1259
1260 static const char settings_dlg[] =
1261 "property \"Disable gapless playback (faster scanning)\" checkbox mp3.disable_gapless 0;\n"
1262 #if defined(USE_LIBMAD) && defined(USE_LIBMPG123)
1263 "property \"Backend\" select[2] mp3.backend 0 mpg123 mad;\n"
1264 #endif
1265 ;
1266
1267 // define plugin interface
1268 static DB_decoder_t plugin = {
1269 .plugin.api_vmajor = 1,
1270 .plugin.api_vminor = 0,
1271 .plugin.version_major = 1,
1272 .plugin.version_minor = 0,
1273 .plugin.type = DB_PLUGIN_DECODER,
1274 .plugin.id = "stdmpg",
1275 .plugin.name = "MP3 player",
1276 .plugin.descr = "MPEG v1/2 layer1/2/3 decoder\n\n"
1277 #if defined(USE_LIBMPG123) && defined(USE_LIBMAD)
1278 "Can use libmad and libmpg123 backends.\n"
1279 "Changing the backend will take effect when the next track starts.\n"
1280 #elif defined(USE_LIBMAD)
1281 "Using libmad backend.\n"
1282 #elif defined(USE_LIBMPG123)
1283 "Using libmpg123 backend.\n"
1284 #endif
1285 ,
1286 .plugin.copyright =
1287 "MPEG decoder plugin for DeaDBeeF Player\n"
1288 "Copyright (C) 2009-2014 Alexey Yakovenko\n"
1289 "\n"
1290 "This software is provided 'as-is', without any express or implied\n"
1291 "warranty. In no event will the authors be held liable for any damages\n"
1292 "arising from the use of this software.\n"
1293 "\n"
1294 "Permission is granted to anyone to use this software for any purpose,\n"
1295 "including commercial applications, and to alter it and redistribute it\n"
1296 "freely, subject to the following restrictions:\n"
1297 "\n"
1298 "1. The origin of this software must not be misrepresented; you must not\n"
1299 " claim that you wrote the original software. If you use this software\n"
1300 " in a product, an acknowledgment in the product documentation would be\n"
1301 " appreciated but is not required.\n"
1302 "\n"
1303 "2. Altered source versions must be plainly marked as such, and must not be\n"
1304 " misrepresented as being the original software.\n"
1305 "\n"
1306 "3. This notice may not be removed or altered from any source distribution.\n"
1307 ,
1308 .plugin.website = "http://deadbeef.sf.net",
1309 .plugin.configdialog = settings_dlg,
1310 .open = cmp3_open,
1311 .init = cmp3_init,
1312 .free = cmp3_free,
1313 .read = cmp3_read,
1314 .seek = cmp3_seek,
1315 .seek_sample = cmp3_seek_sample,
1316 .insert = cmp3_insert,
1317 .read_metadata = cmp3_read_metadata,
1318 .write_metadata = cmp3_write_metadata,
1319 .exts = exts,
1320 };
1321
1322 DB_plugin_t *
mp3_load(DB_functions_t * api)1323 mp3_load (DB_functions_t *api) {
1324 deadbeef = api;
1325 return DB_PLUGIN (&plugin);
1326 }
1327