Files
UltraGrid/dxt_compress/main.c
2012-09-07 11:05:28 +02:00

472 lines
16 KiB
C

/*
* Copyright (c) 2011, Martin Srom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#define DEBUG
#include "dxt_encoder.h"
#include "dxt_decoder.h"
#include "dxt_display.h"
#include <getopt.h>
#include <string.h>
#include <strings.h>
#define RUN_MAX 100
static float duration[RUN_MAX];
void
printf_duration(const char* name, int run)
{
float min = 999999.0f;
float max = 0.0f;
float middle = 0.0f;
float avg = 0.0f;
for ( int index = 0; index < run; index++ ) {
if ( duration[index] < min )
min = duration[index];
if ( duration[index] > max )
max = duration[index];
avg += duration[index];
}
avg /= (float)run;
middle = duration[run / 2];
printf("%s: %0.2f ms (med %0.1f ms, min %0.1f ms, max %0.1f ms)\n", name, avg, middle, min, max);
}
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)
{
DXT_IMAGE_TYPE* image = NULL;
if ( dxt_image_load_from_file(filename_in, width, height, &image) != 0 ) {
fprintf(stderr, "Failed to load image [%s]!\n", filename_in);
return -1;
}
if ( display == 1 )
dxt_display_image("Encode Before", image, width, height);
struct dxt_encoder* encoder = dxt_encoder_create(type, width, height, format, 1);
if ( encoder == NULL ) {
fprintf(stderr, "Create DXT encoder failed!\n");
return -1;
}
unsigned char* image_compressed = NULL;
int image_compressed_size = 0;
if ( dxt_encoder_buffer_allocate(encoder, &image_compressed, &image_compressed_size) != 0 ) {
fprintf(stderr, "DXT encoder allocation failed!\n");
return -1;
}
TIMER_INIT();
for ( int index = 0; index < run; index++ ) {
TIMER_START();
if ( dxt_encoder_compress(encoder, image, image_compressed) != 0 ) {
fprintf(stderr, "DXT encoder compressing failed!\n");
return -1;
}
TIMER_STOP();
duration[index] = TIMER_DURATION();
}
printf_duration("Encoding Duration", run);
if ( display == 1 )
dxt_display_image_compressed("Encode After", image_compressed, image_compressed_size, type, width, height);
if ( dxt_image_compressed_save_to_file(filename_out, image_compressed, image_compressed_size) != 0 ) {
fprintf(stderr, "Failed to save compressed image [%s]!\n", filename_out);
return -1;
}
dxt_encoder_buffer_free(image_compressed);
dxt_encoder_destroy(encoder);
dxt_image_destroy(image);
return 0;
}
int
perform_decode(const char* filename_in, const char* filename_out, enum dxt_type type,
int width, int height, int display, int run)
{
unsigned char* image_compressed = NULL;
int image_compressed_size = 0;
if ( dxt_image_compressed_load_from_file(filename_in, &image_compressed, &image_compressed_size) != 0 ) {
fprintf(stderr, "Failed to load compressed image [%s]!\n", filename_in);
return -1;
}
if ( display == 1 )
dxt_display_image_compressed("Decode Before", image_compressed, image_compressed_size, type, width, height);
struct dxt_decoder* decoder = dxt_decoder_create(type, width, height, DXT_FORMAT_RGBA, 1);
if ( decoder == NULL ) {
fprintf(stderr, "Create DXT decoder failed!\n");
return -1;
}
DXT_IMAGE_TYPE* image = NULL;
int image_size = 0;
if ( dxt_decoder_buffer_allocate(decoder, &image, &image_size) != 0 ) {
fprintf(stderr, "DXT decoder allocation failed!\n");
return -1;
}
TIMER_INIT();
for ( int index = 0; index < run; index++ ) {
TIMER_START();
if ( dxt_decoder_decompress(decoder, image_compressed, image) != 0 ) {
fprintf(stderr, "DXT decoder decompressing failed!\n");
return -1;
}
TIMER_STOP();
duration[index] = TIMER_DURATION();
}
printf_duration("Decoding Duration", run);
if ( display == 1 )
dxt_display_image("Decode After", image, width, height);
if ( dxt_image_save_to_file(filename_out, image, width, height) != 0 ) {
fprintf(stderr, "Failed to save image [%s]!\n", filename_out);
return -1;
}
dxt_decoder_buffer_free(image);
dxt_decoder_destroy(decoder);
dxt_image_compressed_destroy(image_compressed);
return 0;
}
const char*
get_filename_extension(const char* filename)
{
char * ext = strrchr(filename, '.');
if ( ext == NULL )
return NULL;
ext++;
return ext;
}
int
perform_display(const char* filename, enum dxt_type type, int width, int height, enum dxt_format format)
{
// Get file extension
const char * ext = get_filename_extension(filename);
// Display image in RGB format
if ( strncasecmp(ext, "rgb", 3) == 0 ) {
DXT_IMAGE_TYPE* image = NULL;
if ( dxt_image_load_from_file(filename, width, height, &image) != 0 ) {
fprintf(stderr, "Failed to load image [%s]!\n", filename);
return -1;
}
dxt_display_image("Display RGB Image", image, width, height);
dxt_image_destroy(image);
}
// Display image in DXT buffer format
else {
unsigned char* image_compressed = NULL;
int image_compressed_size = 0;
if ( dxt_image_compressed_load_from_file(filename, &image_compressed, &image_compressed_size) != 0 ) {
fprintf(stderr, "Failed to load compressed image [%s]!\n", filename);
return -1;
}
dxt_display_image_compressed("Display DXT Compressed Image", image_compressed, image_compressed_size, type, width, height);
dxt_image_compressed_destroy(image_compressed);
}
}
int
perform_comparison(const char* input, const char* output, enum dxt_type type, int width, int height, enum dxt_format format)
{
// Get file extensions
const char * input_ext = get_filename_extension(input);
const char * output_ext = get_filename_extension(output);
// Set proper filenames
const char * filename_image = NULL;
const char * filename_image_compressed = NULL;
if ( strncasecmp(input_ext, "rgb", 3) == 0 )
filename_image = input;
else
filename_image_compressed = input;
if ( strncasecmp(output_ext, "rgb", 3) == 0 )
filename_image = output;
else
filename_image_compressed = output;
if ( filename_image == NULL || filename_image_compressed == NULL ) {
fprintf(stderr, "Display comparison can't be performed, one file must be RGB image and one compressed image!\n");
return -1;
}
// Load images
DXT_IMAGE_TYPE* image = NULL;
unsigned char* image_compressed = NULL;
int image_compressed_size = 0;
if ( dxt_image_load_from_file(filename_image, width, height, &image) != 0 ) {
fprintf(stderr, "Failed to load image [%s]!\n", filename_image);
return -1;
}
if ( dxt_image_compressed_load_from_file(filename_image_compressed, &image_compressed, &image_compressed_size) != 0 ) {
fprintf(stderr, "Failed to load compressed image [%s]!\n", filename_image_compressed);
return -1;
}
dxt_display_image_comparison(image, image_compressed, image_compressed_size, type, width, height);
dxt_image_destroy(image);
dxt_image_compressed_destroy(image_compressed);
return 0;
}
void
print_help()
{
printf(
"dxt_compress [options]\n"
" -h, --help\t\tprint help\n"
" -e, --encode\t\tencode image from RGB format to DXT data buffer\n"
" -d, --decode\t\tdecode image from DXT data buffer to RGB format\n"
" -s, --size\t\timage size in pixels, e.g. 1920x1080\n"
" -i, --input\t\tinput image in RGB format\n"
" -o, --output\t\toutput image in RGB format\n"
" --display\tdisplay image or compare images\n"
" -t, --type\t\tdxt type 'dxt1' or 'dxt5ycocg' (default 'dxt5ycocg')\n"
" -f, --format\t\tcolor format 'rgb' or 'yuv' (default 'rgb')\n"
" -r, --run\t\tmultiple run times for debugging (default 1)\n"
);
}
int
main(int argc, char *argv[])
{
struct option longopts[] = {
{"help", no_argument, 0, 'h'},
{"encode", no_argument, 0, 'e'},
{"decode", no_argument, 0, 'd'},
{"size", required_argument, 0, 's'},
{"input", required_argument, 0, 'i'},
{"output", required_argument, 0, 'o'},
{"display", no_argument, 0, 1 },
{"type", required_argument, 0, 't'},
{"format", required_argument, 0, 'f'},
{"run", required_argument, 0, 'r'},
{"batch", no_argument, 0, 'b'},
};
// Parameters
enum dxt_type type = DXT_TYPE_DXT5_YCOCG;
enum dxt_format format = DXT_FORMAT_RGBA; // encoder _internal_ format (!)
int width = 512;
int height = 512;
int encode = 0;
int decode = 0;
char input[255] = { '\0' };
char output[255] = { '\0' };
int display = 0;
int run = 1;
int batch = 0;
// Parse command line
char ch = '\0';
int optindex = 0;
char* pos = 0;
while ( (ch = getopt_long(argc, argv, "heds:i:o:t:f:b", longopts, &optindex)) != -1 ) {
switch (ch) {
case 'h':
print_help();
return 0;
case 'e':
encode = 1;
break;
case 'd':
decode = 1;
break;
case 's':
width = atoi(optarg);
pos = strstr(optarg, "x");
if ( pos == NULL || width == 0 || (strlen(pos) >= strlen(optarg)) ) {
print_help();
return -1;
}
height = atoi(pos + 1);
break;
case 'i':
strncpy(input, optarg, 255);
break;
case 'o':
strncpy(output, optarg, 255);
break;
case 't':
if ( strcasecmp(optarg, "dxt1") == 0 )
type = DXT_TYPE_DXT1;
else if ( strcasecmp(optarg, "dxt5ycocg") == 0 )
type = DXT_TYPE_DXT5_YCOCG;
break;
case 'f':
if ( strcasecmp(optarg, "rgb") == 0 )
format = DXT_FORMAT_RGBA;
else if ( strcasecmp(optarg, "yuv") == 0 ) {
format = DXT_FORMAT_YUV;
fprintf(stderr, "yuv not supported!\n");
abort();
}
break;
case 'r':
run = atoi(optarg);
break;
case 1:
display = 1;
break;
case 'b':
batch = 1;
break;
case '?':
return -1;
default:
print_help();
return -1;
}
}
argc -= optind;
argv += optind;
if ( run > RUN_MAX ) {
printf("Warning: Maximum run times is %d using that number!\n", RUN_MAX);
run = RUN_MAX;
}
// Input image must be presented
if ( !batch && input[0] == '\0' ) {
printf("Please supply input image filename!\n");
print_help();
return -1;
}
// Output image must be presented for encoding or decoding
if ( !batch && output[0] == '\0' && (encode == 1 || decode == 1) ) {
printf("Please supply output image filename!\n");
print_help();
return -1;
}
// Init DXT compressor
if ( dxt_init() != 0 )
return -1;
// Perform encode
if ( encode == 1 ) {
if(batch) {
DXT_IMAGE_TYPE* image = NULL;
struct dxt_encoder* encoder = dxt_encoder_create(type, width, height, format, 1);
if ( encoder == NULL ) {
fprintf(stderr, "Create DXT encoder failed!\n");
return -1;
}
unsigned char* image_compressed = NULL;
int image_compressed_size = 0;
if ( dxt_encoder_buffer_allocate(encoder, &image_compressed, &image_compressed_size) != 0 ) {
fprintf(stderr, "DXT encoder allocation failed!\n");
return -1;
}
while (argc > 0) {
char *in_filename = argv[0];
char out_filename[512];
printf("encoding %s\n", in_filename);
snprintf(out_filename, 512, "%s.dxt", in_filename);
if ( dxt_image_load_from_file(in_filename, width, height, &image) != 0 ) {
fprintf(stderr, "Failed to load image [%s]!\n", in_filename);
return -1;
}
if ( dxt_encoder_compress(encoder, image, image_compressed) != 0 ) {
fprintf(stderr, "DXT encoder compressing failed!\n");
return -1;
}
if ( dxt_image_compressed_save_to_file(out_filename, image_compressed, image_compressed_size) != 0 ) {
fprintf(stderr, "Failed to save compressed image [%s]!\n", out_filename);
return -1;
}
dxt_image_destroy(image);
argc--;
argv++;
}
dxt_encoder_buffer_free(image_compressed);
dxt_encoder_destroy(encoder);
} else {
if ( perform_encode(input, output, type, width, height, format, display, run) != 0 ) {
fprintf(stderr, "Failed to encode image [%s]!\n", input);
return -1;
}
}
}
// Setup input and output for decoding (when encoding was performed)
if ( encode == 1 && decode == 1 ) {
char new_output[255];
snprintf(new_output, 255, "decoded_%s", input);
strncpy(input, output, 255);
strncpy(output, new_output, 255);
}
// Perform decode
if ( decode == 1 ) {
if ( perform_decode(input, output, type, width, height, display, run) != 0 ) {
fprintf(stderr, "Failed to decode image [%s]!\n", input);
return -1;
}
}
// Only display image
if ( display == 1 && encode == 0 && decode == 0 ) {
if ( output[0] != '\0' ) {
if ( perform_comparison(input, output, type, width, height, format) != 0 ) {
fprintf(stderr, "Failed to perform comparison for images [%s, %s]!\n", input, output);
return -1;
}
} else {
if ( perform_display(input, type, width, height, format) != 0 ) {
fprintf(stderr, "Failed to display image [%s]!\n", input);
return -1;
}
}
}
return 0;
}