Windows编译及使用fdk-aac编码器

  1. 源码获取
  2. git clone https://github.com/mstorsjo/fdk-aac.git
  3. cd fdk-aac
  4. git checkout v2.0.3 #选择稳定版本
  5. 编译
  6. 源码路径:D:\fdk-aac
  7. 编译路径:D:\fdk-aac\build
  8. 打开cmake分别选择源码路径和编译路径,点击Configure和Generate,执行成功之后打开fdk-aac.sln用vs2017编译即可,编译完之后运行install(管理员运行)
  9. pcm编码aac 示例
  10. 代码实现

#include <fdk-aac/aacenc_lib.h>

#include

typedef void(AacFrameCallback)(uint8_t aac_data, size_t aac_size, void* user_data);

class AACEncoder {

public:

AACEncoder() = default;

~AACEncoder();

复制代码
    // 初始化AAC编码器
int init(int sample_rate, int channels, int audio_bitrate);

    // 接收PCM数据流并进行编码
    void receivePcmStream(const uint8_t* data, size_t size);

    // 清理资源
    void cleanup();

    // aac音频数据回调
    void setCallback(AacFrameCallback callback, void* user_data = nullptr);

private:

HANDLE_AACENCODER encoder_ = nullptr; // 编码器句柄

int frame_samples_ = 0; // 每帧需要的样本数(单声道)

short pcm_buffer_ = nullptr; // PCM 缓冲区(存储累积的样本)
size_t buffer_size_ = 0; // 缓冲区当前存储的样本数(总样本 = buffer_size * 声道数)
int channels_ = 2; // 默认PCM声道数为2(立体声)
AacFrameCallback callback_;
void
user_data_;

};

复制代码
实现

#include "AACEncoder.h"

#include <stdio.h>

AACEncoder::~AACEncoder()

{

cleanup();

}

int AACEncoder::init(int sample_rate, int channels, int audio_bitrate)

{

AACENC_ERROR err;

复制代码
// 初始化AAC编码器
if ((err = aacEncOpen(&encoder_, 0, channels)) != AACENC_OK)
{
    fprintf(stderr, "aacEncOpen failed, error code: %d\n", err);
    return -1;
}

// 设置编码参数
if ((err = aacEncoder_SetParam(encoder_, AACENC_AOT, AOT_AAC_LC)) != AACENC_OK
    || (err = aacEncoder_SetParam(encoder_, AACENC_SAMPLERATE, sample_rate)) != AACENC_OK
    || (err = aacEncoder_SetParam(encoder_, AACENC_CHANNELMODE, channels == 1 ? MODE_1 : MODE_2)) != AACENC_OK
    || (err = aacEncoder_SetParam(encoder_, AACENC_CHANNELORDER, 1)) != AACENC_OK ||  // WAV通道顺序
    (err = aacEncoder_SetParam(encoder_, AACENC_BITRATE, audio_bitrate)) != AACENC_OK)
{
    fprintf(stderr, "Parameter setting failed, error code: %d\n", err);
    aacEncClose(&encoder_);
    return -1;
}

// 初始化编码器
if ((err = aacEncEncode(encoder_, nullptr, nullptr, nullptr, nullptr)) != AACENC_OK)
{
    fprintf(stderr, "Encoder initialization failed, error code: %d\n", err);
    aacEncClose(&encoder_);
    return -1;
}

// 获取编码器信息
AACENC_InfoStruct info = {0};
if ((err = aacEncInfo(encoder_, &info)) != AACENC_OK)
{
    fprintf(stderr, "Failed to get encoder info, error code: %d\n", err);
    aacEncClose(&encoder_);
    return -1;
}

frame_samples_ = info.frameLength;
channels_      = channels;

// 分配PCM缓冲区
pcm_buffer_ = (short *)malloc(frame_samples_ * channels * 2 * sizeof(short));
if (!pcm_buffer_)
{
    fprintf(stderr, "PCM buffer allocation failed\n");
    aacEncClose(&encoder_);
    return -1;
}

return 0;

}

void AACEncoder::setCallback(AacFrameCallback callback, void *user_data)

{

callback_ = callback;

user_data_ = user_data;

}

void AACEncoder::receivePcmStream(const uint8_t *data, size_t size)

