2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
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.
12 #include "vpx_ports/config.h"
13 #include "vpx_scale/yv12config.h"
15 #include "vpx_scale/yv12extend.h"
16 #include "vpx_scale/vpxscale.h"
17 #include "systemdependent.h"
24 static const short kernel5[] =
29 const short vp8_rv[] =
31 8, 5, 2, 2, 8, 12, 4, 9, 8, 3,
32 0, 3, 9, 0, 0, 0, 8, 3, 14, 4,
33 10, 1, 11, 14, 1, 14, 9, 6, 12, 11,
34 8, 6, 10, 0, 0, 8, 9, 0, 3, 14,
35 8, 11, 13, 4, 2, 9, 0, 3, 9, 6,
36 1, 2, 3, 14, 13, 1, 8, 2, 9, 7,
37 3, 3, 1, 13, 13, 6, 6, 5, 2, 7,
38 11, 9, 11, 8, 7, 3, 2, 0, 13, 13,
39 14, 4, 12, 5, 12, 10, 8, 10, 13, 10,
40 4, 14, 4, 10, 0, 8, 11, 1, 13, 7,
41 7, 14, 6, 14, 13, 2, 13, 5, 4, 4,
42 0, 10, 0, 5, 13, 2, 12, 7, 11, 13,
43 8, 0, 4, 10, 7, 2, 7, 2, 2, 5,
44 3, 4, 7, 3, 3, 14, 14, 5, 9, 13,
45 3, 14, 3, 6, 3, 0, 11, 8, 13, 1,
46 13, 1, 12, 0, 10, 9, 7, 6, 2, 8,
47 5, 2, 13, 7, 1, 13, 14, 7, 6, 7,
48 9, 6, 10, 11, 7, 8, 7, 5, 14, 8,
49 4, 4, 0, 8, 7, 10, 0, 8, 14, 11,
50 3, 12, 5, 7, 14, 3, 14, 5, 2, 6,
51 11, 12, 12, 8, 0, 11, 13, 1, 2, 0,
52 5, 10, 14, 7, 8, 0, 4, 11, 0, 8,
53 0, 3, 10, 5, 8, 0, 11, 6, 7, 8,
54 10, 7, 13, 9, 2, 5, 1, 5, 10, 2,
55 4, 3, 5, 6, 10, 8, 9, 4, 11, 14,
56 0, 10, 0, 5, 13, 2, 12, 7, 11, 13,
57 8, 0, 4, 10, 7, 2, 7, 2, 2, 5,
58 3, 4, 7, 3, 3, 14, 14, 5, 9, 13,
59 3, 14, 3, 6, 3, 0, 11, 8, 13, 1,
60 13, 1, 12, 0, 10, 9, 7, 6, 2, 8,
61 5, 2, 13, 7, 1, 13, 14, 7, 6, 7,
62 9, 6, 10, 11, 7, 8, 7, 5, 14, 8,
63 4, 4, 0, 8, 7, 10, 0, 8, 14, 11,
64 3, 12, 5, 7, 14, 3, 14, 5, 2, 6,
65 11, 12, 12, 8, 0, 11, 13, 1, 2, 0,
66 5, 10, 14, 7, 8, 0, 4, 11, 0, 8,
67 0, 3, 10, 5, 8, 0, 11, 6, 7, 8,
68 10, 7, 13, 9, 2, 5, 1, 5, 10, 2,
69 4, 3, 5, 6, 10, 8, 9, 4, 11, 14,
70 3, 8, 3, 7, 8, 5, 11, 4, 12, 3,
71 11, 9, 14, 8, 14, 13, 4, 3, 1, 2,
72 14, 6, 5, 4, 4, 11, 4, 6, 2, 1,
73 5, 8, 8, 12, 13, 5, 14, 10, 12, 13,
74 0, 9, 5, 5, 11, 10, 13, 9, 10, 13,
78 extern void vp8_blit_text(const char *msg, unsigned char *address, const int pitch);
79 extern void vp8_blit_line(int x0, int x1, int y0, int y1, unsigned char *image, const int pitch);
80 /***********************************************************************************************************
82 void vp8_post_proc_down_and_across_c
84 unsigned char *src_ptr,
85 unsigned char *dst_ptr,
86 int src_pixels_per_line,
87 int dst_pixels_per_line,
93 unsigned char *p_src, *p_dst;
98 int pitch = src_pixels_per_line;
100 (void)dst_pixels_per_line;
102 for (row = 0; row < rows; row++)
104 // post_proc_down for one row
108 for (col = 0; col < cols; col++)
114 for (i = -2; i <= 2; i++)
116 if (abs(v - p_src[col+i*pitch]) > flimit)
117 goto down_skip_convolve;
119 kernel += kernel5[2+i] * p_src[col+i*pitch];
127 // now post_proc_across
131 for (i = 0; i < 8; i++)
134 for (col = 0; col < cols; col++)
141 for (i = -2; i <= 2; i++)
143 if (abs(v - p_src[col+i]) > flimit)
144 goto across_skip_convolve;
146 kernel += kernel5[2+i] * p_src[col+i];
149 d[col&7] = (kernel >> 3);
150 across_skip_convolve:
153 p_dst[col-2] = d[(col-2)&7];
156 //handle the last two pixels
157 p_dst[col-2] = d[(col-2)&7];
158 p_dst[col-1] = d[(col-1)&7];
171 x = 50 + (x - 50) * 10 / 8;
174 void vp8_mbpost_proc_across_ip_c(unsigned char *src, int pitch, int rows, int cols, int flimit)
178 unsigned char *s = src;
182 for (r = 0; r < rows; r++)
187 for (i = -8; i <= 6; i++)
189 sumsq += s[i] * s[i];
194 for (c = 0; c < cols + 8; c++)
196 int x = s[c+7] - s[c-8];
197 int y = s[c+7] + s[c-8];
204 if (sumsq * 15 - sum * sum < flimit)
206 d[c&15] = (8 + sum + s[c]) >> 4;
209 s[c-8] = d[(c-8)&15];
220 void vp8_mbpost_proc_down_c(unsigned char *dst, int pitch, int rows, int cols, int flimit)
223 const short *rv3 = &vp8_rv[63&rand()];
225 for (c = 0; c < cols; c++)
227 unsigned char *s = &dst[c];
231 const short *rv2 = rv3 + ((c * 17) & 127);
233 for (i = -8; i <= 6; i++)
235 sumsq += s[i*pitch] * s[i*pitch];
239 for (r = 0; r < rows + 8; r++)
241 sumsq += s[7*pitch] * s[ 7*pitch] - s[-8*pitch] * s[-8*pitch];
242 sum += s[7*pitch] - s[-8*pitch];
245 if (sumsq * 15 - sum * sum < flimit)
247 d[r&15] = (rv2[r&127] + sum + s[0]) >> 4;
250 s[-8*pitch] = d[(r-8)&15];
257 static void vp8_deblock_and_de_macro_block(YV12_BUFFER_CONFIG *source,
258 YV12_BUFFER_CONFIG *post,
262 vp8_postproc_rtcd_vtable_t *rtcd)
264 double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
265 int ppl = (int)(level + .5);
266 (void) low_var_thresh;
269 POSTPROC_INVOKE(rtcd, downacross)(source->y_buffer, post->y_buffer, source->y_stride, post->y_stride, source->y_height, source->y_width, ppl);
270 POSTPROC_INVOKE(rtcd, across)(post->y_buffer, post->y_stride, post->y_height, post->y_width, vp8_q2mbl(q));
271 POSTPROC_INVOKE(rtcd, down)(post->y_buffer, post->y_stride, post->y_height, post->y_width, vp8_q2mbl(q));
273 POSTPROC_INVOKE(rtcd, downacross)(source->u_buffer, post->u_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl);
274 POSTPROC_INVOKE(rtcd, downacross)(source->v_buffer, post->v_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl);
278 void vp8_deblock(YV12_BUFFER_CONFIG *source,
279 YV12_BUFFER_CONFIG *post,
283 vp8_postproc_rtcd_vtable_t *rtcd)
285 double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
286 int ppl = (int)(level + .5);
287 (void) low_var_thresh;
290 POSTPROC_INVOKE(rtcd, downacross)(source->y_buffer, post->y_buffer, source->y_stride, post->y_stride, source->y_height, source->y_width, ppl);
291 POSTPROC_INVOKE(rtcd, downacross)(source->u_buffer, post->u_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl);
292 POSTPROC_INVOKE(rtcd, downacross)(source->v_buffer, post->v_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl);
295 void vp8_de_noise(YV12_BUFFER_CONFIG *source,
296 YV12_BUFFER_CONFIG *post,
300 vp8_postproc_rtcd_vtable_t *rtcd)
302 double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
303 int ppl = (int)(level + .5);
305 (void) low_var_thresh;
308 POSTPROC_INVOKE(rtcd, downacross)(
309 source->y_buffer + 2 * source->y_stride + 2,
310 source->y_buffer + 2 * source->y_stride + 2,
313 source->y_height - 4,
316 POSTPROC_INVOKE(rtcd, downacross)(
317 source->u_buffer + 2 * source->uv_stride + 2,
318 source->u_buffer + 2 * source->uv_stride + 2,
321 source->uv_height - 4,
322 source->uv_width - 4, ppl);
323 POSTPROC_INVOKE(rtcd, downacross)(
324 source->v_buffer + 2 * source->uv_stride + 2,
325 source->v_buffer + 2 * source->uv_stride + 2,
328 source->uv_height - 4,
329 source->uv_width - 4, ppl);
333 double vp8_gaussian(double sigma, double mu, double x)
335 return 1 / (sigma * sqrt(2.0 * 3.14159265)) *
336 (exp(-(x - mu) * (x - mu) / (2 * sigma * sigma)));
339 extern void (*vp8_clear_system_state)(void);
342 static void fillrd(struct postproc_state *state, int q, int a)
347 int ai = a, qi = q, i;
349 vp8_clear_system_state();
352 sigma = ai + .5 + .6 * (63 - qi) / 63.0;
354 // set up a lookup table of 256 entries that matches
355 // a gaussian distribution with sigma determined by q.
363 for (i = -32; i < 32; i++)
365 int a = (int)(.5 + 256 * vp8_gaussian(sigma, 0, i));
369 for (j = 0; j < a; j++)
371 char_dist[next+j] = (char) i;
379 for (next = next; next < 256; next++)
384 for (i = 0; i < 3072; i++)
386 state->noise[i] = char_dist[rand() & 0xff];
389 for (i = 0; i < 16; i++)
391 state->blackclamp[i] = -char_dist[0];
392 state->whiteclamp[i] = -char_dist[0];
393 state->bothclamp[i] = -2 * char_dist[0];
397 state->last_noise = a;
400 /****************************************************************************
402 * ROUTINE : plane_add_noise_c
404 * INPUTS : unsigned char *Start starting address of buffer to add gaussian
406 * unsigned int Width width of plane
407 * unsigned int Height height of plane
408 * int Pitch distance between subsequent lines of frame
409 * int q quantizer used to determine amount of noise
416 * FUNCTION : adds gaussian noise to a plane of pixels
418 * SPECIAL NOTES : None.
420 ****************************************************************************/
421 void vp8_plane_add_noise_c(unsigned char *Start, char *noise,
425 unsigned int Width, unsigned int Height, int Pitch)
429 for (i = 0; i < Height; i++)
431 unsigned char *Pos = Start + i * Pitch;
432 char *Ref = (char *)(noise + (rand() & 0xff));
434 for (j = 0; j < Width; j++)
436 if (Pos[j] < blackclamp[0])
437 Pos[j] = blackclamp[0];
439 if (Pos[j] > 255 + whiteclamp[0])
440 Pos[j] = 255 + whiteclamp[0];
447 #if CONFIG_RUNTIME_CPU_DETECT
448 #define RTCD_VTABLE(oci) (&(oci)->rtcd.postproc)
450 #define RTCD_VTABLE(oci) NULL
453 static void constrain_line (int x0, int *x1, int y0, int *y1, int width, int height)
462 *y1 = ((width-x0)*dy)/dx + y0;
470 *y1 = ((0-x0)*dy)/dx + y0;
478 *x1 = ((height-y0)*dx)/dy + x0;
486 *x1 = ((0-y0)*dx)/dy + x0;
492 int vp8_post_proc_frame(VP8_COMMON *oci, YV12_BUFFER_CONFIG *dest, int deblock_level, int noise_level, int flags)
495 int q = oci->filter_level * 10 / 6;
497 if (!oci->frame_to_show)
505 *dest = *oci->frame_to_show;
507 // handle problem with extending borders
508 dest->y_width = oci->Width;
509 dest->y_height = oci->Height;
510 dest->uv_height = dest->y_height / 2;
515 #if ARCH_X86||ARCH_X86_64
516 vpx_reset_mmx_state();
519 if (flags & VP8D_DEMACROBLOCK)
521 vp8_deblock_and_de_macro_block(oci->frame_to_show, &oci->post_proc_buffer,
522 q + (deblock_level - 5) * 10, 1, 0, RTCD_VTABLE(oci));
524 else if (flags & VP8D_DEBLOCK)
526 vp8_deblock(oci->frame_to_show, &oci->post_proc_buffer,
527 q, 1, 0, RTCD_VTABLE(oci));
531 vp8_yv12_copy_frame_ptr(oci->frame_to_show, &oci->post_proc_buffer);
534 if (flags & VP8D_ADDNOISE)
536 if (oci->postproc_state.last_q != q
537 || oci->postproc_state.last_noise != noise_level)
539 fillrd(&oci->postproc_state, 63 - q, noise_level);
542 POSTPROC_INVOKE(RTCD_VTABLE(oci), addnoise)
543 (oci->post_proc_buffer.y_buffer,
544 oci->postproc_state.noise,
545 oci->postproc_state.blackclamp,
546 oci->postproc_state.whiteclamp,
547 oci->postproc_state.bothclamp,
548 oci->post_proc_buffer.y_width, oci->post_proc_buffer.y_height,
549 oci->post_proc_buffer.y_stride);
552 if (flags & VP8D_DEBUG_LEVEL1)
554 sprintf(message, "F%1dG%1dQ%3dF%3dP%d_s%dx%d",
555 (oci->frame_type == KEY_FRAME),
556 oci->refresh_golden_frame,
560 oci->mb_cols, oci->mb_rows);
561 vp8_blit_text(message, oci->post_proc_buffer.y_buffer, oci->post_proc_buffer.y_stride);
563 else if (flags & VP8D_DEBUG_LEVEL2)
566 unsigned char *y_ptr;
567 YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
568 int mb_rows = post->y_height >> 4;
569 int mb_cols = post->y_width >> 4;
571 MODE_INFO *mi = oci->mi;
573 y_ptr = post->y_buffer + 4 * post->y_stride + 4;
575 // vp8_filter each macro block
576 for (i = 0; i < mb_rows; i++)
578 for (j = 0; j < mb_cols; j++)
582 sprintf(zz, "%c", mi[mb_index].mbmi.mode + 'a');
584 vp8_blit_text(zz, y_ptr, post->y_stride);
589 mb_index ++; //border
590 y_ptr += post->y_stride * 16 - post->y_width;
594 else if (flags & VP8D_DEBUG_LEVEL3)
597 unsigned char *y_ptr;
598 YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
599 int mb_rows = post->y_height >> 4;
600 int mb_cols = post->y_width >> 4;
602 MODE_INFO *mi = oci->mi;
604 y_ptr = post->y_buffer + 4 * post->y_stride + 4;
606 // vp8_filter each macro block
607 for (i = 0; i < mb_rows; i++)
609 for (j = 0; j < mb_cols; j++)
613 if (oci->frame_type == KEY_FRAME)
616 sprintf(zz, "%c", mi[mb_index].mbmi.dc_diff + '0');
618 vp8_blit_text(zz, y_ptr, post->y_stride);
623 mb_index ++; //border
624 y_ptr += post->y_stride * 16 - post->y_width;
628 else if (flags & VP8D_DEBUG_LEVEL4)
630 sprintf(message, "Bitrate: %10.2f frame_rate: %10.2f ", oci->bitrate, oci->framerate);
631 vp8_blit_text(message, oci->post_proc_buffer.y_buffer, oci->post_proc_buffer.y_stride);
634 unsigned char *y_ptr;
635 YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
636 int mb_rows = post->y_height >> 4;
637 int mb_cols = post->y_width >> 4;
639 MODE_INFO *mi = oci->mi;
641 y_ptr = post->y_buffer + 4 * post->y_stride + 4;
643 // vp8_filter each macro block
644 for (i = 0; i < mb_rows; i++)
646 for (j = 0; j < mb_cols; j++)
650 sprintf(zz, "%c", mi[mb_index].mbmi.dc_diff + '0');
651 vp8_blit_text(zz, y_ptr, post->y_stride);
656 mb_index ++; //border
657 y_ptr += post->y_stride * 16 - post->y_width;
664 else if (flags & VP8D_DEBUG_LEVEL5)
666 YV12_BUFFER_CONFIG *post = &oci->post_proc_buffer;
667 int width = post->y_width;
668 int height = post->y_height;
669 int mb_cols = width >> 4;
670 unsigned char *y_buffer = oci->post_proc_buffer.y_buffer;
671 int y_stride = oci->post_proc_buffer.y_stride;
672 MODE_INFO *mi = oci->mi;
675 for (y0 = 8; y0 < (height + 8); y0 += 16)
677 for (x0 = 8; x0 < (width + 8); x0 += 16)
680 if (mi->mbmi.mode >= NEARESTMV)
682 MV *mv = &mi->mbmi.mv.as_mv;
684 x1 = x0 + (mv->col >> 3);
685 y1 = y0 + (mv->row >> 3);
687 constrain_line (x0, &x1, y0, &y1, width, height);
688 vp8_blit_line (x0, x1, y0, y1, y_buffer, y_stride);
696 *dest = oci->post_proc_buffer;
698 // handle problem with extending borders
699 dest->y_width = oci->Width;
700 dest->y_height = oci->Height;
701 dest->uv_height = dest->y_height / 2;