Skip to content

Commit

Permalink
Fix panic with 1-row frames
Browse files Browse the repository at this point in the history
  • Loading branch information
valadaptive committed Sep 23, 2024
1 parent 499f964 commit 190a5e4
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 37 deletions.
4 changes: 3 additions & 1 deletion crates/gui/src/bin/ntsc-rs-standalone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::error::Error;
use gui::app::main::run;

fn main() -> Result<(), Box<dyn Error>> {
#[cfg(windows)]
#[cfg(all(windows, not(debug_assertions)))]
std::panic::set_hook(Box::new(|info| {
let backtrace = std::backtrace::Backtrace::force_capture();
rfd::MessageDialog::new()
Expand All @@ -14,6 +14,8 @@ fn main() -> Result<(), Box<dyn Error>> {
.set_description(format!("{info}\n\nBacktrace:\n{backtrace}"))
.set_title("Error")
.show();

std::process::exit(1);
}));

run()
Expand Down
18 changes: 12 additions & 6 deletions crates/ntscrs/src/ntsc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1349,21 +1349,27 @@ impl NtscEffect {
// fields in the top half and the odd/even fields in the bottom half.
match yiq.field {
YiqField::InterleavedUpper => {
let num_upper_rows = YiqField::Upper.num_image_rows(yiq.dimensions.1);
let num_upper_rows = YiqField::Upper.num_actual_image_rows(yiq.dimensions.1);
let (upper, lower) = yiq.split_at_row(num_upper_rows);
(upper, lower, frame_num * 2, frame_num * 2 + 1)
}
YiqField::InterleavedLower => {
let num_lower_rows = YiqField::Lower.num_image_rows(yiq.dimensions.1);
let num_lower_rows = YiqField::Lower.num_actual_image_rows(yiq.dimensions.1);
let (lower, upper) = yiq.split_at_row(num_lower_rows);
(upper, lower, frame_num * 2 + 1, frame_num * 2)
}
_ => unreachable!(),
};
yiq_upper.field = YiqField::Upper;
yiq_lower.field = YiqField::Lower;
self.apply_effect_to_yiq_field(&mut yiq_upper, frame_num_upper);
self.apply_effect_to_yiq_field(&mut yiq_lower, frame_num_lower);

if let Some(yiq_upper) = yiq_upper.as_mut() {
yiq_upper.field = YiqField::Upper;
self.apply_effect_to_yiq_field(yiq_upper, frame_num_upper);
}

if let Some(yiq_lower) = yiq_lower.as_mut() {
yiq_lower.field = YiqField::Lower;
self.apply_effect_to_yiq_field(yiq_lower, frame_num_lower);
}
}
})
}
Expand Down
103 changes: 73 additions & 30 deletions crates/ntscrs/src/yiq_fielding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,19 @@ impl YiqField {
}
}

/// The number of rows that correspond to this field for a given vertical resolution. Can be 0 unlike
/// `num_image_rows`.
pub fn num_actual_image_rows(&self, image_height: usize) -> usize {
// On an image with an odd input height, we do ceiling division if we render upper-field-first
// (take an image 3 pixels tall. it goes render, skip, render--that's 2 renders) but floor division if we
// render lower-field-first (skip, render, skip--only 1 render).
match self {
Self::Upper => (image_height + 1) / 2,
Self::Lower => image_height / 2,
Self::Both | Self::InterleavedUpper | Self::InterleavedLower => image_height,
}
}

