4.15. Framebuffere

Odată ce senzorul camerei este inițializat, acesta emite cadre în mod continuu la rata sa de cadre – un cadru nou la fiecare perioadă de cadru, indiferent dacă aplicația este sau nu pregătită pentru el. Fiecare cadru are nevoie de un loc în RAM unde să ajungă, altfel se pierde. Pool-ul de framebuffere este locul unde acele cadre se află între momentul în care părăsesc DMA și momentul în care sunt procesate de codul utilizatorului, iar numărul de framebuffere pe care camera le păstrează în acel pool controlează modul în care DMA și aplicația le partajează. Alegerea este expusă prin framebuffers(), fiind disponibile patru moduri, selectate prin numărul de tampoane.

4.15.1. Tampon unic (count = 1)

Un singur framebuffer în RAM. DMA îl umple; aplicația citește din el; următorul apel la snapshot() nu poate începe până când aplicația nu a eliberat tamponul, deoarece același tampon este necesar pentru ambele operații.

Camera și aplicația rulează sincron, pas cu pas. DMA trebuie să aștepte ca aplicația să termine, iar aplicația trebuie să aștepte ca DMA să termine, ceea ce înseamnă că rata de cadre care poate fi atinsă este în cel mai bun caz jumătate din rata de cadre a senzorului – la fiecare al doilea cadru pe care senzorul îl emite, acesta ajunge în timp ce tamponul este ocupat și se pierde.

Acest mod este cel mai redus ca utilizare a RAM și cel mai lent ca debit. Folosiți-l doar atunci când RAM este prea limitată pentru a aloca un al doilea tampon.

4.15.2. Tampon dublu (count = 2)

Două framebuffere în RAM: un tampon posterior pe care DMA îl umple și un tampon frontal din care aplicația citește. Când aplicația termină tamponul frontal, cele două roluri se schimbă, iar DMA începe să umple tamponul tocmai eliberat în timp ce aplicația citește din cel care tocmai a fost umplut.

Atâta timp cât aplicația procesează fiecare cadru în mai puțin de o perioadă de cadru a camerei, aplicația vede rata completă de cadre a senzorului – următorul cadru al DMA așteaptă deja în tamponul posterior atunci când aplicația apelează din nou snapshot(). În momentul în care timpul de procesare depășește însă o perioadă de cadru, rata se înjumătățește: camera va produce două cadre în timpul în care aplicația procesează unul, iar dintre acestea două va fi livrat doar al doilea.

Dincolo de acel punct, rata se degradează lin în funcție de timpul de procesare. De fiecare dată când DMA termină un nou cadru în tamponul posterior în timp ce aplicația încă lucrează la tamponul frontal, noul cadru suprascrie captura anterioară pe loc, în loc să fie aruncat. Aplicația obține întotdeauna cel mai recent cadru produs de cameră la următorul său snapshot(), iar rata care poate fi atinsă de aplicație devine inversul timpului său de procesare.

4.15.3. Tampon triplu (count = 3)

Trei framebuffere în RAM: două tampoane posterioare prin care DMA circulă și un tampon frontal la care aplicația lucrează în prezent. Acesta este modul implicit pe care OpenMV Cam îl alege atunci când există suficientă RAM disponibilă, cu revenire automată la tampon dublu sau unic atunci când nu există.

Al treilea tampon decuplează complet rata de cadre a camerei de rata de cadre a aplicației. DMA are întotdeauna un tampon în care să scrie; aplicația are întotdeauna un tampon din care să citească; la fiecare snapshot() cel mai recent tampon posterior pregătit devine noul tampon frontal, iar tamponul frontal anterior este eliberat pentru DMA. Rata de cadre a aplicației corespunde timpului necesar în mod real pentru procesarea fiecărui cadru – fără pasul de 1/2 în care cade tamponul dublu atunci când timpul de procesare depășește puțin o perioadă de cadru.

4.15.4. Video FIFO (count = 4 sau mai mult)

Patru sau mai multe framebuffere în RAM, dispuse ca un inel de cadre capturate succesiv. Fiecare cadru pe care camera îl livrează este pus în coadă în FIFO, iar snapshot() returnează cel mai vechi cadru din coadă, în loc de cel mai recent. Aplicația parcurge cadrele capturate în ordinea capturării, în timpul de care dispune efectiv pentru fiecare.

Acest mod este alegerea potrivită atunci când fiecare cadru contează și sunt așteptate scurte blocaje de procesare: scrierea materialului video pe un card SD a cărui stivă de stocare se poate bloca pentru zeci de milisecunde în timpul unei ștergeri, transmiterea prin USB către o gazdă care încetează pentru scurt timp să citească sau memorarea unei rafale scurte a unui eveniment rapid pentru inspecția în cod.

Două politici tratează cazul în care FIFO se umple înainte ca aplicația să-l fi golit.

  • Eliminarea cadrelor vechi (implicit). Când FIFO se umple, toate cadrele din coadă, cu excepția celui activ, sunt aruncate, astfel încât următorul snapshot() să returneze un cadru recent, nu unul învechit. DMA continuă să captureze pe tot parcursul, astfel încât aplicația vede întotdeauna date proaspete după un blocaj. Aceasta este politica potrivită atunci când scopul este menținerea fluxului capturat la zi – înregistrare video, transmisie în direct.

  • Oprirea capturii la depășire. Treceți fflush=False la constructorul CSI, iar DMA oprește umplerea FIFO atunci când este plin, lăsând cadrele din coadă intacte. snapshot() continuă să returneze cadre în ordinea capturării până când aplicația le-a golit, după care DMA se reia. Aceasta este politica potrivită atunci când scopul este păstrarea fiecărui cadru al unei rafale scurte – capturarea unei mișcări rapide pentru a o inspecta ulterior cadru cu cadru în cod.

Consultați csi.CSI.framebuffers() pentru API-ul complet.

4.15.5. Mod declanșat

O alternativă la modurile cu rulare continuă de mai sus este captura declanșată, în care senzorul emite un cadru doar atunci când snapshot() cere unul. Camera rămâne inactivă între instantanee și începe o nouă expunere de fiecare dată când aplicația apelează.

Costul este debitul: o captură declanșată nu se poate suprapune cu cea anterioară, astfel încât rata maximă de cadre care poate fi atinsă este jumătate din rata normală a senzorului. Beneficiul este sincronizarea expunerii. Snapshot controlează exact când începe expunerea, ceea ce dorește o aplicație atunci când expunerea trebuie să se alinieze cu un eveniment extern – un bliț stroboscopic, un senzor de poziție a benzii transportoare, un impuls pe o linie GPIO – în loc să apară oriunde se întâmplă să se afle cadrul în desfășurare al senzorului cu rulare liberă atunci când aplicația este pregătită să-l citească.

Modul declanșat este specific senzorului. Pe senzorii compatibili acesta este activat prin apelarea csi0.ioctl(csi.IOCTL_SET_TRIGGERED_MODE, True) și dezactivat prin trecerea valorii False.