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}