core: Use real Error enums for video backend

This commit is contained in:
= 2022-08-20 21:59:54 +02:00 committed by Nathan Adams
parent 17f261fc1f
commit 1c7bfd8c5f
6 changed files with 112 additions and 48 deletions

View File

@ -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<dyn std::error::Error>;
#[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<BitmapInfo, Error> {
Err("Video decoding not implemented".into())
Err(Error::DecodingNotSupported)
}
}

View File

@ -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<DecodedFrame, Error> {
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);

View File

@ -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<u8, Error> {
fn read_byte(&mut self) -> Result<u8, ScreenError> {
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<u16, Error> {
fn read_u16be(&mut self) -> Result<u16, ScreenError> {
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];

View File

@ -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<nihav_core::codecs::DecoderError> 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());

View File

@ -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 {

View File

@ -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))
}
}
},