PyNvVideoCodec 2.2.1__cp313-cp313-win_arm64.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 (63) hide show
  1. PyNvVideoCodec/PyNvVideoCodec_121.cp313-win_arm64.pyd +0 -0
  2. PyNvVideoCodec/PyNvVideoCodec_130.cp313-win_arm64.pyd +0 -0
  3. PyNvVideoCodec/VersionCheck.cp313-win_arm64.pyd +0 -0
  4. PyNvVideoCodec/__init__.py +251 -0
  5. PyNvVideoCodec/avformat-62.dll +0 -0
  6. PyNvVideoCodec/avutil-60.dll +0 -0
  7. PyNvVideoCodec/decoders/SimpleDecoder.py +273 -0
  8. PyNvVideoCodec/decoders/ThreadedDecoder.py +129 -0
  9. PyNvVideoCodec/decoders/__init__.py +22 -0
  10. PyNvVideoCodec/transcoder/Transcoder.py +55 -0
  11. PyNvVideoCodec/transcoder/__init__.py +22 -0
  12. benchmarks/cached_decoder_benchmark.py +813 -0
  13. benchmarks/frame_sampling_benchmark.py +765 -0
  14. benchmarks/requirements.txt +52 -0
  15. benchmarks/segmented_transcode_benchmark.py +1546 -0
  16. benchmarks/setup_pycuda_win_arm64.bat +531 -0
  17. pynvvideocodec-2.2.1.data/data/external/ffmpeg/readme.txt +39 -0
  18. pynvvideocodec-2.2.1.data/data/external/ffmpeg/src/ffmpeg-8.1.2.tar.xz +0 -0
  19. pynvvideocodec-2.2.1.dist-info/METADATA +97 -0
  20. pynvvideocodec-2.2.1.dist-info/RECORD +63 -0
  21. pynvvideocodec-2.2.1.dist-info/WHEEL +5 -0
  22. pynvvideocodec-2.2.1.dist-info/licenses/LICENSE.txt +22 -0
  23. pynvvideocodec-2.2.1.dist-info/licenses/NOTICES.txt +167 -0
  24. pynvvideocodec-2.2.1.dist-info/top_level.txt +3 -0
  25. samples/advanced/decode.py +173 -0
  26. samples/advanced/decode_from_memory_buffer.py +204 -0
  27. samples/advanced/decode_perf.py +299 -0
  28. samples/advanced/decode_reconfigure.py +184 -0
  29. samples/advanced/decode_sei_msg.py +193 -0
  30. samples/advanced/decode_with_cuda_control.py +214 -0
  31. samples/advanced/decode_with_low_latency.py +183 -0
  32. samples/advanced/encode_config.json +12 -0
  33. samples/advanced/encode_config_lowlatency.json +13 -0
  34. samples/advanced/encode_perf.py +338 -0
  35. samples/advanced/encode_reconfigure.py +211 -0
  36. samples/advanced/encode_sei_msg.py +188 -0
  37. samples/advanced/simple_decode_from_memory.py +151 -0
  38. samples/advanced/simple_decode_stats.py +179 -0
  39. samples/advanced/transcode.py +288 -0
  40. samples/basic/create_video_segments.py +187 -0
  41. samples/basic/encode.py +574 -0
  42. samples/basic/segments.txt +3 -0
  43. samples/basic/simple_decode_sampling.py +182 -0
  44. samples/basic/transcode_config.json +6 -0
  45. samples/jupyter/ReconfigureDecoder.png +0 -0
  46. samples/jupyter/SimpleDecoderAPIs.png +0 -0
  47. samples/jupyter/ThreadedDecoder.png +0 -0
  48. samples/jupyter/coco_classes.pickle +0 -0
  49. samples/jupyter/face_protect_tutorial.ipynb +881 -0
  50. samples/jupyter/object_detection_tutorial.ipynb +781 -0
  51. samples/jupyter/simple_decode_tutorial.ipynb +674 -0
  52. samples/requirements.txt +84 -0
  53. samples/setup_pycuda_win_arm64.bat +531 -0
  54. samples/utils/Utils.py +405 -0
  55. samples/utils/__init__.py +36 -0
  56. samples/utils/decode_parser.py +642 -0
  57. samples/utils/decode_stats_writer.py +177 -0
  58. samples/utils/encode_parallel_utils.py +174 -0
  59. samples/utils/encode_parser.py +379 -0
  60. samples/utils/frame_utils.py +89 -0
  61. samples/utils/sei_message_parser.py +223 -0
  62. samples/utils/sei_parser.py +223 -0
  63. samples/utils/transcode_parser.py +218 -0
