Html HTML5 视频缓冲属性特性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18422517/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
HTML5 Video buffered attribute features
提问by SexyBeast
I am designing a custom HTML5
video player. Thus, it will have its own custom slider to mimic the video progress, so I need to understand the entire buffering shebang of a HTML5
video.
我正在设计一个自定义HTML5
视频播放器。因此,它将有自己的自定义滑块来模拟视频进度,因此我需要了解HTML5
视频的整个缓冲过程。
I came across this article: Video Buffering. It says that the buffered object consists of several time ranges in linear order of start time. But I couldn't find out the following:
我遇到了这篇文章:视频缓冲。它表示缓冲对象由几个时间范围按开始时间的线性顺序组成。但我找不到以下内容:
Say the video starts. It continues upto 1:45 on its own (occasionally stalling perhaps, waiting for further data), after which I suddenly jump to 32:45. Now after some time, if I jump back to 1:27 (within the time range initially loaded and played through, before I made the jump), will it start playing immediately as it was already loaded before? Or is it that since I made a jump, that portion is lost and will have to be fetched again? Either way, is the behavior consistent for all such scenarios?
Say I make 5 or 6 such jumps, each time waiting for a few seconds for some data to load after the jump. Does that mean the
buffered
object will have all those time ranges stored? Or might some get lost? Is it a stack kind of thing, where the earlier ranges will get popped off as more ranges get loaded due to further jumps?Will checking whether the
buffered
object has one time range starting at 0 (forget live streaming) and ending at the video duration length ensure that the entire video resource has been loaded fully? If not, is there some way to know that the entire video has been downloaded, and any portion is seekable, from which video can play continuously upto end without a moment's delay?
说视频开始。它自己持续到 1:45(可能偶尔会停顿,等待进一步的数据),之后我突然跳到 32:45。现在过了一段时间,如果我跳回到 1:27(在我开始跳转之前最初加载和播放的时间范围内),它会不会因为之前已经加载而立即开始播放?或者是因为我做了一个跳跃,那部分丢失了,必须再次获取?无论哪种方式,所有这些场景的行为是否一致?
假设我进行了 5 或 6 次这样的跳转,每次都等待几秒钟以在跳转后加载一些数据。这是否意味着该
buffered
对象将存储所有这些时间范围?或者可能有些人迷路了?它是一种堆栈类型的东西,当更多的范围由于进一步的跳跃而加载时,较早的范围会被弹出吗?检查
buffered
对象是否有一个从 0 开始(忘记直播)到视频时长结束的时间范围是否确保整个视频资源已完全加载?如果没有,有没有办法知道整个视频已经下载,任何部分都是可搜索的,从哪个视频可以连续播放到结束而没有片刻延迟?
The W3C specs are not very clear on this, and I also can't find a suitably large (say more than an hour) remote video resource to test.
W3C 规范对此不是很清楚,我也找不到合适的大(比如一个多小时)远程视频资源来测试。
回答by
How video is buffered is browser implementation-dependent and therefore may vary from browser to browser.
视频的缓冲方式取决于浏览器的实现,因此可能因浏览器而异。
Various browsers can use different factors to determine to keep or to discard a part of the buffer. Old segments, disk space, memory, and performance are typical factors.
各种浏览器可以使用不同的因素来确定保留或丢弃缓冲区的一部分。旧段、磁盘空间、内存和性能是典型的因素。
The only way to know is to "see" what the browser has or is loading.
知道的唯一方法是“查看”浏览器已加载或正在加载的内容。
For example - in Chrome I played a few seconds then I skipped to about 30 seconds and you can see that it starts to load another part starting from that position.
例如 - 在 Chrome 中我玩了几秒钟然后我跳到大约 30 秒,你可以看到它从那个位置开始加载另一个部分。
(The buffer also seem to be bounded to key-frames so it is possible to decode the n-frames in that buffer. This means the buffer can start to load data a little before the actual position).
(缓冲区似乎也受关键帧的限制,因此可以对该缓冲区中的 n 帧进行解码。这意味着缓冲区可以在实际位置之前开始加载数据)。
I supplied a demo video about 1 minute long - however, this is not long enough to do proper testing. Free free to supply video links that contain longer video (or please share if you want me to update the demo with this).
我提供了一个大约 1 分钟长的演示视频 - 但是,这不足以进行适当的测试。免费提供包含更长视频的视频链接(或者,如果您希望我使用此更新演示,请分享)。
The main function will iterate through the buffered
object on the video element. It will render all parts that exist to the canvas right below the video showing in red.
main 函数将遍历buffered
视频元素上的对象。它将渲染存在于画布上以红色显示的视频正下方的所有部分。
You can click (bit not drag) on this viewer to move the video to different positions.
您可以在此查看器上单击(不拖动)以将视频移动到不同位置。
/// 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);
}
回答by Cobra_Fast
According to
根据
- https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video
- https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges
- https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges.start
- https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video
- https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges
- https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges.start
the buffered
attribute holds information about all currently buffered time ranges. To my understanding, if a buffered portion is lost, it is removed from the object (in case that ever happens).
该buffered
属性保存有关所有当前缓冲时间范围的信息。据我了解,如果缓冲部分丢失,则会从对象中删除(以防万一)。
Esepcially the last link seems to be very useful for understanding the matter (since it offers a code sample) but keep in mind these are mozilla documents and support might be different in other browsers.
特别是最后一个链接似乎对理解问题非常有用(因为它提供了代码示例),但请记住,这些是 mozilla 文档,其他浏览器的支持可能会有所不同。
To answer your questions
回答您的问题
Say the video starts. It continues upto 1:45 on its own (occasionally stalling perhaps, waiting for further data), after which I suddenly jump to 32:45. Now after some time, if I jump back to 1:27 (within the time range initially loaded and played through, before I made the jump), will it start playing immediately as it was already loaded before?
说视频开始。它自己持续到 1:45(可能偶尔会停顿,等待进一步的数据),之后我突然跳到 32:45。现在过了一段时间,如果我跳回到 1:27(在我开始跳转之前最初加载和播放的时间范围内),它会不会因为之前已经加载而立即开始播放?
It shouldplay immediately when jumping back unless the buffer of that portion was unloaded. I think it's very reasonable to assume that buffers or buffer ranges are unloaded at some point if the overall buffersize exceeds a certain volume.
它应该在跳回时立即播放,除非该部分的缓冲区被卸载。我认为假设缓冲区或缓冲区范围在某个时间点卸载是非常合理的,如果整体缓冲区大小超过某个量。
Say I make 5 or 6 such jumps, each time waiting for a few seconds for some data to load after the jump. Does that mean the buffered object will have all those time ranges stored?
假设我进行了 5 或 6 次这样的跳转,每次都等待几秒钟以在跳转后加载一些数据。这是否意味着缓冲对象将存储所有这些时间范围?
Yes, all buffered ranges should be readable through the attribute.
是的,所有缓冲范围都应该可以通过属性读取。
Will checking whether the buffered object has one time range starting at 0 (forget live streaming) and ending at the video duration length ensure tht the entire video resource has been loaded fully?
检查缓冲对象是否有一个从 0 开始(忘记直播)并以视频持续时间长度结束的时间范围是否确保整个视频资源已完全加载?
Yes, this is the code example in the last link. Apparently this is an applicable method of determining if the entire video has been loaded.
是的,这是最后一个链接中的代码示例。显然,这是确定整个视频是否已加载的适用方法。
if (buf.start(0) == 0 && buf.end(0) == v.duration)
回答by Afzaal Ahmad Zeeshan
Almost every browser saves the buffered data in cache for that session. The cache expires after the user goes away from that page. I don't think that the user will have to load the page each time he loads the video from a point where the video has been loaded. The user will face this issue only when the server is clearing out all the cache data. HTML5 video tag will support this, and will save the video upto the point till where it has been loaded.
It doesnot mean that the session has been lost, it means that either the object (if you are using flash player) is looking for some data from that particular point or the html5 video tag is having some issues either because of the INTERNET connection failure, or some other server errors.
The metadata is automatically loaded, untill you use this
<audio preload="none"...
this will make the browser not to download anything from server, you can use it as:<audio preload="auto|metadata|none"...
If you use none, nothing is downloaded unless the user clicks play button, and metadata will download name, timing and other meta data from server, but not the file somehow, auto will start downloading as soon as the page loads.
几乎每个浏览器都将缓冲数据保存在该会话的缓存中。用户离开该页面后,缓存将过期。我不认为用户每次从视频加载点加载视频时都必须加载页面。只有当服务器清除所有缓存数据时,用户才会面临这个问题。HTML5 视频标签将支持此功能,并将视频保存到已加载的位置。
这并不意味着会话已丢失,这意味着对象(如果您使用的是 Flash 播放器)正在从该特定点查找一些数据,或者 html5 视频标签由于 INTERNET 连接失败而出现一些问题,或其他一些服务器错误。
元数据是自动加载的,直到你使用它
<audio preload="none"...
这将使浏览器不从服务器下载任何东西,你可以使用它:<audio preload="auto|metadata|none"...
如果你不使用,除非用户点击播放按钮,否则不会下载任何东西,元数据将下载名称,时间和来自服务器的其他元数据,但不是文件,自动将在页面加载后立即开始下载。
I will always refer you to read some documentations by jQuery. As the jQuery will let you change and update the content using ajax API and will be helpfull too. Hope you succeed! Cheers.
我会一直推荐你阅读 jQuery 的一些文档。因为 jQuery 将允许您使用 ajax API 更改和更新内容,并且也会有所帮助。希望你成功!干杯。
回答by Jamie Birch
Although the accepted answer's description is excellent, I decided to update its code sample, for several reasons:
尽管接受的答案的描述非常好,但我决定更新其代码示例,原因如下:
- The progress render task should really be fired only on a
progress
event. - The progress render task is mixed up with some other tasks like drawing the timestamp and the playhead position.
- The code refers to several DOM elements by their IDs without using
document.getElementById()
. - The variable names were all obscured.
- I thought a forward
for()
loop was more elegant than a backwardwhile()
loop.
- 进度渲染任务应该只在
progress
事件上触发。 - 进度渲染任务与其他一些任务混合在一起,例如绘制时间戳和播放头位置。
- 代码通过 ID 引用多个 DOM 元素,而不使用
document.getElementById()
. - 变量名都被掩盖了。
- 我认为前向
for()
循环比后向while()
循环更优雅。
Note that I have removed the playhead and timestamp to keep the code clean, as this answer focusses purely on visualisation of the video buffer.
请注意,我已删除播放头和时间戳以保持代码清洁,因为此答案仅关注视频缓冲区的可视化。
LINK TO ONLINE VIDEO BUFFER VISUALISER
Rewrite of accepted answer's loop()
function:
重写已接受答案的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);
}
}
回答by Qwerty
This is just a variation of this excellent answer https://stackoverflow.com/a/18624833/985454
这只是这个优秀答案的变体https://stackoverflow.com/a/18624833/985454
I only made it work without any work required and added few perks. Everything is automatic.
我只是让它在不需要任何工作的情况下工作,并增加了一些额外的好处。一切都是自动的。
- currently intended for full-screen video playback such as netflix or hbogo
- automatically creates the canvas
- auto-updates width to 100% viewport width
- works as a bookmarklet
- does not obstruct the view much (transparent, 2px tall)
- 目前用于全屏视频播放,例如 netflix 或 hbogo
- 自动创建画布
- 自动更新宽度为 100% 视口宽度
- 作为书签工作
- 不会阻碍视线(透明,2px 高)
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();
And the code for bookmarklet is here
书签的代码在这里
javascript:eval(atob("CmZ1bmN0aW9uIHByZXBhcmUoKSB7CiAgICBjb25zb2xlLmxvZygncHJlcGFyZScpOwoKICAgIF92ID0gJCgndmlkZW8nKVswXTsKICAgIF92Lmluc2VydEFkamFjZW50SFRNTCgnYWZ0ZXJlbmQnLAogICAgYDxjYW52YXMKICAgICAgICBpZD0iV293U3VjaE5hbWUiCiAgICAgICAgaGVpZ2h0PSIxIgogICAgICAgIHN0eWxlPSIKICAgICAgICAgICAgcG9zaXRpb246IGFic29sdXRlOwogICAgICAgICAgICBib3R0b206IDA7CiAgICAgICAgICAgIGxlZnQ6IDA7CiAgICAgICAgICAgIG9wYWNpdHk6IDAuNDsKICAgICAgICAiPjwvY2FudmFzPmApOwogICAgCiAgICBfYyA9IFdvd1N1Y2hOYW1lCiAgICBfY3ggPSBfYy5nZXRDb250ZXh0KCcyZCcpOwoKICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdyZXNpemUnLCByZXNpemVDYW52YXMsIGZhbHNlKTsKCiAgICBmdW5jdGlvbiByZXNpemVDYW52YXMoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ3Jlc2l6ZScpOwogICAgICAgIF9jLndpZHRoID0gd2luZG93LmlubmVyV2lkdGg7CiAgICB9CiAgICByZXNpemVDYW52YXMoKTsKfQoKLy8vIGJ1ZmZlciB2aWV3ZXIgbG9vcCAodXBkYXRlcyBhYm91dCBldmVyeSAybmQgZnJhbWUpCmZ1bmN0aW9uIGxvb3AoKSB7CiAgICBpZiAoIXdpbmRvdy5Xb3dTdWNoTmFtZSkgeyBwcmVwYXJlKCk7IH0KCiAgICB2YXIgYiA9IF92LmJ1ZmZlcmVkLCAgLy8vIGdldCBidWZmZXIgb2JqZWN0CiAgICAgICAgaSA9IGIubGVuZ3RoLCAgICAgLy8vIGNvdW50ZXIgZm9yIGxvb3AKICAgICAgICB3ID0gX2Mud2lkdGgsICAgICAvLy8gY2FjaGUgY2FudmFzIHdpZHRoIGFuZCBoZWlnaHQKICAgICAgICBoID0gX2MuaGVpZ2h0LAogICAgICAgIHZsID0gX3YuZHVyYXRpb24sIC8vLyB0b3RhbCB2aWRlbyBkdXJhdGlvbiBpbiBzZWNvbmRzCiAgICAgICAgeDEsIHgyOyAgICAgICAgICAgLy8vIGJ1ZmZlciBzZWdtZW50IG1hcmsgcG9zaXRpb25zCgogICAgLy8vIGNsZWFyIGNhbnZhcwovLyAgICAgX2N4LmZpbGxTdHlsZSA9ICcjMDAwJzsKLy8gICAgIF9jeC5maWxsUmVjdCgwLCAwLCB3LCBoKTsKICAgIF9jeC5jbGVhclJlY3QoMCwgMCwgdywgaCk7CgogICAgLy8vIGNvbG9yIGZvciBsb2FkZWQgYnVmZmVyKHMpCiAgICBfY3guZmlsbFN0eWxlID0gJyM4ODgnOwoKICAgIC8vLyBpdGVyYXRlIHRocm91Z2ggYnVmZmVycwogICAgd2hpbGUgKGktLSkgewogICAgICAgIHgxID0gYi5zdGFydChpKSAvIHZsICogdzsKICAgICAgICB4MiA9IGIuZW5kKGkpIC8gdmwgKiB3OwogICAgICAgIF9jeC5maWxsUmVjdCh4MSwgMCwgeDIgLSB4MSwgaCk7CiAgICB9CgogICAgLy8vIGRyYXcgY3Vyc29yIGZvciBwb3NpdGlvbgogICAgX2N4LmZpbGxTdHlsZSA9ICcjZmZmJzsKICAgIHgxID0gX3YuY3VycmVudFRpbWUgLyB2bCAqIHc7CiAgICBfY3guZmlsbFJlY3QoeDEtMSwgMCwgMiwgaCk7CgogICAgc2V0VGltZW91dChsb29wLCAyOSk7Cn0KCmxvb3AoKTsK"))