Pendrive da FSF com Arch

Categoria: Linux Publicado: Quarta, 29 Dezembro 2021 Escrito por Helio Loureiro

Cartão pendrive da FSF

No artigo a era do Arch Linux eu esqueci de comentar, mas segue aqui a menção honrosa ao cartão pendrive da FSF que funcionou maravilhosamente pra instalar o Arch.  Uma pena que eles não mencionem o suporte ao Arch, assim como não o fazem pro Debian, em usa página de Free distros.  O Arch não instala nada pra você.  Nem sugere.  Mas já faz anos que a FSF adotou uma postura anti-liberdade, onde o bloqueio de uso de firmwares têm de ser forçado goela abaixo do usuário pra ser aprovada.  Espero que isso mude em 2022 na FSF.

A era do Arch Linux

Categoria: Linux Publicado: Quarta, 29 Dezembro 2021 Escrito por Helio Loureiro

Já faz um certo tempo que venho acompanhando o Archlinux de perto.   Já tinha uma VM rodando pra testes.  Mas com a decisão da Steam de lançar o device de games steam deck baseado no Arch, eu realmente fiquei tentado a experimentar mais a fundo, como meu sistema principal no desktop.

Antes de mais nada vou deixar claro que como desktop eu não tenho somente um computador.  Tenho um gabinete desktop mesmo, que já descrevi anos atrás no artigo goosfraba, e tenho também o laptop de trabalho.  Eu geralmente passo mais tempo no laptop, que roda Ubuntu.  O meu desktop estava também com Ubuntu, mas rodando o 21.10.  E não tinha reclamações a respeito.  Mas faz um tempo que desejo sair do mundo Debian/Ubuntu por vários motivos.  De comunidade a questão de forma de participação.

Então aproveitando as férias que peguei nesse fim de ano, resolvi partir pra cima da instalação do Arch.   Peço antecipadamente desculpas por ser muita coisa em imagens, mas eu fiz registros dos passos e dificuldades de instalação atráves de imagens em posts no Twitter pra justamente descrever aqui.

Como o computador já roda Ubuntu com LVM, não precisei fazer muita coisa além de criar mais partições que seriam próprias do Arch.  Então simplesmente as criei assim:

lvcreate diskspace -L 10G -n archlinux-root
lvcreate diskspace -L 50G -n archlinux-usr
lvcreate diskspace -L 10G -n archlinux-var

E em teoria isso deveria ser o suficiente.  Parti pra instalação e o primeiro problema foi encontrar o pendrive pra dar boot na instalação do Arch.   Eu tinha criado o pendrive com o comando dd mas eu resolvi seguir à risca a instalação do Arch e refiz o pendrive novamente.

dd if=/usr/local/tmp/ISO/archlinux-2021.12.01-x86_64.iso of=/dev/sdc conv=fsync oflag=direct status=progress

Não que tivesse mudado muita coisa.  Eu precisei mexer nos parâmetros de boot da BIOS pra aceitar o pendrive.  Depois de algumas configurações extras que mais foram mais próximas ao vodoo, eis que consegui o tão almejado boot.

BIOS do computador mostrando opção "EUFI: USB Flash Disk"

O boot do Arch foi um passeio no parque.   Como ele não faz nada automático e você faz tudo manualmente bastou apenas formatar e montar as partições que eu já tinha criado pra seguir com a instalação.

Shell de instalação do Arch mostrando a montagem das partições.

Nos passos de instalação do grub e meio que empaquei.  Eu já tinha o grub instalado na partição UEFI e funcionando no Ubuntu.  Seria o caso de apenas adicionar uma nova entrada no grub.cfg?  E foi

menuentry 'Arch Linux' --class archlinux --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-16a93a2f-e4a6-4ab3-8eee-b33403509ed4' {
        recordfail
        load_video
        gfxmode $linux_gfx_mode
        insmod gzio
        if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
        insmod part_gpt
        insmod ext2
        set root='hd0,gpt2'
        if [ x$feature_platform_search_hint = xy ]; then
          search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2 --hint='hd0,gpt2'  bfc3c17e-d451-4c35-8c4a-f93b17436783
        else
          search --no-floppy --fs-uuid --set=root bfc3c17e-d451-4c35-8c4a-f93b17436783
        fi
        linux   /vmlinuz-linux root=/dev/mapper/diskspace-archlinux--root init=/usr/lib/systemd/systemd ro net.ifnames=0 biosdevname=0 iommu=pt showopts noquiet nosplash verbose
        initrd  /initramfs-linux.img
}

