mfqe.c 13.7 KB
Newer Older
Johann's avatar
Johann committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
 *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */


/* MFQE: Multiframe Quality Enhancement
 * In rate limited situations keyframes may cause significant visual artifacts
 * commonly referred to as "popping." This file implements a postproccesing
 * algorithm which blends data from the preceeding frame when there is no
 * motion and the q from the previous frame is lower which indicates that it is
 * higher quality.
 */

#include "postproc.h"
#include "variance.h"
#include "vpx_mem/vpx_mem.h"
23
#include "vp8_rtcd.h"
Johann's avatar
Johann committed
24
25
26
27
28
#include "vpx_scale/yv12config.h"

#include <limits.h>
#include <stdlib.h>

29
30
31
static void filter_by_weight(unsigned char *src, int src_stride,
                             unsigned char *dst, int dst_stride,
                             int block_size, int src_weight)
Johann's avatar
Johann committed
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
{
    int dst_weight = (1 << MFQE_PRECISION) - src_weight;
    int rounding_bit = 1 << (MFQE_PRECISION - 1);
    int r, c;

    for (r = 0; r < block_size; r++)
    {
        for (c = 0; c < block_size; c++)
        {
            dst[c] = (src[c] * src_weight +
                      dst[c] * dst_weight +
                      rounding_bit) >> MFQE_PRECISION;
        }
        src += src_stride;
        dst += dst_stride;
    }
}

void vp8_filter_by_weight16x16_c(unsigned char *src, int src_stride,
                                 unsigned char *dst, int dst_stride,
                                 int src_weight)
{
    filter_by_weight(src, src_stride, dst, dst_stride, 16, src_weight);
}

void vp8_filter_by_weight8x8_c(unsigned char *src, int src_stride,
                               unsigned char *dst, int dst_stride,
                               int src_weight)
{
    filter_by_weight(src, src_stride, dst, dst_stride, 8, src_weight);
}

void vp8_filter_by_weight4x4_c(unsigned char *src, int src_stride,
                               unsigned char *dst, int dst_stride,
                               int src_weight)
{
    filter_by_weight(src, src_stride, dst, dst_stride, 4, src_weight);
}

71
72
73
74
75
76
77
78
79
80
81
82
static void 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)
Johann's avatar
Johann committed
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
{
    if (block_size == 16)
    {
        vp8_filter_by_weight16x16(y_src, y_src_stride, y_dst, y_dst_stride, src_weight);
        vp8_filter_by_weight8x8(u_src, uv_src_stride, u_dst, uv_dst_stride, src_weight);
        vp8_filter_by_weight8x8(v_src, uv_src_stride, v_dst, uv_dst_stride, src_weight);
    }
    else /* if (block_size == 8) */
    {
        vp8_filter_by_weight8x8(y_src, y_src_stride, y_dst, y_dst_stride, src_weight);
        vp8_filter_by_weight4x4(u_src, uv_src_stride, u_dst, uv_dst_stride, src_weight);
        vp8_filter_by_weight4x4(v_src, uv_src_stride, v_dst, uv_dst_stride, src_weight);
    }
}

98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
static unsigned int int_sqrt(unsigned int x)
{
    unsigned int y = x;
    unsigned int guess;
    int p = 1;
    while (y>>=1) p++;
    p>>=1;

    guess=0;
    while (p>=0)
    {
        guess |= (1<<p);
        if (x<guess*guess)
            guess -= (1<<p);
        p--;
    }
    /* choose between guess or guess+1 */
    return guess+(guess*guess+guess+1<=x);
}

