nvidia_video_codec_sdk/safe/buffer.rs
1//! Defines traits and types for dealing with input and output buffers.
2
3use std::{ffi::c_void, ptr};
4
5use cudarc::driver::{DevicePtr, MappedBuffer};
6
7use super::{api::ENCODE_API, encoder::Encoder, result::EncodeError, session::Session};
8use crate::sys::nvEncodeAPI::{
9 NV_ENC_BUFFER_FORMAT,
10 NV_ENC_CREATE_BITSTREAM_BUFFER,
11 NV_ENC_CREATE_BITSTREAM_BUFFER_VER,
12 NV_ENC_CREATE_INPUT_BUFFER,
13 NV_ENC_CREATE_INPUT_BUFFER_VER,
14 NV_ENC_INPUT_RESOURCE_TYPE,
15 NV_ENC_LOCK_BITSTREAM,
16 NV_ENC_LOCK_BITSTREAM_VER,
17 NV_ENC_LOCK_INPUT_BUFFER,
18 NV_ENC_LOCK_INPUT_BUFFER_VER,
19 NV_ENC_MAP_INPUT_RESOURCE,
20 NV_ENC_MAP_INPUT_RESOURCE_VER,
21 NV_ENC_PIC_TYPE,
22 NV_ENC_REGISTER_RESOURCE,
23};
24
25/// If a type implements this trait it means it is a valid input buffer
26/// for the encoding API.
27pub trait EncoderInput {
28 /// Get the pitch (AKA stride) of the input resource.
29 fn pitch(&self) -> u32;
30
31 /// Get the handle of the input resource.
32 fn handle(&mut self) -> *mut c_void;
33}
34
35/// If a type implements this trait it means it is a valid output buffer
36/// for the encoding API.
37pub trait EncoderOutput {
38 /// Get the handle of the output resource.
39 fn handle(&mut self) -> *mut c_void;
40}
41
42/// Functions for creating input and output buffers.
43impl Session {
44 /// Create a [`Buffer`].
45 ///
46 /// See [NVIDIA docs](https://docs.nvidia.com/video-technologies/video-codec-sdk/12.0/nvenc-video-encoder-api-prog-guide/index.html#creating-resources-required-to-hold-inputoutput-data).
47 ///
48 /// # Errors
49 ///
50 /// Could error if the `width`, `height`, or `buffer_format` is invalid,
51 /// or if we run out of memory.
52 ///
53 /// # Examples
54 ///
55 /// ```
56 /// # use cudarc::driver::CudaContext;
57 /// # use nvidia_video_codec_sdk::{
58 /// # sys::nvEncodeAPI::{
59 /// # NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_ARGB,
60 /// # NV_ENC_CODEC_H264_GUID,
61 /// # NV_ENC_PIC_PARAMS,
62 /// # NV_ENC_PIC_STRUCT,
63 /// # },
64 /// # Encoder, EncoderInitParams
65 /// # };
66 /// # const WIDTH: u32 = 1920;
67 /// # const HEIGHT: u32 = 1080;
68 /// //* Create encoder. *//
69 /// # let cuda_ctx = CudaContext::new(0).unwrap();
70 /// # let encoder = Encoder::initialize_with_cuda(cuda_ctx).unwrap();
71 ///
72 /// //* Set `encode_guid` and `buffer_format`, and check that H.264 encoding and the ARGB format are supported. *//
73 /// # let encode_guid = NV_ENC_CODEC_H264_GUID;
74 /// # let encode_guids = encoder.get_encode_guids().unwrap();
75 /// # assert!(encode_guids.contains(&encode_guid));
76 /// # let buffer_format = NV_ENC_BUFFER_FORMAT_ARGB;
77 /// # let input_formats = encoder.get_supported_input_formats(encode_guid).unwrap();
78 /// # assert!(input_formats.contains(&buffer_format));
79 ///
80 /// //* Begin encoder session. *//
81 /// # let mut initialize_params = EncoderInitParams::new(encode_guid, WIDTH, HEIGHT);
82 /// # initialize_params.display_aspect_ratio(16, 9)
83 /// # .framerate(30, 1)
84 /// # .enable_picture_type_decision();
85 /// # let session = encoder.start_session(
86 /// # buffer_format,
87 /// # initialize_params,
88 /// # ).unwrap();
89 ///
90 /// // Create an input buffer.
91 /// let _input_buffer = session
92 /// .create_input_buffer()
93 /// .unwrap();
94 /// ```
95 pub fn create_input_buffer(&self) -> Result<Buffer<'_>, EncodeError> {
96 let mut create_input_buffer_params = NV_ENC_CREATE_INPUT_BUFFER {
97 version: NV_ENC_CREATE_INPUT_BUFFER_VER,
98 width: self.width,
99 height: self.height,
100 bufferFmt: self.buffer_format,
101 inputBuffer: ptr::null_mut(),
102 ..Default::default()
103 };
104 unsafe {
105 (ENCODE_API.create_input_buffer)(self.encoder.ptr, &mut create_input_buffer_params)
106 }
107 .result(&self.encoder)?;
108 Ok(Buffer {
109 ptr: create_input_buffer_params.inputBuffer,
110 pitch: self.width,
111 encoder: &self.encoder,
112 })
113 }
114
115 /// Create a [`Bitstream`].
116 ///
117 /// See [NVIDIA docs](https://docs.nvidia.com/video-technologies/video-codec-sdk/12.0/nvenc-video-encoder-api-prog-guide/index.html#creating-resources-required-to-hold-inputoutput-data).
118 ///
119 /// # Errors
120 ///
121 /// Could error is we run out of memory.
122 ///
123 /// # Examples
124 ///
125 /// ```
126 /// # use cudarc::driver::CudaContext;
127 /// # use nvidia_video_codec_sdk::{
128 /// # sys::nvEncodeAPI::{
129 /// # NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_ARGB,
130 /// # NV_ENC_CODEC_H264_GUID,
131 /// # NV_ENC_PIC_PARAMS,
132 /// # NV_ENC_PIC_STRUCT,
133 /// # },
134 /// # Encoder, EncoderInitParams
135 /// # };
136 /// # const WIDTH: u32 = 1920;
137 /// # const HEIGHT: u32 = 1080;
138 /// //* Create encoder. *//
139 /// # let cuda_ctx = CudaContext::new(0).unwrap();
140 /// # let encoder = Encoder::initialize_with_cuda(cuda_ctx).unwrap();
141 ///
142 /// //* Set `encode_guid` and `buffer_format`, and check that H.264 encoding and the ARGB format are supported. *//
143 /// # let encode_guid = NV_ENC_CODEC_H264_GUID;
144 /// # let encode_guids = encoder.get_encode_guids().unwrap();
145 /// # assert!(encode_guids.contains(&encode_guid));
146 /// # let buffer_format = NV_ENC_BUFFER_FORMAT_ARGB;
147 /// # let input_formats = encoder.get_supported_input_formats(encode_guid).unwrap();
148 /// # assert!(input_formats.contains(&buffer_format));
149 ///
150 /// //* Begin encoder session. *//
151 /// # let mut initialize_params = EncoderInitParams::new(encode_guid, WIDTH, HEIGHT);
152 /// # initialize_params.display_aspect_ratio(16, 9)
153 /// # .framerate(30, 1)
154 /// # .enable_picture_type_decision();
155 /// # let session = encoder.start_session(
156 /// # buffer_format,
157 /// # initialize_params,
158 /// # ).unwrap();
159 ///
160 /// // Create an output bitstream buffer.
161 /// let _output_bitstream = session
162 /// .create_output_bitstream()
163 /// .unwrap();
164 /// ```
165 pub fn create_output_bitstream(&self) -> Result<Bitstream<'_>, EncodeError> {
166 let mut create_bitstream_buffer_params = NV_ENC_CREATE_BITSTREAM_BUFFER {
167 version: NV_ENC_CREATE_BITSTREAM_BUFFER_VER,
168 bitstreamBuffer: ptr::null_mut(),
169 ..Default::default()
170 };
171 unsafe {
172 (ENCODE_API.create_bitstream_buffer)(
173 self.encoder.ptr,
174 &mut create_bitstream_buffer_params,
175 )
176 }
177 .result(&self.encoder)?;
178 Ok(Bitstream {
179 ptr: create_bitstream_buffer_params.bitstreamBuffer,
180 encoder: &self.encoder,
181 })
182 }
183
184 /// Create a [`RegisteredResource`] from a [`MappedBuffer`].
185 ///
186 /// See [`Session::register_generic_resource`].
187 ///
188 /// `pitch` should be set to the value obtained from `cuMemAllocPitch()`,
189 /// or to the width in **bytes** (if this resource was created by using
190 /// `cuMemAlloc()`). This value must be a multiple of 4.
191 ///
192 /// # Errors
193 ///
194 /// Could error if registration or mapping fails,
195 /// if the resource is invalid, or if we run out of memory.
196 pub fn register_cuda_resource(
197 &self,
198 pitch: u32,
199 mapped_buffer: MappedBuffer,
200 ) -> Result<RegisteredResource<'_, MappedBuffer>, EncodeError> {
201 let stream = self.encoder.ctx.default_stream();
202 let (device_ptr, _) = mapped_buffer.device_ptr(&stream);
203 self.register_generic_resource(
204 mapped_buffer,
205 NV_ENC_INPUT_RESOURCE_TYPE::NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR,
206 device_ptr as *mut c_void,
207 pitch,
208 )
209 }
210
211 /// Create a [`RegisteredResource`].
212 ///
213 /// This function is generic in the marker. This is so that you can
214 /// optionally put a value on the [`RegisteredResource`] to make sure that
215 /// value does not get dropped while the resource is registered. You should
216 /// prefer using specific functions for the resource you are registering,
217 /// such as [`Session::register_cuda_resource`], when they are available.
218 ///
219 /// See [NVIDIA docs](https://docs.nvidia.com/video-technologies/video-codec-sdk/12.0/nvenc-video-encoder-api-prog-guide/index.html#input-buffers-allocated-externally).
220 ///
221 /// # Errors
222 ///
223 /// Could error if registration or mapping fails,
224 /// if the resource is invalid, or if we run out of memory.
225 pub fn register_generic_resource<T>(
226 &self,
227 marker: T,
228 resource_type: NV_ENC_INPUT_RESOURCE_TYPE,
229 resource_to_register: *mut c_void,
230 pitch: u32,
231 ) -> Result<RegisteredResource<'_, T>, EncodeError> {
232 // Register resource.
233 let mut register_resource_params = NV_ENC_REGISTER_RESOURCE::new(
234 resource_type,
235 self.width,
236 self.height,
237 resource_to_register,
238 self.buffer_format,
239 )
240 .pitch(pitch);
241 unsafe { (ENCODE_API.register_resource)(self.encoder.ptr, &mut register_resource_params) }
242 .result(&self.encoder)?;
243 let registered_resource = register_resource_params.registeredResource;
244
245 // Map resource.
246 let mut map_input_resource_params = NV_ENC_MAP_INPUT_RESOURCE {
247 version: NV_ENC_MAP_INPUT_RESOURCE_VER,
248 registeredResource: registered_resource,
249 mappedResource: ptr::null_mut(),
250 mappedBufferFmt: NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_UNDEFINED,
251 ..Default::default()
252 };
253 unsafe {
254 (ENCODE_API.map_input_resource)(self.encoder.ptr, &mut map_input_resource_params)
255 }
256 .result(&self.encoder)?;
257
258 let mapped_resource = map_input_resource_params.mappedResource;
259 Ok(RegisteredResource {
260 reg_ptr: registered_resource,
261 map_ptr: mapped_resource,
262 pitch,
263 encoder: &self.encoder,
264 _marker: marker,
265 })
266 }
267}
268
269/// Abstraction around input buffer allocated using
270/// the NVIDIA Video Encoder API.
271///
272/// The buffer is automatically destroyed when dropped.
273#[derive(Debug)]
274pub struct Buffer<'a> {
275 pub(crate) ptr: *mut c_void,
276 pitch: u32,
277 encoder: &'a Encoder,
278}
279
280unsafe impl Send for Buffer<'_> {}
281
282impl<'a> Buffer<'a> {
283 /// Lock the input buffer.
284 ///
285 /// On a successful lock you get a [`BufferLock`] which can be used to write
286 /// data to the input buffer. On drop, [`BufferLock`] will unlock the
287 /// buffer.
288 ///
289 /// This function will block until a lock is acquired. For the non-blocking
290 /// version see [`Buffer::try_lock`].
291 ///
292 /// See [NVIDIA docs](https://docs.nvidia.com/video-technologies/video-codec-sdk/12.0/nvenc-video-encoder-api-prog-guide/index.html#input-buffers-allocated-through-nvidia-video-encoder-interface).
293 ///
294 /// # Errors
295 ///
296 /// Could error if we run out of memory.
297 ///
298 /// # Examples
299 ///
300 /// ```
301 /// # use cudarc::driver::CudaContext;
302 /// # use nvidia_video_codec_sdk::{
303 /// # sys::nvEncodeAPI::{
304 /// # NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_ARGB,
305 /// # NV_ENC_CODEC_H264_GUID,
306 /// # NV_ENC_PIC_PARAMS,
307 /// # NV_ENC_PIC_STRUCT,
308 /// # },
309 /// # Encoder, EncoderInitParams
310 /// # };
311 /// # const WIDTH: u32 = 1920;
312 /// # const HEIGHT: u32 = 1080;
313 /// # const DATA_LEN: usize = (WIDTH * HEIGHT * 4) as usize;
314 /// //* Create encoder. *//
315 /// # let cuda_ctx = CudaContext::new(0).unwrap();
316 /// # let encoder = Encoder::initialize_with_cuda(cuda_ctx).unwrap();
317 /// //* Set `encode_guid` and `buffer_format`, and check that H.264 encoding and the ARGB format are supported. *//
318 /// # let encode_guid = NV_ENC_CODEC_H264_GUID;
319 /// # let encode_guids = encoder.get_encode_guids().unwrap();
320 /// # assert!(encode_guids.contains(&encode_guid));
321 /// # let buffer_format = NV_ENC_BUFFER_FORMAT_ARGB;
322 /// # let input_formats = encoder.get_supported_input_formats(encode_guid).unwrap();
323 /// # assert!(input_formats.contains(&buffer_format));
324 /// //* Begin encoder session. *//
325 /// # let mut initialize_params = EncoderInitParams::new(encode_guid, WIDTH, HEIGHT);
326 /// # initialize_params.display_aspect_ratio(16, 9)
327 /// # .framerate(30, 1)
328 /// # .enable_picture_type_decision();
329 /// # let session = encoder.start_session(
330 /// # buffer_format,
331 /// # initialize_params,
332 /// # ).unwrap();
333 ///
334 /// // Create an input buffer.
335 /// let mut input_buffer = session
336 /// .create_input_buffer()
337 /// .unwrap();
338 /// unsafe { input_buffer.lock().unwrap().write(&[0; DATA_LEN]) };
339 /// ```
340 pub fn lock<'b>(&'b mut self) -> Result<BufferLock<'b, 'a>, EncodeError> {
341 self.lock_inner(true)
342 }
343
344 /// Non-blocking version of [`Buffer::lock`]. See it for more info.
345 ///
346 /// This function will return an error with
347 /// [`ErrorKind::EncoderBusy`](super::ErrorKind::EncoderBusy) or
348 /// [`ErrorKind::LockBusy`](super::ErrorKind::LockBusy) if the lock is being
349 /// used. The NVIDIA documentation from the header file is unclear about
350 /// this.
351 ///
352 /// # Errors
353 ///
354 /// Could error if we run out of memory.
355 ///
356 /// If this returns an error with
357 /// [`ErrorKind::EncoderBusy`](super::ErrorKind::EncoderBusy) or
358 /// [`ErrorKind::LockBusy`](super::ErrorKind::LockBusy) then that means the
359 /// lock is still busy and the client should retry in a few
360 /// milliseconds.
361 pub fn try_lock<'b>(&'b mut self) -> Result<BufferLock<'b, 'a>, EncodeError> {
362 self.lock_inner(false)
363 }
364
365 #[inline]
366 fn lock_inner<'b>(&'b mut self, wait: bool) -> Result<BufferLock<'b, 'a>, EncodeError> {
367 let mut lock_input_buffer_params = NV_ENC_LOCK_INPUT_BUFFER {
368 version: NV_ENC_LOCK_INPUT_BUFFER_VER,
369 inputBuffer: self.ptr,
370 ..Default::default()
371 };
372 if !wait {
373 lock_input_buffer_params.set_doNotWait(1);
374 }
375 unsafe { (ENCODE_API.lock_input_buffer)(self.encoder.ptr, &mut lock_input_buffer_params) }
376 .result(self.encoder)?;
377
378 let data_ptr = lock_input_buffer_params.bufferDataPtr;
379 let pitch = lock_input_buffer_params.pitch;
380 self.pitch = pitch;
381
382 Ok(BufferLock {
383 buffer: self,
384 data_ptr,
385 pitch,
386 })
387 }
388}
389
390impl Drop for Buffer<'_> {
391 fn drop(&mut self) {
392 unsafe { (ENCODE_API.destroy_input_buffer)(self.encoder.ptr, self.ptr) }
393 .result(self.encoder)
394 .expect("The encoder and buffer pointers should be valid.");
395 }
396}
397
398impl EncoderInput for Buffer<'_> {
399 fn pitch(&self) -> u32 {
400 self.pitch
401 }
402
403 fn handle(&mut self) -> *mut c_void {
404 self.ptr
405 }
406}
407
408/// An RAII lock on the input buffer.
409///
410/// This type is created via [`Buffer::lock`] or [`Buffer::try_lock`].
411/// The purpose of this type is similar to [`std::sync::MutexGuard`] -
412/// it automatically unlocks the buffer when the lock goes out of scope.
413#[allow(clippy::module_name_repetitions)]
414#[derive(Debug)]
415pub struct BufferLock<'a, 'b> {
416 buffer: &'a Buffer<'b>,
417 data_ptr: *mut c_void,
418 #[allow(dead_code)]
419 pitch: u32,
420}
421
422impl BufferLock<'_, '_> {
423 /// Write data to the buffer.
424 ///
425 /// # Safety
426 ///
427 /// The size of the data should be less or equal to the size of the buffer.
428 /// The size of the buffer depends on the width, height, and buffer format.
429 ///
430 /// The user should also account for pitch, the data is written
431 /// contiguously.
432 pub unsafe fn write(&mut self, data: &[u8]) {
433 // TODO: Make this safe by doing checks.
434 // - Check that length of data fits (depends on format).
435 // - Write pitched?
436 data.as_ptr()
437 .copy_to(self.data_ptr.cast::<u8>(), data.len());
438 }
439}
440
441impl Drop for BufferLock<'_, '_> {
442 fn drop(&mut self) {
443 unsafe { (ENCODE_API.unlock_input_buffer)(self.buffer.encoder.ptr, self.buffer.ptr) }
444 .result(self.buffer.encoder)
445 .expect("The encoder and buffer pointers should be valid.");
446 }
447}
448
449/// Abstraction around the output bitstream buffer that
450/// is used as the output of the encoding.
451///
452/// The buffer is automatically destroyed when dropped.
453#[derive(Debug)]
454pub struct Bitstream<'a> {
455 pub(crate) ptr: *mut c_void,
456 encoder: &'a Encoder,
457}
458
459unsafe impl Send for Bitstream<'_> {}
460
461impl Bitstream<'_> {
462 /// Lock the output bitstream.
463 ///
464 /// On a successful lock you get a [`BitstreamLock`] which can be used to
465 /// access the bitstream data as well as any other information the
466 /// encoder provides when locking a bitstream.
467 ///
468 /// This function will block until a lock is acquired. For the non-blocking
469 /// version see [`Bitstream::try_lock`].
470 ///
471 /// See [NVIDIA docs](https://docs.nvidia.com/video-technologies/video-codec-sdk/12.0/nvenc-video-encoder-api-prog-guide/index.html#retrieving-encoded-output).
472 ///
473 /// # Errors
474 ///
475 /// Could error if we run out of memory.
476 pub fn lock(&mut self) -> Result<BitstreamLock<'_, '_>, EncodeError> {
477 self.lock_inner(true)
478 }
479
480 /// Non-blocking version of [`Bitstream::lock`]. See it for more info.
481 ///
482 /// This function will return an error with
483 /// [`ErrorKind::LockBusy`](super::ErrorKind::LockBusy) if the
484 /// lock is currently busy.
485 ///
486 /// # Errors
487 ///
488 /// Could error if we run out of memory.
489 ///
490 /// An error with [`ErrorKind::LockBusy`](super::ErrorKind::LockBusy) could
491 /// be returned if the lock is currently busy. This is a recoverable
492 /// error and the client should retry in a few milliseconds.
493 pub fn try_lock(&mut self) -> Result<BitstreamLock<'_, '_>, EncodeError> {
494 self.lock_inner(false)
495 }
496
497 fn lock_inner(&mut self, wait: bool) -> Result<BitstreamLock<'_, '_>, EncodeError> {
498 // Lock bitstream.
499 let mut lock_bitstream_buffer_params = NV_ENC_LOCK_BITSTREAM {
500 version: NV_ENC_LOCK_BITSTREAM_VER,
501 outputBitstream: self.ptr,
502 ..Default::default()
503 };
504 if !wait {
505 lock_bitstream_buffer_params.set_doNotWait(1);
506 }
507 unsafe { (ENCODE_API.lock_bitstream)(self.encoder.ptr, &mut lock_bitstream_buffer_params) }
508 .result(self.encoder)?;
509
510 // Get data.
511 let data_ptr = lock_bitstream_buffer_params.bitstreamBufferPtr;
512 let data_size = lock_bitstream_buffer_params.bitstreamSizeInBytes as usize;
513 let data = unsafe { std::slice::from_raw_parts_mut(data_ptr.cast::<u8>(), data_size) };
514
515 Ok(BitstreamLock {
516 bitstream: self,
517 data,
518 frame_index: lock_bitstream_buffer_params.frameIdx,
519 timestamp: lock_bitstream_buffer_params.outputTimeStamp,
520 duration: lock_bitstream_buffer_params.outputDuration,
521 picture_type: lock_bitstream_buffer_params.pictureType,
522 })
523 }
524}
525
526impl Drop for Bitstream<'_> {
527 fn drop(&mut self) {
528 unsafe { (ENCODE_API.destroy_bitstream_buffer)(self.encoder.ptr, self.ptr) }
529 .result(self.encoder)
530 .expect("The encoder and bitstream pointers should be valid.");
531 }
532}
533
534impl EncoderOutput for Bitstream<'_> {
535 fn handle(&mut self) -> *mut c_void {
536 self.ptr
537 }
538}
539
540/// An RAII lock on the output bitstream buffer.
541///
542/// This type is created via [`Bitstream::lock`] or [`Bitstream::try_lock`].
543/// The purpose of this type is similar to [`std::sync::MutexGuard`] -
544/// it automatically unlocks the buffer when the lock goes out of scope.
545#[derive(Debug)]
546pub struct BitstreamLock<'a, 'b> {
547 bitstream: &'a Bitstream<'b>,
548 data: &'a [u8],
549 // statistics and other info
550 frame_index: u32,
551 timestamp: u64,
552 duration: u64,
553 picture_type: NV_ENC_PIC_TYPE,
554 // TODO: other fields
555}
556
557impl BitstreamLock<'_, '_> {
558 /// Getter for the data contained in the output bitstream.
559 #[must_use]
560 pub fn data(&self) -> &[u8] {
561 self.data
562 }
563
564 /// Getter for the frame index.
565 #[must_use]
566 pub fn frame_index(&self) -> u32 {
567 self.frame_index
568 }
569
570 /// Getter for the timestamp.
571 #[must_use]
572 pub fn timestamp(&self) -> u64 {
573 self.timestamp
574 }
575
576 /// Getter for the duration.
577 #[must_use]
578 pub fn duration(&self) -> u64 {
579 self.duration
580 }
581
582 /// Getter for the picture type.
583 #[must_use]
584 pub fn picture_type(&self) -> NV_ENC_PIC_TYPE {
585 self.picture_type
586 }
587}
588
589impl Drop for BitstreamLock<'_, '_> {
590 fn drop(&mut self) {
591 unsafe { (ENCODE_API.unlock_bitstream)(self.bitstream.encoder.ptr, self.bitstream.ptr) }
592 .result(self.bitstream.encoder)
593 .expect("The encoder and bitstream pointers should be valid.");
594 }
595}
596
597/// Abstraction for a registered and mapped external resource.
598///
599/// The Encoder API exposes a way to use input buffers allocated externally,
600/// for example through CUDA or OpenGL.
601///
602/// The buffer is automatically unmapped and unregistered when dropped.
603/// The external buffer memory should still be properly destroyed by the client.
604#[derive(Debug)]
605pub struct RegisteredResource<'a, T> {
606 pub(crate) reg_ptr: *mut c_void,
607 pub(crate) map_ptr: *mut c_void,
608 pitch: u32,
609 encoder: &'a Encoder,
610 // A generic marker to make sure the external resources are dropped
611 // after the resource is unregistered.
612 _marker: T,
613}
614
615unsafe impl Send for RegisteredResource<'_, MappedBuffer> {}
616
617/// Automatically unmap and unregister the external resource
618/// when it goes out of scope.
619impl<T> Drop for RegisteredResource<'_, T> {
620 fn drop(&mut self) {
621 // Unmapping resource.
622 unsafe { (ENCODE_API.unmap_input_resource)(self.encoder.ptr, self.map_ptr) }
623 .result(self.encoder)
624 .expect("The encoder pointer and map handle should be valid.");
625 // Unregister resource.
626 unsafe { (ENCODE_API.unregister_resource)(self.encoder.ptr, self.reg_ptr) }
627 .result(self.encoder)
628 .expect("The encoder pointer and resource handle should be valid.");
629 }
630}
631
632impl<T> EncoderInput for RegisteredResource<'_, T> {
633 fn pitch(&self) -> u32 {
634 self.pitch
635 }
636
637 fn handle(&mut self) -> *mut c_void {
638 self.map_ptr
639 }
640}