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