#define USE_SSD
Johann's avatar
Johann committed
119
120
static void multiframe_quality_enhance_block
(
Attila Nagy's avatar
Attila Nagy committed
121
    int blksize, /* Currently only values supported are 16, 8 */
Johann's avatar
Johann committed
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
    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
)
{
    static const unsigned char VP8_ZEROS[16]=
    {
138
         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
Johann's avatar
Johann committed
139
    };
140
    int uvblksize = blksize >> 1;
Johann's avatar
Johann committed
141
142
    int qdiff = qcurr - qprev;

Attila Nagy's avatar
Attila Nagy committed
143
    int i;
Johann's avatar
Johann committed
144
145
146
147
148
    unsigned char *up;
    unsigned char *udp;
    unsigned char *vp;
    unsigned char *vdp;

149
    unsigned int act, actd, sad, usad, vsad, sse, thr, thrsq, actrisk;
Johann's avatar
Johann committed
150
151
152

    if (blksize == 16)
    {
153
154
155
156
157
158
159
160
161
162
        actd = (vp8_variance16x16(yd, yd_stride, VP8_ZEROS, 0, &sse)+128)>>8;
        act = (vp8_variance16x16(y, y_stride, VP8_ZEROS, 0, &sse)+128)>>8;
#ifdef USE_SSD
        sad = (vp8_variance16x16(y, y_stride, yd, yd_stride, &sse));
        sad = (sse + 128)>>8;
        usad = (vp8_variance8x8(u, uv_stride, ud, uvd_stride, &sse));
        usad = (sse + 32)>>6;
        vsad = (vp8_variance8x8(v, uv_stride, vd, uvd_stride, &sse));
        vsad = (sse + 32)>>6;
#else
Johann's avatar
Johann committed
163
164
165
        sad = (vp8_sad16x16(y, y_stride, yd, yd_stride, UINT_MAX) + 128) >> 8;
        usad = (vp8_sad8x8(u, uv_stride, ud, uvd_stride, UINT_MAX) + 32) >> 6;
        vsad = (vp8_sad8x8(v, uv_stride, vd, uvd_stride, UINT_MAX)+ 32) >> 6;
166
#endif
Johann's avatar
Johann committed
167
    }
Attila Nagy's avatar
Attila Nagy committed
168
    else /* if (blksize == 8) */
Johann's avatar
Johann committed
169
    {
170
171
172
173
174
175
176
177
178
179
        actd = (vp8_variance8x8(yd, yd_stride, VP8_ZEROS, 0, &sse)+32)>>6;
        act = (vp8_variance8x8(y, y_stride, VP8_ZEROS, 0, &sse)+32)>>6;
#ifdef USE_SSD
        sad = (vp8_variance8x8(y, y_stride, yd, yd_stride, &sse));
        sad = (sse + 32)>>6;
        usad = (vp8_variance4x4(u, uv_stride, ud, uvd_stride, &sse));
        usad = (sse + 8)>>4;
        vsad = (vp8_variance4x4(v, uv_stride, vd, uvd_stride, &sse));
        vsad = (sse + 8)>>4;
#else
Johann's avatar
Johann committed
180
181
182
        sad = (vp8_sad8x8(y, y_stride, yd, yd_stride, UINT_MAX) + 32) >> 6;
        usad = (vp8_sad4x4(u, uv_stride, ud, uvd_stride, UINT_MAX) + 8) >> 4;
        vsad = (vp8_sad4x4(v, uv_stride, vd, uvd_stride, UINT_MAX) + 8) >> 4;
183
#endif
Johann's avatar
Johann committed
184
185
    }

186
187
    actrisk = (actd > act * 5);

188
189
    /* thr = qdiff/16 + log2(act) + log4(qprev) */
    thr = (qdiff >> 4);
190
    while (actd >>= 1) thr++;
191
    while (qprev >>= 2) thr++;
Johann's avatar
Johann committed
192

193
194
195
196
197
198
199
200
201
202
203
204
#ifdef USE_SSD
    thrsq = thr * thr;
    if (sad < thrsq &&
        /* additional checks for color mismatch and excessive addition of
         * high-frequencies */
        4 * usad < thrsq && 4 * vsad < thrsq && !actrisk)
#else
    if (sad < thr &&
        /* additional checks for color mismatch and excessive addition of
         * high-frequencies */
        2 * usad < thr && 2 * vsad < thr && !actrisk)
#endif
Johann's avatar
Johann committed
205
    {
206
207
208
209
210
211
212
        int ifactor;
#ifdef USE_SSD
        /* TODO: optimize this later to not need sqr root */
        sad = int_sqrt(sad);
#endif
        ifactor = (sad << MFQE_PRECISION) / thr;
        ifactor >>= (qdiff >> 5);
213

214
        if (ifactor)
215
        {
216
217
218
219
            apply_ifactor(y, y_stride, yd, yd_stride,
                          u, v, uv_stride,
                          ud, vd, uvd_stride,
                          blksize, ifactor);
220
221
        }
    }
222
    else  /* else implicitly copy from previous frame */
223
224
225
    {
        if (blksize == 16)
        {
226
227
228
            vp8_copy_mem16x16(y, y_stride, yd, yd_stride);
            vp8_copy_mem8x8(u, uv_stride, ud, uvd_stride);
            vp8_copy_mem8x8(v, uv_stride, vd, uvd_stride);
229
        }
230
        else  /* if (blksize == 8) */
231
        {
232
233
234
235
236
            vp8_copy_mem8x8(y, y_stride, yd, yd_stride);
            for (up = u, udp = ud, i = 0; i < uvblksize; ++i, up += uv_stride, udp += uvd_stride)
                vpx_memcpy(udp, up, uvblksize);
            for (vp = v, vdp = vd, i = 0; i < uvblksize; ++i, vp += uv_stride, vdp += uvd_stride)
                vpx_memcpy(vdp, vp, uvblksize);
237
238
        }
    }
239
}
240

