4.15. Framebuffers¶
Zodra de camerasensor is geïnitialiseerd, levert hij continu frames op zijn framesnelheid – één nieuw frame per frameperiode, ongeacht of de applicatie er klaar voor is. Elk frame moet ergens in het RAM terechtkomen, anders gaat het verloren. De framebufferpool is de plek waar die frames leven tussen het verlaten van de DMA en de verwerking door gebruikerscode, en hoeveel framebuffers de camera in die pool aanhoudt bepaalt hoe de DMA en de applicatie ze delen. De keuze wordt blootgesteld via framebuffers(), en er zijn vier modi beschikbaar, geselecteerd door het bufferaantal.
4.15.1. Enkele buffer (count = 1)¶
Eén framebuffer in het RAM. De DMA vult hem; de applicatie leest eruit; de volgende aanroep van snapshot() kan niet starten voordat de applicatie de buffer heeft vrijgegeven, omdat dezelfde buffer voor beide nodig is.
De camera en de applicatie lopen in lockstep. De DMA moet wachten tot de applicatie klaar is, en de applicatie moet wachten tot de DMA klaar is, wat betekent dat de haalbare framesnelheid in het beste geval de helft is van de framesnelheid van de sensor – elk tweede frame dat de sensor uitstoot arriveert terwijl de buffer bezet is en gaat verloren.
Deze modus is de kleinste qua RAM en de traagste qua doorvoer. Gebruik hem alleen wanneer het RAM te krap is om een tweede buffer toe te wijzen.
4.15.2. Dubbele buffer (count = 2)¶
Twee framebuffers in het RAM: één back-buffer die de DMA vult, en één front-buffer waaruit de applicatie leest. Wanneer de applicatie klaar is met de front-buffer wisselen de twee rollen, en de DMA begint de zojuist vrijgegeven buffer te vullen terwijl de applicatie leest uit de net gevulde buffer.
Zolang de applicatie elk frame verwerkt in minder dan één cameraframeperiode, ziet de applicatie de volledige framesnelheid van de sensor – het volgende frame van de DMA staat al klaar in de back-buffer wanneer de applicatie opnieuw snapshot() aanroept. Op het moment dat de verwerkingstijd echter één frameperiode overschrijdt, halveert de snelheid: de camera produceert twee frames in de tijd die de applicatie nodig heeft om er één te verwerken, en alleen het tweede van die twee wordt afgeleverd.
Voorbij dat punt neemt de snelheid geleidelijk af met de verwerkingstijd. Telkens wanneer de DMA een nieuw back-bufferframe voltooit terwijl de applicatie nog met de front-buffer bezig is, overschrijft het nieuwe frame de vorige opname ter plaatse in plaats van te worden weggegooid. De applicatie krijgt bij haar volgende snapshot() altijd het meest recente frame dat de camera produceerde, en de haalbare applicatiesnelheid wordt de inverse van de verwerkingstijd.
4.15.3. Drievoudige buffer (count = 3)¶
Drie framebuffers in het RAM: twee back-buffers die de DMA doorloopt en één front-buffer waar de applicatie momenteel mee werkt. Dit is de standaardmodus die de OpenMV Cam kiest wanneer er genoeg RAM beschikbaar is, met automatische terugval naar dubbele of enkele buffer wanneer dat niet zo is.
De derde buffer ontkoppelt de cameraframesnelheid volledig van de applicatieframesnelheid. De DMA heeft altijd een buffer om in te schrijven; de applicatie heeft altijd een buffer om uit te lezen; bij elke snapshot() wordt de meest recente gereedstaande back-buffer de nieuwe front-buffer en wordt de vorige front-buffer vrijgegeven voor de DMA. De framesnelheid van de applicatie komt overeen met de tijd die het werkelijk kost om elk frame te verwerken – zonder de halveringsstap waar dubbele buffer in vervalt wanneer de verwerkingstijd net één frameperiode overschrijdt.
4.15.4. Video-FIFO (count = 4 of meer)¶
Vier of meer framebuffers in het RAM, gerangschikt als een ring van achter elkaar opgenomen frames. Elk frame dat de camera aflevert wordt in de FIFO gezet, en snapshot() retourneert het oudste in de wachtrij geplaatste frame in plaats van het meest recente. De applicatie loopt de opgenomen frames in opnamevolgorde door, in de tijd die ze er werkelijk aan kan besteden.
Deze modus is de juiste keuze wanneer elk frame ertoe doet en korte verwerkingsstilstanden te verwachten zijn: video naar een SD-kaart schrijven waarvan de opslagstack tijdens een wisbewerking tientallen milliseconden kan blokkeren, streamen via USB naar een host die kort stopt met lezen, of een korte burst van een snelle gebeurtenis bufferen voor inspectie in code.
Twee beleidsregels behandelen het geval waarin de FIFO vol raakt voordat de applicatie hem heeft leeggemaakt.
Oude frames laten vallen (standaard). Wanneer de FIFO vol raakt, worden alle frames in de wachtrij behalve het actieve weggegooid, zodat de volgende
snapshot()een recent frame retourneert in plaats van een verouderd. De DMA blijft de hele tijd opnemen, zodat de applicatie na een stilstand altijd verse data ziet. Dit is het juiste beleid wanneer het doel is de opgenomen stream actueel te houden – video-opname, live streaming.Stoppen met opnemen bij overloop. Geef
fflush=Falsedoor aan deCSI-constructor en de DMA stopt met het vullen van de FIFO wanneer deze vol is, waarbij de frames in de wachtrij intact blijven.snapshot()blijft frames retourneren in opnamevolgorde totdat de applicatie ze heeft leeggemaakt, waarna de DMA hervat. Dit is het juiste beleid wanneer het doel is elk frame van een korte burst te bewaren – snelle beweging opnemen om die naderhand frame voor frame in code te inspecteren.
Zie csi.CSI.framebuffers() voor de volledige API.
4.15.5. Getriggerde modus¶
Een alternatief voor de bovenstaande continu lopende modi is getriggerde opname, waarbij de sensor alleen een frame uitstoot wanneer snapshot() erom vraagt. De camera staat stil tussen momentopnamen en start elke keer dat de applicatie aanroept een nieuwe belichting.
De prijs is doorvoer: een getriggerde opname kan niet overlappen met de vorige, dus de maximaal haalbare framesnelheid is de helft van de normale snelheid van de sensor. Het voordeel is de belichtingstiming. Snapshot bepaalt precies wanneer de belichting begint, wat een applicatie wil wanneer de belichting moet samenvallen met een externe gebeurtenis – een stroboscoopflits, een sensor voor de positie van een transportband, een puls op een GPIO-lijn – in plaats van terecht te komen waar het rollende frame van de vrijlopende sensor zich toevallig bevindt op het moment dat de applicatie klaar is om het te lezen.
De getriggerde modus is sensorspecifiek. Op ondersteunde sensoren wordt deze ingeschakeld door csi0.ioctl(csi.IOCTL_SET_TRIGGERED_MODE, True) aan te roepen en uitgeschakeld door False door te geven.