Coverage Report

Created: 2024-09-06 07:53

/src/libvpx/vpx_scale/generic/vpx_scale.c
Line
Count
Source (jump to first uncovered line)
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
 *   Module Title :     scale.c
14
 *
15
 *   Description  :     Image scaling functions.
16
 *
17
 ***************************************************************************/
18
19
/****************************************************************************
20
 *  Header Files
21
 ****************************************************************************/
22
#include <assert.h>
23
24
#include "./vpx_scale_rtcd.h"
25
#include "vpx_mem/vpx_mem.h"
26
#include "vpx_scale/vpx_scale.h"
27
#include "vpx_scale/yv12config.h"
28
29
typedef struct {
30
  int expanded_frame_width;
31
  int expanded_frame_height;
32
33
  int HScale;
34
  int HRatio;
35
  int VScale;
36
  int VRatio;
37
38
  YV12_BUFFER_CONFIG *src_yuv_config;
39
  YV12_BUFFER_CONFIG *dst_yuv_config;
40
41
} SCALE_VARS;
42
43
/****************************************************************************
44
 *
45
 *  ROUTINE       : scale1d_2t1_i
46
 *
47
 *  INPUTS        : const unsigned char *source : Pointer to data to be scaled.
48
 *                  int source_step             : Number of pixels to step on in
49
 *                                                source.
50
 *                  unsigned int source_scale   : Scale for source (UNUSED).
51
 *                  unsigned int source_length  : Length of source (UNUSED).
52
 *                  unsigned char *dest         : Pointer to output data array.
53
 *                  int dest_step               : Number of pixels to step on in
54
 *                                                destination.
55
 *                  unsigned int dest_scale     : Scale for destination
56
 *                                                (UNUSED).
57
 *                  unsigned int dest_length    : Length of destination.
58
 *
59
 *  OUTPUTS       : None.
60
 *
61
 *  RETURNS       : void
62
 *
63
 *  FUNCTION      : Performs 2-to-1 interpolated scaling.
64
 *
65
 *  SPECIAL NOTES : None.
66
 *
67
 ****************************************************************************/
68
static void scale1d_2t1_i(const unsigned char *source, int source_step,
69
                          unsigned int source_scale, unsigned int source_length,
70
                          unsigned char *dest, int dest_step,
71
0
                          unsigned int dest_scale, unsigned int dest_length) {
72
0
  unsigned int i, j;
73
0
  unsigned int temp;
74
0
  int source_pitch = source_step;
75
0
  (void)source_length;
76
0
  (void)source_scale;
77
0
  (void)dest_scale;
78
79
0
  source_step *= 2;
80
0
  dest[0] = source[0];
81
82
0
  for (i = dest_step, j = source_step; i < dest_length * dest_step;
83
0
       i += dest_step, j += source_step) {
84
0
    temp = 8;
85
0
    temp += 3 * source[j - source_pitch];
86
0
    temp += 10 * source[j];
87
0
    temp += 3 * source[j + source_pitch];
88
0
    temp >>= 4;
89
0
    dest[i] = (char)(temp);
90
0
  }
91
0
}
92
93
/****************************************************************************
94
 *
95
 *  ROUTINE       : scale1d_2t1_ps
96
 *
97
 *  INPUTS        : const unsigned char *source : Pointer to data to be scaled.
98
 *                  int source_step             : Number of pixels to step on in
99
 *                                                source.
100
 *                  unsigned int source_scale   : Scale for source (UNUSED).
101
 *                  unsigned int source_length  : Length of source (UNUSED).
102
 *                  unsigned char *dest         : Pointer to output data array.
103
 *                  int dest_step               : Number of pixels to step on in
104
 *                                                destination.
105
 *                  unsigned int dest_scale     : Scale for destination
106
 *                                                (UNUSED).
107
 *                  unsigned int dest_length    : Length of destination.
108
 *
109
 *  OUTPUTS       : None.
110
 *
111
 *  RETURNS       : void
112
 *
113
 *  FUNCTION      : Performs 2-to-1 point subsampled scaling.
114
 *
115
 *  SPECIAL NOTES : None.
116
 *
117
 ****************************************************************************/
