最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Qt+FFmpeg 實現(xiàn)音頻重采樣的示例代碼

 更新時間:2026年02月04日 08:19:54   作者:xmRao  
本文主要介紹了Qt+FFmpeg 實現(xiàn)音頻重采樣的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

本文面向編程小白,用最通俗的語言講解如何基于 Qt+FFmpeg 實現(xiàn)音頻重采樣(簡單說:把音頻文件的采樣率 / 采樣格式 / 聲道數(shù)轉(zhuǎn)換成目標規(guī)格)。全程避開復(fù)雜術(shù)語,只講核心邏輯,代碼可直接運行~

3 個核心概念

概念通俗解釋
采樣率每秒采集的音頻 “樣本數(shù)”,比如 44100Hz = 每秒采 44100 個樣本,數(shù)值越高音質(zhì)越細膩
采樣格式每個音頻樣本的 “存儲格式”,比如 S16(16 位整數(shù))、F32(32 位浮點)
聲道數(shù)單聲道(MONO,1 個聲道)、立體聲(STEREO,2 個聲道)
音頻重采樣把音頻的采樣率 / 采樣格式 / 聲道數(shù),轉(zhuǎn)換成目標規(guī)格的過程(本文核心)

整體流程

  1. 用 Qt 做一個帶按鈕的簡單界面;
  2. 點擊按鈕后,啟動一個獨立線程(避免界面卡死);
  3. 線程中調(diào)用 FFmpeg 的音頻重采樣接口,把指定的 PCM 音頻文件轉(zhuǎn)換成新格式;
  4. 生成轉(zhuǎn)換后的新音頻文件。

環(huán)境準備

  • Qt:隨便一個版本(比如 Qt 5.15),用來做界面和線程管理;
  • FFmpeg:編譯好的庫(重點包含swresample模塊,音頻重采樣專用);
  • PCM 文件:測試用的無壓縮音頻文件(本文用44100_s16le_2.pcm,格式:44100 采樣率、16 位整數(shù)、立體聲)。

完整代碼

目錄結(jié)構(gòu)

├── main.cpp          // 程序入口
├── mainwindow.h/.cpp // 主界面(帶按鈕)
├── audiothread.h/.cpp// 音頻處理線程(避免界面卡死)
├── ffmpegs.h/.cpp    // FFmpeg重采樣核心邏輯

1. main.cpp(程序入口)

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[]) {
    // 創(chuàng)建Qt應(yīng)用程序?qū)ο螅ǔ绦蚩傞_關(guān))
    QApplication a(argc, argv);
    // 創(chuàng)建主窗口
    MainWindow w;
    // 顯示窗口
    w.show();
    // 啟動Qt事件循環(huán)(讓窗口能點擊、能響應(yīng)操作)
    return a.exec();
}

小白解析:所有 Qt 程序的標準入口,作用就是 “啟動程序 + 顯示窗口”。

2. mainwindow.h(主窗口頭文件)

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "audiothread.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    // 按鈕點擊的響應(yīng)函數(shù)
    void on_audioButton_clicked();

private:
    // 界面控件(比如按鈕)的管理對象
    Ui::MainWindow *ui;
    // 音頻線程對象(避免界面卡死)
    AudioThread *_audioThread = nullptr;
};
#endif // MAINWINDOW_H

3. mainwindow.cpp(主窗口實現(xiàn))

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow) {
    // 初始化界面(加載Qt設(shè)計師畫的按鈕)
    ui->setupUi(this);
}

MainWindow::~MainWindow() {
    // 銷毀界面控件,釋放內(nèi)存
    delete ui;
}

void MainWindow::on_audioButton_clicked() {
    // 創(chuàng)建音頻線程對象
    _audioThread = new AudioThread(this);
    // 啟動線程(執(zhí)行AudioThread的run函數(shù))
    _audioThread->start();
}

4. audiothread.h(音頻線程頭文件)

#ifndef AUDIOTHREAD_H
#define AUDIOTHREAD_H

#include <QThread>

class AudioThread : public QThread {
    Q_OBJECT
private:
    // 線程啟動后自動執(zhí)行的函數(shù)(核心邏輯寫這)
    void run();

public:
    explicit AudioThread(QObject *parent = nullptr);
    ~AudioThread();
};

#endif // AUDIOTHREAD_H

5. audiothread.cpp(音頻線程實現(xiàn))

#include "audiothread.h"
#include <QDebug>
#include "ffmpegs.h"

AudioThread::AudioThread(QObject *parent) : QThread(parent) {
    // 線程結(jié)束后自動釋放內(nèi)存(Qt內(nèi)存管理小技巧)
    connect(this, &AudioThread::finished, this, &AudioThread::deleteLater);
}

AudioThread::~AudioThread() {
    // 斷開所有連接
    disconnect();
    // 要求線程安全退出
    requestInterruption();
    quit();
    wait();
    qDebug() << this << "析構(gòu)(內(nèi)存被回收)";
}

void AudioThread::run() {
    // 定義轉(zhuǎn)換規(guī)則:44100立體聲16位 → 48000單聲道浮點 → 48000單聲道32位 → 還原成原始格式
    ResampleAudioSpec ras1;
    ras1.filename = "D:/44100_s16le_2.pcm";  // 原始文件路徑
    ras1.sampleFmt = AV_SAMPLE_FMT_S16;      // 16位整數(shù)格式
    ras1.sampleRate = 44100;                 // 44100采樣率
    ras1.chLayout = AV_CH_LAYOUT_STEREO;     // 立體聲

    ResampleAudioSpec ras2;
    ras2.filename = "D:/48000_f32le_1.pcm";  // 轉(zhuǎn)換后文件1
    ras2.sampleFmt = AV_SAMPLE_FMT_FLT;      // 浮點格式
    ras2.sampleRate = 48000;                 // 48000采樣率
    ras2.chLayout = AV_CH_LAYOUT_MONO;       // 單聲道

    ResampleAudioSpec ras3;
    ras3.filename = "D:/48000_s32le_1.pcm";  // 轉(zhuǎn)換后文件2
    ras3.sampleFmt = AV_SAMPLE_FMT_S32;      // 32位整數(shù)格式
    ras3.sampleRate = 48000;                 // 48000采樣率
    ras3.chLayout = AV_CH_LAYOUT_MONO;       // 單聲道

    ResampleAudioSpec ras4 = ras1;
    ras4.filename = "D:/44100_s16le_2_new.pcm"; // 最終還原的文件

    // 調(diào)用FFmpeg重采樣函數(shù),一步步轉(zhuǎn)換
    FFmpegs::resampleAudio(ras1, ras2);
    FFmpegs::resampleAudio(ras2, ras3);
    FFmpegs::resampleAudio(ras3, ras4);
}

6. ffmpegs.h(FFmpeg 核心頭文件)

#ifndef FFMPEGS_H
#define FFMPEGS_H

extern "C" {
#include <libavformat/avformat.h>
}

// 封裝音頻規(guī)格的結(jié)構(gòu)體(方便傳參)
typedef struct {
    const char *filename;   // 文件路徑
    int sampleRate;         // 采樣率
    AVSampleFormat sampleFmt; // 采樣格式
    int chLayout;           // 聲道布局(單聲道/立體聲)
} ResampleAudioSpec;

class FFmpegs {
public:
    FFmpegs();
    // 重載的重采樣函數(shù)(傳結(jié)構(gòu)體更方便)
    static void resampleAudio(ResampleAudioSpec &in, ResampleAudioSpec &out);
    // 核心重采樣函數(shù)(傳單個參數(shù))
    static void resampleAudio(const char *inFilename,
                              int inSampleRate,
                              AVSampleFormat inSampleFmt,
                              int inChLayout,
                              const char *outFilename,
                              int outSampleRate,
                              AVSampleFormat outSampleFmt,
                              int outChLayout);
};

#endif // FFMPEGS_H

7. ffmpegs.cpp(FFmpeg 重采樣核心實現(xiàn))

#include "ffmpegs.h"
#include <QDebug>
#include <QFile>

extern "C" {
#include <libswresample/swresample.h>
#include <libavutil/avutil.h>
}

