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