Есть canvas
, который рисует video
. Я хочу поменять источник видео и пока делаю это просто изменением атрибута src
. Я не понимаю, что в таком случае происходит с канвасом, но при каждой смене источника (или load
у видео)
производительность падает, а нагрузка на CPU растет. Очевидно, делаю что-то не правильно.
Собственно, вопрос - почему так происходит и как правильно менять источник видео, чтобы избежать возможных проблем с производительностью?
P.S В сниппете канвас маленький, лагать начинает после 30+ замен, в проекте канвас на весь экран и их две штуки, там это заметно уже после 6-8 замены.
videos = new Array();
videos[0] = {
source: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4"
};
videos[1] = {
source: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4"
};
videos[2] = {
source: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerFun.mp4"
};
var setSource = function(num) {
$('video').attr('src', videos[num].source);
}
var loadVideo = function() {
var i = 0;
var loadTimer = setInterval(function() {
i += 1;
$('video').get(0).load();
if (i == 41) {
clearInterval(loadTimer);
};
}, 100);
}
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext("2d");
const video = document.querySelector('video');
video.addEventListener('play', () => {
function step() {
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
requestAnimationFrame(step);
}
requestAnimationFrame(step);
})
let frameCount = function _fc(timeStart) {
let now = performance.now();
let duration = now - timeStart;
if (duration < 1000) {
_fc.counter++;
} else {
_fc.fps = _fc.counter;
_fc.counter = 0;
timeStart = now;
$("#fps-counter").html(_fc.fps);
if (_fc.fps >= 55) {
$("#fps-counter").css("color", "green");
} else if (_fc.fps >= 30) {
$("#fps-counter").css("color", "orange");
} else if (_fc.fps < 30) {
$("#fps-counter").css("color", "red");
}
}
requestAnimationFrame(() => frameCount(timeStart));
};
frameCount.counter = 0;
frameCount.fps = 0;
frameCount(performance.now());
canvas, video {
position: absolute;
right: 0;
margin: auto;
}
canvas {
top: 0;
width: 300px;
border: 1px solid red;
}
video {
bottom: 0;
width: 100px;
border: 1px solid blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Set video source</p>
<button onclick="setSource(0)">1</button>
<button onclick="setSource(1)">2</button>
<button onclick="setSource(2)">3</button>
<p>video.load() x40</p>
<button onclick="loadVideo()">load()</button>
<p> fps: <span id='fps-counter'>0</span></p>
<video autoplay muted loop src='https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4'></video>
<canvas></canvas>
Дело в событии play
. При каждой смене источника или загрузке это событие вызывается.
Соответственно, у вас очень много одинаковых вызовов функции step
. Из-за этого и происходит утечка.
Способ решения в примере - просто proof of concept. В реальном коде надо будет сделать как-то по другому.
videos = new Array();
videos[0] = {
source: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4"
};
videos[1] = {
source: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4"
};
videos[2] = {
source: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerFun.mp4"
};
var setSource = function(num) {
$('video').attr('src', videos[num].source);
}
var loadVideo = function() {
var i = 0;
var loadTimer = setInterval(function() {
i += 1;
$('video').get(0).load();
if (i == 41) {
clearInterval(loadTimer);
};
}, 100);
}
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext("2d");
const video = document.querySelector('video');
let isPlaying = false;
video.addEventListener('play', () => {
if (!isPlaying) {
console.log('play');
requestAnimationFrame(step);
isPlaying = true;
}
});
function step() {
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
requestAnimationFrame(step);
}
let frameCount = function _fc(timeStart) {
let now = performance.now();
let duration = now - timeStart;
if (duration < 1000) {
_fc.counter++;
} else {
_fc.fps = _fc.counter;
_fc.counter = 0;
timeStart = now;
$("#fps-counter").html(_fc.fps);
if (_fc.fps >= 55) {
$("#fps-counter").css("color", "green");
} else if (_fc.fps >= 30) {
$("#fps-counter").css("color", "orange");
} else if (_fc.fps < 30) {
$("#fps-counter").css("color", "red");
}
}
requestAnimationFrame(() => frameCount(timeStart));
};
frameCount.counter = 0;
frameCount.fps = 0;
frameCount(performance.now());
canvas,
video {
position: absolute;
right: 0;
margin: auto;
}
canvas {
top: 0;
width: 300px;
border: 1px solid red;
}
video {
bottom: 0;
width: 100px;
border: 1px solid blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Set video source</p>
<button onclick="setSource(0)">1</button>
<button onclick="setSource(1)">2</button>
<button onclick="setSource(2)">3</button>
<p>video.load() x40</p>
<button onclick="loadVideo()">load()</button>
<p> fps: <span id='fps-counter'>0</span></p>
<video autoplay muted loop src='https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4'></video>
<canvas></canvas>
Виртуальный выделенный сервер (VDS) становится отличным выбором
Мне нужно сформировать отчет Excel и скачать егоДанные берутся из SQL ( примерно 200 тысяч строк на 70 столбиков)
Форма изначально невидима, открывается при нажатии на кнопкуВ форме есть поля, одно из которых input в который нужно вставить дату (каждый раз...
IE9 не поддерживает classList в связи с этим написал небольшую функцию для удаления классов, есть два варианта :