xref: /aosp_15_r20/external/crosvm/media/libvda/src/encode/session.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2020 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::File;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Read;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::mem;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::os::unix::io::FromRawFd;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::rc::Rc;
10*bb4ee6a4SAndroid Build Coastguard Worker 
11*bb4ee6a4SAndroid Build Coastguard Worker use super::bindings;
12*bb4ee6a4SAndroid Build Coastguard Worker use super::event::*;
13*bb4ee6a4SAndroid Build Coastguard Worker use super::format::Bitrate;
14*bb4ee6a4SAndroid Build Coastguard Worker use super::vea_instance::Config;
15*bb4ee6a4SAndroid Build Coastguard Worker use super::VeaConnection;
16*bb4ee6a4SAndroid Build Coastguard Worker use crate::error::*;
17*bb4ee6a4SAndroid Build Coastguard Worker use crate::format::BufferFd;
18*bb4ee6a4SAndroid Build Coastguard Worker use crate::format::FramePlane;
19*bb4ee6a4SAndroid Build Coastguard Worker 
20*bb4ee6a4SAndroid Build Coastguard Worker pub type VeaInputBufferId = bindings::vea_input_buffer_id_t;
21*bb4ee6a4SAndroid Build Coastguard Worker pub type VeaOutputBufferId = bindings::vea_output_buffer_id_t;
22*bb4ee6a4SAndroid Build Coastguard Worker 
23*bb4ee6a4SAndroid Build Coastguard Worker /// Represents an encode session.
24*bb4ee6a4SAndroid Build Coastguard Worker pub struct Session {
25*bb4ee6a4SAndroid Build Coastguard Worker     // Pipe file to be notified encode session events.
26*bb4ee6a4SAndroid Build Coastguard Worker     pipe: File,
27*bb4ee6a4SAndroid Build Coastguard Worker     // Ensures the VEA connection remains open for as long as there are active sessions.
28*bb4ee6a4SAndroid Build Coastguard Worker     connection: Rc<VeaConnection>,
29*bb4ee6a4SAndroid Build Coastguard Worker     session_ptr: *mut bindings::vea_session_info_t,
30*bb4ee6a4SAndroid Build Coastguard Worker }
31*bb4ee6a4SAndroid Build Coastguard Worker 
convert_error_code(code: i32) -> Result<()>32*bb4ee6a4SAndroid Build Coastguard Worker fn convert_error_code(code: i32) -> Result<()> {
33*bb4ee6a4SAndroid Build Coastguard Worker     if code == 0 {
34*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
35*bb4ee6a4SAndroid Build Coastguard Worker     } else {
36*bb4ee6a4SAndroid Build Coastguard Worker         Err(Error::EncodeSessionFailure(code))
37*bb4ee6a4SAndroid Build Coastguard Worker     }
38*bb4ee6a4SAndroid Build Coastguard Worker }
39*bb4ee6a4SAndroid Build Coastguard Worker 
40*bb4ee6a4SAndroid Build Coastguard Worker impl Session {
41*bb4ee6a4SAndroid Build Coastguard Worker     /// Creates a new `Session`.
new(connection: &Rc<VeaConnection>, config: Config) -> Option<Self>42*bb4ee6a4SAndroid Build Coastguard Worker     pub(super) fn new(connection: &Rc<VeaConnection>, config: Config) -> Option<Self> {
43*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because `conn_ptr()` is valid and won't be invalidated by `init_encode_session()`.
44*bb4ee6a4SAndroid Build Coastguard Worker         let session_ptr: *mut bindings::vea_session_info_t = unsafe {
45*bb4ee6a4SAndroid Build Coastguard Worker             bindings::init_encode_session(connection.conn_ptr(), &mut config.to_raw_config())
46*bb4ee6a4SAndroid Build Coastguard Worker         };
47*bb4ee6a4SAndroid Build Coastguard Worker 
48*bb4ee6a4SAndroid Build Coastguard Worker         if session_ptr.is_null() {
49*bb4ee6a4SAndroid Build Coastguard Worker             return None;
50*bb4ee6a4SAndroid Build Coastguard Worker         }
51*bb4ee6a4SAndroid Build Coastguard Worker 
52*bb4ee6a4SAndroid Build Coastguard Worker         // Dereferencing `session_ptr` is safe because it is a valid pointer to a FD provided by
53*bb4ee6a4SAndroid Build Coastguard Worker         // libvda. We need to dup() the `event_pipe_fd` because File object close() the FD while
54*bb4ee6a4SAndroid Build Coastguard Worker         // libvda also close() it when `close_encode_session` is called.
55*bb4ee6a4SAndroid Build Coastguard Worker         // Calling `from_raw_fd` here is safe because the dup'ed FD is not going to be used by
56*bb4ee6a4SAndroid Build Coastguard Worker         // anything else and `pipe` has full ownership of it.
57*bb4ee6a4SAndroid Build Coastguard Worker         let pipe = unsafe { File::from_raw_fd(libc::dup((*session_ptr).event_pipe_fd)) };
58*bb4ee6a4SAndroid Build Coastguard Worker 
59*bb4ee6a4SAndroid Build Coastguard Worker         Some(Session {
60*bb4ee6a4SAndroid Build Coastguard Worker             connection: Rc::clone(connection),
61*bb4ee6a4SAndroid Build Coastguard Worker             pipe,
62*bb4ee6a4SAndroid Build Coastguard Worker             session_ptr,
63*bb4ee6a4SAndroid Build Coastguard Worker         })
64*bb4ee6a4SAndroid Build Coastguard Worker     }
65*bb4ee6a4SAndroid Build Coastguard Worker 
66*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns a reference for the pipe that notifies of encode events.
pipe(&self) -> &File67*bb4ee6a4SAndroid Build Coastguard Worker     pub fn pipe(&self) -> &File {
68*bb4ee6a4SAndroid Build Coastguard Worker         &self.pipe
69*bb4ee6a4SAndroid Build Coastguard Worker     }
70*bb4ee6a4SAndroid Build Coastguard Worker 
71*bb4ee6a4SAndroid Build Coastguard Worker     /// Reads an `Event` object from a pipe provided by an encode session.
read_event(&mut self) -> Result<Event>72*bb4ee6a4SAndroid Build Coastguard Worker     pub fn read_event(&mut self) -> Result<Event> {
73*bb4ee6a4SAndroid Build Coastguard Worker         const BUF_SIZE: usize = mem::size_of::<bindings::vea_event_t>();
74*bb4ee6a4SAndroid Build Coastguard Worker         let mut buf = [0u8; BUF_SIZE];
75*bb4ee6a4SAndroid Build Coastguard Worker 
76*bb4ee6a4SAndroid Build Coastguard Worker         self.pipe
77*bb4ee6a4SAndroid Build Coastguard Worker             .read_exact(&mut buf)
78*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(Error::ReadEventFailure)?;
79*bb4ee6a4SAndroid Build Coastguard Worker 
80*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because libvda must have written vea_event_t to the pipe.
81*bb4ee6a4SAndroid Build Coastguard Worker         let vea_event = unsafe { mem::transmute::<[u8; BUF_SIZE], bindings::vea_event_t>(buf) };
82*bb4ee6a4SAndroid Build Coastguard Worker 
83*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because `vea_event` is a value read from `self.pipe`.
84*bb4ee6a4SAndroid Build Coastguard Worker         unsafe { Event::new(vea_event) }
85*bb4ee6a4SAndroid Build Coastguard Worker     }
86*bb4ee6a4SAndroid Build Coastguard Worker 
87*bb4ee6a4SAndroid Build Coastguard Worker     /// Sends an encode request for an input buffer given as `fd` with planes described
88*bb4ee6a4SAndroid Build Coastguard Worker     /// by `planes. The timestamp of the frame to encode is typically provided in
89*bb4ee6a4SAndroid Build Coastguard Worker     /// milliseconds by `timestamp`. `force_keyframe` indicates to the encoder that
90*bb4ee6a4SAndroid Build Coastguard Worker     /// the frame should be encoded as a keyframe.
91*bb4ee6a4SAndroid Build Coastguard Worker     ///
92*bb4ee6a4SAndroid Build Coastguard Worker     /// When the input buffer has been filled, an `EncoderEvent::ProcessedInputBuffer`
93*bb4ee6a4SAndroid Build Coastguard Worker     /// event can be read from the event pipe.
94*bb4ee6a4SAndroid Build Coastguard Worker     ///
95*bb4ee6a4SAndroid Build Coastguard Worker     /// The caller is responsible for passing in a unique value for `input_buffer_id`
96*bb4ee6a4SAndroid Build Coastguard Worker     /// which can be referenced when the event is received.
97*bb4ee6a4SAndroid Build Coastguard Worker     ///
98*bb4ee6a4SAndroid Build Coastguard Worker     /// `fd` will be closed after encoding has occurred.
encode( &self, input_buffer_id: VeaInputBufferId, fd: BufferFd, planes: &[FramePlane], timestamp: i64, force_keyframe: bool, ) -> Result<()>99*bb4ee6a4SAndroid Build Coastguard Worker     pub fn encode(
100*bb4ee6a4SAndroid Build Coastguard Worker         &self,
101*bb4ee6a4SAndroid Build Coastguard Worker         input_buffer_id: VeaInputBufferId,
102*bb4ee6a4SAndroid Build Coastguard Worker         fd: BufferFd,
103*bb4ee6a4SAndroid Build Coastguard Worker         planes: &[FramePlane],
104*bb4ee6a4SAndroid Build Coastguard Worker         timestamp: i64,
105*bb4ee6a4SAndroid Build Coastguard Worker         force_keyframe: bool,
106*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
107*bb4ee6a4SAndroid Build Coastguard Worker         let mut planes: Vec<_> = planes.iter().map(FramePlane::to_raw_frame_plane).collect();
108*bb4ee6a4SAndroid Build Coastguard Worker 
109*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because `session_ptr` is valid and libvda's encode API is called properly.
110*bb4ee6a4SAndroid Build Coastguard Worker         let r = unsafe {
111*bb4ee6a4SAndroid Build Coastguard Worker             bindings::vea_encode(
112*bb4ee6a4SAndroid Build Coastguard Worker                 (*self.session_ptr).ctx,
113*bb4ee6a4SAndroid Build Coastguard Worker                 input_buffer_id,
114*bb4ee6a4SAndroid Build Coastguard Worker                 fd,
115*bb4ee6a4SAndroid Build Coastguard Worker                 planes.len(),
116*bb4ee6a4SAndroid Build Coastguard Worker                 planes.as_mut_ptr(),
117*bb4ee6a4SAndroid Build Coastguard Worker                 timestamp,
118*bb4ee6a4SAndroid Build Coastguard Worker                 force_keyframe.into(),
119*bb4ee6a4SAndroid Build Coastguard Worker             )
120*bb4ee6a4SAndroid Build Coastguard Worker         };
121*bb4ee6a4SAndroid Build Coastguard Worker         convert_error_code(r)
122*bb4ee6a4SAndroid Build Coastguard Worker     }
123*bb4ee6a4SAndroid Build Coastguard Worker 
124*bb4ee6a4SAndroid Build Coastguard Worker     /// Provides a buffer for storing encoded output.
125*bb4ee6a4SAndroid Build Coastguard Worker     ///
126*bb4ee6a4SAndroid Build Coastguard Worker     /// When the output buffer has been filled, an `EncoderEvent::ProcessedOutputBuffer`
127*bb4ee6a4SAndroid Build Coastguard Worker     /// event can be read from the event pipe.
128*bb4ee6a4SAndroid Build Coastguard Worker     ///
129*bb4ee6a4SAndroid Build Coastguard Worker     /// The caller is responsible for passing in a unique value for `output_buffer_id`
130*bb4ee6a4SAndroid Build Coastguard Worker     /// which can be referenced when the event is received.
131*bb4ee6a4SAndroid Build Coastguard Worker     ///
132*bb4ee6a4SAndroid Build Coastguard Worker     /// This function takes ownership of `fd`.
use_output_buffer( &self, output_buffer_id: VeaOutputBufferId, fd: BufferFd, offset: u32, size: u32, ) -> Result<()>133*bb4ee6a4SAndroid Build Coastguard Worker     pub fn use_output_buffer(
134*bb4ee6a4SAndroid Build Coastguard Worker         &self,
135*bb4ee6a4SAndroid Build Coastguard Worker         output_buffer_id: VeaOutputBufferId,
136*bb4ee6a4SAndroid Build Coastguard Worker         fd: BufferFd,
137*bb4ee6a4SAndroid Build Coastguard Worker         offset: u32,
138*bb4ee6a4SAndroid Build Coastguard Worker         size: u32,
139*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
140*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because `session_ptr` is valid and libvda's encode API is called properly.
141*bb4ee6a4SAndroid Build Coastguard Worker         let r = unsafe {
142*bb4ee6a4SAndroid Build Coastguard Worker             bindings::vea_use_output_buffer(
143*bb4ee6a4SAndroid Build Coastguard Worker                 (*self.session_ptr).ctx,
144*bb4ee6a4SAndroid Build Coastguard Worker                 output_buffer_id,
145*bb4ee6a4SAndroid Build Coastguard Worker                 fd,
146*bb4ee6a4SAndroid Build Coastguard Worker                 offset,
147*bb4ee6a4SAndroid Build Coastguard Worker                 size,
148*bb4ee6a4SAndroid Build Coastguard Worker             )
149*bb4ee6a4SAndroid Build Coastguard Worker         };
150*bb4ee6a4SAndroid Build Coastguard Worker         convert_error_code(r)
151*bb4ee6a4SAndroid Build Coastguard Worker     }
152*bb4ee6a4SAndroid Build Coastguard Worker 
153*bb4ee6a4SAndroid Build Coastguard Worker     /// Requests encoding parameter changes.
154*bb4ee6a4SAndroid Build Coastguard Worker     ///
155*bb4ee6a4SAndroid Build Coastguard Worker     /// The request is not guaranteed to be honored by libvda and could be ignored
156*bb4ee6a4SAndroid Build Coastguard Worker     /// by the backing encoder implementation.
request_encoding_params_change(&self, bitrate: Bitrate, framerate: u32) -> Result<()>157*bb4ee6a4SAndroid Build Coastguard Worker     pub fn request_encoding_params_change(&self, bitrate: Bitrate, framerate: u32) -> Result<()> {
158*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because `session_ptr` is valid and libvda's encode API is called properly.
159*bb4ee6a4SAndroid Build Coastguard Worker         let r = unsafe {
160*bb4ee6a4SAndroid Build Coastguard Worker             bindings::vea_request_encoding_params_change(
161*bb4ee6a4SAndroid Build Coastguard Worker                 (*self.session_ptr).ctx,
162*bb4ee6a4SAndroid Build Coastguard Worker                 bitrate.to_raw_bitrate(),
163*bb4ee6a4SAndroid Build Coastguard Worker                 framerate,
164*bb4ee6a4SAndroid Build Coastguard Worker             )
165*bb4ee6a4SAndroid Build Coastguard Worker         };
166*bb4ee6a4SAndroid Build Coastguard Worker         convert_error_code(r)
167*bb4ee6a4SAndroid Build Coastguard Worker     }
168*bb4ee6a4SAndroid Build Coastguard Worker 
169*bb4ee6a4SAndroid Build Coastguard Worker     /// Flushes the encode session.
170*bb4ee6a4SAndroid Build Coastguard Worker     ///
171*bb4ee6a4SAndroid Build Coastguard Worker     /// When this operation has completed, Event::FlushResponse can be read from
172*bb4ee6a4SAndroid Build Coastguard Worker     /// the event pipe.
flush(&self) -> Result<()>173*bb4ee6a4SAndroid Build Coastguard Worker     pub fn flush(&self) -> Result<()> {
174*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because `session_ptr` is valid and libvda's encode API is called properly.
175*bb4ee6a4SAndroid Build Coastguard Worker         let r = unsafe { bindings::vea_flush((*self.session_ptr).ctx) };
176*bb4ee6a4SAndroid Build Coastguard Worker         convert_error_code(r)
177*bb4ee6a4SAndroid Build Coastguard Worker     }
178*bb4ee6a4SAndroid Build Coastguard Worker }
179*bb4ee6a4SAndroid Build Coastguard Worker 
180*bb4ee6a4SAndroid Build Coastguard Worker impl Drop for Session {
drop(&mut self)181*bb4ee6a4SAndroid Build Coastguard Worker     fn drop(&mut self) {
182*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because `session_ptr` is unchanged from the time `new` was called, and
183*bb4ee6a4SAndroid Build Coastguard Worker         // `connection` also guarantees that the pointer returned by `conn_ptr()` is a valid
184*bb4ee6a4SAndroid Build Coastguard Worker         // connection to a VEA instance.
185*bb4ee6a4SAndroid Build Coastguard Worker         unsafe {
186*bb4ee6a4SAndroid Build Coastguard Worker             bindings::close_encode_session(self.connection.conn_ptr(), self.session_ptr);
187*bb4ee6a4SAndroid Build Coastguard Worker         }
188*bb4ee6a4SAndroid Build Coastguard Worker     }
189*bb4ee6a4SAndroid Build Coastguard Worker }
190