我正在将一系列视频提取到一个Surface阵列,重新排列成一个新视频,随时间交换x维。以下是一些不同类型的效果示例:http://www.youtube.com/view_play_list?p=B2540182DE868E85
当我尝试将1280帧1280x720视频(1,179,648,000像素)存储到std::bad_alloc
时,应用始终与Surface[]
崩溃。它不会因1280帧1080x720视频(995,328,000像素)而崩溃。
我做了一个简单的测试,它可以在我的电脑上运行(4GB RAM),但不能在朋友的懦弱笔记本电脑上运行:
maxWidth = 1920;
while ((inW * inH * maxWidth) >= 1000000000)
maxWidth -= 20;
两个问题:
maxWidth
时对其进行测试并避免使用?非常感谢C ++ noob。我将来源放在Github: Redimensionator上。它使用Cinder。
答案 0 :(得分:2)
嗯,这取决于您的硬件/操作系统/软件/编译器。
是的,每个问题的后半部分都使您更容易使用大型数组。
答案 1 :(得分:1)
你试图存储10亿像素,每个像素有一个24位的颜色?假设你有1GB的可用内存,你就可以使用256色的调色板并且每个字节存储一个像素。
尝试将其存储在连续的内存中更有可能失败。如果你使用std :: deque,你就有更多的机会将大量的内容装入内存。
顺便说一句,即使你的系统有RAM,你的地址空间也有限。
假设256种颜色是不够的,你可以选择65536种颜色,这将使用2个字节的像素,但这需要2GB。 64位地址空间可以帮到你。完整的24位颜色需要至少3GB,更有可能使用4GB进行正确对齐。
从长远来看,如果你想要高分辨率,你可能不希望将它全部存储在内存中。
答案 2 :(得分:1)
首先,在32位平台上,您对地址空间使用的硬限制将大约为2GB(但可能更低) - 假设您将其全部映射到一次。最好假设在连续内存中不能超过512MB,在非连续内存中不能超过1-1.5GB(即通过制作多个小映射)。这很可能是你遇到的问题;你用完了连续的地址空间。对于32位系统,硬件又限制在(对于intel CPU)大约16GB的内存。你真的,真的不想交换。所以这意味着您有以下几种选择之一:
shm_open
和mmap
。 (复杂,几乎和64位一样快,如果做得好的话。最小化你做的重映射次数。还需要大量内存)如果您有足够的内存来容纳整个输出视频,前两个选项都很好。理想情况下,你想要64位路线;重新映射共享内存窗口是一项昂贵的操作,你将会做很多事情。
使用第四个选项,可能很难知道内存限制是什么。我建议使用测试分配进行二进制搜索,以确定您可以使用的地址空间中有多少空间(您应该使用低级分配调用来避免堆开销,请注意)。请注意,如果您不小心这可能不会为视频解码器留下任何地址空间 - 最好从结果中减去100mb左右,并重新分配它以为正常堆提供一些空间。你也应该小心保持低于总物理内存,以避免触及交换。
在不了解您的操作系统以及您从Surface
课程中获得的库的情况下,很难更具体地了解如何进行探测 - 但您确实应该避免将其保留在正常堆中,以避免其他代码中的分配错误,可能没有检测到处理OOM。
作为旁注,您可能希望在准备输出帧时将其旋转90度(即将它们放入column major order)。然后,您可以在构建所有原始图像后(或者甚至在从原始图像数据编码为压缩格式时)将它们作为最终传递回旋转。如果您决定使用带有SSD的磁盘路径,这一点尤其重要 - 它将有助于避免不必要的读取和写入,就像行主要顺序(视频的常规顺序)一样,您必须跳过其他列的像素你写一个。但是,对于内存工作,它仍然有用,因为它可以改善缓存局部性。
答案 3 :(得分:1)
为什么不一次为一帧分配存储,直到操作系统无法分配内存为止?这样,您不需要打扰32位与64位或共享内存。唯一的价格是额外的间接。
关键是,确实没有一个好的,独立于平台的方法来确定操作系统可以给你的最大块的大小(这取决于很多因素......虚拟地址空间碎片,数量物理内存可用(包括交换空间),配额)。