LCOV - code coverage report
Current view: top level - gfx/ycbcr - scale_yuv_argb.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 470 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 19 0.0 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.13