PyNvVideoCodec 2.0.0__cp313-cp313-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.cp313-win_amd64.pyd +0 -0
  2. PyNvVideoCodec/PyNvVideoCodec_130.cp313-win_amd64.pyd +0 -0
  3. PyNvVideoCodec/VersionCheck.cp313-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
@@ -0,0 +1,416 @@
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 necessary libraries
25
+ import argparse
26
+ import json
27
+ from pathlib import Path
28
+ import PyNvVideoCodec as nvc
29
+ import numpy as np
30
+ import pycuda.driver as cuda
31
+ from pathlib import Path
32
+ from pycuda.autoinit import context
33
+ import sys
34
+ import os
35
+ from os.path import join, dirname, abspath
36
+
37
+ # Add the parent directory to Python path in a way that works from any working directory
38
+ current_dir = dirname(abspath(__file__))
39
+ parent_dir = dirname(current_dir)
40
+ if parent_dir not in sys.path:
41
+ sys.path.append(parent_dir)
42
+
43
+ from Utils import cast_address_to_1d_bytearray
44
+
45
+
46
+ def frame_to_yuv(frames, use_device_memory):
47
+ """
48
+ Converts frames to YUV format with option for device or host memory processing.
49
+
50
+ Args:
51
+ frames: List of frames to convert
52
+ use_device_memory: Boolean flag to determine memory processing location
53
+ simple_decoder: Decoder object
54
+
55
+ Returns:
56
+ frames_in_yuv: List of YUV frames as bytearrays
57
+ """
58
+ frames_in_yuv = []
59
+ for frame in frames:
60
+ raw_frame = np.ndarray(shape=frame.framesize(), dtype=np.uint8)
61
+ luma_base_addr = frame.GetPtrToPlane(0)
62
+ if use_device_memory == True:
63
+ cuda.memcpy_dtoh(raw_frame, luma_base_addr)
64
+ else:
65
+ raw_frame = cast_address_to_1d_bytearray(base_address=luma_base_addr, size=frame.framesize())
66
+ bits = bytearray(raw_frame)
67
+ frames_in_yuv.append(bits)
68
+
69
+ return frames_in_yuv
70
+
71
+
72
+
73
+ def save_frames_in_yuv(dec_file_path, frames, use_device_memory):
74
+ """
75
+ Saves the frames in a YUV file.
76
+
77
+ Args:
78
+ dec_file_path(str): YUV file path.
79
+ frames(List[DecodedFrame]): List of frames to convert
80
+ use_device_memory(bool): Boolean flag to determine memory processing location
81
+
82
+ """
83
+ with open(dec_file_path, "ab") as decFile:
84
+ for frame in frames:
85
+ decoded_frame_size = frame.framesize()
86
+ raw_frame = np.ndarray(shape=decoded_frame_size, dtype=np.uint8)
87
+ luma_base_addr = frame.GetPtrToPlane(0)
88
+ if use_device_memory:
89
+ cuda.memcpy_dtoh(raw_frame, luma_base_addr)
90
+ bits = bytearray(raw_frame)
91
+ decFile.write(bits)
92
+ else:
93
+ new_array = cast_address_to_1d_bytearray(base_address=luma_base_addr, size=decoded_frame_size)
94
+ decFile.write(bytearray(new_array))
95
+
96
+
97
+ def perform_batch_comparison(input_file_path, use_device_memory, gpu_id):
98
+ """Compares sequential vs index-based batch frame retrieval methods."""
99
+ batch_size = 5
100
+ output_color_type = nvc.OutputColorType.NATIVE
101
+ print("1. Comparing batch frames retrieval methods:")
102
+ print(f"Method 1: Sequential batch (size={batch_size})")
103
+ print(f"Method 2: Index-based batch (indices=[0,1,2,3,4])\n")
104
+
105
+ simple_decoder = nvc.SimpleDecoder(input_file_path, need_scanned_stream_metadata=False,
106
+ use_device_memory=use_device_memory,
107
+ output_color_type=output_color_type,
108
+ gpu_id=gpu_id)
109
+
110
+ simple_decoder.seek_to_index(0)
111
+ batch_frames = simple_decoder.get_batch_frames(batch_size)
112
+ batch_frames_in_yuv = frame_to_yuv(batch_frames, use_device_memory)
113
+ batch_frames_idx_list = simple_decoder.get_batch_frames_by_index([0,1,2,3,4])
114
+ batch_frames_idx_list_yuv = frame_to_yuv(batch_frames_idx_list, use_device_memory)
115
+
116
+ if batch_frames_in_yuv == batch_frames_idx_list_yuv:
117
+ print("Results match: Both methods returned identical frame data\n")
118
+ else:
119
+ print("Results differ: Frame data mismatch between methods\n")
120
+
121
+ return simple_decoder
122
+
123
+ def perform_frame_slicing(simple_decoder, use_device_memory):
124
+ """Validates frame extraction using slice operations vs sequential parsing."""
125
+ print("2. Get frames by slicing [start:end:step] and get frames by sequential parsing\n")
126
+
127
+ sliced_frames = simple_decoder[0:10:2]
128
+ sliced_frames_in_yuv = frame_to_yuv(sliced_frames, use_device_memory)
129
+
130
+ seq_frames_in_yuv = []
131
+ for i in range(10):
132
+ if (i%2)==0:
133
+ frame = simple_decoder[i]
134
+ raw_frame = np.ndarray(shape=frame.framesize(), dtype=np.uint8)
135
+ luma_base_addr = frame.GetPtrToPlane(0)
136
+ if use_device_memory == True:
137
+ cuda.memcpy_dtoh(raw_frame, luma_base_addr)
138
+ else:
139
+ raw_frame = cast_address_to_1d_bytearray(base_address=luma_base_addr, size=frame.framesize())
140
+ bits = bytearray(raw_frame)
141
+ seq_frames_in_yuv.append(bits)
142
+
143
+ if seq_frames_in_yuv==sliced_frames_in_yuv:
144
+ print("Results match: Both methods returned identical frame data\n")
145
+ else:
146
+ print("Results differ: Frame data mismatch between methods\n")
147
+
148
+ def perform_timestamp_extraction(simple_decoder, time_file_path, use_device_memory):
149
+ """Extracts frames using timestamp-based indexing."""
150
+ print("3. Get frames for input time list in seconds\n")
151
+
152
+ out_yuv_path = "framesFromInputTimeList.yuv"
153
+ # Delete existing file before writing
154
+ if os.path.exists(out_yuv_path):
155
+ os.remove(out_yuv_path)
156
+ target_frame_indices=[]
157
+
158
+ with open(time_file_path, 'r') as file:
159
+ for line in file:
160
+ try:
161
+ time_value = float(line.strip())
162
+ target_frame_idx = simple_decoder.get_index_from_time_in_seconds(time_value)
163
+ target_frame_indices.append(target_frame_idx)
164
+ frame = simple_decoder[target_frame_idx]
165
+ save_frames_in_yuv(out_yuv_path, [frame], use_device_memory)
166
+ except ValueError:
167
+ print(f"Warning: Skipping invalid time value: {line.strip()}")
168
+
169
+ with open('timeValueIndices.txt', 'w') as file:
170
+ file.write(str(target_frame_indices))
171
+
172
+ print(f"Successfully saved frames to: {out_yuv_path}\n")
173
+ print(f"Indices corresponding to the time values are saved in timeValueIndices.txt\n")
174
+
175
+ def perform_keyframe_extraction(input_file_path, use_device_memory, gpu_id):
176
+ """Extracts and identifies keyframes."""
177
+ print("4. Get key frames\n")
178
+ simple_decoder = nvc.SimpleDecoder(input_file_path, need_scanned_stream_metadata=True,
179
+ use_device_memory=use_device_memory, gpu_id=gpu_id)
180
+ metadata = simple_decoder.get_scanned_stream_metadata()
181
+ key_frame_indices = metadata.key_frame_indices
182
+
183
+ with open('keyFrameIndices.txt', 'w') as file:
184
+ file.write(str(key_frame_indices))
185
+
186
+ key_frames_batch = [key_frame_indices[i:i + 8] for i in range(0, len(key_frame_indices), 8)]
187
+ out_yuv_path = "keyFrames.yuv"
188
+ # Delete existing file before writing
189
+ if os.path.exists(out_yuv_path):
190
+ os.remove(out_yuv_path)
191
+
192
+ for frames in key_frames_batch:
193
+ batch_frames = simple_decoder.get_batch_frames_by_index(frames)
194
+ save_frames_in_yuv(out_yuv_path, batch_frames, use_device_memory)
195
+
196
+ print(f"Successfully saved frames to: {out_yuv_path}\n")
197
+ print(f"Key frame indices are saved in keyFrameIndices.txt\n")
198
+
199
+ def perform_segment_generation(input_file_path, segments_file_path, config_file_path, segment_output_template, gpu_id):
200
+ """Generates video segments based on time ranges."""
201
+ print("5. Get segments given start and end time values.")
202
+
203
+ with open(config_file_path) as jsonFile:
204
+ config = json.loads(jsonFile.read())
205
+
206
+ with open(segments_file_path, 'r') as file:
207
+ for line in file:
208
+ try:
209
+ time_values = line.strip()
210
+ if not time_values: # Skip empty lines
211
+ continue
212
+ start_ts_str, end_ts_str = time_values.split(' ')
213
+
214
+ input_file_name_base = os.path.splitext(os.path.basename(input_file_path))[0]
215
+
216
+ # Template is for the base path, should primarily use {input_file_name}
217
+ base_path_template_vars = {
218
+ "input_file_name": input_file_name_base
219
+ }
220
+ # This is the base path to be passed to the Transcoder
221
+ base_segment_output_path = segment_output_template.format(**base_path_template_vars)
222
+
223
+ # Ensure the output path has an extension, default to .mp4 if none provided
224
+ base_output_name_part, base_output_ext_part = os.path.splitext(base_segment_output_path)
225
+ if not base_output_ext_part:
226
+ base_output_ext_part = '.mp4'
227
+ base_segment_output_path = base_output_name_part + base_output_ext_part
228
+
229
+ # Construct the final expected path for printing
230
+ final_expected_path = f"{base_output_name_part}_{start_ts_str}_{end_ts_str}{base_output_ext_part}"
231
+
232
+
233
+ tr = nvc.Transcoder(input_file_path,
234
+ base_segment_output_path, # Pass base path
235
+ gpu_id,
236
+ 0, 0,
237
+ **config)
238
+
239
+ tr.segmented_transcode(float(start_ts_str), float(end_ts_str))
240
+ # Use the constructed final_expected_path for the confirmation message
241
+ print(f"Segmented output saved as {final_expected_path}")
242
+ except ValueError:
243
+ print(f"Warning: Skipping invalid time value or format: {line.strip()}")
244
+ except Exception as e:
245
+ print(f"An error occurred while processing segment: {line.strip()}. Error: {e}")
246
+
247
+ def get_enabled_operations(operation_ids=None):
248
+ """Determines which operations should be run based on provided IDs."""
249
+ # Define mapping between operation IDs and names
250
+ operation_map = {
251
+ 1: 'batch_comparison',
252
+ 2: 'frame_slicing',
253
+ 3: 'timestamp_extraction',
254
+ 4: 'keyframe_extraction',
255
+ 5: 'segment_generation'
256
+ }
257
+
258
+ # Define all available operations
259
+ all_operations = {
260
+ 'batch_comparison': False,
261
+ 'frame_slicing': False,
262
+ 'timestamp_extraction': False,
263
+ 'keyframe_extraction': False,
264
+ 'segment_generation': False
265
+ }
266
+
267
+ # If no operations specified, run all operations
268
+ if not operation_ids:
269
+ for operation in all_operations:
270
+ all_operations[operation] = True
271
+ else:
272
+ # Enable only selected operations
273
+ for op_id in operation_ids:
274
+ if op_id in operation_map:
275
+ all_operations[operation_map[op_id]] = True
276
+ else:
277
+ print(f"Warning: Unknown operation ID '{op_id}' specified - skipping")
278
+
279
+ return all_operations
280
+
281
+ def ensemble_app(input_file_path, time_file_path, use_device_memory, segments_file_path, config_file_path, gpu_id, segment_output_template, operation_ids=None):
282
+ '''
283
+ Validates and compares different frame extraction methods from a video source:
284
+
285
+ Available operations:
286
+ 1. Batch Frame Comparison: Compares sequential vs index-based frame retrieval
287
+ 2. Frame Slicing: Validates frame extraction using slice operations vs sequential parsing
288
+ 3. Timestamp Extraction: Tests frame retrieval using timestamp-based indexing
289
+ 4. Keyframe Extraction: Verifies keyframe identification and extraction
290
+ 5. Segment Generation: Retrieves video segments based on start and end time values
291
+ '''
292
+
293
+ try:
294
+ # Determine which operations to run
295
+ all_operations = get_enabled_operations(operation_ids)
296
+
297
+ # Initialize decoder for operations that share it
298
+ simple_decoder = None
299
+
300
+ # Perform enabled operations
301
+ if all_operations['batch_comparison']:
302
+ simple_decoder = perform_batch_comparison(input_file_path, use_device_memory, gpu_id)
303
+
304
+ if all_operations['frame_slicing']:
305
+ if not simple_decoder:
306
+ simple_decoder = nvc.SimpleDecoder(input_file_path, need_scanned_stream_metadata=False,
307
+ use_device_memory=use_device_memory, gpu_id=gpu_id)
308
+ perform_frame_slicing(simple_decoder, use_device_memory)
309
+
310
+ if all_operations['timestamp_extraction']:
311
+ if not simple_decoder:
312
+ simple_decoder = nvc.SimpleDecoder(input_file_path, need_scanned_stream_metadata=False,
313
+ use_device_memory=use_device_memory, gpu_id=gpu_id)
314
+ perform_timestamp_extraction(simple_decoder, time_file_path, use_device_memory)
315
+
316
+ if all_operations['keyframe_extraction']:
317
+ perform_keyframe_extraction(input_file_path, use_device_memory, gpu_id)
318
+
319
+ if all_operations['segment_generation']:
320
+ perform_segment_generation(input_file_path, segments_file_path, config_file_path, segment_output_template, gpu_id)
321
+
322
+ except Exception as e:
323
+ print(f"An unexpected error occurred: {e}")
324
+
325
+
326
+ if __name__ == "__main__":
327
+
328
+
329
+ parser = argparse.ArgumentParser("This sample application demonstrates different functionalities of Simple Decoder & Simple transcoder",
330
+ formatter_class=argparse.RawTextHelpFormatter)
331
+
332
+ parser.add_argument("-i", "--input_file_path",
333
+ required=True,
334
+ type=Path,
335
+ help='Path to input video file' )
336
+
337
+ parser.add_argument("-g", "--gpu_id",
338
+ type=int,
339
+ default=0,
340
+ help="Check nvidia-smi for available GPUs. Default: 0"
341
+ )
342
+
343
+
344
+ parser.add_argument("-t", '--time_file_path',
345
+ type=Path,
346
+ default=join(current_dir, "timeListInSeconds.txt"),
347
+ help='''Path to the input time file.
348
+ File format requirements:
349
+ - One time value (in seconds) per line
350
+ - Values should be numeric (integer or decimal)
351
+ - Empty lines will be ignored
352
+ Default: timeListInSeconds.txt in the same directory'''
353
+ )
354
+
355
+ parser.add_argument("-d", "--use_device_memory",
356
+ choices=[0, 1],
357
+ default=1,
358
+ type=int,
359
+ help="Decoder output surface is in device memory else in "
360
+ "host memory. Default is 1 (device memory).",
361
+ )
362
+
363
+ parser.add_argument("-json", "--config_file_path",
364
+ type=Path,
365
+ default=join(current_dir, "transcode_config.json"),
366
+ help="Path of json config file (default: transcode_config.json in the same directory)", )
367
+
368
+ parser.add_argument("-segments", '--segments_file_path',
369
+ type=Path,
370
+ default=join(current_dir, "segments.txt"),
371
+ help='''Path to the input segment file.
372
+ File format requirements:
373
+ - Each line should contain a start and end time value separated by a space.
374
+ - Values should be numeric (integer or decimal)
375
+ - Empty lines will be ignored
376
+ Default: segments.txt in the same directory'''
377
+ )
378
+
379
+ parser.add_argument("-so", "--segment-output",
380
+ type=str,
381
+ default="{input_file_name}.mp4",
382
+ help='''Base output file name template for segmented transcode.
383
+ The API will append '_{start_ts}_{end_ts}' (e.g., _0.0_10.5) to this base name.
384
+ Default: '{input_file_name}_segment.mp4'''
385
+ )
386
+
387
+ parser.add_argument("-o", "--operations",
388
+ type=int,
389
+ nargs='+',
390
+ choices=range(1, 6),
391
+ help='''Specify which decoder/transcoder operations to perform using operation IDs. Multiple IDs can be specified. IDs should be separated by space.
392
+ Available operations:
393
+ 1. Batch Frame Comparison: Compare sequential vs index-based frame retrieval
394
+ 2. Frame Slicing: Perform frame slicing operations vs sequential parsing
395
+ 3. Timestamp Extraction: Extract frames using timestamps
396
+ 4. Keyframe Extraction: Extract and identify keyframes
397
+ 5. Segment Generation: Generate video segments based on time ranges
398
+ If not specified, all operations will be performed.''')
399
+
400
+ args = parser.parse_args()
401
+ input_file_path = args.input_file_path.as_posix()
402
+ time_file_path = args.time_file_path.as_posix()
403
+ config_file_path = args.config_file_path.as_posix()
404
+ segments_file_path = args.segments_file_path.as_posix()
405
+ use_device_memory = args.use_device_memory
406
+ gpu_id = args.gpu_id
407
+ operation_ids = args.operations
408
+ segment_output_template_arg = args.segment_output
409
+
410
+ ensemble_app(input_file_path, time_file_path, use_device_memory, segments_file_path, config_file_path, gpu_id, segment_output_template_arg, operation_ids)
411
+
412
+
413
+
414
+
415
+
416
+