0. support for memory mapped files

1. zero copy reads for buffer/memory mapped stream interface

2. no code block allocation
This commit is contained in:
Aaron Boxer 2015-12-29 16:38:07 -05:00
parent 51efe91971
commit 964b065cf2
19 changed files with 1439 additions and 181 deletions

View File

@ -1177,6 +1177,7 @@ static opj_image_t* upsample_image_components(opj_image_t* original)
* OPJ_DECOMPRESS MAIN
*/
/* -------------------------------------------------------------------------- */
int main(int argc, char **argv)
{
opj_decompress_parameters parameters; /* decompression parameters */
@ -1236,22 +1237,47 @@ int main(int argc, char **argv)
}
/*Decoding image one by one*/
for(imageno = 0; imageno < num_images ; imageno++) {
for (imageno = 0; imageno < num_images; imageno++) {
fprintf(stderr,"\n");
fprintf(stderr, "\n");
if(img_fol.set_imgdir==1){
if (get_next_file(imageno, dirptr,&img_fol, &parameters)) {
fprintf(stderr,"skipping file...\n");
if (img_fol.set_imgdir == 1) {
if (get_next_file(imageno, dirptr, &img_fol, &parameters)) {
fprintf(stderr, "skipping file...\n");
destroy_parameters(&parameters);
continue;
}
}
/* read the input file and put it in memory */
/* ---------------------------------------- */
/* DEBUGGING: read the input file and put it in memory */
/* --------------------------------------------------- */
/*
OPJ_BOOL debug_buffers = OPJ_FALSE;
if (debug_buffers) {
FILE* p_file = NULL;
OPJ_SIZE_T sz = 0;
OPJ_BYTE* buffer = NULL;
p_file = fopen(parameters.infile, "rb");
if (p_file) {
fseek(p_file, 0L, SEEK_END);
sz = ftell(p_file);
fseek(p_file, 0L, SEEK_SET);
buffer = (OPJ_BYTE*)malloc(sz);
if (buffer) {
OPJ_SIZE_T res = fread(buffer, 1, sz, p_file);
if (res) {
fclose(p_file);
l_stream = opj_stream_create_buffer_stream(buffer, sz, 1);
}
}
}
}
*/
if (!l_stream) {
l_stream = opj_stream_create_mapped_file_read_stream(parameters.infile);
}
l_stream = opj_stream_create_default_file_stream(parameters.infile,1);
if (!l_stream){
fprintf(stderr, "ERROR -> failed to create the stream from the file %s\n", parameters.infile);
destroy_parameters(&parameters);
@ -1284,6 +1310,7 @@ int main(int argc, char **argv)
fprintf(stderr, "skipping file..\n");
destroy_parameters(&parameters);
opj_stream_destroy(l_stream);
l_stream = NULL;
continue;
}
@ -1363,6 +1390,7 @@ int main(int argc, char **argv)
/* Close the byte stream */
opj_stream_destroy(l_stream);
l_stream = NULL;
if( image->color_space != OPJ_CLRSPC_SYCC
&& image->numcomps == 3 && image->comps[0].dx == image->comps[0].dy

View File

@ -37,6 +37,8 @@ set(OPENJPEG_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/pi.h
${CMAKE_CURRENT_SOURCE_DIR}/raw.c
${CMAKE_CURRENT_SOURCE_DIR}/raw.h
${CMAKE_CURRENT_SOURCE_DIR}/segmented_stream.c
${CMAKE_CURRENT_SOURCE_DIR}/segmented_stream.h
${CMAKE_CURRENT_SOURCE_DIR}/t1.c
${CMAKE_CURRENT_SOURCE_DIR}/t1.h
${CMAKE_CURRENT_SOURCE_DIR}/t2.c
@ -53,6 +55,8 @@ set(OPENJPEG_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/opj_malloc.c
${CMAKE_CURRENT_SOURCE_DIR}/opj_malloc.h
${CMAKE_CURRENT_SOURCE_DIR}/opj_stdint.h
${CMAKE_CURRENT_SOURCE_DIR}/vector.h
${CMAKE_CURRENT_SOURCE_DIR}/vector.c
)
if(BUILD_JPIP)
add_definitions(-DUSE_JPIP)

View File

@ -156,15 +156,16 @@ opj_stream_t* OPJ_CALLCONV opj_stream_create(OPJ_SIZE_T p_buffer_size,OPJ_BOOL l
return 00;
}
l_stream->m_buffer_size = p_buffer_size;
l_stream->m_stored_data = (OPJ_BYTE *) opj_malloc(p_buffer_size);
if (! l_stream->m_stored_data) {
opj_free(l_stream);
return 00;
if (p_buffer_size) {
l_stream->m_buffer_size = p_buffer_size;
l_stream->m_stored_data = (OPJ_BYTE *)opj_malloc(p_buffer_size);
if (!l_stream->m_stored_data) {
opj_free(l_stream);
return 00;
}
l_stream->m_current_data = l_stream->m_stored_data;
}
l_stream->m_current_data = l_stream->m_stored_data;
if (l_is_input) {
l_stream->m_status |= OPJ_STREAM_STATUS_INPUT;
l_stream->m_opj_skip = opj_stream_read_skip;
@ -197,8 +198,10 @@ void OPJ_CALLCONV opj_stream_destroy(opj_stream_t* p_stream)
if (l_stream->m_free_user_data_fn) {
l_stream->m_free_user_data_fn(l_stream->m_user_data);
}
opj_free(l_stream->m_stored_data);
l_stream->m_stored_data = 00;
if (l_stream->m_stored_data) {
opj_free(l_stream->m_stored_data);
l_stream->m_stored_data = 00;
}
opj_free(l_stream);
}
}
@ -214,6 +217,17 @@ void OPJ_CALLCONV opj_stream_set_read_function(opj_stream_t* p_stream, opj_strea
l_stream->m_read_fn = p_function;
}
void OPJ_CALLCONV opj_stream_set_zero_copy_read_function(opj_stream_t* p_stream, opj_stream_zero_copy_read_fn p_function)
{
opj_stream_private_t* l_stream = (opj_stream_private_t*)p_stream;
if ((!l_stream) || (!(l_stream->m_status & OPJ_STREAM_STATUS_INPUT))) {
return;
}
l_stream->m_zero_copy_read_fn = p_function;
}
void OPJ_CALLCONV opj_stream_set_seek_function(opj_stream_t* p_stream, opj_stream_seek_fn p_function)
{
opj_stream_private_t* l_stream = (opj_stream_private_t*) p_stream;
@ -263,6 +277,12 @@ void OPJ_CALLCONV opj_stream_set_user_data_length(opj_stream_t* p_stream, OPJ_UI
l_stream->m_user_data_length = data_length;
}
OPJ_BOOL opj_stream_supports_zero_copy_read(opj_stream_private_t * p_stream) {
return p_stream->m_zero_copy_read_fn ? OPJ_TRUE : OPJ_FALSE;
}
OPJ_SIZE_T opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_buffer, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr)
{
OPJ_SIZE_T l_read_nb_bytes = 0;
@ -370,6 +390,26 @@ OPJ_SIZE_T opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_bu
}
}
OPJ_SIZE_T opj_stream_read_data_zero_copy(opj_stream_private_t * p_stream, OPJ_BYTE ** p_buffer, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr)
{
OPJ_SIZE_T l_read_nb_bytes = p_stream->m_zero_copy_read_fn(p_buffer, p_size, p_stream->m_user_data);
if (l_read_nb_bytes == (OPJ_SIZE_T)-1) {
/* end of stream */
opj_event_msg(p_event_mgr, EVT_INFO, "Stream reached its end !\n");
p_stream->m_status |= OPJ_STREAM_STATUS_END;
return (OPJ_SIZE_T)-1;
}
else {
p_stream->m_byte_offset += (OPJ_OFF_T)l_read_nb_bytes;
return l_read_nb_bytes;
}
}
OPJ_SIZE_T opj_stream_write_data (opj_stream_private_t * p_stream,
const OPJ_BYTE * p_buffer,
OPJ_SIZE_T p_size,

View File

@ -98,10 +98,16 @@ typedef struct opj_stream_private
OPJ_UINT64 m_user_data_length;
/**
* Pointer to actual read function (NULL at the initialization of the cio.
* Pointer to actual read function (NULL at the initialization of the cio).
*/
opj_stream_read_fn m_read_fn;
/**
* Pointer to actual zero copy read function (NULL at the initialization of the cio).
*/
opj_stream_zero_copy_read_fn m_zero_copy_read_fn;
/**
* Pointer to actual write function (NULL at the initialization of the cio.
*/
@ -268,6 +274,13 @@ void opj_write_float_BE(OPJ_BYTE * p_buffer, OPJ_FLOAT32 p_value);
*/
OPJ_SIZE_T opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_buffer, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr);
OPJ_SIZE_T opj_stream_read_data_zero_copy(opj_stream_private_t * p_stream, OPJ_BYTE ** p_buffer, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr);
/**
* Check if this stream supports zero copy reads
*/
OPJ_BOOL opj_stream_supports_zero_copy_read(opj_stream_private_t * p_stream);
/**
* Writes some bytes to the stream.
* @param p_stream the stream to write data to.

View File

@ -4310,9 +4310,7 @@ static OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k,
{
OPJ_SIZE_T l_current_read_size;
opj_codestream_index_t * l_cstr_index = 00;
OPJ_BYTE ** l_current_data = 00;
opj_tcp_t * l_tcp = 00;
OPJ_UINT32 * l_tile_len = 00;
OPJ_BOOL l_sot_length_pb_detected = OPJ_FALSE;
/* preconditions */
@ -4338,8 +4336,6 @@ static OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k,
}
}
l_current_data = &(l_tcp->m_data);
l_tile_len = &l_tcp->m_data_size;
/* Patch to support new PHR data */
if (p_j2k->m_specific_param.m_decoder.m_sot_length) {
@ -4349,28 +4345,6 @@ static OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k,
opj_event_msg(p_manager, EVT_ERROR, "Tile part length size inconsistent with stream length\n");
return OPJ_FALSE;
}
if (! *l_current_data) {
/* LH: oddly enough, in this path, l_tile_len!=0.
* TODO: If this was consistent, we could simplify the code to only use realloc(), as realloc(0,...) default to malloc(0,...).
*/
*l_current_data = (OPJ_BYTE*) opj_malloc(p_j2k->m_specific_param.m_decoder.m_sot_length);
}
else {
OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(*l_current_data, *l_tile_len + p_j2k->m_specific_param.m_decoder.m_sot_length);
if (! l_new_current_data) {
opj_free(*l_current_data);
/*nothing more is done as l_current_data will be set to null, and just
afterward we enter in the error path
and the actual tile_len is updated (committed) at the end of the
function. */
}
*l_current_data = l_new_current_data;
}
if (*l_current_data == 00) {
opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode tile\n");
return OPJ_FALSE;
}
}
else {
l_sot_length_pb_detected = OPJ_TRUE;
@ -4401,11 +4375,24 @@ static OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k,
/* Patch to support new PHR data */
if (!l_sot_length_pb_detected) {
l_current_read_size = opj_stream_read_data(
p_stream,
*l_current_data + *l_tile_len,
p_j2k->m_specific_param.m_decoder.m_sot_length,
p_manager);
if (opj_stream_supports_zero_copy_read(p_stream)) {
OPJ_BYTE* ptr = NULL;
l_current_read_size = opj_stream_read_data_zero_copy(p_stream,
&ptr,
p_j2k->m_specific_param.m_decoder.m_sot_length,
p_manager);
opj_seg_buf_push_back(&l_tcp->m_data, ptr, p_j2k->m_specific_param.m_decoder.m_sot_length);
}
else {
opj_seg_buf_alloc_and_push_back(&l_tcp->m_data, p_j2k->m_specific_param.m_decoder.m_sot_length);
l_current_read_size = opj_stream_read_data(
p_stream,
opj_seg_buf_get_global_ptr(&l_tcp->m_data),
p_j2k->m_specific_param.m_decoder.m_sot_length,
p_manager);
}
}
else
{
@ -4418,9 +4405,6 @@ static OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k,
else {
p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_TPHSOT;
}
*l_tile_len += (OPJ_UINT32)l_current_read_size;
return OPJ_TRUE;
}
@ -7618,11 +7602,7 @@ static void opj_j2k_tcp_destroy (opj_tcp_t *p_tcp)
static void opj_j2k_tcp_data_destroy (opj_tcp_t *p_tcp)
{
if (p_tcp->m_data) {
opj_free(p_tcp->m_data);
p_tcp->m_data = NULL;
p_tcp->m_data_size = 0;
}
opj_seg_buf_cleanup(&p_tcp->m_data);
}
static void opj_j2k_cp_destroy (opj_cp_t *p_cp)
@ -8002,7 +7982,7 @@ OPJ_BOOL opj_j2k_read_tile_header( opj_j2k_t * p_j2k,
OPJ_UINT32 l_nb_tiles = p_j2k->m_cp.th * p_j2k->m_cp.tw;
l_tcp = p_j2k->m_cp.tcps + p_j2k->m_current_tile_number;
while( (p_j2k->m_current_tile_number < l_nb_tiles) && (l_tcp->m_data == 00) ) {
while( (p_j2k->m_current_tile_number < l_nb_tiles) && (l_tcp->m_data.segments.data == 00) ) {
++p_j2k->m_current_tile_number;
++l_tcp;
}
@ -8062,16 +8042,15 @@ OPJ_BOOL opj_j2k_decode_tile ( opj_j2k_t * p_j2k,
}
l_tcp = &(p_j2k->m_cp.tcps[p_tile_index]);
if (! l_tcp->m_data) {
if (! l_tcp->m_data.segments.data) {
opj_j2k_tcp_destroy(l_tcp);
return OPJ_FALSE;
}
if (! opj_tcd_decode_tile( p_j2k->m_tcd,
l_tcp->m_data,
l_tcp->m_data_size,
p_tile_index,
p_j2k->cstr_index, p_manager) ) {
if (! opj_tcd_decode_tile( p_j2k->m_tcd,
&l_tcp->m_data,
p_tile_index,
p_j2k->cstr_index, p_manager) ) {
opj_j2k_tcp_destroy(l_tcp);
p_j2k->m_specific_param.m_decoder.m_state |= 0x8000;/*FIXME J2K_DEC_STATE_ERR;*/
opj_event_msg(p_manager, EVT_ERROR, "Failed to decode.\n");

View File

@ -280,10 +280,9 @@ typedef struct opj_tcp
opj_tccp_t *tccps;
/** number of tile parts for the tile. */
OPJ_UINT32 m_nb_tile_parts;
/** data for the tile */
OPJ_BYTE * m_data;
/** size of data */
OPJ_UINT32 m_data_size;
opj_seg_buf_t m_data;
/** encoding norms */
OPJ_FLOAT64 * mct_norms;
/** the mct decoding matrix */

View File

@ -33,7 +33,19 @@
#ifdef _WIN32
#include <windows.h>
#endif /* _WIN32 */
#else /* _WIN32 */
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <sys/stat.h>
# include <unistd.h>
# include <sys/mman.h>
#endif
#include <fcntl.h>
#include "opj_includes.h"
@ -129,6 +141,103 @@ static OPJ_BOOL opj_seek_from_file (OPJ_OFF_T p_nb_bytes, FILE * p_user_data)
}
/* ---------------------------------------------------------------------- */
#ifdef _WIN32
typedef void* opj_handle_t;
#else
typedef OPJ_INT32 opj_handle_t;
#endif
typedef struct opj_buf_info
{
OPJ_BYTE *buf;
OPJ_OFF_T off;
OPJ_SIZE_T len;
opj_handle_t fd; // for file mapping
} opj_buf_info_t;
static void opj_free_buffer_info(void* user_data) {
if (user_data)
opj_free(user_data);
}
static OPJ_SIZE_T opj_zero_copy_read_from_buffer(void ** p_buffer,
OPJ_SIZE_T p_nb_bytes,
opj_buf_info_t* p_source_buffer)
{
OPJ_SIZE_T l_nb_read = 0;
if (p_source_buffer->off + p_nb_bytes < p_source_buffer->len) {
l_nb_read = p_nb_bytes;
}
*p_buffer = p_source_buffer->buf + p_source_buffer->off;
p_source_buffer->off += l_nb_read;
return l_nb_read ? l_nb_read : ((OPJ_SIZE_T)-1);
}
static OPJ_SIZE_T opj_read_from_buffer(void * p_buffer,
OPJ_SIZE_T p_nb_bytes,
opj_buf_info_t* p_source_buffer)
{
OPJ_SIZE_T l_nb_read;
if (p_source_buffer->off + p_nb_bytes < p_source_buffer->len)
{
l_nb_read = p_nb_bytes;
}
else
{
l_nb_read = (OPJ_SIZE_T)(p_source_buffer->len - p_source_buffer->off);
}
memcpy(p_buffer, p_source_buffer->buf + p_source_buffer->off, l_nb_read);
p_source_buffer->off += l_nb_read;
return l_nb_read ? l_nb_read : ((OPJ_SIZE_T)-1);
}
static OPJ_SIZE_T opj_write_from_buffer(void * p_buffer,
OPJ_SIZE_T p_nb_bytes,
opj_buf_info_t* p_source_buffer)
{
memcpy(p_source_buffer->buf + p_source_buffer->off, p_buffer, p_nb_bytes);
p_source_buffer->off += p_nb_bytes;
p_source_buffer->len += p_nb_bytes;
return p_nb_bytes;
}
static OPJ_OFF_T opj_skip_from_buffer(OPJ_OFF_T p_nb_bytes,
opj_buf_info_t * p_source_buffer)
{
if (p_source_buffer->off + p_nb_bytes < (OPJ_OFF_T)p_source_buffer->len) {
p_source_buffer->off += p_nb_bytes;
}
else {
p_source_buffer->off = p_source_buffer->len;
}
return p_nb_bytes;
}
static OPJ_BOOL opj_seek_from_buffer(OPJ_OFF_T p_nb_bytes,
opj_buf_info_t * p_source_buffer)
{
if (p_nb_bytes < (OPJ_OFF_T)p_source_buffer->len)
{
p_source_buffer->off = p_nb_bytes;
}
else {
p_source_buffer->off = p_source_buffer->len;
}
return OPJ_TRUE;
}
/* ---------------------------------------------------------------------- */
#ifdef _WIN32
#ifndef OPJ_STATIC
BOOL APIENTRY
@ -917,6 +1026,8 @@ void OPJ_CALLCONV opj_destroy_cstr_index(opj_codestream_index_t **p_cstr_index)
}
}
/* ---------------------------------------------------------------------- */
opj_stream_t* OPJ_CALLCONV opj_stream_create_default_file_stream (const char *fname, OPJ_BOOL p_is_read_stream)
{
return opj_stream_create_file_stream(fname, OPJ_J2K_STREAM_CHUNK_SIZE, p_is_read_stream);
@ -958,3 +1069,273 @@ opj_stream_t* OPJ_CALLCONV opj_stream_create_file_stream (
return l_stream;
}
/* ---------------------------------------------------------------------- */
static void opj_set_up_buffer_stream(opj_stream_t* l_stream, OPJ_SIZE_T len, OPJ_BOOL p_is_read_stream) {
opj_stream_set_user_data_length(l_stream, len);
if (p_is_read_stream) {
opj_stream_set_read_function(l_stream, (opj_stream_read_fn)opj_read_from_buffer);
opj_stream_set_zero_copy_read_function(l_stream, (opj_stream_zero_copy_read_fn)opj_zero_copy_read_from_buffer);
}
else
opj_stream_set_write_function(l_stream, (opj_stream_write_fn)opj_write_from_buffer);
opj_stream_set_skip_function(l_stream, (opj_stream_skip_fn)opj_skip_from_buffer);
opj_stream_set_seek_function(l_stream, (opj_stream_seek_fn)opj_seek_from_buffer);
}
opj_stream_t* OPJ_CALLCONV opj_stream_create_buffer_stream(OPJ_BYTE *buf,
OPJ_SIZE_T len,
OPJ_BOOL p_is_read_stream)
{
opj_stream_t* l_stream;
opj_buf_info_t* p_source_buffer = NULL;
if (!buf || !len)
return NULL;
p_source_buffer = (opj_buf_info_t*)opj_malloc(sizeof(opj_buf_info_t));
if (!p_source_buffer)
return NULL;
l_stream = opj_stream_create(0,p_is_read_stream);
if (!l_stream) {
opj_free(p_source_buffer);
return NULL;
}
memset(p_source_buffer, 0, sizeof(opj_buf_info_t));
p_source_buffer->buf = buf;
p_source_buffer->off = 0;
p_source_buffer->len = len;
opj_stream_set_user_data(l_stream, p_source_buffer, opj_free_buffer_info);
opj_set_up_buffer_stream(l_stream, p_source_buffer->len, p_is_read_stream);
return l_stream;
}
/* ---------------------------------------------------------------------- */
OPJ_INT32 opj_get_file_open_mode(const char* mode)
{
OPJ_INT32 m = -1;
switch (mode[0]) {
case 'r':
m = O_RDONLY;
if (mode[1] == '+')
m = O_RDWR;
break;
case 'w':
case 'a':
m = O_RDWR | O_CREAT;
if (mode[0] == 'w')
m |= O_TRUNC;
break;
default:
break;
}
return m;
}
#ifdef _WIN32
static OPJ_UINT64 opj_size_proc(opj_handle_t fd)
{
ULARGE_INTEGER m;
m.LowPart = GetFileSize(fd, &m.HighPart);
return(m.QuadPart);
}
static void* opj_map(opj_handle_t fd, OPJ_SIZE_T len) {
void* ptr = NULL;
HANDLE hMapFile = NULL;
if (!fd || !len)
return NULL;
/* Passing in 0 for the maximum file size indicates that we
would like to create a file mapping object for the full file size */
hMapFile = CreateFileMapping(fd, NULL, PAGE_READONLY, 0, 0, NULL);
if (hMapFile == NULL) {
return NULL;
}
ptr = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
CloseHandle(hMapFile);
return ptr;
}
static OPJ_INT32 opj_unmap(void* ptr, OPJ_SIZE_T len){
OPJ_INT32 rc = -1;
if (ptr)
rc = UnmapViewOfFile(ptr) ? 0 : -1;
return rc;
}
static opj_handle_t opj_open_fd(const char* fname, const char* mode) {
void* fd = NULL;
OPJ_INT32 m = -1;
DWORD dwMode = 0;
if (!fname)
return (opj_handle_t)-1;
m = opj_get_file_open_mode(mode);
switch (m) {
case O_RDONLY:
dwMode = OPEN_EXISTING;
break;
case O_RDWR:
dwMode = OPEN_ALWAYS;
break;
case O_RDWR | O_CREAT:
dwMode = OPEN_ALWAYS;
break;
case O_RDWR | O_TRUNC:
dwMode = CREATE_ALWAYS;
break;
case O_RDWR | O_CREAT | O_TRUNC:
dwMode = CREATE_ALWAYS;
break;
default:
return NULL;
}
fd = (opj_handle_t)CreateFileA(fname,
(m == O_RDONLY) ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE),
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, dwMode,
(m == O_RDONLY) ? FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_NORMAL,
NULL);
if (fd == INVALID_HANDLE_VALUE) {
return (opj_handle_t)-1;
}
return fd;
}
static OPJ_INT32 opj_close_fd(opj_handle_t fd) {
OPJ_INT32 rc = -1;
if (fd) {
rc = CloseHandle(fd) ? 0 : -1;
}
return rc;
}
#else
static OPJ_UINT64 opj_size_proc(opj_handle_t fd)
{
struct stat sb;
if (!fd)
return 0;
if (fstat(fd, &sb)<0)
return(0);
else
return((OPJ_UINT64)sb.st_size);
}
static void* opj_map(opj_handle_t fd, OPJ_SIZE_T len) {
void* ptr = NULL;
OPJ_UINT64 size64 = 0;
if (!fd)
return NULL;
size64 = opj_size_proc(fd);
ptr = (void*)mmap(0, (size_t)size64, PROT_READ, MAP_SHARED, fd, 0);
return ptr == (void*)-1 ? NULL : ptr;
}
static OPJ_INT32 opj_unmap(void* ptr, OPJ_SIZE_T len) {
if (ptr)
munmap(ptr, (off_t)len);
return 0;
}
static opj_handle_t opj_open_fd(const char* fname, const char* mode) {
opj_handle_t fd = 0;
OPJ_INT32 m = -1;
if (!fname) {
return (opj_handle_t )-1;
}
m = opj_get_file_open_mode(mode);
fd = open(fname, m, 0666);
if (fd < 0) {
#ifdef DEBUG_ERRNO
if (errno > 0 && strerror(errno) != NULL) {
printf("%s: %s", fname, strerror(errno));
}
else {
printf("%s: Cannot open", fname);
}
#endif
return (opj_handle_t )-1;
}
return fd;
}
static OPJ_INT32 opj_close_fd(opj_handle_t fd) {
if (!fd)
return 0;
return (close(fd));
}
#endif
static void opj_mem_map_free(void* user_data) {
if (user_data) {
opj_buf_info_t* buffer_info = (opj_buf_info_t*)user_data;
opj_unmap(buffer_info->buf, buffer_info->len);
opj_close_fd(buffer_info->fd);
opj_free(buffer_info);
}
}
/*
Currently, only read streams are supported for memory mapped files.
*/
opj_stream_t* OPJ_CALLCONV opj_stream_create_mapped_file_read_stream(const char *fname)
{
opj_stream_t* l_stream = NULL;
opj_buf_info_t* buffer_info = NULL;
void* mapped_view = NULL;
OPJ_BOOL p_is_read_stream = OPJ_TRUE;
opj_handle_t fd = opj_open_fd(fname, p_is_read_stream ? "r" : "w");
if (fd == (opj_handle_t)-1)
return NULL;
buffer_info = (opj_buf_info_t*)opj_malloc(sizeof(opj_buf_info_t));
memset(buffer_info, 0, sizeof(opj_buf_info_t));
buffer_info->fd = fd;
buffer_info->len = (OPJ_SIZE_T)opj_size_proc(fd);
l_stream = opj_stream_create(0, p_is_read_stream);
if (!l_stream) {
opj_mem_map_free(buffer_info);
return NULL;
}
mapped_view = opj_map(fd, buffer_info->len);
if (!mapped_view) {
opj_stream_destroy(l_stream);
opj_mem_map_free(buffer_info);
return NULL;
}
buffer_info->buf = mapped_view;
buffer_info->off = 0;
opj_stream_set_user_data(l_stream, buffer_info, (opj_stream_free_user_data_fn)opj_mem_map_free);
opj_set_up_buffer_stream(l_stream, buffer_info->len, p_is_read_stream);
return l_stream;
}

View File

@ -568,6 +568,7 @@ typedef struct opj_dparameters {
} opj_dparameters_t;
/**
* JPEG2000 codec V2.
* */
@ -592,6 +593,12 @@ typedef void * opj_codec_t;
*/
typedef OPJ_SIZE_T (* opj_stream_read_fn) (void * p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data) ;
/*
* Callback function prototype for zero copy read function
*/
typedef OPJ_SIZE_T(*opj_stream_zero_copy_read_fn) (void ** p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data);
/*
* Callback function prototype for write function
*/
@ -1128,6 +1135,15 @@ OPJ_API void OPJ_CALLCONV opj_stream_destroy(opj_stream_t* p_stream);
*/
OPJ_API void OPJ_CALLCONV opj_stream_set_read_function(opj_stream_t* p_stream, opj_stream_read_fn p_function);
/**
* Sets the given function to be used as a zero copy read function.
* NOTE: this feature is only available for memory mapped and buffer backed streams, not file streams
* @param p_stream the stream to modify
* @param p_function the function to use a read function.
*/
OPJ_API void OPJ_CALLCONV opj_stream_set_zero_copy_read_function(opj_stream_t* p_stream, opj_stream_zero_copy_read_fn p_function);
/**
* Sets the given function to be used as a write function.
* @param p_stream the stream to modify
@ -1180,6 +1196,11 @@ OPJ_API opj_stream_t* OPJ_CALLCONV opj_stream_create_default_file_stream (const
OPJ_API opj_stream_t* OPJ_CALLCONV opj_stream_create_file_stream (const char *fname,
OPJ_SIZE_T p_buffer_size,
OPJ_BOOL p_is_read_stream);
OPJ_API opj_stream_t* OPJ_CALLCONV opj_stream_create_buffer_stream(OPJ_BYTE *buf,
OPJ_SIZE_T len,
OPJ_BOOL p_is_read_stream);
OPJ_API opj_stream_t* OPJ_CALLCONV opj_stream_create_mapped_file_read_stream(const char *fname);
/*
==========================================================

View File

@ -177,6 +177,8 @@ static INLINE long opj_lrintf(float f) {
#include "opj_malloc.h"
#include "event.h"
#include "function_list.h"
#include "vector.h"
#include "segmented_stream.h"
#include "bio.h"
#include "cio.h"
@ -198,6 +200,7 @@ static INLINE long opj_lrintf(float f) {
#include "mct.h"
#include "opj_intmath.h"
#ifdef USE_JPIP
#include "cidx_manager.h"
#include "indexbox_manager.h"

View File

@ -0,0 +1,414 @@
/*
* 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) 2015, Aaron Boxer
* 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"
/* #define DEBUG_SEG_BUF */
OPJ_BOOL opj_min_buf_vec_copy_to_contiguous_buffer(opj_vec_t* min_buf_vec, OPJ_BYTE* buffer) {
OPJ_INT32 i = 0;
OPJ_SIZE_T offset = 0;
if (!buffer || !min_buf_vec)
return OPJ_FALSE;
for (i = 0; i < min_buf_vec->size; ++i) {
opj_min_buf_t* seg = (opj_min_buf_t*)opj_vec_get(min_buf_vec, i);
if (seg->len)
memcpy(buffer + offset, seg->buf, seg->len);
offset += seg->len;
}
return OPJ_TRUE;
}
OPJ_BOOL opj_min_buf_vec_push_back(opj_vec_t* buf_vec, OPJ_BYTE* buf, OPJ_UINT16 len) {
opj_min_buf_t* seg = NULL;
if (!buf_vec || !buf || !len)
return OPJ_FALSE;
if (!buf_vec->data) {
opj_vec_init(buf_vec);
buf_vec->owns_data = OPJ_TRUE;
}
seg = (opj_min_buf_t*)opj_malloc(sizeof(opj_buf_t));
if (!seg)
return OPJ_FALSE;
seg->buf = buf;
seg->len = len;
if (!opj_vec_push_back(buf_vec, seg)) {
opj_free(seg);
return OPJ_FALSE;
}
return OPJ_TRUE;
}
OPJ_UINT16 opj_min_buf_vec_get_len(opj_vec_t* min_buf_vec) {
OPJ_INT32 i = 0;
OPJ_UINT16 len = 0;
if (!min_buf_vec || !min_buf_vec->data)
return 0;
for (i = 0; i < min_buf_vec->size; ++i) {
opj_min_buf_t* seg = (opj_min_buf_t*)opj_vec_get(min_buf_vec, i);
if (seg)
len += seg->len;
}
return len;
}
/*--------------------------------------------------------------------------*/
/* Segmented Buffer Stream */
static void opj_seg_buf_increment(opj_seg_buf_t * seg_buf)
{
opj_buf_t* cur_seg = NULL;
if (seg_buf == NULL || seg_buf->cur_seg_id == seg_buf->segments.size-1) {
return;
}
cur_seg = (opj_buf_t*)opj_vec_get(&seg_buf->segments, seg_buf->cur_seg_id);
if (cur_seg->offset == cur_seg->len &&
seg_buf->cur_seg_id < seg_buf->segments.size -1) {
seg_buf->cur_seg_id++;
}
}
static OPJ_SIZE_T opj_seg_buf_read(opj_seg_buf_t * seg_buf,
void * p_buffer,
OPJ_SIZE_T p_nb_bytes)
{
OPJ_SIZE_T bytes_in_current_segment;
OPJ_SIZE_T bytes_to_read;
OPJ_SIZE_T total_bytes_read;
OPJ_SIZE_T bytes_left_to_read;
OPJ_SIZE_T bytes_remaining_in_file;
if (p_buffer == NULL || p_nb_bytes == 0 || seg_buf == NULL)
return 0;
/*don't try to read more bytes than are available */
bytes_remaining_in_file = seg_buf->data_len - opj_seg_buf_get_global_offset(seg_buf);
if (p_nb_bytes > bytes_remaining_in_file) {
#ifdef DEBUG_SEG_BUF
printf("Warning: attempt to read past end of segmented buffer\n");
#endif
p_nb_bytes = bytes_remaining_in_file;
}
total_bytes_read = 0;
bytes_left_to_read = p_nb_bytes;
while (bytes_left_to_read > 0 && seg_buf->cur_seg_id < seg_buf->segments.size) {
opj_buf_t* cur_seg = (opj_buf_t*)opj_vec_get(&seg_buf->segments, seg_buf->cur_seg_id);
bytes_in_current_segment = (OPJ_SIZE_T)(cur_seg->len - cur_seg->offset);
bytes_to_read = (bytes_left_to_read < bytes_in_current_segment) ?
bytes_left_to_read : bytes_in_current_segment;
if (p_buffer) {
memcpy((OPJ_BYTE*)p_buffer + total_bytes_read,cur_seg->buf + cur_seg->offset, bytes_to_read);
}
opj_seg_buf_incr_cur_seg_offset(seg_buf,bytes_to_read);
total_bytes_read += bytes_to_read;
bytes_left_to_read -= bytes_to_read;
}
return total_bytes_read ? total_bytes_read : (OPJ_SIZE_T)-1;
}
static OPJ_OFF_T opj_seg_buf_skip(OPJ_OFF_T p_nb_bytes, opj_seg_buf_t * seg_buf)
{
OPJ_SIZE_T bytes_in_current_segment;
OPJ_SIZE_T bytes_remaining;
if (!seg_buf)
return p_nb_bytes;
if (p_nb_bytes + opj_seg_buf_get_global_offset(seg_buf)> (OPJ_OFF_T)seg_buf->data_len) {
#ifdef DEBUG_SEG_BUF
printf("Warning: attempt to skip past end of segmented buffer\n");
#endif
return p_nb_bytes;
}
if (p_nb_bytes == 0)
return 0;
bytes_remaining = (OPJ_SIZE_T)p_nb_bytes;
while (seg_buf->cur_seg_id < seg_buf->segments.size && bytes_remaining > 0) {
opj_buf_t* cur_seg = (opj_buf_t*)opj_vec_get(&seg_buf->segments, seg_buf->cur_seg_id);
bytes_in_current_segment = (OPJ_SIZE_T)(cur_seg->len -cur_seg->offset);
/* hoover up all the bytes in this segment, and move to the next one */
if (bytes_in_current_segment > bytes_remaining) {
opj_seg_buf_incr_cur_seg_offset(seg_buf, bytes_in_current_segment);
bytes_remaining -= bytes_in_current_segment;
cur_seg = (opj_buf_t*)opj_vec_get(&seg_buf->segments, seg_buf->cur_seg_id);
}
else /* bingo! we found the segment */
{
opj_seg_buf_incr_cur_seg_offset(seg_buf, bytes_remaining);
return p_nb_bytes;
}
}
return p_nb_bytes;
}
static OPJ_BOOL opj_seg_buf_seek(OPJ_OFF_T p_nb_bytes, opj_seg_buf_t* seg_buf)
{
return OPJ_FALSE;
}
static OPJ_BOOL opj_seg_buf_add_segment(opj_seg_buf_t* seg_buf, OPJ_BYTE* buf, OPJ_SIZE_T len) {
opj_buf_t* new_seg = NULL;
if (!seg_buf)
return OPJ_FALSE;
new_seg = (opj_buf_t*)opj_malloc(sizeof(opj_buf_t));
if (!new_seg)
return OPJ_FALSE;
memset(new_seg, 0, sizeof(opj_buf_t));
new_seg->buf = buf;
new_seg->len = len;
if (!opj_vec_push_back(&seg_buf->segments, new_seg)) {
opj_free(new_seg);
return OPJ_FALSE;
}
seg_buf->cur_seg_id = seg_buf->segments.size - 1;
seg_buf->data_len += len;
return OPJ_TRUE;
}
/*--------------------------------------------------------------------------*/
void opj_seg_buf_cleanup(opj_seg_buf_t* seg_buf) {
OPJ_INT32 i;
if (!seg_buf)
return;
for (i = 0; i < seg_buf->segments.size; ++i) {
opj_buf_t* seg = (opj_buf_t*)opj_vec_get(&seg_buf->segments, i);
if (seg) {
opj_buf_free(seg);
}
}
opj_vec_cleanup(&seg_buf->segments);
}
void opj_seg_buf_rewind(opj_seg_buf_t* seg_buf) {
OPJ_INT32 i;
if (!seg_buf)
return;
for (i = 0; i < seg_buf->segments.size; ++i) {
opj_buf_t* seg = (opj_buf_t*)opj_vec_get(&seg_buf->segments, i);
if (seg) {
seg->offset = 0;
}
}
seg_buf->cur_seg_id = 0;
}
OPJ_BOOL opj_seg_buf_push_back(opj_seg_buf_t* seg_buf, OPJ_BYTE* buf, OPJ_SIZE_T len) {
opj_buf_t* seg = NULL;
if (!seg_buf || !buf || !len)
return OPJ_FALSE;
if (!seg_buf->segments.data) {
opj_vec_init(&seg_buf->segments);
/* let segmented buffer free the segment and its internal buffer,
so don't make vector manage memory */
seg_buf->segments.owns_data = OPJ_FALSE;
}
if (!opj_seg_buf_add_segment(seg_buf, buf, len))
return OPJ_FALSE;
seg = (opj_buf_t*)opj_vec_back(&seg_buf->segments);
seg->owns_data = OPJ_FALSE;
return OPJ_TRUE;
}
OPJ_BOOL opj_seg_buf_alloc_and_push_back(opj_seg_buf_t* seg_buf, OPJ_SIZE_T len) {
opj_buf_t* seg = NULL;
OPJ_BYTE* buf = NULL;
if (!seg_buf || !len)
return OPJ_FALSE;
if (!seg_buf->segments.data) {
opj_vec_init(&seg_buf->segments);
/* we want to free the segment and its internal buffer, so don't make vector manage memory*/
seg_buf->segments.owns_data = OPJ_FALSE;
}
buf = (OPJ_BYTE*)opj_malloc(len);
if (!buf)
return OPJ_FALSE;
if (!opj_seg_buf_add_segment(seg_buf, buf, len)) {
opj_free(buf);
return OPJ_FALSE;
}
seg = (opj_buf_t*)opj_vec_back(&seg_buf->segments);
seg->owns_data = OPJ_TRUE;
return OPJ_TRUE;
}
void opj_seg_buf_incr_cur_seg_offset(opj_seg_buf_t* seg_buf, OPJ_OFF_T offset) {
opj_buf_t* cur_seg = NULL;
if (!seg_buf)
return;
cur_seg = (opj_buf_t*)(seg_buf->segments.data[seg_buf->cur_seg_id]);
opj_buf_incr_offset(cur_seg, offset);
if (cur_seg->offset == cur_seg->len) {
opj_seg_buf_increment(seg_buf);
}
}
/**
* Zero copy read of contiguous chunk from current segment.
* Returns OPJ_FALSE if unable to get a contiguous chunk, OPJ_TRUE otherwise
*/
OPJ_BOOL opj_seg_buf_zero_copy_read(opj_seg_buf_t* seg_buf,
OPJ_BYTE** ptr,
OPJ_SIZE_T chunk_len) {
opj_buf_t* cur_seg = NULL;
if (!seg_buf)
return OPJ_FALSE;
cur_seg = (opj_buf_t*)opj_vec_get(&seg_buf->segments, seg_buf->cur_seg_id);
if (!cur_seg)
return OPJ_FALSE;
if (cur_seg->offset + chunk_len <= cur_seg->len) {
*ptr = cur_seg->buf + cur_seg->offset;
opj_seg_buf_read(seg_buf, NULL, chunk_len);
return OPJ_TRUE;
}
return OPJ_FALSE;
}
OPJ_BOOL opj_seg_buf_copy_to_contiguous_buffer(opj_seg_buf_t* seg_buf, OPJ_BYTE* buffer) {
OPJ_INT32 i = 0;
OPJ_SIZE_T offset = 0;
if (!buffer || !seg_buf)
return OPJ_FALSE;
for (i = 0; i < seg_buf->segments.size; ++i) {
opj_buf_t* seg = (opj_buf_t*)opj_vec_get(&seg_buf->segments, i);
if (seg->len)
memcpy(buffer + offset, seg->buf, seg->len);
offset += seg->len;
}
return OPJ_TRUE;
}
OPJ_BYTE* opj_seg_buf_get_global_ptr(opj_seg_buf_t* seg_buf) {
opj_buf_t* cur_seg = NULL;
if (!seg_buf)
return NULL;
cur_seg = (opj_buf_t*)(seg_buf->segments.data[seg_buf->cur_seg_id]);
return (cur_seg) ? (cur_seg->buf + cur_seg->offset) : NULL;
}
OPJ_SIZE_T opj_seg_buf_get_cur_seg_len(opj_seg_buf_t* seg_buf) {
opj_buf_t* cur_seg = NULL;
if (!seg_buf)
return 0;
cur_seg = (opj_buf_t*)(opj_vec_get(&seg_buf->segments, seg_buf->cur_seg_id));
return (cur_seg) ? (OPJ_SIZE_T)(cur_seg->len - cur_seg->offset) : 0;
}
OPJ_OFF_T opj_seg_buf_get_cur_seg_offset(opj_seg_buf_t* seg_buf) {
opj_buf_t* cur_seg = NULL;
if (!seg_buf)
return 0;
cur_seg = (opj_buf_t*)(opj_vec_get(&seg_buf->segments, seg_buf->cur_seg_id));
return (cur_seg) ? (OPJ_OFF_T)(cur_seg->offset) : 0;
}
OPJ_OFF_T opj_seg_buf_get_global_offset(opj_seg_buf_t* seg_buf) {
OPJ_INT32 i = 0;
OPJ_OFF_T offset = 0;
if (!seg_buf)
return 0;
for (i = 0; i < seg_buf->cur_seg_id; ++i) {
opj_buf_t* seg = (opj_buf_t*)opj_vec_get(&seg_buf->segments, i);
offset += seg->len;
}
return offset + opj_seg_buf_get_cur_seg_offset(seg_buf);
}
void opj_buf_incr_offset(opj_buf_t* buf, OPJ_OFF_T off) {
if (!buf)
return;
/* we allow the offset to move to one location beyond end of buffer segment*/
if (buf->offset + off > (OPJ_OFF_T)buf->len) {
#ifdef DEBUG_SEG_BUF
printf("Warning: attempt to increment buffer offset out of bounds\n");
#endif
buf->offset = buf->len;
}
buf->offset += off;
}
void opj_buf_free(opj_buf_t* buffer) {
if (!buffer)
return;
if (buffer->buf && buffer->owns_data)
opj_free(buffer->buf);
opj_free(buffer);
}

View File

@ -0,0 +1,154 @@
/*
* 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) 2015, Aaron Boxer
* 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.
*/
#ifndef __SEGMENTED_STREAM_H
#define __SEGMENTED_STREAM_H
/*
Smart wrapper to low level C array
*/
typedef struct opj_min_buf {
OPJ_BYTE *buf; /* internal array*/
OPJ_UINT16 len; /* length of array */
} opj_min_buf_t;
/*
Copy all segments, in sequence, into contiguous array
*/
OPJ_BOOL opj_min_buf_vec_copy_to_contiguous_buffer(opj_vec_t* min_buf_vec, OPJ_BYTE* buffer);
/*
Push buffer to back of min buf vector
*/
OPJ_BOOL opj_min_buf_vec_push_back(opj_vec_t* buf_vec, OPJ_BYTE* buf, OPJ_UINT16 len);
/*
Sum lengths of all buffers
*/
OPJ_UINT16 opj_min_buf_vec_get_len(opj_vec_t* min_buf_vec);
typedef struct opj_buf {
OPJ_BYTE *buf; /* internal array*/
OPJ_OFF_T offset; /* current offset into array */
OPJ_SIZE_T len; /* length of array */
OPJ_BOOL owns_data; /* OPJ_TRUE if buffer manages the buf array */
} opj_buf_t;
/*
Increment buffer offset
*/
void opj_buf_incr_offset(opj_buf_t* buf, OPJ_OFF_T off);
/*
Free buffer and also its internal array if owns_data is true
*/
void opj_buf_free(opj_buf_t* buf);
/* Segmented Buffer Interface
A segmented buffer stores a list of buffers, or segments, but can be treated as one single
contiguous buffer.
*/
typedef struct opj_seg_buf
{
OPJ_SIZE_T data_len; /* total length of all segments*/
OPJ_INT32 cur_seg_id; /* current index into segments vector */
opj_vec_t segments; /* vector of segments */
} opj_seg_buf_t;
/*
Wrap existing array and add to the back of the segmented buffer.
*/
OPJ_BOOL opj_seg_buf_push_back(opj_seg_buf_t* seg_buf, OPJ_BYTE* buf, OPJ_SIZE_T len);
/*
Allocate array and add to the back of the segmented buffer
*/
OPJ_BOOL opj_seg_buf_alloc_and_push_back(opj_seg_buf_t* seg_buf, OPJ_SIZE_T len);
/*
Increment offset of current segment
*/
void opj_seg_buf_incr_cur_seg_offset(opj_seg_buf_t* seg_buf, OPJ_OFF_T offset);
/*
Get length of current segment
*/
OPJ_SIZE_T opj_seg_buf_get_cur_seg_len(opj_seg_buf_t* seg_buf);
/*
Get offset of current segment
*/
OPJ_OFF_T opj_seg_buf_get_cur_seg_offset(opj_seg_buf_t* seg_buf);
/*
Treat segmented buffer as single contiguous buffer, and get current pointer
*/
OPJ_BYTE* opj_seg_buf_get_global_ptr(opj_seg_buf_t* seg_buf);
/*
Treat segmented buffer as single contiguous buffer, and get current offset
*/
OPJ_OFF_T opj_seg_buf_get_global_offset(opj_seg_buf_t* seg_buf);
/*
Reset all offsets to zero, and set current segment to beginning of list
*/
void opj_seg_buf_rewind(opj_seg_buf_t* seg_buf);
/*
Copy all segments, in sequence, into contiguous array
*/
OPJ_BOOL opj_seg_buf_copy_to_contiguous_buffer(opj_seg_buf_t* seg_buf, OPJ_BYTE* buffer);
/*
Cleans up internal resources
*/
void opj_seg_buf_cleanup(opj_seg_buf_t* seg_buf);
/*
Return current pointer, stored in ptr variable, and advance segmented buffer
offset by chunk_len
*/
OPJ_BOOL opj_seg_buf_zero_copy_read(opj_seg_buf_t* seg_buf,
OPJ_BYTE** ptr,
OPJ_SIZE_T chunk_len);
#endif

View File

@ -1210,7 +1210,7 @@ static OPJ_BOOL opj_t1_allocate_buffers(
* and initializes the look-up tables of the Tier-1 coder/decoder
* @return a new T1 handle if successful, returns NULL otherwise
*/
opj_t1_t* opj_t1_create(OPJ_BOOL isEncoder)
opj_t1_t* opj_t1_create(OPJ_BOOL isEncoder, OPJ_UINT16 code_block_width, OPJ_UINT16 code_block_height)
{
opj_t1_t *l_t1 = 00;
@ -1231,6 +1231,16 @@ opj_t1_t* opj_t1_create(OPJ_BOOL isEncoder)
opj_t1_destroy(l_t1);
return 00;
}
if (!isEncoder && code_block_width > 0 && code_block_height > 0) {
l_t1->compressed_block = (OPJ_BYTE*)opj_malloc(code_block_width * code_block_height);
if (!l_t1->compressed_block) {
opj_t1_destroy(l_t1);
return 00;
}
l_t1->compressed_block_size = (OPJ_SIZE_T)(code_block_width * code_block_height);
}
l_t1->encoder = isEncoder;
return l_t1;
@ -1264,7 +1274,8 @@ void opj_t1_destroy(opj_t1_t *p_t1)
opj_aligned_free(p_t1->flags);
p_t1->flags = 00;
}
if (p_t1->compressed_block)
opj_free(p_t1->compressed_block);
opj_free(p_t1);
}
@ -1371,6 +1382,8 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1,
OPJ_UINT32 passtype;
OPJ_UINT32 segno, passno;
OPJ_BYTE type = T1_TYPE_MQ; /* BYPASS mode */
OPJ_BYTE* block_buffer = NULL;
OPJ_SIZE_T total_seg_len;
if(!opj_t1_allocate_buffers(
t1,
@ -1380,6 +1393,33 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1,
return OPJ_FALSE;
}
total_seg_len = opj_min_buf_vec_get_len(&cblk->seg_buffers);
if (cblk->real_num_segs && total_seg_len) {
/* if there is only one segment, then it is already contiguous, so no need to make a copy*/
if (total_seg_len == 1 && cblk->seg_buffers.data[0]) {
block_buffer = ((opj_buf_t*)(cblk->seg_buffers.data[0]))->buf;
}
else {
/* block should have been allocated on creation of t1*/
if (!t1->compressed_block)
return OPJ_FALSE;
if (t1->compressed_block_size < total_seg_len) {
OPJ_BYTE* new_block = opj_realloc(t1->compressed_block, total_seg_len);
if (!new_block)
return OPJ_FALSE;
t1->compressed_block = new_block;
t1->compressed_block_size = total_seg_len;
}
opj_min_buf_vec_copy_to_contiguous_buffer(&cblk->seg_buffers, t1->compressed_block);
block_buffer = t1->compressed_block;
}
}
else {
return OPJ_TRUE;
}
bpno_plus_one = (OPJ_INT32)(roishift + cblk->numbps);
passtype = 2;
@ -1393,14 +1433,10 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1,
/* BYPASS mode */
type = ((bpno_plus_one <= ((OPJ_INT32) (cblk->numbps)) - 4) && (passtype < 2) && (cblksty & J2K_CCP_CBLKSTY_LAZY)) ? T1_TYPE_RAW : T1_TYPE_MQ;
/* FIXME: slviewer gets here with a null pointer. Why? Partially downloaded and/or corrupt textures? */
if(seg->data == 00){
continue;
}
if (type == T1_TYPE_RAW) {
opj_raw_init_dec(raw, (*seg->data) + seg->dataindex, seg->len);
opj_raw_init_dec(raw, block_buffer + seg->dataindex, seg->len);
} else {
if (OPJ_FALSE == opj_mqc_init_dec(mqc, (*seg->data) + seg->dataindex, seg->len)) {
if (OPJ_FALSE == opj_mqc_init_dec(mqc, block_buffer + seg->dataindex, seg->len)) {
return OPJ_FALSE;
}
}

View File

@ -97,7 +97,8 @@ typedef OPJ_INT16 opj_flag_t;
Tier-1 coding (coding of code-block coefficients)
*/
typedef struct opj_t1 {
OPJ_BYTE* compressed_block;
OPJ_SIZE_T compressed_block_size;
/** MQC component */
opj_mqc_t *mqc;
/** RAW component */
@ -151,7 +152,7 @@ OPJ_BOOL opj_t1_decode_cblks( opj_t1_t* t1,
* and initializes the look-up tables of the Tier-1 coder/decoder
* @return a new T1 handle if successful, returns NULL otherwise
*/
opj_t1_t* opj_t1_create(OPJ_BOOL isEncoder);
opj_t1_t* opj_t1_create(OPJ_BOOL isEncoder, OPJ_UINT16 code_block_width, OPJ_UINT16 code_block_height);
/**
* Destroys a previously created T1 handle

View File

@ -94,9 +94,8 @@ static OPJ_BOOL opj_t2_decode_packet( opj_t2_t* t2,
opj_tcd_tile_t *tile,
opj_tcp_t *tcp,
opj_pi_iterator_t *pi,
OPJ_BYTE *src,
opj_seg_buf_t* src_buf,
OPJ_UINT32 * data_read,
OPJ_UINT32 max_length,
opj_packet_info_t *pack_info,
opj_event_mgr_t *p_manager);
@ -104,9 +103,8 @@ static OPJ_BOOL opj_t2_skip_packet( opj_t2_t* p_t2,
opj_tcd_tile_t *p_tile,
opj_tcp_t *p_tcp,
opj_pi_iterator_t *p_pi,
OPJ_BYTE *p_src,
opj_seg_buf_t* src_buf,
OPJ_UINT32 * p_data_read,
OPJ_UINT32 p_max_length,
opj_packet_info_t *p_pack_info,
opj_event_mgr_t *p_manager);
@ -115,18 +113,16 @@ static OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2,
opj_tcp_t *p_tcp,
opj_pi_iterator_t *p_pi,
OPJ_BOOL * p_is_data_present,
OPJ_BYTE *p_src_data,
opj_seg_buf_t* src_buf,
OPJ_UINT32 * p_data_read,
OPJ_UINT32 p_max_length,
opj_packet_info_t *p_pack_info,
opj_event_mgr_t *p_manager);
static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2,
opj_tcd_tile_t *p_tile,
opj_pi_iterator_t *p_pi,
OPJ_BYTE *p_src_data,
opj_seg_buf_t* src_buf,
OPJ_UINT32 * p_data_read,
OPJ_UINT32 p_max_length,
opj_packet_info_t *pack_info,
opj_event_mgr_t *p_manager);
@ -347,13 +343,11 @@ static void opj_null_jas_fprintf(FILE* file, const char * format, ...)
OPJ_BOOL opj_t2_decode_packets( opj_t2_t *p_t2,
OPJ_UINT32 p_tile_no,
opj_tcd_tile_t *p_tile,
OPJ_BYTE *p_src,
opj_seg_buf_t* src_buf,
OPJ_UINT32 * p_data_read,
OPJ_UINT32 p_max_len,
opj_codestream_index_t *p_cstr_index,
opj_event_mgr_t *p_manager)
{
OPJ_BYTE *l_current_data = p_src;
opj_pi_iterator_t *l_pi = 00;
OPJ_UINT32 pino;
opj_image_t *l_image = p_t2->image;
@ -419,7 +413,9 @@ OPJ_BOOL opj_t2_decode_packets( opj_t2_t *p_t2,
first_pass_failed[l_current_pi->compno] = OPJ_FALSE;
if (! opj_t2_decode_packet(p_t2,p_tile,l_tcp,l_current_pi,l_current_data,&l_nb_bytes_read,p_max_len,l_pack_info, p_manager)) {
if (! opj_t2_decode_packet(p_t2,p_tile,l_tcp,l_current_pi,
src_buf,&l_nb_bytes_read,
l_pack_info, p_manager)) {
opj_pi_destroy(l_pi,l_nb_pocs);
opj_free(first_pass_failed);
return OPJ_FALSE;
@ -430,7 +426,10 @@ OPJ_BOOL opj_t2_decode_packets( opj_t2_t *p_t2,
}
else {
l_nb_bytes_read = 0;
if (! opj_t2_skip_packet(p_t2,p_tile,l_tcp,l_current_pi,l_current_data,&l_nb_bytes_read,p_max_len,l_pack_info, p_manager)) {
if (! opj_t2_skip_packet(p_t2,p_tile,l_tcp,l_current_pi,
src_buf,
&l_nb_bytes_read,
l_pack_info, p_manager)) {
opj_pi_destroy(l_pi,l_nb_pocs);
opj_free(first_pass_failed);
return OPJ_FALSE;
@ -443,8 +442,8 @@ OPJ_BOOL opj_t2_decode_packets( opj_t2_t *p_t2,
l_img_comp->resno_decoded = p_tile->comps[l_current_pi->compno].minimum_num_resolutions - 1;
}
l_current_data += l_nb_bytes_read;
p_max_len -= l_nb_bytes_read;
*p_data_read += l_nb_bytes_read;
/* INDEX >> */
#ifdef TODO_MSD
@ -484,7 +483,6 @@ OPJ_BOOL opj_t2_decode_packets( opj_t2_t *p_t2,
/* don't forget to release pi */
opj_pi_destroy(l_pi,l_nb_pocs);
*p_data_read = (OPJ_UINT32)(l_current_data - p_src);
return OPJ_TRUE;
}
@ -521,9 +519,8 @@ static OPJ_BOOL opj_t2_decode_packet( opj_t2_t* p_t2,
opj_tcd_tile_t *p_tile,
opj_tcp_t *p_tcp,
opj_pi_iterator_t *p_pi,
OPJ_BYTE *p_src,
opj_seg_buf_t* src_buf,
OPJ_UINT32 * p_data_read,
OPJ_UINT32 p_max_length,
opj_packet_info_t *p_pack_info,
opj_event_mgr_t *p_manager)
{
@ -533,22 +530,24 @@ static OPJ_BOOL opj_t2_decode_packet( opj_t2_t* p_t2,
*p_data_read = 0;
if (! opj_t2_read_packet_header(p_t2,p_tile,p_tcp,p_pi,&l_read_data,p_src,&l_nb_bytes_read,p_max_length,p_pack_info, p_manager)) {
if (! opj_t2_read_packet_header(p_t2,p_tile,p_tcp,p_pi,&l_read_data,
src_buf,
&l_nb_bytes_read,
p_pack_info, p_manager)) {
return OPJ_FALSE;
}
p_src += l_nb_bytes_read;
l_nb_total_bytes_read += l_nb_bytes_read;
p_max_length -= l_nb_bytes_read;
/* we should read data for the packet */
if (l_read_data) {
l_nb_bytes_read = 0;
if (! opj_t2_read_packet_data(p_t2,p_tile,p_pi,p_src,&l_nb_bytes_read,p_max_length,p_pack_info, p_manager)) {
if (! opj_t2_read_packet_data(p_t2,p_tile,p_pi,
src_buf,&l_nb_bytes_read,
p_pack_info, p_manager)) {
return OPJ_FALSE;
}
l_nb_total_bytes_read += l_nb_bytes_read;
}
@ -797,37 +796,42 @@ static OPJ_BOOL opj_t2_skip_packet( opj_t2_t* p_t2,
opj_tcd_tile_t *p_tile,
opj_tcp_t *p_tcp,
opj_pi_iterator_t *p_pi,
OPJ_BYTE *p_src,
opj_seg_buf_t* src_buf,
OPJ_UINT32 * p_data_read,
OPJ_UINT32 p_max_length,
opj_packet_info_t *p_pack_info,
opj_event_mgr_t *p_manager)
{
OPJ_BOOL l_read_data;
OPJ_UINT32 l_nb_bytes_read = 0;
OPJ_UINT32 l_nb_total_bytes_read = 0;
OPJ_UINT32 p_max_length = (OPJ_UINT32)opj_seg_buf_get_cur_seg_len(src_buf);
*p_data_read = 0;
if (! opj_t2_read_packet_header(p_t2,p_tile,p_tcp,p_pi,&l_read_data,p_src,&l_nb_bytes_read,p_max_length,p_pack_info, p_manager)) {
if (! opj_t2_read_packet_header(p_t2,p_tile,p_tcp,p_pi,&l_read_data,
src_buf,
&l_nb_bytes_read,
p_pack_info, p_manager)) {
return OPJ_FALSE;
}
p_src += l_nb_bytes_read;
l_nb_total_bytes_read += l_nb_bytes_read;
p_max_length -= l_nb_bytes_read;
p_max_length -= l_nb_bytes_read;
/* we should read data for the packet */
if (l_read_data) {
l_nb_bytes_read = 0;
if (! opj_t2_skip_packet_data(p_t2,p_tile,p_pi,&l_nb_bytes_read,p_max_length,p_pack_info, p_manager)) {
if (! opj_t2_skip_packet_data(p_t2,p_tile,p_pi,
&l_nb_bytes_read,
p_max_length,p_pack_info, p_manager)) {
return OPJ_FALSE;
}
opj_seg_buf_incr_cur_seg_offset(src_buf, l_nb_bytes_read);
l_nb_total_bytes_read += l_nb_bytes_read;
}
*p_data_read = l_nb_total_bytes_read;
return OPJ_TRUE;
}
@ -838,13 +842,14 @@ static OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2,
opj_tcp_t *p_tcp,
opj_pi_iterator_t *p_pi,
OPJ_BOOL * p_is_data_present,
OPJ_BYTE *p_src_data,
opj_seg_buf_t* src_buf,
OPJ_UINT32 * p_data_read,
OPJ_UINT32 p_max_length,
opj_packet_info_t *p_pack_info,
opj_event_mgr_t *p_manager)
{
OPJ_BYTE *p_src_data = opj_seg_buf_get_global_ptr(src_buf);
OPJ_UINT32 p_max_length = (OPJ_UINT32)opj_seg_buf_get_cur_seg_len(src_buf);
/* loop */
OPJ_UINT32 bandno, cblkno;
OPJ_UINT32 l_nb_code_blocks;
@ -966,6 +971,7 @@ static OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2,
* p_is_data_present = OPJ_FALSE;
*p_data_read = (OPJ_UINT32)(l_current_data - p_src_data);
opj_seg_buf_incr_cur_seg_offset(src_buf, *p_data_read);
return OPJ_TRUE;
}
@ -1096,6 +1102,7 @@ static OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2,
*p_is_data_present = OPJ_TRUE;
*p_data_read = (OPJ_UINT32)(l_current_data - p_src_data);
opj_seg_buf_incr_cur_seg_offset(src_buf, *p_data_read);
return OPJ_TRUE;
}
@ -1103,15 +1110,13 @@ static OPJ_BOOL opj_t2_read_packet_header( opj_t2_t* p_t2,
static OPJ_BOOL opj_t2_read_packet_data( opj_t2_t* p_t2,
opj_tcd_tile_t *p_tile,
opj_pi_iterator_t *p_pi,
OPJ_BYTE *p_src_data,
opj_seg_buf_t* src_buf,
OPJ_UINT32 * p_data_read,
OPJ_UINT32 p_max_length,
opj_packet_info_t *pack_info,
opj_packet_info_t *pack_info,
opj_event_mgr_t* p_manager)
{
OPJ_UINT32 bandno, cblkno;
OPJ_UINT32 l_nb_code_blocks;
OPJ_BYTE *l_current_data = p_src_data;
opj_tcd_band_t *l_band = 00;
opj_tcd_cblk_dec_t* l_cblk = 00;
opj_tcd_resolution_t* l_res = &p_tile->comps[p_pi->compno].resolutions[p_pi->resno];
@ -1155,10 +1160,12 @@ static OPJ_BOOL opj_t2_read_packet_data( opj_t2_t* p_t2,
}
do {
OPJ_OFF_T offset = opj_seg_buf_get_global_offset(src_buf);
OPJ_SIZE_T len = src_buf->data_len;
/* Check possible overflow (on l_current_data only, assumes input args already checked) then size */
if ((((OPJ_SIZE_T)l_current_data + (OPJ_SIZE_T)l_seg->newlen) < (OPJ_SIZE_T)l_current_data) || (l_current_data + l_seg->newlen > p_src_data + p_max_length)) {
if ((((OPJ_SIZE_T)offset + (OPJ_SIZE_T)l_seg->newlen) > (OPJ_SIZE_T)len)) {
opj_event_msg(p_manager, EVT_ERROR, "read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n",
l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, p_pi->compno);
l_seg->newlen, len, cblkno, p_pi->precno, bandno, p_pi->resno, p_pi->compno);
return OPJ_FALSE;
}
@ -1187,6 +1194,7 @@ static OPJ_BOOL opj_t2_read_packet_data( opj_t2_t* p_t2,
l_seg->newlen, l_cblk->data_current_size, 0xFFFFFFFF - l_seg->newlen, cblkno, p_pi->precno, bandno, p_pi->resno, p_pi->compno);
return OPJ_FALSE;
}
#ifdef POO
/* Check if the cblk->data have allocated enough memory */
if ((l_cblk->data_current_size + l_seg->newlen) > l_cblk->data_max_size) {
OPJ_BYTE* new_cblk_data = (OPJ_BYTE*) opj_realloc(l_cblk->data, l_cblk->data_current_size + l_seg->newlen);
@ -1201,15 +1209,19 @@ static OPJ_BOOL opj_t2_read_packet_data( opj_t2_t* p_t2,
l_cblk->data = new_cblk_data;
}
memcpy(l_cblk->data + l_cblk->data_current_size, l_current_data, l_seg->newlen);
memcpy(l_cblk->data + l_cblk->data_current_size, src_buf->mother.buf + src_buf->mother.offset, l_seg->newlen);
#endif
if (l_seg->numpasses == 0) {
l_seg->data = &l_cblk->data;
l_seg->dataindex = l_cblk->data_current_size;
l_seg->dataindex = l_cblk->data_current_size;
}
l_current_data += l_seg->newlen;
l_seg->numpasses += l_seg->numnewpasses;
opj_min_buf_vec_push_back(&l_cblk->seg_buffers, opj_seg_buf_get_global_ptr(src_buf), l_seg->newlen);
*(p_data_read) += l_seg->newlen;
opj_seg_buf_incr_cur_seg_offset(src_buf, l_seg->newlen);
l_seg->numpasses += l_seg->numnewpasses;
l_cblk->numnewpasses -= l_seg->numnewpasses;
l_seg->real_num_passes = l_seg->numpasses;
@ -1228,10 +1240,6 @@ static OPJ_BOOL opj_t2_read_packet_data( opj_t2_t* p_t2,
++l_band;
}
*(p_data_read) = (OPJ_UINT32)(l_current_data - p_src_data);
return OPJ_TRUE;
}

View File

@ -105,9 +105,8 @@ Decode the packets of a tile from a source buffer
OPJ_BOOL opj_t2_decode_packets( opj_t2_t *t2,
OPJ_UINT32 tileno,
opj_tcd_tile_t *tile,
OPJ_BYTE *src,
opj_seg_buf_t* src_buf,
OPJ_UINT32 * p_data_read,
OPJ_UINT32 len,
opj_codestream_index_t *cstr_info,
opj_event_mgr_t *p_manager);

View File

@ -110,7 +110,7 @@ void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_image_t * img) {
static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no, OPJ_BOOL isEncoder, OPJ_FLOAT32 fraction, OPJ_SIZE_T sizeof_block, opj_event_mgr_t* manager);
/**
* Allocates memory for a decoding code block.
* Allocates memory for a decoding code block (but not data)
*/
static OPJ_BOOL opj_tcd_code_block_dec_allocate (opj_tcd_cblk_dec_t * p_code_block);
@ -143,9 +143,8 @@ static void opj_tcd_free_tile(opj_tcd_t *tcd);
static OPJ_BOOL opj_tcd_t2_decode ( opj_tcd_t *p_tcd,
OPJ_BYTE * p_src_data,
opj_seg_buf_t* src_buf,
OPJ_UINT32 * p_data_read,
OPJ_UINT32 p_max_src_size,
opj_codestream_index_t *p_cstr_index,
opj_event_mgr_t *p_manager);
@ -695,6 +694,8 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no,
l_image = p_tcd->image;
l_image_comp = p_tcd->image->comps;
opj_seg_buf_rewind(&l_tcp->m_data);
p = p_tile_no % l_cp->tw; /* tile coordinates */
q = p_tile_no / l_cp->tw;
/*fprintf(stderr, "Tile coordinate = %d,%d\n", p, q);*/
@ -1091,42 +1092,36 @@ static OPJ_BOOL opj_tcd_code_block_enc_allocate_data (opj_tcd_cblk_enc_t * p_cod
}
/**
* Allocates memory for a decoding code block.
* Allocates memory for a decoding code block (but not data)
*/
static OPJ_BOOL opj_tcd_code_block_dec_allocate (opj_tcd_cblk_dec_t * p_code_block)
{
if (! p_code_block->data) {
if (!p_code_block->segs) {
p_code_block->segs = (opj_tcd_seg_t *)opj_calloc(OPJ_J2K_DEFAULT_NB_SEGS, sizeof(opj_tcd_seg_t));
if (!p_code_block->segs) {
return OPJ_FALSE;
}
/*fprintf(stderr, "Allocate %d elements of code_block->data\n", OPJ_J2K_DEFAULT_NB_SEGS * sizeof(opj_tcd_seg_t));*/
p_code_block->data = (OPJ_BYTE*) opj_malloc(OPJ_J2K_DEFAULT_CBLK_DATA_SIZE);
if (! p_code_block->data) {
return OPJ_FALSE;
}
p_code_block->data_max_size = OPJ_J2K_DEFAULT_CBLK_DATA_SIZE;
/*fprintf(stderr, "Allocate 8192 elements of code_block->data\n");*/
p_code_block->m_current_max_segs = OPJ_J2K_DEFAULT_NB_SEGS;
p_code_block->segs = (opj_tcd_seg_t *) opj_calloc(OPJ_J2K_DEFAULT_NB_SEGS,sizeof(opj_tcd_seg_t));
if (! p_code_block->segs) {
return OPJ_FALSE;
}
/*fprintf(stderr, "Allocate %d elements of code_block->data\n", OPJ_J2K_DEFAULT_NB_SEGS * sizeof(opj_tcd_seg_t));*/
/*fprintf(stderr, "Allocate 8192 elements of code_block->data\n");*/
/*fprintf(stderr, "m_current_max_segs of code_block->data = %d\n", p_code_block->m_current_max_segs);*/
}
else {
/* sanitize */
opj_tcd_seg_t * l_segs = p_code_block->segs;
OPJ_UINT32 l_current_max_segs = p_code_block->m_current_max_segs;
p_code_block->m_current_max_segs = OPJ_J2K_DEFAULT_NB_SEGS;
/*fprintf(stderr, "m_current_max_segs of code_block->data = %d\n", p_code_block->m_current_max_segs);*/
} else {
/* sanitize */
OPJ_BYTE* l_data = p_code_block->data;
OPJ_UINT32 l_data_max_size = p_code_block->data_max_size;
opj_tcd_seg_t * l_segs = p_code_block->segs;
OPJ_UINT32 l_current_max_segs = p_code_block->m_current_max_segs;
/* Note: since seg_buffers simply holds references to another data buffer,
we do not need to copy it to the sanitized block */
opj_vec_cleanup(&p_code_block->seg_buffers);
memset(p_code_block, 0, sizeof(opj_tcd_cblk_dec_t));
p_code_block->data = l_data;
p_code_block->data_max_size = l_data_max_size;
p_code_block->segs = l_segs;
p_code_block->m_current_max_segs = l_current_max_segs;
}
return OPJ_TRUE;
memset(p_code_block, 0, sizeof(opj_tcd_cblk_dec_t));
p_code_block->segs = l_segs;
p_code_block->m_current_max_segs = l_current_max_segs;
}
return OPJ_TRUE;
}
OPJ_UINT32 opj_tcd_get_decoded_tile_size ( opj_tcd_t *p_tcd )
@ -1251,8 +1246,7 @@ OPJ_BOOL opj_tcd_encode_tile( opj_tcd_t *p_tcd,
}
OPJ_BOOL opj_tcd_decode_tile( opj_tcd_t *p_tcd,
OPJ_BYTE *p_src,
OPJ_UINT32 p_max_length,
opj_seg_buf_t* src_buf,
OPJ_UINT32 p_tile_no,
opj_codestream_index_t *p_cstr_index,
opj_event_mgr_t *p_manager
@ -1288,7 +1282,7 @@ OPJ_BOOL opj_tcd_decode_tile( opj_tcd_t *p_tcd,
/*--------------TIER2------------------*/
/* FIXME _ProfStart(PGROUP_T2); */
l_data_read = 0;
if (! opj_tcd_t2_decode(p_tcd, p_src, &l_data_read, p_max_length, p_cstr_index, p_manager))
if (! opj_tcd_t2_decode(p_tcd, src_buf, &l_data_read,p_cstr_index, p_manager))
{
return OPJ_FALSE;
}
@ -1535,9 +1529,8 @@ static void opj_tcd_free_tile(opj_tcd_t *p_tcd)
static OPJ_BOOL opj_tcd_t2_decode (opj_tcd_t *p_tcd,
OPJ_BYTE * p_src_data,
opj_seg_buf_t* src_buf,
OPJ_UINT32 * p_data_read,
OPJ_UINT32 p_max_src_size,
opj_codestream_index_t *p_cstr_index,
opj_event_mgr_t *p_manager
)
@ -1553,9 +1546,8 @@ static OPJ_BOOL opj_tcd_t2_decode (opj_tcd_t *p_tcd,
l_t2,
p_tcd->tcd_tileno,
p_tcd->tcd_image->tiles,
p_src_data,
src_buf,
p_data_read,
p_max_src_size,
p_cstr_index,
p_manager)) {
opj_t2_destroy(l_t2);
@ -1576,8 +1568,7 @@ static OPJ_BOOL opj_tcd_t1_decode ( opj_tcd_t *p_tcd )
opj_tcd_tilecomp_t* l_tile_comp = l_tile->comps;
opj_tccp_t * l_tccp = p_tcd->tcp->tccps;
l_t1 = opj_t1_create(OPJ_FALSE);
l_t1 = opj_t1_create(OPJ_FALSE, l_tccp->cblkw, l_tccp->cblkh);
if (l_t1 == 00) {
return OPJ_FALSE;
}
@ -1801,12 +1792,7 @@ static void opj_tcd_code_block_dec_deallocate (opj_tcd_precinct_t * p_precinct)
/*fprintf(stderr,"nb_code_blocks =%d\t}\n", l_nb_code_blocks);*/
for (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) {
if (l_code_block->data) {
opj_free(l_code_block->data);
l_code_block->data = 00;
}
opj_vec_cleanup(&l_code_block->seg_buffers);
if (l_code_block->segs) {
opj_free(l_code_block->segs );
l_code_block->segs = 00;
@ -2012,7 +1998,7 @@ static OPJ_BOOL opj_tcd_t1_encode ( opj_tcd_t *p_tcd )
OPJ_UINT32 l_mct_numcomps = 0U;
opj_tcp_t * l_tcp = p_tcd->tcp;
l_t1 = opj_t1_create(OPJ_TRUE);
l_t1 = opj_t1_create(OPJ_TRUE,0,0);
if (l_t1 == 00) {
return OPJ_FALSE;
}

View File

@ -53,7 +53,6 @@ each other. The functions in TCD.C are used by other functions in J2K.C.
FIXME DOC
*/
typedef struct opj_tcd_seg {
OPJ_BYTE ** data;
OPJ_UINT32 dataindex;
OPJ_UINT32 numpasses;
OPJ_UINT32 real_num_passes;
@ -101,7 +100,7 @@ typedef struct opj_tcd_cblk_enc {
typedef struct opj_tcd_cblk_dec {
OPJ_BYTE * data; /* Data */
opj_vec_t seg_buffers;
opj_tcd_seg_t* segs; /* segments information */
OPJ_INT32 x0, y0, x1, y1; /* position of the code-blocks : left upper corner (x0, y0) right low corner (x1,y1) */
OPJ_UINT32 numbps;
@ -316,8 +315,7 @@ 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_BYTE *src,
OPJ_UINT32 len,
opj_seg_buf_t* src_buf,
OPJ_UINT32 tileno,
opj_codestream_index_t *cstr_info,
opj_event_mgr_t *manager);

116
src/lib/openjp2/vector.c Normal file
View File

@ -0,0 +1,116 @@
/*
* 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) 2015, Aaron Boxer
* 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"
const OPJ_INT32 VECTOR_INITIAL_CAPACITY = 4;
static OPJ_BOOL opj_vec_double_capacity_if_full(opj_vec_t *vec) {
if (!vec)
return OPJ_FALSE;
if (vec->size == vec->capacity-1) {
void** new_data = NULL;
OPJ_INT32 new_capacity = (OPJ_INT32)(1.5*vec->capacity);
new_data = opj_realloc(vec->data, (OPJ_SIZE_T)(sizeof(void*) * new_capacity));
if (new_data) {
vec->capacity = new_capacity;
vec->data = new_data;
return OPJ_TRUE;
}
else {
return OPJ_FALSE;
}
}
return OPJ_TRUE;
}
OPJ_BOOL opj_vec_init(opj_vec_t *vec) {
if (!vec)
return OPJ_FALSE;
if (vec->data)
return OPJ_TRUE;
vec->size = 0;
vec->capacity = VECTOR_INITIAL_CAPACITY;
vec->data = opj_malloc(sizeof(void*) * vec->capacity);
return vec->data ? OPJ_TRUE : OPJ_FALSE;
}
OPJ_BOOL opj_vec_push_back(opj_vec_t *vec, void* value) {
if (!opj_vec_double_capacity_if_full(vec))
return OPJ_FALSE;
vec->data[vec->size++] = value;
return OPJ_TRUE;
}
void* opj_vec_get(opj_vec_t *vec, OPJ_INT32 index) {
if (!vec->data)
return NULL;
assert(index < vec->size && index >= 0);
if (index >= vec->size || index < 0) {
return NULL;
}
return vec->data[index];
}
void* opj_vec_back(opj_vec_t *vec) {
if (!vec || !vec->data || !vec->size)
return NULL;
return opj_vec_get(vec, vec->size - 1);
}
OPJ_BOOL opj_vec_set(opj_vec_t *vec, OPJ_INT32 index, void* value) {
if (!vec)
return OPJ_FALSE;
while (index >= vec->size) {
if (!opj_vec_push_back(vec, NULL))
return OPJ_FALSE;
}
vec->data[index] = value;
return OPJ_TRUE;
}
void opj_vec_cleanup(opj_vec_t *vec) {
OPJ_INT32 i;
if (!vec || !vec->data)
return;
if (vec->owns_data) {
for (i = 0; i < vec->size; ++i) {
if (vec->data[i])
opj_free(vec->data[i]);
}
}
opj_free(vec->data);
vec->data = NULL;
vec->size = 0;
}

78
src/lib/openjp2/vector.h Normal file
View File

@ -0,0 +1,78 @@
/*
* 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) 2015, Aaron Boxer
* 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.
*/
#ifndef __VECTOR_H
#define __VECTOR_H
/*
Vector - a dynamic array.
*/
typedef struct opj_vec{
OPJ_INT32 size; /* current size of vec */
OPJ_INT32 capacity; /* maximum size of vec */
void* *data; /* array of void* pointers */
OPJ_BOOL owns_data;
} opj_vec_t;
/*
Initialize vector
*/
OPJ_BOOL opj_vec_init(opj_vec_t *vec);
/*
Add a value to the end of the vector
*/
OPJ_BOOL opj_vec_push_back(opj_vec_t *vec, void* value);
/*
Set a value at specified index. If index is greater then the size of the vector,
all intervening indices will be initialized to NULL
*/
OPJ_BOOL opj_vec_set(opj_vec_t *vec, OPJ_INT32 index, void* value);
/*
Get value at specified index
*/
void* opj_vec_get(opj_vec_t *vec, OPJ_INT32 index);
/*
Get value at end of vector
*/
void* opj_vec_back(opj_vec_t *vec);
/*
Clean up vector resources. Does NOT free vector itself
*/
void opj_vec_cleanup(opj_vec_t *vec);
#endif