GNOME Bugzilla – Bug 621663
x264enc: support changing bitrate property on the fly
Last modified: 2011-03-30 08:05:29 UTC
In particular would like to change "bitrate" on the fly. If you set this property after gst_x264_enc_init_encoder() it just silently does nothing though. (Sets encoder->bitrate but does not pass it on to x264) I don't know if this is an x264 limitation or just something unimplemented in x264enc. Thoughts on how to patch this welcome
It looks like x264_encoder_reconfig() allows changing some but not all props on the fly. Bitrate can be changed if in VBV mode /* VBV can't be turned on if it wasn't on to begin with */ if( h->param.rc.i_vbv_max_bitrate > 0 && h->param.rc.i_vbv_buffer_size > 0 && param->rc.i_vbv_max_bitrate > 0 && param->rc.i_vbv_buffer_size > 0 ) { COPY( rc.i_vbv_max_bitrate ); COPY( rc.i_vbv_buffer_size ); COPY( rc.i_bitrate ); rc_reconfig = 1; } Anyway either setting a prop could immediately reconfig, I guess, or x264enc could have some kind of "need reconfig" flag that it handles on the next buffer?
Created attachment 163706 [details] [review] RFC: allow changing x264enc bitrate on the fly Seems to have noticeable visual impact on quality when decreased (to very low) from configured value. Configuring the pipeline to low bitrate and then increasing the value doesn't improve the quality as much as it should.
This sounds like a nice thing to support. FWIW, we now have GST_PARAM_MUTABLE_PLAYING with which properties that can be updated during playing state can be marked. Patch needs updating after recent x264enc changes.
Specifically, x264 lets you do one of three things: 1. In CBR mode, you can change the bitrate. You cannot go out of CBR mode if you started there. Thus, you must change maxrate and bitrate together, keeping them equal. You probably want to change bufsize too, depending on the application. 2. In CRF mode, you can change the CRF. 3. In any mode with VBV active, you can change the maxrate and bufsize. However, if you started in CBR (per 1), you must stay in CBR. In short, you can modify CRF, maxrate, and bufsize arbitrarily, but you cannot change ratecontrol modes (where the available modes are CBR, ABR, and CRF).
Created attachment 170801 [details] [review] x264enc: Make it clear that constant quantizer is for debugging only That's what Jason told me on IRC.
Created attachment 170802 [details] [review] x264enc: Set max bitrate in quality mode The maximum bitrate can be set in that case too, its probably what we want most of the time.
Created attachment 170803 [details] [review] x264enc: Allow changing the bitrate and quantitizers dynamically
Created attachment 170804 [details] [review] x264enc: Force frameref=1 if the intra-refresh is true If it is not forced to 1, x264 will print a warning and set it to 1 anyway.
as for the lowered quality when you switch bitrate, if you do it slowly instead of in big jumps, it doesn't happen.
Don't force ref=1 for intra-refresh; in the future, x264 may add support for multiref + intra refresh. It's not conceptually wrong.
Comment on attachment 170804 [details] [review] x264enc: Force frameref=1 if the intra-refresh is true Jason, ok thanks for the info, please don't make it a warning then!
Those statements seem completely irrelevant to me. x264 currently doesn't implement X + Y. It may one day implement X + Y. What's wrong with telling the user in the meantime that it doesn't?
was making the user (me) think he was doing something wrong
Hi, I wrote a simple test routine in h264 to see if a constant 250kb rate encoded stream had the same quality and size as a stream with an average rate of 250kb(every 50 frames it changed between 350kb and 150kb to average at 250kb, there are 600 frames in the file). The file for the average case had a slightly lower PNSR but much larger file size. Has anybody else tried this before? Thanks, Ian
Can you post your two output samples?
Created attachment 175220 [details] Video encoded at 250k
Created attachment 175221 [details] Video encoded at an average of 250k The constant bitrate stream. ---------------------------- The arguments are: --threads 1 --rc-lookahead 0 --no-psy --bitrate 250 --vbv-maxrate 250 --vbv-bufsize 250 --psnr --input-res 352x288 -b 0 --no-scenecut --no-progress -i 25 -I 25 -o video1 /devel/statmux/rawvid/quadforeman_cif The average stream. ------------------- Once each frame is encoded(from x264_encoder_frame_end in encoder.c) this is called: if( (frameCount % 50) == 0 ) { int newBitrate; if( test_args[0].bitrate == 350) { newBitrate = 150; } else { newBitrate = 350; } for( i=0 ; i < NO_ENCODERS ; i++ ) { set_bitrate( i, newBitrate ); } } The workings of the set_bitrate function are: x264_encoder_parameters( test_args[encoderIndex].handle , ¶m ); param.rc.i_bitrate = bitrate; param.rc.i_vbv_max_bitrate = bitrate; param.rc.i_vbv_buffer_size = bitrate; /* the size = bitrate x delay, say 1 second delay at the moment so bitrate = buffer size */ if( (ret = x264_encoder_reconfig( test_args[encoderIndex].handle, ¶m)) != 0 ) {
And the x264 log output with PSNR and other info?
For the constant bitrate one: x264 [info]: frame I:24 Avg QP:34.84 size: 7949 PSNR Mean Y:30.14 U:38.52 V:40.00 Avg:31.63 Global:31.59 x264 [info]: frame P:576 Avg QP:37.78 size: 992 PSNR Mean Y:28.06 U:38.10 V:39.67 Avg:29.64 Global:29.60 x264 [info]: mb I I16..4: 14.2% 55.3% 30.6% x264 [info]: mb P I16..4: 0.5% 0.3% 0.2% P16..4: 38.0% 11.9% 3.7% 0.0% 0.0% skip:45.4% x264 [info]: 8x8 transform intra:50.3% inter:61.7% x264 [info]: coded y,uvDC,uvAC intra: 80.5% 40.3% 12.3% inter: 13.0% 3.3% 0.1% x264 [info]: i16 v,h,dc,p: 18% 38% 34% 11% x264 [info]: i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 22% 28% 20% 4% 4% 4% 5% 4% 8% x264 [info]: i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 29% 35% 15% 3% 4% 3% 4% 3% 4% x264 [info]: i8c dc,h,v,p: 71% 20% 7% 2% x264 [info]: Weighted P-Frames: Y:0.7% x264 [info]: ref P L0: 69.7% 17.3% 9.4% 3.4% 0.1% x264 [info]: PSNR Mean Y:28.138 U:38.121 V:39.687 Avg:29.716 Global:29.661 kb/s:254.07 encoded[1] 600 frames, 33.34 fps, 254.07 kb/s And for the average bitrate one: x264 [info]: frame I:24 Avg QP:32.18 size: 10738 PSNR Mean Y:32.16 U:39.16 V:40.86 Avg:33.57 Global:33.54 x264 [info]: frame P:576 Avg QP:35.34 size: 1406 PSNR Mean Y:29.66 U:38.57 V:40.35 Avg:31.20 Global:31.16 x264 [info]: mb I I16..4: 10.5% 55.4% 34.2% x264 [info]: mb P I16..4: 0.4% 0.3% 0.3% P16..4: 38.6% 15.3% 6.3% 0.0% 0.0% skip:39.0% x264 [info]: 8x8 transform intra:51.0% inter:57.8% x264 [info]: coded y,uvDC,uvAC intra: 86.7% 47.9% 17.8% inter: 17.8% 4.6% 0.1% x264 [info]: i16 v,h,dc,p: 19% 38% 34% 10% x264 [info]: i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 20% 27% 19% 5% 5% 4% 6% 5% 10% x264 [info]: i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 27% 36% 13% 3% 4% 3% 4% 4% 5% x264 [info]: i8c dc,h,v,p: 62% 25% 11% 3% x264 [info]: Weighted P-Frames: Y:0.7% x264 [info]: ref P L0: 67.8% 18.4% 9.8% 3.8% 0.1% x264 [info]: PSNR Mean Y:29.763 U:38.591 V:40.374 Avg:31.291 Global:31.230 kb/s:355.83 encoded[1] 600 frames, 29.77 fps, 355.83 kb/s
$ ls -l video* -rwx------+ 1 Administrators None 757760 2010-11-25 01:02 video250k -rwx------+ 1 Administrators None 798720 2010-11-25 01:02 videoavg250k I highly doubt these files match up to the logs you just posted.
Created attachment 175228 [details] Video encoded at 250k My bad! a replacement file, the average and logs to come...
Created attachment 175229 [details] Video encoded at an average of 250k Log for the constant 250k bitrate: x264 [info]: frame I:24 Avg QP:27.43 size: 7548 PSNR Mean Y:37.04 U:41.15 V:43.41 Avg:38.17 Global:37.90 x264 [info]: frame P:576 Avg QP:30.57 size: 1008 PSNR Mean Y:35.01 U:40.32 V:42.23 Avg:36.26 Global:36.02 x264 [info]: mb I I16..4: 16.2% 44.0% 39.8% x264 [info]: mb P I16..4: 1.3% 1.8% 0.3% P16..4: 40.4% 12.0% 3.2% 0.0% 0.0% skip:41.0% x264 [info]: 8x8 transform intra:48.4% inter:69.3% x264 [info]: coded y,uvDC,uvAC intra: 62.8% 51.6% 18.1% inter: 14.2% 7.5% 0.3% x264 [info]: i16 v,h,dc,p: 29% 23% 23% 24% x264 [info]: i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 14% 16% 21% 4% 11% 9% 10% 6% 8% x264 [info]: i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 14% 14% 21% 4% 20% 7% 9% 3% 9% x264 [info]: i8c dc,h,v,p: 57% 20% 18% 5% x264 [info]: Weighted P-Frames: Y:0.3% x264 [info]: ref P L0: 65.2% 21.1% 10.0% 3.7% 0.0% x264 [info]: PSNR Mean Y:35.090 U:40.352 V:42.276 Avg:36.339 Global:36.086 kb/s:253.83 encoded[0] 600 frames, 76.99 fps, 253.83 kb/s Log for the 25k average bitrate: x264 [info]: frame I:24 Avg QP:30.11 size: 6419 PSNR Mean Y:35.44 U:40.39 V:42.40 Avg:36.65 Global:35.79 x264 [info]: NULL handle! Average PSNR for encoder 0 is 36.059 frame #600, total bits so far 816642 Average PSNR for encoder 1 is 0.000 frame #600, total bits so far 0 frame P:576 Avg QP:30.73 size: 1150 PSNR Mean Y:34.78 U:40.11 V:41.97 Avg:36.03 Global:35.43 x264 [info]: mb I I16..4: 18.6% 49.7% 31.7% x264 [info]: mb P I16..4: 1.4% 1.7% 0.3% P16..4: 41.4% 12.8% 4.4% 0.0% 0.0% skip:38.0% x264 [info]: 8x8 transform intra:50.1% inter:65.2% x264 [info]: coded y,uvDC,uvAC intra: 54.9% 47.9% 17.2% inter: 16.1% 9.1% 0.4% x264 [info]: i16 v,h,dc,p: 32% 26% 21% 22% x264 [info]: i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 14% 14% 24% 4% 12% 9% 10% 6% 8% x264 [info]: i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 13% 13% 23% 4% 19% 7% 9% 3% 8% x264 [info]: i8c dc,h,v,p: 63% 17% 16% 4% x264 [info]: Weighted P-Frames: Y:0.3% x264 [info]: ref P L0: 65.6% 18.9% 11.3% 4.2% 0.0% x264 [info]: PSNR Mean Y:34.809 U:40.124 V:41.986 Avg:36.059 Global:35.444 kb/s:272.21 encoded[0] 600 frames, 72.73 fps, 272.21 kb/s I was in a rush and got it wrong, sorry about that, these are the correct files and logs.
What's your problem then? The constant bitrate (as expected) has higher PSNR.
Why is a higher PSNR expected from a stream that is encoded at 250k than a steam that has an average requested rate of 250k?
If you change the bitrate between 150k and 350k constantly, you will get worse quality than if you left it at 250k for the whole encode. This isn't blazingly obvious?!!
To be honest, its not obvious to me, I apologise for my lack of understanding. If you have the time, please can you explain why you'd expect a lower quality? I can comprehend that there could be a quality penalty in if you change the bitrate but I don't exactly know why that'd happen. Leaving the quality aside, why would the overall bitrate be different? The requested bitrate averages at 250k. Do you think the encoder rate controller reacts to a bitrate increase quicker than a decrease? I'm not sure what is going on here. Thanks for your help.
The overall bitrate is different because your video is short and the difference in VBV states is sufficient to account for the difference. A drop in bitrate hurts PSNR more than a rise in bitrate helps PSNR. Thus, artificially dropping bitrate for a part of the video (and boosting it for another) will generally hurt overall PSNR.
I can understand the quality, that makes sense to me, thanks. However I'm not quite sure of the size difference being due to the VBV buffer size because the buffer size(on average) is the same. But this helps me, I will spend more time understanding the buffer size effect. Maybe I shouldn't one to one map it with bitrate, I did that because I assumed that a buffer that could hold one seconds worth of data would be sufficient, maybe the buffer should stay constant. I'll experiment. Thanks for you help, it is much appreciated.
Created attachment 177609 [details] [review] x264enc: Allow changing the bitrate and quantitizers dynamically Updated patch to match master.. Any chance some can review/merge this ?
ping ?
Comment on attachment 177609 [details] [review] x264enc: Allow changing the bitrate and quantitizers dynamically Looks fine to me. > state = GST_STATE (encoder); >- if (state != GST_STATE_READY && state != GST_STATE_NULL) >+ if ((state != GST_STATE_READY && state != GST_STATE_NULL) && >+ !(pspec->flags & GST_PARAM_MUTABLE_PLAYING)) > goto wrong_state; (Nitpick: I guess & (MUTABLE_PLAYING | MUTABLE_PAUSED) would be more correct, but it doesn't matter currently, and is unlikely to ever matter, since PAUSED vs. PLAYING behaviour is the same for an encoder, so MUTABLE_PAUSED doesn't make sense)..
MUTABLE_PLAYING includes PAUSED & READY.. see: http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstParamSpec.html#GST-PARAM-MUTABLE-PLAYING:CAPS commit 62e35a6b40feb7bb5d080cd2660b4ebe8fb107d6 Author: Olivier Crête <olivier.crete@collabora.co.uk> Date: Tue Sep 21 20:14:04 2010 -0400 x264enc: Allow changing the bitrate and quantitizers dynamically https://bugzilla.gnome.org/show_bug.cgi?id=621663 commit a4df8f90310ddfb7997d19435ced80a3b4902e74 Author: Olivier Crête <olivier.crete@collabora.co.uk> Date: Tue Sep 21 19:33:10 2010 -0400 x264enc: Set max bitrate in quality mode https://bugzilla.gnome.org/show_bug.cgi?id=621663 commit 1370f3f161ff36d0e31f65dae5c7efed5a6f6648 Author: Olivier Crête <olivier.crete@collabora.co.uk> Date: Tue Sep 21 19:20:29 2010 -0400 x264enc: Make it clear that constant quantizer is for debugging only https://bugzilla.gnome.org/show_bug.cgi?id=621663
> MUTABLE_PLAYING includes PAUSED & READY.. see: What I meant was that the check would fail with MUTABLE_PAUSED properties (but there aren't any atm, so..)