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,187 @@
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 video segmentation which can be useful for creating training data for machine learning models.
26
+ It shows how to:
27
+ 1. Extract segments from a video file based on timestamp ranges
28
+ 2. Use the SimpleDecoder to get video metadata
29
+ 3. Configure and use the Transcoder for segment extraction
30
+ 4. Handle multiple output segments with proper naming
31
+
32
+ Usage:
33
+ python create_video_segments.py -i <input_file> [options]
34
+
35
+ Example:
36
+ python create_video_segments.py -i input.mp4 -s segments.txt -c config.json
37
+
38
+ Arguments:
39
+ -i: Input video file
40
+ -s: Segments file (default: segments.txt)
41
+ -c: Transcoder config file (default: transcode_config.json)
42
+ -o: Output filename template
43
+ -g: GPU ID (default: 0)
44
+
45
+ Segments File Format:
46
+ start_time end_time
47
+ Example:
48
+ 0.0 10.5
49
+ 15.0 30.0
50
+ 45.5 60.0
51
+
52
+ Output file format:
53
+ This is the default output template. The file name can be customized using the -o argument. Time stamp is appended to the file name.
54
+ {input_file_name}_segment_{start_time}_{end_time}.mp4
55
+ Example:
56
+ input_file_name_segment_0.0_10.5.mp4
57
+ input_file_name_segment_15.0_30.0.mp4
58
+ input_file_name_segment_45.5_60.0.mp4
59
+
60
+ Note: Times are in seconds. Each segment is validated against video duration.
61
+ '''
62
+
63
+ import json
64
+ import os
65
+ import sys
66
+ from os.path import dirname, abspath
67
+ import PyNvVideoCodec as nvc
68
+
69
+
70
+ # Add the parent directory to Python path in a way that works from any working directory
71
+ current_dir = dirname(abspath(__file__))
72
+ parent_dir = dirname(current_dir)
73
+ if parent_dir not in sys.path:
74
+ sys.path.append(parent_dir)
75
+
76
+ from utils.transcode_parser import parse_transcode_args
77
+
78
+
79
+ def get_video_duration(input_file_path: str, gpu_id: int) -> float:
80
+ """Get video duration in seconds."""
81
+ try:
82
+ decoder = nvc.SimpleDecoder(input_file_path, gpu_id=gpu_id)
83
+ duration = decoder.get_stream_metadata().duration
84
+ print(f"Video duration: {duration:.2f} seconds")
85
+ return duration
86
+ except Exception as e:
87
+ print(f"Error getting video duration: {e}")
88
+ return 0.0
89
+
90
+
91
+ def create_video_segments(input_file_path: str, segments_file_path: str,
92
+ config_file_path: str, output_template: str, gpu_id: int):
93
+ """Create video segments from input file based on segments text file."""
94
+
95
+ # Get video duration for validation
96
+ duration = get_video_duration(input_file_path, gpu_id)
97
+ if duration <= 0:
98
+ print("Error: Could not determine video duration")
99
+ return
100
+
101
+ # Load transcoder configuration
102
+ with open(config_file_path) as json_file:
103
+ config = json.load(json_file)
104
+
105
+ input_file_name_base = os.path.splitext(os.path.basename(input_file_path))[0]
106
+ successful_segments = 0
107
+
108
+ # Process segments file
109
+ with open(segments_file_path, 'r') as file:
110
+ for line_num, line in enumerate(file, 1):
111
+ line = line.strip()
112
+ if not line: # Skip empty lines
113
+ continue
114
+
115
+ try:
116
+ start_ts_str, end_ts_str = line.split()
117
+ start_time = float(start_ts_str)
118
+ end_time = float(end_ts_str)
119
+
120
+ # Error check: end timestamp should not exceed media duration
121
+ if end_time > duration:
122
+ print(f"Warning: Line {line_num}: End time {end_time:.2f}s exceeds video duration {duration:.2f}s - clipping to duration")
123
+ end_time = duration
124
+
125
+ if start_time >= end_time:
126
+ print(f"Error: Line {line_num}: Invalid time range {start_time}-{end_time}")
127
+ continue
128
+
129
+ # Generate output path
130
+ base_output_path = output_template.format(input_file_name=input_file_name_base)
131
+ base_output_name, base_output_ext = os.path.splitext(base_output_path)
132
+ if not base_output_ext:
133
+ base_output_ext = '.mp4'
134
+ base_output_path = base_output_name + base_output_ext
135
+
136
+ start_time = round(start_time, 2)
137
+ end_time = round(end_time, 2)
138
+ print(f"Creating segment: {start_time:g}s - {end_time:g}s")
139
+
140
+ # Create transcoder and generate segment
141
+ transcoder = nvc.Transcoder(input_file_path, base_output_path, gpu_id, 0, 0, **config)
142
+ transcoder.segmented_transcode(start_time, end_time)
143
+
144
+ # Expected output filename (API appends timestamps)
145
+ final_output = f"{base_output_name}_{start_time:g}_{end_time:g}{base_output_ext}"
146
+ print(f"✓ Created: {final_output}")
147
+ successful_segments += 1
148
+
149
+ except ValueError as e:
150
+ print(f"Error: Line {line_num}: Invalid format '{line}' - {e}")
151
+ except Exception as e:
152
+ print(f"Error: Line {line_num}: Failed to create segment - {e}")
153
+
154
+ print(f"\nSummary: {successful_segments} segments created successfully")
155
+
156
+
157
+ def main():
158
+ args = parse_transcode_args("Create video segments from text file input")
159
+
160
+ # Display configuration
161
+ print("=" * 60)
162
+ print("VIDEO SEGMENTATION CONFIGURATION")
163
+ print("=" * 60)
164
+ print(f"Input: {args.input_file_path}")
165
+ print(f"Segments File: {args.segments_file_path}")
166
+ print(f"Config File: {args.config_file_path}")
167
+ print(f"GPU ID: {args.gpu_id}")
168
+ print("=" * 60)
169
+
170
+ # Validate files exist
171
+ for file_path, name in [(args.input_file_path, "Input video"),
172
+ (args.segments_file_path, "Segments file"),
173
+ (args.config_file_path, "Config file")]:
174
+ if not os.path.exists(file_path):
175
+ print(f"Error: {name} not found: {file_path}")
176
+ return
177
+
178
+ create_video_segments(args.input_file_path, args.segments_file_path, args.config_file_path,
179
+ args.output_template, args.gpu_id)
180
+
181
+ print("=" * 60)
182
+ print("SEGMENTATION COMPLETE")
183
+ print("=" * 60)
184
+
185
+
186
+ if __name__ == "__main__":
187
+ main()
@@ -0,0 +1,347 @@
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 unified video encoding with support for both CPU and GPU buffer modes.
26
+
27
+ It shows how to:
28
+ 1. Configure and use different buffer modes for encoding
29
+ 2. Handle both host (CPU) and device (GPU) memory efficiently
30
+ 3. Manage encoder resources and states
31
+ 4. Process frames with optimal memory handling
32
+ 5. Write encoded elementary streams to a file
33
+
34
+ The sample supports two buffer modes:
35
+ - CPU Buffer Mode:
36
+ * Uses host memory for frame data
37
+
38
+ - GPU Buffer Mode:
39
+ * Uses device memory for frame data
40
+
41
+ Usage:
42
+ python encode.py -i <input_file> -s <size> -m <mode> [options]
43
+
44
+ Examples:
45
+ # Encode to raw H.264 bitstream
46
+ python encode.py -i input.yuv -s 1920x1080 -m gpu -o output.h264
47
+
48
+ # AV1 elementary (.av1): IVF container + patched frame count (AppEncCuda-compatible)
49
+ python encode.py -i input.yuv -s 1920x1080 -m cpu -c AV1 -o output.av1
50
+
51
+ Arguments:
52
+ -i: Raw input video file
53
+ -s: Frame size (e.g., 1920x1080)
54
+ -m: Buffer mode (cpu/gpu)
55
+ -if: Input format (default: NV12)
56
+ -c: Codec (H264, HEVC, AV1)
57
+ -f: Number of frames (default: all)
58
+ -g: GPU ID (default: 0)
59
+ -json: Encoder config file
60
+ -o: Output file
61
+
62
+ '''
63
+
64
+ import PyNvVideoCodec as nvc
65
+ import numpy as np
66
+ import os
67
+ import sys
68
+ from os.path import join, dirname, abspath
69
+
70
+ # Add the parent directory to Python path in a way that works from any working directory
71
+ current_dir = dirname(abspath(__file__))
72
+ parent_dir = dirname(current_dir)
73
+ if parent_dir not in sys.path:
74
+ sys.path.append(parent_dir)
75
+
76
+ # Import utilities for GPU buffer mode
77
+ try:
78
+ from utils.Utils import AppFrame, FetchCPUFrame, FetchGPUFrame
79
+ GPU_UTILS_AVAILABLE = True
80
+ except ImportError:
81
+ GPU_UTILS_AVAILABLE = False
82
+ print("Warning: Utils module not found. GPU buffer mode will be disabled.")
83
+
84
+
85
+ # Import utilities for frame handling
86
+ from utils.frame_utils import get_frame_size
87
+ from utils.encode_parser import parse_unified_args
88
+
89
+
90
+
91
+
92
+ def _concat_encode_packets(packets) -> bytes:
93
+ """Join Encode / EndEncode output into one bitstream blob."""
94
+ return b"".join(bytes(p["data"]) for p in packets)
95
+
96
+
97
+ def _av1_ivf_elementary_enabled(config_params: dict) -> bool:
98
+ """True when output is AV1 in IVF (elementary), matching VideoCodecSDK AppEncCuda."""
99
+ if config_params.get("codec", "h264").lower() != "av1":
100
+ return False
101
+ v = str(config_params.get("use_ivf_container", "1")).lower()
102
+ return v not in ("0", "false", "no")
103
+
104
+
105
+ def _patch_ivf_output_file(output_file_path: str, ivf_packet_count: int) -> None:
106
+ """Match FFmpeg ivf_write_trailer: frame count at IVF global header offset 24 (LE32)."""
107
+ if ivf_packet_count <= 0:
108
+ return
109
+ with open(output_file_path, "r+b") as out_f:
110
+ if out_f.read(4) != b"DKIF":
111
+ return
112
+ out_f.seek(24)
113
+ out_f.write(ivf_packet_count.to_bytes(4, "little"))
114
+
115
+
116
+ def encode_cpu_buffer(gpu_id, dec_file_path, enc_file_path, width, height, fmt, config_params, frame_count):
117
+ """
118
+ Encode frames using host memory buffers as input.
119
+
120
+ This function reads image data from a file and copies it to CUDA buffers for encoding.
121
+ The encoder submits the data to NVENC hardware for encoding. Video memory buffer is
122
+ allocated to get the NVENC hardware output. The output is copied from video memory
123
+ to host memory for file storage.
124
+
125
+ Parameters:
126
+ gpu_id (int): Ordinal of GPU to use
127
+ dec_file_path (str): Path to file to be decoded
128
+ enc_file_path (str): Path to output file for encoded frames
129
+ width (int): Width of encoded frame
130
+ height (int): Height of encoded frame
131
+ fmt (str): Surface format string in uppercase (e.g., "NV12")
132
+ config_params (dict): Key-value pairs providing fine-grained control on encoding
133
+ frame_count (int): Number of frames to encode
134
+
135
+ Returns:
136
+ None
137
+ """
138
+ print("Using CPU buffer mode")
139
+
140
+ codec = config_params.get("codec", "h264").lower()
141
+ if codec == "av1":
142
+ config_params.setdefault("use_ivf_container", "1")
143
+
144
+ frame_size = get_frame_size(width, height, fmt)
145
+
146
+ with open(dec_file_path, "rb") as dec_file:
147
+ config_params["gpu_id"] = gpu_id
148
+ nvenc = nvc.CreateEncoder(width, height, fmt, True, **config_params) # True = use CPU buffers
149
+
150
+ # Calculate total available frames from file size
151
+ file_size = os.path.getsize(dec_file_path)
152
+ available_frames = file_size // frame_size
153
+
154
+ # Determine frames to process with limit
155
+ frames_to_process = frame_count if frame_count > 0 else available_frames
156
+ frames_to_process = min(frames_to_process, available_frames)
157
+
158
+ print(f"File contains {available_frames} frames, processing {frames_to_process} frames using CPU buffers...")
159
+
160
+ enc_file = open(enc_file_path, "wb")
161
+ frames_encoded = 0
162
+ ivf_packets = 0
163
+
164
+ for i in range(frames_to_process):
165
+ chunk = np.fromfile(dec_file, np.uint8, count=frame_size)
166
+ if chunk.size != 0:
167
+ pic_params = nvc.NV_ENC_PIC_PARAMS()
168
+ pic_params.inputTimeStamp = frames_encoded
169
+ enc_list = nvenc.Encode(chunk, pic_params)
170
+ ivf_packets += len(enc_list)
171
+ enc_file.write(bytearray(_concat_encode_packets(enc_list)))
172
+ frames_encoded += 1
173
+ else:
174
+ print(f"Warning: Could not read frame {i+1}")
175
+ break
176
+
177
+ # Flush encoder queue
178
+ flush_list = nvenc.EndEncode()
179
+ ivf_packets += len(flush_list)
180
+ enc_file.write(bytearray(_concat_encode_packets(flush_list)))
181
+ if _av1_ivf_elementary_enabled(config_params):
182
+ enc_file.flush()
183
+ _patch_ivf_output_file(enc_file_path, ivf_packets)
184
+ enc_file.close()
185
+
186
+ print(f"Completed encoding {frames_encoded} frames using CPU buffers")
187
+ print(f"Output file: {enc_file_path}")
188
+
189
+
190
+ def encode_gpu_buffer(gpu_id, dec_file_path, enc_file_path, width, height, fmt, config_params, frame_count):
191
+ """
192
+ Encode frames using CUDA device buffers as input.
193
+
194
+ This function reads image data from a file and loads it to CUDA input buffers using
195
+ FetchGPUFrame(). The encoder copies the CUDA buffers and submits them to NVENC hardware
196
+ for encoding. Video memory buffer is allocated to get the NVENC hardware output.
197
+ The output is copied from video memory to host memory for file storage.
198
+
199
+ Parameters:
200
+ gpu_id (int): Ordinal of GPU to use
201
+ dec_file_path (str): Path to file to be decoded
202
+ enc_file_path (str): Path to output file for encoded frames
203
+ width (int): Width of encoded frame
204
+ height (int): Height of encoded frame
205
+ fmt (str): Surface format string in uppercase (e.g., "NV12")
206
+ config_params (dict): Key-value pairs providing fine-grained control on encoding
207
+ frame_count (int): Number of frames to encode
208
+
209
+ Returns:
210
+ None
211
+ """
212
+ print("Using GPU buffer mode")
213
+
214
+ if not GPU_UTILS_AVAILABLE:
215
+ raise RuntimeError("GPU buffer mode requires Utils module (AppFrame, FetchCPUFrame, FetchGPUFrame)")
216
+
217
+ codec = config_params.get("codec", "h264").lower()
218
+ if codec == "av1":
219
+ config_params.setdefault("use_ivf_container", "1")
220
+
221
+ # Show encoder capabilities
222
+ caps = nvc.GetEncoderCaps(codec=config_params.get("codec", "h264"))
223
+ if "num_encoder_engines" in caps:
224
+ print(f"Number of NVENCs: {caps['num_encoder_engines']}")
225
+
226
+ with open(dec_file_path, "rb") as decFile:
227
+ config_params["gpu_id"] = gpu_id
228
+ nvenc = nvc.CreateEncoder(width, height, fmt, False, **config_params) # False = use GPU buffers
229
+ input_frame_list = [AppFrame(width, height, fmt) for _ in range(1, 5)]
230
+
231
+ # Calculate total available frames from file size
232
+ file_size = os.path.getsize(dec_file_path)
233
+ available_frames = file_size // input_frame_list[0].frameSize
234
+
235
+ # Determine frames to process with limit
236
+ frames_to_process = frame_count if frame_count > 0 else available_frames
237
+ frames_to_process = min(frames_to_process, available_frames)
238
+
239
+ print(f"File contains {available_frames} frames, processing {frames_to_process} frames using GPU buffers...")
240
+
241
+ encFile = open(enc_file_path, "wb")
242
+ frames_encoded = 0
243
+ ivf_packets = 0
244
+
245
+ for input_gpu_frame in FetchGPUFrame(
246
+ input_frame_list,
247
+ FetchCPUFrame(decFile, input_frame_list[0].frameSize),
248
+ frames_to_process
249
+ ):
250
+ pic_params = nvc.NV_ENC_PIC_PARAMS()
251
+ pic_params.inputTimeStamp = frames_encoded
252
+ enc_list = nvenc.Encode(input_gpu_frame, pic_params)
253
+ ivf_packets += len(enc_list)
254
+ encFile.write(bytearray(_concat_encode_packets(enc_list)))
255
+ frames_encoded += 1
256
+
257
+ # Flush encoder queue
258
+ flush_list = nvenc.EndEncode()
259
+ ivf_packets += len(flush_list)
260
+ encFile.write(bytearray(_concat_encode_packets(flush_list)))
261
+ if _av1_ivf_elementary_enabled(config_params):
262
+ encFile.flush()
263
+ _patch_ivf_output_file(enc_file_path, ivf_packets)
264
+ encFile.close()
265
+
266
+ print(f"Completed encoding {frames_to_process} frames using GPU buffers")
267
+ print(f"Output file: {enc_file_path}")
268
+
269
+
270
+ def encode_unified(gpu_id, dec_file_path, enc_file_path, width, height, fmt, config_params, frame_count, buffer_mode):
271
+ """
272
+ Unified encoding function that supports both CPU and GPU buffer modes.
273
+
274
+ Parameters:
275
+ gpu_id (int): Ordinal of GPU to use
276
+ dec_file_path (str): Path to file to be decoded
277
+ enc_file_path (str): Path to output file for encoded frames
278
+ width (int): Width of encoded frame
279
+ height (int): Height of encoded frame
280
+ fmt (str): Surface format string in uppercase (e.g., "NV12")
281
+ config_params (dict): Key-value pairs providing fine-grained control on encoding
282
+ frame_count (int): Number of frames to encode
283
+ buffer_mode (str): Buffer mode - "cpu" or "gpu"
284
+
285
+ Returns:
286
+ None
287
+ """
288
+ try:
289
+ if buffer_mode.lower() == "cpu":
290
+ encode_cpu_buffer(gpu_id, dec_file_path, enc_file_path, width, height, fmt, config_params, frame_count)
291
+ elif buffer_mode.lower() == "gpu":
292
+ encode_gpu_buffer(gpu_id, dec_file_path, enc_file_path, width, height, fmt, config_params, frame_count)
293
+ else:
294
+ raise ValueError(f"Invalid buffer mode: {buffer_mode}. Must be 'cpu' or 'gpu'")
295
+
296
+ except nvc.PyNvVCExceptionUnsupported as e:
297
+ print(f"CreateEncoder failure: {e}")
298
+ except Exception as e:
299
+ print(f"An unexpected error occurred: {e}")
300
+
301
+
302
+ def validate_gpu_mode(args) -> None:
303
+ """Validate GPU buffer mode requirements."""
304
+ if args.buffer_mode == "gpu" and not GPU_UTILS_AVAILABLE:
305
+ print("Error: GPU buffer mode requires Utils module, but it's not available.")
306
+ print("Please use CPU buffer mode (-m cpu) or ensure Utils module is accessible.")
307
+ sys.exit(1)
308
+
309
+
310
+ if __name__ == "__main__":
311
+ args = parse_unified_args(
312
+ "Unified encoding application supporting both CPU and GPU buffer modes."
313
+ )
314
+
315
+ # Display configuration
316
+ print("=" * 60)
317
+ print("ENCODER CONFIGURATION")
318
+ print("=" * 60)
319
+ print(f"Buffer mode: {args.buffer_mode.upper()}")
320
+ print(f"Input file: {args.raw_file_path}")
321
+ print(f"Output file: {args.encoded_file_path}")
322
+ print(f"Resolution: {args.width}x{args.height}")
323
+ print(f"Format: {args.format}")
324
+ print(f"Codec: {args.codec}")
325
+ print(f"GPU ID: {args.gpu_id}")
326
+ print(f"Frame count: {args.frame_count if args.frame_count > 0 else 'All frames'}")
327
+ print("=" * 60)
328
+
329
+ # Validate GPU mode requirements
330
+ validate_gpu_mode(args)
331
+
332
+ # Run encoding
333
+ encode_unified(
334
+ args.gpu_id,
335
+ args.raw_file_path.as_posix(),
336
+ args.encoded_file_path.as_posix(),
337
+ args.width,
338
+ args.height,
339
+ args.format,
340
+ args.config,
341
+ args.frame_count,
342
+ args.buffer_mode,
343
+ )
344
+
345
+ print("=" * 60)
346
+ print("ENCODING COMPLETE")
347
+ print("=" * 60)
@@ -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,3 @@
1
+ 0.3 0.8
2
+ 2 4
3
+ 3 8