FFMPEG AAC编码使音频的音调降低
我构建了一个示例应用程序,将AAC(来自PortAudio)编码到MP4容器中(无视频流) 产生的音频音调较低FFMPEG AAC编码使音频的音调降低,ffmpeg,audio-recording,aac,portaudio,Ffmpeg,Audio Recording,Aac,Portaudio,我构建了一个示例应用程序,将AAC(来自PortAudio)编码到MP4容器中(无视频流) 产生的音频音调较低 #include "stdafx.h" #include "TestRecording.h" #include "libffmpeg.h" TestRecording::TestRecording() { } TestRecording::~TestRecording() { } struct RecordingContext { RecordingContext()
#include "stdafx.h"
#include "TestRecording.h"
#include "libffmpeg.h"
TestRecording::TestRecording()
{
}
TestRecording::~TestRecording()
{
}
struct RecordingContext
{
RecordingContext()
{
formatContext = NULL;
audioStream = NULL;
audioFrame = NULL;
audioFrameframeNumber = 0;
}
libffmpeg::AVFormatContext* formatContext;
libffmpeg::AVStream* audioStream;
libffmpeg::AVFrame* audioFrame;
int audioFrameframeNumber;
};
static int AudioRecordCallback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData)
{
RecordingContext* recordingContext = (RecordingContext*)userData;
libffmpeg::avcodec_fill_audio_frame(recordingContext->audioFrame,
recordingContext->audioFrame->channels,
recordingContext->audioStream->codec->sample_fmt,
static_cast<const unsigned char*>(inputBuffer),
(framesPerBuffer * sizeof(float) * recordingContext->audioFrame->channels),
0);
libffmpeg::AVPacket pkt;
libffmpeg::av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
int gotpacket;
int result = avcodec_encode_audio2(recordingContext->audioStream->codec, &pkt, recordingContext->audioFrame, &gotpacket);
if (result < 0)
{
LOGINT_WITH_MESSAGE(ERROR, result, "Couldn't encode the audio frame to acc");
return paContinue;
}
if (gotpacket)
{
pkt.stream_index = recordingContext->audioStream->index;
recordingContext->audioFrameframeNumber++;
// this codec requires no bitstream filter, just send it to the muxer!
result = libffmpeg::av_write_frame(recordingContext->formatContext, &pkt);
if (result < 0)
{
LOG(ERROR) << "Couldn't write the encoded audio frame";
libffmpeg::av_free_packet(&pkt);
return paContinue;
}
libffmpeg::av_free_packet(&pkt);
}
return paContinue;
}
static bool InitializeRecordingContext(RecordingContext* recordingContext)
{
int result = libffmpeg::avformat_alloc_output_context2(&recordingContext->formatContext, NULL, NULL, "C:\\Users\\Paul\\Desktop\\test.mp4");
if (result < 0)
{
LOGINT_WITH_MESSAGE(ERROR, result, "Couldn't create output format context");
return false;
}
libffmpeg::AVCodec *audioCodec;
audioCodec = libffmpeg::avcodec_find_encoder(libffmpeg::AV_CODEC_ID_AAC);
if (audioCodec == NULL)
{
LOG(ERROR) << "Couldn't find the encoder for AAC";
}
recordingContext->audioStream = libffmpeg::avformat_new_stream(recordingContext->formatContext, audioCodec);
if (!recordingContext->audioStream)
{
LOG(ERROR) << "Couldn't create the audio stream";
return false;
}
recordingContext->audioStream->codec->bit_rate = 64000;
recordingContext->audioStream->codec->sample_fmt = libffmpeg::AV_SAMPLE_FMT_FLTP;
recordingContext->audioStream->codec->sample_rate = 48000;
recordingContext->audioStream->codec->channel_layout = AV_CH_LAYOUT_STEREO;
recordingContext->audioStream->codec->channels = libffmpeg::av_get_channel_layout_nb_channels(recordingContext->audioStream->codec->channel_layout);
recordingContext->audioStream->codecpar->bit_rate = recordingContext->audioStream->codec->bit_rate;
recordingContext->audioStream->codecpar->format = recordingContext->audioStream->codec->sample_fmt;
recordingContext->audioStream->codecpar->sample_rate = recordingContext->audioStream->codec->sample_rate;
recordingContext->audioStream->codecpar->channel_layout = recordingContext->audioStream->codec->channel_layout;
recordingContext->audioStream->codecpar->channels = recordingContext->audioStream->codec->channels;
result = libffmpeg::avcodec_open2(recordingContext->audioStream->codec, audioCodec, NULL);
if (result < 0)
{
LOGINT_WITH_MESSAGE(ERROR, result, "Couldn't open the audio codec");
return false;
}
// create a new frame to store the audio samples
recordingContext->audioFrame = libffmpeg::av_frame_alloc();
if (!recordingContext->audioFrame)
{
LOG(ERROR) << "Couldn't alloce the output audio frame";
return false;
}
recordingContext->audioFrame->nb_samples = recordingContext->audioStream->codec->frame_size;
recordingContext->audioFrame->channel_layout = recordingContext->audioStream->codec->channel_layout;
recordingContext->audioFrame->channels = recordingContext->audioStream->codec->channels;
recordingContext->audioFrame->format = recordingContext->audioStream->codec->sample_fmt;
recordingContext->audioFrame->sample_rate = recordingContext->audioStream->codec->sample_rate;
result = libffmpeg::av_frame_get_buffer(recordingContext->audioFrame, 0);
if (result < 0)
{
LOG(ERROR) << "Coudln't initialize the output audio frame buffer";
return false;
}
// some formats want video_stream headers to be separate
if (!strcmp(recordingContext->formatContext->oformat->name, "mp4") || !strcmp(recordingContext->formatContext->oformat->name, "mov") || !strcmp(recordingContext->formatContext->oformat->name, "3gp"))
{
recordingContext->audioStream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
// open the ouput file
if (!(recordingContext->formatContext->oformat->flags & AVFMT_NOFILE))
{
result = libffmpeg::avio_open(&recordingContext->formatContext->pb, recordingContext->formatContext->filename, AVIO_FLAG_WRITE);
if (result < 0)
{
LOGINT_WITH_MESSAGE(ERROR, result, "Couldn't open the output file");
return false;
}
}
// write the stream headers
result = libffmpeg::avformat_write_header(recordingContext->formatContext, NULL);
if (result < 0)
{
LOGINT_WITH_MESSAGE(ERROR, result, "Couldn't write the headers to the file");
return false;
}
return true;
}
static bool FinalizeRecordingContext(RecordingContext* recordingContext)
{
int result = 0;
// write the trailing information
if (recordingContext->formatContext->pb)
{
result = libffmpeg::av_write_trailer(recordingContext->formatContext);
if (result < 0)
{
LOGINT_WITH_MESSAGE(ERROR, result, "Couldn't write the trailer information");
return false;
}
}
// close all the codes
for (int i = 0; i < (int)recordingContext->formatContext->nb_streams; i++)
{
result = libffmpeg::avcodec_close(recordingContext->formatContext->streams[i]->codec);
if (result < 0)
{
LOGINT_WITH_MESSAGE(ERROR, result, "Couldn't close the codec");
return false;
}
}
// close the output file
if (recordingContext->formatContext->pb)
{
if (!(recordingContext->formatContext->oformat->flags & AVFMT_NOFILE))
{
result = libffmpeg::avio_close(recordingContext->formatContext->pb);
if (result < 0)
{
LOGINT_WITH_MESSAGE(ERROR, result, "Couldn't close the output file");
return false;
}
}
}
// free the format context and all of its data
libffmpeg::avformat_free_context(recordingContext->formatContext);
recordingContext->formatContext = NULL;
recordingContext->audioStream = NULL;
if (recordingContext->audioFrame)
{
libffmpeg::av_frame_free(&recordingContext->audioFrame);
recordingContext->audioFrame = NULL;
}
return true;
}
int TestRecording::Test()
{
PaError result = paNoError;
result = Pa_Initialize();
if (result != paNoError) LOGINT_WITH_MESSAGE(ERROR, result, "Error initializing audio device framework");
RecordingContext recordingContext;
if (!InitializeRecordingContext(&recordingContext))
{
LOG(ERROR) << "Couldn't start recording file";
return 0;
}
auto defaultDevice = Pa_GetDefaultInputDevice();
auto deviceInfo = Pa_GetDeviceInfo(defaultDevice);
PaStreamParameters inputParameters;
inputParameters.device = defaultDevice;
inputParameters.channelCount = 2;
inputParameters.sampleFormat = paFloat32;
inputParameters.suggestedLatency = deviceInfo->defaultLowInputLatency;
inputParameters.hostApiSpecificStreamInfo = NULL;
PaStream* stream = NULL;
result = Pa_OpenStream(
&stream,
&inputParameters,
NULL,
48000,
1024,
paClipOff,
AudioRecordCallback,
&recordingContext);
if (result != paNoError)LOGINT_WITH_MESSAGE(ERROR, result, "Couldn't open the audio stream");
result = Pa_StartStream(stream);
if (result != paNoError)LOGINT_WITH_MESSAGE(ERROR, result, "Couldn't start the audio stream");
Sleep(1000 * 5);
result = Pa_StopStream(stream);
if (result != paNoError)LOGINT_WITH_MESSAGE(ERROR, result, "Couldn't stop the audio stream");
if (!FinalizeRecordingContext(&recordingContext)) LOG(ERROR) << "Couldn't stop recording file";
result = Pa_CloseStream(stream);
if (result != paNoError)LOGINT_WITH_MESSAGE(ERROR, result, "Couldn't stop the audio stream");
return 0;
}
#包括“stdafx.h”
#包括“TestRecording.h”
#包括“libffmpeg.h”
TestRecording::TestRecording()
{
}
TestRecording::~TestRecording()
{
}
结构记录上下文
{
RecordingContext()
{
formatContext=NULL;
audioStream=NULL;
audioFrame=NULL;
AudioFrameNumber=0;
}
libffmpeg::AVFormatContext*formatContext;
libffmpeg::AVStream*音频流;
libffmpeg::AVFrame*音频帧;
int音频帧编号;
};
静态int AudioRecordCallback(常量void*inputBuffer,void*outputBuffer,
未签名的长帧缓冲,
const Pastream CallbackTimeInfo*timeInfo,
PaStreamCallbackFlags状态标志,
void*用户数据)
{
RecordingContext*RecordingContext=(RecordingContext*)用户数据;
libffmpeg::avcodec\u fill\u audio\u frame(录制上下文->audioFrame,
录制上下文->音频帧->频道,
录制上下文->音频流->编解码器->示例,
静态_转换(输入缓冲区),
(framesPerBuffer*sizeof(float)*录制上下文->音频帧->频道),
0);
libffmpeg::AVPacket-pkt;
libffmpeg::av_init_数据包(&pkt);
pkt.data=NULL;
pkt.size=0;
int-gotpack;
int result=avcodec\u encode\u audio2(recordingContext->audioStream->codec和pkt,recordingContext->audioFrame和gotpacket);
如果(结果<0)
{
使用消息登录(错误,结果,“无法将音频帧编码到acc”);
返回继续;
}
如果(数据包)
{
pkt.stream_index=recordingContext->audioStream->index;
recordingContext->AudioFrameNumber++;
//此编解码器不需要位流过滤器,只需将其发送到muxer!
结果=libffmpeg::av_write_frame(recordingContext->formatContext,&pkt);
如果(结果<0)
{
日志(错误)formatContext,NULL,NULL,“C:\\Users\\Paul\\Desktop\\test.mp4”);
如果(结果<0)
{
使用消息登录(错误,结果,“无法创建输出格式上下文”);
返回false;
}
libffmpeg::AVCodec*音频编解码器;
audioCodec=libffmpeg::avcodec\u find\u编码器(libffmpeg::AV\u CODEC\u ID\u AAC);
如果(音频编解码器==NULL)
{
日志(错误)audioStream=libffmpeg::avformat_new_流(recordingContext->formatContext,audioCodec);
如果(!recordingContext->audioStream)
{
日志(错误)音频流->编解码器->比特率=64000;
录制上下文->音频流->编解码器->示例\u fmt=libffmpeg::AV\u示例\u fmt\u FLTP;
录制上下文->音频流->编解码器->采样率=48000;
录制上下文->音频流->编解码器->频道布局=AV\U频道布局\U立体声;
recordingContext->audioStream->codec->channels=libffmpeg::av\u get\u channel\u layout\u nb\u channels(recordingContext->audioStream->codec->channel\u layout);
录制上下文->音频流->编解码器->比特率=录制上下文->音频流->编解码器->比特率;
录制上下文->音频流->编解码器->格式=录制上下文->音频流->编解码器->示例;
recordingContext->audioStream->codepar->sample\u rate=recordingContext->audioStream->codec->sample\u rate;
recordingContext->audioStream->CodePar->channel_layout=recordingContext->audioStream->codec->channel_layout;
录制上下文->音频流->编解码器->频道=录制上下文->音频流->编解码器->频道;
结果=libffmpeg::avcodec_open2(录制上下文->音频流->编解码器,音频编解码器,空);
如果(结果<0)
{
使用消息登录(错误,结果,“无法打开音频编解码器”);
返回false;
}
//创建新帧以存储音频样本
recordingContext->audioFrame=libffmpeg::av_frame_alloc();
如果(!recordingContext->audioFrame)
{
记录(错误)音频帧->nb\U样本=录制上下文->音频流->编解码器->帧大小;
录制上下文->音频帧->频道布局=录制上下文->音频流->编解码器->频道布局;
录制上下文->音频帧->频道=录制上下文->音频流->编解码器->频道;
recordingContext->audioFrame->format=recordingContext->audioStream->codec->sample\u fmt;
录制上下文->音频帧->采样率=录制上下文->音频流->编解码器->采样率;
结果=libffmpeg::av_frame_get_buffer(recordingContext->audioFrame,0);
如果(结果<0)
{
日志(错误)formatContext->oformat->name,“mp4”)| |!strcmp(recordingContext->formatContext->oformat->name,“mov”)| |!strcmp(recordingContext->formatContext->oformat->name,“3gp”))
{
recordingContext->audioStream->codec->flags |=codec_FLAG_GLOBAL_头;
}
//打开输出文件
if(!(recordingContext->formatContext->oformat->flags&AVFMT_NOFILE))
{
结果=libffmpeg::avio_打开(&recordingContext->formatContext->pb,recordingContext->formatContext->filename,avio_标志_写入);
如果(结果<0)
{
使用_消息登录_(错误,结果,“无法打开输出文件”);
返回false;
}
}
//编写流标题
结果=libffmpeg::avformat\u write\u头(recordingContext->formatContext,NULL);
如果(结果<0)
{
使用消息登录(错误,结果,“无法将标题写入文件”);
返回false;
}
返回true;
}
静态bool FinalizeRecordingContext(RecordingContext*RecordingContext)
{
int结果=0;
//写出尾随信息
如果(recordingContext->formatContext->pb)
{
结果=libffmpeg::av_write_trail(recordingContext->formatContext);
如果(结果<0)
{
使用消息登录(错误,结果,“无法写入拖车信息”);
返回false;
}
}
//关闭所有代码
对于(int i=0;i<(int)recordingContext->formatContext->nb_streams;i++)