// Find the block boundary for each discard level in the input image. // We parse the input blocks and copy them in a temporary output stream. // For the moment, we do nothing more that parsing the raw list of blocks and outputing result. void LLImageJ2CKDU::findDiscardLevelsBoundaries(LLImageJ2C &base) { // We need the number of levels in that image before starting. getMetadata(base); for (int discard_level = 0; discard_level < mLevels; discard_level++) { //std::cout << "Parsing discard level = " << discard_level << std::endl; // Create the input codestream object. setupCodeStream(base, TRUE, MODE_FAST); mCodeStreamp->apply_input_restrictions(0, 4, discard_level, 0, NULL); mCodeStreamp->set_max_bytes(KDU_LONG_MAX,true); siz_params *siz_in = mCodeStreamp->access_siz(); // Create the output codestream object. siz_params siz; siz.copy_from(siz_in,-1,-1,-1,0,discard_level,false,false,false); siz.set(Scomponents,0,0,mCodeStreamp->get_num_components()); U32 max_output_size = base.getWidth()*base.getHeight()*base.getComponents(); max_output_size = (max_output_size < 1000 ? 1000 : max_output_size); U8 *output_buffer = new U8[max_output_size]; U32 output_size = 0; // Address updated by LLKDUMemTarget to give the final compressed buffer size LLKDUMemTarget output(output_buffer, output_size, max_output_size); kdu_codestream codestream_out; codestream_out.create(&siz,&output); //codestream_out.share_buffering(*mCodeStreamp); siz_params *siz_out = codestream_out.access_siz(); siz_out->copy_from(siz_in,-1,-1,-1,0,discard_level,false,false,false); codestream_out.access_siz()->finalize_all(-1); // Set up rate control variables kdu_long max_bytes = KDU_LONG_MAX; kdu_params *cod = siz_out->access_cluster(COD_params); int total_layers; cod->get(Clayers,0,0,total_layers); kdu_long *layer_bytes = new kdu_long[total_layers]; int nel, non_empty_layers = 0; // Now ready to perform the transfer of compressed data between streams int flush_counter = INT_MAX; kdu_dims tile_indices_in; mCodeStreamp->get_valid_tiles(tile_indices_in); kdu_dims tile_indices_out; codestream_out.get_valid_tiles(tile_indices_out); assert((tile_indices_in.size.x == tile_indices_out.size.x) && (tile_indices_in.size.y == tile_indices_out.size.y)); int num_blocks=0; kdu_coords idx; //std::cout << "Parsing tiles : x = " << tile_indices_out.size.x << " to y = " << tile_indices_out.size.y << std::endl; for (idx.y=0; idx.y < tile_indices_out.size.y; idx.y++) { for (idx.x=0; idx.x < tile_indices_out.size.x; idx.x++) { kdu_tile tile_in = mCodeStreamp->open_tile(idx+tile_indices_in.pos); int tnum_in = tile_in.get_tnum(); int tnum_out = idx.x + idx.y*tile_indices_out.size.x; siz_out->copy_from(siz_in,tnum_in,tnum_out,0,0,discard_level,false,false,false); siz_out->finalize_all(tnum_out); // Note: do not open the output tile without first copying any tile-specific code-stream parameters kdu_tile tile_out = codestream_out.open_tile(idx+tile_indices_out.pos); assert(tnum_out == tile_out.get_tnum()); copy_tile(tile_in,tile_out,tnum_in,tnum_out,siz_in,siz_out,0,num_blocks); tile_in.close(); tile_out.close(); flush_counter--; if ((flush_counter <= 0) && codestream_out.ready_for_flush()) { flush_counter = INT_MAX; nel = codestream_out.trans_out(max_bytes,layer_bytes,total_layers); non_empty_layers = (nel > non_empty_layers)?nel:non_empty_layers; } } } // Generate the output code-stream if (codestream_out.ready_for_flush()) { nel = codestream_out.trans_out(max_bytes,layer_bytes,total_layers); non_empty_layers = (nel > non_empty_layers)?nel:non_empty_layers; } if (non_empty_layers > total_layers) non_empty_layers = total_layers; // Can happen if a tile has more layers // Print out stats std::cout << "Code stream parsing for discard level = " << discard_level << std::endl; std::cout << " Total compressed memory in = " << mCodeStreamp->get_compressed_data_memory() << " bytes" << std::endl; std::cout << " Total compressed memory out = " << codestream_out.get_compressed_data_memory() << " bytes" << std::endl; //std::cout << " Output contains " << total_layers << " quality layers" << std::endl; std::cout << " Transferred " << num_blocks << " code-blocks from in to out" << std::endl; //std::cout << " Read " << mCodeStreamp->get_num_tparts() << " tile-part(s) from a total of " << (int) tile_indices_in.area() << " tile(s)" << std::endl; std::cout << " Total bytes read = " << mCodeStreamp->get_total_bytes() << std::endl; //std::cout << " Wrote " << codestream_out.get_num_tparts() << " tile-part(s) in a total of " << (int) tile_indices_out.area() << " tile(s)" << std::endl; std::cout << " Total bytes written = " << codestream_out.get_total_bytes() << std::endl; std::cout << "-------------" << std::endl; // Clean-up cleanupCodeStream(); codestream_out.destroy(); delete[] output_buffer; } return; }
// Returns TRUE to mean done, whether successful or not. BOOL LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) { ECodeStreamMode mode = MODE_FAST; LLTimer decode_timer; if (!mCodeStreamp) { if (!initDecode(base, raw_image, decode_time, mode, first_channel, max_channel_count)) { // Initializing the J2C decode failed, bail out. cleanupCodeStream(); return TRUE; // done } } // These can probably be grabbed from what's saved in the class. kdu_dims dims; mCodeStreamp->get_dims(0,dims); // Now we are ready to walk through the tiles processing them one-by-one. kdu_byte *buffer = raw_image.getData(); while (mTPosp->y < mTileIndicesp->size.y) { while (mTPosp->x < mTileIndicesp->size.x) { try { if (!mDecodeState) { kdu_tile tile = mCodeStreamp->open_tile(*(mTPosp)+mTileIndicesp->pos); // Find the region of the buffer occupied by this // tile. Note that we have no control over // sub-sampling factors which might have been used // during compression and so it can happen that tiles // (at the image component level) actually have // different dimensions. For this reason, we cannot // figure out the buffer region occupied by a tile // directly from the tile indices. Instead, we query // the highest resolution of the first tile-component // concerning its location and size on the canvas -- // the `dims' object already holds the location and // size of the entire image component on the same // canvas coordinate system. Comparing the two tells // us where the current tile is in the buffer. S32 channels = base.getComponents() - first_channel; if (channels > max_channel_count) { channels = max_channel_count; } kdu_resolution res = tile.access_component(0).access_resolution(); kdu_dims tile_dims; res.get_dims(tile_dims); kdu_coords offset = tile_dims.pos - dims.pos; int row_gap = channels*dims.size.x; // inter-row separation kdu_byte *buf = buffer + offset.y*row_gap + offset.x*channels; mDecodeState = new LLKDUDecodeState(tile, buf, row_gap); } // Do the actual processing F32 remaining_time = decode_time - decode_timer.getElapsedTimeF32(); // This is where we do the actual decode. If we run out of time, return false. if (mDecodeState->processTileDecode(remaining_time, (decode_time > 0.0f))) { delete mDecodeState; mDecodeState = NULL; } else { // Not finished decoding yet. // setLastError("Ran out of time while decoding"); return FALSE; } } catch (const char* msg) { base.setLastError(ll_safe_string(msg)); base.decodeFailed(); cleanupCodeStream(); return TRUE; // done } catch (...) { base.setLastError( "Unknown J2C error" ); base.decodeFailed(); cleanupCodeStream(); return TRUE; // done } mTPosp->x++; } mTPosp->y++; mTPosp->x = 0; } cleanupCodeStream(); return TRUE; }
// Returns TRUE to mean done, whether successful or not. BOOL InWorldzJ2C::decodeImpl(ImageBaseForKDU* base, ImageBaseForKDU* raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) { if (!base || !raw_image) { // do nothing return TRUE; } if ((base->getData() == NULL) || (raw_image->getData() == NULL)) { base->mLastErrorMsg = "We've been sent bad data"; return TRUE; } ECodeStreamMode mode = MODE_FAST; DecodeTimer decode_timer; decode_timer.start(); if (!mCodeStreamp) { if (!initDecode(*base, *raw_image, decode_time, mode, first_channel, max_channel_count)) { // Initializing the J2C decode failed, bail out. cleanupCodeStream(); return TRUE; // done } } // These can probably be grabbed from what's saved in the class. kdu_dims dims; mCodeStreamp->get_dims(0, dims); if (dims.size.x <=0 || dims.size.y <= 0) { std::cout << "bad sizes in stream, not decoding!" << std::endl; return TRUE; } // figure out why this is happening -- MC /*if (dims.pos.get_x() < 0) { dims.pos.set_x(0); } if (dims.pos.get_y() < 0) { dims.pos.set_y(0); }*/ // Now we are ready to walk through the tiles processing them one-by-one. kdu_byte* buffer = raw_image->getData(); if (!buffer) { // shouldn't ever happen! cleanupCodeStream(); return TRUE; } while ((mTPosp->y < mTileIndicesp->size.y) && mTPosp->y >= 0) { while ((mTPosp->x < mTileIndicesp->size.x) && mTPosp->x >= 0) { try { if (!mDecodeState) { kdu_tile tile = mCodeStreamp->open_tile(*(mTPosp) + mTileIndicesp->pos); // Find the region of the buffer occupied by this // tile. Note that we have no control over // sub-sampling factors which might have been used // during compression and so it can happen that tiles // (at the image component level) actually have // different dimensions. For this reason, we cannot // figure out the buffer region occupied by a tile // directly from the tile indices. Instead, we query // the highest resolution of the first tile-component // concerning its location and size on the canvas -- // the `dims' object already holds the location and // size of the entire image component on the same // canvas coordinate system. Comparing the two tells // us where the current tile is in the buffer. S32 channels = base->getComponents() - first_channel; if (channels > max_channel_count) { channels = max_channel_count; } kdu_resolution res = tile.access_component(0).access_resolution(); kdu_dims tile_dims; res.get_dims(tile_dims); kdu_coords offset = tile_dims.pos - dims.pos; S32 row_gap = channels * dims.size.x; // inter-row separation kdu_byte* buf = buffer + offset.y*row_gap + offset.x * channels; mDecodeState = new LLKDUDecodeState(tile, buf, row_gap); } // Do the actual processing F32 remaining_time = decode_time - decode_timer.getElapsedTime(); // This is where we do the actual decode. If we run out of time, return false. if (mDecodeState->processTileDecode(remaining_time, (decode_time > 0.0f))) { delete mDecodeState; mDecodeState = NULL; //cleanupCodeStream(); ??? base->mDecodeSuccessful = true; //return TRUE; } else { // Not finished decoding yet. // setLastError("Ran out of time while decoding"); base->mDecodeSuccessful = false; //cleanupCodeStream(); ????? return FALSE; } } catch (const char* msg) { if (msg) { base->mLastErrorMsg = msg; } base->mDecodeSuccessful = false; cleanupCodeStream(); return TRUE; // done } catch (...) { base->mLastErrorMsg = "Unknown J2C error"; base->mDecodeSuccessful = false; cleanupCodeStream(); return TRUE; // done } mTPosp->x++; } mTPosp->y++; mTPosp->x = 0; } cleanupCodeStream(); return TRUE; }
LLImageJ2CKDU::~LLImageJ2CKDU() { cleanupCodeStream(); // in case destroyed before decode completed }
InWorldzJ2C::~InWorldzJ2C() { cleanupCodeStream(); // in case destroyed before decode completed }