如何有效地实现Youtube的缩略图预览功能?

时间:2016-05-16 14:03:19

标签: performance http thumbnails processing-efficiency video-thumbnails

我正在尝试为我的简单视频播放器实现Youtube的缩略图预览功能。这就是Snap for it:

enter image description here  

好事:一旦播放器从HTTP服务器获取所有缩略图预览,它就能顺利运行。

不好的事情:获取所有缩略图预览需要花费大量时间(20-30秒)。 (对于14分钟(~110 MB)的视频(.mp4文件),大约有550个缩略图预览(160x120)在那里)

我正在做的是:当用户开始播放视频时,我会制作" total_thumbnails"向服务器发出HTTP请求以获取所有这些内容。

  

另请注意

     
      
  1. 我将在异步任务中执行多个HTTP请求。
  2.   
  3. 我不会这样做,提出请求,等到下载   完成然后再提出要求。
  4.   
  5. 我将制作" total_thumbnails" HTTP请求盲目,所以请求得到   在管道中排队,然后并行接收响应。
  6.   

额外详细信息:HTTP(lighttpd)服务器将运行,用户从列表中选择要播放的video.mp4后,我的播放器将从该处获取所有缩略图。此外,播放器将使用相同的服务器来使用HTTP流式传输来获取video.mp4。

问题:当我开始播放视频,然后我快速搜索时,我最终看到了这一点(白色缩略图是默认的,当缩略图映射到那个时间时尚未从服务器获取):

enter image description here

问题:我可以多高效地获取所有(或部分)缩略图预览,以便用户(大部分时间)都能获得正确及时映射缩略图的体验?
<登记/> 我已经在视频开始时看到youtube的视频(这很快),播放器能够显示所有及时的正确缩略图(无论你将拇指拖到最后一分钟还是悬停在栏上&#39 ;最后几分钟,几乎每次你都会看到正确映射的缩略图)。

他们是同时下载所有缩略图还是下载压缩的缩略图预览系列或其他一些智能的东西在那里发生?

有没有人对此有所了解?

3 个答案:

答案 0 :(得分:2)

  1. 将多个缩略图分组为单个容器图像。使用canvas(我不是JS开发人员,但相信这是正确的词)在客户端分别提取每个缩略图。例如,here is example of such container image used by youtube。这适用于各种协议(例如,启用或不启用keep-alive)。
  2. 预处理缩略图以缩小其大小。尽可能降低jpeg的质量(~q = 70)。您也可以尝试模糊缩略图或减少颜色数量。
  3. 优化下载顺序。例如,如果您的视频长度为2:55:
    1. 首先,用8个大拇指下载容器图像,覆盖整个视频时间范围:0:00,0:25,0:50,1:15,1:40,2:05,2:30,2:55。这使您的服务对于慢速客户端显示为“立即工作”。
    2. 接下来,下载4个容器图像,总共32个大拇指,覆盖全部视频,但更密集:0:00,0:06,0:11,0:17,...
    3. 现在,逐步下载所有其他缩略图,没有任何特定顺序。

答案 1 :(得分:1)

  

对于14分钟(~110 MB)的视频(.mp4文件),大约有550个缩略图预览(160x120)

这里的主要因素可能是您向HTTP服务器发出了550个单独的请求。我假设您这样做:请求缩略图 k ,等待它下载,然后请求缩略图 k +1。这是非常低效的,因为HTTP服务器处于空闲状态,而正在下载缩略图 k 并且正在上传下一个请求。

解决方案1 ​​

将所有550个缩略图合并为一个大文件,并请求而不是550个单独的文件。

也许有一个很好的现有文件格式,您可以为此目的重复使用。 Tar浮现在脑海中,但它可能是一个糟糕的选择,因为(1)它似乎不支持随机访问(即直接获取 k 缩略图),以及(2)它为每个缩略图增加了512字节的开销。

无论如何,应该很容易想出自己的文件格式。像这样:

  • 前4个字节给出 n ,这是文件中缩略图的数量;
  • 下一个4× n 字节给出每个缩略图相对于文件开头的偏移量;
  • 之后,只是缩略图本身,端到端拼接。

解决方案2

使用HTTP pipelining - HTTP / 1.1的一项功能,您可以同时发送许多请求(可能全部为550),然后一次读取多个响应。在请求下一个缩略图之前,您不必等待每个缩略图下载。

您需要两件事才能实现。

首先,您的HTTP客户端必须支持HTTP流水线操作。我不知道你的平台上有什么最先进的技术,但在Python领域,这是一个罕见的功能。一个似乎支持它的客户是libcurl(通过CURLMOPT_PIPELININGCURLMOPT_MAX_PIPELINE_LENGTH)。 libcurl适用于大多数平台,并且具有大多数语言的绑定。

其次,您可能需要更改Lighttpd配置。默认情况下,server.max-keep-alive-requests变量设置为16,这意味着服务器在处理完17个请求后将关闭连接,您必须建立一个新连接。你可能希望这个数字更大。

在客户端和服务器上管道化大量请求可能(或可能不)具有不良副作用,例如意外的内存使用。请自己测试。

此外,如果客户端和服务器之间存在任何HTTP中介(如代理),则可能会破坏HTTP流水线。

测量

我跑了一些快速而肮脏的测试。 Lighttpd 1.4.31提供来自柏林的550张缩略图(总共4.2M)和server.max-keep-alive-requests = 600。客户在莫斯科。平均超过10点运行。

  • 简单方法(请求下载请求,使用Python的http.client):27.3 s。
  • 组合文件(使用Python的http.client):2.95 s。
  • 管道传输550个请求(没有真正的HTTP客户端,只是原始套接字):3.04 s。

答案 2 :(得分:0)

还有另一种解决方案可以使图像文件更大,但更容易在html页面上显示。正如其他人所说,你可以创建一个精灵表,但不是老式的方式。您可以将缩略图组合为逗号/冒号分隔的base64图像列表。

E.g。 {base64_encoded_image},{time},...,将其提取为图像/时间元组,然后显示它。 Html页面默认能够显示base64编码图像,因此客户端不需要进一步处理。

注意我必须提醒您,base64大约要大37%。 Gziped它可以比较,但Gziped二进制文件仍然会更小。由于base64每8位使用6位。二进制使用全8位。