diff options
author | Joseph Wen <josephwen@google.com> | 2010-07-12 13:15:16 +0800 |
---|---|---|
committer | Joseph Wen <josephwen@google.com> | 2010-08-04 17:18:03 +0800 |
commit | 3147fbe7688fc353e6ae03825a37cf101a4ee01d (patch) | |
tree | ea69b77eecc6c06ae2f46ba913dfa185c6a33ea3 | |
parent | 3a10203724328878e5901a460697ccfdd8135254 (diff) | |
download | jpeg-3147fbe7688fc353e6ae03825a37cf101a4ee01d.tar.gz |
Support tile-based jpeg decoding.This change only handles the baseline case.
The functionality of tile-based decode is enabled by default.
To disable it, mark off the flag of ANDROID_TILE_BASED_DECODE in Android.mk
Change-Id: Ib9f7839095b0ca55260c28d3c499c871e81332ea
-rw-r--r-- | Android.mk | 3 | ||||
-rw-r--r-- | jdapimin.c | 5 | ||||
-rw-r--r-- | jdapistd.c | 72 | ||||
-rw-r--r-- | jdcoefct.c | 81 | ||||
-rw-r--r-- | jdhuff.c | 209 | ||||
-rw-r--r-- | jdhuff.h | 1 | ||||
-rw-r--r-- | jdinput.c | 20 | ||||
-rw-r--r-- | jdmaster.c | 5 | ||||
-rw-r--r-- | jdtrans.c | 83 | ||||
-rw-r--r-- | jpegint.h | 7 | ||||
-rw-r--r-- | jpeglib.h | 65 |
11 files changed, 526 insertions, 25 deletions
@@ -32,6 +32,9 @@ LOCAL_CFLAGS += -DAVOID_TABLES LOCAL_CFLAGS += -O3 -fstrict-aliasing -fprefetch-loop-arrays #LOCAL_CFLAGS += -march=armv6j +# enable tile based decode +LOCAL_CFLAGS += -DANDROID_TILE_BASED_DECODE + LOCAL_MODULE:= libjpeg include $(BUILD_SHARED_LIBRARY) @@ -371,6 +371,9 @@ jpeg_finish_decompress (j_decompress_ptr cinfo) if ((cinfo->global_state == DSTATE_SCANNING || cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) { /* Terminate final pass of non-buffered mode */ +#ifdef ANDROID_TILE_BASED_DECODE + cinfo->output_scanline = cinfo->output_height; +#endif if (cinfo->output_scanline < cinfo->output_height) ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); (*cinfo->master->finish_output_pass) (cinfo); @@ -383,10 +386,12 @@ jpeg_finish_decompress (j_decompress_ptr cinfo) ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); } /* Read until EOI */ +#ifndef ANDROID_TILE_BASED_DECODE while (! cinfo->inputctl->eoi_reached) { if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) return FALSE; /* Suspend, come back later */ } +#endif /* Do final cleanup */ (*cinfo->src->term_source) (cinfo); /* We can use jpeg_abort to release memory and reset global_state */ @@ -174,6 +174,78 @@ jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines, cinfo->output_scanline += row_ctr; return row_ctr; } +/* + * Initialize the jpeg decoder to decompressing a rectangle with size of (width, height) + * and its upper-left corner located at (start_x, start_y). + * Align start_x and start_y to multiplies of iMCU width and height, respectively. + * Also, the new reader position will be returned in (start_x, start_y). + */ + +GLOBAL(void) +jpeg_init_read_tile_scanline(j_decompress_ptr cinfo, huffman_index *index, + int *start_x, int *start_y, int *width, int *height) +{ + // Calculates the boundary of iMCU + int lines_per_iMCU_row = cinfo->max_v_samp_factor * DCTSIZE; + int lines_per_iMCU_col = cinfo->max_h_samp_factor * DCTSIZE; + int row_offset = *start_y / lines_per_iMCU_row; + int col_left_boundary = ((*start_x / lines_per_iMCU_col) / index->MCU_sample_size) + * index->MCU_sample_size; + int col_right_boundary = (*start_x + *width + lines_per_iMCU_col - 1) / lines_per_iMCU_col; + + *height = (*start_y - row_offset * lines_per_iMCU_row) + *height; + *start_x = col_left_boundary * lines_per_iMCU_col; + *start_y = row_offset * lines_per_iMCU_row; + cinfo->image_width = (col_right_boundary - col_left_boundary) * lines_per_iMCU_col; + cinfo->input_iMCU_row = row_offset; + cinfo->output_iMCU_row = row_offset; + + // Updates JPEG decoder parameter + jinit_color_deconverter(cinfo); + jpeg_calc_output_dimensions(cinfo); + jinit_upsampler(cinfo); + jpeg_decompress_per_scan_setup(cinfo); + cinfo->MCUs_per_row = col_right_boundary - col_left_boundary; + + int sampleSize = cinfo->image_width / cinfo->output_width; + *height /= sampleSize; + *width = cinfo->output_width; + cinfo->output_scanline = lines_per_iMCU_row * row_offset / sampleSize; + (*cinfo->master->prepare_for_output_pass) (cinfo); +} + +/* + * Read a scanline from the current position. + * + * Return the number of lines actually read. + */ + +GLOBAL(JDIMENSION) +jpeg_read_tile_scanline (j_decompress_ptr cinfo, huffman_index *index, + JSAMPARRAY scanlines, int start_x, int start_y, int width, int height) +{ + // Calculates the boundary of iMCU + int lines_per_iMCU_row = cinfo->max_v_samp_factor * DCTSIZE; + int lines_per_iMCU_col = cinfo->max_h_samp_factor * DCTSIZE; + int col_left_boundary = ((start_x / lines_per_iMCU_col) / index->MCU_sample_size) + * index->MCU_sample_size; + int sampleSize = cinfo->image_width / cinfo->output_width; + + if (cinfo->output_scanline % (lines_per_iMCU_row / sampleSize) == 0) { + // Set the read head to the next iMCU row + cinfo->unread_marker = 0; + int iMCU_row_offset = cinfo->output_scanline / (lines_per_iMCU_row / sampleSize); + int offset_data_col_position = col_left_boundary / index->MCU_sample_size; + huffman_offset_data *offset_data = + &index->scan[0].offset[iMCU_row_offset][offset_data_col_position]; + + jpeg_configure_huffman_decoder(cinfo, + offset_data->bitstream_offset, offset_data->prev_dc); + } + + int row_ctr = jpeg_read_scanlines(cinfo, scanlines, 1); // Read one line + return row_ctr; +} /* @@ -263,7 +263,6 @@ consume_data (j_decompress_ptr cinfo) * because we requested a pre-zeroed array. */ } - /* Loop to process one whole iMCU row */ for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; yoffset++) { @@ -272,14 +271,14 @@ consume_data (j_decompress_ptr cinfo) /* Construct list of pointers to DCT blocks belonging to this MCU */ blkn = 0; /* index of current DCT block within MCU */ for (ci = 0; ci < cinfo->comps_in_scan; ci++) { - compptr = cinfo->cur_comp_info[ci]; - start_col = MCU_col_num * compptr->MCU_width; - for (yindex = 0; yindex < compptr->MCU_height; yindex++) { - buffer_ptr = buffer[ci][yindex+yoffset] + start_col; - for (xindex = 0; xindex < compptr->MCU_width; xindex++) { - coef->MCU_buffer[blkn++] = buffer_ptr++; - } - } + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < compptr->MCU_width; xindex++) { + coef->MCU_buffer[blkn++] = buffer_ptr++; + } + } } /* Try to fetch the MCU. */ if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) { @@ -302,6 +301,68 @@ consume_data (j_decompress_ptr cinfo) return JPEG_SCAN_COMPLETED; } +#define rounded_division(A,B) ((A+B-1)/(B)) +/* + * Same as consume_data, expect for saving the Huffman decode information + * - bitstream offset and DC coefficient to index. + */ + +METHODDEF(int) +consume_data_with_huffman_index (j_decompress_ptr cinfo, huffman_index *index, + int current_scan) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + int ci, xindex, yindex, yoffset; + JDIMENSION start_col; + JBLOCKROW buffer_ptr; + + huffman_scan_header current_header = index->scan[current_scan]; + current_header.MCU_rows_per_iMCU_row = coef->MCU_rows_per_iMCU_row; + current_header.MCUs_per_row = cinfo->MCUs_per_row; + current_header.comps_in_scan = cinfo->comps_in_scan; + + size_t allocate_size = coef->MCU_rows_per_iMCU_row + * rounded_division(cinfo->MCUs_per_row, index->MCU_sample_size) + * sizeof(huffman_offset_data); + current_header.offset[cinfo->input_iMCU_row] = (huffman_offset_data*)malloc(allocate_size); + index->mem_used += allocate_size; + + huffman_offset_data *offset_data = current_header.offset[cinfo->input_iMCU_row]; + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + // Record huffman bit offset + if (MCU_col_num % index->MCU_sample_size == 0) { + jpeg_get_huffman_decoder_configuration(cinfo, + &offset_data->bitstream_offset, offset_data->prev_dc); + ++offset_data; + } + + /* Try to fetch the MCU. */ + if (! (*cinfo->entropy->decode_mcu_discard_coef) (cinfo)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->MCU_ctr = MCU_col_num; + return JPEG_SUSPENDED; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + start_iMCU_row(cinfo); + return JPEG_ROW_COMPLETED; + } + /* Completed the scan */ + (*cinfo->inputctl->finish_input_pass) (cinfo); + return JPEG_SCAN_COMPLETED; +} + /* * Decompress and return some data in the multi-pass case. @@ -712,6 +773,7 @@ jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer) (long) compptr->v_samp_factor), (JDIMENSION) access_rows); } + coef->pub.consume_data_with_huffman_index = consume_data_with_huffman_index; coef->pub.consume_data = consume_data; coef->pub.decompress_data = decompress_data; coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */ @@ -729,6 +791,7 @@ jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer) for (i = 0; i < D_MAX_BLOCKS_IN_MCU; i++) { coef->MCU_buffer[i] = buffer + i; } + coef->pub.consume_data_with_huffman_index = consume_data_with_huffman_index; coef->pub.consume_data = dummy_consume_data; coef->pub.decompress_data = decompress_onepass; coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */ @@ -77,7 +77,6 @@ typedef struct { typedef huff_entropy_decoder * huff_entropy_ptr; - /* * Initialize for a Huffman-compressed scan. */ @@ -497,6 +496,80 @@ process_restart (j_decompress_ptr cinfo) return TRUE; } +/* + * Configure the Huffman decoder to decode the image + * starting from (iMCU_row_offset, iMCU_col_offset). + */ + +GLOBAL(void) +jpeg_configure_huffman_decoder(j_decompress_ptr cinfo, + unsigned int bitstream_offset, short int *dc_info) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int blkn, i; + + BITREAD_STATE_VARS; + savable_state state; + + unsigned int byte_offset = bitstream_offset >> LOG_TWO_BIT_BUF_SIZE; + unsigned int bit_in_bit_buffer = + bitstream_offset & ((1 << LOG_TWO_BIT_BUF_SIZE) - 1); + + cinfo->src->next_input_byte = cinfo->src->start_input_byte + byte_offset; + cinfo->src->bytes_in_buffer = cinfo->src->total_byte - byte_offset; + + entropy->bitstate.bits_left = 0; + + /* + * When byte_offset points to the middle of a JPEG marker (2-bytes data + * starting with 0xFF), we need to shift the byte_offset backward so that + * CHECK_BIT_BUFFER can handle it properly. + */ + for (i = 0; i < 5 || *(cinfo->src->next_input_byte - 1) == 0xFF; i++) { + if (cinfo->src->next_input_byte <= cinfo->src->start_input_byte) + break; + cinfo->src->next_input_byte--; + cinfo->src->bytes_in_buffer++; + } + + BITREAD_LOAD_STATE(cinfo, entropy->bitstate); + CHECK_BIT_BUFFER(br_state, BIT_BUF_SIZE, return); + while (cinfo->src->total_byte - br_state.bytes_in_buffer < byte_offset) { + DROP_BITS(8); + CHECK_BIT_BUFFER(br_state, BIT_BUF_SIZE, return); + } + DROP_BITS(bits_left - bit_in_bit_buffer); + BITREAD_SAVE_STATE(cinfo, entropy->bitstate); + + for (i = 0; i < cinfo->comps_in_scan; i++) { + entropy->saved.last_dc_val[i] = dc_info[i]; + } +} + +/* + * Save the current Huffman deocde position and the DC coefficients + * for each component into bitstream_offset and dc_info[], respectively. + */ + +GLOBAL(void) +jpeg_get_huffman_decoder_configuration(j_decompress_ptr cinfo, + unsigned int *bitstream_offset, short int *dc_info) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + + BITREAD_STATE_VARS; + savable_state state; + int i; + + BITREAD_LOAD_STATE(cinfo, entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + *bitstream_offset = ((cinfo->src->total_byte - cinfo->src->bytes_in_buffer) + << LOG_TWO_BIT_BUF_SIZE) + bits_left; + for (i = 0; i < cinfo->comps_in_scan; i++) { + dc_info[i] = state.last_dc_val[i]; + } +} /* * Decode and return one MCU's worth of Huffman-compressed coefficients. @@ -532,7 +605,6 @@ decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) * This way, we return uniform gray for the remainder of the segment. */ if (! entropy->pub.insufficient_data) { - /* Load up working state */ BITREAD_LOAD_STATE(cinfo,entropy->bitstate); ASSIGN_STATE(state, entropy->saved); @@ -626,6 +698,87 @@ decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) return TRUE; } +/* + * Decode one MCU's worth of Huffman-compressed coefficients. + * The propose of this method is to calculate the + * data length of one MCU in Huffman-coded format. + * Therefore, all coefficients are discarded. + */ + +METHODDEF(boolean) +decode_mcu_discard_coef (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int blkn; + BITREAD_STATE_VARS; + savable_state state; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + if (! entropy->pub.insufficient_data) { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn]; + d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn]; + register int s, k, r; + + /* Decode a single block's worth of coefficients */ + + /* Section F.2.2.1: decode the DC coefficient difference */ + HUFF_DECODE(s, br_state, dctbl, return FALSE, label1); + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + + /* discard all coefficients */ + if (entropy->dc_needed[blkn]) { + /* Convert DC difference to actual value, update last_dc_val */ + int ci = cinfo->MCU_membership[blkn]; + s += state.last_dc_val[ci]; + state.last_dc_val[ci] = s; + } + for (k = 1; k < DCTSIZE2; k++) { + HUFF_DECODE(s, br_state, actbl, return FALSE, label3); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + DROP_BITS(s); + } else { + if (r != 15) + break; + k += 15; + } + } + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(entropy->saved, state); + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + /* * Module initialization routine for Huffman entropy decoding. @@ -649,3 +802,55 @@ jinit_huff_decoder (j_decompress_ptr cinfo) entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; } } + +GLOBAL(void) +jinit_huff_decoder_no_data (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy; + int i; + + entropy = (huff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(huff_entropy_decoder)); + cinfo->entropy = (struct jpeg_entropy_decoder *) entropy; + entropy->pub.start_pass = start_pass_huff_decoder; + entropy->pub.decode_mcu = decode_mcu; + entropy->pub.decode_mcu_discard_coef = decode_mcu_discard_coef; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; + } +} + +/* + * Call after jpeg_read_header + */ +GLOBAL(void) +jpeg_create_huffman_index(j_decompress_ptr cinfo, huffman_index *index) +{ + int i, s; + index->scan_count = 1; + index->scan = (huffman_scan_header*)malloc(index->scan_count + * sizeof(huffman_scan_header)); + index->total_iMCU_rows = cinfo->total_iMCU_rows; + index->scan[0].offset = (huffman_offset_data**)malloc(cinfo->total_iMCU_rows + * sizeof(huffman_offset_data*)); + index->MCU_sample_size = DEFAULT_MCU_SAMPLE_SIZE; + + index->mem_used = sizeof(huffman_scan_header) + + cinfo->total_iMCU_rows*sizeof(huffman_offset_data*); +} + +GLOBAL(void) +jpeg_destroy_huffman_index(huffman_index *index) +{ + int i, j; + for (i = 0; i < index->scan_count; i++) { + for(j = 0; j < index->total_iMCU_rows; j++) { + free(index->scan[i].offset[j]); + } + free(index->scan[i].offset); + } + free(index->scan); +} @@ -71,6 +71,7 @@ EXTERN(void) jpeg_make_d_derived_tbl typedef INT32 bit_buf_type; /* type of bit-extraction buffer */ #define BIT_BUF_SIZE 32 /* size of buffer in bits */ +#define LOG_TWO_BIT_BUF_SIZE 5 /* log_2(BIT_BUF_SIZE) */ /* If long is > 32 bits on your machine, and shifting/masking longs is * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE @@ -29,6 +29,8 @@ typedef my_input_controller * my_inputctl_ptr; /* Forward declarations */ METHODDEF(int) consume_markers JPP((j_decompress_ptr cinfo)); +METHODDEF(int) consume_markers_with_huffman_index JPP((j_decompress_ptr cinfo, + huffman_index *index)); /* @@ -116,7 +118,6 @@ initial_setup (j_decompress_ptr cinfo) cinfo->inputctl->has_multiple_scans = FALSE; } - LOCAL(void) per_scan_setup (j_decompress_ptr cinfo) /* Do computations that are needed before processing a JPEG scan */ @@ -194,6 +195,13 @@ per_scan_setup (j_decompress_ptr cinfo) } } +GLOBAL(void) +jpeg_decompress_per_scan_setup(j_decompress_ptr cinfo) +{ + per_scan_setup(cinfo); +} + + /* * Save away a copy of the Q-table referenced by each component present @@ -258,6 +266,7 @@ start_input_pass (j_decompress_ptr cinfo) (*cinfo->entropy->start_pass) (cinfo); (*cinfo->coef->start_input_pass) (cinfo); cinfo->inputctl->consume_input = cinfo->coef->consume_data; + cinfo->inputctl->consume_input_with_huffman_index = cinfo->coef->consume_data_with_huffman_index; } @@ -271,9 +280,15 @@ METHODDEF(void) finish_input_pass (j_decompress_ptr cinfo) { cinfo->inputctl->consume_input = consume_markers; + cinfo->inputctl->consume_input_with_huffman_index = consume_markers_with_huffman_index; } +METHODDEF(int) +consume_markers_with_huffman_index (j_decompress_ptr cinfo, huffman_index *index) +{ + return consume_markers(cinfo); +} /* * Read JPEG markers before, between, or after compressed-data scans. * Change state as necessary when a new scan is reached. @@ -341,6 +356,7 @@ reset_input_controller (j_decompress_ptr cinfo) my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; inputctl->pub.consume_input = consume_markers; + inputctl->pub.consume_input_with_huffman_index = consume_markers_with_huffman_index; inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ inputctl->pub.eoi_reached = FALSE; inputctl->inheaders = TRUE; @@ -372,6 +388,8 @@ jinit_input_controller (j_decompress_ptr cinfo) inputctl->pub.reset_input_controller = reset_input_controller; inputctl->pub.start_input_pass = start_input_pass; inputctl->pub.finish_input_pass = finish_input_pass; + + inputctl->pub.consume_input_with_huffman_index = consume_markers_with_huffman_index; /* Initialize state: can't use reset_input_controller since we don't * want to try to reset other modules yet. */ @@ -103,8 +103,9 @@ jpeg_calc_output_dimensions (j_decompress_ptr cinfo) #endif /* Prevent application from calling me at wrong times */ - if (cinfo->global_state != DSTATE_READY) - ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + // FIXME + //if (cinfo->global_state != DSTATE_READY) + // ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); #ifdef IDCT_SCALING_SUPPORTED @@ -16,7 +16,7 @@ /* Forward declarations */ -LOCAL(void) transdecode_master_selection JPP((j_decompress_ptr cinfo)); +LOCAL(void) transdecode_master_selection JPP((j_decompress_ptr cinfo, boolean need_full_buffer)); /* @@ -46,7 +46,7 @@ jpeg_read_coefficients (j_decompress_ptr cinfo) { if (cinfo->global_state == DSTATE_READY) { /* First call: initialize active modules */ - transdecode_master_selection(cinfo); + transdecode_master_selection(cinfo, TRUE); cinfo->global_state = DSTATE_RDCOEFS; } if (cinfo->global_state == DSTATE_RDCOEFS) { @@ -55,20 +55,20 @@ jpeg_read_coefficients (j_decompress_ptr cinfo) int retcode; /* Call progress monitor hook if present */ if (cinfo->progress != NULL) - (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); /* Absorb some more input */ retcode = (*cinfo->inputctl->consume_input) (cinfo); if (retcode == JPEG_SUSPENDED) - return NULL; + return NULL; if (retcode == JPEG_REACHED_EOI) - break; + break; /* Advance progress counter if appropriate */ if (cinfo->progress != NULL && (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { - if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { /* startup underestimated number of scans; ratchet up one scan */ - cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; - } + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + } } } /* Set state so that jpeg_finish_decompress does the right thing */ @@ -87,6 +87,62 @@ jpeg_read_coefficients (j_decompress_ptr cinfo) return NULL; /* keep compiler happy */ } +GLOBAL(boolean) +jpeg_build_huffman_index(j_decompress_ptr cinfo, huffman_index *index) +{ + if (cinfo->global_state == DSTATE_READY) { + /* First call: initialize active modules */ + transdecode_master_selection(cinfo, FALSE); + cinfo->global_state = DSTATE_RDCOEFS; + } + if (cinfo->global_state == DSTATE_RDCOEFS) { + /* Absorb whole file into the coef buffer */ + for (;;) { + int retcode; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + /* Absorb some more input */ + retcode = (*cinfo->inputctl->consume_input_with_huffman_index) (cinfo, index, 0); + if (retcode == JPEG_SUSPENDED) + return FALSE; + if (retcode == JPEG_REACHED_EOI) + break; + + /* + * TODO + * Baseline have one sacn only. + * If we reach scan complete the whole image is processed. + * Need changing for progressive mode. + */ + if (retcode == JPEG_SCAN_COMPLETED) + break; + + /* Advance progress counter if appropriate */ + if (cinfo->progress != NULL && + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + /* startup underestimated number of scans; ratchet up one scan */ + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + } + } + } + /* Set state so that jpeg_finish_decompress does the right thing */ + cinfo->global_state = DSTATE_STOPPING; + } + /* At this point we should be in state DSTATE_STOPPING if being used + * standalone, or in state DSTATE_BUFIMAGE if being invoked to get access + * to the coefficients during a full buffered-image-mode decompression. + */ + if ((cinfo->global_state == DSTATE_STOPPING || + cinfo->global_state == DSTATE_BUFIMAGE) && cinfo->buffered_image) { + return TRUE; + } + /* Oops, improper usage */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return FALSE; /* keep compiler happy */ +} + /* * Master selection of decompression modules for transcoding. @@ -94,7 +150,7 @@ jpeg_read_coefficients (j_decompress_ptr cinfo) */ LOCAL(void) -transdecode_master_selection (j_decompress_ptr cinfo) +transdecode_master_selection (j_decompress_ptr cinfo, boolean need_full_buffer) { /* This is effectively a buffered-image operation. */ cinfo->buffered_image = TRUE; @@ -109,12 +165,17 @@ transdecode_master_selection (j_decompress_ptr cinfo) #else ERREXIT(cinfo, JERR_NOT_COMPILED); #endif - } else + } else { +#ifdef ANDROID_TILE_BASED_DECODE + jinit_huff_decoder_no_data(cinfo); +#else jinit_huff_decoder(cinfo); +#endif + } } /* Always get a full-image coefficient buffer. */ - jinit_d_coef_controller(cinfo, TRUE); + jinit_d_coef_controller(cinfo, need_full_buffer); /* We can now tell the memory manager to allocate virtual arrays. */ (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); @@ -145,6 +145,8 @@ struct jpeg_decomp_master { /* Input control module */ struct jpeg_input_controller { JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); + JMETHOD(int, consume_input_with_huffman_index, (j_decompress_ptr cinfo, + huffman_index *index, int scan_count)); JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); @@ -166,6 +168,8 @@ struct jpeg_d_main_controller { struct jpeg_d_coef_controller { JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); + JMETHOD(int, consume_data_with_huffman_index, (j_decompress_ptr cinfo, + huffman_index* index, int scan_count)); JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); @@ -210,6 +214,7 @@ struct jpeg_entropy_decoder { JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)); + JMETHOD(boolean, decode_mcu_discard_coef, (j_decompress_ptr cinfo)); /* This is here to share code between baseline and progressive decoders; */ /* other modules probably should not use it */ @@ -357,6 +362,7 @@ EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_huff_decoder_no_data JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); @@ -364,6 +370,7 @@ EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_decompress_per_scan_setup (j_decompress_ptr cinfo); /* Memory manager initialization */ EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); @@ -633,6 +633,47 @@ struct jpeg_decompress_struct { struct jpeg_color_quantizer * cquantize; }; +typedef struct { + + // |--- byte_offset ---|- bit_left -| + // \------ 27 -------/ \---- 5 ----/ + unsigned int bitstream_offset; + short prev_dc[3]; +} huffman_offset_data; + +typedef struct { + + // The header starting position of this scan + unsigned int bitstream_offset; + + // Number of components in this scan + int comps_in_scan; + + // Number of MCUs in each row + int MCUs_per_row; + int MCU_rows_per_iMCU_row; + + huffman_offset_data **offset; +} huffman_scan_header; + +#define DEFAULT_MCU_SAMPLE_SIZE 16 + +typedef struct { + + // The number of MCUs that we sample each time as an index point + int MCU_sample_size; + + // Number of scan in this image + int scan_count; + + // Number of iMCUs rows in this image + int total_iMCU_rows; + + // Memory used by scan struct + size_t mem_used; + huffman_scan_header *scan; +} huffman_index; + /* "Object" declarations for JPEG modules that may be supplied or called * directly by the surrounding application. @@ -728,7 +769,9 @@ struct jpeg_destination_mgr { struct jpeg_source_mgr { const JOCTET * next_input_byte; /* => next byte to read from buffer */ + const JOCTET * start_input_byte; /* => first byte to read from input */ size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + size_t total_byte; /* # of bytes in input */ JMETHOD(void, init_source, (j_decompress_ptr cinfo)); JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); @@ -980,6 +1023,19 @@ EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION max_lines)); +EXTERN(JDIMENSION) jpeg_read_scanlines_from JPP((j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + int line_offset, + JDIMENSION max_lines)); +EXTERN(JDIMENSION) jpeg_read_tile_scanline JPP((j_decompress_ptr cinfo, + huffman_index *index, + JSAMPARRAY scanlines, + int start_x, int start_y, + int width, int height)); +EXTERN(void) jpeg_init_read_tile_scanline JPP((j_decompress_ptr cinfo, + huffman_index *index, + int *start_x, int *start_y, + int *width, int *height)); EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); /* Replaces jpeg_read_scanlines when reading raw downsampled data. */ @@ -1017,6 +1073,7 @@ EXTERN(void) jpeg_set_marker_processor /* Read or write raw DCT coefficients --- useful for lossless transcoding. */ EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_build_huffman_index JPP((j_decompress_ptr cinfo, huffman_index *index)); EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, @@ -1041,6 +1098,14 @@ EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, int desired)); +EXTERN(void) jpeg_configure_huffman_decoder(j_decompress_ptr cinfo, + unsigned int bitstream_offset, short int *dc_info); +EXTERN(void) jpeg_get_huffman_decoder_configuration(j_decompress_ptr cinfo, + unsigned int *bitstream_offset, short int *dc_info); +EXTERN(void) jpeg_create_huffman_index(j_decompress_ptr cinfo, + huffman_index *index); +EXTERN(void) jpeg_destroy_huffman_index(huffman_index *index); + /* These marker codes are exported since applications and data source modules * are likely to want to use them. |