分享

homerHEVC代码阅读(42)——码率控制

 托尼虎 2018-12-05
一、码率控制的相关理论请看: HEVC/H.265理论知识(9)——码率控制

二、码率控制可以分为几个几个级别,HomerHEVC只支持帧级和CTU级的码率控制

三、码率控制实际就是控制量化参数,通过量化参数来提高码率或者降低码率

四、码率控制基本都要配备缓冲区,因为码率控制不可能完全精确,因此需要使用缓冲区来匹配比特生成的速度和发送的速度

码率控制初始化,基本就是根据缓冲区计算,每一个CTU应该分配多少比特数:

  1. void hmr_rc_init(hvenc_engine_t* enc_engine)
  2. {
  3. /* 缓冲区的大小 */
  4. enc_engine->rc.vbv_size = enc_engine->vbv_size*1000;
  5. enc_engine->rc.vbv_fullness = enc_engine->vbv_init*1000;
  6. /* 每一帧平均的尺寸 */
  7. enc_engine->rc.average_pict_size = enc_engine->bitrate*1000/enc_engine->frame_rate;
  8. /* 每一个CTU平均的比特数 */
  9. enc_engine->rc.average_bits_per_ctu = enc_engine->rc.average_pict_size/enc_engine->pict_total_ctu;
  10. enc_engine->hvenc->rc = enc_engine->rc;
  11. }

帧级码率控制初始化,目的是计算一帧的目标比特数:
  1. void hmr_rc_init_pic(hvenc_engine_t* enc_engine, slice_t *currslice)
  2. {
  3. int ithreads;
  4. int clipped_intra_period = enc_engine->intra_period==0?20:enc_engine->intra_period;
  5. double intra_avg_size = 2.25*enc_engine->rc.average_pict_size*sqrt((double)clipped_intra_period);
  6. enc_engine->rc = enc_engine->hvenc->rc;
  7. enc_engine->rc.extra_bits = 0;
  8. switch(currslice->slice_type)
  9. {
  10. case I_SLICE:
  11. {
  12. enc_engine->rc.target_pict_size = min(intra_avg_size, enc_engine->rc.vbv_fullness);///*(2.25-((double)enc_engine->avg_dist/15000.))**/2.25*enc_engine->rc.average_pict_size*sqrt((double)clipped_intra_period);
  13. if(enc_engine->num_b>0)
  14. enc_engine->rc.target_pict_size *= (1.0+.1*enc_engine->num_b);//.5*enc_engine->rc.average_pict_size;
  15. break;
  16. }
  17. case P_SLICE:
  18. {
  19. enc_engine->rc.target_pict_size = (enc_engine->rc.average_pict_size*clipped_intra_period-intra_avg_size)/(clipped_intra_period-1);//.5*enc_engine->rc.average_pict_size;
  20. if(enc_engine->num_b>0)
  21. enc_engine->rc.target_pict_size *= (1.0+.1*enc_engine->num_b);//.5*enc_engine->rc.average_pict_size;
  22. break;
  23. }
  24. case B_SLICE:
  25. {
  26. enc_engine->rc.target_pict_size = enc_engine->rc.average_pict_size/2;
  27. break;
  28. }
  29. }
  30. #ifdef COMPUTE_AS_HM
  31. currslice->qp = enc_engine->pict_qp-(enc_engine->num_encoded_frames%4);
  32. if(currslice->qp<1)
  33. {
  34. currslice->qp=1;
  35. }
  36. #endif
  37. enc_engine->rc.target_bits_per_ctu = enc_engine->rc.target_pict_size/enc_engine->pict_total_ctu;
  38. for(ithreads=0;ithreads<enc_engine->wfpp_num_threads;ithreads++)
  39. {
  40. henc_thread_t* henc_th = enc_engine->thread[ithreads];
  41. henc_th->target_pict_size = (uint32_t)enc_engine->rc.target_pict_size;
  42. henc_th->num_encoded_ctus = 0;
  43. henc_th->num_bits = 0;
  44. henc_th->acc_qp = 0;
  45. }
  46. enc_engine->hvenc->rc = enc_engine->rc;
  47. }

