-
Notifications
You must be signed in to change notification settings - Fork 54
08. Async Decompression API
Grok provides an asynchronous decompression API that enables swath-based tile retrieval. This is the pattern used by the GDAL JP2Grok driver for efficient random-access decoding of large tiled images.
The async API separates the decompression start from result retrieval:
-
Start async decompression with
grk_decompress()(called once) -
Wait for specific swath regions with
grk_decompress_wait() -
Retrieve per-tile decoded data with
grk_decompress_get_tile_image() - For subsequent swaths, only call
grk_decompress_wait()(no restart needed)
This is particularly efficient for:
- Large tiled images where only a portion is needed
- Cloud-hosted images where tiles arrive incrementally
- Applications that need to process rows/strips progressively
Enable async mode by setting these fields in grk_decompress_parameters:
grk_decompress_parameters params = {};
params.asynchronous = true;
params.simulate_synchronous = true;
params.core.tile_cache_strategy = GRK_TILE_CACHE_IMAGE;
params.core.skip_allocate_composite = true; // For multi-tile imagesgrk_object* grk_decompress_init(grk_stream_params* stream_params,
grk_decompress_parameters* params);Initialize the decompressor with stream and parameter configuration.
bool grk_decompress_read_header(grk_object* codec, grk_header_info* header_info);Read the JPEG 2000 header. Populates header_info with image dimensions,
tile grid, number of layers, resolutions, etc.
bool grk_decompress_update(grk_decompress_parameters* params, grk_object* codec);Update decompression parameters after header read (e.g., apply reduce factor, change tile cache strategy).
bool grk_decompress(grk_object* codec, grk_plugin_tile* tile);Start decompression. In async mode, this returns immediately and tiles are
decoded in background threads. Pass NULL for the tile parameter.
void grk_decompress_wait(grk_object* codec, grk_wait_swath* swath);Wait for decompression to complete.
- If
swathis non-null: waits for all tiles covering the swath region, then populatesswath->tile_x0/y0/x1/y1andswath->num_tile_colswith the tile grid indices covering the requested region. - If
swathis null: waits for the entire decompression to complete.
grk_image* grk_decompress_get_tile_image(grk_object* codec, uint16_t tile_index, bool wait);Get decoded image data for a specific tile. The tile index is computed as:
tile_index = tile_y * num_tile_cols + tile_x
Use the output fields from grk_wait_swath to compute tile indices.
Set wait=true to block until the tile is ready.
typedef struct grk_wait_swath {
uint32_t x0; // Input: top-left x (pixels)
uint32_t y0; // Input: top-left y (pixels)
uint32_t x1; // Input: bottom-right x (exclusive)
uint32_t y1; // Input: bottom-right y (exclusive)
uint16_t tile_x0; // Output: tile column start (inclusive)
uint16_t tile_y0; // Output: tile row start (inclusive)
uint16_t tile_x1; // Output: tile column end (exclusive)
uint16_t tile_y1; // Output: tile row end (exclusive)
uint16_t num_tile_cols; // Output: total tile columns in image
} grk_wait_swath;#include "grok.h"
// Initialize
grk_initialize(NULL, 0, NULL);
grk_decompress_parameters params = {};
params.asynchronous = true;
params.simulate_synchronous = true;
params.core.tile_cache_strategy = GRK_TILE_CACHE_IMAGE;
params.core.skip_allocate_composite = true;
grk_stream_params stream = {};
safe_strcpy(stream.file, "image.jp2");
grk_object* codec = grk_decompress_init(&stream, ¶ms);
grk_header_info header = {};
grk_decompress_read_header(codec, &header);
grk_decompress_update(¶ms, codec);
// Start async decompression
grk_decompress(codec, NULL);
// Process in swaths
uint32_t swathHeight = header.t_height;
for (uint32_t y = 0; y < header.header_image.y1; y += swathHeight) {
grk_wait_swath swath = {};
swath.x0 = 0;
swath.y0 = y;
swath.x1 = header.header_image.x1;
swath.y1 = min(y + swathHeight, header.header_image.y1);
grk_decompress_wait(codec, &swath);
// Retrieve tiles in this swath
for (uint16_t ty = swath.tile_y0; ty < swath.tile_y1; ++ty) {
for (uint16_t tx = swath.tile_x0; tx < swath.tile_x1; ++tx) {
uint16_t idx = ty * swath.num_tile_cols + tx;
grk_image* tile = grk_decompress_get_tile_image(codec, idx, true);
// Process tile->comps[c].data ...
}
}
}
// Cleanup
grk_object_unref(codec);
grk_deinitialize();A full working example is available in examples/core/core_decompress_async.cpp.
| Constant | Value | Description |
|---|---|---|
GRK_TILE_CACHE_NONE |
0 | No tile caching |
GRK_TILE_CACHE_IMAGE |
1 | Cache final tile image (recommended for async) |
GRK_TILE_CACHE_ALL |
2 | Cache everything |
For efficient random access into large tiled images, use PLT/TLM markers during
compression (-L and -X flags in grk_compress). During decompression, these
markers can be selectively disabled with the -m flag:
| Flag | Value | Marker |
|---|---|---|
GRK_RANDOM_ACCESS_PLT |
1 | PLT (Packet Length in Tile-part) |
GRK_RANDOM_ACCESS_TLM |
2 | TLM (Tile-part Length in Main header) |
GRK_RANDOM_ACCESS_PLM |
4 | PLM (Packet Length in Main header) |