4.15. Framebuffers¶
Assim que o sensor da câmara é inicializado, emite fotogramas continuamente à sua taxa de fotogramas – um novo fotograma a cada período de fotograma, independentemente de a aplicação estar ou não pronta para o receber. Cada fotograma precisa de um espaço em RAM para ser guardado, caso contrário perde-se. O conjunto de framebuffers é onde esses fotogramas residem entre o momento em que saem do DMA e o momento em que são processados pelo código do utilizador, e o número de framebuffers que a câmara mantém nesse conjunto controla a forma como o DMA e a aplicação os partilham. A escolha é exposta através de framebuffers(), e estão disponíveis quatro modos, selecionados pelo número de buffers.
4.15.1. Buffer único (count = 1)¶
Um framebuffer em RAM. O DMA preenche-o; a aplicação lê a partir dele; a próxima chamada a snapshot() não pode iniciar até que a aplicação tenha libertado o buffer, porque o mesmo buffer é necessário para ambos.
A câmara e a aplicação funcionam em sincronismo. O DMA tem de aguardar que a aplicação termine, e a aplicação tem de aguardar que o DMA termine, o que significa que a taxa de fotogramas atingível é, na melhor das hipóteses, metade da taxa de fotogramas do sensor – em cada dois fotogramas emitidos pelo sensor, um chega enquanto o buffer está ocupado e perde-se.
Este modo é o que ocupa menos RAM e tem o menor débito. Utilize-o apenas quando a RAM é demasiado limitada para alocar um segundo buffer.
4.15.2. Buffer duplo (count = 2)¶
Dois framebuffers em RAM: um buffer traseiro que o DMA preenche e um buffer frontal que a aplicação lê. Quando a aplicação termina o buffer frontal, os dois papéis invertem-se, e o DMA começa a preencher o buffer recém-libertado enquanto a aplicação lê o que acabou de ser preenchido.
Desde que a aplicação processe cada fotograma em menos de um período de fotograma da câmara, a aplicação vê a taxa de fotogramas completa do sensor – o próximo fotograma do DMA já está a aguardar no buffer traseiro quando a aplicação volta a chamar snapshot(). No entanto, no momento em que o tempo de processamento excede um período de fotograma, a taxa cai para metade: a câmara produz dois fotogramas no tempo que a aplicação demora a processar um, e apenas o segundo desses dois será entregue.
A partir desse ponto, a taxa degrada-se suavemente com o tempo de processamento. Sempre que o DMA termina um novo fotograma no buffer traseiro enquanto a aplicação ainda está a trabalhar no buffer frontal, o novo fotograma sobrescreve a captura anterior em vez de ser descartado. A aplicação obtém sempre o fotograma mais recente produzido pela câmara no próximo snapshot(), e a taxa atingível pela aplicação passa a ser o inverso do seu tempo de processamento.
4.15.3. Buffer triplo (count = 3)¶
Três framebuffers em RAM: dois buffers traseiros pelos quais o DMA circula e um buffer frontal com o qual a aplicação está a trabalhar no momento. Este é o modo predefinido que a OpenMV Cam seleciona quando há RAM suficiente disponível, com recuo automático para buffer duplo ou simples quando não há.
O terceiro buffer desacopla completamente a taxa de fotogramas da câmara da taxa de fotogramas da aplicação. O DMA tem sempre um buffer para escrever; a aplicação tem sempre um buffer para ler; em cada snapshot() o buffer traseiro pronto mais recente torna-se o novo buffer frontal e o buffer frontal anterior é libertado para o DMA. A taxa de fotogramas da aplicação corresponde ao tempo que realmente demora a processar cada fotograma – sem o passo 1/2 em que o buffer duplo cai quando o tempo de processamento ultrapassa ligeiramente um período de fotograma.
4.15.4. FIFO de vídeo (count = 4 ou mais)¶
Quatro ou mais framebuffers em RAM, dispostos como um anel de fotogramas capturados consecutivamente. Cada fotograma entregue pela câmara é colocado em fila no FIFO, e snapshot() devolve o fotograma em fila mais antigo em vez do mais recente. A aplicação percorre os fotogramas capturados por ordem de captura, no tempo que realmente tem disponível para cada um.
Este modo é a escolha certa quando cada fotograma é importante e são esperadas breves pausas no processamento: gravação de vídeo num cartão SD cuja pilha de armazenamento pode bloquear durante dezenas de milissegundos durante um apagamento, transmissão por USB para um anfitrião que para brevemente de ler, ou armazenar uma curta rajada de um evento rápido para inspeção no código.
Duas políticas tratam o caso em que o FIFO fica cheio antes de a aplicação o ter esvaziado.
Descartar fotogramas antigos (predefinição). Quando o FIFO fica cheio, todos os fotogramas em fila exceto o ativo são descartados, para que o próximo
snapshot()devolva um fotograma recente em vez de um desatualizado. O DMA continua a capturar durante todo o processo, pelo que a aplicação vê sempre dados atuais após uma pausa. Esta é a política certa quando o objetivo é manter a corrente capturada atual – gravação de vídeo, transmissão em direto.Parar a captura em caso de transbordamento. Passe
fflush=Falseao construtorCSIe o DMA para de preencher o FIFO quando este está cheio, mantendo intactos os fotogramas em fila.snapshot()continua a devolver fotogramas por ordem de captura até que a aplicação os tenha esgotado, após o que o DMA recomeça. Esta é a política certa quando o objetivo é preservar cada fotograma de uma curta rajada – capturar movimento rápido para inspecionar fotograma a fotograma no código a seguir.
Consulte csi.CSI.framebuffers() para obter a API completa.
4.15.5. Modo disparado¶
Uma alternativa aos modos de execução contínua descritos acima é a captura disparada, em que o sensor emite um fotograma apenas quando snapshot() o solicita. A câmara fica inativa entre capturas e inicia uma nova exposição cada vez que a aplicação a invoca.
O custo é em débito: uma captura disparada não pode sobrepor-se à anterior, pelo que a taxa de fotogramas máxima atingível é metade da taxa normal do sensor. O benefício está no momento da exposição. O snapshot controla exatamente quando a exposição começa, o que é o que uma aplicação necessita quando a exposição tem de coincidir com um evento externo – um flash estroboscópico, um sensor de posição de tapete rolante, um impulso numa linha GPIO – em vez de cair onde quer que o fotograma em curso do sensor de execução livre se encontre quando a aplicação está pronta para o ler.
O modo disparado é específico do sensor. Nos sensores suportados é ativado chamando csi0.ioctl(csi.IOCTL_SET_TRIGGERED_MODE, True) e desativado passando False.