提供一个可以运行的ffmpeg工程:https://gitee.com/qiuguolu1108/ffmpeg-study
ffmpeg -i Jasmine.flv -acodec copy -vn Jasmine.aac
进入工程中的player目录,使用上述命令,生成待处理的Jasmine.aac文件。
#include "spdlog/spdlog.h"
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavutil/frame.h"
#include "libavutil/mem.h"
}
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096
char error_buf[1024] = {0};
char* av_get_err(int err_num) {
av_strerror(err_num, error_buf, sizeof(error_buf));
return error_buf;
}
void print_sample_format(const AVFrame* frame) {
SPDLOG_INFO("ar-samplerate: {}", frame->sample_rate);
SPDLOG_INFO("ac-channel: {}", frame->channels);
SPDLOG_INFO("f-format: {}",
frame->format); //实际存储到本地文件时已经改成交错模式
}
void decode(AVCodecContext* dec_ctx, AVPacket* pkt, AVFrame* frame,
FILE* pcm_file) {
// send the packet with the compressed data to the decoder
int ret = avcodec_send_packet(dec_ctx, pkt);
if (ret == AVERROR(EAGAIN)) {
SPDLOG_ERROR(
"Receive_frame and send_packet both returned EAGAIN, which is an API "
"violation.");
} else if (ret < 0) {
SPDLOG_WARN(
"Error submitting the packet to the decoder, err: {}, pkt_size: {}",
av_get_err(ret), pkt->size);
return;
}
// read all the output frames (in general there may be any number of them
while (ret >= 0) {
ret = avcodec_receive_frame(dec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
return;
} else if (ret < 0) {
SPDLOG_ERROR("Error during decoding");
}
int data_size = av_get_bytes_per_sample(dec_ctx->sample_fmt);
if (data_size < 0) {
// This should not occur, checking just for paranoia
SPDLOG_ERROR("Failed to calculate data size");
}
static int s_print_format = 0;
if (s_print_format == 0) {
s_print_format = 1;
print_sample_format(frame);
}
for (int i = 0; i < frame->nb_samples; i++) {
for (int ch = 0; ch < dec_ctx->channels; ch++) {
fwrite(frame->data[ch] + data_size * i, 1, data_size, pcm_file);
}
}
}
}
int main() {
const char* aac_file_name = "Jasmine.aac";
const char* pcm_file_name = "Jasmine.pcm";
FILE* aac_file = fopen(aac_file_name, "rb");
if (!aac_file) {
SPDLOG_ERROR("Could not open {}", aac_file_name);
}
FILE* pcm_file = fopen(pcm_file_name, "wb");
if (!pcm_file) {
SPDLOG_ERROR("Could not open {}", pcm_file_name);
}
//查找解码器
const AVCodec* audio_codec = avcodec_find_decoder(AV_CODEC_ID_AAC);
if (!audio_codec) {
SPDLOG_ERROR("Audio codec not found");
}
//获取裸流的解析器
AVCodecParserContext* audio_parser_ctx = av_parser_init(audio_codec->id);
if (!audio_parser_ctx) {
SPDLOG_ERROR("Parser not found");
}
//分配解码上下文
AVCodecContext* audio_codec_ctx = avcodec_alloc_context3(audio_codec);
if (!audio_codec_ctx) {
SPDLOG_ERROR("Could not allocate audio codec context");
}
//将解码器和解码器上下文进行关联
int ret = avcodec_open2(audio_codec_ctx, audio_codec, NULL);
if (ret < 0) {
SPDLOG_ERROR("Could not oepn audio codec");
}
uint8_t aac_buf[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
uint8_t* data = aac_buf;
AVPacket* pkt = av_packet_alloc();
AVFrame* decoded_frame = NULL;
size_t data_size = fread(aac_buf, 1, AUDIO_INBUF_SIZE, aac_file);
while (data_size > 0) {
if (!decoded_frame) {
SPDLOG_WARN("decode frame is NULL");
if (!(decoded_frame = av_frame_alloc())) {
SPDLOG_ERROR("Could not allocate audio frame");
}
}
ret = av_parser_parse2(audio_parser_ctx, audio_codec_ctx, &pkt->data,
&pkt->size, data, data_size, AV_NOPTS_VALUE,
AV_NOPTS_VALUE, 0);
if (ret < 0) {
SPDLOG_ERROR("Error while parsing");
}
data += ret; // 跳过已经解析的数据
data_size -= ret;
if (pkt->size > 0) {
decode(audio_codec_ctx, pkt, decoded_frame, pcm_file);
}
if (data_size < AUDIO_REFILL_THRESH) {
memmove(aac_buf, data, data_size);
data = aac_buf;
int len =
fread(data + data_size, 1, AUDIO_INBUF_SIZE - data_size, aac_file);
if (len > 0) {
data_size += len;
}
}
}
pkt->data = NULL;
pkt->size = 0;
decode(audio_codec_ctx, pkt, decoded_frame, pcm_file); // 冲刷解码器
fclose(aac_file);
fclose(pcm_file);
avcodec_free_context(&audio_codec_ctx);
av_parser_close(audio_parser_ctx);
av_frame_free(&decoded_frame);
av_packet_free(&pkt);
SPDLOG_INFO("audio decode successful");
return 0;
}
[2021-09-14 21:30:46.182] [warning] [main.cpp:123] decode frame is NULL
[2021-09-14 21:30:46.184] [info] [main.cpp:19] ar-samplerate: 48000
[2021-09-14 21:30:46.184] [info] [main.cpp:20] ac-channel: 2
[2021-09-14 21:30:46.184] [info] [main.cpp:22] f-format: 8
[2021-09-14 21:30:48.442] [info] [main.cpp:165] audio decode successful
使用如下命令播放生成的pcm文件:
ffplay -f f32le -ar 48000 -ac 2 Jasmine.pcm