Skip to content

Commit ac03acb

Browse files
author
Grok Compression
committed
compression: buffered write stream was not being created
1 parent 652fd2d commit ac03acb

File tree

4 files changed

+136
-52
lines changed

4 files changed

+136
-52
lines changed

.vscode/launch.json

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,38 @@
169169
],
170170
"MIMode": "gdb",
171171
"miDebuggerPath": "/usr/bin/gdb"
172-
},
172+
},
173+
{
174+
"name": "core compress",
175+
"type": "cppdbg",
176+
"request": "launch",
177+
"program": "${workspaceFolder}/build/bin/core_compress",
178+
"args": [],
179+
"environment": [
180+
{ "name": "GRK_DEBUG", "value": "3" }
181+
],
182+
"cwd": "${workspaceFolder}",
183+
"MIMode": "gdb",
184+
"miDebuggerPath": "/usr/bin/gdb"
185+
},
186+
{
187+
"name": "encode TIFF",
188+
"type": "cppdbg",
189+
"request": "launch",
190+
"program": "${workspaceFolder}/build/bin/grk_compress",
191+
"args": [
192+
"-i",
193+
"$HOME/temp/test.tif",
194+
"-o",
195+
"$HOME/temp/test.tif.jp2",
196+
],
197+
"environment": [
198+
{ "name": "GRK_DEBUG", "value": "3" }
199+
],
200+
"cwd": "${workspaceFolder}",
201+
"MIMode": "gdb",
202+
"miDebuggerPath": "/usr/bin/gdb"
203+
},
173204
{
174205
"name": "test",
175206
"type": "cppdbg",
@@ -407,6 +438,28 @@
407438
"miDebuggerPath": "/usr/bin/gdb"
408439
},
409440
{
441+
"name": "Pleiades KDU",
442+
"type": "cppdbg",
443+
"request": "launch",
444+
"program": "/usr/bin/time",
445+
"args": [
446+
"-v",
447+
"$HOME/src/gorgon/gorgon/bin/Linux-x86-64-gcc/kdu_expand",
448+
"-i",
449+
"$HOME/temp/IMG_PHR1B_P_202406071720183_SEN_7038440101-1_R1C1.JP2",
450+
"-region",
451+
"\"{0.00000000000000000,0.00000000000000000},{0.10101109741060420,0.09905204101373573}\"",
452+
"-o",
453+
"/tmp/pleiades.tif"
454+
],
455+
"cwd": "${workspaceFolder}",
456+
"environment": [
457+
{ "name": "GRK_DEBUG", "value": "3" },
458+
],
459+
"MIMode": "gdb",
460+
"miDebuggerPath": "/usr/bin/gdb"
461+
},
462+
{
410463
"name": "Pleiades",
411464
"type": "cppdbg",
412465
"request": "launch",
@@ -416,10 +469,12 @@
416469
"${workspaceFolder}/build/bin/core_decompress",
417470
"-i",
418471
"$HOME/temp/IMG_PHR1B_P_202406071720183_SEN_7038440101-1_R1C1.JP2",
472+
"-d 0,0,2048,2048",
419473
],
420474
"cwd": "${workspaceFolder}",
421475
"environment": [
422476
{ "name": "GRK_DEBUG", "value": "3" },
477+
{ "name": "GRK_WINDOWED_SCHEDULING", "value": "1" }
423478
],
424479
"MIMode": "gdb",
425480
"miDebuggerPath": "/usr/bin/gdb"
@@ -705,9 +760,14 @@
705760
"program": "${workspaceFolder}/build/bin/grk_decompress",
706761
"args": [
707762
"-i",
708-
"$HOME/Downloads/clusterfuzz-testcase-minimized-grk_decompress_fuzzer-6466697174843392",
763+
"$HOME/temp/clusterfuzz-testcase-minimized-grk_decompress_fuzzer-4734814600364032",
764+
"-d 0,0,1024,1024",
709765
"-o",
710-
"$HOME/temp/fuzzer.tif"
766+
"$HOME/temp/fuzz.tif"
767+
768+
],
769+
"environment": [
770+
{ "name": "GRK_DEBUG", "value": "3" },
711771
],
712772
"cwd": "${workspaceFolder}",
713773
"MIMode": "gdb",

examples/core/core_compress.cpp

Lines changed: 67 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,22 @@
1414
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1515
*
1616
*/
17-
1817
#include <cstdio>
1918
#include <cstring>
2019
#include <memory>
2120
#include <inttypes.h>
2221

2322
#include "grok.h"
24-
2523
#include "core.h"
2624

