下载链接:

【免费】牛马投屏软件:一款基于**Flutter+Platinum(DLL)**的Windows桌面投屏接收端,支持DLNA协议资源-CSDN下载

界面图

摘  要

NiuMa 投屏是一款运行在 Windows 桌面上的跨协议投屏接收软件,同时支持 DLNA、AirPlay、Miracast 三大主流投屏协议。软件采用"Flutter 渲染 UI + 原生 C++ DLL 解码视频"的混合架构,把面向用户的交互层与重资源的协议栈 / 解码层解耦,既保留了 Flutter 高效的开发体验,又拿到了原生层对硬解、SSDP 广播、HWND 视频层等 Win32 能力的完全控制。本文从项目背景、痛点分析、技术架构、关键源码解析、创新点、典型应用等维度,系统性地介绍 NiuMa 投屏的设计与实现,为 Flutter 桌面混合开发、DLNA/AirPlay 投屏协议研究、单 DLL 动态加载等方向提供一份可直接复用的工程参考。

关键词:Flutter;DLNA;AirPlay;Miracast;UPnP;Platinum SDK;FFmpeg;MethodChannel;原生混合开发;动态加载 DLL;视频硬解;Flutter Windows 桌面

一、项目背景与行业痛点

随着手机视频、网课、直播的爆发式增长,"把手机画面投到电脑大屏"成为高频刚需。然而现有方案普遍存在以下痛点:

1. 商业投屏软件强推会员、广告、捆绑安装——乐播投屏、AirDroid 等免费版频繁弹窗、限速、限清晰度,专业版动辄 30~60 元/月;电脑端要么被强塞全家桶,要么强制绑定账号体系。

2. 系统自带"连接"功能对国内 App 兼容性差——Windows 自带的"投影到此电脑"仅支持 Miracast,而国内主流视频 App(B 站、爱优腾、抖音)几乎只走 DLNA / AirPlay,根本搜不到设备。

3. 浏览器投屏对编码格式挑剔——Chrome / Edge 的 Tab Cast 走 WebRTC,4K 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 / DXVA2),CPU 占用低、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 SDK:DLNA / AirPlay / Miracast 三协议

● 解码:FFmpeg:H.264 / H.265 / AAC,自适应 D3D11VA / DXVA2 / Soft

● 设备发现:SSDP:组播 M-SEARCH + 单播 NOTIFY,主动广播 + max-age

● 网络监听:netsh wlan show interfaces:WiFi 状态、SSID、信号强度

● 系统集成:Win32 HWND 视频层(WS_POPUP),盖在 Flutter UI 之上

● 打包:单 platinum_sink.dll,无 .lib,LoadLibrary 动态加载

● 构建: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    = StreamController<SinkStateEvent>.broadcast();
  final _eventController    = StreamController<SinkDataEvent>.broadcast();
  final _maximizedController= StreamController<bool>.broadcast();
  final _pointerController  = StreamController<String>.broadcast();
 
  Stream<SinkStateEvent> get onState  => _stateController.stream;
  Stream<SinkDataEvent> get onEvent  => _eventController.stream;
  Stream<bool>           get onMaximized => _maximizedController.stream;
  Stream<String>         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(命令调用):

Future<void> start({String friendlyName = 'NiuMa 投屏'}) async {
  ensureListening();
  await _method.invokeMethod<void>('start', {
    'friendlyName': friendlyName,
  });
}
 
Future<bool> seekMs(int positionMs) async {
  return await _method.invokeMethod<bool>('seekMs', {
    'positionMs': positionMs,
  }) ?? false;
}
 
Future<String> getMediaInfoJson() async {
  return await _method.invokeMethod<String>('getMediaInfoJson') ?? '';
}

5.2 WiFi 状态监控:wifi_monitor.dart

投屏需要电脑与手机在同一局域网,因此软件需要实时感知当前 WiFi 的状态(SSID、信号、连接状态)以提示用户。NiuMa 投屏通过解析 `netsh wlan show interfaces` 的输出获取这些信息,对中英文 Windows 系统均做了兼容。

static Future<WifiInfo> 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 秒超时保护避免阻塞 UI;catch-all 容错保证任何异常都不会让 UI 卡住;`_parseInterfaces` 同时识别 "State / 状态"、"SSID / 网络名称"、"Signal / 信号" 三种 key,覆盖中英文 Windows 10/11。

在主进程中,这个 Monitor 被周期调用:每当 WiFi SSID 变化或重连,自动触发投屏服务的 stop + start 重绑,让手机无需重新搜索即可恢复投屏。

5.3 强制免责声明:disclaimer_dialog.dart

为符合软件著作权与合规要求,每次启动主窗口前都强制弹出免责声明,用户必须二选一才能继续。下面是它的核心实现:

static Future<void> show(BuildContext context) {
  return showDialog<void>(
    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 更稳)
  Future<void>.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 反馈。

Future<void> _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('已复制作者 QQ:35744025,可粘贴到 QQ 添加好友'),
        duration: Duration(seconds: 2),
        behavior: SnackBarBehavior.floating,
      ),
    );
}

亮点:maybeOf 安全获取 ScaffoldMessenger,避免无 Scaffold 上下文时崩溃;mounted 检查避免 dispose 后操作;clearSnackBars 防止多次点击堆叠。

5.5 醒目引导:投屏操作提示

主界面在"等待连接"状态时,下方会显示一段醒目的引导文字("移动端打开各大视频 APP 后,选择上面的名字进行投屏"),用项目自研的 `hintHighlight` 样式实现,在深色面板上视觉权重极高。

// theme.dart
static const TextStyle hintHighlight = TextStyle(
  color: niuHighlight,                    // 亮琥珀 #FBBF24
  fontSize: 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 投屏技术分享 · 完 ——

Logo

一站式 AI 云服务平台

更多推荐