samples/utils/Utils.py ADDED
@@ -0,0 +1,405 @@
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
+ import sys
25
+ import logging
26
+
27
+ from struct import pack
28
+ import sys
29
+ import os
30
+ import argparse
31
+ from pathlib import Path
32
+ from enum import Enum
33
+
34
+ import pycuda.driver as cuda
35
+ import PyNvVideoCodec as nvc
36
+ import numpy as np
37
+ from pycuda.compiler import SourceModule
38
+ import ctypes as C
39
+ from typing import List
40
+ import torch
41
+
42
+ import pycuda.autoinit as context
43
+ import json
44
+
45
+ from contextlib import contextmanager
46
+
47
+ import io
48
+ import tempfile
49
+
50
+ SERVICE_LOGGING_FORMAT = (
51
+ "[{filename:s}][{funcName:s}:{lineno:d}]" + "[{levelname:s}] {message:s}"
52
+ )
53
+ SERVICE_LOGGING_STREAM = sys.stdout
54
+
55
+
56
+ def get_logger(logger_name, log_level="info"):
57
+ SERVICE_LOGGING_LEVEL = getattr(logging, log_level.upper(), None)
58
+
59
+ logger = logging.getLogger(logger_name)
60
+ logger.setLevel(SERVICE_LOGGING_LEVEL)
61
+ ch = logging.StreamHandler(SERVICE_LOGGING_STREAM)
62
+ formatter = logging.Formatter(SERVICE_LOGGING_FORMAT, style="{")
63
+ ch.setFormatter(formatter)
64
+ ch.setLevel(SERVICE_LOGGING_LEVEL)
65
+ logger.addHandler(ch)
66
+ logger.propagate = False
67
+
68
+ return logger
69
+
70
+
71
+ logger = get_logger(__file__)
72
+
73
+
74
+ def cast_address_to_1d_bytearray(base_address, size):
75
+ return np.ctypeslib.as_array(C.cast(base_address, C.POINTER(C.c_uint8)),
76
+ shape=(size,))
77
+
78
+
79
+ from contextlib import contextmanager
80
+ import ctypes
81
+ import io
82
+ import os, sys
83
+ import tempfile
84
+
85
+ class AppCAI:
86
+ def __init__(self, shape, stride, typestr, gpualloc):
87
+ shape_int = tuple([int(x) for x in shape])
88
+ stride_int = tuple([int(x) for x in stride])
89
+ self.__cuda_array_interface__ = {"shape": shape_int, "strides": stride_int, "data": (int(gpualloc), False),
90
+ "typestr": typestr, "version": 3}
91
+
92
+
93
+ class AppFrame:
94
+ def __init__(self, width, height, format):
95
+ if format == "NV12":
96
+ nv12_frame_size = int(width * height * 3 / 2)
97
+ self.gpuAlloc = cuda.mem_alloc(nv12_frame_size)
98
+ self.cai = []
99
+ self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", self.gpuAlloc))
100
+ chroma_alloc = int(self.gpuAlloc) + width * height
101
+ self.cai.append(AppCAI((int(height / 2), int(width / 2), 2), (width, 2, 1), "|u1", chroma_alloc))
102
+ self.frameSize = nv12_frame_size
103
+ if format == "ARGB" or format == "ABGR":
104
+ self.frameSize = width * height * 4
105
+ self.gpuAlloc = cuda.mem_alloc(self.frameSize)
106
+ self.cai = AppCAI((height, width, 4), (4 * width, 4, 1), "|u1", self.gpuAlloc)
107
+ if format == "YUV444":
108
+ self.frameSize = width * height * 3
109
+ self.gpuAlloc = cuda.mem_alloc(self.frameSize)
110
+ self.cai = []
111
+ self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", self.gpuAlloc))
112
+ self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", int(self.gpuAlloc) + width * height))
113
+ self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", int(self.gpuAlloc) + 2 * width * height))
114
+ if format == "YUV420":
115
+ self.frameSize = int(width * height * 3 / 2)
116
+ self.gpuAlloc = cuda.mem_alloc(self.frameSize)
117
+ self.cai = []
118
+ self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", self.gpuAlloc))
119
+ self.cai.append(
120
+ AppCAI((height / 2, width / 2, 1), (width / 2, 1, 1), "|u1", int(self.gpuAlloc) + width * height))
121
+ self.cai.append(AppCAI((height / 2, width / 2, 1), (width / 2, 1, 1), "|u1",
122
+ int(self.gpuAlloc) + width * height + width / 2 * height / 2))
123
+ if format == "P010" or format == "YUV420_10BIT":
124
+ self.frameSize = int(width * height * 3 / 2 * 2)
125
+ self.gpuAlloc = cuda.mem_alloc(self.frameSize)
126
+ self.cai = []
127
+ self.cai.append(AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", self.gpuAlloc))
128
+ chroma_alloc = int(self.gpuAlloc) + width * height * 2
129
+ self.cai.append(AppCAI((int(height / 2), int(width / 2), 2), (width*2, 2, 1), "|u2", chroma_alloc))
130
+ if format == "P016" or format == "YUV444_16BIT":
131
+ self.frameSize = int(width * height * 3 * 2)
132
+ self.gpuAlloc = cuda.mem_alloc(self.frameSize)
133
+ self.cai = []
134
+ self.cai.append(AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", self.gpuAlloc))
135
+ self.cai.append(
136
+ AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", int(self.gpuAlloc) + width * height * 2))
137
+ self.cai.append(
138
+ AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", int(self.gpuAlloc) + width * height * 4))
139
+
140
+ if format == "NV16":
141
+ self.frameSize = width * height * 2
142
+ self.gpuAlloc = cuda.mem_alloc(self.frameSize)
143
+ self.cai = []
144
+ self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", self.gpuAlloc))
145
+ self.cai.append(AppCAI((height, width, 1), (width, 1, 1 ), "|u1", int(self.gpuAlloc) + width * height))
146
+
147
+ if format == "P210":
148
+ self.frameSize = width * height * 2 * 2
149
+ self.gpuAlloc = cuda.mem_alloc(self.frameSize)
150
+ self.cai = []
151
+ self.cai.append(AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", self.gpuAlloc))
152
+ self.cai.append(AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", int(self.gpuAlloc) + width * height * 2))
153
+
154
+
155
+
156
+ def cuda(self):
157
+ return self.cai
158
+
159
+
160
+ class AppFramePerf:
161
+ def __init__(self, width, height, format, dataptr, frame_idx):
162
+ if format == "NV12":
163
+ nv12_frame_size = int(width * height * 3 / 2)
164
+ self.gpuAlloc = int(dataptr) + (frame_idx * nv12_frame_size)
165
+ self.cai = []
166
+ self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", self.gpuAlloc))
167
+ chroma_alloc = int(self.gpuAlloc) + width * height
168
+ self.cai.append(AppCAI((int(height / 2), int(width / 2), 2), (width, 2, 1), "|u1", chroma_alloc))
169
+ self.frameSize = nv12_frame_size
170
+ if format == "ARGB" or format == "ABGR":
171
+ self.frameSize = width * height * 4
172
+ self.gpuAlloc = int(dataptr) + (frame_idx * self.frameSize)
173
+ self.cai = AppCAI((height, width, 4), (4 * width, 4, 1), "|u1", self.gpuAlloc)
174
+ if format == "YUV444":
175
+ self.frameSize = width * height * 3
176
+ self.gpuAlloc = int(dataptr) + (frame_idx * self.frameSize)
177
+ self.cai = []
178
+ self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", self.gpuAlloc))
179
+ self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", int(self.gpuAlloc) + width * height))
180
+ self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", int(self.gpuAlloc) + 2 * width * height))
181
+ if format == "YUV420":
182
+ self.frameSize = int(width * height * 3 / 2)
183
+ self.gpuAlloc = int(dataptr) + (frame_idx * self.frameSize)
184
+ self.cai = []
185
+ self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", self.gpuAlloc))
186
+ self.cai.append(
187
+ AppCAI((height / 2, width / 2, 1), (width / 2, 1, 1), "|u1", int(self.gpuAlloc) + width * height))
188
+ self.cai.append(AppCAI((height / 2, width / 2, 1), (width / 2, 1, 1), "|u1",
189
+ int(self.gpuAlloc) + width * height + width / 2 * height / 2))
190
+ if format == "P010" or format == "YUV420_10BIT":
191
+ self.frameSize = int(width * height * 3 / 2 * 2)
192
+ self.gpuAlloc = int(dataptr) + (frame_idx * self.frameSize)
193
+ self.cai = []
194
+ self.cai.append(AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", self.gpuAlloc))
195
+ chroma_alloc = int(self.gpuAlloc) + width * height * 2
196
+ self.cai.append(AppCAI((int(height / 2), int(width / 2), 2), (width*2, 2, 1), "|u2", chroma_alloc))
197
+ if format == "P016" or format == "YUV444_16BIT":
198
+ self.frameSize = int(width * height * 3 * 2)
199
+ self.gpuAlloc = int(dataptr) + (frame_idx * self.frameSize)
200
+ self.cai = []
201
+ self.cai.append(AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", self.gpuAlloc))
202
+ self.cai.append(
203
+ AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", int(self.gpuAlloc) + width * height * 2))
204
+ self.cai.append(
205
+ AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", int(self.gpuAlloc) + width * height * 4))
206
+ if format == "NV16":
207
+ self.frameSize = width * height * 2
208
+ self.gpuAlloc = int(dataptr) + (frame_idx * self.frameSize)
209
+ self.cai = []
210
+ self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", self.gpuAlloc))
211
+ self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", int(self.gpuAlloc) + width * height))
212
+ if format == "P210":
213
+ self.frameSize = width * height * 2 * 2
214
+ self.gpuAlloc = int(dataptr) + (frame_idx * self.frameSize)
215
+ self.cai = []
216
+ self.cai.append(AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", self.gpuAlloc))
217
+ self.cai.append(AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", int(self.gpuAlloc) + width * height * 2))
218
+
219
+ def cuda(self):
220
+ return self.cai
221
+
222
+
223
+ def FetchGPUFrame(input_frame_list, GetCPUFrameFunc, num_frames):
224
+ for i in range(num_frames):
225
+ n = i % len(input_frame_list)
226
+ raw_frame = GetCPUFrameFunc()
227
+ if not raw_frame.size:
228
+ return
229
+ cuda.memcpy_htod(input_frame_list[n].gpuAlloc, raw_frame)
230
+ cuda.Context.synchronize()
231
+ yield input_frame_list[n]
232
+
233
+
234
+
235
+ def FetchCPUFrame(dec_file, frame_size):
236
+ def InnerFunc():
237
+ return np.fromfile(dec_file, np.uint8, count=frame_size)
238
+
239
+ return InnerFunc
240
+
241
+ def GetChromaFormat(demuxer):
242
+ strFormat = "NV12"
243
+
244
+ bitdepth = demuxer.BitDepth()
245
+ chromaformat = demuxer.ChromaFormat()
246
+
247
+ #print (" bitdepth : " + str(bitdepth))
248
+ #print (" chromaformat : " + str(chromaformat))
249
+
250
+ if str(chromaformat) == str("cudaVideoChromaFormat.444"):
251
+ if bitdepth == 10:
252
+ strFormat = "YUV444_10BIT"
253
+ elif bitdepth == 16:
254
+ strFormat = "YUV444_16BIT"
255
+ elif bitdepth == 12:
256
+ strFormat = "YUV444_16BIT"
257
+ print ("Unsupported bitdepth for YUV444 12BIT. It will be treated as YUV444_16BIT" )
258
+ elif bitdepth == 8:
259
+ strFormat = "YUV444"
260
+ elif str(chromaformat) == str("cudaVideoChromaFormat.420"):
261
+ if bitdepth == 8:
262
+ strFormat = "NV12"
263
+ elif bitdepth == 10:
264
+ strFormat = "YUV420_10BIT"
265
+ elif bitdepth == 16:
266
+ strFormat = "P016"
267
+ elif str(chromaformat) == str("cudaVideoChromaFormat.422"):
268
+ if bitdepth == 10:
269
+ strFormat = "YUV422_10BIT"
270
+ elif bitdepth == 16:
271
+ strFormat = "YUV422_16BIT"
272
+ elif bitdepth == 8:
273
+ strFormat = "YUV422"
274
+
275
+ #print (" strFormat : " + str(strFormat))
276
+
277
+ return strFormat
278
+
279
+
280
+ def GetVideoCodec(demuxer):
281
+ codec=str(demuxer.GetNvCodecId())
282
+ #print (" codec : " + str(codec))
283
+
284
+ # Common prefix to remove
285
+ common_prefix = "cudaVideoCodec."
286
+
287
+ strCodec = codec.removeprefix(common_prefix)
288
+
289
+ #print (" codec : " + str(strCodec))
290
+ return str(strCodec)
291
+
292
+
293
+ def get_frame_data(frame, use_device_memory=False):
294
+ """
295
+ Get raw frame data from a decoded frame.
296
+
297
+ Args:
298
+ frame: DecodedFrame object from PyNvVideoCodec
299
+ use_device_memory: Boolean indicating if frame data is in device memory
300
+
301
+ Returns:
302
+ Raw frame data (numpy array if device memory, bytearray if host memory)
303
+ """
304
+ raw_frame = np.ndarray(shape=frame.framesize(), dtype=np.uint8)
305
+ luma_base_addr = frame.GetPtrToPlane(0)
306
+
307
+ if use_device_memory:
308
+ cuda.memcpy_dtoh(raw_frame, luma_base_addr)
309
+ return raw_frame
310
+ else:
311
+ return cast_address_to_1d_bytearray(base_address=luma_base_addr, size=frame.framesize())
312
+
313
+ def convert_frames_to_torch(decoded_frames: List, color_format: nvc.OutputColorType = nvc.OutputColorType.RGB) -> torch.Tensor:
314
+ """
315
+ Convert batched frames from decoder to torch tensor.
316
+
317
+ Args:
318
+ decoded_frames: List of decoded frames from PyNvVideoCodec
319
+ color_format: OutputColorType enum (RGB or RGBP)
320
+
321
+ Returns:
322
+ torch.Tensor: Stacked tensor of shape (T, H, W, C) where T is number of frames
323
+ """
324
+ if not decoded_frames:
325
+ raise ValueError("No frames provided for conversion")
326
+
327
+ try:
328
+ if color_format == nvc.OutputColorType.RGB:
329
+ # For RGB format, frames are already in HWC format
330
+ torch_frames = [torch.from_dlpack(frame) for frame in decoded_frames]
331
+ batched_tensor = torch.stack(torch_frames)
332
+
333
+ elif color_format == nvc.OutputColorType.RGBP:
334
+ # For RGBP format, frames are in planar format
335
+ torch_frames = []
336
+ for frame in decoded_frames:
337
+ # Convert frame to torch tensor
338
+ planar_tensor = torch.from_dlpack(frame)
339
+
340
+ # For RGBP, we get a tensor in shape (H*3, W)
341
+ if len(planar_tensor.shape) == 2:
342
+ height = planar_tensor.shape[0] // 3
343
+ width = planar_tensor.shape[1]
344
+
345
+ # Split into R,G,B planes
346
+ r_plane = planar_tensor[:height]
347
+ g_plane = planar_tensor[height:2*height]
348
+ b_plane = planar_tensor[2*height:3*height]
349
+
350
+ # Stack planes along new dimension to get (H,W,3)
351
+ frame_tensor = torch.stack([r_plane, g_plane, b_plane], dim=-1)
352
+ else:
353
+ frame_tensor = planar_tensor
354
+
355
+ torch_frames.append(frame_tensor)
356
+
357
+ batched_tensor = torch.stack(torch_frames)
358
+ else:
359
+ raise ValueError(f"Unsupported color format: {color_format}. Only RGB and RGBP formats are supported.")
360
+
361
+ return batched_tensor
362
+
363
+ except Exception as e:
364
+ print(f"Error converting frames to torch tensor: {e}")
365
+ raise
366
+
367
+ def frame_to_numpy(frame, color_format: nvc.OutputColorType, use_device_memory=False, width=None, height=None):
368
+ """
369
+ Convert a decoded frame to an RGB numpy array suitable for display.
370
+
371
+ Args:
372
+ frame: DecodedFrame object from PyNvVideoCodec
373
+ color_format: nvc.OutputColorType enum (RGB or RGBP)
374
+ use_device_memory: Boolean indicating if frame data is in device memory
375
+ width: Optional frame width (if None, uses frame.width)
376
+ height: Optional frame height (if None, uses frame.height)
377
+
378
+ Returns:
379
+ numpy.ndarray: RGB frame data as a numpy array in HWC format, ready for display
380
+ """
381
+
382
+ # Get frame data using the helper function
383
+ frame_data = get_frame_data(frame, use_device_memory)
384
+
385
+ # Convert to numpy array
386
+ frame_array = np.array(frame_data)
387
+
388
+ # Handle different color formats
389
+ if color_format == nvc.OutputColorType.RGB:
390
+ # For RGB format, we expect 3 channels in HWC format
391
+ return frame_array.reshape(height, width, 3)
392
+ elif color_format == nvc.OutputColorType.RGBP:
393
+ # For planar RGB format, each plane is height*width
394
+ plane_size = height * width
395
+ if len(frame_array) != 3 * plane_size:
396
+ raise ValueError(f"RGBP format expects {3 * plane_size} bytes but got {len(frame_array)}")
397
+ r_plane = frame_array[:plane_size].reshape(height, width)
398
+ g_plane = frame_array[plane_size:2*plane_size].reshape(height, width)
399
+ b_plane = frame_array[2*plane_size:].reshape(height, width)
400
+ # Stack the planes to create HWC format
401
+ return np.dstack((r_plane, g_plane, b_plane))
402
+ else:
403
+ raise ValueError(f"Unsupported color format: {color_format}. Only RGB and RGBP formats are supported.")
404
+
405
+
@@ -0,0 +1,36 @@
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
+ Utility modules for PyNvVideoCodec samples.
26
+
27
+ This package contains shared functionality used across multiple samples:
28
+ - Utils.py: Common video codec utilities
29
+ - decode_parser.py: Command line argument parsing for decoder samples
30
+ - decode_stats_writer.py: Decode statistics extraction and analysis
31
+ - sei_message_parser.py: SEI message extraction and parsing
32
+ - transcode_parser.py: Transcoder command line argument parsing
33
+ - encode_parser.py: Encoder command line argument parsing
34
+ - frame_utils.py: Helper module for frame and memory management in video encoding/decoding.
35
+ - encode_parallel_utils.py: Parallel utilities for encoding
36
+ """