27-
struct WriteStreamInfo
25+
/**
26+
* @struct WriteCallbackInfo
27+
* @brief used by write callbacks to get information about stream
28+
*
29+
*/
30+
struct WriteCallbackInfo
2831
{
29-
explicit WriteStreamInfo(grk_stream_params* streamParams)
32+
explicit WriteCallbackInfo(grk_stream_params* streamParams)
3033
: streamParams_(streamParams), data_(nullptr), dataLen_(0), offset_(0)
3134
{}
3235
grk_stream_params* streamParams_;
@@ -35,17 +38,33 @@ struct WriteStreamInfo
3538
size_t offset_;
3639
};
3740

41+
/**
42+
* @brief stream write callback
43+
*
44+
* @param buffer //buffer of data to write
45+
* @param numBytes // number of bytes to write
46+
* @param user_data // user data
47+
* @return size_t // number of bytes written
48+
*/
3849
size_t stream_write_fn(const uint8_t* buffer, size_t numBytes, void* user_data)
3950
{
40-
auto sinfo = (WriteStreamInfo*)user_data;
51+
auto sinfo = (WriteCallbackInfo*)user_data;
4152
if(sinfo->offset_ + numBytes <= sinfo->dataLen_)
4253
memcpy(sinfo->data_ + sinfo->offset_, buffer, numBytes);
4354

4455
return numBytes;
4556
}
57+
58+
/**
59+
* @brief stream seek callback
60+
*
61+
* @param offset //offset to seek to
62+
* @param user_data // user dat
63+
* @return true if seek successful, otherwise false
64+
*/
4665
bool stream_seek_fn(uint64_t offset, void* user_data)
4766
{
48-
auto sinfo = (WriteStreamInfo*)user_data;
67+
auto sinfo = (WriteCallbackInfo*)user_data;
4968
if(offset <= sinfo->dataLen_)
5069
sinfo->offset_ = offset;
5170
else
@@ -62,52 +81,58 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] const char** argv)
6281
const uint32_t precision = 8;
6382
const char* outFile = "test.jp2";
6483

84+
grk_object* codec = nullptr;
85+
grk_image* inputImage = nullptr;
86+
int32_t rc = EXIT_FAILURE;
87+
6588
uint64_t compressedLength = 0;
6689

67-
// initialize compress parameters
90+
// 1. initialize library
91+
grk_initialize(nullptr, 0);
92+
93+
// 2. initialize compress parameters
6894
grk_cparameters compressParams;
6995
grk_compress_set_default_params(&compressParams);
7096
compressParams.cod_format = GRK_FMT_JP2;
7197
compressParams.verbose = true;
7298

73-
grk_object* codec = nullptr;
74-
grk_image* image = nullptr;
75-
int32_t rc = EXIT_FAILURE;
76-
77-
bool outputToBuffer = false;
78-
bool useCallbacks = true;
79-
80-
// initialize library
81-
grk_initialize(nullptr, 0);
99+
// 3.initialize output stream
100+
enum eStreamOutput
101+
{
102+
STREAM_OUTPUT_BUFFER, // output to buffer
103+
STREAM_OUTPUT_CALLBACK, // output using user-defined callback
104+
STREAM_OUTPUT_FILE // output to file
105+
};
106+
eStreamOutput output = STREAM_OUTPUT_BUFFER;
82107

83-
grk_stream_params streamParams = {};
84-
WriteStreamInfo sinfo(&streamParams);
108+
grk_stream_params outputStreamParams = {};
109+
WriteCallbackInfo writeCallbackInfo(&outputStreamParams);
85110

86111
std::unique_ptr<uint8_t[]> data;
87112
size_t bufLen = (size_t)numComps * ((precision + 7) / 8) * dimX * dimY;
88-
if(useCallbacks || outputToBuffer)
113+
if(output != STREAM_OUTPUT_FILE)
89114
{
90115
data = std::make_unique<uint8_t[]>(bufLen);
91116
}
92-
if(useCallbacks)
117+
if(output == STREAM_OUTPUT_CALLBACK)
93118
{
94-
streamParams.seek_fn = stream_seek_fn;
95-
streamParams.write_fn = stream_write_fn;
96-
streamParams.user_data = &sinfo;
97-
sinfo.data_ = data.get();
98-
sinfo.dataLen_ = bufLen;
119+
outputStreamParams.seek_fn = stream_seek_fn;
120+
outputStreamParams.write_fn = stream_write_fn;
121+
outputStreamParams.user_data = &writeCallbackInfo;
122+
writeCallbackInfo.data_ = data.get();
123+
writeCallbackInfo.dataLen_ = bufLen;
99124
}
100-
else if(outputToBuffer)
125+
else if(output == STREAM_OUTPUT_BUFFER)
101126
{
102-
streamParams.buf = data.get();
103-
streamParams.buf_len = bufLen;
127+
outputStreamParams.buf = data.get();
128+
outputStreamParams.buf_len = bufLen;
104129
}
105130
else
106131
{
107-
safe_strcpy(streamParams.file, outFile);
132+
safe_strcpy(outputStreamParams.file, outFile);
108133
}
109134

