You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
347 lines
15 KiB
347 lines
15 KiB
/*
|
|
* The copyright in this software is being made available under the 2-clauses
|
|
* BSD License, included below. This software may be subject to other third
|
|
* party and contributor rights, including patent rights, and no such rights
|
|
* are granted under this license.
|
|
*
|
|
* Copyright (c) 2017, IntoPix SA <contact@intopix.com>
|
|
* 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 OWNER 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.
|
|
*/
|
|
|
|
#include "opj_includes.h"
|
|
|
|
|
|
struct opj_sparse_array_int32 {
|
|
OPJ_UINT32 width;
|
|
OPJ_UINT32 height;
|
|
OPJ_UINT32 block_width;
|
|
OPJ_UINT32 block_height;
|
|
OPJ_UINT32 block_count_hor;
|
|
OPJ_UINT32 block_count_ver;
|
|
OPJ_INT32** data_blocks;
|
|
};
|
|
|
|
opj_sparse_array_int32_t* opj_sparse_array_int32_create(OPJ_UINT32 width,
|
|
OPJ_UINT32 height,
|
|
OPJ_UINT32 block_width,
|
|
OPJ_UINT32 block_height)
|
|
{
|
|
opj_sparse_array_int32_t* sa;
|
|
|
|
if (width == 0 || height == 0 || block_width == 0 || block_height == 0) {
|
|
return NULL;
|
|
}
|
|
if (block_width > ((OPJ_UINT32)~0U) / block_height / sizeof(OPJ_INT32)) {
|
|
return NULL;
|
|
}
|
|
|
|
sa = (opj_sparse_array_int32_t*) opj_calloc(1,
|
|
sizeof(opj_sparse_array_int32_t));
|
|
sa->width = width;
|
|
sa->height = height;
|
|
sa->block_width = block_width;
|
|
sa->block_height = block_height;
|
|
sa->block_count_hor = opj_uint_ceildiv(width, block_width);
|
|
sa->block_count_ver = opj_uint_ceildiv(height, block_height);
|
|
if (sa->block_count_hor > ((OPJ_UINT32)~0U) / sa->block_count_ver) {
|
|
opj_free(sa);
|
|
return NULL;
|
|
}
|
|
sa->data_blocks = (OPJ_INT32**) opj_calloc(sizeof(OPJ_INT32*),
|
|
sa->block_count_hor * sa->block_count_ver);
|
|
if (sa->data_blocks == NULL) {
|
|
opj_free(sa);
|
|
return NULL;
|
|
}
|
|
|
|
return sa;
|
|
}
|
|
|
|
void opj_sparse_array_int32_free(opj_sparse_array_int32_t* sa)
|
|
{
|
|
if (sa) {
|
|
OPJ_UINT32 i;
|
|
for (i = 0; i < sa->block_count_hor * sa->block_count_ver; i++) {
|
|
if (sa->data_blocks[i]) {
|
|
opj_free(sa->data_blocks[i]);
|
|
}
|
|
}
|
|
opj_free(sa->data_blocks);
|
|
opj_free(sa);
|
|
}
|
|
}
|
|
|
|
OPJ_BOOL opj_sparse_array_is_region_valid(const opj_sparse_array_int32_t* sa,
|
|
OPJ_UINT32 x0,
|
|
OPJ_UINT32 y0,
|
|
OPJ_UINT32 x1,
|
|
OPJ_UINT32 y1)
|
|
{
|
|
return !(x0 >= sa->width || x1 <= x0 || x1 > sa->width ||
|
|
y0 >= sa->height || y1 <= y0 || y1 > sa->height);
|
|
}
|
|
|
|
static OPJ_BOOL opj_sparse_array_int32_read_or_write(
|
|
const opj_sparse_array_int32_t* sa,
|
|
OPJ_UINT32 x0,
|
|
OPJ_UINT32 y0,
|
|
OPJ_UINT32 x1,
|
|
OPJ_UINT32 y1,
|
|
OPJ_INT32* buf,
|
|
OPJ_UINT32 buf_col_stride,
|
|
OPJ_UINT32 buf_line_stride,
|
|
OPJ_BOOL forgiving,
|
|
OPJ_BOOL is_read_op)
|
|
{
|
|
OPJ_UINT32 y, block_y;
|
|
OPJ_UINT32 y_incr = 0;
|
|
const OPJ_UINT32 block_width = sa->block_width;
|
|
|
|
if (!opj_sparse_array_is_region_valid(sa, x0, y0, x1, y1)) {
|
|
return forgiving;
|
|
}
|
|
|
|
block_y = y0 / sa->block_height;
|
|
for (y = y0; y < y1; block_y ++, y += y_incr) {
|
|
OPJ_UINT32 x, block_x;
|
|
OPJ_UINT32 x_incr = 0;
|
|
OPJ_UINT32 block_y_offset;
|
|
y_incr = (y == y0) ? sa->block_height - (y0 % sa->block_height) :
|
|
sa->block_height;
|
|
block_y_offset = sa->block_height - y_incr;
|
|
y_incr = opj_uint_min(y_incr, y1 - y);
|
|
block_x = x0 / block_width;
|
|
for (x = x0; x < x1; block_x ++, x += x_incr) {
|
|
OPJ_UINT32 j;
|
|
OPJ_UINT32 block_x_offset;
|
|
OPJ_INT32* src_block;
|
|
x_incr = (x == x0) ? block_width - (x0 % block_width) : block_width;
|
|
block_x_offset = block_width - x_incr;
|
|
x_incr = opj_uint_min(x_incr, x1 - x);
|
|
src_block = sa->data_blocks[block_y * sa->block_count_hor + block_x];
|
|
if (is_read_op) {
|
|
if (src_block == NULL) {
|
|
if (buf_col_stride == 1) {
|
|
OPJ_INT32* dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride +
|
|
(x - x0) * buf_col_stride;
|
|
for (j = 0; j < y_incr; j++) {
|
|
memset(dest_ptr, 0, sizeof(OPJ_INT32) * x_incr);
|
|
dest_ptr += buf_line_stride;
|
|
}
|
|
} else {
|
|
OPJ_INT32* dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride +
|
|
(x - x0) * buf_col_stride;
|
|
for (j = 0; j < y_incr; j++) {
|
|
OPJ_UINT32 k;
|
|
for (k = 0; k < x_incr; k++) {
|
|
dest_ptr[k * buf_col_stride] = 0;
|
|
}
|
|
dest_ptr += buf_line_stride;
|
|
}
|
|
}
|
|
} else {
|
|
const OPJ_INT32* OPJ_RESTRICT src_ptr = src_block + block_y_offset *
|
|
(OPJ_SIZE_T)block_width + block_x_offset;
|
|
if (buf_col_stride == 1) {
|
|
OPJ_INT32* OPJ_RESTRICT dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride
|
|
+
|
|
(x - x0) * buf_col_stride;
|
|
if (x_incr == 4) {
|
|
/* Same code as general branch, but the compiler */
|
|
/* can have an efficient memcpy() */
|
|
(void)(x_incr); /* trick to silent cppcheck duplicateBranch warning */
|
|
for (j = 0; j < y_incr; j++) {
|
|
memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr);
|
|
dest_ptr += buf_line_stride;
|
|
src_ptr += block_width;
|
|
}
|
|
} else {
|
|
for (j = 0; j < y_incr; j++) {
|
|
memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr);
|
|
dest_ptr += buf_line_stride;
|
|
src_ptr += block_width;
|
|
}
|
|
}
|
|
} else {
|
|
OPJ_INT32* OPJ_RESTRICT dest_ptr = buf + (y - y0) * (OPJ_SIZE_T)buf_line_stride
|
|
+
|
|
(x - x0) * buf_col_stride;
|
|
if (x_incr == 1) {
|
|
for (j = 0; j < y_incr; j++) {
|
|
*dest_ptr = *src_ptr;
|
|
dest_ptr += buf_line_stride;
|
|
src_ptr += block_width;
|
|
}
|
|
} else if (y_incr == 1 && buf_col_stride == 2) {
|
|
OPJ_UINT32 k;
|
|
for (k = 0; k < (x_incr & ~3U); k += 4) {
|
|
dest_ptr[k * buf_col_stride] = src_ptr[k];
|
|
dest_ptr[(k + 1) * buf_col_stride] = src_ptr[k + 1];
|
|
dest_ptr[(k + 2) * buf_col_stride] = src_ptr[k + 2];
|
|
dest_ptr[(k + 3) * buf_col_stride] = src_ptr[k + 3];
|
|
}
|
|
for (; k < x_incr; k++) {
|
|
dest_ptr[k * buf_col_stride] = src_ptr[k];
|
|
}
|
|
} else if (x_incr >= 8 && buf_col_stride == 8) {
|
|
for (j = 0; j < y_incr; j++) {
|
|
OPJ_UINT32 k;
|
|
for (k = 0; k < (x_incr & ~3U); k += 4) {
|
|
dest_ptr[k * buf_col_stride] = src_ptr[k];
|
|
dest_ptr[(k + 1) * buf_col_stride] = src_ptr[k + 1];
|
|
dest_ptr[(k + 2) * buf_col_stride] = src_ptr[k + 2];
|
|
dest_ptr[(k + 3) * buf_col_stride] = src_ptr[k + 3];
|
|
}
|
|
for (; k < x_incr; k++) {
|
|
dest_ptr[k * buf_col_stride] = src_ptr[k];
|
|
}
|
|
dest_ptr += buf_line_stride;
|
|
src_ptr += block_width;
|
|
}
|
|
} else {
|
|
/* General case */
|
|
for (j = 0; j < y_incr; j++) {
|
|
OPJ_UINT32 k;
|
|
for (k = 0; k < x_incr; k++) {
|
|
dest_ptr[k * buf_col_stride] = src_ptr[k];
|
|
}
|
|
dest_ptr += buf_line_stride;
|
|
src_ptr += block_width;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (src_block == NULL) {
|
|
src_block = (OPJ_INT32*) opj_calloc(1,
|
|
sa->block_width * sa->block_height * sizeof(OPJ_INT32));
|
|
if (src_block == NULL) {
|
|
return OPJ_FALSE;
|
|
}
|
|
sa->data_blocks[block_y * sa->block_count_hor + block_x] = src_block;
|
|
}
|
|
|
|
if (buf_col_stride == 1) {
|
|
OPJ_INT32* OPJ_RESTRICT dest_ptr = src_block + block_y_offset *
|
|
(OPJ_SIZE_T)block_width + block_x_offset;
|
|
const OPJ_INT32* OPJ_RESTRICT src_ptr = buf + (y - y0) *
|
|
(OPJ_SIZE_T)buf_line_stride + (x - x0) * buf_col_stride;
|
|
if (x_incr == 4) {
|
|
/* Same code as general branch, but the compiler */
|
|
/* can have an efficient memcpy() */
|
|
(void)(x_incr); /* trick to silent cppcheck duplicateBranch warning */
|
|
for (j = 0; j < y_incr; j++) {
|
|
memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr);
|
|
dest_ptr += block_width;
|
|
src_ptr += buf_line_stride;
|
|
}
|
|
} else {
|
|
for (j = 0; j < y_incr; j++) {
|
|
memcpy(dest_ptr, src_ptr, sizeof(OPJ_INT32) * x_incr);
|
|
dest_ptr += block_width;
|
|
src_ptr += buf_line_stride;
|
|
}
|
|
}
|
|
} else {
|
|
OPJ_INT32* OPJ_RESTRICT dest_ptr = src_block + block_y_offset *
|
|
(OPJ_SIZE_T)block_width + block_x_offset;
|
|
const OPJ_INT32* OPJ_RESTRICT src_ptr = buf + (y - y0) *
|
|
(OPJ_SIZE_T)buf_line_stride + (x - x0) * buf_col_stride;
|
|
if (x_incr == 1) {
|
|
for (j = 0; j < y_incr; j++) {
|
|
*dest_ptr = *src_ptr;
|
|
src_ptr += buf_line_stride;
|
|
dest_ptr += block_width;
|
|
}
|
|
} else if (x_incr >= 8 && buf_col_stride == 8) {
|
|
for (j = 0; j < y_incr; j++) {
|
|
OPJ_UINT32 k;
|
|
for (k = 0; k < (x_incr & ~3U); k += 4) {
|
|
dest_ptr[k] = src_ptr[k * buf_col_stride];
|
|
dest_ptr[k + 1] = src_ptr[(k + 1) * buf_col_stride];
|
|
dest_ptr[k + 2] = src_ptr[(k + 2) * buf_col_stride];
|
|
dest_ptr[k + 3] = src_ptr[(k + 3) * buf_col_stride];
|
|
}
|
|
for (; k < x_incr; k++) {
|
|
dest_ptr[k] = src_ptr[k * buf_col_stride];
|
|
}
|
|
src_ptr += buf_line_stride;
|
|
dest_ptr += block_width;
|
|
}
|
|
} else {
|
|
/* General case */
|
|
for (j = 0; j < y_incr; j++) {
|
|
OPJ_UINT32 k;
|
|
for (k = 0; k < x_incr; k++) {
|
|
dest_ptr[k] = src_ptr[k * buf_col_stride];
|
|
}
|
|
src_ptr += buf_line_stride;
|
|
dest_ptr += block_width;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return OPJ_TRUE;
|
|
}
|
|
|
|
OPJ_BOOL opj_sparse_array_int32_read(const opj_sparse_array_int32_t* sa,
|
|
OPJ_UINT32 x0,
|
|
OPJ_UINT32 y0,
|
|
OPJ_UINT32 x1,
|
|
OPJ_UINT32 y1,
|
|
OPJ_INT32* dest,
|
|
OPJ_UINT32 dest_col_stride,
|
|
OPJ_UINT32 dest_line_stride,
|
|
OPJ_BOOL forgiving)
|
|
{
|
|
return opj_sparse_array_int32_read_or_write(
|
|
(opj_sparse_array_int32_t*)sa, x0, y0, x1, y1,
|
|
dest,
|
|
dest_col_stride,
|
|
dest_line_stride,
|
|
forgiving,
|
|
OPJ_TRUE);
|
|
}
|
|
|
|
OPJ_BOOL opj_sparse_array_int32_write(opj_sparse_array_int32_t* sa,
|
|
OPJ_UINT32 x0,
|
|
OPJ_UINT32 y0,
|
|
OPJ_UINT32 x1,
|
|
OPJ_UINT32 y1,
|
|
const OPJ_INT32* src,
|
|
OPJ_UINT32 src_col_stride,
|
|
OPJ_UINT32 src_line_stride,
|
|
OPJ_BOOL forgiving)
|
|
{
|
|
return opj_sparse_array_int32_read_or_write(sa, x0, y0, x1, y1,
|
|
(OPJ_INT32*)src,
|
|
src_col_stride,
|
|
src_line_stride,
|
|
forgiving,
|
|
OPJ_FALSE);
|
|
}
|