`encode_video` truncates a fractional `fps`, so the video runs longer than its audio
Maintainers usually reply within 1 day
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 83/100
Research direction
Start with src/diffusers/utils/export_utils.py at the encode_video stream setup; the issue identifies rate=int(fps) as the cause and points to the LTX-2 HDR exporter for a fractional-rate example. Add the proposed regression test in tests/others/test_utils.py, encoding 30 frames at 29.97 fps. Done when the encoded stream reports average_rate == Fraction(2997, 100).
Written by the indexing model from the issue text.
Description
Describe the bug
diffusers.utils.export_utils.encode_video opens the video stream with rate=int(fps)
(export_utils.py#L364),
so 29.97 is written as 29 fps and 23.976 as 23. The audio stream keeps its real sample rate, so the video ends up
longer than the audio and drifts further out of sync the longer the clip is: about 0.35 s over 10 s at 29.97.
The LTX-2 pipelines take frame_rate as a float and the docs pass it straight through as encode_video(..., fps=frame_rate).
The LTX-2 HDR exporter already keeps the fraction with Fraction(frame_rate).limit_denominator(1000)
(ltx2/export_utils.py#L74).
Reproduction
I can't run the LTX-2 checkpoint on my machine, so this calls encode_video the way the LTX-2 docs do, with inputs
shaped like the pipeline's output_type="np" video and stereo audio:
import av
import numpy as np
import torch
from diffusers.utils.export_utils import encode_video
for fps in (24.0, 29.97, 23.976):
num_frames = round(fps * 10) # 10 seconds
video = np.random.rand(num_frames, 64, 64, 3).astype(np.float32)
audio = torch.zeros(2, 48000 * 10)
encode_video(video, fps=fps, output_path="out.mp4", audio=audio, audio_sample_rate=48000)
with av.open("out.mp4") as container:
v, a = container.streams.video[0], container.streams.audio[0]
print(fps, v.average_rate, f"video {float(v.duration * v.time_base):.3f}s", f"audio {float(a.duration * a.time_base):.3f}s")
Logs
24.0 24/1 video 10.000s audio 10.000s
29.97 29/1 video 10.345s audio 10.000s
23.976 23/1 video 10.435s audio 10.000s
System Info
- diffusers main (29d199aba)
- torch 2.14.1+cpu, PyAV 19.0.2, Python 3.12.13, Windows 11
Proposed fix
Use the same expression as the LTX-2 HDR exporter, rate=Fraction(fps).limit_denominator(1000) (Fraction is already imported in that file), plus a test in tests/others/test_utils.py that encodes 30 frames at 29.97 and checks average_rate == Fraction(2997, 100). The test fails on main with AVRational(29, 1) and passes with the change. With the change the same script prints (300 frames at 29.97 fps really are 10.010 s):
24.0 24/1 video 10.000s audio 10.000s
29.97 2997/100 video 10.010s audio 10.000s
23.976 2997/125 video 10.010s audio 10.000s
Happy to open a PR if that works for you.
Who can help?
@DN6
- Dominant language
- Python
- Stars
- 34.8k
- Forks
- 7.4k
- Avg merge
- 2d 13h
- Merged PRs (30d)
- 58
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from huggingface/diffusers
-
Difficulty 1/5 Under an hour Newbie friendliness 78/100
huggingface/diffusers#15170 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
huggingface/diffusers#15163 · 3 comments ·
Maintainers usually reply within 1 day
-
Clarify set_adapters() adapter_weights documentation and type hintsPossibly taken @gorkadabo1 claimed this 4 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
huggingface/diffusers#15146 · 1 comment · 1 assignee ·
Maintainers usually reply within 1 day
-
VaeImageProcessor.denormalize() raises AttributeError for NumPy inputsPossibly taken @tonycoder-hub claimed this 22 days ago. Openbug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
huggingface/diffusers#15011 · 1 comment ·
Maintainers usually reply within 1 day
-
`ModelMixin.from_pretrained` on a sharded checkpoint fails under `HF_HUB_OFFLINE=1` even when fully cached (`_get_checkpoint_shard_files` still calls `model_info`)Possibly taken @Subodh-17 claimed this 28 days ago. Openbug models
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
huggingface/diffusers#14952 · 1 comment ·
Maintainers usually reply within 1 day
All issues in huggingface/diffusers
Similar issues
-
Difficulty 1/5 1-3 hours Newbie friendliness 78/100
QuantConnect/Documentation#2838 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
awslabs/route53-dynamic-dns-with-lambda#67 · 1 comment ·
-
`SubAgents` returns a child run's `DeferredToolRequests` to the parent as a successful tool resultOpenbug pkg:harness
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
pydantic/pydantic-ai#12405 ·
Maintainers usually reply within 1 day
-
good first issue help wanted
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
good first issue help wanted
Difficulty 1/5 Under an hour Newbie friendliness 82/100