【FFmpeg】PCM编码成AAC

使用FFmpeg把PCM裸数据编码成AAC音频流,具体步骤跟YUV编码成H264差不多。

1、命令行

ffmpeg -f s16le -ar 44100 -ac 2 -i bb1.pcm output.aac

-f PCM数据为s16le

-ar 采样率为44100

-ac 通道数为2

这样就通过命令把PCM数据编码成AAC了。

2、使用API编码

FFmpeg内部AAC格式只支持AV_SAMPLE_FMT_FLTP格式的PCM,由于我们的PCM数据是s16le的,因此我们需要把s16le格式转换成fltp格式再进行编码。我们可以在AVCodec结构体中的sample_fmts字段中判断编码器是否支持你的格式。

  • 初始化输出文件上下文

    int avformat_alloc_output_context2(AVFormatContext **ctx, ff_const59 AVOutputFormat *oformat,
                                       const char *format_name, const char *filename);

    ctx 输出文件的上下文

    oformat 输出文件的AVOutputFormat,传NULL,FFmpeg会根据filename的格式初始化oformat

    format_name 输出文件的格式, 传NULL,FFmpeg会根据filename的格式初始化format_name

    filename 输出文件路径

  • 初始化编码器上下文

    dec = avcodec_find_encoder(ofmt_ctx->oformat->audio_codec);
    if (!dec) {
        printf("avcodec_find_encoder fail \n");
        goto __FAIL;
    }
    dec_ctx = avcodec_alloc_context3(dec);
    dec_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
    if (!check_sample_fmt(dec, dec_ctx->sample_fmt)) {
        fprintf(stderr, "Encoder does not support sample format %s",
                av_get_sample_fmt_name(dec_ctx->sample_fmt));
        goto __FAIL;
    }
    dec_ctx->channel_layout = select_channel_layout(dec);
    dec_ctx->channels = av_get_channel_layout_nb_channels(dec_ctx->channel_layout);
    dec_ctx->sample_rate = select_sample_rate(dec);
    dec_ctx->bit_rate = 64000;
    ret = avcodec_open2(dec_ctx, dec, NULL);

    FFmpeg内部AAC音频流只支持fltp格式的PCM,使用check_sample_fmt函数可以检测编码器是否支持AV_SAMPLE_FMT_FLTP,通过select_channel_layout函数选择最佳的音频通道布局,通过select_sample_rate函数选择最佳的采样率。

    检测是否支持AVSampleFormat

    static int check_sample_fmt(const AVCodec *codec, enum AVSampleFormat sample_fmt)
    {
        const enum AVSampleFormat *p = codec->sample_fmts;
    ​
        while (*p != AV_SAMPLE_FMT_NONE) {
            if (*p == sample_fmt)
                return 1;
            p++;
        }
        return 0;
    }

    选择最佳采样率

    static int select_sample_rate(const AVCodec *codec)
    {
        const int *p;
        int best_samplerate = 0;
    ​
        if (!codec->supported_samplerates)
            return 44100;
    ​
        p = codec->supported_samplerates;
        while (*p) {
            if (!best_samplerate || abs(44100 - *p) < abs(44100 - best_samplerate))
                best_samplerate = *p;
            p++;
        }
        return best_samplerate;
    }

    选择最佳通道布局

    static int select_channel_layout(const AVCodec *codec)
    {
        const uint64_t *p;
        uint64_t best_ch_layout = 0;
        int best_nb_channels   = 0;
    ​
        if (!codec->channel_layouts)
            return AV_CH_LAYOUT_STEREO;
    ​
        p = codec->channel_layouts;
        while (*p) {
            int nb_channels = av_get_channel_layout_nb_channels(*p);
    ​
            if (nb_channels > best_nb_channels) {
                best_ch_layout    = *p;
                best_nb_channels = nb_chann
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值