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}