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,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
|