[MPEG-DASH] Bento4でDRMパッケージを行う

# はじめに
Bento4を使って、アダプティブストリーミングのメディアファイルを作成するまでを紹介します。

# Bento4
- 実行形式: コマンドライン
- 対応OS: Windows, macOS, Linux
- ライセンス: GPL
- https://www.bento4.com/

Bento4は、MP4の結合やMPEG-DASH/HLSの作成が行えるフリーソフトウェアです。

```xml:動作環境
Bento4: 1.5.1.629
```

# DRMなし
## Profile:Live
入力はMP4ファイルです。`mp4fragment`で[Fragmented MP4]()を生成します。`--fragment-duration 2000 --timescale 1000`を指定すると2秒間隔のフラグメントが生成されます。
`mp4dash`でMPEG-DASHのセグメントファイルとマニフェストファイルを作成します。`--profiles=live`を指定するとライブ配信向けになります。

```bash:Profile-Live
mp4fragment --fragment-duration 2000 --timescale 1000 Bullfinch.mp4 Bullfinch.frag.mp4
mp4dash --profiles=live --use-segment-template-number-padding --use-segment-timeline --mpd-name=Bullfinch.mpd --o out Bullfinch.frag.mp4
```

## Profile:On-Demand
`--profiles=on-demand`を指定するとオンデマンド配信向けになります。

```bash:Profile-On-Demand
mp4fragment --fragment-duration 2000 --timescale 1000 Bullfinch.mp4 Bullfinch.frag.mp4
mp4dash --profiles=on-demand --mpd-name=Bullfinch.mpd --o out Bullfinch.frag.mp4
```

