• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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 
5 //! This module provides type safe interfaces for each operation exposed by Chrome's
6 //! VideoDecodeAccelerator.
7 
8 use std::os::raw::c_void;
9 use std::rc::Rc;
10 
11 use super::bindings;
12 use super::format::*;
13 use super::session::*;
14 use crate::error::*;
15 use crate::format::*;
16 
17 /// Represents a backend implementation of libvda.
18 pub enum VdaImplType {
19     Fake,
20     Gavda, // GpuArcVideoDecodeAccelerator
21     Gavd,  // GpuArcVideoDecoder
22 }
23 
24 /// Represents decoding capabilities of libvda instances.
25 pub struct Capabilities {
26     pub input_formats: Vec<InputFormat>,
27     pub output_formats: Vec<PixelFormat>,
28 }
29 
30 // An active connection to the VDA, which closes automatically as it is dropped.
31 pub struct VdaConnection {
32     // `conn_ptr` must be a valid pointer obtained from `decode_bindings::initialize`.
33     conn_ptr: *mut c_void,
34 }
35 
36 impl VdaConnection {
new(typ: VdaImplType) -> Result<Self>37     fn new(typ: VdaImplType) -> Result<Self> {
38         let impl_type = match typ {
39             VdaImplType::Fake => bindings::vda_impl_type_FAKE,
40             VdaImplType::Gavda => bindings::vda_impl_type_GAVDA,
41             VdaImplType::Gavd => bindings::vda_impl_type_GAVD,
42         };
43 
44         // Safe because libvda's API is called properly.
45         match unsafe { bindings::initialize(impl_type) } {
46             ptr if ptr.is_null() => Err(Error::InstanceInitFailure),
47             conn_ptr => Ok(VdaConnection { conn_ptr }),
48         }
49     }
50 
51     // Returns the raw pointer to the VDA connection instance that can be passed
52     // to bindings functions that require it.
conn_ptr(&self) -> *mut c_void53     pub(super) fn conn_ptr(&self) -> *mut c_void {
54         self.conn_ptr
55     }
56 }
57 
58 impl Drop for VdaConnection {
drop(&mut self)59     fn drop(&mut self) {
60         // Safe because libvda's API is called properly.
61         unsafe { bindings::deinitialize(self.conn_ptr) }
62     }
63 }
64 
65 /// Represents a libvda instance.
66 pub struct VdaInstance {
67     connection: Rc<VdaConnection>,
68     caps: Capabilities,
69 }
70 
71 impl VdaInstance {
72     /// Creates VdaInstance. `typ` specifies which backend will be used.
new(typ: VdaImplType) -> Result<Self>73     pub fn new(typ: VdaImplType) -> Result<Self> {
74         let connection = VdaConnection::new(typ)?;
75 
76         // Get available input/output formats.
77         // Safe because `conn_ptr` is valid and `get_vda_capabilities()` won't invalidate it.
78         let vda_cap_ptr = unsafe { bindings::get_vda_capabilities(connection.conn_ptr) };
79         if vda_cap_ptr.is_null() {
80             return Err(Error::GetCapabilitiesFailure);
81         }
82         // Safe because `vda_cap_ptr` is not NULL.
83         let vda_cap = unsafe { *vda_cap_ptr };
84 
85         // Safe because `input_formats` is valid for |`num_input_formats`| elements if both are valid.
86         let input_formats = unsafe {
87             InputFormat::from_raw_parts(vda_cap.input_formats, vda_cap.num_input_formats)?
88         };
89 
90         // Output formats
91         // Safe because `output_formats` is valid for |`num_output_formats`| elements if both are valid.
92         let output_formats = unsafe {
93             PixelFormat::from_raw_parts(vda_cap.output_formats, vda_cap.num_output_formats)?
94         };
95 
96         Ok(VdaInstance {
97             connection: Rc::new(connection),
98             caps: Capabilities {
99                 input_formats,
100                 output_formats,
101             },
102         })
103     }
104 
105     /// Get media capabilities.
get_capabilities(&self) -> &Capabilities106     pub fn get_capabilities(&self) -> &Capabilities {
107         &self.caps
108     }
109 
110     /// Opens a new `Session` for a given `Profile`.
open_session(&self, profile: Profile) -> Result<Session>111     pub fn open_session(&self, profile: Profile) -> Result<Session> {
112         Session::new(&self.connection, profile).ok_or(Error::SessionInitFailure(profile))
113     }
114 }
115