Edited at

mp4をFFmpegでhlsに変換し、ストリーミング再生

Webページに動画を埋め込む際、Youtubeなどを使わず、ストリーミング再生を実装したい場合に色々調べて実装することができたので、メモします。

(間違っているところがあるかもしれません。ご指摘いただけましたら幸いです)


こんな方向け


  • 動画の形式のことはよくわからない

  • とりあえずストリーミングを実装したい

  • mp4ファイルだけはある

  • Youtubeなどは利用しない(自サーバーに動画をUPする)


動画変換の話


ストリーミング再生対応形式について


  • MPEG-dash


    • 主にwindows系が対応している



  • hls


    • 主にapple系が対応している



の2種類が主流の模様ようで、ブラウザではなく、OSレベルの話で対応が変わるので注意。

参考


2つの形式に変換するのは面倒

それぞれのデバイス用に動画ファイルの作成とjsでの振り分けをすると面倒なので、何か便利なものはないのかと検索すると、hls.jsというものがヒットします。

hls.js

hls非対応のブラウザを対応させるJSライブラリで、対応しているブラウザは、そのままhlsを利用する。

if(Hls.isSupported()) {

var video = document.getElementById('video');
var hls = new Hls();
hls.loadSource('https://video-dev.github.io/streams/x36xhzz/x36xhzz.m3u8');
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED,function() {
video.play();
});
}
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = 'https://video-dev.github.io/streams/x36xhzz/x36xhzz.m3u8';
video.addEventListener('canplay',function() {
video.play();
});
}


mp4ファイルをffmpegを使ってhls形式に変換

素のmp4ではできないため、FFmpegというソフトを使い、hls形式(m3u8ファイルとtsファイル)に変換します。

ffmpegのインストールはこちら

諸々試したところ、以下を参考にコマンドを入れるとうまく動作する模様。

https://engineer-world.duckdns.org/2018/03/07/post-1423/

セグメント(tsファイル)の長さは10秒が推奨とのことです。

https://developer.apple.com/jp/documentation/NetworkingInternet/Conceptual/StreamingMediaGuide/FrequentlyAskedQuestions/FrequentlyAskedQuestions.html

コマンドは以下の通りです。

ffmpeg -i [input file path] .mp4 -codec copy -map 0 -f segment -vbsf h264_mp4toannexb -segment_format mpegts -segment_time 10 -segment_list  [output file path] .m3u8 [output file name] -%03d.ts

実際入力する際は、以下のような感じです。

ffmpeg -i video\video.mp4 -codec copy -map 0 -f segment -vbsf h264_mp4toannexb -segment_format mpegts -segment_time 10 -segment_list video\video.m3u8 video\video-%03d.ts

以下のようなファイルが出力されれば成功です。

video

├video.m3u8
├video-000.ts
├video-001.ts
├video-002.ts
├video-003.ts
├video-004.ts
├video-005.ts
├video.mp4(最初から入っているファイルです。)


実装

諸々イベントがあると便利なので、デフォルトのvideoは利用せずplyr.jsを利用する。

plyr.js


実装コード

コード全体は以下のような感じです。

<!DOCTYPE html>

<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/plyr/3.4.3/plyr.css" />
<style>
.video-content {
width: 1000px;
margin: 20px auto;
}
.video-content video {
width: 100%;
}
</style>
</head>
<body>
<div class="video-content">
<video id="player" playsinline="playsinline" poster="./images/poster.jpg"></video>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/hls.js/0.10.1/hls.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/plyr/3.4.3/plyr.min.js"></script>
<script>
const video = document.querySelector('#player');
const videoSrc = './video/video.m3u8';
const hlsCheck = Hls.isSupported();
const player = new Plyr(video);
if (hlsCheck) {
var hls = new Hls();
hls.loadSource(videoSrc);
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED, function () { });
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = videoSrc;
video.addEventListener('loadedmetadata', function () { });
}
</script>
</body>
</html>


まとめ


  • youtubeやvimeoなど、利用しなくともストリーミング配信は可能。

  • ffmpegのコマンドは難しい。

  • hls.jsの存在はありがたい。

  • plyr.jsはイベント取得が容易。


参考サイト

以下サイトを参考にさせていただきました。