编码音频pcm为aac(使用faac库)

编码无损音频pcm为aac(使用faac库)

粉丝福利, 免费领取C++音视频学习资料包+学习路线大纲、技术视频/代码,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,编解码,推拉流,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

1.使用faac库

使用faac库编码无损音频pcm为aac时,主要使用以下几个函数:

faacEncHandle faacEncOpen(unsigned long sampleRate,
				  unsigned int numChannels,
				  unsigned long *inputSamples,
                  unsigned long *maxOutputBytes);
 
faacEncConfigurationPtr faacEncGetCurrentConfiguration(faacEncHandle hEncoder);
 
int faacEncSetConfiguration(faacEncHandle hEncoder,
				    faacEncConfigurationPtr config);
 
int faacEncEncode(faacEncHandle hEncoder, 
             int32_t * inputBuffer, 
             unsigned int samplesInput,
			 unsigned char *outputBuffer,
			 unsigned int bufferSize);
 
int faacEncClose(faacEncHandle hEncoder);

我们从上往下进行介绍:

1.1 打开和关闭handle

typedef void *faacEncHandle;
 
/*
 *  @brief  打开一个用于aac编码的handle
 *  @param  sampleRate[in] 音频采样率
 *          numChannels[in] 音频通道数量(一般是1或2,表示单通道和立体声)
 *          inputSamples[out] aac编码器一次需要输入的音频采样
 *          maxOutputBytes[out] 编码后aac数据的最大长度
 *  @return 失败返回NULL
 */
faacEncHandle faacEncOpen(unsigned long sampleRate,
				  unsigned int numChannels,
				  unsigned long *inputSamples,
                  unsigned long *maxOutputBytes);
 
 
//关闭一个用于aac编码的handle
int faacEncClose(faacEncHandle hEncoder);

sampleRate、numChannels是输入参数,需要在打开handle时告诉编码器,等会儿需要编码的pcm音频的采样率和声道(音频通道)是多少。

inputSamples、maxOutputBytes是输出参数,需要传int类型的地址(不能为nullptr),当调用faacEncOpen成功后,返回用于编码的句柄,并且填充inputSamples、maxOutputBytes两个参数,告诉用户等会儿编码时,每次需要输入的音频采样数量,以及编码成aac数据的最大数据长度。用户需要提前分配好至少maxOutputBytes大小的空间用于存储编码后aac音频数据。

1.2 获取、设置编码参数

/* MPEG ID's */
#define MPEG2 1
#define MPEG4 0
 
/* AAC object types */
#define MAIN 1
#define LOW  2
#define SSR  3
#define LTP  4
 
/* Input Formats */
#define FAAC_INPUT_NULL    0
#define FAAC_INPUT_16BIT   1
#define FAAC_INPUT_24BIT   2
#define FAAC_INPUT_32BIT   3
#define FAAC_INPUT_FLOAT   4
 
