|
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 |
}
|