sz_compat.c 7.37 KB
Newer Older
1
#include <stdio.h>
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
2
#include <stddef.h>
3 4
#include <string.h>
#include <stdlib.h>
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
5
#include "szlib.h"
6
#include "libaec.h"
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
7

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
#define NOPTS 129

static int convert_options(int sz_opts)
{
    int co[NOPTS];
    int i;
    int opts = 0;

    memset(co, 0, sizeof(int) * NOPTS);
    co[SZ_MSB_OPTION_MASK] = AEC_DATA_MSB;
    co[SZ_NN_OPTION_MASK] = AEC_DATA_PREPROCESS;

    for (i = 1; i < NOPTS; i <<= 1)
        opts |= co[i];

    return opts;
}

26 27 28 29 30 31 32 33 34 35
static int bits_to_bytes(int bit_length)
{
    if (bit_length > 16)
        return 4;
    else if (bit_length > 8)
        return 2;
    else
        return 1;
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
36
static void interleave_buffer(void *dest, const void *src,
37 38 39
                              size_t n, int wordsize)
{
    size_t i, j;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
40 41 42 43 44
    const unsigned char *src8;
    unsigned char *dest8;

    src8 = (unsigned char *)src;
    dest8 = (unsigned char *)dest;
45 46 47

    for (i = 0; i < n / wordsize; i++)
        for (j = 0; j < wordsize; j++)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
48
            dest8[j * (n / wordsize) + i] = src8[i * wordsize + j];
49 50
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
51 52
static void deinterleave_buffer(void *dest, const void *src,
                                size_t n, int wordsize)
53 54
{
    size_t i, j;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
55 56 57 58 59
    const unsigned char *src8;
    unsigned char *dest8;

    src8 = (unsigned char *)src;
    dest8 = (unsigned char *)dest;
60 61 62

    for (i = 0; i < n / wordsize; i++)
        for (j = 0; j < wordsize; j++)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
63
            dest8[i * wordsize + j] = src8[j * (n / wordsize) + i];
64 65
}

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
static size_t add_padding(void *dest, const void *src, size_t total,
                          size_t line_size, size_t padding_size,
                          int pixel_size, int pp)
{
    size_t i, j, k;
    const char *pixel;
    const char zero_pixel[] = {0, 0, 0, 0, 0, 0, 0, 0};

    for (i = 0, j = 0;
         i < total;
         i += pixel_size, j += pixel_size) {
        if (i > 0 && (i % line_size) == 0) {
            if (pp)
                pixel = (char *)src + i - 1;
            else
                pixel = zero_pixel;
            for (k = 0; k < padding_size; k += pixel_size)
                memcpy((char *)dest + j + k, pixel, pixel_size);
            j += padding_size;
        }
        memcpy((char *)dest + j, (char *)src + i, pixel_size);
    }
    return j;
}

static size_t remove_padding(void *buf, size_t total,
                             size_t line_size, size_t padding_size,
                             int pixel_size)
{
    size_t i, j;

    for (i = 0, j = padding_size;
         i < total;
         i += pixel_size, j += pixel_size) {
        if (i % (line_size + padding_size) == 0)
            j -= padding_size;
        memcpy((char *)buf + j, (char *)buf + i, pixel_size);
    }
    if ((i % (line_size + padding_size)) == 0)
        j -= padding_size;
    return j;
}

109 110 111
int SZ_BufftoBuffCompress(void *dest, size_t *destLen,
                          const void *source, size_t sourceLen,
                          SZ_com_t *param)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
112
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
113
    struct aec_stream strm;
114 115
    int status;
    void *padbuf;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
116
    void *buf;
117 118 119 120 121 122 123 124 125 126 127 128 129 130
    size_t padding_size;
    size_t padded_length;
    size_t scanlines;
    size_t buf_size;
    int pixel_size;
    int pad_scanline;
    int interleave;

    strm.block_size = param->pixels_per_block;
    strm.rsi = (param->pixels_per_scanline + param->pixels_per_block - 1)
        / param->pixels_per_block;
    strm.flags = convert_options(param->options_mask);
    strm.avail_out = *destLen;
    strm.next_out = dest;
131

132 133 134 135 136
    pad_scanline = param->pixels_per_scanline % param->pixels_per_block;
    interleave = param->bits_per_pixel == 32 || param->bits_per_pixel == 64;

    if (interleave) {
        strm.bit_per_sample = 8;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
137
        buf = malloc(sourceLen);
138 139 140 141 142
        if (buf == NULL)
            return SZ_MEM_ERROR;
        interleave_buffer(buf, source, sourceLen, param->bits_per_pixel / 8);
    } else {
        strm.bit_per_sample = param->bits_per_pixel;
143
        buf = (void *)source;
144
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
145

146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
    pixel_size = bits_to_bytes(strm.bit_per_sample);

    if (pad_scanline) {
        scanlines = (sourceLen / pixel_size + param->pixels_per_scanline - 1)
            / param->pixels_per_scanline;
        buf_size = strm.rsi * param->pixels_per_block * pixel_size * scanlines;

        padbuf = malloc(buf_size);
        if (padbuf == NULL)
            return SZ_MEM_ERROR;

        padding_size = (
            param->pixels_per_block -
            (param->pixels_per_scanline % param->pixels_per_block)
            ) * pixel_size;

        padded_length = add_padding(padbuf, buf, sourceLen,
                                    param->pixels_per_scanline * pixel_size,
                                    padding_size, pixel_size,
                                    strm.flags & AEC_DATA_PREPROCESS);

        strm.next_in = padbuf;
        strm.avail_in = padded_length;
    } else {
        strm.next_in = buf;
        strm.avail_in = sourceLen;
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
173

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
174
    status = aec_buffer_encode(&strm);
175
    if (status != AEC_OK)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
176 177
        return status;

178 179 180 181 182 183
    *destLen = strm.total_out;

    if (pad_scanline)
        free(padbuf);

    if (interleave)
184 185
        free(buf);

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
186 187 188
    return SZ_OK;
}

189 190 191
int SZ_BufftoBuffDecompress(void *dest, size_t *destLen,
                            const void *source, size_t sourceLen,
                            SZ_com_t *param)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
192
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
193
    struct aec_stream strm;
194
    int status;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
195
    void *buf;
196 197 198 199 200 201 202
    size_t padding_size;
    size_t scanlines;
    size_t buf_size, total_out;
    int pixel_size;
    int pad_scanline;
    int deinterleave;
    int extra_buffer;
203

204 205 206 207 208 209 210 211 212 213
    strm.block_size = param->pixels_per_block;
    strm.rsi = (param->pixels_per_scanline + param->pixels_per_block - 1)
        / param->pixels_per_block;
    strm.flags = convert_options(param->options_mask);
    strm.avail_in = sourceLen;
    strm.next_in = source;

    pad_scanline = param->pixels_per_scanline % param->pixels_per_block;
    deinterleave = param->bits_per_pixel == 32 || param->bits_per_pixel == 64;
    extra_buffer = pad_scanline || deinterleave;
214

215
    if (deinterleave)
216
        strm.bit_per_sample = 8;
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
    else
        strm.bit_per_sample = param->bits_per_pixel;

    pixel_size = bits_to_bytes(strm.bit_per_sample);

    if (extra_buffer) {
        if (pad_scanline) {
            scanlines = (*destLen / pixel_size + param->pixels_per_scanline - 1)
                / param->pixels_per_scanline;
            buf_size = strm.rsi * param->pixels_per_block
                * pixel_size * scanlines;
        } else {
            buf_size = *destLen;
        }
        buf = malloc(buf_size);
        if (buf == NULL)
            return SZ_MEM_ERROR;
234
        strm.next_out = buf;
235
        strm.avail_out = buf_size;
236 237
    } else {
        strm.next_out = dest;
238
        strm.avail_out = *destLen;
239
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
240

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
241
    status = aec_buffer_decode(&strm);
242
    if (status != AEC_OK)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
243 244
        return status;

245 246 247 248 249 250 251 252 253 254 255 256 257 258
    if (pad_scanline) {
        padding_size = (
            param->pixels_per_block -
            (param->pixels_per_scanline % param->pixels_per_block)
            ) * pixel_size;
        total_out = remove_padding(buf, strm.total_out,
                                   param->pixels_per_scanline * pixel_size,
                                   padding_size, pixel_size);
    } else {
        total_out = strm.total_out;
    }

    if (total_out < *destLen)
        *destLen = total_out;
259

260
    if (deinterleave)
261
        deinterleave_buffer(dest, buf, *destLen, param->bits_per_pixel / 8);
262 263 264 265
    else if (pad_scanline)
        memcpy(dest, buf, *destLen);

    if (extra_buffer)
266 267
        free(buf);

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
268 269
    return SZ_OK;
}
270 271 272 273 274

int SZ_encoder_enabled(void)
{
    return 1;
}