終於要開始進行FFmpeg實戰了,一塊兒來感覺一下FFmpeg的強大吧。html
FFmpeg的bin目錄中提供了3個命令(可執行程序),能夠直接在命令行上使用。編程
ffmpeg的主要做用:對音視頻進行編解碼。ide
# 將MP3文件轉成WAV文件 ffmpeg -i xx.mp3 yy.wav
當輸入命令ffmpeg時,能夠看到ffmpeg命令的使用格式是:函數
ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...
簡化一下,經常使用格式是:工具
ffmpeg arg1 arg2 -i arg3 arg4 arg5
更多詳細用法,能夠參考官方文檔:ffmpeg-all.html,或者使用如下命令查看:測試
# 簡易版 ffmpeg -h # 詳細版 ffmpeg -h long # 完整版 ffmpeg -h full # 或者使用 # ffmpeg -help # ffmpeg -help long # ffmpeg -help full
ffprobe的主要做用:查看音視頻的參數信息。ui
# 能夠查看MP3文件的採樣率、比特率、時長等信息 ffprobe xx.mp3
當輸入命令ffprobe時,能夠看到ffprobe命令的使用格式是:this
ffprobe [OPTIONS] [INPUT_FILE] # OPTIONS:參數 # INPUT_FILE:輸入文件
更多詳細用法,能夠參考官方文檔:ffprobe-all.html,或者使用如下命令查看:命令行
# 簡易版 ffprobe -h # 詳細版 ffprobe -h long # 完整版 ffprobe -h full # 或者使用 # ffprobe -help # ffprobe -help long # ffprobe -help full
ffplay的主要做用:播放音視頻。線程
# 播放MP3文件 ffplay xx.mp3
當輸入命令ffplay時,能夠看到ffplay命令的使用格式是:
ffplay [options] input_file # options:參數 # input_file:輸入文件
更多詳細用法,能夠參考官方文檔:ffplay-all.html,或者使用如下命令查看:
# 簡易版 ffplay -h # 詳細版 ffplay -h long # 完整版 ffplay -h full # 或者使用 # ffplay -help # ffplay -help long # ffplay -help full
增長-hide_bannder參數能夠隱藏一些冗餘的描述信息,能夠去實踐比較如下2條命令的區別:
ffprobe xx.mp3 ffprobe -hide_banner xx.mp3 # ffmpeg、ffprobe、ffplay都適用
使用命令行查看當前平臺的可用設備:
ffmpeg -devices
Windows的輸出結果以下所示:
Devices: D. = Demuxing supported .E = Muxing supported -- E caca caca (color ASCII art) output device D dshow DirectShow capture D gdigrab GDI API Windows frame grabber D lavfi Libavfilter virtual input device D libcdio E sdl,sdl2 SDL2 output device D vfwcap VfW video capture
Mac的輸出結果以下所示:
Devices: D. = Demuxing supported .E = Muxing supported -- D avfoundation AVFoundation input device D lavfi Libavfilter virtual input device E sdl,sdl2 SDL2 output device
# 查看dshow支持的設備 ffmpeg -f dshow -list_devices true -i dummy # 或者 # ffmpeg -list_devices true -f dshow -i '' # ffmpeg -list_devices true -f dshow -i ""
-f dshow
-list_devices true
-i dummy 或 -i '' 或 -i ""
個人筆記本外接了一隻麥克風。
所以,命令的執行結果大體以下所示:
DirectShow video devices (some may be both video and audio devices) "Integrated Camera" DirectShow audio devices "線路輸入 (3- 魅聲T800)" "麥克風陣列 (Realtek(R) Audio)"
dshow支持的視頻設備
dshow支持的音頻設備
在Mac平臺,使用的是avfoundation,而不是dshow。
ffmpeg -f avfoudation -list_devices true -i ''
輸出結果以下所示:
AVFoundation video devices: [0] FaceTime高清攝像頭(內建) [1] Capture screen 0 AVFoundation audio devices: [0] MS-T800 [1] Edu Audio Device [2] MacBook Pro麥克風
列表中的MS-T800是外接的麥克風。在Mac上,FFmpeg還給每個視頻、音頻設備進行了編號,好比MS-T800的編號是0、Mac自帶麥克風的編號是2。
# 使用外接的麥克風進行錄音,最後生成一個wav文件 ffmpeg -f dshow -i audio="麥克風陣列 (Realtek(R) Audio)" out.wav # 在Mac上經過編號指定設備 ffmpeg -f avfoundation -i :0 out.wav # :0表示使用0號音頻設備 # 0:2表示使用0號視頻設備和2號音頻設備
先經過命令查看一下dshow可使用的參數,詳情能夠查看官方文檔:dshow參數。
# 從ffmpeg -devices命令的結果能夠看得出來:dshow屬於demuxer,而不是muxer ffmpeg -h demuxer=dshow
部分輸出結果以下所示:
# 採樣率 -sample_rate <int> set audio sample rate (from 0 to INT_MAX) # 採樣大小(位深度) -sample_size <int> set audio sample size (from 0 to 16) # 聲道數 -channels <int> set number of audio channels, such as 1 or 2 (from 0 to INT_MAX) # 列出特定設備支持的參數 -list_options <boolean> list available options for specified device (default false)
而後再看看你的設備支持哪些參數。
ffmpeg -f dshow -list_options true -i audio="麥克風陣列 (Realtek(R) Audio)"
輸出結果以下所示:
DirectShow audio only device options (from audio devices) Pin "Capture" (alternative pin name "Capture") min ch=1 bits=8 rate= 11025 max ch=2 bits=16 rate= 44100 # 能夠看出來:採樣率範圍是11025~44100Hz
接下來設置錄音時的音頻參數。
ffmpeg -f dshow -sample_rate 15000 -sample_size 16 -channels 1 -i audio="麥克風陣列 (Realtek(R) Audio)" out.wav
開發錄音功能的主要步驟是:
之後的開發過程當中,常常須要查詢的資料:官方API文檔。
錄音是個耗時操做,所以最好放到一個子線程中進行。這裏建立了一個繼承自QThread的線程類,線程一旦啓動(start),就會自動調用run函數。
#include <QThread> class AudioThread : public QThread { Q_OBJECT private: void run(); public: explicit AudioThread(QObject *parent = nullptr); ~AudioThread(); };
#include "audiothread.h" #include <QDebug> #include <QFile> extern "C" { // 編解碼相關API #include <libavcodec/avcodec.h> // 格式相關API #include <libavformat/avformat.h> // 工具API(好比錯誤處理) #include <libavutil/avutil.h> } AudioThread::AudioThread(QObject *parent) : QThread(parent) { // 在線程結束時自動回收線程的內存 connect(this, &AudioThread::finished, this, &AudioThread::deleteLater); } AudioThread::~AudioThread() { // 線程銷燬時,正常退出線程 quit(); requestInterruption(); wait(); } void AudioThread::run() { // 格式名稱 const char *fmtName; #if defined (Q_OS_WIN) fmtName = "dshow"; #else fmtName = "avfoundation"; #endif // 根據名稱找到輸入格式對象 AVInputFormat *fmt = av_find_input_format(fmtName); if (fmt == NULL) { qDebug() << "找不到輸入格式:" << fmtName; return; } // 設備名稱 const char *deviceName; #if defined (Q_OS_WIN) deviceName = "audio=麥克風陣列 (Realtek(R) Audio)"; #else deviceName = ":0"; #endif // 格式上下文 AVFormatContext *ctx = NULL; // 選項 AVDictionary *options = NULL; // 打開輸入流 int ret = avformat_open_input(&ctx, deviceName, fmt, &options); // 若是打開輸入流失敗 if (ret < 0) { char errbuf[1024] = {0}; av_strerror(ret, errbuf, sizeof(errbuf)); qDebug() << "打開輸入流失敗:" << errbuf; return; } // 定義文件 QFile file("F:/out.pcm"); // 刪除舊文件 if (file.exists()) { file.remove(); } // 打開文件 if (!file.open(QIODevice::WriteOnly)){ qDebug() << "文件打開失敗"; // 關閉輸入流 avformat_close_input(&ctx); return; } // 數據包 AVPacket pkt; while (!isInterruptionRequested() && av_read_frame(ctx, &pkt) == 0) { // 寫入數據 file.write((char *) pkt.data, pkt.size); } // 關閉文件 file.close(); // 關閉輸入流 avformat_close_input(&ctx); }
在MainWindow控制開始、結束錄音。
class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void on_audioBtn_clicked(); private: Ui::MainWindow *ui; AudioThread *_audioThread = nullptr; };
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QDebug> #include "audiothread.h" extern "C" { // 設備相關API #include <libavdevice/avdevice.h> } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); // 初始化libavdevice並註冊全部輸入和輸出設備 avdevice_register_all(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_audioBtn_clicked() { // 沒有線程 if (_audioThread == nullptr) { // 開啓新線程 _audioThread = new AudioThread(this); _audioThread->start(); // 設置按鈕文字 ui->audioBtn->setText("中止錄音"); } else { // 中止錄音 _audioThread->requestInterruption(); _audioThread = nullptr; // 設置按鈕文字 ui->audioBtn->setText("開始錄音"); } }
播放PCM時須要制定相關參數:
ffplay -ar 44100 -ac 2 -f s16le out.pcm