File Coverage

src/mp3.c
Criterion Covered Total %
statement 443 487 90.9
branch 288 400 72.0
condition n/a
subroutine n/a
pod n/a
total 731 887 82.4


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 82           get_mp3fileinfo(PerlIO *infile, char *file, HV *info)
25             {
26 82           mp3info *mp3 = _mp3_parse(infile, file, info);
27              
28 82           buffer_free(mp3->buf);
29 82           Safefree(mp3->buf);
30 82           Safefree(mp3->first_frame);
31 82           Safefree(mp3->xing_frame);
32 82           Safefree(mp3);
33              
34 82           return 0;
35             }
36              
37             int
38 89           get_mp3tags(PerlIO *infile, char *file, HV *info, HV *tags)
39             {
40             int ret;
41              
42 89           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 89 100         if ( _has_ape(infile, file_size, info) ) {
47 6           get_ape_metadata(infile, file, info, tags);
48             }
49              
50 89           ret = parse_id3(infile, file, info, tags, 0, file_size);
51              
52 89           return ret;
53             }
54              
55             int
56 175           _is_ape_header(char *bptr)
57             {
58 175 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 169           return 0;
66             }
67              
68             int
69 89           _has_ape(PerlIO *infile, off_t file_size, HV *info)
70             {
71             Buffer buf;
72 89           uint8_t ret = 0;
73             char *bptr;
74              
75 89 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 89           buffer_init(&buf, 136);
84 89 50         if ( !_check_buf(infile, &buf, 136, 136) ) {
85 0           goto out;
86             }
87              
88 89           bptr = buffer_ptr(&buf);
89              
90 89 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 86           bptr += 23;
97 86 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 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 85           buffer_consume(&buf, 128);
138              
139 85           bptr = buffer_ptr(&buf);
140              
141 85 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             out:
148 89           buffer_free(&buf);
149              
150 89           return ret;
151             }
152              
153             // _decode_mp3_frame, based on pcutmp3 FrameHeader.decode()
154             int
155 1656           _decode_mp3_frame(unsigned char *bptr, struct mp3frame *frame)
156             {
157             int i;
158              
159 1656           frame->header32 = GET_INT32BE(bptr);
160              
161 1656           frame->mpegID = (frame->header32 >> 19) & 3;
162 1656           frame->layerID = (frame->header32 >> 17) & 3;
163 1656           frame->crc16_used = (frame->header32 & 0x00010000) == 0;
164 1656           frame->bitrate_index = (frame->header32 >> 12) & 0xF;
165 1656           frame->samplingrate_index = (frame->header32 >> 10) & 3;
166 1656           frame->padding = (frame->header32 & 0x00000200) != 0;
167 1656           frame->private_bit_set = (frame->header32 & 0x00000100) != 0;
168 1656           frame->mode = (frame->header32 >> 6) & 3;
169 1656           frame->mode_extension = (frame->header32 >> 4) & 3;
170 1656           frame->copyrighted = (frame->header32 & 0x00000008) != 0;
171 1656           frame->original = (frame->header32 & 0x00000004) == 0; // bit set -> copy
172 1656           frame->emphasis = frame->header32 & 3;
173              
174 3312           frame->valid = (frame->mpegID != ILLEGAL_MPEG_ID)
175 1652 100         && (frame->layerID != ILLEGAL_LAYER_ID)
176 1620 100         && (frame->bitrate_index != 0)
177 1617 100         && (frame->bitrate_index != 15)
178 3308 100         && (frame->samplingrate_index != ILLEGAL_SR);
    100          
179              
180 1656 100         if (!frame->valid) {
181 74           return -1;
182             }
183              
184 1582           frame->samplerate = sample_rate_tbl[ frame->samplingrate_index ];
185              
186 1582 100         if (frame->mpegID == MPEG2_ID)
187 114           frame->samplerate >>= 1; // 16,22,48 kHz
188              
189 1582 100         if (frame->mpegID == MPEG25_ID)
190 35           frame->samplerate >>= 2; // 8,11,24 kHz
191              
192 1582 100         frame->channels = (frame->mode == MODE_MONO) ? 1 : 2;
193              
194 1582           frame->bitrate_kbps = bitrate_map[ frame->mpegID ][ frame->layerID ][ frame->bitrate_index ];
195              
196 1582 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 1577 100         frame->samples_per_frame = ((frame->mpegID == MPEG1_ID) || (frame->layerID == LAYER2_ID)) ? 1152 : 576;
    100          
205 1577           frame->bytes_per_slot = 1;
206             }
207              
208 1582           frame->frame_size = ((frame->bitrate_kbps * 125) * frame->samples_per_frame) / frame->samplerate;
209              
210 1582 100         if (frame->bytes_per_slot > 1)
211 5           frame->frame_size -= frame->frame_size % frame->bytes_per_slot;
212              
213 1582 100         if (frame->padding)
214 176           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 1582           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 54           static short _mp3_get_average_bitrate(mp3info *mp3, uint32_t offset, uint32_t audio_size)
229             {
230             struct mp3frame frame;
231 54           int frame_count = 0;
232 54           int bitrate_total = 0;
233 54           int err = 0;
234 54           int done = 0;
235 54           int wrap_skip = 0;
236 54           int prev_bitrate = 0;
237 54           bool vbr = FALSE;
238              
239             unsigned char *bptr;
240              
241 54           buffer_clear(mp3->buf);
242              
243             // Seek to offset
244 54           PerlIO_seek(mp3->infile, offset, SEEK_SET);
245              
246 113 100         while ( done < audio_size - 4 ) {
247             // Buffer size is optimized for a possible common case: 20 frames of 192kbps CBR
248 86 50         if ( !_check_buf(mp3->infile, mp3->buf, 4, MP3_BLOCK_SIZE * 3) ) {
249 0           err = -1;
250 0           goto out;
251             }
252              
253 86           done += buffer_len(mp3->buf);
254              
255 86 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 1347 100         while ( buffer_len(mp3->buf) >= 4 ) {
263 1288           bptr = buffer_ptr(mp3->buf);
264 1412 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 1287 50         if ( !_decode_mp3_frame( buffer_ptr(mp3->buf), &frame ) ) {
276             // Found a valid frame
277 1287           frame_count++;
278 1287           bitrate_total += frame.bitrate_kbps;
279              
280 1287 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 699 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 686 100         if (frame_count > 20) {
290             DEBUG_TRACE("Found 20 frames with same bitrate, assuming CBR\n");
291 26           goto out;
292             }
293              
294 660           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 1261 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 1261           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             out:
317 54 50         if (err) return err;
318              
319 54 50         if (!frame_count) return -1;
320              
321             DEBUG_TRACE("Average of %d frames: %dkbps\n", frame_count, bitrate_total / frame_count);
322              
323 54           return bitrate_total / frame_count;
324             }
325              
326             static int
327 85           _parse_xing(mp3info *mp3)
328             {
329             int i;
330             unsigned char *bptr;
331 85           int xing_offset = 4;
332              
333 85 100         if (mp3->first_frame->mpegID == MPEG1_ID) {
334 70 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 85 50         if ( !_check_buf(mp3->infile, mp3->buf, 4 + xing_offset, MP3_BLOCK_SIZE) ) {
341 0           return 0;
342             }
343              
344 85           buffer_consume(mp3->buf, xing_offset);
345              
346 85           bptr = buffer_ptr(mp3->buf);
347              
348 85 100         if ( bptr[0] == 'X' || bptr[0] == 'I' ) {
    100          
349 58 100         if (
350 22 50         ( bptr[1] == 'i' && bptr[2] == 'n' && bptr[3] == 'g' )
    50          
351 7 50         ||
352 7 50         ( bptr[1] == 'n' && bptr[2] == 'f' && bptr[3] == 'o' )
    50          
353             ) {
354             DEBUG_TRACE("Found Xing/Info tag\n");
355              
356 29           mp3->xing_frame->xing_tag = bptr[0] == 'X';
357 29           mp3->xing_frame->info_tag = bptr[0] == 'I';
358 29           mp3->xing_frame->frame_size = mp3->first_frame->frame_size;
359              
360 29 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 29 100         mp3->vbr = bptr[1] == 'i' ? VBR : CBR;
366              
367 29           buffer_consume(mp3->buf, 4);
368              
369 29           mp3->xing_frame->flags = buffer_get_int(mp3->buf);
370              
371 29 50         if (mp3->xing_frame->flags & XING_FRAMES) {
372 29           mp3->xing_frame->xing_frames = buffer_get_int(mp3->buf);
373             }
374              
375 29 50         if ( mp3->xing_frame->flags & XING_BYTES) {
376 29           mp3->xing_frame->xing_bytes = buffer_get_int(mp3->buf);
377             }
378              
379 29 50         if (mp3->xing_frame->flags & XING_TOC) {
380             uint8_t i;
381 29           bptr = buffer_ptr(mp3->buf);
382 2929 100         for (i = 0; i < 100; i++) {
383 2900           mp3->xing_frame->xing_toc[i] = bptr[i];
384             }
385              
386 29           mp3->xing_frame->has_toc = 1;
387              
388 29           buffer_consume(mp3->buf, 100);
389             }
390              
391 29 100         if (mp3->xing_frame->flags & XING_QUALITY) {
392 28           mp3->xing_frame->xing_quality = buffer_get_int(mp3->buf);
393             }
394              
395             // LAME tag
396 29           bptr = buffer_ptr(mp3->buf);
397 29 100         if ( bptr[0] == 'L' && bptr[1] == 'A' && bptr[2] == 'M' && bptr[3] == 'E' ) {
    50          
    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             case 1:
411             case 8:
412 7           mp3->vbr = CBR;
413 7           break;
414             case 2:
415             case 9:
416 3           mp3->vbr = ABR;
417 3           break;
418             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 56 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 85           return 1;
530             }
531              
532             static int
533 85           _is_mp3x_profile(mp3info *mp3)
534             {
535 85 100         if (mp3->first_frame->layerID != LAYER3_ID)
536 2           return 0;
537              
538 83 100         if (mp3->first_frame->mpegID != MPEG1_ID && mp3->first_frame->mpegID != MPEG2_ID)
    100          
539 6           return 0;
540              
541 77 100         if (mp3->first_frame->samplerate != 16000
542 75 100         && mp3->first_frame->samplerate != 22050
543 71 100         && mp3->first_frame->samplerate != 24000)
544 69           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 77           _is_mp3_profile(mp3info *mp3)
554             {
555 77 100         if (mp3->first_frame->layerID != LAYER3_ID)
556 2           return 0;
557              
558 75 100         if (mp3->first_frame->mpegID != MPEG1_ID)
559 6           return 0;
560              
561 69 100         if (mp3->first_frame->samplerate != 32000
562 37 100         && mp3->first_frame->samplerate != 44100
563 1 50         && mp3->first_frame->samplerate != 48000)
564 0           return 0;
565              
566 69 50         if (mp3->bitrate >= 32 && mp3->bitrate <= 320)
    50          
567 69           return 1;
568              
569 0           return 0;
570             }
571              
572             mp3info *
573 86           _mp3_parse(PerlIO *infile, char *file, HV *info)
574             {
575             unsigned char *bptr;
576             char id3v1taghdr[4];
577              
578 86           uint32_t song_length_ms = 0;
579 86           uint64_t total_samples = 0;
580             struct mp3frame frame;
581              
582 86           bool found_first_frame = FALSE;
583              
584             mp3info *mp3;
585 86           Newz(0, mp3, sizeof(mp3info), mp3info);
586 86           Newz(0, mp3->buf, sizeof(Buffer), Buffer);
587 86           Newz(0, mp3->first_frame, sizeof(mp3frame), mp3frame);
588 86           Newz(0, mp3->xing_frame, sizeof(xingframe), xingframe);
589              
590 86           mp3->infile = infile;
591 86           mp3->file = file;
592 86           mp3->info = info;
593              
594 86           mp3->file_size = _file_size(infile);
595 86           mp3->id3_size = 0;
596 86           mp3->audio_offset = 0;
597 86           mp3->audio_size = 0;
598 86           mp3->bitrate = 0;
599              
600 86           buffer_init(mp3->buf, MP3_BLOCK_SIZE);
601              
602 86           my_hv_store( info, "file_size", newSVuv(mp3->file_size) );
603              
604 86 50         if ( !_check_buf(mp3->infile, mp3->buf, 10, MP3_BLOCK_SIZE) ) {
605 0           goto out;
606             }
607              
608 86           bptr = buffer_ptr(mp3->buf);
609              
610 86 100         if (
611 65 50         (bptr[0] == 'I' && bptr[1] == 'D' && bptr[2] == '3') &&
    50          
    50          
612 65 50         bptr[3] < 0xff && bptr[4] < 0xff &&
    50          
613 65 50         bptr[6] < 0x80 && bptr[7] < 0x80 && bptr[8] < 0x80 && bptr[9] < 0x80
    50          
    50          
614             ) {
615             /* found an ID3 header... */
616 65           mp3->id3_size = 10 + (bptr[6]<<21) + (bptr[7]<<14) + (bptr[8]<<7) + bptr[9];
617              
618 65 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 65           _mp3_skip(mp3, mp3->id3_size);
627              
628 65 50         if ( !_check_buf(mp3->infile, mp3->buf, 4, MP3_BLOCK_SIZE) ) {
629 0           goto out;
630             }
631              
632 65           mp3->audio_offset += mp3->id3_size;
633             }
634              
635             // Find an MP3 frame
636 249 100         while ( !found_first_frame && buffer_len(mp3->buf) ) {
    50          
637 164           bptr = buffer_ptr(mp3->buf);
638              
639 16170 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 163 50         if ( !_check_buf(mp3->infile, mp3->buf, 4, MP3_BLOCK_SIZE) ) {
664 0           goto out;
665             }
666              
667 163 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 109 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 109 50         && (
676 109           !_check_buf(mp3->infile, mp3->buf, frame.frame_size + 4, MP3_BLOCK_SIZE)
677 109 100         || (
678 109           !_decode_mp3_frame( (unsigned char *)buffer_ptr(mp3->buf) + frame.frame_size, &frame2 )
679 97 100         && frame.samplerate == frame2.samplerate
680 85 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 85 50         && (
687 85           !_check_buf(mp3->infile, mp3->buf, frame.frame_size + frame2.frame_size + 4, MP3_BLOCK_SIZE)
688 85 50         || (
689 85           !_decode_mp3_frame( (unsigned char *)buffer_ptr(mp3->buf) + frame.frame_size + frame2.frame_size, &frame3 )
690 85 50         && frame.samplerate == frame3.samplerate
691 85 50         && frame.channels == frame3.channels
692             )
693             )
694             ) {
695             // Found a valid frame
696             DEBUG_TRACE(" valid frame\n");
697              
698 109           found_first_frame = 1;
699             }
700             else {
701             DEBUG_TRACE(" false sync\n");
702             }
703             }
704              
705 163 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 85 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 85           mp3->audio_size = mp3->file_size - mp3->audio_offset;
720              
721 85           memcpy(mp3->first_frame, &frame, sizeof(mp3frame));
722              
723             // now check for Xing/Info/VBRI/LAME headers
724 85 50         if ( !_parse_xing(mp3) ) {
725 0           goto out;
726             }
727              
728             // use LAME CBR/ABR value for bitrate if available
729 85 100         if ( (mp3->vbr == CBR || mp3->vbr == ABR) && mp3->xing_frame->lame_abr_rate ) {
    100          
    50          
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 104 100         if (!mp3->bitrate && (mp3->xing_frame->xing_frames && mp3->xing_frame->xing_bytes)) {
    100          
    50          
745 19 100         float mfs = (float)frame.samplerate / ( frame.mpegID == MPEG2_ID || frame.mpegID == MPEG25_ID ? 72000. : 144000. );
    100          
746 19           mp3->bitrate = ( mp3->xing_frame->xing_bytes / 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 66 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 85           PerlIO_seek(infile, mp3->file_size - 128, SEEK_SET);
759 85 50         if (PerlIO_read(infile, id3v1taghdr, 4) == 4) {
760 85 100         if (id3v1taghdr[0]=='T' && id3v1taghdr[1]=='A' && id3v1taghdr[2]=='G') {
    50          
    50          
761             DEBUG_TRACE("ID3v1 tag found\n");
762 13           mp3->audio_size -= 128;
763             }
764             }
765              
766             // If we don't know the bitrate from Xing/LAME/VBRI, calculate average
767 85 100         if ( !mp3->bitrate ) {
768             DEBUG_TRACE("Calculating average bitrate starting from %d...\n", (int)mp3->audio_offset);
769 54           mp3->bitrate = _mp3_get_average_bitrate(mp3, mp3->audio_offset, mp3->audio_size);
770              
771 54 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 85 100         if (mp3->xing_frame->xing_frames) {
780 29           total_samples = mp3->xing_frame->xing_frames * frame.samples_per_frame;
781              
782 29 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 29           song_length_ms = (int) ((double)(total_samples * 1000.) / (double) frame.samplerate);
788             }
789 56 100         else if (mp3->xing_frame->vbri_frames) {
790 4           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 54           song_length_ms = (int) ((double)mp3->audio_size * 8. /
796 54           (double)mp3->bitrate);
797             }
798              
799 85           mp3->song_length_ms = song_length_ms;
800              
801 85           my_hv_store( info, "song_length_ms", newSVuv(song_length_ms) );
802 85           my_hv_store( info, "layer", newSVuv(frame.layerID) );
803 85           my_hv_store( info, "stereo", newSVuv(frame.channels == 2 ? 1 : 0) );
804 85           my_hv_store( info, "samples_per_frame", newSVuv(frame.samples_per_frame) );
805 85           my_hv_store( info, "padding", newSVuv(frame.padding) );
806 85           my_hv_store( info, "audio_size", newSVuv(mp3->audio_size) );
807 85           my_hv_store( info, "audio_offset", newSVuv(mp3->audio_offset) );
808 85           my_hv_store( info, "bitrate", newSVuv( mp3->bitrate * 1000 ) );
809 85           my_hv_store( info, "samplerate", newSVuv( frame.samplerate ) );
810              
811 85 100         if (mp3->xing_frame->xing_tag || mp3->xing_frame->info_tag) {
    100          
812 29 50         if (mp3->xing_frame->xing_frames) {
813 29           my_hv_store( info, "xing_frames", newSVuv(mp3->xing_frame->xing_frames) );
814             }
815              
816 29 50         if (mp3->xing_frame->xing_bytes) {
817 29           my_hv_store( info, "xing_bytes", newSVuv(mp3->xing_frame->xing_bytes) );
818             }
819              
820 29 50         if (mp3->xing_frame->has_toc) {
821             uint8_t i;
822 29           AV *xing_toc = newAV();
823              
824 2929 100         for (i = 0; i < 100; i++) {
825 2900           av_push( xing_toc, newSVuv(mp3->xing_frame->xing_toc[i]) );
826             }
827              
828 29           my_hv_store( info, "xing_toc", newRV_noinc( (SV *)xing_toc ) );
829             }
830              
831 29 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 85 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 85 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 85 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 85 100         if (_is_mp3x_profile(mp3))
897 8           my_hv_store( info, "dlna_profile", newSVpvn( "MP3X", 4 ) );
898 77 100         else if (_is_mp3_profile(mp3))
899 69           my_hv_store( info, "dlna_profile", newSVpvn( "MP3", 3 ) );
900              
901             out:
902              
903 86           return mp3;
904             }
905              
906             int
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 1           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 1           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 100         ||
1014 12 100         ( bptr[0] == 0xFF && !_decode_mp3_frame( bptr, &frame ) )
1015             ) {
1016             break;
1017             }
1018              
1019 1504           bptr++;
1020 1504           buf_size--;
1021 1504           }
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             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 65           _mp3_skip(mp3info *mp3, uint32_t size)
1048             {
1049 65 100         if ( buffer_len(mp3->buf) >= size ) {
1050 42           buffer_consume(mp3->buf, size);
1051              
1052             DEBUG_TRACE(" skipped buffer data size %d\n", size);
1053             }
1054             else {
1055 23           PerlIO_seek(mp3->infile, size - buffer_len(mp3->buf), SEEK_CUR);
1056 23           buffer_clear(mp3->buf);
1057              
1058             DEBUG_TRACE(" seeked past %d bytes to %d\n", size, (int)PerlIO_tell(mp3->infile));
1059             }
1060 65           }