// Consume input data and store it in the full-image coefficient buffer. // We read as much as one fully interleaved MCU row ("iMCU" row) per call, // ie, v_samp_factor block rows for each component in the scan. // Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. static CONSUME_INPUT consume_data(jpeg_decompress cinfo) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; d_coef_controller coef = (d_coef_controller)lossyd.coef_private; short[][][][] buffer = new short[MAX_COMPS_IN_SCAN][][][]; int[] buffer_ind = new int[MAX_COMPS_IN_SCAN]; // Align the buffers for the components used in this scan. for (int ci = 0; ci < cinfo.comps_in_scan; ci++) { jpeg_component_info compptr = cinfo.cur_comp_info[ci]; buffer[ci] = coef.whole_image[compptr.component_index]; buffer_ind[ci] = (int)cinfo.input_iMCU_row * compptr.v_samp_factor; // Note: entropy decoder expects buffer to be zeroed, // but this is handled automatically by the memory manager // because we requested a pre-zeroed array. } // Loop to process one whole iMCU row for (int yoffset = coef.MCU_vert_offset; yoffset < coef.MCU_rows_per_iMCU_row; yoffset++) { for (uint MCU_col_num = coef.MCU_ctr; MCU_col_num < cinfo.MCUs_per_row; MCU_col_num++) // index of current MCU within row { // Construct list of pointers to DCT blocks belonging to this MCU int blkn = 0; // index of current DCT block within MCU for (int ci = 0; ci < cinfo.comps_in_scan; ci++) { jpeg_component_info compptr = cinfo.cur_comp_info[ci]; uint start_col = MCU_col_num * (uint)compptr.MCU_width; for (int yindex = 0; yindex < compptr.MCU_height; yindex++) { short[][] buffer_ptr = buffer[ci][buffer_ind[ci] + yindex + yoffset]; uint buffer_ptr_ind = start_col; for (int xindex = 0; xindex < compptr.MCU_width; xindex++) { coef.MCU_buffer[blkn++] = buffer_ptr[buffer_ptr_ind++]; } } } // Try to fetch the MCU. if (!lossyd.entropy_decode_mcu(cinfo, coef.MCU_buffer)) { // Suspension forced; update state counters and exit coef.MCU_vert_offset = yoffset; coef.MCU_ctr = MCU_col_num; return(CONSUME_INPUT.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_d_coef(cinfo); return(CONSUME_INPUT.JPEG_ROW_COMPLETED); } // Completed the scan cinfo.inputctl.finish_input_pass(cinfo); return(CONSUME_INPUT.JPEG_SCAN_COMPLETED); }
// Decompress and return some data in the single-pass case. // Always attempts to emit one fully interleaved MCU row ("iMCU" row). // Input and output must run in lockstep since we have only a one-MCU buffer. // Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. // // NB: output_buf contains a plane for each component in image, // which we index according to the component's SOF position. static CONSUME_INPUT decompress_onepass(jpeg_decompress cinfo, byte[][][] output_buf) { jpeg_lossy_d_codec lossyd = (jpeg_lossy_d_codec)cinfo.coef; d_coef_controller coef = (d_coef_controller)lossyd.coef_private; uint last_MCU_col = cinfo.MCUs_per_row - 1; uint last_iMCU_row = cinfo.total_iMCU_rows - 1; // Loop to process as much as one whole iMCU row for (int yoffset = coef.MCU_vert_offset; yoffset < coef.MCU_rows_per_iMCU_row; yoffset++) { for (uint MCU_col_num = coef.MCU_ctr; MCU_col_num <= last_MCU_col; MCU_col_num++) // index of current MCU within row { // Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. for (int i = 0; i < cinfo.blocks_in_MCU; i++) { for (int a = 0; a < DCTSIZE2; a++) { coef.MCU_buffer[i][a] = 0; } } if (!lossyd.entropy_decode_mcu(cinfo, coef.MCU_buffer)) { // Suspension forced; update state counters and exit coef.MCU_vert_offset = yoffset; coef.MCU_ctr = MCU_col_num; return(CONSUME_INPUT.JPEG_SUSPENDED); } // Determine where data should go in output_buf and do the IDCT thing. // We skip dummy blocks at the right and bottom edges (but blkn gets // incremented past them!). Note the inner loop relies on having // allocated the MCU_buffer[] blocks sequentially. int blkn = 0; // index of current DCT block within MCU for (int ci = 0; ci < cinfo.comps_in_scan; ci++) { jpeg_component_info compptr = cinfo.cur_comp_info[ci]; // Don't bother to IDCT an uninteresting component. if (!compptr.component_needed) { blkn += (int)compptr.MCU_blocks; continue; } inverse_DCT_method_ptr inverse_DCT = lossyd.inverse_DCT[compptr.component_index]; int useful_width = (MCU_col_num < last_MCU_col)?compptr.MCU_width:compptr.last_col_width; byte[][] output_ptr = output_buf[compptr.component_index]; uint output_ptr_ind = (uint)yoffset * compptr.DCT_scaled_size; uint start_col = MCU_col_num * (uint)compptr.MCU_sample_width; for (int yindex = 0; yindex < compptr.MCU_height; yindex++) { if (cinfo.input_iMCU_row < last_iMCU_row || yoffset + yindex < compptr.last_row_height) { uint output_col = start_col; for (int xindex = 0; xindex < useful_width; xindex++) { inverse_DCT(cinfo, compptr, coef.MCU_buffer[blkn + xindex], output_ptr, output_ptr_ind, output_col); output_col += compptr.DCT_scaled_size; } } blkn += compptr.MCU_width; output_ptr_ind += compptr.DCT_scaled_size; } } } // Completed an MCU row, but perhaps not an iMCU row coef.MCU_ctr = 0; } // Completed the iMCU row, advance counters for next one cinfo.output_iMCU_row++; if (++(cinfo.input_iMCU_row) < cinfo.total_iMCU_rows) { start_iMCU_row_d_coef(cinfo); return(CONSUME_INPUT.JPEG_ROW_COMPLETED); } // Completed the scan cinfo.inputctl.finish_input_pass(cinfo); return(CONSUME_INPUT.JPEG_SCAN_COMPLETED); }