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

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

Issue 2651883004: libwebp-0.6.0-rc1 (Closed)
Patch Set: Created 3 years, 10 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
« no previous file with comments | « third_party/libwebp/enc/picture_csp.c ('k') | third_party/libwebp/enc/picture_enc.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
11 // 11 //
12 // Author: Skal (pascal.massimino@gmail.com) 12 // Author: Skal (pascal.massimino@gmail.com)
13 13
14 #include <assert.h> 14 #include <assert.h>
15 #include <stdlib.h> 15 #include <stdlib.h>
16 #include <math.h> 16 #include <math.h>
17 17
18 #include "./vp8enci.h" 18 #include "./vp8i_enc.h"
19 #include "../utils/random.h" 19 #include "../utils/random_utils.h"
20 #include "../utils/utils.h" 20 #include "../utils/utils.h"
21 #include "../dsp/yuv.h" 21 #include "../dsp/yuv.h"
22 22
23 // Uncomment to disable gamma-compression during RGB->U/V averaging 23 // Uncomment to disable gamma-compression during RGB->U/V averaging
24 #define USE_GAMMA_COMPRESSION 24 #define USE_GAMMA_COMPRESSION
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 {
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
146 return (rg == NULL) ? VP8RGBToU(r, g, b, YUV_HALF << 2) 146 return (rg == NULL) ? VP8RGBToU(r, g, b, YUV_HALF << 2)
147 : VP8RGBToU(r, g, b, VP8RandomBits(rg, YUV_FIX + 2)); 147 : VP8RGBToU(r, g, b, VP8RandomBits(rg, YUV_FIX + 2));
148 } 148 }
149 149
150 static int RGBToV(int r, int g, int b, VP8Random* const rg) { 150 static int RGBToV(int r, int g, int b, VP8Random* const rg) {
151 return (rg == NULL) ? VP8RGBToV(r, g, b, YUV_HALF << 2) 151 return (rg == NULL) ? VP8RGBToV(r, g, b, YUV_HALF << 2)
152 : VP8RGBToV(r, g, b, VP8RandomBits(rg, YUV_FIX + 2)); 152 : VP8RGBToV(r, g, b, VP8RandomBits(rg, YUV_FIX + 2));
153 } 153 }
154 154
155 //------------------------------------------------------------------------------ 155 //------------------------------------------------------------------------------
156 // Smart RGB->YUV conversion 156 // Sharp RGB->YUV conversion
157 157
158 static const int kNumIterations = 6; 158 static const int kNumIterations = 4;
159 static const int kMinDimensionIterativeConversion = 4; 159 static const int kMinDimensionIterativeConversion = 4;
160 160
161 // We could use SFIX=0 and only uint8_t for fixed_y_t, but it produces some 161 // We could use SFIX=0 and only uint8_t for fixed_y_t, but it produces some
162 // banding sometimes. Better use extra precision. 162 // banding sometimes. Better use extra precision.
163 #define SFIX 2 // fixed-point precision of RGB and Y/W 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 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 165 typedef uint16_t fixed_y_t; // unsigned type with extra SFIX precision for W
166 166
167 #define SHALF (1 << SFIX >> 1) 167 #define SHALF (1 << SFIX >> 1)
168 #define MAX_Y_T ((256 << SFIX) - 1) 168 #define MAX_Y_T ((256 << SFIX) - 1)
169 #define SROUNDER (1 << (YUV_FIX + SFIX - 1)) 169 #define SROUNDER (1 << (YUV_FIX + SFIX - 1))
170 170
171 #if defined(USE_GAMMA_COMPRESSION) 171 #if defined(USE_GAMMA_COMPRESSION)
172 172
173 // float variant of gamma-correction 173 // float variant of gamma-correction
174 // We use tables of different size and precision, along with a 'real-world' 174 // We use tables of different size and precision for the Rec709
175 // Gamma value close to ~2. 175 // transfer function.
176 #define kGammaF 2.2 176 #define kGammaF (1./0.45)
177 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
178 static float kLinearToGammaTabF[kGammaTabSize + 2]; 178 static float kLinearToGammaTabF[kGammaTabSize + 2];
179 static volatile int kGammaTablesFOk = 0; 179 static volatile int kGammaTablesFOk = 0;
180 180
181 static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTablesF(void) { 181 static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTablesF(void) {
182 if (!kGammaTablesFOk) { 182 if (!kGammaTablesFOk) {
183 int v; 183 int v;
184 const double norm = 1. / MAX_Y_T; 184 const double norm = 1. / MAX_Y_T;
185 const double scale = 1. / kGammaTabSize; 185 const double scale = 1. / kGammaTabSize;
186 const double a = 0.099;
187 const double thresh = 0.018;
186 for (v = 0; v <= MAX_Y_T; ++v) { 188 for (v = 0; v <= MAX_Y_T; ++v) {
187 kGammaToLinearTabF[v] = (float)pow(norm * v, kGammaF); 189 const double g = norm * v;
190 if (g <= thresh * 4.5) {
191 kGammaToLinearTabF[v] = (float)(g / 4.5);
192 } else {
193 const double a_rec = 1. / (1. + a);
194 kGammaToLinearTabF[v] = (float)pow(a_rec * (g + a), kGammaF);
195 }
188 } 196 }
189 for (v = 0; v <= kGammaTabSize; ++v) { 197 for (v = 0; v <= kGammaTabSize; ++v) {
190 kLinearToGammaTabF[v] = (float)(MAX_Y_T * pow(scale * v, 1. / kGammaF)); 198 const double g = scale * v;
199 double value;
200 if (g <= thresh) {
201 value = 4.5 * g;
202 } else {
203 value = (1. + a) * pow(g, 1. / kGammaF) - a;
204 }
205 kLinearToGammaTabF[v] = (float)(MAX_Y_T * value);
191 } 206 }
192 // to prevent small rounding errors to cause read-overflow: 207 // to prevent small rounding errors to cause read-overflow:
193 kLinearToGammaTabF[kGammaTabSize + 1] = kLinearToGammaTabF[kGammaTabSize]; 208 kLinearToGammaTabF[kGammaTabSize + 1] = kLinearToGammaTabF[kGammaTabSize];
194 kGammaTablesFOk = 1; 209 kGammaTablesFOk = 1;
195 } 210 }
196 } 211 }
197 212
198 static WEBP_INLINE float GammaToLinearF(int v) { 213 static WEBP_INLINE float GammaToLinearF(int v) {
199 return kGammaToLinearTabF[v]; 214 return kGammaToLinearTabF[v];
200 } 215 }
(...skipping 27 matching lines...) Expand all
228 return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u; 243 return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u;
229 } 244 }
230 245
231 static fixed_y_t clip_y(int y) { 246 static fixed_y_t clip_y(int y) {
232 return (!(y & ~MAX_Y_T)) ? (fixed_y_t)y : (y < 0) ? 0 : MAX_Y_T; 247 return (!(y & ~MAX_Y_T)) ? (fixed_y_t)y : (y < 0) ? 0 : MAX_Y_T;
233 } 248 }
234 249
235 //------------------------------------------------------------------------------ 250 //------------------------------------------------------------------------------
236 251
237 static int RGBToGray(int r, int g, int b) { 252 static int RGBToGray(int r, int g, int b) {
238 const int luma = 19595 * r + 38470 * g + 7471 * b + YUV_HALF; 253 const int luma = 13933 * r + 46871 * g + 4732 * b + YUV_HALF;
239 return (luma >> YUV_FIX); 254 return (luma >> YUV_FIX);
240 } 255 }
241 256
242 static float RGBToGrayF(float r, float g, float b) { 257 static float RGBToGrayF(float r, float g, float b) {
243 return 0.299f * r + 0.587f * g + 0.114f * b; 258 return (float)(0.2126 * r + 0.7152 * g + 0.0722 * b);
244 } 259 }
245 260
246 static int ScaleDown(int a, int b, int c, int d) { 261 static int ScaleDown(int a, int b, int c, int d) {
247 const float A = GammaToLinearF(a); 262 const float A = GammaToLinearF(a);
248 const float B = GammaToLinearF(b); 263 const float B = GammaToLinearF(b);
249 const float C = GammaToLinearF(c); 264 const float C = GammaToLinearF(c);
250 const float D = GammaToLinearF(d); 265 const float D = GammaToLinearF(d);
251 return LinearToGammaF(0.25f * (A + B + C + D)); 266 return LinearToGammaF(0.25f * (A + B + C + D));
252 } 267 }
253 268
254 static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int len) { 269 static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w) {
255 while (len-- > 0) { 270 int i;
256 const float R = GammaToLinearF(src[0]); 271 for (i = 0; i < w; ++i) {
257 const float G = GammaToLinearF(src[1]); 272 const float R = GammaToLinearF(src[0 * w + i]);
258 const float B = GammaToLinearF(src[2]); 273 const float G = GammaToLinearF(src[1 * w + i]);
274 const float B = GammaToLinearF(src[2 * w + i]);
259 const float Y = RGBToGrayF(R, G, B); 275 const float Y = RGBToGrayF(R, G, B);
260 *dst++ = (fixed_y_t)LinearToGammaF(Y); 276 dst[i] = (fixed_y_t)LinearToGammaF(Y);
261 src += 3;
262 } 277 }
263 } 278 }
264 279
265 static int UpdateChroma(const fixed_y_t* src1, 280 static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2,
266 const fixed_y_t* src2, 281 fixed_t* dst, int uv_w) {
267 fixed_t* dst, fixed_y_t* tmp, int len) { 282 int i;
268 int diff = 0; 283 for (i = 0; i < uv_w; ++i) {
269 while (len--> 0) { 284 const int r = ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1],
270 const int r = ScaleDown(src1[0], src1[3], src2[0], src2[3]); 285 src2[0 * uv_w + 0], src2[0 * uv_w + 1]);
271 const int g = ScaleDown(src1[1], src1[4], src2[1], src2[4]); 286 const int g = ScaleDown(src1[2 * uv_w + 0], src1[2 * uv_w + 1],
272 const int b = ScaleDown(src1[2], src1[5], src2[2], src2[5]); 287 src2[2 * uv_w + 0], src2[2 * uv_w + 1]);
288 const int b = ScaleDown(src1[4 * uv_w + 0], src1[4 * uv_w + 1],
289 src2[4 * uv_w + 0], src2[4 * uv_w + 1]);
273 const int W = RGBToGray(r, g, b); 290 const int W = RGBToGray(r, g, b);
274 const int r_avg = (src1[0] + src1[3] + src2[0] + src2[3] + 2) >> 2; 291 dst[0 * uv_w] = (fixed_t)(r - W);
275 const int g_avg = (src1[1] + src1[4] + src2[1] + src2[4] + 2) >> 2; 292 dst[1 * uv_w] = (fixed_t)(g - W);
276 const int b_avg = (src1[2] + src1[5] + src2[2] + src2[5] + 2) >> 2; 293 dst[2 * uv_w] = (fixed_t)(b - W);
277 dst[0] = (fixed_t)(r - W); 294 dst += 1;
278 dst[1] = (fixed_t)(g - W); 295 src1 += 2;
279 dst[2] = (fixed_t)(b - W); 296 src2 += 2;
280 dst += 3;
281 src1 += 6;
282 src2 += 6;
283 if (tmp != NULL) {
284 tmp[0] = tmp[1] = clip_y(W);
285 tmp += 2;
286 }
287 diff += abs(RGBToGray(r_avg, g_avg, b_avg) - W);
288 } 297 }
289 return diff; 298 }
299
300 static void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) {
301 int i;
302 for (i = 0; i < w; ++i) {
303 y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]);
304 }
290 } 305 }
291 306
292 //------------------------------------------------------------------------------ 307 //------------------------------------------------------------------------------
293 308
294 static WEBP_INLINE int Filter(const fixed_t* const A, const fixed_t* const B, 309 static WEBP_INLINE fixed_y_t Filter2(int A, int B, int W0) {
295 int rightwise) { 310 const int v0 = (A * 3 + B + 2) >> 2;
296 int v; 311 return clip_y(v0 + W0);
297 if (!rightwise) {
298 v = (A[0] * 9 + A[-3] * 3 + B[0] * 3 + B[-3]);
299 } else {
300 v = (A[0] * 9 + A[+3] * 3 + B[0] * 3 + B[+3]);
301 }
302 return (v + 8) >> 4;
303 } 312 }
304 313
305 static WEBP_INLINE int Filter2(int A, int B) { return (A * 3 + B + 2) >> 2; }
306
307 //------------------------------------------------------------------------------ 314 //------------------------------------------------------------------------------
308 315
309 static WEBP_INLINE fixed_y_t UpLift(uint8_t a) { // 8bit -> SFIX 316 static WEBP_INLINE fixed_y_t UpLift(uint8_t a) { // 8bit -> SFIX
310 return ((fixed_y_t)a << SFIX) | SHALF; 317 return ((fixed_y_t)a << SFIX) | SHALF;
311 } 318 }
312 319
313 static void ImportOneRow(const uint8_t* const r_ptr, 320 static void ImportOneRow(const uint8_t* const r_ptr,
314 const uint8_t* const g_ptr, 321 const uint8_t* const g_ptr,
315 const uint8_t* const b_ptr, 322 const uint8_t* const b_ptr,
316 int step, 323 int step,
317 int pic_width, 324 int pic_width,
318 fixed_y_t* const dst) { 325 fixed_y_t* const dst) {
319 int i; 326 int i;
327 const int w = (pic_width + 1) & ~1;
320 for (i = 0; i < pic_width; ++i) { 328 for (i = 0; i < pic_width; ++i) {
321 const int off = i * step; 329 const int off = i * step;
322 dst[3 * i + 0] = UpLift(r_ptr[off]); 330 dst[i + 0 * w] = UpLift(r_ptr[off]);
323 dst[3 * i + 1] = UpLift(g_ptr[off]); 331 dst[i + 1 * w] = UpLift(g_ptr[off]);
324 dst[3 * i + 2] = UpLift(b_ptr[off]); 332 dst[i + 2 * w] = UpLift(b_ptr[off]);
325 } 333 }
326 if (pic_width & 1) { // replicate rightmost pixel 334 if (pic_width & 1) { // replicate rightmost pixel
327 memcpy(dst + 3 * pic_width, dst + 3 * (pic_width - 1), 3 * sizeof(*dst)); 335 dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1];
336 dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1];
337 dst[pic_width + 2 * w] = dst[pic_width + 2 * w - 1];
328 } 338 }
329 } 339 }
330 340
331 static void InterpolateTwoRows(const fixed_y_t* const best_y, 341 static void InterpolateTwoRows(const fixed_y_t* const best_y,
332 const fixed_t* const prev_uv, 342 const fixed_t* prev_uv,
333 const fixed_t* const cur_uv, 343 const fixed_t* cur_uv,
334 const fixed_t* const next_uv, 344 const fixed_t* next_uv,
335 int w, 345 int w,
336 fixed_y_t* const out1, 346 fixed_y_t* out1,
337 fixed_y_t* const out2) { 347 fixed_y_t* out2) {
338 int i, k; 348 const int uv_w = w >> 1;
339 { // special boundary case for i==0 349 const int len = (w - 1) >> 1; // length to filter
340 const int W0 = best_y[0]; 350 int k = 3;
341 const int W1 = best_y[w]; 351 while (k-- > 0) { // process each R/G/B segments in turn
342 for (k = 0; k <= 2; ++k) { 352 // special boundary case for i==0
343 out1[k] = clip_y(Filter2(cur_uv[k], prev_uv[k]) + W0); 353 out1[0] = Filter2(cur_uv[0], prev_uv[0], best_y[0]);
344 out2[k] = clip_y(Filter2(cur_uv[k], next_uv[k]) + W1); 354 out2[0] = Filter2(cur_uv[0], next_uv[0], best_y[w]);
355
356 WebPSharpYUVFilterRow(cur_uv, prev_uv, len, best_y + 0 + 1, out1 + 1);
357 WebPSharpYUVFilterRow(cur_uv, next_uv, len, best_y + w + 1, out2 + 1);
358
359 // special boundary case for i == w - 1 when w is even
360 if (!(w & 1)) {
361 out1[w - 1] = Filter2(cur_uv[uv_w - 1], prev_uv[uv_w - 1],
362 best_y[w - 1 + 0]);
363 out2[w - 1] = Filter2(cur_uv[uv_w - 1], next_uv[uv_w - 1],
364 best_y[w - 1 + w]);
345 } 365 }
346 } 366 out1 += w;
347 for (i = 1; i < w - 1; ++i) { 367 out2 += w;
348 const int W0 = best_y[i + 0]; 368 prev_uv += uv_w;
349 const int W1 = best_y[i + w]; 369 cur_uv += uv_w;
350 const int off = 3 * (i >> 1); 370 next_uv += uv_w;
351 for (k = 0; k <= 2; ++k) {
352 const int tmp0 = Filter(cur_uv + off + k, prev_uv + off + k, i & 1);
353 const int tmp1 = Filter(cur_uv + off + k, next_uv + off + k, i & 1);
354 out1[3 * i + k] = clip_y(tmp0 + W0);
355 out2[3 * i + k] = clip_y(tmp1 + W1);
356 }
357 }
358 { // special boundary case for i == w - 1
359 const int W0 = best_y[i + 0];
360 const int W1 = best_y[i + w];
361 const int off = 3 * (i >> 1);
362 for (k = 0; k <= 2; ++k) {
363 out1[3 * i + k] = clip_y(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);
365 }
366 } 371 }
367 } 372 }
368 373
369 static WEBP_INLINE uint8_t ConvertRGBToY(int r, int g, int b) { 374 static WEBP_INLINE uint8_t ConvertRGBToY(int r, int g, int b) {
370 const int luma = 16839 * r + 33059 * g + 6420 * b + SROUNDER; 375 const int luma = 16839 * r + 33059 * g + 6420 * b + SROUNDER;
371 return clip_8b(16 + (luma >> (YUV_FIX + SFIX))); 376 return clip_8b(16 + (luma >> (YUV_FIX + SFIX)));
372 } 377 }
373 378
374 static WEBP_INLINE uint8_t ConvertRGBToU(int r, int g, int b) { 379 static WEBP_INLINE uint8_t ConvertRGBToU(int r, int g, int b) {
375 const int u = -9719 * r - 19081 * g + 28800 * b + SROUNDER; 380 const int u = -9719 * r - 19081 * g + 28800 * b + SROUNDER;
(...skipping 11 matching lines...) Expand all
387 uint8_t* dst_y = picture->y; 392 uint8_t* dst_y = picture->y;
388 uint8_t* dst_u = picture->u; 393 uint8_t* dst_u = picture->u;
389 uint8_t* dst_v = picture->v; 394 uint8_t* dst_v = picture->v;
390 const fixed_t* const best_uv_base = best_uv; 395 const fixed_t* const best_uv_base = best_uv;
391 const int w = (picture->width + 1) & ~1; 396 const int w = (picture->width + 1) & ~1;
392 const int h = (picture->height + 1) & ~1; 397 const int h = (picture->height + 1) & ~1;
393 const int uv_w = w >> 1; 398 const int uv_w = w >> 1;
394 const int uv_h = h >> 1; 399 const int uv_h = h >> 1;
395 for (best_uv = best_uv_base, j = 0; j < picture->height; ++j) { 400 for (best_uv = best_uv_base, j = 0; j < picture->height; ++j) {
396 for (i = 0; i < picture->width; ++i) { 401 for (i = 0; i < picture->width; ++i) {
397 const int off = 3 * (i >> 1); 402 const int off = (i >> 1);
398 const int W = best_y[i]; 403 const int W = best_y[i];
399 const int r = best_uv[off + 0] + W; 404 const int r = best_uv[off + 0 * uv_w] + W;
400 const int g = best_uv[off + 1] + W; 405 const int g = best_uv[off + 1 * uv_w] + W;
401 const int b = best_uv[off + 2] + W; 406 const int b = best_uv[off + 2 * uv_w] + W;
402 dst_y[i] = ConvertRGBToY(r, g, b); 407 dst_y[i] = ConvertRGBToY(r, g, b);
403 } 408 }
404 best_y += w; 409 best_y += w;
405 best_uv += (j & 1) * 3 * uv_w; 410 best_uv += (j & 1) * 3 * uv_w;
406 dst_y += picture->y_stride; 411 dst_y += picture->y_stride;
407 } 412 }
408 for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) { 413 for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) {
409 for (i = 0; i < uv_w; ++i) { 414 for (i = 0; i < uv_w; ++i) {
410 const int off = 3 * i; 415 const int off = i;
411 const int r = best_uv[off + 0]; 416 const int r = best_uv[off + 0 * uv_w];
412 const int g = best_uv[off + 1]; 417 const int g = best_uv[off + 1 * uv_w];
413 const int b = best_uv[off + 2]; 418 const int b = best_uv[off + 2 * uv_w];
414 dst_u[i] = ConvertRGBToU(r, g, b); 419 dst_u[i] = ConvertRGBToU(r, g, b);
415 dst_v[i] = ConvertRGBToV(r, g, b); 420 dst_v[i] = ConvertRGBToV(r, g, b);
416 } 421 }
417 best_uv += 3 * uv_w; 422 best_uv += 3 * uv_w;
418 dst_u += picture->uv_stride; 423 dst_u += picture->uv_stride;
419 dst_v += picture->uv_stride; 424 dst_v += picture->uv_stride;
420 } 425 }
421 return 1; 426 return 1;
422 } 427 }
423 428
424 //------------------------------------------------------------------------------ 429 //------------------------------------------------------------------------------
425 // Main function 430 // Main function
426 431
427 #define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((W) * (H), sizeof(T))) 432 #define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((W) * (H), sizeof(T)))
428 433
429 static int PreprocessARGB(const uint8_t* r_ptr, 434 static int PreprocessARGB(const uint8_t* r_ptr,
430 const uint8_t* g_ptr, 435 const uint8_t* g_ptr,
431 const uint8_t* b_ptr, 436 const uint8_t* b_ptr,
432 int step, int rgb_stride, 437 int step, int rgb_stride,
433 WebPPicture* const picture) { 438 WebPPicture* const picture) {
434 // we expand the right/bottom border if needed 439 // we expand the right/bottom border if needed
435 const int w = (picture->width + 1) & ~1; 440 const int w = (picture->width + 1) & ~1;
436 const int h = (picture->height + 1) & ~1; 441 const int h = (picture->height + 1) & ~1;
437 const int uv_w = w >> 1; 442 const int uv_w = w >> 1;
438 const int uv_h = h >> 1; 443 const int uv_h = h >> 1;
439 int i, j, iter; 444 uint64_t prev_diff_y_sum = ~0;
445 int j, iter;
440 446
441 // TODO(skal): allocate one big memory chunk. But for now, it's easier 447 // TODO(skal): allocate one big memory chunk. But for now, it's easier
442 // for valgrind debugging to have several chunks. 448 // for valgrind debugging to have several chunks.
443 fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch 449 fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch
444 fixed_y_t* const best_y_base = SAFE_ALLOC(w, h, fixed_y_t); 450 fixed_y_t* const best_y_base = SAFE_ALLOC(w, h, fixed_y_t);
445 fixed_y_t* const target_y_base = SAFE_ALLOC(w, h, fixed_y_t); 451 fixed_y_t* const target_y_base = SAFE_ALLOC(w, h, fixed_y_t);
446 fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t); 452 fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t);
447 fixed_t* const best_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); 453 fixed_t* const best_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
448 fixed_t* const target_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); 454 fixed_t* const target_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
449 fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t); 455 fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t);
450 fixed_y_t* best_y = best_y_base; 456 fixed_y_t* best_y = best_y_base;
451 fixed_y_t* target_y = target_y_base; 457 fixed_y_t* target_y = target_y_base;
452 fixed_t* best_uv = best_uv_base; 458 fixed_t* best_uv = best_uv_base;
453 fixed_t* target_uv = target_uv_base; 459 fixed_t* target_uv = target_uv_base;
460 const uint64_t diff_y_threshold = (uint64_t)(3.0 * w * h);
454 int ok; 461 int ok;
455 int diff_sum = 0;
456 const int first_diff_threshold = (int)(2.5 * w * h);
457 const int min_improvement = 5; // stop if improvement is below this %
458 const int min_first_improvement = 80;
459 462
460 if (best_y_base == NULL || best_uv_base == NULL || 463 if (best_y_base == NULL || best_uv_base == NULL ||
461 target_y_base == NULL || target_uv_base == NULL || 464 target_y_base == NULL || target_uv_base == NULL ||
462 best_rgb_y == NULL || best_rgb_uv == NULL || 465 best_rgb_y == NULL || best_rgb_uv == NULL ||
463 tmp_buffer == NULL) { 466 tmp_buffer == NULL) {
464 ok = WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); 467 ok = WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
465 goto End; 468 goto End;
466 } 469 }
467 assert(picture->width >= kMinDimensionIterativeConversion); 470 assert(picture->width >= kMinDimensionIterativeConversion);
468 assert(picture->height >= kMinDimensionIterativeConversion); 471 assert(picture->height >= kMinDimensionIterativeConversion);
469 472
473 WebPInitConvertARGBToYUV();
474
470 // Import RGB samples to W/RGB representation. 475 // Import RGB samples to W/RGB representation.
471 for (j = 0; j < picture->height; j += 2) { 476 for (j = 0; j < picture->height; j += 2) {
472 const int is_last_row = (j == picture->height - 1); 477 const int is_last_row = (j == picture->height - 1);
473 fixed_y_t* const src1 = tmp_buffer; 478 fixed_y_t* const src1 = tmp_buffer + 0 * w;
474 fixed_y_t* const src2 = tmp_buffer + 3 * w; 479 fixed_y_t* const src2 = tmp_buffer + 3 * w;
475 480
476 // prepare two rows of input 481 // prepare two rows of input
477 ImportOneRow(r_ptr, g_ptr, b_ptr, step, picture->width, src1); 482 ImportOneRow(r_ptr, g_ptr, b_ptr, step, picture->width, src1);
478 if (!is_last_row) { 483 if (!is_last_row) {
479 ImportOneRow(r_ptr + rgb_stride, g_ptr + rgb_stride, b_ptr + rgb_stride, 484 ImportOneRow(r_ptr + rgb_stride, g_ptr + rgb_stride, b_ptr + rgb_stride,
480 step, picture->width, src2); 485 step, picture->width, src2);
481 } else { 486 } else {
482 memcpy(src2, src1, 3 * w * sizeof(*src2)); 487 memcpy(src2, src1, 3 * w * sizeof(*src2));
483 } 488 }
489 StoreGray(src1, best_y + 0, w);
490 StoreGray(src2, best_y + w, w);
491
484 UpdateW(src1, target_y, w); 492 UpdateW(src1, target_y, w);
485 UpdateW(src2, target_y + w, w); 493 UpdateW(src2, target_y + w, w);
486 diff_sum += UpdateChroma(src1, src2, target_uv, best_y, uv_w); 494 UpdateChroma(src1, src2, target_uv, uv_w);
487 memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv)); 495 memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv));
488 memcpy(best_y + w, best_y, w * sizeof(*best_y));
489 best_y += 2 * w; 496 best_y += 2 * w;
490 best_uv += 3 * uv_w; 497 best_uv += 3 * uv_w;
491 target_y += 2 * w; 498 target_y += 2 * w;
492 target_uv += 3 * uv_w; 499 target_uv += 3 * uv_w;
493 r_ptr += 2 * rgb_stride; 500 r_ptr += 2 * rgb_stride;
494 g_ptr += 2 * rgb_stride; 501 g_ptr += 2 * rgb_stride;
495 b_ptr += 2 * rgb_stride; 502 b_ptr += 2 * rgb_stride;
496 } 503 }
497 504
498 // Iterate and resolve clipping conflicts. 505 // Iterate and resolve clipping conflicts.
499 for (iter = 0; iter < kNumIterations; ++iter) { 506 for (iter = 0; iter < kNumIterations; ++iter) {
500 int k;
501 const fixed_t* cur_uv = best_uv_base; 507 const fixed_t* cur_uv = best_uv_base;
502 const fixed_t* prev_uv = best_uv_base; 508 const fixed_t* prev_uv = best_uv_base;
503 const int old_diff_sum = diff_sum; 509 uint64_t diff_y_sum = 0;
504 diff_sum = 0;
505 510
506 best_y = best_y_base; 511 best_y = best_y_base;
507 best_uv = best_uv_base; 512 best_uv = best_uv_base;
508 target_y = target_y_base; 513 target_y = target_y_base;
509 target_uv = target_uv_base; 514 target_uv = target_uv_base;
510 for (j = 0; j < h; j += 2) { 515 for (j = 0; j < h; j += 2) {
511 fixed_y_t* const src1 = tmp_buffer; 516 fixed_y_t* const src1 = tmp_buffer + 0 * w;
512 fixed_y_t* const src2 = tmp_buffer + 3 * w; 517 fixed_y_t* const src2 = tmp_buffer + 3 * w;
513 { 518 {
514 const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0); 519 const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0);
515 InterpolateTwoRows(best_y, prev_uv, cur_uv, next_uv, w, src1, src2); 520 InterpolateTwoRows(best_y, prev_uv, cur_uv, next_uv, w, src1, src2);
516 prev_uv = cur_uv; 521 prev_uv = cur_uv;
517 cur_uv = next_uv; 522 cur_uv = next_uv;
518 } 523 }
519 524
520 UpdateW(src1, best_rgb_y + 0 * w, w); 525 UpdateW(src1, best_rgb_y + 0 * w, w);
521 UpdateW(src2, best_rgb_y + 1 * w, w); 526 UpdateW(src2, best_rgb_y + 1 * w, w);
522 diff_sum += UpdateChroma(src1, src2, best_rgb_uv, NULL, uv_w); 527 UpdateChroma(src1, src2, best_rgb_uv, uv_w);
523 528
524 // update two rows of Y and one row of RGB 529 // update two rows of Y and one row of RGB
525 for (i = 0; i < 2 * w; ++i) { 530 diff_y_sum += WebPSharpYUVUpdateY(target_y, best_rgb_y, best_y, 2 * w);
526 const int diff_y = target_y[i] - best_rgb_y[i]; 531 WebPSharpYUVUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w);
527 const int new_y = (int)best_y[i] + diff_y; 532
528 best_y[i] = clip_y(new_y);
529 }
530 for (i = 0; i < uv_w; ++i) {
531 const int off = 3 * i;
532 int W;
533 for (k = 0; k <= 2; ++k) {
534 const int diff_uv = (int)target_uv[off + k] - best_rgb_uv[off + k];
535 best_uv[off + k] += diff_uv;
536 }
537 W = RGBToGray(best_uv[off + 0], best_uv[off + 1], best_uv[off + 2]);
538 for (k = 0; k <= 2; ++k) {
539 best_uv[off + k] -= W;
540 }
541 }
542 best_y += 2 * w; 533 best_y += 2 * w;
543 best_uv += 3 * uv_w; 534 best_uv += 3 * uv_w;
544 target_y += 2 * w; 535 target_y += 2 * w;
545 target_uv += 3 * uv_w; 536 target_uv += 3 * uv_w;
546 } 537 }
547 // test exit condition 538 // test exit condition
548 if (diff_sum > 0) { 539 if (iter > 0) {
549 const int improvement = 100 * abs(diff_sum - old_diff_sum) / diff_sum; 540 if (diff_y_sum < diff_y_threshold) break;
550 // Check if first iteration gave good result already, without a large 541 if (diff_y_sum > prev_diff_y_sum) break;
551 // jump of improvement (otherwise it means we need to try few extra
552 // iterations, just to be sure).
553 if (iter == 0 && diff_sum < first_diff_threshold &&
554 improvement < min_first_improvement) {
555 break;
556 }
557 // then, check if improvement is stalling.
558 if (improvement < min_improvement) {
559 break;
560 }
561 } else {
562 break;
563 } 542 }
543 prev_diff_y_sum = diff_y_sum;
564 } 544 }
565
566 // final reconstruction 545 // final reconstruction
567 ok = ConvertWRGBToYUV(best_y_base, best_uv_base, picture); 546 ok = ConvertWRGBToYUV(best_y_base, best_uv_base, picture);
568 547
569 End: 548 End:
570 WebPSafeFree(best_y_base); 549 WebPSafeFree(best_y_base);
571 WebPSafeFree(best_uv_base); 550 WebPSafeFree(best_uv_base);
572 WebPSafeFree(target_y_base); 551 WebPSafeFree(target_y_base);
573 WebPSafeFree(target_uv_base); 552 WebPSafeFree(target_uv_base);
574 WebPSafeFree(best_rgb_y); 553 WebPSafeFree(best_rgb_y);
575 WebPSafeFree(best_rgb_uv); 554 WebPSafeFree(best_rgb_uv);
(...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after
1025 1004
1026 int WebPPictureARGBToYUVADithered(WebPPicture* picture, WebPEncCSP colorspace, 1005 int WebPPictureARGBToYUVADithered(WebPPicture* picture, WebPEncCSP colorspace,
1027 float dithering) { 1006 float dithering) {
1028 return PictureARGBToYUVA(picture, colorspace, dithering, 0); 1007 return PictureARGBToYUVA(picture, colorspace, dithering, 0);
1029 } 1008 }
1030 1009
1031 int WebPPictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace) { 1010 int WebPPictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace) {
1032 return PictureARGBToYUVA(picture, colorspace, 0.f, 0); 1011 return PictureARGBToYUVA(picture, colorspace, 0.f, 0);
1033 } 1012 }
1034 1013
1014 int WebPPictureSharpARGBToYUVA(WebPPicture* picture) {
1015 return PictureARGBToYUVA(picture, WEBP_YUV420, 0.f, 1);
1016 }
1017 // for backward compatibility
1035 int WebPPictureSmartARGBToYUVA(WebPPicture* picture) { 1018 int WebPPictureSmartARGBToYUVA(WebPPicture* picture) {
1036 return PictureARGBToYUVA(picture, WEBP_YUV420, 0.f, 1); 1019 return WebPPictureSharpARGBToYUVA(picture);
1037 } 1020 }
1038 1021
1039 //------------------------------------------------------------------------------ 1022 //------------------------------------------------------------------------------
1040 // call for YUVA -> ARGB conversion 1023 // call for YUVA -> ARGB conversion
1041 1024
1042 int WebPPictureYUVAToARGB(WebPPicture* picture) { 1025 int WebPPictureYUVAToARGB(WebPPicture* picture) {
1043 if (picture == NULL) return 0; 1026 if (picture == NULL) return 0;
1044 if (picture->y == NULL || picture->u == NULL || picture->v == NULL) { 1027 if (picture->y == NULL || picture->u == NULL || picture->v == NULL) {
1045 return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER); 1028 return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
1046 } 1029 }
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
1183 } 1166 }
1184 1167
1185 int WebPPictureImportBGRX(WebPPicture* picture, 1168 int WebPPictureImportBGRX(WebPPicture* picture,
1186 const uint8_t* rgba, int rgba_stride) { 1169 const uint8_t* rgba, int rgba_stride) {
1187 return (picture != NULL && rgba != NULL) 1170 return (picture != NULL && rgba != NULL)
1188 ? Import(picture, rgba, rgba_stride, 4, 1, 0) 1171 ? Import(picture, rgba, rgba_stride, 4, 1, 0)
1189 : 0; 1172 : 0;
1190 } 1173 }
1191 1174
1192 //------------------------------------------------------------------------------ 1175 //------------------------------------------------------------------------------
OLDNEW
« no previous file with comments | « third_party/libwebp/enc/picture_csp.c ('k') | third_party/libwebp/enc/picture_enc.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698