110-
// create blank image
135+
// 4. create input image (blank)
111136
auto components = std::make_unique<grk_image_comp[]>(numComps);
112137
for(uint32_t i = 0; i < numComps; ++i)
113138
{
@@ -119,13 +144,12 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] const char** argv)
119144
c->prec = precision;
120145
c->sgnd = false;
121146
}
122-
image = grk_image_new(numComps, components.get(), GRK_CLRSPC_SRGB, true);
147+
inputImage = grk_image_new(numComps, components.get(), GRK_CLRSPC_SRGB, true);
123148

124-
// fill in component data
125-
// see grok.h header for full details of image structure
126-
for(uint16_t compno = 0; compno < image->numcomps; ++compno)
149+
// fill in component data: see grok.h header for full details of image structure
150+
for(uint16_t compno = 0; compno < inputImage->numcomps; ++compno)
127151
{
128-
auto comp = image->comps + compno;
152+
auto comp = inputImage->comps + compno;
129153
auto compWidth = comp->w;
130154
auto compHeight = comp->h;
131155
auto compData = (int32_t*)comp->data;
@@ -148,26 +172,25 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] const char** argv)
148172
delete[] srcData;
149173
}
150174

151-
// initialize compressor
152-
codec = grk_compress_init(&streamParams, &compressParams, image);
175+
// 5. initialize compressor
176+
codec = grk_compress_init(&outputStreamParams, &compressParams, inputImage);
153177
if(!codec)
154178
{
155179
fprintf(stderr, "Failed to initialize compressor\n");
156180
goto beach;
157181
}
158182

159-
// compress
183+
// 6. compress
160184
compressedLength = grk_compress(codec, nullptr);
161185
if(compressedLength == 0)
162186
{
163187
fprintf(stderr, "Failed to compress\n");
164188
goto beach;
165189
}
166-
167190
printf("Compression succeeded: %" PRIu64 " bytes used.\n", compressedLength);
168191

169-
// write buffer to file
170-
if(outputToBuffer)
192+
// 7. write buffer to file if needed
193+
if(output == STREAM_OUTPUT_FILE)
171194
{
172195
auto fp = fopen(outFile, "wb");
173196
if(!fp)
@@ -176,7 +199,7 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] const char** argv)
176199
}
177200
else
178201
{
179-
size_t written = fwrite(streamParams.buf, 1, compressedLength, fp);
202+
size_t written = fwrite(outputStreamParams.buf, 1, compressedLength, fp);
180203
if(written != compressedLength)
181204
{
182205
fprintf(stderr, "Buffer compress: only %" PRIu64 " bytes written out of %" PRIu64 " total",
@@ -188,9 +211,10 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] const char** argv)
188211

189212
rc = EXIT_SUCCESS;
190213
beach:
214+
191215
// cleanup
192216
grk_object_unref(codec);
193-
grk_object_unref(&image->obj);
217+
grk_object_unref(&inputImage->obj);
194218
grk_deinitialize();
195219

196220
return rc;

src/lib/core/grok.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -556,15 +556,15 @@ typedef struct _grk_stream_params
556556
size_t initial_double_buffer_len; /* choose a larger initial length
557557
to read the main header in one go */
558558
bool from_network; /* indicates stream source is on network if true */
559-
bool is_read_stream;
559+
bool is_read_stream; /* true if read stream, otherwise false */
560560

561561
/* 1. File Streaming */
562562
char file[GRK_PATH_LEN];
563563
bool use_stdio; /* use C file api - if false then use memory mapping */
564564

565565
/* 2. Buffer Streaming */
566-
uint8_t* buf;
567-
size_t buf_len; /* buffer length */
566+
uint8_t* buf; /* data buffer */
567+
size_t buf_len; /* data buffer length */
568568
size_t buf_compressed_len; /* length of compressed stream (set by compressor, not client) */
569569

570570
/* 3. Callback Streaming */

src/lib/core/stream/StreamGenerator.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class StreamGenerator
7878
{
7979
if(streamParams_.buf && streamParams_.buf_len)
8080
{
81-
return createBufferReadStream();
81+
return createBufferStream(streamParams_.is_read_stream);
8282
}
8383

8484
if(streamParams_.read_fn || streamParams_.write_fn)
@@ -125,10 +125,10 @@ class StreamGenerator
125125

126126
IStream* createCallbackStream(void);
127127

128-
IStream* createBufferReadStream(void)
128+
IStream* createBufferStream(bool isReadStream)
129129
{
130130
auto stream = memStreamCreate(streamParams_.buf, streamParams_.buf_len, false, nullptr,
131-
GRK_CODEC_FORMAT::GRK_CODEC_UNK, true);
131+
GRK_CODEC_FORMAT::GRK_CODEC_UNK, isReadStream);
132132
if(!stream)
133133
{
134134
grklog.error("Unable to create memory stream.");

0 commit comments

Comments
 (0)