PyNvVideoCodec 2.0.0__cp312-cp312-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.
- PyNvVideoCodec/PyNvVideoCodec_121.cp312-win_amd64.pyd +0 -0
- PyNvVideoCodec/PyNvVideoCodec_130.cp312-win_amd64.pyd +0 -0
- PyNvVideoCodec/VersionCheck.cp312-win_amd64.pyd +0 -0
- PyNvVideoCodec/__init__.py +237 -0
- PyNvVideoCodec/avcodec-58.dll +0 -0
- PyNvVideoCodec/avcodec-61.dll +0 -0
- PyNvVideoCodec/avcodec.dll +0 -0
- PyNvVideoCodec/avdevice-58.dll +0 -0
- PyNvVideoCodec/avdevice-61.dll +0 -0
- PyNvVideoCodec/avdevice.dll +0 -0
- PyNvVideoCodec/avfilter-10.dll +0 -0
- PyNvVideoCodec/avfilter-7.dll +0 -0
- PyNvVideoCodec/avfilter.dll +0 -0
- PyNvVideoCodec/avformat-58.dll +0 -0
- PyNvVideoCodec/avformat-61.dll +0 -0
- PyNvVideoCodec/avformat.dll +0 -0
- PyNvVideoCodec/avutil-56.dll +0 -0
- PyNvVideoCodec/avutil-59.dll +0 -0
- PyNvVideoCodec/avutil.dll +0 -0
- PyNvVideoCodec/decoders/SimpleDecoder.py +225 -0
- PyNvVideoCodec/decoders/ThreadedDecoder.py +119 -0
- PyNvVideoCodec/decoders/__init__.py +22 -0
- PyNvVideoCodec/swresample-3.dll +0 -0
- PyNvVideoCodec/swresample-5.dll +0 -0
- PyNvVideoCodec/swresample.dll +0 -0
- PyNvVideoCodec/swscale-5.dll +0 -0
- PyNvVideoCodec/swscale-8.dll +0 -0
- PyNvVideoCodec/swscale.dll +0 -0
- PyNvVideoCodec/transcoder/Transcoder.py +55 -0
- PyNvVideoCodec/transcoder/__init__.py +22 -0
- PyNvVideoCodec-2.0.0.data/data/external/ffmpeg/readme.txt +10 -0
- PyNvVideoCodec-2.0.0.data/data/external/ffmpeg/src/ffmpeg-7.0.2.tar.xz +0 -0
- PyNvVideoCodec-2.0.0.dist-info/METADATA +77 -0
- PyNvVideoCodec-2.0.0.dist-info/RECORD +64 -0
- PyNvVideoCodec-2.0.0.dist-info/WHEEL +5 -0
- PyNvVideoCodec-2.0.0.dist-info/licenses/LICENSE.txt +22 -0
- PyNvVideoCodec-2.0.0.dist-info/licenses/NOTICES.txt +167 -0
- PyNvVideoCodec-2.0.0.dist-info/top_level.txt +3 -0
- benchmarks/cached_decoder_benchmark.py +635 -0
- benchmarks/frame_sampling_benchmark.py +610 -0
- benchmarks/segmented_transcode_benchmark.py +1072 -0
- samples/Decode.py +194 -0
- samples/DecodeMultiprocessing.py +162 -0
- samples/DecodePerf.py +215 -0
- samples/DecodeSEIMsgExtraction.py +338 -0
- samples/DemuxFromByteArray.py +185 -0
- samples/Encode.py +189 -0
- samples/EncodeFromCPUBuffer.py +220 -0
- samples/EncodeMultiprocessing.py +268 -0
- samples/EncodePerf.py +380 -0
- samples/EncodeReconfigure.py +201 -0
- samples/EncodeSEIMsgInsertion.py +189 -0
- samples/ObjectDetection.py +218 -0
- samples/SimpleDecoder/EnsembleApp.py +416 -0
- samples/SimpleDecoder/SubsamplingAndReconfigure.py +341 -0
- samples/SimpleDecoder/fileLists.txt +4 -0
- samples/SimpleDecoder/segments.txt +3 -0
- samples/SimpleDecoder/timeListInSeconds.txt +5 -0
- samples/SimpleDecoder/transcode_config.json +6 -0
- samples/Utils.py +290 -0
- samples/coco_classes.pickle +0 -0
- samples/encode_config.json +16 -0
- samples/encode_config_lowlatency.json +11 -0
- samples/encode_config_perf.json +9 -0
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
# This copyright notice applies to this file only
|
|
2
|
+
#
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2025 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
|
+
# Import necessary libraries
|
|
25
|
+
import argparse
|
|
26
|
+
import json
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
import PyNvVideoCodec as nvc
|
|
29
|
+
import numpy as np
|
|
30
|
+
import pycuda.driver as cuda
|
|
31
|
+
from pathlib import Path
|
|
32
|
+
from pycuda.autoinit import context
|
|
33
|
+
import sys
|
|
34
|
+
import os
|
|
35
|
+
from os.path import join, dirname, abspath
|
|
36
|
+
|
|
37
|
+
# Add the parent directory to Python path in a way that works from any working directory
|
|
38
|
+
current_dir = dirname(abspath(__file__))
|
|
39
|
+
parent_dir = dirname(current_dir)
|
|
40
|
+
if parent_dir not in sys.path:
|
|
41
|
+
sys.path.append(parent_dir)
|
|
42
|
+
|
|
43
|
+
from Utils import cast_address_to_1d_bytearray
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def frame_to_yuv(frames, use_device_memory):
|
|
47
|
+
"""
|
|
48
|
+
Converts frames to YUV format with option for device or host memory processing.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
frames: List of frames to convert
|
|
52
|
+
use_device_memory: Boolean flag to determine memory processing location
|
|
53
|
+
simple_decoder: Decoder object
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
frames_in_yuv: List of YUV frames as bytearrays
|
|
57
|
+
"""
|
|
58
|
+
frames_in_yuv = []
|
|
59
|
+
for frame in frames:
|
|
60
|
+
raw_frame = np.ndarray(shape=frame.framesize(), dtype=np.uint8)
|
|
61
|
+
luma_base_addr = frame.GetPtrToPlane(0)
|
|
62
|
+
if use_device_memory == True:
|
|
63
|
+
cuda.memcpy_dtoh(raw_frame, luma_base_addr)
|
|
64
|
+
else:
|
|
65
|
+
raw_frame = cast_address_to_1d_bytearray(base_address=luma_base_addr, size=frame.framesize())
|
|
66
|
+
bits = bytearray(raw_frame)
|
|
67
|
+
frames_in_yuv.append(bits)
|
|
68
|
+
|
|
69
|
+
return frames_in_yuv
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def save_frames_in_yuv(dec_file_path, frames, use_device_memory):
|
|
74
|
+
"""
|
|
75
|
+
Saves the frames in a YUV file.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
dec_file_path(str): YUV file path.
|
|
79
|
+
frames(List[DecodedFrame]): List of frames to convert
|
|
80
|
+
use_device_memory(bool): Boolean flag to determine memory processing location
|
|
81
|
+
|
|
82
|
+
"""
|
|
83
|
+
with open(dec_file_path, "ab") as decFile:
|
|
84
|
+
for frame in frames:
|
|
85
|
+
decoded_frame_size = frame.framesize()
|
|
86
|
+
raw_frame = np.ndarray(shape=decoded_frame_size, dtype=np.uint8)
|
|
87
|
+
luma_base_addr = frame.GetPtrToPlane(0)
|
|
88
|
+
if use_device_memory:
|
|
89
|
+
cuda.memcpy_dtoh(raw_frame, luma_base_addr)
|
|
90
|
+
bits = bytearray(raw_frame)
|
|
91
|
+
decFile.write(bits)
|
|
92
|
+
else:
|
|
93
|
+
new_array = cast_address_to_1d_bytearray(base_address=luma_base_addr, size=decoded_frame_size)
|
|
94
|
+
decFile.write(bytearray(new_array))
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def perform_batch_comparison(input_file_path, use_device_memory, gpu_id):
|
|
98
|
+
"""Compares sequential vs index-based batch frame retrieval methods."""
|
|
99
|
+
batch_size = 5
|
|
100
|
+
output_color_type = nvc.OutputColorType.NATIVE
|
|
101
|
+
print("1. Comparing batch frames retrieval methods:")
|
|
102
|
+
print(f"Method 1: Sequential batch (size={batch_size})")
|
|
103
|
+
print(f"Method 2: Index-based batch (indices=[0,1,2,3,4])\n")
|
|
104
|
+
|
|
105
|
+
simple_decoder = nvc.SimpleDecoder(input_file_path, need_scanned_stream_metadata=False,
|
|
106
|
+
use_device_memory=use_device_memory,
|
|
107
|
+
output_color_type=output_color_type,
|
|
108
|
+
gpu_id=gpu_id)
|
|
109
|
+
|
|
110
|
+
simple_decoder.seek_to_index(0)
|
|
111
|
+
batch_frames = simple_decoder.get_batch_frames(batch_size)
|
|
112
|
+
batch_frames_in_yuv = frame_to_yuv(batch_frames, use_device_memory)
|
|
113
|
+
batch_frames_idx_list = simple_decoder.get_batch_frames_by_index([0,1,2,3,4])
|
|
114
|
+
batch_frames_idx_list_yuv = frame_to_yuv(batch_frames_idx_list, use_device_memory)
|
|
115
|
+
|
|
116
|
+
if batch_frames_in_yuv == batch_frames_idx_list_yuv:
|
|
117
|
+
print("Results match: Both methods returned identical frame data\n")
|
|
118
|
+
else:
|
|
119
|
+
print("Results differ: Frame data mismatch between methods\n")
|
|
120
|
+
|
|
121
|
+
return simple_decoder
|
|
122
|
+
|
|
123
|
+
def perform_frame_slicing(simple_decoder, use_device_memory):
|
|
124
|
+
"""Validates frame extraction using slice operations vs sequential parsing."""
|
|
125
|
+
print("2. Get frames by slicing [start:end:step] and get frames by sequential parsing\n")
|
|
126
|
+
|
|
127
|
+
sliced_frames = simple_decoder[0:10:2]
|
|
128
|
+
sliced_frames_in_yuv = frame_to_yuv(sliced_frames, use_device_memory)
|
|
129
|
+
|
|
130
|
+
seq_frames_in_yuv = []
|
|
131
|
+
for i in range(10):
|
|
132
|
+
if (i%2)==0:
|
|
133
|
+
frame = simple_decoder[i]
|
|
134
|
+
raw_frame = np.ndarray(shape=frame.framesize(), dtype=np.uint8)
|
|
135
|
+
luma_base_addr = frame.GetPtrToPlane(0)
|
|
136
|
+
if use_device_memory == True:
|
|
137
|
+
cuda.memcpy_dtoh(raw_frame, luma_base_addr)
|
|
138
|
+
else:
|
|
139
|
+
raw_frame = cast_address_to_1d_bytearray(base_address=luma_base_addr, size=frame.framesize())
|
|
140
|
+
bits = bytearray(raw_frame)
|
|
141
|
+
seq_frames_in_yuv.append(bits)
|
|
142
|
+
|
|
143
|
+
if seq_frames_in_yuv==sliced_frames_in_yuv:
|
|
144
|
+
print("Results match: Both methods returned identical frame data\n")
|
|
145
|
+
else:
|
|
146
|
+
print("Results differ: Frame data mismatch between methods\n")
|
|
147
|
+
|
|
148
|
+
def perform_timestamp_extraction(simple_decoder, time_file_path, use_device_memory):
|
|
149
|
+
"""Extracts frames using timestamp-based indexing."""
|
|
150
|
+
print("3. Get frames for input time list in seconds\n")
|
|
151
|
+
|
|
152
|
+
out_yuv_path = "framesFromInputTimeList.yuv"
|
|
153
|
+
# Delete existing file before writing
|
|
154
|
+
if os.path.exists(out_yuv_path):
|
|
155
|
+
os.remove(out_yuv_path)
|
|
156
|
+
target_frame_indices=[]
|
|
157
|
+
|
|
158
|
+
with open(time_file_path, 'r') as file:
|
|
159
|
+
for line in file:
|
|
160
|
+
try:
|
|
161
|
+
time_value = float(line.strip())
|
|
162
|
+
target_frame_idx = simple_decoder.get_index_from_time_in_seconds(time_value)
|
|
163
|
+
target_frame_indices.append(target_frame_idx)
|
|
164
|
+
frame = simple_decoder[target_frame_idx]
|
|
165
|
+
save_frames_in_yuv(out_yuv_path, [frame], use_device_memory)
|
|
166
|
+
except ValueError:
|
|
167
|
+
print(f"Warning: Skipping invalid time value: {line.strip()}")
|
|
168
|
+
|
|
169
|
+
with open('timeValueIndices.txt', 'w') as file:
|
|
170
|
+
file.write(str(target_frame_indices))
|
|
171
|
+
|
|
172
|
+
print(f"Successfully saved frames to: {out_yuv_path}\n")
|
|
173
|
+
print(f"Indices corresponding to the time values are saved in timeValueIndices.txt\n")
|
|
174
|
+
|
|
175
|
+
def perform_keyframe_extraction(input_file_path, use_device_memory, gpu_id):
|
|
176
|
+
"""Extracts and identifies keyframes."""
|
|
177
|
+
print("4. Get key frames\n")
|
|
178
|
+
simple_decoder = nvc.SimpleDecoder(input_file_path, need_scanned_stream_metadata=True,
|
|
179
|
+
use_device_memory=use_device_memory, gpu_id=gpu_id)
|
|
180
|
+
metadata = simple_decoder.get_scanned_stream_metadata()
|
|
181
|
+
key_frame_indices = metadata.key_frame_indices
|
|
182
|
+
|
|
183
|
+
with open('keyFrameIndices.txt', 'w') as file:
|
|
184
|
+
file.write(str(key_frame_indices))
|
|
185
|
+
|
|
186
|
+
key_frames_batch = [key_frame_indices[i:i + 8] for i in range(0, len(key_frame_indices), 8)]
|
|
187
|
+
out_yuv_path = "keyFrames.yuv"
|
|
188
|
+
# Delete existing file before writing
|
|
189
|
+
if os.path.exists(out_yuv_path):
|
|
190
|
+
os.remove(out_yuv_path)
|
|
191
|
+
|
|
192
|
+
for frames in key_frames_batch:
|
|
193
|
+
batch_frames = simple_decoder.get_batch_frames_by_index(frames)
|
|
194
|
+
save_frames_in_yuv(out_yuv_path, batch_frames, use_device_memory)
|
|
195
|
+
|
|
196
|
+
print(f"Successfully saved frames to: {out_yuv_path}\n")
|
|
197
|
+
print(f"Key frame indices are saved in keyFrameIndices.txt\n")
|
|
198
|
+
|
|
199
|
+
def perform_segment_generation(input_file_path, segments_file_path, config_file_path, segment_output_template, gpu_id):
|
|
200
|
+
"""Generates video segments based on time ranges."""
|
|
201
|
+
print("5. Get segments given start and end time values.")
|
|
202
|
+
|
|
203
|
+
with open(config_file_path) as jsonFile:
|
|
204
|
+
config = json.loads(jsonFile.read())
|
|
205
|
+
|
|
206
|
+
with open(segments_file_path, 'r') as file:
|
|
207
|
+
for line in file:
|
|
208
|
+
try:
|
|
209
|
+
time_values = line.strip()
|
|
210
|
+
if not time_values: # Skip empty lines
|
|
211
|
+
continue
|
|
212
|
+
start_ts_str, end_ts_str = time_values.split(' ')
|
|
213
|
+
|
|
214
|
+
input_file_name_base = os.path.splitext(os.path.basename(input_file_path))[0]
|
|
215
|
+
|
|
216
|
+
# Template is for the base path, should primarily use {input_file_name}
|
|
217
|
+
base_path_template_vars = {
|
|
218
|
+
"input_file_name": input_file_name_base
|
|
219
|
+
}
|
|
220
|
+
# This is the base path to be passed to the Transcoder
|
|
221
|
+
base_segment_output_path = segment_output_template.format(**base_path_template_vars)
|
|
222
|
+
|
|
223
|
+
# Ensure the output path has an extension, default to .mp4 if none provided
|
|
224
|
+
base_output_name_part, base_output_ext_part = os.path.splitext(base_segment_output_path)
|
|
225
|
+
if not base_output_ext_part:
|
|
226
|
+
base_output_ext_part = '.mp4'
|
|
227
|
+
base_segment_output_path = base_output_name_part + base_output_ext_part
|
|
228
|
+
|
|
229
|
+
# Construct the final expected path for printing
|
|
230
|
+
final_expected_path = f"{base_output_name_part}_{start_ts_str}_{end_ts_str}{base_output_ext_part}"
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
tr = nvc.Transcoder(input_file_path,
|
|
234
|
+
base_segment_output_path, # Pass base path
|
|
235
|
+
gpu_id,
|
|
236
|
+
0, 0,
|
|
237
|
+
**config)
|
|
238
|
+
|
|
239
|
+
tr.segmented_transcode(float(start_ts_str), float(end_ts_str))
|
|
240
|
+
# Use the constructed final_expected_path for the confirmation message
|
|
241
|
+
print(f"Segmented output saved as {final_expected_path}")
|
|
242
|
+
except ValueError:
|
|
243
|
+
print(f"Warning: Skipping invalid time value or format: {line.strip()}")
|
|
244
|
+
except Exception as e:
|
|
245
|
+
print(f"An error occurred while processing segment: {line.strip()}. Error: {e}")
|
|
246
|
+
|
|
247
|
+
def get_enabled_operations(operation_ids=None):
|
|
248
|
+
"""Determines which operations should be run based on provided IDs."""
|
|
249
|
+
# Define mapping between operation IDs and names
|
|
250
|
+
operation_map = {
|
|
251
|
+
1: 'batch_comparison',
|
|
252
|
+
2: 'frame_slicing',
|
|
253
|
+
3: 'timestamp_extraction',
|
|
254
|
+
4: 'keyframe_extraction',
|
|
255
|
+
5: 'segment_generation'
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
# Define all available operations
|
|
259
|
+
all_operations = {
|
|
260
|
+
'batch_comparison': False,
|
|
261
|
+
'frame_slicing': False,
|
|
262
|
+
'timestamp_extraction': False,
|
|
263
|
+
'keyframe_extraction': False,
|
|
264
|
+
'segment_generation': False
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
# If no operations specified, run all operations
|
|
268
|
+
if not operation_ids:
|
|
269
|
+
for operation in all_operations:
|
|
270
|
+
all_operations[operation] = True
|
|
271
|
+
else:
|
|
272
|
+
# Enable only selected operations
|
|
273
|
+
for op_id in operation_ids:
|
|
274
|
+
if op_id in operation_map:
|
|
275
|
+
all_operations[operation_map[op_id]] = True
|
|
276
|
+
else:
|
|
277
|
+
print(f"Warning: Unknown operation ID '{op_id}' specified - skipping")
|
|
278
|
+
|
|
279
|
+
return all_operations
|
|
280
|
+
|
|
281
|
+
def ensemble_app(input_file_path, time_file_path, use_device_memory, segments_file_path, config_file_path, gpu_id, segment_output_template, operation_ids=None):
|
|
282
|
+
'''
|
|
283
|
+
Validates and compares different frame extraction methods from a video source:
|
|
284
|
+
|
|
285
|
+
Available operations:
|
|
286
|
+
1. Batch Frame Comparison: Compares sequential vs index-based frame retrieval
|
|
287
|
+
2. Frame Slicing: Validates frame extraction using slice operations vs sequential parsing
|
|
288
|
+
3. Timestamp Extraction: Tests frame retrieval using timestamp-based indexing
|
|
289
|
+
4. Keyframe Extraction: Verifies keyframe identification and extraction
|
|
290
|
+
5. Segment Generation: Retrieves video segments based on start and end time values
|
|
291
|
+
'''
|
|
292
|
+
|
|
293
|
+
try:
|
|
294
|
+
# Determine which operations to run
|
|
295
|
+
all_operations = get_enabled_operations(operation_ids)
|
|
296
|
+
|
|
297
|
+
# Initialize decoder for operations that share it
|
|
298
|
+
simple_decoder = None
|
|
299
|
+
|
|
300
|
+
# Perform enabled operations
|
|
301
|
+
if all_operations['batch_comparison']:
|
|
302
|
+
simple_decoder = perform_batch_comparison(input_file_path, use_device_memory, gpu_id)
|
|
303
|
+
|
|
304
|
+
if all_operations['frame_slicing']:
|
|
305
|
+
if not simple_decoder:
|
|
306
|
+
simple_decoder = nvc.SimpleDecoder(input_file_path, need_scanned_stream_metadata=False,
|
|
307
|
+
use_device_memory=use_device_memory, gpu_id=gpu_id)
|
|
308
|
+
perform_frame_slicing(simple_decoder, use_device_memory)
|
|
309
|
+
|
|
310
|
+
if all_operations['timestamp_extraction']:
|
|
311
|
+
if not simple_decoder:
|
|
312
|
+
simple_decoder = nvc.SimpleDecoder(input_file_path, need_scanned_stream_metadata=False,
|
|
313
|
+
use_device_memory=use_device_memory, gpu_id=gpu_id)
|
|
314
|
+
perform_timestamp_extraction(simple_decoder, time_file_path, use_device_memory)
|
|
315
|
+
|
|
316
|
+
if all_operations['keyframe_extraction']:
|
|
317
|
+
perform_keyframe_extraction(input_file_path, use_device_memory, gpu_id)
|
|
318
|
+
|
|
319
|
+
if all_operations['segment_generation']:
|
|
320
|
+
perform_segment_generation(input_file_path, segments_file_path, config_file_path, segment_output_template, gpu_id)
|
|
321
|
+
|
|
322
|
+
except Exception as e:
|
|
323
|
+
print(f"An unexpected error occurred: {e}")
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
if __name__ == "__main__":
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
parser = argparse.ArgumentParser("This sample application demonstrates different functionalities of Simple Decoder & Simple transcoder",
|
|
330
|
+
formatter_class=argparse.RawTextHelpFormatter)
|
|
331
|
+
|
|
332
|
+
parser.add_argument("-i", "--input_file_path",
|
|
333
|
+
required=True,
|
|
334
|
+
type=Path,
|
|
335
|
+
help='Path to input video file' )
|
|
336
|
+
|
|
337
|
+
parser.add_argument("-g", "--gpu_id",
|
|
338
|
+
type=int,
|
|
339
|
+
default=0,
|
|
340
|
+
help="Check nvidia-smi for available GPUs. Default: 0"
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
parser.add_argument("-t", '--time_file_path',
|
|
345
|
+
type=Path,
|
|
346
|
+
default=join(current_dir, "timeListInSeconds.txt"),
|
|
347
|
+
help='''Path to the input time file.
|
|
348
|
+
File format requirements:
|
|
349
|
+
- One time value (in seconds) per line
|
|
350
|
+
- Values should be numeric (integer or decimal)
|
|
351
|
+
- Empty lines will be ignored
|
|
352
|
+
Default: timeListInSeconds.txt in the same directory'''
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
parser.add_argument("-d", "--use_device_memory",
|
|
356
|
+
choices=[0, 1],
|
|
357
|
+
default=1,
|
|
358
|
+
type=int,
|
|
359
|
+
help="Decoder output surface is in device memory else in "
|
|
360
|
+
"host memory. Default is 1 (device memory).",
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
parser.add_argument("-json", "--config_file_path",
|
|
364
|
+
type=Path,
|
|
365
|
+
default=join(current_dir, "transcode_config.json"),
|
|
366
|
+
help="Path of json config file (default: transcode_config.json in the same directory)", )
|
|
367
|
+
|
|
368
|
+
parser.add_argument("-segments", '--segments_file_path',
|
|
369
|
+
type=Path,
|
|
370
|
+
default=join(current_dir, "segments.txt"),
|
|
371
|
+
help='''Path to the input segment file.
|
|
372
|
+
File format requirements:
|
|
373
|
+
- Each line should contain a start and end time value separated by a space.
|
|
374
|
+
- Values should be numeric (integer or decimal)
|
|
375
|
+
- Empty lines will be ignored
|
|
376
|
+
Default: segments.txt in the same directory'''
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
parser.add_argument("-so", "--segment-output",
|
|
380
|
+
type=str,
|
|
381
|
+
default="{input_file_name}.mp4",
|
|
382
|
+
help='''Base output file name template for segmented transcode.
|
|
383
|
+
The API will append '_{start_ts}_{end_ts}' (e.g., _0.0_10.5) to this base name.
|
|
384
|
+
Default: '{input_file_name}_segment.mp4'''
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
parser.add_argument("-o", "--operations",
|
|
388
|
+
type=int,
|
|
389
|
+
nargs='+',
|
|
390
|
+
choices=range(1, 6),
|
|
391
|
+
help='''Specify which decoder/transcoder operations to perform using operation IDs. Multiple IDs can be specified. IDs should be separated by space.
|
|
392
|
+
Available operations:
|
|
393
|
+
1. Batch Frame Comparison: Compare sequential vs index-based frame retrieval
|
|
394
|
+
2. Frame Slicing: Perform frame slicing operations vs sequential parsing
|
|
395
|
+
3. Timestamp Extraction: Extract frames using timestamps
|
|
396
|
+
4. Keyframe Extraction: Extract and identify keyframes
|
|
397
|
+
5. Segment Generation: Generate video segments based on time ranges
|
|
398
|
+
If not specified, all operations will be performed.''')
|
|
399
|
+
|
|
400
|
+
args = parser.parse_args()
|
|
401
|
+
input_file_path = args.input_file_path.as_posix()
|
|
402
|
+
time_file_path = args.time_file_path.as_posix()
|
|
403
|
+
config_file_path = args.config_file_path.as_posix()
|
|
404
|
+
segments_file_path = args.segments_file_path.as_posix()
|
|
405
|
+
use_device_memory = args.use_device_memory
|
|
406
|
+
gpu_id = args.gpu_id
|
|
407
|
+
operation_ids = args.operations
|
|
408
|
+
segment_output_template_arg = args.segment_output
|
|
409
|
+
|
|
410
|
+
ensemble_app(input_file_path, time_file_path, use_device_memory, segments_file_path, config_file_path, gpu_id, segment_output_template_arg, operation_ids)
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
|