x264 - x264_ratecontrol_start




// 在编码一帧前,为该帧选择qp
/* Before encoding a frame, choose a QP for it */
void x264_ratecontrol_start( x264_t *h, int i_force_qp, int overhead )
{
    x264_ratecontrol_t *rc = h->rc;
    ratecontrol_entry_t *rce = NULL;
    x264_zone_t *zone = get_zone( h, h->fenc->i_frame );
    float q;

    x264_emms();

    // 对于zone设置, 重新配置编码器
    if( zone && (!rc->prev_zone || zone->param != rc->prev_zone->param) )
        x264_encoder_reconfig_apply( h, zone->param );
    rc->prev_zone = zone;

    // 对于两阶段编码, stat 将被读取
    if( h->param.rc.b_stat_read )
    {
        // 获得编码帧的序号
        int frame = h->fenc->i_frame;
       
        assert( frame >= 0 && frame < rc->num_entries );
        // 获取该帧的rce条目
        rce = h->rc->rce = &h->rc->entry[frame];

        if( h->sh.i_type == SLICE_TYPE_B
            && h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_AUTO )
        {
            // 直接空间预测
            h->sh.b_direct_spatial_mv_pred = ( rce->direct_mode == 's' );
            h->mb.b_direct_auto_read = ( rce->direct_mode == 's' || rce->direct_mode == 't' );
        }
    }

    if( rc->b_vbv )
    {
        // rc vbv 使能
        // 初始化重构帧的row变量
        memset( h->fdec->i_row_bits, 0, h->mb.i_mb_height * sizeof(int) );
        memset( h->fdec->f_row_qp, 0, h->mb.i_mb_height * sizeof(float) );
        memset( h->fdec->f_row_qscale, 0, h->mb.i_mb_height * sizeof(float) );
        // 将rc row_pred 指向当前帧类型的row_pred
        rc->row_pred = &rc->row_preds[h->sh.i_type];
        // 重新计算rc 的 buffer_rate
        rc->buffer_rate = h->fenc->i_cpb_duration * rc->vbv_max_rate * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale;
        // 计算缓冲区预计大小
        update_vbv_plan( h, overhead );

        const x264_level_t *l = x264_levels;
        while( l->level_idc != 0 && l->level_idc != h->param.i_level_idc )
            l++;

        // 获得对应level的mincr
        int mincr = l->mincr;

        if( h->param.b_bluray_compat )
            mincr = 4;

        /* Profiles above High don't require minCR, so just set the maximum to a large value. */
        // 对于 profile_idc 大于 PROFILE_HIGH,直接设置rc->frame_size_maximum
        if( h->sps->i_profile_idc > PROFILE_HIGH )
            rc->frame_size_maximum = 1e9;
        else
        {
            /* The spec has a bizarre special case for the first frame. */
            if( h->i_frame == 0 )
            {
                // 对于第一帧, 计算rc->frame_size_maximum
                //384 * ( Max( PicSizeInMbs, fR * MaxMBPS ) + MaxMBPS * ( tr( 0 ) - tr,n( 0 ) ) ) / MinCR
                double fr = 1. / 172;
                int pic_size_in_mbs = h->mb.i_mb_width * h->mb.i_mb_height;
                rc->frame_size_maximum = 384 * BIT_DEPTH * X264_MAX( pic_size_in_mbs, fr*l->mbps ) / mincr;
            }
            else
            {
                // 对于其他帧, 计算rc->frame_size_maximum
                // 384 * MaxMBPS * ( tr( n ) - tr( n - 1 ) ) / MinCR
                rc->frame_size_maximum = 384 * BIT_DEPTH * ((double)h->fenc->i_cpb_duration * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale) * l->mbps / mincr;
            }
        }
    }

    // 当前帧不是B帧, 获取当前帧的B帧数
    if( h->sh.i_type != SLICE_TYPE_B )
        rc->bframes = h->fenc->i_bframes;

    // 如果自适应码率控制
    if( rc->b_abr )
    {
        // 估计qscale, 然后转换为qp
        q = qscale2qp( rate_estimate_qscale( h ) );
    }
    else if( rc->b_2pass )
    {
        // 对于两阶段,同样估计qscale, 然后转换为qp
        rce->new_qscale = rate_estimate_qscale( h );
        q = qscale2qp( rce->new_qscale );
    }
    else /* CQP */
    {
        // 对于cqp(constant qp)设置
        // 如果当前帧B帧, 则其qp取B帧类型的常qp和P帧类型的常qp的平均值
        // 否则,直接取该帧类型的常qp
        if( h->sh.i_type == SLICE_TYPE_B && h->fdec->b_kept_as_ref )
            q = ( rc->qp_constant[ SLICE_TYPE_B ] + rc->qp_constant[ SLICE_TYPE_P ] ) / 2;
        else
            q = rc->qp_constant[ h->sh.i_type ];

        // 对于有zone, 调整qp
        if( zone )
        {
            if( zone->b_force_qp )
                q += zone->i_qp - rc->qp_constant[SLICE_TYPE_P];
            else
                q -= 6*log2f( zone->f_bitrate_factor );
        }
    }
    if( i_force_qp != X264_QP_AUTO )
        q = i_force_qp - 1;

    // 裁减 qp
    q = x264_clip3f( q, h->param.rc.i_qp_min, h->param.rc.i_qp_max );

    rc->qpa_rc = rc->qpa_rc_prev =
    rc->qpa_aq = rc->qpa_aq_prev = 0;
    // 将求得的qp赋值给rc->qp
    rc->qp = x264_clip3( q + 0.5f, 0, QP_MAX );
    // 将求得的qp赋值给重构帧的平均qp_avg_rc
    // 和qp_avg_aq, 和rc->qpm
    h->fdec->f_qp_avg_rc =
    h->fdec->f_qp_avg_aq =
    rc->qpm = q;
   
    // 两阶段
    if( rce )
        rce->new_qp = rc->qp;

    // 更新累计qp信息, 见accm_p_qp_update
    accum_p_qp_update( h, rc->qpm );

    // 如果当前帧不是B帧, 将帧类型
    // 赋值给rc->last_non_b_pict_type
    if( h->sh.i_type != SLICE_TYPE_B )
        rc->last_non_b_pict_type = h->sh.i_type;
}