Com isso eu consegui deixar a opção de boot do Arch disponível.   Existe aí um pequeno problema, o tal elefante na sala: o que acontece quando o Ubuntu atualizar.  Eventualmente eu devo dar boot no Ubuntu e rodar algum upgrade de kernel.  Ao rodar o mkinitram, com certeza vai sobreescrever essa entrada.  Ainda não resolvi esse problema, mas por enquanto sigo usando somente Arch.

Menu do bootloader grub mostrando a opção de Arch Linux para boot.

Então a coisa foi mesmo fácil e bastou apenas apertar o <Enter>...

Boot do Arch quebrado por não encontrar init.

O que deu errado?  E aqui eu comecei a entender um pouco mais do Arch além da superfície.  E essa era meu objetivo desde o início.  Pra entender o problema é preciso olhar como são os diretórios dentro do Arch primeiro.

root@goosfraba /u/bin# ls -l /
total 28
lrwxrwxrwx   1 root root    7 Dec  7 03:41 bin -> usr/bin
drwxr-xr-x   5 root root 4096 Dec 27 21:51 boot
drwxr-xr-x  23 root root 4600 Dec 29 00:12 dev
drwxr-xr-x   3 root root 4096 Jan  1  1970 efi
drwxr-xr-x  90 root root 8192 Dec 29 13:48 etc
drwxr-xr-x  35 root root 4096 Jun  9  2020 home
lrwxrwxrwx   1 root root    7 Dec  7 03:41 lib -> usr/lib
lrwxrwxrwx   1 root root    7 Dec  7 03:41 lib64 -> usr/lib
drwxr-xr-x   2 root root    6 Dec  7 03:41 mnt
drwxr-xr-x  11 root root  154 Dec 29 13:48 opt
dr-xr-xr-x 437 root root    0 Dec 27 21:59 proc
drwxr-x---  14 root root  239 Dec 29 13:27 root
drwxr-xr-x  26 root root  740 Dec 29 00:45 run
lrwxrwxrwx   1 root root    7 Dec  7 03:41 sbin -> usr/bin
drwxr-xr-x   4 root root   29 Dec 27 21:17 srv
dr-xr-xr-x  13 root root    0 Dec 27 21:59 sys
drwxrwxrwt  24 root root 4096 Dec 29 13:48 tmp
drwxr-xr-x  23 root root  332 Jun 19  2018 ubuntu
drwxr-xr-x   9 root root  118 Dec 29 13:48 usr
drwxr-xr-x  14 root root  201 Dec 29 12:58 var

O Arch não tem /bin, /sbin, /lib e /lib64.  Ele joga todos os executáveis em /usr/bin e todas as libs em /usr/lib.  Isso talvez facilite algum tipo de manutenção, mas quebra o princípio de que pra dar boot todo o necessário deveria estar em /bin pra executáveis de usuário e /sbin pra executáveis de root.  Assim como a libc em /lib.  O problema foi que eu tinha criado uma partição /dev/devicemapper/diskspace-arch--usr e montado no /usr, que não é passada no boot, que pede somente a partição root.

Então tive de replanejar minha instalação aumentando a partição raiz e removendo a partição que abrigava o /usr.

Mostrando como aumentar a partição usando LVM and XFS.

E finalmente copiar os dados do que era /usr.

Passos pra migrar o /usr antigo pra um novo.

E finalmente remover a partição criada pra abrigar originalmente o /usr.

Removendo um partição lógica no LVM.

Com isso eu pude finalmente dar boot no Arch e subir o KDE plasma.

Imagem do ambiente desktop KDE Plasma

Mas foi só isso.  Não consegui mexer em mais nada.  O que deu errado?  Primeiramente foi a escolha de KDE que fiz durante a etapa do pacstrap.  Eu escolhi o plasma-desktop e o mesmo não vem completo, o certo era plasma-meta.  Não tinha um shell pra eu abrir como o gnome-terminal nem konsole.  E como habilitei o sddm, então não conseguia voltar pro console virtual usando <ctrl>+<alt>+<F1>.   Fiquei empacado.  E precisei novamente dar boot pelo pendrive pra corrigir isso.

E consegui subir meu ambiente da mesma forma que antes.  Apenas re-criei meu usuário com mesmo UID e GID e montei a mesma partição /home que era do Ubuntu.  Transparentemente.

