封装libmad音频解码库,支持MPEG-1(Layer Ⅰ,Layer Ⅱ和Layer Ⅲ)解码。
文章目录
一、libmad是什么?
libmad是一个开源的高精度MPEG音频解码库,支持MPEG-1标准,提供24-bit的PCM输出,彻底定点计算。使用libmad的API能够实现音频的解码。
二、下载和编译
首先下载libmad库,下载地址是:https://downloads.sourceforge.net/mad/libmad-0.15.1b.tar.gz,或者直接点击下载,解压压缩包,如下:
打开msvc++文件夹,用Visual Studio打开工程,编译出libmad.lib:
之后就可以使用libmad库了。以下是对该库的一个封装类:
// LibMPEGDec.h
// 封装libmad音频解码库,支持MPEG-1(Layer Ⅰ,Layer Ⅱ和Layer Ⅲ)解码
//#pragma once
#ifndef _LIB_MPEG_DECODE_H_
#define _LIB_MPEG_DECODE_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "mad.h"
#ifdef __cplusplus
}
#endif
typedef struct _mpeg_audio_decoder_t {
mad_stream stream;
mad_frame frame;
mad_synth synth;
} mpeg_audio_decoder_t;
typedef struct _mpeg_audio_header_t {
unsigned int sync; // 同步信息
unsigned int version; // 版本 0:MPEG V2.5, 1:reserved, 2:MPEG_V2, 3:MPEG_V1
unsigned int layer; // 层 1:reserved, 1:layer3, 2:layer2, 3:layer1
unsigned int error_protection; // CRC校验
/*
* bits V1,L1 V1,L2 V1,L3 V2,L1 V2,L2&L3
* 0000 free free free free free
* 0001 32 32 32 32 32
* 0010 64 48 40 48 16
* 0011 96 56 48 57 24
* 0100 128 64 56 64 32
* 0101 160 80 64 80 40
* 0110 192 96 80 96 48
* 0111 224 112 96 112 56
* 1000 256 128 112 128 64
* 1001 288 160 128 144 80
* 1010 320 192 160 160 96
* 1011 352 224 192 176 112
* 1100 384 256 224 192 128
* 1101 416 320 256 224 144
* 1110 448 384 320 256 160
* 1111 bad bad bad bad
*/
unsigned int bitrate_index; // 位率
/*
* 采样频率
* bits MPEG1 MPEG2 MPEG2.5
* 00 44100 22050 11025
* 01 48000 24000 12000
* 10 32000 16000 8000
* 11 reserved
*/
unsigned int sampling_frequency; // 采样频率
unsigned int padding; // 帧长调节
unsigned int pri; // 保留字
unsigned int mode; // 声道模式
unsigned int mode_extension; // 扩充模式
unsigned int copyright; // 版权
unsigned int original; // 原版标志
unsigned int emphasis; // 强调模式
} mpeg_audio_header_t;
class MPEG2PCM {
public:
MPEG2PCM();
virtual ~MPEG2PCM();
int Decode(unsigned char* pData, unsigned int dataLen,
unsigned char* pPcmData, unsigned int pcmDataMaxLen,
unsigned int* pPcmDataOutLen);
int PraseHeader(unsigned char* pData, unsigned int dataLen, mpeg_audio_header_t* pHeader);
int GetSampleRate(mpeg_audio_header_t* pHeader, int* pSampleRate);
private:
// 初始化
int Init();
// 反初始化
int Uninit();
int Scale(mad_fixed_t sample);
public:
unsigned int m_samplerate;
private:
mpeg_audio_decoder_t *m_pDecoder;
};
#endif //_LIB_MPEG_DECODE_H_
// LibMPEGDec.cpp
#include <stdio.h>
#include "LibMPEGDec.h"
#ifdef _DEBUG
#pragma comment(lib, "../ThirdParty/libmad/lib/libmadd.lib")
#else
#pragma comment(lib, "../ThirdParty/libmad/lib/libmad.lib")
#endif
MPEG2PCM::MPEG2PCM() {
m_pDecoder = nullptr;
m_samplerate = 0;
Init();
}
MPEG2PCM::~MPEG2PCM() {
Uninit();
}
int MPEG2PCM::Init() {
m_pDecoder = new mpeg_audio_decoder_t;
mad_stream_init(&m_pDecoder->stream);
mad_frame_init(&m_pDecoder->frame);
mad_synth_init(&m_pDecoder->synth);
return 0;
}
int MPEG2PCM::Uninit() {
if (m_pDecoder != nullptr) {
mad_synth_finish(&m_pDecoder->synth);
mad_frame_finish(&m_pDecoder->frame);
mad_stream_finish(&m_pDecoder->stream);
delete m_pDecoder;
m_pDecoder = nullptr;
}
return 0;
}
int MPEG2PCM::Decode(unsigned char *pData, unsigned int dataLen,
unsigned char *pPcmData, unsigned int pcmDataMaxLen,
unsigned int *pPcmDataOutLen) {
mad_stream *pStream;
mad_frame *pFrame;
mad_synth *pSynth;
mad_pcm *pDecPcmData = nullptr;
unsigned int nChannels, nSamples, nSamplerate;
mad_fixed_t const *left_ch, *right_ch;
int offset = 0;
*pPcmDataOutLen = 0;
if (m_pDecoder == nullptr || pData == nullptr || pPcmData == nullptr) {
return -1;
}
pStream = &m_pDecoder->stream;
pFrame = &m_pDecoder->frame;
pSynth = &m_pDecoder->synth;
mad_stream_buffer(pStream, pData, dataLen);
if (mad_header_decode(&pFrame->header, pStream) == -1) {
return -1;
}
if (mad_frame_decode(pFrame, pStream) == -1) {
return -1;
}
mad_synth_frame(pSynth, pFrame);
pDecPcmData = &pSynth->pcm;
nChannels = pDecPcmData->channels;
nSamplerate = pDecPcmData->samplerate;
nSamples = pDecPcmData->length;
left_ch = pDecPcmData->samples[0];
right_ch = pDecPcmData->samples[1];
printf("nChannels %d, nSamplerate %d, nSamples %d, options %d\n", nChannels, nSamplerate, nSamples, pFrame->options);
m_samplerate = nSamplerate;
if (pcmDataMaxLen > nSamples * 2 * nChannels) {
while (nSamples--) {
int sample;
// output sample(s) in 16-bit signed little-endian PCM
// channel 1
sample = Scale(*left_ch++);
pPcmData[offset++] = (sample >> 0) & 0xff;
pPcmData[offset++] = (sample >> 8) & 0xff;
//channel 2
if (nChannels == 2) {
sample = Scale(*right_ch++);
pPcmData[offset++] = (sample >> 0) & 0xff;
pPcmData[offset++] = (sample >> 8) & 0xff;
}
*pPcmDataOutLen = offset;
}
} else {
printf("error %d pcmDataMaxLen %d, need %d\n", pcmDataMaxLen, nSamples * 2 * nChannels);
}
return 0;
}
int MPEG2PCM::PraseHeader(unsigned char *pData, unsigned int dataLen, mpeg_audio_header_t *pHeader) {
char *buff = (char*)pData;
if (buff[0] != 0xff) {
printf("input header data error!\n");
return -1;
}
pHeader->sync = (buff[0] << 3) + ((buff[1] & 0xe0) >> 5);
pHeader->version = (buff[1] & 0x18) >> 3;
pHeader->layer = (buff[1] & 0x06) >> 1;
pHeader->error_protection = (buff[1] & 0x01) >> 0;
pHeader->bitrate_index = (buff[2] & 0xf0) >> 4;
pHeader->sampling_frequency = (buff[2] & 0x0c) >> 2;
pHeader->padding = (buff[2] & 0x02) >> 1;
pHeader->pri = (buff[2] & 0x01) >> 0;
pHeader->mode = (buff[3] & 0xc0) >> 6;
pHeader->mode_extension = (buff[3] & 0x30) >> 4;
pHeader->copyright = (buff[3] & 0x08) >> 3;
pHeader->original = (buff[3] & 0x04) >> 2;
pHeader->emphasis = (buff[3] & 0x03) >> 0;
return 0;
}
int MPEG2PCM::GetSampleRate(mpeg_audio_header_t *pHeader, int *pSampleRate) {
int version, layer, sampling_frequency_index, sample_rate = 0;
if (pHeader == nullptr) {
printf("input header data error!\n");
return -1;
}
version = pHeader->version;
layer = pHeader->layer;
sampling_frequency_index = pHeader->sampling_frequency;
switch (sampling_frequency_index) {
case 0:
switch (version) {
case 0: // MPEG V2.5
sample_rate = 11025;
break;
case 2: // MPEG_V2
sample_rate = 22050;
break;
case 3: // MPEG_V1
sample_rate = 44100;
break;
default:
break;
} break;
case 1:
switch (version) {
case 0: // MPEG V2.5
sample_rate = 12000;
break;
case 2: // MPEG_V2
sample_rate = 24000;
break;
case 3: // MPEG_V1
sample_rate = 48000;
break;
default:
break;
} break;
case 2:
switch (version) {
case 0: // MPEG V2.5
sample_rate = 8000;
break;
case 2: // MPEG_V2
sample_rate = 16000;
break;
case 3: // MPEG_V1
sample_rate = 32000;
break;
default:
break;
} break;
default:
break;
}
*pSampleRate = sample_rate;
return 0;
}
int MPEG2PCM::Scale(mad_fixed_t sample) {
// round
sample += (1L << (MAD_F_FRACBITS - 16));
// clip
if (sample >= MAD_F_ONE)
sample = MAD_F_ONE - 1;
else if (sample < -MAD_F_ONE)
sample = -MAD_F_ONE;
// quantize
return sample >> (MAD_F_FRACBITS + 1 - 16);
}
使用例子(伪代码):
// 初始化
MPEG2PCM* pMpegDec = new MPEG2PCM();
// 解码数据
unsigned int outSize = 0;
unsigned char tempData[8192] = {0};
memcpy(tempData, inputBuffer, inSize);
pMpegDec->Decode(tempData, 8192, outputBuffer, outputMaxLen, &outSize);
// 释放
delete pMpegDec;
pMpegDec= nullptr;