FFMPEG AAC编码器问题

时间:2018-11-27 03:21:20

标签: audio encoding ffmpeg alsa aac

我正在尝试捕获和编码音频数据,我正在使用 FFMPEG AAC和要捕获的PCM数据我使用的是ALSA,在我的情况下,捕获部分正在工作,但是AAC编码器不工作。

我正在尝试使用以下文件播放test.aac文件

ffplay test.aac

但是它包含很多噪音。

aac编码器的附加代码:

#include "AudioEncoder.h"

void* AudioEncoder::run(void *ctx)
{
    return ((AudioEncoder *)ctx)->execute();
}

static int frameCount = 0;

void* AudioEncoder::execute(void)
{
    float buf[size], *temp;
    int totalSize = 0;
    int fd = open("in.pcm", O_CREAT| O_RDWR, 0666);
    int frameSize = 128 * snd_pcm_format_width(SND_PCM_FORMAT_FLOAT) / 8 * 2;
    av_new_packet(&pkt,size);
    cout << size << endl;
    while (!Main::stopThread)
    {
        temp = (Main::fbAudio)->dequeue();
        memcpy(buf + totalSize, temp, frameSize);
        write(fd, temp, frameSize); // Can play in.pcm with no noise in it.
        totalSize += frameSize;
        delete temp;
        if (totalSize >= size)
        {
            totalSize = 0;
            //frame_buf = (uint8_t *) buf;
            pFrame->data[0] = (uint8_t *)buf;  //PCM Data

            pFrame->pts=frameCount;
            frameCount++;
            got_frame=0;
            //Encode
            ret = avcodec_encode_audio2(pCodecCtx, &pkt,pFrame, &got_frame);
            if(ret < 0){
                cerr << "Failed to encode!\n";
                return NULL;
            }
            if (got_frame==1){
                printf("Succeed to encode 1 frame! \tsize:%5d\n",pkt.size);
                pkt.stream_index = audio_st->index;
#ifdef DUMP_TEST
                ret = av_write_frame(pFormatCtx, &pkt);
#endif
                av_free_packet(&pkt);
            }
            //memset(buf, 0, sizeof(float)*size);
        }
        //delete temp;
        //if (buf.size() >= m_audio_output_decoder_ctx->frame_size)
        /* encode the audio*/
    }
        close(fd);
    Main::stopThread = true;
    return NULL;
}

int AudioEncoder::flush_encoder(AVFormatContext *fmt_ctx,unsigned int stream_index){
    int ret;
    int got_frame;
    AVPacket enc_pkt;
    if (!(fmt_ctx->streams[stream_index]->codec->codec->capabilities &
        CODEC_CAP_DELAY))
        return 0;
    while (1) {
        enc_pkt.data = NULL;
        enc_pkt.size = 0;
        av_init_packet(&enc_pkt);
        ret = avcodec_encode_audio2 (fmt_ctx->streams[stream_index]->codec, &enc_pkt,
            NULL, &got_frame);
        av_frame_free(NULL);
        if (ret < 0)
            break;
        if (!got_frame){
            ret=0;
            break;
        }
        printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n",enc_pkt.size);
        /* mux encoded frame */
#ifdef DUMP_TEST
        ret = av_write_frame(fmt_ctx, &enc_pkt);
        if (ret < 0)
            break;
#endif
    }
    return ret;
}

void AudioEncoder::start(void)
{
    pthread_t encoder;
    pthread_create(&encoder, NULL, &AudioEncoder::run, this);
}