// 錯誤信息封裝(小白不用摳,復(fù)制就行)
#define ERROR_BUF(ret) \
    char errbuf[1024]; \
    av_strerror(ret, errbuf, sizeof (errbuf));

FFmpegs::FFmpegs() {}

// 重載函數(shù):調(diào)用核心重采樣函數(shù)
void FFmpegs::resampleAudio(ResampleAudioSpec &in, ResampleAudioSpec &out) {
    resampleAudio(in.filename, in.sampleRate, in.sampleFmt, in.chLayout,
                  out.filename, out.sampleRate, out.sampleFmt, out.chLayout);
}

// 核心重采樣函數(shù)
void FFmpegs::resampleAudio(const char *inFilename,
                            int inSampleRate,
                            AVSampleFormat inSampleFmt,
                            int inChLayout,
                            const char *outFilename,
                            int outSampleRate,
                            AVSampleFormat outSampleFmt,
                            int outChLayout) {
    // ===== 1. 初始化變量 =====
    QFile inFile(inFilename);   // 輸入文件
    QFile outFile(outFilename); // 輸出文件

    // 輸入緩沖區(qū)相關(guān)
    uint8_t **inData = nullptr; // 輸入緩沖區(qū)指針
    int inLinesize = 0;         // 輸入緩沖區(qū)大小
    int inChs = av_get_channel_layout_nb_channels(inChLayout); // 輸入聲道數(shù)
    int inBytesPerSample = inChs * av_get_bytes_per_sample(inSampleFmt); // 輸入單個樣本大小
    int inSamples = 1024;       // 輸入緩沖區(qū)樣本數(shù)
    int len = 0;                // 讀取文件的字節(jié)數(shù)

    // 輸出緩沖區(qū)相關(guān)
    uint8_t **outData = nullptr;// 輸出緩沖區(qū)指針
    int outLinesize = 0;        // 輸出緩沖區(qū)大小
    int outChs = av_get_channel_layout_nb_channels(outChLayout); // 輸出聲道數(shù)
    int outBytesPerSample = outChs * av_get_bytes_per_sample(outSampleFmt); // 輸出單個樣本大小
    // 計算輸出緩沖區(qū)樣本數(shù)(按采樣率比例縮放,向上取整)
    int outSamples = av_rescale_rnd(outSampleRate, inSamples, inSampleRate, AV_ROUND_UP);

    int ret = 0; // FFmpeg函數(shù)返回值

    // ===== 2. 創(chuàng)建并初始化重采樣上下文 =====
    // 創(chuàng)建上下文(配置輸入/輸出參數(shù))
    SwrContext *ctx = swr_alloc_set_opts(nullptr,
                                         // 輸出參數(shù)
                                         outChLayout, outSampleFmt, outSampleRate,
                                         // 輸入?yún)?shù)
                                         inChLayout, inSampleFmt, inSampleRate,
                                         0, nullptr);
    if (!ctx) {
        qDebug() << "創(chuàng)建重采樣上下文失敗";
        goto end; // 跳轉(zhuǎn)到釋放資源的位置
    }

    // 初始化上下文
    ret = swr_init(ctx);
    if (ret < 0) {
        ERROR_BUF(ret);
        qDebug() << "初始化重采樣上下文失?。? << errbuf;
        goto end;
    }

    // ===== 3. 創(chuàng)建輸入/輸出緩沖區(qū) =====
    // 創(chuàng)建輸入緩沖區(qū)
    ret = av_samples_alloc_array_and_samples(&inData, &inLinesize, inChs, inSamples, inSampleFmt, 1);
    if (ret < 0) {
        ERROR_BUF(ret);
        qDebug() << "創(chuàng)建輸入緩沖區(qū)失?。? << errbuf;
        goto end;
    }

    // 創(chuàng)建輸出緩沖區(qū)
    ret = av_samples_alloc_array_and_samples(&outData, &outLinesize, outChs, outSamples, outSampleFmt, 1);
    if (ret < 0) {
        ERROR_BUF(ret);
        qDebug() << "創(chuàng)建輸出緩沖區(qū)失?。? << errbuf;
        goto end;
    }

    // ===== 4. 打開文件 =====
    if (!inFile.open(QFile::ReadOnly)) {
        qDebug() << "打開輸入文件失?。? << inFilename;
        goto end;
    }
    if (!outFile.open(QFile::WriteOnly)) {
        qDebug() << "打開輸出文件失?。? << outFilename;
        goto end;
    }

    // ===== 5. 循環(huán)讀取→重采樣→寫入 =====
    while ((len = inFile.read((char *) inData[0], inLinesize)) > 0) {
        // 計算實際讀取的樣本數(shù)
        inSamples = len / inBytesPerSample;

        // 核心:調(diào)用FFmpeg重采樣函數(shù)
        ret = swr_convert(ctx, outData, outSamples, (const uint8_t **) inData, inSamples);
        if (ret < 0) {
            ERROR_BUF(ret);
            qDebug() << "重采樣失?。? << errbuf;
            goto end;
        }

        // 把轉(zhuǎn)換后的數(shù)據(jù)寫入輸出文件
        outFile.write((char *) outData[0], ret * outBytesPerSample);
    }

    // 處理緩沖區(qū)殘留的樣本(避免數(shù)據(jù)丟失)
    while ((ret = swr_convert(ctx, outData, outSamples, nullptr, 0)) > 0) {
        outFile.write((char *) outData[0], ret * outBytesPerSample);
    }

    // ===== 6. 釋放資源 =====
end:
    // 關(guān)閉文件
    inFile.close();
    outFile.close();

    // 釋放輸入緩沖區(qū)
    if (inData) {
        av_freep(&inData[0]);
    }
    av_freep(&inData);

    // 釋放輸出緩沖區(qū)
    if (outData) {
        av_freep(&outData[0]);
    }
    av_freep(&outData);

    // 釋放重采樣上下文
    swr_free(&ctx);
}

