// Copyright 2020 The ChromiumOS Authors1// Use of this source code is governed by a BSD-style license that can be2// found in the LICENSE file.34use std::fs::File;5use std::io::Read;6use std::mem;7use std::os::unix::io::FromRawFd;8use std::rc::Rc;910use super::bindings;11use super::event::*;12use super::VdaConnection;13use crate::error::*;14use crate::format::BufferFd;15use crate::format::FramePlane;16use crate::format::PixelFormat;17use crate::format::Profile;1819/// Represents a decode session.20pub struct Session {21// Ensures the VDA connection remains open for as long as there are active sessions.22connection: Rc<VdaConnection>,23// Pipe file to be notified decode session events.24pipe: File,25session_ptr: *mut bindings::vda_session_info_t,26}2728impl Session {29/// Creates a new `Session`.30pub(super) fn new(connection: &Rc<VdaConnection>, profile: Profile) -> Option<Self> {31// Safe because `conn_ptr()` is valid and won't be invalidated by `init_decode_session()`.32let session_ptr: *mut bindings::vda_session_info_t = unsafe {33bindings::init_decode_session(connection.conn_ptr(), profile.to_raw_profile())34};3536if session_ptr.is_null() {37return None;38}3940// Dereferencing `session_ptr` is safe because it is a valid pointer to a FD provided by41// libvda. We need to dup() the `event_pipe_fd` because File object close() the FD while42// libvda also close() it when `close_decode_session` is called.43let pipe = unsafe { File::from_raw_fd(libc::dup((*session_ptr).event_pipe_fd)) };4445Some(Session {46connection: Rc::clone(connection),47pipe,48session_ptr,49})50}5152/// Gets a reference of pipe that notifies events from VDA session.53pub fn pipe(&self) -> &File {54&self.pipe55}5657/// Reads an `Event` object from a pipe provided a decode session.58pub fn read_event(&mut self) -> Result<Event> {59const BUF_SIZE: usize = mem::size_of::<bindings::vda_event_t>();60let mut buf = [0u8; BUF_SIZE];6162self.pipe63.read_exact(&mut buf)64.map_err(Error::ReadEventFailure)?;6566// Safe because libvda must have written vda_event_t to the pipe.67let vda_event = unsafe { mem::transmute::<[u8; BUF_SIZE], bindings::vda_event_t>(buf) };6869// Safe because `vda_event` is a value read from `self.pipe`.70unsafe { Event::new(vda_event) }71}7273/// Sends a decode request for a bitstream buffer given as `fd`.74///75/// `fd` will be closed by Chrome after decoding has occurred.76pub fn decode(77&self,78bitstream_id: i32,79fd: BufferFd,80offset: u32,81bytes_used: u32,82) -> Result<()> {83// Safe because `session_ptr` is valid and a libvda's API is called properly.84let r = unsafe {85bindings::vda_decode(86(*self.session_ptr).ctx,87bitstream_id,88fd,89offset,90bytes_used,91)92};93Response::new(r).into()94}9596/// Sets the number of expected output buffers.97///98/// This function must be called after `Event::ProvidePictureBuffers` are notified.99/// After calling this function, `user_output_buffer` must be called `num_output_buffers` times.100pub fn set_output_buffer_count(&self, num_output_buffers: usize) -> Result<()> {101// Safe because `session_ptr` is valid and a libvda's API is called properly.102let r = unsafe {103bindings::vda_set_output_buffer_count((*self.session_ptr).ctx, num_output_buffers)104};105Response::new(r).into()106}107108/// Provides an output buffer that will be filled with decoded frames.109///110/// Users calls this function after `set_output_buffer_count`. Then, libvda111/// will fill next frames in the buffer and noitify `Event::PictureReady`.112///113/// This function is also used to notify that they consumed decoded frames114/// in the output buffer.115///116/// This function takes ownership of `output_buffer`.117pub fn use_output_buffer(118&self,119picture_buffer_id: i32,120format: PixelFormat,121output_buffer: BufferFd,122planes: &[FramePlane],123modifier: u64,124) -> Result<()> {125let mut planes: Vec<_> = planes.iter().map(FramePlane::to_raw_frame_plane).collect();126127// Safe because `session_ptr` is valid and a libvda's API is called properly.128let r = unsafe {129bindings::vda_use_output_buffer(130(*self.session_ptr).ctx,131picture_buffer_id,132format.to_raw_pixel_format(),133output_buffer,134planes.len(),135planes.as_mut_ptr(),136modifier,137)138};139Response::new(r).into()140}141142/// Returns an output buffer for reuse.143///144/// `picture_buffer_id` must be a value for which `use_output_buffer` has been called already.145pub fn reuse_output_buffer(&self, picture_buffer_id: i32) -> Result<()> {146// Safe because `session_ptr` is valid and a libvda's API is called properly.147let r = unsafe {148bindings::vda_reuse_output_buffer((*self.session_ptr).ctx, picture_buffer_id)149};150Response::new(r).into()151}152153/// Flushes the decode session.154///155/// When this operation has completed, `Event::FlushResponse` will be notified.156pub fn flush(&self) -> Result<()> {157// Safe because `session_ptr` is valid and a libvda's API is called properly.158let r = unsafe { bindings::vda_flush((*self.session_ptr).ctx) };159Response::new(r).into()160}161162/// Resets the decode session.163///164/// When this operation has completed, Event::ResetResponse will be notified.165pub fn reset(&self) -> Result<()> {166// Safe because `session_ptr` is valid and a libvda's API is called properly.167let r = unsafe { bindings::vda_reset((*self.session_ptr).ctx) };168Response::new(r).into()169}170}171172impl Drop for Session {173fn drop(&mut self) {174// Safe because `session_ptr` is unchanged from the time `new` was called, and175// `connection` also guarantees that the pointer returned by `conn_ptr()` is a valid176// connection to a VDA instance.177unsafe {178bindings::close_decode_session(self.connection.conn_ptr(), self.session_ptr);179}180}181}182183184