Get the NSF internal playlists working again. Fix a few wrongdoings in the metadata...
[kugel-rb.git] / apps / mp3data.c
blob9fed72760900950d3ce28022e70892ce3b5e74b7
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;
315 static int buf_getbyte(int fd, unsigned char *c)
317 if(fnf_read_index < fnf_buf_len)
319 *c = audiobuf[fnf_read_index++];
320 return 1;
322 else
324 fnf_buf_len = read(fd, audiobuf, audiobufend - audiobuf);
325 if(fnf_buf_len < 0)
326 return -1;
328 fnf_read_index = 0;
330 if(fnf_buf_len > 0)
332 *c = audiobuf[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, audiobuf, audiobufend - audiobuf);
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(void)
366 fnf_buf_len = 0;
367 fnf_read_index = 0;
370 static unsigned long buf_find_next_frame(int fd, long *offset, long max_offset)
372 return __find_next_frame(fd, offset, max_offset, 0, buf_getbyte, true);
375 static int audiobuflen;
376 static int mem_pos;
377 static int mem_cnt;
378 static int mem_maxlen;
380 static int mem_getbyte(int dummy, unsigned char *c)
382 dummy = dummy;
384 *c = audiobuf[mem_pos++];
385 if(mem_pos >= audiobuflen)
386 mem_pos = 0;
388 if(mem_cnt++ >= mem_maxlen)
389 return 0;
390 else
391 return 1;
394 unsigned long mem_find_next_frame(int startpos,
395 long *offset,
396 long max_offset,
397 unsigned long reference_header)
399 audiobuflen = audiobufend - audiobuf;
400 mem_pos = startpos;
401 mem_cnt = 0;
402 mem_maxlen = max_offset;
404 return __find_next_frame(0, offset, max_offset, reference_header,
405 mem_getbyte, true);
407 #endif
409 /* Extract information from a 'Xing' or 'Info' header. */
410 static void get_xing_info(struct mp3info *info, unsigned char *buf)
412 int i = 8;
414 /* Is it a VBR file? */
415 info->is_vbr = !memcmp(buf, "Xing", 4);
417 if (buf[7] & VBR_FRAMES_FLAG) /* Is the frame count there? */
419 info->frame_count = bytes2int(buf[i], buf[i+1], buf[i+2], buf[i+3]);
420 if (info->frame_count <= ULONG_MAX / info->ft_num)
421 info->file_time = info->frame_count * info->ft_num / info->ft_den;
422 else
423 info->file_time = info->frame_count / info->ft_den * info->ft_num;
424 i += 4;
427 if (buf[7] & VBR_BYTES_FLAG) /* Is byte count there? */
429 info->byte_count = bytes2int(buf[i], buf[i+1], buf[i+2], buf[i+3]);
430 i += 4;
433 if (info->file_time && info->byte_count)
435 if (info->byte_count <= (ULONG_MAX/8))
436 info->bitrate = info->byte_count * 8 / info->file_time;
437 else
438 info->bitrate = info->byte_count / (info->file_time >> 3);
441 if (buf[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */
443 info->has_toc = true;
444 memcpy( info->toc, buf+i, 100 );
445 i += 100;
447 if (buf[7] & VBR_QUALITY_FLAG)
449 /* We don't care about this, but need to skip it */
450 i += 4;
452 #if CONFIG_CODEC==SWCODEC
453 i += 21;
454 info->enc_delay = ((int)buf[i ] << 4) | (buf[i+1] >> 4);
455 info->enc_padding = ((int)(buf[i+1]&0xF) << 8) | buf[i+2];
456 /* TODO: This sanity checking is rather silly, seeing as how the LAME
457 header contains a CRC field that can be used to verify integrity. */
458 if (!(info->enc_delay >= 0 && info->enc_delay <= 2880 &&
459 info->enc_padding >= 0 && info->enc_padding <= 2*1152))
461 /* Invalid data */
462 info->enc_delay = -1;
463 info->enc_padding = -1;
465 #endif
468 /* Extract information from a 'VBRI' header. */
469 static void get_vbri_info(struct mp3info *info, unsigned char *buf)
471 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
473 int i, num_offsets, offset = 0;
476 info->is_vbr = true; /* Yes, it is a FhG VBR file */
477 info->has_toc = false; /* We don't parse the TOC (yet) */
479 info->byte_count = bytes2int(buf[10], buf[11], buf[12], buf[13]);
480 info->frame_count = bytes2int(buf[14], buf[15], buf[16], buf[17]);
481 if (info->frame_count <= ULONG_MAX / info->ft_num)
482 info->file_time = info->frame_count * info->ft_num / info->ft_den;
483 else
484 info->file_time = info->frame_count / info->ft_den * info->ft_num;
486 if (info->byte_count <= (ULONG_MAX/8))
487 info->bitrate = info->byte_count * 8 / info->file_time;
488 else
489 info->bitrate = info->byte_count / (info->file_time >> 3);
491 VDEBUGF("Frame size (%dkpbs): %d bytes (0x%x)\n",
492 info->bitrate, info->frame_size, info->frame_size);
493 VDEBUGF("Frame count: %lx\n", info->frame_count);
494 VDEBUGF("Byte count: %lx\n", info->byte_count);
496 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
498 num_offsets = bytes2int(0, 0, buf[18], buf[19]);
499 VDEBUGF("Offsets: %d\n", num_offsets);
500 VDEBUGF("Frames/entry: %ld\n", bytes2int(0, 0, buf[24], buf[25]));
502 for(i = 0; i < num_offsets; i++)
504 offset += bytes2int(0, 0, buf[26+i*2], buf[27+i*2]);;
505 VDEBUGF("%03d: %lx\n", i, offset - bytecount,);
510 /* Seek to next mpeg header and extract relevant information. */
511 static int get_next_header_info(int fd, long *bytecount, struct mp3info *info,
512 bool single_header)
514 long tmp;
515 unsigned long header = 0;
517 header = __find_next_frame(fd, &tmp, 0x20000, 0, fileread, single_header);
518 if(header == 0)
519 return -1;
521 if(!mp3headerinfo(info, header))
522 return -2;
524 /* Next frame header is tmp bytes away. */
525 *bytecount += tmp;
527 return 0;
530 int get_mp3file_info(int fd, struct mp3info *info)
532 unsigned char frame[VBR_HEADER_MAX_SIZE], *vbrheader;
533 long bytecount = 0;
534 int result, buf_size;
536 /* Initialize info and frame */
537 memset(info, 0, sizeof(struct mp3info));
538 memset(frame, 0, sizeof(frame));
540 #if CONFIG_CODEC==SWCODEC
541 /* These two are needed for proper LAME gapless MP3 playback */
542 info->enc_delay = -1;
543 info->enc_padding = -1;
544 #endif
546 /* Get the very first single MPEG frame. */
547 result = get_next_header_info(fd, &bytecount, info, true);
548 if(result)
549 return result;
551 /* Read the amount of frame data to the buffer that is required for the
552 * vbr tag parsing. Skip the rest. */
553 buf_size = MIN(info->frame_size-4, (int)sizeof(frame));
554 if(read(fd, frame, buf_size) < 0)
555 return -3;
556 lseek(fd, info->frame_size - 4 - buf_size, SEEK_CUR);
558 /* Calculate position of a possible VBR header */
559 if (info->version == MPEG_VERSION1) {
560 if (info->channel_mode == 3) /* mono */
561 vbrheader = frame + 17;
562 else
563 vbrheader = frame + 32;
564 } else {
565 if (info->channel_mode == 3) /* mono */
566 vbrheader = frame + 9;
567 else
568 vbrheader = frame + 17;
571 if (!memcmp(vbrheader, "Xing", 4) || !memcmp(vbrheader, "Info", 4))
573 VDEBUGF("-- XING header --\n");
575 /* We want to skip the Xing frame when playing the stream */
576 bytecount += info->frame_size;
578 /* Now get the next frame to read the real info about the mp3 stream */
579 result = get_next_header_info(fd, &bytecount, info, false);
580 if(result)
581 return result;
583 get_xing_info(info, vbrheader);
585 else if (!memcmp(vbrheader, "VBRI", 4))
587 VDEBUGF("-- VBRI header --\n");
589 /* We want to skip the VBRI frame when playing the stream */
590 bytecount += info->frame_size;
592 /* Now get the next frame to read the real info about the mp3 stream */
593 result = get_next_header_info(fd, &bytecount, info, false);
594 if(result)
595 return result;
597 get_vbri_info(info, vbrheader);
599 else
601 VDEBUGF("-- No VBR header --\n");
603 /* There was no VBR header found. So, we seek back to beginning and
604 * search for the first MPEG frame header of the mp3 stream. */
605 lseek(fd, -info->frame_size, SEEK_CUR);
606 result = get_next_header_info(fd, &bytecount, info, false);
607 if(result)
608 return result;
611 return bytecount;
614 #ifndef __PCTOOL__
615 static void long2bytes(unsigned char *buf, long val)
617 buf[0] = (val >> 24) & 0xff;
618 buf[1] = (val >> 16) & 0xff;
619 buf[2] = (val >> 8) & 0xff;
620 buf[3] = val & 0xff;
623 int count_mp3_frames(int fd, int startpos, int filesize,
624 void (*progressfunc)(int))
626 unsigned long header = 0;
627 struct mp3info info;
628 int num_frames;
629 long bytes;
630 int cnt;
631 long progress_chunk = filesize / 50; /* Max is 50%, in 1% increments */
632 int progress_cnt = 0;
633 bool is_vbr = false;
634 int last_bitrate = 0;
635 int header_template = 0;
637 if(lseek(fd, startpos, SEEK_SET) < 0)
638 return -1;
640 buf_init();
642 /* Find out the total number of frames */
643 num_frames = 0;
644 cnt = 0;
646 while((header = buf_find_next_frame(fd, &bytes, header_template))) {
647 mp3headerinfo(&info, header);
649 if(!header_template)
650 header_template = header;
652 /* See if this really is a VBR file */
653 if(last_bitrate && info.bitrate != last_bitrate)
655 is_vbr = true;
657 last_bitrate = info.bitrate;
659 buf_seek(fd, info.frame_size-4);
660 num_frames++;
661 if(progressfunc)
663 cnt += bytes + info.frame_size;
664 if(cnt > progress_chunk)
666 progress_cnt++;
667 progressfunc(progress_cnt);
668 cnt = 0;
672 VDEBUGF("Total number of frames: %d\n", num_frames);
674 if(is_vbr)
675 return num_frames;
676 else
678 DEBUGF("Not a VBR file\n");
679 return 0;
683 static const char cooltext[] = "Rockbox - rocks your box";
685 /* buf needs to be the audio buffer with TOC generation enabled,
686 and at least MAX_XING_HEADER_SIZE bytes otherwise */
687 int create_xing_header(int fd, long startpos, long filesize,
688 unsigned char *buf, unsigned long num_frames,
689 unsigned long rec_time, unsigned long header_template,
690 void (*progressfunc)(int), bool generate_toc)
692 struct mp3info info;
693 unsigned char toc[100];
694 unsigned long header = 0;
695 unsigned long xing_header_template = header_template;
696 unsigned long filepos;
697 long pos, last_pos;
698 long j;
699 long bytes;
700 int i;
701 int index;
703 DEBUGF("create_xing_header()\n");
705 if(generate_toc)
707 lseek(fd, startpos, SEEK_SET);
708 buf_init();
710 /* Generate filepos table */
711 last_pos = 0;
712 filepos = 0;
713 header = 0;
714 for(i = 0;i < 100;i++) {
715 /* Calculate the absolute frame number for this seek point */
716 pos = i * num_frames / 100;
718 /* Advance from the last seek point to this one */
719 for(j = 0;j < pos - last_pos;j++)
721 header = buf_find_next_frame(fd, &bytes, header_template);
722 filepos += bytes;
723 mp3headerinfo(&info, header);
724 buf_seek(fd, info.frame_size-4);
725 filepos += info.frame_size;
727 if(!header_template)
728 header_template = header;
731 /* Save a header for later use if header_template is empty.
732 We only save one header, and we want to save one in the
733 middle of the stream, just in case the first and the last
734 headers are corrupt. */
735 if(!xing_header_template && i == 1)
736 xing_header_template = header;
738 if(progressfunc)
740 progressfunc(50 + i/2);
743 /* Fill in the TOC entry */
744 /* each toc is a single byte indicating how many 256ths of the
745 * way through the file, is that percent of the way through the
746 * song. the easy method, filepos*256/filesize, chokes when
747 * the upper 8 bits of the file position are nonzero
748 * (i.e. files over 16mb in size).
750 if (filepos > (ULONG_MAX/256))
752 /* instead of multiplying filepos by 256, we divide
753 * filesize by 256.
755 toc[i] = filepos / (filesize >> 8);
757 else
759 toc[i] = filepos * 256 / filesize;
762 VDEBUGF("Pos %d: %ld relpos: %ld filepos: %lx tocentry: %x\n",
763 i, pos, pos-last_pos, filepos, toc[i]);
765 last_pos = pos;
769 /* Use the template header and create a new one.
770 We ignore the Protection bit even if the rest of the stream is
771 protected. */
772 header = xing_header_template & ~(BITRATE_MASK|PROTECTION_MASK|PADDING_MASK);
773 header |= 8 << 12; /* This gives us plenty of space, 192..576 bytes */
775 if (!mp3headerinfo(&info, header))
776 return 0; /* invalid header */
778 if (num_frames == 0 && rec_time) {
779 /* estimate the number of frames based on the recording time */
780 if (rec_time <= ULONG_MAX / info.ft_den)
781 num_frames = rec_time * info.ft_den / info.ft_num;
782 else
783 num_frames = rec_time / info.ft_num * info.ft_den;
786 /* Clear the frame */
787 memset(buf, 0, MAX_XING_HEADER_SIZE);
789 /* Write the header to the buffer */
790 long2bytes(buf, header);
792 /* Calculate position of VBR header */
793 if (info.version == MPEG_VERSION1) {
794 if (info.channel_mode == 3) /* mono */
795 index = 21;
796 else
797 index = 36;
799 else {
800 if (info.channel_mode == 3) /* mono */
801 index = 13;
802 else
803 index = 21;
806 /* Create the Xing data */
807 memcpy(&buf[index], "Xing", 4);
808 long2bytes(&buf[index+4], (num_frames ? VBR_FRAMES_FLAG : 0)
809 | (filesize ? VBR_BYTES_FLAG : 0)
810 | (generate_toc ? VBR_TOC_FLAG : 0));
811 index += 8;
812 if(num_frames)
814 long2bytes(&buf[index], num_frames);
815 index += 4;
818 if(filesize)
820 long2bytes(&buf[index], filesize - startpos);
821 index += 4;
824 /* Copy the TOC */
825 memcpy(buf + index, toc, 100);
827 /* And some extra cool info */
828 memcpy(buf + index + 100, cooltext, sizeof(cooltext));
830 #ifdef DEBUG
831 for(i = 0;i < info.frame_size;i++)
833 if(i && !(i % 16))
834 DEBUGF("\n");
836 DEBUGF("%02x ", buf[i]);
838 #endif
840 return info.frame_size;
843 #endif