如果屏幕大小改变了,那么需要调整目标比特数:
  1. void hmr_rc_change_pic_mode(henc_thread_t* et, slice_t *currslice)
  2. {
  3. hvenc_engine_t* enc_engine = et->enc_engine;
  4. int clipped_intra_period = (enc_engine->intra_period==0)?20:enc_engine->intra_period;
  5. double pic_size_new;
  6. int consumed_bitrate = 0;
  7. int consumed_ctus = 0;
  8. int current_pic_size = enc_engine->rc.target_pict_size;
  9. // if(enc_engine->is_scene_change)
  10. {
  11. int ithreads;
  12. if(et->enc_engine->gop_reinit_on_scene_change && enc_engine->rc.vbv_fullness<.5*enc_engine->rc.vbv_size)
  13. {
  14. pic_size_new = 1.*enc_engine->rc.average_pict_size*sqrt((double)clipped_intra_period);
  15. }
  16. else
  17. {
  18. pic_size_new = .75*enc_engine->rc.average_pict_size*sqrt((double)clipped_intra_period);
  19. }
  20. enc_engine->rc.target_pict_size = min(pic_size_new, enc_engine->rc.vbv_fullness);
  21. enc_engine->rc.target_bits_per_ctu = enc_engine->rc.target_pict_size/enc_engine->pict_total_ctu;
  22. for(ithreads=0;ithreads<enc_engine->wfpp_num_threads;ithreads++)
  23. {
  24. henc_thread_t* henc_th = enc_engine->thread[ithreads];
  25. henc_th->target_pict_size = (uint32_t)enc_engine->rc.target_pict_size;
  26. consumed_bitrate += henc_th->num_bits;
  27. consumed_ctus += henc_th->num_encoded_ctus;
  28. }
  29. enc_engine->rc.extra_bits = enc_engine->rc.target_pict_size*((double)consumed_ctus/et->enc_engine->pict_total_ctu)-consumed_bitrate;//clip(((double)pic_size_new/current_pic_size)*consumed_bitrate - consumed_bitrate, 0, pic_size_new/2);
  30. }
  31. enc_engine->hvenc->rc = enc_engine->rc;
  32. }

