Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/ycbcr/scale_yuv_argb.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *  Copyright 2011 The LibYuv Project Authors. All rights reserved.
3
 *  Copyright 2016 Mozilla Foundation
4
 *
5
 *  Use of this source code is governed by a BSD-style license
6
 *  that can be found in the LICENSE file in the root of the source
7
 *  tree. An additional intellectual property rights grant can be found
8
 *  in the file PATENTS. All contributing project authors may
9
 *  be found in the AUTHORS file in the root of the source tree.
10
 */
11
12
#include "libyuv/scale.h"
13
14
#include <assert.h>
15
#include <string.h>
16
17
#include "libyuv/cpu_id.h"
18
#include "libyuv/row.h"
19
#include "libyuv/scale_row.h"
20
#include "libyuv/video_common.h"
21
22
#ifdef __cplusplus
23
namespace libyuv {
24
extern "C" {
25
#endif
26
27
// YUV to RGB conversion and scaling functions were implemented by referencing
28
// scale_argb.cc
29
//
30
// libyuv already has ScaleYUVToARGBBilinearUp(), but its implementation is not
31
// completed yet. Implementations of the functions are based on it.
32
// At first, ScaleYUVToARGBBilinearUp() was implemented by modidying the
33
// libyuv's one. Then all another functions were implemented similarly.
34
//
35
// Function relationship between yuv_convert.cpp abd scale_argb.cc are like
36
// the followings
37
//  - ScaleYUVToARGBDown2()      <-- ScaleARGBDown2()
38
//  - ScaleYUVToARGBDownEven()   <-- ScaleARGBDownEven()
39
//  - ScaleYUVToARGBBilinearDown() <-- ScaleARGBBilinearDown()
40
//  - ScaleYUVToARGBBilinearUp() <-- ScaleARGBBilinearUp() and ScaleYUVToARGBBilinearUp() in libyuv
41
//  - ScaleYUVToARGBSimple()     <-- ScaleARGBSimple()
42
//  - ScaleYUVToARGB()           <-- ScaleARGB() // Removed some function calls for simplicity.
43
//  - YUVToARGBScale()           <-- ARGBScale()
44
//
45
// Callings and selections of InterpolateRow() and ScaleARGBFilterCols() were
46
// kept as same as possible.
47
//
48
// The followings changes were done to each scaling functions.
49
//
50
// -[1] Allocate YUV conversion buffer and use it as source buffer of scaling.
51
//      Its usage is borrowed from the libyuv's ScaleYUVToARGBBilinearUp().
52
// -[2] Conversion from YUV to RGB was abstracted as YUVBuferIter.
53
//      It is for handling multiple yuv color formats.
54
// -[3] Modified scaling functions as to handle YUV conversion buffer and
55
//      use YUVBuferIter.
56
// -[4] Color conversion function selections in YUVBuferIter were borrowed from
57
//      I444ToARGBMatrix(), I422ToARGBMatrix() and I420ToARGBMatrix() 
58
59
0
static __inline int Abs(int v) {
60
0
  return v >= 0 ? v : -v;
61
0
}
62
63
struct YUVBuferIter {
64
  int src_width;
65
  int src_height;
66
  int src_stride_y;
67
  int src_stride_u;
68
  int src_stride_v;
69
  const uint8* src_y;
70
  const uint8* src_u;
71
  const uint8* src_v;
72
73
  uint32 src_fourcc;
74
  const struct YuvConstants* yuvconstants;
75
  int y_index;
76
  const uint8* src_row_y;
77
  const uint8* src_row_u;
78
  const uint8* src_row_v;
79
80
  void (*YUVToARGBRow)(const uint8* y_buf,
81
                       const uint8* u_buf,
82
                       const uint8* v_buf,
83
                       uint8* rgb_buf,
84
                       const struct YuvConstants* yuvconstants,
85
                       int width);
86
  void (*MoveTo)(YUVBuferIter& iter, int y_index);
87
  void (*MoveToNextRow)(YUVBuferIter& iter);
88
};
89
90
0
void YUVBuferIter_InitI422(YUVBuferIter& iter) {
91
0
  iter.YUVToARGBRow = I422ToARGBRow_C;
92
0
#if defined(HAS_I422TOARGBROW_SSSE3)
93
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
94
0
    iter.YUVToARGBRow = I422ToARGBRow_Any_SSSE3;
95
0
    if (IS_ALIGNED(iter.src_width, 8)) {
96
0
      iter.YUVToARGBRow = I422ToARGBRow_SSSE3;
97
0
    }
98
0
  }
99
0
#endif
100
0
#if defined(HAS_I422TOARGBROW_AVX2)
101
0
  if (TestCpuFlag(kCpuHasAVX2)) {
102
0
    iter.YUVToARGBRow = I422ToARGBRow_Any_AVX2;
103
0
    if (IS_ALIGNED(iter.src_width, 16)) {
104
0
      iter.YUVToARGBRow = I422ToARGBRow_AVX2;
105
0
    }
106
0
  }
107
0
#endif
108
#if defined(HAS_I422TOARGBROW_NEON)
109
  if (TestCpuFlag(kCpuHasNEON)) {
110
    iter.YUVToARGBRow = I422ToARGBRow_Any_NEON;
111
    if (IS_ALIGNED(iter.src_width, 8)) {
112
      iter.YUVToARGBRow = I422ToARGBRow_NEON;
113
    }
114
  }
115
#endif
116
#if defined(HAS_I422TOARGBROW_DSPR2)
117
  if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(iter.src_width, 4) &&
118
      IS_ALIGNED(iter.src_y, 4) && IS_ALIGNED(iter.src_stride_y, 4) &&
119
      IS_ALIGNED(iter.src_u, 2) && IS_ALIGNED(iter.src_stride_u, 2) &&
120
      IS_ALIGNED(iter.src_v, 2) && IS_ALIGNED(iter.src_stride_v, 2) {
121
    // Always satisfy IS_ALIGNED(argb_cnv_row, 4) && IS_ALIGNED(argb_cnv_rowstride, 4)
122
    iter.YUVToARGBRow = I422ToARGBRow_DSPR2;
123
  }
124
#endif
125
}
126
127
0
void YUVBuferIter_InitI444(YUVBuferIter& iter) {
128
0
  iter.YUVToARGBRow = I444ToARGBRow_C;
129
0
#if defined(HAS_I444TOARGBROW_SSSE3)
130
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
131
0
    iter.YUVToARGBRow = I444ToARGBRow_Any_SSSE3;
132
0
    if (IS_ALIGNED(iter.src_width, 8)) {
133
0
      iter.YUVToARGBRow = I444ToARGBRow_SSSE3;
134
0
    }
135
0
  }
136
0
#endif
137
0
#if defined(HAS_I444TOARGBROW_AVX2)
138
0
  if (TestCpuFlag(kCpuHasAVX2)) {
139
0
    iter.YUVToARGBRow = I444ToARGBRow_Any_AVX2;
140
0
    if (IS_ALIGNED(iter.src_width, 16)) {
141
0
      iter.YUVToARGBRow = I444ToARGBRow_AVX2;
142
0
    }
143
0
  }
144
0
#endif
145
#if defined(HAS_I444TOARGBROW_NEON)
146
  if (TestCpuFlag(kCpuHasNEON)) {
147
    iter.YUVToARGBRow = I444ToARGBRow_Any_NEON;
148
    if (IS_ALIGNED(iter.src_width, 8)) {
149
      iter.YUVToARGBRow = I444ToARGBRow_NEON;
150
    }
151
  }
152
#endif
153
}
154
155
156
0
static void YUVBuferIter_MoveToForI444(YUVBuferIter& iter, int y_index) {
157
0
  iter.y_index = y_index;
158
0
  iter.src_row_y = iter.src_y + y_index * iter.src_stride_y;
159
0
  iter.src_row_u = iter.src_u + y_index * iter.src_stride_u;
160
0
  iter.src_row_v = iter.src_v + y_index * iter.src_stride_v;
161
0
}
162
163
0
static void YUVBuferIter_MoveToNextRowForI444(YUVBuferIter& iter) {
164
0
  iter.src_row_y += iter.src_stride_y;
165
0
  iter.src_row_u += iter.src_stride_u;
166
0
  iter.src_row_v += iter.src_stride_v;
167
0
  iter.y_index++;
168
0
}
169
170
0
static void YUVBuferIter_MoveToForI422(YUVBuferIter& iter, int y_index) {
171
0
  iter.y_index = y_index;
172
0
  iter.src_row_y = iter.src_y + y_index * iter.src_stride_y;
173
0
  iter.src_row_u = iter.src_u + y_index * iter.src_stride_u;
174
0
  iter.src_row_v = iter.src_v + y_index * iter.src_stride_v;
175
0
}
176
177
0
static void YUVBuferIter_MoveToNextRowForI422(YUVBuferIter& iter) {
178
0
  iter.src_row_y += iter.src_stride_y;
179
0
  iter.src_row_u += iter.src_stride_u;
180
0
  iter.src_row_v += iter.src_stride_v;
181
0
  iter.y_index++;
182
0
}
183
184
0
static void YUVBuferIter_MoveToForI420(YUVBuferIter& iter, int y_index) {
185
0
  const int kYShift = 1;  // Shift Y by 1 to convert Y plane to UV coordinate.
186
0
  int uv_y_index = y_index >> kYShift;
187
0
188
0
  iter.y_index = y_index;
189
0
  iter.src_row_y = iter.src_y + y_index * iter.src_stride_y;
190
0
  iter.src_row_u = iter.src_u + uv_y_index * iter.src_stride_u;
191
0
  iter.src_row_v = iter.src_v + uv_y_index * iter.src_stride_v;
192
0
}
193
194
0
static void YUVBuferIter_MoveToNextRowForI420(YUVBuferIter& iter) {
195
0
  iter.src_row_y += iter.src_stride_y;
196
0
  if (iter.y_index & 1) {
197
0
    iter.src_row_u += iter.src_stride_u;
198
0
    iter.src_row_v += iter.src_stride_v;
199
0
  }
200
0
  iter.y_index++;
201
0
}
202
203
0
static __inline void YUVBuferIter_ConvertToARGBRow(YUVBuferIter& iter, uint8* argb_row) {
204
0
  iter.YUVToARGBRow(iter.src_row_y, iter.src_row_u, iter.src_row_v, argb_row, iter.yuvconstants, iter.src_width);
205
0
}
206
207
0
void YUVBuferIter_Init(YUVBuferIter& iter, uint32 src_fourcc, mozilla::YUVColorSpace yuv_color_space) {
208
0
  iter.src_fourcc = src_fourcc;
209
0
  iter.y_index = 0;
210
0
  iter.src_row_y = iter.src_y;
211
0
  iter.src_row_u = iter.src_u;
212
0
  iter.src_row_v = iter.src_v;
213
0
  if (yuv_color_space == mozilla::YUVColorSpace::BT709) {
214
0
    iter.yuvconstants = &kYuvH709Constants;
215
0
  } else {
216
0
    iter.yuvconstants = &kYuvI601Constants;
217
0
  }
218
0
219
0
  if (src_fourcc == FOURCC_I444) {
220
0
    YUVBuferIter_InitI444(iter);
221
0
    iter.MoveTo = YUVBuferIter_MoveToForI444;
222
0
    iter.MoveToNextRow = YUVBuferIter_MoveToNextRowForI444;
223
0
  } else if(src_fourcc == FOURCC_I422){
224
0
    YUVBuferIter_InitI422(iter);
225
0
    iter.MoveTo = YUVBuferIter_MoveToForI422;
226
0
    iter.MoveToNextRow = YUVBuferIter_MoveToNextRowForI422;
227
0
  } else {
228
0
    assert(src_fourcc == FOURCC_I420); // Should be FOURCC_I420
229
0
    YUVBuferIter_InitI422(iter);
230
0
    iter.MoveTo = YUVBuferIter_MoveToForI420;
231
0
    iter.MoveToNextRow = YUVBuferIter_MoveToNextRowForI420;
232
0
  }
233
0
}
234
235
// ScaleARGB ARGB, 1/2
236
// This is an optimized version for scaling down a ARGB to 1/2 of
237
// its original size.
238
static void ScaleYUVToARGBDown2(int src_width, int src_height,
239
                                int dst_width, int dst_height,
240
                                int src_stride_y,
241
                                int src_stride_u,
242
                                int src_stride_v,
243
                                int dst_stride_argb,
244
                                const uint8* src_y,
245
                                const uint8* src_u,
246
                                const uint8* src_v,
247
                                uint8* dst_argb,
248
                                int x, int dx, int y, int dy,
249
                                enum FilterMode filtering,
250
                                uint32 src_fourcc,
251
0
                                mozilla::YUVColorSpace yuv_color_space) {
252
0
  int j;
253
0
254
0
  // Allocate 2 rows of ARGB for source conversion.
255
0
  const int kRowSize = (src_width * 4 + 15) & ~15;
256
0
  align_buffer_64(argb_cnv_row, kRowSize * 2);
257
0
  uint8* argb_cnv_rowptr = argb_cnv_row;
258
0
  int argb_cnv_rowstride = kRowSize;
259
0
260
0
  YUVBuferIter iter;
261
0
  iter.src_width = src_width;
262
0
  iter.src_height = src_height;
263
0
  iter.src_stride_y = src_stride_y;
264
0
  iter.src_stride_u = src_stride_u;
265
0
  iter.src_stride_v = src_stride_v;
266
0
  iter.src_y = src_y;
267
0
  iter.src_u = src_u;
268
0
  iter.src_v = src_v;
269
0
  YUVBuferIter_Init(iter, src_fourcc, yuv_color_space);
270
0
271
0
  void (*ScaleARGBRowDown2)(const uint8* src_argb, ptrdiff_t src_stride,
272
0
                            uint8* dst_argb, int dst_width) =
273
0
    filtering == kFilterNone ? ScaleARGBRowDown2_C :
274
0
        (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_C :
275
0
        ScaleARGBRowDown2Box_C);
276
0
  assert(dx == 65536 * 2);  // Test scale factor of 2.
277
0
  assert((dy & 0x1ffff) == 0);  // Test vertical scale is multiple of 2.
278
0
  // Advance to odd row, even column.
279
0
  int yi = y >> 16;
280
0
  iter.MoveTo(iter, yi);
281
0
  ptrdiff_t x_offset;
282
0
  if (filtering == kFilterBilinear) {
283
0
    x_offset = (x >> 16) * 4;
284
0
  } else {
285
0
    x_offset = ((x >> 16) - 1) * 4;
286
0
  }
287
0
#if defined(HAS_SCALEARGBROWDOWN2_SSE2)
288
0
  if (TestCpuFlag(kCpuHasSSE2)) {
289
0
    ScaleARGBRowDown2 = filtering == kFilterNone ? ScaleARGBRowDown2_Any_SSE2 :
290
0
        (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_Any_SSE2 :
291
0
        ScaleARGBRowDown2Box_Any_SSE2);
292
0
    if (IS_ALIGNED(dst_width, 4)) {
293
0
      ScaleARGBRowDown2 = filtering == kFilterNone ? ScaleARGBRowDown2_SSE2 :
294
0
          (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_SSE2 :
295
0
          ScaleARGBRowDown2Box_SSE2);
296
0
    }
297
0
  }
298
0
299
0
#endif
300
#if defined(HAS_SCALEARGBROWDOWN2_NEON)
301
  if (TestCpuFlag(kCpuHasNEON)) {
302
    ScaleARGBRowDown2 = filtering == kFilterNone ? ScaleARGBRowDown2_Any_NEON :
303
        (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_Any_NEON :
304
        ScaleARGBRowDown2Box_Any_NEON);
305
    if (IS_ALIGNED(dst_width, 8)) {
306
      ScaleARGBRowDown2 = filtering == kFilterNone ? ScaleARGBRowDown2_NEON :
307
          (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_NEON :
308
          ScaleARGBRowDown2Box_NEON);
309
    }
310
  }
311
#endif
312
313
0
  const int dyi = dy >> 16;
314
0
  int lastyi = yi;
315
0
  YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_rowptr);
