Проблема с кодировщиком FFMPEG AAC - PullRequest
0 голосов
/ 27 ноября 2018

Я пытаюсь захватить и кодировать аудиоданные, я кодирую аудио с использованием 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, я уже включил его.

Может кто-нибудь сказать мне, в чем проблема?

Спасибо, Harshil

1 Ответ

0 голосов
/ 28 ноября 2018

Я могу решить эту проблему, правильно передавая буфер из ALSA в кодировщик AAC.

Здесь AAC ожидает размер буфера 4096 байт, но из deque я передаю 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);
}
...