Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,18 @@ We are operating with `semantic versioning <https://semver.org>`_.
- Bug fixes (PATCH) go here.
- $CHANGE by :gh-user:`mikeboers` in (:pr:`1`).

v18.0.0 (next)
--------------
v18.0.0
-------

Breaking:

- Remove Python 3.10
- Support HW encoding via a ``hwaccel`` parameter on ``OutputContainer.add_stream`` (e.g. ``h264_vaapi``, ``h264_nvenc``, ``h264_videotoolbox``); software frames passed to ``encode`` are uploaded to the device automatically by :gh-user:`WyattBlue` (:issue:`2156`).

Features:

- Support HW encoding via a ``hwaccel`` parameter on ``OutputContainer.add_stream`` (e.g. ``h264_vaapi``, ``h264_nvenc``, ``h264_videotoolbox``); software frames passed to ``encode`` are uploaded to the device automatically by :gh-user:`WyattBlue` (:issue:`2156`).
- Use FFmpeg 8.1.2 in the binary wheels by :gh-user:`WyattBlue`.
- Expose ``sw_format`` on ``VideoCodecContext``, and allow configuring the software format of hardware encoders by :gh-user:`WyattBlue`.
- Add ``options`` parameter to ``AudioResampler`` for passing ``libswresample`` options (e.g. ``resampler``, ``filter_size``, ``cutoff``) by :gh-user:`WyattBlue` (:issue:`2262`).
- Support ``yuv420p10le`` in ``VideoFrame.to_ndarray`` and ``VideoFrame.from_ndarray`` by :gh-user:`WyattBlue` (:issue:`1981`).
- Add ``at`` parameter to ``Graph.push`` and ``Graph.vpush`` to push a frame to a single buffer source by index, for multi-input filters like ``overlay`` by :gh-user:`WyattBlue`.
Expand All @@ -50,6 +52,8 @@ Fixes:
- Fix ``VideoFrame.reformat`` (and ``to_ndarray``/``to_rgb``/``to_image``) raising ``OSError`` ``Operation not supported`` on frames tagged with reserved or otherwise unsupported ``color_primaries``/``color_trc`` values (e.g. VP9 and NVDEC output); a transfer/primaries conversion is now only performed when explicitly requested by :gh-user:`WyattBlue` (:issue:`2208`).
- Fix ``add_mux_stream`` producing unwritable Matroska files by extracting codec extradata from the bitstream before the header is written by :gh-user:`WyattBlue` (:issue:`2198`).
- Encode GPU frames (e.g. CUDA frames from DLPack) directly with ``pix_fmt="cuda"`` by adopting the frame's ``hw_frames_ctx`` before opening the encoder by :gh-user:`WyattBlue` (:issue:`2199`).
- Fix a crash when reading ``VideoCodecContext.pix_fmt`` before it is set; it now returns ``None`` by :gh-user:`CarlosRDomin`.
- Preserve frame attributes (``pts``, ``time_base``, colorspace, etc.) when downloading hardware frames to system memory by :gh-user:`CarlosRDomin`.

v17.1.0
-------
Expand Down
2 changes: 1 addition & 1 deletion av/about.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "18.0.0pre"
__version__ = "18.0.0"
25 changes: 25 additions & 0 deletions av/codec/hwaccel.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ def is_supported(self):

@cython.ccall
def hwdevices_available():
"""Return the names of the hardware device types FFmpeg was built with,
e.g. ``["cuda", "videotoolbox"]``."""
result: list = []
x: lib.AVHWDeviceType = lib.AV_HWDEVICE_TYPE_NONE
while True:
Expand All @@ -107,6 +109,29 @@ def hwdevices_available():
@cython.final
@cython.cclass
class HWAccel:
"""HWAccel(device_type, device=None, allow_software_fallback=True, options=None, flags=None, is_hw_owned=False)

Settings for hardware-accelerated decoding and encoding. Pass an instance to
:func:`av.open` to decode on the device, or to
:meth:`OutputContainer.add_stream <av.container.OutputContainer.add_stream>`
to encode on it.

:param device_type: The kind of device, e.g. ``"cuda"``, ``"vaapi"``,
``"videotoolbox"``. See :func:`hwdevices_available` for the types
supported by the loaded FFmpeg.
:type device_type: str or HWDeviceType
:param str device: An optional device identifier, e.g. a DRI render node path
(``"/dev/dri/renderD128"``) for VAAPI or a device index (``"1"``) for CUDA.
Uses the default device if ``None``.
:param bool allow_software_fallback: Whether decoding falls back to a software
decoder when the hardware decoder cannot handle the stream.
:param dict options: Options passed to ``av_hwdevice_ctx_create``.
:param int flags: Flags passed to ``av_hwdevice_ctx_create``.
:param bool is_hw_owned: If True, decoded frames stay on the device (for
consumption via DLPack, for example) instead of being downloaded to
system memory.
"""

def __init__(
self,
device_type,
Expand Down
11 changes: 10 additions & 1 deletion av/filter/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,15 @@ def set_audio_frame_size(self, frame_size):
)

def push(self, frame, at: cython.int = -1):
"""Push a frame into the graph's buffer source(s).

:param frame: An :class:`.AudioFrame` or :class:`.VideoFrame` to push into
the matching buffer sources, or ``None`` to signal end of stream to
every buffer source.
:param int at: Index of a single buffer source to push to, for graphs with
multiple inputs (e.g. ``overlay``). The default of ``-1`` pushes to
every buffer source matching the frame's type.
"""
if frame is None:
contexts = self._video_sources + self._audio_sources
elif isinstance(frame, VideoFrame):
Expand All @@ -263,7 +272,7 @@ def push(self, frame, at: cython.int = -1):
ctx.push(frame)

def vpush(self, frame: VideoFrame | None, at: cython.int = -1):
"""Like `push`, but only for VideoFrames."""
"""Like :meth:`push`, but only for :class:`.VideoFrame`."""
contexts = self._video_sources
if at >= 0:
if at >= len(contexts):
Expand Down
34 changes: 34 additions & 0 deletions docs/api/codec.rst
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,37 @@ Enums and Flags
.. enumtable:: av.codec.context.ThreadType


Hardware Acceleration
---------------------

.. currentmodule:: av.codec.hwaccel
.. automodule:: av.codec.hwaccel

.. autoclass:: HWAccel

.. autofunction:: hwdevices_available

To decode on a hardware device, pass an :class:`HWAccel` to :func:`av.open`::

import av
from av.codec.hwaccel import HWAccel

hwaccel = HWAccel(device_type="videotoolbox")
with av.open("input.mp4", hwaccel=hwaccel) as container:
for frame in container.decode(video=0):
... # Frames are downloaded to system memory by default.

To encode on a hardware device, pass one to :meth:`OutputContainer.add_stream
<av.container.OutputContainer.add_stream>` with a hardware encoder. Software
frames passed to ``encode`` are uploaded to the device automatically::

with av.open("output.mp4", "w") as container:
stream = container.add_stream(
"h264_videotoolbox", rate=30, hwaccel=HWAccel(device_type="videotoolbox")
)
...

See ``examples/basics/hw_decode.py`` for a complete example, including
recommended device types per platform.


Loading