引言
在实际应用中由于受传输带宽等外界因素的影响,数据在传输过程中往往会被拆分成多组数据进行发送,MP3数据可能会被拆分传输,理想情况下,用户希望是按MP3数据帧的整数倍进行传输的,但往往并不能如愿以偿。MP3数据是以帧作为一个解码单元,所以需对实际数据进行解析拆解拼接成完整的数据帧进行解码。
流程图
代码实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DR_MP3_IMPLEMENTATION
#include "dr_mp3.h"
#define MP3_BUF_LEN (72)
#define PCM_BUF_LEN (1152)
static FILE *fout = NULL;
static drmp3dec *dec = NULL;
static drmp3dec_frame_info *info = NULL;
int CheckMp3Header(const char *mp3Buf, const int len)
{
// static char header[] = {0xFF, 0xE3, 0x28, 0xC0};
static char header[] = {
0xFF, 0xE3, 0x18, 0xC4};
int headerLen = sizeof(header);
int index = 0;
while (index < len)
{
if (memcmp((mp3Buf+index), header, headerLen)) {
index++;
}
else
break;
}
printf("(%s %s LINE-%d)index: %d\n", __FILE__, __FUNCTION__, __LINE__, index);
if (index > len)
return -1;
else
return index;
}
void HandleMp3Data(const char *buf, const int len, void (*pFuncMp3Decode)(const char *mp3Data, const int len))
{
static int restLen;
static char restBuf[MP3_BUF_LEN];
char mp3Buf[MP3_BUF_LEN] = {
0x00};
int handleLen = len;
int i = 0;
if (restLen + len > MP3_BUF_LEN) {
while (i < len) {
if (restLen == 0) {
memcpy(mp3Buf, buf+i, MP3_BUF_LEN);
i += MP3_BUF_LEN;
handleLen -= MP3_BUF_LEN;
}
else {
memcpy(mp3Buf, restBuf, restLen);
memcpy(&(mp3Buf[restLen]), buf, MP3_BUF_LEN-restLen);
handleLen -= (MP3_BUF_LEN-restLen);
i += (MP3_BUF_LEN-restLen);
restLen = 0;
}
int index = CheckMp3Header(mp3Buf, MP3_BUF_LEN);
if (index == 0) {
// decode
pFuncMp3Decode(mp3Buf, MP3_BUF_LEN);
}
else if (index == -1) {
// throw away
memset(mp3Buf, 0x00, MP3_BUF_LEN);
}
else {
restLen = MP3_BUF_LEN-index;
memcpy(restBuf, mp3Buf+index, restLen);
continue;
}
if (handleLen < MP3_BUF_LEN && i < len) {
memcpy(restBuf, buf+i, handleLen);
restLen = handleLen;
break;
}
memset(mp3Buf, 0x00, MP3_BUF_LEN);
}
}
else {
memcpy(&(restBuf[restLen]), buf, len);
restLen += len;
}
}
void DecodeMp3Data(const char *mp3Data, const int mp3Len)
{
char pcmBuf[PCM_BUF_LEN] = {
0x00};
int decLen = drmp3dec_decode_frame(dec, (drmp3_uint8 *)mp3Data, mp3Len, pcmBuf, info);
if (decLen > 0) {
// printf("frame_bytes(%d), channels(%d), hz(%d), layer(%d), bitrate_kbps(%d)\n", info->frame_bytes, info->channels, info->hz, info->layer, info->bitrate_kbps);
fwrite(pcmBuf, 1, decLen << 1, fout);
}
}
int main(int argc, char *argv[])
{
FILE *fin = fopen(argv[1], "r");
fout = fopen(argv[2], "wb+");
int inLen = atoi(argv[3]);
info = (drmp3dec_frame_info *)calloc(sizeof(drmp3dec_frame_info), 1);
dec = (drmp3dec *)calloc(sizeof(drmp3dec), 1);
char *mp3Buf = (char *)calloc(1, inLen);
fseek(fin, 50, 0);
while (1)
{
int mp3Len = fread(mp3Buf, 1, inLen, fin);
HandleMp3Data(mp3Buf, mp3Len, DecodeMp3Data);
if (feof(fin))
break;
}
free(info);
free(dec);
free(mp3Buf);
fclose(fin);
fclose(fout);
return 0;
}
以开源库tinymp3作为解码库进行实现。
测试结果
该MP3帧长为72,分别采取不同长度的输入进行解码,解码结果均一致。