// 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::format::Bitrate;13use super::vea_instance::Config;14use super::VeaConnection;15use crate::error::*;16use crate::format::BufferFd;17use crate::format::FramePlane;1819pub type VeaInputBufferId = bindings::vea_input_buffer_id_t;20pub type VeaOutputBufferId = bindings::vea_output_buffer_id_t;2122/// Represents an encode session.23pub struct Session {24// Pipe file to be notified encode session events.25pipe: File,26// Ensures the VEA connection remains open for as long as there are active sessions.27connection: Rc<VeaConnection>,28session_ptr: *mut bindings::vea_session_info_t,29}3031fn convert_error_code(code: i32) -> Result<()> {32if code == 0 {33Ok(())34} else {35Err(Error::EncodeSessionFailure(code))36}37}3839impl Session {40/// Creates a new `Session`.41pub(super) fn new(connection: &Rc<VeaConnection>, config: Config) -> Option<Self> {42// Safe because `conn_ptr()` is valid and won't be invalidated by `init_encode_session()`.43let session_ptr: *mut bindings::vea_session_info_t = unsafe {44bindings::init_encode_session(connection.conn_ptr(), &mut config.to_raw_config())45};4647if session_ptr.is_null() {48return None;49}5051// Dereferencing `session_ptr` is safe because it is a valid pointer to a FD provided by52// libvda. We need to dup() the `event_pipe_fd` because File object close() the FD while53// libvda also close() it when `close_encode_session` is called.54// Calling `from_raw_fd` here is safe because the dup'ed FD is not going to be used by55// anything else and `pipe` has full ownership of it.56let pipe = unsafe { File::from_raw_fd(libc::dup((*session_ptr).event_pipe_fd)) };5758Some(Session {59connection: Rc::clone(connection),60pipe,61session_ptr,62})63}6465/// Returns a reference for the pipe that notifies of encode events.66pub fn pipe(&self) -> &File {67&self.pipe68}6970/// Reads an `Event` object from a pipe provided by an encode session.71pub fn read_event(&mut self) -> Result<Event> {72const BUF_SIZE: usize = mem::size_of::<bindings::vea_event_t>();73let mut buf = [0u8; BUF_SIZE];7475self.pipe76.read_exact(&mut buf)77.map_err(Error::ReadEventFailure)?;7879// Safe because libvda must have written vea_event_t to the pipe.80let vea_event = unsafe { mem::transmute::<[u8; BUF_SIZE], bindings::vea_event_t>(buf) };8182// Safe because `vea_event` is a value read from `self.pipe`.83unsafe { Event::new(vea_event) }84}8586/// Sends an encode request for an input buffer given as `fd` with planes described87/// by `planes. The timestamp of the frame to encode is typically provided in88/// milliseconds by `timestamp`. `force_keyframe` indicates to the encoder that89/// the frame should be encoded as a keyframe.90///91/// When the input buffer has been filled, an `EncoderEvent::ProcessedInputBuffer`92/// event can be read from the event pipe.93///94/// The caller is responsible for passing in a unique value for `input_buffer_id`95/// which can be referenced when the event is received.96///97/// `fd` will be closed after encoding has occurred.98pub fn encode(99&self,100input_buffer_id: VeaInputBufferId,101fd: BufferFd,102planes: &[FramePlane],103timestamp: i64,104force_keyframe: bool,105) -> Result<()> {106let mut planes: Vec<_> = planes.iter().map(FramePlane::to_raw_frame_plane).collect();107108// Safe because `session_ptr` is valid and libvda's encode API is called properly.109let r = unsafe {110bindings::vea_encode(111(*self.session_ptr).ctx,112input_buffer_id,113fd,114planes.len(),115planes.as_mut_ptr(),116timestamp,117force_keyframe.into(),118)119};120convert_error_code(r)121}122123/// Provides a buffer for storing encoded output.124///125/// When the output buffer has been filled, an `EncoderEvent::ProcessedOutputBuffer`126/// event can be read from the event pipe.127///128/// The caller is responsible for passing in a unique value for `output_buffer_id`129/// which can be referenced when the event is received.130///131/// This function takes ownership of `fd`.132pub fn use_output_buffer(133&self,134output_buffer_id: VeaOutputBufferId,135fd: BufferFd,136offset: u32,137size: u32,138) -> Result<()> {139// Safe because `session_ptr` is valid and libvda's encode API is called properly.140let r = unsafe {141bindings::vea_use_output_buffer(142(*self.session_ptr).ctx,143output_buffer_id,144fd,145offset,146size,147)148};149convert_error_code(r)150}151152/// Requests encoding parameter changes.153///154/// The request is not guaranteed to be honored by libvda and could be ignored155/// by the backing encoder implementation.156pub fn request_encoding_params_change(&self, bitrate: Bitrate, framerate: u32) -> Result<()> {157// Safe because `session_ptr` is valid and libvda's encode API is called properly.158let r = unsafe {159bindings::vea_request_encoding_params_change(160(*self.session_ptr).ctx,161bitrate.to_raw_bitrate(),162framerate,163)164};165convert_error_code(r)166}167168/// Flushes the encode session.169///170/// When this operation has completed, Event::FlushResponse can be read from171/// the event pipe.172pub fn flush(&self) -> Result<()> {173// Safe because `session_ptr` is valid and libvda's encode API is called properly.174let r = unsafe { bindings::vea_flush((*self.session_ptr).ctx) };175convert_error_code(r)176}177}178179impl Drop for Session {180fn drop(&mut self) {181// Safe because `session_ptr` is unchanged from the time `new` was called, and182// `connection` also guarantees that the pointer returned by `conn_ptr()` is a valid183// connection to a VEA instance.184unsafe {185bindings::close_encode_session(self.connection.conn_ptr(), self.session_ptr);186}187}188}189190191