[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:
co-authored by
Claude
parent
f226af0e11
commit
ee406adf0c
@@ -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",
|
||||
[
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user