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