1. 程式人生 > 實用技巧 >FFMpeg音訊混合,背景音(五):將PCM壓縮為MP3

FFMpeg音訊混合,背景音(五):將PCM壓縮為MP3

一、原理

pcm:樣本格式為s16交錯儲存,左右左右交錯儲存,取樣率為44100,通道數為2,立體聲 mp3:格式為s16P, 也就是平面模式,先儲存左聲道,再存右聲道,雙聲道,立體聲。單幀樣本1152個,取樣率為44100.

二、程式碼

#include <iostream>
using namespace std;
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include 
<libavutil/opt.h> #include <libswresample/swresample.h> } #pragma comment(lib,"avcodec.lib") #pragma comment(lib,"avformat.lib") #pragma comment(lib,"avutil.lib") #pragma comment(lib,"swresample.lib") int main() { av_register_all(); char inputfile[] = "audio.pcm"; char outputfile[] = "
audio.mp3"; int ret = 0; FILE* finput = NULL; FILE* foutput = NULL; //======================================MP3收尾工作============================================ //尋找mp3編碼器 AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_MP3); //建立並配置mp3編(解)碼器上下文 AVCodecContext* ctx = avcodec_alloc_context3(codec); ctx
->bit_rate = 64000; ctx->channels = 2; ctx->channel_layout = AV_CH_LAYOUT_STEREO; ctx->sample_rate = 44100; ctx->sample_fmt = AV_SAMPLE_FMT_S16P; //開啟mp3編(解)碼器 ret = avcodec_open2(ctx, codec, 0); //開啟輸出的MP3檔案流 foutput = fopen(outputfile, "wb"); //===========================================PCM重取樣為MP3============================================ //準備一個frame結構體來接受重取樣MP3的,每一幀的音訊資料,每幀的樣本大小為1152。 //其實就是分配記憶體緩衝區,放重取樣後的資料 AVFrame* frame = av_frame_alloc(); frame->nb_samples = 1152; frame->channels = 2; frame->channel_layout = AV_CH_LAYOUT_STEREO; frame->format = AV_SAMPLE_FMT_S16P; av_frame_get_buffer(frame, 0); //建立音訊重取樣上下文 SwrContext* swr = swr_alloc(); //設定重取樣輸入引數,通道佈局立體聲,取樣率44100,樣本格式不一致,輸入S16交錯儲存,輸出S16P平面儲存 av_opt_set_int(swr, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0); av_opt_set_int(swr, "in_sample_rate", 44100, 0); av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0); //設定重取樣輸出引數 av_opt_set_int(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0); av_opt_set_int(swr, "out_sample_rate", 44100, 0); av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16P, 0); swr_init(swr); //===========================================PCM讀入處理工作============================================ finput = fopen(inputfile, "rb"); //儲存從pcm檔案讀取過來的資料,進行快取 uint8_t** input_data = NULL; //快取重取樣之後的資料 uint8_t** output_data = NULL; int input_linesize, output_linesize; //給儲存pcm檔案資料分配空間 av_samples_alloc_array_and_samples(&input_data, &input_linesize, 2, 1152, AV_SAMPLE_FMT_S16, 0); //快取重取樣資料的空間分配 av_samples_alloc_array_and_samples(&output_data, &output_linesize, 2, 1152, AV_SAMPLE_FMT_S16P, 0); //接受編碼之後的資料 AVPacket* pkt = av_packet_alloc(); while (!feof(finput)) { fread(input_data[0], 1, 1152 * 2 * 2, finput); //重取樣 swr_convert(swr, output_data, 1152, (const uint8_t**)input_data, 1152); //左聲道資料 frame->data[0] = output_data[0]; //右聲道資料 frame->data[1] = output_data[1]; //編碼,寫入mp3檔案,實際上是對frame這個結構體裡面的資料進行編碼操作。 ret = avcodec_send_frame(ctx, frame); while (ret >= 0) { ret = avcodec_receive_packet(ctx, pkt); //AVERROR(EEAGAIN) -11 AVERROR_EOF表示已經沒有資料了 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { continue; } else if (ret < 0) { break; } fwrite(pkt->data, 1, pkt->size, foutput); av_packet_unref(pkt); } } if (input_data) { av_freep(input_data); } if (output_data) { av_freep(output_data); } fclose(finput); fclose(foutput); av_frame_free(&frame); av_packet_free(&pkt); swr_free(&swr); avcodec_free_context(&ctx); return 0; }