使用FFMPEG进行麦克风录音编码。
但是执行avcodec_send_frame报错AVERROR(EINVAL)
感觉是编码器参数和frame参数不匹配导致的。
有没有哪位熟悉ffmpeg的专家给看看,是哪的错误。
编码器设置为
c_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP; //AV_SAMPLE_FMT_S16,AV_SAMPLE_FMT_FLTP;
c_ctx->channel_layout = AV_CH_LAYOUT_MONO; // 输入音频的CHANNEL LAYOUT
c_ctx->channels = 1; // 输入音频的声道数
c_ctx->sample_rate = 44100; // 输入音频的采样率
c_ctx->bit_rate = 16000; // AAC : 128K AAV_HE: 64K AAC_HE_V2: 32K. bit_rate为0时才会查找profile属性值
c_ctx->profile = FF_PROFILE_AAC_LOW;
frame设置为
frame = av_frame_alloc();
frame->nb_samples = 1024;
frame->format=AV_SAMPLE_FMT_FLTP;
frame->channel_layout=AV_CH_LAYOUT_MONO;
完整代码如下:
#include "audiodecode.h"
#include <QMessageBox>
#include <QDebug>
// init context
static AVFormatContext *fmt_ctx = nullptr;
static AVPacket ptk;
static int pktPos = 0;
static AVFrame* frame =nullptr;
static AVPacket *newpkt = nullptr;
static int swr_num = 0;
static uint8_t bufferData[2048];
static AVCodecContext* c_ctx = nullptr;
AudioDecode::AudioDecode( QObject* parent ):QObject(parent)
{
}
bool AudioDecode::init(){
// register device
avdevice_register_all();
// set logger level
av_log_set_level(AV_LOG_DEBUG);
// get input device format
AVInputFormat *iformat = av_find_input_format("dshow");
if( !iformat ){
emit error("get input format fail");
return false;
}
// 输入设备
QString deviceName = QString::fromLocal8Bit("audio=麦克风 (High Definition Audio Device)");
AVDictionary *options = nullptr;
// open audio device
int r = avformat_open_input(&fmt_ctx, deviceName.toStdString().c_str(), iformat, &options);
if (r < 0){
emit error(QString("Failed to open audio device! ret=%1").arg(QString::number(r)));
return false;
}
av_init_packet(&ptk);
const AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
if( codec==NULL ){
emit error("faild to open encoder");
return false;
}
c_ctx = avcodec_alloc_context3(codec);
c_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP; //AV_SAMPLE_FMT_S16,AV_SAMPLE_FMT_FLTP;
c_ctx->channel_layout = AV_CH_LAYOUT_MONO; // 输入音频的CHANNEL LAYOUT
c_ctx->channels = 1; // 输入音频的声道数
c_ctx->sample_rate = 44100; // 输入音频的采样率
c_ctx->bit_rate = 16000; // AAC : 128K AAV_HE: 64K AAC_HE_V2: 32K. bit_rate为0时才会查找profile属性值
c_ctx->profile = FF_PROFILE_AAC_LOW;
// 打开编码器
if (avcodec_open2(c_ctx, codec, NULL) < 0){
emit error("failed to open aac");
return false;
}
frame = av_frame_alloc();
frame->nb_samples = 1024;
frame->format=AV_SAMPLE_FMT_FLTP;
frame->channel_layout=AV_CH_LAYOUT_MONO;
av_frame_get_buffer(frame,0);
newpkt = av_packet_alloc();//分配编码后的数据空间
return true;
}
AudioDecode::~AudioDecode(){
if( frame )
av_frame_free(&frame);
if( newpkt )
av_packet_free(&newpkt);
if( c_ctx )
av_free(c_ctx);
if( fmt_ctx )
avformat_close_input(&fmt_ctx);
}
AVPacket* AudioDecode::getInput(){
// 从编码器直接取包
int ret = avcodec_receive_packet(c_ctx,newpkt);
if( ret==0 ){
emit debug(QString("direct audio packet ").append(QString::number(newpkt->size)));
return newpkt;
}
while(true){
// 没有获取过输入包
if( ptk.size==0 ){
ret = av_read_frame(fmt_ctx,&ptk);
if( ret<0 ){
emit debug("No new frame");
return NULL;
}
pktPos = 0;
}
// 输入包的数据已经编码
if( pktPos==ptk.size ){
av_packet_unref(&ptk);
ret = av_read_frame(fmt_ctx,&ptk);
if( ret<0 ){
emit debug("No new frame");
return NULL;
}
pktPos = 0;
}
// 拷贝出帧数据到编码缓冲区
while( swr_num!=2048 && pktPos!=ptk.size ){
bufferData[swr_num] = ptk.data[pktPos];
++swr_num;
++pktPos;
}
// 编码缓冲区已满
if( swr_num==2048 ){
swr_num = 0;
memcpy((void *)frame->data[0], bufferData, 2048);
ret = avcodec_send_frame(c_ctx,frame);
if( ret<0 ){
switch( ret ){
case AVERROR(EAGAIN):
emit warn(QString("avcodec_send_frame [input is not accepted in the current state - user must read output with avcodec_receive_packet() (once all output is read, the packet should be resent, and the call will not fail with EAGAIN).]"));
break;
case AVERROR_EOF:
emit warn(QString("avcodec_send_frame [the encoder has been flushed, and no new frames can be sent to it]"));
break;
case AVERROR(EINVAL):
emit warn(QString("avcodec_send_frame [codec not opened, refcounted_frames not set, it is a decoder, or requires flush]"));
break;
case AVERROR(ENOMEM):
emit warn(QString("avcodec_send_frame [failed to add packet to internal queue, or similar]"));
break;
default:
emit warn(QString("avcodec_send_frame %1").arg(QString::number(ret)));
}
return NULL;
}
ret = avcodec_receive_packet(c_ctx,newpkt);
if( ret<0 ){
emit debug(QString("avcodec_receive_packet %1").arg(QString::number(ret)));
return NULL;
}
emit debug(QString("new audio packet ").append(QString::number(newpkt->size)));
return newpkt;
}
}
}