将音频样本转换为 AVFrame FFmpeg & C++

问题描述

我真的需要帮助来纠正我目前正在使用的方法。该方法应将样本转换并写入ac3文件

输入样本为 AV_SAMPLE_FMT_FLT 格式的 BYTE*

对于编码器,样本必须具有 AV_SAMPLE_FMT_FLTP 格式

a1.xyz()

这里是缓冲包的上下文重采样设置和计算:

bool AddAudioSample(AVFormatContext * pformatContext,AVStream * pStream,BYTE * audiodata,uint32_t sampleCount,uint64_t devicets)
{
    AVCodecContext * pCodecCxt = NULL;
    bool res = true;

    pCodecCxt = pStream->codec;

    AVFrame*  pFLTAudioFrame = NULL;
    pFLTAudioFrame = av_frame_alloc();

    AVFrame*  pFLTPAudioFrame = NULL;
    pFLTPAudioFrame = av_frame_alloc();

    ProcessData(pFLTAudioFrame,pFLTPAudioFrame,(uint8_t *)audiodata,sampleCount,devicets);

    swr_convert(pSmplConvertCtx,pFLTPAudioFrame->data,pFLTPAudioFrame->nb_samples,(const uint8_t **)pFLTAudioFrame->data,pFLTAudioFrame->nb_samples);

    AVPacket pkt;
    av_init_packet(&pkt);

    pkt.flags |= AV_PKT_FLAG_KEY;
    pkt.stream_index = pStream->index;
    pkt.data = pAudioEncodeBuffer;
    pkt.size = pFLTPAudioFrame->pkt_size;

    int gotOutput = 0;
    auto ret = avcodec_encode_audio2(pCodecCxt,&pkt,&gotOutput);
    if (ret < 0)
    {
        exit(1);
    }
    if (gotOutput)
    {
        pkt.pts = av_rescale_q(pCodecCxt->coded_frame->pts,pCodecCxt->time_base,pStream->time_base);
        ret = av_interleaved_write_frame(pformatContext,&pkt);
        if (ret < 0)
        {
            exit(1);
        }
    }

    return res;
}

void ProcessData(AVFrame *inputframe,AVFrame *outputFrame,uint8_t* data,uint32_t sample_count,uint64_t device_ts)
{
    inputframe->nb_samples = sample_count;
    inputframe->format = AV_SAMPLE_FMT_FLT;
    inputframe->sample_rate = mWFX->nSamplesPerSec;
    inputframe->channels = mWFX->nChannels;
    inputframe->pkt_size = sample_count*mWFX->nBlockAlign;

    av_samples_fill_arrays(inputframe->data,inputframe->linesize,data,mWFX->nChannels,sample_count,AV_SAMPLE_FMT_FLT,1);

    outputFrame->nb_samples = inputframe->nb_samples;
    outputFrame->format = AV_SAMPLE_FMT_FLTP;
    outputFrame->sample_rate = inputframe->sample_rate;
    outputFrame->channels = inputframe->channels;
    outputFrame->pkt_size = sample_count*mWFX->nBlockAlign;

    av_samples_fill_arrays(outputFrame->data,outputFrame->linesize,pAudioEncodeBuffer,AV_SAMPLE_FMT_FLTP,1);
}

解决方法

这里是进程函数:

process_data(AVFrame *frame,uint8_t* data,uint32_t sample_count,uint64_t device_ts)
{
    int sample_size = _bit_per_sample / 8 * _channel_num;

    //wasapi time unit is 100ns,so time base is NS_PER_SEC
    frame->pts = _use_device_ts ? device_ts * 100 : av_gettime_relative();

    if(_use_device_ts == false)
        frame->pts -= (int64_t)sample_count * NS_PER_SEC / (int64_t)_sample_rate;

    frame->pkt_dts = frame->pts;
    frame->nb_samples = sample_count;
    frame->format = _fmt;
    frame->sample_rate = _sample_rate;
    frame->channels = _channel_num;
    frame->pkt_size = sample_count*sample_size;

    av_samples_fill_arrays(frame->data,frame->linesize,data,_channel_num,sample_count,_fmt,1);

    if (_on_data) _on_data(frame,_cb_extra_index);
}

更多详情,可以关注 https://github.com/peilinok/screen-recorder