2 * Copyright 2004-2005 Timo Hirvonen
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 * Xing code copied from xmms-mad plugin.
35 struct seek_idx_entry
{
41 struct mad_stream stream
;
42 struct mad_frame frame
;
43 struct mad_synth synth
;
44 struct mad_header header
;
46 unsigned long cur_frame
;
48 unsigned char input_buffer
[INPUT_BUFFER_SIZE
];
50 unsigned int fast
: 1;
51 unsigned int has_xing
: 1;
55 unsigned int nr_frames
;
58 unsigned char toc
[100];
63 struct seek_idx_entry
*table
;
66 struct nomad_info info
;
69 struct nomad_callbacks cbs
;
72 /* ------------------------------------------------------------------------- */
74 static ssize_t
default_read(void *datasource
, void *buffer
, size_t count
)
76 int fd
= *(int *)datasource
;
78 return read(fd
, buffer
, count
);
81 static off_t
default_lseek(void *datasource
, off_t offset
, int whence
)
83 int fd
= *(int *)datasource
;
85 return lseek(fd
, offset
, whence
);
88 static int default_close(void *datasource
)
90 int fd
= *(int *)datasource
;
95 /* ------------------------------------------------------------------------- */
97 static inline int scale(mad_fixed_t sample
)
99 sample
+= 1L << (MAD_F_FRACBITS
- 16);
100 if (sample
>= MAD_F_ONE
) {
101 sample
= MAD_F_ONE
- 1;
102 } else if (sample
< -MAD_F_ONE
) {
105 return sample
>> (MAD_F_FRACBITS
- 15);
108 static inline double timer_to_seconds(mad_timer_t timer
)
112 ms
= mad_timer_count(timer
, MAD_UNITS_MILLISECONDS
);
113 return (double)ms
/ 1000.0;
117 XING_FRAMES
= 0x00000001L
,
118 XING_BYTES
= 0x00000002L
,
119 XING_TOC
= 0x00000004L
,
120 XING_SCALE
= 0x00000008L
128 * 4 frames (optional)
133 static int xing_parse(struct nomad
*nomad
)
135 struct mad_bitptr ptr
= nomad
->stream
.anc_ptr
;
136 int bitlen
= nomad
->stream
.anc_bitlen
;
141 if (mad_bit_read(&ptr
, 32) != (('X' << 24) | ('i' << 16) | ('n' << 8) | 'g'))
143 nomad
->xing
.flags
= mad_bit_read(&ptr
, 32);
145 if (nomad
->xing
.flags
& XING_FRAMES
) {
148 nomad
->xing
.nr_frames
= mad_bit_read(&ptr
, 32);
151 if (nomad
->xing
.flags
& XING_BYTES
) {
154 nomad
->xing
.bytes
= mad_bit_read(&ptr
, 32);
157 if (nomad
->xing
.flags
& XING_TOC
) {
162 for (i
= 0; i
< 100; i
++)
163 nomad
->xing
.toc
[i
] = mad_bit_read(&ptr
, 8);
166 if (nomad
->xing
.flags
& XING_SCALE
) {
169 nomad
->xing
.scale
= mad_bit_read(&ptr
, 32);
182 static int fill_buffer(struct nomad
*nomad
)
184 if (nomad
->stream
.buffer
== NULL
|| nomad
->stream
.error
== MAD_ERROR_BUFLEN
) {
185 ssize_t read_size
, remaining
, len
;
186 unsigned char *read_start
;
188 if (nomad
->stream
.next_frame
!= NULL
) {
189 remaining
= nomad
->stream
.bufend
- nomad
->stream
.next_frame
;
190 memmove(nomad
->input_buffer
, nomad
->stream
.next_frame
, remaining
);
191 read_start
= nomad
->input_buffer
+ remaining
;
192 read_size
= INPUT_BUFFER_SIZE
- remaining
;
194 read_size
= INPUT_BUFFER_SIZE
;
195 read_start
= nomad
->input_buffer
;
198 read_size
= nomad
->cbs
.read(nomad
->datasource
, read_start
, read_size
);
199 if (read_size
== -1) {
201 d_print("read error on bitstream (%d:%s)\n", errno
, strerror(errno
));
207 len
= read_size
+ remaining
;
209 nomad
->input_offset
+= read_size
;
211 if (len
< MAD_BUFFER_GUARD
) {
212 memset(nomad
->input_buffer
+ len
, 0, MAD_BUFFER_GUARD
- len
);
213 len
= MAD_BUFFER_GUARD
;
216 mad_stream_buffer(&nomad
->stream
, nomad
->input_buffer
, len
);
217 nomad
->stream
.error
= 0;
222 static void handle_lost_sync(struct nomad
*nomad
)
227 frame
= nomad
->cur_frame
;
229 /* cur_frame is not set when scanning file */
230 frame
= nomad
->info
.nr_frames
;
233 size
= id3_tag_size((const char *)nomad
->stream
.this_frame
,
234 nomad
->stream
.bufend
- nomad
->stream
.this_frame
);
236 d_print("frame %ld, skipping ID3 tag (%d bytes)\n", frame
, size
);
237 mad_stream_skip(&nomad
->stream
, size
);
239 d_print("frame %ld\n", frame
);
244 /* builds a seek index as the file is decoded
245 * should be called after every call to mad_decode_header,
246 * and before increasing nomad->timer
248 static void build_seek_index(struct nomad
*nomad
)
257 timer
= nomad
->timer
;
258 mad_timer_add(&timer
, nomad
->header
.duration
);
260 if (timer
.seconds
< (nomad
->seek_idx
.size
+ 1) * SEEK_IDX_INTERVAL
)
263 /* offset = ftell() */
264 offset
= nomad
->input_offset
;
265 /* subtract by buffer length to get offset to start of buffer */
266 offset
-= (nomad
->stream
.bufend
- nomad
->input_buffer
);
267 /* then add offset to the current frame */
268 offset
+= (nomad
->stream
.this_frame
- nomad
->input_buffer
);
270 idx
= nomad
->seek_idx
.size
;
272 nomad
->seek_idx
.table
= xrenew(struct seek_idx_entry
, nomad
->seek_idx
.table
, idx
+ 1);
273 nomad
->seek_idx
.table
[idx
].offset
= offset
;
274 nomad
->seek_idx
.table
[idx
].timer
= nomad
->timer
;
276 nomad
->seek_idx
.size
++;
282 * nomad->info.avg_bitrate and
284 * are filled only if fast = 0
286 static int scan(struct nomad
*nomad
)
288 int frame_decoded
= 0;
290 unsigned long long int bitrate_sum
= 0;
292 nomad
->info
.nr_frames
= 0;
297 rc
= fill_buffer(nomad
);
303 if (mad_header_decode(&nomad
->header
, &nomad
->stream
) == 0) {
304 bitrate_sum
+= nomad
->header
.bitrate
;
305 build_seek_index(nomad
);
306 mad_timer_add(&nomad
->timer
, nomad
->header
.duration
);
307 nomad
->info
.nr_frames
++;
308 if (!frame_decoded
) {
309 nomad
->info
.sample_rate
= nomad
->header
.samplerate
;
310 nomad
->info
.channels
= MAD_NCHANNELS(&nomad
->header
);
311 nomad
->info
.layer
= nomad
->header
.layer
;
312 nomad
->info
.dual_channel
= nomad
->header
.mode
== MAD_MODE_DUAL_CHANNEL
;
313 nomad
->info
.joint_stereo
= nomad
->header
.mode
== MAD_MODE_JOINT_STEREO
;
315 nomad
->frame
.header
= nomad
->header
;
316 if (mad_frame_decode(&nomad
->frame
, &nomad
->stream
) == -1) {
317 if (nomad
->stream
.error
== MAD_ERROR_BUFLEN
)
319 if (!MAD_RECOVERABLE(nomad
->stream
.error
)) {
320 d_print("unrecoverable frame level error.\n");
323 if (nomad
->stream
.error
== MAD_ERROR_LOSTSYNC
)
324 handle_lost_sync(nomad
);
330 #if defined(DEBUG_XING)
331 if (nomad
->has_xing
&& (nomad
->xing
.flags
& XING_FRAMES
))
332 d_print("xing: frames: %d (xing)\n", nomad
->xing
.nr_frames
);
336 nomad
->info
.avg_bitrate
= -1;
337 nomad
->info
.vbr
= -1;
338 if (nomad
->has_xing
&& (nomad
->xing
.flags
& XING_FRAMES
)) {
339 nomad
->info
.nr_frames
= nomad
->xing
.nr_frames
;
340 mad_timer_multiply(&nomad
->timer
, nomad
->info
.nr_frames
);
342 nomad
->info
.nr_frames
= nomad
->info
.filesize
/
343 (nomad
->stream
.next_frame
- nomad
->stream
.this_frame
);
344 mad_timer_multiply(&nomad
->timer
, nomad
->info
.nr_frames
);
349 if (old_bitrate
!= nomad
->header
.bitrate
)
352 old_bitrate
= nomad
->header
.bitrate
;
354 if (!MAD_RECOVERABLE(nomad
->stream
.error
) && nomad
->stream
.error
!= MAD_ERROR_BUFLEN
) {
355 d_print("unrecoverable frame level error.\n");
358 if (nomad
->stream
.error
== MAD_ERROR_LOSTSYNC
)
359 handle_lost_sync(nomad
);
362 if (nomad
->info
.nr_frames
== 0) {
363 d_print("error: not an mp3 file!\n");
364 return -NOMAD_ERROR_FILE_FORMAT
;
366 nomad
->info
.duration
= timer_to_seconds(nomad
->timer
);
368 nomad
->info
.avg_bitrate
= bitrate_sum
/ nomad
->info
.nr_frames
;
369 nomad
->cur_frame
= 0;
370 nomad
->cbs
.lseek(nomad
->datasource
, 0, SEEK_SET
);
371 nomad
->input_offset
= 0;
375 static int decode(struct nomad
*nomad
)
380 rc
= fill_buffer(nomad
);
386 if (mad_frame_decode(&nomad
->frame
, &nomad
->stream
)) {
387 if (nomad
->stream
.error
== MAD_ERROR_BUFLEN
)
389 if (!MAD_RECOVERABLE(nomad
->stream
.error
)) {
390 d_print("unrecoverable frame level error.\n");
393 if (nomad
->stream
.error
== MAD_ERROR_LOSTSYNC
)
394 handle_lost_sync(nomad
);
398 if (nomad
->info
.filesize
> 0)
399 build_seek_index(nomad
);
400 mad_timer_add(&nomad
->timer
, nomad
->frame
.header
.duration
);
401 mad_synth_frame(&nomad
->synth
, &nomad
->frame
);
405 static void init_mad(struct nomad
*nomad
)
407 mad_stream_init(&nomad
->stream
);
408 mad_frame_init(&nomad
->frame
);
409 mad_synth_init(&nomad
->synth
);
410 mad_header_init(&nomad
->header
);
411 mad_timer_reset(&nomad
->timer
);
412 nomad
->cur_frame
= 0;
414 nomad
->input_offset
= 0;
417 static void free_mad(struct nomad
*nomad
)
419 mad_stream_finish(&nomad
->stream
);
420 mad_frame_finish(&nomad
->frame
);
421 mad_synth_finish(nomad
->synth
);
422 mad_header_finish(&nomad
->header
);
425 static int do_open(struct nomad
*nomad
, int fast
)
430 nomad
->info
.filesize
= nomad
->cbs
.lseek(nomad
->datasource
, 0, SEEK_END
);
431 if (nomad
->info
.filesize
== -1) {
434 nomad
->fast
= fast
!= 0;
435 nomad
->cbs
.lseek(nomad
->datasource
, 0, SEEK_SET
);
437 if (nomad
->info
.filesize
== -1) {
443 nomad
->info
.sample_rate
= nomad
->frame
.header
.samplerate
;
444 nomad
->info
.channels
= MAD_NCHANNELS(&nomad
->frame
.header
);
445 nomad
->info
.layer
= nomad
->frame
.header
.layer
;
446 nomad
->info
.dual_channel
= nomad
->header
.mode
== MAD_MODE_DUAL_CHANNEL
;
447 nomad
->info
.joint_stereo
= nomad
->header
.mode
== MAD_MODE_JOINT_STEREO
;
450 nomad
->info
.duration
= -1.0;
451 nomad
->info
.nr_frames
= -1;
452 nomad
->info
.vbr
= -1;
453 nomad
->info
.avg_bitrate
= -1;
463 d_print("\n frames: %d, br: %d b/s, sr: %d Hz, ch: %d, layer: %d, joint stereo: %d\n"
464 " dual channel: %d, vbr: %d, duration: %g s, xing: %d\n",
465 nomad
->info
.nr_frames
, nomad
->info
.avg_bitrate
,
466 nomad
->info
.sample_rate
, nomad
->info
.channels
,
467 nomad
->info
.layer
, nomad
->info
.joint_stereo
,
468 nomad
->info
.dual_channel
, nomad
->info
.vbr
,
469 nomad
->info
.duration
,
471 #if defined(DEBUG_XING)
473 d_print("xing: flags: 0x%x, frames: %d, bytes: %d, scale: %d\n",
475 nomad
->xing
.nr_frames
,
485 return -NOMAD_ERROR_FILE_FORMAT
;
488 int nomad_open(struct nomad
**nomadp
, int fd
, int fast
)
492 nomad
= xnew0(struct nomad
, 1);
493 nomad
->datasource
= &nomad
->datasource_fd
;
494 nomad
->datasource_fd
= fd
;
495 nomad
->cbs
.read
= default_read
;
496 nomad
->cbs
.lseek
= default_lseek
;
497 nomad
->cbs
.close
= default_close
;
499 /* on error do_open calls nomad_close */
500 return do_open(nomad
, fast
);
503 int nomad_open_callbacks(struct nomad
**nomadp
, void *datasource
, int fast
, struct nomad_callbacks
*cbs
)
507 nomad
= xnew0(struct nomad
, 1);
508 nomad
->datasource
= datasource
;
511 /* on error do_open calls nomad_close */
512 return do_open(nomad
, fast
);
515 void nomad_close(struct nomad
*nomad
)
518 nomad
->cbs
.close(nomad
->datasource
);
519 free(nomad
->seek_idx
.table
);
523 void nomad_info(struct nomad
*nomad
, struct nomad_info
*info
)
528 int nomad_read(struct nomad
*nomad
, char *buffer
, int count
)
530 int i
, j
, size
, psize
, to
;
532 if (nomad
->i
== -1) {
542 psize
= nomad
->info
.channels
* 16 / 8;
543 size
= (nomad
->synth
.pcm
.length
- nomad
->i
) * psize
;
545 to
= nomad
->i
+ count
/ psize
;
547 to
= nomad
->synth
.pcm
.length
;
550 for (i
= nomad
->i
; i
< to
; i
++) {
553 sample
= scale(nomad
->synth
.pcm
.samples
[0][i
]);
554 buffer
[j
++] = (sample
>> 0) & 0xff;
555 buffer
[j
++] = (sample
>> 8) & 0xff;
557 if (nomad
->info
.channels
== 2) {
558 sample
= scale(nomad
->synth
.pcm
.samples
[1][i
]);
559 buffer
[j
++] = (sample
>> 0) & 0xff;
560 buffer
[j
++] = (sample
>> 8) & 0xff;
563 if (to
!= nomad
->synth
.pcm
.length
) {
571 int nomad_time_seek(struct nomad
*nomad
, double pos
)
575 if (pos
< 0.0 || pos
> nomad
->info
.duration
) {
579 if (nomad
->info
.filesize
== -1) {
586 /* calculate seek offset */
587 if (nomad
->has_xing
) {
588 /* seek to truncate(pos / duration * 100) / 100 * duration */
592 k
= pos
/ nomad
->info
.duration
* 100.0;
594 tmp_pos
= ((double)ki
) / 100.0 * nomad
->info
.duration
;
595 nomad
->timer
.seconds
= (signed int)tmp_pos
;
596 nomad
->timer
.fraction
= (tmp_pos
- (double)nomad
->timer
.seconds
) * MAD_TIMER_RESOLUTION
;
597 #if defined(DEBUG_XING)
598 d_print("seeking to %g = %g %d%%\n",
600 timer_to_seconds(nomad
->timer
),
603 offset
= ((unsigned long long)nomad
->xing
.toc
[ki
] * nomad
->xing
.bytes
) / 256;
604 } else if (nomad
->seek_idx
.size
> 0) {
605 int idx
= (int)(pos
/ SEEK_IDX_INTERVAL
) - 1;
607 if (idx
> nomad
->seek_idx
.size
- 1)
608 idx
= nomad
->seek_idx
.size
- 1;
611 offset
= nomad
->seek_idx
.table
[idx
].offset
;
612 nomad
->timer
= nomad
->seek_idx
.table
[idx
].timer
;
615 if (nomad
->cbs
.lseek(nomad
->datasource
, offset
, SEEK_SET
) < 0)
618 nomad
->input_offset
= offset
;
619 while (timer_to_seconds(nomad
->timer
) < pos
) {
622 rc
= fill_buffer(nomad
);
628 if (mad_header_decode(&nomad
->header
, &nomad
->stream
) == 0) {
629 build_seek_index(nomad
);
630 mad_timer_add(&nomad
->timer
, nomad
->header
.duration
);
632 if (!MAD_RECOVERABLE(nomad
->stream
.error
) && nomad
->stream
.error
!= MAD_ERROR_BUFLEN
) {
633 d_print("unrecoverable frame level error.\n");
636 if (nomad
->stream
.error
== MAD_ERROR_LOSTSYNC
)
637 handle_lost_sync(nomad
);
640 #if defined(DEBUG_XING)
642 d_print("seeked to %g = %g\n", pos
, timer_to_seconds(nomad
->timer
));
647 double nomad_time_tell(struct nomad
*nomad
)
649 return timer_to_seconds(nomad
->timer
);
652 double nomad_time_total(struct nomad
*nomad
)
654 return nomad
->info
.duration
;