Blame src/libbluray/decoders/rle.c

Packit 5e46da
/*
Packit 5e46da
 * This file is part of libbluray
Packit 5e46da
 * Copyright (C) 2013  Petri Hintukainen <phintuka@users.sourceforge.net>
Packit 5e46da
 *
Packit 5e46da
 * This library is free software; you can redistribute it and/or
Packit 5e46da
 * modify it under the terms of the GNU Lesser General Public
Packit 5e46da
 * License as published by the Free Software Foundation; either
Packit 5e46da
 * version 2.1 of the License, or (at your option) any later version.
Packit 5e46da
 *
Packit 5e46da
 * This library is distributed in the hope that it will be useful,
Packit 5e46da
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 5e46da
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 5e46da
 * Lesser General Public License for more details.
Packit 5e46da
 *
Packit 5e46da
 * You should have received a copy of the GNU Lesser General Public
Packit 5e46da
 * License along with this library. If not, see
Packit 5e46da
 * <http://www.gnu.org/licenses/>.
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
#if HAVE_CONFIG_H
Packit 5e46da
#include "config.h"
Packit 5e46da
#endif
Packit 5e46da
Packit 5e46da
#include "rle.h"
Packit 5e46da
Packit 5e46da
#include "util/logging.h"
Packit 5e46da
Packit 5e46da
/*
Packit 5e46da
 * util
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
static int _rle_ensure_size(RLE_ENC *p)
Packit 5e46da
{
Packit 5e46da
    if (BD_UNLIKELY(!p->free_elem)) {
Packit 5e46da
        BD_PG_RLE_ELEM *start = rle_get(p);
Packit 5e46da
        if (p->error) {
Packit 5e46da
            return -1;
Packit 5e46da
        }
Packit 5e46da
        /* realloc to 2x */
Packit 5e46da
        void *tmp = refcnt_realloc(start, p->num_elem * 2 * sizeof(BD_PG_RLE_ELEM));
Packit 5e46da
        if (!tmp) {
Packit 5e46da
            p->error = 1;
Packit 5e46da
            return -1;
Packit 5e46da
        }
Packit 5e46da
        start = tmp;
Packit 5e46da
        p->elem = start + p->num_elem;
Packit 5e46da
        p->free_elem = p->num_elem;
Packit 5e46da
        p->num_elem *= 2;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    return 0;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
/*
Packit 5e46da
 * crop encoded image
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
static int _enc_elem(RLE_ENC *p, uint16_t color, uint16_t len)
Packit 5e46da
{
Packit 5e46da
    if (BD_UNLIKELY(_rle_ensure_size(p) < 0)) {
Packit 5e46da
        return -1;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    p->elem->color = color;
Packit 5e46da
    p->elem->len = len;
Packit 5e46da
Packit 5e46da
    p->free_elem--;
Packit 5e46da
    p->elem++;
Packit 5e46da
Packit 5e46da
    return 0;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int _enc_eol(RLE_ENC *p)
Packit 5e46da
{
Packit 5e46da
    return _enc_elem(p, 0, 0);
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
BD_PG_RLE_ELEM *rle_crop_object(const BD_PG_RLE_ELEM *orig, int width,
Packit 5e46da
                                int crop_x, int crop_y, int crop_w, int crop_h)
Packit 5e46da
{
Packit 5e46da
    RLE_ENC  rle;
Packit 5e46da
    int      x0 = crop_x;
Packit 5e46da
    int      x1 = crop_x + crop_w; /* first pixel outside of cropped region */
Packit 5e46da
    int      x, y;
