diff --git a/examples/Makefile.am b/examples/Makefile.am index c38d5f3a..6cf7ea52 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -14,7 +14,7 @@ endif noinst_LTLIBRARIES = libexampleutil.la -libexampleutil_la_SOURCES = example_util.c example_util.h +libexampleutil_la_SOURCES = example_util.c example_util.h stopwatch.h dwebp_SOURCES = dwebp.c stopwatch.h dwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) diff --git a/examples/dwebp.c b/examples/dwebp.c index cd5e1314..2876828a 100644 --- a/examples/dwebp.c +++ b/examples/dwebp.c @@ -571,11 +571,6 @@ static void Help(void) { ); } -static const char* const kStatusMessages[] = { - "OK", "OUT_OF_MEMORY", "INVALID_PARAM", "BITSTREAM_ERROR", - "UNSUPPORTED_FEATURE", "SUSPENDED", "USER_ABORT", "NOT_ENOUGH_DATA" -}; - static const char* const kFormatType[] = { "unspecified", "lossy", "lossless" }; @@ -671,27 +666,11 @@ int main(int argc, const char *argv[]) { } { - Stopwatch stop_watch; VP8StatusCode status = VP8_STATUS_OK; size_t data_size = 0; const uint8_t* data = NULL; - - if (!ExUtilReadFile(in_file, &data, &data_size)) return -1; - - if (verbose) { - StopwatchReset(&stop_watch); - } - - status = WebPGetFeatures(data, data_size, bitstream); - if (status != VP8_STATUS_OK) { - goto end; - } - - if (bitstream->has_animation) { - fprintf(stderr, - "Error! Decoding of an animated WebP file is not supported.\n" - " Use webpmux to extract the individual frames or\n" - " vwebp to view this image.\n"); + if (!ExUtilLoadWebP(in_file, &data, &data_size, bitstream)) { + goto End; } switch (format) { @@ -727,31 +706,12 @@ int main(int argc, const char *argv[]) { return -1; } - // Decoding call. - if (!incremental) { - status = WebPDecode(data, data_size, &config); - } else { - WebPIDecoder* const idec = WebPIDecode(data, data_size, &config); - if (idec == NULL) { - fprintf(stderr, "Failed during WebPINewDecoder().\n"); - status = VP8_STATUS_OUT_OF_MEMORY; - goto end; - } else { - status = WebPIUpdate(idec, data, data_size); - WebPIDelete(idec); - } - } - - if (verbose) { - const double decode_time = StopwatchReadAndReset(&stop_watch); - fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time); - } - end: + status = ExUtilDecodeWebP(data, data_size, incremental, verbose, &config); + End: free((void*)data); ok = (status == VP8_STATUS_OK); if (!ok) { - fprintf(stderr, "Decoding of %s failed.\n", in_file); - fprintf(stderr, "Status: %d (%s)\n", status, kStatusMessages[status]); + ExUtilPrintWebPError(in_file, status); goto Exit; } } diff --git a/examples/example_util.c b/examples/example_util.c index f2d49750..8bfff69f 100644 --- a/examples/example_util.c +++ b/examples/example_util.c @@ -15,6 +15,9 @@ #include #include +#include "webp/decode.h" +#include "./stopwatch.h" + // ----------------------------------------------------------------------------- // File I/O @@ -107,3 +110,77 @@ int ExUtilWriteFile(const char* const file_name, return ok; } +//------------------------------------------------------------------------------ +// WebP decoding + +static const char* const kStatusMessages[] = { + "OK", "OUT_OF_MEMORY", "INVALID_PARAM", "BITSTREAM_ERROR", + "UNSUPPORTED_FEATURE", "SUSPENDED", "USER_ABORT", "NOT_ENOUGH_DATA" +}; + +void ExUtilPrintWebPError(const char* const in_file, int status) { + fprintf(stderr, "Decoding of %s failed.\n", in_file); + fprintf(stderr, "Status: %d", status); + if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) { + fprintf(stderr, "(%s)", kStatusMessages[status]); + } + fprintf(stderr, "\n"); +} + +int ExUtilLoadWebP(const char* const in_file, + const uint8_t** data, size_t* data_size, + WebPBitstreamFeatures* bitstream) { + VP8StatusCode status; + if (!ExUtilReadFile(in_file, data, data_size)) return 0; + + status = WebPGetFeatures(*data, *data_size, bitstream); + if (status != VP8_STATUS_OK) { + free((void*)*data); + *data = NULL; + *data_size = 0; + ExUtilPrintWebPError(in_file, status); + return 0; + } + return 1; +} + +VP8StatusCode ExUtilDecodeWebP(const uint8_t* const data, size_t data_size, + int incremental, int verbose, + WebPDecoderConfig* const config) { + Stopwatch stop_watch; + VP8StatusCode status = VP8_STATUS_OK; + if (config == NULL) return 0; + + if (verbose) { + StopwatchReset(&stop_watch); + } + + if (config->input.has_animation) { + fprintf(stderr, + "Error! Decoding of an animated WebP file is not supported.\n" + " Use webpmux to extract the individual frames or\n" + " vwebp to view this image.\n"); + } + + // Decoding call. + if (!incremental) { + status = WebPDecode(data, data_size, config); + } else { + WebPIDecoder* const idec = WebPIDecode(data, data_size, config); + if (idec == NULL) { + fprintf(stderr, "Failed during WebPINewDecoder().\n"); + return VP8_STATUS_OUT_OF_MEMORY; + } else { + status = WebPIUpdate(idec, data, data_size); + WebPIDelete(idec); + } + } + + if (verbose) { + const double decode_time = StopwatchReadAndReset(&stop_watch); + fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time); + } + return status; +} + +// ----------------------------------------------------------------------------- diff --git a/examples/example_util.h b/examples/example_util.h index b191bd2a..a160786e 100644 --- a/examples/example_util.h +++ b/examples/example_util.h @@ -19,6 +19,9 @@ extern "C" { #endif +struct WebPDecoderConfig; +struct WebPBitstreamFeatures; + // Allocates storage for entire file 'file_name' and returns contents and size // in 'data' and 'data_size'. Returns 1 on success, 0 otherwise. '*data' should // be deleted using free(). @@ -35,6 +38,32 @@ int ExUtilReadFromStdin(const uint8_t** data, size_t* data_size); int ExUtilWriteFile(const char* const file_name, const uint8_t* data, size_t data_size); +//------------------------------------------------------------------------------ +// WebP decoding + +// Prints an informative error message regarding decode failure of 'in_file'. +// 'status' is treated as a VP8StatusCode and if valid will be printed as a +// text string. +void ExUtilPrintWebPError(const char* const in_file, int status); + +// Reads a WebP from 'in_file', returning the contents and size in 'data' and +// 'data_size'. 'bitstream' is populated using WebPGetFeatures(). +// Returns true on success. +int ExUtilLoadWebP(const char* const in_file, + const uint8_t** data, size_t* data_size, + struct WebPBitstreamFeatures* bitstream); + +// Decodes the WebP contained in 'data'. 'config' is a structure previously +// initialized by WebPInitDecoderConfig(). 'config->output' should have the +// desired colorspace selected. If 'incremental' is set to true the WebP +// incremental decoder will be used. 'verbose' will cause decode timing to be +// reported. +// Returns the decoder status. On success 'config->output' will contain the +// decoded picture. +enum VP8StatusCode ExUtilDecodeWebP(const uint8_t* const data, size_t data_size, + int incremental, int verbose, + struct WebPDecoderConfig* const config); + #ifdef __cplusplus } // extern "C" #endif