Signed-off-by: david6666666 <530634352@qq.com> Signed-off-by: David Chen <530634352@qq.com> Signed-off-by: WeiQing Chen <40507679+david6666666@users.noreply.github.com>
147 lines
5.1 KiB
Python
147 lines
5.1 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
|
"""Unit tests for OpenAI-compatible video API encoding helpers."""
|
|
|
|
import numpy as np
|
|
import pytest
|
|
import torch
|
|
|
|
from vllm_omni.diffusion.postprocess import rife_interpolator
|
|
from vllm_omni.entrypoints.openai import video_api_utils
|
|
|
|
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
|
|
|
|
|
|
def _install_fake_video_mux(monkeypatch, mux_calls):
|
|
def _fake_mux_video_audio_bytes(frames, audio, fps, audio_sample_rate, video_codec_options=None):
|
|
mux_calls.append(
|
|
{
|
|
"frames": frames,
|
|
"audio": audio,
|
|
"fps": fps,
|
|
"audio_sample_rate": audio_sample_rate,
|
|
"video_codec_options": video_codec_options,
|
|
}
|
|
)
|
|
return b"fake-video"
|
|
|
|
monkeypatch.setattr(
|
|
"vllm_omni.diffusion.utils.media_utils.mux_video_audio_bytes",
|
|
_fake_mux_video_audio_bytes,
|
|
)
|
|
|
|
|
|
def _install_fake_export_to_video(monkeypatch, export_calls):
|
|
def _fake_export_to_video(frames, output_path, fps):
|
|
export_calls.append(
|
|
{
|
|
"frames": frames,
|
|
"output_path": output_path,
|
|
"fps": fps,
|
|
}
|
|
)
|
|
with open(output_path, "wb") as f:
|
|
f.write(b"fake-video")
|
|
|
|
monkeypatch.setattr("diffusers.utils.export_to_video", _fake_export_to_video)
|
|
|
|
|
|
def test_encode_video_bytes_exports_frames_without_interpolation(monkeypatch):
|
|
export_calls = []
|
|
_install_fake_export_to_video(monkeypatch, export_calls)
|
|
|
|
frames = [np.full((2, 2, 3), fill_value=i / 5, dtype=np.float32) for i in range(5)]
|
|
video_bytes = video_api_utils._encode_video_bytes(
|
|
frames,
|
|
fps=8,
|
|
)
|
|
|
|
assert video_bytes == b"fake-video"
|
|
assert len(export_calls) == 1
|
|
assert len(export_calls[0]["frames"]) == 5
|
|
assert export_calls[0]["frames"][0].shape == (2, 2, 3)
|
|
assert export_calls[0]["fps"] == 8
|
|
|
|
|
|
def test_encode_video_bytes_uses_array_fast_path(monkeypatch):
|
|
export_calls = []
|
|
_install_fake_export_to_video(monkeypatch, export_calls)
|
|
monkeypatch.setattr(
|
|
video_api_utils,
|
|
"_normalize_frames",
|
|
lambda frames: (_ for _ in ()).throw(AssertionError("ndarray input should not go through frame list path")),
|
|
)
|
|
|
|
video = np.linspace(0.0, 1.0, num=5 * 2 * 2 * 3, dtype=np.float32).reshape(5, 2, 2, 3)
|
|
video_bytes = video_api_utils._encode_video_bytes(video, fps=12)
|
|
|
|
assert video_bytes == b"fake-video"
|
|
assert len(export_calls) == 1
|
|
assert len(export_calls[0]["frames"]) == 5
|
|
assert export_calls[0]["frames"][0].flags["C_CONTIGUOUS"]
|
|
assert export_calls[0]["fps"] == 12.0
|
|
|
|
|
|
def test_encode_video_bytes_without_audio_uses_diffusers_export(monkeypatch):
|
|
export_calls = []
|
|
_install_fake_export_to_video(monkeypatch, export_calls)
|
|
monkeypatch.setattr(
|
|
"vllm_omni.diffusion.utils.media_utils.mux_video_audio_bytes",
|
|
lambda *args, **kwargs: (_ for _ in ()).throw(
|
|
AssertionError("no-audio path should not use mux_video_audio_bytes")
|
|
),
|
|
)
|
|
|
|
video = np.linspace(0.0, 1.0, num=4 * 2 * 2 * 3, dtype=np.float32).reshape(4, 2, 2, 3)
|
|
video_bytes = video_api_utils._encode_video_bytes(video, fps=10)
|
|
|
|
assert video_bytes == b"fake-video"
|
|
assert len(export_calls) == 1
|
|
assert export_calls[0]["fps"] == 10
|
|
assert len(export_calls[0]["frames"]) == 4
|
|
|
|
|
|
def test_rife_model_inference_runs_on_dummy_tensors():
|
|
model = rife_interpolator.Model().eval()
|
|
img0 = torch.rand(1, 3, 32, 32)
|
|
img1 = torch.rand(1, 3, 32, 32)
|
|
|
|
output = model.inference(img0, img1, scale=1.0)
|
|
|
|
assert output.shape == (1, 3, 32, 32)
|
|
assert torch.isfinite(output).all()
|
|
|
|
|
|
def test_frame_interpolator_runs_actual_torch_tensor_path(monkeypatch):
|
|
model = rife_interpolator.Model().eval()
|
|
interpolator = rife_interpolator.FrameInterpolator()
|
|
monkeypatch.setattr(interpolator, "_ensure_model_loaded", lambda preferred_device=None: model)
|
|
|
|
video = torch.zeros(1, 3, 2, 32, 32)
|
|
output_video, multiplier = interpolator.interpolate_tensor(video, exp=1, scale=1.0)
|
|
|
|
assert multiplier == 2
|
|
assert output_video.shape == (1, 3, 3, 32, 32)
|
|
assert torch.isfinite(output_video).all()
|
|
|
|
|
|
def test_frame_interpolator_uses_platform_device_when_tensor_is_cpu(monkeypatch):
|
|
chosen_devices = []
|
|
model = rife_interpolator.Model().eval()
|
|
|
|
def _fake_ensure_model_loaded(*, preferred_device=None):
|
|
chosen_devices.append(preferred_device)
|
|
return model
|
|
|
|
interpolator = rife_interpolator.FrameInterpolator()
|
|
monkeypatch.setattr(interpolator, "_ensure_model_loaded", _fake_ensure_model_loaded)
|
|
monkeypatch.setattr(model.flownet, "to", lambda device: model.flownet)
|
|
monkeypatch.setattr(rife_interpolator, "_select_torch_device", lambda: torch.device("cuda"))
|
|
|
|
video = torch.zeros(1, 3, 2, 32, 32)
|
|
output_video, multiplier = interpolator.interpolate_tensor(video, exp=1, scale=1.0)
|
|
|
|
assert chosen_devices == [torch.device("cuda")]
|
|
assert multiplier == 2
|
|
assert output_video.shape == (1, 3, 3, 32, 32)
|