PyNvVideoCodec 2.0.4__cp314-cp314-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 (65) hide show
  1. PyNvVideoCodec/PyNvVideoCodec_121.cp314-win_amd64.pyd +0 -0
  2. PyNvVideoCodec/PyNvVideoCodec_130.cp314-win_amd64.pyd +0 -0
  3. PyNvVideoCodec/VersionCheck.cp314-win_amd64.pyd +0 -0
  4. PyNvVideoCodec/__init__.py +246 -0
  5. PyNvVideoCodec/avcodec-62.dll +0 -0
  6. PyNvVideoCodec/avdevice-62.dll +0 -0
  7. PyNvVideoCodec/avfilter-11.dll +0 -0
  8. PyNvVideoCodec/avformat-62.dll +0 -0
  9. PyNvVideoCodec/avutil-60.dll +0 -0
  10. PyNvVideoCodec/decoders/SimpleDecoder.py +230 -0
  11. PyNvVideoCodec/decoders/ThreadedDecoder.py +129 -0
  12. PyNvVideoCodec/decoders/__init__.py +22 -0
  13. PyNvVideoCodec/swresample-6.dll +0 -0
  14. PyNvVideoCodec/swscale-9.dll +0 -0
  15. PyNvVideoCodec/transcoder/Transcoder.py +55 -0
  16. PyNvVideoCodec/transcoder/__init__.py +22 -0
  17. benchmarks/cached_decoder_benchmark.py +813 -0
  18. benchmarks/frame_sampling_benchmark.py +765 -0
  19. benchmarks/requirements.txt +47 -0
  20. benchmarks/segmented_transcode_benchmark.py +1546 -0
  21. pynvvideocodec-2.0.4.data/data/external/ffmpeg/readme.txt +15 -0
  22. pynvvideocodec-2.0.4.data/data/external/ffmpeg/src/ffmpeg-8.1.1.tar.xz +0 -0
  23. pynvvideocodec-2.0.4.dist-info/METADATA +84 -0
  24. pynvvideocodec-2.0.4.dist-info/RECORD +65 -0
  25. pynvvideocodec-2.0.4.dist-info/WHEEL +5 -0
  26. pynvvideocodec-2.0.4.dist-info/licenses/LICENSE.txt +22 -0
  27. pynvvideocodec-2.0.4.dist-info/licenses/NOTICES.txt +167 -0
  28. pynvvideocodec-2.0.4.dist-info/top_level.txt +3 -0
  29. samples/advanced/decode.py +173 -0
  30. samples/advanced/decode_from_memory_buffer.py +204 -0
  31. samples/advanced/decode_perf.py +299 -0
  32. samples/advanced/decode_reconfigure.py +184 -0
  33. samples/advanced/decode_sei_msg.py +193 -0
  34. samples/advanced/decode_with_cuda_control.py +214 -0
  35. samples/advanced/decode_with_low_latency.py +183 -0
  36. samples/advanced/encode_config.json +9 -0
  37. samples/advanced/encode_config_lowlatency.json +11 -0
  38. samples/advanced/encode_perf.py +338 -0
  39. samples/advanced/encode_reconfigure.py +211 -0
  40. samples/advanced/encode_sei_msg.py +188 -0
  41. samples/advanced/simple_decode_stats.py +179 -0
  42. samples/advanced/transcode.py +288 -0
  43. samples/basic/create_video_segments.py +187 -0
  44. samples/basic/encode.py +347 -0
  45. samples/basic/encode_config.json +9 -0
  46. samples/basic/segments.txt +3 -0
  47. samples/basic/simple_decode_sampling.py +182 -0
  48. samples/basic/transcode_config.json +6 -0
  49. samples/jupyter/ReconfigureDecoder.png +0 -0
  50. samples/jupyter/SimpleDecoderAPIs.png +0 -0
  51. samples/jupyter/ThreadedDecoder.png +0 -0
  52. samples/jupyter/coco_classes.pickle +0 -0
  53. samples/jupyter/object_detection_tutorial.ipynb +762 -0
  54. samples/jupyter/simple_decode_tutorial.ipynb +651 -0
  55. samples/requirements.txt +78 -0
  56. samples/utils/Utils.py +405 -0
  57. samples/utils/__init__.py +36 -0
  58. samples/utils/decode_parser.py +642 -0
  59. samples/utils/decode_stats_writer.py +177 -0
  60. samples/utils/encode_parallel_utils.py +174 -0
  61. samples/utils/encode_parser.py +357 -0
  62. samples/utils/frame_utils.py +89 -0
  63. samples/utils/sei_message_parser.py +223 -0
  64. samples/utils/sei_parser.py +223 -0
  65. samples/utils/transcode_parser.py +218 -0
