無料でできる MPEG-DASH + Widevine ストリーミング テスト配信

# はじめに

こんにちは cloudpack 事業戦略本部 streampack チームの木村です。

動画配信においてあまり需要がないけど、要求されるところではしっかり要求されてしまうDRMについて、無料で**テスト配信（ココ重要）**を試すまでの手順をまとめてみたいと思います。


# 用意するもの

|||
|:--|:--|
|MPEG-DASH パッケージャー|shaka-packager|
|DRM パッケージャー|shaka-packager|
|メディア プレイヤー|shaka-player|
|パッケージャーを動かすマシン|Amazon EC2|
|配信サーバー|Amazon S3|
|コンテンツ|適当な MP4（H.264/AAC）|


配信方式は MPEG-DASH、DRM は Widevine で進めていきます。
パッケージングや配信はローカルでやっても良いのですが、cloudpack の人間なので、当然のごとく AWS 上に環境を構築していきます。

# shaka-packager のインストール

Google 謹製のパッケージャーです。 これを利用して MPEG-DASH 化と Widevine DRM 化を一気にやっちゃいます。
今回は Amazon EC2 （Amazon Linux） 上に展開していきます。

## インストール前の準備

curl, git, python, gcc-c++ が必要ですが、curl と python は予め Amazon Linux にインストールされているので、git と gcc-c++ をインストールします。

### git, gcc-c++ インストール

```

$ sudo yum install git gcc-c++
```

### depot_tools のインストール

Chromium から depot_tools リポジトリをクローンします。

```
$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
```

取得したらPATHを通しておきます。 .bashrc 等に以下を環境に合わせて追記します。

```
export PATH="$PATH:/path/to/depot_tools"
```

### shaka-packager の取得

shaka_packager ディレクトリーを作成します。

```
$ mkdir shaka_packager && cd shaka_packager
```

depot_tools の glient を使ってコードと依存性をチェックします。


```
$ gclient config https://www.github.com/google/shaka-packager.git --name=src --unmanaged
```
sync を実行して暫くほーちします。（数分間）

```
$ gclient sync
```

完了したら src ディレクトリーに移動して、depot_tools の ninja を使ってコードをビルドします。


```
$ cd src
$ ninja -C out/Release
```

終了したら shaka-packager インストール完了です。

packager は以下に作成されるので PATH を通しておいても良いでしょう。

```
shaka_packager/src/out/Release/packager
```

# MPEG-DASH & Widevine パッケージング

Google さんの方でテスト用のライセンスサーバー、キー、IV を用意してくれてるのでそれを使います。

|||
|:--|:--|
| key_server_url: | https://license.uat.widevine.com/cenc/getcontentkey/widevine_test |
| signer: | widevine_test |
| aes_signing_key:|1ae8ccd0e7985cc0b6203a55855a1034afc252980e970ca90e5202689f947ab9 
| aes_signing_iv: | d58ce954203b7c9a9a9d467f59839249 |

あとは DASH 化するコンテンツを用意（ここでは sample.mp4） して、packager で以下のコマンドを実行します。

```
packager \
  in=sample.mp4,stream=audio,output=audio.mp4 \
  in=sample.mp4,stream=video,output=video.mp4 \
  --mpd_output sample.mpd \
  --enable_widevine_encryption \
  --key_server_url https://license.uat.widevine.com/cenc/getcontentkey/widevine_test \
  --content_id 7465737420636f6e74656e74206964 \
  --signer widevine_test \
  --aes_signing_key 1ae8ccd0e7985cc0b6203a55855a1034afc252980e970ca90e5202689f947ab9 \
  --aes_signing_iv d58ce954203b7c9a9a9d467f59839249
```

実行すると以下のファイルが生成されます。


- sample.mpd
- video.mp4
- audio.mp4

MP4Box で video.mp4 ファイル情報を見てみると、

```
# MP4Box -info video.mp4
* Movie Info *
	Timescale 15360 - Duration 00:00:00.000
	1 track(s)
	Fragmented File: yes - duration 00:10:34.633
64 fragments - 1 SegmentIndexes
	File suitable for progressive download (moov before mdat)
	File Brand isom - version 0
	Created: GMT Fri Jan  5 09:27:51 2018
	Modified: GMT Fri Jan  5 09:27:51 2018

Moov Meta type: "ID32" - 0 resource item(s)
File has no MPEG4 IOD/OD

Track # 1 Info - TrackID 1 - TimeScale 15360 - Media Duration 00:00:00.000
Media Info: Language "und (und)" - Type "vide:encv" - 0 samples
Fragmented track: 19039 samples - Media Duration 00:10:34.633
Visual Track layout: x=0 y=0 width=512 height=288
MPEG-4 Config: Visual Stream - ObjectTypeIndication 0x21
AVC/H264 Video - Visual Size 512 x 288
	AVC Info: 1 SPS - 1 PPS - Profile Baseline @ Level 2.1
	NAL Unit length bits: 32
	Pixel Aspect Ratio 1:1 - Indicated track size 512 x 288
Self-synchronized

*Encrypted stream - CENC scheme cenc (version 65536)
Initialization Vector size: 64 bits
```

