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