Skip to content

Commit 2bd7933

Browse files
committed
Allow setting video rate after adding stream
Synchronize the stream average frame rate from the codec context before writing the output header. Closes #2301.
1 parent 46a67aa commit 2bd7933

2 files changed

Lines changed: 22 additions & 0 deletions

File tree

av/video/stream.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ def decode(self, packet: Packet | None = None):
6363
@cython.cfunc
6464
def _finalize_for_output(self):
6565
Stream._finalize_for_output(self)
66+
if self.codec_context is not None:
67+
self.ptr.avg_frame_rate = self.codec_context.ptr.framerate
6668
# avcodec_parameters_from_context() overwrites codecpar.coded_side_data,
6769
# so inject the display matrix after it, before avformat_write_header().
6870
if self.codec_context is not None and self._has_display_matrix:

tests/test_encode.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,26 @@ def test_encoding_with_pts(self) -> None:
162162
assert packet.time_base == Fraction(1, 24)
163163
output.mux(packet)
164164

165+
def test_set_rate_after_add_stream(self) -> None:
166+
path = self.sandboxed("deferred_rate.mp4")
167+
168+
with av.open(path, "w") as output:
169+
stream = output.add_stream("mpeg4")
170+
stream.codec_context.framerate = Fraction(30, 1)
171+
stream.width = 16
172+
stream.height = 16
173+
174+
for i in range(30):
175+
frame = VideoFrame(16, 16, "yuv420p")
176+
frame.pts = i
177+
frame.time_base = Fraction(1, 30)
178+
output.mux(stream.encode(frame))
179+
180+
output.mux(stream.encode(None))
181+
182+
with av.open(path) as input_:
183+
assert input_.streams.video[0].average_rate == 30
184+
165185
def test_encoding_with_unicode_filename(self) -> None:
166186
path = self.sandboxed("¢∞§¶•ªº.mov")
167187

0 commit comments

Comments
 (0)