Android视频开发进阶(part6-安卓的DRM,视频版权保护)

之前因为种种原因好久没有更新视频开发的文章了。今天刚刚从国内飞回来,趁着周末更新一下.不过关于DRM这块首先一般的开发者很少用到,而且DRM的开发需要前后台的密切合作,可以说后台的工作占了一大半,安卓前端这块DRM的API封装其实已经很到位了,只是因为接触的人少,所以文档并没有多么而已。所以这篇文章只是给大家过一遍概念,细节我就少讲一些。有具体的问题可以留言,

今天主要开始讲解一下安卓视频开发的DRM这个问题,DRM是英文Digital rights management的缩写,可以理解为版权保护。众所周知,视频或者音频的盗版问题是困扰发行商的一个大麻烦,因为盗版的横行会直接导致发行商利润的减少。那么像在PC端或者移动端的在线/离线多媒体内容的播放上,发行商又能怎么解决呢?

比如最近优酷很火的《白夜追凶》这种电视剧,

附上我超级喜欢的潘老师。。。

vip的会员可以享受离线观看。假如说这种类型的文件没有进行版权保护,或者说加密,那么会员机制就会轻易作废.(我可以申请一个会员,然后把文件从SD卡中复制粘贴并且发送到网上)

所以一般来说,对这种premiere content(因为我们公司也是做电视剧,老板都这么叫,中文翻译应该可以说是付费内容???),都需要对当前文件,例如MP4文件的audio或者video track部分的内容进行加密,但是metadata部分不加密。只有在用户登录之后,进行身份验证了才传一个密钥用来对该视频进行解密。

那么问题来了

在安卓平台上的视频怎么做DRM的解析?

在回答这个问题之前我们先了解一下当前移动端的DRM的一些概念。


1.DRM platform

DRM 平台可以理解为DRM服务的提供商,它提供了一整套DRM的服务方案,从前端到后端,这里大家可以把这种服务理解为一套带引号的SDK,不同的提供商在服务器端和客户端会要求不同的数据传输格式。因平台而异,安卓的设备普遍拥有Widevine这个服务(在framework层),是近几年才被google收购的。

从上图可以看出,现有的成熟的DRM平台并不多,安卓端的话一般使用的是第一个。


2.DRM 是怎么工作的?

简单点来讲,DRM的后台,即服务器端的工作其实和大部分视频内容分发处理后台没有太大的区别,唯一的不同就是它需要对视频数据部分进行适当的加密(在这里我们不讨论加密算法)。

而客户端呢就需要相应的获得解密的秘钥对视频内容解密,值得注意的是DRM里面秘钥一般被称license而不是key。整个过程可以用以下的流程图来解释。


3.一般的DRM平台提供商的任务

我们这一部分来详细的了解一下DRM的平台提供商的任务(当然平台提供商并不是必需的,如果企业自己有能力做一整套解决方案那也ok,不过这整篇文章你也不用看了😁)。

Widevine的后台为例,widevine自从被google收购之后就将其后台发展为类似云平台的PASS服务了,企业的后台可以购买Widevine的服务,服务提供加密的API组还有数据库容量,用来保存企业视频的license,即解密秘钥。至于身份验证啊等等功能就留给企业后台自己完成。以下示意图可以大概解释一下Widevine的DRM流程

在第四步之后的流程里面,企业后台会根据播放器的请求去返回一个向Widevine数据库请求license 的URL,播放器在获得视频URL和license URL之后就可以开始播放了。

这是最naive的实现。原因是现在的视频服务出现了很多中间商。。。。 :cat:

因为中间涉及很多步骤,所以很多小型的企业决定不要自己去和google的Widevine服务器打交道,而是交给一些视频服务的中间商去做这个事情,然后和这些中间商做身份验证,这样免去了很多麻烦,api相对简单,弊端当然就是要多付钱了。。。

不过无论怎么样,安卓平台上播放DRM视频的宗旨就是获取视频url加上解密用的license。就是这么简单


4.Android的DRM实例代码

说了这么多,终于到安卓的重点了,代码怎么写?????

安卓端的DRM比较蛋疼,因为对于使用MediaCodec API组的和使用原生的MediaPlayer API的开发者来说,两者的代码完全不相同。因为DRM开发者比较少,谷歌的官方文档也不完整,而且很难被理解,我也是研究了很久文档才整明白。

先说MediaCodec API的DRM:

4.1 MediaCodec API组的DRM处理

在这个官方文档里面已经讲的很详细了,如果使用MediaCodec进行decode的时候,configure()方法需要传进一个MediaCrypto

首先我们需要创建一个MediaDrm对象并且调用其openSession方法,该方法会返回一个sessionID,标识该次解码工作。

第二步我们需要创建一个MediaCrypto对象给MediaCodec 对象。 它需要一个UUID和initdata,UUID是Widevine的Scheme ID,在Exoplayer的源码中可以看到,在C.java里面。而initData就是上面说到的sessionID.

public static final UUID WIDEVINE_UUID = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL);

最后我们还需要对license server做license的call,得到的reponse就是我们需要的license了,此时只需要调用MediaDrm的provideKeyResponse()方法,视频就可以自动开始播放了。

