1 /*
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 */
11
12 #include "aom/aom_codec.h"
13 #include "aom/aomdx.h"
14 #include "aom_mem/aom_mem.h"
15 #include "av1/av1_iface_common.h"
16 #include "av1/encoder/firstpass.h"
17 #include "av1/encoder/thirdpass.h"
18 #include "av1/common/blockd.h"
19
20 #if CONFIG_THREE_PASS
21 #include "common/ivfdec.h"
22 #endif
23
24 #if CONFIG_THREE_PASS
setup_two_pass_stream_input(struct AvxInputContext ** input_ctx_ptr,const char * input_file_name,struct aom_internal_error_info * err_info)25 static void setup_two_pass_stream_input(
26 struct AvxInputContext **input_ctx_ptr, const char *input_file_name,
27 struct aom_internal_error_info *err_info) {
28 FILE *infile;
29 infile = fopen(input_file_name, "rb");
30 if (!infile) {
31 aom_internal_error(err_info, AOM_CODEC_INVALID_PARAM,
32 "Failed to open input file '%s'.", input_file_name);
33 }
34 struct AvxInputContext *aom_input_ctx = aom_malloc(sizeof(*aom_input_ctx));
35 if (!aom_input_ctx) {
36 fclose(infile);
37 aom_internal_error(err_info, AOM_CODEC_MEM_ERROR,
38 "Failed to allocate memory for third-pass context.");
39 }
40 memset(aom_input_ctx, 0, sizeof(*aom_input_ctx));
41 aom_input_ctx->filename = input_file_name;
42 aom_input_ctx->file = infile;
43
44 if (file_is_ivf(aom_input_ctx)) {
45 aom_input_ctx->file_type = FILE_TYPE_IVF;
46 } else {
47 fclose(infile);
48 aom_free(aom_input_ctx);
49 aom_internal_error(err_info, AOM_CODEC_INVALID_PARAM,
50 "Unrecognized input file type.");
51 }
52 *input_ctx_ptr = aom_input_ctx;
53 }
54
init_third_pass(THIRD_PASS_DEC_CTX * ctx)55 static void init_third_pass(THIRD_PASS_DEC_CTX *ctx) {
56 if (!ctx->input_ctx) {
57 if (ctx->input_file_name == NULL) {
58 aom_internal_error(ctx->err_info, AOM_CODEC_INVALID_PARAM,
59 "No third pass input specified.");
60 }
61 setup_two_pass_stream_input(&ctx->input_ctx, ctx->input_file_name,
62 ctx->err_info);
63 }
64
65 #if CONFIG_AV1_DECODER
66 if (!ctx->decoder.iface) {
67 aom_codec_iface_t *decoder_iface = &aom_codec_av1_inspect_algo;
68 if (aom_codec_dec_init(&ctx->decoder, decoder_iface, NULL, 0)) {
69 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
70 "Failed to initialize decoder.");
71 }
72 }
73 #else
74 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
75 "To utilize three-pass encoding, libaom must be built "
76 "with CONFIG_AV1_DECODER=1.");
77 #endif
78 }
79 #endif // CONFIG_THREE_PASS
80
81 // Return 0: success
82 // 1: cannot read because this is end of file
83 // -1: failure to read the frame
read_frame(THIRD_PASS_DEC_CTX * ctx)84 static int read_frame(THIRD_PASS_DEC_CTX *ctx) {
85 #if CONFIG_THREE_PASS
86 if (!ctx->input_ctx || !ctx->decoder.iface) {
87 init_third_pass(ctx);
88 }
89 if (!ctx->have_frame) {
90 if (ivf_read_frame(ctx->input_ctx->file, &ctx->buf, &ctx->bytes_in_buffer,
91 &ctx->buffer_size, NULL) != 0) {
92 if (feof(ctx->input_ctx->file)) {
93 return 1;
94 } else {
95 return -1;
96 }
97 }
98 ctx->frame = ctx->buf;
99 ctx->end_frame = ctx->frame + ctx->bytes_in_buffer;
100 ctx->have_frame = 1;
101 }
102 #else
103 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
104 "Cannot parse bitstream without CONFIG_THREE_PASS.");
105 #endif
106 Av1DecodeReturn adr;
107 if (aom_codec_decode(&ctx->decoder, ctx->frame,
108 (unsigned int)ctx->bytes_in_buffer,
109 &adr) != AOM_CODEC_OK) {
110 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
111 "Failed to decode frame for third pass.");
112 }
113 ctx->frame = adr.buf;
114 ctx->bytes_in_buffer = ctx->end_frame - ctx->frame;
115 if (ctx->frame == ctx->end_frame) ctx->have_frame = 0;
116 return 0;
117 }
118
119 // This function gets the information needed from the recently decoded frame,
120 // via various decoder APIs, and saves the info into ctx->frame_info.
121 // Return 0: success
122 // 1: cannot read because this is end of file
123 // -1: failure to read the frame
get_frame_info(THIRD_PASS_DEC_CTX * ctx)124 static int get_frame_info(THIRD_PASS_DEC_CTX *ctx) {
125 int ret = read_frame(ctx);
126 if (ret != 0) return ret;
127 int cur = ctx->frame_info_count;
128 if (cur >= MAX_THIRD_PASS_BUF) {
129 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
130 "Third pass frame info ran out of available slots.");
131 }
132 int frame_type_flags = 0;
133 if (aom_codec_control(&ctx->decoder, AOMD_GET_FRAME_FLAGS,
134 &frame_type_flags) != AOM_CODEC_OK) {
135 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
136 "Failed to read frame flags.");
137 }
138 if (frame_type_flags & AOM_FRAME_IS_KEY) {
139 ctx->frame_info[cur].frame_type = KEY_FRAME;
140 } else if (frame_type_flags & AOM_FRAME_IS_INTRAONLY) {
141 ctx->frame_info[cur].frame_type = INTRA_ONLY_FRAME;
142 } else if (frame_type_flags & AOM_FRAME_IS_SWITCH) {
143 ctx->frame_info[cur].frame_type = S_FRAME;
144 } else {
145 ctx->frame_info[cur].frame_type = INTER_FRAME;
146 }
147
148 // Get frame base q idx
149 if (aom_codec_control(&ctx->decoder, AOMD_GET_BASE_Q_IDX,
150 &ctx->frame_info[cur].base_q_idx) != AOM_CODEC_OK) {
151 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
152 "Failed to read base q index.");
153 }
154
155 // Get show existing frame flag
156 if (aom_codec_control(&ctx->decoder, AOMD_GET_SHOW_EXISTING_FRAME_FLAG,
157 &ctx->frame_info[cur].is_show_existing_frame) !=
158 AOM_CODEC_OK) {
159 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
160 "Failed to read show existing frame flag.");
161 }
162
163 // Get show frame flag
164 if (aom_codec_control(&ctx->decoder, AOMD_GET_SHOW_FRAME_FLAG,
165 &ctx->frame_info[cur].is_show_frame) != AOM_CODEC_OK) {
166 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
167 "Failed to read show frame flag.");
168 }
169
170 // Get order hint
171 if (aom_codec_control(&ctx->decoder, AOMD_GET_ORDER_HINT,
172 &ctx->frame_info[cur].order_hint) != AOM_CODEC_OK) {
173 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
174 "Failed to read order hint.");
175 }
176 ctx->frame_info_count++;
177 return 0;
178 }
179
180 // Parse the frames in the gop and determine the last frame of the current GOP.
181 // Decode more frames if necessary. The variable max_num is the maximum static
182 // GOP length if we detect an IPPP structure, and it is expected that max_mum >=
183 // MAX_GF_INTERVAL.
get_current_gop_end(THIRD_PASS_DEC_CTX * ctx,int max_num,int * last_idx)184 static void get_current_gop_end(THIRD_PASS_DEC_CTX *ctx, int max_num,
185 int *last_idx) {
186 assert(max_num >= MAX_GF_INTERVAL);
187 *last_idx = 0;
188 int cur_idx = 0;
189 int arf_order_hint = -1;
190 int num_show_frames = 0;
191 while (num_show_frames < max_num) {
192 assert(cur_idx < MAX_THIRD_PASS_BUF);
193 // Read in from bitstream if needed.
194 if (cur_idx >= ctx->frame_info_count) {
195 int ret = get_frame_info(ctx);
196 if (ret == 1) {
197 // At the end of the file, GOP ends in the prev frame.
198 if (arf_order_hint >= 0) {
199 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
200 "Failed to derive GOP length.");
201 }
202 *last_idx = cur_idx - 1;
203 return;
204 }
205 if (ret < 0) {
206 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
207 "Failed to read frame for third pass.");
208 }
209 }
210
211 // TODO(bohanli): verify that fwd_kf works here.
212 if (ctx->frame_info[cur_idx].frame_type == KEY_FRAME &&
213 ctx->frame_info[cur_idx].is_show_frame) {
214 if (cur_idx != 0) {
215 // If this is a key frame and is not the first kf in this kf group, we
216 // have reached the next key frame. Stop here.
217 *last_idx = cur_idx - 1;
218 return;
219 }
220 } else if (!ctx->frame_info[cur_idx].is_show_frame &&
221 arf_order_hint == -1) {
222 // If this is an arf (the first no show)
223 if (num_show_frames <= 1) {
224 // This is an arf and we should end the GOP with its overlay.
225 arf_order_hint = ctx->frame_info[cur_idx].order_hint;
226 } else {
227 // There are multiple show frames before the this arf, so we treat the
228 // frames previous to this arf as a GOP.
229 *last_idx = cur_idx - 1;
230 return;
231 }
232 } else if (arf_order_hint >= 0 && ctx->frame_info[cur_idx].order_hint ==
233 (unsigned int)arf_order_hint) {
234 // If this is the overlay/show existing of the arf
235 assert(ctx->frame_info[cur_idx].is_show_frame);
236 *last_idx = cur_idx;
237 return;
238 } else {
239 // This frame is part of the GOP.
240 if (ctx->frame_info[cur_idx].is_show_frame) num_show_frames++;
241 }
242 cur_idx++;
243 }
244 // This is a long IPPP GOP and we will use a length of max_num here.
245 assert(arf_order_hint < 0);
246 *last_idx = max_num - 1;
247 return;
248 }
249
av1_set_gop_third_pass(THIRD_PASS_DEC_CTX * ctx,GF_GROUP * gf_group,int order_hint_bits,int * gf_len)250 void av1_set_gop_third_pass(THIRD_PASS_DEC_CTX *ctx, GF_GROUP *gf_group,
251 int order_hint_bits, int *gf_len) {
252 // Read in future frames and find the last frame in the current GOP.
253 int last_idx;
254 get_current_gop_end(ctx, MAX_GF_INTERVAL, &last_idx);
255
256 // Determine the GOP length.
257 // TODO(bohanli): Define and set the GOP structure here. Then we also
258 // dont't need to store prev_gop_end here.
259 (void)gf_group;
260 if (last_idx < 0) {
261 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
262 "Failed to derive GOP length.");
263 }
264 *gf_len = ctx->frame_info[last_idx].order_hint - ctx->prev_gop_end;
265 *gf_len = (*gf_len + (1 << order_hint_bits)) % (1 << order_hint_bits);
266
267 ctx->prev_gop_end = ctx->frame_info[last_idx].order_hint;
268 }
269
av1_pop_third_pass_info(THIRD_PASS_DEC_CTX * ctx)270 void av1_pop_third_pass_info(THIRD_PASS_DEC_CTX *ctx) {
271 if (ctx->frame_info_count == 0) {
272 aom_internal_error(ctx->err_info, AOM_CODEC_ERROR,
273 "No available frame info for third pass.");
274 }
275 ctx->frame_info_count--;
276 for (int i = 0; i < ctx->frame_info_count; i++) {
277 ctx->frame_info[i] = ctx->frame_info[i + 1];
278 }
279 }
280
av1_init_thirdpass_ctx(AV1_COMMON * cm,THIRD_PASS_DEC_CTX ** ctx,const char * file)281 void av1_init_thirdpass_ctx(AV1_COMMON *cm, THIRD_PASS_DEC_CTX **ctx,
282 const char *file) {
283 av1_free_thirdpass_ctx(*ctx);
284 CHECK_MEM_ERROR(cm, *ctx, aom_calloc(1, sizeof(**ctx)));
285 THIRD_PASS_DEC_CTX *ctx_ptr = *ctx;
286 ctx_ptr->input_file_name = file;
287 ctx_ptr->prev_gop_end = -1;
288 ctx_ptr->err_info = cm->error;
289 }
290
av1_free_thirdpass_ctx(THIRD_PASS_DEC_CTX * ctx)291 void av1_free_thirdpass_ctx(THIRD_PASS_DEC_CTX *ctx) {
292 if (ctx == NULL) return;
293 if (ctx->decoder.iface) {
294 aom_codec_destroy(&ctx->decoder);
295 }
296 #if CONFIG_THREE_PASS
297 if (ctx->input_ctx && ctx->input_ctx->file) fclose(ctx->input_ctx->file);
298 aom_free(ctx->input_ctx);
299 #endif
300 if (ctx->buf) free(ctx->buf);
301 aom_free(ctx);
302 }
303