【发布时间】:2011-07-13 17:36:42
【问题描述】:
HTML5 <video> 标签可以反向播放,还是我必须下载 2 个视频(向前和向后播放)?
我正在寻找一种避免用户下载 2 个视频的解决方案。
【问题讨论】:
-
我强烈倾向于 NO,因为大多数压缩方案都假定您正在播放 Forward。
标签: javascript html html5-video
HTML5 <video> 标签可以反向播放,还是我必须下载 2 个视频(向前和向后播放)?
我正在寻找一种避免用户下载 2 个视频的解决方案。
【问题讨论】:
标签: javascript html html5-video
甚至无需进入 HTML5 或 Javascript,许多视频格式都是设计用于向前播放的 streaming 格式。向后播放需要解码整个流,将每个原始帧存储在磁盘上以避免破坏内存,然后向后渲染帧。
不过,至少有一个人actually tried that 使用mplayer,所以它可以做到,至少原则上是这样。
【讨论】:
我设法在更新方法中做到了。每一帧我都会将 video.currentTime 减少到经过的时间,到目前为止,这是我设法获得的最佳结果。
【讨论】:
0.1 和 100 来设置速率(即 0.1 秒等于 100 毫秒):@987654323 @
clearInterval(reverse);
aMediaElement.playbackRate = -1;
UA 可能不支持这一点,尽管将playbackRate 设置为负值是有效的。
【讨论】:
这个 sn-p 只是显示了它是如何完成的,但是复制每一帧需要一些时间。这在很大程度上取决于硬件。
它会为必须播放的每一帧生成一个画布。当它打开 100% 时,播放直接开始并向后、向前播放……等等。原始视频在生成后也会附加,但由于 iframe 规则,不会自动播放。
它适用于短视频和概念验证。
更新: 我更改了捕获部分的顺序,以便跳过最长持续时间的帧,但捕获 0 处的帧(之前忘记了)。
最大持续时间的帧在我尝试的每个视频上都导致白色画布。
我还将播放更改为在到达最后一帧后立即以相反的顺序播放以进行无休止的播放。所以你很容易看到,与硬件加速的视频相比,这种播放有点 CPU 密集型。
fetch('https://i.imgur.com/BPQF5yy.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 秒)间隔。请注意,此方法仍然向前播放媒体。尝试提高媒体播放速率,让它感觉更流畅。
【讨论】: