FFmpeg录制屏幕和音频

一、FFmpeg命令行实现录制屏幕和音频

1、Windows 示例

#include 
#include 
#include 

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 
#include 
extern "C" {
#include 
#include 
#include 
#include 
}

int main() {
    // 初始化 FFmpeg
    avdevice_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 
#include 
extern "C" {
#include 
#include 
#include 
}

int main() {
    // 初始化 FFmpeg
    avdevice_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)。

你可能感兴趣的:(音视频,ffmpeg,音视频)