/**************************************************************************************
MP3 同步头搜索并检验程序
**************************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MP3_HEADER_MASK 0xFFFE0C00 // 同步头匹配, 忽略比特率
#define MIN_MP3_DURATION 4000
#define MP3_MIN_LENGTH 1000 // MP3 文件最小长度
#define MP3_BUF_LENGTH 1024 // MP3 文件缓冲区大小
#define MP3_SEARCH_LEN 0x3FFE // MP3 搜索同步头最大长度
#define MAX_AUDIO_FILE 10
/* audio error code */
#define AUDIO_ERR_NONE 0 // 无错误
#define AUDIO_ERR_DISK 1 // 磁盘错误(读写)
#define AUDIO_ERR_FORMAT 2 // 文件格式错误
#define AUDIO_ERR_MEMORY 3 // 内存错误
#define AUDIO_ERR_PARAM 4 // 参数错误
#define AUDIO_ERR_NOTSUPPORT 5 // 不支持的操作或类型
#define AUDIO_ERR_TOOMANYFILE 6 // 打开太多文件
#define AUDIO_ERR_NOTFOUND 7 // 文件未找到
#define AUDIO_ERR_LOWVOLTAGE 8 // 低电
#define AUDIO_ERR_DECODER 9 // 解码器未响应
#define AUDIO_ERR_DISKFULL 10 // 磁盘满
// MP3
typedef struct tagFRAMEHEADER
{
unsigned emphasis : 2; // M ▓
unsigned original : 1; // L
unsigned copyright : 1; // K
unsigned modeext : 2; // J
unsigned chanmode : 2; // I
unsigned privbit : 1; // H
unsigned padding : 1; // G
unsigned samplerate : 2; // F
unsigned bitrate : 4; // E
unsigned hascrc : 1; // D
unsigned mpeglayer : 2; // C
unsigned mpegver : 2; // B
unsigned framesync : 11; // A
} FRAMEHEADER;
typedef struct tagMEDIAFILEINFO
{
unsigned long dwFileLength; // 文件长度
unsigned long dwDuration; // 播放时间
unsigned long dwBitRate; // 比特率
unsigned long dwSampleRate; // 采样率
unsigned char bSampleSize; // 采样大小
unsigned char bChannels; // 声道数目
unsigned char bIsVBR; // 是否为变速
unsigned char bIsProtected; // 是否受保护
unsigned long dwNumOfFrames; // 帧数量
unsigned long dwFrameSize; // 帧大小
unsigned long dwFrameDuration; // 帧播放时间
unsigned long dwFrameOffset; // 首帧偏移
const char* szArtist; // 艺术家
const char* szAlbumTitle; // 专辑名
unsigned short wYear; // 年
unsigned short wTrackNumber; // 音轨号
const char* szGenre; // 流派
const char* szLyrics; // 文本歌词
const char* szTitle; // 名称
const char* szComments; // 备注
} MEDIAFILEINFO;
typedef struct tagMP3_FILE
{
FILE* fp;
MEDIAFILEINFO mfi;
unsigned char* vbr_toc;
long pos;
unsigned long* vbri_toc;
long vbri_toc_cnt;
long vbri_toc_frm;
float fFrameDuration;
} MP3_FILE;
///
const int nMpegVer [] = { 3, 0, 2, 1 };
const int nMpegLayer[] = { 0, 3, 2, 1 };
const int nBitrateTable[3][3][16] =
{
// V1 L1
0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1,
// V1 L2
0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1,
// V1 L3
0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1,
// V2 L1
0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1,
// V2 L2
0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1,
// V2 L3
// 0, 8, 16, 24, 32, 64, 80, 56, 64, 128, 160, 112, 128, 256, 320, -1,
0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1,
// V2.5 L1
0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1,
// V2.5 L2
0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1,
// V2.5 L3
// 0, 8, 16, 24, 32, 64, 80, 56, 64, 128, 160, 112, 128, 256, 320, -1
0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1
};
const int nSamplingRateTable[3][4] =
{
// MPEG1 // MPEG 2 // MPEG 2.5
44100, 48000, 32000, 0, 22050, 24000, 16000, 0, 11025, 12000, 8000, 0
};
// Samples per Frame: 1. index = LSF, 2. index = Layer
const int dwSamplesPerFrames[][3] =
{
{ // MPEG 1
384, // Layer1
1152, // Layer2
1152 // Layer3
},
{ // MPEG 2
384, // Layer1
1152, // Layer2
576 // Layer3
},
{ // MPEG 2.5
384, // Layer1
1152, // Layer2
576 // Layer3
}
};
///
static MP3_FILE* mp3HandleTable[10];
int gAudioErrCode; // 错误代码
int gWaittingMemory;
///
static void REV_DWORD(void* p);
int IsValidFrameHeader(FRAMEHEADER* pfh);
///
// reverse dword(32 bit)
static
void REV_DWORD(void* p)
{
unsigned char b0, b1, b2, b3;
b0 = *((unsigned char*)p + 0);
b1 = *((unsigned char*)p + 1);
b2 = *((unsigned char*)p + 2);
b3 = *((unsigned char*)p + 3);
*((unsigned char*)p + 0) = b3;
*((unsigned char*)p + 1) = b2;
*((unsigned char*)p + 2) = b1;
*((unsigned char*)p + 3) = b0;
}
static
unsigned short RevShort(unsigned short data)
{
unsigned char b0, b1 ;
short *p = &data ;
b0 = *((unsigned char*)p + 0);
b1 = *((unsigned char*)p + 1);
*((unsigned char*)p + 0) = b1;
*((unsigned char*)p + 1) = b0;
return data ;
}
// 验证是否为有效帧头
int IsValidFrameHeader(FRAMEHEADER* pfh)
{
// 11 bit
if (0x7FF != pfh->framesync) return 0;
// 2bit
if (0x01 == pfh->mpegver) return 0;
// 2bit
if (0x00 == pfh->mpeglayer) return 0;
// 4bit
if (0x00 == pfh->bitrate || 0x0F == pfh->bitrate) return 0;
// 2bit
if (0x03 == pfh->samplerate) return 0;
return 1;
}
// calc frame size
long calc_mp3_frm_size(FRAMEHEADER* pfh)
{
int ver = nMpegVer[pfh->mpegver];
int layer = nMpegLayer[pfh->mpeglayer];
long frame_size;
int bit_rate;
int sample_rate;
bit_rate = nBitrateTable[ver - 1][layer - 1][pfh->bitrate];
sample_rate = nSamplingRateTable[ver - 1][pfh->samplerate];
if (1 == ver) // MPEG 1
frame_size = 144 * 1000 * bit_rate / sample_rate + pfh->padding;
else
frame_size = 72 * 1000 * bit_rate / sample_rate + pfh->padding;
return frame_size;
}
///
int MP3_Init(void)
{
memset(mp3HandleTable, 0x00, MAX_AUDIO_FILE * sizeof(MP3_FILE*));
return 0;
}
int MP3_Open(char* mp3_filename)
{
FRAMEHEADER fh;
int valid_frame = 0;
long id;
int i;
FILE* fp;
long file_length; // 文件长度
// MP3 frame info
long frame_num; // 帧总数
long frame_size; // 帧大小
long frame_offset; // 第一个帧在文件内偏移
// MP3 format info
unsigned char* vbr_toc; // VBR索引 (Xing)
unsigned long* vbri_toc; // (VBRI)
long vbri_toc_cnt; // (VBRI)
long vbri_toc_frm; // (VBRI)
unsigned char is_vbr_format; // 是否为VBR格式
unsigned char channels;
int bit_rate; // 比特率
int sample_rate; // 采样率
int duration; // 总播放时间
long search_start; // 开始搜索帧头的位置
float fFrameDuration;
fp = fopen(mp3_filename, "rb");
if (0 == fp)
{
gAudioErrCode = AUDIO_ERR_NOTFOUND;
return -1;
}
fseek(fp, 0, SEEK_END);
file_length = ftell(fp);
if (file_length MP3_MIN_LENGTH)
{
gAudioErrCode = AUDIO_ERR_FORMAT;
fclose(fp);
return -1;
}
// ID3 tag
fseek(fp, -128, SEEK_END);
fread(&id, 4, 1, fp);
if ('GAT' == id) // "TAG\0"
file_length -= 128;
fseek(fp, 0, SEEK_SET);
if (!fread(&id, 4, 1, fp))
{
gAudioErrCode = AUDIO_ERR_FORMAT;
fclose(fp);
return -1;
}
// 存在ID3标签
id &= 0xFFFFFF; // remove version field
if (0x334449 == id) // 'ID3'
{
char buf[4];
fseek(fp, 2, SEEK_CUR);
if (!fread(buf, 4, 1, fp))
{
gAudioErrCode = AUDIO_ERR_FORMAT;
fclose(fp);
return -1;
}
else
{
frame_offset = (buf[0] & 0x7F) * 0x200000L
+ (buf[1] & 0x7F) * 0x004000L
+ (buf[2] & 0x7F) * 0x000080L
+ (buf[3] & 0x7F)
+ 10; // ID3 header
// ID3 length error
if (frame_offset file_length)
{
// read 1st frame header
fseek(fp, frame_offset, SEEK_SET);
if (!fread(&fh, 4, 1, fp))
{
gAudioErrCode = AUDIO_ERR_DISK;
fclose(fp);
return -1;
}
// big endian -> little endian
REV_DWORD(&fh);
valid_frame = IsValidFrameHeader(&fh);
}
}
}
else
{
fseek(fp, 0, SEEK_SET);
}
// search sync
if (!valid_frame)
{
search_start = ftell(fp);
while (1)
{
// read frame header
if (4 != fread(&fh, 1, 4, fp))
{
gAudioErrCode = AUDIO_ERR_FORMAT;
fclose(fp);
return -1;
}
// big endian -> little endian
REV_DWORD(&fh);
if (IsValidFrameHeader(&fh)) break;
if (ftell(fp) - search_start > MP3_SEARCH_LEN)
{
gAudioErrCode = AUDIO_ERR_FORMAT;
fclose(fp);
return -1;
}
fseek(fp, -3, SEEK_CUR);
}
}
else
{
search_start = 0;
}
// 1st frame header found
frame_offset = ftell(fp) - 4;
frame_size = calc_mp3_frm_size(&fh);
//-------------------------------------------------------------------------------------
// check for VBR format
if (3 == fh.mpegver) // MPEG 1
{
if (3 == fh.chanmode) // mono
fseek(fp, 21 - 4, SEEK_CUR);
else // stereo
fseek(fp, 36 - 4, SEEK_CUR);
}
else if (2 == fh.mpegver) // MPEG 2
{
if (3 == fh.chanmode) // mono
fseek(fp, 13 - 4, SEEK_CUR);
else // stereo
fseek(fp, 21 - 4, SEEK_CUR);
}
if (4 != fread(&id, 1, 4, fp))
{
gAudioErrCode = AUDIO_ERR_DISK;
fclose(fp);
return -1;
}
vbr_toc = (unsigned char*)0;
vbri_toc = 0;
vbri_toc_cnt = 0;
frame_num = 0;
is_vbr_format = ('gniX' == id) || // Xing
('ofnI' == id) || // Info
('IRBV' == id); // VBRI
// 0; // none
if (is_vbr_format)
{
if ('IRBV' == id) // 'VBRI'
{
unsigned short toc_cnt;
unsigned short toc_scale;
unsigned short toc_size;
unsigned short toc_frames;
fseek(fp, 6, SEEK_CUR);
// Number of Bytes as Big-Endian DWORD
if (0 == fread(&file_length, 4, 1, fp))
{
gAudioErrCode = AUDIO_ERR_DISK;
fclose(fp);
return -1;
}
REV_DWORD(&file_length);
// Number of Frames as Big-Endian DWORD
if (0 == fread(&frame_num, 4, 1, fp))
{
gAudioErrCode = AUDIO_ERR_DISK;
fclose(fp);
return -1;
}
REV_DWORD(&frame_num);
// Number of entries within TOC table as Big-Endian WORD
if (0 == fread(&toc_cnt, 2, 1, fp))
{
gAudioErrCode = AUDIO_ERR_DISK;
fclose(fp);
return -1;
}
toc_cnt = RevShort(toc_cnt);
vbri_toc_cnt = toc_cnt + 1; // !!!
// Scale factor of TOC table entries as Big-Endian WORD
if (0 == fread(&toc_scale, 2, 1, fp))
{
gAudioErrCode = AUDIO_ERR_DISK;
fclose(fp);
return -1;
}
toc_scale = RevShort(toc_scale);
// Size per table entry in bytes (max 4) as Big-Endian WORD
if (0 == fread(&toc_size, 2, 1, fp))
{
gAudioErrCode = AUDIO_ERR_DISK;
fclose(fp);
return -1;
}
toc_size = RevShort(toc_size);
if (toc_size > 4 || toc_size 1)
{
gAudioErrCode = AUDIO_ERR_FORMAT;
fclose(fp);
return -1;
}
// Frames per table entry as Big-Endian WORD
if (0 == fread(&toc_frames, 2, 1, fp))
{
gAudioErrCode = AUDIO_ERR_DISK;
fclose(fp);
return -1;
}
toc_frames = RevShort(toc_frames);
vbri_toc_frm = toc_frames;
vbri_toc = (unsigned long*)malloc(vbri_toc_cnt * sizeof(unsigned long));
if (!vbri_toc)
{
gAudioErrCode = AUDIO_ERR_MEMORY;
fclose(fp);
return -1;
}
// read toc
{
int j = vbri_toc_cnt + 1;
unsigned long* p = vbri_toc;
unsigned long pos = 0; // must be unsigned
float fscale;
while (--j)
{
unsigned long toc_entry = 0; // must be unsigned
if (0 == fread(&toc_entry, toc_size, 1, fp))
{
free(vbri_toc);
gAudioErrCode = AUDIO_ERR_FORMAT;
fclose(fp);
return -1;
}
REV_DWORD(&toc_entry);
toc_entry >>= 8 * (4 - toc_size);
pos += toc_entry * toc_scale;
*p++ = pos;
}
j = vbri_toc_cnt + 1;
p = vbri_toc;
fscale = (float)((double)file_length / (double)pos);
while (--j)
{
*p *= (unsigned long)fscale;
p++;
}
}
}
else // 'Xing'
{
long flag;
if (0 == fread(&flag, 4, 1, fp))
{
gAudioErrCode = AUDIO_ERR_DISK;
fclose(fp);
return -1;
}
REV_DWORD(&flag);
if (flag & 1) // Frames Flag
{
if (0 == fread(&frame_num, 4, 1, fp))
{
gAudioErrCode = AUDIO_ERR_DISK;
fclose(fp);
return -1;
}
REV_DWORD(&frame_num);
}
if (flag & 2) // Bytes Flag
{
if (0 == fread(&file_length, 4, 1, fp))
{
gAudioErrCode = AUDIO_ERR_DISK;
fclose(fp);
return -1;
}
REV_DWORD(&file_length);
}
vbr_toc = malloc(100);
if (0 == vbr_toc)
{
gAudioErrCode = AUDIO_ERR_MEMORY;
fclose(fp);
return -1;
}
if (flag & 4) // TOC Flag
{
if (0 == fread(vbr_toc, 100, 1, fp))
{
gAudioErrCode = AUDIO_ERR_DISK;
free(vbr_toc);
fclose(fp);
return -1;
}
}
else // TOC Flag does not exist, create it
{
for (i = 0; i 100; i++)
vbr_toc[i] = i * 256 / 100;
}
}
}
//-------------------------------------------------------------------------------------
else
{
long last_header;
// check next frame...
fseek(fp, frame_offset + frame_size, SEEK_SET);
while (1)
{
last_header = *(long*)&fh;
// search sync
while (1)
{
// read frame header
if (4 != fread(&fh, 1, 4, fp))
{
gAudioErrCode = AUDIO_ERR_FORMAT;
fclose(fp);
return -1;
}
// big endian -> little endian
REV_DWORD(&fh);
if (IsValidFrameHeader(&fh)) break;
if (ftell(fp) - search_start > MP3_SEARCH_LEN)
{
gAudioErrCode = AUDIO_ERR_FORMAT;
fclose(fp);
return -1;
}
fseek(fp, -3, SEEK_CUR);
}
// found it
if ((*(long*)&fh & MP3_HEADER_MASK) == (last_header & MP3_HEADER_MASK))
{
frame_size += calc_mp3_frm_size(&fh);
break;
}
// BUG文档编号: DW/BUG/200511/0203
frame_offset = ftell(fp) - 4;
frame_size = calc_mp3_frm_size(&fh);
fseek(fp, frame_size - 4, SEEK_CUR);
}
}
//-------------------------------------------------------------------------------------
{
int ver = nMpegVer[fh.mpegver];
int layer = nMpegLayer[fh.mpeglayer];
// only layer 3 is supportted
if (3 != layer)
{
gAudioErrCode = AUDIO_ERR_NOTSUPPORT;
if (vbr_toc) free(vbr_toc);
if (vbri_toc) free(vbri_toc);
fclose(fp);
return -1;
}
bit_rate = nBitrateTable[ver - 1][layer - 1][fh.bitrate];
sample_rate = nSamplingRateTable[ver - 1][fh.samplerate];
if (is_vbr_format)
fFrameDuration = (float)((double)dwSamplesPerFrames[ver - 1][layer - 1] * 1000.0 / (double)sample_rate);
else
fFrameDuration = (float)((double)frame_size * 8.0 / (double)bit_rate);
}
if (3 != fh.chanmode)
channels = 2;
else
channels = 1;
//-------------------------------------------------------------------------------------
if (0 == frame_num)
frame_num = (file_length - frame_offset) / frame_size;
duration = (int)((double)frame_num * (double)fFrameDuration);
//-------------------------------------------------------------------------------------
fseek(fp, frame_offset, SEEK_SET);
// find free handle
for (i = 0; i MAX_AUDIO_FILE; i++)
{
if (0 == mp3HandleTable[i])
break;
}
if (MAX_AUDIO_FILE == i)
{
gAudioErrCode = AUDIO_ERR_TOOMANYFILE;
if (vbr_toc) free(vbr_toc);
if (vbri_toc) free(vbri_toc);
fclose(fp);
return -1;
}
mp3HandleTable[i] = (MP3_FILE*)malloc(sizeof(MP3_FILE));
if (0 == mp3HandleTable[i])
{
gAudioErrCode = AUDIO_ERR_MEMORY;
if (vbr_toc) free(vbr_toc);
if (vbri_toc) free(vbri_toc);
fclose(fp);
return -1;
}
memset(mp3HandleTable[i], 0x00, sizeof(MP3_FILE));
mp3HandleTable[i]->fp = fp;
mp3HandleTable[i]->vbr_toc = vbr_toc;
mp3HandleTable[i]->vbri_toc = vbri_toc;
mp3HandleTable[i]->vbri_toc_cnt = vbri_toc_cnt;
mp3HandleTable[i]->vbri_toc_frm = vbri_toc_frm;
mp3HandleTable[i]->pos = frame_offset;
mp3HandleTable[i]->fFrameDuration = fFrameDuration;
// media file infomation
mp3HandleTable[i]->mfi.dwFileLength = file_length;
mp3HandleTable[i]->mfi.dwDuration = duration;
mp3HandleTable[i]->mfi.dwBitRate = bit_rate;
mp3HandleTable[i]->mfi.dwSampleRate = sample_rate;
mp3HandleTable[i]->mfi.bSampleSize = 16; // 16 bit
mp3HandleTable[i]->mfi.bChannels = channels;
mp3HandleTable[i]->mfi.bIsVBR = is_vbr_format;
mp3HandleTable[i]->mfi.bIsProtected = 1;
mp3HandleTable[i]->mfi.dwNumOfFrames = frame_num;
mp3HandleTable[i]->mfi.dwFrameSize = frame_size;
mp3HandleTable[i]->mfi.dwFrameDuration = (long)fFrameDuration;
mp3HandleTable[i]->mfi.dwFrameOffset = frame_offset;
mp3HandleTable[i]->mfi.szArtist = 0;
mp3HandleTable[i]->mfi.szAlbumTitle = 0;
mp3HandleTable[i]->mfi.wYear = 0;
mp3HandleTable[i]->mfi.wTrackNumber = 1;
mp3HandleTable[i]->mfi.szGenre = 0;
mp3HandleTable[i]->mfi.szLyrics = 0;
mp3HandleTable[i]->mfi.szTitle = 0;
mp3HandleTable[i]->mfi.szComments = 0;
gAudioErrCode = AUDIO_ERR_NONE;
return i;
}
int MP3_Close(int handle)
{
if (handle >= MAX_AUDIO_FILE)
{
gAudioErrCode = AUDIO_ERR_PARAM;
return -1;
}
if (0 == mp3HandleTable[handle])
{
gAudioErrCode = AUDIO_ERR_PARAM;
return -1;
}
if (mp3HandleTable[handle]->vbr_toc)
free(mp3HandleTable[handle]->vbr_toc);
if (mp3HandleTable[handle]->vbri_toc)
free(mp3HandleTable[handle]->vbri_toc);
fclose(mp3HandleTable[handle]->fp);
free(mp3HandleTable[handle]);
mp3HandleTable[handle] = 0;
return 0;
}
int MP3_Seek(int handle, unsigned long time)
{
MEDIAFILEINFO* pmfi;
long pos;
if (handle >= MAX_AUDIO_FILE)
{
gAudioErrCode = AUDIO_ERR_PARAM;
return -1;
}
if (0 == mp3HandleTable[handle])
{
gAudioErrCode = AUDIO_ERR_PARAM;
return -1;
}
pmfi = &mp3HandleTable[handle]->mfi;
if (time 0)
time = 0;
if (time > pmfi->dwDuration)
time = pmfi->dwDuration;
#ifdef MP3_SUPPORT_FAV
fav_mp3_time = time;
#endif
// 计算文件偏移
if (pmfi->bIsVBR)
{
if (mp3HandleTable[handle]->vbr_toc) // Xing
{
long ratio = mp3HandleTable[handle]->vbr_toc[time * 99 / pmfi->dwDuration];
pos = ratio * pmfi->dwFileLength / 256;
}
else // VBRI
{
float fidx = time / mp3HandleTable[handle]->fFrameDuration / mp3HandleTable[handle]->vbri_toc_frm;
int iidx = (int)fidx;
fidx -= iidx;
if (iidx)
{
if (iidx > mp3HandleTable[handle]->vbri_toc_cnt)
iidx = mp3HandleTable[handle]->vbri_toc_cnt;
iidx--;
pos = mp3HandleTable[handle]->vbri_toc[iidx] + pmfi->dwFrameOffset;
}
else
{
pos = 0;
}
if (iidx mp3HandleTable[handle]->vbri_toc_cnt - 1)
pos += (long)((mp3HandleTable[handle]->vbri_toc[iidx + 1] - mp3HandleTable[handle]->vbri_toc[iidx]) * fidx);
}
}
else
{
pos = (long)((double)time * (double)pmfi->dwFrameSize / (double)mp3HandleTable[handle]->fFrameDuration
+ pmfi->dwFrameOffset);
}
mp3HandleTable[handle]->pos = pos;
return 0;
}
size_t MP3_Read(int handle, void* buf, size_t length)
{
size_t ret;
if (handle >= MAX_AUDIO_FILE)
{
gAudioErrCode = AUDIO_ERR_PARAM;
return 0;
}
if (0 == mp3HandleTable[handle])
{
gAudioErrCode = AUDIO_ERR_PARAM;
return -1;
}
ret = fread(buf, mp3HandleTable[handle]->pos, length, mp3HandleTable[handle]->fp);
mp3HandleTable[handle]->pos += ret;
return ret;
}
size_t MP3_Write(int handle, const void* buf, size_t length)
{
return 0;
}
size_t MP3_ReadBuffer(int handle, void* buf, size_t length)
{
return 0;
}
size_t MP3_WriteBuffer(int handle, const void* buf, size_t length)
{
return 0;
}
int MP3_GetInfo(int handle, MEDIAFILEINFO* pmfi)
{
if (handle >= MAX_AUDIO_FILE)
{
gAudioErrCode = AUDIO_ERR_PARAM;
return -1;
}
if (0 == mp3HandleTable[handle])
{
gAudioErrCode = AUDIO_ERR_PARAM;
return -1;
}
memcpy(pmfi, &mp3HandleTable[handle]->mfi, sizeof(MEDIAFILEINFO));
return 0;
}
int main()
{
int i ;
MP3_Init();
i = MP3_Open("d:\\1.mp3") ;
if (i)
{
printf("mp3 open err!!!\r\n");
}
else
{
printf("===========MP3 Infomation==================\r\n");
printf("Channel , BitRate , SampleRate , Duration \r\n");
printf(" %d , %dKbps , %dHZ , %dMS \r\n" , mp3HandleTable[0]->mfi.bChannels , mp3HandleTable[0]->mfi.dwBitRate , mp3HandleTable[0]->mfi.dwSampleRate , mp3HandleTable[0]->mfi.dwDuration );
printf("=====================================\r\n");
}
return 0 ;
}
/**************************************************************************************/