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,237 @@
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
+ """
25
+
26
+ """
27
+
28
+ __author__ = "NVIDIA"
29
+ __copyright__ = "Copyright 2025, NVIDIA"
30
+ __credits__ = []
31
+ __license__ = "MIT"
32
+ __version__ = "2.0.0"
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
+ else:
76
+ # Linux: Update LD_LIBRARY_PATH
77
+ lib_paths = [
78
+ os.path.join(package_dir, "lib"),
79
+ "/usr/local/cuda/lib64",
80
+ ]
81
+
82
+ # Add architecture-specific paths
83
+ if machine == 'aarch64':
84
+ lib_paths.extend([
85
+ "/usr/lib/aarch64-linux-gnu",
86
+ "/usr/local/cuda/targets/aarch64-linux/lib"
87
+ ])
88
+ else: # x86_64
89
+ lib_paths.append("/usr/lib/x86_64-linux-gnu")
90
+
91
+ if "LD_LIBRARY_PATH" in os.environ:
92
+ lib_paths.extend(os.environ["LD_LIBRARY_PATH"].split(":"))
93
+ os.environ["LD_LIBRARY_PATH"] = ":".join(filter(None, lib_paths))
94
+
95
+ def _get_module_path(module_suffix):
96
+ """Get the appropriate module file path"""
97
+ package_dir = os.path.dirname(os.path.abspath(__file__))
98
+ py_version = f"{sys.version_info.major}{sys.version_info.minor}"
99
+ machine = platform.machine()
100
+
101
+ if platform.system() == "Windows":
102
+ ext = ".pyd"
103
+ possible_names = [
104
+ f"PyNvVideoCodec{module_suffix}.cp{py_version}-win_amd64{ext}"
105
+ ]
106
+ else:
107
+ ext = ".so"
108
+ if machine == 'aarch64':
109
+ possible_names = [
110
+ f"PyNvVideoCodec{module_suffix}.cpython-{py_version}-aarch64-linux-gnu{ext}",
111
+ f"PyNvVideoCodec{module_suffix}.cpython-{py_version}-aarch64-linux{ext}",
112
+ f"PyNvVideoCodec{module_suffix}.cp{py_version}-manylinux_2_28_aarch64{ext}"
113
+ ]
114
+ else: # x86_64
115
+ possible_names = [
116
+ f"PyNvVideoCodec{module_suffix}.cpython-{py_version}-x86_64-linux-gnu{ext}",
117
+ f"PyNvVideoCodec{module_suffix}.cpython-{py_version}-x86_64-linux{ext}",
118
+ f"PyNvVideoCodec{module_suffix}.cp{py_version}-manylinux_2_28_x86_64{ext}"
119
+ ]
120
+
121
+ # Try each possible name
122
+ for name in possible_names:
123
+ path = os.path.join(package_dir, name)
124
+ if os.path.exists(path):
125
+ logger.debug(f"Found module: {path}")
126
+ return path
127
+
128
+ # If no module found, list directory contents for debugging
129
+ logger.error(f"Available files in {package_dir}:")
130
+ try:
131
+ for file in os.listdir(package_dir):
132
+ logger.error(f" {file}")
133
+ except Exception as e:
134
+ logger.error(f"Error listing directory: {e}")
135
+
136
+ # Return the first name for error message
137
+ return os.path.join(package_dir, possible_names[0])
138
+
139
+ def _get_driver_version():
140
+ """Get the driver version using VersionCheck"""
141
+ try:
142
+ from .VersionCheck import DriverWrapper
143
+ driver = DriverWrapper()
144
+ version = driver.GetDriverVersion()
145
+ logger.info(f"Supported NVENC Driver Version: {version}")
146
+ return version
147
+ except Exception as e:
148
+ logger.error(f"Error getting driver version: {e}")
149
+ raise
150
+
151
+ try:
152
+ # Setup environment
153
+ _setup_environment()
154
+
155
+ # Get driver version
156
+ supportedNvEncVersion = _get_driver_version()
157
+
158
+ # Define driver version thresholds
159
+ NVENC_VER_13 = 13 * 16 # Driver version for NVENC 13
160
+ NVENC_VER_12 = 12 * 16 + 1 # Driver version for NVENC 12.1
161
+
162
+ # Determine which version to use
163
+ if supportedNvEncVersion >= NVENC_VER_13:
164
+ module_suffix = "_130"
165
+ logger.info("Using NVENC 13.0 version")
166
+ elif supportedNvEncVersion >= NVENC_VER_12:
167
+ module_suffix = "_121"
168
+ logger.info("Using NVENC 12.1 version")
169
+ else:
170
+ raise RuntimeError("Driver version is too old")
171
+
172
+ # Get module path
173
+ module_path = _get_module_path(module_suffix)
174
+ if not os.path.exists(module_path):
175
+ raise ImportError(f"Module not found: {module_path}")
176
+
177
+ # Import the module
178
+ spec = importlib.util.spec_from_file_location("_PyNvVideoCodec", module_path)
179
+ if spec is None:
180
+ raise ImportError(f"Could not create module spec for {module_path}")
181
+
182
+ _PyNvVideoCodec = importlib.util.module_from_spec(spec)
183
+ spec.loader.exec_module(_PyNvVideoCodec)
184
+
185
+ # Import all symbols into current namespace
186
+ globals().update({name: getattr(_PyNvVideoCodec, name) for name in dir(_PyNvVideoCodec)
187
+ if not name.startswith('_')})
188
+
189
+ # Import submodules
190
+ from .decoders.SimpleDecoder import SimpleDecoder
191
+ from .decoders.ThreadedDecoder import ThreadedDecoder
192
+ from .transcoder.Transcoder import Transcoder
193
+
194
+ except Exception as e:
195
+ logger.error(f"Error importing PyNvVideoCodec: {e}")
196
+ logger.error(f"System: {platform.system()}")
197
+ logger.error(f"Python version: {sys.version}")
198
+ if platform.system() == "Linux":
199
+ logger.error(f"LD_LIBRARY_PATH: {os.environ.get('LD_LIBRARY_PATH', 'Not set')}")
200
+ raise
201
+
202
+ def tostring(val):
203
+ if type(val) == dict:
204
+ x = dict(map(lambda x: (x[0], tostring(x[1])), val.items()))
205
+ else:
206
+ x = str(val)
207
+ x = x.replace("]", "")
208
+ x = x.replace("[", "")
209
+ return x
210
+
211
+ def format_optional_params(optional_param):
212
+ param = tostring(optional_param)
213
+
214
+ if "slice" in param:
215
+ param["slice_mode"] = param["slice"]["mode"]
216
+ param["slice_data"] = param["slice"]["data"]
217
+ del param["slice"]
218
+
219
+ if "timinginfo" in param:
220
+ param["num_unit_in_ticks"] = param["timinginfo"]["num_unit_in_ticks"]
221
+ param["timescale"] = param["timinginfo"]["timescale"]
222
+ del param["timinginfo"]
223
+
224
+ return param
225
+
226
+ def CreateEncoder(width, height, fmt, usecpuinputbuffer, **kwargs):
227
+ cudacontext = 0
228
+ cudastream = 0
229
+ if "cudacontext" in kwargs:
230
+ cudacontext = int(kwargs["cudacontext"])
231
+ del kwargs["cudacontext"]
232
+ if "cudastream" in kwargs:
233
+ cudastream = int(kwargs["cudastream"])
234
+ del kwargs["cudastream"]
235
+
236
+ optional_args = format_optional_params(kwargs)
237
+ return PyNvEncoder(width, height, fmt, cudacontext, cudastream, usecpuinputbuffer, optional_args)
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,225 @@
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
+ from typing import Union
25
+ # from ._SimpleDecoderImpl import SimpleDecoderImpl
26
+ import PyNvVideoCodec as nvc
27
+ import warnings
28
+
29
+ class SimpleDecoder:
30
+ """
31
+ A simple class for decoding a video stream and accessing frames in varied ways.
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
+ """
49
+
50
+ def __init__(self, enc_file_path,
51
+ gpu_id = 0, cuda_context = 0,
52
+ cuda_stream = 0, use_device_memory = True,
53
+ max_width = 0,
54
+ max_height = 0,
55
+ need_scanned_stream_metadata = 0,
56
+ decoder_cache_size = 4,
57
+ output_color_type = nvc.OutputColorType.NATIVE,
58
+ bWaitForSessionWarmUp = False):
59
+ self.need_scanned_stream_metadata = need_scanned_stream_metadata
60
+ self.simple_decoder = nvc.CreateSimpleDecoder(enc_file_path, gpu_id,
61
+ cuda_context, cuda_stream,
62
+ use_device_memory, max_width,
63
+ max_height, need_scanned_stream_metadata,
64
+ decoder_cache_size, output_color_type,
65
+ bWaitForSessionWarmUp)
66
+
67
+ total_frames = self.__len__()
68
+ if total_frames == 0:
69
+ raise Exception("Elementary streams not supported by Simple Decoder. Invalid input stream.")
70
+
71
+ def __getitem__(self, key: Union[int, slice]):
72
+ """
73
+ Return frame or batch of frames depending on the key
74
+ Args:
75
+ key (int or slice): The index or range of index to get the frames
76
+ Returns:
77
+ DecodedFrame: Decoded frame(s) based on the key
78
+ """
79
+ if isinstance(key, int):
80
+ self.validate_index(key)
81
+ return self.simple_decoder[key]
82
+ elif isinstance(key, slice):
83
+ indices = range(key.start, key.stop, key.step)
84
+ idxs = list(iter(indices))
85
+ if not idxs:
86
+ raise ValueError(f"Invalid input.")
87
+ self.validate_index(key.start)
88
+ self.validate_index(key.stop)
89
+ return self.simple_decoder[idxs]
90
+ else:
91
+ raise TypeError(
92
+ f"Unsupported key type: {type(key)}. Supported types are int and slice."
93
+ )
94
+
95
+
96
+ def __len__(self):
97
+ """
98
+ Returns the total number of frames in the video
99
+ """
100
+ stream_meta = self.simple_decoder.get_stream_metadata()
101
+ if stream_meta.num_frames == 0 and self.need_scanned_stream_metadata == True:
102
+ scanned_stream_data = self.simple_decoder.get_scanned_stream_metadata()
103
+ return scanned_stream_data.num_frames
104
+ return stream_meta.num_frames
105
+
106
+
107
+ def get_batch_frames(self, batch_size):
108
+ """
109
+ Returns a batch of frames based on the batch size
110
+ Args:
111
+ batch_size(int): Number of frames in the batch
112
+ Returns:
113
+ DecodedFrame[] : A list of decoded frames
114
+ """
115
+ return self.simple_decoder.get_batch_frames(batch_size)
116
+
117
+ def stop(self):
118
+ return self.simple_decoder.stop()
119
+
120
+
121
+ def get_batch_frames_by_index(self, indices):
122
+ """
123
+ Returns a batch of frames based on the indices
124
+ Args:
125
+ indices(list): A list containing the frame indices to be retrieved
126
+ Returns:
127
+ DecodedFrame[] : A list of decoded frames
128
+ """
129
+ total_frames = self.__len__()
130
+ validated_indices = []
131
+ seen = set()
132
+ for index in indices:
133
+ if 0 <= index < total_frames:
134
+ if index not in seen:
135
+ seen.add(index)
136
+ validated_indices.append(index)
137
+ else:
138
+ warnings.warn(
139
+ f"Skipping index {index}: Out of valid range [0, {total_frames-1}]")
140
+
141
+ if len(indices) > len(validated_indices):
142
+ warnings.warn(
143
+ f"Duplicates are not supported and have been removed. Modified index list: {validated_indices}"
144
+ )
145
+ sorted_validated_indices = sorted(validated_indices)
146
+ sorted_frames = self.simple_decoder.get_batch_frames_by_index(sorted_validated_indices)
147
+ mapping = {val: sorted_frames[idx] for idx, val in enumerate(sorted_validated_indices)}
148
+ reordered_frames = [mapping[val] for val in validated_indices]
149
+ return reordered_frames
150
+
151
+
152
+ def get_stream_metadata(self):
153
+ """
154
+ Returns stream metadata
155
+ Returns:
156
+ StreamMetadata : StreamMetadata structure with metadata info
157
+ """
158
+ stream_meta = self.simple_decoder.get_stream_metadata()
159
+ return stream_meta
160
+
161
+ def get_scanned_stream_metadata(self):
162
+ """
163
+ Returns stream metadata by performing entitre stream scan.
164
+ Returns:
165
+ ScannedStreamMetadata : ScannedStreamMetadata structure with
166
+ metadata info
167
+ """
168
+ if self.need_scanned_stream_metadata == 0:
169
+ raise Exception("Invalid call to funtion. Decoder was created with \
170
+ need_scanned_stream_metadata = 0.")
171
+ stream_meta = self.simple_decoder.get_scanned_stream_metadata()
172
+ return stream_meta
173
+
174
+ def seek_to_index(self, index):
175
+ """
176
+ Moves the demuxer marker to the specified index
177
+ Args:
178
+ index(int): The index to which the marker needs to be set
179
+ """
180
+ self.validate_index(index)
181
+ return self.simple_decoder.seek_to_index(index)
182
+
183
+ def get_index_from_time_in_seconds(self, time_in_seconds):
184
+ """
185
+ Gives the frame index corresponding to the time in seconds
186
+ Args:
187
+ timestamp(float): Frame timestamp
188
+ """
189
+ return self.simple_decoder.get_index_from_time_in_seconds(time_in_seconds)
190
+
191
+ def validate_index(self, index):
192
+ total_frames = self.__len__()
193
+ if not (0 <= index < total_frames):
194
+ raise IndexError(f"Index {index} is out of range [0, {total_frames-1}]")
195
+
196
+ def reconfigure_decoder(self, new_source):
197
+ """
198
+ Reconfigures the current decoder to use the new source. Internally it
199
+ holds a cache of decoders. The best available is choosen else a new decoder is
200
+ created.
201
+ Args:
202
+ new_source(str): Encoded source
203
+ """
204
+ return self.simple_decoder.reconfigure_decoder(new_source)
205
+
206
+ def get_session_init_time(self):
207
+ """
208
+ Returns the session initialization time in milliseconds.
209
+ This is useful for performance measurement.
210
+
211
+ Returns:
212
+ int64_t: Session initialization time in milliseconds
213
+ """
214
+ return self.simple_decoder.get_session_init_time()
215
+
216
+ @staticmethod
217
+ def set_session_count(count):
218
+ """
219
+ Sets the number of decoder sessions to be created.
220
+ This is useful for multi-threaded scenarios.
221
+
222
+ Args:
223
+ count (int): Number of decoder sessions
224
+ """
225
+ nvc.SimpleDecoder.set_session_count(count)
@@ -0,0 +1,119 @@
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
+ 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
+ """
49
+ def __init__(self, enc_file_path, buffer_size,
50
+ gpu_id = 0, cuda_context = 0,
51
+ cuda_stream = 0, use_device_memory = True,
52
+ max_width = 0,
53
+ max_height = 0,
54
+ need_scanned_stream_metadata = 0,
55
+ decoder_cache_size = 4,
56
+ output_color_type = nvc.OutputColorType.NATIVE):
57
+ self.buffer_size = buffer_size
58
+ self.need_scanned_stream_metadata = need_scanned_stream_metadata
59
+ self.threaded_decoder = nvc.CreateThreadedDecoder(enc_file_path, buffer_size, gpu_id,
60
+ cuda_context, cuda_stream,
61
+ use_device_memory, max_width,
62
+ max_height, need_scanned_stream_metadata,
63
+ decoder_cache_size, output_color_type)
64
+
65
+ def __len__(self):
66
+ stream_meta = self.threaded_decoder.get_stream_metadata()
67
+ if stream_meta.num_frames == 0 and self.need_scanned_stream_metadata == True:
68
+ scanned_stream_data = self.threaded_decoder.get_scanned_stream_metadata()
69
+ return scanned_stream_data.num_frames
70
+ return stream_meta.num_frames
71
+
72
+ def get_batch_frames(self, batch_size):
73
+ """
74
+ Returns a batch of frames based on the batch size
75
+ Args:
76
+ batch_size(int): Number of frames in the batch
77
+ Returns:
78
+ DecodedFrame[] : A list of decoded frames
79
+ """
80
+ if batch_size > self.buffer_size:
81
+ raise Exception(f"batch_size cannot be greater than buffer_size. \
82
+ Got batch_size = {batch_size} whereas buffer_size = {self.buffer_size}")
83
+ return self.threaded_decoder.get_batch_frames(batch_size)
84
+
85
+ def end(self):
86
+ return self.threaded_decoder.end()
87
+
88
+
89
+ def get_stream_metadata(self):
90
+ """
91
+ Returns stream metadata
92
+ Returns:
93
+ StreamMetadata : StreamMetadata structure with metadata info
94
+ """
95
+ stream_meta = self.threaded_decoder.get_stream_metadata()
96
+ return stream_meta
97
+
98
+ def get_scanned_stream_metadata(self):
99
+ """
100
+ Returns stream metadata by performing entitre stream scan.
101
+ Returns:
102
+ ScannedStreamMetadata : ScannedStreamMetadata structure with
103
+ metadata info
104
+ """
105
+ if self.need_scanned_stream_metadata == 0:
106
+ raise Exception("Invalid call to funtion. Decoder was created with \
107
+ need_scanned_stream_metadata = 0.")
108
+ stream_meta = self.threaded_decoder.get_scanned_stream_metadata()
109
+ return stream_meta
110
+
111
+ def reconfigure_decoder(self, new_source):
112
+ """
113
+ Reconfigures the current decoder to use the new source. Internally it
114
+ holds a cache of decoders. The best available is choosen else a new decoder is
115
+ created.
116
+ Args:
117
+ new_source(str): Encoded source
118
+ """
119
+ return self.threaded_decoder.reconfigure_decoder(new_source)
@@ -0,0 +1,22 @@
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.
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file