1use crate::ffi::*;
5use crate::load::SharedLibrary;
6use crate::{NvInt, NvencError};
7use std::ptr::addr_of_mut;
8use std::{
9 fmt::{Debug, Formatter},
10 mem::MaybeUninit,
11 pin::Pin,
12 rc::Rc,
13};
14
15macro_rules! api_call {
16 ($expr:expr_2021) => {{
17 let status = $expr;
18 if status != _NVENCSTATUS::NV_ENC_SUCCESS {
19 return Err(NvencError::ErrCode {
20 status,
21 fname: file!(),
22 line_num: line!(),
23 message: crate::error::code_to_string(status),
24 });
25 }
26 }};
27}
28
29macro_rules! load_func {
30 ($inner:expr_2021, $ident:ident) => {{
31 let func = if let Some(func) = $inner.$ident {
32 func
33 } else {
34 return Err(NvencError::NameFFIError {
35 name: stringify!($ident).to_string(),
36 });
37 };
38
39 Ok(func)
40 }};
41}
42
43macro_rules! get_func {
44 ($lib:expr_2021, $name:expr_2021) => {{
45 unsafe { $lib.library.get($name) }.map_err(|source| NvencError::NameFFIError2 {
46 name: String::from_utf8_lossy($name).to_string(),
47 source,
48 })
49 }};
52}
53
54pub fn init(library: &SharedLibrary) -> Result<Rc<LibNvEncode<'_>>, NvencError> {
55 let lib_nv_encode = LibNvEncode {
56 NvEncodeAPICreateInstance: get_func!(library, b"NvEncodeAPICreateInstance\0")?,
57 NvEncodeAPIGetMaxSupportedVersion: get_func!(
58 library,
59 b"NvEncodeAPIGetMaxSupportedVersion\0"
60 )?,
61 };
62
63 Ok(Rc::new(lib_nv_encode))
64}
65
66#[expect(non_snake_case)]
67pub struct LibNvEncode<'lib> {
68 NvEncodeAPICreateInstance:
69 libloading::Symbol<'lib, extern "C" fn(*mut NV_ENCODE_API_FUNCTION_LIST) -> NVENCSTATUS>,
70 NvEncodeAPIGetMaxSupportedVersion:
71 libloading::Symbol<'lib, extern "C" fn(*mut u32) -> NVENCSTATUS>,
72}
73
74impl<'lib> LibNvEncode<'lib> {
75 pub fn api_create_instance(
76 self_: Rc<Self>,
77 ) -> Result<NvEncodeApiFunctionList<'lib>, NvencError> {
78 let function_list = MaybeUninit::zeroed();
79 let mut function_list: NV_ENCODE_API_FUNCTION_LIST = unsafe { function_list.assume_init() };
80
81 function_list.version = NV_ENCODE_API_FUNCTION_LIST_VER;
82
83 api_call!((*self_.NvEncodeAPICreateInstance)(&mut function_list));
84 Ok(NvEncodeApiFunctionList {
85 inner: function_list,
86 _libnvencode: self_.clone(),
87 })
88 }
89 pub fn api_get_max_supported_version(&self) -> Result<ApiVersion, NvencError> {
90 let mut value = 0;
91 api_call!((*self.NvEncodeAPIGetMaxSupportedVersion)(&mut value));
92 Ok(ApiVersion {
93 major: value >> 4,
94 minor: value & 0xf,
95 })
96 }
97}
98
99#[derive(Debug)]
100pub struct ApiVersion {
101 pub major: u32,
102 pub minor: u32,
103}
104
105#[derive(Clone)]
107pub struct NvEncodeApiFunctionList<'lib> {
108 inner: NV_ENCODE_API_FUNCTION_LIST,
109 _libnvencode: Rc<LibNvEncode<'lib>>,
110}
111
112struct EncoderPtr(*mut std::ffi::c_void);
113
114impl<'lib> NvEncodeApiFunctionList<'lib> {
115 pub fn new_encoder(
116 &self,
117 mut ctx: dynlink_cuda::CudaContext,
118 ) -> Result<Rc<Encoder<'lib>>, NvencError> {
119 let func = load_func!(self.inner, nvEncOpenEncodeSessionEx)?;
120 let params = MaybeUninit::zeroed();
121 let mut params: NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS = unsafe { params.assume_init() };
122
123 params.version = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER;
124 params.apiVersion = NVENCAPI_VERSION;
125 params.deviceType = _NV_ENC_DEVICE_TYPE::NV_ENC_DEVICE_TYPE_CUDA;
126 params.device = ctx.as_mut_void_ptr();
127
128 let mut encoder: *mut std::ffi::c_void = std::ptr::null_mut();
129 api_call!(unsafe { func(&mut params, &mut encoder) });
130 Ok(Rc::new(Encoder {
131 parent: self.clone(),
132 inner: EncoderPtr(encoder),
133 destroyed: false,
134 }))
135 }
136}
137
138pub struct Encoder<'lib> {
140 parent: NvEncodeApiFunctionList<'lib>,
141 inner: EncoderPtr,
142 destroyed: bool,
143}
144
145impl<'lib> Encoder<'lib> {
146 pub fn get_encode_guid_count(&self) -> Result<u32, NvencError> {
147 let func = load_func!(self.parent.inner, nvEncGetEncodeGUIDCount)?;
148 let mut value = 0;
149 api_call!(unsafe { func(self.inner.0, &mut value) });
150 Ok(value)
151 }
152
153 pub fn get_encode_preset_config(
154 &self,
155 encode: GUID,
156 preset: GUID,
157 ) -> Result<EncodeConfig, NvencError> {
158 let func = load_func!(self.parent.inner, nvEncGetEncodePresetConfig)?;
159
160 let config = MaybeUninit::zeroed();
161 let mut config: NV_ENC_PRESET_CONFIG = unsafe { config.assume_init() };
162
163 config.presetCfg.version = NV_ENC_CONFIG_VER;
164 config.version = NV_ENC_PRESET_CONFIG_VER;
165
166 api_call!(unsafe { func(self.inner.0, encode, preset, &mut config) });
167 Ok(EncodeConfig {
168 config: config.presetCfg,
169 })
170 }
171
172 pub fn initialize(&self, init_params: &InitParams) -> Result<(), NvencError> {
174 let func = load_func!(self.parent.inner, nvEncInitializeEncoder)?;
177 let params = init_params.init_params;
180 let params = ¶ms as *const NV_ENC_INITIALIZE_PARAMS;
181 let params = params as *mut NV_ENC_INITIALIZE_PARAMS;
182
183 api_call!(unsafe { func(self.inner.0, params) });
184
185 Ok(())
186 }
187
188 pub fn alloc_input_buffer(
190 self_: &Rc<Self>,
191 width: u32,
192 height: u32,
193 format: BufferFormat,
194 ) -> Result<InputBuffer<'lib>, NvencError> {
195 let func = load_func!(self_.parent.inner, nvEncCreateInputBuffer)?;
196
197 let params = MaybeUninit::zeroed();
198 let mut params: NV_ENC_CREATE_INPUT_BUFFER = unsafe { params.assume_init() };
199
200 params.version = NV_ENC_CREATE_INPUT_BUFFER_VER;
201 params.width = width;
202 params.height = height;
203 params.bufferFmt = format as NvInt;
204
205 api_call!(unsafe { func(self_.inner.0, &mut params) });
206
207 Ok(InputBuffer {
208 encoder: self_.clone(),
209 ptr: params.inputBuffer,
210 format,
211 width,
212 height,
213 destroyed: false,
214 })
215 }
216
217 pub fn alloc_output_buffer(self_: &Rc<Self>) -> Result<OutputBuffer<'lib>, NvencError> {
218 let func = load_func!(self_.parent.inner, nvEncCreateBitstreamBuffer)?;
219
220 let params = MaybeUninit::zeroed();
221 let mut params: NV_ENC_CREATE_BITSTREAM_BUFFER = unsafe { params.assume_init() };
222
223 params.version = NV_ENC_CREATE_BITSTREAM_BUFFER_VER;
224 api_call!(unsafe { func(self_.inner.0, &mut params) });
225 Ok(OutputBuffer {
226 encoder: self_.clone(),
227 ptr: params.bitstreamBuffer,
228 destroyed: false,
229 })
230 }
231
232 pub fn encode_picture(
237 &self,
238 input: &InputBuffer,
239 output: &OutputBuffer,
240 pitch: usize,
241 pts: std::time::Duration,
242 ) -> Result<(), NvencError> {
243 let func = load_func!(self.parent.inner, nvEncEncodePicture)?;
244
245 let params = MaybeUninit::zeroed();
246 let mut params: NV_ENC_PIC_PARAMS = unsafe { params.assume_init() };
247
248 params.version = NV_ENC_PIC_PARAMS_VER;
249 params.inputTimeStamp = dur2raw(&pts);
250 params.inputBuffer = input.ptr;
251 params.bufferFmt = input.format as NvInt;
252 params.inputWidth = input.width;
253 params.inputHeight = input.height;
254 params.inputPitch = pitch as u32;
255 params.pictureStruct = _NV_ENC_PIC_STRUCT::NV_ENC_PIC_STRUCT_FRAME;
256 params.outputBitstream = output.ptr;
257
258 api_call!(unsafe { func(self.inner.0, &mut params) });
259 Ok(())
260 }
261
262 pub fn end_stream(&self) -> Result<(), NvencError> {
266 let func = load_func!(self.parent.inner, nvEncEncodePicture)?;
267
268 let params = MaybeUninit::zeroed();
269 let mut params: NV_ENC_PIC_PARAMS = unsafe { params.assume_init() };
270
271 params.version = NV_ENC_PIC_PARAMS_VER;
272 params.encodePicFlags = _NV_ENC_PIC_FLAGS::NV_ENC_PIC_FLAG_EOS;
273 api_call!(unsafe { func(self.inner.0, &mut params) });
274 Ok(())
275 }
276
277 pub fn get_sequence_parameter_sets(&self) -> Result<Vec<u8>, NvencError> {
278 let func = load_func!(self.parent.inner, nvEncGetSequenceParams)?;
279
280 let mut buf: Vec<u8> = vec![0; 256];
281 let mut new_len: u32 = 0;
282
283 let mut params = NV_ENC_SEQUENCE_PARAM_PAYLOAD {
284 version: NV_ENC_SEQUENCE_PARAM_PAYLOAD_VER,
285 inBufferSize: buf.len().try_into().unwrap(),
286 spsId: 0,
287 ppsId: 0,
288 spsppsBuffer: buf.as_mut_ptr() as *mut std::ffi::c_void,
289 outSPSPPSPayloadSize: &mut new_len,
290 reserved: [0; 250],
291 reserved2: [std::ptr::null_mut(); 64],
292 };
293
294 api_call!(unsafe { func(self.inner.0, &mut params) });
295
296 buf.truncate(new_len.try_into().unwrap());
297
298 Ok(buf)
299 }
300}
301
302const H264_RATE: u32 = 90_000;
303
304fn from_secs_f64(secs: f64) -> std::time::Duration {
306 let whole_secs = secs.floor() as u64;
307 let subsec_nanos = ((secs - whole_secs as f64) * 1e9).round() as u32;
308 std::time::Duration::new(whole_secs, subsec_nanos)
309}
310
311fn dur2raw(dur: &std::time::Duration) -> u64 {
312 (dur.as_secs_f64() * H264_RATE as f64).round() as u64
313}
314
315fn raw2dur(raw: u64) -> std::time::Duration {
316 from_secs_f64((raw as f64) / H264_RATE as f64)
317}
318
319#[test]
320fn test_timestamp_conversion() {
321 for expected in &[0, 1, 100, 100_000, 100_000_000] {
322 let dur = raw2dur(*expected);
323 let actual = dur2raw(&dur);
324 assert_eq!(*expected, actual);
325 }
326}
327
328impl Drop for Encoder<'_> {
329 fn drop(&mut self) {
330 if !self.destroyed {
331 let func = if let Some(func) = self.parent.inner.nvEncDestroyEncoder {
332 func
333 } else {
334 panic!("No function 'nvEncDestroyEncoder'");
335 };
336 let status = unsafe { func(self.inner.0) };
337 assert!(
338 status == _NVENCSTATUS::NV_ENC_SUCCESS,
339 "NV_ENC error code: {}",
340 status
341 );
342 self.destroyed = true;
343 }
344 }
345}
346
347pub struct InputBuffer<'lib> {
349 encoder: Rc<Encoder<'lib>>,
350 ptr: NV_ENC_INPUT_PTR,
351 format: BufferFormat,
352 width: u32,
353 height: u32,
354 destroyed: bool,
355}
356
357pub struct LockedInputBuffer<'lock, 'lib> {
361 inner: &'lock InputBuffer<'lib>,
362 mem: &'lock mut [u8],
363 pitch: usize,
364 dropped: bool,
365}
366
367impl<'lib> InputBuffer<'lib> {
368 pub fn lock<'lock>(&'lock self) -> Result<LockedInputBuffer<'lock, 'lib>, NvencError> {
369 let func = load_func!(self.encoder.parent.inner, nvEncLockInputBuffer)?;
370
371 let params = MaybeUninit::zeroed();
372 let mut params: NV_ENC_LOCK_INPUT_BUFFER = unsafe { params.assume_init() };
373
374 params.version = NV_ENC_LOCK_INPUT_BUFFER_VER;
375 params.inputBuffer = self.ptr;
376
377 api_call!(unsafe { func(self.encoder.inner.0, &mut params) });
378
379 let sz = self.format.calculate_size(params.pitch, self.height)?;
380
381 let mem = unsafe { std::slice::from_raw_parts_mut(params.bufferDataPtr as *mut u8, sz) };
382
383 Ok(LockedInputBuffer {
384 inner: self,
385 mem,
386 pitch: params.pitch as usize,
387 dropped: false,
388 })
389 }
390}
391
392impl Drop for LockedInputBuffer<'_, '_> {
393 fn drop(&mut self) {
394 if !self.dropped {
395 let func = if let Some(func) = self.inner.encoder.parent.inner.nvEncUnlockInputBuffer {
396 func
397 } else {
398 panic!("No function 'nvEncUnlockInputBuffer'");
399 };
400
401 let status = unsafe { func(self.inner.encoder.inner.0, self.inner.ptr) };
402
403 assert!(
404 status == _NVENCSTATUS::NV_ENC_SUCCESS,
405 "NV_ENC error code: {}",
406 status
407 );
408
409 self.dropped = true;
415 }
416 }
417}
418
419impl LockedInputBuffer<'_, '_> {
420 pub fn mem(&self) -> &[u8] {
421 self.mem
422 }
423 pub fn mem_mut(&mut self) -> &mut [u8] {
424 self.mem
425 }
426 pub fn pitch(&self) -> usize {
427 self.pitch
428 }
429}
430
431impl Drop for InputBuffer<'_> {
432 fn drop(&mut self) {
433 if !self.destroyed {
434 let func = if let Some(func) = self.encoder.parent.inner.nvEncDestroyInputBuffer {
435 func
436 } else {
437 panic!("No function 'nvEncDestroyInputBuffer'");
438 };
439
440 let status = unsafe { func(self.encoder.inner.0, self.ptr) };
441 assert!(
442 status == _NVENCSTATUS::NV_ENC_SUCCESS,
443 "NV_ENC error code: {}",
444 status
445 );
446
447 self.destroyed = true;
448 }
449 }
450}
451
452pub struct OutputBuffer<'lib> {
453 encoder: Rc<Encoder<'lib>>,
454 ptr: NV_ENC_OUTPUT_PTR,
455 destroyed: bool,
456}
457
458pub struct LockedOutputBuffer<'lock, 'lib> {
462 inner: &'lock OutputBuffer<'lib>,
463 mem: &'lock [u8],
464 picture_type: NvInt,
465 pts: std::time::Duration,
467 output_time_stamp: u64,
468 output_duration: u64,
469 dropped: bool,
470}
471
472impl Drop for OutputBuffer<'_> {
473 fn drop(&mut self) {
474 if !self.destroyed {
475 let func = if let Some(func) = self.encoder.parent.inner.nvEncDestroyBitstreamBuffer {
476 func
477 } else {
478 panic!("No function 'nvEncDestroyBitstreamBuffer'");
479 };
480
481 let status = unsafe { func(self.encoder.inner.0, self.ptr) };
482 assert!(
483 status == _NVENCSTATUS::NV_ENC_SUCCESS,
484 "NV_ENC error code: {}",
485 status
486 );
487
488 self.destroyed = true;
489 }
490 }
491}
492
493impl LockedOutputBuffer<'_, '_> {
494 pub fn mem(&self) -> &[u8] {
495 self.mem
496 }
497 pub fn pts(&self) -> &std::time::Duration {
498 &self.pts
499 }
500 pub fn output_time_stamp(&self) -> u64 {
501 self.output_time_stamp
502 }
503 pub fn output_duration(&self) -> u64 {
504 self.output_duration
505 }
506 pub fn is_keyframe(&self) -> bool {
507 use crate::ffi::_NV_ENC_PIC_TYPE::*;
508 matches!(self.picture_type, NV_ENC_PIC_TYPE_I | NV_ENC_PIC_TYPE_IDR)
509 }
510}
511
512impl Drop for LockedOutputBuffer<'_, '_> {
513 fn drop(&mut self) {
514 if !self.dropped {
515 let func = if let Some(func) = self.inner.encoder.parent.inner.nvEncUnlockBitstream {
516 func
517 } else {
518 panic!("No function 'nvEncUnlockBitstream'");
519 };
520
521 let status = unsafe { func(self.inner.encoder.inner.0, self.inner.ptr) };
522
523 assert!(
524 status == _NVENCSTATUS::NV_ENC_SUCCESS,
525 "NV_ENC error code: {}",
526 status
527 );
528
529 self.dropped = true;
535 }
536 }
537}
538
539impl<'lib> OutputBuffer<'lib> {
540 pub fn lock<'lock>(&'lock self) -> Result<LockedOutputBuffer<'lock, 'lib>, NvencError> {
541 let func = load_func!(self.encoder.parent.inner, nvEncLockBitstream)?;
542
543 let params = MaybeUninit::zeroed();
544 let mut params: NV_ENC_LOCK_BITSTREAM = unsafe { params.assume_init() };
545
546 params.version = NV_ENC_LOCK_BITSTREAM_VER;
547 params.outputBitstream = self.ptr;
548
549 api_call!(unsafe { func(self.encoder.inner.0, &mut params) });
550
551 let output_time_stamp = params.outputTimeStamp;
552 let output_duration = params.outputDuration;
553 let pts = raw2dur(output_time_stamp);
554 let picture_type = params.pictureType;
555
556 let mem = unsafe {
557 std::slice::from_raw_parts(
558 params.bitstreamBufferPtr as *mut u8,
559 params.bitstreamSizeInBytes as usize,
560 )
561 };
562
563 Ok(LockedOutputBuffer {
564 inner: self,
565 mem,
566 pts,
567 output_time_stamp,
568 output_duration,
569 picture_type,
570 dropped: false,
571 })
572 }
573}
574
575#[repr(u32)]
577#[derive(Copy, Clone, Debug)]
578pub enum BufferFormat {
579 Undefined = _NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_UNDEFINED,
580 NV12 = _NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_NV12,
581 YV12 = _NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_YV12,
582 IYUV = _NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_IYUV,
583 YUV444 = _NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_YUV444,
584 YUV444_10Bit = _NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_YUV444_10BIT,
585 YUV420_10Bit = _NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_YUV420_10BIT,
586 ARGB = _NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_ARGB,
587 ARGB10 = _NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_ARGB10,
588 ABGR = _NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_ABGR,
589 AYUV = _NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_AYUV,
590 ABGR10 = _NV_ENC_BUFFER_FORMAT::NV_ENC_BUFFER_FORMAT_ABGR10,
591 }
593
594impl BufferFormat {
595 fn calculate_size(&self, stride: u32, height: u32) -> Result<usize, NvencError> {
596 match self {
597 &BufferFormat::NV12 | &BufferFormat::YV12 | &BufferFormat::IYUV => {
598 Ok((stride as usize) * (height as usize) * 3 / 2)
599 }
600 &BufferFormat::ARGB => Ok((stride as usize) * (height as usize) * 4),
601 _ => Err(NvencError::UnableToComputeSize {}),
602 }
603 }
604}
605
606pub struct InitParams {
608 init_params: NV_ENC_INITIALIZE_PARAMS,
609 encode_config: EncodeConfig,
610}
611
612impl Debug for InitParams {
613 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
614 let p = &self.init_params;
615 write!(
616 f,
617 "InitParams{{version: {}, encodeGUID: {}, encodeWidth: {}, encodeHeight: {}, darWidth: {}, darHeight: {}, enablePTD: {}, presetGUID: {}, encodeConfig: {:?}, frameRateNum: {}, frameRateDen: {}, maxEncodeWidth: {}, maxEncodeHeight: {} }}",
618 p.version,
619 guid_string(&p.encodeGUID),
620 p.encodeWidth,
621 p.encodeHeight,
622 p.darWidth,
623 p.darHeight,
624 p.enablePTD,
625 guid_string(&p.presetGUID),
626 self.encode_config,
627 p.frameRateNum,
628 p.frameRateDen,
629 p.maxEncodeWidth,
630 p.maxEncodeHeight,
631 )
632 }
633}
634
635fn guid_string(guid: &GUID) -> String {
636 format!(
637 "{{ 0x{:x}, 0x{:x}, 0x{:x}, {} }}",
638 guid.Data1,
639 guid.Data2,
640 guid.Data3,
641 arr_string(&guid.Data4)
642 )
643}
644
645fn arr_string(arr: &[u8; 8]) -> String {
646 format!(
647 "{{ 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x} }}",
648 arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6], arr[7]
649 )
650}
651
652pub struct InitParamsBuilder {
653 init_params: std::mem::MaybeUninit<NV_ENC_INITIALIZE_PARAMS>,
654 encode_config: Option<EncodeConfig>,
655}
656
657impl InitParamsBuilder {
658 pub fn new(encode: GUID, width: u32, height: u32) -> Self {
659 let mut uninit = std::mem::MaybeUninit::<NV_ENC_INITIALIZE_PARAMS>::zeroed();
660
661 let ptr = uninit.as_mut_ptr();
662
663 unsafe {
664 addr_of_mut!((*ptr).version).write(NV_ENC_INITIALIZE_PARAMS_VER);
665 addr_of_mut!((*ptr).encodeGUID).write(encode);
666 addr_of_mut!((*ptr).encodeWidth).write(width);
667 addr_of_mut!((*ptr).encodeHeight).write(height);
668 addr_of_mut!((*ptr).darWidth).write(width);
669 addr_of_mut!((*ptr).darHeight).write(height);
670 addr_of_mut!((*ptr).enablePTD).write(1);
671 addr_of_mut!((*ptr).maxEncodeWidth).write(width);
672 addr_of_mut!((*ptr).maxEncodeHeight).write(height);
673 }
674 Self {
675 init_params: uninit,
676 encode_config: None,
677 }
678 }
679
680 pub fn dar_width(mut self, width: u32) -> Self {
682 let ptr = self.init_params.as_mut_ptr();
683 unsafe {
684 addr_of_mut!((*ptr).darWidth).write(width);
685 }
686 self
687 }
688
689 pub fn dar_height(mut self, height: u32) -> Self {
691 let ptr = self.init_params.as_mut_ptr();
692 unsafe {
693 addr_of_mut!((*ptr).darHeight).write(height);
694 }
695 self
696 }
697
698 pub fn preset_guid(mut self, preset: GUID) -> Self {
699 let ptr = self.init_params.as_mut_ptr();
700 unsafe {
701 addr_of_mut!((*ptr).presetGUID).write(preset);
702 }
703 self
704 }
705
706 pub fn set_encode_config(mut self, config: EncodeConfig) -> Self {
707 self.encode_config = Some(config);
708 self
710 }
711
712 pub fn set_framerate(mut self, num: u32, den: u32) -> Self {
717 let ptr = self.init_params.as_mut_ptr();
718 unsafe {
719 addr_of_mut!((*ptr).frameRateNum).write(num);
720 addr_of_mut!((*ptr).frameRateDen).write(den);
721 }
722 self
723 }
724
725 pub fn build(self) -> Result<Pin<Box<InitParams>>, NvencError> {
726 let encode_config = match self.encode_config {
727 Some(c) => c,
728 None => {
729 return Err(NvencError::EncodeConfigRequired {});
730 }
731 };
732 let params = InitParams {
733 init_params: unsafe { self.init_params.assume_init() },
734 encode_config,
735 };
736 let mut boxed = Box::pin(params);
737
738 let ptr: *mut NV_ENC_CONFIG = &mut boxed.encode_config.config;
739 unsafe {
741 let mut_ref: Pin<&mut InitParams> = Pin::as_mut(&mut boxed);
742 Pin::get_unchecked_mut(mut_ref).init_params.encodeConfig = ptr;
743 }
744 Ok(boxed)
745 }
746}
747
748pub struct EncodeConfig {
750 config: NV_ENC_CONFIG,
751}
752
753impl Debug for EncodeConfig {
754 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
755 write!(
756 f,
757 "{{rcParams.rateControlMode: {}, rcParams.averageBitRate: {}, rcParams.maxBitRate: {} }}",
758 self.config.rcParams.rateControlMode,
759 self.config.rcParams.averageBitRate,
760 self.config.rcParams.maxBitRate,
761 )
762 }
763}
764
765impl EncodeConfig {
766 pub fn set_rate_control_mode(&mut self, mode: RateControlMode) {
767 self.config.rcParams.rateControlMode = mode.to_c();
768 }
769 pub fn set_average_bit_rate(&mut self, value: u32) {
770 self.config.rcParams.averageBitRate = value;
771 }
772 pub fn set_max_bit_rate(&mut self, value: u32) {
773 self.config.rcParams.maxBitRate = value;
774 }
775}
776
777#[derive(Clone, Copy, Debug)]
778pub enum RateControlMode {
779 Constqp,
781 Vbr,
783 Cbr,
785 LowdelayHq,
787 CbrHq,
789 VbrHq,
791}
792
793impl RateControlMode {
794 fn to_c(self) -> NvInt {
795 use RateControlMode::*;
796 match self {
797 Constqp => _NV_ENC_PARAMS_RC_MODE::NV_ENC_PARAMS_RC_CONSTQP,
798 Vbr => _NV_ENC_PARAMS_RC_MODE::NV_ENC_PARAMS_RC_VBR,
799 Cbr => _NV_ENC_PARAMS_RC_MODE::NV_ENC_PARAMS_RC_CBR,
800 LowdelayHq => _NV_ENC_PARAMS_RC_MODE::NV_ENC_PARAMS_RC_CBR_LOWDELAY_HQ,
801 CbrHq => _NV_ENC_PARAMS_RC_MODE::NV_ENC_PARAMS_RC_CBR_HQ,
802 VbrHq => _NV_ENC_PARAMS_RC_MODE::NV_ENC_PARAMS_RC_VBR_HQ,
803 }
804 }
805}