/work/svt-av1/Source/Lib/Codec/rest_process.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright(c) 2019 Intel Corporation |
3 | | * Copyright (c) 2016, Alliance for Open Media. All rights reserved |
4 | | * |
5 | | * This source code is subject to the terms of the BSD 2 Clause License and |
6 | | * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License |
7 | | * was not distributed with this source code in the LICENSE file, you can |
8 | | * obtain it at https://www.aomedia.org/license/software-license. If the Alliance for Open |
9 | | * Media Patent License 1.0 was not distributed with this source code in the |
10 | | * PATENTS file, you can obtain it at www.aomedia.org/license/patent. |
11 | | */ |
12 | | |
13 | | #include <stdlib.h> |
14 | | |
15 | | #include "enc_handle.h" |
16 | | #include "rest_process.h" |
17 | | #include "enc_dec_results.h" |
18 | | #include "svt_threads.h" |
19 | | #include "pic_demux_results.h" |
20 | | #include "reference_object.h" |
21 | | #include "pcs.h" |
22 | | #include "resource_coordination_process.h" |
23 | | #include "resize.h" |
24 | | #include "enc_mode_config.h" |
25 | | |
26 | | /************************************** |
27 | | * Rest Context |
28 | | **************************************/ |
29 | | typedef struct RestContext { |
30 | | EbDctor dctor; |
31 | | EbFifo* rest_input_fifo_ptr; |
32 | | EbFifo* rest_output_fifo_ptr; |
33 | | EbFifo* picture_demux_fifo_ptr; |
34 | | |
35 | | EbPictureBufferDesc* trial_frame_rst; |
36 | | |
37 | | EbPictureBufferDesc* org_rec_frame; |
38 | | // while doing the filtering recon gets updated using setup/restore processing_stripe_bounadaries |
39 | | // many threads doing the above will result in race condition. |
40 | | // each thread will hence have his own copy of recon to work on. |
41 | | // later we can have a search version that does not need the exact right recon |
42 | | int32_t* rst_tmpbuf; |
43 | | } RestContext; |
44 | | |
45 | | void svt_aom_recon_output(PictureControlSet* pcs, SequenceControlSet* scs); |
46 | | void svt_av1_loop_restoration_filter_frame(int32_t* rst_tmpbuf, Yv12BufferConfig* frame, Av1Common* cm, |
47 | | int32_t optimized_lr); |
48 | | EbErrorType psnr_calculations(PictureControlSet* pcs, SequenceControlSet* scs, bool free_memory); |
49 | | EbErrorType svt_aom_ssim_calculations(PictureControlSet* pcs, SequenceControlSet* scs, bool free_memory); |
50 | | void pad_ref_and_set_flags(PictureControlSet* pcs, SequenceControlSet* scs); |
51 | | void restoration_seg_search(int32_t* rst_tmpbuf, Yv12BufferConfig* org_fts, const Yv12BufferConfig* src, |
52 | | Yv12BufferConfig* trial_frame_rst, PictureControlSet* pcs, uint32_t segment_index); |
53 | | void rest_finish_search(PictureControlSet* pcs); |
54 | | |
55 | 474 | static void rest_context_dctor(EbPtr p) { |
56 | 474 | EbThreadContext* thread_ctx = (EbThreadContext*)p; |
57 | 474 | RestContext* obj = (RestContext*)thread_ctx->priv; |
58 | 474 | EB_DELETE(obj->trial_frame_rst); |
59 | | // buffer only malloc'd if boundaries are used in rest. search. |
60 | | // see scs->seq_header.use_boundaries_in_rest_search |
61 | 474 | if (obj->org_rec_frame) { |
62 | 0 | EB_DELETE(obj->org_rec_frame); |
63 | 0 | } |
64 | 474 | EB_FREE_ALIGNED(obj->rst_tmpbuf); |
65 | 474 | EB_FREE_ARRAY(obj); |
66 | 474 | } |
67 | | |
68 | | /****************************************************** |
69 | | * Rest Context Constructor |
70 | | ******************************************************/ |
71 | | EbErrorType svt_aom_rest_context_ctor(EbThreadContext* thread_ctx, const EbEncHandle* enc_handle_ptr, int index, |
72 | 474 | int demux_index) { |
73 | 474 | const SequenceControlSet* scs = enc_handle_ptr->scs_instance->scs; |
74 | 474 | const EbSvtAv1EncConfiguration* config = &scs->static_config; |
75 | 474 | RestContext* context_ptr; |
76 | 474 | const bool allintra = scs->allintra; |
77 | 474 | const bool rtc_tune = scs->static_config.rtc; |
78 | 474 | EB_CALLOC_ARRAY(context_ptr, 1); |
79 | 474 | thread_ctx->priv = context_ptr; |
80 | 474 | thread_ctx->dctor = rest_context_dctor; |
81 | | |
82 | | // Input/Output System Resource Manager FIFOs |
83 | 474 | context_ptr->rest_input_fifo_ptr = svt_system_resource_get_consumer_fifo(enc_handle_ptr->cdef_results_resource_ptr, |
84 | 474 | index); |
85 | 474 | context_ptr->rest_output_fifo_ptr = svt_system_resource_get_producer_fifo(enc_handle_ptr->rest_results_resource_ptr, |
86 | 474 | index); |
87 | 474 | context_ptr->picture_demux_fifo_ptr = svt_system_resource_get_producer_fifo( |
88 | 474 | enc_handle_ptr->picture_demux_results_resource_ptr, demux_index); |
89 | | |
90 | 474 | bool is_16bit = scs->is_16bit_pipeline; |
91 | 474 | uint8_t enable_restoration = allintra |
92 | 474 | ? svt_aom_get_enable_restoration_allintra(config->enc_mode, config->enable_restoration_filtering) |
93 | 474 | : rtc_tune |
94 | 0 | #if TUNE_SIMPLIFY_SETTINGS |
95 | 0 | ? svt_aom_get_enable_restoration_rtc( |
96 | 0 | config->enable_restoration_filtering, scs->input_resolution, config->fast_decode) |
97 | | #else |
98 | | ? svt_aom_get_enable_restoration_rtc( |
99 | | config->enc_mode, config->enable_restoration_filtering, scs->input_resolution, config->fast_decode) |
100 | | #endif |
101 | 0 | : svt_aom_get_enable_restoration_default( |
102 | 0 | config->enc_mode, config->enable_restoration_filtering, scs->input_resolution, config->fast_decode); |
103 | | |
104 | 474 | uint8_t enable_sg = allintra ? svt_aom_get_enable_sg_allintra() |
105 | 474 | #if TUNE_SIMPLIFY_SETTINGS |
106 | 474 | : rtc_tune ? svt_aom_get_enable_sg_rtc(scs->input_resolution, config->fast_decode) |
107 | | #else |
108 | | : rtc_tune ? svt_aom_get_enable_sg_rtc(config->enc_mode, scs->input_resolution, config->fast_decode) |
109 | | #endif |
110 | 0 | : svt_aom_get_enable_sg_default(config->enc_mode, scs->input_resolution, config->fast_decode); |
111 | | |
112 | 474 | if (enable_restoration) { |
113 | 0 | EbPictureBufferDescInitData init_data; |
114 | |
|
115 | 0 | init_data.buffer_enable_mask = PICTURE_BUFFER_DESC_FULL_MASK; |
116 | 0 | init_data.max_width = (uint16_t)scs->max_input_luma_width; |
117 | 0 | init_data.max_height = (uint16_t)scs->max_input_luma_height; |
118 | 0 | init_data.bit_depth = is_16bit ? EB_SIXTEEN_BIT : EB_EIGHT_BIT; |
119 | 0 | init_data.color_format = config->encoder_color_format; |
120 | 0 | init_data.border = AOM_RESTORATION_FRAME_BORDER; |
121 | 0 | init_data.split_mode = false; |
122 | 0 | init_data.is_16bit_pipeline = is_16bit; |
123 | |
|
124 | 0 | EB_NEW(context_ptr->trial_frame_rst, svt_picture_buffer_desc_ctor, (EbPtr)&init_data); |
125 | 0 | if (scs->use_boundaries_in_rest_search) { |
126 | 0 | EB_NEW(context_ptr->org_rec_frame, svt_picture_buffer_desc_ctor, (EbPtr)&init_data); |
127 | 0 | } else { |
128 | 0 | context_ptr->org_rec_frame = NULL; |
129 | 0 | } |
130 | 0 | if (!is_16bit) { |
131 | 0 | context_ptr->trial_frame_rst->bit_depth = EB_EIGHT_BIT; |
132 | 0 | if (scs->use_boundaries_in_rest_search) { |
133 | 0 | context_ptr->org_rec_frame->bit_depth = EB_EIGHT_BIT; |
134 | 0 | } |
135 | 0 | } |
136 | 0 | context_ptr->rst_tmpbuf = NULL; |
137 | |
|
138 | 0 | if (enable_sg) { |
139 | 0 | EB_MALLOC_ALIGNED(context_ptr->rst_tmpbuf, RESTORATION_TMPBUF_SIZE); |
140 | 0 | } |
141 | 0 | } |
142 | | |
143 | 474 | return EB_ErrorNone; |
144 | 474 | } |
145 | | |
146 | | // If using boundaries during the filter search, copy the recon pic to a new buffer (to |
147 | | // avoid race conidition from many threads modifying the same recon pic). |
148 | | // |
149 | | // If not using boundaries during the filter search, return the input recon picture location |
150 | | // to be used in restoration search (save cycles/memory of copying pic to a new buffer). |
151 | | // The recon pic should not be modified during the search, otherwise there will be a race |
152 | | // condition between threads. |
153 | | // |
154 | | // Return a pointer to the recon pic to be used during the restoration search. |
155 | | static EbPictureBufferDesc* get_own_recon(SequenceControlSet* scs, PictureControlSet* pcs, RestContext* context_ptr, |
156 | 0 | bool is_16bit) { |
157 | 0 | EbPictureBufferDesc* recon_pic; |
158 | 0 | svt_aom_get_recon_pic(pcs, &recon_pic, is_16bit); |
159 | | // if boundaries are not used, don't need to copy pic to new buffer, as the |
160 | | // search will not modify the pic |
161 | 0 | if (!scs->use_boundaries_in_rest_search) { |
162 | 0 | return recon_pic; |
163 | 0 | } |
164 | | |
165 | 0 | const uint32_t ss_x = scs->subsampling_x; |
166 | 0 | const uint32_t ss_y = scs->subsampling_y; |
167 | |
|
168 | 0 | EbPictureBufferDesc* org_rec = context_ptr->org_rec_frame; |
169 | |
|
170 | 0 | int org_stride_y = org_rec->y_stride << is_16bit; |
171 | 0 | int org_stride_cb = org_rec->u_stride << is_16bit; |
172 | 0 | int org_stride_cr = org_rec->v_stride << is_16bit; |
173 | |
|
174 | 0 | int rec_stride_y = recon_pic->y_stride << is_16bit; |
175 | 0 | int rec_stride_cb = recon_pic->u_stride << is_16bit; |
176 | 0 | int rec_stride_cr = recon_pic->v_stride << is_16bit; |
177 | |
|
178 | 0 | uint8_t* org_ptr = org_rec->y_buffer; |
179 | 0 | uint8_t* org_ptr_cb = org_rec->u_buffer; |
180 | 0 | uint8_t* org_ptr_cr = org_rec->v_buffer; |
181 | |
|
182 | 0 | uint8_t* rec_ptr = recon_pic->y_buffer; |
183 | 0 | uint8_t* rec_ptr_cb = recon_pic->u_buffer; |
184 | 0 | uint8_t* rec_ptr_cr = recon_pic->v_buffer; |
185 | |
|
186 | 0 | int rec_width = recon_pic->width << is_16bit; |
187 | |
|
188 | 0 | for (int r = 0; r < recon_pic->height; ++r) { |
189 | 0 | svt_memcpy(org_ptr + r * org_stride_y, rec_ptr + r * rec_stride_y, rec_width); |
190 | 0 | } |
191 | |
|
192 | 0 | for (int r = 0; r < (recon_pic->height >> ss_y); ++r) { |
193 | 0 | svt_memcpy(org_ptr_cb + r * org_stride_cb, rec_ptr_cb + r * rec_stride_cb, rec_width >> ss_x); |
194 | 0 | svt_memcpy(org_ptr_cr + r * org_stride_cr, rec_ptr_cr + r * rec_stride_cr, rec_width >> ss_x); |
195 | 0 | } |
196 | 0 | return org_rec; |
197 | 0 | } |
198 | | |
199 | 0 | static void copy_statistics_to_ref_obj_ect(PictureControlSet* pcs, SequenceControlSet* scs) { |
200 | 0 | PictureParentControlSet* ppcs = pcs->ppcs; |
201 | 0 | FrameHeader* frm_hdr = &ppcs->frm_hdr; |
202 | 0 | EbReferenceObject* obj = (EbReferenceObject*)ppcs->ref_pic_wrapper->object_ptr; |
203 | |
|
204 | 0 | obj->intra_coded_area = (uint8_t)pcs->intra_coded_area; |
205 | 0 | obj->skip_coded_area = (uint8_t)pcs->skip_coded_area; |
206 | 0 | obj->hp_coded_area = (uint8_t)pcs->hp_coded_area; |
207 | 0 | obj->is_mfmv_used = frm_hdr->use_ref_frame_mvs; |
208 | |
|
209 | 0 | obj->filter_level[0] = frm_hdr->loop_filter_params.filter_level[0]; |
210 | 0 | obj->filter_level[1] = frm_hdr->loop_filter_params.filter_level[1]; |
211 | 0 | obj->filter_level_u = frm_hdr->loop_filter_params.filter_level_u; |
212 | 0 | obj->filter_level_v = frm_hdr->loop_filter_params.filter_level_v; |
213 | 0 | obj->dlf_dist_dev = pcs->dlf_dist_dev; |
214 | 0 | obj->cdef_dist_dev = pcs->cdef_dist_dev; |
215 | |
|
216 | 0 | obj->ref_cdef_strengths_num = ppcs->nb_cdef_strengths; |
217 | 0 | for (int i = 0; i < ppcs->nb_cdef_strengths; i++) { |
218 | 0 | obj->ref_cdef_strengths[0][i] = frm_hdr->cdef_params.cdef_y_strength[i]; |
219 | 0 | obj->ref_cdef_strengths[1][i] = frm_hdr->cdef_params.cdef_uv_strength[i]; |
220 | 0 | } |
221 | 0 | uint32_t sb_index; |
222 | 0 | for (sb_index = 0; sb_index < pcs->b64_total_count; ++sb_index) { |
223 | 0 | obj->sb_intra[sb_index] = pcs->sb_intra[sb_index]; |
224 | 0 | obj->sb_skip[sb_index] = pcs->sb_skip[sb_index]; |
225 | 0 | obj->sb_64x64_mvp[sb_index] = pcs->sb_64x64_mvp[sb_index]; |
226 | 0 | obj->sb_me_64x64_dist[sb_index] = ppcs->me_64x64_distortion[sb_index]; |
227 | 0 | obj->sb_me_8x8_cost_var[sb_index] = ppcs->me_8x8_cost_variance[sb_index]; |
228 | 0 | obj->sb_min_sq_size[sb_index] = pcs->sb_min_sq_size[sb_index]; |
229 | 0 | obj->sb_max_sq_size[sb_index] = pcs->sb_max_sq_size[sb_index]; |
230 | 0 | } |
231 | 0 | obj->tmp_layer_idx = pcs->temporal_layer_index; |
232 | 0 | obj->is_scene_change = ppcs->scene_change_flag; |
233 | |
|
234 | 0 | Av1Common* cm = ppcs->av1_cm; |
235 | 0 | if (scs->mfmv_enabled || !ppcs->is_not_scaled) { |
236 | 0 | obj->frame_type = frm_hdr->frame_type; |
237 | 0 | obj->order_hint = ppcs->cur_order_hint; |
238 | 0 | svt_memcpy(obj->ref_order_hint, ppcs->ref_order_hint, sizeof(obj->ref_order_hint)); |
239 | 0 | } |
240 | | // Copy the prev frame wn filter coeffs |
241 | 0 | if (cm->wn_filter_ctrls.enabled && cm->wn_filter_ctrls.use_prev_frame_coeffs) { |
242 | 0 | for (int32_t plane = 0; plane < MAX_PLANES; ++plane) { |
243 | 0 | int32_t ntiles = pcs->rst_info[plane].units_per_tile; |
244 | 0 | for (int32_t u = 0; u < ntiles; ++u) { |
245 | 0 | obj->unit_info[plane][u].restoration_type = pcs->rst_info[plane].unit_info[u].restoration_type; |
246 | 0 | if (pcs->rst_info[plane].unit_info[u].restoration_type == RESTORE_WIENER) { |
247 | 0 | obj->unit_info[plane][u].wiener_info = pcs->rst_info[plane].unit_info[u].wiener_info; |
248 | 0 | } |
249 | 0 | } |
250 | 0 | } |
251 | 0 | } |
252 | 0 | } |
253 | | |
254 | | /****************************************************** |
255 | | * Rest Kernel |
256 | | ******************************************************/ |
257 | 948 | EbErrorType svt_aom_rest_kernel_iter(void* context) { |
258 | 948 | RestContext* context_ptr = (RestContext*)context; |
259 | | |
260 | | // Get Cdef Results |
261 | 948 | EbObjectWrapper* cdef_results_wrapper; |
262 | 948 | EB_GET_FULL_OBJECT(context_ptr->rest_input_fifo_ptr, &cdef_results_wrapper); |
263 | | |
264 | 474 | CdefResults* cdef_results = (CdefResults*)cdef_results_wrapper->object_ptr; |
265 | 474 | PictureControlSet* pcs = (PictureControlSet*)cdef_results->pcs_wrapper->object_ptr; |
266 | 474 | PictureParentControlSet* ppcs = pcs->ppcs; |
267 | 474 | SequenceControlSet* scs = pcs->scs; |
268 | 474 | FrameHeader* frm_hdr = &ppcs->frm_hdr; |
269 | 474 | bool is_16bit = scs->is_16bit_pipeline; |
270 | 474 | Av1Common* cm = ppcs->av1_cm; |
271 | 474 | if (ppcs->enable_restoration && frm_hdr->allow_intrabc == 0) { |
272 | | // If using boundaries during the filter search, copy the recon pic to a new buffer (to |
273 | | // avoid race condition from many threads modifying the same recon pic). |
274 | | // |
275 | | // If not using boundaries during the filter search, copy the input recon picture |
276 | | // location to be used in restoration search (save cycles/memory of copying pic to a new |
277 | | // buffer). The recon pic should not be modified during the search, otherwise there will |
278 | | // be a race condition between threads. |
279 | 0 | EbPictureBufferDesc* recon_pic = get_own_recon(scs, pcs, context_ptr, is_16bit); |
280 | 0 | EbPictureBufferDesc* input_pic = is_16bit ? pcs->input_frame16bit : ppcs->enhanced_unscaled_pic; |
281 | | |
282 | | // downscale input picture if recon is resized |
283 | 0 | bool is_resized = recon_pic->width != input_pic->width || recon_pic->height != input_pic->height; |
284 | 0 | if (is_resized) { |
285 | 0 | input_pic = pcs->scaled_input_pic; |
286 | 0 | } |
287 | | |
288 | | // there are padding pixels if input pics are not 8 pixel aligned |
289 | | // but there is no extra padding after input pics are resized for |
290 | | // reference scaling |
291 | 0 | Yv12BufferConfig cpi_source; |
292 | 0 | svt_aom_link_eb_to_aom_buffer_desc(input_pic, |
293 | 0 | &cpi_source, |
294 | 0 | is_resized ? 0 : scs->max_input_pad_right, |
295 | 0 | is_resized ? 0 : scs->max_input_pad_bottom, |
296 | 0 | is_16bit); |
297 | |
|
298 | 0 | Yv12BufferConfig trial_frame_rst; |
299 | 0 | svt_aom_link_eb_to_aom_buffer_desc(context_ptr->trial_frame_rst, |
300 | 0 | &trial_frame_rst, |
301 | 0 | is_resized ? 0 : scs->max_input_pad_right, |
302 | 0 | is_resized ? 0 : scs->max_input_pad_bottom, |
303 | 0 | is_16bit); |
304 | |
|
305 | 0 | Yv12BufferConfig org_fts; |
306 | 0 | svt_aom_link_eb_to_aom_buffer_desc(recon_pic, |
307 | 0 | &org_fts, |
308 | 0 | is_resized ? 0 : scs->max_input_pad_right, |
309 | 0 | is_resized ? 0 : scs->max_input_pad_bottom, |
310 | 0 | is_16bit); |
311 | |
|
312 | 0 | if (ppcs->slice_type != I_SLICE && cm->wn_filter_ctrls.enabled && cm->wn_filter_ctrls.use_prev_frame_coeffs) { |
313 | 0 | EbReferenceObject* ref_obj_l0 = (EbReferenceObject*)pcs->ref_pic_ptr_array[REF_LIST_0][0]->object_ptr; |
314 | 0 | for (int32_t plane = 0; plane < MAX_PLANES; ++plane) { |
315 | 0 | int32_t ntiles = pcs->rst_info[plane].units_per_tile; |
316 | 0 | for (int32_t u = 0; u < ntiles; ++u) { |
317 | 0 | pcs->rst_info[plane].unit_info[u].restoration_type = |
318 | 0 | ref_obj_l0->unit_info[plane][u].restoration_type; |
319 | 0 | if (ref_obj_l0->unit_info[plane][u].restoration_type == RESTORE_WIENER) { |
320 | 0 | pcs->rst_info[plane].unit_info[u].wiener_info = ref_obj_l0->unit_info[plane][u].wiener_info; |
321 | 0 | } |
322 | 0 | } |
323 | 0 | } |
324 | 0 | } |
325 | 0 | restoration_seg_search( |
326 | 0 | context_ptr->rst_tmpbuf, &org_fts, &cpi_source, &trial_frame_rst, pcs, cdef_results->segment_index); |
327 | 0 | } |
328 | | |
329 | | //all seg based search is done. update total processed segments. if all done, finish the search and perfrom application. |
330 | 474 | svt_block_on_mutex(pcs->rest_search_mutex); |
331 | | |
332 | 474 | pcs->tot_seg_searched_rest++; |
333 | 474 | if (pcs->tot_seg_searched_rest == pcs->rest_segments_total_count) { |
334 | 474 | if (ppcs->enable_restoration && frm_hdr->allow_intrabc == 0) { |
335 | 0 | rest_finish_search(pcs); |
336 | | |
337 | | // Only need recon if REF pic or recon is output |
338 | 0 | if (ppcs->is_ref || scs->static_config.recon_enabled) { |
339 | 0 | if (pcs->rst_info[0].frame_restoration_type != RESTORE_NONE || |
340 | 0 | pcs->rst_info[1].frame_restoration_type != RESTORE_NONE || |
341 | 0 | pcs->rst_info[2].frame_restoration_type != RESTORE_NONE) { |
342 | 0 | svt_av1_loop_restoration_filter_frame(context_ptr->rst_tmpbuf, cm->frame_to_show, cm, 0); |
343 | 0 | } |
344 | 0 | } |
345 | 474 | } else { |
346 | 474 | pcs->rst_info[0].frame_restoration_type = RESTORE_NONE; |
347 | 474 | pcs->rst_info[1].frame_restoration_type = RESTORE_NONE; |
348 | 474 | pcs->rst_info[2].frame_restoration_type = RESTORE_NONE; |
349 | 474 | } |
350 | | |
351 | | // delete scaled_input_pic after lr finished |
352 | 474 | EB_DELETE(pcs->scaled_input_pic); |
353 | | |
354 | | // normalize stats - RC uses these even for non-ref frames |
355 | 474 | int num_pixels = ppcs->aligned_width * ppcs->aligned_height; |
356 | 474 | pcs->intra_coded_area = (pcs->slice_type == I_SLICE) ? 0 : 100 * pcs->intra_coded_area / num_pixels; |
357 | 474 | pcs->skip_coded_area = 100 * pcs->skip_coded_area / num_pixels; |
358 | 474 | pcs->hp_coded_area = 100 * pcs->hp_coded_area / num_pixels; |
359 | 474 | pcs->avg_cnt_zeromv = 100 * pcs->avg_cnt_zeromv / num_pixels; |
360 | | |
361 | 474 | if (ppcs->ref_pic_wrapper != NULL) { |
362 | | // copy stat to ref object (intra_coded_area, Luminance, Scene change detection |
363 | | // flags) |
364 | 0 | copy_statistics_to_ref_obj_ect(pcs, scs); |
365 | 0 | } |
366 | | |
367 | 474 | bool superres_recode = ppcs->superres_total_recode_loop > 0 ? true : false; |
368 | | |
369 | | // Pad the reference picture and set ref POC |
370 | 474 | { |
371 | 474 | if (ppcs->is_ref == true) { |
372 | 0 | pad_ref_and_set_flags(pcs, scs); |
373 | 474 | } else { |
374 | | // convert non-reference frame buffer from 16-bit to 8-bit, to export recon and |
375 | | // psnr/ssim calculation |
376 | 474 | if (is_16bit && scs->static_config.encoder_bit_depth == EB_EIGHT_BIT) { |
377 | 0 | EbPictureBufferDesc* ref_pic_ptr = ppcs->enc_dec_ptr->recon_pic; |
378 | 0 | EbPictureBufferDesc* ref_pic_16bit_ptr = ppcs->enc_dec_ptr->recon_pic_16bit; |
379 | | // Y |
380 | 0 | uint16_t* buf_16bit = (uint16_t*)(ref_pic_16bit_ptr->y_buffer) - |
381 | 0 | (ref_pic_16bit_ptr->border + (ref_pic_16bit_ptr->border * ref_pic_16bit_ptr->y_stride)); |
382 | 0 | uint8_t* buf_8bit = ref_pic_ptr->y_buffer - |
383 | 0 | (ref_pic_ptr->border + (ref_pic_ptr->border * ref_pic_ptr->y_stride)); |
384 | 0 | svt_convert_16bit_to_8bit(buf_16bit, |
385 | 0 | ref_pic_16bit_ptr->y_stride, |
386 | 0 | buf_8bit, |
387 | 0 | ref_pic_ptr->y_stride, |
388 | 0 | ref_pic_16bit_ptr->width + (ref_pic_ptr->border << 1), |
389 | 0 | ref_pic_16bit_ptr->height + (ref_pic_ptr->border << 1)); |
390 | | |
391 | | //CB |
392 | 0 | buf_16bit = (uint16_t*)(ref_pic_16bit_ptr->u_buffer) - |
393 | 0 | ((ref_pic_16bit_ptr->border >> scs->subsampling_x) + |
394 | 0 | ((ref_pic_16bit_ptr->border >> scs->subsampling_y) * ref_pic_16bit_ptr->u_stride)); |
395 | 0 | buf_8bit = ref_pic_ptr->u_buffer - |
396 | 0 | ((ref_pic_ptr->border >> scs->subsampling_x) + |
397 | 0 | ((ref_pic_ptr->border >> scs->subsampling_y) * ref_pic_ptr->u_stride)); |
398 | 0 | svt_convert_16bit_to_8bit( |
399 | 0 | buf_16bit, |
400 | 0 | ref_pic_16bit_ptr->u_stride, |
401 | 0 | buf_8bit, |
402 | 0 | ref_pic_ptr->u_stride, |
403 | 0 | (ref_pic_16bit_ptr->width + (ref_pic_ptr->border << 1)) >> scs->subsampling_x, |
404 | 0 | (ref_pic_16bit_ptr->height + (ref_pic_ptr->border << 1)) >> scs->subsampling_y); |
405 | | |
406 | | //CR |
407 | 0 | buf_16bit = (uint16_t*)(ref_pic_16bit_ptr->v_buffer) - |
408 | 0 | ((ref_pic_16bit_ptr->border >> scs->subsampling_x) + |
409 | 0 | ((ref_pic_16bit_ptr->border >> scs->subsampling_y) * ref_pic_16bit_ptr->v_stride)); |
410 | 0 | buf_8bit = ref_pic_ptr->v_buffer - |
411 | 0 | ((ref_pic_ptr->border >> scs->subsampling_x) + |
412 | 0 | ((ref_pic_ptr->border >> scs->subsampling_y) * ref_pic_ptr->v_stride)); |
413 | 0 | svt_convert_16bit_to_8bit( |
414 | 0 | buf_16bit, |
415 | 0 | ref_pic_16bit_ptr->v_stride, |
416 | 0 | buf_8bit, |
417 | 0 | ref_pic_ptr->v_stride, |
418 | 0 | (ref_pic_16bit_ptr->width + (ref_pic_ptr->border << 1)) >> scs->subsampling_x, |
419 | 0 | (ref_pic_16bit_ptr->height + (ref_pic_ptr->border << 1)) >> scs->subsampling_y); |
420 | 0 | } |
421 | 474 | } |
422 | 474 | } |
423 | | |
424 | | // PSNR and SSIM Calculation. |
425 | 474 | if (superres_recode) { // superres needs psnr to compute rdcost |
426 | | // Note: if superres recode is actived, memory needs to be freed in packetization process by calling free_temporal_filtering_buffer() |
427 | 0 | EbErrorType return_error = psnr_calculations(pcs, scs, false); |
428 | 0 | if (return_error != EB_ErrorNone) { |
429 | 0 | svt_aom_assert_err(0, |
430 | 0 | "Couldn't allocate memory for uncompressed 10bit buffers for PSNR " |
431 | 0 | "calculations"); |
432 | 0 | } |
433 | 474 | } else { |
434 | 474 | EbErrorType return_error; |
435 | 474 | if (pcs->ppcs->compute_psnr) { |
436 | | // Note: if temporal_filtering is used, memory needs to be freed in the last of these calls |
437 | 0 | return_error = psnr_calculations(pcs, scs, !pcs->ppcs->compute_ssim); |
438 | 0 | if (return_error != EB_ErrorNone) { |
439 | 0 | svt_aom_assert_err(0, |
440 | 0 | "Couldn't allocate memory for uncompressed 10bit buffers for PSNR " |
441 | 0 | "calculations"); |
442 | 0 | } |
443 | 0 | } |
444 | 474 | if (pcs->ppcs->compute_ssim) { |
445 | 0 | return_error = svt_aom_ssim_calculations(pcs, scs, true /* free memory here */); |
446 | 0 | if (return_error != EB_ErrorNone) { |
447 | 0 | svt_aom_assert_err(0, |
448 | 0 | "Couldn't allocate memory for uncompressed 10bit buffers for SSIM " |
449 | 0 | "calculations"); |
450 | 0 | } |
451 | 0 | } |
452 | 474 | } |
453 | | |
454 | 474 | if (!superres_recode) { |
455 | 474 | if (scs->static_config.recon_enabled) { |
456 | 0 | svt_aom_recon_output(pcs, scs); |
457 | 0 | } |
458 | | // post reference picture task in packetization process if it's superres_recode |
459 | 474 | if (ppcs->is_ref) { |
460 | | // Get Empty PicMgr Results |
461 | 0 | EbObjectWrapper* picture_demux_results_wrapper_ptr; |
462 | 0 | svt_get_empty_object(context_ptr->picture_demux_fifo_ptr, &picture_demux_results_wrapper_ptr); |
463 | |
|
464 | 0 | PictureDemuxResults* picture_demux_results_rtr = (PictureDemuxResults*) |
465 | 0 | picture_demux_results_wrapper_ptr->object_ptr; |
466 | 0 | picture_demux_results_rtr->ref_pic_wrapper = ppcs->ref_pic_wrapper; |
467 | 0 | picture_demux_results_rtr->scs = pcs->scs; |
468 | 0 | picture_demux_results_rtr->picture_number = pcs->picture_number; |
469 | 0 | picture_demux_results_rtr->picture_type = EB_PIC_REFERENCE; |
470 | | |
471 | | // Post Reference Picture |
472 | 0 | svt_post_full_object(picture_demux_results_wrapper_ptr); |
473 | 0 | } |
474 | 474 | } |
475 | | |
476 | 474 | int tile_cols = ppcs->av1_cm->tiles_info.tile_cols; |
477 | 474 | int tile_rows = ppcs->av1_cm->tiles_info.tile_rows; |
478 | | |
479 | 1.99k | for (int tile_row_idx = 0; tile_row_idx < tile_rows; tile_row_idx++) { |
480 | 6.51k | for (int tile_col_idx = 0; tile_col_idx < tile_cols; tile_col_idx++) { |
481 | 4.99k | const int tile_idx = tile_row_idx * tile_cols + tile_col_idx; |
482 | 4.99k | EbObjectWrapper* rest_results_wrapper; |
483 | 4.99k | svt_get_empty_object(context_ptr->rest_output_fifo_ptr, &rest_results_wrapper); |
484 | 4.99k | RestResults* rest_results = (RestResults*)rest_results_wrapper->object_ptr; |
485 | 4.99k | rest_results->pcs_wrapper = cdef_results->pcs_wrapper; |
486 | 4.99k | rest_results->tile_index = tile_idx; |
487 | | // Post Rest Results |
488 | 4.99k | svt_post_full_object(rest_results_wrapper); |
489 | 4.99k | } |
490 | 1.51k | } |
491 | 474 | } |
492 | 474 | svt_release_mutex(pcs->rest_search_mutex); |
493 | | |
494 | | // Release input Results |
495 | 474 | svt_release_object(cdef_results_wrapper); |
496 | 474 | return EB_ErrorNone; |
497 | 948 | } |
498 | | |
499 | 474 | void* svt_aom_rest_kernel(void* input_ptr) { |
500 | 474 | EbThreadContext* thread_ctx = (EbThreadContext*)input_ptr; |
501 | 948 | for (;;) { |
502 | 948 | EbErrorType err = svt_aom_rest_kernel_iter(thread_ctx->priv); |
503 | 948 | if (err == EB_NoErrorFifoShutdown) { |
504 | 474 | return NULL; |
505 | 474 | } |
506 | 948 | } |
507 | 0 | return NULL; |
508 | 474 | } |