316
0
  // Prepare next row if necessary
317
0
  if (filtering != kFilterLinear) {
318
0
    if ((yi + dyi) < (src_height - 1)) {
319
0
      iter.MoveTo(iter, yi + dyi);
320
0
      YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_rowptr + argb_cnv_rowstride);
321
0
    } else {
322
0
      argb_cnv_rowstride = 0;
323
0
    }
324
0
  }
325
0
326
0
  if (filtering == kFilterLinear) {
327
0
    argb_cnv_rowstride = 0;
328
0
  }
329
0
  const int max_yi = src_height - 1;
330
0
  const int max_yi_minus_dyi = max_yi - dyi;
331
0
  for (j = 0; j < dst_height; ++j) {
332
0
    if (yi != lastyi) {
333
0
      if (yi > max_yi) {
334
0
        yi = max_yi;
335
0
      }
336
0
      if (yi != lastyi) {
337
0
        if (filtering == kFilterLinear) {
338
0
          iter.MoveTo(iter, yi);
339
0
          YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_rowptr);
340
0
          lastyi = yi;
341
0
        } else {
342
0
          // Prepare current row
343
0
          if (yi == iter.y_index) {
344
0
            argb_cnv_rowptr = argb_cnv_rowptr + argb_cnv_rowstride;
345
0
            argb_cnv_rowstride = - argb_cnv_rowstride;
346
0
          } else {
347
0
            iter.MoveTo(iter, yi);
348
0
            argb_cnv_rowptr = argb_cnv_row;
349
0
            argb_cnv_rowstride = kRowSize;
350
0
            YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_rowptr);
351
0
          }
352
0
          // Prepare next row if necessary
353
0
          if (iter.y_index  < max_yi) {
354
0
            int next_yi = yi < max_yi_minus_dyi ? yi + dyi : max_yi;
355
0
            iter.MoveTo(iter, next_yi);
356
0
            YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_rowptr + argb_cnv_rowstride);
357
0
          } else {
358
0
            argb_cnv_rowstride = 0;
359
0
          }
360
0
          lastyi = yi;
361
0
        }
