5秒ごとにビデオからフレームをキャプチャしたい。
これは私のJavaScriptコードです。
video.addEventListener('loadeddata', function() {
var duration = video.duration;
var i = 0;
var interval = setInterval(function() {
video.currentTime = i;
generateThumbnail(i);
i = i+5;
if (i > duration) clearInterval(interval);
}, 300);
});
function generateThumbnail(i) {
//generate thumbnail URL data
var context = thecanvas.getContext('2d');
context.drawImage(video, 0, 0, 220, 150);
var dataURL = thecanvas.toDataURL();
//create img
var img = document.createElement('img');
img.setAttribute('src', dataURL);
//append img in container div
document.getElementById('thumbnailContainer').appendChild(img);
}
私が抱えている問題は、最初に生成された2つの画像が同じであり、持続時間5秒の画像が生成されないことです。特定の時間のビデオフレームが< video>
タグに表示される前にサムネイルが生成されることがわかりました。
たとえば、video.currentTime = 5
の場合、フレーム0sの画像が生成されます。その後、ビデオフレームは時間5秒にジャンプします。したがって、video.currentTime = 10
の場合、フレーム5の画像が生成されます。
問題は、ビデオのシーク(currentTime
の設定による)が非同期であることです。
seeked
イベントをリッスンする必要があります。そうしないと、古い値である可能性のある実際の現在のフレームを取得するリスクがあります。
非同期であるため、setInterval()
も非同期に使用しないでください。次のフレームがシークされたときに適切に同期することはできません。代わりにseeked
イベントを使用するため、setInterval()
を使用する必要はありません。これにより、すべての同期が維持されます。
コードを少し書き直すことで、seeked
イベントを使用してビデオを通過し、正しいフレームをキャプチャできます。このイベントにより、currentTime
プロパティ。
例
// global or parent scope of handlers
var video = document.getElementById("video"); // added for clarity: this is needed
var i = 0;
video.addEventListener('loadeddata', function() {
this.currentTime = i;
});
このイベントハンドラーをパーティーに追加します。
video.addEventListener('seeked', function() {
// now video has seeked and current frames will show
// at the time as we expect
generateThumbnail(i);
// when frame is captured increase, here by 5 seconds
i += 5;
// if we are not passed end, seek to next interval
if (i <= this.duration) {
// this will trigger another seeked event
this.currentTime = i;
}
else {
// Done!, next action
}
});