PyNvVideoCodec 2.0.0__cp312-cp312-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. PyNvVideoCodec/PyNvVideoCodec_121.cp312-win_amd64.pyd +0 -0
  2. PyNvVideoCodec/PyNvVideoCodec_130.cp312-win_amd64.pyd +0 -0
  3. PyNvVideoCodec/VersionCheck.cp312-win_amd64.pyd +0 -0
  4. PyNvVideoCodec/__init__.py +237 -0
  5. PyNvVideoCodec/avcodec-58.dll +0 -0
  6. PyNvVideoCodec/avcodec-61.dll +0 -0
  7. PyNvVideoCodec/avcodec.dll +0 -0
  8. PyNvVideoCodec/avdevice-58.dll +0 -0
  9. PyNvVideoCodec/avdevice-61.dll +0 -0
  10. PyNvVideoCodec/avdevice.dll +0 -0
  11. PyNvVideoCodec/avfilter-10.dll +0 -0
  12. PyNvVideoCodec/avfilter-7.dll +0 -0
  13. PyNvVideoCodec/avfilter.dll +0 -0
  14. PyNvVideoCodec/avformat-58.dll +0 -0
  15. PyNvVideoCodec/avformat-61.dll +0 -0
  16. PyNvVideoCodec/avformat.dll +0 -0
  17. PyNvVideoCodec/avutil-56.dll +0 -0
  18. PyNvVideoCodec/avutil-59.dll +0 -0
  19. PyNvVideoCodec/avutil.dll +0 -0
  20. PyNvVideoCodec/decoders/SimpleDecoder.py +225 -0
  21. PyNvVideoCodec/decoders/ThreadedDecoder.py +119 -0
  22. PyNvVideoCodec/decoders/__init__.py +22 -0
  23. PyNvVideoCodec/swresample-3.dll +0 -0
  24. PyNvVideoCodec/swresample-5.dll +0 -0
  25. PyNvVideoCodec/swresample.dll +0 -0
  26. PyNvVideoCodec/swscale-5.dll +0 -0
  27. PyNvVideoCodec/swscale-8.dll +0 -0
  28. PyNvVideoCodec/swscale.dll +0 -0
  29. PyNvVideoCodec/transcoder/Transcoder.py +55 -0
  30. PyNvVideoCodec/transcoder/__init__.py +22 -0
  31. PyNvVideoCodec-2.0.0.data/data/external/ffmpeg/readme.txt +10 -0
  32. PyNvVideoCodec-2.0.0.data/data/external/ffmpeg/src/ffmpeg-7.0.2.tar.xz +0 -0
  33. PyNvVideoCodec-2.0.0.dist-info/METADATA +77 -0
  34. PyNvVideoCodec-2.0.0.dist-info/RECORD +64 -0
  35. PyNvVideoCodec-2.0.0.dist-info/WHEEL +5 -0
  36. PyNvVideoCodec-2.0.0.dist-info/licenses/LICENSE.txt +22 -0
  37. PyNvVideoCodec-2.0.0.dist-info/licenses/NOTICES.txt +167 -0
  38. PyNvVideoCodec-2.0.0.dist-info/top_level.txt +3 -0
  39. benchmarks/cached_decoder_benchmark.py +635 -0
  40. benchmarks/frame_sampling_benchmark.py +610 -0
  41. benchmarks/segmented_transcode_benchmark.py +1072 -0
  42. samples/Decode.py +194 -0
  43. samples/DecodeMultiprocessing.py +162 -0
  44. samples/DecodePerf.py +215 -0
  45. samples/DecodeSEIMsgExtraction.py +338 -0
  46. samples/DemuxFromByteArray.py +185 -0
  47. samples/Encode.py +189 -0
  48. samples/EncodeFromCPUBuffer.py +220 -0
  49. samples/EncodeMultiprocessing.py +268 -0
  50. samples/EncodePerf.py +380 -0
  51. samples/EncodeReconfigure.py +201 -0
  52. samples/EncodeSEIMsgInsertion.py +189 -0
  53. samples/ObjectDetection.py +218 -0
  54. samples/SimpleDecoder/EnsembleApp.py +416 -0
  55. samples/SimpleDecoder/SubsamplingAndReconfigure.py +341 -0
  56. samples/SimpleDecoder/fileLists.txt +4 -0
  57. samples/SimpleDecoder/segments.txt +3 -0
  58. samples/SimpleDecoder/timeListInSeconds.txt +5 -0
  59. samples/SimpleDecoder/transcode_config.json +6 -0
  60. samples/Utils.py +290 -0
  61. samples/coco_classes.pickle +0 -0
  62. samples/encode_config.json +16 -0
  63. samples/encode_config_lowlatency.json +11 -0
  64. samples/encode_config_perf.json +9 -0