#pragma pack(push, 1)
typedef struct faacEncConfiguration
{
    /* config version */
    int version;
 
    /* library version */
    char *name;
 
    /* copyright string */
    char *copyright;
 
    /* MPEG version, 2 or 4 */
    /* mpeg的版本号,MPEG2 or MPEG2 */
    unsigned int mpegVersion;
 
    /* AAC object type */
    /* AAC规格 MAIN、LOW、SSR、LTP */
    unsigned int aacObjectType;
 
    union {
        /* Joint coding mode */
        unsigned int jointmode;
        /* compatibility alias */
        unsigned int allowMidside;
    };
 
    /* Use one of the channels as LFE channel */
    /*
     * 低频音效加强通道LFE (low frequency effects)
     * 低频效果通道是一个有限带宽的音轨,用于再现3–120 Hz频率范围内深沉而强烈的低频声音。
     * 此轨道通常会发送到超低音扬声器,即用于重现极低频率的扬声器。
     */
    unsigned int useLfe;
 
    /* Use Temporal Noise Shaping */
    /*
     * 瞬时噪声定形TNS
     * 
     * TNS是用来消除由激发讯号所造成pre-echo现象的一个模组,
     * 它可以控制量化误差并且将误差塑形在遮避能力较大的激发讯号里,进而改进音乐品质。
     * 
     * TNS 是感官式音訊編碼(Perceptual Audio Coding) 中的一個新的觀念,
     * 目的在於使單一區塊在經過時間 -頻率轉換、量化及編碼之後,
     * 音訊在區塊內時間上的噪音遮蔽效果仍然能夠維持。
     */
    unsigned int useTns;
 
    /* bitrate / channel of AAC file */
    /* 每个通道的码率(比特率) */
    unsigned long bitRate;
 
    /* AAC file frequency bandwidth */
    unsigned int bandWidth;
 
    /* Quantizer quality */
    /* 默认100, 值越大音质越好 */
    unsigned long quantqual;
 
    /* Bitstream output format (0 = Raw; 1 = ADTS) */
    /* 是纯AAC音频数据,还是带了ADTS头的AAC(一般使用ADTS)*/
    unsigned int outputFormat;
 
    /* psychoacoustic model list */
    psymodellist_t *psymodellist;
 
    /* selected index in psymodellist */
    unsigned int psymodelidx;
 
    /*
		PCM Sample Input Format
		0	FAAC_INPUT_NULL			invalid, signifies a misconfigured config
		1	FAAC_INPUT_16BIT		native endian 16bit
		2	FAAC_INPUT_24BIT		native endian 24bit in 24 bits		(not implemented)
		3	FAAC_INPUT_32BIT		native endian 24bit in 32 bits		(DEFAULT)
		4	FAAC_INPUT_FLOAT		32bit floating point
    */
    /* 
     * 输入音频的位深度,也叫位宽,量化精度。
     * 位数越多,表示得就越精细,声音质量自然就越好,当然,数据量也会成倍增大。
     * 16bit被认为是专业音频领域里面最低的位深度标准。
     */
    unsigned int inputFormat;
 
    /* block type enforcing (SHORTCTL_NORMAL/SHORTCTL_NOSHORT/SHORTCTL_NOLONG) */
    int shortctl;
	
	/*
		Channel Remapping
		Default			0, 1, 2, 3 ... 63  (64 is MAX_CHANNELS in coder.h)
		WAVE 4.0		2, 0, 1, 3
		WAVE 5.0		2, 0, 1, 3, 4
		WAVE 5.1		2, 0, 1, 4, 5, 3
		AIFF 5.1		2, 0, 3, 1, 4, 5 
	*/
    int channel_map[64];
    int pnslevel;
} faacEncConfiguration, *faacEncConfigurationPtr;
 
/* 
 * 获取编码配置的结构体指针 
 * 在调用设置编码参数之前,需要先调用该函数获取结构体指针,再进行参数填充
 */
faacEncConfigurationPtr faacEncGetCurrentConfiguration(faacEncHandle hEncoder);
 
/* 
 * 设置编码参数
 * 在调用编码函数之前,需要调用该函数设置编码参数
 */
int faacEncSetConfiguration(faacEncHandle hEncoder,
				    faacEncConfigurationPtr config);

其中faacEncConfigurationPtr 是编码参数的结构体指针。经常使用的参数已经在上面的代码中用中文进行了注释,inputFormat、outputFormat、aacObjectType、mpegVersion、(bitRate一般编码器会自动设置成64kpbs,即每个通道的码率为64kpbs)、(useTns、useLfe一般设置为0,即不使用)

1.3编码无损音频pcm为aac

/*
 *  @brief  编码pcm音频为aac音频
 *  @param  hEncoder[in] 调用faacEncOpen函数成功后获取的句柄
 *          inputBuffer[in] pcm音频数据
 *          samplesInput[in] 通过faacEncOpen得到的“每次需要输入的音频采样数量”
 *          outputBuffer[out] 用于存储编码后数据空间的首地址(需要提前分配好空间)
 *          bufferSize[out] 编码后aac数据的最大长度
 *  @return 返回编码后aac实际数据大小
 */
int faacEncEncode(faacEncHandle hEncoder, 
             int32_t * inputBuffer, 
             unsigned int samplesInput,
			 unsigned char *outputBuffer,
			 unsigned int bufferSize);

samplesInput是指音频采样数量,而非pcm音频数据的大小!是通过调用faacEncOpen后得到的。输入的pcm音频数据的大小 = samplesInput * 音频位深 / 8;

outputBuffer是提前分配好的空间,存储编码后的aac数据,至少需要分配的大小 = 通过调用faacEncOpen后得到的maxOutputBytes。

2.总结

1. 调用faacEncOpen打开一个用于编码pcm为aac的句柄,需要传入采样率、声道数。成功返回编码句柄,并且得到每次需要输入的采样数量inputSamples,和编码后aac数据的最大数据大小maxOutputBytes。

2. 通过得到的maxOutputBytes分配空间,用于之后存储aac数据。

3. 调用faacEncGetCurrentConfiguration获取编码参数的结构体指针,并填充编码参数,主要填充inputFormat、outputFormat、aacObjectType、mpegVersion等参数;useTns、useLfe通常不使用,设置为0; bitRate是每个声道的码率,而非总码率,一般会自动填充好,也可以手动赋值。

