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,193 @@
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
+ This sample demonstrates how to extract and parse Supplemental Enhancement Information (SEI) from video streams.
26
+
27
+ It shows how to:
28
+ 1. Access SEI messages from decoded frames and write them to a file
29
+ 2. Parse different SEI message types
30
+
31
+
32
+ SEI messages are additional data embedded in video streams that provide supplementary information:
33
+ - HDR/Display Metadata: Color volume, light levels, and transfer characteristics for HDR content
34
+ - Timecode Data: Frame timing and sequence information
35
+ - Custom Metadata: User-defined data for application-specific needs
36
+
37
+ Common Use Cases:
38
+ - Video Playback: HDR display configuration and color management
39
+ - Content Creation: Frame accurate editing and post-processing
40
+ - Broadcast: Timing synchronization and content identification
41
+ - Custom Applications: Embedding application-specific metadata in the video stream
42
+
43
+
44
+ Usage: python decode_sei_msg.py -i <input_file> -s <sei_file>
45
+ Example: python decode_sei_msg.py -i input.mp4 -s sei_data.bin
46
+
47
+ Arguments:
48
+ -i: Input video file
49
+ -s: Output SEI message file (default: sei_message.bin).
50
+ -st: Output SEI type message file (default: sei_type_message.bin)
51
+ -d: Use device memory (1) or host memory (0) (default: 1)
52
+ -g: GPU ID to use (default: 0)
53
+ '''
54
+
55
+ import sys
56
+ import numpy as np
57
+ import pickle
58
+ import ctypes
59
+ import argparse
60
+ import pycuda.driver as cuda
61
+ import PyNvVideoCodec as nvc
62
+ from os.path import join, dirname, abspath
63
+
64
+ # Add the parent directory to Python path in a way that works from any working directory
65
+ current_dir = dirname(abspath(__file__))
66
+ parent_dir = dirname(current_dir)
67
+ if parent_dir not in sys.path:
68
+ sys.path.append(parent_dir)
69
+
70
+ from utils.decode_parser import parse_sei_args
71
+
72
+ from utils.sei_message_parser import (
73
+ TIMECODE, TIMECODEMPEG2, SEICONTENTLIGHTLEVELINFO,
74
+ SEIMASTERINGDISPLAYINFO, SEIALTERNATIVETRANSFERCHARACTERISTICS
75
+ )
76
+
77
+ def extract_sei_messages(gpu_id, enc_file_path, sei_file_path, sei_type_file_path, use_device_memory):
78
+ """
79
+ Function to extract SEI messages from a video file.
80
+
81
+ This function decodes a video file and extracts SEI messages, producing three output files:
82
+ 1. sei_message.bin - Raw binary SEI messages
83
+ 2. sei_type_message.bin - Pickled SEI type information
84
+
85
+ Parameters:
86
+ gpu_id (int): Ordinal of GPU to use
87
+ enc_file_path (str): Path to file to be decoded
88
+ sei_file_path (str): Path to output file for SEI messages. Sei type message is written to sei_type_message.bin
89
+ sei_type_file_path (str): Path to output file for SEI type messages.
90
+ use_device_memory (int): If set to 1, output decoded frame is CUDeviceptr wrapped in CUDA Array Interface
91
+
92
+ Returns:
93
+ None
94
+ """
95
+ cuda_ctx = None
96
+
97
+ # Open files for storing SEI data
98
+ file_message = open(sei_file_path, "wb")
99
+ file_type_message = open(sei_type_file_path, "wb")
100
+
101
+ try:
102
+ cuda.init()
103
+ device_id = gpu_id
104
+ cuda_device = cuda.Device(device_id) # pyright: ignore[reportAttributeAccessIssue]
105
+ cuda_ctx = cuda_device.retain_primary_context()
106
+ cuda_ctx.push()
107
+ cuda_stream = cuda.Stream()
108
+
109
+ nv_dmx = nvc.CreateDemuxer(filename=enc_file_path)
110
+
111
+ nv_dec = nvc.CreateDecoder(
112
+ gpuid=gpu_id,
113
+ codec=nv_dmx.GetNvCodecId(),
114
+ cudacontext=cuda_ctx.handle,
115
+ cudastream=cuda_stream.handle,
116
+ usedevicememory=use_device_memory,
117
+ enableSEIMessage=1
118
+ )
119
+
120
+ sei_message_found = False
121
+ print(f"FPS = {nv_dmx.FrameRate()}")
122
+
123
+
124
+ for packet in nv_dmx:
125
+ for decoded_frame in nv_dec.Decode(packet):
126
+
127
+ # Process SEI messages
128
+ seiMessage = decoded_frame.getSEIMessage()
129
+ if seiMessage:
130
+ sei_message_found = True
131
+ for sei_info, sei_message in seiMessage:
132
+ sei_type = sei_info["sei_type"]
133
+ sei_uncompressed = sei_info["sei_uncompressed"]
134
+
135
+ if sei_uncompressed == 1:
136
+ buffer = (ctypes.c_ubyte * len(sei_message))(*sei_message)
137
+ sei_struct = None
138
+
139
+ # Handle different SEI message types
140
+ if sei_type in (nvc.SEI_TYPE.TIME_CODE_H264, nvc.SEI_TYPE.TIME_CODE):
141
+ sei_struct = ctypes.cast(
142
+ buffer,
143
+ ctypes.POINTER(TIMECODEMPEG2 if nv_dmx.GetNvCodecId() == nvc.cudaVideoCodec.MPEG2 else TIMECODE)
144
+ ).contents
145
+ elif sei_type == nvc.SEI_TYPE.MASTERING_DISPLAY_COLOR_VOLUME:
146
+ sei_struct = ctypes.cast(buffer, ctypes.POINTER(SEIMASTERINGDISPLAYINFO)).contents
147
+ elif sei_type == nvc.SEI_TYPE.CONTENT_LIGHT_LEVEL_INFO:
148
+ sei_struct = ctypes.cast(buffer, ctypes.POINTER(SEICONTENTLIGHTLEVELINFO)).contents
149
+ elif sei_type == nvc.SEI_TYPE.ALTERNATIVE_TRANSFER_CHARACTERISTICS:
150
+ sei_struct = ctypes.cast(buffer, ctypes.POINTER(SEIALTERNATIVETRANSFERCHARACTERISTICS)).contents
151
+
152
+
153
+ file_message.write(bytearray(sei_message))
154
+ pickle.dump(seiMessage, file_type_message)
155
+
156
+ if sei_message_found:
157
+ print(f"SEI message written to:")
158
+ print(f" Binary data: {sei_file_path}")
159
+ print(f" Type info: {sei_type_file_path}")
160
+ else:
161
+ print("No SEI message found")
162
+
163
+ except nvc.PyNvVCExceptionUnsupported as e:
164
+ print(f"CreateDecoder failure: {e}")
165
+ except Exception as e:
166
+ print(f"An unexpected error occurred: {e}")
167
+ finally:
168
+ file_message.close()
169
+ file_type_message.close()
170
+ if cuda_ctx is not None:
171
+ cuda_ctx.pop()
172
+
173
+ if __name__ == "__main__":
174
+ args = parse_sei_args(
175
+ "This sample application demonstrates extracting SEI messages from video files."
176
+ )
177
+
178
+ print("=" * 60)
179
+ print("Configuration:")
180
+ print(f"Input: {args.encoded_file_path}")
181
+ print(f"SEI Output: {args.sei_file_path}")
182
+ print(f"SEI Type Output: {args.sei_type_file_path}")
183
+ print(f"GPU ID: {args.gpu_id}")
184
+ print(f"Use Device Memory: {args.use_device_memory}")
185
+ print("=" * 60)
186
+
187
+ extract_sei_messages(
188
+ args.gpu_id,
189
+ args.encoded_file_path,
190
+ args.sei_file_path,
191
+ args.sei_type_file_path,
192
+ args.use_device_memory
193
+ )
@@ -0,0 +1,214 @@
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
+ This sample demonstrates advanced video decoding with explicit CUDA resource management.
26
+
27
+ It shows how to:
28
+ 1. Initialize and manage CUDA contexts and streams
29
+ 2. Set up a decoder with custom CUDA resources
30
+ 3. Handle device memory and data transfers
31
+ 4. Clean up CUDA resources properly
32
+
33
+ Key Learning Outcomes:
34
+ 1. Using explicit CUDA context management for decoder creation. This enables the application to have full control over the CUDA resources.
35
+ 2. Proper CUDA resource cleanup order: decoder → demuxer → stream → context
36
+ 3. Switching between device memory (zero-copy) and host memory modes (use_device_memory)
37
+ 4. Querying hardware capabilities like number of decoder engines
38
+
39
+
40
+ Usage: python decode_with_cuda_control.py -i <input_video_file> -o <output_file> -d <use_device_memory>
41
+ Example: python decode_with_cuda_control.py -i input.mp4 -o output.yuv -d 1
42
+
43
+ Arguments:
44
+ -i: Input video file
45
+ -o: Output raw video file (default: <input_name>.yuv)
46
+ -d: Use device memory (1) or host memory (0) (default: 1)
47
+ -g: GPU ID to use (default: 0)
48
+ -f: Number of frames to decode (optional, default: all frames)
49
+ '''
50
+
51
+ import sys
52
+ from pathlib import Path
53
+ import pycuda.driver as cuda
54
+ import PyNvVideoCodec as nvc
55
+ from os.path import join, dirname, abspath, splitext
56
+
57
+ # Add the parent directory to Python path in a way that works from any working directory
58
+ current_dir = dirname(abspath(__file__))
59
+ parent_dir = dirname(current_dir)
60
+ if parent_dir not in sys.path:
61
+ sys.path.append(parent_dir)
62
+
63
+ # Import utilities for decoding
64
+ from utils.decode_parser import parse_decode_args
65
+ from utils.Utils import get_frame_data
66
+
67
+
68
+
69
+ def decode(gpu_id, enc_file_path, dec_file_path, use_device_memory, frame_count=None):
70
+ """
71
+ Function to decode media file and write raw frames into an output file.
72
+ Demonstrates explicit CUDA context and stream handling for decoder operations.
73
+
74
+ This function demonstrates hardware-accelerated video decoding. Here's how it works:
75
+ 1. Creates a demuxer (nv_dmx) that reads the video file and extracts encoded frame packets
76
+ 2. Sets up a GPU decoder (nv_dec) with custom CUDA context and stream
77
+ 3. The demuxer automatically extracts frame packets as you iterate over it
78
+ 4. Each packet is sent to the GPU decoder for hardware-accelerated decoding
79
+ 5. The decoder outputs raw YUV frames that can be processed or saved
80
+
81
+ Parameters:
82
+ gpu_id (int): Ordinal of GPU to use
83
+ enc_file_path (str): Path to file to be decoded
84
+ dec_file_path (str): Path to output file into which raw frames are stored
85
+ use_device_memory (int): If set to 1, output decoded frame is CUDeviceptr wrapped in CUDA Array Interface
86
+ frame_count (int, optional): Maximum number of frames to decode. If None, 0, or negative, decode all frames.
87
+ """
88
+ # Validate GPU ID
89
+ try:
90
+ cuda.init()
91
+ device_count = cuda.Device.count()
92
+ if gpu_id < 0 or gpu_id >= device_count:
93
+ raise ValueError(f"Invalid GPU ID {gpu_id}. Available GPUs: {device_count}")
94
+ except cuda.Error as e:
95
+ raise RuntimeError(f"CUDA initialization failed: {e}")
96
+
97
+ # Normalize frame count
98
+ decode_all = frame_count is None or frame_count <= 0
99
+ if decode_all:
100
+ print("Decoding all available frames")
101
+ frame_count = None
102
+
103
+ cuda_ctx = None
104
+ cuda_ctx = None
105
+ cuda_stream = None
106
+ nv_dmx = None
107
+ nv_dec = None
108
+ frames_decoded = 0
109
+
110
+ try:
111
+ # Initialize CUDA context and stream
112
+ print(f"Initializing CUDA for GPU {gpu_id}")
113
+ cuda_device = cuda.Device(gpu_id)
114
+ cuda_ctx = cuda_device.retain_primary_context()
115
+ cuda_ctx.push()
116
+ print(f"Created CUDA context for device: {cuda_device.name()}")
117
+
118
+ # Create CUDA stream for asynchronous operations
119
+ cuda_stream = cuda.Stream()
120
+ print("Created CUDA stream for asynchronous operations")
121
+
122
+ # Create demuxer and get codec information
123
+ nv_dmx = nvc.CreateDemuxer(filename=enc_file_path)
124
+ print(f"Created demuxer for file: {enc_file_path}")
125
+ print(f"Codec: {nv_dmx.GetNvCodecId()}")
126
+ print(f"Chroma Format: {nv_dmx.ChromaFormat()}")
127
+ print(f"Bit Depth: {nv_dmx.BitDepth()}")
128
+
129
+ # Get decoder capabilities
130
+ caps = nvc.GetDecoderCaps(
131
+ gpuid=gpu_id,
132
+ codec=nv_dmx.GetNvCodecId(),
133
+ chromaformat=nv_dmx.ChromaFormat(),
134
+ bitdepth=nv_dmx.BitDepth()
135
+ )
136
+ if "num_decoder_engines" in caps:
137
+ print("Number of NVDECs:", caps["num_decoder_engines"])
138
+
139
+ # Create decoder with CUDA context and stream
140
+ nv_dec = nvc.CreateDecoder(gpuid=gpu_id,
141
+ codec=nv_dmx.GetNvCodecId(),
142
+ cudacontext=cuda_ctx.handle,
143
+ cudastream=cuda_stream.handle,
144
+ usedevicememory=use_device_memory)
145
+ print("Created decoder with CUDA context and stream")
146
+ print("FPS =", nv_dmx.FrameRate())
147
+
148
+ # Process frames
149
+ with open(dec_file_path, "wb") as decFile:
150
+ for packet in nv_dmx:
151
+ decoded_frames = nv_dec.Decode(packet)
152
+ for decoded_frame in decoded_frames:
153
+ if frame_count is not None and frames_decoded >= frame_count:
154
+ break
155
+
156
+ # Get frame data using Utils helper function
157
+ frame_data = get_frame_data(decoded_frame, use_device_memory)
158
+ decFile.write(bytearray(frame_data))
159
+ frames_decoded += 1
160
+
161
+ if frame_count is not None and frames_decoded >= frame_count:
162
+ print(f"Successfully decoded requested {frame_count} frames to {dec_file_path}")
163
+ return
164
+
165
+ # If we get here, we've decoded all available frames
166
+ if frame_count is not None and frames_decoded < frame_count:
167
+ print(f"Warning: Video ended before reaching requested frame count. Requested: {frame_count}, Decoded: {frames_decoded}")
168
+ print(f"Decoded frames written to {dec_file_path}")
169
+ else:
170
+ print(f"Successfully decoded all {frames_decoded} frames to {dec_file_path}")
171
+
172
+ except nvc.PyNvVCExceptionUnsupported as e:
173
+ print(f"Operation or configuration not supported: {e}")
174
+ raise
175
+ except cuda.Error as e:
176
+ print(f"CUDA error (context/stream/memory): {e}")
177
+ raise
178
+ except Exception as e:
179
+ print(f"An unexpected error occurred: {e}")
180
+ raise
181
+ finally:
182
+ # Cleanup resources in reverse order of creation
183
+ if nv_dec is not None:
184
+ del nv_dec
185
+ if nv_dmx is not None:
186
+ del nv_dmx
187
+ if cuda_stream is not None:
188
+ cuda_stream.synchronize()
189
+ del cuda_stream
190
+ if cuda_ctx is not None:
191
+ cuda_ctx.pop()
192
+ del cuda_ctx
193
+
194
+ if __name__ == "__main__":
195
+ args = parse_decode_args(
196
+ "Advanced video decoding with explicit CUDA context and stream handling. "
197
+ "Demonstrates fine-grained control over CUDA resources and synchronization."
198
+ )
199
+ print("=" * 60)
200
+ print("Configuration:")
201
+ print(f"Input: {args.encoded_file_path}")
202
+ print(f"Output: {args.raw_file_path}")
203
+ print(f"GPU ID: {args.gpu_id}")
204
+ print(f"Use Device Memory: {args.use_device_memory}")
205
+ print(f"Frame Count: {args.frame_count if args.frame_count else 'All frames'}")
206
+ print("=" * 60)
207
+
208
+ decode(
209
+ gpu_id=args.gpu_id,
210
+ enc_file_path=args.encoded_file_path,
211
+ dec_file_path=args.raw_file_path,
212
+ use_device_memory=args.use_device_memory,
213
+ frame_count=args.frame_count
214
+ )
@@ -0,0 +1,183 @@
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
+ This sample demonstrates low-latency video decoding using the native decoder.
26
+ It shows how to:
27
+ 1. Configure different decoder latency modes
28
+ 2. Use zero-latency decoding for minimal delay
29
+ 3. Control frame output ordering
30
+ 4. Set end-of-picture flags for immediate decode
31
+
32
+
33
+ The DisplayDecodeLatencyType enumeration defines three possible latency modes:
34
+
35
+ - NATIVE: For a stream with B-frames, there is at least 1 frame latency between submitting an input packet and
36
+ getting the decoded frame in display order.
37
+
38
+ - LOW: For All-Intra and IPPP sequences (without B-frames), there is no latency between submitting an input packet
39
+ and getting the decoded frame in display order. Do not use this flag if the stream contains B-frames.
40
+ This mode maintains proper display ordering.
41
+
42
+ - ZERO: Enables zero latency for All-Intra / IPPP streams. Do not use this flag if the stream contains B-frames.
43
+ This mode maintains decode ordering.
44
+
45
+
46
+ Usage: python decode_with_low_latency.py -i <input_video_file> -o <output_file> -dl <latency_mode>
47
+ Example: python decode_with_low_latency.py -i input.mp4 -o output.yuv -dl 1
48
+
49
+ Arguments:
50
+ -i: Input video file
51
+ -o: Output raw video file (default: <input_name>.yuv)
52
+ -d: Use device memory (1) or host memory (0) (default: 1)
53
+ -g: GPU ID to use (default: 0)
54
+ -f: Number of frames to decode (optional, default: all frames)
55
+ -dl: Decode latency mode (0: NATIVE, 1: LOW, 2: ZERO)
56
+ '''
57
+
58
+ import sys
59
+ from pathlib import Path
60
+ import PyNvVideoCodec as nvc
61
+ from os.path import join, dirname, abspath, splitext
62
+
63
+ # Add the parent directory to Python path in a way that works from any working directory
64
+ current_dir = dirname(abspath(__file__))
65
+ parent_dir = dirname(current_dir)
66
+ if parent_dir not in sys.path:
67
+ sys.path.append(parent_dir)
68
+
69
+ # Import utilities for decoding
70
+ from utils.decode_parser import parse_low_latency_args
71
+ from utils.Utils import get_frame_data
72
+
73
+
74
+
75
+ def decode(gpu_id, enc_file_path, dec_file_path, use_device_memory, decode_latency, frame_count=None):
76
+ """
77
+ Function to decode media file and write raw frames into an output file.
78
+ Demonstrates different latency modes for decoding:
79
+ - NATIVE: Default mode with 4 frame latency, output in display order
80
+ - LOW: Zero frame latency, output in display order
81
+ - ZERO: Zero frame latency, output in decode order
82
+
83
+ Parameters:
84
+ gpu_id (int): Ordinal of GPU to use
85
+ enc_file_path (str): Path to file to be decoded
86
+ dec_file_path (str): Path to output file into which raw frames are stored
87
+ use_device_memory (int): If set to 1, output decoded frame is CUDeviceptr wrapped in CUDA Array Interface
88
+ decode_latency (nvc.DisplayDecodeLatencyType): Latency mode for decoding
89
+ frame_count (int, optional): Maximum number of frames to decode. If None, 0, or negative, decode all frames.
90
+ """
91
+ # Validate frame count if provided
92
+ if frame_count is None or frame_count <= 0:
93
+ print(f"Decoding all available frames")
94
+ frame_count = None # Reset to None to decode all frames
95
+
96
+ try:
97
+ nv_dmx = nvc.CreateDemuxer(filename=enc_file_path)
98
+
99
+ caps = nvc.GetDecoderCaps(
100
+ gpuid=gpu_id,
101
+ codec=nv_dmx.GetNvCodecId(),
102
+ chromaformat=nv_dmx.ChromaFormat(),
103
+ bitdepth=nv_dmx.BitDepth()
104
+ )
105
+ if "num_decoder_engines" in caps:
106
+ print("Number of NVDECs:", caps["num_decoder_engines"])
107
+
108
+ # Create decoder with specified latency mode
109
+ nv_dec = nvc.CreateDecoder(gpuid=gpu_id,
110
+ codec=nv_dmx.GetNvCodecId(),
111
+ usedevicememory=use_device_memory,
112
+ latency=decode_latency)
113
+
114
+ # Print latency mode information
115
+ latency_mode = "NATIVE (4 frame latency, display order)"
116
+ if decode_latency == nvc.DisplayDecodeLatencyType.LOW:
117
+ latency_mode = "LOW (0 frame latency, display order)"
118
+ elif decode_latency == nvc.DisplayDecodeLatencyType.ZERO:
119
+ latency_mode = "ZERO (0 frame latency, decode order)"
120
+ print(f"Decoding with latency mode: {latency_mode}")
121
+ print("FPS =", nv_dmx.FrameRate())
122
+
123
+ # open the file to be decoded in write mode
124
+ with open(dec_file_path, "wb") as decFile:
125
+ frames_decoded = 0
126
+ for packet in nv_dmx:
127
+ # For low latency modes, set ENDOFPICTURE flag to trigger immediate decode
128
+ if decode_latency in [nvc.DisplayDecodeLatencyType.LOW, nvc.DisplayDecodeLatencyType.ZERO]:
129
+ packet.decode_flag = nvc.VideoPacketFlag.ENDOFPICTURE
130
+
131
+ for decoded_frame in nv_dec.Decode(packet):
132
+ # Get frame data using Utils helper function
133
+ frame_data = get_frame_data(decoded_frame, use_device_memory)
134
+ decFile.write(bytearray(frame_data))
135
+
136
+ frames_decoded += 1
137
+ if frame_count is not None and frame_count > 0 and frames_decoded >= frame_count:
138
+ print(f"Reached requested frame count: {frame_count}. Frames written to {dec_file_path}")
139
+ return
140
+
141
+ if frame_count is not None and frame_count > 0 and frames_decoded < frame_count:
142
+ print(f"Video ended before reaching requested frame count. Decoded {frames_decoded} frames")
143
+
144
+ if frames_decoded > 0:
145
+ print(f"Decoded {frames_decoded} frames written to {dec_file_path}")
146
+ else:
147
+ print("No frames were decoded")
148
+ except nvc.PyNvVCExceptionUnsupported as e:
149
+ print(f"CreateDecoder failure: {e}")
150
+ except Exception as e:
151
+ print(f"An unexpected error occurred: {e}")
152
+
153
+ if __name__ == "__main__":
154
+
155
+ args = parse_low_latency_args()
156
+
157
+ # Map latency mode to nvc type
158
+ latency_map = {
159
+ 0: nvc.DisplayDecodeLatencyType.NATIVE,
160
+ 1: nvc.DisplayDecodeLatencyType.LOW,
161
+ 2: nvc.DisplayDecodeLatencyType.ZERO
162
+ }
163
+ decode_latency = latency_map[args.decode_latency]
164
+ latency_names = {0: "NATIVE", 1: "LOW", 2: "ZERO"}
165
+
166
+ print("=" * 60)
167
+ print("Configuration:")
168
+ print(f"Input: {args.encoded_file_path}")
169
+ print(f"Output: {args.raw_file_path}")
170
+ print(f"GPU ID: {args.gpu_id}")
171
+ print(f"Use Device Memory: {args.use_device_memory}")
172
+ print(f"Frame Count: {args.frame_count if args.frame_count else 'All frames'}")
173
+ print(f"Decode Latency: {latency_names[args.decode_latency]}")
174
+ print("=" * 60)
175
+
176
+ decode(
177
+ gpu_id=args.gpu_id,
178
+ enc_file_path=args.encoded_file_path,
179
+ dec_file_path=args.raw_file_path,
180
+ use_device_memory=args.use_device_memory,
181
+ decode_latency=decode_latency,
182
+ frame_count=args.frame_count
183
+ )
@@ -0,0 +1,9 @@
1
+ {
2
+ "preset" : "p3",
3
+ "tuning_info" : "high_quality",
4
+ "rc": "vbr",
5
+ "fps" : 30,
6
+ "bitrate" : 10000000,
7
+ "maxbitrate" : 10000000,
8
+ "vbvbufsize" : 10000000
9
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "preset": "P3",
3
+ "tuning_info": "low_latency",
4
+ "rc": "cbr",
5
+ "fps": 30,
6
+ "bf": 1,
7
+ "multipass":"fullres",
8
+ "bitrate": 3000000,
9
+ "maxbitrate": 3000000,
10
+ "vbvbufsize": 100000
11
+ }