FFmpeg录制屏幕和音频

news2025/4/7 13:33:07

一、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 gdigrabWindows 屏幕捕获驱动
-f x11grabLinux 屏幕捕获驱动
-f avfoundationmacOS 屏幕/音频捕获驱动
-i desktop捕获整个屏幕(Windows)
-i :0.0Linux 主显示器(X11)
-f dshow -i audio="..."Windows 音频设备名(通过 ffmpeg -list_devices true -f dshow -i dummy 查询)
-f alsa -i defaultLinux 默认音频输入
-c:v libx264H.264 视频编码
-preset ultrafast编码速度优化(牺牲压缩率)
-crf 18视频质量(18~28,值越小质量越高)
-c:a aacAAC 音频编码
-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() {
    // 初始化 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 <iostream>
#include <Windows.h>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
}

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)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2327909.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

爬虫:请求头,requests库基本使用

请求方式&#xff1a;get(向服务器要资源)和post(提交资源) user-agent&#xff1a;模拟正常用户的一种方式 cookie&#xff1a;登陆保持 referer&#xff1a;表示当前这一次请求是由哪个请求过来的 抓取数据包得到的内容才是判断依据elements中的源码是渲染之后的不能作为…

[物联网iot]对比WIFI、MQTT、TCP、UDP通信协议

第一步&#xff1a;先理解最基础的关系&#xff08;类比快递&#xff09; 假设你要给朋友寄快递&#xff1a; Wi-Fi&#xff1a;相当于“公路和卡车”&#xff0c;负责把包裹从你家运到快递站。 TCP/UDP&#xff1a;相当于“快递公司的运输规则”。 TCP&#xff1a;顺丰快递&…

CSDN自动设置vip文章的解除办法

文章目录 CSDN真的会将“全部可见”文章偷偷自动设置为“VIP可读”最省事的途径&#xff1a;联系客服&#xff0c;预计1-2个工作日可以取消新版“内容管理”内手工操作 CSDN真的会将“全部可见”文章偷偷自动设置为“VIP可读” 今天无意中发现之前一些公开的文章变为仅VIP可读…

P4305 [JLOI2011] 不重复数字

使用stl中的动态数组和unordered_map #include<iostream> #include<iostream> #include<vector> #include<unordered_map> using namespace std; int t; int main(){cin>>t;while(t--){//每次处理一组数据.int n;cin>>n;vector<int&…

Joomla教程—Joomla 模块管理与Joomla 模块类型介绍

Joomla 模块管理 原文&#xff1a;Joomla 模块管理_w3cschool 模块管理&#xff0c;从文字意面上理解&#xff0c;可想而知&#xff0c;就是管理网站中所有的模块&#xff0c;模块的增、删、改、查都会在模块管理进行。这一节将简单介绍joomla后台的模块管理 1、模块管理的界…

安装gvm后普通用户模式下无法使用cd切换目录

