File Coverage

src/mp3.c
Criterion Covered Total %
statement 447 493 90.6
branch 290 398 72.8
condition n/a
subroutine n/a
pod n/a
total 737 891 82.7


line stmt bran cond sub pod time code
1             /*
2             * This program is free software; you can redistribute it and/or modify
3             * it under the terms of the GNU General Public License as published by
4             * the Free Software Foundation; either version 2 of the License, or
5             * (at your option) any later version.
6             *
7             * This program is distributed in the hope that it will be useful,
8             * but WITHOUT ANY WARRANTY; without even the implied warranty of
9             * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10             * GNU General Public License for more details.
11             *
12             * You should have received a copy of the GNU General Public License
13             * along with this program; if not, write to the Free Software
14             * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15             */
16              
17             /*
18             * This file is derived from mt-daap project.
19             */
20              
21             #include "mp3.h"
22              
23             int
24 88           get_mp3fileinfo(PerlIO *infile, char *file, HV *info)
25             {
26 88           mp3info *mp3 = _mp3_parse(infile, file, info);
27              
28 88           buffer_free(mp3->buf);
29 88           Safefree(mp3->buf);
30 88           Safefree(mp3->first_frame);
31 88           Safefree(mp3->xing_frame);
32 88           Safefree(mp3);
33              
34 88           return 0;
35             }
36              
37             int
38 97           get_mp3tags(PerlIO *infile, char *file, HV *info, HV *tags)
39             {
40             int ret;
41              
42 97           off_t file_size = _file_size(infile);
43              
44             // See if this file has an APE tag as fast as possible
45             // This is still a big performance hit :(
46 97 100         if ( _has_ape(infile, file_size, info) ) {
47 6           get_ape_metadata(infile, file, info, tags);
48             }
49              
50 97           ret = parse_id3(infile, file, info, tags, 0, file_size);
51              
52 97           return ret;
53             }
54              
55             int
56 191           _is_ape_header(char *bptr)
57             {
58 191 100         if ( bptr[0] == 'A' && bptr[1] == 'P' && bptr[2] == 'E'
    100          
    50          
59 6 50         && bptr[3] == 'T' && bptr[4] == 'A' && bptr[5] == 'G'
    50          
    50          
60 6 50         && bptr[6] == 'E' && bptr[7] == 'X'
    50          
61             ) {
62 6           return 1;
63             }
64              
65 185           return 0;
66             }
67              
68             int
69 97           _has_ape(PerlIO *infile, off_t file_size, HV *info)
70             {
71             Buffer buf;
72 97           uint8_t ret = 0;
73             char *bptr;
74              
75 97 50         if ( (PerlIO_seek(infile, file_size - 160, SEEK_SET)) == -1 ) {
76 0           return 0;
77             }
78              
79             DEBUG_TRACE("Seeked to %d looking for APE tag\n", (int)PerlIO_tell(infile));
80              
81             // Bug 9942, read 136 bytes so we can check at -32 bytes in case file
82             // does not have an ID3v1 tag
83 97           buffer_init(&buf, 136);
84 97 50         if ( !_check_buf(infile, &buf, 136, 136) ) {
85 0           goto out;
86             }
87              
88 97           bptr = buffer_ptr(&buf);
89              
90 97 100         if ( _is_ape_header(bptr) ) {
91             DEBUG_TRACE("APE tag found at -160 (with ID3v1)\n");
92 3           ret = 1;
93             }
94             else {
95             // Look for Lyrics tag which may possibly be between APE and ID3v1
96 94           bptr += 23;
97 94 100         if ( bptr[0] == 'L' && bptr[1] == 'Y' && bptr[2] == 'R'
    50          
    50          
98 1 50         && bptr[3] == 'I' && bptr[4] == 'C' && bptr[5] == 'S'
    50          
    50          
99 1 50         && bptr[6] == '2' && bptr[7] == '0' && bptr[8] == '0'
    50          
    50          
100             ) {
101             // read Lyrics tag size, stored as a 6-digit number (!?)
102             // http://www.id3.org/Lyrics3v2
103 1           uint32_t lyrics_size = 0;
104 1           off_t file_size = _file_size(infile);
105              
106 1           bptr -= 6;
107 1           lyrics_size = atoi(bptr);
108              
109             DEBUG_TRACE("LYRICS200 tag found (size %d), adjusting APE offset (%d)\n", lyrics_size, -(160 + lyrics_size + 15));
110              
111 1 50         if ( (PerlIO_seek(infile, file_size - (160 + lyrics_size + 15), SEEK_SET)) == -1 ) {
112 0           goto out;
113             }
114              
115             DEBUG_TRACE("Seeked before Lyrics tag to %d\n", (int)PerlIO_tell(infile));
116              
117 1           buffer_clear(&buf);
118 1 50         if ( !_check_buf(infile, &buf, 136, 136) ) {
119 0           goto out;
120             }
121              
122 1 50         if ( _is_ape_header( buffer_ptr(&buf) ) ) {
123             DEBUG_TRACE("APE tag found at %d (ID3v1 + Lyricsv2)\n", -(160 + lyrics_size + 15));
124 1           ret = 1;
125 1           goto out;
126             }
127              
128             // APE code will remove the lyrics_size from audio_size, but if no APE tag do it here
129 0 0         if (my_hv_exists(info, "audio_size")) {
130 0           int audio_size = SvIV(*(my_hv_fetch(info, "audio_size")));
131 0           my_hv_store(info, "audio_size", newSVuv(audio_size - lyrics_size - 15));
132             DEBUG_TRACE("Reduced audio_size value by Lyrics2 tag size %d\n", lyrics_size + 15);
133             }
134             }
135              
136             // APE tag without ID3v1 tag will be -32 bytes from end
137 93           buffer_consume(&buf, 128);
138              
139 93           bptr = buffer_ptr(&buf);
140              
141 93 100         if ( _is_ape_header(bptr) ) {
142             DEBUG_TRACE("APE tag found at -32 (no ID3v1)\n");
143 2           ret = 1;
144             }
145             }
146              
147 91           out:
148 97           buffer_free(&buf);
149              
150 97           return ret;
151             }
152              
153             // _decode_mp3_frame, based on pcutmp3 FrameHeader.decode()
154             int
155 1743           _decode_mp3_frame(unsigned char *bptr, struct mp3frame *frame)
156             {
157             int i;
158              
159 1743           frame->header32 = GET_INT32BE(bptr);
160              
161 1743           frame->mpegID = (frame->header32 >> 19) & 3;
162 1743           frame->layerID = (frame->header32 >> 17) & 3;
163 1743           frame->crc16_used = (frame->header32 & 0x00010000) == 0;
164 1743           frame->bitrate_index = (frame->header32 >> 12) & 0xF;
165 1743           frame->samplingrate_index = (frame->header32 >> 10) & 3;
166 1743           frame->padding = (frame->header32 & 0x00000200) != 0;
167 1743           frame->private_bit_set = (frame->header32 & 0x00000100) != 0;
168 1743           frame->mode = (frame->header32 >> 6) & 3;
169 1743           frame->mode_extension = (frame->header32 >> 4) & 3;
170 1743           frame->copyrighted = (frame->header32 & 0x00000008) != 0;
171 1743           frame->original = (frame->header32 & 0x00000004) == 0; // bit set -> copy
172 1743           frame->emphasis = frame->header32 & 3;
173              
174 3486           frame->valid = (frame->mpegID != ILLEGAL_MPEG_ID)
175 1739 100         && (frame->layerID != ILLEGAL_LAYER_ID)
176 1707 100         && (frame->bitrate_index != 0)
177 1704 100         && (frame->bitrate_index != 15)
178 3482 100         && (frame->samplingrate_index != ILLEGAL_SR);
    100          
179              
180 1743 100         if (!frame->valid) {
181 74           return -1;
182             }
183              
184 1669           frame->samplerate = sample_rate_tbl[ frame->samplingrate_index ];
185              
186 1669 100         if (frame->mpegID == MPEG2_ID)
187 114           frame->samplerate >>= 1; // 16,22,48 kHz
188              
189 1669 100         if (frame->mpegID == MPEG25_ID)
190 35           frame->samplerate >>= 2; // 8,11,24 kHz
191              
192 1669 100         frame->channels = (frame->mode == MODE_MONO) ? 1 : 2;
193              
194 1669           frame->bitrate_kbps = bitrate_map[ frame->mpegID ][ frame->layerID ][ frame->bitrate_index ];
195              
196 1669 100         if (frame->layerID == LAYER1_ID) {
197             // layer 1: always 384 samples/frame and 4byte-slots
198 5           frame->samples_per_frame = 384;
199 5           frame->bytes_per_slot = 4;
200             }
201             else {
202             // layer 2: always 1152 samples/frame
203             // layer 3: MPEG1: 1152 samples/frame, MPEG2/2.5: 576 samples/frame
204 1664 100         frame->samples_per_frame = ((frame->mpegID == MPEG1_ID) || (frame->layerID == LAYER2_ID)) ? 1152 : 576;
    100          
205 1664           frame->bytes_per_slot = 1;
206             }
207              
208 1669           frame->frame_size = ((frame->bitrate_kbps * 125) * frame->samples_per_frame) / frame->samplerate;
209              
210 1669 100         if (frame->bytes_per_slot > 1)
211 5           frame->frame_size -= frame->frame_size % frame->bytes_per_slot;
212              
213 1669 100         if (frame->padding)
214 189           frame->frame_size += frame->bytes_per_slot;
215              
216             DEBUG_TRACE("Frame @%p: size=%d, %d samples, %dkbps %d/%d\n",
217             bptr, frame->frame_size, frame->samples_per_frame,
218             frame->bitrate_kbps, frame->samplerate, frame->channels);
219              
220 1669           return 0;
221             }
222              
223             // _mp3_get_average_bitrate
224             // average bitrate by averaging all the frames in the file. This used
225             // to seek to the middle of the file and take a 32K chunk but this was
226             // found to have bugs if it seeked near invalid FF sync bytes that could
227             // be detected as a real frame
228 59           static short _mp3_get_average_bitrate(mp3info *mp3, uint32_t offset, uint32_t audio_size)
229             {
230             struct mp3frame frame;
231 59           int frame_count = 0;
232 59           int bitrate_total = 0;
233 59           int err = 0;
234 59           int done = 0;
235 59           int wrap_skip = 0;
236 59           int prev_bitrate = 0;
237 59           bool vbr = FALSE;
238              
239             unsigned char *bptr;
240              
241 59           buffer_clear(mp3->buf);
242              
243             // Seek to offset
244 59           PerlIO_seek(mp3->infile, offset, SEEK_SET);
245              
246 120 100         while ( done < audio_size - 4 ) {
247             // Buffer size is optimized for a possible common case: 20 frames of 192kbps CBR
248 91 50         if ( !_check_buf(mp3->infile, mp3->buf, 4, MP3_BLOCK_SIZE * 3) ) {
249 0           err = -1;
250 0           goto out;
251             }
252              
253 91           done += buffer_len(mp3->buf);
254              
255 91 100         if (wrap_skip) {
256             // Skip rest of frame from last buffer
257             DEBUG_TRACE("Wrapped, consuming %d bytes from previous frame\n", wrap_skip);
258 32           buffer_consume(mp3->buf, wrap_skip);
259 32           wrap_skip = 0;
260             }
261              
262 1418 100         while ( buffer_len(mp3->buf) >= 4 ) {
263 1357           bptr = buffer_ptr(mp3->buf);
264 1481 100         while ( *bptr != 0xFF ) {
265 125           buffer_consume(mp3->buf, 1);
266              
267 125 100         if ( buffer_len(mp3->buf) < 4 ) {
268             // ran out of data
269 1           goto out;
270             }
271              
272 124           bptr = buffer_ptr(mp3->buf);
273             }
274              
275 1356 50         if ( !_decode_mp3_frame( buffer_ptr(mp3->buf), &frame ) ) {
276             // Found a valid frame
277 1356           frame_count++;
278 1356           bitrate_total += frame.bitrate_kbps;
279              
280 1356 100         if ( !vbr ) {
281             // If we see the bitrate changing, we have a VBR file, and read
282             // the entire file. Otherwise, if we see 20 frames with the same
283             // bitrate, assume CBR and stop
284 768 100         if (prev_bitrate > 0 && prev_bitrate != frame.bitrate_kbps) {
    100          
285             DEBUG_TRACE("Bitrate changed, assuming file is VBR\n");
286 13           vbr = TRUE;
287             }
288             else {
289 755 100         if (frame_count > 20) {
290             DEBUG_TRACE("Found 20 frames with same bitrate, assuming CBR\n");
291 29           goto out;
292             }
293              
294 726           prev_bitrate = frame.bitrate_kbps;
295             }
296             }
297              
298             //DEBUG_TRACE(" Frame %d: %dkbps, %dkHz\n", frame_count, frame.bitrate_kbps, frame.samplerate);
299              
300 1327 100         if (frame.frame_size > buffer_len(mp3->buf)) {
301             // Partial frame in buffer
302 44           wrap_skip = frame.frame_size - buffer_len(mp3->buf);
303 44           buffer_consume(mp3->buf, buffer_len(mp3->buf));
304             }
305             else {
306 1283           buffer_consume(mp3->buf, frame.frame_size);
307             }
308             }
309             else {
310             // Not a valid frame, stray 0xFF
311 0           buffer_consume(mp3->buf, 1);
312             }
313             }
314             }
315              
316 29           out:
317 59 50         if (err) return err;
318              
319 59 50         if (!frame_count) return -1;
320              
321             DEBUG_TRACE("Average of %d frames: %dkbps\n", frame_count, bitrate_total / frame_count);
322              
323 59           return bitrate_total / frame_count;
324             }
325              
326             static int
327 91           _parse_xing(mp3info *mp3)
328             {
329             int i;
330             unsigned char *bptr;
331 91           int xing_offset = 4;
332              
333 91 100         if (mp3->first_frame->mpegID == MPEG1_ID) {
334 76 100         xing_offset += mp3->first_frame->channels == 2 ? 32 : 17;
335             }
336             else {
337 15 100         xing_offset += mp3->first_frame->channels == 2 ? 17 : 9;
338             }
339              
340 91 50         if ( !_check_buf(mp3->infile, mp3->buf, 4 + xing_offset, MP3_BLOCK_SIZE) ) {
341 0           return 0;
342             }
343              
344 91           buffer_consume(mp3->buf, xing_offset);
345              
346 91           bptr = buffer_ptr(mp3->buf);
347              
348 91 100         if ( bptr[0] == 'X' || bptr[0] == 'I' ) {
    100          
349 30           if (
350 30 100         ( bptr[1] == 'i' && bptr[2] == 'n' && bptr[3] == 'g' )
    50          
    50          
351 8           ||
352 8 50         ( bptr[1] == 'n' && bptr[2] == 'f' && bptr[3] == 'o' )
    50          
    50          
353             ) {
354             DEBUG_TRACE("Found Xing/Info tag\n");
355              
356 30           mp3->xing_frame->xing_tag = bptr[0] == 'X';
357 30           mp3->xing_frame->info_tag = bptr[0] == 'I';
358 30           mp3->xing_frame->frame_size = mp3->first_frame->frame_size;
359              
360 30 50         if ( !_check_buf(mp3->infile, mp3->buf, 160, MP3_BLOCK_SIZE) ) {
361 0           return 0;
362             }
363              
364             // It's VBR if tag is Xing, and CBR if Info
365 30 100         mp3->vbr = bptr[1] == 'i' ? VBR : CBR;
366              
367 30           buffer_consume(mp3->buf, 4);
368              
369 30           mp3->xing_frame->flags = buffer_get_int(mp3->buf);
370              
371 30 50         if (mp3->xing_frame->flags & XING_FRAMES) {
372 30           mp3->xing_frame->xing_frames = buffer_get_int(mp3->buf);
373             }
374              
375 30 50         if ( mp3->xing_frame->flags & XING_BYTES) {
376 30           mp3->xing_frame->xing_bytes = buffer_get_int(mp3->buf);
377             }
378              
379 30 50         if (mp3->xing_frame->flags & XING_TOC) {
380             uint8_t i;
381 30           bptr = buffer_ptr(mp3->buf);
382 3030 100         for (i = 0; i < 100; i++) {
383 3000           mp3->xing_frame->xing_toc[i] = bptr[i];
384             }
385              
386 30           mp3->xing_frame->has_toc = 1;
387              
388 30           buffer_consume(mp3->buf, 100);
389             }
390              
391 30 100         if (mp3->xing_frame->flags & XING_QUALITY) {
392 29           mp3->xing_frame->xing_quality = buffer_get_int(mp3->buf);
393             }
394              
395             // LAME tag
396 30           bptr = buffer_ptr(mp3->buf);
397 30 100         if ( bptr[0] == 'L' && bptr[1] == 'A' && bptr[2] == 'M' && bptr[3] == 'E' ) {
    100          
    50          
    50          
398 19           mp3->xing_frame->lame_tag = TRUE;
399              
400 19           strncpy(mp3->xing_frame->lame_encoder_version, (char *)bptr, 9);
401 19           bptr += 9;
402              
403             // revision/vbr method byte
404 19           mp3->xing_frame->lame_tag_revision = bptr[0] >> 4;
405 19           mp3->xing_frame->lame_vbr_method = bptr[0] & 15;
406 19           buffer_consume(mp3->buf, 10);
407              
408             // Determine vbr status
409 19           switch (mp3->xing_frame->lame_vbr_method) {
410 7           case 1:
411             case 8:
412 7           mp3->vbr = CBR;
413 7           break;
414 3           case 2:
415             case 9:
416 3           mp3->vbr = ABR;
417 3           break;
418 9           default:
419 9           mp3->vbr = VBR;
420             }
421              
422 19           mp3->xing_frame->lame_lowpass = buffer_get_char(mp3->buf) * 100;
423              
424             // Skip peak
425 19           buffer_consume(mp3->buf, 4);
426              
427             // Replay Gain, code from mpg123
428 19           mp3->xing_frame->lame_replay_gain[0] = 0;
429 19           mp3->xing_frame->lame_replay_gain[1] = 0;
430              
431 57 100         for (i=0; i<2; i++) {
432             // Originator
433             unsigned char origin;
434 38           bptr = buffer_ptr(mp3->buf);
435              
436 38           origin = (bptr[0] >> 2) & 0x7;
437              
438 38 100         if (origin != 0) {
439             // Gain type
440 15           unsigned char gt = bptr[0] >> 5;
441 15 50         if (gt == 1)
442 15           gt = 0; /* radio */
443 0 0         else if (gt == 2)
444 0           gt = 1; /* audiophile */
445             else
446 0           continue;
447              
448 15           mp3->xing_frame->lame_replay_gain[gt]
449 15 50         = (( (bptr[0] & 0x4) >> 2 ) ? -0.1 : 0.1)
450 15           * ( (bptr[0] & 0x3) | bptr[1] );
451             }
452              
453 38           buffer_consume(mp3->buf, 2);
454             }
455              
456             // Skip encoding flags
457 19           buffer_consume(mp3->buf, 1);
458              
459             // ABR rate/VBR minimum
460 19           mp3->xing_frame->lame_abr_rate = buffer_get_char(mp3->buf);
461              
462             // Encoder delay/padding
463 19           bptr = buffer_ptr(mp3->buf);
464 19           mp3->xing_frame->lame_encoder_delay = ((((int)bptr[0]) << 4) | (((int)bptr[1]) >> 4));
465 19           mp3->xing_frame->lame_encoder_padding = (((((int)bptr[1]) << 8) | (((int)bptr[2]))) & 0xfff);
466             // sanity check
467 19 50         if (mp3->xing_frame->lame_encoder_delay < 0 || mp3->xing_frame->lame_encoder_delay > 3000) {
    50          
468 0           mp3->xing_frame->lame_encoder_delay = -1;
469             }
470 19 50         if (mp3->xing_frame->lame_encoder_padding < 0 || mp3->xing_frame->lame_encoder_padding > 3000) {
    50          
471 0           mp3->xing_frame->lame_encoder_padding = -1;
472             }
473 19           buffer_consume(mp3->buf, 3);
474              
475             // Misc
476 19           bptr = buffer_ptr(mp3->buf);
477 19           mp3->xing_frame->lame_noise_shaping = bptr[0] & 0x3;
478 19           mp3->xing_frame->lame_stereo_mode = (bptr[0] & 0x1C) >> 2;
479 19           mp3->xing_frame->lame_unwise = (bptr[0] & 0x20) >> 5;
480 19           mp3->xing_frame->lame_source_freq = (bptr[0] & 0xC0) >> 6;
481 19           buffer_consume(mp3->buf, 1);
482              
483             // XXX MP3 Gain, can't find a test file, current
484             // mp3gain doesn't write this data
485             /*
486             bptr = buffer_ptr(mp3->buf);
487             unsigned char sign = (bptr[0] & 0x80) >> 7;
488             mp3->xing_frame->lame_mp3gain = bptr[0] & 0x7F;
489             if (sign) {
490             mp3->xing_frame->lame_mp3gain *= -1;
491             }
492             mp3->xing_frame->lame_mp3gain_db = mp3->xing_frame->lame_mp3gain * 1.5;
493             */
494 19           buffer_consume(mp3->buf, 1);
495              
496             // Preset/Surround
497 19           bptr = buffer_ptr(mp3->buf);
498 19           mp3->xing_frame->lame_surround = (bptr[0] & 0x38) >> 3;
499 19           mp3->xing_frame->lame_preset = ((bptr[0] << 8) | bptr[1]) & 0x7ff;
500 19           buffer_consume(mp3->buf, 2);
501              
502             // Music Length
503 19           mp3->xing_frame->lame_music_length = buffer_get_int(mp3->buf);
504              
505             // Skip CRCs
506             }
507             }
508             }
509             // Check for VBRI header from Fhg encoders
510 61 100         else if ( bptr[0] == 'V' && bptr[1] == 'B' && bptr[2] == 'R' && bptr[3] == 'I' ) {
    50          
    50          
    50          
511             DEBUG_TRACE("Found VBRI tag\n");
512              
513 2           mp3->xing_frame->vbri_tag = TRUE;
514 2           mp3->vbr = VBR;
515              
516 2 50         if ( !_check_buf(mp3->infile, mp3->buf, 14, MP3_BLOCK_SIZE) ) {
517 0           return 0;
518             }
519              
520             // Skip tag and version ID
521 2           buffer_consume(mp3->buf, 6);
522              
523 2           mp3->xing_frame->vbri_delay = buffer_get_short(mp3->buf);
524 2           mp3->xing_frame->vbri_quality = buffer_get_short(mp3->buf);
525 2           mp3->xing_frame->vbri_bytes = buffer_get_int(mp3->buf);
526 2           mp3->xing_frame->vbri_frames = buffer_get_int(mp3->buf);
527             }
528              
529 91           return 1;
530             }
531              
532             static int
533 91           _is_mp3x_profile(mp3info *mp3)
534             {
535 91 100         if (mp3->first_frame->layerID != LAYER3_ID)
536 2           return 0;
537              
538 89 100         if (mp3->first_frame->mpegID != MPEG1_ID && mp3->first_frame->mpegID != MPEG2_ID)
    100          
539 6           return 0;
540              
541 83 100         if (mp3->first_frame->samplerate != 16000
542 81 100         && mp3->first_frame->samplerate != 22050
543 77 100         && mp3->first_frame->samplerate != 24000)
544 75           return 0;
545              
546 8 50         if (mp3->bitrate >= 8 && mp3->bitrate <= 320)
    50          
547 8           return 1;
548              
549 0           return 0;
550             }
551              
552             static int
553 83           _is_mp3_profile(mp3info *mp3)
554             {
555 83 100         if (mp3->first_frame->layerID != LAYER3_ID)
556 2           return 0;
557              
558 81 100         if (mp3->first_frame->mpegID != MPEG1_ID)
559 6           return 0;
560              
561 75 100         if (mp3->first_frame->samplerate != 32000
562 40 100         && mp3->first_frame->samplerate != 44100
563 1 50         && mp3->first_frame->samplerate != 48000)
564 0           return 0;
565              
566 75 50         if (mp3->bitrate >= 32 && mp3->bitrate <= 320)
    50          
567 75           return 1;
568              
569 0           return 0;
570             }
571              
572             mp3info *
573 92           _mp3_parse(PerlIO *infile, char *file, HV *info)
574             {
575             unsigned char *bptr;
576             char id3v1taghdr[4];
577              
578 92           uint32_t song_length_ms = 0;
579 92           uint64_t total_samples = 0;
580             struct mp3frame frame;
581              
582 92           bool found_first_frame = FALSE;
583              
584             mp3info *mp3;
585 92           Newz(0, mp3, sizeof(mp3info), mp3info);
586 92           Newz(0, mp3->buf, sizeof(Buffer), Buffer);
587 92           Newz(0, mp3->first_frame, sizeof(mp3frame), mp3frame);
588 92           Newz(0, mp3->xing_frame, sizeof(xingframe), xingframe);
589              
590 92           mp3->infile = infile;
591 92           mp3->file = file;
592 92           mp3->info = info;
593              
594 92           mp3->file_size = _file_size(infile);
595 92           mp3->id3_size = 0;
596 92           mp3->audio_offset = 0;
597 92           mp3->audio_size = 0;
598 92           mp3->bitrate = 0;
599              
600 92           buffer_init(mp3->buf, MP3_BLOCK_SIZE);
601              
602 92           my_hv_store( info, "file_size", newSVuv(mp3->file_size) );
603              
604 92 50         if ( !_check_buf(mp3->infile, mp3->buf, 10, MP3_BLOCK_SIZE) ) {
605 0           goto out;
606             }
607              
608 92           bptr = buffer_ptr(mp3->buf);
609              
610 92           if (
611 92 100         (bptr[0] == 'I' && bptr[1] == 'D' && bptr[2] == '3') &&
    50          
    50          
612 71 50         bptr[3] < 0xff && bptr[4] < 0xff &&
    50          
613 71 50         bptr[6] < 0x80 && bptr[7] < 0x80 && bptr[8] < 0x80 && bptr[9] < 0x80
    50          
    50          
    50          
614             ) {
615             /* found an ID3 header... */
616 71           mp3->id3_size = 10 + (bptr[6]<<21) + (bptr[7]<<14) + (bptr[8]<<7) + bptr[9];
617              
618 71 50         if (bptr[5] & 0x10) {
619             // footer present
620 0           mp3->id3_size += 10;
621             }
622              
623             DEBUG_TRACE("Found ID3v2.%d.%d tag, size %d\n", bptr[3], bptr[4], mp3->id3_size);
624              
625             // Always seek past the ID3 tags
626 71           _mp3_skip(mp3, mp3->id3_size);
627              
628 71 50         if ( !_check_buf(mp3->infile, mp3->buf, 4, MP3_BLOCK_SIZE) ) {
629 0           goto out;
630             }
631              
632 71           mp3->audio_offset += mp3->id3_size;
633             }
634              
635             // Find an MP3 frame
636 261 100         while ( !found_first_frame && buffer_len(mp3->buf) ) {
    50          
637 170           bptr = buffer_ptr(mp3->buf);
638              
639 16176 100         while ( *bptr != 0xFF ) {
640 16007           buffer_consume(mp3->buf, 1);
641              
642 16007           mp3->audio_offset++;
643              
644 16007 100         if ( !buffer_len(mp3->buf) ) {
645 3 100         if (mp3->audio_offset >= mp3->file_size - 4) {
646             // No audio frames in file
647 1           warn("Unable to find any MP3 frames in file: %s\n", file);
648 1           goto out;
649             }
650              
651 2 50         if ( !_check_buf(mp3->infile, mp3->buf, 4, MP3_BLOCK_SIZE) ) {
652 0           warn("Unable to find any MP3 frames in file: %s\n", file);
653 0           goto out;
654             }
655             }
656              
657 16006           bptr = buffer_ptr(mp3->buf);
658             }
659              
660             DEBUG_TRACE("Found FF sync at offset %d\n", (int)mp3->audio_offset);
661              
662             // Make sure we have 4 bytes
663 169 50         if ( !_check_buf(mp3->infile, mp3->buf, 4, MP3_BLOCK_SIZE) ) {
664 0           goto out;
665             }
666              
667 169 100         if ( !_decode_mp3_frame( (unsigned char *)buffer_ptr(mp3->buf), &frame ) ) {
668             struct mp3frame frame2, frame3;
669              
670             // Need the whole frame to consider it valid
671 115 50         if ( _check_buf(mp3->infile, mp3->buf, frame.frame_size, MP3_BLOCK_SIZE)
672              
673             // If we have enough data for the start of the next frame then
674             // it must also look valid and be consistent
675 115 50         && (
676 115           !_check_buf(mp3->infile, mp3->buf, frame.frame_size + 4, MP3_BLOCK_SIZE)
677 115 100         || (
678 115           !_decode_mp3_frame( (unsigned char *)buffer_ptr(mp3->buf) + frame.frame_size, &frame2 )
679 103 100         && frame.samplerate == frame2.samplerate
680 91 50         && frame.channels == frame2.channels
681             )
682             )
683              
684             // If we have enough data for the start of the over-next frame then
685             // it must also look valid and be consistent
686 91 50         && (
687 91           !_check_buf(mp3->infile, mp3->buf, frame.frame_size + frame2.frame_size + 4, MP3_BLOCK_SIZE)
688 91 50         || (
689 91           !_decode_mp3_frame( (unsigned char *)buffer_ptr(mp3->buf) + frame.frame_size + frame2.frame_size, &frame3 )
690 91 50         && frame.samplerate == frame3.samplerate
691 91 50         && frame.channels == frame3.channels
692             )
693             )
694             ) {
695             // Found a valid frame
696             DEBUG_TRACE(" valid frame\n");
697              
698 91           found_first_frame = 1;
699             }
700             else {
701             DEBUG_TRACE(" false sync\n");
702             }
703             }
704              
705 169 100         if (!found_first_frame) {
706             // Not a valid frame, stray 0xFF
707             DEBUG_TRACE(" invalid frame\n");
708              
709 78           buffer_consume(mp3->buf, 1);
710 78           mp3->audio_offset++;
711             }
712             }
713              
714 91 50         if ( !found_first_frame ) {
715 0           warn("Unable to find any MP3 frames in file (checked 4K): %s\n", file);
716 0           goto out;
717             }
718              
719 91           mp3->audio_size = mp3->file_size - mp3->audio_offset;
720              
721 91           memcpy(mp3->first_frame, &frame, sizeof(mp3frame));
722              
723             // now check for Xing/Info/VBRI/LAME headers
724 91 50         if ( !_parse_xing(mp3) ) {
725 0           goto out;
726             }
727              
728             // use LAME CBR/ABR value for bitrate if available
729 91 100         if ( (mp3->vbr == CBR || mp3->vbr == ABR) && mp3->xing_frame->lame_abr_rate ) {
    100          
    100          
730 10 100         if (mp3->xing_frame->lame_abr_rate >= 255) {
731             // ABR rate field only codes up to 255, use preset value instead
732 2 50         if (mp3->xing_frame->lame_preset <= 320) {
733 2           mp3->bitrate = mp3->xing_frame->lame_preset;
734             DEBUG_TRACE("bitrate from lame_preset: %d\n", mp3->bitrate);
735             }
736             }
737             else {
738 8           mp3->bitrate = mp3->xing_frame->lame_abr_rate;
739             DEBUG_TRACE("bitrate from lame_abr_rate: %d\n", mp3->bitrate);
740             }
741             }
742              
743             // Or if we have a Xing header, use it to determine bitrate
744 91 100         if (!mp3->bitrate && (mp3->xing_frame->xing_frames && mp3->xing_frame->xing_bytes)) {
    100          
    50          
745 20 100         float mfs = (float)frame.samplerate / ( frame.mpegID == MPEG2_ID || frame.mpegID == MPEG25_ID ? 72000. : 144000. );
    100          
746 20           mp3->bitrate = ( (float)mp3->xing_frame->xing_bytes / (float)mp3->xing_frame->xing_frames * mfs );
747             DEBUG_TRACE("bitrate from Xing header: %d\n", mp3->bitrate);
748             }
749              
750             // Or use VBRI header
751 71 100         else if (mp3->xing_frame->vbri_frames && mp3->xing_frame->vbri_bytes) {
    50          
752 2 50         float mfs = (float)frame.samplerate / ( frame.mpegID == MPEG2_ID || frame.mpegID == MPEG25_ID ? 72000. : 144000. );
    50          
753 2           mp3->bitrate = ( mp3->xing_frame->vbri_bytes / mp3->xing_frame->vbri_frames * mfs );
754             DEBUG_TRACE("bitrate from VBRI header: %d\n", mp3->bitrate);
755             }
756              
757             // check if last 128 bytes is ID3v1.0 or ID3v1.1 tag
758 91           PerlIO_seek(infile, mp3->file_size - 128, SEEK_SET);
759 91 50         if (PerlIO_read(infile, id3v1taghdr, 4) == 4) {
760 91 100         if (id3v1taghdr[0]=='T' && id3v1taghdr[1]=='A' && id3v1taghdr[2]=='G') {
    50          
    50          
761             DEBUG_TRACE("ID3v1 tag found\n");
762 14           mp3->audio_size -= 128;
763             }
764             }
765              
766             // If we don't know the bitrate from Xing/LAME/VBRI, calculate average
767 91 100         if ( !mp3->bitrate ) {
768             DEBUG_TRACE("Calculating average bitrate starting from %d...\n", (int)mp3->audio_offset);
769 59           mp3->bitrate = _mp3_get_average_bitrate(mp3, mp3->audio_offset, mp3->audio_size);
770              
771 59 50         if (mp3->bitrate <= 0) {
772             // Couldn't determine bitrate, just use
773             // the bitrate from the last frame we parsed
774             DEBUG_TRACE("Unable to determine bitrate, using bitrate of most recent frame (%d)\n", frame.bitrate_kbps);
775 0           mp3->bitrate = frame.bitrate_kbps;
776             }
777             }
778              
779 91 100         if (mp3->xing_frame->xing_frames) {
780 30           total_samples = mp3->xing_frame->xing_frames * frame.samples_per_frame;
781              
782 30 100         if (mp3->xing_frame->lame_tag) {
783             // subtract delay/padding to get accurate sample count
784 19           total_samples -= (mp3->xing_frame->lame_encoder_delay + mp3->xing_frame->lame_encoder_padding);
785             }
786              
787 30           song_length_ms = (int) ((double)(total_samples * 1000.) / (double) frame.samplerate);
788             }
789 61 100         else if (mp3->xing_frame->vbri_frames) {
790 2           song_length_ms = (int) ((double)(mp3->xing_frame->vbri_frames * frame.samples_per_frame * 1000.)/
791 2           (double) frame.samplerate);
792 2           total_samples = mp3->xing_frame->vbri_frames * frame.samples_per_frame;
793             }
794             else {
795 59           song_length_ms = (int) ((double)mp3->audio_size * 8. /
796 59           (double)mp3->bitrate);
797             }
798              
799 91           mp3->song_length_ms = song_length_ms;
800              
801 91           my_hv_store( info, "song_length_ms", newSVuv(song_length_ms) );
802 91           my_hv_store( info, "layer", newSVuv(frame.layerID) );
803 91           my_hv_store( info, "stereo", newSVuv(frame.channels == 2 ? 1 : 0) );
804 91           my_hv_store( info, "samples_per_frame", newSVuv(frame.samples_per_frame) );
805 91           my_hv_store( info, "padding", newSVuv(frame.padding) );
806 91           my_hv_store( info, "audio_size", newSVuv(mp3->audio_size) );
807 91           my_hv_store( info, "audio_offset", newSVuv(mp3->audio_offset) );
808 91           my_hv_store( info, "bitrate", newSVuv( mp3->bitrate * 1000 ) );
809 91           my_hv_store( info, "samplerate", newSVuv( frame.samplerate ) );
810              
811 91 100         if (mp3->xing_frame->xing_tag || mp3->xing_frame->info_tag) {
    100          
812 30 50         if (mp3->xing_frame->xing_frames) {
813 30           my_hv_store( info, "xing_frames", newSVuv(mp3->xing_frame->xing_frames) );
814             }
815              
816 30 50         if (mp3->xing_frame->xing_bytes) {
817 30           my_hv_store( info, "xing_bytes", newSVuv(mp3->xing_frame->xing_bytes) );
818             }
819              
820 30 50         if (mp3->xing_frame->has_toc) {
821             uint8_t i;
822 30           AV *xing_toc = newAV();
823              
824 3030 100         for (i = 0; i < 100; i++) {
825 3000           av_push( xing_toc, newSVuv(mp3->xing_frame->xing_toc[i]) );
826             }
827              
828 30           my_hv_store( info, "xing_toc", newRV_noinc( (SV *)xing_toc ) );
829             }
830              
831 30 100         if (mp3->xing_frame->xing_quality) {
832 22           my_hv_store( info, "xing_quality", newSVuv(mp3->xing_frame->xing_quality) );
833             }
834             }
835              
836 91 100         if (mp3->xing_frame->vbri_tag) {
837 2           my_hv_store( info, "vbri_delay", newSVuv(mp3->xing_frame->vbri_delay) );
838 2           my_hv_store( info, "vbri_frames", newSVuv(mp3->xing_frame->vbri_frames) );
839 2           my_hv_store( info, "vbri_bytes", newSVuv(mp3->xing_frame->vbri_bytes) );
840 2           my_hv_store( info, "vbri_quality", newSVuv(mp3->xing_frame->vbri_quality) );
841             }
842              
843 91 100         if (mp3->xing_frame->lame_tag) {
844 19           my_hv_store( info, "lame_encoder_version", newSVpvn(mp3->xing_frame->lame_encoder_version, 9) );
845 19           my_hv_store( info, "lame_tag_revision", newSViv(mp3->xing_frame->lame_tag_revision) );
846 19           my_hv_store( info, "lame_vbr_method", newSVpv( vbr_methods[mp3->xing_frame->lame_vbr_method], 0 ) );
847 19           my_hv_store( info, "lame_lowpass", newSViv(mp3->xing_frame->lame_lowpass) );
848              
849 19 100         if (mp3->xing_frame->lame_replay_gain[0]) {
850 15           my_hv_store( info, "lame_replay_gain_radio", newSVpvf( "%.1f dB", mp3->xing_frame->lame_replay_gain[0] ) );
851             }
852              
853 19 50         if (mp3->xing_frame->lame_replay_gain[1]) {
854 0           my_hv_store( info, "lame_replay_gain_audiophile", newSVpvf( "%.1f dB", mp3->xing_frame->lame_replay_gain[1] ) );
855             }
856              
857 19           my_hv_store( info, "lame_encoder_delay", newSViv(mp3->xing_frame->lame_encoder_delay) );
858 19           my_hv_store( info, "lame_encoder_padding", newSViv(mp3->xing_frame->lame_encoder_padding) );
859              
860 19           my_hv_store( info, "lame_noise_shaping", newSViv(mp3->xing_frame->lame_noise_shaping) );
861 19           my_hv_store( info, "lame_stereo_mode", newSVpv( stereo_modes[mp3->xing_frame->lame_stereo_mode], 0 ) );
862 19           my_hv_store( info, "lame_unwise_settings", newSViv(mp3->xing_frame->lame_unwise) );
863 19           my_hv_store( info, "lame_source_freq", newSVpv( source_freqs[mp3->xing_frame->lame_source_freq], 0 ) );
864              
865             // my_hv_store( info, "lame_mp3gain", newSViv(mp3->xing_frame->lame_mp3gain) );
866             // my_hv_store( info, "lame_mp3gain_db", newSVnv(mp3->xing_frame->lame_mp3gain_db) );
867              
868 19           my_hv_store( info, "lame_surround", newSVpv( surround[mp3->xing_frame->lame_surround], 0 ) );
869              
870 19 100         if (mp3->xing_frame->lame_preset < 8) {
871 1           my_hv_store( info, "lame_preset", newSVpvn( "Unknown", 7 ) );
872             }
873 18 100         else if (mp3->xing_frame->lame_preset <= 320) {
874 10           my_hv_store( info, "lame_preset", newSVpvf( "ABR %d", mp3->xing_frame->lame_preset ) );
875             }
876 8 50         else if (mp3->xing_frame->lame_preset <= 500) {
877 8           mp3->xing_frame->lame_preset /= 10;
878 8           mp3->xing_frame->lame_preset -= 41;
879 8 50         if ( presets_v[mp3->xing_frame->lame_preset] ) {
880 8           my_hv_store( info, "lame_preset", newSVpv( presets_v[mp3->xing_frame->lame_preset], 0 ) );
881             }
882             }
883 0 0         else if (mp3->xing_frame->lame_preset >= 1000 && mp3->xing_frame->lame_preset <= 1007) {
    0          
884 0           mp3->xing_frame->lame_preset -= 1000;
885 0 0         if ( presets_old[mp3->xing_frame->lame_preset] ) {
886 0           my_hv_store( info, "lame_preset", newSVpv( presets_old[mp3->xing_frame->lame_preset], 0 ) );
887             }
888             }
889             }
890              
891 91 100         if (mp3->vbr == ABR || mp3->vbr == VBR) {
    100          
892 24           my_hv_store( info, "vbr", newSViv(1) );
893             }
894              
895             // DLNA profile detection
896 91 100         if (_is_mp3x_profile(mp3))
897 8           my_hv_store( info, "dlna_profile", newSVpvn( "MP3X", 4 ) );
898 83 100         else if (_is_mp3_profile(mp3))
899 75           my_hv_store( info, "dlna_profile", newSVpvn( "MP3", 3 ) );
900              
901 8           out:
902              
903 92           return mp3;
904             }
905              
906             off_t
907 4           mp3_find_frame(PerlIO *infile, char *file, int offset)
908             {
909             Buffer mp3_buf;
910             unsigned char *bptr;
911             unsigned int buf_size;
912             struct mp3frame frame;
913 4           int frame_offset = -1;
914 4           HV *info = newHV();
915              
916 4           mp3info *mp3 = _mp3_parse(infile, file, info);
917              
918 4           buffer_init(&mp3_buf, MP3_BLOCK_SIZE);
919              
920 4 50         if (!mp3->song_length_ms)
921 0           goto out;
922              
923             // (undocumented) If offset is negative, treat it as an absolute file offset in bytes
924             // This is a bit ugly but avoids the need to write an entirely new method
925 4 100         if (offset < 0) {
926 1           frame_offset = abs(offset);
927 1 50         if (frame_offset < mp3->audio_offset) {
928             // Force offset to be at least audio_offset, so we don't end up in an ID3 tag
929 0           frame_offset = mp3->audio_offset;
930             }
931             DEBUG_TRACE("find_frame: using absolute offset value %d\n", frame_offset);
932             }
933             else {
934 3 50         if (offset >= mp3->song_length_ms) {
935 0           goto out;
936             }
937              
938             // Use Xing TOC if available
939 3 100         if ( mp3->xing_frame->has_toc ) {
940             float percent;
941             uint8_t ipercent;
942             uint16_t tva;
943             uint16_t tvb;
944             float tvx;
945              
946 1           percent = (offset * 1.0 / mp3->song_length_ms) * 100;
947 1           ipercent = (int)percent;
948              
949 1 50         if (ipercent > 99)
950 0           ipercent = 99;
951              
952             // Interpolate between 2 TOC points
953 1           tva = mp3->xing_frame->xing_toc[ipercent];
954 1 50         if (ipercent < 99) {
955 1           tvb = mp3->xing_frame->xing_toc[ipercent + 1];
956             }
957             else {
958 0           tvb = 256;
959             }
960              
961 1           tvx = tva + (tvb - tva) * (percent - ipercent);
962              
963 1           frame_offset = (int)((1.0/256.0) * tvx * mp3->xing_frame->xing_bytes);
964              
965 1           frame_offset += mp3->audio_offset;
966              
967             // Don't return offset == audio_offset, because that would be the Xing frame
968 1 50         if (frame_offset == mp3->audio_offset) {
969             DEBUG_TRACE("find_frame: frame_offset == audio_offset, skipping to next frame\n");
970 0           frame_offset += 1;
971             }
972              
973             DEBUG_TRACE("find_frame: using Xing TOC, song_length_ms: %d, percent: %f, tva: %d, tvb: %d, tvx: %f, frame offset: %d\n",
974             mp3->song_length_ms, percent, tva, tvb, tvx, frame_offset
975             );
976             }
977             else {
978             // calculate offset using bitrate
979 2           float bytes_per_ms = mp3->bitrate / 8.0;
980              
981 2           frame_offset = (int)(bytes_per_ms * offset);
982              
983 2           frame_offset += mp3->audio_offset;
984              
985             DEBUG_TRACE("find_frame: using bitrate %d, bytes_per_ms: %f, frame offset: %d\n", mp3->bitrate, bytes_per_ms, frame_offset);
986             }
987             }
988              
989             // If frame_offset is too near the end of the file we won't find a valid frame
990             // so require offset to be at least 1000 bytes from the end of the file
991             // XXX this would be more accurate if we determined max_frame_len
992 4 100         if ((mp3->file_size - frame_offset) < 1000) {
993 1           frame_offset -= 1000 - (mp3->file_size - frame_offset);
994 1 50         if (frame_offset < 0)
995 0           frame_offset = 0;
996             DEBUG_TRACE("find_frame: offset too close to end of file, adjusted to %d\n", frame_offset);
997             }
998              
999 4           PerlIO_seek(infile, frame_offset, SEEK_SET);
1000              
1001 4 50         if ( !_check_buf(infile, &mp3_buf, 4, MP3_BLOCK_SIZE) ) {
1002 0           frame_offset = -1;
1003 0           goto out;
1004             }
1005              
1006 4           bptr = (unsigned char *)buffer_ptr(&mp3_buf);
1007 4           buf_size = buffer_len(&mp3_buf);
1008              
1009             // Find 0xFF sync and verify it's a valid mp3 frame header
1010             while (1) {
1011 1508 50         if (
1012             buf_size < 4
1013 1508           ||
1014 1508 100         ( bptr[0] == 0xFF && !_decode_mp3_frame( bptr, &frame ) )
    100          
1015             ) {
1016             break;
1017             }
1018              
1019 1504           bptr++;
1020 1504           buf_size--;
1021             }
1022              
1023 4 50         if (buf_size >= 4) {
1024 4           frame_offset += buffer_len(&mp3_buf) - buf_size;
1025             DEBUG_TRACE("find_frame: frame_offset: %d\n", frame_offset);
1026             }
1027             else {
1028             // Didn't find a valid frame, probably too near the end of the file
1029             DEBUG_TRACE("find_frame: did not find a valid frame\n");
1030 0           frame_offset = -1;
1031             }
1032              
1033 4           out:
1034 4           buffer_free(&mp3_buf);
1035 4           SvREFCNT_dec(info);
1036              
1037 4           buffer_free(mp3->buf);
1038 4           Safefree(mp3->buf);
1039 4           Safefree(mp3->first_frame);
1040 4           Safefree(mp3->xing_frame);
1041 4           Safefree(mp3);
1042              
1043 4           return frame_offset;
1044             }
1045              
1046             void
1047 71           _mp3_skip(mp3info *mp3, uint32_t size)
1048             {
1049 71 100         if ( buffer_len(mp3->buf) >= size ) {
1050 47           buffer_consume(mp3->buf, size);
1051              
1052             DEBUG_TRACE(" skipped buffer data size %d\n", size);
1053             }
1054             else {
1055 24           PerlIO_seek(mp3->infile, size - buffer_len(mp3->buf), SEEK_CUR);
1056 24           buffer_clear(mp3->buf);
1057              
1058             DEBUG_TRACE(" seeked past %d bytes to %d\n", size, (int)PerlIO_tell(mp3->infile));
1059             }
1060 71           }