362
0
      }
363
0
    }
364
0
    ScaleARGBRowDown2(argb_cnv_rowptr + x_offset, argb_cnv_rowstride, dst_argb, dst_width);
365
0
    dst_argb += dst_stride_argb;
366
0
    yi += dyi;
367
0
  }
368
0
369
0
  free_aligned_buffer_64(argb_cnv_row);
370
0
}
371
372
// ScaleARGB ARGB Even
373
// This is an optimized version for scaling down a ARGB to even
374
// multiple of its original size.
375
static void ScaleYUVToARGBDownEven(int src_width, int src_height,
376
                                   int dst_width, int dst_height,
377
                                   int src_stride_y,
378
                                   int src_stride_u,
379
                                   int src_stride_v,
380
                                   int dst_stride_argb,
381
                                   const uint8* src_y,
382
                                   const uint8* src_u,
383
                                   const uint8* src_v,
384
                                   uint8* dst_argb,
385
                                   int x, int dx, int y, int dy,
386
                                   enum FilterMode filtering,
387
                                   uint32 src_fourcc,
388
0
                                   mozilla::YUVColorSpace yuv_color_space) {
389
0
  int j;
390
0
  // Allocate 2 rows of ARGB for source conversion.
391
0
  const int kRowSize = (src_width * 4 + 15) & ~15;
392
0
  align_buffer_64(argb_cnv_row, kRowSize * 2);
393
0
  uint8* argb_cnv_rowptr = argb_cnv_row;
394
0
  int argb_cnv_rowstride = kRowSize;
395
0
396
0
  int col_step = dx >> 16;
397
0
  void (*ScaleARGBRowDownEven)(const uint8* src_argb, ptrdiff_t src_stride,
398
0
                               int src_step, uint8* dst_argb, int dst_width) =
399
0
      filtering ? ScaleARGBRowDownEvenBox_C : ScaleARGBRowDownEven_C;
400
0
  assert(IS_ALIGNED(src_width, 2));
401
0
  assert(IS_ALIGNED(src_height, 2));
402
0
  int yi = y >> 16;
403
0
  const ptrdiff_t x_offset = (x >> 16) * 4;
404
0
405
0
#if defined(HAS_SCALEARGBROWDOWNEVEN_SSE2)
406
0
  if (TestCpuFlag(kCpuHasSSE2)) {
407
0
    ScaleARGBRowDownEven = filtering ? ScaleARGBRowDownEvenBox_Any_SSE2 :
408
0
        ScaleARGBRowDownEven_Any_SSE2;
409
0
    if (IS_ALIGNED(dst_width, 4)) {
410
0
      ScaleARGBRowDownEven = filtering ? ScaleARGBRowDownEvenBox_SSE2 :
411
0
          ScaleARGBRowDownEven_SSE2;
412
0
    }
413
0
  }
414
0
#endif
415
#if defined(HAS_SCALEARGBROWDOWNEVEN_NEON)
416
  if (TestCpuFlag(kCpuHasNEON)) {
417
    ScaleARGBRowDownEven = filtering ? ScaleARGBRowDownEvenBox_Any_NEON :
418
        ScaleARGBRowDownEven_Any_NEON;
419
    if (IS_ALIGNED(dst_width, 4)) {
420
      ScaleARGBRowDownEven = filtering ? ScaleARGBRowDownEvenBox_NEON :
421
          ScaleARGBRowDownEven_NEON;
422
    }
423
  }
424
#endif
425
426
0
  YUVBuferIter iter;
427
0
  iter.src_width = src_width;
428
0
  iter.src_height = src_height;
429
0
  iter.src_stride_y = src_stride_y;
430
0
  iter.src_stride_u = src_stride_u;
431
0
  iter.src_stride_v = src_stride_v;
432
0
  iter.src_y = src_y;
433
0
  iter.src_u = src_u;
434
0
  iter.src_v = src_v;
435
0
  YUVBuferIter_Init(iter, src_fourcc, yuv_color_space);
436
0
437
0
  const int dyi = dy >> 16;
438
0
  int lastyi = yi;
439
0
  YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_rowptr);
