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