4.15. Кадрові буфери¶
Після ініціалізації датчика камери він безперервно випромінює кадри зі своєю частотою – один новий кадр за кожен період кадру незалежно від того, чи готова до цього програма. Кожному кадру потрібне місце в оперативній пам’яті або він буде втрачений. Пул кадрових буферів – це місце, де кадри зберігаються між виходом із DMA та обробкою кодом користувача, а кількість кадрових буферів у цьому пулі визначає, як DMA та програма ними обмінюються. Вибір здійснюється через framebuffers(), і доступні чотири режими, що вибираються за кількістю буферів.
4.15.1. Одинарний буфер (count = 1)¶
Один кадровий буфер у оперативній пам’яті. DMA заповнює його; програма зчитує з нього; наступний виклик snapshot() не може розпочатися, поки програма не звільнить буфер, адже той самий буфер потрібен для обох операцій.
Камера та програма працюють у крок. DMA мусить чекати, поки програма завершить роботу, а програма мусить чекати, поки завершить DMA, що означає: максимально досяжна частота кадрів становить у кращому разі половину частоти датчика – кожен другий кадр, що надходить від датчика, застає буфер зайнятим і втрачається.
Цей режим найменш витратний за оперативною пам’яттю і найповільніший за пропускною здатністю. Використовуйте його лише тоді, коли оперативної пам’яті замало для виділення другого буфера.
4.15.2. Подвійний буфер (count = 2)¶
Два кадрові буфери в оперативній пам’яті: один задній буфер, який заповнює DMA, і один передній буфер, який зчитує програма. Коли програма завершує роботу з переднім буфером, ролі міняються місцями: DMA починає заповнювати щойно звільнений буфер, а програма зчитує з щойно заповненого.
Допоки програма обробляє кожен кадр швидше, ніж за один період кадру камери, вона бачить повну частоту кадрів датчика – наступний кадр DMA вже чекає в задньому буфері, коли програма знову викликає snapshot(). Однак щойно час обробки перевищує один період кадру, частота вдвічі знижується: камера встигає виробити два кадри за час, що програма витрачає на один, і лише другий із них буде доставлений.
Після цієї межі частота плавно деградує зі збільшенням часу обробки. Щоразу, коли DMA завершує новий кадр у задньому буфері, поки програма ще працює з переднім, новий кадр перезаписує попередній знімок на місці, а не відкидається. Програма завжди отримує найсвіжіший кадр, вироблений камерою, при наступному виклику snapshot(), і досяжна частота кадрів програми стає оберненою до часу її обробки.
4.15.3. Потрійний буфер (count = 3)¶
Три кадрові буфери в оперативній пам’яті: два задні буфери, між якими циклічно перемикається DMA, і один передній буфер, з яким у цей момент працює програма. Це режим за замовчуванням, який OpenMV Cam обирає за наявності достатньо оперативної пам’яті, з автоматичним поверненням до подвійного або одинарного буфера, якщо її не вистачає.
Третій буфер повністю розв’язує частоту кадрів камери від частоти кадрів програми. DMA завжди має буфер для запису; програма завжди має буфер для читання; при кожному виклику snapshot() найсвіжіший готовий задній буфер стає новим переднім, а попередній передній буфер звільняється для DMA. Частота кадрів програми відповідає фактичному часу обробки кожного кадру – без ефекту зниження вдвічі, характерного для подвійного буфера, коли час обробки щойно перевищує один період кадру.
4.15.4. Відеофіфо (count = 4 або більше)¶
Чотири або більше кадрових буферів у оперативній пам’яті, організованих у кільце кадрів, зафіксованих один за одним. Кожен кадр, що надходить від камери, ставиться у чергу FIFO, а snapshot() повертає найстаріший кадр у черзі, а не найновіший. Програма проходить через зафіксовані кадри в порядку їх захоплення за фактично наявний на обробку кожного час.
Цей режим є правильним вибором, коли важливий кожен кадр і очікуються короткі затримки обробки: запис відео на SD-карту, стек пам’яті якої може блокуватися на десятки мілісекунд під час стирання; потокова передача через USB на хост, що ненадовго припиняє читання; або буферизація короткого сплеску швидкої події для подальшого аналізу в коді.
Дві політики обробляють випадок, коли FIFO заповнюється до того, як програма його спустошила.
Відкидання старих кадрів (за замовчуванням). Коли FIFO заповнений, усі кадри в черзі, крім активного, відкидаються, щоб наступний
snapshot()повертав свіжий кадр, а не застарілий. DMA продовжує захоплення весь цей час, тому після затримки програма завжди бачить актуальні дані. Це правильна політика, коли мета – підтримувати поточність захопленого потоку: запис відео, пряма трансляція.Зупинка захоплення при переповненні. Передайте
fflush=Falseдо конструктораCSI, і DMA перестане заповнювати FIFO, коли той буде повним, залишаючи кадри в черзі недоторканими.snapshot()продовжить повертати кадри в порядку захоплення, поки програма їх не вичерпає, після чого DMA поновлює роботу. Це правильна політика, коли мета – зберегти кожен кадр короткого сплеску: наприклад, захопити швидкий рух, щоб потім покадрово переглянути його в коді.
Повний API описано в csi.CSI.framebuffers().
4.15.5. Режим за тригером¶
Альтернативою до постійно-активних режимів вище є захоплення за тригером, при якому датчик випромінює кадр лише тоді, коли snapshot() його запитує. Між знімками камера перебуває в режимі очікування і щоразу починає нову витримку, коли програма звертається до неї.
Ціна – пропускна здатність: захоплення за тригером не може перекриватися з попереднім, тому максимально досяжна частота кадрів становить половину від звичайної швидкості датчика. Перевага – точність часу витримки. Знімок точно контролює момент початку витримки, що необхідно програмі, коли витримка повинна збігатися із зовнішньою подією – стробоспалахом, датчиком положення конвеєра, імпульсом на лінії GPIO – а не припадати на довільний момент у рамках кадру датчика, що вільно працює, коли програма готова зчитати його.
Режим за тригером є датчико-специфічним. На підтримуваних датчиках він вмикається викликом csi0.ioctl(csi.IOCTL_SET_TRIGGERED_MODE, True) і вимикається передачею False.