1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
//! Defines `ENCODE_API`, which is a lazy static of [`EncodeAPI`].

use core::ffi::{c_int, c_void};

use crate::sys::nvEncodeAPI::{
    NvEncodeAPICreateInstance,
    NvEncodeAPIGetMaxSupportedVersion,
    GUID,
    NVENCAPI_MAJOR_VERSION,
    NVENCAPI_MINOR_VERSION,
    NVENCSTATUS,
    NV_ENCODE_API_FUNCTION_LIST,
    NV_ENCODE_API_FUNCTION_LIST_VER,
    NV_ENC_BUFFER_FORMAT,
    NV_ENC_CAPS_PARAM,
    NV_ENC_CREATE_BITSTREAM_BUFFER,
    NV_ENC_CREATE_INPUT_BUFFER,
    NV_ENC_CREATE_MV_BUFFER,
    NV_ENC_CUSTREAM_PTR,
    NV_ENC_EVENT_PARAMS,
    NV_ENC_INITIALIZE_PARAMS,
    NV_ENC_INPUT_PTR,
    NV_ENC_LOCK_BITSTREAM,
    NV_ENC_LOCK_INPUT_BUFFER,
    NV_ENC_LOOKAHEAD_PIC_PARAMS,
    NV_ENC_MAP_INPUT_RESOURCE,
    NV_ENC_MEONLY_PARAMS,
    NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS,
    NV_ENC_OUTPUT_PTR,
    NV_ENC_PIC_PARAMS,
    NV_ENC_PRESET_CONFIG,
    NV_ENC_RECONFIGURE_PARAMS,
    NV_ENC_REGISTERED_PTR,
    NV_ENC_REGISTER_RESOURCE,
    NV_ENC_RESTORE_ENCODER_STATE_PARAMS,
    NV_ENC_SEQUENCE_PARAM_PAYLOAD,
    NV_ENC_STAT,
    NV_ENC_TUNING_INFO,
};

lazy_static! {
    /// A lazy static for the Encoder API.
    ///
    /// You should not interact with this directly.
    /// [`Encoder`](crate::Encoder) exposes much of the functionality and provides a nicer API.
    pub static ref ENCODE_API: EncodeAPI =
        EncodeAPI::new();
}

// Function type aliases to shorten later definitions.
type OpenEncodeSession = unsafe extern "C" fn(*mut c_void, u32, *mut *mut c_void) -> NVENCSTATUS;
type GetEncodeGUIDCount = unsafe extern "C" fn(*mut c_void, *mut u32) -> NVENCSTATUS;
type GetEncodeGUIDs = unsafe extern "C" fn(*mut c_void, *mut GUID, u32, *mut u32) -> NVENCSTATUS;
type GetInputFormatCount = unsafe extern "C" fn(*mut c_void, GUID, *mut u32) -> NVENCSTATUS;
type GetInputFormats = unsafe extern "C" fn(
    *mut c_void,
    GUID,
    *mut NV_ENC_BUFFER_FORMAT,
    u32,
    *mut u32,
) -> NVENCSTATUS;
type GetEncodeCaps =
    unsafe extern "C" fn(*mut c_void, GUID, *mut NV_ENC_CAPS_PARAM, *mut c_int) -> NVENCSTATUS;
type GetEncodePresetCount = unsafe extern "C" fn(*mut c_void, GUID, *mut u32) -> NVENCSTATUS;
type GetEncodePresetGUIDs =
    unsafe extern "C" fn(*mut c_void, GUID, *mut GUID, u32, *mut u32) -> NVENCSTATUS;
type GetEncodeProfileGUIDCount = GetEncodePresetCount;
type GetEncodeProfileGUIDs = GetEncodePresetGUIDs;
type GetEncodePresetConfig =
    unsafe extern "C" fn(*mut c_void, GUID, GUID, *mut NV_ENC_PRESET_CONFIG) -> NVENCSTATUS;
