📄 mp3data.c
字号:
/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id: mp3data.c,v 1.21 2004/01/13 14:06:18 linusnielsen Exp $ * * Copyright (C) 2002 by Daniel Stenberg * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************//* * Parts of this code has been stolen from the Ample project and was written * by David H鋜deman. It has since been extended and enhanced pretty much by * all sorts of friendly Rockbox people. * * A nice reference for MPEG header info: * http://rockbox.haxx.se/docs/mpeghdr.html * */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdbool.h>#include "debug.h"#include "mp3data.h"#include "file.h"#include "buffer.h"#define DEBUG_VERBOSE#define BYTES2INT(b1,b2,b3,b4) (((b1 & 0xFF) << (3*8)) | \ ((b2 & 0xFF) << (2*8)) | \ ((b3 & 0xFF) << (1*8)) | \ ((b4 & 0xFF) << (0*8)))#define SYNC_MASK (0x7ff << 21)#define VERSION_MASK (3 << 19)#define LAYER_MASK (3 << 17)#define PROTECTION_MASK (1 << 16)#define BITRATE_MASK (0xf << 12)#define SAMPLERATE_MASK (3 << 10)#define PADDING_MASK (1 << 9)#define PRIVATE_MASK (1 << 8)#define CHANNELMODE_MASK (3 << 6)#define MODE_EXT_MASK (3 << 4)#define COPYRIGHT_MASK (1 << 3)#define ORIGINAL_MASK (1 << 2)#define EMPHASIS_MASK 3/* Table of bitrates for MP3 files, all values in kilo. * Indexed by version, layer and value of bit 15-12 in header. */const int bitrate_table[2][3][16] ={ { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, {0,32,48,56, 64,80, 96, 112,128,160,192,224,256,320,384,0}, {0,32,40,48, 56,64, 80, 96, 112,128,160,192,224,256,320,0} }, { {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,0}, {0, 8,16,24,32,40,48, 56, 64, 80, 96,112,128,144,160,0}, {0, 8,16,24,32,40,48, 56, 64, 80, 96,112,128,144,160,0} }};/* Table of samples per frame for MP3 files. * Indexed by layer. Multiplied with 1000. */const int bs[3] = {384000, 1152000, 1152000};/* Table of sample frequency for MP3 files. * Indexed by version and layer. */const int freqtab[][4] ={ {11025, 12000, 8000, 0}, /* MPEG version 2.5 */ {44100, 48000, 32000, 0}, /* MPEG Version 1 */ {22050, 24000, 16000, 0}, /* MPEG version 2 */};/* check if 'head' is a valid mp3 frame header */static bool is_mp3frameheader(unsigned long head){ if ((head & SYNC_MASK) != (unsigned long)SYNC_MASK) /* bad sync? */ return false; if ((head & VERSION_MASK) == (1 << 19)) /* bad version? */ return false; if (!(head & LAYER_MASK)) /* no layer? */ return false; if ((head & BITRATE_MASK) == BITRATE_MASK) /* bad bitrate? */ return false; if (!(head & BITRATE_MASK)) /* no bitrate? */ return false; if ((head & SAMPLERATE_MASK) == SAMPLERATE_MASK) /* bad sample rate? */ return false; if (((head >> 19) & 1) == 1 && ((head >> 17) & 3) == 3 && ((head >> 16) & 1) == 1) return false; if ((head & 0xffff0000) == 0xfffe0000) return false; return true;}static bool mp3headerinfo(struct mp3info *info, unsigned long header){ int bittable = 0; int bitindex; int freqindex; /* MPEG Audio Version */ switch(header & VERSION_MASK) { case 0: /* MPEG version 2.5 is not an official standard */ info->version = MPEG_VERSION2_5; bittable = MPEG_VERSION2 - 1; /* use the V2 bit rate table */ break; case (1 << 19): return false; case (2 << 19): /* MPEG version 2 (ISO/IEC 13818-3) */ info->version = MPEG_VERSION2; bittable = MPEG_VERSION2 - 1; break; case (3 << 19): /* MPEG version 1 (ISO/IEC 11172-3) */ info->version = MPEG_VERSION1; bittable = MPEG_VERSION1 - 1; break; } switch(header & LAYER_MASK) { case 0: return false; case (1 << 17): info->layer = 2; break; case (2 << 17): info->layer = 1; break; case (3 << 17): info->layer = 0; break; } info->protection = (header & PROTECTION_MASK)?true:false; /* Bitrate */ bitindex = (header & 0xf000) >> 12; info->bitrate = bitrate_table[bittable][info->layer][bitindex]; if(info->bitrate == 0) return false; /* Sampling frequency */ freqindex = (header & 0x0C00) >> 10; info->frequency = freqtab[info->version][freqindex]; if(info->frequency == 0) return false; info->padding = (header & 0x0200)?1:0; /* Calculate number of bytes, calculation depends on layer */ switch(info->layer) { case 0: info->frame_size = info->bitrate * 48000; info->frame_size /= freqtab[info->version][freqindex] << bittable; break; case 1: case 2: info->frame_size = info->bitrate * 144000; info->frame_size /= freqtab[info->version][freqindex] << bittable; break; default: info->frame_size = 1; } info->frame_size += info->padding; /* Calculate time per frame */ info->frame_time = bs[info->layer] / (freqtab[info->version][freqindex] << bittable); info->channel_mode = (header & 0xc0) >> 6; info->mode_extension = (header & 0x30) >> 4; info->emphasis = header & 3;#ifdef DEBUG_VERBOSE DEBUGF( "Header: %08x, Ver %d, lay %d, bitr %d, freq %d, " "chmode %d, mode_ext %d, emph %d, bytes: %d time: %d\n", header, info->version, info->layer, info->bitrate, info->frequency, info->channel_mode, info->mode_extension, info->emphasis, info->frame_size, info->frame_time);#endif return true;}static unsigned long __find_next_frame(int fd, int *offset, int max_offset, unsigned long last_header, int(*getfunc)(int fd, unsigned char *c)){ unsigned long header=0; unsigned char tmp; int i; int pos = 0; /* We remember the last header we found, to use as a template to see if the header we find has the same frequency, layer etc */ last_header &= 0xffff0c00; /* Fill up header with first 24 bits */ for(i = 0; i < 3; i++) { header <<= 8; if(!getfunc(fd, &tmp)) return 0; header |= tmp; pos++; } do { header <<= 8; if(!getfunc(fd, &tmp)) return 0; header |= tmp; pos++; if(max_offset > 0 && pos > max_offset) return 0; } while(!is_mp3frameheader(header) || (last_header?((header & 0xffff0c00) != last_header):false)); *offset = pos - 4;#if defined(DEBUG) || defined(SIMULATOR) if(*offset) DEBUGF("Warning: skipping %d bytes of garbage\n", *offset);#endif return header;}static int fileread(int fd, unsigned char *c){ return read(fd, c, 1);}unsigned long find_next_frame(int fd, int *offset, int max_offset, unsigned long last_header){ return __find_next_frame(fd, offset, max_offset, last_header, fileread);}static int fnf_read_index;static int fnf_buf_len;static int buf_getbyte(int fd, unsigned char *c){ if(fnf_read_index < fnf_buf_len) { *c = mp3buf[fnf_read_index++]; return 1; } else { fnf_buf_len = read(fd, mp3buf, mp3end - mp3buf); if(fnf_buf_len < 0) return -1; fnf_read_index = 0; if(fnf_buf_len > 0) { *c = mp3buf[fnf_read_index++]; return 1; } else return 0; } return 0;}static int buf_seek(int fd, int len){ fnf_read_index += len; if(fnf_read_index > fnf_buf_len) { len = fnf_read_index - fnf_buf_len; fnf_buf_len = read(fd, mp3buf, mp3end - mp3buf); if(fnf_buf_len < 0) return -1; fnf_read_index = 0; fnf_read_index += len; } if(fnf_read_index > fnf_buf_len) { return -1; } else return 0;}static void buf_init(void){ fnf_buf_len = 0; fnf_read_index = 0;}unsigned long buf_find_next_frame(int fd, int *offset, int max_offset, unsigned long last_header){ return __find_next_frame(fd, offset, max_offset, last_header, buf_getbyte);}static int mp3buflen;static int mem_pos;static int mem_cnt;static int mem_maxlen;static int mem_getbyte(int dummy, unsigned char *c){ dummy = dummy; *c = mp3buf[mem_pos++]; if(mem_pos >= mp3buflen) mem_pos = 0; if(mem_cnt++ >= mem_maxlen) return 0; else return 1;}unsigned long mem_find_next_frame(int startpos, int *offset, int max_offset, unsigned long last_header){ mp3buflen = mp3end - mp3buf; mem_pos = startpos; mem_cnt = 0; mem_maxlen = max_offset; return __find_next_frame(0, offset, max_offset, last_header, mem_getbyte);}int get_mp3file_info(int fd, struct mp3info *info){ unsigned char frame[1800]; unsigned char *vbrheader; unsigned long header; int bytecount; int num_offsets; int frames_per_entry; int i; int offset; int j; int tmp; header = find_next_frame(fd, &bytecount, 0x20000, 0); /* Quit if we haven't found a valid header within 128K */ if(header == 0) return -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -