mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-07-11 17:07:14 +08:00
fix: trim transcode with missing leading PTS
Signed-off-by: bigcat88 <bigcat88@icloud.com>
This commit is contained in:
parent
1d595d4a70
commit
be27c9c3df
@ -626,7 +626,8 @@ class VideoFromFile(VideoInput):
|
|||||||
video_done = True
|
video_done = True
|
||||||
if last_video_pts is not None:
|
if last_video_pts is not None:
|
||||||
# the source continues past the window: hold the last kept frame to the window end
|
# the source continues past the window: hold the last kept frame to the window end
|
||||||
last_video_end = max(last_video_end, end_pts - video_pts_offset)
|
end_offset = video_pts_offset if video_pts_offset is not None else start_pts
|
||||||
|
last_video_end = max(last_video_end, end_pts - end_offset)
|
||||||
break
|
break
|
||||||
# the source's true display duration of this frame; average_rate is not a
|
# the source's true display duration of this frame; average_rate is not a
|
||||||
# frame duration (sparse/VFR sources), so it is only the fallback
|
# frame duration (sparse/VFR sources), so it is only the fallback
|
||||||
|
|||||||
@ -595,6 +595,61 @@ def test_save_to_transcode_irregular_vfr_keeps_span():
|
|||||||
assert trimmed["video_seconds"] == pytest.approx(10.0, abs=0.05)
|
assert trimmed["video_seconds"] == pytest.approx(10.0, abs=0.05)
|
||||||
|
|
||||||
|
|
||||||
|
def test_save_to_transcode_trim_survives_missing_leading_pts():
|
||||||
|
"""A trim should survive pts-less kept frames followed by a real-pts frame past the window."""
|
||||||
|
nulled_frames = 0
|
||||||
|
|
||||||
|
class _PacketProxy:
|
||||||
|
def __init__(self, packet):
|
||||||
|
self._packet = packet
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
return getattr(self._packet, name)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def stream(self):
|
||||||
|
return self._packet.stream
|
||||||
|
|
||||||
|
def decode(self):
|
||||||
|
nonlocal nulled_frames
|
||||||
|
frames = self._packet.decode()
|
||||||
|
for frame in frames:
|
||||||
|
if nulled_frames < 2:
|
||||||
|
frame.pts = None
|
||||||
|
nulled_frames += 1
|
||||||
|
return frames
|
||||||
|
|
||||||
|
class _ContainerProxy:
|
||||||
|
def __init__(self, real):
|
||||||
|
self._real = real
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
return getattr(self._real, name)
|
||||||
|
|
||||||
|
def demux(self, *streams):
|
||||||
|
for packet in self._real.demux(*streams):
|
||||||
|
yield _PacketProxy(packet)
|
||||||
|
|
||||||
|
file_path = create_transcode_source(frames=10, audio_streams=0)
|
||||||
|
try:
|
||||||
|
buffer = io.BytesIO()
|
||||||
|
with av.open(file_path) as container:
|
||||||
|
# 0.05 s window: both pts-less frames are kept (synthesized pts 0 and 512),
|
||||||
|
# and the first real-pts frame (1024 ticks) already lies past end_pts (768)
|
||||||
|
VideoFromFile(file_path, duration=0.05)._save_transcoded(
|
||||||
|
_ContainerProxy(container), buffer, VideoContainer.MP4, VideoCodec.H264, None, 8
|
||||||
|
)
|
||||||
|
assert nulled_frames == 2
|
||||||
|
buffer.seek(0)
|
||||||
|
with av.open(buffer) as container:
|
||||||
|
video_stream = container.streams.video[0]
|
||||||
|
frames = [f for p in container.demux(video_stream) for f in p.decode()]
|
||||||
|
assert len(frames) == 2
|
||||||
|
assert float(video_stream.duration * video_stream.time_base) == pytest.approx(2 / 30, abs=0.01)
|
||||||
|
finally:
|
||||||
|
os.unlink(file_path)
|
||||||
|
|
||||||
|
|
||||||
def test_save_to_transcode_bakes_rotation():
|
def test_save_to_transcode_bakes_rotation():
|
||||||
"""A 90-degree display-matrix rotation swaps the output dimensions (portrait video)"""
|
"""A 90-degree display-matrix rotation swaps the output dimensions (portrait video)"""
|
||||||
file_path = create_transcode_source(width=64, height=32, rotation=True)
|
file_path = create_transcode_source(width=64, height=32, rotation=True)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user