blob: 5e555b66243a02bf40272baef065a40175638766 [file] [log] [blame]
James Zernad1e1632012-01-06 14:49:06 -08001// Copyright 2011 Google Inc. All Rights Reserved.
Urvang Joshia4f32ca2011-09-30 11:07:01 +05302//
3// This code is licensed under the same terms as WebM:
4// Software License Agreement: http://www.webmproject.org/license/software/
5// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
6// -----------------------------------------------------------------------------
7//
8// Simple command-line to create a WebP container file and to extract or strip
9// relevant data from the container file.
10//
James Zern04e84cf2011-11-04 15:20:08 -070011// Compile with: gcc -o webpmux webpmux.c -lwebpmux -lwebp
Urvang Joshia4f32ca2011-09-30 11:07:01 +053012//
13//
14// Authors: Vikas (vikaas.arora@gmail.com),
15// Urvang (urvang@google.com)
16
17/* Usage examples:
18
19 Create container WebP file:
Urvang Joshia4f32ca2011-09-30 11:07:01 +053020 webpmux -tile tile_1.webp +0+0 \
21 -tile tile_2.webp +960+0 \
22 -tile tile_3.webp +0+576 \
23 -tile tile_4.webp +960+576 \
24 -o out_tile_container.webp
25
26 webpmux -frame anim_1.webp +0+0+0 \
27 -frame anim_2.webp +25+25+100 \
28 -frame anim_3.webp +50+50+100 \
29 -frame anim_4.webp +0+0+100 \
30 -loop 10 \
31 -o out_animation_container.webp
32
33 webpmux -set icc image_profile.icc in.webp -o out_icc_container.webp
Urvang Joshif6c096a2012-08-23 15:54:13 +053034 webpmux -set meta image_metadata.meta in.webp -o out_meta_container.webp
Urvang Joshia4f32ca2011-09-30 11:07:01 +053035
Urvang Joshia4f32ca2011-09-30 11:07:01 +053036 Extract relevant data from WebP container file:
Urvang Joshia4f32ca2011-09-30 11:07:01 +053037 webpmux -get tile n in.webp -o out_tile.webp
Urvang Joshia4f32ca2011-09-30 11:07:01 +053038 webpmux -get frame n in.webp -o out_frame.webp
Urvang Joshia4f32ca2011-09-30 11:07:01 +053039 webpmux -get icc in.webp -o image_profile.icc
Urvang Joshif6c096a2012-08-23 15:54:13 +053040 webpmux -get meta in.webp -o image_metadata.meta
Urvang Joshia4f32ca2011-09-30 11:07:01 +053041
Urvang Joshia4f32ca2011-09-30 11:07:01 +053042 Strip data from WebP Container file:
James Zern04e84cf2011-11-04 15:20:08 -070043 webpmux -strip icc in.webp -o out.webp
Urvang Joshif6c096a2012-08-23 15:54:13 +053044 webpmux -strip meta in.webp -o out.webp
Urvang Joshia4f32ca2011-09-30 11:07:01 +053045
46 Misc:
Urvang Joshia4f32ca2011-09-30 11:07:01 +053047 webpmux -info in.webp
James Zern04e84cf2011-11-04 15:20:08 -070048 webpmux [ -h | -help ]
Urvang Joshia4f32ca2011-09-30 11:07:01 +053049*/
50
51#include <assert.h>
52#include <stdio.h>
53#include <stdlib.h>
54#include <string.h>
55#include "webp/mux.h"
James Zern061263a2012-05-11 16:00:57 -070056#include "./example_util.h"
Urvang Joshia4f32ca2011-09-30 11:07:01 +053057
Urvang Joshia4f32ca2011-09-30 11:07:01 +053058//------------------------------------------------------------------------------
59// Config object to parse command-line arguments.
60
61typedef enum {
62 NIL_ACTION = 0,
63 ACTION_GET,
64 ACTION_SET,
65 ACTION_STRIP,
66 ACTION_INFO,
67 ACTION_HELP
68} ActionType;
69
70typedef enum {
71 NIL_SUBTYPE = 0,
72 SUBTYPE_FRM,
73 SUBTYPE_LOOP
74} FeatureSubType;
75
76typedef struct {
77 FeatureSubType subtype_;
78 const char* filename_;
79 const char* params_;
80} FeatureArg;
81
82typedef enum {
83 NIL_FEATURE = 0,
Urvang Joshif6c096a2012-08-23 15:54:13 +053084 FEATURE_META,
Urvang Joshia4f32ca2011-09-30 11:07:01 +053085 FEATURE_ICCP,
86 FEATURE_FRM,
87 FEATURE_TILE
88} FeatureType;
89
90typedef struct {
91 FeatureType type_;
92 FeatureArg* args_;
93 int arg_count_;
94} Feature;
95
96typedef struct {
97 ActionType action_type_;
98 const char* input_;
99 const char* output_;
100 Feature feature_;
101} WebPMuxConfig;
102
103//------------------------------------------------------------------------------
104// Helper functions.
105
James Zern04e84cf2011-11-04 15:20:08 -0700106static int CountOccurrences(const char* arglist[], int list_length,
107 const char* arg) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530108 int i;
109 int num_occurences = 0;
110
111 for (i = 0; i < list_length; ++i) {
112 if (!strcmp(arglist[i], arg)) {
113 ++num_occurences;
114 }
115 }
116 return num_occurences;
117}
118
Urvang Joshid11f6fc2012-06-27 16:55:01 +0530119static const char* const kErrorMessages[] = {
Urvang Joshia4b9b1c2012-07-06 17:33:59 +0530120 "WEBP_MUX_NOT_FOUND", "WEBP_MUX_INVALID_ARGUMENT", "WEBP_MUX_BAD_DATA",
121 "WEBP_MUX_MEMORY_ERROR", "WEBP_MUX_NOT_ENOUGH_DATA"
Urvang Joshid11f6fc2012-06-27 16:55:01 +0530122};
123
124static const char* ErrorString(WebPMuxError err) {
Urvang Joshia4b9b1c2012-07-06 17:33:59 +0530125 assert(err <= WEBP_MUX_NOT_FOUND && err >= WEBP_MUX_NOT_ENOUGH_DATA);
Urvang Joshid11f6fc2012-06-27 16:55:01 +0530126 return kErrorMessages[-err];
127}
128
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530129static int IsNotCompatible(int count1, int count2) {
James Zern04e84cf2011-11-04 15:20:08 -0700130 return (count1 > 0) != (count2 > 0);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530131}
132
James Zerna0b27362012-01-27 17:39:47 -0800133#define RETURN_IF_ERROR(ERR_MSG) \
134 if (err != WEBP_MUX_OK) { \
135 fprintf(stderr, ERR_MSG); \
136 return err; \
137 }
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530138
James Zerna0b27362012-01-27 17:39:47 -0800139#define RETURN_IF_ERROR2(ERR_MSG, FORMAT_STR) \
140 if (err != WEBP_MUX_OK) { \
141 fprintf(stderr, ERR_MSG, FORMAT_STR); \
142 return err; \
143 }
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530144
Urvang Joshid0c79f02012-08-23 16:28:36 +0530145#define RETURN_IF_ERROR3(ERR_MSG, FORMAT_STR1, FORMAT_STR2) \
146 if (err != WEBP_MUX_OK) { \
147 fprintf(stderr, ERR_MSG, FORMAT_STR1, FORMAT_STR2); \
148 return err; \
149 }
150
James Zerna0b27362012-01-27 17:39:47 -0800151#define ERROR_GOTO1(ERR_MSG, LABEL) \
152 do { \
153 fprintf(stderr, ERR_MSG); \
154 ok = 0; \
155 goto LABEL; \
156 } while (0)
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530157
James Zerna0b27362012-01-27 17:39:47 -0800158#define ERROR_GOTO2(ERR_MSG, FORMAT_STR, LABEL) \
159 do { \
160 fprintf(stderr, ERR_MSG, FORMAT_STR); \
161 ok = 0; \
162 goto LABEL; \
163 } while (0)
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530164
James Zerna0b27362012-01-27 17:39:47 -0800165#define ERROR_GOTO3(ERR_MSG, FORMAT_STR1, FORMAT_STR2, LABEL) \
166 do { \
167 fprintf(stderr, ERR_MSG, FORMAT_STR1, FORMAT_STR2); \
168 ok = 0; \
169 goto LABEL; \
170 } while (0)
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530171
172static WebPMuxError DisplayInfo(const WebPMux* mux) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530173 uint32_t flag;
174
175 WebPMuxError err = WebPMuxGetFeatures(mux, &flag);
176 RETURN_IF_ERROR("Failed to retrieve features\n");
177
178 if (flag == 0) {
179 fprintf(stderr, "No features present.\n");
180 return err;
181 }
182
183 // Print the features present.
James Zern974aaff2012-01-24 12:46:46 -0800184 printf("Features present:");
185 if (flag & ANIMATION_FLAG) printf(" animation");
186 if (flag & TILE_FLAG) printf(" tiling");
187 if (flag & ICCP_FLAG) printf(" icc profile");
188 if (flag & META_FLAG) printf(" metadata");
189 if (flag & ALPHA_FLAG) printf(" transparency");
190 printf("\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530191
Urvang Joshid0c79f02012-08-23 16:28:36 +0530192 if ((flag & ANIMATION_FLAG) || (flag & TILE_FLAG)) {
193 const int is_anim = !!(flag & ANIMATION_FLAG);
Urvang Joshi92f80592012-10-30 12:14:10 -0700194 const WebPChunkId id = is_anim ? WEBP_CHUNK_ANMF : WEBP_CHUNK_FRGM;
Urvang Joshid0c79f02012-08-23 16:28:36 +0530195 const char* const type_str = is_anim ? "frame" : "tile";
James Zerneec4b872012-01-07 12:44:01 -0800196 int nFrames;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530197
Urvang Joshid0c79f02012-08-23 16:28:36 +0530198 if (is_anim) {
199 int loop_count;
200 err = WebPMuxGetLoopCount(mux, &loop_count);
201 RETURN_IF_ERROR("Failed to retrieve loop count\n");
202 printf("Loop Count : %d\n", loop_count);
203 }
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530204
Urvang Joshid0c79f02012-08-23 16:28:36 +0530205 err = WebPMuxNumChunks(mux, id, &nFrames);
206 RETURN_IF_ERROR2("Failed to retrieve number of %ss\n", type_str);
207
208 printf("Number of %ss: %d\n", type_str, nFrames);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530209 if (nFrames > 0) {
210 int i;
Urvang Joshid0c79f02012-08-23 16:28:36 +0530211 printf("No.: x_offset y_offset ");
212 if (is_anim) printf("duration ");
213 printf("image_size\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530214 for (i = 1; i <= nFrames; i++) {
Urvang Joshiab3234a2012-08-23 15:18:51 +0530215 WebPMuxFrameInfo frame;
216 err = WebPMuxGetFrame(mux, i, &frame);
Urvang Joshid0c79f02012-08-23 16:28:36 +0530217 RETURN_IF_ERROR3("Failed to retrieve %s#%d\n", type_str, i);
218 printf("%3d: %8d %8d ", i, frame.x_offset_, frame.y_offset_);
219 if (is_anim) printf("%8d ", frame.duration_);
220 printf("%10zu\n", frame.bitstream_.size_);
Urvang Joshiab3234a2012-08-23 15:18:51 +0530221 WebPDataClear(&frame.bitstream_);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530222 }
223 }
224 }
225
226 if (flag & ICCP_FLAG) {
James Zerneec4b872012-01-07 12:44:01 -0800227 WebPData icc_profile;
Urvang Joshi1c04a0d2012-08-23 15:28:20 +0530228 err = WebPMuxGetChunk(mux, "ICCP", &icc_profile);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530229 RETURN_IF_ERROR("Failed to retrieve the color profile\n");
James Zern95667b82012-04-18 17:13:34 -0700230 printf("Size of the color profile data: %zu\n", icc_profile.size_);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530231 }
232
233 if (flag & META_FLAG) {
James Zerneec4b872012-01-07 12:44:01 -0800234 WebPData metadata;
Urvang Joshi1c04a0d2012-08-23 15:28:20 +0530235 err = WebPMuxGetChunk(mux, "META", &metadata);
Urvang Joshif6c096a2012-08-23 15:54:13 +0530236 RETURN_IF_ERROR("Failed to retrieve the metadata\n");
237 printf("Size of the metadata: %zu\n", metadata.size_);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530238 }
239
Urvang Joshicdf97aa2011-12-01 16:11:51 +0530240 if ((flag & ALPHA_FLAG) && !(flag & (ANIMATION_FLAG | TILE_FLAG))) {
Urvang Joshid0c79f02012-08-23 16:28:36 +0530241 WebPMuxFrameInfo image;
242 err = WebPMuxGetFrame(mux, 1, &image);
Urvang Joshicdf97aa2011-12-01 16:11:51 +0530243 RETURN_IF_ERROR("Failed to retrieve the image\n");
Urvang Joshid0c79f02012-08-23 16:28:36 +0530244 printf("Size of the image (with alpha): %zu\n", image.bitstream_.size_);
Urvang Joshicdf97aa2011-12-01 16:11:51 +0530245 }
246
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530247 return WEBP_MUX_OK;
248}
249
Pascal Massiminoabd030b2011-11-01 06:24:34 -0700250static void PrintHelp(void) {
James Zern974aaff2012-01-24 12:46:46 -0800251 printf("Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT\n");
252 printf(" webpmux -set SET_OPTIONS INPUT -o OUTPUT\n");
253 printf(" webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT\n");
254 printf(" webpmux -tile TILE_OPTIONS [-tile...] -o OUTPUT\n");
255 printf(" webpmux -frame FRAME_OPTIONS [-frame...]");
256 printf(" -loop LOOP_COUNT -o OUTPUT\n");
257 printf(" webpmux -info INPUT\n");
258 printf(" webpmux [-h|-help]\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530259
James Zern974aaff2012-01-24 12:46:46 -0800260 printf("\n");
261 printf("GET_OPTIONS:\n");
262 printf(" Extract relevant data.\n");
263 printf(" icc Get ICCP Color profile.\n");
Urvang Joshif6c096a2012-08-23 15:54:13 +0530264 printf(" meta Get XMP/EXIF metadata.\n");
James Zern974aaff2012-01-24 12:46:46 -0800265 printf(" tile n Get nth tile.\n");
266 printf(" frame n Get nth frame.\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530267
James Zern974aaff2012-01-24 12:46:46 -0800268 printf("\n");
269 printf("SET_OPTIONS:\n");
270 printf(" Set color profile/metadata.\n");
Urvang Joshiddfe8712012-08-23 15:45:39 +0530271 printf(" icc file.icc Set ICC Color profile.\n");
Urvang Joshif6c096a2012-08-23 15:54:13 +0530272 printf(" meta file.meta Set XMP/EXIF metadata.\n");
Urvang Joshiddfe8712012-08-23 15:45:39 +0530273 printf(" where: 'file.icc' contains the color profile to be set,\n");
Urvang Joshif6c096a2012-08-23 15:54:13 +0530274 printf(" 'file.meta' contains the metadata to be set\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530275
James Zern974aaff2012-01-24 12:46:46 -0800276 printf("\n");
277 printf("STRIP_OPTIONS:\n");
278 printf(" Strip color profile/metadata.\n");
279 printf(" icc Strip ICCP color profile.\n");
Urvang Joshif6c096a2012-08-23 15:54:13 +0530280 printf(" meta Strip XMP/EXIF metadata.\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530281
James Zern974aaff2012-01-24 12:46:46 -0800282 printf("\n");
283 printf("TILE_OPTIONS(i):\n");
284 printf(" Create tiled image.\n");
285 printf(" file_i +xi+yi\n");
286 printf(" where: 'file_i' is the i'th tile (webp format),\n");
287 printf(" 'xi','yi' specify the image offset for this tile.\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530288
James Zern974aaff2012-01-24 12:46:46 -0800289 printf("\n");
290 printf("FRAME_OPTIONS(i):\n");
291 printf(" Create animation.\n");
292 printf(" file_i +xi+yi+di\n");
293 printf(" where: 'file_i' is the i'th animation frame (webp format),\n");
294 printf(" 'xi','yi' specify the image offset for this frame.\n");
295 printf(" 'di' is the pause duration before next frame.\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530296
James Zern974aaff2012-01-24 12:46:46 -0800297 printf("\nINPUT & OUTPUT are in webp format.\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530298}
299
Urvang Joshi4fc4a472012-06-05 14:20:45 +0530300static int ReadFileToWebPData(const char* const filename,
301 WebPData* const webp_data) {
302 const uint8_t* data;
303 size_t size;
304 if (!ExUtilReadFile(filename, &data, &size)) return 0;
305 webp_data->bytes_ = data;
306 webp_data->size_ = size;
307 return 1;
308}
309
James Zern061263a2012-05-11 16:00:57 -0700310static int CreateMux(const char* const filename, WebPMux** mux) {
Urvang Joshi4fc4a472012-06-05 14:20:45 +0530311 WebPData bitstream;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530312 assert(mux != NULL);
Urvang Joshi4fc4a472012-06-05 14:20:45 +0530313 if (!ReadFileToWebPData(filename, &bitstream)) return 0;
Urvang Joshi6d5c7972012-06-07 13:45:06 +0530314 *mux = WebPMuxCreate(&bitstream, 1);
Urvang Joshi4fc4a472012-06-05 14:20:45 +0530315 free((void*)bitstream.bytes_);
Urvang Joshi6d5c7972012-06-07 13:45:06 +0530316 if (*mux != NULL) return 1;
317 fprintf(stderr, "Failed to create mux object from file %s.\n", filename);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530318 return 0;
319}
320
James Zern0f7820e2012-01-24 14:08:27 -0800321static int WriteData(const char* filename, const WebPData* const webpdata) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530322 int ok = 0;
James Zern04e84cf2011-11-04 15:20:08 -0700323 FILE* fout = strcmp(filename, "-") ? fopen(filename, "wb") : stdout;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530324 if (!fout) {
325 fprintf(stderr, "Error opening output WebP file %s!\n", filename);
326 return 0;
327 }
James Zern0f7820e2012-01-24 14:08:27 -0800328 if (fwrite(webpdata->bytes_, webpdata->size_, 1, fout) != 1) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530329 fprintf(stderr, "Error writing file %s!\n", filename);
330 } else {
James Zern95667b82012-04-18 17:13:34 -0700331 fprintf(stderr, "Saved file %s (%zu bytes)\n", filename, webpdata->size_);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530332 ok = 1;
333 }
334 if (fout != stdout) fclose(fout);
335 return ok;
336}
337
338static int WriteWebP(WebPMux* const mux, const char* filename) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530339 int ok;
Urvang Joshif1df5582012-06-07 11:04:57 +0530340 WebPData webp_data;
341 const WebPMuxError err = WebPMuxAssemble(mux, &webp_data);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530342 if (err != WEBP_MUX_OK) {
Urvang Joshid11f6fc2012-06-27 16:55:01 +0530343 fprintf(stderr, "Error (%s) assembling the WebP file.\n", ErrorString(err));
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530344 return 0;
345 }
Urvang Joshif1df5582012-06-07 11:04:57 +0530346 ok = WriteData(filename, &webp_data);
347 WebPDataClear(&webp_data);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530348 return ok;
349}
350
Urvang Joshiab3234a2012-08-23 15:18:51 +0530351static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) {
352 return (sscanf(args, "+%d+%d+%d",
353 &info->x_offset_, &info->y_offset_, &info->duration_) == 3);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530354}
355
Urvang Joshiab3234a2012-08-23 15:18:51 +0530356static int ParseTileArgs(const char* args, WebPMuxFrameInfo* const info) {
357 return (sscanf(args, "+%d+%d", &info->x_offset_, &info->y_offset_) == 2);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530358}
359
360//------------------------------------------------------------------------------
361// Clean-up.
362
363static void DeleteConfig(WebPMuxConfig* config) {
364 if (config != NULL) {
365 free(config->feature_.args_);
366 free(config);
367 }
368}
369
370//------------------------------------------------------------------------------
371// Parsing.
372
373// Basic syntactic checks on the command-line arguments.
374// Returns 1 on valid, 0 otherwise.
375// Also fills up num_feature_args to be number of feature arguments given.
376// (e.g. if there are 4 '-frame's and 1 '-loop', then num_feature_args = 5).
377static int ValidateCommandLine(int argc, const char* argv[],
378 int* num_feature_args) {
379 int num_frame_args;
380 int num_tile_args;
381 int num_loop_args;
382 int ok = 1;
383
384 assert(num_feature_args != NULL);
385 *num_feature_args = 0;
386
387 // Simple checks.
James Zern04e84cf2011-11-04 15:20:08 -0700388 if (CountOccurrences(argv, argc, "-get") > 1) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530389 ERROR_GOTO1("ERROR: Multiple '-get' arguments specified.\n", ErrValidate);
390 }
James Zern04e84cf2011-11-04 15:20:08 -0700391 if (CountOccurrences(argv, argc, "-set") > 1) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530392 ERROR_GOTO1("ERROR: Multiple '-set' arguments specified.\n", ErrValidate);
393 }
James Zern04e84cf2011-11-04 15:20:08 -0700394 if (CountOccurrences(argv, argc, "-strip") > 1) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530395 ERROR_GOTO1("ERROR: Multiple '-strip' arguments specified.\n", ErrValidate);
396 }
James Zern04e84cf2011-11-04 15:20:08 -0700397 if (CountOccurrences(argv, argc, "-info") > 1) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530398 ERROR_GOTO1("ERROR: Multiple '-info' arguments specified.\n", ErrValidate);
399 }
James Zern04e84cf2011-11-04 15:20:08 -0700400 if (CountOccurrences(argv, argc, "-o") > 1) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530401 ERROR_GOTO1("ERROR: Multiple output files specified.\n", ErrValidate);
402 }
403
404 // Compound checks.
James Zern04e84cf2011-11-04 15:20:08 -0700405 num_frame_args = CountOccurrences(argv, argc, "-frame");
406 num_tile_args = CountOccurrences(argv, argc, "-tile");
407 num_loop_args = CountOccurrences(argv, argc, "-loop");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530408
409 if (num_loop_args > 1) {
410 ERROR_GOTO1("ERROR: Multiple loop counts specified.\n", ErrValidate);
411 }
412
413 if (IsNotCompatible(num_frame_args, num_loop_args)) {
414 ERROR_GOTO1("ERROR: Both frames and loop count have to be specified.\n",
415 ErrValidate);
416 }
417 if (num_frame_args > 0 && num_tile_args > 0) {
418 ERROR_GOTO1("ERROR: Only one of frames & tiles can be specified at a time."
419 "\n", ErrValidate);
420 }
421
422 assert(ok == 1);
423 if (num_frame_args == 0 && num_tile_args == 0) {
Urvang Joshif6c096a2012-08-23 15:54:13 +0530424 // Single argument ('set' action for META or ICCP, OR a 'get' action).
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530425 *num_feature_args = 1;
426 } else {
427 // Multiple arguments ('set' action for animation or tiling).
428 if (num_frame_args > 0) {
429 *num_feature_args = num_frame_args + num_loop_args;
430 } else {
431 *num_feature_args = num_tile_args;
432 }
433 }
434
435 ErrValidate:
436 return ok;
437}
438
439#define ACTION_IS_NIL (config->action_type_ == NIL_ACTION)
440
441#define FEATURETYPE_IS_NIL (feature->type_ == NIL_FEATURE)
442
443#define CHECK_NUM_ARGS_LESS(NUM, LABEL) \
444 if (argc < i + (NUM)) { \
445 fprintf(stderr, "ERROR: Too few arguments for '%s'.\n", argv[i]); \
446 goto LABEL; \
447 }
448
449#define CHECK_NUM_ARGS_NOT_EQUAL(NUM, LABEL) \
450 if (argc != i + (NUM)) { \
451 fprintf(stderr, "ERROR: Too many arguments for '%s'.\n", argv[i]); \
452 goto LABEL; \
453 }
454
455// Parses command-line arguments to fill up config object. Also performs some
456// semantic checks.
457static int ParseCommandLine(int argc, const char* argv[],
458 WebPMuxConfig* config) {
459 int i = 0;
460 int feature_arg_index = 0;
461 int ok = 1;
462
463 while (i < argc) {
464 Feature* const feature = &config->feature_;
James Zern04e84cf2011-11-04 15:20:08 -0700465 FeatureArg* const arg = &feature->args_[feature_arg_index];
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530466 if (argv[i][0] == '-') { // One of the action types or output.
467 if (!strcmp(argv[i], "-set")) {
468 if (ACTION_IS_NIL) {
469 config->action_type_ = ACTION_SET;
470 } else {
471 ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
472 }
473 ++i;
474 } else if (!strcmp(argv[i], "-get")) {
475 if (ACTION_IS_NIL) {
476 config->action_type_ = ACTION_GET;
477 } else {
478 ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
479 }
480 ++i;
481 } else if (!strcmp(argv[i], "-strip")) {
482 if (ACTION_IS_NIL) {
483 config->action_type_ = ACTION_STRIP;
484 feature->arg_count_ = 0;
485 } else {
486 ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
487 }
488 ++i;
489 } else if (!strcmp(argv[i], "-frame")) {
490 CHECK_NUM_ARGS_LESS(3, ErrParse);
491 if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) {
492 config->action_type_ = ACTION_SET;
493 } else {
494 ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
495 }
496 if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_FRM) {
497 feature->type_ = FEATURE_FRM;
498 } else {
499 ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
500 }
501 arg->subtype_ = SUBTYPE_FRM;
502 arg->filename_ = argv[i + 1];
503 arg->params_ = argv[i + 2];
504 ++feature_arg_index;
505 i += 3;
506 } else if (!strcmp(argv[i], "-loop")) {
507 CHECK_NUM_ARGS_LESS(2, ErrParse);
508 if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) {
509 config->action_type_ = ACTION_SET;
510 } else {
511 ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
512 }
513 if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_FRM) {
514 feature->type_ = FEATURE_FRM;
515 } else {
516 ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
517 }
518 arg->subtype_ = SUBTYPE_LOOP;
519 arg->params_ = argv[i + 1];
520 ++feature_arg_index;
521 i += 2;
522 } else if (!strcmp(argv[i], "-tile")) {
523 CHECK_NUM_ARGS_LESS(3, ErrParse);
524 if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) {
525 config->action_type_ = ACTION_SET;
526 } else {
527 ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
528 }
529 if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_TILE) {
530 feature->type_ = FEATURE_TILE;
531 } else {
532 ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
533 }
534 arg->filename_ = argv[i + 1];
535 arg->params_ = argv[i + 2];
536 ++feature_arg_index;
537 i += 3;
538 } else if (!strcmp(argv[i], "-o")) {
539 CHECK_NUM_ARGS_LESS(2, ErrParse);
540 config->output_ = argv[i + 1];
541 i += 2;
542 } else if (!strcmp(argv[i], "-info")) {
543 CHECK_NUM_ARGS_NOT_EQUAL(2, ErrParse);
544 if (config->action_type_ != NIL_ACTION) {
545 ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
546 } else {
547 config->action_type_ = ACTION_INFO;
548 feature->arg_count_ = 0;
549 config->input_ = argv[i + 1];
550 }
551 i += 2;
552 } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help")) {
553 PrintHelp();
554 DeleteConfig(config);
James Zern974aaff2012-01-24 12:46:46 -0800555 exit(0);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530556 } else {
557 ERROR_GOTO2("ERROR: Unknown option: '%s'.\n", argv[i], ErrParse);
558 }
559 } else { // One of the feature types or input.
560 if (ACTION_IS_NIL) {
561 ERROR_GOTO1("ERROR: Action must be specified before other arguments.\n",
562 ErrParse);
563 }
Urvang Joshif6c096a2012-08-23 15:54:13 +0530564 if (!strcmp(argv[i], "icc") || !strcmp(argv[i], "meta")) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530565 if (FEATURETYPE_IS_NIL) {
566 feature->type_ = (!strcmp(argv[i], "icc")) ? FEATURE_ICCP :
Urvang Joshif6c096a2012-08-23 15:54:13 +0530567 FEATURE_META;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530568 } else {
569 ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
570 }
571 if (config->action_type_ == ACTION_SET) {
572 CHECK_NUM_ARGS_LESS(2, ErrParse);
573 arg->filename_ = argv[i + 1];
574 ++feature_arg_index;
575 i += 2;
576 } else {
577 ++i;
578 }
579 } else if ((!strcmp(argv[i], "frame") ||
580 !strcmp(argv[i], "tile")) &&
581 (config->action_type_ == ACTION_GET)) {
582 CHECK_NUM_ARGS_LESS(2, ErrParse);
583 feature->type_ = (!strcmp(argv[i], "frame")) ? FEATURE_FRM :
584 FEATURE_TILE;
585 arg->params_ = argv[i + 1];
586 ++feature_arg_index;
587 i += 2;
James Zern04e84cf2011-11-04 15:20:08 -0700588 } else { // Assume input file.
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530589 if (config->input_ == NULL) {
590 config->input_ = argv[i];
591 } else {
592 ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n",
593 argv[i], ErrParse);
594 }
595 ++i;
596 }
597 }
598 }
599 ErrParse:
600 return ok;
601}
602
James Zern04e84cf2011-11-04 15:20:08 -0700603// Additional checks after config is filled.
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530604static int ValidateConfig(WebPMuxConfig* config) {
605 int ok = 1;
606 Feature* const feature = &config->feature_;
607
608 // Action.
609 if (ACTION_IS_NIL) {
610 ERROR_GOTO1("ERROR: No action specified.\n", ErrValidate2);
611 }
612
613 // Feature type.
614 if (FEATURETYPE_IS_NIL && config->action_type_ != ACTION_INFO) {
615 ERROR_GOTO1("ERROR: No feature specified.\n", ErrValidate2);
616 }
617
618 // Input file.
619 if (config->input_ == NULL) {
620 if (config->action_type_ != ACTION_SET) {
621 ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
622 } else if (feature->type_ != FEATURE_FRM &&
623 feature->type_ != FEATURE_TILE) {
624 ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
625 }
626 }
627
628 // Output file.
629 if (config->output_ == NULL && config->action_type_ != ACTION_INFO) {
630 ERROR_GOTO1("ERROR: No output file specified.\n", ErrValidate2);
631 }
632
633 ErrValidate2:
634 return ok;
635}
636
637// Create config object from command-line arguments.
638static int InitializeConfig(int argc, const char* argv[],
639 WebPMuxConfig** config) {
640 int num_feature_args = 0;
641 int ok = 1;
642
643 assert(config != NULL);
644 *config = NULL;
645
646 // Validate command-line arguments.
647 if (!ValidateCommandLine(argc, argv, &num_feature_args)) {
648 ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1);
649 }
650
651 // Allocate memory.
652 *config = (WebPMuxConfig*)calloc(1, sizeof(**config));
653 if (*config == NULL) {
654 ERROR_GOTO1("ERROR: Memory allocation error.\n", Err1);
655 }
656 (*config)->feature_.arg_count_ = num_feature_args;
657 (*config)->feature_.args_ =
658 (FeatureArg*)calloc(num_feature_args, sizeof(FeatureArg));
659 if ((*config)->feature_.args_ == NULL) {
660 ERROR_GOTO1("ERROR: Memory allocation error.\n", Err1);
661 }
662
663 // Parse command-line.
James Zern04e84cf2011-11-04 15:20:08 -0700664 if (!ParseCommandLine(argc, argv, *config) ||
665 !ValidateConfig(*config)) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530666 ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1);
667 }
668
669 Err1:
670 return ok;
671}
672
673#undef ACTION_IS_NIL
674#undef FEATURETYPE_IS_NIL
675#undef CHECK_NUM_ARGS_LESS
676#undef CHECK_NUM_ARGS_MORE
677
678//------------------------------------------------------------------------------
679// Processing.
680
James Zern04e84cf2011-11-04 15:20:08 -0700681static int GetFrameTile(const WebPMux* mux,
682 const WebPMuxConfig* config, int isFrame) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530683 WebPMuxError err = WEBP_MUX_OK;
684 WebPMux* mux_single = NULL;
685 long num = 0;
686 int ok = 1;
Urvang Joshi92f80592012-10-30 12:14:10 -0700687 const WebPChunkId id = isFrame ? WEBP_CHUNK_ANMF : WEBP_CHUNK_FRGM;
Urvang Joshiab3234a2012-08-23 15:18:51 +0530688 WebPMuxFrameInfo info;
689 WebPDataInit(&info.bitstream_);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530690
691 num = strtol(config->feature_.args_[0].params_, NULL, 10);
692 if (num < 0) {
693 ERROR_GOTO1("ERROR: Frame/Tile index must be non-negative.\n", ErrGet);
694 }
695
Urvang Joshid0c79f02012-08-23 16:28:36 +0530696 err = WebPMuxGetFrame(mux, num, &info);
697 if (err == WEBP_MUX_OK && info.id != id) err = WEBP_MUX_NOT_FOUND;
698 if (err != WEBP_MUX_OK) {
699 ERROR_GOTO3("ERROR (%s): Could not get frame %ld.\n",
700 ErrorString(err), num, ErrGet);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530701 }
702
703 mux_single = WebPMuxNew();
704 if (mux_single == NULL) {
705 err = WEBP_MUX_MEMORY_ERROR;
Urvang Joshid11f6fc2012-06-27 16:55:01 +0530706 ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n",
707 ErrorString(err), ErrGet);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530708 }
Urvang Joshiab3234a2012-08-23 15:18:51 +0530709 err = WebPMuxSetImage(mux_single, &info.bitstream_, 1);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530710 if (err != WEBP_MUX_OK) {
Urvang Joshid11f6fc2012-06-27 16:55:01 +0530711 ERROR_GOTO2("ERROR (%s): Could not create single image mux object.\n",
712 ErrorString(err), ErrGet);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530713 }
Urvang Joshid0c79f02012-08-23 16:28:36 +0530714
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530715 ok = WriteWebP(mux_single, config->output_);
716
717 ErrGet:
Urvang Joshiab3234a2012-08-23 15:18:51 +0530718 WebPDataClear(&info.bitstream_);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530719 WebPMuxDelete(mux_single);
720 return ok;
721}
722
723// Read and process config.
James Zern04e84cf2011-11-04 15:20:08 -0700724static int Process(const WebPMuxConfig* config) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530725 WebPMux* mux = NULL;
Urvang Joshi4fc4a472012-06-05 14:20:45 +0530726 WebPData metadata, color_profile;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530727 WebPMuxError err = WEBP_MUX_OK;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530728 int index = 0;
729 int ok = 1;
James Zern04e84cf2011-11-04 15:20:08 -0700730 const Feature* const feature = &config->feature_;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530731
James Zern04e84cf2011-11-04 15:20:08 -0700732 switch (config->action_type_) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530733 case ACTION_GET:
James Zern061263a2012-05-11 16:00:57 -0700734 ok = CreateMux(config->input_, &mux);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530735 if (!ok) goto Err2;
James Zern04e84cf2011-11-04 15:20:08 -0700736 switch (feature->type_) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530737 case FEATURE_FRM:
738 ok = GetFrameTile(mux, config, 1);
739 break;
740
741 case FEATURE_TILE:
742 ok = GetFrameTile(mux, config, 0);
743 break;
744
745 case FEATURE_ICCP:
Urvang Joshi1c04a0d2012-08-23 15:28:20 +0530746 err = WebPMuxGetChunk(mux, "ICCP", &color_profile);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530747 if (err != WEBP_MUX_OK) {
Urvang Joshid11f6fc2012-06-27 16:55:01 +0530748 ERROR_GOTO2("ERROR (%s): Could not get color profile.\n",
749 ErrorString(err), Err2);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530750 }
Urvang Joshiab3234a2012-08-23 15:18:51 +0530751 ok = WriteData(config->output_, &color_profile);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530752 break;
Urvang Joshif6c096a2012-08-23 15:54:13 +0530753 case FEATURE_META:
Urvang Joshi1c04a0d2012-08-23 15:28:20 +0530754 err = WebPMuxGetChunk(mux, "META", &metadata);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530755 if (err != WEBP_MUX_OK) {
Urvang Joshif6c096a2012-08-23 15:54:13 +0530756 ERROR_GOTO2("ERROR (%s): Could not get the metadata.\n",
Urvang Joshid11f6fc2012-06-27 16:55:01 +0530757 ErrorString(err), Err2);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530758 }
Urvang Joshiab3234a2012-08-23 15:18:51 +0530759 ok = WriteData(config->output_, &metadata);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530760 break;
761
762 default:
763 ERROR_GOTO1("ERROR: Invalid feature for action 'get'.\n", Err2);
764 break;
765 }
766 break;
767
768 case ACTION_SET:
James Zern04e84cf2011-11-04 15:20:08 -0700769 switch (feature->type_) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530770 case FEATURE_FRM:
771 mux = WebPMuxNew();
772 if (mux == NULL) {
Urvang Joshid11f6fc2012-06-27 16:55:01 +0530773 ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n",
774 ErrorString(WEBP_MUX_MEMORY_ERROR), Err2);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530775 }
776 for (index = 0; index < feature->arg_count_; ++index) {
777 if (feature->args_[index].subtype_ == SUBTYPE_LOOP) {
James Zern0f7820e2012-01-24 14:08:27 -0800778 const long num = strtol(feature->args_[index].params_, NULL, 10);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530779 if (num < 0) {
780 ERROR_GOTO1("ERROR: Loop count must be non-negative.\n", Err2);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530781 }
James Zern0f7820e2012-01-24 14:08:27 -0800782 err = WebPMuxSetLoopCount(mux, num);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530783 if (err != WEBP_MUX_OK) {
Urvang Joshid11f6fc2012-06-27 16:55:01 +0530784 ERROR_GOTO2("ERROR (%s): Could not set loop count.\n",
785 ErrorString(err), Err2);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530786 }
787 } else if (feature->args_[index].subtype_ == SUBTYPE_FRM) {
Urvang Joshiab3234a2012-08-23 15:18:51 +0530788 WebPMuxFrameInfo frame;
Urvang Joshib74ed6e2012-06-20 10:59:40 -0700789 ok = ReadFileToWebPData(feature->args_[index].filename_,
Urvang Joshiab3234a2012-08-23 15:18:51 +0530790 &frame.bitstream_);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530791 if (!ok) goto Err2;
Urvang Joshiab3234a2012-08-23 15:18:51 +0530792 ok = ParseFrameArgs(feature->args_[index].params_, &frame);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530793 if (!ok) {
Urvang Joshiab3234a2012-08-23 15:18:51 +0530794 WebPDataClear(&frame.bitstream_);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530795 ERROR_GOTO1("ERROR: Could not parse frame properties.\n", Err2);
796 }
Urvang Joshi92f80592012-10-30 12:14:10 -0700797 frame.id = WEBP_CHUNK_ANMF;
Urvang Joshiab3234a2012-08-23 15:18:51 +0530798 err = WebPMuxPushFrame(mux, &frame, 1);
799 WebPDataClear(&frame.bitstream_);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530800 if (err != WEBP_MUX_OK) {
Urvang Joshid11f6fc2012-06-27 16:55:01 +0530801 ERROR_GOTO3("ERROR (%s): Could not add a frame at index %d.\n",
802 ErrorString(err), index, Err2);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530803 }
804 } else {
805 ERROR_GOTO1("ERROR: Invalid subtype for 'frame'", Err2);
806 }
807 }
808 break;
809
810 case FEATURE_TILE:
811 mux = WebPMuxNew();
812 if (mux == NULL) {
Urvang Joshid11f6fc2012-06-27 16:55:01 +0530813 ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n",
814 ErrorString(WEBP_MUX_MEMORY_ERROR), Err2);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530815 }
816 for (index = 0; index < feature->arg_count_; ++index) {
Urvang Joshiab3234a2012-08-23 15:18:51 +0530817 WebPMuxFrameInfo tile;
818 ok = ReadFileToWebPData(feature->args_[index].filename_,
819 &tile.bitstream_);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530820 if (!ok) goto Err2;
Urvang Joshiab3234a2012-08-23 15:18:51 +0530821 ok = ParseTileArgs(feature->args_[index].params_, &tile);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530822 if (!ok) {
Urvang Joshiab3234a2012-08-23 15:18:51 +0530823 WebPDataClear(&tile.bitstream_);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530824 ERROR_GOTO1("ERROR: Could not parse tile properties.\n", Err2);
825 }
Urvang Joshi92f80592012-10-30 12:14:10 -0700826 tile.id = WEBP_CHUNK_FRGM;
Urvang Joshid0c79f02012-08-23 16:28:36 +0530827 err = WebPMuxPushFrame(mux, &tile, 1);
Urvang Joshiab3234a2012-08-23 15:18:51 +0530828 WebPDataClear(&tile.bitstream_);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530829 if (err != WEBP_MUX_OK) {
Urvang Joshid11f6fc2012-06-27 16:55:01 +0530830 ERROR_GOTO3("ERROR (%s): Could not add a tile at index %d.\n",
831 ErrorString(err), index, Err2);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530832 }
833 }
834 break;
835
836 case FEATURE_ICCP:
James Zern061263a2012-05-11 16:00:57 -0700837 ok = CreateMux(config->input_, &mux);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530838 if (!ok) goto Err2;
Urvang Joshi4fc4a472012-06-05 14:20:45 +0530839 ok = ReadFileToWebPData(feature->args_[0].filename_, &color_profile);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530840 if (!ok) goto Err2;
Urvang Joshi1c04a0d2012-08-23 15:28:20 +0530841 err = WebPMuxSetChunk(mux, "ICCP", &color_profile, 1);
Urvang Joshi4fc4a472012-06-05 14:20:45 +0530842 free((void*)color_profile.bytes_);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530843 if (err != WEBP_MUX_OK) {
Urvang Joshid11f6fc2012-06-27 16:55:01 +0530844 ERROR_GOTO2("ERROR (%s): Could not set color profile.\n",
845 ErrorString(err), Err2);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530846 }
847 break;
848
Urvang Joshif6c096a2012-08-23 15:54:13 +0530849 case FEATURE_META:
James Zern061263a2012-05-11 16:00:57 -0700850 ok = CreateMux(config->input_, &mux);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530851 if (!ok) goto Err2;
Urvang Joshi4fc4a472012-06-05 14:20:45 +0530852 ok = ReadFileToWebPData(feature->args_[0].filename_, &metadata);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530853 if (!ok) goto Err2;
Urvang Joshi1c04a0d2012-08-23 15:28:20 +0530854 err = WebPMuxSetChunk(mux, "META", &metadata, 1);
Urvang Joshi4fc4a472012-06-05 14:20:45 +0530855 free((void*)metadata.bytes_);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530856 if (err != WEBP_MUX_OK) {
Urvang Joshif6c096a2012-08-23 15:54:13 +0530857 ERROR_GOTO2("ERROR (%s): Could not set the metadata.\n",
Urvang Joshid11f6fc2012-06-27 16:55:01 +0530858 ErrorString(err), Err2);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530859 }
860 break;
861
862 default:
863 ERROR_GOTO1("ERROR: Invalid feature for action 'set'.\n", Err2);
864 break;
865 }
866 ok = WriteWebP(mux, config->output_);
867 break;
868
869 case ACTION_STRIP:
James Zern061263a2012-05-11 16:00:57 -0700870 ok = CreateMux(config->input_, &mux);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530871 if (!ok) goto Err2;
James Zern04e84cf2011-11-04 15:20:08 -0700872 switch (feature->type_) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530873 case FEATURE_ICCP:
Urvang Joshi1c04a0d2012-08-23 15:28:20 +0530874 err = WebPMuxDeleteChunk(mux, "ICCP");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530875 if (err != WEBP_MUX_OK) {
Urvang Joshid11f6fc2012-06-27 16:55:01 +0530876 ERROR_GOTO2("ERROR (%s): Could not delete color profile.\n",
877 ErrorString(err), Err2);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530878 }
879 break;
Urvang Joshif6c096a2012-08-23 15:54:13 +0530880 case FEATURE_META:
Urvang Joshi1c04a0d2012-08-23 15:28:20 +0530881 err = WebPMuxDeleteChunk(mux, "META");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530882 if (err != WEBP_MUX_OK) {
Urvang Joshif6c096a2012-08-23 15:54:13 +0530883 ERROR_GOTO2("ERROR (%s): Could not delete the metadata.\n",
Urvang Joshid11f6fc2012-06-27 16:55:01 +0530884 ErrorString(err), Err2);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530885 }
886 break;
887 default:
888 ERROR_GOTO1("ERROR: Invalid feature for action 'strip'.\n", Err2);
889 break;
890 }
891 ok = WriteWebP(mux, config->output_);
892 break;
893
894 case ACTION_INFO:
James Zern061263a2012-05-11 16:00:57 -0700895 ok = CreateMux(config->input_, &mux);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530896 if (!ok) goto Err2;
897 ok = (DisplayInfo(mux) == WEBP_MUX_OK);
898 break;
899
900 default:
901 assert(0); // Invalid action.
902 break;
903 }
904
905 Err2:
906 WebPMuxDelete(mux);
907 return ok;
908}
909
910//------------------------------------------------------------------------------
911// Main.
912
913int main(int argc, const char* argv[]) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530914 WebPMuxConfig* config;
James Zern974aaff2012-01-24 12:46:46 -0800915 int ok = InitializeConfig(argc - 1, argv + 1, &config);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530916 if (ok) {
James Zern974aaff2012-01-24 12:46:46 -0800917 ok = Process(config);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530918 } else {
919 PrintHelp();
920 }
921 DeleteConfig(config);
James Zern974aaff2012-01-24 12:46:46 -0800922 return !ok;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530923}
924
925//------------------------------------------------------------------------------