]> granicus.if.org Git - libvpx/blob - vp9/simple_encode.cc
Merge "vp9-rtc: Fix condition in regulate_q for cyclic_refresh"
[libvpx] / vp9 / simple_encode.cc
1 /*
2  *  Copyright (c) 2019 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 <vector>
12 #include "vp9/common/vp9_entropymode.h"
13 #include "vp9/common/vp9_enums.h"
14 #include "vp9/common/vp9_onyxc_int.h"
15 #include "vp9/vp9_iface_common.h"
16 #include "vp9/encoder/vp9_encoder.h"
17 #include "vp9/encoder/vp9_firstpass.h"
18 #include "vp9/simple_encode.h"
19 #include "vp9/vp9_cx_iface.h"
20
21 namespace vp9 {
22
23 // TODO(angiebird): Merge this function with vpx_img_plane_width()
24 static int img_plane_width(const vpx_image_t *img, int plane) {
25   if (plane > 0 && img->x_chroma_shift > 0)
26     return (img->d_w + 1) >> img->x_chroma_shift;
27   else
28     return img->d_w;
29 }
30
31 // TODO(angiebird): Merge this function with vpx_img_plane_height()
32 static int img_plane_height(const vpx_image_t *img, int plane) {
33   if (plane > 0 && img->y_chroma_shift > 0)
34     return (img->d_h + 1) >> img->y_chroma_shift;
35   else
36     return img->d_h;
37 }
38
39 // TODO(angiebird): Merge this function with vpx_img_read()
40 static int img_read(vpx_image_t *img, FILE *file) {
41   int plane;
42
43   for (plane = 0; plane < 3; ++plane) {
44     unsigned char *buf = img->planes[plane];
45     const int stride = img->stride[plane];
46     const int w = img_plane_width(img, plane) *
47                   ((img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1);
48     const int h = img_plane_height(img, plane);
49     int y;
50
51     for (y = 0; y < h; ++y) {
52       if (fread(buf, 1, w, file) != (size_t)w) return 0;
53       buf += stride;
54     }
55   }
56
57   return 1;
58 }
59
60 class SimpleEncode::EncodeImpl {
61  public:
62   VP9_COMP *cpi;
63   vpx_img_fmt_t img_fmt;
64   vpx_image_t tmp_img;
65   std::vector<FIRSTPASS_STATS> first_pass_stats;
66 };
67
68 static VP9_COMP *init_encoder(const VP9EncoderConfig *oxcf,
69                               vpx_img_fmt_t img_fmt) {
70   VP9_COMP *cpi;
71   BufferPool *buffer_pool = (BufferPool *)vpx_calloc(1, sizeof(*buffer_pool));
72   vp9_initialize_enc();
73   cpi = vp9_create_compressor(oxcf, buffer_pool);
74   vp9_update_compressor_with_img_fmt(cpi, img_fmt);
75   return cpi;
76 }
77
78 static void free_encoder(VP9_COMP *cpi) {
79   BufferPool *buffer_pool = cpi->common.buffer_pool;
80   vp9_remove_compressor(cpi);
81   // buffer_pool needs to be free after cpi because buffer_pool contains
82   // allocated buffers that will be free in vp9_remove_compressor()
83   vpx_free(buffer_pool);
84 }
85
86 static INLINE vpx_rational_t make_vpx_rational(int num, int den) {
87   vpx_rational_t v;
88   v.num = num;
89   v.den = den;
90   return v;
91 }
92
93 static INLINE FrameType
94 get_frame_type_from_update_type(FRAME_UPDATE_TYPE update_type) {
95   // TODO(angiebird): Figure out if we need frame type other than key frame,
96   // alternate reference and inter frame
97   switch (update_type) {
98     case KF_UPDATE: return kKeyFrame; break;
99     case ARF_UPDATE: return kAlternateReference; break;
100     default: return kInterFrame; break;
101   }
102 }
103
104 static void update_frame_counts(const FRAME_COUNTS *input_counts,
105                                 FrameCounts *output_counts) {
106   // Init array sizes.
107   output_counts->y_mode.resize(BLOCK_SIZE_GROUPS);
108   for (int i = 0; i < BLOCK_SIZE_GROUPS; ++i) {
109     output_counts->y_mode[i].resize(INTRA_MODES);
110   }
111
112   output_counts->uv_mode.resize(INTRA_MODES);
113   for (int i = 0; i < INTRA_MODES; ++i) {
114     output_counts->uv_mode[i].resize(INTRA_MODES);
115   }
116
117   output_counts->partition.resize(PARTITION_CONTEXTS);
118   for (int i = 0; i < PARTITION_CONTEXTS; ++i) {
119     output_counts->partition[i].resize(PARTITION_TYPES);
120   }
121
122   output_counts->coef.resize(TX_SIZES);
123   output_counts->eob_branch.resize(TX_SIZES);
124   for (int i = 0; i < TX_SIZES; ++i) {
125     output_counts->coef[i].resize(PLANE_TYPES);
126     output_counts->eob_branch[i].resize(PLANE_TYPES);
127     for (int j = 0; j < PLANE_TYPES; ++j) {
128       output_counts->coef[i][j].resize(REF_TYPES);
129       output_counts->eob_branch[i][j].resize(REF_TYPES);
130       for (int k = 0; k < REF_TYPES; ++k) {
131         output_counts->coef[i][j][k].resize(COEF_BANDS);
132         output_counts->eob_branch[i][j][k].resize(COEF_BANDS);
133         for (int l = 0; l < COEF_BANDS; ++l) {
134           output_counts->coef[i][j][k][l].resize(COEFF_CONTEXTS);
135           output_counts->eob_branch[i][j][k][l].resize(COEFF_CONTEXTS);
136           for (int m = 0; m < COEFF_CONTEXTS; ++m) {
137             output_counts->coef[i][j][k][l][m].resize(UNCONSTRAINED_NODES + 1);
138           }
139         }
140       }
141     }
142   }
143
144   output_counts->switchable_interp.resize(SWITCHABLE_FILTER_CONTEXTS);
145   for (int i = 0; i < SWITCHABLE_FILTER_CONTEXTS; ++i) {
146     output_counts->switchable_interp[i].resize(SWITCHABLE_FILTERS);
147   }
148
149   output_counts->inter_mode.resize(INTER_MODE_CONTEXTS);
150   for (int i = 0; i < INTER_MODE_CONTEXTS; ++i) {
151     output_counts->inter_mode[i].resize(INTER_MODES);
152   }
153
154   output_counts->intra_inter.resize(INTRA_INTER_CONTEXTS);
155   for (int i = 0; i < INTRA_INTER_CONTEXTS; ++i) {
156     output_counts->intra_inter[i].resize(2);
157   }
158
159   output_counts->comp_inter.resize(COMP_INTER_CONTEXTS);
160   for (int i = 0; i < COMP_INTER_CONTEXTS; ++i) {
161     output_counts->comp_inter[i].resize(2);
162   }
163
164   output_counts->single_ref.resize(REF_CONTEXTS);
165   for (int i = 0; i < REF_CONTEXTS; ++i) {
166     output_counts->single_ref[i].resize(2);
167     for (int j = 0; j < 2; ++j) {
168       output_counts->single_ref[i][j].resize(2);
169     }
170   }
171
172   output_counts->comp_ref.resize(REF_CONTEXTS);
173   for (int i = 0; i < REF_CONTEXTS; ++i) {
174     output_counts->comp_ref[i].resize(2);
175   }
176
177   output_counts->skip.resize(SKIP_CONTEXTS);
178   for (int i = 0; i < SKIP_CONTEXTS; ++i) {
179     output_counts->skip[i].resize(2);
180   }
181
182   output_counts->tx.p32x32.resize(TX_SIZE_CONTEXTS);
183   output_counts->tx.p16x16.resize(TX_SIZE_CONTEXTS);
184   output_counts->tx.p8x8.resize(TX_SIZE_CONTEXTS);
185   for (int i = 0; i < TX_SIZE_CONTEXTS; i++) {
186     output_counts->tx.p32x32[i].resize(TX_SIZES);
187     output_counts->tx.p16x16[i].resize(TX_SIZES - 1);
188     output_counts->tx.p8x8[i].resize(TX_SIZES - 2);
189   }
190   output_counts->tx.tx_totals.resize(TX_SIZES);
191
192   output_counts->mv.joints.resize(MV_JOINTS);
193   output_counts->mv.comps.resize(2);
194   for (int i = 0; i < 2; ++i) {
195     output_counts->mv.comps[i].sign.resize(2);
196     output_counts->mv.comps[i].classes.resize(MV_CLASSES);
197     output_counts->mv.comps[i].class0.resize(CLASS0_SIZE);
198     output_counts->mv.comps[i].bits.resize(MV_OFFSET_BITS);
199     for (int j = 0; j < MV_OFFSET_BITS; ++j) {
200       output_counts->mv.comps[i].bits[j].resize(2);
201     }
202     output_counts->mv.comps[i].class0_fp.resize(CLASS0_SIZE);
203     for (int j = 0; j < CLASS0_SIZE; ++j) {
204       output_counts->mv.comps[i].class0_fp[j].resize(MV_FP_SIZE);
205     }
206     output_counts->mv.comps[i].fp.resize(MV_FP_SIZE);
207     output_counts->mv.comps[i].class0_hp.resize(2);
208     output_counts->mv.comps[i].hp.resize(2);
209   }
210
211   // Populate counts.
212   for (int i = 0; i < BLOCK_SIZE_GROUPS; ++i) {
213     for (int j = 0; j < INTRA_MODES; ++j) {
214       output_counts->y_mode[i][j] = input_counts->y_mode[i][j];
215     }
216   }
217   for (int i = 0; i < INTRA_MODES; ++i) {
218     for (int j = 0; j < INTRA_MODES; ++j) {
219       output_counts->uv_mode[i][j] = input_counts->uv_mode[i][j];
220     }
221   }
222   for (int i = 0; i < PARTITION_CONTEXTS; ++i) {
223     for (int j = 0; j < PARTITION_TYPES; ++j) {
224       output_counts->partition[i][j] = input_counts->partition[i][j];
225     }
226   }
227   for (int i = 0; i < TX_SIZES; ++i) {
228     for (int j = 0; j < PLANE_TYPES; ++j) {
229       for (int k = 0; k < REF_TYPES; ++k) {
230         for (int l = 0; l < COEF_BANDS; ++l) {
231           for (int m = 0; m < COEFF_CONTEXTS; ++m) {
232             output_counts->eob_branch[i][j][k][l][m] =
233                 input_counts->eob_branch[i][j][k][l][m];
234             for (int n = 0; n < UNCONSTRAINED_NODES + 1; n++) {
235               output_counts->coef[i][j][k][l][m][n] =
236                   input_counts->coef[i][j][k][l][m][n];
237             }
238           }
239         }
240       }
241     }
242   }
243   for (int i = 0; i < SWITCHABLE_FILTER_CONTEXTS; ++i) {
244     for (int j = 0; j < SWITCHABLE_FILTERS; ++j) {
245       output_counts->switchable_interp[i][j] =
246           input_counts->switchable_interp[i][j];
247     }
248   }
249   for (int i = 0; i < INTER_MODE_CONTEXTS; ++i) {
250     for (int j = 0; j < INTER_MODES; ++j) {
251       output_counts->inter_mode[i][j] = input_counts->inter_mode[i][j];
252     }
253   }
254   for (int i = 0; i < INTRA_INTER_CONTEXTS; ++i) {
255     for (int j = 0; j < 2; ++j) {
256       output_counts->intra_inter[i][j] = input_counts->intra_inter[i][j];
257     }
258   }
259   for (int i = 0; i < COMP_INTER_CONTEXTS; ++i) {
260     for (int j = 0; j < 2; ++j) {
261       output_counts->comp_inter[i][j] = input_counts->comp_inter[i][j];
262     }
263   }
264   for (int i = 0; i < REF_CONTEXTS; ++i) {
265     for (int j = 0; j < 2; ++j) {
266       for (int k = 0; k < 2; ++k) {
267         output_counts->single_ref[i][j][k] = input_counts->single_ref[i][j][k];
268       }
269     }
270   }
271   for (int i = 0; i < REF_CONTEXTS; ++i) {
272     for (int j = 0; j < 2; ++j) {
273       output_counts->comp_ref[i][j] = input_counts->comp_ref[i][j];
274     }
275   }
276   for (int i = 0; i < SKIP_CONTEXTS; ++i) {
277     for (int j = 0; j < 2; ++j) {
278       output_counts->skip[i][j] = input_counts->skip[i][j];
279     }
280   }
281   for (int i = 0; i < TX_SIZE_CONTEXTS; i++) {
282     for (int j = 0; j < TX_SIZES; j++) {
283       output_counts->tx.p32x32[i][j] = input_counts->tx.p32x32[i][j];
284     }
285     for (int j = 0; j < TX_SIZES - 1; j++) {
286       output_counts->tx.p16x16[i][j] = input_counts->tx.p16x16[i][j];
287     }
288     for (int j = 0; j < TX_SIZES - 2; j++) {
289       output_counts->tx.p8x8[i][j] = input_counts->tx.p8x8[i][j];
290     }
291   }
292   for (int i = 0; i < TX_SIZES; i++) {
293     output_counts->tx.tx_totals[i] = input_counts->tx.tx_totals[i];
294   }
295   for (int i = 0; i < MV_JOINTS; i++) {
296     output_counts->mv.joints[i] = input_counts->mv.joints[i];
297   }
298   for (int k = 0; k < 2; k++) {
299     const nmv_component_counts *const comps_t = &input_counts->mv.comps[k];
300     for (int i = 0; i < 2; i++) {
301       output_counts->mv.comps[k].sign[i] = comps_t->sign[i];
302       output_counts->mv.comps[k].class0_hp[i] = comps_t->class0_hp[i];
303       output_counts->mv.comps[k].hp[i] = comps_t->hp[i];
304     }
305     for (int i = 0; i < MV_CLASSES; i++) {
306       output_counts->mv.comps[k].classes[i] = comps_t->classes[i];
307     }
308     for (int i = 0; i < CLASS0_SIZE; i++) {
309       output_counts->mv.comps[k].class0[i] = comps_t->class0[i];
310       for (int j = 0; j < MV_FP_SIZE; j++) {
311         output_counts->mv.comps[k].class0_fp[i][j] = comps_t->class0_fp[i][j];
312       }
313     }
314     for (int i = 0; i < MV_OFFSET_BITS; i++) {
315       for (int j = 0; j < 2; j++) {
316         output_counts->mv.comps[k].bits[i][j] = comps_t->bits[i][j];
317       }
318     }
319     for (int i = 0; i < MV_FP_SIZE; i++) {
320       output_counts->mv.comps[k].fp[i] = comps_t->fp[i];
321     }
322   }
323 }
324
325 static void update_encode_frame_result(
326     EncodeFrameResult *encode_frame_result,
327     const ENCODE_FRAME_RESULT *encode_frame_info) {
328   encode_frame_result->coding_data_bit_size =
329       encode_frame_result->coding_data_byte_size * 8;
330   encode_frame_result->show_idx = encode_frame_info->show_idx;
331   encode_frame_result->frame_type =
332       get_frame_type_from_update_type(encode_frame_info->update_type);
333   encode_frame_result->psnr = encode_frame_info->psnr;
334   encode_frame_result->sse = encode_frame_info->sse;
335   encode_frame_result->quantize_index = encode_frame_info->quantize_index;
336   update_frame_counts(&encode_frame_info->frame_counts,
337                       &encode_frame_result->frame_counts);
338 }
339
340 static void IncreaseGroupOfPictureIndex(GroupOfPicture *group_of_picture) {
341   ++group_of_picture->next_encode_frame_index;
342 }
343
344 static int IsGroupOfPictureFinished(const GroupOfPicture &group_of_picture) {
345   return static_cast<size_t>(group_of_picture.next_encode_frame_index) ==
346          group_of_picture.encode_frame_list.size();
347 }
348
349 static void SetGroupOfPicture(int first_is_key_frame, int use_alt_ref,
350                               int coding_frame_count, int first_show_idx,
351                               GroupOfPicture *group_of_picture) {
352   // Clean up the state of previous group of picture.
353   group_of_picture->encode_frame_list.clear();
354   group_of_picture->next_encode_frame_index = 0;
355   group_of_picture->show_frame_count = coding_frame_count - use_alt_ref;
356   group_of_picture->start_show_index = first_show_idx;
357   {
358     // First frame in the group of pictures. It's either key frame or show inter
359     // frame.
360     EncodeFrameInfo encode_frame_info;
361     if (first_is_key_frame) {
362       encode_frame_info.frame_type = kKeyFrame;
363     } else {
364       encode_frame_info.frame_type = kInterFrame;
365     }
366     encode_frame_info.show_idx = first_show_idx;
367     group_of_picture->encode_frame_list.push_back(encode_frame_info);
368   }
369
370   const int show_frame_count = coding_frame_count - use_alt_ref;
371   if (use_alt_ref) {
372     // If there is alternate reference, it is always coded at the second place.
373     // Its show index (or timestamp) is at the last of this group
374     EncodeFrameInfo encode_frame_info;
375     encode_frame_info.frame_type = kAlternateReference;
376     encode_frame_info.show_idx = first_show_idx + show_frame_count;
377     group_of_picture->encode_frame_list.push_back(encode_frame_info);
378   }
379
380   // Encode the rest show inter frames.
381   for (int i = 1; i < show_frame_count; ++i) {
382     EncodeFrameInfo encode_frame_info;
383     encode_frame_info.frame_type = kInterFrame;
384     encode_frame_info.show_idx = first_show_idx + i;
385     group_of_picture->encode_frame_list.push_back(encode_frame_info);
386   }
387 }
388
389 static void UpdateGroupOfPicture(const VP9_COMP *cpi,
390                                  GroupOfPicture *group_of_picture) {
391   int first_is_key_frame;
392   int use_alt_ref;
393   int coding_frame_count;
394   int first_show_idx;
395   vp9_get_next_group_of_picture(cpi, &first_is_key_frame, &use_alt_ref,
396                                 &coding_frame_count, &first_show_idx);
397   SetGroupOfPicture(first_is_key_frame, use_alt_ref, coding_frame_count,
398                     first_show_idx, group_of_picture);
399 }
400
401 SimpleEncode::SimpleEncode(int frame_width, int frame_height,
402                            int frame_rate_num, int frame_rate_den,
403                            int target_bitrate, int num_frames,
404                            const char *infile_path) {
405   impl_ptr_ = std::unique_ptr<EncodeImpl>(new EncodeImpl());
406   frame_width_ = frame_width;
407   frame_height_ = frame_height;
408   frame_rate_num_ = frame_rate_num;
409   frame_rate_den_ = frame_rate_den;
410   target_bitrate_ = target_bitrate;
411   num_frames_ = num_frames;
412   // TODO(angirbid): Should we keep a file pointer here or keep the file_path?
413   file_ = fopen(infile_path, "r");
414   impl_ptr_->cpi = NULL;
415   impl_ptr_->img_fmt = VPX_IMG_FMT_I420;
416 }
417
418 void SimpleEncode::ComputeFirstPassStats() {
419   vpx_rational_t frame_rate =
420       make_vpx_rational(frame_rate_num_, frame_rate_den_);
421   const VP9EncoderConfig oxcf =
422       vp9_get_encoder_config(frame_width_, frame_height_, frame_rate,
423                              target_bitrate_, VPX_RC_FIRST_PASS);
424   VP9_COMP *cpi = init_encoder(&oxcf, impl_ptr_->img_fmt);
425   struct lookahead_ctx *lookahead = cpi->lookahead;
426   int i;
427   int use_highbitdepth = 0;
428 #if CONFIG_VP9_HIGHBITDEPTH
429   use_highbitdepth = cpi->common.use_highbitdepth;
430 #endif
431   vpx_image_t img;
432   vpx_img_alloc(&img, impl_ptr_->img_fmt, frame_width_, frame_height_, 1);
433   rewind(file_);
434   impl_ptr_->first_pass_stats.clear();
435   for (i = 0; i < num_frames_; ++i) {
436     assert(!vp9_lookahead_full(lookahead));
437     if (img_read(&img, file_)) {
438       int next_show_idx = vp9_lookahead_next_show_idx(lookahead);
439       int64_t ts_start =
440           timebase_units_to_ticks(&oxcf.g_timebase_in_ts, next_show_idx);
441       int64_t ts_end =
442           timebase_units_to_ticks(&oxcf.g_timebase_in_ts, next_show_idx + 1);
443       YV12_BUFFER_CONFIG sd;
444       image2yuvconfig(&img, &sd);
445       vp9_lookahead_push(lookahead, &sd, ts_start, ts_end, use_highbitdepth, 0);
446       {
447         int64_t time_stamp;
448         int64_t time_end;
449         int flush = 1;  // Makes vp9_get_compressed_data process a frame
450         size_t size;
451         unsigned int frame_flags = 0;
452         ENCODE_FRAME_RESULT encode_frame_info;
453         // TODO(angiebird): Call vp9_first_pass directly
454         vp9_get_compressed_data(cpi, &frame_flags, &size, NULL, &time_stamp,
455                                 &time_end, flush, &encode_frame_info);
456         // vp9_get_compressed_data only generates first pass stats not
457         // compresses data
458         assert(size == 0);
459       }
460       impl_ptr_->first_pass_stats.push_back(vp9_get_frame_stats(&cpi->twopass));
461     }
462   }
463   vp9_end_first_pass(cpi);
464   // TODO(angiebird): Store the total_stats apart form first_pass_stats
465   impl_ptr_->first_pass_stats.push_back(vp9_get_total_stats(&cpi->twopass));
466   free_encoder(cpi);
467   rewind(file_);
468   vpx_img_free(&img);
469 }
470
471 std::vector<std::vector<double>> SimpleEncode::ObserveFirstPassStats() {
472   std::vector<std::vector<double>> output_stats;
473   // TODO(angiebird): This function make several assumptions of
474   // FIRSTPASS_STATS. 1) All elements in FIRSTPASS_STATS are double except the
475   // last one. 2) The last entry of first_pass_stats is the total_stats.
476   // Change the code structure, so that we don't have to make these assumptions
477
478   // Note the last entry of first_pass_stats is the total_stats, we don't need
479   // it.
480   for (size_t i = 0; i < impl_ptr_->first_pass_stats.size() - 1; ++i) {
481     double *buf_start =
482         reinterpret_cast<double *>(&impl_ptr_->first_pass_stats[i]);
483     // We use - 1 here because the last member in FIRSTPASS_STATS is not double
484     double *buf_end =
485         buf_start + sizeof(impl_ptr_->first_pass_stats[i]) / sizeof(*buf_end) -
486         1;
487     std::vector<double> this_stats(buf_start, buf_end);
488     output_stats.push_back(this_stats);
489   }
490   return output_stats;
491 }
492
493 void SimpleEncode::StartEncode() {
494   assert(impl_ptr_->first_pass_stats.size() > 0);
495   vpx_rational_t frame_rate =
496       make_vpx_rational(frame_rate_num_, frame_rate_den_);
497   VP9EncoderConfig oxcf =
498       vp9_get_encoder_config(frame_width_, frame_height_, frame_rate,
499                              target_bitrate_, VPX_RC_LAST_PASS);
500   vpx_fixed_buf_t stats;
501   stats.buf = impl_ptr_->first_pass_stats.data();
502   stats.sz = sizeof(impl_ptr_->first_pass_stats[0]) *
503              impl_ptr_->first_pass_stats.size();
504
505   vp9_set_first_pass_stats(&oxcf, &stats);
506   assert(impl_ptr_->cpi == NULL);
507   impl_ptr_->cpi = init_encoder(&oxcf, impl_ptr_->img_fmt);
508   vpx_img_alloc(&impl_ptr_->tmp_img, impl_ptr_->img_fmt, frame_width_,
509                 frame_height_, 1);
510   UpdateGroupOfPicture(impl_ptr_->cpi, &group_of_picture_);
511   rewind(file_);
512 }
513
514 void SimpleEncode::EndEncode() {
515   free_encoder(impl_ptr_->cpi);
516   impl_ptr_->cpi = nullptr;
517   vpx_img_free(&impl_ptr_->tmp_img);
518   rewind(file_);
519 }
520
521 int SimpleEncode::GetKeyFrameGroupSize(int key_frame_index) const {
522   const VP9_COMP *cpi = impl_ptr_->cpi;
523   return vp9_get_frames_to_next_key(&cpi->oxcf, &cpi->frame_info,
524                                     &cpi->twopass.first_pass_info,
525                                     key_frame_index, cpi->rc.min_gf_interval);
526 }
527
528 GroupOfPicture SimpleEncode::ObserveGroupOfPicture() const {
529   return group_of_picture_;
530 }
531
532 EncodeFrameInfo SimpleEncode::GetNextEncodeFrameInfo() const {
533   return group_of_picture_
534       .encode_frame_list[group_of_picture_.next_encode_frame_index];
535 }
536
537 void SimpleEncode::EncodeFrame(EncodeFrameResult *encode_frame_result) {
538   VP9_COMP *cpi = impl_ptr_->cpi;
539   struct lookahead_ctx *lookahead = cpi->lookahead;
540   int use_highbitdepth = 0;
541 #if CONFIG_VP9_HIGHBITDEPTH
542   use_highbitdepth = cpi->common.use_highbitdepth;
543 #endif
544   // The lookahead's size is set to oxcf->lag_in_frames.
545   // We want to fill lookahead to it's max capacity if possible so that the
546   // encoder can construct alt ref frame in time.
547   // In the other words, we hope vp9_get_compressed_data to encode a frame
548   // every time in the function
549   while (!vp9_lookahead_full(lookahead)) {
550     // TODO(angiebird): Check whether we can move this file read logics to
551     // lookahead
552     if (img_read(&impl_ptr_->tmp_img, file_)) {
553       int next_show_idx = vp9_lookahead_next_show_idx(lookahead);
554       int64_t ts_start =
555           timebase_units_to_ticks(&cpi->oxcf.g_timebase_in_ts, next_show_idx);
556       int64_t ts_end = timebase_units_to_ticks(&cpi->oxcf.g_timebase_in_ts,
557                                                next_show_idx + 1);
558       YV12_BUFFER_CONFIG sd;
559       image2yuvconfig(&impl_ptr_->tmp_img, &sd);
560       vp9_lookahead_push(lookahead, &sd, ts_start, ts_end, use_highbitdepth, 0);
561     } else {
562       break;
563     }
564   }
565   assert(encode_frame_result->coding_data.get() == nullptr);
566   const size_t max_coding_data_byte_size = frame_width_ * frame_height_ * 3;
567   encode_frame_result->coding_data = std::move(
568       std::unique_ptr<uint8_t[]>(new uint8_t[max_coding_data_byte_size]));
569   int64_t time_stamp;
570   int64_t time_end;
571   int flush = 1;  // Make vp9_get_compressed_data encode a frame
572   unsigned int frame_flags = 0;
573   ENCODE_FRAME_RESULT encode_frame_info;
574   vp9_get_compressed_data(cpi, &frame_flags,
575                           &encode_frame_result->coding_data_byte_size,
576                           encode_frame_result->coding_data.get(), &time_stamp,
577                           &time_end, flush, &encode_frame_info);
578   // vp9_get_compressed_data is expected to encode a frame every time, so the
579   // data size should be greater than zero.
580   assert(encode_frame_result->coding_data_byte_size > 0);
581   assert(encode_frame_result->coding_data_byte_size <
582          max_coding_data_byte_size);
583
584   update_encode_frame_result(encode_frame_result, &encode_frame_info);
585   IncreaseGroupOfPictureIndex(&group_of_picture_);
586   if (IsGroupOfPictureFinished(group_of_picture_)) {
587     UpdateGroupOfPicture(impl_ptr_->cpi, &group_of_picture_);
588   }
589 }
590
591 void SimpleEncode::EncodeFrameWithQuantizeIndex(
592     EncodeFrameResult *encode_frame_result, int quantize_index) {
593   encode_command_set_external_quantize_index(&impl_ptr_->cpi->encode_command,
594                                              quantize_index);
595   EncodeFrame(encode_frame_result);
596   encode_command_reset_external_quantize_index(&impl_ptr_->cpi->encode_command);
597 }
598
599 int SimpleEncode::GetCodingFrameNum() const {
600   assert(impl_ptr_->first_pass_stats.size() - 1 > 0);
601   // These are the default settings for now.
602   const int multi_layer_arf = 0;
603   const int allow_alt_ref = 1;
604   vpx_rational_t frame_rate =
605       make_vpx_rational(frame_rate_num_, frame_rate_den_);
606   const VP9EncoderConfig oxcf =
607       vp9_get_encoder_config(frame_width_, frame_height_, frame_rate,
608                              target_bitrate_, VPX_RC_LAST_PASS);
609   FRAME_INFO frame_info = vp9_get_frame_info(&oxcf);
610   FIRST_PASS_INFO first_pass_info;
611   fps_init_first_pass_info(&first_pass_info, impl_ptr_->first_pass_stats.data(),
612                            num_frames_);
613   return vp9_get_coding_frame_num(&oxcf, &frame_info, &first_pass_info,
614                                   multi_layer_arf, allow_alt_ref);
615 }
616
617 uint64_t SimpleEncode::GetFramePixelCount() const {
618   assert(frame_width_ % 2 == 0);
619   assert(frame_height_ % 2 == 0);
620   switch (impl_ptr_->img_fmt) {
621     case VPX_IMG_FMT_I420: return frame_width_ * frame_height_ * 3 / 2;
622     case VPX_IMG_FMT_I422: return frame_width_ * frame_height_ * 2;
623     case VPX_IMG_FMT_I444: return frame_width_ * frame_height_ * 3;
624     case VPX_IMG_FMT_I440: return frame_width_ * frame_height_ * 2;
625     case VPX_IMG_FMT_I42016: return frame_width_ * frame_height_ * 3 / 2;
626     case VPX_IMG_FMT_I42216: return frame_width_ * frame_height_ * 2;
627     case VPX_IMG_FMT_I44416: return frame_width_ * frame_height_ * 3;
628     case VPX_IMG_FMT_I44016: return frame_width_ * frame_height_ * 2;
629     default: return 0;
630   }
631 }
632
633 SimpleEncode::~SimpleEncode() {
634   if (this->file_ != NULL) {
635     fclose(this->file_);
636   }
637 }
638
639 }  // namespace vp9