blob: d3dbc618acb34dd2da48bcdb5566ccaaab2c5f77 [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;
Pascal Massiminof0b65c92014-04-26 01:10:52 -0700134 WebPBitstreamFeatures local_features;
James Zern4a0e7392014-04-22 19:33:22 -0700135 if (!ExUtilReadFile(in_file, data, data_size)) return 0;
136
Pascal Massiminof0b65c92014-04-26 01:10:52 -0700137 if (bitstream == NULL) {
138 bitstream = &local_features;
139 }
140
James Zern4a0e7392014-04-22 19:33:22 -0700141 status = WebPGetFeatures(*data, *data_size, bitstream);
142 if (status != VP8_STATUS_OK) {
143 free((void*)*data);
144 *data = NULL;
145 *data_size = 0;
146 ExUtilPrintWebPError(in_file, status);
147 return 0;
148 }
149 return 1;
150}
151
152VP8StatusCode ExUtilDecodeWebP(const uint8_t* const data, size_t data_size,
153 int incremental, int verbose,
154 WebPDecoderConfig* const config) {
155 Stopwatch stop_watch;
156 VP8StatusCode status = VP8_STATUS_OK;
157 if (config == NULL) return 0;
158
159 if (verbose) {
160 StopwatchReset(&stop_watch);
161 }
162
163 if (config->input.has_animation) {
164 fprintf(stderr,
165 "Error! Decoding of an animated WebP file is not supported.\n"
166 " Use webpmux to extract the individual frames or\n"
167 " vwebp to view this image.\n");
168 }
169
170 // Decoding call.
171 if (!incremental) {
172 status = WebPDecode(data, data_size, config);
173 } else {
174 WebPIDecoder* const idec = WebPIDecode(data, data_size, config);
175 if (idec == NULL) {
176 fprintf(stderr, "Failed during WebPINewDecoder().\n");
177 return VP8_STATUS_OUT_OF_MEMORY;
178 } else {
179 status = WebPIUpdate(idec, data, data_size);
180 WebPIDelete(idec);
181 }
182 }
183
184 if (verbose) {
185 const double decode_time = StopwatchReadAndReset(&stop_watch);
186 fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time);
187 }
188 return status;
189}
190
191// -----------------------------------------------------------------------------