【问题标题】:How to efficiently implement Youtube's Thumbnail preview feature?如何高效实现 Youtube 的缩略图预览功能?
【发布时间】:2016-09-12 08:31:15
【问题描述】:

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



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

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

我正在做的是:当用户开始播放视频时,我将向服务器发出“total_thumbnails”HTTP 请求以获取所有视频。

另请注意

  1. 我将在异步任务中执行多个 HTTP 请求。
  2. 时尚不做,求个求,等下载 完成,然后提出另一个请求。
  3. 我会盲目地发出“total_thumbnails”HTTP请求,所以所有的请求都得到 在管道中排队,稍后并行接收响应。

额外细节:一个 HTTP (lighttpd) 服务器将运行,一旦用户从列表中选择要播放的 video.mp4,我的播放器就会从中获取所有缩略图。此外,播放器将使用同一服务器通过 HTTP 流获取 video.mp4。

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

问题是:我如何有效地获取所有(或部分)缩略图预览,以便用户(大部分时间)能够获得正确及时映射的缩略图的体验?

视频一开始我就看过youtube的视频(很快),播放器能够显示所有及时的右侧缩略图(无论您将拇指拖到最后一分钟还是将鼠标悬停在栏的最后一分钟,几乎每次您将看到正确映射的缩略图)。

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

有没有人解决过这个问题?

【问题讨论】:

  • 因此 14 分钟 á 60 秒和 550 个缩略图大约每 (14 * 60) / 550 ≈ 1.53 秒生成一个缩略图。是否将间隔时间延长到 5 秒?
  • 这里 1.53 秒(你计算出来的)是从播放器向服务器发出 http 请求直到我们收到请求的缩略图图像的时间。我们无法控制它,这里所用的时间将取决于 http 握手 +从服务器下载图像的时间。
  • 哦,好的。但问题仍然存在:你真的需要那么多缩略图吗?如果您仅每 120 (PAL) 或 150 (NTSC) 帧创建一个缩略图,您将大大减少数据量,不是吗?
  • 哦,我知道了。实际上,我们试过这个,问题是用户体验非常糟糕。差到什么程度?当用户完成搜索时,播放器将搜索到最近的前一个 I 帧,这可能与向用户显示的缩略图预览不对应(因为预览间隔 5 秒,而 I 帧间隔 1-1.5 秒)。当视频很短(最长 30 分钟)时,这种体验变得很重要。对于大型纪录片或电影,我觉得 5 秒或更长的时间间隔会起作用
  • 嗯,我明白了。那么,一个不固定的利率呢?毕竟,用户可以寻找的地方只有这么多。因此,如果您将视频中的帧数除以用户可以寻找的点数,那么无论实际视频长度如何,您最终都应该得到恒定数量的缩略图。话虽如此,我真的相信减少数据量是解决这里问题的关键。

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


【解决方案1】:

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

例如{base64_encoded_image},{time},...,将其提取到图像/时间的元组中,然后显示。默认情况下,Html 页面能够显示 base64 编码的图像,因此客户端不需要进一步处理。

注意我必须警告你,base64 将大约大 37%。 Gziped 它将具有可比性,但 Gziped 二进制文件仍然会更小。由于 base64 每 8 位使用 6 位。二进制使用所有 8 位。

【讨论】:

    【解决方案2】:
    1. 将多个缩略图组合成单个容器图像。使用画布(我不是 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. 现在,逐步下载所有其他缩略图,没有任何特定顺序。

    【讨论】:

    • 接下来我会尝试这种方法,我会发布它对我的效果的结果,仍然 youtube 速度和准确性是压倒性的,在 1-2 秒内你可以看到和感觉到正确的时间缩略图加载整个擦洗栏(悬停或拖动拇指,没关系)
    【解决方案3】:

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

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

    解决方案 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 个缩略图(总共 420 万个),server.max-keep-alive-requests = 600。客户在莫斯科。平均超过 10 次运行。

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

    【讨论】:

    • 至于解决方案 1 标签之前的 Para,请检查我的编辑 - 也 - 注意部分。根据您提出的解决方案-1,我们尝试过,瞧。!!,获取所有缩略图需要 3 秒,但问题是 tar 文件或任何其他用户定义的文件将在 6-7 MB 左右(更大视频,大小可以更大),以及我想要这个的平台,我们被限制发出不超过 64K 的响应大小的请求,所以对于 7 MB 我必须发出超过 ~110 个 HTTP 请求。跨度>
    • 我正在使用 HttpURLConnection 类来发出所有请求,它确实支持 HTTP 流水线,它仍然需要 20 秒左右,我认为我的 Lighttpd 的 server.max-keep-alive-requests 更少,而且不允许更改服务器配置。
    • @CoolToshi45 尝试使用sniffer 来检查流水线是否按预期进行:您没有等待每个响应,也没有在每个连接上流水线太多请求(每个流水线请求在max-keep-alive-requests + 1 被浪费之后)。
    • 解决方案 1 非常可靠。但是为什么要提出一种新的文件格式呢?只需创建一个巨大的图像并使用time * thumbnail_width 作为偏移量。哦,tar 确实支持随机搜索。毕竟它是为 tape archives 设计的。 压缩焦油 OTOH ...运气不好。
    • @DaSourcerer 我也同意解决方案 1,但问题是,在我最先进的技术中,此解决方案可能不起作用,因为服务器最多只能为一个请求发送 64K 字节。因此,要检索大小超过 64K 的数据,您需要发出两个或多个请求。所以也许我觉得可以安全地避开解决方案 1。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-07
    • 2020-01-30
    • 2011-12-19
    • 1970-01-01
    • 2011-11-04
    • 2012-03-12
    相关资源
    最近更新 更多