]> git.nihav.org Git - nihav-player.git/blobdiff - nihed-cros-libva/src/display.rs
nihed-cros-libva: re-export VA_INVALID_ID for convenience
[nihav-player.git] / nihed-cros-libva / src / display.rs
index 462bc3e8db1dcb154b14bf8026fa06ea579f4842..7cff18fa3ab6ab80fa182e669f04a3f3abc2eb6d 100644 (file)
@@ -9,16 +9,13 @@ use std::path::Path;
 use std::path::PathBuf;
 use std::rc::Rc;
 
-use anyhow::anyhow;
-use anyhow::Context as AnyhowContext;
-use anyhow::Result;
-
 use crate::bindings;
 use crate::config::Config;
 use crate::context::Context;
-use crate::status::Status;
+use crate::formats::{RTFormat, VAFourcc};
+use crate::status::*;
 use crate::surface::Surface;
-use crate::UsageHint;
+use crate::UsageHints;
 
 /// Iterates over existing DRM devices.
 ///
@@ -59,6 +56,10 @@ impl Iterator for DrmDeviceIterator {
     }
 }
 
+unsafe extern "C" fn null_msg_cb(_ctx: *mut std::ffi::c_void, _message: *const std::ffi::c_char) {
+//    let msg = CStr::from_ptr(message).to_string_lossy();
+}
+
 /// A VADisplay opened over DRM.
 ///
 /// A Display is the starting point to using libva. This struct is essentially a safe wrapper over
@@ -80,29 +81,43 @@ impl Display {
     /// Opens and initializes a specific DRM `Display`.
     ///
     /// `path` is the path to a DRM device that supports VAAPI, e.g. `/dev/dri/renderD128`.
-    pub fn open_drm_display<P: AsRef<Path>>(path: P) -> Result<Rc<Self>> {
+    pub fn open_drm_display<P: AsRef<Path>>(path: P) -> VAResult<Rc<Self>> {
+        Self::open_drm_display_internal(path, false)
+    }
+    fn open_drm_display_internal<P: AsRef<Path>>(path: P, silent: bool) -> VAResult<Rc<Self>> {
         let file = std::fs::File::options()
             .read(true)
             .write(true)
             .open(path.as_ref())
-            .context(format!("failed to open {}", path.as_ref().display()))?;
+            .map_err(|_| VAError::InvalidValue)?;
 
         // Safe because fd represents a valid file descriptor and the pointer is checked for
         // NULL afterwards.
         let display = unsafe { bindings::vaGetDisplayDRM(file.as_raw_fd()) };
         if display.is_null() {
             // The File will close the DRM fd on drop.
-            return Err(anyhow!(
-                "failed to obtain VA display from DRM device {}",
-                path.as_ref().display()
-            ));
+            return Err(VAError::InvalidDisplay);
+        }
+
+        if silent {
+            // Safe because we ensure that the display is valid (i.e not NULL) before call.
+            unsafe {
+                bindings::vaSetInfoCallback(display, Some(null_msg_cb), std::ptr::null_mut());
+            }
         }
 
         let mut major = 0i32;
         let mut minor = 0i32;
         // Safe because we ensure that the display is valid (i.e not NULL) before calling
         // vaInitialize. The File will close the DRM fd on drop.
-        Status(unsafe { bindings::vaInitialize(display, &mut major, &mut minor) }).check()?;
+        (unsafe { bindings::vaInitialize(display, &mut major, &mut minor) }).check()?;
+
+        if silent {
+            // Safe because we ensure that the display is valid (i.e not NULL) before call.
+            unsafe {
+                bindings::vaSetInfoCallback(display, None, std::ptr::null_mut());
+            }
+        }
 
         Ok(Rc::new(Self {
             handle: display,
@@ -127,20 +142,40 @@ impl Display {
         None
     }
 
+    /// Opens the first device that succeeds and returns its `Display`.
+    ///
+    /// The only difference from ordinary `open` is that it does not print debug information
+    /// about libva version and opened driver.
+    ///
+    /// If an error occurs on a given device, it is ignored and the next one is tried until one
+    /// succeeds or we reach the end of the iterator.
+    pub fn open_silently() -> Option<Rc<Self>> {
+        let devices = DrmDeviceIterator::default();
+
+        // Try all the DRM devices until one succeeds.
+        for device in devices {
+            if let Ok(display) = Self::open_drm_display_internal(device, true) {
+                return Some(display);
+            }
+        }
+
+        None
+    }
+
     /// Returns the handle of this display.
     pub(crate) fn handle(&self) -> bindings::VADisplay {
         self.handle
     }
 
     /// Queries supported profiles by this display.
-    pub fn query_config_profiles(&self) -> Result<Vec<bindings::VAProfile::Type>> {
+    pub fn query_config_profiles(&self) -> VAResult<Vec<bindings::VAProfile::Type>> {
         // Safe because `self` represents a valid VADisplay.
         let mut max_num_profiles = unsafe { bindings::vaMaxNumProfiles(self.handle) };
         let mut profiles = Vec::with_capacity(max_num_profiles as usize);
 
         // Safe because `self` represents a valid `VADisplay` and the vector has `max_num_profiles`
         // as capacity.
-        Status(unsafe {
+        (unsafe {
             bindings::vaQueryConfigProfiles(
                 self.handle,
                 profiles.as_mut_ptr(),
@@ -182,14 +217,14 @@ impl Display {
     pub fn query_config_entrypoints(
         &self,
         profile: bindings::VAProfile::Type,
-    ) -> Result<Vec<bindings::VAEntrypoint::Type>> {
+    ) -> VAResult<Vec<bindings::VAEntrypoint::Type>> {
         // Safe because `self` represents a valid VADisplay.
         let mut max_num_entrypoints = unsafe { bindings::vaMaxNumEntrypoints(self.handle) };
         let mut entrypoints = Vec::with_capacity(max_num_entrypoints as usize);
 
         // Safe because `self` represents a valid VADisplay and the vector has `max_num_entrypoints`
         // as capacity.
-        Status(unsafe {
+        (unsafe {
             bindings::vaQueryConfigEntrypoints(
                 self.handle,
                 profile,
@@ -218,10 +253,10 @@ impl Display {
         profile: bindings::VAProfile::Type,
         entrypoint: bindings::VAEntrypoint::Type,
         attributes: &mut [bindings::VAConfigAttrib],
-    ) -> Result<()> {
+    ) -> VAResult<()> {
         // Safe because `self` represents a valid VADisplay. The slice length is passed to the C
         // function, so it is impossible to write past the end of the slice's storage by mistake.
-        Status(unsafe {
+        (unsafe {
             bindings::vaGetConfigAttributes(
                 self.handle,
                 profile,
@@ -237,7 +272,7 @@ impl Display {
     ///
     /// # Arguments
     ///
-    /// * `rt_format` - The desired surface format. See `VA_RT_FORMAT_*`
+    /// * `rt_format` - The desired surface format.
     /// * `va_fourcc` - The desired pixel format (optional). See `VA_FOURCC_*`
     /// * `width` - Width for the create surfaces
     /// * `height` - Height for the created surfaces
@@ -245,20 +280,20 @@ impl Display {
     /// * `num_surfaces` - Number of surfaces to create
     pub fn create_surfaces(
         self: &Rc<Self>,
-        rt_format: u32,
-        va_fourcc: Option<u32>,
+        rt_format: RTFormat,
+        va_fourcc: Option<VAFourcc>,
         width: u32,
         height: u32,
-        usage_hint: Option<UsageHint>,
+        usage_hints: Option<UsageHints>,
         num_surfaces: u32,
-    ) -> Result<Vec<Surface>> {
+    ) -> VAResult<Vec<Surface>> {
         Surface::new(
             Rc::clone(self),
             rt_format,
             va_fourcc,
             width,
             height,
-            usage_hint,
+            usage_hints,
             num_surfaces,
         )
     }
@@ -279,7 +314,7 @@ impl Display {
         coded_height: i32,
         surfaces: Option<&Vec<Surface>>,
         progressive: bool,
-    ) -> Result<Rc<Context>> {
+    ) -> VAResult<Rc<Context>> {
         Context::new(
             Rc::clone(self),
             config,
@@ -301,12 +336,12 @@ impl Display {
         attrs: Vec<bindings::VAConfigAttrib>,
         profile: bindings::VAProfile::Type,
         entrypoint: bindings::VAEntrypoint::Type,
-    ) -> Result<Config> {
+    ) -> VAResult<Config> {
         Config::new(Rc::clone(self), attrs, profile, entrypoint)
     }
 
     /// Returns available image formats for this display by wrapping around `vaQueryImageFormats`.
-    pub fn query_image_formats(&self) -> Result<Vec<bindings::VAImageFormat>> {
+    pub fn query_image_formats(&self) -> VAResult<Vec<bindings::VAImageFormat>> {
         // Safe because `self` represents a valid VADisplay.
         let mut num_image_formats = unsafe { bindings::vaMaxNumImageFormats(self.handle) };
         let mut image_formats = Vec::with_capacity(num_image_formats as usize);
@@ -314,7 +349,7 @@ impl Display {
         // Safe because `self` represents a valid VADisplay. The `image_formats` vector is properly
         // initialized and a valid size is passed to the C function, so it is impossible to write
         // past the end of their storage by mistake.
-        Status(unsafe {
+        (unsafe {
             bindings::vaQueryImageFormats(
                 self.handle,
                 image_formats.as_mut_ptr(),