📄 tran_rc.cpp
字号:
/*//// INTEL CORPORATION PROPRIETARY INFORMATION// This software is supplied under the terms of a license agreement or// nondisclosure agreement with Intel Corporation and may not be copied// or disclosed except in accordance with the terms of that agreement.// Copyright (c) 2005 Intel Corporation. All Rights Reserved.//// Purpose// frame adaptive bitrate control*/#include "mpeg2_defs.h"/* quant scale values table ISO/IEC 13818-2, 7.4.2.2 table 7-6 */static int Val_QScale[2][32] ={ /* linear q_scale */ {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62}, /* non-linear q_scale */ {0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36, 40, 44, 48, 52, 56, 64, 72, 80, 88, 96,104,112}};int ippMPEG2VideoEncoder::PictureRateControl(){ int isfield = (picture_structure != FRAME_PICTURE); double ip_delay; // secondfield should be moved to class, code to frame start int secondfield = (encodeInfo.top_field_first == (picture_structure == BOTTOM_FIELD)); if(BitRate <= 0) { changeQuant(qscale[picture_coding_type-I_TYPE]); // changes also intra_dc_precision, q_scale_type vbv_delay = 0xffff; return quantiser_scale_value; } if(encodeInfo.prog_seq) { rc_delay = rc_ave_frame_bits; if(encodeInfo.repeat_first_field) rc_delay += rc_ave_frame_bits; if(encodeInfo.top_field_first) rc_delay += rc_ave_frame_bits; } else { rc_delay = rc_ave_frame_bits; if(!isfield) rc_delay += rc_ave_frame_bits; if(encodeInfo.repeat_first_field) rc_delay += rc_ave_frame_bits; rc_delay = rc_delay / 2; } if(picture_coding_type != B_TYPE) { ip_delay = rc_delay; if(!isfield) { rc_delay = rc_ip_delay; rc_ip_delay = ip_delay; } else if(secondfield) { rc_delay = rc_ip_delay - rc_delay; rc_ip_delay = 2*ip_delay; } } vbv_delay = (int)(rc_vbv_fullness * 90000.0/BitRate); if(vbv_delay < 0) vbv_delay = 0; // for a while // vbv computations for len range rc_vbv_max = (int)rc_vbv_fullness; rc_vbv_min = (int)(rc_vbv_fullness - (encodeInfo.VBV_BufferSize*16384 - rc_delay)); int q0, q2, sz1; q0 = qscale[picture_coding_type-I_TYPE]; // proposed from post picture q2 = prqscale[picture_coding_type-I_TYPE]; // last used scale sz1 = prsize[picture_coding_type-I_TYPE]; // last coded size // compute newscale again // adaptation to current rate deviation double target_size = rc_tagsize[picture_coding_type-I_TYPE]; int wanted_size = (int)(target_size - rc_dev / 3 * target_size / rc_tagsize[0]); if (sz1 > 2*wanted_size) q2 = q2 * 3 / 2 + 1; else if(sz1 > wanted_size+100) q2 ++; else if(2*sz1 < wanted_size) q2 = q2 * 3 / 4; else if(sz1 < wanted_size-100) q2 --; if(rc_dev > 0) { q2 = max(q0,q2); } else { q2 = min(q0,q2); } // this call is used to accept small changes in value, which are mapped to the same code // changeQuant bothers about to change scale code if value changes q2 = changeQuant(q2); qscale[picture_coding_type-I_TYPE] = q2; return quantiser_scale_value;}// encoded size check, vbv computation, qscale code adaptation// returns positive bitcount when vbv overflow,// negative bitcount when vbv underflow, 0 if OKint ippMPEG2VideoEncoder::PostPictureRateControl(Ipp64s bits_encoded){ int isfield = (picture_structure != FRAME_PICTURE); Ipp64s vbv_size = encodeInfo.VBV_BufferSize * 16384; int ret = 0; prsize[picture_coding_type-I_TYPE] = (int)bits_encoded << isfield; prqscale[picture_coding_type-I_TYPE] = qscale[picture_coding_type-I_TYPE]; if(BitRate <= 0) { return 0; } rc_vbv_fullness = rc_vbv_fullness - bits_encoded; rc_vbv_fullness += rc_delay; // int cur_qscale = qscale[picture_coding_type-I_TYPE]; double target_size = rc_tagsize[picture_coding_type-I_TYPE]; rc_dev += bits_encoded - (isfield ? target_size/2 : target_size); int wanted_size = (int)(target_size - rc_dev / 3 * target_size / rc_tagsize[0]); int newscale; int del_sc; newscale = cur_qscale; wanted_size >>= isfield; if(bits_encoded > wanted_size) newscale ++; if(bits_encoded > 2*wanted_size) newscale = cur_qscale * 3 / 2 + 1; if(bits_encoded < wanted_size) newscale --; if(2*bits_encoded < wanted_size) newscale = cur_qscale * 3 / 4; // this call is used to accept small changes in value, which are mapped to the same code // changeQuant bothers about to change scale code if value changes newscale = changeQuant(newscale); if(picture_coding_type == I_TYPE) { if( newscale+1 > qscale[1] ) qscale[1] = newscale+1; if( newscale+2 > qscale[2] ) qscale[2] = newscale+2; } else if(picture_coding_type == P_TYPE) { if( newscale < qscale[0] ) { del_sc = qscale[0] - newscale; qscale[0] -= del_sc/2; newscale = qscale[0]; newscale = changeQuant(newscale); } if( newscale+1 > qscale[2] ) qscale[2] = newscale+1; } else { if( newscale < qscale[1] ) { del_sc = qscale[1] - newscale; qscale[1] -= del_sc/2; newscale = qscale[1]; newscale = changeQuant(newscale); if( qscale[1] < qscale[0] ) qscale[0] = qscale[1]; } } qscale[picture_coding_type-I_TYPE] = newscale; if(rc_vbv_fullness > vbv_size) { ret = (int)(rc_vbv_fullness - vbv_size); } if(rc_vbv_fullness < rc_delay) { ret = (int)(rc_vbv_fullness - rc_delay); } return ret;}int ippMPEG2VideoEncoder::InitRateControl(){ double ppb; //pixels per bit (~ density) int i; if (BitRate <= 0) { // not given bitrate BitRate = 0; vbv_delay = 0xffff; // unused qscale[0] = 4; // values from air qscale[1] = 6; qscale[2] = 8; for (i=0; i<3; i++) { // in old parfile nonLinearQScale used to set qscale, in common - it's 0 or 1 if (encodeInfo.nonLinearQScale[i] > 1) qscale[i] = encodeInfo.nonLinearQScale[i]; } return 0; } // one can vary weights, can be added to API rc_weight[0] = 120; rc_weight[1] = 50; rc_weight[2] = 25; //M = encodeInfo.IPDistance; //N = encodeInfo.gopSize; double nr = N/M; double gopw = (M-1)*rc_weight[2]*nr + rc_weight[1]*(nr-1) + rc_weight[0]; double u_len = rc_ave_frame_bits * N / gopw; rc_tagsize[0] = u_len * rc_weight[0]; rc_tagsize[1] = u_len * rc_weight[1]; rc_tagsize[2] = u_len * rc_weight[2]; // if bitrate is 0 - could be no rc rc_ave_frame_bits = BitRate/FrameRate; // we want ideal case - I frame to be centered in vbv buffer, compute start pos rc_vbv_fullness = encodeInfo.VBV_BufferSize * 16384 / 2 + // half of vbv_buffer rc_tagsize[0] / 2 + // top to center length of I frame (M-1) * (rc_ave_frame_bits - rc_tagsize[2]); // first gop has no M-1 B frames: add'em vbv_delay = (int)(rc_vbv_fullness*90000.0/BitRate); // bits to clocks rc_vbv_max = (int)(rc_vbv_fullness); rc_ip_delay = rc_ave_frame_bits; rc_dev = 0; // deviation from ideal bitrate (should be float or renewed) double rrel = gopw / (rc_weight[0] * N); ppb = srcYFrameHSize*srcYFrameVSize*FrameRate/BitRate * (block_count-2) / (6-2); qscale[0] = (int)(6.0 * rrel * ppb); // numbers are empiric qscale[1] = (int)(9.0 * rrel * ppb); qscale[2] = (int)(12.0 * rrel * ppb); for(i=0; i<3; i++) { if (qscale[i]< 1) qscale[i]= 1; else if(qscale[i]>63) qscale[i]=63; // can be even more prqscale[i] = qscale[i]; prsize[i] = (int)rc_tagsize[i]; // for first iteration } return 0;}int ippMPEG2VideoEncoder::mapQuant(int quant_value){ int qs_type, qs_code; if(encodeInfo.mpeg1 || (quant_value > 7 && quant_value <= 62)) { qs_type = 0; qs_code = (quant_value + 1) >> 1; } else { // non-linear quantizer qs_type = 1; if(quant_value <= 8) qs_code = quant_value; else /* if(quant_value > 62) */ qs_code = 25+((quant_value-64+4)>>3); } if(qs_code < 1) qs_code = 1; if(qs_code > 31) qs_code = 31; return Val_QScale[qs_type][qs_code];}int ippMPEG2VideoEncoder::changeQuant(int quant_value){ int curq = quantiser_scale_value; if(quant_value == quantiser_scale_value) return quantiser_scale_value; if(encodeInfo.mpeg1 || (quant_value > 7 && quant_value <= 62)) { q_scale_type = 0; quantiser_scale_code = (quant_value + 1) >> 1; } else { // non-linear quantizer q_scale_type = 1; if(quant_value <= 8) quantiser_scale_code = quant_value; else if(quant_value > 62) quantiser_scale_code = 25+((quant_value-64+4)>>3); } if(quantiser_scale_code < 1) quantiser_scale_code = 1; if(quantiser_scale_code > 31) quantiser_scale_code = 31; quantiser_scale_value = Val_QScale[q_scale_type][quantiser_scale_code]; if(quantiser_scale_value == curq) { if(quant_value > curq) if(quantiser_scale_code == 31) return quantiser_scale_value; else quantiser_scale_code ++; if(quant_value < curq) if(quantiser_scale_code == 1) return quantiser_scale_value; else quantiser_scale_code --; quantiser_scale_value = Val_QScale[q_scale_type][quantiser_scale_code]; } if(encodeInfo.mpeg1 || quantiser_scale_value >= 16) encodeInfo.intra_dc_precision = 0; else if(quantiser_scale_value >= 4) encodeInfo.intra_dc_precision = 1; else encodeInfo.intra_dc_precision = 2; // only for High profile //if(quantiser_scale_value == 1) encodeInfo.intra_dc_precision = 3; return quantiser_scale_value;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -