基于FFmpeg-4.0 SDK的PCM编码成AAC


1. 初始化
    AVCodecContext         *m_avctx;
    AVCodec                      *m_codec;

    /* Init ffmpeg log */
    ffmpeg_log_callback pcb_log = libffmpeg_log_callback;
    av_log_set_level(AV_LOG_DEBUG);
    av_log_set_flags(AV_LOG_SKIP_REPEATED);
    av_log_set_callback(pcb_log);

    printf("Current ffmpeg log_level = %d\n", av_log_get_level());

    /* Open the encoder. */
    m_codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
    if (!m_codec){
        printf("Codec not found\n");
        exit(1);
    }
    
    m_avctx = avcodec_alloc_context3(m_codec);
    if (!m_avctx) {
        printf("Could not allocate audio codec context\n");
        exit(1);
    }

    m_avctx->codec_type = AVMEDIA_TYPE_AUDIO;
    m_avctx->codec_id = AV_CODEC_ID_AAC;
    m_avctx->bit_rate = m_audio_bitrate;
    m_avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;  
    if (!check_sample_fmt(m_codec, m_avctx->sample_fmt)) {
        printf("Encoder does not support sample format %s",
                av_get_sample_fmt_name(m_avctx->sample_fmt));
        exit(1);
    }
    m_avctx->sample_rate = m_audio_clock_rate;
    m_avctx->channels    = m_audio_channel_num;
    m_avctx->channel_layout = 
        (m_audio_channel_num == 1) ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;
    m_avctx->time_base = (AVRational){1, m_avctx->sample_rate};
    
    /* open it */
    if (avcodec_open2(m_avctx, m_codec, NULL) < 0) {
        printf("Could not open codec\n");
        exit(1);
    }




2. 调用
NOTE: 
1. 这里只举了个简单的例子, PCM数据是用伪码实现的;
2. PCM的数据格式要和编码器相匹配,
     即 编码器要求是: AV_SAMPLE_FMT_S16,则输入的PCM数据也要是 AV_SAMPLE_FMT_S16
    通常,ffmpeg原生的AAC编码器 :  AV_SAMPLE_FMT_FLT
              libfaac                               :  AV_SAMPLE_FMT_S16
              libfdk-aac                          :   AV_SAMPLE_FTM_FLTP
              

for (int i = 0 ;  i <  XXX; i++) {
    /* Encode by Using ffmpeg-4.0  */    
    AVPacket *pkt;
    AVFrame  *frame;
    uint16_t *samples;

    pkt = av_packet_alloc();
    if (!pkt) {
        printf("could not allocate the packet\n");
        exit(1);
    }



    /* frame containing input raw audio */
    frame = av_frame_alloc();
    if (!frame) {
        printf("Could not allocate audio frame\n");
        exit(1);
    }

    frame->nb_samples     = m_avctx->frame_size;
    frame->format         = m_avctx->sample_fmt;
    frame->channel_layout = m_avctx->channel_layout;

    /* allocate the data buffers */
    ret = av_frame_get_buffer(frame, 0);
    if (ret < 0) {
        printf("Could not allocate audio data buffers\n");
        exit(1);
    }

    /* make sure the frame is writable -- makes a copy if the encoder
     * kept a reference internally */
    ret = av_frame_make_writable(frame);
    if (ret < 0){
        exit(1);
    }
    samples = (uint16_t*)frame->data[0];    

    /* 复制一帧待编码的PCM数据 */
    int   in_pcm_buffer_size = 1024; 
    uint8_t  *in_pcm_buffer;  // 输入的数据
    memcpy(samples, in_pcm_buffer, in_pcm_buffer_size);
    

    /* send the frame for encoding */
    ret = avcodec_send_frame(m_avctx, frame);
    if (ret < 0) {
        printf("Error sending the frame to the encoder\n");
        exit(1);
    }

    ret = avcodec_receive_packet(m_avctx, pkt);
    if (ret == AVERROR(EAGAIN) ){
        printf("Encoding audio frame again! \n");
    } else if (ret == AVERROR_EOF) {
        printf("Encoding audio frame EOF! \n");
    } else if (ret < 0) {
        printf("Error encoding audio frame\n");
        exit(1);
    }

    /* 将编码后的数据输出*/
    if (pkt->size > 0){
        memcpy(aac_buf, pkt->data, pkt->size);
        aac_size = pkt->size;
    }

    
    av_packet_unref(pkt);
    av_frame_free(&frame);
    av_packet_free(&pkt);
}

/* 资源释放 */
    if (m_avctx) {
        avcodec_close(m_avctx);
        av_free(m_avctx);
        m_avctx = NULL;
    }

猜你喜欢

转载自blog.csdn.net/fireroll/article/details/83032148