neofetch logo após a instalação

neofetch com as fontes corrigidas

É nítida a diferença do primeiro screenshot do neofetch pro segundo, em como as fontes melhoraram.  Aos poucos vou instalando e habilitando aquilo que preciso no Arch.

Ambiente desktop (2 telas) com aplicativos funcionando.

Eu de cara já sai com alguns extras funcionando sem mexer, como o Google Chrome, que aparece na imagem do desktop.  Como estava na partição /opt, eu simplesmente montei e re-usei.  Instalei o programa yay pra baixar pacotes faltando como steam e spotify.  Ambos já instalados.  E aos poucos vou arrumando a casa.

Um dos problemas que encontrei foi que minha partição de jogos da steam não aparecia disponível.  Mas estava lá no comando lvs:

root@goosfraba /u/bin# lvs 
 LV                    VG        Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
 archlinux-root        diskspace -wi-ao----  60.00g                                                     
 archlinux-var         diskspace -wi-ao----  10.00g                                                     
 debian                diskspace -wi-a-----  10.00g                                                     
 docker                diskspace -wi-ao----  30.00g                                                     
 home                  diskspace -wi-ao---- 500.00g                                                     
 linux-arch            diskspace -wi-a-----  20.00g                                                     
 opt                   diskspace -wi-ao----   4.00g                                                     
 root                  diskspace -wi-ao----  10.00g                                                     
 steam                 diskspace rwi-aor--- 750.00g                                    100.00           
 swap                  diskspace -wi-a-----  15.00g                                                     
 tmp                   diskspace -wi-ao----   5.00g                                                     
 usr                   diskspace -wi-ao----  95.00g                                                     
 usrlocal              diskspace -wi-ao---- 600.00g                                                     
 var                   diskspace -wi-a-----  50.00g                                                    

O problema era que precisava ativar a partição, que faz mirroring entre os dois HDs que tenho.  Bastou fazer o comando:

lvchange -a y /dev/diskspace/steam

 E meu steam passou a funcionar de novo. 

E como eu já deixei o docker em um partição só sua, bastou montar pra ter novamente os containers que uso disponíveis no Arch.

root@goosfraba /u/bin# docker images 
REPOSITORY            TAG       IMAGE ID       CREATED        SIZE
debian                11.0      6c97952ad9c0   6 days ago     626MB
theiaide/theia-full   latest    de7823cee314   2 months ago   11.5GB
debian                <none>    a178460bae57   3 months ago   124MB
theiaide/theia-full   <none>    9c178198e255   3 months ago   8.86GB

No arch já sai com o python 3.10 funcionando. 

Tela de ipython mostrando versão 3.10.1 do python.

E pra minha surpresa a instalação do suporte à NVIDIA foi fácil e tranquilo.  Mais que no Ubuntu.

Tela do NVIDIA X Server Settings mostrando que está ativa.

Como foi possível ver é bem divertido o uso do Arch e resgata um pouco daquele espírito hacker de fuçar no seu sistema operacional pra ter tudo funcionando.  Eu estou gostando da experiência por equanto.  Acho que agora já posso fazer como o Kretcheu, se bem que Debian eu já não uso faz alguns anos.

Modificando um livecd de Ubuntu

Categoria: Linux Publicado: Sábado, 11 Dezembro 2021 Escrito por Helio Loureiro

Não é sempre que preciso fazer dessas coisas, mas recentemente precisei mexer num disco de livecd do Ubuntu que estava em formato iso pra alterar algumas coisa.

Então aqui fica receita de como fazer isso (dependendo do que deseja fazer, claro).

Primeiro eu tenho dois diretórios que uso pra montagem dos filesystems.  Os /cdrom e /mnt.  Como já uso desse forma faz anos, não sei se são criados por padrão no Ubuntu ou outro sistemas.  Então se for copiar o que descrevo aqui, tenha certeza que esses diretórios existem.  Outro ponto importante é que rodo todos os comandos como root.

Então o começo de tudo é montar a imagem do Ubuntu no diretório desejado.

root@goosfraba /# mount -t iso9660 -o loop ubuntu-20.04.03-desktop-amd64.iso /cdrom

Esse conteúdo precisa ser copiado  pra um diretório temporário.

root@goosfraba /# mkdir /tmp/temp-cdrom
root@goosfraba /# cd /tmp/temp-cdrom
root@goosfraba /t/temp-cdrom# tar cvf - -C /cdrom . | tar xvf -

