libva 0.1.4

Safe bindings over libva
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::borrow::Borrow;
use std::marker::PhantomData;
use std::rc::Rc;

use crate::Image;
use crate::SurfaceMemoryDescriptor;
use crate::VaError;
use crate::bindings;
use crate::buffer::Buffer;
use crate::context::Context;
use crate::surface::Surface;
use crate::va_check;

// Use the sealed trait pattern to make sure that new states are not created in caller code. More
// information about the sealed trait pattern can be found at
// <https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed>
mod private {
    pub trait Sealed {}
}

/// A `Picture` will only have valid YUV data after a sequence of operations are performed in a
/// particular order. This order correspond to the following VA-API calls: `vaBeginPicture`,
/// `vaRenderPicture`, `vaEndPicture` and `vaSyncSurface`. This trait enforces this ordering by
/// implementing the Typestate pattern to constrain what operations are available in what particular
/// states.
///
/// The states for the state machine are:
///
/// * PictureNew -> PictureBegin
/// * PictureBegin -> PictureRender
/// * PictureRender ->PictureEnd
/// * PictureEnd -> PictureSync
///
/// Where the surface can be reclaimed in both `PictureNew` and `PictureSync`, as either no
/// operation took place (as in `PictureNew`), or it is guaranteed that the operation has already
/// completed (as in `PictureSync`).
///
/// More information about the Typestate pattern can be found at
/// <http://cliffle.com/blog/rust-typestate/>
pub trait PictureState: private::Sealed {}

/// Represents a `Picture` that has just been created.
pub enum PictureNew {}
impl PictureState for PictureNew {}
impl private::Sealed for PictureNew {}

/// Represents a `Picture` after `vaBeginPicture` has been called.
pub enum PictureBegin {}
impl PictureState for PictureBegin {}
impl private::Sealed for PictureBegin {}

/// Represents a `Picture` after `vaRenderPicture` has been called.
pub enum PictureRender {}
impl PictureState for PictureRender {}
impl private::Sealed for PictureRender {}

/// Represents a `Picture` after `vaEndPicture` has been called.
pub enum PictureEnd {}
impl PictureState for PictureEnd {}
impl private::Sealed for PictureEnd {}

/// Represents a `Picture` after `vaSyncSurface` has been called on the underlying surface.
pub enum PictureSync {}
impl PictureState for PictureSync {}
impl private::Sealed for PictureSync {}

/// Represents a state where one can reclaim the underlying `Surface` for this `Picture`. This is
/// true when either no decoding has been initiated or, alternatively, when the decoding operation
/// has completed for the underlying `vaSurface`
pub trait PictureReclaimableSurface: PictureState + private::Sealed {}
impl PictureReclaimableSurface for PictureNew {}
impl PictureReclaimableSurface for PictureSync {}

/// Inner type for [`Picture`], that is, the part that exists in all states.
struct PictureInner<T> {
    /// Timestamp of the picture.
    timestamp: u64,
    /// A context associated with this picture.
    context: Rc<Context>,
    /// Contains the buffers used to decode the data.
    buffers: Vec<Buffer>,
    /// Contains the actual decoded data. Note that the surface may be shared in
    /// interlaced decoding.
    surface: Rc<T>,
}

/// A `Surface` that is being rendered into.
///
/// This struct abstracts the decoding flow using `vaBeginPicture`, `vaRenderPicture`,
/// `vaEndPicture` and `vaSyncSurface` in a type-safe way.
///
/// The surface will have valid picture data after all the stages of decoding are called.
///
/// The `T` generic parameter must be `Borrow<Surface<_>>`, i.e. it can be [`Surface`] directly or
/// some other type that contains one.
///
/// No constraint on `T` is specified in this declaration because specifying it here would force us
/// to add the generic argument of [`Surface`] to this type as well, turning it into a type with 3
/// generics, one of which is redundant. To avoid that we leave `T` unconstrained and instead
/// constrain the methods that require to act on it as a [`Surface`].
pub struct Picture<S: PictureState, T> {
    inner: Box<PictureInner<T>>,
    phantom: std::marker::PhantomData<S>,
}

impl<T> Picture<PictureNew, T> {
    /// Creates a new Picture with a given `timestamp`. `surface` is the underlying surface that
    /// libva will render to.
    pub fn new<D: SurfaceMemoryDescriptor>(timestamp: u64, context: Rc<Context>, surface: T) -> Self
    where
        T: Borrow<Surface<D>>,
    {
        Self {
            inner: Box::new(PictureInner {
                timestamp,
                context,
                buffers: Default::default(),
                surface: Rc::new(surface),
            }),

            phantom: PhantomData,
        }
    }

    /// Creates a new Picture with a given `timestamp` to identify it,
    /// reusing the Surface from `picture`. This is useful for interlaced
    /// decoding as one can render both fields to the same underlying surface.
    pub fn new_from_same_surface<S: PictureState>(timestamp: u64, picture: &Picture<S, T>) -> Self {
        let context = Rc::clone(&picture.inner.context);
        Picture {
            inner: Box::new(PictureInner {
                timestamp,
                context,
                buffers: Default::default(),
                surface: Rc::clone(&picture.inner.surface),
            }),

            phantom: PhantomData,
        }
    }

    /// Add `buffer` to the picture.
    pub fn add_buffer(&mut self, buffer: Buffer) {
        self.inner.buffers.push(buffer);
    }

