📄 umc_h264_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 "umc_h264_pub.h"#include "umc_h264_video_encoder.h"namespace UMC {int H264VideoEncoder::PictureRateControl(){ PictureStructure picture_structure = m_PicParamSet.picture_structure; int isfield = (picture_structure != FRAME_PICTURE); double ip_delay; // secondfield should be moved to class, code to frame start // Should be corrected, if one decides to place a bottom field before the top. int secondfield = (picture_structure == BOTTOM_FIELD); EnumSliceType slice_type = m_SliceHeader.slice_type; if(BitRate <= 0) { changeQuant(qscale[slice_type]); // changes also intra_dc_precision, q_scale_type vbv_delay = 0xffff; return quantiser_scale_value; } // There is no warranty that there won't be a field coded picture. 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(slice_type != BPREDSLICE) { 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 - (VBV_BufferSize*16384 - rc_delay)); int q0, q2, sz1; q0 = qscale[slice_type]; // proposed from post picture q2 = prqscale[slice_type]; // last used scale sz1 = prsize[slice_type]; // last coded size // compute newscale again // adaptation to current rate deviation double target_size = rc_tagsize[slice_type]; int wanted_size = (int)(target_size - rc_dev / 3 * target_size / rc_tagsize[INTRASLICE]); 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[slice_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 H264VideoEncoder::PostPictureRateControl(Ipp64s bits_encoded){ EnumSliceType slice_type = m_SliceHeader.slice_type; int isfield = (m_PicParamSet.picture_structure != FRAME_PICTURE); Ipp64s vbv_size = VBV_BufferSize * 16384; int ret = 0; { Ipp64s tmp = bits_encoded - lastEncodedBits; lastEncodedBits = bits_encoded; bits_encoded = tmp; } prsize[slice_type] = (int)bits_encoded << isfield; prqscale[slice_type] = qscale[slice_type]; if(BitRate <= 0) { return 0; } rc_vbv_fullness = rc_vbv_fullness - bits_encoded; rc_vbv_fullness += rc_delay; // int cur_qscale = qscale[slice_type]; double target_size = rc_tagsize[slice_type]; rc_dev += bits_encoded - (isfield ? target_size/2 : target_size); int wanted_size = (int)(target_size - rc_dev / 3 * target_size / rc_tagsize[INTRASLICE]); 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(slice_type == INTRASLICE) { if( newscale+1 > qscale[PREDSLICE] ) qscale[PREDSLICE] = newscale+1; if( newscale+2 > qscale[BPREDSLICE] ) qscale[BPREDSLICE] = newscale+2; } else if(slice_type == PREDSLICE) { if( newscale < qscale[INTRASLICE] ) { del_sc = qscale[INTRASLICE] - newscale; qscale[INTRASLICE] -= del_sc/2; newscale = qscale[INTRASLICE]; newscale = changeQuant(newscale); } if( newscale+1 > qscale[BPREDSLICE] ) qscale[BPREDSLICE] = newscale+1; } else { if( newscale < qscale[PREDSLICE] ) { del_sc = qscale[PREDSLICE] - newscale; qscale[PREDSLICE] -= del_sc/2; newscale = qscale[PREDSLICE]; newscale = changeQuant(newscale); if( qscale[PREDSLICE] < qscale[INTRASLICE] ) qscale[INTRASLICE] = qscale[PREDSLICE]; } } qscale[slice_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 H264VideoEncoder::ChangeBitrate(H264EncoderParams *new_info){ if (new_info->rate_controls.bitrate == (Ipp32u)BitRate) { return 0; // Nothing to be done. } int frame_width_in_mbs = (m_info.src_width + 15)/16; int frame_height_in_mbs = (m_info.src_height + 15)/16; m_info.rate_controls.bitrate = BitRate = new_info->rate_controls.bitrate; InitRateControl(frame_width_in_mbs, frame_height_in_mbs); return 0;}int H264VideoEncoder::InitRateControl(int frame_width_in_mbs, int frame_height_in_mbs){ double ppb; //pixels per bit (~ density) int i; int block_count = 6; // for YUV420!!! lastEncodedBits = 0; if (BitRate <= 0) { // not given bitrate BitRate = 0; vbv_delay = 0xffff; // unused qscale[INTRASLICE] = 4; // values from air qscale[PREDSLICE] = 6; qscale[BPREDSLICE] = 8; return 0; } //FrameRate = ratetab[encodeInfo.frame_rate_code - 1]; { int YUVFrameSize = frame_width_in_mbs*frame_height_in_mbs*(256+128); // YUV 420!!! double pixrate = 8/*bits*/*FrameRate * YUVFrameSize; if((double)BitRate > pixrate) BitRate = (int)(pixrate); // too high if((double)BitRate < pixrate/500) BitRate = (int)(pixrate/500); // too low#if defined _DEBUG if (BitRate != BitRate) fprintf(stderr,"BitRate value fixed\n");#endif //_DEBUG BitRate = (BitRate+399)/400*400; // 400 bps step } // if 0 - could be no rc rc_ave_frame_bits = BitRate/FrameRate; if(VBV_BufferSize <= (int)(rc_ave_frame_bits / 16384 * 4) ) { // avoid too small VBV_BufferSize = (int)(rc_ave_frame_bits / 16384 * 8); } VBV_BufferSize = VBV_BufferSize; quantiser_scale_value = 0; // one can vary weights, can be added to API rc_weight[INTRASLICE] = 200; rc_weight[PREDSLICE] = 40; rc_weight[BPREDSLICE] = 12; //M = encodeInfo.IPDistance; //N = encodeInfo.gopSize; if(!N) { // Only the first I picture per stream. N = 100; // Use this approximation instead. } double nr = N/M; double Pnum = (nr > 1)? nr-1: min(nr, (double)(N>1)); double gopw = (M-1)*rc_weight[BPREDSLICE]*nr + rc_weight[PREDSLICE]*Pnum + rc_weight[INTRASLICE]; double u_len = rc_ave_frame_bits * N / gopw; rc_tagsize[INTRASLICE] = u_len * rc_weight[INTRASLICE]; rc_tagsize[PREDSLICE] = u_len * rc_weight[PREDSLICE]; rc_tagsize[BPREDSLICE] = u_len * rc_weight[BPREDSLICE]; // we want ideal case - I frame to be centered in vbv buffer, compute start pos rc_vbv_fullness = VBV_BufferSize * 16384 / 2 + // half of vbv_buffer rc_tagsize[INTRASLICE] / 2 + // top to center length of I frame (M-1) * (rc_ave_frame_bits - rc_tagsize[BPREDSLICE]); // 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[INTRASLICE] * N); ppb = frame_width_in_mbs*frame_height_in_mbs*256*FrameRate/BitRate * (block_count-2) / (6-2); qscale[INTRASLICE] = (int)(41.0 * rrel * ppb); // numbers are empiric qscale[PREDSLICE] = (int)(60.0 * rrel * ppb); qscale[BPREDSLICE] = (int)(120.0 * rrel * ppb); for(i=0; i<3; i++) { if (qscale[i]< 1) qscale[i]= 1; else if(qscale[i]>51) qscale[i]=51; // can be even more prqscale[i] = qscale[i]; prsize[i] = (int)rc_tagsize[i]; // for first iteration } return 0;}int H264VideoEncoder::mapQuant(int quant_value){ int qs_code; qs_code = quant_value; if(qs_code < 1) qs_code = 1; if(qs_code > 51) qs_code = 51; return qs_code;}int H264VideoEncoder::changeQuant(int quant_value){ //int curq = m_fpar.quant_scale_value; int curq = quantiser_scale_value; if(quant_value == quantiser_scale_value) return quantiser_scale_value; quantiser_scale_code = quant_value; if(quantiser_scale_code < 1) quantiser_scale_code = 1; if(quantiser_scale_code > 51) quantiser_scale_code = 51; quantiser_scale_value = quantiser_scale_code; if(quantiser_scale_value == curq) { if(quant_value > curq) if(quantiser_scale_code == 51) 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 = 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 + -