blob: 4443f83d95f764665abce062235f442253ea7624 [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"
James Zern4aaf4632014-08-29 19:07:17 -070014
15#if defined(_WIN32)
16#include <fcntl.h> // for _O_BINARY
17#include <io.h> // for _setmode()
18#endif
James Zern061263a2012-05-11 16:00:57 -070019#include <stdio.h>
20#include <stdlib.h>
skal2bcad892014-03-12 19:32:16 +010021#include <string.h>
James Zern061263a2012-05-11 16:00:57 -070022
James Zern4a0e7392014-04-22 19:33:22 -070023#include "webp/decode.h"
24#include "./stopwatch.h"
25
James Zern061263a2012-05-11 16:00:57 -070026// -----------------------------------------------------------------------------
27// File I/O
28
James Zern4aaf4632014-08-29 19:07:17 -070029FILE* ExUtilSetBinaryMode(FILE* file) {
30#if defined(_WIN32)
31 if (_setmode(_fileno(file), _O_BINARY) == -1) {
32 fprintf(stderr, "Failed to reopen file in O_BINARY mode.\n");
33 return NULL;
34 }
35#endif
36 return file;
37}
skal2bcad892014-03-12 19:32:16 +010038
39int ExUtilReadFromStdin(const uint8_t** data, size_t* data_size) {
James Zern4aaf4632014-08-29 19:07:17 -070040 static const size_t kBlockSize = 16384; // default initial size
skal2bcad892014-03-12 19:32:16 +010041 size_t max_size = 0;
42 size_t size = 0;
43 uint8_t* input = NULL;
44
45 if (data == NULL || data_size == NULL) return 0;
46 *data = NULL;
47 *data_size = 0;
48
49 while (!feof(stdin)) {
50 // We double the buffer size each time and read as much as possible.
51 const size_t extra_size = (max_size == 0) ? kBlockSize : max_size;
52 void* const new_data = realloc(input, max_size + extra_size);
53 if (new_data == NULL) goto Error;
54 input = (uint8_t*)new_data;
55 max_size += extra_size;
56 size += fread(input + size, 1, extra_size, stdin);
57 if (size < max_size) break;
58 }
59 if (ferror(stdin)) goto Error;
60 *data = input;
61 *data_size = size;
62 return 1;
63
64 Error:
65 free(input);
66 fprintf(stderr, "Could not read from stdin\n");
67 return 0;
68}
69
James Zern061263a2012-05-11 16:00:57 -070070int ExUtilReadFile(const char* const file_name,
71 const uint8_t** data, size_t* data_size) {
72 int ok;
73 void* file_data;
74 size_t file_size;
75 FILE* in;
skal2bcad892014-03-12 19:32:16 +010076 const int from_stdin = (file_name == NULL) || !strcmp(file_name, "-");
James Zern061263a2012-05-11 16:00:57 -070077
skal2bcad892014-03-12 19:32:16 +010078 if (from_stdin) return ExUtilReadFromStdin(data, data_size);
79
80 if (data == NULL || data_size == NULL) return 0;
James Zern061263a2012-05-11 16:00:57 -070081 *data = NULL;
82 *data_size = 0;
83
84 in = fopen(file_name, "rb");
85 if (in == NULL) {
86 fprintf(stderr, "cannot open input file '%s'\n", file_name);
87 return 0;
88 }
89 fseek(in, 0, SEEK_END);
90 file_size = ftell(in);
91 fseek(in, 0, SEEK_SET);
92 file_data = malloc(file_size);
93 if (file_data == NULL) return 0;
94 ok = (fread(file_data, file_size, 1, in) == 1);
95 fclose(in);
96
97 if (!ok) {
James Zern14d42af2013-03-20 16:59:35 -070098 fprintf(stderr, "Could not read %d bytes of data from file %s\n",
99 (int)file_size, file_name);
James Zern061263a2012-05-11 16:00:57 -0700100 free(file_data);
101 return 0;
102 }
103 *data = (uint8_t*)file_data;
104 *data_size = file_size;
105 return 1;
106}
107
Urvang Joshie9a15a32012-11-07 14:41:15 -0800108int ExUtilWriteFile(const char* const file_name,
109 const uint8_t* data, size_t data_size) {
110 int ok;
111 FILE* out;
skal2bcad892014-03-12 19:32:16 +0100112 const int to_stdout = (file_name == NULL) || !strcmp(file_name, "-");
Urvang Joshie9a15a32012-11-07 14:41:15 -0800113
skal2bcad892014-03-12 19:32:16 +0100114 if (data == NULL) {
Urvang Joshie9a15a32012-11-07 14:41:15 -0800115 return 0;
116 }
skal2bcad892014-03-12 19:32:16 +0100117 out = to_stdout ? stdout : fopen(file_name, "wb");
Urvang Joshie9a15a32012-11-07 14:41:15 -0800118 if (out == NULL) {
119 fprintf(stderr, "Error! Cannot open output file '%s'\n", file_name);
120 return 0;
121 }
122 ok = (fwrite(data, data_size, 1, out) == 1);
skal2bcad892014-03-12 19:32:16 +0100123 if (out != stdout) fclose(out);
Urvang Joshie9a15a32012-11-07 14:41:15 -0800124 return ok;
125}
126
James Zern4a0e7392014-04-22 19:33:22 -0700127//------------------------------------------------------------------------------
128// WebP decoding
129
skal0b747b12014-07-21 15:44:43 +0200130static const char* const kStatusMessages[VP8_STATUS_NOT_ENOUGH_DATA + 1] = {
James Zern4a0e7392014-04-22 19:33:22 -0700131 "OK", "OUT_OF_MEMORY", "INVALID_PARAM", "BITSTREAM_ERROR",
132 "UNSUPPORTED_FEATURE", "SUSPENDED", "USER_ABORT", "NOT_ENOUGH_DATA"
133};
134
James Zern1b2fe142014-04-26 14:26:13 -0700135static void PrintAnimationWarning(const WebPDecoderConfig* const config) {
136 if (config->input.has_animation) {
137 fprintf(stderr,
138 "Error! Decoding of an animated WebP file is not supported.\n"
139 " Use webpmux to extract the individual frames or\n"
140 " vwebp to view this image.\n");
141 }
142}
143
James Zern4a0e7392014-04-22 19:33:22 -0700144void ExUtilPrintWebPError(const char* const in_file, int status) {
145 fprintf(stderr, "Decoding of %s failed.\n", in_file);
146 fprintf(stderr, "Status: %d", status);
147 if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) {
148 fprintf(stderr, "(%s)", kStatusMessages[status]);
149 }
150 fprintf(stderr, "\n");
151}
152
153int ExUtilLoadWebP(const char* const in_file,
154 const uint8_t** data, size_t* data_size,
155 WebPBitstreamFeatures* bitstream) {
156 VP8StatusCode status;
Pascal Massiminof0b65c92014-04-26 01:10:52 -0700157 WebPBitstreamFeatures local_features;
James Zern4a0e7392014-04-22 19:33:22 -0700158 if (!ExUtilReadFile(in_file, data, data_size)) return 0;
159
Pascal Massiminof0b65c92014-04-26 01:10:52 -0700160 if (bitstream == NULL) {
161 bitstream = &local_features;
162 }
163
James Zern4a0e7392014-04-22 19:33:22 -0700164 status = WebPGetFeatures(*data, *data_size, bitstream);
165 if (status != VP8_STATUS_OK) {
166 free((void*)*data);
167 *data = NULL;
168 *data_size = 0;
169 ExUtilPrintWebPError(in_file, status);
170 return 0;
171 }
172 return 1;
173}
174
James Zern1b2fe142014-04-26 14:26:13 -0700175//------------------------------------------------------------------------------
176
James Zern4a0e7392014-04-22 19:33:22 -0700177VP8StatusCode ExUtilDecodeWebP(const uint8_t* const data, size_t data_size,
James Zern1b2fe142014-04-26 14:26:13 -0700178 int verbose, WebPDecoderConfig* const config) {
James Zern4a0e7392014-04-22 19:33:22 -0700179 Stopwatch stop_watch;
180 VP8StatusCode status = VP8_STATUS_OK;
James Zern1b2fe142014-04-26 14:26:13 -0700181 if (config == NULL) return VP8_STATUS_INVALID_PARAM;
James Zern4a0e7392014-04-22 19:33:22 -0700182
James Zern1b2fe142014-04-26 14:26:13 -0700183 PrintAnimationWarning(config);
James Zern4a0e7392014-04-22 19:33:22 -0700184
James Zern1b2fe142014-04-26 14:26:13 -0700185 StopwatchReset(&stop_watch);
James Zern4a0e7392014-04-22 19:33:22 -0700186
187 // Decoding call.
James Zern1b2fe142014-04-26 14:26:13 -0700188 status = WebPDecode(data, data_size, config);
189
190 if (verbose) {
191 const double decode_time = StopwatchReadAndReset(&stop_watch);
192 fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time);
193 }
194 return status;
195}
196
197VP8StatusCode ExUtilDecodeWebPIncremental(
198 const uint8_t* const data, size_t data_size,
199 int verbose, WebPDecoderConfig* const config) {
200 Stopwatch stop_watch;
201 VP8StatusCode status = VP8_STATUS_OK;
202 if (config == NULL) return VP8_STATUS_INVALID_PARAM;
203
204 PrintAnimationWarning(config);
205
206 StopwatchReset(&stop_watch);
207
208 // Decoding call.
209 {
James Zern4a0e7392014-04-22 19:33:22 -0700210 WebPIDecoder* const idec = WebPIDecode(data, data_size, config);
211 if (idec == NULL) {
212 fprintf(stderr, "Failed during WebPINewDecoder().\n");
213 return VP8_STATUS_OUT_OF_MEMORY;
214 } else {
215 status = WebPIUpdate(idec, data, data_size);
216 WebPIDelete(idec);
217 }
218 }
219
220 if (verbose) {
221 const double decode_time = StopwatchReadAndReset(&stop_watch);
222 fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time);
223 }
224 return status;
225}
226
227// -----------------------------------------------------------------------------