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/****************************************************************************
13 *
14 *   Module Title :     scale.c
15 *
16 *   Description  :     Image scaling functions.
17 *
18 ***************************************************************************/
19
20/****************************************************************************
21*  Header Files
22****************************************************************************/
23#include "vpx_mem/vpx_mem.h"
24#include "vpx_scale/yv12config.h"
25#include "vpx_scale/scale_mode.h"
26
27/****************************************************************************
28*  Exports
29****************************************************************************/
30#ifndef VPX_NO_GLOBALS
31void (*vp8_vertical_band_4_5_scale)(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) = 0;
32void (*vp8_last_vertical_band_4_5_scale)(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) = 0;
33void (*vp8_vertical_band_2_3_scale)(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) = 0;
34void (*vp8_last_vertical_band_2_3_scale)(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) = 0;
35void (*vp8_vertical_band_3_5_scale)(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) = 0;
36void (*vp8_last_vertical_band_3_5_scale)(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) = 0;
37void (*vp8_vertical_band_3_4_scale)(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) = 0;
38void (*vp8_last_vertical_band_3_4_scale)(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) = 0;
39void (*vp8_horizontal_line_1_2_scale)(const unsigned char *source, unsigned int source_width, unsigned char *dest, unsigned int dest_width) = 0;
40void (*vp8_horizontal_line_3_5_scale)(const unsigned char *source, unsigned int source_width, unsigned char *dest, unsigned int dest_width) = 0;
41void (*vp8_horizontal_line_3_4_scale)(const unsigned char *source, unsigned int source_width, unsigned char *dest, unsigned int dest_width) = 0;
42void (*vp8_horizontal_line_2_3_scale)(const unsigned char *source, unsigned int source_width, unsigned char *dest, unsigned int dest_width) = 0;
43void (*vp8_horizontal_line_4_5_scale)(const unsigned char *source, unsigned int source_width, unsigned char *dest, unsigned int dest_width) = 0;
44void (*vp8_vertical_band_1_2_scale)(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) = 0;
45void (*vp8_last_vertical_band_1_2_scale)(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) = 0;
46
47void (*vp8_vertical_band_5_4_scale)(unsigned char *source, unsigned int src_pitch, unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) = 0;
48void (*vp8_vertical_band_5_3_scale)(unsigned char *source, unsigned int src_pitch, unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) = 0;
49void (*vp8_vertical_band_2_1_scale)(unsigned char *source, unsigned int src_pitch, unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) = 0;
50void (*vp8_vertical_band_2_1_scale_i)(unsigned char *source, unsigned int src_pitch, unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) = 0;
51void (*vp8_horizontal_line_2_1_scale)(const unsigned char *source, unsigned int source_width, unsigned char *dest, unsigned int dest_width) = 0;
52void (*vp8_horizontal_line_5_3_scale)(const unsigned char *source, unsigned int source_width, unsigned char *dest, unsigned int dest_width) = 0;
53void (*vp8_horizontal_line_5_4_scale)(const unsigned char *source, unsigned int source_width, unsigned char *dest, unsigned int dest_width) = 0;
54#else
55# include "vpxscale_nofp.h"
56#endif
57
58typedef struct
59{
60    int     expanded_frame_width;
61    int     expanded_frame_height;
62
63    int HScale;
64    int HRatio;
65    int VScale;
66    int VRatio;
67
68    YV12_BUFFER_CONFIG *src_yuv_config;
69    YV12_BUFFER_CONFIG *dst_yuv_config;
70
71} SCALE_VARS;
72
73/****************************************************************************
74 *
75 *  ROUTINE       :     horizontal_line_copy
76 *
77 *  INPUTS        :     None
78 *
79 *
80 *  OUTPUTS       :     None.
81 *
82 *  RETURNS       :     None
83 *
84 *  FUNCTION      :     1 to 1 scaling up for a horizontal line of pixles
85 *
86 *  SPECIAL NOTES :     None.
87 *
88 *  ERRORS        :     None.
89 *
90 ****************************************************************************/
91static
92void horizontal_line_copy(
93    const unsigned char *source,
94    unsigned int source_width,
95    unsigned char *dest,
96    unsigned int dest_width
97)
98{
99    (void) dest_width;
100
101    duck_memcpy(dest, source, source_width);
102}
103/****************************************************************************
104 *
105 *  ROUTINE       :     null_scale
106 *
107 *  INPUTS        :     None
108 *
109 *
110 *  OUTPUTS       :     None.
111 *
112 *  RETURNS       :     None
113 *
114 *  FUNCTION      :     1 to 1 scaling up for a vertical band
115 *
116 *  SPECIAL NOTES :     None.
117 *
118 *  ERRORS        :     None.
119 *
120 ****************************************************************************/
121static
122void null_scale(
123    unsigned char *dest,
124    unsigned int dest_pitch,
125    unsigned int dest_width
126)
127{
128    (void) dest;
129    (void) dest_pitch;
130    (void) dest_width;
131
132    return;
133}
134
135/****************************************************************************
136 *
137 *  ROUTINE       : scale1d_2t1_i
138 *
139 *  INPUTS        : const unsigned char *source : Pointer to data to be scaled.
140 *                  int source_step              : Number of pixels to step on in source.
141 *                  unsigned int source_scale    : Scale for source (UNUSED).
142 *                  unsigned int source_length   : Length of source (UNUSED).
143 *                  unsigned char *dest         : Pointer to output data array.
144 *                  int dest_step                : Number of pixels to step on in destination.
145 *                  unsigned int dest_scale      : Scale for destination (UNUSED).
146 *                  unsigned int dest_length     : Length of destination.
147 *
148 *  OUTPUTS       : None.
149 *
150 *  RETURNS       : void
151 *
152 *  FUNCTION      : Performs 2-to-1 interpolated scaling.
153 *
154 *  SPECIAL NOTES : None.
155 *
156 ****************************************************************************/
157static
158void scale1d_2t1_i
159(
160    const unsigned char *source,
161    int source_step,
162    unsigned int source_scale,
163    unsigned int source_length,
164    unsigned char *dest,
165    int dest_step,
166    unsigned int dest_scale,
167    unsigned int dest_length
168)
169{
170    unsigned int i, j;
171    unsigned int temp;
172    int source_pitch = source_step;
173    (void) source_length;
174    (void) source_scale;
175    (void) dest_scale;
176
177    source_step *= 2;
178    dest[0] = source[0];
179
180    for (i = dest_step, j = source_step; i < dest_length * dest_step; i += dest_step, j += source_step)
181    {
182        temp = 8;
183        temp += 3 * source[j-source_pitch];
184        temp += 10 * source[j];
185        temp += 3 * source[j+source_pitch];
186        temp >>= 4;
187        dest[i] = (char)(temp);
188    }
189}
190
191/****************************************************************************
192 *
193 *  ROUTINE       : scale1d_2t1_ps
194 *
195 *  INPUTS        : const unsigned char *source : Pointer to data to be scaled.
196 *                  int source_step              : Number of pixels to step on in source.
197 *                  unsigned int source_scale    : Scale for source (UNUSED).
198 *                  unsigned int source_length   : Length of source (UNUSED).
199 *                  unsigned char *dest         : Pointer to output data array.
200 *                  int dest_step                : Number of pixels to step on in destination.
201 *                  unsigned int dest_scale      : Scale for destination (UNUSED).
202 *                  unsigned int dest_length     : Length of destination.
203 *
204 *  OUTPUTS       : None.
205 *
206 *  RETURNS       : void
207 *
208 *  FUNCTION      : Performs 2-to-1 point subsampled scaling.
209 *
210 *  SPECIAL NOTES : None.
211 *
212 ****************************************************************************/
213static
214void scale1d_2t1_ps
215(
216    const unsigned char *source,
217    int source_step,
218    unsigned int source_scale,
219    unsigned int source_length,
220    unsigned char *dest,
221    int dest_step,
222    unsigned int dest_scale,
223    unsigned int dest_length
224)
225{
226    unsigned int i, j;
227
228    (void) source_length;
229    (void) source_scale;
230    (void) dest_scale;
231
232    source_step *= 2;
233    j = 0;
234
235    for (i = 0; i < dest_length * dest_step; i += dest_step, j += source_step)
236        dest[i] = source[j];
237}
238/****************************************************************************
239 *
240 *  ROUTINE       : scale1d_c
241 *
242 *  INPUTS        : const unsigned char *source : Pointer to data to be scaled.
243 *                  int source_step              : Number of pixels to step on in source.
244 *                  unsigned int source_scale    : Scale for source.
245 *                  unsigned int source_length   : Length of source (UNUSED).
246 *                  unsigned char *dest         : Pointer to output data array.
247 *                  int dest_step                : Number of pixels to step on in destination.
248 *                  unsigned int dest_scale      : Scale for destination.
249 *                  unsigned int dest_length     : Length of destination.
250 *
251 *  OUTPUTS       : None.
252 *
253 *  RETURNS       : void
254 *
255 *  FUNCTION      : Performs linear interpolation in one dimension.
256 *
257 *  SPECIAL NOTES : None.
258 *
259 ****************************************************************************/
260static
261void scale1d_c
262(
263    const unsigned char *source,
264    int source_step,
265    unsigned int source_scale,
266    unsigned int source_length,
267    unsigned char *dest,
268    int dest_step,
269    unsigned int dest_scale,
270    unsigned int dest_length
271)
272{
273    unsigned int i;
274    unsigned int round_value = dest_scale / 2;
275    unsigned int left_modifier = dest_scale;
276    unsigned int right_modifier = 0;
277    unsigned char left_pixel = *source;
278    unsigned char right_pixel = *(source + source_step);
279
280    (void) source_length;
281
282    /* These asserts are needed if there are boundary issues... */
283    /*assert ( dest_scale > source_scale );*/
284    /*assert ( (source_length-1) * dest_scale >= (dest_length-1) * source_scale );*/
285
286    for (i = 0; i < dest_length * dest_step; i += dest_step)
287    {
288        dest[i] = (char)((left_modifier * left_pixel + right_modifier * right_pixel + round_value) / dest_scale);
289
290        right_modifier += source_scale;
291
292        while (right_modifier > dest_scale)
293        {
294            right_modifier -= dest_scale;
295            source += source_step;
296            left_pixel = *source;
297            right_pixel = *(source + source_step);
298        }
299
300        left_modifier = dest_scale - right_modifier;
301    }
302}
303
304/****************************************************************************
305 *
306 *  ROUTINE       : Scale2D
307 *
308 *  INPUTS        : const unsigned char *source  : Pointer to data to be scaled.
309 *                  int source_pitch              : Stride of source image.
310 *                  unsigned int source_width     : Width of input image.
311 *                  unsigned int source_height    : Height of input image.
312 *                  unsigned char *dest          : Pointer to output data array.
313 *                  int dest_pitch                : Stride of destination image.
314 *                  unsigned int dest_width       : Width of destination image.
315 *                  unsigned int dest_height      : Height of destination image.
316 *                  unsigned char *temp_area      : Pointer to temp work area.
317 *                  unsigned char temp_area_height : Height of temp work area.
318 *                  unsigned int hscale          : Horizontal scale factor numerator.
319 *                  unsigned int hratio          : Horizontal scale factor denominator.
320 *                  unsigned int vscale          : Vertical scale factor numerator.
321 *                  unsigned int vratio          : Vertical scale factor denominator.
322 *                  unsigned int interlaced      : Interlace flag.
323 *
324 *  OUTPUTS       : None.
325 *
326 *  RETURNS       : void
327 *
328 *  FUNCTION      : Performs 2-tap linear interpolation in two dimensions.
329 *
330 *  SPECIAL NOTES : Expansion is performed one band at a time to help with
331 *                  caching.
332 *
333 ****************************************************************************/
334static
335void Scale2D
336(
337    /*const*/
338    unsigned char *source,
339    int source_pitch,
340    unsigned int source_width,
341    unsigned int source_height,
342    unsigned char *dest,
343    int dest_pitch,
344    unsigned int dest_width,
345    unsigned int dest_height,
346    unsigned char *temp_area,
347    unsigned char temp_area_height,
348    unsigned int hscale,
349    unsigned int hratio,
350    unsigned int vscale,
351    unsigned int vratio,
352    unsigned int interlaced
353)
354{
355    /*unsigned*/
356    int i, j, k;
357    int bands;
358    int dest_band_height;
359    int source_band_height;
360
361    typedef void (*Scale1D)(const unsigned char * source, int source_step, unsigned int source_scale, unsigned int source_length,
362                            unsigned char * dest, int dest_step, unsigned int dest_scale, unsigned int dest_length);
363
364    Scale1D Scale1Dv = scale1d_c;
365    Scale1D Scale1Dh = scale1d_c;
366
367    void (*horiz_line_scale)(const unsigned char *, unsigned int, unsigned char *, unsigned int) = NULL;
368    void (*vert_band_scale)(unsigned char *, unsigned int, unsigned char *, unsigned int, unsigned int) = NULL;
369
370    int ratio_scalable = 1;
371    int interpolation = 0;
372
373    unsigned char *source_base; /* = (unsigned char *) ((source_pitch >= 0) ? source : (source + ((source_height-1) * source_pitch))); */
374    unsigned char *line_src;
375
376
377    source_base = (unsigned char *)source;
378
379    if (source_pitch < 0)
380    {
381        int offset;
382
383        offset = (source_height - 1);
384        offset *= source_pitch;
385
386        source_base += offset;
387    }
388
389    /* find out the ratio for each direction */
390    switch (hratio * 10 / hscale)
391    {
392    case 8:
393        /* 4-5 Scale in Width direction */
394        horiz_line_scale = vp8_horizontal_line_5_4_scale;
395        break;
396    case 6:
397        /* 3-5 Scale in Width direction */
398        horiz_line_scale = vp8_horizontal_line_5_3_scale;
399        break;
400    case 5:
401        /* 1-2 Scale in Width direction */
402        horiz_line_scale = vp8_horizontal_line_2_1_scale;
403        break;
404    default:
405        /* The ratio is not acceptable now */
406        /* throw("The ratio is not acceptable for now!"); */
407        ratio_scalable = 0;
408        break;
409    }
410
411    switch (vratio * 10 / vscale)
412    {
413    case 8:
414        /* 4-5 Scale in vertical direction */
415        vert_band_scale     = vp8_vertical_band_5_4_scale;
416        source_band_height  = 5;
417        dest_band_height    = 4;
418        break;
419    case 6:
420        /* 3-5 Scale in vertical direction */
421        vert_band_scale     = vp8_vertical_band_5_3_scale;
422        source_band_height  = 5;
423        dest_band_height    = 3;
424        break;
425    case 5:
426        /* 1-2 Scale in vertical direction */
427
428        if (interlaced)
429        {
430            /* if the content is interlaced, point sampling is used */
431            vert_band_scale     = vp8_vertical_band_2_1_scale;
432        }
433        else
434        {
435
436            interpolation = 1;
437            /* if the content is progressive, interplo */
438            vert_band_scale     = vp8_vertical_band_2_1_scale_i;
439
440        }
441
442        source_band_height  = 2;
443        dest_band_height    = 1;
444        break;
445    default:
446        /* The ratio is not acceptable now */
447        /* throw("The ratio is not acceptable for now!"); */
448        ratio_scalable = 0;
449        break;
450    }
451
452    if (ratio_scalable)
453    {
454        if (source_height == dest_height)
455        {
456            /* for each band of the image */
457            for (k = 0; k < (int)dest_height; k++)
458            {
459                horiz_line_scale(source, source_width, dest, dest_width);
460                source += source_pitch;
461                dest   += dest_pitch;
462            }
463
464            return;
465        }
466
467        if (interpolation)
468        {
469            if (source < source_base)
470                source = source_base;
471
472            horiz_line_scale(source, source_width, temp_area, dest_width);
473        }
474
475        for (k = 0; k < (int)(dest_height + dest_band_height - 1) / dest_band_height; k++)
476        {
477            /* scale one band horizontally */
478            for (i = 0; i < source_band_height; i++)
479            {
480                /* Trap case where we could read off the base of the source buffer */
481
482                line_src = (unsigned char *)source + i * source_pitch;
483
484                if (line_src < source_base)
485                    line_src = source_base;
486
487                horiz_line_scale(line_src, source_width,
488                                 temp_area + (i + 1)*dest_pitch, dest_width);
489            }
490
491            /* Vertical scaling is in place */
492            vert_band_scale(temp_area + dest_pitch, dest_pitch, dest, dest_pitch, dest_width);
493
494            if (interpolation)
495                vpx_memcpy(temp_area, temp_area + source_band_height * dest_pitch, dest_width);
496
497            /* Next band... */
498            source += (unsigned long) source_band_height  * source_pitch;
499            dest   += (unsigned long) dest_band_height * dest_pitch;
500        }
501
502        return;
503    }
504
505    if (hscale == 2 && hratio == 1)
506        Scale1Dh = scale1d_2t1_ps;
507
508    if (vscale == 2 && vratio == 1)
509    {
510        if (interlaced)
511            Scale1Dv = scale1d_2t1_ps;
512        else
513            Scale1Dv = scale1d_2t1_i;
514    }
515
516    if (source_height == dest_height)
517    {
518        /* for each band of the image */
519        for (k = 0; k < (int)dest_height; k++)
520        {
521            Scale1Dh(source, 1, hscale, source_width + 1, dest, 1, hratio, dest_width);
522            source += source_pitch;
523            dest   += dest_pitch;
524        }
525
526        return;
527    }
528
529    if (dest_height > source_height)
530    {
531        dest_band_height   = temp_area_height - 1;
532        source_band_height = dest_band_height * source_height / dest_height;
533    }
534    else
535    {
536        source_band_height = temp_area_height - 1;
537        dest_band_height   = source_band_height * vratio / vscale;
538    }
539
540    /* first row needs to be done so that we can stay one row ahead for vertical zoom */
541    Scale1Dh(source, 1, hscale, source_width + 1, temp_area, 1, hratio, dest_width);
542
543    /* for each band of the image */
544    bands = (dest_height + dest_band_height - 1) / dest_band_height;
545
546    for (k = 0; k < bands; k++)
547    {
548        /* scale one band horizontally */
549        for (i = 1; i < source_band_height + 1; i++)
550        {
551            if (k * source_band_height + i < (int) source_height)
552            {
553                Scale1Dh(source + i * source_pitch, 1, hscale, source_width + 1,
554                         temp_area + i * dest_pitch, 1, hratio, dest_width);
555            }
556            else  /*  Duplicate the last row */
557            {
558                /* copy temp_area row 0 over from last row in the past */
559                duck_memcpy(temp_area + i * dest_pitch, temp_area + (i - 1)*dest_pitch, dest_pitch);
560            }
561        }
562
563        /* scale one band vertically */
564        for (j = 0; j < (int)dest_width; j++)
565        {
566            Scale1Dv(&temp_area[j], dest_pitch, vscale, source_band_height + 1,
567                     &dest[j], dest_pitch, vratio, dest_band_height);
568        }
569
570        /* copy temp_area row 0 over from last row in the past */
571        duck_memcpy(temp_area, temp_area + source_band_height * dest_pitch, dest_pitch);
572
573        /* move to the next band */
574        source += source_band_height * source_pitch;
575        dest   += dest_band_height * dest_pitch;
576    }
577}
578
579/****************************************************************************
580 *
581 *  ROUTINE       :
582 *
583 *  INPUTS        : YV12_BUFFER_CONFIG *src       : Pointer to frame to be scaled.
584 *                  YV12_BUFFER_CONFIG *dst       : Pointer to buffer to hold scaled frame.
585 *                  unsigned char *temp_area      : Pointer to temp work area.
586 *                  unsigned char temp_area_height : Height of temp work area.
587 *                  unsigned int hscale          : Horizontal scale factor numerator.
588 *                  unsigned int hratio          : Horizontal scale factor denominator.
589 *                  unsigned int vscale          : Vertical scale factor numerator.
590 *                  unsigned int vratio          : Vertical scale factor denominator.
591 *                  unsigned int interlaced      : Interlace flag.
592 *
593 *  OUTPUTS       : None.
594 *
595 *  RETURNS       : void
596 *
597 *  FUNCTION      : Performs 2-tap linear interpolation in two dimensions.
598 *
599 *  SPECIAL NOTES : Expansion is performed one band at a time to help with
600 *                  caching.
601 *
602 ****************************************************************************/
603void vp8_scale_frame
604(
605    YV12_BUFFER_CONFIG *src,
606    YV12_BUFFER_CONFIG *dst,
607    unsigned char *temp_area,
608    unsigned char temp_height,
609    unsigned int hscale,
610    unsigned int hratio,
611    unsigned int vscale,
612    unsigned int vratio,
613    unsigned int interlaced
614)
615{
616    int i;
617    int dw = (hscale - 1 + src->y_width * hratio) / hscale;
618    int dh = (vscale - 1 + src->y_height * vratio) / vscale;
619
620    /* call our internal scaling routines!! */
621    Scale2D((unsigned char *) src->y_buffer, src->y_stride, src->y_width, src->y_height,
622            (unsigned char *) dst->y_buffer, dst->y_stride, dw, dh,
623            temp_area, temp_height, hscale, hratio, vscale, vratio, interlaced);
624
625    if (dw < (int)dst->y_width)
626        for (i = 0; i < dh; i++)
627            duck_memset(dst->y_buffer + i * dst->y_stride + dw - 1, dst->y_buffer[i*dst->y_stride+dw-2], dst->y_width - dw + 1);
628
629    if (dh < (int)dst->y_height)
630        for (i = dh - 1; i < (int)dst->y_height; i++)
631            duck_memcpy(dst->y_buffer + i * dst->y_stride, dst->y_buffer + (dh - 2) * dst->y_stride, dst->y_width + 1);
632
633    Scale2D((unsigned char *) src->u_buffer, src->uv_stride, src->uv_width, src->uv_height,
634            (unsigned char *) dst->u_buffer, dst->uv_stride, dw / 2, dh / 2,
635            temp_area, temp_height, hscale, hratio, vscale, vratio, interlaced);
636
637    if (dw / 2 < (int)dst->uv_width)
638        for (i = 0; i < dst->uv_height; i++)
639            duck_memset(dst->u_buffer + i * dst->uv_stride + dw / 2 - 1, dst->u_buffer[i*dst->uv_stride+dw/2-2], dst->uv_width - dw / 2 + 1);
640
641    if (dh / 2 < (int)dst->uv_height)
642        for (i = dh / 2 - 1; i < (int)dst->y_height / 2; i++)
643            duck_memcpy(dst->u_buffer + i * dst->uv_stride, dst->u_buffer + (dh / 2 - 2)*dst->uv_stride, dst->uv_width);
644
645    Scale2D((unsigned char *) src->v_buffer, src->uv_stride, src->uv_width, src->uv_height,
646            (unsigned char *) dst->v_buffer, dst->uv_stride, dw / 2, dh / 2,
647            temp_area, temp_height, hscale, hratio, vscale, vratio, interlaced);
648
649    if (dw / 2 < (int)dst->uv_width)
650        for (i = 0; i < dst->uv_height; i++)
651            duck_memset(dst->v_buffer + i * dst->uv_stride + dw / 2 - 1, dst->v_buffer[i*dst->uv_stride+dw/2-2], dst->uv_width - dw / 2 + 1);
652
653    if (dh / 2 < (int) dst->uv_height)
654        for (i = dh / 2 - 1; i < (int)dst->y_height / 2; i++)
655            duck_memcpy(dst->v_buffer + i * dst->uv_stride, dst->v_buffer + (dh / 2 - 2)*dst->uv_stride, dst->uv_width);
656}
657/****************************************************************************
658 *
659 *  ROUTINE       : any_ratio_2d_scale
660 *
661 *  INPUTS        : SCALE_INSTANCE *si      : Pointer to post-processor instance (NOT USED).
662 *                  const unsigned char *source : Pointer to source image.
663 *                  unsigned int source_pitch    : Stride of source image.
664 *                  unsigned int source_width    : Width of source image.
665 *                  unsigned int source_height   : Height of source image (NOT USED).
666 *                  unsigned char *dest         : Pointer to destination image.
667 *                  unsigned int dest_pitch      : Stride of destination image.
668 *                  unsigned int dest_width      : Width of destination image.
669 *                  unsigned int dest_height     : Height of destination image.
670 *
671 *  OUTPUTS       : None.
672 *
673 *  RETURNS       : int: 1 if image scaled, 0 if image could not be scaled.
674 *
675 *  FUNCTION      : Scale the image with changing apect ratio.
676 *
677 *  SPECIAL NOTES : This scaling is a bi-linear scaling. Need to re-work the
678 *                  whole function for new scaling algorithm.
679 *
680 ****************************************************************************/
681static
682int any_ratio_2d_scale
683(
684    SCALE_VARS *si,
685    const unsigned char *source,
686    int source_pitch,
687    unsigned int source_width,
688    unsigned int source_height,
689    unsigned char *dest,
690    unsigned int dest_pitch,
691    unsigned int dest_width,
692    unsigned int dest_height
693)
694{
695    unsigned int i, k;
696    unsigned int src_band_height  = 0;
697    unsigned int dest_band_height = 0;
698
699    /* suggested scale factors */
700    int hs = si->HScale;
701    int hr = si->HRatio;
702    int vs = si->VScale;
703    int vr = si->VRatio;
704
705    /* assume the ratios are scalable instead of should be centered */
706    int ratio_scalable = 1;
707
708    const unsigned char *source_base = ((source_pitch >= 0) ? source : (source + ((source_height - 1) * source_pitch)));
709    const unsigned char *line_src;
710
711    void (*horiz_line_scale)(const unsigned char *, unsigned int, unsigned char *, unsigned int) = NULL;
712    void (*vert_band_scale)(unsigned char *, unsigned int, unsigned int) = NULL;
713    void (*last_vert_band_scale)(unsigned char *, unsigned int, unsigned int) = NULL;
714
715    (void) si;
716
717    /* find out the ratio for each direction */
718    switch (hr * 30 / hs)
719    {
720    case 24:
721        /* 4-5 Scale in Width direction */
722        horiz_line_scale = vp8_horizontal_line_4_5_scale;
723        break;
724    case 22:
725        /* 3-4 Scale in Width direction */
726        horiz_line_scale = vp8_horizontal_line_3_4_scale;
727        break;
728
729    case 20:
730        /* 4-5 Scale in Width direction */
731        horiz_line_scale = vp8_horizontal_line_2_3_scale;
732        break;
733    case 18:
734        /* 3-5 Scale in Width direction */
735        horiz_line_scale = vp8_horizontal_line_3_5_scale;
736        break;
737    case 15:
738        /* 1-2 Scale in Width direction */
739        horiz_line_scale = vp8_horizontal_line_1_2_scale;
740        break;
741    case 30:
742        /* no scale in Width direction */
743        horiz_line_scale = horizontal_line_copy;
744        break;
745    default:
746        /* The ratio is not acceptable now */
747        /* throw("The ratio is not acceptable for now!"); */
748        ratio_scalable = 0;
749        break;
750    }
751
752    switch (vr * 30 / vs)
753    {
754    case 24:
755        /* 4-5 Scale in vertical direction */
756        vert_band_scale     = vp8_vertical_band_4_5_scale;
757        last_vert_band_scale = vp8_last_vertical_band_4_5_scale;
758        src_band_height     = 4;
759        dest_band_height    = 5;
760        break;
761    case 22:
762        /* 3-4 Scale in vertical direction */
763        vert_band_scale     = vp8_vertical_band_3_4_scale;
764        last_vert_band_scale = vp8_last_vertical_band_3_4_scale;
765        src_band_height     = 3;
766        dest_band_height    = 4;
767        break;
768    case 20:
769        /* 2-3 Scale in vertical direction */
770        vert_band_scale     = vp8_vertical_band_2_3_scale;
771        last_vert_band_scale = vp8_last_vertical_band_2_3_scale;
772        src_band_height     = 2;
773        dest_band_height    = 3;
774        break;
775    case 18:
776        /* 3-5 Scale in vertical direction */
777        vert_band_scale     = vp8_vertical_band_3_5_scale;
778        last_vert_band_scale = vp8_last_vertical_band_3_5_scale;
779        src_band_height     = 3;
780        dest_band_height    = 5;
781        break;
782    case 15:
783        /* 1-2 Scale in vertical direction */
784        vert_band_scale     = vp8_vertical_band_1_2_scale;
785        last_vert_band_scale = vp8_last_vertical_band_1_2_scale;
786        src_band_height     = 1;
787        dest_band_height    = 2;
788        break;
789    case 30:
790        /* no scale in Width direction */
791        vert_band_scale     = null_scale;
792        last_vert_band_scale = null_scale;
793        src_band_height     = 4;
794        dest_band_height    = 4;
795        break;
796    default:
797        /* The ratio is not acceptable now */
798        /* throw("The ratio is not acceptable for now!"); */
799        ratio_scalable = 0;
800        break;
801    }
802
803    if (ratio_scalable == 0)
804        return ratio_scalable;
805
806    horiz_line_scale(source, source_width, dest, dest_width);
807
808    /* except last band */
809    for (k = 0; k < (dest_height + dest_band_height - 1) / dest_band_height - 1; k++)
810    {
811        /* scale one band horizontally */
812        for (i = 1; i < src_band_height; i++)
813        {
814            /* Trap case where we could read off the base of the source buffer */
815            line_src = source + i * source_pitch;
816
817            if (line_src < source_base)
818                line_src = source_base;
819
820            horiz_line_scale(line_src, source_width,
821                             dest + i * dest_pitch, dest_width);
822        }
823
824        /* first line of next band */
825        /* Trap case where we could read off the base of the source buffer */
826        line_src = source + src_band_height * source_pitch;
827
828        if (line_src < source_base)
829            line_src = source_base;
830
831        horiz_line_scale(line_src, source_width,
832                         dest + dest_band_height * dest_pitch,
833                         dest_width);
834
835        /* Vertical scaling is in place */
836        vert_band_scale(dest, dest_pitch, dest_width);
837
838        /* Next band... */
839        source += src_band_height  * source_pitch;
840        dest   += dest_band_height * dest_pitch;
841    }
842
843    /* scale one band horizontally */
844    for (i = 1; i < src_band_height; i++)
845    {
846        /* Trap case where we could read off the base of the source buffer */
847        line_src = source + i * source_pitch;
848
849        if (line_src < source_base)
850            line_src = source_base;
851
852        horiz_line_scale(line_src, source_width,
853                         dest + i * dest_pitch,
854                         dest_width);
855    }
856
857    /* Vertical scaling is in place */
858    last_vert_band_scale(dest, dest_pitch, dest_width);
859
860    return ratio_scalable;
861}
862
863/****************************************************************************
864 *
865 *  ROUTINE       : any_ratio_frame_scale
866 *
867 *  INPUTS        : SCALE_INSTANCE *si       : Pointer to post-processor instance (NOT USED).
868 *                  unsigned char *frame_buffer           : Pointer to source image.
869 *                  int YOffset                : Offset from start of buffer to Y samples.
870 *                  int UVOffset               : Offset from start of buffer to UV samples.
871 *
872 *  OUTPUTS       : None.
873 *
874 *  RETURNS       : int: 1 if image scaled, 0 if image could not be scaled.
875 *
876 *  FUNCTION      : Scale the image with changing apect ratio.
877 *
878 *  SPECIAL NOTES : None.
879 *
880 ****************************************************************************/
881static
882int any_ratio_frame_scale(SCALE_VARS *scale_vars, int YOffset, int UVOffset)
883{
884    int i;
885    int ew;
886    int eh;
887
888    /* suggested scale factors */
889    int hs = scale_vars->HScale;
890    int hr = scale_vars->HRatio;
891    int vs = scale_vars->VScale;
892    int vr = scale_vars->VRatio;
893
894    int ratio_scalable = 1;
895
896    int sw = (scale_vars->expanded_frame_width * hr + hs - 1) / hs;
897    int sh = (scale_vars->expanded_frame_height * vr + vs - 1) / vs;
898    int dw = scale_vars->expanded_frame_width;
899    int dh = scale_vars->expanded_frame_height;
900    YV12_BUFFER_CONFIG *src_yuv_config = scale_vars->src_yuv_config;
901    YV12_BUFFER_CONFIG *dst_yuv_config = scale_vars->dst_yuv_config;
902
903    if (hr == 3)
904        ew = (sw + 2) / 3 * 3 * hs / hr;
905    else
906        ew = (sw + 7) / 8 * 8 * hs / hr;
907
908    if (vr == 3)
909        eh = (sh + 2) / 3 * 3 * vs / vr;
910    else
911        eh = (sh + 7) / 8 * 8 * vs / vr;
912
913    ratio_scalable = any_ratio_2d_scale(scale_vars,
914                                        (const unsigned char *)src_yuv_config->y_buffer,
915                                        src_yuv_config->y_stride, sw, sh,
916                                        (unsigned char *) dst_yuv_config->y_buffer + YOffset,
917                                        dst_yuv_config->y_stride, dw, dh);
918
919    for (i = 0; i < eh; i++)
920        duck_memset(dst_yuv_config->y_buffer + YOffset + i * dst_yuv_config->y_stride + dw, 0, ew - dw);
921
922    for (i = dh; i < eh; i++)
923        duck_memset(dst_yuv_config->y_buffer + YOffset + i * dst_yuv_config->y_stride, 0, ew);
924
925    if (ratio_scalable == 0)
926        return ratio_scalable;
927
928    sw = (sw + 1) >> 1;
929    sh = (sh + 1) >> 1;
930    dw = (dw + 1) >> 1;
931    dh = (dh + 1) >> 1;
932
933    any_ratio_2d_scale(scale_vars,
934                       (const unsigned char *)src_yuv_config->u_buffer,
935                       src_yuv_config->y_stride / 2, sw, sh,
936                       (unsigned char *)dst_yuv_config->u_buffer + UVOffset,
937                       dst_yuv_config->uv_stride, dw, dh);
938
939    any_ratio_2d_scale(scale_vars,
940                       (const unsigned char *)src_yuv_config->v_buffer,
941                       src_yuv_config->y_stride / 2, sw, sh,
942                       (unsigned char *)dst_yuv_config->v_buffer + UVOffset,
943                       dst_yuv_config->uv_stride, dw, dh);
944
945    return ratio_scalable;
946}
947
948/****************************************************************************
949 *
950 *  ROUTINE       : center_image
951 *
952 *  INPUTS        : SCALE_INSTANCE *si       : Pointer to post-processor instance.
953 *
954 *  OUTPUTS       : None.
955 *
956 *  RETURNS       : void
957 *
958 *  FUNCTION      : Centers the image without scaling in the output buffer.
959 *
960 *  SPECIAL NOTES : None.
961 *
962 ****************************************************************************/
963static void
964center_image(YV12_BUFFER_CONFIG *src_yuv_config, YV12_BUFFER_CONFIG *dst_yuv_config)
965{
966    int i;
967    int row_offset, col_offset;
968    unsigned char *src_data_pointer;
969    unsigned char *dst_data_pointer;
970
971    /* center values */
972    row_offset = (dst_yuv_config->y_height - src_yuv_config->y_height) / 2;
973    col_offset = (dst_yuv_config->y_width - src_yuv_config->y_width) / 2;
974
975    /* Y's */
976    src_data_pointer = src_yuv_config->y_buffer;
977    dst_data_pointer = (unsigned char *)dst_yuv_config->y_buffer + (row_offset * dst_yuv_config->y_stride) + col_offset;
978
979    for (i = 0; i < src_yuv_config->y_height; i++)
980    {
981        duck_memcpy(dst_data_pointer, src_data_pointer, src_yuv_config->y_width);
982        dst_data_pointer += dst_yuv_config->y_stride;
983        src_data_pointer += src_yuv_config->y_stride;
984    }
985
986    row_offset /= 2;
987    col_offset /= 2;
988
989    /* U's */
990    src_data_pointer = src_yuv_config->u_buffer;
991    dst_data_pointer = (unsigned char *)dst_yuv_config->u_buffer + (row_offset * dst_yuv_config->uv_stride) + col_offset;
992
993    for (i = 0; i < src_yuv_config->uv_height; i++)
994    {
995        duck_memcpy(dst_data_pointer, src_data_pointer, src_yuv_config->uv_width);
996        dst_data_pointer += dst_yuv_config->uv_stride;
997        src_data_pointer += src_yuv_config->uv_stride;
998    }
999
1000    /* V's */
1001    src_data_pointer = src_yuv_config->v_buffer;
1002    dst_data_pointer = (unsigned char *)dst_yuv_config->v_buffer + (row_offset * dst_yuv_config->uv_stride) + col_offset;
1003
1004    for (i = 0; i < src_yuv_config->uv_height; i++)
1005    {
1006        duck_memcpy(dst_data_pointer, src_data_pointer, src_yuv_config->uv_width);
1007        dst_data_pointer += dst_yuv_config->uv_stride;
1008        src_data_pointer += src_yuv_config->uv_stride;
1009    }
1010}
1011
1012/****************************************************************************
1013 *
1014 *  ROUTINE       : scale_or_center
1015 *
1016 *  INPUTS        : SCALE_INSTANCE *si       : Pointer to post-processor instance.
1017 *
1018 *
1019 *
1020 *  OUTPUTS       : None.
1021 *
1022 *  RETURNS       : void
1023 *
1024 *  FUNCTION      : Decides to scale or center image in scale buffer for blit
1025 *
1026 *  SPECIAL NOTES : None.
1027 *
1028 ****************************************************************************/
1029void
1030vp8_yv12_scale_or_center
1031(
1032    YV12_BUFFER_CONFIG *src_yuv_config,
1033    YV12_BUFFER_CONFIG *dst_yuv_config,
1034    int expanded_frame_width,
1035    int expanded_frame_height,
1036    int scaling_mode,
1037    int HScale,
1038    int HRatio,
1039    int VScale,
1040    int VRatio
1041)
1042{
1043    /*if ( ppi->post_processing_level )
1044          update_umvborder ( ppi, frame_buffer );*/
1045
1046
1047    switch (scaling_mode)
1048    {
1049    case SCALE_TO_FIT:
1050    case MAINTAIN_ASPECT_RATIO:
1051    {
1052        SCALE_VARS scale_vars;
1053        /* center values */
1054#if 1
1055        int row = (dst_yuv_config->y_height - expanded_frame_height) / 2;
1056        int col = (dst_yuv_config->y_width  - expanded_frame_width) / 2;
1057        /*int YOffset  = row * dst_yuv_config->y_width + col;
1058        int UVOffset = (row>>1) * dst_yuv_config->uv_width + (col>>1);*/
1059        int YOffset  = row * dst_yuv_config->y_stride + col;
1060        int UVOffset = (row >> 1) * dst_yuv_config->uv_stride + (col >> 1);
1061#else
1062        int row = (src_yuv_config->y_height - expanded_frame_height) / 2;
1063        int col = (src_yuv_config->y_width  - expanded_frame_width) / 2;
1064        int YOffset  = row * src_yuv_config->y_width + col;
1065        int UVOffset = (row >> 1) * src_yuv_config->uv_width + (col >> 1);
1066#endif
1067
1068        scale_vars.dst_yuv_config = dst_yuv_config;
1069        scale_vars.src_yuv_config = src_yuv_config;
1070        scale_vars.HScale = HScale;
1071        scale_vars.HRatio = HRatio;
1072        scale_vars.VScale = VScale;
1073        scale_vars.VRatio = VRatio;
1074        scale_vars.expanded_frame_width = expanded_frame_width;
1075        scale_vars.expanded_frame_height = expanded_frame_height;
1076
1077        /* perform center and scale */
1078        any_ratio_frame_scale(&scale_vars, YOffset, UVOffset);
1079
1080        break;
1081    }
1082    case CENTER:
1083        center_image(src_yuv_config, dst_yuv_config);
1084        break;
1085
1086    default:
1087        break;
1088    }
1089}
1090