将 PCM 数据编码为AAC格式

TOC

1.将mp3文件转换为pcm文件

ffmpeg -i test.mp3 -f s16le test.pcm

2.贴上代码

aac.c

#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswresample/swresample.h>
#include <stdio.h>
#include <stdbool.h>


SwrContext *g_swr_ctx = NULL;


static int audio_resampling_2(AVFrame *dst, const AVFrame *src)
{
    int ret = 0;


    if (!dst || !src)
    {
        av_log(NULL, AV_LOG_ERROR, "frame pointer is null\n");
        return -1;
    }


    //创建swr对象
    if (!g_swr_ctx)
    {
        g_swr_ctx = swr_alloc();
        if (!g_swr_ctx)
        {
            av_log(NULL, AV_LOG_ERROR, "swr contex alloc failed\n");
            return -1;
        }


        printf("in_channel_layout = %d\n", src->channel_layout);
        printf("in_sample_rate = %d\n", src->sample_rate);
        printf("in_format = %d\n", src->format);


        printf("out_channel_layout = %d\n", dst->channel_layout);
        printf("out_sample_rate = %d\n", dst->sample_rate);
        printf("out_format = %d\n", dst->format);
        //设置转换参数
        av_opt_set_int(g_swr_ctx, "in_channel_layout", src->channel_layout, 0);
        av_opt_set_int(g_swr_ctx, "in_sample_rate", src->sample_rate, 0);
        av_opt_set_sample_fmt(g_swr_ctx, "in_sample_fmt", src->format, 0);


        av_opt_set_int(g_swr_ctx, "out_channel_layout", dst->channel_layout, 0);
        av_opt_set_int(g_swr_ctx, "out_sample_rate", dst->sample_rate, 0);
        av_opt_set_sample_fmt(g_swr_ctx, "out_sample_fmt", dst->format, 0);


        //初始化swr对象
        if ((ret = swr_init(g_swr_ctx)) < 0)
        {
            av_log(NULL, AV_LOG_ERROR, "init swr contex failed\n");
            swr_free(&g_swr_ctx);
            return -1;
        }
    }


    //估算输出的采样数
    dst->nb_samples = FFMAX(av_rescale_rnd(swr_get_delay(g_swr_ctx, src->sample_rate) + src->nb_samples,
                                    dst->sample_rate, src->sample_rate, AV_ROUND_UP), 
                            av_rescale_rnd(src->nb_samples, dst->sample_rate, src->sample_rate, AV_ROUND_UP));


    //分配样本空间
    ret = av_samples_alloc(dst->data, &dst->linesize[0], dst->channels,
                          dst->nb_samples, dst->format, 0);
    if (ret < 0)
    {
        av_log(NULL, AV_LOG_ERROR, "samples alloc failed\n");
        swr_free(&g_swr_ctx);
        return -1;
    }


    //进行重采样,并且把缓存的样本flush掉
    ret = swr_convert(g_swr_ctx, dst->data, dst->nb_samples, (const uint8_t **)src->data, src->nb_samples) 
          + swr_convert(g_swr_ctx, dst->data, dst->nb_samples, 0, 0);
    if (ret < 0)
    {
        av_log(NULL, AV_LOG_ERROR, "resample failed\n");
        swr_free(&g_swr_ctx);
        return -1;
    }


    //重新设置输出采样数
    dst->nb_samples = ret;


    return 0;
}




int flush_encoder(AVFormatContext *fmt_ctx, unsigned int stream_index)
{
    int ret = 0;
    int got_frame = 0;
    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);
        if(ret < 0)
        {
            break;
        }
        if(!got_frame)
        {
            ret = 0;
            break;
        }


        ret = av_write_frame(fmt_ctx, &enc_pkt);
        if(ret < 0)
        {
            break;
        }
    }


    return ret;
}


void usage(void)
{
    printf("./aac input_file output_file.aac\n");
}


