Sub-tile decoding: only decode precincts and codeblocks that intersect the window specified in opj_set_decode_area()

This commit is contained in:
Even Rouault 2017-08-14 13:23:57 +02:00
parent 17ea17f487
commit fe338a057c
10 changed files with 697 additions and 28 deletions

View File

@ -16,6 +16,7 @@
* Copyright (c) 2010-2011, Kaori Hagihara
* Copyright (c) 2011-2012, Centre National d'Etudes Spatiales (CNES), France
* Copyright (c) 2012, CS Systemes d'Information, France
* Copyright (c) 2017, IntoPIX SA <support@intopix.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -5162,7 +5163,13 @@ static OPJ_BOOL opj_j2k_update_rates(opj_j2k_t *p_j2k,
++l_img_comp;
}
l_tile_size = (OPJ_UINT32)(l_tile_size * 0.1625); /* 1.3/8 = 0.1625 */
/* TODO: where does this magic value come from ? */
/* This used to be 1.3 / 8, but with random data and very small code */
/* block sizes, this is not enough. For example with */
/* bin/test_tile_encoder 1 256 256 32 32 8 0 reversible_with_precinct.j2k 4 4 3 0 0 1 16 16 */
/* TODO revise this to take into account the overhead linked to the */
/* number of packets and number of code blocks in packets */
l_tile_size = (OPJ_UINT32)(l_tile_size * 1.4 / 8);
l_tile_size += opj_j2k_get_specific_header_sizes(p_j2k);
@ -8770,6 +8777,7 @@ OPJ_BOOL opj_j2k_decode_tile(opj_j2k_t * p_j2k,
OPJ_UINT32 l_current_marker;
OPJ_BYTE l_data [2];
opj_tcp_t * l_tcp;
opj_image_t* l_image_for_bounds;
/* preconditions */
assert(p_stream != 00);
@ -8787,7 +8795,18 @@ OPJ_BOOL opj_j2k_decode_tile(opj_j2k_t * p_j2k,
return OPJ_FALSE;
}
/* When using the opj_read_tile_header / opj_decode_tile_data API */
/* such as in test_tile_decoder, m_output_image is NULL, so fall back */
/* to the full image dimension. This is a bit surprising that */
/* opj_set_decode_area() is only used to determinte intersecting tiles, */
/* but full tile decoding is done */
l_image_for_bounds = p_j2k->m_output_image ? p_j2k->m_output_image :
p_j2k->m_private_image;
if (! opj_tcd_decode_tile(p_j2k->m_tcd,
l_image_for_bounds->x0,
l_image_for_bounds->y0,
l_image_for_bounds->x1,
l_image_for_bounds->y1,
l_tcp->m_data,
l_tcp->m_data_size,
p_tile_index,

View File

@ -1751,7 +1751,7 @@ static void opj_t1_clbl_decode_processor(void* user_data, opj_tls_t* tls)
}
void opj_t1_decode_cblks(opj_thread_pool_t* tp,
void opj_t1_decode_cblks(opj_tcd_t* tcd,
volatile OPJ_BOOL* pret,
opj_tcd_tilecomp_t* tilec,
opj_tccp_t* tccp,
@ -1760,6 +1760,7 @@ void opj_t1_decode_cblks(opj_thread_pool_t* tp,
OPJ_BOOL check_pterm
)
{
opj_thread_pool_t* tp = tcd->thread_pool;
OPJ_UINT32 resno, bandno, precno, cblkno;
for (resno = 0; resno < tilec->minimum_num_resolutions; ++resno) {
@ -1775,6 +1776,17 @@ void opj_t1_decode_cblks(opj_thread_pool_t* tp,
opj_tcd_cblk_dec_t* cblk = &precinct->cblks.dec[cblkno];
opj_t1_cblk_decode_processing_job_t* job;
if (!opj_tcd_is_subband_area_of_interest(tcd,
tilec->compno,
resno,
band->bandno,
(OPJ_UINT32)cblk->x0,
(OPJ_UINT32)cblk->y0,
(OPJ_UINT32)cblk->x1,
(OPJ_UINT32)cblk->y1)) {
continue;
}
job = (opj_t1_cblk_decode_processing_job_t*) opj_calloc(1,
sizeof(opj_t1_cblk_decode_processing_job_t));
if (!job) {

View File

@ -230,7 +230,7 @@ OPJ_BOOL opj_t1_encode_cblks(opj_t1_t *t1,
/**
Decode the code-blocks of a tile
@param tp Thread pool
@param tcd TCD handle
@param pret Pointer to return value
@param tilec The tile to decode
@param tccp Tile coding parameters
@ -238,7 +238,7 @@ Decode the code-blocks of a tile
@param p_manager_mutex mutex for the event manager
@param check_pterm whether PTERM correct termination should be checked
*/
void opj_t1_decode_cblks(opj_thread_pool_t* tp,
void opj_t1_decode_cblks(opj_tcd_t* tcd,
volatile OPJ_BOOL* pret,
opj_tcd_tilecomp_t* tilec,
opj_tccp_t* tccp,

View File

@ -13,6 +13,7 @@
* Copyright (c) 2005, Herve Drolon, FreeImage Team
* Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR
* Copyright (c) 2012, CS Systemes d'Information, France
* Copyright (c) 2017, IntoPIX SA <support@intopix.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -369,7 +370,8 @@ static void opj_null_jas_fprintf(FILE* file, const char * format, ...)
#define JAS_FPRINTF opj_null_jas_fprintf
#endif
OPJ_BOOL opj_t2_decode_packets(opj_t2_t *p_t2,
OPJ_BOOL opj_t2_decode_packets(opj_tcd_t* tcd,
opj_t2_t *p_t2,
OPJ_UINT32 p_tile_no,
opj_tcd_tile_t *p_tile,
OPJ_BYTE *p_src,
@ -434,14 +436,54 @@ OPJ_BOOL opj_t2_decode_packets(opj_t2_t *p_t2,
memset(first_pass_failed, OPJ_TRUE, l_image->numcomps * sizeof(OPJ_BOOL));
while (opj_pi_next(l_current_pi)) {
OPJ_BOOL skip_packet = OPJ_FALSE;
JAS_FPRINTF(stderr,
"packet offset=00000166 prg=%d cmptno=%02d rlvlno=%02d prcno=%03d lyrno=%02d\n\n",
l_current_pi->poc.prg1, l_current_pi->compno, l_current_pi->resno,
l_current_pi->precno, l_current_pi->layno);
if (l_tcp->num_layers_to_decode > l_current_pi->layno
&& l_current_pi->resno <
/* If the packet layer is greater or equal than the maximum */
/* number of layers, skip the packet */
if (l_current_pi->layno >= l_tcp->num_layers_to_decode) {
skip_packet = OPJ_TRUE;
}
/* If the packet resolution number is greater than the minimum */
/* number of resolution allowed, skip the packet */
else if (l_current_pi->resno >=
p_tile->comps[l_current_pi->compno].minimum_num_resolutions) {
skip_packet = OPJ_TRUE;
} else {
/* If no precincts of any band intersects the area of interest, */
/* skip the packet */
OPJ_UINT32 bandno;
opj_tcd_tilecomp_t *tilec = &p_tile->comps[l_current_pi->compno];
opj_tcd_resolution_t *res = &tilec->resolutions[l_current_pi->resno];
skip_packet = OPJ_TRUE;
for (bandno = 0; bandno < res->numbands; ++bandno) {
opj_tcd_band_t* band = &res->bands[bandno];
opj_tcd_precinct_t* prec = &band->precincts[l_current_pi->precno];
if (opj_tcd_is_subband_area_of_interest(tcd,
l_current_pi->compno,
l_current_pi->resno,
band->bandno,
(OPJ_UINT32)prec->x0,
(OPJ_UINT32)prec->y0,
(OPJ_UINT32)prec->x1,
(OPJ_UINT32)prec->y1)) {
skip_packet = OPJ_FALSE;
break;
}
}
/*
printf("packet cmptno=%02d rlvlno=%02d prcno=%03d lyrno=%02d -> %s\n",
l_current_pi->compno, l_current_pi->resno,
l_current_pi->precno, l_current_pi->layno, skip_packet ? "skipped" : "kept");
*/
}
if (!skip_packet) {
l_nb_bytes_read = 0;
first_pass_failed[l_current_pi->compno] = OPJ_FALSE;

View File

@ -13,6 +13,7 @@
* Copyright (c) 2005, Herve Drolon, FreeImage Team
* Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR
* Copyright (c) 2012, CS Systemes d'Information, France
* Copyright (c) 2017, IntoPIX SA <support@intopix.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -94,6 +95,7 @@ OPJ_BOOL opj_t2_encode_packets(opj_t2_t* t2,
/**
Decode the packets of a tile from a source buffer
@param tcd TCD handle
@param t2 T2 handle
@param tileno number that identifies the tile for which to decode the packets
@param tile tile for which to decode the packets
@ -105,7 +107,8 @@ Decode the packets of a tile from a source buffer
@return FIXME DOC
*/
OPJ_BOOL opj_t2_decode_packets(opj_t2_t *t2,
OPJ_BOOL opj_t2_decode_packets(opj_tcd_t* tcd,
opj_t2_t *t2,
OPJ_UINT32 tileno,
opj_tcd_tile_t *tile,
OPJ_BYTE *src,

View File

@ -14,6 +14,7 @@
* Copyright (c) 2006-2007, Parvatha Elangovan
* Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR
* Copyright (c) 2012, CS Systemes d'Information, France
* Copyright (c) 2017, IntoPIX SA <support@intopix.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -790,6 +791,7 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no,
l_tilec->y0 = opj_int_ceildiv(l_tile->y0, (OPJ_INT32)l_image_comp->dy);
l_tilec->x1 = opj_int_ceildiv(l_tile->x1, (OPJ_INT32)l_image_comp->dx);
l_tilec->y1 = opj_int_ceildiv(l_tile->y1, (OPJ_INT32)l_image_comp->dy);
l_tilec->compno = compno;
/*fprintf(stderr, "\tTile compo border = %d,%d,%d,%d\n", l_tilec->x0, l_tilec->y0,l_tilec->x1,l_tilec->y1);*/
/* compute l_data_size with overflow check */
@ -1399,6 +1401,10 @@ OPJ_BOOL opj_tcd_encode_tile(opj_tcd_t *p_tcd,
}
OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd,
OPJ_UINT32 decoded_x0,
OPJ_UINT32 decoded_y0,
OPJ_UINT32 decoded_x1,
OPJ_UINT32 decoded_y1,
OPJ_BYTE *p_src,
OPJ_UINT32 p_max_length,
OPJ_UINT32 p_tile_no,
@ -1409,6 +1415,10 @@ OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd,
OPJ_UINT32 l_data_read;
p_tcd->tcd_tileno = p_tile_no;
p_tcd->tcp = &(p_tcd->cp->tcps[p_tile_no]);
p_tcd->decoded_x0 = decoded_x0;
p_tcd->decoded_y0 = decoded_y0;
p_tcd->decoded_x1 = decoded_x1;
p_tcd->decoded_y1 = decoded_y1;
#ifdef TODO_MSD /* FIXME */
/* INDEX >> */
@ -1690,6 +1700,7 @@ static OPJ_BOOL opj_tcd_t2_decode(opj_tcd_t *p_tcd,
}
if (! opj_t2_decode_packets(
p_tcd,
l_t2,
p_tcd->tcd_tileno,
p_tcd->tcd_image->tiles,
@ -1727,7 +1738,7 @@ static OPJ_BOOL opj_tcd_t1_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager)
}
for (compno = 0; compno < l_tile->numcomps; ++compno) {
opj_t1_decode_cblks(p_tcd->thread_pool, &ret, l_tile_comp, l_tccp,
opj_t1_decode_cblks(p_tcd, &ret, l_tile_comp, l_tccp,
p_manager, p_manager_mutex, check_pterm);
if (!ret) {
break;
@ -2359,3 +2370,72 @@ OPJ_BOOL opj_tcd_is_band_empty(opj_tcd_band_t* band)
{
return (band->x1 - band->x0 == 0) || (band->y1 - band->y0 == 0);
}
OPJ_BOOL opj_tcd_is_subband_area_of_interest(opj_tcd_t *tcd,
OPJ_UINT32 compno,
OPJ_UINT32 resno,
OPJ_UINT32 bandno,
OPJ_UINT32 band_x0,
OPJ_UINT32 band_y0,
OPJ_UINT32 band_x1,
OPJ_UINT32 band_y1)
{
OPJ_UINT32 filter_margin = (tcd->tcp->tccps[compno].qmfbid == 1) ? 2 : 3;
opj_tcd_tilecomp_t *tilec = &(tcd->tcd_image->tiles->comps[compno]);
opj_image_comp_t* image_comp = &(tcd->image->comps[compno]);
/* Compute the intersection of the area of interest, expressed in tile coordinates */
/* with the tile coordinates */
OPJ_UINT32 tcx0 = opj_uint_max(
(OPJ_UINT32)tilec->x0,
opj_uint_ceildiv(tcd->decoded_x0, image_comp->dx));
OPJ_UINT32 tcy0 = opj_uint_max(
(OPJ_UINT32)tilec->y0,
opj_uint_ceildiv(tcd->decoded_y0, image_comp->dy));
OPJ_UINT32 tcx1 = opj_uint_min(
(OPJ_UINT32)tilec->x1,
opj_uint_ceildiv(tcd->decoded_x1, image_comp->dx));
OPJ_UINT32 tcy1 = opj_uint_min(
(OPJ_UINT32)tilec->y1,
opj_uint_ceildiv(tcd->decoded_y1, image_comp->dy));
/* Compute number of decomposition for this band. See table F-1 */
OPJ_UINT32 nb = (resno == 0) ?
tilec->numresolutions - 1 :
tilec->numresolutions - resno;
/* Map above tile-based coordinates to sub-band-based coordinates per */
/* equation B-15 of the standard */
OPJ_UINT32 x0b = bandno & 1;
OPJ_UINT32 y0b = bandno >> 1;
OPJ_UINT32 tbx0 = (nb == 0) ? tcx0 : opj_uint_ceildiv(tcx0 - (1U <<
(nb - 1)) * x0b, 1U << nb);
OPJ_UINT32 tby0 = (nb == 0) ? tcy0 : opj_uint_ceildiv(tcy0 - (1U <<
(nb - 1)) * y0b, 1U << nb);
OPJ_UINT32 tbx1 = (nb == 0) ? tcx1 : opj_uint_ceildiv(tcx1 - (1U <<
(nb - 1)) * x0b, 1U << nb);
OPJ_UINT32 tby1 = (nb == 0) ? tcy1 : opj_uint_ceildiv(tcy1 - (1U <<
(nb - 1)) * y0b, 1U << nb);
OPJ_BOOL intersects;
if (tbx0 < filter_margin) {
tbx0 = 0;
} else {
tbx0 -= filter_margin;
}
if (tby0 < filter_margin) {
tby0 = 0;
} else {
tby0 -= filter_margin;
}
tbx1 = opj_uint_adds(tbx1, filter_margin);
tby1 = opj_uint_adds(tby1, filter_margin);
intersects = band_x0 < tbx1 && band_y0 < tby1 && band_x1 > tbx0 &&
band_y1 > tby0;
#ifdef DEBUG_VERBOSE
printf("compno=%u resno=%u nb=%u bandno=%u x0b=%u y0b=%u band=%u,%u,%u,%u tb=%u,%u,%u,%u -> %u\n",
compno, resno, nb, bandno, x0b, y0b,
band_x0, band_y0, band_x1, band_y1,
tbx0, tby0, tbx1, tby1, intersects);
#endif
return intersects;
}

View File

@ -13,6 +13,7 @@
* Copyright (c) 2005, Herve Drolon, FreeImage Team
* Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR
* Copyright (c) 2012, CS Systemes d'Information, France
* Copyright (c) 2017, IntoPIX SA <support@intopix.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -180,6 +181,8 @@ typedef struct opj_tcd_resolution {
typedef struct opj_tcd_tilecomp {
/* dimension of component : left upper corner (x0, y0) right low corner (x1,y1) */
OPJ_INT32 x0, y0, x1, y1;
/* component number */
OPJ_UINT32 compno;
/* number of resolutions level */
OPJ_UINT32 numresolutions;
/* number of resolutions level to decode (at max)*/
@ -252,6 +255,10 @@ typedef struct opj_tcd {
OPJ_BITFIELD m_is_decoder : 1;
/** Thread pool */
opj_thread_pool_t* thread_pool;
OPJ_UINT32 decoded_x0;
OPJ_UINT32 decoded_y0;
OPJ_UINT32 decoded_x1;
OPJ_UINT32 decoded_y1;
} opj_tcd_t;
/** @name Exported functions */
@ -348,6 +355,10 @@ OPJ_BOOL opj_tcd_encode_tile(opj_tcd_t *p_tcd,
/**
Decode a tile from a buffer into a raw image
@param tcd TCD handle
@param decoded_x0 Upper left x of region to decode (in grid coordinates)
@param decoded_y0 Upper left y of region to decode (in grid coordinates)
@param decoded_x1 Lower right x of region to decode (in grid coordinates)
@param decoded_y1 Lower right y of region to decode (in grid coordinates)
@param src Source buffer
@param len Length of source buffer
@param tileno Number that identifies one of the tiles to be decoded
@ -355,6 +366,10 @@ Decode a tile from a buffer into a raw image
@param manager the event manager.
*/
OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *tcd,
OPJ_UINT32 decoded_x0,
OPJ_UINT32 decoded_y0,
OPJ_UINT32 decoded_x1,
OPJ_UINT32 decoded_y1,
OPJ_BYTE *src,
OPJ_UINT32 len,
OPJ_UINT32 tileno,
@ -409,6 +424,31 @@ OPJ_BOOL opj_tcd_is_band_empty(opj_tcd_band_t* band);
/** Reinitialize a segment */
void opj_tcd_reinit_segment(opj_tcd_seg_t* seg);
/** Returns whether a sub-band region contributes to the area of interest
* tcd->decoded_x0,tcd->decoded_y0,tcd->decoded_x1,tcd->decoded_y1.
*
* @param tcd TCD handle.
* @param compno Component number
* @param resno Resolution number
* @param bandno Band number (*not* band index, ie 0, 1, 2 or 3)
* @param x0 Upper left x in subband coordinates
* @param y0 Upper left y in subband coordinates
* @param x1 Lower right x in subband coordinates
* @param y1 Lower right y in subband coordinates
* @return OPJ_TRUE whether the sub-band region contributs to the area of
* interest.
*/
OPJ_BOOL opj_tcd_is_subband_area_of_interest(opj_tcd_t *tcd,
OPJ_UINT32 compno,
OPJ_UINT32 resno,
OPJ_UINT32 bandno,
OPJ_UINT32 x0,
OPJ_UINT32 y0,
OPJ_UINT32 x1,
OPJ_UINT32 y1);
/* ----------------------------------------------------------------------- */
/*@}*/

View File

@ -45,6 +45,9 @@ add_executable(compare_raw_files ${compare_raw_files_SRCS})
add_executable(test_tile_encoder test_tile_encoder.c)
target_link_libraries(test_tile_encoder ${OPENJPEG_LIBRARY_NAME})
add_executable(test_decode_area test_decode_area.c)
target_link_libraries(test_decode_area ${OPENJPEG_LIBRARY_NAME})
# Let's try a couple of possibilities:
add_test(NAME tte0 COMMAND test_tile_encoder)
add_test(NAME tte1 COMMAND test_tile_encoder 3 2048 2048 1024 1024 8 1 tte1.j2k)
@ -80,6 +83,18 @@ set_property(TEST rta4 APPEND PROPERTY DEPENDS tte4)
add_test(NAME rta5 COMMAND j2k_random_tile_access tte5.j2k)
set_property(TEST rta5 APPEND PROPERTY DEPENDS tte5)
add_test(NAME tda_prep_reversible_no_precinct COMMAND test_tile_encoder 1 256 256 32 32 8 0 reversible_no_precinct.j2k 4 4 3 0 0 1)
add_test(NAME tda_reversible_no_precinct COMMAND test_decode_area -q reversible_no_precinct.j2k)
set_property(TEST tda_reversible_no_precinct APPEND PROPERTY DEPENDS tda_prep_reversible_no_precinct)
add_test(NAME tda_prep_reversible_with_precinct COMMAND test_tile_encoder 1 256 256 32 32 8 0 reversible_with_precinct.j2k 4 4 3 0 0 1 16 16)
add_test(NAME tda_reversible_with_precinct COMMAND test_decode_area -q reversible_with_precinct.j2k)
set_property(TEST tda_reversible_with_precinct APPEND PROPERTY DEPENDS tda_prep_reversible_with_precinct)
add_test(NAME tda_prep_irreversible_no_precinct COMMAND test_tile_encoder 1 256 256 32 32 8 1 irreversible_no_precinct.j2k 4 4 3 0 0 1)
add_test(NAME tda_irreversible_no_precinct COMMAND test_decode_area -q irreversible_no_precinct.j2k)
set_property(TEST tda_irreversible_no_precinct APPEND PROPERTY DEPENDS tda_prep_irreversible_no_precinct)
add_executable(include_openjpeg include_openjpeg.c)
# No image send to the dashboard if lib PNG is not available.

394
tests/test_decode_area.c Normal file
View File

@ -0,0 +1,394 @@
/*
* 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 <string.h>
#include <stdlib.h>
#include "openjpeg.h"
#include "format_defs.h"
/* -------------------------------------------------------------------------- */
#define JP2_RFC3745_MAGIC "\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a"
#define JP2_MAGIC "\x0d\x0a\x87\x0a"
/* position 45: "\xff\x52" */
#define J2K_CODESTREAM_MAGIC "\xff\x4f\xff\x51"
static int infile_format(const char *fname)
{
FILE *reader;
unsigned char buf[12];
unsigned int l_nb_read;
reader = fopen(fname, "rb");
if (reader == NULL) {
return -1;
}
memset(buf, 0, 12);
l_nb_read = (unsigned int)fread(buf, 1, 12, reader);
fclose(reader);
if (l_nb_read != 12) {
return -1;
}
if (memcmp(buf, JP2_RFC3745_MAGIC, 12) == 0 || memcmp(buf, JP2_MAGIC, 4) == 0) {
return JP2_CFMT;
} else if (memcmp(buf, J2K_CODESTREAM_MAGIC, 4) == 0) {
return J2K_CFMT;
} else {
return -1;
}
}
/* -------------------------------------------------------------------------- */
/**
sample error debug callback expecting no client object
*/
static void error_callback(const char *msg, void *client_data)
{
(void)client_data;
fprintf(stdout, "[ERROR] %s", msg);
}
/**
sample warning debug callback expecting no client object
*/
static void warning_callback(const char *msg, void *client_data)
{
(void)client_data;
fprintf(stdout, "[WARNING] %s", msg);
}
/**
sample debug callback expecting no client object
*/
static void info_callback(const char *msg, void *client_data)
{
(void)client_data;
(void)msg;
/*fprintf(stdout, "[INFO] %s", msg);*/
}
opj_image_t* decode(
OPJ_BOOL quiet,
const char* input_file,
OPJ_INT32 x0,
OPJ_INT32 y0,
OPJ_INT32 x1,
OPJ_INT32 y1,
OPJ_UINT32* ptilew,
OPJ_UINT32* ptileh,
OPJ_UINT32* pcblkw,
OPJ_UINT32* pcblkh)
{
opj_dparameters_t l_param;
opj_codec_t * l_codec = NULL;
opj_image_t * l_image = NULL;
opj_stream_t * l_stream = NULL;
if (!quiet) {
if (x0 != 0 || x1 != 0 || y0 != 0 || y1 != 0) {
printf("Decoding %d,%d,%d,%d\n", x0, y0, x1, y1);
} else {
printf("Decoding full image\n");
}
}
l_stream = opj_stream_create_default_file_stream(input_file, OPJ_TRUE);
if (!l_stream) {
fprintf(stderr, "ERROR -> failed to create the stream from the file\n");
return NULL;
}
/* Set the default decoding parameters */
opj_set_default_decoder_parameters(&l_param);
/* */
l_param.decod_format = infile_format(input_file);
switch (l_param.decod_format) {
case J2K_CFMT: { /* JPEG-2000 codestream */
/* Get a decoder handle */
l_codec = opj_create_decompress(OPJ_CODEC_J2K);
break;
}
case JP2_CFMT: { /* JPEG 2000 compressed image data */
/* Get a decoder handle */
l_codec = opj_create_decompress(OPJ_CODEC_JP2);
break;
}
default: {
fprintf(stderr, "ERROR -> Not a valid JPEG2000 file!\n");
opj_stream_destroy(l_stream);
return NULL;
}
}
/* catch events using our callbacks and give a local context */
opj_set_info_handler(l_codec, info_callback, 00);
opj_set_warning_handler(l_codec, warning_callback, 00);
opj_set_error_handler(l_codec, error_callback, 00);
/* Setup the decoder decoding parameters using user parameters */
if (! opj_setup_decoder(l_codec, &l_param)) {
fprintf(stderr, "ERROR ->failed to setup the decoder\n");
opj_stream_destroy(l_stream);
opj_destroy_codec(l_codec);
return NULL;
}
/* Read the main header of the codestream and if necessary the JP2 boxes*/
if (! opj_read_header(l_stream, l_codec, &l_image)) {
fprintf(stderr, "ERROR -> failed to read the header\n");
opj_stream_destroy(l_stream);
opj_destroy_codec(l_codec);
return NULL;
}
{
opj_codestream_info_v2_t* pCodeStreamInfo = opj_get_cstr_info(l_codec);
if (ptilew) {
*ptilew = pCodeStreamInfo->tdx;
}
if (ptileh) {
*ptilew = pCodeStreamInfo->tdy;
}
//int numResolutions = pCodeStreamInfo->m_default_tile_info.tccp_info[0].numresolutions;
if (pcblkw) {
*pcblkw = 1U << pCodeStreamInfo->m_default_tile_info.tccp_info[0].cblkw;
}
if (pcblkh) {
*pcblkh = 1U << pCodeStreamInfo->m_default_tile_info.tccp_info[0].cblkh;
}
opj_destroy_cstr_info(&pCodeStreamInfo);
}
if (x0 != 0 || x1 != 0 || y0 != 0 || y1 != 0) {
if (!opj_set_decode_area(l_codec, l_image, x0, y0, x1, y1)) {
fprintf(stderr, "ERROR -> failed to set the decoded area\n");
opj_stream_destroy(l_stream);
opj_destroy_codec(l_codec);
opj_image_destroy(l_image);
return NULL;
}
}
/* Get the decoded image */
if (!(opj_decode(l_codec, l_stream, l_image))) {
fprintf(stderr, "ERROR -> failed to decode image!\n");
opj_stream_destroy(l_stream);
opj_destroy_codec(l_codec);
opj_image_destroy(l_image);
return NULL;
}
if (! opj_end_decompress(l_codec, l_stream)) {
opj_stream_destroy(l_stream);
opj_destroy_codec(l_codec);
opj_image_destroy(l_image);
return NULL;
}
opj_stream_destroy(l_stream);
opj_destroy_codec(l_codec);
return l_image;
}
OPJ_BOOL check_consistency(opj_image_t* p_image, opj_image_t* p_sub_image)
{
OPJ_UINT32 compno;
for (compno = 0; compno < p_image->numcomps; compno ++) {
OPJ_UINT32 y;
OPJ_UINT32 shift_y = p_sub_image->comps[compno].y0 - p_image->comps[compno].y0;
OPJ_UINT32 shift_x = p_sub_image->comps[compno].x0 - p_image->comps[compno].x0;
OPJ_UINT32 image_w = p_image->comps[compno].w;
OPJ_UINT32 sub_image_w = p_sub_image->comps[compno].w;
for (y = 0; y < p_sub_image->comps[compno].h; y++) {
OPJ_UINT32 x;
for (x = 0; x < sub_image_w; x++) {
OPJ_INT32 sub_image_val =
p_sub_image->comps[compno].data[y * sub_image_w + x];
OPJ_INT32 image_val =
p_image->comps[compno].data[(y + shift_y) * image_w + x + shift_x];
if (sub_image_val != image_val) {
fprintf(stderr,
"Difference found at subimage pixel (%u,%u) "
"of compno=%u: got %d, expected %d\n",
x, y, compno, sub_image_val, image_val);
return OPJ_FALSE;
}
}
}
}
return OPJ_TRUE;
}
static INLINE OPJ_UINT32 opj_uint_min(OPJ_UINT32 a, OPJ_UINT32 b)
{
return (a < b) ? a : b;
}
int main(int argc, char** argv)
{
opj_image_t * l_image = NULL;
opj_image_t * l_sub_image = NULL;
OPJ_INT32 da_x0 = 0, da_y0 = 0, da_x1 = 0, da_y1 = 0;
const char* input_file = NULL;
OPJ_UINT32 tilew, tileh, cblkw, cblkh;
OPJ_UINT32 w, h;
OPJ_UINT32 x, y;
OPJ_UINT32 step_x, step_y;
OPJ_BOOL quiet = OPJ_FALSE;
OPJ_UINT32 nsteps = 100;
if (argc < 2) {
fprintf(stderr,
"Usage: test_decode_area [-q] [-steps n] input_file_jp2_or_jk2 [x0 y0 x1 y1]\n");
return 1;
}
{
int iarg;
for (iarg = 1; iarg < argc; iarg++) {
if (strcmp(argv[iarg], "-q") == 0) {
quiet = OPJ_TRUE;
} else if (strcmp(argv[iarg], "-steps") == 0 && iarg + 1 < argc) {
nsteps = (OPJ_UINT32)atoi(argv[iarg + 1]);
iarg ++;
} else if (input_file == NULL) {
input_file = argv[iarg];
} else if (iarg + 3 < argc) {
da_x0 = atoi(argv[iarg]);
da_y0 = atoi(argv[iarg + 1]);
da_x1 = atoi(argv[iarg + 2]);
da_y1 = atoi(argv[iarg + 3]);
iarg += 3;
}
}
}
l_image = decode(quiet, input_file, 0, 0, 0, 0,
&tilew, &tileh, &cblkw, &cblkh);
if (!l_image) {
return 1;
}
if (da_x0 != 0 || da_x1 != 0 || da_y0 != 0 || da_y1 != 0) {
l_sub_image = decode(quiet, input_file, da_x0, da_y0, da_x1, da_y1,
NULL, NULL, NULL, NULL);
if (!l_sub_image) {
fprintf(stderr, "decode failed for %d,%d,%d,%d\n",
da_x0, da_y0, da_x1, da_y1);
opj_image_destroy(l_sub_image);
opj_image_destroy(l_image);
return 1;
}
if (!check_consistency(l_image, l_sub_image)) {
fprintf(stderr, "Consistency checked failed for %d,%d,%d,%d\n",
da_x0, da_y0, da_x1, da_y1);
opj_image_destroy(l_sub_image);
opj_image_destroy(l_image);
return 1;
}
opj_image_destroy(l_sub_image);
opj_image_destroy(l_image);
return 0;
}
w = l_image->x1 - l_image->x0;
h = l_image->y1 - l_image->y0;
step_x = w > nsteps ? w / nsteps : 1;
step_y = h > nsteps ? h / nsteps : 1;
for (y = 0; y < h; y += step_y) {
for (x = 0; x < w; x += step_x) {
da_x0 = (OPJ_INT32)(l_image->x0 + x);
da_y0 = (OPJ_INT32)(l_image->y0 + y);
da_x1 = (OPJ_INT32)opj_uint_min(l_image->x1, l_image->x0 + x + 1);
da_y1 = (OPJ_INT32)opj_uint_min(l_image->y1, l_image->y0 + y + 1);
l_sub_image = decode(quiet, input_file, da_x0, da_y0, da_x1, da_y1,
NULL, NULL, NULL, NULL);
if (!l_sub_image) {
fprintf(stderr, "decode failed for %d,%d,%d,%d\n",
da_x0, da_y0, da_x1, da_y1);
opj_image_destroy(l_sub_image);
opj_image_destroy(l_image);
return 1;
}
if (!check_consistency(l_image, l_sub_image)) {
fprintf(stderr, "Consistency checked failed for %d,%d,%d,%d\n",
da_x0, da_y0, da_x1, da_y1);
opj_image_destroy(l_sub_image);
opj_image_destroy(l_image);
return 1;
}
opj_image_destroy(l_sub_image);
if (step_x > 1 || step_y > 1) {
if (step_x > 1) {
da_x0 = (OPJ_INT32)opj_uint_min(l_image->x1, (OPJ_UINT32)da_x0 + 1);
da_x1 = (OPJ_INT32)opj_uint_min(l_image->x1, (OPJ_UINT32)da_x1 + 1);
}
if (step_y > 1) {
da_y0 = (OPJ_INT32)opj_uint_min(l_image->y1, (OPJ_UINT32)da_y0 + 1);
da_y1 = (OPJ_INT32)opj_uint_min(l_image->y1, (OPJ_UINT32)da_y1 + 1);
}
l_sub_image = decode(quiet, input_file, da_x0, da_y0, da_x1, da_y1,
NULL, NULL, NULL, NULL);
if (!l_sub_image) {
fprintf(stderr, "decode failed for %d,%d,%d,%d\n",
da_x0, da_y0, da_x1, da_y1);
opj_image_destroy(l_sub_image);
opj_image_destroy(l_image);
return 1;
}
if (!check_consistency(l_image, l_sub_image)) {
fprintf(stderr, "Consistency checked failed for %d,%d,%d,%d\n",
da_x0, da_y0, da_x1, da_y1);
opj_image_destroy(l_sub_image);
opj_image_destroy(l_image);
return 1;
}
opj_image_destroy(l_sub_image);
}
}
}
opj_image_destroy(l_image);
return 0;
}

View File

@ -60,6 +60,16 @@ static void info_callback(const char *msg, void *client_data)
fprintf(stdout, "[INFO] %s", msg);
}
static INLINE OPJ_UINT32 opj_uint_max(OPJ_UINT32 a, OPJ_UINT32 b)
{
return (a > b) ? a : b;
}
static INLINE OPJ_UINT32 opj_uint_min(OPJ_UINT32 a, OPJ_UINT32 b)
{
return (a < b) ? a : b;
}
/* -------------------------------------------------------------------------- */
#define NUM_COMPS_MAX 4
@ -70,7 +80,7 @@ int main(int argc, char *argv[])
opj_image_t * l_image;
opj_image_cmptparm_t l_params [NUM_COMPS_MAX];
opj_stream_t * l_stream;
OPJ_UINT32 l_nb_tiles;
OPJ_UINT32 l_nb_tiles_width, l_nb_tiles_height, l_nb_tiles;
OPJ_UINT32 l_data_size;
size_t len;
@ -98,9 +108,18 @@ int main(int argc, char *argv[])
int comp_prec;
int irreversible;
const char *output_file;
int cblockw_init = 64;
int cblockh_init = 64;
int numresolution = 6;
OPJ_UINT32 offsetx = 0;
OPJ_UINT32 offsety = 0;
int quality_loss = 1;
int is_rand = 0;
/* should be test_tile_encoder 3 2000 2000 1000 1000 8 tte1.j2k */
if (argc == 9) {
opj_set_default_encoder_parameters(&l_param);
/* should be test_tile_encoder 3 2000 2000 1000 1000 8 tte1.j2k [64 64] [6] [0 0] [0] [256 256] */
if (argc >= 9) {
num_comps = (OPJ_UINT32)atoi(argv[1]);
image_width = atoi(argv[2]);
image_height = atoi(argv[3]);
@ -109,6 +128,28 @@ int main(int argc, char *argv[])
comp_prec = atoi(argv[6]);
irreversible = atoi(argv[7]);
output_file = argv[8];
if (argc >= 12) {
quality_loss = 0;
cblockw_init = atoi(argv[9]);
cblockh_init = atoi(argv[10]);
}
if (argc >= 13) {
numresolution = atoi(argv[11]);
}
if (argc >= 14) {
offsetx = (OPJ_UINT32)atoi(argv[12]);
offsety = (OPJ_UINT32)atoi(argv[13]);
}
if (argc >= 15) {
is_rand = atoi(argv[14]);
}
for (i = 15; i + 1 < (OPJ_UINT32)argc &&
l_param.res_spec < OPJ_J2K_MAXRLVLS; i += 2) {
l_param.csty |= 0x01;
l_param.prcw_init[l_param.res_spec] = atoi(argv[i]);
l_param.prch_init[l_param.res_spec] = atoi(argv[i + 1]);
l_param.res_spec ++;
}
} else {
num_comps = 3;
image_width = 2000;
@ -122,8 +163,11 @@ int main(int argc, char *argv[])
if (num_comps > NUM_COMPS_MAX) {
return 1;
}
l_nb_tiles = (OPJ_UINT32)(image_width / tile_width) * (OPJ_UINT32)(
image_height / tile_height);
l_nb_tiles_width = (offsetx + (OPJ_UINT32)image_width +
(OPJ_UINT32)tile_width - 1) / (OPJ_UINT32)tile_width;
l_nb_tiles_height = (offsety + (OPJ_UINT32)image_height +
(OPJ_UINT32)tile_height - 1) / (OPJ_UINT32)tile_height;
l_nb_tiles = l_nb_tiles_width * l_nb_tiles_height;
l_data_size = (OPJ_UINT32)tile_width * (OPJ_UINT32)tile_height *
(OPJ_UINT32)num_comps * (OPJ_UINT32)(comp_prec / 8);
@ -134,16 +178,21 @@ int main(int argc, char *argv[])
fprintf(stdout,
"Encoding random values -> keep in mind that this is very hard to compress\n");
for (i = 0; i < l_data_size; ++i) {
l_data[i] = (OPJ_BYTE)i; /*rand();*/
if (is_rand) {
l_data[i] = (OPJ_BYTE)rand();
} else {
l_data[i] = (OPJ_BYTE)i;
}
}
opj_set_default_encoder_parameters(&l_param);
/** you may here add custom encoding parameters */
/* rate specifications */
/** number of quality layers in the stream */
if (quality_loss) {
l_param.tcp_numlayers = 1;
l_param.cp_fixed_quality = 1;
l_param.tcp_distoratio[0] = 20;
}
/* is using others way of calculation */
/* l_param.cp_disto_alloc = 1 or l_param.cp_fixed_alloc = 1 */
/* l_param.tcp_rates[0] = ... */
@ -158,6 +207,10 @@ int main(int argc, char *argv[])
l_param.cp_tdx = tile_width;
l_param.cp_tdy = tile_height;
/* code block size */
l_param.cblockw_init = cblockw_init;
l_param.cblockh_init = cblockh_init;
/* use irreversible encoding ?*/
l_param.irreversible = irreversible;
@ -187,7 +240,7 @@ int main(int argc, char *argv[])
/* l_param.mode = 0;*/
/** number of resolutions */
l_param.numresolution = 6;
l_param.numresolution = numresolution;
/** progression order to use*/
/** OPJ_LRCP, OPJ_RLCP, OPJ_RPCL, PCRL, CPRL */
@ -221,8 +274,8 @@ int main(int argc, char *argv[])
l_current_param_ptr->sgnd = 0;
l_current_param_ptr->prec = (OPJ_UINT32)comp_prec;
l_current_param_ptr->x0 = 0;
l_current_param_ptr->y0 = 0;
l_current_param_ptr->x0 = offsetx;
l_current_param_ptr->y0 = offsety;
++l_current_param_ptr;
}
@ -251,10 +304,10 @@ int main(int argc, char *argv[])
return 1;
}
l_image->x0 = 0;
l_image->y0 = 0;
l_image->x1 = (OPJ_UINT32)image_width;
l_image->y1 = (OPJ_UINT32)image_height;
l_image->x0 = offsetx;
l_image->y0 = offsety;
l_image->x1 = offsetx + (OPJ_UINT32)image_width;
l_image->y1 = offsety + (OPJ_UINT32)image_height;
l_image->color_space = OPJ_CLRSPC_SRGB;
if (! opj_setup_encoder(l_codec, &l_param, l_image)) {
@ -286,7 +339,18 @@ int main(int argc, char *argv[])
}
for (i = 0; i < l_nb_tiles; ++i) {
if (! opj_write_tile(l_codec, i, l_data, l_data_size, l_stream)) {
OPJ_UINT32 tile_y = i / l_nb_tiles_width;
OPJ_UINT32 tile_x = i % l_nb_tiles_width;
OPJ_UINT32 tile_x0 = opj_uint_max(l_image->x0, tile_x * (OPJ_UINT32)tile_width);
OPJ_UINT32 tile_y0 = opj_uint_max(l_image->y0,
tile_y * (OPJ_UINT32)tile_height);
OPJ_UINT32 tile_x1 = opj_uint_min(l_image->x1,
(tile_x + 1) * (OPJ_UINT32)tile_width);
OPJ_UINT32 tile_y1 = opj_uint_min(l_image->y1,
(tile_y + 1) * (OPJ_UINT32)tile_height);
OPJ_UINT32 tilesize = (tile_x1 - tile_x0) * (tile_y1 - tile_y0) *
(OPJ_UINT32)num_comps * (OPJ_UINT32)(comp_prec / 8);
if (! opj_write_tile(l_codec, i, l_data, tilesize, l_stream)) {
fprintf(stderr, "ERROR -> test_tile_encoder: failed to write the tile %d!\n",
i);
opj_stream_destroy(l_stream);