Packit 5e46da
Packit 5e46da
    if (rle_begin(&rle) < 0) {
Packit 5e46da
        return NULL;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    /* skip crop_y */
Packit 5e46da
    for (y = 0; y < crop_y; y++) {
Packit 5e46da
        for (x = 0; x < width; x += orig->len, orig++) ;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    /* crop lines */
Packit 5e46da
Packit 5e46da
    for (y = 0; y < crop_h; y++) {
Packit 5e46da
        for (x = 0; x < width; ) {
Packit 5e46da
          BD_PG_RLE_ELEM bite = *(orig++);
Packit 5e46da
Packit 5e46da
            if (BD_UNLIKELY(bite.len < 1)) {
Packit 5e46da
                BD_DEBUG(DBG_GC | DBG_CRIT, "rle eol marker in middle of line (x=%d/%d)\n", x, width);
Packit 5e46da
                continue;
Packit 5e46da
            }
Packit 5e46da
Packit 5e46da
            /* starts outside, ends outside */
Packit 5e46da
            if (x + bite.len < x0 || x >= x1) {
Packit 5e46da
                x += bite.len;
Packit 5e46da
                continue;
Packit 5e46da
            }
Packit 5e46da
Packit 5e46da
            /* starts before ? */
Packit 5e46da
            if (BD_UNLIKELY(x < x0)) {
Packit 5e46da
                bite.len -= x0 - x;
Packit 5e46da
                x = x0;
Packit 5e46da
            }
Packit 5e46da
Packit 5e46da
            x += bite.len;
Packit 5e46da
Packit 5e46da
            /* ends after ? */
Packit 5e46da
            if (BD_UNLIKELY(x >= x1)) {
Packit 5e46da
                bite.len -= x - x1;
Packit 5e46da
            }
Packit 5e46da
Packit 5e46da
            if (BD_UNLIKELY(_enc_elem(&rle, bite.color, bite.len) < 0)) {
Packit 5e46da
                goto out;
Packit 5e46da
            }
Packit 5e46da
        }
Packit 5e46da
Packit 5e46da
        if (BD_LIKELY(!orig->len)) {
Packit 5e46da
            /* skip eol marker */
Packit 5e46da
            orig++;
Packit 5e46da
        } else {
Packit 5e46da
            BD_DEBUG(DBG_GC | DBG_CRIT, "rle eol marker missing\n");
Packit 5e46da
        }
Packit 5e46da
Packit 5e46da
        if (BD_UNLIKELY(_enc_eol(&rle) < 0)) {
Packit 5e46da
            goto out;
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
 out:
Packit 5e46da
    return rle_get(&rle;;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
/*
Packit 5e46da
 * compression
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
static int _rle_grow(RLE_ENC *p)
Packit 5e46da
{
Packit 5e46da
    p->free_elem--;
Packit 5e46da
    p->elem++;
Packit 5e46da
Packit 5e46da
    if (BD_UNLIKELY(_rle_ensure_size(p) < 0)) {
Packit 5e46da
        return -1;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    p->elem->len = 0;
Packit 5e46da
Packit 5e46da
    return 0;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
int rle_add_eol(RLE_ENC *p)
Packit 5e46da
{
Packit 5e46da
    if (BD_LIKELY(p->elem->len)) {
Packit 5e46da
        if (BD_UNLIKELY(_rle_grow(p) < 0)) {
Packit 5e46da
            return -1;
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
    p->elem->color = 0;
Packit 5e46da
Packit 5e46da
    if (BD_UNLIKELY(_rle_grow(p) < 0)) {
Packit 5e46da
        return -1;
Packit 5e46da
    }
Packit 5e46da
    p->elem->color = 0xffff;
Packit 5e46da
Packit 5e46da
    return 0;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
int rle_add_bite(RLE_ENC *p, uint8_t color, int len)
Packit 5e46da
{
Packit 5e46da
    if (BD_LIKELY(color == p->elem->color)) {
Packit 5e46da
        p->elem->len += len;
Packit 5e46da
    } else {
Packit 5e46da
        if (BD_LIKELY(p->elem->len)) {
Packit 5e46da
            if (BD_UNLIKELY(_rle_grow(p) < 0)) {
Packit 5e46da
                return -1;
Packit 5e46da
            }
Packit 5e46da
        }
Packit 5e46da
        p->elem->color = color;
Packit 5e46da
        p->elem->len = len;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    return 0;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
int rle_compress_chunk(RLE_ENC *p, const uint8_t *mem, unsigned width)
Packit 5e46da
{
Packit 5e46da
    unsigned ii;
Packit 5e46da
    for (ii = 0; ii < width; ii++) {
Packit 5e46da
        if (BD_UNLIKELY(rle_add_bite(p, mem[ii], 1) < 0)) {
Packit 5e46da
              return -1;
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
    return 0;
Packit 5e46da
}