UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
main.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011, Martin Srom
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#define DEBUG
28#include "dxt_encoder.h"
29#include "dxt_decoder.h"
30#include "dxt_display.h"
31
32#include <getopt.h>
33#include <string.h>
34#include <strings.h>
35
36#define RUN_MAX 100
37
38static float duration[RUN_MAX];
39
40void
41printf_duration(const char* name, int run)
42{
43 float min = 999999.0f;
44 float max = 0.0f;
45 float middle = 0.0f;
46 float avg = 0.0f;
47 for ( int index = 0; index < run; index++ ) {
48 if ( duration[index] < min )
49 min = duration[index];
50 if ( duration[index] > max )
51 max = duration[index];
52 avg += duration[index];
53 }
54 avg /= (float)run;
55 middle = duration[run / 2];
56
57 printf("%s: %0.2f ms (med %0.1f ms, min %0.1f ms, max %0.1f ms)\n", name, avg, middle, min, max);
58}
59
60int
61perform_encode(const char* filename_in, const char* filename_out, enum dxt_type type,
62 int width, int height, enum dxt_format format, int display, int run)
63{
64 DXT_IMAGE_TYPE* image = NULL;
65 if ( dxt_image_load_from_file(filename_in, width, height, &image) != 0 ) {
66 fprintf(stderr, "Failed to load image [%s]!\n", filename_in);
67 return -1;
68 }
69
70 if ( display == 1 )
71 dxt_display_image("Encode Before", image, width, height);
72
74 if ( encoder == NULL ) {
75 fprintf(stderr, "Create DXT encoder failed!\n");
76 return -1;
77 }
78
79 unsigned char* image_compressed = NULL;
80 int image_compressed_size = 0;
81 if ( dxt_encoder_buffer_allocate(encoder, &image_compressed, &image_compressed_size) != 0 ) {
82 fprintf(stderr, "DXT encoder allocation failed!\n");
83 return -1;
84 }
85
86 TIMER_INIT();
87 for ( int index = 0; index < run; index++ ) {
89 if ( dxt_encoder_compress(encoder, image, image_compressed) != 0 ) {
90 fprintf(stderr, "DXT encoder compressing failed!\n");
91 return -1;
92 }
93 TIMER_STOP();
94 duration[index] = TIMER_DURATION();
95 }
96 printf_duration("Encoding Duration", run);
97
98 if ( display == 1 )
99 dxt_display_image_compressed("Encode After", image_compressed, image_compressed_size, type, width, height);
100
101 if ( dxt_image_compressed_save_to_file(filename_out, image_compressed, image_compressed_size) != 0 ) {
102 fprintf(stderr, "Failed to save compressed image [%s]!\n", filename_out);
103 return -1;
104 }
105
106 dxt_encoder_buffer_free(image_compressed);
108 dxt_image_destroy(image);
109
110 return 0;
111}
112
113int
114perform_decode(const char* filename_in, const char* filename_out, enum dxt_type type,
115 int width, int height, int display, int run)
116{
117 unsigned char* image_compressed = NULL;
118 int image_compressed_size = 0;
119 if ( dxt_image_compressed_load_from_file(filename_in, &image_compressed, &image_compressed_size) != 0 ) {
120 fprintf(stderr, "Failed to load compressed image [%s]!\n", filename_in);
121 return -1;
122 }
123
124 if ( display == 1 )
125 dxt_display_image_compressed("Decode Before", image_compressed, image_compressed_size, type, width, height);
126
128 if ( decoder == NULL ) {
129 fprintf(stderr, "Create DXT decoder failed!\n");
130 return -1;
131 }
132
133 DXT_IMAGE_TYPE* image = NULL;
134 int image_size = 0;
135 if ( dxt_decoder_buffer_allocate(decoder, &image, &image_size) != 0 ) {
136 fprintf(stderr, "DXT decoder allocation failed!\n");
137 return -1;
138 }
139
140 TIMER_INIT();
141 for ( int index = 0; index < run; index++ ) {
142 TIMER_START();
143 if ( dxt_decoder_decompress(decoder, image_compressed, image) != 0 ) {
144 fprintf(stderr, "DXT decoder decompressing failed!\n");
145 return -1;
146 }
147 TIMER_STOP();
148 duration[index] = TIMER_DURATION();
149 }
150 printf_duration("Decoding Duration", run);
151
152 if ( display == 1 )
153 dxt_display_image("Decode After", image, width, height);
154
155 if ( dxt_image_save_to_file(filename_out, image, width, height) != 0 ) {
156 fprintf(stderr, "Failed to save image [%s]!\n", filename_out);
157 return -1;
158 }
159
161 dxt_decoder_destroy(decoder);
162 dxt_image_compressed_destroy(image_compressed);
163
164 return 0;
165}
166
167const char*
168get_filename_extension(const char* filename)
169{
170 char * ext = strrchr(filename, '.');
171 if ( ext == NULL )
172 return NULL;
173 ext++;
174 return ext;
175}
176
177int
178perform_display(const char* filename, enum dxt_type type, int width, int height, enum dxt_format format)
179{
180 // Get file extension
181 const char * ext = get_filename_extension(filename);
182
183 // Display image in RGB format
184 if ( strncasecmp(ext, "rgb", 3) == 0 ) {
185 DXT_IMAGE_TYPE* image = NULL;
186 if ( dxt_image_load_from_file(filename, width, height, &image) != 0 ) {
187 fprintf(stderr, "Failed to load image [%s]!\n", filename);
188 return -1;
189 }
190 dxt_display_image("Display RGB Image", image, width, height);
191 dxt_image_destroy(image);
192 }
193 // Display image in DXT buffer format
194 else {
195 unsigned char* image_compressed = NULL;
196 int image_compressed_size = 0;
197 if ( dxt_image_compressed_load_from_file(filename, &image_compressed, &image_compressed_size) != 0 ) {
198 fprintf(stderr, "Failed to load compressed image [%s]!\n", filename);
199 return -1;
200 }
201 dxt_display_image_compressed("Display DXT Compressed Image", image_compressed, image_compressed_size, type, width, height);
202 dxt_image_compressed_destroy(image_compressed);
203 }
204}
205
206int
207perform_comparison(const char* input, const char* output, enum dxt_type type, int width, int height, enum dxt_format format)
208{
209 // Get file extensions
210 const char * input_ext = get_filename_extension(input);
211 const char * output_ext = get_filename_extension(output);
212
213 // Set proper filenames
214 const char * filename_image = NULL;
215 const char * filename_image_compressed = NULL;
216 if ( strncasecmp(input_ext, "rgb", 3) == 0 )
217 filename_image = input;
218 else
219 filename_image_compressed = input;
220 if ( strncasecmp(output_ext, "rgb", 3) == 0 )
221 filename_image = output;
222 else
223 filename_image_compressed = output;
224
225 if ( filename_image == NULL || filename_image_compressed == NULL ) {
226 fprintf(stderr, "Display comparison can't be performed, one file must be RGB image and one compressed image!\n");
227 return -1;
228 }
229
230 // Load images
231 DXT_IMAGE_TYPE* image = NULL;
232 unsigned char* image_compressed = NULL;
233 int image_compressed_size = 0;
234 if ( dxt_image_load_from_file(filename_image, width, height, &image) != 0 ) {
235 fprintf(stderr, "Failed to load image [%s]!\n", filename_image);
236 return -1;
237 }
238 if ( dxt_image_compressed_load_from_file(filename_image_compressed, &image_compressed, &image_compressed_size) != 0 ) {
239 fprintf(stderr, "Failed to load compressed image [%s]!\n", filename_image_compressed);
240 return -1;
241 }
242
243 dxt_display_image_comparison(image, image_compressed, image_compressed_size, type, width, height);
244 dxt_image_destroy(image);
245 dxt_image_compressed_destroy(image_compressed);
246
247 return 0;
248}
249
250void
252{
253 printf(
254 "dxt_compress [options]\n"
255 " -h, --help\t\tprint help\n"
256 " -e, --encode\t\tencode image from RGB format to DXT data buffer\n"
257 " -d, --decode\t\tdecode image from DXT data buffer to RGB format\n"
258 " -s, --size\t\timage size in pixels, e.g. 1920x1080\n"
259 " -i, --input\t\tinput image in RGB format\n"
260 " -o, --output\t\toutput image in RGB format\n"
261 " --display\tdisplay image or compare images\n"
262 " -t, --type\t\tdxt type 'dxt1' or 'dxt5ycocg' (default 'dxt5ycocg')\n"
263 " -f, --format\t\tcolor format 'rgb' or 'yuv' (default 'rgb')\n"
264 " -r, --run\t\tmultiple run times for debugging (default 1)\n"
265 );
266}
267
268int
269main(int argc, char *argv[])
270{
271 struct option longopts[] = {
272 {"help", no_argument, 0, 'h'},
273 {"encode", no_argument, 0, 'e'},
274 {"decode", no_argument, 0, 'd'},
275 {"size", required_argument, 0, 's'},
276 {"input", required_argument, 0, 'i'},
277 {"output", required_argument, 0, 'o'},
278 {"display", no_argument, 0, 1 },
279 {"type", required_argument, 0, 't'},
280 {"format", required_argument, 0, 'f'},
281 {"run", required_argument, 0, 'r'},
282 {"batch", no_argument, 0, 'b'},
283 };
284
285 // Parameters
287 enum dxt_format format = DXT_FORMAT_RGBA; // encoder _internal_ format (!)
288 int width = 512;
289 int height = 512;
290 int encode = 0;
291 int decode = 0;
292 char input[255] = { '\0' };
293 char output[255] = { '\0' };
294 int display = 0;
295 int run = 1;
296 int batch = 0;
297
298 // Parse command line
299 char ch = '\0';
300 int optindex = 0;
301 char* pos = 0;
302 while ( (ch = getopt_long(argc, argv, "heds:i:o:t:f:b", longopts, &optindex)) != -1 ) {
303 switch (ch) {
304 case 'h':
305 print_help();
306 return 0;
307 case 'e':
308 encode = 1;
309 break;
310 case 'd':
311 decode = 1;
312 break;
313 case 's':
314 width = atoi(optarg);
315 pos = strstr(optarg, "x");
316 if ( pos == NULL || width == 0 || (strlen(pos) >= strlen(optarg)) ) {
317 print_help();
318 return -1;
319 }
320 height = atoi(pos + 1);
321 break;
322 case 'i':
323 strncpy(input, optarg, 255);
324 break;
325 case 'o':
326 strncpy(output, optarg, 255);
327 break;
328 case 't':
329 if ( strcasecmp(optarg, "dxt1") == 0 )
331 else if ( strcasecmp(optarg, "dxt5ycocg") == 0 )
333 break;
334 case 'f':
335 if ( strcasecmp(optarg, "rgb") == 0 )
336 format = DXT_FORMAT_RGBA;
337 else if ( strcasecmp(optarg, "yuv") == 0 ) {
338 format = DXT_FORMAT_YUV;
339 fprintf(stderr, "yuv not supported!\n");
340 abort();
341 }
342 break;
343 case 'r':
344 run = atoi(optarg);
345 break;
346 case 1:
347 display = 1;
348 break;
349 case 'b':
350 batch = 1;
351 break;
352 case '?':
353 return -1;
354 default:
355 print_help();
356 return -1;
357 }
358 }
359 argc -= optind;
360 argv += optind;
361
362 if ( run > RUN_MAX ) {
363 printf("Warning: Maximum run times is %d using that number!\n", RUN_MAX);
364 run = RUN_MAX;
365 }
366
367 // Input image must be presented
368 if ( !batch && input[0] == '\0' ) {
369 printf("Please supply input image filename!\n");
370 print_help();
371 return -1;
372 }
373
374 // Output image must be presented for encoding or decoding
375 if ( !batch && output[0] == '\0' && (encode == 1 || decode == 1) ) {
376 printf("Please supply output image filename!\n");
377 print_help();
378 return -1;
379 }
380
381 // Init DXT compressor
382 if ( dxt_init() != 0 )
383 return -1;
384
385 // Perform encode
386 if ( encode == 1 ) {
387 if(batch) {
388 DXT_IMAGE_TYPE* image = NULL;
390 if ( encoder == NULL ) {
391 fprintf(stderr, "Create DXT encoder failed!\n");
392 return -1;
393 }
394
395 unsigned char* image_compressed = NULL;
396 int image_compressed_size = 0;
397 if ( dxt_encoder_buffer_allocate(encoder, &image_compressed, &image_compressed_size) != 0 ) {
398 fprintf(stderr, "DXT encoder allocation failed!\n");
399 return -1;
400 }
401
402 while (argc > 0) {
403 char *in_filename = argv[0];
404 char out_filename[512];
405
406 printf("encoding %s\n", in_filename);
407
408 snprintf(out_filename, 512, "%s.dxt", in_filename);
409 if ( dxt_image_load_from_file(in_filename, width, height, &image) != 0 ) {
410 fprintf(stderr, "Failed to load image [%s]!\n", in_filename);
411 return -1;
412 }
413
414 if ( dxt_encoder_compress(encoder, image, image_compressed) != 0 ) {
415 fprintf(stderr, "DXT encoder compressing failed!\n");
416 return -1;
417 }
418
419 if ( dxt_image_compressed_save_to_file(out_filename, image_compressed, image_compressed_size) != 0 ) {
420 fprintf(stderr, "Failed to save compressed image [%s]!\n", out_filename);
421 return -1;
422 }
423 dxt_image_destroy(image);
424
425 argc--;
426 argv++;
427 }
428
429 dxt_encoder_buffer_free(image_compressed);
431 } else {
432 if ( perform_encode(input, output, type, width, height, format, display, run) != 0 ) {
433 fprintf(stderr, "Failed to encode image [%s]!\n", input);
434 return -1;
435 }
436 }
437 }
438
439 // Setup input and output for decoding (when encoding was performed)
440 if ( encode == 1 && decode == 1 ) {
441 char new_output[255];
442 snprintf(new_output, 255, "decoded_%s", input);
443 strncpy(input, output, 255);
444 strncpy(output, new_output, 255);
445 }
446
447 // Perform decode
448 if ( decode == 1 ) {
449 if ( perform_decode(input, output, type, width, height, display, run) != 0 ) {
450 fprintf(stderr, "Failed to decode image [%s]!\n", input);
451 return -1;
452 }
453 }
454
455 // Only display image
456 if ( display == 1 && encode == 0 && decode == 0 ) {
457 if ( output[0] != '\0' ) {
458 if ( perform_comparison(input, output, type, width, height, format) != 0 ) {
459 fprintf(stderr, "Failed to perform comparison for images [%s, %s]!\n", input, output);
460 return -1;
461 }
462 } else {
463 if ( perform_display(input, type, width, height, format) != 0 ) {
464 fprintf(stderr, "Failed to display image [%s]!\n", input);
465 return -1;
466 }
467 }
468 }
469
470 return 0;
471}
int dxt_image_compressed_load_from_file(const char *filename, unsigned char **data, int *data_size)
Definition dxt_common.c:145
int dxt_image_destroy(DXT_IMAGE_TYPE *image)
Definition dxt_common.c:197
int dxt_image_load_from_file(const char *filename, int width, int height, DXT_IMAGE_TYPE **image)
Definition dxt_common.c:67
int dxt_image_save_to_file(const char *filename, DXT_IMAGE_TYPE *image, int width, int height)
Definition dxt_common.c:107
int dxt_image_compressed_destroy(unsigned char *image_compressed)
Definition dxt_common.c:206
int dxt_image_compressed_save_to_file(const char *filename, unsigned char *image, int image_size)
Definition dxt_common.c:173
int dxt_init()
Definition dxt_common.c:32
dxt_format
Definition dxt_common.h:78
@ DXT_FORMAT_RGBA
Definition dxt_common.h:80
@ DXT_FORMAT_YUV
Definition dxt_common.h:81
#define TIMER_START()
Definition dxt_common.h:56
dxt_type
Definition dxt_common.h:88
@ DXT_TYPE_DXT1
Definition dxt_common.h:89
@ DXT_TYPE_DXT5_YCOCG
Definition dxt_common.h:91
#define TIMER_INIT()
Definition dxt_common.h:52
#define TIMER_STOP()
Definition dxt_common.h:58
#define DXT_IMAGE_TYPE
Definition dxt_common.h:71
#define TIMER_DURATION()
Definition dxt_common.h:63
int dxt_decoder_buffer_free(unsigned char *image)
struct dxt_decoder * dxt_decoder_create(enum dxt_type type, int width, int height, enum dxt_format out_format, int legacy)
int dxt_decoder_buffer_allocate(struct dxt_decoder *decoder, unsigned char **image, int *image_size)
int dxt_decoder_destroy(struct dxt_decoder *decoder)
int dxt_decoder_decompress(struct dxt_decoder *decoder, unsigned char *image_compressed, DXT_IMAGE_TYPE *image)
int dxt_display_image(const char *title, DXT_IMAGE_TYPE *image, int width, int height)
int dxt_display_image_comparison(DXT_IMAGE_TYPE *image, unsigned char *image_compressed, int image_compressed_size, enum dxt_type type, int width, int height)
int dxt_display_image_compressed(const char *title, unsigned char *image_compressed, int image_compressed_size, enum dxt_type type, int width, int height)
int dxt_encoder_buffer_allocate(struct dxt_encoder *encoder, unsigned char **image_compressed, int *image_compressed_size)
int dxt_encoder_compress(struct dxt_encoder *encoder, DXT_IMAGE_TYPE *image, unsigned char *image_compressed)
struct dxt_encoder * dxt_encoder_create(enum dxt_type type, int width, int height, enum dxt_format format, int legacy)
int dxt_encoder_destroy(struct dxt_encoder *encoder)
int dxt_encoder_buffer_free(unsigned char *image_compressed)
steady_clock::duration duration
Definition echo.cpp:67
int perform_encode(const char *filename_in, const char *filename_out, enum dxt_type type, int width, int height, enum dxt_format format, int display, int run)
Definition main.c:61
#define RUN_MAX
Definition main.c:36
int perform_decode(const char *filename_in, const char *filename_out, enum dxt_type type, int width, int height, int display, int run)
Definition main.c:114
const char * get_filename_extension(const char *filename)
Definition main.c:168
void printf_duration(const char *name, int run)
Definition main.c:41
void print_help()
Definition main.c:251
int perform_comparison(const char *input, const char *output, enum dxt_type type, int width, int height, enum dxt_format format)
Definition main.c:207
int perform_display(const char *filename, enum dxt_type type, int width, int height, enum dxt_format format)
Definition main.c:178
Option::OptType type
Definition settings.cpp:194
const char * name
Definition settings.cpp:193
This struct represents initialized video display state.
enum dxt_format format
Definition dxt_encoder.c:88