Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / media / base / yuv_convert.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // This webpage shows layout of YV12 and other YUV formats
6 // http://www.fourcc.org/yuv.php
7 // The actual conversion is best described here
8 // http://en.wikipedia.org/wiki/YUV
9 // An article on optimizing YUV conversion using tables instead of multiplies
10 // http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf
11 //
12 // YV12 is a full plane of Y and a half height, half width chroma planes
13 // YV16 is a full plane of Y and a full height, half width chroma planes
14 //
15 // ARGB pixel format is output, which on little endian is stored as BGRA.
16 // The alpha is set to 255, allowing the application to use RGBA or RGB32.
17
18 #include "media/base/yuv_convert.h"
19
20 #include "base/cpu.h"
21 #include "base/logging.h"
22 #include "base/memory/scoped_ptr.h"
23 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
24 #include "build/build_config.h"
25 #include "media/base/simd/convert_rgb_to_yuv.h"
26 #include "media/base/simd/convert_yuv_to_rgb.h"
27 #include "media/base/simd/filter_yuv.h"
28 #include "media/base/simd/yuv_to_rgb_table.h"
29
30 #if defined(ARCH_CPU_X86_FAMILY)
31 #if defined(COMPILER_MSVC)
32 #include <intrin.h>
33 #else
34 #include <mmintrin.h>
35 #endif
36 #endif
37
38 // Assembly functions are declared without namespace.
39 extern "C" { void EmptyRegisterState_MMX(); }  // extern "C"
40
41 namespace media {
42
43 typedef void (*FilterYUVRowsProc)(uint8*,
44                                   const uint8*,
45                                   const uint8*,
46                                   int,
47                                   uint8);
48
49 typedef void (*ConvertRGBToYUVProc)(const uint8*,
50                                     uint8*,
51                                     uint8*,
52                                     uint8*,
53                                     int,
54                                     int,
55                                     int,
56                                     int,
57                                     int);
58
59 typedef void (*ConvertYUVToRGB32Proc)(const uint8*,
60                                       const uint8*,
61                                       const uint8*,
62                                       uint8*,
63                                       int,
64                                       int,
65                                       int,
66                                       int,
67                                       int,
68                                       YUVType);
69
70 typedef void (*ConvertYUVAToARGBProc)(const uint8*,
71                                       const uint8*,
72                                       const uint8*,
73                                       const uint8*,
74                                       uint8*,
75                                       int,
76                                       int,
77                                       int,
78                                       int,
79                                       int,
80                                       int,
81                                       YUVType);
82
83 typedef void (*ConvertYUVToRGB32RowProc)(const uint8*,
84                                          const uint8*,
85                                          const uint8*,
86                                          uint8*,
87                                          ptrdiff_t,
88                                          const int16[1024][4]);
89
90 typedef void (*ConvertYUVAToARGBRowProc)(const uint8*,
91                                          const uint8*,
92                                          const uint8*,
93                                          const uint8*,
94                                          uint8*,
95                                          ptrdiff_t,
96                                          const int16[1024][4]);
97
98 typedef void (*ScaleYUVToRGB32RowProc)(const uint8*,
99                                        const uint8*,
100                                        const uint8*,
101                                        uint8*,
102                                        ptrdiff_t,
103                                        ptrdiff_t,
104                                        const int16[1024][4]);
105
106 static FilterYUVRowsProc g_filter_yuv_rows_proc_ = NULL;
107 static ConvertYUVToRGB32RowProc g_convert_yuv_to_rgb32_row_proc_ = NULL;
108 static ScaleYUVToRGB32RowProc g_scale_yuv_to_rgb32_row_proc_ = NULL;
109 static ScaleYUVToRGB32RowProc g_linear_scale_yuv_to_rgb32_row_proc_ = NULL;
110 static ConvertRGBToYUVProc g_convert_rgb32_to_yuv_proc_ = NULL;
111 static ConvertRGBToYUVProc g_convert_rgb24_to_yuv_proc_ = NULL;
112 static ConvertYUVToRGB32Proc g_convert_yuv_to_rgb32_proc_ = NULL;
113 static ConvertYUVAToARGBProc g_convert_yuva_to_argb_proc_ = NULL;
114
115 // Empty SIMD registers state after using them.
116 void EmptyRegisterStateStub() {}
117 #if defined(MEDIA_MMX_INTRINSICS_AVAILABLE)
118 void EmptyRegisterStateIntrinsic() { _mm_empty(); }
119 #endif
120 typedef void (*EmptyRegisterStateProc)();
121 static EmptyRegisterStateProc g_empty_register_state_proc_ = NULL;
122
123 // Get the appropriate value to bitshift by for vertical indices.
124 int GetVerticalShift(YUVType type) {
125   switch (type) {
126     case YV16:
127       return 0;
128     case YV12:
129     case YV12J:
130       return 1;
131   }
132   NOTREACHED();
133   return 0;
134 }
135
136 const int16 (&GetLookupTable(YUVType type))[1024][4] {
137   switch (type) {
138     case YV12:
139     case YV16:
140       return kCoefficientsRgbY;
141     case YV12J:
142       return kCoefficientsRgbY_JPEG;
143   }
144   NOTREACHED();
145   return kCoefficientsRgbY;
146 }
147
148 void InitializeCPUSpecificYUVConversions() {
149   CHECK(!g_filter_yuv_rows_proc_);
150   CHECK(!g_convert_yuv_to_rgb32_row_proc_);
151   CHECK(!g_scale_yuv_to_rgb32_row_proc_);
152   CHECK(!g_linear_scale_yuv_to_rgb32_row_proc_);
153   CHECK(!g_convert_rgb32_to_yuv_proc_);
154   CHECK(!g_convert_rgb24_to_yuv_proc_);
155   CHECK(!g_convert_yuv_to_rgb32_proc_);
156   CHECK(!g_convert_yuva_to_argb_proc_);
157   CHECK(!g_empty_register_state_proc_);
158
159   g_filter_yuv_rows_proc_ = FilterYUVRows_C;
160   g_convert_yuv_to_rgb32_row_proc_ = ConvertYUVToRGB32Row_C;
161   g_scale_yuv_to_rgb32_row_proc_ = ScaleYUVToRGB32Row_C;
162   g_linear_scale_yuv_to_rgb32_row_proc_ = LinearScaleYUVToRGB32Row_C;
163   g_convert_rgb32_to_yuv_proc_ = ConvertRGB32ToYUV_C;
164   g_convert_rgb24_to_yuv_proc_ = ConvertRGB24ToYUV_C;
165   g_convert_yuv_to_rgb32_proc_ = ConvertYUVToRGB32_C;
166   g_convert_yuva_to_argb_proc_ = ConvertYUVAToARGB_C;
167   g_empty_register_state_proc_ = EmptyRegisterStateStub;
168
169   // Assembly code confuses MemorySanitizer.
170 #if defined(ARCH_CPU_X86_FAMILY) && !defined(MEMORY_SANITIZER)
171   g_convert_yuva_to_argb_proc_ = ConvertYUVAToARGB_MMX;
172
173 #if defined(MEDIA_MMX_INTRINSICS_AVAILABLE)
174   g_empty_register_state_proc_ = EmptyRegisterStateIntrinsic;
175 #else
176   g_empty_register_state_proc_ = EmptyRegisterState_MMX;
177 #endif
178
179   g_convert_yuv_to_rgb32_row_proc_ = ConvertYUVToRGB32Row_SSE;
180   g_convert_yuv_to_rgb32_proc_ = ConvertYUVToRGB32_SSE;
181
182   g_filter_yuv_rows_proc_ = FilterYUVRows_SSE2;
183   g_convert_rgb32_to_yuv_proc_ = ConvertRGB32ToYUV_SSE2;
184
185 #if defined(ARCH_CPU_X86_64)
186   g_scale_yuv_to_rgb32_row_proc_ = ScaleYUVToRGB32Row_SSE2_X64;
187
188   // Technically this should be in the MMX section, but MSVC will optimize out
189   // the export of LinearScaleYUVToRGB32Row_MMX, which is required by the unit
190   // tests, if that decision can be made at compile time.  Since all X64 CPUs
191   // have SSE2, we can hack around this by making the selection here.
192   g_linear_scale_yuv_to_rgb32_row_proc_ = LinearScaleYUVToRGB32Row_MMX_X64;
193 #else
194   g_scale_yuv_to_rgb32_row_proc_ = ScaleYUVToRGB32Row_SSE;
195   g_linear_scale_yuv_to_rgb32_row_proc_ = LinearScaleYUVToRGB32Row_SSE;
196 #endif
197
198   base::CPU cpu;
199   if (cpu.has_ssse3()) {
200     g_convert_rgb24_to_yuv_proc_ = &ConvertRGB24ToYUV_SSSE3;
201
202     // TODO(hclam): Add ConvertRGB32ToYUV_SSSE3 when the cyan problem is solved.
203     // See: crbug.com/100462
204   }
205 #endif
206 }
207
208 // Empty SIMD registers state after using them.
209 void EmptyRegisterState() { g_empty_register_state_proc_(); }
210
211 // 16.16 fixed point arithmetic
212 const int kFractionBits = 16;
213 const int kFractionMax = 1 << kFractionBits;
214 const int kFractionMask = ((1 << kFractionBits) - 1);
215
216 // Scale a frame of YUV to 32 bit ARGB.
217 void ScaleYUVToRGB32(const uint8* y_buf,
218                      const uint8* u_buf,
219                      const uint8* v_buf,
220                      uint8* rgb_buf,
221                      int source_width,
222                      int source_height,
223                      int width,
224                      int height,
225                      int y_pitch,
226                      int uv_pitch,
227                      int rgb_pitch,
228                      YUVType yuv_type,
229                      Rotate view_rotate,
230                      ScaleFilter filter) {
231   // Handle zero sized sources and destinations.
232   if ((yuv_type == YV12 && (source_width < 2 || source_height < 2)) ||
233       (yuv_type == YV16 && (source_width < 2 || source_height < 1)) ||
234       width == 0 || height == 0)
235     return;
236
237   // 4096 allows 3 buffers to fit in 12k.
238   // Helps performance on CPU with 16K L1 cache.
239   // Large enough for 3830x2160 and 30" displays which are 2560x1600.
240   const int kFilterBufferSize = 4096;
241   // Disable filtering if the screen is too big (to avoid buffer overflows).
242   // This should never happen to regular users: they don't have monitors
243   // wider than 4096 pixels.
244   // TODO(fbarchard): Allow rotated videos to filter.
245   if (source_width > kFilterBufferSize || view_rotate)
246     filter = FILTER_NONE;
247
248   unsigned int y_shift = GetVerticalShift(yuv_type);
249   // Diagram showing origin and direction of source sampling.
250   // ->0   4<-
251   // 7       3
252   //
253   // 6       5
254   // ->1   2<-
255   // Rotations that start at right side of image.
256   if ((view_rotate == ROTATE_180) || (view_rotate == ROTATE_270) ||
257       (view_rotate == MIRROR_ROTATE_0) || (view_rotate == MIRROR_ROTATE_90)) {
258     y_buf += source_width - 1;
259     u_buf += source_width / 2 - 1;
260     v_buf += source_width / 2 - 1;
261     source_width = -source_width;
262   }
263   // Rotations that start at bottom of image.
264   if ((view_rotate == ROTATE_90) || (view_rotate == ROTATE_180) ||
265       (view_rotate == MIRROR_ROTATE_90) || (view_rotate == MIRROR_ROTATE_180)) {
266     y_buf += (source_height - 1) * y_pitch;
267     u_buf += ((source_height >> y_shift) - 1) * uv_pitch;
268     v_buf += ((source_height >> y_shift) - 1) * uv_pitch;
269     source_height = -source_height;
270   }
271
272   int source_dx = source_width * kFractionMax / width;
273
274   if ((view_rotate == ROTATE_90) || (view_rotate == ROTATE_270)) {
275     int tmp = height;
276     height = width;
277     width = tmp;
278     tmp = source_height;
279     source_height = source_width;
280     source_width = tmp;
281     int source_dy = source_height * kFractionMax / height;
282     source_dx = ((source_dy >> kFractionBits) * y_pitch) << kFractionBits;
283     if (view_rotate == ROTATE_90) {
284       y_pitch = -1;
285       uv_pitch = -1;
286       source_height = -source_height;
287     } else {
288       y_pitch = 1;
289       uv_pitch = 1;
290     }
291   }
292
293   // Need padding because FilterRows() will write 1 to 16 extra pixels
294   // after the end for SSE2 version.
295   uint8 yuvbuf[16 + kFilterBufferSize * 3 + 16];
296   uint8* ybuf =
297       reinterpret_cast<uint8*>(reinterpret_cast<uintptr_t>(yuvbuf + 15) & ~15);
298   uint8* ubuf = ybuf + kFilterBufferSize;
299   uint8* vbuf = ubuf + kFilterBufferSize;
300
301   // TODO(fbarchard): Fixed point math is off by 1 on negatives.
302
303   // We take a y-coordinate in [0,1] space in the source image space, and
304   // transform to a y-coordinate in [0,1] space in the destination image space.
305   // Note that the coordinate endpoints lie on pixel boundaries, not on pixel
306   // centers: e.g. a two-pixel-high image will have pixel centers at 0.25 and
307   // 0.75.  The formula is as follows (in fixed-point arithmetic):
308   //   y_dst = dst_height * ((y_src + 0.5) / src_height)
309   //   dst_pixel = clamp([0, dst_height - 1], floor(y_dst - 0.5))
310   // Implement this here as an accumulator + delta, to avoid expensive math
311   // in the loop.
312   int source_y_subpixel_accum =
313       ((kFractionMax / 2) * source_height) / height - (kFractionMax / 2);
314   int source_y_subpixel_delta = ((1 << kFractionBits) * source_height) / height;
315
316   // TODO(fbarchard): Split this into separate function for better efficiency.
317   for (int y = 0; y < height; ++y) {
318     uint8* dest_pixel = rgb_buf + y * rgb_pitch;
319     int source_y_subpixel = source_y_subpixel_accum;
320     source_y_subpixel_accum += source_y_subpixel_delta;
321     if (source_y_subpixel < 0)
322       source_y_subpixel = 0;
323     else if (source_y_subpixel > ((source_height - 1) << kFractionBits))
324       source_y_subpixel = (source_height - 1) << kFractionBits;
325
326     const uint8* y_ptr = NULL;
327     const uint8* u_ptr = NULL;
328     const uint8* v_ptr = NULL;
329     // Apply vertical filtering if necessary.
330     // TODO(fbarchard): Remove memcpy when not necessary.
331     if (filter & media::FILTER_BILINEAR_V) {
332       int source_y = source_y_subpixel >> kFractionBits;
333       y_ptr = y_buf + source_y * y_pitch;
334       u_ptr = u_buf + (source_y >> y_shift) * uv_pitch;
335       v_ptr = v_buf + (source_y >> y_shift) * uv_pitch;
336
337       // Vertical scaler uses 16.8 fixed point.
338       uint8 source_y_fraction = (source_y_subpixel & kFractionMask) >> 8;
339       if (source_y_fraction != 0) {
340         g_filter_yuv_rows_proc_(
341             ybuf, y_ptr, y_ptr + y_pitch, source_width, source_y_fraction);
342       } else {
343         memcpy(ybuf, y_ptr, source_width);
344       }
345       y_ptr = ybuf;
346       ybuf[source_width] = ybuf[source_width - 1];
347
348       int uv_source_width = (source_width + 1) / 2;
349       uint8 source_uv_fraction;
350
351       // For formats with half-height UV planes, each even-numbered pixel row
352       // should not interpolate, since the next row to interpolate from should
353       // be a duplicate of the current row.
354       if (y_shift && (source_y & 0x1) == 0)
355         source_uv_fraction = 0;
356       else
357         source_uv_fraction = source_y_fraction;
358
359       if (source_uv_fraction != 0) {
360         g_filter_yuv_rows_proc_(
361             ubuf, u_ptr, u_ptr + uv_pitch, uv_source_width, source_uv_fraction);
362         g_filter_yuv_rows_proc_(
363             vbuf, v_ptr, v_ptr + uv_pitch, uv_source_width, source_uv_fraction);
364       } else {
365         memcpy(ubuf, u_ptr, uv_source_width);
366         memcpy(vbuf, v_ptr, uv_source_width);
367       }
368       u_ptr = ubuf;
369       v_ptr = vbuf;
370       ubuf[uv_source_width] = ubuf[uv_source_width - 1];
371       vbuf[uv_source_width] = vbuf[uv_source_width - 1];
372     } else {
373       // Offset by 1/2 pixel for center sampling.
374       int source_y = (source_y_subpixel + (kFractionMax / 2)) >> kFractionBits;
375       y_ptr = y_buf + source_y * y_pitch;
376       u_ptr = u_buf + (source_y >> y_shift) * uv_pitch;
377       v_ptr = v_buf + (source_y >> y_shift) * uv_pitch;
378     }
379     if (source_dx == kFractionMax) {  // Not scaled
380       g_convert_yuv_to_rgb32_row_proc_(
381           y_ptr, u_ptr, v_ptr, dest_pixel, width, kCoefficientsRgbY);
382     } else {
383       if (filter & FILTER_BILINEAR_H) {
384         g_linear_scale_yuv_to_rgb32_row_proc_(y_ptr,
385                                               u_ptr,
386                                               v_ptr,
387                                               dest_pixel,
388                                               width,
389                                               source_dx,
390                                               kCoefficientsRgbY);
391       } else {
392         g_scale_yuv_to_rgb32_row_proc_(y_ptr,
393                                        u_ptr,
394                                        v_ptr,
395                                        dest_pixel,
396                                        width,
397                                        source_dx,
398                                        kCoefficientsRgbY);
399       }
400     }
401   }
402
403   g_empty_register_state_proc_();
404 }
405
406 // Scale a frame of YV12 to 32 bit ARGB for a specific rectangle.
407 void ScaleYUVToRGB32WithRect(const uint8* y_buf,
408                              const uint8* u_buf,
409                              const uint8* v_buf,
410                              uint8* rgb_buf,
411                              int source_width,
412                              int source_height,
413                              int dest_width,
414                              int dest_height,
415                              int dest_rect_left,
416                              int dest_rect_top,
417                              int dest_rect_right,
418                              int dest_rect_bottom,
419                              int y_pitch,
420                              int uv_pitch,
421                              int rgb_pitch) {
422   // This routine doesn't currently support up-scaling.
423   CHECK_LE(dest_width, source_width);
424   CHECK_LE(dest_height, source_height);
425
426   // Sanity-check the destination rectangle.
427   DCHECK(dest_rect_left >= 0 && dest_rect_right <= dest_width);
428   DCHECK(dest_rect_top >= 0 && dest_rect_bottom <= dest_height);
429   DCHECK(dest_rect_right > dest_rect_left);
430   DCHECK(dest_rect_bottom > dest_rect_top);
431
432   // Fixed-point value of vertical and horizontal scale down factor.
433   // Values are in the format 16.16.
434   int y_step = kFractionMax * source_height / dest_height;
435   int x_step = kFractionMax * source_width / dest_width;
436
437   // Determine the coordinates of the rectangle in 16.16 coords.
438   // NB: Our origin is the *center* of the top/left pixel, NOT its top/left.
439   // If we're down-scaling by more than a factor of two, we start with a 50%
440   // fraction to avoid degenerating to point-sampling - we should really just
441   // fix the fraction at 50% for all pixels in that case.
442   int source_left = dest_rect_left * x_step;
443   int source_right = (dest_rect_right - 1) * x_step;
444   if (x_step < kFractionMax * 2) {
445     source_left += ((x_step - kFractionMax) / 2);
446     source_right += ((x_step - kFractionMax) / 2);
447   } else {
448     source_left += kFractionMax / 2;
449     source_right += kFractionMax / 2;
450   }
451   int source_top = dest_rect_top * y_step;
452   if (y_step < kFractionMax * 2) {
453     source_top += ((y_step - kFractionMax) / 2);
454   } else {
455     source_top += kFractionMax / 2;
456   }
457
458   // Determine the parts of the Y, U and V buffers to interpolate.
459   int source_y_left = source_left >> kFractionBits;
460   int source_y_right =
461       std::min((source_right >> kFractionBits) + 2, source_width + 1);
462
463   int source_uv_left = source_y_left / 2;
464   int source_uv_right = std::min((source_right >> (kFractionBits + 1)) + 2,
465                                  (source_width + 1) / 2);
466
467   int source_y_width = source_y_right - source_y_left;
468   int source_uv_width = source_uv_right - source_uv_left;
469
470   // Determine number of pixels in each output row.
471   int dest_rect_width = dest_rect_right - dest_rect_left;
472
473   // Intermediate buffer for vertical interpolation.
474   // 4096 bytes allows 3 buffers to fit in 12k, which fits in a 16K L1 cache,
475   // and is bigger than most users will generally need.
476   // The buffer is 16-byte aligned and padded with 16 extra bytes; some of the
477   // FilterYUVRowsProcs have alignment requirements, and the SSE version can
478   // write up to 16 bytes past the end of the buffer.
479   const int kFilterBufferSize = 4096;
480   const bool kAvoidUsingOptimizedFilter = source_width > kFilterBufferSize;
481   uint8 yuv_temp[16 + kFilterBufferSize * 3 + 16];
482   // memset() yuv_temp to 0 to avoid bogus warnings when running on Valgrind.
483   if (RunningOnValgrind())
484     memset(yuv_temp, 0, sizeof(yuv_temp));
485   uint8* y_temp = reinterpret_cast<uint8*>(
486       reinterpret_cast<uintptr_t>(yuv_temp + 15) & ~15);
487   uint8* u_temp = y_temp + kFilterBufferSize;
488   uint8* v_temp = u_temp + kFilterBufferSize;
489
490   // Move to the top-left pixel of output.
491   rgb_buf += dest_rect_top * rgb_pitch;
492   rgb_buf += dest_rect_left * 4;
493
494   // For each destination row perform interpolation and color space
495   // conversion to produce the output.
496   for (int row = dest_rect_top; row < dest_rect_bottom; ++row) {
497     // Round the fixed-point y position to get the current row.
498     int source_row = source_top >> kFractionBits;
499     int source_uv_row = source_row / 2;
500     DCHECK(source_row < source_height);
501
502     // Locate the first row for each plane for interpolation.
503     const uint8* y0_ptr = y_buf + y_pitch * source_row + source_y_left;
504     const uint8* u0_ptr = u_buf + uv_pitch * source_uv_row + source_uv_left;
505     const uint8* v0_ptr = v_buf + uv_pitch * source_uv_row + source_uv_left;
506     const uint8* y1_ptr = NULL;
507     const uint8* u1_ptr = NULL;
508     const uint8* v1_ptr = NULL;
509
510     // Locate the second row for interpolation, being careful not to overrun.
511     if (source_row + 1 >= source_height) {
512       y1_ptr = y0_ptr;
513     } else {
514       y1_ptr = y0_ptr + y_pitch;
515     }
516     if (source_uv_row + 1 >= (source_height + 1) / 2) {
517       u1_ptr = u0_ptr;
518       v1_ptr = v0_ptr;
519     } else {
520       u1_ptr = u0_ptr + uv_pitch;
521       v1_ptr = v0_ptr + uv_pitch;
522     }
523
524     if (!kAvoidUsingOptimizedFilter) {
525       // Vertical scaler uses 16.8 fixed point.
526       uint8 fraction = (source_top & kFractionMask) >> 8;
527       g_filter_yuv_rows_proc_(
528           y_temp + source_y_left, y0_ptr, y1_ptr, source_y_width, fraction);
529       g_filter_yuv_rows_proc_(
530           u_temp + source_uv_left, u0_ptr, u1_ptr, source_uv_width, fraction);
531       g_filter_yuv_rows_proc_(
532           v_temp + source_uv_left, v0_ptr, v1_ptr, source_uv_width, fraction);
533
534       // Perform horizontal interpolation and color space conversion.
535       // TODO(hclam): Use the MMX version after more testing.
536       LinearScaleYUVToRGB32RowWithRange_C(y_temp,
537                                           u_temp,
538                                           v_temp,
539                                           rgb_buf,
540                                           dest_rect_width,
541                                           source_left,
542                                           x_step,
543                                           kCoefficientsRgbY);
544     } else {
545       // If the frame is too large then we linear scale a single row.
546       LinearScaleYUVToRGB32RowWithRange_C(y0_ptr,
547                                           u0_ptr,
548                                           v0_ptr,
549                                           rgb_buf,
550                                           dest_rect_width,
551                                           source_left,
552                                           x_step,
553                                           kCoefficientsRgbY);
554     }
555
556     // Advance vertically in the source and destination image.
557     source_top += y_step;
558     rgb_buf += rgb_pitch;
559   }
560
561   g_empty_register_state_proc_();
562 }
563
564 void ConvertRGB32ToYUV(const uint8* rgbframe,
565                        uint8* yplane,
566                        uint8* uplane,
567                        uint8* vplane,
568                        int width,
569                        int height,
570                        int rgbstride,
571                        int ystride,
572                        int uvstride) {
573   g_convert_rgb32_to_yuv_proc_(rgbframe,
574                                yplane,
575                                uplane,
576                                vplane,
577                                width,
578                                height,
579                                rgbstride,
580                                ystride,
581                                uvstride);
582 }
583
584 void ConvertRGB24ToYUV(const uint8* rgbframe,
585                        uint8* yplane,
586                        uint8* uplane,
587                        uint8* vplane,
588                        int width,
589                        int height,
590                        int rgbstride,
591                        int ystride,
592                        int uvstride) {
593   g_convert_rgb24_to_yuv_proc_(rgbframe,
594                                yplane,
595                                uplane,
596                                vplane,
597                                width,
598                                height,
599                                rgbstride,
600                                ystride,
601                                uvstride);
602 }
603
604 void ConvertYUY2ToYUV(const uint8* src,
605                       uint8* yplane,
606                       uint8* uplane,
607                       uint8* vplane,
608                       int width,
609                       int height) {
610   for (int i = 0; i < height / 2; ++i) {
611     for (int j = 0; j < (width / 2); ++j) {
612       yplane[0] = src[0];
613       *uplane = src[1];
614       yplane[1] = src[2];
615       *vplane = src[3];
616       src += 4;
617       yplane += 2;
618       uplane++;
619       vplane++;
620     }
621     for (int j = 0; j < (width / 2); ++j) {
622       yplane[0] = src[0];
623       yplane[1] = src[2];
624       src += 4;
625       yplane += 2;
626     }
627   }
628 }
629
630 void ConvertNV21ToYUV(const uint8* src,
631                       uint8* yplane,
632                       uint8* uplane,
633                       uint8* vplane,
634                       int width,
635                       int height) {
636   int y_plane_size = width * height;
637   memcpy(yplane, src, y_plane_size);
638
639   src += y_plane_size;
640   int u_plane_size = y_plane_size >> 2;
641   for (int i = 0; i < u_plane_size; ++i) {
642     *vplane++ = *src++;
643     *uplane++ = *src++;
644   }
645 }
646
647 void ConvertYUVToRGB32(const uint8* yplane,
648                        const uint8* uplane,
649                        const uint8* vplane,
650                        uint8* rgbframe,
651                        int width,
652                        int height,
653                        int ystride,
654                        int uvstride,
655                        int rgbstride,
656                        YUVType yuv_type) {
657   g_convert_yuv_to_rgb32_proc_(yplane,
658                                uplane,
659                                vplane,
660                                rgbframe,
661                                width,
662                                height,
663                                ystride,
664                                uvstride,
665                                rgbstride,
666                                yuv_type);
667 }
668
669 void ConvertYUVAToARGB(const uint8* yplane,
670                        const uint8* uplane,
671                        const uint8* vplane,
672                        const uint8* aplane,
673                        uint8* rgbframe,
674                        int width,
675                        int height,
676                        int ystride,
677                        int uvstride,
678                        int astride,
679                        int rgbstride,
680                        YUVType yuv_type) {
681   g_convert_yuva_to_argb_proc_(yplane,
682                                uplane,
683                                vplane,
684                                aplane,
685                                rgbframe,
686                                width,
687                                height,
688                                ystride,
689                                uvstride,
690                                astride,
691                                rgbstride,
692                                yuv_type);
693 }
694
695 }  // namespace media