type GetEncodePresetConfigEx = unsafe extern "C" fn(
    *mut c_void,
    GUID,
    GUID,
    NV_ENC_TUNING_INFO,
    *mut NV_ENC_PRESET_CONFIG,
) -> NVENCSTATUS;
type InitializeEncoder =
    unsafe extern "C" fn(*mut c_void, *mut NV_ENC_INITIALIZE_PARAMS) -> NVENCSTATUS;
type CreateInputBuffer =
    unsafe extern "C" fn(*mut c_void, *mut NV_ENC_CREATE_INPUT_BUFFER) -> NVENCSTATUS;
type DestroyInputBuffer = unsafe extern "C" fn(*mut c_void, NV_ENC_INPUT_PTR) -> NVENCSTATUS;
type CreateBitstreamBuffer =
    unsafe extern "C" fn(*mut c_void, *mut NV_ENC_CREATE_BITSTREAM_BUFFER) -> NVENCSTATUS;
type DestroyBitstreamBuffer = unsafe extern "C" fn(*mut c_void, NV_ENC_OUTPUT_PTR) -> NVENCSTATUS;
type EncodePicture = unsafe extern "C" fn(*mut c_void, *mut NV_ENC_PIC_PARAMS) -> NVENCSTATUS;
type LockBitstream = unsafe extern "C" fn(*mut c_void, *mut NV_ENC_LOCK_BITSTREAM) -> NVENCSTATUS;
type UnlockBitstream = unsafe extern "C" fn(*mut c_void, NV_ENC_OUTPUT_PTR) -> NVENCSTATUS;
type LockInputBuffer =
    unsafe extern "C" fn(*mut c_void, *mut NV_ENC_LOCK_INPUT_BUFFER) -> NVENCSTATUS;
type UnlockInputBuffer = unsafe extern "C" fn(*mut c_void, NV_ENC_INPUT_PTR) -> NVENCSTATUS;
type GetEncodeStats = unsafe extern "C" fn(*mut c_void, *mut NV_ENC_STAT) -> NVENCSTATUS;
type GetSequenceParams =
    unsafe extern "C" fn(*mut c_void, *mut NV_ENC_SEQUENCE_PARAM_PAYLOAD) -> NVENCSTATUS;
type RegisterAsyncEvent =
    unsafe extern "C" fn(*mut c_void, *mut NV_ENC_EVENT_PARAMS) -> NVENCSTATUS;
type UnregisterAsyncEvent =
    unsafe extern "C" fn(*mut c_void, *mut NV_ENC_EVENT_PARAMS) -> NVENCSTATUS;
type MapInputResource =
    unsafe extern "C" fn(*mut c_void, *mut NV_ENC_MAP_INPUT_RESOURCE) -> NVENCSTATUS;
type UnmapInputResource = unsafe extern "C" fn(*mut c_void, NV_ENC_INPUT_PTR) -> NVENCSTATUS;
type DestroyEncoder = unsafe extern "C" fn(encoder: *mut c_void) -> NVENCSTATUS;
type InvalidateRefFrames = unsafe extern "C" fn(*mut c_void, u64) -> NVENCSTATUS;
type OpenEncodeSessionEx = unsafe extern "C" fn(
    *mut NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS,
    *mut *mut c_void,
) -> NVENCSTATUS;
type RegisterResource =
    unsafe extern "C" fn(*mut c_void, *mut NV_ENC_REGISTER_RESOURCE) -> NVENCSTATUS;
type UnregisterResource = unsafe extern "C" fn(*mut c_void, NV_ENC_REGISTERED_PTR) -> NVENCSTATUS;
type ReconfigureEncoder =
    unsafe extern "C" fn(*mut c_void, *mut NV_ENC_RECONFIGURE_PARAMS) -> NVENCSTATUS;
type CreateMVBuffer =
    unsafe extern "C" fn(*mut c_void, *mut NV_ENC_CREATE_MV_BUFFER) -> NVENCSTATUS;
