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


FFMpeg版本:3.3.1

一、原理

    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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM