MF99 coding 💻

keep learning; keep coding;

使用 Widevine DRM

f:id:mouseface99:20191129171906p:plain

隨著 Android 越來越普及, DRM 的需求也越來越大。 所以 Google 原生支援的 Widevine DRM 的使用率也越來越高。 這邊就稍微記錄一下如果要播放 Widevine 影片的話,要怎麼取得 Widevine DRMaccess right 以及如何播放。

基本上播放的流程分為兩個部分

  • 利用 VideoView 或任何 SurfaceView 播放串流或是影片檔
  • 透過 DrmManagerClient 向 DRM server 取得 Right

特別注意的是,這兩個流程分別是 獨立進行 的,雖然說播放的時候還是會有先後關係(需要先取得 Right 然後才能 decode),但是在執行上是可以分開進行的。(比方說你還在取得串流URL或是準備 Player 相關的元件時,就可以先在背景先去取得 DRM right)

第一個部分利用 VideoView 播放串流/影片檔

這部份跟一般的 MediaPlayer 流程是一模一樣的。

mVideoView = (VideoView) findViewById(R.id.myplaysurface);

Uri uri = Uri.parse(videoPath);
mVideoView.setVideoURI(uri);
mController = new MediaController(this, false);
mVideoView.setMediaController(mController);
mVideoView.requestFocus();
mVideoView.start();

第二部分則是透過 Android 內建的 DrmManagerClient 取得影片的 Right

首先要先建立 DrmManagerClient 的實體

DrmManagerClient mDrmManagerClient = new DrmManagerClient(context);
mDrmManagerClient.setOnEventListener(mEventListener);
mDrmManagerClient.setOnErrorListener(mErrorListener);
mDrmManagerClient.setOnInfoListener(mInfoListener);

接著註冊並檢查目前的機器是否支援 Widevine

DrmInfoRequest drmInfoRequest = new DrmInfoRequest(DrmInfoRequest.TYPE_REGISTRATION_INFO, "video/wvm");
drmInfoRequest.put("WVPortalKey", mPortalKey);

DrmInfo drmInfo = mDrmManagerClient.acquireDrmInfo(drmInfoRequest);

int drmInfoRequestStatusKey = Integer.parseInt((String)info.get("WVDrmInfoRequestStatusKey"));
switch(drmInfoRequestStatusKey){
    case 0:
        // Device has Hardware Widevine Key (L1)
    case 1:
        // Device has no Widevine Key
    case 2:
        // Device has Software Widevine Key (L3)
}

其中第二行 drmInfoRequest.put("WVPortalKey", mPortalKey) 這部份後面再一起解釋。 透過 acquireDrmInfo 取得的 drmInfoRequestStatusKey 會有3種狀態(0/1/2),可以透過這個值得知目前機器是否有支援 Widevine 以及是什麼等級。

再來如果確認可以播放後,就可以再次透過 DrmManagerClient 來取得 Right

DrmInfoRequest drmRightRequest = new DrmInfoRequest(DrmInfoRequest.TYPE_RIGHTS_ACQUISITION_INFO, "video/wvm");
drmRightRequest.put("WVDRMServerKey", drmServerUri);
drmRightRequest.put("WVAssetURIKey", assetUri);
drmRightRequest.put("WVDeviceIDKey", deviceId);
drmRightRequest.put("WVPortalKey", portalId);
drmRightRequest.put("WVCAUserDataKey", userData);

int result = mDrmManagerClient.acquireRights(drmRightRequest);
if(result == 0)
    // Success
else
    // Failure

如果回傳的 result 是 0 (DrmManagerClient.ERROR_NONE)的話就表示成功取得 Right 了。 接下來 VideoView 在播放影片時,系統就會自動透過這個 Right 去做解密的動作。

最後解釋一下在建立 DrmInfoRequest 時要放入的參數。 基本上這些參數是發送給 DRM Server 看的,所以實際上要放什麼東西是要看 DRM Server 的實作方式。 但是 Widevine 常見的參數如下 註冊時會用到

drmInfoRequest.put("WVPortalKey", mPortalKey)

在取得 Right 的時候會用到

drmRightRequest.put("WVDRMServerKey", drmServerUri);
drmRightRequest.put("WVAssetURIKey", assetUri);
drmRightRequest.put("WVDeviceIDKey", deviceId);
drmRightRequest.put("WVPortalKey", portalId);
drmRightRequest.put("WVCAUserDataKey", userData);

至於裡面的 Value 要塞什麼值,就要看個別 DRM server 的設定了,另外有些 DRM server 可能也會要求在認證或是取得 Right 的時候需要額外的資訊,也會是在這個地方把 Key/Value 放入。

Reference