blob: b77b816a9802267f6049a1be65e3b1d44e1a1dca [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
skal0b747b12014-07-21 15:44:43 +0200116static const char* const kStatusMessages[VP8_STATUS_NOT_ENOUGH_DATA + 1] = {
James Zern4a0e7392014-04-22 19:33:22 -0700117 "OK", "OUT_OF_MEMORY", "INVALID_PARAM", "BITSTREAM_ERROR",
118 "UNSUPPORTED_FEATURE", "SUSPENDED", "USER_ABORT", "NOT_ENOUGH_DATA"
119};
120
James Zern1b2fe142014-04-26 14:26:13 -0700121static void PrintAnimationWarning(const WebPDecoderConfig* const config) {
122 if (config->input.has_animation) {
123 fprintf(stderr,
124 "Error! Decoding of an animated WebP file is not supported.\n"
125 " Use webpmux to extract the individual frames or\n"
126 " vwebp to view this image.\n");
127 }
128}
129
James Zern4a0e7392014-04-22 19:33:22 -0700130void ExUtilPrintWebPError(const char* const in_file, int status) {
131 fprintf(stderr, "Decoding of %s failed.\n", in_file);
132 fprintf(stderr, "Status: %d", status);
133 if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) {
134 fprintf(stderr, "(%s)", kStatusMessages[status]);
135 }
136 fprintf(stderr, "\n");
137}
138
139int ExUtilLoadWebP(const char* const in_file,
140 const uint8_t** data, size_t* data_size,
141 WebPBitstreamFeatures* bitstream) {
142 VP8StatusCode status;
Pascal Massiminof0b65c92014-04-26 01:10:52 -0700143 WebPBitstreamFeatures local_features;
James Zern4a0e7392014-04-22 19:33:22 -0700144 if (!ExUtilReadFile(in_file, data, data_size)) return 0;
145
Pascal Massiminof0b65c92014-04-26 01:10:52 -0700146 if (bitstream == NULL) {
147 bitstream = &local_features;
148 }
149
James Zern4a0e7392014-04-22 19:33:22 -0700150 status = WebPGetFeatures(*data, *data_size, bitstream);
151 if (status != VP8_STATUS_OK) {
152 free((void*)*data);
153 *data = NULL;
154 *data_size = 0;
155 ExUtilPrintWebPError(in_file, status);
156 return 0;
157 }
158 return 1;
159}
160
James Zern1b2fe142014-04-26 14:26:13 -0700161//------------------------------------------------------------------------------
162
James Zern4a0e7392014-04-22 19:33:22 -0700163VP8StatusCode ExUtilDecodeWebP(const uint8_t* const data, size_t data_size,
James Zern1b2fe142014-04-26 14:26:13 -0700164 int verbose, WebPDecoderConfig* const config) {
James Zern4a0e7392014-04-22 19:33:22 -0700165 Stopwatch stop_watch;
166 VP8StatusCode status = VP8_STATUS_OK;
James Zern1b2fe142014-04-26 14:26:13 -0700167 if (config == NULL) return VP8_STATUS_INVALID_PARAM;
James Zern4a0e7392014-04-22 19:33:22 -0700168
James Zern1b2fe142014-04-26 14:26:13 -0700169 PrintAnimationWarning(config);
James Zern4a0e7392014-04-22 19:33:22 -0700170
James Zern1b2fe142014-04-26 14:26:13 -0700171 StopwatchReset(&stop_watch);
James Zern4a0e7392014-04-22 19:33:22 -0700172
173 // Decoding call.
James Zern1b2fe142014-04-26 14:26:13 -0700174 status = WebPDecode(data, data_size, config);
175
176 if (verbose) {
177 const double decode_time = StopwatchReadAndReset(&stop_watch);
178 fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time);
179 }
180 return status;
181}
182
183VP8StatusCode ExUtilDecodeWebPIncremental(
184 const uint8_t* const data, size_t data_size,
185 int verbose, WebPDecoderConfig* const config) {
186 Stopwatch stop_watch;
187 VP8StatusCode status = VP8_STATUS_OK;
188 if (config == NULL) return VP8_STATUS_INVALID_PARAM;
189
190 PrintAnimationWarning(config);
191
192 StopwatchReset(&stop_watch);
193
194 // Decoding call.
195 {
James Zern4a0e7392014-04-22 19:33:22 -0700196 WebPIDecoder* const idec = WebPIDecode(data, data_size, config);
197 if (idec == NULL) {
198 fprintf(stderr, "Failed during WebPINewDecoder().\n");
199 return VP8_STATUS_OUT_OF_MEMORY;
200 } else {
201 status = WebPIUpdate(idec, data, data_size);
202 WebPIDelete(idec);
203 }
204 }
205
206 if (verbose) {
207 const double decode_time = StopwatchReadAndReset(&stop_watch);
208 fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time);
209 }
210 return status;
211}
212
213// -----------------------------------------------------------------------------