www.pudn.com > T264-src-0.02.zip > ratecontrol.c
/***************************************************************************** * * T264 AVC CODEC * * Copyright(C) 2004-2005 llcc* 2004-2005 visionany * * This program is free software ; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation ; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY ; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program ; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ****************************************************************************/ #include "stdio.h" #include "t264.h" #include "ratecontrol.h" #include "math.h" #include "memory.h" // #define USE_FIXEDQP #ifndef USE_FIXEDQP void rc_init_seq(T264_t* t) { double bpp, L1, L2, L3; t->rc.gop = T264_MIN(t->param.idrframe, t->param.iframe); t->rc.np = t->rc.gop - 1; t->rc.nb = 0; // current not support b frame t->rc.bc = 0; t->rc.a1 = 1.0; t->rc.a2 = 0.0; if (t->param.qp == 0) { bpp = ((double)t->param.bitrate) / (t->param.framerate * t->param.width * t->param.height); if (t->param.width == 176) { L1 = 0.1; L2 = 0.3; L3 = 0.6; } else if (t->param.width == 352) { L1 = 0.2; L2 = 0.6; L3 = 1.2; } else { L1 = 0.6; L2 = 1.4; L3 = 2.4; } if (t->rc.nb > 0) { t->rc.gamma = 0.25; t->rc.beta = 0.9; } else { t->rc.gamma = 0.5; t->rc.beta = 0.75; } // first gop first i, p if (bpp <= L1) { t->qp_y = 30; } else if (bpp <= L2) { t->qp_y = 25; } else if (bpp <= L3) { t->qp_y = 20; } else { t->qp_y = 10; } } } void rc_init_gop(T264_t* t) { t->rc.gop_bits = (int32_t)(t->rc.gop * t->param.bitrate / (t->param.framerate) - t->rc.bc); if (t->frame_id != 0) { t->qp_y = t->rc.qp_sum / t->rc.np + 8 * t->rc.bc / t->rc.gop_bits - T264_MIN(2, t->rc.gop / 15); t->qp_y = clip3(t->qp_y, t->param.min_qp, t->param.max_qp); } t->rc.qp_sum = 0; t->rc.p_no = 0; } void rc_init_pic(T264_t* t) { int32_t f1, f2, f; if (t->slice_type == SLICE_P) { if (t->rc.p_no > 0) { // Step 1.1 Determination of target buffer occupancy if (t->rc.p_no == 1) { t->rc.deltap = ((double)t->rc.bc) / (double)(t->rc.np - 1); t->rc.tbl = t->rc.bc; } t->rc.tbl -= t->rc.deltap; // Step 1.2 Microscopic control (target bit rate computation). f1 = (int32_t)(t->param.bitrate / t->param.framerate + t->rc.gamma * (t->rc.tbl - t->rc.bc)); f1 = T264_MAX(0, f1); // current no b frames //f2 = t->rc.wp * t->rc.gop_bits / (t->rc.wp * (t->rc.np - t->rc.p_no - 1) + t->rc.wb * (t->rc.nb - t->rc.b_no - 1)); f2 = t->rc.gop_bits / (t->rc.np - t->rc.p_no); f = (int32_t)(t->rc.beta * f1 + (1 - t->rc.beta) * f2); t->rc.ideal_bits = (int32_t)(f * (1 - t->rc.nb * 0.05)); // HRD consideration ?? } } else if (t->slice_type == SLICE_B) { } } void rc_update_pic(T264_t* t) { t->rc.gop_bits -= t->rc.bits; t->rc.bc += (int32_t)(t->rc.bits - t->param.bitrate / t->param.framerate); if (t->slice_type == SLICE_P) { t->rc.qp_sum += t->qp_y; t->rc.p_no ++; // compute mad } else if (t->slice_type == SLICE_B) { } } double qp2qstep( int32_t qp) { int32_t i; double qstep; static const double QP2QSTEP[6] = {0.625, 0.6875, 0.8125, 0.875, 1.0, 1.125}; qstep = QP2QSTEP[qp % 6]; for(i = 0; i< (qp/6) ; i ++) qstep *= 2; return qstep; } int32_t qstep2qp(double qstep) { int32_t q_per = 0, q_rem = 0; if( qstep < qp2qstep(0)) return 0; else if (qstep > qp2qstep(51)) return 51; while( qstep > qp2qstep(5)) { qstep /= 2; q_per += 1; } if (qstep <= (0.625+0.6875)/2) { qstep = 0.625; q_rem = 0; } else if (qstep <= (0.6875+0.8125)/2) { qstep = 0.6875; q_rem = 1; } else if (qstep <= (0.8125+0.875)/2) { qstep = 0.8125; q_rem = 2; } else if (qstep <= (0.875+1.0)/2) { qstep = 0.875; q_rem = 3; } else if (qstep <= (1.0+1.125)/2) { qstep = 1.0; q_rem = 4; } else { qstep = 1.125; q_rem = 5; } return (q_per * 6 + q_rem); } void rc_update_qp(T264_t* t) { if (t->slice_type == SLICE_P) { if (t->rc.p_no != 0) { if (t->rc.ideal_bits < 0) { t->qp_y += 2; t->qp_y = T264_MIN(t->qp_y, t->param.max_qp); } else { double tmp1, tmp2; double step; int32_t bits = t->rc.ideal_bits - t->rc.header_bits; double mad = t->rc.a1 * t->rc.mad_p + t->rc.a2; int32_t qp; bits = T264_MAX(bits, (int32_t)(t->param.bitrate / t->param.framerate / 4)); tmp1 = mad * mad * t->rc.x1 * t->rc.x1 + 4 * t->rc.x2 * mad * bits; tmp2 = sqrt(tmp1) - t->rc.x1 * mad; if (t->rc.x2 < 0.000001 || tmp1 < 0.000001 || tmp2 <= 0.000001) step = t->rc.x1 * mad / bits; else step = t->rc.x2 * mad * 2 / tmp2; qp = qstep2qp(step); qp = T264_MIN(t->qp_y + 2, qp); qp = T264_MIN(t->param.max_qp, qp); qp = T264_MAX(t->qp_y - 2, qp); t->qp_y = T264_MAX(t->param.min_qp, qp); } } } } static void __inline remove_outlier(T264_t* t, int8_t valid[20]) { double error[20]; int32_t i; double std = 0.0; double threshold; for(i = 0 ; i < t->rc.window_p ; i ++) { error[i] = t->rc.x1 / t->rc.qp[i] + t->rc.x2 / (t->rc.qp[i] * t->rc.rp[i]) - t->rc.qp[i]; std += error[i] * error[i]; } threshold = t->rc.window_p == 2 ? 0 : sqrt(std / t->rc.window_p); for(i = 1 ; i < t->rc.window_p ; i ++) { if (error[i] > threshold) valid[i] = FALSE; } } static void __inline remove_mad_outlier(T264_t* t, int8_t valid[20]) { double error[20]; int32_t i; double std = 0.0; double threshold; for(i = 0 ; i < t->rc.mad_window_p ; i ++) { error[i] = t->rc.a1 * t->rc.mad[i + 1] + t->rc.a2 - t->rc.mad[i]; std += error[i] * error[i]; } threshold = t->rc.mad_window_p == 2 ? 0 : sqrt(std / t->rc.mad_window_p); for(i = 1 ; i < t->rc.mad_window_p ; i ++) { if (error[i] > threshold) valid[i] = FALSE; } } void mad_model_estimator(T264_t* t, int8_t valid[20], int32_t window) { int32_t real_window = 0, i; int8_t estimate_x2 = FALSE; double a00 = 0.0, a01 = 0.0, a10 = 0.0, a11 = 0.0, b0 = 0.0, b1 = 0.0; double mad; double matrix_value; for(i = 0 ; i < window ; i ++) { if (valid[i]) { real_window ++; mad = t->rc.mad[i]; } } t->rc.a1 = t->rc.a2 = 0.0; for(i = 0 ; i < window ; i ++) { if (valid[i]) { t->rc.a1 += t->rc.mad[i] / (t->rc.mad[i + 1] * real_window); if (ABS(mad - t->rc.mad[i]) < 0.00001) estimate_x2 = TRUE; } } if (real_window >= 1 && estimate_x2) { for(i = 0 ; i < window ; i ++) { if (valid[i]) { a00 += 1.0; a01 += t->rc.mad[i + 1]; a10 = a01; a11 += t->rc.mad[i + 1] * t->rc.mad[i + 1]; b0 += t->rc.mad[i]; b1 += t->rc.mad[i] * t->rc.mad[i + 1]; } } matrix_value = a00 * a11 - a01 * a10; if (ABS(matrix_value) > 0.000001) { t->rc.a2 = (b0 * a11 - b1 * a01) / matrix_value; t->rc.a1 = (b1 * a00 - b0 * a10) / matrix_value; } else { t->rc.a1 = b0 / a01; t->rc.a2 = 0.0; } } } void rc_update_mad_model(T264_t* t) { int32_t i; int32_t window; double mad; int8_t valid[20]; if (t->slice_type == SLICE_P) { mad = ((double)t->sad_all) / ((double)(t->width * t->height)); // update x1, x2 for (i = 19 ; i > 0 ; i --) { t->rc.mad[i] = t->rc.mad[i - 1]; } t->rc.mad[0] = mad; window = (int32_t)(mad > t->rc.mad_p ? t->rc.mad_p / mad * 20 : mad / t->rc.mad_p * 20); window = clip3(1, t->rc.p_no + 1, window); window = T264_MIN(window, t->rc.mad_window_p + 1); window = T264_MIN(window, 20); t->rc.mad_window_p = window; memset(valid, TRUE, sizeof(valid)); mad_model_estimator(t, valid, window); remove_mad_outlier(t, valid); mad_model_estimator(t, valid, window); } } void quad_model_estimator(T264_t* t, int8_t valid[20], int32_t window) { int32_t real_window = 0, i; int8_t estimate_x2 = FALSE; double a00 = 0.0, a01 = 0.0, a10 = 0.0, a11 = 0.0, b0 = 0.0, b1 = 0.0; double qp; double matrix_value; for(i = 0 ; i < window ; i ++) { if (valid[i]) { real_window ++; qp = t->rc.qp[i]; } } t->rc.x1 = t->rc.x2 = 0.0; for(i = 0 ; i < window ; i ++) { if (valid[i]) { t->rc.x1 += t->rc.qp[i] * t->rc.rp[i] / real_window; if (qp != t->rc.qp[i]) estimate_x2 = TRUE; } } if (real_window >= 1 && estimate_x2) { for(i = 0 ; i < window ; i ++) { if (valid[i]) { a00 += 1.0; a01 += 1.0 / t->rc.qp[i]; a10 = a01; a11 += 1.0 / (t->rc.qp[i] * t->rc.rp[i]); b0 += t->rc.qp[i] * t->rc.rp[i]; b1 += t->rc.rp[i]; } } matrix_value = a00 * a11 - a01 * a10; if (ABS(matrix_value) > 0.000001) { t->rc.x1 = (b0 * a11 - b1 * a01) / matrix_value; t->rc.x2 = (b1 * a00 - b0 * a10) / matrix_value; } else { t->rc.x1 = b0 / a00; t->rc.x2 = 0.0; } } } void rc_update_quad_model(T264_t* t) { int32_t i; int32_t window; double mad; int8_t valid[20]; if (t->slice_type == SLICE_P) { mad = ((double)t->sad_all) / ((double)(t->width * t->height)); // update x1, x2 for (i = 19 ; i > 0 ; i --) { t->rc.qp[i] = t->rc.qp[i - 1]; t->rc.rp[i] = t->rc.rp[i - 1]; } t->rc.qp[0] = t->qp_y; t->rc.rp[0] = ((double)(t->rc.bits - t->rc.header_bits)) / mad; window = (int32_t)(mad > t->rc.mad_p ? t->rc.mad_p / mad * 20 : mad / t->rc.mad_p * 20); window = clip3(1, t->rc.p_no + 1, window); window = T264_MIN(window, t->rc.window_p + 1); window = T264_MIN(window, 20); t->rc.window_p = window; memset(valid, TRUE, sizeof(valid)); quad_model_estimator(t, valid, window); remove_outlier(t, valid); quad_model_estimator(t, valid, window); if (t->rc.p_no > 0) { // update a1, a2 rc_update_mad_model(t); } else { t->rc.mad[0] = mad; } t->rc.mad_p = mad; } } #else // USE_FIXEDQP void rc_init_seq(T264_t* t) { } void rc_init_gop(T264_t* t) { } void rc_init_pic(T264_t* t) { } void rc_update_pic(T264_t* t) { } void rc_update_qp(T264_t* t) { } void rc_update_quad_model(T264_t* t) { } #endif