一、DRM 是什么?解决什么问题?
目标:控制“谁、在什么条件下、以什么清晰度/时长/设备/输出方式”播放受保护的音视频。
核心思路:媒体按片段被加密;客户端在受信任环境里拿许可证/密钥→解密→安全解码与输出。
二、体系结构(端到端)
-
打包/加密(Packager)
- 典型:CENC(Common Encryption)家族,常见模式 cenc/cbcs;容器多为 MP4/CMAF。
- HLS 也支持 AES-128 与 SAMPLE-AES;现代 HLS 常用 CMAF(与 DASH 统一打包)。
-
许可证/密钥服务(License Server / KMS)
- 根据用户/设备/地域/并发/有效期等策略下发许可证(包含解密密钥)。
-
客户端 DRM 模块(CDM/MediaDrm)
- 建会话 → 发送 许可证请求 → 拿到密钥 → 在受保护路径解密样本。
-
安全解码与输出(Secure Path)
-
硬件安全环境(TEE)、Secure Decoder、Secure Surface、外接显示要求 HDCP 等。
-
三、主流 DRM 方案
| 方案 | 生态/平台 | 说明 |
|---|---|---|
| Widevine | Android、Chrome、很多智能电视 | 分 L1/L2/L3 安全等级(L1=全链路硬件安全,支持高码率/4K;L3=纯软件) |
| PlayReady | Windows/Edge、部分电视 | 与 Widevine 并列的广泛商用方案 |
| FairPlay Streaming | iOS、tvOS、Safari | 苹果生态专用 |
| ClearKey | 测试/低风险内容 | 明文密钥机制,适合联调与非敏感内容 |
CMAF 一套打包 + 多清单(HLS/DASH) + 多 DRM(Widevine/PlayReady/FairPlay) 是跨平台常见做法。
四、播放时的工作流程(简化)
加密媒体片段 ──> 播放器读取清单/容器中的初始化数据(PSSH/KEY URI)
└─> 客户端CDM/MediaDrm 生成 License Request
└─> 许可证服务器校验并返回密钥(license)
└─> 客户端在受保护环境解密样本 → 解码 → 渲染到安全输出
五、关键能力与策略
-
权限/策略:有效期(租赁/购买)、地域限制、并发设备数、清晰度上限、是否允许离线、输出保护(HDCP)。
-
离线播放:下发持久许可证(Persistent License),本地缓存密钥;到期需续租。
-
Key Rotation:直播/长视频定期换 Key,降低泄露风险。
-
水印:可与 DRM 搭配客户端/服务端水印,定位泄露源(DRM 仅防技术窃取,不防“屏摄”)。
六、Android 开发者视角(ExoPlayer/Media3)
最简使用(Widevine 例子)
val drmCfg = MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID)
.setLicenseUri(licenseUrl)
// .setMultiSession(true) // 多轨/多Key可打开
.build()
val item = MediaItem.Builder()
.setUri(videoUrl) // HLS/DASH/MP4 都可
.setDrmConfiguration(drmCfg)
.build()
val player = ExoPlayer.Builder(context).build()
player.setMediaItem(item)
player.prepare()
player.play()
安全链路要点****
-
Widevine 安全等级:L1(TEE+Secure Decoder+Secure Surface)> L3(软件解码)。很多平台会对 L3 限制分辨率/码率。
-
禁止截图/录屏:窗口设 FLAG_SECURE;视频面板用 Secure Surface(系统/DRM组合决定)。
-
错误处理:区分 DRM_SESSION_ERROR、LicenseExpired 等,按提示走重试/续租/降级清晰度。
七、打包与清单(服务端)
-
DASH(.mpd) :MPD 的 ContentProtection/cenc:pssh 指定 DRM;片段多为 fMP4/CMAF。
-
HLS(.m3u8) :#EXT-X-KEY 指定密钥/方法;现代 HLS 常走 CMAF fMP4 并配合 Widevine/PlayReady/FairPlay。
-
工具链:Shaka Packager / bento4 / 商用多 DRM 平台。
-
低延迟:LL-HLS/LL-DASH + chunked CMAF,客户端再配 LiveConfiguration。
八、与“媒体管线”的衔接
-
DRM 是解码前的一道门:解密成功 → 解码 → 渲染。
-
在 Android 管线中:MediaSource → (可选缓存/自适应) → Extractor/ChunkSource → DrmSession(MediaDrm) → MediaCodec(Renderer) → Surface/AudioTrack。
九、常见坑与排查
-
黑屏/花屏/播放失败
- 密钥/加密模式与解码链不匹配(cenc vs cbcs)、许可证 URL/证书错误、时区/时钟偏差。
-
Widevine 等级不达标
- L3 设备尝试播放 L1 限制内容 → 降清晰度或失败;需做设备能力检测与自适应策略。
-
离线许可证
- 忘记持久化/续租;切换账户/设备清理后失效。
-
输出保护
- 外接显示器无 HDCP 导致拒播;UI 需给出清晰提示。
-
联调/测试困难
-
先用 ClearKey 跑通链路再切换正式 DRM;前后端日志对齐(请求体、响应体、KeyId)。
-
十、最佳实践(简表)
- 跨端一致:CMAF 一套打包 + HLS/DASH 双清单 + 多 DRM(WV/PR/FP)。
- Android:优先 ExoPlayer/Media3 + MediaDrm;DRM 错误分类上报,埋点覆盖失败类型/设备安全级别。
- 体验:按设备能力分发(L1/L3)、弱网保播放(多码率 + 保守 ABR)、低延迟需端云协同(LL-HLS/LL-DASH)。
- 安全:Secure Surface/FLAG_SECURE/HDCP;结合水印应对“屏摄”。
- 运维:License 服务高可用,Key Rotation,缓存策略(片段可缓存;密钥不缓存或有策略限制)。
一句话总结:
DRM 是把“加密内容 + 许可证服务 + 受保护的端侧解密/输出”串起来的完整体系。它不改变编解码本身,而是在解码前加了一道“门卫”。做好打包与端侧适配、处理好策略与错误,既能守住版权,又能保证播放体验。