forked from webmproject/libwebp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
Showing
1 changed file
with
80 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
// | ||
// Author: Skal ([email protected]) | ||
|
||
#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; | ||
} | ||
} | ||
} | ||
|