]> git.nihav.org Git - nihav-player.git/blame_incremental - nihed-cros-libva/src/picture.rs
hwdec-vaapi: handle copying data into kodaed chroma planes
[nihav-player.git] / nihed-cros-libva / src / picture.rs
... / ...
CommitLineData
1// Copyright 2022 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::cell::Ref;
6use std::cell::RefCell;
7use std::cell::RefMut;
8use std::marker::PhantomData;
9use std::rc::Rc;
10
11use crate::bindings;
12use crate::buffer::Buffer;
13use crate::context::Context;
14use crate::display::Display;
15use crate::drmprime::*;
16use crate::status::*;
17use crate::surface::Surface;
18
19// Use the sealed trait pattern to make sure that new states are not created in caller code. More
20// information about the sealed trait pattern can be found at
21// <https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed>
22mod private {
23 pub trait Sealed {}
24}
25
26/// A `Picture` will only have valid YUV data after a sequence of operations are performed in a
27/// particular order. This order correspond to the following VA-API calls: `vaBeginPicture`,
28/// `vaRenderPicture`, `vaEndPicture` and `vaSyncSurface`. This trait enforces this ordering by
29/// implementing the Typestate pattern to constrain what operations are available in what particular
30/// states.
31///
32/// The states for the state machine are:
33///
34/// * PictureNew -> PictureBegin
35/// * PictureBegin -> PictureRender
36/// * PictureRender ->PictureEnd
37/// * PictureEnd -> PictureSync
38///
39/// Where the surface can be reclaimed in both `PictureNew` and `PictureSync`, as either no
40/// operation took place (as in `PictureNew`), or it is guaranteed that the operation has already
41/// completed (as in `PictureSync`).
42///
43/// More information about the Typestate pattern can be found at
44/// <http://cliffle.com/blog/rust-typestate/>
45pub trait PictureState: private::Sealed {}
46
47/// Represents a `Picture` that has just been created.
48pub enum PictureNew {}
49impl PictureState for PictureNew {}
50impl private::Sealed for PictureNew {}
51
52/// Represents a `Picture` after `vaBeginPicture` has been called.
53pub enum PictureBegin {}
54impl PictureState for PictureBegin {}
55impl private::Sealed for PictureBegin {}
56
57/// Represents a `Picture` after `vaRenderPicture` has been called.
58pub enum PictureRender {}
59impl PictureState for PictureRender {}
60impl private::Sealed for PictureRender {}
61
62/// Represents a `Picture` after `vaEndPicture` has been called.
63pub enum PictureEnd {}
64impl PictureState for PictureEnd {}
65impl private::Sealed for PictureEnd {}
66
67/// Represents a `Picture` after `vaSyncSurface` has been called on the underlying surface.
68pub enum PictureSync {}
69impl PictureState for PictureSync {}
70impl private::Sealed for PictureSync {}
71
72/// Represents a state where one can reclaim the underlying `Surface` for this `Picture`. This is
73/// true when either no decoding has been initiated or, alternatively, when the decoding operation
74/// has completed for the underlying `vaSurface`
75pub trait PictureReclaimableSurface: PictureState + private::Sealed {}
76impl PictureReclaimableSurface for PictureNew {}
77impl PictureReclaimableSurface for PictureSync {}
78
79struct PictureInner {
80 /// Timestamp of the picture.
81 timestamp: u64,
82 /// A context associated with this picture.
83 context: Rc<Context>,
84 /// Contains the buffers used to decode the data.
85 buffers: Vec<Buffer>,
86 /// Contains the actual decoded data. Note that the surface may be shared in
87 /// interlaced decoding.
88 surface: Rc<RefCell<Surface>>,
89}
90
91/// A `Surface` that is being rendered into.
92///
93/// This struct abstracts the decoding flow using `vaBeginPicture`, `vaRenderPicture`,
94/// `vaEndPicture` and `vaSyncSurface` in a type-safe way.
95///
96/// The surface will have valid picture data after all the stages of decoding are called.
97pub struct Picture<S: PictureState> {
98 inner: Box<PictureInner>,
99 phantom: std::marker::PhantomData<S>,
100}
101
102impl Picture<PictureNew> {
103 /// Creates a new Picture with a given `timestamp`. `surface` is the underlying surface that
104 /// libva will render to.
105 pub fn new(timestamp: u64, context: Rc<Context>, surface: Surface) -> Self {
106 Self {
107 inner: Box::new(PictureInner {
108 timestamp,
109 context,
110 buffers: Default::default(),
111 surface: Rc::new(RefCell::new(surface)),
112 }),
113
114 phantom: PhantomData,
115 }
116 }
117
118 /// Creates a new Picture with a given `frame_number` to identify it,
119 /// reusing the Surface from `picture`. This is useful for interlaced
120 /// decoding as one can render both fields to the same underlying surface.
121 pub fn new_from_same_surface<T: PictureReclaimableSurface, S: PictureReclaimableSurface>(
122 timestamp: u64,
123 picture: &Picture<S>,
124 ) -> Picture<T> {
125 let context = Rc::clone(&picture.inner.context);
126 Picture {
127 inner: Box::new(PictureInner {
128 timestamp,
129 context,
130 buffers: Default::default(),
131 surface: Rc::clone(&picture.inner.surface),
132 }),
133
134 phantom: PhantomData,
135 }
136 }
137
138 /// Add `buffer` to the picture.
139 pub fn add_buffer(&mut self, buffer: Buffer) {
140 self.inner.buffers.push(buffer);
141 }
142
143 /// Wrapper around `vaBeginPicture`.
144 pub fn begin(self) -> VAResult<Picture<PictureBegin>> {
145 // Safe because `self.inner.context` represents a valid VAContext and
146 // `self.inner.surface` represents a valid VASurface.
147 (unsafe {
148 bindings::vaBeginPicture(
149 self.inner.context.display().handle(),
150 self.inner.context.id(),
151 self.inner.surface.borrow().id(),
152 )
153 })
154 .check()?;
155
156 Ok(Picture {
157 inner: self.inner,
158 phantom: PhantomData,
159 })
160 }
161}
162
163impl Picture<PictureBegin> {
164 /// Wrapper around `vaRenderPicture`.
165 pub fn render(self) -> VAResult<Picture<PictureRender>> {
166 // Safe because `self.inner.context` represents a valid `VAContext` and `self.inner.surface`
167 // represents a valid `VASurface`. `buffers` point to a Rust struct and the vector length is
168 // passed to the C function, so it is impossible to write past the end of the vector's
169 // storage by mistake.
170 (unsafe {
171 bindings::vaRenderPicture(
172 self.inner.context.display().handle(),
173 self.inner.context.id(),
174 Buffer::as_id_vec(&self.inner.buffers).as_mut_ptr(),
175 self.inner.buffers.len() as i32,
176 )
177 })
178 .check()?;
179
180 Ok(Picture {
181 inner: self.inner,
182 phantom: PhantomData,
183 })
184 }
185}
186
187impl Picture<PictureRender> {
188 /// Wrapper around `vaEndPicture`.
189 pub fn end(self) -> VAResult<Picture<PictureEnd>> {
190 // Safe because `self.inner.context` represents a valid `VAContext`.
191 (unsafe {
192 bindings::vaEndPicture(
193 self.inner.context.display().handle(),
194 self.inner.context.id(),
195 )
196 })
197 .check()?;
198 Ok(Picture {
199 inner: self.inner,
200 phantom: PhantomData,
201 })
202 }
203}
204
205impl Picture<PictureEnd> {
206 /// Syncs the picture, ensuring that all pending operations are complete when this call returns.
207 pub fn sync(self) -> std::result::Result<Picture<PictureSync>, (VAError, Self)> {
208 let res = self.inner.surface.borrow().sync();
209
210 match res {
211 Ok(()) => Ok(Picture {
212 inner: self.inner,
213 phantom: PhantomData,
214 }),
215 Err(e) => Err((e, self)),
216 }
217 }
218
219 /// Queries the status of the underlying surface.
220 ///
221 /// This call can be used to implement a non-blocking path, wherein a decoder queries the status
222 /// of the surface after each decode operation instead of blocking on it.
223 pub fn query_status(&self) -> VAResult<VASurfaceStatus> {
224 self.inner.surface.borrow_mut().query_status()
225 }
226}
227
228impl<S: PictureState> Picture<S> {
229 /// Returns the timestamp of this picture.
230 pub fn timestamp(&self) -> u64 {
231 self.inner.timestamp
232 }
233
234 /// Returns the ID of the underlying surface.
235 pub fn surface_id(&self) -> bindings::VASurfaceID {
236 self.inner.surface.borrow().id()
237 }
238
239 /// Returns a reference to the display owning this `Picture`.
240 pub(crate) fn display(&self) -> &Rc<Display> {
241 self.inner.context.display()
242 }
243
244 /// Returns the size of the surface being rendered to by this `Picture`.
245 pub fn surface_size(&self) -> (u32, u32) {
246 self.inner.surface.borrow().size()
247 }
248
249 /// Returns DRM Prime surface descriptor.
250 pub fn surface_descriptor(&self) -> Option<VADRMPRIMESurfaceDescriptor> {
251 unsafe {
252 let mut desc = VADRMPRIMESurfaceDescriptor::default();
253 let display = self.inner.context.display().handle();
254 let handle = self.inner.surface.borrow().id();
255 let ret = crate::bindings::vaExportSurfaceHandle(display, handle, VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, crate::constants::VA_EXPORT_SURFACE_READ_ONLY, &mut desc as *mut VADRMPRIMESurfaceDescriptor as *mut ::std::os::raw::c_void);
256 if ret == 0 {
257 Some(desc)
258 } else {
259 None
260 }
261 }
262 }
263}
264
265impl<S: PictureReclaimableSurface> Picture<S> {
266 /// Reclaim ownership of the Surface this picture has been created from, consuming the picture
267 /// in the process. Useful if the Surface is part of a pool.
268 pub fn take_surface(self) -> VAResult<Surface> {
269 match Rc::try_unwrap(self.inner.surface) {
270 Ok(surface) => Ok(surface.into_inner()),
271 Err(_) => Err(VAError::SurfaceBusy),
272 }
273 }
274
275 /// Returns a reference to the underlying `Surface` for this `Picture`
276 pub fn surface(&self) -> Ref<Surface> {
277 self.inner.surface.borrow()
278 }
279
280 /// Returns a mutable reference to the underlying `Surface` for this `Picture`
281 pub fn surface_mut(&mut self) -> RefMut<Surface> {
282 self.inner.surface.borrow_mut()
283 }
284}