## マルチビットレート
マルチビットレートのセグメントファイルを作成するためには、入力のMP4を映像の解像度毎に分ける必要があります。[FFmpeg](https://www.ffmpeg.org/)というソフトウェアを使用して、映像と音声の分割、解像度のエンコードを行います。

```bash:Multi-Bitrate
ffmpeg -i Bullfinch.mp4 -c:v copy -an Bullfinch.video.mp4
ffmpeg -i Bullfinch.mp4 -c:a copy -vn Bullfinch.audio.mp4
ffmpeg -i Bullfinch.video.mp4 -c:v libx264 -filter_complex "scale=1920:1080" -b:v 4800k Bullfinch.video.1080p.mp4
ffmpeg -i Bullfinch.video.mp4 -c:v libx264 -filter_complex "scale=1280:720" -b:v 2400k Bullfinch.video.720p.mp4
ffmpeg -i Bullfinch.video.mp4 -c:v libx264 -filter_complex "scale=640:360" -b:v 800k Bullfinch.video.360p.mp4
mp4fragment --fragment-duration 2000 --timescale 1000 Bullfinch.1080p.video.mp4 Bullfinch.video.1080p.frag.mp4
mp4fragment --fragment-duration 2000 --timescale 1000 Bullfinch.720p.video.mp4 Bullfinch.video.720p.frag.mp4
mp4fragment --fragment-duration 2000 --timescale 1000 Bullfinch.360p.video.mp4 Bullfinch.video.360p.frag.mp4
mp4fragment --fragment-duration 2000 --timescale 1000 Bullfinch.audio.mp4 Bullfinch.audio.frag.mp4
mp4dash --profiles=live --use-segment-template-number-padding --use-segment-timeline --mpd-name=Bullfinch.mpd --o out Bullfinch.video.1080p.frag.mp4 Bullfinch.video.720p.frag.mp4 Bullfinch.video.360p.frag.mp4 Bullfinch.audio.frag.mp4
```

# DRMあり

DRMパッケージを行う際に、KeyIDとKeyを指定する必要があります。`md5sum`で16進数の32桁のハッシュ文字列を生成できますので、これをKeyIDとKeyとします。

```bash:ハッシュ文字列
date | md5sum
```

## ClearKey
ClearKeyでは、`mp4dash`に`--encryption-key=【KeyID】:【Key】`でKeyIDとKeyを指定します。`--encryption-args="--global-option mpeg-cenc.eme-pssh:true"`を付与します。

```bash
mp4dash --profiles=live --use-segment-template-number-padding --use-segment-timeline --encryption-key=38261f9e22d691854040d5c3c1aa9479:8df51ed781a87c9870d52c34c9d7b679 --encryption-args="--global-option mpeg-cenc.eme-pssh:true" --mpd-name=Bullfinch.mpd --o out Bullfinch.video.1080p.frag.mp4 Bullfinch.video.720p.frag.mp4 Bullfinch.video.360p.frag.mp4 Bullfinch.audio.frag.mp4
```

## Widevine
Widevineでは、WEB APIをリクエストしてテスト用のライセンスサーバーのキーを取得する必要があります。下記はそのリクエストのPythonスクリプトになります。

```python:テスト用のライセンスサーバーのキー取得
import base64
import json
import requests
import textwrap

print("create key [start]")

signature = "kwVLL4xVh9mnlZlPqiEWN0E+FsvG0y+/oy451XXeIMo="
contentId = "fkj3ljaSdfalkr3j"

contentIdB64 = base64.b64encode(contentId.encode('utf-8'))
reqObjStr = textwrap.dedent('''{{
  "content_id": "{contentId}",
  "tracks": [
    {{ "type": "SD" }},
    {{ "type": "HD" }},
    {{ "type": "AUDIO" }}
  ],
  "drm_types": [ "WIDEVINE" ],
  "policy": ""
}}
''').format(contentId=contentIdB64.decode("ascii"))

reqObjB64 = base64.b64encode(reqObjStr.encode('utf-8'))
reqBodyObjStr = textwrap.dedent('''{{
  "request": "{request}",
  "signature": "{signature}",
  "signer": "widevine_test" 
}}
''').format(request=reqObjB64.decode("ascii"), signature=signature)

url = "http://license.uat.widevine.com/cenc/getcontentkey/widevine_test"
headers = {"content-type": "application/json"}
res = requests.post(url, data=reqBodyObjStr, headers=headers)

resObj = json.loads(res.text)
resResStr = base64.b64decode(resObj["response"])
print(resResStr)
resResObj = json.loads(resResStr)
keyId = base64.b64decode(resResObj["tracks"][0]["key_id"]).encode('hex')
key = base64.b64decode(resResObj["tracks"][0]["key"]).encode('hex')

print("keyId = " + keyId)
print("key   = " + key)
```

`mp4dash`に`widevine-header=provider:widevine_test#content_id:【Key】#kid:【KeyID】`を指定します。

```bash
mp4dash --profiles=live --use-segment-template-number-padding --use-segment-timeline --encryption-key=0294b9599d755de2bbf0fdca3fa5eab7:3bda2f40344c7def614227b9c0f03e26  --widevine-header=provider:widevine_test#content_id:666b6a336c6a61536466616c6b72336a#kid:0294b9599d755de2bbf0fdca3fa5eab7 --mpd-name=Bullfinch.mpd --o out Bullfinch.video.1080p.frag.mp4 Bullfinch.video.720p.frag.mp4 Bullfinch.video.360p.frag.mp4 Bullfinch.audio.frag.mp4
```

## PlayReady 
PlayReadyでは、`mp4dash`に`--playready`を指定します。

```bash
mp4dash --profiles=live --use-segment-template-number-padding --use-segment-timeline --encryption-key=38261f9e22d691854040d5c3c1aa9479:8df51ed781a87c9870d52c34c9d7b679 --playready --mpd-name=Bullfinch.mpd --o out Bullfinch.video.1080p.frag.mp4 Bullfinch.video.720p.frag.mp4 Bullfinch.video.360p.frag.mp4 Bullfinch.audio.frag.mp4
```

PlayReadyでは、[テスト用のライセンスサーバー](http://testweb.playready.microsoft.com/)では、キーをBase64文字列を使用します。下記のコマンドを実行すると生成できます。

```bash:Base64
echo 【ハッシュ文字列】 | xxd -r -p | base64
```

- 参考:Playreadyテスト用ライセンスURL仕様
- https://testweb.playready.microsoft.com/Server/ServiceQueryStringSyntax

## マルチDRM(Widevine+PlayReady) 

```bash
mp4dash --profiles=live --use-segment-template-number-padding --use-segment-timeline --encryption-key=0294b9599d755de2bbf0fdca3fa5eab7:3bda2f40344c7def614227b9c0f03e26  --widevine-header=provider:widevine_test#content_id:666b6a336c6a61536466616c6b72336a#kid:0294b9599d755de2bbf0fdca3fa5eab7 --widevine --playready --mpd-name=Bullfinch.mpd --o out Bullfinch.video.1080p.frag.mp4 Bullfinch.video.720p.frag.mp4 Bullfinch.video.360p.frag.mp4 Bullfinch.audio.frag.mp4
```

# おわりに
今回、DRMパッケージについて纏めました。
メディアファイルの再生方法は別の投稿で紹介していますので
是非ご覧ください。ありがとうございました。

# 関連リンク
- [[MPEG-DASH] 初心者のためのWEBストリーミング入門](https://qiita.com/yun_bow/items/a97ad78615c6ca3a75bb)
- [[MPEG-DASH] Fragmented MP4のファイル構造](https://qiita.com/yun_bow/items/a33266b78d5aab807c71)
- [[MPEG-DASH] MPDのファイル構造](https://qiita.com/yun_bow/items/780e49531174272e7c44)
- [[MPEG-DASH] DRMシステムの概要と種類](https://qiita.com/yun_bow/items/e573f4754579d1627a13)
- [MPEG-DASH] Bento4でDRMパッケージを行う（本稿）
- [[MPEG-DASH] dashJSでアダプティブストリーミングを再生する](https://qiita.com/yun_bow/items/88582964c113c8499742)
- [[MPEG-DASH] videoJSでアダプティブストリーミングを再生する](https://qiita.com/yun_bow/items/3cdcb0a4f961d6e1e06d)
- [[MPEG-DASH] パフォーマンスチューニングを行う](https://qiita.com/yun_bow/items/e4e37265643a661021ec)

# 参考リンク
- [MPEG-DASHストリームのClearkey復号](https://qiita.com/khagi/items/bfe910e4b09110977049)

以上です。