Local implementation of read_uint32be() in mp3data.c needs a major correction.
[kugel-rb.git] / apps / mp3data.c
blobaa54761c07d65254d5fdd6ddaaa95d7a6668d233
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 /* MPEG Version table, sorted by version index */
67 static const signed char version_table[4] = {
68 MPEG_VERSION2_5, -1, MPEG_VERSION2, MPEG_VERSION1
71 /* Bitrate table for mpeg audio, indexed by row index and birate index */
72 static const short bitrates[5][16] = {
73 {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, /* V1 L1 */
74 {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, /* V1 L2 */
75 {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0}, /* V1 L3 */
76 {0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256,0}, /* V2 L1 */
77 {0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0} /* V2 L2+L3 */
80 /* Bitrate pointer table, indexed by version and layer */
81 static const short *bitrate_table[3][3] =
83 {bitrates[0], bitrates[1], bitrates[2]},
84 {bitrates[3], bitrates[4], bitrates[4]},
85 {bitrates[3], bitrates[4], bitrates[4]}
88 /* Sampling frequency table, indexed by version and frequency index */
89 static const unsigned short freq_table[3][3] =
91 {44100, 48000, 32000}, /* MPEG Version 1 */
92 {22050, 24000, 16000}, /* MPEG version 2 */
93 {11025, 12000, 8000}, /* MPEG version 2.5 */
96 unsigned long bytes2int(unsigned long b0, unsigned long b1,
97 unsigned long b2, unsigned long b3)
99 return (b0 & 0xFF) << (3*8) |
100 (b1 & 0xFF) << (2*8) |
101 (b2 & 0xFF) << (1*8) |
102 (b3 & 0xFF) << (0*8);
105 /* check if 'head' is a valid mp3 frame header */
106 static bool is_mp3frameheader(unsigned long head)
108 if ((head & SYNC_MASK) != (unsigned long)SYNC_MASK) /* bad sync? */
109 return false;
110 if ((head & VERSION_MASK) == (1L << 19)) /* bad version? */
111 return false;
112 if (!(head & LAYER_MASK)) /* no layer? */
113 return false;
114 #if CONFIG_CODEC != SWCODEC
115 /* The MAS can't decode layer 1, so treat layer 1 data as invalid */
116 if ((head & LAYER_MASK) == LAYER_MASK)
117 return false;
118 #endif
119 if ((head & BITRATE_MASK) == BITRATE_MASK) /* bad bitrate? */
120 return false;
121 if (!(head & BITRATE_MASK)) /* no bitrate? */
122 return false;
123 if ((head & SAMPLERATE_MASK) == SAMPLERATE_MASK) /* bad sample rate? */
124 return false;
126 return true;
129 static bool mp3headerinfo(struct mp3info *info, unsigned long header)
131 int bitindex, freqindex;
133 /* MPEG Audio Version */
134 if ((header & VERSION_MASK) >> 19 >= sizeof(version_table))
135 return false;
137 info->version = version_table[(header & VERSION_MASK) >> 19];
138 if (info->version < 0)
139 return false;
141 /* Layer */
142 info->layer = 3 - ((header & LAYER_MASK) >> 17);
143 if (info->layer == 3)
144 return false;
146 /* Rockbox: not used
147 info->protection = (header & PROTECTION_MASK) ? true : false;
150 /* Bitrate */
151 bitindex = (header & BITRATE_MASK) >> 12;
152 info->bitrate = bitrate_table[info->version][info->layer][bitindex];
153 if(info->bitrate == 0)
154 return false;
156 /* Sampling frequency */
157 freqindex = (header & SAMPLERATE_MASK) >> 10;
158 if (freqindex == 3)
159 return false;
160 info->frequency = freq_table[info->version][freqindex];
162 info->padding = (header & PADDING_MASK) ? 1 : 0;
164 /* Calculate number of bytes, calculation depends on layer */
165 if (info->layer == 0) {
166 info->frame_samples = 384;
167 info->frame_size = (12000 * info->bitrate / info->frequency
168 + info->padding) * 4;
170 else {
171 if ((info->version > MPEG_VERSION1) && (info->layer == 2))
172 info->frame_samples = 576;
173 else
174 info->frame_samples = 1152;
175 info->frame_size = (1000/8) * info->frame_samples * info->bitrate
176 / info->frequency + info->padding;
179 /* Frametime fraction denominator */
180 if (freqindex != 0) { /* 48/32/24/16/12/8 kHz */
181 info->ft_den = 1; /* integer number of milliseconds */
183 else { /* 44.1/22.05/11.025 kHz */
184 if (info->layer == 0) /* layer 1 */
185 info->ft_den = 147;
186 else /* layer 2+3 */
187 info->ft_den = 49;
189 /* Frametime fraction numerator */
190 info->ft_num = 1000 * info->ft_den * info->frame_samples / info->frequency;
192 info->channel_mode = (header & CHANNELMODE_MASK) >> 6;
193 /* Rockbox: not used
194 info->mode_extension = (header & MODE_EXT_MASK) >> 4;
195 info->emphasis = header & EMPHASIS_MASK;
197 VDEBUGF( "Header: %08lx, Ver %d, lay %d, bitr %d, freq %ld, "
198 "chmode %d, bytes: %d time: %d/%d\n",
199 header, info->version, info->layer+1, info->bitrate,
200 info->frequency, info->channel_mode,
201 info->frame_size, info->ft_num, info->ft_den);
202 return true;
205 static bool headers_have_same_type(unsigned long header1,
206 unsigned long header2)
208 /* Compare MPEG version, layer and sampling frequency. If header1 is zero
209 * it is assumed both frame headers are of same type. */
210 unsigned int mask = SYNC_MASK | VERSION_MASK | LAYER_MASK | SAMPLERATE_MASK;
211 header1 &= mask;
212 header2 &= mask;
213 return header1 ? (header1 == header2) : true;
216 /* Helper function to read 4-byte in big endian format. */
217 static void read_uint32be_mp3data(int fd, unsigned long *data)
219 #ifdef ROCKBOX_BIG_ENDIAN
220 (void)read(fd, (char*)data, 4);
221 #else
222 (void)read(fd, (char*)data, 4);
223 *data = betoh32(*data);
224 #endif
227 static unsigned long __find_next_frame(int fd, long *offset, long max_offset,
228 unsigned long reference_header,
229 int(*getfunc)(int fd, unsigned char *c),
230 bool single_header)
232 unsigned long header=0;
233 unsigned char tmp;
234 long pos = 0;
236 /* We will search until we find two consecutive MPEG frame headers with
237 * the same MPEG version, layer and sampling frequency. The first header
238 * of this pair is assumed to be the first valid MPEG frame header of the
239 * whole stream. */
240 do {
241 /* Read 1 new byte. */
242 header <<= 8;
243 if (!getfunc(fd, &tmp))
244 return 0;
245 header |= tmp;
246 pos++;
248 /* Abort if max_offset is reached. Stop parsing. */
249 if (max_offset > 0 && pos > max_offset)
250 return 0;
252 if (is_mp3frameheader(header)) {
253 if (single_header) {
254 /* We search for one _single_ valid header that has the same
255 * type as the reference_header (if reference_header != 0).
256 * In this case we are finished. */
257 if (headers_have_same_type(reference_header, header))
258 break;
259 } else {
260 /* The current header is valid. Now gather the frame size,
261 * seek to this byte position and check if there is another
262 * valid MPEG frame header of the same type. */
263 struct mp3info info;
265 /* Gather frame size from given header and seek to next
266 * frame header. */
267 mp3headerinfo(&info, header);
268 lseek(fd, info.frame_size-4, SEEK_CUR);
270 /* Read possible next frame header and seek back to last frame
271 * headers byte position. */
272 reference_header = 0;
273 read_uint32be_mp3data(fd, &reference_header);
275 lseek(fd, -info.frame_size, SEEK_CUR);
277 /* If the current header is of the same type as the previous
278 * header we are finished. */
279 if (headers_have_same_type(header, reference_header))
280 break;
284 } while (true);
286 *offset = pos - 4;
288 if(*offset)
289 VDEBUGF("Warning: skipping %ld bytes of garbage\n", *offset);
291 return header;
294 static int fileread(int fd, unsigned char *c)
296 return read(fd, c, 1);
299 unsigned long find_next_frame(int fd,
300 long *offset,
301 long max_offset,
302 unsigned long reference_header)
304 return __find_next_frame(fd, offset, max_offset, reference_header,
305 fileread, true);
308 #ifndef __PCTOOL__
309 static int fnf_read_index;
310 static int fnf_buf_len;
312 static int buf_getbyte(int fd, unsigned char *c)
314 if(fnf_read_index < fnf_buf_len)
316 *c = audiobuf[fnf_read_index++];
317 return 1;
319 else
321 fnf_buf_len = read(fd, audiobuf, audiobufend - audiobuf);
322 if(fnf_buf_len < 0)
323 return -1;
325 fnf_read_index = 0;
327 if(fnf_buf_len > 0)
329 *c = audiobuf[fnf_read_index++];
330 return 1;
332 else
333 return 0;
335 return 0;
338 static int buf_seek(int fd, int len)
340 fnf_read_index += len;
341 if(fnf_read_index > fnf_buf_len)
343 len = fnf_read_index - fnf_buf_len;
345 fnf_buf_len = read(fd, audiobuf, audiobufend - audiobuf);
346 if(fnf_buf_len < 0)
347 return -1;
349 fnf_read_index = 0;
350 fnf_read_index += len;
353 if(fnf_read_index > fnf_buf_len)
355 return -1;
357 else
358 return 0;
361 static void buf_init(void)
363 fnf_buf_len = 0;
364 fnf_read_index = 0;
367 static unsigned long buf_find_next_frame(int fd, long *offset, long max_offset)
369 return __find_next_frame(fd, offset, max_offset, 0, buf_getbyte, true);
372 static int audiobuflen;
373 static int mem_pos;
374 static int mem_cnt;
375 static int mem_maxlen;
377 static int mem_getbyte(int dummy, unsigned char *c)
379 dummy = dummy;
381 *c = audiobuf[mem_pos++];
382 if(mem_pos >= audiobuflen)
383 mem_pos = 0;
385 if(mem_cnt++ >= mem_maxlen)
386 return 0;
387 else
388 return 1;
391 unsigned long mem_find_next_frame(int startpos,
392 long *offset,
393 long max_offset,
394 unsigned long reference_header)
396 audiobuflen = audiobufend - audiobuf;
397 mem_pos = startpos;
398 mem_cnt = 0;
399 mem_maxlen = max_offset;
401 return __find_next_frame(0, offset, max_offset, reference_header,
402 mem_getbyte, true);
404 #endif
406 /* Extract information from a 'Xing' or 'Info' header. */
407 static void get_xing_info(struct mp3info *info, unsigned char *buf)
409 int i = 8;
411 /* Is it a VBR file? */
412 info->is_vbr = !memcmp(buf, "Xing", 4);
414 if (buf[7] & VBR_FRAMES_FLAG) /* Is the frame count there? */
416 info->frame_count = bytes2int(buf[i], buf[i+1], buf[i+2], buf[i+3]);
417 if (info->frame_count <= ULONG_MAX / info->ft_num)
418 info->file_time = info->frame_count * info->ft_num / info->ft_den;
419 else
420 info->file_time = info->frame_count / info->ft_den * info->ft_num;
421 i += 4;
424 if (buf[7] & VBR_BYTES_FLAG) /* Is byte count there? */
426 info->byte_count = bytes2int(buf[i], buf[i+1], buf[i+2], buf[i+3]);
427 i += 4;
430 if (info->file_time && info->byte_count)
432 if (info->byte_count <= (ULONG_MAX/8))
433 info->bitrate = info->byte_count * 8 / info->file_time;
434 else
435 info->bitrate = info->byte_count / (info->file_time >> 3);
438 if (buf[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */
440 info->has_toc = true;
441 memcpy( info->toc, buf+i, 100 );
442 i += 100;
444 if (buf[7] & VBR_QUALITY_FLAG)
446 /* We don't care about this, but need to skip it */
447 i += 4;
449 #if CONFIG_CODEC==SWCODEC
450 i += 21;
451 info->enc_delay = ((int)buf[i ] << 4) | (buf[i+1] >> 4);
452 info->enc_padding = ((int)buf[i+1] << 8) | buf[i+2];
453 /* TODO: This sanity checking is rather silly, seeing as how the LAME
454 header contains a CRC field that can be used to verify integrity. */
455 if (!(info->enc_delay >= 0 && info->enc_delay <= 2880 &&
456 info->enc_padding >= 0 && info->enc_padding <= 2*1152))
458 /* Invalid data */
459 info->enc_delay = -1;
460 info->enc_padding = -1;
462 #endif
465 /* Extract information from a 'VBRI' header. */
466 static void get_vbri_info(struct mp3info *info, unsigned char *buf)
468 int i, num_offsets, offset = 0;
470 info->is_vbr = true; /* Yes, it is a FhG VBR file */
471 info->has_toc = false; /* We don't parse the TOC (yet) */
473 info->byte_count = bytes2int(buf[10], buf[11], buf[12], buf[13]);
474 info->frame_count = bytes2int(buf[14], buf[15], buf[16], buf[17]);
475 if (info->frame_count <= ULONG_MAX / info->ft_num)
476 info->file_time = info->frame_count * info->ft_num / info->ft_den;
477 else
478 info->file_time = info->frame_count / info->ft_den * info->ft_num;
480 if (info->byte_count <= (ULONG_MAX/8))
481 info->bitrate = info->byte_count * 8 / info->file_time;
482 else
483 info->bitrate = info->byte_count / (info->file_time >> 3);
485 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
486 num_offsets = bytes2int(0, 0, buf[18], buf[19]);
487 VDEBUGF("Frame size (%dkpbs): %d bytes (0x%x)\n",
488 info->bitrate, info->frame_size, info->frame_size);
489 VDEBUGF("Frame count: %lx\n", info->frame_count);
490 VDEBUGF("Byte count: %lx\n", info->byte_count);
491 VDEBUGF("Offsets: %d\n", num_offsets);
492 VDEBUGF("Frames/entry: %ld\n",
493 bytes2int(0, 0, buf[24], buf[25]));
495 for(i = 0; i < num_offsets; i++)
497 offset += bytes2int(0, 0, buf[26+i*2], buf[27+i*2]);;
498 VDEBUGF("%03d: %lx\n", i, offset - bytecount,);
502 /* Seek to next mpeg header and extract relevant information. */
503 static int get_next_header_info(int fd, long *bytecount, struct mp3info *info,
504 bool single_header)
506 long tmp;
507 unsigned long header = 0;
509 header = __find_next_frame(fd, &tmp, 0x20000, 0, fileread, single_header);
510 if(header == 0)
511 return -1;
513 if(!mp3headerinfo(info, header))
514 return -2;
516 /* Next frame header is tmp bytes away. */
517 *bytecount += tmp;
519 return 0;
522 int get_mp3file_info(int fd, struct mp3info *info)
524 unsigned char frame[1800], *vbrheader;
525 long bytecount = 0;
526 int result;
528 /* Initialize info and frame */
529 memset(info, 0, sizeof(struct mp3info));
530 memset(frame, 0, sizeof(frame));
532 #if CONFIG_CODEC==SWCODEC
533 /* These two are needed for proper LAME gapless MP3 playback */
534 info->enc_delay = -1;
535 info->enc_padding = -1;
536 #endif
538 /* Get the very first single MPEG frame. */
539 result = get_next_header_info(fd, &bytecount, info, true);
540 if(result)
541 return result;
543 /* OK, we have found a frame. Let's see if it has a Xing header */
544 if (info->frame_size-4 >= (int)sizeof(frame))
546 DEBUGF("Error: Invalid id3 header, frame_size: %d\n", info->frame_size);
547 return -8;
550 if(read(fd, frame, info->frame_size-4) < 0)
551 return -3;
553 /* Calculate position of a possible VBR header */
554 if (info->version == MPEG_VERSION1) {
555 if (info->channel_mode == 3) /* mono */
556 vbrheader = frame + 17;
557 else
558 vbrheader = frame + 32;
559 } else {
560 if (info->channel_mode == 3) /* mono */
561 vbrheader = frame + 9;
562 else
563 vbrheader = frame + 17;
566 if (!memcmp(vbrheader, "Xing", 4) || !memcmp(vbrheader, "Info", 4))
568 VDEBUGF("-- XING header --\n");
570 /* We want to skip the Xing frame when playing the stream */
571 bytecount += info->frame_size;
573 /* Now get the next frame to read the real info about the mp3 stream */
574 result = get_next_header_info(fd, &bytecount, info, false);
575 if(result)
576 return result;
578 get_xing_info(info, vbrheader);
580 else if (!memcmp(vbrheader, "VBRI", 4))
582 VDEBUGF("-- VBRI header --\n");
584 /* We want to skip the VBRI frame when playing the stream */
585 bytecount += info->frame_size;
587 /* Now get the next frame to read the real info about the mp3 stream */
588 result = get_next_header_info(fd, &bytecount, info, false);
589 if(result)
590 return result;
592 get_vbri_info(info, vbrheader);
594 else
596 VDEBUGF("-- No VBR header --\n");
598 /* There was no VBR header found. So, we seek back to beginning and
599 * search for the first MPEG frame header of the mp3 stream. */
600 lseek(fd, -info->frame_size, SEEK_CUR);
601 result = get_next_header_info(fd, &bytecount, info, false);
602 if(result)
603 return result;
606 return bytecount;
609 #ifndef __PCTOOL__
610 static void long2bytes(unsigned char *buf, long val)
612 buf[0] = (val >> 24) & 0xff;
613 buf[1] = (val >> 16) & 0xff;
614 buf[2] = (val >> 8) & 0xff;
615 buf[3] = val & 0xff;
618 int count_mp3_frames(int fd, int startpos, int filesize,
619 void (*progressfunc)(int))
621 unsigned long header = 0;
622 struct mp3info info;
623 int num_frames;
624 long bytes;
625 int cnt;
626 long progress_chunk = filesize / 50; /* Max is 50%, in 1% increments */
627 int progress_cnt = 0;
628 bool is_vbr = false;
629 int last_bitrate = 0;
630 int header_template = 0;
632 if(lseek(fd, startpos, SEEK_SET) < 0)
633 return -1;
635 buf_init();
637 /* Find out the total number of frames */
638 num_frames = 0;
639 cnt = 0;
641 while((header = buf_find_next_frame(fd, &bytes, header_template))) {
642 mp3headerinfo(&info, header);
644 if(!header_template)
645 header_template = header;
647 /* See if this really is a VBR file */
648 if(last_bitrate && info.bitrate != last_bitrate)
650 is_vbr = true;
652 last_bitrate = info.bitrate;
654 buf_seek(fd, info.frame_size-4);
655 num_frames++;
656 if(progressfunc)
658 cnt += bytes + info.frame_size;
659 if(cnt > progress_chunk)
661 progress_cnt++;
662 progressfunc(progress_cnt);
663 cnt = 0;
667 VDEBUGF("Total number of frames: %d\n", num_frames);
669 if(is_vbr)
670 return num_frames;
671 else
673 DEBUGF("Not a VBR file\n");
674 return 0;
678 static const char cooltext[] = "Rockbox - rocks your box";
680 /* buf needs to be the audio buffer with TOC generation enabled,
681 and at least MAX_XING_HEADER_SIZE bytes otherwise */
682 int create_xing_header(int fd, long startpos, long filesize,
683 unsigned char *buf, unsigned long num_frames,
684 unsigned long rec_time, unsigned long header_template,
685 void (*progressfunc)(int), bool generate_toc)
687 struct mp3info info;
688 unsigned char toc[100];
689 unsigned long header = 0;
690 unsigned long xing_header_template = header_template;
691 unsigned long filepos;
692 long pos, last_pos;
693 long j;
694 long bytes;
695 int i;
696 int index;
698 DEBUGF("create_xing_header()\n");
700 if(generate_toc)
702 lseek(fd, startpos, SEEK_SET);
703 buf_init();
705 /* Generate filepos table */
706 last_pos = 0;
707 filepos = 0;
708 header = 0;
709 for(i = 0;i < 100;i++) {
710 /* Calculate the absolute frame number for this seek point */
711 pos = i * num_frames / 100;
713 /* Advance from the last seek point to this one */
714 for(j = 0;j < pos - last_pos;j++)
716 header = buf_find_next_frame(fd, &bytes, header_template);
717 filepos += bytes;
718 mp3headerinfo(&info, header);
719 buf_seek(fd, info.frame_size-4);
720 filepos += info.frame_size;
722 if(!header_template)
723 header_template = header;
726 /* Save a header for later use if header_template is empty.
727 We only save one header, and we want to save one in the
728 middle of the stream, just in case the first and the last
729 headers are corrupt. */
730 if(!xing_header_template && i == 1)
731 xing_header_template = header;
733 if(progressfunc)
735 progressfunc(50 + i/2);
738 /* Fill in the TOC entry */
739 /* each toc is a single byte indicating how many 256ths of the
740 * way through the file, is that percent of the way through the
741 * song. the easy method, filepos*256/filesize, chokes when
742 * the upper 8 bits of the file position are nonzero
743 * (i.e. files over 16mb in size).
745 if (filepos > (ULONG_MAX/256))
747 /* instead of multiplying filepos by 256, we divide
748 * filesize by 256.
750 toc[i] = filepos / (filesize >> 8);
752 else
754 toc[i] = filepos * 256 / filesize;
757 VDEBUGF("Pos %d: %ld relpos: %ld filepos: %lx tocentry: %x\n",
758 i, pos, pos-last_pos, filepos, toc[i]);
760 last_pos = pos;
764 /* Use the template header and create a new one.
765 We ignore the Protection bit even if the rest of the stream is
766 protected. */
767 header = xing_header_template & ~(BITRATE_MASK|PROTECTION_MASK|PADDING_MASK);
768 header |= 8 << 12; /* This gives us plenty of space, 192..576 bytes */
770 if (!mp3headerinfo(&info, header))
771 return 0; /* invalid header */
773 if (num_frames == 0 && rec_time) {
774 /* estimate the number of frames based on the recording time */
775 if (rec_time <= ULONG_MAX / info.ft_den)
776 num_frames = rec_time * info.ft_den / info.ft_num;
777 else
778 num_frames = rec_time / info.ft_num * info.ft_den;
781 /* Clear the frame */
782 memset(buf, 0, MAX_XING_HEADER_SIZE);
784 /* Write the header to the buffer */
785 long2bytes(buf, header);
787 /* Calculate position of VBR header */
788 if (info.version == MPEG_VERSION1) {
789 if (info.channel_mode == 3) /* mono */
790 index = 21;
791 else
792 index = 36;
794 else {
795 if (info.channel_mode == 3) /* mono */
796 index = 13;
797 else
798 index = 21;
801 /* Create the Xing data */
802 memcpy(&buf[index], "Xing", 4);
803 long2bytes(&buf[index+4], (num_frames ? VBR_FRAMES_FLAG : 0)
804 | (filesize ? VBR_BYTES_FLAG : 0)
805 | (generate_toc ? VBR_TOC_FLAG : 0));
806 index += 8;
807 if(num_frames)
809 long2bytes(&buf[index], num_frames);
810 index += 4;
813 if(filesize)
815 long2bytes(&buf[index], filesize - startpos);
816 index += 4;
819 /* Copy the TOC */
820 memcpy(buf + index, toc, 100);
822 /* And some extra cool info */
823 memcpy(buf + index + 100, cooltext, sizeof(cooltext));
825 #ifdef DEBUG
826 for(i = 0;i < info.frame_size;i++)
828 if(i && !(i % 16))
829 DEBUGF("\n");
831 DEBUGF("%02x ", buf[i]);
833 #endif
835 return info.frame_size;
838 #endif