`Encrypted stream - CENC scheme cenc (version 65536)`で暗号化されていることが確認できます。

また mpd の中身を見てみると `ContentProtection` Element が確認できます。


```xml:sample.mpd

<?xml version="1.0" encoding="UTF-8"?>
<!--Generated with https://github.com/google/shaka-packager version c88fe54553-release-->
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT634.633S">
  <Period id="0">
    <AdaptationSet id="0" contentType="video" width="512" height="288" frameRate="15360/512" subsegmentAlignment="true" par="16:9">
      <ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="abba271e-8bcf-552b-bd2e-86a434a9a5d9"/>
      <ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
        <cenc:pssh>AAAAoHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAIASEKu6Jx6Lz1UrvS6GpDSppdkSEG128lyxf14WuOrva79YLY4SEGR4YzefQVQQg3fnTG7A47gSEP3MPWFu3FzqmyVYWB2c048SEPPF4DYeZlSyj4BJx3iyOUYaDXdpZGV2aW5lX3Rlc3QiD3Rlc3QgY29udGVudCBpZEjj3JWbBg==</cenc:pssh>
      </ContentProtection>
      <Representation id="0" bandwidth="646006" codecs="avc1.42c015" mimeType="video/mp4" sar="1:1">
        <BaseURL>video.mp4</BaseURL>
        <SegmentBase indexRange="1192-1991" timescale="15360">
          <Initialization range="0-1191"/>
        </SegmentBase>
      </Representation>
    </AdaptationSet>
    <AdaptationSet id="1" contentType="audio" subsegmentAlignment="true">
      <ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="f3c5e036-1e66-54b2-8f80-49c778b23946"/>
      <ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
        <cenc:pssh>AAAAoHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAIASEKu6Jx6Lz1UrvS6GpDSppdkSEG128lyxf14WuOrva79YLY4SEGR4YzefQVQQg3fnTG7A47gSEP3MPWFu3FzqmyVYWB2c048SEPPF4DYeZlSyj4BJx3iyOUYaDXdpZGV2aW5lX3Rlc3QiD3Rlc3QgY29udGVudCBpZEjj3JWbBg==</cenc:pssh>
      </ContentProtection>
      <Representation id="1" bandwidth="100806" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="48000">
        <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
        <BaseURL>audio.mp4</BaseURL>
        <SegmentBase indexRange="1074-1873" timescale="48000">
          <Initialization range="0-1073"/>
        </SegmentBase>
      </Representation>
    </AdaptationSet>
  </Period>
</MPD>
```

そしてこれらのファイルを S3 のてきとーな場所に配置して公開します。

hogehoge バケットの shaka ディレクトリー配下にアップした例

```
$ aws s3 ls s3://hogehoge/shaka/
2018-01-05 09:31:42          0
2018-01-05 09:37:22    7990901 audio.mp4
2018-01-05 09:37:43       2499 sample.mpd
2018-01-05 09:37:33   51247089 video.mp4
```

# 再生確認

再生にはこれまた Google 謹製 Shaka Player を使います。
取り敢えず Web で公開されている誰でも使えるバージョンで。

https://shaka-player-demo.appspot.com



<img width="699" alt="スクリーンショット 2018-01-05 18.51.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/172426/49ec2394-77d8-9a66-09ed-34dcddc99307.png">

各項目には以下を入力します。

|Asset:|custom asset|
|:-----------------|:-----------------|
|Custom Manifest:| mpd の URL （例： https://s3-ap-northeast-1.amazonaws.com/hogehoge/shaka/sample.mpd）|
|Custom License Server:|https://widevine-proxy.appspot.com/proxy|
|Custom License certificate URL:|N/A|

Load を押すと再生が開始されます。

<img width="667" alt="スクリーンショット 2018-01-05 18.58.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/172426/1bef60dd-6da1-8f03-7888-bbadfe4b164a.png">

(c) copyright 2008, Blender Foundation / www.bigbuckbunny.org

# まとめ

商用利用では DRM サービスプロバイダーなどと契約するケースが多いかと思いますが、今回はサワリとして無料のツールのみで試してみました。

Shaka Packager　と Shaka Player を利用しましたが、他にも Bento4 や ExoPlayer などでも無料で遊ぶことができますよ。

尚、今回利用した Widevine のキーは Google 様がテスト用に用意しているものですので、実際に商用利用する場合にはお金かかりますのご注意を〜

# 参考

https://google.github.io/shaka-packager/html/index.html