Existe o arquivo casper/filesystem.squashfs que é o filesystem do livecd.  Você pode montar esse disco com o seguinte comando (e aqui entra o /mnt que comentei antes):

root@goosfraba /t/temp-cdrom# mount -t squashfs -o loop /tmp/temp-cdrom/casper/filesystem.squashfs /mnt

mas esse disco é apenas read-only.  Pra modificar é preciso usar a ferramenta unsquashfs que faz parte do pacote squashfs-tools.

root@goosfraba /t/temp-cdrom# mkdir /tmp/squashfs
root@goosfraba /t/temp-cdrom# cd /tmp/squashfs
root@goosfraba /t/squashfs# unsquashfs /tmp/temp-cdrom/casper/filesystem.squashfs
Parallel unsquashfs: Using 8 processors
185020 inodes (205968 blocks) to write
[=================================================================================================================================================================/] 205968/205968 100%
created 155722 files
created 19319 directories
created 29184 symlinks
created 8 devices
created 0 fifos

root@goosfraba /t/squashfs# ls squashfs-root/
bin@  boot/  dev/  etc/  home/  lib@  lib32@  lib64@  libx32@  media/  mnt/  opt/  proc/  root/  run/  sbin@  snap/  srv/  sys/  tmp/  usr/  var/

Daí sim fazer as modificações desejadas.

Ao terminar é preciso gerar a imagem no formato squashfs novamente, agora usando o mksquashfs.  Prepare-se pra ir fazer um café ou assistir um filme pois o processo demora bastante nesse passo.

root@goosfraba /t/squashfs# mksquashfs squashfs-root /tmp/temp-cdrom/casper/filesystem.squashfs -b 1024k -comp xz -Xbcj x86 -e boot
Parallel mksquashfs: Using 8 processors
Creating 4.0 filesystem on /tmp/temp-cdrom/casper/filesystem.squashfs, block size 1048576. [=================================================================================================================================================================/] 149629/149629 100%

Exportable Squashfs 4.0 filesystem, xz compressed, data block size 1048576
        compressed data, compressed metadata, compressed fragments,
        compressed xattrs, compressed ids
        duplicates are removed
Filesystem size 1695376.64 Kbytes (1655.64 Mbytes)
        32.81% of uncompressed filesystem size (5167137.40 Kbytes)
Inode table size 1550743 bytes (1514.40 Kbytes)
        20.75% of uncompressed inode table size (7473067 bytes)
Directory table size 1819524 bytes (1776.88 Kbytes)
        36.53% of uncompressed directory table size (4981005 bytes)
Xattr table size 98 bytes (0.10 Kbytes)
        81.67% of uncompressed xattr table size (120 bytes)
Number of duplicate files found 18577
Number of inodes 204220
Number of files 155715
Number of fragments 2275
Number of symbolic links  29180
Number of device nodes 8
Number of fifo nodes 0
Number of socket nodes 0
Number of directories 19317
Number of ids (unique uids + gids) 37
Number of uids 15
        root (0)
        ntp (126)
        dnsmasq (112)
        saned (119)
        speech-dispatcher (114)
        systemd-timesync (100)
        _apt (105)
        rtkit (118)
        messagebus (106)
        man (6)
        postfix (125)
        whoopsie (109)
        sshd (121)
        sddm (122)
        syslog (104)
Number of gids 28
        root (0)
        dip (30)
        shadow (42)
        lpadmin (113)
        rtkit (126)
        mysql (131)
        nogroup (65534)
        lp (7)
        audio (29)
        systemd-timesync (102)
        utmp (43)
        tty (5)
        geoclue (105)
        _ssh (118)
        input (106)
        mail (8)
        staff (50)
        avahi (120)
        man (12)
        pulse-access (125)
        whoopsie (116)
        munin (130)
        saned (127)
        pulse (124)
        uuidd (111)
        systemd-journal (101)
        adm (4)
        messagebus (110)

E o último passo é gerar o disco bootável.  Pra isso eu usei o genisoimage:

root@goosfraba /tmp# genisoimage -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -r -J -o /tmp/ubuntu-20.04.03-modificado-desktop-amd64.iso /tmp/temp-cdrom

Com isso a image iso ubuntu-20.04.03-modificado-desktop-amd64.iso é gerada.

Resgatando a chave pública de um perfil no Jenkins

Categoria: Linux Publicado: Terça, 09 Novembro 2021 Escrito por Helio Loureiro

