core: Use real Error enums for video backend
This commit is contained in:
parent
17f261fc1f
commit
1c7bfd8c5f
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue