Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/media/libvda/src/decode/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::VdaConnection;
14
use crate::error::*;
15
use crate::format::BufferFd;
16
use crate::format::FramePlane;
17
use crate::format::PixelFormat;
18
use crate::format::Profile;
19
20
/// Represents a decode session.
21
pub struct Session {
22
// Ensures the VDA connection remains open for as long as there are active sessions.
23
connection: Rc<VdaConnection>,
24
// Pipe file to be notified decode session events.
25
pipe: File,
26
session_ptr: *mut bindings::vda_session_info_t,
27
}
28
29
impl Session {
30
/// Creates a new `Session`.
31
pub(super) fn new(connection: &Rc<VdaConnection>, profile: Profile) -> Option<Self> {
32
// Safe because `conn_ptr()` is valid and won't be invalidated by `init_decode_session()`.
33
let session_ptr: *mut bindings::vda_session_info_t = unsafe {
34
bindings::init_decode_session(connection.conn_ptr(), profile.to_raw_profile())
35
};
36
37
if session_ptr.is_null() {
38
return None;
39
}
40
41
// Dereferencing `session_ptr` is safe because it is a valid pointer to a FD provided by
42
// libvda. We need to dup() the `event_pipe_fd` because File object close() the FD while
43
// libvda also close() it when `close_decode_session` is called.
44
let pipe = unsafe { File::from_raw_fd(libc::dup((*session_ptr).event_pipe_fd)) };
45
46
Some(Session {
47
connection: Rc::clone(connection),
48
pipe,
49
session_ptr,
50
})
51
}
52
53
/// Gets a reference of pipe that notifies events from VDA session.
54
pub fn pipe(&self) -> &File {
55
&self.pipe
56
}
57
58
/// Reads an `Event` object from a pipe provided a decode session.
59
pub fn read_event(&mut self) -> Result<Event> {
60
const BUF_SIZE: usize = mem::size_of::<bindings::vda_event_t>();
61
let mut buf = [0u8; BUF_SIZE];
62
63
self.pipe
64
.read_exact(&mut buf)
65
.map_err(Error::ReadEventFailure)?;
66
67
// Safe because libvda must have written vda_event_t to the pipe.
68
let vda_event = unsafe { mem::transmute::<[u8; BUF_SIZE], bindings::vda_event_t>(buf) };
69
70
// Safe because `vda_event` is a value read from `self.pipe`.
71
unsafe { Event::new(vda_event) }
72
}
73
74
/// Sends a decode request for a bitstream buffer given as `fd`.
75
///
76
/// `fd` will be closed by Chrome after decoding has occurred.
77
pub fn decode(
78
&self,
79
bitstream_id: i32,
80
fd: BufferFd,
81
offset: u32,
82
bytes_used: u32,
83
) -> Result<()> {
84
// Safe because `session_ptr` is valid and a libvda's API is called properly.
85
let r = unsafe {
86
bindings::vda_decode(
87
(*self.session_ptr).ctx,
88
bitstream_id,
89
fd,
90
offset,
91
bytes_used,
92
)
93
};
94
Response::new(r).into()
95
}
96
97
/// Sets the number of expected output buffers.
98
///
99
/// This function must be called after `Event::ProvidePictureBuffers` are notified.
100
/// After calling this function, `user_output_buffer` must be called `num_output_buffers` times.
101
pub fn set_output_buffer_count(&self, num_output_buffers: usize) -> Result<()> {
102
// Safe because `session_ptr` is valid and a libvda's API is called properly.
103
let r = unsafe {
104
bindings::vda_set_output_buffer_count((*self.session_ptr).ctx, num_output_buffers)
105
};
106
Response::new(r).into()
107
}
108
109
/// Provides an output buffer that will be filled with decoded frames.
110
///
111
/// Users calls this function after `set_output_buffer_count`. Then, libvda
112
/// will fill next frames in the buffer and noitify `Event::PictureReady`.
113
///
114
/// This function is also used to notify that they consumed decoded frames
115
/// in the output buffer.
116
///
117
/// This function takes ownership of `output_buffer`.
118
pub fn use_output_buffer(
119
&self,
120
picture_buffer_id: i32,
121
format: PixelFormat,
122
output_buffer: BufferFd,
123
planes: &[FramePlane],
124
modifier: u64,
125
) -> Result<()> {
126
let mut planes: Vec<_> = planes.iter().map(FramePlane::to_raw_frame_plane).collect();
127
128
// Safe because `session_ptr` is valid and a libvda's API is called properly.
129
let r = unsafe {
130
bindings::vda_use_output_buffer(
131
(*self.session_ptr).ctx,
132
picture_buffer_id,
133
format.to_raw_pixel_format(),
134
output_buffer,
135
planes.len(),
136
planes.as_mut_ptr(),
137
modifier,
138
)
139
};
140
Response::new(r).into()
141
}
142
143
/// Returns an output buffer for reuse.
144
///
145
/// `picture_buffer_id` must be a value for which `use_output_buffer` has been called already.
146
pub fn reuse_output_buffer(&self, picture_buffer_id: i32) -> Result<()> {
147
// Safe because `session_ptr` is valid and a libvda's API is called properly.
148
let r = unsafe {
149
bindings::vda_reuse_output_buffer((*self.session_ptr).ctx, picture_buffer_id)
150
};
151
Response::new(r).into()
152
}
153
154
/// Flushes the decode session.
155
///
156
/// When this operation has completed, `Event::FlushResponse` will be notified.
157
pub fn flush(&self) -> Result<()> {
158
// Safe because `session_ptr` is valid and a libvda's API is called properly.
159
let r = unsafe { bindings::vda_flush((*self.session_ptr).ctx) };
160
Response::new(r).into()
161
}
162
163
/// Resets the decode session.
164
///
165
/// When this operation has completed, Event::ResetResponse will be notified.
166
pub fn reset(&self) -> Result<()> {
167
// Safe because `session_ptr` is valid and a libvda's API is called properly.
168
let r = unsafe { bindings::vda_reset((*self.session_ptr).ctx) };
169
Response::new(r).into()
170
}
171
}
172
173
impl Drop for Session {
174
fn drop(&mut self) {
175
// Safe because `session_ptr` is unchanged from the time `new` was called, and
176
// `connection` also guarantees that the pointer returned by `conn_ptr()` is a valid
177
// connection to a VDA instance.
178
unsafe {
179
bindings::close_decode_session(self.connection.conn_ptr(), self.session_ptr);
180
}
181
}
182
}
183
184