FFMPEG AAC编码使音频的音调降低

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()

我构建了一个示例应用程序,将AAC(来自PortAudio)编码到MP4容器中(无视频流)

产生的音频音调较低

#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++)