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)]
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/// H.265 Main profile GUID.
381pub const NV_ENC_HEVC_PROFILE_MAIN_GUID: GUID = GUID {
382    Data1: 0xB514C39A,
383    Data2: 0xB55B,
384    Data3: 0x40FA,
385    Data4: [0x87, 0x87, 0x67, 0xED, 0x5E, 0x28, 0x49, 0x4D],
386};
387
388/// H.265 Main10 profile GUID.
389pub const NV_ENC_HEVC_PROFILE_MAIN10_GUID: GUID = GUID {
390    Data1: 0xFA4D2B6C,
391    Data2: 0x3A5B,
392    Data3: 0x411A,
393    Data4: [0x80, 0x18, 0x0A, 0x3F, 0x5E, 0x3C, 0x9B, 0x44],
394};
395
396// ─── NVENC enums ─────────────────────────────────────────────────────────
397
398#[repr(u32)]
399#[derive(Clone, Copy, Debug, PartialEq, Eq)]
400pub enum NV_ENC_DEVICE_TYPE {
401    DIRECTX = 0,
402    CUDA = 1,
403    OPENGL = 2,
404}
405
406#[repr(u32)]
407#[derive(Clone, Copy, Debug, PartialEq, Eq)]
408pub enum NV_ENC_INPUT_RESOURCE_TYPE {
409    DIRECTX = 0,
410    CUDADEVICEPTR = 1,
411    CUDAARRAY = 2,
412    OPENGL_TEX = 3,
413}
414
415#[repr(u32)]
416#[derive(Clone, Copy, Debug, PartialEq, Eq)]
417pub enum NV_ENC_BUFFER_FORMAT {
418    UNDEFINED = 0x00000000,
419    NV12 = 0x00000001,
420    YV12 = 0x00000010,
421    IYUV = 0x00000100,
422    YUV444 = 0x00001000,
423    YUV420_10BIT = 0x00010000,
424    ARGB = 0x01000000,
425    ABGR = 0x02000000,
426}
427
428#[repr(u32)]
429#[derive(Clone, Copy, Debug, PartialEq, Eq)]
430pub enum NV_ENC_PIC_TYPE {
431    P = 0,
432    B = 1,
433    I = 2,
434    IDR = 3,
435    BI = 4,
436    SKIPPED = 5,
437}
438
439#[repr(u32)]
440#[derive(Clone, Copy, Debug, PartialEq, Eq)]
441pub enum NV_ENC_PIC_STRUCT {
442    FRAME = 0x01,
443    FIELD_TOP_BOTTOM = 0x02,
444    FIELD_BOTTOM_TOP = 0x03,
445}
446
447#[repr(u32)]
448#[derive(Clone, Copy, Debug, PartialEq, Eq)]
449pub enum NV_ENC_TUNING_INFO {
450    UNDEFINED = 0,
451    HIGH_QUALITY = 1,
452    LOW_LATENCY = 2,
453    ULTRA_LOW_LATENCY = 3,
454    LOSSLESS = 4,
455}
456
457// ─── NVENC params structs ────────────────────────────────────────────────
458
459/// Matches `NVENCAPI_MAJOR_VERSION` in `nvEncodeAPI.h`.
460pub const NVENCAPI_MAJOR_VERSION: u32 = 13;
461/// Matches `NVENCAPI_MINOR_VERSION` in `nvEncodeAPI.h`.
462pub const NVENCAPI_MINOR_VERSION: u32 = 0;
463/// Matches `NVENCAPI_VERSION` in `nvEncodeAPI.h`.
464pub const NVENCAPI_VERSION: u32 = NVENCAPI_MAJOR_VERSION | (NVENCAPI_MINOR_VERSION << 24);
465
466/// Matches `NVENCAPI_STRUCT_VERSION(ver)` in `nvEncodeAPI.h`.
467#[inline]
468pub const fn nvenc_struct_version(struct_ver: u32) -> u32 {
469    NVENCAPI_VERSION | (struct_ver << 16) | (0x7 << 28)
470}
471
472pub const NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER: u32 = nvenc_struct_version(1);
473pub const NV_ENCODE_API_FUNCTION_LIST_VER: u32 = nvenc_struct_version(2);
474
475/// Session open params.
476#[repr(C)]
477pub struct NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS {
478    pub version: u32,
479    pub deviceType: NV_ENC_DEVICE_TYPE,
480    pub device: *mut c_void,
481    pub reserved: *mut c_void,
482    pub apiVersion: u32,
483    pub reserved1: [u32; 253],
484    pub reserved2: [*mut c_void; 64],
485}
486
487/// Rate control params (simplified).
488#[repr(C)]
489#[derive(Clone, Copy)]
490pub struct NV_ENC_RC_PARAMS {
491    pub version: u32,
492    pub rateControlMode: u32,
493    pub constQP_interP: u32,
494    pub constQP_interB: u32,
495    pub constQP_intra: u32,
496    pub averageBitRate: u32,
497    pub maxBitRate: u32,
498    pub vbvBufferSize: u32,
499    pub vbvInitialDelay: u32,
500    pub reserved: [u32; 247],
501}
502
503/// HEVC-specific config (simplified).
504#[repr(C)]
505#[derive(Clone, Copy)]
506pub struct NV_ENC_CONFIG_HEVC {
507    pub level: u32,
508    pub tier: u32,
509    pub minCUSize: u32,
510    pub maxCUSize: u32,
511    pub reserved: [u32; 252],
512}
513
514/// Codec-specific config union (simplified — only HEVC used).
515#[repr(C)]
516#[derive(Clone, Copy)]
517pub union NV_ENC_CODEC_CONFIG {
518    pub hevcConfig: NV_ENC_CONFIG_HEVC,
519    pub reserved: [u32; 256],
520}
521
522/// Encoder configuration.
523#[repr(C)]
524#[derive(Clone, Copy)]
525pub struct NV_ENC_CONFIG {
526    pub version: u32,
527    pub profileGUID: GUID,
528    pub gopLength: u32,
529    pub frameIntervalP: i32,
530    pub monoChromeEncoding: u32,
531    pub frameFieldMode: u32,
532    pub mvPrecision: u32,
533    pub rcParams: NV_ENC_RC_PARAMS,
534    pub encodeCodecConfig: NV_ENC_CODEC_CONFIG,
535    pub reserved: [u32; 278],
536    pub reserved2: [*mut c_void; 64],
537}
538
539/// Encoder initialization params.
540#[repr(C)]
541pub struct NV_ENC_INITIALIZE_PARAMS {
542    pub version: u32,
543    pub encodeGUID: GUID,
544    pub presetGUID: GUID,
545    pub encodeWidth: u32,
546    pub encodeHeight: u32,
547    pub darWidth: u32,
548    pub darHeight: u32,
549    pub frameRateNum: u32,
550    pub frameRateDen: u32,
551    pub enableEncodeAsync: u32,
552    pub enablePTD: u32,
553    pub reportSliceOffsets: u32,
554    pub enableSubFrameWrite: u32,
555    pub enableExternalMEHints: u32,
556    pub enableMEOnlyMode: u32,
557    pub enableWeightedPrediction: u32,
558    pub enableOutputInVidmem: u32,
559    pub reserved1: u32,
560    pub privDataSize: u32,
561    pub privData: *mut c_void,
562    pub encodeConfig: *mut NV_ENC_CONFIG,
563    pub maxEncodeWidth: u32,
564    pub maxEncodeHeight: u32,
565    pub maxMEHintCountsPerBlock: [u32; 2],
566    pub tuningInfo: NV_ENC_TUNING_INFO,
567    pub reserved: [u32; 289],
568    pub reserved2: [*mut c_void; 64],
569}
570
571/// Register external resource.
572#[repr(C)]
573pub struct NV_ENC_REGISTER_RESOURCE {
574    pub version: u32,
575    pub resourceType: NV_ENC_INPUT_RESOURCE_TYPE,
576    pub width: u32,
577    pub height: u32,
578    pub pitch: u32,
579    pub subResourceIndex: u32,
580    pub resourceToRegister: *mut c_void,
581    pub registeredResource: *mut c_void,
582    pub bufferFormat: NV_ENC_BUFFER_FORMAT,
583    pub bufferUsage: u32,
584    pub pInputFencePoint: *mut c_void,
585    pub pOutputFencePoint: *mut c_void,
586    pub reserved: [u32; 247],
587    pub reserved2: [*mut c_void; 62],
588}
589
590/// Map input resource.
591#[repr(C)]
592pub struct NV_ENC_MAP_INPUT_RESOURCE {
593    pub version: u32,
594    pub subResourceIndex: u32,
595    pub inputResource: *mut c_void,
596    pub registeredResource: *mut c_void,
597    pub mappedResource: *mut c_void,
598    pub mappedBufferFmt: NV_ENC_BUFFER_FORMAT,
599    pub reserved: [u32; 251],
600    pub reserved2: [*mut c_void; 63],
601}
602
603/// Create bitstream buffer.
604#[repr(C)]
605pub struct NV_ENC_CREATE_BITSTREAM_BUFFER {
606    pub version: u32,
607    pub bitstreamBuffer: *mut c_void,
608    pub size: u32,
609    pub memoryHeap: u32,
610    pub reserved: [u32; 252],
611    pub reserved2: [*mut c_void; 64],
612}
613
614/// Encode picture params.
615#[repr(C)]
616pub struct NV_ENC_PIC_PARAMS {
617    pub version: u32,
618    pub inputWidth: u32,
619    pub inputHeight: u32,
620    pub inputPitch: u32,
621    pub encodePicFlags: u32,
622    pub frameIdx: u32,
623    pub inputTimeStamp: u64,
624    pub inputDuration: u64,
625    pub inputBuffer: *mut c_void,
626    pub outputBitstream: *mut c_void,
627    pub completionEvent: *mut c_void,
628    pub bufferFmt: NV_ENC_BUFFER_FORMAT,
629    pub pictureStruct: NV_ENC_PIC_STRUCT,
630    pub pictureType: NV_ENC_PIC_TYPE,
631    pub codecPicParams: [u32; 256],
632    pub meHintCountsPerBlock: [u32; 2],
633    pub meExternalHints: *mut c_void,
634    pub reserved1: [u32; 6],
635    pub reserved2: [*mut c_void; 2],
636    pub qpDeltaMap: *mut i8,
637    pub qpDeltaMapSize: u32,
638    pub reservedBitFields: u32,
639    pub meHintRefPicDist: [u32; 2],
640    pub alphaBuffer: *mut c_void,
641    pub reserved3: [u32; 286],
642    pub reserved4: [*mut c_void; 60],
643}
644
645/// Lock bitstream output.
646#[repr(C)]
647pub struct NV_ENC_LOCK_BITSTREAM {
648    pub version: u32,
649    pub doNotWait: u32,
650    pub ltrFrame: u32,
651    pub reservedBitFields: u32,
652    pub outputBitstream: *mut c_void,
653    pub sliceOffsets: *mut u32,
654    pub frameIdx: u32,
655    pub hwEncodeStatus: u32,
656    pub numSlices: u32,
657    pub bitstreamSizeInBytes: u32,
658    pub outputTimeStamp: u64,
659    pub outputDuration: u64,
660    pub bitstreamBufferPtr: *mut c_void,
661    pub pictureType: NV_ENC_PIC_TYPE,
662    pub pictureStruct: NV_ENC_PIC_STRUCT,
663    pub frameAvgQP: u32,
664    pub frameSatd: u32,
665    pub ltrFrameIdx: u32,
666    pub ltrFrameBitmap: u32,
667    pub temporalId: u32,
668    pub reserved: [u32; 13],
669    pub intraMBCount: u32,
670    pub interMBCount: u32,
671    pub averageMVX: i32,
672    pub averageMVY: i32,
673    pub reserved1: [u32; 226],
674    pub reserved2: [*mut c_void; 64],
675}
676
677/// End-of-stream flag for NV_ENC_PIC_PARAMS.
678pub const NV_ENC_PIC_FLAG_EOS: u32 = 0x01;
679/// Force IDR flag.
680pub const NV_ENC_PIC_FLAG_FORCEIDR: u32 = 0x04;
681
682// ─── NVENC function pointer table ────────────────────────────────────────
683
684/// Subset of the NV_ENCODE_API_FUNCTION_LIST that we actually call.
685#[repr(C)]
686pub struct NV_ENCODE_API_FUNCTION_LIST {
687    pub version: u32,
688    pub reserved: u32,
689    pub nvEncOpenEncodeSession: *const c_void,
690    pub nvEncGetEncodeGUIDCount: *const c_void,
691    pub nvEncGetEncodeProfileGUIDCount: *const c_void,
692    pub nvEncGetEncodeProfileGUIDs: *const c_void,
693    pub nvEncGetEncodeGUIDs: *const c_void,
694    pub nvEncGetInputFormatCount: *const c_void,
695    pub nvEncGetInputFormats: *const c_void,
696    pub nvEncGetEncodeCaps: *const c_void,
697    pub nvEncGetEncodePresetCount: *const c_void,
698    pub nvEncGetEncodePresetGUIDs: *const c_void,
699    pub nvEncGetEncodePresetConfig: *const c_void,
700    pub nvEncInitializeEncoder:
701        Option<unsafe extern "C" fn(*mut c_void, *mut NV_ENC_INITIALIZE_PARAMS) -> NVENCSTATUS>,
702    pub nvEncCreateInputBuffer: *const c_void,
703    pub nvEncDestroyInputBuffer: *const c_void,
704    pub nvEncCreateBitstreamBuffer: Option<
705        unsafe extern "C" fn(*mut c_void, *mut NV_ENC_CREATE_BITSTREAM_BUFFER) -> NVENCSTATUS,
706    >,
707    pub nvEncDestroyBitstreamBuffer:
708        Option<unsafe extern "C" fn(*mut c_void, *mut c_void) -> NVENCSTATUS>,
709    pub nvEncEncodePicture:
710        Option<unsafe extern "C" fn(*mut c_void, *mut NV_ENC_PIC_PARAMS) -> NVENCSTATUS>,
711    pub nvEncLockBitstream:
712        Option<unsafe extern "C" fn(*mut c_void, *mut NV_ENC_LOCK_BITSTREAM) -> NVENCSTATUS>,
713    pub nvEncUnlockBitstream: Option<unsafe extern "C" fn(*mut c_void, *mut c_void) -> NVENCSTATUS>,
714    pub nvEncLockInputBuffer: *const c_void,
715    pub nvEncUnlockInputBuffer: *const c_void,
716    pub nvEncGetEncodeStats: *const c_void,
717    pub nvEncGetSequenceParams: *const c_void,
718    pub nvEncRegisterAsyncEvent: *const c_void,
719    pub nvEncUnregisterAsyncEvent: *const c_void,
720    pub nvEncMapInputResource:
721        Option<unsafe extern "C" fn(*mut c_void, *mut NV_ENC_MAP_INPUT_RESOURCE) -> NVENCSTATUS>,
722    pub nvEncUnmapInputResource:
723        Option<unsafe extern "C" fn(*mut c_void, *mut c_void) -> NVENCSTATUS>,
724    pub nvEncDestroyEncoder: Option<unsafe extern "C" fn(*mut c_void) -> NVENCSTATUS>,
725    pub nvEncInvalidateRefFrames: *const c_void,
726    pub nvEncOpenEncodeSessionEx: Option<
727        unsafe extern "C" fn(
728            *mut NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS,
729            *mut *mut c_void,
730        ) -> NVENCSTATUS,
731    >,
732    pub nvEncRegisterResource:
733        Option<unsafe extern "C" fn(*mut c_void, *mut NV_ENC_REGISTER_RESOURCE) -> NVENCSTATUS>,
734    pub nvEncUnregisterResource:
735        Option<unsafe extern "C" fn(*mut c_void, *mut c_void) -> NVENCSTATUS>,
736    pub nvEncReconfigureEncoder: *const c_void,
737    pub reserved1: *const c_void,
738    pub nvEncCreateMVBuffer: *const c_void,
739    pub nvEncDestroyMVBuffer: *const c_void,
740    pub nvEncRunMotionEstimationOnly: *const c_void,
741    pub nvEncGetLastErrorString: *const c_void,
742    pub nvEncSetIOCudaStreams: *const c_void,
743    pub nvEncGetEncodePresetConfigEx: Option<
744        unsafe extern "C" fn(
745            *mut c_void,
746            GUID,
747            GUID,
748            NV_ENC_TUNING_INFO,
749            *mut NV_ENC_PRESET_CONFIG,
750        ) -> NVENCSTATUS,
751    >,
752    pub nvEncGetSequenceParamEx: *const c_void,
753    pub nvEncRestoreEncoderState: *const c_void,
754    pub nvEncLookaheadPicture: *const c_void,
755    pub reserved2: [*const c_void; 275],
756}
757
758/// Preset config wrapper.
759#[repr(C)]
760pub struct NV_ENC_PRESET_CONFIG {
761    pub version: u32,
762    pub presetCfg: NV_ENC_CONFIG,
763    pub reserved: [u32; 255],
764    pub reserved2: [*mut c_void; 64],
765}
766
767unsafe extern "C" {
768    pub fn NvEncodeAPIGetMaxSupportedVersion(version: *mut u32) -> NVENCSTATUS;
769    /// Entry point to get the NVENC function table.
770    pub fn NvEncodeAPICreateInstance(
771        function_list: *mut NV_ENCODE_API_FUNCTION_LIST,
772    ) -> NVENCSTATUS;
773}
774
775// ═══════════════════════════════════════════════════════════════════════════
776//  CUDA DRIVER — event functions (not in cudarc)
777// ═══════════════════════════════════════════════════════════════════════════
778
779/// CUDA event handle.
780pub type CUevent = *mut c_void;
781
782pub const CU_EVENT_DISABLE_TIMING: c_uint = 0x02;
783
784unsafe extern "C" {
785    pub fn cuCtxGetCurrent(pctx: *mut CUcontext) -> CUresult;
786    pub fn cuCtxSetCurrent(ctx: CUcontext) -> CUresult;
787    pub fn cuEventCreate(phEvent: *mut CUevent, Flags: c_uint) -> CUresult;
788    pub fn cuEventDestroy_v2(hEvent: CUevent) -> CUresult;
789    pub fn cuEventRecord(hEvent: CUevent, hStream: CUstream) -> CUresult;
790    pub fn cuStreamWaitEvent(hStream: CUstream, hEvent: CUevent, Flags: c_uint) -> CUresult;
791    pub fn cuStreamSynchronize(hStream: CUstream) -> CUresult;
792}
793
794// ═══════════════════════════════════════════════════════════════════════════
795//  CUDA DRIVER — async memcpy (for D2D copy of decoded surfaces)
796// ═══════════════════════════════════════════════════════════════════════════
797
798unsafe extern "C" {
799    pub fn cuMemcpy2DAsync_v2(pCopy: *const CUDA_MEMCPY2D, hStream: CUstream) -> CUresult;
800}
801
802/// 2D memory copy descriptor.
803#[repr(C)]
804#[derive(Clone, Copy, Debug)]
805pub struct CUDA_MEMCPY2D {
806    pub srcXInBytes: usize,
807    pub srcY: usize,
808    pub srcMemoryType: CUmemorytype,
809    pub srcHost: *const c_void,
810    pub srcDevice: CUdeviceptr,
811    pub srcArray: *const c_void,
812    pub srcPitch: usize,
813    pub dstXInBytes: usize,
814    pub dstY: usize,
815    pub dstMemoryType: CUmemorytype,
816    pub dstHost: *mut c_void,
817    pub dstDevice: CUdeviceptr,
818    pub dstArray: *mut c_void,
819    pub dstPitch: usize,
820    pub WidthInBytes: usize,
821    pub Height: usize,
822}
823
824#[repr(C)]
825#[derive(Clone, Copy, Debug, PartialEq, Eq)]
826pub enum CUmemorytype {
827    Host = 0x01,
828    Device = 0x02,
829    Array = 0x03,
830    Unified = 0x04,
831}
832
833// ═══════════════════════════════════════════════════════════════════════════
834//  HELPERS
835// ═══════════════════════════════════════════════════════════════════════════
836
837/// Convert a CUDA result to an engine Result.
838#[inline]
839pub fn check_cu(result: CUresult, context: &str) -> rave_core::error::Result<()> {
840    if result == CUDA_SUCCESS {
841        Ok(())
842    } else {
843        Err(rave_core::error::EngineError::Decode(format!(
844            "{context}: CUDA error code {result}"
845        )))
846    }
847}
848
849/// Convert an NVENC status to an engine Result.
850#[inline]
851pub fn check_nvenc(status: NVENCSTATUS, context: &str) -> rave_core::error::Result<()> {
852    if status == NV_ENC_SUCCESS {
853        Ok(())
854    } else {
855        Err(rave_core::error::EngineError::Encode(format!(
856            "{context}: NVENC error code {status} ({})",
857            nvenc_status_name(status)
858        )))
859    }
860}
861
862/// Human-readable NVENC status names for diagnostics.
863#[inline]
864pub const fn nvenc_status_name(status: NVENCSTATUS) -> &'static str {
865    match status {
866        NV_ENC_SUCCESS => "NV_ENC_SUCCESS",
867        NV_ENC_ERR_NO_ENCODE_DEVICE => "NV_ENC_ERR_NO_ENCODE_DEVICE",
868        NV_ENC_ERR_UNSUPPORTED_DEVICE => "NV_ENC_ERR_UNSUPPORTED_DEVICE",
869        NV_ENC_ERR_INVALID_ENCODERDEVICE => "NV_ENC_ERR_INVALID_ENCODERDEVICE",
870        NV_ENC_ERR_INVALID_DEVICE => "NV_ENC_ERR_INVALID_DEVICE",
871        NV_ENC_ERR_DEVICE_NOT_EXIST => "NV_ENC_ERR_DEVICE_NOT_EXIST",
872        NV_ENC_ERR_INVALID_PTR => "NV_ENC_ERR_INVALID_PTR",
873        NV_ENC_ERR_INVALID_EVENT => "NV_ENC_ERR_INVALID_EVENT",
874        NV_ENC_ERR_INVALID_PARAM => "NV_ENC_ERR_INVALID_PARAM",
875        NV_ENC_ERR_INVALID_CALL => "NV_ENC_ERR_INVALID_CALL",
876        NV_ENC_ERR_OUT_OF_MEMORY => "NV_ENC_ERR_OUT_OF_MEMORY",
877        NV_ENC_ERR_ENCODER_NOT_INITIALIZED => "NV_ENC_ERR_ENCODER_NOT_INITIALIZED",
878        NV_ENC_ERR_UNSUPPORTED_PARAM => "NV_ENC_ERR_UNSUPPORTED_PARAM",
879        NV_ENC_ERR_LOCK_BUSY => "NV_ENC_ERR_LOCK_BUSY",
880        NV_ENC_ERR_NOT_ENOUGH_BUFFER => "NV_ENC_ERR_NOT_ENOUGH_BUFFER",
881        NV_ENC_ERR_INVALID_VERSION => "NV_ENC_ERR_INVALID_VERSION",
882        NV_ENC_ERR_MAP_FAILED => "NV_ENC_ERR_MAP_FAILED",
883        NV_ENC_ERR_NEED_MORE_INPUT => "NV_ENC_ERR_NEED_MORE_INPUT",
884        NV_ENC_ERR_ENCODER_BUSY => "NV_ENC_ERR_ENCODER_BUSY",
885        NV_ENC_ERR_EVENT_NOT_REGISTERD => "NV_ENC_ERR_EVENT_NOT_REGISTERD",
886        NV_ENC_ERR_GENERIC => "NV_ENC_ERR_GENERIC",
887        _ => "NV_ENC_ERR_UNKNOWN",
888    }
889}