    /// Wrapper around `vaBeginPicture`.
    pub fn begin<D: SurfaceMemoryDescriptor>(self) -> Result<Picture<PictureBegin, T>, VaError>
    where
        T: Borrow<Surface<D>>,
    {
        // Safe because `self.inner.context` represents a valid VAContext and
        // `self.inner.surface` represents a valid VASurface.
        let res = va_check(unsafe {
            crate::va::vaBeginPicture(
                self.inner.context.display().handle(),
                self.inner.context.id(),
                self.surface().id(),
            )
        });

        res.map(|()| Picture {
            inner: self.inner,
            phantom: PhantomData,
        })
    }
}

impl<T> Picture<PictureBegin, T> {
    /// Wrapper around `vaRenderPicture`.
    pub fn render(self) -> Result<Picture<PictureRender, T>, VaError> {
        // Safe because `self.inner.context` represents a valid `VAContext` and `self.inner.surface`
        // represents a valid `VASurface`. `buffers` point to a Rust struct and the vector length is
        // passed to the C function, so it is impossible to write past the end of the vector's
        // storage by mistake.
        va_check(unsafe {
            crate::va::vaRenderPicture(
                self.inner.context.display().handle(),
                self.inner.context.id(),
                Buffer::as_id_vec(&self.inner.buffers).as_mut_ptr(),
                self.inner.buffers.len() as i32,
            )
        })
        .map(|()| Picture {
            inner: self.inner,
            phantom: PhantomData,
        })
    }
}

impl<T> Picture<PictureRender, T> {
    /// Wrapper around `vaEndPicture`.
    pub fn end(self) -> Result<Picture<PictureEnd, T>, VaError> {
        // Safe because `self.inner.context` represents a valid `VAContext`.
        va_check(unsafe {
            crate::va::vaEndPicture(
                self.inner.context.display().handle(),
                self.inner.context.id(),
            )
        })
        .map(|()| Picture {
            inner: self.inner,
            phantom: PhantomData,
        })
    }
}

impl<T> Picture<PictureEnd, T> {
    /// Syncs the picture, ensuring that all pending operations are complete when this call returns.
    pub fn sync<D: SurfaceMemoryDescriptor>(
        self,
    ) -> Result<Picture<PictureSync, T>, (VaError, Self)>
    where
        T: Borrow<Surface<D>>,
    {
        let res = self.surface().sync();

        match res {
            Ok(()) => Ok(Picture {
                inner: self.inner,
                phantom: PhantomData,
            }),
            Err(e) => Err((e, self)),
        }
    }
}

impl<S: PictureState, T> Picture<S, T> {
    /// Returns the timestamp of this picture.
    pub fn timestamp(&self) -> u64 {
        self.inner.timestamp
    }

    /// Returns a reference to the underlying `Surface`.
    ///
    /// If you are interested in obtaining the container of the `Surface`, use `as_ref()` instead.
    /// This is a convenience method to avoid having to call `borrow()` every time the surface is
    /// needed.
    pub fn surface<D: SurfaceMemoryDescriptor>(&self) -> &Surface<D>
    where
        T: Borrow<Surface<D>>,
    {
        self.as_ref().borrow()
    }
}

impl<S: PictureReclaimableSurface, T> Picture<S, T> {
    /// Reclaim ownership of the Surface this picture has been created from, consuming the picture
    /// in the process. Useful if the Surface is part of a pool.
    ///
    /// This will fail and return the passed object if there are more than one reference to the
    /// underlying surface.
    pub fn take_surface(self) -> Result<T, Self> {
        let inner = self.inner;
        match Rc::try_unwrap(inner.surface) {
            Ok(surface) => Ok(surface),
            Err(surface) => Err(Self {
                inner: Box::new(PictureInner {
                    surface,
                    context: inner.context,
                    buffers: inner.buffers,
                    timestamp: inner.timestamp,
                }),
                phantom: PhantomData,
            }),
        }
    }

    /// Create a new derived image from this `Picture` using `vaDeriveImage`.
    ///
    /// Derived images are a direct view (i.e. without any copy) on the buffer content of the
    /// `Picture`. On the other hand, not all `Pictures` can be derived.
    pub fn derive_image<'a, D: SurfaceMemoryDescriptor + 'a>(
        &'a self,
        visible_rect: (u32, u32),
    ) -> Result<Image<'a>, VaError>
    where
        T: Borrow<Surface<D>>,
    {
        Image::derive_from(self.surface(), visible_rect)
    }

    /// Create new image from the `Picture` using `vaCreateImage` and `vaGetImage`.
    ///
    /// The image will contain a copy of the `Picture` in the desired `format` and `coded_resolution`.
    pub fn create_image<'a, D: SurfaceMemoryDescriptor + 'a>(
        &'a self,
        format: bindings::VAImageFormat,
        coded_resolution: (u32, u32),
        visible_rect: (u32, u32),
    ) -> Result<Image<'a>, VaError>
    where
        T: Borrow<Surface<D>>,
    {
        Image::create_from(self.surface(), format, coded_resolution, visible_rect)
    }
}

impl<S: PictureState, T> AsRef<T> for Picture<S, T> {
    fn as_ref(&self) -> &T {
        (*self.inner.surface).borrow()
    }
}