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.
- PyNvVideoCodec/PyNvVideoCodec_121.cp314-win_amd64.pyd +0 -0
- PyNvVideoCodec/PyNvVideoCodec_130.cp314-win_amd64.pyd +0 -0
- PyNvVideoCodec/VersionCheck.cp314-win_amd64.pyd +0 -0
- PyNvVideoCodec/__init__.py +246 -0
- PyNvVideoCodec/avcodec-62.dll +0 -0
- PyNvVideoCodec/avdevice-62.dll +0 -0
- PyNvVideoCodec/avfilter-11.dll +0 -0
- PyNvVideoCodec/avformat-62.dll +0 -0
- PyNvVideoCodec/avutil-60.dll +0 -0
- PyNvVideoCodec/decoders/SimpleDecoder.py +230 -0
- PyNvVideoCodec/decoders/ThreadedDecoder.py +129 -0
- PyNvVideoCodec/decoders/__init__.py +22 -0
- PyNvVideoCodec/swresample-6.dll +0 -0
- PyNvVideoCodec/swscale-9.dll +0 -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 +47 -0
- benchmarks/segmented_transcode_benchmark.py +1546 -0
- pynvvideocodec-2.0.4.data/data/external/ffmpeg/readme.txt +15 -0
- pynvvideocodec-2.0.4.data/data/external/ffmpeg/src/ffmpeg-8.1.1.tar.xz +0 -0
- pynvvideocodec-2.0.4.dist-info/METADATA +84 -0
- pynvvideocodec-2.0.4.dist-info/RECORD +65 -0
- pynvvideocodec-2.0.4.dist-info/WHEEL +5 -0
- pynvvideocodec-2.0.4.dist-info/licenses/LICENSE.txt +22 -0
- pynvvideocodec-2.0.4.dist-info/licenses/NOTICES.txt +167 -0
- pynvvideocodec-2.0.4.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 +9 -0
- samples/advanced/encode_config_lowlatency.json +11 -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_stats.py +179 -0
- samples/advanced/transcode.py +288 -0
- samples/basic/create_video_segments.py +187 -0
- samples/basic/encode.py +347 -0
- samples/basic/encode_config.json +9 -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/object_detection_tutorial.ipynb +762 -0
- samples/jupyter/simple_decode_tutorial.ipynb +651 -0
- samples/requirements.txt +78 -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 +357 -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
samples/requirements.txt
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
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
|
+
# Requirements for PyNvVideoCodec Sample Applications
|
|
25
|
+
# This file covers dependencies for:
|
|
26
|
+
# - samples/basic/
|
|
27
|
+
# - samples/advanced/
|
|
28
|
+
# - samples/jupyter/ (object_detection_tutorial.ipynb, simple_decode_tutorial.ipynb)
|
|
29
|
+
|
|
30
|
+
# IMPORTANT: PyTorch must be installed separately with CUDA support!
|
|
31
|
+
# DO NOT install torch/torchvision from this file directly as it may install CPU-only versions.
|
|
32
|
+
# See installation instructions at the bottom of this file.
|
|
33
|
+
|
|
34
|
+
# Core dependencies (required for most samples)
|
|
35
|
+
numpy>=1.21.0
|
|
36
|
+
pycuda>=2021.1
|
|
37
|
+
|
|
38
|
+
# PyNvVideoCodec (assuming it's installed separately or available locally)
|
|
39
|
+
# PyNvVideoCodec
|
|
40
|
+
|
|
41
|
+
# For visualization in jupyter notebooks
|
|
42
|
+
matplotlib>=3.3.0
|
|
43
|
+
|
|
44
|
+
# For downloading sample videos in jupyter notebooks
|
|
45
|
+
requests>=2.25.0
|
|
46
|
+
|
|
47
|
+
# For running Jupyter notebooks
|
|
48
|
+
jupyter>=1.0.0
|
|
49
|
+
jupyterlab>=3.0.0
|
|
50
|
+
ipython>=7.20.0
|
|
51
|
+
|
|
52
|
+
# PyTorch with CUDA 13.0 support
|
|
53
|
+
# See: https://download.pytorch.org/whl/cu130/torch/
|
|
54
|
+
--extra-index-url https://download.pytorch.org/whl/cu130
|
|
55
|
+
torch==2.9.1
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# Note: Standard library modules used (no installation needed):
|
|
59
|
+
# - json, os, sys, pathlib, argparse, time, threading, multiprocessing
|
|
60
|
+
# - queue, ctypes, pickle, datetime, gc, atexit
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# Running Jupyter Notebooks:
|
|
64
|
+
#
|
|
65
|
+
# Option 1 - Using Jupyter Notebook (Classic):
|
|
66
|
+
# jupyter notebook
|
|
67
|
+
# # Then navigate to samples/jupyter/ and open the desired .ipynb file
|
|
68
|
+
#
|
|
69
|
+
# Option 2 - Using JupyterLab (Recommended):
|
|
70
|
+
# jupyter lab
|
|
71
|
+
# # Then navigate to samples/jupyter/ and open the desired .ipynb file
|
|
72
|
+
#
|
|
73
|
+
# Option 3 - Using specific notebook:
|
|
74
|
+
# jupyter notebook samples/jupyter/object_detection_tutorial.ipynb
|
|
75
|
+
# jupyter notebook samples/jupyter/simple_decode_tutorial.ipynb
|
|
76
|
+
#
|
|
77
|
+
# Note: Ensure PyNvVideoCodec is installed before running the notebooks
|
|
78
|
+
|
samples/utils/Utils.py
ADDED
|
@@ -0,0 +1,405 @@
|
|
|
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
|
+
import sys
|
|
25
|
+
import logging
|
|
26
|
+
|
|
27
|
+
from struct import pack
|
|
28
|
+
import sys
|
|
29
|
+
import os
|
|
30
|
+
import argparse
|
|
31
|
+
from pathlib import Path
|
|
32
|
+
from enum import Enum
|
|
33
|
+
|
|
34
|
+
import pycuda.driver as cuda
|
|
35
|
+
import PyNvVideoCodec as nvc
|
|
36
|
+
import numpy as np
|
|
37
|
+
from pycuda.compiler import SourceModule
|
|
38
|
+
import ctypes as C
|
|
39
|
+
from typing import List
|
|
40
|
+
import torch
|
|
41
|
+
|
|
42
|
+
import pycuda.autoinit as context
|
|
43
|
+
import json
|
|
44
|
+
|
|
45
|
+
from contextlib import contextmanager
|
|
46
|
+
|
|
47
|
+
import io
|
|
48
|
+
import tempfile
|
|
49
|
+
|
|
50
|
+
SERVICE_LOGGING_FORMAT = (
|
|
51
|
+
"[{filename:s}][{funcName:s}:{lineno:d}]" + "[{levelname:s}] {message:s}"
|
|
52
|
+
)
|
|
53
|
+
SERVICE_LOGGING_STREAM = sys.stdout
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def get_logger(logger_name, log_level="info"):
|
|
57
|
+
SERVICE_LOGGING_LEVEL = getattr(logging, log_level.upper(), None)
|
|
58
|
+
|
|
59
|
+
logger = logging.getLogger(logger_name)
|
|
60
|
+
logger.setLevel(SERVICE_LOGGING_LEVEL)
|
|
61
|
+
ch = logging.StreamHandler(SERVICE_LOGGING_STREAM)
|
|
62
|
+
formatter = logging.Formatter(SERVICE_LOGGING_FORMAT, style="{")
|
|
63
|
+
ch.setFormatter(formatter)
|
|
64
|
+
ch.setLevel(SERVICE_LOGGING_LEVEL)
|
|
65
|
+
logger.addHandler(ch)
|
|
66
|
+
logger.propagate = False
|
|
67
|
+
|
|
68
|
+
return logger
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
logger = get_logger(__file__)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def cast_address_to_1d_bytearray(base_address, size):
|
|
75
|
+
return np.ctypeslib.as_array(C.cast(base_address, C.POINTER(C.c_uint8)),
|
|
76
|
+
shape=(size,))
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
from contextlib import contextmanager
|
|
80
|
+
import ctypes
|
|
81
|
+
import io
|
|
82
|
+
import os, sys
|
|
83
|
+
import tempfile
|
|
84
|
+
|
|
85
|
+
class AppCAI:
|
|
86
|
+
def __init__(self, shape, stride, typestr, gpualloc):
|
|
87
|
+
shape_int = tuple([int(x) for x in shape])
|
|
88
|
+
stride_int = tuple([int(x) for x in stride])
|
|
89
|
+
self.__cuda_array_interface__ = {"shape": shape_int, "strides": stride_int, "data": (int(gpualloc), False),
|
|
90
|
+
"typestr": typestr, "version": 3}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class AppFrame:
|
|
94
|
+
def __init__(self, width, height, format):
|
|
95
|
+
if format == "NV12":
|
|
96
|
+
nv12_frame_size = int(width * height * 3 / 2)
|
|
97
|
+
self.gpuAlloc = cuda.mem_alloc(nv12_frame_size)
|
|
98
|
+
self.cai = []
|
|
99
|
+
self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", self.gpuAlloc))
|
|
100
|
+
chroma_alloc = int(self.gpuAlloc) + width * height
|
|
101
|
+
self.cai.append(AppCAI((int(height / 2), int(width / 2), 2), (width, 2, 1), "|u1", chroma_alloc))
|
|
102
|
+
self.frameSize = nv12_frame_size
|
|
103
|
+
if format == "ARGB" or format == "ABGR":
|
|
104
|
+
self.frameSize = width * height * 4
|
|
105
|
+
self.gpuAlloc = cuda.mem_alloc(self.frameSize)
|
|
106
|
+
self.cai = AppCAI((height, width, 4), (4 * width, 4, 1), "|u1", self.gpuAlloc)
|
|
107
|
+
if format == "YUV444":
|
|
108
|
+
self.frameSize = width * height * 3
|
|
109
|
+
self.gpuAlloc = cuda.mem_alloc(self.frameSize)
|
|
110
|
+
self.cai = []
|
|
111
|
+
self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", self.gpuAlloc))
|
|
112
|
+
self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", int(self.gpuAlloc) + width * height))
|
|
113
|
+
self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", int(self.gpuAlloc) + 2 * width * height))
|
|
114
|
+
if format == "YUV420":
|
|
115
|
+
self.frameSize = int(width * height * 3 / 2)
|
|
116
|
+
self.gpuAlloc = cuda.mem_alloc(self.frameSize)
|
|
117
|
+
self.cai = []
|
|
118
|
+
self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", self.gpuAlloc))
|
|
119
|
+
self.cai.append(
|
|
120
|
+
AppCAI((height / 2, width / 2, 1), (width / 2, 1, 1), "|u1", int(self.gpuAlloc) + width * height))
|
|
121
|
+
self.cai.append(AppCAI((height / 2, width / 2, 1), (width / 2, 1, 1), "|u1",
|
|
122
|
+
int(self.gpuAlloc) + width * height + width / 2 * height / 2))
|
|
123
|
+
if format == "P010" or format == "YUV420_10BIT":
|
|
124
|
+
self.frameSize = int(width * height * 3 / 2 * 2)
|
|
125
|
+
self.gpuAlloc = cuda.mem_alloc(self.frameSize)
|
|
126
|
+
self.cai = []
|
|
127
|
+
self.cai.append(AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", self.gpuAlloc))
|
|
128
|
+
chroma_alloc = int(self.gpuAlloc) + width * height * 2
|
|
129
|
+
self.cai.append(AppCAI((int(height / 2), int(width / 2), 2), (width*2, 2, 1), "|u2", chroma_alloc))
|
|
130
|
+
if format == "P016" or format == "YUV444_16BIT":
|
|
131
|
+
self.frameSize = int(width * height * 3 * 2)
|
|
132
|
+
self.gpuAlloc = cuda.mem_alloc(self.frameSize)
|
|
133
|
+
self.cai = []
|
|
134
|
+
self.cai.append(AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", self.gpuAlloc))
|
|
135
|
+
self.cai.append(
|
|
136
|
+
AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", int(self.gpuAlloc) + width * height * 2))
|
|
137
|
+
self.cai.append(
|
|
138
|
+
AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", int(self.gpuAlloc) + width * height * 4))
|
|
139
|
+
|
|
140
|
+
if format == "NV16":
|
|
141
|
+
self.frameSize = width * height * 2
|
|
142
|
+
self.gpuAlloc = cuda.mem_alloc(self.frameSize)
|
|
143
|
+
self.cai = []
|
|
144
|
+
self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", self.gpuAlloc))
|
|
145
|
+
self.cai.append(AppCAI((height, width, 1), (width, 1, 1 ), "|u1", int(self.gpuAlloc) + width * height))
|
|
146
|
+
|
|
147
|
+
if format == "P210":
|
|
148
|
+
self.frameSize = width * height * 2 * 2
|
|
149
|
+
self.gpuAlloc = cuda.mem_alloc(self.frameSize)
|
|
150
|
+
self.cai = []
|
|
151
|
+
self.cai.append(AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", self.gpuAlloc))
|
|
152
|
+
self.cai.append(AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", int(self.gpuAlloc) + width * height * 2))
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def cuda(self):
|
|
157
|
+
return self.cai
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class AppFramePerf:
|
|
161
|
+
def __init__(self, width, height, format, dataptr, frame_idx):
|
|
162
|
+
if format == "NV12":
|
|
163
|
+
nv12_frame_size = int(width * height * 3 / 2)
|
|
164
|
+
self.gpuAlloc = int(dataptr) + (frame_idx * nv12_frame_size)
|
|
165
|
+
self.cai = []
|
|
166
|
+
self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", self.gpuAlloc))
|
|
167
|
+
chroma_alloc = int(self.gpuAlloc) + width * height
|
|
168
|
+
self.cai.append(AppCAI((int(height / 2), int(width / 2), 2), (width, 2, 1), "|u1", chroma_alloc))
|
|
169
|
+
self.frameSize = nv12_frame_size
|
|
170
|
+
if format == "ARGB" or format == "ABGR":
|
|
171
|
+
self.frameSize = width * height * 4
|
|
172
|
+
self.gpuAlloc = int(dataptr) + (frame_idx * self.frameSize)
|
|
173
|
+
self.cai = AppCAI((height, width, 4), (4 * width, 4, 1), "|u1", self.gpuAlloc)
|
|
174
|
+
if format == "YUV444":
|
|
175
|
+
self.frameSize = width * height * 3
|
|
176
|
+
self.gpuAlloc = int(dataptr) + (frame_idx * self.frameSize)
|
|
177
|
+
self.cai = []
|
|
178
|
+
self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", self.gpuAlloc))
|
|
179
|
+
self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", int(self.gpuAlloc) + width * height))
|
|
180
|
+
self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", int(self.gpuAlloc) + 2 * width * height))
|
|
181
|
+
if format == "YUV420":
|
|
182
|
+
self.frameSize = int(width * height * 3 / 2)
|
|
183
|
+
self.gpuAlloc = int(dataptr) + (frame_idx * self.frameSize)
|
|
184
|
+
self.cai = []
|
|
185
|
+
self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", self.gpuAlloc))
|
|
186
|
+
self.cai.append(
|
|
187
|
+
AppCAI((height / 2, width / 2, 1), (width / 2, 1, 1), "|u1", int(self.gpuAlloc) + width * height))
|
|
188
|
+
self.cai.append(AppCAI((height / 2, width / 2, 1), (width / 2, 1, 1), "|u1",
|
|
189
|
+
int(self.gpuAlloc) + width * height + width / 2 * height / 2))
|
|
190
|
+
if format == "P010" or format == "YUV420_10BIT":
|
|
191
|
+
self.frameSize = int(width * height * 3 / 2 * 2)
|
|
192
|
+
self.gpuAlloc = int(dataptr) + (frame_idx * self.frameSize)
|
|
193
|
+
self.cai = []
|
|
194
|
+
self.cai.append(AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", self.gpuAlloc))
|
|
195
|
+
chroma_alloc = int(self.gpuAlloc) + width * height * 2
|
|
196
|
+
self.cai.append(AppCAI((int(height / 2), int(width / 2), 2), (width*2, 2, 1), "|u2", chroma_alloc))
|
|
197
|
+
if format == "P016" or format == "YUV444_16BIT":
|
|
198
|
+
self.frameSize = int(width * height * 3 * 2)
|
|
199
|
+
self.gpuAlloc = int(dataptr) + (frame_idx * self.frameSize)
|
|
200
|
+
self.cai = []
|
|
201
|
+
self.cai.append(AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", self.gpuAlloc))
|
|
202
|
+
self.cai.append(
|
|
203
|
+
AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", int(self.gpuAlloc) + width * height * 2))
|
|
204
|
+
self.cai.append(
|
|
205
|
+
AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", int(self.gpuAlloc) + width * height * 4))
|
|
206
|
+
if format == "NV16":
|
|
207
|
+
self.frameSize = width * height * 2
|
|
208
|
+
self.gpuAlloc = int(dataptr) + (frame_idx * self.frameSize)
|
|
209
|
+
self.cai = []
|
|
210
|
+
self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", self.gpuAlloc))
|
|
211
|
+
self.cai.append(AppCAI((height, width, 1), (width, 1, 1), "|u1", int(self.gpuAlloc) + width * height))
|
|
212
|
+
if format == "P210":
|
|
213
|
+
self.frameSize = width * height * 2 * 2
|
|
214
|
+
self.gpuAlloc = int(dataptr) + (frame_idx * self.frameSize)
|
|
215
|
+
self.cai = []
|
|
216
|
+
self.cai.append(AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", self.gpuAlloc))
|
|
217
|
+
self.cai.append(AppCAI((height, width, 1), (width * 2, 2, 1), "|u2", int(self.gpuAlloc) + width * height * 2))
|
|
218
|
+
|
|
219
|
+
def cuda(self):
|
|
220
|
+
return self.cai
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def FetchGPUFrame(input_frame_list, GetCPUFrameFunc, num_frames):
|
|
224
|
+
for i in range(num_frames):
|
|
225
|
+
n = i % len(input_frame_list)
|
|
226
|
+
raw_frame = GetCPUFrameFunc()
|
|
227
|
+
if not raw_frame.size:
|
|
228
|
+
return
|
|
229
|
+
cuda.memcpy_htod(input_frame_list[n].gpuAlloc, raw_frame)
|
|
230
|
+
cuda.Context.synchronize()
|
|
231
|
+
yield input_frame_list[n]
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def FetchCPUFrame(dec_file, frame_size):
|
|
236
|
+
def InnerFunc():
|
|
237
|
+
return np.fromfile(dec_file, np.uint8, count=frame_size)
|
|
238
|
+
|
|
239
|
+
return InnerFunc
|
|
240
|
+
|
|
241
|
+
def GetChromaFormat(demuxer):
|
|
242
|
+
strFormat = "NV12"
|
|
243
|
+
|
|
244
|
+
bitdepth = demuxer.BitDepth()
|
|
245
|
+
chromaformat = demuxer.ChromaFormat()
|
|
246
|
+
|
|
247
|
+
#print (" bitdepth : " + str(bitdepth))
|
|
248
|
+
#print (" chromaformat : " + str(chromaformat))
|
|
249
|
+
|
|
250
|
+
if str(chromaformat) == str("cudaVideoChromaFormat.444"):
|
|
251
|
+
if bitdepth == 10:
|
|
252
|
+
strFormat = "YUV444_10BIT"
|
|
253
|
+
elif bitdepth == 16:
|
|
254
|
+
strFormat = "YUV444_16BIT"
|
|
255
|
+
elif bitdepth == 12:
|
|
256
|
+
strFormat = "YUV444_16BIT"
|
|
257
|
+
print ("Unsupported bitdepth for YUV444 12BIT. It will be treated as YUV444_16BIT" )
|
|
258
|
+
elif bitdepth == 8:
|
|
259
|
+
strFormat = "YUV444"
|
|
260
|
+
elif str(chromaformat) == str("cudaVideoChromaFormat.420"):
|
|
261
|
+
if bitdepth == 8:
|
|
262
|
+
strFormat = "NV12"
|
|
263
|
+
elif bitdepth == 10:
|
|
264
|
+
strFormat = "YUV420_10BIT"
|
|
265
|
+
elif bitdepth == 16:
|
|
266
|
+
strFormat = "P016"
|
|
267
|
+
elif str(chromaformat) == str("cudaVideoChromaFormat.422"):
|
|
268
|
+
if bitdepth == 10:
|
|
269
|
+
strFormat = "YUV422_10BIT"
|
|
270
|
+
elif bitdepth == 16:
|
|
271
|
+
strFormat = "YUV422_16BIT"
|
|
272
|
+
elif bitdepth == 8:
|
|
273
|
+
strFormat = "YUV422"
|
|
274
|
+
|
|
275
|
+
#print (" strFormat : " + str(strFormat))
|
|
276
|
+
|
|
277
|
+
return strFormat
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def GetVideoCodec(demuxer):
|
|
281
|
+
codec=str(demuxer.GetNvCodecId())
|
|
282
|
+
#print (" codec : " + str(codec))
|
|
283
|
+
|
|
284
|
+
# Common prefix to remove
|
|
285
|
+
common_prefix = "cudaVideoCodec."
|
|
286
|
+
|
|
287
|
+
strCodec = codec.removeprefix(common_prefix)
|
|
288
|
+
|
|
289
|
+
#print (" codec : " + str(strCodec))
|
|
290
|
+
return str(strCodec)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def get_frame_data(frame, use_device_memory=False):
|
|
294
|
+
"""
|
|
295
|
+
Get raw frame data from a decoded frame.
|
|
296
|
+
|
|
297
|
+
Args:
|
|
298
|
+
frame: DecodedFrame object from PyNvVideoCodec
|
|
299
|
+
use_device_memory: Boolean indicating if frame data is in device memory
|
|
300
|
+
|
|
301
|
+
Returns:
|
|
302
|
+
Raw frame data (numpy array if device memory, bytearray if host memory)
|
|
303
|
+
"""
|
|
304
|
+
raw_frame = np.ndarray(shape=frame.framesize(), dtype=np.uint8)
|
|
305
|
+
luma_base_addr = frame.GetPtrToPlane(0)
|
|
306
|
+
|
|
307
|
+
if use_device_memory:
|
|
308
|
+
cuda.memcpy_dtoh(raw_frame, luma_base_addr)
|
|
309
|
+
return raw_frame
|
|
310
|
+
else:
|
|
311
|
+
return cast_address_to_1d_bytearray(base_address=luma_base_addr, size=frame.framesize())
|
|
312
|
+
|
|
313
|
+
def convert_frames_to_torch(decoded_frames: List, color_format: nvc.OutputColorType = nvc.OutputColorType.RGB) -> torch.Tensor:
|
|
314
|
+
"""
|
|
315
|
+
Convert batched frames from decoder to torch tensor.
|
|
316
|
+
|
|
317
|
+
Args:
|
|
318
|
+
decoded_frames: List of decoded frames from PyNvVideoCodec
|
|
319
|
+
color_format: OutputColorType enum (RGB or RGBP)
|
|
320
|
+
|
|
321
|
+
Returns:
|
|
322
|
+
torch.Tensor: Stacked tensor of shape (T, H, W, C) where T is number of frames
|
|
323
|
+
"""
|
|
324
|
+
if not decoded_frames:
|
|
325
|
+
raise ValueError("No frames provided for conversion")
|
|
326
|
+
|
|
327
|
+
try:
|
|
328
|
+
if color_format == nvc.OutputColorType.RGB:
|
|
329
|
+
# For RGB format, frames are already in HWC format
|
|
330
|
+
torch_frames = [torch.from_dlpack(frame) for frame in decoded_frames]
|
|
331
|
+
batched_tensor = torch.stack(torch_frames)
|
|
332
|
+
|
|
333
|
+
elif color_format == nvc.OutputColorType.RGBP:
|
|
334
|
+
# For RGBP format, frames are in planar format
|
|
335
|
+
torch_frames = []
|
|
336
|
+
for frame in decoded_frames:
|
|
337
|
+
# Convert frame to torch tensor
|
|
338
|
+
planar_tensor = torch.from_dlpack(frame)
|
|
339
|
+
|
|
340
|
+
# For RGBP, we get a tensor in shape (H*3, W)
|
|
341
|
+
if len(planar_tensor.shape) == 2:
|
|
342
|
+
height = planar_tensor.shape[0] // 3
|
|
343
|
+
width = planar_tensor.shape[1]
|
|
344
|
+
|
|
345
|
+
# Split into R,G,B planes
|
|
346
|
+
r_plane = planar_tensor[:height]
|
|
347
|
+
g_plane = planar_tensor[height:2*height]
|
|
348
|
+
b_plane = planar_tensor[2*height:3*height]
|
|
349
|
+
|
|
350
|
+
# Stack planes along new dimension to get (H,W,3)
|
|
351
|
+
frame_tensor = torch.stack([r_plane, g_plane, b_plane], dim=-1)
|
|
352
|
+
else:
|
|
353
|
+
frame_tensor = planar_tensor
|
|
354
|
+
|
|
355
|
+
torch_frames.append(frame_tensor)
|
|
356
|
+
|
|
357
|
+
batched_tensor = torch.stack(torch_frames)
|
|
358
|
+
else:
|
|
359
|
+
raise ValueError(f"Unsupported color format: {color_format}. Only RGB and RGBP formats are supported.")
|
|
360
|
+
|
|
361
|
+
return batched_tensor
|
|
362
|
+
|
|
363
|
+
except Exception as e:
|
|
364
|
+
print(f"Error converting frames to torch tensor: {e}")
|
|
365
|
+
raise
|
|
366
|
+
|
|
367
|
+
def frame_to_numpy(frame, color_format: nvc.OutputColorType, use_device_memory=False, width=None, height=None):
|
|
368
|
+
"""
|
|
369
|
+
Convert a decoded frame to an RGB numpy array suitable for display.
|
|
370
|
+
|
|
371
|
+
Args:
|
|
372
|
+
frame: DecodedFrame object from PyNvVideoCodec
|
|
373
|
+
color_format: nvc.OutputColorType enum (RGB or RGBP)
|
|
374
|
+
use_device_memory: Boolean indicating if frame data is in device memory
|
|
375
|
+
width: Optional frame width (if None, uses frame.width)
|
|
376
|
+
height: Optional frame height (if None, uses frame.height)
|
|
377
|
+
|
|
378
|
+
Returns:
|
|
379
|
+
numpy.ndarray: RGB frame data as a numpy array in HWC format, ready for display
|
|
380
|
+
"""
|
|
381
|
+
|
|
382
|
+
# Get frame data using the helper function
|
|
383
|
+
frame_data = get_frame_data(frame, use_device_memory)
|
|
384
|
+
|
|
385
|
+
# Convert to numpy array
|
|
386
|
+
frame_array = np.array(frame_data)
|
|
387
|
+
|
|
388
|
+
# Handle different color formats
|
|
389
|
+
if color_format == nvc.OutputColorType.RGB:
|
|
390
|
+
# For RGB format, we expect 3 channels in HWC format
|
|
391
|
+
return frame_array.reshape(height, width, 3)
|
|
392
|
+
elif color_format == nvc.OutputColorType.RGBP:
|
|
393
|
+
# For planar RGB format, each plane is height*width
|
|
394
|
+
plane_size = height * width
|
|
395
|
+
if len(frame_array) != 3 * plane_size:
|
|
396
|
+
raise ValueError(f"RGBP format expects {3 * plane_size} bytes but got {len(frame_array)}")
|
|
397
|
+
r_plane = frame_array[:plane_size].reshape(height, width)
|
|
398
|
+
g_plane = frame_array[plane_size:2*plane_size].reshape(height, width)
|
|
399
|
+
b_plane = frame_array[2*plane_size:].reshape(height, width)
|
|
400
|
+
# Stack the planes to create HWC format
|
|
401
|
+
return np.dstack((r_plane, g_plane, b_plane))
|
|
402
|
+
else:
|
|
403
|
+
raise ValueError(f"Unsupported color format: {color_format}. Only RGB and RGBP formats are supported.")
|
|
404
|
+
|
|
405
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
Utility modules for PyNvVideoCodec samples.
|
|
26
|
+
|
|
27
|
+
This package contains shared functionality used across multiple samples:
|
|
28
|
+
- Utils.py: Common video codec utilities
|
|
29
|
+
- decode_parser.py: Command line argument parsing for decoder samples
|
|
30
|
+
- decode_stats_writer.py: Decode statistics extraction and analysis
|
|
31
|
+
- sei_message_parser.py: SEI message extraction and parsing
|
|
32
|
+
- transcode_parser.py: Transcoder command line argument parsing
|
|
33
|
+
- encode_parser.py: Encoder command line argument parsing
|
|
34
|
+
- frame_utils.py: Helper module for frame and memory management in video encoding/decoding.
|
|
35
|
+
- encode_parallel_utils.py: Parallel utilities for encoding
|
|
36
|
+
"""
|