html5のvideoに関する覚書的なメモ

…覚書とメモってどう違うんだろう。というかメモランダムって単語使わないよね日本。
どうでもいい導入はさておき。あ、オーラルヒストリーは大好きです僕（あまり関係ない

#ここに書いてること
videoタグで動画いろいろいじりながら考えたりこねくり回したりしたことをメモってる。一部は過程も書いておきたい。
いろいろなところで見かける簡素な内容はできるだけ割愛して、ちょっと掘った内容多めにしたい。

#基本的なこと
https://www.w3.org/2010/05/video/mediaevents.html
ここ見ればだいたいわかる。ある程度技術があるなら、ここに行きつければだいたいできることは見えると思う。
触り始めてから一ヶ月ほどたってここに行きついたけど、初日にここ見つけてればもっと楽だったなぁ（吐血

さらに下記サイトを合わせて読むとシナジーがマッハになるので、もう何も怖くない（死亡フラグ
http://www.antytle.com/js/video-element-attr
各種制御要素の日本語解説とか
http://www.antytle.com/js/video-element-events
イベント系の日本語解説

以降、以下の感じでvideoに掴んでいるものと想定して話を進めまする。細かくは突っ込まないように。

```JavaScript:hoge.js
var video = document.getElementById("hoge");
（または、jQueryで）
var video = $("#hoge").get(0);
```



#動画視聴に直接関わりそうな属性
分類ちょっと迷ったけど、とりあえずこんな感じで書くだけ書いてから考える。

- 再生状態
- 再生位置
- 音量
- ミュート状態

##再生状態
（boolean）video.paused
停止しているかどうかがboolで帰ってくるので、ものすごく簡単。もちろん、再生中であるならfalse。
例えば以下のように書ける（サンプルは以前自分で書いたhtml5+videoのソースから拝借）

```JavaScript:sample.js
$(document).on("click", "#play_btn", function(){
	var video = $('#hoge').get(0);
	if(video.paused){
		video.play(); // 動画再生が始まり、video.pausedはfalseになる
	}else{
		video.pause(); // 動画再生が止まり、video.pausedはtrueになる
	}
});
```

##再生位置
(number)video.currentTime (second)
中身は"0.959811"とかみたいに小数点以下まで入っている。細かすぎ。
直接いじるとすぐ反映するので、例えば１秒送るのであれば以下のように。

```JavaScript:sample.js
$(document).on("click", "#1sec_forword_btn", function(){
	var video = $('#hoge').get(0),
	video.currentTime += 1 ;
});
```

言うに及ばず、再生中は常時増えている。
下限（0）、上限（video.duration）を超す計算をすると勝手に矯正される様子。特にエラーを吐かない。

##音量
(number)video.volume
0～1までの値をとる。0～100を使って管理して、代入時に100で除算する的な取り回しをよく見る。

```JavaScript:sample.js
$(document).on("click", "#volup_btn", function(){
	var video = $('#hoge').get(0),
	video.volume += 0.1 ;
});
```

こっちも範囲外に出られないところまでは一緒だが、上限／下限越えともに以下の例外を吐く。
>Uncaught DOMException: Failed to set the 'volume' property on 'HTMLMediaElement': The volume provided (1.0331) is outside the range [0, 1].
※1.0331のところは実際に入れようとした値。

##音声ミュート
(boolean)video.muted
ミュート状態かどうかのboolが返ってくる。素直に使えばよさそう。

```JavaScript:sample.js
$(document).on("click", "#mute_btn", function(){
	var video = $('#proxy_play').get(0);
	
	if(video.muted){
		video.muted = false;
	}else{
		video.muted = true;
	}
});
```
###（付記１）デフォルトのミュート設定
タグに"muted"っていれておくと、デフォルトでミュートがかかる。

```sample.html
    <video id='video' controls muted>
```

(boolean)video.defaultMuted
デフォルトでミュートがかかっているかどうかを調べられる。

###（付記２）ミュート周りのデフォルトコントローラの挙動
デフォルトのコントローラでは、ミュート有効時に音量スライダーが０の位置まで下がるが、実際のvideo.volumeはミュート前の位置の値をキープしており、ミュート開示時にその位置まで戻る。
さらにミュートした状態でスライダーを動かすと、ミュート解除＋スライダー位置の音量をvideo.volumeに代入する。

これ独自実装で再現しようとすると結構めんどくさいような…スライダーの位置連動で音量調整という実装の場合、ミュート前の値を外部に逃がして解除時に戻す処理が必要になるし、ミュート中にスライダーが動いた場合の解除を別枠で用意しないといけないし…（他処理との絡みも含めて面倒だったので、自分はミュート中のスライダーをdisableして逃げた）

