blob: 25e40f897adb46e0fbf539a3688849b8e0d55698 [file] [log] [blame]
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Daniel Stenberg
11 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22/*
23 * Parts of this code has been stolen from the Ample project and was written
Nicolas Pennequin357ffb32008-05-05 10:32:46 +000024 * by David Härdeman. It has since been extended and enhanced pretty much by
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +000025 * all sorts of friendly Rockbox people.
26 *
27 * A nice reference for MPEG header info:
28 * http://rockbox.haxx.se/docs/mpeghdr.html
29 *
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <stdbool.h>
Jens Arnoldec9b2022005-09-10 12:28:16 +000036#include <limits.h>
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +000037#include "debug.h"
Thom Johansen57f0ec12005-06-12 14:03:31 +000038#include "logf.h"
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +000039#include "mp3data.h"
40#include "file.h"
Linus Nielsen Feltzing20d031f2003-05-09 16:01:21 +000041#include "buffer.h"
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +000042
Steve Bavin799e9482008-04-07 17:19:53 +000043// #define DEBUG_VERBOSE
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +000044
Jean-Philippe Bernardy98a81322005-01-30 14:11:50 +000045#define SYNC_MASK (0x7ffL << 21)
46#define VERSION_MASK (3L << 19)
47#define LAYER_MASK (3L << 17)
48#define PROTECTION_MASK (1L << 16)
49#define BITRATE_MASK (0xfL << 12)
50#define SAMPLERATE_MASK (3L << 10)
51#define PADDING_MASK (1L << 9)
52#define PRIVATE_MASK (1L << 8)
53#define CHANNELMODE_MASK (3L << 6)
54#define MODE_EXT_MASK (3L << 4)
55#define COPYRIGHT_MASK (1L << 3)
56#define ORIGINAL_MASK (1L << 2)
57#define EMPHASIS_MASK 3L
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +000058
Jens Arnoldec9b2022005-09-10 12:28:16 +000059/* MPEG Version table, sorted by version index */
60static const signed char version_table[4] = {
61 MPEG_VERSION2_5, -1, MPEG_VERSION2, MPEG_VERSION1
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +000062};
63
Jens Arnoldec9b2022005-09-10 12:28:16 +000064/* Bitrate table for mpeg audio, indexed by row index and birate index */
65static const short bitrates[5][16] = {
66 {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, /* V1 L1 */
67 {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, /* V1 L2 */
68 {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0}, /* V1 L3 */
69 {0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256,0}, /* V2 L1 */
70 {0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0} /* V2 L2+L3 */
71};
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +000072
Jens Arnoldec9b2022005-09-10 12:28:16 +000073/* Bitrate pointer table, indexed by version and layer */
74static const short *bitrate_table[3][3] =
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +000075{
Jens Arnoldec9b2022005-09-10 12:28:16 +000076 {bitrates[0], bitrates[1], bitrates[2]},
77 {bitrates[3], bitrates[4], bitrates[4]},
78 {bitrates[3], bitrates[4], bitrates[4]}
79};
80
81/* Sampling frequency table, indexed by version and frequency index */
Linus Nielsen Feltzingaa8761f2007-02-15 22:55:22 +000082static const unsigned short freq_table[3][3] =
Jens Arnoldec9b2022005-09-10 12:28:16 +000083{
84 {44100, 48000, 32000}, /* MPEG Version 1 */
85 {22050, 24000, 16000}, /* MPEG version 2 */
86 {11025, 12000, 8000}, /* MPEG version 2.5 */
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +000087};
88
Linus Nielsen Feltzingaa8761f2007-02-15 22:55:22 +000089unsigned long bytes2int(unsigned long b0,
90 unsigned long b1,
91 unsigned long b2,
92 unsigned long b3)
93{
94 return (((long)(b0 & 0xFF) << (3*8)) |
95 ((long)(b1 & 0xFF) << (2*8)) |
96 ((long)(b2 & 0xFF) << (1*8)) |
97 ((long)(b3 & 0xFF) << (0*8)));
98}
99
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000100/* check if 'head' is a valid mp3 frame header */
101static bool is_mp3frameheader(unsigned long head)
102{
103 if ((head & SYNC_MASK) != (unsigned long)SYNC_MASK) /* bad sync? */
104 return false;
Jean-Philippe Bernardy98a81322005-01-30 14:11:50 +0000105 if ((head & VERSION_MASK) == (1L << 19)) /* bad version? */
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000106 return false;
107 if (!(head & LAYER_MASK)) /* no layer? */
108 return false;
Jens Arnoldd6c05452005-08-29 21:15:27 +0000109#if CONFIG_CODEC != SWCODEC
Jens Arnoldb0287722005-06-18 11:26:14 +0000110 /* The MAS can't decode layer 1, so treat layer 1 data as invalid */
111 if ((head & LAYER_MASK) == LAYER_MASK)
112 return false;
113#endif
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000114 if ((head & BITRATE_MASK) == BITRATE_MASK) /* bad bitrate? */
115 return false;
116 if (!(head & BITRATE_MASK)) /* no bitrate? */
117 return false;
118 if ((head & SAMPLERATE_MASK) == SAMPLERATE_MASK) /* bad sample rate? */
119 return false;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000120
121 return true;
122}
123
124static bool mp3headerinfo(struct mp3info *info, unsigned long header)
125{
Jens Arnoldec9b2022005-09-10 12:28:16 +0000126 int bitindex, freqindex;
127
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000128 /* MPEG Audio Version */
Miika Pekkarinen93b6a1d2006-04-02 20:19:00 +0000129 if ((header & VERSION_MASK) >> 19 >= sizeof(version_table))
130 return false;
131
Jens Arnoldec9b2022005-09-10 12:28:16 +0000132 info->version = version_table[(header & VERSION_MASK) >> 19];
133 if (info->version < 0)
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000134 return false;
Jens Arnold509117d2005-06-04 09:01:40 +0000135
Jens Arnoldec9b2022005-09-10 12:28:16 +0000136 /* Layer */
137 info->layer = 3 - ((header & LAYER_MASK) >> 17);
138 if (info->layer == 3)
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000139 return false;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000140
Jens Arnoldec9b2022005-09-10 12:28:16 +0000141 info->protection = (header & PROTECTION_MASK) ? true : false;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000142
143 /* Bitrate */
Jens Arnoldec9b2022005-09-10 12:28:16 +0000144 bitindex = (header & BITRATE_MASK) >> 12;
145 info->bitrate = bitrate_table[info->version][info->layer][bitindex];
Linus Nielsen Feltzingdf4cf2e2003-03-24 11:35:53 +0000146 if(info->bitrate == 0)
147 return false;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000148
Jens Arnoldec9b2022005-09-10 12:28:16 +0000149 /* Sampling frequency */
150 freqindex = (header & SAMPLERATE_MASK) >> 10;
151 if (freqindex == 3)
152 return false;
153 info->frequency = freq_table[info->version][freqindex];
154
155 info->padding = (header & PADDING_MASK) ? 1 : 0;
Jens Arnold249f86c2005-08-22 00:15:57 +0000156
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000157 /* Calculate number of bytes, calculation depends on layer */
Jens Arnoldec9b2022005-09-10 12:28:16 +0000158 if (info->layer == 0) {
159 info->frame_samples = 384;
160 info->frame_size = (12000 * info->bitrate / info->frequency
161 + info->padding) * 4;
162 }
163 else {
164 if ((info->version > MPEG_VERSION1) && (info->layer == 2))
165 info->frame_samples = 576;
166 else
167 info->frame_samples = 1152;
168 info->frame_size = (1000/8) * info->frame_samples * info->bitrate
169 / info->frequency + info->padding;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000170 }
171
Jens Arnold893669c2005-09-25 19:07:56 +0000172 /* Frametime fraction denominator */
173 if (freqindex != 0) { /* 48/32/24/16/12/8 kHz */
174 info->ft_den = 1; /* integer number of milliseconds */
Jens Arnoldec9b2022005-09-10 12:28:16 +0000175 }
Jens Arnold893669c2005-09-25 19:07:56 +0000176 else { /* 44.1/22.05/11.025 kHz */
177 if (info->layer == 0) /* layer 1 */
Jens Arnoldec9b2022005-09-10 12:28:16 +0000178 info->ft_den = 147;
Jens Arnold893669c2005-09-25 19:07:56 +0000179 else /* layer 2+3 */
Jens Arnoldec9b2022005-09-10 12:28:16 +0000180 info->ft_den = 49;
Jens Arnoldec9b2022005-09-10 12:28:16 +0000181 }
Jens Arnold893669c2005-09-25 19:07:56 +0000182 /* Frametime fraction numerator */
183 info->ft_num = 1000 * info->ft_den * info->frame_samples / info->frequency;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000184
Jens Arnoldec9b2022005-09-10 12:28:16 +0000185 info->channel_mode = (header & CHANNELMODE_MASK) >> 6;
186 info->mode_extension = (header & MODE_EXT_MASK) >> 4;
187 info->emphasis = header & EMPHASIS_MASK;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000188
189#ifdef DEBUG_VERBOSE
Jens Arnoldf68362a2007-03-17 09:54:28 +0000190 DEBUGF( "Header: %08lx, Ver %d, lay %d, bitr %d, freq %ld, "
Jens Arnoldec9b2022005-09-10 12:28:16 +0000191 "chmode %d, mode_ext %d, emph %d, bytes: %d time: %d/%d\n",
Linus Nielsen Feltzinga0d5bea2004-12-01 11:04:39 +0000192 header, info->version, info->layer+1, info->bitrate,
193 info->frequency, info->channel_mode, info->mode_extension,
Jens Arnoldec9b2022005-09-10 12:28:16 +0000194 info->emphasis, info->frame_size, info->ft_num, info->ft_den);
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000195#endif
196 return true;
197}
198
Jean-Philippe Bernardy98a81322005-01-30 14:11:50 +0000199static unsigned long __find_next_frame(int fd, long *offset, long max_offset,
200 unsigned long last_header,
201 int(*getfunc)(int fd, unsigned char *c))
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000202{
203 unsigned long header=0;
204 unsigned char tmp;
205 int i;
206
Jean-Philippe Bernardy98a81322005-01-30 14:11:50 +0000207 long pos = 0;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000208
209 /* We remember the last header we found, to use as a template to see if
210 the header we find has the same frequency, layer etc */
211 last_header &= 0xffff0c00;
212
213 /* Fill up header with first 24 bits */
214 for(i = 0; i < 3; i++) {
215 header <<= 8;
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +0000216 if(!getfunc(fd, &tmp))
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000217 return 0;
218 header |= tmp;
219 pos++;
220 }
221
222 do {
223 header <<= 8;
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +0000224 if(!getfunc(fd, &tmp))
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000225 return 0;
226 header |= tmp;
227 pos++;
228 if(max_offset > 0 && pos > max_offset)
229 return 0;
230 } while(!is_mp3frameheader(header) ||
231 (last_header?((header & 0xffff0c00) != last_header):false));
232
233 *offset = pos - 4;
234
Steve Bavin799e9482008-04-07 17:19:53 +0000235#if defined(DEBUG)
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000236 if(*offset)
Jens Arnoldf68362a2007-03-17 09:54:28 +0000237 DEBUGF("Warning: skipping %ld bytes of garbage\n", *offset);
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000238#endif
Jens Arnoldec9b2022005-09-10 12:28:16 +0000239
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000240 return header;
241}
242
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +0000243static int fileread(int fd, unsigned char *c)
Miika Pekkarinenb0e78a42005-07-13 13:13:10 +0000244{
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +0000245 return read(fd, c, 1);
246}
247
Jean-Philippe Bernardy98a81322005-01-30 14:11:50 +0000248unsigned long find_next_frame(int fd, long *offset, long max_offset, unsigned long last_header)
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +0000249{
250 return __find_next_frame(fd, offset, max_offset, last_header, fileread);
251}
252
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000253#ifndef __PCTOOL__
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000254static int fnf_read_index;
255static int fnf_buf_len;
256
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000257static int buf_getbyte(int fd, unsigned char *c)
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000258{
259 if(fnf_read_index < fnf_buf_len)
260 {
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000261 *c = audiobuf[fnf_read_index++];
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000262 return 1;
263 }
264 else
265 {
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000266 fnf_buf_len = read(fd, audiobuf, audiobufend - audiobuf);
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000267 if(fnf_buf_len < 0)
268 return -1;
269
270 fnf_read_index = 0;
271
272 if(fnf_buf_len > 0)
273 {
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000274 *c = audiobuf[fnf_read_index++];
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000275 return 1;
276 }
277 else
278 return 0;
279 }
280 return 0;
281}
282
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000283static int buf_seek(int fd, int len)
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000284{
285 fnf_read_index += len;
286 if(fnf_read_index > fnf_buf_len)
287 {
288 len = fnf_read_index - fnf_buf_len;
289
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000290 fnf_buf_len = read(fd, audiobuf, audiobufend - audiobuf);
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000291 if(fnf_buf_len < 0)
292 return -1;
293
294 fnf_read_index = 0;
295 fnf_read_index += len;
296 }
297
298 if(fnf_read_index > fnf_buf_len)
299 {
300 return -1;
301 }
302 else
303 return 0;
304}
305
306static void buf_init(void)
307{
308 fnf_buf_len = 0;
309 fnf_read_index = 0;
310}
311
Bertrik Sikkene15f8a22008-05-03 08:35:14 +0000312static unsigned long buf_find_next_frame(int fd, long *offset, long max_offset,
313 unsigned long last_header)
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000314{
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +0000315 return __find_next_frame(fd, offset, max_offset, last_header, buf_getbyte);
316}
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000317
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000318static int audiobuflen;
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +0000319static int mem_pos;
320static int mem_cnt;
321static int mem_maxlen;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000322
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +0000323static int mem_getbyte(int dummy, unsigned char *c)
324{
325 dummy = dummy;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000326
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000327 *c = audiobuf[mem_pos++];
328 if(mem_pos >= audiobuflen)
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +0000329 mem_pos = 0;
330
331 if(mem_cnt++ >= mem_maxlen)
332 return 0;
333 else
334 return 1;
335}
336
Jean-Philippe Bernardy98a81322005-01-30 14:11:50 +0000337unsigned long mem_find_next_frame(int startpos, long *offset, long max_offset,
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +0000338 unsigned long last_header)
339{
Linus Nielsen Feltzingd34865a2005-04-05 11:33:58 +0000340 audiobuflen = audiobufend - audiobuf;
Linus Nielsen Feltzing24a8b6a2003-11-02 11:24:38 +0000341 mem_pos = startpos;
342 mem_cnt = 0;
343 mem_maxlen = max_offset;
344
345 return __find_next_frame(0, offset, max_offset, last_header, mem_getbyte);
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000346}
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000347#endif
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000348
349int get_mp3file_info(int fd, struct mp3info *info)
350{
Linus Nielsen Feltzingd28a5062003-06-03 21:50:21 +0000351 unsigned char frame[1800];
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000352 unsigned char *vbrheader;
353 unsigned long header;
Jean-Philippe Bernardy98a81322005-01-30 14:11:50 +0000354 long bytecount;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000355 int num_offsets;
356 int frames_per_entry;
357 int i;
Jean-Philippe Bernardy98a81322005-01-30 14:11:50 +0000358 long offset;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000359 int j;
Jean-Philippe Bernardy98a81322005-01-30 14:11:50 +0000360 long tmp;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000361
362 header = find_next_frame(fd, &bytecount, 0x20000, 0);
363 /* Quit if we haven't found a valid header within 128K */
364 if(header == 0)
365 return -1;
366
367 memset(info, 0, sizeof(struct mp3info));
Linus Nielsen Feltzingaa8761f2007-02-15 22:55:22 +0000368#if CONFIG_CODEC==SWCODEC
Thom Johansen57f0ec12005-06-12 14:03:31 +0000369 /* These two are needed for proper LAME gapless MP3 playback */
Thom Johansen57f0ec12005-06-12 14:03:31 +0000370 info->enc_delay = -1;
371 info->enc_padding = -1;
Linus Nielsen Feltzingaa8761f2007-02-15 22:55:22 +0000372#endif
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000373 if(!mp3headerinfo(info, header))
374 return -2;
375
376 /* OK, we have found a frame. Let's see if it has a Xing header */
Daniel Stenbergc16c7272006-04-02 23:06:20 +0000377 if (info->frame_size-4 >= (int)sizeof(frame))
Miika Pekkarinen93b6a1d2006-04-02 20:19:00 +0000378 {
Steve Bavin799e9482008-04-07 17:19:53 +0000379#if defined(DEBUG)
Miika Pekkarinen93b6a1d2006-04-02 20:19:00 +0000380 DEBUGF("Error: Invalid id3 header, frame_size: %d\n", info->frame_size);
381#endif
382 return -8;
383 }
384
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000385 if(read(fd, frame, info->frame_size-4) < 0)
386 return -3;
387
388 /* calculate position of VBR header */
389 if ( info->version == MPEG_VERSION1 ) {
390 if (info->channel_mode == 3) /* mono */
391 vbrheader = frame + 17;
392 else
393 vbrheader = frame + 32;
394 }
395 else {
396 if (info->channel_mode == 3) /* mono */
397 vbrheader = frame + 9;
398 else
399 vbrheader = frame + 17;
400 }
401
Magnus Holmgren501ab1a2005-08-13 08:09:28 +0000402 if (!memcmp(vbrheader, "Xing", 4)
403 || !memcmp(vbrheader, "Info", 4))
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000404 {
405 int i = 8; /* Where to start parsing info */
406
Nicolas Pennequin06c199e2008-04-07 19:33:48 +0000407 /* DEBUGF("Xing/Info header\n"); */
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000408
409 /* Remember where in the file the Xing header is */
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000410 info->vbr_header_pos = lseek(fd, 0, SEEK_CUR) - info->frame_size;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000411
412 /* We want to skip the Xing frame when playing the stream */
413 bytecount += info->frame_size;
414
415 /* Now get the next frame to find out the real info about
416 the mp3 stream */
417 header = find_next_frame(fd, &tmp, 0x20000, 0);
418 if(header == 0)
419 return -4;
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000420
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000421 if(!mp3headerinfo(info, header))
422 return -5;
423
Magnus Holmgren501ab1a2005-08-13 08:09:28 +0000424 /* Is it a VBR file? */
425 info->is_vbr = info->is_xing_vbr = !memcmp(vbrheader, "Xing", 4);
426
Jens Arnoldba966c12005-09-15 05:29:26 +0000427 if (vbrheader[7] & VBR_FRAMES_FLAG) /* Is the frame count there? */
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000428 {
Linus Nielsen Feltzingaa8761f2007-02-15 22:55:22 +0000429 info->frame_count = bytes2int(vbrheader[i], vbrheader[i+1],
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000430 vbrheader[i+2], vbrheader[i+3]);
Jens Arnoldec9b2022005-09-10 12:28:16 +0000431 if (info->frame_count <= ULONG_MAX / info->ft_num)
432 info->file_time = info->frame_count * info->ft_num / info->ft_den;
433 else
434 info->file_time = info->frame_count / info->ft_den * info->ft_num;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000435 i += 4;
436 }
437
Jens Arnoldba966c12005-09-15 05:29:26 +0000438 if (vbrheader[7] & VBR_BYTES_FLAG) /* Is byte count there? */
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000439 {
Linus Nielsen Feltzingaa8761f2007-02-15 22:55:22 +0000440 info->byte_count = bytes2int(vbrheader[i], vbrheader[i+1],
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000441 vbrheader[i+2], vbrheader[i+3]);
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000442 i += 4;
443 }
444
Jens Arnoldba966c12005-09-15 05:29:26 +0000445 if (info->file_time && info->byte_count)
446 {
447 if (info->byte_count <= (ULONG_MAX/8))
448 info->bitrate = info->byte_count * 8 / info->file_time;
449 else
450 info->bitrate = info->byte_count / (info->file_time >> 3);
451 }
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000452 else
453 info->bitrate = 0;
Jens Arnoldba966c12005-09-15 05:29:26 +0000454
455 if (vbrheader[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000456 {
Magnus Holmgren2cf14db2006-10-19 18:03:11 +0000457 info->has_toc = true;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000458 memcpy( info->toc, vbrheader+i, 100 );
Thom Johansen57f0ec12005-06-12 14:03:31 +0000459 i += 100;
460 }
461 if (vbrheader[7] & VBR_QUALITY_FLAG)
462 {
463 /* We don't care about this, but need to skip it */
464 i += 4;
465 }
Linus Nielsen Feltzingaa8761f2007-02-15 22:55:22 +0000466#if CONFIG_CODEC==SWCODEC
Thom Johansen57f0ec12005-06-12 14:03:31 +0000467 i += 21;
468 info->enc_delay = (vbrheader[i] << 4) | (vbrheader[i + 1] >> 4);
469 info->enc_padding = ((vbrheader[i + 1] & 0x0f) << 8) | vbrheader[i + 2];
Thom Johansena1df0602005-11-02 18:05:31 +0000470 /* TODO: This sanity checking is rather silly, seeing as how the LAME
471 header contains a CRC field that can be used to verify integrity. */
472 if (!(info->enc_delay >= 0 && info->enc_delay <= 2880 &&
Thom Johansen57f0ec12005-06-12 14:03:31 +0000473 info->enc_padding >= 0 && info->enc_padding <= 2*1152))
474 {
475 /* Invalid data */
476 info->enc_delay = -1;
477 info->enc_padding = -1;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000478 }
Linus Nielsen Feltzingaa8761f2007-02-15 22:55:22 +0000479#endif
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000480 }
481
Jens Arnold35b6dc32004-08-03 21:54:24 +0000482 if (!memcmp(vbrheader, "VBRI", 4))
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000483 {
484 DEBUGF("VBRI header\n");
485
486 /* We want to skip the VBRI frame when playing the stream */
487 bytecount += info->frame_size;
488
489 /* Now get the next frame to find out the real info about
490 the mp3 stream */
Linus Nielsen Feltzinga2330362004-04-29 01:18:15 +0000491 header = find_next_frame(fd, &tmp, 0x20000, 0);
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000492 if(header == 0)
493 return -6;
Linus Nielsen Feltzinga2330362004-04-29 01:18:15 +0000494
495 bytecount += tmp;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000496
497 if(!mp3headerinfo(info, header))
498 return -7;
499
Jens Arnoldf68362a2007-03-17 09:54:28 +0000500 DEBUGF("%04x: %04x %04x ", 0, (short)(header >> 16),
501 (short)(header & 0xffff));
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000502 for(i = 4;i < (int)sizeof(frame)-4;i+=2) {
503 if(i % 16 == 0) {
504 DEBUGF("\n%04x: ", i-4);
505 }
506 DEBUGF("%04x ", (frame[i-4] << 8) | frame[i-4+1]);
507 }
508
509 DEBUGF("\n");
510
511 /* Yes, it is a FhG VBR file */
512 info->is_vbr = true;
513 info->is_vbri_vbr = true;
514 info->has_toc = false; /* We don't parse the TOC (yet) */
515
Linus Nielsen Feltzingaa8761f2007-02-15 22:55:22 +0000516 info->byte_count = bytes2int(vbrheader[10], vbrheader[11],
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000517 vbrheader[12], vbrheader[13]);
Linus Nielsen Feltzingaa8761f2007-02-15 22:55:22 +0000518 info->frame_count = bytes2int(vbrheader[14], vbrheader[15],
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000519 vbrheader[16], vbrheader[17]);
Jens Arnoldec9b2022005-09-10 12:28:16 +0000520 if (info->frame_count <= ULONG_MAX / info->ft_num)
521 info->file_time = info->frame_count * info->ft_num / info->ft_den;
522 else
523 info->file_time = info->frame_count / info->ft_den * info->ft_num;
Jens Arnoldba966c12005-09-15 05:29:26 +0000524
525 if (info->byte_count <= (ULONG_MAX/8))
526 info->bitrate = info->byte_count * 8 / info->file_time;
527 else
528 info->bitrate = info->byte_count / (info->file_time >> 3);
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000529
530 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
Linus Nielsen Feltzingaa8761f2007-02-15 22:55:22 +0000531 num_offsets = bytes2int(0, 0, vbrheader[18], vbrheader[19]);
532 frames_per_entry = bytes2int(0, 0, vbrheader[24], vbrheader[25]);
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000533 DEBUGF("Frame size (%dkpbs): %d bytes (0x%x)\n",
534 info->bitrate, info->frame_size, info->frame_size);
Jens Arnoldf68362a2007-03-17 09:54:28 +0000535 DEBUGF("Frame count: %lx\n", info->frame_count);
536 DEBUGF("Byte count: %lx\n", info->byte_count);
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000537 DEBUGF("Offsets: %d\n", num_offsets);
538 DEBUGF("Frames/entry: %d\n", frames_per_entry);
539
540 offset = 0;
541
542 for(i = 0;i < num_offsets;i++)
543 {
Linus Nielsen Feltzingaa8761f2007-02-15 22:55:22 +0000544 j = bytes2int(0, 0, vbrheader[26+i*2], vbrheader[27+i*2]);
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000545 offset += j;
Jens Arnoldf68362a2007-03-17 09:54:28 +0000546 DEBUGF("%03d: %lx (%x)\n", i, offset - bytecount, j);
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000547 }
548 }
549
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000550 return bytecount;
551}
552
Jean-Philippe Bernardy98a81322005-01-30 14:11:50 +0000553static void long2bytes(unsigned char *buf, long val)
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000554{
555 buf[0] = (val >> 24) & 0xff;
556 buf[1] = (val >> 16) & 0xff;
557 buf[2] = (val >> 8) & 0xff;
558 buf[3] = val & 0xff;
559}
560
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000561#ifndef __PCTOOL__
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000562int count_mp3_frames(int fd, int startpos, int filesize,
563 void (*progressfunc)(int))
564{
565 unsigned long header = 0;
566 struct mp3info info;
567 int num_frames;
Jean-Philippe Bernardy98a81322005-01-30 14:11:50 +0000568 long bytes;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000569 int cnt;
Jean-Philippe Bernardy98a81322005-01-30 14:11:50 +0000570 long progress_chunk = filesize / 50; /* Max is 50%, in 1% increments */
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000571 int progress_cnt = 0;
Linus Nielsen Feltzing2c07e782003-03-10 18:25:40 +0000572 bool is_vbr = false;
573 int last_bitrate = 0;
Linus Nielsen Feltzing1936c412004-01-13 14:06:18 +0000574 int header_template = 0;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000575
576 if(lseek(fd, startpos, SEEK_SET) < 0)
577 return -1;
578
579 buf_init();
580
581 /* Find out the total number of frames */
582 num_frames = 0;
583 cnt = 0;
584
Linus Nielsen Feltzing1936c412004-01-13 14:06:18 +0000585 while((header = buf_find_next_frame(fd, &bytes, -1, header_template))) {
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000586 mp3headerinfo(&info, header);
Linus Nielsen Feltzing2c07e782003-03-10 18:25:40 +0000587
Linus Nielsen Feltzing1936c412004-01-13 14:06:18 +0000588 if(!header_template)
589 header_template = header;
590
Linus Nielsen Feltzing2c07e782003-03-10 18:25:40 +0000591 /* See if this really is a VBR file */
592 if(last_bitrate && info.bitrate != last_bitrate)
593 {
594 is_vbr = true;
595 }
596 last_bitrate = info.bitrate;
597
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000598 buf_seek(fd, info.frame_size-4);
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000599 num_frames++;
600 if(progressfunc)
601 {
602 cnt += bytes + info.frame_size;
603 if(cnt > progress_chunk)
604 {
605 progress_cnt++;
606 progressfunc(progress_cnt);
607 cnt = 0;
608 }
609 }
610 }
611 DEBUGF("Total number of frames: %d\n", num_frames);
Linus Nielsen Feltzing2c07e782003-03-10 18:25:40 +0000612
613 if(is_vbr)
614 return num_frames;
615 else
616 {
617 DEBUGF("Not a VBR file\n");
618 return 0;
619 }
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000620}
621
Linus Nielsen Feltzing478da622003-04-20 22:00:30 +0000622static const char cooltext[] = "Rockbox - rocks your box";
623
Jens Arnoldba966c12005-09-15 05:29:26 +0000624/* buf needs to be the audio buffer with TOC generation enabled,
625 and at least MAX_XING_HEADER_SIZE bytes otherwise */
626int create_xing_header(int fd, long startpos, long filesize,
627 unsigned char *buf, unsigned long num_frames,
628 unsigned long rec_time, unsigned long header_template,
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000629 void (*progressfunc)(int), bool generate_toc)
Jens Arnoldba966c12005-09-15 05:29:26 +0000630{
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000631 struct mp3info info;
Linus Nielsen Feltzing478da622003-04-20 22:00:30 +0000632 unsigned char toc[100];
Jens Arnoldba966c12005-09-15 05:29:26 +0000633 unsigned long header = 0;
634 unsigned long xing_header_template = header_template;
635 unsigned long filepos;
636 long pos, last_pos;
637 long j;
638 long bytes;
639 int i;
640 int index;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000641
642 DEBUGF("create_xing_header()\n");
Linus Nielsen Feltzing1936c412004-01-13 14:06:18 +0000643
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000644 if(generate_toc)
645 {
Linus Nielsen Feltzing478da622003-04-20 22:00:30 +0000646 lseek(fd, startpos, SEEK_SET);
647 buf_init();
Jens Arnoldba966c12005-09-15 05:29:26 +0000648
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000649 /* Generate filepos table */
650 last_pos = 0;
651 filepos = 0;
652 header = 0;
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000653 for(i = 0;i < 100;i++) {
654 /* Calculate the absolute frame number for this seek point */
655 pos = i * num_frames / 100;
656
657 /* Advance from the last seek point to this one */
658 for(j = 0;j < pos - last_pos;j++)
659 {
Linus Nielsen Feltzing1936c412004-01-13 14:06:18 +0000660 header = buf_find_next_frame(fd, &bytes, -1, header_template);
661 filepos += bytes;
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000662 mp3headerinfo(&info, header);
663 buf_seek(fd, info.frame_size-4);
664 filepos += info.frame_size;
Linus Nielsen Feltzing1936c412004-01-13 14:06:18 +0000665
666 if(!header_template)
667 header_template = header;
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000668 }
Linus Nielsen Feltzing7fdef572003-04-19 01:59:23 +0000669
Linus Nielsen Feltzingfb5f4582003-12-28 03:40:41 +0000670 /* Save a header for later use if header_template is empty.
671 We only save one header, and we want to save one in the
672 middle of the stream, just in case the first and the last
673 headers are corrupt. */
Linus Nielsen Feltzing1936c412004-01-13 14:06:18 +0000674 if(!xing_header_template && i == 1)
675 xing_header_template = header;
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000676
677 if(progressfunc)
678 {
679 progressfunc(50 + i/2);
680 }
681
Linus Nielsen Feltzing478da622003-04-20 22:00:30 +0000682 /* Fill in the TOC entry */
Daniel Stenberg24756e12003-05-19 14:15:21 +0000683 /* each toc is a single byte indicating how many 256ths of the
684 * way through the file, is that percent of the way through the
685 * song. the easy method, filepos*256/filesize, chokes when
686 * the upper 8 bits of the file position are nonzero
687 * (i.e. files over 16mb in size).
688 */
Jens Arnoldba966c12005-09-15 05:29:26 +0000689 if (filepos > (ULONG_MAX/256))
Daniel Stenberg24756e12003-05-19 14:15:21 +0000690 {
691 /* instead of multiplying filepos by 256, we divide
692 * filesize by 256.
693 */
694 toc[i] = filepos / (filesize >> 8);
695 }
696 else
697 {
698 toc[i] = filepos * 256 / filesize;
699 }
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000700
Jens Arnoldf68362a2007-03-17 09:54:28 +0000701 DEBUGF("Pos %d: %ld relpos: %ld filepos: %lx tocentry: %x\n",
Linus Nielsen Feltzing478da622003-04-20 22:00:30 +0000702 i, pos, pos-last_pos, filepos, toc[i]);
Linus Nielsen Feltzing6475aa02003-03-10 18:05:01 +0000703
704 last_pos = pos;
705 }
Linus Nielsen Feltzing478da622003-04-20 22:00:30 +0000706 }
Jens Arnold9352ac82005-09-04 21:55:15 +0000707
Jens Arnoldba966c12005-09-15 05:29:26 +0000708 /* Use the template header and create a new one.
709 We ignore the Protection bit even if the rest of the stream is
710 protected. */
711 header = xing_header_template & ~(BITRATE_MASK|PROTECTION_MASK|PADDING_MASK);
712 header |= 8 << 12; /* This gives us plenty of space, 192..576 bytes */
713
714 if (!mp3headerinfo(&info, header))
Jens Arnold9352ac82005-09-04 21:55:15 +0000715 return 0; /* invalid header */
Jens Arnold509117d2005-06-04 09:01:40 +0000716
Jens Arnoldba966c12005-09-15 05:29:26 +0000717 if (num_frames == 0 && rec_time) {
718 /* estimate the number of frames based on the recording time */
719 if (rec_time <= ULONG_MAX / info.ft_den)
720 num_frames = rec_time * info.ft_den / info.ft_num;
721 else
722 num_frames = rec_time / info.ft_num * info.ft_den;
723 }
724
Linus Nielsen Feltzing478da622003-04-20 22:00:30 +0000725 /* Clear the frame */
Jens Arnold9352ac82005-09-04 21:55:15 +0000726 memset(buf, 0, MAX_XING_HEADER_SIZE);
Linus Nielsen Feltzing478da622003-04-20 22:00:30 +0000727
Jens Arnoldba966c12005-09-15 05:29:26 +0000728 /* Write the header to the buffer */
729 long2bytes(buf, header);
Jens Arnold9352ac82005-09-04 21:55:15 +0000730
Jens Arnoldba966c12005-09-15 05:29:26 +0000731 /* Calculate position of VBR header */
Jens Arnold9352ac82005-09-04 21:55:15 +0000732 if (info.version == MPEG_VERSION1) {
Linus Nielsen Feltzing478da622003-04-20 22:00:30 +0000733 if (info.channel_mode == 3) /* mono */
734 index = 21;
735 else
736 index = 36;
Linus Nielsen Feltzing7fdef572003-04-19 01:59:23 +0000737 }
Linus Nielsen Feltzing478da622003-04-20 22:00:30 +0000738 else {
739 if (info.channel_mode == 3) /* mono */
740 index = 13;
741 else
742 index = 21;
743 }
744
Linus Nielsen Feltzing478da622003-04-20 22:00:30 +0000745 /* Create the Xing data */
Jens Arnold509117d2005-06-04 09:01:40 +0000746 memcpy(&buf[index], "Xing", 4);
Jens Arnoldba966c12005-09-15 05:29:26 +0000747 long2bytes(&buf[index+4], (num_frames ? VBR_FRAMES_FLAG : 0)
748 | (filesize ? VBR_BYTES_FLAG : 0)
749 | (generate_toc ? VBR_TOC_FLAG : 0));
750 index += 8;
Linus Nielsen Feltzing478da622003-04-20 22:00:30 +0000751 if(num_frames)
Linus Nielsen Feltzing7fdef572003-04-19 01:59:23 +0000752 {
Jean-Philippe Bernardy98a81322005-01-30 14:11:50 +0000753 long2bytes(&buf[index], num_frames);
Linus Nielsen Feltzing478da622003-04-20 22:00:30 +0000754 index += 4;
Linus Nielsen Feltzing7fdef572003-04-19 01:59:23 +0000755 }
Linus Nielsen Feltzing478da622003-04-20 22:00:30 +0000756
757 if(filesize)
758 {
Jean-Philippe Bernardy98a81322005-01-30 14:11:50 +0000759 long2bytes(&buf[index], filesize - startpos);
Linus Nielsen Feltzing478da622003-04-20 22:00:30 +0000760 index += 4;
761 }
762
763 /* Copy the TOC */
764 memcpy(buf + index, toc, 100);
765
766 /* And some extra cool info */
Linus Nielsen Feltzing1b466e02003-04-19 02:09:56 +0000767 memcpy(buf + index + 100, cooltext, sizeof(cooltext));
Linus Nielsen Feltzing7fdef572003-04-19 01:59:23 +0000768
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000769#ifdef DEBUG
Linus Nielsen Feltzing126a7b32003-04-20 22:09:23 +0000770 for(i = 0;i < info.frame_size;i++)
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000771 {
772 if(i && !(i % 16))
773 DEBUGF("\n");
774
775 DEBUGF("%02x ", buf[i]);
776 }
777#endif
778
Linus Nielsen Feltzing7fdef572003-04-19 01:59:23 +0000779 return info.frame_size;
Linus Nielsen Feltzinga0390912003-03-10 14:55:31 +0000780}
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000781
782#endif