1.背景
音频aac编码的时候,调用函数接口avcodec_encode_audio2)提示错误信息:[aac @ 0x7f7bb40184a0] more samples than frame size (avcodec_encode_audio2)
2.原因
代码块如下:
if (frame->nb_samples > avctx->frame_size) {
av_log(avctx, AV_LOG_ERROR, "more samples than frame size (avcodec_encode_audio2)\n");
ret = AVERROR(EINVAL);
goto end;
}
解析:
frame->nb_samples:实际编码时音频采样数的大小;
avctx->frame_size:预设定的音频编码采样率;
根据原因可知道,是喂给编码器的每帧采样数和预设定的音频编码采样率不一致导致的,解决方法就是让他们达到一致即可。
方法:将每次采集到的音频frame数据保存到一个AUDIO FIFO中,每次凑齐到frame_size大小的数据时,把这些数据喂给音频编码器即可。
以下代码未解决
#include <stdio.h>
#include <iostream>
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavdevice/avdevice.h"
#include "libavutil/audio_fifo.h"
}
using namespace std;
//'1' Use Dshow
//'0' Use VFW
#define USE_DSHOW 0
static int init_fifo(AVAudioFifo **fifo, AVCodecContext *output_codec_context)
{
/* Create the FIFO buffer based on the specified output sample format. */
if (!(*fifo = av_audio_fifo_alloc(output_codec_context->sample_fmt,
output_codec_context->channels, 1))) {
fprintf(stderr, "Could not allocate FIFO\n");
return AVERROR(ENOMEM);
}
return 0;
}
//Show Dshow Device
void show_dshow_device(){
AVFormatContext *pFormatCtx = avformat_alloc_context();
AVDictionary* options = NULL;
av_dict_set(&options,"list_devices","true",0);
AVInputFormat *iformat = av_find_input_format("dshow");
printf("========Device Info=============\n");
avformat_open_input(&pFormatCtx,"video=dummy",iformat,&options);
printf("================================\n");
}
//Show Dshow Device Option
void show_dshow_device_option(){
AVFormatContext *pFormatCtx = avformat_alloc_context();
AVDictionary* options = NULL;
av_dict_set(&options,"list_options","true",0);
AVInputFormat *iformat = av_find_input_format("dshow");
printf("========Device Option Info======\n");
avformat_open_input(&pFormatCtx,"video=Integrated Camera",iformat,&options);
printf("================================\n");
}
//Show VFW Device
void show_vfw_device(){
AVFormatContext *pFormatCtx = avformat_alloc_context();
AVInputFormat *iformat = av_find_input_format("vfwcap");
printf("========VFW Device Info======\n");
avformat_open_input(&pFormatCtx,"list",iformat,NULL);
printf("=============================\n");
}
//Show AVFoundation Device
void show_avfoundation_device(){
AVFormatContext *pFormatCtx = avformat_alloc_context();
AVDictionary* options = NULL;
av_dict_set(&options,"list_devices","true",0);
AVInputFormat *iformat = av_find_input_format("avfoundation");
printf("==AVFoundation Device Info===\n");
avformat_open_input(&pFormatCtx,"",iformat,&options);
printf("=============================\n");
}
#define USE_DSHOW 1
int main(int argc, char* argv[])
{
AVFormatContext *pFormatCtx;
int i, audioindex;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
av_register_all();
avformat_network_init();
avdevice_register_all();//Register Device
pFormatCtx = avformat_alloc_context();
#if 1
AVInputFormat *ifmt=av_find_input_format("dshow");
//Set own audio device's name
if(avformat_open_input(&pFormatCtx,"audio=麦克风 (Realtek High Definition Au",ifmt,NULL)!=0){
printf("Couldn't open input stream.\n");
return -1;
}
#else
AVInputFormat *ifmt=av_find_input_format("vfwcap");
if(avformat_open_input(&pFormatCtx,"audio=麦克风 (Realtek High Definition Au0",ifmt,NULL)!=0){
printf("Couldn't open input stream.\n");
return -1;
}
#endif
if(avformat_find_stream_info(pFormatCtx,NULL)<0)
{
printf("Couldn't find stream information.\n");
return -1;
}
audioindex=-1;
for(i=0; i<pFormatCtx->nb_streams; i++)
{
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO)
{
audioindex=i;
}
}
if(audioindex==-1)
{
printf("Couldn't find a audio stream.\n");
return -1;
}
pCodecCtx=pFormatCtx->streams[audioindex]->codec;
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==NULL)
{
printf("Codec not found.\n");
return -1;
}
if(avcodec_open2(pCodecCtx, pCodec,NULL)<0)
{
printf("Could not open codec.\n");
return -1;
}
///这里打印出音频的信息
cout<<"audio info:"<<pCodecCtx->sample_fmt<<pCodecCtx->bit_rate<<pCodecCtx->sample_rate<<pCodecCtx->channels<<endl;
FILE *fp_pcm=fopen("output.pcm","wb");
FILE *fp_aac=fopen("output.aac", "wb");
//查找编码器
AVCodecContext* pAAC_CodecCtx;
AVCodec* pAAC_Codec;
pAAC_Codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
if(!pAAC_Codec)
{
fprintf(stderr, "---------AAC codec not found----\n");
exit(1);
}
pAAC_CodecCtx = avcodec_alloc_context3(pAAC_Codec);
pAAC_CodecCtx->codec_id = AV_CODEC_ID_AAC;
pAAC_CodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
pAAC_CodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;
pAAC_CodecCtx->sample_rate= 44100;
pAAC_CodecCtx->channel_layout=AV_CH_LAYOUT_STEREO; //
pAAC_CodecCtx->channels = av_get_channel_layout_nb_channels(pAAC_CodecCtx->channel_layout);
pAAC_CodecCtx->bit_rate = 64000;
pAAC_Codec = avcodec_find_encoder(pAAC_CodecCtx->codec_id);
if (!pAAC_Codec)
{
printf("没有找到合适的编码器!\n");
return -1;
}
if (avcodec_open2(pAAC_CodecCtx, pAAC_Codec,NULL) < 0)
{
printf("编码器打开失败!\n");
return -1;
}
AVPacket *packet= (AVPacket*)av_malloc(sizeof(AVPacket));
AVFrame *pFrame = av_frame_alloc();
//uint8_t *out_buffer=(uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));
//avpicture_fill((AVPicture *)pFrame, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
int got_picture = 0;
float Time = 0;
AVAudioFifo *fifo = NULL;
if (init_fifo(&fifo, pAAC_CodecCtx))
{
cout<<"init_fifo failed"<<endl;
return -1;
}
for(int i=0;;i++)
{
if (Time > 10) break; //就采集10秒
if(av_read_frame(pFormatCtx, packet) < 0)
{
break;
}
if(packet->stream_index==audioindex)
{
int ret = avcodec_decode_audio4(pCodecCtx, pFrame, &got_picture, packet);
if(ret < 0){
printf("Decode Error.\n");
return -1;
}
if(got_picture)
{
int pcmSize = av_samples_get_buffer_size(NULL,pCodecCtx->channels, pFrame->nb_samples,pCodecCtx->sample_fmt, 1);
uint8_t * pcmBuffer = pFrame->data[0];
//pFrame->data[0] =
float useTime = pFrame->nb_samples * 1.0 / pCodecCtx->sample_rate;
Time += useTime;
cout<<i<<Time<<useTime;
//编码为aac
//int avcodec_encode_audio2(AVCodecContext *avctx, AVPacket *avpkt,
//const AVFrame *frame, int *got_packet_ptr);
int got_packet_ptr=0;
uint8_t data_aac;
int ret = avcodec_encode_audio2(pAAC_CodecCtx, packet , pFrame, &got_packet_ptr);
if (0 > ret)
{
cout<<"encoded aac failed"<<endl;
return -1;
}
if (got_packet_ptr == 1)
{
fwrite(packet->data,1,packet->size,fp_aac); //写入文件
}
}
}
av_free_packet(packet);
}
fclose(fp_pcm);
av_free(pFrame);
avcodec_close(pAAC_CodecCtx);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
return 0;
}