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 use std::os::raw::c_void; 6 use std::rc::Rc; 7 8 use super::bindings; 9 use super::format::Bitrate; 10 use super::format::OutputProfile; 11 use super::session::*; 12 use crate::error::*; 13 use crate::format::*; 14 15 /// Represents a backend implementation of libvda. 16 pub enum VeaImplType { 17 Fake, 18 Gavea, // GpuArcVideoEncoderAccelerator 19 } 20 21 /// Represents encoding capabilities of libvda encode instances. 22 pub struct EncodeCapabilities { 23 pub input_formats: Vec<PixelFormat>, 24 pub output_formats: Vec<OutputProfile>, 25 } 26 27 pub struct VeaConnection { 28 // `conn_ptr` must be a valid pointer obtained from `decode_bindings::initialize_encode`. 29 conn_ptr: *mut c_void, 30 } 31 32 impl VeaConnection { new(typ: VeaImplType) -> Result<Self>33 fn new(typ: VeaImplType) -> Result<Self> { 34 let impl_type = match typ { 35 VeaImplType::Fake => bindings::vea_impl_type_VEA_FAKE, 36 VeaImplType::Gavea => bindings::vea_impl_type_GAVEA, 37 }; 38 39 // Safe because libvda's API is called properly. 40 match unsafe { bindings::initialize_encode(impl_type) } { 41 ptr if ptr.is_null() => Err(Error::InstanceInitFailure), 42 conn_ptr => Ok(VeaConnection { conn_ptr }), 43 } 44 } 45 46 // Returns the raw pointer to the VEA connection instance that can be passed 47 // to bindings functions that require it. conn_ptr(&self) -> *mut c_void48 pub(super) fn conn_ptr(&self) -> *mut c_void { 49 self.conn_ptr 50 } 51 } 52 53 impl Drop for VeaConnection { drop(&mut self)54 fn drop(&mut self) { 55 // Safe because libvda's API is called properly. 56 unsafe { bindings::deinitialize_encode(self.conn_ptr) } 57 } 58 } 59 60 /// Represents a libvda encode instance. 61 pub struct VeaInstance { 62 connection: Rc<VeaConnection>, 63 caps: EncodeCapabilities, 64 } 65 66 /// Represents an encoding configuration for a libvda encode session. 67 #[derive(Debug, Clone, Copy)] 68 pub struct Config { 69 pub input_format: PixelFormat, 70 pub input_visible_width: u32, 71 pub input_visible_height: u32, 72 pub output_profile: Profile, 73 pub bitrate: Bitrate, 74 pub initial_framerate: Option<u32>, 75 pub h264_output_level: Option<u8>, 76 } 77 78 impl Config { to_raw_config(self) -> bindings::vea_config_t79 pub(crate) fn to_raw_config(self) -> bindings::vea_config_t { 80 bindings::vea_config_t { 81 input_format: self.input_format.to_raw_pixel_format(), 82 input_visible_width: self.input_visible_width, 83 input_visible_height: self.input_visible_height, 84 output_profile: self.output_profile.to_raw_profile(), 85 bitrate: self.bitrate.to_raw_bitrate(), 86 initial_framerate: self.initial_framerate.unwrap_or(0), 87 has_initial_framerate: self.initial_framerate.is_some().into(), 88 h264_output_level: self.h264_output_level.unwrap_or(0), 89 has_h264_output_level: self.h264_output_level.is_some().into(), 90 } 91 } 92 } 93 94 impl VeaInstance { 95 /// Creates VeaInstance. `impl_type` specifies which backend will be used. new(impl_type: VeaImplType) -> Result<Self>96 pub fn new(impl_type: VeaImplType) -> Result<Self> { 97 let connection = VeaConnection::new(impl_type)?; 98 99 // Get available input/output formats. 100 // Safe because libvda's API is called properly. 101 let vea_caps_ptr = unsafe { bindings::get_vea_capabilities(connection.conn_ptr()) }; 102 if vea_caps_ptr.is_null() { 103 return Err(Error::GetCapabilitiesFailure); 104 } 105 // Safe because `vea_cap_ptr` is not NULL and provided by get_vea_capabilities(). 106 let bindings::vea_capabilities_t { 107 num_input_formats, 108 input_formats, 109 num_output_formats, 110 output_formats, 111 } = unsafe { *vea_caps_ptr }; 112 113 if num_input_formats == 0 || input_formats.is_null() { 114 return Err(Error::InvalidCapabilities( 115 "invalid input formats".to_string(), 116 )); 117 } 118 if num_output_formats == 0 || output_formats.is_null() { 119 return Err(Error::InvalidCapabilities( 120 "invalid output formats".to_string(), 121 )); 122 } 123 124 // Safe because `input_formats` is valid for |`num_input_formats`| elements. 125 let input_formats = 126 unsafe { PixelFormat::from_raw_parts(input_formats, num_input_formats)? }; 127 128 // Safe because `output_formats` is valid for |`num_output_formats`| elements. 129 let output_formats = 130 unsafe { OutputProfile::from_raw_parts(output_formats, num_output_formats)? }; 131 132 Ok(Self { 133 connection: Rc::new(connection), 134 caps: EncodeCapabilities { 135 input_formats, 136 output_formats, 137 }, 138 }) 139 } 140 141 /// Gets encoder capabilities. get_capabilities(&self) -> &EncodeCapabilities142 pub fn get_capabilities(&self) -> &EncodeCapabilities { 143 &self.caps 144 } 145 146 /// Opens a new `Session` for a given `Config`. open_session(&self, config: Config) -> Result<Session>147 pub fn open_session(&self, config: Config) -> Result<Session> { 148 Session::new(&self.connection, config).ok_or(Error::EncodeSessionInitFailure(config)) 149 } 150 } 151