]> granicus.if.org Git - libvpx/blob - vp8/common/postproc.c
Merge commit 'refs/changes/09/809/1' of https://review.webmproject.org/p/libvpx
[libvpx] / vp8 / common / postproc.c
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 // global constants
23
24 static const short kernel5[] =
25 {
26     1, 1, 4, 1, 1
27 };
28
29 const short vp8_rv[] =
30 {
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,
75 };
76
77
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 /***********************************************************************************************************
81  */
82 void vp8_post_proc_down_and_across_c
83 (
84     unsigned char *src_ptr,
85     unsigned char *dst_ptr,
86     int src_pixels_per_line,
87     int dst_pixels_per_line,
88     int rows,
89     int cols,
90     int flimit
91 )
92 {
93     unsigned char *p_src, *p_dst;
94     int row;
95     int col;
96     int i;
97     int v;
98     int pitch = src_pixels_per_line;
99     unsigned char d[8];
100     (void)dst_pixels_per_line;
101
102     for (row = 0; row < rows; row++)
103     {
104         // post_proc_down for one row
105         p_src = src_ptr;
106         p_dst = dst_ptr;
107
108         for (col = 0; col < cols; col++)
109         {
110
111             int kernel = 4;
112             int v = p_src[col];
113
114             for (i = -2; i <= 2; i++)
115             {
116                 if (abs(v - p_src[col+i*pitch]) > flimit)
117                     goto down_skip_convolve;
118
119                 kernel += kernel5[2+i] * p_src[col+i*pitch];
120             }
121
122             v = (kernel >> 3);
123         down_skip_convolve:
124             p_dst[col] = v;
125         }
126
127         // now post_proc_across
128         p_src = dst_ptr;
129         p_dst = dst_ptr;
130
131         for (i = 0; i < 8; i++)
132             d[i] = p_src[i];
133
134         for (col = 0; col < cols; col++)
135         {
136             int kernel = 4;
137             v = p_src[col];
138
139             d[col&7] = v;
140
141             for (i = -2; i <= 2; i++)
142             {
143                 if (abs(v - p_src[col+i]) > flimit)
144                     goto across_skip_convolve;
145
146                 kernel += kernel5[2+i] * p_src[col+i];
147             }
148
149             d[col&7] = (kernel >> 3);
150         across_skip_convolve:
151
152             if (col >= 2)
153                 p_dst[col-2] = d[(col-2)&7];
154         }
155
156         //handle the last two pixels
157         p_dst[col-2] = d[(col-2)&7];
158         p_dst[col-1] = d[(col-1)&7];
159
160
161         //next row
162         src_ptr += pitch;
163         dst_ptr += pitch;
164     }
165 }
166
167 int vp8_q2mbl(int x)
168 {
169     if (x < 20) x = 20;
170
171     x = 50 + (x - 50) * 10 / 8;
172     return x * x / 3;
173 }
174 void vp8_mbpost_proc_across_ip_c(unsigned char *src, int pitch, int rows, int cols, int flimit)
175 {
176     int r, c, i;
177
178     unsigned char *s = src;
179     unsigned char d[16];
180
181
182     for (r = 0; r < rows; r++)
183     {
184         int sumsq = 0;
185         int sum   = 0;
186
187         for (i = -8; i <= 6; i++)
188         {
189             sumsq += s[i] * s[i];
190             sum   += s[i];
191             d[i+8] = 0;
192         }
193
194         for (c = 0; c < cols + 8; c++)
195         {
196             int x = s[c+7] - s[c-8];
197             int y = s[c+7] + s[c-8];
198
199             sum  += x;
200             sumsq += x * y;
201
202             d[c&15] = s[c];
203
204             if (sumsq * 15 - sum * sum < flimit)
205             {
206                 d[c&15] = (8 + sum + s[c]) >> 4;
207             }
208
209             s[c-8] = d[(c-8)&15];
210         }
211
212         s += pitch;
213     }
214 }
215
216
217
218
219
220 void vp8_mbpost_proc_down_c(unsigned char *dst, int pitch, int rows, int cols, int flimit)
221 {
222     int r, c, i;
223     const short *rv3 = &vp8_rv[63&rand()];
224
225     for (c = 0; c < cols; c++)
226     {
227         unsigned char *s = &dst[c];
228         int sumsq = 0;
229         int sum   = 0;
230         unsigned char d[16];
231         const short *rv2 = rv3 + ((c * 17) & 127);
232
233         for (i = -8; i <= 6; i++)
234         {
235             sumsq += s[i*pitch] * s[i*pitch];
236             sum   += s[i*pitch];
237         }
238
239         for (r = 0; r < rows + 8; r++)
240         {
241             sumsq += s[7*pitch] * s[ 7*pitch] - s[-8*pitch] * s[-8*pitch];
242             sum  += s[7*pitch] - s[-8*pitch];
243             d[r&15] = s[0];
244
245             if (sumsq * 15 - sum * sum < flimit)
246             {
247                 d[r&15] = (rv2[r&127] + sum + s[0]) >> 4;
248             }
249
250             s[-8*pitch] = d[(r-8)&15];
251             s += pitch;
252         }
253     }
254 }
255
256
257 static void vp8_deblock_and_de_macro_block(YV12_BUFFER_CONFIG         *source,
258         YV12_BUFFER_CONFIG         *post,
259         int                         q,
260         int                         low_var_thresh,
261         int                         flag,
262         vp8_postproc_rtcd_vtable_t *rtcd)
263 {
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;
267     (void) flag;
268
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));
272
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);
275
276 }
277
278 void vp8_deblock(YV12_BUFFER_CONFIG         *source,
279                         YV12_BUFFER_CONFIG         *post,
280                         int                         q,
281                         int                         low_var_thresh,
282                         int                         flag,
283                         vp8_postproc_rtcd_vtable_t *rtcd)
284 {
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;
288     (void) flag;
289
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);
293 }
294
295 void vp8_de_noise(YV12_BUFFER_CONFIG         *source,
296                   YV12_BUFFER_CONFIG         *post,
297                   int                         q,
298                   int                         low_var_thresh,
299                   int                         flag,
300                   vp8_postproc_rtcd_vtable_t *rtcd)
301 {
302     double level = 6.0e-05 * q * q * q - .0067 * q * q + .306 * q + .0065;
303     int ppl = (int)(level + .5);
304     (void) post;
305     (void) low_var_thresh;
306     (void) flag;
307
308     POSTPROC_INVOKE(rtcd, downacross)(
309         source->y_buffer + 2 * source->y_stride + 2,
310         source->y_buffer + 2 * source->y_stride + 2,
311         source->y_stride,
312         source->y_stride,
313         source->y_height - 4,
314         source->y_width - 4,
315         ppl);
316     POSTPROC_INVOKE(rtcd, downacross)(
317         source->u_buffer + 2 * source->uv_stride + 2,
318         source->u_buffer + 2 * source->uv_stride + 2,
319         source->uv_stride,
320         source->uv_stride,
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,
326         source->uv_stride,
327         source->uv_stride,
328         source->uv_height - 4,
329         source->uv_width - 4, ppl);
330
331 }
332
333 double vp8_gaussian(double sigma, double mu, double x)
334 {
335     return 1 / (sigma * sqrt(2.0 * 3.14159265)) *
336            (exp(-(x - mu) * (x - mu) / (2 * sigma * sigma)));
337 }
338
339 extern void (*vp8_clear_system_state)(void);
340
341
342 static void fillrd(struct postproc_state *state, int q, int a)
343 {
344     char char_dist[300];
345
346     double sigma;
347     int ai = a, qi = q, i;
348
349     vp8_clear_system_state();
350
351
352     sigma = ai + .5 + .6 * (63 - qi) / 63.0;
353
354     // set up a lookup table of 256 entries that matches
355     // a gaussian distribution with sigma determined by q.
356     //
357     {
358         double i;
359         int next, j;
360
361         next = 0;
362
363         for (i = -32; i < 32; i++)
364         {
365             int a = (int)(.5 + 256 * vp8_gaussian(sigma, 0, i));
366
367             if (a)
368             {
369                 for (j = 0; j < a; j++)
370                 {
371                     char_dist[next+j] = (char) i;
372                 }
373
374                 next = next + j;
375             }
376
377         }
378
379         for (next = next; next < 256; next++)
380             char_dist[next] = 0;
381
382     }
383
384     for (i = 0; i < 3072; i++)
385     {
386         state->noise[i] = char_dist[rand() & 0xff];
387     }
388
389     for (i = 0; i < 16; i++)
390     {
391         state->blackclamp[i] = -char_dist[0];
392         state->whiteclamp[i] = -char_dist[0];
393         state->bothclamp[i] = -2 * char_dist[0];
394     }
395
396     state->last_q = q;
397     state->last_noise = a;
398 }
399
400 /****************************************************************************
401  *
402  *  ROUTINE       : plane_add_noise_c
403  *
404  *  INPUTS        : unsigned char *Start    starting address of buffer to add gaussian
405  *                                  noise to
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
410  *                                  to add
411  *
412  *  OUTPUTS       : None.
413  *
414  *  RETURNS       : void.
415  *
416  *  FUNCTION      : adds gaussian noise to a plane of pixels
417  *
418  *  SPECIAL NOTES : None.
419  *
420  ****************************************************************************/
421 void vp8_plane_add_noise_c(unsigned char *Start, char *noise,
422                            char blackclamp[16],
423                            char whiteclamp[16],
424                            char bothclamp[16],
425                            unsigned int Width, unsigned int Height, int Pitch)
426 {
427     unsigned int i, j;
428
429     for (i = 0; i < Height; i++)
430     {
431         unsigned char *Pos = Start + i * Pitch;
432         char  *Ref = (char *)(noise + (rand() & 0xff));
433
434         for (j = 0; j < Width; j++)
435         {
436             if (Pos[j] < blackclamp[0])
437                 Pos[j] = blackclamp[0];
438
439             if (Pos[j] > 255 + whiteclamp[0])
440                 Pos[j] = 255 + whiteclamp[0];
441
442             Pos[j] += Ref[j];
443         }
444     }
445 }
446
447 #if CONFIG_RUNTIME_CPU_DETECT
448 #define RTCD_VTABLE(oci) (&(oci)->rtcd.postproc)
449 #else
450 #define RTCD_VTABLE(oci) NULL
451 #endif
452
453 static void constrain_line (int x0, int *x1, int y0, int *y1, int width, int height)
454 {
455     int dx = *x1 - x0;
456     int dy = *y1 - y0;
457
458     if (*x1 > width)
459     {
460         *x1 = width;
461         if (dy)
462             *y1 = ((width-x0)*dy)/dx + y0;
463         dx = *x1 - x0;
464         dy = *y1 - y0;
465     }
466     if (*x1 < 0)
467     {
468         *x1 = 0;
469         if (dy)
470             *y1 = ((0-x0)*dy)/dx + y0;
471         dx = *x1 - x0;
472         dy = *y1 - y0;
473     }
474     if (*y1 > height)
475     {
476         *y1 = height;
477         if (dx)
478             *x1 = ((height-y0)*dx)/dy + x0;
479         dx = *x1 - x0;
480         dy = *y1 - y0;
481     }
482     if (*y1 < 0)
483     {
484         *y1 = 0;
485         if (dx)
486             *x1 = ((0-y0)*dx)/dy + x0;
487         dx = *x1 - x0;
488         dy = *y1 - y0;
489     }
490 }
491
492 int vp8_post_proc_frame(VP8_COMMON *oci, YV12_BUFFER_CONFIG *dest, int deblock_level, int noise_level, int flags)
493 {
494     char message[512];
495     int q = oci->filter_level * 10 / 6;
496
497     if (!oci->frame_to_show)
498         return -1;
499
500     if (q > 63)
501         q = 63;
502
503     if (!flags)
504     {
505         *dest = *oci->frame_to_show;
506
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;
511         return 0;
512
513     }
514
515 #if ARCH_X86||ARCH_X86_64
516     vpx_reset_mmx_state();
517 #endif
518
519     if (flags & VP8D_DEMACROBLOCK)
520     {
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));
523     }
524     else if (flags & VP8D_DEBLOCK)
525     {
526         vp8_deblock(oci->frame_to_show, &oci->post_proc_buffer,
527                     q, 1, 0, RTCD_VTABLE(oci));
528     }
529     else
530     {
531         vp8_yv12_copy_frame_ptr(oci->frame_to_show, &oci->post_proc_buffer);
532     }
533
534     if (flags & VP8D_ADDNOISE)
535     {
536         if (oci->postproc_state.last_q != q
537             || oci->postproc_state.last_noise != noise_level)
538         {
539             fillrd(&oci->postproc_state, 63 - q, noise_level);
540         }
541
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);
550     }
551
552     if (flags & VP8D_DEBUG_LEVEL1)
553     {
554         sprintf(message, "F%1dG%1dQ%3dF%3dP%d_s%dx%d",
555                 (oci->frame_type == KEY_FRAME),
556                 oci->refresh_golden_frame,
557                 oci->base_qindex,
558                 oci->filter_level,
559                 flags,
560                 oci->mb_cols, oci->mb_rows);
561         vp8_blit_text(message, oci->post_proc_buffer.y_buffer, oci->post_proc_buffer.y_stride);
562     }
563     else if (flags & VP8D_DEBUG_LEVEL2)
564     {
565         int i, j;
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;
570         int mb_index = 0;
571         MODE_INFO *mi = oci->mi;
572
573         y_ptr = post->y_buffer + 4 * post->y_stride + 4;
574
575         // vp8_filter each macro block
576         for (i = 0; i < mb_rows; i++)
577         {
578             for (j = 0; j < mb_cols; j++)
579             {
580                 char zz[4];
581
582                 sprintf(zz, "%c", mi[mb_index].mbmi.mode + 'a');
583
584                 vp8_blit_text(zz, y_ptr, post->y_stride);
585                 mb_index ++;
586                 y_ptr += 16;
587             }
588
589             mb_index ++; //border
590             y_ptr += post->y_stride  * 16 - post->y_width;
591
592         }
593     }
594     else if (flags & VP8D_DEBUG_LEVEL3)
595     {
596         int i, j;
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;
601         int mb_index = 0;
602         MODE_INFO *mi = oci->mi;
603
604         y_ptr = post->y_buffer + 4 * post->y_stride + 4;
605
606         // vp8_filter each macro block
607         for (i = 0; i < mb_rows; i++)
608         {
609             for (j = 0; j < mb_cols; j++)
610             {
611                 char zz[4];
612
613                 if (oci->frame_type == KEY_FRAME)
614                     sprintf(zz, "a");
615                 else
616                     sprintf(zz, "%c", mi[mb_index].mbmi.dc_diff + '0');
617
618                 vp8_blit_text(zz, y_ptr, post->y_stride);
619                 mb_index ++;
620                 y_ptr += 16;
621             }
622
623             mb_index ++; //border
624             y_ptr += post->y_stride  * 16 - post->y_width;
625
626         }
627     }
628     else if (flags & VP8D_DEBUG_LEVEL4)
629     {
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);
632 #if 0
633         int i, j;
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;
638         int mb_index = 0;
639         MODE_INFO *mi = oci->mi;
640
641         y_ptr = post->y_buffer + 4 * post->y_stride + 4;
642
643         // vp8_filter each macro block
644         for (i = 0; i < mb_rows; i++)
645         {
646             for (j = 0; j < mb_cols; j++)
647             {
648                 char zz[4];
649
650                 sprintf(zz, "%c", mi[mb_index].mbmi.dc_diff + '0');
651                 vp8_blit_text(zz, y_ptr, post->y_stride);
652                 mb_index ++;
653                 y_ptr += 16;
654             }
655
656             mb_index ++; //border
657             y_ptr += post->y_stride  * 16 - post->y_width;
658
659         }
660
661 #endif
662
663     }
664     else if (flags & VP8D_DEBUG_LEVEL5)
665     {
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;
673         int x0, y0;
674
675         for (y0 = 8; y0 < (height + 8); y0 += 16)
676         {
677             for (x0 = 8; x0 < (width + 8); x0 += 16)
678             {
679                int x1, y1;
680                if (mi->mbmi.mode >= NEARESTMV)
681                 {
682                     MV *mv = &mi->mbmi.mv.as_mv;
683
684                     x1 = x0 + (mv->col >> 3);
685                     y1 = y0 + (mv->row >> 3);
686
687                     constrain_line (x0, &x1, y0, &y1, width, height);
688                     vp8_blit_line (x0, x1, y0, y1, y_buffer, y_stride);
689                 }
690                 mi++;
691             }
692             mi++;
693         }
694     }
695
696     *dest = oci->post_proc_buffer;
697
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;
702     return 0;
703 }