tinymp3解码

引言

在实际应用中由于受传输带宽等外界因素的影响,数据在传输过程中往往会被拆分成多组数据进行发送,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,分别采取不同长度的输入进行解码,解码结果均一致。

猜你喜欢

转载自blog.csdn.net/liang_zhaocong/article/details/129463358