Pode parecer meio estranho, mas foi isso mesmo que precisei fazer: pegar a chave pública de ssh de um perfil que estava no jenkins pra configurar o acesso num repositório Gitlab.

Mas o Jenkins, sabiamente, não guarda ou mostra essas credenciais pra você.  Então precisei recorrer a meios não muito convencionais pra fazer isso.

Primeiro fooi pegar a chave privada que ele tinha armazenado.  Pra isso encontrei uma receita de bolo, escrita em Groovy.

https://scriptcrunch.com/groovy-script-retrieve-jenkins-credentials/


import jenkins.*
import jenkins.model.* 
import hudson.*
import hudson.model.*
def jenkinsCredentials = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
        com.cloudbees.plugins.credentials.Credentials.class,
        Jenkins.instance,
        null,
        null
);
for (creds in jenkinsCredentials) {
    // descomente essa parte abaixo se precisar de mais detalhes
    //println(jenkinsCredentials.id)
    println(creds.username))
    if(creds.id == "2671e11a-4831-fa3f-0d58-7b331318c04d"){
    	println(creds.privateKey)
    }
}

E pra rodar junto ao Jenkins, na área de scripts.  Se não sabia ainda, é possível rodar script pela interface web atráves da url que tem do Jenkins mais o final "/script".

No laço "if" onde olho se o creds.id bate com um número gigante, esse é o identificador que você vê como ID nas credenciais.

Esse foi o resultado:


user1
user2
user3
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAyONzf1Ti1Dv8jI68/oyGJ2Gf6CNkN64ncZAVB5QnR+0NbyzN
G9U6uFqKUoSuuYblqANJNGR3PKCVhCJCB6Ge7azPK10eYEHFyYXGuIwi9Rb3MsjN
Cof57NzenIUcErm0Cuxk34xEXdR5UFm8GI0q3MEuBSwopQfAnfGa5L+QxGt/+YuY
ei/n/V0QsgYuZb9RVF2NbTrNLk09vBQ7SVwyDzKBaaGFkO0uh6fvCz/gq8L+f9cL
Z/twZNy1/Z13VSe2Agd/1ErLBqlTrxabPCFPMWm4YiAAwIUqhwaI6GU7IRLo/HWo
9eqfvYUWh6FyBKRf7bdSdWfWSSTNxgwPCfJavQIDAQABAoIBADjjaG6znDSb9C3d
shmns8ntNHppo1S9RcA8HCh0RRdyQu6r0j3CiYlxYmBx4IT7dYe5vn5OwRFzLEQp
62b71uTZniVajmKV3avu7VKPpMqhQUmpYZ9M2HLCLWxHqaaH3juFrB8+OpITvHML
pl+RgoTXU+/1DGGHq31O0R1cPmPQyRDhaxVpzsYwbCcIYGJ1hjz2g+098LwtIr5W
5i2Z6JUpE6GyXlVZAM1f9tsYWgGGEBqbH4frUjH9Ao1F7dKARDHsiwcjbreywBx1
aVk8AsTP31vqdOJgUJC9JcM/cf2GLUQxg7ZjdDTrTPWnNzWFhALoFe79UKw4lhE7
ezrqi0UCgYEA457BTvaKI+pcxuh5waV1SrfBYDC9czZpYht1R1i3lmYJKdQFHtVl
HAoy18zuYec9MaNPdqbzWysqkH6D6R8T/qdogQ9/5XpSnPVGbsg2IRKq4jNPrh1M
y8Kx2SOYpk6eLtPxYeRHaAKv/GYbQMs8Sh+GNkSiudhTEESj+KKhmO8CgYEA4e93
phLCmzP+SI2pgqFkZ2H2R5X8aCkbuV7pdcnTb4T/rH0Zah2vFEOmjWaUaGHJDOWk
6y+JPzWmxdweb+2FKTg1g6m8ig1DazcmkTG0CEWwwDLJ93LiQYl59uXt2UuQSkj6
Be+JcUzY2w1lhD0+vNfVF/RrH+xTaYfze1PiDxMCgYBtHNUdvSFLRjVjRF3Zbi9j
ueKA8dxfNl4eIXt+0BBxkEgkPPaXaUQmxNzKhfpgBDFZcifNgQp3UaH90if5wGQd
VrLJ61wr7Q9dHla9FEyeXgx8koxHstP1eUc4B9BNKLK7T+4ONxfjzCYAoBHAZaxo
++OicBRxcjmfOsg/j/ZXEQKBgQDZS84gfJSMXsIml5C7YWvGfpI2IUukBj1y2JTi
w1zGOf0IsTybMbdsXvA1uL3tcnbCH6+wvoRatcgTLfRcI+3ZSgU1/y6k+8KmwGEo
bcw/1H79KxvSEL0I2SbjThqmzaUVvQAya0IeJRHABC9pstm/GDoLkvjguBM1QRrs
ty2I3wKBgEBRpeSp/07x6LaIqHULNuV515BqtvWmWQuc8ngMOkcOO1mcQ745VbDj
YO0pIFHmK1iCtrXhyKPxOOitBjiQOZTeR6cZehm/7Mg+LWR6qdloqOOOij//WND6
PEeIskhUu6Dg07S91meHs3u/TRL0Gmr+zjCIn/0P40O38iyZTaVK
-----END RSA PRIVATE KEY-----
user4
user5
user6