241
242
243
244
245
static int qualify_inter_mb(const MODE_INFO *mode_info_context, int *map)
{
    if (mode_info_context->mbmi.mb_skip_coeff)
        map[0] = map[1] = map[2] = map[3] = 1;
    else if (mode_info_context->mbmi.mode==SPLITMV)
246
    {
247
        static int ndx[4][4] =
Johann's avatar
Johann committed
248
        {
249
250
251
252
253
254
255
256
257
258
259
260
            {0, 1, 4, 5},
            {2, 3, 6, 7},
            {8, 9, 12, 13},
            {10, 11, 14, 15}
        };
        int i, j;
        for (i=0; i<4; ++i)
        {
            map[i] = 1;
            for (j=0; j<4 && map[j]; ++j)
                map[i] &= (mode_info_context->bmi[ndx[i][j]].mv.as_mv.row <= 2 &&
                           mode_info_context->bmi[ndx[i][j]].mv.as_mv.col <= 2);
Johann's avatar
Johann committed
261
262
263
264
        }
    }
    else
    {
265
266
267
268
        map[0] = map[1] = map[2] = map[3] =
            (mode_info_context->mbmi.mode > B_PRED &&
             abs(mode_info_context->mbmi.mv.as_mv.row) <= 2 &&
             abs(mode_info_context->mbmi.mv.as_mv.col) <= 2);
Johann's avatar
Johann committed
269
    }
270
    return (map[0]+map[1]+map[2]+map[3]);
Johann's avatar
Johann committed
271
272
273
274
275
276
277
278
279
280
281
282
}

