[3/N] Encode streamed video on the worker with bounded batching (#7018)

Signed-off-by: specture724 <specture724@gmail.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com>
This commit is contained in:
authored and GitHub committed 2026-09-12 20:58:11 +08:00
1 parent 9edc1b4667
commit 7e520f9cc4
9 files changed
+517 -40

No files matched your search

@@ -1,5 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Unit tests for `/v1/realtime/video` WebSocket video output streaming."""
from __future__ import annotations
@@ -7,12 +7,13 @@ from __future__ import annotations
import asyncio
import json
from collections.abc import AsyncGenerator, Callable
from http import HTTPStatus
from types import SimpleNamespace
from unittest.mock import MagicMock
import numpy as np
import pytest
from fastapi import FastAPI, WebSocket
from fastapi import FastAPI, HTTPException, WebSocket
from pytest_mock import MockerFixture
from starlette.testclient import TestClient
@@ -957,3 +958,30 @@ class TestStreamingVideoOutputPromptUpdate:
"transition_chunks": 2,
},
)
class TestStreamingVideoOutputExtraParams:
"""extra_params handling when building streaming generation inputs."""
@staticmethod
def _handler() -> OmniStreamingVideoOutputHandler:
handler = object.__new__(OmniStreamingVideoOutputHandler)
handler._engine_client = SimpleNamespace(default_sampling_params_list=[])
return handler
async def test_preencode_mp4_is_rejected_for_streaming_sessions(self):
"""Worker-side pre-encoding emits one progressive MP4 the fMP4 encoder cannot consume."""
request = VideoGenerationRequest(prompt="p", extra_params={"preencode_mp4": True})
with pytest.raises(HTTPException) as excinfo:
await self._handler()._build_prompt_and_sampling_params(request)
assert excinfo.value.status_code == HTTPStatus.BAD_REQUEST.value
assert "preencode_mp4" in excinfo.value.detail
async def test_other_extra_params_still_reach_the_engine(self):
request = VideoGenerationRequest(prompt="p", extra_params={"flow_shift": 3.0})
_, gen_params, _ = await self._handler()._build_prompt_and_sampling_params(request)
assert gen_params.extra_args["flow_shift"] == 3.0
@@ -134,6 +134,60 @@ def test_raw_and_base64_encoders_receive_persistent_converter(mocker: MockerFixt
handler.shutdown()
@pytest.mark.parametrize("batch_frames", [0, -1, True, 1.5, "17", None])
def test_preencode_rejects_invalid_batch_frames_before_generation(batch_frames):
engine = FakeAsyncOmni()
handler = OmniOpenAIServingVideo.for_diffusion(engine, model_name="test-model")
request = VideoGenerationRequest(
prompt="test", extra_params={"preencode_mp4": True, "preencode_batch_frames": batch_frames}
)
try:
with pytest.raises(HTTPException, match="preencode_batch_frames") as exc:
asyncio.run(handler.generate_video_bytes(request, "invalid-batch"))
assert exc.value.status_code == 400
assert engine.captured_prompt is None
finally:
handler.shutdown()
def test_preencoded_video_bytes_preserve_metadata(mocker: MockerFixture):
from vllm_omni.entrypoints.openai.serving_video import VideoGenerationArtifacts
handler = OmniOpenAIServingVideo.for_diffusion(FakeAsyncOmni(), model_name="test-model")
# Resolved frame count differs from anything the request asked for, so the
# metadata has to come from the encoded stream rather than request defaults.
preencoded = _make_test_video_bytes((32, 24), num_frames=7)
artifacts = VideoGenerationArtifacts(
videos=[preencoded],
audios=[None],
actions=[None],
audio_sample_rate=24000,
output_fps=24.0,
stage_durations={"decode": 0.5},
peak_memory_mb=123.0,
metrics={"generation_time": 1.25},
)
mocker.patch.object(handler, "_run_and_extract", return_value=artifacts)
encoder = mocker.patch("vllm_omni.entrypoints.openai.serving_video._encode_video_bytes")
try:
result = asyncio.run(handler.generate_video_bytes(VideoGenerationRequest(prompt="test"), "preencoded"))
assert result == (
preencoded,
{"decode": 0.5},
123.0,
None,
{
"fps": 24.0,
"num_frames": 7,
"duration_s": 7 / 24.0,
"metrics": {"generation_time": 1.25},
},
)
encoder.assert_not_called()
finally:
handler.shutdown()
def test_resolve_diffusion_od_config_falls_back_to_attribute():
od_config = SimpleNamespace(model_class_name="WanPipeline")
handler = OmniOpenAIServingVideo.for_diffusion(