blob: a25522fbc5d4260ecf3560a8c4ca16de87087e35 [file] [log] [blame]
Bohan Li15b3c6d2021-07-27 17:27:20 -07001/*
2 * Copyright (c) 2021, Alliance for Open Media. All rights reserved
3 *
4 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10 */
James Zern59fc5492022-09-15 16:23:00 -070011#include "av1/encoder/thirdpass.h"
Bohan Li15b3c6d2021-07-27 17:27:20 -070012
James Zern59fc5492022-09-15 16:23:00 -070013#if CONFIG_THREE_PASS && CONFIG_AV1_DECODER
Bohan Li15b3c6d2021-07-27 17:27:20 -070014#include "aom/aom_codec.h"
15#include "aom/aomdx.h"
Bohan Li3c5b1242021-12-08 11:30:41 -080016#include "aom_dsp/psnr.h"
Bohan Li15b3c6d2021-07-27 17:27:20 -070017#include "aom_mem/aom_mem.h"
18#include "av1/av1_iface_common.h"
Bohan Liedec7cd2021-08-26 09:17:47 -070019#include "av1/encoder/encoder.h"
Bohan Li15b3c6d2021-07-27 17:27:20 -070020#include "av1/encoder/firstpass.h"
Bohan Li15b3c6d2021-07-27 17:27:20 -070021#include "av1/common/blockd.h"
Bohan Lida224f22021-09-01 14:31:55 -070022#include "common/ivfdec.h"
Bohan Lida224f22021-09-01 14:31:55 -070023
Bohan Li15b3c6d2021-07-27 17:27:20 -070024static void setup_two_pass_stream_input(
25 struct AvxInputContext **input_ctx_ptr, const char *input_file_name,
26 struct aom_internal_error_info *err_info) {
27 FILE *infile;
28 infile = fopen(input_file_name, "rb");
29 if (!infile) {
30 aom_internal_error(err_info, AOM_CODEC_INVALID_PARAM,
31 "Failed to open input file '%s'.", input_file_name);
32 }
33 struct AvxInputContext *aom_input_ctx = aom_malloc(sizeof(*aom_input_ctx));
34 if (!aom_input_ctx) {
35 fclose(infile);
36 aom_internal_error(err_info, AOM_CODEC_MEM_ERROR,
37 "Failed to allocate memory for third-pass context.");
38 }
39 memset(aom_input_ctx, 0, sizeof(*aom_input_ctx));
40 aom_input_ctx->filename = input_file_name;
41 aom_input_ctx->file = infile;
42
43 if (file_is_ivf(aom_input_ctx)) {
44 aom_input_ctx->file_type = FILE_TYPE_IVF;
45 } else {
46 fclose(infile);
47 aom_free(aom_input_ctx);
48 aom_internal_error(err_info, AOM_CODEC_INVALID_PARAM,
49 "Unrecognized input file type.");
50 }
51 *input_ctx_ptr = aom_input_ctx;
52}
53
54static void init_third_pass(THIRD_PASS_DEC_CTX *ctx) {
55 if (!ctx->input_ctx) {
56 if (ctx->input_file_name == NULL) {
57 aom_internal_error(ctx->err_info, AOM_CODEC_INVALID_PARAM,
58 "No third pass input specified.");
59 }
60 setup_two_pass_stream_input(&ctx->input_ctx, ctx->input_file_name,
61 ctx->err_info);
62 }
63
Bohan Li15b3c6d2021-07-27 17:27:20 -070064 if (!ctx->decoder.iface) {
65 aom_codec_iface_t *decoder_iface = &aom_codec_av1_inspect_algo;
66 if (aom_codec_dec_init(&ctx->decoder, decoder_iface, NULL, 0)) {
67 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
68 "Failed to initialize decoder.");
69 }
70 }
Bohan Li15b3c6d2021-07-27 17:27:20 -070071}
72
73// Return 0: success
74// 1: cannot read because this is end of file
75// -1: failure to read the frame
76static int read_frame(THIRD_PASS_DEC_CTX *ctx) {
77 if (!ctx->input_ctx || !ctx->decoder.iface) {
78 init_third_pass(ctx);
79 }
80 if (!ctx->have_frame) {
Bohan Li16f904b2022-09-28 15:17:29 -070081 if (ivf_read_frame(ctx->input_ctx, &ctx->buf, &ctx->bytes_in_buffer,
Bohan Li15b3c6d2021-07-27 17:27:20 -070082 &ctx->buffer_size, NULL) != 0) {
83 if (feof(ctx->input_ctx->file)) {
84 return 1;
85 } else {
86 return -1;
87 }
88 }
89 ctx->frame = ctx->buf;
90 ctx->end_frame = ctx->frame + ctx->bytes_in_buffer;
91 ctx->have_frame = 1;
92 }
James Zern59fc5492022-09-15 16:23:00 -070093
Bohan Li15b3c6d2021-07-27 17:27:20 -070094 Av1DecodeReturn adr;
95 if (aom_codec_decode(&ctx->decoder, ctx->frame,
96 (unsigned int)ctx->bytes_in_buffer,
97 &adr) != AOM_CODEC_OK) {
98 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
99 "Failed to decode frame for third pass.");
100 }
Bohan Li3c5b1242021-12-08 11:30:41 -0800101 ctx->this_frame_bits = (int)(adr.buf - ctx->frame) << 3;
Bohan Li15b3c6d2021-07-27 17:27:20 -0700102 ctx->frame = adr.buf;
103 ctx->bytes_in_buffer = ctx->end_frame - ctx->frame;
104 if (ctx->frame == ctx->end_frame) ctx->have_frame = 0;
105 return 0;
106}
107
Bohan Lifefbaa42021-10-14 13:04:34 -0700108static void free_frame_info(THIRD_PASS_FRAME_INFO *frame_info) {
109 if (!frame_info) return;
110 aom_free(frame_info->mi_info);
111 frame_info->mi_info = NULL;
112}
113
Bohan Li15b3c6d2021-07-27 17:27:20 -0700114// This function gets the information needed from the recently decoded frame,
115// via various decoder APIs, and saves the info into ctx->frame_info.
116// Return 0: success
117// 1: cannot read because this is end of file
118// -1: failure to read the frame
119static int get_frame_info(THIRD_PASS_DEC_CTX *ctx) {
120 int ret = read_frame(ctx);
121 if (ret != 0) return ret;
122 int cur = ctx->frame_info_count;
Bohan Li3c5b1242021-12-08 11:30:41 -0800123
124 ctx->frame_info[cur].actual_bits = ctx->this_frame_bits;
125
Bohan Li15b3c6d2021-07-27 17:27:20 -0700126 if (cur >= MAX_THIRD_PASS_BUF) {
127 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
128 "Third pass frame info ran out of available slots.");
129 }
James Zern408ab0e2022-11-03 17:26:09 -0700130 aom_codec_frame_flags_t frame_type_flags = 0;
Bohan Li15b3c6d2021-07-27 17:27:20 -0700131 if (aom_codec_control(&ctx->decoder, AOMD_GET_FRAME_FLAGS,
132 &frame_type_flags) != AOM_CODEC_OK) {
133 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
134 "Failed to read frame flags.");
135 }
136 if (frame_type_flags & AOM_FRAME_IS_KEY) {
137 ctx->frame_info[cur].frame_type = KEY_FRAME;
138 } else if (frame_type_flags & AOM_FRAME_IS_INTRAONLY) {
139 ctx->frame_info[cur].frame_type = INTRA_ONLY_FRAME;
140 } else if (frame_type_flags & AOM_FRAME_IS_SWITCH) {
141 ctx->frame_info[cur].frame_type = S_FRAME;
142 } else {
143 ctx->frame_info[cur].frame_type = INTER_FRAME;
144 }
145
Bohan Lifefbaa42021-10-14 13:04:34 -0700146 // Get frame width and height
147 int frame_size[2];
148 if (aom_codec_control(&ctx->decoder, AV1D_GET_FRAME_SIZE, frame_size) !=
149 AOM_CODEC_OK) {
150 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
151 "Failed to read frame size.");
152 }
153
154 // Check if we need to re-alloc the mi fields.
155 const int mi_cols = (frame_size[0] + 3) >> 2;
156 const int mi_rows = (frame_size[1] + 3) >> 2;
157 ctx->frame_info[cur].mi_stride = mi_cols;
158 ctx->frame_info[cur].mi_rows = mi_rows;
159 ctx->frame_info[cur].mi_cols = mi_cols;
160
161 if (ctx->frame_info[cur].width != frame_size[0] ||
162 ctx->frame_info[cur].height != frame_size[1] ||
163 !ctx->frame_info[cur].mi_info) {
164 free_frame_info(&ctx->frame_info[cur]);
165
166 ctx->frame_info[cur].mi_info =
167 aom_malloc(mi_cols * mi_rows * sizeof(*ctx->frame_info[cur].mi_info));
168
169 if (!ctx->frame_info[cur].mi_info) {
170 aom_internal_error(ctx->err_info, AOM_CODEC_MEM_ERROR,
Bohan Lia9bbead2021-11-09 13:02:52 -0800171 "Failed to allocate mi buffer for the third pass.");
Bohan Lifefbaa42021-10-14 13:04:34 -0700172 }
173 }
174
175 ctx->frame_info[cur].width = frame_size[0];
176 ctx->frame_info[cur].height = frame_size[1];
177
Bohan Li15b3c6d2021-07-27 17:27:20 -0700178 // Get frame base q idx
179 if (aom_codec_control(&ctx->decoder, AOMD_GET_BASE_Q_IDX,
180 &ctx->frame_info[cur].base_q_idx) != AOM_CODEC_OK) {
181 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
182 "Failed to read base q index.");
183 }
184
185 // Get show existing frame flag
186 if (aom_codec_control(&ctx->decoder, AOMD_GET_SHOW_EXISTING_FRAME_FLAG,
187 &ctx->frame_info[cur].is_show_existing_frame) !=
188 AOM_CODEC_OK) {
189 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
190 "Failed to read show existing frame flag.");
191 }
192
193 // Get show frame flag
194 if (aom_codec_control(&ctx->decoder, AOMD_GET_SHOW_FRAME_FLAG,
195 &ctx->frame_info[cur].is_show_frame) != AOM_CODEC_OK) {
196 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
197 "Failed to read show frame flag.");
198 }
199
200 // Get order hint
201 if (aom_codec_control(&ctx->decoder, AOMD_GET_ORDER_HINT,
202 &ctx->frame_info[cur].order_hint) != AOM_CODEC_OK) {
203 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
204 "Failed to read order hint.");
205 }
Bohan Lifefbaa42021-10-14 13:04:34 -0700206
207 // Clear MI info
208 for (int mi_row = 0; mi_row < mi_rows; mi_row++) {
209 for (int mi_col = 0; mi_col < mi_cols; mi_col++) {
210 ctx->frame_info[cur].mi_info[mi_row * mi_cols + mi_col].bsize =
211 BLOCK_INVALID;
212 }
213 }
214
215 // Get relevant information regarding each 4x4 MI
216 MB_MODE_INFO cur_mi_info;
217 THIRD_PASS_MI_INFO *const this_mi = ctx->frame_info[cur].mi_info;
218 for (int mi_row = 0; mi_row < mi_rows; mi_row++) {
219 for (int mi_col = 0; mi_col < mi_cols; mi_col++) {
220 const int offset = mi_row * mi_cols + mi_col;
221 if (this_mi[offset].bsize != BLOCK_INVALID) {
222 continue;
223 }
224 // Get info of this MI
225 if (aom_codec_control(&ctx->decoder, AV1D_GET_MI_INFO, mi_row, mi_col,
226 &cur_mi_info) != AOM_CODEC_OK) {
227 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
228 "Failed to read mi info.");
229 }
230 const int blk_mi_rows = mi_size_high[cur_mi_info.bsize];
231 const int blk_mi_cols = mi_size_wide[cur_mi_info.bsize];
232
233 for (int h = 0; h < blk_mi_rows; h++) {
234 for (int w = 0; w < blk_mi_cols; w++) {
235 if (h + mi_row >= mi_rows || w + mi_col >= mi_cols) {
236 continue;
237 }
238 const int this_offset = offset + h * mi_cols + w;
239 this_mi[this_offset].bsize = cur_mi_info.bsize;
Bohan Liafa0a022021-11-09 12:55:48 -0800240 this_mi[this_offset].partition = cur_mi_info.partition;
Bohan Lifefbaa42021-10-14 13:04:34 -0700241 this_mi[this_offset].mi_row_start = mi_row;
242 this_mi[this_offset].mi_col_start = mi_col;
243 this_mi[this_offset].mv[0] = cur_mi_info.mv[0];
244 this_mi[this_offset].mv[1] = cur_mi_info.mv[1];
245 this_mi[this_offset].ref_frame[0] = cur_mi_info.ref_frame[0];
246 this_mi[this_offset].ref_frame[1] = cur_mi_info.ref_frame[1];
Bohan Licaabfeb2021-11-16 17:39:50 -0800247 this_mi[this_offset].pred_mode = cur_mi_info.mode;
Bohan Lifefbaa42021-10-14 13:04:34 -0700248 }
249 }
250 }
251 }
252
Bohan Li15b3c6d2021-07-27 17:27:20 -0700253 ctx->frame_info_count++;
Bohan Lifefbaa42021-10-14 13:04:34 -0700254
Bohan Li15b3c6d2021-07-27 17:27:20 -0700255 return 0;
256}
257
Bohan Lif3759fa2021-10-13 11:20:02 -0700258#define USE_SECOND_PASS_FILE 1
259
260#if !USE_SECOND_PASS_FILE
Bohan Li15b3c6d2021-07-27 17:27:20 -0700261// Parse the frames in the gop and determine the last frame of the current GOP.
262// Decode more frames if necessary. The variable max_num is the maximum static
263// GOP length if we detect an IPPP structure, and it is expected that max_mum >=
264// MAX_GF_INTERVAL.
265static void get_current_gop_end(THIRD_PASS_DEC_CTX *ctx, int max_num,
266 int *last_idx) {
267 assert(max_num >= MAX_GF_INTERVAL);
268 *last_idx = 0;
269 int cur_idx = 0;
270 int arf_order_hint = -1;
271 int num_show_frames = 0;
272 while (num_show_frames < max_num) {
273 assert(cur_idx < MAX_THIRD_PASS_BUF);
274 // Read in from bitstream if needed.
275 if (cur_idx >= ctx->frame_info_count) {
276 int ret = get_frame_info(ctx);
277 if (ret == 1) {
278 // At the end of the file, GOP ends in the prev frame.
279 if (arf_order_hint >= 0) {
280 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
281 "Failed to derive GOP length.");
282 }
283 *last_idx = cur_idx - 1;
284 return;
285 }
286 if (ret < 0) {
287 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
288 "Failed to read frame for third pass.");
289 }
290 }
291
292 // TODO(bohanli): verify that fwd_kf works here.
293 if (ctx->frame_info[cur_idx].frame_type == KEY_FRAME &&
294 ctx->frame_info[cur_idx].is_show_frame) {
295 if (cur_idx != 0) {
296 // If this is a key frame and is not the first kf in this kf group, we
297 // have reached the next key frame. Stop here.
298 *last_idx = cur_idx - 1;
299 return;
300 }
301 } else if (!ctx->frame_info[cur_idx].is_show_frame &&
302 arf_order_hint == -1) {
303 // If this is an arf (the first no show)
304 if (num_show_frames <= 1) {
305 // This is an arf and we should end the GOP with its overlay.
306 arf_order_hint = ctx->frame_info[cur_idx].order_hint;
307 } else {
308 // There are multiple show frames before the this arf, so we treat the
309 // frames previous to this arf as a GOP.
310 *last_idx = cur_idx - 1;
311 return;
312 }
313 } else if (arf_order_hint >= 0 && ctx->frame_info[cur_idx].order_hint ==
314 (unsigned int)arf_order_hint) {
315 // If this is the overlay/show existing of the arf
316 assert(ctx->frame_info[cur_idx].is_show_frame);
317 *last_idx = cur_idx;
318 return;
319 } else {
320 // This frame is part of the GOP.
321 if (ctx->frame_info[cur_idx].is_show_frame) num_show_frames++;
322 }
323 cur_idx++;
324 }
325 // This is a long IPPP GOP and we will use a length of max_num here.
326 assert(arf_order_hint < 0);
327 *last_idx = max_num - 1;
328 return;
329}
Bohan Lif3759fa2021-10-13 11:20:02 -0700330#endif
Bohan Li15b3c6d2021-07-27 17:27:20 -0700331
Bohan Lif3759fa2021-10-13 11:20:02 -0700332static AOM_INLINE void read_gop_frames(THIRD_PASS_DEC_CTX *ctx) {
333 int cur_idx = 0;
334 while (cur_idx < ctx->gop_info.num_frames) {
335 assert(cur_idx < MAX_THIRD_PASS_BUF);
336 // Read in from bitstream if needed.
337 if (cur_idx >= ctx->frame_info_count) {
338 int ret = get_frame_info(ctx);
339 if (ret != 0) {
340 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
341 "Failed to read frame for third pass.");
342 }
343 }
344 cur_idx++;
Bohan Li15b3c6d2021-07-27 17:27:20 -0700345 }
Bohan Lif3759fa2021-10-13 11:20:02 -0700346 return;
347}
Bohan Li15b3c6d2021-07-27 17:27:20 -0700348
Bohan Lif3759fa2021-10-13 11:20:02 -0700349void av1_set_gop_third_pass(THIRD_PASS_DEC_CTX *ctx) {
350 // Read in future frames in the current GOP.
351 read_gop_frames(ctx);
352
353 int gf_len = 0;
354 // Check the GOP length against the value read from second_pass_file
355 for (int i = 0; i < ctx->gop_info.num_frames; i++) {
356 if (ctx->frame_info[i].is_show_frame) gf_len++;
357 }
358
359 if (gf_len != ctx->gop_info.gf_length) {
360 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
361 "Mismatch in third pass GOP length!");
362 }
Bohan Li15b3c6d2021-07-27 17:27:20 -0700363}
364
365void av1_pop_third_pass_info(THIRD_PASS_DEC_CTX *ctx) {
366 if (ctx->frame_info_count == 0) {
367 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
368 "No available frame info for third pass.");
369 }
370 ctx->frame_info_count--;
Bohan Lifefbaa42021-10-14 13:04:34 -0700371 free_frame_info(&ctx->frame_info[0]);
Bohan Li15b3c6d2021-07-27 17:27:20 -0700372 for (int i = 0; i < ctx->frame_info_count; i++) {
373 ctx->frame_info[i] = ctx->frame_info[i + 1];
374 }
Bohan Lifefbaa42021-10-14 13:04:34 -0700375 ctx->frame_info[ctx->frame_info_count].mi_info = NULL;
Bohan Li15b3c6d2021-07-27 17:27:20 -0700376}
377
378void av1_init_thirdpass_ctx(AV1_COMMON *cm, THIRD_PASS_DEC_CTX **ctx,
379 const char *file) {
380 av1_free_thirdpass_ctx(*ctx);
381 CHECK_MEM_ERROR(cm, *ctx, aom_calloc(1, sizeof(**ctx)));
382 THIRD_PASS_DEC_CTX *ctx_ptr = *ctx;
383 ctx_ptr->input_file_name = file;
384 ctx_ptr->prev_gop_end = -1;
385 ctx_ptr->err_info = cm->error;
386}
387
388void av1_free_thirdpass_ctx(THIRD_PASS_DEC_CTX *ctx) {
389 if (ctx == NULL) return;
390 if (ctx->decoder.iface) {
391 aom_codec_destroy(&ctx->decoder);
392 }
393 if (ctx->input_ctx && ctx->input_ctx->file) fclose(ctx->input_ctx->file);
394 aom_free(ctx->input_ctx);
Bohan Li15b3c6d2021-07-27 17:27:20 -0700395 if (ctx->buf) free(ctx->buf);
Bohan Lifefbaa42021-10-14 13:04:34 -0700396 for (int i = 0; i < MAX_THIRD_PASS_BUF; i++) {
397 free_frame_info(&ctx->frame_info[i]);
398 }
Bohan Li15b3c6d2021-07-27 17:27:20 -0700399 aom_free(ctx);
400}
Bohan Liedec7cd2021-08-26 09:17:47 -0700401
402void av1_write_second_pass_gop_info(AV1_COMP *cpi) {
403 const AV1EncoderConfig *const oxcf = &cpi->oxcf;
404 const GF_GROUP *const gf_group = &cpi->ppi->gf_group;
405 const PRIMARY_RATE_CONTROL *const p_rc = &cpi->ppi->p_rc;
406
407 if (oxcf->pass == AOM_RC_SECOND_PASS && oxcf->second_pass_log) {
408 // Write the GOP length to a log file.
Angie Chiang21c2ff42022-01-03 01:08:24 -0800409 av1_open_second_pass_log(cpi, 0);
Bohan Liedec7cd2021-08-26 09:17:47 -0700410
411 THIRD_PASS_GOP_INFO gop_info;
412
413 gop_info.num_frames = gf_group->size;
414 gop_info.use_arf = (gf_group->arf_index >= 0);
415 gop_info.gf_length = p_rc->baseline_gf_interval;
416
417 size_t count =
418 fwrite(&gop_info, sizeof(gop_info), 1, cpi->second_pass_log_stream);
419 if (count < 1) {
420 aom_internal_error(cpi->common.error, AOM_CODEC_ERROR,
421 "Could not write to second pass log file!");
422 }
423 }
424}
425
Bohan Li3c5b1242021-12-08 11:30:41 -0800426void av1_write_second_pass_per_frame_info(AV1_COMP *cpi, int gf_index) {
427 const AV1EncoderConfig *const oxcf = &cpi->oxcf;
428 const GF_GROUP *const gf_group = &cpi->ppi->gf_group;
429
430 if (oxcf->pass == AOM_RC_SECOND_PASS && oxcf->second_pass_log) {
431 // write target bitrate
432 int bits = gf_group->bit_allocation[gf_index];
433 size_t count = fwrite(&bits, sizeof(bits), 1, cpi->second_pass_log_stream);
434 if (count < 1) {
435 aom_internal_error(cpi->common.error, AOM_CODEC_ERROR,
436 "Could not write to second pass log file!");
437 }
438
439 // write sse
440 uint64_t sse = 0;
441 int pkt_idx = cpi->ppi->output_pkt_list->cnt - 1;
442 if (pkt_idx >= 0 &&
443 cpi->ppi->output_pkt_list->pkts[pkt_idx].kind == AOM_CODEC_PSNR_PKT) {
444 sse = cpi->ppi->output_pkt_list->pkts[pkt_idx].data.psnr.sse[0];
445#if CONFIG_INTERNAL_STATS
446 } else if (cpi->ppi->b_calculate_psnr) {
447 sse = cpi->ppi->total_sq_error[0];
448#endif
449 } else {
450 const YV12_BUFFER_CONFIG *orig = cpi->source;
451 const YV12_BUFFER_CONFIG *recon = &cpi->common.cur_frame->buf;
452 PSNR_STATS psnr;
453#if CONFIG_AV1_HIGHBITDEPTH
454 const uint32_t in_bit_depth = cpi->oxcf.input_cfg.input_bit_depth;
455 const uint32_t bit_depth = cpi->td.mb.e_mbd.bd;
456 aom_calc_highbd_psnr(orig, recon, &psnr, bit_depth, in_bit_depth);
457#else
458 aom_calc_psnr(orig, recon, &psnr);
459#endif
460 sse = psnr.sse[0];
461 }
462
463 count = fwrite(&sse, sizeof(sse), 1, cpi->second_pass_log_stream);
464 if (count < 1) {
465 aom_internal_error(cpi->common.error, AOM_CODEC_ERROR,
466 "Could not write to second pass log file!");
467 }
Bohan Li4772b932021-12-08 16:05:06 -0800468
469 // write bpm_factor
470 double factor = cpi->ppi->twopass.bpm_factor;
471 count = fwrite(&factor, sizeof(factor), 1, cpi->second_pass_log_stream);
472 if (count < 1) {
473 aom_internal_error(cpi->common.error, AOM_CODEC_ERROR,
474 "Could not write to second pass log file!");
475 }
Bohan Li3c5b1242021-12-08 11:30:41 -0800476 }
477}
Angie Chiang21c2ff42022-01-03 01:08:24 -0800478void av1_open_second_pass_log(AV1_COMP *cpi, int is_read) {
Bohan Liedec7cd2021-08-26 09:17:47 -0700479 const AV1EncoderConfig *const oxcf = &cpi->oxcf;
Angie Chiang21c2ff42022-01-03 01:08:24 -0800480 if (oxcf->second_pass_log == NULL) {
481 aom_internal_error(cpi->common.error, AOM_CODEC_INVALID_PARAM,
482 "No second pass log file specified for the third pass!");
483 }
484 // Read the GOP length from a file.
485 if (!cpi->second_pass_log_stream) {
486 if (is_read) {
Bohan Liedec7cd2021-08-26 09:17:47 -0700487 cpi->second_pass_log_stream = fopen(cpi->oxcf.second_pass_log, "rb");
Angie Chiang21c2ff42022-01-03 01:08:24 -0800488 } else {
489 cpi->second_pass_log_stream = fopen(cpi->oxcf.second_pass_log, "wb");
Bohan Liedec7cd2021-08-26 09:17:47 -0700490 }
Angie Chiang21c2ff42022-01-03 01:08:24 -0800491 if (!cpi->second_pass_log_stream) {
Bohan Liedec7cd2021-08-26 09:17:47 -0700492 aom_internal_error(cpi->common.error, AOM_CODEC_ERROR,
Angie Chiang21c2ff42022-01-03 01:08:24 -0800493 "Could not open second pass log file!");
Bohan Liedec7cd2021-08-26 09:17:47 -0700494 }
495 }
496}
Bohan Lid0986522021-10-13 11:25:16 -0700497
Angie Chiang21c2ff42022-01-03 01:08:24 -0800498void av1_close_second_pass_log(AV1_COMP *cpi) {
499 if (cpi->second_pass_log_stream) {
500 int ret = fclose(cpi->second_pass_log_stream);
501 if (ret != 0) {
502 aom_internal_error(cpi->common.error, AOM_CODEC_ERROR,
503 "Could not close second pass log file!");
Bohan Li3c5b1242021-12-08 11:30:41 -0800504 }
Angie Chiang21c2ff42022-01-03 01:08:24 -0800505 cpi->second_pass_log_stream = 0;
506 }
507}
508
509void av1_read_second_pass_gop_info(FILE *second_pass_log_stream,
510 THIRD_PASS_GOP_INFO *gop_info,
511 struct aom_internal_error_info *error) {
512 size_t count = fread(gop_info, sizeof(*gop_info), 1, second_pass_log_stream);
513 if (count < 1) {
514 aom_internal_error(error, AOM_CODEC_ERROR,
515 "Could not read from second pass log file!");
516 }
517}
518
519void av1_read_second_pass_per_frame_info(
520 FILE *second_pass_log_stream, THIRD_PASS_FRAME_INFO *frame_info_arr,
521 int frame_info_count, struct aom_internal_error_info *error) {
522 for (int i = 0; i < frame_info_count; i++) {
523 // read target bits
524 int bits = 0;
525 size_t count = fread(&bits, sizeof(bits), 1, second_pass_log_stream);
526 if (count < 1) {
527 aom_internal_error(error, AOM_CODEC_ERROR,
528 "Could not read from second pass log file!");
529 }
530 frame_info_arr[i].bits_allocated = bits;
531
532 // read distortion
533 uint64_t sse;
534 count = fread(&sse, sizeof(sse), 1, second_pass_log_stream);
535 if (count < 1) {
536 aom_internal_error(error, AOM_CODEC_ERROR,
537 "Could not read from second pass log file!");
538 }
539 frame_info_arr[i].sse = sse;
540
541 // read bpm factor
542 double factor;
543 count = fread(&factor, sizeof(factor), 1, second_pass_log_stream);
544 if (count < 1) {
545 aom_internal_error(error, AOM_CODEC_ERROR,
546 "Could not read from second pass log file!");
547 }
548 frame_info_arr[i].bpm_factor = factor;
Bohan Li3c5b1242021-12-08 11:30:41 -0800549 }
550}
551
Bohan Lid0986522021-10-13 11:25:16 -0700552int av1_check_use_arf(THIRD_PASS_DEC_CTX *ctx) {
553 if (ctx == NULL) return -1;
554 int use_arf = 0;
555 for (int i = 0; i < ctx->gop_info.gf_length; i++) {
556 if (ctx->frame_info[i].order_hint != 0 &&
557 ctx->frame_info[i].is_show_frame == 0) {
558 use_arf = 1;
559 }
560 }
561 if (use_arf != ctx->gop_info.use_arf) {
562 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
563 "Mismatch in third pass GOP length!");
564 }
565 return use_arf;
566}
Bohan Lifefbaa42021-10-14 13:04:34 -0700567
568void av1_get_third_pass_ratio(THIRD_PASS_DEC_CTX *ctx, int fidx, int fheight,
569 int fwidth, double *ratio_h, double *ratio_w) {
570 assert(ctx);
571 assert(fidx < ctx->frame_info_count);
572 const int fheight_second_pass = ctx->frame_info[fidx].height;
573 const int fwidth_second_pass = ctx->frame_info[fidx].width;
574 assert(fheight_second_pass <= fheight && fwidth_second_pass <= fwidth);
575
576 *ratio_h = (double)fheight / fheight_second_pass;
577 *ratio_w = (double)fwidth / fwidth_second_pass;
578}
579
580THIRD_PASS_MI_INFO *av1_get_third_pass_mi(THIRD_PASS_DEC_CTX *ctx, int fidx,
581 int mi_row, int mi_col,
582 double ratio_h, double ratio_w) {
583 assert(ctx);
584 assert(fidx < ctx->frame_info_count);
585
586 const int mi_rows_second_pass = ctx->frame_info[fidx].mi_rows;
587 const int mi_cols_second_pass = ctx->frame_info[fidx].mi_cols;
588
589 const int mi_row_second_pass =
590 clamp((int)round(mi_row / ratio_h), 0, mi_rows_second_pass - 1);
591 const int mi_col_second_pass =
592 clamp((int)round(mi_col / ratio_w), 0, mi_cols_second_pass - 1);
593
594 const int mi_stride_second_pass = ctx->frame_info[fidx].mi_stride;
595 THIRD_PASS_MI_INFO *this_mi = ctx->frame_info[fidx].mi_info +
596 mi_row_second_pass * mi_stride_second_pass +
597 mi_col_second_pass;
598 return this_mi;
599}
600
601void av1_third_pass_get_adjusted_mi(THIRD_PASS_MI_INFO *third_pass_mi,
602 double ratio_h, double ratio_w, int *mi_row,
603 int *mi_col) {
604 *mi_row = (int)round(third_pass_mi->mi_row_start * ratio_h);
605 *mi_col = (int)round(third_pass_mi->mi_col_start * ratio_w);
606}
607
608int_mv av1_get_third_pass_adjusted_mv(THIRD_PASS_MI_INFO *this_mi,
609 double ratio_h, double ratio_w,
610 MV_REFERENCE_FRAME frame) {
611 assert(this_mi != NULL);
612 int_mv cur_mv;
613 cur_mv.as_int = INVALID_MV;
614
615 if (frame < LAST_FRAME || frame > ALTREF_FRAME) return cur_mv;
616
617 for (int r = 0; r < 2; r++) {
618 if (this_mi->ref_frame[r] == frame) {
619 cur_mv.as_mv.row = (int16_t)round(this_mi->mv[r].as_mv.row * ratio_h);
620 cur_mv.as_mv.col = (int16_t)round(this_mi->mv[r].as_mv.col * ratio_w);
621 }
622 }
623
624 return cur_mv;
625}
626
627BLOCK_SIZE av1_get_third_pass_adjusted_blk_size(THIRD_PASS_MI_INFO *this_mi,
628 double ratio_h,
629 double ratio_w) {
630 assert(this_mi != NULL);
631 BLOCK_SIZE bsize = BLOCK_INVALID;
632
633 const BLOCK_SIZE bsize_second_pass = this_mi->bsize;
634 assert(bsize_second_pass != BLOCK_INVALID);
635
636 const int w_second_pass = block_size_wide[bsize_second_pass];
637 const int h_second_pass = block_size_high[bsize_second_pass];
638
639 int part_type;
640
641 if (w_second_pass == h_second_pass) {
642 part_type = PARTITION_NONE;
643 } else if (w_second_pass / h_second_pass == 2) {
644 part_type = PARTITION_HORZ;
645 } else if (w_second_pass / h_second_pass == 4) {
646 part_type = PARTITION_HORZ_4;
647 } else if (h_second_pass / w_second_pass == 2) {
648 part_type = PARTITION_VERT;
649 } else if (h_second_pass / w_second_pass == 4) {
650 part_type = PARTITION_VERT_4;
651 } else {
652 part_type = PARTITION_INVALID;
653 }
654 assert(part_type != PARTITION_INVALID);
655
656 const int w = (int)(round(w_second_pass * ratio_w));
657 const int h = (int)(round(h_second_pass * ratio_h));
658
659 for (int i = 0; i < SQR_BLOCK_SIZES; i++) {
660 const BLOCK_SIZE this_bsize = subsize_lookup[part_type][i];
661 if (this_bsize == BLOCK_INVALID) continue;
662
663 const int this_w = block_size_wide[this_bsize];
664 const int this_h = block_size_high[this_bsize];
665
666 if (this_w >= w && this_h >= h) {
667 // find the smallest block size that contains the mapped block
668 bsize = this_bsize;
669 break;
670 }
671 }
672 if (bsize == BLOCK_INVALID) {
673 // could not find a proper one, just use the largest then.
674 bsize = BLOCK_128X128;
675 }
676
677 return bsize;
678}
Bohan Liafa0a022021-11-09 12:55:48 -0800679
Bohan Lia9bbead2021-11-09 13:02:52 -0800680PARTITION_TYPE av1_third_pass_get_sb_part_type(THIRD_PASS_DEC_CTX *ctx,
681 THIRD_PASS_MI_INFO *this_mi) {
Bohan Liafa0a022021-11-09 12:55:48 -0800682 int mi_stride = ctx->frame_info[0].mi_stride;
683
684 int mi_row = this_mi->mi_row_start;
685 int mi_col = this_mi->mi_col_start;
686
687 THIRD_PASS_MI_INFO *corner_mi =
688 &ctx->frame_info[0].mi_info[mi_row * mi_stride + mi_col];
689
690 return corner_mi->partition;
691}
Angie Chiangb17a57d2021-12-28 17:34:39 -0800692
James Zern59fc5492022-09-15 16:23:00 -0700693#else // !(CONFIG_THREE_PASS && CONFIG_AV1_DECODER)
694void av1_init_thirdpass_ctx(AV1_COMMON *cm, THIRD_PASS_DEC_CTX **ctx,
695 const char *file) {
696 (void)ctx;
697 (void)file;
698 aom_internal_error(cm->error, AOM_CODEC_ERROR,
699 "To utilize three-pass encoding, libaom must be built "
700 "with CONFIG_THREE_PASS=1 & CONFIG_AV1_DECODER=1.");
701}
702
703void av1_free_thirdpass_ctx(THIRD_PASS_DEC_CTX *ctx) { (void)ctx; }
704
705void av1_set_gop_third_pass(THIRD_PASS_DEC_CTX *ctx) { (void)ctx; }
706
707void av1_pop_third_pass_info(THIRD_PASS_DEC_CTX *ctx) { (void)ctx; }
708
709void av1_open_second_pass_log(struct AV1_COMP *cpi, int is_read) {
710 (void)cpi;
711 (void)is_read;
712}
713
714void av1_close_second_pass_log(struct AV1_COMP *cpi) { (void)cpi; }
715
716void av1_write_second_pass_gop_info(struct AV1_COMP *cpi) { (void)cpi; }
717
718void av1_write_second_pass_per_frame_info(struct AV1_COMP *cpi, int gf_index) {
719 (void)cpi;
720 (void)gf_index;
721}
722
723void av1_read_second_pass_gop_info(FILE *second_pass_log_stream,
724 THIRD_PASS_GOP_INFO *gop_info,
725 struct aom_internal_error_info *error) {
726 (void)second_pass_log_stream;
727 (void)gop_info;
728 (void)error;
729}
730
731void av1_read_second_pass_per_frame_info(
732 FILE *second_pass_log_stream, THIRD_PASS_FRAME_INFO *frame_info_arr,
733 int frame_info_count, struct aom_internal_error_info *error) {
734 (void)second_pass_log_stream;
735 (void)frame_info_arr;
736 (void)frame_info_count;
737 (void)error;
738}
739
740int av1_check_use_arf(THIRD_PASS_DEC_CTX *ctx) {
741 (void)ctx;
742 return 1;
743}
744
745void av1_get_third_pass_ratio(THIRD_PASS_DEC_CTX *ctx, int fidx, int fheight,
746 int fwidth, double *ratio_h, double *ratio_w) {
747 (void)ctx;
748 (void)fidx;
749 (void)fheight;
750 (void)fwidth;
751 (void)ratio_h;
752 (void)ratio_w;
753}
754
755THIRD_PASS_MI_INFO *av1_get_third_pass_mi(THIRD_PASS_DEC_CTX *ctx, int fidx,
756 int mi_row, int mi_col,
757 double ratio_h, double ratio_w) {
758 (void)ctx;
759 (void)fidx;
760 (void)mi_row;
761 (void)mi_col;
762 (void)ratio_h;
763 (void)ratio_w;
764 return NULL;
765}
766
767int_mv av1_get_third_pass_adjusted_mv(THIRD_PASS_MI_INFO *this_mi,
768 double ratio_h, double ratio_w,
769 MV_REFERENCE_FRAME frame) {
770 (void)this_mi;
771 (void)ratio_h;
772 (void)ratio_w;
773 (void)frame;
774 int_mv mv;
775 mv.as_int = INVALID_MV;
776 return mv;
777}
778
779BLOCK_SIZE av1_get_third_pass_adjusted_blk_size(THIRD_PASS_MI_INFO *this_mi,
780 double ratio_h,
781 double ratio_w) {
782 (void)this_mi;
783 (void)ratio_h;
784 (void)ratio_w;
785 return BLOCK_INVALID;
786}
787
788void av1_third_pass_get_adjusted_mi(THIRD_PASS_MI_INFO *third_pass_mi,
789 double ratio_h, double ratio_w, int *mi_row,
790 int *mi_col) {
791 (void)third_pass_mi;
792 (void)ratio_h;
793 (void)ratio_w;
794 (void)mi_row;
795 (void)mi_col;
796}
797
798PARTITION_TYPE av1_third_pass_get_sb_part_type(THIRD_PASS_DEC_CTX *ctx,
799 THIRD_PASS_MI_INFO *this_mi) {
800 (void)ctx;
801 (void)this_mi;
802 return PARTITION_INVALID;
803}
804#endif // CONFIG_THREE_PASS && CONFIG_AV1_DECODER
805
Angie Chiangb17a57d2021-12-28 17:34:39 -0800806#if CONFIG_BITRATE_ACCURACY
807static void fwrite_and_check(const void *ptr, size_t size, size_t nmemb,
808 FILE *stream,
809 struct aom_internal_error_info *error) {
Wan-Teh Chang0552d892022-03-21 18:25:47 -0700810 size_t count = fwrite(ptr, size, nmemb, stream);
811 if (count < nmemb) {
Angie Chiangb17a57d2021-12-28 17:34:39 -0800812 aom_internal_error(error, AOM_CODEC_ERROR, "fwrite_and_check failed\n");
813 }
814}
815
816static void fread_and_check(void *ptr, size_t size, size_t nmemb, FILE *stream,
817 struct aom_internal_error_info *error) {
Wan-Teh Chang0552d892022-03-21 18:25:47 -0700818 size_t count = fread(ptr, size, nmemb, stream);
819 if (count < nmemb) {
Angie Chiangb17a57d2021-12-28 17:34:39 -0800820 aom_internal_error(error, AOM_CODEC_ERROR, "fread_and_check failed\n");
821 }
822}
823
824void av1_pack_tpl_info(TPL_INFO *tpl_info, const GF_GROUP *gf_group,
825 const TplParams *tpl_data) {
826 tpl_info->tpl_ready = tpl_data->ready;
827 if (tpl_info->tpl_ready) {
828 tpl_info->gf_length = gf_group->size;
829 for (int i = 0; i < tpl_info->gf_length; ++i) {
830 tpl_info->txfm_stats_list[i] = tpl_data->txfm_stats_list[i];
831 tpl_info->qstep_ratio_ls[i] = av1_tpl_get_qstep_ratio(tpl_data, i);
Angie Chiang215e9062022-04-06 11:35:31 -0700832 tpl_info->update_type_list[i] = gf_group->update_type[i];
Angie Chiangb17a57d2021-12-28 17:34:39 -0800833 }
834 }
835}
836
837void av1_write_tpl_info(const TPL_INFO *tpl_info, FILE *log_stream,
838 struct aom_internal_error_info *error) {
Wan-Teh Chang0552d892022-03-21 18:25:47 -0700839 fwrite_and_check(&tpl_info->tpl_ready, sizeof(tpl_info->tpl_ready), 1,
840 log_stream, error);
Angie Chiangb17a57d2021-12-28 17:34:39 -0800841 if (tpl_info->tpl_ready) {
842 fwrite_and_check(&tpl_info->gf_length, sizeof(tpl_info->gf_length), 1,
843 log_stream, error);
844 assert(tpl_info->gf_length <= MAX_LENGTH_TPL_FRAME_STATS);
845 fwrite_and_check(&tpl_info->txfm_stats_list,
846 sizeof(tpl_info->txfm_stats_list[0]), tpl_info->gf_length,
847 log_stream, error);
848 fwrite_and_check(&tpl_info->qstep_ratio_ls,
849 sizeof(tpl_info->qstep_ratio_ls[0]), tpl_info->gf_length,
850 log_stream, error);
Angie Chiang215e9062022-04-06 11:35:31 -0700851 fwrite_and_check(&tpl_info->update_type_list,
852 sizeof(tpl_info->update_type_list[0]), tpl_info->gf_length,
853 log_stream, error);
Angie Chiangb17a57d2021-12-28 17:34:39 -0800854 }
855}
856
857void av1_read_tpl_info(TPL_INFO *tpl_info, FILE *log_stream,
858 struct aom_internal_error_info *error) {
859 av1_zero(*tpl_info);
860 fread_and_check(&tpl_info->tpl_ready, sizeof(tpl_info->tpl_ready), 1,
861 log_stream, error);
862 if (tpl_info->tpl_ready) {
863 fread_and_check(&tpl_info->gf_length, sizeof(tpl_info->gf_length), 1,
864 log_stream, error);
865 assert(tpl_info->gf_length <= MAX_LENGTH_TPL_FRAME_STATS);
866 fread_and_check(&tpl_info->txfm_stats_list,
867 sizeof(tpl_info->txfm_stats_list[0]), tpl_info->gf_length,
868 log_stream, error);
869 fread_and_check(&tpl_info->qstep_ratio_ls,
870 sizeof(tpl_info->qstep_ratio_ls[0]), tpl_info->gf_length,
871 log_stream, error);
Angie Chiang215e9062022-04-06 11:35:31 -0700872 fread_and_check(&tpl_info->update_type_list,
873 sizeof(tpl_info->update_type_list[0]), tpl_info->gf_length,
874 log_stream, error);
Angie Chiangb17a57d2021-12-28 17:34:39 -0800875 }
876}
877#endif // CONFIG_BITRATE_ACCURACY