当前位置: 首页 > news >正文

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;
}

}

http://www.xdnf.cn/news/236917.html

相关文章:

  • 力扣hot100——98.验证二叉搜索树
  • 论MMUSMMUIOMMU
  • 分支限界法:用“快递分拣”思维解决复杂问题的算法艺术
  • 数据清洗的定义跟实际操作
  • 文件读取操作
  • Java 事务详解
  • allegro 怎样显示/隐藏铜皮shape?
  • AI时代生产工厂制造业数字化转型培训师培训讲师唐兴通教授专家顾问清华大学讲授AI库存降本增效智能制造供应链生产调度智能管理设备健康
  • Python math 库教学指南
  • Kubernetes 核心组件架构详解
  • git中reset和checkout的用法
  • C语言实现库函数strlen
  • 健康养生:构建健康生活的多维度指南
  • curl和wget的使用介绍
  • 修改apk包名
  • 使用atomic实现无锁方式的全局变量访问
  • 美林数据基于大模型的设备智能运维检修方案—驱动设备运检业务效率跃迁
  • 基于SpringBoot的旅游网站的设计与实现
  • spring boot中@Validated
  • pytorch对应gpu版本是否可用判断逻辑
  • JWT GenTokenParseToken
  • AnimateCC教学:形状补间动画的代码实现
  • 零改造实现MySQL加密:安当TDE透明加密与KSP密钥管理系统的创新实践
  • Kaggle比赛入门攻略(以 Titanic 为例)
  • 玩转MCP
  • C# dataGridView分页
  • JMeter WebSocket 压测详细步骤(支持 ws+proto 协议)
  • flutter 专题 五十六 Google 2020开发者大会Flutter专题
  • 驱动车辆诊断测试创新 | 支持诊断测试的模拟器及数据文件转换生成
  • 斯坦福RGA软件 老版本和兼容Windows 11版本可选