// provisionally update VBV according to the planned size of all frames currently in progress
// 计算缓冲区预计大小
static void update_vbv_plan( x264_t *h, int overhead )
{
    x264_ratecontrol_t *rcc = h->rc;

    rcc->buffer_fill = h->thread[0]->rc->buffer_fill_final / h->sps->vui.i_time_scale;
    if( h->i_thread_frames > 1 )
    {
        int j = h->rc - h->thread[0]->rc;
        for( int i = 1; i < h->i_thread_frames; i++ )
        {
            x264_t *t = h->thread[ (j+i)%h->i_thread_frames ];
            double bits = t->rc->frame_size_planned;
            if( !t->b_thread_active )
                continue;
            bits = X264_MAX(bits, t->rc->frame_size_estimated);
            rcc->buffer_fill -= bits;
            rcc->buffer_fill = X264_MAX( rcc->buffer_fill, 0 );
            rcc->buffer_fill += t->rc->buffer_rate;
            rcc->buffer_fill = X264_MIN( rcc->buffer_fill, rcc->buffer_size );
        }
    }
    rcc->buffer_fill = X264_MIN( rcc->buffer_fill, rcc->buffer_size );
    rcc->buffer_fill -= overhead;
}


static void accum_p_qp_update( x264_t *h, float qp )
{
    x264_ratecontrol_t *rc = h->rc;
    rc->accum_p_qp   *= .95;
    rc->accum_p_norm *= .95;
    rc->accum_p_norm += 1;
    if( h->sh.i_type == SLICE_TYPE_I )
        rc->accum_p_qp += qp + rc->ip_offset;
    else
        rc->accum_p_qp += qp;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
详细解释以下Python代码:import numpy as np import adi import matplotlib.pyplot as plt sample_rate = 1e6 # Hz center_freq = 915e6 # Hz num_samps = 100000 # number of samples per call to rx() sdr = adi.Pluto("ip:192.168.2.1") sdr.sample_rate = int(sample_rate) # Config Tx sdr.tx_rf_bandwidth = int(sample_rate) # filter cutoff, just set it to the same as sample rate sdr.tx_lo = int(center_freq) sdr.tx_hardwaregain_chan0 = -50 # Increase to increase tx power, valid range is -90 to 0 dB # Config Rx sdr.rx_lo = int(center_freq) sdr.rx_rf_bandwidth = int(sample_rate) sdr.rx_buffer_size = num_samps sdr.gain_control_mode_chan0 = 'manual' sdr.rx_hardwaregain_chan0 = 0.0 # dB, increase to increase the receive gain, but be careful not to saturate the ADC # Create transmit waveform (QPSK, 16 samples per symbol) num_symbols = 1000 x_int = np.random.randint(0, 4, num_symbols) # 0 to 3 x_degrees = x_int*360/4.0 + 45 # 45, 135, 225, 315 degrees x_radians = x_degrees*np.pi/180.0 # sin() and cos() takes in radians x_symbols = np.cos(x_radians) + 1j*np.sin(x_radians) # this produces our QPSK complex symbols samples = np.repeat(x_symbols, 16) # 16 samples per symbol (rectangular pulses) samples *= 2**14 # The PlutoSDR expects samples to be between -2^14 and +2^14, not -1 and +1 like some SDRs # Start the transmitter sdr.tx_cyclic_buffer = True # Enable cyclic buffers sdr.tx(samples) # start transmitting # Clear buffer just to be safe for i in range (0, 10): raw_data = sdr.rx() # Receive samples rx_samples = sdr.rx() print(rx_samples) # Stop transmitting sdr.tx_destroy_buffer() # Calculate power spectral density (frequency domain version of signal) psd = np.abs(np.fft.fftshift(np.fft.fft(rx_samples)))**2 psd_dB = 10*np.log10(psd) f = np.linspace(sample_rate/-2, sample_rate/2, len(psd)) # Plot time domain plt.figure(0) plt.plot(np.real(rx_samples[::100])) plt.plot(np.imag(rx_samples[::100])) plt.xlabel("Time") # Plot freq domain plt.figure(1) plt.plot(f/1e6, psd_dB) plt.xlabel("Frequency [MHz]") plt.ylabel("PSD") plt.show(),并分析该代码中QPSK信号的功率谱密度图的特点
最新发布
06-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值