De posse da chave privada, foi então questão de salvar em arquivo, que chamei de jenkins, e gerar a chave pública a partir dela.

Achei que o openssl iria fazer isso, mas todas as tentativas foram frustradas.  No fim descobri como resolver com o próprio ssh-keygen olhando no stackoverflow, sempre ele pra nos ajudar:

https://stackoverflow.com/questions/10271197/how-to-extract-public-key-using-openssl


> ssh-keygen -y -f jenkins
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABA
AABAQDI43N/VOLUO/yMjrz+jIYnYZ/oI2Q3ridxkBUHlCdH7Q1vLM0b1Tq4W
opShK65huWoA0k0ZHc8oJWEIkIHoZ7trM8rXR5gQcXJhca4jCL1FvcyyM0Kh
/ns3N6chRwSubQK7GTfjERd1HlQWbwYjSrcwS4FLCilB8Cd8Zrkv5DEa3/5i
5h6L+f9XRCyBi5lv1FUXY1tOs0uTT28FDtJXDIPMoFpoYWQ7S6Hp+8LP+Crw
v5/1wtn+3Bk3LX9nXdVJ7YCB3/USssGqVOvFps8IU8xabhiIADAhSqHBojoZ
TshEuj8daj16p+9hRaHoXIEpF/tt1J1Z9ZJJM3GDA8J8lq9

e foi assim que consegui conectar o Jenkins usando o user3 com chave ssh no Gitlab.  Peço desculpas em ter quebrado a chave em 60 colunas aqui, mas o fiz pra que ficasse bom pra ler também em smartphones.

AVISO: todos os dados aqui não são os verdadeiros.  Antes de alguém perder tempo usando isso pra tentar invadir alguma coisa minha, eu gerei tanto o ID com sha256sum da data atual e preenchi pra parecer o ID do Jenkins quanto a chave privada, que gerei também só pra mostrar aqui.  Nada disso está em uso em lugar algum.

Usando a GPU para renderizar vídeo

Categoria: Linux Publicado: Domingo, 31 Outubro 2021 Escrito por Helio Loureiro

Durante a útima gravação do Unix Load On, Ingo comentou sobre aceleração de hardware via VAAPI.  Eu imaginava que isso apenas era possível com GPUs da NVIDIA, mas depois que ele comentou sobre VAPI rodando em Intel, fui atrás de como isso funcionava.

Então fiz o teste de criar um vídeo a partir das imagens que fiz da troca de pneus da bicicleta pros de inverno.

