mp4をエンコードしてMPEG-DASHにして再生する
videoMPEG-DASHとは
HTTPで動画をストリーミングするための規格。似たようなのにAppleの独自規格であるHLSなどがある。
サーバーはMPD(Media Presentation Description)ファイルと、セグメントに分けられた動画や音声ファイルを持っていて、 クライアントはMPDファイルをリクエストし、この内容をもとにセグメントをリクエストしていく。
準備
ffmpegと MP4Boxを使うので、これらを実行できるようにする。 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)。可変(VBR, Variable Bitrate)ではなく固定(CBR, Constant Bitrate)にする場合は-min/maxrate
を同じ値にする-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」技術概要と標準化・関連技術動向