[Bugfix] Fix ZeroDivisionError in Qwen3-VL video sampling when the source fps is unknown (#60501)

Signed-off-by: Vadim Gimpelson <vadim.gimpelson@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Vadim Gimpelson
2026-10-08 06:28:44 +00:00
committed by GitHub
co-authored by Claude
parent f226af0e11
commit ee406adf0c
2 changed files with 42 additions and 1 deletions
+32 -1
View File
@@ -13,7 +13,7 @@ import numpy as np
import numpy.typing as npt
import pytest
import torch
from transformers import AutoVideoProcessor
from transformers import AutoVideoProcessor, Qwen3VLVideoProcessor
from transformers.video_utils import VideoMetadata
from vllm.assets.base import get_vllm_public_assets
@@ -35,6 +35,7 @@ from vllm.multimodal.video import (
get_video_loader_backend_for_processor,
)
from vllm.multimodal.video_decoders import decode_video, resolve_video_backend_kwargs
from vllm.multimodal.video_decoders.opencv import OpenCVVideoBackendMixin
from vllm.multimodal.video_decoders.pynvvideocodec import (
PYNVVIDEOCODEC_DECODER_CACHE_SIZE,
PyNvVideoCodecDecoderSlot,
@@ -730,6 +731,36 @@ def test_cosmos3_edge_uses_qwen3_vl_video_backend():
assert isinstance(VIDEO_LOADER_REGISTRY.load(backend), Qwen3VLVideoBackend)
def test_qwen3_vl_unknown_source_fps_matches_hf(
dummy_video_path, monkeypatch: pytest.MonkeyPatch
):
"""An unknown source fps (reported as 0) samples like HF's fps=None, and
the metadata carries the fps HF assumes, which the frame timestamps use."""
get_video_metadata = OpenCVVideoBackendMixin.get_video_metadata
def unknown_fps(cap) -> VideoSourceMetadata:
return get_video_metadata(cap)._replace(original_fps=0.0, duration=0.0)
monkeypatch.setattr(
OpenCVVideoBackendMixin, "get_video_metadata", staticmethod(unknown_fps)
)
_, metadata = Qwen3VLVideoBackend.load_bytes(
dummy_video_path.read_bytes(), fps=2, backend="opencv"
)
total_frames = metadata["total_num_frames"]
hf_metadata = VideoMetadata(total_num_frames=total_frames, fps=None)
hf_indices = Qwen3VLVideoProcessor().sample_frames(hf_metadata, fps=2).tolist()
assert metadata["frames_indices"] == hf_indices
assert metadata["fps"] == hf_metadata.fps
source = VideoSourceMetadata(total_frames, original_fps=0.0, duration=0.0)
target = VideoTargetMetadata(num_frames=-1, fps=2, max_duration=300)
assert (
Qwen3VLVideoBackend.compute_frames_index_to_sample(source, target) == hf_indices
)
@pytest.mark.parametrize(
"model_repo, expected_loader_cls, hf_sample_kwargs",
[
+10
View File
@@ -361,6 +361,15 @@ class Qwen3VLVideoBackend(VideoBackend):
_MAX_FRAMES: ClassVar[int] = 768
_MAX_FPS: ClassVar[int] = 30
@classmethod
def _prepare_source(cls, source: VideoSourceMetadata) -> VideoSourceMetadata:
# vLLM reports an unknown source fps as 0. HF's Qwen3VLVideoProcessor
# assumes a 24 fps source then, and keeps it in the metadata for the
# frame timestamps.
if source.original_fps > 0:
return source
return VideoSourceMetadata(source.total_frames_num, 24.0, source.duration)
@classmethod
def compute_frames_index_to_sample(
cls,
@@ -368,6 +377,7 @@ class Qwen3VLVideoBackend(VideoBackend):
target: VideoTargetMetadata,
**kwargs,
) -> list[int]:
source = cls._prepare_source(source)
total_frames_num = source.total_frames_num
original_fps = source.original_fps
fps = min(target.fps, cls._MAX_FPS)