代码对一些数据没做判断,仅仅是做个备忘!请谨慎参考!
#include <libavcodec/avcodec.h>
#include <stdio.h>
void f32le_convert_to_fltp(float *f32le, float *fltp, int nb_samples) {
float *fltp_l = fltp; // 左通道
float *fltp_r = fltp + nb_samples; // 右通道
for (int i = 0; i < nb_samples; i++) {
fltp_l[i] = f32le[i * 2];
fltp_r[i] = f32le[i * 2 + 1];
}
}
static void get_adts_header(AVCodecContext *ctx, uint8_t *adts_header,
int aac_length) {
uint8_t freq_idx = 0;
switch (ctx->sample_rate) {
case 96000:
freq_idx = 0;
break;
case 88200:
freq_idx = 1;
break;
case 64000:
freq_idx = 2;
break;
case 48000:
freq_idx = 3;
break;
case 44100:
freq_idx = 4;
break;
case 32000:
freq_idx = 5;
break;
case 24000:
freq_idx = 6;
break;
case 22050:
freq_idx = 7;
break;
case 16000:
freq_idx = 8;
break;
case 12000:
freq_idx = 9;
break;
case 11025:
freq_idx = 10;
break;
case 8000:
freq_idx = 11;
break;
case 7350:
freq_idx = 12;
break;
default:
freq_idx = 4;
break;
}
uint8_t chanCfg = ctx->channels;
uint32_t frame_length = aac_length + 7;
adts_header[0] = 0xFF;
adts_header[1] = 0xF1;
adts_header[2] = ((ctx->profile) << 6) + (freq_idx << 2) + (chanCfg >> 2);
adts_header[3] = (((chanCfg & 3) << 6) + (frame_length >> 11));
adts_header[4] = ((frame_length & 0x7FF) >> 3);
adts_header[5] = (((frame_length & 7) << 5) + 0x1F);
adts_header[6] = 0xFC;
}
void encode_audio(AVCodecContext *codec_ctx, AVFrame *frame, AVPacket *pkt,
FILE *out_aac) {
int ret;
ret = avcodec_send_frame(codec_ctx, frame);
while (!ret) {
ret = avcodec_receive_packet(codec_ctx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
printf("EAGAIN OR EOF\n");
return;
} else if (ret < 0) {
printf("error 6\n");
exit(1);
}
if ((codec_ctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) {
uint8_t aac_header[7];//7个字节的adts header
get_adts_header(codec_ctx, aac_header, pkt->size);
ret = fwrite(aac_header, 1, 7, out_aac);
if (ret != 7) {
fprintf(stderr, "fwrite aac_header failed\n");
return -1;
}
}
fwrite(pkt->data, 1, pkt->size, out_aac);
}
}
/**
* @brief 音频编码 PCM编码为AAC
* @param argc
* @param argv
* @return
*/
int main(int argc, char **argv) {
AVCodecContext *codec_ctx;
AVCodec *codec;
FILE *in_pcm;
FILE *out_aac;
AVPacket *pkt;
AVFrame *frame;
int ret;
if(argc != 3){
printf("param error\n");
exit(1);
}
in_pcm = fopen(argv[1], "rb");
out_aac = fopen(argv[2], "wb");
codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
if (!codec) {
printf("error 1\n");
exit(1);
}
codec_ctx = avcodec_alloc_context3(codec);
codec_ctx->codec_id = AV_CODEC_ID_AAC;
codec_ctx->sample_rate = 44100;
codec_ctx->bit_rate = 512 * 1024;
codec_ctx->channels = 2;
codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
codec_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
codec_ctx->profile = FF_PROFILE_AAC_LOW;
codec_ctx->codec_type = AVMEDIA_TYPE_AUDIO;
codec_ctx->time_base = (AVRational){1, codec_ctx->sample_rate};
codec_ctx->flags = AV_CODEC_FLAG_GLOBAL_HEADER;
ret = avcodec_open2(codec_ctx, codec, NULL);
if (ret) {
printf("error 2\n");
exit(1);
}
frame = av_frame_alloc();
frame->nb_samples = codec_ctx->frame_size;
frame->channels = 2;
frame->channel_layout = AV_CH_LAYOUT_STEREO;
frame->format = codec_ctx->sample_fmt;
ret = av_frame_get_buffer(frame, 0);
int nb_samples = 0;
if (ret) {
printf("error 3\n");
exit(1);
}
pkt = av_packet_alloc();
av_init_packet(pkt);
int bytes_per_frame = av_get_bytes_per_sample(AV_SAMPLE_FMT_FLTP) *
frame->nb_samples * frame->channels;
uint8_t *in_buf = (uint8_t *)av_mallocz(bytes_per_frame);
uint8_t *in_buf_temp = (uint8_t *)malloc(bytes_per_frame);
if (!in_buf_temp) {
printf("in_buf_temp malloc failed\n");
return 1;
}
while (fread(in_buf, 1, bytes_per_frame, in_pcm) == bytes_per_frame) {
ret = av_frame_make_writable(frame);
//fltp如果是按照packeted方式存储的,需要先转换成planar方式
// memset(in_buf_temp, 0, bytes_per_frame);
// f32le_convert_to_fltp((float *)in_buf, (float *)in_buf_temp,
// frame->nb_samples);
ret = av_samples_fill_arrays(frame->data, frame->linesize, in_buf/*in_buf_temp*/,
frame->channels, frame->nb_samples,
frame->format, 0);
if (ret < 0) {
printf("error 4\n");
exit(1);
}
frame->pts = nb_samples;
nb_samples += frame->nb_samples;
encode_audio(codec_ctx, frame, pkt, out_aac);
memset(in_buf, 0, bytes_per_frame);
}
encode_audio(codec_ctx, NULL, pkt, out_aac);
end:
fclose(in_pcm);
fclose(out_aac);
avcodec_free_context(&codec_ctx);
av_frame_free(&frame);
av_packet_free(&pkt);
printf("Hello World!\n");
return 0;
}