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.
- PyNvVideoCodec/PyNvVideoCodec_121.cp313-win_arm64.pyd +0 -0
- PyNvVideoCodec/PyNvVideoCodec_130.cp313-win_arm64.pyd +0 -0
- PyNvVideoCodec/VersionCheck.cp313-win_arm64.pyd +0 -0
- PyNvVideoCodec/__init__.py +251 -0
- PyNvVideoCodec/avformat-62.dll +0 -0
- PyNvVideoCodec/avutil-60.dll +0 -0
- PyNvVideoCodec/decoders/SimpleDecoder.py +273 -0
- PyNvVideoCodec/decoders/ThreadedDecoder.py +129 -0
- PyNvVideoCodec/decoders/__init__.py +22 -0
- PyNvVideoCodec/transcoder/Transcoder.py +55 -0
- PyNvVideoCodec/transcoder/__init__.py +22 -0
- benchmarks/cached_decoder_benchmark.py +813 -0
- benchmarks/frame_sampling_benchmark.py +765 -0
- benchmarks/requirements.txt +52 -0
- benchmarks/segmented_transcode_benchmark.py +1546 -0
- benchmarks/setup_pycuda_win_arm64.bat +531 -0
- pynvvideocodec-2.2.1.data/data/external/ffmpeg/readme.txt +39 -0
- pynvvideocodec-2.2.1.data/data/external/ffmpeg/src/ffmpeg-8.1.2.tar.xz +0 -0
- pynvvideocodec-2.2.1.dist-info/METADATA +97 -0
- pynvvideocodec-2.2.1.dist-info/RECORD +63 -0
- pynvvideocodec-2.2.1.dist-info/WHEEL +5 -0
- pynvvideocodec-2.2.1.dist-info/licenses/LICENSE.txt +22 -0
- pynvvideocodec-2.2.1.dist-info/licenses/NOTICES.txt +167 -0
- pynvvideocodec-2.2.1.dist-info/top_level.txt +3 -0
- samples/advanced/decode.py +173 -0
- samples/advanced/decode_from_memory_buffer.py +204 -0
- samples/advanced/decode_perf.py +299 -0
- samples/advanced/decode_reconfigure.py +184 -0
- samples/advanced/decode_sei_msg.py +193 -0
- samples/advanced/decode_with_cuda_control.py +214 -0
- samples/advanced/decode_with_low_latency.py +183 -0
- samples/advanced/encode_config.json +12 -0
- samples/advanced/encode_config_lowlatency.json +13 -0
- samples/advanced/encode_perf.py +338 -0
- samples/advanced/encode_reconfigure.py +211 -0
- samples/advanced/encode_sei_msg.py +188 -0
- samples/advanced/simple_decode_from_memory.py +151 -0
- samples/advanced/simple_decode_stats.py +179 -0
- samples/advanced/transcode.py +288 -0
- samples/basic/create_video_segments.py +187 -0
- samples/basic/encode.py +574 -0
- samples/basic/segments.txt +3 -0
- samples/basic/simple_decode_sampling.py +182 -0
- samples/basic/transcode_config.json +6 -0
- samples/jupyter/ReconfigureDecoder.png +0 -0
- samples/jupyter/SimpleDecoderAPIs.png +0 -0
- samples/jupyter/ThreadedDecoder.png +0 -0
- samples/jupyter/coco_classes.pickle +0 -0
- samples/jupyter/face_protect_tutorial.ipynb +881 -0
- samples/jupyter/object_detection_tutorial.ipynb +781 -0
- samples/jupyter/simple_decode_tutorial.ipynb +674 -0
- samples/requirements.txt +84 -0
- samples/setup_pycuda_win_arm64.bat +531 -0
- samples/utils/Utils.py +405 -0
- samples/utils/__init__.py +36 -0
- samples/utils/decode_parser.py +642 -0
- samples/utils/decode_stats_writer.py +177 -0
- samples/utils/encode_parallel_utils.py +174 -0
- samples/utils/encode_parser.py +379 -0
- samples/utils/frame_utils.py +89 -0
- samples/utils/sei_message_parser.py +223 -0
- samples/utils/sei_parser.py +223 -0
- samples/utils/transcode_parser.py +218 -0
|
@@ -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
|
+
)
|