/// Flips the field parity--upper becomes lower and vice versa.
pub fn flip(&self) -> Self {
match self {
Expand Down Expand Up @@ -359,32 +372,40 @@ impl<T: Fn([f32; 3]) -> [f32; 3] + Send + Sync + Copy> PixelTransform for T {}

impl<'a> YiqView<'a> {
/// Split this `YiqView` into two `YiqView`s vertically at a given row.
pub fn split_at_row(&mut self, idx: usize) -> (YiqView<'_>, YiqView<'_>) {
pub fn split_at_row(&mut self, idx: usize) -> (Option<YiqView<'_>>, Option<YiqView<'_>>) {
let (y1, y2) = self.y.split_at_mut(idx * self.dimensions.0);
let (i1, i2) = self.i.split_at_mut(idx * self.dimensions.0);
let (q1, q2) = self.q.split_at_mut(idx * self.dimensions.0);
let (s1, s2) = self.scratch.split_at_mut(idx * self.dimensions.0);
(
YiqView {
y: y1,
i: i1,
q: q1,
scratch: s1,
dimensions: (self.dimensions.0, self.dimensions.1),
field: self.field,
if y1.len() > 0 {
Some(YiqView {
y: y1,
i: i1,
q: q1,
scratch: s1,
dimensions: (self.dimensions.0, self.dimensions.1),
field: self.field,
})
} else {
None
},
YiqView {
y: y2,
i: i2,
q: q2,
scratch: s2,
dimensions: (self.dimensions.0, self.dimensions.1),
field: self.field,
if y2.len() > 0 {
Some(YiqView {
y: y2,
i: i2,
q: q2,
scratch: s2,
dimensions: (self.dimensions.0, self.dimensions.1),
field: self.field,
})
} else {
None
},
)
}

/// Number of actual rows of pixels being stored in this view. This will be smaller than `dimensions.1` if some
/// Number of rows of pixels being stored in this view. This will be smaller than `dimensions.1` if some
/// fields are being skipped.
pub fn num_rows(&self) -> usize {
self.field.num_image_rows(self.dimensions.1)
Expand Down Expand Up @@ -507,20 +528,46 @@ impl<'a> YiqView<'a> {
)
}
YiqField::InterleavedUpper => {
let num_upper_rows = YiqField::Upper.num_image_rows(self.dimensions.1);
let num_upper_rows = YiqField::Upper.num_actual_image_rows(self.dimensions.1);
let (mut upper, mut lower) = self.split_at_row(num_upper_rows);
upper.field = YiqField::Upper;
lower.field = YiqField::Lower;
upper.set_from_strided_buffer_maybe_uninit::<S, F>(buf, blit_info, pixel_transform);
lower.set_from_strided_buffer_maybe_uninit::<S, F>(buf, blit_info, pixel_transform);
if let Some(upper) = upper.as_mut() {
upper.field = YiqField::Upper;
upper.set_from_strided_buffer_maybe_uninit::<S, F>(
buf,
blit_info,
pixel_transform,
);
};

if let Some(lower) = lower.as_mut() {
lower.field = YiqField::Lower;
lower.set_from_strided_buffer_maybe_uninit::<S, F>(
buf,
blit_info,
pixel_transform,
);
};
}
YiqField::InterleavedLower => {
let num_lower_rows = YiqField::Lower.num_image_rows(self.dimensions.1);
let num_lower_rows = YiqField::Lower.num_actual_image_rows(self.dimensions.1);
let (mut lower, mut upper) = self.split_at_row(num_lower_rows);
upper.field = YiqField::Upper;
lower.field = YiqField::Lower;
upper.set_from_strided_buffer_maybe_uninit::<S, F>(buf, blit_info, pixel_transform);
lower.set_from_strided_buffer_maybe_uninit::<S, F>(buf, blit_info, pixel_transform);
if let Some(upper) = upper.as_mut() {
upper.field = YiqField::Upper;
upper.set_from_strided_buffer_maybe_uninit::<S, F>(
buf,
blit_info,
pixel_transform,
);
};

if let Some(lower) = lower.as_mut() {
lower.field = YiqField::Lower;
lower.set_from_strided_buffer_maybe_uninit::<S, F>(
buf,
blit_info,
pixel_transform,
);
};
}
}
}
Expand Down Expand Up @@ -815,10 +862,6 @@ pub struct YiqOwned {
}

impl YiqOwned {
pub fn num_rows(&self) -> usize {
self.field.num_image_rows(self.dimensions.1)
}

pub fn from_strided_buffer<S: PixelFormat>(
buf: &[S::DataFormat],
row_bytes: usize,
Expand Down

0 comments on commit 190a5e4

Please sign in to comment.