118
static void scale1d_2t1_ps(const unsigned char *source, int source_step,
119
                           unsigned int source_scale,
120
                           unsigned int source_length, unsigned char *dest,
121
                           int dest_step, unsigned int dest_scale,
122
0
                           unsigned int dest_length) {
123
0
  unsigned int i, j;
124
125
0
  (void)source_length;
126
0
  (void)source_scale;
127
0
  (void)dest_scale;
128
129
0
  source_step *= 2;
130
0
  j = 0;
131
132
0
  for (i = 0; i < dest_length * dest_step; i += dest_step, j += source_step)
133
0
    dest[i] = source[j];
134
0
}
135
/****************************************************************************
136
 *
137
 *  ROUTINE       : scale1d_c
138
 *
139
 *  INPUTS        : const unsigned char *source : Pointer to data to be scaled.
140
 *                  int source_step             : Number of pixels to step on in
141
 *                                                source.
142
 *                  unsigned int source_scale   : Scale for source.
143
 *                  unsigned int source_length  : Length of source (UNUSED).
144
 *                  unsigned char *dest         : Pointer to output data array.
145
 *                  int dest_step               : Number of pixels to step on in
146
 *                                                destination.
147
 *                  unsigned int dest_scale     : Scale for destination.
148
 *                  unsigned int dest_length    : Length of destination.
149
 *
150
 *  OUTPUTS       : None.
151
 *
152
 *  RETURNS       : void
153
 *
154
 *  FUNCTION      : Performs linear interpolation in one dimension.
155
 *
156
 *  SPECIAL NOTES : None.
157
 *
158
 ****************************************************************************/
159
static void scale1d_c(const unsigned char *source, int source_step,
160
                      unsigned int source_scale, unsigned int source_length,
161
                      unsigned char *dest, int dest_step,
162
0
                      unsigned int dest_scale, unsigned int dest_length) {
163
0
  unsigned int i;
164
0
  unsigned int round_value = dest_scale / 2;
165
0
  unsigned int left_modifier = dest_scale;
166
0
  unsigned int right_modifier = 0;
167
0
  unsigned char left_pixel = *source;
168
0
  unsigned char right_pixel = *(source + source_step);
169
170
0
  (void)source_length;
171
172
  /* These asserts are needed if there are boundary issues... */
173
  /*assert ( dest_scale > source_scale );*/
174
  /*assert ( (source_length-1) * dest_scale >= (dest_length-1) * source_scale
175
   * );*/
176
177
0
  assert(dest_scale != 0);
178
0
  for (i = 0; i < dest_length * dest_step; i += dest_step) {
179
0
    dest[i] = (char)((left_modifier * left_pixel +
180
0
                      right_modifier * right_pixel + round_value) /
181
0
                     dest_scale);
182
183
0
    right_modifier += source_scale;
184
185
0
    while (right_modifier > dest_scale) {
186
0
      right_modifier -= dest_scale;
187
0
      source += source_step;
188
0
      left_pixel = *source;
189
0
      right_pixel = *(source + source_step);
190
0
    }
191
192
0
    left_modifier = dest_scale - right_modifier;
193
0
  }
194
0
}
195
196
/****************************************************************************
197
 *
198
 *  ROUTINE       : Scale2D
199
 *
200
 *  INPUTS        : const unsigned char *source    : Pointer to data to be
201
 *                                                   scaled.
202
 *                  int source_pitch               : Stride of source image.
203
 *                  unsigned int source_width      : Width of input image.
204
 *                  unsigned int source_height     : Height of input image.
205
 *                  unsigned char *dest            : Pointer to output data
206
 *                                                   array.
207
 *                  int dest_pitch                 : Stride of destination
208
 *                                                   image.
209
 *                  unsigned int dest_width        : Width of destination image.
210
 *                  unsigned int dest_height       : Height of destination
211
 *                                                   image.
212
 *                  unsigned char *temp_area       : Pointer to temp work area.
213
 *                  unsigned char temp_area_height : Height of temp work area.
214
 *                  unsigned int hscale            : Horizontal scale factor
215
 *                                                   numerator.
216
 *                  unsigned int hratio            : Horizontal scale factor
217
 *                                                   denominator.
218
 *                  unsigned int vscale            : Vertical scale factor
219
 *                                                   numerator.
220
 *                  unsigned int vratio            : Vertical scale factor
221
 *                                                   denominator.
222
 *                  unsigned int interlaced        : Interlace flag.
223
 *
224
 *  OUTPUTS       : None.
225
 *
226
 *  RETURNS       : void
227
 *
228
 *  FUNCTION      : Performs 2-tap linear interpolation in two dimensions.
229
 *
230
 *  SPECIAL NOTES : Expansion is performed one band at a time to help with
231
 *                  caching.
232
 *
233
 ****************************************************************************/
