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
@@ -0,0 +1,177 @@
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
+ Core module for handling decode statistics.
26
+
27
+ This module provides functionality for extracting and analyzing low-level video decoding
28
+ statistics from H.264/H.265 streams. The following statistics are collected and analyzed:
29
+
30
+ 1. QP (Quantization Parameter) Analysis:
31
+ - Average, min, max QP values per frame
32
+ - Indicates compression level and quality trade-offs
33
+ - Higher QP = more compression, potentially lower quality
34
+
35
+ 2. CU (Coding Unit) Type Distribution:
36
+ - INTRA: Spatial prediction (current frame only)
37
+ - INTER: Temporal prediction (motion compensation)
38
+ - SKIP: Copy from reference without residual
39
+ - PCM: Uncompressed raw pixel values
40
+
41
+ 3. Motion Vector Statistics:
42
+ - MV0: Primary motion vectors (L0 reference)
43
+ - MV1: Secondary motion vectors (L1 reference, B-frames)
44
+ - Magnitude analysis for temporal complexity assessment
45
+
46
+ 4. Macroblock Details:
47
+ - Per-block encoding decisions and parameters
48
+ - Motion vector coordinates and directions
49
+ - QP values and prediction types for debugging
50
+
51
+ These statistics are valuable for:
52
+ - Video quality analysis
53
+ - Encoder behavior understanding
54
+ - Performance optimization
55
+ - Debugging encoding/decoding issues
56
+ """
57
+
58
+ # CU type definitions and mapping
59
+ CU_TYPES = {
60
+ 0: "INTRA",
61
+ 1: "INTER",
62
+ 2: "SKIP",
63
+ 3: "PCM",
64
+ 7: "INVALID"
65
+ }
66
+
67
+ class DecodeStatsWriter:
68
+ """Handles writing of decode statistics to output files."""
69
+
70
+ def __init__(self, output_file):
71
+ """Initialize with output file handle."""
72
+ self.output_file = output_file
73
+
74
+ def write_frame_stats(self, frame_idx, parsed_stats):
75
+ """Write all statistics for a single frame."""
76
+ if not parsed_stats or len(parsed_stats) == 0:
77
+ self._write_frame_header(frame_idx)
78
+ self.output_file.write("No decode stats available\n")
79
+ return
80
+
81
+ self._write_frame_header(frame_idx)
82
+
83
+ qp_luma_list = parsed_stats["qp_luma"]
84
+ if not qp_luma_list or len(qp_luma_list) == 0:
85
+ self.output_file.write("No macroblock statistics available\n")
86
+ return
87
+
88
+ num_blocks = len(qp_luma_list)
89
+ self.output_file.write(f"Macroblock Statistics ({num_blocks} blocks):\n")
90
+
91
+ # Write all block statistics
92
+ self._write_qp_stats(qp_luma_list)
93
+ self._write_cu_distribution(parsed_stats["cu_type"], num_blocks)
94
+ self._write_motion_stats(parsed_stats)
95
+ self._write_detailed_blocks(parsed_stats, num_blocks)
96
+
97
+ def _write_frame_header(self, frame_idx):
98
+ """Write frame header with index."""
99
+ self.output_file.write(f"\n=== Frame {frame_idx} ===\n")
100
+
101
+ def _write_qp_stats(self, qp_luma_list):
102
+ """Write QP statistics summary."""
103
+ avg_qp = sum(qp_luma_list) / len(qp_luma_list)
104
+ self.output_file.write(f" Average Luma QP: {avg_qp:.2f}\n")
105
+ self.output_file.write(f" Min Luma QP: {min(qp_luma_list)}, Max Luma QP: {max(qp_luma_list)}\n")
106
+
107
+ def _write_cu_distribution(self, cu_type_list, num_blocks):
108
+ """Write CU type distribution."""
109
+ cu_counts = {}
110
+ for i in range(num_blocks):
111
+ if i < len(cu_type_list):
112
+ cu_type = int(cu_type_list[i])
113
+ cu_counts[cu_type] = cu_counts.get(cu_type, 0) + 1
114
+
115
+ if cu_counts:
116
+ self.output_file.write(" CU Type Distribution:\n")
117
+ for cu_type, count in sorted(cu_counts.items()):
118
+ percentage = (count / num_blocks) * 100
119
+ cu_name = CU_TYPES.get(cu_type, f"UNKNOWN_{cu_type}")
120
+ self.output_file.write(f" {cu_name} (Type {cu_type}): {count} blocks ({percentage:.1f}%)\n")
121
+
122
+ def _write_motion_stats(self, parsed_stats):
123
+ """Write motion vector statistics."""
124
+ mv_0, mv_1 = self._calculate_mv_magnitudes(parsed_stats)
125
+
126
+ if mv_0:
127
+ self.output_file.write(f" Motion Vector Statistics (INTER and B blocks):\n")
128
+ self.output_file.write(f" Average MV0 Magnitude: {sum(mv_0) / len(mv_0):.2f}\n")
129
+ self.output_file.write(f" Max MV0 Magnitude: {max(mv_0):.2f}\n")
130
+
131
+ if mv_1:
132
+ self.output_file.write(f" Average MV1 Magnitude: {sum(mv_1) / len(mv_1):.2f}\n")
133
+ self.output_file.write(f" Max MV1 Magnitude: {max(mv_1):.2f}\n")
134
+
135
+ def _calculate_mv_magnitudes(self, parsed_stats):
136
+ """Calculate motion vector magnitudes for INTER blocks."""
137
+ mv_0, mv_1 = [], []
138
+ cu_type_list = parsed_stats["cu_type"]
139
+
140
+ for i in range(len(cu_type_list)):
141
+ if int(cu_type_list[i]) != 1: # Skip non-INTER blocks
142
+ continue
143
+
144
+ # Calculate MV0 magnitude
145
+ if i < len(parsed_stats["mv0_x"]) and i < len(parsed_stats["mv0_y"]):
146
+ mv_x = float(parsed_stats["mv0_x"][i])
147
+ mv_y = float(parsed_stats["mv0_y"][i])
148
+ mv_0.append((mv_x * mv_x + mv_y * mv_y) ** 0.5)
149
+
150
+ # Calculate MV1 magnitude
151
+ if i < len(parsed_stats["mv1_x"]) and i < len(parsed_stats["mv1_y"]):
152
+ mv_x = float(parsed_stats["mv1_x"][i])
153
+ mv_y = float(parsed_stats["mv1_y"][i])
154
+ mv_1.append((mv_x * mv_x + mv_y * mv_y) ** 0.5)
155
+
156
+ return mv_0, mv_1
157
+
158
+ def _write_detailed_blocks(self, parsed_stats, num_blocks, max_blocks=5):
159
+ """Write detailed information for first few blocks."""
160
+ self.output_file.write(f" Detailed Macroblock Information (first {max_blocks} blocks):\n")
161
+
162
+ for i in range(min(max_blocks, num_blocks)):
163
+ # Get block type and QP
164
+ cu_type = int(parsed_stats["cu_type"][i]) if i < len(parsed_stats["cu_type"]) else "UNKNOWN"
165
+ qp_luma = int(parsed_stats["qp_luma"][i]) if i < len(parsed_stats["qp_luma"]) else "UNKNOWN"
166
+
167
+ # Build motion vector info string
168
+ mv_info = []
169
+ if i < len(parsed_stats["mv0_x"]) and i < len(parsed_stats["mv0_y"]):
170
+ mv_info.append(f"MV0=({int(parsed_stats['mv0_x'][i])}, {int(parsed_stats['mv0_y'][i])})")
171
+ if i < len(parsed_stats["mv1_x"]) and i < len(parsed_stats["mv1_y"]):
172
+ mv_info.append(f"MV1=({int(parsed_stats['mv1_x'][i])}, {int(parsed_stats['mv1_y'][i])})")
173
+
174
+ mv_str = ", ".join(mv_info) if mv_info else "No MVs"
175
+ cu_name = CU_TYPES.get(cu_type, f"UNKNOWN_{cu_type}")
176
+
177
+ self.output_file.write(f" Block {i}: QP={qp_luma}, Type={cu_name}, {mv_str}\n")
@@ -0,0 +1,174 @@
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
+ Helper module for parallel processing in video encoding.
26
+ """
27
+
28
+ import os
29
+ import threading
30
+ import multiprocessing
31
+ from typing import Callable, Any, Dict, Union
32
+ import pycuda.driver as cuda
33
+ import PyNvVideoCodec as nvc
34
+ from .Utils import AppFramePerf
35
+ from .frame_utils import get_frame_size
36
+ from .encode_parser import PERF_MAX_FRAMES
37
+
38
+ def print_performance_summary(mode: str, num_workers: int, total_frames: int, duration: float) -> None:
39
+ """Print performance statistics for parallel encoding/decoding."""
40
+ print(f"\n--- {mode.capitalize()} Performance Summary ---")
41
+ print(f"Number of {mode}: {num_workers}")
42
+ print(f"Total frames processed: {total_frames}")
43
+ if duration > 0:
44
+ fps = total_frames / duration
45
+ print(f"Duration: {duration:.2f} seconds")
46
+ print(f"Total FPS: {fps:.2f}")
47
+ print(f"Average FPS per {mode[:-1]}: {fps / num_workers:.2f}")
48
+
49
+ def encode_thread_worker(
50
+ thread_id: int,
51
+ input_file: str,
52
+ encoder: nvc.PyNvEncoder,
53
+ device_data: cuda.DeviceAllocation,
54
+ frame_size: int,
55
+ width: int,
56
+ height: int,
57
+ fmt: str,
58
+ frame_count: int,
59
+ result_queue: Union[multiprocessing.Queue, 'queue.Queue']
60
+ ) -> None:
61
+ """Worker function for threaded encoding."""
62
+ try:
63
+ worker_name = f"Thread-{thread_id + 1}" # 1-based indexing
64
+ print(f"Starting encode worker {worker_name}")
65
+
66
+ # Calculate frames to process
67
+ file_size = os.path.getsize(input_file)
68
+ available_frames = file_size // frame_size
69
+
70
+ # Determine how many frames to encode
71
+ frames_to_process = min(frame_count or available_frames, available_frames, PERF_MAX_FRAMES)
72
+
73
+ # Encode frames
74
+ frames_encoded = 0
75
+ for i in range(frames_to_process):
76
+ input_gpu_frame = AppFramePerf(width, height, fmt, device_data, i)
77
+ pic_params = nvc.NV_ENC_PIC_PARAMS()
78
+ pic_params.inputTimeStamp = i
79
+ encoder.Encode(input_gpu_frame, pic_params)
80
+ frames_encoded += 1
81
+
82
+ # Flush encoder
83
+ encoder.EndEncode()
84
+ print(f"Worker {worker_name} completed encoding {frames_encoded} frames")
85
+ result_queue.put(frames_encoded)
86
+
87
+ except Exception as e:
88
+ print(f"Worker {worker_name}: An unexpected error occurred: {e}")
89
+ result_queue.put(0)
90
+
91
+ def encode_process_worker(
92
+ process_id: int,
93
+ input_file: str,
94
+ width: int,
95
+ height: int,
96
+ fmt: str,
97
+ ipc_handle: Any,
98
+ frame_size: int,
99
+ config: Dict[str, Any],
100
+ frame_count: int,
101
+ result_queue: multiprocessing.Queue,
102
+ ready_queue: multiprocessing.Queue,
103
+ go_event: Any,
104
+ ) -> None:
105
+ """Worker function for multiprocess encoding.
106
+
107
+ Signals readiness on ``ready_queue`` after encoder and IPC memory are set up,
108
+ then blocks on ``go_event`` so the parent can measure encode-only duration.
109
+ """
110
+ worker_name = f"Process-{process_id + 1}" # 1-based indexing
111
+ print(f"Starting encode worker {worker_name}")
112
+
113
+ worker_context = None
114
+ encoder = None
115
+ try:
116
+ # Match thread mode: explicit context + stream (avoids primary-context + extra stream path).
117
+ # Open IPC memory in this context before CreateEncoder so NVENC sees a consistent CUcontext.
118
+ cuda.init()
119
+ gpu_id = int(config.get("gpu_id", 0))
120
+ worker_context = cuda.Device(gpu_id).make_context()
121
+ worker_stream = cuda.Stream()
122
+ device_data = cuda.IPCMemoryHandle(ipc_handle)
123
+ encoder = nvc.CreateEncoder(
124
+ width,
125
+ height,
126
+ fmt,
127
+ False,
128
+ cudacontext=worker_context.handle,
129
+ cudastream=worker_stream.handle,
130
+ **config,
131
+ )
132
+ except Exception as e:
133
+ print(f"Worker {worker_name}: setup failed: {e}")
134
+ ready_queue.put((process_id, False))
135
+ result_queue.put(0)
136
+ if worker_context is not None:
137
+ try:
138
+ worker_context.pop()
139
+ worker_context.detach()
140
+ except Exception:
141
+ pass
142
+ return
143
+
144
+ file_size = os.path.getsize(input_file)
145
+ available_frames = file_size // frame_size
146
+ frames_to_process = min(frame_count or available_frames, available_frames, PERF_MAX_FRAMES)
147
+
148
+ ready_queue.put((process_id, True))
149
+ go_event.wait()
150
+
151
+ try:
152
+ frames_encoded = 0
153
+ for i in range(frames_to_process):
154
+ input_gpu_frame = AppFramePerf(width, height, fmt, device_data, i)
155
+ pic_params = nvc.NV_ENC_PIC_PARAMS()
156
+ pic_params.inputTimeStamp = i
157
+ encoder.Encode(input_gpu_frame, pic_params)
158
+ frames_encoded += 1
159
+
160
+ encoder.EndEncode()
161
+ print(f"Worker {worker_name} completed encoding {frames_encoded} frames")
162
+ result_queue.put(frames_encoded)
163
+
164
+ except Exception as e:
165
+ print(f"Worker {worker_name}: An unexpected error occurred: {e}")
166
+ result_queue.put(0)
167
+ finally:
168
+ encoder = None
169
+ if worker_context is not None:
170
+ try:
171
+ worker_context.pop()
172
+ worker_context.detach()
173
+ except Exception:
174
+ pass