blob: 8bfff69f588a316bbbe47c99018939374882bb8c [file] [log] [blame]
James Zern061263a2012-05-11 16:00:57 -07001// Copyright 2012 Google Inc. All Rights Reserved.
2//
James Zernd6406142013-06-06 23:05:58 -07003// Use of this source code is governed by a BSD-style license
4// that can be found in the COPYING file in the root of the source
5// tree. An additional intellectual property rights grant can be found
6// in the file PATENTS. All contributing project authors may
7// be found in the AUTHORS file in the root of the source tree.
James Zern061263a2012-05-11 16:00:57 -07008// -----------------------------------------------------------------------------
9//
10// Utility functions used by the example programs.
11//
12
13#include "./example_util.h"
14#include <stdio.h>
15#include <stdlib.h>
skal2bcad892014-03-12 19:32:16 +010016#include <string.h>
James Zern061263a2012-05-11 16:00:57 -070017
James Zern4a0e7392014-04-22 19:33:22 -070018#include "webp/decode.h"
19#include "./stopwatch.h"
20
James Zern061263a2012-05-11 16:00:57 -070021// -----------------------------------------------------------------------------
22// File I/O
23
skal2bcad892014-03-12 19:32:16 +010024static const size_t kBlockSize = 16384; // default initial size
25
26int ExUtilReadFromStdin(const uint8_t** data, size_t* data_size) {
27 size_t max_size = 0;
28 size_t size = 0;
29 uint8_t* input = NULL;
30
31 if (data == NULL || data_size == NULL) return 0;
32 *data = NULL;
33 *data_size = 0;
34
35 while (!feof(stdin)) {
36 // We double the buffer size each time and read as much as possible.
37 const size_t extra_size = (max_size == 0) ? kBlockSize : max_size;
38 void* const new_data = realloc(input, max_size + extra_size);
39 if (new_data == NULL) goto Error;
40 input = (uint8_t*)new_data;
41 max_size += extra_size;
42 size += fread(input + size, 1, extra_size, stdin);
43 if (size < max_size) break;
44 }
45 if (ferror(stdin)) goto Error;
46 *data = input;
47 *data_size = size;
48 return 1;
49
50 Error:
51 free(input);
52 fprintf(stderr, "Could not read from stdin\n");
53 return 0;
54}
55
James Zern061263a2012-05-11 16:00:57 -070056int ExUtilReadFile(const char* const file_name,
57 const uint8_t** data, size_t* data_size) {
58 int ok;
59 void* file_data;
60 size_t file_size;
61 FILE* in;
skal2bcad892014-03-12 19:32:16 +010062 const int from_stdin = (file_name == NULL) || !strcmp(file_name, "-");
James Zern061263a2012-05-11 16:00:57 -070063
skal2bcad892014-03-12 19:32:16 +010064 if (from_stdin) return ExUtilReadFromStdin(data, data_size);
65
66 if (data == NULL || data_size == NULL) return 0;
James Zern061263a2012-05-11 16:00:57 -070067 *data = NULL;
68 *data_size = 0;
69
70 in = fopen(file_name, "rb");
71 if (in == NULL) {
72 fprintf(stderr, "cannot open input file '%s'\n", file_name);
73 return 0;
74 }
75 fseek(in, 0, SEEK_END);
76 file_size = ftell(in);
77 fseek(in, 0, SEEK_SET);
78 file_data = malloc(file_size);
79 if (file_data == NULL) return 0;
80 ok = (fread(file_data, file_size, 1, in) == 1);
81 fclose(in);
82
83 if (!ok) {
James Zern14d42af2013-03-20 16:59:35 -070084 fprintf(stderr, "Could not read %d bytes of data from file %s\n",
85 (int)file_size, file_name);
James Zern061263a2012-05-11 16:00:57 -070086 free(file_data);
87 return 0;
88 }
89 *data = (uint8_t*)file_data;
90 *data_size = file_size;
91 return 1;
92}
93
Urvang Joshie9a15a32012-11-07 14:41:15 -080094int ExUtilWriteFile(const char* const file_name,
95 const uint8_t* data, size_t data_size) {
96 int ok;
97 FILE* out;
skal2bcad892014-03-12 19:32:16 +010098 const int to_stdout = (file_name == NULL) || !strcmp(file_name, "-");
Urvang Joshie9a15a32012-11-07 14:41:15 -080099
skal2bcad892014-03-12 19:32:16 +0100100 if (data == NULL) {
Urvang Joshie9a15a32012-11-07 14:41:15 -0800101 return 0;
102 }
skal2bcad892014-03-12 19:32:16 +0100103 out = to_stdout ? stdout : fopen(file_name, "wb");
Urvang Joshie9a15a32012-11-07 14:41:15 -0800104 if (out == NULL) {
105 fprintf(stderr, "Error! Cannot open output file '%s'\n", file_name);
106 return 0;
107 }
108 ok = (fwrite(data, data_size, 1, out) == 1);
skal2bcad892014-03-12 19:32:16 +0100109 if (out != stdout) fclose(out);
Urvang Joshie9a15a32012-11-07 14:41:15 -0800110 return ok;
111}
112
James Zern4a0e7392014-04-22 19:33:22 -0700113//------------------------------------------------------------------------------
114// WebP decoding
115
116static const char* const kStatusMessages[] = {
117 "OK", "OUT_OF_MEMORY", "INVALID_PARAM", "BITSTREAM_ERROR",
118 "UNSUPPORTED_FEATURE", "SUSPENDED", "USER_ABORT", "NOT_ENOUGH_DATA"
119};
120
121void ExUtilPrintWebPError(const char* const in_file, int status) {
122 fprintf(stderr, "Decoding of %s failed.\n", in_file);
123 fprintf(stderr, "Status: %d", status);
124 if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) {
125 fprintf(stderr, "(%s)", kStatusMessages[status]);
126 }
127 fprintf(stderr, "\n");
128}
129
130int ExUtilLoadWebP(const char* const in_file,
131 const uint8_t** data, size_t* data_size,
132 WebPBitstreamFeatures* bitstream) {
133 VP8StatusCode status;
134 if (!ExUtilReadFile(in_file, data, data_size)) return 0;
135
136 status = WebPGetFeatures(*data, *data_size, bitstream);
137 if (status != VP8_STATUS_OK) {
138 free((void*)*data);
139 *data = NULL;
140 *data_size = 0;
141 ExUtilPrintWebPError(in_file, status);
142 return 0;
143 }
144 return 1;
145}
146
147VP8StatusCode ExUtilDecodeWebP(const uint8_t* const data, size_t data_size,
148 int incremental, int verbose,
149 WebPDecoderConfig* const config) {
150 Stopwatch stop_watch;
151 VP8StatusCode status = VP8_STATUS_OK;
152 if (config == NULL) return 0;
153
154 if (verbose) {
155 StopwatchReset(&stop_watch);
156 }
157
158 if (config->input.has_animation) {
159 fprintf(stderr,
160 "Error! Decoding of an animated WebP file is not supported.\n"
161 " Use webpmux to extract the individual frames or\n"
162 " vwebp to view this image.\n");
163 }
164
165 // Decoding call.
166 if (!incremental) {
167 status = WebPDecode(data, data_size, config);
168 } else {
169 WebPIDecoder* const idec = WebPIDecode(data, data_size, config);
170 if (idec == NULL) {
171 fprintf(stderr, "Failed during WebPINewDecoder().\n");
172 return VP8_STATUS_OUT_OF_MEMORY;
173 } else {
174 status = WebPIUpdate(idec, data, data_size);
175 WebPIDelete(idec);
176 }
177 }
178
179 if (verbose) {
180 const double decode_time = StopwatchReadAndReset(&stop_watch);
181 fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time);
182 }
183 return status;
184}
185
186// -----------------------------------------------------------------------------