Replace all direct accesses to audiobuf with buffer API functions.
[kugel-rb.git] / apps / mp3data.c
blob53f13f4f6412645ca8d1fb2105ded8289eb66165
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 "buffer.h"
42 #include "system.h"
44 //#define DEBUG_VERBOSE
46 #ifdef DEBUG_VERBOSE
47 #define VDEBUGF DEBUGF
48 #else
49 #define VDEBUGF(...) do { } while(0)
50 #endif
52 #define SYNC_MASK (0x7ffL << 21)
53 #define VERSION_MASK (3L << 19)
54 #define LAYER_MASK (3L << 17)
55 #define PROTECTION_MASK (1L << 16)
56 #define BITRATE_MASK (0xfL << 12)
57 #define SAMPLERATE_MASK (3L << 10)
58 #define PADDING_MASK (1L << 9)
59 #define PRIVATE_MASK (1L << 8)
60 #define CHANNELMODE_MASK (3L << 6)
61 #define MODE_EXT_MASK (3L << 4)
62 #define COPYRIGHT_MASK (1L << 3)
63 #define ORIGINAL_MASK (1L << 2)
64 #define EMPHASIS_MASK (3L)
66 /* Maximum number of bytes needed by Xing/Info/VBRI parser. */
67 #define VBR_HEADER_MAX_SIZE (180)
69 /* MPEG Version table, sorted by version index */
70 static const signed char version_table[4] = {
71 MPEG_VERSION2_5, -1, MPEG_VERSION2, MPEG_VERSION1
74 /* Bitrate table for mpeg audio, indexed by row index and birate index */
75 static const short bitrates[5][16] = {
76 {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, /* V1 L1 */
77 {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, /* V1 L2 */
78 {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0}, /* V1 L3 */
79 {0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256,0}, /* V2 L1 */
80 {0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0} /* V2 L2+L3 */
83 /* Bitrate pointer table, indexed by version and layer */
84 static const short *bitrate_table[3][3] =
86 {bitrates[0], bitrates[1], bitrates[2]},
87 {bitrates[3], bitrates[4], bitrates[4]},
88 {bitrates[3], bitrates[4], bitrates[4]}
91 /* Sampling frequency table, indexed by version and frequency index */
92 static const unsigned short freq_table[3][3] =
94 {44100, 48000, 32000}, /* MPEG Version 1 */
95 {22050, 24000, 16000}, /* MPEG version 2 */
96 {11025, 12000, 8000}, /* MPEG version 2.5 */
99 unsigned long bytes2int(unsigned long b0, unsigned long b1,
100 unsigned long b2, unsigned long b3)
102 return (b0 & 0xFF) << (3*8) |
103 (b1 & 0xFF) << (2*8) |
104 (b2 & 0xFF) << (1*8) |
105 (b3 & 0xFF) << (0*8);
108 /* check if 'head' is a valid mp3 frame header */
109 static bool is_mp3frameheader(unsigned long head)
111 if ((head & SYNC_MASK) != (unsigned long)SYNC_MASK) /* bad sync? */
112 return false;
113 if ((head & VERSION_MASK) == (1L << 19)) /* bad version? */
114 return false;
115 if (!(head & LAYER_MASK)) /* no layer? */
116 return false;
117 #if CONFIG_CODEC != SWCODEC
118 /* The MAS can't decode layer 1, so treat layer 1 data as invalid */
119 if ((head & LAYER_MASK) == LAYER_MASK)
120 return false;
121 #endif
122 if ((head & BITRATE_MASK) == BITRATE_MASK) /* bad bitrate? */
123 return false;
124 if (!(head & BITRATE_MASK)) /* no bitrate? */
125 return false;
126 if ((head & SAMPLERATE_MASK) == SAMPLERATE_MASK) /* bad sample rate? */
127 return false;
129 return true;
132 static bool mp3headerinfo(struct mp3info *info, unsigned long header)
134 int bitindex, freqindex;
136 /* MPEG Audio Version */
137 if ((header & VERSION_MASK) >> 19 >= sizeof(version_table))
138 return false;
140 info->version = version_table[(header & VERSION_MASK) >> 19];
141 if (info->version < 0)
142 return false;
144 /* Layer */
145 info->layer = 3 - ((header & LAYER_MASK) >> 17);
146 if (info->layer == 3)
147 return false;
149 /* Rockbox: not used
150 info->protection = (header & PROTECTION_MASK) ? true : false;
153 /* Bitrate */
154 bitindex = (header & BITRATE_MASK) >> 12;
155 info->bitrate = bitrate_table[info->version][info->layer][bitindex];
156 if(info->bitrate == 0)
157 return false;
159 /* Sampling frequency */
160 freqindex = (header & SAMPLERATE_MASK) >> 10;
161 if (freqindex == 3)
162 return false;
163 info->frequency = freq_table[info->version][freqindex];
165 info->padding = (header & PADDING_MASK) ? 1 : 0;
167 /* Calculate number of bytes, calculation depends on layer */
168 if (info->layer == 0) {
169 info->frame_samples = 384;
170 info->frame_size = (12000 * info->bitrate / info->frequency
171 + info->padding) * 4;
173 else {
174 if ((info->version > MPEG_VERSION1) && (info->layer == 2))
175 info->frame_samples = 576;
176 else
177 info->frame_samples = 1152;
178 info->frame_size = (1000/8) * info->frame_samples * info->bitrate
179 / info->frequency + info->padding;
182 /* Frametime fraction denominator */
183 if (freqindex != 0) { /* 48/32/24/16/12/8 kHz */
184 info->ft_den = 1; /* integer number of milliseconds */
186 else { /* 44.1/22.05/11.025 kHz */
187 if (info->layer == 0) /* layer 1 */
188 info->ft_den = 147;
189 else /* layer 2+3 */
190 info->ft_den = 49;
192 /* Frametime fraction numerator */
193 info->ft_num = 1000 * info->ft_den * info->frame_samples / info->frequency;
195 info->channel_mode = (header & CHANNELMODE_MASK) >> 6;
196 /* Rockbox: not used
197 info->mode_extension = (header & MODE_EXT_MASK) >> 4;
198 info->emphasis = header & EMPHASIS_MASK;
200 VDEBUGF( "Header: %08lx, Ver %d, lay %d, bitr %d, freq %ld, "
201 "chmode %d, bytes: %d time: %d/%d\n",
202 header, info->version, info->layer+1, info->bitrate,
203 info->frequency, info->channel_mode,
204 info->frame_size, info->ft_num, info->ft_den);
205 return true;
208 static bool headers_have_same_type(unsigned long header1,
209 unsigned long header2)
211 /* Compare MPEG version, layer and sampling frequency. If header1 is zero
212 * it is assumed both frame headers are of same type. */
213 unsigned int mask = SYNC_MASK | VERSION_MASK | LAYER_MASK | SAMPLERATE_MASK;
214 header1 &= mask;
215 header2 &= mask;
216 return header1 ? (header1 == header2) : true;
219 /* Helper function to read 4-byte in big endian format. */
220 static void read_uint32be_mp3data(int fd, unsigned long *data)
222 #ifdef ROCKBOX_BIG_ENDIAN
223 (void)read(fd, (char*)data, 4);
224 #else
225 (void)read(fd, (char*)data, 4);
226 *data = betoh32(*data);
227 #endif
230 static unsigned long __find_next_frame(int fd, long *offset, long max_offset,
231 unsigned long reference_header,
232 int(*getfunc)(int fd, unsigned char *c),
233 bool single_header)
235 unsigned long header=0;
236 unsigned char tmp;
237 long pos = 0;
239 /* We will search until we find two consecutive MPEG frame headers with
240 * the same MPEG version, layer and sampling frequency. The first header
241 * of this pair is assumed to be the first valid MPEG frame header of the
242 * whole stream. */
243 do {
244 /* Read 1 new byte. */
245 header <<= 8;
246 if (!getfunc(fd, &tmp))
247 return 0;
248 header |= tmp;
249 pos++;
251 /* Abort if max_offset is reached. Stop parsing. */
252 if (max_offset > 0 && pos > max_offset)
253 return 0;
255 if (is_mp3frameheader(header)) {
256 if (single_header) {
257 /* We search for one _single_ valid header that has the same
258 * type as the reference_header (if reference_header != 0).
259 * In this case we are finished. */
260 if (headers_have_same_type(reference_header, header))
261 break;
262 } else {
263 /* The current header is valid. Now gather the frame size,
264 * seek to this byte position and check if there is another
265 * valid MPEG frame header of the same type. */
266 struct mp3info info;
268 /* Gather frame size from given header and seek to next
269 * frame header. */
270 mp3headerinfo(&info, header);
271 lseek(fd, info.frame_size-4, SEEK_CUR);
273 /* Read possible next frame header and seek back to last frame
274 * headers byte position. */
275 reference_header = 0;
276 read_uint32be_mp3data(fd, &reference_header);
278 lseek(fd, -info.frame_size, SEEK_CUR);
280 /* If the current header is of the same type as the previous
281 * header we are finished. */
282 if (headers_have_same_type(header, reference_header))
283 break;
287 } while (true);
289 *offset = pos - 4;
291 if(*offset)
292 VDEBUGF("Warning: skipping %ld bytes of garbage\n", *offset);
294 return header;
297 static int fileread(int fd, unsigned char *c)
299 return read(fd, c, 1);
302 unsigned long find_next_frame(int fd,
303 long *offset,
304 long max_offset,
305 unsigned long reference_header)
307 return __find_next_frame(fd, offset, max_offset, reference_header,
308 fileread, true);
311 #ifndef __PCTOOL__
312 static int fnf_read_index;
313 static int fnf_buf_len;
314 static unsigned char *fnf_buf;
316 static int buf_getbyte(int fd, unsigned char *c)
318 if(fnf_read_index < fnf_buf_len)
320 *c = fnf_buf[fnf_read_index++];
321 return 1;
323 else
325 fnf_buf_len = read(fd, fnf_buf, fnf_buf_len);
326 if(fnf_buf_len < 0)
327 return -1;
329 fnf_read_index = 0;
331 if(fnf_buf_len > 0)
333 *c = fnf_buf[fnf_read_index++];
334 return 1;
336 else
337 return 0;
339 return 0;
342 static int buf_seek(int fd, int len)
344 fnf_read_index += len;
345 if(fnf_read_index > fnf_buf_len)
347 len = fnf_read_index - fnf_buf_len;
349 fnf_buf_len = read(fd, fnf_buf, fnf_buf_len);
350 if(fnf_buf_len < 0)
351 return -1;
353 fnf_read_index = 0;
354 fnf_read_index += len;
357 if(fnf_read_index > fnf_buf_len)
359 return -1;
361 else
362 return 0;
365 static void buf_init(unsigned char* buf, size_t buflen)
367 fnf_buf = buf;
368 fnf_buf_len = buflen;
369 fnf_read_index = 0;
372 static unsigned long buf_find_next_frame(int fd, long *offset, long max_offset)
374 return __find_next_frame(fd, offset, max_offset, 0, buf_getbyte, true);
377 static size_t mem_buflen;
378 static unsigned char* mem_buf;
379 static size_t mem_pos;
380 static int mem_cnt;
381 static int mem_maxlen;
383 static int mem_getbyte(int dummy, unsigned char *c)
385 dummy = dummy;
387 *c = mem_buf[mem_pos++];
388 if(mem_pos >= mem_buflen)
389 mem_pos = 0;
391 if(mem_cnt++ >= mem_maxlen)
392 return 0;
393 else
394 return 1;
397 unsigned long mem_find_next_frame(int startpos,
398 long *offset,
399 long max_offset,
400 unsigned long reference_header,
401 unsigned char* buf, size_t buflen)
403 mem_buf = buf;
404 mem_buflen = buflen;
405 mem_pos = startpos;
406 mem_cnt = 0;
407 mem_maxlen = max_offset;
409 return __find_next_frame(0, offset, max_offset, reference_header,
410 mem_getbyte, true);
412 #endif
414 /* Extract information from a 'Xing' or 'Info' header. */
415 static void get_xing_info(struct mp3info *info, unsigned char *buf)
417 int i = 8;
419 /* Is it a VBR file? */
420 info->is_vbr = !memcmp(buf, "Xing", 4);
422 if (buf[7] & VBR_FRAMES_FLAG) /* Is the frame count there? */
424 info->frame_count = bytes2int(buf[i], buf[i+1], buf[i+2], buf[i+3]);
425 if (info->frame_count <= ULONG_MAX / info->ft_num)
426 info->file_time = info->frame_count * info->ft_num / info->ft_den;
427 else
428 info->file_time = info->frame_count / info->ft_den * info->ft_num;
429 i += 4;
432 if (buf[7] & VBR_BYTES_FLAG) /* Is byte count there? */
434 info->byte_count = bytes2int(buf[i], buf[i+1], buf[i+2], buf[i+3]);
435 i += 4;
438 if (info->file_time && info->byte_count)
440 if (info->byte_count <= (ULONG_MAX/8))
441 info->bitrate = info->byte_count * 8 / info->file_time;
442 else
443 info->bitrate = info->byte_count / (info->file_time >> 3);
446 if (buf[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */
448 info->has_toc = true;
449 memcpy( info->toc, buf+i, 100 );
450 i += 100;
452 if (buf[7] & VBR_QUALITY_FLAG)
454 /* We don't care about this, but need to skip it */
455 i += 4;
457 #if CONFIG_CODEC==SWCODEC
458 i += 21;
459 info->enc_delay = ((int)buf[i ] << 4) | (buf[i+1] >> 4);
460 info->enc_padding = ((int)(buf[i+1]&0xF) << 8) | buf[i+2];
461 /* TODO: This sanity checking is rather silly, seeing as how the LAME
462 header contains a CRC field that can be used to verify integrity. */
463 if (!(info->enc_delay >= 0 && info->enc_delay <= 2880 &&
464 info->enc_padding >= 0 && info->enc_padding <= 2*1152))
466 /* Invalid data */
467 info->enc_delay = -1;
468 info->enc_padding = -1;
470 #endif
473 /* Extract information from a 'VBRI' header. */
474 static void get_vbri_info(struct mp3info *info, unsigned char *buf)
476 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
478 int i, num_offsets, offset = 0;
481 info->is_vbr = true; /* Yes, it is a FhG VBR file */
482 info->has_toc = false; /* We don't parse the TOC (yet) */
484 info->byte_count = bytes2int(buf[10], buf[11], buf[12], buf[13]);
485 info->frame_count = bytes2int(buf[14], buf[15], buf[16], buf[17]);
486 if (info->frame_count <= ULONG_MAX / info->ft_num)
487 info->file_time = info->frame_count * info->ft_num / info->ft_den;
488 else
489 info->file_time = info->frame_count / info->ft_den * info->ft_num;
491 if (info->byte_count <= (ULONG_MAX/8))
492 info->bitrate = info->byte_count * 8 / info->file_time;
493 else
494 info->bitrate = info->byte_count / (info->file_time >> 3);
496 VDEBUGF("Frame size (%dkpbs): %d bytes (0x%x)\n",
497 info->bitrate, info->frame_size, info->frame_size);
498 VDEBUGF("Frame count: %lx\n", info->frame_count);
499 VDEBUGF("Byte count: %lx\n", info->byte_count);
501 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
503 num_offsets = bytes2int(0, 0, buf[18], buf[19]);
504 VDEBUGF("Offsets: %d\n", num_offsets);
505 VDEBUGF("Frames/entry: %ld\n", bytes2int(0, 0, buf[24], buf[25]));
507 for(i = 0; i < num_offsets; i++)
509 offset += bytes2int(0, 0, buf[26+i*2], buf[27+i*2]);;
510 VDEBUGF("%03d: %lx\n", i, offset - bytecount,);
515 /* Seek to next mpeg header and extract relevant information. */
516 static int get_next_header_info(int fd, long *bytecount, struct mp3info *info,
517 bool single_header)
519 long tmp;
520 unsigned long header = 0;
522 header = __find_next_frame(fd, &tmp, 0x20000, 0, fileread, single_header);
523 if(header == 0)
524 return -1;
526 if(!mp3headerinfo(info, header))
527 return -2;
529 /* Next frame header is tmp bytes away. */
530 *bytecount += tmp;
532 return 0;
535 int get_mp3file_info(int fd, struct mp3info *info)
537 unsigned char frame[VBR_HEADER_MAX_SIZE], *vbrheader;
538 long bytecount = 0;
539 int result, buf_size;
541 /* Initialize info and frame */
542 memset(info, 0, sizeof(struct mp3info));
543 memset(frame, 0, sizeof(frame));
545 #if CONFIG_CODEC==SWCODEC
546 /* These two are needed for proper LAME gapless MP3 playback */
547 info->enc_delay = -1;
548 info->enc_padding = -1;
549 #endif
551 /* Get the very first single MPEG frame. */
552 result = get_next_header_info(fd, &bytecount, info, true);
553 if(result)
554 return result;
556 /* Read the amount of frame data to the buffer that is required for the
557 * vbr tag parsing. Skip the rest. */
558 buf_size = MIN(info->frame_size-4, (int)sizeof(frame));
559 if(read(fd, frame, buf_size) < 0)
560 return -3;
561 lseek(fd, info->frame_size - 4 - buf_size, SEEK_CUR);
563 /* Calculate position of a possible VBR header */
564 if (info->version == MPEG_VERSION1) {
565 if (info->channel_mode == 3) /* mono */
566 vbrheader = frame + 17;
567 else
568 vbrheader = frame + 32;
569 } else {
570 if (info->channel_mode == 3) /* mono */
571 vbrheader = frame + 9;
572 else
573 vbrheader = frame + 17;
576 if (!memcmp(vbrheader, "Xing", 4) || !memcmp(vbrheader, "Info", 4))
578 VDEBUGF("-- XING header --\n");
580 /* We want to skip the Xing frame when playing the stream */
581 bytecount += info->frame_size;
583 /* Now get the next frame to read the real info about the mp3 stream */
584 result = get_next_header_info(fd, &bytecount, info, false);
585 if(result)
586 return result;
588 get_xing_info(info, vbrheader);
590 else if (!memcmp(vbrheader, "VBRI", 4))
592 VDEBUGF("-- VBRI header --\n");
594 /* We want to skip the VBRI frame when playing the stream */
595 bytecount += info->frame_size;
597 /* Now get the next frame to read the real info about the mp3 stream */
598 result = get_next_header_info(fd, &bytecount, info, false);
599 if(result)
600 return result;
602 get_vbri_info(info, vbrheader);
604 else
606 VDEBUGF("-- No VBR header --\n");
608 /* There was no VBR header found. So, we seek back to beginning and
609 * search for the first MPEG frame header of the mp3 stream. */
610 lseek(fd, -info->frame_size, SEEK_CUR);
611 result = get_next_header_info(fd, &bytecount, info, false);
612 if(result)
613 return result;
616 return bytecount;
619 #ifndef __PCTOOL__
620 static void long2bytes(unsigned char *buf, long val)
622 buf[0] = (val >> 24) & 0xff;
623 buf[1] = (val >> 16) & 0xff;
624 buf[2] = (val >> 8) & 0xff;
625 buf[3] = val & 0xff;
628 int count_mp3_frames(int fd, int startpos, int filesize,
629 void (*progressfunc)(int),
630 unsigned char* buf, size_t buflen)
632 unsigned long header = 0;
633 struct mp3info info;
634 int num_frames;
635 long bytes;
636 int cnt;
637 long progress_chunk = filesize / 50; /* Max is 50%, in 1% increments */
638 int progress_cnt = 0;
639 bool is_vbr = false;
640 int last_bitrate = 0;
641 int header_template = 0;
643 if(lseek(fd, startpos, SEEK_SET) < 0)
644 return -1;
646 buf_init(buf, buflen);
648 /* Find out the total number of frames */
649 num_frames = 0;
650 cnt = 0;
652 while((header = buf_find_next_frame(fd, &bytes, header_template))) {
653 mp3headerinfo(&info, header);
655 if(!header_template)
656 header_template = header;
658 /* See if this really is a VBR file */
659 if(last_bitrate && info.bitrate != last_bitrate)
661 is_vbr = true;
663 last_bitrate = info.bitrate;
665 buf_seek(fd, info.frame_size-4);
666 num_frames++;
667 if(progressfunc)
669 cnt += bytes + info.frame_size;
670 if(cnt > progress_chunk)
672 progress_cnt++;
673 progressfunc(progress_cnt);
674 cnt = 0;
678 VDEBUGF("Total number of frames: %d\n", num_frames);
680 if(is_vbr)
681 return num_frames;
682 else
684 DEBUGF("Not a VBR file\n");
685 return 0;
689 static const char cooltext[] = "Rockbox - rocks your box";
691 /* buf needs to be the audio buffer with TOC generation enabled,
692 and at least MAX_XING_HEADER_SIZE bytes otherwise */
693 int create_xing_header(int fd, long startpos, long filesize,
694 unsigned char *buf, unsigned long num_frames,
695 unsigned long rec_time, unsigned long header_template,
696 void (*progressfunc)(int), bool generate_toc,
697 unsigned char *tempbuf, size_t tempbuflen )
699 struct mp3info info;
700 unsigned char toc[100];
701 unsigned long header = 0;
702 unsigned long xing_header_template = header_template;
703 unsigned long filepos;
704 long pos, last_pos;
705 long j;
706 long bytes;
707 int i;
708 int index;
710 DEBUGF("create_xing_header()\n");
712 if(generate_toc)
714 lseek(fd, startpos, SEEK_SET);
715 buf_init(tempbuf, tempbuflen);
717 /* Generate filepos table */
718 last_pos = 0;
719 filepos = 0;
720 header = 0;
721 for(i = 0;i < 100;i++) {
722 /* Calculate the absolute frame number for this seek point */
723 pos = i * num_frames / 100;
725 /* Advance from the last seek point to this one */
726 for(j = 0;j < pos - last_pos;j++)
728 header = buf_find_next_frame(fd, &bytes, header_template);
729 filepos += bytes;
730 mp3headerinfo(&info, header);
731 buf_seek(fd, info.frame_size-4);
732 filepos += info.frame_size;
734 if(!header_template)
735 header_template = header;
738 /* Save a header for later use if header_template is empty.
739 We only save one header, and we want to save one in the
740 middle of the stream, just in case the first and the last
741 headers are corrupt. */
742 if(!xing_header_template && i == 1)
743 xing_header_template = header;
745 if(progressfunc)
747 progressfunc(50 + i/2);
750 /* Fill in the TOC entry */
751 /* each toc is a single byte indicating how many 256ths of the
752 * way through the file, is that percent of the way through the
753 * song. the easy method, filepos*256/filesize, chokes when
754 * the upper 8 bits of the file position are nonzero
755 * (i.e. files over 16mb in size).
757 if (filepos > (ULONG_MAX/256))
759 /* instead of multiplying filepos by 256, we divide
760 * filesize by 256.
762 toc[i] = filepos / (filesize >> 8);
764 else
766 toc[i] = filepos * 256 / filesize;
769 VDEBUGF("Pos %d: %ld relpos: %ld filepos: %lx tocentry: %x\n",
770 i, pos, pos-last_pos, filepos, toc[i]);
772 last_pos = pos;
776 /* Use the template header and create a new one.
777 We ignore the Protection bit even if the rest of the stream is
778 protected. */
779 header = xing_header_template & ~(BITRATE_MASK|PROTECTION_MASK|PADDING_MASK);
780 header |= 8 << 12; /* This gives us plenty of space, 192..576 bytes */
782 if (!mp3headerinfo(&info, header))
783 return 0; /* invalid header */
785 if (num_frames == 0 && rec_time) {
786 /* estimate the number of frames based on the recording time */
787 if (rec_time <= ULONG_MAX / info.ft_den)
788 num_frames = rec_time * info.ft_den / info.ft_num;
789 else
790 num_frames = rec_time / info.ft_num * info.ft_den;
793 /* Clear the frame */
794 memset(buf, 0, MAX_XING_HEADER_SIZE);
796 /* Write the header to the buffer */
797 long2bytes(buf, header);
799 /* Calculate position of VBR header */
800 if (info.version == MPEG_VERSION1) {
801 if (info.channel_mode == 3) /* mono */
802 index = 21;
803 else
804 index = 36;
806 else {
807 if (info.channel_mode == 3) /* mono */
808 index = 13;
809 else
810 index = 21;
813 /* Create the Xing data */
814 memcpy(&buf[index], "Xing", 4);
815 long2bytes(&buf[index+4], (num_frames ? VBR_FRAMES_FLAG : 0)
816 | (filesize ? VBR_BYTES_FLAG : 0)
817 | (generate_toc ? VBR_TOC_FLAG : 0));
818 index += 8;
819 if(num_frames)
821 long2bytes(&buf[index], num_frames);
822 index += 4;
825 if(filesize)
827 long2bytes(&buf[index], filesize - startpos);
828 index += 4;
831 /* Copy the TOC */
832 memcpy(buf + index, toc, 100);
834 /* And some extra cool info */
835 memcpy(buf + index + 100, cooltext, sizeof(cooltext));
837 #ifdef DEBUG
838 for(i = 0;i < info.frame_size;i++)
840 if(i && !(i % 16))
841 DEBUGF("\n");
843 DEBUGF("%02x ", buf[i]);
845 #endif
847 return info.frame_size;
850 #endif