1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! Codec contexts.
use std::{ptr, sync::Arc};
use crate::{
buffer::Buffer, check, check_log, config::Config, display::DisplayOwner, raw::VAContextID,
surface::Surface, Result,
};
/// A codec, configured for a video operation.
///
/// Submit work to a context by calling [`Context::begin_picture`].
pub struct Context {
pub(crate) d: Arc<DisplayOwner>,
pub(crate) id: VAContextID,
}
impl Context {
pub fn new(config: &Config, picture_width: u32, picture_height: u32) -> Result<Self> {
unsafe {
let mut context_id = 0;
check(
"vaCreateContext",
config.d.libva.vaCreateContext(
config.d.raw,
config.id,
picture_width as _,
picture_height as _,
0,
ptr::null_mut(),
0,
&mut context_id,
),
)?;
Ok(Context {
d: config.d.clone(),
id: context_id,
})
}
}
/// Begins a libva operation that will render to (or encode from) the given [`Surface`].
///
/// Returns an [`InProgressPicture`] that can be used to submit parameter and data buffers to
/// libva.
pub fn begin_picture<'a>(
&'a mut self,
target: &'a mut Surface,
) -> Result<InProgressPicture<'a>> {
unsafe {
check(
"vaBeginPicture",
self.d
.libva
.vaBeginPicture(self.d.raw, self.id, target.id()),
)?;
}
Ok(InProgressPicture {
d: self.d.clone(),
context: self,
})
}
}
impl Drop for Context {
fn drop(&mut self) {
unsafe {
check_log(
"vaDestroyContext",
self.d.libva.vaDestroyContext(self.d.raw, self.id),
);
}
}
}
/// An operation whose submission is still in progress.
///
/// Submit parameter and data buffers with [`InProgressPicture::render_picture`] and finish the
/// operation, kicking off decoding or encoding, by calling [`InProgressPicture::end_picture`].
pub struct InProgressPicture<'a> {
d: Arc<DisplayOwner>,
context: &'a mut Context,
}
impl<'a> InProgressPicture<'a> {
/// Submits a [`Buffer`] as part of this libva operation.
///
/// Typically, libva does not document which buffer types are required for any given entry
/// point, so good luck!
///
/// # Safety
///
/// Buffers containing metadata structures must contain a valid value of the particular subtype
/// required by the configured [`Profile`][crate::Profile] and
/// [`Entrypoint`][crate::Entrypoint].
///
/// For example, when using [`Profile::JPEGBaseline`][crate::Profile::JPEGBaseline] and
/// [`Entrypoint::VLD`][crate::Entrypoint::VLD], submitting a [`Buffer`] with
/// [`BufferType::SliceParameter`][crate::buffer::BufferType::SliceParameter] requires that the
/// [`Buffer`] contains a [`jpeg::SliceParameterBuffer`][crate::jpeg::SliceParameterBuffer],
/// and submitting only the substructure [`SliceParameterBufferBase`] will cause Undefined
/// Behavior.
///
/// [`SliceParameterBufferBase`]: crate::SliceParameterBufferBase
pub unsafe fn render_picture<T>(&mut self, buffer: &mut Buffer<T>) -> Result<()> {
check(
"vaRenderPicture",
self.d
.libva
.vaRenderPicture(self.d.raw, self.context.id, &mut buffer.id(), 1),
)
}
/// Finishes submitting buffers, and begins the libva operation (encode, decode, etc.).
///
/// # Safety
///
/// libva does not specify when Undefined Behavior occurs, and in practice at least some
/// implementations exhibit UB-like behavior when buffers are submitted incorrectly (or when
/// not all buffers required by the operation were submitted). It also does not document which
/// buffer types must be submitted (or must not be submitted) for any given entry point.
///
/// So, basically, the safety invariant of this method is "fuck if I know". Good luck, Loser.
pub unsafe fn end_picture(self) -> Result<()> {
check(
"vaEndPicture",
self.d.libva.vaEndPicture(self.d.raw, self.context.id),
)
}
}