Skip to content

Commit bc18ecf

Browse files
author
HeroicKatora
authored
Merge pull request #176 from quilan1/bugfix-non-interleaved-mcus
Bugfix non interleaved mcus
2 parents 29b9c04 + bc1a817 commit bc18ecf

File tree

3 files changed

+96
-62
lines changed

3 files changed

+96
-62
lines changed

src/decoder.rs

Lines changed: 96 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -484,9 +484,6 @@ impl<R: Read> Decoder<R> {
484484
}
485485
}
486486

487-
let blocks_per_mcu: Vec<u16> = components.iter()
488-
.map(|c| c.horizontal_sampling_factor as u16 * c.vertical_sampling_factor as u16)
489-
.collect();
490487
let is_progressive = frame.coding_process == CodingProcess::DctProgressive;
491488
let is_interleaved = components.len() > 1;
492489
let mut dummy_block = [0i16; 64];
@@ -504,70 +501,37 @@ impl<R: Read> Decoder<R> {
504501
}
505502
}
506503

507-
for mcu_y in 0 .. frame.mcu_size.height {
508-
for mcu_x in 0 .. frame.mcu_size.width {
509-
for (i, component) in components.iter().enumerate() {
510-
for j in 0 .. blocks_per_mcu[i] {
511-
let (block_x, block_y) = if is_interleaved {
512-
// Section A.2.3
513-
(mcu_x * component.horizontal_sampling_factor as u16 + j % component.horizontal_sampling_factor as u16,
514-
mcu_y * component.vertical_sampling_factor as u16 + j / component.horizontal_sampling_factor as u16)
515-
}
516-
else {
517-
// Section A.2.2
518-
519-
let blocks_per_row = component.block_size.width as usize;
520-
let block_num = (mcu_y as usize * frame.mcu_size.width as usize +
521-
mcu_x as usize) * blocks_per_mcu[i] as usize + j as usize;
522-
523-
let x = (block_num % blocks_per_row) as u16;
524-
let y = (block_num / blocks_per_row) as u16;
525-
526-
if x * component.dct_scale as u16 >= component.size.width || y * component.dct_scale as u16 >= component.size.height {
527-
continue;
528-
}
504+
// 4.8.2
505+
// When reading from the stream, if the data is non-interleaved then an MCU consists of
506+
// exactly one block (effectively a 1x1 sample).
507+
let (mcu_horizontal_samples, mcu_vertical_samples) = if is_interleaved {
508+
let horizontal = components.iter().map(|component| component.horizontal_sampling_factor as u16).collect::<Vec<_>>();
509+
let vertical = components.iter().map(|component| component.vertical_sampling_factor as u16).collect::<Vec<_>>();
510+
(horizontal, vertical)
511+
} else {
512+
(vec![1], vec![1])
513+
};
529514

530-
(x, y)
531-
};
515+
// This also affects how many MCU values we read from stream. If it's a non-interleaved stream,
516+
// the MCUs will be exactly the block count.
517+
let (max_mcu_x, max_mcu_y) = if is_interleaved {
518+
(frame.mcu_size.width, frame.mcu_size.height)
519+
} else {
520+
(components[0].block_size.width, components[0].block_size.height)
521+
};
532522

533-
let block_offset = (block_y as usize * component.block_size.width as usize + block_x as usize) * 64;
534-
let mcu_row_offset = mcu_y as usize * component.block_size.width as usize * component.vertical_sampling_factor as usize * 64;
535-
let coefficients = if is_progressive {
536-
&mut self.coefficients[scan.component_indices[i]][block_offset .. block_offset + 64]
537-
} else if finished[i] {
538-
&mut mcu_row_coefficients[i][block_offset - mcu_row_offset .. block_offset - mcu_row_offset + 64]
539-
} else {
540-
&mut dummy_block[..]
541-
};
523+
for mcu_y in 0..max_mcu_y {
524+
if mcu_y * 8 >= frame.image_size.height {
525+
break;
526+
}
542527

543-
if scan.successive_approximation_high == 0 {
544-
decode_block(&mut self.reader,
545-
coefficients,
546-
&mut huffman,
547-
self.dc_huffman_tables[scan.dc_table_indices[i]].as_ref(),
548-
self.ac_huffman_tables[scan.ac_table_indices[i]].as_ref(),
549-
scan.spectral_selection.clone(),
550-
scan.successive_approximation_low,
551-
&mut eob_run,
552-
&mut dc_predictors[i])?;
553-
}
554-
else {
555-
decode_block_successive_approximation(&mut self.reader,
556-
coefficients,
557-
&mut huffman,
558-
self.ac_huffman_tables[scan.ac_table_indices[i]].as_ref(),
559-
scan.spectral_selection.clone(),
560-
scan.successive_approximation_low,
561-
&mut eob_run)?;
562-
}
563-
}
528+
for mcu_x in 0..max_mcu_x {
529+
if mcu_x * 8 >= frame.image_size.width {
530+
break;
564531
}
565532

566533
if self.restart_interval > 0 {
567-
let is_last_mcu = mcu_x == frame.mcu_size.width - 1 && mcu_y == frame.mcu_size.height - 1;
568-
mcus_left_until_restart -= 1;
569-
570-
if mcus_left_until_restart == 0 && !is_last_mcu {
534+
if mcus_left_until_restart == 0 {
571535
match huffman.take_marker(&mut self.reader)? {
572536
Some(Marker::RST(n)) => {
573537
if n != expected_rst_num {
@@ -587,16 +551,86 @@ impl<R: Read> Decoder<R> {
587551
None => return Err(Error::Format(format!("no marker found where RST{} was expected", expected_rst_num))),
588552
}
589553
}
554+
555+
mcus_left_until_restart -= 1;
556+
}
557+
558+
for (i, component) in components.iter().enumerate() {
559+
for v_pos in 0..mcu_vertical_samples[i] {
560+
for h_pos in 0..mcu_horizontal_samples[i] {
561+
let coefficients = if is_progressive {
562+
let block_y = (mcu_y * mcu_vertical_samples[i] + v_pos) as usize;
563+
let block_x = (mcu_x * mcu_horizontal_samples[i] + h_pos) as usize;
564+
let block_offset = (block_y * component.block_size.width as usize + block_x) * 64;
565+
&mut self.coefficients[scan.component_indices[i]][block_offset..block_offset + 64]
566+
} else if finished[i] {
567+
// Because the worker thread operates in batches as if we were always interleaved, we
568+
// need to distinguish between a single-shot buffer and one that's currently in process
569+
// (for a non-interleaved) stream
570+
let mcu_batch_current_row = if is_interleaved {
571+
0
572+
} else {
573+
mcu_y % component.vertical_sampling_factor as u16
574+
};
575+
576+
let block_y = (mcu_batch_current_row * mcu_vertical_samples[i] + v_pos) as usize;
577+
let block_x = (mcu_x * mcu_horizontal_samples[i] + h_pos) as usize;
578+
let block_offset = (block_y * component.block_size.width as usize + block_x) * 64;
579+
&mut mcu_row_coefficients[i][block_offset..block_offset + 64]
580+
} else {
581+
&mut dummy_block[..]
582+
};
583+
584+
if scan.successive_approximation_high == 0 {
585+
decode_block(&mut self.reader,
586+
coefficients,
587+
&mut huffman,
588+
self.dc_huffman_tables[scan.dc_table_indices[i]].as_ref(),
589+
self.ac_huffman_tables[scan.ac_table_indices[i]].as_ref(),
590+
scan.spectral_selection.clone(),
591+
scan.successive_approximation_low,
592+
&mut eob_run,
593+
&mut dc_predictors[i])?;
594+
}
595+
else {
596+
decode_block_successive_approximation(&mut self.reader,
597+
coefficients,
598+
&mut huffman,
599+
self.ac_huffman_tables[scan.ac_table_indices[i]].as_ref(),
600+
scan.spectral_selection.clone(),
601+
scan.successive_approximation_low,
602+
&mut eob_run)?;
603+
}
604+
}
605+
}
590606
}
591607
}
592608

593609
// Send the coefficients from this MCU row to the worker thread for dequantization and idct.
594610
for (i, component) in components.iter().enumerate() {
595611
if finished[i] {
612+
// In the event of non-interleaved streams, if we're still building the buffer out,
613+
// keep going; don't send it yet. We also need to ensure we don't skip over the last
614+
// row(s) of the image.
615+
if !is_interleaved && (mcu_y + 1) * 8 < frame.image_size.height {
616+
if (mcu_y + 1) % component.vertical_sampling_factor as u16 > 0 {
617+
continue;
618+
}
619+
}
620+
596621
let coefficients_per_mcu_row = component.block_size.width as usize * component.vertical_sampling_factor as usize * 64;
597622

598623
let row_coefficients = if is_progressive {
599-
let offset = mcu_y as usize * coefficients_per_mcu_row;
624+
// Because non-interleaved streams will have multiple MCU rows concatenated together,
625+
// the row for calculating the offset is different.
626+
let worker_mcu_y = if is_interleaved {
627+
mcu_y
628+
} else {
629+
// Explicitly doing floor-division here
630+
mcu_y / component.vertical_sampling_factor as u16
631+
};
632+
633+
let offset = worker_mcu_y as usize * coefficients_per_mcu_row;
600634
self.coefficients[scan.component_indices[i]][offset .. offset + coefficients_per_mcu_row].to_vec()
601635
} else {
602636
mem::replace(&mut mcu_row_coefficients[i], vec![0i16; coefficients_per_mcu_row])
572 Bytes
Loading
138 Bytes
Loading

0 commit comments

Comments
 (0)