From 63b181170c0e3478d619bca0ba2be0687b1ac815 Mon Sep 17 00:00:00 2001 From: Harrison Booth <73434116+Harrison-Booth@users.noreply.github.com> Date: Wed, 28 Oct 2026 09:56:13 -0500 Subject: [PATCH] F-19: guard decoder picture setup against panics --- crates/h264/src/decoder.rs | 59 +++++++++++++++++++------------------- crates/hevc/src/decoder.rs | 28 +++++++++--------- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/crates/h264/src/decoder.rs b/crates/h264/src/decoder.rs index 37ef1f29..38bb17c3 100644 --- a/crates/h264/src/decoder.rs +++ b/crates/h264/src/decoder.rs @@ -557,16 +557,16 @@ impl Decoder { /// Decode all slices of one picture and publish its rows. fn run_job(frame: FrameRef, slices: Vec, shared: &Shared, draft: bool) { - let reuse = shared.pool.lock().ok().and_then(|mut p| p.pop()); - let mut pic = match reuse { - Some(mut p) if p.mb_w == frame.mb_w && p.mb_h == frame.mb_h() => { - p.reset(frame.clone()); - p - } - _ => PicState::new(frame.clone()), - }; - pic.skip_deblock = draft; let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + let reuse = shared.pool.lock().ok().and_then(|mut p| p.pop()); + let mut pic = match reuse { + Some(mut p) if p.mb_w == frame.mb_w && p.mb_h == frame.mb_h() => { + p.reset(frame.clone()); + p + } + _ => PicState::new(frame.clone()), + }; + pic.skip_deblock = draft; let mut first_err = None; for s in &slices { if let Err(e) = decode_slice(s, &mut pic) { @@ -574,10 +574,10 @@ fn run_job(frame: FrameRef, slices: Vec, shared: &Shared, draft: bool) } } pic.flush_rows(true); - first_err + (pic, first_err) })); - let err = match result { - Ok(e) => e, + let (pic, err) = match result { + Ok((pic, err)) => (Some(pic), err), Err(_) => { // Make sure readers never block on this frame. let fallback = Planes::gray(frame.width, frame.height); @@ -587,34 +587,35 @@ fn run_job(frame: FrameRef, slices: Vec, shared: &Shared, draft: bool) frame.publish(r, Frame::make_row(&fallback, r, &blank, &|_, _, _| u32::MAX)); } } - pic = PicState::new(frame.clone()); - Some(Error::Invalid("internal error while decoding a picture".into())) + (None, Some(Error::Invalid("internal error while decoding a picture".into()))) } }; if let Ok(mut s) = shared.stats.lock() { s.pictures += 1; s.draft_pictures += draft as u64; - for st in &pic.mbs { - match st.kind { - MbKind::I4x4 => s.mb_i4x4 += 1, - MbKind::I8x8 => s.mb_i8x8 += 1, - MbKind::I16x16 => s.mb_i16x16 += 1, - MbKind::IPcm => s.mb_pcm += 1, - MbKind::PSkip => s.mb_p_skip += 1, - MbKind::BSkip => s.mb_b_skip += 1, - MbKind::BDirect16x16 => s.mb_b_direct16x16 += 1, - MbKind::Inter => s.mb_inter += 1, - MbKind::None => {} - } - if st.transform_8x8 && !st.kind.is_intra() { - s.mb_inter_8x8_transform += 1; + if let Some(pic) = &pic { + for st in &pic.mbs { + match st.kind { + MbKind::I4x4 => s.mb_i4x4 += 1, + MbKind::I8x8 => s.mb_i8x8 += 1, + MbKind::I16x16 => s.mb_i16x16 += 1, + MbKind::IPcm => s.mb_pcm += 1, + MbKind::PSkip => s.mb_p_skip += 1, + MbKind::BSkip => s.mb_b_skip += 1, + MbKind::BDirect16x16 => s.mb_b_direct16x16 += 1, + MbKind::Inter => s.mb_inter += 1, + MbKind::None => {} + } + if st.transform_8x8 && !st.kind.is_intra() { + s.mb_inter_8x8_transform += 1; + } } } } if let (Some(e), Ok(mut slot)) = (err, shared.error.lock()) { slot.get_or_insert(e); } - if let Ok(mut p) = shared.pool.lock() + if let (Some(pic), Ok(mut p)) = (pic, shared.pool.lock()) && p.len() < 4 { p.push(pic); diff --git a/crates/hevc/src/decoder.rs b/crates/hevc/src/decoder.rs index 4b46044d..bcb5364b 100644 --- a/crates/hevc/src/decoder.rs +++ b/crates/hevc/src/decoder.rs @@ -561,9 +561,9 @@ fn run_job( draft: bool, shared: &Shared, ) { - let mut pic = PicState::new(frame.clone(), sps, pps, layout, scaling); - pic.draft = draft; let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + let mut pic = PicState::new(frame.clone(), sps, pps, layout, scaling); + pic.draft = draft; let mut first_err = None; for s in &slices { if let Err(e) = SliceDecoder::decode(&mut pic, s) { @@ -571,10 +571,10 @@ fn run_job( } } crate::filter::finish(&mut pic); - first_err + (pic, first_err) })); - let err = match result { - Ok(e) => e, + let (pic, err) = match result { + Ok((pic, err)) => (Some(pic), err), Err(_) => { // make sure readers never block on this frame let gray = Frame::gray(0, frame.poc, &frame); @@ -584,18 +584,20 @@ fn run_job( frame.publish(r, crate::picture::FrameRow { y: row.y.clone(), cb: row.cb.clone(), cr: row.cr.clone(), col: row.col.clone() }); } } - Some(Error::Invalid("internal error while decoding a picture".into())) + (None, Some(Error::Invalid("internal error while decoding a picture".into()))) } }; if let Ok(mut s) = shared.stats.lock() { s.pictures += 1; - for b in &pic.blk { - if b.flags & F_INTRA != 0 { - s.intra_4x4_blocks += 1; - } else if b.flags & F_SKIP != 0 { - s.skip_4x4_blocks += 1; - } else if b.flags != 0 { - s.inter_4x4_blocks += 1; + if let Some(pic) = &pic { + for b in &pic.blk { + if b.flags & F_INTRA != 0 { + s.intra_4x4_blocks += 1; + } else if b.flags & F_SKIP != 0 { + s.skip_4x4_blocks += 1; + } else if b.flags != 0 { + s.inter_4x4_blocks += 1; + } } } }