|
1 /* |
|
2 * Copyright (c) 2012 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 |
|
12 /* MFQE: Multiframe Quality Enhancement |
|
13 * In rate limited situations keyframes may cause significant visual artifacts |
|
14 * commonly referred to as "popping." This file implements a postproccesing |
|
15 * algorithm which blends data from the preceeding frame when there is no |
|
16 * motion and the q from the previous frame is lower which indicates that it is |
|
17 * higher quality. |
|
18 */ |
|
19 |
|
20 #include "postproc.h" |
|
21 #include "variance.h" |
|
22 #include "vpx_mem/vpx_mem.h" |
|
23 #include "vp8_rtcd.h" |
|
24 #include "vpx_scale/yv12config.h" |
|
25 |
|
26 #include <limits.h> |
|
27 #include <stdlib.h> |
|
28 |
|
29 static void filter_by_weight(unsigned char *src, int src_stride, |
|
30 unsigned char *dst, int dst_stride, |
|
31 int block_size, int src_weight) |
|
32 { |
|
33 int dst_weight = (1 << MFQE_PRECISION) - src_weight; |
|
34 int rounding_bit = 1 << (MFQE_PRECISION - 1); |
|
35 int r, c; |
|
36 |
|
37 for (r = 0; r < block_size; r++) |
|
38 { |
|
39 for (c = 0; c < block_size; c++) |
|
40 { |
|
41 dst[c] = (src[c] * src_weight + |
|
42 dst[c] * dst_weight + |
|
43 rounding_bit) >> MFQE_PRECISION; |
|
44 } |
|
45 src += src_stride; |
|
46 dst += dst_stride; |
|
47 } |
|
48 } |
|
49 |
|
50 void vp8_filter_by_weight16x16_c(unsigned char *src, int src_stride, |
|
51 unsigned char *dst, int dst_stride, |
|
52 int src_weight) |
|
53 { |
|
54 filter_by_weight(src, src_stride, dst, dst_stride, 16, src_weight); |
|
55 } |
|
56 |
|
57 void vp8_filter_by_weight8x8_c(unsigned char *src, int src_stride, |
|
58 unsigned char *dst, int dst_stride, |
|
59 int src_weight) |
|
60 { |
|
61 filter_by_weight(src, src_stride, dst, dst_stride, 8, src_weight); |
|
62 } |
|
63 |
|
64 void vp8_filter_by_weight4x4_c(unsigned char *src, int src_stride, |
|
65 unsigned char *dst, int dst_stride, |
|
66 int src_weight) |
|
67 { |
|
68 filter_by_weight(src, src_stride, dst, dst_stride, 4, src_weight); |
|
69 } |
|
70 |
|
71 static void apply_ifactor(unsigned char *y_src, |
|
72 int y_src_stride, |
|
73 unsigned char *y_dst, |
|
74 int y_dst_stride, |
|
75 unsigned char *u_src, |
|
76 unsigned char *v_src, |
|
77 int uv_src_stride, |
|
78 unsigned char *u_dst, |
|
79 unsigned char *v_dst, |
|
80 int uv_dst_stride, |
|
81 int block_size, |
|
82 int src_weight) |
|
83 { |
|
84 if (block_size == 16) |
|
85 { |
|
86 vp8_filter_by_weight16x16(y_src, y_src_stride, y_dst, y_dst_stride, src_weight); |
|
87 vp8_filter_by_weight8x8(u_src, uv_src_stride, u_dst, uv_dst_stride, src_weight); |
|
88 vp8_filter_by_weight8x8(v_src, uv_src_stride, v_dst, uv_dst_stride, src_weight); |
|
89 } |
|
90 else /* if (block_size == 8) */ |
|
91 { |
|
92 vp8_filter_by_weight8x8(y_src, y_src_stride, y_dst, y_dst_stride, src_weight); |
|
93 vp8_filter_by_weight4x4(u_src, uv_src_stride, u_dst, uv_dst_stride, src_weight); |
|
94 vp8_filter_by_weight4x4(v_src, uv_src_stride, v_dst, uv_dst_stride, src_weight); |
|
95 } |
|
96 } |
|
97 |
|
98 static unsigned int int_sqrt(unsigned int x) |
|
99 { |
|
100 unsigned int y = x; |
|
101 unsigned int guess; |
|
102 int p = 1; |
|
103 while (y>>=1) p++; |
|
104 p>>=1; |
|
105 |
|
106 guess=0; |
|
107 while (p>=0) |
|
108 { |
|
109 guess |= (1<<p); |
|
110 if (x<guess*guess) |
|
111 guess -= (1<<p); |
|
112 p--; |
|
113 } |
|
114 /* choose between guess or guess+1 */ |
|
115 return guess+(guess*guess+guess+1<=x); |
|
116 } |
|
117 |
|
118 #define USE_SSD |
|
119 static void multiframe_quality_enhance_block |
|
120 ( |
|
121 int blksize, /* Currently only values supported are 16, 8 */ |
|
122 int qcurr, |
|
123 int qprev, |
|
124 unsigned char *y, |
|
125 unsigned char *u, |
|
126 unsigned char *v, |
|
127 int y_stride, |
|
128 int uv_stride, |
|
129 unsigned char *yd, |
|
130 unsigned char *ud, |
|
131 unsigned char *vd, |
|
132 int yd_stride, |
|
133 int uvd_stride |
|
134 ) |
|
135 { |
|
136 static const unsigned char VP8_ZEROS[16]= |
|
137 { |
|
138 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 |
|
139 }; |
|
140 int uvblksize = blksize >> 1; |
|
141 int qdiff = qcurr - qprev; |
|
142 |
|
143 int i; |
|
144 unsigned char *up; |
|
145 unsigned char *udp; |
|
146 unsigned char *vp; |
|
147 unsigned char *vdp; |
|
148 |
|
149 unsigned int act, actd, sad, usad, vsad, sse, thr, thrsq, actrisk; |
|
150 |
|
151 if (blksize == 16) |
|
152 { |
|
153 actd = (vp8_variance16x16(yd, yd_stride, VP8_ZEROS, 0, &sse)+128)>>8; |
|
154 act = (vp8_variance16x16(y, y_stride, VP8_ZEROS, 0, &sse)+128)>>8; |
|
155 #ifdef USE_SSD |
|
156 sad = (vp8_variance16x16(y, y_stride, yd, yd_stride, &sse)); |
|
157 sad = (sse + 128)>>8; |
|
158 usad = (vp8_variance8x8(u, uv_stride, ud, uvd_stride, &sse)); |
|
159 usad = (sse + 32)>>6; |
|
160 vsad = (vp8_variance8x8(v, uv_stride, vd, uvd_stride, &sse)); |
|
161 vsad = (sse + 32)>>6; |
|
162 #else |
|
163 sad = (vp8_sad16x16(y, y_stride, yd, yd_stride, UINT_MAX) + 128) >> 8; |
|
164 usad = (vp8_sad8x8(u, uv_stride, ud, uvd_stride, UINT_MAX) + 32) >> 6; |
|
165 vsad = (vp8_sad8x8(v, uv_stride, vd, uvd_stride, UINT_MAX)+ 32) >> 6; |
|
166 #endif |
|
167 } |
|
168 else /* if (blksize == 8) */ |
|
169 { |
|
170 actd = (vp8_variance8x8(yd, yd_stride, VP8_ZEROS, 0, &sse)+32)>>6; |
|
171 act = (vp8_variance8x8(y, y_stride, VP8_ZEROS, 0, &sse)+32)>>6; |
|
172 #ifdef USE_SSD |
|
173 sad = (vp8_variance8x8(y, y_stride, yd, yd_stride, &sse)); |
|
174 sad = (sse + 32)>>6; |
|
175 usad = (vp8_variance4x4(u, uv_stride, ud, uvd_stride, &sse)); |
|
176 usad = (sse + 8)>>4; |
|
177 vsad = (vp8_variance4x4(v, uv_stride, vd, uvd_stride, &sse)); |
|
178 vsad = (sse + 8)>>4; |
|
179 #else |
|
180 sad = (vp8_sad8x8(y, y_stride, yd, yd_stride, UINT_MAX) + 32) >> 6; |
|
181 usad = (vp8_sad4x4(u, uv_stride, ud, uvd_stride, UINT_MAX) + 8) >> 4; |
|
182 vsad = (vp8_sad4x4(v, uv_stride, vd, uvd_stride, UINT_MAX) + 8) >> 4; |
|
183 #endif |
|
184 } |
|
185 |
|
186 actrisk = (actd > act * 5); |
|
187 |
|
188 /* thr = qdiff/16 + log2(act) + log4(qprev) */ |
|
189 thr = (qdiff >> 4); |
|
190 while (actd >>= 1) thr++; |
|
191 while (qprev >>= 2) thr++; |
|
192 |
|
193 #ifdef USE_SSD |
|
194 thrsq = thr * thr; |
|
195 if (sad < thrsq && |
|
196 /* additional checks for color mismatch and excessive addition of |
|
197 * high-frequencies */ |
|
198 4 * usad < thrsq && 4 * vsad < thrsq && !actrisk) |
|
199 #else |
|
200 if (sad < thr && |
|
201 /* additional checks for color mismatch and excessive addition of |
|
202 * high-frequencies */ |
|
203 2 * usad < thr && 2 * vsad < thr && !actrisk) |
|
204 #endif |
|
205 { |
|
206 int ifactor; |
|
207 #ifdef USE_SSD |
|
208 /* TODO: optimize this later to not need sqr root */ |
|
209 sad = int_sqrt(sad); |
|
210 #endif |
|
211 ifactor = (sad << MFQE_PRECISION) / thr; |
|
212 ifactor >>= (qdiff >> 5); |
|
213 |
|
214 if (ifactor) |
|
215 { |
|
216 apply_ifactor(y, y_stride, yd, yd_stride, |
|
217 u, v, uv_stride, |
|
218 ud, vd, uvd_stride, |
|
219 blksize, ifactor); |
|
220 } |
|
221 } |
|
222 else /* else implicitly copy from previous frame */ |
|
223 { |
|
224 if (blksize == 16) |
|
225 { |
|
226 vp8_copy_mem16x16(y, y_stride, yd, yd_stride); |
|
227 vp8_copy_mem8x8(u, uv_stride, ud, uvd_stride); |
|
228 vp8_copy_mem8x8(v, uv_stride, vd, uvd_stride); |
|
229 } |
|
230 else /* if (blksize == 8) */ |
|
231 { |
|
232 vp8_copy_mem8x8(y, y_stride, yd, yd_stride); |
|
233 for (up = u, udp = ud, i = 0; i < uvblksize; ++i, up += uv_stride, udp += uvd_stride) |
|
234 vpx_memcpy(udp, up, uvblksize); |
|
235 for (vp = v, vdp = vd, i = 0; i < uvblksize; ++i, vp += uv_stride, vdp += uvd_stride) |
|
236 vpx_memcpy(vdp, vp, uvblksize); |
|
237 } |
|
238 } |
|
239 } |
|
240 |
|
241 static int qualify_inter_mb(const MODE_INFO *mode_info_context, int *map) |
|
242 { |
|
243 if (mode_info_context->mbmi.mb_skip_coeff) |
|
244 map[0] = map[1] = map[2] = map[3] = 1; |
|
245 else if (mode_info_context->mbmi.mode==SPLITMV) |
|
246 { |
|
247 static int ndx[4][4] = |
|
248 { |
|
249 {0, 1, 4, 5}, |
|
250 {2, 3, 6, 7}, |
|
251 {8, 9, 12, 13}, |
|
252 {10, 11, 14, 15} |
|
253 }; |
|
254 int i, j; |
|
255 for (i=0; i<4; ++i) |
|
256 { |
|
257 map[i] = 1; |
|
258 for (j=0; j<4 && map[j]; ++j) |
|
259 map[i] &= (mode_info_context->bmi[ndx[i][j]].mv.as_mv.row <= 2 && |
|
260 mode_info_context->bmi[ndx[i][j]].mv.as_mv.col <= 2); |
|
261 } |
|
262 } |
|
263 else |
|
264 { |
|
265 map[0] = map[1] = map[2] = map[3] = |
|
266 (mode_info_context->mbmi.mode > B_PRED && |
|
267 abs(mode_info_context->mbmi.mv.as_mv.row) <= 2 && |
|
268 abs(mode_info_context->mbmi.mv.as_mv.col) <= 2); |
|
269 } |
|
270 return (map[0]+map[1]+map[2]+map[3]); |
|
271 } |
|
272 |
|
273 void vp8_multiframe_quality_enhance |
|
274 ( |
|
275 VP8_COMMON *cm |
|
276 ) |
|
277 { |
|
278 YV12_BUFFER_CONFIG *show = cm->frame_to_show; |
|
279 YV12_BUFFER_CONFIG *dest = &cm->post_proc_buffer; |
|
280 |
|
281 FRAME_TYPE frame_type = cm->frame_type; |
|
282 /* Point at base of Mb MODE_INFO list has motion vectors etc */ |
|
283 const MODE_INFO *mode_info_context = cm->show_frame_mi; |
|
284 int mb_row; |
|
285 int mb_col; |
|
286 int totmap, map[4]; |
|
287 int qcurr = cm->base_qindex; |
|
288 int qprev = cm->postproc_state.last_base_qindex; |
|
289 |
|
290 unsigned char *y_ptr, *u_ptr, *v_ptr; |
|
291 unsigned char *yd_ptr, *ud_ptr, *vd_ptr; |
|
292 |
|
293 /* Set up the buffer pointers */ |
|
294 y_ptr = show->y_buffer; |
|
295 u_ptr = show->u_buffer; |
|
296 v_ptr = show->v_buffer; |
|
297 yd_ptr = dest->y_buffer; |
|
298 ud_ptr = dest->u_buffer; |
|
299 vd_ptr = dest->v_buffer; |
|
300 |
|
301 /* postprocess each macro block */ |
|
302 for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) |
|
303 { |
|
304 for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) |
|
305 { |
|
306 /* if motion is high there will likely be no benefit */ |
|
307 if (frame_type == INTER_FRAME) totmap = qualify_inter_mb(mode_info_context, map); |
|
308 else totmap = (frame_type == KEY_FRAME ? 4 : 0); |
|
309 if (totmap) |
|
310 { |
|
311 if (totmap < 4) |
|
312 { |
|
313 int i, j; |
|
314 for (i=0; i<2; ++i) |
|
315 for (j=0; j<2; ++j) |
|
316 { |
|
317 if (map[i*2+j]) |
|
318 { |
|
319 multiframe_quality_enhance_block(8, qcurr, qprev, |
|
320 y_ptr + 8*(i*show->y_stride+j), |
|
321 u_ptr + 4*(i*show->uv_stride+j), |
|
322 v_ptr + 4*(i*show->uv_stride+j), |
|
323 show->y_stride, |
|
324 show->uv_stride, |
|
325 yd_ptr + 8*(i*dest->y_stride+j), |
|
326 ud_ptr + 4*(i*dest->uv_stride+j), |
|
327 vd_ptr + 4*(i*dest->uv_stride+j), |
|
328 dest->y_stride, |
|
329 dest->uv_stride); |
|
330 } |
|
331 else |
|
332 { |
|
333 /* copy a 8x8 block */ |
|
334 int k; |
|
335 unsigned char *up = u_ptr + 4*(i*show->uv_stride+j); |
|
336 unsigned char *udp = ud_ptr + 4*(i*dest->uv_stride+j); |
|
337 unsigned char *vp = v_ptr + 4*(i*show->uv_stride+j); |
|
338 unsigned char *vdp = vd_ptr + 4*(i*dest->uv_stride+j); |
|
339 vp8_copy_mem8x8(y_ptr + 8*(i*show->y_stride+j), show->y_stride, |
|
340 yd_ptr + 8*(i*dest->y_stride+j), dest->y_stride); |
|
341 for (k = 0; k < 4; ++k, up += show->uv_stride, udp += dest->uv_stride, |
|
342 vp += show->uv_stride, vdp += dest->uv_stride) |
|
343 { |
|
344 vpx_memcpy(udp, up, 4); |
|
345 vpx_memcpy(vdp, vp, 4); |
|
346 } |
|
347 } |
|
348 } |
|
349 } |
|
350 else /* totmap = 4 */ |
|
351 { |
|
352 multiframe_quality_enhance_block(16, qcurr, qprev, y_ptr, |
|
353 u_ptr, v_ptr, |
|
354 show->y_stride, |
|
355 show->uv_stride, |
|
356 yd_ptr, ud_ptr, vd_ptr, |
|
357 dest->y_stride, |
|
358 dest->uv_stride); |
|
359 } |
|
360 } |
|
361 else |
|
362 { |
|
363 vp8_copy_mem16x16(y_ptr, show->y_stride, yd_ptr, dest->y_stride); |
|
364 vp8_copy_mem8x8(u_ptr, show->uv_stride, ud_ptr, dest->uv_stride); |
|
365 vp8_copy_mem8x8(v_ptr, show->uv_stride, vd_ptr, dest->uv_stride); |
|
366 } |
|
367 y_ptr += 16; |
|
368 u_ptr += 8; |
|
369 v_ptr += 8; |
|
370 yd_ptr += 16; |
|
371 ud_ptr += 8; |
|
372 vd_ptr += 8; |
|
373 mode_info_context++; /* step to next MB */ |
|
374 } |
|
375 |
|
376 y_ptr += show->y_stride * 16 - 16 * cm->mb_cols; |
|
377 u_ptr += show->uv_stride * 8 - 8 * cm->mb_cols; |
|
378 v_ptr += show->uv_stride * 8 - 8 * cm->mb_cols; |
|
379 yd_ptr += dest->y_stride * 16 - 16 * cm->mb_cols; |
|
380 ud_ptr += dest->uv_stride * 8 - 8 * cm->mb_cols; |
|
381 vd_ptr += dest->uv_stride * 8 - 8 * cm->mb_cols; |
|
382 |
|
383 mode_info_context++; /* Skip border mb */ |
|
384 } |
|
385 } |