mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-15 00:44:05 +09:00
much better bitrate control
This commit is contained in:
@@ -356,12 +356,13 @@ static float get_video_rate_kbps(tav_encoder_t *enc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PID controller parameters - heavily damped to prevent oscillation
|
// PID controller parameters - heavily damped to prevent oscillation
|
||||||
#define PID_KP 0.15f // Proportional gain - very conservative
|
#define PID_KP 0.08f // Proportional gain - extremely conservative
|
||||||
#define PID_KI 0.01f // Integral gain - slow convergence
|
#define PID_KI 0.002f // Integral gain - very slow to prevent windup
|
||||||
#define PID_KD 0.6f // Derivative gain - heavy damping to resist changes
|
#define PID_KD 0.4f // Derivative gain - moderate damping
|
||||||
#define MAX_QY_CHANGE 1 // Maximum quantiser change per frame - very conservative
|
#define MAX_QY_CHANGE 0.5f // Maximum quantiser change per frame - extremely conservative
|
||||||
#define DERIVATIVE_FILTER 0.75f // Heavy low-pass filter for derivative
|
#define DERIVATIVE_FILTER 0.85f // Very heavy low-pass filter for derivative
|
||||||
#define INTEGRAL_DEADBAND 0.10f // Don't accumulate integral within ±10% of target
|
#define INTEGRAL_DEADBAND 0.05f // Don't accumulate integral within ±5% of target
|
||||||
|
#define INTEGRAL_CLAMP 500.0f // Clamp integral term to prevent windup
|
||||||
|
|
||||||
static void adjust_quantiser_for_bitrate(tav_encoder_t *enc) {
|
static void adjust_quantiser_for_bitrate(tav_encoder_t *enc) {
|
||||||
if (!enc->bitrate_mode) {
|
if (!enc->bitrate_mode) {
|
||||||
@@ -411,10 +412,14 @@ static void adjust_quantiser_for_bitrate(tav_encoder_t *enc) {
|
|||||||
if (error_percent > INTEGRAL_DEADBAND && enc->scene_change_cooldown == 0) {
|
if (error_percent > INTEGRAL_DEADBAND && enc->scene_change_cooldown == 0) {
|
||||||
enc->pid_integral += error;
|
enc->pid_integral += error;
|
||||||
} else {
|
} else {
|
||||||
// Decay integral when within deadband or during scene changes
|
// Aggressively decay integral when within deadband or during scene changes
|
||||||
enc->pid_integral *= 0.95f;
|
// This prevents integral windup that causes qY drift
|
||||||
|
enc->pid_integral *= 0.90f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clamp integral immediately to prevent windup
|
||||||
|
enc->pid_integral = FCLAMP(enc->pid_integral, -INTEGRAL_CLAMP, INTEGRAL_CLAMP);
|
||||||
|
|
||||||
float derivative = error - enc->pid_prev_error;
|
float derivative = error - enc->pid_prev_error;
|
||||||
enc->pid_prev_error = error;
|
enc->pid_prev_error = error;
|
||||||
|
|
||||||
@@ -423,42 +428,40 @@ static void adjust_quantiser_for_bitrate(tav_encoder_t *enc) {
|
|||||||
enc->pid_filtered_derivative = (DERIVATIVE_FILTER * enc->pid_filtered_derivative) +
|
enc->pid_filtered_derivative = (DERIVATIVE_FILTER * enc->pid_filtered_derivative) +
|
||||||
((1.0f - DERIVATIVE_FILTER) * derivative);
|
((1.0f - DERIVATIVE_FILTER) * derivative);
|
||||||
|
|
||||||
// Clamp integral to prevent windup (tighter bounds)
|
|
||||||
enc->pid_integral = FCLAMP(enc->pid_integral, -200.0f, 200.0f);
|
|
||||||
|
|
||||||
// Calculate adjustment using filtered derivative for smoother response
|
// Calculate adjustment using filtered derivative for smoother response
|
||||||
float pid_output = (PID_KP * proportional) + (PID_KI * enc->pid_integral) +
|
float pid_output = (PID_KP * proportional) + (PID_KI * enc->pid_integral) +
|
||||||
(PID_KD * enc->pid_filtered_derivative);
|
(PID_KD * enc->pid_filtered_derivative);
|
||||||
|
|
||||||
// Adaptive scaling based on error magnitude and current quantiser position
|
// Adaptive scaling based on error magnitude and current quantiser position
|
||||||
// At low quantisers (0-10), QLUT is exponential and small changes cause huge bitrate swings
|
// At low quantisers (0-10), QLUT is exponential and small changes cause huge bitrate swings
|
||||||
float scale_factor = 50.0f; // Base: ~50 kbps error = 1 quantiser step
|
float scale_factor = 100.0f; // Base: ~100 kbps error = 1 quantiser step
|
||||||
int max_change = MAX_QY_CHANGE;
|
float max_change = MAX_QY_CHANGE;
|
||||||
|
|
||||||
if (enc->adjusted_quantiser_y_float < 5.0f) {
|
if (enc->adjusted_quantiser_y_float < 5.0f) {
|
||||||
// Extreme lossless (qY 0-4) - be very conservative but still responsive
|
// Extreme lossless (qY 0-4) - be very conservative but still responsive
|
||||||
// At qY=0, QLUT[0]=1, which is essentially lossless and bitrate is huge
|
// At qY=0, QLUT[0]=1, which is essentially lossless and bitrate is huge
|
||||||
// Use fixed scale factor to ensure controller can actually respond
|
// Use fixed scale factor to ensure controller can actually respond
|
||||||
scale_factor = 150.0f; // ~150 kbps error = 1 step
|
scale_factor = 200.0f; // ~200 kbps error = 1 step
|
||||||
max_change = 1;
|
max_change = 0.3f;
|
||||||
} else if (enc->adjusted_quantiser_y_float < 15.0f) {
|
} else if (enc->adjusted_quantiser_y_float < 15.0f) {
|
||||||
// Very near lossless (qY 5-14) - very conservative
|
// Very near lossless (qY 5-14) - very conservative
|
||||||
scale_factor = 300.0f; // ~300 kbps error = 1 step
|
scale_factor = 400.0f; // ~400 kbps error = 1 step
|
||||||
max_change = 1;
|
max_change = 0.4f;
|
||||||
} else if (enc->adjusted_quantiser_y_float < 30.0f) {
|
} else if (enc->adjusted_quantiser_y_float < 30.0f) {
|
||||||
// Near lossless range (qY 15-29) - be conservative
|
// Near lossless range (qY 15-29) - be conservative
|
||||||
scale_factor = 120.0f; // ~120 kbps error = 1 step
|
scale_factor = 200.0f; // ~200 kbps error = 1 step
|
||||||
max_change = 2;
|
max_change = 0.5f;
|
||||||
} else if (error_percent > 0.5f) {
|
} else if (error_percent > 0.5f) {
|
||||||
// Large error - be more aggressive
|
// Large error - be slightly more aggressive
|
||||||
scale_factor = 30.0f;
|
scale_factor = 150.0f;
|
||||||
|
max_change = 0.6f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate float adjustment (no integer quantization yet)
|
// Calculate float adjustment (no integer quantization yet)
|
||||||
float adjustment_float = pid_output / scale_factor;
|
float adjustment_float = pid_output / scale_factor;
|
||||||
|
|
||||||
// Limit maximum change per frame to prevent wild swings (adaptive limit)
|
// Limit maximum change per frame to prevent wild swings (adaptive limit)
|
||||||
adjustment_float = FCLAMP(adjustment_float, -(float)max_change, (float)max_change);
|
adjustment_float = FCLAMP(adjustment_float, -max_change, max_change);
|
||||||
|
|
||||||
// Apply logarithmic scaling to adjustment based on current qY
|
// Apply logarithmic scaling to adjustment based on current qY
|
||||||
// At low qY (0-10), QLUT is exponential so we need much smaller steps
|
// At low qY (0-10), QLUT is exponential so we need much smaller steps
|
||||||
|
|||||||
Reference in New Issue
Block a user