type DestroyMVBuffer = unsafe extern "C" fn(*mut c_void, NV_ENC_OUTPUT_PTR) -> NVENCSTATUS;
type RunMotionEstimationOnly =
    unsafe extern "C" fn(*mut c_void, *mut NV_ENC_MEONLY_PARAMS) -> NVENCSTATUS;
type GetLastErrorString = unsafe extern "C" fn(encoder: *mut c_void) -> *const ::core::ffi::c_char;
type SetIOCudaStreams =
    unsafe extern "C" fn(*mut c_void, NV_ENC_CUSTREAM_PTR, NV_ENC_CUSTREAM_PTR) -> NVENCSTATUS;
type GetSequenceParamEx = unsafe extern "C" fn(
    *mut c_void,
    *mut NV_ENC_INITIALIZE_PARAMS,
    *mut NV_ENC_SEQUENCE_PARAM_PAYLOAD,
) -> NVENCSTATUS;
type RestoreEncoderState =
    unsafe extern "C" fn(*mut c_void, *mut NV_ENC_RESTORE_ENCODER_STATE_PARAMS) -> NVENCSTATUS;
type LookaheadPicture =
    unsafe extern "C" fn(*mut c_void, *mut NV_ENC_LOOKAHEAD_PIC_PARAMS) -> NVENCSTATUS;

