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