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

Unified 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/libwebp/enc/analysis.c
diff --git a/third_party/libwebp/enc/analysis.c b/third_party/libwebp/enc/analysis.c
index 4ff3edd2a73c9fadb6ba5702fab66de1119b8e6f..7d4cfdc190fa5723a9b42ec05986b01aaae1dbcf 100644
--- a/third_party/libwebp/enc/analysis.c
+++ b/third_party/libwebp/enc/analysis.c
@@ -19,10 +19,6 @@
#include "./cost.h"
#include "../utils/utils.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
#define MAX_ITERS_K_MEANS 6
//------------------------------------------------------------------------------
@@ -55,6 +51,7 @@ static void SmoothSegmentMap(VP8Encoder* const enc) {
for (n = 0; n < NUM_MB_SEGMENTS; ++n) {
if (cnt[n] >= majority_cnt_3_x_3_grid) {
majority_seg = n;
+ break;
}
}
tmp[x + y * w] = majority_seg;
@@ -153,6 +150,8 @@ static void AssignSegments(VP8Encoder* const enc,
// 'int' type is ok for histo, and won't overflow
int accum[NUM_MB_SEGMENTS], dist_accum[NUM_MB_SEGMENTS];
+ assert(nb >= 1);
+
// bracket the input
for (n = 0; n <= MAX_ALPHA && alphas[n] == 0; ++n) {}
min_a = n;
@@ -161,8 +160,9 @@ static void AssignSegments(VP8Encoder* const enc,
range_a = max_a - min_a;
// Spread initial centers evenly
- for (n = 1, k = 0; n < 2 * nb; n += 2) {
- centers[k++] = min_a + (n * range_a) / (2 * nb);
+ for (k = 0, n = 1; k < nb; ++k, n += 2) {
+ assert(n < 2 * nb);
+ centers[k] = min_a + (n * range_a) / (2 * nb);
}
for (k = 0; k < MAX_ITERS_K_MEANS; ++k) { // few iters are enough
@@ -177,7 +177,7 @@ static void AssignSegments(VP8Encoder* const enc,
n = 0; // track the nearest center for current 'a'
for (a = min_a; a <= max_a; ++a) {
if (alphas[a]) {
- while (n < nb - 1 && abs(a - centers[n + 1]) < abs(a - centers[n])) {
+ while (n + 1 < nb && abs(a - centers[n + 1]) < abs(a - centers[n])) {
n++;
}
map[a] = n;
@@ -384,38 +384,114 @@ static void ResetAllMBInfo(VP8Encoder* const enc) {
// Default susceptibilities.
enc->dqm_[0].alpha_ = 0;
enc->dqm_[0].beta_ = 0;
- // Note: we can't compute this alpha_ / uv_alpha_.
+ // Note: we can't compute this alpha_ / uv_alpha_ -> set to default value.
+ enc->alpha_ = 0;
+ enc->uv_alpha_ = 0;
WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_);
}
+// struct used to collect job result
+typedef struct {
+ WebPWorker worker;
+ int alphas[MAX_ALPHA + 1];
+ int alpha, uv_alpha;
+ VP8EncIterator it;
+ int delta_progress;
+} SegmentJob;
+
+// main work call
+static int DoSegmentsJob(SegmentJob* const job, VP8EncIterator* const it) {
+ int ok = 1;
+ if (!VP8IteratorIsDone(it)) {
+ uint8_t tmp[32 + ALIGN_CST];
+ uint8_t* const scratch = (uint8_t*)DO_ALIGN(tmp);
+ do {
+ // Let's pretend we have perfect lossless reconstruction.
+ VP8IteratorImport(it, scratch);
+ MBAnalyze(it, job->alphas, &job->alpha, &job->uv_alpha);
+ ok = VP8IteratorProgress(it, job->delta_progress);
+ } while (ok && VP8IteratorNext(it));
+ }
+ return ok;
+}
+
+static void MergeJobs(const SegmentJob* const src, SegmentJob* const dst) {
+ int i;
+ for (i = 0; i <= MAX_ALPHA; ++i) dst->alphas[i] += src->alphas[i];
+ dst->alpha += src->alpha;
+ dst->uv_alpha += src->uv_alpha;
+}
+
+// initialize the job struct with some TODOs
+static void InitSegmentJob(VP8Encoder* const enc, SegmentJob* const job,
+ int start_row, int end_row) {
+ WebPWorkerInit(&job->worker);
+ job->worker.data1 = job;
+ job->worker.data2 = &job->it;
+ job->worker.hook = (WebPWorkerHook)DoSegmentsJob;
+ VP8IteratorInit(enc, &job->it);
+ VP8IteratorSetRow(&job->it, start_row);
+ VP8IteratorSetCountDown(&job->it, (end_row - start_row) * enc->mb_w_);
+ memset(job->alphas, 0, sizeof(job->alphas));
+ job->alpha = 0;
+ job->uv_alpha = 0;
+ // only one of both jobs can record the progress, since we don't
+ // expect the user's hook to be multi-thread safe
+ job->delta_progress = (start_row == 0) ? 20 : 0;
+}
+
+// main entry point
int VP8EncAnalyze(VP8Encoder* const enc) {
int ok = 1;
const int do_segments =
enc->config_->emulate_jpeg_size || // We need the complexity evaluation.
(enc->segment_hdr_.num_segments_ > 1) ||
(enc->method_ == 0); // for method 0, we need preds_[] to be filled.
- enc->alpha_ = 0;
- enc->uv_alpha_ = 0;
if (do_segments) {
- int alphas[MAX_ALPHA + 1] = { 0 };
- VP8EncIterator it;
-
- VP8IteratorInit(enc, &it);
- do {
- VP8IteratorImport(&it);
- MBAnalyze(&it, alphas, &enc->alpha_, &enc->uv_alpha_);
- ok = VP8IteratorProgress(&it, 20);
- // Let's pretend we have perfect lossless reconstruction.
- } while (ok && VP8IteratorNext(&it, it.yuv_in_));
- enc->alpha_ /= enc->mb_w_ * enc->mb_h_;
- enc->uv_alpha_ /= enc->mb_w_ * enc->mb_h_;
- if (ok) AssignSegments(enc, alphas);
+ const int last_row = enc->mb_h_;
+ // We give a little more than a half work to the main thread.
+ const int split_row = (9 * last_row + 15) >> 4;
+ const int total_mb = last_row * enc->mb_w_;
+#ifdef WEBP_USE_THREAD
+ const int kMinSplitRow = 2; // minimal rows needed for mt to be worth it
+ const int do_mt = (enc->thread_level_ > 0) && (split_row >= kMinSplitRow);
+#else
+ const int do_mt = 0;
+#endif
+ SegmentJob main_job;
+ if (do_mt) {
+ SegmentJob side_job;
+ // Note the use of '&' instead of '&&' because we must call the functions
+ // no matter what.
+ InitSegmentJob(enc, &main_job, 0, split_row);
+ InitSegmentJob(enc, &side_job, split_row, last_row);
+ // we don't need to call Reset() on main_job.worker, since we're calling
+ // WebPWorkerExecute() on it
+ ok &= WebPWorkerReset(&side_job.worker);
+ // launch the two jobs in parallel
+ if (ok) {
+ WebPWorkerLaunch(&side_job.worker);
+ WebPWorkerExecute(&main_job.worker);
+ ok &= WebPWorkerSync(&side_job.worker);
+ ok &= WebPWorkerSync(&main_job.worker);
+ }
+ WebPWorkerEnd(&side_job.worker);
+ if (ok) MergeJobs(&side_job, &main_job); // merge results together
+ } else {
+ // Even for single-thread case, we use the generic Worker tools.
+ InitSegmentJob(enc, &main_job, 0, last_row);
+ WebPWorkerExecute(&main_job.worker);
+ ok &= WebPWorkerSync(&main_job.worker);
+ }
+ WebPWorkerEnd(&main_job.worker);
+ if (ok) {
+ enc->alpha_ = main_job.alpha / total_mb;
+ enc->uv_alpha_ = main_job.uv_alpha / total_mb;
+ AssignSegments(enc, main_job.alphas);
+ }
} else { // Use only one default segment.
ResetAllMBInfo(enc);
}
return ok;
}
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
« 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