blob: 5e34f305442bda07fc97910300fff6d12b66b06e [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 Zern5927e152014-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 Zern5927e152014-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 Zern5927e152014-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
James Zerna6140192014-08-29 19:16:54 -070049 if (!ExUtilSetBinaryMode(stdin)) return 0;
50
skal2bcad892014-03-12 19:32:16 +010051 while (!feof(stdin)) {
52 // We double the buffer size each time and read as much as possible.
53 const size_t extra_size = (max_size == 0) ? kBlockSize : max_size;
54 void* const new_data = realloc(input, max_size + extra_size);
55 if (new_data == NULL) goto Error;
56 input = (uint8_t*)new_data;
57 max_size += extra_size;
58 size += fread(input + size, 1, extra_size, stdin);
59 if (size < max_size) break;
60 }
61 if (ferror(stdin)) goto Error;
62 *data = input;
63 *data_size = size;
64 return 1;
65
66 Error:
67 free(input);
68 fprintf(stderr, "Could not read from stdin\n");
69 return 0;
70}
71
James Zern061263a2012-05-11 16:00:57 -070072int ExUtilReadFile(const char* const file_name,
73 const uint8_t** data, size_t* data_size) {
74 int ok;
75 void* file_data;
76 size_t file_size;
77 FILE* in;
skal2bcad892014-03-12 19:32:16 +010078 const int from_stdin = (file_name == NULL) || !strcmp(file_name, "-");
James Zern061263a2012-05-11 16:00:57 -070079
skal2bcad892014-03-12 19:32:16 +010080 if (from_stdin) return ExUtilReadFromStdin(data, data_size);
81
82 if (data == NULL || data_size == NULL) return 0;
James Zern061263a2012-05-11 16:00:57 -070083 *data = NULL;
84 *data_size = 0;
85
86 in = fopen(file_name, "rb");
87 if (in == NULL) {
88 fprintf(stderr, "cannot open input file '%s'\n", file_name);
89 return 0;
90 }
91 fseek(in, 0, SEEK_END);
92 file_size = ftell(in);
93 fseek(in, 0, SEEK_SET);
94 file_data = malloc(file_size);
95 if (file_data == NULL) return 0;
96 ok = (fread(file_data, file_size, 1, in) == 1);
97 fclose(in);
98
99 if (!ok) {
James Zern14d42af2013-03-20 16:59:35 -0700100 fprintf(stderr, "Could not read %d bytes of data from file %s\n",
101 (int)file_size, file_name);
James Zern061263a2012-05-11 16:00:57 -0700102 free(file_data);
103 return 0;
104 }
105 *data = (uint8_t*)file_data;
106 *data_size = file_size;
107 return 1;
108}
109
Urvang Joshie9a15a32012-11-07 14:41:15 -0800110int ExUtilWriteFile(const char* const file_name,
111 const uint8_t* data, size_t data_size) {
112 int ok;
113 FILE* out;
skal2bcad892014-03-12 19:32:16 +0100114 const int to_stdout = (file_name == NULL) || !strcmp(file_name, "-");
Urvang Joshie9a15a32012-11-07 14:41:15 -0800115
skal2bcad892014-03-12 19:32:16 +0100116 if (data == NULL) {
Urvang Joshie9a15a32012-11-07 14:41:15 -0800117 return 0;
118 }
skal2bcad892014-03-12 19:32:16 +0100119 out = to_stdout ? stdout : fopen(file_name, "wb");
Urvang Joshie9a15a32012-11-07 14:41:15 -0800120 if (out == NULL) {
121 fprintf(stderr, "Error! Cannot open output file '%s'\n", file_name);
122 return 0;
123 }
124 ok = (fwrite(data, data_size, 1, out) == 1);
skal2bcad892014-03-12 19:32:16 +0100125 if (out != stdout) fclose(out);
Urvang Joshie9a15a32012-11-07 14:41:15 -0800126 return ok;
127}
128
James Zern4a0e7392014-04-22 19:33:22 -0700129//------------------------------------------------------------------------------
130// WebP decoding
131
skal0b747b12014-07-21 15:44:43 +0200132static const char* const kStatusMessages[VP8_STATUS_NOT_ENOUGH_DATA + 1] = {
James Zern4a0e7392014-04-22 19:33:22 -0700133 "OK", "OUT_OF_MEMORY", "INVALID_PARAM", "BITSTREAM_ERROR",
134 "UNSUPPORTED_FEATURE", "SUSPENDED", "USER_ABORT", "NOT_ENOUGH_DATA"
135};
136
James Zern1b2fe142014-04-26 14:26:13 -0700137static void PrintAnimationWarning(const WebPDecoderConfig* const config) {
138 if (config->input.has_animation) {
139 fprintf(stderr,
140 "Error! Decoding of an animated WebP file is not supported.\n"
141 " Use webpmux to extract the individual frames or\n"
142 " vwebp to view this image.\n");
143 }
144}
145
James Zern4a0e7392014-04-22 19:33:22 -0700146void ExUtilPrintWebPError(const char* const in_file, int status) {
147 fprintf(stderr, "Decoding of %s failed.\n", in_file);
148 fprintf(stderr, "Status: %d", status);
149 if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) {
150 fprintf(stderr, "(%s)", kStatusMessages[status]);
151 }
152 fprintf(stderr, "\n");
153}
154
155int ExUtilLoadWebP(const char* const in_file,
156 const uint8_t** data, size_t* data_size,
157 WebPBitstreamFeatures* bitstream) {
158 VP8StatusCode status;
Pascal Massiminof0b65c92014-04-26 01:10:52 -0700159 WebPBitstreamFeatures local_features;
James Zern4a0e7392014-04-22 19:33:22 -0700160 if (!ExUtilReadFile(in_file, data, data_size)) return 0;
161
Pascal Massiminof0b65c92014-04-26 01:10:52 -0700162 if (bitstream == NULL) {
163 bitstream = &local_features;
164 }
165
James Zern4a0e7392014-04-22 19:33:22 -0700166 status = WebPGetFeatures(*data, *data_size, bitstream);
167 if (status != VP8_STATUS_OK) {
168 free((void*)*data);
169 *data = NULL;
170 *data_size = 0;
171 ExUtilPrintWebPError(in_file, status);
172 return 0;
173 }
174 return 1;
175}
176
James Zern1b2fe142014-04-26 14:26:13 -0700177//------------------------------------------------------------------------------
178
James Zern4a0e7392014-04-22 19:33:22 -0700179VP8StatusCode ExUtilDecodeWebP(const uint8_t* const data, size_t data_size,
James Zern1b2fe142014-04-26 14:26:13 -0700180 int verbose, WebPDecoderConfig* const config) {
James Zern4a0e7392014-04-22 19:33:22 -0700181 Stopwatch stop_watch;
182 VP8StatusCode status = VP8_STATUS_OK;
James Zern1b2fe142014-04-26 14:26:13 -0700183 if (config == NULL) return VP8_STATUS_INVALID_PARAM;
James Zern4a0e7392014-04-22 19:33:22 -0700184
James Zern1b2fe142014-04-26 14:26:13 -0700185 PrintAnimationWarning(config);
James Zern4a0e7392014-04-22 19:33:22 -0700186
James Zern1b2fe142014-04-26 14:26:13 -0700187 StopwatchReset(&stop_watch);
James Zern4a0e7392014-04-22 19:33:22 -0700188
189 // Decoding call.
James Zern1b2fe142014-04-26 14:26:13 -0700190 status = WebPDecode(data, data_size, config);
191
192 if (verbose) {
193 const double decode_time = StopwatchReadAndReset(&stop_watch);
194 fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time);
195 }
196 return status;
197}
198
199VP8StatusCode ExUtilDecodeWebPIncremental(
200 const uint8_t* const data, size_t data_size,
201 int verbose, WebPDecoderConfig* const config) {
202 Stopwatch stop_watch;
203 VP8StatusCode status = VP8_STATUS_OK;
204 if (config == NULL) return VP8_STATUS_INVALID_PARAM;
205
206 PrintAnimationWarning(config);
207
208 StopwatchReset(&stop_watch);
209
210 // Decoding call.
211 {
James Zern4a0e7392014-04-22 19:33:22 -0700212 WebPIDecoder* const idec = WebPIDecode(data, data_size, config);
213 if (idec == NULL) {
214 fprintf(stderr, "Failed during WebPINewDecoder().\n");
215 return VP8_STATUS_OUT_OF_MEMORY;
216 } else {
217 status = WebPIUpdate(idec, data, data_size);
218 WebPIDelete(idec);
219 }
220 }
221
222 if (verbose) {
223 const double decode_time = StopwatchReadAndReset(&stop_watch);
224 fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time);
225 }
226 return status;
227}
228
229// -----------------------------------------------------------------------------