Portál AbcLinuxu, 5. května 2025 09:09
Ahojte. Mám 32-bitový lineárny float point výstup z OpenGL (áno som si na 100% istý, že je lineárny). Chcel by som z toho uploadnúť video na Youtube s 10-bitovou hĺbkou pretože 8 bitov vyzerá v tmavých odtieňoch hrozne.
Teraz moje neúspešné pokusy (screenshoty sú v priloženom obrázku, horný riadok je výstup z OpenGL).
Takže tento príkaz vyzerá na desktope OK a má 12 bitový výstup, ale youtube ho prevedie na 8 bit:
# 1 ffmpeg \ -r 60 \ -f rawvideo \ -s 1920x1080 \ -pix_fmt gbrpf32le \ -color_range pc \ -color_trc linear \ -color_primaries bt2020 \ -colorspace bt2020nc \ -i pipe:0 \ -y \ -crf 18 \ -c:v libx265 \ -c:a flac \ -pix_fmt yuv444p12le \ -preset fast \ -loglevel error out.mkv
Podľa youtube musí mať HDR video metadáta, takže ich pridávam:
# 2 ... -i pipe:0 \ ... -color_range pc \ -color_trc linear \ -color_primaries bt2020 \ -colorspace bt2020nc \ -x265-params colorprim=bt2020:transfer=linear:colormatrix=bt2020nc:range=full \ ...
To neberie, pretože používa lineárny transfer. Takže:
# 3 ffmpeg \ ... -i pipe:0 \ ... -vf zscale=rin=full:pin=2020:tin=linear:min=2020:r=full:p=2020:npl=200:t=arib-std-b67,format=yuv444p12le \ -color_range pc \ -color_trc arib-std-b67 \ -color_primaries bt2020 \ -colorspace bt2020nc \ -x265-params colorprim=bt2020:transfer=arib-std-b67:colormatrix=bt2020nc:range=full \ ...
Youtube to berie, ale vyzerá úplne naprd na všetkom, čím prehrávam. Keď však zmením vstupnú transfer funkciu na bt709 vyzerá to skoro dobre (ale prečo bt709 keď je vstup lineárny?)
# 4 ffmpeg \ ... -i pipe:0 \ ... -vf zscale=rin=full:pin=2020:tin=709:min=2020:r=full:p=2020:npl=200:t=arib-std-b67,format=yuv444p12le \ -color_range pc \ -color_trc arib-std-b67 \ -color_primaries bt2020 \ -colorspace bt2020nc \ -x265-params colorprim=bt2020:transfer=arib-std-b67:colormatrix=bt2020nc:range=full \ ...
Colorspace filter s lineárnym vstupom vyzerá rovnako zle:
# 5 ffmpeg \ ... -i pipe:0 \ ... -vf colorspace=bt2020:ispace=bt2020nc:itrc=linear:iprimaries=bt2020:trc=bt2020-12:irange=pc:range=pc:format=yuv444p12 \ -color_range pc \ -color_trc arib-std-b67 \ -color_primaries bt2020 \ -colorspace bt2020nc \ -x265-params colorprim=bt2020:transfer=arib-std-b67:colormatrix=bt2020nc:range=full:master-display=G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,1):max-cll=1000 \ ...
Ale zase s bt709 vyzerá skoro dobre, akurát farby sú rozhodené a jas tiež celkom nesedí
# 6 ffmpeg \ ... -i pipe:0 \ ... -vf colorspace=bt2020:ispace=bt2020nc:itrc=bt709:iprimaries=bt2020:trc=bt2020-12:irange=pc:range=pc:format=yuv444p12 \ -color_range pc \ -color_trc arib-std-b67 \ -color_primaries bt2020 \ -colorspace bt2020nc \ -x265-params colorprim=bt2020:transfer=arib-std-b67:colormatrix=bt2020nc:range=full:master-display=G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,1):max-cll=1000 \ ...
Aké parametre sú správne pre HDR určené na youtube?
Malá doplnková informácia. Za hlavný problém považujem posun farieb. Jas si viem vykompenzovať aj keby som mal urobiť vlastnú korekciu (zrejme by som vynásobil jas nejakým polynómom v shaderi keď už aj tak riešim prevod z packed formy na planar v pomocou shaderov).
Teraz k posunu. Zdá sa, že youtube akceptuje len farebný priestor Rec. 2020. Keď tak pozerám na farebné priestory, Rec. 2020 je výrazne posunutá do zelenej, preto je aj môj výstup viacej zelený.
Okrem toho nepoužívam (okrem úpravy fotografií) kalibračný profil môjho panelu. Bez toho je panel považovaný za sRGB (Rec. 709). Youtube pridáva sýtosť farieb tak, aby farby zobraziteľné v sRGB zodpovedali skutočným farbám v dôsledku čoho je väčšina farieb absolútne presaturovaná.
Keďže uploadujem len generované videá, nevidím dôvod na použitie farebných profilov. Skúšal som z videa stripnúť informáciu o farebnom profile. V tom prípade mpv aj ffmpeg renderovali video korektne, ale youtube hlási, že video sa nepodarilo spracovať.
Otázka je teda, či existuje špinavý trik, ktorý dovolí nahrať na youtube video s 10-bitovou hĺbkou, ale bez farebného profilu, aby sa využil maximálny gamut displaya bez toho, aby to bola na sRGB extrémne prepálená saturácia?
Veď práve ... tá požiadavka na Rec. 2020 spôsobí buď totálne prepálené farby na displayoch s menším gamutom ak nastavím ako vstup Rec 2020, alebo ak nastavím vstup sRGB tak na displayoch so širším gamutom (napr. ja mám DCI-P3) to bude mať vyblednuté farby. Ak nastavím vstup DCI-P3 potom to bude vyzerať dobre u mňa, ale blbo na sRGB (prepálené farby) aj Rec. 2020 (nevýrazné farby).
... 248 webm 1920x1080 1080p 41k , webm_dash container, vp9@ 41k, 24fps, video only, 98.85KiB 137 mp4 1920x1080 1080p 72k , mp4_dash container, avc1.640028@ 72k, 24fps, video only, 175.55KiB 335 webm 1920x1080 1080p HDR 237k , webm_dash container, vp9.2@ 237k, 24fps, video only, 572.68KiBVypis z MediaInfo
Format : MPEG-4 Format profile : Base Media Codec ID : isom (isom/iso2/mp41) File size : 7.82 MiB Duration : 19 s 750 ms Overall bit rate : 3 323 kb/s Encoded date : UTC 2022-09-05 15:58:07 Tagged date : UTC 2022-09-05 15:58:07 Writing application : Blackmagic Design DaVinci Resolve Studio Video ID : 1 Format : HEVC Format/Info : High Efficiency Video Coding Format profile : Format Range@L4@Main Codec ID : hvc1 Codec ID/Info : High Efficiency Video Coding Duration : 19 s 750 ms Bit rate : 3 322 kb/s Width : 1 920 pixels Height : 1 080 pixels Display aspect ratio : 16:9 Frame rate mode : Constant Frame rate : 24.000 FPS Color space : YUV Chroma subsampling : 4:4:4 Bit depth : 10 bits Scan type : Progressive Bits/(Pixel*Frame) : 0.067 Stream size : 7.82 MiB (100%) Encoded date : UTC 2022-09-05 15:58:07 Tagged date : UTC 2022-09-05 15:58:07 Color range : Limited Color primaries : BT.2020 Transfer characteristics : HLG Matrix coefficients : BT.2020 non-constant Codec configuration box : hvcC Other ID : 2 Type : Time code Format : QuickTime TC Duration : 19 s 750 ms Frame rate : 24.000 FPS Time code of first frame : 01:00:00:00 Time code, striped : Yes Language : English Default : No Encoded date : UTC 2022-09-05 15:58:07 Tagged date : UTC 2022-09-05 15:58:07
Cez yt-dlp samozrejme kontrolujem. Pri splnení podmienok nie je problém, aby to uložilo ako HDR:
yt-dlp -F https://youtu.be/iXg-1cvxhr8 ... 702 mp4 7680x4320 60 10 │ 1.38GiB 47698k https │ av01.0.17M.10 47698k video only 4320p60 HDR, mp4_dash
Problém je, že sa nevyužíva plný farebný rozsah, ktorý ponúka display (keďže som v tomto prípade určil, že vstup je sRGB). Keď určím vstup ako Rec.2020 tak to zase preexponuje saturáciu. Pri reálnych záberoch z kamery to väčšinou nevadí pretože farby v reálnom svete nebývajú až tak saturované, ale počítačom generované animácie sú niečo úplne iné.
Tu je sRGB a tu je Rec. 2020. Zdroj je generovaný z tohto shaderu.
Do akého typu súboru? Ak obrázok tak hneď v otázke je priložený súbor a je to prvý riadok, prvý obrázok. Môžem uploadnúť aj vo vyššom rozlíšení. Teoreticky môžem niekde uploadnúť aj raw stream, ale to má vyše 30MB na každý frame pri full HD.
V cieľovom rozlíšení to síce neviem preniesť, ale sekundu videa v 1/100 rozlíšení hádam v priebehu najbližších dní stihnem uploadnúť. Ehm rád by som za t vetu dal smajlíka, ale s 10kB/s uploadom video s vyše 200Gbit/s bitratom nemám šancu uploadnúť tento rok.
Tak nakoniec mi dnes ide internet celkom dobre, takže tu je video.
Je to 62 framov, v rozlíšení 960x540 pri 32 bitovej (4B) hĺbke, takže je to 62*960*540*3*4 = 385 689 600 B = 367 MiB.
Formát je planárny, teda jednotlivé kanály sú uložené za sebou, najskôr zelený, potom modrý a červený. Každý pixel je 32-bitové float point little endian číslo v rozsahu [0, 1]. Za bežných okolností by som uložil ako packované RGB, ale ffmpeg vie čítať len planárny RAW float point formát:
ffmpeg -pix_fmts|grep f IO... gbrpf32be 3 96 IO... gbrpf32le 3 96 IO... gbrapf32be 4 128 IO... gbrapf32le 4 128 IO... grayf32be 1 32 IO... grayf32le 1 32
Nakoniec príkaz, ktorým sa dá enkódovať:
xzcat video.raw.xz|ffmpeg -r 60 -f rawvideo -s 960x540 -pix_fmt gbrpf32le -i - -c:v libx265 -crf 25 -y video.mkv
Vďaka, vyzerá to tak, že keď nastavím primaries na smpte431 (zodpovedá DCI-P3) a nastavím icc profil pre môj panel, potom to zodpovedá tomu, čo by som chcel vidieť. Ak zmením profil späť na sRGB je to presaturované, ale zase nie je to až tak hrozne. V zásade by som povedal, že farby by som mal OK
Zostáva ešte gama korekcia. Tu je divné, že keď posielam lineárny vstup a nastavím ho ako lineárny, potom čistá čierna sa mi zobrazuje ako 20% šedá. S trc bt709 je čierna niekde na úrovni tak 2%. Nechápem na základe čoho ffmpeg z nuly robí niečo iné. Musím to ešte preskúmať.
Je to jedna z možností. Dnes sa k tomu asi nedostanem, ale cez víkend skúsim prehnať cez ffmpeg tiffka a skúsim sa pozrieť presne na vstup / výstup (číselné hodnoty). Možno podľa toho zistím kde robí nejakú korekciu navyše. Inak na vstupe, výstupe aj filtroch nastavujem full range.
To som aj spravil, testovací obrázok je hneď v otázke :) Skúšal som urobiť aj vlastnú konverziu napríklad do srgb (prikladám kód, je to výťažok humusu, ktorý prevádza packed formu na planárnu a prevracia obraz podľa osi y):
#define get_texel(x, y) texelFetch(input_buffer, ivec2(int(x), __h__ - int(y)), 0) #define lin_to_srgb(val) (val <= .0031308 ? (val) * 12.92 : 1.055 * pow(val, 1.0/2.4) - 0.055) float get_addr(in int addr) { int pix = addr / 4; int component = ((addr % 4) + 1) % 3; return lin_to_srgb(get_texel(pix % __w__, pix / __w__)[component]); }
V každom prípade neurobil som poriadnu analýzu krivky, ktorá lezie na výstupe ffmpegu. Musím sa na to pozrieť, ale až cez víkend.
Takže pár zistení ...
V prvom rade nápad použiť limitovaný rozsah (tv) bol správny. Po nastavení na limited sa využíva plný rozsah odtieňov šedej.
Jediný parameter, s ktorým som sa teraz hral je colorspace (alebo ekvivalentné volanie zscale s rovnakým výsledkom, preto ho neuvádzam).
Testovací obrázok je src.png.
Výstup s parametrami:
colorspace=bt2020:ispace=bt2020nc:space=bt2020nc:itrc=linear:trc=linear:iprimaries=smpte431:primaries=bt2020:irange=tv:range=tv
je v youtube_dci_p3.png
Transfer funkcia je linear. Vyzerá to tak, že interne sa používa linear a akákoľvek kombinácia itrc a trc generuje nesprávny výstup.
S osekaním na farby DCI-P3 je výsledná farba modrej v SDR fialová. Červená nedosahuje nikdy plnú hodnotu ak nie je kombinovaná s ostatnými farbami.
Nakoniec výstup youtube_bez_vf.png je bez parametra vf, alebo s iprimaries=bt2020 (výstup je v tomto prípade rovnaký, colorspace teraz nerobí žiadnu konverziu). Asi bude najrozumnejšie nepoužívať žiadnu konverziu :\
Spôsob prevodu farieb bola jedna z prvých vecí, ktoré som sa snažil nájsť, ale jediná oficiálna dokumentácia, ktorú som k tomu našiel je tu.
V prílohe je white point. Gama je samostatná pre každý kanál RGB. Podľa EDID by som mal mať 14" panel MNE001EA1-5. Používam icc profil od výrobcu notebooku.
Pravdu povediac netuším. Vidím, že tento panel má redukovanú modrú zložku, takže bez icm profilu je obraz trochu posunutý do oranžova. Nahranie profilu posun upraví na +/- bielu (nemám spektrometer, takže neviem to posúdiť).
Takže aby som to nejak uzavrel ...
FFmpeg normálne očakáva lineárny vstup a ak človek nevynúti blbú konverziu medzi trc enkóduje väčšinou dobre.
FFplay prehárava dobre.
Prehrávač mpv sa snaží robiť nejaký tonemapping ale ako všetky HDR-SDR algoritmy robí s farbami a odtieňmi divné veci, ale keď sa vynúťi --tone-mapping=gamma
prehrávanie funguje dobre.
Nakoniec youtube. Farby v SDR verzii sú zle. Či to orežem na sRGB, alebo DCI-P3 alebo dám plné Rec.2020 stále sú zle (moc šedé, alebo fialová namiesto modrej). Gama v SDR je zle. Jednoducho robí to nejaký magický prevod z HDR do SDR a ten nemám pod kontrolou.
Tiskni
Sdílej:
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.