所以其实总结一下,MediaCodec负责解码,它需要一个MediaCrypto对象,同时需要一个MediaDrm对象,前者获取后者的sessionId让framework去寻找对应的license,后者负责保存从服务器下载下来的license并且提供一个唯一的sessionId给前者。附上伪代码


public static final UUID WIDEVINE_UUID = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL);
//获取sessionId
MediaDrm mediaDrm = new MediaDrm();
String sessionId = mediaDrm.openSession();
//创建MediaCrypto
/**
sessionId 是串联 MediaDrm和MediaCrypto的关键
**/
MediaCrypto ctypto = new MediaCrypto(WIDEVINE_UUID, sessionId)
//用cypto对象来进行解密
MediaCodec codec = new MediaCodec("xxxx")
codec.configure(..,...,ctypto)
/**
注意的是license并不需要在configure之前获取,可以稍后再进行
**/

//网络连接
byte[] license = HttpUrlConnection.connect().......
mediaDrm.provideKeyResponse(xxx,license);

/**
所有工作结束,视频可以正常播放了。
**/


MediaCodec的drm处理文档比较齐全,所以问题不大,具体源码还是又不懂的可以参考ExoPlayer的代码,
StreamingDrmSessionManager.java里面整个流程都有。


4.2 MediaPlayer API组的DRM处理

最后一个难点来了,就是原生的播放器MediaPlayer的DRM处理,这部分着实让我苦恼了很久,因为网上资料很少文档极其不齐全。如果你直接谷歌搜索MediaPlayer DRM,是没有任何结果的。。。你也不会知道MediaCodec和MediaPlayer处理DRM有任何不同。

不过功夫不负有心人,费劲千辛万苦之后我终于找到了一丢丢线索。先看官方文档。

https://developer.android.com/reference/android/drm/package-summary.html

重点在这个地方:

这么重要的事情。。。。谷歌就这么轻描淡写的在这个文档里面随便一提。

也就是说,其实MediaPlayer播放视频的时候,是不需要传任何类似MediaCrypto之类的对象的,直接用DrmManagerClient进行相关操作,framework层会自动处理解密工作了。

下面附上伪代码:

  public static final String WV_DRM_SERVER_KEY = "WVDRMServerKey";
    public static final String WV_ASSET_URI_KEY = "WVAssetURIKey";
    public static final String WV_DEVICE_ID_KEY = "WVDeviceIDKey";
    public static final String WV_PORTAL_KEY = "WVPortalKey";


/**
调用该方法进行解密,执行成功就ok了
**/

  public  void acquireKey(){
        DrmInfoRequest drmInfoRequest = createDrmInfoRequest(assetUrl, infoHolder.getDrmLisenceUrl());
        DrmInfo drmInfo = mDrmManager.acquireDrmInfo(drmInfoRequest);
        int rights = mDrmManager.acquireRights(drmInfoRequest);
    }
    
  
  
  /**
  licenseServerUri 就是 对license server进行http通信的Url
  **/
  
   private DrmInfoRequest createDrmInfoRequest(String assetUri, String licenseServerUri) {
        DrmInfoRequest rightsAcquisitionInfo;
        rightsAcquisitionInfo = new DrmInfoRequest(DrmInfoRequest.TYPE_RIGHTS_ACQUISITION_INFO,
                WIDEVINE_MIME_TYPE);

        if (licenseServerUri != null) {
            rightsAcquisitionInfo.put(WV_DRM_SERVER_KEY, licenseServerUri);
        }
        rightsAcquisitionInfo.put(WV_ASSET_URI_KEY, assetUri);
        rightsAcquisitionInfo.put(WV_DEVICE_ID_KEY, mDeviceId);
        rightsAcquisitionInfo.put(WV_PORTAL_KEY, PORTAL_NAME);

        return rightsAcquisitionInfo;
    }


所以说MediaPlayer的DRM处理更加简单暴力。。。。当然DrmManagerClient还有其他的一些操作,比如说callback的注册等等。。。

这期的文章就到这,因为Drm涉及到很多细节的处理,还有和后台沟通的问题,这里我只是大概介绍一下Drm的概念和不同类型的api的用法,就不详细展开我工作中具体遇到的麻烦了,有问题可以直接留言或者私信~

刚刚从国内回新就感冒了,这几天昏昏沉沉的。。。。要再点睡觉好好休息了。

参考文档

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,398评论 25 707
  • 上两期我们已经学习了关于视频播放的基础知识,还有容器格式文件的结构。那么今天终于可以开始学习安卓平台的视频播放知识...
    qing的世界阅读 9,202评论 29 55
  • 越来越熟悉的环境,越来越熟的同事,随之而来的懈怠,我不知所措了。像马老师说的,缺少激情。
    忆江南1991阅读 239评论 0 0
  • 我之前说过,校长是我叔叔,从小到大也是比较喜欢我的。然后也不知道为什么让我带了人人畏惧的一年级。 一开始我们班是有...
    Pakaki阅读 159评论 0 0
  • 文/左心 我看到空气的一端 流淌的视线 我的喘息淹没于月光 树林中小草左右着风向 解说春的朦...
    5b8fd3f74fc5阅读 408评论 0 2