ffmpeg把pcm编码为aac

version

#define LIBSWRESAMPLE_VERSION_MAJOR 2

#define LIBSWRESAMPLE_VERSION_MINOR 9

#define LIBSWRESAMPLE_VERSION_MICRO 100

#define LIBAVCODEC_VERSION_MINOR 31

#define LIBAVCODEC_VERSION_MICRO 102

code

void CFfmpegOps::EncodePCMToAAC(const char *pcm_file, const char *aac_file)
{
    AVFormatContext *fmt_ctx = nullptr;
    const AVOutputFormat *out_fmt = nullptr;
    int ret = -1;
    AVStream *avstream = nullptr;
    const AVCodec *codec = nullptr;
    AVCodecContext *codec_ctx = nullptr;
    AVFrame *avframe = nullptr;       // pcm file对应的avframe
    AVFrame *codec_avframe = nullptr; // 编码器接收的avframe
    AVPacket *avpacket = nullptr;
    int frame_data_bytes = 0;
    FILE *in_fp = nullptr;
    size_t n = 0;
    int64_t pts = 0;
    struct SwrContext *swr_ctx = nullptr; // 音频帧转换器
    AVChannelLayout src_channel_layout;
    AVChannelLayout dest_channel_layout;

    codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
    if (!codec)
    {
        printf("avcodec_find_encoder error\n");
        goto END;
    }

    codec_ctx = avcodec_alloc_context3(codec);
    if (!codec_ctx)
    {
        printf("avcodec_alloc_context3 error\n");
        goto END;
    }
    codec_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP; // 编码器的接受的采样格式
    codec_ctx->sample_rate = 44100;
    codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
    codec_ctx->channels = av_get_channel_layout_nb_channels(codec_ctx->channel_layout);
    codec_ctx->bit_rate = 128000;
    codec_ctx->time_base.num = 1;
    codec_ctx->time_base.den = codec_ctx->sample_rate;

    ret = avcodec_open2(codec_ctx, codec, nullptr);
    if (ret < 0)
    {
        printf("avcodec_open2 error(%s)\n", GetFfmpegERR(ret));
        goto END;
    }
    printf("codec_ctx->frame_size:%d\n", codec_ctx->frame_size);

    codec_avframe = av_frame_alloc();
    if (!codec_avframe)
    {
        printf("av_frame_alloc error\n");
        goto END;
    }
    codec_avframe->format = codec_ctx->sample_fmt; // pcm的采样格式
    codec_avframe->sample_rate = codec_ctx->sample_rate;
    codec_avframe->channel_layout = codec_ctx->channel_layout;
    codec_avframe->channels = av_get_channel_layout_nb_channels(codec_avframe->channel_layout);
    codec_avframe->nb_samples = codec_ctx->frame_size;

    ret = av_frame_get_buffer(codec_avframe, 0);
    if (ret < 0)
    {
        printf("av_frame_get_buffer error(%s)\n", GetFfmpegERR(ret));
        goto END;
    }

    avframe = av_frame_alloc();
    if (!avframe)
    {
        printf("av_frame_alloc error\n");
        goto END;
    }
    avframe->format = AV_SAMPLE_FMT_FLT; // pcm的采样格式
    avframe->sample_rate = 44100;
    avframe->channel_layout = AV_CH_LAYOUT_STEREO;
    avframe->channels = av_get_channel_layout_nb_channels(avframe->channel_layout);
    avframe->nb_samples = 1024;

    ret = av_samples_get_buffer_size(nullptr,
                                     avframe->channels,
                                     avframe->nb_samples,
                                     (AVSampleFormat)(avframe->format),
                                     1);
    if (ret < 0)
    {
        printf("av_samples_get_buffer_size error(%s)\n", GetFfmpegERR(ret));
        goto END;
    }

    frame_data_bytes = av_get_bytes_per_sample((AVSampleFormat)(avframe->format)) * av_get_channel_layout_nb_channels(avframe->channel_layout) * avframe->nb_samples;
    if (frame_data_bytes != ret)
    {
        printf("frame_data_bytes != ret\n");
        goto END;
    }

    ret = av_frame_get_buffer(avframe, 0);
    if (ret < 0)
    {
        printf("av_frame_get_buffer error(%s)\n", GetFfmpegERR(ret));
        goto END;
    }

    avpacket = av_packet_alloc();
    if (!avpacket)
    {
        printf("av_packet_alloc error\n");
        goto END;
    }

    ret = avformat_alloc_output_context2(&fmt_ctx, nullptr, nullptr, aac_file);
    if (ret < 0)
    {
        printf("avformat_alloc_output_context2 error(%s)\n", GetFfmpegERR(ret));
        goto END;
    }
    out_fmt = fmt_ctx->oformat; // name:adts    long_name:ADTS AAC

    avstream = avformat_new_stream(fmt_ctx, codec);
    if (!avstream)
    {
        printf("avformat_new_stream error\n");
        goto END;
    }

    ret = avcodec_parameters_from_context(avstream->codecpar, codec_ctx);
    if (ret < 0)
    {
        printf("avcodec_parameters_from_context error(%s)\n", GetFfmpegERR(ret));
        goto END;
    }

    if (!(fmt_ctx->flags & AVFMT_FLAG_NOFILLIN))
    {
        ret = avio_open(&(fmt_ctx->pb), aac_file, AVIO_FLAG_WRITE);
        if (ret < 0)
        {
            printf("avio_open error(%s)\n", GetFfmpegERR(ret));
            goto END;
        }
    }

    in_fp = fopen(pcm_file, "rb");
    if (!in_fp)
    {
        printf("fopen error\n");
        goto END;
    }

    // int av_channel_layout_from_mask(AVChannelLayout *channel_layout, uint64_t mask);
    ret = av_channel_layout_from_mask(&src_channel_layout, avframe->channel_layout);
    if (ret < 0)
    {
        printf("av_channel_layout_from_mask error(%s)\n", GetFfmpegERR(ret));
        goto END;
    }

    ret = av_channel_layout_from_mask(&dest_channel_layout, codec_avframe->channel_layout);
    if (ret < 0)
    {
        printf("av_channel_layout_from_mask error(%s)\n", GetFfmpegERR(ret));
        goto END;
    }

    // int swr_alloc_set_opts2(struct SwrContext **ps,
    //                     const AVChannelLayout *out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
    //                     const AVChannelLayout *in_ch_layout, enum AVSampleFormat  in_sample_fmt, int  in_sample_rate,
    //                     int log_offset, void *log_ctx);

    ret = swr_alloc_set_opts2(&swr_ctx,
                              &dest_channel_layout, (AVSampleFormat)(codec_avframe->format), codec_avframe->sample_rate,
                              &src_channel_layout, (AVSampleFormat)(avframe->format), avframe->sample_rate,
                              0, nullptr);
    if (ret < 0)
    {
        printf("swr_alloc_set_opts2 error(%s)\n", GetFfmpegERR(ret));
        goto END;
    }

    ret = avformat_write_header(fmt_ctx, nullptr);
    if (ret < 0)
    {
        printf("avformat_write_header error(%s)\n", GetFfmpegERR(ret));
        goto END;
    }

    while (1)
    {
        if (feof(in_fp))
        {
            printf("feof\n");
            break;
        }

        if (av_sample_fmt_is_planar((AVSampleFormat)(avframe->format)))
        {
            n = fread(avframe->data[0], sizeof(uint8_t), frame_data_bytes / 2, in_fp);
            if ((int)n != frame_data_bytes / 2)
            {
                printf("n != frame_data_bytes / 2\n");
            }

            n = fread(avframe->data[1], sizeof(uint8_t), frame_data_bytes / 2, in_fp);
            if ((int)n != frame_data_bytes / 2)
            {
                printf("n != frame_data_bytes / 2\n");
            }
        }
        else
        {
            n = fread(avframe->data[0], sizeof(uint8_t), frame_data_bytes, in_fp);
            if ((int)n != frame_data_bytes)
            {
                printf("n != frame_data_bytes\n");
            }
        }

        ret = swr_convert_frame(swr_ctx, codec_avframe, avframe);
        if (ret < 0)
        {
            printf("swr_convert_frame error(%s)\n", GetFfmpegERR(ret));
            goto END;
        }

        codec_avframe->pts = pts;
        ++pts;

        ret = avcodec_send_frame(codec_ctx, codec_avframe);
        if (ret < 0)
        {
            if (ret == AVERROR(EAGAIN))
            {
                printf("read output first\n");
            }
            else
            {
                printf("avcodec_send_frame error(%s)\n", GetFfmpegERR(ret));
                break;
            }
        }

        while (1)
        {
            ret = avcodec_receive_packet(codec_ctx, avpacket);
            if (ret < 0)
            {
                if (ret == AVERROR(EAGAIN))
                {
                    printf("send input first\n");
                    break;
                }
                else
                {
                    printf("avcodec_receive_packet error(%s)\n", GetFfmpegERR(ret));
                    break;
                }
            }

            ret = av_write_frame(fmt_ctx, avpacket);
            if (ret < 0)
            {
                printf("av_write_frame error(%s)\n", GetFfmpegERR(ret));
                av_packet_unref(avpacket);
                goto END;
            }

            av_packet_unref(avpacket);
        }
    }

    ret = avcodec_send_frame(codec_ctx, nullptr);
    while (1)
    {
        ret = avcodec_receive_packet(codec_ctx, avpacket);
        if (ret < 0)
        {
            if (ret == AVERROR(EAGAIN))
            {
                printf("send input first\n");
                break;
            }
            else
            {
                printf("avcodec_receive_packet error(%s)\n", GetFfmpegERR(ret));
                break;
            }
        }

        ret = av_write_frame(fmt_ctx, avpacket);
        if (ret < 0)
        {
            printf("av_write_frame error(%s)\n", GetFfmpegERR(ret));
            av_packet_unref(avpacket);
            goto END;
        }

        av_packet_unref(avpacket);
    }

    ret = av_write_trailer(fmt_ctx);
    if (ret != 0)
    {
        printf("av_write_trailer error(%s)\n", GetFfmpegERR(ret));
        goto END;
    }

END:
    if (swr_ctx)
    {
        swr_free(&swr_ctx);
        swr_ctx = nullptr;
    }
    if (in_fp)
    {
        fclose(in_fp);
        in_fp = nullptr;
    }
    if (avpacket)
    {
        av_packet_free(&avpacket);
        avpacket = nullptr;
    }
    if (codec_avframe)
    {
        av_frame_free(&codec_avframe);
        codec_avframe = nullptr;
    }
    if (avframe)
    {
        av_frame_free(&avframe);
        avframe = nullptr;
    }
    if (codec_ctx)
    {
        avcodec_free_context(&codec_ctx);
        codec_ctx = nullptr;
    }

    if (fmt_ctx)
    {
        if (fmt_ctx->pb)
        {
            avio_close(fmt_ctx->pb);
            fmt_ctx->pb = nullptr;
        }

        avformat_free_context(fmt_ctx);
        fmt_ctx = nullptr;
    }
}

performance

  • 14
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值