Skip to content

About

Controle da webcam Insta360 Link no Linux — rastreamento por IA, gimbal e modos via unidades de extensão UVC. Python puro, sem dependências.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

linkctl — Insta360 Link no Linux

Controla uma webcam Insta360 Link no Linux, incluindo os recursos que a Insta360 só expõe pelo Link Controller, aplicativo que existe apenas para Windows e macOS.

Não há dependência externa: só a biblioteca padrão do Python 3.11 ou mais novo. Nada de compilar, nada de Lazarus, nada de v4l-utils.

Por que isto existe

A Link funciona como webcam comum no Linux através do uvcvideo, e não falta driver nenhum — o kernel 6.10 e posteriores até trazem uma correção específica para este modelo (UVC_QUIRK_DISABLE_AUTOSUSPEND). O que falta é o programa que fala os comandos proprietários. Sem ele, o rastreamento por IA fica desligado, que é justamente o recurso que distingue esta câmera de uma webcam de 200 reais.

Instalação

git clone <este repositório> ~/Projects/insta360-link-ctl
ln -s ~/Projects/insta360-link-ctl/bin/linkctl ~/.local/bin/linkctl

O acesso a /dev/video* costuma vir da ACL da sessão gráfica, e nesse caso nada mais é preciso. Se linkctl info reclamar de permissão, entre no grupo video:

sudo usermod -aG video "$USER"   # exige sair e entrar de novo na sessão

Uso

linkctl info                 # firmware, modo, rastreamento, enquadramento
linkctl list                 # câmeras Insta360 conectadas
linkctl tracking on          # liga o rastreamento por IA
linkctl tracking off
linkctl framing half         # head | half | full
linkctl home                 # recentra o gimbal
linkctl detect               # caixa do sujeito detectado
linkctl formats              # resoluções e taxas oferecidas
linkctl ctl                  # lista os controles V4L2
linkctl ctl saturation 60    # altera um controle
linkctl pan 36000            # pan absoluto em arcsec (±522000)
linkctl tilt -18000
linkctl pan -r 3600          # relativo à posição atual
linkctl zoom 200             # 100 = 1x, 400 = 4x
linkctl mode deskview        # normal | tracking | whiteboard | overhead | deskview
linkctl preset save mesa     # guarda pan, tilt e zoom
linkctl preset recall mesa
linkctl preset list
linkctl dump -o estado.json  # instantâneo (oculta identificadores do aparelho)
linkctl raw info 0x13        # lê um seletor cru

Ligue o rastreamento com o vídeo já rodando

Este é o comportamento mais importante de entender, e o que mais confunde.

A câmera só aceita o comando enquanto está capturando vídeo. Escrito em repouso, o ajuste parece funcionar — a leitura de volta confirma na hora — mas o firmware o descarta cerca de um segundo depois, sem erro nenhum, e ele não sobrevive à captura seguinte. O procedimento certo, portanto, é:

  1. Abra primeiro o que vai usar a câmera: a reunião, o OBS, a gravação.
  2. Com o vídeo já rodando, execute linkctl tracking on.

Feito assim, o rastreamento engata em cerca de dois segundos e a câmera passa a lembrar da preferência: nas capturas seguintes ele volta sozinho, sem precisar repetir o comando.

O linkctl não confia na leitura imediata: ele escreve, espera o tempo de descarte e reconfere. Se o valor não sobreviveu, ele avisa em vez de mentir que deu certo, e sai com código 3 para que um script perceba que o ajuste não pegou.

Essa verificação empírica substituiu uma tentativa anterior de detectar o repouso pelo primeiro byte do seletor de modo. Não funciona: em repouso esse byte lê ora 0x00, ora 0xff, e não há sinal em banda confiável para "há captura em andamento".

Procedência do mapa de seletores

Os comandos proprietários trafegam por três unidades de extensão UVC. As GUIDs foram lidas dos descritores USB desta câmera; os seletores vêm de engenharia reversa da comunidade, e cada linha abaixo diz o quanto foi confirmado aqui.

