在SQLite数据库中存储视频?

3
我正在开发一种算法,它需要非常快速的随机访问视频帧,在可能很长的视频(最短30分钟)中。我目前正在使用OpenCV的VideoCapture读取我的视频,但查找功能要么不起作用,要么速度非常慢。到目前为止,我找到的最好方法是在MKV容器中使用MJPEG编解码器,但速度还不够快。
我可以选择任何视频格式,甚至创建一个新的视频格式。存储空间不是问题(当然有一定限制)。唯一的要求是获得尽可能快的时间来找到视频中的任何位置。理想情况下,我希望能同时访问多个帧,并利用我的四核CPU优势。
我知道关系数据库非常适合存储大量数据,它们允许同时读取访问,并且使用索引时非常快。
对于我的特定需求,SQLite是否适合?我打算将每个视频帧压缩为JPEG并在帧编号上使用索引以快速访问它们。
编辑:对我来说,一个“帧”仅是一个图像,而不是整个视频。以25fps播放的30分钟视频包含30 * 60 * 25 = 45000帧,我希望能够通过其编号快速获取其中之一。
编辑:对于那些可能有兴趣的人,我最终实现了一个自定义视频容器,将每个帧保存在固定大小的块中(因此,任何帧的位置都可以直接计算!)。图像使用turbojpeg库压缩,并且文件访问是多线程的(以便支持NCQ)。瓶颈不再是硬盘驱动器,并且我最终获得了更好的性能 :)

@Cicada:视频大小没有限制。目前我正在处理30分钟的VGA视频(MPEG格式500MB,MJPEG格式1.7GB),但是该程序也应该能够处理5小时的视频。你所说的“文件系统”是什么意思?我需要尽快处理像“获取第1530帧”的请求。使用数据库是一个建议,如果你有更好的想法,我很乐意听取! - Frédéric Terrazzoni
SQLite有一个内置的BLOB大小限制为1 GB(953 MiB),因此每个单独的帧的大小不能超过该限制。我的意思是,为什么不将帧直接存储为文件呢?数据库并不适合你所尝试做的事情。 - user703016
@Cicada:也许我用词不当(我不是英语母语者)。对我来说,一个框架就是一张图片,所以它不会大于1MB。一个25fps的30分钟视频包含306025 = 45000帧。一个5小时的视频需要450000个文件,我认为这不是一个好的解决方案。 - Frédéric Terrazzoni
2个回答

5
我认为使用SQLite(或任何其他数据库引擎)不是解决您问题的好方法。数据库不是文件系统。
如果您需要非常快速的随机访问,那么请坚持使用文件系统,它是专门为此类用途设计并进行了优化。根据您的评论,您说5小时的视频需要450k个文件,那么在我看来这不是问题。当然,目录列表可能会有点长,但您将获得绝对最快的随机访问。而且它肯定比SQLite更快,因为您只需要一层抽象。
如果您真的担心目录列表时间,您只需像树一样组织文件夹结构即可。这将带来更长的路径,但是快速的列表。

确实,目录列表会非常慢,但我不在意,因为我不需要列出那些文件。树形结构的建议听起来很有趣,但是使用450k个文件将使“视频文件”难以高效地复制(根据我的经验,复制一个大文件总是比复制许多小文件快得多)。感谢您的帮助。 - Frédéric Terrazzoni
再次强调,现代文件系统针对复制许多小文件进行了优化(特别是EXT4),您只需仔细选择工具即可。 - user703016
很不幸,我正在使用NTFS,我不知道它在处理小文件时的表现如何,但是通过我的经验,当我将成千上万个文件从我的USB存储器复制到计算机中或者反之时,速度非常慢。比如,比我复制高清电影时要慢得多。无论如何,我想我会听从你的建议,并将我的视频存储在基于目录树的结构中:这样做不可能比我现在使用的更慢。谢谢 :) - Frédéric Terrazzoni

