diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 258a57d30..0232959d7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -52,6 +52,7 @@ Fixes: - Filters added or linked after ``Graph.configure()`` are now configured on the next push or pull instead of segfaulting. - ``SubtitleCodecContext.decode(None)`` flushes the decoder instead of raising ``RuntimeError``, so delayed decoders such as EIA-608 closed captions return their final subtitle. - ``AudioFrame.planes`` no longer counts one plane too many for 8-channel planar audio (e.g. ``fltp`` with ``7.1``), which made ``planes``, ``to_ndarray()``, and ``from_ndarray()`` raise ``ValueError``, and no longer reads past the end of ``extended_data`` for more channels. By :gh-user:`ChandraChaan` in (:pr:`2502`). +- ``AudioFifo.write()`` now raises ``ValueError`` for a frame whose channel layout differs from the first frame's, instead of reading the wrong number of channels and scrambling or over-reading the samples. By :gh-user:`ChandraChaan` in (:pr:`2505`). v19.0.2 ------- diff --git a/av/audio/fifo.py b/av/audio/fifo.py index a000711ab..c7f4ebbd1 100644 --- a/av/audio/fifo.py +++ b/av/audio/fifo.py @@ -76,6 +76,10 @@ def write(self, frame: AudioFrame | None): elif ( frame.ptr.format != self.template.ptr.format or frame.ptr.sample_rate != self.template.ptr.sample_rate + or lib.av_channel_layout_compare( + cython.address(frame.ptr.ch_layout), + cython.address(self.template.ptr.ch_layout), + ) or ( frame._time_base.num and self.template._time_base.num diff --git a/tests/test_audiofifo.py b/tests/test_audiofifo.py index ce8be1273..25121e55c 100644 --- a/tests/test_audiofifo.py +++ b/tests/test_audiofifo.py @@ -1,5 +1,7 @@ from fractions import Fraction +import pytest + import av from .common import TestCase, fate_suite @@ -115,3 +117,14 @@ def test_missing_time_base(self) -> None: assert oframe is not None assert oframe.pts is None and not oframe.time_base assert oframe.sample_rate == iframe.sample_rate + + def test_layout_mismatch(self) -> None: + fifo = av.AudioFifo() + fifo.write(av.AudioFrame(format="s16", layout="mono", samples=1024)) + + # The FIFO was allocated for one channel, so a stereo frame would be + # read as mono and its samples scrambled. + with pytest.raises(ValueError): + fifo.write(av.AudioFrame(format="s16", layout="stereo", samples=1024)) + + assert fifo.samples == 1024