Add proper svn:mime-type
[maemo-rb.git] / apps / mp3data.c
blobf5ef12280110bf3947bf1dda042dee702613b98f
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"
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 /* MPEG Version table, sorted by version index */
66 static const signed char version_table[4] = {
67 MPEG_VERSION2_5, -1, MPEG_VERSION2, MPEG_VERSION1
70 /* Bitrate table for mpeg audio, indexed by row index and birate index */
71 static const short bitrates[5][16] = {
72 {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, /* V1 L1 */
73 {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, /* V1 L2 */
74 {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0}, /* V1 L3 */
75 {0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256,0}, /* V2 L1 */
76 {0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0} /* V2 L2+L3 */
79 /* Bitrate pointer table, indexed by version and layer */
80 static const short *bitrate_table[3][3] =
82 {bitrates[0], bitrates[1], bitrates[2]},
83 {bitrates[3], bitrates[4], bitrates[4]},
84 {bitrates[3], bitrates[4], bitrates[4]}
87 /* Sampling frequency table, indexed by version and frequency index */
88 static const unsigned short freq_table[3][3] =
90 {44100, 48000, 32000}, /* MPEG Version 1 */
91 {22050, 24000, 16000}, /* MPEG version 2 */
92 {11025, 12000, 8000}, /* MPEG version 2.5 */
95 unsigned long bytes2int(unsigned long b0, unsigned long b1,
96 unsigned long b2, unsigned long b3)
98 return (b0 & 0xFF) << (3*8) |
99 (b1 & 0xFF) << (2*8) |
100 (b2 & 0xFF) << (1*8) |
101 (b3 & 0xFF) << (0*8);
104 /* check if 'head' is a valid mp3 frame header */
105 static bool is_mp3frameheader(unsigned long head)
107 if ((head & SYNC_MASK) != (unsigned long)SYNC_MASK) /* bad sync? */
108 return false;
109 if ((head & VERSION_MASK) == (1L << 19)) /* bad version? */
110 return false;
111 if (!(head & LAYER_MASK)) /* no layer? */
112 return false;
113 #if CONFIG_CODEC != SWCODEC
114 /* The MAS can't decode layer 1, so treat layer 1 data as invalid */
115 if ((head & LAYER_MASK) == LAYER_MASK)
116 return false;
117 #endif
118 if ((head & BITRATE_MASK) == BITRATE_MASK) /* bad bitrate? */
119 return false;
120 if (!(head & BITRATE_MASK)) /* no bitrate? */
121 return false;
122 if ((head & SAMPLERATE_MASK) == SAMPLERATE_MASK) /* bad sample rate? */
123 return false;
125 return true;
128 static bool mp3headerinfo(struct mp3info *info, unsigned long header)
130 int bitindex, freqindex;
132 /* MPEG Audio Version */
133 if ((header & VERSION_MASK) >> 19 >= sizeof(version_table))
134 return false;
136 info->version = version_table[(header & VERSION_MASK) >> 19];
137 if (info->version < 0)
138 return false;
140 /* Layer */
141 info->layer = 3 - ((header & LAYER_MASK) >> 17);
142 if (info->layer == 3)
143 return false;
145 /* Rockbox: not used
146 info->protection = (header & PROTECTION_MASK) ? true : false;
149 /* Bitrate */
150 bitindex = (header & BITRATE_MASK) >> 12;
151 info->bitrate = bitrate_table[info->version][info->layer][bitindex];
152 if(info->bitrate == 0)
153 return false;
155 /* Sampling frequency */
156 freqindex = (header & SAMPLERATE_MASK) >> 10;
157 if (freqindex == 3)
158 return false;
159 info->frequency = freq_table[info->version][freqindex];
161 info->padding = (header & PADDING_MASK) ? 1 : 0;
163 /* Calculate number of bytes, calculation depends on layer */
164 if (info->layer == 0) {
165 info->frame_samples = 384;
166 info->frame_size = (12000 * info->bitrate / info->frequency
167 + info->padding) * 4;
169 else {
170 if ((info->version > MPEG_VERSION1) && (info->layer == 2))
171 info->frame_samples = 576;
172 else
173 info->frame_samples = 1152;
174 info->frame_size = (1000/8) * info->frame_samples * info->bitrate
175 / info->frequency + info->padding;
178 /* Frametime fraction denominator */
179 if (freqindex != 0) { /* 48/32/24/16/12/8 kHz */
180 info->ft_den = 1; /* integer number of milliseconds */
182 else { /* 44.1/22.05/11.025 kHz */
183 if (info->layer == 0) /* layer 1 */
184 info->ft_den = 147;
185 else /* layer 2+3 */
186 info->ft_den = 49;
188 /* Frametime fraction numerator */
189 info->ft_num = 1000 * info->ft_den * info->frame_samples / info->frequency;
191 info->channel_mode = (header & CHANNELMODE_MASK) >> 6;
192 /* Rockbox: not used
193 info->mode_extension = (header & MODE_EXT_MASK) >> 4;
194 info->emphasis = header & EMPHASIS_MASK;
196 VDEBUGF( "Header: %08lx, Ver %d, lay %d, bitr %d, freq %ld, "
197 "chmode %d, bytes: %d time: %d/%d\n",
198 header, info->version, info->layer+1, info->bitrate,
199 info->frequency, info->channel_mode,
200 info->frame_size, info->ft_num, info->ft_den);
201 return true;
204 static unsigned long __find_next_frame(int fd, long *offset, long max_offset,
205 unsigned long last_header,
206 int(*getfunc)(int fd, unsigned char *c))
208 unsigned long header=0;
209 unsigned char tmp;
210 int i;
212 long pos = 0;
214 /* We remember the last header we found, to use as a template to see if
215 the header we find has the same frequency, layer etc */
216 last_header &= 0xffff0c00;
218 /* Fill up header with first 24 bits */
219 for(i = 0; i < 3; i++) {
220 header <<= 8;
221 if(!getfunc(fd, &tmp))
222 return 0;
223 header |= tmp;
224 pos++;
227 do {
228 header <<= 8;
229 if(!getfunc(fd, &tmp))
230 return 0;
231 header |= tmp;
232 pos++;
233 if(max_offset > 0 && pos > max_offset)
234 return 0;
235 } while(!is_mp3frameheader(header) ||
236 (last_header?((header & 0xffff0c00) != last_header):false));
238 *offset = pos - 4;
240 if(*offset)
241 VDEBUGF("Warning: skipping %ld bytes of garbage\n", *offset);
243 return header;
246 static int fileread(int fd, unsigned char *c)
248 return read(fd, c, 1);
251 unsigned long find_next_frame(int fd, long *offset, long max_offset, unsigned long last_header)
253 return __find_next_frame(fd, offset, max_offset, last_header, fileread);
256 #ifndef __PCTOOL__
257 static int fnf_read_index;
258 static int fnf_buf_len;
260 static int buf_getbyte(int fd, unsigned char *c)
262 if(fnf_read_index < fnf_buf_len)
264 *c = audiobuf[fnf_read_index++];
265 return 1;
267 else
269 fnf_buf_len = read(fd, audiobuf, audiobufend - audiobuf);
270 if(fnf_buf_len < 0)
271 return -1;
273 fnf_read_index = 0;
275 if(fnf_buf_len > 0)
277 *c = audiobuf[fnf_read_index++];
278 return 1;
280 else
281 return 0;
283 return 0;
286 static int buf_seek(int fd, int len)
288 fnf_read_index += len;
289 if(fnf_read_index > fnf_buf_len)
291 len = fnf_read_index - fnf_buf_len;
293 fnf_buf_len = read(fd, audiobuf, audiobufend - audiobuf);
294 if(fnf_buf_len < 0)
295 return -1;
297 fnf_read_index = 0;
298 fnf_read_index += len;
301 if(fnf_read_index > fnf_buf_len)
303 return -1;
305 else
306 return 0;
309 static void buf_init(void)
311 fnf_buf_len = 0;
312 fnf_read_index = 0;
315 static unsigned long buf_find_next_frame(int fd, long *offset, long max_offset,
316 unsigned long last_header)
318 return __find_next_frame(fd, offset, max_offset, last_header, buf_getbyte);
321 static int audiobuflen;
322 static int mem_pos;
323 static int mem_cnt;
324 static int mem_maxlen;
326 static int mem_getbyte(int dummy, unsigned char *c)
328 dummy = dummy;
330 *c = audiobuf[mem_pos++];
331 if(mem_pos >= audiobuflen)
332 mem_pos = 0;
334 if(mem_cnt++ >= mem_maxlen)
335 return 0;
336 else
337 return 1;
340 unsigned long mem_find_next_frame(int startpos, long *offset, long max_offset,
341 unsigned long last_header)
343 audiobuflen = audiobufend - audiobuf;
344 mem_pos = startpos;
345 mem_cnt = 0;
346 mem_maxlen = max_offset;
348 return __find_next_frame(0, offset, max_offset, last_header, mem_getbyte);
350 #endif
352 int get_mp3file_info(int fd, struct mp3info *info)
354 unsigned char frame[1800];
355 unsigned char *vbrheader;
356 unsigned long header;
357 long bytecount;
358 int num_offsets;
359 int i;
360 long offset;
361 int j;
362 long tmp;
364 header = find_next_frame(fd, &bytecount, 0x20000, 0);
365 /* Quit if we haven't found a valid header within 128K */
366 if(header == 0)
367 return -1;
369 memset(info, 0, sizeof(struct mp3info));
370 memset(frame, 0, sizeof(frame));
371 #if CONFIG_CODEC==SWCODEC
372 /* These two are needed for proper LAME gapless MP3 playback */
373 info->enc_delay = -1;
374 info->enc_padding = -1;
375 #endif
376 if(!mp3headerinfo(info, header))
377 return -2;
379 /* OK, we have found a frame. Let's see if it has a Xing header */
380 if (info->frame_size-4 >= (int)sizeof(frame))
382 DEBUGF("Error: Invalid id3 header, frame_size: %d\n", info->frame_size);
383 return -8;
386 if(read(fd, frame, info->frame_size-4) < 0)
387 return -3;
389 /* calculate position of VBR header */
390 if ( info->version == MPEG_VERSION1 ) {
391 if (info->channel_mode == 3) /* mono */
392 vbrheader = frame + 17;
393 else
394 vbrheader = frame + 32;
396 else {
397 if (info->channel_mode == 3) /* mono */
398 vbrheader = frame + 9;
399 else
400 vbrheader = frame + 17;
403 if (!memcmp(vbrheader, "Xing", 4)
404 || !memcmp(vbrheader, "Info", 4))
406 int i = 8; /* Where to start parsing info */
408 /* DEBUGF("Xing/Info header\n"); */
410 /* Remember where in the file the Xing header is */
411 /* Rockbox: not used
412 info->vbr_header_pos = lseek(fd, 0, SEEK_CUR) - info->frame_size;
414 /* We want to skip the Xing frame when playing the stream */
415 bytecount += info->frame_size;
417 /* Now get the next frame to find out the real info about
418 the mp3 stream */
419 header = find_next_frame(fd, &tmp, 0x20000, 0);
420 if(header == 0)
421 return -4;
423 if(!mp3headerinfo(info, header))
424 return -5;
426 /* Is it a VBR file? */
427 info->is_vbr = !memcmp(vbrheader, "Xing", 4);
428 /* Rockbox: not used
429 info->is_xing_vbr = info->is_vbr;
432 if (vbrheader[7] & VBR_FRAMES_FLAG) /* Is the frame count there? */
434 info->frame_count = bytes2int(vbrheader[i], vbrheader[i+1],
435 vbrheader[i+2], vbrheader[i+3]);
436 if (info->frame_count <= ULONG_MAX / info->ft_num)
437 info->file_time = info->frame_count * info->ft_num / info->ft_den;
438 else
439 info->file_time = info->frame_count / info->ft_den * info->ft_num;
440 i += 4;
443 if (vbrheader[7] & VBR_BYTES_FLAG) /* Is byte count there? */
445 info->byte_count = bytes2int(vbrheader[i], vbrheader[i+1],
446 vbrheader[i+2], vbrheader[i+3]);
447 i += 4;
450 if (info->file_time && info->byte_count)
452 if (info->byte_count <= (ULONG_MAX/8))
453 info->bitrate = info->byte_count * 8 / info->file_time;
454 else
455 info->bitrate = info->byte_count / (info->file_time >> 3);
458 if (vbrheader[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */
460 info->has_toc = true;
461 memcpy( info->toc, vbrheader+i, 100 );
462 i += 100;
464 if (vbrheader[7] & VBR_QUALITY_FLAG)
466 /* We don't care about this, but need to skip it */
467 i += 4;
469 #if CONFIG_CODEC==SWCODEC
470 i += 21;
471 info->enc_delay = ((int)vbrheader[i ] << 4) | (vbrheader[i+1] >> 4);
472 info->enc_padding = ((int)vbrheader[i+1] << 8) | vbrheader[i+2];
473 /* TODO: This sanity checking is rather silly, seeing as how the LAME
474 header contains a CRC field that can be used to verify integrity. */
475 if (!(info->enc_delay >= 0 && info->enc_delay <= 2880 &&
476 info->enc_padding >= 0 && info->enc_padding <= 2*1152))
478 /* Invalid data */
479 info->enc_delay = -1;
480 info->enc_padding = -1;
482 #endif
485 if (!memcmp(vbrheader, "VBRI", 4))
487 VDEBUGF("VBRI header\n");
489 /* We want to skip the VBRI frame when playing the stream */
490 bytecount += info->frame_size;
492 /* Now get the next frame to find out the real info about
493 the mp3 stream */
494 header = find_next_frame(fd, &tmp, 0x20000, 0);
495 if(header == 0)
496 return -6;
498 bytecount += tmp;
500 if(!mp3headerinfo(info, header))
501 return -7;
503 VDEBUGF("%04x: %04x %04x ", 0, (short)(header >> 16),
504 (short)(header & 0xffff));
505 for(i = 4;i < (int)sizeof(frame)-4;i+=2) {
506 if(i % 16 == 0) {
507 VDEBUGF("\n%04x: ", i-4);
509 VDEBUGF("%04x ", (frame[i-4] << 8) | frame[i-4+1]);
512 VDEBUGF("\n");
514 /* Yes, it is a FhG VBR file */
515 info->is_vbr = true;
516 /* Rockbox: not used
517 info->is_vbri_vbr = true;
519 info->has_toc = false; /* We don't parse the TOC (yet) */
521 info->byte_count = bytes2int(vbrheader[10], vbrheader[11],
522 vbrheader[12], vbrheader[13]);
523 info->frame_count = bytes2int(vbrheader[14], vbrheader[15],
524 vbrheader[16], vbrheader[17]);
525 if (info->frame_count <= ULONG_MAX / info->ft_num)
526 info->file_time = info->frame_count * info->ft_num / info->ft_den;
527 else
528 info->file_time = info->frame_count / info->ft_den * info->ft_num;
530 if (info->byte_count <= (ULONG_MAX/8))
531 info->bitrate = info->byte_count * 8 / info->file_time;
532 else
533 info->bitrate = info->byte_count / (info->file_time >> 3);
535 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
536 num_offsets = bytes2int(0, 0, vbrheader[18], vbrheader[19]);
537 VDEBUGF("Frame size (%dkpbs): %d bytes (0x%x)\n",
538 info->bitrate, info->frame_size, info->frame_size);
539 VDEBUGF("Frame count: %lx\n", info->frame_count);
540 VDEBUGF("Byte count: %lx\n", info->byte_count);
541 VDEBUGF("Offsets: %d\n", num_offsets);
542 VDEBUGF("Frames/entry: %ld\n",
543 bytes2int(0, 0, vbrheader[24], vbrheader[25]));
545 offset = 0;
547 for(i = 0;i < num_offsets;i++)
549 j = bytes2int(0, 0, vbrheader[26+i*2], vbrheader[27+i*2]);
550 offset += j;
551 VDEBUGF("%03d: %lx (%x)\n", i, offset - bytecount, j);
555 return bytecount;
558 #ifndef __PCTOOL__
559 static void long2bytes(unsigned char *buf, long val)
561 buf[0] = (val >> 24) & 0xff;
562 buf[1] = (val >> 16) & 0xff;
563 buf[2] = (val >> 8) & 0xff;
564 buf[3] = val & 0xff;
567 int count_mp3_frames(int fd, int startpos, int filesize,
568 void (*progressfunc)(int))
570 unsigned long header = 0;
571 struct mp3info info;
572 int num_frames;
573 long bytes;
574 int cnt;
575 long progress_chunk = filesize / 50; /* Max is 50%, in 1% increments */
576 int progress_cnt = 0;
577 bool is_vbr = false;
578 int last_bitrate = 0;
579 int header_template = 0;
581 if(lseek(fd, startpos, SEEK_SET) < 0)
582 return -1;
584 buf_init();
586 /* Find out the total number of frames */
587 num_frames = 0;
588 cnt = 0;
590 while((header = buf_find_next_frame(fd, &bytes, -1, header_template))) {
591 mp3headerinfo(&info, header);
593 if(!header_template)
594 header_template = header;
596 /* See if this really is a VBR file */
597 if(last_bitrate && info.bitrate != last_bitrate)
599 is_vbr = true;
601 last_bitrate = info.bitrate;
603 buf_seek(fd, info.frame_size-4);
604 num_frames++;
605 if(progressfunc)
607 cnt += bytes + info.frame_size;
608 if(cnt > progress_chunk)
610 progress_cnt++;
611 progressfunc(progress_cnt);
612 cnt = 0;
616 VDEBUGF("Total number of frames: %d\n", num_frames);
618 if(is_vbr)
619 return num_frames;
620 else
622 DEBUGF("Not a VBR file\n");
623 return 0;
627 static const char cooltext[] = "Rockbox - rocks your box";
629 /* buf needs to be the audio buffer with TOC generation enabled,
630 and at least MAX_XING_HEADER_SIZE bytes otherwise */
631 int create_xing_header(int fd, long startpos, long filesize,
632 unsigned char *buf, unsigned long num_frames,
633 unsigned long rec_time, unsigned long header_template,
634 void (*progressfunc)(int), bool generate_toc)
636 struct mp3info info;
637 unsigned char toc[100];
638 unsigned long header = 0;
639 unsigned long xing_header_template = header_template;
640 unsigned long filepos;
641 long pos, last_pos;
642 long j;
643 long bytes;
644 int i;
645 int index;
647 DEBUGF("create_xing_header()\n");
649 if(generate_toc)
651 lseek(fd, startpos, SEEK_SET);
652 buf_init();
654 /* Generate filepos table */
655 last_pos = 0;
656 filepos = 0;
657 header = 0;
658 for(i = 0;i < 100;i++) {
659 /* Calculate the absolute frame number for this seek point */
660 pos = i * num_frames / 100;
662 /* Advance from the last seek point to this one */
663 for(j = 0;j < pos - last_pos;j++)
665 header = buf_find_next_frame(fd, &bytes, -1, header_template);
666 filepos += bytes;
667 mp3headerinfo(&info, header);
668 buf_seek(fd, info.frame_size-4);
669 filepos += info.frame_size;
671 if(!header_template)
672 header_template = header;
675 /* Save a header for later use if header_template is empty.
676 We only save one header, and we want to save one in the
677 middle of the stream, just in case the first and the last
678 headers are corrupt. */
679 if(!xing_header_template && i == 1)
680 xing_header_template = header;
682 if(progressfunc)
684 progressfunc(50 + i/2);
687 /* Fill in the TOC entry */
688 /* each toc is a single byte indicating how many 256ths of the
689 * way through the file, is that percent of the way through the
690 * song. the easy method, filepos*256/filesize, chokes when
691 * the upper 8 bits of the file position are nonzero
692 * (i.e. files over 16mb in size).
694 if (filepos > (ULONG_MAX/256))
696 /* instead of multiplying filepos by 256, we divide
697 * filesize by 256.
699 toc[i] = filepos / (filesize >> 8);
701 else
703 toc[i] = filepos * 256 / filesize;
706 VDEBUGF("Pos %d: %ld relpos: %ld filepos: %lx tocentry: %x\n",
707 i, pos, pos-last_pos, filepos, toc[i]);
709 last_pos = pos;
713 /* Use the template header and create a new one.
714 We ignore the Protection bit even if the rest of the stream is
715 protected. */
716 header = xing_header_template & ~(BITRATE_MASK|PROTECTION_MASK|PADDING_MASK);
717 header |= 8 << 12; /* This gives us plenty of space, 192..576 bytes */
719 if (!mp3headerinfo(&info, header))
720 return 0; /* invalid header */
722 if (num_frames == 0 && rec_time) {
723 /* estimate the number of frames based on the recording time */
724 if (rec_time <= ULONG_MAX / info.ft_den)
725 num_frames = rec_time * info.ft_den / info.ft_num;
726 else
727 num_frames = rec_time / info.ft_num * info.ft_den;
730 /* Clear the frame */
731 memset(buf, 0, MAX_XING_HEADER_SIZE);
733 /* Write the header to the buffer */
734 long2bytes(buf, header);
736 /* Calculate position of VBR header */
737 if (info.version == MPEG_VERSION1) {
738 if (info.channel_mode == 3) /* mono */
739 index = 21;
740 else
741 index = 36;
743 else {
744 if (info.channel_mode == 3) /* mono */
745 index = 13;
746 else
747 index = 21;
750 /* Create the Xing data */
751 memcpy(&buf[index], "Xing", 4);
752 long2bytes(&buf[index+4], (num_frames ? VBR_FRAMES_FLAG : 0)
753 | (filesize ? VBR_BYTES_FLAG : 0)
754 | (generate_toc ? VBR_TOC_FLAG : 0));
755 index += 8;
756 if(num_frames)
758 long2bytes(&buf[index], num_frames);
759 index += 4;
762 if(filesize)
764 long2bytes(&buf[index], filesize - startpos);
765 index += 4;
768 /* Copy the TOC */
769 memcpy(buf + index, toc, 100);
771 /* And some extra cool info */
772 memcpy(buf + index + 100, cooltext, sizeof(cooltext));
774 #ifdef DEBUG
775 for(i = 0;i < info.frame_size;i++)
777 if(i && !(i % 16))
778 DEBUGF("\n");
780 DEBUGF("%02x ", buf[i]);
782 #endif
784 return info.frame_size;
787 #endif