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