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