int main(int argc, char *argv[])
{


    if(argc != 3)
    {
        usage();
        return -1;
    }


    char *input_file = argv[1];
    char *output_file = argv[2];


    AVFormatContext *pFormatCtx = NULL;
    AVOutputFormat *ofmt = NULL;
    AVStream *audio_stream = NULL;
    AVCodecContext *pCodecCtx = NULL;
    AVCodec *pCodec = NULL;


    uint8_t *frame_buf = NULL;
    AVFrame *pFrame = NULL;
    AVPacket pkt;


    int got_frame = 0;
    int ret = 0;
    int size = 0;


    int i = 0;


    FILE *fp = fopen(input_file, "rb");


    av_register_all();
    avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, output_file);
    ofmt = pFormatCtx->oformat;


    if(avio_open(&pFormatCtx->pb, output_file, AVIO_FLAG_READ_WRITE) < 0)
    {
        printf("Error: call avio_open failed!\n");
        return -1;
    }


    audio_stream = avformat_new_stream(pFormatCtx, 0);
    if(!audio_stream)
    {
        return -1;
    }


    //初始化编码器
    pCodecCtx = audio_stream->codec;
    pCodecCtx->codec_id = ofmt->audio_codec;
    pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
    pCodecCtx->sample_fmt = AV_SAMPLE_FMT_FLTP;
    pCodecCtx->channel_layout = AV_CH_LAYOUT_STEREO;
    pCodecCtx->channels = av_get_channel_layout_nb_channels(pCodecCtx->channel_layout);
    pCodecCtx->sample_rate = 44100;
    pCodecCtx->bit_rate = 192000;
    pCodecCtx->frame_size = 1024;


    AVFrame *src_frame = NULL;
    AVFrame *dst_frame = NULL;


    src_frame = av_frame_alloc();
    src_frame->nb_samples = 1024;
    src_frame->sample_rate = 44100;
    src_frame->format= AV_SAMPLE_FMT_S16;
    src_frame->channel_layout = AV_CH_LAYOUT_STEREO;
    src_frame->channels = av_get_channel_layout_nb_channels(src_frame->channel_layout);


    //重采样
    dst_frame = av_frame_alloc();
    dst_frame->sample_rate = 44100;
    dst_frame->format = AV_SAMPLE_FMT_FLTP;
    dst_frame->channel_layout = AV_CH_LAYOUT_STEREO;
    dst_frame->channels = av_get_channel_layout_nb_channels(dst_frame->channel_layout);




    pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
    //pCodec = avcodec_find_encoder_by_name("aac");
    if(!pCodec)
    {
        printf("Error: call avcodec_find_encoder failed!\n");
        return -1;
    }


    if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
    {
        printf("Error: call avcodec_open2 failed!\n");
        return -1;
    }


    int sr_size = 0;
    sr_size = av_samples_get_buffer_size(NULL, src_frame->channels, src_frame->nb_samples, src_frame->format, 1);
    frame_buf = (uint8_t *)av_malloc(sr_size);
    if(!frame_buf)
    {
        printf("Error: call av_malloc failed, sr_size = %d\n", sr_size);
        return -1;
    }


    if(av_sample_fmt_is_planar(src_frame->format))
    {
        avcodec_fill_audio_frame(src_frame, src_frame->channels, src_frame->format, (const uint8_t *)frame_buf, sr_size * src_frame->channels, 1 );
    }
    else
    {
        avcodec_fill_audio_frame(src_frame, src_frame->channels, src_frame->format, (const uint8_t *)frame_buf, sr_size, 0 );
    }




    //Write Header
    if(avformat_write_header(pFormatCtx,NULL) < 0)
    {
        printf("Error: call avformat_write_header..\n");
        return -1;
    }


    AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));
    av_init_packet(packet);


    dst_frame->pts = 0;
    while(fread(frame_buf, 1, sr_size, fp) > 0)
    {
        //printf("Read a frame..\n");
        got_frame = 0;
        if(audio_resampling_2(dst_frame, src_frame) < 0)
        {
            printf("Error: call audio_resampling_2\n");
            return -1;
        }


        ret = avcodec_encode_audio2(pCodecCtx, packet, dst_frame, &got_frame);
        if(ret < 0)
        {
            printf("Error: call avcodec_encode_audio2\n");
            return -1;
        }
        i++;


        dst_frame->pts = i * 100;


        if(1 == got_frame)
        {
            packet->stream_index = audio_stream->index;
            ret = av_write_frame(pFormatCtx, packet);
            if(ret < 0)
            {
                printf("Error: call av_write_frame..\n");
            }
            av_free_packet(packet);
        }


        if(dst_frame->data[0])
        {
            av_free(dst_frame->data[0]);
        }
    }


    //flush encoder
    ret = flush_encoder(pFormatCtx, 0);
    if(ret < 0)
    {
        printf("Error: call flush_encoder failed!\n");
        return -1;
    }


    if(av_write_trailer(pFormatCtx) < 0)
    {
        printf("Error: call av_write_trailer..\n");
        return -1;
    }


    if(audio_stream)
    {
        avcodec_close(audio_stream->codec);
        av_frame_free(&dst_frame);
        av_frame_free(&src_frame);
        av_free(frame_buf);
    }


    av_free(packet);
    avio_close(pFormatCtx->pb);
    avformat_free_context(pFormatCtx);


    fclose(fp);


    printf("Encode Audio End...\n");


    return 0;
}

3.编译

gcc -g mp2.c -o mp2 -lavformat -lavcodec -lavutil -lswresample

4.执行

./mp2 test.pcm test.aac

posted @ 2020-03-23 16:45  standardzero  阅读(1298)  评论(0编辑  收藏  举报