Загрузка большого количества данных изображения (10 ^ 9 пикселей) в память - PullRequest
1 голос
/ 08 марта 2011

Я извлекаю кадры видео в массив Surface, чтобы преобразовать его в новое видео, торгуя измерением x со временем.Вот несколько примеров различных видов эффектов, которые получаются: http://www.youtube.com/view_play_list?p=B2540182DE868E85

Приложение всегда падает с std::bad_alloc, когда я пытаюсь сохранить 1280 кадров видео 1280x720 (1 179 648 000 пикселей) в Surface[].Он не падает с 1280 кадрами видео 1080x720 (995,328,000 пикселей).

Я сделал простой тест, который заставляет его работать на моем компьютере (4 ГБ ОЗУ), но не на более слабом ноутбуке друга:

maxWidth = 1920;
while ((inW * inH * maxWidth) >= 1000000000)
  maxWidth -= 20;

Два вопроса:

  1. Есть ли лучший способ иметь быстрый доступ к 10 ^ 9 пикселям, чем массив Surface?
  2. Что это за предел памяти, и как я могу его проверить и избежать при настройке maxWidth для вывода?

Большое спасибо от нуба C ++.Я поставил источник на Github: Redimensionator .Использует Cinder.

Ответы [ 4 ]

2 голосов
/ 08 марта 2011

Ну, это зависит от вашего оборудования / ОС / программного обеспечения / компилятора.

  • Работаете ли вы на 32-битной или 64-битной ОС?
  • Скомпилируете ли вы ваше приложение в 32-битную или 64-битную версию?
  • Вы распределяете все сразу или по частям (скажем, каждый кадр отдельно)?
  • Вам действительно нужны все изображения в памяти одновременно или вы можете разделить свою работу?

Да, в последней части каждого вопроса вам будет проще использовать большой массив.

1 голос
/ 08 марта 2011

Почему бы не выделить память для одного кадра за раз, пока ОС не сможет выделить память? Таким образом, вам не нужно беспокоиться о 32 или 64 бит или общей памяти. Единственная цена - это дополнительное косвенное обращение.

Дело в том, что на самом деле не существует хорошего и независимого от платформы способа определения размера самого большого блока, который может предоставить операционная система (зависит от множества факторов ... фрагментация виртуального адресного пространства, количество доступной физической памяти (включая пространство подкачки), квота).

1 голос
/ 08 марта 2011

Во-первых, на 32-битной платформе ваш жесткий лимит использования адресного пространства будет где-то около 2 ГБ (но, возможно, намного меньше) - при условии, что вы сохраняете все это за раз. Лучше предположить, что вы не сможете получить больше, чем, может быть, 512 МБ в непрерывной памяти и 1-1,5 ГБ или около того в несмежной памяти (т. Е. Делая несколько небольших сопоставлений). Скорее всего, это ваша проблема; вы исчерпали смежное адресное пространство. Аппаратное обеспечение в свою очередь ограничено (для процессоров Intel) где-то около 16 ГБ памяти для 32-битной системы. И вы действительно действительно не хотите обмениваться. Таким образом, это означает, что у вас есть один из нескольких вариантов:

  • Используйте 64-битную систему и действительно большой массив (простой и быстрый, требует много памяти).
  • Используйте 32-битную систему и взломайте, чтобы обойти ограничения адресного пространства. Это означает, что вам нужно создавать объекты общей памяти и отображать только часть пространства за раз. В Windows вы можете использовать для этого анонимный объект сопоставления файлов - в основном это разделяемая память с пустым именем. В Linux вам нужно сначала увеличить максимальный размер / dev / shm, затем использовать shm_open и mmap. (сложный, почти такой же быстрый, как 64-битный, если все сделано правильно. Минимизируйте количество повторных отображений, которые вы делаете. Все еще требуется много памяти)
  • Использовать файлы на диске. Только реальная опция с SSD ; на реальном диске поиск займет слишком много времени, чтобы быть практичным. По сути, вы просто будете искать по файлу и записывать столбцы данных за раз. (Относительно медленно, но не слишком сложно. Требуется SSD. Минимальные требования к памяти)
  • Сделайте несколько проходов. Вы можете выбрать группу выходных кадров для хранения в памяти одновременно; декодируйте все видео, пропуская части, которые соответствуют кадрам, которые вы еще не храните в памяти. Как только вы закончите текущий набор кадров, запишите их на диск и начните заново, расшифровывая видео с нуля, с новым набором выходных кадров. Это хорошо подходит для массового параллелизма - вы можете отключить каждый выходной набор на другом отдельном компьютере для выполнения работы, а затем соединить их все вместе в конце. (умеренно сложный; медленный; меняет процессорное время на память. Может быть очень быстрым, если распараллелен).

Первые два варианта хороши, если у вас достаточно памяти для хранения всего выходного видео. В идеале вы хотите пойти по 64-битному маршруту; переназначение окон совместно используемой памяти - дорогостоящая операция, и вы будете много заниматься этим.

С четвертым вариантом может быть сложно узнать, каков предел памяти. Я бы порекомендовал выполнить бинарный поиск с использованием тестовых выделений, чтобы выяснить, сколько места в вашем адресном пространстве вы можете использовать (вы должны использовать низкоуровневые вызовы выделения, чтобы избежать накладных расходов кучи, обратите внимание). Обратите внимание, что если вы не будете осторожны, это может не оставить адресного пространства для вашего видеодекодера - вероятно, было бы лучше вычесть или около того 100 МБ из результата и перераспределить его, чтобы освободить место для нормальной кучи. Вы также должны быть осторожны, чтобы не превышать общую физическую память, чтобы избежать попадания в своп.

Не зная вашей ОС и из какой библиотеки вы получаете этот класс Surface, трудно быть более точным в отношении того, как его проверять, но вам действительно следует избегать сохранения его в обычной куче, просто чтобы избежать ошибок выделения. в другом коде, который, возможно, не приспособлен для работы с OOM.

В качестве примечания вы можете повернуть выходные кадры на 90 градусов при их подготовке (то есть поместить их в основной порядок столбцов ). Затем вы можете повернуть их обратно в качестве последнего прохода после создания всех необработанных изображений (или даже при кодировании из необработанных данных изображений в сжатый формат). Это особенно важно, если вы решите использовать дисковый маршрут с SSD - это поможет избежать ненужных операций чтения и записи, так как в случае основного порядка строк (обычный порядок для видео) вам придется пропустить пиксели для других столбцов всякий раз, когда ты пишешь один. Однако при работе в оперативной памяти это все еще полезно, поскольку улучшает локальность кэша.

1 голос
/ 08 марта 2011

Вы пытаетесь сохранить 1 миллиард пикселей, и каждый пиксель имеет цвет 24 бита? Предполагая, что у вас есть 1 ГБ доступной памяти, вы сможете использовать 256-цветовую палитру и хранить один пиксель за байт.

Попытка сохранить его в непрерывной памяти с большей вероятностью потерпит неудачу. Если вы используете std :: deque, у вас больше шансов разместить большое количество в памяти.

Кстати, у вас ограниченное адресное пространство, даже если в вашей системе имеется ОЗУ.

Предполагая, что 256 цветов недостаточно, вы можете выбрать 65536 цветов, которые будут использовать 2 байта на пиксель, но для этого потребуется 2 ГБ. Здесь вам поможет 64-битное адресное пространство. Для полного 24-битного цвета потребуется не менее 3 ГБ, и более вероятно, что для правильного выравнивания вы будете использовать 4 ГБ.

В долгосрочной перспективе вы, вероятно, не захотите хранить все это в памяти, если хотите высокое разрешение.

...