4. 调用faacEncSetConfiguration设置编码参数。

5. 调用faacEncEncode进行音频编码,并把编码后的数据保存下来。(正常情况下前面几帧会返回0,即没有aac数据,属于正常现象)。

6. 编码结束后,调用faacEncClose关闭句柄。

3.代码展示

PcmToAac.cpp

#include <cstdio>
#include <string>
#include <cstring>
#include "PcmToAac.h"
 
PcmToAac::PcmToAac(uint32_t maxPcmSize, uint32_t maxAacQueueSize)
        : hEncoder(nullptr)
        , pConfiguration(nullptr)
        , m_AacBuffer(nullptr)
        , m_nInputSamples(0)
        , m_nMaxOutputBytes(0)
        , m_nMaxInputBytes(0)
        , m_nPCMBitSize(0)
        , m_PcmMaxSize(maxPcmSize)
        , m_AacMaxQueueSize(maxAacQueueSize)
{
 
}
 
 
PcmToAac::~PcmToAac()
{
    //关闭句柄
    if (nullptr != hEncoder) {
        faacEncClose(hEncoder);
    }
 
    //释放内存
    delete []m_AacBuffer;
}
 
int PcmToAac::Init(uint8_t Channel, uint32_t SampleRate, uint32_t BitSize)
{
    m_nPCMBitSize = BitSize;
    //打开句柄
    hEncoder = faacEncOpen(SampleRate, Channel, &m_nInputSamples, &m_nMaxOutputBytes);
    if (hEncoder == nullptr) {
        fprintf(stderr, "faac enc open failed\n");
        return -1;
    }
    //计算每次输入pcm数据大小
    m_nMaxInputBytes = m_nInputSamples * m_nPCMBitSize / 8;
 
    //分配空间用于存储aac数据
    m_AacBuffer = new unsigned char[m_nMaxOutputBytes];
 
    //获取结构体指针用于填充编码参数
    pConfiguration = faacEncGetCurrentConfiguration(hEncoder);
    pConfiguration->inputFormat = FAAC_INPUT_16BIT; //位深16
    pConfiguration->outputFormat = 1;   //ADTS
    pConfiguration->useTns = 0;
    pConfiguration->useLfe = 0;
    pConfiguration->aacObjectType = LOW;    //AAC-LC
    pConfiguration->mpegVersion = MPEG2;
 
    //设置编码参数
    faacEncSetConfiguration(hEncoder, pConfiguration);
 
    return 0;
}
 
int PcmToAac::InputPcmData(const uint8_t* pcmData, uint32_t dataSize) {
    if (dataSize + m_PcmStr.size() > m_PcmMaxSize) {
        fprintf(stderr, "Input pcm data is too large\n");
        return -1;
    }
    m_PcmStr.append((const char*)pcmData, dataSize);
 
    if (m_AacQueue.size() > m_AacMaxQueueSize) {
        fprintf(stderr, "Aac queue is full\n");
        return -1;  //aac队列已满
    }
 
    int ret = 0;
    while(m_PcmStr.size() >= m_nMaxInputBytes) {
        memset(m_AacBuffer, 0, m_nMaxOutputBytes);
        ret = faacEncEncode(hEncoder, (int32_t*)m_PcmStr.data(), m_nInputSamples, m_AacBuffer, m_nMaxOutputBytes);
        if (ret > 0) {
            m_AacQueue.emplace((const char*)m_AacBuffer, ret);
        }
        m_PcmStr.erase(0, m_nMaxInputBytes);
    }
 
    return 0;
}
 
 
std::string PcmToAac::GetAacFrame() {
    if (m_AacQueue.empty()) {
        return "";
    }
    std::string aac = m_AacQueue.front();
    m_AacQueue.pop();
    return aac;
}

PcmToAac.h

#ifndef _PCM_TO_AAC_H
#define _PCM_TO_AAC_H
 
#include <queue>
extern "C"
{
#include <faac.h>
}
 
class PcmToAac
{
public:
    explicit PcmToAac(uint32_t maxPcmSize = 1024 * 1024, uint32_t maxAacQueueSize = 1024);
    ~PcmToAac();
 
    int InputPcmData(const uint8_t* pcmData, uint32_t dataSize);
    std::string GetAacFrame();
    int Init(uint8_t Channel, uint32_t SampleRate, uint32_t BitSize);
 
private:
    faacEncHandle hEncoder;
    faacEncConfigurationPtr pConfiguration;
    uint32_t m_nPCMBitSize /*= 16*/;
    unsigned long m_nInputSamples /*= 0*/;
    unsigned long m_nMaxOutputBytes /*= 0*/;
    unsigned long m_nMaxInputBytes /*= 0*/;
 
