• 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 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