4.15. Kehyspuskurit¶
Kun kamerasensori on alustettu, se lähettää kehyksiä jatkuvasti kehysnopeudellaan – yhden uuden kehyksen jokaisen kehysjakson aikana riippumatta siitä, onko sovellus valmis vastaanottamaan sen. Jokainen kehys tarvitsee paikan RAM-muistissa, johon laskeutua, tai se menetetään. Kehyspuskuripooli on paikka, jossa nämä kehykset elävät DMA:lta poistumisen ja käyttäjän koodin käsittelyn välissä, ja se, kuinka monta kehyspuskuria kamera pitää poolissa, määrää sen, miten DMA ja sovellus jakavat ne. Valinta tehdään framebuffers()-metodin kautta, ja saatavilla on neljä tilaa, jotka valitaan puskurien lukumäärällä.
4.15.1. Yksittäinen puskuri (count = 1)¶
Yksi kehyspuskuri RAM-muistissa. DMA täyttää sen; sovellus lukee siitä; seuraava snapshot()-kutsu ei voi käynnistyä ennen kuin sovellus on vapauttanut puskurin, koska samaa puskuria tarvitaan molempiin.
Kamera ja sovellus etenevät tahdissa toistensa kanssa. DMA:n on odotettava sovelluksen valmistumista, ja sovelluksen on odotettava DMA:n valmistumista, mikä tarkoittaa, että saavutettavissa oleva kehysnopeus on parhaimmillaan puolet sensorin kehysnopeudesta – joka toinen sensorin lähettämä kehys saapuu silloin, kun puskuri on varattuna, ja menetetään.
Tämä tila on pienin RAM-muistin käytöltään ja hitain läpäisykyvyltään. Käytä sitä vain, kun RAM on liian tiukalla toisen puskurin varaamiseen.
4.15.2. Kaksoispuskuri (count = 2)¶
Kaksi kehyspuskuria RAM-muistissa: yksi takapuskuri, jonka DMA täyttää, ja yksi etupuskuri, josta sovellus lukee. Kun sovellus saa etupuskurin valmiiksi, kaksi roolia vaihtuvat, ja DMA alkaa täyttää juuri vapautettua puskuria samalla, kun sovellus lukee juuri täytetystä.
Niin kauan kuin sovellus käsittelee jokaisen kehyksen alle yhdessä kameran kehysjaksossa, sovellus näkee sensorin täyden kehysnopeuden – DMA:n seuraava kehys odottaa jo takapuskurissa, kun sovellus kutsuu snapshot()-metodia uudelleen. Sillä hetkellä, kun käsittelyaika ylittää yhden kehysjakson, nopeus kuitenkin puolittuu: kamera tuottaa kaksi kehystä siinä ajassa, jonka sovellus käyttää yhden käsittelyyn, ja näistä kahdesta toimitetaan vain jälkimmäinen.
Tämän pisteen jälkeen nopeus heikkenee tasaisesti käsittelyajan mukaan. Joka kerta, kun DMA saa uuden takapuskurikehyksen valmiiksi sovelluksen vielä työstäessä etupuskuria, uusi kehys ylikirjoittaa edellisen kaappauksen paikallaan sen sijaan, että se hylättäisiin. Sovellus saa aina viimeisimmän kameran tuottaman kehyksen seuraavalla snapshot()-kutsullaan, ja saavutettavissa olevasta sovellusnopeudesta tulee käsittelyajan käänteisluku.
4.15.3. Kolmoispuskuri (count = 3)¶
Kolme kehyspuskuria RAM-muistissa: kaksi takapuskuria, joiden läpi DMA kiertää, ja yksi etupuskuri, jota sovellus parhaillaan työstää. Tämä on oletustila, jonka OpenMV Cam valitsee, kun RAM-muistia on riittävästi käytettävissä, automaattisella varatilana kaksois- tai yksittäispuskuriin, kun sitä ei ole.
Kolmas puskuri erottaa kameran kehysnopeuden täysin sovelluksen kehysnopeudesta. DMA:lla on aina puskuri, johon kirjoittaa; sovelluksella on aina puskuri, josta lukea; jokaisella snapshot()-kutsulla viimeisin valmis takapuskuri tulee uudeksi etupuskuriksi ja edellinen etupuskuri vapautetaan DMA:lle. Sovelluksen kehysnopeus vastaa sitä aikaa, joka kuluu kunkin kehyksen käsittelyyn – ilman sitä 1/2-porrasta, johon kaksoispuskuri ajautuu, kun käsittelyaika livahtaa juuri yhden kehysjakson yli.
4.15.4. Video-FIFO (count = 4 tai enemmän)¶
Neljä tai useampia kehyspuskureita RAM-muistissa, järjestettynä peräkkäin kaapattujen kehysten renkaaksi. Jokainen kameran toimittama kehys laitetaan jonoon FIFO:on, ja snapshot() palauttaa vanhimman jonossa olevan kehyksen viimeisimmän sijaan. Sovellus käy kaapatut kehykset läpi kaappausjärjestyksessä, sillä ajalla, joka sillä todellisuudessa on käytettävissä kuhunkin.
Tämä tila on oikea valinta, kun jokainen kehys on tärkeä ja lyhyitä käsittelykatkoksia on odotettavissa: videon kirjoittaminen SD-kortille, jonka tallennuspino voi tukkeutua kymmeniksi millisekunneiksi tyhjennyksen aikana, suoratoisto USB:n kautta isäntäkoneelle, joka lakkaa hetkeksi lukemasta, tai nopean tapahtuman lyhyen purskeen puskurointi koodissa tarkasteltavaksi.
Kaksi käytäntöä käsittelee tilannetta, jossa FIFO täyttyy ennen kuin sovellus on tyhjentänyt sen.
Pudota vanhat kehykset (oletus). Kun FIFO täyttyy, kaikki jonossa olevat kehykset aktiivista lukuun ottamatta hylätään, jotta seuraava
snapshot()palauttaa tuoreen kehyksen vanhentuneen sijaan. DMA jatkaa kaappaamista koko ajan, joten sovellus näkee aina tuoretta dataa katkoksen jälkeen. Tämä on oikea käytäntö, kun tavoitteena on pitää kaapattu virta ajantasaisena – videon tallennus, suoratoisto.Pysäytä kaappaus ylivuodon yhteydessä. Välitä
fflush=FalseCSI-konstruktorille, jolloin DMA lakkaa täyttämästä FIFO:a sen ollessa täynnä jättäen jonossa olevat kehykset ennalleen.snapshot()jatkaa kehysten palauttamista kaappausjärjestyksessä, kunnes sovellus on tyhjentänyt ne, minkä jälkeen DMA jatkaa. Tämä on oikea käytäntö, kun tavoitteena on säilyttää lyhyen purskeen jokainen kehys – nopean liikkeen kaappaaminen tarkasteltavaksi kehys kerrallaan koodissa jälkikäteen.
Katso csi.CSI.framebuffers() saadaksesi täydellisen API:n.
4.15.5. Liipaistu tila¶
Vaihtoehto yllä kuvatuille jatkuvasti käynnissä oleville tiloille on liipaistu kaappaus, jossa sensori lähettää kehyksen vain silloin, kun snapshot() pyytää sitä. Kamera on jouten tilannekuvien välissä ja aloittaa uuden valotuksen joka kerta, kun sovellus kutsuu sitä.
Hintana on läpäisykyky: liipaistu kaappaus ei voi limittyä edellisen kanssa, joten suurin saavutettavissa oleva kehysnopeus on puolet sensorin normaalista nopeudesta. Hyötynä on valotuksen ajoitus. Tilannekuva ohjaa tarkalleen sitä, milloin valotus alkaa, mikä on juuri se, mitä sovellus haluaa, kun valotuksen on osuttava samaan kohtaan ulkoisen tapahtuman kanssa – salamavälähdys, kuljettimen sijaintisensori, pulssi GPIO-linjalla – sen sijaan, että se laskeutuisi mihin tahansa kohtaan, jossa vapaasti käyvän sensorin liikkuva kehys sattuu olemaan, kun sovellus on valmis lukemaan sen.
Liipaistu tila on sensorikohtainen. Tuetuilla sensoreilla se otetaan käyttöön kutsumalla csi0.ioctl(csi.IOCTL_SET_TRIGGERED_MODE, True) ja poistetaan käytöstä välittämällä False.