    const uint32_t m_PcmMaxSize;         //内存中能存储的最大pcm
    const uint32_t m_AacMaxQueueSize;    //aac队列最大数量
    std::string m_PcmStr;
    std::queue<std::string> m_AacQueue;
    unsigned char* m_AacBuffer;
};
 
#endif

main.cpp

#include <memory>
#include <cstring>
#include "PcmToAac.h"
 
int main() {
    //打开2个文件,我们目标是读取pcm文件并编码,最后保存为aac文件
    FILE *fpIn = fopen("D:\\music.pcm", "rb");
    if (!fpIn) {
        return -1;
    }
    FILE *fpOut = fopen("D:\\music.aac", "wb");
    if (!fpOut) {
        return -1;
    }
 
    //构造类对象PcmToAac并初始化, 最大编码大小 和 缓存中的aac队列大小 可以自己定义
    std::shared_ptr<PcmToAac> pcmToAacPtr = std::make_shared<PcmToAac>();
    //输入pcm音频:采样率44100, 立体声, 位深16
    if(pcmToAacPtr->Init(2, 44100, 16)) {
        return -1;
    }
 
    char buf[1024] = {0};
    for(; ;) {
        memset(buf, 0, sizeof(buf));
        int ret = fread(buf, 1, sizeof(buf), fpIn);
        if (ret <= 0) {
            break;
        }
 
        pcmToAacPtr->InputPcmData((const uint8_t *)buf, ret);
 
        //循环从缓存中输出aac数据并保存为文件
        std::string aacFrame;
        for( ; ; ) {
            aacFrame = pcmToAacPtr->GetAacFrame();
            if (aacFrame.empty()) {
                break;
            }
 
            fwrite(aacFrame.data(), 1, aacFrame.size(), fpOut);
        }
    }
    return 0;
}

4.代码下载

1. 功能:使用faac库编码pcm音频为aac,输入文件和输出文件在main函数中修改文件名即可。

2. 支持vs2017 & linux环境下gcc、g++编译(linuxx使用的gcc版本为4.8.5,系统为centos7.8)

3. faac库使用的1_30版本,源码放在depend目录下,打开depends\faac\project\msvc\faac.sln可直接使用vs2017编译库。

4. lib目录包含了vs2017编译的库以及linux环境下(4.8.5gcc)编译的静态库、动态库。