void vp8_multiframe_quality_enhance
(
    VP8_COMMON *cm
)
{
    YV12_BUFFER_CONFIG *show = cm->frame_to_show;
    YV12_BUFFER_CONFIG *dest = &cm->post_proc_buffer;

    FRAME_TYPE frame_type = cm->frame_type;
    /* Point at base of Mb MODE_INFO list has motion vectors etc */
283
    const MODE_INFO *mode_info_context = cm->show_frame_mi;
Johann's avatar
Johann committed
284
285
    int mb_row;
    int mb_col;
286
    int totmap, map[4];
Johann's avatar
Johann committed
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
    int qcurr = cm->base_qindex;
    int qprev = cm->postproc_state.last_base_qindex;

    unsigned char *y_ptr, *u_ptr, *v_ptr;
    unsigned char *yd_ptr, *ud_ptr, *vd_ptr;

    /* Set up the buffer pointers */
    y_ptr = show->y_buffer;
    u_ptr = show->u_buffer;
    v_ptr = show->v_buffer;
    yd_ptr = dest->y_buffer;
    ud_ptr = dest->u_buffer;
    vd_ptr = dest->v_buffer;

    /* postprocess each macro block */
    for (mb_row = 0; mb_row < cm->mb_rows; mb_row++)
    {
        for (mb_col = 0; mb_col < cm->mb_cols; mb_col++)
        {
            /* if motion is high there will likely be no benefit */
307
308
309
            if (frame_type == INTER_FRAME) totmap = qualify_inter_mb(mode_info_context, map);
            else totmap = (frame_type == KEY_FRAME ? 4 : 0);
            if (totmap)
Johann's avatar
Johann committed
310
            {
311
                if (totmap < 4)
Johann's avatar
Johann committed
312
313
314
315
                {
                    int i, j;
                    for (i=0; i<2; ++i)
                        for (j=0; j<2; ++j)
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
                        {
                            if (map[i*2+j])
                            {
                                multiframe_quality_enhance_block(8, qcurr, qprev,
                                                                 y_ptr + 8*(i*show->y_stride+j),
                                                                 u_ptr + 4*(i*show->uv_stride+j),
                                                                 v_ptr + 4*(i*show->uv_stride+j),
                                                                 show->y_stride,
                                                                 show->uv_stride,
                                                                 yd_ptr + 8*(i*dest->y_stride+j),
                                                                 ud_ptr + 4*(i*dest->uv_stride+j),
                                                                 vd_ptr + 4*(i*dest->uv_stride+j),
                                                                 dest->y_stride,
                                                                 dest->uv_stride);
                            }
                            else
                            {
                                /* copy a 8x8 block */
                                int k;
                                unsigned char *up = u_ptr + 4*(i*show->uv_stride+j);
                                unsigned char *udp = ud_ptr + 4*(i*dest->uv_stride+j);
                                unsigned char *vp = v_ptr + 4*(i*show->uv_stride+j);
                                unsigned char *vdp = vd_ptr + 4*(i*dest->uv_stride+j);
                                vp8_copy_mem8x8(y_ptr + 8*(i*show->y_stride+j), show->y_stride,
                                                yd_ptr + 8*(i*dest->y_stride+j), dest->y_stride);
                                for (k = 0; k < 4; ++k, up += show->uv_stride, udp += dest->uv_stride,
                                                        vp += show->uv_stride, vdp += dest->uv_stride)
                                {
                                    vpx_memcpy(udp, up, 4);
                                    vpx_memcpy(vdp, vp, 4);
                                }
                            }
                        }
Johann's avatar
Johann committed
349
                }
350
                else /* totmap = 4 */
Johann's avatar
Johann committed
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
                {
                    multiframe_quality_enhance_block(16, qcurr, qprev, y_ptr,
                                                     u_ptr, v_ptr,
                                                     show->y_stride,
                                                     show->uv_stride,
                                                     yd_ptr, ud_ptr, vd_ptr,
                                                     dest->y_stride,
                                                     dest->uv_stride);
                }
            }
            else
            {
                vp8_copy_mem16x16(y_ptr, show->y_stride, yd_ptr, dest->y_stride);
                vp8_copy_mem8x8(u_ptr, show->uv_stride, ud_ptr, dest->uv_stride);
                vp8_copy_mem8x8(v_ptr, show->uv_stride, vd_ptr, dest->uv_stride);
            }
            y_ptr += 16;
            u_ptr += 8;
            v_ptr += 8;
            yd_ptr += 16;
            ud_ptr += 8;
            vd_ptr += 8;
            mode_info_context++;     /* step to next MB */
        }

        y_ptr += show->y_stride  * 16 - 16 * cm->mb_cols;
        u_ptr += show->uv_stride *  8 - 8 * cm->mb_cols;
        v_ptr += show->uv_stride *  8 - 8 * cm->mb_cols;
        yd_ptr += dest->y_stride  * 16 - 16 * cm->mb_cols;
        ud_ptr += dest->uv_stride *  8 - 8 * cm->mb_cols;
        vd_ptr += dest->uv_stride *  8 - 8 * cm->mb_cols;

        mode_info_context++;         /* Skip border mb */
    }
}