根据码率控制获取CTU的量化参数:
  1. int hmr_rc_get_cu_qp(henc_thread_t* et, ctu_info_t *ctu, cu_partition_info_t *curr_cu_info, slice_t *currslice)
  2. {
  3. int qp;
  4. #ifdef COMPUTE_AS_HM
  5. double debug_qp = currslice->qp+ctu->ctu_number%4;//28+ctu->ctu_number%4;
  6. if(et->enc_engine->bitrate_mode == BR_FIXED_QP)
  7. {
  8. qp = et->enc_engine->current_pict.slice.qp;
  9. }
  10. else//cbr, vbr
  11. {
  12. if(curr_cu_info->depth <= et->enc_engine->qp_depth)
  13. qp = (int)debug_qp;//hmr_rc_calc_cu_qp(et);
  14. else
  15. qp = curr_cu_info->parent->qp;
  16. }
  17. #else
  18. if(et->enc_engine->bitrate_mode == BR_FIXED_QP)
  19. {
  20. qp = et->enc_engine->current_pict.slice.qp;
  21. }
  22. else//cbr, vbr
  23. {
  24. if(curr_cu_info->depth <= et->enc_engine->qp_depth)
  25. {
  26. qp = hmr_rc_calc_cu_qp(et, ctu, currslice);
  27. }
  28. else
  29. qp = curr_cu_info->parent->qp;
  30. }
  31. #endif
  32. return qp;
  33. }
  1. int hmr_rc_calc_cu_qp(henc_thread_t* curr_thread, ctu_info_t *ctu/*, cu_partition_info_t *curr_cu_info*/, slice_t *currslice)
  2. {
  3. hvenc_engine_t* enc_engine = curr_thread->enc_engine;
  4. int ithreads;
  5. double qp;
  6. double pic_corrector = 0.0;
  7. double vbv_corrector;
  8. double consumed_bitrate = 0.0, entropy;
  9. double min_vbv_size;
  10. int consumed_ctus = 0;
  11. for(ithreads=0;ithreads<enc_engine->wfpp_num_threads;ithreads++)
  12. {
  13. henc_thread_t* henc_th = enc_engine->thread[ithreads];
  14. consumed_bitrate += henc_th->num_bits;
  15. consumed_ctus += henc_th->num_encoded_ctus;
  16. }
  17. entropy = 3;//sqrt(((double)enc_engine->avg_dist/3000.)*(curr_cu_info->variance))/40;//25.0;
  18. consumed_bitrate += enc_engine->rc.extra_bits;
  19. // if(consumed_ctus>0 && (currslice->slice_type != P_SLICE || enc_engine->is_scene_change))
  20. {
  21. if(consumed_bitrate>1.5*enc_engine->rc.target_bits_per_ctu*consumed_ctus)//*consumed_ctus && currslice->slice_type != I_SLICE)
  22. {
  23. if(currslice->slice_type == I_SLICE)
  24. pic_corrector = 2.5*.0125*(consumed_bitrate/(enc_engine->rc.target_bits_per_ctu*consumed_ctus));
  25. else
  26. pic_corrector = .0125*(consumed_bitrate/(enc_engine->rc.target_bits_per_ctu*consumed_ctus));
  27. }
  28. pic_corrector = clip(pic_corrector, 0, .5);
  29. }
  30. min_vbv_size = clip(enc_engine->rc.vbv_fullness,enc_engine->rc.vbv_fullness,enc_engine->rc.vbv_size*.95);
  31. if(consumed_bitrate>enc_engine->rc.target_bits_per_ctu*consumed_ctus)
  32. vbv_corrector = 1.0-clip((min_vbv_size-consumed_bitrate+enc_engine->rc.target_bits_per_ctu*consumed_ctus)/enc_engine->rc.vbv_size, 0.0, 1.0);
  33. else
  34. vbv_corrector = 1.0-clip((min_vbv_size)/enc_engine->rc.vbv_size, 0.0, 1.0);
  35. qp = ((pic_corrector+vbv_corrector)/1.)*(MAX_QP)+/*(pic_corrector-1)+*/(entropy-3.);
  36. //variable rate
  37. if(enc_engine->bitrate_mode == BR_VBR)
  38. {
  39. if(qp<enc_engine->qp_min)
  40. qp=enc_engine->qp_min;
  41. }
  42. if(curr_thread->enc_engine->intra_period>1)
  43. {
  44. if(currslice->slice_type == I_SLICE || (enc_engine->is_scene_change && enc_engine->gop_reinit_on_scene_change))
  45. {
  46. qp/=clip(1.5-((double)enc_engine->avg_dist/15000.),1.15,1.5);
  47. }
  48. else if(currslice->slice_type == B_SLICE && enc_engine->num_b!=enc_engine->gop_size)
  49. {
  50. qp*=clip(1.125-((double)enc_engine->avg_dist/15000.),1.15,1.5);
  51. }
  52. else if(enc_engine->is_scene_change)
  53. qp/=1.1;
  54. }
  55. if((enc_engine->is_scene_change) && qp<=5)
  56. {
  57. qp=5;
  58. }
  59. if(enc_engine->num_encoded_frames==0)
  60. {
  61. qp+=4;
  62. }
  63. else if(currslice->slice_type == I_SLICE && consumed_bitrate > 1.*(enc_engine->rc.target_bits_per_ctu*consumed_ctus) && enc_engine->rc.vbv_fullness<.5*enc_engine->rc.vbv_size)//control scene changes in I frames
  64. {
  65. qp+=2;
  66. }
  67. return (int)clip(qp+.5,1.0,MAX_QP);
  68. }

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多