@@ -0,0 +1,246 @@
1
+ # This copyright notice applies to this file only
2
+ #
3
+ # SPDX-FileCopyrightText: Copyright (c) 2026 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
+ """
25
+
26
+ """
27
+
28
+ __author__ = "NVIDIA"
29
+ __copyright__ = "Copyright 2026, NVIDIA"
30
+ __credits__ = []
31
+ __license__ = "MIT"
32
+ __version__ = "2.1.1"
33
+ __maintainer__ = "NVIDIA"
34
+ __email__ = "TODO"
35
+ __status__ = "Production"
36
+
37
+ from ast import Str
38
+ import string
39
+ import os
40
+ import platform
41
+ import sys
42
+ import site
43
+ from pathlib import Path
44
+ import importlib.util
45
+ import logging
46
+
47
+ logger = logging.getLogger(__name__)
48
+ logger.setLevel(logging.INFO)
49
+
50
+ def _setup_environment():
51
+ """Setup environment variables and paths"""
52
+ package_dir = os.path.dirname(os.path.abspath(__file__))
53
+ machine = platform.machine()
54
+
55
+ if platform.system() == 'Windows':
56
+ try:
57
+ # Add CUDA path if available
58
+ cuda_path = os.environ.get('CUDA_PATH')
59
+ if cuda_path:
60
+ dll_paths = [
61
+ os.path.join(cuda_path, "bin"),
62
+ os.path.join(cuda_path, "lib", "x64"),
63
+ package_dir, # Package directory for ffmpeg DLLs
64
+ os.path.join(package_dir, "lib") # Additional lib directory
65
+ ]
66
+
67
+ # Add paths to DLL search path
68
+ if hasattr(os, 'add_dll_directory'):
69
+ for path in dll_paths:
70
+ if os.path.exists(path):
71
+ os.add_dll_directory(path)
72
+ logger.debug(f"Added DLL directory: {path}")
73
+ except Exception as e:
74
+ logger.error(f"Error setting up DLL paths: {e}")
75
+
76
+ def _get_module_path(module_suffix):
77
+ """Get the appropriate module file path"""
78
+ package_dir = os.path.dirname(os.path.abspath(__file__))
79
+ py_version = f"{sys.version_info.major}{sys.version_info.minor}"
80
+ machine = platform.machine()
81
+
82
+ if platform.system() == "Windows":
83
+ ext = ".pyd"
84
+ possible_names = [
85
+ f"PyNvVideoCodec{module_suffix}.cp{py_version}-win_amd64{ext}"
86
+ ]
87
+ else:
88
+ ext = ".so"
89
+ if machine == 'aarch64':
90
+ possible_names = [
91
+ f"PyNvVideoCodec{module_suffix}.cpython-{py_version}-aarch64-linux-gnu{ext}",
92
+ f"PyNvVideoCodec{module_suffix}.cpython-{py_version}-aarch64-linux{ext}",
93
+ f"PyNvVideoCodec{module_suffix}.cp{py_version}-manylinux_2_28_aarch64{ext}"
94
+ ]
95
+ else: # x86_64
96
+ possible_names = [
97
+ f"PyNvVideoCodec{module_suffix}.cpython-{py_version}-x86_64-linux-gnu{ext}",
98
+ f"PyNvVideoCodec{module_suffix}.cpython-{py_version}-x86_64-linux{ext}",
99
+ f"PyNvVideoCodec{module_suffix}.cp{py_version}-manylinux_2_28_x86_64{ext}"
100
+ ]
101
+
102
+ # Try each possible name
103
+ for name in possible_names:
104
+ path = os.path.join(package_dir, name)
105
+ if os.path.exists(path):
106
+ logger.debug(f"Found module: {path}")
107
+ return path
108
+
109
+ # If no module found, list directory contents for debugging
110
+ logger.error(f"Available files in {package_dir}:")
111
+ try:
112
+ for file in os.listdir(package_dir):
113
+ logger.error(f" {file}")
114
+ except Exception as e:
115
+ logger.error(f"Error listing directory: {e}")
116
+
117
+ # Return the first name for error message
118
+ return os.path.join(package_dir, possible_names[0])
119
+
120
+ def _get_driver_version():
121
+ """Get the driver version using VersionCheck"""
122
+ try:
123
+ from .VersionCheck import DriverWrapper
124
+ driver = DriverWrapper()
125
+ version = driver.GetDriverVersion()
126
+ logger.info(f"Supported NVENC Driver Version: {version}")
127
+ return version
128
+ except Exception as e:
129
+ error_msg = str(e)
130
+
131
+ # Provide troubleshooting guidance
132
+ troubleshooting = "\n\n=== TROUBLESHOOTING STEPS ===\n"
133
+
134
+ if "libnvidia-encode.so" in error_msg or "cannot open shared object file" in error_msg:
135
+ troubleshooting += "\nThe NVENC library could not be found. This usually means:\n"
136
+ troubleshooting += "\n1. **Running in Docker?**"
137
+ troubleshooting += "\n - Ensure your container was launched with: NVIDIA_DRIVER_CAPABILITIES=compute,utility,video"
138
+ troubleshooting += "\n - Example: docker run --gpus all -e NVIDIA_DRIVER_CAPABILITIES=compute,utility,video ..."
139
+ troubleshooting += "\n - Or add to docker-compose.yml:"
140
+ troubleshooting += "\n environment:"
141
+ troubleshooting += "\n - NVIDIA_DRIVER_CAPABILITIES=compute,utility,video"
142
+ troubleshooting += "\n\n2. **NVIDIA drivers not installed or outdated**"
143
+ troubleshooting += "\n - Check driver installation: nvidia-smi"
144
+ troubleshooting += "\n - Ensure NVENC-capable GPU is present"
145
+ troubleshooting += "\n - Update to latest NVIDIA drivers if needed"
146
+ troubleshooting += "\n\n3. **Library path issues**"
147
+ troubleshooting += "\n - Check if library exists: find /usr -name 'libnvidia-encode.so*' 2>/dev/null"
148
+ troubleshooting += "\n - Verify LD_LIBRARY_PATH includes NVIDIA library directories"
149
+ else:
150
+ troubleshooting += f"\nOriginal error: {error_msg}\n"
151
+ troubleshooting += "\nPlease ensure:"
152
+ troubleshooting += "\n1. NVIDIA drivers are properly installed"
153
+ troubleshooting += "\n2. NVENC-capable GPU is available"
154
+ troubleshooting += "\n3. If using Docker, NVIDIA_DRIVER_CAPABILITIES includes 'video'"
155
+
156
+ raise RuntimeError(f"{error_msg}{troubleshooting}") from e
157
+
158
+ try:
159
+ # Setup environment
160
+ _setup_environment()
161
+
162
+ # Get driver version
163
+ supportedNvEncVersion = _get_driver_version()
164
+
165
+ # Define driver version thresholds
166
+ NVENC_VER_13 = 13 * 16 # Driver version for NVENC 13
167
+ NVENC_VER_12 = 12 * 16 + 1 # Driver version for NVENC 12.1
168
+
169
+ # Determine which version to use
170
+ if supportedNvEncVersion >= NVENC_VER_13:
171
+ module_suffix = "_130"
172
+ logger.info("Using NVENC 13.0 version")
173
+ elif supportedNvEncVersion >= NVENC_VER_12:
174
+ module_suffix = "_121"
175
+ logger.info("Using NVENC 12.1 version")
176
+ else:
177
+ raise RuntimeError("Driver version is too old")
178
+
179
+ # Get module path
180
+ module_path = _get_module_path(module_suffix)
181
+ if not os.path.exists(module_path):
182
+ raise ImportError(f"Module not found: {module_path}")
183
+
184
+ # Import the module
185
+ spec = importlib.util.spec_from_file_location("_PyNvVideoCodec", module_path)
186
+ if spec is None:
187
+ raise ImportError(f"Could not create module spec for {module_path}")
188
+
189
+ _PyNvVideoCodec = importlib.util.module_from_spec(spec)
190
+ spec.loader.exec_module(_PyNvVideoCodec)
191
+
192
+ # Import all symbols into current namespace
193
+ globals().update({name: getattr(_PyNvVideoCodec, name) for name in dir(_PyNvVideoCodec)
194
+ if not name.startswith('_')})
195
+
196
+ # Import submodules
197
+ from .decoders.SimpleDecoder import SimpleDecoder
198
+ from .decoders.ThreadedDecoder import ThreadedDecoder
199
+ from .transcoder.Transcoder import Transcoder
200
+
201
+ except Exception as e:
202
+ # Only log additional diagnostics if troubleshooting steps not already included
203
+ if "TROUBLESHOOTING STEPS" not in str(e):
204
+ logger.error(f"Error importing PyNvVideoCodec: {e}")
205
+ logger.error(f"System: {platform.system()}")
206
+ logger.error(f"Python version: {sys.version}")
207
+ if platform.system() == "Linux":
208
+ logger.error(f"LD_LIBRARY_PATH: {os.environ.get('LD_LIBRARY_PATH', 'Not set')}")
209
+ raise
210
+
211
+ def tostring(val):
212
+ if type(val) == dict:
213
+ x = dict(map(lambda x: (x[0], tostring(x[1])), val.items()))
214
+ else:
215
+ x = str(val)
216
+ x = x.replace("]", "")
217
+ x = x.replace("[", "")
218
+ return x
219
+
220
+ def format_optional_params(optional_param):
221
+ param = tostring(optional_param)
222
+
223
+ if "slice" in param:
224
+ param["slice_mode"] = param["slice"]["mode"]
225
+ param["slice_data"] = param["slice"]["data"]
226
+ del param["slice"]
227
+
228
+ if "timinginfo" in param:
229
+ param["num_unit_in_ticks"] = param["timinginfo"]["num_unit_in_ticks"]
230
+ param["timescale"] = param["timinginfo"]["timescale"]
231
+ del param["timinginfo"]
232
+
233
+ return param
234
+
235
+ def CreateEncoder(width, height, fmt, usecpuinputbuffer, **kwargs):
236
+ cudacontext = 0
237
+ cudastream = 0
238
+ if "cudacontext" in kwargs:
239
+ cudacontext = int(kwargs["cudacontext"])
240
+ del kwargs["cudacontext"]
241
+ if "cudastream" in kwargs:
242
+ cudastream = int(kwargs["cudastream"])
243
+ del kwargs["cudastream"]
244
+
245
+ optional_args = format_optional_params(kwargs)
246
+ return PyNvEncoder(width, height, fmt, cudacontext, cudastream, usecpuinputbuffer, optional_args)
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,230 @@
1
+ # This copyright notice applies to this file only
2
+ #
3
+ # SPDX-FileCopyrightText: Copyright (c) 2026 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
+ from typing import Union
25
+ # from ._SimpleDecoderImpl import SimpleDecoderImpl
26
+ import PyNvVideoCodec as nvc
27
+ import warnings
28
+ import logging
29
+
30
+ class SimpleDecoder:
31
+ """
32
+ A simple class for decoding a video stream and accessing frames in varied ways.
33
+
34
+ Args:
35
+ enc_file_path (str): Encoded file path.
36
+ gpu_id (int) : gpu id on which to decode on.
37
+ cuda_context(pycuda._driver.Context): Cuda context under which the source is decoded
38
+ cuda_stream(pycuda._driver.Stream): Cuda stream used by the decoder
39
+ use_device_memory (bool): If set to 'True' output decoded frame is CUDeviceptr wrapped in CUDA Array Interface else its Host memory.
40
+ max_width(int): maximum width that the decoder must support
41
+ max_height(int): maximum height that the decoder must support
42
+ need_scanned_stream_metadata(bool): If set to 'True', the stream metadata will be collected by going through each of the packets. This
43
+ runs on a different thread and its running time depends on the total size of input stream.
44
+ decoder_cache_size(int): LRU cache size for the number of decoders to cache.
45
+ output_color_type (OutputColorType): Output format type of the decoded frames. By default it is OutputColorType::NATIVE which
46
+ implies decoded output is returned in native format(NV12, YUV444 etc.). Other supported values are OutputColorType::RGB(which implies
47
+ the decoded output is converted to interleaved RGB(HWC)) and OutputColorType::RGBP(which implies decoded output is converted to planar
48
+ RGB(CHW))
49
+ enableDecodeStats (bool): If set to 'True', decode statistics will be available for each decoded frame. Default is False.
50
+ """
51
+
52
+ def __init__(self, enc_file_path,
53
+ gpu_id = 0, cuda_context = 0,
54
+ cuda_stream = 0, use_device_memory = True,
55
+ max_width = 0,
56
+ max_height = 0,
57
+ need_scanned_stream_metadata = 0,
58
+ decoder_cache_size = 4,
59
+ output_color_type = nvc.OutputColorType.NATIVE,
60
+ bWaitForSessionWarmUp = False,
61
+ enableDecodeStats = False):
62
+
63
+
64
+ self.need_scanned_stream_metadata = need_scanned_stream_metadata
65
+ self.simple_decoder = nvc.CreateSimpleDecoder(enc_file_path, gpu_id,
66
+ cuda_context, cuda_stream,
67
+ use_device_memory, max_width,
68
+ max_height, need_scanned_stream_metadata,
69
+ decoder_cache_size, output_color_type,
70
+ bWaitForSessionWarmUp, enableDecodeStats)
71
+
72
+ total_frames = self.__len__()
73
+ if total_frames == 0:
74
+ raise Exception("Elementary streams not supported by Simple Decoder. Invalid input stream.")
75
+
76
+ def __getitem__(self, key: Union[int, slice]):
77
+ """
78
+ Return frame or batch of frames depending on the key.
79
+ Supports Python slice semantics: stop is exclusive, so dec[0:len(dec)]
80
+ returns all frames.
81
+ Args:
82
+ key (int or slice): The index or range of indices to get the frames
83
+ Returns:
84
+ DecodedFrame: Decoded frame(s) based on the key
85
+ """
86
+ if isinstance(key, int):
87
+ self.validate_index(key)
88
+ return self.simple_decoder[key]
89
+ elif isinstance(key, slice):
90
+ start, stop, step = key.indices(len(self))
91
+ indices = list(range(start, stop, step))
92
+ if not indices:
93
+ return self.get_batch_frames_by_index([])
94
+ return self.get_batch_frames_by_index(indices)
95
+ else:
96
+ raise TypeError(
97
+ f"Unsupported key type: {type(key)}. Supported types are int and slice."
98
+ )
99
+
100
+
101
+ def __len__(self):
102
+ """
103
+ Returns the total number of frames in the video
104
+ """
105
+ stream_meta = self.simple_decoder.get_stream_metadata()
106
+ if stream_meta.num_frames == 0 and self.need_scanned_stream_metadata == True:
107
+ scanned_stream_data = self.simple_decoder.get_scanned_stream_metadata()
108
+ return scanned_stream_data.num_frames
109
+ return stream_meta.num_frames
110
+
111
+
112
+ def get_batch_frames(self, batch_size):
113
+ """
114
+ Returns a batch of frames based on the batch size
115
+ Args:
116
+ batch_size(int): Number of frames in the batch
117
+ Returns:
118
+ DecodedFrame[] : A list of decoded frames
119
+ """
120
+ return self.simple_decoder.get_batch_frames(batch_size)
121
+
122
+ def stop(self):
123
+ return self.simple_decoder.stop()
124
+
125
+
126
+ def get_batch_frames_by_index(self, indices):
127
+ """
128
+ Returns a batch of frames based on the indices
129
+ Args:
130
+ indices(list): A list containing the frame indices to be retrieved
131
+ Returns:
132
+ DecodedFrame[] : A list of decoded frames
133
+ """
134
+ total_frames = self.__len__()
135
+ validated_indices = []
136
+ seen = set()
137
+ for index in indices:
138
+ if 0 <= index < total_frames:
139
+ if index not in seen:
140
+ seen.add(index)
141
+ validated_indices.append(index)
142
+ else:
143
+ warnings.warn(
144
+ f"Skipping index {index}: Out of valid range [0, {total_frames-1}]")
145
+
146
+ if len(indices) > len(validated_indices):
147
+ warnings.warn(
148
+ f"Duplicates are not supported and have been removed. Modified index list: {validated_indices}"
149
+ )
150
+ sorted_validated_indices = sorted(validated_indices)
151
+ sorted_frames = self.simple_decoder.get_batch_frames_by_index(sorted_validated_indices)
152
+ mapping = {val: sorted_frames[idx] for idx, val in enumerate(sorted_validated_indices)}
153
+ reordered_frames = [mapping[val] for val in validated_indices]
154
+ return reordered_frames
155
+
156
+
157
+ def get_stream_metadata(self):
158
+ """
159
+ Returns stream metadata
160
+ Returns:
161
+ StreamMetadata : StreamMetadata structure with metadata info
162
+ """
163
+ stream_meta = self.simple_decoder.get_stream_metadata()
164
+ return stream_meta
165
+
166
+ def get_scanned_stream_metadata(self):
167
+ """
168
+ Returns stream metadata by performing entitre stream scan.
169
+ Returns:
170
+ ScannedStreamMetadata : ScannedStreamMetadata structure with
171
+ metadata info
172
+ """
173
+ if self.need_scanned_stream_metadata == 0:
174
+ raise Exception("Invalid call to funtion. Decoder was created with \
175
+ need_scanned_stream_metadata = 0.")
176
+ stream_meta = self.simple_decoder.get_scanned_stream_metadata()
177
+ return stream_meta
178
+
179
+ def seek_to_index(self, index):
180
+ """
181
+ Moves the demuxer marker to the specified index
182
+ Args:
183
+ index(int): The index to which the marker needs to be set
184
+ """
185
+ self.validate_index(index)
186
+ return self.simple_decoder.seek_to_index(index)
187
+
188
+ def get_index_from_time_in_seconds(self, time_in_seconds):
189
+ """
190
+ Gives the frame index corresponding to the time in seconds
191
+ Args:
192
+ timestamp(float): Frame timestamp
193
+ """
194
+ return self.simple_decoder.get_index_from_time_in_seconds(time_in_seconds)
195
+
196
+ def validate_index(self, index):
197
+ total_frames = self.__len__()
198
+ if not (0 <= index < total_frames):
199
+ raise IndexError(f"Index {index} is out of range [0, {total_frames-1}]")
200
+
201
+ def reconfigure_decoder(self, new_source):
202
+ """
203
+ Reconfigures the current decoder to use the new source. Internally it
204
+ holds a cache of decoders. The best available is choosen else a new decoder is
205
+ created.
206
+ Args:
207
+ new_source(str): Encoded source
208
+ """
209
+ return self.simple_decoder.reconfigure_decoder(new_source)
210
+
211
+ def get_session_init_time(self):
212
+ """
213
+ Returns the session initialization time in milliseconds.
214
+ This is useful for performance measurement.
215
+
216
+ Returns:
217
+ int64_t: Session initialization time in milliseconds
218
+ """
219
+ return self.simple_decoder.get_session_init_time()
220
+
221
+ @staticmethod
222
+ def set_session_count(count):
223
+ """
224
+ Sets the number of decoder sessions to be created.
225
+ This is useful for multi-threaded scenarios.
226
+
227
+ Args:
228
+ count (int): Number of decoder sessions
229
+ """
230
+ nvc.SimpleDecoder.set_session_count(count)
@@ -0,0 +1,129 @@
1
+ # This copyright notice applies to this file only
2
+ #
3
+ # SPDX-FileCopyrightText: Copyright (c) 2026 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
+ from typing import Union
25
+ #from ._SimpleDecoderImpl import SimpleDecoderImpl
26
+ import PyNvVideoCodec as nvc
27
+
28
+ class ThreadedDecoder():
29
+ """
30
+ Class for decoding video in background thread. This can be used for linear access in pipeines which are
31
+ CPU bound. In such a pipeline this decoder offes near zero frame fetch latency.
32
+
33
+ Args:
34
+ enc_file_path (str): Encoded file path.
35
+ gpu_id (int) : gpu id on which to decode on.
36
+ cuda_context(pycuda._driver.Context): Cuda context under which the source is decoded
37
+ cuda_stream(pycuda._driver.Stream): Cuda stream used by the decoder
38
+ use_device_memory (bool): If set to 'True' output decoded frame is CUDeviceptr wrapped in CUDA Array Interface else its Host memory.
39
+ max_width(int): maximum width that the decoder must support
40
+ max_height(int): maximum height that the decoder must support
41
+ need_scanned_stream_metadata(bool): If set to 'True', the stream metadata will be collected by going through each of the packets. This
42
+ runs on a different thread and its running time depends on the total size of input stream.
43
+ decoder_cache_size(int): LRU cache size for the number of decoders to cache.
44
+ output_color_type (OutputColorType): Output format type of the decoded frames. By default it is OutputColorType::NATIVE which
45
+ implies decoded output is returned in native format(NV12, YUV444 etc.). Other supported values are OutputColorType::RGB(which implies
46
+ the decoded output is converted to interleaved RGB(HWC)) and OutputColorType::RGBP(which implies decoded output is converted to planar
47
+ RGB(CHW))
48
+ start_frame (int): Frame number to start decoding from (uses seeking)
49
+ enableDecodeStats (bool): If set to 'True', decode statistics will be available for each decoded frame. Default is False.
50
+ """
51
+ def __init__(self, enc_file_path, buffer_size,
52
+ gpu_id = 0, cuda_context = 0,
53
+ cuda_stream = 0, use_device_memory = True,
54
+ max_width = 0,
55
+ max_height = 0,
56
+ need_scanned_stream_metadata = 0,
57
+ decoder_cache_size = 4,
58
+ output_color_type = nvc.OutputColorType.NATIVE,
59
+ start_frame = 0,
60
+ enableDecodeStats = False):
61
+ self.buffer_size = buffer_size
62
+ self.need_scanned_stream_metadata = need_scanned_stream_metadata
63
+ self.start_frame = start_frame
64
+ self.threaded_decoder = nvc.CreateThreadedDecoder(enc_file_path, buffer_size, gpu_id,
65
+ cuda_context, cuda_stream,
66
+ use_device_memory, max_width,
67
+ max_height, need_scanned_stream_metadata,
68
+ decoder_cache_size, output_color_type,
69
+ start_frame, enableDecodeStats)
70
+
71
+ def __len__(self):
72
+ stream_meta = self.threaded_decoder.get_stream_metadata()
73
+ if stream_meta.num_frames == 0 and self.need_scanned_stream_metadata == True:
74
+ scanned_stream_data = self.threaded_decoder.get_scanned_stream_metadata()
75
+ return scanned_stream_data.num_frames
76
+ return stream_meta.num_frames
77
+
78
+ def get_batch_frames(self, batch_size):
79
+ """
80
+ Returns a batch of frames based on the batch size
81
+ Args:
82
+ batch_size(int): Number of frames in the batch
83
+ Returns:
84
+ DecodedFrame[] : A list of decoded frames
85
+ """
86
+ if batch_size > self.buffer_size:
87
+ raise Exception(f"batch_size cannot be greater than buffer_size. \
88
+ Got batch_size = {batch_size} whereas buffer_size = {self.buffer_size}")
89
+ return self.threaded_decoder.get_batch_frames(batch_size)
90
+
91
+ def end(self):
92
+ return self.threaded_decoder.end()
93
+
94
+
95
+ def get_stream_metadata(self):
96
+ """
97
+ Returns stream metadata
98
+ Returns:
99
+ StreamMetadata : StreamMetadata structure with metadata info
100
+ """
101
+ stream_meta = self.threaded_decoder.get_stream_metadata()
102
+ return stream_meta
103
+
104
+ def get_scanned_stream_metadata(self):
105
+ """
106
+ Returns stream metadata by performing entitre stream scan.
107
+ Returns:
108
+ ScannedStreamMetadata : ScannedStreamMetadata structure with
109
+ metadata info
110
+ """
111
+ if self.need_scanned_stream_metadata == 0:
112
+ raise Exception("Invalid call to funtion. Decoder was created with \
113
+ need_scanned_stream_metadata = 0.")
114
+ stream_meta = self.threaded_decoder.get_scanned_stream_metadata()
115
+ return stream_meta
116
+
117
+ def reconfigure_decoder(self, new_source, start_frame=0):
118
+ """
119
+ Reconfigures the current decoder to use the new source and optionally
120
+ start from a specific frame. Internally it holds a cache of decoders.
121
+ The best available is chosen else a new decoder is created.
122
+
123
+ Args:
124
+ new_source (str): Path to new encoded video file
125
+ start_frame (int): Frame number to start decoding from (default 0).
126
+ Uses seeking to efficiently skip to the target frame.
127
+ """
128
+ self.start_frame = start_frame
129
+ return self.threaded_decoder.reconfigure_decoder(new_source, start_frame)
@@ -0,0 +1,22 @@
1
+ # This copyright notice applies to this file only
2
+ #
3
+ # SPDX-FileCopyrightText: Copyright (c) 2026 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.
Binary file
Binary file