新版大于3.0后的版本,按雷霄骅大神的 最简单的基于FFMPEG的音频编码器(PCM编码为AAC)的例子已经无法走完流程,avcodec_open2会返回-22,其中原因是
1、新版版的ffmpeg 编码AAC只支持的AV_SAMPLE_FMT_FLTP,老版本的是AV_SAMPLE_FMT_S16,参数开之后avcodec_open2返回正确,但不要高兴太早;
2、很可能你传入的PCM数据是AV_SAMPLE_FMT_S16的,avcodec_encode_audio2还是返回-22错误,争取做法是需要AV_SAMPLE_FMT_S16的数据转为AV_SAMPLE_FMT_FLTP就可以了。下面贴一个ffmpeg4.0能编译通过执行编码的代码
/**
*最简单的基于FFmpeg的音频编码器
*Simplest FFmpeg Audio Encoder
*
*雷霄骅 Lei Xiaohua
*[email protected]
*中国传媒大学/数字电视技术
*Communication University of China / Digital TV Technology
*http://blog.csdn.net/leixiaohua1020
*
*本程序实现了音频PCM采样数据编码为压缩码流(MP3,WMA,AAC等)。
*是最简单的FFmpeg音频编码方面的教程。
*通过学习本例子可以了解FFmpeg的编码流程。
*This software encode PCM data to AAC bitstream.
*It's the simplest audio encoding software based on FFmpeg.
*Suitable for beginner of FFmpeg
*/
#include
#define __STDC_CONSTANT_MACROS
#ifdef _WIN32
//Windows
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"
#include "libavutil/opt.h"
};
#else
//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include
#include
#include
#ifdef __cplusplus
};
#endif
#endif
int flush_encoder(AVFormatContext *fmt_ctx,unsigned int stream_index){
int ret;
int got_frame;
AVPacket enc_pkt;
if (!(fmt_ctx->streams[stream_index]->codec->codec->capabilities &
AV_CODEC_CAP_DELAY))
return 0;
while (1) {
enc_pkt.data = NULL;
enc_pkt.size = 0;
av_init_packet(&enc_pkt);
ret = avcodec_encode_audio2 (fmt_ctx->streams[stream_index]->codec, &enc_pkt,
NULL, &got_frame);
av_frame_free(NULL);
if (ret < 0)
break;
if (!got_frame){
ret=0;
break;
}
printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n",enc_pkt.size);
/* mux encoded frame */
ret = av_write_frame(fmt_ctx, &enc_pkt);
if (ret < 0)
break;
}
return ret;
}
int main(int argc, char* argv[])
{
AVFormatContext* pFormatCtx;
AVOutputFormat* fmt;
AVStream* audio_st;
AVCodecContext* pCodecCtx;
AVCodec* pCodec;
uint8_t* frame_buf;
AVFrame* pFrame;
AVPacket pkt;
SwrContext *swr;
int got_frame=0;
int ret=0;
int size=0;
FILE *in_file=NULL; //Raw PCM data
int framenum=1000; //Audio frame number
const char* out_file = "tdjm.aac"; //Output URL
int i;
in_file= fopen("tdjm.pcm", "rb");
av_register_all();
//Method 1.
pFormatCtx = avformat_alloc_context();
fmt = av_guess_format(NULL, out_file, NULL);
pFormatCtx->oformat = fmt;
//Method 2.
//avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, out_file);
//fmt = pFormatCtx->oformat;
//Open output URL
if (avio_open(&pFormatCtx->pb,out_file, AVIO_FLAG_READ_WRITE) < 0){
printf("Failed to open output file!\n");
return -1;
}
audio_st = avformat_new_stream(pFormatCtx, 0);
if (audio_st==NULL){
return -1;
}
pCodec = avcodec_find_encoder(fmt->audio_codec);
if (!pCodec){
printf("Can not find encoder!\n");
return -1;
}
pCodecCtx = audio_st->codec;
pCodecCtx->codec_id = fmt->audio_codec;
pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
pCodecCtx->sample_fmt = pCodec->sample_fmts[0];
pCodecCtx->sample_rate= 44100;
pCodecCtx->channel_layout=AV_CH_LAYOUT_STEREO;
pCodecCtx->channels = av_get_channel_layout_nb_channels(pCodecCtx->channel_layout);
pCodecCtx->bit_rate = 64000;
pCodecCtx->profile=FF_PROFILE_AAC_MAIN ;
pCodecCtx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
//Show some information
av_dump_format(pFormatCtx, 0, out_file, 1);
swr = swr_alloc();
av_opt_set_int(swr, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_int(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
av_opt_set_int(swr, "in_sample_rate", 44100, 0);
av_opt_set_int(swr, "out_sample_rate", 44100, 0);
av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);
swr_init(swr);
uint8_t *outs[2];
int len = 4096;
outs[0]=(uint8_t *)malloc(len);//len 为4096
outs[1]=(uint8_t *)malloc(len);
if ((ret = avcodec_open2(pCodecCtx, pCodec,NULL)) < 0){
printf("Failed to open encoder!\n");
return -1;
}
pFrame = av_frame_alloc();
pFrame->nb_samples= pCodecCtx->frame_size;
pFrame->format= pCodec->sample_fmts[0];
size = av_samples_get_buffer_size(NULL, pCodecCtx->channels,pCodecCtx->frame_size,pCodecCtx->sample_fmt, 1);
frame_buf = (uint8_t *)av_malloc(size);
avcodec_fill_audio_frame(pFrame, pCodecCtx->channels, pCodecCtx->sample_fmt,(const uint8_t*)frame_buf, size, 1);
//Write Header
avformat_write_header(pFormatCtx,NULL);
av_new_packet(&pkt,size);
for (i=0; idata[0] =(uint8_t*)outs[0];//audioFrame 是VFrame
pFrame->data[1] =(uint8_t*)outs[1];
//pFrame->data[0] = frame_buf; //PCM Data
pFrame->pts=i*100;
got_frame=0;
//Encode
ret = avcodec_encode_audio2(pCodecCtx, &pkt,pFrame, &got_frame);
if(ret < 0){
printf("Failed to encode!\n");
return -1;
}
if (got_frame==1){
printf("Succeed to encode 1 frame! \tsize:%5d\n",pkt.size);
pkt.stream_index = audio_st->index;
ret = av_write_frame(pFormatCtx, &pkt);
av_free_packet(&pkt);
}
}
//Flush Encoder
ret = flush_encoder(pFormatCtx,0);
if (ret < 0) {
printf("Flushing encoder failed\n");
return -1;
}
//Write Trailer
av_write_trailer(pFormatCtx);
//Clean
if (audio_st){
avcodec_close(audio_st->codec);
av_free(pFrame);
av_free(frame_buf);
}
avio_close(pFormatCtx->pb);
avformat_free_context(pFormatCtx);
fclose(in_file);
return 0;
}
嵌入式与windows桌面音视频技术交流可叫微信