AudioEncoder::AudioEncoder() : out_file("test.aac")
{
    got_frame = 0;
    ret = 0;
    size = 0;
    av_register_all();
    avcodec_register_all();
    //Method 1.
    pFormatCtx = avformat_alloc_context();
    fmt = av_guess_format(NULL, out_file, NULL);
    pFormatCtx->oformat = fmt;

#ifdef DUMP_TEST
    if (avio_open(&pFormatCtx->pb,out_file, AVIO_FLAG_READ_WRITE) < 0){
        cerr << "Failed to open output file!\n";
        return;
    }
#endif
    audio_st = avformat_new_stream(pFormatCtx, 0);
    if (audio_st==NULL){
        return;
    }
    pCodecCtx = audio_st->codec;
    pCodecCtx->codec_id = fmt->audio_codec;
    pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
    pCodecCtx->sample_fmt = AV_SAMPLE_FMT_FLTP;
    pCodecCtx->sample_rate= 8000;
    pCodecCtx->channel_layout=AV_CH_LAYOUT_STEREO;
    pCodecCtx->channels = av_get_channel_layout_nb_channels(pCodecCtx->channel_layout);
//    pCodecCtx->bit_rate = 64000;

#ifdef DUMP_TEST
    //Show some information
    av_dump_format(pFormatCtx, 0, out_file, 1);
#endif

    pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
    if (!pCodec){
        printf("Can not find encoder!\n");
        return;
    }
    if (avcodec_open2(pCodecCtx, pCodec,NULL) < 0){
        printf("Failed to open encoder!\n");
        return;
    }
    pFrame = av_frame_alloc();
    pFrame->nb_samples= pCodecCtx->frame_size;
    pFrame->format= pCodecCtx->sample_fmt;

    size = av_samples_get_buffer_size(NULL, pCodecCtx->channels,pCodecCtx->frame_size,pCodecCtx->sample_fmt, 1);
    frame_buf = (uint8_t *)av_malloc(size);
    avcodec_fill_audio_frame(pFrame, pCodecCtx->channels, pCodecCtx->sample_fmt,(const uint8_t*)frame_buf, size, 1);
    //Write Header
#ifdef DUMP_TEST
    avformat_write_header(pFormatCtx,NULL);
#endif
}

AudioEncoder::~AudioEncoder()
{
    //Flush Encoder
    ret = flush_encoder(pFormatCtx,0);
    if (ret < 0) {
        cerr << "Flushing encoder failed\n";
        return;
    }

#ifdef DUMP_TEST
    //Write Trailer
    av_write_trailer(pFormatCtx);
#endif
    //Clean
    if (audio_st){
        avcodec_close(audio_st->codec);
        av_free(pFrame);
        av_free(frame_buf);
    }
    avio_close(pFormatCtx->pb);
    avformat_free_context(pFormatCtx);
}

在这里,请忽略DUMP_TEST标志,我已经启用了它。

有人可以告诉我问题是什么吗?

谢谢, 哈西尔

1 个答案:

答案 0 :(得分:1)

通过将缓冲区从ALSA正确传递到AAC编码器,我能够解决此问题。

此处AAC期望缓冲区大小为4096字节,但是从双端队列中我传递了1024个字节,这会导致问题,我也将音频通道更新为MONO,以代替STEREO。附上我的工作代码段以获取更多信息:

#include "AudioEncoder.h"

void* AudioEncoder::run(void *ctx)
{
    return ((AudioEncoder *)ctx)->execute();
}

static int frameCount = 0;

void* AudioEncoder::execute(void)
{
    float *temp;
#ifdef DUMP_TEST
    int fd = open("in.pcm", O_CREAT| O_RDWR, 0666);
#endif
    int frameSize = 1024 * snd_pcm_format_width(SND_PCM_FORMAT_FLOAT) / 8 * 1;
    av_new_packet(&pkt,size);
    while (!Main::stopThread)
    {
        temp = (Main::fbAudio)->dequeue();
        frame_buf = (uint8_t *) temp;
        pFrame->data[0] = frame_buf;
        pFrame->pts=frameCount*100;
        frameCount++;
        got_frame=0;
        //Encode
        ret = avcodec_encode_audio2(pCodecCtx, &pkt,pFrame, &got_frame);
        if(ret < 0){
            cerr << "Failed to encode!\n";
            return NULL;
        }
        if (got_frame==1){
            cout << "Encoded frame\n";
            pkt.stream_index = audio_st->index;
#ifdef DUMP_TEST
            write(fd, temp, frameSize);
            ret = av_interleaved_write_frame(pFormatCtx, &pkt);
#endif
            av_free_packet(&pkt);
        }
        delete temp;
    }
#ifdef DUMP_TEST
    close(fd);
#endif
    Main::stopThread = true;
    return NULL;
}

