基于 Platinum SDK(铂金)的 Android DLNA 学习项目,用于在 Android 上实现 DLNA 服务端/客户端能力。
| Video | Audio | Image |
|---|---|---|
![]() |
![]() |
![]() |
该项目基于 C++ 开源库 Platinum SDK(铂金)学习 DLNA 服务协议,Platinum 又依赖于 C++ 开源库 Neptune(海王星)。源码本身已适配 Android,无需修改即可编译,Log 打印也完美兼容。
DLNA(数字生活网络联盟)涉及三种核心角色:
- Digital Media Server (DMS) 数字媒体服务器:提供媒体档案的获取、录制、储存,作为内容来源。
- Digital Media Renderer (DMR) 数字媒体渲染器:接收并播放从 DMC 推送过来的多媒体(图片、音乐、视频)。
- Digital Media Controller (DMC) 数字媒体控制器:作为遥控装置,寻找 DMS 上的多媒体档案,并指定可播放该档案的 DMR 进行播放或控制。
本项目把这套能力封装为标准的 Android Gradle 多模块工程,原生代码通过 JNI 暴露给 Java 层调用。
PlatinumMedia/
├── settings.gradle # 根配置,包含 :platinum :client :server 三个子模块
├── build.gradle # 根构建脚本(AGP 8.9.1)
├── platinum/ # 原生库模块(com.android.library)
│ └── src/main/
│ ├── cpp/ # C/C++ 源码与 CMake 构建脚本
│ │ ├── CMakeLists.txt # 编译 libplatinum.so(arm64-v8a)
│ │ ├── PlatinumApi.{h,cpp} # JNI 桥接入口
│ │ ├── Hupnp/ # Android 侧封装(AndUPnP 等)
│ │ ├── Neptune/ # Neptune 运行时(Core/System/...)
│ │ ├── Platinum/ # Platinum UPnP SDK
│ │ │ ├── Core/ # 控制点、设备主机、SSDP、HTTP、任务
│ │ │ ├── Devices/ # MediaServer / MediaRenderer / MediaConnect
│ │ │ └── Extras/ # 额外工具
│ │ └── json/ # nlohmann JSON(参数解析)
│ └── java/com/plutinosoft/platinum/
│ └── NativeUpnpApi.java # 单例 JNI 封装(loadLibrary "platinum")
├── server/ # DMR 渲染器 App(com.hzy.platinum.server)
│ └── src/main/java/com/hzy/platinum/server/
│ ├── activity/ # SplashActivity(显示版本)/ MainActivity(播放界面)
│ ├── service/ # DLNAService(前台服务 + 多播锁 + 原生渲染器)
│ ├── player/ # PlayerManager(按渲染器事件驱动 MediaPlayer)+ MediaType(媒体类型判定)
│ └── utils/UUIDUtils # 持久化设备 UUID
└── client/ # DMC 控制器 App(com.hzy.platinum.client)
└── src/main/java/com/hzy/platinum/client/
└── activity/ # SplashActivity / MainActivity(设备发现 + 投送控制)
原生库 libplatinum.so 由 platinum/src/main/cpp/CMakeLists.txt 通过 GLOB_RECURSE 编译所有 *.cpp 生成,链接 log、android,目标 ABI 为 arm64-v8a。LOAD 段已按 16 KB 对齐(-Wl,-z,max-page-size=16384),兼容 Android 15+ 16 KB 设备。
JNI 入口集中在 PlatinumApi.{h,cpp},通过 JNI_FUNC 宏映射到 Java 类 com.plutinosoft.platinum.NativeUpnpApi:
| JNI 函数 | 作用 |
|---|---|
getVersionString |
返回 PLT_PLATINUM_SDK_VERSION_STRING |
nInit |
创建 AndUPnP 实例并返回指针(C++ 对象句柄) |
nSetCallback |
注册 Java 回调 onEvent(String):String |
nAddRenderer |
解析 JSON 参数并添加 PLT_MediaRenderer 设备(含 AndMediaRenderer 委托) |
nAddController |
解析 JSON 参数并添加 PLT_MediaController 控制点(含 AndMediaController 委托,负责设备发现) |
nInvokeAction |
解析 JSON 动作并发送到指定渲染器(DMC 投送指令) |
nStart / nStop |
启动 / 停止 PLT_UPnP |
AndUPnP(位于 Hupnp/AndUPnP.{h,cpp})封装了 PLT_UPnP,负责:
AddRenderer:从 JSON(friendly_name/show_ip/uuid/port/port_rebind)构造PLT_MediaRenderer,并通过AndMediaRenderer委托把 AVTransport/RenderingControl 指令序列化为 JSON 回调 Java;AddController:创建PLT_CtrlPoint+PLT_MediaController,由AndMediaController委托把发现的渲染器({"type":"device",...})与动作结果({"type":"action",...})上抛 Java;InvokeAction:按uuid+action查找渲染器并调用对应 AVTransport/RenderingControl 动作;notifyJEvent:通过缓存的JavaVM*跨线程AttachCurrentThread,回调 Java 的onEvent,实现原生事件上抛。
Java 侧 NativeUpnpApi 为单例枚举,持有 mInstanceId(C++ 实例指针),并提供 init / addRenderer / addController / invokeAction / start / stop 高层方法,以及 dispatch(String, NativeDelegate) 把原生 JSON 事件分派给 onRendererEvent / onDeviceEvent / onActionResult。
- server(DMR 渲染器):
DLNAService前台服务获取 WiFi 多播锁、初始化原生渲染器并持久化设备 UUID;原生层收到控制器指令(SetAVTransportURI / Play / Pause / Stop / Seek / SetVolume / SetMute)后通过onRendererEvent驱动PlayerManager(基于MediaPlayer+SurfaceView)实际播放,Activity 仅做界面与控制。- 多类型媒体 UI:
MediaType(player/MediaType.java)按 URI / 元数据 MIME 自动判定VIDEO/AUDIO/IMAGE/UNKNOWN。PlayerManager根据类型切换 UI:视频走SurfaceView渲染画面;音频隐藏画面、显示音频占位与媒体信息;图片通过HttpURLConnection后台下载并回调onImage(Bitmap)显示到ImageView。MainActivity通过onMediaType/onImage/onUri/onStateChanged等StateListener回调实时切换界面与进度条。
- 多类型媒体 UI:
- client(DMC 控制器):
MainActivity通过addController启动发现,列表展示局域网内渲染设备;选定设备后输入媒体 URL,发送 SetAVTransportURI + Play 进行投送,并支持 Pause / Stop / Seek / 音量调节。
- 安装
server到一台设备(手机/电视),启动即作为 DLNA 渲染器上线(前台通知常驻)。 - 安装
client到同一局域网的另一台设备,自动发现渲染器。 - 在 client 选中渲染器,输入形如
http://192.168.1.10:8080/video.mp4的媒体地址,点「投送」即可在 server 端播放。 - 也可用任意标准 DLNA 控制器(如 BubbleUPnP)向 server 投送。
依赖 Android NDK + CMake 编译原生代码。
./gradlew :server:assembleDebug # 构建 DMR App
./gradlew :client:assembleDebug # 构建 DMC App签名使用模块内置 demokey.jks(demokey / demokey)。platinum 模块 minSdk 15,debug 构建开启 NPT_CONFIG_ENABLE_LOGGING 与 NPT_DEBUG。
- 图片加载:
PlayerManager通过HttpURLConnection下载图片后直接解码为Bitmap,未做inSampleSize缩放,超大图存在 OOM 风险,后续可加采样与尺寸约束。 - 编译兼容性:模块
sourceCompatibility / targetCompatibility目前为Java 8,在 JDK 21 环境下仅产生告警(不影响构建);如需消除告警可升级到Java 17。 - JNI 跨线程:原生事件通过缓存的
JavaVM*在任意线程AttachCurrentThread后回调 Java,回调对象(onEvent)以全局引用持有,避免回收后空指针。
- Platinum UPnP SDK
- Neptune C++ Runtime
- nlohmann/json(原生 JSON 解析)
- ViewBinding(Android Gradle Plugin 内置,视图绑定)
- ViewBinding(Android Gradle Plugin 内置,替代原 ButterKnife 视图绑定)
- AndroidUtilCode
- GitHub: https://huzongyao.github.io/
- ITEye博客:https://hzy3774.iteye.com/
- 新浪微博: https://weibo.com/hzy3774
- QQ: 377406997
- Gmail: hzy3774@gmail.com
- Foxmail: hzy3774@qq.com
- WeChat: hzy3774




