📄 codestream.cpp
字号:
for (int t=0; t < num_tiles.x*num_tiles.y; t++) { kd_tile *tile = tile_refs[t]; assert(tile != KD_EXPIRED_TILE); if (tile == NULL) continue; for (int c=0; c < tile->num_components; c++) { kd_tile_comp *tc = tile->comps+c; for (int r=0; r <= tc->dwt_levels; r++) { kd_resolution *res = tc->resolutions + r; for (int p=0; p < res->precinct_indices.area(); p++) { kd_precinct *precinct = res->precinct_refs[p]; assert(precinct != KD_EXPIRED_PRECINCT); if (precinct == NULL) continue; for (int b=res->min_band; b <= res->max_band; b++) { kd_precinct_band *pb = precinct->bands + b; for (int n=0; n < pb->block_indices.area(); n++) { kd_block *block = pb->blocks + n; block->trim_data(threshold,buf_server); } } } } } }}/*****************************************************************************//* kd_codestream::get_min_header_cost *//*****************************************************************************/void kd_codestream::get_min_header_cost(int &fixed_cost, int &per_layer_cost){ per_layer_cost = 0; fixed_cost = 2 + siz->generate_marker_segments(NULL,-1,0);#ifdef KDU_IDENTIFIER fixed_cost += strlen(KDU_IDENTIFIER)+6;#endif for (int tnum=0; tnum < num_tiles.x*num_tiles.y; tnum++) { kd_tile *tile = tile_refs[tnum]; assert((tile != NULL) && (tile != KD_EXPIRED_TILE)); // Calculate cost of all tile-part headers for this tile. int new_bytes = 0; int try_tpart = 0; do { new_bytes = siz->generate_marker_segments(NULL,tnum,try_tpart); if ((new_bytes > 0) || (try_tpart == 0)) { new_bytes += 12; // Cost of SOT marker segment new_bytes += 2; // Cost of SOD marker } fixed_cost += new_bytes; try_tpart++; } while (new_bytes != 0); // Calculate min packet header cost per_layer_cost += tile->total_precincts; if (tile->use_eph) per_layer_cost += tile->total_precincts*2; if (tile->use_sop) per_layer_cost += tile->total_precincts*6; }}/*****************************************************************************//* kd_codestream::simulate_output *//*****************************************************************************/int kd_codestream::simulate_output(int &header_bytes, int layer_idx, kdu_uint16 slope_threshold, bool finalize_layer, bool last_layer, int max_bytes, int *sloppy_bytes){ header_bytes = 0; if (layer_idx == 0) { header_bytes = 2 + siz->generate_marker_segments(NULL,-1,0);#ifdef KDU_IDENTIFIER header_bytes += strlen(KDU_IDENTIFIER)+6;#endif } int total_bytes = header_bytes; for (int n=0; n < num_tiles.x*num_tiles.y; n++) { if (total_bytes > max_bytes) { assert(!finalize_layer); return total_bytes; } int tile_header_bytes; assert((tile_refs[n] != NULL) && (tile_refs[n] != KD_EXPIRED_TILE)); total_bytes += tile_refs[n]->simulate_output(tile_header_bytes,layer_idx, slope_threshold,finalize_layer, last_layer,max_bytes-total_bytes, sloppy_bytes); header_bytes += tile_header_bytes; } return total_bytes;}/*****************************************************************************//* kd_codestream::pcrd_opt *//*****************************************************************************/void kd_codestream::pcrd_opt(int layer_bytes[], kdu_uint16 slope_thresholds[], int num_layers){ int rough_upper_bound = 0; int fixed_header_cost, per_layer_header_cost; get_min_header_cost(fixed_header_cost,per_layer_header_cost); int new_header_bytes, new_layer_bytes; int last_layer_bytes, last_target_bytes, layer_idx; if (layer_bytes[num_layers-1] == 0) { // Find rough upper bound for the purpose of spacing intermediate layers rough_upper_bound = simulate_output(new_header_bytes,0,0,false,false); } // Now work through the layers. int threshold; int min_threshold = 0; // Inclusive lower bound. int lim_threshold = (1<<16); // Exclusive upper bound. last_layer_bytes = 0; last_target_bytes = 0; for (layer_idx=0; layer_idx < num_layers; layer_idx++) { bool last_layer = (layer_idx == (num_layers-1)); bool auto_targeting = (layer_bytes[layer_idx] == 0); if (auto_targeting) { // Have to make up a suitable number of target bytes if (last_layer) { layer_bytes[layer_idx] = INT_MAX; auto_targeting = false; } else { int next_idx, next_target_bytes; for (next_idx=layer_idx+1; next_idx < num_layers; next_idx++) if ((next_target_bytes = layer_bytes[next_idx]) > 0) break; if (next_target_bytes == 0) { // Can only happen if final layer has no assigned rate target next_idx = num_layers-1; next_target_bytes = rough_upper_bound; } if (layer_idx > 0) { // Logarithmically interpolate known rate targets, after // discounting the minimum header cost. int start_bytes = last_target_bytes - fixed_header_cost - layer_idx*per_layer_header_cost; int end_bytes = next_target_bytes - fixed_header_cost - (next_idx+1)*per_layer_header_cost; if (start_bytes < 1) start_bytes = 1; if (end_bytes < start_bytes) end_bytes = start_bytes; double y_start = log(start_bytes); double y_end = log(end_bytes); double x_start = layer_idx-1; double x_end = next_idx; double x = layer_idx; double y = y_start + (x-x_start)/(x_end-x_start)*(y_end-y_start); layer_bytes[layer_idx] = ((int) exp(y)) + fixed_header_cost + (layer_idx+1)*per_layer_header_cost; } else { // Need to settle on a good starting rate target. int end_bytes = next_target_bytes - fixed_header_cost - (next_idx+1)*per_layer_header_cost; if (end_bytes < 1) end_bytes = 1; int start_bytes = (int) (end_bytes / sqrt(1<<next_idx)); layer_bytes[0] = start_bytes + fixed_header_cost + per_layer_header_cost; } } } // First use a simple bisection search for the slope threshold if (lim_threshold < 1) lim_threshold = 1; int target_bytes = layer_bytes[layer_idx] - last_layer_bytes - 2; // 2 is for an EOC int best_threshold = lim_threshold-1; min_threshold = 0; do { threshold = (min_threshold+lim_threshold)>>1; assert(threshold < (1<<16)); new_layer_bytes = simulate_output(new_header_bytes,layer_idx,(kdu_uint16) threshold, false,last_layer,target_bytes); if (new_layer_bytes > target_bytes) min_threshold = threshold+1; else if (new_layer_bytes <= target_bytes) { best_threshold = threshold; if (new_layer_bytes == target_bytes) break; // Found target exactly lim_threshold = threshold; } } while (lim_threshold > min_threshold); // Finalize the allocation for this layer threshold = best_threshold; new_layer_bytes = // Don't finalize yet simulate_output(new_header_bytes,layer_idx,(kdu_uint16) threshold, false,last_layer); int remaining_bytes = target_bytes - new_layer_bytes; if ((remaining_bytes < 0) && !auto_targeting) { kdu_warning w; w << "Unable to achieve the rate target " "for quality layer " << layer_idx << ". Try requesting a smaller " "number of quality layers.\n"; } if (last_layer && (remaining_bytes > 0) && (threshold > 0)) { threshold--; new_layer_bytes = // Finalize with sloppy fill in. simulate_output(new_header_bytes,layer_idx,(kdu_uint16) threshold, true,true,target_bytes,&remaining_bytes); } else new_layer_bytes = // Finalize without sloppy fill in. simulate_output(new_header_bytes,layer_idx,(kdu_uint16) threshold, true,last_layer); slope_thresholds[layer_idx] = (kdu_uint16) threshold; lim_threshold = threshold+1; // We are allowed to repeat the threshold. last_layer_bytes += new_layer_bytes; last_target_bytes = layer_bytes[layer_idx]; layer_bytes[layer_idx] = last_layer_bytes+2; // Put EOC back. }}/*****************************************************************************//* kd_codestream::generate_codestream *//*****************************************************************************/void kd_codestream::generate_codestream(int max_layers, kdu_uint16 slope_thresholds[]){ assert(out != NULL); // First write the main header. out->put(KDU_SOC); siz->generate_marker_segments(out,-1,0);#ifdef KDU_IDENTIFIER int length = strlen(KDU_IDENTIFIER); out->put(KDU_COM); out->put((kdu_uint16)(length+4)); out->put((kdu_uint16) 1); // Latin values for COM body. out->write((kdu_byte *) KDU_IDENTIFIER,length);#endif // Now cycle through the tiles, interleaving their tile-parts. bool done; do { done = true; for (int n=0; n < num_tiles.x*num_tiles.y; n++) { assert(tile_refs[n] != KD_EXPIRED_TILE); if (tile_refs[n] == NULL) { kdu_error e; e << "You may not currently flush compressed " "code-stream data without completing the compression of all " "tiles."; } int tpart_bytes = tile_refs[n]->generate_tile_part(max_layers,slope_thresholds); if (tpart_bytes > 0) done = false; } } while (!done); // Finish up with the EOC marker. out->put(KDU_EOC);}/* ========================================================================= *//* kdu_codestream *//* ========================================================================= *//*****************************************************************************//* kdu_codestream::create (input) *//*****************************************************************************/void kdu_codestream::create(kdu_compressed_source *source){ assert(state == NULL); state = new kd_codestream; state->in = new kd_compressed_input(source); state->marker = new kd_marker(state->in); if ((!state->marker->read()) || (state->marker->get_code() != KDU_SOC)) { kdu_error e; e << "Code-stream must start with an SOC marker!"; } state->siz = new siz_params; if (!(state->marker->read() && state->siz->translate_marker_segment(state->marker->get_code(), state->marker->get_length(), state->marker->get_bytes(),-1,0))) { kdu_error e; e << "Code-stream must contain a valid SIZ marker segment, " "immediately after the SOC marker!"; } state->construct_common();}/*****************************************************************************//* kdu_codestream::create (output) *//*****************************************************************************/void kdu_codestream::create(siz_params *siz_in, kdu_compressed_target *target){ assert(state == NULL); state = new kd_codestream; state->out = new kd_compressed_output(target); state->siz = new siz_params; state->siz->copy_from(siz_in,-1,-1); state->construct_common();}/*****************************************************************************//* kdu_codestream::destroy *//*****************************************************************************/void kdu_codestream::destroy(){ assert(state != NULL); delete state; state = NULL;}/*****************************************************************************//* kdu_codestream::share_buffering *//*****************************************************************************/void kdu_codestream::share_buffering(kdu_codestream existing){ assert(!state->tiles_accessed); state->buf_server->detach(); delete state->buf_server; state->buf_server = existing.state->buf_server; state->buf_server->attach();}/*****************************************************************************//* kdu_codestream::set_per
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -