From 1c7bfd8c5f4304c5e8b68c7ca2c03de517f02e7d Mon Sep 17 00:00:00 2001 From: = Date: Sat, 20 Aug 2022 21:59:54 +0200 Subject: [PATCH] core: Use real Error enums for video backend --- core/src/backend/video.rs | 33 +++++++++++++- .../backend/video/software/decoders/h263.rs | 28 +++++++++--- .../backend/video/software/decoders/screen.rs | 41 ++++++++++++------ .../backend/video/software/decoders/vp6.rs | 43 +++++++++++-------- core/src/backend/video/software/mod.rs | 8 ++-- core/src/display_object/video.rs | 7 +-- 6 files changed, 112 insertions(+), 48 deletions(-) diff --git a/core/src/backend/video.rs b/core/src/backend/video.rs index d759b3b30..907c79022 100644 --- a/core/src/backend/video.rs +++ b/core/src/backend/video.rs @@ -4,6 +4,7 @@ use generational_arena::{Arena, Index}; use ruffle_render::backend::RenderBackend; use ruffle_render::bitmap::BitmapInfo; use swf::{VideoCodec, VideoDeblocking}; +use thiserror::Error; mod software; @@ -11,7 +12,35 @@ pub use crate::backend::video::software::SoftwareVideoBackend; pub type VideoStreamHandle = Index; -pub type Error = Box; +#[derive(Error, Debug)] +pub enum Error { + #[error("Attempted to seek to omitted frame {0} without prior decoded frame")] + SeekingBeforeDecoding(u32), + + #[error("Unsupported video codec type: {0:?}")] + UnsupportedCodec(VideoCodec), + + #[error("Video stream is not registered")] + VideoStreamIsNotRegistered, + + #[error("Couldn't create bitmap for video frame")] + BitmapError(#[from] ruffle_render::error::Error), + + #[error("Video decoding isn't supported")] + DecodingNotSupported, + + #[cfg(feature = "h263")] + #[error("H263 decoder error")] + H263Error(#[from] software::decoders::h263::H263Error), + + #[cfg(feature = "vp6")] + #[error("VP6 decoder error")] + VP6Error(#[from] software::decoders::vp6::Vp6Error), + + #[cfg(feature = "screenvideo")] + #[error("Screen Video decoder error")] + ScreenVideoError(#[from] software::decoders::screen::ScreenError), +} /// An encoded video frame of some video codec. pub struct EncodedFrame<'a> { @@ -178,6 +207,6 @@ impl VideoBackend for NullVideoBackend { _encoded_frame: EncodedFrame<'_>, _renderer: &mut dyn RenderBackend, ) -> Result { - Err("Video decoding not implemented".into()) + Err(Error::DecodingNotSupported) } } diff --git a/core/src/backend/video/software/decoders/h263.rs b/core/src/backend/video/software/decoders/h263.rs index 2b02e07b2..aadd8f16d 100644 --- a/core/src/backend/video/software/decoders/h263.rs +++ b/core/src/backend/video/software/decoders/h263.rs @@ -4,6 +4,21 @@ use h263_rs::parser::H263Reader; use h263_rs::{DecoderOption, H263State, PictureTypeCode}; use h263_rs_yuv::bt601::yuv420_to_rgba; +#[derive(thiserror::Error, Debug)] +pub enum H263Error { + #[error("Picture wasn't found in the video stream")] + NoPictureInVideoStream, + + #[error("Decoder error")] + DecoderError(#[from] h263_rs::Error), + + #[error("Invalid picture type code: {0:?}")] + InvalidPictureType(PictureTypeCode), + + #[error("Picture is missing width and height details")] + MissingWidthHeight, +} + /// H263 video decoder. pub struct H263Decoder(H263State); @@ -18,21 +33,24 @@ impl VideoDecoder for H263Decoder { let mut reader = H263Reader::from_source(encoded_frame.data()); let picture = self .0 - .parse_picture(&mut reader, None)? - .ok_or("Picture in video stream is not a picture")?; + .parse_picture(&mut reader, None) + .map_err(H263Error::DecoderError)? + .ok_or(H263Error::NoPictureInVideoStream)?; match picture.picture_type { PictureTypeCode::IFrame => Ok(FrameDependency::None), PictureTypeCode::PFrame => Ok(FrameDependency::Past), PictureTypeCode::DisposablePFrame => Ok(FrameDependency::Past), - _ => Err("Invalid picture type code!".into()), + code => Err(H263Error::InvalidPictureType(code).into()), } } fn decode_frame(&mut self, encoded_frame: EncodedFrame<'_>) -> Result { let mut reader = H263Reader::from_source(encoded_frame.data()); - self.0.decode_next_picture(&mut reader)?; + self.0 + .decode_next_picture(&mut reader) + .map_err(H263Error::DecoderError)?; let picture = self .0 @@ -42,7 +60,7 @@ impl VideoDecoder for H263Decoder { let (width, height) = picture .format() .into_width_and_height() - .ok_or("H.263 decoder error!")?; + .ok_or(H263Error::MissingWidthHeight)?; let chroma_width = picture.chroma_samples_per_row(); let (y, b, r) = picture.as_yuv(); let rgba = yuv420_to_rgba(y, b, r, width.into(), chroma_width); diff --git a/core/src/backend/video/software/decoders/screen.rs b/core/src/backend/video/software/decoders/screen.rs index cb971a8d9..411b9d502 100644 --- a/core/src/backend/video/software/decoders/screen.rs +++ b/core/src/backend/video/software/decoders/screen.rs @@ -6,6 +6,24 @@ use crate::backend::video::{DecodedFrame, EncodedFrame, Error, FrameDependency}; use flate2::Decompress; +#[derive(thiserror::Error, Debug)] +pub enum ScreenError { + #[error("Unexpected end of file")] + UnexpectedEOF, + + #[error("Decompression error")] + DecompressionError(#[from] flate2::DecompressError), + + #[error("Invalid frame type: {0}")] + InvalidFrameType(u8), + + #[error("Missing reference frame")] + MissingReferenceFrame, + + #[error("Not all blocks were updated by a supposed keyframe")] + KeyframeInvalid, +} + /// Screen Video (V1 only) decoder. pub struct ScreenVideoDecoder { w: usize, @@ -28,24 +46,24 @@ impl<'a> ByteReader<'a> { Self { data, pos: 0 } } - fn read_byte(&mut self) -> Result { + fn read_byte(&mut self) -> Result { if self.pos >= self.data.len() { - return Err(Error::from("Unexpected end of data")); + return Err(ScreenError::UnexpectedEOF); } let byte = self.data[self.pos]; self.pos += 1; Ok(byte) } - fn read_u16be(&mut self) -> Result { + fn read_u16be(&mut self) -> Result { let byte1 = self.read_byte()?; let byte2 = self.read_byte()?; Ok((byte1 as u16) << 8 | (byte2 as u16)) } - fn read_buf_ref(&mut self, length: usize) -> Result<&[u8], Error> { + fn read_buf_ref(&mut self, length: usize) -> Result<&[u8], ScreenError> { if self.pos + length > self.data.len() { - return Err(Error::from("Unexpected end of data")); + return Err(ScreenError::UnexpectedEOF); } let result = &self.data[self.pos..self.pos + length]; self.pos += length; @@ -85,7 +103,7 @@ impl ScreenVideoDecoder { &mut self.tile[..cur_w * cur_h * 3], flate2::FlushDecompress::Finish, ) - .map_err(|e| format!("Error while inflating block: {}", e))?; + .map_err(ScreenError::DecompressionError)?; for (dst, src) in row[x * 3..] .chunks_mut(stride) @@ -118,10 +136,7 @@ impl VideoDecoder for ScreenVideoDecoder { match encoded_frame.data[0] >> 4 { 1 => Ok(FrameDependency::None), 2 => Ok(FrameDependency::Past), - x => Err(Error::from(format!( - "Unexpected Screen Video frame type: {}", - x - ))), + x => Err(ScreenError::InvalidFrameType(x).into()), } } @@ -129,7 +144,7 @@ impl VideoDecoder for ScreenVideoDecoder { let is_keyframe = encoded_frame.data[0] >> 4 == 1; if !is_keyframe && self.last_frame.is_none() { - return Err(Error::from("Missing reference frame")); + return Err(ScreenError::MissingReferenceFrame.into()); } // Need to drop the extra preceding byte @@ -164,9 +179,7 @@ impl VideoDecoder for ScreenVideoDecoder { let is_intra = self.decode_v1(&mut br, data.as_mut_slice(), stride)?; if is_intra != is_keyframe { - return Err(Error::from( - "Not all blocks were updated by a supposed keyframe", - )); + return Err(ScreenError::KeyframeInvalid.into()); } let mut rgba = vec![0u8; w * h * 4]; diff --git a/core/src/backend/video/software/decoders/vp6.rs b/core/src/backend/video/software/decoders/vp6.rs index 8a85b3d5b..e8e50e09e 100644 --- a/core/src/backend/video/software/decoders/vp6.rs +++ b/core/src/backend/video/software/decoders/vp6.rs @@ -9,6 +9,25 @@ use nihav_core::codecs::NADecoderSupport; use nihav_duck::codecs::vp6::{VP56Decoder, VP56Parser, VP6BR}; use nihav_duck::codecs::vpcommon::{BoolCoder, VP_YUVA420_FORMAT}; +#[derive(thiserror::Error, Debug)] +pub enum Vp6Error { + #[error("Decoder error: {0:?}")] + // DecoderError doesn't impl Error... so this is manual. + DecoderError(nihav_core::codecs::DecoderError), + + #[error("Unexpected skip frame")] + UnexpectedSkipFrame, + + #[error("Invalid buffer type")] + InvalidBufferType, +} + +impl From for Vp6Error { + fn from(error: nihav_core::codecs::DecoderError) -> Self { + Vp6Error::DecoderError(error) + } +} + /// VP6 video decoder. pub struct Vp6Decoder { with_alpha: bool, @@ -72,16 +91,12 @@ impl VideoDecoder for Vp6Decoder { } else { encoded_frame.data }) - .map_err(|error| { - Error::from(format!("Error constructing VP6 bool coder: {:?}", error)) - })?; + .map_err(Vp6Error::DecoderError)?; let header = self .bitreader .parse_header(&mut bool_coder) - .map_err(|error| { - Error::from(format!("Error parsing VP6 frame header: {:?}", error)) - })?; + .map_err(Vp6Error::DecoderError)?; let video_info = NAVideoInfo::new( header.disp_w as usize * 16, @@ -96,9 +111,7 @@ impl VideoDecoder for Vp6Decoder { self.decoder .init(&mut self.support, video_info) - .map_err(|error| { - Error::from(format!("Error initializing VP6 decoder: {:?}", error)) - })?; + .map_err(Vp6Error::DecoderError)?; self.init_called = true; } @@ -110,11 +123,7 @@ impl VideoDecoder for Vp6Decoder { match &self.last_frame { Some(frame) => frame.clone(), - None => { - return Err(Error::from( - "No previous frame found when encountering a skip frame", - )) - } + None => return Err(Vp6Error::UnexpectedSkipFrame.into()), } } else { // Actually decoding the frame and extracting the buffer it is stored in. @@ -122,13 +131,11 @@ impl VideoDecoder for Vp6Decoder { let decoded = self .decoder .decode_frame(&mut self.support, encoded_frame.data, &mut self.bitreader) - .map_err(|error| Error::from(format!("VP6 decoder error: {:?}", error)))?; + .map_err(Vp6Error::DecoderError)?; let frame = match decoded { (Video(buffer), _) => Ok(buffer), - _ => Err(Error::from( - "Unexpected buffer type after decoding a VP6 frame", - )), + _ => Err(Vp6Error::InvalidBufferType), }?; self.last_frame = Some(frame.clone()); diff --git a/core/src/backend/video/software/mod.rs b/core/src/backend/video/software/mod.rs index 719b9084a..93578dff2 100644 --- a/core/src/backend/video/software/mod.rs +++ b/core/src/backend/video/software/mod.rs @@ -8,7 +8,7 @@ use ruffle_render::backend::RenderBackend; use ruffle_render::bitmap::{Bitmap, BitmapFormat, BitmapHandle, BitmapInfo}; use swf::{VideoCodec, VideoDeblocking}; -mod decoders; +pub mod decoders; #[cfg(feature = "h263")] use self::decoders::h263; @@ -57,7 +57,7 @@ impl VideoBackend for SoftwareVideoBackend { VideoCodec::Vp6WithAlpha => Box::new(vp6::Vp6Decoder::new(true, size)), #[cfg(feature = "screenvideo")] VideoCodec::ScreenVideo => Box::new(screen::ScreenVideoDecoder::new()), - _ => return Err(format!("Unsupported video codec type {:?}", codec).into()), + other => return Err(Error::UnsupportedCodec(other)), }; let stream = VideoStream::new(decoder); let stream_handle = self.streams.insert(stream); @@ -72,7 +72,7 @@ impl VideoBackend for SoftwareVideoBackend { let stream = self .streams .get_mut(stream) - .ok_or("Unregistered video stream")?; + .ok_or(Error::VideoStreamIsNotRegistered)?; stream.decoder.preload_frame(encoded_frame) } @@ -86,7 +86,7 @@ impl VideoBackend for SoftwareVideoBackend { let stream = self .streams .get_mut(stream) - .ok_or("Unregistered video stream")?; + .ok_or(Error::VideoStreamIsNotRegistered)?; let frame = stream.decoder.decode_frame(encoded_frame)?; let handle = if let Some(bitmap) = stream.bitmap { diff --git a/core/src/display_object/video.rs b/core/src/display_object/video.rs index cf56bc8fc..2352cba17 100644 --- a/core/src/display_object/video.rs +++ b/core/src/display_object/video.rs @@ -4,7 +4,7 @@ use crate::avm1::{Object as Avm1Object, StageObject as Avm1StageObject}; use crate::avm2::{ Activation as Avm2Activation, Object as Avm2Object, StageObject as Avm2StageObject, }; -use crate::backend::video::{EncodedFrame, VideoStreamHandle}; +use crate::backend::video::{EncodedFrame, Error, VideoStreamHandle}; use crate::context::{RenderContext, UpdateContext}; use crate::display_object::{DisplayObjectBase, DisplayObjectPtr, TDisplayObject}; use crate::prelude::*; @@ -257,10 +257,7 @@ impl<'gc> Video<'gc> { if let Some((_old_id, old_frame)) = read.decoded_frame { Ok(old_frame) } else { - Err(Box::from(format!( - "Attempted to seek to omitted frame {} without prior decoded frame", - frame_id - ))) + Err(Error::SeekingBeforeDecoding(frame_id)) } } },