• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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