440
0
  // Prepare next row if necessary
441
0
  if (filtering != kFilterLinear) {
442
0
    if ((yi + dyi) < (src_height - 1)) {
443
0
      iter.MoveTo(iter, yi + dyi);
444
0
      YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_rowptr + argb_cnv_rowstride);
445
0
    } else {
446
0
      argb_cnv_rowstride = 0;
447
0
    }
448
0
  }
449
0
450
0
  if (filtering == kFilterLinear) {
451
0
    argb_cnv_rowstride = 0;
452
0
  }
453
0
  const int max_yi = src_height - 1;
454
0
  const int max_yi_minus_dyi = max_yi - dyi;
455
0
  for (j = 0; j < dst_height; ++j) {
456
0
    if (yi != lastyi) {
457
0
      if (yi > max_yi) {
458
0
        yi = max_yi;
459
0
      }
460
0
      if (yi != lastyi) {
461
0
        if (filtering == kFilterLinear) {
462
0
          iter.MoveTo(iter, yi);
463
0
          YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_rowptr);
464
0
          lastyi = yi;
465
0
        } else {
466
0
          // Prepare current row
467
0
          if (yi == iter.y_index) {
468
0
            argb_cnv_rowptr = argb_cnv_rowptr + argb_cnv_rowstride;
469
0
            argb_cnv_rowstride = - argb_cnv_rowstride;
470
0
          } else {
471
0
            iter.MoveTo(iter, yi);
472
0
            argb_cnv_rowptr = argb_cnv_row;
473
0
            argb_cnv_rowstride = kRowSize;
474
0
            YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_rowptr);
475
0
          }
476
0
          // Prepare next row if necessary
477
0
          if (iter.y_index  < max_yi) {
478
0
            int next_yi = yi < max_yi_minus_dyi ? yi + dyi : max_yi;
479
0
            iter.MoveTo(iter, next_yi);
480
0
            YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_rowptr + argb_cnv_rowstride);
481
0
          } else {
482
0
            argb_cnv_rowstride = 0;
483
0
          }
484
0
          lastyi = yi;
485
0
        }
486
0
      }
487
0
    }
488
0
    ScaleARGBRowDownEven(argb_cnv_rowptr + x_offset, argb_cnv_rowstride, col_step, dst_argb, dst_width);
489
0
    dst_argb += dst_stride_argb;
490
0
    yi += dyi;
491
0
  }
492
0
  free_aligned_buffer_64(argb_cnv_row);
493
0
}
494
495
// Scale YUV to ARGB down with bilinear interpolation.
496
static void ScaleYUVToARGBBilinearDown(int src_width, int src_height,
497
                                       int dst_width, int dst_height,
498
                                       int src_stride_y,
499
                                       int src_stride_u,
500
                                       int src_stride_v,
501
                                       int dst_stride_argb,
502
                                       const uint8* src_y,
503
                                       const uint8* src_u,
504
                                       const uint8* src_v,
505
                                       uint8* dst_argb,
506
                                       int x, int dx, int y, int dy,
507
                                       enum FilterMode filtering,
508
                                       uint32 src_fourcc,
509
0
                                       mozilla::YUVColorSpace yuv_color_space) {
510
0
  int j;
511
0
  void (*InterpolateRow)(uint8* dst_argb, const uint8* src_argb,
512
0
      ptrdiff_t src_stride, int dst_width, int source_y_fraction) =
513
0
      InterpolateRow_C;
514
0
  void (*ScaleARGBFilterCols)(uint8* dst_argb, const uint8* src_argb,
515
0
      int dst_width, int x, int dx) =
516
0
      (src_width >= 32768) ? ScaleARGBFilterCols64_C : ScaleARGBFilterCols_C;
517
0
  int64 xlast = x + (int64)(dst_width - 1) * dx;
518
0
  int64 xl = (dx >= 0) ? x : xlast;
519
0
  int64 xr = (dx >= 0) ? xlast : x;
520
0
  int clip_src_width;
521
0
  xl = (xl >> 16) & ~3;  // Left edge aligned.
522
0
  xr = (xr >> 16) + 1;  // Right most pixel used.  Bilinear uses 2 pixels.
523
0
  xr = (xr + 1 + 3) & ~3;  // 1 beyond 4 pixel aligned right most pixel.
524
0
  if (xr > src_width) {
525
0
    xr = src_width;
526
0
  }
527
0
  clip_src_width = (int)(xr - xl) * 4;  // Width aligned to 4.
528
0
  const ptrdiff_t xl_offset = xl * 4;
529
0
  x -= (int)(xl << 16);
530
0
531
0
  // Allocate 2 row of ARGB for source conversion.
532
0
  const int kRowSize = (src_width * 4 + 15) & ~15;
533
0
  align_buffer_64(argb_cnv_row, kRowSize * 2);
534
0
  uint8* argb_cnv_rowptr = argb_cnv_row; 
535
0
  int argb_cnv_rowstride = kRowSize;
536
0
537
0
#if defined(HAS_INTERPOLATEROW_SSSE3)
538
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
539
0
    InterpolateRow = InterpolateRow_Any_SSSE3;
540
0
    if (IS_ALIGNED(clip_src_width, 16)) {
541
0
      InterpolateRow = InterpolateRow_SSSE3;
542
0
    }
543
0
  }
