Nahrávame desktop

12.06.2021 | 05:26 | Mirecove dristy | Miroslav Bendík

V dnešnom blogu si ukážeme, ako nahrávať desktop s minimálnou záťažou CPU. Využijeme pritom hardvérový enkóder, ffmpeg a priame nahrávanie z GPU bez kopírovania obrazu do RAM.

Každý Intel CPU od mikroarchitektúry Sandy Bridge vyššie podporuje hardvérové enkódovanie video formátu h.264. Ak máme podporovaný hardvér je nahrávanie videa z desktopu pomocou ffmpeg hračkou. Stačí príkaz:

ffmpeg \
    -f kmsgrab \
    -i - \
    -vf 'hwmap=derive_device=vaapi,scale_vaapi=format=nv12' \
    -c:v h264_vaapi \
    vystup.mkv

Jednoduché, nie? Keby to fungovalo …

Vo väčšine distribúcií tento príkaz zlyhá, pretože ffmpeg nemá dostatočné práva. Príkaz musí byť buď spustený pod rootom, alebo ffmpegu musíme prideliť dodatočné práva (pozor, toto môže byť poriadna bezpečnostná diera do systému) príkazom spusteným pod rootom:

# setcap cap_sys_admin+ep `which ffmpeg`

Odobrať práva je možné rovnakým príkazom, akurát namiesto znamienka + sa použije znamienko -.

Než sa pustíme do zložitejších prípadov pozrieme sa na parametre príkazu ffmpeg. Začneme netradične v strede príkazu. Parameter -i - znamená, že vstupný súbor je stdin (štandardný vstup). My však nahrávame obrazovku, ktorá vstupný súbor nemá, takže tento parameter je síce ffmpegom vyžadovaný, ale nie je použitý.

Poradie parametrov vo ffmpegu hraje dôležitú úlohu. Parametre týkajúce sa vstupu sa vždy vzťahujú k nasledujúcemu vstupu, takže -f kmsgrab sa vzťahuje k vstupu -i -. V preklade to znamená: otvor súbor stdin a spracuj ho pomocou kmsgrab (nahrávanie z KMS subsystému). Keďže kmsgrab nepotrebuje vstupný súbor, zožerie prakticky čokoľvek, čo mu podhodíme, či už video súbor, alebo stdin.

Filter -vf 'hwmap=derive_device=vaapi,scale_vaapi=format=nv12' sa skladá z 2 častí. V prvej sa namapuje zariadenie typu vaapi do pamäte (hwmap=derive_device=vaapi) a následne sa použije škálovanie, orezanie a zmena formátu (scale_vaapi=format=nv12). Zatiaľ síce nahrávame celú obrazovku bez zmeny rozlíšenia, ale tento filter potrebujeme kvôli zmene formátu obrazu na nv12. Nebudem zachádzať do detailov, ale je dôležité si uvedomiť, že typický display má pixely uložené, ako hodnoty červenej, zelenej a modrej. Hardvérový enkóder však vyžaduje formát nv12 (podobný yuv420p), ktorý má pixely uložené ako jas pre každý pixel zvlášť a farbu pre bloky veľkosti 2x2 pixely. Takýto formát bol zavedený kvôli šetreniu prenosovej kapacity.

Uvedený príkaz na mojom notebooku z 2011 spotrebuje 2% procesorového času počas zobrazovania animovaného dema zo stránky shadertoy.com.

Zaťaženie CPU počas nahrávania
Obrázok 1: Zaťaženie CPU počas nahrávania

Výber oblasti

Oblasť nahrávania sa dá obmedziť video filtrom crop. Medzi filtre hwmap a scale_vaapi sa vloží filter crop=šírka:výška:vzdialenosť od ľavého okraja:vzdialenosť od horného okraja. Ak chcem napríklad nahrávať oblasť o veľkosti 800x600 pixelov umiestnenú 100 pixelov od ľavého okraja a 50 pixelov od horného okraja použijem crop=800:600:100:50. Obraz však bude deformovaný, pretože filter scale_vaapi bude meniť rozlíšenie vide na rovnaké, aké je rozlíšenie obrazovky. Je preto nutné ešte doplniť parametre w a h filtra scale_vaapi. Celý parameter filtra bude teda vyzerať takto:

-vf 'hwmap=derive_device=vaapi,crop=800:600:100:50,scale_vaapi=w=800:h=600:format=nv12'

Ako však postupovať keď máme viacej obrazoviek? Pred parameter -i stačí vložiť -crtc_id id obrazovky. Ako však zistiť ID obrazovky netuším. Ak niekto vloží do komentárov správny postup budem rád a rád ho sem doplním. Keďže správny postup nepoznám napíšem 2 spôsoby, ktorými to u mňa fungovalo.