核心邏輯

  1. 初始化變量:定義輸入 / 輸出文件、緩沖區(qū)參數(shù);
  2. 創(chuàng)建重采樣上下文:告訴 FFmpeg “輸入格式” 和 “輸出格式”;
  3. 創(chuàng)建緩沖區(qū):用來存放讀取的音頻數(shù)據(jù)和轉(zhuǎn)換后的音頻數(shù)據(jù);
  4. 打開文件:準備讀原始文件、寫新文件;
  5. 循環(huán)處理:讀一點數(shù)據(jù)→轉(zhuǎn)格式→寫一點數(shù)據(jù),直到文件讀完;
  6. 釋放資源:FFmpeg 的資源要手動釋放,避免內(nèi)存泄漏。

運行步驟

  1. 把代碼中的文件路徑(比如D:/44100_s16le_2.pcm)換成自己的 PCM 文件路徑;
  2. 配置 Qt 工程,鏈接 FFmpeg 的swresample庫;
  3. 編譯運行程序,點擊界面上的按鈕;
  4. 去指定路徑(比如 D 盤)查看轉(zhuǎn)換后的 PCM 文件。

核心總結(jié)

  1. 為啥用線程?→ 避免界面卡死,讓 “界面操作” 和 “音頻處理” 并行;
  2. FFmpeg 核心?→ swr_alloc_set_opts(配置參數(shù))、swr_init(初始化)、swr_convert(重采樣);
  3. 內(nèi)存管理?→ FFmpeg 的緩沖區(qū) / 上下文要手動釋放,Qt 線程要安全退出;
  4. 核心流程?→ 讀原始 PCM→轉(zhuǎn)格式→寫新 PCM。

常見問題

  1. 運行報錯 “找不到 FFmpeg 庫”→ 檢查 Qt 工程的庫鏈接路徑;
  2. 轉(zhuǎn)換后文件沒聲音→ 檢查原始 PCM 文件路徑是否正確、格式參數(shù)是否匹配;
  3. 界面卡死→ 確認音頻處理邏輯在獨立線程中執(zhí)行。