安装gvm后普通用户模式下无法使用cd切换目录 今天装完gvm后发现无法使用cd来切换目录了。。。 1.使用type cd命令发现cd命令被定义为了函数 usrusr-pc:~$ type cd cd 是函数 cd () { if __gvm_is_function __gvm_oldcd; then__gvm_oldcd $*;fi;local dot_go_version dot_go_…

Vue中虚拟DOM创建到挂载的过程

Vue中虚拟DOM创建到挂载的过程 流程概括下来基本上就是&#xff1a;模板 → AST → render函数 → 虚拟节点 → 挂载 AST&#xff1a;抽象语法树&#xff0c;它用于记录原始代码中所有的关键信息&#xff0c;根据AST可以将代码从一种语言转化为另一种语言。 虚拟DOM创建到挂载…

选择网上购物系统要看几方面?

随着电子商务的迅猛发展&#xff0c;选择一个合适的网上购物系统已成为许多企业成功的关键。无论是初创企业还是已经成熟的公司&#xff0c;选择合适的购物系统都能显著提升用户体验、提高销售额和优化运营效率。本文将从几个重要方面探讨选择网上购物系统时需要考虑的关键因素…

定制开发开源AI智能名片S2B2C商城小程序:技术赋能商业价值实现路径研究

摘要 在数字经济与社交新零售蓬勃发展的背景下&#xff0c;本研究聚焦"定制开发开源AI智能名片S2B2C商城小程序"这一创新技术解决方案&#xff0c;通过解析其技术架构、功能模块及业务应用场景&#xff0c;探讨其如何支持企业目标达成、补充技术栈短板、实现数据整合…

美关税加征下,Odoo免费开源ERP如何助企业破局?

近期&#xff0c;美国特朗普政府推行的关税政策对全球供应链和进出口企业造成巨大冲击&#xff0c;尤其是依赖中美贸易的企业面临成本激增、利润压缩和合规风险。在此背景下&#xff0c;如何通过数字化转型优化管理效率、降低运营成本成为企业生存的关键。本文以免费开源ERP系统…

Unity中 JobSystem使用整理

Unity 的JobSystem允许创建多线程代码&#xff0c;以便应用程序可以使用所有可用的 CPU 内核来执行代码&#xff0c;这提供了更高的性能&#xff0c;因为您的应用程序可以更高效地使用运行它的所有 CPU 内核的容量&#xff0c;而不是在一个 CPU 内核上运行所有代码。 可以单独使…

42.C++11-右值引用与移动语义/完美转发

⭐上篇文章&#xff1a;41.C哈希6&#xff08;哈希切割/分片/位图/布隆过滤器与海量数据处理场景&#xff09;-CSDN博客 ⭐本篇代码&#xff1a;c学习/22.C11新特性的使用 橘子真甜/c-learning-of-yzc - 码云 - 开源中国 (gitee.com) ⭐标⭐是比较重要的部分 目录 一. 右值引用…

LeetCode题二:判断回文

查阅资料我得到的结果远没有大佬们的做法更省时间&#xff0c;而且还很麻烦 我的代码(完整)&#xff1a; class Solution:def isPalindrome(self, x: int) -> bool:# 若 x 为负数&#xff0c;由于负数不可能是回文数&#xff0c;直接返回 Falseif x < 0:return False# …

[王阳明代数讲义]琴语言类型系统工程特性

琴语言类型系统工程特性 层展物理学组织实务与艺术与琴生生.物机.械科.技工.业研究.所软凝聚态物理开发工具包社会科学气质砥砺学人生意气场社群成员魅力场与心气微积分社会关系力学 意气实体过程图论信息编码&#xff0c;如来码导引 注意力机制道装Transformer架构的发展标度律…

问题:tomcat下部署eureka双重路径

开发时在tomcat下启动eureka服务 客户端注册时需要地址需要注意 http://localhost:8761/eureka/eureka 后面一个eureka与tomcat context-path有关系按实际配置替换 如果不想要两个path可将tomcat context-path写为 / 建议使用 / 避免出现其他问题 如图

React(九)React Hooks

初识Hook 我们到底为什么需要hook那? 函数组件类组件存在问题 函数组件存在的问题&#xff1a; import React, { PureComponent } from reactfunction HelloWorld2(props) {let message"Hello world"// 函数式组件存在的缺陷&#xff1a;// 1.修改message之后&a…

《AI大模型应知应会100篇》加餐篇:LlamaIndex 与 LangChain 的无缝集成

加餐篇&#xff1a;LlamaIndex 与 LangChain 的无缝集成 问题背景&#xff1a;在实际应用中&#xff0c;开发者常常需要结合多个框架的优势。例如&#xff0c;使用 LangChain 管理复杂的业务逻辑链&#xff0c;同时利用 LlamaIndex 的高效索引和检索能力构建知识库。本文在基于…

元素三大等待

硬性等待&#xff08;强制等待&#xff09; 线程休眠&#xff0c;强制等待 Thread.sleep(long millis);这是最简单的等待方式&#xff0c;使用time.sleep()方法来实现。在代码中强制等待一定的时间&#xff0c;不论元素是否已经加载完成&#xff0c;都会等待指定的时间后才继…

【DY】信息化集成化信号采集与处理系统;生物信号采集处理系统一体机

MD3000-C信息化一体机生物信号采集处理系统 实验平台技术指标 01、整机外形尺寸&#xff1a;1680mm(L)*750mm(w)*2260mm(H)&#xff1b; 02、实验台操作面积&#xff1a;750(w)*1340(L&#xff09;&#xff08;长*宽&#xff09;&#xff1b; 03、实验台面离地高度&#xf…

康谋分享 | 仿真驱动、数据自造:巧用合成数据重构智能座舱

随着汽车向智能化、场景化加速演进&#xff0c;智能座舱已成为人车交互的核心承载。从驾驶员注意力监测到儿童遗留检测&#xff0c;从乘员识别到安全带状态判断&#xff0c;座舱内的每一次行为都蕴含着巨大的安全与体验价值。 然而&#xff0c;这些感知系统要在多样驾驶行为、…