More robust implementation of MPEG frame header search. The parser will not only...
[maemo-rb.git] / apps / mp3data.c
blob89af49849fe90510ab046fd6eabc959fc69e8a03
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 "metadata/metadata_common.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 the headers are of same type. */
210 unsigned int mask = 0xfffe0c00;
211 header1 &= mask;
212 header2 &= mask;
213 return header1 ? (header1 == header2) : true;
216 static unsigned long __find_next_frame(int fd, long *offset, long max_offset,
217 unsigned long reference_header,
218 int(*getfunc)(int fd, unsigned char *c),
219 bool single_header)
221 unsigned long header=0;
222 unsigned char tmp;
223 long pos = 0;
225 /* We will search until we find two consecutive MPEG frame headers with
226 * the same MPEG version, layer and sampling frequency. The first header
227 * of this pair is assumed to be the first valid MPEG frame header of the
228 * whole stream. */
229 do {
230 /* Read 1 new byte. */
231 header <<= 8;
232 if (!getfunc(fd, &tmp))
233 return 0;
234 header |= tmp;
235 pos++;
237 /* Abort if max_offset is reached. Stop parsing. */
238 if (max_offset > 0 && pos > max_offset)
239 return 0;
241 if (is_mp3frameheader(header)) {
242 if (single_header) {
243 /* We search for one _single_ valid header that has the same
244 * type as the reference_header (if reference_header != 0).
245 * In this case we are finished. */
246 if (headers_have_same_type(reference_header, header))
247 break;
248 } else {
249 /* The current header is valid. Now gather the frame size,
250 * seek to this byte position and check if there is another
251 * valid MPEG frame header of the same type. */
252 struct mp3info info;
254 /* Gather frame size from given header and seek to next
255 * frame header. */
256 mp3headerinfo(&info, header);
257 lseek(fd, info.frame_size-4, SEEK_CUR);
259 /* Read possible next frame header and seek back to last frame
260 * headers byte position. */
261 reference_header = 0;
262 read_uint32be(fd, (uint32_t*)&reference_header);
263 lseek(fd, -info.frame_size, SEEK_CUR);
265 /* If the current header is of the same type as the previous
266 * header we are finished. */
267 if (headers_have_same_type(header, reference_header))
268 break;
272 } while (true);
274 *offset = pos - 4;
276 if(*offset)
277 VDEBUGF("Warning: skipping %ld bytes of garbage\n", *offset);
279 return header;
282 static int fileread(int fd, unsigned char *c)
284 return read(fd, c, 1);
287 unsigned long find_next_frame(int fd,
288 long *offset,
289 long max_offset,
290 unsigned long reference_header)
292 return __find_next_frame(fd, offset, max_offset, reference_header,
293 fileread, true);
296 #ifndef __PCTOOL__
297 static int fnf_read_index;
298 static int fnf_buf_len;
300 static int buf_getbyte(int fd, unsigned char *c)
302 if(fnf_read_index < fnf_buf_len)
304 *c = audiobuf[fnf_read_index++];
305 return 1;
307 else
309 fnf_buf_len = read(fd, audiobuf, audiobufend - audiobuf);
310 if(fnf_buf_len < 0)
311 return -1;
313 fnf_read_index = 0;
315 if(fnf_buf_len > 0)
317 *c = audiobuf[fnf_read_index++];
318 return 1;
320 else
321 return 0;
323 return 0;
326 static int buf_seek(int fd, int len)
328 fnf_read_index += len;
329 if(fnf_read_index > fnf_buf_len)
331 len = fnf_read_index - fnf_buf_len;
333 fnf_buf_len = read(fd, audiobuf, audiobufend - audiobuf);
334 if(fnf_buf_len < 0)
335 return -1;
337 fnf_read_index = 0;
338 fnf_read_index += len;
341 if(fnf_read_index > fnf_buf_len)
343 return -1;
345 else
346 return 0;
349 static void buf_init(void)
351 fnf_buf_len = 0;
352 fnf_read_index = 0;
355 static unsigned long buf_find_next_frame(int fd, long *offset, long max_offset)
357 return __find_next_frame(fd, offset, max_offset, 0, buf_getbyte, true);
360 static int audiobuflen;
361 static int mem_pos;
362 static int mem_cnt;
363 static int mem_maxlen;
365 static int mem_getbyte(int dummy, unsigned char *c)
367 dummy = dummy;
369 *c = audiobuf[mem_pos++];
370 if(mem_pos >= audiobuflen)
371 mem_pos = 0;
373 if(mem_cnt++ >= mem_maxlen)
374 return 0;
375 else
376 return 1;
379 unsigned long mem_find_next_frame(int startpos,
380 long *offset,
381 long max_offset,
382 unsigned long reference_header)
384 audiobuflen = audiobufend - audiobuf;
385 mem_pos = startpos;
386 mem_cnt = 0;
387 mem_maxlen = max_offset;
389 return __find_next_frame(0, offset, max_offset, reference_header,
390 mem_getbyte, true);
392 #endif
394 /* Extract information from a 'Xing' or 'Info' header. */
395 static void get_xing_info(struct mp3info *info, unsigned char *buf)
397 int i = 8;
399 /* Is it a VBR file? */
400 info->is_vbr = !memcmp(buf, "Xing", 4);
402 if (buf[7] & VBR_FRAMES_FLAG) /* Is the frame count there? */
404 info->frame_count = bytes2int(buf[i], buf[i+1], buf[i+2], buf[i+3]);
405 if (info->frame_count <= ULONG_MAX / info->ft_num)
406 info->file_time = info->frame_count * info->ft_num / info->ft_den;
407 else
408 info->file_time = info->frame_count / info->ft_den * info->ft_num;
409 i += 4;
412 if (buf[7] & VBR_BYTES_FLAG) /* Is byte count there? */
414 info->byte_count = bytes2int(buf[i], buf[i+1], buf[i+2], buf[i+3]);
415 i += 4;
418 if (info->file_time && info->byte_count)
420 if (info->byte_count <= (ULONG_MAX/8))
421 info->bitrate = info->byte_count * 8 / info->file_time;
422 else
423 info->bitrate = info->byte_count / (info->file_time >> 3);
426 if (buf[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */
428 info->has_toc = true;
429 memcpy( info->toc, buf+i, 100 );
430 i += 100;
432 if (buf[7] & VBR_QUALITY_FLAG)
434 /* We don't care about this, but need to skip it */
435 i += 4;
437 #if CONFIG_CODEC==SWCODEC
438 i += 21;
439 info->enc_delay = ((int)buf[i ] << 4) | (buf[i+1] >> 4);
440 info->enc_padding = ((int)buf[i+1] << 8) | buf[i+2];
441 /* TODO: This sanity checking is rather silly, seeing as how the LAME
442 header contains a CRC field that can be used to verify integrity. */
443 if (!(info->enc_delay >= 0 && info->enc_delay <= 2880 &&
444 info->enc_padding >= 0 && info->enc_padding <= 2*1152))
446 /* Invalid data */
447 info->enc_delay = -1;
448 info->enc_padding = -1;
450 #endif
453 /* Extract information from a 'VBRI' header. */
454 static void get_vbri_info(struct mp3info *info, unsigned char *buf)
456 int i, num_offsets, offset = 0;
458 info->is_vbr = true; /* Yes, it is a FhG VBR file */
459 info->has_toc = false; /* We don't parse the TOC (yet) */
461 info->byte_count = bytes2int(buf[10], buf[11], buf[12], buf[13]);
462 info->frame_count = bytes2int(buf[14], buf[15], buf[16], buf[17]);
463 if (info->frame_count <= ULONG_MAX / info->ft_num)
464 info->file_time = info->frame_count * info->ft_num / info->ft_den;
465 else
466 info->file_time = info->frame_count / info->ft_den * info->ft_num;
468 if (info->byte_count <= (ULONG_MAX/8))
469 info->bitrate = info->byte_count * 8 / info->file_time;
470 else
471 info->bitrate = info->byte_count / (info->file_time >> 3);
473 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
474 num_offsets = bytes2int(0, 0, buf[18], buf[19]);
475 VDEBUGF("Frame size (%dkpbs): %d bytes (0x%x)\n",
476 info->bitrate, info->frame_size, info->frame_size);
477 VDEBUGF("Frame count: %lx\n", info->frame_count);
478 VDEBUGF("Byte count: %lx\n", info->byte_count);
479 VDEBUGF("Offsets: %d\n", num_offsets);
480 VDEBUGF("Frames/entry: %ld\n",
481 bytes2int(0, 0, buf[24], buf[25]));
483 for(i = 0; i < num_offsets; i++)
485 offset += bytes2int(0, 0, buf[26+i*2], buf[27+i*2]);;
486 VDEBUGF("%03d: %lx\n", i, offset - bytecount,);
490 /* Seek to next mpeg header and extract relevant information. */
491 static int get_next_header_info(int fd, long *bytecount, struct mp3info *info,
492 bool single_header)
494 long tmp;
495 unsigned long header = 0;
497 header = __find_next_frame(fd, &tmp, 0x20000, 0, fileread, single_header);
498 if(header == 0)
499 return -1;
501 if(!mp3headerinfo(info, header))
502 return -2;
504 /* Next frame header is tmp bytes away. */
505 *bytecount += tmp;
507 return 0;
510 int get_mp3file_info(int fd, struct mp3info *info)
512 unsigned char frame[1800], *vbrheader;
513 long bytecount = 0;
514 int result;
516 /* Initialize info and frame */
517 memset(info, 0, sizeof(struct mp3info));
518 memset(frame, 0, sizeof(frame));
520 #if CONFIG_CODEC==SWCODEC
521 /* These two are needed for proper LAME gapless MP3 playback */
522 info->enc_delay = -1;
523 info->enc_padding = -1;
524 #endif
526 /* Get the very first single MPEG frame. */
527 result = get_next_header_info(fd, &bytecount, info, true);
528 if(result)
529 return result;
531 /* OK, we have found a frame. Let's see if it has a Xing header */
532 if (info->frame_size-4 >= (int)sizeof(frame))
534 DEBUGF("Error: Invalid id3 header, frame_size: %d\n", info->frame_size);
535 return -8;
538 if(read(fd, frame, info->frame_size-4) < 0)
539 return -3;
541 /* Calculate position of a possible VBR header */
542 if (info->version == MPEG_VERSION1) {
543 if (info->channel_mode == 3) /* mono */
544 vbrheader = frame + 17;
545 else
546 vbrheader = frame + 32;
547 } else {
548 if (info->channel_mode == 3) /* mono */
549 vbrheader = frame + 9;
550 else
551 vbrheader = frame + 17;
554 if (!memcmp(vbrheader, "Xing", 4) || !memcmp(vbrheader, "Info", 4))
556 VDEBUGF("-- XING header --\n");
558 /* We want to skip the Xing frame when playing the stream */
559 bytecount += info->frame_size;
561 /* Now get the next frame to read the real info about the mp3 stream */
562 result = get_next_header_info(fd, &bytecount, info, false);
563 if(result)
564 return result;
566 get_xing_info(info, vbrheader);
568 else if (!memcmp(vbrheader, "VBRI", 4))
570 VDEBUGF("-- VBRI header --\n");
572 /* We want to skip the VBRI frame when playing the stream */
573 bytecount += info->frame_size;
575 /* Now get the next frame to read the real info about the mp3 stream */
576 result = get_next_header_info(fd, &bytecount, info, false);
577 if(result)
578 return result;
580 get_vbri_info(info, vbrheader);
582 else
584 VDEBUGF("-- No VBR header --\n");
586 /* There was no VBR header found. So, we seek back to beginning and
587 * search for the first MPEG frame header of the mp3 stream. */
588 lseek(fd, -info->frame_size, SEEK_CUR);
589 result = get_next_header_info(fd, &bytecount, info, false);
590 if(result)
591 return result;
594 return bytecount;
597 #ifndef __PCTOOL__
598 static void long2bytes(unsigned char *buf, long val)
600 buf[0] = (val >> 24) & 0xff;
601 buf[1] = (val >> 16) & 0xff;
602 buf[2] = (val >> 8) & 0xff;
603 buf[3] = val & 0xff;
606 int count_mp3_frames(int fd, int startpos, int filesize,
607 void (*progressfunc)(int))
609 unsigned long header = 0;
610 struct mp3info info;
611 int num_frames;
612 long bytes;
613 int cnt;
614 long progress_chunk = filesize / 50; /* Max is 50%, in 1% increments */
615 int progress_cnt = 0;
616 bool is_vbr = false;
617 int last_bitrate = 0;
618 int header_template = 0;
620 if(lseek(fd, startpos, SEEK_SET) < 0)
621 return -1;
623 buf_init();
625 /* Find out the total number of frames */
626 num_frames = 0;
627 cnt = 0;
629 while((header = buf_find_next_frame(fd, &bytes, header_template))) {
630 mp3headerinfo(&info, header);
632 if(!header_template)
633 header_template = header;
635 /* See if this really is a VBR file */
636 if(last_bitrate && info.bitrate != last_bitrate)
638 is_vbr = true;
640 last_bitrate = info.bitrate;
642 buf_seek(fd, info.frame_size-4);
643 num_frames++;
644 if(progressfunc)
646 cnt += bytes + info.frame_size;
647 if(cnt > progress_chunk)
649 progress_cnt++;
650 progressfunc(progress_cnt);
651 cnt = 0;
655 VDEBUGF("Total number of frames: %d\n", num_frames);
657 if(is_vbr)
658 return num_frames;
659 else
661 DEBUGF("Not a VBR file\n");
662 return 0;
666 static const char cooltext[] = "Rockbox - rocks your box";
668 /* buf needs to be the audio buffer with TOC generation enabled,
669 and at least MAX_XING_HEADER_SIZE bytes otherwise */
670 int create_xing_header(int fd, long startpos, long filesize,
671 unsigned char *buf, unsigned long num_frames,
672 unsigned long rec_time, unsigned long header_template,
673 void (*progressfunc)(int), bool generate_toc)
675 struct mp3info info;
676 unsigned char toc[100];
677 unsigned long header = 0;
678 unsigned long xing_header_template = header_template;
679 unsigned long filepos;
680 long pos, last_pos;
681 long j;
682 long bytes;
683 int i;
684 int index;
686 DEBUGF("create_xing_header()\n");
688 if(generate_toc)
690 lseek(fd, startpos, SEEK_SET);
691 buf_init();
693 /* Generate filepos table */
694 last_pos = 0;
695 filepos = 0;
696 header = 0;
697 for(i = 0;i < 100;i++) {
698 /* Calculate the absolute frame number for this seek point */
699 pos = i * num_frames / 100;
701 /* Advance from the last seek point to this one */
702 for(j = 0;j < pos - last_pos;j++)
704 header = buf_find_next_frame(fd, &bytes, header_template);
705 filepos += bytes;
706 mp3headerinfo(&info, header);
707 buf_seek(fd, info.frame_size-4);
708 filepos += info.frame_size;
710 if(!header_template)
711 header_template = header;
714 /* Save a header for later use if header_template is empty.
715 We only save one header, and we want to save one in the
716 middle of the stream, just in case the first and the last
717 headers are corrupt. */
718 if(!xing_header_template && i == 1)
719 xing_header_template = header;
721 if(progressfunc)
723 progressfunc(50 + i/2);
726 /* Fill in the TOC entry */
727 /* each toc is a single byte indicating how many 256ths of the
728 * way through the file, is that percent of the way through the
729 * song. the easy method, filepos*256/filesize, chokes when
730 * the upper 8 bits of the file position are nonzero
731 * (i.e. files over 16mb in size).
733 if (filepos > (ULONG_MAX/256))
735 /* instead of multiplying filepos by 256, we divide
736 * filesize by 256.
738 toc[i] = filepos / (filesize >> 8);
740 else
742 toc[i] = filepos * 256 / filesize;
745 VDEBUGF("Pos %d: %ld relpos: %ld filepos: %lx tocentry: %x\n",
746 i, pos, pos-last_pos, filepos, toc[i]);
748 last_pos = pos;
752 /* Use the template header and create a new one.
753 We ignore the Protection bit even if the rest of the stream is
754 protected. */
755 header = xing_header_template & ~(BITRATE_MASK|PROTECTION_MASK|PADDING_MASK);
756 header |= 8 << 12; /* This gives us plenty of space, 192..576 bytes */
758 if (!mp3headerinfo(&info, header))
759 return 0; /* invalid header */
761 if (num_frames == 0 && rec_time) {
762 /* estimate the number of frames based on the recording time */
763 if (rec_time <= ULONG_MAX / info.ft_den)
764 num_frames = rec_time * info.ft_den / info.ft_num;
765 else
766 num_frames = rec_time / info.ft_num * info.ft_den;
769 /* Clear the frame */
770 memset(buf, 0, MAX_XING_HEADER_SIZE);
772 /* Write the header to the buffer */
773 long2bytes(buf, header);
775 /* Calculate position of VBR header */
776 if (info.version == MPEG_VERSION1) {
777 if (info.channel_mode == 3) /* mono */
778 index = 21;
779 else
780 index = 36;
782 else {
783 if (info.channel_mode == 3) /* mono */
784 index = 13;
785 else
786 index = 21;
789 /* Create the Xing data */
790 memcpy(&buf[index], "Xing", 4);
791 long2bytes(&buf[index+4], (num_frames ? VBR_FRAMES_FLAG : 0)
792 | (filesize ? VBR_BYTES_FLAG : 0)
793 | (generate_toc ? VBR_TOC_FLAG : 0));
794 index += 8;
795 if(num_frames)
797 long2bytes(&buf[index], num_frames);
798 index += 4;
801 if(filesize)
803 long2bytes(&buf[index], filesize - startpos);
804 index += 4;
807 /* Copy the TOC */
808 memcpy(buf + index, toc, 100);
810 /* And some extra cool info */
811 memcpy(buf + index + 100, cooltext, sizeof(cooltext));
813 #ifdef DEBUG
814 for(i = 0;i < info.frame_size;i++)
816 if(i && !(i % 16))
817 DEBUGF("\n");
819 DEBUGF("%02x ", buf[i]);
821 #endif
823 return info.frame_size;
826 #endif