/// An instance of the `NvEncodeAPI` interface, containing function pointers
/// which should be used to interface with the rest of the Encoder API.
#[allow(dead_code, missing_docs)]
#[derive(Debug, Clone)]
pub struct EncodeAPI {
    #[doc(alias = "NvEncOpenEncodeSession")]
    pub open_encode_session: OpenEncodeSession,
    #[doc(alias = "NvEncOpenEncodeSessionEx")]
    pub open_encode_session_ex: OpenEncodeSessionEx,
    #[doc(alias = "NvEncInitializeEncoder")]
    pub initialize_encoder: InitializeEncoder,
    #[doc(alias = "NvEncReconfigureEncoder")]
    pub reconfigure_encoder: ReconfigureEncoder,
    #[doc(alias = "NvEncDestroyEncoder")]
    pub destroy_encoder: DestroyEncoder,
    #[doc(alias = "NvEncGetEncodeGuidCount")]
    pub get_encode_guid_count: GetEncodeGUIDCount,
    #[doc(alias = "NvEncGetEncodeGUIDs")]
    pub get_encode_guids: GetEncodeGUIDs,
    #[doc(alias = "NvEncGetEncodeProfileGuidCount")]
    pub get_encode_profile_guid_count: GetEncodeProfileGUIDCount,
    #[doc(alias = "NvEncGetEncodeProfileGUIDs")]
    pub get_encode_profile_guids: GetEncodeProfileGUIDs,
    #[doc(alias = "NvEncGetInputFormatCount")]
    pub get_input_format_count: GetInputFormatCount,
    #[doc(alias = "NvEncGetInputFormats")]
    pub get_input_formats: GetInputFormats,
    #[doc(alias = "NvEncGetEncodePresetCount")]
    pub get_encode_preset_count: GetEncodePresetCount,
    #[doc(alias = "NvEncGetEncodePresetGUIDs")]
    pub get_encode_preset_guids: GetEncodePresetGUIDs,
    #[doc(alias = "NvEncGetEncodePresetConfig")]
    pub get_encode_preset_config: GetEncodePresetConfig,
    #[doc(alias = "NvEncGetEncodePresetConfigEx")]
    pub get_encode_preset_config_ex: GetEncodePresetConfigEx,
    #[doc(alias = "NvEncGetEncodeCaps")]
    pub get_encode_caps: GetEncodeCaps,
    #[doc(alias = "NvEncCreateInputBuffer")]
    pub create_input_buffer: CreateInputBuffer,
    #[doc(alias = "NvEncDestroyInputBuffer")]
    pub destroy_input_buffer: DestroyInputBuffer,
    #[doc(alias = "NvLockInputBuffer")]
    pub lock_input_buffer: LockInputBuffer,
    #[doc(alias = "NvUnlockInputBuffer")]
    pub unlock_input_buffer: UnlockInputBuffer,
    #[doc(alias = "NvEncCreateBitstreamBuffer")]
    pub create_bitstream_buffer: CreateBitstreamBuffer,
    #[doc(alias = "NvEncDestroyBitstreamBuffer")]
    pub destroy_bitstream_buffer: DestroyBitstreamBuffer,
    #[doc(alias = "NvEncLockBitstream")]
    pub lock_bitstream: LockBitstream,
    #[doc(alias = "NvEncUnlockBitstream")]
    pub unlock_bitstream: UnlockBitstream,
    #[doc(alias = "NvEncMapInputResource")]
    pub map_input_resource: MapInputResource,
    #[doc(alias = "NvEncUnmapInputResource")]
    pub unmap_input_resource: UnmapInputResource,
    #[doc(alias = "NvEncRegisterResource")]
    pub register_resource: RegisterResource,
    #[doc(alias = "NvEncUnregisterResource")]
    pub unregister_resource: UnregisterResource,
    #[doc(alias = "NvEncCreateMVBuffer")]
    pub create_mv_buffer: CreateMVBuffer,
    #[doc(alias = "NvEncDestroyMVBuffer")]
    pub destroy_mv_buffer: DestroyMVBuffer,
    #[doc(alias = "NvEncEncodePicture")]
    pub encode_picture: EncodePicture,
    #[doc(alias = "NvEncGetEncodeStats")]
    pub get_encode_stats: GetEncodeStats,
    #[doc(alias = "NvEncGetSequenceParams")]
    pub get_sequence_params: GetSequenceParams,
    #[doc(alias = "NvEncGetSequenceParamEx")]
    pub get_sequence_param_ex: GetSequenceParamEx,
    #[doc(alias = "NvEncRegisterAsyncEvent")]
    pub register_async_event: RegisterAsyncEvent,
    #[doc(alias = "NvEncUnregisterAsyncEvent")]
    pub unregister_async_event: UnregisterAsyncEvent,
    #[doc(alias = "NvEncInvalidateRefFrames")]
    pub invalidate_ref_frames: InvalidateRefFrames,
    #[doc(alias = "NvEncRunMotionEstimationOnly")]
    pub run_motion_estimation_only: RunMotionEstimationOnly,
    #[doc(alias = "NvEncGetLastErrorString")]
    pub get_last_error_string: GetLastErrorString,
    #[doc(alias = "NvEncSetIOCudaStreams")]
    pub set_io_cuda_streams: SetIOCudaStreams,
    #[doc(alias = "NvEncRestoreEncoderState")]
    pub restore_encoder_state: RestoreEncoderState,
    #[doc(alias = "NvEncLookaheadPicture")]
    pub lookahead_picture: LookaheadPicture,
}

fn assert_versions_match(max_supported_version: u32) {
    let major_version = max_supported_version >> 4;
    let minor_version = max_supported_version & 0b1111;
    assert!(
        (major_version, minor_version) >= (NVENCAPI_MAJOR_VERSION, NVENCAPI_MINOR_VERSION),
        "The maximum supported version should be greater or equal than the header version."
    );
}

