Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/media/libvda/src/encode/session.rs
5394 views
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
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`.
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.
67
pub fn pipe(&self) -> &File {
68
&self.pipe
69
}
70
71
/// Reads an `Event` object from a pipe provided by an encode session.
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.
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`.
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.
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.
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 {
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
191