YouTube的HTML5视频播放器如何控制缓冲?

52

我在观看YouTube视频时,决定调查其视频播放器的某些部分。我注意到与我见过的大多数HTML5视频不同,Youtube的视频播放器没有使用普通的视频源,而是将blob url作为源。

以前,我测试过HTML5视频,并发现服务器从开始就开始流式传输整个视频,并在后台缓冲完整的视频。这意味着如果您的视频大小为300兆字节,那么就会下载全部300兆字节。如果您跳转到中间,它将从跳转位置开始下载直到末尾。

Youtube不以这种方式工作(至少在Chrome浏览器中)。相反,它设法控制缓冲,因此仅在暂停时缓存一定数量。它还似乎只缓存相关片段,因此如果您跳来跳去,它会确保不缓存不太可能被观看的片段。

在我试图调查它是如何工作的时候,我注意到视频src标签的值为blob:http%3A//www.youtube.com/ee625eee-2802-49b2-a13f-eb374d551d54,这将我带到了blobs,然后又引导我到typed arrays。使用这两个资源,我能够将mp4视频加载到blob中,并在HTML5视频标签中显示它。

然而,我现在遇到的问题是Youtube如何处理这些片段。查看网络流量,它似乎会向http://r6---sn-p5q7ynee.c.youtube.com/videoplayback发送请求,并以1.1MB为单位返回二进制视频数据的块。值得注意的是,由于HTML5视频请求,大多数正常请求似乎会在流式传输时收到206响应代码,而Youtube的playvideo调用则会得到200响应代码。

我试图通过设置Range http头信息,仅加载字节范围,但遗憾的是失败了(我猜测是因为视频没有附带元数据)。

目前我卡在如何解决这个问题上。我想到了几个方法,但都存在一些问题并无法完全解决:

1)Youtube会在每个/videoplayback请求中发送自包含的音频和视频块。这看起来对上传端的负担很重,并且似乎很难将它们拼接在一起使其看起来像一个无缝的视频。此外,从调用$('video').duration$('video').currentTime来看,视频标签也认为它是一个完整的视频。最后,视频src标签从未更改,这使我相信它正在使用单个blob而不是切换blob。

2)Youtube构建一个预先设置为完整视频数组大小的空blob,并在下载过程中更新blob的片段。然后,它会确保用户没有接近最后一个下载的部分(以防止用户进入未下载的blob部分)。我认为这个方法的问题在于我没有看到任何通过javascript动态更新blob的方法(也许我只是在搜索时有些困难)

3)Youtube下载元数据,然后按顺序构建blob,随着下载它们将视频块附加到blob上。我认为这种方法的问题在于我不理解它如何处理已缓冲区域内的寻址。

也许我只是忽略了一个显而易见的答案。有没有人有任何想法?


编辑:我刚想到第四个选择。另一个想法是他们可能使用文件API将二进制块写入文件,并使用该文件进行流式传输。文件API似乎具有定位到特定位置的能力,因此允许您填充视频为空字节,并在接收到空字节时进行填充。这肯定也适合视频寻找。


我认为他们使用了MediaStream API,但是到目前为止,我懒得进行全面调查。请你调查一下并让我知道!=) - Rudie
MediaSource API不同... - Rudie
有趣的API,尽管它缺少一些必要的东西(比如启动方式),除非我读错了。无论如何,我已经不在之前从事这项研究的公司工作了,也不知道什么时候会回到这种类型的工作中 :) - KallDrexx
是的,也许你是对的,它可能不兼容。我没有完全调查。如果你也不会,我会把它留在TODO清单上。 - Rudie
@KallDrexx自帖子发布以来有什么新发现吗? - user1708860
4个回答

6
好的,您需要知道的是YouTube基于这个名为“Project”的伟大开源项目。它在每个浏览器上的行为都不同,如果您的浏览器支持更强的解码(如WEBM),它将使用该解码方法来节省谷歌的带宽。此外,如果您查看演示,则会发现一个部分将整个视频下载到名为“离线存储”的东西中。我知道Chrome有它,其他浏览器不一定都有,有时他们必须使用整个视频源而不是块。因此,具体情况根据用户与视频的交互而定。是的,视频只是一个文件,他们还为该视频提供了元数据,就像一个小型数据库,其中包含视频的时间和可以划分块的点。

您可以通过阅读该项目的文档来了解更多信息。我真的建议您查看演示。


5
当您查看GoogleChrome的AppData时,观看YouTube视频时,您会发现它以分段文件进行缓冲。上传到YouTube的视频是分段的,因此如果您在当前片段之外的第一次单击栏中的时间帧,则无法完全确定时间帧。
段数取决于视频的长度,以及您开始和停止播放视频的时间。
当您链接到视频的某个时间帧时,它将简单地跳过该时间帧之前的分段缓冲。
不幸的是,我不太了解视频播放的编码,但我希望这可以指引您朝着正确的方向前进。

2
有趣的是,我确实看到许多文件被添加到我的AppData\Local\Google\Chrome\User Data\Default\Cache目录中,并且从网络流量来看,这些1.1MB的文件是视频块。现在问题在于如何将它们拼接在一起。谢谢 :) - KallDrexx

4
页面中有一个canvas元素,这可能会有所帮助:http://html5doctor.com/video-canvas-magic/
我们知道视频已被分段,问题在于如何将它们拼接起来。我认为真正的视频元素并不处理播放工作,它支持数据源,并将每一帧的段绘制到canvas元素上。
var v = document.getElementById('v'); 
var canvas = document.getElementById('c');
v.addEventListener('play', function(){ 
   if(v.paused || v.ended) return false; 
   c.drawImage(v,0,0,w,h); 
   setTimeout(draw,20,v,c,w,h); 
},false);


请进一步解释您的答案(也许可以添加一些来自您提供的链接的信息)。仅提供链接的答案是不被鼓励的。 - soktinpk
抱歉,我的英语很差。我们知道视频已经被分段了,问题是如何将它们拼接在一起。我认为真正的视频元素并不执行播放工作,它支持数据源,并将每个帧的片段绘制到画布元素上... - vetch

3

Youtube仅在支持媒体源扩展的浏览器中使用此功能,因此由于此功能,其余所有方面都取决于浏览器。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接