基於FFmpeg-4.0 SDK的PCM編碼成AAC
阿新 • • 發佈:2018-12-15
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; }