Skip to content

Commit d5121a1

Browse files
committed
Clean up hwaccel
1 parent 6fa996c commit d5121a1

7 files changed

Lines changed: 104 additions & 111 deletions

File tree

av/__main__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@ def main() -> None:
3333
print(f"{libname:<13} {version[0]:3d}.{version[1]:3d}.{version[2]:3d}")
3434

3535
if args.hwdevices:
36-
from av.codec.hwaccel import dump_hwdevices
36+
from av.codec.hwaccel import hwdevices_available
3737

38-
dump_hwdevices()
38+
print("Hardware device types:")
39+
for x in hwdevices_available():
40+
print(" ", x)
3941

4042
if args.hwconfigs:
4143
from av.codec.codec import dump_hwconfigs

av/codec/codec.pyx

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ cdef class Codec:
119119
raise RuntimeError("%s is both encoder and decoder.")
120120

121121
def __repr__(self):
122-
return f"<av.{self.__class__.__name__}({self.name!r}, {self.mode!r})>"
122+
mode = "w" if self.is_encoder else "r"
123+
return f"<av.{self.__class__.__name__} {self.name} {mode=}>"
123124

124125
def create(self, kind = None):
125126
"""Create a :class:`.CodecContext` for this codec.
@@ -315,16 +316,18 @@ codec_descriptor = wrap_avclass(lib.avcodec_get_class())
315316
def dump_codecs():
316317
"""Print information about available codecs."""
317318

318-
print('''Codecs:
319-
D.... = Decoding supported
320-
.E... = Encoding supported
321-
..V.. = Video codec
322-
..A.. = Audio codec
323-
..S.. = Subtitle codec
324-
...I. = Intra frame-only codec
325-
....L = Lossless compression
326-
.....H = Hardware decoding supported
327-
------''')
319+
print(
320+
"""Codecs:
321+
D..... = Decoding supported
322+
.E.... = Encoding supported
323+
..V... = Video codec
324+
..A... = Audio codec
325+
..S... = Subtitle codec
326+
...I.. = Intra frame-only codec
327+
....L. = Lossy compression
328+
.....S = Lossless compression
329+
------"""
330+
)
328331

329332
for name in sorted(codecs_available):
330333
try:
@@ -342,14 +345,14 @@ def dump_codecs():
342345

343346
try:
344347
print(
345-
" %s%s%s%s%s%s %-18s %s"
348+
" %s%s%s%s%s%s %-18s %s"
346349
% (
347350
".D"[bool(d_codec)],
348351
".E"[bool(e_codec)],
349352
codec.type[0].upper(),
350353
".I"[codec.intra_only],
351-
".L"[codec.lossless],
352-
".H"[bool((d_codec or codec).hardware_configs)],
354+
".L"[codec.lossy],
355+
".S"[codec.lossless],
353356
codec.name,
354357
codec.long_name,
355358
)
@@ -358,15 +361,17 @@ def dump_codecs():
358361
print(f"...... {codec.name:<18} ERROR: {e}")
359362

360363
def dump_hwconfigs():
361-
print('Hardware configs:')
364+
print("Hardware configs:")
362365
for name in sorted(codecs_available):
363366
try:
364-
codec = Codec(name, 'r')
367+
codec = Codec(name, "r")
365368
except ValueError:
366369
continue
370+
367371
configs = codec.hardware_configs
368372
if not configs:
369373
continue
370-
print(' ', codec.name)
374+
375+
print(" ", codec.name)
371376
for config in configs:
372-
print(' ', config)
377+
print(" ", config)

av/codec/context.pyi

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@ class CodecContext:
8888
def open(self, strict: bool = True) -> None: ...
8989
@staticmethod
9090
def create(
91-
codec: str | Codec, mode: Literal["r", "w"] | None = None
91+
codec: str | Codec,
92+
mode: Literal["r", "w"] | None = None,
93+
hwaccel: HWAccel | None = None,
9294
) -> CodecContext: ...
9395
def parse(
9496
self, raw_input: bytes | bytearray | memoryview | None = None

av/codec/hwaccel.pyi

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,48 @@
11
from enum import IntEnum
2-
from typing import Sequence
32

43
from av.codec.codec import Codec
4+
from av.video.format import VideoFormat
55

66
class HWDeviceType(IntEnum):
7-
NONE = int
8-
VDPAU = int
9-
CUDA = int
10-
VAAPI = int
11-
DXVA2 = int
12-
QSV = int
13-
VIDEOTOOLBOX = int
14-
D3D11VA = int
15-
DRM = int
16-
OPENCL = int
17-
MEDIACODEC = int
18-
VULKAN = int
19-
D3D12VA = int
7+
none: int
8+
vdpau: int
9+
cuda: int
10+
vaapi: int
11+
dxva2: int
12+
qsv: int
13+
videotoolbox: int
14+
d3d11va: int
15+
drm: int
16+
opencl: int
17+
mediacodec: int
18+
vulkan: int
19+
d3d12va: int
2020

21-
class HWConfig(object):
22-
def __init__(self, sentinel): ...
23-
def __repr__(self): ...
21+
class HWConfigMethod(IntEnum):
22+
none: int
23+
hw_device_ctx: int
24+
hw_frame_ctx: int
25+
internal: int
26+
ad_hoc: int
27+
28+
class HWConfig:
2429
@property
25-
def device_type(self): ...
30+
def device_type(self) -> HWDeviceType: ...
2631
@property
27-
def format(self): ...
32+
def format(self) -> VideoFormat: ...
2833
@property
29-
def methods(self): ...
34+
def methods(self) -> HWConfigMethod: ...
3035
@property
31-
def is_supported(self): ...
36+
def is_supported(self) -> bool: ...
3237

3338
class HWAccel:
3439
def __init__(
3540
self,
3641
device_type: str | HWDeviceType,
3742
device: str | None = None,
38-
allow_software_fallback: bool = True,
39-
options=None,
40-
**kwargs
41-
): ...
43+
allow_software_fallback: bool = False,
44+
options: dict[str, object] | None = None,
45+
) -> None: ...
4246
def create(self, codec: Codec): ...
4347

44-
hwdevices_available: Sequence[str]
45-
46-
def dump_hwdevices() -> None: ...
48+
def hwdevices_available() -> list[str]: ...

av/codec/hwaccel.pyx

Lines changed: 40 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,26 @@ from av.dictionary import Dictionary
1414

1515

1616
class HWDeviceType(IntEnum):
17-
NONE = lib.AV_HWDEVICE_TYPE_NONE
18-
VDPAU = lib.AV_HWDEVICE_TYPE_VDPAU
19-
CUDA = lib.AV_HWDEVICE_TYPE_CUDA
20-
VAAPI = lib.AV_HWDEVICE_TYPE_VAAPI
21-
DXVA2 = lib.AV_HWDEVICE_TYPE_DXVA2
22-
QSV = lib.AV_HWDEVICE_TYPE_QSV
23-
VIDEOTOOLBOX = lib.AV_HWDEVICE_TYPE_VIDEOTOOLBOX
24-
D3D11VA = lib.AV_HWDEVICE_TYPE_D3D11VA
25-
DRM = lib.AV_HWDEVICE_TYPE_DRM
26-
OPENCL = lib.AV_HWDEVICE_TYPE_OPENCL
27-
MEDIACODEC = lib.AV_HWDEVICE_TYPE_MEDIACODEC
28-
VULKAN = lib.AV_HWDEVICE_TYPE_VULKAN
29-
D3D12VA = lib.AV_HWDEVICE_TYPE_D3D12VA
17+
none = lib.AV_HWDEVICE_TYPE_NONE
18+
vdpau = lib.AV_HWDEVICE_TYPE_VDPAU
19+
cuda = lib.AV_HWDEVICE_TYPE_CUDA
20+
vaapi = lib.AV_HWDEVICE_TYPE_VAAPI
21+
dxva2 = lib.AV_HWDEVICE_TYPE_DXVA2
22+
qsv = lib.AV_HWDEVICE_TYPE_QSV
23+
videotoolbox = lib.AV_HWDEVICE_TYPE_VIDEOTOOLBOX
24+
d3d11va = lib.AV_HWDEVICE_TYPE_D3D11VA
25+
drm = lib.AV_HWDEVICE_TYPE_DRM
26+
opencl = lib.AV_HWDEVICE_TYPE_OPENCL
27+
mediacodec = lib.AV_HWDEVICE_TYPE_MEDIACODEC
28+
vulkan = lib.AV_HWDEVICE_TYPE_VULKAN
29+
d3d12va = lib.AV_HWDEVICE_TYPE_D3D12VA
3030

3131
class HWConfigMethod(IntEnum):
32-
NONE = 0
33-
HW_DEVICE_CTX = lib.AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX # This is the only one we support.
34-
HW_FRAME_CTX = lib.AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX
35-
INTERNAL = lib.AV_CODEC_HW_CONFIG_METHOD_INTERNAL
36-
AD_HOC = lib.AV_CODEC_HW_CONFIG_METHOD_AD_HOC
32+
none = 0
33+
hw_device_ctx = lib.AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX # This is the only one we support.
34+
hw_frame_ctx = lib.AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX
35+
internal = lib.AV_CODEC_HW_CONFIG_METHOD_INTERNAL
36+
ad_hoc = lib.AV_CODEC_HW_CONFIG_METHOD_AD_HOC
3737

3838

3939
cdef object _cinit_sentinel = object()
@@ -82,30 +82,22 @@ cdef class HWConfig:
8282
def is_supported(self):
8383
return bool(self.ptr.methods & lib.AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)
8484

85-
hwdevices_available = []
8685

87-
cdef lib.AVHWDeviceType x = lib.AV_HWDEVICE_TYPE_NONE
88-
while True:
89-
x = lib.av_hwdevice_iterate_types(x)
90-
if x == lib.AV_HWDEVICE_TYPE_NONE:
91-
break
92-
hwdevices_available.append(lib.av_hwdevice_get_type_name(HWDeviceType(x)))
86+
cpdef hwdevices_available():
87+
result = []
9388

94-
def dump_hwdevices():
95-
print("Hardware device types:")
96-
for x in hwdevices_available:
97-
print(" ", x)
89+
cdef lib.AVHWDeviceType x = lib.AV_HWDEVICE_TYPE_NONE
90+
while True:
91+
x = lib.av_hwdevice_iterate_types(x)
92+
if x == lib.AV_HWDEVICE_TYPE_NONE:
93+
break
94+
result.append(lib.av_hwdevice_get_type_name(HWDeviceType(x)))
95+
96+
return result
9897

9998

10099
cdef class HWAccel:
101-
def __init__(
102-
self,
103-
device_type: str | HWDeviceType,
104-
device: str | None = None,
105-
allow_software_fallback: bool = True,
106-
options=None,
107-
**kwargs,
108-
):
100+
def __init__(self, device_type, device=None, allow_software_fallback=True, options=None):
109101
if isinstance(device_type, HWDeviceType):
110102
self._device_type = device_type
111103
elif isinstance(device_type, str):
@@ -115,25 +107,22 @@ cdef class HWAccel:
115107

116108
self._device = device
117109
self.allow_software_fallback = allow_software_fallback
110+
self.options = {} if not options else dict(options)
118111

119-
if options and kwargs:
120-
raise ValueError("accepts only one of options arg or kwargs")
121-
self.options = dict(options or kwargs)
122-
123-
def create(self, Codec codec):
112+
def create(self, Codec codec not None):
124113
return HWAccelContext(
125-
device_type=HWDeviceType(self._device_type),
126-
device=self._device,
127-
options=self.options,
128-
codec=codec,
129-
allow_software_fallback=self.allow_software_fallback,
114+
HWDeviceType(self._device_type),
115+
self._device,
116+
self.options,
117+
self.allow_software_fallback,
118+
codec,
130119
)
131120

132121
cdef class HWAccelContext(HWAccel):
133-
def __init__(self, device_type, device, options, codec, allow_software_fallback, **kwargs):
134-
super().__init__(device_type, device, options, **kwargs)
122+
def __init__(self, device_type, device, allow_software_fallback, options, codec):
123+
super().__init__(device_type, device, options)
135124
if not codec:
136-
raise ValueError("codec is required")
125+
raise ValueError("`codec` is required")
137126
self.codec = codec
138127
cdef HWConfig config
139128

@@ -144,7 +133,7 @@ cdef class HWAccelContext(HWAccel):
144133
continue
145134
break
146135
else:
147-
raise NotImplementedError(f"no supported hardware config for {codec}")
136+
raise NotImplementedError(f"No supported hardware config for {codec}")
148137

149138
self.config = config
150139
cdef char *c_device = NULL
@@ -162,6 +151,3 @@ cdef class HWAccelContext(HWAccel):
162151
def __dealloc__(self):
163152
if self.ptr:
164153
lib.av_buffer_unref(&self.ptr)
165-
166-
def create(self, *args, **kwargs):
167-
raise ValueError("cannot call HWAccelContext.create")

av/container/core.pyi

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ class Container:
4444
options: dict[str, str]
4545
container_options: dict[str, str]
4646
stream_options: list[dict[str, str]]
47-
hwaccel: HWAccel
4847
streams: StreamContainer
4948
metadata: dict[str, str]
5049
open_timeout: Real | None

tests/test_decode.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -204,30 +204,27 @@ def test_side_data(self) -> None:
204204
assert frame.rotation == -90
205205

206206
def test_hardware_decode(self) -> None:
207+
hwdevices_available = av.codec.hwaccel.hwdevices_available()
207208
if "HWACCEL_DEVICE_TYPE" not in os.environ:
208209
pytest.skip(
209210
"Set the HWACCEL_DEVICE_TYPE to run this test. "
210-
f"Options are {' '.join(av.codec.hwaccel.hwdevices_available)}"
211+
f"Options are {' '.join(hwdevices_available)}"
211212
)
212213

213214
HWACCEL_DEVICE_TYPE = os.environ["HWACCEL_DEVICE_TYPE"]
214-
215215
assert (
216-
HWACCEL_DEVICE_TYPE in av.codec.hwaccel.hwdevices_available
216+
HWACCEL_DEVICE_TYPE in hwdevices_available
217217
), f"{HWACCEL_DEVICE_TYPE} not available"
218218

219219
test_video_path = "tests/assets/black.mp4"
220220
make_h264_test_video(test_video_path)
221221

222-
# Test decode.
223222
hwaccel = av.codec.hwaccel.HWAccel(
224223
device_type=HWACCEL_DEVICE_TYPE, allow_software_fallback=False
225224
)
226225

227226
container = av.open(test_video_path, hwaccel=hwaccel)
228-
video_stream = next(s for s in container.streams if s.type == "video")
229-
230-
assert video_stream is container.streams.video[0]
227+
video_stream = container.streams.video[0]
231228
assert video_stream.codec_context.is_hwaccel
232229

233230
frame_count = 0

0 commit comments

Comments
 (0)