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