Logo Search packages:      
Sourcecode: librasterlite version File versions  Download package

int eps_encode_truecolor_block ( unsigned char **  block_R,
unsigned char **  block_G,
unsigned char **  block_B,
int  W,
int  H,
int  w,
int  h,
int  x,
int  y,
int  resample,
unsigned char *  buf,
int *  buf_size,
int  Y_rt,
int  Cb_rt,
int  Cr_rt,
char *  fb_id,
int  mode 
)

Encode a TRUECOLOR block

This function encodes a generic RGB truecolor image block. The original RGB data is arranged in three arrays: block_R, block_G and block_B respectively. All components should have equal dimensions: w by h pixels. It is assumed that the block is taken from the image of size W by H pixels at position (x, y). All these parameters should be consistent. The encoded data is stored in the buf of size buf_size.

Note:
The most surprising thing here is that you can choose almost any (see note below) buf_size you wish! Thus you can precisely control encoding bit-rate. This technique is called embedded coding. In a few words, any encoded prefix can be used to decode a whole image. So, you can safely truncate stream at any point.
The caller should allocate at least EPS_MIN_TRUECOLOR_BUF bytes for the buf.
The overall bit-budget available for the encoder is buf_size bytes. The caller should divide it between three channels (Y, Cb, Cr) using the following parameters: Y_rt, Cb_rt and Cr_rt. The function will report an error unless Y_rt + Cb_rt + Cr_rt equals to 100%. If no matter you can use default values: EPS_Y_RT, EPS_Cb_RT and EPS_Cr_RT.
On successful return, the value pointed by the buf_size will be overwritten with a real amount of bytes used in the buf (it will be less then or equal to the original buf_size value).
Depending on the mode parameter maximal block width or height is either EPS_MAX_BLOCK_SIZE (if mode = EPS_MODE_NORMAL) or EPS_MAX_BLOCK_SIZE + 1 (if mode = EPS_MODE_OTLPF).
There is no restrictions on the image size itself.
The caller should select a value for the fb_id parameter from the list generated by the eps_get_fb_info function.
The caller should not use orthogonal filterbanks with mode = EPS_MODE_OTLPF. Orthogonality type can be queried with the eps_get_fb_info function.
Parameters:
block_RRed component
block_GGreen component
block_BBlue component
WImage width
HImage height
wBlock width
hBlock height
xBlock X coordinate
yBlock Y coordinate
resampleResampling scheme: either EPS_RESAMPLE_444 or EPS_RESAMPLE_420
bufBuffer
buf_sizeBuffer size
Y_rtBit-budget percent for the Y channel
Cb_rtBit-budget percent for the Cb channel
Cr_rtBit-budget percent for the Cr channel
fb_idFilterbank ID
modeEither EPS_MODE_NORMAL or EPS_MODE_OTLPF
Returns:
The function returns either EPS_OK (the block is successfully encoded), or EPS_PARAM_ERROR (one or more parameters are incorrect) or EPS_UNSUPPORTED_FB (filterbank with specified fb_id not found).

Definition at line 841 of file libmain.c.

References analysis_2D(), bilinear_resample_channel(), CLIP, convert_RGB_to_YCbCr(), dc_level_shift(), EPS_MAX_BLOCK_SIZE, EPS_MIN_RT, EPS_MIN_TRUECOLOR_BUF, EPS_MODE_NORMAL, EPS_MODE_OTLPF, EPS_OK, EPS_PARAM_ERROR, EPS_RESAMPLE_420, EPS_RESAMPLE_444, EPS_UNSUPPORTED_FB, extend_channel(), free_2D(), get_block_size(), get_fb(), malloc_2D(), MAX, merge_channels(), MIN, ORTHOGONAL, round_channel(), speck_encode(), stuff_data(), filterbank_t_tag::type, and xmalloc().

