CESNET / UltraGrid

UltraGrid low-latency audio and video network transmission system
http://www.ultragrid.cz
Other
489 stars 55 forks source link

using qp mode with hevc_qsv for bitrate control #298

Closed alatteri closed 1 year ago

alatteri commented 1 year ago

Hello,

Is there a way to use qp mode to set quality instead of using fixed bitrate=XXm when using hevc_qsv?

Thanks.

TheSashmo commented 1 year ago

Thats a good question! +1

MartinPulec commented 1 year ago

Good question. As per this, this rate-control should be toggled on by setting a flag AV_CODEC_FLAG_QSCALE. Then I believe that the quality should be governed by global_quality setting.

I've already made couple of changes in devel that reflect the above observations so that you can now use cqp= option also with QSV. You can verify that CQP is used by running:

$ uv -t testcard -c libavcodec:encoder=hevc_qsv:low_power=1:cqp=5000 -V 2>/dev/null | grep 'ratecontrol\|\<QPI'
[1677588129.598] [lavc hevc_qsv @ 0x7ffa30001100] Using the constant quantization parameter (CQP) ratecontrol method
[1677588129.601] [lavc hevc_qsv @ 0x7ffa30001100] QPI: 33; QPP: 42; QPB: 51

Actually it took me quite a while to figure out that the CQP factor needs to be quite large for hevc_qsv (but not eg. for mjpeg_qsv), sth like 5000 ± 3000. If you look to one of the links, that I've linked above, the given value will be divided by 118, so that after the division you get a coefficient in usual range [10..51].

alatteri commented 1 year ago

I tested this a bit tonight with UHD material.
5000 was very low quality. Lots of soft macro blocking and GOP pops. Unusable. 4500 was decent. A little bit of macroblocks during dissolves and in dark areas. OK, not great. 4000 picture was good. bitrate averaged around 36mb/s with peaks into the 90s, that would lead to some packet loss. 3500 stream was in the 100s of megabits. tons of decode errors (likely packet loss), unusable.

I settled on just using encoder=hevc_qsv:bitrate=25M and the picture is great and stable.

alatteri commented 1 year ago

although I was not setting low_power=1 with cqp.

Update Did quick testing using low_power, saw no difference.

MartinPulec commented 1 year ago

I tested this a bit tonight with UHD material.

Thanks for the testing, it is a pity. On the other hand, it may not be such a surprise, even libx264/5 does have constant quantizer and AFAIK it doesn't perform the best, for scenarios where bitrate should be more or less automatic, depending not only on video properties but also its content to keep equal quality for different scenes, CRF is much better.

CRF is, however, not available for QSV. Would you like to try any different RC mode? It is not so straightforward to toggle it directly since there is no explicit setting and it depends on combination of parameters. I believe that UltraGrid uses CBR by default. I don't know if eg. VBR (or any of other modes) is worth to try? Anyways, the quality factor as a single number seem to use QVBR, ICQ and LA_ICQ, which may not be supported in Linux according the linked document (but the document was last updated almost 7 yrs ago, so who knows)

alatteri commented 1 year ago

It would be good to try other RC modes, maybe *VBR, as when using defaults with:bitrate=23M even if the SDI signal is static black, the encoder still outputs a full 25Mb/s stream. This is really unnecessary network load.

In a scenario where the input is 2K@24 RGB10bit444, a pure black frame.

using x265. with defaults the output stream data load is ~700Kib/s and hevc_qsv is ~26Mib/s, for a pure black SDI signal.

MartinPulec commented 1 year ago

It would be good to try other RC modes, maybe *VBR

I've already added the rc= option. Supported modes are cbr (behaving exactly as current default), cqp (slightly different from cqp= param), icq (doesn't work), qvbr and vbr.

I'll left aside cqp and cbr, which are already tested (cqp as a RC opt differs only in that that the quality value may be omitted).vbr seems to work correctly, maybe even better than cbr (the cbr's minimal bitrate seems strange to me).

qvbr runs in theory, and it should be governed by both bitrate and cqp parameter (so eg. :rc=qvbr:bitrate=20M:cqp=20). Here the "quality" parameter looks to be in a yet another range than for CQP (usable range is in tens). Other RCs doesn't seem to be promising (lookahead ones – latency); VCM is only for H.264.

If you wish, you can let me know if you think that some of the defaults could be changed (eg. the vbr instead of cbr), for me it is slightly difficult to evaluate visually. Also I've noticed interesting observation, that having intra-refresh disabled (:disable_intra_refresh) yields actually smaller variance in frame sizes (as seen with -V param). But it is just for record, if in your experience is intra refresh better enabled, we should keep it (in theory it should be, anyways).

alatteri commented 1 year ago

Hi Martin,

I've done some quick testing with both qvbr and vbr. I took a ~3minute UHD source and output it via 12G RGB10bit SDI (R10k limited), and just kept it looping. I then graphed the network out data load using telegraf/influx/grafana for about 15minutes each.

See screenshots attached.

qvbr behaves like I feel x265 does normally which is good. the UG bitrate specified is the median, with dips both down and up.

with just plain vbr, the bitrate is more of the floor, with not many down dips, and lots of up spikes.

Visually they both looked good. I'll do more testing over the weekend. Currently I feel :rc=qvbr:bitrate=20M:cqp=20 is the best default for hevc_qsv, and that cbr is not good.

In addition, the below graphs included total data load from the machine, which includes the audio stream (8channel at AAC 256k), and any overhead from the VPN.

qvbr vbr