media: cros-codecs: move methods from StatelessDecoderBackend to VideoDecoderBackend

Move some methods that are common for all codecs from the `HandleType`
type from StatelessDecoderBackend to VideoDecoderBackend.

This makes the `StatelessDecoderBackend` traits implement the
codec-specific part of the backend (which requires a custom interface),
while the `VideoDecoderBackend` trait implements the shared behavior
of the backend, regardless of the underlying codec.

This separation will also allow us to factorize the implementations of
these methods further down this series.

BUG=b:214478588
TEST=cargo test --features vaapi -p cros-codecs

Change-Id: Id9f6874a1a57531ff092975f3692b10f7c1afcae
Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/4123654
Commit-Queue: Alexandre Courbot <acourbot@chromium.org>
Reviewed-by: Keiichi Watanabe <keiichiw@chromium.org>
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.corp-partner.google.com>
This commit is contained in:
Alexandre Courbot 2022-12-22 15:36:40 +09:00 committed by crosvm LUCI
parent e010e848d5
commit 80b9fa53d7
11 changed files with 296 additions and 360 deletions

View file

@ -5,6 +5,7 @@
use std::cell::Ref;
use std::cell::RefCell;
use std::cell::RefMut;
use std::collections::VecDeque;
use std::rc::Rc;
use thiserror::Error;
@ -40,7 +41,15 @@ pub enum StatelessBackendError {
Other(#[from] anyhow::Error),
}
pub type StatelessBackendResult<T> = std::result::Result<T, StatelessBackendError>;
pub(crate) trait VideoDecoderBackend {
/// 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 coded resolution of the bitstream being processed.
/// This may be None if we have not read the stream parameters yet.
fn coded_resolution(&self) -> Option<Resolution>;
@ -62,6 +71,17 @@ pub(crate) trait VideoDecoderBackend {
/// Try altering the decoded format.
fn try_format(&mut self, format: DecodedFormat) -> Result<()>;
/// Poll for any ready pictures. `block` dictates whether this call should
/// block on the operation or return immediately.
fn poll(&mut self, blocking_mode: BlockingMode) -> Result<VecDeque<Self::Handle>>;
/// Whether the handle is ready for presentation. The decoder will check
/// this before returning the handle to clients.
fn handle_is_ready(&self, handle: &Self::Handle) -> bool;
/// Block on handle `handle`.
fn block_on_handle(&mut self, handle: &Self::Handle) -> StatelessBackendResult<()>;
}
pub trait VideoDecoder {

View file

@ -3,7 +3,6 @@
// found in the LICENSE file.
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;
use crate::decoders::h264::dpb::Dpb;
@ -11,11 +10,10 @@ use crate::decoders::h264::parser::Pps;
use crate::decoders::h264::parser::Slice;
use crate::decoders::h264::parser::Sps;
use crate::decoders::h264::picture::H264Picture;
use crate::decoders::BlockingMode;
use crate::decoders::DecodedHandle;
use crate::decoders::VideoDecoderBackend;
pub type Result<T> = std::result::Result<T, crate::decoders::StatelessBackendError>;
pub type Result<T> = crate::decoders::StatelessBackendResult<T>;
#[cfg(test)]
pub mod dummy;
@ -38,12 +36,6 @@ pub type AsBackendHandle<Handle> = <Handle as DecodedHandle>::BackendHandle;
/// mode, where it should return immediately with any previously decoded frames
/// that happen to be ready.
pub(crate) trait StatelessDecoderBackend: VideoDecoderBackend {
/// 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;
/// Called when a new SPS is parsed.
fn new_sequence(&mut self, sps: &Sps, dpb_size: usize) -> Result<()>;
@ -109,10 +101,6 @@ pub(crate) trait StatelessDecoderBackend: VideoDecoderBackend {
block: bool,
) -> Result<Self::Handle>;
/// Poll for any ready pictures. `block` dictates whether this call should
/// block on the operation or return immediately.
fn poll(&mut self, blocking_mode: BlockingMode) -> Result<VecDeque<Self::Handle>>;
/// Indicates that the decoder has split a picture and that a new Handle
/// must be obtained.
fn new_handle(
@ -120,13 +108,6 @@ pub(crate) trait StatelessDecoderBackend: VideoDecoderBackend {
picture: ContainedPicture<AsBackendHandle<Self::Handle>>,
) -> Result<Self::Handle>;
/// Whether the handle is ready for presentation. The decoder will check
/// this before returning the handle to clients.
fn handle_is_ready(&self, handle: &Self::Handle) -> bool;
/// Block on handle `handle`.
fn block_on_handle(&mut self, handle: &Self::Handle) -> Result<()>;
/// Get the test parameters for the backend. The caller is reponsible for
/// downcasting them to the correct type, which is backend-dependent.
#[cfg(test)]

View file

@ -6,11 +6,9 @@
//! run so we can test it in isolation.
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;
use crate::decoders::h264::backends::AsBackendHandle;
use crate::decoders::h264::backends::BlockingMode;
use crate::decoders::h264::backends::ContainedPicture;
use crate::decoders::h264::backends::Result as StatelessBackendResult;
use crate::decoders::h264::backends::StatelessDecoderBackend;
@ -20,11 +18,10 @@ use crate::decoders::h264::parser::Pps;
use crate::decoders::h264::parser::Slice;
use crate::decoders::h264::parser::Sps;
use crate::decoders::h264::picture::H264Picture;
use crate::decoders::BlockingMode;
use crate::utils::dummy::*;
impl StatelessDecoderBackend for Backend {
type Handle = Handle<H264Picture<BackendHandle>>;
impl StatelessDecoderBackend for Backend<H264Picture<BackendHandle>> {
fn new_sequence(&mut self, _: &Sps, _: usize) -> StatelessBackendResult<()> {
Ok(())
}
@ -72,10 +69,6 @@ impl StatelessDecoderBackend for Backend {
})
}
fn poll(&mut self, _: BlockingMode) -> StatelessBackendResult<VecDeque<Self::Handle>> {
Ok(VecDeque::new())
}
fn new_handle(
&mut self,
picture: ContainedPicture<AsBackendHandle<Self::Handle>>,
@ -99,14 +92,6 @@ impl StatelessDecoderBackend for Backend {
Ok(())
}
fn handle_is_ready(&self, _: &Self::Handle) -> bool {
true
}
fn block_on_handle(&mut self, _: &Self::Handle) -> StatelessBackendResult<()> {
Ok(())
}
#[cfg(test)]
fn get_test_params(&self) -> &dyn std::any::Any {
// There are no test parameters for the dummy backend.
@ -117,6 +102,6 @@ impl StatelessDecoderBackend for Backend {
impl Decoder<Handle<H264Picture<BackendHandle>>> {
// Creates a new instance of the decoder using the dummy backend.
pub fn new_dummy(blocking_mode: BlockingMode) -> anyhow::Result<Self> {
Self::new(Box::new(Backend), blocking_mode)
Self::new(Box::new(Backend::new()), blocking_mode)
}
}

View file

@ -21,9 +21,7 @@ use libva::SliceParameter;
use libva::UsageHint;
use log::debug;
use crate::decoders::h264::backends::BlockingMode;
use crate::decoders::h264::backends::ContainedPicture;
use crate::decoders::h264::backends::DecodedHandle;
use crate::decoders::h264::backends::Result as StatelessBackendResult;
use crate::decoders::h264::backends::StatelessDecoderBackend;
use crate::decoders::h264::decoder::Decoder;
@ -35,6 +33,8 @@ use crate::decoders::h264::parser::Sps;
use crate::decoders::h264::picture::Field;
use crate::decoders::h264::picture::H264Picture;
use crate::decoders::h264::picture::Reference;
use crate::decoders::BlockingMode;
use crate::decoders::DecodedHandle;
use crate::decoders::Error as DecoderError;
use crate::decoders::Result as DecoderResult;
use crate::decoders::StatelessBackendError;
@ -51,7 +51,7 @@ use crate::DecodedFormat;
use crate::Resolution;
/// Resolves to the type used as Handle by the backend.
type AssociatedHandle = <Backend as StatelessDecoderBackend>::Handle;
type AssociatedHandle = <Backend as VideoDecoderBackend>::Handle;
#[cfg(test)]
#[derive(Default)]
@ -609,6 +609,8 @@ impl Backend {
}
impl VideoDecoderBackend for Backend {
type Handle = VADecodedHandle<H264Picture<GenericBackendHandle>>;
fn num_resources_total(&self) -> usize {
self.num_allocated_surfaces
}
@ -667,11 +669,81 @@ impl VideoDecoderBackend for Backend {
fn display_resolution(&self) -> Option<Resolution> {
self.metadata_state.display_resolution().ok()
}
fn poll(&mut self, blocking_mode: BlockingMode) -> DecoderResult<VecDeque<Self::Handle>> {
let mut completed = VecDeque::new();
let candidates = self.pending_jobs.drain(..).collect::<VecDeque<_>>();
for job in candidates {
if matches!(blocking_mode, BlockingMode::NonBlocking) {
let status = job.va_picture.query_status()?;
if status != libva::VASurfaceStatus::VASurfaceReady {
self.pending_jobs.push_back(job);
continue;
}
}
let current_picture = job.va_picture.sync()?;
let map_format = self.metadata_state.map_format()?;
let backend_handle = GenericBackendHandle::new_ready(
current_picture,
Rc::clone(map_format),
self.metadata_state.display_resolution()?,
);
job.codec_picture.borrow_mut().backend_handle = Some(backend_handle);
completed.push_back(job.codec_picture);
}
let completed = completed.into_iter().map(|picture| {
self.build_va_decoded_handle(&picture)
.map_err(|e| DecoderError::from(StatelessBackendError::Other(anyhow!(e))))
});
completed.collect::<Result<VecDeque<_>, _>>()
}
fn handle_is_ready(&self, handle: &Self::Handle) -> bool {
match &handle.picture().backend_handle {
Some(backend_handle) => backend_handle.is_ready(),
None => true,
}
}
fn block_on_handle(&mut self, handle: &Self::Handle) -> StatelessBackendResult<()> {
for i in 0..self.pending_jobs.len() {
// Remove from the queue in order.
let job = &self.pending_jobs[i];
if H264Picture::same(&job.codec_picture, handle.picture_container()) {
let job = self.pending_jobs.remove(i).unwrap();
let current_picture = job.va_picture.sync()?;
let map_format = self.metadata_state.map_format()?;
let backend_handle = GenericBackendHandle::new_ready(
current_picture,
Rc::clone(map_format),
self.metadata_state.display_resolution()?,
);
job.codec_picture.borrow_mut().backend_handle = Some(backend_handle);
return Ok(());
}
}
Err(StatelessBackendError::Other(anyhow!(
"Asked to block on a pending job that doesn't exist"
)))
}
}
impl StatelessDecoderBackend for Backend {
type Handle = VADecodedHandle<H264Picture<GenericBackendHandle>>;
fn new_sequence(&mut self, sps: &Sps, dpb_size: usize) -> StatelessBackendResult<()> {
self.open(sps, dpb_size, None)?;
self.negotiation_status = NegotiationStatus::Possible(Box::new((sps.clone(), dpb_size)));
@ -802,45 +874,6 @@ impl StatelessDecoderBackend for Backend {
.map_err(|e| StatelessBackendError::Other(anyhow!(e)))
}
fn poll(
&mut self,
blocking_mode: BlockingMode,
) -> StatelessBackendResult<VecDeque<Self::Handle>> {
let mut completed = VecDeque::new();
let candidates = self.pending_jobs.drain(..).collect::<VecDeque<_>>();
for job in candidates {
if matches!(blocking_mode, BlockingMode::NonBlocking) {
let status = job.va_picture.query_status()?;
if status != libva::VASurfaceStatus::VASurfaceReady {
self.pending_jobs.push_back(job);
continue;
}
}
let current_picture = job.va_picture.sync()?;
let map_format = self.metadata_state.map_format()?;
let backend_handle = GenericBackendHandle::new_ready(
current_picture,
Rc::clone(map_format),
self.metadata_state.display_resolution()?,
);
job.codec_picture.borrow_mut().backend_handle = Some(backend_handle);
completed.push_back(job.codec_picture);
}
let completed = completed.into_iter().map(|picture| {
self.build_va_decoded_handle(&picture)
.map_err(|e| StatelessBackendError::Other(anyhow!(e)))
});
completed.collect::<Result<VecDeque<_>, StatelessBackendError>>()
}
fn new_handle(
&mut self,
picture: ContainedPicture<GenericBackendHandle>,
@ -906,42 +939,6 @@ impl StatelessDecoderBackend for Backend {
Ok(())
}
fn handle_is_ready(&self, handle: &Self::Handle) -> bool {
match &handle.picture().backend_handle {
Some(backend_handle) => backend_handle.is_ready(),
None => true,
}
}
fn block_on_handle(&mut self, handle: &Self::Handle) -> StatelessBackendResult<()> {
for i in 0..self.pending_jobs.len() {
// Remove from the queue in order.
let job = &self.pending_jobs[i];
if H264Picture::same(&job.codec_picture, handle.picture_container()) {
let job = self.pending_jobs.remove(i).unwrap();
let current_picture = job.va_picture.sync()?;
let map_format = self.metadata_state.map_format()?;
let backend_handle = GenericBackendHandle::new_ready(
current_picture,
Rc::clone(map_format),
self.metadata_state.display_resolution()?,
);
job.codec_picture.borrow_mut().backend_handle = Some(backend_handle);
return Ok(());
}
}
Err(StatelessBackendError::Other(anyhow!(
"Asked to block on a pending job that doesn't exist"
)))
}
#[cfg(test)]
fn get_test_params(&self) -> &dyn std::any::Any {
&self.test_params
@ -963,12 +960,12 @@ mod tests {
use crate::decoders::h264::backends::vaapi::AssociatedHandle;
use crate::decoders::h264::backends::vaapi::TestParams;
use crate::decoders::h264::backends::BlockingMode;
use crate::decoders::h264::backends::DecodedHandle;
use crate::decoders::h264::backends::StatelessDecoderBackend;
use crate::decoders::h264::decoder::tests::process_ready_frames;
use crate::decoders::h264::decoder::tests::run_decoding_loop;
use crate::decoders::h264::decoder::Decoder;
use crate::decoders::BlockingMode;
use crate::decoders::DecodedHandle;
use crate::decoders::DynPicture;
fn get_test_params(

View file

@ -3,13 +3,11 @@
// found in the LICENSE file.
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;
use crate::decoders::vp8::parser::Header;
use crate::decoders::vp8::parser::Parser;
use crate::decoders::vp8::picture::Vp8Picture;
use crate::decoders::BlockingMode;
use crate::decoders::DecodedHandle;
use crate::decoders::VideoDecoderBackend;
@ -18,7 +16,7 @@ pub mod dummy;
#[cfg(feature = "vaapi")]
pub mod vaapi;
pub type Result<T> = std::result::Result<T, crate::decoders::StatelessBackendError>;
pub type Result<T> = crate::decoders::StatelessBackendResult<T>;
/// The container type for the picture. Pictures must offer interior mutability
/// as they may be shared.
@ -35,12 +33,6 @@ pub type AsBackendHandle<Handle> = <Handle as DecodedHandle>::BackendHandle;
/// mode, where it should return immediately with any previously decoded frames
/// that happen to be ready.
pub(crate) trait StatelessDecoderBackend: VideoDecoderBackend {
/// 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;
/// Called when new stream parameters are found.
fn new_sequence(&mut self, header: &Header) -> Result<()>;
@ -63,17 +55,6 @@ pub(crate) trait StatelessDecoderBackend: VideoDecoderBackend {
block: bool,
) -> Result<Self::Handle>;
/// Poll for any ready pictures. `block` dictates whether this call should
/// block on the operation or return immediately.
fn poll(&mut self, blocking_mode: BlockingMode) -> Result<VecDeque<Self::Handle>>;
/// Whether the handle is ready for presentation. The decoder will check
/// this before returning the handle to clients.
fn handle_is_ready(&self, handle: &Self::Handle) -> bool;
/// Block on handle `handle`.
fn block_on_handle(&mut self, handle: &Self::Handle) -> Result<()>;
/// Get the test parameters for the backend. The caller is reponsible for
/// downcasting them to the correct type, which is backend-dependent.
#[cfg(test)]

View file

@ -6,7 +6,6 @@
// run so we can test it in isolation.
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;
use crate::decoders::vp8::backends::StatelessDecoderBackend;
@ -15,9 +14,7 @@ use crate::decoders::vp8::decoder::Decoder;
use crate::decoders::BlockingMode;
use crate::utils::dummy::*;
impl StatelessDecoderBackend for Backend {
type Handle = Handle<Vp8Picture<BackendHandle>>;
impl StatelessDecoderBackend for Backend<Vp8Picture<BackendHandle>> {
fn new_sequence(&mut self, _: &crate::decoders::vp8::parser::Header) -> super::Result<()> {
Ok(())
}
@ -38,18 +35,6 @@ impl StatelessDecoderBackend for Backend {
})
}
fn poll(&mut self, _: super::BlockingMode) -> super::Result<VecDeque<Self::Handle>> {
Ok(VecDeque::new())
}
fn handle_is_ready(&self, _: &Self::Handle) -> bool {
true
}
fn block_on_handle(&mut self, _: &Self::Handle) -> super::Result<()> {
Ok(())
}
#[cfg(test)]
fn get_test_params(&self) -> &dyn std::any::Any {
// There are no test parameters for the dummy backend.
@ -60,6 +45,6 @@ impl StatelessDecoderBackend for Backend {
impl Decoder<Handle<Vp8Picture<BackendHandle>>> {
// Creates a new instance of the decoder using the dummy backend.
pub fn new_dummy(blocking_mode: BlockingMode) -> anyhow::Result<Self> {
Self::new(Box::new(Backend), blocking_mode)
Self::new(Box::new(Backend::new()), blocking_mode)
}
}

View file

@ -21,9 +21,7 @@ use libva::UsageHint;
use crate::decoders::h264::backends::Result as StatelessBackendResult;
use crate::decoders::vp8::backends::AsBackendHandle;
use crate::decoders::vp8::backends::BlockingMode;
use crate::decoders::vp8::backends::ContainedPicture;
use crate::decoders::vp8::backends::DecodedHandle;
use crate::decoders::vp8::backends::StatelessDecoderBackend;
use crate::decoders::vp8::backends::Vp8Picture;
use crate::decoders::vp8::decoder::Decoder;
@ -31,6 +29,8 @@ use crate::decoders::vp8::parser::Header;
use crate::decoders::vp8::parser::MbLfAdjustments;
use crate::decoders::vp8::parser::Parser;
use crate::decoders::vp8::parser::Segmentation;
use crate::decoders::BlockingMode;
use crate::decoders::DecodedHandle;
use crate::decoders::Error as DecoderError;
use crate::decoders::Result as DecoderResult;
use crate::decoders::StatelessBackendError;
@ -47,7 +47,7 @@ use crate::DecodedFormat;
use crate::Resolution;
/// Resolves to the type used as Handle by the backend.
type AssociatedHandle = <Backend as StatelessDecoderBackend>::Handle;
type AssociatedHandle = <Backend as VideoDecoderBackend>::Handle;
/// The number of surfaces to allocate for this codec. Same as GStreamer's vavp8dec.
const NUM_SURFACES: usize = 7;
@ -371,8 +371,6 @@ impl Backend {
}
impl StatelessDecoderBackend for Backend {
type Handle = VADecodedHandle<Vp8Picture<GenericBackendHandle>>;
fn new_sequence(&mut self, header: &Header) -> StatelessBackendResult<()> {
self.open(header, None)?;
self.negotiation_status = NegotiationStatus::Possible(Box::new(header.clone()));
@ -487,81 +485,6 @@ impl StatelessDecoderBackend for Backend {
.map_err(|e| StatelessBackendError::Other(anyhow!(e)))
}
fn poll(
&mut self,
blocking_mode: super::BlockingMode,
) -> StatelessBackendResult<VecDeque<Self::Handle>> {
let mut completed = VecDeque::new();
let candidates = self.pending_jobs.drain(..).collect::<VecDeque<_>>();
for job in candidates {
if matches!(blocking_mode, BlockingMode::NonBlocking) {
let status = job.va_picture.query_status()?;
if status != libva::VASurfaceStatus::VASurfaceReady {
self.pending_jobs.push_back(job);
continue;
}
}
let current_picture = job.va_picture.sync()?;
let map_format = self.metadata_state.map_format()?;
let backend_handle = GenericBackendHandle::new_ready(
current_picture,
Rc::clone(map_format),
self.metadata_state.display_resolution()?,
);
job.codec_picture.borrow_mut().backend_handle = Some(backend_handle);
completed.push_back(job.codec_picture);
}
let completed = completed.into_iter().map(|picture| {
self.build_va_decoded_handle(&picture)
.map_err(|e| StatelessBackendError::Other(anyhow!(e)))
});
completed.collect::<Result<VecDeque<_>, StatelessBackendError>>()
}
fn handle_is_ready(&self, handle: &Self::Handle) -> bool {
match &handle.picture().backend_handle {
Some(backend_handle) => backend_handle.is_ready(),
None => true,
}
}
fn block_on_handle(&mut self, handle: &Self::Handle) -> StatelessBackendResult<()> {
for i in 0..self.pending_jobs.len() {
// Remove from the queue in order.
let job = &self.pending_jobs[i];
if Vp8Picture::same(&job.codec_picture, handle.picture_container()) {
let job = self.pending_jobs.remove(i).unwrap();
let current_picture = job.va_picture.sync()?;
let map_format = self.metadata_state.map_format()?;
let backend_handle = GenericBackendHandle::new_ready(
current_picture,
Rc::clone(map_format),
self.metadata_state.display_resolution()?,
);
job.codec_picture.borrow_mut().backend_handle = Some(backend_handle);
return Ok(());
}
}
Err(StatelessBackendError::Other(anyhow!(
"Asked to block on a pending job that doesn't exist"
)))
}
#[cfg(test)]
fn get_test_params(&self) -> &dyn Any {
&self.test_params
@ -569,6 +492,8 @@ impl StatelessDecoderBackend for Backend {
}
impl VideoDecoderBackend for Backend {
type Handle = VADecodedHandle<Vp8Picture<GenericBackendHandle>>;
fn coded_resolution(&self) -> Option<Resolution> {
self.metadata_state.coded_resolution().ok()
}
@ -626,6 +551,78 @@ impl VideoDecoderBackend for Backend {
))
}
}
fn poll(&mut self, blocking_mode: BlockingMode) -> DecoderResult<VecDeque<Self::Handle>> {
let mut completed = VecDeque::new();
let candidates = self.pending_jobs.drain(..).collect::<VecDeque<_>>();
for job in candidates {
if matches!(blocking_mode, BlockingMode::NonBlocking) {
let status = job.va_picture.query_status()?;
if status != libva::VASurfaceStatus::VASurfaceReady {
self.pending_jobs.push_back(job);
continue;
}
}
let current_picture = job.va_picture.sync()?;
let map_format = self.metadata_state.map_format()?;
let backend_handle = GenericBackendHandle::new_ready(
current_picture,
Rc::clone(map_format),
self.metadata_state.display_resolution()?,
);
job.codec_picture.borrow_mut().backend_handle = Some(backend_handle);
completed.push_back(job.codec_picture);
}
let completed = completed.into_iter().map(|picture| {
self.build_va_decoded_handle(&picture)
.map_err(|e| DecoderError::from(StatelessBackendError::Other(anyhow!(e))))
});
completed.collect::<Result<VecDeque<_>, _>>()
}
fn handle_is_ready(&self, handle: &Self::Handle) -> bool {
match &handle.picture().backend_handle {
Some(backend_handle) => backend_handle.is_ready(),
None => true,
}
}
fn block_on_handle(&mut self, handle: &Self::Handle) -> StatelessBackendResult<()> {
for i in 0..self.pending_jobs.len() {
// Remove from the queue in order.
let job = &self.pending_jobs[i];
if Vp8Picture::same(&job.codec_picture, handle.picture_container()) {
let job = self.pending_jobs.remove(i).unwrap();
let current_picture = job.va_picture.sync()?;
let map_format = self.metadata_state.map_format()?;
let backend_handle = GenericBackendHandle::new_ready(
current_picture,
Rc::clone(map_format),
self.metadata_state.display_resolution()?,
);
job.codec_picture.borrow_mut().backend_handle = Some(backend_handle);
return Ok(());
}
}
Err(StatelessBackendError::Other(anyhow!(
"Asked to block on a pending job that doesn't exist"
)))
}
}
impl Decoder<VADecodedHandle<Vp8Picture<GenericBackendHandle>>> {
@ -647,12 +644,12 @@ mod tests {
use crate::decoders::vp8::backends::vaapi::AssociatedHandle;
use crate::decoders::vp8::backends::vaapi::TestParams;
use crate::decoders::vp8::backends::BlockingMode;
use crate::decoders::vp8::backends::DecodedHandle;
use crate::decoders::vp8::backends::StatelessDecoderBackend;
use crate::decoders::vp8::decoder::tests::process_ready_frames;
use crate::decoders::vp8::decoder::tests::run_decoding_loop;
use crate::decoders::vp8::decoder::Decoder;
use crate::decoders::BlockingMode;
use crate::decoders::DecodedHandle;
use crate::decoders::DynPicture;
fn get_test_params(

View file

@ -3,13 +3,11 @@
// found in the LICENSE file.
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;
use crate::decoders::vp9::parser::Header;
use crate::decoders::vp9::parser::NUM_REF_FRAMES;
use crate::decoders::vp9::picture::Vp9Picture;
use crate::decoders::BlockingMode;
use crate::decoders::DecodedHandle;
use crate::decoders::VideoDecoderBackend;
@ -18,7 +16,7 @@ pub mod dummy;
#[cfg(feature = "vaapi")]
pub mod vaapi;
pub type Result<T> = std::result::Result<T, crate::decoders::StatelessBackendError>;
pub type Result<T> = crate::decoders::StatelessBackendResult<T>;
/// The container type for the picture. Pictures must offer interior mutability
/// as they may be shared.
@ -35,12 +33,6 @@ pub type AsBackendHandle<Handle> = <Handle as DecodedHandle>::BackendHandle;
/// mode, where it should return immediately with any previously decoded frames
/// that happen to be ready.
pub(crate) trait StatelessDecoderBackend: VideoDecoderBackend {
/// 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;
/// Called when new stream parameters are found.
fn new_sequence(&mut self, header: &Header) -> Result<()>;
@ -60,17 +52,6 @@ pub(crate) trait StatelessDecoderBackend: VideoDecoderBackend {
block: bool,
) -> Result<Self::Handle>;
/// Poll for any ready pictures. `block` dictates whether this call should
/// block on the operation or return immediately.
fn poll(&mut self, blocking_mode: BlockingMode) -> Result<VecDeque<Self::Handle>>;
/// Whether the handle is ready for presentation. The decoder will check
/// this before returning the handle to clients.
fn handle_is_ready(&self, handle: &Self::Handle) -> bool;
/// Block on handle `handle`.
fn block_on_handle(&mut self, handle: &Self::Handle) -> Result<()>;
/// Get the test parameters for the backend. The caller is reponsible for
/// downcasting them to the correct type, which is backend-dependent.
#[cfg(test)]

View file

@ -6,7 +6,6 @@
//! run so we can test it in isolation.
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;
use crate::decoders::vp9::backends::StatelessDecoderBackend;
@ -16,9 +15,7 @@ use crate::decoders::vp9::parser::NUM_REF_FRAMES;
use crate::decoders::BlockingMode;
use crate::utils::dummy::*;
impl StatelessDecoderBackend for Backend {
type Handle = Handle<Vp9Picture<BackendHandle>>;
impl StatelessDecoderBackend for Backend<Vp9Picture<BackendHandle>> {
fn new_sequence(&mut self, _: &crate::decoders::vp9::parser::Header) -> super::Result<()> {
Ok(())
}
@ -36,18 +33,6 @@ impl StatelessDecoderBackend for Backend {
})
}
fn poll(&mut self, _: super::BlockingMode) -> super::Result<VecDeque<Self::Handle>> {
Ok(VecDeque::new())
}
fn handle_is_ready(&self, _: &Self::Handle) -> bool {
true
}
fn block_on_handle(&mut self, _: &Self::Handle) -> super::Result<()> {
Ok(())
}
#[cfg(test)]
fn get_test_params(&self) -> &dyn std::any::Any {
// There are no test parameters for the dummy backend.
@ -58,6 +43,6 @@ impl StatelessDecoderBackend for Backend {
impl Decoder<Handle<Vp9Picture<BackendHandle>>> {
// Creates a new instance of the decoder using the dummy backend.
pub fn new_dummy(blocking_mode: BlockingMode) -> anyhow::Result<Self> {
Self::new(Box::new(Backend), blocking_mode)
Self::new(Box::new(Backend::new()), blocking_mode)
}
}

View file

@ -16,9 +16,7 @@ use libva::SegmentParameterVP9;
use libva::UsageHint;
use crate::decoders::vp9::backends::AsBackendHandle;
use crate::decoders::vp9::backends::BlockingMode;
use crate::decoders::vp9::backends::ContainedPicture;
use crate::decoders::vp9::backends::DecodedHandle;
use crate::decoders::vp9::backends::Result as StatelessBackendResult;
use crate::decoders::vp9::backends::StatelessDecoderBackend;
use crate::decoders::vp9::backends::Vp9Picture;
@ -44,6 +42,8 @@ use crate::decoders::vp9::parser::NUM_REF_FRAMES;
use crate::decoders::vp9::parser::SEG_LVL_ALT_L;
use crate::decoders::vp9::parser::SEG_LVL_REF_FRAME;
use crate::decoders::vp9::parser::SEG_LVL_SKIP;
use crate::decoders::BlockingMode;
use crate::decoders::DecodedHandle;
use crate::decoders::Error as DecoderError;
use crate::decoders::Result as DecoderResult;
use crate::decoders::StatelessBackendError;
@ -60,7 +60,7 @@ use crate::DecodedFormat;
use crate::Resolution;
/// Resolves to the type used as Handle by the backend.
type AssociatedHandle = <Backend as StatelessDecoderBackend>::Handle;
type AssociatedHandle = <Backend as VideoDecoderBackend>::Handle;
/// The number of surfaces to allocate for this codec.
const NUM_SURFACES: usize = 12;
@ -582,8 +582,6 @@ impl Backend {
}
impl StatelessDecoderBackend for Backend {
type Handle = VADecodedHandle<Vp9Picture<GenericBackendHandle>>;
fn new_sequence(&mut self, header: &Header) -> StatelessBackendResult<()> {
self.open(header, None)?;
self.negotiation_status = NegotiationStatus::Possible(Box::new(header.clone()));
@ -674,81 +672,6 @@ impl StatelessDecoderBackend for Backend {
.map_err(|e| StatelessBackendError::Other(anyhow!(e)))
}
fn poll(
&mut self,
blocking_mode: super::BlockingMode,
) -> StatelessBackendResult<VecDeque<Self::Handle>> {
let mut completed = VecDeque::new();
let candidates = self.pending_jobs.drain(..).collect::<VecDeque<_>>();
for job in candidates {
if matches!(blocking_mode, BlockingMode::NonBlocking) {
let status = job.va_picture.query_status()?;
if status != libva::VASurfaceStatus::VASurfaceReady {
self.pending_jobs.push_back(job);
continue;
}
}
let current_picture = job.va_picture.sync()?;
let map_format = self.metadata_state.map_format()?;
let backend_handle = GenericBackendHandle::new_ready(
current_picture,
Rc::clone(map_format),
self.metadata_state.display_resolution()?,
);
job.codec_picture.borrow_mut().backend_handle = Some(backend_handle);
completed.push_back(job.codec_picture);
}
let completed = completed.into_iter().map(|picture| {
self.build_va_decoded_handle(&picture)
.map_err(|e| StatelessBackendError::Other(anyhow!(e)))
});
completed.collect::<Result<VecDeque<_>, StatelessBackendError>>()
}
fn handle_is_ready(&self, handle: &Self::Handle) -> bool {
match &handle.picture().backend_handle {
Some(backend_handle) => backend_handle.is_ready(),
None => true,
}
}
fn block_on_handle(&mut self, handle: &Self::Handle) -> StatelessBackendResult<()> {
for i in 0..self.pending_jobs.len() {
// Remove from the queue in order.
let job = &self.pending_jobs[i];
if Vp9Picture::same(&job.codec_picture, handle.picture_container()) {
let job = self.pending_jobs.remove(i).unwrap();
let current_picture = job.va_picture.sync()?;
let map_format = self.metadata_state.map_format()?;
let backend_handle = GenericBackendHandle::new_ready(
current_picture,
Rc::clone(map_format),
self.metadata_state.display_resolution()?,
);
job.codec_picture.borrow_mut().backend_handle = Some(backend_handle);
return Ok(());
}
}
Err(StatelessBackendError::Other(anyhow!(
"Asked to block on a pending job that doesn't exist"
)))
}
#[cfg(test)]
fn get_test_params(&self) -> &dyn std::any::Any {
&self.test_params
@ -756,6 +679,8 @@ impl StatelessDecoderBackend for Backend {
}
impl VideoDecoderBackend for Backend {
type Handle = VADecodedHandle<Vp9Picture<GenericBackendHandle>>;
fn coded_resolution(&self) -> Option<Resolution> {
self.metadata_state.coded_resolution().ok()
}
@ -813,6 +738,78 @@ impl VideoDecoderBackend for Backend {
))
}
}
fn poll(&mut self, blocking_mode: BlockingMode) -> DecoderResult<VecDeque<Self::Handle>> {
let mut completed = VecDeque::new();
let candidates = self.pending_jobs.drain(..).collect::<VecDeque<_>>();
for job in candidates {
if matches!(blocking_mode, BlockingMode::NonBlocking) {
let status = job.va_picture.query_status()?;
if status != libva::VASurfaceStatus::VASurfaceReady {
self.pending_jobs.push_back(job);
continue;
}
}
let current_picture = job.va_picture.sync()?;
let map_format = self.metadata_state.map_format()?;
let backend_handle = GenericBackendHandle::new_ready(
current_picture,
Rc::clone(map_format),
self.metadata_state.display_resolution()?,
);
job.codec_picture.borrow_mut().backend_handle = Some(backend_handle);
completed.push_back(job.codec_picture);
}
let completed = completed.into_iter().map(|picture| {
self.build_va_decoded_handle(&picture)
.map_err(|e| DecoderError::from(StatelessBackendError::Other(anyhow!(e))))
});
completed.collect::<Result<VecDeque<_>, _>>()
}
fn handle_is_ready(&self, handle: &Self::Handle) -> bool {
match &handle.picture().backend_handle {
Some(backend_handle) => backend_handle.is_ready(),
None => true,
}
}
fn block_on_handle(&mut self, handle: &Self::Handle) -> StatelessBackendResult<()> {
for i in 0..self.pending_jobs.len() {
// Remove from the queue in order.
let job = &self.pending_jobs[i];
if Vp9Picture::same(&job.codec_picture, handle.picture_container()) {
let job = self.pending_jobs.remove(i).unwrap();
let current_picture = job.va_picture.sync()?;
let map_format = self.metadata_state.map_format()?;
let backend_handle = GenericBackendHandle::new_ready(
current_picture,
Rc::clone(map_format),
self.metadata_state.display_resolution()?,
);
job.codec_picture.borrow_mut().backend_handle = Some(backend_handle);
return Ok(());
}
}
Err(StatelessBackendError::Other(anyhow!(
"Asked to block on a pending job that doesn't exist"
)))
}
}
impl Decoder<VADecodedHandle<Vp9Picture<GenericBackendHandle>>> {
@ -832,13 +829,13 @@ mod tests {
use crate::decoders::vp9::backends::vaapi::AssociatedHandle;
use crate::decoders::vp9::backends::vaapi::TestParams;
use crate::decoders::vp9::backends::BlockingMode;
use crate::decoders::vp9::backends::DecodedHandle;
use crate::decoders::vp9::backends::StatelessDecoderBackend;
use crate::decoders::vp9::decoder::tests::process_ready_frames;
use crate::decoders::vp9::decoder::tests::run_decoding_loop;
use crate::decoders::vp9::decoder::Decoder;
use crate::decoders::vp9::parser::NUM_REF_FRAMES;
use crate::decoders::BlockingMode;
use crate::decoders::DecodedHandle;
use crate::decoders::DynPicture;
fn get_test_params(

View file

@ -6,14 +6,18 @@
//! run so we can test it in isolation.
use std::cell::RefCell;
use std::collections::VecDeque;
use std::marker::PhantomData;
use std::rc::Rc;
use crate::decoders::BlockingMode;
use crate::decoders::DecodedHandle;
use crate::decoders::DynPicture;
use crate::decoders::FrameInfo;
use crate::decoders::MappableHandle;
use crate::decoders::Picture;
use crate::decoders::Result;
use crate::decoders::StatelessBackendResult;
use crate::decoders::VideoDecoderBackend;
use crate::DecodedFormat;
use crate::Resolution;
@ -68,9 +72,20 @@ impl<T: FrameInfo> DecodedHandle for Handle<Picture<T, BackendHandle>> {
}
/// Dummy backend that can be used for any codec.
pub(crate) struct Backend;
pub(crate) struct Backend<H>(PhantomData<H>);
impl<H> Backend<H> {
pub(crate) fn new() -> Self {
Self(Default::default())
}
}
impl<H> VideoDecoderBackend for Backend<H>
where
Handle<H>: DecodedHandle,
{
type Handle = Handle<H>;
impl VideoDecoderBackend for Backend {
fn num_resources_total(&self) -> usize {
1
}
@ -94,4 +109,16 @@ impl VideoDecoderBackend for Backend {
fn display_resolution(&self) -> Option<Resolution> {
None
}
fn poll(&mut self, _: BlockingMode) -> crate::decoders::Result<VecDeque<Self::Handle>> {
Ok(VecDeque::new())
}
fn handle_is_ready(&self, _: &Self::Handle) -> bool {
true
}
fn block_on_handle(&mut self, _: &Self::Handle) -> StatelessBackendResult<()> {
Ok(())
}
}