FFMpeg AAC编码

FFMpeg AAC编码流程:

  • 添加头文件
  • 注册编解码器,avcodec_register_all()
  • 通过编解码器名找到编解码器,avcodec_register_all()
  • 设置参数,打开编码器,avcodec_open2()
  • 获取数据,进行编码。
    FFMpeg AAC编码_第1张图片

相关API

文件操作
相关API

源码

#include 
#include 
#include 

#include 

#include 
#include 
#include 
#include 

//判断编码器是否支持某个采样格式(采样大小)
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) { //如果找到支持此采样格式,便返回 1
            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;
    //从编码器所支持的采样率中获取与44100最接近的采样率
    while (*p) {
        if (!best_samplerate || abs(44100 - *p) < abs(44100 - best_samplerate)) {
            best_samplerate = *p;
        }
        p++;
    }
    return best_samplerate;
}

//选择声道数
static uint64_t 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_channels;
        }
        p++;
    }
    return best_ch_layout;
}

static void encodeAudio(AVCodecContext *c_ctx, AVPacket *pkt, AVFrame *frame, FILE *outfile) {
    
    int ret = avcodec_send_frame(c_ctx, frame);
    if (ret < 0) {
        fprintf(stderr, "Error sending a frame for encoding\n");
        exit(1);
    }
    while (ret >= 0) {
        ret = avcodec_receive_packet(c_ctx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            break;
        else if (ret < 0) {
            fprintf(stderr, "Error during encoding\n");
            exit(1);
        }
        fwrite(pkt->data, 1, pkt->size, outfile);
        av_packet_unref(pkt);
    }
}


int encode_audio( const char *filename) {
    //编码器
    AVCodec *codec = NULL;
    //编码器上下文
    AVCodecContext *c_ctx = NULL;
    //存储未压缩数据
    AVFrame *frame;
    //存储压缩后的数据
    AVPacket pkt;
    
    FILE *f;
    uint16_t *sameples;
    
    //注册所有编解码器
    avcodec_register_all();

    codec = avcodec_find_encoder(AV_CODEC_ID_MP2);
    if (!codec) {
        fprintf(stderr, "Codec not found\n");
        exit(1);
    }
    
    c_ctx = avcodec_alloc_context3(codec);
    if (!c_ctx) {
        fprintf(stderr, "Could not allocate audio codec context\n");
        exit(1);
    }
    
    //参数设置
//    比特率
    c_ctx->bit_rate = 64000;
    //采样大小为16位
    c_ctx->sample_fmt = AV_SAMPLE_FMT_S16;
    //
    if (!check_sample_fmt(codec, c_ctx->sample_fmt)) {
        fprintf(stderr, "Encoder does not support sameple format %s", av_get_sample_fmt_name(c_ctx->sample_fmt));
        exit(1);
    }
    //采样率
    c_ctx->sample_rate = select_sample_rate(codec);
    //channel_layout为各个通道存储顺序,可以据此算出声道数。设置声道数也可以直接写具体值
    c_ctx->channel_layout = select_channel_layout(codec);
    c_ctx->channels = av_get_channel_layout_nb_channels(c_ctx->channel_layout);
    
    //打开编码器
    if (avcodec_open2(c_ctx, codec, NULL) < 0) {
        fprintf(stderr, "Could not open codec\n");
        exit(1);
    }
    
    //打开输出文件
    f = fopen(filename, "wb");
    if (!f) {
        fprintf(stderr, "Could not open %s\n", filename);
        exit(1);
    }
    
    //初始化帧并设置帧的YUV格式和分辨率
    frame = av_frame_alloc();
    if (!frame) {
        fprintf(stderr, "Could not allocate audio data buffers\n");
        exit(1);
    }
    //一个frame 可能包含多个音频帧,nb_samples记录音频帧的数量
    frame->nb_samples = c_ctx->frame_size;
    //frame 的格式和声道信息
    frame->format = c_ctx->sample_fmt;
    frame->channel_layout = c_ctx->channel_layout;
    
//    为音频或视频数据分配新的缓冲区
    int ret = av_frame_get_buffer(frame, 0);
    if (ret < 0) {
        fprintf(stderr, "Could not allocate audio data buffers\n");
        exit(1);
    }
    
    float t, tincr;
    
    //实际应用中原始数据是来自麦克风或解码后的音频,这里是人工添加的模拟数据
    t  = 0;
    tincr = 2 * M_PI * 440.0 / c_ctx->sample_rate;
    for (int i = 0; i < 200; i++) {
        av_init_packet(&pkt);
        pkt.data = NULL;
        pkt.size = 0;
        
        /* make sure the frame is writable -- makes a copy if the encoder
        * kept a reference internally */
        if (ret < 0)
            exit(1);
        sameples = (uint16_t*)frame->data[0];

        for (int j = 0; j < c_ctx->frame_size; j++) {
            sameples[2*j] = (int)(sin(t) * 10000);

            for (int k = 1; k < c_ctx->channels; k++)
                sameples[2*j + k] = sameples[2*j];
            t += tincr;
        }
        encodeAudio(c_ctx, &pkt, frame, f);
    }
    encodeAudio(c_ctx, &pkt, frame, f);
    
    fclose(f);
    av_frame_free(&frame);
    avcodec_free_context(&c_ctx);
    return 0;
}

你可能感兴趣的:(音视频,ffmpeg)