Move Info tab content to a separate widget.
[maemo-rb.git] / apps / mp3data.c
blob13ff0a87a7a6431238a89f15eaf175522eab19ec
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Daniel Stenberg
12 * 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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 * Parts of this code has been stolen from the Ample project and was written
24 * by David Härdeman. It has since been extended and enhanced pretty much by
25 * all sorts of friendly Rockbox people.
27 * A nice reference for MPEG header info:
28 * http://rockbox.haxx.se/docs/mpeghdr.html
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <stdbool.h>
36 #include <limits.h>
37 #include "debug.h"
38 #include "logf.h"
39 #include "mp3data.h"
40 #include "file.h"
41 #include "system.h"
43 //#define DEBUG_VERBOSE
45 #ifdef DEBUG_VERBOSE
46 #define VDEBUGF DEBUGF
47 #else
48 #define VDEBUGF(...) do { } while(0)
49 #endif
51 #define SYNC_MASK (0x7ffL << 21)
52 #define VERSION_MASK (3L << 19)
53 #define LAYER_MASK (3L << 17)
54 #define PROTECTION_MASK (1L << 16)
55 #define BITRATE_MASK (0xfL << 12)
56 #define SAMPLERATE_MASK (3L << 10)
57 #define PADDING_MASK (1L << 9)
58 #define PRIVATE_MASK (1L << 8)
59 #define CHANNELMODE_MASK (3L << 6)
60 #define MODE_EXT_MASK (3L << 4)
61 #define COPYRIGHT_MASK (1L << 3)
62 #define ORIGINAL_MASK (1L << 2)
63 #define EMPHASIS_MASK (3L)
65 /* Maximum number of bytes needed by Xing/Info/VBRI parser. */
66 #define VBR_HEADER_MAX_SIZE (180)
68 /* MPEG Version table, sorted by version index */
69 static const signed char version_table[4] = {
70 MPEG_VERSION2_5, -1, MPEG_VERSION2, MPEG_VERSION1
73 /* Bitrate table for mpeg audio, indexed by row index and birate index */
74 static const short bitrates[5][16] = {
75 {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, /* V1 L1 */
76 {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, /* V1 L2 */
77 {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0}, /* V1 L3 */
78 {0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256,0}, /* V2 L1 */
79 {0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0} /* V2 L2+L3 */
82 /* Bitrate pointer table, indexed by version and layer */
83 static const short *bitrate_table[3][3] =
85 {bitrates[0], bitrates[1], bitrates[2]},
86 {bitrates[3], bitrates[4], bitrates[4]},
87 {bitrates[3], bitrates[4], bitrates[4]}
90 /* Sampling frequency table, indexed by version and frequency index */
91 static const unsigned short freq_table[3][3] =
93 {44100, 48000, 32000}, /* MPEG Version 1 */
94 {22050, 24000, 16000}, /* MPEG version 2 */
95 {11025, 12000, 8000}, /* MPEG version 2.5 */
98 unsigned long bytes2int(unsigned long b0, unsigned long b1,
99 unsigned long b2, unsigned long b3)
101 return (b0 & 0xFF) << (3*8) |
102 (b1 & 0xFF) << (2*8) |
103 (b2 & 0xFF) << (1*8) |
104 (b3 & 0xFF) << (0*8);
107 /* check if 'head' is a valid mp3 frame header */
108 static bool is_mp3frameheader(unsigned long head)
110 if ((head & SYNC_MASK) != (unsigned long)SYNC_MASK) /* bad sync? */
111 return false;
112 if ((head & VERSION_MASK) == (1L << 19)) /* bad version? */
113 return false;
114 if (!(head & LAYER_MASK)) /* no layer? */
115 return false;
116 #if CONFIG_CODEC != SWCODEC
117 /* The MAS can't decode layer 1, so treat layer 1 data as invalid */
118 if ((head & LAYER_MASK) == LAYER_MASK)
119 return false;
120 #endif
121 if ((head & BITRATE_MASK) == BITRATE_MASK) /* bad bitrate? */
122 return false;
123 if (!(head & BITRATE_MASK)) /* no bitrate? */
124 return false;
125 if ((head & SAMPLERATE_MASK) == SAMPLERATE_MASK) /* bad sample rate? */
126 return false;
128 return true;
131 static bool mp3headerinfo(struct mp3info *info, unsigned long header)
133 int bitindex, freqindex;
135 /* MPEG Audio Version */
136 if ((header & VERSION_MASK) >> 19 >= sizeof(version_table))
137 return false;
139 info->version = version_table[(header & VERSION_MASK) >> 19];
140 if (info->version < 0)
141 return false;
143 /* Layer */
144 info->layer = 3 - ((header & LAYER_MASK) >> 17);
145 if (info->layer == 3)
146 return false;
148 /* Rockbox: not used
149 info->protection = (header & PROTECTION_MASK) ? true : false;
152 /* Bitrate */
153 bitindex = (header & BITRATE_MASK) >> 12;
154 info->bitrate = bitrate_table[info->version][info->layer][bitindex];
155 if(info->bitrate == 0)
156 return false;
158 /* Sampling frequency */
159 freqindex = (header & SAMPLERATE_MASK) >> 10;
160 if (freqindex == 3)
161 return false;
162 info->frequency = freq_table[info->version][freqindex];
164 info->padding = (header & PADDING_MASK) ? 1 : 0;
166 /* Calculate number of bytes, calculation depends on layer */
167 if (info->layer == 0) {
168 info->frame_samples = 384;
169 info->frame_size = (12000 * info->bitrate / info->frequency
170 + info->padding) * 4;
172 else {
173 if ((info->version > MPEG_VERSION1) && (info->layer == 2))
174 info->frame_samples = 576;
175 else
176 info->frame_samples = 1152;
177 info->frame_size = (1000/8) * info->frame_samples * info->bitrate
178 / info->frequency + info->padding;
181 /* Frametime fraction denominator */
182 if (freqindex != 0) { /* 48/32/24/16/12/8 kHz */
183 info->ft_den = 1; /* integer number of milliseconds */
185 else { /* 44.1/22.05/11.025 kHz */
186 if (info->layer == 0) /* layer 1 */
187 info->ft_den = 147;
188 else /* layer 2+3 */
189 info->ft_den = 49;
191 /* Frametime fraction numerator */
192 info->ft_num = 1000 * info->ft_den * info->frame_samples / info->frequency;
194 info->channel_mode = (header & CHANNELMODE_MASK) >> 6;
195 /* Rockbox: not used
196 info->mode_extension = (header & MODE_EXT_MASK) >> 4;
197 info->emphasis = header & EMPHASIS_MASK;
199 VDEBUGF( "Header: %08lx, Ver %d, lay %d, bitr %d, freq %ld, "
200 "chmode %d, bytes: %d time: %d/%d\n",
201 header, info->version, info->layer+1, info->bitrate,
202 info->frequency, info->channel_mode,
203 info->frame_size, info->ft_num, info->ft_den);
204 return true;
207 static bool headers_have_same_type(unsigned long header1,
208 unsigned long header2)
210 /* Compare MPEG version, layer and sampling frequency. If header1 is zero
211 * it is assumed both frame headers are of same type. */
212 unsigned int mask = SYNC_MASK | VERSION_MASK | LAYER_MASK | SAMPLERATE_MASK;
213 header1 &= mask;
214 header2 &= mask;
215 return header1 ? (header1 == header2) : true;
218 /* Helper function to read 4-byte in big endian format. */
219 static void read_uint32be_mp3data(int fd, unsigned long *data)
221 #ifdef ROCKBOX_BIG_ENDIAN
222 (void)read(fd, (char*)data, 4);
223 #else
224 (void)read(fd, (char*)data, 4);
225 *data = betoh32(*data);
226 #endif
229 static unsigned long __find_next_frame(int fd, long *offset, long max_offset,
230 unsigned long reference_header,
231 int(*getfunc)(int fd, unsigned char *c),
232 bool single_header)
234 unsigned long header=0;
235 unsigned char tmp;
236 long pos = 0;
238 /* We will search until we find two consecutive MPEG frame headers with
239 * the same MPEG version, layer and sampling frequency. The first header
240 * of this pair is assumed to be the first valid MPEG frame header of the
241 * whole stream. */
242 do {
243 /* Read 1 new byte. */
244 header <<= 8;
245 if (!getfunc(fd, &tmp))
246 return 0;
247 header |= tmp;
248 pos++;
250 /* Abort if max_offset is reached. Stop parsing. */
251 if (max_offset > 0 && pos > max_offset)
252 return 0;
254 if (is_mp3frameheader(header)) {
255 if (single_header) {
256 /* We search for one _single_ valid header that has the same
257 * type as the reference_header (if reference_header != 0).
258 * In this case we are finished. */
259 if (headers_have_same_type(reference_header, header))
260 break;
261 } else {
262 /* The current header is valid. Now gather the frame size,
263 * seek to this byte position and check if there is another
264 * valid MPEG frame header of the same type. */
265 struct mp3info info;
267 /* Gather frame size from given header and seek to next
268 * frame header. */
269 mp3headerinfo(&info, header);
270 lseek(fd, info.frame_size-4, SEEK_CUR);
272 /* Read possible next frame header and seek back to last frame
273 * headers byte position. */
274 reference_header = 0;
275 read_uint32be_mp3data(fd, &reference_header);
277 lseek(fd, -info.frame_size, SEEK_CUR);
279 /* If the current header is of the same type as the previous
280 * header we are finished. */
281 if (headers_have_same_type(header, reference_header))
282 break;
286 } while (true);
288 *offset = pos - 4;
290 if(*offset)
291 VDEBUGF("Warning: skipping %ld bytes of garbage\n", *offset);
293 return header;
296 static int fileread(int fd, unsigned char *c)
298 return read(fd, c, 1);
301 unsigned long find_next_frame(int fd,
302 long *offset,
303 long max_offset,
304 unsigned long reference_header)
306 return __find_next_frame(fd, offset, max_offset, reference_header,
307 fileread, true);
310 #ifndef __PCTOOL__
311 static int fnf_read_index;
312 static int fnf_buf_len;
313 static unsigned char *fnf_buf;
315 static int buf_getbyte(int fd, unsigned char *c)
317 if(fnf_read_index < fnf_buf_len)
319 *c = fnf_buf[fnf_read_index++];
320 return 1;
322 else
324 fnf_buf_len = read(fd, fnf_buf, fnf_buf_len);
325 if(fnf_buf_len < 0)
326 return -1;
328 fnf_read_index = 0;
330 if(fnf_buf_len > 0)
332 *c = fnf_buf[fnf_read_index++];
333 return 1;
335 else
336 return 0;
338 return 0;
341 static int buf_seek(int fd, int len)
343 fnf_read_index += len;
344 if(fnf_read_index > fnf_buf_len)
346 len = fnf_read_index - fnf_buf_len;
348 fnf_buf_len = read(fd, fnf_buf, fnf_buf_len);
349 if(fnf_buf_len < 0)
350 return -1;
352 fnf_read_index = 0;
353 fnf_read_index += len;
356 if(fnf_read_index > fnf_buf_len)
358 return -1;
360 else
361 return 0;
364 static void buf_init(unsigned char* buf, size_t buflen)
366 fnf_buf = buf;
367 fnf_buf_len = buflen;
368 fnf_read_index = 0;
371 static unsigned long buf_find_next_frame(int fd, long *offset, long max_offset)
373 return __find_next_frame(fd, offset, max_offset, 0, buf_getbyte, true);
376 static size_t mem_buflen;
377 static unsigned char* mem_buf;
378 static size_t mem_pos;
379 static int mem_cnt;
380 static int mem_maxlen;
382 static int mem_getbyte(int dummy, unsigned char *c)
384 (void)dummy;
386 *c = mem_buf[mem_pos++];
387 if(mem_pos >= mem_buflen)
388 mem_pos = 0;
390 if(mem_cnt++ >= mem_maxlen)
391 return 0;
392 else
393 return 1;
396 unsigned long mem_find_next_frame(int startpos,
397 long *offset,
398 long max_offset,
399 unsigned long reference_header,
400 unsigned char* buf, size_t buflen)
402 mem_buf = buf;
403 mem_buflen = buflen;
404 mem_pos = startpos;
405 mem_cnt = 0;
406 mem_maxlen = max_offset;
408 return __find_next_frame(0, offset, max_offset, reference_header,
409 mem_getbyte, true);
411 #endif
413 /* Extract information from a 'Xing' or 'Info' header. */
414 static void get_xing_info(struct mp3info *info, unsigned char *buf)
416 int i = 8;
418 /* Is it a VBR file? */
419 info->is_vbr = !memcmp(buf, "Xing", 4);
421 if (buf[7] & VBR_FRAMES_FLAG) /* Is the frame count there? */
423 info->frame_count = bytes2int(buf[i], buf[i+1], buf[i+2], buf[i+3]);
424 if (info->frame_count <= ULONG_MAX / info->ft_num)
425 info->file_time = info->frame_count * info->ft_num / info->ft_den;
426 else
427 info->file_time = info->frame_count / info->ft_den * info->ft_num;
428 i += 4;
431 if (buf[7] & VBR_BYTES_FLAG) /* Is byte count there? */
433 info->byte_count = bytes2int(buf[i], buf[i+1], buf[i+2], buf[i+3]);
434 i += 4;
437 if (info->file_time && info->byte_count)
439 if (info->byte_count <= (ULONG_MAX/8))
440 info->bitrate = info->byte_count * 8 / info->file_time;
441 else
442 info->bitrate = info->byte_count / (info->file_time >> 3);
445 if (buf[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */
447 info->has_toc = true;
448 memcpy( info->toc, buf+i, 100 );
449 i += 100;
451 if (buf[7] & VBR_QUALITY_FLAG)
453 /* We don't care about this, but need to skip it */
454 i += 4;
456 #if CONFIG_CODEC==SWCODEC
457 i += 21;
458 info->enc_delay = ((int)buf[i ] << 4) | (buf[i+1] >> 4);
459 info->enc_padding = ((int)(buf[i+1]&0xF) << 8) | buf[i+2];
460 /* TODO: This sanity checking is rather silly, seeing as how the LAME
461 header contains a CRC field that can be used to verify integrity. */
462 if (!(info->enc_delay >= 0 && info->enc_delay <= 2880 &&
463 info->enc_padding >= 0 && info->enc_padding <= 2*1152))
465 /* Invalid data */
466 info->enc_delay = -1;
467 info->enc_padding = -1;
469 #endif
472 /* Extract information from a 'VBRI' header. */
473 static void get_vbri_info(struct mp3info *info, unsigned char *buf)
475 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
477 int i, num_offsets, offset = 0;
480 info->is_vbr = true; /* Yes, it is a FhG VBR file */
481 info->has_toc = false; /* We don't parse the TOC (yet) */
483 info->byte_count = bytes2int(buf[10], buf[11], buf[12], buf[13]);
484 info->frame_count = bytes2int(buf[14], buf[15], buf[16], buf[17]);
485 if (info->frame_count <= ULONG_MAX / info->ft_num)
486 info->file_time = info->frame_count * info->ft_num / info->ft_den;
487 else
488 info->file_time = info->frame_count / info->ft_den * info->ft_num;
490 if (info->byte_count <= (ULONG_MAX/8))
491 info->bitrate = info->byte_count * 8 / info->file_time;
492 else
493 info->bitrate = info->byte_count / (info->file_time >> 3);
495 VDEBUGF("Frame size (%dkpbs): %d bytes (0x%x)\n",
496 info->bitrate, info->frame_size, info->frame_size);
497 VDEBUGF("Frame count: %lx\n", info->frame_count);
498 VDEBUGF("Byte count: %lx\n", info->byte_count);
500 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
502 num_offsets = bytes2int(0, 0, buf[18], buf[19]);
503 VDEBUGF("Offsets: %d\n", num_offsets);
504 VDEBUGF("Frames/entry: %ld\n", bytes2int(0, 0, buf[24], buf[25]));
506 for(i = 0; i < num_offsets; i++)
508 offset += bytes2int(0, 0, buf[26+i*2], buf[27+i*2]);;
509 VDEBUGF("%03d: %lx\n", i, offset - bytecount,);
514 /* Seek to next mpeg header and extract relevant information. */
515 static int get_next_header_info(int fd, long *bytecount, struct mp3info *info,
516 bool single_header)
518 long tmp;
519 unsigned long header = 0;
521 header = __find_next_frame(fd, &tmp, 0x20000, 0, fileread, single_header);
522 if(header == 0)
523 return -1;
525 if(!mp3headerinfo(info, header))
526 return -2;
528 /* Next frame header is tmp bytes away. */
529 *bytecount += tmp;
531 return 0;
534 int get_mp3file_info(int fd, struct mp3info *info)
536 unsigned char frame[VBR_HEADER_MAX_SIZE], *vbrheader;
537 long bytecount = 0;
538 int result, buf_size;
540 /* Initialize info and frame */
541 memset(info, 0, sizeof(struct mp3info));
542 memset(frame, 0, sizeof(frame));
544 #if CONFIG_CODEC==SWCODEC
545 /* These two are needed for proper LAME gapless MP3 playback */
546 info->enc_delay = -1;
547 info->enc_padding = -1;
548 #endif
550 /* Get the very first single MPEG frame. */
551 result = get_next_header_info(fd, &bytecount, info, true);
552 if(result)
553 return result;
555 /* Read the amount of frame data to the buffer that is required for the
556 * vbr tag parsing. Skip the rest. */
557 buf_size = MIN(info->frame_size-4, (int)sizeof(frame));
558 if(read(fd, frame, buf_size) < 0)
559 return -3;
560 lseek(fd, info->frame_size - 4 - buf_size, SEEK_CUR);
562 /* Calculate position of a possible VBR header */
563 if (info->version == MPEG_VERSION1) {
564 if (info->channel_mode == 3) /* mono */
565 vbrheader = frame + 17;
566 else
567 vbrheader = frame + 32;
568 } else {
569 if (info->channel_mode == 3) /* mono */
570 vbrheader = frame + 9;
571 else
572 vbrheader = frame + 17;
575 if (!memcmp(vbrheader, "Xing", 4) || !memcmp(vbrheader, "Info", 4))
577 VDEBUGF("-- XING header --\n");
579 /* We want to skip the Xing frame when playing the stream */
580 bytecount += info->frame_size;
582 /* Now get the next frame to read the real info about the mp3 stream */
583 result = get_next_header_info(fd, &bytecount, info, false);
584 if(result)
585 return result;
587 get_xing_info(info, vbrheader);
589 else if (!memcmp(vbrheader, "VBRI", 4))
591 VDEBUGF("-- VBRI header --\n");
593 /* We want to skip the VBRI frame when playing the stream */
594 bytecount += info->frame_size;
596 /* Now get the next frame to read the real info about the mp3 stream */
597 result = get_next_header_info(fd, &bytecount, info, false);
598 if(result)
599 return result;
601 get_vbri_info(info, vbrheader);
603 else
605 VDEBUGF("-- No VBR header --\n");
607 /* There was no VBR header found. So, we seek back to beginning and
608 * search for the first MPEG frame header of the mp3 stream. */
609 lseek(fd, -info->frame_size, SEEK_CUR);
610 result = get_next_header_info(fd, &bytecount, info, false);
611 if(result)
612 return result;
615 return bytecount;
618 #ifndef __PCTOOL__
619 static void long2bytes(unsigned char *buf, long val)
621 buf[0] = (val >> 24) & 0xff;
622 buf[1] = (val >> 16) & 0xff;
623 buf[2] = (val >> 8) & 0xff;
624 buf[3] = val & 0xff;
627 int count_mp3_frames(int fd, int startpos, int filesize,
628 void (*progressfunc)(int),
629 unsigned char* buf, size_t buflen)
631 unsigned long header = 0;
632 struct mp3info info;
633 int num_frames;
634 long bytes;
635 int cnt;
636 long progress_chunk = filesize / 50; /* Max is 50%, in 1% increments */
637 int progress_cnt = 0;
638 bool is_vbr = false;
639 int last_bitrate = 0;
640 int header_template = 0;
642 if(lseek(fd, startpos, SEEK_SET) < 0)
643 return -1;
645 buf_init(buf, buflen);
647 /* Find out the total number of frames */
648 num_frames = 0;
649 cnt = 0;
651 while((header = buf_find_next_frame(fd, &bytes, header_template))) {
652 mp3headerinfo(&info, header);
654 if(!header_template)
655 header_template = header;
657 /* See if this really is a VBR file */
658 if(last_bitrate && info.bitrate != last_bitrate)
660 is_vbr = true;
662 last_bitrate = info.bitrate;
664 buf_seek(fd, info.frame_size-4);
665 num_frames++;
666 if(progressfunc)
668 cnt += bytes + info.frame_size;
669 if(cnt > progress_chunk)
671 progress_cnt++;
672 progressfunc(progress_cnt);
673 cnt = 0;
677 VDEBUGF("Total number of frames: %d\n", num_frames);
679 if(is_vbr)
680 return num_frames;
681 else
683 DEBUGF("Not a VBR file\n");
684 return 0;
688 static const char cooltext[] = "Rockbox - rocks your box";
690 /* buf needs to be the audio buffer with TOC generation enabled,
691 and at least MAX_XING_HEADER_SIZE bytes otherwise */
692 int create_xing_header(int fd, long startpos, long filesize,
693 unsigned char *buf, unsigned long num_frames,
694 unsigned long rec_time, unsigned long header_template,
695 void (*progressfunc)(int), bool generate_toc,
696 unsigned char *tempbuf, size_t tempbuflen )
698 struct mp3info info;
699 unsigned char toc[100];
700 unsigned long header = 0;
701 unsigned long xing_header_template = header_template;
702 unsigned long filepos;
703 long pos, last_pos;
704 long j;
705 long bytes;
706 int i;
707 int index;
709 DEBUGF("create_xing_header()\n");
711 if(generate_toc)
713 lseek(fd, startpos, SEEK_SET);
714 buf_init(tempbuf, tempbuflen);
716 /* Generate filepos table */
717 last_pos = 0;
718 filepos = 0;
719 header = 0;
720 for(i = 0;i < 100;i++) {
721 /* Calculate the absolute frame number for this seek point */
722 pos = i * num_frames / 100;
724 /* Advance from the last seek point to this one */
725 for(j = 0;j < pos - last_pos;j++)
727 header = buf_find_next_frame(fd, &bytes, header_template);
728 filepos += bytes;
729 mp3headerinfo(&info, header);
730 buf_seek(fd, info.frame_size-4);
731 filepos += info.frame_size;
733 if(!header_template)
734 header_template = header;
737 /* Save a header for later use if header_template is empty.
738 We only save one header, and we want to save one in the
739 middle of the stream, just in case the first and the last
740 headers are corrupt. */
741 if(!xing_header_template && i == 1)
742 xing_header_template = header;
744 if(progressfunc)
746 progressfunc(50 + i/2);
749 /* Fill in the TOC entry */
750 /* each toc is a single byte indicating how many 256ths of the
751 * way through the file, is that percent of the way through the
752 * song. the easy method, filepos*256/filesize, chokes when
753 * the upper 8 bits of the file position are nonzero
754 * (i.e. files over 16mb in size).
756 if (filepos > (ULONG_MAX/256))
758 /* instead of multiplying filepos by 256, we divide
759 * filesize by 256.
761 toc[i] = filepos / (filesize >> 8);
763 else
765 toc[i] = filepos * 256 / filesize;
768 VDEBUGF("Pos %d: %ld relpos: %ld filepos: %lx tocentry: %x\n",
769 i, pos, pos-last_pos, filepos, toc[i]);
771 last_pos = pos;
775 /* Use the template header and create a new one.
776 We ignore the Protection bit even if the rest of the stream is
777 protected. */
778 header = xing_header_template & ~(BITRATE_MASK|PROTECTION_MASK|PADDING_MASK);
779 header |= 8 << 12; /* This gives us plenty of space, 192..576 bytes */
781 if (!mp3headerinfo(&info, header))
782 return 0; /* invalid header */
784 if (num_frames == 0 && rec_time) {
785 /* estimate the number of frames based on the recording time */
786 if (rec_time <= ULONG_MAX / info.ft_den)
787 num_frames = rec_time * info.ft_den / info.ft_num;
788 else
789 num_frames = rec_time / info.ft_num * info.ft_den;
792 /* Clear the frame */
793 memset(buf, 0, MAX_XING_HEADER_SIZE);
795 /* Write the header to the buffer */
796 long2bytes(buf, header);
798 /* Calculate position of VBR header */
799 if (info.version == MPEG_VERSION1) {
800 if (info.channel_mode == 3) /* mono */
801 index = 21;
802 else
803 index = 36;
805 else {
806 if (info.channel_mode == 3) /* mono */
807 index = 13;
808 else
809 index = 21;
812 /* Create the Xing data */
813 memcpy(&buf[index], "Xing", 4);
814 long2bytes(&buf[index+4], (num_frames ? VBR_FRAMES_FLAG : 0)
815 | (filesize ? VBR_BYTES_FLAG : 0)
816 | (generate_toc ? VBR_TOC_FLAG : 0));
817 index += 8;
818 if(num_frames)
820 long2bytes(&buf[index], num_frames);
821 index += 4;
824 if(filesize)
826 long2bytes(&buf[index], filesize - startpos);
827 index += 4;
830 /* Copy the TOC */
831 memcpy(buf + index, toc, 100);
833 /* And some extra cool info */
834 memcpy(buf + index + 100, cooltext, sizeof(cooltext));
836 #ifdef DEBUG
837 for(i = 0;i < info.frame_size;i++)
839 if(i && !(i % 16))
840 DEBUGF("\n");
842 DEBUGF("%02x ", buf[i]);
844 #endif
846 return info.frame_size;
849 #endif