{

if (!encoder_)

{

fprintf(stderr, "Encoder not initialized\n");

return;

}

复制代码
// 将输入的uint8_t数据转换为short数组(假设小端格式)
size_t num_samples = size / sizeof(short);
short *new_samples = (short *)data;

// 将新数据追加到缓冲区
memcpy(pcm_buffer_ + buffer_size_, new_samples, size);
buffer_size_ += num_samples;

// 计算每帧所需的总样本数(单通道样本数 * 通道数)
const size_t samples_per_frame = frame_samples_ * channels_;

// 如果有足够的数据进行编码
while (buffer_size_ >= samples_per_frame)
{
    AACENC_BufDesc in_buf = {0}, out_buf = {0};
    AACENC_InArgs  in_args  = {0};
    AACENC_OutArgs out_args = {0};
    unsigned char  temp_aac_buffer[20480];  // 临时AAC输出缓冲区

    int in  = 2;
    int out = 1;

    // 输入设置
    void *in_ptr[]           = {pcm_buffer_};
    int   in_size[]          = {(int)(samples_per_frame * sizeof(short))};
    int   in_ident[]         = {IN_AUDIO_DATA};
    in_args.numInSamples     = frame_samples_ * channels_;  // 总样本数
    in_buf.numBufs           = 1;
    in_buf.bufs              = in_ptr;
    in_buf.bufferIdentifiers = in_ident;
    in_buf.bufSizes          = in_size;
    in_buf.bufElSizes        = &in;

    // 输出设置
    void *out_ptr[]           = {temp_aac_buffer};
    int   out_size[]          = {sizeof(temp_aac_buffer)};
    int   out_ident[]         = {OUT_BITSTREAM_DATA};
    out_buf.numBufs           = 1;
    out_buf.bufs              = out_ptr;
    out_buf.bufferIdentifiers = out_ident;
    out_buf.bufSizes          = out_size;
    out_buf.bufElSizes        = &out;

    // 执行编码
    AACENC_ERROR err;
    if ((err = aacEncEncode(encoder_, &in_buf, &out_buf, &in_args, &out_args)) != AACENC_OK)
    {
        fprintf(stderr, "Encoding failed, error code: %d\n", err);
        break;
    }

    // 如果有有效的AAC数据,调用回调函数
    if (out_args.numOutBytes > 0 && callback_)
    {
        callback_(temp_aac_buffer, out_args.numOutBytes, user_data_);
    }

    // 将剩余的数据移到缓冲区头部
    buffer_size_ -= samples_per_frame;
    if (buffer_size_ > 0)
    {
        memmove(pcm_buffer_, pcm_buffer_ + samples_per_frame, buffer_size_ * sizeof(short));
    }
}

}

void AACEncoder::cleanup()

{

if (encoder_)

{

AACENC_BufDesc in_buf = {0}, out_buf = {0};

AACENC_InArgs in_args = {0};

AACENC_OutArgs out_args = {0};

unsigned char aac_buffer[20480];

in_args.numInSamples = -1;

复制代码
    void *out_ptr[]           = {aac_buffer};
    int   out_size[]          = {sizeof(aac_buffer)};
    int   out_ident[]         = {OUT_BITSTREAM_DATA};
    out_buf.numBufs           = 1;
    out_buf.bufs              = out_ptr;
    out_buf.bufferIdentifiers = out_ident;
    out_buf.bufSizes          = out_size;

    // 处理剩余的编码数据
    while (aacEncEncode(encoder_, &in_buf, &out_buf, &in_args, &out_args) == AACENC_OK)
    {
        // 如果有有效的AAC数据,调用回调函数
        if (out_args.numOutBytes > 0 && callback_)
        {
            callback_(aac_buffer, out_args.numOutBytes, user_data_);
        }
    }

    aacEncClose(&encoder_);
    free(pcm_buffer_);
    encoder_ = nullptr;
}

}

相关推荐
吳所畏惧3 小时前
NVM踩坑实录:配置了npm的阿里云cdn之后,下载nodejs老版本(如:12.18.4)时,报404异常,下载失败的问题解决
前端·windows·阿里云·npm·node.js·batch命令
leese2333 小时前
FreeMarker模板引擎
windows
love530love4 小时前
命令行创建 UV 环境及本地化实战演示—— 基于《Python 多版本与开发环境治理架构设计》的最佳实践
开发语言·人工智能·windows·python·conda·uv
呉師傅4 小时前
佳能iR-ADV C5560复印机如何扫描文件到电脑
运维·网络·windows·计算机外设·电脑
程序视点4 小时前
【最新专业评测】PDF Reducer专业版:85%超高压缩率的PDF压缩神器|Windows最佳PDF压缩工具推荐
windows
qyhua8 小时前
Windows 平台源码部署 Dify教程(不依赖 Docker)
人工智能·windows·python
女程序猿!!!9 小时前
网址收集总结
windows
love530love12 小时前
Windows 如何更改 ModelScope 的模型下载缓存位置?
运维·人工智能·windows·python·缓存·modelscope
weixin_3077791318 小时前
Windows 11下纯软件模拟虚拟机的设备模拟与虚拟化(仅终端和网络)
windows·系统架构
程序员黄老师1 天前
在 Windows 使用 Nginx/HAProxy 实现负载均衡
windows·nginx·负载均衡