libmad音频解码库的使用

封装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;
  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值