我正在设计一个自定义HTML5
视频播放器。因此,它将拥有自己的自定义滑块来模仿视频进度,因此我需要了解HTML5
视频的整个缓冲框。
我看到了这篇文章:Video Buffering。它表示缓冲对象由几个时间范围组成,它们以开始时间的线性顺序排列。但我找不到以下内容:
说视频开始了。它自己一直持续到1:45(偶尔也会停滞,等待进一步的数据),之后我突然跳到32:45。现在过了一段时间,如果我跳回到1:27(在最初加载和播放的时间范围内,在我跳跃之前),它会立即开始播放,因为之前已经加载了吗?或者是因为我跳了一下,那部分会丢失并且必须再次取出?无论哪种方式,所有这些情况的行为是否一致?
假设我做了5次或6次这样的跳转,每次等待几秒钟以便在跳转后加载一些数据。这是否意味着buffered
对象将存储所有这些时间范围?或者有些人会迷路?它是一种堆栈类型的东西,当更多的范围由于进一步的跳跃而加载时,较早的范围会弹出吗?
检查buffered
对象是否有一个时间范围从0开始(忘记直播)并以视频持续时间长度结束,确保整个视频资源已完全加载?如果没有,是否有某种方式可以知道整个视频已被下载,并且任何部分都是可搜索的,视频可以连续播放而不会有片刻的延迟?
W3C规范对此并不十分清楚,我也找不到适当大的(比如一个多小时)远程视频资源来测试。
答案 0 :(得分:31)
视频的缓冲方式取决于浏览器的实现,因此浏览器可能会有所不同。
各种浏览器可以使用不同的因素来确定保留或丢弃缓冲区的一部分。旧段,磁盘空间,内存和性能是典型因素。
真正了解的唯一方法是“查看”浏览器的内容或正在加载的内容。
为此,我制作了一个缓冲区查看器,显示缓冲区中的哪个部分。查看器将显示整个缓冲区的当前和所有部分:
<强> ONLINE BUFFER VIEWER 强>
例如 - 在Chrome中我播放了几秒钟然后我跳过了大约30秒,您可以看到它开始从该位置开始加载另一部分。
(缓冲区似乎也与关键帧有关,因此可以对该缓冲区中的n帧进行解码。这意味着缓冲区可以在实际位置之前开始加载数据。)
我提供了大约1分钟的演示视频 - 但这不足以进行正确的测试。免费提供包含更长视频的视频链接(如果您希望我用此更新演示,请分享)。
主函数将遍历视频元素上的buffered
对象。它将呈现画布正下方的所有部分以红色显示。
您可以在此查看器上单击(不拖动)以将视频移动到不同的位置。
/// buffer viewer loop (updates about every 2nd frame)
function loop() {
var b = vid.buffered, /// get buffer object
i = b.length, /// counter for loop
w = canvas.width, /// cache canvas width and height
h = canvas.height,
vl = vid.duration, /// total video duration in seconds
x1, x2; /// buffer segment mark positions
/// clear canvas with black
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, w, h);
/// red color for loaded buffer(s)
ctx.fillStyle = '#d00';
/// iterate through buffers
while (i--) {
x1 = b.start(i) / vl * w;
x2 = b.end(i) / vl * w;
ctx.fillRect(x1, 0, x2 - x1, h);
}
/// draw info
ctx.fillStyle = '#fff';
ctx.textBaseline = 'top';
ctx.textAlign = 'left';
ctx.fillText(vid.currentTime.toFixed(1), 4, 4);
ctx.textAlign = 'right';
ctx.fillText(vl.toFixed(1), w - 4, 4);
/// draw cursor for position
x1 = vid.currentTime / vl * w;
ctx.beginPath();
ctx.arc(x1, h * 0.5, 7, 0, 2 * Math.PI);
ctx.fill();
setTimeout(loop, 29);
}
答案 1 :(得分:7)
根据
buffered
属性包含有关所有当前缓冲时间范围的信息。根据我的理解,如果缓冲部分丢失,它将从对象中删除(万一发生)。
特别是最后一个链接对于理解这个问题似乎非常有用(因为它提供了代码示例),但请记住这些是mozilla文档,并且在其他浏览器中支持可能会有所不同。
回答你的问题
说视频开始了。它自己一直持续到1:45(偶尔也会停滞,等待进一步的数据),之后我突然跳到32:45。现在过了一段时间,如果我跳回到1:27(在最初加载和播放的时间范围内,在我跳转之前),它会立即开始播放,因为之前已经加载了吗?
应该在跳回时立即播放,除非该部分的缓冲区被卸载。我认为假设缓冲区或缓冲区范围在某些时候卸载是非常合理的,如果整个缓冲区大小超过一定的体积。
假设我做了5或6次这样的跳转,每次等待几秒钟以便在跳转后加载一些数据。这是否意味着缓冲对象将存储所有这些时间范围?
是的,所有缓冲的范围都应该通过属性可读。
检查缓冲对象是否有一个从0开始的时间范围(忘记直播)并以视频持续时间长度结束,确保整个视频资源已经完全加载?
是的,这是最后一个链接中的代码示例。显然,这是一种确定整个视频是否已加载的适用方法。
if (buf.start(0) == 0 && buf.end(0) == v.duration)
答案 2 :(得分:3)
几乎每个浏览器都将缓冲的数据保存在该会话的缓存中。用户离开该页面后,缓存将过期。我不认为用户每次从加载视频的点加载视频时都必须加载页面。仅当服务器清除所有缓存数据时,用户才会遇到此问题。 HTML5视频代码将支持此功能,并将视频保存到点,直到加载完毕。
这并不意味着会话已经丢失,这意味着对象(如果您使用的是Flash播放器)正在寻找该特定点的某些数据,或者html5视频标签是否存在某些问题,因为INTERNET连接失败或其他一些服务器错误。
自动加载元数据,直到你使用它
<audio preload="none"...
这将使浏览器不从服务器下载任何内容,您可以将其用作:
<audio preload="auto|metadata|none"...
如果您使用none,则除非用户单击播放按钮,否则不下载任何内容,元数据将从服务器下载名称,时间和其他元数据,但不会以某种方式下载文件,auto会在页面加载后立即开始下载
我将一直推荐您阅读jQuery的一些文档。由于jQuery允许您使用ajax API更改和更新内容,因此也会有所帮助。希望你成功!欢呼声。
答案 3 :(得分:0)
虽然接受的答案描述非常好,但我决定更新其代码示例,原因如下:
progress
事件上触发进度渲染任务。document.getElementById()
。for()
循环比后向while()
循环更优雅。请注意,我已删除播放头和时间戳以保持代码清洁,因为此答案主要关注视频缓冲区的可视化。
LINK TO ONLINE VIDEO BUFFER VISUALISER
重写已接受答案的loop()
功能:
function drawProgress(canvas, buffered, duration){
// I've turned off anti-aliasing since we're just drawing rectangles.
var context = canvas.getContext('2d', { antialias: false });
context.fillStyle = 'blue';
var width = canvas.width;
var height = canvas.height;
if(!width || !height) throw "Canvas's width or height weren't set!";
context.clearRect(0, 0, width, height); // clear canvas
for(var i = 0; i < buffered.length; i++){
var leadingEdge = buffered.start(i) / duration * width;
var trailingEdge = buffered.end(i) / duration * width;
context.fillRect(leadingEdge, 0, trailingEdge - leadingEdge, height);
}
}
答案 4 :(得分:0)
这只是这个出色答案https://stackoverflow.com/a/18624833/985454
的变体我只是使它工作而无需任何工作,并且增加了一些额外的好处。一切都是自动的。
function prepare() {
console.log('prepare');
_v = $('video')[0];
_v.insertAdjacentHTML('afterend',
`<canvas
id="WowSuchName"
height="1"
style="
position: absolute;
bottom: 0;
left: 0;
opacity: 0.4;
"></canvas>`);
_c = WowSuchName
_cx = _c.getContext('2d');
window.addEventListener('resize', resizeCanvas, false);
function resizeCanvas() {
console.log('resize');
_c.width = window.innerWidth;
}
resizeCanvas();
}
/// buffer viewer loop (updates about every 2nd frame)
function loop() {
if (!window.WowSuchName) { prepare(); }
var b = _v.buffered, /// get buffer object
i = b.length, /// counter for loop
w = _c.width, /// cache canvas width and height
h = _c.height,
vl = _v.duration, /// total video duration in seconds
x1, x2; /// buffer segment mark positions
/// clear canvas
_cx.clearRect(0, 0, w, h);
/// color for loaded buffer(s)
_cx.fillStyle = '#888';
/// iterate through buffers
while (i--) {
x1 = b.start(i) / vl * w;
x2 = b.end(i) / vl * w;
_cx.fillRect(x1, 0, x2 - x1, h);
}
/// draw cursor for position
_cx.fillStyle = '#fff';
x1 = _v.currentTime / vl * w;
_cx.fillRect(x1-1, 0, 2, h);
setTimeout(loop, 29);
}
loop();
书签的代码在这里
javascript:eval(atob("CmZ1bmN0aW9uIHByZXBhcmUoKSB7CiAgICBjb25zb2xlLmxvZygncHJlcGFyZScpOwoKICAgIF92ID0gJCgndmlkZW8nKVswXTsKICAgIF92Lmluc2VydEFkamFjZW50SFRNTCgnYWZ0ZXJlbmQnLAogICAgYDxjYW52YXMKICAgICAgICBpZD0iV293U3VjaE5hbWUiCiAgICAgICAgaGVpZ2h0PSIxIgogICAgICAgIHN0eWxlPSIKICAgICAgICAgICAgcG9zaXRpb246IGFic29sdXRlOwogICAgICAgICAgICBib3R0b206IDA7CiAgICAgICAgICAgIGxlZnQ6IDA7CiAgICAgICAgICAgIG9wYWNpdHk6IDAuNDsKICAgICAgICAiPjwvY2FudmFzPmApOwogICAgCiAgICBfYyA9IFdvd1N1Y2hOYW1lCiAgICBfY3ggPSBfYy5nZXRDb250ZXh0KCcyZCcpOwoKICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdyZXNpemUnLCByZXNpemVDYW52YXMsIGZhbHNlKTsKCiAgICBmdW5jdGlvbiByZXNpemVDYW52YXMoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ3Jlc2l6ZScpOwogICAgICAgIF9jLndpZHRoID0gd2luZG93LmlubmVyV2lkdGg7CiAgICB9CiAgICByZXNpemVDYW52YXMoKTsKfQoKLy8vIGJ1ZmZlciB2aWV3ZXIgbG9vcCAodXBkYXRlcyBhYm91dCBldmVyeSAybmQgZnJhbWUpCmZ1bmN0aW9uIGxvb3AoKSB7CiAgICBpZiAoIXdpbmRvdy5Xb3dTdWNoTmFtZSkgeyBwcmVwYXJlKCk7IH0KCiAgICB2YXIgYiA9IF92LmJ1ZmZlcmVkLCAgLy8vIGdldCBidWZmZXIgb2JqZWN0CiAgICAgICAgaSA9IGIubGVuZ3RoLCAgICAgLy8vIGNvdW50ZXIgZm9yIGxvb3AKICAgICAgICB3ID0gX2Mud2lkdGgsICAgICAvLy8gY2FjaGUgY2FudmFzIHdpZHRoIGFuZCBoZWlnaHQKICAgICAgICBoID0gX2MuaGVpZ2h0LAogICAgICAgIHZsID0gX3YuZHVyYXRpb24sIC8vLyB0b3RhbCB2aWRlbyBkdXJhdGlvbiBpbiBzZWNvbmRzCiAgICAgICAgeDEsIHgyOyAgICAgICAgICAgLy8vIGJ1ZmZlciBzZWdtZW50IG1hcmsgcG9zaXRpb25zCgogICAgLy8vIGNsZWFyIGNhbnZhcwovLyAgICAgX2N4LmZpbGxTdHlsZSA9ICcjMDAwJzsKLy8gICAgIF9jeC5maWxsUmVjdCgwLCAwLCB3LCBoKTsKICAgIF9jeC5jbGVhclJlY3QoMCwgMCwgdywgaCk7CgogICAgLy8vIGNvbG9yIGZvciBsb2FkZWQgYnVmZmVyKHMpCiAgICBfY3guZmlsbFN0eWxlID0gJyM4ODgnOwoKICAgIC8vLyBpdGVyYXRlIHRocm91Z2ggYnVmZmVycwogICAgd2hpbGUgKGktLSkgewogICAgICAgIHgxID0gYi5zdGFydChpKSAvIHZsICogdzsKICAgICAgICB4MiA9IGIuZW5kKGkpIC8gdmwgKiB3OwogICAgICAgIF9jeC5maWxsUmVjdCh4MSwgMCwgeDIgLSB4MSwgaCk7CiAgICB9CgogICAgLy8vIGRyYXcgY3Vyc29yIGZvciBwb3NpdGlvbgogICAgX2N4LmZpbGxTdHlsZSA9ICcjZmZmJzsKICAgIHgxID0gX3YuY3VycmVudFRpbWUgLyB2bCAqIHc7CiAgICBfY3guZmlsbFJlY3QoeDEtMSwgMCwgMiwgaCk7CgogICAgc2V0VGltZW91dChsb29wLCAyOSk7Cn0KCmxvb3AoKTsK"))