mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-26 05:38:22 +01:00
Implement progress report (and user abort)
New cwebp flag is -progress Change-Id: Ied872cca13f512036860783bbee1bdbccad72768
This commit is contained in:
parent
eda520a92e
commit
30971c9e95
7
README
7
README
@ -127,6 +127,7 @@ options:
|
|||||||
-h / -help ............ short help
|
-h / -help ............ short help
|
||||||
-H / -longhelp ........ long help
|
-H / -longhelp ........ long help
|
||||||
-q <float> ............. quality factor (0:small..100:big)
|
-q <float> ............. quality factor (0:small..100:big)
|
||||||
|
-alpha_q <int> ......... Transparency-compression quality (0..100)
|
||||||
-preset <string> ....... Preset setting, one of:
|
-preset <string> ....... Preset setting, one of:
|
||||||
default, photo, picture,
|
default, photo, picture,
|
||||||
drawing, icon, text
|
drawing, icon, text
|
||||||
@ -141,20 +142,22 @@ options:
|
|||||||
-strong ................ use strong filter instead of simple.
|
-strong ................ use strong filter instead of simple.
|
||||||
-partition_limit <int> . limit quality to fit the 512k limit on
|
-partition_limit <int> . limit quality to fit the 512k limit on
|
||||||
the first partition (0=no degradation ... 100=full)
|
the first partition (0=no degradation ... 100=full)
|
||||||
-alpha_comp <int> ...... set the transparency-compression
|
|
||||||
-noalpha ............... discard any transparency information.
|
|
||||||
-pass <int> ............ analysis pass number (1..10)
|
-pass <int> ............ analysis pass number (1..10)
|
||||||
-partitions <int> ...... number of partitions to use (0..3)
|
-partitions <int> ...... number of partitions to use (0..3)
|
||||||
-crop <x> <y> <w> <h> .. crop picture with the given rectangle
|
-crop <x> <y> <w> <h> .. crop picture with the given rectangle
|
||||||
-resize <w> <h> ........ resize picture (after any cropping)
|
-resize <w> <h> ........ resize picture (after any cropping)
|
||||||
-map <int> ............. print map of extra info.
|
-map <int> ............. print map of extra info.
|
||||||
-d <file.pgm> .......... dump the compressed output (PGM file).
|
-d <file.pgm> .......... dump the compressed output (PGM file).
|
||||||
|
-alpha_method <int> .... Transparency-compression method (0..1)
|
||||||
|
-noalpha ............... discard any transparency information.
|
||||||
|
|
||||||
-short ................. condense printed message
|
-short ................. condense printed message
|
||||||
-quiet ................. don't print anything.
|
-quiet ................. don't print anything.
|
||||||
-version ............... print version number and exit.
|
-version ............... print version number and exit.
|
||||||
-noasm ................. disable all assembly optimizations.
|
-noasm ................. disable all assembly optimizations.
|
||||||
-v ..................... verbose, e.g. print encoding/decoding times
|
-v ..................... verbose, e.g. print encoding/decoding times
|
||||||
|
-progress .............. report encoding progress
|
||||||
|
|
||||||
|
|
||||||
Experimental Options:
|
Experimental Options:
|
||||||
-size <int> ............ Target size (in bytes)
|
-size <int> ............ Target size (in bytes)
|
||||||
|
@ -641,6 +641,15 @@ static int DumpPicture(const WebPPicture* const picture, const char* PGM_name) {
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static int ProgressReport(int percent, const WebPPicture* const picture) {
|
||||||
|
printf("[%s]: %3d %% \r",
|
||||||
|
(char*)picture->stats->user_data, percent);
|
||||||
|
fflush(stdout);
|
||||||
|
return 1; // all ok
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static void HelpShort(void) {
|
static void HelpShort(void) {
|
||||||
printf("Usage:\n\n");
|
printf("Usage:\n\n");
|
||||||
printf(" cwebp [options] -q quality input.png -o output.webp\n\n");
|
printf(" cwebp [options] -q quality input.png -o output.webp\n\n");
|
||||||
@ -702,6 +711,7 @@ static void HelpLong(void) {
|
|||||||
#endif
|
#endif
|
||||||
printf(" -v ..................... verbose, e.g. print encoding/decoding "
|
printf(" -v ..................... verbose, e.g. print encoding/decoding "
|
||||||
"times\n");
|
"times\n");
|
||||||
|
printf(" -progress .............. report encoding progress\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("Experimental Options:\n");
|
printf("Experimental Options:\n");
|
||||||
printf(" -af .................... auto-adjust filter strength.\n");
|
printf(" -af .................... auto-adjust filter strength.\n");
|
||||||
@ -727,7 +737,8 @@ static const char* const kErrorMessages[] = {
|
|||||||
"in the manual (`man cwebp`)",
|
"in the manual (`man cwebp`)",
|
||||||
"PARTITION_OVERFLOW: Partition is too big to fit 16M",
|
"PARTITION_OVERFLOW: Partition is too big to fit 16M",
|
||||||
"BAD_WRITE: Picture writer returned an I/O error",
|
"BAD_WRITE: Picture writer returned an I/O error",
|
||||||
"FILE_TOO_BIG: File would be too big to fit in 4G"
|
"FILE_TOO_BIG: File would be too big to fit in 4G",
|
||||||
|
"USER_ABORT: encoding abort requested by user"
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@ -741,6 +752,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
int keep_alpha = 1;
|
int keep_alpha = 1;
|
||||||
int crop = 0, crop_x = 0, crop_y = 0, crop_w = 0, crop_h = 0;
|
int crop = 0, crop_x = 0, crop_y = 0, crop_w = 0, crop_h = 0;
|
||||||
int resize_w = 0, resize_h = 0;
|
int resize_w = 0, resize_h = 0;
|
||||||
|
int show_progress = 0;
|
||||||
WebPPicture picture;
|
WebPPicture picture;
|
||||||
WebPConfig config;
|
WebPConfig config;
|
||||||
WebPAuxStats stats;
|
WebPAuxStats stats;
|
||||||
@ -833,6 +845,8 @@ int main(int argc, const char *argv[]) {
|
|||||||
printf("%d.%d.%d\n",
|
printf("%d.%d.%d\n",
|
||||||
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
|
(version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (!strcmp(argv[c], "-progress")) {
|
||||||
|
show_progress = 1;
|
||||||
} else if (!strcmp(argv[c], "-quiet")) {
|
} else if (!strcmp(argv[c], "-quiet")) {
|
||||||
quiet = 1;
|
quiet = 1;
|
||||||
} else if (!strcmp(argv[c], "-preset") && c < argc - 1) {
|
} else if (!strcmp(argv[c], "-preset") && c < argc - 1) {
|
||||||
@ -882,6 +896,8 @@ int main(int argc, const char *argv[]) {
|
|||||||
fprintf(stderr, "Error! Cannot read input picture\n");
|
fprintf(stderr, "Error! Cannot read input picture\n");
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
|
picture.progress_hook = (show_progress && !quiet) ? ProgressReport : NULL;
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
const double time = StopwatchReadAndReset(&stop_watch);
|
const double time = StopwatchReadAndReset(&stop_watch);
|
||||||
fprintf(stderr, "Time to read input: %.3fs\n", time);
|
fprintf(stderr, "Time to read input: %.3fs\n", time);
|
||||||
@ -908,6 +924,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
picture.stats = &stats;
|
picture.stats = &stats;
|
||||||
|
stats.user_data = (void*)in_file;
|
||||||
|
|
||||||
// Compress
|
// Compress
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
|
@ -156,6 +156,9 @@ Disable all assembly optimizations.
|
|||||||
.B \-v
|
.B \-v
|
||||||
Print extra information (encoding time in particular).
|
Print extra information (encoding time in particular).
|
||||||
.TP
|
.TP
|
||||||
|
.B \-progress
|
||||||
|
Report encoding progress in percent.
|
||||||
|
.TP
|
||||||
.B \-quiet
|
.B \-quiet
|
||||||
Do not print anything.
|
Do not print anything.
|
||||||
.TP
|
.TP
|
||||||
|
@ -46,7 +46,7 @@ int VP8EncFinishAlpha(VP8Encoder* enc) {
|
|||||||
enc->alpha_data_size_ = (uint32_t)tmp_size;
|
enc->alpha_data_size_ = (uint32_t)tmp_size;
|
||||||
enc->alpha_data_ = tmp_data;
|
enc->alpha_data_ = tmp_data;
|
||||||
}
|
}
|
||||||
return 1;
|
return WebPReportProgress(enc, enc->percent_ + 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VP8EncDeleteAlpha(VP8Encoder* enc) {
|
void VP8EncDeleteAlpha(VP8Encoder* enc) {
|
||||||
|
@ -339,6 +339,7 @@ static void MBAnalyze(VP8EncIterator* const it,
|
|||||||
// this stage.
|
// this stage.
|
||||||
|
|
||||||
int VP8EncAnalyze(VP8Encoder* const enc) {
|
int VP8EncAnalyze(VP8Encoder* const enc) {
|
||||||
|
int ok = 1;
|
||||||
int alphas[256] = { 0 };
|
int alphas[256] = { 0 };
|
||||||
VP8EncIterator it;
|
VP8EncIterator it;
|
||||||
|
|
||||||
@ -347,12 +348,13 @@ int VP8EncAnalyze(VP8Encoder* const enc) {
|
|||||||
do {
|
do {
|
||||||
VP8IteratorImport(&it);
|
VP8IteratorImport(&it);
|
||||||
MBAnalyze(&it, alphas, &enc->uv_alpha_);
|
MBAnalyze(&it, alphas, &enc->uv_alpha_);
|
||||||
|
ok = VP8IteratorProgress(&it, 20);
|
||||||
// Let's pretend we have perfect lossless reconstruction.
|
// Let's pretend we have perfect lossless reconstruction.
|
||||||
} while (VP8IteratorNext(&it, it.yuv_in_));
|
} while (ok && VP8IteratorNext(&it, it.yuv_in_));
|
||||||
enc->uv_alpha_ /= enc->mb_w_ * enc->mb_h_;
|
enc->uv_alpha_ /= enc->mb_w_ * enc->mb_h_;
|
||||||
AssignSegments(enc, alphas);
|
if (ok) AssignSegments(enc, alphas);
|
||||||
|
|
||||||
return 1;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
@ -560,6 +560,7 @@ static void ResetAfterSkip(VP8EncIterator* const it) {
|
|||||||
|
|
||||||
int VP8EncLoop(VP8Encoder* const enc) {
|
int VP8EncLoop(VP8Encoder* const enc) {
|
||||||
int i, s, p;
|
int i, s, p;
|
||||||
|
int ok = 1;
|
||||||
VP8EncIterator it;
|
VP8EncIterator it;
|
||||||
VP8ModeScore info;
|
VP8ModeScore info;
|
||||||
const int dont_use_skip = !enc->proba_.use_skip_proba_;
|
const int dont_use_skip = !enc->proba_.use_skip_proba_;
|
||||||
@ -595,12 +596,17 @@ int VP8EncLoop(VP8Encoder* const enc) {
|
|||||||
StoreSideInfo(&it);
|
StoreSideInfo(&it);
|
||||||
VP8StoreFilterStats(&it);
|
VP8StoreFilterStats(&it);
|
||||||
VP8IteratorExport(&it);
|
VP8IteratorExport(&it);
|
||||||
} while (VP8IteratorNext(&it, it.yuv_out_));
|
ok = VP8IteratorProgress(&it, 20);
|
||||||
VP8AdjustFilterStrength(&it);
|
} while (ok && VP8IteratorNext(&it, it.yuv_out_));
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
VP8AdjustFilterStrength(&it);
|
||||||
|
}
|
||||||
|
|
||||||
// Finalize the partitions
|
// Finalize the partitions
|
||||||
for (p = 0; p < enc->num_parts_; ++p) {
|
for (p = 0; p < enc->num_parts_; ++p) {
|
||||||
VP8BitWriterFinish(enc->parts_ + p);
|
VP8BitWriterFinish(enc->parts_ + p);
|
||||||
|
ok &= !enc->parts_[p].error_;
|
||||||
}
|
}
|
||||||
// and byte counters
|
// and byte counters
|
||||||
if (enc->pic_->stats) {
|
if (enc->pic_->stats) {
|
||||||
@ -610,7 +616,10 @@ int VP8EncLoop(VP8Encoder* const enc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
if (!ok) { // need to do some memory cleanup
|
||||||
|
VP8EncFreeBitWriters(enc);
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@ -622,7 +631,7 @@ int VP8EncLoop(VP8Encoder* const enc) {
|
|||||||
#define kHeaderSizeEstimate (15 + 20 + 10) // TODO: fix better
|
#define kHeaderSizeEstimate (15 + 20 + 10) // TODO: fix better
|
||||||
|
|
||||||
static int OneStatPass(VP8Encoder* const enc, float q, int rd_opt, int nb_mbs,
|
static int OneStatPass(VP8Encoder* const enc, float q, int rd_opt, int nb_mbs,
|
||||||
float* const PSNR) {
|
float* const PSNR, int percent_delta) {
|
||||||
VP8EncIterator it;
|
VP8EncIterator it;
|
||||||
uint64_t size = 0;
|
uint64_t size = 0;
|
||||||
uint64_t distortion = 0;
|
uint64_t distortion = 0;
|
||||||
@ -651,6 +660,8 @@ static int OneStatPass(VP8Encoder* const enc, float q, int rd_opt, int nb_mbs,
|
|||||||
RecordResiduals(&it, &info);
|
RecordResiduals(&it, &info);
|
||||||
size += info.R;
|
size += info.R;
|
||||||
distortion += info.D;
|
distortion += info.D;
|
||||||
|
if (percent_delta && !VP8IteratorProgress(&it, percent_delta))
|
||||||
|
return 0;
|
||||||
} while (VP8IteratorNext(&it, it.yuv_out_) && --nb_mbs > 0);
|
} while (VP8IteratorNext(&it, it.yuv_out_) && --nb_mbs > 0);
|
||||||
size += FinalizeSkipProba(enc);
|
size += FinalizeSkipProba(enc);
|
||||||
size += FinalizeTokenProbas(enc);
|
size += FinalizeTokenProbas(enc);
|
||||||
@ -671,6 +682,10 @@ int VP8StatLoop(VP8Encoder* const enc) {
|
|||||||
(enc->config_->target_size > 0 || enc->config_->target_PSNR > 0);
|
(enc->config_->target_size > 0 || enc->config_->target_PSNR > 0);
|
||||||
const int fast_probe = (enc->method_ < 2 && !do_search);
|
const int fast_probe = (enc->method_ < 2 && !do_search);
|
||||||
float q = enc->config_->quality;
|
float q = enc->config_->quality;
|
||||||
|
const int max_passes = enc->config_->pass;
|
||||||
|
const int task_percent = 20;
|
||||||
|
const int percent_per_pass = (task_percent + max_passes / 2) / max_passes;
|
||||||
|
const int final_percent = enc->percent_ + task_percent;
|
||||||
int pass;
|
int pass;
|
||||||
int nb_mbs;
|
int nb_mbs;
|
||||||
|
|
||||||
@ -680,36 +695,38 @@ int VP8StatLoop(VP8Encoder* const enc) {
|
|||||||
|
|
||||||
// No target size: just do several pass without changing 'q'
|
// No target size: just do several pass without changing 'q'
|
||||||
if (!do_search) {
|
if (!do_search) {
|
||||||
for (pass = 0; pass < enc->config_->pass; ++pass) {
|
for (pass = 0; pass < max_passes; ++pass) {
|
||||||
const int rd_opt = (enc->method_ > 2);
|
const int rd_opt = (enc->method_ > 2);
|
||||||
OneStatPass(enc, q, rd_opt, nb_mbs, NULL);
|
if (!OneStatPass(enc, q, rd_opt, nb_mbs, NULL, percent_per_pass)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
} else {
|
||||||
}
|
// binary search for a size close to target
|
||||||
|
for (pass = 0; pass < max_passes && (dqs[pass] > 0); ++pass) {
|
||||||
// binary search for a size close to target
|
const int rd_opt = 1;
|
||||||
for (pass = 0; pass < enc->config_->pass && (dqs[pass] > 0); ++pass) {
|
float PSNR;
|
||||||
const int rd_opt = 1;
|
int criterion;
|
||||||
float PSNR;
|
const int size = OneStatPass(enc, q, rd_opt, nb_mbs, &PSNR,
|
||||||
int criterion;
|
percent_per_pass);
|
||||||
const int size = OneStatPass(enc, q, rd_opt, nb_mbs, &PSNR);
|
|
||||||
#if DEBUG_SEARCH
|
#if DEBUG_SEARCH
|
||||||
printf("#%d size=%d PSNR=%.2f q=%.2f\n", pass, size, PSNR, q);
|
printf("#%d size=%d PSNR=%.2f q=%.2f\n", pass, size, PSNR, q);
|
||||||
#endif
|
#endif
|
||||||
|
if (!size) return 0;
|
||||||
if (enc->config_->target_PSNR > 0) {
|
if (enc->config_->target_PSNR > 0) {
|
||||||
criterion = (PSNR < enc->config_->target_PSNR);
|
criterion = (PSNR < enc->config_->target_PSNR);
|
||||||
} else {
|
} else {
|
||||||
criterion = (size < enc->config_->target_size);
|
criterion = (size < enc->config_->target_size);
|
||||||
}
|
}
|
||||||
// dichotomize
|
// dichotomize
|
||||||
if (criterion) {
|
if (criterion) {
|
||||||
q += dqs[pass];
|
q += dqs[pass];
|
||||||
} else {
|
} else {
|
||||||
q -= dqs[pass];
|
q -= dqs[pass];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return WebPReportProgress(enc, final_percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -66,9 +66,18 @@ void VP8IteratorInit(VP8Encoder* const enc, VP8EncIterator* const it) {
|
|||||||
it->yuv_out2_ = enc->yuv_out2_;
|
it->yuv_out2_ = enc->yuv_out2_;
|
||||||
it->yuv_p_ = enc->yuv_p_;
|
it->yuv_p_ = enc->yuv_p_;
|
||||||
it->lf_stats_ = enc->lf_stats_;
|
it->lf_stats_ = enc->lf_stats_;
|
||||||
|
it->percent0_ = enc->percent_;
|
||||||
VP8IteratorReset(it);
|
VP8IteratorReset(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int VP8IteratorProgress(const VP8EncIterator* const it, int delta) {
|
||||||
|
if (delta && it->enc_->pic_->progress_hook) {
|
||||||
|
const int percent = it->percent0_ + delta * it->y_ / (it->enc_->mb_h_ - 1);
|
||||||
|
return WebPReportProgress(it->enc_, percent);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Import the source samples into the cache. Takes care of replicating
|
// Import the source samples into the cache. Takes care of replicating
|
||||||
// boundary pixels if necessary.
|
// boundary pixels if necessary.
|
||||||
|
@ -18,10 +18,6 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
|
||||||
|
|
||||||
#endif /* WEBP_EXPERIMENTAL_FEATURES */
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
void VP8EncInitLayer(VP8Encoder* const enc) {
|
void VP8EncInitLayer(VP8Encoder* const enc) {
|
||||||
@ -35,8 +31,6 @@ void VP8EncInitLayer(VP8Encoder* const enc) {
|
|||||||
|
|
||||||
void VP8EncCodeLayerBlock(VP8EncIterator* it) {
|
void VP8EncCodeLayerBlock(VP8EncIterator* it) {
|
||||||
(void)it; // remove a warning
|
(void)it; // remove a warning
|
||||||
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
|
||||||
#endif /* WEBP_EXPERIMENTAL_FEATURES */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int VP8EncFinishLayer(VP8Encoder* const enc) {
|
int VP8EncFinishLayer(VP8Encoder* const enc) {
|
||||||
|
@ -356,9 +356,20 @@ static size_t GeneratePartition0(VP8Encoder* const enc) {
|
|||||||
return !bw->error_;
|
return !bw->error_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VP8EncFreeBitWriters(VP8Encoder* const enc) {
|
||||||
|
int p;
|
||||||
|
VP8BitWriterWipeOut(&enc->bw_);
|
||||||
|
for (p = 0; p < enc->num_parts_; ++p) {
|
||||||
|
VP8BitWriterWipeOut(enc->parts_ + p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int VP8EncWrite(VP8Encoder* const enc) {
|
int VP8EncWrite(VP8Encoder* const enc) {
|
||||||
WebPPicture* const pic = enc->pic_;
|
WebPPicture* const pic = enc->pic_;
|
||||||
VP8BitWriter* const bw = &enc->bw_;
|
VP8BitWriter* const bw = &enc->bw_;
|
||||||
|
const int task_percent = 19;
|
||||||
|
const int percent_per_part = task_percent / enc->num_parts_;
|
||||||
|
const int final_percent = enc->percent_ + task_percent;
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
size_t vp8_size, pad, riff_size;
|
size_t vp8_size, pad, riff_size;
|
||||||
int p;
|
int p;
|
||||||
@ -399,7 +410,7 @@ int VP8EncWrite(VP8Encoder* const enc) {
|
|||||||
ok = ok && PutWebPHeaders(enc, size0, vp8_size, riff_size)
|
ok = ok && PutWebPHeaders(enc, size0, vp8_size, riff_size)
|
||||||
&& pic->writer(part0, size0, pic)
|
&& pic->writer(part0, size0, pic)
|
||||||
&& EmitPartitionsSize(enc, pic);
|
&& EmitPartitionsSize(enc, pic);
|
||||||
free((void*)part0);
|
VP8BitWriterWipeOut(bw); // will free the internal buffer.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Token partitions
|
// Token partitions
|
||||||
@ -408,7 +419,8 @@ int VP8EncWrite(VP8Encoder* const enc) {
|
|||||||
const size_t size = VP8BitWriterSize(enc->parts_ + p);
|
const size_t size = VP8BitWriterSize(enc->parts_ + p);
|
||||||
if (size)
|
if (size)
|
||||||
ok = ok && pic->writer(buf, size, pic);
|
ok = ok && pic->writer(buf, size, pic);
|
||||||
free((void*)buf);
|
VP8BitWriterWipeOut(enc->parts_ + p); // will free the internal buffer.
|
||||||
|
ok = ok && WebPReportProgress(enc, enc->percent_ + percent_per_part);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Padding byte
|
// Padding byte
|
||||||
@ -417,6 +429,7 @@ int VP8EncWrite(VP8Encoder* const enc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enc->coded_size_ = (int)(CHUNK_HEADER_SIZE + riff_size);
|
enc->coded_size_ = (int)(CHUNK_HEADER_SIZE + riff_size);
|
||||||
|
ok = ok && WebPReportProgress(enc, final_percent);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,6 +272,7 @@ typedef struct {
|
|||||||
LFStats* lf_stats_; // filter stats (borrowed from enc_)
|
LFStats* lf_stats_; // filter stats (borrowed from enc_)
|
||||||
int do_trellis_; // if true, perform extra level optimisation
|
int do_trellis_; // if true, perform extra level optimisation
|
||||||
int done_; // true when scan is finished
|
int done_; // true when scan is finished
|
||||||
|
int percent0_; // saved initial progress percent
|
||||||
} VP8EncIterator;
|
} VP8EncIterator;
|
||||||
|
|
||||||
// in iterator.c
|
// in iterator.c
|
||||||
@ -288,6 +289,9 @@ void VP8IteratorExport(const VP8EncIterator* const it);
|
|||||||
// it->yuv_out_ or it->yuv_in_.
|
// it->yuv_out_ or it->yuv_in_.
|
||||||
int VP8IteratorNext(VP8EncIterator* const it,
|
int VP8IteratorNext(VP8EncIterator* const it,
|
||||||
const uint8_t* const block_to_save);
|
const uint8_t* const block_to_save);
|
||||||
|
// Report progression based on macroblock rows. Return 0 for user-abort request.
|
||||||
|
int VP8IteratorProgress(const VP8EncIterator* const it,
|
||||||
|
int final_delta_percent);
|
||||||
// Intra4x4 iterations
|
// Intra4x4 iterations
|
||||||
void VP8IteratorStartI4(VP8EncIterator* const it);
|
void VP8IteratorStartI4(VP8EncIterator* const it);
|
||||||
// returns true if not done.
|
// returns true if not done.
|
||||||
@ -330,6 +334,8 @@ struct VP8Encoder {
|
|||||||
VP8BitWriter bw_; // part0
|
VP8BitWriter bw_; // part0
|
||||||
VP8BitWriter parts_[MAX_NUM_PARTITIONS]; // token partitions
|
VP8BitWriter parts_[MAX_NUM_PARTITIONS]; // token partitions
|
||||||
|
|
||||||
|
int percent_; // for progress
|
||||||
|
|
||||||
// transparency blob
|
// transparency blob
|
||||||
int has_alpha_;
|
int has_alpha_;
|
||||||
uint8_t* alpha_data_; // non-NULL if transparency is present
|
uint8_t* alpha_data_; // non-NULL if transparency is present
|
||||||
@ -401,6 +407,8 @@ void VP8CodeIntraModes(VP8Encoder* const enc);
|
|||||||
// and appending an assembly of all the pre-coded token partitions.
|
// and appending an assembly of all the pre-coded token partitions.
|
||||||
// Return true if everything is ok.
|
// Return true if everything is ok.
|
||||||
int VP8EncWrite(VP8Encoder* const enc);
|
int VP8EncWrite(VP8Encoder* const enc);
|
||||||
|
// Release memory allocated for bit-writing in VP8EncLoop & seq.
|
||||||
|
void VP8EncFreeBitWriters(VP8Encoder* const enc);
|
||||||
|
|
||||||
// in frame.c
|
// in frame.c
|
||||||
extern const uint8_t VP8EncBands[16 + 1];
|
extern const uint8_t VP8EncBands[16 + 1];
|
||||||
@ -422,6 +430,7 @@ int VP8StatLoop(VP8Encoder* const enc);
|
|||||||
// in webpenc.c
|
// in webpenc.c
|
||||||
// Assign an error code to a picture. Return false for convenience.
|
// Assign an error code to a picture. Return false for convenience.
|
||||||
int WebPEncodingSetError(WebPPicture* const pic, WebPEncodingError error);
|
int WebPEncodingSetError(WebPPicture* const pic, WebPEncodingError error);
|
||||||
|
int WebPReportProgress(VP8Encoder* const enc, int percent);
|
||||||
|
|
||||||
// in analysis.c
|
// in analysis.c
|
||||||
// Main analysis loop. Decides the segmentations and complexity.
|
// Main analysis loop. Decides the segmentations and complexity.
|
||||||
|
@ -242,6 +242,7 @@ static VP8Encoder* InitEncoder(const WebPConfig* const config,
|
|||||||
enc->config_ = config;
|
enc->config_ = config;
|
||||||
enc->profile_ = use_filter ? ((config->filter_type == 1) ? 0 : 1) : 2;
|
enc->profile_ = use_filter ? ((config->filter_type == 1) ? 0 : 1) : 2;
|
||||||
enc->pic_ = picture;
|
enc->pic_ = picture;
|
||||||
|
enc->percent_ = 0;
|
||||||
|
|
||||||
MapConfigToTools(enc);
|
MapConfigToTools(enc);
|
||||||
VP8EncDspInit();
|
VP8EncDspInit();
|
||||||
@ -301,15 +302,28 @@ static void StoreStats(VP8Encoder* const enc) {
|
|||||||
stats->block_count[i] = enc->block_count_[i];
|
stats->block_count[i] = enc->block_count_[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
WebPReportProgress(enc, 100); // done!
|
||||||
}
|
}
|
||||||
|
|
||||||
int WebPEncodingSetError(WebPPicture* const pic, WebPEncodingError error) {
|
int WebPEncodingSetError(WebPPicture* const pic, WebPEncodingError error) {
|
||||||
assert((int)error <= VP8_ENC_ERROR_BAD_WRITE);
|
assert((int)error < VP8_ENC_ERROR_LAST);
|
||||||
assert((int)error >= VP8_ENC_OK);
|
assert((int)error >= VP8_ENC_OK);
|
||||||
pic->error_code = error;
|
pic->error_code = error;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int WebPReportProgress(VP8Encoder* const enc, int percent) {
|
||||||
|
if (percent != enc->percent_) {
|
||||||
|
WebPPicture* const pic = enc->pic_;
|
||||||
|
enc->percent_ = percent;
|
||||||
|
if (pic->progress_hook && !pic->progress_hook(percent, pic)) {
|
||||||
|
// user abort requested
|
||||||
|
WebPEncodingSetError(pic, VP8_ENC_ERROR_USER_ABORT);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1; // ok
|
||||||
|
}
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
int WebPEncode(const WebPConfig* const config, WebPPicture* const pic) {
|
int WebPEncode(const WebPConfig* const config, WebPPicture* const pic) {
|
||||||
@ -332,6 +346,7 @@ int WebPEncode(const WebPConfig* const config, WebPPicture* const pic) {
|
|||||||
|
|
||||||
enc = InitEncoder(config, pic);
|
enc = InitEncoder(config, pic);
|
||||||
if (enc == NULL) return 0; // pic->error is already set.
|
if (enc == NULL) return 0; // pic->error is already set.
|
||||||
|
// Note: each of the tasks below account for 20% in the progress report.
|
||||||
ok = VP8EncAnalyze(enc)
|
ok = VP8EncAnalyze(enc)
|
||||||
&& VP8StatLoop(enc)
|
&& VP8StatLoop(enc)
|
||||||
&& VP8EncLoop(enc)
|
&& VP8EncLoop(enc)
|
||||||
@ -341,6 +356,9 @@ int WebPEncode(const WebPConfig* const config, WebPPicture* const pic) {
|
|||||||
#endif
|
#endif
|
||||||
&& VP8EncWrite(enc);
|
&& VP8EncWrite(enc);
|
||||||
StoreStats(enc);
|
StoreStats(enc);
|
||||||
|
if (!ok) {
|
||||||
|
VP8EncFreeBitWriters(enc);
|
||||||
|
}
|
||||||
DeleteEncoder(enc);
|
DeleteEncoder(enc);
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
|
@ -179,6 +179,13 @@ int VP8BitWriterAppend(VP8BitWriter* const bw,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VP8BitWriterWipeOut(VP8BitWriter* const bw) {
|
||||||
|
if (bw) {
|
||||||
|
free(bw->buf_);
|
||||||
|
memset(bw, 0, sizeof(*bw));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
@ -27,18 +27,26 @@ struct VP8BitWriter {
|
|||||||
int32_t value_;
|
int32_t value_;
|
||||||
int run_; // number of outstanding bits
|
int run_; // number of outstanding bits
|
||||||
int nb_bits_; // number of pending bits
|
int nb_bits_; // number of pending bits
|
||||||
uint8_t* buf_;
|
uint8_t* buf_; // internal buffer. Re-allocated regularly. Not owned.
|
||||||
size_t pos_;
|
size_t pos_;
|
||||||
size_t max_pos_;
|
size_t max_pos_;
|
||||||
int error_; // true in case of error
|
int error_; // true in case of error
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Initialize the object. Allocates some initial memory based on expected_size.
|
||||||
int VP8BitWriterInit(VP8BitWriter* const bw, size_t expected_size);
|
int VP8BitWriterInit(VP8BitWriter* const bw, size_t expected_size);
|
||||||
|
// Finalize the bitstream coding. Returns a pointer to the internal buffer.
|
||||||
uint8_t* VP8BitWriterFinish(VP8BitWriter* const bw);
|
uint8_t* VP8BitWriterFinish(VP8BitWriter* const bw);
|
||||||
|
// Release any pending memory and zeroes the object. Not a mandatory call.
|
||||||
|
// Only useful in case of error, when the internal buffer hasn't been grabbed!
|
||||||
|
void VP8BitWriterWipeOut(VP8BitWriter* const bw);
|
||||||
|
|
||||||
int VP8PutBit(VP8BitWriter* const bw, int bit, int prob);
|
int VP8PutBit(VP8BitWriter* const bw, int bit, int prob);
|
||||||
int VP8PutBitUniform(VP8BitWriter* const bw, int bit);
|
int VP8PutBitUniform(VP8BitWriter* const bw, int bit);
|
||||||
void VP8PutValue(VP8BitWriter* const bw, int value, int nb_bits);
|
void VP8PutValue(VP8BitWriter* const bw, int value, int nb_bits);
|
||||||
void VP8PutSignedValue(VP8BitWriter* const bw, int value, int nb_bits);
|
void VP8PutSignedValue(VP8BitWriter* const bw, int value, int nb_bits);
|
||||||
|
|
||||||
|
// Appends some bytes to the internal buffer. Data is copied.
|
||||||
int VP8BitWriterAppend(VP8BitWriter* const bw,
|
int VP8BitWriterAppend(VP8BitWriter* const bw,
|
||||||
const uint8_t* data, size_t size);
|
const uint8_t* data, size_t size);
|
||||||
|
|
||||||
@ -47,9 +55,11 @@ static WEBP_INLINE uint64_t VP8BitWriterPos(const VP8BitWriter* const bw) {
|
|||||||
return (uint64_t)(bw->pos_ + bw->run_) * 8 + 8 + bw->nb_bits_;
|
return (uint64_t)(bw->pos_ + bw->run_) * 8 + 8 + bw->nb_bits_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns a pointer to the internal buffer.
|
||||||
static WEBP_INLINE uint8_t* VP8BitWriterBuf(const VP8BitWriter* const bw) {
|
static WEBP_INLINE uint8_t* VP8BitWriterBuf(const VP8BitWriter* const bw) {
|
||||||
return bw->buf_;
|
return bw->buf_;
|
||||||
}
|
}
|
||||||
|
// Returns the size of the internal buffer.
|
||||||
static WEBP_INLINE size_t VP8BitWriterSize(const VP8BitWriter* const bw) {
|
static WEBP_INLINE size_t VP8BitWriterSize(const VP8BitWriter* const bw) {
|
||||||
return bw->pos_;
|
return bw->pos_;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define WEBP_ENCODER_ABI_VERSION 0x0002
|
#define WEBP_ENCODER_ABI_VERSION 0x0003
|
||||||
|
|
||||||
// Return the encoder's version number, packed in hexadecimal using 8bits for
|
// Return the encoder's version number, packed in hexadecimal using 8bits for
|
||||||
// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
|
// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
|
||||||
@ -72,7 +72,7 @@ typedef struct {
|
|||||||
int partition_limit; // quality degradation allowed to fit the 512k limit on
|
int partition_limit; // quality degradation allowed to fit the 512k limit on
|
||||||
// prediction modes coding (0=no degradation, 100=full)
|
// prediction modes coding (0=no degradation, 100=full)
|
||||||
int alpha_compression; // Algorithm for encoding the alpha plane (0 = none,
|
int alpha_compression; // Algorithm for encoding the alpha plane (0 = none,
|
||||||
// 1 = Backward reference counts encoded with
|
// 1 = backward reference counts encoded with
|
||||||
// arithmetic encoder). Default is 1.
|
// arithmetic encoder). Default is 1.
|
||||||
int alpha_quality; // Between 0 (smallest size) and 100 (lossless).
|
int alpha_quality; // Between 0 (smallest size) and 100 (lossless).
|
||||||
// Default is 100.
|
// Default is 100.
|
||||||
@ -134,6 +134,9 @@ typedef struct {
|
|||||||
|
|
||||||
int alpha_data_size; // size of the transparency data
|
int alpha_data_size; // size of the transparency data
|
||||||
int layer_data_size; // size of the enhancement layer data
|
int layer_data_size; // size of the enhancement layer data
|
||||||
|
|
||||||
|
void* user_data; // this field is free to be set to any value and
|
||||||
|
// used during callbacks (like progress-report e.g.).
|
||||||
} WebPAuxStats;
|
} WebPAuxStats;
|
||||||
|
|
||||||
// Signature for output function. Should return 1 if writing was successful.
|
// Signature for output function. Should return 1 if writing was successful.
|
||||||
@ -142,6 +145,10 @@ typedef struct {
|
|||||||
typedef int (*WebPWriterFunction)(const uint8_t* data, size_t data_size,
|
typedef int (*WebPWriterFunction)(const uint8_t* data, size_t data_size,
|
||||||
const WebPPicture* const picture);
|
const WebPPicture* const picture);
|
||||||
|
|
||||||
|
// Progress hook, called from time to time to report progress. It can return 0
|
||||||
|
// to request an abort of the encoding process, or 1 otherwise if all is OK.
|
||||||
|
typedef int (*WebPProgressHook)(int percent, const WebPPicture* const picture);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
// chroma sampling
|
// chroma sampling
|
||||||
WEBP_YUV420 = 0, // 4:2:0
|
WEBP_YUV420 = 0, // 4:2:0
|
||||||
@ -169,6 +176,8 @@ typedef enum {
|
|||||||
VP8_ENC_ERROR_PARTITION_OVERFLOW, // partition is bigger than 16M
|
VP8_ENC_ERROR_PARTITION_OVERFLOW, // partition is bigger than 16M
|
||||||
VP8_ENC_ERROR_BAD_WRITE, // error while flushing bytes
|
VP8_ENC_ERROR_BAD_WRITE, // error while flushing bytes
|
||||||
VP8_ENC_ERROR_FILE_TOO_BIG, // file is bigger than 4G
|
VP8_ENC_ERROR_FILE_TOO_BIG, // file is bigger than 4G
|
||||||
|
VP8_ENC_ERROR_USER_ABORT, // abort request by user
|
||||||
|
VP8_ENC_ERROR_LAST // list terminator. always last.
|
||||||
} WebPEncodingError;
|
} WebPEncodingError;
|
||||||
|
|
||||||
// maximum width/height allowed (inclusive), in pixels
|
// maximum width/height allowed (inclusive), in pixels
|
||||||
@ -205,6 +214,8 @@ struct WebPPicture {
|
|||||||
int uv0_stride;
|
int uv0_stride;
|
||||||
|
|
||||||
WebPEncodingError error_code; // error code in case of problem.
|
WebPEncodingError error_code; // error code in case of problem.
|
||||||
|
|
||||||
|
WebPProgressHook progress_hook; // if not NULL, called while encoding.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Internal, version-checked, entry point
|
// Internal, version-checked, entry point
|
||||||
|
Loading…
Reference in New Issue
Block a user