Prvým je spustenie ffmpegu s parametrom -v debug a s náhodne zvoleným crtc_id:

$ ffmpeg \
  -f kmsgrab \
  -crtc_id 99999 \
  -i - \
  -vf 'hwmap=derive_device=vaapi,scale_vaapi=format=nv12' \
  -c:v h264_vaapi \
  -y /dev/null \
  -v debug
...
[AVHWDeviceContext @ 0x55fcf0bae720] Opened DRM device /dev/dri/card0: driver i915 version 1.6.0.
[kmsgrab @ 0x55fcf0bad940] Plane 31: CRTC 0 FB 0.
[kmsgrab @ 0x55fcf0bad940] Plane 35: CRTC 0 FB 0.
[kmsgrab @ 0x55fcf0bad940] Plane 41: CRTC 0 FB 0.
[kmsgrab @ 0x55fcf0bad940] Plane 46: CRTC 60 FB 99.
[kmsgrab @ 0x55fcf0bad940] Plane 50: CRTC 0 FB 0.
[kmsgrab @ 0x55fcf0bad940] Plane 56: CRTC 60 FB 102.

Z výpisu stačí už len uhádnuť, že správne číslo crtc_id je 60.

Okrem toho som na githube objavil repozitár drmtoy. Po kompilácii vznikne v adresári build/rel súbor enum. Stačí spustiť a vo výpise nájsť spávne ID:

$ ./enum
open = 4
drm version 1.6.0 driver=i915 date=20200917 desc=Intel Graphics
drm lib version 1.3.0 driver= date= desc=
busid=pci:0000:00:02.0
drmGetStats = 0
    count = 0
    count_fbs = 0
    count_crtcs = 2
        0: 0x2d
            buffer_id = 0x0 gamma_size = 256
            (0 0 0 0) 0
            mode.name =
        1: 0x3c
            buffer_id = 0x63 gamma_size = 256
            (0 0 1280 1024) 1
            mode.name =

Vo výpise vidíme crtc s rozlíšením 1280x1024px a ID 0x3c, čo je v desiatkovej sústave 60.

Pri použití viacerých grafických kariet môžme špecifikovať zariadenie, ktoré bude akcelerovať enkódovanie parametrom -vaapi_device /cest/k/zariadeniu napr. -vaapi_device /dev/dri/renderD128.

Kvalita

Začneme nastavením frekvencie snímkov. Pre vstup kmsgrab je štandardná hodnota 30 snímkov za sekundu. Ak by sme chceli napríklad 60 snímkov stačí pred parameter -i pridať -framerate 60, alebo skrátene -r 60.

Kvalita videa sa nastavuje argumentmi zadanými pred výstupným súborom. Môžme nastaviť buď konštantný dátový tok, alebo konštantnú kvalitu. Vo väčšine prípadov odporúčam konštantnú kvalitu.

Konštantná kvalita sa nastavuje argumentom -qp [1 - 52]. Najvyššia kvalita je 1, najnižišia je 52. Konštantný bitrate sa dá nastaviť parametrom -b:v bitrate napr. -b:v 10M. Kompletný príkaz pre nahrávanie kvalita v celkom slušne kvalite vyzerá takto:

ffmpeg \
  -framerate 60 \
  -f kmsgrab \
  -i - \
  -vf 'hwmap=derive_device=vaapi,scale_vaapi=format=nv12' \
  -c:v h264_vaapi \
  -qp 18 \
  video.mkv

Ďalšie parametre enkódera sa dajú zobraziť príkazom ffmpeg -h encoder=h264_vaapi.

Nenahráva sa kurzor

Pod X serverom sa kurzor renderuje zvyčajne ako hardvérový overlay nad framebufferom. Nahrávané video preto nebude obsahovať kurzor.

Na githube sa dá nájsť program swcursor, ktorý pod skutočným kurzorom zobrazuje veľký softvérový kurzor. Voči tomuto softvéru mám pár výhrad: kurzor nemení svoj tvar napr. na symbol I nad textom, má vysokú latenciu (pretože nepočúva na udalosti, ale namiesto toho používa polling), nepodporuje hotspot atď.

Napísal som preto vlastný softwarovo renderovaný kurzor, ktorý používa pixmapu z aktuálneho kurzora, nemá žiadne závislostí okrem xlibu a namiesto pollingu je plne riadený eventmi. Program stačí skompilovať (make), spustiť kompozitor a spustiť ./softwarecursor-x11. Ak je kurzor väčší než 32 pixelov je potrebné doplniť parameter -s veľkosť napr. -s 48. Veľkosť zvýraznenia sa určuje parametrom -r a štandardne má rovnakú veľkosť, ako je maximálna veľkosť kurzora.

Softvérový kurzor
Obrázok 2: Softvérový kurzor

