Qt音視訊開發11-ffmpeg常用命令
阿新 • • 發佈:2020-08-16
一、前言
大部分的格式轉換工具比如格式化工廠等,都用到了ffmpeg來處理,ffmpeg編譯後生成的ffmpeg.exe、ffplay.exe、ffprobe.exe等可執行檔案,其實就封裝了眾多牛逼的功能,ffprobe檢視媒體檔案頭資訊的工具,ffplay用於播放媒體檔案的工具,尤其是ffmpeg.exe,強大的媒體檔案轉換工具,可以轉換任何媒體檔案,還可以用自己的 AudioFilter 以及 VideoFliter 進行處理和編輯,比如下面的一些功能。
- 列出支援的格式:ffmpeg -formats
- 剪下一段媒體檔案:ffmpeg -i input.mp4 -ss 00:00:50.0 -codec copy -t 20 output.mp4
- 提取一個視訊檔案中的音訊檔案:ffmpeg -i input.mp4 -vn -acodec copy output.m4a
- 視訊靜音,即只保留視訊:ffmpeg -i input.mp4 -an -vcodec copy output.mp4
- 從MP4檔案中抽取視訊流匯出為裸的H264資料:ffmpeg -i output.mp4 -an -vcodec copy -bsf:v h264_mp4toannexb output.h264
- 使用AAC音訊資料和H264視訊生成MP4檔案:ffmpeg -i test.aac -i test.h264 -acodec copy -bsf:a aac_adtstoasc -vcodec copy -f mp4 output.mp4
- 音訊格式轉換:ffmpeg -i input.wav -acodec libfdk_aac output.aac
- 將一個MP4的檔案轉換為一個GIF動圖:ffmpeg -i input.mp4 -vf scale=100:-1 -t 5 -r 10 image.gif
既然這些工具這麼牛逼,那是不是可以考慮做一個功能,直接程式呼叫這些可執行檔案做處理呢?當然,QProcess上場了,他可以直接呼叫可執行程式或者直接執行命令,然後能夠攔截輸出列印的資訊,管道的形式read出來,這樣就非常直觀了,可以在呼叫可執行檔案執行的時候,將列印資訊全部輸出。
二、功能特點
- 多執行緒實時播放視訊流+本地視訊+USB攝像頭等。
- 支援windows+linux+mac,支援ffmpeg3和ffmpeg4,支援32位和64位。
- 多執行緒顯示影象,不卡主介面。
- 自動重連網路攝像頭。
- 可設定邊框大小即偏移量和邊框顏色。
- 可設定是否繪製OSD標籤即標籤文字或圖片和標籤位置。
- 可設定兩種OSD位置和風格。
- 可設定是否儲存到檔案以及檔名。
- 可直接拖曳檔案到ffmpegwidget控制元件播放。
- 支援h265視訊流+rtmp等常見視訊流。
- 可暫停播放和繼續播放。
- 支援儲存單個視訊檔案和定時儲存視訊檔案。
- 自定義頂部懸浮條,傳送單擊訊號通知,可設定是否啟用。
- 可設定畫面拉伸填充或者等比例填充。
- 可設定解碼是速度優先、質量優先、均衡處理。
- 可對視訊進行截圖(原始圖片)和截圖。
- 錄影檔案儲存支援裸流和MP4檔案。
- 支援qsv、dxva2、d3d11va等硬解碼。
- 支援opengl繪製視訊資料,極低CPU佔用。
- 支援嵌入式linux,交叉編譯即可。
三、效果圖
四、相關站點
- 國內站點:https://gitee.com/feiyangqingyun/QWidgetDemo
- 國際站點:https://github.com/feiyangqingyun/QWidgetDemo
- 個人主頁:https://blog.csdn.net/feiyangqingyun
- 知乎主頁:https://www.zhihu.com/people/feiyangqingyun/
- 體驗地址:https://blog.csdn.net/feiyangqingyun/article/details/97565652
五、核心程式碼
FFmpegTool::FFmpegTool(QObject *parent) : QObject(parent)
{
//繫結訊號槽
connect(&process, SIGNAL(started()), this, SIGNAL(started()));
connect(&process, SIGNAL(finished(int)), this, SIGNAL(finished()));
connect(&process, SIGNAL(readyReadStandardOutput()), this, SLOT(readData()));
process.setProcessChannelMode(QProcess::MergedChannels);
}
void FFmpegTool::readData()
{
QString data = process.readAllStandardOutput();
emit receiveData(data);
}
void FFmpegTool::start(const QString &command)
{
process.start(command);
}
void FFmpegTool::start(const QString &program, const QStringList &arguments)
{
process.start(program, arguments);
}
void FFmpegTool::getMediaInfo(const QString &mediaFile, bool json)
{
//ffprobe -print_format json -show_streams d:/out.mp4
//不同平臺可執行檔案路徑改成自己的
QString jsonArg = "-print_format json -show_streams";
QString binFile = qApp->applicationDirPath() + "/ffprobe.exe";
QString cmd = QString("%1 %2 %3").arg(binFile).arg(json ? jsonArg : "").arg(mediaFile);
start(cmd);
}
void FFmpegTool::h264ToMp4ByCmd(const QString &h264File, const QString &aacFile, const QString &mp4File)
{
if (!QFile(h264File).exists() || mp4File.isEmpty()) {
return;
}
//具體引數可以參考 https://www.cnblogs.com/renhui/p/9223969.html
//ffmpeg.exe -y -i d:/1.aac -i d:/1.mp4 -map 0:0 -map 1:0 d:/out.mp4
//-y引數表示預設yes覆蓋檔案
//不同平臺可執行檔案路徑改成自己的
QString binFile = qApp->applicationDirPath() + "/ffmpeg.exe";
//下面兩種方法都可以,怎麼方便怎麼來
#if 0
QString cmd = QString("%1 -y -i %2 -i %3 -map 0:0 -map 1:0 %4").arg(binFile).arg(h264File).arg(aacFile).arg(mp4File);
start(cmd);
#else
QStringList args;
args << "-y";
args << "-i" << h264File;
//如果存在音訊檔案則新增
if (QFile(aacFile).exists()) {
args << "-i" << aacFile;
}
//args << "-map" << "0:0";
//args << "-map" << "1:0";
args << mp4File;
start(binFile, args);
#endif
}