flvビデオをオンデマンド再生 ビデオソースをダウンロードされないようにする
flvビデオでオンデマンド再生します。
flvビデオを簡単にオンデマンド再生する方法と、簡単にはビデオソースをダウンロードされない方法を検討したいと思います。
Flashの再生がだんだん難しくなっており、ChromeなどはFlash再生のためにそのサイトの許可を書かないといけない必要が出てきています。これは多くの方にビデオを見ていただきたいという時にかなり不利です。面倒くさい作業はしてくれません。
nginxにrtmp-moduleを利用してflvをrtmp化して映像配信していましたが、上記Flashのブラウザ上のセキュリティ対策にぶち当たるようになり、flvビデオを簡単にオンデマンド映像にし、後はそのビデオソースもダウンロードできないようにできないかと考え、下記の方法にあたりました。
まず、最近はHTML5のvideoタグで簡単にストリーミング再生できるようになっていますが、HTML5のvideoタグではflvファイルは再生できません。
プレーヤー flv.js
web配置するflv.jsプレーヤは、Flashなしで純粋なJavaScriptで書かれたHTML5 Flash Video(FLV)プレーヤーです。このプレーヤーは、FLVファイルストリームをMP4セグメントに変換し、mp4セグメントをHTML5要素に送る事によって動作します。
特徴
H.264 + AAC / MP3コーデック再生によるFLVコンテナ
マルチパート分割ビデオ再生
HTTP FLV低遅延ライブストリーム再生
FLV over WebSocketライブストリーム再生
Chrome、FireFox、Safari 10、IE11、Edgeと互換性があります
非常にオーバーヘッドが少なく、ハードウェアはブラウザで高速化されます!
https://github.com/Bilibili/flv.js/
ダウンロードします
git clone https://github.com/Bilibili/flv.js.git
cd flv.js
npm -i
npm run build
videojsプレーヤーとは関係ないのですが、フォルダを作るのが面倒なので、videojsフォルダの中にできた flv.min.jsファイルを突っ込みます。
flv.js/dist# cp flv.min.js /usr/local/nginx/html/ondemand/videojs/
プレーヤーのhtml
簡単なプレーヤーの配置を考えてみます。
VOD
if (flvjs.isSupported()) {
var videoElement = document.getElementById('videoElement');
var flvPlayer = flvjs.createPlayer({
type: 'flv',
url: 'http://cloudn.hanako.jp/movies/doga.flv'
});
flvPlayer.attachMediaElement(videoElement);
flvPlayer.load();
flvPlayer.play();
}
NginxでBasic認証
パスワードを知っている人しか映像を見る事はできない。
location /movies/ {
auth_basic "Eizo Ha Eizo";
auth_basic_user_file "/usr/local/nginx/passwd/.htpasswd";
}
Nginxでリファラ制御
自分のサイトからしか映像を再生させない。直リンクを避ける意味合い
location ~ ^/movies/ {
valid_referers server_names cloudn.hanako.jp;
if ($invalid_referer) { return 403; }
}
参考
http://technical.live-on.net/archives/1486
公式サイトにあるデモ
http://bilibili.github.io/flv.js/demo/
flv.js demo
Stream URL:
Switch to MediaDataSource
isLive
withCredentials
hasAudio
hasVideo
MediaDataSource JsonURL:
Switch to URL
Your browser is too old which doesn't support HTML5 video.
Load
Start
Pause
Destroy
SeekTo
var checkBoxFields = ['isLive', 'withCredentials', 'hasAudio', 'hasVideo'];
var streamURL, mediaSourceURL;
function flv_load() {
console.log('isSupported: ' + flvjs.isSupported());
if (mediaSourceURL.className === '') {
var url = document.getElementById('msURL').value;
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function (e) {
var mediaDataSource = JSON.parse(xhr.response);
flv_load_mds(mediaDataSource);
}
xhr.send();
} else {
var i;
var mediaDataSource = {
type: 'flv'
};
for (i = 0; i < checkBoxFields.length; i++) {
var field = checkBoxFields[i];
/** @type {HTMLInputElement} */
var checkbox = document.getElementById(field);
mediaDataSource[field] = checkbox.checked;
}
mediaDataSource['url'] = document.getElementById('sURL').value;
console.log('MediaDataSource', mediaDataSource);
flv_load_mds(mediaDataSource);
}
}
function flv_load_mds(mediaDataSource) {
var element = document.getElementsByName('videoElement')[0];
if (typeof player !== "undefined") {
if (player != null) {
player.unload();
player.detachMediaElement();
player.destroy();
player = null;
}
}
player = flvjs.createPlayer(mediaDataSource, {
enableWorker: false,
lazyLoadMaxDuration: 3 * 60,
seekType: 'range',
});
player.attachMediaElement(element);
player.load();
}
function flv_start() {
player.play();
}
function flv_pause() {
player.pause();
}
function flv_destroy() {
player.pause();
player.unload();
player.detachMediaElement();
player.destroy();
player = null;
}
function flv_seekto() {
var input = document.getElementsByName('seekpoint')[0];
player.currentTime = parseFloat(input.value);
}
function switch_url() {
streamURL.className = '';
mediaSourceURL.className = 'hidden';
saveSettings();
}
function switch_mds() {
streamURL.className = 'hidden';
mediaSourceURL.className = '';
saveSettings();
}
function ls_get(key, def) {
try {
var ret = localStorage.getItem('flvjs_demo.' + key);
if (ret === null) {
ret = def;
}
return ret;
} catch (e) {}
return def;
}
function ls_set(key, value) {
try {
localStorage.setItem('flvjs_demo.' + key, value);
} catch (e) {}
}
function saveSettings() {
if (mediaSourceURL.className === '') {
ls_set('inputMode', 'MediaDataSource');
} else {
ls_set('inputMode', 'StreamURL');
}
var i;
for (i = 0; i < checkBoxFields.length; i++) {
var field = checkBoxFields[i];
/** @type {HTMLInputElement} */
var checkbox = document.getElementById(field);
ls_set(field, checkbox.checked ? '1' : '0');
}
var msURL = document.getElementById('msURL');
var sURL = document.getElementById('sURL');
ls_set('msURL', msURL.value);
ls_set('sURL', sURL.value);
console.log('save');
}
function loadSettings() {
var i;
for (i = 0; i < checkBoxFields.length; i++) {
var field = checkBoxFields[i];
/** @type {HTMLInputElement} */
var checkbox = document.getElementById(field);
var c = ls_get(field, checkbox.checked ? '1' : '0');
checkbox.checked = c === '1' ? true : false;
}
var msURL = document.getElementById('msURL');
var sURL = document.getElementById('sURL');
msURL.value = ls_get('msURL', msURL.value);
sURL.value = ls_get('sURL', sURL.value);
if (ls_get('inputMode', 'StreamURL') === 'StreamURL') {
switch_url();
} else {
switch_mds();
}
}
function showVersion() {
var version = flvjs.version;
document.title = document.title + " (v" + version + ")";
}
var logcatbox = document.getElementsByName('logcatbox')[0];
flvjs.LoggingControl.addLogListener(function(type, str) {
logcatbox.value = logcatbox.value + str + '\n';
logcatbox.scrollTop = logcatbox.scrollHeight;
});
document.addEventListener('DOMContentLoaded', function () {
streamURL = document.getElementById('streamURL');
mediaSourceURL = document.getElementById('mediaSourceURL');
loadSettings();
showVersion();
flv_load();
});