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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
use std::ptr::NonNull;
use std::rc::Rc;
use libde265_sys::*;
use crate::{DeError, Image, Result};
/// Create a new decoder.
pub fn new_decoder() -> Result<(DecoderInput, DecoderOutput)> {
let decoder_context_ptr = unsafe { de265_new_decoder() };
if decoder_context_ptr.is_null() {
return Err(DeError::ErrorLibraryInitializationFailed);
}
let context = Rc::new(DecoderContext {
inner: decoder_context_ptr,
});
Ok((
DecoderInput {
context: context.clone(),
},
DecoderOutput { context },
))
}
#[derive(Debug, Copy, Clone)]
#[non_exhaustive]
pub enum ParamI32 {
/// Dump SPS headers to a specified file-descriptor.
DumpSpsHeaders = de265_param::DE265_DECODER_PARAM_DUMP_SPS_HEADERS as _,
/// Dump VPS headers to a specified file-descriptor.
DumpVpsHeaders = de265_param::DE265_DECODER_PARAM_DUMP_VPS_HEADERS as _,
/// Dump PPS headers to a specified file-descriptor.
DumpPpsHeaders = de265_param::DE265_DECODER_PARAM_DUMP_PPS_HEADERS as _,
/// Dump Slice headers to a specified file-descriptor.
DumpSliceHeaders = de265_param::DE265_DECODER_PARAM_DUMP_SLICE_HEADERS as _,
}
#[derive(Debug, Copy, Clone)]
#[non_exhaustive]
pub enum ParamBool {
/// Perform SEI hash check on decoded pictures.
SeiCheckHash = de265_param::DE265_DECODER_PARAM_BOOL_SEI_CHECK_HASH as _,
/// Do not output frames with decoding errors, default: `false` (output all images)
SuppressFaultyPictures = de265_param::DE265_DECODER_PARAM_SUPPRESS_FAULTY_PICTURES as _,
/// Disable deblocking
DisableDeblocking = de265_param::DE265_DECODER_PARAM_DISABLE_DEBLOCKING as _,
/// Disable SAO filter
DisableSAO = de265_param::DE265_DECODER_PARAM_DISABLE_SAO as _,
}
/// Sorted such that a large ID includes all optimizations from lower IDs
#[derive(Debug, Copy, Clone)]
#[non_exhaustive]
pub enum Acceleration {
/// only fallback implementation
Scalar = de265_acceleration::de265_acceleration_SCALAR as _,
MMS = de265_acceleration::de265_acceleration_MMX as _,
SSE = de265_acceleration::de265_acceleration_SSE as _,
SSE2 = de265_acceleration::de265_acceleration_SSE2 as _,
SSE4 = de265_acceleration::de265_acceleration_SSE4 as _,
/// not implemented yet
AVX = de265_acceleration::de265_acceleration_AVX as _,
/// not implemented yet
AVX2 = de265_acceleration::de265_acceleration_AVX2 as _,
ARM = de265_acceleration::de265_acceleration_ARM as _,
NEON = de265_acceleration::de265_acceleration_NEON as _,
Auto = de265_acceleration::de265_acceleration_AUTO as _,
}
pub(crate) struct DecoderContext {
pub(crate) inner: *mut de265_decoder_context,
}
impl Drop for DecoderContext {
fn drop(&mut self) {
if !self.inner.is_null() {
unsafe { de265_free_decoder(self.inner) };
}
}
}
pub enum DecodeResult {
/// The decoding process was finished.
Done,
/// The decoding process isn't yet finished,
/// and the [`DecoderInput::decode()`] method must be called again.
CallAgain,
}
/// Instance of this type is used to push input data for the decoder.
pub struct DecoderInput {
context: Rc<DecoderContext>,
}
impl DecoderInput {
#[inline(always)]
fn inner(&self) -> *mut de265_decoder_context {
self.context.inner
}
/// Initialize background decoding threads.
///
/// If this function is not called, all decoding is done in
/// the main thread (no multi-threading).
pub fn start_worker_threads(&mut self, num_threads: u32) -> Result<()> {
let result = unsafe {
de265_start_worker_threads(self.inner(), num_threads.min(i32::MAX as _) as _)
};
DeError::from_raw(result)
}
/// Push more data into the decoder.
///
/// Tha data must be a raw h265 bytestream with startcodes.
/// The PTS (presentation time stamp) is assigned to all NALs whose
/// start-code 0x000001 is contained in the data.
/// The bytestream must contain all stuffing-bytes.
/// This function only pushes data into the decoder, nothing will be decoded.
pub fn push_data(&mut self, data: &[u8], pts: i64, user_data: usize) -> Result<()> {
let result = unsafe {
de265_push_data(
self.inner(),
data.as_ptr() as _,
data.len() as _,
pts,
user_data as _,
)
};
DeError::from_raw(result)
}
/// Indicate that the `push_data` method has just received data until the end of a NAL.
/// The remaining pending input data is put into a NAL package and forwarded to the decoder.
pub fn push_end_of_nal(&mut self) {
unsafe { de265_push_end_of_NAL(self.inner()) };
}
/// Indicate that the `push_data` method has just received data until the end of a frame.
///
/// All data pending at the decoder input will be pushed into the decoder,
/// and the decoded picture is pushed to the output queue.
pub fn push_end_of_frame(&mut self) {
unsafe { de265_push_end_of_frame(self.inner()) };
}
/// Push a complete NAL unit without startcode into the decoder.
///
/// The data must still contain all stuffing-bytes.
/// This function only pushes data into the decoder, nothing will be decoded.
pub fn push_nal(&mut self, data: &[u8], pts: i64, user_data: usize) -> Result<()> {
let result = unsafe {
de265_push_NAL(
self.inner(),
data.as_ptr() as _,
data.len() as _,
pts,
user_data as _,
)
};
DeError::from_raw(result)
}
/// Indicate the end-of-stream.
///
/// All data pending at the decoder input will be pushed into the decoder,
/// and the decoded picture queue will be completely emptied.
pub fn flush_data(&mut self) -> Result<()> {
let result = unsafe { de265_flush_data(self.inner()) };
DeError::from_raw(result)
}
/// Return the number of bytes pending at the decoder input.
///
/// Can be used to avoid overflowing the decoder with too much data.
pub fn number_of_input_bytes_pending(&self) -> usize {
let value = unsafe { de265_get_number_of_input_bytes_pending(self.inner()) };
value.max(0) as _
}
/// Return the number of NAL units pending at the decoder input.
///
/// Can be used to avoid overflowing the decoder with too much data.
pub fn number_of_nal_units_pending(&self) -> usize {
let value = unsafe { de265_get_number_of_NAL_units_pending(self.inner()) };
value.max(0) as _
}
/// Do some decoding.
///
/// Returns status whether it did perform some decoding or why it could not do so.
///
/// The result can be one of the following values:
/// - [`DecodeResult::Done`] - decoding was finished;
/// - [`DecodeResult::CallAgain`] - the decoding process isn't yet finished,
/// and the [`DecoderInput::decode()`] method must be called again.
///
/// There are a few errors that indicate that this method should be called again
/// (possibly after resolving the indicated problem).
/// - [`DeError::ErrorImageBufferFull`] - the decoded picture buffer is full,
/// extract some images before continuing;
/// - [`DeError::ErrorWaitingForInputData`] - insert more data
/// before continuing.
pub fn decode(&mut self) -> Result<DecodeResult> {
let mut more = 0;
let result = unsafe { de265_decode(self.inner(), &mut more) };
DeError::from_raw(result).map(|_| {
if more > 0 {
DecodeResult::CallAgain
} else {
DecodeResult::Done
}
})
}
/// Push more data into the decoder.
///
/// The data must be raw h265 bytestream.
/// All complete images in the data will be decoded, hence, do not push
/// too much data at once to prevent image buffer overflows.
/// The end of a picture can only be detected when the succeeding start-code
/// is read from the data.
/// If you want to flush the data and force decoding of the data so far
/// (e.g. at the end of a file), call `decode_data()` with an empty slice as
/// the `data` argument.
#[deprecated(note = "you should use `push_data` or `push_nal` and `decode` methods instead.")]
pub fn decode_data(&mut self, data: &[u8]) -> Result<()> {
let result =
unsafe { de265_decode_data(self.inner(), data.as_ptr() as _, data.len() as _) };
DeError::from_raw(result)
}
/// Clear decoder state. Call this when skipping in the stream.
pub fn reset(&mut self) {
unsafe { de265_reset(self.inner()) };
}
pub fn get_warning(&self) -> Result<()> {
let result = unsafe { de265_get_warning(self.inner()) };
DeError::from_raw(result)
}
/// Returns the maximum layer ID in the stream.
///
/// Note that the maximum layer ID can change throughout the stream.
pub fn highest_tid(&self) -> u32 {
unsafe { de265_get_highest_TID(self.inner()).max(0) as _ }
}
/// Returns an ID of the currently decoded temporal substream.
pub fn current_tid(&self) -> u32 {
unsafe { de265_get_current_TID(self.inner()).max(0) as _ }
}
/// Limits decoding to a maximum temporal layer (TID).
pub fn set_limit_tid(&mut self, max_tid: u32) {
unsafe { de265_set_limit_TID(self.inner(), max_tid.min(i32::MAX as _) as _) };
}
/// It is used for a fine-grained selection of the frame-rate.
///
/// A percentage of 100% will decode all frames in all temporal layers. A lower percentage
/// will drop approximately as many frames. Note that this is only accurate if the frames
/// are distributed evenly among the layers. Otherwise, the mapping is non-linear.
///
/// The TID limit has a higher precedence than the framerate ratio. Hence, setting a higher
/// framerate ratio will decode at TID limit without dropping.
pub fn set_framerate_ratio(&mut self, percent: u8) {
unsafe { de265_set_framerate_ratio(self.inner(), percent as _) };
}
/// Increase or decrease the output frame-rate to some
/// discrete preferable value. Currently, these are non-dropped decoding at various
/// TID layers.
///
/// The `more_vs_less` argument can be one of [-1, 0, 1].
///
/// Returns the corresponding framerate ratio.
pub fn change_framerate(&mut self, more_vs_less: i8) -> u32 {
unsafe {
de265_change_framerate(self.inner(), more_vs_less.clamp(-1, 1) as i32).max(0) as _
}
}
/// Set an integer decoding parameter.
pub fn set_parameter_i32(&mut self, param: ParamI32, val: i32) {
unsafe {
de265_set_parameter_int(self.inner(), param as de265_param::Type, val);
}
}
/// Set a bool decoding parameter.
pub fn set_parameter_bool(&mut self, param: ParamBool, val: bool) {
unsafe {
de265_set_parameter_bool(
self.inner(),
param as de265_param::Type,
if val { 1 } else { 0 },
);
}
}
/// Set acceleration method, default: [`Acceleration::Auto`]
pub fn set_acceleration(&mut self, val: Acceleration) {
unsafe {
de265_set_parameter_int(
self.inner(),
de265_param::DE265_DECODER_PARAM_ACCELERATION_CODE,
val as i32,
);
}
}
/// Get a bool decoding parameter.
pub fn get_parameter_bool(&self, param: ParamBool) -> bool {
unsafe { de265_get_parameter_bool(self.inner(), param as de265_param::Type) != 0 }
}
}
/// Instance of this type is used to receive decoded pictures.
pub struct DecoderOutput {
context: Rc<DecoderContext>,
}
impl DecoderOutput {
#[inline(always)]
pub(crate) fn inner(&self) -> *mut de265_decoder_context {
self.context.inner
}
/// Return the next decoded picture if there is any.
pub fn next_picture(&mut self) -> Option<Image<'_>> {
let image_ptr = unsafe { de265_peek_next_picture(self.inner()) };
NonNull::new(image_ptr as _).map(|p| Image::new(self.context.as_ref(), p))
}
}