当前位置: 首页 > news >正文

Linux(含麒麟操作系统)如何实现多显示器屏幕采集录制

技术背景

在操作系统领域,很多核心技术掌握在国外企业手中。如果过度依赖国外技术,在国际形势变化、贸易摩擦等情况下,可能面临技术封锁和断供风险。开发国产操作系统可以降低这种风险,确保国家关键信息基础设施的稳定运行。在一些敏感行业如国防、金融等,对技术的自主可控要求极高。

音视频信息在很多场合涉及国家安全和敏感内容。如果操作系统的音视频模块依赖国外技术,可能存在安全漏洞被利用的风险,导致国家机密信息泄露。自主开发的音视频模块可以进行更严格的安全管控,增强国家信息安全防护能力。

在这样的背景下,我们实现了Linux平台下的以屏幕采集、摄像头采集、麦克风扬声器采集为数据源的RTMP推送模块、轻量级RTSP服务模块,和RTMP播放器和RTSP播放器模块,并同时覆盖了x86-64架构和aarch64架构。

技术实现

xrandr

本文我们要讨论的是,如何在Linux平台实现多显示器的屏幕采集录制。我们知道,Linux下,X Window Sysem支持多显示器的配置和显示器列表获取。可以使用xrandr查看显示器列表:

xrandr --listactivemonitors” 可在Linux 系统中用于显示当前活动监视器信息的命令。

命令作用

  1. 显示连接状态

    • 该命令可以列出当前连接到系统的所有活动监视器,包括其名称、分辨率、刷新率以及位置信息等。通过查看这些信息,你可以了解到每个监视器的连接状态和基本参数。
    • 例如,如果你连接了多个显示器,这个命令可以帮助你确定哪些显示器是处于活动状态的,以及它们的具体配置。
  2. 帮助配置多显示器

    • 对于使用多显示器的用户来说,这个命令非常有用。它可以让你了解当前的显示器布局,以便更好地进行配置和调整。
    • 你可以根据命令输出的信息,使用其他 xrandr 命令来设置显示器的分辨率、位置、旋转等参数,实现个性化的多显示器设置。

如何使用libXrandr获取显示器列表

先看看Xrandr.h

/** Copyright © 2000 Compaq Computer Corporation, Inc.* Copyright © 2002 Hewlett-Packard Company, Inc.* Copyright © 2006 Intel Corporation* Copyright © 2008 Red Hat, Inc.** Permission to use, copy, modify, distribute, and sell this software and its* documentation for any purpose is hereby granted without fee, provided that* the above copyright notice appear in all copies and that both that copyright* notice and this permission notice appear in supporting documentation, and* that the name of the copyright holders not be used in advertising or* publicity pertaining to distribution of the software without specific,* written prior permission.  The copyright holders make no representations* about the suitability of this software for any purpose.  It is provided "as* is" without express or implied warranty.** THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE* OF THIS SOFTWARE.** Author:  Jim Gettys, HP Labs, Hewlett-Packard, Inc.*	    Keith Packard, Intel Corporation*/#ifndef _XRANDR_H_
#define _XRANDR_H_#include <X11/extensions/randr.h>
#include <X11/extensions/Xrender.h>#include <X11/Xfuncproto.h>_XFUNCPROTOBEGINtypedef struct _XRRMonitorInfo {Atom name;Bool primary;Bool automatic;int noutput;int x;int y;int width;int height;int mwidth;int mheight;RROutput *outputs;
} XRRMonitorInfo;XRRMonitorInfo *
XRRAllocateMonitor(Display *dpy, int noutput);XRRMonitorInfo *
XRRGetMonitors(Display *dpy, Window window, Bool get_active, int *nmonitors);void
XRRSetMonitor(Display *dpy, Window window, XRRMonitorInfo *monitor);void
XRRDeleteMonitor(Display *dpy, Window window, Atom name);void
XRRFreeMonitors(XRRMonitorInfo *monitors);_XFUNCPROTOEND#endif /* _XRANDR_H_ */

我们Linux平台RTMP推送、轻量级RTSP服务设计的选择接口如下:

