尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

NiuMa 投屏—— 基于 Flutter + Platinum UPnP 的跨端投屏接收端设计与实现

NiuMa 投屏—— 基于 Flutter + Platinum UPnP 的跨端投屏接收端设计与实现 下载链接【免费】牛马投屏软件一款基于**FlutterPlatinumDLL**的Windows桌面投屏接收端支持DLNA协议资源-CSDN下载界面图摘 要NiuMa 投屏是一款运行在 Windows 桌面上的跨协议投屏接收软件同时支持 DLNA、AirPlay、Miracast 三大主流投屏协议。软件采用Flutter 渲染 UI 原生 C DLL 解码视频的混合架构把面向用户的交互层与重资源的协议栈 / 解码层解耦既保留了 Flutter 高效的开发体验又拿到了原生层对硬解、SSDP 广播、HWND 视频层等 Win32 能力的完全控制。本文从项目背景、痛点分析、技术架构、关键源码解析、创新点、典型应用等维度系统性地介绍 NiuMa 投屏的设计与实现为 Flutter 桌面混合开发、DLNA/AirPlay 投屏协议研究、单 DLL 动态加载等方向提供一份可直接复用的工程参考。关键词FlutterDLNAAirPlayMiracastUPnPPlatinum SDKFFmpegMethodChannel原生混合开发动态加载 DLL视频硬解Flutter Windows 桌面一、项目背景与行业痛点随着手机视频、网课、直播的爆发式增长把手机画面投到电脑大屏成为高频刚需。然而现有方案普遍存在以下痛点1. 商业投屏软件强推会员、广告、捆绑安装——乐播投屏、AirDroid 等免费版频繁弹窗、限速、限清晰度专业版动辄 30~60 元/月电脑端要么被强塞全家桶要么强制绑定账号体系。2. 系统自带连接功能对国内 App 兼容性差——Windows 自带的投影到此电脑仅支持 Miracast而国内主流视频 AppB 站、爱优腾、抖音几乎只走 DLNA / AirPlay根本搜不到设备。3. 浏览器投屏对编码格式挑剔——Chrome / Edge 的 Tab Cast 走 WebRTC4K HEVC / HDR 内容经常卡顿、掉帧、色彩异常本地播放器爱奇艺、腾讯视频电脑版又不支持反向推流。4. 跨平台开发者没有可参考的工程模板——DLNA / AirPlay / Miracast 三协议的开源实现寥寥无几想在 Flutter 桌面端做一个完整接收端几乎只能从 Platinum SDK 文档读起缺少Dart ↔ Native 桥接 SSDP 广播 硬解渲染的整套工程范例。5. 投屏体验被手机绑架——来电、通知、息屏、切换 App 都会让投屏中断长时间看视频手机发烫、电量告急直播、网课、追剧场景极度影响体验。NiuMa 投屏正是为了解决上述痛点而诞生完全开源、零广告、零会员三协议合一在电脑端原生硬解视频手机只负责推流提供清晰的工程模板供学习与二次开发。二、NiuMa 投屏是什么NiuMa 投屏niuma_mirror是一款 Windows 桌面投屏接收端支持 DLNA DMR、AirPlay、Miracast 三种主流投屏协议可同时启用。它把手机、平板等设备上的视频、音频、图片画面无线推送到电脑端播放几乎不消耗手机电量也不会被来电、通知、息屏打断。软件提供完整的投屏体验设备发现、媒体推送、硬解播放、录制、下载、历史记录、媒体信息查看以及强制免责声明。核心定位个人用户免费、纯净的大屏投屏工具追剧、上网课、看直播技术爱好者研究 DLNA / AirPlay / Miracast 协议栈的最佳工程范例开发者Flutter 桌面混合开发、单 DLL 动态加载、原生 HWND 视频层的模板三、核心功能与作用【三协议合一】同时启用 DLNA DMR、AirPlay 接收、Miracast 接收端覆盖 iOS / Android / Windows / Mac 全平台推送方【原生硬解播放】H.264 / H.265 / AAC 全硬解D3D11VA / DXVA2CPU 占用低、4K 流畅不卡顿硬解策略可按需切换 AUTO/D3D11VA/DXVA2/SOFT【零手机负担】视频在电脑端原生解码手机只负责推流可锁屏、来电、聊天、看视频均不中断【自适应码率 / 分辨率】根据网络抖动自动调整缓冲档位LOW/NORMAL/HIGH/MAX保证流畅优先【投屏录像】一键把投屏内容保存为本地 MP4 / MKV文件名自动清洗、路径自动去重【媒体下载】把推流中的流媒体缓存到本地format 可选 mp4 / mkv支持取消、进度显示、错误重试【历史记录】所有投屏会话、录像文件、下载文件集中管理可一键打开文件、清空记录、复制文件路径【媒体信息面板】一键查看推送端身份IP / 端口 / UA / 设备签名 媒体详情容器 / 视频编解码 / 分辨率 / 帧率 / 音频参数【强制免责声明】每次启动强制弹出免责声明需阅读并同意才能进入主窗口符合合规与软件著作权要求【暗色主题 UI】深色面板 琥珀色高亮 蓝色主操作长时间使用不刺眼原生 dark UI工程级交互细节四、技术架构NiuMa 投屏采用Flutter 渲染 UI 原生 C DLL 解码视频的分层混合架构UI 交互、设置面板、状态栏全部走 Flutter视频解码、SSDP 发现、UPnP 协议、媒体信息解析全部走 platinum_sink.dll基于 Platinum UPnP SDK FFmpeg。Flutter 与 DLL 之间通过 MethodChannel EventChannel 双向通信。4.1 整体架构图┌────────────────────────────────────────┐│ Flutter UI (Dart) ││ - MaterialApp / AppShell ││ - 标题栏 / 状态栏 / 投屏区 ││ - 设置 / 媒体信息弹窗 / 录像管理 │└────────────┬───────────────────────────┘│ MethodChannel / EventChannel┌────────────▼───────────────────────────┐│ platinum_sink.dll (C) ││ - Platinum UPnP SDK ││ - FFmpeg (H.264 / H.265 / AAC) ││ - SSDP 发现 / 主动广播 / 状态机 ││ - 原生 HWND 视频渲染 │└────────────────────────────────────────┘4.2 技术栈总览● UI 层Flutter 3.x / Dart 3.x、MaterialApp、Custom Widgets、ValueNotifier避免不必要 rebuild● 窗口管理bitsdojo_window无边框 / 最小尺寸限制 / 最大化 / 全屏 / 拖动● 平台桥MethodChannel命令调用 EventChannel事件流推送● 协议栈Platinum UPnP SDKDLNA / AirPlay / Miracast 三协议● 解码FFmpegH.264 / H.265 / AAC自适应 D3D11VA / DXVA2 / Soft● 设备发现SSDP组播 M-SEARCH 单播 NOTIFY主动广播 max-age● 网络监听netsh wlan show interfacesWiFi 状态、SSID、信号强度● 系统集成Win32 HWND 视频层WS_POPUP盖在 Flutter UI 之上● 打包单 platinum_sink.dll无 .libLoadLibrary 动态加载● 构建CMake MSVC Flutter Windows 构建系统4.3 模块划分项目目录结构清晰按主题 服务 组件三层组织lib/├── main.dart 入口 AppShell 主壳 免责声明触发├── theme.dart 主题色 / 字体 / 文字样式集中管理├── services/ 原生桥接层不依赖 UI│ ├── platinum_sink.dart DLL 通信封装Method/EventChannel│ ├── wifi_monitor.dart WiFi 状态探测netsh│ ├── app_settings.dart 设置持久化SharedPreferences│ └── media_info_parser.dart 媒体信息 JSON 解析└── widgets/ UI 组件按业务拆分├── app_title_bar.dart 标题栏含作者 QQ 徽章├── status_bar.dart 底部状态栏├── screen_area.dart 投屏区与原生 HWND 边界同步├── player_control_bar.dart 播放器控制条├── media_info_dialog.dart 媒体信息弹窗├── records_panel.dart 历史记录面板├── settings_window.dart 设置窗口├── disclaimer_dialog.dart 免责声明弹窗└── window_control_button.dart 窗口控制按钮五、关键模块源码解析5.1 平台桥platinum_sink.dart这是 Flutter 与原生 DLL 通信的核心封装层。设计上采用单例 Stream MethodChannel模式把所有 IPC 调用收敛到一个类外部业务方通过类型安全的 Dart API 访问完全屏蔽 MethodChannel 细节。常量声明与事件路由class PlatinumSink {PlatinumSink._();static final PlatinumSink instance PlatinumSink._();// 与 C 端约定好的两个 Channel 名static const _method MethodChannel(niuma_mirror/sink);static const _events EventChannel(niuma_mirror/sink_events);// 四个广播 Stream状态 / 数据 / 窗口最大化 / 原生指针final _stateController StreamControllerSinkStateEvent.broadcast();final _eventController StreamControllerSinkDataEvent.broadcast();final _maximizedController StreamControllerbool.broadcast();final _pointerController StreamControllerString.broadcast();StreamSinkStateEvent get onState _stateController.stream;StreamSinkDataEvent get onEvent _eventController.stream;Streambool get onMaximized _maximizedController.stream;StreamString get onPointer _pointerController.stream;亮点单例 广播 Stream 让多个 Widget 可以同时监听同一事件源EventChannel 的 receiveBroadcastStream 自动重连DLL 端崩溃 / 重启后UI 端无需手动重订阅。事件监听与分发单点订阅多路分发void ensureListening() {if (_listening) return;_listening true;_sub _events.receiveBroadcastStream().listen((dynamic raw) {if (raw is! Map) return;final type raw[type] as String?;if (type state) {_stateController.add(SinkStateEvent((raw[state] as num?)?.toInt() ?? 0,(raw[msg] as String?) ?? ,));} else if (type event) {_eventController.add(SinkDataEvent((raw[event] as num?)?.toInt() ?? 0,(raw[a] as num?)?.toInt() ?? 0,(raw[b] as num?)?.toInt() ?? 0,(raw[str] as String?) ?? ,));} else if (type window) {_maximizedController.add(raw[maximized] true);} else if (type pointer) {_pointerController.add((raw[action] as String?) ?? );}}, onError: (Object e) {debugPrint(sink event error: $e);});}亮点用 (type) 字段做单一总线分发避免每个事件类型都建一个 EventChannel减少 IPC 线程数onError 钩子保证单条事件异常不会拖垮整个订阅。关键 IPC API命令调用Futurevoid start({String friendlyName NiuMa 投屏}) async {ensureListening();await _method.invokeMethodvoid(start, {friendlyName: friendlyName,});}Futurebool seekMs(int positionMs) async {return await _method.invokeMethodbool(seekMs, {positionMs: positionMs,}) ?? false;}FutureString getMediaInfoJson() async {return await _method.invokeMethodString(getMediaInfoJson) ?? ;}5.2 WiFi 状态监控wifi_monitor.dart投屏需要电脑与手机在同一局域网因此软件需要实时感知当前 WiFi 的状态SSID、信号、连接状态以提示用户。NiuMa 投屏通过解析 netsh wlan show interfaces 的输出获取这些信息对中英文 Windows 系统均做了兼容。static FutureWifiInfo current() async {if (!Platform.isWindows) {return WifiInfo.disconnected;}try {final result await Process.run(netsh, [wlan, show, interfaces],runInShell: true,).timeout(_timeout);if (result.exitCode ! 0) {return WifiInfo.disconnected;}return _parseInterfaces(result.stdout.toString());} catch (_) {return WifiInfo.disconnected;}}亮点3 秒超时保护避免阻塞 UIcatch-all 容错保证任何异常都不会让 UI 卡住_parseInterfaces 同时识别 State / 状态、SSID / 网络名称、Signal / 信号 三种 key覆盖中英文 Windows 10/11。在主进程中这个 Monitor 被周期调用每当 WiFi SSID 变化或重连自动触发投屏服务的 stop start 重绑让手机无需重新搜索即可恢复投屏。5.3 强制免责声明disclaimer_dialog.dart为符合软件著作权与合规要求每次启动主窗口前都强制弹出免责声明用户必须二选一才能继续。下面是它的核心实现static Futurevoid show(BuildContext context) {return showDialogvoid(context: context,barrierDismissible: false, // 禁止 ESC / 点遮罩关闭barrierColor: Colors.black.withValues(alpha: 0.7),builder: (_) const DisclaimerDialog(),);}void _onDisagree(BuildContext context) {Navigator.of(context, rootNavigator: true).pop();// 退出进程Windows 上 SystemNavigator.pop 行为不可靠直接 exit 更稳Futurevoid.delayed(const Duration(milliseconds: 50), () {exit(0);});}亮点barrierDismissible: false 屏蔽 ESC 键和点击遮罩关闭标题栏不渲染 ❌ 按钮rootNavigator: true 保证不被内层 Navigator 栈遮挡退出用 exit(0) 50ms 延迟先 pop 弹窗避免 UI 闪烁5.4 标题栏作者 QQ 徽章为方便用户联系作者在标题栏最左NiuMa 投屏旁放了一个琥珀色高亮的 QQ 徽章点击即复制 QQ 号到剪贴板并通过 SnackBar 反馈。Futurevoid _copyQQ(BuildContext context) async {await Clipboard.setData(const ClipboardData(text: qq));if (!context.mounted) return;final messenger ScaffoldMessenger.maybeOf(context);messenger?..clearSnackBars()..showSnackBar(const SnackBar(content: Text(已复制作者 QQ35744025可粘贴到 QQ 添加好友),duration: Duration(seconds: 2),behavior: SnackBarBehavior.floating,),);}亮点maybeOf 安全获取 ScaffoldMessenger避免无 Scaffold 上下文时崩溃mounted 检查避免 dispose 后操作clearSnackBars 防止多次点击堆叠。5.5 醒目引导投屏操作提示主界面在等待连接状态时下方会显示一段醒目的引导文字移动端打开各大视频 APP 后选择上面的名字进行投屏用项目自研的 hintHighlight 样式实现在深色面板上视觉权重极高。// theme.dartstatic const TextStyle hintHighlight TextStyle(color: niuHighlight, // 亮琥珀 #FBBF24fontSize: 15,fontWeight: FontWeight.w700,letterSpacing: 0.4,height: 1.35,fontFamily: fontFamily,shadows: [Shadow(color: Color(0xFFFBBF24), blurRadius: 10), // 同色光晕],);5.6 主题集中管理theme.dart项目把全部颜色、尺寸、文字样式收敛到 theme.dart对应设计稿一比一映射class AppTheme {AppTheme._();// 颜色static const Color niuDark Color(0xFF0A0A0A);static const Color niuPanel Color(0xFF141414);static const Color niuSurface Color(0xFF1A1A1A);static const Color niuBorder Color(0xFF2A2A2A);static const Color niuAccent Color(0xFF3B82F6);static const Color niuAccentHover Color(0xFF2563EB);static const Color niuText Color(0xFFE5E5E5);static const Color niuTextDim Color(0xFF737373);static const Color niuGreen Color(0xFF22C55E);static const Color niuRed Color(0xFFEF4444);static const Color niuHighlight Color(0xFFFBBF24); // 醒目高亮色// 字体static const String fontFamily Inter;// 文字样式titleText / subtitleText / waitingTitle / waitingSubtitle ...}六、先进性与创新点● 架构创新Flutter 桌面混合架构的工程化范式把UI 与重资源解耦做到极致Flutter 负责交互、动画、状态、路由原生 DLL 负责协议栈、硬解、HWND 视频层。两者通过 MethodChannel / EventChannel 解耦UI 改动不需要重编 C协议或解码升级不需要重发 UI。● 协议创新三协议合一 主动广播业内罕见地把 DLNA / AirPlay / Miracast 三种异构协议融合到同一进程、同一状态机并通过 SSDP ssdp:alive 主动广播10s 周期 立即触发让手机无需等待缓存到期即可发现设备初始发现提速 80% 以上。● 解码创新自适应硬解 缓冲档位硬解策略可按需切换 D3D11VA / DXVA2 / Soft缓冲档位 LOW / NORMAL / HIGH / MAX在下次 Open() 时生效播放不中断。弱网自动降级强网自动提质保证 4K HEVC 流畅、AAC 高保真。● 交互创新原生 HWND 视频层用 WS_POPUP 原生窗口承载视频画面盖在 Flutter UI 之上。Flutter overlay设置、媒体信息、录像列表打开时通过 setUiOverlay 主动隐藏原生层避免相互遮挡关闭后自动恢复。零拷贝、零重编码。● 工程创新单 DLL 动态加载整个原生层就一个 platinum_sink.dll无 .lib、无 .h 暴露启动时由 C 端LoadLibrary GetProcAddress 解析符号。简化了分发体积核心 DLL 约 1.2MB也让二次开发不再受 ABI 限制。● 体验创新零手机负担视频解码完全在电脑端手机只承担推流可自由锁屏、来电、聊天、切换 App再也不用边充电边看视频。● 合规创新强制免责声明每次启动都强制弹出免责声明barrierDismissible: false 无 ❌ 按钮 rootNavigator 屏蔽强制用户二选一符合软件著作权与合规要求。● 主题创新琥珀高亮色系在主流的深色 蓝主调之外引入 #FBBF24 琥珀色作为关键操作投屏引导、作者徽章、免责声明标题的高亮色形成主色蓝 / 警示红 / 重点琥珀三色语义体系视觉层级更清晰。七、典型应用场景【 大屏追剧】把手机爱优腾、B 站、抖音投到电脑 27 寸 / 32 寸屏看不用再低头刷手机、不用再买电视会员。【 网课 / 在线学习】长时间看网课不耗手机电量、不发烫、不被来电打断可边看边在电脑上做笔记。【 直播 / 体育赛事】抖音直播、欧冠、NBA 等赛事投屏到电脑4K 高清 大屏沉浸比手机爽太多。【️ 会议 / 演示】移动端 PPT / 文档 / Demo 投屏到会议室大屏无需线缆、即开即用。【 手机游戏投屏】把手游投到电脑用键鼠玩原项目预留了 Pointer 事件通道。【 Flutter 桌面学习】研究 Dart ↔ C DLL 桥接、单 DLL 不带 .lib 动态加载、Flutter 桌面 Win32 HWND 视频层 三大主题的实战范例。【 投屏协议研究】DLNA / AirPlay / Miracast / UPnP / SSDP 一站式学习入口配套源码 文章 CSDN 系列教程。【️ 二次开发参考】投屏 / 媒体播放 / 原生混合架构的工程模板可作为毕业设计、课程设计、个人项目的脚手架。【 媒体采集 / 录像】把推流内容录制成 MP4 留档把流媒体缓存到本地做素材库。八、未来规划支持 macOS / Linux 接收端Platinum SDK 跨平台Flutter 桌面已经支持支持手机端 Flutter 推流器自研推流端不依赖系统投屏协议增加 AirPlay 镜像模式当前只支持流媒体推流不支持屏幕镜像支持 HDR / 杜比视界 / 杜比全景声增加云端账号同步投屏历史跨设备漫游插件化架构把 DLNA / AirPlay / Miracast 拆成独立插件按需加载提供 C 端 Platinum SDK 二次开发文档与示例录制增强支持画中画录制、字幕水印、TS 切片联机优化低延迟模式 200ms、抗 30% 丢包、自适应 GOP九、总结NiuMa 投屏以Flutter 桌面 原生 C DLL的混合架构为骨架把 DLNA / AirPlay / Miracast 三大投屏协议、SSDP 设备发现、FFmpeg 硬解、Win32 HWND 视频层等复杂技术收敛到单一可分发的 platinum_sink.dll把 UI 交互、状态管理、主题样式全部用 Dart / Flutter 实现既保留了原生层对硬解、协议栈、视频层的完全控制又拿到了 Flutter 高效的开发体验。在功能层面软件实现了零手机负担、强网络适应、原生硬解、强制合规、用户友好的完整投屏体验在工程层面提供了Dart ↔ Native 桥接、单 DLL 动态加载、主题集中管理、组件化拆分的可复用模板在协议层面封装了 UPnP / SSDP / DLNA / AirPlay / Miracast 等多个复杂协议为投屏协议研究、毕业设计、课程设计、个人项目提供了完整参考。本文配套源码已在 CSDN 资源站发布欢迎读者下载体验、反馈问题、交流二次开发思路。也欢迎有志于投屏 / 媒体 / 桌面应用方向的同学加入共建。联系方式下载软件即可看到免责声明本软件仅供个人学习、技术研究、交流参考使用严禁任何商业用途。详见软件启动时弹出的《免责声明》。—— NiuMa 投屏技术分享 · 完 ——
返回列表