OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This webpage shows layout of YV12 and other YUV formats | 5 // This webpage shows layout of YV12 and other YUV formats |
6 // http://www.fourcc.org/yuv.php | 6 // http://www.fourcc.org/yuv.php |
7 // The actual conversion is best described here | 7 // The actual conversion is best described here |
8 // http://en.wikipedia.org/wiki/YUV | 8 // http://en.wikipedia.org/wiki/YUV |
9 // An article on optimizing YUV conversion using tables instead of multiplies | 9 // An article on optimizing YUV conversion using tables instead of multiplies |
10 // http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf | 10 // http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf |
(...skipping 10 matching lines...) Expand all Loading... |
21 #include "media/base/yuv_row.h" | 21 #include "media/base/yuv_row.h" |
22 | 22 |
23 #if USE_MMX | 23 #if USE_MMX |
24 #if defined(_MSC_VER) | 24 #if defined(_MSC_VER) |
25 #include <intrin.h> | 25 #include <intrin.h> |
26 #else | 26 #else |
27 #include <mmintrin.h> | 27 #include <mmintrin.h> |
28 #endif | 28 #endif |
29 #endif | 29 #endif |
30 | 30 |
31 #if USE_SSE | 31 #if USE_SSE2 |
32 #include <emmintrin.h> | 32 #include <emmintrin.h> |
33 #endif | 33 #endif |
34 | 34 |
35 namespace media { | 35 namespace media { |
36 | 36 |
37 // 16.16 fixed point arithmetic. | 37 // 16.16 fixed point arithmetic |
38 const int kFractionBits = 16; | 38 const int kFractionBits = 16; |
39 const int kFractionMax = 1 << kFractionBits; | 39 const int kFractionMax = 1 << kFractionBits; |
| 40 const int kFractionMask = ((1 << kFractionBits) - 1); |
40 | 41 |
41 // Convert a frame of YUV to 32 bit ARGB. | 42 // Convert a frame of YUV to 32 bit ARGB. |
42 void ConvertYUVToRGB32(const uint8* y_buf, | 43 void ConvertYUVToRGB32(const uint8* y_buf, |
43 const uint8* u_buf, | 44 const uint8* u_buf, |
44 const uint8* v_buf, | 45 const uint8* v_buf, |
45 uint8* rgb_buf, | 46 uint8* rgb_buf, |
46 int width, | 47 int source_width, |
47 int height, | 48 int source_height, |
48 int y_pitch, | 49 int y_pitch, |
49 int uv_pitch, | 50 int uv_pitch, |
50 int rgb_pitch, | 51 int rgb_pitch, |
51 YUVType yuv_type) { | 52 YUVType yuv_type) { |
52 unsigned int y_shift = yuv_type; | 53 unsigned int y_shift = yuv_type; |
53 for (int y = 0; y < height; ++y) { | 54 for (int y = 0; y < source_height; ++y) { |
54 uint8* rgb_row = rgb_buf + y * rgb_pitch; | 55 uint8* rgb_row = rgb_buf + y * rgb_pitch; |
55 const uint8* y_ptr = y_buf + y * y_pitch; | 56 const uint8* y_ptr = y_buf + y * y_pitch; |
56 const uint8* u_ptr = u_buf + (y >> y_shift) * uv_pitch; | 57 const uint8* u_ptr = u_buf + (y >> y_shift) * uv_pitch; |
57 const uint8* v_ptr = v_buf + (y >> y_shift) * uv_pitch; | 58 const uint8* v_ptr = v_buf + (y >> y_shift) * uv_pitch; |
58 | 59 |
59 FastConvertYUVToRGB32Row(y_ptr, | 60 FastConvertYUVToRGB32Row(y_ptr, |
60 u_ptr, | 61 u_ptr, |
61 v_ptr, | 62 v_ptr, |
62 rgb_row, | 63 rgb_row, |
63 width); | 64 source_width); |
64 } | 65 } |
65 | 66 |
66 // MMX used for FastConvertYUVToRGB32Row requires emms instruction. | 67 // MMX used for FastConvertYUVToRGB32Row requires emms instruction. |
67 EMMS(); | 68 EMMS(); |
68 } | 69 } |
69 | 70 |
70 #if USE_MMX | 71 #if USE_SSE2 |
71 #if USE_SSE | |
72 // FilterRows combines two rows of the image using linear interpolation. | 72 // FilterRows combines two rows of the image using linear interpolation. |
73 // SSE2 version blends 8 pixels at a time. | 73 // SSE2 version blends 8 pixels at a time. |
74 static void FilterRows(uint8* ybuf, const uint8* y0_ptr, const uint8* y1_ptr, | 74 static void FilterRows(uint8* ybuf, const uint8* y0_ptr, const uint8* y1_ptr, |
75 int width, int scaled_y_fraction) { | 75 int source_width, int source_y_fraction) { |
76 __m128i zero = _mm_setzero_si128(); | 76 __m128i zero = _mm_setzero_si128(); |
77 __m128i y1_fraction = _mm_set1_epi16( | 77 __m128i y1_fraction = _mm_set1_epi16( |
78 static_cast<uint16>(scaled_y_fraction >> 8)); | 78 static_cast<uint16>(source_y_fraction >> 8)); |
79 __m128i y0_fraction = _mm_set1_epi16( | 79 __m128i y0_fraction = _mm_set1_epi16( |
80 static_cast<uint16>((scaled_y_fraction >> 8) ^ 255)); | 80 static_cast<uint16>(256 - (source_y_fraction >> 8))); |
81 | 81 |
82 uint8* end = ybuf + width; | 82 uint8* end = ybuf + source_width; |
83 if (ybuf < end) { | 83 if (ybuf < end) { |
84 do { | 84 do { |
85 __m128i y0 = _mm_loadl_epi64(reinterpret_cast<__m128i const*>(y0_ptr)); | 85 __m128i y0 = _mm_loadl_epi64(reinterpret_cast<__m128i const*>(y0_ptr)); |
86 __m128i y1 = _mm_loadl_epi64(reinterpret_cast<__m128i const*>(y1_ptr)); | 86 __m128i y1 = _mm_loadl_epi64(reinterpret_cast<__m128i const*>(y1_ptr)); |
87 y0 = _mm_unpacklo_epi8(y0, zero); | 87 y0 = _mm_unpacklo_epi8(y0, zero); |
88 y1 = _mm_unpacklo_epi8(y1, zero); | 88 y1 = _mm_unpacklo_epi8(y1, zero); |
89 y0 = _mm_mullo_epi16(y0, y0_fraction); | 89 y0 = _mm_mullo_epi16(y0, y0_fraction); |
90 y1 = _mm_mullo_epi16(y1, y1_fraction); | 90 y1 = _mm_mullo_epi16(y1, y1_fraction); |
91 y0 = _mm_add_epi16(y0, y1); // 8.8 fixed point result | 91 y0 = _mm_add_epi16(y0, y1); // 8.8 fixed point result |
92 y0 = _mm_srli_epi16(y0, 8); | 92 y0 = _mm_srli_epi16(y0, 8); |
93 y0 = _mm_packus_epi16(y0, y0); | 93 y0 = _mm_packus_epi16(y0, y0); |
94 _mm_storel_epi64(reinterpret_cast<__m128i *>(ybuf), y0); | 94 _mm_storel_epi64(reinterpret_cast<__m128i *>(ybuf), y0); |
95 y0_ptr += 8; | 95 y0_ptr += 8; |
96 y1_ptr += 8; | 96 y1_ptr += 8; |
97 ybuf += 8; | 97 ybuf += 8; |
98 } while (ybuf < end); | 98 } while (ybuf < end); |
99 } | 99 } |
100 } | 100 } |
101 | 101 |
102 #else | 102 #elif USE_MMX |
103 // MMX version blends 4 pixels at a time. | 103 // MMX version blends 4 pixels at a time. |
104 static void FilterRows(uint8* ybuf, const uint8* y0_ptr, const uint8* y1_ptr, | 104 static void FilterRows(uint8* ybuf, const uint8* y0_ptr, const uint8* y1_ptr, |
105 int width, int scaled_y_fraction) { | 105 int source_width, int source_y_fraction) { |
106 __m64 zero = _mm_setzero_si64(); | 106 __m64 zero = _mm_setzero_si64(); |
107 __m64 y1_fraction = _mm_set1_pi16( | 107 __m64 y1_fraction = _mm_set1_pi16( |
108 static_cast<int16>(scaled_y_fraction >> 8)); | 108 static_cast<int16>(source_y_fraction >> 8)); |
109 __m64 y0_fraction = _mm_set1_pi16( | 109 __m64 y0_fraction = _mm_set1_pi16( |
110 static_cast<int16>((scaled_y_fraction >> 8) ^ 255)); | 110 static_cast<int16>(256 - (source_y_fraction >> 8))); |
111 | 111 |
112 uint8* end = ybuf + width; | 112 uint8* end = ybuf + source_width; |
113 if (ybuf < end) { | 113 if (ybuf < end) { |
114 do { | 114 do { |
115 __m64 y0 = _mm_cvtsi32_si64(*reinterpret_cast<const int *>(y0_ptr)); | 115 __m64 y0 = _mm_cvtsi32_si64(*reinterpret_cast<const int *>(y0_ptr)); |
116 __m64 y1 = _mm_cvtsi32_si64(*reinterpret_cast<const int *>(y1_ptr)); | 116 __m64 y1 = _mm_cvtsi32_si64(*reinterpret_cast<const int *>(y1_ptr)); |
117 y0 = _mm_unpacklo_pi8(y0, zero); | 117 y0 = _mm_unpacklo_pi8(y0, zero); |
118 y1 = _mm_unpacklo_pi8(y1, zero); | 118 y1 = _mm_unpacklo_pi8(y1, zero); |
119 y0 = _mm_mullo_pi16(y0, y0_fraction); | 119 y0 = _mm_mullo_pi16(y0, y0_fraction); |
120 y1 = _mm_mullo_pi16(y1, y1_fraction); | 120 y1 = _mm_mullo_pi16(y1, y1_fraction); |
121 y0 = _mm_add_pi16(y0, y1); // 8.8 fixed point result | 121 y0 = _mm_add_pi16(y0, y1); // 8.8 fixed point result |
122 y0 = _mm_srli_pi16(y0, 8); | 122 y0 = _mm_srli_pi16(y0, 8); |
123 y0 = _mm_packs_pu16(y0, y0); | 123 y0 = _mm_packs_pu16(y0, y0); |
124 *reinterpret_cast<int *>(ybuf) = _mm_cvtsi64_si32(y0); | 124 *reinterpret_cast<int *>(ybuf) = _mm_cvtsi64_si32(y0); |
125 y0_ptr += 4; | 125 y0_ptr += 4; |
126 y1_ptr += 4; | 126 y1_ptr += 4; |
127 ybuf += 4; | 127 ybuf += 4; |
128 } while (ybuf < end); | 128 } while (ybuf < end); |
129 } | 129 } |
130 } | 130 } |
131 | 131 #else // no MMX or SSE2 |
132 #endif // USE_SSE | |
133 #else // no MMX or SSE | |
134 // C version blends 4 pixels at a time. | 132 // C version blends 4 pixels at a time. |
135 static void FilterRows(uint8* ybuf, const uint8* y0_ptr, const uint8* y1_ptr, | 133 static void FilterRows(uint8* ybuf, const uint8* y0_ptr, const uint8* y1_ptr, |
136 int width, int scaled_y_fraction) { | 134 int source_width, int source_y_fraction) { |
137 int y0_fraction = kFractionMax - scaled_y_fraction; | 135 int y1_fraction = source_y_fraction >> 8; |
138 int y1_fraction = scaled_y_fraction; | 136 int y0_fraction = 256 - (source_y_fraction >> 8); |
139 uint8* end = ybuf + width; | 137 |
| 138 int y0_fraction = kFractionMax - source_y_fraction; |
| 139 int y1_fraction = source_y_fraction; |
| 140 uint8* end = ybuf + source_width; |
140 if (ybuf < end) { | 141 if (ybuf < end) { |
141 do { | 142 do { |
142 ybuf[0] = (y0_ptr[0] * (y0_fraction) + y1_ptr[0] * (y1_fraction)) >> 16; | 143 ybuf[0] = (y0_ptr[0] * (y0_fraction) + y1_ptr[0] * (y1_fraction)) >> 8; |
143 ybuf[1] = (y0_ptr[1] * (y0_fraction) + y1_ptr[1] * (y1_fraction)) >> 16; | 144 ybuf[1] = (y0_ptr[1] * (y0_fraction) + y1_ptr[1] * (y1_fraction)) >> 8; |
144 ybuf[2] = (y0_ptr[2] * (y0_fraction) + y1_ptr[2] * (y1_fraction)) >> 16; | 145 ybuf[2] = (y0_ptr[2] * (y0_fraction) + y1_ptr[2] * (y1_fraction)) >> 8; |
145 ybuf[3] = (y0_ptr[3] * (y0_fraction) + y1_ptr[3] * (y1_fraction)) >> 16; | 146 ybuf[3] = (y0_ptr[3] * (y0_fraction) + y1_ptr[3] * (y1_fraction)) >> 8; |
146 y0_ptr += 4; | 147 y0_ptr += 4; |
147 y1_ptr += 4; | 148 y1_ptr += 4; |
148 ybuf += 4; | 149 ybuf += 4; |
149 } while (ybuf < end); | 150 } while (ybuf < end); |
150 } | 151 } |
151 } | 152 } |
152 #endif // USE_MMX | 153 #endif |
153 | 154 |
154 // Scale a frame of YUV to 32 bit ARGB. | 155 // Scale a frame of YUV to 32 bit ARGB. |
155 void ScaleYUVToRGB32(const uint8* y_buf, | 156 void ScaleYUVToRGB32(const uint8* y_buf, |
156 const uint8* u_buf, | 157 const uint8* u_buf, |
157 const uint8* v_buf, | 158 const uint8* v_buf, |
158 uint8* rgb_buf, | 159 uint8* rgb_buf, |
| 160 int source_width, |
| 161 int source_height, |
159 int width, | 162 int width, |
160 int height, | 163 int height, |
161 int scaled_width, | |
162 int scaled_height, | |
163 int y_pitch, | 164 int y_pitch, |
164 int uv_pitch, | 165 int uv_pitch, |
165 int rgb_pitch, | 166 int rgb_pitch, |
166 YUVType yuv_type, | 167 YUVType yuv_type, |
167 Rotate view_rotate, | 168 Rotate view_rotate, |
168 ScaleFilter filter) { | 169 ScaleFilter filter) { |
169 const int kFilterBufferSize = 8192; | 170 const int kFilterBufferSize = 8192; |
170 // Disable filtering if the screen is too big (to avoid buffer overflows). | 171 // Disable filtering if the screen is too big (to avoid buffer overflows). |
171 // This should never happen to regular users: they don't have monitors | 172 // This should never happen to regular users: they don't have monitors |
172 // wider than 8192 pixels. | 173 // wider than 8192 pixels. |
173 if (width > kFilterBufferSize) | 174 // TODO(fbarchard): Allow rotated videos to filter. |
| 175 if (source_width > kFilterBufferSize || view_rotate) |
174 filter = FILTER_NONE; | 176 filter = FILTER_NONE; |
175 | 177 |
176 unsigned int y_shift = yuv_type; | 178 unsigned int y_shift = yuv_type; |
177 // Diagram showing origin and direction of source sampling. | 179 // Diagram showing origin and direction of source sampling. |
178 // ->0 4<- | 180 // ->0 4<- |
179 // 7 3 | 181 // 7 3 |
180 // | 182 // |
181 // 6 5 | 183 // 6 5 |
182 // ->1 2<- | 184 // ->1 2<- |
183 // Rotations that start at right side of image. | 185 // Rotations that start at right side of image. |
184 if ((view_rotate == ROTATE_180) || | 186 if ((view_rotate == ROTATE_180) || |
185 (view_rotate == ROTATE_270) || | 187 (view_rotate == ROTATE_270) || |
186 (view_rotate == MIRROR_ROTATE_0) || | 188 (view_rotate == MIRROR_ROTATE_0) || |
187 (view_rotate == MIRROR_ROTATE_90)) { | 189 (view_rotate == MIRROR_ROTATE_90)) { |
188 y_buf += width - 1; | 190 y_buf += source_width - 1; |
189 u_buf += width / 2 - 1; | 191 u_buf += source_width / 2 - 1; |
190 v_buf += width / 2 - 1; | 192 v_buf += source_width / 2 - 1; |
191 width = -width; | 193 source_width = -source_width; |
192 } | 194 } |
193 // Rotations that start at bottom of image. | 195 // Rotations that start at bottom of image. |
194 if ((view_rotate == ROTATE_90) || | 196 if ((view_rotate == ROTATE_90) || |
195 (view_rotate == ROTATE_180) || | 197 (view_rotate == ROTATE_180) || |
196 (view_rotate == MIRROR_ROTATE_90) || | 198 (view_rotate == MIRROR_ROTATE_90) || |
197 (view_rotate == MIRROR_ROTATE_180)) { | 199 (view_rotate == MIRROR_ROTATE_180)) { |
198 y_buf += (height - 1) * y_pitch; | 200 y_buf += (source_height - 1) * y_pitch; |
199 u_buf += ((height >> y_shift) - 1) * uv_pitch; | 201 u_buf += ((source_height >> y_shift) - 1) * uv_pitch; |
200 v_buf += ((height >> y_shift) - 1) * uv_pitch; | 202 v_buf += ((source_height >> y_shift) - 1) * uv_pitch; |
201 height = -height; | 203 source_height = -source_height; |
202 } | 204 } |
203 | 205 |
204 // Handle zero sized destination. | 206 // Handle zero sized destination. |
205 if (scaled_width == 0 || scaled_height == 0) | 207 if (width == 0 || height == 0) |
206 return; | 208 return; |
207 int scaled_dx = width * kFractionMax / scaled_width; | 209 int source_dx = source_width * kFractionMax / width; |
208 int scaled_dy = height * kFractionMax / scaled_height; | 210 int source_dy = source_height * kFractionMax / height; |
209 int scaled_dx_uv = scaled_dx; | 211 int source_dx_uv = source_dx; |
210 | 212 |
211 if ((view_rotate == ROTATE_90) || | 213 if ((view_rotate == ROTATE_90) || |
212 (view_rotate == ROTATE_270)) { | 214 (view_rotate == ROTATE_270)) { |
213 int tmp = scaled_height; | 215 int tmp = height; |
214 scaled_height = scaled_width; | |
215 scaled_width = tmp; | |
216 tmp = height; | |
217 height = width; | 216 height = width; |
218 width = tmp; | 217 width = tmp; |
219 int original_dx = scaled_dx; | 218 tmp = source_height; |
220 int original_dy = scaled_dy; | 219 source_height = source_width; |
221 scaled_dx = ((original_dy >> kFractionBits) * y_pitch) << kFractionBits; | 220 source_width = tmp; |
222 scaled_dx_uv = ((original_dy >> kFractionBits) * uv_pitch) << kFractionBits; | 221 int original_dx = source_dx; |
223 scaled_dy = original_dx; | 222 int original_dy = source_dy; |
| 223 source_dx = ((original_dy >> kFractionBits) * y_pitch) << kFractionBits; |
| 224 source_dx_uv = ((original_dy >> kFractionBits) * uv_pitch) << kFractionBits; |
| 225 source_dy = original_dx; |
224 if (view_rotate == ROTATE_90) { | 226 if (view_rotate == ROTATE_90) { |
225 y_pitch = -1; | 227 y_pitch = -1; |
226 uv_pitch = -1; | 228 uv_pitch = -1; |
227 height = -height; | 229 source_height = -source_height; |
228 } else { | 230 } else { |
229 y_pitch = 1; | 231 y_pitch = 1; |
230 uv_pitch = 1; | 232 uv_pitch = 1; |
231 } | 233 } |
232 } | 234 } |
233 | 235 |
234 // Need padding because FilterRows() may write up to 15 extra pixels | 236 // Need padding because FilterRows() may write up to 15 extra pixels |
235 // after the end for SSE2 version. | 237 // after the end for SSE2 version. |
236 uint8 ybuf[kFilterBufferSize + 16]; | 238 uint8 ybuf[kFilterBufferSize + 16]; |
237 uint8 ubuf[kFilterBufferSize / 2 + 16]; | 239 uint8 ubuf[kFilterBufferSize / 2 + 16]; |
238 uint8 vbuf[kFilterBufferSize / 2 + 16]; | 240 uint8 vbuf[kFilterBufferSize / 2 + 16]; |
239 int yscale_fixed = (height << kFractionBits) / scaled_height; | 241 // TODO(fbarchard): Fixed point math is off by 1 on negatives. |
240 for (int y = 0; y < scaled_height; ++y) { | 242 int yscale_fixed = (source_height << kFractionBits) / height; |
| 243 for (int y = 0; y < height; ++y) { |
241 uint8* dest_pixel = rgb_buf + y * rgb_pitch; | 244 uint8* dest_pixel = rgb_buf + y * rgb_pitch; |
242 int source_y_subpixel = (y * yscale_fixed); | 245 int source_y_subpixel = (y * yscale_fixed); |
243 int source_y = source_y_subpixel >> kFractionBits; | 246 int source_y = source_y_subpixel >> kFractionBits; |
244 | 247 |
245 const uint8* y0_ptr = y_buf + source_y * y_pitch; | 248 const uint8* y0_ptr = y_buf + source_y * y_pitch; |
246 const uint8* y1_ptr = y0_ptr + y_pitch; | 249 const uint8* y1_ptr = y0_ptr + y_pitch; |
247 | 250 |
248 const uint8* u0_ptr = u_buf + (source_y >> y_shift) * uv_pitch; | 251 const uint8* u0_ptr = u_buf + (source_y >> y_shift) * uv_pitch; |
249 const uint8* u1_ptr = u0_ptr + uv_pitch; | 252 const uint8* u1_ptr = u0_ptr + uv_pitch; |
250 const uint8* v0_ptr = v_buf + (source_y >> y_shift) * uv_pitch; | 253 const uint8* v0_ptr = v_buf + (source_y >> y_shift) * uv_pitch; |
251 const uint8* v1_ptr = v0_ptr + uv_pitch; | 254 const uint8* v1_ptr = v0_ptr + uv_pitch; |
252 | 255 |
253 int scaled_y_fraction = source_y_subpixel & (kFractionMax - 1); | 256 int source_y_fraction = source_y_subpixel & kFractionMask; |
254 int scaled_uv_fraction = (source_y_subpixel >> y_shift) & (kFractionMax - 1)
; | 257 int source_uv_fraction = (source_y_subpixel >> y_shift) & kFractionMask; |
255 | 258 |
256 const uint8* y_ptr = y0_ptr; | 259 const uint8* y_ptr = y0_ptr; |
257 const uint8* u_ptr = u0_ptr; | 260 const uint8* u_ptr = u0_ptr; |
258 const uint8* v_ptr = v0_ptr; | 261 const uint8* v_ptr = v0_ptr; |
259 // Apply vertical filtering if necessary. | 262 // Apply vertical filtering if necessary. |
260 // TODO(fbarchard): Remove memcpy when not necessary. | 263 // TODO(fbarchard): Remove memcpy when not necessary. |
261 if (filter == media::FILTER_BILINEAR) { | 264 if (filter == media::FILTER_BILINEAR) { |
262 if (yscale_fixed != kFractionMax && | 265 if (yscale_fixed != kFractionMax && |
263 scaled_y_fraction && ((source_y + 1) < height)) { | 266 source_y_fraction && ((source_y + 1) < source_height)) { |
264 FilterRows(ybuf, y0_ptr, y1_ptr, width, scaled_y_fraction); | 267 FilterRows(ybuf, y0_ptr, y1_ptr, source_width, source_y_fraction); |
265 } else { | 268 } else { |
266 memcpy(ybuf, y0_ptr, width); | 269 memcpy(ybuf, y0_ptr, source_width); |
267 } | 270 } |
268 y_ptr = ybuf; | 271 y_ptr = ybuf; |
269 ybuf[width] = ybuf[width-1]; | 272 ybuf[source_width] = ybuf[source_width-1]; |
270 int uv_width = (width + 1) / 2; | 273 int uv_source_width = (source_width + 1) / 2; |
271 if (yscale_fixed != kFractionMax && | 274 if (yscale_fixed != kFractionMax && |
272 scaled_uv_fraction && | 275 source_uv_fraction && |
273 (((source_y >> y_shift) + 1) < (height >> y_shift))) { | 276 (((source_y >> y_shift) + 1) < (source_height >> y_shift))) { |
274 FilterRows(ubuf, u0_ptr, u1_ptr, uv_width, scaled_uv_fraction); | 277 FilterRows(ubuf, u0_ptr, u1_ptr, uv_source_width, source_uv_fraction); |
275 FilterRows(vbuf, v0_ptr, v1_ptr, uv_width, scaled_uv_fraction); | 278 FilterRows(vbuf, v0_ptr, v1_ptr, uv_source_width, source_uv_fraction); |
276 } else { | 279 } else { |
277 memcpy(ubuf, u0_ptr, uv_width); | 280 memcpy(ubuf, u0_ptr, uv_source_width); |
278 memcpy(vbuf, v0_ptr, uv_width); | 281 memcpy(vbuf, v0_ptr, uv_source_width); |
279 } | 282 } |
280 u_ptr = ubuf; | 283 u_ptr = ubuf; |
281 v_ptr = vbuf; | 284 v_ptr = vbuf; |
282 ubuf[uv_width] = ubuf[uv_width - 1]; | 285 ubuf[uv_source_width] = ubuf[uv_source_width - 1]; |
283 vbuf[uv_width] = vbuf[uv_width - 1]; | 286 vbuf[uv_source_width] = vbuf[uv_source_width - 1]; |
284 } | 287 } |
285 if (scaled_dx == kFractionMax) { // Not scaled | 288 if (source_dx == kFractionMax) { // Not scaled |
286 FastConvertYUVToRGB32Row(y_ptr, u_ptr, v_ptr, | 289 FastConvertYUVToRGB32Row(y_ptr, u_ptr, v_ptr, |
287 dest_pixel, scaled_width); | 290 dest_pixel, width); |
288 } else { | 291 } else { |
289 if (filter == FILTER_BILINEAR) | 292 if (filter == FILTER_BILINEAR) |
290 LinearScaleYUVToRGB32Row(y_ptr, u_ptr, v_ptr, | 293 LinearScaleYUVToRGB32Row(y_ptr, u_ptr, v_ptr, |
291 dest_pixel, scaled_width, scaled_dx); | 294 dest_pixel, width, source_dx); |
292 else | 295 else { |
| 296 // Specialized scalers and rotation. |
| 297 #if USE_MMX && defined(_MSC_VER) |
| 298 if (width == (source_width * 2)) { |
| 299 DoubleYUVToRGB32Row(y_ptr, u_ptr, v_ptr, |
| 300 dest_pixel, width); |
| 301 } else if ((source_dx & kFractionMask) == 0) { |
| 302 // Scaling by integer scale factor. ie half. |
| 303 ConvertYUVToRGB32Row(y_ptr, u_ptr, v_ptr, |
| 304 dest_pixel, width, |
| 305 source_dx >> kFractionBits); |
| 306 } else if (source_dx_uv == source_dx) { // Not rotated. |
| 307 ScaleYUVToRGB32Row(y_ptr, u_ptr, v_ptr, |
| 308 dest_pixel, width, source_dx); |
| 309 } else { |
| 310 RotateConvertYUVToRGB32Row(y_ptr, u_ptr, v_ptr, |
| 311 dest_pixel, width, |
| 312 source_dx >> kFractionBits, |
| 313 source_dx_uv >> kFractionBits); |
| 314 } |
| 315 #else |
293 ScaleYUVToRGB32Row(y_ptr, u_ptr, v_ptr, | 316 ScaleYUVToRGB32Row(y_ptr, u_ptr, v_ptr, |
294 dest_pixel, scaled_width, scaled_dx); | 317 dest_pixel, width, source_dx); |
| 318 #endif |
| 319 } |
295 } | 320 } |
296 } | 321 } |
297 | 322 // MMX used for FastConvertYUVToRGB32Row and FilterRows requires emms. |
298 // MMX used for FastConvertYUVToRGB32Row requires emms instruction. | |
299 EMMS(); | 323 EMMS(); |
300 } | 324 } |
301 | 325 |
302 } // namespace media | 326 } // namespace media |
OLD | NEW |