Nahrávame desktop
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.
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.
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.
Pre pridávanie komentárov sa musíte prihlásiť.
Tak ma v súvislosti s tým nahrávaním napadli dve veci.
V ergonomike ovládania má ten program ešte čo doháňať.
1. buď ručne pravítkom (screenshot + pravítko v grafickom editore), alebo napríklad príkazom
xdotool selectwindow getwindowgeometry --shell
a klik na okno2. nie je problém nabindovať ffmpeg na klávesovú skratku
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?
Aplikácie s touto capability majú skoro root prístup (administrácia blokových zariadení je docela desivá).
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 :)
ffmpeg vie prehrávať internetové streamy, stačí vhodný bugfer overflow a útočník ľahko získa root práva
Dobre mám antiX úplne všade, či doma, či v práci, poďme na to :)
vidno, ze tomu rozumies...
Nie je menej narocne nahodou: recordmydesktop
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.
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é.
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é.
Pozeral si aj kvalitu vystupu, lebo tusim ten recordmydesktop tusim defaulne zabaluje do bezstratoveo kodeku, ci ako. Pride mi ze je lepsi ako .mkv.
recordmydesktop ukladá v stratovej kompresii (theora). Mkv aj ogg sú len kontajnery, s kvalitou nemajú nič spoločné
No, kvalitu - ak ulozis text v jpeg, tak to jemne rozmaze.
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).
vidno, ze tomu hovno rozumies...
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ť
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.
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
Ja som lenivý na príkazy, radšej používam grafické nadstavby ako Kazam alebo vokoscreen Qt,,,