O primeiro foi usando a CPU.

  $ rm -f out.mp4; time ffmpeg -r 60 -i image-%03d.jpg -c:v libx264 -vf fps=60 -pix_fmt yuv420p out.mp4                                                                                                          
  ffmpeg version 3.4.8-0ubuntu0.2 Copyright (c) 2000-2020 the FFmpeg developers
    built with gcc 7 (Ubuntu 7.5.0-3ubuntu1~18.04)
    configuration: --prefix=/usr --extra-version=0ubuntu0.2
    --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu
    --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --disable-stripping
    --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa
    --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca
    --enable-libcdio --enable-libflite --enable-libfontconfig
    --enable-libfreetype --enable-libfribidi --enable-libgme
    --enable-libgsm --enable-libmp3lame --enable-libmysofa
    --enable-libopenjpeg --enable-libopenmpt --enable-libopus
    --enable-libpulse --enable-librubberband --enable-librsvg
    --enable-libshine --enable-libsnappy --enable-libsoxr
    --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame
    --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp
    --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq
    --enable-libzvbi --enable-omx --enable-openal --enable-opengl
    --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883
    --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264
    --enable-shared
    libavutil      55. 78.100 / 55. 78.100
    libavcodec     57.107.100 / 57.107.100
    libavformat    57. 83.100 / 57. 83.100
    libavdevice    57. 10.100 / 57. 10.100
    libavfilter     6.107.100 /  6.107.100
    libavresample   3.  7.  0 /  3.  7.  0
    libswscale      4.  8.100 /  4.  8.100
    libswresample   2.  9.100 /  2.  9.100
    libpostproc    54.  7.100 / 54.  7.100
  Input #0, image2, from 'image-%03d.jpg':
    Duration: 00:00:25.24, start: 0.000000, bitrate: N/A
      Stream #0:0: Video: mjpeg, yuvj420p(pc, bt470bg/unknown/unknown),
      4000x3000 [SAR 1:1 DAR 4:3], 25 fps, 25 tbr, 25 tbn, 25 tbc
  Stream mapping:
    Stream #0:0 -> #0:0 (mjpeg (native) -> h264 (libx264))
  Press [q] to stop, [?] for help
  [swscaler @ 0x56448c3106c0] deprecated pixel format used, make sure you did set range correctly
  [libx264 @ 0x56448c268ee0] using SAR=1/1
  [libx264 @ 0x56448c268ee0] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
  [libx264 @ 0x56448c268ee0] profile High, level 6.0
  [libx264 @ 0x56448c268ee0] 264 - core 152 r2854 e9a5903 - H.264/MPEG-4
  AVC codec - Copyleft 2003-2017 - http://www.videolan.org/x264.html -
  options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7
  psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1
  8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=6
  lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0
  bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1
  b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25
  scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0
  qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
  Output #0, mp4, to 'out.mp4':
    Metadata:
      encoder         : Lavf57.83.100
      Stream #0:0: Video: h264 (libx264) (avc1 / 0x31637661), yuv420p,
      4000x3000 [SAR 1:1 DAR 4:3], q=-1--1, 60 fps, 15360 tbn, 60 tbc
      Metadata:
        encoder         : Lavc57.107.100 libx264
      Side data:
        cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: -1
  frame=  631 fps=1.1 q=-1.0 Lsize=   64381kB time=00:00:10.46 bitrate=50388.8kbits/s speed=0.0188x
  video:64372kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.013232%
  [libx264 @ 0x56448c268ee0] frame I:11    Avg QP:23.13  size:216485
  [libx264 @ 0x56448c268ee0] frame P:236   Avg QP:25.43  size:133712
  [libx264 @ 0x56448c268ee0] frame B:384   Avg QP:25.38  size: 83278
  [libx264 @ 0x56448c268ee0] consecutive B-frames: 14.1% 11.7%  7.6% 66.6%
  [libx264 @ 0x56448c268ee0] mb I  I16..4: 16.8% 81.8%  1.4%
  [libx264 @ 0x56448c268ee0] mb P  I16..4: 24.8% 44.9%  0.4%  P16..4:
  16.1%  1.8%  0.9%  0.0%  0.0%    skip:11.1%
  [libx264 @ 0x56448c268ee0] mb B  I16..4: 12.5% 18.4%  0.1%  B16..8:
  21.0%  2.2%  0.3%  direct: 2.5%  skip:43.1%  L0:50.8% L1:46.8% BI: 2.4%
  [libx264 @ 0x56448c268ee0] 8x8 transform intra:62.8% inter:92.5%
  [libx264 @ 0x56448c268ee0] coded y,uvDC,uvAC intra: 29.1% 18.4% 0.7% inter: 11.4% 16.9% 0.1%
  [libx264 @ 0x56448c268ee0] i16 v,h,dc,p: 41% 27% 23%  9%
  [libx264 @ 0x56448c268ee0] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 29% 22% 42%  2%  1%  1%  1%  1%  1%
  [libx264 @ 0x56448c268ee0] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 31% 17% 19%  6%  6%  6%  6%  5%  3%
  [libx264 @ 0x56448c268ee0] i8c dc,h,v,p: 66% 16% 18%  1%
  [libx264 @ 0x56448c268ee0] Weighted P-Frames: Y:33.5% UV:16.5%
  [libx264 @ 0x56448c268ee0] ref P L0: 40.1% 13.1% 23.2% 17.1%  6.5%
  [libx264 @ 0x56448c268ee0] ref B L0: 59.5% 30.9%  9.6%
  [libx264 @ 0x56448c268ee0] ref B L1: 83.0% 17.0%
  [libx264 @ 0x56448c268ee0] kb/s:50142.36
  1190.99user 25.61system 9:17.29elapsed 218%CPU (0avgtext+0avgdata 2714684maxresident)k
  117280inputs+128944outputs (45major+630483minor)pagefaults 0swaps