#バッファ属性
(object)video.buffered

動画データの、先読みでローカル（？）にロードされている範囲。
正直ここが一番書きたかった（メモとして記録したかった）。

##バッファ範囲数
(number)video.buffered.length (個)
実際はunsigned longなので自然数。いや範囲が自然数じゃないってさすがにありえないっしょ。
そしてこれ、必ずしも１であるとは限らないのがミソ。２以上になることがあるんだよね…

##バッファ範囲始点／終点
(number)video.buffered.start(index) (sec)
(number)video.buffered.end(index) (sec)
※indexは0～(video.buffer.length-1)
大抵セットで使うのでまとめて。それぞれのバッファの始点と終点の秒数が入っている。

##バッファについて詳しく
デフォルトのコントローラでは直近のものしか反映されないので追いづらい上に、なかなか面白い挙動をしてくれて涙目。

###突然ですが、問題です
３０分の動画を最初から見たとしましょう。
再生が始まりましたが、最初の２分少々はOPの様子なのでちょっとだけ見て２分飛ばしました。
１４分でCMが始まったので、１分スキップしてから最後まで見ました。

さてこの状態、バッファの状態はどうなっているでしょう。

###見た目君の答えー
デフォルトのコントローラをはじめ、ほとんどの動画サイトのプログレスバーは
最後にシークした場所から先のバッファしか表示してないし、そこより前の部分は捨ててるんじゃないの？

###中身君の答えー
(object)video.buffered
オブジェクト君かー、じゃあ中身見せてね
https://developer.mozilla.org/ja/docs/Web/API/TimeRanges
（英語サイト）

すごーい、きみは始点と終点があって、そのセット数をlengthで帰してくるobjectなんだね。
じゃあ実際にさっきの動画のvideo.bufferedちゃんの中身を見てみようね。
（以下イメージです。実態が間違ってたらごめん）

|index|start|end|
|:-:|:-:|:-:|
|0|0|2.525|
|1|122.525|840|
|2|900|1800|

…というように、見事なまでに３セット入っていたりする（くどいようですがイメージです）

###これをふまえてー
「実はOPに伏線があったかもしれない」と思い直したので、最初に戻ってオープニングを見直しました。
本編が130秒から始まったとして、この時のvideo.bufferedちゃんの中身はどうなっているでしょう。

…
……
………

|index|start|end|
|:-:|:-:|:-:|
|0|0|840|
|1|900|1800|

ホワッツ？

ゴシゴシ…（aa略

|index|start|end|
|:-:|:-:|:-:|
|0|0|840|
|1|900|1800|

もしもし　ポリスメン？
うちのbufferedちゃんのセットが一つ行方不明なんだけど？

###というわけでまとめ
こいつ、範囲が重複するときは、合成してindexつけなおしやがるのよね…
さらに、例えばこの後に855～870（１５秒CM１本分だと思いねぇ）のindexを加えると、

|index|start|end|
|:-:|:-:|:-:|
|0|0|840|
|1|855|870|
|2|900|1800|

その位置に挿入されやがります。なので、実装状態次第では突然表示範囲が面白いことになります。
最終インデックスをベースにバッファ範囲だしてると、合成発生時に突然バッファ範囲が広がったりとか。

###補足トリビア
例えば15秒バッファするのに5秒かかるとして。すでにバッファされた範囲が拡大しても、その外のバッファがすぐに増えることはなく、その分時間がかかります。
例えば以下の状況スタートでsetIntervalとか使ってバッファ状況を確認すると、

|index|start|end|
|:-:|:-:|:-:|
|0|0|840|
|1|855|870|

0:0/840.0123とかで読み込みが始まってから、5秒で855到達後、
0:0/870になってからしばらくは中身が動いていない。
5秒後あたりに0/870.1234とかって動き出してからは同じペース。
…筆者個人の環境では何度でも再現。既にバッファされてるのに読み込んでるんじゃないかコレ？
実際にバッファされてるのかどうかとかいろいろ疑問は尽きないが、調査員は（とりあえず）ここで考えるのをやめた。

※この辺諸々、object TimeRangeの挙動なのかvideoとしての挙動なのかの切り分けとかが要るような


#その他
- 別途調べたら追記するかもしれない。（自分が）使いそうな要素は大分掘ったと思う。
- 後輩に「なんでわざわざ範囲外に出そうとしたりするんですか？」って言われた。別の後輩に「バグだす挙動好きですね」って言われた。…割とショック。いや普通出すでしょ？ましてその時の挙動書いてあるサイト見つかってないし…

#本文中で出てこなかった参考サイト
https://techblog.yahoo.co.jp/lab/ehon/
http://takazudo.github.io/blog/entry/2013-02-06-videoaudio.html