Posted at

videoのインライン動画再生について調査した。

More than 1 year has passed since last update.


まずはじめに

タイトルの通り、スマホでもPCでもビデオをつかったサイトが作りたい!

といった要望に応えるべく、いろいろ調べてみるもいろいろな方法がまばらになってるので

面倒だけれど意を決して2018年5月バージョンを自分で検証してみることにした。

ここに書いてあることを鵜呑みにせず、最終的には自身の手で仕様にあった検証をすることをおすすめします。

記事の整合性等は保証しません。書いていることが間違っていたらコメント等で教えてください。


結果

以下検証用に作ったページ。

https://sakokazuki.github.io/inline-video-test/

リポジトリ

https://github.com/sakokazuki/inline-video-test

webm形式の動画は検証していない。

自分の調べたい仕様になかったので音声つきは検証していない。

control click
autoplay
canvas-play
canvas-clickplay
canvas-currenttime
注釈

Chrome





-

FireFox





A

Safari





-

IE11





-

Edge





-

iOS Safari 10~*1





-

iOS Safari ~9*2





-

Android*3 Browser





B

Android*3 Chrome





-

Android*4 Browser





B

Android*4 Chrome





-

*1 iOS 11.3.1

*2 iOS 9.3.5

*3 Galaxy S5 SCL23 v6.0.1

*4 GALAXY J SC-02F v5.0

control click: コントロールを出して再生ボタンを押してインライン再生できるかどうか

auto play: inlineで動画がオートプレイされるかどうか。(再生ボタンを押さないと始まらない場合は✗)

canvas-play: videoをcanvasに描画し、play関数で再生。

canvas-click-play: videoをcanvasに描画し, onclickのクリックイベントからplay関数で再生。

canvas-currenttime: videoをcanvasに描画し, 再生はせずcurrenTtimeを更新する。

A: canvas-currenttimeは描画はされるものの、フレーム落ちしているので実用性にはかける

B: ビデオの同時再生ができない模様

一応手元にある端末で一つずつ確認していったけれど、リロードしたら再生されるやつとかあって微妙に信じがたい。

結論としてはPCは特に気にすることなくvideoタグ置けばいいと思う。

Androidは、オート再生をしたければ安定して動く方法がなさそうなので標準ブラウザはごめんなさいしたい。

なのでchromeもごめんなさいしたいところだがどうしてもという場合はchromeとそれ以外で分ける。

クリックイベントが取れるならば、canvasに描画する方法でiOS10~も動くのでそれでやる。

iOSは10以上はどんな方法もとれそうなのでandroidに合わせる。iOS9以下も対応したいとなると苦しい。


検証方法

気になる人はこちらも。githubに全部上がっているのでそちらを参考にしたほうが早いと思いつつ、コードべたばりで。

jsはbabelでトランスパイルしてるのでコピペじゃ動かないかもしれないです。

canvas絡まないやつはhtmlにvideoタグ置いてoptionをいろいろ変更している。

canvas絡むやつはjsを書いて、videoはcreateElementで生成して確認用にappendchildしてる。

canvasを使うやつは、


  1. videoをplay関数んで再生つつcanvasにdrawImageする方法

  2. インタラクション起点じゃないと再生しないというふうに世の中が向かってるのでボタンをおいて再生

  3. play関数呼ばずにcurrentTimeを操作するというやや強引な方方法

を試した。

currentTimeを操作する方法は<video src=''></video>の形式じゃないと動かなかった。。


index.html

<!doctype html>

<html>
<head>
<meta charset="UTF-8">
<title>video test</title>
<style>
body{
background: #000;
color: #fff;
}
canvas, video{
background: #f00;
}
</style>
</head>
<body>
<h1>inline video test</h1>
<p>common parameter: [controls, playsinline, webkit-playsinline loop muted]</p>

<div>
<h3>そのまま</h3>
<video id="test" controls playsinline webkit-playsinline loop muted>
<source src="./test1.mp4">
</video>
</div>

<div>
<h3>オートプレイ</h3>
<video controls playsinline webkit-playsinline autoplay loop muted>
<source src="./test1.mp4">
</video>
</div>

<div>
<h3>control抜いてオートプレイ</h3>
<video playsinline webkit-playsinline autoplay loop muted>
<source src="./test1.mp4">
</video>
</div>

<div>
<h3>canvasに描画して scriptでplay();</h3>
<p>canvas</p>
<canvas id="video" width="640" height="320"></canvas>
<p>video</p>
</div>

<div>
<h3>canvasに描画して clickイベントでplay()</h3>
<button id="video-click-button" style="width: 300px; height: 100px;">PLAY</button>
<p>canvas</p>
<canvas id="video-click" width="640" height="320"></canvas>
<p>video</p>
</div>

<div>
<h3>canvasに描画して currenttimeを操作</h3>
<p>canvas</p>
<canvas id="currenttime" width="640" height="320"></canvas>
<p>video</p>
</div>
<script src="./main.js"></script>

</body>
</html>



main.js

import 'babel-polyfill'

window.onload = ()=>{

main();
}

const main = ()=>{
 cocanvasplay('video');
canvasbuttonplay('video-click')
currentTime('currenttime');

}

const canvasplay = async (canvasID)=>{
const video = await loadvideoSource();
const canvas = document.getElementById(canvasID);

canvas.parentNode.appendChild(video);

const ctx = canvas.getContext('2d');
const fps = 30;
setInterval(()=>{
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
}, 1000/fps)

video.play();
}

const canvasbuttonplay = async (canvasID)=>{
const video = await loadvideoSource();
const canvas = document.getElementById(canvasID);

canvas.parentNode.appendChild(video);

const ctx = canvas.getContext('2d');
const fps = 30;
setInterval(()=>{
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
}, 1000/fps)

const button = document.getElementById(canvasID+'-button');
button.onclick = ()=>{
video.play();
}

}

const currentTime = async (canvasID)=>{
const video = await loadvideo();
const canvas = document.getElementById(canvasID);
const ctx = canvas.getContext('2d');
const fps = 30;

canvas.parentNode.appendChild(video);

let time = 0;
let lasttime = new Date().getTime();;
setInterval(()=>{
//前フレームとの差分
const currenttime = new Date().getTime();
const delta = currenttime - lasttime;
lasttime = currenttime;

time += delta/1000;
video.currentTime = time;

ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
//loop
if(time > video.duration){
time = 0;
}
}, fps);
}

//<video src=""></video>
//のかたち
const loadvideo = ()=>{
return new Promise((resolve, reject)=>{
//videoタグ作成
const video = document.createElement("video")
video.src = './test1.mp4';

//アトリビュート追加
const attrs = ['playsinline', 'webkit-playsinline', 'loop', 'muted']
for(let i=0; i<attrs.length; i++){
video.setAttribute(attrs[i], "");
}
video.addEventListener('canplaythrough',(e)=>{
resolve(video)
})

video.load();
})
}

//<video>
// <source src="">
//</video>
//のかたち
const loadvideoSource = ()=>{
return new Promise((resolve, reject)=>{
//videoタグ作成
const video = document.createElement("video")
const source = document.createElement("source")
source.src = './test1.mp4';
source.type = 'video/mp4'
video.appendChild(source);

//アトリビュート追加
const attrs = ['controls', 'playsinline', 'webkit-playsinline', 'loop', 'muted']
for(let i=0; i<attrs.length; i++){
video.setAttribute(attrs[i], "");
}
video.addEventListener('canplaythrough',(e)=>{
resolve(video)
})

video.load();
})
}



参考にさせていただきました。

https://qiita.com/hadakadenkyu/items/75162099d0bf7cdcfdc7