/** nt_liunx_smart_publisher_sdk.h* Author: daniusdk.com* WeChat: xinsheng120*/
/*
* 获取active XRR-Monitor列表, X RandR 1.5及以上版本支持(可以用:"xrandr --version"查看版本)
* x_display_name:传入实际使用的名称或者NULL,调用XOpenDisplay时使用.
* monitors: 预分配的XRR-Monitor数组
* monitors_array_size: 预分配的XRR-Monitor数组长度
* out_count: 返回实际的XRR-Monitor数量
* 成功返回:NT_ERC_OK, 如果返回值是:NT_ERC_MORE_DATA, 说明预分配的数组长度不够, 请分配更大的数组再尝试.
*/
NT_UINT32 NT_API NT_PB_GetXRRMonitors(NT_PCSTR x_display_name, NT_PB_XRR_MonitorBaseInfo* monitors, NT_INT32 monitors_array_size, NT_INT32* out_count);/*
* 设置要采集的XRRMonitor id, 采集X屏幕时使用
* xrr_monitor_id: -1:采集所有屏幕, SDK默认为-1.
*/
NT_UINT32 NT_API NT_PB_SetCaptureXRRMonitor(NT_HANDLE handle, NT_INT64 xrr_monitor_id);

 NT_PB_GetXRRMonitors()可以获取active XRR-Monitor列表。

NT_PB_SetCaptureXRRMonitor()设置要采集的XRRMonitor id, 采集X屏幕时使用。

以RTMP推送模块为例,目前我们的功能设计如下:

Linux平台x64_64架构|aarch64架构RTMP直播推送模块

  • 音频编码:AAC/SPEEX;
  • 视频编码:H.264;
  • 推流协议:RTMP;
  • [音视频]支持纯音频/纯视频/音视频推送;
  • 支持X11屏幕采集;
  • 支持部分V4L2摄像头设备采集;
  • [屏幕/V4L2摄像头]支持帧率、关键帧间隔(GOP)、码率(bit-rate)设置;
  • [V4L2摄像头]支持V4L2摄像头设备选择(设备文件名范围:[/dev/video0, /dev/video63])、分辨率设置、帧率设置;
  • [V4L2摄像头]支持水平反转、垂直反转、0° 90° 180° 270°旋转;
  • [音频]支持基于alsa-lib接口的音频采集;
  • [音频]支持基于libpulse接口采集本机PulseAudio服务音频;
  • [预览]支持推送端实时预览;
  • [对接服务器]支持自建标准RTMP服务器或CDN;
  • 支持断网自动重连、网络状态回调;
  • 屏幕和摄像头合成/多层合成;
  • 支持窗口采集(一般不建议使用);
  • 支持实时快照;
  • 支持降噪处理、自动增益控制、VAD端点检测;
  • 支持扬声器和麦克风混音;
  • 支持外部编码前音视频数据对接;
  • 支持外部编码后音视频数据对接;
  • 支持实时音量调节;
  • 支持扩展录像模块;
  • 支持Unity接口;
  • 支持H.264扩展SEI发送模块;
  • 支持x64_64架构、aarch64架构(需要glibc-2.21及以上版本的Linux系统, 需要libX11.so.6, 需要GLib–2.0, 需安装 libstdc++.so.6.0.21、GLIBCXX_3.4.21、 CXXABI_1.3.9)。

RTMP推送调用示例

以大牛直播SDK的Linux平台RTMP直播推送模块为例,本Demo实现的是Linux上实现桌面和系统声音采集,然后使用RTMP协议推出去的一个SDK. 集成调用非常简单。

int main(int argc, char *argv[])
{signal(SIGINT, &OnSigIntHandler);//printf("sizeof(NT_SmartPublisherSDKAPI)=%d\n", sizeof(NT_SmartPublisherSDKAPI));LogInit();NT_SmartPublisherSDKAPI push_api;if (!PushSDKInit(push_api)){return 0;}auto push_handle = StartPush(&push_api, "rtmp://192.168.0.154:1935/live/test1", 30);if (!push_handle){fprintf(stderr, "start push failed.\n");push_api.UnInit();return 0;}while (!g_is_exit){sleep(2);}fprintf(stdout, "Skip run loop, is_exit:%d\n", g_is_exit);push_api.StopPublisher(push_handle);push_api.Close(push_handle);push_handle = nullptr;push_api.UnInit();fprintf(stdout, "SDK UnInit..\n");return 0;
}