544
0
#endif
545
0
#if defined(HAS_INTERPOLATEROW_AVX2)
546
0
  if (TestCpuFlag(kCpuHasAVX2)) {
547
0
    InterpolateRow = InterpolateRow_Any_AVX2;
548
0
    if (IS_ALIGNED(clip_src_width, 32)) {
549
0
      InterpolateRow = InterpolateRow_AVX2;
550
0
    }
551
0
  }
552
0
#endif
553
#if defined(HAS_INTERPOLATEROW_NEON)
554
  if (TestCpuFlag(kCpuHasNEON)) {
555
    InterpolateRow = InterpolateRow_Any_NEON;
556
    if (IS_ALIGNED(clip_src_width, 16)) {
557
      InterpolateRow = InterpolateRow_NEON;
558
    }
559
  }
560
#endif
561
#if defined(HAS_INTERPOLATEROW_DSPR2)
562
  if (TestCpuFlag(kCpuHasDSPR2) &&
563
      IS_ALIGNED(src_argb, 4) && IS_ALIGNED(argb_cnv_rowstride, 4)) {
564
    InterpolateRow = InterpolateRow_Any_DSPR2;
565
    if (IS_ALIGNED(clip_src_width, 4)) {
566
      InterpolateRow = InterpolateRow_DSPR2;
567
    }
568
  }
569
#endif
570
#if defined(HAS_SCALEARGBFILTERCOLS_SSSE3)
571
0
  if (TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
572
0
    ScaleARGBFilterCols = ScaleARGBFilterCols_SSSE3;
573
0
  }
574
0
#endif
575
#if defined(HAS_SCALEARGBFILTERCOLS_NEON)
576
  if (TestCpuFlag(kCpuHasNEON)) {
577
    ScaleARGBFilterCols = ScaleARGBFilterCols_Any_NEON;
578
    if (IS_ALIGNED(dst_width, 4)) {
579
      ScaleARGBFilterCols = ScaleARGBFilterCols_NEON;
580
    }
581
  }
582
#endif
583
584
0
  int yi = y >> 16;
585
0
586
0
  YUVBuferIter iter;
587
0
  iter.src_width = src_width;
588
0
  iter.src_height = src_height;
589
0
  iter.src_stride_y = src_stride_y;
590
0
  iter.src_stride_u = src_stride_u;
591
0
  iter.src_stride_v = src_stride_v;
592
0
  iter.src_y = src_y;
593
0
  iter.src_u = src_u;
594
0
  iter.src_v = src_v;
595
0
  YUVBuferIter_Init(iter, src_fourcc, yuv_color_space);
596
0
  iter.MoveTo(iter, yi);
597
0
598
0
  // TODO(fbarchard): Consider not allocating row buffer for kFilterLinear.
599
0
  // Allocate a row of ARGB.
600
0
  align_buffer_64(row, clip_src_width * 4);
601
0
602
0
  int lastyi = yi;
603
0
  YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_rowptr);
604
0
  // Prepare next row if necessary
605
0
  if (filtering != kFilterLinear) {
606
0
    if ((yi + 1) < src_height) {
607
0
      iter.MoveToNextRow(iter);
608
0
      YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_rowptr + argb_cnv_rowstride);
609
0
    } else {
610
0
      argb_cnv_rowstride = 0;
611
0
    }
612
0
  }
613
0
614
0
  const int max_y = (src_height - 1) << 16;
615
0
  const int max_yi = src_height - 1;
616
0
  for (j = 0; j < dst_height; ++j) {
617
0
    yi = y >> 16;
618
0
    if (yi != lastyi) {
619
0
      if (y > max_y) {
620
0
        y = max_y;
621
0
        yi = y >> 16;
622
0
      }
623
0
      if (yi != lastyi) {
624
0
        if (filtering == kFilterLinear) {
625
0
          iter.MoveTo(iter, yi);
626
0
          YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_rowptr);
627
0
          lastyi = yi;
628
0
        } else {
629
0
          // Prepare current row
630
0
          if (yi == iter.y_index) {
631
0
            argb_cnv_rowptr = argb_cnv_rowptr + argb_cnv_rowstride;
632
0
            argb_cnv_rowstride = - argb_cnv_rowstride;
633
0
          } else {
634
0
            iter.MoveTo(iter, yi);
635
0
            argb_cnv_rowptr = argb_cnv_row;
636
0
            argb_cnv_rowstride = kRowSize;
637
0
            YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_rowptr);
638
0
          }
639
0
          // Prepare next row if necessary
640
0
          if (iter.y_index < max_yi) {
641
0
            iter.MoveToNextRow(iter);
642
0
            YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_rowptr + argb_cnv_rowstride);
643
0
          } else {
644
0
            argb_cnv_rowstride = 0;
645
0
          }
646
0
          lastyi = yi;
647
0
        }
648
0
      }
649
0
    }
650
0
    if (filtering == kFilterLinear) {
651
0
      ScaleARGBFilterCols(dst_argb, argb_cnv_rowptr + xl_offset, dst_width, x, dx);
652
0
    } else {
653
0
      int yf = (y >> 8) & 255;
654
0
      InterpolateRow(row, argb_cnv_rowptr + xl_offset, argb_cnv_rowstride, clip_src_width, yf);
655
0
      ScaleARGBFilterCols(dst_argb, row, dst_width, x, dx);
656
0
    }
657
0
    dst_argb += dst_stride_argb;
658
0
    y += dy;
659
0
  }
660
0
  free_aligned_buffer_64(row);
661
0
  free_aligned_buffer_64(argb_cnv_row);
