一、FFmpeg命令行實現錄制屏幕和音頻
1、Windows 示例
#include <cstdlib>
#include <string>
#include <iostream>int main() {// FFmpeg 命令行(錄制屏幕 + 麥克風音頻)std::string command = "ffmpeg -f gdigrab -framerate 30 -i desktop " // 屏幕捕獲(GDI)"-f dshow -i audio=\"麥克風 (Realtek Audio)\" " // 音頻設備(需替換為你的設備名)"-c:v libx264 -preset ultrafast -crf 18 " // 視頻編碼(H.264)"-c:a aac -b:a 192k " // 音頻編碼(AAC)"-pix_fmt yuv420p " // 兼容性格式"output.mp4"; // 輸出文件std::cout << "開始錄制(按 Ctrl+C 停止)..." << std::endl;int ret = system(command.c_str());if (ret == 0) {std::cout << "錄制完成!保存為 output.mp4" << std::endl;} else {std::cerr << "錄制失敗!錯誤碼: " << ret << std::endl;}return 0;
}
僅僅錄制視頻:
ffmpeg -f gdigrab -framerate 30 -i desktop -vcodec libx264 -pix_fmt yuv420p output.mp4
2、Linux 示例
std::string command ="ffmpeg -f x11grab -framerate 30 -video_size 1920x1080 -i :0.0 " // X11 屏幕捕獲"-f alsa -i default " // ALSA 音頻輸入"-c:v libx264 -preset ultrafast -crf 18 ""-c:a aac -b:a 192k ""output.mp4";
?3、macOS 示例
std::string command ="ffmpeg -f avfoundation -framerate 30 -i \"1:0\" " // 屏幕+音頻捕獲"-c:v libx264 -preset ultrafast -crf 18 ""-c:a aac -b:a 192k ""output.mp4";
關鍵參數說明
參數 | 說明 |
---|---|
-f gdigrab | Windows 屏幕捕獲驅動 |
-f x11grab | Linux 屏幕捕獲驅動 |
-f avfoundation | macOS 屏幕/音頻捕獲驅動 |
-i desktop | 捕獲整個屏幕(Windows) |
-i :0.0 | Linux 主顯示器(X11) |
-f dshow -i audio="..." | Windows 音頻設備名(通過?ffmpeg -list_devices true -f dshow -i dummy ?查詢) |
-f alsa -i default | Linux 默認音頻輸入 |
-c:v libx264 | H.264 視頻編碼 |
-preset ultrafast | 編碼速度優化(犧牲壓縮率) |
-crf 18 | 視頻質量(18~28,值越小質量越高) |
-c:a aac | AAC 音頻編碼 |
-b:a 192k | 音頻比特率(192kbps) |
4、高級功能
1)錄制特定窗口(Windows)
// 替換 -i desktop 為窗口標題(模糊匹配)
std::string command = "ffmpeg -f gdigrab -framerate 30 -i title=\"Chrome\" output.mp4";
2)硬件加速(NVIDIA/Intel)
// NVIDIA NVENC
std::string command = "ffmpeg -f gdigrab -framerate 30 -i desktop -c:v h264_nvenc -preset p7 -tune hq output.mp4";// Intel QuickSync
std::string command = "ffmpeg -f gdigrab -framerate 30 -i desktop -c:v h264_qsv -preset faster output.mp4";
?3)僅錄制音頻
// Windows
std::string command = "ffmpeg -f dshow -i audio=\"麥克風 (Realtek Audio)\" -c:a aac audio.m4a";// Linux
std::string command = "ffmpeg -f alsa -i default -c:a aac audio.m4a";
4)設備名稱:Windows 需通過?ffmpeg -list_devices true -f dshow -i dummy?查詢正確的音頻設備名。
5)權限問題:Linux/macOS 可能需要?sudo?或音頻組權限。
6)性能優化:高分辨率錄制建議使用硬件加速(如?h264_nvenc)。
二、FFmpeg庫實現錄制屏幕和音頻
1、?初始化 FFmpeg
#include <iostream>
#include <string>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libswscale/swscale.h>
}int main() {// 初始化 FFmpegavdevice_register_all(); // 注冊設備輸入(屏幕、麥克風等)avformat_network_init();// ... 后續代碼return 0;
}
2、捕獲屏幕(Windows 使用?gdigrab
)
AVFormatContext* screenFormatCtx = nullptr;
AVDictionary* screenOptions = nullptr;// 設置屏幕捕獲參數(Windows GDI)
av_dict_set(&screenOptions, "framerate", "30", 0); // 幀率
av_dict_set(&screenOptions, "offset_x", "0", 0); // 起始 X 坐標
av_dict_set(&screenOptions, "offset_y", "0", 0); // 起始 Y 坐標
av_dict_set(&screenOptions, "video_size", "1920x1080", 0); // 分辨率// 打開屏幕輸入流
if (avformat_open_input(&screenFormatCtx, "desktop", av_find_input_format("gdigrab"), &screenOptions) < 0) {std::cerr << "無法打開屏幕輸入!" << std::endl;return -1;
}// 查找視頻流
if (avformat_find_stream_info(screenFormatCtx, nullptr) < 0) {std::cerr << "無法獲取屏幕流信息!" << std::endl;return -1;
}
3、捕獲音頻(Windows 使用?dshow
)
AVFormatContext* audioFormatCtx = nullptr;
AVDictionary* audioOptions = nullptr;// 設置音頻設備(需替換為你的設備名)
av_dict_set(&audioOptions, "sample_rate", "44100", 0); // 采樣率
av_dict_set(&audioOptions, "channels", "2", 0); // 聲道數// 打開音頻輸入流
if (avformat_open_input(&audioFormatCtx, "audio=麥克風 (Realtek Audio)", av_find_input_format("dshow"), &audioOptions) < 0) {std::cerr << "無法打開音頻輸入!" << std::endl;return -1;
}// 查找音頻流
if (avformat_find_stream_info(audioFormatCtx, nullptr) < 0) {std::cerr << "無法獲取音頻流信息!" << std::endl;return -1;
}
?4、創建輸出文件(MP4 封裝)
AVFormatContext* outputFormatCtx = nullptr;
avformat_alloc_output_context2(&outputFormatCtx, nullptr, nullptr, "output.mp4");// 添加視頻流(H.264)
AVStream* videoStream = avformat_new_stream(outputFormatCtx, nullptr);
AVCodecParameters* videoCodecParams = videoStream->codecpar;
videoCodecParams->codec_id = AV_CODEC_ID_H264;
videoCodecParams->codec_type = AVMEDIA_TYPE_VIDEO;
videoCodecParams->width = 1920;
videoCodecParams->height = 1080;
videoCodecParams->format = AV_PIX_FMT_YUV420P;// 添加音頻流(AAC)
AVStream* audioStream = avformat_new_stream(outputFormatCtx, nullptr);
AVCodecParameters* audioCodecParams = audioStream->codecpar;
audioCodecParams->codec_id = AV_CODEC_ID_AAC;
audioCodecParams->codec_type = AVMEDIA_TYPE_AUDIO;
audioCodecParams->sample_rate = 44100;
audioCodecParams->channels = 2;
audioCodecParams->channel_layout = AV_CH_LAYOUT_STEREO;// 打開輸出文件
if (avio_open(&outputFormatCtx->pb, "output.mp4", AVIO_FLAG_WRITE) < 0) {std::cerr << "無法打開輸出文件!" << std::endl;return -1;
}// 寫入文件頭
if (avformat_write_header(outputFormatCtx, nullptr) < 0) {std::cerr << "無法寫入文件頭!" << std::endl;return -1;
}
5、循環讀取音視頻幀并寫入文件
AVPacket packet;
while (true) {// 讀取視頻幀if (av_read_frame(screenFormatCtx, &packet) >= 0) {av_packet_rescale_ts(&packet, screenFormatCtx->streams[packet.stream_index]->time_base, videoStream->time_base);packet.stream_index = videoStream->index;av_interleaved_write_frame(outputFormatCtx, &packet);av_packet_unref(&packet);}// 讀取音頻幀if (av_read_frame(audioFormatCtx, &packet) >= 0) {av_packet_rescale_ts(&packet, audioFormatCtx->streams[packet.stream_index]->time_base, audioStream->time_base);packet.stream_index = audioStream->index;av_interleaved_write_frame(outputFormatCtx, &packet);av_packet_unref(&packet);}// 按 Ctrl+C 停止錄制if (GetAsyncKeyState(VK_ESCAPE) {break;}
}// 寫入文件尾
av_write_trailer(outputFormatCtx);
6、釋放資源
avformat_close_input(&screenFormatCtx);
avformat_close_input(&audioFormatCtx);
avio_closep(&outputFormatCtx->pb);
avformat_free_context(outputFormatCtx);
7、示例代碼(window)
#include <iostream>
#include <Windows.h>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
}int main() {// 初始化 FFmpegavdevice_register_all();avformat_network_init();// 1. 打開屏幕輸入AVFormatContext* screenFormatCtx = nullptr;AVDictionary* screenOptions = nullptr;av_dict_set(&screenOptions, "framerate", "30", 0);av_dict_set(&screenOptions, "video_size", "1920x1080", 0);if (avformat_open_input(&screenFormatCtx, "desktop", av_find_input_format("gdigrab"), &screenOptions) < 0) {std::cerr << "無法打開屏幕輸入!" << std::endl;return -1;}// 2. 打開音頻輸入AVFormatContext* audioFormatCtx = nullptr;AVDictionary* audioOptions = nullptr;av_dict_set(&audioOptions, "sample_rate", "44100", 0);av_dict_set(&audioOptions, "channels", "2", 0);if (avformat_open_input(&audioFormatCtx, "audio=麥克風 (Realtek Audio)", av_find_input_format("dshow"), &audioOptions) < 0) {std::cerr << "無法打開音頻輸入!" << std::endl;return -1;}// 3. 創建輸出文件AVFormatContext* outputFormatCtx = nullptr;avformat_alloc_output_context2(&outputFormatCtx, nullptr, nullptr, "output.mp4");// 4. 寫入音視頻流AVStream* videoStream = avformat_new_stream(outputFormatCtx, nullptr);AVStream* audioStream = avformat_new_stream(outputFormatCtx, nullptr);// 5. 循環讀取幀并寫入文件AVPacket packet;while (!GetAsyncKeyState(VK_ESCAPE)) {// 讀取視頻幀if (av_read_frame(screenFormatCtx, &packet) >= 0) {av_packet_rescale_ts(&packet, screenFormatCtx->streams[packet.stream_index]->time_base, videoStream->time_base);packet.stream_index = videoStream->index;av_interleaved_write_frame(outputFormatCtx, &packet);av_packet_unref(&packet);}// 讀取音頻幀if (av_read_frame(audioFormatCtx, &packet) >= 0) {av_packet_rescale_ts(&packet, audioFormatCtx->streams[packet.stream_index]->time_base, audioStream->time_base);packet.stream_index = audioStream->index;av_interleaved_write_frame(outputFormatCtx, &packet);av_packet_unref(&packet);}}// 6. 釋放資源avformat_close_input(&screenFormatCtx);avformat_close_input(&audioFormatCtx);avio_closep(&outputFormatCtx->pb);avformat_free_context(outputFormatCtx);std::cout << "錄制完成!保存為 output.mp4" << std::endl;return 0;
}
三、總結
方法 | 適用場景 | 優點 | 缺點 |
---|---|---|---|
FFmpeg 命令行 | 快速開發 | 簡單 | 依賴外部進程 |
libavformat/libavcodec | 高性能、精細控制 | 直接操作音視頻流 | 代碼復雜 |
推薦:
-
快速開發?→ 直接調用?
ffmpeg
?命令行。 -
高性能/嵌入式?→ 使用 FFmpeg 庫(如?
libavformat
)。