impl EncodeAPI {
    fn new() -> Self {
        const MSG: &str = "The API instance should populate the whole function list.";

        // Check that the driver max supported version matches the version
        // from the header files. If they do not match, the bindings should be updated.
        let mut version = 0;
        unsafe { NvEncodeAPIGetMaxSupportedVersion(&mut version) }
            .result_without_string()
            .expect("The pointer to the version should be valid.");
        assert_versions_match(version);

        // Create empty function buffer.
        let mut function_list = NV_ENCODE_API_FUNCTION_LIST {
            version: NV_ENCODE_API_FUNCTION_LIST_VER,
            ..Default::default()
        };
        // Create Encode API Instance (populate function buffer).
        unsafe { NvEncodeAPICreateInstance(&mut function_list) }
            .result_without_string()
            .expect("The pointer to the function list should be valid.");

        Self {
            open_encode_session: function_list.nvEncOpenEncodeSession.expect(MSG),
            open_encode_session_ex: function_list.nvEncOpenEncodeSessionEx.expect(MSG),
            initialize_encoder: function_list.nvEncInitializeEncoder.expect(MSG),
            reconfigure_encoder: function_list.nvEncReconfigureEncoder.expect(MSG),
            destroy_encoder: function_list.nvEncDestroyEncoder.expect(MSG),
            get_encode_guid_count: function_list.nvEncGetEncodeGUIDCount.expect(MSG),
            get_encode_guids: function_list.nvEncGetEncodeGUIDs.expect(MSG),
            get_encode_profile_guid_count: function_list.nvEncGetEncodeProfileGUIDCount.expect(MSG),
            get_encode_profile_guids: function_list.nvEncGetEncodeProfileGUIDs.expect(MSG),
            get_input_format_count: function_list.nvEncGetInputFormatCount.expect(MSG),
            get_input_formats: function_list.nvEncGetInputFormats.expect(MSG),
            get_encode_preset_count: function_list.nvEncGetEncodePresetCount.expect(MSG),
            get_encode_preset_guids: function_list.nvEncGetEncodePresetGUIDs.expect(MSG),
            get_encode_preset_config: function_list.nvEncGetEncodePresetConfig.expect(MSG),
            get_encode_preset_config_ex: function_list.nvEncGetEncodePresetConfigEx.expect(MSG),
            get_encode_caps: function_list.nvEncGetEncodeCaps.expect(MSG),
            create_input_buffer: function_list.nvEncCreateInputBuffer.expect(MSG),
            destroy_input_buffer: function_list.nvEncDestroyInputBuffer.expect(MSG),
            lock_input_buffer: function_list.nvEncLockInputBuffer.expect(MSG),
            unlock_input_buffer: function_list.nvEncUnlockInputBuffer.expect(MSG),
            create_bitstream_buffer: function_list.nvEncCreateBitstreamBuffer.expect(MSG),
            destroy_bitstream_buffer: function_list.nvEncDestroyBitstreamBuffer.expect(MSG),
            lock_bitstream: function_list.nvEncLockBitstream.expect(MSG),
            unlock_bitstream: function_list.nvEncUnlockBitstream.expect(MSG),
            map_input_resource: function_list.nvEncMapInputResource.expect(MSG),
            unmap_input_resource: function_list.nvEncUnmapInputResource.expect(MSG),
            register_resource: function_list.nvEncRegisterResource.expect(MSG),
            unregister_resource: function_list.nvEncUnregisterResource.expect(MSG),
            create_mv_buffer: function_list.nvEncCreateMVBuffer.expect(MSG),
            destroy_mv_buffer: function_list.nvEncDestroyMVBuffer.expect(MSG),
            encode_picture: function_list.nvEncEncodePicture.expect(MSG),
            get_encode_stats: function_list.nvEncGetEncodeStats.expect(MSG),
            get_sequence_params: function_list.nvEncGetSequenceParams.expect(MSG),
            get_sequence_param_ex: function_list.nvEncGetSequenceParamEx.expect(MSG),
            register_async_event: function_list.nvEncRegisterAsyncEvent.expect(MSG),
            unregister_async_event: function_list.nvEncUnregisterAsyncEvent.expect(MSG),
            invalidate_ref_frames: function_list.nvEncInvalidateRefFrames.expect(MSG),
            run_motion_estimation_only: function_list.nvEncRunMotionEstimationOnly.expect(MSG),
            get_last_error_string: function_list.nvEncGetLastErrorString.expect(MSG),
            set_io_cuda_streams: function_list.nvEncSetIOCudaStreams.expect(MSG),
            restore_encoder_state: function_list.nvEncRestoreEncoderState.expect(MSG),
            lookahead_picture: function_list.nvEncLookaheadPicture.expect(MSG),
        }
    }
}