Como imitar a saída de uma webcam atualizando um arquivo jpg?

3

Eu tenho uma pasta A na qual, de vez em quando, aparecem novos arquivos. Pode acontecer que não haja novos arquivos por uma hora, mas também que haja vários novos arquivos a cada segundo. Todos os arquivos têm um registro de data e hora exclusivo em seus nomes e diferentes extensões de arquivo. O que, como e quando algo é colocado na pasta não pode ser modificado. É um diretório no meu pc que é acessado do lado de fora via ftp.

Em outra pasta B, eu gostaria de ter uma cópia do arquivo jpg mais recente da pasta A chamada "Newest.jpg" assim que houver uma nova. 1 segundo atraso seria bom. Supõe-se que imite a saída de uma webcam.

Qual é o melhor e menos oneroso modo computacional para conseguir isso em um sistema parecido com o Raspberry que roda o Ubuntu 14.04 LTS?

    
por Rob 11.10.2016 / 11:13

2 respostas

3

Se você instalar o pacote inotify-tools , poderá escrever um script simples que receberá inotify events quando um novo arquivo for criado.

inotifywait  -m -e create --format %f A | 
while read filename
do    ln -f A/"$filename" B/Newest.jpg
done

Sempre que um novo arquivo é criado no diretório assistido A , o evento é impresso no formato dado %f ou seja, apenas o nome do arquivo. O loop do shell lê isso e cria um link. Não deve haver nenhum atraso entre a criação do arquivo e o link sendo feito.

Se for necessário excluir determinados nomes de arquivos, você poderá adicionar --exclude e um padrão regex ao inotifywait , por exemplo, --exclude '.*.wav$' para excluir *.wav arquivos. Como alternativa, pode ser mais simples testar um padrão *.jpg desejado dentro do loop do shell. Se você está usando o bash você pode simplesmente adicionar no início, depois do do :

[[ "$filename" != *.jpg ]] && continue

Isso testa um padrão glob em vez de um regex.

    
por 11.10.2016 / 16:32
3

Primeiro, crie um link simbólico para qualquer arquivo no diretório e chame-o de "mais recente":

ln -s somefile.jpg latest

Em seguida, execute o seguinte comando no diretório quantas vezes quiser:

find . -type f -newer latest -exec ln -fs {} latest \;

Isso é bem elegante, porque a sequência de avaliação não importa. No final deste comando latest será um symlink para o arquivo mais novo no diretório. EDIT: Isso está errado. De acordo com POSIX :

The -user, -group, and -newer primaries each shall evaluate their respective arguments only once.

Isso praticamente invalida essa abordagem, mas você ainda pode fazer algo com isso. No entanto, dado esse fato, eu usaria inotify como sugerido na outra resposta.

Eu não sei quantos ciclos de CPU ele queimaria, mas apenas em execução:

while true; do find . -type f -name '*.jpg' -newer latest -exec ln -fs {} latest \; ; done

garantirá que latest sempre aponte para o arquivo jpeg mais recente, o mais rápido possível. Se você não espera novas imagens com mais frequência do que uma vez por segundo, você pode usar while sleep 1 em vez de while true .

Observe que à medida que o número de arquivos em seu diretório aumenta, isso fica cada vez mais ineficiente. Eu tenho algumas idéias de como você pode lidar com isso, mas como é no ftp elas podem não ser aplicáveis.

Meu primeiro pensamento foi mover os arquivos mais antigos para outro diretório como parte do mesmo comando find , para que eles não precisem ser avaliados novamente. O problema é que o arquivo que o símbolo latest aponta para contar como "mais antigo", já que não é mais recente. Não podemos mover o arquivo ou quebraremos o link simbólico!

No entanto, como estamos avaliando apenas os arquivos com o nome .jpg, podemos contornar isso criando latest a link físico em vez de um link simbólico:

mkdir ../oldfiles
while sleep 1; do find . -type f -name '*.jpg' \( -newer latest -exec ln -f {} latest \; -o -exec mv {} ../oldfiles \; \)

Mais uma vez, eu não sei como isso vai no ftp, mas para arquivos locais ele deve funcionar muito bem.

    
por 11.10.2016 / 11:54