HTML5<video>
标签可以反向播放,还是我必须下载 2 个视频(向前和向后播放)?
我正在寻找避免用户下载 2 个视频的解决方案。
HTML5<video>
标签可以反向播放,还是我必须下载 2 个视频(向前和向后播放)?
我正在寻找避免用户下载 2 个视频的解决方案。
我设法在更新方法中做到了。每一帧我都将 video.currentTime 减少到经过的时间,到目前为止,这是我设法获得的最佳结果。
aMediaElement.playbackRate = -1;
UA 可能不支持这一点,尽管设置playbackRate
为负值是有效的。
这个片段只是展示了它是如何完成的,但是复制每一帧需要一些时间。这在很大程度上取决于硬件。
它为它必须播放的每一帧生成一个画布。当它打开 100% 时,播放直接开始并向后播放、向前播放......等等。原来的Video也是在生成后附上的,但是由于iframe规则,不会自动播放。
它适用于短视频并作为概念证明。
更新: 我更改了捕获部分的顺序,以便跳过最大持续时间的帧,但捕获 0 处的帧(之前忘记了)。
最大持续时间的帧在我尝试的每个视频上都会导致白色画布。
我还更改了播放,以便在到达最后一帧后立即以相反的顺序播放以进行无休止的播放。所以你很容易看到,与硬件加速视频相比,这种播放有点 CPU 密集型。
fetch('https://i.imgur.com/cSmeKr4.mp4')
.then(res => res.blob())
.then(blob => {
return new Promise((res) => {
const fr = new FileReader();
fr.onload = e => res(fr.result);
fr.readAsDataURL(blob);
})
}).then(async(base64str) => {
const video = document.createElement("video");
video.src = base64str;
video.controls = true;
video.className = "w-50";
while (isNaN(video.duration))
await new Promise((r) => setTimeout(r, 50));
const FPS = 25;
const status = document.createElement("div"),
length = document.createElement("div");
length.innerText = `Generating ${Math.ceil(video.duration / (1 / FPS))} frames for a ${FPS} FPS playback (Video Duration = ${video.duration})`;
document.body.appendChild(length);
document.body.appendChild(status);
const frames = [],
copy = () => {
const c = document.createElement("canvas");
Object.assign(c, {
width: video.videoWidth,
height: video.videoHeight,
className: "w-50"
});
c.getContext("2d").drawImage(video, 0, 0);
return c;
};
// first seek outside of the loop this image won't be copied
video.currentTime = video.duration;
// this frame seems to be always white/transparent
while (video.currentTime) {
if (video.currentTime - 1 / FPS < 0)
video.currentTime = 0;
else
video.currentTime = video.currentTime - 1 / FPS;
await new Promise((next) => {
video.addEventListener('seeked', () => {
frames.push(copy());
status.innerText = (frames.length / (Math.ceil(video.duration / (1 / FPS))) * 100).toFixed(2) + '%';
next();
}, {
once: true
});
});
}
/*
* frames now contains all canvas elements created,
* I just append the first image and replace it on
* every tick with the next frame.
* using last.replaceWith(frames[currentPos]) guarantees a smooth playback.
*/
let i = 0, last = frames[0];
document.body.insertAdjacentHTML('beforeend', `<div class="w-50">Captured</div><div class="w-50">Video</div>`);
document.body.appendChild(frames[0]);
const interval = setInterval(() => {
if (frames[++i]) {
last.replaceWith(frames[i]);
last = frames[i];
} else {
frames.reverse();
i=0;
}
}, 1000 / FPS);
document.body.appendChild(video);
// won't :(
video.play();
});
/* Just for this example */
.w-50 {
width: 50%;
display: inline-block;
}
* {
margin: 0;
padding: 0;
font-family: Sans-Serif;
font-size: 12px;
}
获取 HTMLMediaElement 的持续时间,然后设置一个间隔,该间隔将每秒运行一次并通过设置 .currentTime 播放媒体,并将该值每秒减少 1。媒体元素必须完全下载才能工作。我只在 30 秒的剪辑上测试过这个,不确定是否可以更快(小于 1 秒)间隔。请注意,此方法仍向前播放媒体。尝试提高媒体播放速率,使其感觉更加无缝。