ffmpeg7.0 aac转pcm
#pragma once
#define __STDC_CONSTANT_MACROS
#define _CRT_SECURE_NO_WARNINGS
extern "C"
{
#include "libavcodec/avcodec.h"
}
//缓冲区大小(缓存5帧数据)
#define AUDIO_INBUF_SIZE 40960
/*
name depth
u8 8
s16 16
s32 32
flt 32
dbl 64
u8p 8
s16p 16
s32p 32
fltp 32
dblp 64
s64 64
s64p 64
//此代码解码的音频文件格式如下:
//AAC文件(一帧1024字节),双声道(2),FLTP(32位,4字节)
//AAC文件 frame_size 和 nb_samples 大小均为1024
//一帧音频所占字节大小
//1024*2*4=8192字节
*/
#define AUDIO_REFILL_THRESH 8192
using namespace std;
#define INPUT_FILE_NAME "d:\\123.aac"
#define OUTPUT_FILE_NAME "d:\\1111.pcm"
static int get_format_from_sample_fmt(const char** fmt, enum AVSampleFormat sample_fmt)
{
struct sample_fmt_entry {
enum AVSampleFormat sample_fmt;
const char* fmt_be, * fmt_le;
} sample_fmt_entries[] = {
{ AV_SAMPLE_FMT_U8, "u8", "u8" },
{ AV_SAMPLE_FMT_S16, "s16be", "s16le" },
{ AV_SAMPLE_FMT_S32, "s32be", "s32le" },
{ AV_SAMPLE_FMT_FLT, "f32be", "f32le" },
{ AV_SAMPLE_FMT_DBL, "f64be", "f64le" },
};
*fmt = NULL;
for (int i = 0; i < FF_ARRAY_ELEMS(sample_fmt_entries); i++) {
struct sample_fmt_entry* entry = &sample_fmt_entries[i];
if (sample_fmt == entry->sample_fmt) {
*fmt = AV_NE(entry->fmt_be, entry->fmt_le);
return 0;
}
}
av_log(NULL, AV_LOG_ERROR, "sample format %s is not supported as output format\n", av_get_sample_fmt_name(sample_fmt));
return -1;
}
static void decode(AVCodecContext* pCodecContext, AVFrame* pFrame, AVPacket* pPacket, FILE* pFile)
{
int ret = avcodec_send_packet(pCodecContext, pPacket);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "发送数据包到解码器出错。\n");
exit(1);
}
while (ret >= 0) {
ret = avcodec_receive_frame(pCodecContext, pFrame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
return;
}
else if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error sending a packet for decoding.\n");
exit(1);
}
//获取每个采样点当中每个声道的大小
int nDataSize = av_get_bytes_per_sample(pCodecContext->sample_fmt);
if (nDataSize < 0) {
av_log(NULL, AV_LOG_ERROR, "Failed to calculate data size.\n");
exit(1);
}
//遍历采样点
for (int i = 0; i < pFrame->nb_samples; i++) {
//遍历声道
for (int ch = 0; ch < pCodecContext->ch_layout.nb_channels; ch++) {
fwrite(pFrame->data[ch] + nDataSize * i, 1, nDataSize, pFile);
}
}
}
}
int main(int argc, char* argv[])
{
//初始化inbuf数字默认值
uint8_t inbuf[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE] = {0};
//获取解码器(此处需要读取的文件是AAC,故)
const AVCodec* pCodecOfAAC = avcodec_find_decoder(AV_CODEC_ID_AAC);
if (!pCodecOfAAC) {
av_log(NULL, AV_LOG_ERROR, "Codec not found.\n");
exit(1);
}
//注册解析器
AVCodecParserContext* pCodecParserParser = av_parser_init(pCodecOfAAC->id);
if (!pCodecParserParser) {
av_log(NULL, AV_LOG_ERROR, "parser not found.\n");
exit(1);
}
//分配解析器上下文
AVCodecContext* pCodecContextOfAAC = avcodec_alloc_context3(pCodecOfAAC);
if (!pCodecContextOfAAC) {
av_log(NULL, AV_LOG_ERROR, "Could not allocate video codec context.\n");
exit(1);
}
//打开解码器
if (avcodec_open2(pCodecContextOfAAC, pCodecOfAAC, NULL) < 0) {
av_log(NULL, AV_LOG_ERROR, "Could not open codec.\n");
exit(1);
}
//分配AVPacket
AVPacket* pPacket = av_packet_alloc();
if (!pPacket) {
exit(1);
}
//分配AVFrame
AVFrame* pFrame = av_frame_alloc();
if (!pFrame) {
exit(1);
}
//打开输入文件
FILE* ifile = fopen(INPUT_FILE_NAME, "rb");
if (!ifile) {
av_log(NULL, AV_LOG_ERROR, "Could not open \s.\n", INPUT_FILE_NAME);
exit(1);
}
//打开输入文件
FILE* ofile = fopen(OUTPUT_FILE_NAME, "wb+");
if (!ofile) {
av_log(NULL, AV_LOG_ERROR, "Could not open \s.\n", OUTPUT_FILE_NAME);
exit(1);
}
//从输入流 ifile 读取数据到 inbuf 所指向的数组中
uint8_t* data = inbuf;
size_t nDataSize = fread(inbuf, 1, AUDIO_INBUF_SIZE, ifile);
while (nDataSize > 0) {
//使用注册的解析器 parser 把数据分割成帧
int nRet = av_parser_parse2(pCodecParserParser, pCodecContextOfAAC, &pPacket->data, &pPacket->size, data, nDataSize, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
if (nRet < 0) {
fprintf(stderr, "Error while parsing\n");
exit(1);
}
//根据使用情况重置数据位置
data += nRet;
nDataSize -= nRet;
//送往解码
if (pPacket->size) {
decode(pCodecContextOfAAC, pFrame, pPacket, ofile);
}
//判断缓存区剩余数据是否小于一帧音频大小
//小于的话从文件继续读取,之后在送往解码
if (nDataSize < AUDIO_REFILL_THRESH) {
memmove(inbuf, data, nDataSize);
data = inbuf;
int nLen = fread(data + nDataSize, 1, AUDIO_INBUF_SIZE - nDataSize, ifile);
if (nLen > 0) {
nDataSize += nLen;
}
}
}
//flush 解码器
decode(pCodecContextOfAAC, pFrame, NULL, ofile);
//此时就已经解码完了,我们稍后使用ffplay播放下音频
//解码出来的pcm数据是没有这些基础数据的,我们需要从元数据获取
//打印下基本信息
//声道数
printf("channels: %d \n", pCodecContextOfAAC->ch_layout.nb_channels);
//采样率
printf("sample_rate: %d \n", pCodecContextOfAAC->sample_rate);
//一帧音频所占字节代销
printf("buffer: %d \n", av_samples_get_buffer_size(NULL, pCodecContextOfAAC->ch_layout.nb_channels, pCodecContextOfAAC->frame_size, pCodecContextOfAAC->sample_fmt, 1));
//采样格式
enum AVSampleFormat sfmt = pCodecContextOfAAC->sample_fmt;
printf("sample_fmt: %s \n", av_get_sample_fmt_name(sfmt));
//如果为planar,转换为packed格式
if (av_sample_fmt_is_planar(sfmt)) {
const char* packed = av_get_sample_fmt_name(sfmt);
sfmt = av_get_packed_sample_fmt(sfmt);
}
const char* fmt = NULL;
if (get_format_from_sample_fmt(&fmt, sfmt) < 0) {
av_log(NULL, AV_LOG_ERROR, "Could not get forma \s.\n", av_get_sample_fmt_name(sfmt));
exit(1);
}
//资源释放
fclose(ifile);
fclose(ofile);
av_parser_close(pCodecParserParser);
avcodec_free_context(&pCodecContextOfAAC);
av_frame_free(&pFrame);
av_packet_free(&pPacket);
return 0;
}