aec.c 7.44 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
/**
 * @file aec.c
 *
 * @author Mathis Rosenhauer, Deutsches Klimarechenzentrum
 * @author Moritz Hanke, Deutsches Klimarechenzentrum
 * @author Joerg Behrens, Deutsches Klimarechenzentrum
 * @author Luis Kornblueh, Max-Planck-Institut fuer Meteorologie
 *
 * @section LICENSE
 * Copyright 2012
 *
 * Mathis Rosenhauer,                 Luis Kornblueh
 * Moritz Hanke,
 * Joerg Behrens
 *
 * Deutsches Klimarechenzentrum GmbH  Max-Planck-Institut fuer Meteorologie
 * Bundesstr. 45a                     Bundesstr. 53
 * 20146 Hamburg                      20146 Hamburg
 * Germany                            Germany
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 *
 * @section DESCRIPTION
 *
 * CLI frontend for Adaptive Entropy Coding library
 *
 */

53 54 55 56 57
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
58 59

#ifndef _AIX
60
#include <getopt.h>
61 62
#endif

63
#include <libaec.h>
64 65 66 67 68

#define CHUNK 1024

int main(int argc, char *argv[])
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
69
    struct aec_stream strm;
70 71
    unsigned char *in;
    unsigned char *out;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
72 73
    size_t total_out;
    int chunk, status, c;
74
    int input_avail, output_avail;
75
    char *outfn, *infn, *ext;
76 77
    FILE *infp, *outfp;
    int cflag = 0;
78
    int dflag = 0;
79 80

    chunk = CHUNK;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
81
    strm.bits_per_sample = 8;
82
    strm.block_size = 8;
83
    strm.rsi = 2;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
84
    strm.flags = AEC_DATA_PREPROCESS;
85 86
    opterr = 0;

87
    while ((c = getopt (argc, argv, "3b:cdj:mn:r:st")) != -1)
88
        switch (c) {
89 90
        case '3':
            strm.flags |= AEC_DATA_3BYTE;
91
            break;
92
        case 'b':
93
            chunk = atoi(optarg);
94
            break;
95 96 97 98 99
        case 'c':
            cflag = 1;
            break;
        case 'd':
            dflag = 1;
100
            break;
101
        case 'j':
102 103
            strm.block_size = atoi(optarg);
            break;
104 105 106 107 108 109
        case 'm':
            strm.flags |= AEC_DATA_MSB;
            break;
        case 'n':
            strm.bits_per_sample = atoi(optarg);
            break;
110
        case 'r':
111
            strm.rsi = atoi(optarg);
112
            break;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
113
        case 's':
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
114
            strm.flags |= AEC_DATA_SIGNED;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
115
            break;
116 117
        case 't':
            strm.flags |= AEC_DATA_RESTRICT;
118
            break;
119 120 121 122 123 124 125 126 127 128 129 130 131 132
        case '?':
            if (optopt == 'b')
                fprintf (stderr, "Option -%c requires an argument.\n", optopt);
            else if (isprint (optopt))
                fprintf (stderr, "Unknown option `-%c'.\n", optopt);
            else
                fprintf (stderr,
                         "Unknown option character `\\x%x'.\n",
                         optopt);
            return 1;
        default:
            abort ();
        }

133
    if (optind < argc) {
134
        infn = argv[optind];
135 136 137 138 139 140 141 142 143 144 145
    } else {
        fprintf(stderr, "Usage: %s [OPTION] SOURCE\n", argv[0]);
        fprintf(stderr, "\nOPTIONS\n");
        fprintf(stderr, "-3\n   24 bit samples are sored in 3 bytes\n");
        fprintf(stderr, "-b\n   internal buffer size\n");
        fprintf(stderr, "-c\n   write output on standard output\n");
        fprintf(stderr, "-d\n   decode SOURCE. If -d is not specified encode.\n");
        fprintf(stderr, "-j\n   block size in samples\n");
        fprintf(stderr, "-m\n   samples are MSB first. Default is LSB\n");
        fprintf(stderr, "-n\n   bits per sample\n");
        fprintf(stderr, "-r\n   reference sample interval in blocks\n");
146 147
        fprintf(stderr, "-s\n   samples are signed. Default is unsigned\n");
        fprintf(stderr, "-t\n   use restricted set of code options\n\n");
148 149 150
        exit(-1);
    }