9 minutos e 17 segundos.  Usando 218% de CPU, de um laptop com 4 CPUs.  Esse é o funcionamento normal.

E usando a GPU pra isso?  Eu demorei um pouco pra acertar os parâmetros pra usar a VAAPI, mas no fim deu certo.

  $ rm -f out.mp4; time ffmpeg -vaapi_device /dev/dri/renderD128 -r 60 -i image-%03d.jpg -vf 'format=nv12,hwupload,fps=60' -c:v h264_vaapi  -pix_fmt vaapi_vld out.mp4                                           
  ffmpeg version 3.4.8-0ubuntu0.2 Copyright (c) 2000-2020 the FFmpeg developers
    built with gcc 7 (Ubuntu 7.5.0-3ubuntu1~18.04)
    configuration: --prefix=/usr --extra-version=0ubuntu0.2
    --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu
    --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --disable-stripping
    --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa
    --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca
    --enable-libcdio --enable-libflite --enable-libfontconfig
    --enable-libfreetype --enable-libfribidi --enable-libgme
    --enable-libgsm --enable-libmp3lame --enable-libmysofa
    --enable-libopenjpeg --enable-libopenmpt --enable-libopus
    --enable-libpulse --enable-librubberband --enable-librsvg
    --enable-libshine --enable-libsnappy --enable-libsoxr
    --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame
    --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp
    --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq
    --enable-libzvbi --enable-omx --enable-openal --enable-opengl
    --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883
    --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264
    --enable-shared
    libavutil      55. 78.100 / 55. 78.100
    libavcodec     57.107.100 / 57.107.100
    libavformat    57. 83.100 / 57. 83.100
    libavdevice    57. 10.100 / 57. 10.100
    libavfilter     6.107.100 /  6.107.100
    libavresample   3.  7.  0 /  3.  7.  0
    libswscale      4.  8.100 /  4.  8.100
    libswresample   2.  9.100 /  2.  9.100
    libpostproc    54.  7.100 / 54.  7.100
  Input #0, image2, from 'image-%03d.jpg':
    Duration: 00:00:25.24, start: 0.000000, bitrate: N/A
      Stream #0:0: Video: mjpeg, yuvj420p(pc, bt470bg/unknown/unknown),
      4000x3000 [SAR 1:1 DAR 4:3], 25 fps, 25 tbr, 25 tbn, 25 tbc
  Stream mapping:
    Stream #0:0 -> #0:0 (mjpeg (native) -> h264 (h264_vaapi))
  Press [q] to stop, [?] for help
  [swscaler @ 0x5577c4cfb3c0] deprecated pixel format used, make sure you did set range correctly
  Output #0, mp4, to 'out.mp4':
    Metadata:
      encoder         : Lavf57.83.100
      Stream #0:0: Video: h264 (h264_vaapi) (High) (avc1 / 0x31637661),
      vaapi_vld, 4000x3000 [SAR 1:1 DAR 4:3], q=0-31, 60 fps, 15360 tbn,
      60 tbc
      Metadata:
        encoder         : Lavc57.107.100 h264_vaapi
  frame=  631 fps=9.3 q=-0.0 Lsize=  133604kB time=00:00:10.48
  bitrate=104401.7kbits/s speed=0.154x
  video:133596kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB
  muxing overhead: 0.006032%
  59.94user 1.03system 1:08.18elapsed 89%CPU (0avgtext+0avgdata 120480maxresident)k
  3504inputs+267264outputs (0major+44766minor)pagefaults 0swaps

Resultado?  1 minuto e 08 segundos.  Incrível.  Usou 89% de CPU, o que significa que das 4 CPUs, uma somente ficou ocupada.  E não 100%, apenas 90%.

Realmente incrível.

Não são todos os formatos de vídeo que são suportados, mas pra ter esse desempenho acho que vale sacrificar os formatos pra gerar um simples mp4.

 UPDATE: 2021-11-01.  O vídeo que renderizei pros testes.