Skip to main content

rave_nvcodec/
sys.rs

1//! Raw FFI bindings to NVIDIA Video Codec SDK (nvcuvid + nvEncodeAPI).
2//!
3//! Covers the minimal subset required by [`NvDecoder`](super::nvdec) and
4//! [`NvEncoder`](super::nvenc).  Matches Video Codec SDK v12.x headers.
5//!
6//! # Linking
7//!
8//! `build.rs` emits `-l nvcuvid` and `-l nvencodeapi` (Windows: `nvEncodeAPI64`).
9//! Libraries are located via `CUDA_PATH` env var.
10//!
11//! # Safety
12//!
13//! All functions in this module are `unsafe extern "C"`.  The safe wrappers
14//! in `nvdec.rs` and `nvenc.rs` enforce invariants documented below.
15
16#![allow(non_camel_case_types, non_snake_case, dead_code, missing_docs)]
17
18use std::ffi::c_void;
19use std::os::raw::{c_int, c_short, c_uint, c_ulong, c_ulonglong};
20
21// ═══════════════════════════════════════════════════════════════════════════
22//  COMMON TYPES
23// ═══════════════════════════════════════════════════════════════════════════
24
25/// CUDA result code.
26pub type CUresult = c_int;
27pub const CUDA_SUCCESS: CUresult = 0;
28
29/// CUDA device pointer (64-bit).
30pub type CUdeviceptr = c_ulonglong;
31
32/// CUDA stream handle.
33pub type CUstream = *mut c_void;
34
35/// CUDA context handle.
36pub type CUcontext = *mut c_void;
37
38// ═══════════════════════════════════════════════════════════════════════════
39//  NVDEC — cuviddec.h / nvcuvid.h
40// ═══════════════════════════════════════════════════════════════════════════
41
42/// Opaque decoder handle.
43pub type CUvideodecoder = *mut c_void;
44
45/// Opaque parser handle.
46pub type CUvideoparser = *mut c_void;
47
48// ─── Enums ───────────────────────────────────────────────────────────────
49
50#[repr(C)]
51#[derive(Clone, Copy, Debug, PartialEq, Eq)]
52pub enum cudaVideoCodec {
53    MPEG1 = 0,
54    MPEG2 = 1,
55    MPEG4 = 2,
56    VC1 = 3,
57    H264 = 4,
58    JPEG = 5,
59    H264_SVC = 6,
60    H264_MVC = 7,
61    HEVC = 8,
62    VP8 = 9,
63    VP9 = 10,
64    AV1 = 11,
65    NumCodecs = 12,
66}
67
68#[repr(C)]
69#[derive(Clone, Copy, Debug, PartialEq, Eq)]
70pub enum cudaVideoSurfaceFormat {
71    NV12 = 0,
72    P016 = 1,
73    YUV444 = 2,
74    YUV444_16Bit = 3,
75}
76
77#[repr(C)]
78#[derive(Clone, Copy, Debug, PartialEq, Eq)]
79pub enum cudaVideoChromaFormat {
80    Monochrome = 0,
81    _420 = 1,
82    _422 = 2,
83    _444 = 3,
84}
85
86#[repr(C)]
87#[derive(Clone, Copy, Debug, PartialEq, Eq)]
88pub enum cudaVideoDeinterlaceMode {
89    Weave = 0,
90    Bob = 1,
91    Adaptive = 2,
92}
93
94#[repr(C)]
95#[derive(Clone, Copy, Debug, PartialEq, Eq)]
96pub enum cudaVideoCreateFlags {
97    /// Default (no flags).
98    PreferCUVID = 0,
99    /// Use dedicated hardware decoder (NVDEC).
100    PreferDXVA = 1,
101    /// Use CUDA-based decoder.
102    PreferCUDA = 2,
103}
104
105// ─── Decoder creation params ─────────────────────────────────────────────
106
107/// Cropping rectangle for decode output.
108#[repr(C)]
109#[derive(Clone, Copy, Debug, Default)]
110pub struct CUVIDDECODECREATEINFO_display_area {
111    pub left: c_short,
112    pub top: c_short,
113    pub right: c_short,
114    pub bottom: c_short,
115}
116
117/// Target output rectangle (scaling).
118#[repr(C)]
119#[derive(Clone, Copy, Debug, Default)]
120pub struct CUVIDDECODECREATEINFO_target_rect {
121    pub left: c_short,
122    pub top: c_short,
123    pub right: c_short,
124    pub bottom: c_short,
125}
126
127/// Parameters for `cuvidCreateDecoder`.
128#[repr(C)]
129#[derive(Clone, Copy, Debug)]
130pub struct CUVIDDECODECREATEINFO {
131    pub ulWidth: c_ulong,
132    pub ulHeight: c_ulong,
133    pub ulNumDecodeSurfaces: c_ulong,
134    pub CodecType: cudaVideoCodec,
135    pub ChromaFormat: cudaVideoChromaFormat,
136    pub ulCreationFlags: c_ulong,
137    pub bitDepthMinus8: c_ulong,
138    pub ulIntraDecodeOnly: c_ulong,
139    pub ulMaxWidth: c_ulong,
140    pub ulMaxHeight: c_ulong,
141    pub Reserved1: c_ulong,
142    pub display_area: CUVIDDECODECREATEINFO_display_area,
143    pub OutputFormat: cudaVideoSurfaceFormat,
144    pub DeinterlaceMode: cudaVideoDeinterlaceMode,
145    pub ulTargetWidth: c_ulong,
146    pub ulTargetHeight: c_ulong,
147    pub ulNumOutputSurfaces: c_ulong,
148    pub vidLock: *mut c_void,
149    pub target_rect: CUVIDDECODECREATEINFO_target_rect,
150    pub enableHistogram: c_ulong,
151    pub Reserved2: [c_ulong; 4],
152}
153
154// ─── Picture params (decode a single frame) ──────────────────────────────
155
156/// Simplified picture params — full struct is codec-union, we use opaque bytes.
157#[repr(C)]
158#[derive(Clone, Copy)]
159pub struct CUVIDPICPARAMS {
160    pub PicWidthInMbs: c_int,
161    pub FrameHeightInMbs: c_int,
162    pub CurrPicIdx: c_int,
163    pub field_pic_flag: c_int,
164    pub bottom_field_flag: c_int,
165    pub second_field: c_int,
166    pub nBitstreamDataLen: c_uint,
167    pub pBitstreamData: *const u8,
168    pub nNumSlices: c_uint,
169    pub pSliceDataOffsets: *const c_uint,
170    pub ref_pic_flag: c_int,
171    pub intra_pic_flag: c_int,
172    pub Reserved: [c_uint; 30],
173    /// Codec-specific packed data (H.264/HEVC/VP9/AV1 union).
174    pub CodecSpecific: [u8; 1024],
175}
176
177// ─── Parser callback types ───────────────────────────────────────────────
178
179/// Video format information emitted by the parser.
180#[repr(C)]
181#[derive(Clone, Copy, Debug)]
182pub struct CUVIDEOFORMAT {
183    pub codec: cudaVideoCodec,
184    pub frame_rate_num: c_uint,
185    pub frame_rate_den: c_uint,
186    pub progressive_sequence: u8,
187    pub bit_depth_luma_minus8: u8,
188    pub bit_depth_chroma_minus8: u8,
189    pub min_num_decode_surfaces: u8,
190    pub coded_width: c_uint,
191    pub coded_height: c_uint,
192    pub display_area_left: c_short,
193    pub display_area_top: c_short,
194    pub display_area_right: c_short,
195    pub display_area_bottom: c_short,
196    pub chroma_format: cudaVideoChromaFormat,
197    pub bitrate: c_uint,
198    pub display_aspect_ratio_x: c_uint,
199    pub display_aspect_ratio_y: c_uint,
200    pub video_signal_description: [u8; 8],
201    pub seqhdr_data_length: c_uint,
202}
203
204/// Parser dispatch info for a decoded picture.
205#[repr(C)]
206#[derive(Clone, Copy, Debug)]
207pub struct CUVIDPARSERDISPINFO {
208    pub picture_index: c_int,
209    pub progressive_frame: c_int,
210    pub top_field_first: c_int,
211    pub repeat_first_field: c_int,
212    pub timestamp: c_ulonglong,
213}
214
215/// Callback: sequence header parsed (reports format).
216pub type PFNVIDSEQUENCECALLBACK =
217    unsafe extern "C" fn(user_data: *mut c_void, format: *mut CUVIDEOFORMAT) -> c_int;
218
219/// Callback: a picture has been decoded.
220pub type PFNVIDDECODECALLBACK =
221    unsafe extern "C" fn(user_data: *mut c_void, pic_params: *mut CUVIDPICPARAMS) -> c_int;
222
223/// Callback: a decoded picture is ready for display.
224pub type PFNVIDDISPLAYCALLBACK =
225    unsafe extern "C" fn(user_data: *mut c_void, disp_info: *mut CUVIDPARSERDISPINFO) -> c_int;
226
227/// Parser creation params.
228#[repr(C)]
229pub struct CUVIDPARSERPARAMS {
230    pub CodecType: cudaVideoCodec,
231    pub ulMaxNumDecodeSurfaces: c_uint,
232    pub ulClockRate: c_uint,
233    pub ulErrorThreshold: c_uint,
234    pub ulMaxDisplayDelay: c_uint,
235    pub bAnnexb: c_uint,
236    pub uReserved: c_uint,
237    pub Reserved: [c_uint; 4],
238    pub pUserData: *mut c_void,
239    pub pfnSequenceCallback: Option<PFNVIDSEQUENCECALLBACK>,
240    pub pfnDecodePicture: Option<PFNVIDDECODECALLBACK>,
241    pub pfnDisplayPicture: Option<PFNVIDDISPLAYCALLBACK>,
242    pub pvReserved2: [*mut c_void; 7],
243    pub pExtVideoInfo: *mut c_void,
244}
245
246/// Bitstream packet fed to the parser.
247#[repr(C)]
248pub struct CUVIDSOURCEDATAPACKET {
249    pub flags: c_ulong,
250    pub payload_size: c_ulong,
251    pub payload: *const u8,
252    pub timestamp: c_ulonglong,
253}
254
255/// Parser input flags.
256pub const CUVID_PKT_ENDOFSTREAM: c_ulong = 0x01;
257pub const CUVID_PKT_TIMESTAMP: c_ulong = 0x02;
258pub const CUVID_PKT_DISCONTINUITY: c_ulong = 0x04;
259
260/// Processing params for `cuvidMapVideoFrame64`.
261#[repr(C)]
262#[derive(Clone, Copy, Debug)]
263pub struct CUVIDPROCPARAMS {
264    pub progressive_frame: c_int,
265    pub second_field: c_int,
266    pub top_field_first: c_int,
267    pub unpaired_field: c_int,
268    pub reserved_flags: c_uint,
269    pub reserved_zero: c_uint,
270    pub raw_input_dptr: c_ulonglong,
271    pub raw_input_pitch: c_uint,
272    pub raw_input_format: c_uint,
273    pub raw_output_dptr: c_ulonglong,
274    pub raw_output_pitch: c_uint,
275    pub Reserved1: c_uint,
276    pub output_stream: CUstream,
277    pub Reserved: [c_uint; 46],
278}
279
280// ─── NVDEC functions ─────────────────────────────────────────────────────
281
282unsafe extern "C" {
283    pub fn cuvidCreateVideoParser(
284        parser: *mut CUvideoparser,
285        params: *mut CUVIDPARSERPARAMS,
286    ) -> CUresult;
287
288    pub fn cuvidParseVideoData(
289        parser: CUvideoparser,
290        packet: *mut CUVIDSOURCEDATAPACKET,
291    ) -> CUresult;
292
293    pub fn cuvidDestroyVideoParser(parser: CUvideoparser) -> CUresult;
294
295    pub fn cuvidCreateDecoder(
296        decoder: *mut CUvideodecoder,
297        params: *mut CUVIDDECODECREATEINFO,
298    ) -> CUresult;
299
300    pub fn cuvidDecodePicture(decoder: CUvideodecoder, pic_params: *mut CUVIDPICPARAMS)
301    -> CUresult;
302
303    pub fn cuvidMapVideoFrame64(
304        decoder: CUvideodecoder,
305        pic_idx: c_int,
306        dev_ptr: *mut CUdeviceptr,
307        pitch: *mut c_uint,
308        params: *mut CUVIDPROCPARAMS,
309    ) -> CUresult;
310
311    pub fn cuvidUnmapVideoFrame64(decoder: CUvideodecoder, dev_ptr: CUdeviceptr) -> CUresult;
312
313    pub fn cuvidDestroyDecoder(decoder: CUvideodecoder) -> CUresult;
314}
315
316// ═══════════════════════════════════════════════════════════════════════════
317//  NVENC — nvEncodeAPI.h
318// ═══════════════════════════════════════════════════════════════════════════
319
320/// NVENC status code.
321pub type NVENCSTATUS = c_int;
322pub const NV_ENC_SUCCESS: NVENCSTATUS = 0;
323pub const NV_ENC_ERR_NO_ENCODE_DEVICE: NVENCSTATUS = 1;
324pub const NV_ENC_ERR_UNSUPPORTED_DEVICE: NVENCSTATUS = 2;
325pub const NV_ENC_ERR_INVALID_ENCODERDEVICE: NVENCSTATUS = 3;
326pub const NV_ENC_ERR_INVALID_DEVICE: NVENCSTATUS = 4;
327pub const NV_ENC_ERR_DEVICE_NOT_EXIST: NVENCSTATUS = 5;
328pub const NV_ENC_ERR_INVALID_PTR: NVENCSTATUS = 6;
329pub const NV_ENC_ERR_INVALID_EVENT: NVENCSTATUS = 7;
330pub const NV_ENC_ERR_INVALID_PARAM: NVENCSTATUS = 8;
331pub const NV_ENC_ERR_INVALID_CALL: NVENCSTATUS = 9;
332pub const NV_ENC_ERR_OUT_OF_MEMORY: NVENCSTATUS = 10;
333pub const NV_ENC_ERR_ENCODER_NOT_INITIALIZED: NVENCSTATUS = 11;
334pub const NV_ENC_ERR_UNSUPPORTED_PARAM: NVENCSTATUS = 12;
335pub const NV_ENC_ERR_LOCK_BUSY: NVENCSTATUS = 13;
336pub const NV_ENC_ERR_NOT_ENOUGH_BUFFER: NVENCSTATUS = 14;
337pub const NV_ENC_ERR_INVALID_VERSION: NVENCSTATUS = 15;
338pub const NV_ENC_ERR_MAP_FAILED: NVENCSTATUS = 16;
339pub const NV_ENC_ERR_NEED_MORE_INPUT: NVENCSTATUS = 17;
340pub const NV_ENC_ERR_ENCODER_BUSY: NVENCSTATUS = 18;
341pub const NV_ENC_ERR_EVENT_NOT_REGISTERD: NVENCSTATUS = 19;
342pub const NV_ENC_ERR_GENERIC: NVENCSTATUS = 20;
343
344/// GUID type mirroring Windows GUID layout.
345#[repr(C)]
346#[derive(Clone, Copy, Debug, PartialEq, Eq)]
347pub struct GUID {
348    pub Data1: u32,
349    pub Data2: u16,
350    pub Data3: u16,
351    pub Data4: [u8; 8],
352}
353
354// ─── Well-known GUIDs ────────────────────────────────────────────────────
355
356/// H.264 encode GUID.
357pub const NV_ENC_CODEC_H264_GUID: GUID = GUID {
358    Data1: 0x6BC82762,
359    Data2: 0x4E63,
360    Data3: 0x4CA4,
361    Data4: [0xAA, 0x85, 0x1A, 0x4F, 0x6A, 0x21, 0xF5, 0x07],
362};
363
364/// H.265/HEVC encode GUID.
365pub const NV_ENC_CODEC_HEVC_GUID: GUID = GUID {
366    Data1: 0x790CDC88,
367    Data2: 0x4522,
368    Data3: 0x4D7B,
369    Data4: [0x94, 0x25, 0xBD, 0xA9, 0x97, 0x5F, 0x76, 0x03],
370};
371
372/// Low-latency high-quality preset GUID (P7).
373pub const NV_ENC_PRESET_P7_GUID: GUID = GUID {
374    Data1: 0x84848C12,
375    Data2: 0x6F71,
376    Data3: 0x4C13,
377    Data4: [0x93, 0x1B, 0x53, 0xE5, 0x6F, 0x78, 0x84, 0x3B],
378};
379
380/// Balanced quality/performance preset GUID (P4).
381pub const NV_ENC_PRESET_P4_GUID: GUID = GUID {
382    Data1: 0x90A7B826,
383    Data2: 0xDF06,
384    Data3: 0x4862,
385    Data4: [0xB9, 0xD2, 0xCD, 0x6D, 0x73, 0xA0, 0x86, 0x81],
386};
387
388/// H.265 Main profile GUID.
389pub const NV_ENC_HEVC_PROFILE_MAIN_GUID: GUID = GUID {
390    Data1: 0xB514C39A,
391    Data2: 0xB55B,
392    Data3: 0x40FA,
393    Data4: [0x87, 0x87, 0x67, 0xED, 0x5E, 0x28, 0x49, 0x4D],
394};
395
396/// H.265 Main10 profile GUID.
397pub const NV_ENC_HEVC_PROFILE_MAIN10_GUID: GUID = GUID {
398    Data1: 0xFA4D2B6C,
399    Data2: 0x3A5B,
400    Data3: 0x411A,
401    Data4: [0x80, 0x18, 0x0A, 0x3F, 0x5E, 0x3C, 0x9B, 0x44],
402};
403
404// ─── NVENC enums ─────────────────────────────────────────────────────────
405
406#[repr(u32)]
407#[derive(Clone, Copy, Debug, PartialEq, Eq)]
408pub enum NV_ENC_DEVICE_TYPE {
409    DIRECTX = 0,
410    CUDA = 1,
411    OPENGL = 2,
412}
413
414#[repr(u32)]
415#[derive(Clone, Copy, Debug, PartialEq, Eq)]
416pub enum NV_ENC_INPUT_RESOURCE_TYPE {
417    DIRECTX = 0,
418    CUDADEVICEPTR = 1,
419    CUDAARRAY = 2,
420    OPENGL_TEX = 3,
421}
422
423#[repr(u32)]
424#[derive(Clone, Copy, Debug, PartialEq, Eq)]
425pub enum NV_ENC_BUFFER_FORMAT {
426    UNDEFINED = 0x00000000,
427    NV12 = 0x00000001,
428    YV12 = 0x00000010,
429    IYUV = 0x00000100,
430    YUV444 = 0x00001000,
431    YUV420_10BIT = 0x00010000,
432    ARGB = 0x01000000,
433    ABGR = 0x02000000,
434}
435
436#[repr(u32)]
437#[derive(Clone, Copy, Debug, PartialEq, Eq)]
438pub enum NV_ENC_PIC_TYPE {
439    P = 0,
440    B = 1,
441    I = 2,
442    IDR = 3,
443    BI = 4,
444    SKIPPED = 5,
445}
446
447#[repr(u32)]
448#[derive(Clone, Copy, Debug, PartialEq, Eq)]
449pub enum NV_ENC_PIC_STRUCT {
450    FRAME = 0x01,
451    FIELD_TOP_BOTTOM = 0x02,
452    FIELD_BOTTOM_TOP = 0x03,
453}
454
455#[repr(u32)]
456#[derive(Clone, Copy, Debug, PartialEq, Eq)]
457pub enum NV_ENC_TUNING_INFO {
458    UNDEFINED = 0,
459    HIGH_QUALITY = 1,
460    LOW_LATENCY = 2,
461    ULTRA_LOW_LATENCY = 3,
462    LOSSLESS = 4,
463}
464
465// ─── NVENC params structs ────────────────────────────────────────────────
466
467/// Matches `NVENCAPI_MAJOR_VERSION` in `nvEncodeAPI.h`.
468pub const NVENCAPI_MAJOR_VERSION: u32 = 13;
469/// Matches `NVENCAPI_MINOR_VERSION` in `nvEncodeAPI.h`.
470pub const NVENCAPI_MINOR_VERSION: u32 = 0;
471/// Matches `NVENCAPI_VERSION` in `nvEncodeAPI.h`.
472pub const NVENCAPI_VERSION: u32 = NVENCAPI_MAJOR_VERSION | (NVENCAPI_MINOR_VERSION << 24);
473
474/// Matches `NVENCAPI_STRUCT_VERSION(ver)` in `nvEncodeAPI.h`.
475#[inline]
476pub const fn nvenc_struct_version(struct_ver: u32) -> u32 {
477    NVENCAPI_VERSION | (struct_ver << 16) | (0x7 << 28)
478}
479
480pub const NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER: u32 = nvenc_struct_version(1);
481pub const NV_ENCODE_API_FUNCTION_LIST_VER: u32 = nvenc_struct_version(2);
482
483/// Session open params.
484#[repr(C)]
485pub struct NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS {
486    pub version: u32,
487    pub deviceType: NV_ENC_DEVICE_TYPE,
488    pub device: *mut c_void,
489    pub reserved: *mut c_void,
490    pub apiVersion: u32,
491    pub reserved1: [u32; 253],
492    pub reserved2: [*mut c_void; 64],
493}
494
495/// Rate control params (simplified).
496#[repr(C)]
497#[derive(Clone, Copy)]
498pub struct NV_ENC_RC_PARAMS {
499    pub version: u32,
500    pub rateControlMode: u32,
501    pub constQP_interP: u32,
502    pub constQP_interB: u32,
503    pub constQP_intra: u32,
504    pub averageBitRate: u32,
505    pub maxBitRate: u32,
506    pub vbvBufferSize: u32,
507    pub vbvInitialDelay: u32,
508    pub reserved: [u32; 247],
509}
510
511/// HEVC-specific config (simplified).
512#[repr(C)]
513#[derive(Clone, Copy)]
514pub struct NV_ENC_CONFIG_HEVC {
515    pub level: u32,
516    pub tier: u32,
517    pub minCUSize: u32,
518    pub maxCUSize: u32,
519    pub reserved: [u32; 252],
520}
521
522/// Codec-specific config union (simplified — only HEVC used).
523#[repr(C)]
524#[derive(Clone, Copy)]
525pub union NV_ENC_CODEC_CONFIG {
526    pub hevcConfig: NV_ENC_CONFIG_HEVC,
527    pub reserved: [u32; 256],
528}
529
530/// Encoder configuration.
531#[repr(C)]
532#[derive(Clone, Copy)]
533pub struct NV_ENC_CONFIG {
534    pub version: u32,
535    pub profileGUID: GUID,
536    pub gopLength: u32,
537    pub frameIntervalP: i32,
538    pub monoChromeEncoding: u32,
539    pub frameFieldMode: u32,
540    pub mvPrecision: u32,
541    pub rcParams: NV_ENC_RC_PARAMS,
542    pub encodeCodecConfig: NV_ENC_CODEC_CONFIG,
543    pub reserved: [u32; 278],
544    pub reserved2: [*mut c_void; 64],
545}
546
547/// Encoder initialization params.
548#[repr(C)]
549pub struct NV_ENC_INITIALIZE_PARAMS {
550    pub version: u32,
551    pub encodeGUID: GUID,
552    pub presetGUID: GUID,
553    pub encodeWidth: u32,
554    pub encodeHeight: u32,
555    pub darWidth: u32,
556    pub darHeight: u32,
557    pub frameRateNum: u32,
558    pub frameRateDen: u32,
559    pub enableEncodeAsync: u32,
560    pub enablePTD: u32,
561    pub reportSliceOffsets: u32,
562    pub enableSubFrameWrite: u32,
563    pub enableExternalMEHints: u32,
564    pub enableMEOnlyMode: u32,
565    pub enableWeightedPrediction: u32,
566    pub enableOutputInVidmem: u32,
567    pub reserved1: u32,
568    pub privDataSize: u32,
569    pub privData: *mut c_void,
570    pub encodeConfig: *mut NV_ENC_CONFIG,
571    pub maxEncodeWidth: u32,
572    pub maxEncodeHeight: u32,
573    pub maxMEHintCountsPerBlock: [u32; 2],
574    pub tuningInfo: NV_ENC_TUNING_INFO,
575    pub reserved: [u32; 289],
576    pub reserved2: [*mut c_void; 64],
577}
578
579/// Register external resource.
580#[repr(C)]
581pub struct NV_ENC_REGISTER_RESOURCE {
582    pub version: u32,
583    pub resourceType: NV_ENC_INPUT_RESOURCE_TYPE,
584    pub width: u32,
585    pub height: u32,
586    pub pitch: u32,
587    pub subResourceIndex: u32,
588    pub resourceToRegister: *mut c_void,
589    pub registeredResource: *mut c_void,
590    pub bufferFormat: NV_ENC_BUFFER_FORMAT,
591    pub bufferUsage: u32,
592    pub pInputFencePoint: *mut c_void,
593    pub pOutputFencePoint: *mut c_void,
594    pub reserved: [u32; 247],
595    pub reserved2: [*mut c_void; 62],
596}
597
598/// Map input resource.
599#[repr(C)]
600pub struct NV_ENC_MAP_INPUT_RESOURCE {
601    pub version: u32,
602    pub subResourceIndex: u32,
603    pub inputResource: *mut c_void,
604    pub registeredResource: *mut c_void,
605    pub mappedResource: *mut c_void,
606    pub mappedBufferFmt: NV_ENC_BUFFER_FORMAT,
607    pub reserved: [u32; 251],
608    pub reserved2: [*mut c_void; 63],
609}
610
611/// Create bitstream buffer.
612#[repr(C)]
613pub struct NV_ENC_CREATE_BITSTREAM_BUFFER {
614    pub version: u32,
615    pub bitstreamBuffer: *mut c_void,
616    pub size: u32,
617    pub memoryHeap: u32,
618    pub reserved: [u32; 252],
619    pub reserved2: [*mut c_void; 64],
620}
621
622/// Encode picture params.
623#[repr(C)]
624pub struct NV_ENC_PIC_PARAMS {
625    pub version: u32,
626    pub inputWidth: u32,
627    pub inputHeight: u32,
628    pub inputPitch: u32,
629    pub encodePicFlags: u32,
630    pub frameIdx: u32,
631    pub inputTimeStamp: u64,
632    pub inputDuration: u64,
633    pub inputBuffer: *mut c_void,
634    pub outputBitstream: *mut c_void,
635    pub completionEvent: *mut c_void,
636    pub bufferFmt: NV_ENC_BUFFER_FORMAT,
637    pub pictureStruct: NV_ENC_PIC_STRUCT,
638    pub pictureType: NV_ENC_PIC_TYPE,
639    pub codecPicParams: [u32; 256],
640    pub meHintCountsPerBlock: [u32; 2],
641    pub meExternalHints: *mut c_void,
642    pub reserved1: [u32; 6],
643    pub reserved2: [*mut c_void; 2],
644    pub qpDeltaMap: *mut i8,
645    pub qpDeltaMapSize: u32,
646    pub reservedBitFields: u32,
647    pub meHintRefPicDist: [u32; 2],
648    pub alphaBuffer: *mut c_void,
649    pub reserved3: [u32; 286],
650    pub reserved4: [*mut c_void; 60],
651}
652
653/// Lock bitstream output.
654#[repr(C)]
655pub struct NV_ENC_LOCK_BITSTREAM {
656    pub version: u32,
657    pub doNotWait: u32,
658    pub ltrFrame: u32,
659    pub reservedBitFields: u32,
660    pub outputBitstream: *mut c_void,
661    pub sliceOffsets: *mut u32,
662    pub frameIdx: u32,
663    pub hwEncodeStatus: u32,
664    pub numSlices: u32,
665    pub bitstreamSizeInBytes: u32,
666    pub outputTimeStamp: u64,
667    pub outputDuration: u64,
668    pub bitstreamBufferPtr: *mut c_void,
669    pub pictureType: NV_ENC_PIC_TYPE,
670    pub pictureStruct: NV_ENC_PIC_STRUCT,
671    pub frameAvgQP: u32,
672    pub frameSatd: u32,
673    pub ltrFrameIdx: u32,
674    pub ltrFrameBitmap: u32,
675    pub temporalId: u32,
676    pub reserved: [u32; 13],
677    pub intraMBCount: u32,
678    pub interMBCount: u32,
679    pub averageMVX: i32,
680    pub averageMVY: i32,
681    pub reserved1: [u32; 226],
682    pub reserved2: [*mut c_void; 64],
683}
684
685/// End-of-stream flag for NV_ENC_PIC_PARAMS.
686pub const NV_ENC_PIC_FLAG_EOS: u32 = 0x01;
687/// Force IDR flag.
688pub const NV_ENC_PIC_FLAG_FORCEIDR: u32 = 0x04;
689
690// ─── NVENC function pointer table ────────────────────────────────────────
691
692/// Subset of the NV_ENCODE_API_FUNCTION_LIST that we actually call.
693#[repr(C)]
694pub struct NV_ENCODE_API_FUNCTION_LIST {
695    pub version: u32,
696    pub reserved: u32,
697    pub nvEncOpenEncodeSession: *const c_void,
698    pub nvEncGetEncodeGUIDCount: *const c_void,
699    pub nvEncGetEncodeProfileGUIDCount: *const c_void,
700    pub nvEncGetEncodeProfileGUIDs: *const c_void,
701    pub nvEncGetEncodeGUIDs: *const c_void,
702    pub nvEncGetInputFormatCount: *const c_void,
703    pub nvEncGetInputFormats: *const c_void,
704    pub nvEncGetEncodeCaps: *const c_void,
705    pub nvEncGetEncodePresetCount: *const c_void,
706    pub nvEncGetEncodePresetGUIDs: *const c_void,
707    pub nvEncGetEncodePresetConfig: *const c_void,
708    pub nvEncInitializeEncoder:
709        Option<unsafe extern "C" fn(*mut c_void, *mut NV_ENC_INITIALIZE_PARAMS) -> NVENCSTATUS>,
710    pub nvEncCreateInputBuffer: *const c_void,
711    pub nvEncDestroyInputBuffer: *const c_void,
712    pub nvEncCreateBitstreamBuffer: Option<
713        unsafe extern "C" fn(*mut c_void, *mut NV_ENC_CREATE_BITSTREAM_BUFFER) -> NVENCSTATUS,
714    >,
715    pub nvEncDestroyBitstreamBuffer:
716        Option<unsafe extern "C" fn(*mut c_void, *mut c_void) -> NVENCSTATUS>,
717    pub nvEncEncodePicture:
718        Option<unsafe extern "C" fn(*mut c_void, *mut NV_ENC_PIC_PARAMS) -> NVENCSTATUS>,
719    pub nvEncLockBitstream:
720        Option<unsafe extern "C" fn(*mut c_void, *mut NV_ENC_LOCK_BITSTREAM) -> NVENCSTATUS>,
721    pub nvEncUnlockBitstream: Option<unsafe extern "C" fn(*mut c_void, *mut c_void) -> NVENCSTATUS>,
722    pub nvEncLockInputBuffer: *const c_void,
723    pub nvEncUnlockInputBuffer: *const c_void,
724    pub nvEncGetEncodeStats: *const c_void,
725    pub nvEncGetSequenceParams: *const c_void,
726    pub nvEncRegisterAsyncEvent: *const c_void,
727    pub nvEncUnregisterAsyncEvent: *const c_void,
728    pub nvEncMapInputResource:
729        Option<unsafe extern "C" fn(*mut c_void, *mut NV_ENC_MAP_INPUT_RESOURCE) -> NVENCSTATUS>,
730    pub nvEncUnmapInputResource:
731        Option<unsafe extern "C" fn(*mut c_void, *mut c_void) -> NVENCSTATUS>,
732    pub nvEncDestroyEncoder: Option<unsafe extern "C" fn(*mut c_void) -> NVENCSTATUS>,
733    pub nvEncInvalidateRefFrames: *const c_void,
734    pub nvEncOpenEncodeSessionEx: Option<
735        unsafe extern "C" fn(
736            *mut NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS,
737            *mut *mut c_void,
738        ) -> NVENCSTATUS,
739    >,
740    pub nvEncRegisterResource:
741        Option<unsafe extern "C" fn(*mut c_void, *mut NV_ENC_REGISTER_RESOURCE) -> NVENCSTATUS>,
742    pub nvEncUnregisterResource:
743        Option<unsafe extern "C" fn(*mut c_void, *mut c_void) -> NVENCSTATUS>,
744    pub nvEncReconfigureEncoder: *const c_void,
745    pub reserved1: *const c_void,
746    pub nvEncCreateMVBuffer: *const c_void,
747    pub nvEncDestroyMVBuffer: *const c_void,
748    pub nvEncRunMotionEstimationOnly: *const c_void,
749    pub nvEncGetLastErrorString: *const c_void,
750    pub nvEncSetIOCudaStreams: *const c_void,
751    pub nvEncGetEncodePresetConfigEx: Option<
752        unsafe extern "C" fn(
753            *mut c_void,
754            GUID,
755            GUID,
756            NV_ENC_TUNING_INFO,
757            *mut NV_ENC_PRESET_CONFIG,
758        ) -> NVENCSTATUS,
759    >,
760    pub nvEncGetSequenceParamEx: *const c_void,
761    pub nvEncRestoreEncoderState: *const c_void,
762    pub nvEncLookaheadPicture: *const c_void,
763    pub reserved2: [*const c_void; 275],
764}
765
766/// Preset config wrapper.
767#[repr(C)]
768pub struct NV_ENC_PRESET_CONFIG {
769    pub version: u32,
770    pub presetCfg: NV_ENC_CONFIG,
771    pub reserved: [u32; 255],
772    pub reserved2: [*mut c_void; 64],
773}
774
775unsafe extern "C" {
776    pub fn NvEncodeAPIGetMaxSupportedVersion(version: *mut u32) -> NVENCSTATUS;
777    /// Entry point to get the NVENC function table.
778    pub fn NvEncodeAPICreateInstance(
779        function_list: *mut NV_ENCODE_API_FUNCTION_LIST,
780    ) -> NVENCSTATUS;
781}
782
783// ═══════════════════════════════════════════════════════════════════════════
784//  CUDA DRIVER — event functions (not in cudarc)
785// ═══════════════════════════════════════════════════════════════════════════
786
787/// CUDA event handle.
788pub type CUevent = *mut c_void;
789
790pub const CU_EVENT_DISABLE_TIMING: c_uint = 0x02;
791
792unsafe extern "C" {
793    pub fn cuCtxGetCurrent(pctx: *mut CUcontext) -> CUresult;
794    pub fn cuCtxSetCurrent(ctx: CUcontext) -> CUresult;
795    pub fn cuEventCreate(phEvent: *mut CUevent, Flags: c_uint) -> CUresult;
796    pub fn cuEventDestroy_v2(hEvent: CUevent) -> CUresult;
797    pub fn cuEventRecord(hEvent: CUevent, hStream: CUstream) -> CUresult;
798    pub fn cuStreamWaitEvent(hStream: CUstream, hEvent: CUevent, Flags: c_uint) -> CUresult;
799    pub fn cuStreamSynchronize(hStream: CUstream) -> CUresult;
800}
801
802// ═══════════════════════════════════════════════════════════════════════════
803//  CUDA DRIVER — async memcpy (for D2D copy of decoded surfaces)
804// ═══════════════════════════════════════════════════════════════════════════
805
806unsafe extern "C" {
807    pub fn cuMemcpy2DAsync_v2(pCopy: *const CUDA_MEMCPY2D, hStream: CUstream) -> CUresult;
808}
809
810/// 2D memory copy descriptor.
811#[repr(C)]
812#[derive(Clone, Copy, Debug)]
813pub struct CUDA_MEMCPY2D {
814    pub srcXInBytes: usize,
815    pub srcY: usize,
816    pub srcMemoryType: CUmemorytype,
817    pub srcHost: *const c_void,
818    pub srcDevice: CUdeviceptr,
819    pub srcArray: *const c_void,
820    pub srcPitch: usize,
821    pub dstXInBytes: usize,
822    pub dstY: usize,
823    pub dstMemoryType: CUmemorytype,
824    pub dstHost: *mut c_void,
825    pub dstDevice: CUdeviceptr,
826    pub dstArray: *mut c_void,
827    pub dstPitch: usize,
828    pub WidthInBytes: usize,
829    pub Height: usize,
830}
831
832#[repr(C)]
833#[derive(Clone, Copy, Debug, PartialEq, Eq)]
834pub enum CUmemorytype {
835    Host = 0x01,
836    Device = 0x02,
837    Array = 0x03,
838    Unified = 0x04,
839}
840
841// ═══════════════════════════════════════════════════════════════════════════
842//  HELPERS
843// ═══════════════════════════════════════════════════════════════════════════
844
845/// Convert a CUDA result to an engine `Result`, mapping failures to
846/// [`EngineError::Decode`](rave_core::error::EngineError::Decode).
847///
848/// Use in decode-side code paths (NVDEC, parser, stream sync during decode).
849#[inline]
850pub fn check_cu(result: CUresult, context: &str) -> rave_core::error::Result<()> {
851    if result == CUDA_SUCCESS {
852        Ok(())
853    } else {
854        Err(rave_core::error::EngineError::Decode(format!(
855            "{context}: CUDA error code {result}"
856        )))
857    }
858}
859
860/// Convert a CUDA result to an engine `Result`, mapping failures to
861/// [`EngineError::Encode`](rave_core::error::EngineError::Encode).
862///
863/// Use in encode-side code paths (NVENC session, context switching for encoder,
864/// stream sync during encode).
865#[inline]
866pub fn check_cu_encode(result: CUresult, context: &str) -> rave_core::error::Result<()> {
867    if result == CUDA_SUCCESS {
868        Ok(())
869    } else {
870        Err(rave_core::error::EngineError::Encode(format!(
871            "{context}: CUDA error code {result}"
872        )))
873    }
874}
875
876/// Convert an NVENC status to an engine Result.
877#[inline]
878pub fn check_nvenc(status: NVENCSTATUS, context: &str) -> rave_core::error::Result<()> {
879    if status == NV_ENC_SUCCESS {
880        Ok(())
881    } else {
882        Err(rave_core::error::EngineError::Encode(format!(
883            "{context}: NVENC error code {status} ({})",
884            nvenc_status_name(status)
885        )))
886    }
887}
888
889/// Human-readable NVENC status names for diagnostics.
890#[inline]
891pub const fn nvenc_status_name(status: NVENCSTATUS) -> &'static str {
892    match status {
893        NV_ENC_SUCCESS => "NV_ENC_SUCCESS",
894        NV_ENC_ERR_NO_ENCODE_DEVICE => "NV_ENC_ERR_NO_ENCODE_DEVICE",
895        NV_ENC_ERR_UNSUPPORTED_DEVICE => "NV_ENC_ERR_UNSUPPORTED_DEVICE",
896        NV_ENC_ERR_INVALID_ENCODERDEVICE => "NV_ENC_ERR_INVALID_ENCODERDEVICE",
897        NV_ENC_ERR_INVALID_DEVICE => "NV_ENC_ERR_INVALID_DEVICE",
898        NV_ENC_ERR_DEVICE_NOT_EXIST => "NV_ENC_ERR_DEVICE_NOT_EXIST",
899        NV_ENC_ERR_INVALID_PTR => "NV_ENC_ERR_INVALID_PTR",
900        NV_ENC_ERR_INVALID_EVENT => "NV_ENC_ERR_INVALID_EVENT",
901        NV_ENC_ERR_INVALID_PARAM => "NV_ENC_ERR_INVALID_PARAM",
902        NV_ENC_ERR_INVALID_CALL => "NV_ENC_ERR_INVALID_CALL",
903        NV_ENC_ERR_OUT_OF_MEMORY => "NV_ENC_ERR_OUT_OF_MEMORY",
904        NV_ENC_ERR_ENCODER_NOT_INITIALIZED => "NV_ENC_ERR_ENCODER_NOT_INITIALIZED",
905        NV_ENC_ERR_UNSUPPORTED_PARAM => "NV_ENC_ERR_UNSUPPORTED_PARAM",
906        NV_ENC_ERR_LOCK_BUSY => "NV_ENC_ERR_LOCK_BUSY",
907        NV_ENC_ERR_NOT_ENOUGH_BUFFER => "NV_ENC_ERR_NOT_ENOUGH_BUFFER",
908        NV_ENC_ERR_INVALID_VERSION => "NV_ENC_ERR_INVALID_VERSION",
909        NV_ENC_ERR_MAP_FAILED => "NV_ENC_ERR_MAP_FAILED",
910        NV_ENC_ERR_NEED_MORE_INPUT => "NV_ENC_ERR_NEED_MORE_INPUT",
911        NV_ENC_ERR_ENCODER_BUSY => "NV_ENC_ERR_ENCODER_BUSY",
912        NV_ENC_ERR_EVENT_NOT_REGISTERD => "NV_ENC_ERR_EVENT_NOT_REGISTERD",
913        NV_ENC_ERR_GENERIC => "NV_ENC_ERR_GENERIC",
914        _ => "NV_ENC_ERR_UNKNOWN",
915    }
916}