Unidade GUID Papel
info FAF1672D-B71B-4793-8C91-7B1C9B7F95F8 modo, enquadramento, dados do aparelho
image E307E649-4618-A3FF-82FC-2D8B5F216773 papel não confirmado; 6 seletores responsivos
ai A8BD5DF2-1A98-474E-8DD0-D92672D194FA rastreamento por IA

A busca é sempre por GUID, nunca pelo número da unidade, porque o número pode mudar entre versões de firmware. Nesta câmera eles resolvem para 9, 10 e 11.

Recurso Onde Situação
Rastreamento por IA ai, seletor 0x02 Confirmado: o gimbal se moveu e travou no sujeito
Dados do aparelho info, seletor 0x03 Confirmado: série, UUID e firmware legíveis
Detecção do sujeito info, seletor 0x14 Confirmado: caixa coerente com alguém em quadro
Enquadramento info, seletor 0x13 Escrita aceita e lida de volta exata; efeito visual não validado
Formato do fluxo info, seletores 0x1c e 0x1d Confirmado, somente leitura: espelham largura, altura e taxa do fluxo ativo
Recentrar gimbal info, seletor 0x0E Só escrita, sem leitura de volta possível
Whiteboard, Overhead, DeskView info, seletor 0x02 Confirmado na gen 1: aceitos durante captura, com mudança estrutural medida na imagem
Exposição ver abaixo Não encontrada: nenhuma escrita testada surtiu efeito

O mapa de seletores vem do projeto de vrwallace, que o levantou monitorando o aplicativo oficial no Windows. Sem esse trabalho este projeto não existiria. O README de lá declara licença MIT, embora o repositório não traga um arquivo LICENSE. A ideia de manter as posições memorizadas do lado do programa, e não da câmera, também é de lá.

Outras fontes: fmontes/insta360-link-cli e a issue #55 do cameractrls.

O que descobrimos que contraria essas fontes

O seletor de modo (info 0x02) não deve ser escrito à mão para ligar o rastreamento. A câmera o atualiza sozinha para 0x01 quando começa a rastrear. Escrever nele produz apenas leituras enganosas, e por isso set_tracking toca somente a unidade de IA.

A escrita só é aceita durante uma captura de vídeo. Em repouso o firmware aceita a requisição sem erro, a leitura de volta confirma, e cerca de um segundo depois o valor volta ao anterior. Nenhum dos projetos existentes documenta isso, e é a explicação mais provável para relatos de "o comando não faz nada".

Exposição: um resultado negativo, medido

Na issue #55 do cameractrls, jorgecastro05 relatou em abril de 2025 ter localizado a exposição por captura de tráfego USB no aplicativo do Windows: unidade 9, seletor 0x19, valor de dois bytes little-endian, com 400, 500 e 640 surtindo efeito visível.

No firmware v1.4.3.8_build5 essa escrita não funciona. Testamos com o gimbal parado e a cena fixa, alternando 400 e 8000 em seis ciclos de quatro segundos e medindo a luminância média dos quadros. A luminância não acompanhou o valor escrito: ela decaiu de forma monótona de 72,9 para 28,4 e estabilizou, que é o comportamento do ganho automático assentando. A leitura de volta do seletor também nunca ecoa o que foi escrito e só decai, o que sugere telemetria e não um registrador gravável.

Isso não desmente o achado dele. As explicações plausíveis são firmware diferente, ou a necessidade de desligar antes a exposição automática por algum seletor que não localizamos. Fica registrado para quem for tentar de novo não repetir o mesmo caminho.

Os seletores 0x16 a 0x1e da unidade info existem e respondem, e nenhum deles está mapeado. Quem quiser investigar pode partir de linkctl dump.

Pan e tilt: a leitura obsoleta que parece defeito

pan_absolute e tilt_absolute funcionam bem, mas até a primeira escrita a câmera reporta um valor obsoleto e fora do intervalo — aqui, 34083580 num controle que vai de −522000 a 522000. Depois de uma escrita qualquer, a leitura passa a devolver exatamente o valor escrito.

