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
14 changes: 12 additions & 2 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ We are operating with `semantic versioning <https://semver.org>`_.
- Bug fixes (PATCH) go here.
- $CHANGE by :gh-user:`mikeboers` in (:pr:`1`).

v18.1.0 (Unreleased)
--------------------
v18.1.0
-------

Features:

Expand All @@ -39,11 +39,21 @@ Features:
- Support reusing the thread's current CUDA context via a ``current_ctx`` flag on ``CudaContext`` and ``VideoFrame.from_dlpack``, for interop with libraries like PyTorch that initialize CUDA first by :gh-user:`Yozer` (:pr:`2339`).
- ``VideoFrame.from_dlpack`` no longer requires restating ``primary_ctx``/``current_ctx`` when passing an explicit ``cuda_context``; the flags are only validated when explicitly given by :gh-user:`WyattBlue`.
- Support passing an explicit CUDA stream to FFmpeg CUDA operations, including NVENC input and output, via a ``cuda_stream`` parameter on ``CudaContext``; currently limited to logical CUDA device 0 by :gh-user:`Yozer` (:pr:`2360`).
- Add ``av.AVRational``, an exact rational number stored as two int32s that mirrors FFmpeg's ``AVRational``. ``Codec.frame_rates`` now holds these rather than ``fractions.Fraction``, and every setter that accepts a ``Fraction`` also accepts an ``AVRational``. Unset rational attributes are falsy, so test them with ``if not stream.time_base:`` rather than ``is None`` by :gh-user:`WyattBlue`.
- Add ``Frame.metadata``, the metadata FFmpeg attaches to a frame, by :gh-user:`WyattBlue`.
- Add ``CodecContext.level`` by :gh-user:`WyattBlue`.
- Add ``VideoCodecContext.field_order`` by :gh-user:`WyattBlue`.
- ``VideoFrame.save`` now forwards keyword arguments to the encoder, letting callers trade file size for speed (e.g. ``pred="none"`` or ``compression_level=1`` for PNG, ``qscale=2`` for JPG) by :gh-user:`WyattBlue`.
- Add ``InputContainer.start_time_realtime``, the stream's start time in microseconds since the Unix epoch, which RTSP derives from RTCP sender reports, by :gh-user:`WyattBlue` (:issue:`2365`).

Fixes:

- Fix ``VideoFrame.save`` raising ``AttributeError`` when given a ``Path`` rather than a ``str`` by :gh-user:`WyattBlue`.
- Fix a frame rate assigned to a ``VideoStream`` after ``add_stream`` being dropped from the output; the codec context's frame rate is now copied to the stream before the header is written by :gh-user:`WyattBlue` (:issue:`2301`).

Misc.:

- Support building from source against FFmpeg 9.0 by :gh-user:`WyattBlue`. The binary wheels still ship FFmpeg 8.1.2.

- Prevent crashes and corrupted output when structural codec properties are changed after an output stream has been opened by :gh-user:`WyattBlue`, reported by :gh-user:`oakaigh` (:issue:`2232`).
- Fix a crash when using a stream that has no ``CodecContext`` (a demuxed stream with no available decoder, such as one from a truncated file, or a stream created by ``add_mux_stream``); decoding now raises ``DecoderNotFoundError``, encoding now raises ``EncoderNotFoundError``, and ``BitStreamFilterContext`` accepts such a stream as ``out_stream`` by :gh-user:`WyattBlue`, reported by :gh-user:`justinrmiller` (:issue:`2344`).
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.0"
__version__ = "18.1.0"
14 changes: 14 additions & 0 deletions av/container/input.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,20 @@ def start_time(self):
if self.ptr.start_time != lib.AV_NOPTS_VALUE:
return self.ptr.start_time

@property
def start_time_realtime(self):
"""Start time of the stream in real world time, in microseconds since the
Unix epoch, or ``None`` if unknown.

Only a few demuxers know this; RTSP computes it from RTCP sender reports,
which is what makes it useful for aligning analytics with a camera's clock.

Wraps :ffmpeg:`AVFormatContext.start_time_realtime`.
"""
self._assert_open()
if self.ptr.start_time_realtime != lib.AV_NOPTS_VALUE:
return self.ptr.start_time_realtime

@property
def duration(self):
self._assert_open()
Expand Down
1 change: 1 addition & 0 deletions av/container/input.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ from .core import Container

class InputContainer(Container):
start_time: int
start_time_realtime: int | None
duration: int | None
bit_rate: int
size: int
Expand Down
1 change: 1 addition & 0 deletions include/avformat.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ cdef extern from "libavformat/avformat.h" nogil:
AVIOInterruptCB interrupt_callback
AVDictionary *metadata
int64_t start_time
int64_t start_time_realtime
int64_t duration
int64_t bit_rate
int flags
Expand Down
2 changes: 2 additions & 0 deletions tests/test_file_probing.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ def test_container_probing(self) -> None:
assert self.file.metadata == {}
assert self.file.size == 207740
assert self.file.start_time == 1400000
# Only RTSP-like inputs carry a wall clock; a plain file has none.
assert self.file.start_time_realtime is None
assert len(self.file.streams) == 1

def test_stream_probing(self) -> None:
Expand Down
Loading