xref: /aosp_15_r20/external/crosvm/media/libvda/src/decode/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::VdaConnection;
14*bb4ee6a4SAndroid Build Coastguard Worker use crate::error::*;
15*bb4ee6a4SAndroid Build Coastguard Worker use crate::format::BufferFd;
16*bb4ee6a4SAndroid Build Coastguard Worker use crate::format::FramePlane;
17*bb4ee6a4SAndroid Build Coastguard Worker use crate::format::PixelFormat;
18*bb4ee6a4SAndroid Build Coastguard Worker use crate::format::Profile;
19*bb4ee6a4SAndroid Build Coastguard Worker 
20*bb4ee6a4SAndroid Build Coastguard Worker /// Represents a decode session.
21*bb4ee6a4SAndroid Build Coastguard Worker pub struct Session {
22*bb4ee6a4SAndroid Build Coastguard Worker     // Ensures the VDA connection remains open for as long as there are active sessions.
23*bb4ee6a4SAndroid Build Coastguard Worker     connection: Rc<VdaConnection>,
24*bb4ee6a4SAndroid Build Coastguard Worker     // Pipe file to be notified decode session events.
25*bb4ee6a4SAndroid Build Coastguard Worker     pipe: File,
26*bb4ee6a4SAndroid Build Coastguard Worker     session_ptr: *mut bindings::vda_session_info_t,
27*bb4ee6a4SAndroid Build Coastguard Worker }
28*bb4ee6a4SAndroid Build Coastguard Worker 
29*bb4ee6a4SAndroid Build Coastguard Worker impl Session {
30*bb4ee6a4SAndroid Build Coastguard Worker     /// Creates a new `Session`.
new(connection: &Rc<VdaConnection>, profile: Profile) -> Option<Self>31*bb4ee6a4SAndroid Build Coastguard Worker     pub(super) fn new(connection: &Rc<VdaConnection>, profile: Profile) -> Option<Self> {
32*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because `conn_ptr()` is valid and won't be invalidated by `init_decode_session()`.
33*bb4ee6a4SAndroid Build Coastguard Worker         let session_ptr: *mut bindings::vda_session_info_t = unsafe {
34*bb4ee6a4SAndroid Build Coastguard Worker             bindings::init_decode_session(connection.conn_ptr(), profile.to_raw_profile())
35*bb4ee6a4SAndroid Build Coastguard Worker         };
36*bb4ee6a4SAndroid Build Coastguard Worker 
37*bb4ee6a4SAndroid Build Coastguard Worker         if session_ptr.is_null() {
38*bb4ee6a4SAndroid Build Coastguard Worker             return None;
39*bb4ee6a4SAndroid Build Coastguard Worker         }
40*bb4ee6a4SAndroid Build Coastguard Worker 
41*bb4ee6a4SAndroid Build Coastguard Worker         // Dereferencing `session_ptr` is safe because it is a valid pointer to a FD provided by
42*bb4ee6a4SAndroid Build Coastguard Worker         // libvda. We need to dup() the `event_pipe_fd` because File object close() the FD while
43*bb4ee6a4SAndroid Build Coastguard Worker         // libvda also close() it when `close_decode_session` is called.
44*bb4ee6a4SAndroid Build Coastguard Worker         let pipe = unsafe { File::from_raw_fd(libc::dup((*session_ptr).event_pipe_fd)) };
45*bb4ee6a4SAndroid Build Coastguard Worker 
46*bb4ee6a4SAndroid Build Coastguard Worker         Some(Session {
47*bb4ee6a4SAndroid Build Coastguard Worker             connection: Rc::clone(connection),
48*bb4ee6a4SAndroid Build Coastguard Worker             pipe,
49*bb4ee6a4SAndroid Build Coastguard Worker             session_ptr,
50*bb4ee6a4SAndroid Build Coastguard Worker         })
51*bb4ee6a4SAndroid Build Coastguard Worker     }
52*bb4ee6a4SAndroid Build Coastguard Worker 
53*bb4ee6a4SAndroid Build Coastguard Worker     /// Gets a reference of pipe that notifies events from VDA session.
pipe(&self) -> &File54*bb4ee6a4SAndroid Build Coastguard Worker     pub fn pipe(&self) -> &File {
55*bb4ee6a4SAndroid Build Coastguard Worker         &self.pipe
56*bb4ee6a4SAndroid Build Coastguard Worker     }
57*bb4ee6a4SAndroid Build Coastguard Worker 
58*bb4ee6a4SAndroid Build Coastguard Worker     /// Reads an `Event` object from a pipe provided a decode session.
read_event(&mut self) -> Result<Event>59*bb4ee6a4SAndroid Build Coastguard Worker     pub fn read_event(&mut self) -> Result<Event> {
60*bb4ee6a4SAndroid Build Coastguard Worker         const BUF_SIZE: usize = mem::size_of::<bindings::vda_event_t>();
61*bb4ee6a4SAndroid Build Coastguard Worker         let mut buf = [0u8; BUF_SIZE];
62*bb4ee6a4SAndroid Build Coastguard Worker 
63*bb4ee6a4SAndroid Build Coastguard Worker         self.pipe
64*bb4ee6a4SAndroid Build Coastguard Worker             .read_exact(&mut buf)
65*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(Error::ReadEventFailure)?;
66*bb4ee6a4SAndroid Build Coastguard Worker 
67*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because libvda must have written vda_event_t to the pipe.
68*bb4ee6a4SAndroid Build Coastguard Worker         let vda_event = unsafe { mem::transmute::<[u8; BUF_SIZE], bindings::vda_event_t>(buf) };
69*bb4ee6a4SAndroid Build Coastguard Worker 
70*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because `vda_event` is a value read from `self.pipe`.
71*bb4ee6a4SAndroid Build Coastguard Worker         unsafe { Event::new(vda_event) }
72*bb4ee6a4SAndroid Build Coastguard Worker     }
73*bb4ee6a4SAndroid Build Coastguard Worker 
74*bb4ee6a4SAndroid Build Coastguard Worker     /// Sends a decode request for a bitstream buffer given as `fd`.
75*bb4ee6a4SAndroid Build Coastguard Worker     ///
76*bb4ee6a4SAndroid Build Coastguard Worker     /// `fd` will be closed by Chrome after decoding has occurred.
decode( &self, bitstream_id: i32, fd: BufferFd, offset: u32, bytes_used: u32, ) -> Result<()>77*bb4ee6a4SAndroid Build Coastguard Worker     pub fn decode(
78*bb4ee6a4SAndroid Build Coastguard Worker         &self,
79*bb4ee6a4SAndroid Build Coastguard Worker         bitstream_id: i32,
80*bb4ee6a4SAndroid Build Coastguard Worker         fd: BufferFd,
81*bb4ee6a4SAndroid Build Coastguard Worker         offset: u32,
82*bb4ee6a4SAndroid Build Coastguard Worker         bytes_used: u32,
83*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
84*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because `session_ptr` is valid and a libvda's API is called properly.
85*bb4ee6a4SAndroid Build Coastguard Worker         let r = unsafe {
86*bb4ee6a4SAndroid Build Coastguard Worker             bindings::vda_decode(
87*bb4ee6a4SAndroid Build Coastguard Worker                 (*self.session_ptr).ctx,
88*bb4ee6a4SAndroid Build Coastguard Worker                 bitstream_id,
89*bb4ee6a4SAndroid Build Coastguard Worker                 fd,
90*bb4ee6a4SAndroid Build Coastguard Worker                 offset,
91*bb4ee6a4SAndroid Build Coastguard Worker                 bytes_used,
92*bb4ee6a4SAndroid Build Coastguard Worker             )
93*bb4ee6a4SAndroid Build Coastguard Worker         };
94*bb4ee6a4SAndroid Build Coastguard Worker         Response::new(r).into()
95*bb4ee6a4SAndroid Build Coastguard Worker     }
96*bb4ee6a4SAndroid Build Coastguard Worker 
97*bb4ee6a4SAndroid Build Coastguard Worker     /// Sets the number of expected output buffers.
98*bb4ee6a4SAndroid Build Coastguard Worker     ///
99*bb4ee6a4SAndroid Build Coastguard Worker     /// This function must be called after `Event::ProvidePictureBuffers` are notified.
100*bb4ee6a4SAndroid Build Coastguard Worker     /// After calling this function, `user_output_buffer` must be called `num_output_buffers` times.
set_output_buffer_count(&self, num_output_buffers: usize) -> Result<()>101*bb4ee6a4SAndroid Build Coastguard Worker     pub fn set_output_buffer_count(&self, num_output_buffers: usize) -> Result<()> {
102*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because `session_ptr` is valid and a libvda's API is called properly.
103*bb4ee6a4SAndroid Build Coastguard Worker         let r = unsafe {
104*bb4ee6a4SAndroid Build Coastguard Worker             bindings::vda_set_output_buffer_count((*self.session_ptr).ctx, num_output_buffers)
105*bb4ee6a4SAndroid Build Coastguard Worker         };
106*bb4ee6a4SAndroid Build Coastguard Worker         Response::new(r).into()
107*bb4ee6a4SAndroid Build Coastguard Worker     }
108*bb4ee6a4SAndroid Build Coastguard Worker 
109*bb4ee6a4SAndroid Build Coastguard Worker     /// Provides an output buffer that will be filled with decoded frames.
110*bb4ee6a4SAndroid Build Coastguard Worker     ///
111*bb4ee6a4SAndroid Build Coastguard Worker     /// Users calls this function after `set_output_buffer_count`. Then, libvda
112*bb4ee6a4SAndroid Build Coastguard Worker     /// will fill next frames in the buffer and noitify `Event::PictureReady`.
113*bb4ee6a4SAndroid Build Coastguard Worker     ///
114*bb4ee6a4SAndroid Build Coastguard Worker     /// This function is also used to notify that they consumed decoded frames
115*bb4ee6a4SAndroid Build Coastguard Worker     /// in the output buffer.
116*bb4ee6a4SAndroid Build Coastguard Worker     ///
117*bb4ee6a4SAndroid Build Coastguard Worker     /// This function takes ownership of `output_buffer`.
use_output_buffer( &self, picture_buffer_id: i32, format: PixelFormat, output_buffer: BufferFd, planes: &[FramePlane], modifier: u64, ) -> Result<()>118*bb4ee6a4SAndroid Build Coastguard Worker     pub fn use_output_buffer(
119*bb4ee6a4SAndroid Build Coastguard Worker         &self,
120*bb4ee6a4SAndroid Build Coastguard Worker         picture_buffer_id: i32,
121*bb4ee6a4SAndroid Build Coastguard Worker         format: PixelFormat,
122*bb4ee6a4SAndroid Build Coastguard Worker         output_buffer: BufferFd,
123*bb4ee6a4SAndroid Build Coastguard Worker         planes: &[FramePlane],
124*bb4ee6a4SAndroid Build Coastguard Worker         modifier: u64,
125*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
126*bb4ee6a4SAndroid Build Coastguard Worker         let mut planes: Vec<_> = planes.iter().map(FramePlane::to_raw_frame_plane).collect();
127*bb4ee6a4SAndroid Build Coastguard Worker 
128*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because `session_ptr` is valid and a libvda's API is called properly.
129*bb4ee6a4SAndroid Build Coastguard Worker         let r = unsafe {
130*bb4ee6a4SAndroid Build Coastguard Worker             bindings::vda_use_output_buffer(
131*bb4ee6a4SAndroid Build Coastguard Worker                 (*self.session_ptr).ctx,
132*bb4ee6a4SAndroid Build Coastguard Worker                 picture_buffer_id,
133*bb4ee6a4SAndroid Build Coastguard Worker                 format.to_raw_pixel_format(),
134*bb4ee6a4SAndroid Build Coastguard Worker                 output_buffer,
135*bb4ee6a4SAndroid Build Coastguard Worker                 planes.len(),
136*bb4ee6a4SAndroid Build Coastguard Worker                 planes.as_mut_ptr(),
137*bb4ee6a4SAndroid Build Coastguard Worker                 modifier,
138*bb4ee6a4SAndroid Build Coastguard Worker             )
139*bb4ee6a4SAndroid Build Coastguard Worker         };
140*bb4ee6a4SAndroid Build Coastguard Worker         Response::new(r).into()
141*bb4ee6a4SAndroid Build Coastguard Worker     }
142*bb4ee6a4SAndroid Build Coastguard Worker 
143*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns an output buffer for reuse.
144*bb4ee6a4SAndroid Build Coastguard Worker     ///
145*bb4ee6a4SAndroid Build Coastguard Worker     /// `picture_buffer_id` must be a value for which `use_output_buffer` has been called already.
reuse_output_buffer(&self, picture_buffer_id: i32) -> Result<()>146*bb4ee6a4SAndroid Build Coastguard Worker     pub fn reuse_output_buffer(&self, picture_buffer_id: i32) -> Result<()> {
147*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because `session_ptr` is valid and a libvda's API is called properly.
148*bb4ee6a4SAndroid Build Coastguard Worker         let r = unsafe {
149*bb4ee6a4SAndroid Build Coastguard Worker             bindings::vda_reuse_output_buffer((*self.session_ptr).ctx, picture_buffer_id)
150*bb4ee6a4SAndroid Build Coastguard Worker         };
151*bb4ee6a4SAndroid Build Coastguard Worker         Response::new(r).into()
152*bb4ee6a4SAndroid Build Coastguard Worker     }
153*bb4ee6a4SAndroid Build Coastguard Worker 
154*bb4ee6a4SAndroid Build Coastguard Worker     /// Flushes the decode session.
155*bb4ee6a4SAndroid Build Coastguard Worker     ///
156*bb4ee6a4SAndroid Build Coastguard Worker     /// When this operation has completed, `Event::FlushResponse` will be notified.
flush(&self) -> Result<()>157*bb4ee6a4SAndroid Build Coastguard Worker     pub fn flush(&self) -> Result<()> {
158*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because `session_ptr` is valid and a libvda's API is called properly.
159*bb4ee6a4SAndroid Build Coastguard Worker         let r = unsafe { bindings::vda_flush((*self.session_ptr).ctx) };
160*bb4ee6a4SAndroid Build Coastguard Worker         Response::new(r).into()
161*bb4ee6a4SAndroid Build Coastguard Worker     }
162*bb4ee6a4SAndroid Build Coastguard Worker 
163*bb4ee6a4SAndroid Build Coastguard Worker     /// Resets the decode session.
164*bb4ee6a4SAndroid Build Coastguard Worker     ///
165*bb4ee6a4SAndroid Build Coastguard Worker     /// When this operation has completed, Event::ResetResponse will be notified.
reset(&self) -> Result<()>166*bb4ee6a4SAndroid Build Coastguard Worker     pub fn reset(&self) -> Result<()> {
167*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because `session_ptr` is valid and a libvda's API is called properly.
168*bb4ee6a4SAndroid Build Coastguard Worker         let r = unsafe { bindings::vda_reset((*self.session_ptr).ctx) };
169*bb4ee6a4SAndroid Build Coastguard Worker         Response::new(r).into()
170*bb4ee6a4SAndroid Build Coastguard Worker     }
171*bb4ee6a4SAndroid Build Coastguard Worker }
172*bb4ee6a4SAndroid Build Coastguard Worker 
173*bb4ee6a4SAndroid Build Coastguard Worker impl Drop for Session {
drop(&mut self)174*bb4ee6a4SAndroid Build Coastguard Worker     fn drop(&mut self) {
175*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because `session_ptr` is unchanged from the time `new` was called, and
176*bb4ee6a4SAndroid Build Coastguard Worker         // `connection` also guarantees that the pointer returned by `conn_ptr()` is a valid
177*bb4ee6a4SAndroid Build Coastguard Worker         // connection to a VDA instance.
178*bb4ee6a4SAndroid Build Coastguard Worker         unsafe {
179*bb4ee6a4SAndroid Build Coastguard Worker             bindings::close_decode_session(self.connection.conn_ptr(), self.session_ptr);
180*bb4ee6a4SAndroid Build Coastguard Worker         }
181*bb4ee6a4SAndroid Build Coastguard Worker     }
182*bb4ee6a4SAndroid Build Coastguard Worker }
183