到此這篇關(guān)于Qt+FFmpeg 實現(xiàn)音頻重采樣的示例代碼的文章就介紹到這了,更多相關(guān)Qt FFmpeg 音頻重采樣內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C/C++ 基礎(chǔ) 之回調(diào)函數(shù)示例詳解

    C/C++ 基礎(chǔ) 之回調(diào)函數(shù)示例詳解

    這篇文章主要介紹了C/C++ 基礎(chǔ) 之回調(diào)函數(shù)示例詳解,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2025-04-04
  • 深入解析C++設(shè)計模式編程中解釋器模式的運用

    深入解析C++設(shè)計模式編程中解釋器模式的運用

    這篇文章主要介紹了C++設(shè)計模式編程中解釋器模式的運用,解釋器模式給定一個語言,定義它的文法的一種表示,并定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子,需要的朋友可以參考下
    2016-03-03
  • c++核心編程之函數(shù)的重載

    c++核心編程之函數(shù)的重載

    這篇文章主要介紹了c++核心編程之函數(shù)的重載,函數(shù)可以重復(fù)使用,提高了復(fù)用性,但前提是必須在一個作用域并且函數(shù)名稱相同,下面附代碼詳細介紹,需要的小伙伴可以參考一下
    2022-03-03
  • C語言設(shè)置和取得socket狀態(tài)的相關(guān)函數(shù)用法

    C語言設(shè)置和取得socket狀態(tài)的相關(guān)函數(shù)用法

    這篇文章主要介紹了C語言設(shè)置和取得socket狀態(tài)的相關(guān)函數(shù)用法,分別是setsockopt()函數(shù)和getsockopt()函數(shù)的使用介紹,需要的朋友可以參考下
    2015-09-09
  • C語言的結(jié)構(gòu)體你了解嗎

    C語言的結(jié)構(gòu)體你了解嗎

    這篇文章主要為大家詳細介紹了C語言的結(jié)構(gòu)體,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • 利用Matlab繪制有趣圖像的示例代碼

    利用Matlab繪制有趣圖像的示例代碼

    這篇文章主要為大家總結(jié)了一些利用Matlab繪制的有趣好看的圖像的示例代碼。文中的示例代碼簡潔易懂,感興趣的小伙伴可以動手試一試
    2022-03-03
  • 詳解C++11中綁定器bind的原理與使用

    詳解C++11中綁定器bind的原理與使用

    C++11中引入的function機制,其中綁定器主要有三種:bind1st、bind2nd、bind(C++11)。本文就來和大家聊聊這些綁定器的底層實現(xiàn)原理與使用場景,需要的可以參考一下
    2022-12-12
  • C語言實現(xiàn)運籌學中的馬氏決策算法實例

    C語言實現(xiàn)運籌學中的馬氏決策算法實例

    這篇文章主要介紹了C語言實現(xiàn)運籌學中的馬氏決策算法,簡單介紹了馬氏決策的概念,并結(jié)合實例形式分析了C語言實現(xiàn)馬氏決策算法的具體實現(xiàn)技巧,需要的朋友可以參考下
    2017-09-09
  • C++模板非類型形參的詳細講解

    C++模板非類型形參的詳細講解

    這篇文章主要給大家介紹了關(guān)于C++模板非類型形參的相關(guān)資料,文中通過實例代碼介紹的非常詳細,對大家的學習或者工作就有一定的參考學習價值,需要的朋友可以參考下
    2021-11-11
  • c++ int轉(zhuǎn)string方法

    c++ int轉(zhuǎn)string方法

    int 轉(zhuǎn)string的方法,用到了特分享一下方便需要的朋友
    2013-01-01

最新評論

望江县| 遂溪县| 繁昌县| 阿拉尔市| 瓦房店市| 滁州市| 安丘市| 虹口区| 南康市| 湘潭县| 镇平县| 囊谦县| 库伦旗| 新和县| 宜州市| 贵阳市| 平南县| 绥化市| 成安县| 云安县| 自贡市| 友谊县| 安康市| 大丰市| 昭觉县| 五华县| 许昌市| 公主岭市| 玉溪市| 永济市| 龙川县| 保亭| 六枝特区| 吉林省| 徐闻县| 广西| 东丰县| 冷水江市| 墨玉县| 明星| 右玉县|