• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2020 The WebM project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include <stddef.h>
12 
13 #include "vp9/encoder/vp9_ext_ratectrl.h"
14 #include "vp9/encoder/vp9_encoder.h"
15 #include "vp9/common/vp9_common.h"
16 #include "vpx_dsp/psnr.h"
17 #include "vpx/vpx_codec.h"
18 #include "vpx/vpx_ext_ratectrl.h"
19 #include "vpx/vpx_tpl.h"
20 
vp9_extrc_init(EXT_RATECTRL * ext_ratectrl)21 vpx_codec_err_t vp9_extrc_init(EXT_RATECTRL *ext_ratectrl) {
22   if (ext_ratectrl == NULL) {
23     return VPX_CODEC_INVALID_PARAM;
24   }
25   vp9_zero(*ext_ratectrl);
26   return VPX_CODEC_OK;
27 }
28 
vp9_extrc_create(vpx_rc_funcs_t funcs,vpx_rc_config_t ratectrl_config,EXT_RATECTRL * ext_ratectrl)29 vpx_codec_err_t vp9_extrc_create(vpx_rc_funcs_t funcs,
30                                  vpx_rc_config_t ratectrl_config,
31                                  EXT_RATECTRL *ext_ratectrl) {
32   vpx_rc_status_t rc_status;
33   vpx_rc_firstpass_stats_t *rc_firstpass_stats;
34   if (ext_ratectrl == NULL) {
35     return VPX_CODEC_INVALID_PARAM;
36   }
37   vp9_extrc_delete(ext_ratectrl);
38   ext_ratectrl->funcs = funcs;
39   ext_ratectrl->ratectrl_config = ratectrl_config;
40   rc_status = ext_ratectrl->funcs.create_model(ext_ratectrl->funcs.priv,
41                                                &ext_ratectrl->ratectrl_config,
42                                                &ext_ratectrl->model);
43   if (rc_status == VPX_RC_ERROR) {
44     return VPX_CODEC_ERROR;
45   }
46   rc_firstpass_stats = &ext_ratectrl->rc_firstpass_stats;
47   rc_firstpass_stats->num_frames = ratectrl_config.show_frame_count;
48   rc_firstpass_stats->frame_stats =
49       vpx_malloc(sizeof(*rc_firstpass_stats->frame_stats) *
50                  rc_firstpass_stats->num_frames);
51   if (rc_firstpass_stats->frame_stats == NULL) {
52     return VPX_CODEC_MEM_ERROR;
53   }
54   ext_ratectrl->ready = 1;
55   return VPX_CODEC_OK;
56 }
57 
vp9_extrc_delete(EXT_RATECTRL * ext_ratectrl)58 vpx_codec_err_t vp9_extrc_delete(EXT_RATECTRL *ext_ratectrl) {
59   if (ext_ratectrl == NULL) {
60     return VPX_CODEC_INVALID_PARAM;
61   }
62   if (ext_ratectrl->ready) {
63     vpx_rc_status_t rc_status =
64         ext_ratectrl->funcs.delete_model(ext_ratectrl->model);
65     if (rc_status == VPX_RC_ERROR) {
66       return VPX_CODEC_ERROR;
67     }
68     vpx_free(ext_ratectrl->rc_firstpass_stats.frame_stats);
69   }
70   return vp9_extrc_init(ext_ratectrl);
71 }
72 
gen_rc_firstpass_stats(const FIRSTPASS_STATS * stats,vpx_rc_frame_stats_t * rc_frame_stats)73 static void gen_rc_firstpass_stats(const FIRSTPASS_STATS *stats,
74                                    vpx_rc_frame_stats_t *rc_frame_stats) {
75   rc_frame_stats->frame = stats->frame;
76   rc_frame_stats->weight = stats->weight;
77   rc_frame_stats->intra_error = stats->intra_error;
78   rc_frame_stats->coded_error = stats->coded_error;
79   rc_frame_stats->sr_coded_error = stats->sr_coded_error;
80   rc_frame_stats->frame_noise_energy = stats->frame_noise_energy;
81   rc_frame_stats->pcnt_inter = stats->pcnt_inter;
82   rc_frame_stats->pcnt_motion = stats->pcnt_motion;
83   rc_frame_stats->pcnt_second_ref = stats->pcnt_second_ref;
84   rc_frame_stats->pcnt_neutral = stats->pcnt_neutral;
85   rc_frame_stats->pcnt_intra_low = stats->pcnt_intra_low;
86   rc_frame_stats->pcnt_intra_high = stats->pcnt_intra_high;
87   rc_frame_stats->intra_skip_pct = stats->intra_skip_pct;
88   rc_frame_stats->intra_smooth_pct = stats->intra_smooth_pct;
89   rc_frame_stats->inactive_zone_rows = stats->inactive_zone_rows;
90   rc_frame_stats->inactive_zone_cols = stats->inactive_zone_cols;
91   rc_frame_stats->MVr = stats->MVr;
92   rc_frame_stats->mvr_abs = stats->mvr_abs;
93   rc_frame_stats->MVc = stats->MVc;
94   rc_frame_stats->mvc_abs = stats->mvc_abs;
95   rc_frame_stats->MVrv = stats->MVrv;
96   rc_frame_stats->MVcv = stats->MVcv;
97   rc_frame_stats->mv_in_out_count = stats->mv_in_out_count;
98   rc_frame_stats->duration = stats->duration;
99   rc_frame_stats->count = stats->count;
100   rc_frame_stats->new_mv_count = stats->new_mv_count;
101 }
102 
vp9_extrc_send_firstpass_stats(EXT_RATECTRL * ext_ratectrl,const FIRST_PASS_INFO * first_pass_info)103 vpx_codec_err_t vp9_extrc_send_firstpass_stats(
104     EXT_RATECTRL *ext_ratectrl, const FIRST_PASS_INFO *first_pass_info) {
105   if (ext_ratectrl == NULL) {
106     return VPX_CODEC_INVALID_PARAM;
107   }
108   if (ext_ratectrl->ready) {
109     vpx_rc_status_t rc_status;
110     vpx_rc_firstpass_stats_t *rc_firstpass_stats =
111         &ext_ratectrl->rc_firstpass_stats;
112     int i;
113     assert(rc_firstpass_stats->num_frames == first_pass_info->num_frames);
114     for (i = 0; i < rc_firstpass_stats->num_frames; ++i) {
115       gen_rc_firstpass_stats(&first_pass_info->stats[i],
116                              &rc_firstpass_stats->frame_stats[i]);
117     }
118     rc_status = ext_ratectrl->funcs.send_firstpass_stats(ext_ratectrl->model,
119                                                          rc_firstpass_stats);
120     if (rc_status == VPX_RC_ERROR) {
121       return VPX_CODEC_ERROR;
122     }
123   }
124   return VPX_CODEC_OK;
125 }
126 
vp9_extrc_send_tpl_stats(EXT_RATECTRL * ext_ratectrl,const VpxTplGopStats * tpl_gop_stats)127 vpx_codec_err_t vp9_extrc_send_tpl_stats(EXT_RATECTRL *ext_ratectrl,
128                                          const VpxTplGopStats *tpl_gop_stats) {
129   if (ext_ratectrl == NULL) {
130     return VPX_CODEC_INVALID_PARAM;
131   }
132   if (ext_ratectrl->ready && ext_ratectrl->funcs.send_tpl_gop_stats != NULL) {
133     vpx_rc_status_t rc_status = ext_ratectrl->funcs.send_tpl_gop_stats(
134         ext_ratectrl->model, tpl_gop_stats);
135     if (rc_status == VPX_RC_ERROR) {
136       return VPX_CODEC_ERROR;
137     }
138   }
139   return VPX_CODEC_OK;
140 }
141 
extrc_get_frame_type(FRAME_UPDATE_TYPE update_type)142 static int extrc_get_frame_type(FRAME_UPDATE_TYPE update_type) {
143   // TODO(angiebird): Add unit test to make sure this function behaves like
144   // get_frame_type_from_update_type()
145   // TODO(angiebird): Merge this function with get_frame_type_from_update_type()
146   switch (update_type) {
147     case KF_UPDATE: return 0;       // kFrameTypeKey;
148     case ARF_UPDATE: return 2;      // kFrameTypeAltRef;
149     case GF_UPDATE: return 4;       // kFrameTypeGolden;
150     case OVERLAY_UPDATE: return 3;  // kFrameTypeOverlay;
151     case LF_UPDATE: return 1;       // kFrameTypeInter;
152     default:
153       fprintf(stderr, "Unsupported update_type %d\n", update_type);
154       abort();
155   }
156 }
157 
vp9_extrc_get_encodeframe_decision(EXT_RATECTRL * ext_ratectrl,int show_index,int coding_index,int gop_index,FRAME_UPDATE_TYPE update_type,int gop_size,int use_alt_ref,RefCntBuffer * ref_frame_bufs[MAX_INTER_REF_FRAMES],int ref_frame_flags,vpx_rc_encodeframe_decision_t * encode_frame_decision)158 vpx_codec_err_t vp9_extrc_get_encodeframe_decision(
159     EXT_RATECTRL *ext_ratectrl, int show_index, int coding_index, int gop_index,
160     FRAME_UPDATE_TYPE update_type, int gop_size, int use_alt_ref,
161     RefCntBuffer *ref_frame_bufs[MAX_INTER_REF_FRAMES], int ref_frame_flags,
162     vpx_rc_encodeframe_decision_t *encode_frame_decision) {
163   if (ext_ratectrl == NULL) {
164     return VPX_CODEC_INVALID_PARAM;
165   }
166   if (ext_ratectrl->ready && (ext_ratectrl->funcs.rc_type & VPX_RC_QP) != 0) {
167     vpx_rc_status_t rc_status;
168     vpx_rc_encodeframe_info_t encode_frame_info;
169     encode_frame_info.show_index = show_index;
170     encode_frame_info.coding_index = coding_index;
171     encode_frame_info.gop_index = gop_index;
172     encode_frame_info.frame_type = extrc_get_frame_type(update_type);
173     encode_frame_info.gop_size = gop_size;
174     encode_frame_info.use_alt_ref = use_alt_ref;
175 
176     vp9_get_ref_frame_info(update_type, ref_frame_flags, ref_frame_bufs,
177                            encode_frame_info.ref_frame_coding_indexes,
178                            encode_frame_info.ref_frame_valid_list);
179 
180     rc_status = ext_ratectrl->funcs.get_encodeframe_decision(
181         ext_ratectrl->model, &encode_frame_info, encode_frame_decision);
182     if (rc_status == VPX_RC_ERROR) {
183       return VPX_CODEC_ERROR;
184     }
185   }
186   return VPX_CODEC_OK;
187 }
188 
vp9_extrc_update_encodeframe_result(EXT_RATECTRL * ext_ratectrl,int64_t bit_count,const YV12_BUFFER_CONFIG * source_frame,const YV12_BUFFER_CONFIG * coded_frame,uint32_t bit_depth,uint32_t input_bit_depth,const int actual_encoding_qindex)189 vpx_codec_err_t vp9_extrc_update_encodeframe_result(
190     EXT_RATECTRL *ext_ratectrl, int64_t bit_count,
191     const YV12_BUFFER_CONFIG *source_frame,
192     const YV12_BUFFER_CONFIG *coded_frame, uint32_t bit_depth,
193     uint32_t input_bit_depth, const int actual_encoding_qindex) {
194   if (ext_ratectrl == NULL) {
195     return VPX_CODEC_INVALID_PARAM;
196   }
197   if (ext_ratectrl->ready) {
198     PSNR_STATS psnr;
199     vpx_rc_status_t rc_status;
200     vpx_rc_encodeframe_result_t encode_frame_result;
201     encode_frame_result.bit_count = bit_count;
202     encode_frame_result.pixel_count =
203         source_frame->y_crop_width * source_frame->y_crop_height +
204         2 * source_frame->uv_crop_width * source_frame->uv_crop_height;
205     encode_frame_result.actual_encoding_qindex = actual_encoding_qindex;
206 #if CONFIG_VP9_HIGHBITDEPTH
207     vpx_calc_highbd_psnr(source_frame, coded_frame, &psnr, bit_depth,
208                          input_bit_depth);
209 #else
210     (void)bit_depth;
211     (void)input_bit_depth;
212     vpx_calc_psnr(source_frame, coded_frame, &psnr);
213 #endif
214     encode_frame_result.sse = psnr.sse[0];
215     rc_status = ext_ratectrl->funcs.update_encodeframe_result(
216         ext_ratectrl->model, &encode_frame_result);
217     if (rc_status == VPX_RC_ERROR) {
218       return VPX_CODEC_ERROR;
219     }
220   }
221   return VPX_CODEC_OK;
222 }
223 
vp9_extrc_get_gop_decision(EXT_RATECTRL * ext_ratectrl,const vpx_rc_gop_info_t * const gop_info,vpx_rc_gop_decision_t * gop_decision)224 vpx_codec_err_t vp9_extrc_get_gop_decision(
225     EXT_RATECTRL *ext_ratectrl, const vpx_rc_gop_info_t *const gop_info,
226     vpx_rc_gop_decision_t *gop_decision) {
227   vpx_rc_status_t rc_status;
228   if (ext_ratectrl == NULL || !ext_ratectrl->ready ||
229       (ext_ratectrl->funcs.rc_type & VPX_RC_GOP) == 0) {
230     return VPX_CODEC_INVALID_PARAM;
231   }
232   rc_status = ext_ratectrl->funcs.get_gop_decision(ext_ratectrl->model,
233                                                    gop_info, gop_decision);
234   if (gop_decision->use_alt_ref) {
235     const int arf_constraint =
236         gop_decision->gop_coding_frames >= gop_info->min_gf_interval &&
237         gop_decision->gop_coding_frames < gop_info->lag_in_frames;
238     if (!arf_constraint || !gop_info->allow_alt_ref) return VPX_CODEC_ERROR;
239   }
240   // TODO(chengchen): Take min and max gf interval from the model
241   // and overwrite libvpx's decision so that we can get rid
242   // of one of the checks here.
243   if (gop_decision->gop_coding_frames > gop_info->frames_to_key ||
244       gop_decision->gop_coding_frames - gop_decision->use_alt_ref >
245           gop_info->max_gf_interval) {
246     return VPX_CODEC_ERROR;
247   }
248   if (rc_status == VPX_RC_ERROR) {
249     return VPX_CODEC_ERROR;
250   }
251   return VPX_CODEC_OK;
252 }
253 
vp9_extrc_get_frame_rdmult(EXT_RATECTRL * ext_ratectrl,int show_index,int coding_index,int gop_index,FRAME_UPDATE_TYPE update_type,int gop_size,int use_alt_ref,RefCntBuffer * ref_frame_bufs[MAX_INTER_REF_FRAMES],int ref_frame_flags,int * rdmult)254 vpx_codec_err_t vp9_extrc_get_frame_rdmult(
255     EXT_RATECTRL *ext_ratectrl, int show_index, int coding_index, int gop_index,
256     FRAME_UPDATE_TYPE update_type, int gop_size, int use_alt_ref,
257     RefCntBuffer *ref_frame_bufs[MAX_INTER_REF_FRAMES], int ref_frame_flags,
258     int *rdmult) {
259   vpx_rc_status_t rc_status;
260   vpx_rc_encodeframe_info_t encode_frame_info;
261   if (ext_ratectrl == NULL || !ext_ratectrl->ready ||
262       (ext_ratectrl->funcs.rc_type & VPX_RC_RDMULT) == 0) {
263     return VPX_CODEC_INVALID_PARAM;
264   }
265   encode_frame_info.show_index = show_index;
266   encode_frame_info.coding_index = coding_index;
267   encode_frame_info.gop_index = gop_index;
268   encode_frame_info.frame_type = extrc_get_frame_type(update_type);
269   encode_frame_info.gop_size = gop_size;
270   encode_frame_info.use_alt_ref = use_alt_ref;
271 
272   vp9_get_ref_frame_info(update_type, ref_frame_flags, ref_frame_bufs,
273                          encode_frame_info.ref_frame_coding_indexes,
274                          encode_frame_info.ref_frame_valid_list);
275   rc_status = ext_ratectrl->funcs.get_frame_rdmult(ext_ratectrl->model,
276                                                    &encode_frame_info, rdmult);
277   if (rc_status == VPX_RC_ERROR) {
278     return VPX_CODEC_ERROR;
279   }
280   return VPX_CODEC_OK;
281 }
282