{
    filterbank_t *fb;

    unsigned char *buf_next;
    int bytes_left;

    unsigned char *buf_Y;
    unsigned char *buf_Cb;
    unsigned char *buf_Cr;

    int buf_Y_size;
    int buf_Cb_size;
    int buf_Cr_size;

    unsigned char *buf_Cb_Cr;
    unsigned char *buf_Y_Cb_Cr;

    unsigned char *stuff_buf;

    int stuff_bytes;
    int stuff_max;
    int stuff_cut;

    coeff_t **pad_block_R;
    coeff_t **pad_block_G;
    coeff_t **pad_block_B;

    coeff_t **pad_block_Y;
    coeff_t **pad_block_Cb;
    coeff_t **pad_block_Cr;

    coeff_t **block_Y;
    coeff_t **block_Cb;
    coeff_t **block_Cr;

    coeff_t **dwt_block_Y;
    coeff_t **dwt_block_Cb;
    coeff_t **dwt_block_Cr;

    int **int_block_Y;
    int **int_block_Cb;
    int **int_block_Cr;

    int block_Y_size;
    int block_Cb_size;
    int block_Cr_size;

    int speck_bytes_Y;
    int speck_bytes_Cb;
    int speck_bytes_Cr;

    int speck_bytes;

    int full_size;
    int half_size;

    coeff_t dc_Y;
    coeff_t dc_Cb;
    coeff_t dc_Cr;

    unsigned char dc_Y_int;
    unsigned char dc_Cb_int;
    unsigned char dc_Cr_int;

    crc32_t hdr_crc;
    crc32_t data_crc;

    unsigned char *crc_pos;
    int str_len;

    /* Sanity checks */
    if (!block_R || !block_G || !block_B) {
        return EPS_PARAM_ERROR;
    }

    if (!buf || !buf_size || !fb_id) {
        return EPS_PARAM_ERROR;
    }

    /* Check input parameters for consistency */
    if ((mode != EPS_MODE_NORMAL) && (mode != EPS_MODE_OTLPF)) {
        return EPS_PARAM_ERROR;
    }

    if ((W <= 0) || (H <= 0)) {
        return EPS_PARAM_ERROR;
    }

    if ((w < 1) || (h < 1)) {
        return EPS_PARAM_ERROR;
    }

    if (w > EPS_MAX_BLOCK_SIZE + mode == EPS_MODE_OTLPF) {
        return EPS_PARAM_ERROR;
    }

    if (h > EPS_MAX_BLOCK_SIZE + mode == EPS_MODE_OTLPF) {
        return EPS_PARAM_ERROR;
    }

    if ((x < 0) || (y < 0)) {
        return EPS_PARAM_ERROR;
    }

    if ((x + w > W) || (y + h > H)) {
        return EPS_PARAM_ERROR;
    }

    if ((resample != EPS_RESAMPLE_444) && (resample != EPS_RESAMPLE_420)) {
        return EPS_PARAM_ERROR;
    }

    if (*buf_size < EPS_MIN_TRUECOLOR_BUF) {
        return EPS_PARAM_ERROR;
    }

    if ((Y_rt < EPS_MIN_RT) || (Cb_rt < EPS_MIN_RT) || (Cr_rt < EPS_MIN_RT)) {
        return EPS_PARAM_ERROR;
    }

    if (Y_rt + Cb_rt + Cr_rt != 100) {
        return EPS_PARAM_ERROR;
    }

    /* Find filterbank from id */
    if (!(fb = get_fb(fb_id))) {
        return EPS_UNSUPPORTED_FB;
    }

    /* EPS_MODE_NORMAL is the only valid choise for orthogonal filters */
    if ((fb->type == ORTHOGONAL) && (mode != EPS_MODE_NORMAL)) {
        return EPS_PARAM_ERROR;
    }

    buf_next = buf;
    bytes_left = *buf_size;

    /* Compute bid-budget for each channel */
    buf_Cr_size = MAX((bytes_left / 100) * Cr_rt, 1);
    buf_Cb_size = MAX((bytes_left / 100) * Cb_rt, 1);
    buf_Y_size = bytes_left - buf_Cb_size - buf_Cr_size;

    /* Ensure that everything is ok */
    assert((buf_Y_size > 0) && (buf_Cb_size > 0) && (buf_Cr_size > 0));
    assert(buf_Y_size + buf_Cb_size + buf_Cr_size == bytes_left);

    /* Compute block sizes for full and resampled channels */
    full_size = get_block_size(w, h, mode, 4);
    half_size = full_size / 2 + (mode == EPS_MODE_OTLPF);

    /* Allocate memory for extended R,G,B channels */
    pad_block_R = (coeff_t **) malloc_2D(full_size, full_size,
        sizeof(coeff_t));
    pad_block_G = (coeff_t **) malloc_2D(full_size, full_size,
        sizeof(coeff_t));
    pad_block_B = (coeff_t **) malloc_2D(full_size, full_size,
        sizeof(coeff_t));

    /* Extend R,G,B channels */
    extend_channel(block_R, pad_block_R, w, h, full_size, full_size);
    extend_channel(block_G, pad_block_G, w, h, full_size, full_size);
    extend_channel(block_B, pad_block_B, w, h, full_size, full_size);

    /* Allocate memory for extended Y,Cb,Cr channels */
    pad_block_Y = (coeff_t **) malloc_2D(full_size, full_size,
        sizeof(coeff_t));
    pad_block_Cb = (coeff_t **) malloc_2D(full_size, full_size,
        sizeof(coeff_t));
    pad_block_Cr = (coeff_t **) malloc_2D(full_size, full_size,
        sizeof(coeff_t));

    /* Convert from R,G,B to Y,Cb,Cr color space */
    convert_RGB_to_YCbCr(pad_block_R, pad_block_G, pad_block_B,
                         pad_block_Y, pad_block_Cb, pad_block_Cr,
                         full_size, full_size);

    /* No longer needed */
    free_2D((void *) pad_block_R, full_size, full_size);
    free_2D((void *) pad_block_G, full_size, full_size);
    free_2D((void *) pad_block_B, full_size, full_size);

    if (resample == EPS_RESAMPLE_444) {
        /* No resampling: all channels are full sized */
        block_Y_size = full_size;
        block_Cb_size = full_size;
        block_Cr_size = full_size;

        /* No changes */
        block_Y = pad_block_Y;
        block_Cb = pad_block_Cb;
        block_Cr = pad_block_Cr;
    } else {
        /* Resample image using 4:2:0 scheme */
        block_Y_size = full_size;
        block_Cb_size = half_size;
        block_Cr_size = half_size;

        /* No changes in Y channel */
        block_Y = pad_block_Y;

        /* Allocate memory for resampled Cb and Cr channels */
        block_Cb = (coeff_t **) malloc_2D(half_size, half_size,
            sizeof(coeff_t));
        block_Cr = (coeff_t **) malloc_2D(half_size, half_size,
            sizeof(coeff_t));

        /* Resample Cb channel */
        bilinear_resample_channel(pad_block_Cb, block_Cb,
                                  full_size, full_size,
                                  half_size, half_size);

        /* Resample Cr channel */
        bilinear_resample_channel(pad_block_Cr, block_Cr,
                                  full_size, full_size,
                                  half_size, half_size);

        /* No longer needed */
        free_2D((void *) pad_block_Cb, full_size, full_size);
        free_2D((void *) pad_block_Cr, full_size, full_size);
    }

    /* DC level shift */
    dc_Y = dc_level_shift(block_Y, block_Y_size, block_Y_size);
    dc_Cb = dc_level_shift(block_Cb, block_Cb_size, block_Cb_size);
    dc_Cr = dc_level_shift(block_Cr, block_Cr_size, block_Cr_size);

    /* Clip DC values */
    dc_Y_int = (unsigned char) CLIP(dc_Y);
    dc_Cb_int = (unsigned char) CLIP(dc_Cb);
    dc_Cr_int = (unsigned char) CLIP(dc_Cr);

    /* Allocate memory for wavelet coefficients */
    dwt_block_Y = (coeff_t **) malloc_2D(block_Y_size, block_Y_size,
        sizeof(coeff_t));
    dwt_block_Cb = (coeff_t **) malloc_2D(block_Cb_size, block_Cb_size,
        sizeof(coeff_t));
    dwt_block_Cr = (coeff_t **) malloc_2D(block_Cr_size, block_Cr_size,
        sizeof(coeff_t));

    /* Wavelet transform */
    analysis_2D(block_Y, dwt_block_Y, block_Y_size, mode, fb);
    analysis_2D(block_Cb, dwt_block_Cb, block_Cb_size, mode, fb);
    analysis_2D(block_Cr, dwt_block_Cr, block_Cr_size, mode, fb);

    /* No longer needed */
    free_2D((void *) block_Y, block_Y_size, block_Y_size);
    free_2D((void *) block_Cb, block_Cb_size, block_Cb_size);
    free_2D((void *) block_Cr, block_Cr_size, block_Cr_size);

    /* Allocate memory for rounded wavelet coefficients */
    int_block_Y = (int **) malloc_2D(block_Y_size, block_Y_size,
        sizeof(int));
    int_block_Cb = (int **) malloc_2D(block_Cb_size, block_Cb_size,
        sizeof(int));
    int_block_Cr = (int **) malloc_2D(block_Cr_size, block_Cr_size,
        sizeof(int));

    /* Round wavelet coefficients */
    round_channel(dwt_block_Y, int_block_Y, block_Y_size);
    round_channel(dwt_block_Cb, int_block_Cb, block_Cb_size);
    round_channel(dwt_block_Cr, int_block_Cr, block_Cr_size);

    /* No longer needed */
    free_2D((void *) dwt_block_Y, block_Y_size, block_Y_size);
    free_2D((void *) dwt_block_Cb, block_Cb_size, block_Cb_size);
    free_2D((void *) dwt_block_Cr, block_Cr_size, block_Cr_size);

    /* Allocate memory for encoded data */
    buf_Y = (unsigned char *) xmalloc(buf_Y_size *
        sizeof(unsigned char));
    buf_Cb = (unsigned char *) xmalloc(buf_Cb_size *
        sizeof(unsigned char));
    buf_Cr = (unsigned char *) xmalloc(buf_Cr_size *
        sizeof(unsigned char));

    /* Encode Y,Cb,Cr channels */
    speck_bytes_Y = speck_encode(int_block_Y, block_Y_size,
                                 buf_Y, buf_Y_size);

    speck_bytes_Cb = speck_encode(int_block_Cb, block_Cb_size,
                                  buf_Cb, buf_Cb_size);


    speck_bytes_Cr = speck_encode(int_block_Cr, block_Cr_size,
                                  buf_Cr, buf_Cr_size);

    /* No longer needed */
    free_2D((void *) int_block_Y, block_Y_size, block_Y_size);
    free_2D((void *) int_block_Cb, block_Cb_size, block_Cb_size);
    free_2D((void *) int_block_Cr, block_Cr_size, block_Cr_size);

    /* Total number of encoded bytes */
    speck_bytes = speck_bytes_Y + speck_bytes_Cb + speck_bytes_Cr;

    /* Allocate memory for mixed Cb + Cr channel */
    buf_Cb_Cr = (unsigned char *) xmalloc((speck_bytes_Cb + speck_bytes_Cr) *
        sizeof(unsigned char));

    /* Merge Cb and Cr channels */
    merge_channels(buf_Cb, buf_Cr, buf_Cb_Cr, speck_bytes_Cb, speck_bytes_Cr);

    /* No longer needed */
    free(buf_Cb);
    free(buf_Cr);

    /* Allocate memory for mixed Y + (Cb + Cr) channel */
    buf_Y_Cb_Cr = (unsigned char *) xmalloc(speck_bytes *
        sizeof(unsigned char));

    /* Merge Y and (Cb + Cr) channels */
    merge_channels(buf_Y, buf_Cb_Cr, buf_Y_Cb_Cr, speck_bytes_Y,
        speck_bytes_Cb + speck_bytes_Cr);

    /* No longer needed */
    free(buf_Y);
    free(buf_Cb_Cr);

    /* Byte stuffing */
    stuff_max = speck_bytes + speck_bytes / 254 + 1;
    stuff_buf = (unsigned char *) xmalloc(stuff_max * sizeof(unsigned char));
    stuff_bytes = stuff_data(buf_Y_Cb_Cr, stuff_buf, speck_bytes, stuff_max);

    assert(stuff_bytes >= speck_bytes);

    free(buf_Y_Cb_Cr);

    /* Write block header */
    str_len = snprintf((char *) buf_next, bytes_left,
        "type=tc;W=%d;H=%d;w=%d;h=%d;x=%d;y=%d;m=%d;r=%d;"
        "dc=%d:%d:%d;rt=%d:%d:%d;fb=%s;",
        W, H, w, h, x, y, mode, resample,
        dc_Y_int, dc_Cb_int, dc_Cr_int,
        speck_bytes_Y, speck_bytes_Cb,
        speck_bytes_Cr, fb_id);

    assert(str_len < bytes_left);

    buf_next += str_len;
    bytes_left -= str_len;

    /* Compute and save header CRC */
    hdr_crc = epsilon_crc32(buf, str_len);
    hdr_crc = (hdr_crc ^ (hdr_crc >> 16)) & 0xffff;

    str_len = snprintf((char *) buf_next, bytes_left,
                       "chk=%04x;crc=????????;", hdr_crc);

    assert(str_len < bytes_left);

    buf_next += str_len;
    bytes_left -= str_len;

    crc_pos = buf_next - 9;

    /* Cut encoded stream to fit it within available space */
    stuff_cut = MIN(bytes_left, stuff_bytes);
    memcpy(buf_next, stuff_buf, stuff_cut);

    free(stuff_buf);

    /* Compute and save data CRC */
    data_crc = epsilon_crc32(buf_next, stuff_cut);
    snprintf((char *) crc_pos, 9, "%08x", data_crc);
    crc_pos[8] = ';';

    buf_next += stuff_cut;
    bytes_left -= stuff_cut;

    /* Compute real amount of used bytes */
    *buf_size = buf_next - buf;

    return EPS_OK;
}

Here is the call graph for this function:


Generated by  Doxygen 1.6.0   Back to index