视频编解码学习十二之Android疑点
一、android.view.SurfaceControl.setDisplaySurface的作用
android.view.SurfaceControl.setDisplaySurface
是 Android 系统中一个 native 层级别的 API,主要用于 设置某个物理显示屏(Display)的输出 Surface,属于 SurfaceFlinger 的一部分功能。这个 API 并不是应用开发常用的接口,而是系统或原始设备制造商(OEM)用于控制显示输出的低层接口。
🔧 作用解析
SurfaceControl.setDisplaySurface(SurfaceControl displayToken, Surface surface)
的主要作用是:
将一个 Surface 与特定的 Display(显示设备)绑定,使该 Surface 成为该 Display 的渲染目标。
也就是说,这个接口决定了 某个显示屏最终画面要显示到哪个 Surface 上,可以理解为是 SurfaceFlinger 告诉硬件:“你应该把图像输出到这个 Surface 对应的物理设备上。”
📦 参数说明
-
displayToken
: 一个代表物理 Display 的 token,通常通过SurfaceControl.getInternalDisplayToken()
或类似接口获得。 -
surface
: 目标 Surface,用于接收最终的图像内容。比如一个SurfaceTexture
或SurfaceView
所提供的Surface
。
📍 使用场景
此函数多用于系统级的图像输出控制,比如:
-
投屏系统(屏幕镜像):系统想要将主屏内容输出到一个 HDMI 显示器或虚拟显示上。
-
多屏协作/扩展显示:比如一台 Android 设备连接多个显示器时,需要绑定每个显示器的输出 Surface。
-
截图或录屏:系统通过一个 Surface 捕获整个 Display 的输出内容。
-
系统 UI 渲染控制:用于系统引导期间或锁屏、开机动画等控制显示。
🧪 注意事项
-
这个 API 是 隐藏的、系统级别的,普通应用无法直接调用。
-
使用它需要 系统权限,并且通常配合
SurfaceComposerClient
、SurfaceFlinger
或 AIDL 接口工作。 -
设置错误或参数异常可能会导致显示黑屏、卡死或输出内容不正常。
📚 相关源码路径(AOSP)
在 AOSP 源码中,你可以看到它的实现大致在以下路径中:
plaintext
复制编辑
frameworks/base/core/java/android/view/SurfaceControl.java frameworks/native/libs/gui/SurfaceComposerClient.cpp frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
具体来说,Java 层只是包装,最终会调用到 native 层通过 binder 调用 SurfaceFlinger
的 setDisplaySurface
.
二、Display是物理显示设备吗?
是的,在 SurfaceControl.setDisplaySurface
的上下文中,Display
是指物理显示设备(physical display device)。
📌 详细说明
✅ 在这个上下文中的 Display
含义:
-
指的是一个实际存在的硬件输出设备,比如:
-
内置屏幕(手机、平板的主屏)
-
外接 HDMI 显示器
-
无线显示器(Miracast、WiDi)
-
虚拟显示设备(在系统看来也被当成一个“显示”,但可能是用于录屏或投屏)
-
-
Android 系统中的
DisplayToken
(在 native 层)代表的就是这种显示设备的引用,和 Java 层Display
类不是同一个概念,但都是为了描述某个显示目标。
🎯 举个例子:
你可以通过 native 层(比如 C++ 中的 SurfaceComposerClient
)调用:
cpp
复制编辑
sp<IBinder> display = SurfaceComposerClient::getInternalDisplayToken();
这个 display
就是系统主屏幕的 display token,它在调用:
java
复制编辑
SurfaceControl.setDisplaySurface(display, surface);
时被用来绑定输出 surface。
这表示:“我希望把主屏幕的输出,显示到这个 surface 上。”
🔁 对比:Java 层的 Display
在 Java 层中,也有一个 android.view.Display
类,这个类通常是代表系统中抽象出来的显示输出,常用于多窗口、投屏等,但它和 SurfaceControl.setDisplaySurface
所用的 displayToken
并不直接等价。
🧠 补充:物理 Display 的获取
在系统或 native 开发中,可以通过如下方式获取 display:
cpp
复制编辑
sp<IBinder> token = SurfaceComposerClient::getInternalDisplayToken(); // 主屏幕 sp<IBinder> token = SurfaceComposerClient::getExternalDisplayToken(); // 外接屏幕
✅ 结论
是的,
Display
在setDisplaySurface()
中指的是 一个物理或系统级的显示设备,通常代表的是 硬件屏幕输出接口,比如内屏、HDMI、虚拟显示等。
三、display和surface是什么关系?
这是个很核心的问题,在 Android 图形系统(特别是 SurfaceFlinger
和 SurfaceControl
)中:
🎯 简明结论:
Display
是“输出目标”(比如屏幕),而
Surface
是“内容来源”(谁要被显示)。
通过 setDisplaySurface(display, surface)
,你告诉系统:
“请把这个
Surface
的内容,作为这个Display
的显示输出。”
🧱 各自的定义和角色
概念 | 定义 | 在图形系统中的作用 |
---|---|---|
Display | 代表一个物理显示设备或虚拟显示目标。 | 最终图像的去处(输出目标) |
Surface | 一个可以被写入图像内容的缓冲区,比如由应用或系统提供 | 图像内容的来源(输入图层或缓冲区) |
📦 具体关系理解:
在 Android 中,一个典型的图像渲染流程是这样的:
-
应用或系统绘制内容 → 写入某个
Surface
-
SurfaceFlinger
收集所有Surface
→ 合成(Compose) -
合成好的最终图像 → 输出到某个
Display
这个流程可以简化为:
rust
复制编辑
多个 Surface(图层) --合成--> 最终帧图像 --送出--> Display
🧩 setDisplaySurface()
的作用
这个函数的作用是:
“把这个显示设备(
Display
)的最终输出图像放入这个Surface
中。”
常用于这些场景:
-
录屏:你把一个
Surface
设置为显示的输出,这样它会收到完整的画面内容 -
投屏:将主显示的画面输出到一个外接 HDMI/无线显示的 Surface
-
多显示系统:为每个显示设备配置自己的输出 Surface
🖼️ 举个实际例子
比如你在开发一个系统级的投屏功能:
-
你创建一个虚拟显示
Display
(比如通过SurfaceComposerClient.createDisplay()
) -
你创建一个
Surface
(比如基于 SurfaceTexture 或 BufferQueue) -
你用
setDisplaySurface(display, surface)
将两者绑定
这表示:这个虚拟显示产生的画面,将写入这个 Surface 中,你可以用这个 Surface 编码、传输或其他处理。
🧠 类比理解
可以把它类比为:
-
Display
是 电视机 -
Surface
是 HDMI 线接口的输入源
你可以把某个视频源(Surface)接到电视(Display)上,让它显示出来。
✅ 总结:
项目 | Display | Surface |
---|---|---|
是什么 | 显示目标(物理或虚拟屏幕) | 内容缓冲区(应用写图像的地方) |
作用 | 显示画面的“去向” | 提供画面的“来源”或“容器” |
使用位置 | 输出、目标端 | 输入、内容端 |
SurfaceControl.setDisplaySurface(display, surface)
就是连接两者的桥梁 —— 把 谁要显示的内容(surface) 输出到 哪个屏幕(display) 上。
四、setDisplaySurface()中,当display是主屏,surface是虚拟屏的surface,是相当于把主屏的内容复制到虚拟屏上,还是会影响主屏的显示?
下面我来给你准确、深入地解析。
✅ 简要回答:
setDisplaySurface(display=主屏, surface=虚拟屏的 surface)
表示:你将主屏的最终图像输出到这个 surface 中,
✅ 是复制主屏内容(画面镜像),而不是影响主屏显示。
即:
-
主屏继续正常显示
-
你只是在“拷贝”它的画面到另一个 Surface,用于录制、投屏等目的
🧠 更详细解释:
📌 setDisplaySurface()
的行为是什么?
它不是把 surface
当作某个图层,而是把它当成 Display 的输出缓冲区(Framebuffer)。
这意味着:
-
Display 原本输出是发到物理屏的,现在你通过这个 API 拦截了这个输出,让它 输出到你指定的 Surface。
-
被指定的
surface
会接收到合成后的整帧图像(就是用户当前看到的整个屏幕),相当于屏幕的“镜像帧”拷贝。
📊 举个例子(场景对照)
场景 | display | surface | 结果 |
---|---|---|---|
录屏 | 主屏 | 一个 Surface (比如 MediaProjection 提供的) | 你会收到主屏的内容帧,但不影响主屏显示 |
投屏 | 主屏 | 外接设备的 buffer(通过网络或 HDMI 虚拟) | 外设看到主屏内容,主屏依然显示 |
反例 | 主屏 | App 提供的 Surface,并作为图层提交 | 你会替换部分图层内容,不是复制 |
🚧 注意事项(系统开发中):
-
你是在设置合成后的结果的输出目标,不是控制图层。
-
这个操作通常 需要系统权限或 Root 权限。
-
如果你只想“显示”某个 Surface 的内容,应该用
SurfaceControl.setLayer()
之类的 API,而不是setDisplaySurface()
。 -
不能频繁更改
setDisplaySurface()
,它是低频、系统级的配置操作。
📚 对应 Android 系统中的用法:
比如 Android 的录屏、投屏服务(如 SurfaceFlinger::doComposition()
的输出流程),就是:
-
使用一个虚拟
Surface
作为输出 -
设置主屏的
Display
输出到该Surface
-
继续正常渲染主屏,不会影响物理屏幕的显示
这种方式是目前 Android 中录屏、无线投屏的基础机制。
✅ 结论重申:
setDisplaySurface(主屏, 虚拟 Surface)
是一种不影响主屏显示的“画面复制”操作,
你只是“截获”了主屏的合成输出结果,输出到了另一个 Surface 中。
五、像这样把主屏内容复制到另一个surface中通常需要花多长时间?
这个问题非常关键,尤其涉及 性能、时延 和 帧同步。我们来拆解一下:
✅ 简短答案:
把主屏内容复制到另一个
Surface
(如录屏、投屏用的)通常不需要额外的耗时,拷贝几乎是“零成本”的 DMA 或硬件合成输出操作。延迟一般控制在 1~2 帧内(16~33ms 左右)甚至更低。
🧠 为什么这么快?背后发生了什么?
这并不是“CPU 上逐像素拷贝”,而是:
🔧 GPU/HWComposer/SurfaceFlinger 一体完成:
-
SurfaceFlinger
将所有 Layer 合成为一帧时,会根据设置:-
将这一帧输出给物理 Display(正常显示)
-
同时输出到你指定的
Surface
(投屏、录屏)
-
✅ 输出操作不是“复制”,而是“多路输出”
-
通常使用 硬件层的双输出/双写 DMA(Dual-Write DMA) 或 GPU多目标渲染
-
输出到显示器 + 输出到 Surface 可以并行进行
-
所以这个操作几乎不会增加帧合成的总时长(不会影响 UI 响应)
📉 实测延迟范围(参考值):
场景 | 输出方式 | 延迟(帧) | 延迟(毫秒) |
---|---|---|---|
系统级录屏(MediaProjection) | framebuffer copy / virtual display | 1~2 帧 | ~16ms - 33ms |
Wireless Display(Miracast) | surface + 编码 + 网络发送 | 2~4 帧 | ~30ms - 60ms |
HDMI 拓展屏幕复制 | 多路输出 | 接近 0 帧 | < 10ms |
🔍 有哪些因素可能拖慢这个操作?
虽然复制本身快,但以下环节可能造成延迟:
-
Surface 所连接的 BufferQueue 阻塞
-
如果下游(编码器、网络)处理慢,
surface
的消费端来不及消费,就会卡住生产者
-
-
图像格式转换
-
如果目标
Surface
只接受某种格式(如 YUV),而主屏是 RGB,系统需要转换格式,会增加 GPU 负担
-
-
目标
Surface
在另一个进程或 Binder 中跨进程通信-
会带来一次内核用户态上下文切换,产生 1~2ms 延迟
-
-
设备性能差、GPU 压力大
-
可能会造成合成时间整体变慢(但这是系统问题)
-
🔧 优化建议(如你在开发系统服务):
-
使用 硬件合成直出路径(如通过 HWC2 设置 Dual output)
-
减少
Surface
Buffer 格式转换(保持与 Display 相同) -
为目标
Surface
设置较高的BufferCount
(避免生产端等待) -
使用
setDisplaySurface()
而非copyLayer()
,避免 CPU 拷贝
✅ 总结
问题 | 回答 |
---|---|
会不会影响主屏显示? | ❌ 不会,属于多路输出,不干扰主屏 |
是 CPU 复制吗? | ❌ 不是,是 GPU 或 DMA 输出 |
速度有多快? | ✅ 通常在 1 帧内完成,约 16~33ms 延迟 |
有哪些性能影响因素? | Surface 堵塞、格式转换、跨进程通信等 |
六、延迟在什么范围内,才可以玩实时游戏?
你正在触及实时图像传输(如投屏游戏、云游戏、远程控制等)系统中的核心指标之一:端到端延迟。
✅ 简明结论
🎮 要实现“可玩”的实时游戏体验,总延迟应控制在 60ms 以下,理想情况在 30ms 以内。
🎯 延迟的等级划分(针对实时交互游戏)
延迟范围 | 用户感知 | 游戏体验 |
---|---|---|
< 30ms | 几乎无感知,媲美本地 | ✅ 理想、顺畅 |
30~60ms | 有轻微感觉,但可接受 | ✅ 可玩、流畅 |
60~100ms | 有明显延迟感 | ⚠️ 勉强能玩 |
> 100ms | 明显卡顿/延迟严重 | ❌ 不适合玩游戏 |
🧱 实时游戏延迟的组成部分(链路分析)
以“把主屏画面复制到另一个 surface 上用于远程实时游戏”为例,总延迟来自多个阶段:
阶段 | 操作 | 典型耗时 |
---|---|---|
🖼️ 渲染阶段 | 游戏帧在主屏被绘制完成 | 16ms(60fps) |
📤 复制阶段 | 主屏内容复制到目标 Surface | 12ms(DMA/GPU) |
🎞️ 编码阶段 | H.264/H.265 视频编码 | 5~15ms(硬编) |
🌐 传输阶段 | 网络发送(局域网或无线) | 1~20ms |
📥 解码阶段 | 接收方解码画面 | 5~15ms |
🖥️ 显示阶段 | 解码后帧显示到屏幕 | 16ms(60fps) |
总计 | 30~80ms |
✅ 如何优化以达成实时游戏体验?
系统设计角度:
项目 | 推荐做法 |
---|---|
Surface 数据复制方式 | 使用 setDisplaySurface() ,避免 CPU 复制 |
编码方式 | 使用 硬件编码器(MediaCodec) 并调成低延迟模式 |
编码参数 | 使用低 GOP(关键帧间隔)、低缓存 |
网络传输 | 避免 Wi-Fi 干扰,使用 5GHz Wi-Fi,支持 QoS |
解码端 | 使用硬解码 + 提前渲染机制 |
显示刷新机制 | 使用 SurfaceView + Choreographer 提前预渲染 |
🎮 示例:Steam Link / Moonlight 等系统的延迟设计
系统/协议 | 理想延迟 | 技术手段 |
---|---|---|
Moonlight + NVIDIA GameStream | ~30ms | H.265 硬编 + UDP + 低延迟模式 |
Steam Link | 4060ms | 软件优化 + 局域网传输 + 减缓压缩 |
Android 无线投屏 | 50100ms | setDisplaySurface() + MediaProjection |
云游戏系统(如Xbox云游戏) | 80120ms | 云端计算 + 网络优化 |
✅ 结论
🎮 如果你希望在屏幕复制(主屏 -> surface -> 编码传输)场景中实现可玩级别的实时游戏体验:
必须确保 端到端延迟 ≤ 60ms
系统设计上建议使用:
SurfaceControl.setDisplaySurface()
(高效复制)硬件编码(低延迟 H.264/H.265)
局域网(如 5GHz Wi-Fi)
减少 BufferQueue 滞后与双缓冲
七、渲染和显示的区别
这是一个图形系统(无论是 Android、游戏引擎,还是桌面系统)中非常基础但又极易混淆的两个概念:
✅ 简明区分:
概念 | 渲染(Rendering) | 显示(Display) |
---|---|---|
作用 | 生成图像(把场景变成一帧帧像素) | 将生成的图像呈现在屏幕上 |
阶段 | 图像 生产 阶段 | 图像 消费 阶段 |
发生位置 | GPU(或 CPU 渲染引擎) | 显示控制器 / SurfaceFlinger / HWC |
产物 | Frame Buffer(帧缓冲) | 屏幕上的像素内容 |
频率 | 游戏引擎控制(如 60fps、120fps) | 通常与屏幕刷新率同步(如 60Hz VSync) |
🧠 更深入解释
🖼️ 渲染(Rendering)是什么?
-
是“画图”的过程,把游戏场景、UI、视频帧等“抽象内容”变成 具体像素
-
这个过程可能由:
-
应用(Canvas、Skia、OpenGL、Vulkan)
-
系统组件(WindowManager、SurfaceFlinger)
-
游戏引擎(Unity、UE)
-
举例:
把一个按钮绘制成图像,把 3D 场景变成一帧 1080p 图像帧,这都是渲染。
📺 显示(Display)是什么?
-
是把“已经生成好的像素”送到屏幕上、肉眼可见的过程。
-
通常通过:
-
SurfaceFlinger 合成所有图层 → 输出一帧
-
通过 HWC / DRM 驱动 → 输出到显示设备
-
屏幕扫描刷新一次(VSync)
-
举例:
游戏已经生成了一帧图像,但要等到下一次屏幕刷新(比如 16.6ms 后)才能真正出现在屏幕上。
🎯 类比理解:做 PPT 的比喻
-
渲染 = 你在 PowerPoint 中画了一张幻灯片
-
显示 = 你按下播放键,让观众在投影仪上看到它
🔁 在 Android 中的对应:
流程阶段 | 渲染还是显示? | 说明 |
---|---|---|
App 使用 Skia 绘制 UI | 渲染 | 使用 GPU 或 CPU 绘制到 Surface 的缓冲区中 |
Surface 被提交 | 渲染 | 图像还没显示,只是准备好了 |
SurfaceFlinger 合成 | 渲染(最后阶段) | 多个图层合成为一帧 |
Frame 输出到屏幕 | 显示 | 真正肉眼可见,需要 VSync 配合 |
🔄 典型延迟链(从渲染到显示)
-
App 发起 draw call →
RenderThread
开始渲染 →Surface
中 buffer 填满 -
buffer 被提交给
SurfaceFlinger
-
等待下一次 VSync 时机,
SurfaceFlinger
合成所有图层 -
合成帧提交给显示控制器 → 屏幕刷新 → 用户看到内容
通常这整个过程叫做 "Frame pipeline",耗时约为 16.6ms ~ 33ms。
✅ 总结:
问题 | 渲染 | 显示 |
---|---|---|
是干什么的? | 画出图像 | 把图像呈现出来 |
谁负责? | App / GPU / 系统组件 | SurfaceFlinger + HWC + 屏幕 |
图像状态 | “生成了但未显示” | “显示出来了” |
是否可见? | ❌ 不可见(存在于内存) | ✅ 可见(出现在屏幕) |
八、如此看来,投屏做不到延迟低于30ms
你说得很敏锐 —— 常规的投屏系统确实很难做到低于 30ms 的延迟。但是否**“做不到”**,要具体看实现方式、硬件支持程度、网络状况等。
✅ 简明结论:
🎯 传统投屏系统(如 Miracast、AirPlay、Cast)难以低于 30ms,
但高度优化的投屏方案(例如 NVIDIA GameStream + Moonlight)在特定条件下可以做到 20~30ms 延迟,但也极为挑剔环境和实现。
📉 为什么传统投屏难低于 30ms?
投屏链路必须经过以下阶段(每步都吃延迟):
阶段 | 典型耗时 | 说明 |
---|---|---|
渲染 | 16ms | 游戏/系统生成一帧图像(60fps) |
复制到 Surface | 1~2ms | 使用 setDisplaySurface 或虚拟 Display |
编码(硬编) | 5~10ms | 通常是 H.264 baseline |
网络传输 | 5~15ms | 取决于 Wi-Fi / LAN 稳定性 |
解码(硬解) | 5~10ms | 通常使用 MediaCodec 或 GPU |
显示刷新 | ~16ms | 等下一次 vsync,才真正看到帧 |
🔗 总计:约 40~70ms(这是典型系统投屏的真实表现)
🎯 有哪些场景“接近”或“突破”30ms延迟?
系统 / 技术 | 条件 | 延迟范围 |
---|---|---|
✅ Moonlight + NVIDIA GameStream | 局域网、RTX GPU、优化参数 | 20~35ms |
✅ Steam Link(局域网) | 5GHz Wi-Fi + 硬编 + TV 硬解 | 30~45ms |
⚠️ Android MediaProjection + 硬编 | 基于 setDisplaySurface() | 50~80ms |
⚠️ AirPlay / Miracast | 无优化 | 70~120ms |
👉 注意:
-
即使你用最快的编码器,显示刷新(VSync)+网络波动会拖住延迟底线。
-
编码器通常也需要一些 帧缓存,比如 2 帧(就是额外 30ms)。
✅ 结论:能不能做到低于 30ms?
问题 | 答案 |
---|---|
普通投屏能否低于 30ms? | ❌ 几乎不可能(Miracast、AirPlay 等) |
特定方案能否做到? | ✅ 有条件可行(如 Moonlight + 局域网) |
需要什么支持? | - 低延迟编码(快速帧间编码) - 高带宽低干扰 Wi-Fi(最好是 5GHz) - 最小化 buffer、VSync 对齐 - 接收端支持快速解码和低延迟渲染 |
🛠️ 补充建议:如果你自己做投屏系统
你可以考虑如下策略来尽量压缩延迟:
-
使用
setDisplaySurface()
拦截主屏输出,避免在应用层采集 -
使用 MediaCodec 硬编,开启
low-latency
profile -
GOP 设置为 1~2(低 B 帧甚至无 B 帧)
-
目标帧率拉高到 90fps(加快帧传递频率)
-
接收端用 SurfaceView +
async
解码路径 -
推流协议使用 RTP over UDP(而非 RTSP/TCP)
九、高分辨率的原始图像,通过低分辨率的设备用setDisplaySurface投屏到高分辨率的设备,会丢失吗?
触及到了 分辨率适配 和 像素数据保真度 的核心。
✅ 简短回答:
是的,如果你使用
setDisplaySurface()
将一个低分辨率设备的原始图像投屏到高分辨率显示器,最终投出的画面分辨率将受限于原设备的显示分辨率,会失真或模糊,并不会自动变得高清。
📌 为什么会“丢失”高分辨率?
情况还原:
-
你在一个 低分辨率设备(比如 720p 手机)上运行应用
-
使用
setDisplaySurface()
将 主屏输出投到一个高分辨率设备(比如 4K 显示器或虚拟屏) -
你以为能在高分屏上显示更清晰图像,但结果发现仍然是 720p 放大后的效果
原因在于:
点 | 解释 |
---|---|
✅ setDisplaySurface() 拷贝的是合成结果 | 它不会重新渲染或生成高分图像,而是复制低分屏渲染完的最终帧 |
⚠️ 原始渲染内容已是低分辨率 | Android 上应用或系统界面是基于设备 DPI 和屏幕大小渲染的,渲染目标分辨率就是低的 |
❌ 不会自动“高清化” | 除非你在原设备上以更高分辨率渲染图像(通常不可能) |
🧠 类比理解:
这就像你拿一个 720p 的截图,在 4K 显示器上全屏播放 —— 画面还是糊的,像素已经定死了。
✅ 如何判断你最终的投屏分辨率是多少?
你可以通过以下方式验证:
方法 1:查看系统的实际显示分辨率
bash
复制编辑
adb shell dumpsys SurfaceFlinger
在输出中查找你绑定的 Surface
的显示分辨率,以及主屏的 DisplayDevice
信息。
方法 2:通过 MediaCodec 编码时查看输入帧大小
-
如果你设置
setDisplaySurface(surface)
给一个MediaCodec
的input surface
,那编码器收到的帧分辨率就是源设备的屏幕分辨率,不会自动 upscale。
✅ 如何实现“清晰的高分辨率投屏”?
如果你希望:
“用低分辨率设备运行 App,但在高分屏上看到更清晰的图像”
你需要 重新设计渲染路径,如下:
方法 | 效果 | 代价 |
---|---|---|
❌ 直接 setDisplaySurface() | 画面模糊 | 简单,低分辨率限制 |
✅ 使用虚拟 Display 并指定高分辨率 | 高清可行 | 要求应用支持多分屏 |
✅ App 主动渲染到高分辨率 Surface | 高清 | 需改造 App 或引擎 |
✅ 投送原始图像数据(非屏幕采集) | 原始质量 | 通常用于图像类 App |
🎯 示例场景
场景 | 是否可获得高清图像? | 原因 |
---|---|---|
用 setDisplaySurface() 投屏手机 UI | ❌ 模糊,低分限制 | 源图像已是低分 |
用虚拟 Display 指定 1080p 渲染 | ✅ 高清(如果 App 支持) | 渲染目标是高分 |
游戏使用 Vulkan 渲染到 4K Surface | ✅ 高清 | 自定义渲染控制 |
✅ 总结:
问题 | 答案 |
---|---|
setDisplaySurface() 会丢失分辨率吗? | ✅ 是,受限于源屏幕的分辨率 |
会自动高清化吗? | ❌ 不会 |
如何获得高清效果? | ✅ 使用虚拟 display 或高分渲染 |
十、创建了高分的虚拟设备,同时虚拟设备要和低分的主设备同步,会有什么影响?
这个问题触及到了系统合成路径、刷新策略、buffer同步等多个 Android 图形子系统的核心点。我们分步骤来讲:
🎯 场景还原
你现在有两个 Display:
-
主屏(低分辨率,比如 1280x720)
-
虚拟屏(高分辨率,比如 1920x1080 或 4K)
你希望这两个屏幕同步显示相同内容(例如镜像主屏到虚拟屏),但由于它们分辨率不同,系统需要做缩放或重新合成。
✅ 会产生的主要影响
类别 | 影响情况 | 原因说明 |
---|---|---|
📉 性能开销 | ✅ 明显增加 GPU/合成压力 | 系统需要额外执行一次 缩放或 re-composite |
⏱️ 延迟 | ✅ 可能 增加 1 帧以上延迟 | 同步时需要等待 buffer/合成对齐 |
🔁 同步 | ⚠️ 不一定能做到真正的帧级同步 | 两个 Display 的 VSync 信号可能不同步 |
📐 清晰度 | ✅ 虚拟屏虽是高分,但内容是低分缩放上去 | 除非应用对虚拟屏单独高分渲染 |
🌀 帧率差异 | ⚠️ 如果两个屏幕刷新率不同,会导致卡顿或撕裂 | 例如主屏 60Hz,虚拟屏 30Hz 或 90Hz |
🔍 细节分析:SurfaceFlinger 是怎么处理的?
👉 当你开启镜像模式(或自己同步绘制两个屏幕):
-
App 渲染的是 720p 分辨率
-
系统将这帧图像:
-
输出到主屏,照常显示
-
同时缩放到虚拟屏的分辨率(如 1080p)并显示
-
SurfaceFlinger 面临的问题:
问题 | 表现 |
---|---|
Buffer 尺寸不匹配 | 需要 GPU 或硬件合成器执行 scale |
两屏 vsync 不一致 | 可能导致 tearing、掉帧 |
Buffer 填充与提交延迟 | 合成管线拉长,丢帧概率升高 |
🧪 举个真实例子
比如你有个 App,渲染一帧 720p 界面,显示在两个屏幕上:
主屏 720p:完美适配
虚拟屏 4K:SurfaceFlinger 要将内容拉伸到 3840x2160,GPU 消耗上升,部分设备甚至用软件做缩放,非常慢
✅ 如何减少影响?
方法 | 效果 | 说明 |
---|---|---|
使用虚拟 Display 单独渲染高分内容 | ✅ 真正高清、不卡顿 | 代价是需要 App 支持多分屏 |
限制虚拟屏分辨率接近主屏 | ⚠️ 清晰度受限,性能轻 | 保证合成路径一致性 |
不做镜像,而是单独推流内容到虚拟屏 | ✅ 更灵活 | 适合投屏/游戏/视频场景 |
使用硬件合成模块(HWC2 + Display HAL) | ⚠️ 设备依赖强 | 一些 SoC 有 mirror support |
✅ 总结结论
问题 | 是否会发生? | 说明 |
---|---|---|
会不会增加合成和性能开销? | ✅ 明显会 | 多一次缩放、双屏合成开销 |
会不会导致同步问题、撕裂? | ⚠️ 可能会 | 两屏 vsync 不同步是常态 |
虚拟屏内容会更清晰吗? | ❌ 如果仅是镜像 | 渲染内容决定清晰度 |
虚拟屏能不能独立显示高分图像? | ✅ 可以 | 需要专门渲染逻辑 |
🎯 建议你考虑的问题:
-
你是做 UI 镜像?游戏镜像?视频推送?
-
你控制的是 App 层,还是系统层?能不能控制合成/渲染方式?
-
虚拟 Display 是用
DisplayManager.createVirtualDisplay()
创建的吗?
十一、如果不要求虚拟屏和主屏同步,只是把高分的虚拟屏投屏到高分的显示设备上呢
如果你不要求主屏和虚拟屏同步,而是:
✅ 只在高分虚拟屏上渲染内容,并把它独立投屏到一个高分显示设备上
那么,你可以做到:
✅ 高清显示、低延迟、高质量输出!
这实际上是最推荐的方式,比“主屏镜像+缩放”更清晰、更高效,尤其适合:
-
无线投屏(如 DLNA / 自研协议)
-
扩展屏应用(演示模式、PPT、游戏)
-
自研图形应用输出到远程大屏幕
🔧 实现逻辑(推荐路径):
-
使用 DisplayManager#createVirtualDisplay() 创建一个高分辨率虚拟显示设备
java
复制编辑
VirtualDisplay virtualDisplay = displayManager.createVirtualDisplay( "MyVirtualDisplay", 1920, 1080, 320, surface, // 用于接收该显示内容的 Surface(可用于编码) DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC );
-
指定该
VirtualDisplay
的Surface
作为编码输入,使用MediaCodec
进行实时硬编码(比如 H.264) -
将编码结果通过你自己的网络协议(比如 RTP / RTMP / WebRTC / Socket)发送到远端设备
-
在高分显示设备上解码并显示该视频流(1080p / 4K)
✅ 好处对比
点 | 主屏镜像 + 缩放 | 独立高分虚拟屏 |
---|---|---|
图像清晰度 | ❌ 受限于主屏分辨率 | ✅ 高分原始渲染 |
渲染控制 | ❌ 无法分离 | ✅ 可单独绘制 |
多屏逻辑 | ❌ 共用 UI 配置 | ✅ 独立 UI、逻辑 |
延迟控制 | ❌ 被系统帧同步影响 | ✅ 渲染→编码直通 |
可扩展性(多屏) | ❌ 很难 | ✅ 可以创建多个虚拟屏 |
🎮 举个典型例子
假设你做一个“云游戏客户端”:
-
主屏只显示菜单,不参与画面渲染
-
游戏画面渲染到虚拟屏(比如 1080p 60fps)
-
编码后推流到远端显示设备(如电视)
🟢 结果是:
-
主屏不卡顿、不发热
-
虚拟屏保持高清、高帧率、高效率传输
⚠️ 注意事项
问题 | 解决方法或注意点 |
---|---|
如何让 App 渲染到虚拟屏? | 创建新的 Context.createDisplayContext() 或用 Presentation |
虚拟屏没有输入事件? | 正常,不需要交互;如需交互可虚拟输入注入 |
虚拟屏能 4K 吗? | ✅ 可指定 3840x2160,但 GPU 带宽和编码器要跟得上 |
✅ 总结
你的目标 | 可行性 | 建议 |
---|---|---|
高分虚拟屏 → 投屏到高分设备 | ✅ 完全可行 | 推荐使用 VirtualDisplay + MediaCodec 路径 |
不同步主屏,独立渲染内容 | ✅ 高效、清晰 | 不走主屏镜像,性能更优 |
高清投屏,适配远端显示 | ✅ 控制渲染分辨率即可 | 编码传输控制帧率、码率 |
十二、点亮虚拟屏能达到像点亮主屏一样防止手机休眠的效果吗?
你的关注点是:
点亮虚拟屏是否可以像点亮主屏一样,防止手机进入休眠状态(Doze / Suspend / 黑屏)?
✅ 简短结论:
不可以直接等效防止休眠,虚拟屏本身不能阻止系统休眠,但可以通过特定方法间接达到防止休眠的效果。
📌 为什么虚拟屏不能自动防止休眠?
原因 | 解释 |
---|---|
虚拟 Display 不被视为物理屏幕 | 它不会像主屏一样参与电源管理策略 |
系统休眠判断基于主屏状态 | 即使虚拟屏在“输出内容”,主屏息屏或用户无操作,仍可能触发 Doze 或 Suspend |
虚拟屏没有“用户可见性”信号 | 没有接触/亮度/唤醒事件驱动系统保持活跃状态 |
✅ 怎么样才能 真正防止休眠?
你需要组合使用 系统唤醒机制,比如:
方法 | 是否推荐 | 原理 |
---|---|---|
PowerManager.WakeLock | ✅ 推荐 | 阻止 CPU 或屏幕休眠(需权限) |
FLAG_KEEP_SCREEN_ON | ⚠️ 仅限主屏有效 | 虚拟屏不生效 |
ForegroundService + WakeLock | ✅ 常见做法 | 在后台长时间保持活跃 |
播放音频或 MediaProjection | ⚠️ 非常规方法 | 一些厂商限制少时有效 |
✅ 推荐实现方式:使用 WakeLock
java
复制编辑
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); WakeLock wakeLock = powerManager.newWakeLock( PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, "YourApp:VirtualDisplayWakeLock" ); wakeLock.acquire(); // 可选超时参数
如果你只需要防止 CPU 休眠而不需要点亮屏幕:
java
复制编辑
PowerManager.PARTIAL_WAKE_LOCK
记得使用完后 wakeLock.release()
,否则会造成耗电。
🧠 示例场景:你在开发投屏服务
场景 | 是否能阻止休眠? | 备注 |
---|---|---|
只创建虚拟屏 + 开始编码推流 | ❌ 不能 | 虽然图像在输出,但主屏休眠会中断编码 |
虚拟屏 + WakeLock + 前台服务 | ✅ 可以 | 这是推荐做法,适配性最强 |
虚拟屏 + 屏幕共享(MediaProjection) | ⚠️ 不一定 | 部分系统可阻止休眠,但不可依赖 |
❗ 特别提醒:Doze 模式下不保证行为稳定
某些厂商(如华为、小米)在电池策略中,会强制挂起后台虚拟屏服务,除非:
-
你是前台服务(通知栏常驻)
-
App 被加入电池白名单
-
获取了
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
权限(需要手动授权)
✅ 总结
问题 | 是否成立 | 建议方案 |
---|---|---|
虚拟屏会自动阻止系统休眠吗? | ❌ 不会 | 加 WakeLock |
虚拟屏保持内容输出会延长设备唤醒时间吗? | ⚠️ 不一定 | 不稳定,视厂商实现 |
如何确保系统不黑屏 / 不挂起 App? | ✅ 前台服务 + WakeLock | |
虚拟屏是否能用于长时间输出到显示设备? | ✅ 可以,但需配合防休眠机制 |
十三、通过电脑adb命令,用app_process拉起的进程,系统休眠后也会不工作,加 WakeLock确定能解决吗?
涉及到 app_process 启动的进程是否能在系统休眠后继续运行 —— 我们来深入拆解:
🎯 问题背景总结:
你用的是类似如下命令:
bash
复制编辑
adb shell app_process /system/bin com.example.YourMainClass
-
这种方式绕过了普通
Activity
/Service
启动路径 -
通常不受 Android 应用生命周期限制,但也不受系统 power manager 自动保护
现在你想确认:
如果系统休眠(息屏 / Doze / Suspend),这个进程是否会停止?如果加 WakeLock,能否解决?
✅ 简洁结论:
是的,理论上你可以使用
WakeLock
保持 CPU 运行,即使系统休眠,app_process 启动的进程也可以持续工作。
⚠️ 但前提是:
-
你必须获取 正确类型的 WakeLock
-
运行环境有权限申请 WakeLock
-
该进程没有被 SELinux 限制调用 PowerManager
✅ 你该怎么做?
🧩 步骤一:让进程获取 WakeLock
即使你通过 app_process
启动,只要你创建了 Java 进程并能访问系统服务,你可以这样写代码:
java
复制编辑
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyApp::KeepAlive"); wakeLock.acquire();
-
PARTIAL_WAKE_LOCK 是关键!它不要求屏幕亮,但能防止 CPU 进入休眠。
-
你不需要
SCREEN_DIM_WAKE_LOCK
等类型,因为你可能没有界面。
🔐 权限要求:
你必须在代码中拥有:
xml
复制编辑
<uses-permission android:name="android.permission.WAKE_LOCK"/>
但对于 app_process
启动的进程,没有 AndroidManifest.xml
,所以你需要:
-
在 shell 用户或 system 用户下运行(拥有
WAKE_LOCK
权限) -
或使用
pm grant
赋予权限(如果你用 app 包运行)
bash
复制编辑
adb shell pm grant com.example.yourapp android.permission.WAKE_LOCK
⚠️ 注意:不解决以下几种“休眠”问题
休眠类型 | WakeLock 有效? | 说明 |
---|---|---|
屏幕息屏 | ✅ 有效 | PARTIAL_WAKE_LOCK 可以保持后台运行 |
Doze 模式 | ✅ 有效(需前台进程) | 但某些厂商会强杀 |
App standby | ✅ 有效 | 前提是你不通过应用层启动 |
深度挂起(suspend) | ⚠️ 设备依赖,不总有效 | 某些设备强制 system suspend,WakeLock 无效(尤其是长时间息屏后) |
🧠 补充:你应该避免的情况
错误做法 | 后果 |
---|---|
用 SCREEN_DIM_WAKE_LOCK 无界面时 | 无效、被忽略 |
不获取 WakeLock | 系统一旦 Doze 或 CPU suspend,app_process 启动的进程会被冻结或终止 |
依赖 Java Thread.sleep 来保持 | 会被系统挂起,不会真正运行 |
✅ 建议实践方案
如果你正在做的是:
-
开发一个通过 ADB 启动的常驻服务(例如性能监控、远程指令、投屏、流媒体处理)
-
不使用标准 Activity/Service 框架
那么最佳组合是:
功能 | 技术方案 |
---|---|
后台运行 | app_process + PARTIAL_WAKE_LOCK |
防休眠 | 使用 WakeLock.acquire() 持续持有 |
防杀进程 | 推荐使用 nohup 或 app_process & + 守护进程机制 |
稳定性增强 | 可搭配使用 ForegroundService (如用 shell 启 app 服务) |
✅ 结论总结:
问题 | 是否成立? | 备注 |
---|---|---|
app_process 启动的进程休眠后会暂停? | ✅ 是的 | CPU suspend 后会冻结 |
加 WakeLock 能防止进程被冻结? | ✅ 有效 | 使用 PARTIAL_WAKE_LOCK |
所有设备都一定有效? | ⚠️ 不一定 | 厂商可能有特殊电源策略 |
无界面程序也能拿到 WakeLock? | ✅ 可以 | 只要有权限并运行在有能力用户下 |
相关文章:
视频编解码学习十二之Android疑点
一、android.view.SurfaceControl.setDisplaySurface的作用 android.view.SurfaceControl.setDisplaySurface 是 Android 系统中一个 native 层级别的 API,主要用于 设置某个物理显示屏(Display)的输出 Surface,属于 SurfaceFlin…...
web第三次课后作业--基于JDBC对mysql数据库的增删查改操作
一、工程搭建步骤 1.新建java项目,添加jdbc依赖 2.写java程序 3.添加mysql数据源,连接本地数据库 4.运行程序二、运行结果 三、代码 代码解析 加载数据驱动 try {Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundExceptio…...
fiftyone-数据库配置和config与app_config配置文件
一数据库配置:(以本地为例) fiftyone数据库信息存在配置文件中: 配置文件地址: ~/.fiftyone/config.json 这个配置文件的作用:存放数据库地址信息;(如果不配置,fiftyon…...
Nginx的核心功能--正向代理、反向代理、缓存和Rewrite
Nginx作为高性能的Web服务器,其核心功能主要体现在以下四大模块: 一、正向代理 主要用于客户端访问外部网络的中转服务。典型配置示例: server {listen 8080;resolver 8.8.8.8;location / {proxy_pass http://$http_host$request_uri;prox…...
mac latex vscode 配置
mac latex vscode 配置 安装mactex.pkg 这里有个快速下载的镜像 https://mirrors.aliyun.com/CTAN/systems/mac/mactex/ 可以检查是否将 PATH 写入 export PATH"/Library/TeX/texbin:$PATH"vscode 下载插件 Latex Workshop 在配置文件 settings.json 中输入如下的…...
【GESP真题解析】第 4 集 GESP一级 2023 年 3 月编程题 1:每月天数
大家好,我是莫小特。 这篇文章给大家分享 GESP 一级 2023 年 3 月编程题第 1 题:每月天数。 题目链接 洛谷链接:B3835 每月天数 一、完成输入 根据题目要求,我们需要输入两个整数,分别表示一个日期的年份和月份。 年…...
国产免费工作流引擎star 6.5k,Warm-Flow升级1.7.2(新增案例和修复缺陷)
文章目录 主要更新内容项目介绍功能思维导图设计器流程图演示地址官网Warm-Flow视频 主要更新内容 [feat] 开启流程实例,新增流程定义是否存在校验[feat] 新增合同签订流程案例[feat] 新增企业采购流程案例[update] mybatis-plus逻辑删除,删除值和未删除…...
计算机网络:移动通信蜂窝网络指的是什么?
无线基站的蜂窝网络(Cellular Network)是现代移动通信系统的核心架构,其核心思想是通过蜂窝状小区划分和频率复用,实现广域覆盖、高效频谱利用和动态资源管理。以下从设计原理、网络架构、关键技术及实际挑战等方面深入解析蜂窝网络。 一、蜂窝网络的设计原理 1. 蜂窝结构…...
scratch基础-外观模块
一、本次任务 二、内容详解 1、模块介绍 1、说[你好] (2)秒:临时对话框,短暂对话 2、说[你好]:持续显示对话框,长文本显示 3、思考[嗯…] (2)秒:临时显示思考气泡,用于角色思考 4、思考[嗯…] :…...
前端服务器部署分类总结
目前所了解的部署有三种方式: 一是本地服务器部署;二是 nginx 服务器部署;三是云服务器部署 本地部署,准备好部署的包 以Vue项目为例,执行npm run build 命令打成前端包 第二步:将打包结果交给服务器(本地…...
精益数据分析(58/126):移情阶段的深度实践与客户访谈方法论
精益数据分析(58/126):移情阶段的深度实践与客户访谈方法论 在创业的漫长旅途中,正确识别和验证问题是成功的第一步。今天,我们继续围绕《精益数据分析》中创业阶段的核心内容,深入探讨移情阶段的关键实践…...
MK米客方德SD NAND:无人机存储的高效解决方案
在无人机技术迅猛发展的当下,飞控系统的数据记录对于飞行性能剖析、故障排查以及飞行安全保障极为关键。以往,SD 卡是飞控 LOG 记录常见的存储介质,但随着技术的革新,新的存储方案不断涌现。本文聚焦于以 ESP32 芯片为主控制器的无…...
LVDS系列12:Xilinx Ultrascale系可编程输入延迟(二)
本节讲解Ultrascale IDELAYE3的参数; IDELAYE3参数: REFCLK_FREQUENCY:如果使用COUNT模式,保持300MHz的默认值即可; 如果使用TIME模式,则该值与IDELAYCTRL参考时钟要匹配; DELAY_SRC&#…...
Spring的bean的生命周期?
Spring中bean的生命周期包括以下步骤: 通过BeanDefinition获取bean的定义信息。 调用构造函数实例化bean。 进行bean的依赖注入,例如通过setter方法或Autowired注解。 处理实现了Aware接口的bean。 执行BeanPostProcessor的前置处理器。 调用初始化…...
OpenCV CUDA模块中逐元素操作------逻辑运算
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 比较、AND、OR、NOT等。这类操作可用于创建基于条件的掩码,这对于图像分割或特征选择非常有用。 主要函数 1. 按位与 (cv::cuda::b…...
微信开发者工具里面模拟操作返回、录屏、网络速度、截屏等操作
微信开发者工具里面模拟操作返回、录屏、网络速度、截屏等操作...
Void: Cursor 的开源平替
GitHub:https://github.com/voideditor/void 更多AI开源软件:发现分享好用的AI工具、AI开源软件、AI模型、AI变现 - 小众AI Void,这款编辑器号称是开源的 Cursor 和 GitHub Copilot 替代品,而且完全免费! 在你的代码库…...
【MySQL】日志缓冲区详解 以及 InnoDB内存结构总结
📢博客主页:https://blog.csdn.net/2301_779549673 📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! &…...
在Spark搭建YARN
(一)什么是SparkONYarn模式 Spark on YARN(Yet Another Resource Negotiator)是 Spark 框架在 Hadoop 集群中运行的一种部署模式,它借助 Hadoop YARN 来管理资源和调度任务。 架构组成 ResourceManager:作…...
postman 用法 LTS
postman 用法 LTS File ---- View ---- Show Postman Console...
Spring Boot requestBody postman
Spring Boot requestBody postman 在处理Spring Boot应用程序中的RequestBody注解时,通常用于接收客户端(如Postman)发送的JSON格式数据。如果你在Postman中配置请求,并希望将JSON数据发送到Spring Boot后端,你可以按…...
OpenHarmony 开源鸿蒙南向开发——linux下使用make交叉编译第三方库——wget
准备工作 请依照这篇文章搭建环境 OpenHarmony 开源鸿蒙南向开发——linux下使用make交叉编译第三方库——环境配置_openharmony交叉编译-CSDN博客 编译依赖 Wget依赖Gnutls库,gnutls库依赖gmp、nettle、libunistring库 上述库可在历史文章中自行查找 下载 w…...
枢轴支压点策略
一种基于枢轴点(Pivot Point)的交易策略,主要用于在趋势行情中进行交易。 策略的核心思路是通过计算前一天的最高价、最低价和收盘价来确定当天的枢轴点,并据此计算出第一和第二阻力位以及第一和第二支撑位。 可以根据这些关键点位…...
【SSL部署与优化】TLS 1.3的核心改进与性能优化
TLS 1.3 的核心改进与性能优化 TLS 1.3 是当前最安全的 TLS 协议版本,通过简化协议、增强加密算法和优化握手流程,显著提升了性能和安全性。以下是其核心改进、性能优化及关键技术的详细解析: 一、TLS 1.3 核心改进 精简加密套件 • 移除弱算…...
等经纬度投影下求经纬度的行列号
一 概述 使用等经纬度投影(Equirectangular Projection), 将经纬度转换为行列号。 二 C实现 1 代码 以下是C的实现方法。该实现将地球的经纬度范围划分为固定分辨率的网格,每个网格对应一个行列号。 #include <cmath> #in…...
MetaHipMer2:从头组装宏基因组
Terabase-scale metagenome coassembly with MetaHipMer | Scientific Reports https://academic.oup.com/nar/advance-article/doi/10.1093/nar/gkaf369/8126258 安装 配置环境 berkeleylab / upcxx / wiki / INSTALL — Bitbucket mamba create -n mhm2_env -c conda-fo…...
CK-S654-PA60一拖四分体式半导体电子货架专用RFID读写器|读码器接线使用说明
半导体行业RFID电子货架通过物联网技术将传统仓储从“经验驱动”转向“数据驱动”,其自动化识别、实时追踪与智能决策能力,正重塑物流与库存管理的底层逻辑。从晶圆盒的精准定位到柔性化生产,这一技术不仅提升了效率,更让半导体行…...
C++类和对象练习:Date类实现日期的差,比较日期的大小,日期的前置后置++,--,输入输出Date类,对默认函数的练习。
引言 C类和对象练习:Date类实现日期的差,比较日期的大小,日期的前置后置,--,输入输出Date类,对默认函数的练习。 _涂色_-博客主页 C基础专栏 分三个文件来写: Date.cpp //类函数的实现 Date.h…...
C++学习之打车软件git版本控制
目录 01 3-git的简介 02 4-git的下载和提交代码 03 5-git添加一个新文件 04 5-删除一个文件 05 6-git的批量添加和提交文件 06 7-git重命名文件名 07 8-git解决代码冲突 08 9-git的分支的概念 09 10-创建项目代码仓库 10 1-git提交代码复习 01 3-git的简介 1 --------…...
QT之信号与槽
欢迎来到 破晓的历程的 博客 ⛺️不负时光,不负己✈️ 文章目录 QT信号与槽机制详解基本概念信号(Signal)槽(Slot) 信号与槽的连接方式基本语法QT5新语法(推荐) 信号与槽的特点实际示例传统方式QT5新语法 连接类型注意事项高级用法信号连接信号使用lambda表达式自动…...
文章记单词 | 第73篇(六级)
一,单词释义 apart /əˈpɑːt/ adv. 分开地;相距assistant /əˈsɪstənt/ n. 助手;助理useless /ˈjuːsləs/ adj. 无用的;无效的ampere /ˈmpɛr/ n. 安培(电流单位)recite /rɪˈsaɪt/ v. 背诵&am…...
在Ubuntu24.04中配置开源直线特征提取软件DeepLSD
在Ubuntu24.04中配置开源直线特征提取软件DeepLSD 本文提供在Ubuntu24.04中配置开源直线特征提取软件DeepLSD的基础环境配置、列出需要修改的文件内容,以及报错解决方案集锦。 基础的编译安装环境 python3.8.12CUDA12gcc/g 9.5(系统自带的g-13版本太新…...
什么是SparkONYarn模式?
(一)什么是SparkONYarn模式 Spark on YARN(Yet Another Resource Negotiator)是 Spark 框架在 Hadoop 集群中运行的一种部署模式,它借助 Hadoop YARN 来管理资源和调度任务。 架构组成 ResourceManager:作…...
STMCubeMX使用TB6612驱动编码轮并进行测速
硬件介绍 TB6612电机驱动模块功能与特性 电机方向控制 描述如何通过 TB6612 的 IN1 和 IN2 引脚控制电机的旋转方向。提供代码示例,展示如何通过 GPIO 控制电机的正反转。 速度控制与减速 解释如何通过调整 PWM 信号的占空比来控制电机的速度,并…...
数据安全与权限管控,如何实现双重保障?
数据安全和权限管控并非孤立存在,而是相互依存、相互促进的关系。强大的权限管控体系是数据安全的重要防线,能够从源头上限制潜在的风险;而完善的数据安全策略和技术手段,则为权限管控的有效实施提供了保障。只有构建起数据安全与…...
如何创建自动工作流程拆分Google Drive中的PDF文件
以下是完整的工作流程。在构建自动拆分工作流程之前,您可以尝试我们的免费在线 PDF 拆分器。 步骤 1:Make 自动拆分 PDF 的要求 要设置自动 PDF 拆分工作流程,您需要: 免费的Make.com帐户。可访问 Google Drive 并处理 PDF 文件…...
【SpringBoot实战指南】集成Easy ES
一、Easy ES 简介 Easy ES(简称EE)是一款基于 Elasticsearch 官方 RestHighLevelClient 封装的 ORM 框架,提供类似 MyBatis-Plus 的 API 设计,可以帮助开发者更简单地集成和使用 Elasticsearch,让操作 Elasticsearch …...
深入理解指针(1)
🎁个人主页:工藤新一 🔍系列专栏:C面向对象(类和对象篇) 🌟心中的天空之城,终会照亮我前方的路 🎉欢迎大家点赞👍评论📝收藏⭐文章 文章目录 深…...
vue.js中的渲染【条件渲染】
条件渲染 在 Vue 中,条件渲染用于根据表达式的值来决定是否在 DOM 中渲染某个元素。Vue 提供了几种方式来实现条件渲染: v-if 指令 用于根据条件是否为真来销毁或创建元素。 <p v-if"isVisible">显示这段内容</p>data() {retu…...
Qwen3如何强化推理能力?
大模型的推理能力一直是衡量其智能水平的关键指标。近期,Qwen3系列模型在这方面取得了显著突破。通过对Qwen3技术报告的解读,我们可以窥见一套完整的推理能力提升体系。本文将以结构化视角,剖析Qwen3推理能力提升的关键环节。 报告地址&#…...
2025年中国主流DevOps平台对比分析:Gitee、阿里云效与GitLab CE的技术适配与合规实践全景解读
在2025年中国企业数字化转型持续深化的背景下,DevOps 工具的选型呈现出多元化趋势。以下从安全合规、技术生态适配性、实践案例和选型建议四个维度,对 Gitee、阿里云效(云效 DevOps)和 GitLab CE(中国版)三…...
从lightrag的prompt到基于openai Structured Outputs 的优化实现思路
LightRAG 是一个用于构建 RAG 系统核心组件的配置和管理类。它集成了文档处理、存储、向量化、图谱构建和 LLM 交互等功能。你可以通过配置 LightRAG 实例的各种参数来定制 RAG 系统的行为。 目前lightrag中的实体关系抽取实现如下 PROMPTS["entity_extraction"] …...
论文阅读笔记——双流网络
双流网络论文 视频相比图像包含更多信息:运动信息、时序信息、背景信息等等。 原先处理视频的方法: CNN LSTM:CNN 抽取关键特征,LSTM 做时序逻辑;抽取视频中关键 K 帧输入 CNN 得到图片特征,再输入 LSTM&…...
Android清单文件
清单文件AndroidManifest.xml AndroidManifest.xml 配置清单文件是 每个 Android 应用的配置中心,系统在安装和运行应用时,首先会读取它。 它是 Android 应用的 “说明书”,主要作用是: 功能说明声明应用组件比如 Activity、Se…...
Single image dehazing论文阅读
Single image dehazing 1. 论文的研究目标与实际意义1.1 研究目标1.2 实际问题与产业意义2. 论文的创新方法、模型与公式2.1 改进的大气散射模型2.2 局部统计不相关性约束2.2.1 传输函数估计2.2.2 大气光颜色估计2.3 算法流程2.4 与传统方法的对比优势3. 实验设计与结果3.1 实验…...
数字信号处理-大实验1.3
MATLAB仿真实验目录 验证实验:常见离散信号产生和实现验证实验:离散系统的时域分析应用实验:语音信号的基音周期(频率)测定 说明:(1)本文是DSP大实验1的最后一篇,主要讲…...
【Pandas】pandas DataFrame describe
Pandas2.2 DataFrame Computations descriptive stats 方法描述DataFrame.abs()用于返回 DataFrame 中每个元素的绝对值DataFrame.all([axis, bool_only, skipna])用于判断 DataFrame 中是否所有元素在指定轴上都为 TrueDataFrame.any(*[, axis, bool_only, skipna])用于判断…...
C++GO语言微服务之Dockerfile docker-compose②
目录 01 12-yaml文件书写规则01 12-yaml文件书写规则 02 13-yaml中的数据类型 03 14-docker-compose配置文件格式 04 15-docker-compose中的关键字 05 16-prots和volumes关键字的使用 06 17-volumes_from的使用 07 18-extends的使用 08 19-networks的使用 09 20-docker…...
【计算机视觉】OpenCV实战项目:Face-Mask-Detection 项目深度解析:基于深度学习的口罩检测系统
Face-Mask-Detection 项目深度解析:基于深度学习的口罩检测系统 一、项目概述项目特点 二、项目运行方式与执行步骤(一)环境准备(二)项目结构(三)执行步骤 三、重要逻辑代码解析(一&…...
鸿蒙OSUniApp 实现的语音输入与语音识别功能#三方框架 #Uniapp
UniApp 实现的语音输入与语音识别功能 最近在开发跨平台应用时,客户要求添加语音输入功能以提升用户体验。经过一番调研和实践,我成功在UniApp项目中实现了语音输入与识别功能,现将过程和方法分享出来,希望对有类似需求的开发者有…...