我有一个视频文件,它由许多连续的二进制数据帧组成。每个帧还有一个唯一的时间戳(不是文件中的序号,而是摄像机在录制时提供的值)。另一方面,我有一个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 map
,key==timestamp
从该文件value==frame sequential number
创建。
有没有办法更有效地做到这一点?我应该创建我的索引文件作为一些数据结构的转储,所以它可以在打开剪辑时由剪辑播放器加载到内存中,所以我会有O(1)访问帧?你有其他建议吗?
UPD:
我更新了名称和要求(时间戳不一定是顺序的,帧数由MAX_UNSIGNED_SHORT值限制)。还要感谢所有已经花时间并给出答案的人。插值搜索是一个有趣的想法,虽然我自己从未尝试过。我想问题是运行时O(1)
和O(log log N)
之间的差异。
答案 0 :(得分:1)
似乎我们应该能够做出以下假设: a)视频文件本身在创建后不会被修改 b)播放器可能想要找到连续的帧,即它正在进行正常播放时 c)玩家可能想要找到随机帧,即当它正在执行FF,REW或跳过章节
时鉴于此,为什么不做一个关联帧ID和帧索引的HashMap?您可以创建一次,玩家可以阅读它,然后可以轻松,有时间地查找所请求的帧。
答案 1 :(得分:0)
这里有一系列的权衡取舍。
您的索引文件已经是数据结构的转储:数组。如果您不打算经常插入或删除帧,并按排序顺序保留此数组,则可以轻松地对阵列执行二进制搜索(使用std::binary_search
)。插入和删除采用O(N),但搜索仍为O(log N)。该数组将占用更少的内存空间,并且从索引文件中读取和写入的速度会更快。
如果您正在进行大量插入和删除帧,那么转换为std::map
结构将为您提供更好的性能。如果帧数很大,或者您希望使用它们存储更多元数据,则可能需要查看B-tree structure,或者只使用Sqlite或BerkeleyDB等嵌入式数据库。这两个都实现了B树索引,并且是经过良好测试的代码片段。
答案 2 :(得分:0)
只需将帧数据存储在索引表示帧编号的数组中。然后创建从摄像机索引到帧编号的哈希映射。您可以在O(1)中获取属于帧编号或摄像机索引的帧,而几乎不使用比当前方法更多的内存。
或者,您可以维护一个由帧编号索引的数组,该数组存储(摄像机索引,数据)对,并在您需要通过摄像机索引访问它时对其执行O(log n)二进制搜索。这利用了相机索引的排序这一事实。
在C ++的标准库中,哈希映射可用std::unordered_map
(如果编译器/ STL支持它们,可能不是这种情况,因为它们最近才被添加到C ++标准中),尽管树 - 基于std::map
(使用O(log n)查找)可能已经足够用于此目的。
二进制搜索实现可用std::binary_search
。