mp4をエンコードしてMPEG-DASHにして再生する

(2016-10-30)

MPEG-DASHとは

HTTPで動画をストリーミングするための規格。似たようなのにAppleの独自規格であるHLSなどがある。

サーバーはMPD(Media Presentation Description)ファイルと、セグメントに分けられた動画や音声ファイルを持っていて、 クライアントはMPDファイルをリクエストし、この内容をもとにセグメントをリクエストしていく。

準備

ffmpegMP4Boxを使うので、これらを実行できるようにする。 Docker上で実行することもできて、その場合は以下のようにエイリアスを付けると便利。

$ alias ffmpeg='docker run --rm -v `pwd`:/tmp/workdir jrottenberg/ffmpeg'
$ alias MP4Box='docker run --rm -v `pwd`:/work sambaiz/mp4box'

エンコード

$ffmpeg -i input.mp4 -vcodec libx264 -vb 448k -r 30 -x264opts no-scenecut -g 15 -acodec libfaac -ac 2 -ab 128k -frag_duration 5000000 -movflags empty_moov output.mp4

オプションの意味は多分こんな感じ。

  • -vcodec libx264: 動画をH.264にエンコードする
  • -vb 448k: 動画のビットレート(bps)
  • -r 30: 動画のフレームレート(fps)
  • -x264opts no-scenecut: キーフレームの間隔を動画の内容によらず固定にする
  • -g 15: キープレームの間隔。フレームレート(-r) * フラグメントの時間(-frag_duration) / キーフレームの間隔(-g)が整数になるようにする。
  • -acodec libfaac: 音声をAACにエンコードする
  • -ac 2: 音声チャンネル数2(ステレオ)
  • -ab 128k: 音声のビットレート(bps)
  • -frag_duration 5000000: フラグメント(セグメント)の時間(μs)。
  • -movflags empty_moov: 頭にmdat atom(データが含まれる)なしで、moov atom(メタ情報が含まれている)を書き始めるらしい。これがにしないとMP4Boxに入れるときに失敗した。
$ MP4Box -info -v input.mp4
...
[iso file] Current top box start before parsing 0
[iso file] Read Box type ftyp size 24 start 0
[iso file] Current top box start before parsing 24
[iso file] Read Box type free size 8 start 24
[iso file] Current top box start before parsing 32
[iso file] Read Box type mdat size 5216803 start 32 <--
[iso file] Current top box start before parsing 5216835
[iso file] Read Box type moov size 13332 start 5216835 <--
...
$ MP4Box -info -v output.mp4
[iso file] Current top box start before parsing 0
[iso file] Read Box type ftyp size 36 start 0
[iso file] Current top box start before parsing 36
[iso file] Read Box type moov size 1186 start 36 <--

MPEG-DASHにする

$ MP4Box -dash 5000 output.mp4
$ ls
input.mp4 output.mp4 output_dash.mpd output_dashinit.mp4

-dashはセグメントの時間。ただ、このmpdだと

Multiplexed representations are intentionally not supported, as they are not compliant with the DASH-AVC/264 guidelines

と出てしまい再生できない。中を見てみると、

<Representation id="1" mimeType="video/mp4" codecs="avc1.64000d,mp4a.40.2" width="320" height="240" frameRate="30" sar="1:1" audioSamplingRate="44100" startWithSAP="1" bandwidth="564201">

となっていて、動画と音声が一つのRepresentationになっているのがまずそうだったので、動画と音声を分けて実行した。

$ MP4Box -dash 5000 output.mp4#video output.mp4#audio

結果、できたmpdがこんな感じ。

<?xml version="1.0"?>
<!-- MPD file Generated with GPAC version 0.6.1-rev14-g8eb0297-master  at 2016-10-30T14:47:02.962Z-->
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" minBufferTime="PT1.500S" type="static" mediaPresentationDuration="PT0H0M21.545S" maxSegmentDuration="PT0H0M10.000S" profiles="urn:mpeg:dash:profile:full:2011">
 <ProgramInformation moreInformationURL="http://gpac.sourceforge.net">
  <Title>output_dash.mpd generated by GPAC</Title>
 </ProgramInformation>

 <Period duration="PT0H0M21.545S">
  <AdaptationSet segmentAlignment="true" maxWidth="320" maxHeight="240" maxFrameRate="30" par="4:3" lang="eng">
   <Representation id="1" mimeType="video/mp4" codecs="avc3.64000d" width="320" height="240" frameRate="30" sar="1:1" startWithSAP="1" bandwidth="437781">
    <BaseURL>output_track1_dashinit.mp4</BaseURL>
    <SegmentList timescale="15360" duration="153600">
     <Initialization range="0-1128"/>
      <SegmentURL mediaRange="1129-556172" indexRange="1129-1172"/>
      <SegmentURL mediaRange="556173-1134265" indexRange="556173-556216"/>
      <SegmentURL mediaRange="1134266-1172888" indexRange="1134266-1134309"/>
    </SegmentList>
   </Representation>
  </AdaptationSet>
  <AdaptationSet segmentAlignment="true" lang="eng">
   <Representation id="2" mimeType="audio/mp4" codecs="mp4a.40.2" audioSamplingRate="44100" startWithSAP="1" bandwidth="129622">
    <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
    <BaseURL>output_track2_dashinit.mp4</BaseURL>
    <SegmentList timescale="44100" duration="441000">
     <Initialization range="0-1060"/>
      <SegmentURL mediaRange="1061-163674" indexRange="1061-1104"/>
      <SegmentURL mediaRange="163675-326023" indexRange="163675-163718"/>
      <SegmentURL mediaRange="326024-349091" indexRange="326024-326067"/>
    </SegmentList>
   </Representation>
  </AdaptationSet>
 </Period>
</MPD>

再生する

dash.jsを使う。

<html>
  <head>
     <script src="http://cdn.dashjs.org/latest/dash.all.min.js"></script>
     <style>
         video {
             width: 640px;
             height: 360px;
          }
     </style>
  </head>
  <body>
     <div>
         <video data-dashjs-player autoplay src="http://localhost:8080/output_dash.mpd" controls></video>
     </div>
  </body>
</html>

ローカルでサーバーを立ち上げる。

var static = require('node-static');

var fileServer = new static.Server('./public');

require('http').createServer(function (request, response) {
    request.addListener('end', function () {
        fileServer.serve(request, response);
    }).resume();
}).listen(8080);

参考

次世代動画配信技術「MPEG-DASH」技術概要と標準化・関連技術動向

FFmpegでHTML5 readyな動画ファイルを作成 (MP4, WebM) - Qiita

profile?atom?mp4のよくわからないあれこれ(atom編)