Jetson Nano 上实现 YOLOv5n 实时检测NVMM、CUDA、TensorRT 与 EGL 零拷贝复现本文给出一套可复现的 Jetson Nano 实时目标检测方案。摄像头通过 Argus/GStreamer 输出 NVMM 帧CUDA 直接完成预处理和检测框绘制TensorRT 执行 YOLOv5n 推理最后由NvEglRenderer显示。实测摄像头约 59.5 FPS推理和显示稳定在 26 FPS 左右。github有时间会补上去或者放在评论区求⭐。1. 最终效果与测试结果1.1 测试环境项目配置开发板NVIDIA Jetson NanoJetPack4.5.1L4T32.5.2CUDA10.2TensorRT7.1.3GStreamer1.14.5摄像头MIPI CSI通过 Argus 采集摄像头模式1280×720、60 FPS、sensor_mode4模型YOLOv5nCOCO 80 类TensorRT 输入1×3×640×640 FLOAT32TensorRT 输出tensorrtx 自定义YoloLayer_TRT输出工程语言C17CUDA 模块使用 C14本文针对 JetPack 4.x 的旧版 Multimedia API。JetPack 5/6 的NvBufSurface、GStreamer 和 CUDA EGL 接口有所不同不能直接照搬所有底层映射代码。1.2 约两分钟实测指标结果摄像头采集59.50 FPSTensorRT 推理26.23 FPSEGL 实际显示26.23 FPSGPU 预处理0.83 msTensorRT execute35.27 msEGL 渲染2.62 ms端到端平均延迟45.99 ms端到端 P5045.94 ms端到端 P9553.93 ms统计期间共采集 7044 帧、推理 3106 帧、显示 3105 帧。摄像头快于推理时系统主动覆盖过期帧因此不会形成越来越长的处理队列。2. 为什么要重写实时运行链路直接使用 YOLOv5 的 Pythondetect.py在 Jetson Nano 上通常会遇到以下问题MIPI CSI 摄像头需要nvarguscamerasrc不是普通 USB/V4L2 摄像头。CPU resize、颜色转换和 NCHW 排列占用 CPU并增加输入拷贝。cv::imshow和 X11 软件显示会产生明显阻塞。如果摄像头帧进入普通队列推理速度低于采集速度时延迟会持续累积。NVMM、EGLImage、CUDA resource 和借用 FD 的生命周期必须明确管理。本项目采用独立 C runtime把采集、映射、预处理、推理、后处理和显示拆成职责清晰的模块。3. 最终架构MIPI CSI 摄像头Argus NV12 / NVMMnvvidconv RGBA / NVMMappsink opaque NVMM sample提取借用 FDEGLImageCUDA EGL 映射RGBA device viewCUDA resize/letterbox/RGB/CHWTensorRT YOLOv5nCPU 解码与 NMSCUDA 绘制框和逐框标签NvEglRenderer运行时使用两个单槽位CameraSource → LatestFrameSlot只保留最新摄像头帧 → inference worker → LatestResultSlot只保留最新检测结果及其对应帧 → main thread / NvEglRenderer这是一种实时系统常用的“保新不保全”策略。采集到的每一帧不一定都推理但送到屏幕上的结果不会因为队列积压而越来越旧。4. 工程结构假设下载后的项目根目录为PROJECT_ROOT/ ├── tensorrtx/yolov5/ # YOLOv5 TensorRT engine 构建器及插件 ├── yumi/ │ ├── CMakeLists.txt │ ├── config/ │ │ ├── camera.yaml │ │ ├── model.yaml │ │ └── coco.names │ ├── include/yumi/ │ ├── src/ │ └── tools/ └── yolov5n.pt # 需要自行准备主要模块职责模块职责CameraSource创建 Argus/GStreamer 管线并发布帧LatestFrameSlot只保存最新帧覆盖旧帧NvmmCudaMapperNVMM handle → FD → EGLImage → CUDA viewGpuPreprocessorCUDA 融合 resize、letterbox、RGBA→RGB、HWC→CHW 和归一化TrtEngine管理 TensorRT engine、binding、context 和 CUDA streamPostprocessor解码、置信度过滤、NMS 和原图坐标还原GpuDisplayOverlay在 NVMM surface 上绘制检测框和逐框标签LatestResultSlot保存检测结果以及产生该结果的同一帧HardwareDisplay使用NvEglRenderer显示借用 FDMetrics统计各阶段耗时、吞吐、P50/P95 和丢帧5. 准备系统环境5.1 确认 JetPack 组件先确认关键文件存在nvcc--versiondpkg-l|grep-Etensorrt|nvinfer|gstreamer|opencvls/usr/src/jetson_multimedia_api/include/nvbuf_utils.hls/usr/src/jetson_multimedia_api/samples/common/classes/NvEglRenderer.cpp本项目依赖 JetPack 提供的 CUDA、TensorRT、Argus、nvvidconv、libnvbuf_utils和 Jetson Multimedia API 示例源码。如果 Multimedia API 目录不存在应先安装与当前 L4T/JetPack 完全匹配的 Multimedia API而不是从其他 JetPack 版本复制头文件。5.2 安装通用开发依赖sudoaptupdatesudoaptinstall-y\build-essential\cmake\pkg-config\libopencv-dev\libgstreamer1.0-dev\libgstreamer-plugins-base1.0-dev\libx11-devEGL、GLES、CUDA 和libnvbuf_utils应使用 JetPack/L4T 自带版本。不要为了补头文件而混装其他 JetPack 版本或用 Mesa 库替换 NVIDIA 驱动库。检查 GStreamer 的 Jetson 插件gst-inspect-1.0 nvarguscamerasrc gst-inspect-1.0 nvvidconv两条命令都应能显示插件信息。6. 生成 YOLOv5n TensorRT engine6.1 为什么必须在目标 Nano 上生成TensorRT engine 包含与 GPU、TensorRT 版本和 tactic 选择相关的信息。不要直接复制其他 Jetson、PC 或其他 JetPack 版本生成的 engine。推荐在实际运行的 Nano 上重新序列化。本项目使用 tensorrtx 的自定义YoloLayer_TRT输出主程序也按该输出格式解码。不要用一份输出契约不同的 ONNX engine 替换它除非同时修改后处理逻辑。6.2 将.pt转成.wtsgen_wts.py需要在能够加载 YOLOv5 6.0 模型的 Python/PyTorch 环境中执行。可以在 Nano 上执行也可以在兼容的 PC 环境中只生成.wts之后把.wts复制到 Nano。在 YOLOv5 6.0 Python 环境中执行cdPROJECT_ROOTpython3 tensorrtx/yolov5/gen_wts.py\-wyolov5n.pt\-otensorrtx/yolov5/yolov5n.wts如果出现模型结构或anchor_grid不兼容通常是.pt、YOLOv5 源码和gen_wts.py不属于同一代版本。本文使用 YOLOv5 6.0 风格权重和源码。6.3 检查 tensorrtx 编译配置确认tensorrtx/yolov5/src/config.h中使用 FP16 和 80 类#defineUSE_FP16constexprstaticintkNumClass80;tensorrtx/yolov5/CMakeLists.txt中若存在其他机器的 TensorRT 8 路径例如/home/nvidia/TensorRT-8.2.5.1/include /home/nvidia/TensorRT-8.2.5.1/lib应删除或改为当前 JetPack 的系统路径/usr/include/aarch64-linux-gnu /usr/lib/aarch64-linux-gnuJetPack 4.5.1 自带 TensorRT 7.1.3不应混用 TensorRT 8 的头文件或库。6.4 编译 builder 并生成 enginecdPROJECT_ROOT/tensorrtx/yolov5 cmake-S.-Bbuild-native-DYOLO_INPUT_SIZE640cmake--buildbuild-native--targetyolov5_det--parallel2./build-native/yolov5_det\-syolov5n.wts yolov5n.nano.fp16.engine n其中最后一个参数n表示 YOLOv5n 的 depth/width 系数。成功后应得到PROJECT_ROOT/tensorrtx/yolov5/yolov5n.nano.fp16.engine输入尺寸是编译期契约。若改成 512 或 416必须用同一个尺寸重新编译 builder、插件和 engine不能只修改运行时 resize。7. 配置摄像头与模型7.1 摄像头配置编辑yumi/config/camera.yamlsensor_id:0sensor_mode:4width:1280height:720fps:60不同 CSI 摄像头的 mode 列表可能不同。先用以下命令观察 Argus 输出的模式gst-launch-1.0 nvarguscamerasrc sensor-id0num-buffers1\!video/x-raw(memory:NVMM)\!fakesink运行时日志会列出可用 Sensor modes。本文使用的摄像头中sensor_mode4对应 1280×72060 FPS。只写分辨率和帧率不一定能让 Argus 选择预期模式因此建议显式配置sensor_mode。7.2 模型配置yumi/config/model.yaml当前使用绝对路径。公开部署时必须改成读者机器上的真实路径engine:PROJECT_ROOT/tensorrtx/yolov5/yolov5n.nano.fp16.engineplugin:PROJECT_ROOT/yumi/build/libmyplugins.solabels:PROJECT_ROOT/yumi/config/coco.namesclasses:80confidence:0.45iou:0.35max_detections:30请把PROJECT_ROOT替换为绝对路径不能原样保留尖括号占位符。engine 和运行时插件来自同一份yololayer.cu输入尺寸和类别数也必须一致。8. 编译实时程序CUDA 10.2 对 CUDA C17 支持有限因此本工程让普通 C 模块使用 C17CUDA 预处理和显示模块使用 C14。cdPROJECT_ROOT/yumi cmake-S.-Bbuild-DCMAKE_BUILD_TYPERelease cmake--buildbuild--parallel2只重新构建主程序cmake--buildbuild--targetyumi_realtime--parallel2成功后会生成yumi/build/yumi_realtime yumi/build/libmyplugins.so如果看到以下警告cudaEGL.h: warning: extra ; [-Wpedantic]它来自 CUDA 10.2 系统头文件不影响构建结果。9. 先做分层验证不要一开始就运行完整显示链路。按“模型 → 摄像头 → NVMM 映射 → 主程序”的顺序排查定位更快。9.1 检查 enginecdPROJECT_ROOT/yumiLD_PRELOAD./build/libmyplugins.so\./build/engine_probe\PROJECT_ROOT/tensorrtx/yolov5/yolov5n.nano.fp16.engine应确认输入约为3×640×640 FLOAT32输出共 38001 个float。该输出对应1 1000 × sizeof(tensorrtx Detection) / sizeof(float)9.2 检查摄像头./build/camera_probe01280720601204camera_probe的参数依次是sensor_id width height fps frames sensor_mode它不读取camera.yaml所以这里显式传入 mode 4。如果需要直接验证 NVMM 到 CUDA 的映射./build/nvmm_probe01280720601204参数依次为sensor_id width height fps frame_count sensor_mode9.3 无显示运行./build/yumi_realtime--frames120先确认 TensorRT 推理、后处理和资源释放正常再启用显示。10. 运行硬件显示在 Jetson 桌面会话中执行cdPROJECT_ROOT/yumiDISPLAY:0\XAUTHORITY/run/user/1000/gdm/Xauthority\./build/yumi_realtime--display有限帧回归DISPLAY:0\XAUTHORITY/run/user/1000/gdm/Xauthority\./build/yumi_realtime--display--frames120当前硬件窗口使用终端CtrlC退出。如果桌面用户不是 UID 1000XAUTHORITY路径可能不同。可先检查DISPLAY:0\XAUTHORITY/run/user/1000/gdm/Xauthority\xset q10.1 CPU/OpenCV 回退路径用于排查 NVMM/EGL 问题DISPLAY:0\XAUTHORITY/run/user/1000/gdm/Xauthority\./build/yumi_realtime --host-input--display该路径会执行 CPU BGR 转换并使用cv::imshow性能低于默认硬件显示不建议作为正式运行方式。11. 如何阅读性能日志程序周期性输出[metrics] capture_fps... infer_fps... render_fps... preprocess_ms... gpu_preprocess_ms... execute_ms... e2e_ms... render_ms...退出时输出总计[summary] capture_frames... capture_fps... infer_frames... infer_fps... render_frames... e2e_p50_ms... e2e_p95_ms...主要字段字段含义capture_fps摄像头实际采集速度infer_fps完成推理和后处理的速度render_fps实际显示速度gpu_preprocess_msCUDA 融合预处理耗时execute_msTensorRT 网络执行耗时e2e_ms从采集到检测完成的端到端延迟render_msEGL 或 OpenCV 显示耗时camera_drop最新帧槽主动覆盖的过期摄像头帧result_drop显示跟不上时被覆盖的旧结果在本文实测中camera_drop持续增加是预期行为摄像头约 60 FPS而推理约 26 FPS。系统主动丢弃过期帧以保证延迟不累积。12. 零拷贝实现中的关键坑12.1 appsink 内存不是标准 dmabufJetPack 4.5.1 上appsink 得到的 allocator 名称为nvfilter。它是 opaque NVMM memory不是标准GstDmaBufMemory。实际映射链路为GstSample → GstBuffer → map opaque NVMM handle → ExtractFdFromNvBuffer → NvEGLImageFromFd → cuGraphicsEGLRegisterImage → cuGraphicsResourceGetMappedEglFrame不能假设可以直接调用通用 dmabuf API 取 FD。12.2 ExtractFdFromNvBuffer 返回借用 FD该 FD 属于上游 GStreamer/NVMM 缓冲池。当前模块只能借用禁止NvReleaseFd(fd);close(fd);错误释放后可能前几帧正常随后破坏nvvidconv缓冲池。12.3 sample 必须活到渲染完成以下资源存在严格依赖GstSample └─ opaque NVMM buffer └─ borrowed FD └─ EGLImage └─ CUDA graphics resource只有最后一个 CUDA/EGL 消费者完成后才能按逆序释放。项目使用 move-only RAII 对象保存这些资源并让检测结果持有产生该结果的同一 NVMM 帧。12.4 同一帧上绘制同一结果不能把 Frame N 的检测框画到最新的 Frame N2 上。当前顺序是Frame N → 预处理 → TensorRT → 后处理 → 在 Frame N 的 NVMM surface 上绘制 → render(Frame N fd) → 释放 Frame N这样检测框、类别、置信度和底图始终对应。12.5 类别标签不能使用 renderer 全局状态文字NvEglRenderer::setOverlayText()是固定坐标的全局文字不适合逐检测框标签。当前实现先在 CPU 栅格化很小的文字蒙版再由 CUDA 将类别和置信度合成到对应框左上角。它不需要下载整帧也不会退回 OpenCV 软件显示。13. 常见故障排查13.1cannot open config或cannot open engine检查model.yaml中是否仍然是作者机器的绝对路径。把engine、plugin和labels全部改为当前机器真实路径。13.2cannot open display/ EGL 窗口创建失败确认echo$DISPLAYls-l/run/user/1000/gdm/XauthorityDISPLAY:0XAUTHORITY/run/user/1000/gdm/Xauthority xset qSSH 环境下还需要确保 Jetson 本机已有有效桌面会话。13.3 Argus 找不到摄像头或 mode 不匹配先停止其他占用 CSI 摄像头的程序然后测试gst-launch-1.0 nvarguscamerasrc sensor-id0num-buffers30\!video/x-raw(memory:NVMM),width1280,height720,framerate60/1\!nvvidconv\!fakesink根据日志选择当前摄像头真实支持的sensor_mode。13.4 engine 反序列化失败常见原因engine 不是在当前 Nano/JetPack 上生成生成 engine 和运行程序使用了不同 TensorRT 版本自定义插件未加载libmyplugins.so与生成 engine 时的yololayer.cu不一致。删除旧 engine在当前设备重新构建和序列化。13.5 类别错误或框数量异常同时检查以下四处.pt/.wts模型实际类别数tensorrtx/yolov5/src/config.h的kNumClassmodel.yaml的classes标签文件行数。自定义类别模型修改后需要重新编译插件、重新生成 engine并重新构建yumi_realtime。13.6 编译时找不到NvEglRenderer.cpp确认ls/usr/src/jetson_multimedia_api/samples/common/classes/项目会直接编译该目录下的NvEglRenderer.cpp、NvElement.cpp和NvElementProfiler.cpp。不同 JetPack 的示例目录结构可能变化需要相应调整yumi/CMakeLists.txt。14. 优化过程与收益本项目不是一次性改成零拷贝而是按可验证步骤推进阶段改动结果基线CPU BGR、OpenCV 预处理和显示显示约 17 FPSGPU 预处理CUDA 融合 resize/letterbox/RGB/CHW降低 CPU 占用和预处理耗时NVMM→CUDA去除输入全帧 host staging 和 H2DGPU 预处理低于 1 ms混合显示CUDA RGBA→BGR 后全帧 D2Himshow仍是瓶颈CUDA overlay EGL原位画框FD 直接交给 renderer显示约 26 FPSrender 约 2.6 ms逐框标签小型字形蒙版 CUDA 合成保留硬件显示性能与正确标签位置最终主要瓶颈为TensorRT execute ≈ 35 ms继续优化低于 1 ms 的预处理不会让整体帧率翻倍。如果需要明显提高 FPS应优先测试 512/416 输入尺寸并使用验证集评估小目标召回率而不是盲目增加 CUDA stream 或承诺 INT8 一定更快。Jetson Nano 没有 Xavier/Orin 同级的 INT8 Tensor Core因此 INT8 是否优于 FP16必须实测。15. 复现验收清单建议按以下清单验收nvarguscamerasrc和nvvidconv插件可用当前摄像头 mode 能稳定输出 1280×72060 FPSengine 在目标 Nano 上生成engine、插件、类别数和输入尺寸一致engine_probe输出 binding 符合预期nvmm_probe连续 120 帧无映射错误无显示模式可完成 120 帧并正常退出EGL 显示模式下框、类别和置信度对应正确render_ms保持在数毫秒而不是几十毫秒端到端延迟不会随运行时间持续增长连续运行 10 分钟以上没有明显内存增长CtrlC后 Argus、CUDA、EGL 和 GStreamer 正常释放。16. 总结Jetson Nano 实时检测的关键不是只把模型转换成 TensorRT而是建立完整、可控的数据链路Argus/NVMM 采集 → CUDA EGL 零拷贝映射 → CUDA 融合预处理 → TensorRT FP16 推理 → CPU 解码与 NMS → CUDA 原位绘制 → NvEglRenderer 硬件显示这套实现把显示从约 17 FPS 提升到约 26 FPS并将 EGL 渲染控制在约 2.6 ms。当前性能上限主要由 640×640 YOLOv5n 的 TensorRT 网络执行时间决定而不是摄像头采集、预处理或显示。更重要的是系统使用最新帧槽位控制延迟并用 RAII 管理 NVMM、FD、EGLImage、CUDA resource 和GstSample生命周期。对实时视频系统而言这些数据流和所有权设计与模型推理速度同样重要。建议 CSDN 标签Jetson Nano、YOLOv5、TensorRT、CUDA、GStreamer、NVMM、嵌入式视觉
27届海归应届生求职机构横向测评,校招规划参考指南 2026年秋招已悄然启动,2027届海归即将面临回国求职的关键节点。教育部数据显示,2025年中国出国留学人数突破90万,海归回国就业规模持续攀升。但与此同时,国内校招赛道竞争白热化——头部互联网、金融、咨询名企的录取率已跌破2%&a…
【题解-信息学奥赛一本通】1355:字符串匹配问题(strs) 题目:1355:字符串匹配问题(strs) 题目描述 字符串中只含有括号 (),[],<>,{},判断输入的字符串中括号是否匹配。如果括号有互相包含的形式,从内到外必须是<>,(),[],{},例如。输入: [()] 输出:YES,而输入(…
学术文献格式互通存在壁垒,聊聊五款 CAJ 文档转换工具 日常查阅、整理知网文献资料时,CAJ 与通用文档、图像格式互相转换需求较多,各类 CAJ 转换程序支持的转换方向、批量处理、文档兼容范围各有区别。本文仅客观记录各程序运行方式、可处理文件范围与使用边界,不存在任何商业合作,不做…
Grok AI代码助手部署指南:从环境配置到性能优化实战 这次我们来看一个值得关注的数据趋势:Grok 网站访问量在半年内实现了 112.51% 的同比增长。这个增长背后反映的是 Grok 作为 AI 工具在开发者和技术社区中的快速普及。 从网络热词来看,Grok 相关的搜索主要集中在几个实用方向:Grok Build 的…
基于RAG与大模型的长尾搜题系统实战:选型、代码与优化策略 一、长尾搜题痛点与检索增强生成原理 在日常开发和技术排查中,长尾问题往往缺乏标准答案。传统搜索引擎返回大量链接,效率低下。引入大语言模型与检索增强生成技术,可有效解决这一痛点。大语言模型类似于通过海量数据训练的学霸,擅…
2026亲测有效:学信网照片尺寸不符合怎么办 免费解决方法 - 图片处理研究员 上周帮同事小陈弄学信网的学籍照片,他换了新手机拍的证件照,传上去系统一直提示"照片尺寸不符合要求"。他先拿手机自带裁剪工具切了一下,结果像素对上了文件又超了;又试了两个在线网站,不是弹广告就是导…
GLM5模型性能优化实战:从计算图到硬件加速 1. GLM5模型重构性能优化全攻略:从理论到实践最近在重构一个基于GLM5的推荐系统模型时,发现原有实现存在严重的性能瓶颈。经过两周的调优,最终将推理速度提升了3.2倍,内存占用降低了58%。今天就把这次性能优化的完整思路和实操经验…
嘉立创EDA格式STC系列模块-STC8G1K08A-36I-SOP8 在电子实训教学中,贴片封装芯片的焊接一直是学生面临的难点。SOP、TSSOP、LQFP等封装引脚密集,对焊接工艺要求高,容易成为教学中的"拦路虎"。嘉立创EDA的复用模块功能为这一难题提供了创新解决方案——通过设计专用转换板,将贴片引脚转换为易操作的直插引脚,既保…
【K8S 运维实战】10-配置与密钥ConfigMap 配置与密钥:ConfigMap、Secret 与外部配置中心 一句话定位:ConfigMap 热更新的坑 Secret 到底安不安全 Vault 集成实操。 写在前面 "我改了 ConfigMap,为什么 Pod 里的配置还是老的?"这个问题我每年要回答 50 遍。还有一类高频问题:“Secret 是 base64 编码,这不…
从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表) 更多请点击: https://intelliparadigm.com 第一章:从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表) 当AI副业主理人不再仅满足于单次服务交付,而是主动构建可复用、可裂变、可…
帝舵佛山**网点地址更新:2026年7月售后热线电话与服务客户指南 - 帝舵中国官方服务中心 帝舵佛山**网点地址已更新,2026年7月起售后热线电话正式启用为400-801-5381,客户指南同步发布。如需售后、维修或咨询服务,请直接拨打该全国统一**热线,服务时间每日8:00至22:00。地址信息详见下文,请按最新公布信…
亨得利盐城维修点在哪里?手表维修保养地址指南**公示(2026年7月最新) - 亨得利官方 亨得利在盐城设有**售后维修服务点,为当地及周边腕表用户提供标准化的保养与维修支持。2026年7月最新公示的全国统一客服热线为400-878-6612,服务时间为每日8:00至22:00,客户拨打时请确认使用本次公布的最新号码。*…
2026年7月最新太原百达翡丽官方售后客服电话及服务网点地址查询 - 百达翡丽官方售后中心 2026年7月,百达翡丽在太原的官方售后服务体系完成更新,客户可通过全国统一客服热线与服务网点获得直接、合规的腕表养护与维修支持。所有售后服务均遵循品牌直营标准,覆盖全国范围,客户可选择到店或邮寄方式,但需…
【JVM调优实战】16-可视化利器-JConsole-VisualVM-JMC 可视化利器:JConsole、VisualVM、JMC 实战 本文是《JVM调优实战》专栏第 16 讲。 引言 上一讲我们介绍了 JDK 命令行工具箱,它们轻量、快速,但有一个明显的短板:不直观。面对 jstat -gcutil 输出的一行行数字,你能感知 GC 频率,却难以一眼看出内存泄漏的趋势;你能用 js…
什么是PCTFE?医药高端包装的“防潮王牌“材料 ——日氟荣高分子材料(上海)有限公司 专业深耕氟材料领域很多人好奇,高端药品包装为什么比普通包装更防潮、更稳定、保质期更长?核心秘密,就藏在一种特种氟材料——PCTFE聚三氟氯乙烯里!作为国内领先的氟材…
[C++]内存管理:串顺序存储的内存回收 在串(字符串)的顺序存储中,内存回收的方式取决于字符串的存储方式以及所使用的编程语言和相关库。以下以 C 为例进行说明,因为 C 对内存管理有较为直接的控制。 1. 基于 char 数组的串顺序存储 如果使用普通的 char 数组来存储字…
移动端游戏功耗测试实战:电流、功率、亮度和场景对比 移动端游戏功耗测试:先控制变量,再比较优化是否真的省电 摘要:功耗测试最容易犯的错误,是拿两次不同温度、不同亮度、不同场景的平均功率直接比较。本文给出一套可复现的游戏功耗测试方法,覆盖引擎特性验证、版本回归和黑盒体验测试,并说明如何把功耗与帧率、温控、CPU/G…
足球口袋教练 HarmonyOS 离线应用实战(03/20):ArkUI 首页仪表盘搭建 本文是“足球口袋教练 HarmonyOS 离线应用实战”系列第 3 篇。示例项目是一个 HarmonyOS / ArkTS / ArkUI 编写的离线足球训练助手,围绕真实页面、真实截图和可复现操作展开。 本篇要解决的问题 训练 App 的首页不能只展示欢迎语,它要解决“我现在该点哪…