662
0
}
663
664
// Scale YUV to ARGB up with bilinear interpolation.
665
static void ScaleYUVToARGBBilinearUp(int src_width, int src_height,
666
                                     int dst_width, int dst_height,
667
                                     int src_stride_y,
668
                                     int src_stride_u,
669
                                     int src_stride_v,
670
                                     int dst_stride_argb,
671
                                     const uint8* src_y,
672
                                     const uint8* src_u,
673
                                     const uint8* src_v,
674
                                     uint8* dst_argb,
675
                                     int x, int dx, int y, int dy,
676
                                     enum FilterMode filtering,
677
                                     uint32 src_fourcc,
678
0
                                     mozilla::YUVColorSpace yuv_color_space) {
679
0
  int j;
680
0
  void (*InterpolateRow)(uint8* dst_argb, const uint8* src_argb,
681
0
      ptrdiff_t src_stride, int dst_width, int source_y_fraction) =
682
0
      InterpolateRow_C;
683
0
  void (*ScaleARGBFilterCols)(uint8* dst_argb, const uint8* src_argb,
684
0
      int dst_width, int x, int dx) =
685
0
      filtering ? ScaleARGBFilterCols_C : ScaleARGBCols_C;
686
0
  const int max_y = (src_height - 1) << 16;
687
0
688
0
  // Allocate 1 row of ARGB for source conversion.
689
0
  align_buffer_64(argb_cnv_row, src_width * 4);
690
0
691
0
#if defined(HAS_INTERPOLATEROW_SSSE3)
692
0
  if (TestCpuFlag(kCpuHasSSSE3)) {
693
0
    InterpolateRow = InterpolateRow_Any_SSSE3;
694
0
    if (IS_ALIGNED(dst_width, 4)) {
695
0
      InterpolateRow = InterpolateRow_SSSE3;
696
0
    }
697
0
  }
698
0
#endif
699
0
#if defined(HAS_INTERPOLATEROW_AVX2)
700
0
  if (TestCpuFlag(kCpuHasAVX2)) {
701
0
    InterpolateRow = InterpolateRow_Any_AVX2;
702
0
    if (IS_ALIGNED(dst_width, 8)) {
703
0
      InterpolateRow = InterpolateRow_AVX2;
704
0
    }
705
0
  }
706
0
#endif
707
#if defined(HAS_INTERPOLATEROW_NEON)
708
  if (TestCpuFlag(kCpuHasNEON)) {
709
    InterpolateRow = InterpolateRow_Any_NEON;
710
    if (IS_ALIGNED(dst_width, 4)) {
711
      InterpolateRow = InterpolateRow_NEON;
712
    }
713
  }
714
#endif
715
#if defined(HAS_INTERPOLATEROW_DSPR2)
716
  if (TestCpuFlag(kCpuHasDSPR2) &&
717
      IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
718
    InterpolateRow = InterpolateRow_DSPR2;
719
  }
720
#endif
721
0
  if (src_width >= 32768) {
722
0
    ScaleARGBFilterCols = filtering ?
723
0
        ScaleARGBFilterCols64_C : ScaleARGBCols64_C;
724
0
  }
725
0
#if defined(HAS_SCALEARGBFILTERCOLS_SSSE3)
726
0
  if (filtering && TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
727
0
    ScaleARGBFilterCols = ScaleARGBFilterCols_SSSE3;
728
0
  }
729
0
#endif
730
#if defined(HAS_SCALEARGBFILTERCOLS_NEON)
731
  if (filtering && TestCpuFlag(kCpuHasNEON)) {
732
    ScaleARGBFilterCols = ScaleARGBFilterCols_Any_NEON;
733
    if (IS_ALIGNED(dst_width, 4)) {
734
      ScaleARGBFilterCols = ScaleARGBFilterCols_NEON;
735
    }
736
  }
737
#endif
738
#if defined(HAS_SCALEARGBCOLS_SSE2)
739
0
  if (!filtering && TestCpuFlag(kCpuHasSSE2) && src_width < 32768) {
740
0
    ScaleARGBFilterCols = ScaleARGBCols_SSE2;
741
0
  }
742
0
#endif
743
#if defined(HAS_SCALEARGBCOLS_NEON)
744
  if (!filtering && TestCpuFlag(kCpuHasNEON)) {
745
    ScaleARGBFilterCols = ScaleARGBCols_Any_NEON;
746
    if (IS_ALIGNED(dst_width, 8)) {
747
      ScaleARGBFilterCols = ScaleARGBCols_NEON;
748
    }
749
  }
750
#endif
751
0
  if (!filtering && src_width * 2 == dst_width && x < 0x8000) {
752
0
    ScaleARGBFilterCols = ScaleARGBColsUp2_C;
753
0
#if defined(HAS_SCALEARGBCOLSUP2_SSE2)
754
0
    if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8)) {
755
0
      ScaleARGBFilterCols = ScaleARGBColsUp2_SSE2;
756
0
    }
757
0
#endif
758
0
  }
759
0
760
0
  if (y > max_y) {
761
0
    y = max_y;
762
0
  }
763
0
764
0
  int yi = y >> 16;
765
0
766
0
  YUVBuferIter iter;
767
0
  iter.src_width = src_width;
768
0
  iter.src_height = src_height;
769
0
  iter.src_stride_y = src_stride_y;
770
0
  iter.src_stride_u = src_stride_u;
771
0
  iter.src_stride_v = src_stride_v;
772
0
  iter.src_y = src_y;
773
0
  iter.src_u = src_u;
774
0
  iter.src_v = src_v;
775
0
  YUVBuferIter_Init(iter, src_fourcc, yuv_color_space);
776
0
  iter.MoveTo(iter, yi);
777
0
778
0
  // Allocate 2 rows of ARGB.
779
0
  const int kRowSize = (dst_width * 4 + 15) & ~15;
780
0
  align_buffer_64(row, kRowSize * 2);
781
0
782
0
  uint8* rowptr = row;
783
0
  int rowstride = kRowSize;
784
0
  int lastyi = yi;
785
0
786
0
  YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_row);
787
0
  ScaleARGBFilterCols(rowptr, argb_cnv_row, dst_width, x, dx);
788
0
789
0
  if (filtering == kFilterLinear) {
790
0
    rowstride = 0;
791
0
  }
792
0
  // Prepare next row if necessary
793
0
  if (filtering != kFilterLinear) {
794
0
    if ((yi + 1) < src_height) {
795
0
      iter.MoveToNextRow(iter);
796
0
      YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_row);
797
0
      ScaleARGBFilterCols(rowptr + rowstride, argb_cnv_row, dst_width, x, dx);
798
0
    }else {
799
0
      rowstride = 0;
800
0
    }
801
0
  }
802
0
803
0
  const int max_yi = src_height - 1;
