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,338 @@
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 sys
25
+ import argparse
26
+ import numpy as np
27
+ import pickle
28
+ import ctypes
29
+ from pathlib import Path
30
+ import pycuda.driver as cuda
31
+ import PyNvVideoCodec as nvc
32
+ from os.path import join, dirname, abspath
33
+
34
+ # Add the parent directory to Python path in a way that works from any working directory
35
+ current_dir = dirname(abspath(__file__))
36
+ parent_dir = dirname(current_dir)
37
+ if parent_dir not in sys.path:
38
+ sys.path.append(parent_dir)
39
+
40
+ from Utils import cast_address_to_1d_bytearray
41
+
42
+ # Constants
43
+ MAX_CLOCK_TS = 3
44
+
45
+ class TIMECODESET(ctypes.Structure):
46
+ """Structure for time code set information."""
47
+ _fields_ = [
48
+ ("time_offset_value", ctypes.c_uint32), # unsigned int
49
+ ("n_frames", ctypes.c_uint16), # unsigned short
50
+ ("clock_timestamp_flag", ctypes.c_uint8), # unsigned char
51
+ ("units_field_based_flag", ctypes.c_uint8), # unsigned char
52
+ ("counting_type", ctypes.c_uint8), # unsigned char
53
+ ("full_timestamp_flag", ctypes.c_uint8), # unsigned char
54
+ ("discontinuity_flag", ctypes.c_uint8), # unsigned char
55
+ ("cnt_dropped_flag", ctypes.c_uint8), # unsigned char
56
+ ("seconds_value", ctypes.c_uint8), # unsigned char
57
+ ("minutes_value", ctypes.c_uint8), # unsigned char
58
+ ("hours_value", ctypes.c_uint8), # unsigned char
59
+ ("seconds_flag", ctypes.c_uint8), # unsigned char
60
+ ("minutes_flag", ctypes.c_uint8), # unsigned char
61
+ ("hours_flag", ctypes.c_uint8), # unsigned char
62
+ ("time_offset_length", ctypes.c_uint8), # unsigned char
63
+ ("reserved", ctypes.c_uint8), # unsigned char
64
+ ]
65
+
66
+ def __repr__(self):
67
+ return (
68
+ "TIMECODESET(\n"
69
+ f" time_offset_value={self.time_offset_value},\n"
70
+ f" n_frames={self.n_frames},\n"
71
+ f" clock_timestamp_flag={self.clock_timestamp_flag},\n"
72
+ f" units_field_based_flag={self.units_field_based_flag},\n"
73
+ f" counting_type={self.counting_type},\n"
74
+ f" full_timestamp_flag={self.full_timestamp_flag},\n"
75
+ f" discontinuity_flag={self.discontinuity_flag},\n"
76
+ f" cnt_dropped_flag={self.cnt_dropped_flag},\n"
77
+ f" seconds_value={self.seconds_value},\n"
78
+ f" minutes_value={self.minutes_value},\n"
79
+ f" hours_value={self.hours_value},\n"
80
+ f" seconds_flag={self.seconds_flag},\n"
81
+ f" minutes_flag={self.minutes_flag},\n"
82
+ f" hours_flag={self.hours_flag},\n"
83
+ f" time_offset_length={self.time_offset_length},\n"
84
+ f" reserved={self.reserved}\n"
85
+ ")"
86
+ )
87
+
88
+ class TIMECODE(ctypes.Structure):
89
+ """Structure for time code information."""
90
+ _fields_ = [
91
+ ("time_code_set", TIMECODESET * MAX_CLOCK_TS), # Array of TIMECODESET
92
+ ("num_clock_ts", ctypes.c_uint8), # unsigned char
93
+ ]
94
+
95
+ def __repr__(self):
96
+ time_code_set_repr = ",\n ".join(
97
+ repr(self.time_code_set[i]) for i in range(self.num_clock_ts)
98
+ )
99
+ return (
100
+ "TIMECODE(\n"
101
+ f" time_code_set=[\n {time_code_set_repr}\n ],\n"
102
+ f" num_clock_ts={self.num_clock_ts}\n"
103
+ ")"
104
+ )
105
+
106
+ class SEICONTENTLIGHTLEVELINFO(ctypes.Structure):
107
+ """Structure for content light level information."""
108
+ _fields_ = [
109
+ ("max_content_light_level", ctypes.c_uint16), # unsigned short
110
+ ("max_pic_average_light_level", ctypes.c_uint16), # unsigned short
111
+ ("reserved", ctypes.c_uint32), # unsigned int
112
+ ]
113
+
114
+ def __repr__(self):
115
+ return (
116
+ "SEICONTENTLIGHTLEVELINFO(\n"
117
+ f" max_content_light_level={self.max_content_light_level},\n"
118
+ f" max_pic_average_light_level={self.max_pic_average_light_level},\n"
119
+ f" reserved={self.reserved}\n"
120
+ ")"
121
+ )
122
+
123
+ class SEIMASTERINGDISPLAYINFO(ctypes.Structure):
124
+ """Structure for mastering display information."""
125
+ _fields_ = [
126
+ ("display_primaries_x", ctypes.c_uint16 * 3), # Array of 3 unsigned short
127
+ ("display_primaries_y", ctypes.c_uint16 * 3), # Array of 3 unsigned short
128
+ ("white_point_x", ctypes.c_uint16), # unsigned short
129
+ ("white_point_y", ctypes.c_uint16), # unsigned short
130
+ ("max_display_mastering_luminance", ctypes.c_uint32), # unsigned int
131
+ ("min_display_mastering_luminance", ctypes.c_uint32), # unsigned int
132
+ ]
133
+
134
+ def __repr__(self):
135
+ return (
136
+ "SEIMASTERINGDISPLAYINFO(\n"
137
+ f" display_primaries_x={list(self.display_primaries_x)},\n"
138
+ f" display_primaries_y={list(self.display_primaries_y)},\n"
139
+ f" white_point_x={self.white_point_x},\n"
140
+ f" white_point_y={self.white_point_y},\n"
141
+ f" max_display_mastering_luminance={self.max_display_mastering_luminance},\n"
142
+ f" min_display_mastering_luminance={self.min_display_mastering_luminance}\n"
143
+ ")"
144
+ )
145
+
146
+ class TIMECODEMPEG2(ctypes.Structure):
147
+ """Structure for MPEG2 time code information."""
148
+ _fields_ = [
149
+ ("drop_frame_flag", ctypes.c_uint8), # unsigned char
150
+ ("time_code_hours", ctypes.c_uint8), # unsigned char
151
+ ("time_code_minutes", ctypes.c_uint8), # unsigned char
152
+ ("marker_bit", ctypes.c_uint8), # unsigned char
153
+ ("time_code_seconds", ctypes.c_uint8), # unsigned char
154
+ ("time_code_pictures", ctypes.c_uint8), # unsigned char
155
+ ]
156
+
157
+ def __repr__(self):
158
+ return (
159
+ "TIMECODEMPEG2(\n"
160
+ f" drop_frame_flag={self.drop_frame_flag},\n"
161
+ f" time_code_hours={self.time_code_hours},\n"
162
+ f" time_code_minutes={self.time_code_minutes},\n"
163
+ f" marker_bit={self.marker_bit},\n"
164
+ f" time_code_seconds={self.time_code_seconds},\n"
165
+ f" time_code_pictures={self.time_code_pictures}\n"
166
+ ")"
167
+ )
168
+
169
+ class SEIALTERNATIVETRANSFERCHARACTERISTICS(ctypes.Structure):
170
+ """Structure for alternative transfer characteristics."""
171
+ _fields_ = [
172
+ ("preferred_transfer_characteristics", ctypes.c_uint8), # unsigned char
173
+ ]
174
+
175
+ def __repr__(self):
176
+ return f"SEIALTERNATIVETRANSFERCHARACTERISTICS(preferred_transfer_characteristics={self.preferred_transfer_characteristics})"
177
+
178
+ def decode(gpu_id, enc_file_path, dec_file_path, sei_file_path, use_device_memory):
179
+ """
180
+ Function to decode media file, write raw frames and SEI messages into output files.
181
+
182
+ Parameters:
183
+ gpu_id (int): Ordinal of GPU to use
184
+ enc_file_path (str): Path to file to be decoded
185
+ dec_file_path (str): Path to output file for raw frames
186
+ sei_file_path (str): Path to output file for SEI messages
187
+ use_device_memory (int): If set to 1, output decoded frame is CUDeviceptr wrapped in CUDA Array Interface
188
+
189
+ Returns:
190
+ None
191
+ """
192
+ cuda_ctx = None
193
+
194
+ # Open files for storing SEI data
195
+ file_message = open(sei_file_path, "wb")
196
+ script_dir = dirname(abspath(__file__))
197
+ sei_type_message_path = join(script_dir, "sei_type_message.bin")
198
+ file_type_message = open(sei_type_message_path, "wb")
199
+
200
+ try:
201
+ device_id = gpu_id
202
+ cuda_device = cuda.Device(device_id) # pyright: ignore[reportAttributeAccessIssue]
203
+ cuda_ctx = cuda_device.retain_primary_context()
204
+ cuda_ctx.push()
205
+ cuda_stream = cuda.Stream()
206
+ nv_dmx = nvc.CreateDemuxer(filename=enc_file_path)
207
+ nv_dec = nvc.CreateDecoder(
208
+ gpuid=gpu_id,
209
+ codec=nv_dmx.GetNvCodecId(),
210
+ cudacontext=cuda_ctx.handle,
211
+ cudastream=cuda_stream.handle,
212
+ usedevicememory=use_device_memory,
213
+ enableSEIMessage=1
214
+ )
215
+
216
+ decoded_frame_size = 0
217
+ raw_frame = None
218
+ seq_triggered = False
219
+
220
+ print(f"FPS = {nv_dmx.FrameRate()}")
221
+
222
+ sei_message_found = False
223
+ with open(dec_file_path, "wb") as decFile:
224
+ for packet in nv_dmx:
225
+ # Decode returns a list of packets, range of this list is from [0, size of (decode picture buffer)]
226
+ # size of (decode picture buffer) depends on GPU, for Turing series its 8
227
+ for decoded_frame in nv_dec.Decode(packet):
228
+ # 'decoded_frame' contains list of views implementing cuda array interface
229
+ # for nv12, it would contain 2 views for each plane and two planes would be contiguous
230
+ if not seq_triggered:
231
+ decoded_frame_size = nv_dec.GetFrameSize()
232
+ raw_frame = np.ndarray(shape=decoded_frame_size, dtype=np.uint8)
233
+ seq_triggered = True
234
+
235
+ luma_base_addr = decoded_frame.GetPtrToPlane(0)
236
+ if use_device_memory:
237
+ cuda.memcpy_dtoh(raw_frame, luma_base_addr)
238
+ bits = bytearray(raw_frame)
239
+ decFile.write(bits)
240
+ else:
241
+ new_array = cast_address_to_1d_bytearray(
242
+ base_address=luma_base_addr,
243
+ size=decoded_frame.framesize()
244
+ )
245
+ decFile.write(bytearray(new_array))
246
+
247
+ # Process SEI messages
248
+ seiMessage = decoded_frame.getSEIMessage()
249
+ if seiMessage:
250
+ sei_message_found = True
251
+ for sei_info, sei_message in seiMessage:
252
+ sei_type = sei_info["sei_type"]
253
+ sei_uncompressed = sei_info["sei_uncompressed"]
254
+
255
+ if sei_uncompressed == 1:
256
+ buffer = (ctypes.c_ubyte * len(sei_message))(*sei_message)
257
+ sei_struct = None
258
+
259
+ # Handle different SEI message types
260
+ if sei_type in (nvc.SEI_TYPE.TIME_CODE_H264, nvc.SEI_TYPE.TIME_CODE):
261
+ sei_struct = ctypes.cast(
262
+ buffer,
263
+ ctypes.POINTER(TIMECODEMPEG2 if nv_dmx.GetNvCodecId() == nvc.cudaVideoCodec.MPEG2 else TIMECODE)
264
+ ).contents
265
+ elif sei_type == nvc.SEI_TYPE.MASTERING_DISPLAY_COLOR_VOLUME:
266
+ sei_struct = ctypes.cast(buffer, ctypes.POINTER(SEIMASTERINGDISPLAYINFO)).contents
267
+ elif sei_type == nvc.SEI_TYPE.CONTENT_LIGHT_LEVEL_INFO:
268
+ sei_struct = ctypes.cast(buffer, ctypes.POINTER(SEICONTENTLIGHTLEVELINFO)).contents
269
+ elif sei_type == nvc.SEI_TYPE.ALTERNATIVE_TRANSFER_CHARACTERISTICS:
270
+ sei_struct = ctypes.cast(buffer, ctypes.POINTER(SEIALTERNATIVETRANSFERCHARACTERISTICS)).contents
271
+
272
+ if sei_struct:
273
+ print(sei_struct)
274
+
275
+ file_message.write(bytearray(sei_message))
276
+ pickle.dump(seiMessage, file_type_message)
277
+ print(f"SEI message written to {sei_file_path}")
278
+ if not sei_message_found:
279
+ print("No SEI message found")
280
+
281
+ except nvc.PyNvVCExceptionUnsupported as e:
282
+ print(f"CreateDecoder failure: {e}")
283
+ except Exception as e:
284
+ print(f"An unexpected error occurred: {e}")
285
+ finally:
286
+ file_message.close()
287
+ file_type_message.close()
288
+ if cuda_ctx is not None:
289
+ cuda_ctx.pop()
290
+
291
+ if __name__ == "__main__":
292
+ parser = argparse.ArgumentParser(
293
+ description="This sample application demonstrates decoding media files and extracting SEI messages."
294
+ )
295
+ parser.add_argument(
296
+ "-g", "--gpu_id",
297
+ type=int,
298
+ default=0,
299
+ help="Check nvidia-smi for available GPUs. Default: 0"
300
+ )
301
+ parser.add_argument(
302
+ "-i", "--encoded_file_path",
303
+ type=Path,
304
+ required=True,
305
+ help="Encoded video file (read from)"
306
+ )
307
+ parser.add_argument(
308
+ "-o", "--raw_file_path",
309
+ type=Path,
310
+ help="Raw NV12 video file (write to). Default: <input_file_name>.yuv"
311
+ )
312
+ parser.add_argument(
313
+ "-f", "--sei_file_path",
314
+ type=Path,
315
+ default="sei_message.bin",
316
+ help="SEI binary file (write to). Default: sei_message.bin"
317
+ )
318
+ parser.add_argument(
319
+ "-d", "--use_device_memory",
320
+ type=int,
321
+ default=1,
322
+ help="Decoder output surface is in device memory (1) else in host memory (0). Default is 1."
323
+ )
324
+
325
+ args = parser.parse_args()
326
+
327
+ # Set default raw_file_path if not provided
328
+ if args.raw_file_path is None:
329
+ input_path = Path(args.encoded_file_path)
330
+ args.raw_file_path = input_path.with_suffix('.yuv')
331
+
332
+ decode(
333
+ args.gpu_id,
334
+ args.encoded_file_path.as_posix(),
335
+ args.raw_file_path.as_posix(),
336
+ args.sei_file_path.as_posix(),
337
+ args.use_device_memory
338
+ )
@@ -0,0 +1,185 @@
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
+ from pathlib import Path
27
+ import pycuda.driver as cuda
28
+ import PyNvVideoCodec as nvc
29
+ import numpy as np
30
+ import pycuda.autoinit as context
31
+ import sys
32
+ from os.path import join, dirname, abspath
33
+
34
+ # Add the parent directory to Python path in a way that works from any working directory
35
+ current_dir = dirname(abspath(__file__))
36
+ parent_dir = dirname(current_dir)
37
+ if parent_dir not in sys.path:
38
+ sys.path.append(parent_dir)
39
+
40
+ from Utils import cast_address_to_1d_bytearray
41
+
42
+
43
+ class VideoStreamFeeder:
44
+ """
45
+ Class to handle feeding video data in chunks to the demuxer.
46
+
47
+ This class reads a video file into memory and provides a method to feed
48
+ chunks of data to the demuxer buffer.
49
+ """
50
+ def __init__(self, file_path):
51
+ """
52
+ Initialize the VideoStreamFeeder with a video file.
53
+
54
+ Args:
55
+ file_path (str): Path to the video file to be read
56
+ """
57
+ with open(file_path, 'rb') as f:
58
+ self.video_buffer = bytearray(f.read())
59
+ self.current_pos = 0
60
+ self.bytes_remaining = len(self.video_buffer)
61
+ self.chunk_size = 0
62
+
63
+ def feed_chunk(self, demuxer_buffer):
64
+ """
65
+ Feed next chunk of video data to demuxer buffer.
66
+
67
+ Args:
68
+ demuxer_buffer: Pre-allocated buffer provided by demuxer
69
+
70
+ Returns:
71
+ int: Number of bytes copied to buffer, 0 if no more data
72
+ """
73
+ buffer_capacity = len(demuxer_buffer)
74
+
75
+ if self.bytes_remaining < buffer_capacity:
76
+ self.chunk_size = self.bytes_remaining
77
+ else:
78
+ self.chunk_size = buffer_capacity
79
+
80
+ if self.chunk_size == 0:
81
+ return 0
82
+
83
+ demuxer_buffer[:] = self.video_buffer[self.current_pos:self.current_pos + self.chunk_size]
84
+
85
+ self.current_pos += self.chunk_size
86
+ self.bytes_remaining -= self.chunk_size
87
+ return self.chunk_size
88
+
89
+
90
+ def demux_from_byte_array(input_file, yuv_file, use_device_memory, gpu_id):
91
+ """
92
+ Implement buffer-based pipeline that reads the input file in chunks.
93
+
94
+ This function demonstrates how to decode video by processing data directly
95
+ from memory buffers instead of reading from disk.
96
+
97
+ Parameters:
98
+ input_file (str): Path to the input video file to be decoded
99
+ yuv_file (str): Path where the buffer-based pipeline output will be saved
100
+ use_device_memory (int): If set to 1, output decoded frame is CUDeviceptr wrapped in CUDA Array Interface
101
+
102
+ Returns:
103
+ None: Decoded frames are written to a raw file.
104
+ """
105
+ print("Starting buffer-based decoding...")
106
+ data_feeder = VideoStreamFeeder(input_file)
107
+ buffer_demuxer = nvc.CreateDemuxer(data_feeder.feed_chunk)
108
+
109
+ buffer_decoder = nvc.CreateDecoder(
110
+ gpuid=gpu_id,
111
+ codec=buffer_demuxer.GetNvCodecId(),
112
+ cudacontext=0,
113
+ cudastream=0,
114
+ usedevicememory=use_device_memory
115
+ )
116
+
117
+ seq_triggered = False
118
+ decoded_frame_size = 0
119
+ raw_frame = None
120
+
121
+ with open(yuv_file, 'wb') as decFile:
122
+ for packet in buffer_demuxer:
123
+ for decoded_frame in buffer_decoder.Decode(packet):
124
+ if not seq_triggered:
125
+ decoded_frame_size = buffer_decoder.GetFrameSize()
126
+ raw_frame = np.ndarray(shape=decoded_frame_size, dtype=np.uint8)
127
+ seq_triggered = True
128
+
129
+ luma_base_addr = decoded_frame.GetPtrToPlane(0)
130
+ if use_device_memory:
131
+ cuda.memcpy_dtoh(raw_frame, luma_base_addr)
132
+ decFile.write(bytearray(raw_frame))
133
+ else:
134
+ new_array = cast_address_to_1d_bytearray(
135
+ base_address=luma_base_addr,
136
+ size=decoded_frame.framesize()
137
+ )
138
+ decFile.write(bytearray(new_array))
139
+
140
+ print(f"Frames are saved successfully in {yuv_file}")
141
+
142
+
143
+ if __name__ == "__main__":
144
+ parser = argparse.ArgumentParser(
145
+ description="Demonstrates video demuxing by processing video data directly from memory buffers."
146
+ )
147
+
148
+ parser.add_argument(
149
+ "-i", "--input_file",
150
+ type=Path,
151
+ required=True,
152
+ help="Path to input video file"
153
+ )
154
+ parser.add_argument(
155
+ "-g", "--gpu_id",
156
+ type=int,
157
+ default=0,
158
+ help="Check nvidia-smi for available GPUs. Default: 0"
159
+ )
160
+ parser.add_argument(
161
+ "-o", "--yuv_file_path",
162
+ type=Path,
163
+ help="Path to stream based output yuv file. Default: <input_file_name>.yuv"
164
+ )
165
+ parser.add_argument(
166
+ "-d", "--use_device_memory",
167
+ type=int,
168
+ choices=[0, 1],
169
+ default=1,
170
+ help="Decoder output surface is in device memory (1) else in host memory (0). Default is 1."
171
+ )
172
+
173
+ args = parser.parse_args()
174
+
175
+ # Set default yuv_file_path if not provided
176
+ if args.yuv_file_path is None:
177
+ input_path = Path(args.input_file)
178
+ args.yuv_file_path = input_path.with_suffix('.yuv')
179
+
180
+ demux_from_byte_array(
181
+ args.input_file.as_posix(),
182
+ args.yuv_file_path.as_posix(),
183
+ args.use_device_memory,
184
+ args.gpu_id
185
+ )