1 : /*
2 : * Copyright (c) 2010 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 : #include "vpx_ports/config.h"
13 : #include "vpx_scale/yv12config.h"
14 : #include "postproc.h"
15 : #include "vpx_scale/yv12extend.h"
16 : #include "vpx_scale/vpxscale.h"
17 : #include "systemdependent.h"
18 :
19 : #include <math.h>
20 : #include <stdlib.h>
21 : #include <stdio.h>
22 :
23 : #define RGB_TO_YUV(t) \
24 : ( (0.257*(float)(t>>16)) + (0.504*(float)(t>>8&0xff)) + (0.098*(float)(t&0xff)) + 16), \
25 : (-(0.148*(float)(t>>16)) - (0.291*(float)(t>>8&0xff)) + (0.439*(float)(t&0xff)) + 128), \
26 : ( (0.439*(float)(t>>16)) - (0.368*(float)(t>>8&0xff)) - (0.071*(float)(t&0xff)) + 128)
27 :
28 : /* global constants */
29 : #if CONFIG_POSTPROC_VISUALIZER
30 : static const unsigned char MB_PREDICTION_MODE_colors[MB_MODE_COUNT][3] =
31 : {
32 : { RGB_TO_YUV(0x98FB98) }, /* PaleGreen */
33 : { RGB_TO_YUV(0x00FF00) }, /* Green */
34 : { RGB_TO_YUV(0xADFF2F) }, /* GreenYellow */
35 : { RGB_TO_YUV(0x228B22) }, /* ForestGreen */
36 : { RGB_TO_YUV(0x006400) }, /* DarkGreen */
37 : { RGB_TO_YUV(0x98F5FF) }, /* Cadet Blue */
38 : { RGB_TO_YUV(0x6CA6CD) }, /* Sky Blue */
39 : { RGB_TO_YUV(0x00008B) }, /* Dark blue */
40 : { RGB_TO_YUV(0x551A8B) }, /* Purple */
41 : { RGB_TO_YUV(0xFF0000) } /* Red */
42 : };
43 :
44 : static const unsigned char B_PREDICTION_MODE_colors[B_MODE_COUNT][3] =
45 : {
46 : { RGB_TO_YUV(0x6633ff) }, /* Purple */
47 : { RGB_TO_YUV(0xcc33ff) }, /* Magenta */
48 : { RGB_TO_YUV(0xff33cc) }, /* Pink */
49 : { RGB_TO_YUV(0xff3366) }, /* Coral */
50 : { RGB_TO_YUV(0x3366ff) }, /* Blue */
51 : { RGB_TO_YUV(0xed00f5) }, /* Dark Blue */
52 : { RGB_TO_YUV(0x2e00b8) }, /* Dark Purple */
53 : { RGB_TO_YUV(0xff6633) }, /* Orange */
54 : { RGB_TO_YUV(0x33ccff) }, /* Light Blue */
55 : { RGB_TO_YUV(0x8ab800) }, /* Green */
56 : { RGB_TO_YUV(0xffcc33) }, /* Light Orange */
57 : { RGB_TO_YUV(0x33ffcc) }, /* Aqua */
58 : { RGB_TO_YUV(0x66ff33) }, /* Light Green */
59 : { RGB_TO_YUV(0xccff33) }, /* Yellow */
60 : };
61 :
62 : static const unsigned char MV_REFERENCE_FRAME_colors[MAX_REF_FRAMES][3] =
63 : {
64 : { RGB_TO_YUV(0x00ff00) }, /* Blue */
65 : { RGB_TO_YUV(0x0000ff) }, /* Green */
66 : { RGB_TO_YUV(0xffff00) }, /* Yellow */
67 : { RGB_TO_YUV(0xff0000) }, /* Red */
68 : };
69 : #endif
70 :
71 : static const short kernel5[] =
72 : {
73 : 1, 1, 4, 1, 1
74 : };
75 :
76 : const short vp8_rv[] =
77 : {
78 : 8, 5, 2, 2, 8, 12, 4, 9, 8, 3,
79 : 0, 3, 9, 0, 0, 0, 8, 3, 14, 4,
80 : 10, 1, 11, 14, 1, 14, 9, 6, 12, 11,
81 : 8, 6, 10, 0, 0, 8, 9, 0, 3, 14,
82 : 8, 11, 13, 4, 2, 9, 0, 3, 9, 6,
83 : 1, 2, 3, 14, 13, 1, 8, 2, 9, 7,
84 : 3, 3, 1, 13, 13, 6, 6, 5, 2, 7,
85 : 11, 9, 11, 8, 7, 3, 2, 0, 13, 13,
86 : 14, 4, 12, 5, 12, 10, 8, 10, 13, 10,
87 : 4, 14, 4, 10, 0, 8, 11, 1, 13, 7,
88 : 7, 14, 6, 14, 13, 2, 13, 5, 4, 4,
89 : 0, 10, 0, 5, 13, 2, 12, 7, 11, 13,
90 : 8, 0, 4, 10, 7, 2, 7, 2, 2, 5,
91 : 3, 4, 7, 3, 3, 14, 14, 5, 9, 13,
92 : 3, 14, 3, 6, 3, 0, 11, 8, 13, 1,
93 : 13, 1, 12, 0, 10, 9, 7, 6, 2, 8,
94 : 5, 2, 13, 7, 1, 13, 14, 7, 6, 7,
95 : 9, 6, 10, 11, 7, 8, 7, 5, 14, 8,
96 : 4, 4, 0, 8, 7, 10, 0, 8, 14, 11,
97 : 3, 12, 5, 7, 14, 3, 14, 5, 2, 6,
98 : 11, 12, 12, 8, 0, 11, 13, 1, 2, 0,
99 : 5, 10, 14, 7, 8, 0, 4, 11, 0, 8,
100 : 0, 3, 10, 5, 8, 0, 11, 6, 7, 8,
101 : 10, 7, 13, 9, 2, 5, 1, 5, 10, 2,
102 : 4, 3, 5, 6, 10, 8, 9, 4, 11, 14,
103 : 0, 10, 0, 5, 13, 2, 12, 7, 11, 13,
104 : 8, 0, 4, 10, 7, 2, 7, 2, 2, 5,
105 : 3, 4, 7, 3, 3, 14, 14, 5, 9, 13,
106 : 3, 14, 3, 6, 3, 0, 11, 8, 13, 1,
107 : 13, 1, 12, 0, 10, 9, 7, 6, 2, 8,
108 : 5, 2, 13, 7, 1, 13, 14, 7, 6, 7,
109 : 9, 6, 10, 11, 7, 8, 7, 5, 14, 8,
110 : 4, 4, 0, 8, 7, 10, 0, 8, 14, 11,
111 : 3, 12, 5, 7, 14, 3, 14, 5, 2, 6,
112 : 11, 12, 12, 8, 0, 11, 13, 1, 2, 0,
113 : 5, 10, 14, 7, 8, 0, 4, 11, 0, 8,
114 : 0, 3, 10, 5, 8, 0, 11, 6, 7, 8,
115 : 10, 7, 13, 9, 2, 5, 1, 5, 10, 2,
116 : 4, 3, 5, 6, 10, 8, 9, 4, 11, 14,
117 : 3, 8, 3, 7, 8, 5, 11, 4, 12, 3,
118 : 11, 9, 14, 8, 14, 13, 4, 3, 1, 2,
119 : 14, 6, 5, 4, 4, 11, 4, 6, 2, 1,
120 : 5, 8, 8, 12, 13, 5, 14, 10, 12, 13,
121 : 0, 9, 5, 5, 11, 10, 13, 9, 10, 13,
122 : };
123 :
124 :
125 : extern void vp8_blit_text(const char *msg, unsigned char *address, const int pitch);
126 : extern void vp8_blit_line(int x0, int x1, int y0, int y1, unsigned char *image, const int pitch);
127 : /***********************************************************************************************************
128 : */
129 0 : void vp8_post_proc_down_and_across_c
130 : (
131 : unsigned char *src_ptr,
132 : unsigned char *dst_ptr,
133 : int src_pixels_per_line,
134 : int dst_pixels_per_line,
135 : int rows,
136 : int cols,
137 : int flimit
138 : )
139 : {
140 : unsigned char *p_src, *p_dst;
141 : int row;
142 : int col;
143 : int i;
144 : int v;
145 0 : int pitch = src_pixels_per_line;
146 : unsigned char d[8];
147 : (void)dst_pixels_per_line;
148 :
149 0 : for (row = 0; row < rows; row++)
150 : {
151 : /* post_proc_down for one row */
152 0 : p_src = src_ptr;
153 0 : p_dst = dst_ptr;
154 :
155 0 : for (col = 0; col < cols; col++)
156 : {
157 :
158 0 : int kernel = 4;
159 0 : int v = p_src[col];
160 :
161 0 : for (i = -2; i <= 2; i++)
162 : {
163 0 : if (abs(v - p_src[col+i*pitch]) > flimit)
164 0 : goto down_skip_convolve;
165 :
166 0 : kernel += kernel5[2+i] * p_src[col+i*pitch];
167 : }
168 :
169 0 : v = (kernel >> 3);
170 : down_skip_convolve:
171 0 : p_dst[col] = v;
172 : }
173 :
174 : /* now post_proc_across */
175 0 : p_src = dst_ptr;
176 0 : p_dst = dst_ptr;
177 :
178 0 : for (i = 0; i < 8; i++)
179 0 : d[i] = p_src[i];
180 :
181 0 : for (col = 0; col < cols; col++)
182 : {
183 0 : int kernel = 4;
184 0 : v = p_src[col];
185 :
186 0 : d[col&7] = v;
187 :
188 0 : for (i = -2; i <= 2; i++)
189 : {
190 0 : if (abs(v - p_src[col+i]) > flimit)
191 0 : goto across_skip_convolve;
192 :
193 0 : kernel += kernel5[2+i] * p_src[col+i];
194 : }
195 :
196 0 : d[col&7] = (kernel >> 3);
197 : across_skip_convolve:
198 :
199 0 : if (col >= 2)
200 0 : p_dst[col-2] = d[(col-2)&7];
201 : }
202 :
203 : /* handle the last two pixels */
204 0 : p_dst[col-2] = d[(col-2)&7];
205 0 : p_dst[col-1] = d[(col-1)&7];
206 :
207 :
208 : /* next row */
209 0 : src_ptr += pitch;
210 0 : dst_ptr += pitch;
211 : }
212 0 : }
213 :
214 0 : static int q2mbl(int x)
215 : {
216 0 : if (x < 20) x = 20;
217 :
218 0 : x = 50 + (x - 50) * 10 / 8;
219 0 : return x * x / 3;
220 : }
221 0 : void vp8_mbpost_proc_across_ip_c(unsigned char *src, int pitch, int rows, int cols, int flimit)
222 : {
223 : int r, c, i;
224 :
225 0 : unsigned char *s = src;
226 : unsigned char d[16];
227 :
228 :
229 0 : for (r = 0; r < rows; r++)
230 : {
231 0 : int sumsq = 0;
232 0 : int sum = 0;
233 :
234 0 : for (i = -8; i <= 6; i++)
235 : {
236 0 : sumsq += s[i] * s[i];
237 0 : sum += s[i];
238 0 : d[i+8] = 0;
239 : }
240 :
241 0 : for (c = 0; c < cols + 8; c++)
242 : {
243 0 : int x = s[c+7] - s[c-8];
244 0 : int y = s[c+7] + s[c-8];
245 :
246 0 : sum += x;
247 0 : sumsq += x * y;
248 :
249 0 : d[c&15] = s[c];
250 :
251 0 : if (sumsq * 15 - sum * sum < flimit)
252 : {
253 0 : d[c&15] = (8 + sum + s[c]) >> 4;
254 : }
255 :
256 0 : s[c-8] = d[(c-8)&15];
257 : }
258 :
259 0 : s += pitch;
260 : }
261 0 : }
262 :
263 :
264 :
265 :
266 :
267 0 : void vp8_mbpost_proc_down_c(unsigned char *dst, int pitch, int rows, int cols, int flimit)
268 : {
269 : int r, c, i;
270 0 : const short *rv3 = &vp8_rv[63&rand()];
271 :
272 0 : for (c = 0; c < cols; c++)
273 : {
274 0 : unsigned char *s = &dst[c];
275 0 : int sumsq = 0;
276 0 : int sum = 0;
277 : unsigned char d[16];
278 0 : const short *rv2 = rv3 + ((c * 17) & 127);
279 :
280 0 : for (i = -8; i <= 6; i++)
281 : {
282 0 : sumsq += s[i*pitch] * s[i*pitch];
283 0 : sum += s[i*pitch];
284 : }
285 :
286 0 : for (r = 0; r < rows + 8; r++)
287 : {
288 0 : sumsq += s[7*pitch] * s[ 7*pitch] - s[-8*pitch] * s[-8*pitch];
289 0 : sum += s[7*pitch] - s[-8*pitch];
290 0 : d[r&15] = s[0];
291 :
292 0 : if (sumsq * 15 - sum * sum < flimit)
293 : {
294 0 : d[r&15] = (rv2[r&127] + sum + s[0]) >> 4;
295 : }
296 :
297 0 : s[-8*pitch] = d[(r-8)&15];
298 0 : s += pitch;
299 : }
300 : }
301 0 : }
302 :
303 :
304 0 : static void vp8_deblock_and_de_macro_block(YV12_BUFFER_CONFIG *source,
305 : YV12_BUFFER_CONFIG *post,
306 : int q,
307 : int low_var_thresh,
308 : int flag,
309 : vp8_postproc_rtcd_vtable_t *rtcd)
310 : {
311 0 : double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
312 0 : int ppl = (int)(level + .5);
313 : (void) low_var_thresh;
314 : (void) flag;
315 :
316 0 : POSTPROC_INVOKE(rtcd, downacross)(source->y_buffer, post->y_buffer, source->y_stride, post->y_stride, source->y_height, source->y_width, ppl);
317 0 : POSTPROC_INVOKE(rtcd, across)(post->y_buffer, post->y_stride, post->y_height, post->y_width, q2mbl(q));
318 0 : POSTPROC_INVOKE(rtcd, down)(post->y_buffer, post->y_stride, post->y_height, post->y_width, q2mbl(q));
319 :
320 0 : POSTPROC_INVOKE(rtcd, downacross)(source->u_buffer, post->u_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl);
321 0 : POSTPROC_INVOKE(rtcd, downacross)(source->v_buffer, post->v_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl);
322 :
323 0 : }
324 :
325 0 : void vp8_deblock(YV12_BUFFER_CONFIG *source,
326 : YV12_BUFFER_CONFIG *post,
327 : int q,
328 : int low_var_thresh,
329 : int flag,
330 : vp8_postproc_rtcd_vtable_t *rtcd)
331 : {
332 0 : double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
333 0 : int ppl = (int)(level + .5);
334 : (void) low_var_thresh;
335 : (void) flag;
336 :
337 0 : POSTPROC_INVOKE(rtcd, downacross)(source->y_buffer, post->y_buffer, source->y_stride, post->y_stride, source->y_height, source->y_width, ppl);
338 0 : POSTPROC_INVOKE(rtcd, downacross)(source->u_buffer, post->u_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl);
339 0 : POSTPROC_INVOKE(rtcd, downacross)(source->v_buffer, post->v_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl);
340 0 : }
341 :
342 0 : void vp8_de_noise(YV12_BUFFER_CONFIG *source,
343 : YV12_BUFFER_CONFIG *post,
344 : int q,
345 : int low_var_thresh,
346 : int flag,
347 : vp8_postproc_rtcd_vtable_t *rtcd)
348 : {
349 0 : double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
350 0 : int ppl = (int)(level + .5);
351 : (void) post;
352 : (void) low_var_thresh;
353 : (void) flag;
354 :
355 0 : POSTPROC_INVOKE(rtcd, downacross)(
356 0 : source->y_buffer + 2 * source->y_stride + 2,
357 0 : source->y_buffer + 2 * source->y_stride + 2,
358 : source->y_stride,
359 : source->y_stride,
360 0 : source->y_height - 4,
361 0 : source->y_width - 4,
362 : ppl);
363 0 : POSTPROC_INVOKE(rtcd, downacross)(
364 0 : source->u_buffer + 2 * source->uv_stride + 2,
365 0 : source->u_buffer + 2 * source->uv_stride + 2,
366 : source->uv_stride,
367 : source->uv_stride,
368 0 : source->uv_height - 4,
369 0 : source->uv_width - 4, ppl);
370 0 : POSTPROC_INVOKE(rtcd, downacross)(
371 0 : source->v_buffer + 2 * source->uv_stride + 2,
372 0 : source->v_buffer + 2 * source->uv_stride + 2,
373 : source->uv_stride,
374 : source->uv_stride,
375 0 : source->uv_height - 4,
376 0 : source->uv_width - 4, ppl);
377 :
378 0 : }
379 :
380 0 : double vp8_gaussian(double sigma, double mu, double x)
381 : {
382 0 : return 1 / (sigma * sqrt(2.0 * 3.14159265)) *
383 0 : (exp(-(x - mu) * (x - mu) / (2 * sigma * sigma)));
384 : }
385 :
386 : extern void (*vp8_clear_system_state)(void);
387 :
388 :
389 0 : static void fillrd(struct postproc_state *state, int q, int a)
390 : {
391 : char char_dist[300];
392 :
393 : double sigma;
394 0 : int ai = a, qi = q, i;
395 :
396 0 : vp8_clear_system_state();
397 :
398 :
399 0 : sigma = ai + .5 + .6 * (63 - qi) / 63.0;
400 :
401 : /* set up a lookup table of 256 entries that matches
402 : * a gaussian distribution with sigma determined by q.
403 : */
404 : {
405 : double i;
406 : int next, j;
407 :
408 0 : next = 0;
409 :
410 0 : for (i = -32; i < 32; i++)
411 : {
412 0 : int a = (int)(.5 + 256 * vp8_gaussian(sigma, 0, i));
413 :
414 0 : if (a)
415 : {
416 0 : for (j = 0; j < a; j++)
417 : {
418 0 : char_dist[next+j] = (char) i;
419 : }
420 :
421 0 : next = next + j;
422 : }
423 :
424 : }
425 :
426 0 : for (next = next; next < 256; next++)
427 0 : char_dist[next] = 0;
428 :
429 : }
430 :
431 0 : for (i = 0; i < 3072; i++)
432 : {
433 0 : state->noise[i] = char_dist[rand() & 0xff];
434 : }
435 :
436 0 : for (i = 0; i < 16; i++)
437 : {
438 0 : state->blackclamp[i] = -char_dist[0];
439 0 : state->whiteclamp[i] = -char_dist[0];
440 0 : state->bothclamp[i] = -2 * char_dist[0];
441 : }
442 :
443 0 : state->last_q = q;
444 0 : state->last_noise = a;
445 0 : }
446 :
447 : /****************************************************************************
448 : *
449 : * ROUTINE : plane_add_noise_c
450 : *
451 : * INPUTS : unsigned char *Start starting address of buffer to add gaussian
452 : * noise to
453 : * unsigned int Width width of plane
454 : * unsigned int Height height of plane
455 : * int Pitch distance between subsequent lines of frame
456 : * int q quantizer used to determine amount of noise
457 : * to add
458 : *
459 : * OUTPUTS : None.
460 : *
461 : * RETURNS : void.
462 : *
463 : * FUNCTION : adds gaussian noise to a plane of pixels
464 : *
465 : * SPECIAL NOTES : None.
466 : *
467 : ****************************************************************************/
468 0 : void vp8_plane_add_noise_c(unsigned char *Start, char *noise,
469 : char blackclamp[16],
470 : char whiteclamp[16],
471 : char bothclamp[16],
472 : unsigned int Width, unsigned int Height, int Pitch)
473 : {
474 : unsigned int i, j;
475 :
476 0 : for (i = 0; i < Height; i++)
477 : {
478 0 : unsigned char *Pos = Start + i * Pitch;
479 0 : char *Ref = (char *)(noise + (rand() & 0xff));
480 :
481 0 : for (j = 0; j < Width; j++)
482 : {
483 0 : if (Pos[j] < blackclamp[0])
484 0 : Pos[j] = blackclamp[0];
485 :
486 0 : if (Pos[j] > 255 + whiteclamp[0])
487 0 : Pos[j] = 255 + whiteclamp[0];
488 :
489 0 : Pos[j] += Ref[j];
490 : }
491 : }
492 0 : }
493 :
494 : /* Blend the macro block with a solid colored square. Leave the
495 : * edges unblended to give distinction to macro blocks in areas
496 : * filled with the same color block.
497 : */
498 0 : void vp8_blend_mb_inner_c (unsigned char *y, unsigned char *u, unsigned char *v,
499 : int y1, int u1, int v1, int alpha, int stride)
500 : {
501 : int i, j;
502 0 : int y1_const = y1*((1<<16)-alpha);
503 0 : int u1_const = u1*((1<<16)-alpha);
504 0 : int v1_const = v1*((1<<16)-alpha);
505 :
506 0 : y += 2*stride + 2;
507 0 : for (i = 0; i < 12; i++)
508 : {
509 0 : for (j = 0; j < 12; j++)
510 : {
511 0 : y[j] = (y[j]*alpha + y1_const)>>16;
512 : }
513 0 : y += stride;
514 : }
515 :
516 0 : stride >>= 1;
517 :
518 0 : u += stride + 1;
519 0 : v += stride + 1;
520 :
521 0 : for (i = 0; i < 6; i++)
522 : {
523 0 : for (j = 0; j < 6; j++)
524 : {
525 0 : u[j] = (u[j]*alpha + u1_const)>>16;
526 0 : v[j] = (v[j]*alpha + v1_const)>>16;
527 : }
528 0 : u += stride;
529 0 : v += stride;
530 : }
531 0 : }
532 :
533 : /* Blend only the edge of the macro block. Leave center
534 : * unblended to allow for other visualizations to be layered.
535 : */
536 0 : void vp8_blend_mb_outer_c (unsigned char *y, unsigned char *u, unsigned char *v,
537 : int y1, int u1, int v1, int alpha, int stride)
538 : {
539 : int i, j;
540 0 : int y1_const = y1*((1<<16)-alpha);
541 0 : int u1_const = u1*((1<<16)-alpha);
542 0 : int v1_const = v1*((1<<16)-alpha);
543 :
544 0 : for (i = 0; i < 2; i++)
545 : {
546 0 : for (j = 0; j < 16; j++)
547 : {
548 0 : y[j] = (y[j]*alpha + y1_const)>>16;
549 : }
550 0 : y += stride;
551 : }
552 :
553 0 : for (i = 0; i < 12; i++)
554 : {
555 0 : y[0] = (y[0]*alpha + y1_const)>>16;
556 0 : y[1] = (y[1]*alpha + y1_const)>>16;
557 0 : y[14] = (y[14]*alpha + y1_const)>>16;
558 0 : y[15] = (y[15]*alpha + y1_const)>>16;
559 0 : y += stride;
560 : }
561 :
562 0 : for (i = 0; i < 2; i++)
563 : {
564 0 : for (j = 0; j < 16; j++)
565 : {
566 0 : y[j] = (y[j]*alpha + y1_const)>>16;
567 : }
568 0 : y += stride;
569 : }
570 :
571 0 : stride >>= 1;
572 :
573 0 : for (j = 0; j < 8; j++)
574 : {
575 0 : u[j] = (u[j]*alpha + u1_const)>>16;
576 0 : v[j] = (v[j]*alpha + v1_const)>>16;
577 : }
578 0 : u += stride;
579 0 : v += stride;
580 :
581 0 : for (i = 0; i < 6; i++)
582 : {
583 0 : u[0] = (u[0]*alpha + u1_const)>>16;
584 0 : v[0] = (v[0]*alpha + v1_const)>>16;
585 :
586 0 : u[7] = (u[7]*alpha + u1_const)>>16;
587 0 : v[7] = (v[7]*alpha + v1_const)>>16;
588 :
589 0 : u += stride;
590 0 : v += stride;
591 : }
592 :
593 0 : for (j = 0; j < 8; j++)
594 : {
595 0 : u[j] = (u[j]*alpha + u1_const)>>16;
596 0 : v[j] = (v[j]*alpha + v1_const)>>16;
597 : }
598 0 : }
599 :
600 0 : void vp8_blend_b_c (unsigned char *y, unsigned char *u, unsigned char *v,
601 : int y1, int u1, int v1, int alpha, int stride)
602 : {
603 : int i, j;
604 0 : int y1_const = y1*((1<<16)-alpha);
605 0 : int u1_const = u1*((1<<16)-alpha);
606 0 : int v1_const = v1*((1<<16)-alpha);
607 :
608 0 : for (i = 0; i < 4; i++)
609 : {
610 0 : for (j = 0; j < 4; j++)
611 : {
612 0 : y[j] = (y[j]*alpha + y1_const)>>16;
613 : }
614 0 : y += stride;
615 : }
616 :
617 0 : stride >>= 1;
618 :
619 0 : for (i = 0; i < 2; i++)
620 : {
621 0 : for (j = 0; j < 2; j++)
622 : {
623 0 : u[j] = (u[j]*alpha + u1_const)>>16;
624 0 : v[j] = (v[j]*alpha + v1_const)>>16;
625 : }
626 0 : u += stride;
627 0 : v += stride;
628 : }
629 0 : }
630 :
631 0 : static void constrain_line (int x0, int *x1, int y0, int *y1, int width, int height)
632 : {
633 : int dx;
634 : int dy;
635 :
636 0 : if (*x1 > width)
637 : {
638 0 : dx = *x1 - x0;
639 0 : dy = *y1 - y0;
640 :
641 0 : *x1 = width;
642 0 : if (dx)
643 0 : *y1 = ((width-x0)*dy)/dx + y0;
644 : }
645 0 : if (*x1 < 0)
646 : {
647 0 : dx = *x1 - x0;
648 0 : dy = *y1 - y0;
649 :
650 0 : *x1 = 0;
651 0 : if (dx)
652 0 : *y1 = ((0-x0)*dy)/dx + y0;
653 : }
654 0 : if (*y1 > height)
655 : {
656 0 : dx = *x1 - x0;
657 0 : dy = *y1 - y0;
658 :
659 0 : *y1 = height;
660 0 : if (dy)
661 0 : *x1 = ((height-y0)*dx)/dy + x0;
662 : }
663 0 : if (*y1 < 0)
664 : {
665 0 : dx = *x1 - x0;
666 0 : dy = *y1 - y0;
667 :
668 0 : *y1 = 0;
669 0 : if (dy)
670 0 : *x1 = ((0-y0)*dx)/dy + x0;
671 : }
672 0 : }
673 :
674 :
675 : #if CONFIG_RUNTIME_CPU_DETECT
676 : #define RTCD_VTABLE(oci) (&(oci)->rtcd.postproc)
677 : #else
678 : #define RTCD_VTABLE(oci) NULL
679 : #endif
680 :
681 0 : int vp8_post_proc_frame(VP8_COMMON *oci, YV12_BUFFER_CONFIG *dest, vp8_ppflags_t *ppflags)
682 : {
683 0 : int q = oci->filter_level * 10 / 6;
684 0 : int flags = ppflags->post_proc_flag;
685 0 : int deblock_level = ppflags->deblocking_level;
686 0 : int noise_level = ppflags->noise_level;
687 :
688 0 : if (!oci->frame_to_show)
689 0 : return -1;
690 :
691 0 : if (q > 63)
692 0 : q = 63;
693 :
694 0 : if (!flags)
695 : {
696 0 : *dest = *oci->frame_to_show;
697 :
698 : /* handle problem with extending borders */
699 0 : dest->y_width = oci->Width;
700 0 : dest->y_height = oci->Height;
701 0 : dest->uv_height = dest->y_height / 2;
702 0 : return 0;
703 :
704 : }
705 :
706 : #if ARCH_X86||ARCH_X86_64
707 0 : vpx_reset_mmx_state();
708 : #endif
709 :
710 0 : if (flags & VP8D_DEMACROBLOCK)
711 : {
712 0 : vp8_deblock_and_de_macro_block(oci->frame_to_show, &oci->post_proc_buffer,
713 0 : q + (deblock_level - 5) * 10, 1, 0, RTCD_VTABLE(oci));
714 : }
715 0 : else if (flags & VP8D_DEBLOCK)
716 : {
717 0 : vp8_deblock(oci->frame_to_show, &oci->post_proc_buffer,
718 : q, 1, 0, RTCD_VTABLE(oci));
719 : }
720 : else
721 : {
722 0 : vp8_yv12_copy_frame_ptr(oci->frame_to_show, &oci->post_proc_buffer);
723 : }
724 :
725 0 : if (flags & VP8D_ADDNOISE)
726 : {
727 0 : if (oci->postproc_state.last_q != q
728 0 : || oci->postproc_state.last_noise != noise_level)
729 : {
730 0 : fillrd(&oci->postproc_state, 63 - q, noise_level);
731 : }
732 :
733 0 : POSTPROC_INVOKE(RTCD_VTABLE(oci), addnoise)
734 0 : (oci->post_proc_buffer.y_buffer,
735 : oci->postproc_state.noise,
736 : oci->postproc_state.blackclamp,
737 : oci->postproc_state.whiteclamp,
738 : oci->postproc_state.bothclamp,
739 0 : oci->post_proc_buffer.y_width, oci->post_proc_buffer.y_height,
740 : oci->post_proc_buffer.y_stride);
741 : }
742 :
743 : #if CONFIG_POSTPROC_VISUALIZER
744 : if (flags & VP8D_DEBUG_TXT_FRAME_INFO)
745 : {
746 : char message[512];
747 : sprintf(message, "F%1dG%1dQ%3dF%3dP%d_s%dx%d",
748 : (oci->frame_type == KEY_FRAME),
749 : oci->refresh_golden_frame,
750 : oci->base_qindex,
751 : oci->filter_level,
752 : flags,
753 : oci->mb_cols, oci->mb_rows);
754 : vp8_blit_text(message, oci->post_proc_buffer.y_buffer, oci->post_proc_buffer.y_stride);
755 : }
756 :
757 : if (flags & VP8D_DEBUG_TXT_MBLK_MODES)
758 : {
759 : int i, j;
760 : unsigned char *y_ptr;
761 : YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
762 : int mb_rows = post->y_height >> 4;
763 : int mb_cols = post->y_width >> 4;
764 : int mb_index = 0;
765 : MODE_INFO *mi = oci->mi;
766 :
767 : y_ptr = post->y_buffer + 4 * post->y_stride + 4;
768 :
769 : /* vp8_filter each macro block */
770 : for (i = 0; i < mb_rows; i++)
771 : {
772 : for (j = 0; j < mb_cols; j++)
773 : {
774 : char zz[4];
775 :
776 : sprintf(zz, "%c", mi[mb_index].mbmi.mode + 'a');
777 :
778 : vp8_blit_text(zz, y_ptr, post->y_stride);
779 : mb_index ++;
780 : y_ptr += 16;
781 : }
782 :
783 : mb_index ++; /* border */
784 : y_ptr += post->y_stride * 16 - post->y_width;
785 :
786 : }
787 : }
788 :
789 : if (flags & VP8D_DEBUG_TXT_DC_DIFF)
790 : {
791 : int i, j;
792 : unsigned char *y_ptr;
793 : YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
794 : int mb_rows = post->y_height >> 4;
795 : int mb_cols = post->y_width >> 4;
796 : int mb_index = 0;
797 : MODE_INFO *mi = oci->mi;
798 :
799 : y_ptr = post->y_buffer + 4 * post->y_stride + 4;
800 :
801 : /* vp8_filter each macro block */
802 : for (i = 0; i < mb_rows; i++)
803 : {
804 : for (j = 0; j < mb_cols; j++)
805 : {
806 : char zz[4];
807 : int dc_diff = !(mi[mb_index].mbmi.mode != B_PRED &&
808 : mi[mb_index].mbmi.mode != SPLITMV &&
809 : mi[mb_index].mbmi.mb_skip_coeff);
810 :
811 : if (oci->frame_type == KEY_FRAME)
812 : sprintf(zz, "a");
813 : else
814 : sprintf(zz, "%c", dc_diff + '0');
815 :
816 : vp8_blit_text(zz, y_ptr, post->y_stride);
817 : mb_index ++;
818 : y_ptr += 16;
819 : }
820 :
821 : mb_index ++; /* border */
822 : y_ptr += post->y_stride * 16 - post->y_width;
823 :
824 : }
825 : }
826 :
827 : if (flags & VP8D_DEBUG_TXT_RATE_INFO)
828 : {
829 : char message[512];
830 : sprintf(message, "Bitrate: %10.2f frame_rate: %10.2f ", oci->bitrate, oci->framerate);
831 : vp8_blit_text(message, oci->post_proc_buffer.y_buffer, oci->post_proc_buffer.y_stride);
832 : }
833 :
834 : /* Draw motion vectors */
835 : if ((flags & VP8D_DEBUG_DRAW_MV) && ppflags->display_mv_flag)
836 : {
837 : YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
838 : int width = post->y_width;
839 : int height = post->y_height;
840 : unsigned char *y_buffer = oci->post_proc_buffer.y_buffer;
841 : int y_stride = oci->post_proc_buffer.y_stride;
842 : MODE_INFO *mi = oci->mi;
843 : int x0, y0;
844 :
845 : for (y0 = 0; y0 < height; y0 += 16)
846 : {
847 : for (x0 = 0; x0 < width; x0 += 16)
848 : {
849 : int x1, y1;
850 :
851 : if (!(ppflags->display_mv_flag & (1<<mi->mbmi.mode)))
852 : {
853 : mi++;
854 : continue;
855 : }
856 :
857 : if (mi->mbmi.mode == SPLITMV)
858 : {
859 : switch (mi->mbmi.partitioning)
860 : {
861 : case 0 : /* mv_top_bottom */
862 : {
863 : union b_mode_info *bmi = &mi->bmi[0];
864 : MV *mv = &bmi->mv.as_mv;
865 :
866 : x1 = x0 + 8 + (mv->col >> 3);
867 : y1 = y0 + 4 + (mv->row >> 3);
868 :
869 : constrain_line (x0+8, &x1, y0+4, &y1, width, height);
870 : vp8_blit_line (x0+8, x1, y0+4, y1, y_buffer, y_stride);
871 :
872 : bmi = &mi->bmi[8];
873 :
874 : x1 = x0 + 8 + (mv->col >> 3);
875 : y1 = y0 +12 + (mv->row >> 3);
876 :
877 : constrain_line (x0+8, &x1, y0+12, &y1, width, height);
878 : vp8_blit_line (x0+8, x1, y0+12, y1, y_buffer, y_stride);
879 :
880 : break;
881 : }
882 : case 1 : /* mv_left_right */
883 : {
884 : union b_mode_info *bmi = &mi->bmi[0];
885 : MV *mv = &bmi->mv.as_mv;
886 :
887 : x1 = x0 + 4 + (mv->col >> 3);
888 : y1 = y0 + 8 + (mv->row >> 3);
889 :
890 : constrain_line (x0+4, &x1, y0+8, &y1, width, height);
891 : vp8_blit_line (x0+4, x1, y0+8, y1, y_buffer, y_stride);
892 :
893 : bmi = &mi->bmi[2];
894 :
895 : x1 = x0 +12 + (mv->col >> 3);
896 : y1 = y0 + 8 + (mv->row >> 3);
897 :
898 : constrain_line (x0+12, &x1, y0+8, &y1, width, height);
899 : vp8_blit_line (x0+12, x1, y0+8, y1, y_buffer, y_stride);
900 :
901 : break;
902 : }
903 : case 2 : /* mv_quarters */
904 : {
905 : union b_mode_info *bmi = &mi->bmi[0];
906 : MV *mv = &bmi->mv.as_mv;
907 :
908 : x1 = x0 + 4 + (mv->col >> 3);
909 : y1 = y0 + 4 + (mv->row >> 3);
910 :
911 : constrain_line (x0+4, &x1, y0+4, &y1, width, height);
912 : vp8_blit_line (x0+4, x1, y0+4, y1, y_buffer, y_stride);
913 :
914 : bmi = &mi->bmi[2];
915 :
916 : x1 = x0 +12 + (mv->col >> 3);
917 : y1 = y0 + 4 + (mv->row >> 3);
918 :
919 : constrain_line (x0+12, &x1, y0+4, &y1, width, height);
920 : vp8_blit_line (x0+12, x1, y0+4, y1, y_buffer, y_stride);
921 :
922 : bmi = &mi->bmi[8];
923 :
924 : x1 = x0 + 4 + (mv->col >> 3);
925 : y1 = y0 +12 + (mv->row >> 3);
926 :
927 : constrain_line (x0+4, &x1, y0+12, &y1, width, height);
928 : vp8_blit_line (x0+4, x1, y0+12, y1, y_buffer, y_stride);
929 :
930 : bmi = &mi->bmi[10];
931 :
932 : x1 = x0 +12 + (mv->col >> 3);
933 : y1 = y0 +12 + (mv->row >> 3);
934 :
935 : constrain_line (x0+12, &x1, y0+12, &y1, width, height);
936 : vp8_blit_line (x0+12, x1, y0+12, y1, y_buffer, y_stride);
937 : break;
938 : }
939 : default :
940 : {
941 : union b_mode_info *bmi = mi->bmi;
942 : int bx0, by0;
943 :
944 : for (by0 = y0; by0 < (y0+16); by0 += 4)
945 : {
946 : for (bx0 = x0; bx0 < (x0+16); bx0 += 4)
947 : {
948 : MV *mv = &bmi->mv.as_mv;
949 :
950 : x1 = bx0 + 2 + (mv->col >> 3);
951 : y1 = by0 + 2 + (mv->row >> 3);
952 :
953 : constrain_line (bx0+2, &x1, by0+2, &y1, width, height);
954 : vp8_blit_line (bx0+2, x1, by0+2, y1, y_buffer, y_stride);
955 :
956 : bmi++;
957 : }
958 : }
959 : }
960 : }
961 : }
962 : else if (mi->mbmi.mode >= NEARESTMV)
963 : {
964 : MV *mv = &mi->mbmi.mv.as_mv;
965 : const int lx0 = x0 + 8;
966 : const int ly0 = y0 + 8;
967 :
968 : x1 = lx0 + (mv->col >> 3);
969 : y1 = ly0 + (mv->row >> 3);
970 :
971 : if (x1 != lx0 && y1 != ly0)
972 : {
973 : constrain_line (lx0, &x1, ly0-1, &y1, width, height);
974 : vp8_blit_line (lx0, x1, ly0-1, y1, y_buffer, y_stride);
975 :
976 : constrain_line (lx0, &x1, ly0+1, &y1, width, height);
977 : vp8_blit_line (lx0, x1, ly0+1, y1, y_buffer, y_stride);
978 : }
979 : else
980 : vp8_blit_line (lx0, x1, ly0, y1, y_buffer, y_stride);
981 : }
982 :
983 : mi++;
984 : }
985 : mi++;
986 : }
987 : }
988 :
989 : /* Color in block modes */
990 : if ((flags & VP8D_DEBUG_CLR_BLK_MODES)
991 : && (ppflags->display_mb_modes_flag || ppflags->display_b_modes_flag))
992 : {
993 : int y, x;
994 : YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
995 : int width = post->y_width;
996 : int height = post->y_height;
997 : unsigned char *y_ptr = oci->post_proc_buffer.y_buffer;
998 : unsigned char *u_ptr = oci->post_proc_buffer.u_buffer;
999 : unsigned char *v_ptr = oci->post_proc_buffer.v_buffer;
1000 : int y_stride = oci->post_proc_buffer.y_stride;
1001 : MODE_INFO *mi = oci->mi;
1002 :
1003 : for (y = 0; y < height; y += 16)
1004 : {
1005 : for (x = 0; x < width; x += 16)
1006 : {
1007 : int Y = 0, U = 0, V = 0;
1008 :
1009 : if (mi->mbmi.mode == B_PRED &&
1010 : ((ppflags->display_mb_modes_flag & B_PRED) || ppflags->display_b_modes_flag))
1011 : {
1012 : int by, bx;
1013 : unsigned char *yl, *ul, *vl;
1014 : union b_mode_info *bmi = mi->bmi;
1015 :
1016 : yl = y_ptr + x;
1017 : ul = u_ptr + (x>>1);
1018 : vl = v_ptr + (x>>1);
1019 :
1020 : for (by = 0; by < 16; by += 4)
1021 : {
1022 : for (bx = 0; bx < 16; bx += 4)
1023 : {
1024 : if ((ppflags->display_b_modes_flag & (1<<mi->mbmi.mode))
1025 : || (ppflags->display_mb_modes_flag & B_PRED))
1026 : {
1027 : Y = B_PREDICTION_MODE_colors[bmi->as_mode][0];
1028 : U = B_PREDICTION_MODE_colors[bmi->as_mode][1];
1029 : V = B_PREDICTION_MODE_colors[bmi->as_mode][2];
1030 :
1031 : POSTPROC_INVOKE(RTCD_VTABLE(oci), blend_b)
1032 : (yl+bx, ul+(bx>>1), vl+(bx>>1), Y, U, V, 0xc000, y_stride);
1033 : }
1034 : bmi++;
1035 : }
1036 :
1037 : yl += y_stride*4;
1038 : ul += y_stride*1;
1039 : vl += y_stride*1;
1040 : }
1041 : }
1042 : else if (ppflags->display_mb_modes_flag & (1<<mi->mbmi.mode))
1043 : {
1044 : Y = MB_PREDICTION_MODE_colors[mi->mbmi.mode][0];
1045 : U = MB_PREDICTION_MODE_colors[mi->mbmi.mode][1];
1046 : V = MB_PREDICTION_MODE_colors[mi->mbmi.mode][2];
1047 :
1048 : POSTPROC_INVOKE(RTCD_VTABLE(oci), blend_mb_inner)
1049 : (y_ptr+x, u_ptr+(x>>1), v_ptr+(x>>1), Y, U, V, 0xc000, y_stride);
1050 : }
1051 :
1052 : mi++;
1053 : }
1054 : y_ptr += y_stride*16;
1055 : u_ptr += y_stride*4;
1056 : v_ptr += y_stride*4;
1057 :
1058 : mi++;
1059 : }
1060 : }
1061 :
1062 : /* Color in frame reference blocks */
1063 : if ((flags & VP8D_DEBUG_CLR_FRM_REF_BLKS) && ppflags->display_ref_frame_flag)
1064 : {
1065 : int y, x;
1066 : YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
1067 : int width = post->y_width;
1068 : int height = post->y_height;
1069 : unsigned char *y_ptr = oci->post_proc_buffer.y_buffer;
1070 : unsigned char *u_ptr = oci->post_proc_buffer.u_buffer;
1071 : unsigned char *v_ptr = oci->post_proc_buffer.v_buffer;
1072 : int y_stride = oci->post_proc_buffer.y_stride;
1073 : MODE_INFO *mi = oci->mi;
1074 :
1075 : for (y = 0; y < height; y += 16)
1076 : {
1077 : for (x = 0; x < width; x +=16)
1078 : {
1079 : int Y = 0, U = 0, V = 0;
1080 :
1081 : if (ppflags->display_ref_frame_flag & (1<<mi->mbmi.ref_frame))
1082 : {
1083 : Y = MV_REFERENCE_FRAME_colors[mi->mbmi.ref_frame][0];
1084 : U = MV_REFERENCE_FRAME_colors[mi->mbmi.ref_frame][1];
1085 : V = MV_REFERENCE_FRAME_colors[mi->mbmi.ref_frame][2];
1086 :
1087 : POSTPROC_INVOKE(RTCD_VTABLE(oci), blend_mb_outer)
1088 : (y_ptr+x, u_ptr+(x>>1), v_ptr+(x>>1), Y, U, V, 0xc000, y_stride);
1089 : }
1090 :
1091 : mi++;
1092 : }
1093 : y_ptr += y_stride*16;
1094 : u_ptr += y_stride*4;
1095 : v_ptr += y_stride*4;
1096 :
1097 : mi++;
1098 : }
1099 : }
1100 : #endif
1101 :
1102 0 : *dest = oci->post_proc_buffer;
1103 :
1104 : /* handle problem with extending borders */
1105 0 : dest->y_width = oci->Width;
1106 0 : dest->y_height = oci->Height;
1107 0 : dest->uv_height = dest->y_height / 2;
1108 0 : return 0;
1109 : }
|