diff --git a/Cargo.lock b/Cargo.lock index 3c8c6a33..1366dcfa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -83,7 +83,7 @@ checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.32", ] [[package]] @@ -138,6 +138,7 @@ dependencies = [ "matroska-demuxer", "md5", "thiserror", + "zerocopy", ] [[package]] @@ -197,7 +198,7 @@ checksum = "b893c4eb2dc092c811165f84dc7447fae16fb66521717968c34c509b39b1a5c5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.32", ] [[package]] @@ -412,9 +413,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.27" +version = "2.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" dependencies = [ "proc-macro2", "quote", @@ -447,7 +448,7 @@ checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.32", ] [[package]] @@ -552,3 +553,24 @@ name = "windows_x86_64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "zerocopy" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c19fae0c8a9efc6a8281f2e623db8af1db9e57852e04cde3e754dd2dc29340f" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc56589e9ddd1f1c28d4b4b5c773ce232910a6bb67a70133d61c9e347585efe9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.32", +] diff --git a/Cargo.toml b/Cargo.toml index 0ab4c3b8..6fea10bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ libva = { git = "https://github.com/chromeos/cros-libva", rev = "905041a9", pack log = { version = "0", features = ["release_max_level_debug"] } thiserror = "1.0.31" crc32fast = "1.3.2" +zerocopy = { version = "0.7", features = ["derive"] } [dev-dependencies] argh = "0.1" diff --git a/src/decoder.rs b/src/decoder.rs index 4c44eab1..43c3daea 100644 --- a/src/decoder.rs +++ b/src/decoder.rs @@ -9,6 +9,7 @@ //! //! At the moment, only a [stateless] decoder interface is provided. +pub mod stateful; pub mod stateless; use std::collections::VecDeque; diff --git a/src/decoder/stateful.rs b/src/decoder/stateful.rs new file mode 100644 index 00000000..b1ef518e --- /dev/null +++ b/src/decoder/stateful.rs @@ -0,0 +1,169 @@ +// Copyright 2023 The ChromiumOS Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +use thiserror::Error; +use zerocopy::AsBytes; + +use crate::decoder::DecodedHandle; +use crate::decoder::StreamInfo; +use crate::DecodedFormat; +use crate::Resolution; + +use std::sync::Arc; + +pub enum DecodeError { + InvalidState, + InvalidData, +} + +pub enum ConfigError { + InvalidState, + NotSupported, + InvalidConfig, +} + +/// Error returned by stateful backend methods. +#[derive(Error, Debug)] +pub enum StatefulBackendError { + #[error("not enough resources to proceed with the operation now")] + OutOfResources, + #[error("this format is not supported")] + UnsupportedFormat, + #[error(transparent)] + Other(#[from] anyhow::Error), +} + +#[derive(Copy, Clone, Debug)] +pub enum EncodedFormat { + AV1, + H264, + H265, + VP8, + VP9, +} + +/// Common trait shared by all stateful video decoder backends, providing codec-independent +/// methods. +pub trait StatefulDecoderBackend { + /// The type that the backend returns as a result of a decode operation. + /// This will usually be some backend-specific type with a resource and a + /// resource pool so that said buffer can be reused for another decode + /// operation when it goes out of scope. + type Handle: DecodedHandle; + + /// Returns the current decoding parameters, as parsed from the stream. + fn stream_info(&self) -> Option<&StreamInfo>; +} + +pub trait StatefulCodec { + /// State that needs to be kept during a decoding operation, typed by backend. + type DecoderState>; +} + +#[derive(Copy, Clone, Debug)] + +pub enum ColorGamut { + Bt709, + Bt470bg, + Smpte170m, +} + +#[derive(Copy, Clone, Debug)] +pub enum ColorTransfer { + Bt709, + Smpte170m, + Iec61966_2_1, +} + +#[derive(Copy, Clone, Debug)] +pub enum ColorMatrix { + Rgb, + Bt709, + Bt470bg, + Smpte170m, +} + +#[derive(Copy, Clone, Debug)] +pub struct VideoColorSpace { + primaries: ColorGamut, + transfer: ColorTransfer, + matrix: ColorMatrix, +} + +#[derive(Clone, Debug)] +pub struct EncodedVideoChunk { + data: Arc>, +} + +pub struct VideoFrame { + format: DecodedFormat, + coded_resolution: Resolution, + display_resolution: Resolution, + duration: usize, + timestamp: usize, + color_space: VideoColorSpace, + buffer: Option>, +} + +pub enum StatefulDecoderEvent { + /// The next frame has been decoded. + FrameReady(VideoFrame), + /// The format of the stream has changed and action is required. A VideoFrame + /// with no buffer is returned. + FormatChanged(VideoFrame), +} + +pub trait StatefulVideoDecoder { + /// Add a new chunk of video to decoding queue, this is a non-blocking method + fn decode(&mut self, chunk: EncodedVideoChunk) -> Result<(), DecodeError>; + + /// Return information about the currently decoded stream + fn stream_info(&self) -> Option<&StreamInfo>; + + /// Close the decoder and prevent it from future use + fn close(&mut self); + + /// Finish processing all pending decode requests + fn flush(&mut self) -> Result<(), DecodeError>; + + /// Returns the next event, if there is any pending. + fn next_event(&mut self) -> Option; +} + +#[derive(Copy, Clone, Debug, Default)] +pub enum StatefulDecoderState { + #[default] + Unconfigured, + Configured, + Closed, +} + +pub struct StatefulDecoder +where + C: StatefulCodec, + B: StatefulDecoderBackend, +{ + decoding_state: StatefulDecoderState, + + /// The backend used for hardware acceleration. + backend: B, + + /// Codec-specific state. + codec_state: C::DecoderState, +} + +impl StatefulDecoder +where + C: StatefulCodec, + B: StatefulDecoderBackend, + C::DecoderState: Default, +{ + pub fn new(backend: B) -> Self { + Self { + backend, + decoding_state: Default::default(), + codec_state: Default::default(), + } + } +}