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