151
    if (strm.bits_per_sample > 16) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
152
        if (strm.bits_per_sample <= 24 && strm.flags & AEC_DATA_3BYTE)
153 154 155
            chunk *= 3;
        else
            chunk *= 4;
156
    } else if (strm.bits_per_sample > 8) {
157 158 159
        chunk *= 2;
    }

160 161
    out = (unsigned char *)malloc(chunk);
    in = (unsigned char *)malloc(chunk);
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177


    if (in == NULL || out == NULL)
        exit(-1);

    total_out = 0;
    strm.avail_in = 0;
    strm.avail_out = chunk;
    strm.next_out = out;

    input_avail = 1;
    output_avail = 1;

    if ((infp = fopen(infn, "r")) == NULL)
        exit(-1);

178
    if (cflag) {
179
        outfp = stdout;
180
    } else {
181 182 183 184
        outfn = malloc(strlen(infn) + 4);
        if (outfn == NULL)
            exit(-1);

185 186
        if (dflag) {
            if ((ext = strstr(infn, ".rz")) == NULL) {
187
                fprintf(stderr, "ERROR: input file needs to end with .rz\n");
188 189 190
                exit(-1);
            }
            strncpy(outfn, infn, ext - infn);
191
        } else {
192
            sprintf(outfn, "%s.rz", infn);
193
        }
194 195 196 197 198

        if ((outfp = fopen(outfn, "w")) == NULL)
            exit(-1);
    }

199
    if (dflag) {
200 201
        if (aec_decode_init(&strm) != AEC_OK) {
            fprintf(stderr, "ERROR: Initialization failed\n");
202
            return 1;
203
        }
204
    } else {
205 206
        if (aec_encode_init(&strm) != AEC_OK) {
            fprintf(stderr, "ERROR: Initialization failed\n");
207
            return 1;
208
        }
209 210
    }

211 212
    while(input_avail || output_avail) {
        if (strm.avail_in == 0 && input_avail) {
213 214 215
            strm.avail_in = fread(in, 1, chunk, infp);
            if (strm.avail_in != chunk)
                input_avail = 0;
216
            strm.next_in = in;
217 218
        }

219
        if (dflag)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
220
            status = aec_decode(&strm, AEC_NO_FLUSH);
221
        else
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
222
            status = aec_encode(&strm, AEC_NO_FLUSH);
223

224
        if (status != AEC_OK) {
225
            fprintf(stderr, "ERROR: %i\n", status);
226 227 228
            return 1;
        }

229
        if (strm.total_out - total_out > 0) {
230 231 232 233 234
            fwrite(out, strm.total_out - total_out, 1, outfp);
            total_out = strm.total_out;
            output_avail = 1;
            strm.next_out = out;
            strm.avail_out = chunk;
235
        } else {
236 237 238 239 240
            output_avail = 0;
        }

    }

241
    if (dflag) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
242
        aec_decode_end(&strm);
243 244
    } else {
        if ((status = aec_encode(&strm, AEC_FLUSH)) != AEC_OK) {
245
            fprintf(stderr, "ERROR: %i\n", status);
246 247 248 249 250 251
            return 1;
        }

        if (strm.total_out - total_out > 0)
            fwrite(out, strm.total_out - total_out, 1, outfp);

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
252
        aec_encode_end(&strm);
253 254 255 256 257 258
    }

    fclose(infp);
    fclose(outfp);
    free(in);
    free(out);
259
    if (!cflag) {
260 261 262 263 264
        unlink(infn);
        free(outfn);
    }
    return 0;
}