804
0
  for (j = 0; j < dst_height; ++j) {
805
0
    yi = y >> 16;
806
0
    if (yi != lastyi) {
807
0
      if (y > max_y) {
808
0
        y = max_y;
809
0
        yi = y >> 16;
810
0
      }
811
0
      if (yi != lastyi) {
812
0
        if (filtering == kFilterLinear) {
813
0
            iter.MoveToNextRow(iter);
814
0
            YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_row);
815
0
            ScaleARGBFilterCols(rowptr, argb_cnv_row, dst_width, x, dx);
816
0
        } else {
817
0
          // Prepare next row if necessary
818
0
          if (yi < max_yi) {
819
0
            iter.MoveToNextRow(iter);
820
0
            rowptr += rowstride;
821
0
            rowstride = -rowstride;
822
0
            // TODO(fbarchard): Convert the clipped region of row.
823
0
            YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_row);
824
0
            ScaleARGBFilterCols(rowptr + rowstride, argb_cnv_row, dst_width, x, dx);
825
0
          } else {
826
0
            rowstride = 0;
827
0
          }
828
0
        }
829
0
        lastyi = yi;
830
0
      }
831
0
    }
832
0
    if (filtering == kFilterLinear) {
833
0
      InterpolateRow(dst_argb, rowptr, 0, dst_width * 4, 0);
834
0
    } else {
835
0
      int yf = (y >> 8) & 255;
836
0
      InterpolateRow(dst_argb, rowptr, rowstride, dst_width * 4, yf);
837
0
    }
838
0
    dst_argb += dst_stride_argb;
839
0
    y += dy;
840
0
  }
841
0
  free_aligned_buffer_64(row);
842
0
  free_aligned_buffer_64(argb_cnv_row);
843
0
}
844
845
// Scale ARGB to/from any dimensions, without interpolation.
846
// Fixed point math is used for performance: The upper 16 bits
847
// of x and dx is the integer part of the source position and
848
// the lower 16 bits are the fixed decimal part.
849
850
static void ScaleYUVToARGBSimple(int src_width, int src_height,
851
                                 int dst_width, int dst_height,
852
                                 int src_stride_y,
853
                                 int src_stride_u,
854
                                 int src_stride_v,
855
                                 int dst_stride_argb,
856
                                 const uint8* src_y,
857
                                 const uint8* src_u,
858
                                 const uint8* src_v,
859
                                 uint8* dst_argb,
860
                                 int x, int dx, int y, int dy,
861
                                 uint32 src_fourcc,
862
0
                                 mozilla::YUVColorSpace yuv_color_space) {
863
0
  int j;
864
0
  void (*ScaleARGBCols)(uint8* dst_argb, const uint8* src_argb,
865
0
      int dst_width, int x, int dx) =
866
0
      (src_width >= 32768) ? ScaleARGBCols64_C : ScaleARGBCols_C;
867
0
868
0
  // Allocate 1 row of ARGB for source conversion.
869
0
  align_buffer_64(argb_cnv_row, src_width * 4);
870
0
871
0
#if defined(HAS_SCALEARGBCOLS_SSE2)
872
0
  if (TestCpuFlag(kCpuHasSSE2) && src_width < 32768) {
873
0
    ScaleARGBCols = ScaleARGBCols_SSE2;
874
0
  }
875
0
#endif
876
#if defined(HAS_SCALEARGBCOLS_NEON)
877
  if (TestCpuFlag(kCpuHasNEON)) {
878
    ScaleARGBCols = ScaleARGBCols_Any_NEON;
879
    if (IS_ALIGNED(dst_width, 8)) {
880
      ScaleARGBCols = ScaleARGBCols_NEON;
881
    }
882
  }
883
#endif
884
0
  if (src_width * 2 == dst_width && x < 0x8000) {
885
0
    ScaleARGBCols = ScaleARGBColsUp2_C;
886
0
#if defined(HAS_SCALEARGBCOLSUP2_SSE2)
887
0
    if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8)) {
888
0
      ScaleARGBCols = ScaleARGBColsUp2_SSE2;
889
0
    }
890
0
#endif
891
0
  }
892
0
893
0
  int yi = y >> 16;
894
0
895
0
  YUVBuferIter iter;
896
0
  iter.src_width = src_width;
897
0
  iter.src_height = src_height;
898
0
  iter.src_stride_y = src_stride_y;
899
0
  iter.src_stride_u = src_stride_u;
900
0
  iter.src_stride_v = src_stride_v;
901
0
  iter.src_y = src_y;
902
0
  iter.src_u = src_u;
903
0
  iter.src_v = src_v;
904
0
  YUVBuferIter_Init(iter, src_fourcc, yuv_color_space);
905
0
  iter.MoveTo(iter, yi);
906
0
907
0
  int lasty = yi;
908
0
  YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_row);
909
0
910
0
  for (j = 0; j < dst_height; ++j) {
911
0
    yi = y >> 16;
912
0
    if (yi != lasty) {
913
0
      iter.MoveTo(iter, yi);
914
0
      YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_row);
915
0
      lasty = yi;
916
0
    }
917
0
    ScaleARGBCols(dst_argb, argb_cnv_row, dst_width, x, dx);
918
0
    dst_argb += dst_stride_argb;
919
0
    y += dy;
920
0
  }
921
0
  free_aligned_buffer_64(argb_cnv_row);
922
0
}
923
924
static void YUVToARGBCopy(const uint8* src_y, int src_stride_y,
925
                          const uint8* src_u, int src_stride_u,
926
                          const uint8* src_v, int src_stride_v,
927
                          int src_width, int src_height,
928
                          uint8* dst_argb, int dst_stride_argb,
929
                          int dst_width, int dst_height,
930
                          uint32 src_fourcc,
931
                          mozilla::YUVColorSpace yuv_color_space)
932
0
{
933
0
  YUVBuferIter iter;
934
0
  iter.src_width = src_width;
935
0
  iter.src_height = src_height;
936
0
  iter.src_stride_y = src_stride_y;
937
0
  iter.src_stride_u = src_stride_u;
938
0
  iter.src_stride_v = src_stride_v;
939
0
  iter.src_y = src_y;
940
0
  iter.src_u = src_u;
941
0
  iter.src_v = src_v;
942
0
  YUVBuferIter_Init(iter, src_fourcc, yuv_color_space);
943
0
944
0
  for (int j = 0; j < dst_height; ++j) {
945
0
    YUVBuferIter_ConvertToARGBRow(iter, dst_argb);
946
0
    iter.MoveToNextRow(iter);
947
0
    dst_argb += dst_stride_argb;
948
0
  }
949
0
}
950
951
static void ScaleYUVToARGB(const uint8* src_y, int src_stride_y,
952
                           const uint8* src_u, int src_stride_u,
953
                           const uint8* src_v, int src_stride_v,
954
                           int src_width, int src_height,
955
                           uint8* dst_argb, int dst_stride_argb,
956
                           int dst_width, int dst_height,
957
                           enum FilterMode filtering,
958
                           uint32 src_fourcc,
959
                           mozilla::YUVColorSpace yuv_color_space)
