現在フレームを表示するということ
現在フレームを表示するには、まず再生時間を細かく管理する必要がある。
フレーム単位というのは曖昧で、各ファイルのフレームレートは可変になりうる。
これが理由で、例えば時間管理はMP4ではTrackの秒あたりタイムスケールである。
フレームはあくまで表示時間順に並んだコマであって、フレームレートを規定しない方法で管理される。
そのため、フレーム単位で動画を表示するのではなく、秒単位でやるのがよい。
入力ファイルを秒単位で扱うのが目的なので、プロジェクトそのものはフレーム単位で問題ない。
例えば、60fpsでプロジェクトが作成されたら、1/60秒を最小単位で扱うとか。
再生時に現在フレームを表示するには、次のことをする。
1. 各トラックに対して、チャンクのDecoding TimeとComposition Timeのリストを事前に取得する。
2. プロジェクトのフレームレートに応じて、1/(fps)秒が経過したら次のことをして、画面を更新する
1. 各トラックで、チャンクのDecoding Timeに到達したかを確認する。
2. 到達していたら、デコーダー(フォーマットの扱いが難しいのでffmpegがおすすめ)にチャンクを渡す。
(注)メタデータと、mdat上のチャンクのバイトだけを含んだDataViewによるファイルコピーを渡すことができる。
これについては、stco または co64ボックスを見てチャンクのバイトオフセットを取得する。
ただしこれは複雑なので、やらなくてもいいと思う
3. デコーダーからフレームデータを受け取る。
H.264などの場合合成をしないと差分画像しか表示できない。
1. 各トラックで、チャンクのComposition Time に到達したかを確認する。
2. 到達していたら、デコーダーにフレームデータを渡して合成後画像を受け取る
3. トラックのメタデータから再生速度を計算し、再生ヘッドの位置からトラックにおける現在フレーム数を取得する
4. 合成後画像にはチャンク内の画像が複数枚含まれるので、現在フレーム数を使って適当な画像を選択する
5. 表示する
なお、画面の更新前には必ず上の処理をするようにすれば、シークにも対応できる・・・気がする。
実際には、上の処理はしないほうがずっと望ましいと思う。
ブラウザはvideo要素を介してGPUを使ったデコードを自動的にやってくれるはずだから。
私たちはGPUを使うためにWebCodecs APIを使い - 言い換えればFireFoxを見捨てる必要があります