Isso é fácil de confundir com leitura corrompida, e nós mesmos concluímos isso antes de testar direito. O linkctl detecta o valor fora do intervalo e explica o que fazer, em vez de repassar o número.

60 fps: onde procuramos e o que descartamos

Os seletores 0x1c e 0x1d da unidade info espelham o formato do fluxo ativo, o que confirmamos em quatro capturas diferentes:

Capturando 0x1c Decodificado
1280x720@30 00050000 d0020000 1e00 1280 × 720 @ 30
1920x1080@30 80070000 38040000 1e00 1920 × 1080 @ 30
3840x2160@24 000f0000 70080000 1800 3840 × 2160 @ 24
1280x960@25 00050000 c0030000 1900 1280 × 960 @ 25

O arranjo é largura em u32, altura em u32 e taxa em u16, tudo little-endian. Parecia a chave dos 60 fps, e não é: escrever 60 em 0x1d, escrever 1920x1080@60 em 0x1c e mexer em 0x16 são todos aceitos sem erro e não mudam nada — nem o valor lido de volta, nem a lista de formatos, nem o devnum do dispositivo, que continuaria igual se a câmera tivesse reenumerado. São telemetria.

Restam sem mapear os seletores 0x18, 0x1a, 0x1b e 0x1e da unidade info. Não fomos adiante por força bruta: os seletores 0x04 e 0x05 da unidade de IA são só-escrita, e mandar valor arbitrário para um seletor cego numa câmera não é experimento, é aposta.

Divergências em relação ao mapa do vrwallace

Duas, medidas na gen 1 com firmware v1.4.3.8_build5:

  • Seletor 20 é a caixa do sujeito, não o giroscópio. O mapa dele descreve 240 bytes de "IMU/gyroscope floats". Aqui o byte 0 vale 1 quando há alguém em quadro e 0 quando não há, e os quatro floats seguintes ficam sempre em [0,1], acompanham a pessoa ao se mover e obedecem a x+largura < 1 e y+altura < 1, com proporções de pessoa em pé. Um giroscópio não zeraria na ausência de gente nem ficaria confinado a [0,1].
  • O byte de flag do modo não é ecoado como escrito. Pedir Overhead (05 03) lê de volta 05 00; voltar a Normal (00 00) depois do DeskView lê 00 10. Quem determina o modo é o byte 0, e comparar o par leva a relatar "desconhecido" para um modo que está correto.

Limitações que não dá para contornar

Estas vêm do firmware e nenhum programa em Linux resolve:

  • Não existe controle de exposição pelo V4L2. O firmware não declara exposição no Camera Terminal (bmControls = 20 7a 02), então o kernel não tem o que expor. O mesmo vale para ganho, compensação de contraluz e gama.
  • Pan/Tilt Speed são desativados pelo kernel no arranque. A câmera anuncia o controle e depois recusa a requisição com erro de entrada e saída, e o uvcvideo registra UVC non compliance e o desativa em definitivo. Não há movimento suave de gimbal pelo V4L2.
  • 50 e 60 fps não aparecem. A especificação oficial da Link lista 1080p@50/60fps, e a câmera só oferece 24, 25 e 30 ao Linux. No Windows isso é uma chave do Link Controller que faz a câmera reenumerar. Procuramos o seletor e não achamos; veja abaixo o que já foi descartado.

Desenvolvimento

python3 -m unittest discover -s tests -t .   # 47 testes, sem hardware
python3 tests/generate_fixtures.py           # regenera os fixtures (exige a câmera)

A camada pura (protocol.py, usbdesc.py) é a única testada, e de propósito: é onde mora a lógica. As camadas xu.py e v4l2.py são invólucros finos de ioctl, cujo comportamento só se verifica contra o hardware de verdade.

Os valores esperados nos testes vêm de bytes capturados da câmera real, não recalculados pela implementação — do contrário o teste passaria por construção e não provaria nada.

About

Controle da webcam Insta360 Link no Linux — rastreamento por IA, gimbal e modos via unidades de extensão UVC. Python puro, sem dependências.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages