From f32c5e7164e9722b451b07cca6e98d5bd54a3bb8 Mon Sep 17 00:00:00 2001 From: Aaron Boxer Date: Tue, 29 Dec 2015 16:38:07 -0500 Subject: [PATCH] added support for compress/decompress from buffer/memory mapped file --- src/bin/jp2/opj_decompress.c | 39 +++- src/lib/openjp2/openjpeg.c | 359 ++++++++++++++++++++++++++++++++++- src/lib/openjp2/openjpeg.h | 8 + 3 files changed, 399 insertions(+), 7 deletions(-) diff --git a/src/bin/jp2/opj_decompress.c b/src/bin/jp2/opj_decompress.c index f3b1cd5c..5bee04d4 100644 --- a/src/bin/jp2/opj_decompress.c +++ b/src/bin/jp2/opj_decompress.c @@ -1177,6 +1177,8 @@ static opj_image_t* upsample_image_components(opj_image_t* original) * OPJ_DECOMPRESS MAIN */ /* -------------------------------------------------------------------------- */ +OPJ_BOOL debug_buffers = OPJ_FALSE; + int main(int argc, char **argv) { opj_decompress_parameters parameters; /* decompression parameters */ @@ -1236,13 +1238,13 @@ 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, ¶meters)) { - fprintf(stderr,"skipping file...\n"); + if (img_fol.set_imgdir == 1) { + if (get_next_file(imageno, dirptr, &img_fol, ¶meters)) { + fprintf(stderr, "skipping file...\n"); destroy_parameters(¶meters); continue; } @@ -1250,8 +1252,33 @@ int main(int argc, char **argv) /* read the input file and put it in memory */ /* ---------------------------------------- */ + 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) { + int res = 0; + 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_stream(parameters.infile, OPJ_J2K_STREAM_CHUNK_SIZE, OPJ_TRUE); + //l_stream = opj_stream_create_default_file_stream(parameters.infile, 1); + } - 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(¶meters); diff --git a/src/lib/openjp2/openjpeg.c b/src/lib/openjp2/openjpeg.c index 5114cc10..a05b30a7 100644 --- a/src/lib/openjp2/openjpeg.c +++ b/src/lib/openjp2/openjpeg.c @@ -33,7 +33,19 @@ #ifdef _WIN32 #include -#endif /* _WIN32 */ +#else /* _WIN32 */ + +#include + +#include +#include +#include +# include +# include + +#endif + +#include #include "opj_includes.h" @@ -129,6 +141,87 @@ 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_buffer_info +{ + OPJ_BYTE *buf; + OPJ_OFF_T off; + OPJ_SIZE_T len; + opj_handle_t fd; // for file mapping +} opj_buffer_info_t; + +static void opj_free_buffer_info(void* user_data) { + if (user_data) + opj_free(user_data); +} + +static OPJ_SIZE_T opj_read_from_buffer(void * p_buffer, + OPJ_SIZE_T p_nb_bytes, + opj_buffer_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_buffer_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_buffer_info_t * p_source_buffer) +{ + if (p_source_buffer->off + p_nb_bytes < 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_buffer_info_t * p_source_buffer) +{ + if (p_nb_bytes < 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 +1010,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 +1053,265 @@ opj_stream_t* OPJ_CALLCONV opj_stream_create_file_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 (void*)-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) { + // unmap + 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 -1; + } + m = opj_get_file_open_mode(mode); + fd = open(fname, m, 0666); + if (fd < 0) { + if (errno > 0 && strerror(errno) != NULL) { + printf("%s: %s", fname, strerror(errno)); + } + else { + printf("%s: Cannot open", fname); + } + return -1; + } + return fd; +} + +static OPJ_INT32 opj_close_fd(opj_handle_t fd) { + if (!fd) + return 0; + return (close(fd)); +} + +#endif + + + +static void opj_memory_map_cleanup(void* user_data) { + if (user_data) { + opj_buffer_info_t* buffer_info = (opj_buffer_info_t*)user_data; + opj_unmap(buffer_info->buf, buffer_info->len); + opj_close_fd(buffer_info->fd); + opj_free(buffer_info); + } +} + +opj_stream_t* OPJ_CALLCONV opj_stream_create_mapped_file_stream(const char *fname, + OPJ_SIZE_T p_size, + OPJ_BOOL p_is_read_stream) +{ + opj_stream_t* l_stream = NULL; + opj_buffer_info_t* buffer_info = NULL; + void* mapped_view = NULL; + + 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_buffer_info_t*)opj_malloc(sizeof(opj_buffer_info_t)); + memset(buffer_info, 0, sizeof(opj_buffer_info_t)); + buffer_info->fd = fd; + buffer_info->len = (OPJ_SIZE_T)opj_size_proc(fd); + + l_stream = opj_stream_create(p_size, p_is_read_stream); + if (!l_stream) { + opj_memory_map_cleanup(buffer_info); + return NULL; + } + + mapped_view = opj_map(fd, buffer_info->len); + if (mapped_view == NULL) { + opj_memory_map_cleanup(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_memory_map_cleanup); + opj_stream_set_user_data_length(l_stream, buffer_info->len); + + if (p_is_read_stream) + opj_stream_set_read_function(l_stream, (opj_stream_read_fn)opj_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); + + return l_stream; +} + + +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 = NULL; + opj_buffer_info_t* p_source_buffer = NULL; + + if (!buf || !len) return NULL; + + l_stream = opj_stream_default_create(p_is_read_stream); + + if (!l_stream) return NULL; + + p_source_buffer = (opj_buffer_info_t*)opj_malloc(sizeof(opj_buffer_info_t)); + if (!p_source_buffer) + return NULL; + + memset(p_source_buffer, 0, sizeof(opj_buffer_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_stream_set_user_data_length(l_stream, p_source_buffer->len); + + if (p_is_read_stream) + opj_stream_set_read_function(l_stream, (opj_stream_read_fn)opj_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); + + return l_stream; +} + diff --git a/src/lib/openjp2/openjpeg.h b/src/lib/openjp2/openjpeg.h index c07e9c84..ae7d97d1 100644 --- a/src/lib/openjp2/openjpeg.h +++ b/src/lib/openjp2/openjpeg.h @@ -568,6 +568,7 @@ typedef struct opj_dparameters { } opj_dparameters_t; + /** * JPEG2000 codec V2. * */ @@ -1180,6 +1181,13 @@ 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_stream(const char *fname, + OPJ_SIZE_T p_size, + OPJ_BOOL p_is_read_stream); /* ==========================================================