234
static void Scale2D(
235
    /*const*/
236
    unsigned char *source, int source_pitch, unsigned int source_width,
237
    unsigned int source_height, unsigned char *dest, int dest_pitch,
238
    unsigned int dest_width, unsigned int dest_height, unsigned char *temp_area,
239
    unsigned char temp_area_height, unsigned int hscale, unsigned int hratio,
240
0
    unsigned int vscale, unsigned int vratio, unsigned int interlaced) {
241
  /*unsigned*/
242
0
  int i, j, k;
243
0
  int bands;
244
0
  int dest_band_height;
245
0
  int source_band_height;
246
247
0
  typedef void (*Scale1D)(const unsigned char *source, int source_step,
248
0
                          unsigned int source_scale, unsigned int source_length,
249
0
                          unsigned char *dest, int dest_step,
250
0
                          unsigned int dest_scale, unsigned int dest_length);
251
252
0
  Scale1D Scale1Dv = scale1d_c;
253
0
  Scale1D Scale1Dh = scale1d_c;
254
255
0
  void (*horiz_line_scale)(const unsigned char *, unsigned int, unsigned char *,
256
0
                           unsigned int) = NULL;
257
0
  void (*vert_band_scale)(unsigned char *, unsigned int, unsigned char *,
258
0
                          unsigned int, unsigned int) = NULL;
259
260
0
  int ratio_scalable = 1;
261
0
  int interpolation = 0;
262
263
0
  unsigned char *source_base;
264
0
  unsigned char *line_src;
265
266
0
  source_base = (unsigned char *)source;
267
268
0
  if (source_pitch < 0) {
269
0
    int offset;
270
271
0
    offset = (source_height - 1);
272
0
    offset *= source_pitch;
273
274
0
    source_base += offset;
275
0
  }
276
277
  /* find out the ratio for each direction */
278
0
  switch (hratio * 10 / hscale) {
279
0
    case 8:
280
      /* 4-5 Scale in Width direction */
281
0
      horiz_line_scale = vp8_horizontal_line_5_4_scale;
282
0
      break;
283
0
    case 6:
284
      /* 3-5 Scale in Width direction */
285
0
      horiz_line_scale = vp8_horizontal_line_5_3_scale;
286
0
      break;
287
0
    case 5:
288
      /* 1-2 Scale in Width direction */
289
0
      horiz_line_scale = vp8_horizontal_line_2_1_scale;
290
0
      break;
291
0
    default:
292
      /* The ratio is not acceptable now */
293
      /* throw("The ratio is not acceptable for now!"); */
294
0
      ratio_scalable = 0;
295
0
      break;
296
0
  }
297
298
0
  switch (vratio * 10 / vscale) {
299
0
    case 8:
300
      /* 4-5 Scale in vertical direction */
301
0
      vert_band_scale = vp8_vertical_band_5_4_scale;
302
0
      source_band_height = 5;
303
0
      dest_band_height = 4;
304
0
      break;
305
0
    case 6:
306
      /* 3-5 Scale in vertical direction */
307
0
      vert_band_scale = vp8_vertical_band_5_3_scale;
308
0
      source_band_height = 5;
309
0
      dest_band_height = 3;
310
0
      break;
311
0
    case 5:
312
      /* 1-2 Scale in vertical direction */
313
314
0
      if (interlaced) {
315
        /* if the content is interlaced, point sampling is used */
316
0
        vert_band_scale = vp8_vertical_band_2_1_scale;
317
0
      } else {
318
0
        interpolation = 1;
319
        /* if the content is progressive, interplo */
320
0
        vert_band_scale = vp8_vertical_band_2_1_scale_i;
321
0
      }
322
323
0
      source_band_height = 2;
324
0
      dest_band_height = 1;
325
0
      break;
326
0
    default:
327
      /* The ratio is not acceptable now */
328
      /* throw("The ratio is not acceptable for now!"); */
329
0
      ratio_scalable = 0;
330
0
      break;
331
0
  }
332
333
0
  if (ratio_scalable) {
334
0
    if (source_height == dest_height) {
335
      /* for each band of the image */
336
0
      for (k = 0; k < (int)dest_height; k++) {
337
0
        horiz_line_scale(source, source_width, dest, dest_width);
338
0
        source += source_pitch;
339
0
        dest += dest_pitch;
340
0
      }
341
342
0
      return;
343
0
    }
344
345
0
    if (interpolation) {
346
0
      if (source < source_base) source = source_base;
347
348
0
      horiz_line_scale(source, source_width, temp_area, dest_width);
349
0
    }
350
351
0
    for (k = 0;
352
0
         k < (int)(dest_height + dest_band_height - 1) / dest_band_height;
353
0
         k++) {
354
      /* scale one band horizontally */
355
0
      for (i = 0; i < source_band_height; i++) {
356
        /* Trap case where we could read off the base of the source buffer */
357
358
0
        line_src = (unsigned char *)source + i * source_pitch;
359
360
0
        if (line_src < source_base) line_src = source_base;
361
362
0
        horiz_line_scale(line_src, source_width,
363
0
                         temp_area + (i + 1) * dest_pitch, dest_width);
364
0
      }
365
366
      /* Vertical scaling is in place */
367
0
      vert_band_scale(temp_area + dest_pitch, dest_pitch, dest, dest_pitch,
368
0
                      dest_width);
369
370
0
      if (interpolation)
371
0
        memcpy(temp_area, temp_area + source_band_height * dest_pitch,
372
0
               dest_width);
373
374
      /* Next band... */
375
0
      source += (unsigned long)source_band_height * source_pitch;
376
0
      dest += (unsigned long)dest_band_height * dest_pitch;
377
0
    }
378
379
0
    return;
380
0
  }
381
382
0
  if (hscale == 2 && hratio == 1) Scale1Dh = scale1d_2t1_ps;
383
384
0
  if (vscale == 2 && vratio == 1) {
385
0
    if (interlaced)
386
0
      Scale1Dv = scale1d_2t1_ps;
387
0
    else
388
0
      Scale1Dv = scale1d_2t1_i;
389
0
  }
390
391
0
  if (source_height == dest_height) {
392
    /* for each band of the image */
393
0
    for (k = 0; k < (int)dest_height; k++) {
394
0
      Scale1Dh(source, 1, hscale, source_width + 1, dest, 1, hratio,
395
0
               dest_width);
396
0
      source += source_pitch;
397
0
      dest += dest_pitch;
398
0
    }
399
400
0
    return;
401
0
  }
402
403
0
  if (dest_height > source_height) {
404
0
    dest_band_height = temp_area_height - 1;
405
0
    source_band_height = dest_band_height * source_height / dest_height;
406
0
  } else {
407
0
    source_band_height = temp_area_height - 1;
408
0
    dest_band_height = source_band_height * vratio / vscale;
409
0
  }
410
411
  /* first row needs to be done so that we can stay one row ahead for vertical
412
   * zoom */
413
0
  Scale1Dh(source, 1, hscale, source_width + 1, temp_area, 1, hratio,
414
0
           dest_width);
415
416
  /* for each band of the image */
417
0
  bands = (dest_height + dest_band_height - 1) / dest_band_height;
418
419
0
  for (k = 0; k < bands; k++) {
420
    /* scale one band horizontally */
421
0
    for (i = 1; i < source_band_height + 1; i++) {
422
0
      if (k * source_band_height + i < (int)source_height) {
423
0
        Scale1Dh(source + i * source_pitch, 1, hscale, source_width + 1,
424
0
                 temp_area + i * dest_pitch, 1, hratio, dest_width);
425
0
      } else { /*  Duplicate the last row */
426
        /* copy temp_area row 0 over from last row in the past */
427
0
        memcpy(temp_area + i * dest_pitch, temp_area + (i - 1) * dest_pitch,
428
0
               dest_pitch);
429
0
      }
430
0
    }
431
432
    /* scale one band vertically */
433
0
    for (j = 0; j < (int)dest_width; j++) {
434
0
      Scale1Dv(&temp_area[j], dest_pitch, vscale, source_band_height + 1,
435
0
               &dest[j], dest_pitch, vratio, dest_band_height);
436
0
    }
437
438
    /* copy temp_area row 0 over from last row in the past */
439
0
    memcpy(temp_area, temp_area + source_band_height * dest_pitch, dest_pitch);
440
441
    /* move to the next band */
442
0
    source += source_band_height * source_pitch;
443
0
    dest += dest_band_height * dest_pitch;
444
0
  }
445
0
}
446
447
/****************************************************************************
448
 *
449
 *  ROUTINE       : vpx_scale_frame
450
 *
451
 *  INPUTS        : YV12_BUFFER_CONFIG *src        : Pointer to frame to be
452
 *                                                   scaled.
453
 *                  YV12_BUFFER_CONFIG *dst        : Pointer to buffer to hold
454
 *                                                   scaled frame.
455
 *                  unsigned char *temp_area       : Pointer to temp work area.
456
 *                  unsigned char temp_area_height : Height of temp work area.
457
 *                  unsigned int hscale            : Horizontal scale factor
458
 *                                                   numerator.
459
 *                  unsigned int hratio            : Horizontal scale factor
460
 *                                                   denominator.
461
 *                  unsigned int vscale            : Vertical scale factor
462
 *                                                   numerator.
463
 *                  unsigned int vratio            : Vertical scale factor
464
 *                                                   denominator.
465
 *                  unsigned int interlaced        : Interlace flag.
466
 *
467
 *  OUTPUTS       : None.
468
 *
469
 *  RETURNS       : void
470
 *
471
 *  FUNCTION      : Performs 2-tap linear interpolation in two dimensions.
472
 *
473
 *  SPECIAL NOTES : Expansion is performed one band at a time to help with
474
 *                  caching.
475
 *
476
 ****************************************************************************/
