OLD | NEW |
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 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
374 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) { |
375 const int u = -9719 * r - 19081 * g + 28800 * b + SROUNDER; | 375 const int u = -9719 * r - 19081 * g + 28800 * b + SROUNDER; |
376 return clip_8b(128 + (u >> (YUV_FIX + SFIX))); | 376 return clip_8b(128 + (u >> (YUV_FIX + SFIX))); |
377 } | 377 } |
378 | 378 |
379 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) { |
380 const int v = +28800 * r - 24116 * g - 4684 * b + SROUNDER; | 380 const int v = +28800 * r - 24116 * g - 4684 * b + SROUNDER; |
381 return clip_8b(128 + (v >> (YUV_FIX + SFIX))); | 381 return clip_8b(128 + (v >> (YUV_FIX + SFIX))); |
382 } | 382 } |
383 | 383 |
384 static int ConvertWRGBToYUV(const fixed_y_t* const best_y, | 384 static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv, |
385 const fixed_t* const best_uv, | |
386 WebPPicture* const picture) { | 385 WebPPicture* const picture) { |
387 int i, j; | 386 int i, j; |
| 387 uint8_t* dst_y = picture->y; |
| 388 uint8_t* dst_u = picture->u; |
| 389 uint8_t* dst_v = picture->v; |
| 390 const fixed_t* const best_uv_base = best_uv; |
388 const int w = (picture->width + 1) & ~1; | 391 const int w = (picture->width + 1) & ~1; |
389 const int h = (picture->height + 1) & ~1; | 392 const int h = (picture->height + 1) & ~1; |
390 const int uv_w = w >> 1; | 393 const int uv_w = w >> 1; |
391 const int uv_h = h >> 1; | 394 const int uv_h = h >> 1; |
392 for (j = 0; j < picture->height; ++j) { | 395 for (best_uv = best_uv_base, j = 0; j < picture->height; ++j) { |
393 for (i = 0; i < picture->width; ++i) { | 396 for (i = 0; i < picture->width; ++i) { |
394 const int off = 3 * ((i >> 1) + (j >> 1) * uv_w); | 397 const int off = 3 * (i >> 1); |
395 const int off2 = i + j * picture->y_stride; | 398 const int W = best_y[i]; |
396 const int W = best_y[i + j * w]; | |
397 const int r = best_uv[off + 0] + W; | 399 const int r = best_uv[off + 0] + W; |
398 const int g = best_uv[off + 1] + W; | 400 const int g = best_uv[off + 1] + W; |
399 const int b = best_uv[off + 2] + W; | 401 const int b = best_uv[off + 2] + W; |
400 picture->y[off2] = ConvertRGBToY(r, g, b); | 402 dst_y[i] = ConvertRGBToY(r, g, b); |
401 } | 403 } |
| 404 best_y += w; |
| 405 best_uv += (j & 1) * 3 * uv_w; |
| 406 dst_y += picture->y_stride; |
402 } | 407 } |
403 for (j = 0; j < uv_h; ++j) { | 408 for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) { |
404 uint8_t* const dst_u = picture->u + j * picture->uv_stride; | |
405 uint8_t* const dst_v = picture->v + j * picture->uv_stride; | |
406 for (i = 0; i < uv_w; ++i) { | 409 for (i = 0; i < uv_w; ++i) { |
407 const int off = 3 * (i + j * uv_w); | 410 const int off = 3 * i; |
408 const int r = best_uv[off + 0]; | 411 const int r = best_uv[off + 0]; |
409 const int g = best_uv[off + 1]; | 412 const int g = best_uv[off + 1]; |
410 const int b = best_uv[off + 2]; | 413 const int b = best_uv[off + 2]; |
411 dst_u[i] = ConvertRGBToU(r, g, b); | 414 dst_u[i] = ConvertRGBToU(r, g, b); |
412 dst_v[i] = ConvertRGBToV(r, g, b); | 415 dst_v[i] = ConvertRGBToV(r, g, b); |
413 } | 416 } |
| 417 best_uv += 3 * uv_w; |
| 418 dst_u += picture->uv_stride; |
| 419 dst_v += picture->uv_stride; |
414 } | 420 } |
415 return 1; | 421 return 1; |
416 } | 422 } |
417 | 423 |
418 //------------------------------------------------------------------------------ | 424 //------------------------------------------------------------------------------ |
419 // Main function | 425 // Main function |
420 | 426 |
421 #define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((W) * (H), sizeof(T))) | 427 #define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((W) * (H), sizeof(T))) |
422 | 428 |
423 static int PreprocessARGB(const uint8_t* const r_ptr, | 429 static int PreprocessARGB(const uint8_t* r_ptr, |
424 const uint8_t* const g_ptr, | 430 const uint8_t* g_ptr, |
425 const uint8_t* const b_ptr, | 431 const uint8_t* b_ptr, |
426 int step, int rgb_stride, | 432 int step, int rgb_stride, |
427 WebPPicture* const picture) { | 433 WebPPicture* const picture) { |
428 // we expand the right/bottom border if needed | 434 // we expand the right/bottom border if needed |
429 const int w = (picture->width + 1) & ~1; | 435 const int w = (picture->width + 1) & ~1; |
430 const int h = (picture->height + 1) & ~1; | 436 const int h = (picture->height + 1) & ~1; |
431 const int uv_w = w >> 1; | 437 const int uv_w = w >> 1; |
432 const int uv_h = h >> 1; | 438 const int uv_h = h >> 1; |
433 int i, j, iter; | 439 int i, j, iter; |
434 | 440 |
435 // TODO(skal): allocate one big memory chunk. But for now, it's easier | 441 // TODO(skal): allocate one big memory chunk. But for now, it's easier |
436 // for valgrind debugging to have several chunks. | 442 // for valgrind debugging to have several chunks. |
437 fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch | 443 fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch |
438 fixed_y_t* const best_y = SAFE_ALLOC(w, h, fixed_y_t); | 444 fixed_y_t* const best_y_base = SAFE_ALLOC(w, h, fixed_y_t); |
439 fixed_y_t* const target_y = SAFE_ALLOC(w, h, fixed_y_t); | 445 fixed_y_t* const target_y_base = SAFE_ALLOC(w, h, fixed_y_t); |
440 fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t); | 446 fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t); |
441 fixed_t* const best_uv = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); | 447 fixed_t* const best_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); |
442 fixed_t* const target_uv = 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); |
443 fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t); | 449 fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t); |
| 450 fixed_y_t* best_y = best_y_base; |
| 451 fixed_y_t* target_y = target_y_base; |
| 452 fixed_t* best_uv = best_uv_base; |
| 453 fixed_t* target_uv = target_uv_base; |
444 int ok; | 454 int ok; |
445 int diff_sum = 0; | 455 int diff_sum = 0; |
446 const int first_diff_threshold = (int)(2.5 * w * h); | 456 const int first_diff_threshold = (int)(2.5 * w * h); |
447 const int min_improvement = 5; // stop if improvement is below this % | 457 const int min_improvement = 5; // stop if improvement is below this % |
448 const int min_first_improvement = 80; | 458 const int min_first_improvement = 80; |
449 | 459 |
450 if (best_y == NULL || best_uv == NULL || | 460 if (best_y_base == NULL || best_uv_base == NULL || |
451 target_y == NULL || target_uv == NULL || | 461 target_y_base == NULL || target_uv_base == NULL || |
452 best_rgb_y == NULL || best_rgb_uv == NULL || | 462 best_rgb_y == NULL || best_rgb_uv == NULL || |
453 tmp_buffer == NULL) { | 463 tmp_buffer == NULL) { |
454 ok = WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); | 464 ok = WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); |
455 goto End; | 465 goto End; |
456 } | 466 } |
457 assert(picture->width >= kMinDimensionIterativeConversion); | 467 assert(picture->width >= kMinDimensionIterativeConversion); |
458 assert(picture->height >= kMinDimensionIterativeConversion); | 468 assert(picture->height >= kMinDimensionIterativeConversion); |
459 | 469 |
460 // Import RGB samples to W/RGB representation. | 470 // Import RGB samples to W/RGB representation. |
461 for (j = 0; j < picture->height; j += 2) { | 471 for (j = 0; j < picture->height; j += 2) { |
462 const int is_last_row = (j == picture->height - 1); | 472 const int is_last_row = (j == picture->height - 1); |
463 fixed_y_t* const src1 = tmp_buffer; | 473 fixed_y_t* const src1 = tmp_buffer; |
464 fixed_y_t* const src2 = tmp_buffer + 3 * w; | 474 fixed_y_t* const src2 = tmp_buffer + 3 * w; |
465 const int off1 = j * rgb_stride; | |
466 const int off2 = off1 + rgb_stride; | |
467 const int uv_off = (j >> 1) * 3 * uv_w; | |
468 fixed_y_t* const dst_y = best_y + j * w; | |
469 | 475 |
470 // prepare two rows of input | 476 // prepare two rows of input |
471 ImportOneRow(r_ptr + off1, g_ptr + off1, b_ptr + off1, | 477 ImportOneRow(r_ptr, g_ptr, b_ptr, step, picture->width, src1); |
472 step, picture->width, src1); | |
473 if (!is_last_row) { | 478 if (!is_last_row) { |
474 ImportOneRow(r_ptr + off2, g_ptr + off2, b_ptr + off2, | 479 ImportOneRow(r_ptr + rgb_stride, g_ptr + rgb_stride, b_ptr + rgb_stride, |
475 step, picture->width, src2); | 480 step, picture->width, src2); |
476 } else { | 481 } else { |
477 memcpy(src2, src1, 3 * w * sizeof(*src2)); | 482 memcpy(src2, src1, 3 * w * sizeof(*src2)); |
478 } | 483 } |
479 UpdateW(src1, target_y + (j + 0) * w, w); | 484 UpdateW(src1, target_y, w); |
480 UpdateW(src2, target_y + (j + 1) * w, w); | 485 UpdateW(src2, target_y + w, w); |
481 diff_sum += UpdateChroma(src1, src2, target_uv + uv_off, dst_y, uv_w); | 486 diff_sum += UpdateChroma(src1, src2, target_uv, best_y, uv_w); |
482 memcpy(best_uv + uv_off, target_uv + uv_off, 3 * uv_w * sizeof(*best_uv)); | 487 memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv)); |
483 memcpy(dst_y + w, dst_y, w * sizeof(*dst_y)); | 488 memcpy(best_y + w, best_y, w * sizeof(*best_y)); |
| 489 best_y += 2 * w; |
| 490 best_uv += 3 * uv_w; |
| 491 target_y += 2 * w; |
| 492 target_uv += 3 * uv_w; |
| 493 r_ptr += 2 * rgb_stride; |
| 494 g_ptr += 2 * rgb_stride; |
| 495 b_ptr += 2 * rgb_stride; |
484 } | 496 } |
485 | 497 |
486 // Iterate and resolve clipping conflicts. | 498 // Iterate and resolve clipping conflicts. |
487 for (iter = 0; iter < kNumIterations; ++iter) { | 499 for (iter = 0; iter < kNumIterations; ++iter) { |
488 int k; | 500 int k; |
489 const fixed_t* cur_uv = best_uv; | 501 const fixed_t* cur_uv = best_uv_base; |
490 const fixed_t* prev_uv = best_uv; | 502 const fixed_t* prev_uv = best_uv_base; |
491 const int old_diff_sum = diff_sum; | 503 const int old_diff_sum = diff_sum; |
492 diff_sum = 0; | 504 diff_sum = 0; |
| 505 |
| 506 best_y = best_y_base; |
| 507 best_uv = best_uv_base; |
| 508 target_y = target_y_base; |
| 509 target_uv = target_uv_base; |
493 for (j = 0; j < h; j += 2) { | 510 for (j = 0; j < h; j += 2) { |
494 fixed_y_t* const src1 = tmp_buffer; | 511 fixed_y_t* const src1 = tmp_buffer; |
495 fixed_y_t* const src2 = tmp_buffer + 3 * w; | 512 fixed_y_t* const src2 = tmp_buffer + 3 * w; |
496 { | 513 { |
497 const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0); | 514 const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0); |
498 InterpolateTwoRows(best_y + j * w, prev_uv, cur_uv, next_uv, | 515 InterpolateTwoRows(best_y, prev_uv, cur_uv, next_uv, w, src1, src2); |
499 w, src1, src2); | |
500 prev_uv = cur_uv; | 516 prev_uv = cur_uv; |
501 cur_uv = next_uv; | 517 cur_uv = next_uv; |
502 } | 518 } |
503 | 519 |
504 UpdateW(src1, best_rgb_y + 0 * w, w); | 520 UpdateW(src1, best_rgb_y + 0 * w, w); |
505 UpdateW(src2, best_rgb_y + 1 * w, w); | 521 UpdateW(src2, best_rgb_y + 1 * w, w); |
506 diff_sum += UpdateChroma(src1, src2, best_rgb_uv, NULL, uv_w); | 522 diff_sum += UpdateChroma(src1, src2, best_rgb_uv, NULL, uv_w); |
507 | 523 |
508 // update two rows of Y and one row of RGB | 524 // update two rows of Y and one row of RGB |
509 for (i = 0; i < 2 * w; ++i) { | 525 for (i = 0; i < 2 * w; ++i) { |
510 const int off = i + j * w; | 526 const int diff_y = target_y[i] - best_rgb_y[i]; |
511 const int diff_y = target_y[off] - best_rgb_y[i]; | 527 const int new_y = (int)best_y[i] + diff_y; |
512 const int new_y = (int)best_y[off] + diff_y; | 528 best_y[i] = clip_y(new_y); |
513 best_y[off] = clip_y(new_y); | |
514 } | 529 } |
515 for (i = 0; i < uv_w; ++i) { | 530 for (i = 0; i < uv_w; ++i) { |
516 const int off = 3 * (i + (j >> 1) * uv_w); | 531 const int off = 3 * i; |
517 int W; | 532 int W; |
518 for (k = 0; k <= 2; ++k) { | 533 for (k = 0; k <= 2; ++k) { |
519 const int diff_uv = (int)target_uv[off + k] - best_rgb_uv[3 * i + k]; | 534 const int diff_uv = (int)target_uv[off + k] - best_rgb_uv[off + k]; |
520 best_uv[off + k] += diff_uv; | 535 best_uv[off + k] += diff_uv; |
521 } | 536 } |
522 W = RGBToGray(best_uv[off + 0], best_uv[off + 1], best_uv[off + 2]); | 537 W = RGBToGray(best_uv[off + 0], best_uv[off + 1], best_uv[off + 2]); |
523 for (k = 0; k <= 2; ++k) { | 538 for (k = 0; k <= 2; ++k) { |
524 best_uv[off + k] -= W; | 539 best_uv[off + k] -= W; |
525 } | 540 } |
526 } | 541 } |
| 542 best_y += 2 * w; |
| 543 best_uv += 3 * uv_w; |
| 544 target_y += 2 * w; |
| 545 target_uv += 3 * uv_w; |
527 } | 546 } |
528 // test exit condition | 547 // test exit condition |
529 if (diff_sum > 0) { | 548 if (diff_sum > 0) { |
530 const int improvement = 100 * abs(diff_sum - old_diff_sum) / diff_sum; | 549 const int improvement = 100 * abs(diff_sum - old_diff_sum) / diff_sum; |
531 // Check if first iteration gave good result already, without a large | 550 // Check if first iteration gave good result already, without a large |
532 // jump of improvement (otherwise it means we need to try few extra | 551 // jump of improvement (otherwise it means we need to try few extra |
533 // iterations, just to be sure). | 552 // iterations, just to be sure). |
534 if (iter == 0 && diff_sum < first_diff_threshold && | 553 if (iter == 0 && diff_sum < first_diff_threshold && |
535 improvement < min_first_improvement) { | 554 improvement < min_first_improvement) { |
536 break; | 555 break; |
537 } | 556 } |
538 // then, check if improvement is stalling. | 557 // then, check if improvement is stalling. |
539 if (improvement < min_improvement) { | 558 if (improvement < min_improvement) { |
540 break; | 559 break; |
541 } | 560 } |
542 } else { | 561 } else { |
543 break; | 562 break; |
544 } | 563 } |
545 } | 564 } |
546 | 565 |
547 // final reconstruction | 566 // final reconstruction |
548 ok = ConvertWRGBToYUV(best_y, best_uv, picture); | 567 ok = ConvertWRGBToYUV(best_y_base, best_uv_base, picture); |
549 | 568 |
550 End: | 569 End: |
551 WebPSafeFree(best_y); | 570 WebPSafeFree(best_y_base); |
552 WebPSafeFree(best_uv); | 571 WebPSafeFree(best_uv_base); |
553 WebPSafeFree(target_y); | 572 WebPSafeFree(target_y_base); |
554 WebPSafeFree(target_uv); | 573 WebPSafeFree(target_uv_base); |
555 WebPSafeFree(best_rgb_y); | 574 WebPSafeFree(best_rgb_y); |
556 WebPSafeFree(best_rgb_uv); | 575 WebPSafeFree(best_rgb_uv); |
557 WebPSafeFree(tmp_buffer); | 576 WebPSafeFree(tmp_buffer); |
558 return ok; | 577 return ok; |
559 } | 578 } |
560 #undef SAFE_ALLOC | 579 #undef SAFE_ALLOC |
561 | 580 |
562 //------------------------------------------------------------------------------ | 581 //------------------------------------------------------------------------------ |
563 // "Fast" regular RGB->YUV | 582 // "Fast" regular RGB->YUV |
564 | 583 |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
823 int width, | 842 int width, |
824 VP8Random* const rg) { | 843 VP8Random* const rg) { |
825 int i; | 844 int i; |
826 for (i = 0; i < width; i += 1, rgb += 4) { | 845 for (i = 0; i < width; i += 1, rgb += 4) { |
827 const int r = rgb[0], g = rgb[1], b = rgb[2]; | 846 const int r = rgb[0], g = rgb[1], b = rgb[2]; |
828 dst_u[i] = RGBToU(r, g, b, rg); | 847 dst_u[i] = RGBToU(r, g, b, rg); |
829 dst_v[i] = RGBToV(r, g, b, rg); | 848 dst_v[i] = RGBToV(r, g, b, rg); |
830 } | 849 } |
831 } | 850 } |
832 | 851 |
833 static int ImportYUVAFromRGBA(const uint8_t* const r_ptr, | 852 static int ImportYUVAFromRGBA(const uint8_t* r_ptr, |
834 const uint8_t* const g_ptr, | 853 const uint8_t* g_ptr, |
835 const uint8_t* const b_ptr, | 854 const uint8_t* b_ptr, |
836 const uint8_t* const a_ptr, | 855 const uint8_t* a_ptr, |
837 int step, // bytes per pixel | 856 int step, // bytes per pixel |
838 int rgb_stride, // bytes per scanline | 857 int rgb_stride, // bytes per scanline |
839 float dithering, | 858 float dithering, |
840 int use_iterative_conversion, | 859 int use_iterative_conversion, |
841 WebPPicture* const picture) { | 860 WebPPicture* const picture) { |
842 int y; | 861 int y; |
843 const int width = picture->width; | 862 const int width = picture->width; |
844 const int height = picture->height; | 863 const int height = picture->height; |
845 const int has_alpha = CheckNonOpaque(a_ptr, width, height, step, rgb_stride); | 864 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 | 865 const int is_rgb = (r_ptr < b_ptr); // otherwise it's bgr |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
893 use_dsp = 0; // can't use dsp in this case | 912 use_dsp = 0; // can't use dsp in this case |
894 } | 913 } |
895 WebPInitConvertARGBToYUV(); | 914 WebPInitConvertARGBToYUV(); |
896 InitGammaTables(); | 915 InitGammaTables(); |
897 | 916 |
898 if (tmp_rgb == NULL) return 0; // malloc error | 917 if (tmp_rgb == NULL) return 0; // malloc error |
899 | 918 |
900 // Downsample Y/U/V planes, two rows at a time | 919 // Downsample Y/U/V planes, two rows at a time |
901 for (y = 0; y < (height >> 1); ++y) { | 920 for (y = 0; y < (height >> 1); ++y) { |
902 int rows_have_alpha = has_alpha; | 921 int rows_have_alpha = has_alpha; |
903 const int off1 = (2 * y + 0) * rgb_stride; | |
904 const int off2 = (2 * y + 1) * rgb_stride; | |
905 if (use_dsp) { | 922 if (use_dsp) { |
906 if (is_rgb) { | 923 if (is_rgb) { |
907 WebPConvertRGB24ToY(r_ptr + off1, dst_y, width); | 924 WebPConvertRGB24ToY(r_ptr, dst_y, width); |
908 WebPConvertRGB24ToY(r_ptr + off2, dst_y + picture->y_stride, width); | 925 WebPConvertRGB24ToY(r_ptr + rgb_stride, |
| 926 dst_y + picture->y_stride, width); |
909 } else { | 927 } else { |
910 WebPConvertBGR24ToY(b_ptr + off1, dst_y, width); | 928 WebPConvertBGR24ToY(b_ptr, dst_y, width); |
911 WebPConvertBGR24ToY(b_ptr + off2, dst_y + picture->y_stride, width); | 929 WebPConvertBGR24ToY(b_ptr + rgb_stride, |
| 930 dst_y + picture->y_stride, width); |
912 } | 931 } |
913 } else { | 932 } else { |
914 ConvertRowToY(r_ptr + off1, g_ptr + off1, b_ptr + off1, step, | 933 ConvertRowToY(r_ptr, g_ptr, b_ptr, step, dst_y, width, rg); |
915 dst_y, width, rg); | 934 ConvertRowToY(r_ptr + rgb_stride, |
916 ConvertRowToY(r_ptr + off2, g_ptr + off2, b_ptr + off2, step, | 935 g_ptr + rgb_stride, |
| 936 b_ptr + rgb_stride, step, |
917 dst_y + picture->y_stride, width, rg); | 937 dst_y + picture->y_stride, width, rg); |
918 } | 938 } |
919 dst_y += 2 * picture->y_stride; | 939 dst_y += 2 * picture->y_stride; |
920 if (has_alpha) { | 940 if (has_alpha) { |
921 rows_have_alpha &= !WebPExtractAlpha(a_ptr + off1, rgb_stride, | 941 rows_have_alpha &= !WebPExtractAlpha(a_ptr, rgb_stride, width, 2, |
922 width, 2, | |
923 dst_a, picture->a_stride); | 942 dst_a, picture->a_stride); |
924 dst_a += 2 * picture->a_stride; | 943 dst_a += 2 * picture->a_stride; |
925 } | 944 } |
926 // Collect averaged R/G/B(/A) | 945 // Collect averaged R/G/B(/A) |
927 if (!rows_have_alpha) { | 946 if (!rows_have_alpha) { |
928 AccumulateRGB(r_ptr + off1, g_ptr + off1, b_ptr + off1, | 947 AccumulateRGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, tmp_rgb, width); |
929 step, rgb_stride, tmp_rgb, width); | |
930 } else { | 948 } else { |
931 AccumulateRGBA(r_ptr + off1, g_ptr + off1, b_ptr + off1, a_ptr + off1, | 949 AccumulateRGBA(r_ptr, g_ptr, b_ptr, a_ptr, rgb_stride, tmp_rgb, width); |
932 rgb_stride, tmp_rgb, width); | |
933 } | 950 } |
934 // Convert to U/V | 951 // Convert to U/V |
935 if (rg == NULL) { | 952 if (rg == NULL) { |
936 WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width); | 953 WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width); |
937 } else { | 954 } else { |
938 ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg); | 955 ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg); |
939 } | 956 } |
940 dst_u += picture->uv_stride; | 957 dst_u += picture->uv_stride; |
941 dst_v += picture->uv_stride; | 958 dst_v += picture->uv_stride; |
| 959 r_ptr += 2 * rgb_stride; |
| 960 b_ptr += 2 * rgb_stride; |
| 961 g_ptr += 2 * rgb_stride; |
| 962 if (has_alpha) a_ptr += 2 * rgb_stride; |
942 } | 963 } |
943 if (height & 1) { // extra last row | 964 if (height & 1) { // extra last row |
944 const int off = 2 * y * rgb_stride; | |
945 int row_has_alpha = has_alpha; | 965 int row_has_alpha = has_alpha; |
946 if (use_dsp) { | 966 if (use_dsp) { |
947 if (r_ptr < b_ptr) { | 967 if (r_ptr < b_ptr) { |
948 WebPConvertRGB24ToY(r_ptr + off, dst_y, width); | 968 WebPConvertRGB24ToY(r_ptr, dst_y, width); |
949 } else { | 969 } else { |
950 WebPConvertBGR24ToY(b_ptr + off, dst_y, width); | 970 WebPConvertBGR24ToY(b_ptr, dst_y, width); |
951 } | 971 } |
952 } else { | 972 } else { |
953 ConvertRowToY(r_ptr + off, g_ptr + off, b_ptr + off, step, | 973 ConvertRowToY(r_ptr, g_ptr, b_ptr, step, dst_y, width, rg); |
954 dst_y, width, rg); | |
955 } | 974 } |
956 if (row_has_alpha) { | 975 if (row_has_alpha) { |
957 row_has_alpha &= !WebPExtractAlpha(a_ptr + off, 0, width, 1, dst_a, 0); | 976 row_has_alpha &= !WebPExtractAlpha(a_ptr, 0, width, 1, dst_a, 0); |
958 } | 977 } |
959 // Collect averaged R/G/B(/A) | 978 // Collect averaged R/G/B(/A) |
960 if (!row_has_alpha) { | 979 if (!row_has_alpha) { |
961 // Collect averaged R/G/B | 980 // Collect averaged R/G/B |
962 AccumulateRGB(r_ptr + off, g_ptr + off, b_ptr + off, | 981 AccumulateRGB(r_ptr, g_ptr, b_ptr, step, /* rgb_stride = */ 0, |
963 step, /* rgb_stride = */ 0, tmp_rgb, width); | 982 tmp_rgb, width); |
964 } else { | 983 } else { |
965 AccumulateRGBA(r_ptr + off, g_ptr + off, b_ptr + off, a_ptr + off, | 984 AccumulateRGBA(r_ptr, g_ptr, b_ptr, a_ptr, /* rgb_stride = */ 0, |
966 /* rgb_stride = */ 0, tmp_rgb, width); | 985 tmp_rgb, width); |
967 } | 986 } |
968 if (rg == NULL) { | 987 if (rg == NULL) { |
969 WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width); | 988 WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width); |
970 } else { | 989 } else { |
971 ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg); | 990 ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg); |
972 } | 991 } |
973 } | 992 } |
974 WebPSafeFree(tmp_rgb); | 993 WebPSafeFree(tmp_rgb); |
975 } | 994 } |
976 return 1; | 995 return 1; |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1079 return 1; | 1098 return 1; |
1080 } | 1099 } |
1081 | 1100 |
1082 //------------------------------------------------------------------------------ | 1101 //------------------------------------------------------------------------------ |
1083 // automatic import / conversion | 1102 // automatic import / conversion |
1084 | 1103 |
1085 static int Import(WebPPicture* const picture, | 1104 static int Import(WebPPicture* const picture, |
1086 const uint8_t* const rgb, int rgb_stride, | 1105 const uint8_t* const rgb, int rgb_stride, |
1087 int step, int swap_rb, int import_alpha) { | 1106 int step, int swap_rb, int import_alpha) { |
1088 int y; | 1107 int y; |
1089 const uint8_t* const r_ptr = rgb + (swap_rb ? 2 : 0); | 1108 const uint8_t* r_ptr = rgb + (swap_rb ? 2 : 0); |
1090 const uint8_t* const g_ptr = rgb + 1; | 1109 const uint8_t* g_ptr = rgb + 1; |
1091 const uint8_t* const b_ptr = rgb + (swap_rb ? 0 : 2); | 1110 const uint8_t* b_ptr = rgb + (swap_rb ? 0 : 2); |
1092 const uint8_t* const a_ptr = import_alpha ? rgb + 3 : NULL; | 1111 const uint8_t* a_ptr = import_alpha ? rgb + 3 : NULL; |
1093 const int width = picture->width; | 1112 const int width = picture->width; |
1094 const int height = picture->height; | 1113 const int height = picture->height; |
1095 | 1114 |
1096 if (!picture->use_argb) { | 1115 if (!picture->use_argb) { |
1097 return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride, | 1116 return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride, |
1098 0.f /* no dithering */, 0, picture); | 1117 0.f /* no dithering */, 0, picture); |
1099 } | 1118 } |
1100 if (!WebPPictureAlloc(picture)) return 0; | 1119 if (!WebPPictureAlloc(picture)) return 0; |
1101 | 1120 |
1102 VP8EncDspARGBInit(); | 1121 VP8EncDspARGBInit(); |
1103 | 1122 |
1104 if (import_alpha) { | 1123 if (import_alpha) { |
| 1124 uint32_t* dst = picture->argb; |
1105 assert(step == 4); | 1125 assert(step == 4); |
1106 for (y = 0; y < height; ++y) { | 1126 for (y = 0; y < height; ++y) { |
1107 uint32_t* const dst = &picture->argb[y * picture->argb_stride]; | 1127 VP8PackARGB(a_ptr, r_ptr, g_ptr, b_ptr, width, dst); |
1108 const int offset = y * rgb_stride; | 1128 a_ptr += rgb_stride; |
1109 VP8PackARGB(a_ptr + offset, r_ptr + offset, g_ptr + offset, | 1129 r_ptr += rgb_stride; |
1110 b_ptr + offset, width, dst); | 1130 g_ptr += rgb_stride; |
| 1131 b_ptr += rgb_stride; |
| 1132 dst += picture->argb_stride; |
1111 } | 1133 } |
1112 } else { | 1134 } else { |
| 1135 uint32_t* dst = picture->argb; |
1113 assert(step >= 3); | 1136 assert(step >= 3); |
1114 for (y = 0; y < height; ++y) { | 1137 for (y = 0; y < height; ++y) { |
1115 uint32_t* const dst = &picture->argb[y * picture->argb_stride]; | 1138 VP8PackRGB(r_ptr, g_ptr, b_ptr, width, step, dst); |
1116 const int offset = y * rgb_stride; | 1139 r_ptr += rgb_stride; |
1117 VP8PackRGB(r_ptr + offset, g_ptr + offset, b_ptr + offset, | 1140 g_ptr += rgb_stride; |
1118 width, step, dst); | 1141 b_ptr += rgb_stride; |
| 1142 dst += picture->argb_stride; |
1119 } | 1143 } |
1120 } | 1144 } |
1121 return 1; | 1145 return 1; |
1122 } | 1146 } |
1123 | 1147 |
1124 // Public API | 1148 // Public API |
1125 | 1149 |
1126 int WebPPictureImportRGB(WebPPicture* picture, | 1150 int WebPPictureImportRGB(WebPPicture* picture, |
1127 const uint8_t* rgb, int rgb_stride) { | 1151 const uint8_t* rgb, int rgb_stride) { |
1128 return (picture != NULL && rgb != NULL) | 1152 return (picture != NULL && rgb != NULL) |
(...skipping 30 matching lines...) Expand all Loading... |
1159 } | 1183 } |
1160 | 1184 |
1161 int WebPPictureImportBGRX(WebPPicture* picture, | 1185 int WebPPictureImportBGRX(WebPPicture* picture, |
1162 const uint8_t* rgba, int rgba_stride) { | 1186 const uint8_t* rgba, int rgba_stride) { |
1163 return (picture != NULL && rgba != NULL) | 1187 return (picture != NULL && rgba != NULL) |
1164 ? Import(picture, rgba, rgba_stride, 4, 1, 0) | 1188 ? Import(picture, rgba, rgba_stride, 4, 1, 0) |
1165 : 0; | 1189 : 0; |
1166 } | 1190 } |
1167 | 1191 |
1168 //------------------------------------------------------------------------------ | 1192 //------------------------------------------------------------------------------ |
OLD | NEW |