/src/grok/src/lib/core/grok.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2016-2025 Grok Image Compression Inc. |
3 | | * |
4 | | * This source code is free software: you can redistribute it and/or modify |
5 | | * it under the terms of the GNU Affero General Public License, version 3, |
6 | | * as published by the Free Software Foundation. |
7 | | * |
8 | | * This source code is distributed in the hope that it will be useful, |
9 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | | * GNU Affero General Public License for more details. |
12 | | * |
13 | | * You should have received a copy of the GNU Affero General Public License |
14 | | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | | * |
16 | | * |
17 | | * This source code incorporates work covered by the BSD 2-clause license. |
18 | | * Please see the LICENSE file in the root directory for details. |
19 | | * |
20 | | */ |
21 | | |
22 | | #ifdef _WIN32 |
23 | | #include <windows.h> |
24 | | #else /* _WIN32 */ |
25 | | #include <sys/stat.h> |
26 | | #include <unistd.h> |
27 | | #include <sys/mman.h> |
28 | | #endif |
29 | | #include <fcntl.h> |
30 | | |
31 | | #include "grk_includes.h" |
32 | | using namespace grk; |
33 | | |
34 | | struct GrkCodec |
35 | | { |
36 | | explicit GrkCodec(grk_stream* stream); |
37 | | ~GrkCodec(); |
38 | | |
39 | | static GrkCodec* getImpl(grk_object* codec) |
40 | 3.38k | { |
41 | 3.38k | return ((GrkObjectWrapperImpl<GrkCodec>*)codec->wrapper)->getWrappee(); |
42 | 3.38k | } |
43 | | grk_object* getWrapper(void) |
44 | 0 | { |
45 | 0 | return &obj; |
46 | 0 | } |
47 | | |
48 | | grk_object obj; |
49 | | ICodeStreamCompress* compressor_; |
50 | | ICodeStreamDecompress* decompressor_; |
51 | | |
52 | | private: |
53 | | grk_stream* stream_; |
54 | | }; |
55 | | |
56 | | GrkCodec::GrkCodec(grk_stream* stream) |
57 | 752 | : compressor_(nullptr), decompressor_(nullptr), stream_(stream) |
58 | 752 | { |
59 | 752 | obj.wrapper = new GrkObjectWrapperImpl<GrkCodec>(this); |
60 | 752 | } |
61 | | |
62 | | GrkCodec::~GrkCodec() |
63 | 752 | { |
64 | 752 | delete compressor_; |
65 | 752 | delete decompressor_; |
66 | 752 | grk_object_unref(stream_); |
67 | 752 | } |
68 | | |
69 | | /** |
70 | | * Start compressing image |
71 | | * |
72 | | * @param codec compression codec |
73 | | * |
74 | | */ |
75 | | static bool grk_compress_start(grk_object* codec); |
76 | | |
77 | | /** Create stream from a file identified with its filename with a specific buffer size |
78 | | * |
79 | | * @param fname the name of the file to stream |
80 | | * @param buffer_size size of the chunk used to stream |
81 | | * @param is_read_stream whether the stream is a read stream (true) or not (false) |
82 | | */ |
83 | | static grk_stream* grk_stream_create_file_stream(const char* fname, size_t buffer_size, |
84 | | bool is_read_stream); |
85 | | |
86 | | static grk_stream* grk_stream_create_stream(grk_stream_params* stream_params); |
87 | | |
88 | | static grk_stream* grk_stream_new(size_t buffer_size, bool is_input) |
89 | 0 | { |
90 | 0 | auto streamImpl = new BufferedStream(nullptr, buffer_size, is_input); |
91 | |
|
92 | 0 | return streamImpl->getWrapper(); |
93 | 0 | } |
94 | | |
95 | | grk_object* grk_decompress_create(grk_stream* stream) |
96 | 752 | { |
97 | 752 | GrkCodec* codec = nullptr; |
98 | 752 | auto bstream = BufferedStream::getImpl(stream); |
99 | 752 | auto format = bstream->getFormat(); |
100 | 752 | if(format == GRK_CODEC_UNK) |
101 | 0 | { |
102 | 0 | grklog.error("Invalid codec format."); |
103 | 0 | return nullptr; |
104 | 0 | } |
105 | 752 | codec = new GrkCodec(stream); |
106 | 752 | if(format == GRK_CODEC_J2K) |
107 | 588 | codec->decompressor_ = new CodeStreamDecompress(BufferedStream::getImpl(stream)); |
108 | 164 | else |
109 | 164 | codec->decompressor_ = new FileFormatDecompress(BufferedStream::getImpl(stream)); |
110 | | |
111 | 752 | return &codec->obj; |
112 | 752 | } |
113 | | |
114 | | static void infoCallback(const char* msg, [[maybe_unused]] void* client_data) |
115 | 0 | { |
116 | 0 | auto t = std::string(msg) + "\n"; |
117 | 0 | fprintf(stdout, "[INFO] %s", t.c_str()); |
118 | 0 | } |
119 | | static void debugCallback(const char* msg, [[maybe_unused]] void* client_data) |
120 | 0 | { |
121 | 0 | auto t = std::string(msg) + "\n"; |
122 | 0 | fprintf(stdout, "[DEBUG] %s", t.c_str()); |
123 | 0 | } |
124 | | static void traceCallback(const char* msg, [[maybe_unused]] void* client_data) |
125 | 0 | { |
126 | 0 | auto t = std::string(msg) + "\n"; |
127 | 0 | fprintf(stdout, "[TRACE] %s", t.c_str()); |
128 | 0 | } |
129 | | static void warningCallback(const char* msg, [[maybe_unused]] void* client_data) |
130 | 0 | { |
131 | 0 | auto t = std::string(msg) + "\n"; |
132 | 0 | fprintf(stdout, "[WARNING] %s", t.c_str()); |
133 | 0 | } |
134 | | |
135 | | static void errorCallback(const char* msg, [[maybe_unused]] void* client_data) |
136 | 0 | { |
137 | 0 | auto t = std::string(msg) + "\n"; |
138 | 0 | fprintf(stderr, "%s", t.c_str()); |
139 | 0 | } |
140 | | |
141 | | struct InitState |
142 | | { |
143 | | InitState(const char* pluginPath, uint32_t numThreads) |
144 | 4 | : pluginPath_(pluginPath), numThreads_(numThreads), initialized_(false), |
145 | 4 | pluginInitialized_(false) |
146 | 4 | {} |
147 | 2 | InitState(void) : InitState(nullptr, 0) {} |
148 | | bool operator==(const InitState& rhs) const |
149 | 0 | { |
150 | 0 | return pluginPath_ == rhs.pluginPath_ && numThreads_ == rhs.numThreads_; |
151 | 0 | } |
152 | | const char* pluginPath_; |
153 | | uint32_t numThreads_; |
154 | | bool initialized_; |
155 | | bool pluginInitialized_; |
156 | | }; |
157 | | |
158 | | static InitState initState_; |
159 | | bool grk_initialize(const char* pluginPath, uint32_t numThreads) |
160 | 2 | { |
161 | 2 | const char* singleThreadEnv = std::getenv("GRK_TEST_SINGLE"); |
162 | 2 | if(singleThreadEnv && std::atoi(singleThreadEnv) == 1) |
163 | 0 | { |
164 | 0 | numThreads = 1; // Force single-threaded execution |
165 | 0 | } |
166 | | |
167 | 2 | InitState newState(pluginPath, numThreads); |
168 | 2 | if(initState_.initialized_ && newState == initState_) |
169 | 0 | return true; |
170 | | // 1. set up executor |
171 | 2 | ExecSingleton::create(numThreads); |
172 | | |
173 | 2 | if(!grklog.info_handler) |
174 | 2 | { |
175 | 2 | grk_msg_handlers handlers = {}; |
176 | 2 | const char* debug_env = std::getenv("GRK_DEBUG"); |
177 | 2 | if(debug_env) |
178 | 0 | { |
179 | 0 | int level = std::atoi(debug_env); |
180 | 0 | if(level >= 1) |
181 | 0 | handlers.error_callback = errorCallback; |
182 | 0 | if(level >= 2) |
183 | 0 | handlers.warn_callback = warningCallback; |
184 | 0 | if(level >= 3) |
185 | 0 | handlers.info_callback = infoCallback; |
186 | 0 | if(level >= 4) |
187 | 0 | handlers.debug_callback = debugCallback; |
188 | 0 | if(level >= 5) |
189 | 0 | handlers.trace_callback = traceCallback; |
190 | 0 | } |
191 | 2 | grk_set_msg_handlers(handlers); |
192 | 2 | } |
193 | | |
194 | 2 | initState_ = newState; |
195 | | |
196 | | // 2. try to load plugin |
197 | 2 | if(!initState_.pluginInitialized_) |
198 | 2 | { |
199 | 2 | grk_plugin_load_info info; |
200 | 2 | info.pluginPath = pluginPath; |
201 | 2 | initState_.pluginInitialized_ = grk_plugin_load(info); |
202 | 2 | if(!initState_.pluginInitialized_) |
203 | 2 | return false; |
204 | 0 | else |
205 | 0 | grklog.info("Plugin loaded"); |
206 | 2 | } |
207 | | |
208 | 0 | return true; |
209 | 2 | } |
210 | | |
211 | | GRK_API void GRK_CALLCONV grk_deinitialize() |
212 | 0 | { |
213 | 0 | grk_plugin_cleanup(); |
214 | 0 | ExecSingleton::destroy(); |
215 | 0 | } |
216 | | |
217 | | GRK_API grk_object* GRK_CALLCONV grk_object_ref(grk_object* obj) |
218 | 11.1k | { |
219 | 11.1k | if(!obj) |
220 | 0 | return nullptr; |
221 | 11.1k | auto wrapper = (GrkObjectWrapper*)obj->wrapper; |
222 | 11.1k | wrapper->ref(); |
223 | | |
224 | 11.1k | return obj; |
225 | 11.1k | } |
226 | | GRK_API void GRK_CALLCONV grk_object_unref(grk_object* obj) |
227 | 25.4k | { |
228 | 25.4k | if(!obj) |
229 | 3 | return; |
230 | 25.3k | GrkObjectWrapper* wrapper = (GrkObjectWrapper*)obj->wrapper; |
231 | 25.3k | if(wrapper->unref() == 0) |
232 | 14.2k | delete wrapper; |
233 | 25.3k | } |
234 | | |
235 | | GRK_API void GRK_CALLCONV grk_set_msg_handlers(grk_msg_handlers msg_handlers) |
236 | 2 | { |
237 | 2 | grklog.info_handler = msg_handlers.info_callback; |
238 | 2 | grklog.info_data_ = msg_handlers.info_data; |
239 | 2 | grklog.debug_handler = msg_handlers.debug_callback; |
240 | 2 | grklog.debug_data_ = msg_handlers.debug_data; |
241 | 2 | grklog.trace_handler = msg_handlers.trace_callback; |
242 | 2 | grklog.trace_data_ = msg_handlers.trace_data; |
243 | 2 | grklog.warning_handler = msg_handlers.warn_callback; |
244 | 2 | grklog.warning_data_ = msg_handlers.warn_data; |
245 | 2 | grklog.error_handler = msg_handlers.error_callback; |
246 | 2 | grklog.error_data_ = msg_handlers.error_data; |
247 | 2 | } |
248 | | |
249 | | static size_t grk_read_from_file(uint8_t* buffer, size_t numBytes, void* p_file) |
250 | 0 | { |
251 | 0 | return fread(buffer, 1, numBytes, (FILE*)p_file); |
252 | 0 | } |
253 | | |
254 | | static uint64_t grk_get_data_length_from_file(void* filePtr) |
255 | 0 | { |
256 | 0 | auto file = (FILE*)filePtr; |
257 | 0 | GRK_FSEEK(file, 0, SEEK_END); |
258 | 0 | int64_t file_length = (int64_t)GRK_FTELL(file); |
259 | 0 | GRK_FSEEK(file, 0, SEEK_SET); |
260 | 0 | return (uint64_t)file_length; |
261 | 0 | } |
262 | | static size_t grk_write_to_file(const uint8_t* buffer, size_t numBytes, void* p_file) |
263 | 0 | { |
264 | 0 | return fwrite(buffer, 1, numBytes, (FILE*)p_file); |
265 | 0 | } |
266 | | static bool grk_seek_in_file(uint64_t numBytes, void* p_user_data) |
267 | 0 | { |
268 | 0 | if(numBytes > INT64_MAX) |
269 | 0 | { |
270 | 0 | return false; |
271 | 0 | } |
272 | | |
273 | 0 | return GRK_FSEEK((FILE*)p_user_data, (int64_t)numBytes, SEEK_SET) ? false : true; |
274 | 0 | } |
275 | | |
276 | | #ifdef _WIN32 |
277 | | #ifndef GRK_STATIC |
278 | | BOOL APIENTRY DllMain([[maybe_unused]] HINSTANCE hModule, DWORD ul_reason_for_call, |
279 | | [[maybe_unused]] LPVOID lpReserved) |
280 | | { |
281 | | switch(ul_reason_for_call) |
282 | | { |
283 | | case DLL_PROCESS_ATTACH: |
284 | | break; |
285 | | case DLL_PROCESS_DETACH: |
286 | | break; |
287 | | case DLL_THREAD_ATTACH: |
288 | | case DLL_THREAD_DETACH: |
289 | | break; |
290 | | } |
291 | | return TRUE; |
292 | | } |
293 | | #endif /* GRK_STATIC */ |
294 | | #endif /* _WIN32 */ |
295 | | |
296 | | const char* GRK_CALLCONV grk_version(void) |
297 | 0 | { |
298 | 0 | return GRK_PACKAGE_VERSION; |
299 | 0 | } |
300 | | |
301 | | grk_image* GRK_CALLCONV grk_image_new(uint16_t numcmpts, grk_image_comp* cmptparms, |
302 | | GRK_COLOR_SPACE clrspc, bool alloc_data) |
303 | 0 | { |
304 | 0 | return GrkImage::create(nullptr, numcmpts, cmptparms, clrspc, alloc_data); |
305 | 0 | } |
306 | | |
307 | | grk_image_meta* GRK_CALLCONV grk_image_meta_new(void) |
308 | 752 | { |
309 | 752 | return (grk_image_meta*)(new GrkImageMeta()); |
310 | 752 | } |
311 | | |
312 | | /* DECOMPRESSION FUNCTIONS*/ |
313 | | |
314 | | static const char* JP2_RFC3745_MAGIC = "\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a"; |
315 | | static const char* J2K_CODESTREAM_MAGIC = "\xff\x4f\xff\x51"; |
316 | | bool grk_decompress_buffer_detect_format(uint8_t* buffer, size_t len, GRK_CODEC_FORMAT* fmt) |
317 | 755 | { |
318 | 755 | GRK_CODEC_FORMAT magic_format = GRK_CODEC_UNK; |
319 | 755 | if(len < 12) |
320 | 0 | return false; |
321 | | |
322 | 755 | if(memcmp(buffer, JP2_RFC3745_MAGIC, 12) == 0) |
323 | 164 | { |
324 | 164 | magic_format = GRK_CODEC_JP2; |
325 | 164 | grklog.debug("Detected JP2 image format"); |
326 | 164 | } |
327 | 591 | else if(memcmp(buffer, J2K_CODESTREAM_MAGIC, 4) == 0) |
328 | 588 | { |
329 | 588 | magic_format = GRK_CODEC_J2K; |
330 | 588 | grklog.debug("Detected J2K image format"); |
331 | 588 | } |
332 | 3 | else |
333 | 3 | { |
334 | 3 | grklog.error("No JPEG 2000 code stream detected."); |
335 | 3 | *fmt = GRK_CODEC_UNK; |
336 | | |
337 | 3 | return false; |
338 | 3 | } |
339 | 752 | *fmt = magic_format; |
340 | | |
341 | 752 | return true; |
342 | 755 | } |
343 | | bool GRK_CALLCONV grk_decompress_detect_format(const char* fileName, GRK_CODEC_FORMAT* fmt) |
344 | 0 | { |
345 | 0 | uint8_t buf[12]; |
346 | 0 | size_t bytesRead; |
347 | |
|
348 | 0 | auto reader = fopen(fileName, "rb"); |
349 | 0 | if(!reader) |
350 | 0 | { |
351 | 0 | grklog.error("Unable to open file %s.", fileName); |
352 | 0 | return false; |
353 | 0 | } |
354 | | |
355 | 0 | bytesRead = fread(buf, 1, 12, reader); |
356 | 0 | if(fclose(reader)) |
357 | 0 | { |
358 | 0 | grklog.error("Unable to close file {}.", fileName); |
359 | 0 | return false; |
360 | 0 | } |
361 | 0 | if(bytesRead != 12) |
362 | 0 | { |
363 | 0 | grklog.error("Insufficient bytes to detect JPEG 2000 format in file {}.", fileName); |
364 | 0 | return false; |
365 | 0 | } |
366 | | |
367 | 0 | return grk_decompress_buffer_detect_format(buf, 12, fmt); |
368 | 0 | } |
369 | | |
370 | | static grk_object* grk_decompress_create_from_buffer(uint8_t* buf, size_t len) |
371 | 755 | { |
372 | 755 | auto stream = create_mem_stream(buf, len, false, true); |
373 | 755 | if(!stream) |
374 | 3 | { |
375 | 3 | grklog.error("Unable to create memory stream."); |
376 | 3 | return nullptr; |
377 | 3 | } |
378 | 752 | auto codec = grk_decompress_create(stream); |
379 | 752 | if(!codec) |
380 | 0 | { |
381 | 0 | grklog.error("Unable to create codec"); |
382 | 0 | grk_object_unref(stream); |
383 | 0 | return nullptr; |
384 | 0 | } |
385 | | |
386 | 752 | return codec; |
387 | 752 | } |
388 | | |
389 | | static grk_object* grk_decompress_create_from_callbacks(grk_stream_params* stream_params) |
390 | 0 | { |
391 | 0 | auto stream = grk_stream_create_stream(stream_params); |
392 | 0 | if(!stream) |
393 | 0 | { |
394 | 0 | grklog.error("Unable to create callback stream."); |
395 | 0 | return nullptr; |
396 | 0 | } |
397 | 0 | auto codec = grk_decompress_create(stream); |
398 | 0 | if(!codec) |
399 | 0 | { |
400 | 0 | grklog.error("Unable to create codec"); |
401 | 0 | grk_object_unref(stream); |
402 | 0 | return nullptr; |
403 | 0 | } |
404 | | |
405 | 0 | return codec; |
406 | 0 | } |
407 | | |
408 | | static grk_object* grk_decompress_create_from_file(const char* file_name) |
409 | 0 | { |
410 | 0 | auto stream = grk_stream_create_file_stream(file_name, 1000000, true); |
411 | 0 | if(!stream) |
412 | 0 | { |
413 | 0 | grklog.error("Unable to create stream for file %s.", file_name); |
414 | 0 | return nullptr; |
415 | 0 | } |
416 | 0 | auto codec = grk_decompress_create(stream); |
417 | 0 | if(!codec) |
418 | 0 | { |
419 | 0 | grklog.error("Unable to create codec for file %s", file_name); |
420 | 0 | grk_object_unref(stream); |
421 | 0 | return nullptr; |
422 | 0 | } |
423 | | |
424 | 0 | return codec; |
425 | 0 | } |
426 | | |
427 | | grk_object* GRK_CALLCONV grk_decompress_init(grk_stream_params* stream_params, |
428 | | grk_decompress_parameters* params) |
429 | 755 | { |
430 | 755 | if(!params) |
431 | 0 | { |
432 | 0 | std::cerr << "grk_decompress_init: decompress parameters cannot be null.\n"; |
433 | 0 | return nullptr; |
434 | 0 | } |
435 | 755 | if(!stream_params) |
436 | 0 | { |
437 | 0 | std::cerr << "grk_decompress_init: stream parameters cannot be null" |
438 | 0 | " when creating decompression codec.\n"; |
439 | 0 | return nullptr; |
440 | 0 | } |
441 | 755 | grk_object* codec = nullptr; |
442 | 755 | if(stream_params->file) |
443 | 0 | codec = grk_decompress_create_from_file(stream_params->file); |
444 | 755 | else if(stream_params->buf) |
445 | 755 | codec = grk_decompress_create_from_buffer(stream_params->buf, stream_params->buf_len); |
446 | 0 | else if(stream_params->read_fn) |
447 | 0 | { |
448 | 0 | codec = grk_decompress_create_from_callbacks(stream_params); |
449 | 0 | } |
450 | 755 | if(!codec) |
451 | 3 | return nullptr; |
452 | | |
453 | 752 | auto codecImpl = GrkCodec::getImpl(codec); |
454 | 752 | if(!codecImpl->decompressor_) |
455 | 0 | { |
456 | 0 | grk_object_unref(codec); |
457 | |
|
458 | 0 | return nullptr; |
459 | 0 | } |
460 | 752 | codecImpl->decompressor_->init(¶ms->core); |
461 | | |
462 | 752 | return codec; |
463 | 752 | } |
464 | | bool GRK_CALLCONV grk_decompress_read_header(grk_object* codecWrapper, grk_header_info* header_info) |
465 | 752 | { |
466 | 752 | if(codecWrapper) |
467 | 752 | { |
468 | 752 | auto codec = GrkCodec::getImpl(codecWrapper); |
469 | 752 | if(!codec->decompressor_) |
470 | 0 | return false; |
471 | 752 | bool rc = codec->decompressor_->readHeader(header_info); |
472 | 752 | rc &= codec->decompressor_->preProcess(); |
473 | | |
474 | 752 | return rc; |
475 | 752 | } |
476 | 0 | return false; |
477 | 752 | } |
478 | | bool GRK_CALLCONV grk_decompress_set_window(grk_object* codecWrapper, double start_x, |
479 | | double start_y, double end_x, double end_y) |
480 | 626 | { |
481 | 626 | if(codecWrapper) |
482 | 626 | { |
483 | 626 | auto codec = GrkCodec::getImpl(codecWrapper); |
484 | 626 | return codec->decompressor_ ? codec->decompressor_->setDecompressRegion( |
485 | 626 | grk_rect_double(start_x, start_y, end_x, end_y)) |
486 | 626 | : false; |
487 | 626 | } |
488 | 0 | return false; |
489 | 626 | } |
490 | | bool GRK_CALLCONV grk_decompress(grk_object* codecWrapper, grk_plugin_tile* tile) |
491 | 626 | { |
492 | 626 | if(codecWrapper) |
493 | 626 | { |
494 | 626 | auto codec = GrkCodec::getImpl(codecWrapper); |
495 | 626 | bool rc = codec->decompressor_ ? codec->decompressor_->decompress(tile) : false; |
496 | 626 | rc = rc && (codec->decompressor_ ? codec->decompressor_->postProcess() : false); |
497 | | |
498 | 626 | return rc; |
499 | 626 | } |
500 | 0 | return false; |
501 | 626 | } |
502 | | |
503 | | void GRK_CALLCONV grk_decompress_wait(grk_object* codecWrapper) |
504 | 0 | { |
505 | 0 | (void)codecWrapper; |
506 | 0 | } |
507 | | bool GRK_CALLCONV grk_decompress_tile(grk_object* codecWrapper, uint16_t tile_index) |
508 | 0 | { |
509 | 0 | if(codecWrapper) |
510 | 0 | { |
511 | 0 | auto codec = GrkCodec::getImpl(codecWrapper); |
512 | 0 | bool rc = codec->decompressor_ ? codec->decompressor_->decompressTile(tile_index) : false; |
513 | 0 | rc = rc && (codec->decompressor_ ? codec->decompressor_->postProcess() : false); |
514 | 0 | return rc; |
515 | 0 | } |
516 | 0 | return false; |
517 | 0 | } |
518 | | void GRK_CALLCONV grk_dump_codec(grk_object* codecWrapper, uint32_t info_flag, FILE* output_stream) |
519 | 0 | { |
520 | 0 | assert(codecWrapper); |
521 | 0 | if(codecWrapper) |
522 | 0 | { |
523 | 0 | auto codec = GrkCodec::getImpl(codecWrapper); |
524 | 0 | if(codec->decompressor_) |
525 | 0 | codec->decompressor_->dump(info_flag, output_stream); |
526 | 0 | } |
527 | 0 | } |
528 | | |
529 | | bool grk_set_MCT(grk_cparameters* parameters, const float* pEncodingMatrix, int32_t* p_dc_shift, |
530 | | uint32_t pNbComp) |
531 | 0 | { |
532 | 0 | uint32_t l_matrix_size = pNbComp * pNbComp * (uint32_t)sizeof(float); |
533 | 0 | uint32_t l_dc_shift_size = pNbComp * (uint32_t)sizeof(int32_t); |
534 | 0 | uint32_t l_mct_total_size = l_matrix_size + l_dc_shift_size; |
535 | | |
536 | | /* add MCT capability */ |
537 | 0 | if(GRK_IS_PART2(parameters->rsiz)) |
538 | 0 | { |
539 | 0 | parameters->rsiz |= GRK_EXTENSION_MCT; |
540 | 0 | } |
541 | 0 | else |
542 | 0 | { |
543 | 0 | parameters->rsiz = ((GRK_PROFILE_PART2) | (GRK_EXTENSION_MCT)); |
544 | 0 | } |
545 | 0 | parameters->irreversible = true; |
546 | | |
547 | | /* use array based MCT */ |
548 | 0 | parameters->mct = 2; |
549 | 0 | parameters->mct_data = grk_malloc(l_mct_total_size); |
550 | 0 | if(!parameters->mct_data) |
551 | 0 | { |
552 | 0 | return false; |
553 | 0 | } |
554 | 0 | memcpy(parameters->mct_data, pEncodingMatrix, l_matrix_size); |
555 | 0 | memcpy(((uint8_t*)parameters->mct_data) + l_matrix_size, p_dc_shift, l_dc_shift_size); |
556 | 0 | return true; |
557 | 0 | } |
558 | | grk_image* GRK_CALLCONV grk_decompress_get_tile_image(grk_object* codecWrapper, uint16_t tile_index) |
559 | 0 | { |
560 | 0 | if(!codecWrapper) |
561 | 0 | return nullptr; |
562 | 0 | auto codec = GrkCodec::getImpl(codecWrapper); |
563 | 0 | if(!codec->decompressor_) |
564 | 0 | return nullptr; |
565 | 0 | auto img = codec->decompressor_->getImage(tile_index); |
566 | 0 | if(!img) |
567 | 0 | img = codec->decompressor_->getImage(); |
568 | 0 | return img; |
569 | 0 | } |
570 | | |
571 | | // no-op |
572 | | grk_progression_state GRK_CALLCONV grk_decompress_get_progression_state(grk_object* codec, |
573 | | uint16_t tile_index) |
574 | 0 | { |
575 | 0 | (void)codec; |
576 | 0 | (void)tile_index; |
577 | 0 | return {}; |
578 | 0 | } |
579 | | // no-op |
580 | | bool GRK_CALLCONV grk_decompress_set_progression_state(grk_object* codec, |
581 | | grk_progression_state state) |
582 | 0 | { |
583 | 0 | (void)codec; |
584 | 0 | (void)state; |
585 | 0 | return true; |
586 | 0 | } |
587 | | grk_image* GRK_CALLCONV grk_decompress_get_image(grk_object* codecWrapper) |
588 | 626 | { |
589 | 626 | if(codecWrapper) |
590 | 626 | { |
591 | 626 | auto codec = GrkCodec::getImpl(codecWrapper); |
592 | 626 | return codec->decompressor_ ? codec->decompressor_->getImage() : nullptr; |
593 | 626 | } |
594 | 0 | return nullptr; |
595 | 626 | } |
596 | | |
597 | | /* COMPRESSION FUNCTIONS*/ |
598 | | |
599 | | grk_object* GRK_CALLCONV grk_compress_create(GRK_CODEC_FORMAT p_format, grk_stream* stream) |
600 | 0 | { |
601 | 0 | GrkCodec* codec = nullptr; |
602 | 0 | switch(p_format) |
603 | 0 | { |
604 | 0 | case GRK_CODEC_J2K: |
605 | 0 | codec = new GrkCodec(stream); |
606 | 0 | codec->compressor_ = new CodeStreamCompress(BufferedStream::getImpl(stream)); |
607 | 0 | break; |
608 | 0 | case GRK_CODEC_JP2: |
609 | 0 | codec = new GrkCodec(stream); |
610 | 0 | codec->compressor_ = new FileFormatCompress(BufferedStream::getImpl(stream)); |
611 | 0 | break; |
612 | 0 | default: |
613 | 0 | return nullptr; |
614 | 0 | } |
615 | 0 | return &codec->obj; |
616 | 0 | } |
617 | | void GRK_CALLCONV grk_compress_set_default_params(grk_cparameters* parameters) |
618 | 0 | { |
619 | 0 | if(!parameters) |
620 | 0 | return; |
621 | | |
622 | 0 | memset(parameters, 0, sizeof(grk_cparameters)); |
623 | | /* default coding parameters */ |
624 | 0 | parameters->rsiz = GRK_PROFILE_NONE; |
625 | 0 | parameters->max_comp_size = 0; |
626 | 0 | parameters->numresolution = GRK_DEFAULT_NUMRESOLUTION; |
627 | 0 | parameters->cblockw_init = GRK_COMP_PARAM_DEFAULT_CBLOCKW; |
628 | 0 | parameters->cblockh_init = GRK_COMP_PARAM_DEFAULT_CBLOCKH; |
629 | 0 | parameters->numgbits = 2; |
630 | 0 | parameters->prog_order = GRK_DEFAULT_PROG_ORDER; |
631 | 0 | parameters->roi_compno = -1; /* no ROI */ |
632 | 0 | parameters->subsampling_dx = 1; |
633 | 0 | parameters->subsampling_dy = 1; |
634 | 0 | parameters->enable_tile_part_generation = false; |
635 | 0 | parameters->decod_format = GRK_FMT_UNK; |
636 | 0 | parameters->cod_format = GRK_FMT_UNK; |
637 | 0 | parameters->layer_rate[0] = 0; |
638 | 0 | parameters->numlayers = 0; |
639 | 0 | parameters->allocation_by_rate_distortion = false; |
640 | 0 | parameters->allocation_by_quality = false; |
641 | 0 | parameters->write_plt = false; |
642 | 0 | parameters->write_tlm = false; |
643 | 0 | parameters->device_id = 0; |
644 | 0 | parameters->repeats = 1; |
645 | 0 | } |
646 | | grk_object* GRK_CALLCONV grk_compress_init(grk_stream_params* stream_params, |
647 | | grk_cparameters* parameters, grk_image* image) |
648 | 0 | { |
649 | 0 | if(!parameters || !image) |
650 | 0 | return nullptr; |
651 | 0 | if(parameters->cod_format != GRK_FMT_J2K && parameters->cod_format != GRK_FMT_JP2) |
652 | 0 | { |
653 | 0 | grklog.error("Unknown stream format."); |
654 | 0 | return nullptr; |
655 | 0 | } |
656 | 0 | grk_stream* stream = nullptr; |
657 | 0 | if(stream_params->buf) |
658 | 0 | { |
659 | | // let stream clean up compress buffer |
660 | 0 | stream = create_mem_stream(stream_params->buf, stream_params->buf_len, false, false); |
661 | 0 | } |
662 | 0 | else if(stream_params->file) |
663 | 0 | { |
664 | 0 | stream = grk_stream_create_file_stream(stream_params->file, 1024 * 1024, false); |
665 | 0 | } |
666 | 0 | else if(stream_params->write_fn) |
667 | 0 | { |
668 | 0 | stream = grk_stream_create_stream(stream_params); |
669 | 0 | } |
670 | 0 | if(!stream) |
671 | 0 | { |
672 | 0 | grklog.error("failed to create stream"); |
673 | 0 | return nullptr; |
674 | 0 | } |
675 | | |
676 | 0 | grk_object* codecWrapper = nullptr; |
677 | 0 | switch(parameters->cod_format) |
678 | 0 | { |
679 | 0 | case GRK_FMT_J2K: /* JPEG 2000 code stream */ |
680 | 0 | codecWrapper = grk_compress_create(GRK_CODEC_J2K, stream); |
681 | 0 | break; |
682 | 0 | case GRK_FMT_JP2: /* JPEG 2000 compressed image data */ |
683 | 0 | codecWrapper = grk_compress_create(GRK_CODEC_JP2, stream); |
684 | 0 | break; |
685 | 0 | default: |
686 | 0 | break; |
687 | 0 | } |
688 | | |
689 | 0 | auto codec = GrkCodec::getImpl(codecWrapper); |
690 | 0 | bool rc = codec->compressor_ ? codec->compressor_->init(parameters, (GrkImage*)image) : false; |
691 | 0 | if(rc) |
692 | 0 | { |
693 | 0 | rc = grk_compress_start(codecWrapper); |
694 | 0 | } |
695 | 0 | else |
696 | 0 | { |
697 | 0 | grklog.error("Failed to initialize codec."); |
698 | 0 | grk_object_unref(codecWrapper); |
699 | 0 | codecWrapper = nullptr; |
700 | 0 | } |
701 | |
|
702 | 0 | return rc ? codecWrapper : nullptr; |
703 | 0 | } |
704 | | |
705 | | // no-op |
706 | | bool GRK_CALLCONV grk_decompress_update(grk_decompress_parameters* params, grk_object* codec) |
707 | 0 | { |
708 | 0 | (void)params; |
709 | 0 | (void)codec; |
710 | 0 | return false; |
711 | 0 | } |
712 | | |
713 | | static bool grk_compress_start(grk_object* codecWrapper) |
714 | 0 | { |
715 | 0 | if(codecWrapper) |
716 | 0 | { |
717 | 0 | auto codec = GrkCodec::getImpl(codecWrapper); |
718 | 0 | return codec->compressor_ ? codec->compressor_->start() : false; |
719 | 0 | } |
720 | 0 | return false; |
721 | 0 | } |
722 | | |
723 | | uint64_t GRK_CALLCONV grk_compress(grk_object* codecWrapper, grk_plugin_tile* tile) |
724 | 0 | { |
725 | 0 | if(codecWrapper) |
726 | 0 | { |
727 | 0 | auto codec = GrkCodec::getImpl(codecWrapper); |
728 | 0 | return codec->compressor_ ? codec->compressor_->compress(tile) : 0; |
729 | 0 | } |
730 | 0 | return 0; |
731 | 0 | } |
732 | | static void grkFree_file(void* p_user_data) |
733 | 0 | { |
734 | 0 | if(p_user_data) |
735 | 0 | fclose((FILE*)p_user_data); |
736 | 0 | } |
737 | | |
738 | | static grk_stream* grk_stream_create_stream(grk_stream_params* stream_params) |
739 | 0 | { |
740 | 0 | bool readStream = stream_params->read_fn; |
741 | 0 | size_t doubleBufferLen = 16 * 1024 * 1024; |
742 | 0 | if(stream_params->stream_len) |
743 | 0 | doubleBufferLen = std::min(doubleBufferLen, stream_params->stream_len); |
744 | 0 | auto stream = grk_stream_new(doubleBufferLen, readStream); |
745 | 0 | if(!stream) |
746 | 0 | return nullptr; |
747 | | // validate |
748 | 0 | if(readStream) |
749 | 0 | { |
750 | 0 | auto bstream = BufferedStream::getImpl(stream); |
751 | 0 | uint8_t buf[12]; |
752 | 0 | size_t bytesRead = stream_params->read_fn(buf, 12, stream_params->user_data); |
753 | 0 | if(bytesRead != 12) |
754 | 0 | return nullptr; |
755 | 0 | stream_params->seek_fn(0, stream_params->user_data); |
756 | 0 | GRK_CODEC_FORMAT fmt; |
757 | 0 | if(!grk_decompress_buffer_detect_format(buf, 12, &fmt)) |
758 | 0 | { |
759 | 0 | grklog.error("Unable to detect codec format."); |
760 | 0 | return nullptr; |
761 | 0 | } |
762 | 0 | bstream->setFormat(fmt); |
763 | 0 | } |
764 | | |
765 | 0 | grk_stream_set_user_data(stream, stream_params->user_data, stream_params->free_user_data_fn); |
766 | 0 | if(readStream) |
767 | 0 | grk_stream_set_user_data_length(stream, stream_params->stream_len); |
768 | 0 | grk_stream_set_read_function(stream, stream_params->read_fn); |
769 | 0 | grk_stream_set_write_function(stream, stream_params->write_fn); |
770 | 0 | grk_stream_set_seek_function(stream, stream_params->seek_fn); |
771 | |
|
772 | 0 | return stream; |
773 | 0 | } |
774 | | |
775 | | static grk_stream* grk_stream_create_file_stream(const char* fname, size_t buffer_size, |
776 | | bool is_read_stream) |
777 | 0 | { |
778 | 0 | bool stdin_stdout = !fname || !fname[0]; |
779 | 0 | FILE* file = nullptr; |
780 | 0 | if(stdin_stdout) |
781 | 0 | { |
782 | 0 | file = is_read_stream ? stdin : stdout; |
783 | 0 | } |
784 | 0 | else |
785 | 0 | { |
786 | 0 | const char* mode = (is_read_stream) ? "rb" : "wb"; |
787 | 0 | file = fopen(fname, mode); |
788 | 0 | if(!file) |
789 | 0 | return nullptr; |
790 | 0 | } |
791 | 0 | auto stream = grk_stream_new(buffer_size, is_read_stream); |
792 | 0 | if(!stream) |
793 | 0 | { |
794 | 0 | if(!stdin_stdout) |
795 | 0 | fclose(file); |
796 | 0 | return nullptr; |
797 | 0 | } |
798 | | // validate |
799 | 0 | if(is_read_stream) |
800 | 0 | { |
801 | 0 | uint8_t buf[12]; |
802 | 0 | size_t bytesRead = fread(buf, 1, 12, file); |
803 | 0 | if(bytesRead != 12) |
804 | 0 | return nullptr; |
805 | 0 | rewind(file); |
806 | 0 | auto bstream = BufferedStream::getImpl(stream); |
807 | 0 | GRK_CODEC_FORMAT fmt; |
808 | 0 | if(!grk_decompress_buffer_detect_format(buf, 12, &fmt)) |
809 | 0 | { |
810 | 0 | grklog.error("Unable to detect codec format."); |
811 | 0 | return nullptr; |
812 | 0 | } |
813 | 0 | bstream->setFormat(fmt); |
814 | 0 | } |
815 | | |
816 | 0 | grk_stream_set_user_data(stream, file, stdin_stdout ? nullptr : grkFree_file); |
817 | 0 | if(is_read_stream) |
818 | 0 | grk_stream_set_user_data_length(stream, grk_get_data_length_from_file(file)); |
819 | 0 | grk_stream_set_read_function(stream, grk_read_from_file); |
820 | 0 | grk_stream_set_write_function(stream, grk_write_to_file); |
821 | 0 | grk_stream_set_seek_function(stream, grk_seek_in_file); |
822 | 0 | return stream; |
823 | 0 | } |
824 | | |
825 | | /********************************************************************** |
826 | | Plugin interface implementation |
827 | | ***********************************************************************/ |
828 | | |
829 | | static const char* plugin_get_debug_state_method_name = "plugin_get_debug_state"; |
830 | | static const char* plugin_init_method_name = "plugin_init"; |
831 | | static const char* plugin_encode_method_name = "plugin_encode"; |
832 | | static const char* plugin_batch_encode_method_name = "plugin_batch_encode"; |
833 | | static const char* plugin_stop_batch_encode_method_name = "plugin_stop_batch_encode"; |
834 | | static const char* plugin_wait_for_batch_complete_method_name = "plugin_wait_for_batch_complete"; |
835 | | static const char* plugin_decode_method_name = "plugin_decompress"; |
836 | | static const char* plugin_init_batch_decode_method_name = "plugin_init_batch_decompress"; |
837 | | static const char* plugin_batch_decode_method_name = "plugin_batch_decompress"; |
838 | | static const char* plugin_stop_batch_decode_method_name = "plugin_stop_batch_decompress"; |
839 | | |
840 | | static const char* pathSeparator() |
841 | 0 | { |
842 | | #ifdef _WIN32 |
843 | | return "\\"; |
844 | | #else |
845 | 0 | return "/"; |
846 | 0 | #endif |
847 | 0 | } |
848 | | |
849 | | bool pluginLoaded = false; |
850 | | bool GRK_CALLCONV grk_plugin_load(grk_plugin_load_info info) |
851 | 2 | { |
852 | 2 | if(!info.pluginPath) |
853 | 2 | return false; |
854 | | |
855 | | // form plugin name |
856 | 0 | std::string pluginName = ""; |
857 | 0 | #if !defined(_WIN32) |
858 | 0 | pluginName += "lib"; |
859 | 0 | #endif |
860 | 0 | pluginName += std::string(GROK_PLUGIN_NAME) + "." + minpf_get_dynamic_library_extension(); |
861 | | |
862 | | // form absolute plugin path |
863 | 0 | auto pluginPath = std::string(info.pluginPath) + pathSeparator() + pluginName; |
864 | 0 | int32_t rc = minpf_load_from_path(pluginPath.c_str(), info.verbose, nullptr); |
865 | | |
866 | | // if fails, try local path |
867 | 0 | if(rc) |
868 | 0 | { |
869 | 0 | std::string localPlugin = std::string(".") + pathSeparator() + pluginName; |
870 | 0 | rc = minpf_load_from_path(localPlugin.c_str(), info.verbose, nullptr); |
871 | 0 | } |
872 | 0 | pluginLoaded = !rc; |
873 | 0 | if(!pluginLoaded) |
874 | 0 | minpf_cleanup_plugin_manager(); |
875 | 0 | return pluginLoaded; |
876 | 2 | } |
877 | | uint32_t GRK_CALLCONV grk_plugin_get_debug_state() |
878 | 10.5k | { |
879 | 10.5k | uint32_t rc = GRK_PLUGIN_STATE_NO_DEBUG; |
880 | 10.5k | if(!pluginLoaded) |
881 | 10.5k | return rc; |
882 | 0 | auto mgr = minpf_get_plugin_manager(); |
883 | 0 | if(mgr && mgr->num_libraries > 0) |
884 | 0 | { |
885 | 0 | auto func = (PLUGIN_GET_DEBUG_STATE)minpf_get_symbol(mgr->dynamic_libraries[0], |
886 | 0 | plugin_get_debug_state_method_name); |
887 | 0 | if(func) |
888 | 0 | rc = func(); |
889 | 0 | } |
890 | 0 | return rc; |
891 | 10.5k | } |
892 | | void GRK_CALLCONV grk_plugin_cleanup(void) |
893 | 0 | { |
894 | 0 | minpf_cleanup_plugin_manager(); |
895 | 0 | pluginLoaded = false; |
896 | 0 | } |
897 | | GRK_API bool GRK_CALLCONV grk_plugin_init(grk_plugin_init_info initInfo) |
898 | 0 | { |
899 | 0 | if(!pluginLoaded) |
900 | 0 | return false; |
901 | 0 | auto mgr = minpf_get_plugin_manager(); |
902 | 0 | if(mgr && mgr->num_libraries > 0) |
903 | 0 | { |
904 | 0 | auto func = (PLUGIN_INIT)minpf_get_symbol(mgr->dynamic_libraries[0], plugin_init_method_name); |
905 | 0 | if(func) |
906 | 0 | return func(initInfo); |
907 | 0 | } |
908 | 0 | return false; |
909 | 0 | } |
910 | | |
911 | | /******************* |
912 | | Encode Implementation |
913 | | ********************/ |
914 | | |
915 | | GRK_PLUGIN_COMPRESS_USER_CALLBACK userEncodeCallback = 0; |
916 | | |
917 | | /* wrapper for user's compress callback */ |
918 | | uint64_t grk_plugin_internal_encode_callback(grk_plugin_compress_user_callback_info* info) |
919 | 0 | { |
920 | 0 | uint64_t rc = 0; |
921 | 0 | if(userEncodeCallback) |
922 | 0 | rc = userEncodeCallback(info); |
923 | |
|
924 | 0 | return rc; |
925 | 0 | } |
926 | | int32_t GRK_CALLCONV grk_plugin_compress(grk_cparameters* compress_parameters, |
927 | | GRK_PLUGIN_COMPRESS_USER_CALLBACK callback) |
928 | 0 | { |
929 | 0 | if(!pluginLoaded) |
930 | 0 | return -1; |
931 | 0 | userEncodeCallback = callback; |
932 | 0 | auto mgr = minpf_get_plugin_manager(); |
933 | 0 | if(mgr && mgr->num_libraries > 0) |
934 | 0 | { |
935 | 0 | auto func = |
936 | 0 | (PLUGIN_ENCODE)minpf_get_symbol(mgr->dynamic_libraries[0], plugin_encode_method_name); |
937 | 0 | if(func) |
938 | 0 | return func((grk_cparameters*)compress_parameters, grk_plugin_internal_encode_callback); |
939 | 0 | } |
940 | 0 | return -1; |
941 | 0 | } |
942 | | int32_t GRK_CALLCONV grk_plugin_batch_compress(grk_plugin_compress_batch_info info) |
943 | 0 | { |
944 | 0 | if(!pluginLoaded) |
945 | 0 | return -1; |
946 | 0 | userEncodeCallback = info.callback; |
947 | 0 | auto mgr = minpf_get_plugin_manager(); |
948 | 0 | info.callback = grk_plugin_internal_encode_callback; |
949 | 0 | if(mgr && mgr->num_libraries > 0) |
950 | 0 | { |
951 | 0 | auto func = (PLUGIN_BATCH_ENCODE)minpf_get_symbol(mgr->dynamic_libraries[0], |
952 | 0 | plugin_batch_encode_method_name); |
953 | 0 | if(func) |
954 | 0 | return func(info); |
955 | 0 | } |
956 | 0 | return -1; |
957 | 0 | } |
958 | | |
959 | | PLUGIN_WAIT_FOR_BATCH_COMPLETE funcPluginWaitForBatchComplete = nullptr; |
960 | | GRK_API void GRK_CALLCONV grk_plugin_wait_for_batch_complete(void) |
961 | 0 | { |
962 | 0 | if(!pluginLoaded) |
963 | 0 | return; |
964 | 0 | auto mgr = minpf_get_plugin_manager(); |
965 | 0 | if(mgr && mgr->num_libraries > 0) |
966 | 0 | { |
967 | 0 | if(!funcPluginWaitForBatchComplete) |
968 | 0 | funcPluginWaitForBatchComplete = (PLUGIN_WAIT_FOR_BATCH_COMPLETE)minpf_get_symbol( |
969 | 0 | mgr->dynamic_libraries[0], plugin_wait_for_batch_complete_method_name); |
970 | 0 | if(funcPluginWaitForBatchComplete) |
971 | 0 | funcPluginWaitForBatchComplete(); |
972 | 0 | } |
973 | 0 | } |
974 | | void GRK_CALLCONV grk_plugin_stop_batch_compress(void) |
975 | 0 | { |
976 | 0 | if(!pluginLoaded) |
977 | 0 | return; |
978 | 0 | auto mgr = minpf_get_plugin_manager(); |
979 | 0 | if(mgr && mgr->num_libraries > 0) |
980 | 0 | { |
981 | 0 | auto func = (PLUGIN_STOP_BATCH_ENCODE)minpf_get_symbol(mgr->dynamic_libraries[0], |
982 | 0 | plugin_stop_batch_encode_method_name); |
983 | 0 | if(func) |
984 | 0 | func(); |
985 | 0 | } |
986 | 0 | } |
987 | | |
988 | | /******************* |
989 | | Decompress Implementation |
990 | | ********************/ |
991 | | |
992 | | grk_plugin_decompress_callback decodeCallback = 0; |
993 | | |
994 | | /* wrapper for user's decompress callback */ |
995 | | int32_t grk_plugin_internal_decode_callback(PluginDecodeCallbackInfo* info) |
996 | 0 | { |
997 | 0 | int32_t rc = -1; |
998 | | /* set code block data etc on code object */ |
999 | 0 | grk_plugin_decompress_callback_info grokInfo; |
1000 | 0 | memset(&grokInfo, 0, sizeof(grk_plugin_decompress_callback_info)); |
1001 | 0 | grokInfo.init_decompressors_func = info->init_decompressors_func; |
1002 | 0 | grokInfo.input_file_name = info->inputFile.empty() ? nullptr : info->inputFile.c_str(); |
1003 | 0 | grokInfo.output_file_name = info->outputFile.empty() ? nullptr : info->outputFile.c_str(); |
1004 | 0 | grokInfo.decod_format = info->decod_format; |
1005 | 0 | grokInfo.cod_format = info->cod_format; |
1006 | 0 | grokInfo.decompressor_parameters = info->decompressor_parameters; |
1007 | 0 | grokInfo.codec = info->codec; |
1008 | 0 | grokInfo.image = info->image; |
1009 | 0 | grokInfo.plugin_owns_image = info->plugin_owns_image; |
1010 | 0 | grokInfo.tile = info->tile; |
1011 | 0 | grokInfo.decompress_flags = info->decompress_flags; |
1012 | 0 | grokInfo.user_data = info->decompressor_parameters->user_data; |
1013 | 0 | if(decodeCallback) |
1014 | 0 | rc = decodeCallback(&grokInfo); |
1015 | | // synch |
1016 | 0 | info->image = grokInfo.image; |
1017 | 0 | info->codec = grokInfo.codec; |
1018 | 0 | info->header_info = grokInfo.header_info; |
1019 | 0 | return rc; |
1020 | 0 | } |
1021 | | |
1022 | | int32_t GRK_CALLCONV grk_plugin_decompress(grk_decompress_parameters* decompress_parameters, |
1023 | | grk_plugin_decompress_callback callback) |
1024 | 0 | { |
1025 | 0 | if(!pluginLoaded) |
1026 | 0 | return -1; |
1027 | 0 | decodeCallback = callback; |
1028 | 0 | auto mgr = minpf_get_plugin_manager(); |
1029 | 0 | if(mgr && mgr->num_libraries > 0) |
1030 | 0 | { |
1031 | 0 | auto func = |
1032 | 0 | (PLUGIN_DECODE)minpf_get_symbol(mgr->dynamic_libraries[0], plugin_decode_method_name); |
1033 | 0 | if(func) |
1034 | 0 | return func((grk_decompress_parameters*)decompress_parameters, |
1035 | 0 | grk_plugin_internal_decode_callback); |
1036 | 0 | } |
1037 | 0 | return -1; |
1038 | 0 | } |
1039 | | int32_t GRK_CALLCONV grk_plugin_init_batch_decompress( |
1040 | | const char* input_dir, const char* output_dir, grk_decompress_parameters* decompress_parameters, |
1041 | | grk_plugin_decompress_callback callback) |
1042 | 0 | { |
1043 | 0 | if(!pluginLoaded) |
1044 | 0 | return -1; |
1045 | 0 | decodeCallback = callback; |
1046 | 0 | auto mgr = minpf_get_plugin_manager(); |
1047 | 0 | if(mgr && mgr->num_libraries > 0) |
1048 | 0 | { |
1049 | 0 | auto func = (PLUGIN_INIT_BATCH_DECODE)minpf_get_symbol(mgr->dynamic_libraries[0], |
1050 | 0 | plugin_init_batch_decode_method_name); |
1051 | 0 | if(func) |
1052 | 0 | return func(input_dir, output_dir, (grk_decompress_parameters*)decompress_parameters, |
1053 | 0 | grk_plugin_internal_decode_callback); |
1054 | 0 | } |
1055 | 0 | return -1; |
1056 | 0 | } |
1057 | | int32_t GRK_CALLCONV grk_plugin_batch_decompress(void) |
1058 | 0 | { |
1059 | 0 | if(!pluginLoaded) |
1060 | 0 | return -1; |
1061 | 0 | auto mgr = minpf_get_plugin_manager(); |
1062 | 0 | if(mgr && mgr->num_libraries > 0) |
1063 | 0 | { |
1064 | 0 | auto func = (PLUGIN_BATCH_DECODE)minpf_get_symbol(mgr->dynamic_libraries[0], |
1065 | 0 | plugin_batch_decode_method_name); |
1066 | 0 | if(func) |
1067 | 0 | return func(); |
1068 | 0 | } |
1069 | 0 | return -1; |
1070 | 0 | } |
1071 | | void GRK_CALLCONV grk_plugin_stop_batch_decompress(void) |
1072 | 0 | { |
1073 | 0 | if(!pluginLoaded) |
1074 | 0 | return; |
1075 | 0 | auto mgr = minpf_get_plugin_manager(); |
1076 | 0 | if(mgr && mgr->num_libraries > 0) |
1077 | 0 | { |
1078 | 0 | auto func = (PLUGIN_STOP_BATCH_DECODE)minpf_get_symbol(mgr->dynamic_libraries[0], |
1079 | 0 | plugin_stop_batch_decode_method_name); |
1080 | 0 | if(func) |
1081 | 0 | func(); |
1082 | 0 | } |
1083 | 0 | } |
1084 | | |
1085 | | void grk_stream_set_read_function(grk_stream* stream, grk_stream_read_fn func) |
1086 | 752 | { |
1087 | 752 | auto streamImpl = BufferedStream::getImpl(stream); |
1088 | 752 | if((!streamImpl) || (!(streamImpl->getStatus() & GROK_STREAM_STATUS_INPUT))) |
1089 | 0 | return; |
1090 | 752 | streamImpl->setReadFunction(func); |
1091 | 752 | } |
1092 | | |
1093 | | void grk_stream_set_seek_function(grk_stream* stream, grk_stream_seek_fn func) |
1094 | 752 | { |
1095 | 752 | auto streamImpl = BufferedStream::getImpl(stream); |
1096 | 752 | if(streamImpl) |
1097 | 752 | streamImpl->setSeekFunction(func); |
1098 | 752 | } |
1099 | | void grk_stream_set_write_function(grk_stream* stream, grk_stream_write_fn func) |
1100 | 0 | { |
1101 | 0 | auto streamImpl = BufferedStream::getImpl(stream); |
1102 | 0 | if((!streamImpl) || (!(streamImpl->getStatus() & GROK_STREAM_STATUS_OUTPUT))) |
1103 | 0 | return; |
1104 | | |
1105 | 0 | streamImpl->setWriteFunction(func); |
1106 | 0 | } |
1107 | | |
1108 | | void grk_stream_set_user_data(grk_stream* stream, void* p_data, grk_stream_free_user_data_fn func) |
1109 | 752 | { |
1110 | 752 | auto streamImpl = BufferedStream::getImpl(stream); |
1111 | 752 | if(!streamImpl) |
1112 | 0 | return; |
1113 | 752 | streamImpl->setUserData(p_data, func); |
1114 | 752 | } |
1115 | | void grk_stream_set_user_data_length(grk_stream* stream, uint64_t data_length) |
1116 | 752 | { |
1117 | 752 | auto streamImpl = BufferedStream::getImpl(stream); |
1118 | 752 | if(streamImpl) |
1119 | 752 | streamImpl->setUserDataLength(data_length); |
1120 | 752 | } |