【问题标题】:Finding the most efficient data structure to create an index file寻找最有效的数据结构来创建索引文件
【发布时间】:2013-03-07 15:50:10
【问题描述】:

我有一个视频文件,它由许多连续的二进制数据帧组成。每帧也有一个唯一的时间戳(不是它在文件中的序号,而是一个值,由相机在录制时提供)。另一方面,我有一个 API 函数,它根据该帧的序号检索该帧。让事情变得更复杂一些 - 我有一个玩家,它被提供了时间戳,并且应该获取该帧的二进制数据。

这里还有一件可悲的事情:时间戳不是连续的。它们可以是连续的,但不能保证,因为围绕最大无符号短大小可能会发生回绕。 所以一系列时间戳可以是 54567, 54568, ... , 65535, 65536 , ... 或
54567, 54568, ..., 65535, 0, 1, ...

所以它可能如下所示:

Frame 0
timestamp 54567
binary data
........
Frame 1
timestamp 54569
binary data
........
Frame 2
timestamp 54579
binary data
.
.
.
Frame n
timestamp m
binary data

0 <= n <= 65536 (MAX_UNSIGNED_SHORT)
0 <= m <= MAX_UNSIGNED_INT

剪辑播放器 API 应该能够通过时间戳获取二进制帧。但是,在内部,我只能通过帧序号来获取帧。因此,如果我被要求提供时间戳m,我需要遍历n 帧,以找到时间戳m 的帧。

为了优化它,我选择创建一个索引文件,它可以让我在时间戳和帧序号之间进行匹配。这是我的问题:

目前我的索引文件由大小为2*sizeof(unsigned int) 的二进制对组成,其中包含时间戳和帧序号。播放器稍后会从该文件 stl mapkey==timestampvalue==frame sequential number 创建。

有什么方法可以提高效率吗?我是否应该将索引文件创建为某些数据结构的转储,以便以后可以在打开剪辑时由剪辑播放器将其加载到内存中,这样我就可以 O(1) 访问帧?您还有其他建议吗?

更新:

我已经更新了名称和要求(时间戳不一定是连续的,并且帧数由 MAX_UNSIGNED_SHORT 值限制)。还要感谢所有已经抽出时间并给出答案的人。插值搜索是一个有趣的想法,尽管我自己从未尝试过。我想问题是运行时O(1)O(log log N) 之间的增量。

【问题讨论】:

  • 两者之间没有相关性(除了它们都在严格增加之外)?
  • 我猜“帧索引”是时间戳?不会严格影响您将获得的答案,但名称有点笨拙。您可能会在公开的Matroska specification 中找到一些有用的信息
  • “帧索引”可以被认为是一个“时间戳”。我同意这些不是选择的最佳名称:(

标签: c++ performance data-structures big-o video-capture


【解决方案1】:

看起来我们应该能够做出以下假设: a) 视频文件本身创建后不会被修改 b)播放器可能想要找到连续的帧,即当它进行正常播放时 c) 玩家可能想要找到随机帧,即当它正在执行 FF、REW 或跳过或跳过章节时

鉴于此,为什么不做一个 HashMap 关联 Frame Id 和 Frame Index 呢?您可以创建一次,玩家可以阅读它,然后可以对请求的帧进行简单且有时间限制的查找。

【讨论】:

  • 你的意思是std::unordered_map,而不是HashMap。不错的主意,不过,如果帧数很少,那么哈希函数可能会比搜索二叉树或排序数组花费更多。
  • 这是一个公平的观点,但帧数通常非常大(我曾经在摩托罗拉的视频点播组工作)。当然取决于您是播放 10-30 秒的广告还是 2 小时的电影 :-)
  • 我在图像分析方面的大部分工作都是处理 200 帧或更少帧的细胞电影(更长,信号通常会褪色)。可悲的是,几乎没有完美和通用的解决方案。 @JerryCoffin 建议的插值搜索对于这些特定数据似乎是个好主意。
  • 当前帧数不会超过65536
【解决方案2】:

这里需要进行一系列权衡。

您的索引文件已经是一个数据结构的转储:一个数组。如果你不打算经常插入或删除帧,并且保持这个数组是有序的,那么很容易对数组进行二分搜索(使用std::binary_search)。插入和删除需要 O(N),但查找仍然是 O(log N)。该数组将占用更少的内存空间,并且可以更快地从索引文件中读取和写入。

如果您要进行大量的插入和删除帧,那么转换为std::map 结构会给您带来更好的性能。如果帧的数量很大,或者你想用它们存储更多的元数据,你可能想看看B-tree structure,或者只是使用像SqliteBerkeleyDB这样的嵌入式数据库。这两个都实现了 B-tree 索引,并且都是经过良好测试的代码。

【讨论】:

    【解决方案3】:

    只需将帧数据存储在一个数组中,其中索引表示帧号。然后创建一个从相机索引到帧号的哈希映射。您可以在 O(1) 中获取属于帧号或相机索引的帧,而几乎不会使用比当前方法更多的内存。

    或者,您可以维护一个按帧编号索引的数组,该数组存储(相机索引,数据)对,并在您需要通过相机索引访问它时对其执行 O(log n) 二进制搜索。这利用了相机索引已排序这一事实。

    在 C++ 的标准库中,哈希映射以 std::unordered_map 的形式提供(如果您的编译器/STL 支持它们,可能不是这种情况,因为它们最近才被添加到 C++ 标准中),尽管基于树的 @ 987654322@(使用 O(log n) 查找)可能足以满足此目的。

    二分搜索实现可用作std::binary_search

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-02
      相关资源
      最近更新 更多