[FFmpeg-devel] [PATCH] libavcodec: add bit-rate support to RoQ video encoder

Tomas Härdin git at haerdin.se
Tue Jan 23 19:44:03 EET 2024


tis 2024-01-23 klockan 11:33 +0300 skrev Victor Luchitz:
> Re-posting the patch as an attachment. Sorry for the inconvenience!

Yep, this one applies and also passes FATE.

I notice ffplay_buffer whines a lot when playing RoQ files:

> [swscaler @ 0x7fcb44043240] deprecated pixel format used, make sure you did set range correctly
> [ffplay_buffer @ 0x7fcb44032fc0] filter context - w: 256 h: 256 fmt: 14 csp: unknown range: unknown, incoming frame - w: 256 h: 256 fmt: 14 csp: unknown range: pc pts_time: 0
> [ffplay_buffer @ 0x7fcb44032fc0] Changing video frame properties on the fly is not supported by all filters.

I don't think this problem relates to this patch however.

Anyway, using -b:v 100k causes the encoder to effectively become stuck
on the first frame, being unable to go below 621 kbps and increasing
qscale very slowly. But you mentioned this already of course. Perhaps
there should be a faster "startup" phase? Subsequent frames being P-
frames may lead to the average hitting the target bitrate.

Even when using 1 Mbps the encoding is very slow:

./ffmpeg -r:v 30 -t 1 -f lavfi -i testsrc2 -s 256x256 -b:v 1000k -y
foo-1000k.roq

> [roqvideo @ 0x3112980] 
> Generated a frame too big for desired bit rate (1489 kbps), now switching to a bigger qscale value (257).
> [roqvideo @ 0x3112980] 
> Generated a frame too big for desired bit rate (1489 kbps), now switching to a bigger qscale value (259).
> [...]
> Generated a frame too big for desired bit rate (1100 kbps), now switching to a bigger qscale value (196863).
> [roqvideo @ 0x3112980] .0 size=       0kB time=N/A bitrate=N/A speed=N/A    
> Generated a frame too big for desired bit rate (1069 kbps), now switching to a bigger qscale value (262399).
> [roqvideo @ 0x3112980] 
> Generated a frame too small for desired bit rate (601 kbps), reverting lambda and using smaller inc on qscale (196863).
> [roqvideo @ 0x3112980] 0.0 size=      17kB time=00:00:00.16 bitrate= 812.7kbits/s speed=0.0476x    
> Generated a frame too small for desired bit rate (915 kbps), qscale value cannot be lowered any further (1).
> [...]
> [roqvideo @ 0x3112980] 
> Generated a frame too big for desired bit rate (1084 kbps), now switching to a bigger qscale value (327680).
> [roqvideo @ 0x3112980] 
> Generated a frame too big for desired bit rate (1068 kbps), now switching to a bigger qscale value (393216).
> [roqvideo @ 0x3112980] 0.0 size=      42kB time=00:00:00.40 bitrate= 866.5kbits/s speed=0.0667x    
> Generated a frame too small for desired bit rate (514 kbps), reverting lambda and using smaller inc on qscale (327680).
> [roqvideo @ 0x3112980] 0.0 size=      62kB time=00:00:00.56 bitrate= 896.2kbits/s speed=0.0708x    
> Generated a frame too small for desired bit rate (901 kbps), qscale value cannot be lowered any further (1).

This suggests an unstable regulation loop. It also makes the encoder
slower than the Cinepak encoder, amazingly. 59.6 vs 21.57 seconds for
encoding 90 frames of dimension 256x256.

-bt should have a default of 0, and similar default logic as -b. The
default of bitrate/20 also seems excessively small? If I change the
default to be the same as the bitrate then the encoding time above
shrinks to 11.7 seconds.

There is an excessive newline visible here:

> +                   "\nGenerated a frame too big for desired bit rate
> (%d kbps), "

And elsewhere.

Using non-integer framerates causes the encoder to go bananas. For
example 24000/1001 fps makes the ratecontrol think it's running at
24000 fps. An easy fix is to reject avctx->time_base.num != 1 on init.
roq_write_header() rejects non-integer framerates.

I'm also curious about this hunk:

> -        if (enc->lambda > 100000) {
> +        if (enc->lambda > 100000000) {
>              av_log(roq->logctx, AV_LOG_ERROR, "Cannot encode video in Quake compatible form\n");
>              return AVERROR(EINVAL);
>          }

Where in the Quake (3?) source code is this limitation? Seems rather
that there should be a retry limit. There's probably no harm in keeping
going so long as the packet doesn't end up above the limit.

A quick logarithmic regression on bitrate vs qscale suggests it scales
with somewhere between qscale^-0.2833 and qscale^-0.2842. Conversely,
to hit a specific bitrate, try scaling qscale with the bitrate ratio
raised to around 3.5. A more conservative exponent like 2 is probably
also fine. See patch attached.

A more systematic approach might be to do a binary search for qscale,
with an initial guess per the formula above.

/Tomas

-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Fast-ratecontrol-could-be-better.patch
Type: text/x-patch
Size: 6460 bytes
Desc: not available
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20240123/45460822/attachment.bin>


More information about the ffmpeg-devel mailing list