477
void vpx_scale_frame(YV12_BUFFER_CONFIG *src, YV12_BUFFER_CONFIG *dst,
478
                     unsigned char *temp_area, unsigned char temp_height,
479
                     unsigned int hscale, unsigned int hratio,
480
                     unsigned int vscale, unsigned int vratio,
481
0
                     unsigned int interlaced) {
482
0
  int i;
483
0
  int dw = (hscale - 1 + src->y_width * hratio) / hscale;
484
0
  int dh = (vscale - 1 + src->y_height * vratio) / vscale;
485
486
  /* call our internal scaling routines!! */
487
0
  Scale2D((unsigned char *)src->y_buffer, src->y_stride, src->y_width,
488
0
          src->y_height, (unsigned char *)dst->y_buffer, dst->y_stride, dw, dh,
489
0
          temp_area, temp_height, hscale, hratio, vscale, vratio, interlaced);
490
491
0
  if (dw < (int)dst->y_width)
492
0
    for (i = 0; i < dh; i++)
493
0
      memset(dst->y_buffer + i * dst->y_stride + dw - 1,
494
0
             dst->y_buffer[i * dst->y_stride + dw - 2], dst->y_width - dw + 1);
495
496
0
  if (dh < (int)dst->y_height)
497
0
    for (i = dh - 1; i < (int)dst->y_height; i++)
498
0
      memcpy(dst->y_buffer + i * dst->y_stride,
499
0
             dst->y_buffer + (dh - 2) * dst->y_stride, dst->y_width + 1);
500
501
0
  Scale2D((unsigned char *)src->u_buffer, src->uv_stride, src->uv_width,
502
0
          src->uv_height, (unsigned char *)dst->u_buffer, dst->uv_stride,
503
0
          dw / 2, dh / 2, temp_area, temp_height, hscale, hratio, vscale,
504
0
          vratio, interlaced);
505
506
0
  if (dw / 2 < (int)dst->uv_width)
507
0
    for (i = 0; i < dst->uv_height; i++)
508
0
      memset(dst->u_buffer + i * dst->uv_stride + dw / 2 - 1,
509
0
             dst->u_buffer[i * dst->uv_stride + dw / 2 - 2],
510
0
             dst->uv_width - dw / 2 + 1);
511
512
0
  if (dh / 2 < (int)dst->uv_height)
513
0
    for (i = dh / 2 - 1; i < (int)dst->y_height / 2; i++)
514
0
      memcpy(dst->u_buffer + i * dst->uv_stride,
515
0
             dst->u_buffer + (dh / 2 - 2) * dst->uv_stride, dst->uv_width);
516
517
0
  Scale2D((unsigned char *)src->v_buffer, src->uv_stride, src->uv_width,
518
0
          src->uv_height, (unsigned char *)dst->v_buffer, dst->uv_stride,
519
0
          dw / 2, dh / 2, temp_area, temp_height, hscale, hratio, vscale,
520
0
          vratio, interlaced);
521
522
0
  if (dw / 2 < (int)dst->uv_width)
523
0
    for (i = 0; i < dst->uv_height; i++)
524
0
      memset(dst->v_buffer + i * dst->uv_stride + dw / 2 - 1,
525
0
             dst->v_buffer[i * dst->uv_stride + dw / 2 - 2],
526
0
             dst->uv_width - dw / 2 + 1);
527
528
0
  if (dh / 2 < (int)dst->uv_height)
529
0
    for (i = dh / 2 - 1; i < (int)dst->y_height / 2; i++)
530
0
      memcpy(dst->v_buffer + i * dst->uv_stride,
531
0
             dst->v_buffer + (dh / 2 - 2) * dst->uv_stride, dst->uv_width);
532
0
}