粉丝福利, 免费领取C++音视频学习资料包+学习路线大纲、技术视频/代码,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,编解码,推拉流,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java是一种广泛应用于软件开发中的编程语言,而FAAC是一款常用的开源编码器,可以将PCM(脉冲编码调制)格式的音频转换成AAC(高级音频编码)格式。下面是一种使用Java和FAAC进行PCMAAC的简单示例。 首先,需要在Java项目中引入FAAC的依赖。可以通过Maven等构建工具来添加FAAC的依赖项。然后,在Java代码中调用FAAC提供的方法来实现PCMAAC的功能。 ```java import com.googlecode.mp4parser.authoring.Sample; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.ShortBuffer; import java.util.ArrayList; public class PCM2AACConverter { // PCMAAC的方法 public static void pcmToAac(String inputPath, String outputPath) { try { FileInputStream fis = new FileInputStream(inputPath); FileOutputStream fos = new FileOutputStream(outputPath); int channels = 2; // 音频通道数 int sampleRate = 44100; // 采样率 int bitRate = 128000; // 码率 // 创建FAAC编码器 com.googlecode.mp4parser.authoring.Sample sample = new com.googlecode.mp4parser.authoring.Sample(); sample.begin(channels, sampleRate, bitRate); byte[] data = new byte[1024]; int bytesRead = 0; while ((bytesRead = fis.read(data)) > 0) { // 将PCM数据转换成short类型的数组 ShortBuffer shortBuffer = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer(); short[] pcmData = new short[shortBuffer.remaining()]; shortBuffer.get(pcmData); // 将PCM数据添加到FAAC编码器 sample.add(pcmData); } // 完成PCM数据添加操作 sample.end(); // 获取AAC编码后的数据 ArrayList<byte[]> aacData = sample.getAACData(); // 将AAC数据写入输出文件 for (byte[] aacFrame : aacData) { fos.write(aacFrame); } fis.close(); fos.close(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { String inputPath = "input.pcm"; // 输入PCM文件的路径 String outputPath = "output.aac"; // 输出AAC文件的路径 pcmToAac(inputPath, outputPath); } } ``` 上述代码使用了FAAC提供的`Sample`类来进行PCMAAC操作。通过`pcmToAac`方法,将输入的PCM文件转换成AAC格式并输出到指定路径。在此过程中,需要指定音频的通道数、采样率和码率等参数。 要使用上述方法,首先需要确保Java项目已经引入FAAC的依赖,同时将输入的PCM文件和输出的AAC文件放置在正确的路径下。 以上是一个简单的示例,仅供参考。实际应用中,可能需要根据具体需求对代码进行修改和优化。 ### 回答2: Java FAAC PCMAAC可以通过使用FAAC和Java编程语言来实现。以下是一个简单的示例代码来演示如何使用Java FAACPCM音频文件转换为AAC格式: ```java import com.googlecode.faac.Faac; import com.googlecode.faac.FaacConfig; import com.googlecode.faac.FaacConfigParams; import com.googlecode.faac.FaacInstance; public class PCMtoAACConverter { public static void main(String[] args) { String pcmFile = "input.pcm"; String aacFile = "output.aac"; // 初始化FAAC Faac faac = Faac.getInstance(); // 创建FAAC实例 FaacInstance faacInstance = faac.faacEncOpenDefault(48000, 2); // 设置FAAC配置参数 FaacConfig faacConfig = faac.faacEncGetCurrentConfiguration(faacInstance); FaacConfigParams configParams = new FaacConfigParams(); configParams.setBitrate(128000); configParams.setInputFormat(Faac.FAAC_INPUT_FORMAT_16BIT); faacConfig.setParams(configParams); faac.faacEncSetConfiguration(faacInstance, faacConfig); // 打开PCM文件和AAC文件 faac.faacEncOpenFile(faacInstance, pcmFile, aacFile); // 开始转换 faac.faacEncEncode(faacInstance); // 关闭文件和FAAC实例 faac.faacEncClose(faacInstance); faac.faacEncCloseFile(faacInstance); System.out.println("PCMAAC完成!"); } } ``` 上述代码示例使用了FAAC提供的相关函数来实现PCM文件转换为AAC文件的功能。其中,需先准备好待转换的PCM音频文件和指定的输出AAC文件路径。代码中的配置参数可根据需求进行调整,例如比特率、通道数等。 需要注意的是,使用FAAC需要先下载并导入合适的FAAC文件到项目中,并进行相关的配置。此外,FAAC是一个开源的第三方使用时需了解其许可证限制和相关文档。 ### 回答3: 要使用Java将PCM音频文件转换为AAC格式,可以使用FAAC。FAAC是一个用于将音频文件编码AAC格式的开源。 首先,需要确保已经下载并安装了FAAC。然后,可以在Java项目中使用JNI(Java Native Interface)来调用FAAC的功能。 在Java中使用JNI调用FAAC时,可以使用JNIWrapper。这个提供了一种方便的方式来与C/C++代码进行交互。 首先,需要编写一个调用FAAC的Java类。在这个类中,可以使用JNIWrapper提供的函数来加载FAAC和调用它的函数。可以编写一个Java方法来将PCM文件转换为AAC文件。 示例代码如下: ```java import com.jniwrapper.*; import com.jniwrapper.win32.jni.*; import com.jniwrapper.util.*; public class FaacConverter { private static final String LIBRARY_NAME = "your_FAAC_library_name"; static { NativeLibraryLoader.loadLibrary(LIBRARY_NAME); } public static native int convertPcmToAac(String pcmFilePath, String aacFilePath); public static void main(String[] args) { String pcmFilePath = "/path/to/pcm/file.pcm"; String aacFilePath = "/path/to/aac/file.aac"; int result = convertPcmToAac(pcmFilePath, aacFilePath); if (result == 0) { System.out.println("PCM file converted to AAC successfully."); } else { System.out.println("Failed to convert PCM file to AAC."); } } } ``` 要使用这个示例代码,需要将FAAC文件与Java项目一起编译,并将LIBRARY_NAME变量设置为FAAC的名称。 编写完Java类后,可以使用Java编译器将其编译为可执行的Java程序。 然后,可以通过运行这个程序来将PCM文件转换为AAC文件。在main方法中,可以设置PCM文件的路径和要生成的AAC文件的路径。 运行这个程序后,如果转换成功,将会在控制台打印出"PCM file converted to AAC successfully."的消息,否则将会打印出"Failed to convert PCM file to AAC."的消息。 这就是使用Java将PCM音频文件转换为AAC格式的基本步骤。希望对你有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值