samples/EncodePerf.py ADDED
@@ -0,0 +1,380 @@
1
+ # This copyright notice applies to this file only
2
+ #
3
+ # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4
+ # SPDX-License-Identifier: MIT
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a
7
+ # copy of this software and associated documentation files (the "Software"),
8
+ # to deal in the Software without restriction, including without limitation
9
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ # and/or sell copies of the Software, and to permit persons to whom the
11
+ # Software is furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
+ # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
+ # DEALINGS IN THE SOFTWARE.
23
+
24
+ import argparse
25
+ from pathlib import Path
26
+ import pycuda.driver as cuda
27
+ import PyNvVideoCodec as nvc
28
+ import time
29
+ import mmap
30
+ import json
31
+ import threading
32
+ import numpy as np
33
+ import gc
34
+ import sys
35
+ import atexit
36
+ import os
37
+ from os.path import join, dirname, abspath
38
+ from Utils import AppFramePerf
39
+
40
+ # Add the parent directory to Python path in a way that works from any working directory
41
+ current_dir = dirname(abspath(__file__))
42
+ parent_dir = dirname(current_dir)
43
+ if parent_dir not in sys.path:
44
+ sys.path.append(parent_dir)
45
+
46
+
47
+ # Global variables for tracking performance
48
+ total_frames = 0
49
+
50
+ # Global variables to track resources for cleanup
51
+ g_devicedata = None
52
+ g_mmap = None
53
+ g_context = None
54
+
55
+
56
+ def cleanup_resources():
57
+ """
58
+ Clean up global resources including memory map, GPU memory, and CUDA context.
59
+
60
+ This function is registered with atexit to ensure proper cleanup of resources
61
+ when the program exits.
62
+ """
63
+ global g_devicedata, g_mmap, g_context
64
+
65
+ # Force garbage collection first
66
+ gc.collect()
67
+
68
+ # Close memory map
69
+ if g_mmap:
70
+ try:
71
+ g_mmap.close()
72
+ g_mmap = None
73
+ except:
74
+ pass
75
+
76
+ # Free GPU memory
77
+ if g_devicedata:
78
+ try:
79
+ g_devicedata.free()
80
+ g_devicedata = None
81
+ except:
82
+ pass
83
+
84
+ # Clean up CUDA context
85
+ if g_context:
86
+ try:
87
+ g_context.detach()
88
+ g_context = None
89
+ except:
90
+ pass
91
+
92
+
93
+ # Register the cleanup function to run at exit
94
+ atexit.register(cleanup_resources)
95
+
96
+
97
+ def encode(thread_id, dec_file_path, encoder, devicedata, framesize, width, height, fmt, frame_count=1000):
98
+ """
99
+ Thread function that encodes frames and updates the global counter.
100
+
101
+ Parameters:
102
+ thread_id (int): ID of the thread
103
+ dec_file_path (str): Path to the input file
104
+ encoder: NVENC encoder instance
105
+ devicedata: CUDA device memory handle
106
+ framesize (int): Size of each frame in bytes
107
+ width (int): Width of the frame
108
+ height (int): Height of the frame
109
+ fmt (str): Surface format string in uppercase (e.g., "NV12")
110
+ frame_count (int, optional): Number of frames to encode. If None, 0, or negative, encode all frames from input.
111
+ """
112
+ global total_frames
113
+
114
+ try:
115
+ print(f"Starting encode thread {thread_id}")
116
+
117
+ # Calculate total available frames from file size
118
+ file_size = os.path.getsize(dec_file_path)
119
+ available_frames = file_size // framesize
120
+
121
+ if frame_count is None or frame_count == 0:
122
+ print(f"Thread {thread_id} will process all available frames")
123
+ frame_count = available_frames
124
+ elif frame_count < 0 or frame_count > available_frames:
125
+ print(f"Warning: Invalid frame count {frame_count}. Thread {thread_id} will process all available frames.")
126
+ frame_count = available_frames
127
+
128
+ # Encode frames
129
+ for i in range(frame_count):
130
+ # Create a new frame object for each frame
131
+ input_gpu_frame = AppFramePerf(width, height, fmt, devicedata, i)
132
+
133
+ # Encode the frame
134
+ encoder.Encode(input_gpu_frame)
135
+
136
+ # Flush encoder
137
+ encoder.EndEncode()
138
+
139
+ print(f"Thread {thread_id} encoded {frame_count} frames")
140
+
141
+ # Update global counter
142
+ with threading.Lock():
143
+ total_frames += frame_count
144
+
145
+ except Exception as e:
146
+ print(f"Thread {thread_id}: An unexpected error occurred: {e}")
147
+
148
+
149
+ def GetFrameSize(width, height, surface_format):
150
+ """
151
+ Calculate the size of a frame in bytes based on its dimensions and format.
152
+
153
+ Parameters:
154
+ width (int): Width of the frame
155
+ height (int): Height of the frame
156
+ surface_format (str): Format of the surface (e.g., "NV12", "ARGB", "YUV444")
157
+
158
+ Returns:
159
+ int: Size of the frame in bytes
160
+ """
161
+ if surface_format in ("ARGB", "ABGR"):
162
+ return width * height * 4
163
+ elif surface_format == "YUV444":
164
+ return width * height * 3
165
+ elif surface_format == "YUV420":
166
+ return int(width * height * 3 / 2)
167
+ elif surface_format == "P010":
168
+ return int(width * height * 3 / 2 * 2)
169
+ elif surface_format == "YUV444_16BIT":
170
+ return int(width * height * 3 * 2)
171
+ elif surface_format == "NV16":
172
+ return width * height * 2
173
+ elif surface_format == "P210":
174
+ return width * height * 2 * 2
175
+ else:
176
+ return int(width * height * 3 / 2)
177
+
178
+
179
+ def run_parallel_encode(num_threads, gpu_id, dec_file_path, width, height, fmt, config_params, frame_count):
180
+ """
181
+ Run encoding test with multiple threads.
182
+
183
+ Parameters:
184
+ num_threads (int): Number of parallel threads to use
185
+ gpu_id (int): Ordinal of GPU to use
186
+ dec_file_path (str): Path to the input file
187
+ width (int): Width of the frame
188
+ height (int): Height of the frame
189
+ fmt (str): Surface format string in uppercase (e.g., "NV12")
190
+ config_params (dict): Key-value pairs providing fine-grained control on encoding
191
+ frame_count (int): Number of frames to encode. If 0, encodes all frames from input.
192
+
193
+ Returns:
194
+ None: Prints performance metrics to console
195
+ """
196
+ print(f"Initializing {num_threads} encode threads")
197
+ global g_devicedata, g_mmap, g_context, total_frames
198
+
199
+ # Reset global counter
200
+ total_frames = 0
201
+
202
+ g_context = None
203
+ try:
204
+ # Initialize CUDA
205
+ cuda.init()
206
+ cuda_device = cuda.Device(gpu_id)
207
+
208
+ # Create a CUDA context
209
+ g_context = cuda_device.make_context()
210
+
211
+ # Create a CUDA stream
212
+ shared_stream = cuda.Stream()
213
+ # Open input file and prepare data
214
+ with open(dec_file_path, "rb") as dec_file:
215
+ # Calculate frame size based on format
216
+ framesize = GetFrameSize(width, height, fmt)
217
+
218
+ # Read data into memory and copy to GPU
219
+ if sys.platform == 'win32':
220
+ g_mmap = mmap.mmap(dec_file.fileno(), 0, access=mmap.ACCESS_READ)
221
+ else:
222
+ g_mmap = mmap.mmap(dec_file.fileno(), 0, prot=mmap.PROT_READ)
223
+ hostdata = g_mmap.read(g_mmap.size())
224
+ g_devicedata = cuda.mem_alloc(g_mmap.size())
225
+ cuda.memcpy_htod(g_devicedata, hostdata)
226
+
227
+ # Create encoders for all threads
228
+ encoders = []
229
+ for i in range(num_threads):
230
+ # Create a copy of config_params for each encoder
231
+ config_copy = config_params.copy()
232
+ config_copy["gpu_id"] = gpu_id
233
+ # Create encoder
234
+ encoder = nvc.CreateEncoder(
235
+ width, height, fmt, False,
236
+ cudacontext=g_context.handle,
237
+ cudastream=shared_stream.handle,
238
+ **config_copy
239
+ )
240
+ encoders.append(encoder)
241
+
242
+ # Start timing before encoding
243
+ begin = time.perf_counter()
244
+
245
+ # Create and start threads
246
+ threads = []
247
+ for i in range(num_threads):
248
+ t = threading.Thread(
249
+ target=encode,
250
+ args=(
251
+ i,
252
+ dec_file_path,
253
+ encoders[i],
254
+ g_devicedata,
255
+ framesize,
256
+ width,
257
+ height,
258
+ fmt,
259
+ frame_count
260
+ )
261
+ )
262
+ threads.append(t)
263
+ t.start()
264
+
265
+ # Wait for all threads to complete
266
+ for t in threads:
267
+ t.join()
268
+
269
+ # Stop timing after all threads complete
270
+ end = time.perf_counter()
271
+
272
+ duration = end - begin # Time in seconds
273
+
274
+ # Print summary
275
+ print("\n--- Performance Summary ---")
276
+ print(f"Number of threads: {num_threads}")
277
+ print(f"Total frames encoded: {total_frames}")
278
+ if duration > 0:
279
+ fps = total_frames / duration
280
+ print(f"Duration: {duration:.2f} seconds")
281
+ print(f"Total FPS: {fps:.2f}")
282
+ print(f"Average FPS per thread: {fps / num_threads:.2f}")
283
+
284
+ # Clear encoder references
285
+ for encoder in encoders:
286
+ del encoder
287
+ encoders.clear()
288
+
289
+ except Exception as e:
290
+ print(f"An error occurred: {e}")
291
+
292
+ finally:
293
+ # Pop the context
294
+ if g_context is not None:
295
+ g_context.pop()
296
+
297
+
298
+ if __name__ == "__main__":
299
+ parser = argparse.ArgumentParser(
300
+ description="This sample application measures encoding performance in FPS with multiple threads."
301
+ )
302
+
303
+ parser.add_argument(
304
+ "-g", "--gpu_id",
305
+ type=int,
306
+ default=0,
307
+ help="Check nvidia-smi for available GPUs. Default: 0"
308
+ )
309
+ parser.add_argument(
310
+ "-i", "--raw_file_path",
311
+ type=Path,
312
+ required=True,
313
+ help="Raw video file (read from)"
314
+ )
315
+ parser.add_argument(
316
+ "-s", "--size",
317
+ type=str,
318
+ required=True,
319
+ help="WidthxHeight of raw frame (e.g., 1920x1080)"
320
+ )
321
+ parser.add_argument(
322
+ "-if", "--format",
323
+ type=str,
324
+ default="NV12",
325
+ help="Format of input file. Default is NV12"
326
+ )
327
+ parser.add_argument(
328
+ "-c", "--codec",
329
+ type=str,
330
+ help="Video codec (HEVC, H264, AV1). If not specified, uses the codec from config file."
331
+ )
332
+ parser.add_argument(
333
+ "-json", "--config_file",
334
+ type=str,
335
+ default=join(dirname(__file__), "encode_config_perf.json"),
336
+ help="Path of JSON config file (default: encode_config_perf.json in the same directory)"
337
+ )
338
+ parser.add_argument(
339
+ "-n", "--num_threads",
340
+ type=int,
341
+ default=1,
342
+ help="Number of parallel threads. Default is 1"
343
+ )
344
+ parser.add_argument(
345
+ "-f", "--frame_count",
346
+ type=int,
347
+ default=0,
348
+ help="Number of frames to encode (0 for all frames). Default is 0."
349
+ )
350
+
351
+ args = parser.parse_args()
352
+ config = {}
353
+
354
+ if args.config_file:
355
+ with open(args.config_file) as jsonFile:
356
+ config = json.loads(jsonFile.read())
357
+ config["preset"] = config["preset"].upper()
358
+
359
+ # Only set codec from command line if it was explicitly provided
360
+ if args.codec is not None:
361
+ args.codec = args.codec.lower()
362
+ config["codec"] = args.codec
363
+
364
+ args.format = args.format.upper()
365
+ width, height = map(int, args.size.split("x"))
366
+
367
+ try:
368
+ run_parallel_encode(
369
+ args.num_threads,
370
+ args.gpu_id,
371
+ args.raw_file_path.as_posix(),
372
+ width,
373
+ height,
374
+ args.format,
375
+ config,
376
+ args.frame_count
377
+ )
378
+ finally:
379
+ # Force cleanup before exit
380
+ cleanup_resources()
@@ -0,0 +1,201 @@
1
+ # This copyright notice applies to this file only
2
+ #
3
+ # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4
+ # SPDX-License-Identifier: MIT
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a
7
+ # copy of this software and associated documentation files (the "Software"),
8
+ # to deal in the Software without restriction, including without limitation
9
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ # and/or sell copies of the Software, and to permit persons to whom the
11
+ # Software is furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
+ # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
+ # DEALINGS IN THE SOFTWARE.
23
+
24
+ import PyNvVideoCodec as nvc
25
+ import numpy as np
26
+ import json
27
+ import argparse
28
+ from pathlib import Path
29
+ import sys
30
+ import os
31
+ from os.path import join, dirname, abspath
32
+
33
+ # Add the parent directory to Python path in a way that works from any working directory
34
+ current_dir = dirname(abspath(__file__))
35
+ parent_dir = dirname(current_dir)
36
+ if parent_dir not in sys.path:
37
+ sys.path.append(parent_dir)
38
+
39
+ from Utils import AppFrame
40
+ from Utils import FetchCPUFrame
41
+ from Utils import FetchGPUFrame
42
+
43
+
44
+ # Constants
45
+ TOTAL_NUM_FRAMES = 1000
46
+ BITRATE_CHANGE_INTERVAL = 100
47
+ BITRATE_REDUCTION_FACTOR = 2
48
+
49
+
50
+ def encode(gpu_id, dec_file_path, enc_file_path, width, height, fmt, config_params):
51
+ """
52
+ Encode video with dynamic bitrate reconfiguration.
53
+
54
+ This function demonstrates bitrate change at runtime without the need to reset the encoder session.
55
+ The application reduces the bitrate by half and then restores it to the original value after
56
+ every 100 frames.
57
+
58
+ Parameters:
59
+ gpu_id (int): Ordinal of GPU to use [Parameter not in use]
60
+ dec_file_path (str): Path to file to be decoded
61
+ enc_file_path (str): Path to output file for encoded frames
62
+ width (int): Width of encoded frame
63
+ height (int): Height of encoded frame
64
+ fmt (str): Surface format string in uppercase (e.g., "NV12")
65
+ config_params (dict): Key-value pairs providing fine-grained control on encoding
66
+
67
+ Returns:
68
+ None
69
+
70
+ Example:
71
+ >>> encode(0, "input.yuv", "output.h264", 1920, 1080, "NV12", {"codec": "h264"})
72
+ Encode 1080p NV12 raw YUV into elementary bitstream using H.264 codec
73
+ """
74
+ try:
75
+ with open(dec_file_path, "rb") as decFile, open(enc_file_path, "wb") as encFile:
76
+ # Create encoder object
77
+ config_params["gpu_id"] = gpu_id
78
+ nvenc = nvc.CreateEncoder(width, height, fmt, False, **config_params)
79
+
80
+ # Create input frame list
81
+ input_frame_list = [AppFrame(width, height, fmt) for _ in range(1, 5)]
82
+
83
+ # Get initial encoder parameters
84
+ reconf_params = nvenc.GetEncodeReconfigureParams()
85
+ original_avgbitrate = reconf_params.averageBitrate
86
+ original_vbvbuffersize = int(original_avgbitrate * reconf_params.frameRateDen / reconf_params.frameRateNum)
87
+ original_vbvinitdelay = original_vbvbuffersize
88
+
89
+ # Process frames
90
+ for i, input_gpu_frame in enumerate(
91
+ FetchGPUFrame(
92
+ input_frame_list,
93
+ FetchCPUFrame(decFile, input_frame_list[0].frameSize),
94
+ TOTAL_NUM_FRAMES
95
+ )
96
+ ):
97
+ # Reconfigure bitrate every 100 frames
98
+ if i % BITRATE_CHANGE_INTERVAL == 0:
99
+ if i % (BITRATE_CHANGE_INTERVAL * 2) != 0:
100
+ # Reduce bitrate by half
101
+ reconf_params.averageBitrate = int(original_avgbitrate / BITRATE_REDUCTION_FACTOR)
102
+ reconf_params.vbvBufferSize = int(
103
+ reconf_params.averageBitrate * reconf_params.frameRateDen / reconf_params.frameRateNum
104
+ )
105
+ reconf_params.vbvInitialDelay = reconf_params.vbvBufferSize
106
+ else:
107
+ # Restore original bitrate
108
+ reconf_params.averageBitrate = original_avgbitrate
109
+ reconf_params.vbvBufferSize = original_vbvbuffersize
110
+ reconf_params.vbvInitialDelay = original_vbvinitdelay
111
+
112
+ nvenc.Reconfigure(reconf_params)
113
+
114
+ # Encode frame
115
+ bitstream = nvenc.Encode(input_gpu_frame)
116
+ encFile.write(bytearray(bitstream))
117
+
118
+ # Flush encoder queue
119
+ bitstream = nvenc.EndEncode()
120
+ encFile.write(bytearray(bitstream))
121
+
122
+ except nvc.PyNvVCExceptionUnsupported as e:
123
+ print(f"CreateEncoder failure: {e}")
124
+ except Exception as e:
125
+ print(f"An unexpected error occurred: {e}")
126
+
127
+
128
+ if __name__ == "__main__":
129
+ parser = argparse.ArgumentParser(
130
+ description="This sample application demonstrates bitrate change at runtime without resetting the encoder session."
131
+ )
132
+
133
+ parser.add_argument(
134
+ "-g", "--gpu_id",
135
+ type=int,
136
+ default=0,
137
+ help="Check nvidia-smi for available GPUs. Default: 0"
138
+ )
139
+ parser.add_argument(
140
+ "-i", "--raw_file_path",
141
+ type=Path,
142
+ required=True,
143
+ help="Raw video file (read from)"
144
+ )
145
+ parser.add_argument(
146
+ "-o", "--encoded_file_path",
147
+ type=Path,
148
+ help="Encoded video file (write to). Default: <input_file_name>.<codec>"
149
+ )
150
+ parser.add_argument(
151
+ "-s", "--size",
152
+ type=str,
153
+ required=True,
154
+ help="WidthxHeight of raw frame (e.g., 1920x1080)"
155
+ )
156
+ parser.add_argument(
157
+ "-if", "--format",
158
+ type=str,
159
+ default="NV12",
160
+ help="Format of input file. Default is NV12"
161
+ )
162
+ parser.add_argument(
163
+ "-c", "--codec",
164
+ type=str,
165
+ default="H264",
166
+ help="Video codec (HEVC, H264, AV1). Default is H264"
167
+ )
168
+ parser.add_argument(
169
+ "-json", "--config_file",
170
+ type=str,
171
+ default=join(dirname(__file__), "encode_config_perf.json"),
172
+ help="Path of JSON config file (default: encode_config_perf.json in the same directory)"
173
+ )
174
+
175
+ args = parser.parse_args()
176
+ config = {}
177
+
178
+ # Set default encoded_file_path if not provided
179
+ if args.encoded_file_path is None:
180
+ input_path = Path(args.raw_file_path)
181
+ args.encoded_file_path = input_path.with_suffix(f'.{args.codec.lower()}')
182
+
183
+ if args.config_file:
184
+ with open(args.config_file) as jsonFile:
185
+ config = json.loads(jsonFile.read())
186
+ config["preset"] = config["preset"].upper()
187
+
188
+ args.codec = args.codec.lower()
189
+ args.format = args.format.upper()
190
+ config["codec"] = args.codec
191
+ width, height = map(int, args.size.split("x"))
192
+
193
+ encode(
194
+ args.gpu_id,
195
+ args.raw_file_path.as_posix(),
196
+ args.encoded_file_path.as_posix(),
197
+ width,
198
+ height,
199
+ args.format,
200
+ config
201
+ )