960
0
{
961
0
  // Initial source x/y coordinate and step values as 16.16 fixed point.
962
0
  int x = 0;
963
0
  int y = 0;
964
0
  int dx = 0;
965
0
  int dy = 0;
966
0
  // ARGB does not support box filter yet, but allow the user to pass it.
967
0
  // Simplify filtering when possible.
968
0
  filtering = ScaleFilterReduce(src_width, src_height,
969
0
                                dst_width, dst_height,
970
0
                                filtering);
971
0
  ScaleSlope(src_width, src_height, dst_width, dst_height, filtering,
972
0
             &x, &y, &dx, &dy);
973
0
974
0
  // Special case for integer step values.
975
0
  if (((dx | dy) & 0xffff) == 0) {
976
0
    if (!dx || !dy) {  // 1 pixel wide and/or tall.
977
0
      filtering = kFilterNone;
978
0
    } else {
979
0
      // Optimized even scale down. ie 2, 4, 6, 8, 10x.
980
0
      if (!(dx & 0x10000) && !(dy & 0x10000)) {
981
0
        if (dx == 0x20000) {
982
0
          // Optimized 1/2 downsample.
983
0
          ScaleYUVToARGBDown2(src_width, src_height,
984
0
                              dst_width, dst_height,
985
0
                              src_stride_y,
986
0
                              src_stride_u,
987
0
                              src_stride_v,
988
0
                              dst_stride_argb,
989
0
                              src_y,
990
0
                              src_u,
991
0
                              src_v,
992
0
                              dst_argb,
993
0
                              x, dx, y, dy,
994
0
                              filtering,
995
0
                              src_fourcc,
996
0
                              yuv_color_space);
997
0
          return;
998
0
        }
999
0
        ScaleYUVToARGBDownEven(src_width, src_height,
1000
0
                               dst_width, dst_height,
1001
0
                               src_stride_y,
1002
0
                               src_stride_u,
1003
0
                               src_stride_v,
1004
0
                               dst_stride_argb,
1005
0
                               src_y,
1006
0
                               src_u,
1007
0
                               src_v,
1008
0
                               dst_argb,
1009
0
                               x, dx, y, dy,
1010
0
                               filtering,
1011
0
                               src_fourcc,
1012
0
                               yuv_color_space);
1013
0
        return;
1014
0
      }
1015
0
      // Optimized odd scale down. ie 3, 5, 7, 9x.
1016
0
      if ((dx & 0x10000) && (dy & 0x10000)) {
1017
0
        filtering = kFilterNone;
1018
0
        if (dx == 0x10000 && dy == 0x10000) {
1019
0
          // Straight conversion and copy.
1020
0
          YUVToARGBCopy(src_y, src_stride_y,
1021
0
                        src_u, src_stride_u,
1022
0
                        src_v, src_stride_v,
1023
0
                        src_width, src_height,
1024
0
                        dst_argb, dst_stride_argb,
1025
0
                        dst_width, dst_height,
1026
0
                        src_fourcc,
1027
0
                        yuv_color_space);
1028
0
          return;
1029
0
        }
1030
0
      }
1031
0
    }
1032
0
  }
1033
0
  if (filtering && dy < 65536) {
1034
0
    ScaleYUVToARGBBilinearUp(src_width, src_height,
1035
0
                             dst_width, dst_height,
1036
0
                             src_stride_y,
1037
0
                             src_stride_u,
1038
0
                             src_stride_v,
1039
0
                             dst_stride_argb,
1040
0
                             src_y,
1041
0
                             src_u,
1042
0
                             src_v,
1043
0
                             dst_argb,
1044
0
                             x, dx, y, dy,
1045
0
                             filtering,
1046
0
                             src_fourcc,
1047
0
                             yuv_color_space);
1048
0
    return;
1049
0
  }
1050
0
  if (filtering) {
1051
0
    ScaleYUVToARGBBilinearDown(src_width, src_height,
1052
0
                               dst_width, dst_height,
1053
0
                               src_stride_y,
1054
0
                               src_stride_u,
1055
0
                               src_stride_v,
1056
0
                               dst_stride_argb,
1057
0
                               src_y,
1058
0
                               src_u,
1059
0
                               src_v,
1060
0
                               dst_argb,
1061
0
                               x, dx, y, dy,
1062
0
                               filtering,
1063
0
                               src_fourcc,
1064
0
                               yuv_color_space);
1065
0
    return;
1066
0
  }
1067
0
  ScaleYUVToARGBSimple(src_width, src_height,
1068
0
                       dst_width, dst_height,
1069
0
                       src_stride_y,
1070
0
                       src_stride_u,
1071
0
                       src_stride_v,
1072
0
                       dst_stride_argb,
1073
0
                       src_y,
1074
0
                       src_u,
1075
0
                       src_v,
1076
0
                       dst_argb,
1077
0
                       x, dx, y, dy,
1078
0
                       src_fourcc,
1079
0
                       yuv_color_space);
1080
0
}
1081
1082
bool IsConvertSupported(uint32 src_fourcc)
1083
0
{
1084
0
  if (src_fourcc == FOURCC_I444 ||
1085
0
      src_fourcc == FOURCC_I422 ||
1086
0
      src_fourcc == FOURCC_I420) {
1087
0
    return true;
1088
0
  }
1089
0
  return false;
1090
0
}
1091
1092
LIBYUV_API
1093
int YUVToARGBScale(const uint8* src_y, int src_stride_y,
1094
                   const uint8* src_u, int src_stride_u,
1095
                   const uint8* src_v, int src_stride_v,
1096
                   uint32 src_fourcc,
1097
                   mozilla::YUVColorSpace yuv_color_space,
1098
                   int src_width, int src_height,
1099
                   uint8* dst_argb, int dst_stride_argb,
1100
                   int dst_width, int dst_height,
1101
                   enum FilterMode filtering)
1102
0
{
1103
0
  if (!src_y || !src_u || !src_v ||
1104
0
      src_width == 0 || src_height == 0 ||
1105
0
      !dst_argb || dst_width <= 0 || dst_height <= 0) {
1106
0
    return -1;
1107
0
  }
1108
0
  if (!IsConvertSupported(src_fourcc)) {
1109
0
    return -1;
1110
0
  }
1111
0
  ScaleYUVToARGB(src_y, src_stride_y,
1112
0
                 src_u, src_stride_u,
1113
0
                 src_v, src_stride_v,
1114
0
                 src_width, src_height,
1115
0
                 dst_argb, dst_stride_argb,
1116
0
                 dst_width, dst_height,
1117
0
                 filtering,
1118
0
                 src_fourcc,
1119
0
                 yuv_color_space);
1120
0
  return 0;
1121
0
}
1122
1123
#ifdef __cplusplus
1124
}  // extern "C"
1125
}  // namespace libyuv
1126
#endif