Nahrávanie zvuku

Napriek minimálnemu použitiu CPU môže dochádzať k zahadzovaniu snímkov hlavne keď je GPU zaneprázdnená. Pre nahrávanie zvuku stačí použiť ako vstup zvukový server (napr. pulseaudio) a zapnúť vkladanie časových značiek do audia, aby bol zvuk synchronizovaný s obrazom. Synchronizácia sa zapína argumentom -af "asetpts=N/SR/TB". Kompletný príkaz vyzerá napríklad takto:

ffmpeg \
  -f pulse -i default \
  -framerate 60 \
  -thread_queue_size 128 \
  -f kmsgrab -i - \
  -af "asetpts=N/SR/TB" \
  -vf 'hwmap=derive_device=vaapi,scale_vaapi=format=nv12' \
  -c:a aac \
  -c:v h264_vaapi \
  video.mkv

Výsledok

Nasledujúce video som nahrával na svojom starom notebookvom i5-2520M (Sandy bridge). Pre efekt som GPU pekne vyťažil zbytočnými efektnmi.

Video nahrávané pomocou ffmpegu

    • RE: Nahrávame desktop 12.06.2021 | 09:02
      Avatar Livan Manjaro s XFCE  Používateľ

      Tak ma v súvislosti s tým nahrávaním napadli dve veci.

      • Ad 1. ako zistím pri nahrávaní okna rozmery a umiestnenie toho okna?
      • Ad. 2 nie som si istý, či by sa mi chcelo pri nahrávaní vypisovať také dlhé a komplikované príkazy.

      V ergonomike ovládania má ten program ešte čo doháňať.

      • RE: Nahrávame desktop 12.06.2021 | 12:33
        Avatar Miroslav Bendík Gentoo  Administrátor

        1. buď ručne pravítkom (screenshot + pravítko v grafickom editore), alebo napríklad príkazom xdotool selectwindow getwindowgeometry --shell a klik na okno

        2. nie je problém nabindovať ffmpeg na klávesovú skratku

    • RE: Nahrávame desktop 12.06.2021 | 09:39
      Avatar bedňa LegacyIce-antiX  Administrátor

      Dík to si nabindujem.

      Ja mám v antiXe cap_sys_admin+ep už nastavený by default, čo je na tom bezpečnostná diera?

      Táto správa neobsahuje vírus, pretože nepoužívam MS Windows. http://kernelultras.org
      • RE: Nahrávame desktop 12.06.2021 | 12:30
        Avatar Miroslav Bendík Gentoo  Administrátor

        Aplikácie s touto capability majú skoro root prístup (administrácia blokových zariadení je docela desivá).

        • RE: Nahrávame desktop 12.06.2021 | 19:00
          Avatar bedňa LegacyIce-antiX  Administrátor

          Tak keď to beží na desktope, nepokladám to za nič desivé, či sa mýlim? Väčšina systému mi beží pod rootom vrátane všetkých modulov a som tu :)

          Táto správa neobsahuje vírus, pretože nepoužívam MS Windows. http://kernelultras.org
          • RE: Nahrávame desktop 12.06.2021 | 20:32
            Avatar Miroslav Bendík Gentoo  Administrátor

            ffmpeg vie prehrávať internetové streamy, stačí vhodný bugfer overflow a útočník ľahko získa root práva

            • RE: Nahrávame desktop 12.06.2021 | 20:48
              Avatar bedňa LegacyIce-antiX  Administrátor

              Dobre mám antiX úplne všade, či doma, či v práci, poďme na to :)

              Táto správa neobsahuje vírus, pretože nepoužívam MS Windows. http://kernelultras.org
          • RE: Nahrávame desktop 12.06.2021 | 22:10
            Avatar samalama   Návštevník

            vidno, ze tomu rozumies...

    • RE: Nahrávame desktop 12.06.2021 | 12:41
      Avatar +debian+   Návštevník

      Nie je menej narocne nahodou: recordmydesktop

      • RE: Nahrávame desktop 12.06.2021 | 14:33
        Avatar Miroslav Bendík Gentoo  Administrátor

        Nie. Recordmydesktop ani pri polovičnom fps na full HD pod 5% CPU na stroji z roku 2011 nepôjde, nehovoriac o tom, že sa musí po nahrávaní enkódovať, zatiľ čo spomínané riešenie s ffmpegom enkóduje on fly. Dokonca sa dá aj priamo streamovať video s latenciou okolo 100ms, čo používam keď chcem niečo prezentovať a nemám kde zapojiť kábel, takže vysielam cez wifi.

      • RE: Nahrávame desktop 12.06.2021 | 15:56
        Avatar Miroslav Bendík Gentoo  Administrátor

        Takže vyskúšané recordmydesktop. S rovnakými podmienkami ako mal ffmpeg 2% CPU má recordmydesktop okolo 70% CPU. Disk 5MB / 5s s ffmpegom a 1.2GB / 5s s recordmydesktop (recordmydesktop komprimuje dobre, ak sú na obrazovke malé zmeny, ja som však spustil grafické demo). Neporovnateľné.

        • RE: Nahrávame desktop 12.06.2021 | 18:56
          Avatar bedňa LegacyIce-antiX  Administrátor

          RecordMyDesktop je stará šmejďárna a je škoda sa o nej baviť, používal som ju, ale srala ma vždy. Potom som začal používať vokoscreenNG a to tvoje riešenie mi príde najviac NAJVÁC dobré.

          Táto správa neobsahuje vírus, pretože nepoužívam MS Windows. http://kernelultras.org
        • RE: Nahrávame desktop 12.06.2021 | 19:30
          Avatar +debian+   Návštevník

          Pozeral si aj kvalitu vystupu, lebo tusim ten recordmydesktop tusim defaulne zabaluje do bezstratoveo kodeku, ci ako. Pride mi ze je lepsi ako .mkv.

          • RE: Nahrávame desktop 12.06.2021 | 20:28
            Avatar Miroslav Bendík Gentoo  Administrátor

            recordmydesktop ukladá v stratovej kompresii (theora). Mkv aj ogg sú len kontajnery, s kvalitou nemajú nič spoločné

            • RE: Nahrávame desktop 13.06.2021 | 02:46
              Avatar +debian+   Návštevník

              No, kvalitu - ak ulozis text v jpeg, tak to jemne rozmaze.

              • RE: Nahrávame desktop 13.06.2021 | 06:45
                Avatar Miroslav Bendík Gentoo  Administrátor

                Text v jpegu? Tu sa bavíme o kontajnejri. To je ako keby sme sa bavili o tom, či má obrázok zabalený v zip-e inú kvalitu než zabalený v tar.gz. Aj mkv aj ogg sú len kontajnery. Samozrejme recordmydesktop používa aj iný kodek, konkrétne theora, ale kvalita sa bude líšiť hlavne od použitého bitratu a použitého formátu pixelov (420p vs 444p).

          • RE: Nahrávame desktop 12.06.2021 | 22:12
            Avatar samalama   Návštevník

            vidno, ze tomu hovno rozumies...

        • RE: Nahrávame desktop 14.06.2021 | 09:12
          Avatar Branislav Poldauf Manjaro, Debian stable  Používateľ

          vidím že tu nikto nespomenul OBS studio, máš vyskúšané ako je tom ? lebo pokiaľ viem tiež dokáže využívať HW akceleráciu

          ja som ho používal na záznam kadejakých pochybných čínskych usb grabberov analógového signálu a bolo to jediné riešenie kde nebolo treba niečo bastliť, stačilo naklikať

          Linux: the operating system with a CLUE... Command Line User Environment
          • RE: Nahrávame desktop 14.06.2021 | 11:35
            Avatar Miroslav Bendík Gentoo  Administrátor

            Nepovedal by som, že je to jednoduchšie než moje súčasné riešenie typu Ctrl-Enter (otvorenie terminálu), Ctrl+R (hľadať v histórii príkazov), kms, Enter. Okrem toho na mojom hardvéri nepoužiteľné, keďže moja grafická karta nemá rozšírenie EGL_EXT_image_dma_buf_import.

            • RE: Nahrávame desktop 14.06.2021 | 12:42
              Avatar Branislav Poldauf Manjaro, Debian stable  Používateľ

              myslím že ak už si to raz rozlúskol určite je jednouchšie použiť to znovu ako to vždy nanovo nastavovať v nejakom klikátku

              len mne ak by mi to nešlo naklikať v OBS určite by som to nebastlil ako týpek v tom odkaze (alebo ako ty s tým kurzorom), kedže tomu prd rozumiem a vrchol mojich schopností je script čo spustí 3 jednoduché príkazy po sebe

              ja by som hľadal iné riešenie ktoré by fungovalo na pár klikov

              len ma zaujímala efektívnosť OBS studia, keďže recordmydesktop mal katastrofalny vysledok

              pokiaľ si dobre pamätám tak OBS na mojom hw malo zanedbateľnú "spotrebu" aj keď sa nejednalo o nahrávanie desktopu a spúšťal som to na pomerne výkonnom HW

              Linux: the operating system with a CLUE... Command Line User Environment
    • RE: Nahrávame desktop 12.06.2021 | 15:14
      Avatar Pavel Q4OS KDE  Administrátor

      Ja som lenivý na príkazy, radšej používam grafické nadstavby ako Kazam alebo vokoscreen Qt,,,