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

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

Issue 116213006: Update libwebp to 0.4.0 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: After Blink Roll Created 6 years, 11 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 | Annotate | Revision Log
« no previous file with comments | « third_party/libwebp/enc/alpha.c ('k') | third_party/libwebp/enc/backward_references.h » ('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 2011 Google Inc. All Rights Reserved. 1 // Copyright 2011 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 // Macroblock analysis 10 // Macroblock analysis
11 // 11 //
12 // Author: Skal (pascal.massimino@gmail.com) 12 // Author: Skal (pascal.massimino@gmail.com)
13 13
14 #include <stdlib.h> 14 #include <stdlib.h>
15 #include <string.h> 15 #include <string.h>
16 #include <assert.h> 16 #include <assert.h>
17 17
18 #include "./vp8enci.h" 18 #include "./vp8enci.h"
19 #include "./cost.h" 19 #include "./cost.h"
20 #include "../utils/utils.h" 20 #include "../utils/utils.h"
21 21
22 #if defined(__cplusplus) || defined(c_plusplus)
23 extern "C" {
24 #endif
25
26 #define MAX_ITERS_K_MEANS 6 22 #define MAX_ITERS_K_MEANS 6
27 23
28 //------------------------------------------------------------------------------ 24 //------------------------------------------------------------------------------
29 // Smooth the segment map by replacing isolated block by the majority of its 25 // Smooth the segment map by replacing isolated block by the majority of its
30 // neighbours. 26 // neighbours.
31 27
32 static void SmoothSegmentMap(VP8Encoder* const enc) { 28 static void SmoothSegmentMap(VP8Encoder* const enc) {
33 int n, x, y; 29 int n, x, y;
34 const int w = enc->mb_w_; 30 const int w = enc->mb_w_;
35 const int h = enc->mb_h_; 31 const int h = enc->mb_h_;
(...skipping 12 matching lines...) Expand all
48 cnt[mb[-w + 0].segment_]++; // top 44 cnt[mb[-w + 0].segment_]++; // top
49 cnt[mb[-w + 1].segment_]++; // top-right 45 cnt[mb[-w + 1].segment_]++; // top-right
50 cnt[mb[ - 1].segment_]++; // left 46 cnt[mb[ - 1].segment_]++; // left
51 cnt[mb[ + 1].segment_]++; // right 47 cnt[mb[ + 1].segment_]++; // right
52 cnt[mb[ w - 1].segment_]++; // bottom-left 48 cnt[mb[ w - 1].segment_]++; // bottom-left
53 cnt[mb[ w + 0].segment_]++; // bottom 49 cnt[mb[ w + 0].segment_]++; // bottom
54 cnt[mb[ w + 1].segment_]++; // bottom-right 50 cnt[mb[ w + 1].segment_]++; // bottom-right
55 for (n = 0; n < NUM_MB_SEGMENTS; ++n) { 51 for (n = 0; n < NUM_MB_SEGMENTS; ++n) {
56 if (cnt[n] >= majority_cnt_3_x_3_grid) { 52 if (cnt[n] >= majority_cnt_3_x_3_grid) {
57 majority_seg = n; 53 majority_seg = n;
54 break;
58 } 55 }
59 } 56 }
60 tmp[x + y * w] = majority_seg; 57 tmp[x + y * w] = majority_seg;
61 } 58 }
62 } 59 }
63 for (y = 1; y < h - 1; ++y) { 60 for (y = 1; y < h - 1; ++y) {
64 for (x = 1; x < w - 1; ++x) { 61 for (x = 1; x < w - 1; ++x) {
65 VP8MBInfo* const mb = &enc->mb_info_[x + w * y]; 62 VP8MBInfo* const mb = &enc->mb_info_[x + w * y];
66 mb->segment_ = tmp[x + y * w]; 63 mb->segment_ = tmp[x + y * w];
67 } 64 }
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
146 const int alphas[MAX_ALPHA + 1]) { 143 const int alphas[MAX_ALPHA + 1]) {
147 const int nb = enc->segment_hdr_.num_segments_; 144 const int nb = enc->segment_hdr_.num_segments_;
148 int centers[NUM_MB_SEGMENTS]; 145 int centers[NUM_MB_SEGMENTS];
149 int weighted_average = 0; 146 int weighted_average = 0;
150 int map[MAX_ALPHA + 1]; 147 int map[MAX_ALPHA + 1];
151 int a, n, k; 148 int a, n, k;
152 int min_a = 0, max_a = MAX_ALPHA, range_a; 149 int min_a = 0, max_a = MAX_ALPHA, range_a;
153 // 'int' type is ok for histo, and won't overflow 150 // 'int' type is ok for histo, and won't overflow
154 int accum[NUM_MB_SEGMENTS], dist_accum[NUM_MB_SEGMENTS]; 151 int accum[NUM_MB_SEGMENTS], dist_accum[NUM_MB_SEGMENTS];
155 152
153 assert(nb >= 1);
154
156 // bracket the input 155 // bracket the input
157 for (n = 0; n <= MAX_ALPHA && alphas[n] == 0; ++n) {} 156 for (n = 0; n <= MAX_ALPHA && alphas[n] == 0; ++n) {}
158 min_a = n; 157 min_a = n;
159 for (n = MAX_ALPHA; n > min_a && alphas[n] == 0; --n) {} 158 for (n = MAX_ALPHA; n > min_a && alphas[n] == 0; --n) {}
160 max_a = n; 159 max_a = n;
161 range_a = max_a - min_a; 160 range_a = max_a - min_a;
162 161
163 // Spread initial centers evenly 162 // Spread initial centers evenly
164 for (n = 1, k = 0; n < 2 * nb; n += 2) { 163 for (k = 0, n = 1; k < nb; ++k, n += 2) {
165 centers[k++] = min_a + (n * range_a) / (2 * nb); 164 assert(n < 2 * nb);
165 centers[k] = min_a + (n * range_a) / (2 * nb);
166 } 166 }
167 167
168 for (k = 0; k < MAX_ITERS_K_MEANS; ++k) { // few iters are enough 168 for (k = 0; k < MAX_ITERS_K_MEANS; ++k) { // few iters are enough
169 int total_weight; 169 int total_weight;
170 int displaced; 170 int displaced;
171 // Reset stats 171 // Reset stats
172 for (n = 0; n < nb; ++n) { 172 for (n = 0; n < nb; ++n) {
173 accum[n] = 0; 173 accum[n] = 0;
174 dist_accum[n] = 0; 174 dist_accum[n] = 0;
175 } 175 }
176 // Assign nearest center for each 'a' 176 // Assign nearest center for each 'a'
177 n = 0; // track the nearest center for current 'a' 177 n = 0; // track the nearest center for current 'a'
178 for (a = min_a; a <= max_a; ++a) { 178 for (a = min_a; a <= max_a; ++a) {
179 if (alphas[a]) { 179 if (alphas[a]) {
180 while (n < nb - 1 && abs(a - centers[n + 1]) < abs(a - centers[n])) { 180 while (n + 1 < nb && abs(a - centers[n + 1]) < abs(a - centers[n])) {
181 n++; 181 n++;
182 } 182 }
183 map[a] = n; 183 map[a] = n;
184 // accumulate contribution into best centroid 184 // accumulate contribution into best centroid
185 dist_accum[n] += a * alphas[a]; 185 dist_accum[n] += a * alphas[a];
186 accum[n] += alphas[a]; 186 accum[n] += alphas[a];
187 } 187 }
188 } 188 }
189 // All point are classified. Move the centroids to the 189 // All point are classified. Move the centroids to the
190 // center of their respective cloud. 190 // center of their respective cloud.
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 // this stage. 377 // this stage.
378 378
379 static void ResetAllMBInfo(VP8Encoder* const enc) { 379 static void ResetAllMBInfo(VP8Encoder* const enc) {
380 int n; 380 int n;
381 for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) { 381 for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) {
382 DefaultMBInfo(&enc->mb_info_[n]); 382 DefaultMBInfo(&enc->mb_info_[n]);
383 } 383 }
384 // Default susceptibilities. 384 // Default susceptibilities.
385 enc->dqm_[0].alpha_ = 0; 385 enc->dqm_[0].alpha_ = 0;
386 enc->dqm_[0].beta_ = 0; 386 enc->dqm_[0].beta_ = 0;
387 // Note: we can't compute this alpha_ / uv_alpha_. 387 // Note: we can't compute this alpha_ / uv_alpha_ -> set to default value.
388 enc->alpha_ = 0;
389 enc->uv_alpha_ = 0;
388 WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_); 390 WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_);
389 } 391 }
390 392
393 // struct used to collect job result
394 typedef struct {
395 WebPWorker worker;
396 int alphas[MAX_ALPHA + 1];
397 int alpha, uv_alpha;
398 VP8EncIterator it;
399 int delta_progress;
400 } SegmentJob;
401
402 // main work call
403 static int DoSegmentsJob(SegmentJob* const job, VP8EncIterator* const it) {
404 int ok = 1;
405 if (!VP8IteratorIsDone(it)) {
406 uint8_t tmp[32 + ALIGN_CST];
407 uint8_t* const scratch = (uint8_t*)DO_ALIGN(tmp);
408 do {
409 // Let's pretend we have perfect lossless reconstruction.
410 VP8IteratorImport(it, scratch);
411 MBAnalyze(it, job->alphas, &job->alpha, &job->uv_alpha);
412 ok = VP8IteratorProgress(it, job->delta_progress);
413 } while (ok && VP8IteratorNext(it));
414 }
415 return ok;
416 }
417
418 static void MergeJobs(const SegmentJob* const src, SegmentJob* const dst) {
419 int i;
420 for (i = 0; i <= MAX_ALPHA; ++i) dst->alphas[i] += src->alphas[i];
421 dst->alpha += src->alpha;
422 dst->uv_alpha += src->uv_alpha;
423 }
424
425 // initialize the job struct with some TODOs
426 static void InitSegmentJob(VP8Encoder* const enc, SegmentJob* const job,
427 int start_row, int end_row) {
428 WebPWorkerInit(&job->worker);
429 job->worker.data1 = job;
430 job->worker.data2 = &job->it;
431 job->worker.hook = (WebPWorkerHook)DoSegmentsJob;
432 VP8IteratorInit(enc, &job->it);
433 VP8IteratorSetRow(&job->it, start_row);
434 VP8IteratorSetCountDown(&job->it, (end_row - start_row) * enc->mb_w_);
435 memset(job->alphas, 0, sizeof(job->alphas));
436 job->alpha = 0;
437 job->uv_alpha = 0;
438 // only one of both jobs can record the progress, since we don't
439 // expect the user's hook to be multi-thread safe
440 job->delta_progress = (start_row == 0) ? 20 : 0;
441 }
442
443 // main entry point
391 int VP8EncAnalyze(VP8Encoder* const enc) { 444 int VP8EncAnalyze(VP8Encoder* const enc) {
392 int ok = 1; 445 int ok = 1;
393 const int do_segments = 446 const int do_segments =
394 enc->config_->emulate_jpeg_size || // We need the complexity evaluation. 447 enc->config_->emulate_jpeg_size || // We need the complexity evaluation.
395 (enc->segment_hdr_.num_segments_ > 1) || 448 (enc->segment_hdr_.num_segments_ > 1) ||
396 (enc->method_ == 0); // for method 0, we need preds_[] to be filled. 449 (enc->method_ == 0); // for method 0, we need preds_[] to be filled.
397 enc->alpha_ = 0;
398 enc->uv_alpha_ = 0;
399 if (do_segments) { 450 if (do_segments) {
400 int alphas[MAX_ALPHA + 1] = { 0 }; 451 const int last_row = enc->mb_h_;
401 VP8EncIterator it; 452 // We give a little more than a half work to the main thread.
402 453 const int split_row = (9 * last_row + 15) >> 4;
403 VP8IteratorInit(enc, &it); 454 const int total_mb = last_row * enc->mb_w_;
404 do { 455 #ifdef WEBP_USE_THREAD
405 VP8IteratorImport(&it); 456 const int kMinSplitRow = 2; // minimal rows needed for mt to be worth it
406 MBAnalyze(&it, alphas, &enc->alpha_, &enc->uv_alpha_); 457 const int do_mt = (enc->thread_level_ > 0) && (split_row >= kMinSplitRow);
407 ok = VP8IteratorProgress(&it, 20); 458 #else
408 // Let's pretend we have perfect lossless reconstruction. 459 const int do_mt = 0;
409 } while (ok && VP8IteratorNext(&it, it.yuv_in_)); 460 #endif
410 enc->alpha_ /= enc->mb_w_ * enc->mb_h_; 461 SegmentJob main_job;
411 enc->uv_alpha_ /= enc->mb_w_ * enc->mb_h_; 462 if (do_mt) {
412 if (ok) AssignSegments(enc, alphas); 463 SegmentJob side_job;
464 // Note the use of '&' instead of '&&' because we must call the functions
465 // no matter what.
466 InitSegmentJob(enc, &main_job, 0, split_row);
467 InitSegmentJob(enc, &side_job, split_row, last_row);
468 // we don't need to call Reset() on main_job.worker, since we're calling
469 // WebPWorkerExecute() on it
470 ok &= WebPWorkerReset(&side_job.worker);
471 // launch the two jobs in parallel
472 if (ok) {
473 WebPWorkerLaunch(&side_job.worker);
474 WebPWorkerExecute(&main_job.worker);
475 ok &= WebPWorkerSync(&side_job.worker);
476 ok &= WebPWorkerSync(&main_job.worker);
477 }
478 WebPWorkerEnd(&side_job.worker);
479 if (ok) MergeJobs(&side_job, &main_job); // merge results together
480 } else {
481 // Even for single-thread case, we use the generic Worker tools.
482 InitSegmentJob(enc, &main_job, 0, last_row);
483 WebPWorkerExecute(&main_job.worker);
484 ok &= WebPWorkerSync(&main_job.worker);
485 }
486 WebPWorkerEnd(&main_job.worker);
487 if (ok) {
488 enc->alpha_ = main_job.alpha / total_mb;
489 enc->uv_alpha_ = main_job.uv_alpha / total_mb;
490 AssignSegments(enc, main_job.alphas);
491 }
413 } else { // Use only one default segment. 492 } else { // Use only one default segment.
414 ResetAllMBInfo(enc); 493 ResetAllMBInfo(enc);
415 } 494 }
416 return ok; 495 return ok;
417 } 496 }
418 497
419 #if defined(__cplusplus) || defined(c_plusplus)
420 } // extern "C"
421 #endif
OLDNEW
« no previous file with comments | « third_party/libwebp/enc/alpha.c ('k') | third_party/libwebp/enc/backward_references.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698