int AudioEncoder::flush_encoder(AVFormatContext *fmt_ctx,unsigned int stream_index){
    int ret;
    int got_frame;
    AVPacket enc_pkt;
    if (!(fmt_ctx->streams[stream_index]->codec->codec->capabilities &
        CODEC_CAP_DELAY))
        return 0;
    while (1) {
        enc_pkt.data = NULL;
        enc_pkt.size = 0;
        av_init_packet(&enc_pkt);
        ret = avcodec_encode_audio2 (fmt_ctx->streams[stream_index]->codec, &enc_pkt,
            NULL, &got_frame);
        av_frame_free(NULL);
        if (ret < 0)
            break;
        if (!got_frame){
            ret=0;
            break;
        }
        printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n",enc_pkt.size);
        /* mux encoded frame */
#ifdef DUMP_TEST
        ret = av_write_frame(fmt_ctx, &enc_pkt);
        if (ret < 0)
            break;
#endif
    }
    return ret;
}

void AudioEncoder::start(void)
{
    pthread_t encoder;
    pthread_create(&encoder, NULL, &AudioEncoder::run, this);
}

AudioEncoder::AudioEncoder() : out_file("test.aac")
{
    got_frame = 0;
    ret = 0;
    size = 0;
    av_register_all();
    avcodec_register_all();
    //Method 1.
    pFormatCtx = avformat_alloc_context();
    fmt = av_guess_format(NULL, out_file, NULL);
    pFormatCtx->oformat = fmt;

#ifdef DUMP_TEST
    if (avio_open(&pFormatCtx->pb,out_file, AVIO_FLAG_READ_WRITE) < 0){
        cerr << "Failed to open output file!\n";
        return;
    }
#endif
    audio_st = avformat_new_stream(pFormatCtx, 0);
    if (audio_st==NULL){
        return;
    }
    pCodecCtx = audio_st->codec;
    pCodecCtx->codec_id = fmt->audio_codec;
    pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
    pCodecCtx->sample_fmt = AV_SAMPLE_FMT_FLTP;
    pCodecCtx->sample_rate= 8000;
    pCodecCtx->channel_layout=AV_CH_LAYOUT_MONO;
    pCodecCtx->channels = av_get_channel_layout_nb_channels(pCodecCtx->channel_layout);
    pCodecCtx->bit_rate = 64000;

#ifdef DUMP_TEST
    //Show some information
    av_dump_format(pFormatCtx, 0, out_file, 1);
#endif

    pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
    if (!pCodec){
        printf("Can not find encoder!\n");
        return;
    }
    if (avcodec_open2(pCodecCtx, pCodec,NULL) < 0){
        printf("Failed to open encoder!\n");
        return;
    }
    pFrame = av_frame_alloc();
    pFrame->nb_samples= pCodecCtx->frame_size;
    pFrame->format= pCodecCtx->sample_fmt;

    size = av_samples_get_buffer_size(NULL, pCodecCtx->channels,pCodecCtx->frame_size,pCodecCtx->sample_fmt, 1);
    frame_buf = (uint8_t *)av_malloc(size);
    avcodec_fill_audio_frame(pFrame, pCodecCtx->channels, pCodecCtx->sample_fmt,(const uint8_t*)frame_buf, size, 1);
    //Write Header
#ifdef DUMP_TEST
    avformat_write_header(pFormatCtx,NULL);
#endif
}

AudioEncoder::~AudioEncoder()
{
    //Flush Encoder
    ret = flush_encoder(pFormatCtx,0);
    if (ret < 0) {
        cerr << "Flushing encoder failed\n";
        return;
    }

#ifdef DUMP_TEST
    //Write Trailer
    av_write_trailer(pFormatCtx);
#endif
    //Clean
    if (audio_st){
        avcodec_close(audio_st->codec);
        av_free(pFrame);
        av_free(frame_buf);
    }
    avio_close(pFormatCtx->pb);
    avformat_free_context(pFormatCtx);
}