Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "ImageBitmapColorUtils.h"
8 : #include "libyuv.h"
9 :
10 : namespace mozilla {
11 : namespace dom {
12 :
13 : /*
14 : * Utility function form libyuv source files.
15 : */
16 0 : static __inline int32 clamp0(int32 v) {
17 0 : return ((-(v) >> 31) & (v));
18 : }
19 :
20 0 : static __inline int32 clamp255(int32 v) {
21 0 : return (((255 - (v)) >> 31) | (v)) & 255;
22 : }
23 :
24 0 : static __inline uint32 Clamp(int32 val) {
25 0 : int v = clamp0(val);
26 0 : return (uint32)(clamp255(v));
27 : }
28 :
29 : #define YG 74 /* (int8)(1.164 * 64 + 0.5) */
30 :
31 : #define UB 127 /* min(63,(int8)(2.018 * 64)) */
32 : #define UG -25 /* (int8)(-0.391 * 64 - 0.5) */
33 : #define UR 0
34 :
35 : #define VB 0
36 : #define VG -52 /* (int8)(-0.813 * 64 - 0.5) */
37 : #define VR 102 /* (int8)(1.596 * 64 + 0.5) */
38 :
39 : // Bias
40 : #define BB UB * 128 + VB * 128
41 : #define BG UG * 128 + VG * 128
42 : #define BR UR * 128 + VR * 128
43 :
44 : static __inline void
45 0 : YuvPixel(uint8 y, uint8 u, uint8 v, uint8* b, uint8* g, uint8* r)
46 : {
47 0 : int32 y1 = ((int32)(y) - 16) * YG;
48 0 : *b = Clamp((int32)((u * UB + v * VB) - (BB) + y1) >> 6);
49 0 : *g = Clamp((int32)((u * UG + v * VG) - (BG) + y1) >> 6);
50 0 : *r = Clamp((int32)((u * UR + v * VR) - (BR) + y1) >> 6);
51 0 : }
52 :
53 : static __inline int
54 0 : RGBToY(uint8 r, uint8 g, uint8 b)
55 : {
56 0 : return (66 * r + 129 * g + 25 * b + 0x1080) >> 8;
57 : }
58 :
59 : static __inline int
60 0 : RGBToU(uint8 r, uint8 g, uint8 b)
61 : {
62 0 : return (112 * b - 74 * g - 38 * r + 0x8080) >> 8;
63 : }
64 :
65 : static __inline int
66 0 : RGBToV(uint8 r, uint8 g, uint8 b)
67 : {
68 0 : return (112 * r - 94 * g - 18 * b + 0x8080) >> 8;
69 : }
70 :
71 : /*
72 : * Generic functions.
73 : */
74 : template<int aSrcRIndex, int aSrcGIndex, int aSrcBIndex,
75 : int aDstRIndex, int aDstGIndex, int aDstBIndex, int aDstAIndex>
76 : static int
77 0 : RGBFamilyToRGBAFamily(const uint8_t* aSrcBuffer, int aSrcStride,
78 : uint8_t* aDstBuffer, int aDstStride,
79 : int aWidth, int aHeight)
80 : {
81 : static_assert(aSrcRIndex == 0 || aSrcRIndex == 2, "Wrong SrcR index.");
82 : static_assert(aSrcGIndex == 1, "Wrong SrcG index.");
83 : static_assert(aSrcBIndex == 0 || aSrcBIndex == 2, "Wrong SrcB index.");
84 : static_assert(aDstRIndex == 0 || aDstRIndex == 2, "Wrong DstR index.");
85 : static_assert(aDstGIndex == 1, "Wrong DstG index.");
86 : static_assert(aDstBIndex == 0 || aDstBIndex == 2, "Wrong DstB index.");
87 : static_assert(aDstAIndex == 3, "Wrong DstA index.");
88 :
89 0 : for (int i = 0; i < aHeight; ++i) {
90 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
91 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
92 :
93 0 : for (int j = 0; j < aWidth; ++j) {
94 0 : uint8_t r = *(srcBuffer + aSrcRIndex);
95 0 : uint8_t g = *(srcBuffer + aSrcGIndex);
96 0 : uint8_t b = *(srcBuffer + aSrcBIndex);
97 0 : *(dstBuffer + aDstRIndex) = r;
98 0 : *(dstBuffer + aDstGIndex) = g;
99 0 : *(dstBuffer + aDstBIndex) = b;
100 0 : *(dstBuffer + aDstAIndex) = 255;
101 0 : srcBuffer += 3;
102 0 : dstBuffer += 4;
103 : }
104 : }
105 :
106 0 : return 0;
107 : }
108 :
109 : template<int aSrcRIndex, int aSrcGIndex, int aSrcBIndex,
110 : int aDstRIndex, int aDstGIndex, int aDstBIndex>
111 : static int
112 0 : RGBAFamilyToRGBFamily(const uint8_t* aSrcBuffer, int aSrcStride,
113 : uint8_t* aDstBuffer, int aDstStride,
114 : int aWidth, int aHeight)
115 : {
116 : static_assert(aSrcRIndex == 0 || aSrcRIndex == 2, "Wrong SrcR index.");
117 : static_assert(aSrcGIndex == 1, "Wrong SrcG index.");
118 : static_assert(aSrcBIndex == 0 || aSrcBIndex == 2, "Wrong SrcB index.");
119 : static_assert(aDstRIndex == 0 || aDstRIndex == 2, "Wrong DstR index.");
120 : static_assert(aDstGIndex == 1, "Wrong DstG index.");
121 : static_assert(aDstBIndex == 0 || aDstBIndex == 2, "Wrong DstB index.");
122 :
123 0 : for (int i = 0; i < aHeight; ++i) {
124 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
125 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
126 :
127 0 : for (int j = 0; j < aWidth; ++j) {
128 0 : uint8_t r = *(srcBuffer + aSrcRIndex);
129 0 : uint8_t g = *(srcBuffer + aSrcGIndex);
130 0 : uint8_t b = *(srcBuffer + aSrcBIndex);
131 0 : *(dstBuffer + aDstRIndex) = r;
132 0 : *(dstBuffer + aDstGIndex) = g;
133 0 : *(dstBuffer + aDstBIndex) = b;
134 0 : srcBuffer += 4;
135 0 : dstBuffer += 3;
136 : }
137 : }
138 :
139 0 : return 0;
140 : }
141 :
142 : template<int aPixel1YOffset, int aPixel1UOffset, int aPixel1VOffset,
143 : int aPixel2YOffset, int aPixel2UOffset, int aPixel2VOffset,
144 : int aYStep, int aUStep, int aVStep,
145 : int aRIndex, int aGIndex, int aBIndex>
146 : void
147 0 : YUVFamilyToRGBFamily_Row(const uint8_t* aYBuffer,
148 : const uint8_t* aUBuffer,
149 : const uint8_t* aVBuffer,
150 : uint8_t* aDstBuffer,
151 : int aWidth)
152 : {
153 : static_assert(aRIndex == 0 || aRIndex == 2, "Wrong R index.");
154 : static_assert(aGIndex == 1, "Wrong G index.");
155 : static_assert(aBIndex == 0 || aBIndex == 2, "Wrong B index.");
156 :
157 0 : for (int j = 0; j < aWidth - 1; j += 2) {
158 0 : YuvPixel(aYBuffer[aPixel1YOffset], aUBuffer[aPixel1UOffset], aVBuffer[aPixel1VOffset],
159 : aDstBuffer + aBIndex, aDstBuffer + aGIndex, aDstBuffer + aRIndex);
160 0 : YuvPixel(aYBuffer[aPixel2YOffset], aUBuffer[aPixel2UOffset], aVBuffer[aPixel2VOffset],
161 : aDstBuffer + aBIndex + 3, aDstBuffer + aGIndex + 3, aDstBuffer + aRIndex + 3);
162 0 : aYBuffer += aYStep;
163 0 : aUBuffer += aUStep;
164 0 : aVBuffer += aVStep;
165 0 : aDstBuffer += 6;
166 : }
167 :
168 0 : if (aWidth & 1) {
169 0 : YuvPixel(aYBuffer[aPixel1YOffset], aUBuffer[aPixel1UOffset], aVBuffer[aPixel1VOffset],
170 : aDstBuffer + aBIndex, aDstBuffer + aGIndex, aDstBuffer + aRIndex);
171 : }
172 0 : }
173 :
174 : template<int aPixel1YOffset, int aPixel1UOffset, int aPixel1VOffset,
175 : int aPixel2YOffset, int aPixel2UOffset, int aPixel2VOffset,
176 : int aYStep, int aUStep, int aVStep,
177 : int aRIndex, int aGIndex, int aBIndex, int aAIndex>
178 : void
179 0 : YUVFamilyToRGBAFamily_Row(const uint8_t* aYBuffer,
180 : const uint8_t* aUBuffer,
181 : const uint8_t* aVBuffer,
182 : uint8_t* aDstBuffer,
183 : int aWidth)
184 : {
185 : static_assert(aRIndex == 0 || aRIndex == 2, "Wrong R index.");
186 : static_assert(aGIndex == 1, "Wrong G index.");
187 : static_assert(aBIndex == 0 || aBIndex == 2, "Wrong B index.");
188 : static_assert(aAIndex == 3, "Wrong A index.");
189 :
190 0 : for (int j = 0; j < aWidth - 1; j += 2) {
191 0 : YuvPixel(aYBuffer[aPixel1YOffset], aUBuffer[aPixel1UOffset], aVBuffer[aPixel1VOffset],
192 : aDstBuffer + aBIndex, aDstBuffer + aGIndex, aDstBuffer + aRIndex);
193 0 : YuvPixel(aYBuffer[aPixel2YOffset], aUBuffer[aPixel2UOffset], aVBuffer[aPixel2VOffset],
194 : aDstBuffer + aBIndex + 4, aDstBuffer + aGIndex + 4, aDstBuffer + aRIndex + 4);
195 0 : aDstBuffer[aAIndex] = 255;
196 0 : aDstBuffer[aAIndex + 4] = 255;
197 :
198 0 : aYBuffer += aYStep;
199 0 : aUBuffer += aUStep;
200 0 : aVBuffer += aVStep;
201 0 : aDstBuffer += 8;
202 : }
203 :
204 0 : if (aWidth & 1) {
205 0 : YuvPixel(aYBuffer[aPixel1YOffset], aUBuffer[aPixel1UOffset], aVBuffer[aPixel1VOffset],
206 : aDstBuffer + aBIndex, aDstBuffer + aGIndex, aDstBuffer + aRIndex);
207 0 : aDstBuffer[aAIndex] = 255;
208 : }
209 0 : }
210 :
211 : template< int aRIndex, int aGIndex, int aBIndex>
212 : static void
213 0 : RGBFamilyToY_Row(const uint8_t* aSrcBuffer, uint8_t* aYBuffer, int aWidth)
214 : {
215 : static_assert(aRIndex == 0 || aRIndex == 2, "Wrong R index.");
216 : static_assert(aGIndex == 1, "Wrong G index.");
217 : static_assert(aBIndex == 0 || aBIndex == 2, "Wrong B index.");
218 :
219 0 : for (int j = 0; j < aWidth - 1; j += 2) {
220 0 : aYBuffer[0] = RGBToY(aSrcBuffer[aRIndex], aSrcBuffer[aGIndex], aSrcBuffer[aBIndex]);
221 0 : aYBuffer[1] = RGBToY(aSrcBuffer[aRIndex + 3], aSrcBuffer[aGIndex + 3], aSrcBuffer[aBIndex + 3]);
222 :
223 0 : aYBuffer += 2;
224 0 : aSrcBuffer += 3 * 2;
225 : }
226 :
227 0 : if (aWidth & 1) {
228 0 : aYBuffer[0] = RGBToY(aSrcBuffer[aRIndex], aSrcBuffer[aGIndex], aSrcBuffer[aBIndex]);
229 : }
230 0 : }
231 :
232 : template< int aRIndex, int aGIndex, int aBIndex, int aUStep, int aVStep>
233 : static void
234 0 : RGBFamilyToUV_Row(const uint8_t* aSrcBuffer, int aSrcStride,
235 : uint8_t* aUBuffer, uint8_t* aVBuffer, int aWidth)
236 : {
237 : static_assert(aRIndex == 0 || aRIndex == 2, "Wrong R index.");
238 : static_assert(aGIndex == 1, "Wrong G index.");
239 : static_assert(aBIndex == 0 || aBIndex == 2, "Wrong B index.");
240 :
241 0 : uint8_t averageR = 0;
242 0 : uint8_t averageG = 0;
243 0 : uint8_t averageB = 0;
244 :
245 0 : const uint8_t* aSrcBufferNextRow = aSrcBuffer + aSrcStride;
246 0 : for (int j = 0; j < aWidth - 1; j += 2) {
247 0 : averageR = (aSrcBuffer[aRIndex] + aSrcBuffer[aRIndex + 3] + aSrcBufferNextRow[aRIndex] + aSrcBufferNextRow[aRIndex + 3]) >> 2;
248 0 : averageG = (aSrcBuffer[aGIndex] + aSrcBuffer[aGIndex + 3] + aSrcBufferNextRow[aGIndex] + aSrcBufferNextRow[aGIndex + 3]) >> 2;
249 0 : averageB = (aSrcBuffer[aBIndex] + aSrcBuffer[aBIndex + 3] + aSrcBufferNextRow[aBIndex] + aSrcBufferNextRow[aBIndex + 3]) >> 2;
250 :
251 0 : aUBuffer[0] = RGBToU(averageR, averageG, averageB);
252 0 : aVBuffer[0] = RGBToV(averageR, averageG, averageB);
253 :
254 0 : aUBuffer += aUStep;
255 0 : aVBuffer += aVStep;
256 0 : aSrcBuffer += 3 * 2;
257 0 : aSrcBufferNextRow += 3 * 2;
258 : }
259 :
260 0 : if (aWidth & 1) {
261 0 : averageR = (aSrcBuffer[aRIndex] + aSrcBufferNextRow[aRIndex]) >> 1;
262 0 : averageG = (aSrcBuffer[aGIndex] + aSrcBufferNextRow[aGIndex]) >> 1;
263 0 : averageB = (aSrcBuffer[aBIndex] + aSrcBufferNextRow[aBIndex]) >> 1;
264 :
265 0 : aUBuffer[0] = RGBToU(averageR, averageG, averageB);
266 0 : aVBuffer[0] = RGBToV(averageR, averageG, averageB);
267 : }
268 0 : }
269 :
270 : template< int aRIndex, int aGIndex, int aBIndex>
271 : static void
272 0 : RGBAFamilyToY_Row(const uint8_t* aSrcBuffer, uint8_t* aYBuffer, int aWidth)
273 : {
274 : static_assert(aRIndex == 0 || aRIndex == 2, "Wrong R index.");
275 : static_assert(aGIndex == 1, "Wrong G index.");
276 : static_assert(aBIndex == 0 || aBIndex == 2, "Wrong B index.");
277 :
278 0 : for (int j = 0; j < aWidth - 1; j += 2) {
279 0 : aYBuffer[0] = RGBToY(aSrcBuffer[aRIndex], aSrcBuffer[aGIndex], aSrcBuffer[aBIndex]);
280 0 : aYBuffer[1] = RGBToY(aSrcBuffer[aRIndex + 4], aSrcBuffer[aGIndex + 4], aSrcBuffer[aBIndex + 4]);
281 :
282 0 : aYBuffer += 2;
283 0 : aSrcBuffer += 4 * 2;
284 : }
285 :
286 0 : if (aWidth & 1) {
287 0 : aYBuffer[0] = RGBToY(aSrcBuffer[aRIndex], aSrcBuffer[aGIndex], aSrcBuffer[aBIndex]);
288 : }
289 0 : }
290 :
291 : template< int aRIndex, int aGIndex, int aBIndex, int aUStep, int aVStep>
292 : static void
293 0 : RGBAFamilyToUV_Row(const uint8_t* aSrcBuffer, int aSrcStride,
294 : uint8_t* aUBuffer, uint8_t* aVBuffer, int aWidth)
295 : {
296 : static_assert(aRIndex == 0 || aRIndex == 2, "Wrong R index.");
297 : static_assert(aGIndex == 1, "Wrong G index.");
298 : static_assert(aBIndex == 0 || aBIndex == 2, "Wrong B index.");
299 :
300 0 : uint8_t averageR = 0;
301 0 : uint8_t averageG = 0;
302 0 : uint8_t averageB = 0;
303 :
304 0 : const uint8_t* aSrcBufferNextRow = aSrcBuffer + aSrcStride;
305 0 : for (int j = 0; j < aWidth - 1; j += 2) {
306 0 : averageR = (aSrcBuffer[aRIndex] + aSrcBuffer[aRIndex + 4] + aSrcBufferNextRow[aRIndex] + aSrcBufferNextRow[aRIndex + 4]) >> 2;
307 0 : averageG = (aSrcBuffer[aGIndex] + aSrcBuffer[aGIndex + 4] + aSrcBufferNextRow[aGIndex] + aSrcBufferNextRow[aGIndex + 4]) >> 2;
308 0 : averageB = (aSrcBuffer[aBIndex] + aSrcBuffer[aBIndex + 4] + aSrcBufferNextRow[aBIndex] + aSrcBufferNextRow[aBIndex + 4]) >> 2;
309 :
310 0 : aUBuffer[0] = RGBToU(averageR, averageG, averageB);
311 0 : aVBuffer[0] = RGBToV(averageR, averageG, averageB);
312 :
313 0 : aUBuffer += aUStep;
314 0 : aVBuffer += aVStep;
315 0 : aSrcBuffer += 4 * 2;
316 0 : aSrcBufferNextRow += 4 * 2;
317 : }
318 :
319 0 : if (aWidth & 1) {
320 0 : averageR = (aSrcBuffer[aRIndex] + aSrcBufferNextRow[aRIndex]) >> 1;
321 0 : averageG = (aSrcBuffer[aGIndex] + aSrcBufferNextRow[aGIndex]) >> 1;
322 0 : averageB = (aSrcBuffer[aBIndex] + aSrcBufferNextRow[aBIndex]) >> 1;
323 :
324 0 : aUBuffer[0] = RGBToU(averageR, averageG, averageB);
325 0 : aVBuffer[0] = RGBToV(averageR, averageG, averageB);
326 : }
327 0 : }
328 :
329 : /*
330 : * RGB family -> RGBA family.
331 : */
332 : int
333 0 : RGB24ToRGBA32(const uint8_t* aSrcBuffer, int aSrcStride,
334 : uint8_t* aDstBuffer, int aDstStride,
335 : int aWidth, int aHeight)
336 : {
337 : return RGBFamilyToRGBAFamily<0, 1, 2, 0, 1, 2, 3>(aSrcBuffer, aSrcStride,
338 : aDstBuffer, aDstStride,
339 0 : aWidth, aHeight);
340 : }
341 :
342 : int
343 0 : BGR24ToRGBA32(const uint8_t* aSrcBuffer, int aSrcStride,
344 : uint8_t* aDstBuffer, int aDstStride,
345 : int aWidth, int aHeight)
346 : {
347 : return RGBFamilyToRGBAFamily<2, 1, 0, 0, 1, 2, 3>(aSrcBuffer, aSrcStride,
348 : aDstBuffer, aDstStride,
349 0 : aWidth, aHeight);
350 : }
351 :
352 : int
353 0 : RGB24ToBGRA32(const uint8_t* aSrcBuffer, int aSrcStride,
354 : uint8_t* aDstBuffer, int aDstStride,
355 : int aWidth, int aHeight)
356 : {
357 : return RGBFamilyToRGBAFamily<0, 1, 2, 2, 1, 0, 3>(aSrcBuffer, aSrcStride,
358 : aDstBuffer, aDstStride,
359 0 : aWidth, aHeight);
360 : }
361 :
362 : int
363 0 : BGR24ToBGRA32(const uint8_t* aSrcBuffer, int aSrcStride,
364 : uint8_t* aDstBuffer, int aDstStride,
365 : int aWidth, int aHeight)
366 : {
367 : return RGBFamilyToRGBAFamily<2, 1, 0, 2, 1, 0, 3>(aSrcBuffer, aSrcStride,
368 : aDstBuffer, aDstStride,
369 0 : aWidth, aHeight);
370 : }
371 :
372 : /*
373 : * RGBA family -> RGB family.
374 : */
375 : int
376 0 : RGBA32ToRGB24(const uint8_t* aSrcBuffer, int aSrcStride,
377 : uint8_t* aDstBuffer, int aDstStride,
378 : int aWidth, int aHeight)
379 : {
380 : return RGBAFamilyToRGBFamily<0, 1, 2, 0, 1, 2>(aSrcBuffer, aSrcStride,
381 : aDstBuffer, aDstStride,
382 0 : aWidth, aHeight);
383 : }
384 :
385 : int
386 0 : BGRA32ToRGB24(const uint8_t* aSrcBuffer, int aSrcStride,
387 : uint8_t* aDstBuffer, int aDstStride,
388 : int aWidth, int aHeight)
389 : {
390 : return RGBAFamilyToRGBFamily<2, 1, 0, 0, 1, 2>(aSrcBuffer, aSrcStride,
391 : aDstBuffer, aDstStride,
392 0 : aWidth, aHeight);
393 : }
394 :
395 : int
396 0 : RGBA32ToBGR24(const uint8_t* aSrcBuffer, int aSrcStride,
397 : uint8_t* aDstBuffer, int aDstStride,
398 : int aWidth, int aHeight)
399 : {
400 : return RGBAFamilyToRGBFamily<0, 1, 2, 2, 1, 0>(aSrcBuffer, aSrcStride,
401 : aDstBuffer, aDstStride,
402 0 : aWidth, aHeight);
403 : }
404 :
405 : int
406 0 : BGRA32ToBGR24(const uint8_t* aSrcBuffer, int aSrcStride,
407 : uint8_t* aDstBuffer, int aDstStride,
408 : int aWidth, int aHeight)
409 : {
410 : return RGBAFamilyToRGBFamily<2, 1, 0, 2, 1, 0>(aSrcBuffer, aSrcStride,
411 : aDstBuffer, aDstStride,
412 0 : aWidth, aHeight);
413 : }
414 :
415 : /*
416 : * Among RGB family.
417 : */
418 : int
419 0 : RGB24Copy(const uint8_t* aSrcBuffer, int aSrcStride,
420 : uint8_t* aDstBuffer, int aDstStride,
421 : int aWidth, int aHeight)
422 : {
423 0 : MOZ_ASSERT(aSrcStride == aDstStride, "RGB24Copy: aSrcStride != aDstStride");
424 :
425 0 : const uint32_t length = aHeight * aDstStride;
426 0 : memcpy(aDstBuffer, aSrcBuffer, length);
427 0 : return 0;
428 : }
429 :
430 : int
431 0 : RGB24ToBGR24(const uint8_t* aSrcBuffer, int aSrcStride,
432 : uint8_t* aDstBuffer, int aDstStride,
433 : int aWidth, int aHeight)
434 : {
435 0 : for (int i = 0; i < aHeight; ++i) {
436 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
437 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
438 :
439 0 : for (int j = 0; j < aWidth; ++j) {
440 0 : *(dstBuffer + 0) = *(srcBuffer + 2);
441 0 : *(dstBuffer + 1) = *(srcBuffer + 1);
442 0 : *(dstBuffer + 2) = *(srcBuffer + 0);
443 0 : srcBuffer += 3;
444 0 : dstBuffer += 3;
445 : }
446 : }
447 :
448 0 : return 0;
449 : }
450 :
451 : /*
452 : * YUV family -> RGB family.
453 : */
454 : int
455 0 : YUV444PToRGB24(const uint8_t* aYBuffer, int aYStride,
456 : const uint8_t* aUBuffer, int aUStride,
457 : const uint8_t* aVBuffer, int aVStride,
458 : uint8_t* aDstBuffer, int aDstStride,
459 : int aWidth, int aHeight)
460 : {
461 0 : for (int i = 0; i < aHeight; ++i) {
462 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
463 0 : const uint8_t* uBuffer = aUBuffer + aUStride * i;
464 0 : const uint8_t* vBuffer = aVBuffer + aVStride * i;
465 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
466 :
467 : YUVFamilyToRGBFamily_Row<0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 1, 2>(yBuffer,
468 : uBuffer,
469 : vBuffer,
470 : dstBuffer,
471 0 : aWidth);
472 : }
473 :
474 0 : return 0;
475 : }
476 :
477 : int
478 0 : YUV422PToRGB24(const uint8_t* aYBuffer, int aYStride,
479 : const uint8_t* aUBuffer, int aUStride,
480 : const uint8_t* aVBuffer, int aVStride,
481 : uint8_t* aDstBuffer, int aDstStride,
482 : int aWidth, int aHeight)
483 : {
484 0 : for (int i = 0; i < aHeight; ++i) {
485 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
486 0 : const uint8_t* uBuffer = aUBuffer + aUStride * i;
487 0 : const uint8_t* vBuffer = aVBuffer + aVStride * i;
488 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
489 :
490 : YUVFamilyToRGBFamily_Row<0, 0, 0, 1, 0, 0, 2, 1, 1, 0, 1, 2>(yBuffer,
491 : uBuffer,
492 : vBuffer,
493 : dstBuffer,
494 0 : aWidth);
495 : }
496 :
497 0 : return 0;
498 : }
499 :
500 : int
501 0 : YUV420PToRGB24(const uint8_t* aYBuffer, int aYStride,
502 : const uint8_t* aUBuffer, int aUStride,
503 : const uint8_t* aVBuffer, int aVStride,
504 : uint8_t* aDstBuffer, int aDstStride,
505 : int aWidth, int aHeight)
506 : {
507 0 : for (int i = 0; i < aHeight; ++i) {
508 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
509 0 : const uint8_t* uBuffer = aUBuffer + aUStride * (i / 2);
510 0 : const uint8_t* vBuffer = aVBuffer + aVStride * (i / 2);
511 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
512 :
513 : YUVFamilyToRGBFamily_Row<0, 0, 0, 1, 0, 0, 2, 1, 1, 0, 1, 2>(yBuffer,
514 : uBuffer,
515 : vBuffer,
516 : dstBuffer,
517 0 : aWidth);
518 : }
519 :
520 0 : return 0;
521 : }
522 :
523 : int
524 0 : NV12ToRGB24(const uint8_t* aYBuffer, int aYStride,
525 : const uint8_t* aUVBuffer, int aUVStride,
526 : uint8_t* aDstBuffer, int aDstStride,
527 : int aWidth, int aHeight)
528 : {
529 0 : for (int i = 0; i < aHeight; ++i) {
530 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
531 0 : const uint8_t* uBuffer = aUVBuffer + aUVStride * (i / 2);
532 0 : const uint8_t* vBuffer = aUVBuffer + aUVStride * (i / 2) + 1;
533 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
534 :
535 : YUVFamilyToRGBFamily_Row<0, 0, 0, 1, 0, 0, 2, 2, 2, 0, 1, 2>(yBuffer,
536 : uBuffer,
537 : vBuffer,
538 : dstBuffer,
539 0 : aWidth);
540 : }
541 :
542 0 : return 0;
543 : }
544 :
545 : int
546 0 : NV21ToRGB24(const uint8_t* aYBuffer, int aYStride,
547 : const uint8_t* aVUBuffer, int aVUStride,
548 : uint8_t* aDstBuffer, int aDstStride,
549 : int aWidth, int aHeight)
550 : {
551 0 : for (int i = 0; i < aHeight; ++i) {
552 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
553 0 : const uint8_t* uBuffer = aVUBuffer + aVUStride * (i / 2) + 1;
554 0 : const uint8_t* vBuffer = aVUBuffer + aVUStride * (i / 2);
555 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
556 :
557 : YUVFamilyToRGBFamily_Row<0, 0, 0, 1, 0, 0, 2, 2, 2, 0, 1, 2>(yBuffer,
558 : uBuffer,
559 : vBuffer,
560 : dstBuffer,
561 0 : aWidth);
562 : }
563 :
564 0 : return 0;
565 : }
566 :
567 : int
568 0 : YUV444PToBGR24(const uint8_t* aYBuffer, int aYStride,
569 : const uint8_t* aUBuffer, int aUStride,
570 : const uint8_t* aVBuffer, int aVStride,
571 : uint8_t* aDstBuffer, int aDstStride,
572 : int aWidth, int aHeight)
573 : {
574 0 : for (int i = 0; i < aHeight; ++i) {
575 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
576 0 : const uint8_t* uBuffer = aUBuffer + aUStride * i;
577 0 : const uint8_t* vBuffer = aVBuffer + aVStride * i;
578 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
579 :
580 : YUVFamilyToRGBFamily_Row<0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 1, 0>(yBuffer,
581 : uBuffer,
582 : vBuffer,
583 : dstBuffer,
584 0 : aWidth);
585 : }
586 :
587 0 : return 0;
588 : }
589 :
590 : int
591 0 : YUV422PToBGR24(const uint8_t* aYBuffer, int aYStride,
592 : const uint8_t* aUBuffer, int aUStride,
593 : const uint8_t* aVBuffer, int aVStride,
594 : uint8_t* aDstBuffer, int aDstStride,
595 : int aWidth, int aHeight)
596 : {
597 0 : for (int i = 0; i < aHeight; ++i) {
598 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
599 0 : const uint8_t* uBuffer = aUBuffer + aUStride * i;
600 0 : const uint8_t* vBuffer = aVBuffer + aVStride * i;
601 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
602 :
603 : YUVFamilyToRGBFamily_Row<0, 0, 0, 1, 0, 0, 2, 1, 1, 2, 1, 0>(yBuffer,
604 : uBuffer,
605 : vBuffer,
606 : dstBuffer,
607 0 : aWidth);
608 : }
609 :
610 0 : return 0;
611 : }
612 :
613 : int
614 0 : YUV420PToBGR24(const uint8_t* aYBuffer, int aYStride,
615 : const uint8_t* aUBuffer, int aUStride,
616 : const uint8_t* aVBuffer, int aVStride,
617 : uint8_t* aDstBuffer, int aDstStride,
618 : int aWidth, int aHeight)
619 : {
620 0 : for (int i = 0; i < aHeight; ++i) {
621 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
622 0 : const uint8_t* uBuffer = aUBuffer + aUStride * (i / 2);
623 0 : const uint8_t* vBuffer = aVBuffer + aVStride * (i / 2);
624 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
625 :
626 : YUVFamilyToRGBFamily_Row<0, 0, 0, 1, 0, 0, 2, 1, 1, 2, 1, 0>(yBuffer,
627 : uBuffer,
628 : vBuffer,
629 : dstBuffer,
630 0 : aWidth);
631 : }
632 :
633 0 : return 0;
634 : }
635 :
636 : int
637 0 : NV12ToBGR24(const uint8_t* aYBuffer, int aYStride,
638 : const uint8_t* aUVBuffer, int aUVStride,
639 : uint8_t* aDstBuffer, int aDstStride,
640 : int aWidth, int aHeight)
641 : {
642 0 : for (int i = 0; i < aHeight; ++i) {
643 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
644 0 : const uint8_t* uBuffer = aUVBuffer + aUVStride * (i / 2);
645 0 : const uint8_t* vBuffer = aUVBuffer + aUVStride * (i / 2) + 1;
646 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
647 :
648 : YUVFamilyToRGBFamily_Row<0, 0, 0, 1, 0, 0, 2, 2, 2, 2, 1, 0>(yBuffer,
649 : uBuffer,
650 : vBuffer,
651 : dstBuffer,
652 0 : aWidth);
653 : }
654 :
655 0 : return 0;
656 : }
657 :
658 : int
659 0 : NV21ToBGR24(const uint8_t* aYBuffer, int aYStride,
660 : const uint8_t* aVUBuffer, int aVUStride,
661 : uint8_t* aDstBuffer, int aDstStride,
662 : int aWidth, int aHeight)
663 : {
664 0 : for (int i = 0; i < aHeight; ++i) {
665 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
666 0 : const uint8_t* uBuffer = aVUBuffer + aVUStride * (i / 2) + 1;
667 0 : const uint8_t* vBuffer = aVUBuffer + aVUStride * (i / 2);
668 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
669 :
670 : YUVFamilyToRGBFamily_Row<0, 0, 0, 1, 0, 0, 2, 2, 2, 2, 1, 0>(yBuffer,
671 : uBuffer,
672 : vBuffer,
673 : dstBuffer,
674 0 : aWidth);
675 : }
676 :
677 0 : return 0;
678 : }
679 :
680 : /*
681 : * YUV family -> RGBA family.
682 : */
683 : int
684 0 : YUV444PToRGBA32(const uint8_t* aYBuffer, int aYStride,
685 : const uint8_t* aUBuffer, int aUStride,
686 : const uint8_t* aVBuffer, int aVStride,
687 : uint8_t* aDstBuffer, int aDstStride,
688 : int aWidth, int aHeight)
689 : {
690 0 : for (int i = 0; i < aHeight; ++i) {
691 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
692 0 : const uint8_t* uBuffer = aUBuffer + aUStride * i;
693 0 : const uint8_t* vBuffer = aVBuffer + aVStride * i;
694 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
695 :
696 : YUVFamilyToRGBAFamily_Row<0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 1, 2, 3>(yBuffer,
697 : uBuffer,
698 : vBuffer,
699 : dstBuffer,
700 0 : aWidth);
701 : }
702 :
703 0 : return 0;
704 : }
705 :
706 : int
707 0 : YUV422PToRGBA32(const uint8_t* aYBuffer, int aYStride,
708 : const uint8_t* aUBuffer, int aUStride,
709 : const uint8_t* aVBuffer, int aVStride,
710 : uint8_t* aDstBuffer, int aDstStride,
711 : int aWidth, int aHeight)
712 : {
713 0 : for (int i = 0; i < aHeight; ++i) {
714 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
715 0 : const uint8_t* uBuffer = aUBuffer + aUStride * i;
716 0 : const uint8_t* vBuffer = aVBuffer + aVStride * i;
717 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
718 :
719 : YUVFamilyToRGBAFamily_Row<0, 0, 0, 1, 0, 0, 2, 1, 1, 0, 1, 2, 3>(yBuffer,
720 : uBuffer,
721 : vBuffer,
722 : dstBuffer,
723 0 : aWidth);
724 : }
725 :
726 0 : return 0;
727 : }
728 :
729 : int
730 0 : YUV420PToRGBA32(const uint8_t* aYBuffer, int aYStride,
731 : const uint8_t* aUBuffer, int aUStride,
732 : const uint8_t* aVBuffer, int aVStride,
733 : uint8_t* aDstBuffer, int aDstStride,
734 : int aWidth, int aHeight)
735 : {
736 0 : for (int i = 0; i < aHeight; ++i) {
737 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
738 0 : const uint8_t* uBuffer = aUBuffer + aUStride * (i / 2);
739 0 : const uint8_t* vBuffer = aVBuffer + aVStride * (i / 2);
740 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
741 :
742 : YUVFamilyToRGBAFamily_Row<0, 0, 0, 1, 0, 0, 2, 1, 1, 0, 1, 2, 3>(yBuffer,
743 : uBuffer,
744 : vBuffer,
745 : dstBuffer,
746 0 : aWidth);
747 : }
748 :
749 0 : return 0;
750 : }
751 :
752 : int
753 0 : NV12ToRGBA32(const uint8_t* aYBuffer, int aYStride,
754 : const uint8_t* aUVBuffer, int aUVStride,
755 : uint8_t* aDstBuffer, int aDstStride,
756 : int aWidth, int aHeight)
757 : {
758 0 : for (int i = 0; i < aHeight; ++i) {
759 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
760 0 : const uint8_t* uBuffer = aUVBuffer + aUVStride * (i / 2);
761 0 : const uint8_t* vBuffer = aUVBuffer + aUVStride * (i / 2) + 1;
762 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
763 :
764 : YUVFamilyToRGBAFamily_Row<0, 0, 0, 1, 0, 0, 2, 2, 2, 0, 1, 2, 3>(yBuffer,
765 : uBuffer,
766 : vBuffer,
767 : dstBuffer,
768 0 : aWidth);
769 : }
770 :
771 0 : return 0;
772 : }
773 :
774 : int
775 0 : NV21ToRGBA32(const uint8_t* aYBuffer, int aYStride,
776 : const uint8_t* aVUBuffer, int aVUStride,
777 : uint8_t* aDstBuffer, int aDstStride,
778 : int aWidth, int aHeight)
779 : {
780 0 : for (int i = 0; i < aHeight; ++i) {
781 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
782 0 : const uint8_t* uBuffer = aVUBuffer + aVUStride * (i / 2) + 1;
783 0 : const uint8_t* vBuffer = aVUBuffer + aVUStride * (i / 2);
784 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
785 :
786 : YUVFamilyToRGBAFamily_Row<0, 0, 0, 1, 0, 0, 2, 2, 2, 0, 1, 2, 3>(yBuffer,
787 : uBuffer,
788 : vBuffer,
789 : dstBuffer,
790 0 : aWidth);
791 : }
792 :
793 0 : return 0;
794 : }
795 :
796 : int
797 0 : YUV444PToBGRA32(const uint8_t* aYBuffer, int aYStride,
798 : const uint8_t* aUBuffer, int aUStride,
799 : const uint8_t* aVBuffer, int aVStride,
800 : uint8_t* aDstBuffer, int aDstStride,
801 : int aWidth, int aHeight)
802 : {
803 0 : for (int i = 0; i < aHeight; ++i) {
804 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
805 0 : const uint8_t* uBuffer = aUBuffer + aUStride * i;
806 0 : const uint8_t* vBuffer = aVBuffer + aVStride * i;
807 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
808 :
809 : YUVFamilyToRGBAFamily_Row<0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 1, 0, 3>(yBuffer,
810 : uBuffer,
811 : vBuffer,
812 : dstBuffer,
813 0 : aWidth);
814 : }
815 :
816 0 : return 0;
817 : }
818 :
819 : int
820 0 : YUV422PToBGRA32(const uint8_t* aYBuffer, int aYStride,
821 : const uint8_t* aUBuffer, int aUStride,
822 : const uint8_t* aVBuffer, int aVStride,
823 : uint8_t* aDstBuffer, int aDstStride,
824 : int aWidth, int aHeight)
825 : {
826 0 : for (int i = 0; i < aHeight; ++i) {
827 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
828 0 : const uint8_t* uBuffer = aUBuffer + aUStride * i;
829 0 : const uint8_t* vBuffer = aVBuffer + aVStride * i;
830 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
831 :
832 : YUVFamilyToRGBAFamily_Row<0, 0, 0, 1, 0, 0, 2, 1, 1, 2, 1, 0, 3>(yBuffer,
833 : uBuffer,
834 : vBuffer,
835 : dstBuffer,
836 0 : aWidth);
837 : }
838 :
839 0 : return 0;
840 : }
841 :
842 : int
843 0 : YUV420PToBGRA32(const uint8_t* aYBuffer, int aYStride,
844 : const uint8_t* aUBuffer, int aUStride,
845 : const uint8_t* aVBuffer, int aVStride,
846 : uint8_t* aDstBuffer, int aDstStride,
847 : int aWidth, int aHeight)
848 : {
849 0 : for (int i = 0; i < aHeight; ++i) {
850 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
851 0 : const uint8_t* uBuffer = aUBuffer + aUStride * (i / 2);
852 0 : const uint8_t* vBuffer = aVBuffer + aVStride * (i / 2);
853 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
854 :
855 : YUVFamilyToRGBAFamily_Row<0, 0, 0, 1, 0, 0, 2, 1, 1, 2, 1, 0, 3>(yBuffer,
856 : uBuffer,
857 : vBuffer,
858 : dstBuffer,
859 0 : aWidth);
860 : }
861 :
862 0 : return 0;
863 : }
864 :
865 : int
866 0 : NV12ToBGRA32(const uint8_t* aYBuffer, int aYStride,
867 : const uint8_t* aUVBuffer, int aUVStride,
868 : uint8_t* aDstBuffer, int aDstStride,
869 : int aWidth, int aHeight)
870 : {
871 0 : for (int i = 0; i < aHeight; ++i) {
872 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
873 0 : const uint8_t* uBuffer = aUVBuffer + aUVStride * (i / 2);
874 0 : const uint8_t* vBuffer = aUVBuffer + aUVStride * (i / 2) + 1;
875 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
876 :
877 : YUVFamilyToRGBAFamily_Row<0, 0, 0, 1, 0, 0, 2, 2, 2, 2, 1, 0, 3>(yBuffer,
878 : uBuffer,
879 : vBuffer,
880 : dstBuffer,
881 0 : aWidth);
882 : }
883 :
884 0 : return 0;
885 : }
886 :
887 : int
888 0 : NV21ToBGRA32(const uint8_t* aYBuffer, int aYStride,
889 : const uint8_t* aVUBuffer, int aVUStride,
890 : uint8_t* aDstBuffer, int aDstStride,
891 : int aWidth, int aHeight)
892 : {
893 0 : for (int i = 0; i < aHeight; ++i) {
894 0 : const uint8_t* yBuffer = aYBuffer + aYStride * i;
895 0 : const uint8_t* uBuffer = aVUBuffer + aVUStride * (i / 2) + 1;
896 0 : const uint8_t* vBuffer = aVUBuffer + aVUStride * (i / 2);
897 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
898 :
899 : YUVFamilyToRGBAFamily_Row<0, 0, 0, 1, 0, 0, 2, 2, 2, 2, 1, 0, 3>(yBuffer,
900 : uBuffer,
901 : vBuffer,
902 : dstBuffer,
903 0 : aWidth);
904 : }
905 :
906 0 : return 0;
907 : }
908 :
909 : /*
910 : * RGB family -> YUV family.
911 : */
912 : int
913 0 : RGB24ToYUV444P(const uint8_t* aSrcBuffer, int aSrcStride,
914 : uint8_t* aYBuffer, int aYStride,
915 : uint8_t* aUBuffer, int aUStride,
916 : uint8_t* aVBuffer, int aVStride,
917 : int aWidth, int aHeight)
918 : {
919 0 : for (int i = 0; i < aHeight; ++i) {
920 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
921 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
922 0 : uint8_t* uBuffer = aUBuffer + aUStride * i;
923 0 : uint8_t* vBuffer = aVBuffer + aVStride * i;
924 :
925 0 : for (int j = 0; j < aWidth; ++j) {
926 0 : yBuffer[0] = RGBToY(srcBuffer[0], srcBuffer[1], srcBuffer[2]);
927 0 : uBuffer[0] = RGBToU(srcBuffer[0], srcBuffer[1], srcBuffer[2]);
928 0 : vBuffer[0] = RGBToV(srcBuffer[0], srcBuffer[1], srcBuffer[2]);
929 :
930 0 : yBuffer += 1;
931 0 : uBuffer += 1;
932 0 : vBuffer += 1;
933 0 : srcBuffer += 3;
934 : }
935 : }
936 :
937 0 : return 0;
938 : }
939 :
940 : int
941 0 : RGB24ToYUV422P(const uint8_t* aSrcBuffer, int aSrcStride,
942 : uint8_t* aYBuffer, int aYStride,
943 : uint8_t* aUBuffer, int aUStride,
944 : uint8_t* aVBuffer, int aVStride,
945 : int aWidth, int aHeight)
946 : {
947 0 : for (int i = 0; i < aHeight; ++i) {
948 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
949 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
950 0 : uint8_t* uBuffer = aUBuffer + aUStride * i;
951 0 : uint8_t* vBuffer = aVBuffer + aVStride * i;
952 :
953 0 : RGBFamilyToY_Row<0, 1, 2>(srcBuffer, yBuffer, aWidth);
954 :
955 : // Pass 0 as the aSrcStride so we don't sample next row's RGB information.
956 0 : RGBFamilyToUV_Row<0, 1, 2, 1, 1>(srcBuffer, 0, uBuffer, vBuffer, aWidth);
957 : }
958 :
959 0 : return 0;
960 : }
961 :
962 : int
963 0 : RGB24ToYUV420P(const uint8_t* aSrcBuffer, int aSrcStride,
964 : uint8_t* aYBuffer, int aYStride,
965 : uint8_t* aUBuffer, int aUStride,
966 : uint8_t* aVBuffer, int aVStride,
967 : int aWidth, int aHeight)
968 : {
969 0 : for (int i = 0; i < aHeight - 1; i += 2) {
970 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
971 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
972 0 : uint8_t* uBuffer = aUBuffer + aUStride * (i / 2);
973 0 : uint8_t* vBuffer = aVBuffer + aVStride * (i / 2);
974 :
975 0 : RGBFamilyToY_Row<0, 1, 2>(srcBuffer, yBuffer, aWidth);
976 0 : RGBFamilyToY_Row<0, 1, 2>(srcBuffer + aSrcStride, yBuffer + aYStride, aWidth);
977 0 : RGBFamilyToUV_Row<0, 1, 2, 1, 1>(srcBuffer, aSrcStride, uBuffer, vBuffer, aWidth);
978 : }
979 :
980 0 : if (aHeight & 1) {
981 0 : const int i = aHeight - 1;
982 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
983 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
984 0 : uint8_t* uBuffer = aUBuffer + aUStride * (i / 2);
985 0 : uint8_t* vBuffer = aVBuffer + aVStride * (i / 2);
986 :
987 0 : RGBFamilyToY_Row<0, 1, 2>(srcBuffer, yBuffer, aWidth);
988 :
989 : // Pass 0 as the aSrcStride so we don't sample next row's RGB information.
990 0 : RGBFamilyToUV_Row<0, 1, 2, 1, 1>(srcBuffer, 0, uBuffer, vBuffer, aWidth);
991 : }
992 :
993 0 : return 0;
994 : }
995 :
996 : int
997 0 : RGB24ToNV12(const uint8_t* aSrcBuffer, int aSrcStride,
998 : uint8_t* aYBuffer, int aYStride,
999 : uint8_t* aUVBuffer, int aUVStride,
1000 : int aWidth, int aHeight)
1001 : {
1002 0 : for (int i = 0; i < aHeight - 1; i += 2) {
1003 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1004 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1005 0 : uint8_t* uBuffer = aUVBuffer + aUVStride * (i / 2);
1006 0 : uint8_t* vBuffer = aUVBuffer + aUVStride * (i / 2) + 1;
1007 :
1008 0 : RGBFamilyToY_Row<0, 1, 2>(srcBuffer, yBuffer, aWidth);
1009 0 : RGBFamilyToY_Row<0, 1, 2>(srcBuffer + aSrcStride, yBuffer + aYStride, aWidth);
1010 0 : RGBFamilyToUV_Row<0, 1, 2, 2, 2>(srcBuffer, aSrcStride, uBuffer, vBuffer, aWidth);
1011 : }
1012 :
1013 0 : if (aHeight & 1) {
1014 0 : const int i = aHeight - 1;
1015 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1016 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1017 0 : uint8_t* uBuffer = aUVBuffer + aUVStride * (i / 2);
1018 0 : uint8_t* vBuffer = aUVBuffer + aUVStride * (i / 2) + 1;
1019 :
1020 0 : RGBFamilyToY_Row<0, 1, 2>(srcBuffer, yBuffer, aWidth);
1021 :
1022 : // Pass 0 as the aSrcStride so we don't sample next row's RGB information.
1023 0 : RGBFamilyToUV_Row<0, 1, 2, 2, 2>(srcBuffer, 0, uBuffer, vBuffer, aWidth);
1024 : }
1025 :
1026 0 : return 0;
1027 : }
1028 :
1029 : int
1030 0 : RGB24ToNV21(const uint8_t* aSrcBuffer, int aSrcStride,
1031 : uint8_t* aYBuffer, int aYStride,
1032 : uint8_t* aVUBuffer, int aVUStride,
1033 : int aWidth, int aHeight)
1034 : {
1035 0 : for (int i = 0; i < aHeight - 1; i += 2) {
1036 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1037 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1038 0 : uint8_t* uBuffer = aVUBuffer + aVUStride * (i / 2) + 1;
1039 0 : uint8_t* vBuffer = aVUBuffer + aVUStride * (i / 2);
1040 :
1041 0 : RGBFamilyToY_Row<0, 1, 2>(srcBuffer, yBuffer, aWidth);
1042 0 : RGBFamilyToY_Row<0, 1, 2>(srcBuffer + aSrcStride, yBuffer + aYStride, aWidth);
1043 0 : RGBFamilyToUV_Row<0, 1, 2, 2, 2>(srcBuffer, aSrcStride, uBuffer, vBuffer, aWidth);
1044 : }
1045 :
1046 0 : if (aHeight & 1) {
1047 0 : const int i = aHeight - 1;
1048 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1049 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1050 0 : uint8_t* uBuffer = aVUBuffer + aVUStride * (i / 2) + 1;
1051 0 : uint8_t* vBuffer = aVUBuffer + aVUStride * (i / 2);
1052 :
1053 0 : RGBFamilyToY_Row<0, 1, 2>(srcBuffer, yBuffer, aWidth);
1054 :
1055 : // Pass 0 as the aSrcStride so we don't sample next row's RGB information.
1056 0 : RGBFamilyToUV_Row<0, 1, 2, 2, 2>(srcBuffer, 0, uBuffer, vBuffer, aWidth);
1057 : }
1058 :
1059 0 : return 0;
1060 : }
1061 :
1062 : int
1063 0 : BGR24ToYUV444P(const uint8_t* aSrcBuffer, int aSrcStride,
1064 : uint8_t* aYBuffer, int aYStride,
1065 : uint8_t* aUBuffer, int aUStride,
1066 : uint8_t* aVBuffer, int aVStride,
1067 : int aWidth, int aHeight)
1068 : {
1069 0 : for (int i = 0; i < aHeight; ++i) {
1070 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1071 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1072 0 : uint8_t* uBuffer = aUBuffer + aUStride * i;
1073 0 : uint8_t* vBuffer = aVBuffer + aVStride * i;
1074 :
1075 0 : for (int j = 0; j < aWidth; ++j) {
1076 0 : yBuffer[0] = RGBToY(srcBuffer[2], srcBuffer[1], srcBuffer[0]);
1077 0 : uBuffer[0] = RGBToU(srcBuffer[2], srcBuffer[1], srcBuffer[0]);
1078 0 : vBuffer[0] = RGBToV(srcBuffer[2], srcBuffer[1], srcBuffer[0]);
1079 :
1080 0 : yBuffer += 1;
1081 0 : uBuffer += 1;
1082 0 : vBuffer += 1;
1083 0 : srcBuffer += 3;
1084 : }
1085 : }
1086 :
1087 0 : return 0;
1088 : }
1089 :
1090 : int
1091 0 : BGR24ToYUV422P(const uint8_t* aSrcBuffer, int aSrcStride,
1092 : uint8_t* aYBuffer, int aYStride,
1093 : uint8_t* aUBuffer, int aUStride,
1094 : uint8_t* aVBuffer, int aVStride,
1095 : int aWidth, int aHeight)
1096 : {
1097 0 : for (int i = 0; i < aHeight; ++i) {
1098 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1099 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1100 0 : uint8_t* uBuffer = aUBuffer + aUStride * i;
1101 0 : uint8_t* vBuffer = aVBuffer + aVStride * i;
1102 :
1103 0 : RGBFamilyToY_Row<2, 1, 0>(srcBuffer, yBuffer, aWidth);
1104 :
1105 : // Pass 0 as the aSrcStride so we don't sample next row's RGB information.
1106 0 : RGBFamilyToUV_Row<2, 1, 0, 1, 1>(srcBuffer, 0, uBuffer, vBuffer, aWidth);
1107 : }
1108 :
1109 0 : return 0;
1110 : }
1111 :
1112 : int
1113 0 : BGR24ToYUV420P(const uint8_t* aSrcBuffer, int aSrcStride,
1114 : uint8_t* aYBuffer, int aYStride,
1115 : uint8_t* aUBuffer, int aUStride,
1116 : uint8_t* aVBuffer, int aVStride,
1117 : int aWidth, int aHeight)
1118 : {
1119 0 : for (int i = 0; i < aHeight - 1; i += 2) {
1120 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1121 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1122 0 : uint8_t* uBuffer = aUBuffer + aUStride * (i / 2);
1123 0 : uint8_t* vBuffer = aVBuffer + aVStride * (i / 2);
1124 :
1125 0 : RGBFamilyToY_Row<2, 1, 0>(srcBuffer, yBuffer, aWidth);
1126 0 : RGBFamilyToY_Row<2, 1, 0>(srcBuffer + aSrcStride, yBuffer + aYStride, aWidth);
1127 0 : RGBFamilyToUV_Row<2, 1, 0, 1, 1>(srcBuffer, aSrcStride, uBuffer, vBuffer, aWidth);
1128 : }
1129 :
1130 0 : if (aHeight & 1) {
1131 0 : const int i = aHeight - 1;
1132 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1133 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1134 0 : uint8_t* uBuffer = aUBuffer + aUStride * (i / 2);
1135 0 : uint8_t* vBuffer = aVBuffer + aVStride * (i / 2);
1136 :
1137 0 : RGBFamilyToY_Row<2, 1, 0>(srcBuffer, yBuffer, aWidth);
1138 :
1139 : // Pass 0 as the aSrcStride so we don't sample next row's RGB information.
1140 0 : RGBFamilyToUV_Row<2, 1, 0, 1, 1>(srcBuffer, 0, uBuffer, vBuffer, aWidth);
1141 : }
1142 :
1143 0 : return 0;
1144 : }
1145 :
1146 : int
1147 0 : BGR24ToNV12(const uint8_t* aSrcBuffer, int aSrcStride,
1148 : uint8_t* aYBuffer, int aYStride,
1149 : uint8_t* aUVBuffer, int aUVStride,
1150 : int aWidth, int aHeight)
1151 : {
1152 0 : for (int i = 0; i < aHeight - 1; i += 2) {
1153 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1154 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1155 0 : uint8_t* uBuffer = aUVBuffer + aUVStride * (i / 2);
1156 0 : uint8_t* vBuffer = aUVBuffer + aUVStride * (i / 2) + 1;
1157 :
1158 0 : RGBFamilyToY_Row<2, 1, 0>(srcBuffer, yBuffer, aWidth);
1159 0 : RGBFamilyToY_Row<2, 1, 0>(srcBuffer + aSrcStride, yBuffer + aYStride, aWidth);
1160 0 : RGBFamilyToUV_Row<2, 1, 0, 2, 2>(srcBuffer, aSrcStride, uBuffer, vBuffer, aWidth);
1161 : }
1162 :
1163 0 : if (aHeight & 1) {
1164 0 : const int i = aHeight - 1;
1165 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1166 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1167 0 : uint8_t* uBuffer = aUVBuffer + aUVStride * (i / 2);
1168 0 : uint8_t* vBuffer = aUVBuffer + aUVStride * (i / 2) + 1;
1169 :
1170 0 : RGBFamilyToY_Row<2, 1, 0>(srcBuffer, yBuffer, aWidth);
1171 :
1172 : // Pass 0 as the aSrcStride so we don't sample next row's RGB information.
1173 0 : RGBFamilyToUV_Row<2, 1, 0, 2, 2>(srcBuffer, 0, uBuffer, vBuffer, aWidth);
1174 : }
1175 :
1176 0 : return 0;
1177 : }
1178 :
1179 : int
1180 0 : BGR24ToNV21(const uint8_t* aSrcBuffer, int aSrcStride,
1181 : uint8_t* aYBuffer, int aYStride,
1182 : uint8_t* aVUBuffer, int aVUStride,
1183 : int aWidth, int aHeight)
1184 : {
1185 0 : for (int i = 0; i < aHeight - 1; i += 2) {
1186 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1187 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1188 0 : uint8_t* uBuffer = aVUBuffer + aVUStride * (i / 2) + 1;
1189 0 : uint8_t* vBuffer = aVUBuffer + aVUStride * (i / 2);
1190 :
1191 0 : RGBFamilyToY_Row<2, 1, 0>(srcBuffer, yBuffer, aWidth);
1192 0 : RGBFamilyToY_Row<2, 1, 0>(srcBuffer + aSrcStride, yBuffer + aYStride, aWidth);
1193 0 : RGBFamilyToUV_Row<2, 1, 0, 2, 2>(srcBuffer, aSrcStride, uBuffer, vBuffer, aWidth);
1194 : }
1195 :
1196 0 : if (aHeight & 1) {
1197 0 : const int i = aHeight - 1;
1198 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1199 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1200 0 : uint8_t* uBuffer = aVUBuffer + aVUStride * (i / 2) + 1;
1201 0 : uint8_t* vBuffer = aVUBuffer + aVUStride * (i / 2);
1202 :
1203 0 : RGBFamilyToY_Row<2, 1, 0>(srcBuffer, yBuffer, aWidth);
1204 :
1205 : // Pass 0 as the aSrcStride so we don't sample next row's RGB information.
1206 0 : RGBFamilyToUV_Row<2, 1, 0, 2, 2>(srcBuffer, 0, uBuffer, vBuffer, aWidth);
1207 : }
1208 :
1209 0 : return 0;
1210 : }
1211 :
1212 : /*
1213 : * RGBA family -> YUV family.
1214 : */
1215 : int
1216 0 : RGBA32ToYUV444P(const uint8_t* aSrcBuffer, int aSrcStride,
1217 : uint8_t* aYBuffer, int aYStride,
1218 : uint8_t* aUBuffer, int aUStride,
1219 : uint8_t* aVBuffer, int aVStride,
1220 : int aWidth, int aHeight)
1221 : {
1222 0 : for (int i = 0; i < aHeight; ++i) {
1223 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1224 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1225 0 : uint8_t* uBuffer = aUBuffer + aUStride * i;
1226 0 : uint8_t* vBuffer = aVBuffer + aVStride * i;
1227 :
1228 0 : for (int j = 0; j < aWidth; ++j) {
1229 0 : yBuffer[0] = RGBToY(srcBuffer[0], srcBuffer[1], srcBuffer[2]);
1230 0 : uBuffer[0] = RGBToU(srcBuffer[0], srcBuffer[1], srcBuffer[2]);
1231 0 : vBuffer[0] = RGBToV(srcBuffer[0], srcBuffer[1], srcBuffer[2]);
1232 :
1233 0 : yBuffer += 1;
1234 0 : uBuffer += 1;
1235 0 : vBuffer += 1;
1236 0 : srcBuffer += 4;
1237 : }
1238 : }
1239 :
1240 0 : return 0;
1241 : }
1242 :
1243 : int
1244 0 : RGBA32ToYUV422P(const uint8_t* aSrcBuffer, int aSrcStride,
1245 : uint8_t* aYBuffer, int aYStride,
1246 : uint8_t* aUBuffer, int aUStride,
1247 : uint8_t* aVBuffer, int aVStride,
1248 : int aWidth, int aHeight)
1249 : {
1250 0 : for (int i = 0; i < aHeight; ++i) {
1251 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1252 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1253 0 : uint8_t* uBuffer = aUBuffer + aUStride * i;
1254 0 : uint8_t* vBuffer = aVBuffer + aVStride * i;
1255 :
1256 0 : RGBAFamilyToY_Row<0, 1, 2>(srcBuffer, yBuffer, aWidth);
1257 :
1258 : // Pass 0 as the aSrcStride so we don't sample next row's RGB information.
1259 0 : RGBAFamilyToUV_Row<0, 1, 2, 1, 1>(srcBuffer, 0, uBuffer, vBuffer, aWidth);
1260 : }
1261 :
1262 0 : return 0;
1263 : }
1264 :
1265 : int
1266 0 : RGBA32ToYUV420P(const uint8_t* aSrcBuffer, int aSrcStride,
1267 : uint8_t* aYBuffer, int aYStride,
1268 : uint8_t* aUBuffer, int aUStride,
1269 : uint8_t* aVBuffer, int aVStride,
1270 : int aWidth, int aHeight)
1271 : {
1272 0 : for (int i = 0; i < aHeight - 1; i += 2) {
1273 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1274 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1275 0 : uint8_t* uBuffer = aUBuffer + aUStride * (i / 2);
1276 0 : uint8_t* vBuffer = aVBuffer + aVStride * (i / 2);
1277 :
1278 0 : RGBAFamilyToY_Row<0, 1, 2>(srcBuffer, yBuffer, aWidth);
1279 0 : RGBAFamilyToY_Row<0, 1, 2>(srcBuffer + aSrcStride, yBuffer + aYStride, aWidth);
1280 0 : RGBAFamilyToUV_Row<0, 1, 2, 1, 1>(srcBuffer, aSrcStride, uBuffer, vBuffer, aWidth);
1281 : }
1282 :
1283 0 : if (aHeight & 1) {
1284 0 : const int i = aHeight - 1;
1285 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1286 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1287 0 : uint8_t* uBuffer = aUBuffer + aUStride * (i / 2);
1288 0 : uint8_t* vBuffer = aVBuffer + aVStride * (i / 2);
1289 :
1290 0 : RGBAFamilyToY_Row<0, 1, 2>(srcBuffer, yBuffer, aWidth);
1291 :
1292 : // Pass 0 as the aSrcStride so we don't sample next row's RGB information.
1293 0 : RGBAFamilyToUV_Row<0, 1, 2, 1, 1>(srcBuffer, 0, uBuffer, vBuffer, aWidth);
1294 : }
1295 :
1296 0 : return 0;
1297 : }
1298 :
1299 : int
1300 0 : RGBA32ToNV12(const uint8_t* aSrcBuffer, int aSrcStride,
1301 : uint8_t* aYBuffer, int aYStride,
1302 : uint8_t* aUVBuffer, int aUVStride,
1303 : int aWidth, int aHeight)
1304 : {
1305 0 : for (int i = 0; i < aHeight - 1; i += 2) {
1306 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1307 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1308 0 : uint8_t* uBuffer = aUVBuffer + aUVStride * (i / 2);
1309 0 : uint8_t* vBuffer = aUVBuffer + aUVStride * (i / 2) + 1;
1310 :
1311 0 : RGBAFamilyToY_Row<0, 1, 2>(srcBuffer, yBuffer, aWidth);
1312 0 : RGBAFamilyToY_Row<0, 1, 2>(srcBuffer + aSrcStride, yBuffer + aYStride, aWidth);
1313 0 : RGBAFamilyToUV_Row<0, 1, 2, 2, 2>(srcBuffer, aSrcStride, uBuffer, vBuffer, aWidth);
1314 : }
1315 :
1316 0 : if (aHeight & 1) {
1317 0 : const int i = aHeight - 1;
1318 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1319 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1320 0 : uint8_t* uBuffer = aUVBuffer + aUVStride * (i / 2);
1321 0 : uint8_t* vBuffer = aUVBuffer + aUVStride * (i / 2) + 1;
1322 :
1323 0 : RGBAFamilyToY_Row<0, 1, 2>(srcBuffer, yBuffer, aWidth);
1324 :
1325 : // Pass 0 as the aSrcStride so we don't sample next row's RGB information.
1326 0 : RGBAFamilyToUV_Row<0, 1, 2, 2, 2>(srcBuffer, 0, uBuffer, vBuffer, aWidth);
1327 : }
1328 :
1329 0 : return 0;
1330 : }
1331 :
1332 : int
1333 0 : RGBA32ToNV21(const uint8_t* aSrcBuffer, int aSrcStride,
1334 : uint8_t* aYBuffer, int aYStride,
1335 : uint8_t* aVUBuffer, int aVUStride,
1336 : int aWidth, int aHeight)
1337 : {
1338 0 : for (int i = 0; i < aHeight - 1; i += 2) {
1339 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1340 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1341 0 : uint8_t* uBuffer = aVUBuffer + aVUStride * (i / 2) + 1;
1342 0 : uint8_t* vBuffer = aVUBuffer + aVUStride * (i / 2);
1343 :
1344 0 : RGBAFamilyToY_Row<0, 1, 2>(srcBuffer, yBuffer, aWidth);
1345 0 : RGBAFamilyToY_Row<0, 1, 2>(srcBuffer + aSrcStride, yBuffer + aYStride, aWidth);
1346 0 : RGBAFamilyToUV_Row<0, 1, 2, 2, 2>(srcBuffer, aSrcStride, uBuffer, vBuffer, aWidth);
1347 : }
1348 :
1349 0 : if (aHeight & 1) {
1350 0 : const int i = aHeight - 1;
1351 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1352 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1353 0 : uint8_t* uBuffer = aVUBuffer + aVUStride * (i / 2) + 1;
1354 0 : uint8_t* vBuffer = aVUBuffer + aVUStride * (i / 2);
1355 :
1356 0 : RGBAFamilyToY_Row<0, 1, 2>(srcBuffer, yBuffer, aWidth);
1357 :
1358 : // Pass 0 as the aSrcStride so we don't sample next row's RGB information.
1359 0 : RGBAFamilyToUV_Row<0, 1, 2, 2, 2>(srcBuffer, 0, uBuffer, vBuffer, aWidth);
1360 : }
1361 :
1362 0 : return 0;
1363 : }
1364 :
1365 : int
1366 0 : BGRA32ToYUV444P(const uint8_t* aSrcBuffer, int aSrcStride,
1367 : uint8_t* aYBuffer, int aYStride,
1368 : uint8_t* aUBuffer, int aUStride,
1369 : uint8_t* aVBuffer, int aVStride,
1370 : int aWidth, int aHeight)
1371 : {
1372 0 : for (int i = 0; i < aHeight; ++i) {
1373 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1374 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1375 0 : uint8_t* uBuffer = aUBuffer + aUStride * i;
1376 0 : uint8_t* vBuffer = aVBuffer + aVStride * i;
1377 :
1378 0 : for (int j = 0; j < aWidth; ++j) {
1379 0 : yBuffer[0] = RGBToY(srcBuffer[2], srcBuffer[1], srcBuffer[0]);
1380 0 : uBuffer[0] = RGBToU(srcBuffer[2], srcBuffer[1], srcBuffer[0]);
1381 0 : vBuffer[0] = RGBToV(srcBuffer[2], srcBuffer[1], srcBuffer[0]);
1382 :
1383 0 : yBuffer += 1;
1384 0 : uBuffer += 1;
1385 0 : vBuffer += 1;
1386 0 : srcBuffer += 4;
1387 : }
1388 : }
1389 :
1390 0 : return 0;
1391 : }
1392 :
1393 : int
1394 0 : BGRA32ToYUV422P(const uint8_t* aSrcBuffer, int aSrcStride,
1395 : uint8_t* aYBuffer, int aYStride,
1396 : uint8_t* aUBuffer, int aUStride,
1397 : uint8_t* aVBuffer, int aVStride,
1398 : int aWidth, int aHeight)
1399 : {
1400 0 : for (int i = 0; i < aHeight; ++i) {
1401 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1402 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1403 0 : uint8_t* uBuffer = aUBuffer + aUStride * i;
1404 0 : uint8_t* vBuffer = aVBuffer + aVStride * i;
1405 :
1406 0 : RGBAFamilyToY_Row<2, 1, 0>(srcBuffer, yBuffer, aWidth);
1407 :
1408 : // Pass 0 as the aSrcStride so we don't sample next row's RGB information.
1409 0 : RGBAFamilyToUV_Row<2, 1, 0, 1, 1>(srcBuffer, 0, uBuffer, vBuffer, aWidth);
1410 : }
1411 :
1412 0 : return 0;
1413 : }
1414 :
1415 : int
1416 0 : BGRA32ToYUV420P(const uint8_t* aSrcBuffer, int aSrcStride,
1417 : uint8_t* aYBuffer, int aYStride,
1418 : uint8_t* aUBuffer, int aUStride,
1419 : uint8_t* aVBuffer, int aVStride,
1420 : int aWidth, int aHeight)
1421 : {
1422 0 : for (int i = 0; i < aHeight - 1; i += 2) {
1423 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1424 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1425 0 : uint8_t* uBuffer = aUBuffer + aUStride * (i / 2);
1426 0 : uint8_t* vBuffer = aVBuffer + aVStride * (i / 2);
1427 :
1428 0 : RGBAFamilyToY_Row<2, 1, 0>(srcBuffer, yBuffer, aWidth);
1429 0 : RGBAFamilyToY_Row<2, 1, 0>(srcBuffer + aSrcStride, yBuffer + aYStride, aWidth);
1430 0 : RGBAFamilyToUV_Row<2, 1, 0, 1, 1>(srcBuffer, aSrcStride, uBuffer, vBuffer, aWidth);
1431 : }
1432 :
1433 0 : if (aHeight & 1) {
1434 0 : const int i = aHeight - 1;
1435 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1436 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1437 0 : uint8_t* uBuffer = aUBuffer + aUStride * (i / 2);
1438 0 : uint8_t* vBuffer = aVBuffer + aVStride * (i / 2);
1439 :
1440 0 : RGBAFamilyToY_Row<2, 1, 0>(srcBuffer, yBuffer, aWidth);
1441 :
1442 : // Pass 0 as the aSrcStride so we don't sample next row's RGB information.
1443 0 : RGBAFamilyToUV_Row<2, 1, 0, 1, 1>(srcBuffer, 0, uBuffer, vBuffer, aWidth);
1444 : }
1445 :
1446 0 : return 0;
1447 : }
1448 :
1449 : int
1450 0 : BGRA32ToNV12(const uint8_t* aSrcBuffer, int aSrcStride,
1451 : uint8_t* aYBuffer, int aYStride,
1452 : uint8_t* aUVBuffer, int aUVStride,
1453 : int aWidth, int aHeight)
1454 : {
1455 0 : for (int i = 0; i < aHeight - 1; i += 2) {
1456 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1457 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1458 0 : uint8_t* uBuffer = aUVBuffer + aUVStride * (i / 2);
1459 0 : uint8_t* vBuffer = aUVBuffer + aUVStride * (i / 2) + 1;
1460 :
1461 0 : RGBAFamilyToY_Row<2, 1, 0>(srcBuffer, yBuffer, aWidth);
1462 0 : RGBAFamilyToY_Row<2, 1, 0>(srcBuffer + aSrcStride, yBuffer + aYStride, aWidth);
1463 0 : RGBAFamilyToUV_Row<2, 1, 0, 2, 2>(srcBuffer, aSrcStride, uBuffer, vBuffer, aWidth);
1464 : }
1465 :
1466 0 : if (aHeight & 1) {
1467 0 : const int i = aHeight - 1;
1468 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1469 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1470 0 : uint8_t* uBuffer = aUVBuffer + aUVStride * (i / 2);
1471 0 : uint8_t* vBuffer = aUVBuffer + aUVStride * (i / 2) + 1;
1472 :
1473 0 : RGBAFamilyToY_Row<2, 1, 0>(srcBuffer, yBuffer, aWidth);
1474 :
1475 : // Pass 0 as the aSrcStride so we don't sample next row's RGB information.
1476 0 : RGBAFamilyToUV_Row<2, 1, 0, 2, 2>(srcBuffer, 0, uBuffer, vBuffer, aWidth);
1477 : }
1478 :
1479 0 : return 0;
1480 : }
1481 :
1482 : int
1483 0 : BGRA32ToNV21(const uint8_t* aSrcBuffer, int aSrcStride,
1484 : uint8_t* aYBuffer, int aYStride,
1485 : uint8_t* aVUBuffer, int aVUStride,
1486 : int aWidth, int aHeight)
1487 : {
1488 0 : for (int i = 0; i < aHeight - 1; i += 2) {
1489 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1490 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1491 0 : uint8_t* uBuffer = aVUBuffer + aVUStride * (i / 2) + 1;
1492 0 : uint8_t* vBuffer = aVUBuffer + aVUStride * (i / 2);
1493 :
1494 0 : RGBAFamilyToY_Row<2, 1, 0>(srcBuffer, yBuffer, aWidth);
1495 0 : RGBAFamilyToY_Row<2, 1, 0>(srcBuffer + aSrcStride, yBuffer + aYStride, aWidth);
1496 0 : RGBAFamilyToUV_Row<2, 1, 0, 2, 2>(srcBuffer, aSrcStride, uBuffer, vBuffer, aWidth);
1497 : }
1498 :
1499 0 : if (aHeight & 1) {
1500 0 : const int i = aHeight - 1;
1501 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1502 0 : uint8_t* yBuffer = aYBuffer + aYStride * i;
1503 0 : uint8_t* uBuffer = aVUBuffer + aVUStride * (i / 2) + 1;
1504 0 : uint8_t* vBuffer = aVUBuffer + aVUStride * (i / 2);
1505 :
1506 0 : RGBAFamilyToY_Row<2, 1, 0>(srcBuffer, yBuffer, aWidth);
1507 :
1508 : // Pass 0 as the aSrcStride so we don't sample next row's RGB information.
1509 0 : RGBAFamilyToUV_Row<2, 1, 0, 2, 2>(srcBuffer, 0, uBuffer, vBuffer, aWidth);
1510 : }
1511 :
1512 0 : return 0;
1513 : }
1514 :
1515 : /*
1516 : * RGBA/RGB family -> HSV.
1517 : * Reference:
1518 : * (1) https://en.wikipedia.org/wiki/HSL_and_HSV
1519 : * (2) OpenCV implementation:
1520 : * http://docs.opencv.org/3.1.0/de/d25/imgproc_color_conversions.html
1521 : */
1522 : const float EPSILON = 1e-10f;
1523 :
1524 : template<int aRIndex, int aGIndex, int aBIndex, int aSrcStep>
1525 : int
1526 0 : RGBFamilyToHSV(const uint8_t* aSrcBuffer, int aSrcStride,
1527 : float* aDstBuffer, int aDstStride,
1528 : int aWidth, int aHeight)
1529 : {
1530 0 : for (int i = 0; i < aHeight; ++i) {
1531 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1532 0 : float* dstBuffer = (float*)((uint8_t*)(aDstBuffer) + aDstStride * i);
1533 :
1534 0 : for (int j = 0; j < aWidth; ++j) {
1535 0 : const float r = (float)(srcBuffer[aRIndex]) / 255.0f;
1536 0 : const float g = (float)(srcBuffer[aGIndex]) / 255.0f;
1537 0 : const float b = (float)(srcBuffer[aBIndex]) / 255.0f;
1538 0 : float& h = dstBuffer[0];
1539 0 : float& s = dstBuffer[1];
1540 0 : float& v = dstBuffer[2];
1541 :
1542 0 : float min = r;
1543 0 : if (g < min) min = g;
1544 0 : if (b < min) min = b;
1545 :
1546 0 : float max = r;
1547 0 : if (g > max) max = g;
1548 0 : if (b > max) max = b;
1549 :
1550 0 : const float diff = max - min + EPSILON; // Prevent dividing by zero.
1551 :
1552 : // Calculate v.
1553 0 : v = max;
1554 :
1555 : // Calculate s.
1556 0 : if (max == 0.0f) {
1557 0 : s = 0.0f;
1558 : } else {
1559 0 : s = diff / v;
1560 : }
1561 :
1562 : // Calculate h.
1563 0 : if (max == r) {
1564 0 : h = 60.0f * (g - b) / diff;
1565 0 : } else if (max == g) {
1566 0 : h = 60.0f * (b - r) / diff + 120.0f;
1567 0 : } else if (max == b) {
1568 0 : h = 60.0f * (r - g) / diff + 240.0f;
1569 : }
1570 :
1571 0 : if (h < 0.0f) {
1572 0 : h += 360.0f;
1573 : }
1574 :
1575 : // Step one pixel.
1576 0 : srcBuffer += aSrcStep;
1577 0 : dstBuffer += 3;
1578 : }
1579 : }
1580 :
1581 0 : return 0;
1582 : }
1583 :
1584 : static const int sector_data[][3]= {{0,3,1}, {2,0,1}, {1,0,3}, {1,2,0}, {3,1,0}, {0,1,2}};
1585 :
1586 : // If the destination is a RGB24 or BGR24, set the aAIndex to be 0, 1 or 2,
1587 : // so that the r, g or b value will be set to 255 first than to the right value.
1588 : template<int aRIndex, int aGIndex, int aBIndex, int aAIndex, int aDstStep>
1589 : int
1590 0 : HSVToRGBAFamily(const float* aSrcBuffer, int aSrcStride,
1591 : uint8_t* aDstBuffer, int aDstStride,
1592 : int aWidth, int aHeight)
1593 : {
1594 : static_assert(aRIndex == 0 || aRIndex == 2, "Wrong R index.");
1595 : static_assert(aGIndex == 1, "Wrong G index.");
1596 : static_assert(aBIndex == 0 || aBIndex == 2, "Wrong B index.");
1597 : static_assert(aAIndex == 0 || aAIndex == 1 || aAIndex == 2 || aAIndex == 3, "Wrong A index.");
1598 :
1599 0 : for (int i = 0; i < aHeight; ++i) {
1600 0 : const float* srcBuffer = (const float*)((const uint8_t*)(aSrcBuffer) + aSrcStride * i);
1601 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
1602 :
1603 0 : for (int j = 0; j < aWidth; ++j) {
1604 0 : const float h = srcBuffer[0];
1605 0 : const float s = srcBuffer[1];
1606 0 : const float v = srcBuffer[2];
1607 :
1608 : // Calculate h-prime which should be in range [0, 6). -> h should be in
1609 : // range [0, 360).
1610 0 : float hPrime = h / 60.0f;
1611 0 : if (hPrime < 0.0f)
1612 0 : do hPrime += 6.0f; while (hPrime < 0.0f);
1613 0 : else if (hPrime >= 6.0f)
1614 0 : do hPrime -= 6.0f; while (hPrime >= 6.0f);
1615 0 : const int sector = floor(hPrime);
1616 0 : const float hMod1 = hPrime - sector;
1617 :
1618 : float values[4];
1619 0 : values[0] = v;
1620 0 : values[1] = v * (1.0f - s);
1621 0 : values[2] = v * (1.0f - s * hMod1);
1622 0 : values[3] = v * (1.0f - s * (1.0f - hMod1));
1623 :
1624 0 : dstBuffer[aAIndex] = 255;
1625 0 : dstBuffer[aRIndex] = Clamp(values[sector_data[sector][0]] * 255.0f);
1626 0 : dstBuffer[aGIndex] = Clamp(values[sector_data[sector][1]] * 255.0f);
1627 0 : dstBuffer[aBIndex] = Clamp(values[sector_data[sector][2]] * 255.0f);
1628 :
1629 : // Step one pixel.
1630 0 : srcBuffer += 3;
1631 0 : dstBuffer += aDstStep;
1632 : }
1633 : }
1634 :
1635 0 : return 0;
1636 : }
1637 :
1638 : int
1639 0 : RGBA32ToHSV(const uint8_t* aSrcBuffer, int aSrcStride,
1640 : float* aDstBuffer, int aDstStride,
1641 : int aWidth, int aHeight)
1642 : {
1643 : return RGBFamilyToHSV<0, 1, 2, 4>(aSrcBuffer, aSrcStride,
1644 : aDstBuffer, aDstStride,
1645 0 : aWidth, aHeight);
1646 : }
1647 :
1648 : int
1649 0 : BGRA32ToHSV(const uint8_t* aSrcBuffer, int aSrcStride,
1650 : float* aDstBuffer, int aDstStride,
1651 : int aWidth, int aHeight)
1652 : {
1653 : return RGBFamilyToHSV<2, 1, 0, 4>(aSrcBuffer, aSrcStride,
1654 : aDstBuffer, aDstStride,
1655 0 : aWidth, aHeight);
1656 : }
1657 :
1658 : int
1659 0 : RGB24ToHSV(const uint8_t* aSrcBuffer, int aSrcStride,
1660 : float* aDstBuffer, int aDstStride,
1661 : int aWidth, int aHeight)
1662 : {
1663 : return RGBFamilyToHSV<0, 1, 2, 3>(aSrcBuffer, aSrcStride,
1664 : aDstBuffer, aDstStride,
1665 0 : aWidth, aHeight);
1666 : }
1667 :
1668 : int
1669 0 : BGR24ToHSV(const uint8_t* aSrcBuffer, int aSrcStride,
1670 : float* aDstBuffer, int aDstStride,
1671 : int aWidth, int aHeight)
1672 : {
1673 : return RGBFamilyToHSV<2, 1, 0, 3>(aSrcBuffer, aSrcStride,
1674 : aDstBuffer, aDstStride,
1675 0 : aWidth, aHeight);
1676 : }
1677 :
1678 : int
1679 0 : HSVToRGBA32(const float* aSrcBuffer, int aSrcStride,
1680 : uint8_t* aDstBuffer, int aDstStride,
1681 : int aWidth, int aHeight)
1682 : {
1683 : return HSVToRGBAFamily<0, 1, 2, 3, 4>(aSrcBuffer, aSrcStride,
1684 : aDstBuffer, aDstStride,
1685 0 : aWidth, aHeight);
1686 : }
1687 :
1688 : int
1689 0 : HSVToBGRA32(const float* aSrcBuffer, int aSrcStride,
1690 : uint8_t* aDstBuffer, int aDstStride,
1691 : int aWidth, int aHeight)
1692 : {
1693 : return HSVToRGBAFamily<2, 1, 0, 3, 4>(aSrcBuffer, aSrcStride,
1694 : aDstBuffer, aDstStride,
1695 0 : aWidth, aHeight);
1696 : }
1697 :
1698 : int
1699 0 : HSVToRGB24(const float* aSrcBuffer, int aSrcStride,
1700 : uint8_t* aDstBuffer, int aDstStride,
1701 : int aWidth, int aHeight)
1702 : {
1703 : return HSVToRGBAFamily<0, 1, 2, 0, 3>(aSrcBuffer, aSrcStride,
1704 : aDstBuffer, aDstStride,
1705 0 : aWidth, aHeight);
1706 : }
1707 :
1708 : int
1709 0 : HSVToBGR24(const float* aSrcBuffer, int aSrcStride,
1710 : uint8_t* aDstBuffer, int aDstStride,
1711 : int aWidth, int aHeight)
1712 : {
1713 : return HSVToRGBAFamily<2, 1, 0, 0, 3>(aSrcBuffer, aSrcStride,
1714 : aDstBuffer, aDstStride,
1715 0 : aWidth, aHeight);
1716 : }
1717 :
1718 : /*
1719 : * RGBA/RGB family -> Lab.
1720 : * Reference:
1721 : * (1) https://en.wikipedia.org/wiki/SRGB
1722 : * (2) https://en.wikipedia.org/wiki/Lab_color_space
1723 : * (3) OpenCV implementation:
1724 : * http://docs.opencv.org/3.1.0/de/d25/imgproc_color_conversions.html
1725 : */
1726 : static const float sRGBToXYZ_D65[] = {0.412453f, 0.357580f, 0.180423f,
1727 : 0.212671f, 0.715160f, 0.072169f,
1728 : 0.019334f, 0.119193f, 0.950227f};
1729 : static const float XYZTosRGB_D65[] = {3.240479f, -1.53715f, -0.498535f,
1730 : -0.969256f, 1.875991f, 0.041556f,
1731 : 0.055648f, -0.204043f, 1.057311f};
1732 : static const float whitept_D65[] = {0.950456f, 1.0f, 1.088754f};
1733 : static const float _magic = std::pow((6.0 / 29.0), 3.0); // should be around 0.008856.
1734 : static const float _1_3 = 1.0f / 3.0f;
1735 : static const float _a = std::pow((29.0 / 6.0), 2.0) / 3.0; // should be around 7.787.
1736 : static const float _b = 16.0f / 116.0f; // should be around 0.1379.
1737 :
1738 : template<int aRIndex, int aGIndex, int aBIndex, int aSrcStep>
1739 : int
1740 0 : RGBFamilyToLab(const uint8_t* aSrcBuffer, int aSrcStride,
1741 : float* aDstBuffer, int aDstStride,
1742 : int aWidth, int aHeight)
1743 : {
1744 : static_assert(aRIndex == 0 || aRIndex == 2, "Wrong R index.");
1745 : static_assert(aGIndex == 1, "Wrong G index.");
1746 : static_assert(aBIndex == 0 || aBIndex == 2, "Wrong B index.");
1747 :
1748 0 : const float C0 = sRGBToXYZ_D65[0] / whitept_D65[0],
1749 0 : C1 = sRGBToXYZ_D65[1] / whitept_D65[0],
1750 0 : C2 = sRGBToXYZ_D65[2] / whitept_D65[0],
1751 0 : C3 = sRGBToXYZ_D65[3] / whitept_D65[1],
1752 0 : C4 = sRGBToXYZ_D65[4] / whitept_D65[1],
1753 0 : C5 = sRGBToXYZ_D65[5] / whitept_D65[1],
1754 0 : C6 = sRGBToXYZ_D65[6] / whitept_D65[2],
1755 0 : C7 = sRGBToXYZ_D65[7] / whitept_D65[2],
1756 0 : C8 = sRGBToXYZ_D65[8] / whitept_D65[2];
1757 :
1758 0 : for (int i = 0; i < aHeight; ++i) {
1759 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1760 0 : float* dstBuffer = (float*)((uint8_t*)(aDstBuffer) + aDstStride * i);
1761 :
1762 0 : for (int j = 0; j < aWidth; ++j) {
1763 0 : float r = (float)(srcBuffer[aRIndex]) / 255.0f;
1764 0 : float g = (float)(srcBuffer[aGIndex]) / 255.0f;
1765 0 : float b = (float)(srcBuffer[aBIndex]) / 255.0f;
1766 :
1767 : // gamma correction of sRGB
1768 0 : r = r <= 0.04045f ? r / 12.92f : std::pow((r + 0.055) / 1.055, 2.4);
1769 0 : g = g <= 0.04045f ? g / 12.92f : std::pow((g + 0.055) / 1.055, 2.4);
1770 0 : b = b <= 0.04045f ? b / 12.92f : std::pow((b + 0.055) / 1.055, 2.4);
1771 :
1772 0 : const float X = C0 * r + C1 * g + C2 * b;
1773 0 : const float Y = C3 * r + C4 * g + C5 * b;
1774 0 : const float Z = C6 * r + C7 * g + C8 * b;
1775 :
1776 0 : const float FX = X > _magic ? std::pow(X, _1_3) : (_a * X + _b);
1777 0 : const float FY = Y > _magic ? std::pow(Y, _1_3) : (_a * Y + _b);
1778 0 : const float FZ = Z > _magic ? std::pow(Z, _1_3) : (_a * Z + _b);
1779 :
1780 0 : dstBuffer[0] = 116.0f * FY - 16.0f;
1781 0 : dstBuffer[1] = 500.0f * (FX - FY);
1782 0 : dstBuffer[2] = 200.0f * (FY - FZ);
1783 :
1784 : // Step one pixel.
1785 0 : srcBuffer += aSrcStep;
1786 0 : dstBuffer += 3;
1787 : }
1788 : }
1789 0 : return 0;
1790 : }
1791 :
1792 : // If the destination is a RGB24 or BGR24, set the aAIndex to be 0, 1 or 2,
1793 : // so that the r, g or b value will be set to 255 first than to the right value.
1794 : template<int aRIndex, int aGIndex, int aBIndex, int aAIndex, int aDstStep>
1795 : int
1796 0 : LabToRGBAFamily(const float* aSrcBuffer, int aSrcStride,
1797 : uint8_t* aDstBuffer, int aDstStride,
1798 : int aWidth, int aHeight)
1799 : {
1800 : static_assert(aRIndex == 0 || aRIndex == 2, "Wrong R index.");
1801 : static_assert(aGIndex == 1, "Wrong G index.");
1802 : static_assert(aBIndex == 0 || aBIndex == 2, "Wrong B index.");
1803 : static_assert(aAIndex == 0 || aAIndex == 1 || aAIndex == 2 || aAIndex == 3, "Wrong A index.");
1804 :
1805 0 : const float C0 = XYZTosRGB_D65[0] * whitept_D65[0],
1806 0 : C1 = XYZTosRGB_D65[1] * whitept_D65[1],
1807 0 : C2 = XYZTosRGB_D65[2] * whitept_D65[2],
1808 0 : C3 = XYZTosRGB_D65[3] * whitept_D65[0],
1809 0 : C4 = XYZTosRGB_D65[4] * whitept_D65[1],
1810 0 : C5 = XYZTosRGB_D65[5] * whitept_D65[2],
1811 0 : C6 = XYZTosRGB_D65[6] * whitept_D65[0],
1812 0 : C7 = XYZTosRGB_D65[7] * whitept_D65[1],
1813 0 : C8 = XYZTosRGB_D65[8] * whitept_D65[2];
1814 :
1815 0 : for (int i = 0; i < aHeight; ++i) {
1816 0 : const float* srcBuffer = (const float*)((const uint8_t*)(aSrcBuffer) + aSrcStride * i);
1817 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
1818 :
1819 0 : for (int j = 0; j < aWidth; ++j) {
1820 0 : const float L = srcBuffer[0];
1821 0 : const float a = srcBuffer[1];
1822 0 : const float b = srcBuffer[2];
1823 :
1824 0 : const float FY = (L + 16.0f) / 116.0f;
1825 0 : const float FX = (a / 500.0f) + FY;
1826 0 : const float FZ = FY - (b / 200.0f);
1827 :
1828 0 : const float X = FX > 6.0f / 29.0f ? std::pow((double)FX, 3.0) : 3.0 * std::pow((6.0 / 29.0), 2.0) * (FX - (4.0 / 29.0));
1829 0 : const float Y = FY > 6.0f / 29.0f ? std::pow((double)FY, 3.0) : 3.0 * std::pow((6.0 / 29.0), 2.0) * (FY - (4.0 / 29.0));
1830 0 : const float Z = FZ > 6.0f / 29.0f ? std::pow((double)FZ, 3.0) : 3.0 * std::pow((6.0 / 29.0), 2.0) * (FZ - (4.0 / 29.0));
1831 :
1832 0 : const float r0 = C0 * X + C1 * Y + C2 * Z;
1833 0 : const float g0 = C3 * X + C4 * Y + C5 * Z;
1834 0 : const float b0 = C6 * X + C7 * Y + C8 * Z;
1835 :
1836 : // Apply gamma curve of sRGB to the linear rgb values.
1837 0 : dstBuffer[aAIndex] = 255;
1838 0 : dstBuffer[aRIndex] = Clamp((r0 <= 0.0031308f ? r0 * 12.92f : 1.055 * std::pow((double)r0, 1.0 / 2.4) - 0.055) * 255.0);
1839 0 : dstBuffer[aGIndex] = Clamp((g0 <= 0.0031308f ? g0 * 12.92f : 1.055 * std::pow((double)g0, 1.0 / 2.4) - 0.055) * 255.0);
1840 0 : dstBuffer[aBIndex] = Clamp((b0 <= 0.0031308f ? b0 * 12.92f : 1.055 * std::pow((double)b0, 1.0 / 2.4) - 0.055) * 255.0);
1841 :
1842 : // Step one pixel.
1843 0 : srcBuffer += 3;
1844 0 : dstBuffer += aDstStep;
1845 : }
1846 : }
1847 0 : return 0;
1848 : }
1849 :
1850 : int
1851 0 : RGBA32ToLab(const uint8_t* aSrcBuffer, int aSrcStride,
1852 : float* aDstBuffer, int aDstStride,
1853 : int aWidth, int aHeight)
1854 : {
1855 : return RGBFamilyToLab<0, 1, 2, 4>(aSrcBuffer, aSrcStride,
1856 : aDstBuffer, aDstStride,
1857 0 : aWidth, aHeight);
1858 : }
1859 :
1860 : int
1861 0 : BGRA32ToLab(const uint8_t* aSrcBuffer, int aSrcStride,
1862 : float* aDstBuffer, int aDstStride,
1863 : int aWidth, int aHeight)
1864 : {
1865 : return RGBFamilyToLab<2, 1, 0, 4>(aSrcBuffer, aSrcStride,
1866 : aDstBuffer, aDstStride,
1867 0 : aWidth, aHeight);
1868 : }
1869 :
1870 : int
1871 0 : RGB24ToLab(const uint8_t* aSrcBuffer, int aSrcStride,
1872 : float* aDstBuffer, int aDstStride,
1873 : int aWidth, int aHeight)
1874 : {
1875 : return RGBFamilyToLab<0, 1, 2, 3>(aSrcBuffer, aSrcStride,
1876 : aDstBuffer, aDstStride,
1877 0 : aWidth, aHeight);
1878 : }
1879 :
1880 : int
1881 0 : BGR24ToLab(const uint8_t* aSrcBuffer, int aSrcStride,
1882 : float* aDstBuffer, int aDstStride,
1883 : int aWidth, int aHeight)
1884 : {
1885 : return RGBFamilyToLab<2, 1, 0, 3>(aSrcBuffer, aSrcStride,
1886 : aDstBuffer, aDstStride,
1887 0 : aWidth, aHeight);
1888 : }
1889 :
1890 : int
1891 0 : LabToRGBA32(const float* aSrcBuffer, int aSrcStride,
1892 : uint8_t* aDstBuffer, int aDstStride,
1893 : int aWidth, int aHeight)
1894 : {
1895 : return LabToRGBAFamily<0, 1, 2, 3, 4>(aSrcBuffer, aSrcStride,
1896 : aDstBuffer, aDstStride,
1897 0 : aWidth, aHeight);
1898 : }
1899 :
1900 : int
1901 0 : LabToBGRA32(const float* aSrcBuffer, int aSrcStride,
1902 : uint8_t* aDstBuffer, int aDstStride,
1903 : int aWidth, int aHeight)
1904 : {
1905 : return LabToRGBAFamily<2, 1, 0, 3, 4>(aSrcBuffer, aSrcStride,
1906 : aDstBuffer, aDstStride,
1907 0 : aWidth, aHeight);
1908 : }
1909 :
1910 : int
1911 0 : LabToRGB24(const float* aSrcBuffer, int aSrcStride,
1912 : uint8_t* aDstBuffer, int aDstStride,
1913 : int aWidth, int aHeight)
1914 : {
1915 : return LabToRGBAFamily<0, 1, 2, 0, 3>(aSrcBuffer, aSrcStride,
1916 : aDstBuffer, aDstStride,
1917 0 : aWidth, aHeight);
1918 : }
1919 :
1920 : int
1921 0 : LabToBGR24(const float* aSrcBuffer, int aSrcStride,
1922 : uint8_t* aDstBuffer, int aDstStride,
1923 : int aWidth, int aHeight)
1924 : {
1925 : return LabToRGBAFamily<2, 1, 0, 0, 3>(aSrcBuffer, aSrcStride,
1926 : aDstBuffer, aDstStride,
1927 0 : aWidth, aHeight);
1928 : }
1929 :
1930 : /*
1931 : * RGBA/RGB family -> Gray8.
1932 : * Reference:
1933 : * (1) OpenCV implementation:
1934 : * http://docs.opencv.org/3.1.0/de/d25/imgproc_color_conversions.html
1935 : */
1936 : template<int aRIndex, int aGIndex, int aBIndex, int aSrcStep>
1937 : int
1938 0 : RGBFamilyToGray8(const uint8_t* aSrcBuffer, int aSrcStride,
1939 : uint8_t* aDstBuffer, int aDstStride,
1940 : int aWidth, int aHeight)
1941 : {
1942 : static_assert(aRIndex == 0 || aRIndex == 2, "Wrong R index.");
1943 : static_assert(aGIndex == 1, "Wrong G index.");
1944 : static_assert(aBIndex == 0 || aBIndex == 2, "Wrong B index.");
1945 :
1946 0 : for (int i = 0; i < aHeight; ++i) {
1947 0 : const uint8_t* srcBuffer = aSrcBuffer + aSrcStride * i;
1948 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
1949 :
1950 0 : for (int j = 0; j < aWidth; ++j) {
1951 0 : dstBuffer[j] = 0.299 * srcBuffer[aRIndex] +
1952 0 : 0.587 * srcBuffer[aGIndex] +
1953 0 : 0.114 * srcBuffer[aBIndex];
1954 0 : srcBuffer += aSrcStep;
1955 : }
1956 : }
1957 :
1958 0 : return 0;
1959 : }
1960 :
1961 : int
1962 0 : RGB24ToGray8(const uint8_t* aSrcBuffer, int aSrcStride,
1963 : uint8_t* aDstBuffer, int aDstStride,
1964 : int aWidth, int aHeight)
1965 : {
1966 : return RGBFamilyToGray8<0, 1, 2, 3>(aSrcBuffer, aSrcStride,
1967 : aDstBuffer, aDstStride,
1968 0 : aWidth, aHeight);
1969 : }
1970 :
1971 : int
1972 0 : BGR24ToGray8(const uint8_t* aSrcBuffer, int aSrcStride,
1973 : uint8_t* aDstBuffer, int aDstStride,
1974 : int aWidth, int aHeight)
1975 : {
1976 : return RGBFamilyToGray8<2, 1, 0, 3>(aSrcBuffer, aSrcStride,
1977 : aDstBuffer, aDstStride,
1978 0 : aWidth, aHeight);
1979 : }
1980 :
1981 : int
1982 0 : RGBA32ToGray8(const uint8_t* aSrcBuffer, int aSrcStride,
1983 : uint8_t* aDstBuffer, int aDstStride,
1984 : int aWidth, int aHeight)
1985 : {
1986 : return RGBFamilyToGray8<0, 1, 2, 4>(aSrcBuffer, aSrcStride,
1987 : aDstBuffer, aDstStride,
1988 0 : aWidth, aHeight);
1989 : }
1990 :
1991 : int
1992 0 : BGRA32ToGray8(const uint8_t* aSrcBuffer, int aSrcStride,
1993 : uint8_t* aDstBuffer, int aDstStride,
1994 : int aWidth, int aHeight)
1995 : {
1996 : return RGBFamilyToGray8<2, 1, 0, 4>(aSrcBuffer, aSrcStride,
1997 : aDstBuffer, aDstStride,
1998 0 : aWidth, aHeight);
1999 : }
2000 :
2001 : /*
2002 : * YUV family -> Gray8.
2003 : * Reference:
2004 : * (1) OpenCV implementation:
2005 : * http://docs.opencv.org/3.1.0/de/d25/imgproc_color_conversions.html
2006 : */
2007 : int
2008 0 : YUVFamilyToGray8(const uint8_t* aSrcYBuffer, int aSrcYStride,
2009 : uint8_t* aDstBuffer, int aDstStride,
2010 : int aWidth, int aHeight)
2011 : {
2012 0 : for (int i = 0; i < aHeight; ++i) {
2013 0 : const uint8_t* srcYBuffer = aSrcYBuffer + aSrcYStride * i;
2014 0 : uint8_t* dstBuffer = aDstBuffer + aDstStride * i;
2015 :
2016 0 : memcpy(dstBuffer, srcYBuffer, aDstStride);
2017 : }
2018 :
2019 0 : return 0;
2020 : }
2021 :
2022 : int
2023 0 : YUV444PToGray8(const uint8_t* aYBuffer, int aYStride,
2024 : const uint8_t*, int,
2025 : const uint8_t*, int,
2026 : uint8_t* aDstBuffer, int aDstStride,
2027 : int aWidth, int aHeight)
2028 : {
2029 : return YUVFamilyToGray8(aYBuffer, aYStride,
2030 : aDstBuffer, aDstStride,
2031 0 : aWidth, aHeight);
2032 : }
2033 :
2034 : int
2035 0 : YUV422PToGray8(const uint8_t* aYBuffer, int aYStride,
2036 : const uint8_t*, int,
2037 : const uint8_t*, int,
2038 : uint8_t* aDstBuffer, int aDstStride,
2039 : int aWidth, int aHeight)
2040 : {
2041 : return YUVFamilyToGray8(aYBuffer, aYStride,
2042 : aDstBuffer, aDstStride,
2043 0 : aWidth, aHeight);
2044 : }
2045 :
2046 : int
2047 0 : YUV420PToGray8(const uint8_t* aYBuffer, int aYStride,
2048 : const uint8_t*, int,
2049 : const uint8_t*, int,
2050 : uint8_t* aDstBuffer, int aDstStride,
2051 : int aWidth, int aHeight)
2052 : {
2053 : return YUVFamilyToGray8(aYBuffer, aYStride,
2054 : aDstBuffer, aDstStride,
2055 0 : aWidth, aHeight);
2056 : }
2057 :
2058 : int
2059 0 : NV12ToGray8(const uint8_t* aYBuffer, int aYStride,
2060 : const uint8_t*, int,
2061 : uint8_t* aDstBuffer, int aDstStride,
2062 : int aWidth, int aHeight)
2063 : {
2064 : return YUVFamilyToGray8(aYBuffer, aYStride,
2065 : aDstBuffer, aDstStride,
2066 0 : aWidth, aHeight);
2067 : }
2068 :
2069 : int
2070 0 : NV21ToGray8(const uint8_t* aYBuffer, int aYStride,
2071 : const uint8_t*, int,
2072 : uint8_t* aDstBuffer, int aDstStride,
2073 : int aWidth, int aHeight)
2074 : {
2075 : return YUVFamilyToGray8(aYBuffer, aYStride,
2076 : aDstBuffer, aDstStride,
2077 0 : aWidth, aHeight);
2078 : }
2079 :
2080 : } // namespace dom
2081 : } // namespace mozilla
|