HTML には video 要素があり、これは内部に様々な情報を持つことができます。その中にはチャプターについての情報もあり、JavaScript でこれを操作することによって web ページ上で再生する動画にチャプターとチャプターごとのジャンプ機能を付けられます。
<video>: 動画埋め込み要素 – HTML: HyperText Markup Language | MDN
チャプターを操作する前にチャプターを定義する必要があります。これは vtt (VideoTextTrack)ファイルと vtt ファイルを読み込む track 要素で定義できます。
Web ビデオテキストトラックフォーマット (WebVTT) – Web API | MDN
<track>: 埋め込みテキストトラック要素 – HTML: HyperText Markup Language | MDN
vtt ファイルは基本的に次の様な簡素なテキストファイルです。
WEBVTT NOTE チャプター例 00:00:00.000 --> 00:00:30.000 冒頭 00:00:30.000 --> 00:01:00.000 中盤 00:01:00.000 --> 00:01:15.000 終わり
一行目に WEBVTT と記述して、これが VTT ファイルであると宣言します。部品単位の区切りは空行です。空行で挟まれている部分に”hh:mm:ss.ttt –> hh:mm:ss.ttt”で記述された時間帯とその時間帯に紐づくテキストを記述できます。コメントは NOTE というキーワードを使うことで使えます。詳しくは MDN の次リンク参照です。
Web ビデオテキストトラックフォーマット (WebVTT) – Web API | MDN
vtt ファイルで特徴的なのはその中身自体では意味付けがなされていない点です。 track 要素で読み込む際、これは○○の vtt ファイル、といった具合に意味付けできます。
また、ここではチャプターのために vtt ファイルを使うため紹介しませんが字幕も vtt ファイルで定義でき、字幕に対して CSS を適用することができます。
track 要素は次の様に vtt ファイルを読み込むために用います。
<track>: 埋め込みテキストトラック要素 – HTML: HyperText Markup Language | MDN
<video controls> <source src="/animate_css_anime.mp4" type="video/mp4" /> <track default kind="chapters" srcLang="ja" src="/example.vtt" /> </video>
kind 属性でどの様な種別か指定され、この指定によって video 要素の振る舞いが変わります。いくつかのブラウザは JavaScript で特別なことをせずとも track 要素を読んで字幕、キャプションといった機能を web ページ上の動画プレイヤーに自動で追加します。これは例えば、次の様に動作します。
ソースコードを展開
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="theme-color" content="#000000" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<title>React App</title>
</head>
<body>
<video controls style="max-width: 500px;">
<source src="/animate_css_anime.mp4" type="video/mp4" />
<track
default
kind="subtitles"
label="日本語"
srclang="ja"
src="/example.vtt"
/>
</video>
</body>
</html>
この記事を書いている時点では少なくとも Google Chrome, Firefox で字幕を設定できることを確認しています。
この kind を chapters に変えると、現状のプレイヤーには何も出てこなくなりますが DOM の中にはしっかりと情報が入っています。

自家製コードでこれを読み取って、ボタンに紐づけて適宜 video.currentTime を変えてチャプタージャンプを実現するのもありですが、いくつかの動画再生用ライブラリはこのチャプター機能をいい感じに実装してくれています。例えば、 Video.js がその一つです。
videojs/video.js: Video.js – open source HTML5 & Flash video player
Video.js – Make your player yours | Video.js
次のデモは React に Video.js を組み込んでチャプター機能を付けた動画プレイヤーです。
ソースコード
チャプター用 vtt ファイル
WEBVTT NOTE チャプター例 00:00:00.000 --> 00:00:30.000 冒頭 00:00:30.000 --> 00:01:00.000 中盤 00:01:00.000 --> 00:01:15.000 終わり
React 上の動画プレイヤー
import React from "react";
import videojs, { VideoJsPlayer, VideoJsPlayerOptions } from "video.js";
import "video.js/dist/video-js.css";
type VideoPlayerProps = { options: VideoJsPlayerOptions };
export class VideoPlayer extends React.Component<VideoPlayerProps> {
public player?: VideoJsPlayer;
public videoNode?: HTMLVideoElement | null;
componentDidMount() {
// Video.jsのインスタンス化
this.player = videojs(
this.videoNode,
this.props.options,
function onPlayerReady() {
console.log("onPlayerReady");
}
);
}
// Video.js の掃除。これをしないと音が鳴りっぱなしになったりも
componentWillUnmount() {
if (this.player) {
this.player.dispose();
}
}
// videojs が DOM に追加のラッパーを作成しないように、
// `data-vjs-player` 属性でプレーヤーを div でラップします。
// @see https://github.com/videojs/video.js/pull/3856
render() {
return (
<div>
<div data-vjs-player>
<video
controls
ref={(node) => (this.videoNode = node)}
className="video-js"
>
{this.props.children}
</video>
</div>
</div>
);
}
}
React 上の動画プレイヤーの呼び出し
import * as React from "react";
import "./styles.css";
import { VideoPlayer } from "./VideoPlayer";
export default function App() {
const player = React.useRef<VideoPlayer>();
return (
<div className="App">
<VideoPlayer ref={player}>
<source src="/animate_css_anime.mp4" type="video/mp4" />
<track
default
kind="chapters"
label="チャプター"
srcLang="ja"
src="/example.vtt"
/>
</VideoPlayer>
</div>
);
}
こんな感じで web ページ上の動画に比較的簡単にチャプター機能を付けられます。