Line data Source code
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 : static __inline int Abs(int v) {
60 : return v >= 0 ? v : -v;
61 : }
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 : #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 : }
98 : }
99 : #endif
100 : #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 : }
106 : }
107 : #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 0 : }
126 :
127 0 : void YUVBuferIter_InitI444(YUVBuferIter& iter) {
128 0 : iter.YUVToARGBRow = I444ToARGBRow_C;
129 : #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 : }
135 : }
136 : #endif
137 : #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 : }
143 : }
144 : #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 0 : }
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 :
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 : }
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 : } else {
216 0 : iter.yuvconstants = &kYuvI601Constants;
217 : }
218 :
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 : } 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 : }
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 0 : 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 : mozilla::YUVColorSpace yuv_color_space) {
252 : int j;
253 :
254 : // 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 :
260 : 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 :
271 : void (*ScaleARGBRowDown2)(const uint8* src_argb, ptrdiff_t src_stride,
272 : 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 : // Advance to odd row, even column.
279 0 : int yi = y >> 16;
280 0 : iter.MoveTo(iter, yi);
281 : ptrdiff_t x_offset;
282 0 : if (filtering == kFilterBilinear) {
283 0 : x_offset = (x >> 16) * 4;
284 : } else {
285 0 : x_offset = ((x >> 16) - 1) * 4;
286 : }
287 : #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 : 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 : ScaleARGBRowDown2Box_SSE2);
296 : }
297 : }
298 :
299 : #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 : // 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 : } else {
322 0 : argb_cnv_rowstride = 0;
323 : }
324 : }
325 :
326 0 : if (filtering == kFilterLinear) {
327 0 : argb_cnv_rowstride = 0;
328 : }
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 : }
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 : } else {
342 : // 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 : } 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 : }
352 : // 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 : } else {
358 0 : argb_cnv_rowstride = 0;
359 : }
360 0 : lastyi = yi;
361 : }
362 : }
363 : }
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 : }
368 :
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 0 : 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 : mozilla::YUVColorSpace yuv_color_space) {
389 : int j;
390 : // 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 :
396 0 : int col_step = dx >> 16;
397 : void (*ScaleARGBRowDownEven)(const uint8* src_argb, ptrdiff_t src_stride,
398 : 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 :
405 : #if defined(HAS_SCALEARGBROWDOWNEVEN_SSE2)
406 0 : if (TestCpuFlag(kCpuHasSSE2)) {
407 0 : ScaleARGBRowDownEven = filtering ? ScaleARGBRowDownEvenBox_Any_SSE2 :
408 : ScaleARGBRowDownEven_Any_SSE2;
409 0 : if (IS_ALIGNED(dst_width, 4)) {
410 0 : ScaleARGBRowDownEven = filtering ? ScaleARGBRowDownEvenBox_SSE2 :
411 : ScaleARGBRowDownEven_SSE2;
412 : }
413 : }
414 : #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 : 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 :
437 0 : const int dyi = dy >> 16;
438 0 : int lastyi = yi;
439 0 : YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_rowptr);
440 : // 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 : } else {
446 0 : argb_cnv_rowstride = 0;
447 : }
448 : }
449 :
450 0 : if (filtering == kFilterLinear) {
451 0 : argb_cnv_rowstride = 0;
452 : }
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 : }
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 : } else {
466 : // 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 : } 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 : }
476 : // 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 : } else {
482 0 : argb_cnv_rowstride = 0;
483 : }
484 0 : lastyi = yi;
485 : }
486 : }
487 : }
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 : }
492 0 : free_aligned_buffer_64(argb_cnv_row);
493 0 : }
494 :
495 : // Scale YUV to ARGB down with bilinear interpolation.
496 0 : 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 : mozilla::YUVColorSpace yuv_color_space) {
510 : int j;
511 : void (*InterpolateRow)(uint8* dst_argb, const uint8* src_argb,
512 : ptrdiff_t src_stride, int dst_width, int source_y_fraction) =
513 0 : InterpolateRow_C;
514 : void (*ScaleARGBFilterCols)(uint8* dst_argb, const uint8* src_argb,
515 : 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 : 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 : }
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 :
531 : // 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 :
537 : #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 : }
543 : }
544 : #endif
545 : #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 : }
551 : }
552 : #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 : }
574 : #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 :
586 : 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 :
598 : // TODO(fbarchard): Consider not allocating row buffer for kFilterLinear.
599 : // Allocate a row of ARGB.
600 0 : align_buffer_64(row, clip_src_width * 4);
601 :
602 0 : int lastyi = yi;
603 0 : YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_rowptr);
604 : // 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 : } else {
610 0 : argb_cnv_rowstride = 0;
611 : }
612 : }
613 :
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 : }
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 : } else {
629 : // 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 : } 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 : }
639 : // 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 : } else {
644 0 : argb_cnv_rowstride = 0;
645 : }
646 0 : lastyi = yi;
647 : }
648 : }
649 : }
650 0 : if (filtering == kFilterLinear) {
651 0 : ScaleARGBFilterCols(dst_argb, argb_cnv_rowptr + xl_offset, dst_width, x, dx);
652 : } 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 : }
657 0 : dst_argb += dst_stride_argb;
658 0 : y += dy;
659 : }
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 0 : 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 : mozilla::YUVColorSpace yuv_color_space) {
679 : int j;
680 : void (*InterpolateRow)(uint8* dst_argb, const uint8* src_argb,
681 : ptrdiff_t src_stride, int dst_width, int source_y_fraction) =
682 0 : InterpolateRow_C;
683 : void (*ScaleARGBFilterCols)(uint8* dst_argb, const uint8* src_argb,
684 : 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 :
688 : // Allocate 1 row of ARGB for source conversion.
689 0 : align_buffer_64(argb_cnv_row, src_width * 4);
690 :
691 : #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 : }
697 : }
698 : #endif
699 : #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 : }
705 : }
706 : #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 : ScaleARGBFilterCols64_C : ScaleARGBCols64_C;
724 : }
725 : #if defined(HAS_SCALEARGBFILTERCOLS_SSSE3)
726 0 : if (filtering && TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
727 0 : ScaleARGBFilterCols = ScaleARGBFilterCols_SSSE3;
728 : }
729 : #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 : }
742 : #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 : #if defined(HAS_SCALEARGBCOLSUP2_SSE2)
754 0 : if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8)) {
755 0 : ScaleARGBFilterCols = ScaleARGBColsUp2_SSE2;
756 : }
757 : #endif
758 : }
759 :
760 0 : if (y > max_y) {
761 0 : y = max_y;
762 : }
763 :
764 0 : int yi = y >> 16;
765 :
766 : 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 :
778 : // Allocate 2 rows of ARGB.
779 0 : const int kRowSize = (dst_width * 4 + 15) & ~15;
780 0 : align_buffer_64(row, kRowSize * 2);
781 :
782 0 : uint8* rowptr = row;
783 0 : int rowstride = kRowSize;
784 0 : int lastyi = yi;
785 :
786 0 : YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_row);
787 0 : ScaleARGBFilterCols(rowptr, argb_cnv_row, dst_width, x, dx);
788 :
789 0 : if (filtering == kFilterLinear) {
790 0 : rowstride = 0;
791 : }
792 : // 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 : }else {
799 0 : rowstride = 0;
800 : }
801 : }
802 :
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 : }
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 : } else {
817 : // 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 : // 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 : } else {
826 0 : rowstride = 0;
827 : }
828 : }
829 0 : lastyi = yi;
830 : }
831 : }
832 0 : if (filtering == kFilterLinear) {
833 0 : InterpolateRow(dst_argb, rowptr, 0, dst_width * 4, 0);
834 : } else {
835 0 : int yf = (y >> 8) & 255;
836 0 : InterpolateRow(dst_argb, rowptr, rowstride, dst_width * 4, yf);
837 : }
838 0 : dst_argb += dst_stride_argb;
839 0 : y += dy;
840 : }
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 0 : 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 : mozilla::YUVColorSpace yuv_color_space) {
863 : int j;
864 : void (*ScaleARGBCols)(uint8* dst_argb, const uint8* src_argb,
865 : int dst_width, int x, int dx) =
866 0 : (src_width >= 32768) ? ScaleARGBCols64_C : ScaleARGBCols_C;
867 :
868 : // Allocate 1 row of ARGB for source conversion.
869 0 : align_buffer_64(argb_cnv_row, src_width * 4);
870 :
871 : #if defined(HAS_SCALEARGBCOLS_SSE2)
872 0 : if (TestCpuFlag(kCpuHasSSE2) && src_width < 32768) {
873 0 : ScaleARGBCols = ScaleARGBCols_SSE2;
874 : }
875 : #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 : #if defined(HAS_SCALEARGBCOLSUP2_SSE2)
887 0 : if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8)) {
888 0 : ScaleARGBCols = ScaleARGBColsUp2_SSE2;
889 : }
890 : #endif
891 : }
892 :
893 0 : int yi = y >> 16;
894 :
895 : 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 :
907 0 : int lasty = yi;
908 0 : YUVBuferIter_ConvertToARGBRow(iter, argb_cnv_row);
909 :
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 : }
917 0 : ScaleARGBCols(dst_argb, argb_cnv_row, dst_width, x, dx);
918 0 : dst_argb += dst_stride_argb;
919 0 : y += dy;
920 : }
921 0 : free_aligned_buffer_64(argb_cnv_row);
922 0 : }
923 :
924 0 : 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 : {
933 : 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 :
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 : }
949 0 : }
950 :
951 0 : 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 : {
961 : // 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 : // ARGB does not support box filter yet, but allow the user to pass it.
967 : // Simplify filtering when possible.
968 : filtering = ScaleFilterReduce(src_width, src_height,
969 : dst_width, dst_height,
970 0 : filtering);
971 : ScaleSlope(src_width, src_height, dst_width, dst_height, filtering,
972 0 : &x, &y, &dx, &dy);
973 :
974 : // 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 : } else {
979 : // Optimized even scale down. ie 2, 4, 6, 8, 10x.
980 0 : if (!(dx & 0x10000) && !(dy & 0x10000)) {
981 0 : if (dx == 0x20000) {
982 : // Optimized 1/2 downsample.
983 : ScaleYUVToARGBDown2(src_width, src_height,
984 : dst_width, dst_height,
985 : src_stride_y,
986 : src_stride_u,
987 : src_stride_v,
988 : dst_stride_argb,
989 : src_y,
990 : src_u,
991 : src_v,
992 : dst_argb,
993 : x, dx, y, dy,
994 : filtering,
995 : src_fourcc,
996 0 : yuv_color_space);
997 0 : return;
998 : }
999 : ScaleYUVToARGBDownEven(src_width, src_height,
1000 : dst_width, dst_height,
1001 : src_stride_y,
1002 : src_stride_u,
1003 : src_stride_v,
1004 : dst_stride_argb,
1005 : src_y,
1006 : src_u,
1007 : src_v,
1008 : dst_argb,
1009 : x, dx, y, dy,
1010 : filtering,
1011 : src_fourcc,
1012 0 : yuv_color_space);
1013 0 : return;
1014 : }
1015 : // 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 : // Straight conversion and copy.
1020 : YUVToARGBCopy(src_y, src_stride_y,
1021 : src_u, src_stride_u,
1022 : src_v, src_stride_v,
1023 : src_width, src_height,
1024 : dst_argb, dst_stride_argb,
1025 : dst_width, dst_height,
1026 : src_fourcc,
1027 0 : yuv_color_space);
1028 0 : return;
1029 : }
1030 : }
1031 : }
1032 : }
1033 0 : if (filtering && dy < 65536) {
1034 : ScaleYUVToARGBBilinearUp(src_width, src_height,
1035 : dst_width, dst_height,
1036 : src_stride_y,
1037 : src_stride_u,
1038 : src_stride_v,
1039 : dst_stride_argb,
1040 : src_y,
1041 : src_u,
1042 : src_v,
1043 : dst_argb,
1044 : x, dx, y, dy,
1045 : filtering,
1046 : src_fourcc,
1047 0 : yuv_color_space);
1048 0 : return;
1049 : }
1050 0 : if (filtering) {
1051 : ScaleYUVToARGBBilinearDown(src_width, src_height,
1052 : dst_width, dst_height,
1053 : src_stride_y,
1054 : src_stride_u,
1055 : src_stride_v,
1056 : dst_stride_argb,
1057 : src_y,
1058 : src_u,
1059 : src_v,
1060 : dst_argb,
1061 : x, dx, y, dy,
1062 : filtering,
1063 : src_fourcc,
1064 0 : yuv_color_space);
1065 0 : return;
1066 : }
1067 : ScaleYUVToARGBSimple(src_width, src_height,
1068 : dst_width, dst_height,
1069 : src_stride_y,
1070 : src_stride_u,
1071 : src_stride_v,
1072 : dst_stride_argb,
1073 : src_y,
1074 : src_u,
1075 : src_v,
1076 : dst_argb,
1077 : x, dx, y, dy,
1078 : src_fourcc,
1079 0 : yuv_color_space);
1080 : }
1081 :
1082 0 : bool IsConvertSupported(uint32 src_fourcc)
1083 : {
1084 0 : if (src_fourcc == FOURCC_I444 ||
1085 0 : src_fourcc == FOURCC_I422 ||
1086 : src_fourcc == FOURCC_I420) {
1087 0 : return true;
1088 : }
1089 0 : return false;
1090 : }
1091 :
1092 : LIBYUV_API
1093 0 : 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 : {
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 : }
1108 0 : if (!IsConvertSupported(src_fourcc)) {
1109 0 : return -1;
1110 : }
1111 : ScaleYUVToARGB(src_y, src_stride_y,
1112 : src_u, src_stride_u,
1113 : src_v, src_stride_v,
1114 : src_width, src_height,
1115 : dst_argb, dst_stride_argb,
1116 : dst_width, dst_height,
1117 : filtering,
1118 : src_fourcc,
1119 0 : yuv_color_space);
1120 0 : return 0;
1121 : }
1122 :
1123 : #ifdef __cplusplus
1124 : } // extern "C"
1125 : } // namespace libyuv
1126 : #endif
|