Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(161)

Side by Side Diff: third_party/libwebp/enc/picture_csp.c

Issue 1546003002: libwebp: update to 0.5.0 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase around clang-cl fix Created 4 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 Google Inc. All Rights Reserved. 1 // Copyright 2014 Google Inc. All Rights Reserved.
2 // 2 //
3 // Use of this source code is governed by a BSD-style license 3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the COPYING file in the root of the source 4 // that can be found in the COPYING file in the root of the source
5 // tree. An additional intellectual property rights grant can be found 5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS. All contributing project authors may 6 // in the file PATENTS. All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree. 7 // be found in the AUTHORS file in the root of the source tree.
8 // ----------------------------------------------------------------------------- 8 // -----------------------------------------------------------------------------
9 // 9 //
10 // WebPPicture utils for colorspace conversion 10 // WebPPicture utils for colorspace conversion
(...skipping 14 matching lines...) Expand all
25 25
26 // If defined, use table to compute x / alpha. 26 // If defined, use table to compute x / alpha.
27 #define USE_INVERSE_ALPHA_TABLE 27 #define USE_INVERSE_ALPHA_TABLE
28 28
29 static const union { 29 static const union {
30 uint32_t argb; 30 uint32_t argb;
31 uint8_t bytes[4]; 31 uint8_t bytes[4];
32 } test_endian = { 0xff000000u }; 32 } test_endian = { 0xff000000u };
33 #define ALPHA_IS_LAST (test_endian.bytes[3] == 0xff) 33 #define ALPHA_IS_LAST (test_endian.bytes[3] == 0xff)
34 34
35 static WEBP_INLINE uint32_t MakeARGB32(int a, int r, int g, int b) {
36 return (((uint32_t)a << 24) | (r << 16) | (g << 8) | b);
37 }
38
39 //------------------------------------------------------------------------------ 35 //------------------------------------------------------------------------------
40 // Detection of non-trivial transparency 36 // Detection of non-trivial transparency
41 37
42 // Returns true if alpha[] has non-0xff values. 38 // Returns true if alpha[] has non-0xff values.
43 static int CheckNonOpaque(const uint8_t* alpha, int width, int height, 39 static int CheckNonOpaque(const uint8_t* alpha, int width, int height,
44 int x_step, int y_step) { 40 int x_step, int y_step) {
45 if (alpha == NULL) return 0; 41 if (alpha == NULL) return 0;
46 while (height-- > 0) { 42 while (height-- > 0) {
47 int x; 43 int x;
48 for (x = 0; x < width * x_step; x += x_step) { 44 for (x = 0; x < width * x_step; x += x_step) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
82 #define kGamma 0.80 // for now we use a different gamma value than kGammaF 78 #define kGamma 0.80 // for now we use a different gamma value than kGammaF
83 #define kGammaFix 12 // fixed-point precision for linear values 79 #define kGammaFix 12 // fixed-point precision for linear values
84 #define kGammaScale ((1 << kGammaFix) - 1) 80 #define kGammaScale ((1 << kGammaFix) - 1)
85 #define kGammaTabFix 7 // fixed-point fractional bits precision 81 #define kGammaTabFix 7 // fixed-point fractional bits precision
86 #define kGammaTabScale (1 << kGammaTabFix) 82 #define kGammaTabScale (1 << kGammaTabFix)
87 #define kGammaTabRounder (kGammaTabScale >> 1) 83 #define kGammaTabRounder (kGammaTabScale >> 1)
88 #define kGammaTabSize (1 << (kGammaFix - kGammaTabFix)) 84 #define kGammaTabSize (1 << (kGammaFix - kGammaTabFix))
89 85
90 static int kLinearToGammaTab[kGammaTabSize + 1]; 86 static int kLinearToGammaTab[kGammaTabSize + 1];
91 static uint16_t kGammaToLinearTab[256]; 87 static uint16_t kGammaToLinearTab[256];
92 static int kGammaTablesOk = 0; 88 static volatile int kGammaTablesOk = 0;
93 89
94 static void InitGammaTables(void) { 90 static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTables(void) {
95 if (!kGammaTablesOk) { 91 if (!kGammaTablesOk) {
96 int v; 92 int v;
97 const double scale = (double)(1 << kGammaTabFix) / kGammaScale; 93 const double scale = (double)(1 << kGammaTabFix) / kGammaScale;
98 const double norm = 1. / 255.; 94 const double norm = 1. / 255.;
99 for (v = 0; v <= 255; ++v) { 95 for (v = 0; v <= 255; ++v) {
100 kGammaToLinearTab[v] = 96 kGammaToLinearTab[v] =
101 (uint16_t)(pow(norm * v, kGamma) * kGammaScale + .5); 97 (uint16_t)(pow(norm * v, kGamma) * kGammaScale + .5);
102 } 98 }
103 for (v = 0; v <= kGammaTabSize; ++v) { 99 for (v = 0; v <= kGammaTabSize; ++v) {
104 kLinearToGammaTab[v] = (int)(255. * pow(scale * v, 1. / kGamma) + .5); 100 kLinearToGammaTab[v] = (int)(255. * pow(scale * v, 1. / kGamma) + .5);
(...skipping 18 matching lines...) Expand all
123 119
124 // Convert a linear value 'v' to YUV_FIX+2 fixed-point precision 120 // Convert a linear value 'v' to YUV_FIX+2 fixed-point precision
125 // U/V value, suitable for RGBToU/V calls. 121 // U/V value, suitable for RGBToU/V calls.
126 static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) { 122 static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) {
127 const int y = Interpolate(base_value << shift); // final uplifted value 123 const int y = Interpolate(base_value << shift); // final uplifted value
128 return (y + kGammaTabRounder) >> kGammaTabFix; // descale 124 return (y + kGammaTabRounder) >> kGammaTabFix; // descale
129 } 125 }
130 126
131 #else 127 #else
132 128
133 static void InitGammaTables(void) {} 129 static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTables(void) {}
134 static WEBP_INLINE uint32_t GammaToLinear(uint8_t v) { return v; } 130 static WEBP_INLINE uint32_t GammaToLinear(uint8_t v) { return v; }
135 static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) { 131 static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) {
136 return (int)(base_value << shift); 132 return (int)(base_value << shift);
137 } 133 }
138 134
139 #endif // USE_GAMMA_COMPRESSION 135 #endif // USE_GAMMA_COMPRESSION
140 136
141 //------------------------------------------------------------------------------ 137 //------------------------------------------------------------------------------
142 // RGB -> YUV conversion 138 // RGB -> YUV conversion
143 139
(...skipping 11 matching lines...) Expand all
155 return (rg == NULL) ? VP8RGBToV(r, g, b, YUV_HALF << 2) 151 return (rg == NULL) ? VP8RGBToV(r, g, b, YUV_HALF << 2)
156 : VP8RGBToV(r, g, b, VP8RandomBits(rg, YUV_FIX + 2)); 152 : VP8RGBToV(r, g, b, VP8RandomBits(rg, YUV_FIX + 2));
157 } 153 }
158 154
159 //------------------------------------------------------------------------------ 155 //------------------------------------------------------------------------------
160 // Smart RGB->YUV conversion 156 // Smart RGB->YUV conversion
161 157
162 static const int kNumIterations = 6; 158 static const int kNumIterations = 6;
163 static const int kMinDimensionIterativeConversion = 4; 159 static const int kMinDimensionIterativeConversion = 4;
164 160
165 // We use a-priori a different precision for storing RGB and Y/W components 161 // We could use SFIX=0 and only uint8_t for fixed_y_t, but it produces some
166 // We could use YFIX=0 and only uint8_t for fixed_y_t, but it produces some
167 // banding sometimes. Better use extra precision. 162 // banding sometimes. Better use extra precision.
168 // TODO(skal): cleanup once TFIX/YFIX values are fixed. 163 #define SFIX 2 // fixed-point precision of RGB and Y/W
164 typedef int16_t fixed_t; // signed type with extra SFIX precision for UV
165 typedef uint16_t fixed_y_t; // unsigned type with extra SFIX precision for W
169 166
170 typedef int16_t fixed_t; // signed type with extra TFIX precision for UV 167 #define SHALF (1 << SFIX >> 1)
171 typedef uint16_t fixed_y_t; // unsigned type with extra YFIX precision for W 168 #define MAX_Y_T ((256 << SFIX) - 1)
172 #define TFIX 6 // fixed-point precision of RGB 169 #define SROUNDER (1 << (YUV_FIX + SFIX - 1))
173 #define YFIX 2 // fixed point precision for Y/W
174
175 #define THALF ((1 << TFIX) >> 1)
176 #define MAX_Y_T ((256 << YFIX) - 1)
177 #define TROUNDER (1 << (YUV_FIX + TFIX - 1))
178 170
179 #if defined(USE_GAMMA_COMPRESSION) 171 #if defined(USE_GAMMA_COMPRESSION)
180 172
181 // float variant of gamma-correction 173 // float variant of gamma-correction
182 // We use tables of different size and precision, along with a 'real-world' 174 // We use tables of different size and precision, along with a 'real-world'
183 // Gamma value close to ~2. 175 // Gamma value close to ~2.
184 #define kGammaF 2.2 176 #define kGammaF 2.2
185 static float kGammaToLinearTabF[MAX_Y_T + 1]; // size scales with Y_FIX 177 static float kGammaToLinearTabF[MAX_Y_T + 1]; // size scales with Y_FIX
186 static float kLinearToGammaTabF[kGammaTabSize + 2]; 178 static float kLinearToGammaTabF[kGammaTabSize + 2];
187 static int kGammaTablesFOk = 0; 179 static volatile int kGammaTablesFOk = 0;
188 180
189 static void InitGammaTablesF(void) { 181 static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTablesF(void) {
190 if (!kGammaTablesFOk) { 182 if (!kGammaTablesFOk) {
191 int v; 183 int v;
192 const double norm = 1. / MAX_Y_T; 184 const double norm = 1. / MAX_Y_T;
193 const double scale = 1. / kGammaTabSize; 185 const double scale = 1. / kGammaTabSize;
194 for (v = 0; v <= MAX_Y_T; ++v) { 186 for (v = 0; v <= MAX_Y_T; ++v) {
195 kGammaToLinearTabF[v] = (float)pow(norm * v, kGammaF); 187 kGammaToLinearTabF[v] = (float)pow(norm * v, kGammaF);
196 } 188 }
197 for (v = 0; v <= kGammaTabSize; ++v) { 189 for (v = 0; v <= kGammaTabSize; ++v) {
198 kLinearToGammaTabF[v] = (float)(MAX_Y_T * pow(scale * v, 1. / kGammaF)); 190 kLinearToGammaTabF[v] = (float)(MAX_Y_T * pow(scale * v, 1. / kGammaF));
199 } 191 }
200 // to prevent small rounding errors to cause read-overflow: 192 // to prevent small rounding errors to cause read-overflow:
201 kLinearToGammaTabF[kGammaTabSize + 1] = kLinearToGammaTabF[kGammaTabSize]; 193 kLinearToGammaTabF[kGammaTabSize + 1] = kLinearToGammaTabF[kGammaTabSize];
202 kGammaTablesFOk = 1; 194 kGammaTablesFOk = 1;
203 } 195 }
204 } 196 }
205 197
206 static WEBP_INLINE float GammaToLinearF(int v) { 198 static WEBP_INLINE float GammaToLinearF(int v) {
207 return kGammaToLinearTabF[v]; 199 return kGammaToLinearTabF[v];
208 } 200 }
209 201
210 static WEBP_INLINE float LinearToGammaF(float value) { 202 static WEBP_INLINE int LinearToGammaF(float value) {
211 const float v = value * kGammaTabSize; 203 const float v = value * kGammaTabSize;
212 const int tab_pos = (int)v; 204 const int tab_pos = (int)v;
213 const float x = v - (float)tab_pos; // fractional part 205 const float x = v - (float)tab_pos; // fractional part
214 const float v0 = kLinearToGammaTabF[tab_pos + 0]; 206 const float v0 = kLinearToGammaTabF[tab_pos + 0];
215 const float v1 = kLinearToGammaTabF[tab_pos + 1]; 207 const float v1 = kLinearToGammaTabF[tab_pos + 1];
216 const float y = v1 * x + v0 * (1.f - x); // interpolate 208 const float y = v1 * x + v0 * (1.f - x); // interpolate
217 return y; 209 return (int)(y + .5);
218 } 210 }
219 211
220 #else 212 #else
221 213
222 static void InitGammaTablesF(void) {} 214 static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTablesF(void) {}
223 static WEBP_INLINE float GammaToLinearF(int v) { 215 static WEBP_INLINE float GammaToLinearF(int v) {
224 const float norm = 1.f / MAX_Y_T; 216 const float norm = 1.f / MAX_Y_T;
225 return norm * v; 217 return norm * v;
226 } 218 }
227 static WEBP_INLINE float LinearToGammaF(float value) { 219 static WEBP_INLINE int LinearToGammaF(float value) {
228 return MAX_Y_T * value; 220 return (int)(MAX_Y_T * value + .5);
229 } 221 }
230 222
231 #endif // USE_GAMMA_COMPRESSION 223 #endif // USE_GAMMA_COMPRESSION
232 224
233 //------------------------------------------------------------------------------ 225 //------------------------------------------------------------------------------
234 226
235 // precision: YFIX -> TFIX
236 static WEBP_INLINE int FixedYToW(int v) {
237 #if TFIX == YFIX
238 return v;
239 #elif TFIX >= YFIX
240 return v << (TFIX - YFIX);
241 #else
242 return v >> (YFIX - TFIX);
243 #endif
244 }
245
246 static WEBP_INLINE int FixedWToY(int v) {
247 #if TFIX == YFIX
248 return v;
249 #elif YFIX >= TFIX
250 return v << (YFIX - TFIX);
251 #else
252 return v >> (TFIX - YFIX);
253 #endif
254 }
255
256 static uint8_t clip_8b(fixed_t v) { 227 static uint8_t clip_8b(fixed_t v) {
257 return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u; 228 return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u;
258 } 229 }
259 230
260 static fixed_y_t clip_y(int y) { 231 static fixed_y_t clip_y(int y) {
261 return (!(y & ~MAX_Y_T)) ? (fixed_y_t)y : (y < 0) ? 0 : MAX_Y_T; 232 return (!(y & ~MAX_Y_T)) ? (fixed_y_t)y : (y < 0) ? 0 : MAX_Y_T;
262 } 233 }
263 234
264 // precision: TFIX -> YFIX
265 static fixed_y_t clip_fixed_t(fixed_t v) {
266 const int y = FixedWToY(v);
267 const fixed_y_t w = clip_y(y);
268 return w;
269 }
270
271 //------------------------------------------------------------------------------ 235 //------------------------------------------------------------------------------
272 236
273 static int RGBToGray(int r, int g, int b) { 237 static int RGBToGray(int r, int g, int b) {
274 const int luma = 19595 * r + 38470 * g + 7471 * b + YUV_HALF; 238 const int luma = 19595 * r + 38470 * g + 7471 * b + YUV_HALF;
275 return (luma >> YUV_FIX); 239 return (luma >> YUV_FIX);
276 } 240 }
277 241
278 static float RGBToGrayF(float r, float g, float b) { 242 static float RGBToGrayF(float r, float g, float b) {
279 return 0.299f * r + 0.587f * g + 0.114f * b; 243 return 0.299f * r + 0.587f * g + 0.114f * b;
280 } 244 }
281 245
282 static float ScaleDown(int a, int b, int c, int d) { 246 static int ScaleDown(int a, int b, int c, int d) {
283 const float A = GammaToLinearF(a); 247 const float A = GammaToLinearF(a);
284 const float B = GammaToLinearF(b); 248 const float B = GammaToLinearF(b);
285 const float C = GammaToLinearF(c); 249 const float C = GammaToLinearF(c);
286 const float D = GammaToLinearF(d); 250 const float D = GammaToLinearF(d);
287 return LinearToGammaF(0.25f * (A + B + C + D)); 251 return LinearToGammaF(0.25f * (A + B + C + D));
288 } 252 }
289 253
290 static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int len) { 254 static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int len) {
291 while (len-- > 0) { 255 while (len-- > 0) {
292 const float R = GammaToLinearF(src[0]); 256 const float R = GammaToLinearF(src[0]);
293 const float G = GammaToLinearF(src[1]); 257 const float G = GammaToLinearF(src[1]);
294 const float B = GammaToLinearF(src[2]); 258 const float B = GammaToLinearF(src[2]);
295 const float Y = RGBToGrayF(R, G, B); 259 const float Y = RGBToGrayF(R, G, B);
296 *dst++ = (fixed_y_t)(LinearToGammaF(Y) + .5); 260 *dst++ = (fixed_y_t)LinearToGammaF(Y);
297 src += 3; 261 src += 3;
298 } 262 }
299 } 263 }
300 264
301 static WEBP_INLINE void UpdateChroma(const fixed_y_t* src1, 265 static int UpdateChroma(const fixed_y_t* src1,
302 const fixed_y_t* src2, 266 const fixed_y_t* src2,
303 fixed_t* dst, fixed_y_t* tmp, int len) { 267 fixed_t* dst, fixed_y_t* tmp, int len) {
268 int diff = 0;
304 while (len--> 0) { 269 while (len--> 0) {
305 const float r = ScaleDown(src1[0], src1[3], src2[0], src2[3]); 270 const int r = ScaleDown(src1[0], src1[3], src2[0], src2[3]);
306 const float g = ScaleDown(src1[1], src1[4], src2[1], src2[4]); 271 const int g = ScaleDown(src1[1], src1[4], src2[1], src2[4]);
307 const float b = ScaleDown(src1[2], src1[5], src2[2], src2[5]); 272 const int b = ScaleDown(src1[2], src1[5], src2[2], src2[5]);
308 const float W = RGBToGrayF(r, g, b); 273 const int W = RGBToGray(r, g, b);
309 dst[0] = (fixed_t)FixedYToW((int)(r - W)); 274 const int r_avg = (src1[0] + src1[3] + src2[0] + src2[3] + 2) >> 2;
310 dst[1] = (fixed_t)FixedYToW((int)(g - W)); 275 const int g_avg = (src1[1] + src1[4] + src2[1] + src2[4] + 2) >> 2;
311 dst[2] = (fixed_t)FixedYToW((int)(b - W)); 276 const int b_avg = (src1[2] + src1[5] + src2[2] + src2[5] + 2) >> 2;
277 dst[0] = (fixed_t)(r - W);
278 dst[1] = (fixed_t)(g - W);
279 dst[2] = (fixed_t)(b - W);
312 dst += 3; 280 dst += 3;
313 src1 += 6; 281 src1 += 6;
314 src2 += 6; 282 src2 += 6;
315 if (tmp != NULL) { 283 if (tmp != NULL) {
316 tmp[0] = tmp[1] = clip_y((int)(W + .5)); 284 tmp[0] = tmp[1] = clip_y(W);
317 tmp += 2; 285 tmp += 2;
318 } 286 }
287 diff += abs(RGBToGray(r_avg, g_avg, b_avg) - W);
319 } 288 }
289 return diff;
320 } 290 }
321 291
322 //------------------------------------------------------------------------------ 292 //------------------------------------------------------------------------------
323 293
324 static WEBP_INLINE int Filter(const fixed_t* const A, const fixed_t* const B, 294 static WEBP_INLINE int Filter(const fixed_t* const A, const fixed_t* const B,
325 int rightwise) { 295 int rightwise) {
326 int v; 296 int v;
327 if (!rightwise) { 297 if (!rightwise) {
328 v = (A[0] * 9 + A[-3] * 3 + B[0] * 3 + B[-3]); 298 v = (A[0] * 9 + A[-3] * 3 + B[0] * 3 + B[-3]);
329 } else { 299 } else {
330 v = (A[0] * 9 + A[+3] * 3 + B[0] * 3 + B[+3]); 300 v = (A[0] * 9 + A[+3] * 3 + B[0] * 3 + B[+3]);
331 } 301 }
332 return (v + 8) >> 4; 302 return (v + 8) >> 4;
333 } 303 }
334 304
335 static WEBP_INLINE int Filter2(int A, int B) { return (A * 3 + B + 2) >> 2; } 305 static WEBP_INLINE int Filter2(int A, int B) { return (A * 3 + B + 2) >> 2; }
336 306
337 //------------------------------------------------------------------------------ 307 //------------------------------------------------------------------------------
338 308
339 // 8bit -> YFIX 309 static WEBP_INLINE fixed_y_t UpLift(uint8_t a) { // 8bit -> SFIX
340 static WEBP_INLINE fixed_y_t UpLift(uint8_t a) { 310 return ((fixed_y_t)a << SFIX) | SHALF;
341 return ((fixed_y_t)a << YFIX) | (1 << (YFIX - 1));
342 } 311 }
343 312
344 static void ImportOneRow(const uint8_t* const r_ptr, 313 static void ImportOneRow(const uint8_t* const r_ptr,
345 const uint8_t* const g_ptr, 314 const uint8_t* const g_ptr,
346 const uint8_t* const b_ptr, 315 const uint8_t* const b_ptr,
347 int step, 316 int step,
348 int pic_width, 317 int pic_width,
349 fixed_y_t* const dst) { 318 fixed_y_t* const dst) {
350 int i; 319 int i;
351 for (i = 0; i < pic_width; ++i) { 320 for (i = 0; i < pic_width; ++i) {
352 const int off = i * step; 321 const int off = i * step;
353 dst[3 * i + 0] = UpLift(r_ptr[off]); 322 dst[3 * i + 0] = UpLift(r_ptr[off]);
354 dst[3 * i + 1] = UpLift(g_ptr[off]); 323 dst[3 * i + 1] = UpLift(g_ptr[off]);
355 dst[3 * i + 2] = UpLift(b_ptr[off]); 324 dst[3 * i + 2] = UpLift(b_ptr[off]);
356 } 325 }
357 if (pic_width & 1) { // replicate rightmost pixel 326 if (pic_width & 1) { // replicate rightmost pixel
358 memcpy(dst + 3 * pic_width, dst + 3 * (pic_width - 1), 3 * sizeof(*dst)); 327 memcpy(dst + 3 * pic_width, dst + 3 * (pic_width - 1), 3 * sizeof(*dst));
359 } 328 }
360 } 329 }
361 330
362 static void InterpolateTwoRows(const fixed_y_t* const best_y, 331 static void InterpolateTwoRows(const fixed_y_t* const best_y,
363 const fixed_t* const prev_uv, 332 const fixed_t* const prev_uv,
364 const fixed_t* const cur_uv, 333 const fixed_t* const cur_uv,
365 const fixed_t* const next_uv, 334 const fixed_t* const next_uv,
366 int w, 335 int w,
367 fixed_y_t* const out1, 336 fixed_y_t* const out1,
368 fixed_y_t* const out2) { 337 fixed_y_t* const out2) {
369 int i, k; 338 int i, k;
370 { // special boundary case for i==0 339 { // special boundary case for i==0
371 const int W0 = FixedYToW(best_y[0]); 340 const int W0 = best_y[0];
372 const int W1 = FixedYToW(best_y[w]); 341 const int W1 = best_y[w];
373 for (k = 0; k <= 2; ++k) { 342 for (k = 0; k <= 2; ++k) {
374 out1[k] = clip_fixed_t(Filter2(cur_uv[k], prev_uv[k]) + W0); 343 out1[k] = clip_y(Filter2(cur_uv[k], prev_uv[k]) + W0);
375 out2[k] = clip_fixed_t(Filter2(cur_uv[k], next_uv[k]) + W1); 344 out2[k] = clip_y(Filter2(cur_uv[k], next_uv[k]) + W1);
376 } 345 }
377 } 346 }
378 for (i = 1; i < w - 1; ++i) { 347 for (i = 1; i < w - 1; ++i) {
379 const int W0 = FixedYToW(best_y[i + 0]); 348 const int W0 = best_y[i + 0];
380 const int W1 = FixedYToW(best_y[i + w]); 349 const int W1 = best_y[i + w];
381 const int off = 3 * (i >> 1); 350 const int off = 3 * (i >> 1);
382 for (k = 0; k <= 2; ++k) { 351 for (k = 0; k <= 2; ++k) {
383 const int tmp0 = Filter(cur_uv + off + k, prev_uv + off + k, i & 1); 352 const int tmp0 = Filter(cur_uv + off + k, prev_uv + off + k, i & 1);
384 const int tmp1 = Filter(cur_uv + off + k, next_uv + off + k, i & 1); 353 const int tmp1 = Filter(cur_uv + off + k, next_uv + off + k, i & 1);
385 out1[3 * i + k] = clip_fixed_t(tmp0 + W0); 354 out1[3 * i + k] = clip_y(tmp0 + W0);
386 out2[3 * i + k] = clip_fixed_t(tmp1 + W1); 355 out2[3 * i + k] = clip_y(tmp1 + W1);
387 } 356 }
388 } 357 }
389 { // special boundary case for i == w - 1 358 { // special boundary case for i == w - 1
390 const int W0 = FixedYToW(best_y[i + 0]); 359 const int W0 = best_y[i + 0];
391 const int W1 = FixedYToW(best_y[i + w]); 360 const int W1 = best_y[i + w];
392 const int off = 3 * (i >> 1); 361 const int off = 3 * (i >> 1);
393 for (k = 0; k <= 2; ++k) { 362 for (k = 0; k <= 2; ++k) {
394 out1[3 * i + k] = 363 out1[3 * i + k] = clip_y(Filter2(cur_uv[off + k], prev_uv[off + k]) + W0);
395 clip_fixed_t(Filter2(cur_uv[off + k], prev_uv[off + k]) + W0); 364 out2[3 * i + k] = clip_y(Filter2(cur_uv[off + k], next_uv[off + k]) + W1);
396 out2[3 * i + k] =
397 clip_fixed_t(Filter2(cur_uv[off + k], next_uv[off + k]) + W1);
398 } 365 }
399 } 366 }
400 } 367 }
401 368
402 static WEBP_INLINE uint8_t ConvertRGBToY(int r, int g, int b) { 369 static WEBP_INLINE uint8_t ConvertRGBToY(int r, int g, int b) {
403 const int luma = 16839 * r + 33059 * g + 6420 * b + TROUNDER; 370 const int luma = 16839 * r + 33059 * g + 6420 * b + SROUNDER;
404 return clip_8b(16 + (luma >> (YUV_FIX + TFIX))); 371 return clip_8b(16 + (luma >> (YUV_FIX + SFIX)));
405 } 372 }
406 373
407 static WEBP_INLINE uint8_t ConvertRGBToU(int r, int g, int b) { 374 static WEBP_INLINE uint8_t ConvertRGBToU(int r, int g, int b) {
408 const int u = -9719 * r - 19081 * g + 28800 * b + TROUNDER; 375 const int u = -9719 * r - 19081 * g + 28800 * b + SROUNDER;
409 return clip_8b(128 + (u >> (YUV_FIX + TFIX))); 376 return clip_8b(128 + (u >> (YUV_FIX + SFIX)));
410 } 377 }
411 378
412 static WEBP_INLINE uint8_t ConvertRGBToV(int r, int g, int b) { 379 static WEBP_INLINE uint8_t ConvertRGBToV(int r, int g, int b) {
413 const int v = +28800 * r - 24116 * g - 4684 * b + TROUNDER; 380 const int v = +28800 * r - 24116 * g - 4684 * b + SROUNDER;
414 return clip_8b(128 + (v >> (YUV_FIX + TFIX))); 381 return clip_8b(128 + (v >> (YUV_FIX + SFIX)));
415 } 382 }
416 383
417 static int ConvertWRGBToYUV(const fixed_y_t* const best_y, 384 static int ConvertWRGBToYUV(const fixed_y_t* const best_y,
418 const fixed_t* const best_uv, 385 const fixed_t* const best_uv,
419 WebPPicture* const picture) { 386 WebPPicture* const picture) {
420 int i, j; 387 int i, j;
421 const int w = (picture->width + 1) & ~1; 388 const int w = (picture->width + 1) & ~1;
422 const int h = (picture->height + 1) & ~1; 389 const int h = (picture->height + 1) & ~1;
423 const int uv_w = w >> 1; 390 const int uv_w = w >> 1;
424 const int uv_h = h >> 1; 391 const int uv_h = h >> 1;
425 for (j = 0; j < picture->height; ++j) { 392 for (j = 0; j < picture->height; ++j) {
426 for (i = 0; i < picture->width; ++i) { 393 for (i = 0; i < picture->width; ++i) {
427 const int off = 3 * ((i >> 1) + (j >> 1) * uv_w); 394 const int off = 3 * ((i >> 1) + (j >> 1) * uv_w);
428 const int off2 = i + j * picture->y_stride; 395 const int off2 = i + j * picture->y_stride;
429 const int W = FixedYToW(best_y[i + j * w]); 396 const int W = best_y[i + j * w];
430 const int r = best_uv[off + 0] + W; 397 const int r = best_uv[off + 0] + W;
431 const int g = best_uv[off + 1] + W; 398 const int g = best_uv[off + 1] + W;
432 const int b = best_uv[off + 2] + W; 399 const int b = best_uv[off + 2] + W;
433 picture->y[off2] = ConvertRGBToY(r, g, b); 400 picture->y[off2] = ConvertRGBToY(r, g, b);
434 } 401 }
435 } 402 }
436 for (j = 0; j < uv_h; ++j) { 403 for (j = 0; j < uv_h; ++j) {
437 uint8_t* const dst_u = picture->u + j * picture->uv_stride; 404 uint8_t* const dst_u = picture->u + j * picture->uv_stride;
438 uint8_t* const dst_v = picture->v + j * picture->uv_stride; 405 uint8_t* const dst_v = picture->v + j * picture->uv_stride;
439 for (i = 0; i < uv_w; ++i) { 406 for (i = 0; i < uv_w; ++i) {
(...skipping 28 matching lines...) Expand all
468 // TODO(skal): allocate one big memory chunk. But for now, it's easier 435 // TODO(skal): allocate one big memory chunk. But for now, it's easier
469 // for valgrind debugging to have several chunks. 436 // for valgrind debugging to have several chunks.
470 fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch 437 fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch
471 fixed_y_t* const best_y = SAFE_ALLOC(w, h, fixed_y_t); 438 fixed_y_t* const best_y = SAFE_ALLOC(w, h, fixed_y_t);
472 fixed_y_t* const target_y = SAFE_ALLOC(w, h, fixed_y_t); 439 fixed_y_t* const target_y = SAFE_ALLOC(w, h, fixed_y_t);
473 fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t); 440 fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t);
474 fixed_t* const best_uv = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); 441 fixed_t* const best_uv = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
475 fixed_t* const target_uv = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); 442 fixed_t* const target_uv = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
476 fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t); 443 fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t);
477 int ok; 444 int ok;
445 int diff_sum = 0;
446 const int first_diff_threshold = (int)(2.5 * w * h);
447 const int min_improvement = 5; // stop if improvement is below this %
448 const int min_first_improvement = 80;
478 449
479 if (best_y == NULL || best_uv == NULL || 450 if (best_y == NULL || best_uv == NULL ||
480 target_y == NULL || target_uv == NULL || 451 target_y == NULL || target_uv == NULL ||
481 best_rgb_y == NULL || best_rgb_uv == NULL || 452 best_rgb_y == NULL || best_rgb_uv == NULL ||
482 tmp_buffer == NULL) { 453 tmp_buffer == NULL) {
483 ok = WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); 454 ok = WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
484 goto End; 455 goto End;
485 } 456 }
486 assert(picture->width >= kMinDimensionIterativeConversion); 457 assert(picture->width >= kMinDimensionIterativeConversion);
487 assert(picture->height >= kMinDimensionIterativeConversion); 458 assert(picture->height >= kMinDimensionIterativeConversion);
(...skipping 12 matching lines...) Expand all
500 ImportOneRow(r_ptr + off1, g_ptr + off1, b_ptr + off1, 471 ImportOneRow(r_ptr + off1, g_ptr + off1, b_ptr + off1,
501 step, picture->width, src1); 472 step, picture->width, src1);
502 if (!is_last_row) { 473 if (!is_last_row) {
503 ImportOneRow(r_ptr + off2, g_ptr + off2, b_ptr + off2, 474 ImportOneRow(r_ptr + off2, g_ptr + off2, b_ptr + off2,
504 step, picture->width, src2); 475 step, picture->width, src2);
505 } else { 476 } else {
506 memcpy(src2, src1, 3 * w * sizeof(*src2)); 477 memcpy(src2, src1, 3 * w * sizeof(*src2));
507 } 478 }
508 UpdateW(src1, target_y + (j + 0) * w, w); 479 UpdateW(src1, target_y + (j + 0) * w, w);
509 UpdateW(src2, target_y + (j + 1) * w, w); 480 UpdateW(src2, target_y + (j + 1) * w, w);
510 UpdateChroma(src1, src2, target_uv + uv_off, dst_y, uv_w); 481 diff_sum += UpdateChroma(src1, src2, target_uv + uv_off, dst_y, uv_w);
511 memcpy(best_uv + uv_off, target_uv + uv_off, 3 * uv_w * sizeof(*best_uv)); 482 memcpy(best_uv + uv_off, target_uv + uv_off, 3 * uv_w * sizeof(*best_uv));
512 memcpy(dst_y + w, dst_y, w * sizeof(*dst_y)); 483 memcpy(dst_y + w, dst_y, w * sizeof(*dst_y));
513 } 484 }
514 485
515 // Iterate and resolve clipping conflicts. 486 // Iterate and resolve clipping conflicts.
516 for (iter = 0; iter < kNumIterations; ++iter) { 487 for (iter = 0; iter < kNumIterations; ++iter) {
517 int k; 488 int k;
518 const fixed_t* cur_uv = best_uv; 489 const fixed_t* cur_uv = best_uv;
519 const fixed_t* prev_uv = best_uv; 490 const fixed_t* prev_uv = best_uv;
491 const int old_diff_sum = diff_sum;
492 diff_sum = 0;
520 for (j = 0; j < h; j += 2) { 493 for (j = 0; j < h; j += 2) {
521 fixed_y_t* const src1 = tmp_buffer; 494 fixed_y_t* const src1 = tmp_buffer;
522 fixed_y_t* const src2 = tmp_buffer + 3 * w; 495 fixed_y_t* const src2 = tmp_buffer + 3 * w;
523
524 { 496 {
525 const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0); 497 const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0);
526 InterpolateTwoRows(best_y + j * w, prev_uv, cur_uv, next_uv, 498 InterpolateTwoRows(best_y + j * w, prev_uv, cur_uv, next_uv,
527 w, src1, src2); 499 w, src1, src2);
528 prev_uv = cur_uv; 500 prev_uv = cur_uv;
529 cur_uv = next_uv; 501 cur_uv = next_uv;
530 } 502 }
531 503
532 UpdateW(src1, best_rgb_y + 0 * w, w); 504 UpdateW(src1, best_rgb_y + 0 * w, w);
533 UpdateW(src2, best_rgb_y + 1 * w, w); 505 UpdateW(src2, best_rgb_y + 1 * w, w);
534 UpdateChroma(src1, src2, best_rgb_uv, NULL, uv_w); 506 diff_sum += UpdateChroma(src1, src2, best_rgb_uv, NULL, uv_w);
535 507
536 // update two rows of Y and one row of RGB 508 // update two rows of Y and one row of RGB
537 for (i = 0; i < 2 * w; ++i) { 509 for (i = 0; i < 2 * w; ++i) {
538 const int off = i + j * w; 510 const int off = i + j * w;
539 const int diff_y = target_y[off] - best_rgb_y[i]; 511 const int diff_y = target_y[off] - best_rgb_y[i];
540 const int new_y = (int)best_y[off] + diff_y; 512 const int new_y = (int)best_y[off] + diff_y;
541 best_y[off] = clip_y(new_y); 513 best_y[off] = clip_y(new_y);
542 } 514 }
543 for (i = 0; i < uv_w; ++i) { 515 for (i = 0; i < uv_w; ++i) {
544 const int off = 3 * (i + (j >> 1) * uv_w); 516 const int off = 3 * (i + (j >> 1) * uv_w);
545 int W; 517 int W;
546 for (k = 0; k <= 2; ++k) { 518 for (k = 0; k <= 2; ++k) {
547 const int diff_uv = (int)target_uv[off + k] - best_rgb_uv[3 * i + k]; 519 const int diff_uv = (int)target_uv[off + k] - best_rgb_uv[3 * i + k];
548 best_uv[off + k] += diff_uv; 520 best_uv[off + k] += diff_uv;
549 } 521 }
550 W = RGBToGray(best_uv[off + 0], best_uv[off + 1], best_uv[off + 2]); 522 W = RGBToGray(best_uv[off + 0], best_uv[off + 1], best_uv[off + 2]);
551 for (k = 0; k <= 2; ++k) { 523 for (k = 0; k <= 2; ++k) {
552 best_uv[off + k] -= W; 524 best_uv[off + k] -= W;
553 } 525 }
554 } 526 }
555 } 527 }
556 // TODO(skal): add early-termination criterion 528 // test exit condition
529 if (diff_sum > 0) {
530 const int improvement = 100 * abs(diff_sum - old_diff_sum) / diff_sum;
531 // Check if first iteration gave good result already, without a large
532 // jump of improvement (otherwise it means we need to try few extra
533 // iterations, just to be sure).
534 if (iter == 0 && diff_sum < first_diff_threshold &&
535 improvement < min_first_improvement) {
536 break;
537 }
538 // then, check if improvement is stalling.
539 if (improvement < min_improvement) {
540 break;
541 }
542 } else {
543 break;
544 }
557 } 545 }
558 546
559 // final reconstruction 547 // final reconstruction
560 ok = ConvertWRGBToYUV(best_y, best_uv, picture); 548 ok = ConvertWRGBToYUV(best_y, best_uv, picture);
561 549
562 End: 550 End:
563 WebPSafeFree(best_y); 551 WebPSafeFree(best_y);
564 WebPSafeFree(best_uv); 552 WebPSafeFree(best_uv);
565 WebPSafeFree(target_y); 553 WebPSafeFree(target_y);
566 WebPSafeFree(target_uv); 554 WebPSafeFree(target_uv);
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
755 } 743 }
756 744
757 static WEBP_INLINE void ConvertRowToY(const uint8_t* const r_ptr, 745 static WEBP_INLINE void ConvertRowToY(const uint8_t* const r_ptr,
758 const uint8_t* const g_ptr, 746 const uint8_t* const g_ptr,
759 const uint8_t* const b_ptr, 747 const uint8_t* const b_ptr,
760 int step, 748 int step,
761 uint8_t* const dst_y, 749 uint8_t* const dst_y,
762 int width, 750 int width,
763 VP8Random* const rg) { 751 VP8Random* const rg) {
764 int i, j; 752 int i, j;
765 for (i = 0, j = 0; i < width; ++i, j += step) { 753 for (i = 0, j = 0; i < width; i += 1, j += step) {
766 dst_y[i] = RGBToY(r_ptr[j], g_ptr[j], b_ptr[j], rg); 754 dst_y[i] = RGBToY(r_ptr[j], g_ptr[j], b_ptr[j], rg);
767 } 755 }
768 } 756 }
769 757
770 static WEBP_INLINE void ConvertRowsToUVWithAlpha(const uint8_t* const r_ptr, 758 static WEBP_INLINE void AccumulateRGBA(const uint8_t* const r_ptr,
771 const uint8_t* const g_ptr, 759 const uint8_t* const g_ptr,
772 const uint8_t* const b_ptr, 760 const uint8_t* const b_ptr,
773 const uint8_t* const a_ptr, 761 const uint8_t* const a_ptr,
774 int rgb_stride, 762 int rgb_stride,
775 uint8_t* const dst_u, 763 uint16_t* dst, int width) {
776 uint8_t* const dst_v,
777 int width,
778 VP8Random* const rg) {
779 int i, j; 764 int i, j;
780 // we loop over 2x2 blocks and produce one U/V value for each. 765 // we loop over 2x2 blocks and produce one R/G/B/A value for each.
781 for (i = 0, j = 0; i < (width >> 1); ++i, j += 2 * sizeof(uint32_t)) { 766 for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2 * 4, dst += 4) {
782 const uint32_t a = SUM4ALPHA(a_ptr + j); 767 const uint32_t a = SUM4ALPHA(a_ptr + j);
783 int r, g, b; 768 int r, g, b;
784 if (a == 4 * 0xff || a == 0) { 769 if (a == 4 * 0xff || a == 0) {
785 r = SUM4(r_ptr + j, 4); 770 r = SUM4(r_ptr + j, 4);
786 g = SUM4(g_ptr + j, 4); 771 g = SUM4(g_ptr + j, 4);
787 b = SUM4(b_ptr + j, 4); 772 b = SUM4(b_ptr + j, 4);
788 } else { 773 } else {
789 r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 4, rgb_stride); 774 r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 4, rgb_stride);
790 g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 4, rgb_stride); 775 g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 4, rgb_stride);
791 b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 4, rgb_stride); 776 b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 4, rgb_stride);
792 } 777 }
793 dst_u[i] = RGBToU(r, g, b, rg); 778 dst[0] = r;
794 dst_v[i] = RGBToV(r, g, b, rg); 779 dst[1] = g;
780 dst[2] = b;
781 dst[3] = a;
795 } 782 }
796 if (width & 1) { 783 if (width & 1) {
797 const uint32_t a = 2u * SUM2ALPHA(a_ptr + j); 784 const uint32_t a = 2u * SUM2ALPHA(a_ptr + j);
798 int r, g, b; 785 int r, g, b;
799 if (a == 4 * 0xff || a == 0) { 786 if (a == 4 * 0xff || a == 0) {
800 r = SUM2(r_ptr + j); 787 r = SUM2(r_ptr + j);
801 g = SUM2(g_ptr + j); 788 g = SUM2(g_ptr + j);
802 b = SUM2(b_ptr + j); 789 b = SUM2(b_ptr + j);
803 } else { 790 } else {
804 r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 0, rgb_stride); 791 r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 0, rgb_stride);
805 g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 0, rgb_stride); 792 g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 0, rgb_stride);
806 b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 0, rgb_stride); 793 b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 0, rgb_stride);
807 } 794 }
808 dst_u[i] = RGBToU(r, g, b, rg); 795 dst[0] = r;
809 dst_v[i] = RGBToV(r, g, b, rg); 796 dst[1] = g;
797 dst[2] = b;
798 dst[3] = a;
810 } 799 }
811 } 800 }
812 801
813 static WEBP_INLINE void ConvertRowsToUV(const uint8_t* const r_ptr, 802 static WEBP_INLINE void AccumulateRGB(const uint8_t* const r_ptr,
814 const uint8_t* const g_ptr, 803 const uint8_t* const g_ptr,
815 const uint8_t* const b_ptr, 804 const uint8_t* const b_ptr,
816 int step, int rgb_stride, 805 int step, int rgb_stride,
806 uint16_t* dst, int width) {
807 int i, j;
808 for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2 * step, dst += 4) {
809 dst[0] = SUM4(r_ptr + j, step);
810 dst[1] = SUM4(g_ptr + j, step);
811 dst[2] = SUM4(b_ptr + j, step);
812 }
813 if (width & 1) {
814 dst[0] = SUM2(r_ptr + j);
815 dst[1] = SUM2(g_ptr + j);
816 dst[2] = SUM2(b_ptr + j);
817 }
818 }
819
820 static WEBP_INLINE void ConvertRowsToUV(const uint16_t* rgb,
817 uint8_t* const dst_u, 821 uint8_t* const dst_u,
818 uint8_t* const dst_v, 822 uint8_t* const dst_v,
819 int width, 823 int width,
820 VP8Random* const rg) { 824 VP8Random* const rg) {
821 int i, j; 825 int i;
822 for (i = 0, j = 0; i < (width >> 1); ++i, j += 2 * step) { 826 for (i = 0; i < width; i += 1, rgb += 4) {
823 const int r = SUM4(r_ptr + j, step); 827 const int r = rgb[0], g = rgb[1], b = rgb[2];
824 const int g = SUM4(g_ptr + j, step);
825 const int b = SUM4(b_ptr + j, step);
826 dst_u[i] = RGBToU(r, g, b, rg); 828 dst_u[i] = RGBToU(r, g, b, rg);
827 dst_v[i] = RGBToV(r, g, b, rg); 829 dst_v[i] = RGBToV(r, g, b, rg);
828 } 830 }
829 if (width & 1) {
830 const int r = SUM2(r_ptr + j);
831 const int g = SUM2(g_ptr + j);
832 const int b = SUM2(b_ptr + j);
833 dst_u[i] = RGBToU(r, g, b, rg);
834 dst_v[i] = RGBToV(r, g, b, rg);
835 }
836 } 831 }
837 832
838 static int ImportYUVAFromRGBA(const uint8_t* const r_ptr, 833 static int ImportYUVAFromRGBA(const uint8_t* const r_ptr,
839 const uint8_t* const g_ptr, 834 const uint8_t* const g_ptr,
840 const uint8_t* const b_ptr, 835 const uint8_t* const b_ptr,
841 const uint8_t* const a_ptr, 836 const uint8_t* const a_ptr,
842 int step, // bytes per pixel 837 int step, // bytes per pixel
843 int rgb_stride, // bytes per scanline 838 int rgb_stride, // bytes per scanline
844 float dithering, 839 float dithering,
845 int use_iterative_conversion, 840 int use_iterative_conversion,
846 WebPPicture* const picture) { 841 WebPPicture* const picture) {
847 int y; 842 int y;
848 const int width = picture->width; 843 const int width = picture->width;
849 const int height = picture->height; 844 const int height = picture->height;
850 const int has_alpha = CheckNonOpaque(a_ptr, width, height, step, rgb_stride); 845 const int has_alpha = CheckNonOpaque(a_ptr, width, height, step, rgb_stride);
846 const int is_rgb = (r_ptr < b_ptr); // otherwise it's bgr
851 847
852 picture->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420; 848 picture->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420;
853 picture->use_argb = 0; 849 picture->use_argb = 0;
854 850
855 // disable smart conversion if source is too small (overkill). 851 // disable smart conversion if source is too small (overkill).
856 if (width < kMinDimensionIterativeConversion || 852 if (width < kMinDimensionIterativeConversion ||
857 height < kMinDimensionIterativeConversion) { 853 height < kMinDimensionIterativeConversion) {
858 use_iterative_conversion = 0; 854 use_iterative_conversion = 0;
859 } 855 }
860 856
861 if (!WebPPictureAllocYUVA(picture, width, height)) { 857 if (!WebPPictureAllocYUVA(picture, width, height)) {
862 return 0; 858 return 0;
863 } 859 }
864 if (has_alpha) { 860 if (has_alpha) {
865 WebPInitAlphaProcessing(); 861 WebPInitAlphaProcessing();
866 assert(step == 4); 862 assert(step == 4);
867 #if defined(USE_INVERSE_ALPHA_TABLE) 863 #if defined(USE_GAMMA_COMPRESSION) && defined(USE_INVERSE_ALPHA_TABLE)
868 assert(kAlphaFix + kGammaFix <= 31); 864 assert(kAlphaFix + kGammaFix <= 31);
869 #endif 865 #endif
870 } 866 }
871 867
872 if (use_iterative_conversion) { 868 if (use_iterative_conversion) {
873 InitGammaTablesF(); 869 InitGammaTablesF();
874 if (!PreprocessARGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, picture)) { 870 if (!PreprocessARGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, picture)) {
875 return 0; 871 return 0;
876 } 872 }
877 if (has_alpha) { 873 if (has_alpha) {
878 WebPExtractAlpha(a_ptr, rgb_stride, width, height, 874 WebPExtractAlpha(a_ptr, rgb_stride, width, height,
879 picture->a, picture->a_stride); 875 picture->a, picture->a_stride);
880 } 876 }
881 } else { 877 } else {
878 const int uv_width = (width + 1) >> 1;
879 int use_dsp = (step == 3); // use special function in this case
880 // temporary storage for accumulated R/G/B values during conversion to U/V
881 uint16_t* const tmp_rgb =
882 (uint16_t*)WebPSafeMalloc(4 * uv_width, sizeof(*tmp_rgb));
882 uint8_t* dst_y = picture->y; 883 uint8_t* dst_y = picture->y;
883 uint8_t* dst_u = picture->u; 884 uint8_t* dst_u = picture->u;
884 uint8_t* dst_v = picture->v; 885 uint8_t* dst_v = picture->v;
885 uint8_t* dst_a = picture->a; 886 uint8_t* dst_a = picture->a;
886 887
887 VP8Random base_rg; 888 VP8Random base_rg;
888 VP8Random* rg = NULL; 889 VP8Random* rg = NULL;
889 if (dithering > 0.) { 890 if (dithering > 0.) {
890 VP8InitRandom(&base_rg, dithering); 891 VP8InitRandom(&base_rg, dithering);
891 rg = &base_rg; 892 rg = &base_rg;
893 use_dsp = 0; // can't use dsp in this case
892 } 894 }
895 WebPInitConvertARGBToYUV();
896 InitGammaTables();
893 897
894 InitGammaTables(); 898 if (tmp_rgb == NULL) return 0; // malloc error
895 899
896 // Downsample Y/U/V planes, two rows at a time 900 // Downsample Y/U/V planes, two rows at a time
897 for (y = 0; y < (height >> 1); ++y) { 901 for (y = 0; y < (height >> 1); ++y) {
898 int rows_have_alpha = has_alpha; 902 int rows_have_alpha = has_alpha;
899 const int off1 = (2 * y + 0) * rgb_stride; 903 const int off1 = (2 * y + 0) * rgb_stride;
900 const int off2 = (2 * y + 1) * rgb_stride; 904 const int off2 = (2 * y + 1) * rgb_stride;
901 ConvertRowToY(r_ptr + off1, g_ptr + off1, b_ptr + off1, step, 905 if (use_dsp) {
902 dst_y, width, rg); 906 if (is_rgb) {
903 ConvertRowToY(r_ptr + off2, g_ptr + off2, b_ptr + off2, step, 907 WebPConvertRGB24ToY(r_ptr + off1, dst_y, width);
904 dst_y + picture->y_stride, width, rg); 908 WebPConvertRGB24ToY(r_ptr + off2, dst_y + picture->y_stride, width);
909 } else {
910 WebPConvertBGR24ToY(b_ptr + off1, dst_y, width);
911 WebPConvertBGR24ToY(b_ptr + off2, dst_y + picture->y_stride, width);
912 }
913 } else {
914 ConvertRowToY(r_ptr + off1, g_ptr + off1, b_ptr + off1, step,
915 dst_y, width, rg);
916 ConvertRowToY(r_ptr + off2, g_ptr + off2, b_ptr + off2, step,
917 dst_y + picture->y_stride, width, rg);
918 }
905 dst_y += 2 * picture->y_stride; 919 dst_y += 2 * picture->y_stride;
906 if (has_alpha) { 920 if (has_alpha) {
907 rows_have_alpha &= !WebPExtractAlpha(a_ptr + off1, rgb_stride, 921 rows_have_alpha &= !WebPExtractAlpha(a_ptr + off1, rgb_stride,
908 width, 2, 922 width, 2,
909 dst_a, picture->a_stride); 923 dst_a, picture->a_stride);
910 dst_a += 2 * picture->a_stride; 924 dst_a += 2 * picture->a_stride;
911 } 925 }
926 // Collect averaged R/G/B(/A)
912 if (!rows_have_alpha) { 927 if (!rows_have_alpha) {
913 ConvertRowsToUV(r_ptr + off1, g_ptr + off1, b_ptr + off1, 928 AccumulateRGB(r_ptr + off1, g_ptr + off1, b_ptr + off1,
914 step, rgb_stride, dst_u, dst_v, width, rg); 929 step, rgb_stride, tmp_rgb, width);
915 } else { 930 } else {
916 ConvertRowsToUVWithAlpha(r_ptr + off1, g_ptr + off1, b_ptr + off1, 931 AccumulateRGBA(r_ptr + off1, g_ptr + off1, b_ptr + off1, a_ptr + off1,
917 a_ptr + off1, rgb_stride, 932 rgb_stride, tmp_rgb, width);
918 dst_u, dst_v, width, rg); 933 }
934 // Convert to U/V
935 if (rg == NULL) {
936 WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width);
937 } else {
938 ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg);
919 } 939 }
920 dst_u += picture->uv_stride; 940 dst_u += picture->uv_stride;
921 dst_v += picture->uv_stride; 941 dst_v += picture->uv_stride;
922 } 942 }
923 if (height & 1) { // extra last row 943 if (height & 1) { // extra last row
924 const int off = 2 * y * rgb_stride; 944 const int off = 2 * y * rgb_stride;
925 int row_has_alpha = has_alpha; 945 int row_has_alpha = has_alpha;
926 ConvertRowToY(r_ptr + off, g_ptr + off, b_ptr + off, step, 946 if (use_dsp) {
927 dst_y, width, rg); 947 if (r_ptr < b_ptr) {
948 WebPConvertRGB24ToY(r_ptr + off, dst_y, width);
949 } else {
950 WebPConvertBGR24ToY(b_ptr + off, dst_y, width);
951 }
952 } else {
953 ConvertRowToY(r_ptr + off, g_ptr + off, b_ptr + off, step,
954 dst_y, width, rg);
955 }
928 if (row_has_alpha) { 956 if (row_has_alpha) {
929 row_has_alpha &= !WebPExtractAlpha(a_ptr + off, 0, width, 1, dst_a, 0); 957 row_has_alpha &= !WebPExtractAlpha(a_ptr + off, 0, width, 1, dst_a, 0);
930 } 958 }
959 // Collect averaged R/G/B(/A)
931 if (!row_has_alpha) { 960 if (!row_has_alpha) {
932 ConvertRowsToUV(r_ptr + off, g_ptr + off, b_ptr + off, 961 // Collect averaged R/G/B
933 step, 0, dst_u, dst_v, width, rg); 962 AccumulateRGB(r_ptr + off, g_ptr + off, b_ptr + off,
963 step, /* rgb_stride = */ 0, tmp_rgb, width);
934 } else { 964 } else {
935 ConvertRowsToUVWithAlpha(r_ptr + off, g_ptr + off, b_ptr + off, 965 AccumulateRGBA(r_ptr + off, g_ptr + off, b_ptr + off, a_ptr + off,
936 a_ptr + off, 0, 966 /* rgb_stride = */ 0, tmp_rgb, width);
937 dst_u, dst_v, width, rg); 967 }
968 if (rg == NULL) {
969 WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width);
970 } else {
971 ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg);
938 } 972 }
939 } 973 }
974 WebPSafeFree(tmp_rgb);
940 } 975 }
941 return 1; 976 return 1;
942 } 977 }
943 978
944 #undef SUM4 979 #undef SUM4
945 #undef SUM2 980 #undef SUM2
946 #undef SUM4ALPHA 981 #undef SUM4ALPHA
947 #undef SUM2ALPHA 982 #undef SUM2ALPHA
948 983
949 //------------------------------------------------------------------------------ 984 //------------------------------------------------------------------------------
(...skipping 21 matching lines...) Expand all
971 1006
972 int WebPPictureARGBToYUVADithered(WebPPicture* picture, WebPEncCSP colorspace, 1007 int WebPPictureARGBToYUVADithered(WebPPicture* picture, WebPEncCSP colorspace,
973 float dithering) { 1008 float dithering) {
974 return PictureARGBToYUVA(picture, colorspace, dithering, 0); 1009 return PictureARGBToYUVA(picture, colorspace, dithering, 0);
975 } 1010 }
976 1011
977 int WebPPictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace) { 1012 int WebPPictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace) {
978 return PictureARGBToYUVA(picture, colorspace, 0.f, 0); 1013 return PictureARGBToYUVA(picture, colorspace, 0.f, 0);
979 } 1014 }
980 1015
981 #if WEBP_ENCODER_ABI_VERSION > 0x0204
982 int WebPPictureSmartARGBToYUVA(WebPPicture* picture) { 1016 int WebPPictureSmartARGBToYUVA(WebPPicture* picture) {
983 return PictureARGBToYUVA(picture, WEBP_YUV420, 0.f, 1); 1017 return PictureARGBToYUVA(picture, WEBP_YUV420, 0.f, 1);
984 } 1018 }
985 #endif
986 1019
987 //------------------------------------------------------------------------------ 1020 //------------------------------------------------------------------------------
988 // call for YUVA -> ARGB conversion 1021 // call for YUVA -> ARGB conversion
989 1022
990 int WebPPictureYUVAToARGB(WebPPicture* picture) { 1023 int WebPPictureYUVAToARGB(WebPPicture* picture) {
991 if (picture == NULL) return 0; 1024 if (picture == NULL) return 0;
992 if (picture->y == NULL || picture->u == NULL || picture->v == NULL) { 1025 if (picture->y == NULL || picture->u == NULL || picture->v == NULL) {
993 return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER); 1026 return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
994 } 1027 }
995 if ((picture->colorspace & WEBP_CSP_ALPHA_BIT) && picture->a == NULL) { 1028 if ((picture->colorspace & WEBP_CSP_ALPHA_BIT) && picture->a == NULL) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
1059 const uint8_t* const a_ptr = import_alpha ? rgb + 3 : NULL; 1092 const uint8_t* const a_ptr = import_alpha ? rgb + 3 : NULL;
1060 const int width = picture->width; 1093 const int width = picture->width;
1061 const int height = picture->height; 1094 const int height = picture->height;
1062 1095
1063 if (!picture->use_argb) { 1096 if (!picture->use_argb) {
1064 return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride, 1097 return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride,
1065 0.f /* no dithering */, 0, picture); 1098 0.f /* no dithering */, 0, picture);
1066 } 1099 }
1067 if (!WebPPictureAlloc(picture)) return 0; 1100 if (!WebPPictureAlloc(picture)) return 0;
1068 1101
1069 assert(step >= (import_alpha ? 4 : 3)); 1102 VP8EncDspARGBInit();
1070 for (y = 0; y < height; ++y) { 1103
1071 uint32_t* const dst = &picture->argb[y * picture->argb_stride]; 1104 if (import_alpha) {
1072 int x; 1105 assert(step == 4);
1073 for (x = 0; x < width; ++x) { 1106 for (y = 0; y < height; ++y) {
1074 const int offset = step * x + y * rgb_stride; 1107 uint32_t* const dst = &picture->argb[y * picture->argb_stride];
1075 dst[x] = MakeARGB32(import_alpha ? a_ptr[offset] : 0xff, 1108 const int offset = y * rgb_stride;
1076 r_ptr[offset], g_ptr[offset], b_ptr[offset]); 1109 VP8PackARGB(a_ptr + offset, r_ptr + offset, g_ptr + offset,
1110 b_ptr + offset, width, dst);
1111 }
1112 } else {
1113 assert(step >= 3);
1114 for (y = 0; y < height; ++y) {
1115 uint32_t* const dst = &picture->argb[y * picture->argb_stride];
1116 const int offset = y * rgb_stride;
1117 VP8PackRGB(r_ptr + offset, g_ptr + offset, b_ptr + offset,
1118 width, step, dst);
1077 } 1119 }
1078 } 1120 }
1079 return 1; 1121 return 1;
1080 } 1122 }
1081 1123
1082 // Public API 1124 // Public API
1083 1125
1084 int WebPPictureImportRGB(WebPPicture* picture, 1126 int WebPPictureImportRGB(WebPPicture* picture,
1085 const uint8_t* rgb, int rgb_stride) { 1127 const uint8_t* rgb, int rgb_stride) {
1086 return (picture != NULL) ? Import(picture, rgb, rgb_stride, 3, 0, 0) : 0; 1128 return (picture != NULL) ? Import(picture, rgb, rgb_stride, 3, 0, 0) : 0;
(...skipping 18 matching lines...) Expand all
1105 const uint8_t* rgba, int rgba_stride) { 1147 const uint8_t* rgba, int rgba_stride) {
1106 return (picture != NULL) ? Import(picture, rgba, rgba_stride, 4, 0, 0) : 0; 1148 return (picture != NULL) ? Import(picture, rgba, rgba_stride, 4, 0, 0) : 0;
1107 } 1149 }
1108 1150
1109 int WebPPictureImportBGRX(WebPPicture* picture, 1151 int WebPPictureImportBGRX(WebPPicture* picture,
1110 const uint8_t* rgba, int rgba_stride) { 1152 const uint8_t* rgba, int rgba_stride) {
1111 return (picture != NULL) ? Import(picture, rgba, rgba_stride, 4, 1, 0) : 0; 1153 return (picture != NULL) ? Import(picture, rgba, rgba_stride, 4, 1, 0) : 0;
1112 } 1154 }
1113 1155
1114 //------------------------------------------------------------------------------ 1156 //------------------------------------------------------------------------------
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698