1
保持高层次的视角。问题在于OpenCV在寻找源视频时不够快。这可能是因为:
  • 编解码器不是OpenCV的强项
  • 源视频没有编码以进行高效的查找
你的机器有很多专用的图形硬件可以利用,但它没有随机查找17 GB数据集的专门能力,无论是文件、数据库还是一组文件。磁盘每次查找需要几毫秒的时间。对于SSD来说会更好,但仍然不太理想。然后你要等待它加载到主内存中,并且你必须首先生成所有这些数据。
使用ffmpeg,它应该可以非常高效地处理解码,甚至可能使用GPU。这里有一个tutorial。(免责声明,我自己没有使用过。)

您可以预处理视频以添加关键帧。原则上,这不应该需要完全重新编码,至少对于MPEG而言是如此,但我不太了解具体情况。MJPEG基本上将所有帧转换为关键帧,但您可以找到一个折中的方法,也许以2倍的大小成本加速1.5倍。但要避免磁盘读写。


关于SQLite,它是解决在17GB数据中查找的好方法。认为数据库不适用于随机访问是无稽之谈。当然,它们是可以优化随机访问的。文件系统就是一种数据库。在17GB中进行随机访问之所以慢,是因为硬件问题,而不是软件问题。

我建议不要使用文件系统来完成这个任务,因为它是一个与机器的其余部分同步的共享资源。此外,创建50万个文件(并在完成后删除它们)需要很长时间。这不是文件系统专门设计的功能。您可以通过将多个图像存储到每个文件中来解决这个问题。但是,您需要某种格式来查找所需的图像,那么为什么不将它们全部放在一个文件中呢?

实际上,(如果选择17GB路线),为什么不忽略整个问题,将所有内容都放入虚拟内存中呢?虚拟内存在使磁盘寻道方面与SQLite或文件系统一样出色。只要操作系统知道进程可以使用那么多内存,并且您正在使用64位指针,它应该是一个很好的解决方案,也是首先尝试的事情。


很遗憾,我的应用程序有一些32位依赖项,因此我无法转移到64位,因此虚拟机解决方案不适用。当前寻找时间约为30毫秒。我希望SQLite和文件系统都能打败它,即使考虑到硬件限制(磁盘访问约为10毫秒,对吧?) - Frédéric Terrazzoni
你说得对,如果目的是播放视频,那么这并不是一个真正的 bug。实际上,在我开始开发应用程序时,我没有考虑到这个磁盘访问时间的问题。OpenCV 更多地是 ffmpeg 的封装,因此性能应该是相似的。但是,如果每次从磁盘读取图像都可以获得 8+2ms = 10ms(就像你说的那样),那将非常好(提高了 3 倍!)。JPEG 解压缩在这里不是问题,因为 CPU 不是瓶颈,并且可以在另一个线程中异步完成。 - Frédéric Terrazzoni
是的,流媒体存储在MKV容器中(AVI并不更好)。您认为如果我将每个图像连续存储到一个大文件中(对于每个图像使用固定大小,可以轻松计算任何帧的位置),它能否得到改进?这样,我可以避免文件系统膨胀,同时保持良好的性能,对吗? - Frédéric Terrazzoni
如果你能在不损失质量的情况下为每个图像设定一个固定大小,那听起来是合理的,但这仍然相当于重新发明了像avi或mkv这样的格式所保留的索引。也许你可以使用ffmpeg来构建一个更大的索引,这样它就可以更直接地跳转到所需位置了?另外,你是否通过分析器运行程序,以便更好地了解时间实际上花在哪里? - Potatoswatter
当opencv dll寻找另一帧时,时间会花费在其中。我没有细节。我想我会使用一个大文件,并将每个图像连续存储。每个图像都将被压缩为jpeg格式,并填充以使它们的大小相等(我不关心失去空间)。即使有一个大索引,ffmpeg也无法击败frame * frameSize的直接访问(不知道ffmpeg索引是如何构建的,但它不能比这更快!) - Frédéric Terrazzoni
显示剩余3条评论

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