mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-25 13:18:22 +01:00
cwebp: Fix -print_psnr for near_lossless
The output was always 99dB because the lossless pipeline is not modifying the 'picture'. Changing that is not that simple because near_lossless impacts both VP8ApplyNearLossless() and ApplyPredictFilter(); the latter cannot be applied as is to the input and thus the final modified 'picture' cannot be easily retrieved without decoding the encoded bitstream. Hence ReadWebP() is called in cwebp.c on the encoded bitstream kept in memory to get the correct distortion. However -get_psnr returns a different distortion than get_disto for lossy encoding configurations because cwebp loads the source as YUV while get_disto directly reads it as RGB without conversion loss. Change-Id: I5c32cf8f89eb137973dc7eebda747682d921b8e2
This commit is contained in:
parent
cf2f88b38f
commit
def64e920f
112
examples/cwebp.c
112
examples/cwebp.c
@ -12,6 +12,7 @@
|
||||
//
|
||||
// Author: Skal (pascal.massimino@gmail.com)
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -23,6 +24,7 @@
|
||||
#include "../examples/example_util.h"
|
||||
#include "../imageio/image_dec.h"
|
||||
#include "../imageio/imageio_util.h"
|
||||
#include "../imageio/webpdec.h"
|
||||
#include "./stopwatch.h"
|
||||
#include "./unicode.h"
|
||||
#include "webp/encode.h"
|
||||
@ -148,7 +150,7 @@ static void PrintPercents(const int counts[4]) {
|
||||
int s;
|
||||
const int total = counts[0] + counts[1] + counts[2] + counts[3];
|
||||
for (s = 0; s < 4; ++s) {
|
||||
fprintf(stderr, "| %2d%%", (int)(100. * counts[s] / total + .5));
|
||||
fprintf(stderr, "| %3d%%", (int)(100. * counts[s] / total + .5));
|
||||
}
|
||||
fprintf(stderr, "| %7d\n", total);
|
||||
}
|
||||
@ -666,6 +668,7 @@ int main(int argc, const char* argv[]) {
|
||||
WebPConfig config;
|
||||
WebPAuxStats stats;
|
||||
WebPMemoryWriter memory_writer;
|
||||
int use_memory_writer;
|
||||
Metadata metadata;
|
||||
Stopwatch stop_watch;
|
||||
|
||||
@ -981,6 +984,14 @@ int main(int argc, const char* argv[]) {
|
||||
const double read_time = StopwatchReadAndReset(&stop_watch);
|
||||
fprintf(stderr, "Time to read input: %.3fs\n", read_time);
|
||||
}
|
||||
// The bitstream should be kept in memory when metadata must be appended
|
||||
// before writing it to a file/stream, and/or when the near-losslessly encoded
|
||||
// bitstream must be decoded for distortion computation (lossy will modify the
|
||||
// 'picture' but not the lossless pipeline).
|
||||
// Otherwise directly write the bitstream to a file.
|
||||
use_memory_writer = (out_file != NULL && keep_metadata) ||
|
||||
(!quiet && print_distortion >= 0 && config.lossless &&
|
||||
config.near_lossless < 100);
|
||||
|
||||
// Open the output
|
||||
if (out_file != NULL) {
|
||||
@ -995,15 +1006,19 @@ int main(int argc, const char* argv[]) {
|
||||
WFPRINTF(stderr, "Saving file '%s'\n", (const W_CHAR*)out_file);
|
||||
}
|
||||
}
|
||||
if (keep_metadata == 0) {
|
||||
picture.writer = MyWriter;
|
||||
picture.custom_ptr = (void*)out;
|
||||
} else {
|
||||
if (use_memory_writer) {
|
||||
picture.writer = WebPMemoryWrite;
|
||||
picture.custom_ptr = (void*)&memory_writer;
|
||||
} else {
|
||||
picture.writer = MyWriter;
|
||||
picture.custom_ptr = (void*)out;
|
||||
}
|
||||
} else {
|
||||
out = NULL;
|
||||
if (use_memory_writer) {
|
||||
picture.writer = WebPMemoryWrite;
|
||||
picture.custom_ptr = (void*)&memory_writer;
|
||||
}
|
||||
if (!quiet && !short_output) {
|
||||
fprintf(stderr, "No output file specified (no -o flag). Encoding will\n");
|
||||
fprintf(stderr, "be performed, but its results discarded.\n\n");
|
||||
@ -1082,8 +1097,12 @@ int main(int argc, const char* argv[]) {
|
||||
if (picture.extra_info_type > 0) {
|
||||
AllocExtraInfo(&picture);
|
||||
}
|
||||
if (print_distortion >= 0) { // Save original picture for later comparison
|
||||
WebPPictureCopy(&picture, &original_picture);
|
||||
// Save original picture for later comparison. Only for lossy as lossless does
|
||||
// not modify 'picture' (even near-lossless).
|
||||
if (print_distortion >= 0 && !config.lossless &&
|
||||
!WebPPictureCopy(&picture, &original_picture)) {
|
||||
fprintf(stderr, "Error! Cannot copy temporary picture\n");
|
||||
goto Error;
|
||||
}
|
||||
|
||||
// Compress.
|
||||
@ -1101,7 +1120,38 @@ int main(int argc, const char* argv[]) {
|
||||
fprintf(stderr, "Time to encode picture: %.3fs\n", encode_time);
|
||||
}
|
||||
|
||||
// Write info
|
||||
// Get the decompressed image for the lossless pipeline.
|
||||
if (!quiet && print_distortion >= 0 && config.lossless) {
|
||||
if (config.near_lossless == 100) {
|
||||
// Pure lossless: image was not modified, make 'original_picture' a view
|
||||
// of 'picture' by copying all members except the freeable pointers.
|
||||
original_picture = picture;
|
||||
original_picture.memory_ = original_picture.memory_argb_ = NULL;
|
||||
} else {
|
||||
// Decode the bitstream stored in 'memory_writer' to get the altered image
|
||||
// to 'picture'; save the 'original_picture' beforehand.
|
||||
assert(use_memory_writer);
|
||||
original_picture = picture;
|
||||
if (!WebPPictureInit(&picture)) { // Do not free 'picture'.
|
||||
fprintf(stderr, "Error! Version mismatch!\n");
|
||||
goto Error;
|
||||
}
|
||||
|
||||
picture.use_argb = 1;
|
||||
if (!ReadWebP(memory_writer.mem, memory_writer.size, &picture,
|
||||
/*keep_alpha=*/WebPPictureHasTransparency(&picture),
|
||||
/*metadata=*/NULL)) {
|
||||
fprintf(stderr, "Error! Cannot decode encoded WebP bitstream\n");
|
||||
fprintf(stderr, "Error code: %d (%s)\n", picture.error_code,
|
||||
kErrorMessages[picture.error_code]);
|
||||
goto Error;
|
||||
}
|
||||
picture.stats = original_picture.stats;
|
||||
}
|
||||
original_picture.stats = NULL;
|
||||
}
|
||||
|
||||
// Write the YUV planes to a PGM file. Only available for lossy.
|
||||
if (dump_file) {
|
||||
if (picture.use_argb) {
|
||||
fprintf(stderr, "Warning: can't dump file (-d option) "
|
||||
@ -1112,31 +1162,29 @@ int main(int argc, const char* argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
if (keep_metadata != 0) {
|
||||
if (out != NULL) {
|
||||
if (!WriteWebPWithMetadata(out, &picture, &memory_writer,
|
||||
&metadata, keep_metadata, &metadata_written)) {
|
||||
fprintf(stderr, "Error writing WebP file with metadata!\n");
|
||||
goto Error;
|
||||
}
|
||||
} else { // output is disabled, just display the metadata stats.
|
||||
const struct {
|
||||
const MetadataPayload* const payload;
|
||||
int flag;
|
||||
} *iter, info[] = {
|
||||
{ &metadata.exif, METADATA_EXIF },
|
||||
{ &metadata.iccp, METADATA_ICC },
|
||||
{ &metadata.xmp, METADATA_XMP },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
uint32_t unused1 = 0;
|
||||
uint64_t unused2 = 0;
|
||||
if (use_memory_writer && out != NULL &&
|
||||
!WriteWebPWithMetadata(out, &picture, &memory_writer, &metadata,
|
||||
keep_metadata, &metadata_written)) {
|
||||
fprintf(stderr, "Error writing WebP file!\n");
|
||||
goto Error;
|
||||
}
|
||||
|
||||
for (iter = info; iter->payload != NULL; ++iter) {
|
||||
if (UpdateFlagsAndSize(iter->payload, !!(keep_metadata & iter->flag),
|
||||
0, &unused1, &unused2)) {
|
||||
metadata_written |= iter->flag;
|
||||
}
|
||||
if (out == NULL && keep_metadata) {
|
||||
// output is disabled, just display the metadata stats.
|
||||
const struct {
|
||||
const MetadataPayload* const payload;
|
||||
int flag;
|
||||
} *iter, info[] = {{&metadata.exif, METADATA_EXIF},
|
||||
{&metadata.iccp, METADATA_ICC},
|
||||
{&metadata.xmp, METADATA_XMP},
|
||||
{NULL, 0}};
|
||||
uint32_t unused1 = 0;
|
||||
uint64_t unused2 = 0;
|
||||
|
||||
for (iter = info; iter->payload != NULL; ++iter) {
|
||||
if (UpdateFlagsAndSize(iter->payload, !!(keep_metadata & iter->flag),
|
||||
/*flag=*/0, &unused1, &unused2)) {
|
||||
metadata_written |= iter->flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user