相关初始化

	void OnSigIntHandler(int sig){if (SIGINT == sig){g_is_exit = true;}}void LogInit(){SmartLogAPI log_api;memset(&log_api, 0, sizeof(log_api));GetSmartLogAPI(&log_api);log_api.SetLevel(SL_INFO_LEVEL);log_api.SetPath((NT_PVOID)"./");}bool PushSDKInit(NT_SmartPublisherSDKAPI& push_api){memset(&push_api, 0, sizeof(push_api));NT_GetSmartPublisherSDKAPI(&push_api);auto ret = push_api.Init(0, nullptr);if (NT_ERC_OK != ret){fprintf(stderr, "push_api.Init failed!\n");return false;}else{fprintf(stdout, "push_api.Init ok!\n");}return true;}

推送接口封装

	NT_HANDLE StartPush(NT_SmartPublisherSDKAPI* push_api, const std::string& rtmp_url, int dst_fps){NT_INT32 pulse_device_number = 0;if (NT_ERC_OK == push_api->GetAuidoInputDeviceNumber(2, &pulse_device_number)){fprintf(stdout, "Pulse device num:%d\n", pulse_device_number);char device_name[512];for (auto i = 0; i < pulse_device_number; ++i){if (NT_ERC_OK == push_api->GetAuidoInputDeviceName(2, i, device_name, 512)){fprintf(stdout, "index:%d name:%s\n", i, device_name);}}}NT_INT32 alsa_device_number = 0;if (pulse_device_number < 1){if (NT_ERC_OK == push_api->GetAuidoInputDeviceNumber(1, &alsa_device_number)){fprintf(stdout, "Alsa device num:%d\n", alsa_device_number);char device_name[512];for (auto i = 0; i < alsa_device_number; ++i){if (NT_ERC_OK == push_api->GetAuidoInputDeviceName(1, i, device_name, 512)){fprintf(stdout, "index:%d name:%s\n", i, device_name);}}}}NT_INT32 capture_speaker_flag = 0;if ( NT_ERC_OK == push_api->IsCanCaptureSpeaker(2, &capture_speaker_flag) ){if (capture_speaker_flag)fprintf(stdout, "Support speaker capture\n");elsefprintf(stdout, "UnSupport speaker capture\n");}NT_INT32 is_support_window_capture = 0;if (NT_ERC_OK == push_api->IsCaptureWindowSupported(NULL, &is_support_window_capture)){if (is_support_window_capture)fprintf(stdout, "Support window capture\n");elsefprintf(stdout, "UnSupport window capture\n");}NT_HANDLE push_handle = nullptr;// if (NT_ERC_OK != push_api->Open(&push_handle, NT_PB_E_VIDEO_OPTION_LAYER, NT_PB_E_AUDIO_OPTION_CAPTURE_SPEAKER, 0, NULL))if (NT_ERC_OK != push_api->Open(&push_handle, NT_PB_E_VIDEO_OPTION_SCREEN, NT_PB_E_AUDIO_OPTION_CAPTURE_SPEAKER, 0, NULL)){return nullptr;}//push_api->SetXDisplayName(push_handle, ":0");//push_api->SetXDisplayName(push_handle, NULL);// 视频层配置方式//std::vector<std::shared_ptr<nt_pb_sdk::layer_conf_wrapper_base> > layer_confs;//auto index = 0;第0层填充RGBA矩形, 目的是保证帧率, 颜色就填充全黑//auto rgba_layer_c0 = std::make_shared<nt_pb_sdk::RGBARectangleLayerConfigWrapper>(index++, true, 0, 0, 1280, 720);//rgba_layer_c0->conf_.red_ = 0;//rgba_layer_c0->conf_.green_ = 0;//rgba_layer_c0->conf_.blue_ = 0;//rgba_layer_c0->conf_.alpha_ = 255;//layer_confs.push_back(rgba_layer_c0);第一层为桌面层//auto screen_layer_c1 = std::make_shared<nt_pb_sdk::ScreenLayerConfigWrapper>(index++, true, 0, 0, 1280, 720);////screen_layer_c1->conf_.scale_filter_mode_ = 3;//layer_confs.push_back(screen_layer_c1);//std::vector<const NT_PB_LayerBaseConfig* > layer_base_confs;//for (const auto& i : layer_confs)//{//	layer_base_confs.push_back(i->getBase());//}//if (NT_ERC_OK != push_api->SetLayersConfig(push_handle, 0, layer_base_confs.data(),//	layer_base_confs.size(), 0, nullptr))//{//	push_api->Close(push_handle);//	push_handle = nullptr;//	return nullptr;//}// push_api->SetScreenClip(push_handle, 0, 0, 1280, 720);push_api->SetFrameRate(push_handle, dst_fps); // 帧率设置push_api->SetVideoBitRate(push_handle, 2000);  // 平均码率2000kbpspush_api->SetVideoQualityV2(push_handle, 26); push_api->SetVideoMaxBitRate(push_handle, 4000); // 最大码率4000kbpspush_api->SetVideoKeyFrameInterval(push_handle, dst_fps*2); // 关键帧间隔push_api->SetVideoEncoderProfile(push_handle, 3); // h264 baselinepush_api->SetVideoEncoderSpeed(push_handle, 3); // 编码速度设置到3if (pulse_device_number > 0){push_api->SetAudioInputLayer(push_handle, 2);push_api->SetAuidoInputDeviceId(push_handle, 0);}else if (alsa_device_number > 0){push_api->SetAudioInputLayer(push_handle, 1);push_api->SetAuidoInputDeviceId(push_handle, 0);}// 音频配置push_api->SetPublisherAudioCodecType(push_handle, 1);//push_api->SetMute(push_handle, 1);if ( NT_ERC_OK != push_api->SetURL(push_handle, rtmp_url.c_str(), NULL) ){push_api->Close(push_handle);push_handle = nullptr;return nullptr;}if ( NT_ERC_OK != push_api->StartPublisher(push_handle, NULL) ){push_api->Close(push_handle);push_handle = nullptr;return nullptr;}return push_handle;}

相关文章:

Linux(含麒麟操作系统)如何实现多显示器屏幕采集录制

技术背景 在操作系统领域&#xff0c;很多核心技术掌握在国外企业手中。如果过度依赖国外技术&#xff0c;在国际形势变化、贸易摩擦等情况下&#xff0c;可能面临技术封锁和断供风险。开发国产操作系统可以降低这种风险&#xff0c;确保国家关键信息基础设施的稳定运行。在一…...

calibre-web默认左上角字体修改

calibre-web默认左上角字体修改 如图&#xff1a; 有些奇异&#xff0c;如果想变成正常的常规字体&#xff0c;需要修改&#xff1a; cps\static\css\style.css 下的代码&#xff1a; 默认是GrandHotel-Regular&#xff1a; 换成其他字体即可。其他字体在 calibre-web\cps\s…...

考研数据结构——C语言实现归并排序

包含头文件&#xff1a;程序首先包含了标准输入输出库stdio.h&#xff0c;以便使用printf等函数进行输入输出操作。 定义数组和数组大小&#xff1a;定义了一个宏N&#xff0c;其值为5&#xff0c;表示数组q的长度。数组q被初始化为{5, 3, 8, 4, 2}&#xff0c;这是我们要排序…...

LDO功率管选取NMOS和PMOS区别

一、drop电压 LDO如果两个管子流过相同的电流, 假设将管子饱和并顶到接近线性区 NMOS的效率(VIN-VDSAT-VGS)/VIN PMOS的效率&#xff1d;&#xff08;VIN-VDSAT)/VIN 根本原因是 nmos的gate电压比source高vth 如果输出电压(source&#xff09;较高或者驱动电流要大&#xff0c…...

【Linux】进程的标识符、状态(超详解)

目录 进程的概念 进程标识符PID 系统调用创建进程-fork初识 进程状态 R状态&#xff08;运行状态&#xff09; S&#xff0c;D状态&#xff08;休眠状态&#xff09; T&#xff0c;t状态 Z状态&#xff08;僵尸进程&#xff09; 孤儿进程 X状态&#xff08;死亡状态&a…...

Elasticsearch 启动后在浏览器输入http://localhost:9200 访问失败

windows Elasticsearch 启动后在浏览器输入http://localhost:9200 访问失败 文章目录 前言本地下载安装了个elasticsearch&#xff0c;启动成功了&#xff0c;在本地访问http://localhost:9200 无法访问&#xff01;&#xff01;&#xff01;难受了一下。 一、windows Elastics…...

javascript中new操作符的工作原理

在 JavaScript 中&#xff0c;new 操作符用于创建对象的实例。它可以让我们通过构造函数创建一个新的对象&#xff0c;并初始化该对象的属性和方法。尽管 new 操作符的使用很常见&#xff0c;但它在背后实际进行了几个步骤。下面详细解释 new 操作符具体做了哪些事情。 new 操…...

基于springboot+vue 旅游网站的设计与实现

基于springbootvue 旅游网站的设计与实现 摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对信息管理混乱&#xff0c…...

Ansible集群服务部署案例

案例描述 本案例共讲述了多个节点部署Elk集群日志分析系统&#xff0c;分别在三个节点使用ansible部署Kibana、Logstash以及Elasticsearch服务。 案例准备 1. 规划节点 IP 主机名 节点 192.168.100.25 ansible Ansible节点 192.168.100.35 node1 Elasticsearch/Kiba…...

探索AI编程新境界:aider库揭秘

文章目录 **探索AI编程新境界&#xff1a;aider库揭秘**背景&#xff1a;为何选择aider&#xff1f;简介&#xff1a;aider是什么&#xff1f;安装指南&#xff1a;如何安装aider&#xff1f;功能演示&#xff1a;aider的简单用法实战应用&#xff1a;aider在不同场景下的使用常…...

SQL Server 2012 ldf日志文接太大的截断和收缩日志处理

SQL Server 2012 ldf日志文接太大的截断和收缩日志处理操作 --- SQL Server 2012 ldf日志文接太大的截断和收缩日志处理 ----- 查看所有 database 列表及详情 select * from sys.databases;-- 切换到指定的操作数据库 use testdb;-- 查询当前数据库的日志文件ID和逻辑文件名 S…...

java日志门面之JCL和SLF4J

文章目录 前言一、JCL1、JCL简介2、快速入门3、 JCL原理 二、SLF4J1、SLF4J简介2、快速入门2.1、输出动态信息2.2、异常信息的处理 3、绑定日志的实现3.1、slf4j实现slf4j-simple和logback3.2、slf4j绑定适配器实现log4j 4、桥接旧的日志框架4.1、log4j日志重构为slf4jlogback的…...

Oracle DB运维常用的视图及数据字典

List item 本文介绍一些Oracle DB日常运维最常用到&#xff08;使用频率很高&#xff09;的视图及数据字典 用户有关的常用视图&#xff1a; 1、 查看当前用户的缺省表空间* SQL>select username,default_tablespace from user_users; 2、 查看当前用户的角色 SQL>sele…...

vue.config.js devServer中changeOrigin的作用

问题 vue开发时&#xff0c;为了解决前端跨域问题&#xff0c;通常在vue.config.js配置 devServer proxy devServer: {proxy:{/api: {target: http://b.com,changeOrigin: false},}, }官方文档http-proxy options对changeOrigin的解释 option.changeOrigin: true/false, Defa…...

基于Ubuntu 20.04 LTS上部署MicroK8s(最小生产的 Kubernetes)

目录 文章目录 目录简介Kubernetes简介MicroK8s简介Ubuntu系统MicroK8s的优势安装环境基本要求执行安装命令加入群组(使用非 root 用户访问)开启 dashboard 仪表盘查看服务名称查看仪表盘开放的端口打开浏览器检查状态打开你想要的服务(使用附加组件)开始使用 microk8s访问 Kub…...

Spring:项目中的统一异常处理和自定义异常

介绍异常的处理方式。在项目中&#xff0c;都会进行自定义异常&#xff0c;并且都是需要配合统一结果返回进行使用。 1.背景引入 &#xff08;1&#xff09;背景介绍 为什么要处理异常&#xff1f;如果不处理项目中的异常信息&#xff0c;前端访问我们后端就是显示访问失败的…...

有点快要跟不上时代的感觉

团队的群里面有一个同事突然问了下&#xff0c;下面的这个 JavaScript 如何进行优化 var startIndex (start undefined || start null) ? null : start[0].Value;看上面的代码就是典型的判断和返回的问题。 如果是要调试的话也不是做不出来&#xff0c;但可能要花点时间&a…...

【pytorch】pytorch入门4:神经网络的卷积层

文章目录 前言一、定义概念 缩写二、性质三、代码总结参考文献 前言 使用 B站小土堆课程的笔记 一、定义概念 缩写 卷积层是神经网络中用于突出特征来进行分类任务的层。 二、性质 卷积核例子&#xff1a;vgg16 model 三、代码 添加库 python代码块import os import …...

【机器学习】探索LSTM:深度学习领域的强大时间序列处理能力

目录 &#x1f354; LSTM介绍 &#x1f354; LSTM的内部结构图 2.1 LSTM结构分析 2.2 Bi-LSTM介绍 2.3 使用Pytorch构建LSTM模型 2.4 LSTM优缺点 &#x1f354; 小结 学习目标 &#x1f340; 了解LSTM内部结构及计算公式. &#x1f340; 掌握Pytorch中LSTM工具的使用. &…...

QT学习笔记之文件操作

你千万不要跟任何人谈起任何事。你只要一谈起&#xff0c;就会想念起每一个人来。 在ui界面添加一个LineEdit(lEt)、QPushButton(btn)、QWidget widget.cpp #include "widget.h" #include "ui_widget.h" #include <QFile> #include <QFileDialo…...

Mybatis XML配置文件操作数据库

Mybaits在操作数据库时&#xff0c;可以有两种方式&#xff1b;第一种是使用注解的方式操作&#xff0c;另一种是使用XML配置文件的方式&#xff1a;一般而言&#xff0c;若没有特别的要求&#xff0c;则编写一些简单的SQL语句&#xff0c;可以直接使用注解的方式&#xff1b;编…...

Ansible-template模块动态生成特定文件

文章目录 一、Jinja2介绍什么是主要特性安装基本用法进阶特性总结 Jinja2与Ansible关系1. 模板引擎2. Ansible 的依赖3. 变量和模板4. 动态生成配置5. 社区和生态系统总结 二、Ansible如何使用Jinja2使用template模块Jinja2文件中使用判断和循环Jinja2文件中使用判断语法 Jinja…...

【Hadoop】【vim编辑器】【~/.bashrc 文件】如何编辑

1. 进入 vim 编辑器 在终端中输入以下命令&#xff1a; vim ~/.bashrc 2. 进入插入模式 打开文件后&#xff0c;你将处于普通模式。在普通模式下&#xff0c;你不能直接编辑文本。 要进入插入模式&#xff0c;请按下 i 键。这时&#xff0c;你应该会看到屏幕底部出现 -- 插…...

vs code自动报错

让vs code自动报错&#xff0c; 点击插件 → 搜索error lens → 点击install&#xff0c; 下载完后&#xff0c;编写的代码有问题就会自动报错了。 5、修改默认缩进字符 点击设置&#xff08;settings&#xff09; → 点击常用设置 → 修改字符缩进。...

详细分析Nginx中的proxy_pass 末尾斜杠

目录 前言1. 基本知识2. Demo 前言 对于Nginx的讲解&#xff0c;更多推荐阅读&#xff1a; Nginx配置静态网页访问&#xff08;图文界面&#xff09;Nginx将https重定向为http进行访问的配置&#xff08;附Demo&#xff09;Nginx从入门到精通&#xff08;全&#xff09;详细分…...

数据结构:双指针—移动0(OJ283)

给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0]示例 2: 输入: nums [0] 输出: […...

LeetCode - 850 矩形面积 II

题目来源 850. 矩形面积 II - 力扣&#xff08;LeetCode&#xff09; 题目描述 给你一个轴对齐的二维数组 rectangles 。 对于 rectangle[i] [x1, y1, x2, y2]&#xff0c;其中&#xff08;x1&#xff0c;y1&#xff09;是矩形 i 左下角的坐标&#xff0c; (xi1, yi1) 是该…...

Jenkins Pipeline 中通过勾选参数来控制是否构建 Docker 镜像

1.定义参数&#xff1a; 使用 booleanParam 定义一个布尔参数&#xff0c;示例如下 booleanParam(name: BUILD_DOCKER, description: 是否构建Docker镜像, defaultValue: false)2.使用参数&#xff1a; 在 stage 中&#xff0c;根据参数的值决定构建方式&#xff1a; stage(编…...

C++入门基础知识86(实例)——实例11【计算自然数之和】

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于计算自然数之和相关内容&#xff01; 关…...

ChatGPT与R语言融合技术在生态环境数据统计分析、绘图、模型中的实践与进阶应用

自2022年GPT&#xff08;Generative Pre-trained Transformer&#xff09;大语言模型的发布以来&#xff0c;它以其卓越的自然语言处理能力和广泛的应用潜力&#xff0c;在学术界和工业界掀起了一场革命。在短短一年多的时间里&#xff0c;GPT已经在多个领域展现出其独特的价值…...